@devxcrew/platform 0.1.2 → 0.1.6

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 (280) hide show
  1. package/README.md +7 -1
  2. package/dist/index.d.ts +6 -4
  3. package/dist/index.js +4 -2
  4. package/dist/modules/identity/audit/audit.controller.d.ts +17 -0
  5. package/dist/modules/identity/audit/audit.controller.js +12 -0
  6. package/dist/modules/identity/audit/audit.migration.d.ts +1 -0
  7. package/dist/modules/identity/audit/audit.migration.js +1 -0
  8. package/dist/modules/identity/audit/audit.provider.d.ts +24 -0
  9. package/dist/modules/identity/audit/audit.provider.js +14 -0
  10. package/dist/modules/identity/audit/audit.repository.d.ts +26 -0
  11. package/dist/modules/identity/audit/audit.repository.js +46 -0
  12. package/dist/modules/identity/audit/audit.routes.d.ts +5 -0
  13. package/dist/modules/identity/audit/audit.routes.js +2 -0
  14. package/dist/modules/identity/audit/audit.schema.d.ts +1 -0
  15. package/dist/modules/identity/audit/audit.schema.js +1 -0
  16. package/dist/modules/identity/audit/audit.seed.d.ts +1 -0
  17. package/dist/modules/identity/audit/audit.seed.js +1 -0
  18. package/dist/modules/identity/audit/audit.service.d.ts +23 -0
  19. package/dist/modules/identity/audit/audit.service.js +46 -0
  20. package/dist/modules/identity/audit/audit.types.d.ts +12 -0
  21. package/dist/modules/identity/audit/audit.types.js +1 -0
  22. package/dist/modules/identity/audit/index.d.ts +4 -0
  23. package/dist/modules/identity/audit/index.js +3 -0
  24. package/dist/modules/identity/{identity.administration-service.d.ts → composition/identity.composition.d.ts} +59 -27
  25. package/dist/modules/identity/composition/identity.composition.js +171 -0
  26. package/dist/modules/identity/composition/identity.seed.d.ts +3 -0
  27. package/dist/modules/identity/composition/identity.seed.js +16 -0
  28. package/dist/modules/identity/identity.controller.d.ts +8 -6
  29. package/dist/modules/identity/identity.controller.js +90 -70
  30. package/dist/modules/identity/identity.migration.d.ts +1 -2
  31. package/dist/modules/identity/identity.migration.js +1 -79
  32. package/dist/modules/identity/identity.provider.d.ts +39 -13
  33. package/dist/modules/identity/identity.provider.js +19 -73
  34. package/dist/modules/identity/identity.public-schemas.d.ts +9 -3
  35. package/dist/modules/identity/identity.public-schemas.js +9 -3
  36. package/dist/modules/identity/identity.repository.d.ts +1 -40
  37. package/dist/modules/identity/identity.repository.js +1 -196
  38. package/dist/modules/identity/identity.routes.d.ts +2 -5
  39. package/dist/modules/identity/identity.routes.js +3 -11
  40. package/dist/modules/identity/identity.schema.d.ts +1 -27
  41. package/dist/modules/identity/identity.schema.js +1 -34
  42. package/dist/modules/identity/identity.seed.d.ts +1 -3
  43. package/dist/modules/identity/identity.seed.js +1 -81
  44. package/dist/modules/identity/identity.service.d.ts +1 -32
  45. package/dist/modules/identity/identity.service.js +1 -83
  46. package/dist/modules/identity/identity.types.d.ts +13 -106
  47. package/dist/modules/identity/index.d.ts +18 -11
  48. package/dist/modules/identity/index.js +14 -8
  49. package/dist/modules/identity/{identity.administration-migration.js → legacy/identity.administration-migration.js} +3 -11
  50. package/dist/modules/identity/legacy/identity.migration.d.ts +2 -0
  51. package/dist/modules/identity/legacy/identity.migration.js +72 -0
  52. package/dist/modules/identity/organization/index.d.ts +6 -0
  53. package/dist/modules/identity/organization/index.js +5 -0
  54. package/dist/modules/identity/organization/organization.controller.d.ts +35 -0
  55. package/dist/modules/identity/organization/organization.controller.js +18 -0
  56. package/dist/modules/identity/organization/organization.migration.d.ts +1 -0
  57. package/dist/modules/identity/organization/organization.migration.js +1 -0
  58. package/dist/modules/identity/organization/organization.provider.d.ts +46 -0
  59. package/dist/modules/identity/organization/organization.provider.js +33 -0
  60. package/dist/modules/identity/organization/organization.repository.d.ts +58 -0
  61. package/dist/modules/identity/organization/organization.repository.js +101 -0
  62. package/dist/modules/identity/organization/organization.routes.d.ts +5 -0
  63. package/dist/modules/identity/organization/organization.routes.js +2 -0
  64. package/dist/modules/identity/organization/organization.schema.d.ts +11 -0
  65. package/dist/modules/identity/organization/organization.schema.js +18 -0
  66. package/dist/modules/identity/organization/organization.seed.d.ts +3 -0
  67. package/dist/modules/identity/organization/organization.seed.js +11 -0
  68. package/dist/modules/identity/organization/organization.service.d.ts +39 -0
  69. package/dist/modules/identity/organization/organization.service.js +55 -0
  70. package/dist/modules/identity/organization/organization.types.d.ts +19 -0
  71. package/dist/modules/identity/organization/organization.types.js +1 -0
  72. package/dist/modules/identity/permission/index.d.ts +9 -0
  73. package/dist/modules/identity/permission/index.js +6 -0
  74. package/dist/modules/identity/permission/permission.controller.d.ts +21 -0
  75. package/dist/modules/identity/permission/permission.controller.js +12 -0
  76. package/dist/modules/identity/{identity.permission-declarations-migration.js → permission/permission.declarations.migration.js} +9 -4
  77. package/dist/modules/identity/{identity.permission-labels-migration.js → permission/permission.labels.migration.js} +5 -2
  78. package/dist/modules/identity/permission/permission.migration.d.ts +2 -0
  79. package/dist/modules/identity/permission/permission.migration.js +2 -0
  80. package/dist/modules/identity/permission/permission.provider.d.ts +19 -0
  81. package/dist/modules/identity/permission/permission.provider.js +14 -0
  82. package/dist/modules/identity/permission/permission.repository.d.ts +51 -0
  83. package/dist/modules/identity/permission/permission.repository.js +84 -0
  84. package/dist/modules/identity/permission/permission.routes.d.ts +5 -0
  85. package/dist/modules/identity/permission/permission.routes.js +2 -0
  86. package/dist/modules/identity/permission/permission.schema.d.ts +14 -0
  87. package/dist/modules/identity/permission/permission.schema.js +29 -0
  88. package/dist/modules/identity/permission/permission.seed.d.ts +4 -0
  89. package/dist/modules/identity/permission/permission.seed.js +17 -0
  90. package/dist/modules/identity/permission/permission.service.d.ts +31 -0
  91. package/dist/modules/identity/permission/permission.service.js +77 -0
  92. package/dist/modules/identity/permission/permission.types.d.ts +15 -0
  93. package/dist/modules/identity/permission/permission.types.js +1 -0
  94. package/dist/modules/identity/role/index.d.ts +10 -0
  95. package/dist/modules/identity/role/index.js +6 -0
  96. package/dist/modules/identity/role/role.controller.d.ts +42 -0
  97. package/dist/modules/identity/role/role.controller.js +25 -0
  98. package/dist/modules/identity/{identity.roles-migration.js → role/role.migration.js} +5 -18
  99. package/dist/modules/identity/role/role.provider.d.ts +14 -0
  100. package/dist/modules/identity/role/role.provider.js +30 -0
  101. package/dist/modules/identity/role/role.repository.d.ts +38 -0
  102. package/dist/modules/identity/role/role.repository.js +46 -0
  103. package/dist/modules/identity/role/role.routes.d.ts +5 -0
  104. package/dist/modules/identity/role/role.routes.js +2 -0
  105. package/dist/modules/identity/role/role.schema.d.ts +16 -0
  106. package/dist/modules/identity/role/role.schema.js +27 -0
  107. package/dist/modules/identity/role/role.seed.d.ts +3 -0
  108. package/dist/modules/identity/role/role.seed.js +8 -0
  109. package/dist/modules/identity/role/role.service.d.ts +69 -0
  110. package/dist/modules/identity/role/role.service.js +192 -0
  111. package/dist/modules/identity/role/role.types.d.ts +17 -0
  112. package/dist/modules/identity/role/role.types.js +1 -0
  113. package/dist/modules/identity/role-permission/index.d.ts +6 -0
  114. package/dist/modules/identity/role-permission/index.js +4 -0
  115. package/dist/modules/identity/role-permission/role-permission.controller.d.ts +1 -0
  116. package/dist/modules/identity/role-permission/role-permission.controller.js +1 -0
  117. package/dist/modules/identity/role-permission/role-permission.migration.d.ts +1 -0
  118. package/dist/modules/identity/role-permission/role-permission.migration.js +1 -0
  119. package/dist/modules/identity/role-permission/role-permission.provider.d.ts +14 -0
  120. package/dist/modules/identity/role-permission/role-permission.provider.js +15 -0
  121. package/dist/modules/identity/role-permission/role-permission.repository.d.ts +12 -0
  122. package/dist/modules/identity/role-permission/role-permission.repository.js +51 -0
  123. package/dist/modules/identity/role-permission/role-permission.routes.d.ts +1 -0
  124. package/dist/modules/identity/role-permission/role-permission.routes.js +2 -0
  125. package/dist/modules/identity/role-permission/role-permission.schema.d.ts +2 -0
  126. package/dist/modules/identity/role-permission/role-permission.schema.js +3 -0
  127. package/dist/modules/identity/role-permission/role-permission.seed.d.ts +3 -0
  128. package/dist/modules/identity/role-permission/role-permission.seed.js +10 -0
  129. package/dist/modules/identity/role-permission/role-permission.service.d.ts +13 -0
  130. package/dist/modules/identity/role-permission/role-permission.service.js +35 -0
  131. package/dist/modules/identity/role-permission/role-permission.types.d.ts +12 -0
  132. package/dist/modules/identity/role-permission/role-permission.types.js +1 -0
  133. package/dist/modules/identity/session/index.d.ts +6 -0
  134. package/dist/modules/identity/session/index.js +5 -0
  135. package/dist/modules/identity/session/session.authentication.controller.d.ts +30 -0
  136. package/dist/modules/identity/session/session.authentication.controller.js +37 -0
  137. package/dist/modules/identity/session/session.controller.d.ts +18 -0
  138. package/dist/modules/identity/session/session.controller.js +15 -0
  139. package/dist/modules/identity/session/session.migration.d.ts +1 -0
  140. package/dist/modules/identity/session/session.migration.js +1 -0
  141. package/dist/modules/identity/session/session.provider.d.ts +34 -0
  142. package/dist/modules/identity/session/session.provider.js +23 -0
  143. package/dist/modules/identity/session/session.repository.d.ts +36 -0
  144. package/dist/modules/identity/session/session.repository.js +128 -0
  145. package/dist/modules/identity/session/session.routes.d.ts +27 -0
  146. package/dist/modules/identity/session/session.routes.js +13 -0
  147. package/dist/modules/identity/session/session.schema.d.ts +6 -0
  148. package/dist/modules/identity/session/session.schema.js +12 -0
  149. package/dist/modules/identity/session/session.seed.d.ts +1 -0
  150. package/dist/modules/identity/session/session.seed.js +1 -0
  151. package/dist/modules/identity/session/session.service.d.ts +20 -0
  152. package/dist/modules/identity/session/session.service.js +27 -0
  153. package/dist/modules/identity/session/session.types.d.ts +17 -0
  154. package/dist/modules/identity/session/session.types.js +1 -0
  155. package/dist/modules/identity/settings/index.d.ts +5 -0
  156. package/dist/modules/identity/settings/index.js +4 -0
  157. package/dist/modules/identity/settings/settings.controller.d.ts +35 -0
  158. package/dist/modules/identity/settings/settings.controller.js +18 -0
  159. package/dist/modules/identity/settings/settings.migration.d.ts +1 -0
  160. package/dist/modules/identity/settings/settings.migration.js +1 -0
  161. package/dist/modules/identity/settings/settings.provider.d.ts +35 -0
  162. package/dist/modules/identity/settings/settings.provider.js +14 -0
  163. package/dist/modules/identity/settings/settings.repository.d.ts +49 -0
  164. package/dist/modules/identity/settings/settings.repository.js +75 -0
  165. package/dist/modules/identity/settings/settings.routes.d.ts +1 -0
  166. package/dist/modules/identity/settings/settings.routes.js +7 -0
  167. package/dist/modules/identity/settings/settings.schema.d.ts +15 -0
  168. package/dist/modules/identity/settings/settings.schema.js +27 -0
  169. package/dist/modules/identity/settings/settings.seed.d.ts +1 -0
  170. package/dist/modules/identity/settings/settings.seed.js +1 -0
  171. package/dist/modules/identity/settings/settings.service.d.ts +40 -0
  172. package/dist/modules/identity/settings/settings.service.js +101 -0
  173. package/dist/modules/identity/settings/settings.types.d.ts +20 -0
  174. package/dist/modules/identity/settings/settings.types.js +1 -0
  175. package/dist/modules/identity/support/identity.schema.d.ts +8 -0
  176. package/dist/modules/identity/support/identity.schema.js +10 -0
  177. package/dist/modules/identity/support/pagination.d.ts +13 -0
  178. package/dist/modules/identity/support/pagination.js +27 -0
  179. package/dist/modules/identity/support/pagination.schema.d.ts +43 -0
  180. package/dist/modules/identity/support/pagination.schema.js +15 -0
  181. package/dist/modules/identity/support/resource-controller.d.ts +14 -0
  182. package/dist/modules/identity/support/resource-controller.js +1 -0
  183. package/dist/modules/identity/user/index.d.ts +13 -0
  184. package/dist/modules/identity/user/index.js +11 -0
  185. package/dist/modules/identity/user/user.administration.service.d.ts +59 -0
  186. package/dist/modules/identity/user/user.administration.service.js +159 -0
  187. package/dist/modules/identity/user/user.controller.d.ts +44 -0
  188. package/dist/modules/identity/user/user.controller.js +21 -0
  189. package/dist/modules/identity/user/user.lifecycle.controller.d.ts +58 -0
  190. package/dist/modules/identity/user/user.lifecycle.controller.js +27 -0
  191. package/dist/modules/identity/{identity.lifecycle-schema.js → user/user.lifecycle.schema.js} +5 -5
  192. package/dist/modules/identity/{identity.lifecycle-service.d.ts → user/user.lifecycle.service.d.ts} +8 -4
  193. package/dist/modules/identity/{identity.lifecycle-service.js → user/user.lifecycle.service.js} +66 -118
  194. package/dist/modules/identity/user/user.migration.d.ts +1 -0
  195. package/dist/modules/identity/user/user.migration.js +1 -0
  196. package/dist/modules/identity/{identity.password.js → user/user.password.js} +1 -1
  197. package/dist/modules/identity/user/user.provider.d.ts +80 -0
  198. package/dist/modules/identity/user/user.provider.js +22 -0
  199. package/dist/modules/identity/user/user.repository.d.ts +64 -0
  200. package/dist/modules/identity/user/user.repository.js +129 -0
  201. package/dist/modules/identity/user/user.routes.d.ts +12 -0
  202. package/dist/modules/identity/user/user.routes.js +9 -0
  203. package/dist/modules/identity/user/user.schema.d.ts +34 -0
  204. package/dist/modules/identity/user/user.schema.js +46 -0
  205. package/dist/modules/identity/user/user.seed.d.ts +14 -0
  206. package/dist/modules/identity/user/user.seed.js +47 -0
  207. package/dist/modules/identity/user/user.service.d.ts +33 -0
  208. package/dist/modules/identity/user/user.service.js +76 -0
  209. package/dist/modules/identity/user/user.types.d.ts +27 -0
  210. package/dist/modules/identity/user/user.types.js +1 -0
  211. package/dist/modules/identity/user-role/index.d.ts +8 -0
  212. package/dist/modules/identity/user-role/index.js +6 -0
  213. package/dist/modules/identity/user-role/user-role.controller.d.ts +42 -0
  214. package/dist/modules/identity/user-role/user-role.controller.js +21 -0
  215. package/dist/modules/identity/user-role/user-role.migration.d.ts +1 -0
  216. package/dist/modules/identity/user-role/user-role.migration.js +1 -0
  217. package/dist/modules/identity/user-role/user-role.policy.d.ts +3 -0
  218. package/dist/modules/identity/user-role/user-role.policy.js +25 -0
  219. package/dist/modules/identity/user-role/user-role.provider.d.ts +18 -0
  220. package/dist/modules/identity/user-role/user-role.provider.js +23 -0
  221. package/dist/modules/identity/user-role/user-role.repository.d.ts +34 -0
  222. package/dist/modules/identity/user-role/user-role.repository.js +87 -0
  223. package/dist/modules/identity/user-role/user-role.routes.d.ts +5 -0
  224. package/dist/modules/identity/user-role/user-role.routes.js +2 -0
  225. package/dist/modules/identity/user-role/user-role.schema.d.ts +14 -0
  226. package/dist/modules/identity/user-role/user-role.schema.js +25 -0
  227. package/dist/modules/identity/user-role/user-role.seed.d.ts +7 -0
  228. package/dist/modules/identity/user-role/user-role.seed.js +11 -0
  229. package/dist/modules/identity/user-role/user-role.service.d.ts +60 -0
  230. package/dist/modules/identity/user-role/user-role.service.js +216 -0
  231. package/dist/modules/identity/user-role/user-role.types.d.ts +12 -0
  232. package/dist/modules/identity/user-role/user-role.types.js +1 -0
  233. package/dist/modules/tenant/index.d.ts +6 -0
  234. package/dist/modules/tenant/index.js +5 -0
  235. package/dist/modules/tenant/tenant.command.d.ts +3 -0
  236. package/dist/modules/tenant/tenant.command.js +43 -0
  237. package/dist/modules/tenant/tenant.controller.d.ts +4 -0
  238. package/dist/modules/tenant/tenant.controller.js +12 -0
  239. package/dist/modules/tenant/tenant.migration.d.ts +5 -0
  240. package/dist/modules/tenant/tenant.migration.js +46 -0
  241. package/dist/modules/tenant/tenant.provider.d.ts +3 -0
  242. package/dist/modules/tenant/tenant.provider.js +44 -0
  243. package/dist/modules/tenant/tenant.readiness.d.ts +6 -0
  244. package/dist/modules/tenant/tenant.readiness.js +45 -0
  245. package/dist/modules/tenant/tenant.repository.d.ts +15 -0
  246. package/dist/modules/tenant/tenant.repository.js +23 -0
  247. package/dist/modules/tenant/tenant.routes.d.ts +4 -0
  248. package/dist/modules/tenant/tenant.routes.js +7 -0
  249. package/dist/modules/tenant/tenant.schema.d.ts +20 -0
  250. package/dist/modules/tenant/tenant.schema.js +31 -0
  251. package/dist/modules/tenant/tenant.seed.d.ts +8 -0
  252. package/dist/modules/tenant/tenant.seed.js +40 -0
  253. package/dist/modules/tenant/tenant.service.d.ts +16 -0
  254. package/dist/modules/tenant/tenant.service.js +72 -0
  255. package/dist/modules/tenant/tenant.types.d.ts +39 -0
  256. package/dist/modules/tenant/tenant.types.js +1 -0
  257. package/package.json +9 -5
  258. package/dist/modules/identity/identity.administration-repository.d.ts +0 -19
  259. package/dist/modules/identity/identity.administration-repository.js +0 -102
  260. package/dist/modules/identity/identity.administration-schema.d.ts +0 -113
  261. package/dist/modules/identity/identity.administration-schema.js +0 -121
  262. package/dist/modules/identity/identity.administration-service.js +0 -517
  263. package/dist/modules/identity/identity.membership-policy.d.ts +0 -3
  264. package/dist/modules/identity/identity.membership-policy.js +0 -27
  265. package/dist/modules/identity/identity.permission-declarations.d.ts +0 -23
  266. package/dist/modules/identity/identity.permission-declarations.js +0 -57
  267. package/dist/modules/identity/identity.presentation-service.d.ts +0 -23
  268. package/dist/modules/identity/identity.presentation-service.js +0 -51
  269. package/dist/modules/identity/identity.roles-service.d.ts +0 -49
  270. package/dist/modules/identity/identity.roles-service.js +0 -327
  271. /package/dist/modules/identity/{identity.administration-migration.d.ts → legacy/identity.administration-migration.d.ts} +0 -0
  272. /package/dist/modules/identity/{identity.permission-declarations-migration.d.ts → permission/permission.declarations.migration.d.ts} +0 -0
  273. /package/dist/modules/identity/{identity.permission-labels-migration.d.ts → permission/permission.labels.migration.d.ts} +0 -0
  274. /package/dist/modules/identity/{identity.roles-migration.d.ts → role/role.migration.d.ts} +0 -0
  275. /package/dist/modules/identity/{identity.error.d.ts → support/identity.error.d.ts} +0 -0
  276. /package/dist/modules/identity/{identity.error.js → support/identity.error.js} +0 -0
  277. /package/dist/modules/identity/{identity.request-context.d.ts → support/identity.request-context.d.ts} +0 -0
  278. /package/dist/modules/identity/{identity.request-context.js → support/identity.request-context.js} +0 -0
  279. /package/dist/modules/identity/{identity.lifecycle-schema.d.ts → user/user.lifecycle.schema.d.ts} +0 -0
  280. /package/dist/modules/identity/{identity.password.d.ts → user/user.password.d.ts} +0 -0
@@ -0,0 +1,11 @@
1
+ export async function seedOrganization(trx, env) {
2
+ await trx
3
+ .insertInto("identity_tenants")
4
+ .values({
5
+ id: env.IDENTITY_TENANT_ID ?? "default",
6
+ name: env.IDENTITY_TENANT_NAME ?? "Default organization",
7
+ active: 1
8
+ })
9
+ .onConflict((c) => c.column("id").doNothing())
10
+ .execute();
11
+ }
@@ -0,0 +1,39 @@
1
+ import type { Transaction } from "kysely";
2
+ import type { IdentityMutation, IdentitySchema, Principal } from "../identity.types.js";
3
+ import { IdentityOrganizationRepository } from "./organization.repository.js";
4
+ import type { IdentityListQuery } from "../support/pagination.schema.js";
5
+ export declare class IdentityOrganizationService {
6
+ private readonly repository;
7
+ private readonly mutate;
8
+ private readonly revokeTenantSessions;
9
+ constructor(repository: IdentityOrganizationRepository, mutate: IdentityMutation, revokeTenantSessions: (trx: Transaction<IdentitySchema>, tenantId: string) => Promise<void>);
10
+ list(actor: Principal, query: IdentityListQuery): Promise<{
11
+ data: {
12
+ active: boolean;
13
+ version: number;
14
+ }[];
15
+ meta: {
16
+ page: number;
17
+ perPage: number;
18
+ total: number;
19
+ lastPage: number;
20
+ };
21
+ }>;
22
+ show(actor: Principal, id: string): Promise<{
23
+ active: boolean;
24
+ version: number;
25
+ } | undefined>;
26
+ create(actor: Principal, raw: unknown): Promise<{
27
+ id: string;
28
+ name: string;
29
+ active: boolean;
30
+ version: number;
31
+ }>;
32
+ update(actor: Principal, id: string, raw: unknown): Promise<{
33
+ active: boolean;
34
+ version: number;
35
+ id: string;
36
+ name: string;
37
+ }>;
38
+ private manage;
39
+ }
@@ -0,0 +1,55 @@
1
+ import { IdentityError } from "../support/identity.error.js";
2
+ import { organizationCreateSchema, organizationUpdateSchema } from "./organization.schema.js";
3
+ export class IdentityOrganizationService {
4
+ repository;
5
+ mutate;
6
+ revokeTenantSessions;
7
+ constructor(repository, mutate, revokeTenantSessions) {
8
+ this.repository = repository;
9
+ this.mutate = mutate;
10
+ this.revokeTenantSessions = revokeTenantSessions;
11
+ }
12
+ list(actor, query) {
13
+ if (actor.portal === "user")
14
+ throw new IdentityError(403, "Access denied.");
15
+ return this.repository.list(actor, query);
16
+ }
17
+ show(actor, id) {
18
+ if (actor.portal === "user")
19
+ throw new IdentityError(403, "Access denied.");
20
+ return this.repository.show(actor, id);
21
+ }
22
+ async create(actor, raw) {
23
+ this.manage(actor);
24
+ const input = organizationCreateSchema.parse(raw);
25
+ return this.mutate(actor, "organizations", input.id, async (trx) => {
26
+ if (await this.repository.exists(trx, input.id))
27
+ throw new IdentityError(409, "Organization already exists.");
28
+ await this.repository.create(trx, input);
29
+ return { ...input, version: 0 };
30
+ });
31
+ }
32
+ async update(actor, id, raw) {
33
+ this.manage(actor);
34
+ if (!(await this.show(actor, id)))
35
+ throw new IdentityError(404, "Resource not found.");
36
+ const input = organizationUpdateSchema.parse(raw);
37
+ return this.mutate(actor, "organizations", id, async (trx) => {
38
+ const current = await this.repository.version(trx, id);
39
+ if (Number(current.version) !== input.expectedVersion)
40
+ throw new IdentityError(409, "This record changed. Reload before saving.");
41
+ if (input.active === false && id === actor.tenant.id)
42
+ throw new IdentityError(409, "Cannot deactivate your current organization.");
43
+ if (!(await this.repository.update(trx, id, input)))
44
+ throw new IdentityError(409, "This record changed. Reload before saving.");
45
+ if (input.active === false)
46
+ await this.revokeTenantSessions(trx, id);
47
+ const row = await this.repository.get(trx, id);
48
+ return { ...row, active: Boolean(row.active), version: Number(row.version) };
49
+ });
50
+ }
51
+ manage(actor) {
52
+ if (actor.portal !== "super-admin" || !actor.permissions.includes("identity.manage"))
53
+ throw new IdentityError(403, "Only super administrators can change this resource.");
54
+ }
55
+ }
@@ -0,0 +1,19 @@
1
+ import type { Generated } from "kysely";
2
+ export interface IdentityOrganizationTables {
3
+ identity_tenants: {
4
+ id: string;
5
+ name: string;
6
+ active: number;
7
+ version: Generated<number>;
8
+ };
9
+ }
10
+ export type IdentityOrganizationRow = IdentityOrganizationTables["identity_tenants"];
11
+ export interface IdentityTenantDirectory {
12
+ active(id: string): Promise<{
13
+ id: string;
14
+ name: string;
15
+ } | undefined>;
16
+ listActive(after: string, pageSize: number): Promise<{
17
+ id: string;
18
+ }[]>;
19
+ }
@@ -0,0 +1,9 @@
1
+ export { createIdentityPermissionProvider } from "./permission.provider.js";
2
+ export type { IdentityPermissionProvider } from "./permission.provider.js";
3
+ export type { IdentityPermissionDeclaration } from "./permission.schema.js";
4
+ export { defaultPermissions, seedPermissions } from "./permission.seed.js";
5
+ export { permissionResource, permissionResourceRoute } from "./permission.routes.js";
6
+ export { identityPermissionDeclarationsMigration } from "./permission.declarations.migration.js";
7
+ export { identityPermissionLabelsMigration } from "./permission.labels.migration.js";
8
+ export type { IdentityPermissionRow, IdentityPermissionDeclarationRow } from "./permission.types.js";
9
+ export { IdentityPermissionController } from "./permission.controller.js";
@@ -0,0 +1,6 @@
1
+ export { createIdentityPermissionProvider } from "./permission.provider.js";
2
+ export { defaultPermissions, seedPermissions } from "./permission.seed.js";
3
+ export { permissionResource, permissionResourceRoute } from "./permission.routes.js";
4
+ export { identityPermissionDeclarationsMigration } from "./permission.declarations.migration.js";
5
+ export { identityPermissionLabelsMigration } from "./permission.labels.migration.js";
6
+ export { IdentityPermissionController } from "./permission.controller.js";
@@ -0,0 +1,21 @@
1
+ import type { Principal } from "../identity.types.js";
2
+ import type { IdentityListQuery } from "../support/pagination.schema.js";
3
+ import type { IdentityPermissionProvider } from "./permission.provider.js";
4
+ export declare class IdentityPermissionController {
5
+ private readonly service;
6
+ constructor(service: IdentityPermissionProvider);
7
+ index(actor: Principal, query: IdentityListQuery): Promise<{
8
+ data: {
9
+ portals: string[];
10
+ }[];
11
+ meta: {
12
+ page: number;
13
+ perPage: number;
14
+ total: number;
15
+ lastPage: number;
16
+ };
17
+ }>;
18
+ show(actor: Principal, id: string): Promise<{
19
+ portals: string[];
20
+ } | undefined>;
21
+ }
@@ -0,0 +1,12 @@
1
+ export class IdentityPermissionController {
2
+ service;
3
+ constructor(service) {
4
+ this.service = service;
5
+ }
6
+ index(actor, query) {
7
+ return this.service.list(actor, query);
8
+ }
9
+ show(actor, id) {
10
+ return this.service.show(actor, id);
11
+ }
12
+ }
@@ -1,15 +1,20 @@
1
1
  export const identityPermissionDeclarationsMigration = {
2
2
  async up(db) {
3
- await db.schema.createTable("identity_permission_declarations")
3
+ await db.schema
4
+ .createTable("identity_permission_declarations")
4
5
  .addColumn("permission_id", "text", (column) => column.primaryKey().references("identity_permissions.id"))
5
6
  .addColumn("app_id", "text", (column) => column.notNull())
6
7
  .addColumn("owner", "text", (column) => column.notNull())
7
- .addColumn("portals", "text", (column) => column.notNull()).execute();
8
+ .addColumn("portals", "text", (column) => column.notNull())
9
+ .execute();
8
10
  },
9
11
  async down(db) {
10
- const declared = await db.selectFrom("identity_permission_declarations").select("permission_id").executeTakeFirst();
12
+ const declared = await db
13
+ .selectFrom("identity_permission_declarations")
14
+ .select("permission_id")
15
+ .executeTakeFirst();
11
16
  if (declared)
12
17
  throw new Error("Restore a compatible snapshot before removing permission ownership restrictions.");
13
18
  await db.schema.dropTable("identity_permission_declarations").execute();
14
- },
19
+ }
15
20
  };
@@ -1,9 +1,12 @@
1
1
  // Additive migration. Do not rewrite the previously applied declaration schema.
2
2
  export const identityPermissionLabelsMigration = {
3
3
  async up(db) {
4
- await db.schema.alterTable("identity_permission_declarations").addColumn("label", "text").execute();
4
+ await db.schema
5
+ .alterTable("identity_permission_declarations")
6
+ .addColumn("label", "text")
7
+ .execute();
5
8
  },
6
9
  async down(db) {
7
10
  await db.schema.alterTable("identity_permission_declarations").dropColumn("label").execute();
8
- },
11
+ }
9
12
  };
@@ -0,0 +1,2 @@
1
+ export { identityPermissionDeclarationsMigration } from "./permission.declarations.migration.js";
2
+ export { identityPermissionLabelsMigration } from "./permission.labels.migration.js";
@@ -0,0 +1,2 @@
1
+ export { identityPermissionDeclarationsMigration } from "./permission.declarations.migration.js";
2
+ export { identityPermissionLabelsMigration } from "./permission.labels.migration.js";
@@ -0,0 +1,19 @@
1
+ import type { Kysely, Transaction } from "kysely";
2
+ import type { IdentitySchema, Portal } from "../identity.types.js";
3
+ import type { IdentityPermissionDeclaration } from "./permission.schema.js";
4
+ import { IdentityPermissionService } from "./permission.service.js";
5
+ import type { Principal } from "../identity.types.js";
6
+ import type { IdentityListQuery } from "../support/pagination.schema.js";
7
+ export interface IdentityPermissionProvider {
8
+ verify(): Promise<void>;
9
+ list(actor: Principal, query: IdentityListQuery): ReturnType<IdentityPermissionService["list"]>;
10
+ show(actor: Principal, id: string): ReturnType<IdentityPermissionService["show"]>;
11
+ register(appId: string, declaration: IdentityPermissionDeclaration): Promise<{
12
+ owner: string;
13
+ permissionIds: string[];
14
+ }>;
15
+ validateDeclared(database: Kysely<IdentitySchema> | Transaction<IdentitySchema>, appId: string, portal: Portal, ids: string[]): Promise<void>;
16
+ validateKnown(database: Transaction<IdentitySchema>, ids: string[]): Promise<void>;
17
+ filterDeclared(database: Kysely<IdentitySchema>, appId: string, portal: Portal, ids: string[]): Promise<string[]>;
18
+ }
19
+ export declare function createIdentityPermissionProvider(database: Kysely<IdentitySchema>): IdentityPermissionProvider;
@@ -0,0 +1,14 @@
1
+ import { IdentityPermissionRepository } from "./permission.repository.js";
2
+ import { IdentityPermissionService } from "./permission.service.js";
3
+ export function createIdentityPermissionProvider(database) {
4
+ const service = new IdentityPermissionService(new IdentityPermissionRepository(database));
5
+ return Object.freeze({
6
+ verify: service.verify.bind(service),
7
+ list: service.list.bind(service),
8
+ show: service.show.bind(service),
9
+ register: service.register.bind(service),
10
+ validateDeclared: service.validateDeclared.bind(service),
11
+ validateKnown: service.validateKnown.bind(service),
12
+ filterDeclared: service.filterDeclared.bind(service)
13
+ });
14
+ }
@@ -0,0 +1,51 @@
1
+ import { type Kysely, type Transaction } from "kysely";
2
+ import type { IdentitySchema, Principal } from "../identity.types.js";
3
+ import type { IdentityListQuery } from "../support/pagination.schema.js";
4
+ type Database = Kysely<IdentitySchema> | Transaction<IdentitySchema>;
5
+ export declare class IdentityPermissionRepository {
6
+ private readonly db;
7
+ constructor(db: Kysely<IdentitySchema>);
8
+ verifySchema(): Promise<void>;
9
+ list(actor: Principal, query: IdentityListQuery): Promise<{
10
+ data: {
11
+ portals: string[];
12
+ }[];
13
+ meta: {
14
+ page: number;
15
+ perPage: number;
16
+ total: number;
17
+ lastPage: number;
18
+ };
19
+ }>;
20
+ show(actor: Principal, id: string): Promise<{
21
+ portals: string[];
22
+ } | undefined>;
23
+ transaction<T>(action: (trx: Transaction<IdentitySchema>) => Promise<T>): Promise<T>;
24
+ declaration(db: Database, id: string): Promise<{
25
+ app_id: string;
26
+ label: string | null;
27
+ owner: string;
28
+ permission_id: string;
29
+ portals: string;
30
+ } | undefined>;
31
+ declarations(db: Database): Promise<{
32
+ app_id: string;
33
+ label: string | null;
34
+ owner: string;
35
+ permission_id: string;
36
+ portals: string;
37
+ }[]>;
38
+ permission(db: Database, id: string): Promise<{
39
+ id: string;
40
+ } | undefined>;
41
+ knownIds(db: Database): Promise<Set<string>>;
42
+ updateLabel(trx: Transaction<IdentitySchema>, id: string, label: string): Promise<void>;
43
+ create(trx: Transaction<IdentitySchema>, input: {
44
+ id: string;
45
+ appId: string;
46
+ owner: string;
47
+ portals: string;
48
+ label: string | null;
49
+ }): Promise<void>;
50
+ }
51
+ export {};
@@ -0,0 +1,84 @@
1
+ import { sql } from "kysely";
2
+ import { listRows, showRow } from "../support/pagination.js";
3
+ function permissionListSource(actor) {
4
+ return sql `select p.id,coalesce(d.label,p.id) as label,
5
+ coalesce(d.owner,case when p.id like 'desk.%' then 'desk' else 'identity' end) as owner,
6
+ d.app_id as appId,
7
+ coalesce(d.portals,case when p.id='desk.user' then '["user"]' when p.id='desk.admin' then '["admin"]'
8
+ when p.id='desk.super-admin' then '["super-admin"]' when p.id='identity.manage' then '["admin","super-admin"]'
9
+ else '["user","admin","super-admin"]' end) as portals
10
+ from identity_permissions p left join identity_permission_declarations d on d.permission_id=p.id
11
+ where d.permission_id is null or d.app_id=${actor.appId}`;
12
+ }
13
+ export class IdentityPermissionRepository {
14
+ db;
15
+ constructor(db) {
16
+ this.db = db;
17
+ }
18
+ async verifySchema() {
19
+ await this.db.selectFrom("identity_permissions").select("id").limit(1).execute();
20
+ await this.db
21
+ .selectFrom("identity_permission_declarations")
22
+ .select(["permission_id", "label"])
23
+ .limit(1)
24
+ .execute();
25
+ }
26
+ list(actor, query) {
27
+ const present = (row) => ({
28
+ ...row,
29
+ portals: JSON.parse(String(row.portals))
30
+ });
31
+ return listRows(this.db, permissionListSource(actor), ["id"], query, present);
32
+ }
33
+ show(actor, id) {
34
+ const present = (row) => ({
35
+ ...row,
36
+ portals: JSON.parse(String(row.portals))
37
+ });
38
+ return showRow(this.db, permissionListSource(actor), id, present);
39
+ }
40
+ transaction(action) {
41
+ return this.db.transaction().execute(action);
42
+ }
43
+ declaration(db, id) {
44
+ return db
45
+ .selectFrom("identity_permission_declarations")
46
+ .selectAll()
47
+ .where("permission_id", "=", id)
48
+ .executeTakeFirst();
49
+ }
50
+ declarations(db) {
51
+ return db.selectFrom("identity_permission_declarations").selectAll().execute();
52
+ }
53
+ permission(db, id) {
54
+ return db
55
+ .selectFrom("identity_permissions")
56
+ .select("id")
57
+ .where("id", "=", id)
58
+ .executeTakeFirst();
59
+ }
60
+ async knownIds(db) {
61
+ const rows = await db.selectFrom("identity_permissions").select("id").execute();
62
+ return new Set(rows.map((row) => row.id));
63
+ }
64
+ async updateLabel(trx, id, label) {
65
+ await trx
66
+ .updateTable("identity_permission_declarations")
67
+ .set({ label })
68
+ .where("permission_id", "=", id)
69
+ .execute();
70
+ }
71
+ async create(trx, input) {
72
+ await trx.insertInto("identity_permissions").values({ id: input.id }).execute();
73
+ await trx
74
+ .insertInto("identity_permission_declarations")
75
+ .values({
76
+ permission_id: input.id,
77
+ app_id: input.appId,
78
+ owner: input.owner,
79
+ portals: input.portals,
80
+ label: input.label
81
+ })
82
+ .execute();
83
+ }
84
+ }
@@ -0,0 +1,5 @@
1
+ export declare const permissionResource: "permissions";
2
+ export declare const permissionResourceRoute: (controller: import("./permission.controller.js").IdentityPermissionController) => {
3
+ resource: "permissions";
4
+ controller: import("./permission.controller.js").IdentityPermissionController;
5
+ };
@@ -0,0 +1,2 @@
1
+ export const permissionResource = "permissions";
2
+ export const permissionResourceRoute = (controller) => ({ resource: permissionResource, controller });
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ export declare const permissionDeclarationSchema: z.ZodObject<{
3
+ owner: z.ZodString;
4
+ permissions: z.ZodArray<z.ZodObject<{
5
+ id: z.ZodString;
6
+ portals: z.ZodArray<z.ZodEnum<{
7
+ admin: "admin";
8
+ "super-admin": "super-admin";
9
+ user: "user";
10
+ }>>;
11
+ label: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$strict>>;
13
+ }, z.core.$strict>;
14
+ export type IdentityPermissionDeclaration = z.input<typeof permissionDeclarationSchema>;
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import { portalSchema } from "../support/identity.schema.js";
3
+ export const permissionDeclarationSchema = z
4
+ .object({
5
+ owner: z
6
+ .string()
7
+ .regex(/^[a-z][a-z0-9-]{0,63}$/)
8
+ .refine((value) => !["identity", "desk"].includes(value)),
9
+ permissions: z
10
+ .array(z
11
+ .object({
12
+ id: z
13
+ .string()
14
+ .regex(/^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*){2,8}$/)
15
+ .max(250),
16
+ portals: z.array(portalSchema).min(1).max(3),
17
+ label: z
18
+ .string()
19
+ .trim()
20
+ .min(1)
21
+ .max(100)
22
+ .regex(/^[^\x00-\x1f\x7f]+$/)
23
+ .optional()
24
+ })
25
+ .strict())
26
+ .min(1)
27
+ .max(100)
28
+ })
29
+ .strict();
@@ -0,0 +1,4 @@
1
+ import type { Transaction } from "kysely";
2
+ import type { IdentitySchema, Portal } from "../identity.types.js";
3
+ export declare function defaultPermissions(portal: Portal): string[];
4
+ export declare function seedPermissions(trx: Transaction<IdentitySchema>): Promise<void>;
@@ -0,0 +1,17 @@
1
+ export function defaultPermissions(portal) {
2
+ return [
3
+ `desk.${portal}`,
4
+ "identity.self",
5
+ "identity.password",
6
+ ...(portal === "user" ? [] : ["identity.manage"])
7
+ ];
8
+ }
9
+ export async function seedPermissions(trx) {
10
+ for (const portal of ["user", "admin", "super-admin"])
11
+ for (const permission of defaultPermissions(portal))
12
+ await trx
13
+ .insertInto("identity_permissions")
14
+ .values({ id: permission })
15
+ .onConflict((c) => c.column("id").doNothing())
16
+ .execute();
17
+ }
@@ -0,0 +1,31 @@
1
+ import type { Kysely, Transaction } from "kysely";
2
+ import type { IdentitySchema, Portal } from "../identity.types.js";
3
+ import { IdentityPermissionRepository } from "./permission.repository.js";
4
+ import type { Principal } from "../identity.types.js";
5
+ import type { IdentityListQuery } from "../support/pagination.schema.js";
6
+ export declare class IdentityPermissionService {
7
+ private readonly repository;
8
+ constructor(repository: IdentityPermissionRepository);
9
+ verify(): Promise<void>;
10
+ list(actor: Principal, query: IdentityListQuery): Promise<{
11
+ data: {
12
+ portals: string[];
13
+ }[];
14
+ meta: {
15
+ page: number;
16
+ perPage: number;
17
+ total: number;
18
+ lastPage: number;
19
+ };
20
+ }>;
21
+ show(actor: Principal, id: string): Promise<{
22
+ portals: string[];
23
+ } | undefined>;
24
+ register(appId: string, raw: unknown): Promise<{
25
+ owner: string;
26
+ permissionIds: string[];
27
+ }>;
28
+ validateDeclared(db: Kysely<IdentitySchema> | Transaction<IdentitySchema>, appId: string, portal: Portal, ids: string[]): Promise<void>;
29
+ validateKnown(db: Transaction<IdentitySchema>, ids: string[]): Promise<void>;
30
+ filterDeclared(db: Kysely<IdentitySchema>, appId: string, portal: Portal, ids: string[]): Promise<string[]>;
31
+ }
@@ -0,0 +1,77 @@
1
+ import { IdentityError } from "../support/identity.error.js";
2
+ import { permissionDeclarationSchema } from "./permission.schema.js";
3
+ export class IdentityPermissionService {
4
+ repository;
5
+ constructor(repository) {
6
+ this.repository = repository;
7
+ }
8
+ verify() {
9
+ return this.repository.verifySchema();
10
+ }
11
+ list(actor, query) {
12
+ if (actor.portal === "user")
13
+ throw new IdentityError(403, "Access denied.");
14
+ return this.repository.list(actor, query);
15
+ }
16
+ show(actor, id) {
17
+ if (actor.portal === "user")
18
+ throw new IdentityError(403, "Access denied.");
19
+ return this.repository.show(actor, id);
20
+ }
21
+ async register(appId, raw) {
22
+ const declaration = permissionDeclarationSchema.parse(raw);
23
+ const ids = new Set();
24
+ for (const permission of declaration.permissions) {
25
+ if (!permission.id.startsWith(`${appId}.${declaration.owner}.`) || ids.has(permission.id))
26
+ throw new IdentityError(422, "Use unique permission IDs in this app and owner namespace.");
27
+ ids.add(permission.id);
28
+ }
29
+ return this.repository.transaction(async (trx) => {
30
+ for (const permission of declaration.permissions) {
31
+ const portals = JSON.stringify([...new Set(permission.portals)].sort());
32
+ const previous = await this.repository.declaration(trx, permission.id);
33
+ if (previous) {
34
+ if (previous.app_id !== appId ||
35
+ previous.owner !== declaration.owner ||
36
+ previous.portals !== portals)
37
+ throw new IdentityError(409, "Permission declaration conflicts with its registered owner or portal policy.");
38
+ if (permission.label !== undefined && permission.label !== previous.label)
39
+ await this.repository.updateLabel(trx, permission.id, permission.label);
40
+ continue;
41
+ }
42
+ if (await this.repository.permission(trx, permission.id))
43
+ throw new IdentityError(409, "Permission already exists without this owner declaration.");
44
+ await this.repository.create(trx, {
45
+ id: permission.id,
46
+ appId,
47
+ owner: declaration.owner,
48
+ portals,
49
+ label: permission.label ?? null
50
+ });
51
+ }
52
+ return { owner: declaration.owner, permissionIds: [...ids] };
53
+ });
54
+ }
55
+ async validateDeclared(db, appId, portal, ids) {
56
+ const declarations = await this.repository.declarations(db);
57
+ for (const id of ids) {
58
+ const declaration = declarations.find((row) => row.permission_id === id);
59
+ if (declaration &&
60
+ (declaration.app_id !== appId || !JSON.parse(declaration.portals).includes(portal)))
61
+ throw new IdentityError(403, "Permission is unavailable in this app or portal.");
62
+ }
63
+ }
64
+ async validateKnown(db, ids) {
65
+ const known = await this.repository.knownIds(db);
66
+ if (ids.some((id) => !known.has(id)))
67
+ throw new IdentityError(422, "Unknown permission.");
68
+ }
69
+ async filterDeclared(db, appId, portal, ids) {
70
+ const declarations = await this.repository.declarations(db);
71
+ return ids.filter((id) => {
72
+ const declaration = declarations.find((row) => row.permission_id === id);
73
+ return (!declaration ||
74
+ (declaration.app_id === appId && JSON.parse(declaration.portals).includes(portal)));
75
+ });
76
+ }
77
+ }
@@ -0,0 +1,15 @@
1
+ import type { Generated } from "kysely";
2
+ export interface IdentityPermissionTables {
3
+ identity_permissions: {
4
+ id: string;
5
+ };
6
+ identity_permission_declarations: {
7
+ permission_id: string;
8
+ app_id: string;
9
+ owner: string;
10
+ portals: string;
11
+ label: Generated<string | null>;
12
+ };
13
+ }
14
+ export type IdentityPermissionRow = IdentityPermissionTables["identity_permissions"];
15
+ export type IdentityPermissionDeclarationRow = IdentityPermissionTables["identity_permission_declarations"];
@@ -0,0 +1,10 @@
1
+ import type { IdentityRoleProvider } from "./role.provider.js";
2
+ export { createIdentityRoleProvider } from "./role.provider.js";
3
+ export { identityRolesMigration } from "./role.migration.js";
4
+ export { seedRoles } from "./role.seed.js";
5
+ export { roleResource, roleResourceRoute } from "./role.routes.js";
6
+ export { customRoleCreateSchema, customRoleUpdateSchema, roleUpdateSchema } from "./role.schema.js";
7
+ export type { IdentityRoleProvider };
8
+ export type IdentityRoleResolver = IdentityRoleProvider["resolve"];
9
+ export type { IdentityRoleRow, IdentityCustomRoleRow } from "./role.types.js";
10
+ export { IdentityRoleController } from "./role.controller.js";
@@ -0,0 +1,6 @@
1
+ export { createIdentityRoleProvider } from "./role.provider.js";
2
+ export { identityRolesMigration } from "./role.migration.js";
3
+ export { seedRoles } from "./role.seed.js";
4
+ export { roleResource, roleResourceRoute } from "./role.routes.js";
5
+ export { customRoleCreateSchema, customRoleUpdateSchema, roleUpdateSchema } from "./role.schema.js";
6
+ export { IdentityRoleController } from "./role.controller.js";