@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
@@ -6,7 +6,7 @@ import {
6
6
  Injectable,
7
7
  } from "@nestjs/common";
8
8
  import { Reflector } from "@nestjs/core";
9
- import { ABILITY_SUBJECT } from "../ability.js";
9
+ import { ABILITY_SUBJECT } from "./ability.js";
10
10
  import { CHECK_ABILITY_KEY } from "../route-tiers.js";
11
11
 
12
12
  /**
@@ -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 { AbilityBuilder, createMongoAbility, type MongoAbility } from "@casl/ability";
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(permissions: readonly string[] = []): AppAbility {
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();
@@ -36,7 +36,7 @@
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
38
  import { Inject, Injectable } from "@nestjs/common";
39
- import { AUTH_CONFIG, AuthConfig } from "./auth.config.js";
39
+ import { AUTH_CONFIG, AuthConfig } from "../config/auth.config.js";
40
40
 
41
41
  /** DI token for the store. Provide your own to `AuthModule.forRoot({ permissionCacheStore })`. */
42
42
  export const PERMISSION_CACHE_STORE = Symbol("PERMISSION_CACHE_STORE");
@@ -70,7 +70,10 @@ export interface PermissionCacheStore {
70
70
  */
71
71
  export class InMemoryPermissionCacheStore implements PermissionCacheStore {
72
72
  readonly stats = { hits: 0, misses: 0, writes: 0 };
73
- private readonly entries = new Map<string, { value: string; expiresAt: number }>();
73
+ private readonly entries = new Map<
74
+ string,
75
+ { value: string; expiresAt: number }
76
+ >();
74
77
 
75
78
  async get(key: string): Promise<string | undefined> {
76
79
  const entry = this.entries.get(key);
@@ -103,10 +106,14 @@ export class InMemoryPermissionCacheStore implements PermissionCacheStore {
103
106
 
104
107
  async bump(key: string): Promise<number> {
105
108
  const entry = this.entries.get(key);
106
- const next = Number(entry && entry.expiresAt > Date.now() ? entry.value : 0) + 1;
109
+ const next =
110
+ Number(entry && entry.expiresAt > Date.now() ? entry.value : 0) + 1;
107
111
  // Version counters outlive entries on purpose: a counter that expired back to 0 would make
108
112
  // every superseded entry reachable again.
109
- this.entries.set(key, { value: String(next), expiresAt: Number.MAX_SAFE_INTEGER });
113
+ this.entries.set(key, {
114
+ value: String(next),
115
+ expiresAt: Number.MAX_SAFE_INTEGER,
116
+ });
110
117
  return next;
111
118
  }
112
119
  }
@@ -118,8 +125,10 @@ export class InMemoryPermissionCacheStore implements PermissionCacheStore {
118
125
  * write is picked up when the entry expires (`permissionCacheTtlSeconds`), not immediately.
119
126
  */
120
127
  export const POLICY_VERSION_KEY = `${CACHE_NAMESPACE}:policy-version`;
121
- export const subjectVersionKey = (subject: string) => `${CACHE_NAMESPACE}:subject-version:${subject}`;
122
- const entryKey = (subject: string, policy: string, subjectVersion: string) => `${CACHE_NAMESPACE}:entry:${subject}:p${policy}:s${subjectVersion}`;
128
+ export const subjectVersionKey = (subject: string) =>
129
+ `${CACHE_NAMESPACE}:subject-version:${subject}`;
130
+ const entryKey = (subject: string, policy: string, subjectVersion: string) =>
131
+ `${CACHE_NAMESPACE}:entry:${subject}:p${policy}:s${subjectVersion}`;
123
132
 
124
133
  /**
125
134
  * Reads through to the database, once per (principal, policy version, subject version).
@@ -131,7 +140,8 @@ const entryKey = (subject: string, policy: string, subjectVersion: string) => `$
131
140
  @Injectable()
132
141
  export class PermissionCache {
133
142
  constructor(
134
- @Inject(PERMISSION_CACHE_STORE) private readonly store: PermissionCacheStore,
143
+ @Inject(PERMISSION_CACHE_STORE)
144
+ private readonly store: PermissionCacheStore,
135
145
  @Inject(AUTH_CONFIG) private readonly config: AuthConfig,
136
146
  ) {}
137
147
 
@@ -149,11 +159,17 @@ export class PermissionCache {
149
159
  * @param subject the identity these permissions belong to — the cache key's principal
150
160
  * @param load resolves from the database on a miss. Returning `null` is not cached.
151
161
  */
152
- async resolve<T>(subject: string, load: () => Promise<T | null>): Promise<T | null> {
162
+ async resolve<T>(
163
+ subject: string,
164
+ load: () => Promise<T | null>,
165
+ ): Promise<T | null> {
153
166
  const ttl = this.config.permissionCacheTtlSeconds;
154
167
  if (ttl <= 0) return load(); // caching off; the semantics are identical, only the cost differs
155
168
 
156
- const [policy = "0", version = "0"] = await this.store.getMany([POLICY_VERSION_KEY, subjectVersionKey(subject)]);
169
+ const [policy = "0", version = "0"] = await this.store.getMany([
170
+ POLICY_VERSION_KEY,
171
+ subjectVersionKey(subject),
172
+ ]);
157
173
  const key = entryKey(subject, policy, version);
158
174
 
159
175
  const cached = await this.store.get(key);
@@ -165,7 +181,8 @@ export class PermissionCache {
165
181
  const pending = (async () => {
166
182
  const resolved = await load();
167
183
  // A negative result is not written: see the module comment. Only a real answer is cached.
168
- if (resolved !== null) await this.store.set(key, JSON.stringify(resolved), ttl);
184
+ if (resolved !== null)
185
+ await this.store.set(key, JSON.stringify(resolved), ttl);
169
186
  return resolved;
170
187
  })();
171
188
 
@@ -8,7 +8,10 @@ import type { RateLimitDeps } from "@/lib/auth/core/rate-limit.js";
8
8
  */
9
9
  @Injectable()
10
10
  export class InMemoryRateLimitStore implements RateLimitDeps {
11
- private readonly windows = new Map<string, { count: number; resetAt: number }>();
11
+ private readonly windows = new Map<
12
+ string,
13
+ { count: number; resetAt: number }
14
+ >();
12
15
 
13
16
  async increment(key: string, windowMs: number): Promise<number> {
14
17
  const now = Date.now();
@@ -1,4 +1,4 @@
1
- import type { PermissionCacheStore } from "./permission-cache.js";
1
+ import type { PermissionCacheStore } from "../cache/permission-cache.js";
2
2
  import type { RateLimitDeps } from "@/lib/auth/core/rate-limit.js";
3
3
 
4
4
  export const AUTH_CONFIG = Symbol("AUTH_CONFIG");
@@ -5,7 +5,7 @@
5
5
  // style, which is required (not just stylistic) for DI to keep working under esbuild-based
6
6
  // tooling like tsx that skips `emitDecoratorMetadata`'s runtime type reflection.
7
7
  import type { NodePgDatabase } from "drizzle-orm/node-postgres";
8
- import type * as schema from "./schema.js";
8
+ import type * as schema from "../schema.js";
9
9
 
10
10
  export const DRIZZLE_DB = Symbol("DRIZZLE_DB");
11
11
 
@@ -10,11 +10,15 @@ const MIN_SECRET_BYTES = 32; // 256 bits, HS256's own minimum
10
10
  function loadSecret(): Uint8Array {
11
11
  const raw = process.env[ENV_VAR];
12
12
  if (!raw) {
13
- throw new Error(`${ENV_VAR} is not set. Generate one and set it before starting the app — e.g.: openssl rand -base64 32`);
13
+ throw new Error(
14
+ `${ENV_VAR} is not set. Generate one and set it before starting the app — e.g.: openssl rand -base64 32`,
15
+ );
14
16
  }
15
17
  const secret = Buffer.from(raw, "base64");
16
18
  if (secret.length < MIN_SECRET_BYTES) {
17
- throw new Error(`${ENV_VAR} decodes to ${secret.length} bytes — needs at least ${MIN_SECRET_BYTES} (256 bits) for HS256.`);
19
+ throw new Error(
20
+ `${ENV_VAR} decodes to ${secret.length} bytes — needs at least ${MIN_SECRET_BYTES} (256 bits) for HS256.`,
21
+ );
18
22
  }
19
23
  return secret;
20
24
  }
@@ -22,7 +22,7 @@ import {
22
22
  ApiTags,
23
23
  } from "@nestjs/swagger";
24
24
  import type { Request } from "express";
25
- import { AUTH_CONFIG, AuthConfig } from "../auth.config.js";
25
+ import { AUTH_CONFIG, AuthConfig } from "../config/auth.config.js";
26
26
  import { AuthGuard } from "../guards/auth.guard.js";
27
27
  import { AuthService } from "../services/auth.service.js";
28
28
  import { AuthzGuard } from "../guards/authz.guard.js";
@@ -6,7 +6,7 @@ import {
6
6
  UnauthorizedException,
7
7
  } from "@nestjs/common";
8
8
  import { verifyAccessToken } from "@/lib/auth/core/token-service.js";
9
- import { KeyProviderService } from "../key-provider.js";
9
+ import { KeyProviderService } from "../config/key-provider.js";
10
10
  import "../request-context.js";
11
11
  import { SessionRepository } from "../repositories/session.repository.js";
12
12
 
@@ -11,12 +11,16 @@ export function toId(value: string | number | bigint): bigint {
11
11
  }
12
12
  }
13
13
 
14
- export function toIdOrUndefined(value: string | number | bigint | null | undefined): bigint | undefined {
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(value: string | number | bigint | null | undefined): bigint | null {
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(limit && limit > 0 ? Math.floor(limit) : DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);
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(page: number, limit: number, total: number): PageMeta {
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 { page, limit, total, pageCount, hasPreviousPage: page > 1, hasNextPage: page < pageCount };
36
+ return {
37
+ page,
38
+ limit,
39
+ total,
40
+ pageCount,
41
+ hasPreviousPage: page > 1,
42
+ hasNextPage: page < pageCount,
43
+ };
30
44
  }
@@ -1,9 +1,9 @@
1
1
  import { BadRequestException, Inject, Injectable } from "@nestjs/common";
2
2
  import { and, eq } from "drizzle-orm";
3
3
  import type { OAuthStoreDeps } from "@/lib/auth/core/oauth.js";
4
- import { DRIZZLE_DB, type Database } from "../db.js";
4
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
5
5
  import { oauthAccounts, users } from "../schema.js";
6
- import { toId } from "../id.helper.js";
6
+ import { toId } from "../helpers/id.helper.js";
7
7
 
8
8
  @Injectable()
9
9
  export class OAuthRepository implements OAuthStoreDeps {
@@ -1,9 +1,9 @@
1
1
  import { Inject, Injectable } from "@nestjs/common";
2
2
  import { eq } from "drizzle-orm";
3
3
  import type { PasswordResetStoreDeps } from "@/lib/auth/core/password-reset.js";
4
- import { DRIZZLE_DB, type Database } from "../db.js";
4
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
5
5
  import { passwordResetTokens, users } from "../schema.js";
6
- import { toId } from "../id.helper.js";
6
+ import { toId } from "../helpers/id.helper.js";
7
7
 
8
8
  @Injectable()
9
9
  export class PasswordResetRepository implements PasswordResetStoreDeps {
@@ -14,18 +14,14 @@ export class PasswordResetRepository implements PasswordResetStoreDeps {
14
14
  tokenHash: string;
15
15
  expiresAt: string;
16
16
  }): Promise<void> {
17
- await this.db
18
- .insert(passwordResetTokens)
19
- .values({
20
- userId: toId(input.userId),
21
- tokenHash: input.tokenHash,
22
- expiresAt: new Date(input.expiresAt),
23
- });
17
+ await this.db.insert(passwordResetTokens).values({
18
+ userId: toId(input.userId),
19
+ tokenHash: input.tokenHash,
20
+ expiresAt: new Date(input.expiresAt),
21
+ });
24
22
  }
25
23
 
26
- async findValidResetToken(
27
- tokenHash: string,
28
- ): Promise<{
24
+ async findValidResetToken(tokenHash: string): Promise<{
29
25
  userId: string;
30
26
  expiresAt: string;
31
27
  consumedAt: string | null;
@@ -8,10 +8,10 @@ import type {
8
8
  SessionRecord,
9
9
  } from "@/lib/auth/core/types.js";
10
10
  import { AuditLogRepository } from "./audit-log.repository.js";
11
- import { AUTH_CONFIG, AuthConfig } from "../auth.config.js";
12
- import { DRIZZLE_DB, type Database } from "../db.js";
11
+ import { AUTH_CONFIG, AuthConfig } from "../config/auth.config.js";
12
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
13
13
  import { denylistedAccessTokens, sessions } from "../schema.js";
14
- import { toId, toIdOrNull } from "../id.helper.js";
14
+ import { toId, toIdOrNull } from "../helpers/id.helper.js";
15
15
 
16
16
  function toSessionRecord(row: typeof sessions.$inferSelect): SessionRecord {
17
17
  return {
@@ -1,7 +1,7 @@
1
1
  import { Inject, Injectable } from "@nestjs/common";
2
2
  import { and, eq, isNull } from "drizzle-orm";
3
3
  import { verifyBackupCode } from "@/lib/auth/core/two-factor.js";
4
- import { DRIZZLE_DB, type Database } from "../db.js";
4
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
5
5
  import { twoFactorBackupCodes } from "../schema.js";
6
6
 
7
7
  // Takes bigint directly, not string: every caller already has the user row's id in hand from
@@ -13,7 +13,7 @@
13
13
  // authorization was decided, only what it decided — see authz.guard.ts. Importing this module
14
14
  // for its side effect installs the Express `Request` augmentation.
15
15
  import type { AccessTokenClaims } from "@/lib/auth/core/types.js";
16
- import type { AppAbility } from "./ability.js";
16
+ import type { AppAbility } from "./ability/ability.js";
17
17
  import type { AuthzContext } from "./guards/authz.guard.js";
18
18
 
19
19
  declare module "express" {
@@ -2,7 +2,7 @@ import "reflect-metadata";
2
2
  import { Module } from "@nestjs/common";
3
3
  import { NestFactory } from "@nestjs/core";
4
4
  import { AuthModule } from "../src/auth.module.js";
5
- import { InMemoryPermissionCacheStore } from "../src/permission-cache.js";
5
+ import { InMemoryPermissionCacheStore } from "../src/cache/permission-cache.js";
6
6
 
7
7
  // No mailer is wired up for the proof, so this stands in for one — prove-cycle.ts reads the
8
8
  // raw token back out of here the same way a test inbox would, to exercise the reset flow.
@@ -11,7 +11,7 @@ import "dotenv/config";
11
11
  import { randomUUID } from "node:crypto";
12
12
  import { Get } from "@nestjs/common";
13
13
  import { generateTotpCode } from "@/lib/auth/core/two-factor.js";
14
- import { ABILITY_SUBJECT, defineAbilitiesFor } from "../src/ability.js";
14
+ import { ABILITY_SUBJECT, defineAbilitiesFor } from "../src/ability/ability.js";
15
15
  import { AuthController } from "../src/controllers/auth.controller.js";
16
16
  import { bootstrap, capturedResetTokens } from "./bootstrap.js";
17
17
  import {
@@ -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 } 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";
@@ -23,7 +23,7 @@ import {
23
23
  ApiTags,
24
24
  } from "@nestjs/swagger";
25
25
  import type { Request } from "express";
26
- import { AbilityGuard } from "../guards/ability.guard.js";
26
+ import { AbilityGuard } from "../ability/ability.guard.js";
27
27
  import { AuthGuard } from "../guards/auth.guard.js";
28
28
  import { AuthService } from "../services/auth.service.js";
29
29
  import { AuthzGuard } from "../guards/authz.guard.js";
@@ -4,8 +4,8 @@ import {
4
4
  Inject,
5
5
  Injectable,
6
6
  } from "@nestjs/common";
7
- import { defineAbilitiesFor } from "../ability.js";
8
- import { PermissionCache } from "../permission-cache.js";
7
+ import { defineAbilitiesFor } from "../ability/ability.js";
8
+ import { PermissionCache } from "../cache/permission-cache.js";
9
9
  import { RbacRepository } from "../repositories/rbac.repository.js";
10
10
 
11
11
  /**
@@ -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";
@@ -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": { displayName: "List users", description: "GET /auth/admin/users", group: "Users", order: 1 },
48
- "users:block": { displayName: "Block and unblock users", description: "POST /auth/admin/users/:userId/block, .../unblock", group: "Users", order: 2 },
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: "Edit a user's profile or delete their account — PATCH /auth/admin/users/:userId, DELETE /auth/admin/users/:userId",
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: "Create, edit, or delete roles and say what they carry — POST/PATCH/DELETE /auth/admin/roles(/:roleId), POST /auth/admin/roles/:roleId/permissions",
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: "Assign and revoke a user's roles — POST /auth/admin/users/:userId/roles, .../roles/:roleSlug/revoke",
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": { displayName: "Read the permission catalog", description: "GET /auth/admin/permissions", group: "Permissions", order: 1 },
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: "Create a permission, rename it, or deactivate it — POST /auth/admin/permissions. The authority that defines all the others.",
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: "Grant and revoke a permission straight to a user, bypassing roles — POST /auth/admin/users/:userId/permissions, .../permissions/:slug/revoke",
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": { displayName: "Read the audit log", description: "GET /auth/admin/audit-log", group: "Audit", order: 1 },
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(PERMISSION_CATALOG) as PermissionSlug[];
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[] = [...new Set(PERMISSION_SLUGS.map((slug) => PERMISSION_CATALOG[slug].group))];
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 {
@@ -177,12 +206,17 @@ export async function provisionDefaultRoles(db: RbacWriter): Promise<void> {
177
206
  displayName: PERMISSION_CATALOG[slug].displayName,
178
207
  description: PERMISSION_CATALOG[slug].description,
179
208
  group: PERMISSION_CATALOG[slug].group,
180
- groupOrder: PERMISSION_GROUP_ORDER.indexOf(PERMISSION_CATALOG[slug].group),
209
+ groupOrder: PERMISSION_GROUP_ORDER.indexOf(
210
+ PERMISSION_CATALOG[slug].group,
211
+ ),
181
212
  order: PERMISSION_CATALOG[slug].order,
182
213
  })),
183
214
  )
184
215
  .onConflictDoNothing({ target: permissions.slug });
185
- const permissionRows = await db.select({ id: permissions.id, slug: permissions.slug }).from(permissions).where(inArray(permissions.slug, PERMISSION_SLUGS));
216
+ const permissionRows = await db
217
+ .select({ id: permissions.id, slug: permissions.slug })
218
+ .from(permissions)
219
+ .where(inArray(permissions.slug, PERMISSION_SLUGS));
186
220
  const permissionId = new Map(permissionRows.map((p) => [p.slug, p.id]));
187
221
 
188
222
  await db
@@ -210,9 +244,17 @@ export async function provisionDefaultRoles(db: RbacWriter): Promise<void> {
210
244
  const seedBySlug = new Map(DEFAULT_ROLES.map((role) => [role.slug, role]));
211
245
 
212
246
  const pairs = roleRows.flatMap((role) =>
213
- (seedBySlug.get(role.slug)?.permissions ?? []).map((slug) => ({ roleId: role.id, permissionId: permissionId.get(slug)! })),
247
+ (seedBySlug.get(role.slug)?.permissions ?? []).map((slug) => ({
248
+ roleId: role.id,
249
+ permissionId: permissionId.get(slug)!,
250
+ })),
214
251
  );
215
252
  if (pairs.length) {
216
- await db.insert(permissionRole).values(pairs).onConflictDoNothing({ target: [permissionRole.permissionId, permissionRole.roleId] });
253
+ await db
254
+ .insert(permissionRole)
255
+ .values(pairs)
256
+ .onConflictDoNothing({
257
+ target: [permissionRole.permissionId, permissionRole.roleId],
258
+ });
217
259
  }
218
260
  }
@@ -1,15 +1,15 @@
1
1
  import { Inject, Injectable } from "@nestjs/common";
2
2
  import { and, count, desc, eq, gte, lte, type SQL } from "drizzle-orm";
3
3
  import type { AuditEvent } from "@/lib/auth/core/types.js";
4
- import { DRIZZLE_DB, type Database } from "../db.js";
4
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
5
5
  import {
6
6
  buildPageMeta,
7
7
  normalizeLimit,
8
8
  normalizePage,
9
9
  type Paginated,
10
- } from "../pagination.js";
10
+ } from "../helpers/pagination.js";
11
11
  import { auditLogs } from "../schema.js";
12
- import { toIdOrNull, toIdOrUndefined } from "../id.helper.js";
12
+ import { toIdOrNull, toIdOrUndefined } from "../helpers/id.helper.js";
13
13
 
14
14
  export interface AuditLogEntry {
15
15
  id: string;
@@ -15,14 +15,14 @@ import {
15
15
  type SQL,
16
16
  } from "drizzle-orm";
17
17
  import { resolvePermissions } from "@/lib/auth/core/rbac.js";
18
- import { DRIZZLE_DB, type Database } from "../db.js";
18
+ import { DRIZZLE_DB, type Database } from "../config/db.js";
19
19
  import {
20
20
  buildPageMeta,
21
21
  normalizeLimit,
22
22
  normalizePage,
23
23
  type Paginated,
24
- } from "../pagination.js";
25
- import { PermissionCache } from "../permission-cache.js";
24
+ } from "../helpers/pagination.js";
25
+ import { PermissionCache } from "../cache/permission-cache.js";
26
26
  import {
27
27
  permissionRole,
28
28
  permissionUser,
@@ -31,7 +31,7 @@ import {
31
31
  roles,
32
32
  users,
33
33
  } from "../schema.js";
34
- import { toId, toIdOrNull } from "../id.helper.js";
34
+ import { toId, toIdOrNull } from "../helpers/id.helper.js";
35
35
 
36
36
  export interface UserSummary {
37
37
  id: string;