@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.
Files changed (176) hide show
  1. package/lib/copy.ts +1 -1
  2. package/package.json +1 -1
  3. package/registry/combos/express-drizzle/shared/src/{ability.ts → ability/ability.ts} +8 -2
  4. package/registry/combos/express-drizzle/shared/src/{permission-cache.ts → cache/permission-cache.ts} +25 -9
  5. package/registry/combos/express-drizzle/shared/src/{rate-limit.store.ts → cache/rate-limit.store.ts} +4 -1
  6. package/registry/combos/{express-prisma/shared/src → express-drizzle/shared/src/config}/auth.config.ts +1 -1
  7. package/registry/combos/express-drizzle/shared/src/{db.ts → config/db.ts} +1 -1
  8. package/registry/combos/express-drizzle/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
  9. package/registry/combos/express-drizzle/shared/src/{id.helper.ts → helpers/id.helper.ts} +6 -2
  10. package/registry/combos/{nestjs-drizzle/shared/src → express-drizzle/shared/src/helpers}/pagination.ts +17 -3
  11. package/registry/combos/express-drizzle/shared/src/middleware/auth-core-error.middleware.ts +6 -8
  12. package/registry/combos/express-drizzle/shared/src/middleware/auth.middleware.ts +6 -8
  13. package/registry/combos/{express-prisma/shared/src → express-drizzle/shared/src/openapi}/openapi-fragment.ts +13 -4
  14. package/registry/combos/express-drizzle/shared/src/{openapi-spec.ts → openapi/openapi-spec.ts} +251 -52
  15. package/registry/combos/express-drizzle/shared/src/repositories/oauth.repository.ts +2 -2
  16. package/registry/combos/express-drizzle/shared/src/repositories/password-reset.repository.ts +2 -4
  17. package/registry/combos/express-drizzle/shared/src/repositories/session.repository.ts +3 -3
  18. package/registry/combos/express-drizzle/shared/src/request-context.ts +1 -1
  19. package/registry/combos/express-drizzle/shared/src/route-tiers.ts +52 -11
  20. package/registry/combos/express-drizzle/shared/src/routers/auth.router.ts +2 -2
  21. package/registry/combos/express-drizzle/test/bootstrap.ts +4 -2
  22. package/registry/combos/express-drizzle/test/prove-cycle.ts +1095 -308
  23. package/registry/combos/express-drizzle/variants/base/src/create-auth-app.ts +5 -5
  24. package/registry/combos/express-drizzle/variants/base/src/index.ts +8 -0
  25. package/registry/combos/express-drizzle/variants/base/src/middleware/authz.middleware.ts +2 -2
  26. package/registry/combos/express-drizzle/variants/base/src/openapi/openapi-admin.ts +1082 -0
  27. package/registry/combos/express-drizzle/variants/base/src/rbac.defaults.ts +60 -17
  28. package/registry/combos/express-drizzle/variants/base/src/repositories/audit-log.repository.ts +2 -2
  29. package/registry/combos/express-drizzle/variants/base/src/repositories/rbac.repository.ts +5 -5
  30. package/registry/combos/express-drizzle/variants/base/src/routers/admin.router.ts +18 -22
  31. package/registry/combos/express-drizzle/variants/base/src/seed.ts +76 -17
  32. package/registry/combos/express-drizzle/variants/base/src/services/auth.service.ts +7 -9
  33. package/registry/combos/express-drizzle/variants/base/test/variant-hooks.ts +167 -45
  34. package/registry/combos/express-drizzle/variants/workspaces/src/create-auth-app.ts +5 -5
  35. package/registry/combos/express-drizzle/variants/workspaces/src/index.ts +8 -0
  36. package/registry/combos/express-drizzle/variants/workspaces/src/middleware/authz.middleware.ts +3 -3
  37. package/registry/combos/express-drizzle/variants/workspaces/src/openapi/openapi-admin.ts +1176 -0
  38. package/registry/combos/express-drizzle/variants/workspaces/src/openapi-workspace.ts +1 -1
  39. package/registry/combos/express-drizzle/variants/workspaces/src/rbac.defaults.ts +66 -19
  40. package/registry/combos/express-drizzle/variants/workspaces/src/repositories/audit-log.repository.ts +2 -2
  41. package/registry/combos/express-drizzle/variants/workspaces/src/repositories/rbac.repository.ts +5 -5
  42. package/registry/combos/express-drizzle/variants/workspaces/src/repositories/workspace.repository.ts +9 -11
  43. package/registry/combos/express-drizzle/variants/workspaces/src/routers/admin.router.ts +18 -22
  44. package/registry/combos/express-drizzle/variants/workspaces/src/routers/workspace.router.ts +1 -1
  45. package/registry/combos/express-drizzle/variants/workspaces/src/seed.ts +168 -35
  46. package/registry/combos/express-drizzle/variants/workspaces/src/services/auth.service.ts +7 -9
  47. package/registry/combos/express-drizzle/variants/workspaces/test/variant-hooks.ts +539 -133
  48. package/registry/combos/express-prisma/shared/src/{ability.ts → ability/ability.ts} +8 -2
  49. package/registry/combos/express-prisma/shared/src/{permission-cache.ts → cache/permission-cache.ts} +25 -9
  50. package/registry/combos/express-prisma/shared/src/{rate-limit.store.ts → cache/rate-limit.store.ts} +4 -1
  51. package/registry/combos/{express-drizzle/shared/src → express-prisma/shared/src/config}/auth.config.ts +1 -1
  52. package/registry/combos/express-prisma/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
  53. package/registry/combos/{nestjs-prisma/shared/src → express-prisma/shared/src/helpers}/id.helper.ts +6 -2
  54. package/registry/combos/{express-drizzle/shared/src → express-prisma/shared/src/helpers}/pagination.ts +17 -3
  55. package/registry/combos/express-prisma/shared/src/middleware/auth-core-error.middleware.ts +6 -8
  56. package/registry/combos/express-prisma/shared/src/middleware/auth.middleware.ts +6 -8
  57. package/registry/combos/{express-drizzle/shared/src → express-prisma/shared/src/openapi}/openapi-fragment.ts +13 -4
  58. package/registry/combos/express-prisma/shared/src/{openapi-spec.ts → openapi/openapi-spec.ts} +313 -55
  59. package/registry/combos/express-prisma/shared/src/repositories/oauth.repository.ts +2 -2
  60. package/registry/combos/express-prisma/shared/src/repositories/password-reset.repository.ts +2 -4
  61. package/registry/combos/express-prisma/shared/src/repositories/session.repository.ts +2 -2
  62. package/registry/combos/express-prisma/shared/src/request-context.ts +1 -1
  63. package/registry/combos/express-prisma/shared/src/route-tiers.ts +52 -11
  64. package/registry/combos/express-prisma/shared/src/routers/auth.router.ts +2 -2
  65. package/registry/combos/express-prisma/test/bootstrap.ts +7 -3
  66. package/registry/combos/express-prisma/test/prove-cycle.ts +1095 -308
  67. package/registry/combos/express-prisma/variants/base/src/create-auth-app.ts +5 -5
  68. package/registry/combos/express-prisma/variants/base/src/index.ts +8 -0
  69. package/registry/combos/express-prisma/variants/base/src/middleware/authz.middleware.ts +2 -2
  70. package/registry/combos/express-prisma/variants/base/src/openapi/openapi-admin.ts +1102 -0
  71. package/registry/combos/express-prisma/variants/base/src/repositories/audit-log.repository.ts +2 -2
  72. package/registry/combos/express-prisma/variants/base/src/repositories/rbac.repository.ts +4 -4
  73. package/registry/combos/express-prisma/variants/base/src/routers/admin.router.ts +18 -22
  74. package/registry/combos/express-prisma/variants/base/src/services/auth.service.ts +6 -8
  75. package/registry/combos/express-prisma/variants/base/test/variant-hooks.ts +176 -47
  76. package/registry/combos/express-prisma/variants/workspaces/src/create-auth-app.ts +5 -5
  77. package/registry/combos/express-prisma/variants/workspaces/src/index.ts +8 -0
  78. package/registry/combos/express-prisma/variants/workspaces/src/middleware/authz.middleware.ts +3 -3
  79. package/registry/combos/express-prisma/variants/workspaces/src/openapi/openapi-admin.ts +1218 -0
  80. package/registry/combos/express-prisma/variants/workspaces/src/openapi-workspace.ts +1 -1
  81. package/registry/combos/express-prisma/variants/workspaces/src/repositories/audit-log.repository.ts +2 -2
  82. package/registry/combos/express-prisma/variants/workspaces/src/repositories/rbac.repository.ts +4 -4
  83. package/registry/combos/express-prisma/variants/workspaces/src/repositories/workspace.repository.ts +2 -2
  84. package/registry/combos/express-prisma/variants/workspaces/src/routers/admin.router.ts +18 -22
  85. package/registry/combos/express-prisma/variants/workspaces/src/routers/workspace.router.ts +1 -1
  86. package/registry/combos/express-prisma/variants/workspaces/src/services/auth.service.ts +6 -8
  87. package/registry/combos/express-prisma/variants/workspaces/test/variant-hooks.ts +538 -134
  88. package/registry/combos/nestjs-drizzle/shared/src/{guards → ability}/ability.guard.ts +1 -1
  89. package/registry/combos/nestjs-drizzle/shared/src/{ability.ts → ability/ability.ts} +8 -2
  90. package/registry/combos/nestjs-drizzle/shared/src/{permission-cache.ts → cache/permission-cache.ts} +27 -10
  91. package/registry/combos/{nestjs-prisma/shared/src → nestjs-drizzle/shared/src/cache}/rate-limit.store.ts +4 -1
  92. package/registry/combos/nestjs-drizzle/shared/src/{auth.config.ts → config/auth.config.ts} +1 -1
  93. package/registry/combos/nestjs-drizzle/shared/src/{db.ts → config/db.ts} +1 -1
  94. package/registry/combos/nestjs-drizzle/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
  95. package/registry/combos/nestjs-drizzle/shared/src/controllers/auth.controller.ts +1 -1
  96. package/registry/combos/nestjs-drizzle/shared/src/guards/auth.guard.ts +1 -1
  97. package/registry/combos/nestjs-drizzle/shared/src/{id.helper.ts → helpers/id.helper.ts} +6 -2
  98. package/registry/combos/{express-prisma/shared/src → nestjs-drizzle/shared/src/helpers}/pagination.ts +17 -3
  99. package/registry/combos/nestjs-drizzle/shared/src/repositories/oauth.repository.ts +2 -2
  100. package/registry/combos/nestjs-drizzle/shared/src/repositories/password-reset.repository.ts +8 -12
  101. package/registry/combos/nestjs-drizzle/shared/src/repositories/session.repository.ts +3 -3
  102. package/registry/combos/nestjs-drizzle/shared/src/repositories/two-factor.repository.ts +1 -1
  103. package/registry/combos/nestjs-drizzle/shared/src/request-context.ts +1 -1
  104. package/registry/combos/nestjs-drizzle/test/bootstrap.ts +1 -1
  105. package/registry/combos/nestjs-drizzle/test/prove-cycle.ts +1 -1
  106. package/registry/combos/nestjs-drizzle/variants/base/src/auth.module.ts +10 -6
  107. package/registry/combos/nestjs-drizzle/variants/base/src/controllers/admin.controller.ts +1 -1
  108. package/registry/combos/nestjs-drizzle/variants/base/src/guards/authz.guard.ts +2 -2
  109. package/registry/combos/nestjs-drizzle/variants/base/src/index.ts +9 -0
  110. package/registry/combos/nestjs-drizzle/variants/base/src/rbac.defaults.ts +58 -16
  111. package/registry/combos/nestjs-drizzle/variants/base/src/repositories/audit-log.repository.ts +3 -3
  112. package/registry/combos/nestjs-drizzle/variants/base/src/repositories/rbac.repository.ts +4 -4
  113. package/registry/combos/nestjs-drizzle/variants/base/src/seed.ts +76 -17
  114. package/registry/combos/nestjs-drizzle/variants/base/src/services/auth.service.ts +7 -9
  115. package/registry/combos/nestjs-drizzle/variants/base/test/variant-hooks.ts +167 -45
  116. package/registry/combos/nestjs-drizzle/variants/workspaces/src/auth.module.ts +10 -6
  117. package/registry/combos/nestjs-drizzle/variants/workspaces/src/controllers/admin.controller.ts +1 -1
  118. package/registry/combos/nestjs-drizzle/variants/workspaces/src/controllers/workspace.controller.ts +1 -1
  119. package/registry/combos/nestjs-drizzle/variants/workspaces/src/guards/authz.guard.ts +2 -2
  120. package/registry/combos/nestjs-drizzle/variants/workspaces/src/index.ts +9 -0
  121. package/registry/combos/nestjs-drizzle/variants/workspaces/src/rbac.defaults.ts +64 -18
  122. package/registry/combos/nestjs-drizzle/variants/workspaces/src/repositories/audit-log.repository.ts +3 -3
  123. package/registry/combos/nestjs-drizzle/variants/workspaces/src/repositories/rbac.repository.ts +4 -4
  124. package/registry/combos/nestjs-drizzle/variants/workspaces/src/repositories/workspace.repository.ts +8 -10
  125. package/registry/combos/nestjs-drizzle/variants/workspaces/src/seed.ts +171 -36
  126. package/registry/combos/nestjs-drizzle/variants/workspaces/src/services/auth.service.ts +7 -9
  127. package/registry/combos/nestjs-drizzle/variants/workspaces/test/variant-hooks.ts +539 -133
  128. package/registry/combos/nestjs-prisma/shared/src/{guards → ability}/ability.guard.ts +1 -1
  129. package/registry/combos/nestjs-prisma/shared/src/{ability.ts → ability/ability.ts} +8 -2
  130. package/registry/combos/nestjs-prisma/shared/src/{permission-cache.ts → cache/permission-cache.ts} +27 -10
  131. package/registry/combos/{nestjs-drizzle/shared/src → nestjs-prisma/shared/src/cache}/rate-limit.store.ts +4 -1
  132. package/registry/combos/nestjs-prisma/shared/src/{auth.config.ts → config/auth.config.ts} +1 -1
  133. package/registry/combos/nestjs-prisma/shared/src/{key-provider.ts → config/key-provider.ts} +6 -2
  134. package/registry/combos/nestjs-prisma/shared/src/controllers/auth.controller.ts +1 -1
  135. package/registry/combos/nestjs-prisma/shared/src/guards/auth.guard.ts +1 -1
  136. package/registry/combos/{express-prisma/shared/src → nestjs-prisma/shared/src/helpers}/id.helper.ts +6 -2
  137. package/registry/combos/nestjs-prisma/shared/src/{pagination.ts → helpers/pagination.ts} +17 -3
  138. package/registry/combos/nestjs-prisma/shared/src/repositories/oauth.repository.ts +1 -1
  139. package/registry/combos/nestjs-prisma/shared/src/repositories/password-reset.repository.ts +2 -4
  140. package/registry/combos/nestjs-prisma/shared/src/repositories/session.repository.ts +2 -2
  141. package/registry/combos/nestjs-prisma/shared/src/request-context.ts +1 -1
  142. package/registry/combos/nestjs-prisma/test/bootstrap.ts +1 -1
  143. package/registry/combos/nestjs-prisma/test/prove-cycle.ts +1 -1
  144. package/registry/combos/nestjs-prisma/variants/base/src/auth.module.ts +9 -5
  145. package/registry/combos/nestjs-prisma/variants/base/src/controllers/admin.controller.ts +1 -1
  146. package/registry/combos/nestjs-prisma/variants/base/src/gateways/audit-log.gateway.ts +1 -1
  147. package/registry/combos/nestjs-prisma/variants/base/src/guards/authz.guard.ts +2 -2
  148. package/registry/combos/nestjs-prisma/variants/base/src/index.ts +9 -0
  149. package/registry/combos/nestjs-prisma/variants/base/src/{docs.ts → openapi/docs.ts} +23 -6
  150. package/registry/combos/nestjs-prisma/variants/base/src/repositories/audit-log.repository.ts +2 -2
  151. package/registry/combos/nestjs-prisma/variants/base/src/repositories/country.repository.ts +2 -2
  152. package/registry/combos/nestjs-prisma/variants/base/src/repositories/customer.repository.ts +6 -5
  153. package/registry/combos/nestjs-prisma/variants/base/src/repositories/language.repository.ts +2 -2
  154. package/registry/combos/nestjs-prisma/variants/base/src/repositories/rbac.repository.ts +3 -3
  155. package/registry/combos/nestjs-prisma/variants/base/src/services/auth.service.ts +6 -8
  156. package/registry/combos/nestjs-prisma/variants/base/test/variant-hooks.ts +176 -47
  157. package/registry/combos/nestjs-prisma/variants/workspaces/src/auth.module.ts +9 -5
  158. package/registry/combos/nestjs-prisma/variants/workspaces/src/controllers/admin.controller.ts +1 -1
  159. package/registry/combos/nestjs-prisma/variants/workspaces/src/controllers/workspace.controller.ts +1 -1
  160. package/registry/combos/nestjs-prisma/variants/workspaces/src/guards/authz.guard.ts +2 -2
  161. package/registry/combos/nestjs-prisma/variants/workspaces/src/index.ts +9 -0
  162. package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/audit-log.repository.ts +2 -2
  163. package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/country.repository.ts +2 -2
  164. package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/customer.repository.ts +6 -5
  165. package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/language.repository.ts +2 -2
  166. package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/rbac.repository.ts +3 -3
  167. package/registry/combos/nestjs-prisma/variants/workspaces/src/repositories/workspace.repository.ts +1 -1
  168. package/registry/combos/nestjs-prisma/variants/workspaces/src/services/auth.service.ts +6 -8
  169. package/registry/combos/nestjs-prisma/variants/workspaces/test/variant-hooks.ts +538 -134
  170. package/simple-auth-kit.ts +13 -9
  171. package/registry/combos/express-drizzle/variants/base/src/openapi-admin.ts +0 -565
  172. package/registry/combos/express-drizzle/variants/workspaces/src/openapi-admin.ts +0 -596
  173. package/registry/combos/express-prisma/variants/base/src/openapi-admin.ts +0 -569
  174. package/registry/combos/express-prisma/variants/workspaces/src/openapi-admin.ts +0 -601
  175. /package/registry/combos/express-drizzle/shared/src/{http-error.ts → errors/http-error.ts} +0 -0
  176. /package/registry/combos/express-prisma/shared/src/{http-error.ts → errors/http-error.ts} +0 -0
@@ -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 { DEFAULT_ROLES, PERMISSION_SLUGS, SEED_ADMIN_ROLES, SEED_SUPERADMIN_ROLES, provisionDefaultRoles } from "./rbac.defaults.js";
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) throw new Error(`${name} is not set — the seeder cannot reach the database without it`);
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) console.log(`role "${role.slug}": ${role.permissions.length} permission(s)${role.isDefault ? " (signup default)" : ""}`);
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) console.log(`permissions: ${unknown.length} slug(s) outside this build's catalog (no route names them): ${unknown.map((r) => r.slug).join(", ")}`);
53
- const inactive = await db.select({ slug: permissions.slug }).from(permissions).where(eq(permissions.isActive, false));
54
- if (inactive.length) console.log(`permissions: ${inactive.length} deactivated, granting nothing: ${inactive.map((r) => r.slug).join(", ")}`);
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("admin: skipped — set SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD to create one (there is no default password)");
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.select({ id: users.id }).from(users).where(eq(users.email, email)).limit(1);
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 = existing ?? (await db.insert(users).values({ email, passwordHash: await hashPassword(password) }).returning({ id: users.id }))[0];
70
- console.log(existing ? `admin: ${email} already exists — password left unchanged` : `admin: created ${email}`);
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("super admin: skipped — set SEED_SUPERADMIN_EMAIL and SEED_SUPERADMIN_PASSWORD to create one (there is no default password)");
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.select({ id: users.id }).from(users).where(eq(users.email, email)).limit(1);
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 = existing ?? (await db.insert(users).values({ email, username, passwordHash: await hashPassword(password) }).returning({ id: users.id }))[0];
99
- console.log(existing ? `super admin: ${email} already exists — password left unchanged` : `super admin: created ${email}${username ? ` (username ${username})` : ""}`);
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(superAdminRoles.map((role) => ({ userId: user.id, roleId: role.id })))
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(`super admin: holds roles ${superAdminRoles.map((r) => r.slug).join(", ")}`);
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> {
@@ -52,19 +52,19 @@ import {
52
52
  generateTotpSecret,
53
53
  verifyTotpCode,
54
54
  } from "@/lib/auth/core/two-factor.js";
55
- import { AUTH_CONFIG, AuthConfig } from "../auth.config.js";
55
+ import { AUTH_CONFIG, AuthConfig } from "../config/auth.config.js";
56
56
  import {
57
57
  AuditLogEntry,
58
58
  AuditLogListFilter,
59
59
  AuditLogRepository,
60
60
  toAuditLogEntry,
61
61
  } from "../repositories/audit-log.repository.js";
62
- import type { Paginated } from "../pagination.js";
63
- import { DRIZZLE_DB, type Database } from "../db.js";
64
- import { KeyProviderService } from "../key-provider.js";
62
+ import type { Paginated } from "../helpers/pagination.js";
63
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
64
+ import { KeyProviderService } from "../config/key-provider.js";
65
65
  import { OAuthRepository } from "../repositories/oauth.repository.js";
66
66
  import { PasswordResetRepository } from "../repositories/password-reset.repository.js";
67
- import { RATE_LIMIT_STORE } from "../rate-limit.store.js";
67
+ import { RATE_LIMIT_STORE } from "../cache/rate-limit.store.js";
68
68
  import type { Revoker } from "@/lib/auth/core/types.js";
69
69
  import {
70
70
  PermissionInput,
@@ -79,7 +79,7 @@ import {
79
79
  import { sessions, users } from "../schema.js";
80
80
  import { SessionRepository } from "../repositories/session.repository.js";
81
81
  import { TwoFactorRepository } from "../repositories/two-factor.repository.js";
82
- import { toId, toIdOrNull } from "../id.helper.js";
82
+ import { toId, toIdOrNull } from "../helpers/id.helper.js";
83
83
 
84
84
  export interface AuthTokens {
85
85
  accessToken: string;
@@ -490,9 +490,7 @@ export class AuthService {
490
490
  return { twoFactorEnabled: user.twoFactorEnabled };
491
491
  }
492
492
 
493
- async listActiveSessions(
494
- userId: string,
495
- ): Promise<
493
+ async listActiveSessions(userId: string): Promise<
496
494
  Array<{
497
495
  id: string;
498
496
  createdAt: string;
@@ -7,14 +7,24 @@ import "dotenv/config";
7
7
  import { eq, inArray } from "drizzle-orm";
8
8
  import { drizzle } from "drizzle-orm/node-postgres";
9
9
  import { Pool } from "pg";
10
- import type { Database } from "../src/db.js";
11
- import { toId } from "../src/id.helper.js";
12
- import { POLICY_VERSION_KEY } from "../src/permission-cache.js";
13
- import { provisionDefaultRoles, SEED_ADMIN_ROLES } from "../src/rbac.defaults.js";
10
+ import type { Database } from "../src/config/db.js";
11
+ import { toId } from "../src/helpers/id.helper.js";
12
+ import { POLICY_VERSION_KEY } from "../src/cache/permission-cache.js";
13
+ import {
14
+ provisionDefaultRoles,
15
+ SEED_ADMIN_ROLES,
16
+ } from "../src/rbac.defaults.js";
14
17
  import * as schema from "../src/schema.js";
15
18
  import { permissions, roleUser, roles } from "../src/schema.js";
16
19
  import { permissionCacheStore } from "./bootstrap.js";
17
- import { renewingToken, type AdminSession, type AuthTokens, type Principal, type ProofContext, type VariantHooks } from "./harness.js";
20
+ import {
21
+ renewingToken,
22
+ type AdminSession,
23
+ type AuthTokens,
24
+ type Principal,
25
+ type ProofContext,
26
+ type VariantHooks,
27
+ } from "./harness.js";
18
28
 
19
29
  /** One short-lived pool per call, closed on the way out, so the proof process has no lingering handle to wait on. */
20
30
  async function withDb<T>(fn: (db: Database) => Promise<T>): Promise<T> {
@@ -32,7 +42,10 @@ let adminCredentials: { identifier: string; password: string } | undefined;
32
42
  export const hooks: VariantHooks = {
33
43
  variant: "base",
34
44
 
35
- async makeAdmin(ctx: ProofContext, principal: Principal): Promise<AdminSession> {
45
+ async makeAdmin(
46
+ ctx: ProofContext,
47
+ principal: Principal,
48
+ ): Promise<AdminSession> {
36
49
  // The role slug on its own confers nothing — no guard checks for the string "admin". Authority
37
50
  // comes from the permission_role rows behind it, and in this variant the seeder is the only
38
51
  // thing that writes them, so the hook does what `npm run seed` does: calls the same
@@ -46,24 +59,36 @@ export const hooks: VariantHooks = {
46
59
  .where(inArray(roles.slug, SEED_ADMIN_ROLES));
47
60
  await db
48
61
  .insert(roleUser)
49
- .values(adminRoles.map((role) => ({ userId: toId(principal.userId), roleId: role.id })))
62
+ .values(
63
+ adminRoles.map((role) => ({
64
+ userId: toId(principal.userId),
65
+ roleId: role.id,
66
+ })),
67
+ )
50
68
  .onConflictDoNothing({ target: [roleUser.userId, roleUser.roleId] });
51
69
  });
52
70
 
53
- adminCredentials = { identifier: principal.email, password: principal.password };
71
+ adminCredentials = {
72
+ identifier: principal.email,
73
+ password: principal.password,
74
+ };
54
75
  // Those writes went straight to the database, behind the running app's back, so nothing
55
76
  // bumped a version counter and the caller's already-cached (empty) permissions would still be
56
77
  // served. Bumping the policy counter is exactly what an out-of-band writer is supposed to do —
57
78
  // see permission-cache.ts. Logging in would not have helped: nothing about authorization is
58
79
  // in the token.
59
80
  await permissionCacheStore.bump(POLICY_VERSION_KEY);
60
- const login = await ctx.call("POST", "/auth/login", { body: { identifier: principal.email, password: principal.password } });
81
+ const login = await ctx.call("POST", "/auth/login", {
82
+ body: { identifier: principal.email, password: principal.password },
83
+ });
61
84
  const token = (login.body as AuthTokens).accessToken;
62
85
  ctx.assert(!!token, `the seeded admin can log in (got ${login.status})`);
63
86
  return {
64
87
  token,
65
88
  freshToken: renewingToken(async () => {
66
- const res = await ctx.call("POST", "/auth/login", { body: adminCredentials! });
89
+ const res = await ctx.call("POST", "/auth/login", {
90
+ body: adminCredentials!,
91
+ });
67
92
  return (res.body as AuthTokens).accessToken;
68
93
  }),
69
94
  };
@@ -73,16 +98,37 @@ export const hooks: VariantHooks = {
73
98
  // Nothing to do: admin endpoints operate on the whole deployment.
74
99
  },
75
100
 
76
- async proveVariantProperties(ctx: ProofContext, admin: AdminSession): Promise<void> {
77
- const listed = await ctx.call("GET", "/auth/admin/users", { token: await admin.freshToken() });
78
- ctx.assert(listed.status === 200, `admin can list every user in the deployment (got ${listed.status})`);
79
- ctx.assert(Array.isArray(listed.body?.items) && listed.body.items.length > 0, "the user list is non-empty");
101
+ async proveVariantProperties(
102
+ ctx: ProofContext,
103
+ admin: AdminSession,
104
+ ): Promise<void> {
105
+ const listed = await ctx.call("GET", "/auth/admin/users", {
106
+ token: await admin.freshToken(),
107
+ });
108
+ ctx.assert(
109
+ listed.status === 200,
110
+ `admin can list every user in the deployment (got ${listed.status})`,
111
+ );
112
+ ctx.assert(
113
+ Array.isArray(listed.body?.items) && listed.body.items.length > 0,
114
+ "the user list is non-empty",
115
+ );
80
116
 
81
- const workspaces = await ctx.call("GET", "/workspaces", { token: await admin.freshToken() });
82
- ctx.assert(workspaces.status === 404, `no workspace endpoints exist in this variant (got ${workspaces.status})`);
117
+ const workspaces = await ctx.call("GET", "/workspaces", {
118
+ token: await admin.freshToken(),
119
+ });
120
+ ctx.assert(
121
+ workspaces.status === 404,
122
+ `no workspace endpoints exist in this variant (got ${workspaces.status})`,
123
+ );
83
124
 
84
- const me = await ctx.call("GET", "/auth/me", { token: await admin.freshToken() });
85
- ctx.assert(me.body?.roles?.includes("admin"), "roles are global: they apply to every request this user makes");
125
+ const me = await ctx.call("GET", "/auth/me", {
126
+ token: await admin.freshToken(),
127
+ });
128
+ ctx.assert(
129
+ me.body?.roles?.includes("admin"),
130
+ "roles are global: they apply to every request this user makes",
131
+ );
86
132
 
87
133
  // --- authorization is not in the token, so a change lands on the next *request* ---
88
134
  //
@@ -96,24 +142,55 @@ export const hooks: VariantHooks = {
96
142
  const email = ctx.uniqueEmail("immediate");
97
143
  const password = "immediate-pw-12345";
98
144
  const tokens = await ctx.signup(email, password);
99
- const userId = (await ctx.call("GET", "/auth/me", { token: tokens.accessToken })).body.sub as string;
100
-
101
- const beforeGrant = await ctx.call("GET", "/auth/admin/users", { token: tokens.accessToken });
102
- ctx.assert(beforeGrant.status === 403, `a user with no grant is refused (got ${beforeGrant.status})`);
145
+ const userId = (
146
+ await ctx.call("GET", "/auth/me", { token: tokens.accessToken })
147
+ ).body.sub as string;
103
148
 
104
- const granted = await ctx.call("POST", `/auth/admin/users/${userId}/permissions`, { token: await admin.freshToken(), body: { permission: "users:read" } });
105
- ctx.assert(granted.status === 200 || granted.status === 201, `admin can grant a permission directly (got ${granted.status})`);
149
+ const beforeGrant = await ctx.call("GET", "/auth/admin/users", {
150
+ token: tokens.accessToken,
151
+ });
152
+ ctx.assert(
153
+ beforeGrant.status === 403,
154
+ `a user with no grant is refused (got ${beforeGrant.status})`,
155
+ );
106
156
 
107
- const afterGrant = await ctx.call("GET", "/auth/admin/users", { token: tokens.accessToken });
108
- ctx.assert(afterGrant.status === 200, `…and the grant is in effect on the very next request, on the token they already held (got ${afterGrant.status})`);
157
+ const granted = await ctx.call(
158
+ "POST",
159
+ `/auth/admin/users/${userId}/permissions`,
160
+ { token: await admin.freshToken(), body: { permission: "users:read" } },
161
+ );
162
+ ctx.assert(
163
+ granted.status === 200 || granted.status === 201,
164
+ `admin can grant a permission directly (got ${granted.status})`,
165
+ );
109
166
 
110
- const revoked = await ctx.call("POST", `/auth/admin/users/${userId}/permissions/${encodeURIComponent("users:read")}/revoke`, {
111
- token: await admin.freshToken(),
167
+ const afterGrant = await ctx.call("GET", "/auth/admin/users", {
168
+ token: tokens.accessToken,
112
169
  });
113
- ctx.assert(revoked.status === 200 || revoked.status === 201, `admin can revoke the direct grant (got ${revoked.status})`);
170
+ ctx.assert(
171
+ afterGrant.status === 200,
172
+ `…and the grant is in effect on the very next request, on the token they already held (got ${afterGrant.status})`,
173
+ );
114
174
 
115
- const afterRevoke = await ctx.call("GET", "/auth/admin/users", { token: tokens.accessToken });
116
- ctx.assert(afterRevoke.status === 403, `and the revocation lands on the very next request too, on the same token (got ${afterRevoke.status})`);
175
+ const revoked = await ctx.call(
176
+ "POST",
177
+ `/auth/admin/users/${userId}/permissions/${encodeURIComponent("users:read")}/revoke`,
178
+ {
179
+ token: await admin.freshToken(),
180
+ },
181
+ );
182
+ ctx.assert(
183
+ revoked.status === 200 || revoked.status === 201,
184
+ `admin can revoke the direct grant (got ${revoked.status})`,
185
+ );
186
+
187
+ const afterRevoke = await ctx.call("GET", "/auth/admin/users", {
188
+ token: tokens.accessToken,
189
+ });
190
+ ctx.assert(
191
+ afterRevoke.status === 403,
192
+ `and the revocation lands on the very next request too, on the same token (got ${afterRevoke.status})`,
193
+ );
117
194
 
118
195
  await proveTheCacheIsReal(ctx, admin, tokens.accessToken);
119
196
  await proveARawDatabaseEditChangesEnforcement(ctx, admin);
@@ -125,7 +202,11 @@ export const hooks: VariantHooks = {
125
202
  * app resolves through (`test/bootstrap.ts` hands it to `AuthModule.forRoot`), so "the second
126
203
  * request did not touch the database" is a measurement rather than a claim.
127
204
  */
128
- async function proveTheCacheIsReal(ctx: ProofContext, admin: AdminSession, token: string): Promise<void> {
205
+ async function proveTheCacheIsReal(
206
+ ctx: ProofContext,
207
+ admin: AdminSession,
208
+ token: string,
209
+ ): Promise<void> {
129
210
  const N = 8;
130
211
  await ctx.call("GET", "/auth/me", { token }); // warm, so the measurement is of the steady state
131
212
  const before = { ...permissionCacheStore.stats };
@@ -137,16 +218,27 @@ async function proveTheCacheIsReal(ctx: ProofContext, admin: AdminSession, token
137
218
  `${N} identical authorized requests resolve permissions 0 further times — all ${N} were cache hits (misses +${after.misses - before.misses}, hits +${after.hits - before.hits})`,
138
219
  );
139
220
 
140
- const userId = (await ctx.call("GET", "/auth/me", { token })).body.sub as string;
221
+ const userId = (await ctx.call("GET", "/auth/me", { token })).body
222
+ .sub as string;
141
223
  const beforeGrant = { ...permissionCacheStore.stats };
142
- await ctx.call("POST", `/auth/admin/users/${userId}/permissions`, { token: await admin.freshToken(), body: { permission: "probe:cache" } });
224
+ await ctx.call("POST", `/auth/admin/users/${userId}/permissions`, {
225
+ token: await admin.freshToken(),
226
+ body: { permission: "probe:cache" },
227
+ });
143
228
  const afterGrantCall = await ctx.call("GET", "/auth/me", { token });
144
229
  ctx.assert(
145
230
  permissionCacheStore.stats.misses > beforeGrant.misses,
146
231
  "a grant bumps this user's version counter, so the next request misses the cache and re-resolves rather than serving a stale entry",
147
232
  );
148
- ctx.assert((afterGrantCall.body?.permissions ?? []).includes("probe:cache"), "…and the freshly resolved answer contains the new permission");
149
- await ctx.call("POST", `/auth/admin/users/${userId}/permissions/${encodeURIComponent("probe:cache")}/revoke`, { token: await admin.freshToken() });
233
+ ctx.assert(
234
+ (afterGrantCall.body?.permissions ?? []).includes("probe:cache"),
235
+ "…and the freshly resolved answer contains the new permission",
236
+ );
237
+ await ctx.call(
238
+ "POST",
239
+ `/auth/admin/users/${userId}/permissions/${encodeURIComponent("probe:cache")}/revoke`,
240
+ { token: await admin.freshToken() },
241
+ );
150
242
  }
151
243
 
152
244
  /**
@@ -154,26 +246,56 @@ async function proveTheCacheIsReal(ctx: ProofContext, admin: AdminSession, token
154
246
  * doing the writing — this rules out any possibility that it is also doing something in memory.
155
247
  * A `psql` session would look exactly like this.
156
248
  */
157
- async function proveARawDatabaseEditChangesEnforcement(ctx: ProofContext, admin: AdminSession): Promise<void> {
249
+ async function proveARawDatabaseEditChangesEnforcement(
250
+ ctx: ProofContext,
251
+ admin: AdminSession,
252
+ ): Promise<void> {
158
253
  const email = ctx.uniqueEmail("rawedit");
159
254
  const tokens = await ctx.signup(email, "rawedit-pw-12345");
160
- const userId = (await ctx.call("GET", "/auth/me", { token: tokens.accessToken })).body.sub as string;
161
- await ctx.call("POST", `/auth/admin/users/${userId}/permissions`, { token: await admin.freshToken(), body: { permission: "audit-log:read" } });
162
- ctx.assert((await ctx.call("GET", "/auth/admin/audit-log", { token: tokens.accessToken })).status === 200, "a direct grant opens the audit log");
255
+ const userId = (
256
+ await ctx.call("GET", "/auth/me", { token: tokens.accessToken })
257
+ ).body.sub as string;
258
+ await ctx.call("POST", `/auth/admin/users/${userId}/permissions`, {
259
+ token: await admin.freshToken(),
260
+ body: { permission: "audit-log:read" },
261
+ });
262
+ ctx.assert(
263
+ (
264
+ await ctx.call("GET", "/auth/admin/audit-log", {
265
+ token: tokens.accessToken,
266
+ })
267
+ ).status === 200,
268
+ "a direct grant opens the audit log",
269
+ );
163
270
 
164
271
  const setActive = async (isActive: boolean) => {
165
272
  // Written straight to the table, with no code change and no redeploy. The bump that follows is
166
273
  // the out-of-band writer's half of the cache contract (permission-cache.ts) — without it the
167
274
  // edit would still land, but only once the cached entry expired.
168
- await withDb((db) => db.update(permissions).set({ isActive }).where(eq(permissions.slug, "audit-log:read")));
275
+ await withDb((db) =>
276
+ db
277
+ .update(permissions)
278
+ .set({ isActive })
279
+ .where(eq(permissions.slug, "audit-log:read")),
280
+ );
169
281
  await permissionCacheStore.bump(POLICY_VERSION_KEY);
170
282
  };
171
283
 
172
284
  await setActive(false);
173
- const denied = await ctx.call("GET", "/auth/admin/audit-log", { token: tokens.accessToken });
174
- ctx.assert(denied.status === 403, `a permission deactivated by a raw database write stops opening its route (got ${denied.status})`);
285
+ const denied = await ctx.call("GET", "/auth/admin/audit-log", {
286
+ token: tokens.accessToken,
287
+ });
288
+ ctx.assert(
289
+ denied.status === 403,
290
+ `a permission deactivated by a raw database write stops opening its route (got ${denied.status})`,
291
+ );
175
292
 
176
293
  await setActive(true);
177
- const restored = await ctx.call("GET", "/auth/admin/audit-log", { token: tokens.accessToken });
178
- ctx.assert(restored.status === 200, `…and reactivating it in the database opens the route again (got ${restored.status})`);
294
+ const restored = await ctx.call("GET", "/auth/admin/audit-log", {
295
+ token: tokens.accessToken,
296
+ });
297
+ ctx.assert(
298
+ restored.status === 200,
299
+ `…and reactivating it in the database opens the route again (got ${restored.status})`,
300
+ );
179
301
  }
@@ -2,28 +2,32 @@ import { Pool } from "pg";
2
2
  import { drizzle } from "drizzle-orm/node-postgres";
3
3
  import { DynamicModule, Module } from "@nestjs/common";
4
4
  import { APP_FILTER, APP_INTERCEPTOR } from "@nestjs/core";
5
- import { AbilityGuard } from "./guards/ability.guard.js";
5
+ import { AbilityGuard } from "./ability/ability.guard.js";
6
6
  import { AdminController } from "./controllers/admin.controller.js";
7
7
  import { AuditLogRepository } from "./repositories/audit-log.repository.js";
8
8
  import { AuthCoreErrorFilter } from "./filters/auth-core-error.filter.js";
9
- import { AUTH_CONFIG, AuthConfig, defaultAuthConfig } from "./auth.config.js";
9
+ import {
10
+ AUTH_CONFIG,
11
+ AuthConfig,
12
+ defaultAuthConfig,
13
+ } from "./config/auth.config.js";
10
14
  import { AuthController } from "./controllers/auth.controller.js";
11
15
  import { AuthGuard } from "./guards/auth.guard.js";
12
16
  import { AuthService } from "./services/auth.service.js";
13
17
  import { AuthzGuard, WorkspaceGuard } from "./guards/authz.guard.js";
14
- import { DRIZZLE_DB } from "./db.js";
15
- import { KeyProviderService } from "./key-provider.js";
18
+ import { DRIZZLE_DB } from "./config/db.js";
19
+ import { KeyProviderService } from "./config/key-provider.js";
16
20
  import { OAuthRepository } from "./repositories/oauth.repository.js";
17
21
  import { PasswordResetRepository } from "./repositories/password-reset.repository.js";
18
22
  import {
19
23
  InMemoryPermissionCacheStore,
20
24
  PERMISSION_CACHE_STORE,
21
25
  PermissionCache,
22
- } from "./permission-cache.js";
26
+ } from "./cache/permission-cache.js";
23
27
  import {
24
28
  InMemoryRateLimitStore,
25
29
  RATE_LIMIT_STORE,
26
- } from "./rate-limit.store.js";
30
+ } from "./cache/rate-limit.store.js";
27
31
  import { RbacRepository } from "./repositories/rbac.repository.js";
28
32
  import { ResponseInterceptor } from "./interceptors/response.interceptor.js";
29
33
  import { assertEveryRouteDeclaresATier } from "./route-tiers.js";
@@ -25,7 +25,7 @@ import {
25
25
  ApiTags,
26
26
  } from "@nestjs/swagger";
27
27
  import type { Request } from "express";
28
- import { AbilityGuard } from "../guards/ability.guard.js";
28
+ import { AbilityGuard } from "../ability/ability.guard.js";
29
29
  import { AuthGuard } from "../guards/auth.guard.js";
30
30
  import { AuthService } from "../services/auth.service.js";
31
31
  import { WORKSPACE_HEADER, WorkspaceGuard } from "../guards/authz.guard.js";
@@ -22,7 +22,7 @@ import {
22
22
  ApiTags,
23
23
  } from "@nestjs/swagger";
24
24
  import type { Request } from "express";
25
- import { AbilityGuard } from "../guards/ability.guard.js";
25
+ import { AbilityGuard } from "../ability/ability.guard.js";
26
26
  import { AuthGuard } from "../guards/auth.guard.js";
27
27
  import { WORKSPACE_HEADER, WorkspaceGuard } from "../guards/authz.guard.js";
28
28
  import { Authenticated, CheckAbility } from "../route-tiers.js";
@@ -5,8 +5,8 @@ import {
5
5
  Inject,
6
6
  Injectable,
7
7
  } from "@nestjs/common";
8
- import { defineAbilitiesFor } from "../ability.js";
9
- import { PermissionCache } from "../permission-cache.js";
8
+ import { defineAbilitiesFor } from "../ability/ability.js";
9
+ import { PermissionCache } from "../cache/permission-cache.js";
10
10
  import {
11
11
  memberCacheKey,
12
12
  RbacRepository,
@@ -0,0 +1,9 @@
1
+ export * from "./auth.module.js";
2
+
3
+ export * from "./route-tiers.js";
4
+
5
+ export * from "./guards/auth.guard.js";
6
+ export * from "./guards/authz.guard.js";
7
+
8
+ export * from "./ability/ability.js";
9
+ export * from "./ability/ability.guard.js";