@de-otio/trellis 0.6.0 → 0.7.0

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 (339) hide show
  1. package/dist/env.d.ts +21 -0
  2. package/dist/env.d.ts.map +1 -1
  3. package/dist/env.js +12 -0
  4. package/dist/env.js.map +1 -1
  5. package/dist/lambda/nightly-cron.d.ts.map +1 -1
  6. package/dist/lambda/nightly-cron.js +5 -2
  7. package/dist/lambda/nightly-cron.js.map +1 -1
  8. package/dist/lambda/post-confirmation.d.ts +30 -0
  9. package/dist/lambda/post-confirmation.d.ts.map +1 -1
  10. package/dist/lambda/post-confirmation.js +333 -29
  11. package/dist/lambda/post-confirmation.js.map +1 -1
  12. package/dist/lambda/pre-token-generation.d.ts +20 -0
  13. package/dist/lambda/pre-token-generation.d.ts.map +1 -1
  14. package/dist/lambda/pre-token-generation.js +233 -48
  15. package/dist/lambda/pre-token-generation.js.map +1 -1
  16. package/dist/lib/activitypub/activity-processor.d.ts.map +1 -1
  17. package/dist/lib/activitypub/activity-processor.js +2 -1
  18. package/dist/lib/activitypub/activity-processor.js.map +1 -1
  19. package/dist/lib/activitypub/group-service.d.ts +2 -2
  20. package/dist/lib/activitypub/group-service.d.ts.map +1 -1
  21. package/dist/lib/activitypub/group-service.js +5 -2
  22. package/dist/lib/activitypub/group-service.js.map +1 -1
  23. package/dist/lib/age-tier-transition.d.ts.map +1 -1
  24. package/dist/lib/age-tier-transition.js +19 -10
  25. package/dist/lib/age-tier-transition.js.map +1 -1
  26. package/dist/lib/audit/csv-export.d.ts +25 -0
  27. package/dist/lib/audit/csv-export.d.ts.map +1 -0
  28. package/dist/lib/audit/csv-export.js +54 -0
  29. package/dist/lib/audit/csv-export.js.map +1 -0
  30. package/dist/lib/audit/emit.d.ts +56 -0
  31. package/dist/lib/audit/emit.d.ts.map +1 -0
  32. package/dist/lib/audit/emit.js +124 -0
  33. package/dist/lib/audit/emit.js.map +1 -0
  34. package/dist/lib/audit/event-types.d.ts +36 -0
  35. package/dist/lib/audit/event-types.d.ts.map +1 -0
  36. package/dist/lib/audit/event-types.js +69 -0
  37. package/dist/lib/audit/event-types.js.map +1 -0
  38. package/dist/lib/audit/pii-filter.d.ts +22 -0
  39. package/dist/lib/audit/pii-filter.d.ts.map +1 -0
  40. package/dist/lib/audit/pii-filter.js +51 -0
  41. package/dist/lib/audit/pii-filter.js.map +1 -0
  42. package/dist/lib/audit-logger.js +1 -1
  43. package/dist/lib/audit-logger.js.map +1 -1
  44. package/dist/lib/auth/auth-context.d.ts +34 -0
  45. package/dist/lib/auth/auth-context.d.ts.map +1 -0
  46. package/dist/lib/auth/auth-context.js +10 -0
  47. package/dist/lib/auth/auth-context.js.map +1 -0
  48. package/dist/lib/auth/auth-middleware.d.ts +50 -0
  49. package/dist/lib/auth/auth-middleware.d.ts.map +1 -0
  50. package/dist/lib/auth/auth-middleware.js +153 -0
  51. package/dist/lib/auth/auth-middleware.js.map +1 -0
  52. package/dist/lib/auth/capabilities.d.ts +40 -0
  53. package/dist/lib/auth/capabilities.d.ts.map +1 -0
  54. package/dist/lib/auth/capabilities.js +44 -0
  55. package/dist/lib/auth/capabilities.js.map +1 -0
  56. package/dist/lib/auth/claims-cache.d.ts +70 -0
  57. package/dist/lib/auth/claims-cache.d.ts.map +1 -0
  58. package/dist/lib/auth/claims-cache.js +139 -0
  59. package/dist/lib/auth/claims-cache.js.map +1 -0
  60. package/dist/lib/auth/cognito-jwt.d.ts +6 -0
  61. package/dist/lib/auth/cognito-jwt.d.ts.map +1 -1
  62. package/dist/lib/auth/cognito-jwt.js.map +1 -1
  63. package/dist/lib/auth/idp-redirect-builder.d.ts +43 -0
  64. package/dist/lib/auth/idp-redirect-builder.d.ts.map +1 -0
  65. package/dist/lib/auth/idp-redirect-builder.js +48 -0
  66. package/dist/lib/auth/idp-redirect-builder.js.map +1 -0
  67. package/dist/lib/auth/require.d.ts +51 -0
  68. package/dist/lib/auth/require.d.ts.map +1 -0
  69. package/dist/lib/auth/require.js +99 -0
  70. package/dist/lib/auth/require.js.map +1 -0
  71. package/dist/lib/auth/role-grants.d.ts +18 -0
  72. package/dist/lib/auth/role-grants.d.ts.map +1 -0
  73. package/dist/lib/auth/role-grants.js +62 -0
  74. package/dist/lib/auth/role-grants.js.map +1 -0
  75. package/dist/lib/cognito/idp-sdk.d.ts +80 -0
  76. package/dist/lib/cognito/idp-sdk.d.ts.map +1 -0
  77. package/dist/lib/cognito/idp-sdk.js +186 -0
  78. package/dist/lib/cognito/idp-sdk.js.map +1 -0
  79. package/dist/lib/cognito/issuer-probe.d.ts +47 -0
  80. package/dist/lib/cognito/issuer-probe.d.ts.map +1 -0
  81. package/dist/lib/cognito/issuer-probe.js +319 -0
  82. package/dist/lib/cognito/issuer-probe.js.map +1 -0
  83. package/dist/lib/comment-handler.d.ts +7 -7
  84. package/dist/lib/comment-handler.d.ts.map +1 -1
  85. package/dist/lib/comment-handler.js +23 -20
  86. package/dist/lib/comment-handler.js.map +1 -1
  87. package/dist/lib/compliance/baseline.d.ts +15 -0
  88. package/dist/lib/compliance/baseline.d.ts.map +1 -0
  89. package/dist/lib/compliance/baseline.js +205 -0
  90. package/dist/lib/compliance/baseline.js.map +1 -0
  91. package/dist/lib/compliance/tenant-merge.d.ts +35 -0
  92. package/dist/lib/compliance/tenant-merge.d.ts.map +1 -0
  93. package/dist/lib/compliance/tenant-merge.js +80 -0
  94. package/dist/lib/compliance/tenant-merge.js.map +1 -0
  95. package/dist/lib/compliance/types.d.ts +135 -0
  96. package/dist/lib/compliance/types.d.ts.map +1 -0
  97. package/dist/lib/compliance/types.js +9 -0
  98. package/dist/lib/compliance/types.js.map +1 -0
  99. package/dist/lib/connection-code-handler.d.ts +4 -4
  100. package/dist/lib/connection-code-handler.d.ts.map +1 -1
  101. package/dist/lib/connection-code-handler.js +21 -11
  102. package/dist/lib/connection-code-handler.js.map +1 -1
  103. package/dist/lib/feed-handler.d.ts +2 -2
  104. package/dist/lib/feed-handler.d.ts.map +1 -1
  105. package/dist/lib/feed-handler.js +5 -9
  106. package/dist/lib/feed-handler.js.map +1 -1
  107. package/dist/lib/middleware/idempotency-store.d.ts +86 -0
  108. package/dist/lib/middleware/idempotency-store.d.ts.map +1 -0
  109. package/dist/lib/middleware/idempotency-store.js +109 -0
  110. package/dist/lib/middleware/idempotency-store.js.map +1 -0
  111. package/dist/lib/middleware/idempotency.d.ts +37 -0
  112. package/dist/lib/middleware/idempotency.d.ts.map +1 -0
  113. package/dist/lib/middleware/idempotency.js +358 -0
  114. package/dist/lib/middleware/idempotency.js.map +1 -0
  115. package/dist/lib/net/trusted-client-ip.d.ts +39 -0
  116. package/dist/lib/net/trusted-client-ip.d.ts.map +1 -0
  117. package/dist/lib/net/trusted-client-ip.js +100 -0
  118. package/dist/lib/net/trusted-client-ip.js.map +1 -0
  119. package/dist/lib/notification-handler.d.ts +5 -5
  120. package/dist/lib/notification-handler.d.ts.map +1 -1
  121. package/dist/lib/notification-handler.js +11 -9
  122. package/dist/lib/notification-handler.js.map +1 -1
  123. package/dist/lib/oauth/cognito-issuer.d.ts +34 -0
  124. package/dist/lib/oauth/cognito-issuer.d.ts.map +1 -0
  125. package/dist/lib/oauth/cognito-issuer.js +53 -0
  126. package/dist/lib/oauth/cognito-issuer.js.map +1 -0
  127. package/dist/lib/oauth/device-authorization.d.ts +145 -0
  128. package/dist/lib/oauth/device-authorization.d.ts.map +1 -0
  129. package/dist/lib/oauth/device-authorization.js +312 -0
  130. package/dist/lib/oauth/device-authorization.js.map +1 -0
  131. package/dist/lib/oauth/envelope-crypto.d.ts +101 -0
  132. package/dist/lib/oauth/envelope-crypto.d.ts.map +1 -0
  133. package/dist/lib/oauth/envelope-crypto.js +223 -0
  134. package/dist/lib/oauth/envelope-crypto.js.map +1 -0
  135. package/dist/lib/oauth/refresh-detection.d.ts +126 -0
  136. package/dist/lib/oauth/refresh-detection.d.ts.map +1 -0
  137. package/dist/lib/oauth/refresh-detection.js +248 -0
  138. package/dist/lib/oauth/refresh-detection.js.map +1 -0
  139. package/dist/lib/openapi/generator.d.ts +78 -0
  140. package/dist/lib/openapi/generator.d.ts.map +1 -0
  141. package/dist/lib/openapi/generator.js +201 -0
  142. package/dist/lib/openapi/generator.js.map +1 -0
  143. package/dist/lib/post-handler.d.ts +1 -1
  144. package/dist/lib/post-handler.d.ts.map +1 -1
  145. package/dist/lib/post-handler.js +4 -15
  146. package/dist/lib/post-handler.js.map +1 -1
  147. package/dist/lib/rate-limit.d.ts.map +1 -1
  148. package/dist/lib/rate-limit.js +11 -3
  149. package/dist/lib/rate-limit.js.map +1 -1
  150. package/dist/lib/routes/agent-authorize.d.ts +32 -0
  151. package/dist/lib/routes/agent-authorize.d.ts.map +1 -0
  152. package/dist/lib/routes/agent-authorize.js +479 -0
  153. package/dist/lib/routes/agent-authorize.js.map +1 -0
  154. package/dist/lib/routes/agent-sessions.d.ts +20 -0
  155. package/dist/lib/routes/agent-sessions.d.ts.map +1 -0
  156. package/dist/lib/routes/agent-sessions.js +124 -0
  157. package/dist/lib/routes/agent-sessions.js.map +1 -0
  158. package/dist/lib/routes/agent-surface.d.ts +37 -0
  159. package/dist/lib/routes/agent-surface.d.ts.map +1 -0
  160. package/dist/lib/routes/agent-surface.js +208 -0
  161. package/dist/lib/routes/agent-surface.js.map +1 -0
  162. package/dist/lib/routes/auth-discover.d.ts +18 -0
  163. package/dist/lib/routes/auth-discover.d.ts.map +1 -0
  164. package/dist/lib/routes/auth-discover.js +177 -0
  165. package/dist/lib/routes/auth-discover.js.map +1 -0
  166. package/dist/lib/routes/comments.d.ts.map +1 -1
  167. package/dist/lib/routes/comments.js +36 -7
  168. package/dist/lib/routes/comments.js.map +1 -1
  169. package/dist/lib/routes/connection-codes.d.ts.map +1 -1
  170. package/dist/lib/routes/connection-codes.js +21 -4
  171. package/dist/lib/routes/connection-codes.js.map +1 -1
  172. package/dist/lib/routes/content-discovery.d.ts.map +1 -1
  173. package/dist/lib/routes/content-discovery.js +18 -13
  174. package/dist/lib/routes/content-discovery.js.map +1 -1
  175. package/dist/lib/routes/dashboard.js +1 -1
  176. package/dist/lib/routes/dashboard.js.map +1 -1
  177. package/dist/lib/routes/employees.d.ts.map +1 -1
  178. package/dist/lib/routes/employees.js +57 -15
  179. package/dist/lib/routes/employees.js.map +1 -1
  180. package/dist/lib/routes/entities.d.ts.map +1 -1
  181. package/dist/lib/routes/entities.js +35 -19
  182. package/dist/lib/routes/entities.js.map +1 -1
  183. package/dist/lib/routes/errors.d.ts +34 -0
  184. package/dist/lib/routes/errors.d.ts.map +1 -0
  185. package/dist/lib/routes/errors.js +57 -0
  186. package/dist/lib/routes/errors.js.map +1 -0
  187. package/dist/lib/routes/feeds.d.ts.map +1 -1
  188. package/dist/lib/routes/feeds.js +12 -2
  189. package/dist/lib/routes/feeds.js.map +1 -1
  190. package/dist/lib/routes/index.d.ts.map +1 -1
  191. package/dist/lib/routes/index.js +50 -0
  192. package/dist/lib/routes/index.js.map +1 -1
  193. package/dist/lib/routes/mfa.d.ts.map +1 -1
  194. package/dist/lib/routes/mfa.js +1 -0
  195. package/dist/lib/routes/mfa.js.map +1 -1
  196. package/dist/lib/routes/notifications.d.ts.map +1 -1
  197. package/dist/lib/routes/notifications.js +21 -4
  198. package/dist/lib/routes/notifications.js.map +1 -1
  199. package/dist/lib/routes/oauth.d.ts +15 -0
  200. package/dist/lib/routes/oauth.d.ts.map +1 -0
  201. package/dist/lib/routes/oauth.js +139 -0
  202. package/dist/lib/routes/oauth.js.map +1 -0
  203. package/dist/lib/routes/posts.d.ts.map +1 -1
  204. package/dist/lib/routes/posts.js +30 -19
  205. package/dist/lib/routes/posts.js.map +1 -1
  206. package/dist/lib/routes/products.d.ts.map +1 -1
  207. package/dist/lib/routes/products.js +19 -22
  208. package/dist/lib/routes/products.js.map +1 -1
  209. package/dist/lib/routes/setup-status.d.ts +34 -0
  210. package/dist/lib/routes/setup-status.d.ts.map +1 -0
  211. package/dist/lib/routes/setup-status.js +87 -0
  212. package/dist/lib/routes/setup-status.js.map +1 -0
  213. package/dist/lib/routes/taxonomy-analytics.d.ts.map +1 -1
  214. package/dist/lib/routes/taxonomy-analytics.js +15 -14
  215. package/dist/lib/routes/taxonomy-analytics.js.map +1 -1
  216. package/dist/lib/routes/taxonomy.d.ts.map +1 -1
  217. package/dist/lib/routes/taxonomy.js +19 -16
  218. package/dist/lib/routes/taxonomy.js.map +1 -1
  219. package/dist/lib/routes/tenant-audit.d.ts +19 -0
  220. package/dist/lib/routes/tenant-audit.d.ts.map +1 -0
  221. package/dist/lib/routes/tenant-audit.js +244 -0
  222. package/dist/lib/routes/tenant-audit.js.map +1 -0
  223. package/dist/lib/routes/tenant-compliance.d.ts +21 -0
  224. package/dist/lib/routes/tenant-compliance.d.ts.map +1 -0
  225. package/dist/lib/routes/tenant-compliance.js +122 -0
  226. package/dist/lib/routes/tenant-compliance.js.map +1 -0
  227. package/dist/lib/routes/tenant-domains.d.ts +11 -0
  228. package/dist/lib/routes/tenant-domains.d.ts.map +1 -0
  229. package/dist/lib/routes/tenant-domains.js +95 -0
  230. package/dist/lib/routes/tenant-domains.js.map +1 -0
  231. package/dist/lib/routes/tenant-idp.d.ts +3 -0
  232. package/dist/lib/routes/tenant-idp.d.ts.map +1 -0
  233. package/dist/lib/routes/tenant-idp.js +89 -0
  234. package/dist/lib/routes/tenant-idp.js.map +1 -0
  235. package/dist/lib/routes/tenant-members.d.ts +13 -0
  236. package/dist/lib/routes/tenant-members.d.ts.map +1 -0
  237. package/dist/lib/routes/tenant-members.js +75 -0
  238. package/dist/lib/routes/tenant-members.js.map +1 -0
  239. package/dist/lib/routes/tenant-role-mappings.d.ts +11 -0
  240. package/dist/lib/routes/tenant-role-mappings.d.ts.map +1 -0
  241. package/dist/lib/routes/tenant-role-mappings.js +90 -0
  242. package/dist/lib/routes/tenant-role-mappings.js.map +1 -0
  243. package/dist/lib/routes/tenants.d.ts +13 -0
  244. package/dist/lib/routes/tenants.d.ts.map +1 -0
  245. package/dist/lib/routes/tenants.js +121 -0
  246. package/dist/lib/routes/tenants.js.map +1 -0
  247. package/dist/lib/routes/types.d.ts +9 -0
  248. package/dist/lib/routes/types.d.ts.map +1 -1
  249. package/dist/lib/schemas.d.ts +2 -2
  250. package/dist/lib/secrets/idp-secrets.d.ts +51 -0
  251. package/dist/lib/secrets/idp-secrets.d.ts.map +1 -0
  252. package/dist/lib/secrets/idp-secrets.js +111 -0
  253. package/dist/lib/secrets/idp-secrets.js.map +1 -0
  254. package/dist/lib/security-monitor.d.ts.map +1 -1
  255. package/dist/lib/security-monitor.js +6 -1
  256. package/dist/lib/security-monitor.js.map +1 -1
  257. package/dist/lib/session-manager.d.ts +1 -0
  258. package/dist/lib/session-manager.d.ts.map +1 -1
  259. package/dist/lib/session-manager.js.map +1 -1
  260. package/dist/lib/taxonomy-handler-factory.d.ts +4 -2
  261. package/dist/lib/taxonomy-handler-factory.d.ts.map +1 -1
  262. package/dist/lib/taxonomy-handler-factory.js +8 -7
  263. package/dist/lib/taxonomy-handler-factory.js.map +1 -1
  264. package/dist/lib/tenant/audit-emit.d.ts +18 -0
  265. package/dist/lib/tenant/audit-emit.d.ts.map +1 -0
  266. package/dist/lib/tenant/audit-emit.js +16 -0
  267. package/dist/lib/tenant/audit-emit.js.map +1 -0
  268. package/dist/lib/tenant/derive-domain.d.ts +19 -0
  269. package/dist/lib/tenant/derive-domain.d.ts.map +1 -0
  270. package/dist/lib/tenant/derive-domain.js +38 -0
  271. package/dist/lib/tenant/derive-domain.js.map +1 -0
  272. package/dist/lib/tenant/domain-handler.d.ts +42 -0
  273. package/dist/lib/tenant/domain-handler.d.ts.map +1 -0
  274. package/dist/lib/tenant/domain-handler.js +344 -0
  275. package/dist/lib/tenant/domain-handler.js.map +1 -0
  276. package/dist/lib/tenant/domain-validator.d.ts +28 -0
  277. package/dist/lib/tenant/domain-validator.d.ts.map +1 -0
  278. package/dist/lib/tenant/domain-validator.js +145 -0
  279. package/dist/lib/tenant/domain-validator.js.map +1 -0
  280. package/dist/lib/tenant/domain-verifier.d.ts +30 -0
  281. package/dist/lib/tenant/domain-verifier.d.ts.map +1 -0
  282. package/dist/lib/tenant/domain-verifier.js +53 -0
  283. package/dist/lib/tenant/domain-verifier.js.map +1 -0
  284. package/dist/lib/tenant/idp-handler.d.ts +29 -0
  285. package/dist/lib/tenant/idp-handler.d.ts.map +1 -0
  286. package/dist/lib/tenant/idp-handler.js +693 -0
  287. package/dist/lib/tenant/idp-handler.js.map +1 -0
  288. package/dist/lib/tenant/idp-name.d.ts +2 -0
  289. package/dist/lib/tenant/idp-name.d.ts.map +1 -0
  290. package/dist/lib/tenant/idp-name.js +20 -0
  291. package/dist/lib/tenant/idp-name.js.map +1 -0
  292. package/dist/lib/tenant/member-handler.d.ts +31 -0
  293. package/dist/lib/tenant/member-handler.d.ts.map +1 -0
  294. package/dist/lib/tenant/member-handler.js +343 -0
  295. package/dist/lib/tenant/member-handler.js.map +1 -0
  296. package/dist/lib/tenant/reserved-slugs.d.ts +37 -0
  297. package/dist/lib/tenant/reserved-slugs.d.ts.map +1 -0
  298. package/dist/lib/tenant/reserved-slugs.js +116 -0
  299. package/dist/lib/tenant/reserved-slugs.js.map +1 -0
  300. package/dist/lib/tenant/resolve-role.d.ts +39 -0
  301. package/dist/lib/tenant/resolve-role.d.ts.map +1 -0
  302. package/dist/lib/tenant/resolve-role.js +60 -0
  303. package/dist/lib/tenant/resolve-role.js.map +1 -0
  304. package/dist/lib/tenant/role-mapping-handler.d.ts +26 -0
  305. package/dist/lib/tenant/role-mapping-handler.d.ts.map +1 -0
  306. package/dist/lib/tenant/role-mapping-handler.js +260 -0
  307. package/dist/lib/tenant/role-mapping-handler.js.map +1 -0
  308. package/dist/lib/tenant/setup-status.d.ts +83 -0
  309. package/dist/lib/tenant/setup-status.d.ts.map +1 -0
  310. package/dist/lib/tenant/setup-status.js +201 -0
  311. package/dist/lib/tenant/setup-status.js.map +1 -0
  312. package/dist/lib/tenant/slug-validator.d.ts +31 -0
  313. package/dist/lib/tenant/slug-validator.d.ts.map +1 -0
  314. package/dist/lib/tenant/slug-validator.js +42 -0
  315. package/dist/lib/tenant/slug-validator.js.map +1 -0
  316. package/dist/lib/tenant/tenant-handler.d.ts +49 -0
  317. package/dist/lib/tenant/tenant-handler.d.ts.map +1 -0
  318. package/dist/lib/tenant/tenant-handler.js +377 -0
  319. package/dist/lib/tenant/tenant-handler.js.map +1 -0
  320. package/dist/lib/tenant/transfer-ownership.d.ts +39 -0
  321. package/dist/lib/tenant/transfer-ownership.d.ts.map +1 -0
  322. package/dist/lib/tenant/transfer-ownership.js +66 -0
  323. package/dist/lib/tenant/transfer-ownership.js.map +1 -0
  324. package/dist/lib/user/derive-handle.d.ts +29 -0
  325. package/dist/lib/user/derive-handle.d.ts.map +1 -0
  326. package/dist/lib/user/derive-handle.js +65 -0
  327. package/dist/lib/user/derive-handle.js.map +1 -0
  328. package/dist/lib/user-deprovisioning.d.ts +11 -1
  329. package/dist/lib/user-deprovisioning.d.ts.map +1 -1
  330. package/dist/lib/user-deprovisioning.js +46 -2
  331. package/dist/lib/user-deprovisioning.js.map +1 -1
  332. package/dist/lib/validation/feature-toggle-schemas.d.ts +10 -10
  333. package/package.json +6 -3
  334. package/prisma/migrations/20260502094501_add_tenancy_model/migration.sql +334 -0
  335. package/prisma/migrations/20260503000000_add_tenant_region/migration.sql +4 -0
  336. package/prisma/schema.prisma +324 -74
  337. package/src/lambda/nightly-cron.ts +4 -1
  338. package/src/lambda/post-confirmation.ts +405 -29
  339. package/src/lambda/pre-token-generation.ts +300 -59
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ /**
3
+ * Tenant CRUD Handler
4
+ *
5
+ * Handlers for:
6
+ * - POST /api/tenants — create org tenant
7
+ * - GET /api/tenants/:id — read tenant
8
+ * - PATCH /api/tenants/:id — update displayName
9
+ * - GET /api/users/me/tenants — list caller's memberships
10
+ * - POST /api/auth/switch-tenant — change active tenant + invalidate cache
11
+ * - POST /api/tenants/:id/transfer-ownership — OWNER hand-off
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.TenantHandler = void 0;
48
+ const auth_middleware_1 = require("../auth/auth-middleware");
49
+ const require_1 = require("../auth/require");
50
+ const slug_validator_1 = require("./slug-validator");
51
+ const claims_cache_1 = require("../auth/claims-cache");
52
+ const transfer_ownership_1 = require("./transfer-ownership");
53
+ const emit_1 = require("../audit/emit");
54
+ const event_types_1 = require("../audit/event-types");
55
+ const auditEmitter = new emit_1.AuditEventEmitter();
56
+ class TenantHandler {
57
+ /**
58
+ * POST /api/tenants
59
+ * Creates an ORGANIZATION tenant. Caller becomes OWNER.
60
+ * If caller is END_USER their global role is bumped to B2B_PARTNER.
61
+ */
62
+ async handleCreate(request, auth, env) {
63
+ const { z } = await Promise.resolve().then(() => __importStar(require("zod")));
64
+ let body;
65
+ try {
66
+ body = await request.json();
67
+ }
68
+ catch {
69
+ return new Response(JSON.stringify({ error: "INVALID_JSON", message: "Request body must be valid JSON" }), { status: 400, headers: { "content-type": "application/json" } });
70
+ }
71
+ const schema = z.object({
72
+ slug: z.string(),
73
+ displayName: z.string().min(1).max(100),
74
+ });
75
+ const parsed = schema.safeParse(body);
76
+ if (!parsed.success) {
77
+ return new Response(JSON.stringify({ error: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "Invalid input" }), { status: 400, headers: { "content-type": "application/json" } });
78
+ }
79
+ const { slug, displayName } = parsed.data;
80
+ const slugResult = (0, slug_validator_1.validateTenantSlug)(slug);
81
+ if (!slugResult.ok) {
82
+ return new Response(JSON.stringify({ error: slugResult.code, message: slugResult.message }), { status: 400, headers: { "content-type": "application/json" } });
83
+ }
84
+ const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
85
+ const db = createPrisma(env);
86
+ try {
87
+ const result = await db.$transaction(async (tx) => {
88
+ const tenant = await tx.tenant.create({
89
+ data: {
90
+ slug,
91
+ displayName,
92
+ type: "ORGANIZATION",
93
+ status: "ACTIVE",
94
+ },
95
+ });
96
+ await tx.tenantMember.create({
97
+ data: {
98
+ tenantId: tenant.id,
99
+ userId: auth.userId,
100
+ role: "OWNER",
101
+ status: "ACTIVE",
102
+ joinedAt: new Date(),
103
+ },
104
+ });
105
+ // Idempotent role bump: END_USER → B2B_PARTNER.
106
+ await tx.user.updateMany({
107
+ where: { id: auth.userId, role: "END_USER" },
108
+ data: { role: "B2B_PARTNER" },
109
+ });
110
+ return tenant;
111
+ });
112
+ void auditEmitter.emit({
113
+ type: event_types_1.AuditEventType.TENANT_CREATED,
114
+ tenantId: result.id,
115
+ actorUserId: auth.userId,
116
+ payload: { tenantId: result.id, slug: result.slug, displayName: result.displayName, type: "ORGANIZATION" },
117
+ }, db);
118
+ return new Response(JSON.stringify({ id: result.id, slug: result.slug, displayName: result.displayName }), { status: 201, headers: { "content-type": "application/json" } });
119
+ }
120
+ catch (err) {
121
+ if (err instanceof Error &&
122
+ err.code === "P2002") {
123
+ return new Response(JSON.stringify({ error: "SLUG_TAKEN", message: "A tenant with this slug already exists" }), { status: 409, headers: { "content-type": "application/json" } });
124
+ }
125
+ throw err;
126
+ }
127
+ }
128
+ /**
129
+ * GET /api/tenants/:id
130
+ * Returns the tenant. Caller must be an active member.
131
+ */
132
+ async handleGet(tenantId, auth, env) {
133
+ // GET /api/tenants/:id is a data endpoint — leak nothing about tenants
134
+ // outside the caller's scope. requireOwnTenant returns the same 404 as a
135
+ // missing tenant, so the response does not distinguish the two cases.
136
+ const denied = (0, auth_middleware_1.requireOwnTenant)(auth, tenantId);
137
+ if (denied)
138
+ return denied;
139
+ const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
140
+ const db = createPrisma(env);
141
+ const tenant = await db.tenant.findUnique({
142
+ where: { id: tenantId },
143
+ select: {
144
+ id: true,
145
+ slug: true,
146
+ displayName: true,
147
+ type: true,
148
+ status: true,
149
+ createdAt: true,
150
+ },
151
+ });
152
+ if (!tenant) {
153
+ return new Response(JSON.stringify({ error: "NOT_FOUND", message: "Tenant not found" }), { status: 404, headers: { "content-type": "application/json" } });
154
+ }
155
+ return new Response(JSON.stringify(tenant), {
156
+ status: 200,
157
+ headers: { "content-type": "application/json" },
158
+ });
159
+ }
160
+ /**
161
+ * PATCH /api/tenants/:id
162
+ * Updates displayName. Requires OWNER or ADMIN.
163
+ */
164
+ async handleUpdate(tenantId, request, auth, env) {
165
+ const denied = (0, auth_middleware_1.requireActiveTenant)(auth, tenantId) ??
166
+ (0, require_1.requireRole)(auth, "ADMIN");
167
+ if (denied)
168
+ return denied;
169
+ const { z } = await Promise.resolve().then(() => __importStar(require("zod")));
170
+ let body;
171
+ try {
172
+ body = await request.json();
173
+ }
174
+ catch {
175
+ return new Response(JSON.stringify({ error: "INVALID_JSON", message: "Request body must be valid JSON" }), { status: 400, headers: { "content-type": "application/json" } });
176
+ }
177
+ const schema = z.object({
178
+ displayName: z.string().min(1).max(100),
179
+ });
180
+ const parsed = schema.safeParse(body);
181
+ if (!parsed.success) {
182
+ return new Response(JSON.stringify({ error: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "Invalid input" }), { status: 400, headers: { "content-type": "application/json" } });
183
+ }
184
+ const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
185
+ const db = createPrisma(env);
186
+ const tenant = await db.tenant.findUnique({
187
+ where: { id: tenantId },
188
+ select: { id: true },
189
+ });
190
+ if (!tenant) {
191
+ return new Response(JSON.stringify({ error: "NOT_FOUND", message: "Tenant not found" }), { status: 404, headers: { "content-type": "application/json" } });
192
+ }
193
+ const updated = await db.tenant.update({
194
+ where: { id: tenantId },
195
+ data: { displayName: parsed.data.displayName },
196
+ select: { id: true, slug: true, displayName: true },
197
+ });
198
+ void auditEmitter.emit({
199
+ type: event_types_1.AuditEventType.TENANT_UPDATED,
200
+ tenantId,
201
+ actorUserId: auth.userId,
202
+ payload: { tenantId, displayName: parsed.data.displayName },
203
+ }, db);
204
+ return new Response(JSON.stringify(updated), {
205
+ status: 200,
206
+ headers: { "content-type": "application/json" },
207
+ });
208
+ }
209
+ /**
210
+ * GET /api/users/me/tenants
211
+ * Lists all active tenant memberships for the caller.
212
+ */
213
+ async handleListMyTenants(auth, env) {
214
+ const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
215
+ const db = createPrisma(env);
216
+ const memberships = await db.tenantMember.findMany({
217
+ where: { userId: auth.userId, status: "ACTIVE" },
218
+ include: {
219
+ tenant: {
220
+ select: {
221
+ id: true,
222
+ slug: true,
223
+ displayName: true,
224
+ type: true,
225
+ status: true,
226
+ },
227
+ },
228
+ },
229
+ orderBy: { joinedAt: "asc" },
230
+ });
231
+ const result = memberships.map((m) => ({
232
+ tenantId: m.tenantId,
233
+ role: m.role,
234
+ tenant: m.tenant,
235
+ }));
236
+ return new Response(JSON.stringify({ memberships: result }), {
237
+ status: 200,
238
+ headers: { "content-type": "application/json" },
239
+ });
240
+ }
241
+ /**
242
+ * POST /api/auth/switch-tenant
243
+ * Changes the user's active tenant. Invalidates DynamoDB claim cache so
244
+ * the next token refresh picks up the new activeTenantId.
245
+ */
246
+ async handleSwitchTenant(request, auth, env) {
247
+ const { z } = await Promise.resolve().then(() => __importStar(require("zod")));
248
+ let body;
249
+ try {
250
+ body = await request.json();
251
+ }
252
+ catch {
253
+ return new Response(JSON.stringify({ error: "INVALID_JSON", message: "Request body must be valid JSON" }), { status: 400, headers: { "content-type": "application/json" } });
254
+ }
255
+ const schema = z.object({ tenantId: z.string().min(1) });
256
+ const parsed = schema.safeParse(body);
257
+ if (!parsed.success) {
258
+ return new Response(JSON.stringify({ error: "VALIDATION_ERROR", message: "tenantId is required" }), { status: 400, headers: { "content-type": "application/json" } });
259
+ }
260
+ const { tenantId } = parsed.data;
261
+ const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
262
+ const db = createPrisma(env);
263
+ const membership = await db.tenantMember.findUnique({
264
+ where: {
265
+ tenantId_userId: { tenantId, userId: auth.userId },
266
+ },
267
+ select: { status: true },
268
+ });
269
+ if (!membership) {
270
+ return new Response(JSON.stringify({ error: "FORBIDDEN", message: "You are not a member of this tenant" }), { status: 403, headers: { "content-type": "application/json" } });
271
+ }
272
+ if (membership.status !== "ACTIVE") {
273
+ return new Response(JSON.stringify({ error: "FORBIDDEN", message: "Your membership in this tenant is not active" }), { status: 403, headers: { "content-type": "application/json" } });
274
+ }
275
+ // Look up tenant slug + role for cache write so the next pre-token-gen
276
+ // invocation reads the user's chosen tenant rather than re-running the
277
+ // first-org-then-personal heuristic.
278
+ const tenantWithRole = await db.tenantMember.findUnique({
279
+ where: { tenantId_userId: { tenantId, userId: auth.userId } },
280
+ select: {
281
+ role: true,
282
+ tenant: { select: { slug: true } },
283
+ },
284
+ });
285
+ // Persist the user's chosen tenant in the DDB claim cache so the next
286
+ // pre-token-generation invocation honors the choice rather than reverting
287
+ // to the first-org / personal-tenant heuristic.
288
+ try {
289
+ const cache = (0, claims_cache_1.createClaimsCacheFromEnv)();
290
+ if (tenantWithRole) {
291
+ await cache.invalidate(auth.cognitoSub);
292
+ await cache.put(auth.cognitoSub, {
293
+ userId: auth.userId,
294
+ globalRole: auth.globalRole,
295
+ activeTenantId: tenantId,
296
+ tenantSlug: tenantWithRole.tenant.slug,
297
+ tenantRole: tenantWithRole.role,
298
+ handle: auth.handle,
299
+ });
300
+ }
301
+ else {
302
+ await cache.invalidate(auth.cognitoSub);
303
+ }
304
+ }
305
+ catch {
306
+ // Cache write is best-effort: don't block the switch if DDB is
307
+ // unavailable. The TTL-based expiry will eventually correct stale data.
308
+ }
309
+ return new Response(JSON.stringify({ ok: true, tenantId }), { status: 200, headers: { "content-type": "application/json" } });
310
+ }
311
+ /**
312
+ * POST /api/tenants/:id/transfer-ownership
313
+ * Current OWNER hands off ownership to another active member.
314
+ * Both users' cache entries are invalidated.
315
+ */
316
+ async handleTransferOwnership(tenantId, request, auth, env) {
317
+ const activeTenantDenied = (0, auth_middleware_1.requireActiveTenant)(auth, tenantId);
318
+ if (activeTenantDenied)
319
+ return activeTenantDenied;
320
+ const roleDenied = (0, require_1.requireRole)(auth, "OWNER");
321
+ if (roleDenied)
322
+ return roleDenied;
323
+ const { z } = await Promise.resolve().then(() => __importStar(require("zod")));
324
+ let body;
325
+ try {
326
+ body = await request.json();
327
+ }
328
+ catch {
329
+ return new Response(JSON.stringify({ error: "INVALID_JSON", message: "Request body must be valid JSON" }), { status: 400, headers: { "content-type": "application/json" } });
330
+ }
331
+ const schema = z.object({ newOwnerUserId: z.string().min(1) });
332
+ const parsed = schema.safeParse(body);
333
+ if (!parsed.success) {
334
+ return new Response(JSON.stringify({ error: "VALIDATION_ERROR", message: "newOwnerUserId is required" }), { status: 400, headers: { "content-type": "application/json" } });
335
+ }
336
+ const { newOwnerUserId } = parsed.data;
337
+ if (newOwnerUserId === auth.userId) {
338
+ return new Response(JSON.stringify({ error: "VALIDATION_ERROR", message: "New owner must be a different user" }), { status: 400, headers: { "content-type": "application/json" } });
339
+ }
340
+ const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
341
+ const db = createPrisma(env);
342
+ const result = await (0, transfer_ownership_1.transferOwnership)({
343
+ db,
344
+ tenantId,
345
+ currentOwnerUserId: auth.userId,
346
+ newOwnerUserId,
347
+ });
348
+ if (!result.ok) {
349
+ if (result.code === "NOT_MEMBER" || result.code === "INACTIVE") {
350
+ return new Response(JSON.stringify({ error: "NOT_FOUND", message: "New owner must be an active member of this tenant" }), { status: 404, headers: { "content-type": "application/json" } });
351
+ }
352
+ if (result.code === "ALREADY_OWNER") {
353
+ return new Response(JSON.stringify({ error: "VALIDATION_ERROR", message: "New owner must be a different user" }), { status: 400, headers: { "content-type": "application/json" } });
354
+ }
355
+ return new Response(JSON.stringify({ error: "CONFLICT", message: "OWNER row not found" }), { status: 409, headers: { "content-type": "application/json" } });
356
+ }
357
+ void auditEmitter.emit({
358
+ type: event_types_1.AuditEventType.TENANT_OWNERSHIP_TRANSFERRED,
359
+ tenantId,
360
+ actorUserId: auth.userId,
361
+ payload: { tenantId, actorUserId: auth.userId, targetUserId: newOwnerUserId, oldRole: "OWNER", newRole: "ADMIN" },
362
+ }, db);
363
+ try {
364
+ const cache = (0, claims_cache_1.createClaimsCacheFromEnv)();
365
+ await Promise.all([
366
+ result.oldOwnerCognitoSub ? cache.invalidate(result.oldOwnerCognitoSub) : Promise.resolve(),
367
+ result.newOwnerCognitoSub ? cache.invalidate(result.newOwnerCognitoSub) : Promise.resolve(),
368
+ ]);
369
+ }
370
+ catch {
371
+ // Best-effort; don't block the transfer.
372
+ }
373
+ return new Response(JSON.stringify({ ok: true, newOwnerId: newOwnerUserId }), { status: 200, headers: { "content-type": "application/json" } });
374
+ }
375
+ }
376
+ exports.TenantHandler = TenantHandler;
377
+ //# sourceMappingURL=tenant-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-handler.js","sourceRoot":"","sources":["../../../src/lib/tenant/tenant-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Atomic OWNER swap.
3
+ *
4
+ * Single-OWNER invariant: exactly one TenantMember row in a tenant has
5
+ * `role = OWNER`. Promotion to OWNER happens only here (and at tenant
6
+ * creation). Both updates run in one Prisma transaction so a mid-transaction
7
+ * failure cannot leave the tenant with zero or two owners.
8
+ *
9
+ * Cache invalidation for both members runs after the transaction commits and
10
+ * is best-effort: a DDB hiccup must not roll back the role swap.
11
+ */
12
+ import type { PrismaClient, TenantMember } from "@prisma/client";
13
+ export type TransferResult = {
14
+ ok: true;
15
+ oldOwnerCognitoSub: string | null;
16
+ newOwnerCognitoSub: string | null;
17
+ } | {
18
+ ok: false;
19
+ code: "NOT_MEMBER" | "ALREADY_OWNER" | "INACTIVE" | "OWNER_NOT_FOUND";
20
+ };
21
+ interface TransferOwnershipInput {
22
+ db: PrismaClient;
23
+ tenantId: string;
24
+ currentOwnerUserId: string;
25
+ newOwnerUserId: string;
26
+ }
27
+ /**
28
+ * Validates the candidate, then swaps roles in one transaction.
29
+ *
30
+ * Validation runs inside the transaction so a concurrent `member-remove`
31
+ * cannot race with us — once we've SELECTed the candidate's status as ACTIVE,
32
+ * the subsequent UPDATE is part of the same TX and either both rows commit
33
+ * or neither does.
34
+ */
35
+ export declare function transferOwnership(input: TransferOwnershipInput): Promise<TransferResult>;
36
+ /** Convenience: find the OWNER row for a tenant. Used by self-demotion checks. */
37
+ export declare function findTenantOwner(db: PrismaClient, tenantId: string): Promise<TenantMember | null>;
38
+ export {};
39
+ //# sourceMappingURL=transfer-ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer-ownership.d.ts","sourceRoot":"","sources":["../../../src/lib/tenant/transfer-ownership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEjE,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAClF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,YAAY,GAAG,eAAe,GAAG,UAAU,GAAG,iBAAiB,CAAA;CAAE,CAAC;AAEzF,UAAU,sBAAsB;IAC9B,EAAE,EAAE,YAAY,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAyCzB;AAED,kFAAkF;AAClF,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAI9B"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * Atomic OWNER swap.
4
+ *
5
+ * Single-OWNER invariant: exactly one TenantMember row in a tenant has
6
+ * `role = OWNER`. Promotion to OWNER happens only here (and at tenant
7
+ * creation). Both updates run in one Prisma transaction so a mid-transaction
8
+ * failure cannot leave the tenant with zero or two owners.
9
+ *
10
+ * Cache invalidation for both members runs after the transaction commits and
11
+ * is best-effort: a DDB hiccup must not roll back the role swap.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.transferOwnership = transferOwnership;
15
+ exports.findTenantOwner = findTenantOwner;
16
+ /**
17
+ * Validates the candidate, then swaps roles in one transaction.
18
+ *
19
+ * Validation runs inside the transaction so a concurrent `member-remove`
20
+ * cannot race with us — once we've SELECTed the candidate's status as ACTIVE,
21
+ * the subsequent UPDATE is part of the same TX and either both rows commit
22
+ * or neither does.
23
+ */
24
+ async function transferOwnership(input) {
25
+ const { db, tenantId, currentOwnerUserId, newOwnerUserId } = input;
26
+ if (currentOwnerUserId === newOwnerUserId) {
27
+ return { ok: false, code: "ALREADY_OWNER" };
28
+ }
29
+ return db.$transaction(async (tx) => {
30
+ const candidate = await tx.tenantMember.findUnique({
31
+ where: { tenantId_userId: { tenantId, userId: newOwnerUserId } },
32
+ select: { status: true, user: { select: { cognitoSub: true } } },
33
+ });
34
+ if (!candidate)
35
+ return { ok: false, code: "NOT_MEMBER" };
36
+ if (candidate.status !== "ACTIVE")
37
+ return { ok: false, code: "INACTIVE" };
38
+ const currentOwner = await tx.tenantMember.findUnique({
39
+ where: { tenantId_userId: { tenantId, userId: currentOwnerUserId } },
40
+ select: { role: true, user: { select: { cognitoSub: true } } },
41
+ });
42
+ if (!currentOwner || currentOwner.role !== "OWNER") {
43
+ return { ok: false, code: "OWNER_NOT_FOUND" };
44
+ }
45
+ await tx.tenantMember.update({
46
+ where: { tenantId_userId: { tenantId, userId: currentOwnerUserId } },
47
+ data: { role: "ADMIN" },
48
+ });
49
+ await tx.tenantMember.update({
50
+ where: { tenantId_userId: { tenantId, userId: newOwnerUserId } },
51
+ data: { role: "OWNER" },
52
+ });
53
+ return {
54
+ ok: true,
55
+ oldOwnerCognitoSub: currentOwner.user.cognitoSub,
56
+ newOwnerCognitoSub: candidate.user.cognitoSub,
57
+ };
58
+ });
59
+ }
60
+ /** Convenience: find the OWNER row for a tenant. Used by self-demotion checks. */
61
+ async function findTenantOwner(db, tenantId) {
62
+ return db.tenantMember.findFirst({
63
+ where: { tenantId, role: "OWNER", status: "ACTIVE" },
64
+ });
65
+ }
66
+ //# sourceMappingURL=transfer-ownership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer-ownership.js","sourceRoot":"","sources":["../../../src/lib/tenant/transfer-ownership.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAuBH,8CA2CC;AAGD,0CAOC;AA7DD;;;;;;;GAOG;AACI,KAAK,UAAU,iBAAiB,CACrC,KAA6B;IAE7B,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IAEnE,IAAI,kBAAkB,KAAK,cAAc,EAAE,CAAC;QAC1C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IAC9C,CAAC;IAED,OAAO,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAA2B,EAAE;QAC3D,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC;YACjD,KAAK,EAAE,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE;YAChE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;SACjE,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QACzD,IAAI,SAAS,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAE1E,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC;YACpD,KAAK,EAAE,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE;YACpE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;SAC/D,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAChD,CAAC;QAED,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE;YACpE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;SACxB,CAAC,CAAC;QAEH,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,eAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE;YAChE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;SACxB,CAAC,CAAC;QAEH,OAAO;YACL,EAAE,EAAE,IAAI;YACR,kBAAkB,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU;YAChD,kBAAkB,EAAE,SAAS,CAAC,IAAI,CAAC,UAAU;SAC9C,CAAC;IACJ,CAAC,CAA4B,CAAC;AAChC,CAAC;AAED,kFAAkF;AAC3E,KAAK,UAAU,eAAe,CACnC,EAAgB,EAChB,QAAgB;IAEhB,OAAO,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC;QAC/B,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;KACrD,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * User handle derivation from email local-part (T2 — JIT provisioning).
3
+ *
4
+ * Strategy:
5
+ * 1. Take the local-part (everything before `@`).
6
+ * 2. Lowercase, strip any character that isn't `[a-z0-9_-]`.
7
+ * 3. Truncate to {@link HANDLE_MAX_BASE_LENGTH} to leave room for collision
8
+ * suffixes ("alice2" / "alice13") within the Cognito `custom:handle`
9
+ * attribute ceiling of 32 chars.
10
+ * 4. If empty after stripping (e.g., handle was all punctuation, or the
11
+ * email was malformed), fall back to {@link FALLBACK_HANDLE_PREFIX} +
12
+ * a short random suffix.
13
+ * 5. On collision, append a numeric suffix and try again, up to
14
+ * {@link MAX_COLLISION_ATTEMPTS}.
15
+ *
16
+ * The collision-check callback is injected so this module is pure and easy
17
+ * to test without Prisma. The lambda wires it to a `db.user.findFirst`.
18
+ */
19
+ export type HandleExistsCheck = (handle: string) => Promise<boolean>;
20
+ export declare function normalizeHandleBase(emailOrLocalPart: string | null | undefined): string;
21
+ /**
22
+ * Derives a unique handle for a new user from their email address.
23
+ *
24
+ * @param email - the user's email address
25
+ * @param exists - async callback that returns true if `handle` is already in
26
+ * use by some other user. Inject the Prisma lookup here.
27
+ */
28
+ export declare function deriveHandle(email: string | null | undefined, exists: HandleExistsCheck): Promise<string>;
29
+ //# sourceMappingURL=derive-handle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-handle.d.ts","sourceRoot":"","sources":["../../../src/lib/user/derive-handle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAErE,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CASvF;AAMD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /**
3
+ * User handle derivation from email local-part (T2 — JIT provisioning).
4
+ *
5
+ * Strategy:
6
+ * 1. Take the local-part (everything before `@`).
7
+ * 2. Lowercase, strip any character that isn't `[a-z0-9_-]`.
8
+ * 3. Truncate to {@link HANDLE_MAX_BASE_LENGTH} to leave room for collision
9
+ * suffixes ("alice2" / "alice13") within the Cognito `custom:handle`
10
+ * attribute ceiling of 32 chars.
11
+ * 4. If empty after stripping (e.g., handle was all punctuation, or the
12
+ * email was malformed), fall back to {@link FALLBACK_HANDLE_PREFIX} +
13
+ * a short random suffix.
14
+ * 5. On collision, append a numeric suffix and try again, up to
15
+ * {@link MAX_COLLISION_ATTEMPTS}.
16
+ *
17
+ * The collision-check callback is injected so this module is pure and easy
18
+ * to test without Prisma. The lambda wires it to a `db.user.findFirst`.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.normalizeHandleBase = normalizeHandleBase;
22
+ exports.deriveHandle = deriveHandle;
23
+ const HANDLE_MAX_BASE_LENGTH = 24;
24
+ const HANDLE_TOTAL_MAX = 32;
25
+ const MAX_COLLISION_ATTEMPTS = 100;
26
+ const FALLBACK_HANDLE_PREFIX = "user";
27
+ function normalizeHandleBase(emailOrLocalPart) {
28
+ if (!emailOrLocalPart)
29
+ return "";
30
+ const localPart = emailOrLocalPart.includes("@")
31
+ ? emailOrLocalPart.split("@")[0]
32
+ : emailOrLocalPart;
33
+ const cleaned = localPart
34
+ .toLowerCase()
35
+ .replace(/[^a-z0-9_-]/g, "");
36
+ return cleaned.slice(0, HANDLE_MAX_BASE_LENGTH);
37
+ }
38
+ function randomSuffix() {
39
+ return Math.floor(Math.random() * 9000 + 1000).toString();
40
+ }
41
+ /**
42
+ * Derives a unique handle for a new user from their email address.
43
+ *
44
+ * @param email - the user's email address
45
+ * @param exists - async callback that returns true if `handle` is already in
46
+ * use by some other user. Inject the Prisma lookup here.
47
+ */
48
+ async function deriveHandle(email, exists) {
49
+ let base = normalizeHandleBase(email);
50
+ if (!base) {
51
+ base = `${FALLBACK_HANDLE_PREFIX}${randomSuffix()}`.slice(0, HANDLE_MAX_BASE_LENGTH);
52
+ }
53
+ if (!(await exists(base)))
54
+ return base;
55
+ for (let suffix = 2; suffix <= MAX_COLLISION_ATTEMPTS; suffix++) {
56
+ const suffixStr = String(suffix);
57
+ const allowedBaseLen = HANDLE_TOTAL_MAX - suffixStr.length;
58
+ const truncatedBase = base.slice(0, allowedBaseLen);
59
+ const candidate = `${truncatedBase}${suffixStr}`;
60
+ if (!(await exists(candidate)))
61
+ return candidate;
62
+ }
63
+ return `${base.slice(0, HANDLE_TOTAL_MAX - 8)}${randomSuffix()}${randomSuffix().slice(0, 4)}`.slice(0, HANDLE_TOTAL_MAX);
64
+ }
65
+ //# sourceMappingURL=derive-handle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-handle.js","sourceRoot":"","sources":["../../../src/lib/user/derive-handle.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;AASH,kDASC;AAaD,oCAuBC;AApDD,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAClC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,sBAAsB,GAAG,GAAG,CAAC;AACnC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAItC,SAAgB,mBAAmB,CAAC,gBAA2C;IAC7E,IAAI,CAAC,gBAAgB;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC9C,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC,CAAC,gBAAgB,CAAC;IACrB,MAAM,OAAO,GAAG,SAAS;SACtB,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAC/B,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5D,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAChC,KAAgC,EAChC,MAAyB;IAEzB,IAAI,IAAI,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,GAAG,sBAAsB,GAAG,YAAY,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,IAAI,sBAAsB,EAAE,MAAM,EAAE,EAAE,CAAC;QAChE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,cAAc,GAAG,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC;QAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QACpD,MAAM,SAAS,GAAG,GAAG,aAAa,GAAG,SAAS,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;IACnD,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,GAAG,CAAC,CAAC,GAAG,YAAY,EAAE,GAAG,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CACjG,CAAC,EACD,gBAAgB,CACjB,CAAC;AACJ,CAAC"}
@@ -27,7 +27,17 @@ export declare class UserDeprovisioning {
27
27
  */
28
28
  suspendUser(userId: string, reason: DeprovisionReason, env: Env): Promise<void>;
29
29
  /**
30
- * Check if user is suspended
30
+ * Check if user is suspended.
31
+ *
32
+ * Fail-open is intentional and required: this is a best-effort hint used by
33
+ * non-critical paths (e.g. surfacing a banner to operators). The
34
+ * authoritative gate is the pre-token-generation Lambda, which already
35
+ * blocks token issuance for suspended users on the next refresh
36
+ * (see lambda/pre-token-generation.ts — the cache TTL bounds the
37
+ * window). Failing closed here would convert a transient RDS hiccup
38
+ * into a denial-of-service against legitimate users; the security
39
+ * properties hold via the pre-token path. Do not change to fail-closed
40
+ * without first moving the authoritative check off the RDS critical path.
31
41
  */
32
42
  isUserSuspended(userId: string, env: Env, region?: string): Promise<boolean>;
33
43
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"user-deprovisioning.d.ts","sourceRoot":"","sources":["../../src/lib/user-deprovisioning.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAElD,MAAM,WAAW,GAAG;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,MAAM,CAAS;gBAEX,GAAG,CAAC,EAAE,SAAS;IAK3B;;;OAGG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,iBAAiB,EACzB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC;IAwChB;;OAEG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,GAAG,EACR,MAAM,GAAE,MAAa,GACpB,OAAO,CAAC,OAAO,CAAC;IAqCnB;;OAEG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC;IAsChB;;;OAGG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,OAAO,CAAC;CAapB"}
1
+ {"version":3,"file":"user-deprovisioning.d.ts","sourceRoot":"","sources":["../../src/lib/user-deprovisioning.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAGlD,MAAM,WAAW,GAAG;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,MAAM,CAAS;gBAEX,GAAG,CAAC,EAAE,SAAS;IAK3B;;;OAGG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,iBAAiB,EACzB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC;IA0DhB;;;;;;;;;;;;OAYG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,GAAG,EACR,MAAM,GAAE,MAAa,GACpB,OAAO,CAAC,OAAO,CAAC;IAsCnB;;OAEG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC;IAsDhB;;;OAGG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,OAAO,CAAC;CAapB"}