@dudousxd/nestjs-authz-typeorm 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 +7 -0
- package/LICENSE +21 -0
- package/dist/authz-rbac.module.d.ts +46 -0
- package/dist/authz-rbac.module.d.ts.map +1 -0
- package/dist/authz-rbac.module.js +128 -0
- package/dist/authz-rbac.module.js.map +1 -0
- package/dist/entities.d.ts +51 -0
- package/dist/entities.d.ts.map +1 -0
- package/dist/entities.js +137 -0
- package/dist/entities.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +24 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +116 -0
- package/dist/schema.js.map +1 -0
- package/dist/sql.d.ts +30 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +58 -0
- package/dist/sql.js.map +1 -0
- package/dist/typeorm-authz.store.d.ts +64 -0
- package/dist/typeorm-authz.store.d.ts.map +1 -0
- package/dist/typeorm-authz.store.js +196 -0
- package/dist/typeorm-authz.store.js.map +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @dudousxd/nestjs-authz-typeorm
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`51d2fbc`](https://github.com/DavideCarvalho/nestjs-authz/commit/51d2fbc6b966c101a6ff0675c42843f040e02703) - Initial release: Laravel-style authorization for NestJS — gates, `@Policy`/`@Can`, the `Gate` service, a default `:id` resource resolver, `before`/`superAdmin` hooks, optional `nestjs-context` current-user with `resolveUser` hydration, and a `PERMISSION_PROVIDER` seam. The `@dudousxd/nestjs-authz-typeorm` adapter adds opt-in RBAC persistence (roles/permissions store, dialect-correct SQL, identifier allowlist, non-destructive schema auto-manage).
|
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.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type DynamicModule } from '@nestjs/common';
|
|
2
|
+
import type { TypeOrmAuthzStore } from './typeorm-authz.store.js';
|
|
3
|
+
import type { UserRef } from './types.js';
|
|
4
|
+
/** Injection token holding the {@link TypeOrmAuthzStore} 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 TypeORM RBAC store (built with the app-provided DataSource). */
|
|
15
|
+
store: TypeOrmAuthzStore;
|
|
16
|
+
/**
|
|
17
|
+
* Run `ensureAuthzSchema` on bootstrap (default `true`, non-destructive). Set `false`
|
|
18
|
+
* to manage the schema via your ORM's migrations (`createAuthzTables` 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 `DataSource`
|
|
36
|
+
* (via `inject`/`useFactory`) and constructs the {@link TypeOrmAuthzStore} — 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":"AACA,OAAO,EACL,KAAK,aAAa,EAQnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,eAAqD,CAAC;AACnF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,eAAuD,CAAC;AAEvF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GAAG,SAAS,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,KAAK,EAAE,iBAAiB,CAAC;IACzB;;;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;AAiCD;;;;;;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;CAO/B"}
|
|
@@ -0,0 +1,128 @@
|
|
|
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 } from '@dudousxd/nestjs-authz';
|
|
15
|
+
import { Inject, Injectable, Module, Optional, } from '@nestjs/common';
|
|
16
|
+
/** Injection token holding the {@link TypeOrmAuthzStore} the RBAC module manages. */
|
|
17
|
+
export const AUTHZ_RBAC_STORE = Symbol.for('@dudousxd/nestjs-authz-typeorm:store');
|
|
18
|
+
/** Injection token holding the resolved {@link AuthzRbacModuleOptions}. */
|
|
19
|
+
export const AUTHZ_RBAC_OPTIONS = Symbol.for('@dudousxd/nestjs-authz-typeorm: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
|
+
async hasPermission(user, permission) {
|
|
43
|
+
const map = this.options.userRefFrom ?? defaultUserRefMapper;
|
|
44
|
+
const ref = map(user);
|
|
45
|
+
if (ref === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
return this.options.store.userHasPermission(ref, permission);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
RbacPermissionProvider = __decorate([
|
|
51
|
+
Injectable(),
|
|
52
|
+
__param(0, Inject(AUTHZ_RBAC_OPTIONS)),
|
|
53
|
+
__metadata("design:paramtypes", [Object])
|
|
54
|
+
], RbacPermissionProvider);
|
|
55
|
+
/** Runs `ensureAuthzSchema` on bootstrap when `autoCreateSchema` is not disabled. */
|
|
56
|
+
let AuthzRbacBootstrap = class AuthzRbacBootstrap {
|
|
57
|
+
options;
|
|
58
|
+
constructor(options) {
|
|
59
|
+
this.options = options;
|
|
60
|
+
}
|
|
61
|
+
async onModuleInit() {
|
|
62
|
+
if (!this.options)
|
|
63
|
+
return;
|
|
64
|
+
if (this.options.autoCreateSchema === false)
|
|
65
|
+
return;
|
|
66
|
+
await this.options.store.ensureSchema();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
AuthzRbacBootstrap = __decorate([
|
|
70
|
+
Injectable(),
|
|
71
|
+
__param(0, Optional()),
|
|
72
|
+
__param(0, Inject(AUTHZ_RBAC_OPTIONS)),
|
|
73
|
+
__metadata("design:paramtypes", [Object])
|
|
74
|
+
], AuthzRbacBootstrap);
|
|
75
|
+
/**
|
|
76
|
+
* Wires persisted RBAC into the core authz Gate. The app provides the `DataSource`
|
|
77
|
+
* (via `inject`/`useFactory`) and constructs the {@link TypeOrmAuthzStore} — this module
|
|
78
|
+
* NEVER hardcodes a connection token. On init it registers the RBAC permission check into
|
|
79
|
+
* the Gate via the {@link PERMISSION_PROVIDER} seam, so `gate.allows('some.permission')`
|
|
80
|
+
* consults persisted permissions, and (by default) ensures the schema exists.
|
|
81
|
+
*/
|
|
82
|
+
let AuthzRbacModule = AuthzRbacModule_1 = class AuthzRbacModule {
|
|
83
|
+
static forRoot(options) {
|
|
84
|
+
return {
|
|
85
|
+
module: AuthzRbacModule_1,
|
|
86
|
+
global: true,
|
|
87
|
+
providers: [
|
|
88
|
+
{ provide: AUTHZ_RBAC_OPTIONS, useValue: options },
|
|
89
|
+
{ provide: AUTHZ_RBAC_STORE, useValue: options.store },
|
|
90
|
+
...AuthzRbacModule_1.commonProviders(),
|
|
91
|
+
],
|
|
92
|
+
exports: [AUTHZ_RBAC_STORE, PERMISSION_PROVIDER],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
static forRootAsync(options) {
|
|
96
|
+
return {
|
|
97
|
+
module: AuthzRbacModule_1,
|
|
98
|
+
global: true,
|
|
99
|
+
imports: (options.imports ?? []),
|
|
100
|
+
providers: [
|
|
101
|
+
{
|
|
102
|
+
provide: AUTHZ_RBAC_OPTIONS,
|
|
103
|
+
useFactory: options.useFactory,
|
|
104
|
+
inject: (options.inject ?? []),
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
provide: AUTHZ_RBAC_STORE,
|
|
108
|
+
useFactory: (opts) => opts.store,
|
|
109
|
+
inject: [AUTHZ_RBAC_OPTIONS],
|
|
110
|
+
},
|
|
111
|
+
...AuthzRbacModule_1.commonProviders(),
|
|
112
|
+
],
|
|
113
|
+
exports: [AUTHZ_RBAC_STORE, PERMISSION_PROVIDER],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
static commonProviders() {
|
|
117
|
+
return [
|
|
118
|
+
RbacPermissionProvider,
|
|
119
|
+
{ provide: PERMISSION_PROVIDER, useExisting: RbacPermissionProvider },
|
|
120
|
+
AuthzRbacBootstrap,
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
AuthzRbacModule = AuthzRbacModule_1 = __decorate([
|
|
125
|
+
Module({})
|
|
126
|
+
], AuthzRbacModule);
|
|
127
|
+
export { AuthzRbacModule };
|
|
128
|
+
//# 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,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default table names. Override per-deployment via {@link AuthzStoreOptions.tableNames}
|
|
3
|
+
* — the entities below carry these as their decorator defaults so an app that manages
|
|
4
|
+
* the schema through its own ORM gets sane names out of the box, while BYO names flow
|
|
5
|
+
* through the store/schema helpers at runtime.
|
|
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
|
+
* Forward-compat rule: any column added to these entities AFTER v1 MUST be nullable or
|
|
18
|
+
* carry a default — `ADD COLUMN NOT NULL` without a default fails on a populated table,
|
|
19
|
+
* and {@link ensureAuthzSchema} only ever ADDs columns.
|
|
20
|
+
*/
|
|
21
|
+
export declare class RoleEntity {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
guard: string | null;
|
|
25
|
+
createdAt: Date;
|
|
26
|
+
}
|
|
27
|
+
/** A named permission (e.g. `posts.publish`). Granted to roles via {@link RolePermissionEntity}. */
|
|
28
|
+
export declare class PermissionEntity {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
guard: string | null;
|
|
32
|
+
createdAt: Date;
|
|
33
|
+
}
|
|
34
|
+
/** Pivot: role ↔ permission. Composite PK `(roleId, permissionId)`. */
|
|
35
|
+
export declare class RolePermissionEntity {
|
|
36
|
+
roleId: string;
|
|
37
|
+
permissionId: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Pivot: user ↔ role. References the user BY ID ONLY — this package NEVER defines or
|
|
41
|
+
* owns a users table. `userType` lets the same table key polymorphic principals
|
|
42
|
+
* (mirrors nestjs-context's `UserRef` shape).
|
|
43
|
+
*/
|
|
44
|
+
export declare class UserRoleEntity {
|
|
45
|
+
userType: string;
|
|
46
|
+
userId: string;
|
|
47
|
+
roleId: string;
|
|
48
|
+
}
|
|
49
|
+
/** All entities, in dependency order — convenient for `entities: [...]` registration. */
|
|
50
|
+
export declare const AUTHZ_ENTITIES: readonly [typeof RoleEntity, typeof PermissionEntity, typeof RolePermissionEntity, typeof UserRoleEntity];
|
|
51
|
+
//# 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;;;;;;;GAOG;AACH,qBACa,UAAU;IAErB,EAAE,EAAG,MAAM,CAAC;IAIZ,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,EAAG,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,EAAG,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"}
|
package/dist/entities.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
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 { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
|
11
|
+
/**
|
|
12
|
+
* Default table names. Override per-deployment via {@link AuthzStoreOptions.tableNames}
|
|
13
|
+
* — the entities below carry these as their decorator defaults so an app that manages
|
|
14
|
+
* the schema through its own ORM gets sane names out of the box, while BYO names flow
|
|
15
|
+
* through the store/schema helpers at runtime.
|
|
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
|
+
* Forward-compat rule: any column added to these entities AFTER v1 MUST be nullable or
|
|
28
|
+
* carry a default — `ADD COLUMN NOT NULL` without a default fails on a populated table,
|
|
29
|
+
* and {@link ensureAuthzSchema} only ever ADDs columns.
|
|
30
|
+
*/
|
|
31
|
+
let RoleEntity = class RoleEntity {
|
|
32
|
+
id;
|
|
33
|
+
name;
|
|
34
|
+
guard;
|
|
35
|
+
createdAt;
|
|
36
|
+
};
|
|
37
|
+
__decorate([
|
|
38
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], RoleEntity.prototype, "id", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
Index({ unique: true }),
|
|
43
|
+
Column({ type: 'varchar', length: 191 }),
|
|
44
|
+
__metadata("design:type", String)
|
|
45
|
+
], RoleEntity.prototype, "name", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
Column({ type: 'varchar', nullable: true }),
|
|
48
|
+
__metadata("design:type", Object)
|
|
49
|
+
], RoleEntity.prototype, "guard", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
Column({ type: Date }),
|
|
52
|
+
__metadata("design:type", Date)
|
|
53
|
+
], RoleEntity.prototype, "createdAt", void 0);
|
|
54
|
+
RoleEntity = __decorate([
|
|
55
|
+
Entity({ name: DEFAULT_TABLE_NAMES.roles })
|
|
56
|
+
], RoleEntity);
|
|
57
|
+
export { RoleEntity };
|
|
58
|
+
/** A named permission (e.g. `posts.publish`). Granted to roles via {@link RolePermissionEntity}. */
|
|
59
|
+
let PermissionEntity = class PermissionEntity {
|
|
60
|
+
id;
|
|
61
|
+
name;
|
|
62
|
+
guard;
|
|
63
|
+
createdAt;
|
|
64
|
+
};
|
|
65
|
+
__decorate([
|
|
66
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
67
|
+
__metadata("design:type", String)
|
|
68
|
+
], PermissionEntity.prototype, "id", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
Index({ unique: true }),
|
|
71
|
+
Column({ type: 'varchar', length: 191 }),
|
|
72
|
+
__metadata("design:type", String)
|
|
73
|
+
], PermissionEntity.prototype, "name", void 0);
|
|
74
|
+
__decorate([
|
|
75
|
+
Column({ type: 'varchar', nullable: true }),
|
|
76
|
+
__metadata("design:type", Object)
|
|
77
|
+
], PermissionEntity.prototype, "guard", void 0);
|
|
78
|
+
__decorate([
|
|
79
|
+
Column({ type: Date }),
|
|
80
|
+
__metadata("design:type", Date)
|
|
81
|
+
], PermissionEntity.prototype, "createdAt", void 0);
|
|
82
|
+
PermissionEntity = __decorate([
|
|
83
|
+
Entity({ name: DEFAULT_TABLE_NAMES.permissions })
|
|
84
|
+
], PermissionEntity);
|
|
85
|
+
export { PermissionEntity };
|
|
86
|
+
/** Pivot: role ↔ permission. Composite PK `(roleId, permissionId)`. */
|
|
87
|
+
let RolePermissionEntity = class RolePermissionEntity {
|
|
88
|
+
roleId;
|
|
89
|
+
permissionId;
|
|
90
|
+
};
|
|
91
|
+
__decorate([
|
|
92
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
93
|
+
__metadata("design:type", String)
|
|
94
|
+
], RolePermissionEntity.prototype, "roleId", void 0);
|
|
95
|
+
__decorate([
|
|
96
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
97
|
+
__metadata("design:type", String)
|
|
98
|
+
], RolePermissionEntity.prototype, "permissionId", void 0);
|
|
99
|
+
RolePermissionEntity = __decorate([
|
|
100
|
+
Entity({ name: DEFAULT_TABLE_NAMES.rolePermission })
|
|
101
|
+
], RolePermissionEntity);
|
|
102
|
+
export { RolePermissionEntity };
|
|
103
|
+
/**
|
|
104
|
+
* Pivot: user ↔ role. References the user BY ID ONLY — this package NEVER defines or
|
|
105
|
+
* owns a users table. `userType` lets the same table key polymorphic principals
|
|
106
|
+
* (mirrors nestjs-context's `UserRef` shape).
|
|
107
|
+
*/
|
|
108
|
+
let UserRoleEntity = class UserRoleEntity {
|
|
109
|
+
userType;
|
|
110
|
+
userId;
|
|
111
|
+
roleId;
|
|
112
|
+
};
|
|
113
|
+
__decorate([
|
|
114
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
115
|
+
__metadata("design:type", String)
|
|
116
|
+
], UserRoleEntity.prototype, "userType", void 0);
|
|
117
|
+
__decorate([
|
|
118
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
119
|
+
__metadata("design:type", String)
|
|
120
|
+
], UserRoleEntity.prototype, "userId", void 0);
|
|
121
|
+
__decorate([
|
|
122
|
+
PrimaryColumn({ type: 'varchar', length: 191 }),
|
|
123
|
+
__metadata("design:type", String)
|
|
124
|
+
], UserRoleEntity.prototype, "roleId", void 0);
|
|
125
|
+
UserRoleEntity = __decorate([
|
|
126
|
+
Entity({ name: DEFAULT_TABLE_NAMES.userRole }),
|
|
127
|
+
Index(['userType', 'userId'])
|
|
128
|
+
], UserRoleEntity);
|
|
129
|
+
export { UserRoleEntity };
|
|
130
|
+
/** All entities, in dependency order — convenient for `entities: [...]` registration. */
|
|
131
|
+
export const AUTHZ_ENTITIES = [
|
|
132
|
+
RoleEntity,
|
|
133
|
+
PermissionEntity,
|
|
134
|
+
RolePermissionEntity,
|
|
135
|
+
UserRoleEntity,
|
|
136
|
+
];
|
|
137
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { AUTHZ_ENTITIES, DEFAULT_TABLE_NAMES, PermissionEntity, RoleEntity, RolePermissionEntity, UserRoleEntity, } from './entities.js';
|
|
2
|
+
export { createAuthzTables, ensureAuthzSchema } from './schema.js';
|
|
3
|
+
export { TypeOrmAuthzStore } from './typeorm-authz.store.js';
|
|
4
|
+
export type { UserAuthz } from './typeorm-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, TableNames, 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,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,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,UAAU,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 { createAuthzTables, ensureAuthzSchema } from './schema.js';
|
|
3
|
+
export { TypeOrmAuthzStore } from './typeorm-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,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,wBAAwB,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type DataSource, type QueryRunner } from 'typeorm';
|
|
2
|
+
import type { AuthzStoreOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create the RBAC tables (roles, permissions, and the two pivots) if they don't exist.
|
|
5
|
+
* Strictly non-destructive — `CREATE TABLE` only runs for a table that is absent. Call it
|
|
6
|
+
* from a TypeORM migration when `autoCreateSchema: false`:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createAuthzTables } from '@dudousxd/nestjs-authz-typeorm';
|
|
10
|
+
* export class AddAuthz1700000000000 implements MigrationInterface {
|
|
11
|
+
* async up(qr: QueryRunner) { await createAuthzTables(qr); }
|
|
12
|
+
* async down(qr: QueryRunner) { ... }
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function createAuthzTables(queryRunner: QueryRunner, opts?: AuthzStoreOptions): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Ensure the RBAC schema is up to date via a DataSource (used by the store's `ensureSchema`
|
|
19
|
+
* on bootstrap). For each table: creates it if missing, otherwise non-destructively adds any
|
|
20
|
+
* columns that exist in the entity metadata but not yet in the live table (see
|
|
21
|
+
* {@link addMissingColumns}). Never drops/alters/renames — safe to run on every boot.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ensureAuthzSchema(dataSource: DataSource, opts?: AuthzStoreOptions): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,WAAW,EAGjB,MAAM,SAAS,CAAC;AAUjB,OAAO,KAAK,EAAE,iBAAiB,EAAc,MAAM,YAAY,CAAC;AAuDhE;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,WAAW,EACxB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CAOf;AA4BD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,UAAU,EACtB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CAef"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Table, TableColumn, } from 'typeorm';
|
|
2
|
+
import { TableUtils } from 'typeorm/schema-builder/util/TableUtils.js';
|
|
3
|
+
import { DEFAULT_TABLE_NAMES, PermissionEntity, RoleEntity, RolePermissionEntity, UserRoleEntity, } from './entities.js';
|
|
4
|
+
import { assertSafeIdentifier } from './sql.js';
|
|
5
|
+
/** Resolve the (schema-qualified) table name for an entity, applying BYO overrides. */
|
|
6
|
+
function tableName(base, schema) {
|
|
7
|
+
return schema ? `${schema}.${base}` : base;
|
|
8
|
+
}
|
|
9
|
+
function resolveNames(tableNames) {
|
|
10
|
+
return {
|
|
11
|
+
roles: tableNames?.roles ?? DEFAULT_TABLE_NAMES.roles,
|
|
12
|
+
permissions: tableNames?.permissions ?? DEFAULT_TABLE_NAMES.permissions,
|
|
13
|
+
rolePermission: tableNames?.rolePermission ?? DEFAULT_TABLE_NAMES.rolePermission,
|
|
14
|
+
userRole: tableNames?.userRole ?? DEFAULT_TABLE_NAMES.userRole,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** The four table plans (entity + resolved name) for a given options set. */
|
|
18
|
+
function plans(opts) {
|
|
19
|
+
const names = resolveNames(opts?.tableNames);
|
|
20
|
+
const schema = opts?.schema;
|
|
21
|
+
// P4: reject hostile BYO identifiers before they reach DDL.
|
|
22
|
+
for (const [key, name] of Object.entries(names)) {
|
|
23
|
+
assertSafeIdentifier(name, `table name (${key})`);
|
|
24
|
+
}
|
|
25
|
+
if (schema !== undefined)
|
|
26
|
+
assertSafeIdentifier(schema, 'schema name');
|
|
27
|
+
return [
|
|
28
|
+
{ entity: RoleEntity, name: tableName(names.roles, schema) },
|
|
29
|
+
{ entity: PermissionEntity, name: tableName(names.permissions, schema) },
|
|
30
|
+
{ entity: RolePermissionEntity, name: tableName(names.rolePermission, schema) },
|
|
31
|
+
{ entity: UserRoleEntity, name: tableName(names.userRole, schema) },
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a driver-portable {@link Table} from entity metadata, overriding the table name
|
|
36
|
+
* so BYO names + an optional Postgres schema are honored (the metadata's own name is the
|
|
37
|
+
* entity-decorator default).
|
|
38
|
+
*/
|
|
39
|
+
function tableFromMetadata(metadata, driver, name) {
|
|
40
|
+
const table = Table.create(metadata, driver);
|
|
41
|
+
table.name = name;
|
|
42
|
+
return table;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create the RBAC tables (roles, permissions, and the two pivots) if they don't exist.
|
|
46
|
+
* Strictly non-destructive — `CREATE TABLE` only runs for a table that is absent. Call it
|
|
47
|
+
* from a TypeORM migration when `autoCreateSchema: false`:
|
|
48
|
+
*
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { createAuthzTables } from '@dudousxd/nestjs-authz-typeorm';
|
|
51
|
+
* export class AddAuthz1700000000000 implements MigrationInterface {
|
|
52
|
+
* async up(qr: QueryRunner) { await createAuthzTables(qr); }
|
|
53
|
+
* async down(qr: QueryRunner) { ... }
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export async function createAuthzTables(queryRunner, opts) {
|
|
58
|
+
const driver = queryRunner.connection.driver;
|
|
59
|
+
for (const plan of plans(opts)) {
|
|
60
|
+
if (await queryRunner.hasTable(plan.name))
|
|
61
|
+
continue;
|
|
62
|
+
const metadata = queryRunner.connection.getMetadata(plan.entity);
|
|
63
|
+
await queryRunner.createTable(tableFromMetadata(metadata, driver, plan.name), true);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Add any columns present in the entity metadata but missing from the live table.
|
|
68
|
+
*
|
|
69
|
+
* Strictly non-destructive: it only ever ADDs columns — never drops, alters the type of,
|
|
70
|
+
* renames, or otherwise touches existing columns, and is order-independent. Each missing
|
|
71
|
+
* column is built from the entity's `ColumnMetadata` the same way `Table.create` derives a
|
|
72
|
+
* table (via `TableUtils.createTableColumnOptions`), so the resulting `TableColumn` is
|
|
73
|
+
* driver-portable across SQLite, MySQL and Postgres.
|
|
74
|
+
*
|
|
75
|
+
* Forward-compat rule: any column added to an authz entity after v1 MUST be nullable or have
|
|
76
|
+
* a default. `ADD COLUMN` of a NOT NULL column without a default fails on a populated table.
|
|
77
|
+
*/
|
|
78
|
+
async function addMissingColumns(queryRunner, plan) {
|
|
79
|
+
const metadata = queryRunner.connection.getMetadata(plan.entity);
|
|
80
|
+
const driver = queryRunner.connection.driver;
|
|
81
|
+
const table = await queryRunner.getTable(plan.name);
|
|
82
|
+
if (!table)
|
|
83
|
+
return;
|
|
84
|
+
const existing = new Set(table.columns.map((column) => column.name));
|
|
85
|
+
for (const column of metadata.columns) {
|
|
86
|
+
if (column.isVirtualProperty || existing.has(column.databaseName))
|
|
87
|
+
continue;
|
|
88
|
+
const tableColumn = new TableColumn(TableUtils.createTableColumnOptions(column, driver));
|
|
89
|
+
await queryRunner.addColumn(plan.name, tableColumn);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Ensure the RBAC schema is up to date via a DataSource (used by the store's `ensureSchema`
|
|
94
|
+
* on bootstrap). For each table: creates it if missing, otherwise non-destructively adds any
|
|
95
|
+
* columns that exist in the entity metadata but not yet in the live table (see
|
|
96
|
+
* {@link addMissingColumns}). Never drops/alters/renames — safe to run on every boot.
|
|
97
|
+
*/
|
|
98
|
+
export async function ensureAuthzSchema(dataSource, opts) {
|
|
99
|
+
const queryRunner = dataSource.createQueryRunner();
|
|
100
|
+
try {
|
|
101
|
+
const driver = dataSource.driver;
|
|
102
|
+
for (const plan of plans(opts)) {
|
|
103
|
+
if (await queryRunner.hasTable(plan.name)) {
|
|
104
|
+
await addMissingColumns(queryRunner, plan);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const metadata = queryRunner.connection.getMetadata(plan.entity);
|
|
108
|
+
await queryRunner.createTable(tableFromMetadata(metadata, driver, plan.name), true);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
await queryRunner.release();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/sql.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DataSource } from 'typeorm';
|
|
2
|
+
/** True when the DataSource's driver expects `$n` positional placeholders. */
|
|
3
|
+
export declare function isPostgresFamily(dataSource: DataSource): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Build the placeholder token for the parameter at 0-based `index`, dialect-correct
|
|
6
|
+
* for the given DataSource: `$1, $2, …` on Postgres-family drivers, `?` elsewhere.
|
|
7
|
+
*/
|
|
8
|
+
export declare function placeholder(dataSource: DataSource, index: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* A tiny helper that hands out dialect-correct, sequentially-numbered placeholders.
|
|
11
|
+
* Each call to {@link Placeholders.next} returns the next token (`?` or `$n`), so a
|
|
12
|
+
* single query can interleave them in parameter order regardless of dialect.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Placeholders {
|
|
15
|
+
private readonly postgres;
|
|
16
|
+
private index;
|
|
17
|
+
constructor(postgres: boolean);
|
|
18
|
+
static for(dataSource: DataSource): Placeholders;
|
|
19
|
+
/** The next placeholder token, advancing the positional counter. */
|
|
20
|
+
next(): string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Validate an identifier (table/schema name) against {@link SAFE_IDENTIFIER}.
|
|
24
|
+
* Throws on anything containing quotes, dots, whitespace, or other unsafe chars.
|
|
25
|
+
*
|
|
26
|
+
* @param value the identifier to check
|
|
27
|
+
* @param what a label for the error message (e.g. `table name "roles"`)
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertSafeIdentifier(value: string, what: string): void;
|
|
30
|
+
//# sourceMappingURL=sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAS1C,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAEhE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;GAIG;AACH,qBAAa,YAAY;IAEX,OAAO,CAAC,QAAQ,CAAC,QAAQ;IADrC,OAAO,CAAC,KAAK,CAAK;gBACW,QAAQ,EAAE,OAAO;IAE9C,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,YAAY;IAIhD,oEAAoE;IACpE,IAAI,IAAI,MAAM;CAKf;AAUD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAMtE"}
|
package/dist/sql.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database types whose driver binds parameters with positional `$1, $2, …`
|
|
3
|
+
* placeholders instead of `?`. Postgres (and its aurora/cockroach kin) reject the
|
|
4
|
+
* `?` style that MySQL/SQLite accept, so the store must emit the right one.
|
|
5
|
+
*/
|
|
6
|
+
const POSTGRES_FAMILY = new Set(['postgres', 'aurora-postgres', 'cockroachdb', 'spanner']);
|
|
7
|
+
/** True when the DataSource's driver expects `$n` positional placeholders. */
|
|
8
|
+
export function isPostgresFamily(dataSource) {
|
|
9
|
+
return POSTGRES_FAMILY.has(dataSource.options.type);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Build the placeholder token for the parameter at 0-based `index`, dialect-correct
|
|
13
|
+
* for the given DataSource: `$1, $2, …` on Postgres-family drivers, `?` elsewhere.
|
|
14
|
+
*/
|
|
15
|
+
export function placeholder(dataSource, index) {
|
|
16
|
+
return isPostgresFamily(dataSource) ? `$${index + 1}` : '?';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A tiny helper that hands out dialect-correct, sequentially-numbered placeholders.
|
|
20
|
+
* Each call to {@link Placeholders.next} returns the next token (`?` or `$n`), so a
|
|
21
|
+
* single query can interleave them in parameter order regardless of dialect.
|
|
22
|
+
*/
|
|
23
|
+
export class Placeholders {
|
|
24
|
+
postgres;
|
|
25
|
+
index = 0;
|
|
26
|
+
constructor(postgres) {
|
|
27
|
+
this.postgres = postgres;
|
|
28
|
+
}
|
|
29
|
+
static for(dataSource) {
|
|
30
|
+
return new Placeholders(isPostgresFamily(dataSource));
|
|
31
|
+
}
|
|
32
|
+
/** The next placeholder token, advancing the positional counter. */
|
|
33
|
+
next() {
|
|
34
|
+
const token = this.postgres ? `$${this.index + 1}` : '?';
|
|
35
|
+
this.index += 1;
|
|
36
|
+
return token;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* SQL identifiers (table / schema names) are interpolated into query text, NOT
|
|
41
|
+
* passed as bound parameters — `driver.escape()` only wraps them in quotes, it does
|
|
42
|
+
* NOT neutralize an embedded quote. To keep BYO `tableNames`/`schema` safe, restrict
|
|
43
|
+
* them to a conservative allowlist and reject anything else loudly.
|
|
44
|
+
*/
|
|
45
|
+
const SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
46
|
+
/**
|
|
47
|
+
* Validate an identifier (table/schema name) against {@link SAFE_IDENTIFIER}.
|
|
48
|
+
* Throws on anything containing quotes, dots, whitespace, or other unsafe chars.
|
|
49
|
+
*
|
|
50
|
+
* @param value the identifier to check
|
|
51
|
+
* @param what a label for the error message (e.g. `table name "roles"`)
|
|
52
|
+
*/
|
|
53
|
+
export function assertSafeIdentifier(value, what) {
|
|
54
|
+
if (!SAFE_IDENTIFIER.test(value)) {
|
|
55
|
+
throw new Error(`Unsafe ${what}: ${JSON.stringify(value)}. Identifiers must match /^[A-Za-z_][A-Za-z0-9_]*$/ (letters, digits, underscore; not starting with a digit). This blocks SQL injection via configured names.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=sql.js.map
|
package/dist/sql.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.js","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAE3F,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAAC,UAAsB;IACrD,OAAO,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,UAAsB,EAAE,KAAa;IAC/D,OAAO,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9D,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,YAAY;IAEM;IADrB,KAAK,GAAG,CAAC,CAAC;IAClB,YAA6B,QAAiB;QAAjB,aAAQ,GAAR,QAAQ,CAAS;IAAG,CAAC;IAElD,MAAM,CAAC,GAAG,CAAC,UAAsB;QAC/B,OAAO,IAAI,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,oEAAoE;IACpE,IAAI;QACF,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACzD,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAChB,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAa,EAAE,IAAY;IAC9D,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,+JAA+J,CACxM,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { DataSource } from 'typeorm';
|
|
2
|
+
import type { AuthzStoreOptions, 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
|
+
* TypeORM-backed RBAC store. A plain POJO that receives the `DataSource` 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
|
+
* BYO table names + an optional Postgres schema flow from {@link AuthzStoreOptions};
|
|
17
|
+
* the store qualifies every table reference accordingly so it never assumes a name.
|
|
18
|
+
*/
|
|
19
|
+
export declare class TypeOrmAuthzStore {
|
|
20
|
+
private readonly dataSource;
|
|
21
|
+
private readonly opts;
|
|
22
|
+
private readonly names;
|
|
23
|
+
private readonly schema;
|
|
24
|
+
constructor(dataSource: DataSource, opts?: AuthzStoreOptions);
|
|
25
|
+
/** Create/upgrade the RBAC tables (delegates to {@link ensureAuthzSchema}). */
|
|
26
|
+
ensureSchema(): Promise<void>;
|
|
27
|
+
/** A fresh, dialect-correct positional-placeholder generator for one query. */
|
|
28
|
+
private params;
|
|
29
|
+
/** Schema-qualified, driver-escaped table reference. */
|
|
30
|
+
private table;
|
|
31
|
+
private col;
|
|
32
|
+
/** Dialect-correct `INSERT ... <conflict-ignore>` clause for a unique-key upsert. */
|
|
33
|
+
private insertIgnoreSuffix;
|
|
34
|
+
/** Dialect-correct INSERT verb (`INSERT` vs MySQL's `INSERT IGNORE`). */
|
|
35
|
+
private insertIgnoreVerb;
|
|
36
|
+
/**
|
|
37
|
+
* Create the role if absent; returns its id. Idempotent and race-tolerant: the
|
|
38
|
+
* INSERT is dialect-aware conflict-ignoring (`ON CONFLICT DO NOTHING` /
|
|
39
|
+
* `INSERT IGNORE`) on the unique `name`, and the id is re-read afterwards so two
|
|
40
|
+
* concurrent creators converge on the same row.
|
|
41
|
+
*/
|
|
42
|
+
createRole(name: string): Promise<string>;
|
|
43
|
+
/** Create the permission if absent; returns its id. Idempotent and race-tolerant. */
|
|
44
|
+
createPermission(name: string): Promise<string>;
|
|
45
|
+
private findRoleId;
|
|
46
|
+
private findPermissionId;
|
|
47
|
+
/** Grant a permission to a role (creating both by name if needed). Idempotent. */
|
|
48
|
+
givePermissionToRole(roleName: string, permissionName: string): Promise<void>;
|
|
49
|
+
/** Revoke a permission from a role. No-op if either is absent or not linked. */
|
|
50
|
+
revokePermissionFromRole(roleName: string, permissionName: string): Promise<void>;
|
|
51
|
+
/** Assign a role to a user (creating the role by name if needed). Idempotent. */
|
|
52
|
+
assignRole(user: UserRef, roleName: string): Promise<void>;
|
|
53
|
+
/** Remove a role from a user. No-op if the role or assignment is absent. */
|
|
54
|
+
removeRole(user: UserRef, roleName: string): Promise<void>;
|
|
55
|
+
/** The role names a user holds. */
|
|
56
|
+
getRolesForUser(user: UserRef): Promise<string[]>;
|
|
57
|
+
/** The flattened, distinct permission names a user has via their roles. */
|
|
58
|
+
getPermissionsForUser(user: UserRef): Promise<string[]>;
|
|
59
|
+
/** A user's roles + effective permissions in one shot. */
|
|
60
|
+
getUserAuthz(user: UserRef): Promise<UserAuthz>;
|
|
61
|
+
/** True when the user holds `permission` through any of their roles. */
|
|
62
|
+
userHasPermission(user: UserRef, permission: string): Promise<boolean>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=typeorm-authz.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeorm-authz.store.d.ts","sourceRoot":"","sources":["../src/typeorm-authz.store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAU7D;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IALvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0E;IAChG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;gBAGzB,UAAU,EAAE,UAAU,EACtB,IAAI,GAAE,iBAAsB;IAoB/C,+EAA+E;IAC/E,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,+EAA+E;IAC/E,OAAO,CAAC,MAAM;IAId,wDAAwD;IACxD,OAAO,CAAC,KAAK;IAMb,OAAO,CAAC,GAAG;IAMX,qFAAqF;IACrF,OAAO,CAAC,kBAAkB;IAS1B,yEAAyE;IACzE,OAAO,CAAC,gBAAgB;IAMxB;;;;;OAKG;IACG,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;YAWV,gBAAgB;IAa9B,kFAAkF;IAC5E,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnF,gFAAgF;IAC1E,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevF,iFAAiF;IAC3E,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYhE,4EAA4E;IACtE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAehE,mCAAmC;IAC7B,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAavD,2EAA2E;IACrE,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgB7D,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;CAkB7E"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { DEFAULT_TABLE_NAMES } from './entities.js';
|
|
3
|
+
import { ensureAuthzSchema } from './schema.js';
|
|
4
|
+
import { Placeholders, assertSafeIdentifier } from './sql.js';
|
|
5
|
+
/** Normalize a {@link UserRef} to `{ type, id }` with `id` stringified. */
|
|
6
|
+
function normalizeUserRef(ref) {
|
|
7
|
+
if (typeof ref === 'string' || typeof ref === 'number') {
|
|
8
|
+
return { type: 'user', id: String(ref) };
|
|
9
|
+
}
|
|
10
|
+
return { type: ref.type ?? 'user', id: String(ref.id) };
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* TypeORM-backed RBAC store. A plain POJO that receives the `DataSource` in its
|
|
14
|
+
* constructor — NOT `@Injectable`, no internal connection token (the app owns the
|
|
15
|
+
* connection and plugs it via DI; see the persistence contract).
|
|
16
|
+
*
|
|
17
|
+
* BYO table names + an optional Postgres schema flow from {@link AuthzStoreOptions};
|
|
18
|
+
* the store qualifies every table reference accordingly so it never assumes a name.
|
|
19
|
+
*/
|
|
20
|
+
export class TypeOrmAuthzStore {
|
|
21
|
+
dataSource;
|
|
22
|
+
opts;
|
|
23
|
+
names;
|
|
24
|
+
schema;
|
|
25
|
+
constructor(dataSource, opts = {}) {
|
|
26
|
+
this.dataSource = dataSource;
|
|
27
|
+
this.opts = opts;
|
|
28
|
+
this.names = {
|
|
29
|
+
roles: opts.tableNames?.roles ?? DEFAULT_TABLE_NAMES.roles,
|
|
30
|
+
permissions: opts.tableNames?.permissions ?? DEFAULT_TABLE_NAMES.permissions,
|
|
31
|
+
rolePermission: opts.tableNames?.rolePermission ?? DEFAULT_TABLE_NAMES.rolePermission,
|
|
32
|
+
userRole: opts.tableNames?.userRole ?? DEFAULT_TABLE_NAMES.userRole,
|
|
33
|
+
};
|
|
34
|
+
this.schema = opts.schema;
|
|
35
|
+
// P4: identifiers are interpolated into SQL — validate BYO names/schema up
|
|
36
|
+
// front so a hostile value (e.g. one with a `"`) can never reach a query.
|
|
37
|
+
for (const [key, name] of Object.entries(this.names)) {
|
|
38
|
+
assertSafeIdentifier(name, `table name (${key})`);
|
|
39
|
+
}
|
|
40
|
+
if (this.schema !== undefined) {
|
|
41
|
+
assertSafeIdentifier(this.schema, 'schema name');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Create/upgrade the RBAC tables (delegates to {@link ensureAuthzSchema}). */
|
|
45
|
+
ensureSchema() {
|
|
46
|
+
return ensureAuthzSchema(this.dataSource, this.opts);
|
|
47
|
+
}
|
|
48
|
+
/** A fresh, dialect-correct positional-placeholder generator for one query. */
|
|
49
|
+
params() {
|
|
50
|
+
return Placeholders.for(this.dataSource);
|
|
51
|
+
}
|
|
52
|
+
/** Schema-qualified, driver-escaped table reference. */
|
|
53
|
+
table(key) {
|
|
54
|
+
const quote = (id) => this.dataSource.driver.escape(id);
|
|
55
|
+
const name = quote(this.names[key]);
|
|
56
|
+
return this.schema ? `${quote(this.schema)}.${name}` : name;
|
|
57
|
+
}
|
|
58
|
+
col(id) {
|
|
59
|
+
return this.dataSource.driver.escape(id);
|
|
60
|
+
}
|
|
61
|
+
// --- roles & permissions (idempotent upserts by name) ---
|
|
62
|
+
/** Dialect-correct `INSERT ... <conflict-ignore>` clause for a unique-key upsert. */
|
|
63
|
+
insertIgnoreSuffix() {
|
|
64
|
+
// Postgres/SQLite speak `ON CONFLICT DO NOTHING`; MySQL/MariaDB use `INSERT IGNORE`
|
|
65
|
+
// (handled at the verb in `insertIgnoreVerb`). Returning a trailing clause keeps
|
|
66
|
+
// the call sites uniform.
|
|
67
|
+
const type = this.dataSource.options.type;
|
|
68
|
+
if (type === 'mysql' || type === 'mariadb' || type === 'aurora-mysql')
|
|
69
|
+
return '';
|
|
70
|
+
return ' ON CONFLICT DO NOTHING';
|
|
71
|
+
}
|
|
72
|
+
/** Dialect-correct INSERT verb (`INSERT` vs MySQL's `INSERT IGNORE`). */
|
|
73
|
+
insertIgnoreVerb() {
|
|
74
|
+
const type = this.dataSource.options.type;
|
|
75
|
+
if (type === 'mysql' || type === 'mariadb' || type === 'aurora-mysql')
|
|
76
|
+
return 'INSERT IGNORE';
|
|
77
|
+
return 'INSERT';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Create the role if absent; returns its id. Idempotent and race-tolerant: the
|
|
81
|
+
* INSERT is dialect-aware conflict-ignoring (`ON CONFLICT DO NOTHING` /
|
|
82
|
+
* `INSERT IGNORE`) on the unique `name`, and the id is re-read afterwards so two
|
|
83
|
+
* concurrent creators converge on the same row.
|
|
84
|
+
*/
|
|
85
|
+
async createRole(name) {
|
|
86
|
+
const existing = await this.findRoleId(name);
|
|
87
|
+
if (existing)
|
|
88
|
+
return existing;
|
|
89
|
+
const p = this.params();
|
|
90
|
+
await this.dataSource.query(`${this.insertIgnoreVerb()} INTO ${this.table('roles')} (${this.col('id')}, ${this.col('name')}, ${this.col('guard')}, ${this.col('createdAt')}) VALUES (${p.next()}, ${p.next()}, NULL, ${p.next()})${this.insertIgnoreSuffix()}`, [randomUUID(), name, new Date().toISOString()]);
|
|
91
|
+
// Re-read: handles a concurrent insert that won the race (ours was ignored).
|
|
92
|
+
const id = await this.findRoleId(name);
|
|
93
|
+
if (!id)
|
|
94
|
+
throw new Error(`Failed to create or resolve role "${name}".`);
|
|
95
|
+
return id;
|
|
96
|
+
}
|
|
97
|
+
/** Create the permission if absent; returns its id. Idempotent and race-tolerant. */
|
|
98
|
+
async createPermission(name) {
|
|
99
|
+
const existing = await this.findPermissionId(name);
|
|
100
|
+
if (existing)
|
|
101
|
+
return existing;
|
|
102
|
+
const p = this.params();
|
|
103
|
+
await this.dataSource.query(`${this.insertIgnoreVerb()} INTO ${this.table('permissions')} (${this.col('id')}, ${this.col('name')}, ${this.col('guard')}, ${this.col('createdAt')}) VALUES (${p.next()}, ${p.next()}, NULL, ${p.next()})${this.insertIgnoreSuffix()}`, [randomUUID(), name, new Date().toISOString()]);
|
|
104
|
+
const id = await this.findPermissionId(name);
|
|
105
|
+
if (!id)
|
|
106
|
+
throw new Error(`Failed to create or resolve permission "${name}".`);
|
|
107
|
+
return id;
|
|
108
|
+
}
|
|
109
|
+
async findRoleId(name) {
|
|
110
|
+
const p = this.params();
|
|
111
|
+
const rows = (await this.dataSource.query(`SELECT ${this.col('id')} AS id FROM ${this.table('roles')} WHERE ${this.col('name')} = ${p.next()}`, [name]));
|
|
112
|
+
return rows[0]?.id;
|
|
113
|
+
}
|
|
114
|
+
async findPermissionId(name) {
|
|
115
|
+
const p = this.params();
|
|
116
|
+
const rows = (await this.dataSource.query(`SELECT ${this.col('id')} AS id FROM ${this.table('permissions')} WHERE ${this.col('name')} = ${p.next()}`, [name]));
|
|
117
|
+
return rows[0]?.id;
|
|
118
|
+
}
|
|
119
|
+
// --- role ↔ permission ---
|
|
120
|
+
/** Grant a permission to a role (creating both by name if needed). Idempotent. */
|
|
121
|
+
async givePermissionToRole(roleName, permissionName) {
|
|
122
|
+
const roleId = await this.createRole(roleName);
|
|
123
|
+
const permissionId = await this.createPermission(permissionName);
|
|
124
|
+
const p = this.params();
|
|
125
|
+
await this.dataSource.query(`${this.insertIgnoreVerb()} INTO ${this.table('rolePermission')} (${this.col('roleId')}, ${this.col('permissionId')}) VALUES (${p.next()}, ${p.next()})${this.insertIgnoreSuffix()}`, [roleId, permissionId]);
|
|
126
|
+
}
|
|
127
|
+
/** Revoke a permission from a role. No-op if either is absent or not linked. */
|
|
128
|
+
async revokePermissionFromRole(roleName, permissionName) {
|
|
129
|
+
const roleId = await this.findRoleId(roleName);
|
|
130
|
+
const permissionId = await this.findPermissionId(permissionName);
|
|
131
|
+
if (!roleId || !permissionId)
|
|
132
|
+
return;
|
|
133
|
+
const p = this.params();
|
|
134
|
+
await this.dataSource.query(`DELETE FROM ${this.table('rolePermission')} WHERE ${this.col('roleId')} = ${p.next()} AND ${this.col('permissionId')} = ${p.next()}`, [roleId, permissionId]);
|
|
135
|
+
}
|
|
136
|
+
// --- user ↔ role ---
|
|
137
|
+
/** Assign a role to a user (creating the role by name if needed). Idempotent. */
|
|
138
|
+
async assignRole(user, roleName) {
|
|
139
|
+
const { type, id } = normalizeUserRef(user);
|
|
140
|
+
const roleId = await this.createRole(roleName);
|
|
141
|
+
const p = this.params();
|
|
142
|
+
await this.dataSource.query(`${this.insertIgnoreVerb()} INTO ${this.table('userRole')} (${this.col('userType')}, ${this.col('userId')}, ${this.col('roleId')}) VALUES (${p.next()}, ${p.next()}, ${p.next()})${this.insertIgnoreSuffix()}`, [type, id, roleId]);
|
|
143
|
+
}
|
|
144
|
+
/** Remove a role from a user. No-op if the role or assignment is absent. */
|
|
145
|
+
async removeRole(user, roleName) {
|
|
146
|
+
const { type, id } = normalizeUserRef(user);
|
|
147
|
+
const roleId = await this.findRoleId(roleName);
|
|
148
|
+
if (!roleId)
|
|
149
|
+
return;
|
|
150
|
+
const p = this.params();
|
|
151
|
+
await this.dataSource.query(`DELETE FROM ${this.table('userRole')} WHERE ${this.col('userType')} = ${p.next()} AND ${this.col('userId')} = ${p.next()} AND ${this.col('roleId')} = ${p.next()}`, [type, id, roleId]);
|
|
152
|
+
}
|
|
153
|
+
// --- queries ---
|
|
154
|
+
/** The role names a user holds. */
|
|
155
|
+
async getRolesForUser(user) {
|
|
156
|
+
const { type, id } = normalizeUserRef(user);
|
|
157
|
+
const p = this.params();
|
|
158
|
+
const rows = (await this.dataSource.query(`SELECT r.${this.col('name')} AS name
|
|
159
|
+
FROM ${this.table('userRole')} ur
|
|
160
|
+
JOIN ${this.table('roles')} r ON r.${this.col('id')} = ur.${this.col('roleId')}
|
|
161
|
+
WHERE ur.${this.col('userType')} = ${p.next()} AND ur.${this.col('userId')} = ${p.next()}`, [type, id]));
|
|
162
|
+
return rows.map((row) => row.name);
|
|
163
|
+
}
|
|
164
|
+
/** The flattened, distinct permission names a user has via their roles. */
|
|
165
|
+
async getPermissionsForUser(user) {
|
|
166
|
+
const { type, id } = normalizeUserRef(user);
|
|
167
|
+
const p = this.params();
|
|
168
|
+
const rows = (await this.dataSource.query(`SELECT DISTINCT p.${this.col('name')} AS name
|
|
169
|
+
FROM ${this.table('userRole')} ur
|
|
170
|
+
JOIN ${this.table('rolePermission')} rp ON rp.${this.col('roleId')} = ur.${this.col('roleId')}
|
|
171
|
+
JOIN ${this.table('permissions')} p ON p.${this.col('id')} = rp.${this.col('permissionId')}
|
|
172
|
+
WHERE ur.${this.col('userType')} = ${p.next()} AND ur.${this.col('userId')} = ${p.next()}`, [type, id]));
|
|
173
|
+
return rows.map((row) => row.name);
|
|
174
|
+
}
|
|
175
|
+
/** A user's roles + effective permissions in one shot. */
|
|
176
|
+
async getUserAuthz(user) {
|
|
177
|
+
const [roles, permissions] = await Promise.all([
|
|
178
|
+
this.getRolesForUser(user),
|
|
179
|
+
this.getPermissionsForUser(user),
|
|
180
|
+
]);
|
|
181
|
+
return { roles, permissions };
|
|
182
|
+
}
|
|
183
|
+
/** True when the user holds `permission` through any of their roles. */
|
|
184
|
+
async userHasPermission(user, permission) {
|
|
185
|
+
const { type, id } = normalizeUserRef(user);
|
|
186
|
+
const p = this.params();
|
|
187
|
+
const rows = (await this.dataSource.query(`SELECT 1 AS x
|
|
188
|
+
FROM ${this.table('userRole')} ur
|
|
189
|
+
JOIN ${this.table('rolePermission')} rp ON rp.${this.col('roleId')} = ur.${this.col('roleId')}
|
|
190
|
+
JOIN ${this.table('permissions')} p ON p.${this.col('id')} = rp.${this.col('permissionId')}
|
|
191
|
+
WHERE ur.${this.col('userType')} = ${p.next()} AND ur.${this.col('userId')} = ${p.next()} AND p.${this.col('name')} = ${p.next()}
|
|
192
|
+
LIMIT 1`, [type, id, permission]));
|
|
193
|
+
return rows.length > 0;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=typeorm-authz.store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeorm-authz.store.js","sourceRoot":"","sources":["../src/typeorm-authz.store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAG9D,2EAA2E;AAC3E,SAAS,gBAAgB,CAAC,GAAY;IACpC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACvD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;AAC1D,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAiB;IAKT;IACA;IALF,KAAK,CAA0E;IAC/E,MAAM,CAAqB;IAE5C,YACmB,UAAsB,EACtB,OAA0B,EAAE;QAD5B,eAAU,GAAV,UAAU,CAAY;QACtB,SAAI,GAAJ,IAAI,CAAwB;QAE7C,IAAI,CAAC,KAAK,GAAG;YACX,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,IAAI,mBAAmB,CAAC,KAAK;YAC1D,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,IAAI,mBAAmB,CAAC,WAAW;YAC5E,cAAc,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,IAAI,mBAAmB,CAAC,cAAc;YACrF,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,IAAI,mBAAmB,CAAC,QAAQ;SACpE,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE1B,2EAA2E;QAC3E,0EAA0E;QAC1E,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,YAAY;QACV,OAAO,iBAAiB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,+EAA+E;IACvE,MAAM;QACZ,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;IAED,wDAAwD;IAChD,KAAK,CAAC,GAA4B;QACxC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,CAAC;IAEO,GAAG,CAAC,EAAU;QACpB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,2DAA2D;IAE3D,qFAAqF;IAC7E,kBAAkB;QACxB,oFAAoF;QACpF,iFAAiF;QACjF,0BAA0B;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;QAC1C,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,cAAc;YAAE,OAAO,EAAE,CAAC;QACjF,OAAO,yBAAyB,CAAC;IACnC,CAAC;IAED,yEAAyE;IACjE,gBAAgB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;QAC1C,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,cAAc;YAAE,OAAO,eAAe,CAAC;QAC9F,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACzB,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CACpF,MAAM,CACP,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,EACrI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAC/C,CAAC;QACF,6EAA6E;QAC7E,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,IAAI,CAAC,CAAC;QACxE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,qFAAqF;IACrF,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACzB,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,GAAG,CACvE,IAAI,CACL,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAC1J,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAC/C,CAAC;QACF,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,IAAI,CAAC,CAAC;QAC9E,OAAO,EAAE,CAAC;IACZ,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,IAAY;QACnC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACvC,UAAU,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,GAAG,CAC1E,MAAM,CACP,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EACjB,CAAC,IAAI,CAAC,CACP,CAA0B,CAAC;QAC5B,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACzC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACvC,UAAU,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,UAAU,IAAI,CAAC,GAAG,CAChF,MAAM,CACP,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EACjB,CAAC,IAAI,CAAC,CACP,CAA0B,CAAC;QAC5B,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACrB,CAAC;IAED,4BAA4B;IAE5B,kFAAkF;IAClF,KAAK,CAAC,oBAAoB,CAAC,QAAgB,EAAE,cAAsB;QACjE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;QACjE,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACzB,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC,GAAG,CAC1E,QAAQ,CACT,KAAK,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAC/F,CAAC,MAAM,EAAE,YAAY,CAAC,CACvB,CAAC;IACJ,CAAC;IAED,gFAAgF;IAChF,KAAK,CAAC,wBAAwB,CAAC,QAAgB,EAAE,cAAsB;QACrE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY;YAAE,OAAO;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACzB,eAAe,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,IAAI,CAAC,GAAG,CAC3D,QAAQ,CACT,MAAM,CAAC,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAC/D,CAAC,MAAM,EAAE,YAAY,CAAC,CACvB,CAAC;IACJ,CAAC;IAED,sBAAsB;IAEtB,iFAAiF;IACjF,KAAK,CAAC,UAAU,CAAC,IAAa,EAAE,QAAgB;QAC9C,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACzB,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,CACpE,UAAU,CACX,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAC7H,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CACnB,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,KAAK,CAAC,UAAU,CAAC,IAAa,EAAE,QAAgB;QAC9C,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACzB,eAAe,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,GAAG,CAC/F,QAAQ,CACT,MAAM,CAAC,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EACzD,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CACnB,CAAC;IACJ,CAAC;IAED,kBAAkB;IAElB,mCAAmC;IACnC,KAAK,CAAC,eAAe,CAAC,IAAa;QACjC,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACvC,YAAY,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;cACpB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;cACtB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;kBACnE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,WAAW,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAC3F,CAAC,IAAI,EAAE,EAAE,CAAC,CACX,CAA4B,CAAC;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,qBAAqB,CAAC,IAAa;QACvC,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACvC,qBAAqB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;cAC7B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;cACtB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,GAAG,CACjF,QAAQ,CACT;cACM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC;kBAC/E,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,WAAW,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAC3F,CAAC,IAAI,EAAE,EAAE,CAAC,CACX,CAA4B,CAAC;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,0DAA0D;IAC1D,KAAK,CAAC,YAAY,CAAC,IAAa;QAC9B,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC7C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAC1B,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC;SACjC,CAAC,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAChC,CAAC;IAED,wEAAwE;IACxE,KAAK,CAAC,iBAAiB,CAAC,IAAa,EAAE,UAAkB;QACvD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CACvC;cACQ,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;cACtB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,GAAG,CACjF,QAAQ,CACT;cACM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC;kBAC/E,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,WAAW,IAAI,CAAC,GAAG,CAC9D,QAAQ,CACT,MAAM,CAAC,CAAC,IAAI,EAAE,UAAU,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;eAC/C,EACT,CAAC,IAAI,EAAE,EAAE,EAAE,UAAU,CAAC,CACvB,CAAc,CAAC;QAChB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** BYO table names. Any omitted name falls back to {@link DEFAULT_TABLE_NAMES}. */
|
|
2
|
+
export interface TableNames {
|
|
3
|
+
roles?: string;
|
|
4
|
+
permissions?: string;
|
|
5
|
+
rolePermission?: string;
|
|
6
|
+
userRole?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A reference to a user. Matches nestjs-context's `UserRef` shape (`{ type, id }`),
|
|
10
|
+
* but the store accepts either a full ref or a bare id (defaulting `type` to `'user'`).
|
|
11
|
+
*/
|
|
12
|
+
export interface UserRefInput {
|
|
13
|
+
type?: string;
|
|
14
|
+
id: string | number;
|
|
15
|
+
}
|
|
16
|
+
/** A user reference, or just its id (treated as `{ type: 'user', id }`). */
|
|
17
|
+
export type UserRef = UserRefInput | string | number;
|
|
18
|
+
export interface AuthzStoreOptions {
|
|
19
|
+
/** BYO table names; each defaults to the matching {@link DEFAULT_TABLE_NAMES} entry. */
|
|
20
|
+
tableNames?: TableNames;
|
|
21
|
+
/**
|
|
22
|
+
* Optional Postgres schema (NOT a connection — the connection comes from the app's
|
|
23
|
+
* DI per the persistence contract). Tables are created/queried as `"schema"."table"`.
|
|
24
|
+
*/
|
|
25
|
+
schema?: string;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;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,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dudousxd/nestjs-authz-typeorm",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "TypeORM 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/typeorm"
|
|
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
|
+
"typeorm": "^0.3.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@nestjs/common": "^11.0.0",
|
|
36
|
+
"@nestjs/core": "^11.0.0",
|
|
37
|
+
"@nestjs/testing": "^11.0.0",
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"reflect-metadata": "^0.2.2",
|
|
40
|
+
"rxjs": "^7.8.1",
|
|
41
|
+
"sqlite3": "^5.1.7",
|
|
42
|
+
"typeorm": "^0.3.20",
|
|
43
|
+
"typescript": "^5.4.0",
|
|
44
|
+
"vitest": "^3.0.0",
|
|
45
|
+
"@dudousxd/nestjs-authz": "^0.2.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=20"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"nestjs",
|
|
52
|
+
"authorization",
|
|
53
|
+
"authz",
|
|
54
|
+
"rbac",
|
|
55
|
+
"roles",
|
|
56
|
+
"permissions",
|
|
57
|
+
"typeorm"
|
|
58
|
+
],
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsc -p tsconfig.json",
|
|
61
|
+
"test": "vitest run --passWithNoTests",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
64
|
+
}
|
|
65
|
+
}
|