@aooth/arbac 0.1.85 → 0.2.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/dist/index.cjs CHANGED
@@ -997,7 +997,12 @@ function mergePartScope(shared, part) {
997
997
  function composeScope(shared, part) {
998
998
  if (!part) return shared;
999
999
  if (!shared) return part;
1000
- return (attrs, userId) => mergePartScope(shared(attrs, userId), part(attrs, userId));
1000
+ return (attrs, userId) => {
1001
+ const s = shared(attrs, userId);
1002
+ if (s == null) return s;
1003
+ const p = part(attrs, userId);
1004
+ return p == null ? p : mergePartScope(s, p);
1005
+ };
1001
1006
  }
1002
1007
  /**
1003
1008
  * One table policy → consistent rules for every endpoint of an
package/dist/index.d.cts CHANGED
@@ -27,7 +27,7 @@ interface RoleBuilder<TUserAttrs, TScope> {
27
27
  * Append an allow rule for a (resource, action) pair, with an optional scope
28
28
  * function that derives a scope object from user attrs.
29
29
  */
30
- allow(resource: string, action: string, scope?: (attrs: TUserAttrs, userId: string) => TScope): RoleBuilder<TUserAttrs, TScope>;
30
+ allow(resource: string, action: string, scope?: (attrs: TUserAttrs, userId: string) => TScope | null | undefined): RoleBuilder<TUserAttrs, TScope>;
31
31
  /** Append a deny rule (`effect: 'deny'`) for a (resource, action) pair. */
32
32
  deny(resource: string, action: string): RoleBuilder<TUserAttrs, TScope>;
33
33
  /**
@@ -140,7 +140,8 @@ type TTableOp = "read" | "meta" | "insert" | "update" | "replace" | "remove";
140
140
  * for write-only principals that still render forms from `/meta`.
141
141
  */
142
142
  declare const TABLE_OP_ACTIONS: Readonly<Record<TTableOp, readonly string[]>>;
143
- type ScopeFn<TUserAttrs, TScope> = (attrs: TUserAttrs, userId: string) => TScope;
143
+ /** A rule scope; `null` / `undefined` = this rule admits nothing (deny for it). */
144
+ type ScopeFn<TUserAttrs, TScope> = (attrs: TUserAttrs, userId: string) => TScope | null | undefined;
144
145
  interface ScopeOpts<TUserAttrs, TScope> {
145
146
  scope?: ScopeFn<TUserAttrs, TScope>;
146
147
  }
package/dist/index.d.mts CHANGED
@@ -27,7 +27,7 @@ interface RoleBuilder<TUserAttrs, TScope> {
27
27
  * Append an allow rule for a (resource, action) pair, with an optional scope
28
28
  * function that derives a scope object from user attrs.
29
29
  */
30
- allow(resource: string, action: string, scope?: (attrs: TUserAttrs, userId: string) => TScope): RoleBuilder<TUserAttrs, TScope>;
30
+ allow(resource: string, action: string, scope?: (attrs: TUserAttrs, userId: string) => TScope | null | undefined): RoleBuilder<TUserAttrs, TScope>;
31
31
  /** Append a deny rule (`effect: 'deny'`) for a (resource, action) pair. */
32
32
  deny(resource: string, action: string): RoleBuilder<TUserAttrs, TScope>;
33
33
  /**
@@ -140,7 +140,8 @@ type TTableOp = "read" | "meta" | "insert" | "update" | "replace" | "remove";
140
140
  * for write-only principals that still render forms from `/meta`.
141
141
  */
142
142
  declare const TABLE_OP_ACTIONS: Readonly<Record<TTableOp, readonly string[]>>;
143
- type ScopeFn<TUserAttrs, TScope> = (attrs: TUserAttrs, userId: string) => TScope;
143
+ /** A rule scope; `null` / `undefined` = this rule admits nothing (deny for it). */
144
+ type ScopeFn<TUserAttrs, TScope> = (attrs: TUserAttrs, userId: string) => TScope | null | undefined;
144
145
  interface ScopeOpts<TUserAttrs, TScope> {
145
146
  scope?: ScopeFn<TUserAttrs, TScope>;
146
147
  }
package/dist/index.mjs CHANGED
@@ -997,7 +997,12 @@ function mergePartScope(shared, part) {
997
997
  function composeScope(shared, part) {
998
998
  if (!part) return shared;
999
999
  if (!shared) return part;
1000
- return (attrs, userId) => mergePartScope(shared(attrs, userId), part(attrs, userId));
1000
+ return (attrs, userId) => {
1001
+ const s = shared(attrs, userId);
1002
+ if (s == null) return s;
1003
+ const p = part(attrs, userId);
1004
+ return p == null ? p : mergePartScope(s, p);
1005
+ };
1001
1006
  }
1002
1007
  /**
1003
1008
  * One table policy → consistent rules for every endpoint of an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aooth/arbac",
3
- "version": "0.1.85",
3
+ "version": "0.2.0",
4
4
  "description": "Batteries-included RBAC: builder API, privilege factories, scope merge utilities",
5
5
  "keywords": [
6
6
  "access-control",
@@ -45,7 +45,7 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@aooth/arbac-core": "0.1.85"
48
+ "@aooth/arbac-core": "0.2.0"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "vp pack",