@dudousxd/nestjs-authz-mikro-orm 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/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # @dudousxd/nestjs-authz-mikro-orm
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#4](https://github.com/DavideCarvalho/nestjs-authz/pull/4) [`8b7711d`](https://github.com/DavideCarvalho/nestjs-authz/commit/8b7711d11bdb25b3407fea742f6c1158afb36296) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - New package: `@dudousxd/nestjs-authz-mikro-orm` — a MikroORM RBAC persistence adapter
8
+ mirroring `@dudousxd/nestjs-authz-typeorm`. Ships Role/Permission/RolePermission/UserRole
9
+ entities (user referenced by id only), a `MikroOrmAuthzStore` POJO with the same method
10
+ surface, `AuthzRbacModule.forRoot/forRootAsync` registering the core `ROLE_PROVIDER` +
11
+ `PERMISSION_PROVIDER` seams, and non-destructive `ensureAuthzSchema` (native
12
+ `updateSchema({ safe: true })`) with an `authzSchemaSql` migration helper. `autoCreateSchema`
13
+ defaults to true.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Davi Carvalho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # @dudousxd/nestjs-authz-mikro-orm
2
+
3
+ MikroORM RBAC persistence for [`@dudousxd/nestjs-authz`](https://github.com/DavideCarvalho/nestjs-authz) —
4
+ roles, permissions, and a Gate seam, with **zero connection ownership** (your app owns the
5
+ `EntityManager`; this package never opens a connection).
6
+
7
+ This is the MikroORM sibling of `@dudousxd/nestjs-authz-typeorm`: identical store surface
8
+ and `AuthzRbacModule`, backed by MikroORM entities.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @dudousxd/nestjs-authz-mikro-orm @dudousxd/nestjs-authz @mikro-orm/core @mikro-orm/nestjs
14
+ ```
15
+
16
+ ## Entities
17
+
18
+ The package ships four entities (referencing the user **by id only** — it never owns a
19
+ users table):
20
+
21
+ - `RoleEntity` → `authz_roles`
22
+ - `PermissionEntity` → `authz_permissions`
23
+ - `RolePermissionEntity` → `authz_role_permission` (pivot)
24
+ - `UserRoleEntity` → `authz_user_role` (pivot, keyed by `userType` + `userId`)
25
+
26
+ Register them with your ORM so MikroORM can discover them:
27
+
28
+ ```ts
29
+ import { AUTHZ_ENTITIES } from '@dudousxd/nestjs-authz-mikro-orm';
30
+
31
+ await MikroORM.init({ entities: [...AUTHZ_ENTITIES /* , your entities */] });
32
+ ```
33
+
34
+ > BYO table names: MikroORM resolves table names from entity metadata at discovery time,
35
+ > so override them by re-decorating these entities with your own `@Entity({ tableName })`;
36
+ > the store + schema helpers operate purely through the `EntityManager` and never assume a
37
+ > literal name.
38
+
39
+ ## Usage
40
+
41
+ ```ts
42
+ import {
43
+ AuthzRbacModule,
44
+ MikroOrmAuthzStore,
45
+ } from '@dudousxd/nestjs-authz-mikro-orm';
46
+ import { EntityManager } from '@mikro-orm/core';
47
+
48
+ @Module({
49
+ imports: [
50
+ AuthzRbacModule.forRootAsync({
51
+ inject: [EntityManager],
52
+ useFactory: (em: EntityManager) => ({
53
+ store: new MikroOrmAuthzStore(em),
54
+ // autoCreateSchema defaults to true (non-destructive `updateSchema({ safe: true })`)
55
+ }),
56
+ }),
57
+ ],
58
+ })
59
+ export class AppModule {}
60
+ ```
61
+
62
+ Once wired, the Gate consults persisted RBAC:
63
+
64
+ ```ts
65
+ await store.givePermissionToRole('editor', 'posts.publish');
66
+ await store.assignRole({ type: 'user', id: 7 }, 'editor');
67
+
68
+ gate.forUser(user).allows('posts.publish'); // true (PERMISSION_PROVIDER seam)
69
+ gate.forUser(user).hasRole('editor'); // true (ROLE_PROVIDER seam)
70
+ ```
71
+
72
+ ## Schema
73
+
74
+ `autoCreateSchema` (default `true`) runs `ensureAuthzSchema` on `onModuleInit` via MikroORM's
75
+ native **`updateSchema({ safe: true })`** — it creates missing tables and ADDs missing columns,
76
+ but never drops/alters/renames existing ones, so it is safe to run on every boot.
77
+
78
+ To manage the schema with MikroORM migrations instead, set `autoCreateSchema: false` and use
79
+ the SQL helper:
80
+
81
+ ```ts
82
+ import { authzSchemaSql } from '@dudousxd/nestjs-authz-mikro-orm';
83
+
84
+ export class AddAuthz extends Migration {
85
+ async up() {
86
+ this.addSql(await authzSchemaSql(this.getEntityManager().getOrm()));
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## License
92
+
93
+ MIT
@@ -0,0 +1,46 @@
1
+ import { type DynamicModule } from '@nestjs/common';
2
+ import type { MikroOrmAuthzStore } from './mikro-orm-authz.store.js';
3
+ import type { UserRef } from './types.js';
4
+ /** Injection token holding the {@link MikroOrmAuthzStore} the RBAC module manages. */
5
+ export declare const AUTHZ_RBAC_STORE: unique symbol;
6
+ /** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
7
+ export declare const AUTHZ_RBAC_OPTIONS: unique symbol;
8
+ /**
9
+ * Map the Gate's current user (whatever the app's auth layer produced) to a
10
+ * {@link UserRef} the store can key on. Defaults to reading `{ type, id }` / `{ id }`.
11
+ */
12
+ export type UserRefMapper = (user: unknown) => UserRef | undefined;
13
+ export interface AuthzRbacModuleOptions {
14
+ /** The MikroORM RBAC store (built with the app-provided EntityManager). */
15
+ store: MikroOrmAuthzStore;
16
+ /**
17
+ * Run `ensureAuthzSchema` on bootstrap (default `true`, non-destructive). Set `false`
18
+ * to manage the schema via MikroORM migrations (`authzSchemaSql` helper).
19
+ */
20
+ autoCreateSchema?: boolean;
21
+ /**
22
+ * Derive a {@link UserRef} from the Gate's current user. Defaults to
23
+ * {@link defaultUserRefMapper} (`{ type, id }` or `{ id }`).
24
+ */
25
+ userRefFrom?: UserRefMapper;
26
+ }
27
+ export interface AuthzRbacModuleAsyncOptions {
28
+ imports?: unknown[];
29
+ inject?: unknown[];
30
+ useFactory: (...args: unknown[]) => Promise<AuthzRbacModuleOptions> | AuthzRbacModuleOptions;
31
+ }
32
+ /** Default mapping: accept a `{ type, id }` ref, a `{ id }` object, or a bare id. */
33
+ export declare function defaultUserRefMapper(user: unknown): UserRef | undefined;
34
+ /**
35
+ * Wires persisted RBAC into the core authz Gate. The app provides the `EntityManager`
36
+ * (via `inject`/`useFactory`) and constructs the {@link MikroOrmAuthzStore} — this module
37
+ * NEVER hardcodes a connection token. On init it registers the RBAC permission check into
38
+ * the Gate via the {@link PERMISSION_PROVIDER} seam, so `gate.allows('some.permission')`
39
+ * consults persisted permissions, and (by default) ensures the schema exists.
40
+ */
41
+ export declare class AuthzRbacModule {
42
+ static forRoot(options: AuthzRbacModuleOptions): DynamicModule;
43
+ static forRootAsync(options: AuthzRbacModuleAsyncOptions): DynamicModule;
44
+ private static commonProviders;
45
+ }
46
+ //# sourceMappingURL=authz-rbac.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authz-rbac.module.d.ts","sourceRoot":"","sources":["../src/authz-rbac.module.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,aAAa,EAQnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,eAAuD,CAAC;AACrF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,eAAyD,CAAC;AAEzF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,KAAK,EAAE,kBAAkB,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB,CAAC;CAC9F;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAOvE;AAuDD;;;;;;GAMG;AACH,qBACa,eAAe;IAC1B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,aAAa;IAa9D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,2BAA2B,GAAG,aAAa;IAsBxE,OAAO,CAAC,MAAM,CAAC,eAAe;CAS/B"}
@@ -0,0 +1,158 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ var AuthzRbacModule_1;
14
+ import { PERMISSION_PROVIDER, ROLE_PROVIDER, } from '@dudousxd/nestjs-authz';
15
+ import { Inject, Injectable, Module, Optional, } from '@nestjs/common';
16
+ /** Injection token holding the {@link MikroOrmAuthzStore} the RBAC module manages. */
17
+ export const AUTHZ_RBAC_STORE = Symbol.for('@dudousxd/nestjs-authz-mikro-orm:store');
18
+ /** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
19
+ export const AUTHZ_RBAC_OPTIONS = Symbol.for('@dudousxd/nestjs-authz-mikro-orm:options');
20
+ /** Default mapping: accept a `{ type, id }` ref, a `{ id }` object, or a bare id. */
21
+ export function defaultUserRefMapper(user) {
22
+ if (user == null)
23
+ return undefined;
24
+ if (typeof user === 'string' || typeof user === 'number')
25
+ return user;
26
+ const u = user;
27
+ if (u.id == null)
28
+ return undefined;
29
+ const id = u.id;
30
+ return typeof u.type === 'string' ? { type: u.type, id } : { id };
31
+ }
32
+ /**
33
+ * The RBAC {@link PermissionProvider} the Gate consults (via the shared
34
+ * {@link PERMISSION_PROVIDER} token). Grants a named ability when the current user holds
35
+ * the matching persisted permission — the Laravel/spatie `Gate::before` grant.
36
+ */
37
+ let RbacPermissionProvider = class RbacPermissionProvider {
38
+ options;
39
+ constructor(options) {
40
+ this.options = options;
41
+ }
42
+ // The core `PermissionProvider` interface passes an optional `resource` (3rd
43
+ // arg); it is intentionally ignored here. RBAC grants are model-less,
44
+ // named-ability grants (the Laravel/spatie `Gate::before` grant), so the
45
+ // verdict never depends on a specific resource instance.
46
+ async hasPermission(user, permission) {
47
+ const map = this.options.userRefFrom ?? defaultUserRefMapper;
48
+ const ref = map(user);
49
+ if (ref === undefined)
50
+ return undefined;
51
+ return this.options.store.userHasPermission(ref, permission);
52
+ }
53
+ };
54
+ RbacPermissionProvider = __decorate([
55
+ Injectable(),
56
+ __param(0, Inject(AUTHZ_RBAC_OPTIONS)),
57
+ __metadata("design:paramtypes", [Object])
58
+ ], RbacPermissionProvider);
59
+ /**
60
+ * The RBAC {@link RoleProvider} the Gate consults (via the shared {@link ROLE_PROVIDER}
61
+ * token) for coarse role-checks (`gate.hasRole('teacher')`, `@Roles('admin')`). Returns
62
+ * the role names the current user holds in the persisted store. Core unions these with
63
+ * any roles read off the user object by the default `RoleResolver`.
64
+ */
65
+ let RbacRoleProvider = class RbacRoleProvider {
66
+ options;
67
+ constructor(options) {
68
+ this.options = options;
69
+ }
70
+ async getRoles(user) {
71
+ const map = this.options.userRefFrom ?? defaultUserRefMapper;
72
+ const ref = map(user);
73
+ if (ref === undefined)
74
+ return undefined;
75
+ return this.options.store.getRolesForUser(ref);
76
+ }
77
+ };
78
+ RbacRoleProvider = __decorate([
79
+ Injectable(),
80
+ __param(0, Inject(AUTHZ_RBAC_OPTIONS)),
81
+ __metadata("design:paramtypes", [Object])
82
+ ], RbacRoleProvider);
83
+ /** Runs `ensureAuthzSchema` on bootstrap when `autoCreateSchema` is not disabled. */
84
+ let AuthzRbacBootstrap = class AuthzRbacBootstrap {
85
+ options;
86
+ constructor(options) {
87
+ this.options = options;
88
+ }
89
+ async onModuleInit() {
90
+ if (!this.options)
91
+ return;
92
+ if (this.options.autoCreateSchema === false)
93
+ return;
94
+ await this.options.store.ensureSchema();
95
+ }
96
+ };
97
+ AuthzRbacBootstrap = __decorate([
98
+ Injectable(),
99
+ __param(0, Optional()),
100
+ __param(0, Inject(AUTHZ_RBAC_OPTIONS)),
101
+ __metadata("design:paramtypes", [Object])
102
+ ], AuthzRbacBootstrap);
103
+ /**
104
+ * Wires persisted RBAC into the core authz Gate. The app provides the `EntityManager`
105
+ * (via `inject`/`useFactory`) and constructs the {@link MikroOrmAuthzStore} — this module
106
+ * NEVER hardcodes a connection token. On init it registers the RBAC permission check into
107
+ * the Gate via the {@link PERMISSION_PROVIDER} seam, so `gate.allows('some.permission')`
108
+ * consults persisted permissions, and (by default) ensures the schema exists.
109
+ */
110
+ let AuthzRbacModule = AuthzRbacModule_1 = class AuthzRbacModule {
111
+ static forRoot(options) {
112
+ return {
113
+ module: AuthzRbacModule_1,
114
+ global: true,
115
+ providers: [
116
+ { provide: AUTHZ_RBAC_OPTIONS, useValue: options },
117
+ { provide: AUTHZ_RBAC_STORE, useValue: options.store },
118
+ ...AuthzRbacModule_1.commonProviders(),
119
+ ],
120
+ exports: [AUTHZ_RBAC_STORE, PERMISSION_PROVIDER, ROLE_PROVIDER],
121
+ };
122
+ }
123
+ static forRootAsync(options) {
124
+ return {
125
+ module: AuthzRbacModule_1,
126
+ global: true,
127
+ imports: (options.imports ?? []),
128
+ providers: [
129
+ {
130
+ provide: AUTHZ_RBAC_OPTIONS,
131
+ useFactory: options.useFactory,
132
+ inject: (options.inject ?? []),
133
+ },
134
+ {
135
+ provide: AUTHZ_RBAC_STORE,
136
+ useFactory: (opts) => opts.store,
137
+ inject: [AUTHZ_RBAC_OPTIONS],
138
+ },
139
+ ...AuthzRbacModule_1.commonProviders(),
140
+ ],
141
+ exports: [AUTHZ_RBAC_STORE, PERMISSION_PROVIDER, ROLE_PROVIDER],
142
+ };
143
+ }
144
+ static commonProviders() {
145
+ return [
146
+ RbacPermissionProvider,
147
+ { provide: PERMISSION_PROVIDER, useExisting: RbacPermissionProvider },
148
+ RbacRoleProvider,
149
+ { provide: ROLE_PROVIDER, useExisting: RbacRoleProvider },
150
+ AuthzRbacBootstrap,
151
+ ];
152
+ }
153
+ };
154
+ AuthzRbacModule = AuthzRbacModule_1 = __decorate([
155
+ Module({})
156
+ ], AuthzRbacModule);
157
+ export { AuthzRbacModule };
158
+ //# sourceMappingURL=authz-rbac.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authz-rbac.module.js","sourceRoot":"","sources":["../src/authz-rbac.module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Default table names — the entities below carry these as their `tableName`. MikroORM
3
+ * resolves the physical table from the entity metadata (not at runtime), so an app that
4
+ * wants different names re-decorates these entities; the store + schema helpers operate
5
+ * purely through the EntityManager and never assume a literal name.
6
+ */
7
+ export declare const DEFAULT_TABLE_NAMES: {
8
+ readonly roles: "authz_roles";
9
+ readonly permissions: "authz_permissions";
10
+ readonly rolePermission: "authz_role_permission";
11
+ readonly userRole: "authz_user_role";
12
+ };
13
+ /**
14
+ * A named role (e.g. `editor`). Permissions are attached via {@link RolePermissionEntity};
15
+ * users are attached via {@link UserRoleEntity}.
16
+ *
17
+ * Every column declares an explicit `type` instead of relying on `emitDecoratorMetadata`
18
+ * reflection, so the entity discovers correctly even when the consuming app compiles with
19
+ * SWC/esbuild/Vite (which don't emit decorator metadata).
20
+ *
21
+ * Forward-compat rule: any column added to these entities AFTER v1 MUST be nullable or
22
+ * carry a default — `ensureAuthzSchema` only ever runs the non-destructive `safe` diff
23
+ * (create table + add-missing-column), and `ADD COLUMN NOT NULL` without a default fails
24
+ * on a populated table.
25
+ */
26
+ export declare class RoleEntity {
27
+ id: string;
28
+ name: string;
29
+ guard?: string | null;
30
+ createdAt: Date;
31
+ }
32
+ /** A named permission (e.g. `posts.publish`). Granted to roles via {@link RolePermissionEntity}. */
33
+ export declare class PermissionEntity {
34
+ id: string;
35
+ name: string;
36
+ guard?: string | null;
37
+ createdAt: Date;
38
+ }
39
+ /** Pivot: role ↔ permission. Composite PK `(roleId, permissionId)`. */
40
+ export declare class RolePermissionEntity {
41
+ roleId: string;
42
+ permissionId: string;
43
+ }
44
+ /**
45
+ * Pivot: user ↔ role. References the user BY ID ONLY — this package NEVER defines or
46
+ * owns a users table. `userType` lets the same table key polymorphic principals
47
+ * (mirrors nestjs-context's `UserRef` shape).
48
+ */
49
+ export declare class UserRoleEntity {
50
+ userType: string;
51
+ userId: string;
52
+ roleId: string;
53
+ }
54
+ /** All entities, in dependency order — convenient for `entities: [...]` registration. */
55
+ export declare const AUTHZ_ENTITIES: readonly [typeof RoleEntity, typeof PermissionEntity, typeof RolePermissionEntity, typeof UserRoleEntity];
56
+ //# sourceMappingURL=entities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC;AAEX;;;;;;;;;;;;GAYG;AACH,qBACa,UAAU;IAErB,EAAE,EAAG,MAAM,CAAC;IAIZ,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGtB,SAAS,EAAG,IAAI,CAAC;CAClB;AAED,oGAAoG;AACpG,qBACa,gBAAgB;IAE3B,EAAE,EAAG,MAAM,CAAC;IAIZ,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGtB,SAAS,EAAG,IAAI,CAAC;CAClB;AAED,uEAAuE;AACvE,qBACa,oBAAoB;IAE/B,MAAM,EAAG,MAAM,CAAC;IAGhB,YAAY,EAAG,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAEa,cAAc;IAEzB,QAAQ,EAAG,MAAM,CAAC;IAGlB,MAAM,EAAG,MAAM,CAAC;IAGhB,MAAM,EAAG,MAAM,CAAC;CACjB;AAED,yFAAyF;AACzF,eAAO,MAAM,cAAc,2GAKjB,CAAC"}
@@ -0,0 +1,142 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Entity, Index, PrimaryKey, Property } from '@mikro-orm/core';
11
+ /**
12
+ * Default table names — the entities below carry these as their `tableName`. MikroORM
13
+ * resolves the physical table from the entity metadata (not at runtime), so an app that
14
+ * wants different names re-decorates these entities; the store + schema helpers operate
15
+ * purely through the EntityManager and never assume a literal name.
16
+ */
17
+ export const DEFAULT_TABLE_NAMES = {
18
+ roles: 'authz_roles',
19
+ permissions: 'authz_permissions',
20
+ rolePermission: 'authz_role_permission',
21
+ userRole: 'authz_user_role',
22
+ };
23
+ /**
24
+ * A named role (e.g. `editor`). Permissions are attached via {@link RolePermissionEntity};
25
+ * users are attached via {@link UserRoleEntity}.
26
+ *
27
+ * Every column declares an explicit `type` instead of relying on `emitDecoratorMetadata`
28
+ * reflection, so the entity discovers correctly even when the consuming app compiles with
29
+ * SWC/esbuild/Vite (which don't emit decorator metadata).
30
+ *
31
+ * Forward-compat rule: any column added to these entities AFTER v1 MUST be nullable or
32
+ * carry a default — `ensureAuthzSchema` only ever runs the non-destructive `safe` diff
33
+ * (create table + add-missing-column), and `ADD COLUMN NOT NULL` without a default fails
34
+ * on a populated table.
35
+ */
36
+ let RoleEntity = class RoleEntity {
37
+ id;
38
+ name;
39
+ guard;
40
+ createdAt;
41
+ };
42
+ __decorate([
43
+ PrimaryKey({ type: 'string', length: 191 }),
44
+ __metadata("design:type", String)
45
+ ], RoleEntity.prototype, "id", void 0);
46
+ __decorate([
47
+ Index({ name: 'authz_roles_name_uniq' }),
48
+ Property({ type: 'string', length: 191, unique: true }),
49
+ __metadata("design:type", String)
50
+ ], RoleEntity.prototype, "name", void 0);
51
+ __decorate([
52
+ Property({ type: 'string', nullable: true }),
53
+ __metadata("design:type", Object)
54
+ ], RoleEntity.prototype, "guard", void 0);
55
+ __decorate([
56
+ Property({ type: 'datetime' }),
57
+ __metadata("design:type", Date)
58
+ ], RoleEntity.prototype, "createdAt", void 0);
59
+ RoleEntity = __decorate([
60
+ Entity({ tableName: DEFAULT_TABLE_NAMES.roles })
61
+ ], RoleEntity);
62
+ export { RoleEntity };
63
+ /** A named permission (e.g. `posts.publish`). Granted to roles via {@link RolePermissionEntity}. */
64
+ let PermissionEntity = class PermissionEntity {
65
+ id;
66
+ name;
67
+ guard;
68
+ createdAt;
69
+ };
70
+ __decorate([
71
+ PrimaryKey({ type: 'string', length: 191 }),
72
+ __metadata("design:type", String)
73
+ ], PermissionEntity.prototype, "id", void 0);
74
+ __decorate([
75
+ Index({ name: 'authz_permissions_name_uniq' }),
76
+ Property({ type: 'string', length: 191, unique: true }),
77
+ __metadata("design:type", String)
78
+ ], PermissionEntity.prototype, "name", void 0);
79
+ __decorate([
80
+ Property({ type: 'string', nullable: true }),
81
+ __metadata("design:type", Object)
82
+ ], PermissionEntity.prototype, "guard", void 0);
83
+ __decorate([
84
+ Property({ type: 'datetime' }),
85
+ __metadata("design:type", Date)
86
+ ], PermissionEntity.prototype, "createdAt", void 0);
87
+ PermissionEntity = __decorate([
88
+ Entity({ tableName: DEFAULT_TABLE_NAMES.permissions })
89
+ ], PermissionEntity);
90
+ export { PermissionEntity };
91
+ /** Pivot: role ↔ permission. Composite PK `(roleId, permissionId)`. */
92
+ let RolePermissionEntity = class RolePermissionEntity {
93
+ roleId;
94
+ permissionId;
95
+ };
96
+ __decorate([
97
+ PrimaryKey({ type: 'string', length: 191 }),
98
+ __metadata("design:type", String)
99
+ ], RolePermissionEntity.prototype, "roleId", void 0);
100
+ __decorate([
101
+ PrimaryKey({ type: 'string', length: 191 }),
102
+ __metadata("design:type", String)
103
+ ], RolePermissionEntity.prototype, "permissionId", void 0);
104
+ RolePermissionEntity = __decorate([
105
+ Entity({ tableName: DEFAULT_TABLE_NAMES.rolePermission })
106
+ ], RolePermissionEntity);
107
+ export { RolePermissionEntity };
108
+ /**
109
+ * Pivot: user ↔ role. References the user BY ID ONLY — this package NEVER defines or
110
+ * owns a users table. `userType` lets the same table key polymorphic principals
111
+ * (mirrors nestjs-context's `UserRef` shape).
112
+ */
113
+ let UserRoleEntity = class UserRoleEntity {
114
+ userType;
115
+ userId;
116
+ roleId;
117
+ };
118
+ __decorate([
119
+ PrimaryKey({ type: 'string', length: 191 }),
120
+ __metadata("design:type", String)
121
+ ], UserRoleEntity.prototype, "userType", void 0);
122
+ __decorate([
123
+ PrimaryKey({ type: 'string', length: 191 }),
124
+ __metadata("design:type", String)
125
+ ], UserRoleEntity.prototype, "userId", void 0);
126
+ __decorate([
127
+ PrimaryKey({ type: 'string', length: 191 }),
128
+ __metadata("design:type", String)
129
+ ], UserRoleEntity.prototype, "roleId", void 0);
130
+ UserRoleEntity = __decorate([
131
+ Entity({ tableName: DEFAULT_TABLE_NAMES.userRole }),
132
+ Index({ name: 'authz_user_role_user_idx', properties: ['userType', 'userId'] })
133
+ ], UserRoleEntity);
134
+ export { UserRoleEntity };
135
+ /** All entities, in dependency order — convenient for `entities: [...]` registration. */
136
+ export const AUTHZ_ENTITIES = [
137
+ RoleEntity,
138
+ PermissionEntity,
139
+ RolePermissionEntity,
140
+ UserRoleEntity,
141
+ ];
142
+ //# sourceMappingURL=entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.js","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { AUTHZ_ENTITIES, DEFAULT_TABLE_NAMES, PermissionEntity, RoleEntity, RolePermissionEntity, UserRoleEntity, } from './entities.js';
2
+ export { authzSchemaSql, ensureAuthzSchema } from './schema.js';
3
+ export { MikroOrmAuthzStore } from './mikro-orm-authz.store.js';
4
+ export type { UserAuthz } from './mikro-orm-authz.store.js';
5
+ export { AUTHZ_RBAC_OPTIONS, AUTHZ_RBAC_STORE, AuthzRbacModule, defaultUserRefMapper, } from './authz-rbac.module.js';
6
+ export type { AuthzRbacModuleAsyncOptions, AuthzRbacModuleOptions, UserRefMapper, } from './authz-rbac.module.js';
7
+ export type { AuthzStoreOptions, UserRef, UserRefInput } from './types.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,2BAA2B,EAC3B,sBAAsB,EACtB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,iBAAiB,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { AUTHZ_ENTITIES, DEFAULT_TABLE_NAMES, PermissionEntity, RoleEntity, RolePermissionEntity, UserRoleEntity, } from './entities.js';
2
+ export { authzSchemaSql, ensureAuthzSchema } from './schema.js';
3
+ export { MikroOrmAuthzStore } from './mikro-orm-authz.store.js';
4
+ export { AUTHZ_RBAC_OPTIONS, AUTHZ_RBAC_STORE, AuthzRbacModule, defaultUserRefMapper, } from './authz-rbac.module.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { EntityManager } from '@mikro-orm/core';
2
+ import type { UserRef } from './types.js';
3
+ /**
4
+ * A user's effective permissions: the role names they hold and the flattened set of
5
+ * permission names granted by those roles.
6
+ */
7
+ export interface UserAuthz {
8
+ roles: string[];
9
+ permissions: string[];
10
+ }
11
+ /**
12
+ * MikroORM-backed RBAC store. A plain POJO that receives the `EntityManager` in its
13
+ * constructor — NOT `@Injectable`, no internal connection token (the app owns the
14
+ * connection and plugs it via DI; see the persistence contract).
15
+ *
16
+ * The store works purely through the EntityManager + the registered entities, so it never
17
+ * assumes a literal table name — names are owned by the entity metadata. Every read forks
18
+ * the EM (`this.em.fork()`) so it is request-safe under MikroORM's identity-map rules.
19
+ */
20
+ export declare class MikroOrmAuthzStore {
21
+ private readonly em;
22
+ constructor(em: EntityManager, _opts?: Record<string, never>);
23
+ /** Create/upgrade the RBAC tables (non-destructive, delegates to {@link ensureAuthzSchema}). */
24
+ ensureSchema(): Promise<void>;
25
+ /**
26
+ * Create the role if absent; returns its id. Idempotent and race-tolerant: it re-reads
27
+ * by the unique `name` after a create so two concurrent creators converge on the same row.
28
+ */
29
+ createRole(name: string): Promise<string>;
30
+ /** Create the permission if absent; returns its id. Idempotent and race-tolerant. */
31
+ createPermission(name: string): Promise<string>;
32
+ private findRoleId;
33
+ private findPermissionId;
34
+ /** Grant a permission to a role (creating both by name if needed). Idempotent. */
35
+ givePermissionToRole(roleName: string, permissionName: string): Promise<void>;
36
+ /** Revoke a permission from a role. No-op if either is absent or not linked. */
37
+ revokePermissionFromRole(roleName: string, permissionName: string): Promise<void>;
38
+ /** Assign a role to a user (creating the role by name if needed). Idempotent. */
39
+ assignRole(user: UserRef, roleName: string): Promise<void>;
40
+ /** Remove a role from a user. No-op if the role or assignment is absent. */
41
+ removeRole(user: UserRef, roleName: string): Promise<void>;
42
+ /** The role names a user holds. */
43
+ getRolesForUser(user: UserRef): Promise<string[]>;
44
+ /** The flattened, distinct permission names a user has via their roles. */
45
+ getPermissionsForUser(user: UserRef): Promise<string[]>;
46
+ /** A user's roles + effective permissions in one shot. */
47
+ getUserAuthz(user: UserRef): Promise<UserAuthz>;
48
+ /** True when the user holds `permission` through any of their roles. */
49
+ userHasPermission(user: UserRef, permission: string): Promise<boolean>;
50
+ }
51
+ //# sourceMappingURL=mikro-orm-authz.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mikro-orm-authz.store.d.ts","sourceRoot":"","sources":["../src/mikro-orm-authz.store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,iBAAiB,CAAC;AAG/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAU1C;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa,EAClC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAM;IAGnC,gGAAgG;IAChG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB/C,qFAAqF;IAC/E,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAoBvC,UAAU;YAKV,gBAAgB;IAO9B,kFAAkF;IAC5E,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnF,gFAAgF;IAC1E,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvF,iFAAiF;IAC3E,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUhE,4EAA4E;IACtE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAShE,mCAAmC;IAC7B,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAUvD,2EAA2E;IACrE,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAa7D,0DAA0D;IACpD,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IAQrD,wEAAwE;IAClE,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI7E"}
@@ -0,0 +1,170 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { PermissionEntity, RoleEntity, RolePermissionEntity, UserRoleEntity } from './entities.js';
3
+ import { ensureAuthzSchema } from './schema.js';
4
+ /** Normalize a {@link UserRef} to `{ type, id }` with `id` stringified. */
5
+ function normalizeUserRef(ref) {
6
+ if (typeof ref === 'string' || typeof ref === 'number') {
7
+ return { type: 'user', id: String(ref) };
8
+ }
9
+ return { type: ref.type ?? 'user', id: String(ref.id) };
10
+ }
11
+ /**
12
+ * MikroORM-backed RBAC store. A plain POJO that receives the `EntityManager` in its
13
+ * constructor — NOT `@Injectable`, no internal connection token (the app owns the
14
+ * connection and plugs it via DI; see the persistence contract).
15
+ *
16
+ * The store works purely through the EntityManager + the registered entities, so it never
17
+ * assumes a literal table name — names are owned by the entity metadata. Every read forks
18
+ * the EM (`this.em.fork()`) so it is request-safe under MikroORM's identity-map rules.
19
+ */
20
+ export class MikroOrmAuthzStore {
21
+ em;
22
+ // `opts` is reserved for forward-compat (parity with the TypeORM adapter's options); it is
23
+ // accepted but not yet consumed since MikroORM owns table names via entity metadata.
24
+ constructor(em, _opts = {}) {
25
+ this.em = em;
26
+ }
27
+ /** Create/upgrade the RBAC tables (non-destructive, delegates to {@link ensureAuthzSchema}). */
28
+ ensureSchema() {
29
+ return ensureAuthzSchema(this.em);
30
+ }
31
+ // --- roles & permissions (idempotent upserts by name) ---
32
+ /**
33
+ * Create the role if absent; returns its id. Idempotent and race-tolerant: it re-reads
34
+ * by the unique `name` after a create so two concurrent creators converge on the same row.
35
+ */
36
+ async createRole(name) {
37
+ const existing = await this.findRoleId(name);
38
+ if (existing)
39
+ return existing;
40
+ const em = this.em.fork();
41
+ const entity = em.create(RoleEntity, {
42
+ id: randomUUID(),
43
+ name,
44
+ guard: null,
45
+ createdAt: new Date(),
46
+ });
47
+ try {
48
+ await em.persist(entity).flush();
49
+ }
50
+ catch {
51
+ // A concurrent insert won the race on the unique `name`; fall through to re-read.
52
+ }
53
+ const id = await this.findRoleId(name);
54
+ if (!id)
55
+ throw new Error(`Failed to create or resolve role "${name}".`);
56
+ return id;
57
+ }
58
+ /** Create the permission if absent; returns its id. Idempotent and race-tolerant. */
59
+ async createPermission(name) {
60
+ const existing = await this.findPermissionId(name);
61
+ if (existing)
62
+ return existing;
63
+ const em = this.em.fork();
64
+ const entity = em.create(PermissionEntity, {
65
+ id: randomUUID(),
66
+ name,
67
+ guard: null,
68
+ createdAt: new Date(),
69
+ });
70
+ try {
71
+ await em.persist(entity).flush();
72
+ }
73
+ catch {
74
+ // A concurrent insert won the race on the unique `name`; fall through to re-read.
75
+ }
76
+ const id = await this.findPermissionId(name);
77
+ if (!id)
78
+ throw new Error(`Failed to create or resolve permission "${name}".`);
79
+ return id;
80
+ }
81
+ async findRoleId(name) {
82
+ const row = await this.em.fork().findOne(RoleEntity, { name });
83
+ return row?.id;
84
+ }
85
+ async findPermissionId(name) {
86
+ const row = await this.em.fork().findOne(PermissionEntity, { name });
87
+ return row?.id;
88
+ }
89
+ // --- role ↔ permission ---
90
+ /** Grant a permission to a role (creating both by name if needed). Idempotent. */
91
+ async givePermissionToRole(roleName, permissionName) {
92
+ const roleId = await this.createRole(roleName);
93
+ const permissionId = await this.createPermission(permissionName);
94
+ const em = this.em.fork();
95
+ const existing = await em.findOne(RolePermissionEntity, { roleId, permissionId });
96
+ if (existing)
97
+ return;
98
+ em.create(RolePermissionEntity, { roleId, permissionId });
99
+ await em.flush();
100
+ }
101
+ /** Revoke a permission from a role. No-op if either is absent or not linked. */
102
+ async revokePermissionFromRole(roleName, permissionName) {
103
+ const roleId = await this.findRoleId(roleName);
104
+ const permissionId = await this.findPermissionId(permissionName);
105
+ if (!roleId || !permissionId)
106
+ return;
107
+ await this.em.fork().nativeDelete(RolePermissionEntity, { roleId, permissionId });
108
+ }
109
+ // --- user ↔ role ---
110
+ /** Assign a role to a user (creating the role by name if needed). Idempotent. */
111
+ async assignRole(user, roleName) {
112
+ const { type, id } = normalizeUserRef(user);
113
+ const roleId = await this.createRole(roleName);
114
+ const em = this.em.fork();
115
+ const existing = await em.findOne(UserRoleEntity, { userType: type, userId: id, roleId });
116
+ if (existing)
117
+ return;
118
+ em.create(UserRoleEntity, { userType: type, userId: id, roleId });
119
+ await em.flush();
120
+ }
121
+ /** Remove a role from a user. No-op if the role or assignment is absent. */
122
+ async removeRole(user, roleName) {
123
+ const { type, id } = normalizeUserRef(user);
124
+ const roleId = await this.findRoleId(roleName);
125
+ if (!roleId)
126
+ return;
127
+ await this.em.fork().nativeDelete(UserRoleEntity, { userType: type, userId: id, roleId });
128
+ }
129
+ // --- queries ---
130
+ /** The role names a user holds. */
131
+ async getRolesForUser(user) {
132
+ const { type, id } = normalizeUserRef(user);
133
+ const em = this.em.fork();
134
+ const assignments = await em.find(UserRoleEntity, { userType: type, userId: id });
135
+ if (assignments.length === 0)
136
+ return [];
137
+ const roleIds = assignments.map((a) => a.roleId);
138
+ const roles = await em.find(RoleEntity, { id: { $in: roleIds } });
139
+ return roles.map((r) => r.name);
140
+ }
141
+ /** The flattened, distinct permission names a user has via their roles. */
142
+ async getPermissionsForUser(user) {
143
+ const { type, id } = normalizeUserRef(user);
144
+ const em = this.em.fork();
145
+ const assignments = await em.find(UserRoleEntity, { userType: type, userId: id });
146
+ if (assignments.length === 0)
147
+ return [];
148
+ const roleIds = assignments.map((a) => a.roleId);
149
+ const links = await em.find(RolePermissionEntity, { roleId: { $in: roleIds } });
150
+ if (links.length === 0)
151
+ return [];
152
+ const permissionIds = [...new Set(links.map((l) => l.permissionId))];
153
+ const permissions = await em.find(PermissionEntity, { id: { $in: permissionIds } });
154
+ return [...new Set(permissions.map((p) => p.name))];
155
+ }
156
+ /** A user's roles + effective permissions in one shot. */
157
+ async getUserAuthz(user) {
158
+ const [roles, permissions] = await Promise.all([
159
+ this.getRolesForUser(user),
160
+ this.getPermissionsForUser(user),
161
+ ]);
162
+ return { roles, permissions };
163
+ }
164
+ /** True when the user holds `permission` through any of their roles. */
165
+ async userHasPermission(user, permission) {
166
+ const permissions = await this.getPermissionsForUser(user);
167
+ return permissions.includes(permission);
168
+ }
169
+ }
170
+ //# sourceMappingURL=mikro-orm-authz.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mikro-orm-authz.store.js","sourceRoot":"","sources":["../src/mikro-orm-authz.store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { EntityManager, MikroORM } from '@mikro-orm/core';
2
+ /**
3
+ * Returns the non-destructive SQL needed to bring only the authz RBAC tables up to date
4
+ * (creates them / adds missing columns). Mirrors the TypeORM adapter's migration helper —
5
+ * call it inside a MikroORM migration when you disable `autoCreateSchema`:
6
+ *
7
+ * ```ts
8
+ * import { authzSchemaSql } from '@dudousxd/nestjs-authz-mikro-orm';
9
+ * export class AddAuthz extends Migration {
10
+ * async up() { this.addSql(await authzSchemaSql(this.getEntityManager())); }
11
+ * }
12
+ * ```
13
+ */
14
+ export declare function authzSchemaSql(ormOrEm: MikroORM | EntityManager): Promise<string>;
15
+ /**
16
+ * Ensure the RBAC schema is up to date (used by the store's `ensureSchema` on bootstrap).
17
+ *
18
+ * Runs MikroORM's native non-destructive `safe` diff: it creates missing tables and ADDs
19
+ * missing columns, but never drops/alters/renames existing ones, so it is safe to run on
20
+ * every boot. Only statements touching the authz tables are applied. Accepts a
21
+ * {@link MikroORM} or an {@link EntityManager}.
22
+ *
23
+ * Forward-compat rule: any column added to an authz entity after v1 MUST be nullable or
24
+ * have a default — `ADD COLUMN` of a NOT NULL column without a default fails on a populated
25
+ * table, and the `safe` diff never recreates the table.
26
+ */
27
+ export declare function ensureAuthzSchema(ormOrEm: MikroORM | EntityManager): Promise<void>;
28
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAiC/D;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxF"}
package/dist/schema.js ADDED
@@ -0,0 +1,65 @@
1
+ /** The four authz table names — used to filter the schema diff down to our tables. */
2
+ const AUTHZ_TABLES = [
3
+ 'authz_roles',
4
+ 'authz_permissions',
5
+ 'authz_role_permission',
6
+ 'authz_user_role',
7
+ ];
8
+ /** Resolve an {@link EntityManager} from a {@link MikroORM} or an EM. */
9
+ function toEm(ormOrEm) {
10
+ return isOrm(ormOrEm) ? ormOrEm.em : ormOrEm;
11
+ }
12
+ function isOrm(value) {
13
+ return 'em' in value && typeof value.getSchemaGenerator === 'function';
14
+ }
15
+ /** The platform's schema generator for a given EM (driver + EM bound). */
16
+ function generatorFor(em) {
17
+ return em.getPlatform().getSchemaGenerator(em.getDriver(), em);
18
+ }
19
+ /** Statements (split, trimmed) from the non-destructive schema diff that touch our tables. */
20
+ async function authzStatements(em) {
21
+ const sql = await generatorFor(em).getUpdateSchemaSQL({ safe: true, wrap: false });
22
+ return sql
23
+ .split(';')
24
+ .map((s) => s.trim())
25
+ .filter((s) => s.length > 0 && AUTHZ_TABLES.some((t) => new RegExp(`\\b${t}\\b`, 'i').test(s)));
26
+ }
27
+ /**
28
+ * Returns the non-destructive SQL needed to bring only the authz RBAC tables up to date
29
+ * (creates them / adds missing columns). Mirrors the TypeORM adapter's migration helper —
30
+ * call it inside a MikroORM migration when you disable `autoCreateSchema`:
31
+ *
32
+ * ```ts
33
+ * import { authzSchemaSql } from '@dudousxd/nestjs-authz-mikro-orm';
34
+ * export class AddAuthz extends Migration {
35
+ * async up() { this.addSql(await authzSchemaSql(this.getEntityManager())); }
36
+ * }
37
+ * ```
38
+ */
39
+ export async function authzSchemaSql(ormOrEm) {
40
+ const statements = await authzStatements(toEm(ormOrEm));
41
+ return statements.length ? `${statements.join(';\n')};` : '';
42
+ }
43
+ /**
44
+ * Ensure the RBAC schema is up to date (used by the store's `ensureSchema` on bootstrap).
45
+ *
46
+ * Runs MikroORM's native non-destructive `safe` diff: it creates missing tables and ADDs
47
+ * missing columns, but never drops/alters/renames existing ones, so it is safe to run on
48
+ * every boot. Only statements touching the authz tables are applied. Accepts a
49
+ * {@link MikroORM} or an {@link EntityManager}.
50
+ *
51
+ * Forward-compat rule: any column added to an authz entity after v1 MUST be nullable or
52
+ * have a default — `ADD COLUMN` of a NOT NULL column without a default fails on a populated
53
+ * table, and the `safe` diff never recreates the table.
54
+ */
55
+ export async function ensureAuthzSchema(ormOrEm) {
56
+ const em = toEm(ormOrEm);
57
+ const statements = await authzStatements(em);
58
+ if (statements.length === 0)
59
+ return;
60
+ const connection = em.getConnection();
61
+ for (const statement of statements) {
62
+ await connection.execute(statement);
63
+ }
64
+ }
65
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,MAAM,YAAY,GAAG;IACnB,aAAa;IACb,mBAAmB;IACnB,uBAAuB;IACvB,iBAAiB;CAClB,CAAC;AAEF,yEAAyE;AACzE,SAAS,IAAI,CAAC,OAAiC;IAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,OAAO,CAAC,EAA+B,CAAC,CAAC,CAAC,OAAO,CAAC;AAC7E,CAAC;AAED,SAAS,KAAK,CAAC,KAA+B;IAC5C,OAAO,IAAI,IAAK,KAAgB,IAAI,OAAQ,KAAkB,CAAC,kBAAkB,KAAK,UAAU,CAAC;AACnG,CAAC;AAED,0EAA0E;AAC1E,SAAS,YAAY,CAAC,EAAiB;IACrC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,8FAA8F;AAC9F,KAAK,UAAU,eAAe,CAAC,EAAiB;IAC9C,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,EAAE,CAAC,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnF,OAAO,GAAG;SACP,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAiC;IACpE,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACpC,MAAM,UAAU,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;IACtC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A reference to a user. Matches nestjs-context's `UserRef` shape (`{ type, id }`),
3
+ * but the store accepts either a full ref or a bare id (defaulting `type` to `'user'`).
4
+ */
5
+ export interface UserRefInput {
6
+ type?: string;
7
+ id: string | number;
8
+ }
9
+ /** A user reference, or just its id (treated as `{ type: 'user', id }`). */
10
+ export type UserRef = UserRefInput | string | number;
11
+ /**
12
+ * Options for the MikroORM RBAC store. Reserved for forward-compatibility — MikroORM
13
+ * derives table names from the registered entities (`@Entity({ tableName })`), so BYO
14
+ * names are configured by re-decorating the entities, not at runtime.
15
+ */
16
+ export interface AuthzStoreOptions {
17
+ }
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,MAAM,OAAO,GAAG,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;CAAG"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@dudousxd/nestjs-authz-mikro-orm",
3
+ "version": "0.2.0",
4
+ "description": "MikroORM RBAC persistence for @dudousxd/nestjs-authz — roles, permissions, and a Gate seam (zero connection ownership).",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/DavideCarvalho/nestjs-authz.git",
9
+ "directory": "packages/mikro-orm"
10
+ },
11
+ "author": "Davi Carvalho <davi@goflip.ai>",
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist/",
24
+ "README.md",
25
+ "CHANGELOG.md"
26
+ ],
27
+ "peerDependencies": {
28
+ "@dudousxd/nestjs-authz": ">=0.1.0",
29
+ "@mikro-orm/core": "^6.0.0",
30
+ "@mikro-orm/nestjs": "^5.0.0 || ^6.0.0",
31
+ "@nestjs/common": ">=10.0.0",
32
+ "@nestjs/core": ">=10.0.0",
33
+ "reflect-metadata": ">=0.1.13"
34
+ },
35
+ "peerDependenciesMeta": {
36
+ "@mikro-orm/nestjs": {
37
+ "optional": true
38
+ }
39
+ },
40
+ "devDependencies": {
41
+ "@mikro-orm/better-sqlite": "6.6.15",
42
+ "@mikro-orm/core": "6.6.15",
43
+ "@mikro-orm/nestjs": "^6.0.0",
44
+ "@nestjs/common": "^11.0.0",
45
+ "@nestjs/core": "^11.0.0",
46
+ "@nestjs/testing": "^11.0.0",
47
+ "@types/node": "^20.0.0",
48
+ "reflect-metadata": "^0.2.2",
49
+ "rxjs": "^7.8.1",
50
+ "typescript": "^5.4.0",
51
+ "vitest": "^3.0.0",
52
+ "@dudousxd/nestjs-authz": "^0.4.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=20"
56
+ },
57
+ "keywords": [
58
+ "nestjs",
59
+ "authorization",
60
+ "authz",
61
+ "rbac",
62
+ "roles",
63
+ "permissions",
64
+ "mikro-orm"
65
+ ],
66
+ "scripts": {
67
+ "build": "tsc -p tsconfig.json",
68
+ "test": "vitest run --passWithNoTests",
69
+ "test:watch": "vitest",
70
+ "typecheck": "tsc -p tsconfig.json --noEmit"
71
+ }
72
+ }