@dudousxd/nestjs-authz-prisma 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,14 @@
1
+ # @dudousxd/nestjs-authz-prisma
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-prisma` — a Prisma RBAC persistence adapter mirroring
8
+ `@dudousxd/nestjs-authz-typeorm`. Exposes a `PRISMA_CLIENT` DI token plus a minimal
9
+ **structural** `PrismaAuthzClientLike` interface (no `@prisma/client` import / no
10
+ `prisma generate` step), a `PrismaAuthzStore` with the same method surface, and
11
+ `AuthzRbacModule.forRoot/forRootAsync` registering the core `ROLE_PROVIDER` +
12
+ `PERMISSION_PROVIDER` seams. The schema is consumer-managed (the required `Role`/
13
+ `Permission`/`RolePermission`/`UserRole` models are documented in the README);
14
+ `ensureSchema` is a no-op.
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,107 @@
1
+ # @dudousxd/nestjs-authz-prisma
2
+
3
+ Prisma 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
+ `PrismaClient`; this package never opens a connection and never imports `@prisma/client`).
6
+
7
+ This is the Prisma sibling of `@dudousxd/nestjs-authz-typeorm`: identical store surface and
8
+ `AuthzRbacModule`, consuming a **structural** Prisma client interface.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @dudousxd/nestjs-authz-prisma @dudousxd/nestjs-authz
14
+ ```
15
+
16
+ No `@prisma/client` is required by this package — it depends only on the structural
17
+ `PrismaAuthzClientLike` interface, which a real `PrismaClient` satisfies. There is **no
18
+ `prisma generate` step** introduced by this adapter.
19
+
20
+ ## Schema (consumer-managed)
21
+
22
+ Prisma is schema-first: add the four RBAC models to your `schema.prisma` and apply them with
23
+ `prisma migrate` / `prisma db push`. The user is referenced **by id only** — this package
24
+ never owns a users table.
25
+
26
+ ```prisma
27
+ model Role {
28
+ id String @id
29
+ name String @unique
30
+ guard String?
31
+ createdAt DateTime @default(now())
32
+
33
+ @@map("authz_roles")
34
+ }
35
+
36
+ model Permission {
37
+ id String @id
38
+ name String @unique
39
+ guard String?
40
+ createdAt DateTime @default(now())
41
+
42
+ @@map("authz_permissions")
43
+ }
44
+
45
+ model RolePermission {
46
+ roleId String
47
+ permissionId String
48
+
49
+ @@id([roleId, permissionId])
50
+ @@map("authz_role_permission")
51
+ }
52
+
53
+ model UserRole {
54
+ userType String
55
+ userId String
56
+ roleId String
57
+
58
+ @@id([userType, userId, roleId])
59
+ @@index([userType, userId])
60
+ @@map("authz_user_role")
61
+ }
62
+ ```
63
+
64
+ > Unlike the TypeORM/MikroORM adapters there is **no auto-create** — `store.ensureSchema()`
65
+ > is a no-op. Manage the schema with Prisma migrations.
66
+
67
+ ## Usage
68
+
69
+ ```ts
70
+ import { AuthzRbacModule } from '@dudousxd/nestjs-authz-prisma';
71
+ import { PrismaClient } from '@prisma/client';
72
+
73
+ const prisma = new PrismaClient();
74
+
75
+ @Module({
76
+ imports: [
77
+ // Pass the client directly — the module builds the store. (Or pass a pre-built `store`.)
78
+ AuthzRbacModule.forRoot({ client: prisma }),
79
+ ],
80
+ })
81
+ export class AppModule {}
82
+ ```
83
+
84
+ Or build the store yourself and inject the client via the `PRISMA_CLIENT` token:
85
+
86
+ ```ts
87
+ import { PRISMA_CLIENT, PrismaAuthzStore } from '@dudousxd/nestjs-authz-prisma';
88
+
89
+ AuthzRbacModule.forRootAsync({
90
+ inject: [PRISMA_CLIENT],
91
+ useFactory: (client) => ({ store: new PrismaAuthzStore(client) }),
92
+ });
93
+ ```
94
+
95
+ Once wired, the Gate consults persisted RBAC:
96
+
97
+ ```ts
98
+ await store.givePermissionToRole('editor', 'posts.publish');
99
+ await store.assignRole({ type: 'user', id: 7 }, 'editor');
100
+
101
+ gate.forUser(user).allows('posts.publish'); // true (PERMISSION_PROVIDER seam)
102
+ gate.forUser(user).hasRole('editor'); // true (ROLE_PROVIDER seam)
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,53 @@
1
+ import { type DynamicModule } from '@nestjs/common';
2
+ import { PrismaAuthzStore } from './prisma-authz.store.js';
3
+ import { type PrismaAuthzClientLike } from './prisma-client.js';
4
+ import type { UserRef } from './types.js';
5
+ /** Injection token holding the {@link PrismaAuthzStore} the RBAC module manages. */
6
+ export declare const AUTHZ_RBAC_STORE: unique symbol;
7
+ /** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
8
+ export declare const AUTHZ_RBAC_OPTIONS: unique symbol;
9
+ /**
10
+ * Map the Gate's current user (whatever the app's auth layer produced) to a
11
+ * {@link UserRef} the store can key on. Defaults to reading `{ type, id }` / `{ id }`.
12
+ */
13
+ export type UserRefMapper = (user: unknown) => UserRef | undefined;
14
+ export interface AuthzRbacModuleOptions {
15
+ /**
16
+ * The Prisma RBAC store, OR the raw Prisma client. Pass `store` if you already built a
17
+ * {@link PrismaAuthzStore}; pass `client` to let the module build one (a real
18
+ * `PrismaClient` structurally satisfies {@link PrismaAuthzClientLike}).
19
+ */
20
+ store?: PrismaAuthzStore;
21
+ /** The app-owned Prisma client; used to build the store when `store` is omitted. */
22
+ client?: PrismaAuthzClientLike;
23
+ /**
24
+ * Prisma is consumer-managed (schema-first) — there is no auto-create. This flag exists
25
+ * for parity; the store's `ensureSchema` is a no-op regardless. Default `false`.
26
+ */
27
+ autoCreateSchema?: boolean;
28
+ /**
29
+ * Derive a {@link UserRef} from the Gate's current user. Defaults to
30
+ * {@link defaultUserRefMapper} (`{ type, id }` or `{ id }`).
31
+ */
32
+ userRefFrom?: UserRefMapper;
33
+ }
34
+ export interface AuthzRbacModuleAsyncOptions {
35
+ imports?: unknown[];
36
+ inject?: unknown[];
37
+ useFactory: (...args: unknown[]) => Promise<AuthzRbacModuleOptions> | AuthzRbacModuleOptions;
38
+ }
39
+ /** Default mapping: accept a `{ type, id }` ref, a `{ id }` object, or a bare id. */
40
+ export declare function defaultUserRefMapper(user: unknown): UserRef | undefined;
41
+ /**
42
+ * Wires persisted RBAC into the core authz Gate. The app provides the Prisma client (via
43
+ * `client`, or a pre-built `store`, through `inject`/`useFactory`) — this module NEVER
44
+ * hardcodes a connection token. On init it registers the RBAC permission check into the
45
+ * Gate via the {@link PERMISSION_PROVIDER} seam, so `gate.allows('some.permission')`
46
+ * consults persisted permissions. Prisma's schema is consumer-managed (no auto-create).
47
+ */
48
+ export declare class AuthzRbacModule {
49
+ static forRoot(options: AuthzRbacModuleOptions): DynamicModule;
50
+ static forRootAsync(options: AuthzRbacModuleAsyncOptions): DynamicModule;
51
+ private static commonProviders;
52
+ }
53
+ //# 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,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,eAAoD,CAAC;AAClF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,eAAsD,CAAC;AAEtF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,oFAAoF;IACpF,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B;;;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;AAuED;;;;;;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,174 @@
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
+ import { PrismaAuthzStore } from './prisma-authz.store.js';
17
+ /** Injection token holding the {@link PrismaAuthzStore} the RBAC module manages. */
18
+ export const AUTHZ_RBAC_STORE = Symbol.for('@dudousxd/nestjs-authz-prisma:store');
19
+ /** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
20
+ export const AUTHZ_RBAC_OPTIONS = Symbol.for('@dudousxd/nestjs-authz-prisma:options');
21
+ /** Default mapping: accept a `{ type, id }` ref, a `{ id }` object, or a bare id. */
22
+ export function defaultUserRefMapper(user) {
23
+ if (user == null)
24
+ return undefined;
25
+ if (typeof user === 'string' || typeof user === 'number')
26
+ return user;
27
+ const u = user;
28
+ if (u.id == null)
29
+ return undefined;
30
+ const id = u.id;
31
+ return typeof u.type === 'string' ? { type: u.type, id } : { id };
32
+ }
33
+ /** Resolve a concrete store from the options (building one from `client` when needed). */
34
+ function resolveStore(options) {
35
+ if (options.store)
36
+ return options.store;
37
+ if (options.client)
38
+ return new PrismaAuthzStore(options.client);
39
+ throw new Error('AuthzRbacModule (prisma): provide either `store` or `client` in the options.');
40
+ }
41
+ /**
42
+ * The RBAC {@link PermissionProvider} the Gate consults (via the shared
43
+ * {@link PERMISSION_PROVIDER} token). Grants a named ability when the current user holds
44
+ * the matching persisted permission — the Laravel/spatie `Gate::before` grant.
45
+ */
46
+ let RbacPermissionProvider = class RbacPermissionProvider {
47
+ options;
48
+ store;
49
+ constructor(options) {
50
+ this.options = options;
51
+ this.store = resolveStore(options);
52
+ }
53
+ // The core `PermissionProvider` interface passes an optional `resource` (3rd
54
+ // arg); it is intentionally ignored here. RBAC grants are model-less,
55
+ // named-ability grants (the Laravel/spatie `Gate::before` grant), so the
56
+ // verdict never depends on a specific resource instance.
57
+ async hasPermission(user, permission) {
58
+ const map = this.options.userRefFrom ?? defaultUserRefMapper;
59
+ const ref = map(user);
60
+ if (ref === undefined)
61
+ return undefined;
62
+ return this.store.userHasPermission(ref, permission);
63
+ }
64
+ };
65
+ RbacPermissionProvider = __decorate([
66
+ Injectable(),
67
+ __param(0, Inject(AUTHZ_RBAC_OPTIONS)),
68
+ __metadata("design:paramtypes", [Object])
69
+ ], RbacPermissionProvider);
70
+ /**
71
+ * The RBAC {@link RoleProvider} the Gate consults (via the shared {@link ROLE_PROVIDER}
72
+ * token) for coarse role-checks (`gate.hasRole('teacher')`, `@Roles('admin')`). Returns
73
+ * the role names the current user holds in the persisted store. Core unions these with
74
+ * any roles read off the user object by the default `RoleResolver`.
75
+ */
76
+ let RbacRoleProvider = class RbacRoleProvider {
77
+ options;
78
+ store;
79
+ constructor(options) {
80
+ this.options = options;
81
+ this.store = resolveStore(options);
82
+ }
83
+ async getRoles(user) {
84
+ const map = this.options.userRefFrom ?? defaultUserRefMapper;
85
+ const ref = map(user);
86
+ if (ref === undefined)
87
+ return undefined;
88
+ return this.store.getRolesForUser(ref);
89
+ }
90
+ };
91
+ RbacRoleProvider = __decorate([
92
+ Injectable(),
93
+ __param(0, Inject(AUTHZ_RBAC_OPTIONS)),
94
+ __metadata("design:paramtypes", [Object])
95
+ ], RbacRoleProvider);
96
+ /**
97
+ * Runs `ensureSchema` on bootstrap when `autoCreateSchema` is enabled. For Prisma this is
98
+ * a no-op (schema is consumer-managed) — kept for parity with the other adapters.
99
+ */
100
+ let AuthzRbacBootstrap = class AuthzRbacBootstrap {
101
+ options;
102
+ constructor(options) {
103
+ this.options = options;
104
+ }
105
+ async onModuleInit() {
106
+ if (!this.options)
107
+ return;
108
+ if (this.options.autoCreateSchema !== true)
109
+ return;
110
+ await resolveStore(this.options).ensureSchema();
111
+ }
112
+ };
113
+ AuthzRbacBootstrap = __decorate([
114
+ Injectable(),
115
+ __param(0, Optional()),
116
+ __param(0, Inject(AUTHZ_RBAC_OPTIONS)),
117
+ __metadata("design:paramtypes", [Object])
118
+ ], AuthzRbacBootstrap);
119
+ /**
120
+ * Wires persisted RBAC into the core authz Gate. The app provides the Prisma client (via
121
+ * `client`, or a pre-built `store`, through `inject`/`useFactory`) — this module NEVER
122
+ * hardcodes a connection token. On init it registers the RBAC permission check into the
123
+ * Gate via the {@link PERMISSION_PROVIDER} seam, so `gate.allows('some.permission')`
124
+ * consults persisted permissions. Prisma's schema is consumer-managed (no auto-create).
125
+ */
126
+ let AuthzRbacModule = AuthzRbacModule_1 = class AuthzRbacModule {
127
+ static forRoot(options) {
128
+ return {
129
+ module: AuthzRbacModule_1,
130
+ global: true,
131
+ providers: [
132
+ { provide: AUTHZ_RBAC_OPTIONS, useValue: options },
133
+ { provide: AUTHZ_RBAC_STORE, useFactory: () => resolveStore(options) },
134
+ ...AuthzRbacModule_1.commonProviders(),
135
+ ],
136
+ exports: [AUTHZ_RBAC_STORE, PERMISSION_PROVIDER, ROLE_PROVIDER],
137
+ };
138
+ }
139
+ static forRootAsync(options) {
140
+ return {
141
+ module: AuthzRbacModule_1,
142
+ global: true,
143
+ imports: (options.imports ?? []),
144
+ providers: [
145
+ {
146
+ provide: AUTHZ_RBAC_OPTIONS,
147
+ useFactory: options.useFactory,
148
+ inject: (options.inject ?? []),
149
+ },
150
+ {
151
+ provide: AUTHZ_RBAC_STORE,
152
+ useFactory: (opts) => resolveStore(opts),
153
+ inject: [AUTHZ_RBAC_OPTIONS],
154
+ },
155
+ ...AuthzRbacModule_1.commonProviders(),
156
+ ],
157
+ exports: [AUTHZ_RBAC_STORE, PERMISSION_PROVIDER, ROLE_PROVIDER],
158
+ };
159
+ }
160
+ static commonProviders() {
161
+ return [
162
+ RbacPermissionProvider,
163
+ { provide: PERMISSION_PROVIDER, useExisting: RbacPermissionProvider },
164
+ RbacRoleProvider,
165
+ { provide: ROLE_PROVIDER, useExisting: RbacRoleProvider },
166
+ AuthzRbacBootstrap,
167
+ ];
168
+ }
169
+ };
170
+ AuthzRbacModule = AuthzRbacModule_1 = __decorate([
171
+ Module({})
172
+ ], AuthzRbacModule);
173
+ export { AuthzRbacModule };
174
+ //# 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,7 @@
1
+ export { PRISMA_CLIENT, type PrismaAuthzClientLike, type PrismaModelDelegate, } from './prisma-client.js';
2
+ export { PrismaAuthzStore } from './prisma-authz.store.js';
3
+ export type { UserAuthz } from './prisma-authz.store.js';
4
+ export { AUTHZ_RBAC_OPTIONS, AUTHZ_RBAC_STORE, AuthzRbacModule, defaultUserRefMapper, } from './authz-rbac.module.js';
5
+ export type { AuthzRbacModuleAsyncOptions, AuthzRbacModuleOptions, UserRefMapper, } from './authz-rbac.module.js';
6
+ export type { UserRef, UserRefInput } from './types.js';
7
+ //# 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,aAAa,EACb,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,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,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { PRISMA_CLIENT, } from './prisma-client.js';
2
+ export { PrismaAuthzStore } from './prisma-authz.store.js';
3
+ export { AUTHZ_RBAC_OPTIONS, AUTHZ_RBAC_STORE, AuthzRbacModule, defaultUserRefMapper, } from './authz-rbac.module.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,GAGd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { type PrismaAuthzClientLike } from './prisma-client.js';
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
+ * Prisma-backed RBAC store. Receives the app-owned Prisma client via the
13
+ * {@link PRISMA_CLIENT} DI token — NO internal connection ownership, NO `@prisma/client`
14
+ * import (it consumes the structural {@link PrismaAuthzClientLike}).
15
+ *
16
+ * Same method surface as the TypeORM/MikroORM adapters. The user is referenced BY ID ONLY
17
+ * — this package never owns a users table.
18
+ */
19
+ export declare class PrismaAuthzStore {
20
+ private readonly client;
21
+ constructor(client: PrismaAuthzClientLike);
22
+ /**
23
+ * No-op: Prisma is schema-first / consumer-managed. Declare the RBAC models in your
24
+ * `schema.prisma` (see {@link PrismaAuthzClientLike}) and apply them with
25
+ * `prisma migrate` / `prisma db push` — this adapter never runs DDL. Present for parity
26
+ * with the other adapters' store surface.
27
+ */
28
+ ensureSchema(): Promise<void>;
29
+ /** Create the role if absent; returns its id. Idempotent and race-tolerant. */
30
+ createRole(name: string): Promise<string>;
31
+ /** Create the permission if absent; returns its id. Idempotent and race-tolerant. */
32
+ createPermission(name: string): Promise<string>;
33
+ private findRoleId;
34
+ private findPermissionId;
35
+ /** Grant a permission to a role (creating both by name if needed). Idempotent. */
36
+ givePermissionToRole(roleName: string, permissionName: string): Promise<void>;
37
+ /** Revoke a permission from a role. No-op if either is absent or not linked. */
38
+ revokePermissionFromRole(roleName: string, permissionName: string): Promise<void>;
39
+ /** Assign a role to a user (creating the role by name if needed). Idempotent. */
40
+ assignRole(user: UserRef, roleName: string): Promise<void>;
41
+ /** Remove a role from a user. No-op if the role or assignment is absent. */
42
+ removeRole(user: UserRef, roleName: string): Promise<void>;
43
+ /** The role names a user holds. */
44
+ getRolesForUser(user: UserRef): Promise<string[]>;
45
+ /** The flattened, distinct permission names a user has via their roles. */
46
+ getPermissionsForUser(user: UserRef): Promise<string[]>;
47
+ /** A user's roles + effective permissions in one shot. */
48
+ getUserAuthz(user: UserRef): Promise<UserAuthz>;
49
+ /** True when the user holds `permission` through any of their roles. */
50
+ userHasPermission(user: UserRef, permission: string): Promise<boolean>;
51
+ }
52
+ //# sourceMappingURL=prisma-authz.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-authz.store.d.ts","sourceRoot":"","sources":["../src/prisma-authz.store.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAe1C;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,qBACa,gBAAgB;IAGzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,qBAAqB;IAGhD;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAMnC,+EAA+E;IACzE,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgB/C,qFAAqF;IAC/E,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAevC,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;IAWvD,2EAA2E;IACrE,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkB7D,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,187 @@
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
+ import { randomUUID } from 'node:crypto';
14
+ import { PRISMA_CLIENT } from './prisma-client.js';
15
+ // Optional Nest DI decorators — declared structurally so this package does not need a
16
+ // hard runtime dependency on @nestjs/common for the POJO store (the module supplies the
17
+ // real Inject token). The store is usable as a plain POJO: `new PrismaAuthzStore(client)`.
18
+ import { Inject, Injectable } from '@nestjs/common';
19
+ /** Normalize a {@link UserRef} to `{ type, id }` with `id` stringified. */
20
+ function normalizeUserRef(ref) {
21
+ if (typeof ref === 'string' || typeof ref === 'number') {
22
+ return { type: 'user', id: String(ref) };
23
+ }
24
+ return { type: ref.type ?? 'user', id: String(ref.id) };
25
+ }
26
+ /**
27
+ * Prisma-backed RBAC store. Receives the app-owned Prisma client via the
28
+ * {@link PRISMA_CLIENT} DI token — NO internal connection ownership, NO `@prisma/client`
29
+ * import (it consumes the structural {@link PrismaAuthzClientLike}).
30
+ *
31
+ * Same method surface as the TypeORM/MikroORM adapters. The user is referenced BY ID ONLY
32
+ * — this package never owns a users table.
33
+ */
34
+ let PrismaAuthzStore = class PrismaAuthzStore {
35
+ client;
36
+ constructor(client) {
37
+ this.client = client;
38
+ }
39
+ /**
40
+ * No-op: Prisma is schema-first / consumer-managed. Declare the RBAC models in your
41
+ * `schema.prisma` (see {@link PrismaAuthzClientLike}) and apply them with
42
+ * `prisma migrate` / `prisma db push` — this adapter never runs DDL. Present for parity
43
+ * with the other adapters' store surface.
44
+ */
45
+ async ensureSchema() {
46
+ // Intentionally empty — see the doc comment.
47
+ }
48
+ // --- roles & permissions (idempotent upserts by name) ---
49
+ /** Create the role if absent; returns its id. Idempotent and race-tolerant. */
50
+ async createRole(name) {
51
+ const existing = await this.findRoleId(name);
52
+ if (existing)
53
+ return existing;
54
+ try {
55
+ const row = await this.client.role.create({
56
+ data: { id: randomUUID(), name, guard: null, createdAt: new Date() },
57
+ });
58
+ return row.id;
59
+ }
60
+ catch {
61
+ // A concurrent insert won the race on the unique `name`; re-read.
62
+ const id = await this.findRoleId(name);
63
+ if (!id)
64
+ throw new Error(`Failed to create or resolve role "${name}".`);
65
+ return id;
66
+ }
67
+ }
68
+ /** Create the permission if absent; returns its id. Idempotent and race-tolerant. */
69
+ async createPermission(name) {
70
+ const existing = await this.findPermissionId(name);
71
+ if (existing)
72
+ return existing;
73
+ try {
74
+ const row = await this.client.permission.create({
75
+ data: { id: randomUUID(), name, guard: null, createdAt: new Date() },
76
+ });
77
+ return row.id;
78
+ }
79
+ catch {
80
+ const id = await this.findPermissionId(name);
81
+ if (!id)
82
+ throw new Error(`Failed to create or resolve permission "${name}".`);
83
+ return id;
84
+ }
85
+ }
86
+ async findRoleId(name) {
87
+ const row = await this.client.role.findFirst({ where: { name } });
88
+ return row?.id;
89
+ }
90
+ async findPermissionId(name) {
91
+ const row = await this.client.permission.findFirst({ where: { name } });
92
+ return row?.id;
93
+ }
94
+ // --- role ↔ permission ---
95
+ /** Grant a permission to a role (creating both by name if needed). Idempotent. */
96
+ async givePermissionToRole(roleName, permissionName) {
97
+ const roleId = await this.createRole(roleName);
98
+ const permissionId = await this.createPermission(permissionName);
99
+ const existing = await this.client.rolePermission.findFirst({
100
+ where: { roleId, permissionId },
101
+ });
102
+ if (existing)
103
+ return;
104
+ await this.client.rolePermission.create({ data: { roleId, permissionId } });
105
+ }
106
+ /** Revoke a permission from a role. No-op if either is absent or not linked. */
107
+ async revokePermissionFromRole(roleName, permissionName) {
108
+ const roleId = await this.findRoleId(roleName);
109
+ const permissionId = await this.findPermissionId(permissionName);
110
+ if (!roleId || !permissionId)
111
+ return;
112
+ await this.client.rolePermission.deleteMany({ where: { roleId, permissionId } });
113
+ }
114
+ // --- user ↔ role ---
115
+ /** Assign a role to a user (creating the role by name if needed). Idempotent. */
116
+ async assignRole(user, roleName) {
117
+ const { type, id } = normalizeUserRef(user);
118
+ const roleId = await this.createRole(roleName);
119
+ const existing = await this.client.userRole.findFirst({
120
+ where: { userType: type, userId: id, roleId },
121
+ });
122
+ if (existing)
123
+ return;
124
+ await this.client.userRole.create({ data: { userType: type, userId: id, roleId } });
125
+ }
126
+ /** Remove a role from a user. No-op if the role or assignment is absent. */
127
+ async removeRole(user, roleName) {
128
+ const { type, id } = normalizeUserRef(user);
129
+ const roleId = await this.findRoleId(roleName);
130
+ if (!roleId)
131
+ return;
132
+ await this.client.userRole.deleteMany({ where: { userType: type, userId: id, roleId } });
133
+ }
134
+ // --- queries ---
135
+ /** The role names a user holds. */
136
+ async getRolesForUser(user) {
137
+ const { type, id } = normalizeUserRef(user);
138
+ const assignments = await this.client.userRole.findMany({
139
+ where: { userType: type, userId: id },
140
+ });
141
+ if (assignments.length === 0)
142
+ return [];
143
+ const roleIds = assignments.map((a) => a.roleId);
144
+ const roles = await this.client.role.findMany({ where: { id: { in: roleIds } } });
145
+ return roles.map((r) => r.name);
146
+ }
147
+ /** The flattened, distinct permission names a user has via their roles. */
148
+ async getPermissionsForUser(user) {
149
+ const { type, id } = normalizeUserRef(user);
150
+ const assignments = await this.client.userRole.findMany({
151
+ where: { userType: type, userId: id },
152
+ });
153
+ if (assignments.length === 0)
154
+ return [];
155
+ const roleIds = assignments.map((a) => a.roleId);
156
+ const links = await this.client.rolePermission.findMany({
157
+ where: { roleId: { in: roleIds } },
158
+ });
159
+ if (links.length === 0)
160
+ return [];
161
+ const permissionIds = [...new Set(links.map((l) => l.permissionId))];
162
+ const permissions = await this.client.permission.findMany({
163
+ where: { id: { in: permissionIds } },
164
+ });
165
+ return [...new Set(permissions.map((p) => p.name))];
166
+ }
167
+ /** A user's roles + effective permissions in one shot. */
168
+ async getUserAuthz(user) {
169
+ const [roles, permissions] = await Promise.all([
170
+ this.getRolesForUser(user),
171
+ this.getPermissionsForUser(user),
172
+ ]);
173
+ return { roles, permissions };
174
+ }
175
+ /** True when the user holds `permission` through any of their roles. */
176
+ async userHasPermission(user, permission) {
177
+ const permissions = await this.getPermissionsForUser(user);
178
+ return permissions.includes(permission);
179
+ }
180
+ };
181
+ PrismaAuthzStore = __decorate([
182
+ Injectable(),
183
+ __param(0, Inject(PRISMA_CLIENT)),
184
+ __metadata("design:paramtypes", [Object])
185
+ ], PrismaAuthzStore);
186
+ export { PrismaAuthzStore };
187
+ //# sourceMappingURL=prisma-authz.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-authz.store.js","sourceRoot":"","sources":["../src/prisma-authz.store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Structural typings + DI token for the Prisma client consumed by
3
+ * {@link PrismaAuthzStore}.
4
+ *
5
+ * The adapter deliberately does NOT import a generated `@prisma/client` type.
6
+ * Instead it depends on a minimal structural interface describing only the model
7
+ * delegate methods it uses. This keeps the package free of any `prisma generate`
8
+ * step and decouples it from the consumer's generated client location/version — a
9
+ * real `PrismaClient` instance structurally satisfies {@link PrismaAuthzClientLike},
10
+ * so you can inject it directly.
11
+ *
12
+ * ## Required Prisma models
13
+ *
14
+ * The consumer's `schema.prisma` must declare these models (the user is referenced
15
+ * **by id only** — this package never owns a users table):
16
+ *
17
+ * ```prisma
18
+ * model Role {
19
+ * id String @id
20
+ * name String @unique
21
+ * guard String?
22
+ * createdAt DateTime @default(now())
23
+ *
24
+ * @@map("authz_roles")
25
+ * }
26
+ *
27
+ * model Permission {
28
+ * id String @id
29
+ * name String @unique
30
+ * guard String?
31
+ * createdAt DateTime @default(now())
32
+ *
33
+ * @@map("authz_permissions")
34
+ * }
35
+ *
36
+ * model RolePermission {
37
+ * roleId String
38
+ * permissionId String
39
+ *
40
+ * @@id([roleId, permissionId])
41
+ * @@map("authz_role_permission")
42
+ * }
43
+ *
44
+ * model UserRole {
45
+ * userType String
46
+ * userId String
47
+ * roleId String
48
+ *
49
+ * @@id([userType, userId, roleId])
50
+ * @@index([userType, userId])
51
+ * @@map("authz_user_role")
52
+ * }
53
+ * ```
54
+ *
55
+ * Apply it with `prisma migrate` / `prisma db push` — this adapter is
56
+ * consumer-managed and never runs DDL.
57
+ */
58
+ /**
59
+ * Minimal structural view of a Prisma model delegate (the methods the store calls).
60
+ *
61
+ * The arg/return types are intentionally `any`: a generated Prisma delegate's method
62
+ * signatures are far narrower (model-specific), and a structural `unknown`/`Record` here
63
+ * would make a real `PrismaClient` *not* assignable to this interface (arg positions are
64
+ * contravariant). `any` keeps a concrete client structurally compatible without pulling in
65
+ * `@prisma/client`.
66
+ */
67
+ export interface PrismaModelDelegate {
68
+ create(args: {
69
+ data: any;
70
+ }): Promise<any>;
71
+ findFirst(args: {
72
+ where: any;
73
+ }): Promise<any>;
74
+ findMany(args: {
75
+ where: any;
76
+ }): Promise<any[]>;
77
+ deleteMany(args: {
78
+ where: any;
79
+ }): Promise<{
80
+ count: number;
81
+ }>;
82
+ }
83
+ /** Minimal structural view of a Prisma client exposing the four RBAC models. */
84
+ export interface PrismaAuthzClientLike {
85
+ role: PrismaModelDelegate;
86
+ permission: PrismaModelDelegate;
87
+ rolePermission: PrismaModelDelegate;
88
+ userRole: PrismaModelDelegate;
89
+ }
90
+ /**
91
+ * DI token for the app-provided Prisma client ({@link PrismaAuthzClientLike})
92
+ * injected into {@link PrismaAuthzStore}.
93
+ */
94
+ export declare const PRISMA_CLIENT: unique symbol;
95
+ //# sourceMappingURL=prisma-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client.d.ts","sourceRoot":"","sources":["../src/prisma-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAElC,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE1C,SAAS,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE9C,QAAQ,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAE/C,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9D;AAED,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,UAAU,EAAE,mBAAmB,CAAC;IAChC,cAAc,EAAE,mBAAmB,CAAC;IACpC,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,eAAqD,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Structural typings + DI token for the Prisma client consumed by
3
+ * {@link PrismaAuthzStore}.
4
+ *
5
+ * The adapter deliberately does NOT import a generated `@prisma/client` type.
6
+ * Instead it depends on a minimal structural interface describing only the model
7
+ * delegate methods it uses. This keeps the package free of any `prisma generate`
8
+ * step and decouples it from the consumer's generated client location/version — a
9
+ * real `PrismaClient` instance structurally satisfies {@link PrismaAuthzClientLike},
10
+ * so you can inject it directly.
11
+ *
12
+ * ## Required Prisma models
13
+ *
14
+ * The consumer's `schema.prisma` must declare these models (the user is referenced
15
+ * **by id only** — this package never owns a users table):
16
+ *
17
+ * ```prisma
18
+ * model Role {
19
+ * id String @id
20
+ * name String @unique
21
+ * guard String?
22
+ * createdAt DateTime @default(now())
23
+ *
24
+ * @@map("authz_roles")
25
+ * }
26
+ *
27
+ * model Permission {
28
+ * id String @id
29
+ * name String @unique
30
+ * guard String?
31
+ * createdAt DateTime @default(now())
32
+ *
33
+ * @@map("authz_permissions")
34
+ * }
35
+ *
36
+ * model RolePermission {
37
+ * roleId String
38
+ * permissionId String
39
+ *
40
+ * @@id([roleId, permissionId])
41
+ * @@map("authz_role_permission")
42
+ * }
43
+ *
44
+ * model UserRole {
45
+ * userType String
46
+ * userId String
47
+ * roleId String
48
+ *
49
+ * @@id([userType, userId, roleId])
50
+ * @@index([userType, userId])
51
+ * @@map("authz_user_role")
52
+ * }
53
+ * ```
54
+ *
55
+ * Apply it with `prisma migrate` / `prisma db push` — this adapter is
56
+ * consumer-managed and never runs DDL.
57
+ */
58
+ /**
59
+ * DI token for the app-provided Prisma client ({@link PrismaAuthzClientLike})
60
+ * injected into {@link PrismaAuthzStore}.
61
+ */
62
+ export const PRISMA_CLIENT = Symbol.for('@dudousxd/nestjs-authz-prisma:client');
63
+ //# sourceMappingURL=prisma-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client.js","sourceRoot":"","sources":["../src/prisma-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AA8BH;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
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
+ //# 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"}
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,62 @@
1
+ {
2
+ "name": "@dudousxd/nestjs-authz-prisma",
3
+ "version": "0.2.0",
4
+ "description": "Prisma RBAC persistence for @dudousxd/nestjs-authz — roles, permissions, and a Gate seam (zero connection ownership, structural client).",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/DavideCarvalho/nestjs-authz.git",
9
+ "directory": "packages/prisma"
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
+ "@nestjs/common": ">=10.0.0",
30
+ "@nestjs/core": ">=10.0.0",
31
+ "reflect-metadata": ">=0.1.13"
32
+ },
33
+ "devDependencies": {
34
+ "@nestjs/common": "^11.0.0",
35
+ "@nestjs/core": "^11.0.0",
36
+ "@nestjs/testing": "^11.0.0",
37
+ "@types/node": "^20.0.0",
38
+ "reflect-metadata": "^0.2.2",
39
+ "rxjs": "^7.8.1",
40
+ "typescript": "^5.4.0",
41
+ "vitest": "^3.0.0",
42
+ "@dudousxd/nestjs-authz": "^0.4.0"
43
+ },
44
+ "engines": {
45
+ "node": ">=20"
46
+ },
47
+ "keywords": [
48
+ "nestjs",
49
+ "authorization",
50
+ "authz",
51
+ "rbac",
52
+ "roles",
53
+ "permissions",
54
+ "prisma"
55
+ ],
56
+ "scripts": {
57
+ "build": "tsc -p tsconfig.json",
58
+ "test": "vitest run --passWithNoTests",
59
+ "test:watch": "vitest",
60
+ "typecheck": "tsc -p tsconfig.json --noEmit"
61
+ }
62
+ }