@simple-auth-kit/cli 1.5.1 → 1.6.1
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/package.json +1 -1
- package/registry/combos/express-drizzle/shared/src/{ability.ts → ability/ability.ts} +8 -2
- package/registry/combos/express-drizzle/shared/src/{permission-cache.ts → cache/permission-cache.ts} +25 -9
- package/registry/combos/express-drizzle/shared/src/{rate-limit.store.ts → cache/rate-limit.store.ts} +4 -1
- package/registry/combos/{express-prisma/shared/src → express-drizzle/shared/src/config}/auth.config.ts +1 -1
- package/registry/combos/express-drizzle/shared/src/{db.ts → config/db.ts} +1 -1
- package/registry/combos/express-drizzle/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
- package/registry/combos/express-drizzle/shared/src/{id.helper.ts → helpers/id.helper.ts} +6 -2
- package/registry/combos/{nestjs-drizzle/shared/src → express-drizzle/shared/src/helpers}/pagination.ts +17 -3
- package/registry/combos/express-drizzle/shared/src/middleware/auth-core-error.middleware.ts +6 -8
- package/registry/combos/express-drizzle/shared/src/middleware/auth.middleware.ts +6 -8
- package/registry/combos/{express-prisma/shared/src → express-drizzle/shared/src/openapi}/openapi-fragment.ts +13 -4
- package/registry/combos/express-drizzle/shared/src/{openapi-spec.ts → openapi/openapi-spec.ts} +251 -52
- package/registry/combos/express-drizzle/shared/src/repositories/oauth.repository.ts +2 -2
- package/registry/combos/express-drizzle/shared/src/repositories/password-reset.repository.ts +2 -4
- package/registry/combos/express-drizzle/shared/src/repositories/session.repository.ts +3 -3
- package/registry/combos/express-drizzle/shared/src/request-context.ts +1 -1
- package/registry/combos/express-drizzle/shared/src/route-tiers.ts +52 -11
- package/registry/combos/express-drizzle/shared/src/routers/auth.router.ts +2 -2
- package/registry/combos/express-drizzle/test/bootstrap.ts +4 -2
- package/registry/combos/express-drizzle/test/prove-cycle.ts +1095 -308
- package/registry/combos/express-drizzle/variants/base/src/create-auth-app.ts +5 -5
- package/registry/combos/express-drizzle/variants/base/src/index.ts +8 -0
- package/registry/combos/express-drizzle/variants/base/src/middleware/authz.middleware.ts +2 -2
- package/registry/combos/express-drizzle/variants/base/src/openapi/openapi-admin.ts +1082 -0
- package/registry/combos/express-drizzle/variants/base/src/rbac.defaults.ts +60 -17
- package/registry/combos/express-drizzle/variants/base/src/repositories/audit-log.repository.ts +2 -2
- package/registry/combos/express-drizzle/variants/base/src/repositories/rbac.repository.ts +5 -5
- package/registry/combos/express-drizzle/variants/base/src/routers/admin.router.ts +18 -22
- package/registry/combos/express-drizzle/variants/base/src/seed.ts +76 -17
- package/registry/combos/express-drizzle/variants/base/src/services/auth.service.ts +7 -9
- package/registry/combos/express-drizzle/variants/base/test/variant-hooks.ts +167 -45
- package/registry/combos/express-drizzle/variants/workspaces/src/create-auth-app.ts +5 -5
- package/registry/combos/express-drizzle/variants/workspaces/src/index.ts +8 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/middleware/authz.middleware.ts +3 -3
- package/registry/combos/express-drizzle/variants/workspaces/src/openapi/openapi-admin.ts +1176 -0
- package/registry/combos/express-drizzle/variants/workspaces/src/openapi-workspace.ts +1 -1
- package/registry/combos/express-drizzle/variants/workspaces/src/rbac.defaults.ts +66 -19
- package/registry/combos/express-drizzle/variants/workspaces/src/repositories/audit-log.repository.ts +2 -2
- package/registry/combos/express-drizzle/variants/workspaces/src/repositories/rbac.repository.ts +5 -5
- package/registry/combos/express-drizzle/variants/workspaces/src/repositories/workspace.repository.ts +9 -11
- package/registry/combos/express-drizzle/variants/workspaces/src/routers/admin.router.ts +18 -22
- package/registry/combos/express-drizzle/variants/workspaces/src/routers/workspace.router.ts +1 -1
- package/registry/combos/express-drizzle/variants/workspaces/src/seed.ts +168 -35
- package/registry/combos/express-drizzle/variants/workspaces/src/services/auth.service.ts +7 -9
- package/registry/combos/express-drizzle/variants/workspaces/test/variant-hooks.ts +539 -133
- package/registry/combos/express-prisma/shared/src/{ability.ts → ability/ability.ts} +8 -2
- package/registry/combos/express-prisma/shared/src/{permission-cache.ts → cache/permission-cache.ts} +25 -9
- package/registry/combos/express-prisma/shared/src/{rate-limit.store.ts → cache/rate-limit.store.ts} +4 -1
- package/registry/combos/{express-drizzle/shared/src → express-prisma/shared/src/config}/auth.config.ts +1 -1
- package/registry/combos/express-prisma/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
- package/registry/combos/{nestjs-prisma/shared/src → express-prisma/shared/src/helpers}/id.helper.ts +6 -2
- package/registry/combos/{express-drizzle/shared/src → express-prisma/shared/src/helpers}/pagination.ts +17 -3
- package/registry/combos/express-prisma/shared/src/middleware/auth-core-error.middleware.ts +6 -8
- package/registry/combos/express-prisma/shared/src/middleware/auth.middleware.ts +6 -8
- package/registry/combos/{express-drizzle/shared/src → express-prisma/shared/src/openapi}/openapi-fragment.ts +13 -4
- package/registry/combos/express-prisma/shared/src/{openapi-spec.ts → openapi/openapi-spec.ts} +313 -55
- package/registry/combos/express-prisma/shared/src/repositories/oauth.repository.ts +2 -2
- package/registry/combos/express-prisma/shared/src/repositories/password-reset.repository.ts +2 -4
- package/registry/combos/express-prisma/shared/src/repositories/session.repository.ts +2 -2
- package/registry/combos/express-prisma/shared/src/request-context.ts +1 -1
- package/registry/combos/express-prisma/shared/src/route-tiers.ts +52 -11
- package/registry/combos/express-prisma/shared/src/routers/auth.router.ts +2 -2
- package/registry/combos/express-prisma/test/bootstrap.ts +7 -3
- package/registry/combos/express-prisma/test/prove-cycle.ts +1095 -308
- package/registry/combos/express-prisma/variants/base/src/create-auth-app.ts +6 -6
- package/registry/combos/express-prisma/variants/base/src/index.ts +8 -0
- package/registry/combos/express-prisma/variants/base/src/middleware/authz.middleware.ts +2 -2
- package/registry/combos/express-prisma/variants/base/src/openapi/openapi-admin.ts +1102 -0
- package/registry/combos/express-prisma/variants/base/src/rbac.defaults.ts +1 -1
- package/registry/combos/express-prisma/variants/base/src/repositories/audit-log.repository.ts +2 -2
- package/registry/combos/express-prisma/variants/base/src/repositories/rbac.repository.ts +4 -4
- package/registry/combos/express-prisma/variants/base/src/routers/admin.router.ts +18 -22
- package/registry/combos/express-prisma/variants/base/src/seed.ts +1 -1
- package/registry/combos/express-prisma/variants/base/src/services/auth.service.ts +6 -8
- package/registry/combos/express-prisma/variants/base/test/variant-hooks.ts +176 -47
- package/registry/combos/express-prisma/variants/workspaces/src/create-auth-app.ts +6 -6
- package/registry/combos/express-prisma/variants/workspaces/src/index.ts +8 -0
- package/registry/combos/express-prisma/variants/workspaces/src/middleware/authz.middleware.ts +3 -3
- package/registry/combos/express-prisma/variants/workspaces/src/openapi/openapi-admin.ts +1218 -0
- package/registry/combos/express-prisma/variants/workspaces/src/openapi-workspace.ts +1 -1
- package/registry/combos/express-prisma/variants/workspaces/src/rbac.defaults.ts +1 -1
- package/registry/combos/express-prisma/variants/workspaces/src/repositories/audit-log.repository.ts +2 -2
- package/registry/combos/express-prisma/variants/workspaces/src/repositories/rbac.repository.ts +4 -4
- package/registry/combos/express-prisma/variants/workspaces/src/repositories/workspace.repository.ts +2 -2
- package/registry/combos/express-prisma/variants/workspaces/src/routers/admin.router.ts +18 -22
- package/registry/combos/express-prisma/variants/workspaces/src/routers/workspace.router.ts +1 -1
- package/registry/combos/express-prisma/variants/workspaces/src/seed.ts +1 -1
- package/registry/combos/express-prisma/variants/workspaces/src/services/auth.service.ts +6 -8
- package/registry/combos/express-prisma/variants/workspaces/test/variant-hooks.ts +538 -134
- package/registry/combos/nestjs-drizzle/shared/src/{guards → ability}/ability.guard.ts +1 -1
- package/registry/combos/nestjs-drizzle/shared/src/{ability.ts → ability/ability.ts} +8 -2
- package/registry/combos/nestjs-drizzle/shared/src/{permission-cache.ts → cache/permission-cache.ts} +27 -10
- package/registry/combos/{nestjs-prisma/shared/src → nestjs-drizzle/shared/src/cache}/rate-limit.store.ts +4 -1
- package/registry/combos/nestjs-drizzle/shared/src/{auth.config.ts → config/auth.config.ts} +1 -1
- package/registry/combos/nestjs-drizzle/shared/src/{db.ts → config/db.ts} +1 -1
- package/registry/combos/nestjs-drizzle/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
- package/registry/combos/nestjs-drizzle/shared/src/controllers/auth.controller.ts +1 -1
- package/registry/combos/nestjs-drizzle/shared/src/guards/auth.guard.ts +1 -1
- package/registry/combos/nestjs-drizzle/shared/src/{id.helper.ts → helpers/id.helper.ts} +6 -2
- package/registry/combos/{express-prisma/shared/src → nestjs-drizzle/shared/src/helpers}/pagination.ts +17 -3
- package/registry/combos/nestjs-drizzle/shared/src/repositories/oauth.repository.ts +2 -2
- package/registry/combos/nestjs-drizzle/shared/src/repositories/password-reset.repository.ts +8 -12
- package/registry/combos/nestjs-drizzle/shared/src/repositories/session.repository.ts +3 -3
- package/registry/combos/nestjs-drizzle/shared/src/repositories/two-factor.repository.ts +1 -1
- package/registry/combos/nestjs-drizzle/shared/src/request-context.ts +1 -1
- package/registry/combos/nestjs-drizzle/test/bootstrap.ts +1 -1
- package/registry/combos/nestjs-drizzle/test/prove-cycle.ts +1 -1
- package/registry/combos/nestjs-drizzle/variants/base/src/auth.module.ts +10 -6
- package/registry/combos/nestjs-drizzle/variants/base/src/controllers/admin.controller.ts +1 -1
- package/registry/combos/nestjs-drizzle/variants/base/src/guards/authz.guard.ts +2 -2
- package/registry/combos/nestjs-drizzle/variants/base/src/index.ts +9 -0
- package/registry/combos/nestjs-drizzle/variants/base/src/rbac.defaults.ts +58 -16
- package/registry/combos/nestjs-drizzle/variants/base/src/repositories/audit-log.repository.ts +3 -3
- package/registry/combos/nestjs-drizzle/variants/base/src/repositories/rbac.repository.ts +4 -4
- package/registry/combos/nestjs-drizzle/variants/base/src/seed.ts +76 -17
- package/registry/combos/nestjs-drizzle/variants/base/src/services/auth.service.ts +7 -9
- package/registry/combos/nestjs-drizzle/variants/base/test/variant-hooks.ts +167 -45
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/auth.module.ts +10 -6
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/controllers/admin.controller.ts +1 -1
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/controllers/workspace.controller.ts +1 -1
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/guards/authz.guard.ts +2 -2
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/index.ts +9 -0
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/rbac.defaults.ts +64 -18
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/repositories/audit-log.repository.ts +3 -3
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/repositories/rbac.repository.ts +4 -4
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/repositories/workspace.repository.ts +8 -10
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/seed.ts +171 -36
- package/registry/combos/nestjs-drizzle/variants/workspaces/src/services/auth.service.ts +7 -9
- package/registry/combos/nestjs-drizzle/variants/workspaces/test/variant-hooks.ts +539 -133
- package/registry/combos/nestjs-prisma/shared/src/{guards → ability}/ability.guard.ts +1 -1
- package/registry/combos/nestjs-prisma/shared/src/{ability.ts → ability/ability.ts} +8 -2
- package/registry/combos/nestjs-prisma/shared/src/{permission-cache.ts → cache/permission-cache.ts} +27 -10
- package/registry/combos/{nestjs-drizzle/shared/src → nestjs-prisma/shared/src/cache}/rate-limit.store.ts +4 -1
- package/registry/combos/nestjs-prisma/shared/src/{auth.config.ts → config/auth.config.ts} +1 -1
- package/registry/combos/nestjs-prisma/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
- package/registry/combos/nestjs-prisma/shared/src/controllers/auth.controller.ts +1 -1
- package/registry/combos/nestjs-prisma/shared/src/guards/auth.guard.ts +1 -1
- package/registry/combos/{express-prisma/shared/src → nestjs-prisma/shared/src/helpers}/id.helper.ts +6 -2
- package/registry/combos/nestjs-prisma/shared/src/{pagination.ts → helpers/pagination.ts} +17 -3
- package/registry/combos/nestjs-prisma/shared/src/repositories/oauth.repository.ts +1 -1
- package/registry/combos/nestjs-prisma/shared/src/repositories/password-reset.repository.ts +2 -4
- package/registry/combos/nestjs-prisma/shared/src/repositories/session.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/shared/src/request-context.ts +1 -1
- package/registry/combos/nestjs-prisma/test/bootstrap.ts +1 -1
- package/registry/combos/nestjs-prisma/test/prove-cycle.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/base/src/auth.module.ts +10 -6
- package/registry/combos/nestjs-prisma/variants/base/src/controllers/admin.controller.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/base/src/gateways/audit-log.gateway.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/base/src/guards/authz.guard.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/base/src/index.ts +9 -0
- package/registry/combos/nestjs-prisma/variants/base/src/{docs.ts → openapi/docs.ts} +23 -6
- package/registry/combos/nestjs-prisma/variants/base/src/rbac.defaults.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/base/src/repositories/audit-log.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/base/src/repositories/country.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/base/src/repositories/customer.repository.ts +6 -5
- package/registry/combos/nestjs-prisma/variants/base/src/repositories/language.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/base/src/repositories/rbac.repository.ts +3 -3
- package/registry/combos/nestjs-prisma/variants/base/src/seed.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/base/src/services/auth.service.ts +6 -8
- package/registry/combos/nestjs-prisma/variants/base/test/variant-hooks.ts +176 -47
- package/registry/combos/nestjs-prisma/variants/workspaces/src/auth.module.ts +10 -6
- package/registry/combos/nestjs-prisma/variants/workspaces/src/controllers/admin.controller.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/workspaces/src/controllers/workspace.controller.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/workspaces/src/guards/authz.guard.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/workspaces/src/index.ts +9 -0
- package/registry/combos/nestjs-prisma/variants/workspaces/src/rbac.defaults.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/audit-log.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/country.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/customer.repository.ts +6 -5
- package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/language.repository.ts +2 -2
- package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/rbac.repository.ts +3 -3
- package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/workspace.repository.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/workspaces/src/seed.ts +1 -1
- package/registry/combos/nestjs-prisma/variants/workspaces/src/services/auth.service.ts +6 -8
- package/registry/combos/nestjs-prisma/variants/workspaces/test/variant-hooks.ts +538 -134
- package/registry/combos/express-drizzle/variants/base/src/openapi-admin.ts +0 -565
- package/registry/combos/express-drizzle/variants/workspaces/src/openapi-admin.ts +0 -596
- package/registry/combos/express-prisma/variants/base/src/openapi-admin.ts +0 -569
- package/registry/combos/express-prisma/variants/workspaces/src/openapi-admin.ts +0 -601
- /package/registry/combos/express-drizzle/shared/src/{http-error.ts → errors/http-error.ts} +0 -0
- /package/registry/combos/express-prisma/shared/src/{http-error.ts → errors/http-error.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simple-auth-kit/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "simple-auth-kit add <combo> — copies registry source (backend combos, admin consoles, mobile apps) into a consumer repo, shadcn-CLI-style. Nothing is ever installed as a runtime dependency of the consumer.",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,11 @@
|
|
|
17
17
|
// database, no `(action, subject)` pairing to get wrong, and no conditions — which in turn means
|
|
18
18
|
// there is no such thing as a rule the route guard can only *partially* evaluate. What a slug
|
|
19
19
|
// means is decided entirely by which routes name it.
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
AbilityBuilder,
|
|
22
|
+
createMongoAbility,
|
|
23
|
+
type MongoAbility,
|
|
24
|
+
} from "@casl/ability";
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
27
|
* The subject every rule is written against. CASL needs one; this model does not use subjects, so
|
|
@@ -37,7 +41,9 @@ export type AppAbility = MongoAbility<[string, typeof ABILITY_SUBJECT]>;
|
|
|
37
41
|
* answer for "we could not resolve any permissions", and the same answer as "this user genuinely
|
|
38
42
|
* has none". There is no default-allow branch anywhere in this file.
|
|
39
43
|
*/
|
|
40
|
-
export function defineAbilitiesFor(
|
|
44
|
+
export function defineAbilitiesFor(
|
|
45
|
+
permissions: readonly string[] = [],
|
|
46
|
+
): AppAbility {
|
|
41
47
|
const { can, build } = new AbilityBuilder<AppAbility>(createMongoAbility);
|
|
42
48
|
for (const permission of permissions) can(permission, ABILITY_SUBJECT);
|
|
43
49
|
return build();
|
package/registry/combos/express-drizzle/shared/src/{permission-cache.ts → cache/permission-cache.ts}
RENAMED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
// reads this cache — so blocking a user or revoking a session cannot be defeated by a warm entry.
|
|
36
36
|
// Negative results are not cached either: "not a member of this workspace" is re-read every time,
|
|
37
37
|
// so being added to a workspace is effective immediately rather than after a TTL.
|
|
38
|
-
import type { AuthConfig } from "
|
|
38
|
+
import type { AuthConfig } from "../config/auth.config.js";
|
|
39
39
|
|
|
40
40
|
/** Every key this library writes starts here, so a shared Redis can be separated by prefix. */
|
|
41
41
|
export const CACHE_NAMESPACE = "simpleauthkit:authz";
|
|
@@ -66,7 +66,10 @@ export interface PermissionCacheStore {
|
|
|
66
66
|
*/
|
|
67
67
|
export class InMemoryPermissionCacheStore implements PermissionCacheStore {
|
|
68
68
|
readonly stats = { hits: 0, misses: 0, writes: 0 };
|
|
69
|
-
private readonly entries = new Map<
|
|
69
|
+
private readonly entries = new Map<
|
|
70
|
+
string,
|
|
71
|
+
{ value: string; expiresAt: number }
|
|
72
|
+
>();
|
|
70
73
|
|
|
71
74
|
async get(key: string): Promise<string | undefined> {
|
|
72
75
|
const entry = this.entries.get(key);
|
|
@@ -99,10 +102,14 @@ export class InMemoryPermissionCacheStore implements PermissionCacheStore {
|
|
|
99
102
|
|
|
100
103
|
async bump(key: string): Promise<number> {
|
|
101
104
|
const entry = this.entries.get(key);
|
|
102
|
-
const next =
|
|
105
|
+
const next =
|
|
106
|
+
Number(entry && entry.expiresAt > Date.now() ? entry.value : 0) + 1;
|
|
103
107
|
// Version counters outlive entries on purpose: a counter that expired back to 0 would make
|
|
104
108
|
// every superseded entry reachable again.
|
|
105
|
-
this.entries.set(key, {
|
|
109
|
+
this.entries.set(key, {
|
|
110
|
+
value: String(next),
|
|
111
|
+
expiresAt: Number.MAX_SAFE_INTEGER,
|
|
112
|
+
});
|
|
106
113
|
return next;
|
|
107
114
|
}
|
|
108
115
|
}
|
|
@@ -114,8 +121,10 @@ export class InMemoryPermissionCacheStore implements PermissionCacheStore {
|
|
|
114
121
|
* write is picked up when the entry expires (`permissionCacheTtlSeconds`), not immediately.
|
|
115
122
|
*/
|
|
116
123
|
export const POLICY_VERSION_KEY = `${CACHE_NAMESPACE}:policy-version`;
|
|
117
|
-
export const subjectVersionKey = (subject: string) =>
|
|
118
|
-
|
|
124
|
+
export const subjectVersionKey = (subject: string) =>
|
|
125
|
+
`${CACHE_NAMESPACE}:subject-version:${subject}`;
|
|
126
|
+
const entryKey = (subject: string, policy: string, subjectVersion: string) =>
|
|
127
|
+
`${CACHE_NAMESPACE}:entry:${subject}:p${policy}:s${subjectVersion}`;
|
|
119
128
|
|
|
120
129
|
/**
|
|
121
130
|
* Reads through to the database, once per (principal, policy version, subject version).
|
|
@@ -144,11 +153,17 @@ export class PermissionCache {
|
|
|
144
153
|
* @param subject the identity these permissions belong to — the cache key's principal
|
|
145
154
|
* @param load resolves from the database on a miss. Returning `null` is not cached.
|
|
146
155
|
*/
|
|
147
|
-
async resolve<T>(
|
|
156
|
+
async resolve<T>(
|
|
157
|
+
subject: string,
|
|
158
|
+
load: () => Promise<T | null>,
|
|
159
|
+
): Promise<T | null> {
|
|
148
160
|
const ttl = this.config.permissionCacheTtlSeconds;
|
|
149
161
|
if (ttl <= 0) return load(); // caching off; the semantics are identical, only the cost differs
|
|
150
162
|
|
|
151
|
-
const [policy = "0", version = "0"] = await this.store.getMany([
|
|
163
|
+
const [policy = "0", version = "0"] = await this.store.getMany([
|
|
164
|
+
POLICY_VERSION_KEY,
|
|
165
|
+
subjectVersionKey(subject),
|
|
166
|
+
]);
|
|
152
167
|
const key = entryKey(subject, policy, version);
|
|
153
168
|
|
|
154
169
|
const cached = await this.store.get(key);
|
|
@@ -160,7 +175,8 @@ export class PermissionCache {
|
|
|
160
175
|
const pending = (async () => {
|
|
161
176
|
const resolved = await load();
|
|
162
177
|
// A negative result is not written: see the module comment. Only a real answer is cached.
|
|
163
|
-
if (resolved !== null)
|
|
178
|
+
if (resolved !== null)
|
|
179
|
+
await this.store.set(key, JSON.stringify(resolved), ttl);
|
|
164
180
|
return resolved;
|
|
165
181
|
})();
|
|
166
182
|
|
package/registry/combos/express-drizzle/shared/src/{rate-limit.store.ts → cache/rate-limit.store.ts}
RENAMED
|
@@ -9,7 +9,10 @@ import type { RateLimitDeps } from "@/lib/auth/core/rate-limit.js";
|
|
|
9
9
|
* constructed directly instead of registered as an injectable provider.
|
|
10
10
|
*/
|
|
11
11
|
export class InMemoryRateLimitStore implements RateLimitDeps {
|
|
12
|
-
private readonly windows = new Map<
|
|
12
|
+
private readonly windows = new Map<
|
|
13
|
+
string,
|
|
14
|
+
{ count: number; resetAt: number }
|
|
15
|
+
>();
|
|
13
16
|
|
|
14
17
|
async increment(key: string, windowMs: number): Promise<number> {
|
|
15
18
|
const now = Date.now();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RateLimitDeps } from "@/lib/auth/core/rate-limit.js";
|
|
2
|
-
import type { PermissionCacheStore } from "
|
|
2
|
+
import type { PermissionCacheStore } from "../cache/permission-cache.js";
|
|
3
3
|
|
|
4
4
|
export interface GoogleOAuthCredentials {
|
|
5
5
|
clientId: string;
|
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
// Express has no DI container, so `createAuthApp` (see create-auth-app.ts) just builds the
|
|
8
8
|
// database and passes it to each class's constructor directly.
|
|
9
9
|
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
10
|
-
import type * as schema from "
|
|
10
|
+
import type * as schema from "../schema.js";
|
|
11
11
|
|
|
12
12
|
export type Database = NodePgDatabase<typeof schema>;
|
package/registry/combos/express-drizzle/shared/src/{key-provider.ts → config/key-provider.ts}
RENAMED
|
@@ -9,11 +9,15 @@ const MIN_SECRET_BYTES = 32; // 256 bits, HS256's own minimum
|
|
|
9
9
|
function loadSecret(): Uint8Array {
|
|
10
10
|
const raw = process.env[ENV_VAR];
|
|
11
11
|
if (!raw) {
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error(
|
|
13
|
+
`${ENV_VAR} is not set. Generate one and set it before starting the app — e.g.: openssl rand -base64 32`,
|
|
14
|
+
);
|
|
13
15
|
}
|
|
14
16
|
const secret = Buffer.from(raw, "base64");
|
|
15
17
|
if (secret.length < MIN_SECRET_BYTES) {
|
|
16
|
-
throw new Error(
|
|
18
|
+
throw new Error(
|
|
19
|
+
`${ENV_VAR} decodes to ${secret.length} bytes — needs at least ${MIN_SECRET_BYTES} (256 bits) for HS256.`,
|
|
20
|
+
);
|
|
17
21
|
}
|
|
18
22
|
return secret;
|
|
19
23
|
}
|
|
@@ -11,12 +11,16 @@ export function toId(value: string | number | bigint): bigint {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function toIdOrUndefined(
|
|
14
|
+
export function toIdOrUndefined(
|
|
15
|
+
value: string | number | bigint | null | undefined,
|
|
16
|
+
): bigint | undefined {
|
|
15
17
|
if (value === null || value === undefined || value === "") return undefined;
|
|
16
18
|
return toId(value);
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export function toIdOrNull(
|
|
21
|
+
export function toIdOrNull(
|
|
22
|
+
value: string | number | bigint | null | undefined,
|
|
23
|
+
): bigint | null {
|
|
20
24
|
if (value === null || value === undefined || value === "") return null;
|
|
21
25
|
return toId(value);
|
|
22
26
|
}
|
|
@@ -21,10 +21,24 @@ export function normalizePage(page: number | undefined): number {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export function normalizeLimit(limit: number | undefined): number {
|
|
24
|
-
return Math.min(
|
|
24
|
+
return Math.min(
|
|
25
|
+
limit && limit > 0 ? Math.floor(limit) : DEFAULT_PAGE_SIZE,
|
|
26
|
+
MAX_PAGE_SIZE,
|
|
27
|
+
);
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
export function buildPageMeta(
|
|
30
|
+
export function buildPageMeta(
|
|
31
|
+
page: number,
|
|
32
|
+
limit: number,
|
|
33
|
+
total: number,
|
|
34
|
+
): PageMeta {
|
|
28
35
|
const pageCount = Math.ceil(total / limit);
|
|
29
|
-
return {
|
|
36
|
+
return {
|
|
37
|
+
page,
|
|
38
|
+
limit,
|
|
39
|
+
total,
|
|
40
|
+
pageCount,
|
|
41
|
+
hasPreviousPage: page > 1,
|
|
42
|
+
hasNextPage: page < pageCount,
|
|
43
|
+
};
|
|
30
44
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NextFunction, Request, Response } from "express";
|
|
2
2
|
import { AuthCoreError } from "@/lib/auth/core/types.js";
|
|
3
|
-
import { HttpError } from "../http-error.js";
|
|
3
|
+
import { HttpError } from "../errors/http-error.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Replaces the reference combo's `AuthCoreErrorFilter` (a Nest global `@Catch` exception
|
|
@@ -30,13 +30,11 @@ export function authCoreErrorMiddleware(
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (err instanceof HttpError) {
|
|
33
|
-
res
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
message: err.message,
|
|
39
|
-
});
|
|
33
|
+
res.status(err.statusCode).json({
|
|
34
|
+
statusCode: err.statusCode,
|
|
35
|
+
code: err.name,
|
|
36
|
+
message: err.message,
|
|
37
|
+
});
|
|
40
38
|
return;
|
|
41
39
|
}
|
|
42
40
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NextFunction, Request, Response } from "express";
|
|
2
2
|
import { verifyAccessToken } from "@/lib/auth/core/token-service.js";
|
|
3
|
-
import { KeyProviderService } from "../key-provider.js";
|
|
3
|
+
import { KeyProviderService } from "../config/key-provider.js";
|
|
4
4
|
import "../request-context.js";
|
|
5
5
|
import { SessionRepository } from "../repositories/session.repository.js";
|
|
6
6
|
|
|
@@ -24,13 +24,11 @@ export function createAuthMiddleware(
|
|
|
24
24
|
): Promise<void> {
|
|
25
25
|
const header = req.headers["authorization"];
|
|
26
26
|
if (!header?.startsWith("Bearer ")) {
|
|
27
|
-
res
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
message: "missing bearer token",
|
|
33
|
-
});
|
|
27
|
+
res.status(401).json({
|
|
28
|
+
statusCode: 401,
|
|
29
|
+
code: "UNAUTHORIZED",
|
|
30
|
+
message: "missing bearer token",
|
|
31
|
+
});
|
|
34
32
|
return;
|
|
35
33
|
}
|
|
36
34
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// routes plus the fragment `openapi-admin.ts` contributes, and both of those import from here,
|
|
5
5
|
// so nothing imports in a circle. (`rbac.defaults.ts` below is a leaf too — it imports only a
|
|
6
6
|
// Prisma type — so naming the permission catalog here keeps that property.)
|
|
7
|
-
import type { PermissionSlug } from "
|
|
7
|
+
import type { PermissionSlug } from "../rbac.defaults.js";
|
|
8
8
|
|
|
9
9
|
/** One module's contribution to the assembled OpenAPI document — see openapi-spec.ts. */
|
|
10
10
|
export interface OpenApiFragment {
|
|
@@ -23,7 +23,11 @@ export interface OpenApiFragment {
|
|
|
23
23
|
export function errorResponse(description: string): Record<string, unknown> {
|
|
24
24
|
return {
|
|
25
25
|
description,
|
|
26
|
-
content: {
|
|
26
|
+
content: {
|
|
27
|
+
"application/json": {
|
|
28
|
+
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
29
|
+
},
|
|
30
|
+
},
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
|
|
@@ -44,6 +48,11 @@ export function requiresPermission(permission: PermissionSlug): string {
|
|
|
44
48
|
* self-checks, and anything about the scope the request named, where this deployment has one
|
|
45
49
|
* narrower than itself.
|
|
46
50
|
*/
|
|
47
|
-
export function missingPermission(
|
|
48
|
-
|
|
51
|
+
export function missingPermission(
|
|
52
|
+
permission: PermissionSlug,
|
|
53
|
+
...alsoWhen: string[]
|
|
54
|
+
): Record<string, unknown> {
|
|
55
|
+
return errorResponse(
|
|
56
|
+
[`Missing the \`${permission}\` permission`, ...alsoWhen].join(", or "),
|
|
57
|
+
);
|
|
49
58
|
}
|