@vantageos/cloud-identity 0.5.0 → 0.6.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,51 @@
3
3
  All notable changes to `@vantageos/cloud-identity` are documented here.
4
4
  This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## [0.6.0]
7
+
8
+ **Additive — typed refusal for reads, and a role assertion.**
9
+
10
+ ### Added
11
+
12
+ - `resolveTenantIdOrAbsent(source)` (`src/org-guard.ts`): non-throwing sibling
13
+ of `requireTenantId`. Returns `{ present: true, tenantId }` or a typed
14
+ `{ present: false, absence: { code: "TENANT_ABSENT", reason } }`. A read that
15
+ throws crashes a mounted render; a read that returns a bare empty value is
16
+ byte-identical to "there is nothing". This returns neither.
17
+ - `requireHumanRole(session, required)` and
18
+ `resolveHumanRoleOrRefusal(session, required)` (`src/human-path.ts`): role
19
+ assertion on the verified session's `orgRole`, throwing and non-throwing
20
+ forms. Exact match, no hierarchy; an empty required list admits nobody.
21
+ - Types: `TenantAbsence`, `TenantAbsenceReason`, `TenantResolution`,
22
+ `RequiredHumanRole`, `RoleRefusal`, `RoleRefusalReason`, `RoleResolution`.
23
+
24
+ ### Fixed
25
+
26
+ - The Clerk org-role map is now prototype-less (`Object.create(null)`). As a
27
+ plain object literal it inherited `Object.prototype`, so a presented
28
+ `orgRole` of `toString`, `constructor`, `valueOf` or `__proto__` did not
29
+ MISS the lookup — it returned an inherited value, which is truthy, and the
30
+ resolver handed back a FUNCTION as the role instead of refusing. Any key
31
+ that is not one of the eight own keys is now `undefined`, so the existing
32
+ refusal path rejects it. Fixed at the data; no lookup expression and no
33
+ function body changed, and no list of forbidden names was introduced.
34
+
35
+ ### Unchanged
36
+
37
+ - `requireTenantId` and `normalizeVerifiedHumanSession` are byte-for-byte
38
+ unchanged and still throw on every refusal.
39
+ - The tenant key stays opaque: no export takes or returns a slug. That
40
+ opacity is now pinned on all four served paths (session, bearer,
41
+ self-host, `role.identity.tenant`), through BOTH the throwing and the
42
+ non-throwing sibling, with a fixture carrying edge whitespace so that
43
+ splicing a `.trim()` onto a served id goes RED instead of passing.
44
+
45
+ ### Removed
46
+
47
+ - `bun.lock`, committed by accident in 0.5.0. `package-lock.json` is the
48
+ lockfile of record; two lockfiles for two package managers guarantee a
49
+ silent divergence.
50
+
6
51
  ## [0.5.0]
7
52
 
8
53
  **Additive — grant-aware scope filter.** Closes the other pole of the
package/README.md CHANGED
@@ -105,6 +105,27 @@ await resolveTenant({ session: null }); // throws Error("Unauthenticated: no ses
105
105
  `{ kind: "bearer", context }` for a machine caller. A missing session, a
106
106
  missing organization and an empty organization id are all refusals, never a
107
107
  default.
108
+ - `resolveTenantIdOrAbsent(source)` — the NON-throwing sibling of
109
+ `requireTenantId`, for a public READ. Same `TenantSource` union, same
110
+ refusal conditions; instead of throwing it returns
111
+ `{ present: true, tenantId }` or
112
+ `{ present: false, absence: { code: "TENANT_ABSENT", reason } }`
113
+ (`TenantAbsence`, `TenantAbsenceReason`, `TenantResolution`). The absence
114
+ is a non-empty object: it is never `[]`, `{}`, `null` or a zeroed count, so
115
+ "no organization" and "an organization with nothing in it" cannot collapse
116
+ into one value. Use `requireTenantId` at a WRITE boundary and
117
+ `resolveTenantIdOrAbsent` where a throw would crash a mounted render. The
118
+ tenant id is OPAQUE — returned byte-for-byte, never a slug or display name.
119
+ - `requireHumanRole(session, required)` — asserts the VERIFIED session
120
+ carries `required` (a `HumanAccountRole` or a list of them, exact match, no
121
+ hierarchy) and returns the resolved identity; throws otherwise. The role is
122
+ read from `session.orgRole`, never from an argument. `RequiredHumanRole`
123
+ is its `required` type.
124
+ - `resolveHumanRoleOrRefusal(session, required)` — the non-throwing form:
125
+ `{ admitted: true, identity }` or
126
+ `{ admitted: false, refusal: { code: "ROLE_REFUSED", reason } }`
127
+ (`RoleResolution`, `RoleRefusal`, `RoleRefusalReason`). `reason` is
128
+ `role-not-held` for a verified member lacking the role.
108
129
  - `getEffectiveTenantId(ctx, args)` — resolves which tenant a request should
109
130
  act on when a caller may legitimately act on more than one.
110
131
 
@@ -92,4 +92,50 @@ export type ResolvedHumanIdentity = {
92
92
  * ```
93
93
  */
94
94
  export declare function normalizeVerifiedHumanSession(session: ClerkSessionLike | null | undefined): ResolvedHumanIdentity;
95
+ /**
96
+ * Why a caller was not admitted. `role-not-held` is the one that matters: a
97
+ * verified member of the organization who does not carry the required role.
98
+ */
99
+ export type RoleRefusalReason = "no-session" | "no-organization" | "no-verified-role" | "role-not-held";
100
+ /** The typed refusal. A non-empty object carrying its own code. */
101
+ export type RoleRefusal = {
102
+ code: "ROLE_REFUSED";
103
+ reason: RoleRefusalReason;
104
+ };
105
+ /** Result of `resolveHumanRoleOrRefusal`. Branch on `admitted`. */
106
+ export type RoleResolution = {
107
+ admitted: true;
108
+ identity: ResolvedHumanIdentity;
109
+ } | {
110
+ admitted: false;
111
+ refusal: RoleRefusal;
112
+ };
113
+ /**
114
+ * `required` is the POLICY the call site declares; the caller's role is the
115
+ * CLAIM, and it is read only from `session.orgRole` (which the caller has
116
+ * already verified upstream — see the @security note on
117
+ * `normalizeVerifiedHumanSession`). There is no parameter through which a
118
+ * caller can supply its own role. Matching is EXACT, with no hierarchy:
119
+ * `owner` does not satisfy `"admin"`; pass `["owner", "admin"]` to admit
120
+ * either. An empty list admits nobody.
121
+ */
122
+ export type RequiredHumanRole = HumanAccountRole | readonly HumanAccountRole[];
123
+ /**
124
+ * THROWING form, for a write boundary. Returns the resolved identity when
125
+ * the verified session carries one of the `required` roles; throws
126
+ * otherwise. Malformed sessions throw exactly what
127
+ * `normalizeVerifiedHumanSession` throws; a well-formed session lacking the
128
+ * role throws "Role refused: ...".
129
+ *
130
+ * Same `@security` precondition as `normalizeVerifiedHumanSession`: this
131
+ * asserts on a session that is ALREADY verified. It verifies nothing.
132
+ */
133
+ export declare function requireHumanRole(session: ClerkSessionLike | null | undefined, required: RequiredHumanRole): ResolvedHumanIdentity;
134
+ /**
135
+ * NON-THROWING form, for a public read. Returns `{ admitted: true, identity }`
136
+ * or `{ admitted: false, refusal }` where the refusal carries `ROLE_REFUSED`
137
+ * and a reason. Admits exactly the sessions `requireHumanRole` returns for
138
+ * and refuses exactly the ones it throws for.
139
+ */
140
+ export declare function resolveHumanRoleOrRefusal(session: ClerkSessionLike | null | undefined, required: RequiredHumanRole): RoleResolution;
95
141
  //# sourceMappingURL=human-path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"human-path.d.ts","sourceRoot":"","sources":["../src/human-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,sBAAsB;;;;;EAKjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAMtE;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAMF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAAC;AAoBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,GAC3C,qBAAqB,CAiCvB"}
1
+ {"version":3,"file":"human-path.d.ts","sourceRoot":"","sources":["../src/human-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,sBAAsB;;;;;EAKjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAMtE;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAMF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAAC;AAgCF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,GAC3C,qBAAqB,CAiCvB;AAMD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GACzB,YAAY,GACZ,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,CAAC;AAEpB,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,qBAAqB,CAAA;CAAE,GACnD;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,gBAAgB,EAAE,CAAC;AAM/E;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAC5C,QAAQ,EAAE,iBAAiB,GAC1B,qBAAqB,CAWvB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAC5C,QAAQ,EAAE,iBAAiB,GAC1B,cAAc,CAqBhB"}
@@ -35,7 +35,17 @@ export const humanAccountRoleSchema = z.enum([
35
35
  * listed here is refused rather than silently coerced to a default, per
36
36
  * "presented, never inferred from an absence."
37
37
  */
38
- const CLERK_ORG_ROLE_MAP = {
38
+ const CLERK_ORG_ROLE_MAP = Object.assign(
39
+ // PROTOTYPE-LESS on purpose. As a plain object literal this map INHERITED
40
+ // `Object.prototype`, so a lookup of a presented role like `toString`,
41
+ // `constructor` or `__proto__` did not MISS — it returned an inherited
42
+ // value, which is truthy, and the resolver handed back a FUNCTION as the
43
+ // role instead of refusing. With a null prototype, any key that is not one
44
+ // of the eight own keys below is `undefined`, so the existing
45
+ // `if (!mapped) throw` refuses it. The lookup expressions in
46
+ // `normalizeVerifiedHumanSession` and `resolveHumanRoleOrRefusal` are
47
+ // unchanged — this is a fix at the DATA, not a list of forbidden names.
48
+ Object.create(null), {
39
49
  "org:owner": "owner",
40
50
  owner: "owner",
41
51
  "org:admin": "admin",
@@ -44,7 +54,7 @@ const CLERK_ORG_ROLE_MAP = {
44
54
  member: "member",
45
55
  "org:client": "client",
46
56
  client: "client",
47
- };
57
+ });
48
58
  /**
49
59
  * @security ⚠️ DECODE/NORMALIZE-ONLY. NOT AUTHENTICATION. NOT VERIFICATION.
50
60
  *
@@ -114,4 +124,55 @@ export function normalizeVerifiedHumanSession(session) {
114
124
  }
115
125
  return { tenant: orgId, subject: userId, role: mapped };
116
126
  }
127
+ function requiredList(required) {
128
+ return typeof required === "string" ? [required] : required;
129
+ }
130
+ /**
131
+ * THROWING form, for a write boundary. Returns the resolved identity when
132
+ * the verified session carries one of the `required` roles; throws
133
+ * otherwise. Malformed sessions throw exactly what
134
+ * `normalizeVerifiedHumanSession` throws; a well-formed session lacking the
135
+ * role throws "Role refused: ...".
136
+ *
137
+ * Same `@security` precondition as `normalizeVerifiedHumanSession`: this
138
+ * asserts on a session that is ALREADY verified. It verifies nothing.
139
+ */
140
+ export function requireHumanRole(session, required) {
141
+ const identity = normalizeVerifiedHumanSession(session);
142
+ const allowed = requiredList(required);
143
+ if (!allowed.includes(identity.role)) {
144
+ throw new Error(`Role refused: this session is a verified member but does not carry ${allowed.length === 0 ? "any admitted role" : `role ${allowed.join(" or ")}`}.`);
145
+ }
146
+ return identity;
147
+ }
148
+ /**
149
+ * NON-THROWING form, for a public read. Returns `{ admitted: true, identity }`
150
+ * or `{ admitted: false, refusal }` where the refusal carries `ROLE_REFUSED`
151
+ * and a reason. Admits exactly the sessions `requireHumanRole` returns for
152
+ * and refuses exactly the ones it throws for.
153
+ */
154
+ export function resolveHumanRoleOrRefusal(session, required) {
155
+ const refuse = (reason) => ({
156
+ admitted: false,
157
+ refusal: { code: "ROLE_REFUSED", reason },
158
+ });
159
+ if (!session)
160
+ return refuse("no-session");
161
+ const { orgId, userId, orgRole } = session;
162
+ if (typeof orgId !== "string" || orgId.length === 0) {
163
+ return refuse("no-organization");
164
+ }
165
+ if (typeof userId !== "string" || userId.length === 0) {
166
+ return refuse("no-verified-role");
167
+ }
168
+ if (typeof orgRole !== "string" || orgRole.length === 0) {
169
+ return refuse("no-verified-role");
170
+ }
171
+ const role = CLERK_ORG_ROLE_MAP[orgRole];
172
+ if (!role)
173
+ return refuse("no-verified-role");
174
+ if (!requiredList(required).includes(role))
175
+ return refuse("role-not-held");
176
+ return { admitted: true, identity: { tenant: orgId, subject: userId, role } };
177
+ }
117
178
  //# sourceMappingURL=human-path.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"human-path.js","sourceRoot":"","sources":["../src/human-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,IAAI,CAAC;IAC3C,OAAO;IACP,OAAO;IACP,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AA6BH;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAqC;IAC3D,WAAW,EAAE,OAAO;IACpB,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,OAAO;IACpB,KAAK,EAAE,OAAO;IACd,YAAY,EAAE,QAAQ;IACtB,MAAM,EAAE,QAAQ;IAChB,YAAY,EAAE,QAAQ;IACtB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,MAAM,UAAU,6BAA6B,CAC3C,OAA4C;IAE5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,mCAAmC,OAAO,sBAAsB,MAAM,CAAC,IAAI,CACzE,kBAAkB,CACnB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAChB,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"human-path.js","sourceRoot":"","sources":["../src/human-path.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,8 +11,8 @@ export { validateMasterBearer } from "./bearer-validation.js";
11
11
  export type { OAuthCtx, ScopeProfile, NamespacePrefix, FromAllowListEntry, ValidateMasterBearerResult, } from "./types.js";
12
12
  export { workspaceSchema, workspaceMemberSchema, workspaceRoleSchema, tenantContextSchema, ScopeViolationError, getEffectiveTenantId, decodeUnverifiedBearer, } from "./tenancy-domain.js";
13
13
  export type { Workspace, WorkspaceMember, WorkspaceRole, TenantContext, ScopeViolationPayload, BearerPayload, } from "./tenancy-domain.js";
14
- export { requireTenantId } from "./org-guard.js";
15
- export type { SessionIdentity, TenantSource, DeploymentMode, } from "./org-guard.js";
16
- export { humanAccountRoleSchema, normalizeVerifiedHumanSession } from "./human-path.js";
17
- export type { HumanAccountRole, ClerkSessionLike, ResolvedHumanIdentity, } from "./human-path.js";
14
+ export { requireTenantId, resolveTenantIdOrAbsent } from "./org-guard.js";
15
+ export type { TenantAbsence, TenantAbsenceReason, TenantResolution, SessionIdentity, TenantSource, DeploymentMode, } from "./org-guard.js";
16
+ export { humanAccountRoleSchema, normalizeVerifiedHumanSession, requireHumanRole, resolveHumanRoleOrRefusal, } from "./human-path.js";
17
+ export type { RequiredHumanRole, RoleRefusal, RoleRefusalReason, RoleResolution, HumanAccountRole, ClerkSessionLike, ResolvedHumanIdentity, } from "./human-path.js";
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EACV,eAAe,EACf,YAAY,EACZ,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AACxF,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAC7B,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ export { validateMasterBearer } from "./bearer-validation.js";
11
11
  // 0.2.0 — Domain-tenancy layer (additive)
12
12
  export { workspaceSchema, workspaceMemberSchema, workspaceRoleSchema, tenantContextSchema, ScopeViolationError, getEffectiveTenantId, decodeUnverifiedBearer, } from "./tenancy-domain.js";
13
13
  // Organization-membership guard (unified session + bearer + self-host contract)
14
- export { requireTenantId } from "./org-guard.js";
14
+ export { requireTenantId, resolveTenantIdOrAbsent } from "./org-guard.js";
15
15
  // 0.4.0 — Human-path resolver (Clerk-shaped session -> { tenant, subject, role })
16
- export { humanAccountRoleSchema, normalizeVerifiedHumanSession } from "./human-path.js";
16
+ export { humanAccountRoleSchema, normalizeVerifiedHumanSession, requireHumanRole, resolveHumanRoleOrRefusal, } from "./human-path.js";
17
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,mBAAmB,GAEpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAS9D,0CAA0C;AAC1C,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAU7B,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAOjD,kFAAkF;AAClF,OAAO,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,mBAAmB,GAEpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAS9D,0CAA0C;AAC1C,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAU7B,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAU1E,kFAAkF;AAClF,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAC7B,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC"}
@@ -92,4 +92,52 @@ export type TenantSource = {
92
92
  * organization/workspace information is missing.
93
93
  */
94
94
  export declare function requireTenantId(source: TenantSource): string;
95
+ /**
96
+ * Why a caller resolved to no tenant. A closed set, so a consumer can branch
97
+ * on content.
98
+ */
99
+ export type TenantAbsenceReason = "no-session" | "no-organization" | "no-workspace" | "no-tenant-configured";
100
+ /**
101
+ * The typed absence. It is a NON-empty object carrying its own code: it can
102
+ * never be mistaken for `[]`, `{}`, `null`, `0` or a zeroed aggregate, all of
103
+ * which are what "an organization with nothing in it" looks like.
104
+ */
105
+ export type TenantAbsence = {
106
+ code: "TENANT_ABSENT";
107
+ reason: TenantAbsenceReason;
108
+ };
109
+ /**
110
+ * Result of `resolveTenantIdOrAbsent`. Branch on `present`; the two arms
111
+ * share no field, so a consumer that forgets to branch gets a type error
112
+ * rather than a silently-empty read.
113
+ */
114
+ export type TenantResolution = {
115
+ present: true;
116
+ tenantId: string;
117
+ } | {
118
+ present: false;
119
+ absence: TenantAbsence;
120
+ };
121
+ /**
122
+ * The tenant id is OPAQUE. It is returned byte-for-byte as presented
123
+ * (`orgId`, `workspaceId` or the self-host `tenantId`), never trimmed,
124
+ * lower-cased or otherwise interpreted. This package never receives or
125
+ * derives a slug or any human-facing name; each product maps its own notion
126
+ * (an organization id, a workspace id) onto that string.
127
+ *
128
+ * NON-THROWING sibling of `requireTenantId`, for a public READ.
129
+ *
130
+ * `requireTenantId` throws on every branch, which is right for a WRITE
131
+ * boundary and wrong for a subscribed read: a throw at a caller with no
132
+ * organization crashes a mounted render, while a bare empty value is
133
+ * byte-identical to "there is nothing". This function does neither: it
134
+ * returns the tenant, or a typed absence that cannot be confused with an
135
+ * empty result.
136
+ *
137
+ * Same `TenantSource` union, same refusal conditions as `requireTenantId` —
138
+ * every input that makes it throw makes this return `{ present: false }`,
139
+ * and every input it serves is served identically. Grants nothing that
140
+ * `requireTenantId` refuses.
141
+ */
142
+ export declare function resolveTenantIdOrAbsent(source: TenantSource): TenantResolution;
95
143
  //# sourceMappingURL=org-guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"org-guard.d.ts","sourceRoot":"","sources":["../src/org-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,CAAC;AAE/D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CA+B5D"}
1
+ {"version":3,"file":"org-guard.d.ts","sourceRoot":"","sources":["../src/org-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,CAAC;AAE/D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CA+B5D;AAMD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,iBAAiB,GACjB,cAAc,GACd,sBAAsB,CAAC;AAE3B;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,mBAAmB,CAAC;CAC7B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,CA4B9E"}
package/dist/org-guard.js CHANGED
@@ -74,4 +74,52 @@ export function requireTenantId(source) {
74
74
  }
75
75
  return workspaceId;
76
76
  }
77
+ /**
78
+ * The tenant id is OPAQUE. It is returned byte-for-byte as presented
79
+ * (`orgId`, `workspaceId` or the self-host `tenantId`), never trimmed,
80
+ * lower-cased or otherwise interpreted. This package never receives or
81
+ * derives a slug or any human-facing name; each product maps its own notion
82
+ * (an organization id, a workspace id) onto that string.
83
+ *
84
+ * NON-THROWING sibling of `requireTenantId`, for a public READ.
85
+ *
86
+ * `requireTenantId` throws on every branch, which is right for a WRITE
87
+ * boundary and wrong for a subscribed read: a throw at a caller with no
88
+ * organization crashes a mounted render, while a bare empty value is
89
+ * byte-identical to "there is nothing". This function does neither: it
90
+ * returns the tenant, or a typed absence that cannot be confused with an
91
+ * empty result.
92
+ *
93
+ * Same `TenantSource` union, same refusal conditions as `requireTenantId` —
94
+ * every input that makes it throw makes this return `{ present: false }`,
95
+ * and every input it serves is served identically. Grants nothing that
96
+ * `requireTenantId` refuses.
97
+ */
98
+ export function resolveTenantIdOrAbsent(source) {
99
+ const absent = (reason) => ({
100
+ present: false,
101
+ absence: { code: "TENANT_ABSENT", reason },
102
+ });
103
+ if (source.kind === "session") {
104
+ if (!source.identity)
105
+ return absent("no-session");
106
+ const orgId = source.identity.orgId;
107
+ if (typeof orgId !== "string" || orgId.length === 0) {
108
+ return absent("no-organization");
109
+ }
110
+ return { present: true, tenantId: orgId };
111
+ }
112
+ if (source.kind === "self-host") {
113
+ const tenantId = source.tenantId;
114
+ if (typeof tenantId !== "string" || tenantId.length === 0) {
115
+ return absent("no-tenant-configured");
116
+ }
117
+ return { present: true, tenantId };
118
+ }
119
+ const workspaceId = source.context?.workspaceId;
120
+ if (typeof workspaceId !== "string" || workspaceId.length === 0) {
121
+ return absent("no-workspace");
122
+ }
123
+ return { present: true, tenantId: workspaceId };
124
+ }
77
125
  //# sourceMappingURL=org-guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"org-guard.js","sourceRoot":"","sources":["../src/org-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAyCH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CACb,gHAAgH,CACjH,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC;IAChD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"org-guard.js","sourceRoot":"","sources":["../src/org-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAyCH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,MAAoB;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CACb,gHAAgH,CACjH,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC;IAChD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAmCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAoB;IAC1D,MAAM,MAAM,GAAG,CAAC,MAA2B,EAAoB,EAAE,CAAC,CAAC;QACjE,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE;KAC3C,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,OAAO,MAAM,CAAC,YAAY,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,OAAO,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1D,OAAO,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC;IAChD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAClD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vantageos/cloud-identity",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Framework-agnostic identity + scope-filter primitives for VantagePeers Cloud (multi-tenant MCP).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",