@vantageos/cloud-identity 0.9.0 → 0.10.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,39 @@
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.10.0]
7
+
8
+ **Additive — identity gaps a consumer had are now in the package.** Every
9
+ consumer adapts these; none copies them. No existing function changes behaviour.
10
+
11
+ ### Added
12
+
13
+ - `resolveMinRole` / `assertMinRole`: minimum-role check over an order the
14
+ caller supplies as data. Unknown role, unknown minimum, invalid order refuse.
15
+ - `mapRoleClaim`: claim to role through caller data, with a fallback that must
16
+ be explicit. Absent or unmapped claim without a fallback refuses.
17
+ - `resolveMembership` (injected async lookup; error, miss, inactive, malformed
18
+ and other-organisation all refuse), `isRowInTenant` (strict equality,
19
+ unstamped row refused), `membershipRecordSchema`.
20
+ - `requireOrgAdmin`: the proof is bound to the caller's verified organisation.
21
+ - `assertNamespaceWrite` and the shared boundary rule `namespaceMatchesPrefix`
22
+ (now also used by the read filter, same behaviour).
23
+ - `timingSafeEqualSync` / `assertSecretSync`: synchronous constant-time
24
+ comparison; an unset expected secret matches nothing.
25
+ - `IdentityRefusalError` and the `IdentityRefusal` types.
26
+ - New subpath exports `./identity-refusal`, `./role-policy`,
27
+ `./tenant-membership`, `./namespace-write`, `./secret-compare-sync`.
28
+
29
+ ## [0.9.1]
30
+
31
+ ### Fixed
32
+
33
+ - `resolveWriterRole` / `requireWriterRole`: an absent `writerRoles` list (a
34
+ consumer that failed to load it) now returns the typed `role-not-writer`
35
+ refusal instead of throwing a `TypeError`. It already granted nothing; the
36
+ refusal now carries its code, as the JSDoc and test promised. Found by the
37
+ reviewer of #15.
38
+
6
39
  ## [0.9.0]
7
40
 
8
41
  **Additive — the person principal (`./person-principal`).** The decisions a
package/README.md CHANGED
@@ -450,6 +450,77 @@ const mayWrite = resolveWriterRole({
450
450
  The module verifies no credential. The token record must come from your own
451
451
  lookup of the bearer the person presented, never from a request body.
452
452
 
453
+ ## Role policy, membership, namespace writes and secrets (0.10.0)
454
+
455
+ Seven primitives that consumers used to copy. Each is pure, takes its policy as
456
+ DATA from the call site, and refuses on every absence: no role, no claim, no
457
+ list, no prefix, no secret and a failing lookup are all refusals, never a
458
+ default grant. Refusals share one shape, `IdentityRefusal` (`code`, `reason`,
459
+ `door`, `detail`), thrown inside an `IdentityRefusalError` by the asserting
460
+ forms. `IdentityRefusalCode` is `RBAC_DENIED` or `CREDENTIAL_REFUSED`;
461
+ `IdentityRefusalReason` is the closed list of reasons. Every function that
462
+ refuses accepts an optional `door` so the refusal names your own entry point.
463
+
464
+ **Minimum role over an order you supply** (`./role-policy`)
465
+
466
+ - `resolveMinRole({ role, minimum, order, door? })` — `order` is your ordered
467
+ list, MOST privileged first (for example `["admin", "editor", "viewer"]`).
468
+ Returns `{ ok: true, role }` or `{ ok: false, refusal }` (`MinRoleInput`,
469
+ `MinRoleResult`). Refuses an empty or duplicated order, a `minimum` outside
470
+ the order, an absent or unknown role, and a role below the minimum. Matching
471
+ is exact.
472
+ - `assertMinRole(input)` — the throwing form; returns the role or throws
473
+ `IdentityRefusalError`.
474
+
475
+ **Role-claim mapping with an explicit fallback** (`./role-policy`)
476
+
477
+ - `mapRoleClaim({ claim, mapping, fallback?, door? })` — maps a verified claim
478
+ (for example `"org:admin"`) to your role through `mapping`, your data
479
+ (`MapRoleClaimInput`, `MapRoleClaimResult`). The package never picks a
480
+ default: an absent or unmapped claim is served only when YOU pass `fallback`
481
+ (use your least-privileged role), and is refused otherwise. A claim that is
482
+ not a string counts as absent; prototype keys are never mapped. The result
483
+ says whether the role was `mapped` or came from the `fallback`.
484
+
485
+ **Membership and tenant visibility** (`./tenant-membership`)
486
+
487
+ - `resolveMembership({ subject, orgId, lookup, door? })` — async. `lookup` is
488
+ your read of one membership (`MembershipRecord`: `active`, optional `role`,
489
+ optional `orgId`). A throwing lookup, a miss, an inactive row, a malformed
490
+ row and a row naming another organisation are all refusals; the lookup's own
491
+ error text is not surfaced. Served result: `{ ok: true, membership }`
492
+ (`ResolvedMembership`, `ResolveMembershipInput`, `ResolveMembershipResult`).
493
+ `membershipRecordSchema` is the zod schema of the record.
494
+ - `isRowInTenant({ rowOrgId, callerOrgId })` — `true` only on strict equality
495
+ of two non-empty ids. An unstamped row is never visible, not even to a caller
496
+ with no organisation.
497
+ - `requireOrgAdmin({ verifiedOrgId, targetOrgId, role, adminRoles, door? })` —
498
+ the organisation-admin proof, bound to the caller's VERIFIED organisation:
499
+ the target must equal it, and the role must be one of `adminRoles` (your
500
+ data; an empty list admits nobody). Throws `IdentityRefusalError`
501
+ (`RequireOrgAdminInput`).
502
+
503
+ **Namespace writes** (`./namespace-write`, `./scope-filter`)
504
+
505
+ - `assertNamespaceWrite(oauthCtx, namespace, door?)` — throws unless the
506
+ caller's `namespaceWritePrefixes` admit the namespace. Master scope passes;
507
+ a non-master with no write prefix is refused; read prefixes never grant a
508
+ write; an empty-string prefix grants nothing.
509
+ - `namespaceMatchesPrefix(namespace, prefix)` — the one path-boundary rule:
510
+ equality, or the prefix followed by `/`. `team/finance-archive` is not inside
511
+ `team/finance`. The read filter and `assertNamespaceWrite` both use it.
512
+
513
+ **Synchronous constant-time comparison** (`./secret-compare-sync`)
514
+
515
+ - `timingSafeEqualSync(a, b)` — strings (UTF-8) or `Uint8Array`, pure
516
+ JavaScript, no early exit on content. It walks the longer length and folds a
517
+ length difference into the result. Any other input type is `false`. The async
518
+ `timingSafeEqual` is unchanged.
519
+ - `assertSecretSync(presented, expected, door?)` — throws `IdentityRefusalError`
520
+ (`CREDENTIAL_REFUSED`) on mismatch. An unset `expected` (undefined, null or
521
+ empty) matches nothing, so a missing configuration never opens a door. The
522
+ refusal carries neither value.
523
+
453
524
  ## What this package does not do
454
525
 
455
526
  Worth reading before you rely on it.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Typed refusal shared by the 0.10.0 primitives (role policy, membership,
3
+ * org-admin proof, namespace write, secret comparison).
4
+ *
5
+ * A refusal is a value carrying its own code, reason and door, so a caller
6
+ * branches on content rather than on the mere presence of an exception, and an
7
+ * absence can never be mistaken for a refusal. It carries no credential.
8
+ *
9
+ * Mirrors the shape of `PersonRefusal` / `PersonRefusalError` on purpose: same
10
+ * `code`/`reason`/`door`/`detail` fields, same `ERROR: detail (reason, door)`
11
+ * message form. It is a separate type only because `PersonRefusalCode` is a
12
+ * closed vocabulary for the person path.
13
+ */
14
+ export type IdentityRefusalCode = "RBAC_DENIED" | "CREDENTIAL_REFUSED";
15
+ export type IdentityRefusalReason = "unknown-role" | "unknown-minimum-role" | "invalid-role-order" | "role-below-minimum" | "role-claim-absent" | "role-claim-unmapped" | "invalid-role-mapping" | "membership-invalid-input" | "membership-lookup-failed" | "membership-not-found" | "membership-record-invalid" | "membership-inactive" | "other-organisation" | "no-verified-organisation" | "role-not-admin" | "namespace-invalid" | "no-write-prefixes" | "namespace-write-denied" | "secret-not-configured" | "secret-mismatch";
16
+ export type IdentityRefusal = {
17
+ code: IdentityRefusalCode;
18
+ reason: IdentityRefusalReason;
19
+ /** The consumer's own name for the entry point that refused. */
20
+ door: string;
21
+ /** One sentence, safe to show to the caller. Never a credential. */
22
+ detail: string;
23
+ };
24
+ /** Thrown by the asserting forms. Carries the typed refusal untouched. */
25
+ export declare class IdentityRefusalError extends Error {
26
+ readonly refusal: IdentityRefusal;
27
+ constructor(refusal: IdentityRefusal);
28
+ }
29
+ /** @internal Build a refusal. Not exported from the package. */
30
+ export declare function refusal(code: IdentityRefusalCode, reason: IdentityRefusalReason, door: string, detail: string): IdentityRefusal;
31
+ //# sourceMappingURL=identity-refusal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-refusal.d.ts","sourceRoot":"","sources":["../src/identity-refusal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,oBAAoB,CAAC;AAEvE,MAAM,MAAM,qBAAqB,GAE7B,cAAc,GACd,sBAAsB,GACtB,oBAAoB,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,qBAAqB,GACrB,sBAAsB,GAEtB,0BAA0B,GAC1B,0BAA0B,GAC1B,sBAAsB,GACtB,2BAA2B,GAC3B,qBAAqB,GACrB,oBAAoB,GAEpB,0BAA0B,GAC1B,gBAAgB,GAEhB,mBAAmB,GACnB,mBAAmB,GACnB,wBAAwB,GAExB,uBAAuB,GACvB,iBAAiB,CAAC;AAEtB,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,0EAA0E;AAC1E,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;gBACtB,OAAO,EAAE,eAAe;CAKrC;AAED,gEAAgE;AAChE,wBAAgB,OAAO,CACrB,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,qBAAqB,EAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,eAAe,CAEjB"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Typed refusal shared by the 0.10.0 primitives (role policy, membership,
3
+ * org-admin proof, namespace write, secret comparison).
4
+ *
5
+ * A refusal is a value carrying its own code, reason and door, so a caller
6
+ * branches on content rather than on the mere presence of an exception, and an
7
+ * absence can never be mistaken for a refusal. It carries no credential.
8
+ *
9
+ * Mirrors the shape of `PersonRefusal` / `PersonRefusalError` on purpose: same
10
+ * `code`/`reason`/`door`/`detail` fields, same `ERROR: detail (reason, door)`
11
+ * message form. It is a separate type only because `PersonRefusalCode` is a
12
+ * closed vocabulary for the person path.
13
+ */
14
+ /** Thrown by the asserting forms. Carries the typed refusal untouched. */
15
+ export class IdentityRefusalError extends Error {
16
+ refusal;
17
+ constructor(refusal) {
18
+ super(`${refusal.code}: ${refusal.detail} (${refusal.reason}, ${refusal.door})`);
19
+ this.name = "IdentityRefusalError";
20
+ this.refusal = refusal;
21
+ }
22
+ }
23
+ /** @internal Build a refusal. Not exported from the package. */
24
+ export function refusal(code, reason, door, detail) {
25
+ return { code, reason, door, detail };
26
+ }
27
+ //# sourceMappingURL=identity-refusal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-refusal.js","sourceRoot":"","sources":["../src/identity-refusal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAwCH,0EAA0E;AAC1E,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,OAAO,CAAkB;IAClC,YAAY,OAAwB;QAClC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;QACjF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,UAAU,OAAO,CACrB,IAAyB,EACzB,MAA6B,EAC7B,IAAY,EACZ,MAAc;IAEd,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * validation.
7
7
  */
8
8
  export { timingSafeEqual, sha256Hex } from "./crypto.js";
9
- export { passesScopeFilter, scopeFilterList, scopeFilterGet, isMasterScope, isWildcardScope, LEGACY_WILDCARD_CTX, type ScopeFilterable, } from "./scope-filter.js";
9
+ export { passesScopeFilter, scopeFilterList, scopeFilterGet, isMasterScope, isWildcardScope, namespaceMatchesPrefix, LEGACY_WILDCARD_CTX, type ScopeFilterable, } from "./scope-filter.js";
10
10
  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";
@@ -29,4 +29,12 @@ export { oauthErrorFor, pkceChallengeFromVerifier } from "./authorize-shared.js"
29
29
  export type { AuthorizeRefusal, AuthorizeRefusalReason, } from "./authorize-shared.js";
30
30
  export { PERSON_ACTOR_PREFIX, PersonRefusalError, personActorName, isPersonActorName, personTokenRecordSchema, resolvePersonPrincipal, resolvePersonActingName, checkPersonCallShape, resolvePersonTenantAccess, resolveWriterRole, requireWriterRole, } from "./person-principal.js";
31
31
  export type { PersonRefusal, PersonRefusalCode, PersonRefusalReason, PersonTokenRecord, PersonPrincipal, OrganisationState, PersonPrincipalDeps, PersonPrincipalResult, PersonActingNameResult, PersonAccessResult, } from "./person-principal.js";
32
+ export { IdentityRefusalError } from "./identity-refusal.js";
33
+ export type { IdentityRefusal, IdentityRefusalCode, IdentityRefusalReason, } from "./identity-refusal.js";
34
+ export { resolveMinRole, assertMinRole, mapRoleClaim } from "./role-policy.js";
35
+ export type { MinRoleInput, MinRoleResult, MapRoleClaimInput, MapRoleClaimResult, } from "./role-policy.js";
36
+ export { isRowInTenant, resolveMembership, requireOrgAdmin, membershipRecordSchema, } from "./tenant-membership.js";
37
+ export type { MembershipRecord, ResolvedMembership, ResolveMembershipInput, ResolveMembershipResult, RequireOrgAdminInput, } from "./tenant-membership.js";
38
+ export { assertNamespaceWrite } from "./namespace-write.js";
39
+ export { timingSafeEqualSync, assertSecretSync } from "./secret-compare-sync.js";
32
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * validation.
7
7
  */
8
8
  export { timingSafeEqual, sha256Hex } from "./crypto.js";
9
- export { passesScopeFilter, scopeFilterList, scopeFilterGet, isMasterScope, isWildcardScope, LEGACY_WILDCARD_CTX, } from "./scope-filter.js";
9
+ export { passesScopeFilter, scopeFilterList, scopeFilterGet, isMasterScope, isWildcardScope, namespaceMatchesPrefix, LEGACY_WILDCARD_CTX, } from "./scope-filter.js";
10
10
  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";
@@ -29,4 +29,10 @@ export { oauthErrorFor, pkceChallengeFromVerifier } from "./authorize-shared.js"
29
29
  // pure data, the own-name actor rule, the tenant compare and the writer-role
30
30
  // assertion. Every consumer wires a person the same way.
31
31
  export { PERSON_ACTOR_PREFIX, PersonRefusalError, personActorName, isPersonActorName, personTokenRecordSchema, resolvePersonPrincipal, resolvePersonActingName, checkPersonCallShape, resolvePersonTenantAccess, resolveWriterRole, requireWriterRole, } from "./person-principal.js";
32
+ // 0.10.0 — Identity gaps closed in the package so consumers adapt, never copy.
33
+ export { IdentityRefusalError } from "./identity-refusal.js";
34
+ export { resolveMinRole, assertMinRole, mapRoleClaim } from "./role-policy.js";
35
+ export { isRowInTenant, resolveMembership, requireOrgAdmin, membershipRecordSchema, } from "./tenant-membership.js";
36
+ export { assertNamespaceWrite } from "./namespace-write.js";
37
+ export { timingSafeEqualSync, assertSecretSync } from "./secret-compare-sync.js";
32
38
  //# 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,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,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;AAWzB,sEAAsE;AACtE,yEAAyE;AACzE,mEAAmE;AACnE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAY/B,+EAA+E;AAC/E,mEAAmE;AACnE,OAAO,EACL,cAAc,EACd,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAa7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAOhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAQ7D,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AASlE,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAMjF,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,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;AAWzB,sEAAsE;AACtE,yEAAyE;AACzE,mEAAmE;AACnE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAY/B,+EAA+E;AAC/E,mEAAmE;AACnE,OAAO,EACL,cAAc,EACd,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAa7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAOhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAQ7D,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AASlE,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAMjF,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAc/B,+EAA+E;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAM7D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAO/E,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAQhC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Namespace WRITE assertion.
3
+ *
4
+ * `OAuthCtx.namespaceWritePrefixes` has always been on the type with the note
5
+ * "enforced by the caller". This is that enforcement, so no consumer carries
6
+ * its own copy. It uses `namespaceMatchesPrefix` from `./scope-filter`, the
7
+ * same boundary rule as the read filter: prefix equality, or prefix + '/'.
8
+ *
9
+ * A write is never granted by a READ prefix, by an empty prefix list (for a
10
+ * non-master) or by an empty-string prefix.
11
+ */
12
+ import type { OAuthCtx } from "./types.js";
13
+ /**
14
+ * Throws `IdentityRefusalError` unless the caller may write `namespace`.
15
+ * Master scope (`scope === "master"` or `"*"` in `fromAllowList`) passes.
16
+ *
17
+ * @param door The consumer's own name for the entry point, for the refusal.
18
+ */
19
+ export declare function assertNamespaceWrite(oauthCtx: OAuthCtx, namespace: string, door?: string): void;
20
+ //# sourceMappingURL=namespace-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace-write.d.ts","sourceRoot":"","sources":["../src/namespace-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,IAAI,SAAyB,GAC5B,IAAI,CA2BN"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Namespace WRITE assertion.
3
+ *
4
+ * `OAuthCtx.namespaceWritePrefixes` has always been on the type with the note
5
+ * "enforced by the caller". This is that enforcement, so no consumer carries
6
+ * its own copy. It uses `namespaceMatchesPrefix` from `./scope-filter`, the
7
+ * same boundary rule as the read filter: prefix equality, or prefix + '/'.
8
+ *
9
+ * A write is never granted by a READ prefix, by an empty prefix list (for a
10
+ * non-master) or by an empty-string prefix.
11
+ */
12
+ import { IdentityRefusalError, refusal } from "./identity-refusal.js";
13
+ import { isMasterScope, namespaceMatchesPrefix } from "./scope-filter.js";
14
+ /**
15
+ * Throws `IdentityRefusalError` unless the caller may write `namespace`.
16
+ * Master scope (`scope === "master"` or `"*"` in `fromAllowList`) passes.
17
+ *
18
+ * @param door The consumer's own name for the entry point, for the refusal.
19
+ */
20
+ export function assertNamespaceWrite(oauthCtx, namespace, door = "assertNamespaceWrite") {
21
+ if (oauthCtx == null) {
22
+ throw new TypeError("assertNamespaceWrite: oauthCtx is required — pass an explicit OAuthCtx.");
23
+ }
24
+ const deny = (reason, detail) => {
25
+ throw new IdentityRefusalError(refusal("RBAC_DENIED", reason, door, detail));
26
+ };
27
+ if (isMasterScope(oauthCtx))
28
+ return;
29
+ if (typeof namespace !== "string" || namespace.length === 0) {
30
+ deny("namespace-invalid", "A non-empty namespace is required.");
31
+ }
32
+ const prefixes = (oauthCtx.namespaceWritePrefixes ?? []).filter((p) => typeof p === "string" && p.length > 0);
33
+ if (prefixes.length === 0) {
34
+ deny("no-write-prefixes", "This caller holds no namespace write prefix.");
35
+ }
36
+ if (!prefixes.some((p) => namespaceMatchesPrefix(namespace, p))) {
37
+ deny("namespace-write-denied", "The namespace is outside this caller's write prefixes.");
38
+ }
39
+ }
40
+ //# sourceMappingURL=namespace-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace-write.js","sourceRoot":"","sources":["../src/namespace-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAG1E;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAkB,EAClB,SAAiB,EACjB,IAAI,GAAG,sBAAsB;IAE7B,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,SAAS,CACjB,yEAAyE,CAC1E,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,CACX,MAA4E,EAC5E,MAAc,EACP,EAAE;QACT,MAAM,IAAI,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/E,CAAC,CAAC;IAEF,IAAI,aAAa,CAAC,QAAQ,CAAC;QAAE,OAAO;IAEpC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,mBAAmB,EAAE,oCAAoC,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,MAAM,CAC7D,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAC7C,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,mBAAmB,EAAE,8CAA8C,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,wBAAwB,EAAE,wDAAwD,CAAC,CAAC;IAC3F,CAAC;AACH,CAAC"}
@@ -178,8 +178,8 @@ export declare function resolvePersonTenantAccess(input: {
178
178
  type WriterRoleInput = {
179
179
  /** The VERIFIED role claim of the token. Absent or null is refused. */
180
180
  role: string | null | undefined;
181
- /** The writer allowlist the consumer holds as data. Empty refuses all. */
182
- writerRoles: readonly string[];
181
+ /** The writer allowlist the consumer holds as data. Absent or empty refuses all. */
182
+ writerRoles: readonly string[] | null | undefined;
183
183
  door: string;
184
184
  orgSlug?: string | null;
185
185
  };
@@ -1 +1 @@
1
- {"version":3,"file":"person-principal.d.ts","sourceRoot":"","sources":["../src/person-principal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"person-principal.d.ts","sourceRoot":"","sources":["../src/person-principal.ts"],"names":[],"mappings":"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"}
@@ -201,7 +201,8 @@ export function resolvePersonTenantAccess(input) {
201
201
  */
202
202
  export function resolveWriterRole(input) {
203
203
  const role = input.role ?? null;
204
- if (role !== null && input.writerRoles.includes(role))
204
+ const writerRoles = input.writerRoles ?? [];
205
+ if (role !== null && writerRoles.includes(role))
205
206
  return { ok: true };
206
207
  return {
207
208
  ok: false,
@@ -1 +1 @@
1
- {"version":3,"file":"person-principal.js","sourceRoot":"","sources":["../src/person-principal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"person-principal.js","sourceRoot":"","sources":["../src/person-principal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Role policy as DATA: a minimum-role check over a caller-supplied order, and a
3
+ * role-claim mapping with no package-chosen default.
4
+ *
5
+ * The package never knows what roles exist. "admin > editor > viewer" is one
6
+ * consumer's vocabulary, passed in at the call site; another consumer passes
7
+ * another. Every absence (no role, unknown role, empty order, no mapping, no
8
+ * fallback) is a refusal, never a default grant.
9
+ *
10
+ * Pure functions: no framework SDK, no I/O.
11
+ */
12
+ import { type IdentityRefusal } from "./identity-refusal.js";
13
+ export type MinRoleInput = {
14
+ /** The verified role of the caller. null/undefined/"" is "no role". */
15
+ role: string | null | undefined;
16
+ /** The least-privileged role that is admitted. Must appear in `order`. */
17
+ minimum: string;
18
+ /**
19
+ * The caller's ordered role list, MOST privileged FIRST
20
+ * (e.g. `["admin", "editor", "viewer"]`). No empty list, no duplicates.
21
+ */
22
+ order: readonly string[];
23
+ /** The consumer's own name for the entry point. Defaults to the function name. */
24
+ door?: string;
25
+ };
26
+ export type MinRoleResult = {
27
+ ok: true;
28
+ role: string;
29
+ } | {
30
+ ok: false;
31
+ refusal: IdentityRefusal;
32
+ };
33
+ /**
34
+ * Admit `role` when it is at or above `minimum` in `order`.
35
+ *
36
+ * Refuses: an invalid order (empty, duplicated, non-string entries), a
37
+ * `minimum` outside the order, a missing or unknown role, a role below the
38
+ * minimum. Matching is exact (no case-folding), and a role is only ever found
39
+ * by array position, so `"constructor"` or `"__proto__"` are unknown roles.
40
+ */
41
+ export declare function resolveMinRole(input: MinRoleInput): MinRoleResult;
42
+ /** Throwing form of {@link resolveMinRole}; returns the role, throws `IdentityRefusalError`. */
43
+ export declare function assertMinRole(input: MinRoleInput): string;
44
+ export type MapRoleClaimInput = {
45
+ /** The raw claim from the verified credential. Only a non-empty string counts. */
46
+ claim: unknown;
47
+ /** Claim value -> consumer role. Data supplied by the caller. */
48
+ mapping: Readonly<Record<string, string>>;
49
+ /**
50
+ * The role to use when the claim is absent or not in `mapping`. The package
51
+ * never picks one: omit it and an absent or unmapped claim is REFUSED.
52
+ * Supply the least-privileged role you have.
53
+ */
54
+ fallback?: string;
55
+ door?: string;
56
+ };
57
+ export type MapRoleClaimResult = {
58
+ ok: true;
59
+ role: string;
60
+ source: "mapped" | "fallback";
61
+ } | {
62
+ ok: false;
63
+ refusal: IdentityRefusal;
64
+ };
65
+ /**
66
+ * Map a verified role claim to the consumer's role, with a least-privilege
67
+ * fallback that the CALLER must name. A claim that is not a string (array,
68
+ * object, number) is absent, never coerced. Lookup uses own keys only, so a
69
+ * claim of `"constructor"` is unmapped.
70
+ */
71
+ export declare function mapRoleClaim(input: MapRoleClaimInput): MapRoleClaimResult;
72
+ //# sourceMappingURL=role-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-policy.d.ts","sourceRoot":"","sources":["../src/role-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAS/B,MAAM,MAAM,YAAY,GAAG;IACzB,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CA2DjE;AAED,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAIzD;AAMD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC;IACf,iEAAiE;IACjE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAA;CAAE,GACzD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAgDzE"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Role policy as DATA: a minimum-role check over a caller-supplied order, and a
3
+ * role-claim mapping with no package-chosen default.
4
+ *
5
+ * The package never knows what roles exist. "admin > editor > viewer" is one
6
+ * consumer's vocabulary, passed in at the call site; another consumer passes
7
+ * another. Every absence (no role, unknown role, empty order, no mapping, no
8
+ * fallback) is a refusal, never a default grant.
9
+ *
10
+ * Pure functions: no framework SDK, no I/O.
11
+ */
12
+ import { IdentityRefusalError, refusal, } from "./identity-refusal.js";
13
+ const DOOR_MIN = "resolveMinRole";
14
+ const DOOR_MAP = "mapRoleClaim";
15
+ /**
16
+ * Admit `role` when it is at or above `minimum` in `order`.
17
+ *
18
+ * Refuses: an invalid order (empty, duplicated, non-string entries), a
19
+ * `minimum` outside the order, a missing or unknown role, a role below the
20
+ * minimum. Matching is exact (no case-folding), and a role is only ever found
21
+ * by array position, so `"constructor"` or `"__proto__"` are unknown roles.
22
+ */
23
+ export function resolveMinRole(input) {
24
+ const door = input.door ?? DOOR_MIN;
25
+ const { order, role, minimum } = input;
26
+ const orderValid = Array.isArray(order) &&
27
+ order.length > 0 &&
28
+ order.every((r) => typeof r === "string" && r.length > 0) &&
29
+ new Set(order).size === order.length;
30
+ if (!orderValid) {
31
+ return {
32
+ ok: false,
33
+ refusal: refusal("RBAC_DENIED", "invalid-role-order", door, "The role order must be a non-empty list of distinct role names."),
34
+ };
35
+ }
36
+ const minIndex = order.indexOf(minimum);
37
+ if (minIndex === -1) {
38
+ return {
39
+ ok: false,
40
+ refusal: refusal("RBAC_DENIED", "unknown-minimum-role", door, "The required minimum role is not part of the role order."),
41
+ };
42
+ }
43
+ const roleIndex = typeof role === "string" && role.length > 0 ? order.indexOf(role) : -1;
44
+ if (roleIndex === -1) {
45
+ return {
46
+ ok: false,
47
+ refusal: refusal("RBAC_DENIED", "unknown-role", door, "The caller's role is absent or not part of the role order."),
48
+ };
49
+ }
50
+ if (roleIndex > minIndex) {
51
+ return {
52
+ ok: false,
53
+ refusal: refusal("RBAC_DENIED", "role-below-minimum", door, "The caller's role is below the required minimum."),
54
+ };
55
+ }
56
+ return { ok: true, role: order[roleIndex] };
57
+ }
58
+ /** Throwing form of {@link resolveMinRole}; returns the role, throws `IdentityRefusalError`. */
59
+ export function assertMinRole(input) {
60
+ const result = resolveMinRole(input);
61
+ if (!result.ok)
62
+ throw new IdentityRefusalError(result.refusal);
63
+ return result.role;
64
+ }
65
+ /**
66
+ * Map a verified role claim to the consumer's role, with a least-privilege
67
+ * fallback that the CALLER must name. A claim that is not a string (array,
68
+ * object, number) is absent, never coerced. Lookup uses own keys only, so a
69
+ * claim of `"constructor"` is unmapped.
70
+ */
71
+ export function mapRoleClaim(input) {
72
+ const door = input.door ?? DOOR_MAP;
73
+ const { claim, mapping, fallback } = input;
74
+ if (mapping === null || typeof mapping !== "object" || Array.isArray(mapping)) {
75
+ return {
76
+ ok: false,
77
+ refusal: refusal("RBAC_DENIED", "invalid-role-mapping", door, "The role mapping must be a plain object of claim to role."),
78
+ };
79
+ }
80
+ const present = typeof claim === "string" && claim.length > 0;
81
+ if (present && Object.hasOwn(mapping, claim)) {
82
+ const mapped = mapping[claim];
83
+ if (typeof mapped === "string" && mapped.length > 0) {
84
+ return { ok: true, role: mapped, source: "mapped" };
85
+ }
86
+ return {
87
+ ok: false,
88
+ refusal: refusal("RBAC_DENIED", "invalid-role-mapping", door, "The role mapping holds a non-string or empty role."),
89
+ };
90
+ }
91
+ if (typeof fallback === "string" && fallback.length > 0) {
92
+ return { ok: true, role: fallback, source: "fallback" };
93
+ }
94
+ return {
95
+ ok: false,
96
+ refusal: refusal("RBAC_DENIED", present ? "role-claim-unmapped" : "role-claim-absent", door, present
97
+ ? "The role claim is not in the mapping and no fallback was supplied."
98
+ : "No role claim was presented and no fallback was supplied."),
99
+ };
100
+ }
101
+ //# sourceMappingURL=role-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-policy.js","sourceRoot":"","sources":["../src/role-policy.ts"],"names":[],"mappings":"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"}
@@ -61,6 +61,13 @@ import type { OAuthCtx } from "./types.js";
61
61
  * and pass it BY NAME. It is never inferred from an omitted argument.
62
62
  */
63
63
  export declare const LEGACY_WILDCARD_CTX: OAuthCtx;
64
+ /**
65
+ * THE path-boundary rule for namespaces: `namespace` is inside `prefix` when it
66
+ * equals it, or continues it after a '/'. `team/finance-archive` is NOT inside
67
+ * `team/finance`. One implementation, used by the read filter and by
68
+ * `assertNamespaceWrite`, so the two can never drift apart.
69
+ */
70
+ export declare function namespaceMatchesPrefix(namespace: string, prefix: string): boolean;
64
71
  /**
65
72
  * Row shape accepted by the scope filter. All fields optional because real
66
73
  * Convex documents from list_peers / list_messages / etc. don't all carry both.
@@ -1 +1 @@
1
- {"version":3,"file":"scope-filter.d.ts","sourceRoot":"","sources":["../src/scope-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAKjC,CAAC;AAWF;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAIpD;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,MAAM,EAAE,CAAC;AActD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,eAAe,EACzD,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,CAAC,EACN,WAAW,GAAE,qBAAuC,GACnD,OAAO,CAgBT;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,eAAe,EACvD,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,EAAE,EACT,WAAW,GAAE,qBAAuC,GACnD,CAAC,EAAE,CAGL;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,eAAe,EACtD,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EACzB,WAAW,GAAE,qBAAuC,GACnD,CAAC,GAAG,IAAI,CAIV;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAGtD"}
1
+ {"version":3,"file":"scope-filter.d.ts","sourceRoot":"","sources":["../src/scope-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAKjC,CAAC;AAWF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjF;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAIpD;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,MAAM,EAAE,CAAC;AActD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,eAAe,EACzD,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,CAAC,EACN,WAAW,GAAE,qBAAuC,GACnD,OAAO,CAeT;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,eAAe,EACvD,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,EAAE,EACT,WAAW,GAAE,qBAAuC,GACnD,CAAC,EAAE,CAGL;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,eAAe,EACtD,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EACzB,WAAW,GAAE,qBAAuC,GACnD,CAAC,GAAG,IAAI,CAIV;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAGtD"}
@@ -71,6 +71,15 @@ function assertOauthCtx(oauthCtx) {
71
71
  "if you deliberately want the pre-0.3.0 legacy-bearer wildcard behaviour.");
72
72
  }
73
73
  }
74
+ /**
75
+ * THE path-boundary rule for namespaces: `namespace` is inside `prefix` when it
76
+ * equals it, or continues it after a '/'. `team/finance-archive` is NOT inside
77
+ * `team/finance`. One implementation, used by the read filter and by
78
+ * `assertNamespaceWrite`, so the two can never drift apart.
79
+ */
80
+ export function namespaceMatchesPrefix(namespace, prefix) {
81
+ return namespace === prefix || namespace.startsWith(`${prefix}/`);
82
+ }
74
83
  /**
75
84
  * Returns true when the scope profile grants full, wildcard access.
76
85
  * Mirrors `isMasterScope` from the source module: `scope === "master"` OR
@@ -126,9 +135,7 @@ export function passesScopeFilter(oauthCtx, row, grantFields = NO_GRANT_FIELDS)
126
135
  return true;
127
136
  if (namespace) {
128
137
  for (const p of oauthCtx.namespaceReadPrefixes) {
129
- if (namespace === p)
130
- return true;
131
- if (namespace.startsWith(`${p}/`))
138
+ if (namespaceMatchesPrefix(namespace, p))
132
139
  return true;
133
140
  }
134
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scope-filter.js","sourceRoot":"","sources":["../src/scope-filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scope-filter.js","sourceRoot":"","sources":["../src/scope-filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Synchronous constant-time secret comparison.
3
+ *
4
+ * `timingSafeEqual` in `./crypto` is async (it uses Web Crypto for its dummy
5
+ * work) and takes bytes. A synchronous call site — a plain admin-secret gate,
6
+ * a framework hook that cannot await — needs a synchronous equivalent. This is
7
+ * pure JavaScript with no runtime dependency, so it also runs on any edge
8
+ * runtime. The async comparator is unchanged.
9
+ *
10
+ * Constant time here means: the number of loop iterations depends only on the
11
+ * LONGER input's length, never on where the first difference is. JavaScript
12
+ * gives no hard timing guarantee; this removes the content-dependent early
13
+ * exit, which is the leak a naive `===` has.
14
+ */
15
+ /**
16
+ * Compare two strings (UTF-8) or byte arrays in constant time with respect to
17
+ * their content. Always walks the longer length; a length difference is folded
18
+ * into the result rather than returned early. Any other input type is `false`.
19
+ */
20
+ export declare function timingSafeEqualSync(a: string | Uint8Array, b: string | Uint8Array): boolean;
21
+ /**
22
+ * Assert a presented secret equals the configured one. Throws
23
+ * `IdentityRefusalError` (`CREDENTIAL_REFUSED`) on mismatch. An unset expected
24
+ * secret (undefined, null, empty) matches NOTHING, not even an empty
25
+ * presentation: a missing configuration must never open a door. The refusal
26
+ * carries neither value.
27
+ */
28
+ export declare function assertSecretSync(presented: string | Uint8Array | null | undefined, expected: string | Uint8Array | null | undefined, door?: string): void;
29
+ //# sourceMappingURL=secret-compare-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-compare-sync.d.ts","sourceRoot":"","sources":["../src/secret-compare-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,MAAM,GAAG,UAAU,EACtB,CAAC,EAAE,MAAM,GAAG,UAAU,GACrB,OAAO,CAcT;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,EACjD,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,EAChD,IAAI,SAAqB,GACxB,IAAI,CAyBN"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Synchronous constant-time secret comparison.
3
+ *
4
+ * `timingSafeEqual` in `./crypto` is async (it uses Web Crypto for its dummy
5
+ * work) and takes bytes. A synchronous call site — a plain admin-secret gate,
6
+ * a framework hook that cannot await — needs a synchronous equivalent. This is
7
+ * pure JavaScript with no runtime dependency, so it also runs on any edge
8
+ * runtime. The async comparator is unchanged.
9
+ *
10
+ * Constant time here means: the number of loop iterations depends only on the
11
+ * LONGER input's length, never on where the first difference is. JavaScript
12
+ * gives no hard timing guarantee; this removes the content-dependent early
13
+ * exit, which is the leak a naive `===` has.
14
+ */
15
+ import { IdentityRefusalError, refusal } from "./identity-refusal.js";
16
+ const encoder = new TextEncoder();
17
+ function toBytes(value) {
18
+ if (typeof value === "string")
19
+ return encoder.encode(value);
20
+ if (value instanceof Uint8Array)
21
+ return value;
22
+ return null;
23
+ }
24
+ /**
25
+ * Compare two strings (UTF-8) or byte arrays in constant time with respect to
26
+ * their content. Always walks the longer length; a length difference is folded
27
+ * into the result rather than returned early. Any other input type is `false`.
28
+ */
29
+ export function timingSafeEqualSync(a, b) {
30
+ const x = toBytes(a);
31
+ const y = toBytes(b);
32
+ if (x === null || y === null)
33
+ return false;
34
+ const xl = x.length;
35
+ const yl = y.length;
36
+ const max = xl > yl ? xl : yl;
37
+ let diff = xl ^ yl;
38
+ for (let i = 0; i < max; i++) {
39
+ const xi = i < xl ? x[i] : 0;
40
+ const yi = i < yl ? y[i] : 0;
41
+ diff |= xi ^ yi;
42
+ }
43
+ return diff === 0;
44
+ }
45
+ /**
46
+ * Assert a presented secret equals the configured one. Throws
47
+ * `IdentityRefusalError` (`CREDENTIAL_REFUSED`) on mismatch. An unset expected
48
+ * secret (undefined, null, empty) matches NOTHING, not even an empty
49
+ * presentation: a missing configuration must never open a door. The refusal
50
+ * carries neither value.
51
+ */
52
+ export function assertSecretSync(presented, expected, door = "assertSecretSync") {
53
+ const expectedBytes = toBytes(expected);
54
+ if (expectedBytes === null || expectedBytes.length === 0) {
55
+ throw new IdentityRefusalError(refusal("CREDENTIAL_REFUSED", "secret-not-configured", door, "No secret is configured for this entry point, so nothing can match."));
56
+ }
57
+ const presentedBytes = toBytes(presented) ?? new Uint8Array(0);
58
+ // Compare even when presented is empty so the work does not depend on it.
59
+ const equal = timingSafeEqualSync(presentedBytes, expectedBytes);
60
+ if (!equal || presentedBytes.length === 0) {
61
+ throw new IdentityRefusalError(refusal("CREDENTIAL_REFUSED", "secret-mismatch", door, "The presented secret does not match."));
62
+ }
63
+ }
64
+ //# sourceMappingURL=secret-compare-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-compare-sync.js","sourceRoot":"","sources":["../src/secret-compare-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,SAAS,OAAO,CAAC,KAAc;IAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,KAAK,YAAY,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,CAAsB,EACtB,CAAsB;IAEtB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;IACpB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;IACpB,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9B,IAAI,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAiD,EACjD,QAAgD,EAChD,IAAI,GAAG,kBAAkB;IAEzB,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,aAAa,KAAK,IAAI,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,oBAAoB,CAC5B,OAAO,CACL,oBAAoB,EACpB,uBAAuB,EACvB,IAAI,EACJ,qEAAqE,CACtE,CACF,CAAC;IACJ,CAAC;IACD,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,KAAK,GAAG,mBAAmB,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;IACjE,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,oBAAoB,CAC5B,OAAO,CACL,oBAAoB,EACpB,iBAAiB,EACjB,IAAI,EACJ,sCAAsC,CACvC,CACF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Membership resolution, row-in-tenant visibility and the org-admin proof.
3
+ *
4
+ * The package cannot query a datastore, so the membership read is an INJECTED
5
+ * async lookup. Everything that can be got wrong stays here: a throwing lookup,
6
+ * a miss, an inactive row, a row of the wrong shape and a row that names a
7
+ * different organisation are all refusals. Nothing in this module returns a
8
+ * grant on an error path.
9
+ *
10
+ * Identifiers are OPAQUE and compared byte-for-byte: no trimming, no case
11
+ * folding, and never a slug compared against an id (supply the same kind of
12
+ * identifier on both sides).
13
+ */
14
+ import { z } from "zod";
15
+ import { type IdentityRefusal } from "./identity-refusal.js";
16
+ /**
17
+ * True only when the row is stamped with an organisation, the caller has one,
18
+ * and the two are strictly equal. An unstamped row is NEVER visible, including
19
+ * to a caller that also has no organisation (absence equals absence is not a
20
+ * match).
21
+ */
22
+ export declare function isRowInTenant(input: {
23
+ rowOrgId: string | null | undefined;
24
+ callerOrgId: string | null | undefined;
25
+ }): boolean;
26
+ /**
27
+ * What the consumer's lookup returns for (subject, organisation).
28
+ * `orgId`, when the row carries it, is re-checked here so a loose lookup (a
29
+ * prefix match, a wrong index) cannot become a membership in another org.
30
+ */
31
+ export declare const membershipRecordSchema: z.ZodObject<{
32
+ active: z.ZodBoolean;
33
+ role: z.ZodOptional<z.ZodNullable<z.ZodString>>;
34
+ orgId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
+ }, z.core.$strip>;
36
+ export type MembershipRecord = z.infer<typeof membershipRecordSchema>;
37
+ export type ResolvedMembership = {
38
+ subject: string;
39
+ orgId: string;
40
+ /** The role the record carries, or null when it carries none. */
41
+ role: string | null;
42
+ };
43
+ export type ResolveMembershipInput = {
44
+ /** The verified subject. Never a client-supplied argument. */
45
+ subject: string;
46
+ /** The verified organisation id. */
47
+ orgId: string;
48
+ /** Indexed read of one membership. Return null/undefined on a miss. */
49
+ lookup: (subject: string, orgId: string) => Promise<MembershipRecord | null | undefined> | MembershipRecord | null | undefined;
50
+ door?: string;
51
+ };
52
+ export type ResolveMembershipResult = {
53
+ ok: true;
54
+ membership: ResolvedMembership;
55
+ } | {
56
+ ok: false;
57
+ refusal: IdentityRefusal;
58
+ };
59
+ /**
60
+ * Resolve the membership of a verified subject in a verified organisation via
61
+ * the injected `lookup`. Only `active === true` on a well-shaped record that
62
+ * names no other organisation is served. The lookup's own error text is never
63
+ * surfaced.
64
+ */
65
+ export declare function resolveMembership(input: ResolveMembershipInput): Promise<ResolveMembershipResult>;
66
+ export type RequireOrgAdminInput = {
67
+ /** The organisation the credential was VERIFIED for (a verified claim). */
68
+ verifiedOrgId: string | null | undefined;
69
+ /** The organisation the action is aimed at. Must equal `verifiedOrgId`. */
70
+ targetOrgId: string | null | undefined;
71
+ /** The caller's verified role. */
72
+ role: string | null | undefined;
73
+ /** Roles that count as organisation admin: data, supplied by the consumer. */
74
+ adminRoles: readonly string[];
75
+ door?: string;
76
+ };
77
+ /**
78
+ * An org-admin proof is bound to the caller's own verified organisation: the
79
+ * target must equal it, and the role must be one of `adminRoles`. Being an
80
+ * admin somewhere is not being an admin of the target. Throws
81
+ * `IdentityRefusalError`; returns nothing when served. An empty `adminRoles`
82
+ * admits nobody.
83
+ */
84
+ export declare function requireOrgAdmin(input: RequireOrgAdminInput): void;
85
+ //# sourceMappingURL=tenant-membership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-membership.d.ts","sourceRoot":"","sources":["../src/tenant-membership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAU/B;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACxC,GAAG,OAAO,CAGV;AAMD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;iBAIjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,MAAM,EAAE,CACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;IACxF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,kBAAkB,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAU5C;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CA4ClC;AAMD,MAAM,MAAM,oBAAoB,GAAG;IACjC,2EAA2E;IAC3E,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,2EAA2E;IAC3E,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,kCAAkC;IAClC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,8EAA8E;IAC9E,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAmBjE"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Membership resolution, row-in-tenant visibility and the org-admin proof.
3
+ *
4
+ * The package cannot query a datastore, so the membership read is an INJECTED
5
+ * async lookup. Everything that can be got wrong stays here: a throwing lookup,
6
+ * a miss, an inactive row, a row of the wrong shape and a row that names a
7
+ * different organisation are all refusals. Nothing in this module returns a
8
+ * grant on an error path.
9
+ *
10
+ * Identifiers are OPAQUE and compared byte-for-byte: no trimming, no case
11
+ * folding, and never a slug compared against an id (supply the same kind of
12
+ * identifier on both sides).
13
+ */
14
+ import { z } from "zod";
15
+ import { IdentityRefusalError, refusal, } from "./identity-refusal.js";
16
+ function nonEmpty(value) {
17
+ return typeof value === "string" && value.length > 0;
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Row in tenant
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * True only when the row is stamped with an organisation, the caller has one,
24
+ * and the two are strictly equal. An unstamped row is NEVER visible, including
25
+ * to a caller that also has no organisation (absence equals absence is not a
26
+ * match).
27
+ */
28
+ export function isRowInTenant(input) {
29
+ const { rowOrgId, callerOrgId } = input;
30
+ return nonEmpty(rowOrgId) && nonEmpty(callerOrgId) && rowOrgId === callerOrgId;
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Membership
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * What the consumer's lookup returns for (subject, organisation).
37
+ * `orgId`, when the row carries it, is re-checked here so a loose lookup (a
38
+ * prefix match, a wrong index) cannot become a membership in another org.
39
+ */
40
+ export const membershipRecordSchema = z.object({
41
+ active: z.boolean(),
42
+ role: z.string().nullish(),
43
+ orgId: z.string().nullish(),
44
+ });
45
+ function deny(reason, door, detail) {
46
+ return { ok: false, refusal: refusal("RBAC_DENIED", reason, door, detail) };
47
+ }
48
+ /**
49
+ * Resolve the membership of a verified subject in a verified organisation via
50
+ * the injected `lookup`. Only `active === true` on a well-shaped record that
51
+ * names no other organisation is served. The lookup's own error text is never
52
+ * surfaced.
53
+ */
54
+ export async function resolveMembership(input) {
55
+ const door = input.door ?? "resolveMembership";
56
+ if (typeof input?.lookup !== "function") {
57
+ // A programming error in the consumer, not a claim about any caller.
58
+ throw new TypeError("resolveMembership: lookup must be a function.");
59
+ }
60
+ const { subject, orgId, lookup } = input;
61
+ if (!nonEmpty(subject) || !nonEmpty(orgId)) {
62
+ return deny("membership-invalid-input", door, "A verified subject and a verified organisation are both required.");
63
+ }
64
+ let record;
65
+ try {
66
+ record = await lookup(subject, orgId);
67
+ }
68
+ catch {
69
+ return deny("membership-lookup-failed", door, "The membership could not be read, so none is granted.");
70
+ }
71
+ if (record === null || record === undefined) {
72
+ return deny("membership-not-found", door, "No membership for this subject in this organisation.");
73
+ }
74
+ const parsed = membershipRecordSchema.safeParse(record);
75
+ if (!parsed.success) {
76
+ return deny("membership-record-invalid", door, "The membership record is not well formed.");
77
+ }
78
+ const row = parsed.data;
79
+ if (nonEmpty(row.orgId) && row.orgId !== orgId) {
80
+ return deny("other-organisation", door, "The membership belongs to another organisation.");
81
+ }
82
+ if (row.active !== true) {
83
+ return deny("membership-inactive", door, "The membership is not active.");
84
+ }
85
+ return {
86
+ ok: true,
87
+ membership: { subject, orgId, role: nonEmpty(row.role) ? row.role : null },
88
+ };
89
+ }
90
+ /**
91
+ * An org-admin proof is bound to the caller's own verified organisation: the
92
+ * target must equal it, and the role must be one of `adminRoles`. Being an
93
+ * admin somewhere is not being an admin of the target. Throws
94
+ * `IdentityRefusalError`; returns nothing when served. An empty `adminRoles`
95
+ * admits nobody.
96
+ */
97
+ export function requireOrgAdmin(input) {
98
+ const door = input.door ?? "requireOrgAdmin";
99
+ const { verifiedOrgId, targetOrgId, role, adminRoles } = input;
100
+ const fail = (reason, detail) => {
101
+ throw new IdentityRefusalError(refusal("RBAC_DENIED", reason, door, detail));
102
+ };
103
+ if (!nonEmpty(verifiedOrgId)) {
104
+ fail("no-verified-organisation", "The caller has no verified organisation.");
105
+ }
106
+ if (!nonEmpty(targetOrgId) || targetOrgId !== verifiedOrgId) {
107
+ fail("other-organisation", "The target organisation is not the caller's verified organisation.");
108
+ }
109
+ if (!nonEmpty(role) || !Array.isArray(adminRoles) || !adminRoles.includes(role)) {
110
+ fail("role-not-admin", "The caller's role is not an organisation-admin role.");
111
+ }
112
+ }
113
+ //# sourceMappingURL=tenant-membership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-membership.js","sourceRoot":"","sources":["../src/tenant-membership.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vantageos/cloud-identity",
3
- "version": "0.9.0",
3
+ "version": "0.10.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",
@@ -57,6 +57,26 @@
57
57
  "./person-principal": {
58
58
  "types": "./dist/person-principal.d.ts",
59
59
  "import": "./dist/person-principal.js"
60
+ },
61
+ "./identity-refusal": {
62
+ "types": "./dist/identity-refusal.d.ts",
63
+ "import": "./dist/identity-refusal.js"
64
+ },
65
+ "./role-policy": {
66
+ "types": "./dist/role-policy.d.ts",
67
+ "import": "./dist/role-policy.js"
68
+ },
69
+ "./tenant-membership": {
70
+ "types": "./dist/tenant-membership.d.ts",
71
+ "import": "./dist/tenant-membership.js"
72
+ },
73
+ "./namespace-write": {
74
+ "types": "./dist/namespace-write.d.ts",
75
+ "import": "./dist/namespace-write.js"
76
+ },
77
+ "./secret-compare-sync": {
78
+ "types": "./dist/secret-compare-sync.d.ts",
79
+ "import": "./dist/secret-compare-sync.js"
60
80
  }
61
81
  },
62
82
  "files": [