@voltro/plugin-rbac 0.80.0 → 0.82.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.d.ts CHANGED
@@ -54,7 +54,7 @@ export declare const compileRoles: (roleSlugs: ReadonlyArray<string>, roleMap: R
54
54
  * tenant-aware role assignments Just Work). Drop into
55
55
  * `rbacPlugin({ resolveRoles: dataStoreRoleResolver(userRoleStore(ds)) })`.
56
56
  */
57
- export declare const dataStoreRoleResolver: (store: UserRoleStore) => RoleResolver;
57
+ export declare const dataStoreRoleResolver: (store?: UserRoleStore) => RoleResolver;
58
58
 
59
59
  /**
60
60
  * Compile a subject's roles + raw permissions into one resolved scope
@@ -260,9 +260,20 @@ export declare type RoleMap = Readonly<Record<string, ReadonlyArray<string>>>;
260
260
  * A resolver that yields the role slugs a subject holds. The default
261
261
  * reads `subject.metadata.roles` (a `string[]`) when present; a project
262
262
  * that assigns roles at runtime supplies its own (e.g. a DB lookup
263
- * filtered by `subject.tenantId`).
263
+ * filtered by `subject.tenantId`, reading `context.store`).
264
264
  */
265
- export declare type RoleResolver = (subject: Subject) => ReadonlyArray<string> | Promise<ReadonlyArray<string>>;
265
+ export declare type RoleResolver = (subject: Subject, context?: RoleResolverContext) => ReadonlyArray<string> | Promise<ReadonlyArray<string>>;
266
+
267
+ /** What a {@link RoleResolver} is handed beside the subject. */
268
+ export declare interface RoleResolverContext {
269
+ /**
270
+ * The app's store, bound at boot (`bindDataStore`). `app.config.ts` is
271
+ * evaluated before any store exists, so a resolver that reads assignments
272
+ * takes it from here rather than closing over one. `undefined` only before
273
+ * boot has bound it.
274
+ */
275
+ readonly store?: UserRoleDataStore;
276
+ }
266
277
 
267
278
  export declare const ROLES_TABLE = "_voltro_rbac_roles";
268
279
 
package/dist/index.js CHANGED
@@ -10,12 +10,12 @@ var j = "_voltro_rbac_roles", M = "_voltro_rbac_user_roles", N = k(j, {
10
10
  name: A(),
11
11
  permissions: T(),
12
12
  isDefault: S().default(!1)
13
- }).index("byRolesSlug", ["slug"]), P = (e = {}) => k(M, {
13
+ }).index("_voltro_rbac_roles_by_slug", ["slug"]), P = (e = {}) => k(M, {
14
14
  id: w({ prefix: "urole" }),
15
15
  userId: A(),
16
16
  tenantId: e.multitenant ? D(O(), { index: !1 }).nullable() : A().nullable(),
17
17
  roleSlug: A()
18
- }).index("byUserTenant", ["userId", "tenantId"]).index("byRoleSlug", ["roleSlug"]), F = P(), I = (e = {}) => [N, P(e)], L = (e, t) => e.query({
18
+ }).index("_voltro_rbac_user_roles_by_user_tenant", ["userId", "tenantId"]).index("_voltro_rbac_user_roles_by_role_slug", ["roleSlug"]), F = P(), I = (e = {}) => [N, P(e)], L = (e, t) => e.query({
19
19
  table: M,
20
20
  predicate: t,
21
21
  order: [{
@@ -44,9 +44,11 @@ var j = "_voltro_rbac_roles", M = "_voltro_rbac_user_roles", N = k(j, {
44
44
  return [...new Set(r)];
45
45
  }
46
46
  };
47
- }, z = (e) => e === null ? C("tenantId", null) : E(C("tenantId", e), C("tenantId", null)), B = (e) => (t) => {
48
- let n = ("tenantId" in t ? t.tenantId : void 0) ?? null, r = ("id" in t ? t.id : void 0) ?? null;
49
- return r ? e.rolesOf(r, n) : [];
47
+ }, z = (e) => e === null ? C("tenantId", null) : E(C("tenantId", e), C("tenantId", null)), B = (e) => (t, n) => {
48
+ let r = ("tenantId" in t ? t.tenantId : void 0) ?? null, i = ("id" in t ? t.id : void 0) ?? null;
49
+ if (!i) return [];
50
+ let a = e ?? (n?.store === void 0 ? void 0 : R(n.store));
51
+ return a === void 0 ? [] : a.rolesOf(i, r);
50
52
  }, V = b({ scope: "@voltro/plugin-rbac" }), H = (e) => p.suspend(() => {
51
53
  let t = e();
52
54
  return t instanceof Promise ? p.promise(() => t) : p.succeed(t);
@@ -63,33 +65,36 @@ var j = "_voltro_rbac_roles", M = "_voltro_rbac_user_roles", N = k(j, {
63
65
  cause: String(e)
64
66
  }), p.succeed(!1)))));
65
67
  }
66
- let u = (n, r) => p.gen(function* () {
67
- let s = yield* H(() => i(r.subject)).pipe(p.catchAllCause((e) => (V.warn("resolveRoles failed; falling back to raw subject scopes", {
68
+ let u, d = (n, r) => p.gen(function* () {
69
+ let s = yield* H(() => i(r.subject, { ...u === void 0 ? {} : { store: u } })).pipe(p.catchAllCause((e) => (V.warn("resolveRoles failed; falling back to raw subject scopes", {
68
70
  tag: r.tag,
69
71
  traceId: r.traceId,
70
72
  cause: String(e)
71
73
  }), p.succeed([])))), c = o ? yield* H(() => o(r.subject)).pipe(p.catchAllCause(() => p.succeed([]))) : [], l = e(r.subject, s, t.roles, c);
72
74
  return a(r.subject, l, s), yield* n;
73
- }), d = [
75
+ }), f = [
74
76
  "rpc:intercept:mutation",
75
77
  "rpc:intercept:query",
76
78
  "rpc:intercept:action",
77
79
  "rpc:intercept:workflow",
78
80
  ...c ? ["store:write"] : []
79
- ], f = o === void 0 ? r(t.roles) : void 0;
81
+ ], h = o === void 0 ? r(t.roles) : void 0;
80
82
  return _({
81
83
  name: v({
82
84
  base: U,
83
85
  alias: t.alias
84
86
  }),
85
87
  baseName: U,
86
- ...f === void 0 ? {} : { declaredScopes: f },
88
+ ...h === void 0 ? {} : { declaredScopes: h },
87
89
  description: "Role-based access control — roles compile to scopes on top of the protocol scope system. Ships the permission() handler guard + a role→scope interceptor + a resource-aware guard resolver, failing with protocol's typed ScopeError (one denial tag framework-wide).",
88
- permissions: d,
89
- interceptMutation: u,
90
- interceptQuery: u,
91
- interceptAction: u,
92
- interceptWorkflow: u,
90
+ permissions: f,
91
+ bindDataStore: (e) => {
92
+ u = e;
93
+ },
94
+ interceptMutation: d,
95
+ interceptQuery: d,
96
+ interceptAction: d,
97
+ interceptWorkflow: d,
93
98
  errorSchemas: [{
94
99
  schema: g,
95
100
  import: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-rbac",
3
- "version": "0.80.0",
3
+ "version": "0.82.0",
4
4
  "description": "Role-based access control — roles compile to scopes on top of @voltro/protocol's scope system. Ships rbacPlugin() (role→scope interceptor + resource-aware guard resolver, failing with protocol's typed ScopeError), the permission()/assertPermission()/anyPermission() handler guards, the compileRoles() pure compiler, cross-dialect roles + userRoles tables. The UI gate lives in @voltro/client (useCan / useCanAny) — scopes are a framework concept, so gating a button must not require this plugin.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -33,9 +33,9 @@
33
33
  "node": ">=24.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@voltro/database": "0.80.0",
37
- "@voltro/logger": "0.80.0",
38
- "@voltro/protocol": "0.80.0"
36
+ "@voltro/database": "0.82.0",
37
+ "@voltro/logger": "0.82.0",
38
+ "@voltro/protocol": "0.82.0"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "effect": "^3.22.2",