@stratal/framework 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.mts +202 -0
- package/dist/auth/index.d.mts.map +1 -0
- package/dist/auth/index.mjs +323 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/auth-context-BD2ApWg1.d.mts +38 -0
- package/dist/auth-context-BD2ApWg1.d.mts.map +1 -0
- package/dist/auth-context-CV3Ko1ew.mjs +55 -0
- package/dist/auth-context-CV3Ko1ew.mjs.map +1 -0
- package/dist/context/index.d.mts +20 -0
- package/dist/context/index.d.mts.map +1 -0
- package/dist/context/index.mjs +3 -0
- package/dist/database/index.d.mts +3 -0
- package/dist/database/index.mjs +374 -0
- package/dist/database/index.mjs.map +1 -0
- package/dist/decorate-RSane8dy.mjs +9 -0
- package/dist/decorateMetadata-CETItPez.mjs +6 -0
- package/dist/decorateParam-CcTvpNsw.mjs +8 -0
- package/dist/errors-C_KIIU1v.mjs +25 -0
- package/dist/errors-C_KIIU1v.mjs.map +1 -0
- package/dist/factory/index.d.mts +99 -0
- package/dist/factory/index.d.mts.map +1 -0
- package/dist/factory/index.mjs +138 -0
- package/dist/factory/index.mjs.map +1 -0
- package/dist/guards/{auth.guard.d.ts → index.d.mts} +7 -3
- package/dist/guards/index.d.mts.map +1 -0
- package/dist/guards/index.mjs +93 -0
- package/dist/guards/index.mjs.map +1 -0
- package/dist/index-Dlg8mNjq.d.mts +386 -0
- package/dist/index-Dlg8mNjq.d.mts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +1 -0
- package/dist/rbac/index.d.mts +206 -0
- package/dist/rbac/index.d.mts.map +1 -0
- package/dist/rbac/index.mjs +346 -0
- package/dist/rbac/index.mjs.map +1 -0
- package/dist/tokens-Di1ofovy.mjs +32 -0
- package/dist/tokens-Di1ofovy.mjs.map +1 -0
- package/dist/{database/types.d.ts → types-Gjk0d2qB.d.mts} +18 -15
- package/dist/types-Gjk0d2qB.d.mts.map +1 -0
- package/package.json +25 -24
- package/dist/auth/auth.module.d.ts +0 -37
- package/dist/auth/auth.module.d.ts.map +0 -1
- package/dist/auth/auth.module.js +0 -74
- package/dist/auth/auth.module.js.map +0 -1
- package/dist/auth/auth.tokens.d.ts +0 -5
- package/dist/auth/auth.tokens.d.ts.map +0 -1
- package/dist/auth/auth.tokens.js +0 -5
- package/dist/auth/auth.tokens.js.map +0 -1
- package/dist/auth/errors/auth-errors.d.ts +0 -74
- package/dist/auth/errors/auth-errors.d.ts.map +0 -1
- package/dist/auth/errors/auth-errors.js +0 -122
- package/dist/auth/errors/auth-errors.js.map +0 -1
- package/dist/auth/errors/index.d.ts +0 -5
- package/dist/auth/errors/index.d.ts.map +0 -1
- package/dist/auth/errors/index.js +0 -5
- package/dist/auth/errors/index.js.map +0 -1
- package/dist/auth/errors/invalid-token.error.d.ts +0 -5
- package/dist/auth/errors/invalid-token.error.d.ts.map +0 -1
- package/dist/auth/errors/invalid-token.error.js +0 -7
- package/dist/auth/errors/invalid-token.error.js.map +0 -1
- package/dist/auth/errors/token-required.error.d.ts +0 -5
- package/dist/auth/errors/token-required.error.d.ts.map +0 -1
- package/dist/auth/errors/token-required.error.js +0 -7
- package/dist/auth/errors/token-required.error.js.map +0 -1
- package/dist/auth/errors/verification-failed.error.d.ts +0 -5
- package/dist/auth/errors/verification-failed.error.d.ts.map +0 -1
- package/dist/auth/errors/verification-failed.error.js +0 -7
- package/dist/auth/errors/verification-failed.error.js.map +0 -1
- package/dist/auth/index.d.ts +0 -7
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js +0 -7
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/middleware/auth-context.middleware.d.ts +0 -12
- package/dist/auth/middleware/auth-context.middleware.d.ts.map +0 -1
- package/dist/auth/middleware/auth-context.middleware.js +0 -28
- package/dist/auth/middleware/auth-context.middleware.js.map +0 -1
- package/dist/auth/middleware/index.d.ts +0 -3
- package/dist/auth/middleware/index.d.ts.map +0 -1
- package/dist/auth/middleware/index.js +0 -3
- package/dist/auth/middleware/index.js.map +0 -1
- package/dist/auth/middleware/session-verification.middleware.d.ts +0 -18
- package/dist/auth/middleware/session-verification.middleware.d.ts.map +0 -1
- package/dist/auth/middleware/session-verification.middleware.js +0 -48
- package/dist/auth/middleware/session-verification.middleware.js.map +0 -1
- package/dist/auth/services/auth.service.d.ts +0 -32
- package/dist/auth/services/auth.service.d.ts.map +0 -1
- package/dist/auth/services/auth.service.js +0 -62
- package/dist/auth/services/auth.service.js.map +0 -1
- package/dist/auth/services/index.d.ts +0 -2
- package/dist/auth/services/index.d.ts.map +0 -1
- package/dist/auth/services/index.js +0 -2
- package/dist/auth/services/index.js.map +0 -1
- package/dist/auth/utils/auth-helpers.d.ts +0 -11
- package/dist/auth/utils/auth-helpers.d.ts.map +0 -1
- package/dist/auth/utils/auth-helpers.js +0 -31
- package/dist/auth/utils/auth-helpers.js.map +0 -1
- package/dist/auth/utils/better-auth-error-handler.d.ts +0 -11
- package/dist/auth/utils/better-auth-error-handler.d.ts.map +0 -1
- package/dist/auth/utils/better-auth-error-handler.js +0 -95
- package/dist/auth/utils/better-auth-error-handler.js.map +0 -1
- package/dist/auth/utils/index.d.ts +0 -3
- package/dist/auth/utils/index.d.ts.map +0 -1
- package/dist/auth/utils/index.js +0 -3
- package/dist/auth/utils/index.js.map +0 -1
- package/dist/context/auth-context.d.ts +0 -35
- package/dist/context/auth-context.d.ts.map +0 -1
- package/dist/context/auth-context.js +0 -65
- package/dist/context/auth-context.js.map +0 -1
- package/dist/context/errors/context-not-initialized.error.d.ts +0 -5
- package/dist/context/errors/context-not-initialized.error.d.ts.map +0 -1
- package/dist/context/errors/context-not-initialized.error.js +0 -7
- package/dist/context/errors/context-not-initialized.error.js.map +0 -1
- package/dist/context/errors/index.d.ts +0 -4
- package/dist/context/errors/index.d.ts.map +0 -1
- package/dist/context/errors/index.js +0 -4
- package/dist/context/errors/index.js.map +0 -1
- package/dist/context/errors/user-not-authenticated.error.d.ts +0 -5
- package/dist/context/errors/user-not-authenticated.error.d.ts.map +0 -1
- package/dist/context/errors/user-not-authenticated.error.js +0 -7
- package/dist/context/errors/user-not-authenticated.error.js.map +0 -1
- package/dist/context/errors/user-not-authorized.error.d.ts +0 -5
- package/dist/context/errors/user-not-authorized.error.d.ts.map +0 -1
- package/dist/context/errors/user-not-authorized.error.js +0 -7
- package/dist/context/errors/user-not-authorized.error.js.map +0 -1
- package/dist/context/index.d.ts +0 -3
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/index.js +0 -3
- package/dist/context/index.js.map +0 -1
- package/dist/database/custom-pg-types.d.ts +0 -21
- package/dist/database/custom-pg-types.d.ts.map +0 -1
- package/dist/database/custom-pg-types.js +0 -41
- package/dist/database/custom-pg-types.js.map +0 -1
- package/dist/database/database.helpers.d.ts +0 -15
- package/dist/database/database.helpers.d.ts.map +0 -1
- package/dist/database/database.helpers.js +0 -47
- package/dist/database/database.helpers.js.map +0 -1
- package/dist/database/database.module.d.ts +0 -22
- package/dist/database/database.module.d.ts.map +0 -1
- package/dist/database/database.module.js +0 -54
- package/dist/database/database.module.js.map +0 -1
- package/dist/database/database.service.d.ts +0 -18
- package/dist/database/database.service.d.ts.map +0 -1
- package/dist/database/database.service.js +0 -2
- package/dist/database/database.service.js.map +0 -1
- package/dist/database/database.tokens.d.ts +0 -7
- package/dist/database/database.tokens.d.ts.map +0 -1
- package/dist/database/database.tokens.js +0 -8
- package/dist/database/database.tokens.js.map +0 -1
- package/dist/database/decorators/inject-db.decorator.d.ts +0 -3
- package/dist/database/decorators/inject-db.decorator.d.ts.map +0 -1
- package/dist/database/decorators/inject-db.decorator.js +0 -6
- package/dist/database/decorators/inject-db.decorator.js.map +0 -1
- package/dist/database/errors/database-config.error.d.ts +0 -5
- package/dist/database/errors/database-config.error.d.ts.map +0 -1
- package/dist/database/errors/database-config.error.js +0 -8
- package/dist/database/errors/database-config.error.js.map +0 -1
- package/dist/database/errors/database-error.d.ts +0 -14
- package/dist/database/errors/database-error.d.ts.map +0 -1
- package/dist/database/errors/database-error.js +0 -20
- package/dist/database/errors/database-error.js.map +0 -1
- package/dist/database/errors/foreign-key-constraint.error.d.ts +0 -14
- package/dist/database/errors/foreign-key-constraint.error.d.ts.map +0 -1
- package/dist/database/errors/foreign-key-constraint.error.js +0 -19
- package/dist/database/errors/foreign-key-constraint.error.js.map +0 -1
- package/dist/database/errors/from-zenstack-error.d.ts +0 -22
- package/dist/database/errors/from-zenstack-error.d.ts.map +0 -1
- package/dist/database/errors/from-zenstack-error.js +0 -114
- package/dist/database/errors/from-zenstack-error.js.map +0 -1
- package/dist/database/errors/index.d.ts +0 -8
- package/dist/database/errors/index.d.ts.map +0 -1
- package/dist/database/errors/index.js +0 -8
- package/dist/database/errors/index.js.map +0 -1
- package/dist/database/errors/invalid-error-code-range.error.d.ts +0 -12
- package/dist/database/errors/invalid-error-code-range.error.d.ts.map +0 -1
- package/dist/database/errors/invalid-error-code-range.error.js +0 -14
- package/dist/database/errors/invalid-error-code-range.error.js.map +0 -1
- package/dist/database/errors/record-not-found.error.d.ts +0 -15
- package/dist/database/errors/record-not-found.error.d.ts.map +0 -1
- package/dist/database/errors/record-not-found.error.js +0 -20
- package/dist/database/errors/record-not-found.error.js.map +0 -1
- package/dist/database/errors/unique-constraint.error.d.ts +0 -15
- package/dist/database/errors/unique-constraint.error.d.ts.map +0 -1
- package/dist/database/errors/unique-constraint.error.js +0 -20
- package/dist/database/errors/unique-constraint.error.js.map +0 -1
- package/dist/database/event-types.d.ts +0 -137
- package/dist/database/event-types.d.ts.map +0 -1
- package/dist/database/event-types.js +0 -13
- package/dist/database/event-types.js.map +0 -1
- package/dist/database/i18n/en.d.ts +0 -15
- package/dist/database/i18n/en.d.ts.map +0 -1
- package/dist/database/i18n/en.js +0 -10
- package/dist/database/i18n/en.js.map +0 -1
- package/dist/database/i18n/index.d.ts +0 -2
- package/dist/database/i18n/index.d.ts.map +0 -1
- package/dist/database/i18n/index.js +0 -2
- package/dist/database/i18n/index.js.map +0 -1
- package/dist/database/index.d.ts +0 -11
- package/dist/database/index.d.ts.map +0 -1
- package/dist/database/index.js +0 -11
- package/dist/database/index.js.map +0 -1
- package/dist/database/plugins/error-handler.plugin.d.ts +0 -21
- package/dist/database/plugins/error-handler.plugin.d.ts.map +0 -1
- package/dist/database/plugins/error-handler.plugin.js +0 -24
- package/dist/database/plugins/error-handler.plugin.js.map +0 -1
- package/dist/database/plugins/event-emitter.plugin.d.ts +0 -37
- package/dist/database/plugins/event-emitter.plugin.d.ts.map +0 -1
- package/dist/database/plugins/event-emitter.plugin.js +0 -43
- package/dist/database/plugins/event-emitter.plugin.js.map +0 -1
- package/dist/database/plugins/index.d.ts +0 -4
- package/dist/database/plugins/index.d.ts.map +0 -1
- package/dist/database/plugins/index.js +0 -4
- package/dist/database/plugins/index.js.map +0 -1
- package/dist/database/plugins/schema-switcher.plugin.d.ts +0 -32
- package/dist/database/plugins/schema-switcher.plugin.d.ts.map +0 -1
- package/dist/database/plugins/schema-switcher.plugin.js +0 -27
- package/dist/database/plugins/schema-switcher.plugin.js.map +0 -1
- package/dist/database/types.d.ts.map +0 -1
- package/dist/database/types.js +0 -2
- package/dist/database/types.js.map +0 -1
- package/dist/factory/factory.d.ts +0 -56
- package/dist/factory/factory.d.ts.map +0 -1
- package/dist/factory/factory.js +0 -86
- package/dist/factory/factory.js.map +0 -1
- package/dist/factory/index.d.ts +0 -3
- package/dist/factory/index.d.ts.map +0 -1
- package/dist/factory/index.js +0 -3
- package/dist/factory/index.js.map +0 -1
- package/dist/factory/sequence.d.ts +0 -38
- package/dist/factory/sequence.d.ts.map +0 -1
- package/dist/factory/sequence.js +0 -54
- package/dist/factory/sequence.js.map +0 -1
- package/dist/guards/auth.guard.d.ts.map +0 -1
- package/dist/guards/auth.guard.js +0 -99
- package/dist/guards/auth.guard.js.map +0 -1
- package/dist/guards/index.d.ts +0 -3
- package/dist/guards/index.d.ts.map +0 -1
- package/dist/guards/index.js +0 -5
- package/dist/guards/index.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/rbac/adapters/custom-zenstack-adapter.d.ts +0 -61
- package/dist/rbac/adapters/custom-zenstack-adapter.d.ts.map +0 -1
- package/dist/rbac/adapters/custom-zenstack-adapter.js +0 -159
- package/dist/rbac/adapters/custom-zenstack-adapter.js.map +0 -1
- package/dist/rbac/adapters/index.d.ts +0 -2
- package/dist/rbac/adapters/index.d.ts.map +0 -1
- package/dist/rbac/adapters/index.js +0 -2
- package/dist/rbac/adapters/index.js.map +0 -1
- package/dist/rbac/constants.d.ts +0 -8
- package/dist/rbac/constants.d.ts.map +0 -1
- package/dist/rbac/constants.js +0 -8
- package/dist/rbac/constants.js.map +0 -1
- package/dist/rbac/errors/index.d.ts +0 -2
- package/dist/rbac/errors/index.d.ts.map +0 -1
- package/dist/rbac/errors/index.js +0 -2
- package/dist/rbac/errors/index.js.map +0 -1
- package/dist/rbac/errors/insufficient-permissions.error.d.ts +0 -14
- package/dist/rbac/errors/insufficient-permissions.error.d.ts.map +0 -1
- package/dist/rbac/errors/insufficient-permissions.error.js +0 -19
- package/dist/rbac/errors/insufficient-permissions.error.js.map +0 -1
- package/dist/rbac/index.d.ts +0 -9
- package/dist/rbac/index.d.ts.map +0 -1
- package/dist/rbac/index.js +0 -8
- package/dist/rbac/index.js.map +0 -1
- package/dist/rbac/rbac.module.d.ts +0 -26
- package/dist/rbac/rbac.module.d.ts.map +0 -1
- package/dist/rbac/rbac.module.js +0 -62
- package/dist/rbac/rbac.module.js.map +0 -1
- package/dist/rbac/services/casbin-enforcer.service.d.ts +0 -37
- package/dist/rbac/services/casbin-enforcer.service.d.ts.map +0 -1
- package/dist/rbac/services/casbin-enforcer.service.js +0 -86
- package/dist/rbac/services/casbin-enforcer.service.js.map +0 -1
- package/dist/rbac/services/casbin.service.d.ts +0 -37
- package/dist/rbac/services/casbin.service.d.ts.map +0 -1
- package/dist/rbac/services/casbin.service.js +0 -174
- package/dist/rbac/services/casbin.service.js.map +0 -1
- package/dist/rbac/services/index.d.ts +0 -3
- package/dist/rbac/services/index.d.ts.map +0 -1
- package/dist/rbac/services/index.js +0 -3
- package/dist/rbac/services/index.js.map +0 -1
- package/dist/rbac/tokens.d.ts +0 -10
- package/dist/rbac/tokens.d.ts.map +0 -1
- package/dist/rbac/tokens.js +0 -10
- package/dist/rbac/tokens.js.map +0 -1
- package/dist/rbac/types.d.ts +0 -12
- package/dist/rbac/types.d.ts.map +0 -1
- package/dist/rbac/types.js +0 -2
- package/dist/rbac/types.js.map +0 -1
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { t as __decorate } from "../decorate-RSane8dy.mjs";
|
|
2
|
+
import { t as __decorateMetadata } from "../decorateMetadata-CETItPez.mjs";
|
|
3
|
+
import { t as __decorateParam } from "../decorateParam-CcTvpNsw.mjs";
|
|
4
|
+
import { n as InsufficientPermissionsError, t as RBAC_TOKENS } from "../tokens-Di1ofovy.mjs";
|
|
5
|
+
import { Module } from "stratal/module";
|
|
6
|
+
import { DI_TOKENS, Transient } from "stratal/di";
|
|
7
|
+
import { inject } from "tsyringe";
|
|
8
|
+
import { Helper, newCachedEnforcer, newModelFromString } from "casbin";
|
|
9
|
+
//#region src/rbac/constants.ts
|
|
10
|
+
/**
|
|
11
|
+
* RBAC Constants
|
|
12
|
+
*/
|
|
13
|
+
const RBAC_CONTEXT_KEYS = { AUTH_SCOPES: Symbol("rbac:authScopes") };
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/rbac/adapters/custom-zenstack-adapter.ts
|
|
16
|
+
/**
|
|
17
|
+
* Custom ZenStack adapter for Casbin that works with Cloudflare Workers.
|
|
18
|
+
*
|
|
19
|
+
* Based on the original casbin-prisma-adapter but modified to:
|
|
20
|
+
* - Work with ZenStack v3 ORM clients
|
|
21
|
+
* - Avoid bundling errors in Cloudflare Workers
|
|
22
|
+
* - Accept pre-connected ZenStack clients (request-scoped)
|
|
23
|
+
*/
|
|
24
|
+
var CustomZenStackAdapter = class CustomZenStackAdapter {
|
|
25
|
+
#db;
|
|
26
|
+
filtered = false;
|
|
27
|
+
isFiltered() {
|
|
28
|
+
return this.filtered;
|
|
29
|
+
}
|
|
30
|
+
enableFiltered(enabled) {
|
|
31
|
+
this.filtered = enabled;
|
|
32
|
+
}
|
|
33
|
+
constructor(db) {
|
|
34
|
+
this.#db = db;
|
|
35
|
+
}
|
|
36
|
+
async loadPolicy(model) {
|
|
37
|
+
const lines = await this.#db.casbinRule.findMany();
|
|
38
|
+
for (const line of lines) this.#loadPolicyLine(line, model);
|
|
39
|
+
}
|
|
40
|
+
async loadFilteredPolicy(model, filter) {
|
|
41
|
+
const whereFilter = Object.keys(filter).map((ptype) => {
|
|
42
|
+
return filter[ptype].map((policyPattern) => {
|
|
43
|
+
return {
|
|
44
|
+
ptype,
|
|
45
|
+
...policyPattern[0] && { v0: policyPattern[0] },
|
|
46
|
+
...policyPattern[1] && { v1: policyPattern[1] },
|
|
47
|
+
...policyPattern[2] && { v2: policyPattern[2] },
|
|
48
|
+
...policyPattern[3] && { v3: policyPattern[3] },
|
|
49
|
+
...policyPattern[4] && { v4: policyPattern[4] },
|
|
50
|
+
...policyPattern[5] && { v5: policyPattern[5] }
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}).flat();
|
|
54
|
+
(await this.#db.casbinRule.findMany({ where: { OR: whereFilter } })).forEach((line) => this.#loadPolicyLine(line, model));
|
|
55
|
+
this.enableFiltered(true);
|
|
56
|
+
}
|
|
57
|
+
async savePolicy(model) {
|
|
58
|
+
await this.#db.$executeRawUnsafe("DELETE FROM casbin_rule");
|
|
59
|
+
const lines = [];
|
|
60
|
+
const savePolicyType = (ptype) => {
|
|
61
|
+
const astMap = model.model.get(ptype);
|
|
62
|
+
if (astMap) for (const [ptype, ast] of astMap) for (const rule of ast.policy) {
|
|
63
|
+
const line = this.#savePolicyLine(ptype, rule);
|
|
64
|
+
lines.push(line);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
savePolicyType("p");
|
|
68
|
+
savePolicyType("g");
|
|
69
|
+
await this.#db.casbinRule.createMany({ data: lines });
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
async addPolicy(_sec, ptype, rule) {
|
|
73
|
+
const line = this.#savePolicyLine(ptype, rule);
|
|
74
|
+
await this.#db.casbinRule.create({ data: line });
|
|
75
|
+
}
|
|
76
|
+
async addPolicies(_sec, ptype, rules) {
|
|
77
|
+
const processes = [];
|
|
78
|
+
for (const rule of rules) {
|
|
79
|
+
const line = this.#savePolicyLine(ptype, rule);
|
|
80
|
+
const p = this.#db.casbinRule.create({ data: line });
|
|
81
|
+
processes.push(p);
|
|
82
|
+
}
|
|
83
|
+
await Promise.all(processes);
|
|
84
|
+
}
|
|
85
|
+
async removePolicy(_sec, ptype, rule) {
|
|
86
|
+
const line = this.#savePolicyLine(ptype, rule);
|
|
87
|
+
await this.#db.casbinRule.deleteMany({ where: line });
|
|
88
|
+
}
|
|
89
|
+
async removePolicies(_sec, ptype, rules) {
|
|
90
|
+
const processes = [];
|
|
91
|
+
for (const rule of rules) {
|
|
92
|
+
const line = this.#savePolicyLine(ptype, rule);
|
|
93
|
+
const p = this.#db.casbinRule.deleteMany({ where: line });
|
|
94
|
+
processes.push(p);
|
|
95
|
+
}
|
|
96
|
+
await Promise.all(processes);
|
|
97
|
+
}
|
|
98
|
+
async removeFilteredPolicy(_sec, ptype, fieldIndex, ...fieldValues) {
|
|
99
|
+
const line = { ptype };
|
|
100
|
+
const idx = fieldIndex + fieldValues.length;
|
|
101
|
+
if (fieldIndex <= 0 && 0 < idx) line.v0 = fieldValues[0 - fieldIndex];
|
|
102
|
+
if (fieldIndex <= 1 && 1 < idx) line.v1 = fieldValues[1 - fieldIndex];
|
|
103
|
+
if (fieldIndex <= 2 && 2 < idx) line.v2 = fieldValues[2 - fieldIndex];
|
|
104
|
+
if (fieldIndex <= 3 && 3 < idx) line.v3 = fieldValues[3 - fieldIndex];
|
|
105
|
+
if (fieldIndex <= 4 && 4 < idx) line.v4 = fieldValues[4 - fieldIndex];
|
|
106
|
+
if (fieldIndex <= 5 && 5 < idx) line.v5 = fieldValues[5 - fieldIndex];
|
|
107
|
+
await this.#db.casbinRule.deleteMany({ where: line });
|
|
108
|
+
}
|
|
109
|
+
async close() {}
|
|
110
|
+
static newAdapter(db) {
|
|
111
|
+
return new CustomZenStackAdapter(db);
|
|
112
|
+
}
|
|
113
|
+
#loadPolicyLine = (line, model) => {
|
|
114
|
+
const result = line.ptype + ", " + [
|
|
115
|
+
line.v0,
|
|
116
|
+
line.v1,
|
|
117
|
+
line.v2,
|
|
118
|
+
line.v3,
|
|
119
|
+
line.v4,
|
|
120
|
+
line.v5
|
|
121
|
+
].filter((n) => n).join(", ");
|
|
122
|
+
Helper.loadPolicyLine(result, model);
|
|
123
|
+
};
|
|
124
|
+
#savePolicyLine = (ptype, rule) => {
|
|
125
|
+
const line = { ptype };
|
|
126
|
+
if (rule.length > 0) line.v0 = rule[0];
|
|
127
|
+
if (rule.length > 1) line.v1 = rule[1];
|
|
128
|
+
if (rule.length > 2) line.v2 = rule[2];
|
|
129
|
+
if (rule.length > 3) line.v3 = rule[3];
|
|
130
|
+
if (rule.length > 4) line.v4 = rule[4];
|
|
131
|
+
if (rule.length > 5) line.v5 = rule[5];
|
|
132
|
+
return line;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/rbac/services/casbin-enforcer.service.ts
|
|
137
|
+
let CasbinEnforcerService = class CasbinEnforcerService {
|
|
138
|
+
enforcer = null;
|
|
139
|
+
constructor(db, options) {
|
|
140
|
+
this.db = db;
|
|
141
|
+
this.options = options;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get or create the enforcer instance
|
|
145
|
+
*/
|
|
146
|
+
async getEnforcer() {
|
|
147
|
+
this.enforcer ??= await this.createEnforcer();
|
|
148
|
+
return this.enforcer;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Create a new enforcer instance.
|
|
152
|
+
* Can be overridden by subclasses to customize enforcer creation.
|
|
153
|
+
*/
|
|
154
|
+
async createEnforcer() {
|
|
155
|
+
const enforcer = await newCachedEnforcer(newModelFromString(this.options.model), CustomZenStackAdapter.newAdapter(this.db));
|
|
156
|
+
await enforcer.loadPolicy();
|
|
157
|
+
return enforcer;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Seed default policies into database
|
|
161
|
+
*/
|
|
162
|
+
async seedPolicies() {
|
|
163
|
+
const enforcer = await this.getEnforcer();
|
|
164
|
+
const policies = this.options.defaultPolicies ?? [];
|
|
165
|
+
for (const [role, resource, action] of policies) await enforcer.addPolicy(role, resource, action);
|
|
166
|
+
await enforcer.savePolicy();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Clear cached enforcer instance
|
|
170
|
+
*/
|
|
171
|
+
clearCache() {
|
|
172
|
+
this.enforcer = null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Seed role hierarchy into database
|
|
176
|
+
*/
|
|
177
|
+
async seedRoleHierarchy() {
|
|
178
|
+
const enforcer = await this.getEnforcer();
|
|
179
|
+
const hierarchy = this.options.roleHierarchy ?? [];
|
|
180
|
+
for (const [childRole, parentRole] of hierarchy) await enforcer.addGroupingPolicy(childRole, parentRole);
|
|
181
|
+
await enforcer.savePolicy();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
CasbinEnforcerService = __decorate([
|
|
185
|
+
Transient(),
|
|
186
|
+
__decorateParam(0, inject(DI_TOKENS.Database)),
|
|
187
|
+
__decorateParam(1, inject(RBAC_TOKENS.Options)),
|
|
188
|
+
__decorateMetadata("design:paramtypes", [Object, Object])
|
|
189
|
+
], CasbinEnforcerService);
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/rbac/services/casbin.service.ts
|
|
192
|
+
var _ref;
|
|
193
|
+
let CasbinService = class CasbinService {
|
|
194
|
+
constructor(context, enforcerService) {
|
|
195
|
+
this.context = context;
|
|
196
|
+
this.enforcerService = enforcerService;
|
|
197
|
+
}
|
|
198
|
+
async getEnforcer() {
|
|
199
|
+
return this.enforcerService.getEnforcer();
|
|
200
|
+
}
|
|
201
|
+
async addRoleForUser(userId, role) {
|
|
202
|
+
const enforcer = await this.getEnforcer();
|
|
203
|
+
const added = await enforcer.addRoleForUser(userId, role);
|
|
204
|
+
if (added) await enforcer.savePolicy();
|
|
205
|
+
return added;
|
|
206
|
+
}
|
|
207
|
+
async deleteRoleForUser(userId, role) {
|
|
208
|
+
const enforcer = await this.getEnforcer();
|
|
209
|
+
const deleted = await enforcer.deleteRoleForUser(userId, role);
|
|
210
|
+
if (deleted) await enforcer.savePolicy();
|
|
211
|
+
return deleted;
|
|
212
|
+
}
|
|
213
|
+
async deleteRolesForUser(userId) {
|
|
214
|
+
const enforcer = await this.getEnforcer();
|
|
215
|
+
const deleted = await enforcer.deleteRolesForUser(userId);
|
|
216
|
+
if (deleted) await enforcer.savePolicy();
|
|
217
|
+
return deleted;
|
|
218
|
+
}
|
|
219
|
+
async getRolesForUser(userId) {
|
|
220
|
+
return (await this.getEnforcer()).getRolesForUser(userId);
|
|
221
|
+
}
|
|
222
|
+
async getImplicitRolesForUser(userId) {
|
|
223
|
+
return (await this.getEnforcer()).getImplicitRolesForUser(userId);
|
|
224
|
+
}
|
|
225
|
+
async getUsersForRole(role) {
|
|
226
|
+
return (await this.getEnforcer()).getUsersForRole(role);
|
|
227
|
+
}
|
|
228
|
+
async getImplicitUsersForRole(role) {
|
|
229
|
+
return (await this.getEnforcer()).getImplicitUsersForRole(role);
|
|
230
|
+
}
|
|
231
|
+
async hasRoleForUser(userId, role) {
|
|
232
|
+
return (await this.getEnforcer()).hasRoleForUser(userId, role);
|
|
233
|
+
}
|
|
234
|
+
async addRoleInheritance(childRole, parentRole) {
|
|
235
|
+
const enforcer = await this.getEnforcer();
|
|
236
|
+
const added = await enforcer.addGroupingPolicy(childRole, parentRole);
|
|
237
|
+
if (added) await enforcer.savePolicy();
|
|
238
|
+
return added;
|
|
239
|
+
}
|
|
240
|
+
async deleteRoleInheritance(childRole, parentRole) {
|
|
241
|
+
const enforcer = await this.getEnforcer();
|
|
242
|
+
const deleted = await enforcer.removeGroupingPolicy(childRole, parentRole);
|
|
243
|
+
if (deleted) await enforcer.savePolicy();
|
|
244
|
+
return deleted;
|
|
245
|
+
}
|
|
246
|
+
async deleteUser(userId) {
|
|
247
|
+
const enforcer = await this.getEnforcer();
|
|
248
|
+
const deleted = await enforcer.deleteUser(userId);
|
|
249
|
+
if (deleted) await enforcer.savePolicy();
|
|
250
|
+
return deleted;
|
|
251
|
+
}
|
|
252
|
+
async deleteRole(role) {
|
|
253
|
+
const enforcer = await this.getEnforcer();
|
|
254
|
+
const deleted = await enforcer.deleteRole(role);
|
|
255
|
+
if (deleted) await enforcer.savePolicy();
|
|
256
|
+
return deleted;
|
|
257
|
+
}
|
|
258
|
+
async getCurrentUserRoles() {
|
|
259
|
+
const userId = this.context.getUserId();
|
|
260
|
+
if (!userId) return [];
|
|
261
|
+
return this.getImplicitRolesForUser(userId);
|
|
262
|
+
}
|
|
263
|
+
async currentUserHasRole(role) {
|
|
264
|
+
return (await this.getCurrentUserRoles()).includes(role);
|
|
265
|
+
}
|
|
266
|
+
async setRolesForUser(userId, roles) {
|
|
267
|
+
const enforcer = await this.getEnforcer();
|
|
268
|
+
await enforcer.deleteRolesForUser(userId);
|
|
269
|
+
for (const role of roles) await enforcer.addRoleForUser(userId, role);
|
|
270
|
+
await enforcer.savePolicy();
|
|
271
|
+
}
|
|
272
|
+
async hasPermission(userId, scope, action) {
|
|
273
|
+
return (await this.getEnforcer()).enforce(userId, scope, action);
|
|
274
|
+
}
|
|
275
|
+
async currentUserHasPermission(scope, action) {
|
|
276
|
+
const userId = this.context.getUserId();
|
|
277
|
+
if (!userId) return false;
|
|
278
|
+
return this.hasPermission(userId, scope, action);
|
|
279
|
+
}
|
|
280
|
+
async hasAnyPermission(userId, scopes, action) {
|
|
281
|
+
const enforcer = await this.getEnforcer();
|
|
282
|
+
const requests = scopes.map((scope) => [
|
|
283
|
+
userId,
|
|
284
|
+
scope,
|
|
285
|
+
action
|
|
286
|
+
]);
|
|
287
|
+
return (await enforcer.batchEnforce(requests)).some((allowed) => allowed);
|
|
288
|
+
}
|
|
289
|
+
async currentUserHasAnyPermission(scopes, action) {
|
|
290
|
+
const userId = this.context.getUserId();
|
|
291
|
+
if (!userId) return false;
|
|
292
|
+
return this.hasAnyPermission(userId, scopes, action);
|
|
293
|
+
}
|
|
294
|
+
async getPermissionsForUserAsCasbinJs(userId) {
|
|
295
|
+
const permissions = await (await this.getEnforcer()).getImplicitPermissionsForUser(userId);
|
|
296
|
+
const result = {};
|
|
297
|
+
for (const [_role, resource, action] of permissions) {
|
|
298
|
+
result[action] ??= [];
|
|
299
|
+
if (!result[action].includes(resource)) result[action].push(resource);
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
async getCurrentUserPermissionsAsCasbinJs() {
|
|
304
|
+
const userId = this.context.getUserId();
|
|
305
|
+
if (!userId) return {};
|
|
306
|
+
return this.getPermissionsForUserAsCasbinJs(userId);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
CasbinService = __decorate([
|
|
310
|
+
Transient(RBAC_TOKENS.CasbinService),
|
|
311
|
+
__decorateParam(0, inject(DI_TOKENS.AuthContext)),
|
|
312
|
+
__decorateParam(1, inject(CasbinEnforcerService)),
|
|
313
|
+
__decorateMetadata("design:paramtypes", [Object, typeof (_ref = typeof CasbinEnforcerService !== "undefined" && CasbinEnforcerService) === "function" ? _ref : Object])
|
|
314
|
+
], CasbinService);
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/rbac/rbac.module.ts
|
|
317
|
+
var _RbacModule;
|
|
318
|
+
let RbacModule = _RbacModule = class RbacModule {
|
|
319
|
+
static forRoot(options) {
|
|
320
|
+
return {
|
|
321
|
+
module: _RbacModule,
|
|
322
|
+
providers: [{
|
|
323
|
+
provide: RBAC_TOKENS.Options,
|
|
324
|
+
useValue: options
|
|
325
|
+
}]
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
static forRootAsync(options) {
|
|
329
|
+
return {
|
|
330
|
+
module: _RbacModule,
|
|
331
|
+
providers: [{
|
|
332
|
+
provide: RBAC_TOKENS.Options,
|
|
333
|
+
useFactory: options.useFactory,
|
|
334
|
+
inject: options.inject
|
|
335
|
+
}]
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
RbacModule = _RbacModule = __decorate([Module({ providers: [CasbinEnforcerService, {
|
|
340
|
+
provide: RBAC_TOKENS.CasbinService,
|
|
341
|
+
useClass: CasbinService
|
|
342
|
+
}] })], RbacModule);
|
|
343
|
+
//#endregion
|
|
344
|
+
export { CasbinEnforcerService, CasbinService, CustomZenStackAdapter, InsufficientPermissionsError, RBAC_CONTEXT_KEYS, RBAC_TOKENS, RbacModule };
|
|
345
|
+
|
|
346
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["#db","#loadPolicyLine","#savePolicyLine"],"sources":["../../src/rbac/constants.ts","../../src/rbac/adapters/custom-zenstack-adapter.ts","../../src/rbac/services/casbin-enforcer.service.ts","../../src/rbac/services/casbin.service.ts","../../src/rbac/rbac.module.ts"],"sourcesContent":["/**\n * RBAC Constants\n */\nexport const RBAC_CONTEXT_KEYS = {\n /** Key for storing required authorization scopes (permissions) in context */\n AUTH_SCOPES: Symbol('rbac:authScopes'),\n} as const\n","import type { Adapter, Model } from 'casbin'\n\nimport { Helper } from 'casbin'\n\n/**\n * Minimal interface for the database client used by the adapter.\n * The actual DatabaseService extends ZenStackClient which provides these methods\n * when the schema includes a `casbinRule` model.\n */\nexport interface CasbinDbClient {\n casbinRule: {\n findMany(args?: { where?: Record<string, unknown> }): Promise<unknown[]>\n create(args: { data: CasbinRuleCreateInput }): Promise<unknown>\n createMany(args: { data: CasbinRuleCreateInput[] }): Promise<unknown>\n deleteMany(args: { where: CasbinRuleCreateInput }): Promise<{ count: number }>\n }\n $executeRawUnsafe(query: string, ...values: unknown[]): Promise<unknown>\n}\n\ninterface CasbinRuleCreateInput {\n ptype: string\n v0?: string | null\n v1?: string | null\n v2?: string | null\n v3?: string | null\n v4?: string | null\n v5?: string | null\n}\n\ninterface CasbinRuleRecord {\n id: number\n ptype: string\n v0: string | null\n v1: string | null\n v2: string | null\n v3: string | null\n v4: string | null\n v5: string | null\n}\n\n/**\n * Custom ZenStack adapter for Casbin that works with Cloudflare Workers.\n *\n * Based on the original casbin-prisma-adapter but modified to:\n * - Work with ZenStack v3 ORM clients\n * - Avoid bundling errors in Cloudflare Workers\n * - Accept pre-connected ZenStack clients (request-scoped)\n */\nexport class CustomZenStackAdapter implements Adapter {\n #db: CasbinDbClient\n\n filtered = false\n\n public isFiltered(): boolean {\n return this.filtered\n }\n\n public enableFiltered(enabled: boolean): void {\n this.filtered = enabled\n }\n\n constructor(db: CasbinDbClient) {\n this.#db = db\n }\n\n async loadPolicy(model: Model): Promise<void> {\n const lines = await this.#db.casbinRule.findMany()\n\n for (const line of lines) {\n this.#loadPolicyLine(line as CasbinRuleRecord, model)\n }\n }\n\n async loadFilteredPolicy(\n model: Model,\n filter: Record<string, string[][]>\n ): Promise<void> {\n const whereFilter = Object.keys(filter)\n .map((ptype) => {\n const policyPatterns = filter[ptype]\n return policyPatterns.map((policyPattern) => {\n return {\n ptype,\n ...(policyPattern[0] && { v0: policyPattern[0] }),\n ...(policyPattern[1] && { v1: policyPattern[1] }),\n ...(policyPattern[2] && { v2: policyPattern[2] }),\n ...(policyPattern[3] && { v3: policyPattern[3] }),\n ...(policyPattern[4] && { v4: policyPattern[4] }),\n ...(policyPattern[5] && { v5: policyPattern[5] }),\n }\n })\n })\n .flat()\n const lines = await this.#db.casbinRule.findMany({\n where: {\n OR: whereFilter,\n },\n })\n lines.forEach((line) => this.#loadPolicyLine(line as CasbinRuleRecord, model))\n this.enableFiltered(true)\n }\n\n async savePolicy(model: Model): Promise<boolean> {\n await this.#db.$executeRawUnsafe('DELETE FROM casbin_rule')\n\n const lines: CasbinRuleCreateInput[] = []\n\n const savePolicyType = (ptype: string): void => {\n const astMap = model.model.get(ptype)\n if (astMap) {\n for (const [ptype, ast] of astMap) {\n for (const rule of ast.policy) {\n const line = this.#savePolicyLine(ptype, rule)\n lines.push(line)\n }\n }\n }\n }\n\n savePolicyType('p')\n savePolicyType('g')\n\n await this.#db.casbinRule.createMany({ data: lines })\n\n return true\n }\n\n async addPolicy(_sec: string, ptype: string, rule: string[]): Promise<void> {\n const line = this.#savePolicyLine(ptype, rule)\n await this.#db.casbinRule.create({ data: line })\n }\n\n async addPolicies(\n _sec: string,\n ptype: string,\n rules: string[][]\n ): Promise<void> {\n const processes: Promise<CasbinRuleRecord>[] = []\n for (const rule of rules) {\n const line = this.#savePolicyLine(ptype, rule)\n const p = this.#db.casbinRule.create({ data: line }) as Promise<CasbinRuleRecord>\n processes.push(p)\n }\n\n await Promise.all(processes)\n }\n\n async removePolicy(\n _sec: string,\n ptype: string,\n rule: string[]\n ): Promise<void> {\n const line = this.#savePolicyLine(ptype, rule)\n await this.#db.casbinRule.deleteMany({ where: line })\n }\n\n async removePolicies(\n _sec: string,\n ptype: string,\n rules: string[][]\n ): Promise<void> {\n const processes: Promise<{ count: number }>[] = []\n for (const rule of rules) {\n const line = this.#savePolicyLine(ptype, rule)\n const p = this.#db.casbinRule.deleteMany({ where: line })\n processes.push(p)\n }\n\n await Promise.all(processes)\n }\n\n async removeFilteredPolicy(\n _sec: string,\n ptype: string,\n fieldIndex: number,\n ...fieldValues: string[]\n ): Promise<void> {\n const line: CasbinRuleCreateInput = { ptype }\n\n const idx = fieldIndex + fieldValues.length\n if (fieldIndex <= 0 && 0 < idx) {\n line.v0 = fieldValues[0 - fieldIndex]\n }\n if (fieldIndex <= 1 && 1 < idx) {\n line.v1 = fieldValues[1 - fieldIndex]\n }\n if (fieldIndex <= 2 && 2 < idx) {\n line.v2 = fieldValues[2 - fieldIndex]\n }\n if (fieldIndex <= 3 && 3 < idx) {\n line.v3 = fieldValues[3 - fieldIndex]\n }\n if (fieldIndex <= 4 && 4 < idx) {\n line.v4 = fieldValues[4 - fieldIndex]\n }\n if (fieldIndex <= 5 && 5 < idx) {\n line.v5 = fieldValues[5 - fieldIndex]\n }\n\n await this.#db.casbinRule.deleteMany({ where: line })\n }\n\n async close(): Promise<void> {\n // No-op: ZenStack uses pg.Pool for connection management\n }\n\n static newAdapter(db: CasbinDbClient): CustomZenStackAdapter {\n const adapter = new CustomZenStackAdapter(db)\n return adapter\n }\n\n #loadPolicyLine = (line: CasbinRuleRecord, model: Model): void => {\n const result =\n line.ptype +\n ', ' +\n [line.v0, line.v1, line.v2, line.v3, line.v4, line.v5]\n .filter((n) => n)\n .join(', ')\n Helper.loadPolicyLine(result, model)\n }\n\n #savePolicyLine = (\n ptype: string,\n rule: string[]\n ): CasbinRuleCreateInput => {\n const line: CasbinRuleCreateInput = { ptype }\n\n if (rule.length > 0) {\n line.v0 = rule[0]\n }\n if (rule.length > 1) {\n line.v1 = rule[1]\n }\n if (rule.length > 2) {\n line.v2 = rule[2]\n }\n if (rule.length > 3) {\n line.v3 = rule[3]\n }\n if (rule.length > 4) {\n line.v4 = rule[4]\n }\n if (rule.length > 5) {\n line.v5 = rule[5]\n }\n\n return line\n }\n}\n","import { newCachedEnforcer, newModelFromString, type Enforcer } from 'casbin'\nimport { DI_TOKENS, Transient } from 'stratal/di'\nimport { inject } from 'tsyringe'\nimport { CustomZenStackAdapter, type CasbinDbClient } from '../adapters/custom-zenstack-adapter'\nimport { RBAC_TOKENS } from '../tokens'\nimport type { RbacModuleOptions } from '../types'\n\n/**\n * CasbinEnforcerService\n *\n * Manages the Casbin enforcer instance for authorization.\n * Model, default policies, and role hierarchy are provided via DI options.\n */\n@Transient()\nexport class CasbinEnforcerService {\n protected enforcer: Enforcer | null = null\n\n constructor(\n @inject(DI_TOKENS.Database)\n protected readonly db: CasbinDbClient,\n @inject(RBAC_TOKENS.Options)\n protected readonly options: RbacModuleOptions,\n ) { }\n\n /**\n * Get or create the enforcer instance\n */\n async getEnforcer(): Promise<Enforcer> {\n this.enforcer ??= await this.createEnforcer();\n return this.enforcer\n }\n\n /**\n * Create a new enforcer instance.\n * Can be overridden by subclasses to customize enforcer creation.\n */\n protected async createEnforcer(): Promise<Enforcer> {\n const model = newModelFromString(this.options.model)\n\n const adapter = CustomZenStackAdapter.newAdapter(this.db)\n const enforcer = await newCachedEnforcer(model, adapter)\n await enforcer.loadPolicy()\n return enforcer\n }\n\n /**\n * Seed default policies into database\n */\n async seedPolicies(): Promise<void> {\n const enforcer = await this.getEnforcer()\n const policies = this.options.defaultPolicies ?? []\n\n for (const [role, resource, action] of policies) {\n await enforcer.addPolicy(role, resource, action)\n }\n\n await enforcer.savePolicy()\n }\n\n /**\n * Clear cached enforcer instance\n */\n clearCache(): void {\n this.enforcer = null\n }\n\n /**\n * Seed role hierarchy into database\n */\n async seedRoleHierarchy(): Promise<void> {\n const enforcer = await this.getEnforcer()\n const hierarchy = this.options.roleHierarchy ?? []\n\n for (const [childRole, parentRole] of hierarchy) {\n await enforcer.addGroupingPolicy(childRole, parentRole)\n }\n\n await enforcer.savePolicy()\n }\n}\n","import type { Enforcer } from 'casbin'\nimport { inject } from 'tsyringe'\nimport { Transient, DI_TOKENS } from 'stratal/di'\nimport type { AuthContext } from '../../context/auth-context'\nimport { RBAC_TOKENS } from '../tokens'\nimport { CasbinEnforcerService } from './casbin-enforcer.service'\n\n/**\n * CasbinService\n *\n * Request-scoped service that provides the full Casbin RBAC API.\n * Uses AuthContext to get the current user.\n */\n@Transient(RBAC_TOKENS.CasbinService)\nexport class CasbinService {\n constructor(\n @inject(DI_TOKENS.AuthContext)\n protected readonly context: AuthContext,\n @inject(CasbinEnforcerService)\n protected readonly enforcerService: CasbinEnforcerService\n ) {}\n\n protected async getEnforcer(): Promise<Enforcer> {\n return this.enforcerService.getEnforcer()\n }\n\n // ==================== USER-ROLE MANAGEMENT ====================\n\n async addRoleForUser(userId: string, role: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const added = await enforcer.addRoleForUser(userId, role)\n if (added) await enforcer.savePolicy()\n return added\n }\n\n async deleteRoleForUser(userId: string, role: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const deleted = await enforcer.deleteRoleForUser(userId, role)\n if (deleted) await enforcer.savePolicy()\n return deleted\n }\n\n async deleteRolesForUser(userId: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const deleted = await enforcer.deleteRolesForUser(userId)\n if (deleted) await enforcer.savePolicy()\n return deleted\n }\n\n async getRolesForUser(userId: string): Promise<string[]> {\n const enforcer = await this.getEnforcer()\n return enforcer.getRolesForUser(userId)\n }\n\n async getImplicitRolesForUser(userId: string): Promise<string[]> {\n const enforcer = await this.getEnforcer()\n return enforcer.getImplicitRolesForUser(userId)\n }\n\n async getUsersForRole(role: string): Promise<string[]> {\n const enforcer = await this.getEnforcer()\n return enforcer.getUsersForRole(role)\n }\n\n async getImplicitUsersForRole(role: string): Promise<string[]> {\n const enforcer = await this.getEnforcer()\n return enforcer.getImplicitUsersForRole(role)\n }\n\n async hasRoleForUser(userId: string, role: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n return enforcer.hasRoleForUser(userId, role)\n }\n\n // ==================== ROLE HIERARCHY MANAGEMENT ====================\n\n async addRoleInheritance(childRole: string, parentRole: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const added = await enforcer.addGroupingPolicy(childRole, parentRole)\n if (added) await enforcer.savePolicy()\n return added\n }\n\n async deleteRoleInheritance(childRole: string, parentRole: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const deleted = await enforcer.removeGroupingPolicy(childRole, parentRole)\n if (deleted) await enforcer.savePolicy()\n return deleted\n }\n\n // ==================== USER/ROLE DELETION ====================\n\n async deleteUser(userId: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const deleted = await enforcer.deleteUser(userId)\n if (deleted) await enforcer.savePolicy()\n return deleted\n }\n\n async deleteRole(role: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const deleted = await enforcer.deleteRole(role)\n if (deleted) await enforcer.savePolicy()\n return deleted\n }\n\n // ==================== CONVENIENCE METHODS ====================\n\n async getCurrentUserRoles(): Promise<string[]> {\n const userId = this.context.getUserId()\n if (!userId) return []\n return this.getImplicitRolesForUser(userId)\n }\n\n async currentUserHasRole(role: string): Promise<boolean> {\n const roles = await this.getCurrentUserRoles()\n return roles.includes(role)\n }\n\n async setRolesForUser(userId: string, roles: string[]): Promise<void> {\n const enforcer = await this.getEnforcer()\n await enforcer.deleteRolesForUser(userId)\n for (const role of roles) {\n await enforcer.addRoleForUser(userId, role)\n }\n await enforcer.savePolicy()\n }\n\n // ==================== PERMISSION CHECKING ====================\n\n async hasPermission(userId: string, scope: string, action: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n return enforcer.enforce(userId, scope, action)\n }\n\n async currentUserHasPermission(scope: string, action: string): Promise<boolean> {\n const userId = this.context.getUserId()\n if (!userId) return false\n return this.hasPermission(userId, scope, action)\n }\n\n async hasAnyPermission(userId: string, scopes: string[], action: string): Promise<boolean> {\n const enforcer = await this.getEnforcer()\n const requests = scopes.map(scope => [userId, scope, action])\n const results = await enforcer.batchEnforce(requests)\n return results.some(allowed => allowed)\n }\n\n async currentUserHasAnyPermission(scopes: string[], action: string): Promise<boolean> {\n const userId = this.context.getUserId()\n if (!userId) return false\n return this.hasAnyPermission(userId, scopes, action)\n }\n\n // ==================== CASBIN.JS FRONTEND SUPPORT ====================\n\n async getPermissionsForUserAsCasbinJs(userId: string): Promise<Record<string, string[]>> {\n const enforcer = await this.getEnforcer()\n const permissions = await enforcer.getImplicitPermissionsForUser(userId)\n\n const result: Record<string, string[]> = {}\n for (const [_role, resource, action] of permissions) {\n result[action] ??= []\n if (!result[action].includes(resource)) {\n result[action].push(resource)\n }\n }\n\n return result\n }\n\n async getCurrentUserPermissionsAsCasbinJs(): Promise<Record<string, string[]>> {\n const userId = this.context.getUserId()\n if (!userId) return {}\n return this.getPermissionsForUserAsCasbinJs(userId)\n }\n}\n","import { Module } from 'stratal/module'\nimport type { AsyncModuleOptions, DynamicModule } from 'stratal/module'\nimport { CasbinEnforcerService } from './services/casbin-enforcer.service'\nimport { CasbinService } from './services/casbin.service'\nimport { RBAC_TOKENS } from './tokens'\nimport type { RbacModuleOptions } from './types'\n\n/**\n * RBAC Module\n *\n * Provides role-based access control using Casbin.\n * Fully configurable — no hardcoded roles, policies, or model.\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * RbacModule.forRoot({\n * model: MY_RBAC_MODEL,\n * defaultPolicies: [['admin', 'users:*', '.*']],\n * roleHierarchy: [['super_admin', 'admin']],\n * })\n * ]\n * })\n * ```\n */\n@Module({\n providers: [\n CasbinEnforcerService,\n { provide: RBAC_TOKENS.CasbinService, useClass: CasbinService },\n ],\n})\nexport class RbacModule {\n static forRoot(options: RbacModuleOptions): DynamicModule {\n return {\n module: RbacModule,\n providers: [\n { provide: RBAC_TOKENS.Options, useValue: options as unknown as object },\n ],\n }\n }\n\n static forRootAsync(options: AsyncModuleOptions<RbacModuleOptions>): DynamicModule {\n return {\n module: RbacModule,\n providers: [\n {\n provide: RBAC_TOKENS.Options,\n useFactory: options.useFactory,\n inject: options.inject,\n },\n ],\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;AAGA,MAAa,oBAAoB,EAE/B,aAAa,OAAO,kBAAkB,EACvC;;;;;;;;;;;AC0CD,IAAa,wBAAb,MAAa,sBAAyC;CACpD;CAEA,WAAW;CAEX,aAA6B;AAC3B,SAAO,KAAK;;CAGd,eAAsB,SAAwB;AAC5C,OAAK,WAAW;;CAGlB,YAAY,IAAoB;AAC9B,QAAA,KAAW;;CAGb,MAAM,WAAW,OAA6B;EAC5C,MAAM,QAAQ,MAAM,MAAA,GAAS,WAAW,UAAU;AAElD,OAAK,MAAM,QAAQ,MACjB,OAAA,eAAqB,MAA0B,MAAM;;CAIzD,MAAM,mBACJ,OACA,QACe;EACf,MAAM,cAAc,OAAO,KAAK,OAAO,CACpC,KAAK,UAAU;AAEd,UADuB,OAAO,OACR,KAAK,kBAAkB;AAC3C,WAAO;KACL;KACA,GAAI,cAAc,MAAM,EAAE,IAAI,cAAc,IAAI;KAChD,GAAI,cAAc,MAAM,EAAE,IAAI,cAAc,IAAI;KAChD,GAAI,cAAc,MAAM,EAAE,IAAI,cAAc,IAAI;KAChD,GAAI,cAAc,MAAM,EAAE,IAAI,cAAc,IAAI;KAChD,GAAI,cAAc,MAAM,EAAE,IAAI,cAAc,IAAI;KAChD,GAAI,cAAc,MAAM,EAAE,IAAI,cAAc,IAAI;KACjD;KACD;IACF,CACD,MAAM;AAMT,GALc,MAAM,MAAA,GAAS,WAAW,SAAS,EAC/C,OAAO,EACL,IAAI,aACL,EACF,CAAC,EACI,SAAS,SAAS,MAAA,eAAqB,MAA0B,MAAM,CAAC;AAC9E,OAAK,eAAe,KAAK;;CAG3B,MAAM,WAAW,OAAgC;AAC/C,QAAM,MAAA,GAAS,kBAAkB,0BAA0B;EAE3D,MAAM,QAAiC,EAAE;EAEzC,MAAM,kBAAkB,UAAwB;GAC9C,MAAM,SAAS,MAAM,MAAM,IAAI,MAAM;AACrC,OAAI,OACF,MAAK,MAAM,CAAC,OAAO,QAAQ,OACzB,MAAK,MAAM,QAAQ,IAAI,QAAQ;IAC7B,MAAM,OAAO,MAAA,eAAqB,OAAO,KAAK;AAC9C,UAAM,KAAK,KAAK;;;AAMxB,iBAAe,IAAI;AACnB,iBAAe,IAAI;AAEnB,QAAM,MAAA,GAAS,WAAW,WAAW,EAAE,MAAM,OAAO,CAAC;AAErD,SAAO;;CAGT,MAAM,UAAU,MAAc,OAAe,MAA+B;EAC1E,MAAM,OAAO,MAAA,eAAqB,OAAO,KAAK;AAC9C,QAAM,MAAA,GAAS,WAAW,OAAO,EAAE,MAAM,MAAM,CAAC;;CAGlD,MAAM,YACJ,MACA,OACA,OACe;EACf,MAAM,YAAyC,EAAE;AACjD,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,OAAO,MAAA,eAAqB,OAAO,KAAK;GAC9C,MAAM,IAAI,MAAA,GAAS,WAAW,OAAO,EAAE,MAAM,MAAM,CAAC;AACpD,aAAU,KAAK,EAAE;;AAGnB,QAAM,QAAQ,IAAI,UAAU;;CAG9B,MAAM,aACJ,MACA,OACA,MACe;EACf,MAAM,OAAO,MAAA,eAAqB,OAAO,KAAK;AAC9C,QAAM,MAAA,GAAS,WAAW,WAAW,EAAE,OAAO,MAAM,CAAC;;CAGvD,MAAM,eACJ,MACA,OACA,OACe;EACf,MAAM,YAA0C,EAAE;AAClD,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,OAAO,MAAA,eAAqB,OAAO,KAAK;GAC9C,MAAM,IAAI,MAAA,GAAS,WAAW,WAAW,EAAE,OAAO,MAAM,CAAC;AACzD,aAAU,KAAK,EAAE;;AAGnB,QAAM,QAAQ,IAAI,UAAU;;CAG9B,MAAM,qBACJ,MACA,OACA,YACA,GAAG,aACY;EACf,MAAM,OAA8B,EAAE,OAAO;EAE7C,MAAM,MAAM,aAAa,YAAY;AACrC,MAAI,cAAc,KAAK,IAAI,IACzB,MAAK,KAAK,YAAY,IAAI;AAE5B,MAAI,cAAc,KAAK,IAAI,IACzB,MAAK,KAAK,YAAY,IAAI;AAE5B,MAAI,cAAc,KAAK,IAAI,IACzB,MAAK,KAAK,YAAY,IAAI;AAE5B,MAAI,cAAc,KAAK,IAAI,IACzB,MAAK,KAAK,YAAY,IAAI;AAE5B,MAAI,cAAc,KAAK,IAAI,IACzB,MAAK,KAAK,YAAY,IAAI;AAE5B,MAAI,cAAc,KAAK,IAAI,IACzB,MAAK,KAAK,YAAY,IAAI;AAG5B,QAAM,MAAA,GAAS,WAAW,WAAW,EAAE,OAAO,MAAM,CAAC;;CAGvD,MAAM,QAAuB;CAI7B,OAAO,WAAW,IAA2C;AAE3D,SADgB,IAAI,sBAAsB,GAAG;;CAI/C,mBAAmB,MAAwB,UAAuB;EAChE,MAAM,SACJ,KAAK,QACL,OACA;GAAC,KAAK;GAAI,KAAK;GAAI,KAAK;GAAI,KAAK;GAAI,KAAK;GAAI,KAAK;GAAG,CACnD,QAAQ,MAAM,EAAE,CAChB,KAAK,KAAK;AACf,SAAO,eAAe,QAAQ,MAAM;;CAGtC,mBACE,OACA,SAC0B;EAC1B,MAAM,OAA8B,EAAE,OAAO;AAE7C,MAAI,KAAK,SAAS,EAChB,MAAK,KAAK,KAAK;AAEjB,MAAI,KAAK,SAAS,EAChB,MAAK,KAAK,KAAK;AAEjB,MAAI,KAAK,SAAS,EAChB,MAAK,KAAK,KAAK;AAEjB,MAAI,KAAK,SAAS,EAChB,MAAK,KAAK,KAAK;AAEjB,MAAI,KAAK,SAAS,EAChB,MAAK,KAAK,KAAK;AAEjB,MAAI,KAAK,SAAS,EAChB,MAAK,KAAK,KAAK;AAGjB,SAAO;;;;;ACxOJ,IAAA,wBAAA,MAAM,sBAAsB;CACjC,WAAsC;CAEtC,YACE,IAEA,SAEA;AAHmB,OAAA,KAAA;AAEA,OAAA,UAAA;;;;;CAMrB,MAAM,cAAiC;AACrC,OAAK,aAAa,MAAM,KAAK,gBAAgB;AAC7C,SAAO,KAAK;;;;;;CAOd,MAAgB,iBAAoC;EAIlD,MAAM,WAAW,MAAM,kBAHT,mBAAmB,KAAK,QAAQ,MAAM,EAEpC,sBAAsB,WAAW,KAAK,GAAG,CACD;AACxD,QAAM,SAAS,YAAY;AAC3B,SAAO;;;;;CAMT,MAAM,eAA8B;EAClC,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,WAAW,KAAK,QAAQ,mBAAmB,EAAE;AAEnD,OAAK,MAAM,CAAC,MAAM,UAAU,WAAW,SACrC,OAAM,SAAS,UAAU,MAAM,UAAU,OAAO;AAGlD,QAAM,SAAS,YAAY;;;;;CAM7B,aAAmB;AACjB,OAAK,WAAW;;;;;CAMlB,MAAM,oBAAmC;EACvC,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,YAAY,KAAK,QAAQ,iBAAiB,EAAE;AAElD,OAAK,MAAM,CAAC,WAAW,eAAe,UACpC,OAAM,SAAS,kBAAkB,WAAW,WAAW;AAGzD,QAAM,SAAS,YAAY;;;;CAhE9B,WAAW;oBAKP,OAAO,UAAU,SAAS,CAAA;oBAE1B,OAAO,YAAY,QAAQ,CAAA;;;;;;ACNzB,IAAA,gBAAA,MAAM,cAAc;CACzB,YACE,SAEA,iBAEA;AAHmB,OAAA,UAAA;AAEA,OAAA,kBAAA;;CAGrB,MAAgB,cAAiC;AAC/C,SAAO,KAAK,gBAAgB,aAAa;;CAK3C,MAAM,eAAe,QAAgB,MAAgC;EACnE,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,QAAQ,MAAM,SAAS,eAAe,QAAQ,KAAK;AACzD,MAAI,MAAO,OAAM,SAAS,YAAY;AACtC,SAAO;;CAGT,MAAM,kBAAkB,QAAgB,MAAgC;EACtE,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,UAAU,MAAM,SAAS,kBAAkB,QAAQ,KAAK;AAC9D,MAAI,QAAS,OAAM,SAAS,YAAY;AACxC,SAAO;;CAGT,MAAM,mBAAmB,QAAkC;EACzD,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,UAAU,MAAM,SAAS,mBAAmB,OAAO;AACzD,MAAI,QAAS,OAAM,SAAS,YAAY;AACxC,SAAO;;CAGT,MAAM,gBAAgB,QAAmC;AAEvD,UADiB,MAAM,KAAK,aAAa,EACzB,gBAAgB,OAAO;;CAGzC,MAAM,wBAAwB,QAAmC;AAE/D,UADiB,MAAM,KAAK,aAAa,EACzB,wBAAwB,OAAO;;CAGjD,MAAM,gBAAgB,MAAiC;AAErD,UADiB,MAAM,KAAK,aAAa,EACzB,gBAAgB,KAAK;;CAGvC,MAAM,wBAAwB,MAAiC;AAE7D,UADiB,MAAM,KAAK,aAAa,EACzB,wBAAwB,KAAK;;CAG/C,MAAM,eAAe,QAAgB,MAAgC;AAEnE,UADiB,MAAM,KAAK,aAAa,EACzB,eAAe,QAAQ,KAAK;;CAK9C,MAAM,mBAAmB,WAAmB,YAAsC;EAChF,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,QAAQ,MAAM,SAAS,kBAAkB,WAAW,WAAW;AACrE,MAAI,MAAO,OAAM,SAAS,YAAY;AACtC,SAAO;;CAGT,MAAM,sBAAsB,WAAmB,YAAsC;EACnF,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,UAAU,MAAM,SAAS,qBAAqB,WAAW,WAAW;AAC1E,MAAI,QAAS,OAAM,SAAS,YAAY;AACxC,SAAO;;CAKT,MAAM,WAAW,QAAkC;EACjD,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,UAAU,MAAM,SAAS,WAAW,OAAO;AACjD,MAAI,QAAS,OAAM,SAAS,YAAY;AACxC,SAAO;;CAGT,MAAM,WAAW,MAAgC;EAC/C,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,UAAU,MAAM,SAAS,WAAW,KAAK;AAC/C,MAAI,QAAS,OAAM,SAAS,YAAY;AACxC,SAAO;;CAKT,MAAM,sBAAyC;EAC7C,MAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,MAAI,CAAC,OAAQ,QAAO,EAAE;AACtB,SAAO,KAAK,wBAAwB,OAAO;;CAG7C,MAAM,mBAAmB,MAAgC;AAEvD,UADc,MAAM,KAAK,qBAAqB,EACjC,SAAS,KAAK;;CAG7B,MAAM,gBAAgB,QAAgB,OAAgC;EACpE,MAAM,WAAW,MAAM,KAAK,aAAa;AACzC,QAAM,SAAS,mBAAmB,OAAO;AACzC,OAAK,MAAM,QAAQ,MACjB,OAAM,SAAS,eAAe,QAAQ,KAAK;AAE7C,QAAM,SAAS,YAAY;;CAK7B,MAAM,cAAc,QAAgB,OAAe,QAAkC;AAEnF,UADiB,MAAM,KAAK,aAAa,EACzB,QAAQ,QAAQ,OAAO,OAAO;;CAGhD,MAAM,yBAAyB,OAAe,QAAkC;EAC9E,MAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,KAAK,cAAc,QAAQ,OAAO,OAAO;;CAGlD,MAAM,iBAAiB,QAAgB,QAAkB,QAAkC;EACzF,MAAM,WAAW,MAAM,KAAK,aAAa;EACzC,MAAM,WAAW,OAAO,KAAI,UAAS;GAAC;GAAQ;GAAO;GAAO,CAAC;AAE7D,UADgB,MAAM,SAAS,aAAa,SAAS,EACtC,MAAK,YAAW,QAAQ;;CAGzC,MAAM,4BAA4B,QAAkB,QAAkC;EACpF,MAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,KAAK,iBAAiB,QAAQ,QAAQ,OAAO;;CAKtD,MAAM,gCAAgC,QAAmD;EAEvF,MAAM,cAAc,OADH,MAAM,KAAK,aAAa,EACN,8BAA8B,OAAO;EAExE,MAAM,SAAmC,EAAE;AAC3C,OAAK,MAAM,CAAC,OAAO,UAAU,WAAW,aAAa;AACnD,UAAO,YAAY,EAAE;AACrB,OAAI,CAAC,OAAO,QAAQ,SAAS,SAAS,CACpC,QAAO,QAAQ,KAAK,SAAS;;AAIjC,SAAO;;CAGT,MAAM,sCAAyE;EAC7E,MAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,MAAI,CAAC,OAAQ,QAAO,EAAE;AACtB,SAAO,KAAK,gCAAgC,OAAO;;;;CAjKtD,UAAU,YAAY,cAAc;oBAGhC,OAAO,UAAU,YAAY,CAAA;oBAE7B,OAAO,sBAAsB,CAAA;;;;;;ACc3B,IAAA,aAAA,cAAA,MAAM,WAAW;CACtB,OAAO,QAAQ,SAA2C;AACxD,SAAO;GACL,QAAA;GACA,WAAW,CACT;IAAE,SAAS,YAAY;IAAS,UAAU;IAA8B,CACzE;GACF;;CAGH,OAAO,aAAa,SAA+D;AACjF,SAAO;GACL,QAAA;GACA,WAAW,CACT;IACE,SAAS,YAAY;IACrB,YAAY,QAAQ;IACpB,QAAQ,QAAQ;IACjB,CACF;GACF;;;uCA1BJ,OAAO,EACN,WAAW,CACT,uBACA;CAAE,SAAS,YAAY;CAAe,UAAU;CAAe,CAChE,EACF,CAAC,CAAA,EAAA,WAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ApplicationError, ERROR_CODES } from "stratal/errors";
|
|
2
|
+
//#region src/rbac/errors/insufficient-permissions.error.ts
|
|
3
|
+
/**
|
|
4
|
+
* InsufficientPermissionsError
|
|
5
|
+
*
|
|
6
|
+
* Thrown when a user attempts to perform an action without the required permissions.
|
|
7
|
+
* This error is used by the auth guard after authorization check fails.
|
|
8
|
+
*
|
|
9
|
+
* HTTP Status: 403 Forbidden
|
|
10
|
+
* Error Code: 3102 (AUTHZ.INSUFFICIENT_PERMISSIONS)
|
|
11
|
+
*/
|
|
12
|
+
var InsufficientPermissionsError = class extends ApplicationError {
|
|
13
|
+
constructor(requiredScopes, userId) {
|
|
14
|
+
super("errors.insufficientPermissions", ERROR_CODES.AUTHZ.INSUFFICIENT_PERMISSIONS, {
|
|
15
|
+
requiredScopes: requiredScopes.join(", "),
|
|
16
|
+
userId: userId ?? "unknown"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/rbac/tokens.ts
|
|
22
|
+
/**
|
|
23
|
+
* RBAC DI Tokens
|
|
24
|
+
*/
|
|
25
|
+
const RBAC_TOKENS = {
|
|
26
|
+
CasbinService: Symbol.for("stratal:rbac:casbin:service"),
|
|
27
|
+
Options: Symbol.for("stratal:rbac:options")
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { InsufficientPermissionsError as n, RBAC_TOKENS as t };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=tokens-Di1ofovy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens-Di1ofovy.mjs","names":[],"sources":["../src/rbac/errors/insufficient-permissions.error.ts","../src/rbac/tokens.ts"],"sourcesContent":["import { ApplicationError, ERROR_CODES } from 'stratal/errors'\n\n/**\n * InsufficientPermissionsError\n *\n * Thrown when a user attempts to perform an action without the required permissions.\n * This error is used by the auth guard after authorization check fails.\n *\n * HTTP Status: 403 Forbidden\n * Error Code: 3102 (AUTHZ.INSUFFICIENT_PERMISSIONS)\n */\nexport class InsufficientPermissionsError extends ApplicationError {\n constructor(requiredScopes: string[], userId?: string) {\n super('errors.insufficientPermissions', ERROR_CODES.AUTHZ.INSUFFICIENT_PERMISSIONS, {\n requiredScopes: requiredScopes.join(', '),\n userId: userId ?? 'unknown',\n })\n }\n}\n","/**\n * RBAC DI Tokens\n */\nexport const RBAC_TOKENS = {\n /** Request-scoped Casbin service with auto context resolution */\n CasbinService: Symbol.for('stratal:rbac:casbin:service'),\n /** RBAC module options (model, policies, hierarchy) */\n Options: Symbol.for('stratal:rbac:options'),\n} as const\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,+BAAb,cAAkD,iBAAiB;CACjE,YAAY,gBAA0B,QAAiB;AACrD,QAAM,kCAAkC,YAAY,MAAM,0BAA0B;GAClF,gBAAgB,eAAe,KAAK,KAAK;GACzC,QAAQ,UAAU;GACnB,CAAC;;;;;;;;ACbN,MAAa,cAAc;CAEzB,eAAe,OAAO,IAAI,8BAA8B;CAExD,SAAS,OAAO,IAAI,uBAAuB;CAC5C"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { SchemaDef } from "@zenstackhq/schema";
|
|
2
|
+
|
|
3
|
+
//#region src/database/types.d.ts
|
|
2
4
|
/**
|
|
3
5
|
* Augment with per-connection schemas and default connection.
|
|
4
6
|
*
|
|
@@ -15,30 +17,31 @@ import type { SchemaDef } from '@zenstackhq/schema';
|
|
|
15
17
|
* }
|
|
16
18
|
* ```
|
|
17
19
|
*/
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
+
interface StratalDatabase {}
|
|
20
21
|
/** Infer schema type for a specific connection */
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
type InferConnectionSchema<K extends string> = StratalDatabase extends {
|
|
23
|
+
schemas: infer R;
|
|
23
24
|
} ? K extends keyof R ? R[K] extends SchemaDef ? R[K] : SchemaDef : SchemaDef : SchemaDef;
|
|
24
25
|
/** Union of ALL schemas across connections (for events) */
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
type InferAnySchema = StratalDatabase extends {
|
|
27
|
+
schemas: infer R;
|
|
27
28
|
} ? R[keyof R] extends SchemaDef ? R[keyof R] : SchemaDef : SchemaDef;
|
|
28
29
|
/** Connection name — derived from schemas keys */
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
type ConnectionName = StratalDatabase extends {
|
|
31
|
+
schemas: infer R;
|
|
31
32
|
} ? keyof R extends never ? string : Extract<keyof R, string> : string;
|
|
32
33
|
/** Default connection name */
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
type DefaultConnectionName = StratalDatabase extends {
|
|
35
|
+
defaultConnection: infer N extends string;
|
|
35
36
|
} ? N : string;
|
|
36
37
|
/**
|
|
37
38
|
* Internal context used by database service for dynamic event emission
|
|
38
39
|
* @internal
|
|
39
40
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
interface InternalDatabaseEventContext {
|
|
42
|
+
data: unknown;
|
|
43
|
+
result?: unknown;
|
|
43
44
|
}
|
|
44
|
-
//#
|
|
45
|
+
//#endregion
|
|
46
|
+
export { InternalDatabaseEventContext as a, InferConnectionSchema as i, DefaultConnectionName as n, StratalDatabase as o, InferAnySchema as r, ConnectionName as t };
|
|
47
|
+
//# sourceMappingURL=types-Gjk0d2qB.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-Gjk0d2qB.d.mts","names":[],"sources":["../src/database/types.ts"],"mappings":";;;;;AAkBA;;;;;AAGA;;;;;;;;;UAHiB,eAAA;;KAGL,qBAAA,qBACV,eAAA;EAA0B,OAAA;AAAA,IACtB,CAAA,eAAgB,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,SAAA,GAAY,CAAA,CAAE,CAAA,IAAK,SAAA,GAAY,SAAA,GAChE,SAAA;;KAGM,cAAA,GACV,eAAA;EAA0B,OAAA;AAAA,IACtB,CAAA,OAAQ,CAAA,UAAW,SAAA,GAAY,CAAA,OAAQ,CAAA,IAAK,SAAA,GAC5C,SAAA;;KAGM,cAAA,GACV,eAAA;EAA0B,OAAA;AAAA,UAChB,CAAA,0BAA2B,OAAA,OAAc,CAAA;;KAIzC,qBAAA,GACV,eAAA;EAA0B,iBAAA;AAAA,IAA8C,CAAA;;;;;UAMzD,4BAAA;EACf,IAAA;EACA,MAAA;AAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratal/framework",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Temitayo Fadojutimi",
|
|
@@ -23,41 +23,40 @@
|
|
|
23
23
|
],
|
|
24
24
|
"exports": {
|
|
25
25
|
".": {
|
|
26
|
-
"types": "./dist/index.d.
|
|
27
|
-
"import": "./dist/index.
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
27
|
+
"import": "./dist/index.mjs"
|
|
28
28
|
},
|
|
29
29
|
"./auth": {
|
|
30
|
-
"types": "./dist/auth/index.d.
|
|
31
|
-
"import": "./dist/auth/index.
|
|
30
|
+
"types": "./dist/auth/index.d.mts",
|
|
31
|
+
"import": "./dist/auth/index.mjs"
|
|
32
32
|
},
|
|
33
33
|
"./context": {
|
|
34
|
-
"types": "./dist/context/index.d.
|
|
35
|
-
"import": "./dist/context/index.
|
|
34
|
+
"types": "./dist/context/index.d.mts",
|
|
35
|
+
"import": "./dist/context/index.mjs"
|
|
36
36
|
},
|
|
37
37
|
"./database": {
|
|
38
|
-
"types": "./dist/database/index.d.
|
|
39
|
-
"import": "./dist/database/index.
|
|
38
|
+
"types": "./dist/database/index.d.mts",
|
|
39
|
+
"import": "./dist/database/index.mjs"
|
|
40
40
|
},
|
|
41
41
|
"./factory": {
|
|
42
|
-
"types": "./dist/factory/index.d.
|
|
43
|
-
"import": "./dist/factory/index.
|
|
42
|
+
"types": "./dist/factory/index.d.mts",
|
|
43
|
+
"import": "./dist/factory/index.mjs"
|
|
44
44
|
},
|
|
45
45
|
"./guards": {
|
|
46
|
-
"types": "./dist/guards/index.d.
|
|
47
|
-
"import": "./dist/guards/index.
|
|
46
|
+
"types": "./dist/guards/index.d.mts",
|
|
47
|
+
"import": "./dist/guards/index.mjs"
|
|
48
48
|
},
|
|
49
49
|
"./rbac": {
|
|
50
|
-
"types": "./dist/rbac/index.d.
|
|
51
|
-
"import": "./dist/rbac/index.
|
|
52
|
-
}
|
|
50
|
+
"types": "./dist/rbac/index.d.mts",
|
|
51
|
+
"import": "./dist/rbac/index.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./package.json": "./package.json"
|
|
53
54
|
},
|
|
54
55
|
"scripts": {
|
|
55
|
-
"build": "
|
|
56
|
-
"clean": "rm -rf dist",
|
|
57
|
-
"prebuild": "yarn clean",
|
|
56
|
+
"build": "tsdown",
|
|
58
57
|
"generate": "zenstack generate --schema=test/schema.zmodel -o test/zenstack",
|
|
59
58
|
"generate:types": "wrangler types -c test/wrangler.jsonc",
|
|
60
|
-
"pretest": "yarn generate && yarn generate:types",
|
|
59
|
+
"pretest": "npx dotenv -- yarn generate && yarn generate:types",
|
|
61
60
|
"test": "vitest run",
|
|
62
61
|
"test:watch": "vitest",
|
|
63
62
|
"test:e2e": "vitest run --project e2e",
|
|
@@ -78,7 +77,7 @@
|
|
|
78
77
|
"better-auth": "^1.4.9",
|
|
79
78
|
"casbin": "^5.41.0",
|
|
80
79
|
"pg": "^8.0.0",
|
|
81
|
-
"stratal": "0.0.
|
|
80
|
+
"stratal": "0.0.14"
|
|
82
81
|
},
|
|
83
82
|
"peerDependenciesMeta": {
|
|
84
83
|
"@better-auth/core": {
|
|
@@ -99,8 +98,8 @@
|
|
|
99
98
|
},
|
|
100
99
|
"devDependencies": {
|
|
101
100
|
"@better-auth/core": "^1.5.5",
|
|
102
|
-
"@cloudflare/vitest-pool-workers": "
|
|
103
|
-
"@cloudflare/workers-types": "4.
|
|
101
|
+
"@cloudflare/vitest-pool-workers": "^0.13.2",
|
|
102
|
+
"@cloudflare/workers-types": "4.20260317.1",
|
|
104
103
|
"@faker-js/faker": "^10.3.0",
|
|
105
104
|
"@stratal/testing": "workspace:^",
|
|
106
105
|
"@types/node": "^25.5.0",
|
|
@@ -113,11 +112,13 @@
|
|
|
113
112
|
"@zenstackhq/orm": "^3.4.6",
|
|
114
113
|
"better-auth": "^1.5.5",
|
|
115
114
|
"casbin": "^5.49.0",
|
|
115
|
+
"dotenv-cli": "^11.0.0",
|
|
116
116
|
"pg": "^8.20.0",
|
|
117
117
|
"reflect-metadata": "^0.2.2",
|
|
118
118
|
"stratal": "workspace:*",
|
|
119
|
+
"tsdown": "^0.21.4",
|
|
119
120
|
"typescript": "^5.9.3",
|
|
120
121
|
"vitest": "~4.1.0",
|
|
121
|
-
"wrangler": "^4.
|
|
122
|
+
"wrangler": "^4.75.0"
|
|
122
123
|
}
|
|
123
124
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Module
|
|
3
|
-
*
|
|
4
|
-
* Provides configurable authentication using Better Auth.
|
|
5
|
-
* Use `forRootAsync` to configure Better Auth options from the application layer.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* @Module({
|
|
10
|
-
* imports: [
|
|
11
|
-
* AuthModule.forRootAsync({
|
|
12
|
-
* inject: [DI_TOKENS.Database, CONFIG_TOKENS.ConfigService],
|
|
13
|
-
* useFactory: (db, config) => createAuthOptions(db, config)
|
|
14
|
-
* })
|
|
15
|
-
* ]
|
|
16
|
-
* })
|
|
17
|
-
* export class AppModule {}
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
import type { BetterAuthOptions } from 'better-auth';
|
|
21
|
-
import type { MiddlewareConfigurable, MiddlewareConsumer } from 'stratal/middleware';
|
|
22
|
-
import type { AsyncModuleOptions, DynamicModule } from 'stratal/module';
|
|
23
|
-
export declare class AuthModule implements MiddlewareConfigurable {
|
|
24
|
-
/**
|
|
25
|
-
* Configure auth middleware.
|
|
26
|
-
*
|
|
27
|
-
* Registers middlewares in order:
|
|
28
|
-
* 1. AuthContextMiddleware - Creates and registers AuthContext in request container
|
|
29
|
-
* 2. SessionVerificationMiddleware - Verifies session and populates AuthContext with userId
|
|
30
|
-
*/
|
|
31
|
-
configure(consumer: MiddlewareConsumer): void;
|
|
32
|
-
/**
|
|
33
|
-
* Configure AuthModule with async options factory
|
|
34
|
-
*/
|
|
35
|
-
static forRootAsync<TOptions extends BetterAuthOptions>(options: AsyncModuleOptions<TOptions>): DynamicModule;
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=auth.module.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAEpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAMvE,qBAGa,UAAW,YAAW,sBAAsB;IACvD;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAU7C;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,SAAS,iBAAiB,EACpD,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,GACpC,aAAa;CAgBjB"}
|