@simple-auth-kit/cli 1.5.0 → 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/lib/copy.ts +1 -1
- 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 +5 -5
- 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/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/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 +5 -5
- 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/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/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 +9 -5
- 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/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/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 +9 -5
- 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/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/services/auth.service.ts +6 -8
- package/registry/combos/nestjs-prisma/variants/workspaces/test/variant-hooks.ts +538 -134
- package/simple-auth-kit.ts +13 -9
- 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
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
// Callers: `src/seed.ts` (`npm run seed`, the only bootstrap in this variant) and
|
|
23
23
|
// `variants/base/test/variant-hooks.ts`.
|
|
24
24
|
import { inArray } from "drizzle-orm";
|
|
25
|
-
import type { Database } from "./db.js";
|
|
25
|
+
import type { Database } from "./config/db.js";
|
|
26
26
|
import { permissionRole, permissions, roles } from "./schema.js";
|
|
27
27
|
|
|
28
28
|
/** The display metadata a seeded permission carries. `group`/`order` exist so an admin console can render a stable matrix. */
|
|
@@ -44,40 +44,65 @@ export interface PermissionSeed {
|
|
|
44
44
|
* evaluate.
|
|
45
45
|
*/
|
|
46
46
|
export const PERMISSION_CATALOG = {
|
|
47
|
-
"users:read": {
|
|
48
|
-
|
|
47
|
+
"users:read": {
|
|
48
|
+
displayName: "List users",
|
|
49
|
+
description: "GET /auth/admin/users",
|
|
50
|
+
group: "Users",
|
|
51
|
+
order: 1,
|
|
52
|
+
},
|
|
53
|
+
"users:block": {
|
|
54
|
+
displayName: "Block and unblock users",
|
|
55
|
+
description: "POST /auth/admin/users/:userId/block, .../unblock",
|
|
56
|
+
group: "Users",
|
|
57
|
+
order: 2,
|
|
58
|
+
},
|
|
49
59
|
"users:manage": {
|
|
50
60
|
displayName: "Edit and delete users",
|
|
51
|
-
description:
|
|
61
|
+
description:
|
|
62
|
+
"Edit a user's profile or delete their account — PATCH /auth/admin/users/:userId, DELETE /auth/admin/users/:userId",
|
|
52
63
|
group: "Users",
|
|
53
64
|
order: 3,
|
|
54
65
|
},
|
|
55
66
|
"roles:manage": {
|
|
56
67
|
displayName: "Define roles",
|
|
57
|
-
description:
|
|
68
|
+
description:
|
|
69
|
+
"Create, edit, or delete roles and say what they carry — POST/PATCH/DELETE /auth/admin/roles(/:roleId), POST /auth/admin/roles/:roleId/permissions",
|
|
58
70
|
group: "Roles",
|
|
59
71
|
order: 1,
|
|
60
72
|
},
|
|
61
73
|
"roles:assign": {
|
|
62
74
|
displayName: "Assign roles",
|
|
63
|
-
description:
|
|
75
|
+
description:
|
|
76
|
+
"Assign and revoke a user's roles — POST /auth/admin/users/:userId/roles, .../roles/:roleSlug/revoke",
|
|
64
77
|
group: "Roles",
|
|
65
78
|
order: 2,
|
|
66
79
|
},
|
|
67
|
-
"permissions:read": {
|
|
80
|
+
"permissions:read": {
|
|
81
|
+
displayName: "Read the permission catalog",
|
|
82
|
+
description: "GET /auth/admin/permissions",
|
|
83
|
+
group: "Permissions",
|
|
84
|
+
order: 1,
|
|
85
|
+
},
|
|
68
86
|
"permissions:define": {
|
|
69
87
|
displayName: "Define permissions",
|
|
70
|
-
description:
|
|
88
|
+
description:
|
|
89
|
+
"Create a permission, rename it, or deactivate it — POST /auth/admin/permissions. The authority that defines all the others.",
|
|
71
90
|
group: "Permissions",
|
|
72
91
|
order: 2,
|
|
73
92
|
},
|
|
74
93
|
"permissions:grant": {
|
|
75
94
|
displayName: "Grant permissions directly",
|
|
76
|
-
description:
|
|
95
|
+
description:
|
|
96
|
+
"Grant and revoke a permission straight to a user, bypassing roles — POST /auth/admin/users/:userId/permissions, .../permissions/:slug/revoke",
|
|
77
97
|
group: "Permissions",
|
|
78
98
|
order: 3,
|
|
79
99
|
},
|
|
80
|
-
"audit-log:read": {
|
|
100
|
+
"audit-log:read": {
|
|
101
|
+
displayName: "Read the audit log",
|
|
102
|
+
description: "GET /auth/admin/audit-log",
|
|
103
|
+
group: "Audit",
|
|
104
|
+
order: 1,
|
|
105
|
+
},
|
|
81
106
|
} as const satisfies Record<string, PermissionSeed>;
|
|
82
107
|
|
|
83
108
|
/**
|
|
@@ -89,10 +114,14 @@ export const PERMISSION_CATALOG = {
|
|
|
89
114
|
*/
|
|
90
115
|
export type PermissionSlug = keyof typeof PERMISSION_CATALOG;
|
|
91
116
|
|
|
92
|
-
export const PERMISSION_SLUGS = Object.keys(
|
|
117
|
+
export const PERMISSION_SLUGS = Object.keys(
|
|
118
|
+
PERMISSION_CATALOG,
|
|
119
|
+
) as PermissionSlug[];
|
|
93
120
|
|
|
94
121
|
/** Groups, in the order an admin console should render them. Derived from the catalog so it cannot drift from it. */
|
|
95
|
-
export const PERMISSION_GROUP_ORDER: string[] = [
|
|
122
|
+
export const PERMISSION_GROUP_ORDER: string[] = [
|
|
123
|
+
...new Set(PERMISSION_SLUGS.map((slug) => PERMISSION_CATALOG[slug].group)),
|
|
124
|
+
];
|
|
96
125
|
|
|
97
126
|
/** The display metadata a seeded role carries, plus what it starts out granting. */
|
|
98
127
|
export interface RoleSeed {
|
|
@@ -127,7 +156,8 @@ export const DEFAULT_ROLES: readonly RoleSeed[] = [
|
|
|
127
156
|
{
|
|
128
157
|
slug: "superadmin",
|
|
129
158
|
displayName: "Super Admin",
|
|
130
|
-
description:
|
|
159
|
+
description:
|
|
160
|
+
"Carries every permission in the catalog — same authority as admin, held by the seeded super_admin account (see SEED_SUPERADMIN_* in seed.ts).",
|
|
131
161
|
isDefault: false,
|
|
132
162
|
order: 1,
|
|
133
163
|
permissions: PERMISSION_SLUGS,
|
|
@@ -177,12 +207,17 @@ export async function provisionDefaultRoles(db: RbacWriter): Promise<void> {
|
|
|
177
207
|
displayName: PERMISSION_CATALOG[slug].displayName,
|
|
178
208
|
description: PERMISSION_CATALOG[slug].description,
|
|
179
209
|
group: PERMISSION_CATALOG[slug].group,
|
|
180
|
-
groupOrder: PERMISSION_GROUP_ORDER.indexOf(
|
|
210
|
+
groupOrder: PERMISSION_GROUP_ORDER.indexOf(
|
|
211
|
+
PERMISSION_CATALOG[slug].group,
|
|
212
|
+
),
|
|
181
213
|
order: PERMISSION_CATALOG[slug].order,
|
|
182
214
|
})),
|
|
183
215
|
)
|
|
184
216
|
.onConflictDoNothing({ target: permissions.slug });
|
|
185
|
-
const permissionRows = await db
|
|
217
|
+
const permissionRows = await db
|
|
218
|
+
.select({ id: permissions.id, slug: permissions.slug })
|
|
219
|
+
.from(permissions)
|
|
220
|
+
.where(inArray(permissions.slug, PERMISSION_SLUGS));
|
|
186
221
|
const permissionId = new Map(permissionRows.map((p) => [p.slug, p.id]));
|
|
187
222
|
|
|
188
223
|
await db
|
|
@@ -210,9 +245,17 @@ export async function provisionDefaultRoles(db: RbacWriter): Promise<void> {
|
|
|
210
245
|
const seedBySlug = new Map(DEFAULT_ROLES.map((role) => [role.slug, role]));
|
|
211
246
|
|
|
212
247
|
const pairs = roleRows.flatMap((role) =>
|
|
213
|
-
(seedBySlug.get(role.slug)?.permissions ?? []).map((slug) => ({
|
|
248
|
+
(seedBySlug.get(role.slug)?.permissions ?? []).map((slug) => ({
|
|
249
|
+
roleId: role.id,
|
|
250
|
+
permissionId: permissionId.get(slug)!,
|
|
251
|
+
})),
|
|
214
252
|
);
|
|
215
253
|
if (pairs.length) {
|
|
216
|
-
await db
|
|
254
|
+
await db
|
|
255
|
+
.insert(permissionRole)
|
|
256
|
+
.values(pairs)
|
|
257
|
+
.onConflictDoNothing({
|
|
258
|
+
target: [permissionRole.permissionId, permissionRole.roleId],
|
|
259
|
+
});
|
|
217
260
|
}
|
|
218
261
|
}
|
package/registry/combos/express-drizzle/variants/base/src/repositories/audit-log.repository.ts
CHANGED
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
normalizeLimit,
|
|
7
7
|
normalizePage,
|
|
8
8
|
type Paginated,
|
|
9
|
-
} from "../pagination.js";
|
|
9
|
+
} from "../helpers/pagination.js";
|
|
10
10
|
import * as schema from "../schema.js";
|
|
11
|
-
import { toIdOrNull, toIdOrUndefined } from "../id.helper.js";
|
|
11
|
+
import { toIdOrNull, toIdOrUndefined } from "../helpers/id.helper.js";
|
|
12
12
|
|
|
13
13
|
export interface AuditLogEntry {
|
|
14
14
|
id: string;
|
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
type SQL,
|
|
10
10
|
} from "drizzle-orm";
|
|
11
11
|
import { resolvePermissions } from "@/lib/auth/core/rbac.js";
|
|
12
|
-
import type { Database } from "../db.js";
|
|
12
|
+
import type { Database } from "../config/db.js";
|
|
13
13
|
import {
|
|
14
14
|
buildPageMeta,
|
|
15
15
|
normalizeLimit,
|
|
16
16
|
normalizePage,
|
|
17
17
|
type Paginated,
|
|
18
|
-
} from "../pagination.js";
|
|
19
|
-
import { PermissionCache } from "../permission-cache.js";
|
|
18
|
+
} from "../helpers/pagination.js";
|
|
19
|
+
import { PermissionCache } from "../cache/permission-cache.js";
|
|
20
20
|
import {
|
|
21
21
|
permissionRole,
|
|
22
22
|
permissionUser,
|
|
@@ -25,8 +25,8 @@ import {
|
|
|
25
25
|
roles,
|
|
26
26
|
users,
|
|
27
27
|
} from "../schema.js";
|
|
28
|
-
import { HttpError } from "../http-error.js";
|
|
29
|
-
import { toId, toIdOrNull } from "../id.helper.js";
|
|
28
|
+
import { HttpError } from "../errors/http-error.js";
|
|
29
|
+
import { toId, toIdOrNull } from "../helpers/id.helper.js";
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Every column the `users` table has, except the two secrets (`passwordHash`, `twoFactorSecret`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NextFunction, Request, RequestHandler, Response } from "express";
|
|
2
2
|
import { AuthService } from "../services/auth.service.js";
|
|
3
|
-
import { HttpError } from "../http-error.js";
|
|
3
|
+
import { HttpError } from "../errors/http-error.js";
|
|
4
4
|
import {
|
|
5
5
|
ability,
|
|
6
6
|
createTieredRouter,
|
|
@@ -54,15 +54,13 @@ export function createAdminRouter(deps: AdminRouterDeps): RequestHandler {
|
|
|
54
54
|
string,
|
|
55
55
|
string | undefined
|
|
56
56
|
>;
|
|
57
|
-
res
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}),
|
|
65
|
-
);
|
|
57
|
+
res.status(200).json(
|
|
58
|
+
await auth.listUsers({
|
|
59
|
+
search,
|
|
60
|
+
page: page ? Number(page) : undefined,
|
|
61
|
+
limit: limit ? Number(limit) : undefined,
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
66
64
|
} catch (err) {
|
|
67
65
|
next(err);
|
|
68
66
|
}
|
|
@@ -179,18 +177,16 @@ export function createAdminRouter(deps: AdminRouterDeps): RequestHandler {
|
|
|
179
177
|
try {
|
|
180
178
|
const { userId, action, since, until, page, limit } =
|
|
181
179
|
req.query as Record<string, string | undefined>;
|
|
182
|
-
res
|
|
183
|
-
.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}),
|
|
193
|
-
);
|
|
180
|
+
res.status(200).json(
|
|
181
|
+
await auth.listAuditLog({
|
|
182
|
+
userId,
|
|
183
|
+
action,
|
|
184
|
+
since,
|
|
185
|
+
until,
|
|
186
|
+
page: page ? Number(page) : undefined,
|
|
187
|
+
limit: limit ? Number(limit) : undefined,
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
194
190
|
} catch (err) {
|
|
195
191
|
next(err);
|
|
196
192
|
}
|
|
@@ -24,14 +24,23 @@ import { eq, inArray, notInArray } from "drizzle-orm";
|
|
|
24
24
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
25
25
|
import { Pool } from "pg";
|
|
26
26
|
import { hashPassword } from "@/lib/auth/core/crypto.js";
|
|
27
|
-
import type { Database } from "./db.js";
|
|
28
|
-
import {
|
|
27
|
+
import type { Database } from "./config/db.js";
|
|
28
|
+
import {
|
|
29
|
+
DEFAULT_ROLES,
|
|
30
|
+
PERMISSION_SLUGS,
|
|
31
|
+
SEED_ADMIN_ROLES,
|
|
32
|
+
SEED_SUPERADMIN_ROLES,
|
|
33
|
+
provisionDefaultRoles,
|
|
34
|
+
} from "./rbac.defaults.js";
|
|
29
35
|
import * as schema from "./schema.js";
|
|
30
36
|
import { permissions, roleUser, roles, users } from "./schema.js";
|
|
31
37
|
|
|
32
38
|
function requireEnv(name: string): string {
|
|
33
39
|
const value = process.env[name];
|
|
34
|
-
if (!value)
|
|
40
|
+
if (!value)
|
|
41
|
+
throw new Error(
|
|
42
|
+
`${name} is not set — the seeder cannot reach the database without it`,
|
|
43
|
+
);
|
|
35
44
|
return value;
|
|
36
45
|
}
|
|
37
46
|
|
|
@@ -39,7 +48,10 @@ function requireEnv(name: string): string {
|
|
|
39
48
|
async function seedRbacDefaults(db: Database): Promise<void> {
|
|
40
49
|
await provisionDefaultRoles(db);
|
|
41
50
|
console.log(`permissions: ${PERMISSION_SLUGS.length} slug(s) in the catalog`);
|
|
42
|
-
for (const role of DEFAULT_ROLES)
|
|
51
|
+
for (const role of DEFAULT_ROLES)
|
|
52
|
+
console.log(
|
|
53
|
+
`role "${role.slug}": ${role.permissions.length} permission(s)${role.isDefault ? " (signup default)" : ""}`,
|
|
54
|
+
);
|
|
43
55
|
|
|
44
56
|
// Slugs that exist in the database but not in this build's catalog. They are not an error —
|
|
45
57
|
// `POST /auth/admin/permissions` exists so a deployment can define its own, and a grant can
|
|
@@ -49,9 +61,18 @@ async function seedRbacDefaults(db: Database): Promise<void> {
|
|
|
49
61
|
.select({ slug: permissions.slug })
|
|
50
62
|
.from(permissions)
|
|
51
63
|
.where(notInArray(permissions.slug, PERMISSION_SLUGS));
|
|
52
|
-
if (unknown.length)
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
if (unknown.length)
|
|
65
|
+
console.log(
|
|
66
|
+
`permissions: ${unknown.length} slug(s) outside this build's catalog (no route names them): ${unknown.map((r) => r.slug).join(", ")}`,
|
|
67
|
+
);
|
|
68
|
+
const inactive = await db
|
|
69
|
+
.select({ slug: permissions.slug })
|
|
70
|
+
.from(permissions)
|
|
71
|
+
.where(eq(permissions.isActive, false));
|
|
72
|
+
if (inactive.length)
|
|
73
|
+
console.log(
|
|
74
|
+
`permissions: ${inactive.length} deactivated, granting nothing: ${inactive.map((r) => r.slug).join(", ")}`,
|
|
75
|
+
);
|
|
55
76
|
}
|
|
56
77
|
|
|
57
78
|
/** Roles are global here, so administrative authority is a property of the user row itself. */
|
|
@@ -59,15 +80,32 @@ async function seedAdminUser(db: Database): Promise<void> {
|
|
|
59
80
|
const email = process.env["SEED_ADMIN_EMAIL"];
|
|
60
81
|
const password = process.env["SEED_ADMIN_PASSWORD"];
|
|
61
82
|
if (!email || !password) {
|
|
62
|
-
console.log(
|
|
83
|
+
console.log(
|
|
84
|
+
"admin: skipped — set SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD to create one (there is no default password)",
|
|
85
|
+
);
|
|
63
86
|
return;
|
|
64
87
|
}
|
|
65
88
|
|
|
66
89
|
// Their password may have been changed since; rewriting it here would silently reset it.
|
|
67
|
-
const [existing] = await db
|
|
90
|
+
const [existing] = await db
|
|
91
|
+
.select({ id: users.id })
|
|
92
|
+
.from(users)
|
|
93
|
+
.where(eq(users.email, email))
|
|
94
|
+
.limit(1);
|
|
68
95
|
// Hashed by the same function signup uses, so the seeded admin can actually log in.
|
|
69
|
-
const user =
|
|
70
|
-
|
|
96
|
+
const user =
|
|
97
|
+
existing ??
|
|
98
|
+
(
|
|
99
|
+
await db
|
|
100
|
+
.insert(users)
|
|
101
|
+
.values({ email, passwordHash: await hashPassword(password) })
|
|
102
|
+
.returning({ id: users.id })
|
|
103
|
+
)[0];
|
|
104
|
+
console.log(
|
|
105
|
+
existing
|
|
106
|
+
? `admin: ${email} already exists — password left unchanged`
|
|
107
|
+
: `admin: created ${email}`,
|
|
108
|
+
);
|
|
71
109
|
|
|
72
110
|
const adminRoles = await db
|
|
73
111
|
.select({ id: roles.id, slug: roles.slug })
|
|
@@ -87,16 +125,33 @@ async function seedSuperAdminUser(db: Database): Promise<void> {
|
|
|
87
125
|
const email = process.env["SEED_SUPERADMIN_EMAIL"];
|
|
88
126
|
const password = process.env["SEED_SUPERADMIN_PASSWORD"];
|
|
89
127
|
if (!email || !password) {
|
|
90
|
-
console.log(
|
|
128
|
+
console.log(
|
|
129
|
+
"super admin: skipped — set SEED_SUPERADMIN_EMAIL and SEED_SUPERADMIN_PASSWORD to create one (there is no default password)",
|
|
130
|
+
);
|
|
91
131
|
return;
|
|
92
132
|
}
|
|
93
133
|
const username = process.env["SEED_SUPERADMIN_USERNAME"] || undefined;
|
|
94
134
|
|
|
95
135
|
// Their password may have been changed since; rewriting it here would silently reset it.
|
|
96
|
-
const [existing] = await db
|
|
136
|
+
const [existing] = await db
|
|
137
|
+
.select({ id: users.id })
|
|
138
|
+
.from(users)
|
|
139
|
+
.where(eq(users.email, email))
|
|
140
|
+
.limit(1);
|
|
97
141
|
// Hashed by the same function signup uses, so the seeded super admin can actually log in.
|
|
98
|
-
const user =
|
|
99
|
-
|
|
142
|
+
const user =
|
|
143
|
+
existing ??
|
|
144
|
+
(
|
|
145
|
+
await db
|
|
146
|
+
.insert(users)
|
|
147
|
+
.values({ email, username, passwordHash: await hashPassword(password) })
|
|
148
|
+
.returning({ id: users.id })
|
|
149
|
+
)[0];
|
|
150
|
+
console.log(
|
|
151
|
+
existing
|
|
152
|
+
? `super admin: ${email} already exists — password left unchanged`
|
|
153
|
+
: `super admin: created ${email}${username ? ` (username ${username})` : ""}`,
|
|
154
|
+
);
|
|
100
155
|
|
|
101
156
|
const superAdminRoles = await db
|
|
102
157
|
.select({ id: roles.id, slug: roles.slug })
|
|
@@ -105,10 +160,14 @@ async function seedSuperAdminUser(db: Database): Promise<void> {
|
|
|
105
160
|
if (superAdminRoles.length) {
|
|
106
161
|
await db
|
|
107
162
|
.insert(roleUser)
|
|
108
|
-
.values(
|
|
163
|
+
.values(
|
|
164
|
+
superAdminRoles.map((role) => ({ userId: user.id, roleId: role.id })),
|
|
165
|
+
)
|
|
109
166
|
.onConflictDoNothing({ target: [roleUser.userId, roleUser.roleId] });
|
|
110
167
|
}
|
|
111
|
-
console.log(
|
|
168
|
+
console.log(
|
|
169
|
+
`super admin: holds roles ${superAdminRoles.map((r) => r.slug).join(", ")}`,
|
|
170
|
+
);
|
|
112
171
|
}
|
|
113
172
|
|
|
114
173
|
async function main(): Promise<void> {
|
|
@@ -42,17 +42,17 @@ import {
|
|
|
42
42
|
generateTotpSecret,
|
|
43
43
|
verifyTotpCode,
|
|
44
44
|
} from "@/lib/auth/core/two-factor.js";
|
|
45
|
-
import type { AuthConfig } from "../auth.config.js";
|
|
46
|
-
import { HttpError } from "../http-error.js";
|
|
45
|
+
import type { AuthConfig } from "../config/auth.config.js";
|
|
46
|
+
import { HttpError } from "../errors/http-error.js";
|
|
47
47
|
import {
|
|
48
48
|
AuditLogEntry,
|
|
49
49
|
AuditLogListFilter,
|
|
50
50
|
AuditLogRepository,
|
|
51
51
|
toAuditLogEntry,
|
|
52
52
|
} from "../repositories/audit-log.repository.js";
|
|
53
|
-
import type { Paginated } from "../pagination.js";
|
|
54
|
-
import type { Database } from "../db.js";
|
|
55
|
-
import { KeyProviderService } from "../key-provider.js";
|
|
53
|
+
import type { Paginated } from "../helpers/pagination.js";
|
|
54
|
+
import type { Database } from "../config/db.js";
|
|
55
|
+
import { KeyProviderService } from "../config/key-provider.js";
|
|
56
56
|
import { OAuthRepository } from "../repositories/oauth.repository.js";
|
|
57
57
|
import { PasswordResetRepository } from "../repositories/password-reset.repository.js";
|
|
58
58
|
import type { Revoker } from "@/lib/auth/core/types.js";
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
import { sessions, users } from "../schema.js";
|
|
70
70
|
import { SessionRepository } from "../repositories/session.repository.js";
|
|
71
71
|
import { TwoFactorRepository } from "../repositories/two-factor.repository.js";
|
|
72
|
-
import { toId, toIdOrNull } from "../id.helper.js";
|
|
72
|
+
import { toId, toIdOrNull } from "../helpers/id.helper.js";
|
|
73
73
|
|
|
74
74
|
export interface AuthTokens {
|
|
75
75
|
accessToken: string;
|
|
@@ -472,9 +472,7 @@ export class AuthService {
|
|
|
472
472
|
return { twoFactorEnabled: user.twoFactorEnabled };
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
async listActiveSessions(
|
|
476
|
-
userId: string,
|
|
477
|
-
): Promise<
|
|
475
|
+
async listActiveSessions(userId: string): Promise<
|
|
478
476
|
Array<{
|
|
479
477
|
id: string;
|
|
480
478
|
createdAt: string;
|