@de-otio/trellis 0.6.1 → 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 +5 -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,248 @@
1
+ "use strict";
2
+ /**
3
+ * Refresh-token reuse detection (RFC 6819 §5.2.2.5, T9b-d).
4
+ *
5
+ * Each refresh-token JTI is recorded once. On refresh:
6
+ * - load the row by jti
7
+ * - if absent → unknown token; treat as suspect, deny
8
+ * - if `consumed` → REPLAY; revoke all sessions for that user via
9
+ * AdminUserGlobalSignOut and emit `auth.refresh_replay`
10
+ * - if `active` → mark consumed, issue new refresh with new jti
11
+ *
12
+ * Storage: AGENT_REFRESH_TABLE in DynamoDB. Same table also holds the
13
+ * agent-session metadata listed by `/api/users/me/agent-sessions`.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.recordAgentSession = recordAgentSession;
17
+ exports.consumeRefreshJti = consumeRefreshJti;
18
+ exports.handleRefreshReplay = handleRefreshReplay;
19
+ exports.rotateRefreshJti = rotateRefreshJti;
20
+ exports.listAgentSessions = listAgentSessions;
21
+ exports.revokeAgentSession = revokeAgentSession;
22
+ exports.getAgentSession = getAgentSession;
23
+ exports._deleteAgentSessionForTest = _deleteAgentSessionForTest;
24
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
25
+ const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
26
+ const ddb = new client_dynamodb_1.DynamoDBClient({
27
+ region: process.env.AWS_REGION || "us-east-1",
28
+ ...(process.env.DYNAMODB_ENDPOINT ? { endpoint: process.env.DYNAMODB_ENDPOINT } : {}),
29
+ });
30
+ function tableName() {
31
+ return (process.env.AGENT_REFRESH_TABLE ||
32
+ `${process.env.STAGE || "dev"}-trellis-agent-refresh`);
33
+ }
34
+ /** Initial record write at session creation (after approval). */
35
+ async function recordAgentSession(input) {
36
+ const now = Math.floor(Date.now() / 1000);
37
+ await ddb.send(new client_dynamodb_1.PutItemCommand({
38
+ TableName: tableName(),
39
+ Item: (0, util_dynamodb_1.marshall)({
40
+ pk: `s#${input.session.sessionId}`,
41
+ sk: "rec",
42
+ ...input.session,
43
+ gsi1pk: `u#${input.session.userId}`,
44
+ gsi1sk: `s#${input.session.sessionId}`,
45
+ }, { removeUndefinedValues: true }),
46
+ ConditionExpression: "attribute_not_exists(pk)",
47
+ }));
48
+ await ddb.send(new client_dynamodb_1.PutItemCommand({
49
+ TableName: tableName(),
50
+ Item: (0, util_dynamodb_1.marshall)({
51
+ pk: `j#${input.initialJti}`,
52
+ sk: "rec",
53
+ jti: input.initialJti,
54
+ sessionId: input.session.sessionId,
55
+ userId: input.session.userId,
56
+ cognitoSub: input.session.cognitoSub,
57
+ status: "active",
58
+ issuedAt: now,
59
+ }),
60
+ ConditionExpression: "attribute_not_exists(pk)",
61
+ }));
62
+ }
63
+ /**
64
+ * Validate a refresh-token JTI. Three outcomes:
65
+ * - "ok" → the jti was active; row is now flipped to consumed.
66
+ * - "replay" → jti was already consumed → caller must revoke session globally.
67
+ * - "unknown" → jti not present (foreign or expired); deny.
68
+ */
69
+ async function consumeRefreshJti(jti) {
70
+ try {
71
+ const out = await ddb.send(new client_dynamodb_1.UpdateItemCommand({
72
+ TableName: tableName(),
73
+ Key: (0, util_dynamodb_1.marshall)({ pk: `j#${jti}`, sk: "rec" }),
74
+ UpdateExpression: "SET #status = :consumed, consumedAt = :now",
75
+ ConditionExpression: "attribute_exists(pk) AND #status = :active",
76
+ ExpressionAttributeNames: { "#status": "status" },
77
+ ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
78
+ ":active": "active",
79
+ ":consumed": "consumed",
80
+ ":now": Math.floor(Date.now() / 1000),
81
+ }),
82
+ ReturnValues: "ALL_NEW",
83
+ }));
84
+ if (!out.Attributes)
85
+ return { outcome: "unknown" };
86
+ return { outcome: "ok", record: (0, util_dynamodb_1.unmarshall)(out.Attributes) };
87
+ }
88
+ catch (err) {
89
+ if (err instanceof client_dynamodb_1.ConditionalCheckFailedException) {
90
+ // Row exists but wasn't `active` — load to distinguish unknown vs replay.
91
+ const out = await ddb.send(new client_dynamodb_1.GetItemCommand({
92
+ TableName: tableName(),
93
+ Key: (0, util_dynamodb_1.marshall)({ pk: `j#${jti}`, sk: "rec" }),
94
+ }));
95
+ if (!out.Item)
96
+ return { outcome: "unknown" };
97
+ const row = (0, util_dynamodb_1.unmarshall)(out.Item);
98
+ return { outcome: "replay", record: row };
99
+ }
100
+ throw err;
101
+ }
102
+ }
103
+ /**
104
+ * On confirmed replay: revoke all sessions for the user, mark the session
105
+ * row revoked, emit `auth.refresh_replay`. The Cognito SDK call uses
106
+ * AdminUserGlobalSignOut to invalidate every refresh-derived token.
107
+ *
108
+ * Hardening (G4 CRITICAL-1, CRITICAL-2):
109
+ * - The Cognito username used for revocation is read directly from
110
+ * `jtiRecord.cognitoSub` (the value bound at session-creation time).
111
+ * Callers may not supply an alternate identity; this prevents the
112
+ * wrong account from being revoked if a caller forwards a request-
113
+ * scoped value here.
114
+ * - The audit event is emitted FIRST so a downstream Cognito or DDB
115
+ * failure cannot suppress the `auth.refresh_replay` signal. The
116
+ * mutation steps follow in order; each is wrapped so that audit
117
+ * emit completes even when a later step throws.
118
+ */
119
+ async function handleRefreshReplay(input) {
120
+ // Source the Cognito username from the stored jti record only.
121
+ const cognitoUsername = input.jtiRecord.cognitoSub;
122
+ // Step 1: emit the audit event before any mutation. This is the
123
+ // observability anchor — a replay must always produce a record even if
124
+ // the downstream revocation path fails part-way through.
125
+ await input.audit.emit({
126
+ type: "auth.refresh_replay",
127
+ tenantId: input.tenantId,
128
+ actorUserId: input.jtiRecord.userId,
129
+ payload: {
130
+ refreshJti: input.jtiRecord.jti,
131
+ cognitoUserId: cognitoUsername,
132
+ },
133
+ sourceIp: input.sourceIp,
134
+ agentSessionId: input.jtiRecord.sessionId,
135
+ });
136
+ // Step 2: tombstone the session row in DDB. We do this before the
137
+ // Cognito call so a Cognito failure still leaves the local record
138
+ // marked revoked.
139
+ await ddb.send(new client_dynamodb_1.UpdateItemCommand({
140
+ TableName: tableName(),
141
+ Key: (0, util_dynamodb_1.marshall)({ pk: `s#${input.jtiRecord.sessionId}`, sk: "rec" }),
142
+ UpdateExpression: "SET #status = :revoked, currentJti = :null, lastUsedAt = :now",
143
+ ExpressionAttributeNames: { "#status": "status" },
144
+ ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
145
+ ":revoked": "revoked",
146
+ ":null": null,
147
+ ":now": Math.floor(Date.now() / 1000),
148
+ }),
149
+ }));
150
+ // Step 3: invalidate refresh-derived tokens at the IdP. If this throws
151
+ // the local state is already consistent (audit emitted, row revoked)
152
+ // and the caller can retry the global sign-out idempotently.
153
+ await input.cognito.globalSignOut({
154
+ userPoolId: input.userPoolId,
155
+ cognitoUsername,
156
+ });
157
+ }
158
+ /**
159
+ * Issue a new refresh JTI for a session. The old JTI must already be
160
+ * consumed (caller flips it before calling). Updates the session row.
161
+ */
162
+ async function rotateRefreshJti(input) {
163
+ const now = Math.floor(Date.now() / 1000);
164
+ await ddb.send(new client_dynamodb_1.PutItemCommand({
165
+ TableName: tableName(),
166
+ Item: (0, util_dynamodb_1.marshall)({
167
+ pk: `j#${input.newJti}`,
168
+ sk: "rec",
169
+ jti: input.newJti,
170
+ sessionId: input.sessionId,
171
+ userId: input.userId,
172
+ cognitoSub: input.cognitoSub,
173
+ status: "active",
174
+ issuedAt: now,
175
+ }),
176
+ ConditionExpression: "attribute_not_exists(pk)",
177
+ }));
178
+ await ddb.send(new client_dynamodb_1.UpdateItemCommand({
179
+ TableName: tableName(),
180
+ Key: (0, util_dynamodb_1.marshall)({ pk: `s#${input.sessionId}`, sk: "rec" }),
181
+ UpdateExpression: "SET currentJti = :j, lastUsedAt = :n",
182
+ ConditionExpression: "attribute_exists(pk) AND #status = :active",
183
+ ExpressionAttributeNames: { "#status": "status" },
184
+ ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
185
+ ":j": input.newJti,
186
+ ":n": now,
187
+ ":active": "active",
188
+ }),
189
+ }));
190
+ }
191
+ /** List all active sessions for a user. Used by `/api/users/me/agent-sessions`. */
192
+ async function listAgentSessions(userId) {
193
+ const out = await ddb.send(new client_dynamodb_1.QueryCommand({
194
+ TableName: tableName(),
195
+ IndexName: "gsi1",
196
+ KeyConditionExpression: "gsi1pk = :u",
197
+ ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({ ":u": `u#${userId}` }),
198
+ }));
199
+ return (out.Items ?? [])
200
+ .map((it) => (0, util_dynamodb_1.unmarshall)(it))
201
+ .filter((r) => r.status === "active")
202
+ .map(({ ...rec }) => rec);
203
+ }
204
+ /** Revoke a session by id; caller must verify the session belongs to the user. */
205
+ async function revokeAgentSession(input) {
206
+ await input.cognito.globalSignOut({
207
+ userPoolId: input.userPoolId,
208
+ cognitoUsername: input.cognitoUsername,
209
+ });
210
+ await ddb.send(new client_dynamodb_1.UpdateItemCommand({
211
+ TableName: tableName(),
212
+ Key: (0, util_dynamodb_1.marshall)({ pk: `s#${input.sessionId}`, sk: "rec" }),
213
+ UpdateExpression: "SET #status = :revoked, currentJti = :null, lastUsedAt = :now",
214
+ ConditionExpression: "attribute_exists(pk)",
215
+ ExpressionAttributeNames: { "#status": "status" },
216
+ ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
217
+ ":revoked": "revoked",
218
+ ":null": null,
219
+ ":now": Math.floor(Date.now() / 1000),
220
+ }),
221
+ }));
222
+ await input.audit.emit({
223
+ type: "auth.agent_session.revoked",
224
+ tenantId: input.tenantId,
225
+ actorUserId: input.actorUserId,
226
+ payload: { cognitoUserId: input.cognitoUsername },
227
+ sourceIp: input.sourceIp,
228
+ agentSessionId: input.sessionId,
229
+ });
230
+ }
231
+ /** Look up a session by id (auth check helper). */
232
+ async function getAgentSession(sessionId) {
233
+ const out = await ddb.send(new client_dynamodb_1.GetItemCommand({
234
+ TableName: tableName(),
235
+ Key: (0, util_dynamodb_1.marshall)({ pk: `s#${sessionId}`, sk: "rec" }),
236
+ }));
237
+ if (!out.Item)
238
+ return null;
239
+ return (0, util_dynamodb_1.unmarshall)(out.Item);
240
+ }
241
+ /** Test-only: helper to clear a session row directly. */
242
+ async function _deleteAgentSessionForTest(sessionId) {
243
+ await ddb.send(new client_dynamodb_1.DeleteItemCommand({
244
+ TableName: tableName(),
245
+ Key: (0, util_dynamodb_1.marshall)({ pk: `s#${sessionId}`, sk: "rec" }),
246
+ }));
247
+ }
248
+ //# sourceMappingURL=refresh-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-detection.js","sourceRoot":"","sources":["../../../src/lib/oauth/refresh-detection.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AA0EH,gDAsCC;AAQD,8CAqCC;AAkBD,kDAkDC;AAMD,4CAsCC;AAGD,8CAaC;AAGD,gDAsCC;AAGD,0CASC;AAGD,gEAOC;AA1VD,8DAQkC;AAClC,0DAA8D;AAkD9D,MAAM,GAAG,GAAG,IAAI,gCAAc,CAAC;IAC7B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;IAC7C,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CACtF,CAAC,CAAC;AAEH,SAAS,SAAS;IAChB,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC/B,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,wBAAwB,CACtD,CAAC;AACJ,CAAC;AAED,iEAAiE;AAC1D,KAAK,UAAU,kBAAkB,CAAC,KAGxC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,gCAAc,CAAC;QACjB,SAAS,EAAE,SAAS,EAAE;QACtB,IAAI,EAAE,IAAA,wBAAQ,EACZ;YACE,EAAE,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE;YAClC,EAAE,EAAE,KAAK;YACT,GAAG,KAAK,CAAC,OAAO;YAChB,MAAM,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE;YACnC,MAAM,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE;SACvC,EACD,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAChC;QACD,mBAAmB,EAAE,0BAA0B;KAChD,CAAC,CACH,CAAC;IAEF,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,gCAAc,CAAC;QACjB,SAAS,EAAE,SAAS,EAAE;QACtB,IAAI,EAAE,IAAA,wBAAQ,EAAC;YACb,EAAE,EAAE,KAAK,KAAK,CAAC,UAAU,EAAE;YAC3B,EAAE,EAAE,KAAK;YACT,GAAG,EAAE,KAAK,CAAC,UAAU;YACrB,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS;YAClC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;YAC5B,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU;YACpC,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,GAAG;SACd,CAAC;QACF,mBAAmB,EAAE,0BAA0B;KAChD,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,iBAAiB,CAAC,GAAW;IAIjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CACxB,IAAI,mCAAiB,CAAC;YACpB,SAAS,EAAE,SAAS,EAAE;YACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;YAC5C,gBAAgB,EAAE,4CAA4C;YAC9D,mBAAmB,EAAE,4CAA4C;YACjE,wBAAwB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;YACjD,yBAAyB,EAAE,IAAA,wBAAQ,EAAC;gBAClC,SAAS,EAAE,QAAQ;gBACnB,WAAW,EAAE,UAAU;gBACvB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;aACtC,CAAC;YACF,YAAY,EAAE,SAAS;SACxB,CAAC,CACH,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,UAAU;YAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAA,0BAAU,EAAC,GAAG,CAAC,UAAU,CAAqB,EAAE,CAAC;IACnF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,iDAA+B,EAAE,CAAC;YACnD,0EAA0E;YAC1E,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CACxB,IAAI,gCAAc,CAAC;gBACjB,SAAS,EAAE,SAAS,EAAE;gBACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;aAC7C,CAAC,CACH,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,IAAI;gBAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,IAAA,0BAAU,EAAC,GAAG,CAAC,IAAI,CAAqB,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QAC5C,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACI,KAAK,UAAU,mBAAmB,CAAC,KAOzC;IACC,+DAA+D;IAC/D,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC;IAEnD,gEAAgE;IAChE,uEAAuE;IACvE,yDAAyD;IACzD,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;QACrB,IAAI,EAAE,qBAAqB;QAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM;QACnC,OAAO,EAAE;YACP,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG;YAC/B,aAAa,EAAE,eAAe;SAC/B;QACD,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS;KAC1C,CAAC,CAAC;IAEH,kEAAkE;IAClE,kEAAkE;IAClE,kBAAkB;IAClB,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,mCAAiB,CAAC;QACpB,SAAS,EAAE,SAAS,EAAE;QACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QAClE,gBAAgB,EAAE,+DAA+D;QACjF,wBAAwB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QACjD,yBAAyB,EAAE,IAAA,wBAAQ,EAAC;YAClC,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;SACtC,CAAC;KACH,CAAC,CACH,CAAC;IAEF,uEAAuE;IACvE,qEAAqE;IACrE,6DAA6D;IAC7D,MAAM,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;QAChC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,eAAe;KAChB,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,gBAAgB,CAAC,KAKtC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,gCAAc,CAAC;QACjB,SAAS,EAAE,SAAS,EAAE;QACtB,IAAI,EAAE,IAAA,wBAAQ,EAAC;YACb,EAAE,EAAE,KAAK,KAAK,CAAC,MAAM,EAAE;YACvB,EAAE,EAAE,KAAK;YACT,GAAG,EAAE,KAAK,CAAC,MAAM;YACjB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,GAAG;SACd,CAAC;QACF,mBAAmB,EAAE,0BAA0B;KAChD,CAAC,CACH,CAAC;IAEF,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,mCAAiB,CAAC;QACpB,SAAS,EAAE,SAAS,EAAE;QACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QACxD,gBAAgB,EAAE,sCAAsC;QACxD,mBAAmB,EAAE,4CAA4C;QACjE,wBAAwB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QACjD,yBAAyB,EAAE,IAAA,wBAAQ,EAAC;YAClC,IAAI,EAAE,KAAK,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG;YACT,SAAS,EAAE,QAAQ;SACpB,CAAC;KACH,CAAC,CACH,CAAC;AACJ,CAAC;AAED,mFAAmF;AAC5E,KAAK,UAAU,iBAAiB,CAAC,MAAc;IACpD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CACxB,IAAI,8BAAY,CAAC;QACf,SAAS,EAAE,SAAS,EAAE;QACtB,SAAS,EAAE,MAAM;QACjB,sBAAsB,EAAE,aAAa;QACrC,yBAAyB,EAAE,IAAA,wBAAQ,EAAC,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC;KAC7D,CAAC,CACH,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;SACrB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAA,0BAAU,EAAC,EAAE,CAA8D,CAAC;SACxF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;SACpC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,kFAAkF;AAC3E,KAAK,UAAU,kBAAkB,CAAC,KASxC;IACC,MAAM,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;QAChC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC,CAAC,CAAC;IAEH,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,mCAAiB,CAAC;QACpB,SAAS,EAAE,SAAS,EAAE;QACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;QACxD,gBAAgB,EAAE,+DAA+D;QACjF,mBAAmB,EAAE,sBAAsB;QAC3C,wBAAwB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QACjD,yBAAyB,EAAE,IAAA,wBAAQ,EAAC;YAClC,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;SACtC,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;QACrB,IAAI,EAAE,4BAA4B;QAClC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,EAAE,aAAa,EAAE,KAAK,CAAC,eAAe,EAAE;QACjD,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,cAAc,EAAE,KAAK,CAAC,SAAS;KAChC,CAAC,CAAC;AACL,CAAC;AAED,mDAAmD;AAC5C,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CACxB,IAAI,gCAAc,CAAC;QACjB,SAAS,EAAE,SAAS,EAAE;QACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;KACnD,CAAC,CACH,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,IAAA,0BAAU,EAAC,GAAG,CAAC,IAAI,CAAuB,CAAC;AACpD,CAAC;AAED,yDAAyD;AAClD,KAAK,UAAU,0BAA0B,CAAC,SAAiB;IAChE,MAAM,GAAG,CAAC,IAAI,CACZ,IAAI,mCAAiB,CAAC;QACpB,SAAS,EAAE,SAAS,EAAE;QACtB,GAAG,EAAE,IAAA,wBAAQ,EAAC,EAAE,EAAE,EAAE,KAAK,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;KACnD,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * OpenAPI 3.1 Document Generator
3
+ *
4
+ * Introspects the trellis route registry to emit a valid OpenAPI 3.1 document.
5
+ * Coverage priority: federation endpoints (T3–T8) plus the discovery surface.
6
+ * For routes whose Zod schemas aren't directly accessible, minimal `{}` schemas
7
+ * are emitted — validity over richness.
8
+ */
9
+ import type { Route } from "../routes/types";
10
+ export interface OpenApiDocument {
11
+ openapi: "3.1.0";
12
+ info: {
13
+ title: string;
14
+ version: string;
15
+ description?: string;
16
+ };
17
+ paths: Record<string, OpenApiPathItem>;
18
+ components?: {
19
+ schemas?: Record<string, unknown>;
20
+ };
21
+ }
22
+ interface OpenApiPathItem {
23
+ [method: string]: OpenApiOperation;
24
+ }
25
+ interface OpenApiOperation {
26
+ summary?: string;
27
+ description?: string;
28
+ operationId?: string;
29
+ parameters?: OpenApiParameter[];
30
+ requestBody?: {
31
+ required?: boolean;
32
+ content: Record<string, {
33
+ schema: unknown;
34
+ }>;
35
+ };
36
+ responses: Record<string, {
37
+ description: string;
38
+ content?: Record<string, {
39
+ schema: unknown;
40
+ }>;
41
+ }>;
42
+ tags?: string[];
43
+ }
44
+ interface OpenApiParameter {
45
+ name: string;
46
+ in: "path" | "query" | "header";
47
+ required: boolean;
48
+ schema: {
49
+ type: string;
50
+ };
51
+ description?: string;
52
+ }
53
+ /**
54
+ * Convert a route pattern to an OpenAPI path string.
55
+ *
56
+ * Supports:
57
+ * - Exact strings: "/health" → "/health"
58
+ * - Express-style params: "/api/tenants/:id" → "/api/tenants/{id}"
59
+ * - Simple named-group regex: /^\/api\/tenants\/([^/]+)\/domains$/ →
60
+ * "/api/tenants/{param0}/domains"
61
+ * - Wildcards and complex regex are skipped (returns null)
62
+ */
63
+ export declare function routePatternToPath(pattern: Route["path"]): string | null;
64
+ /**
65
+ * Generate an OpenAPI 3.1 document from the trellis route registry.
66
+ *
67
+ * Hardening (G4 MEDIUM-3): the generator emits ONLY routes flagged
68
+ * `publicSpec: true`. Routes without the flag (posts, comments, media,
69
+ * ActivityPub, extension-defined routes, etc.) are excluded so the
70
+ * public spec is a curated agent-integration surface rather than a
71
+ * reflection of every registered handler.
72
+ *
73
+ * Routes that cannot be represented as OpenAPI paths (wildcard handlers,
74
+ * complex regex) are silently skipped.
75
+ */
76
+ export declare function generateOpenApiDoc(routes: Route[]): OpenApiDocument;
77
+ export {};
78
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../src/lib/openapi/generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAI7C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACH;AAED,UAAU,eAAe;IACvB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACpC;AAED,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC9C,CAAC;IACF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAClG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CA+DxE;AAwDD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAmCnE"}
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ /**
3
+ * OpenAPI 3.1 Document Generator
4
+ *
5
+ * Introspects the trellis route registry to emit a valid OpenAPI 3.1 document.
6
+ * Coverage priority: federation endpoints (T3–T8) plus the discovery surface.
7
+ * For routes whose Zod schemas aren't directly accessible, minimal `{}` schemas
8
+ * are emitted — validity over richness.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.routePatternToPath = routePatternToPath;
12
+ exports.generateOpenApiDoc = generateOpenApiDoc;
13
+ // ── Constants ─────────────────────────────────────────────────────────────────
14
+ const API_TITLE = "Trellis API";
15
+ const API_VERSION = "0.7.0";
16
+ const API_DESCRIPTION = "Social-network core API. Discovery surfaces, federation management (T3–T8), and entity/social graph endpoints.";
17
+ /** Methods that support a request body */
18
+ const BODY_METHODS = new Set(["post", "put", "patch"]);
19
+ // Tags derived from path prefix for grouping
20
+ const FEDERATION_PREFIXES = [
21
+ [/^\/api\/tenants\/[^/]+\/domains/, "tenant-domains"],
22
+ [/^\/api\/tenants\/[^/]+\/identity-provider/, "tenant-idp"],
23
+ [/^\/api\/tenants\/[^/]+\/members/, "tenant-members"],
24
+ [/^\/api\/tenants\/[^/]+\/role-mappings/, "tenant-role-mappings"],
25
+ [/^\/api\/tenants\/[^/]+\/audit/, "tenant-audit"],
26
+ [/^\/api\/tenants/, "tenants"],
27
+ [/^\/api\/auth\/discover/, "auth-discover"],
28
+ [/^\/(llms\.txt|openapi\.json|security\.txt)/, "discovery"],
29
+ [/^\/health/, "health"],
30
+ ];
31
+ function deriveTag(path) {
32
+ for (const [pattern, tag] of FEDERATION_PREFIXES) {
33
+ if (pattern.test(path))
34
+ return tag;
35
+ }
36
+ return "other";
37
+ }
38
+ // ── Path normalisation ─────────────────────────────────────────────────────────
39
+ /**
40
+ * Convert a route pattern to an OpenAPI path string.
41
+ *
42
+ * Supports:
43
+ * - Exact strings: "/health" → "/health"
44
+ * - Express-style params: "/api/tenants/:id" → "/api/tenants/{id}"
45
+ * - Simple named-group regex: /^\/api\/tenants\/([^/]+)\/domains$/ →
46
+ * "/api/tenants/{param0}/domains"
47
+ * - Wildcards and complex regex are skipped (returns null)
48
+ */
49
+ function routePatternToPath(pattern) {
50
+ if (typeof pattern === "string") {
51
+ if (pattern === "*")
52
+ return null;
53
+ // Convert express :param style
54
+ return pattern.replace(/:([^/]+)/g, "{$1}");
55
+ }
56
+ if (pattern instanceof RegExp) {
57
+ const src = pattern.source;
58
+ // Skip wildcard-only patterns
59
+ if (src === ".*" || src === "^.*$")
60
+ return null;
61
+ // Strip anchors
62
+ let s = src.replace(/^\^/, "").replace(/\$$/, "");
63
+ // Unescape forward slashes
64
+ s = s.replace(/\\\//g, "/");
65
+ // Replace capture groups with positional placeholders.
66
+ // We walk character-by-character to correctly handle character classes
67
+ // like `([^/]+)` which contain `]` that would fool a naive regex.
68
+ let paramIndex = 0;
69
+ let result = "";
70
+ let i = 0;
71
+ while (i < s.length) {
72
+ if (s[i] === "(") {
73
+ // Scan to the matching closing paren, skipping over [...] classes
74
+ let depth = 1;
75
+ i++;
76
+ while (i < s.length && depth > 0) {
77
+ if (s[i] === "[") {
78
+ // Skip character class entirely
79
+ i++;
80
+ while (i < s.length && s[i] !== "]")
81
+ i++;
82
+ i++; // skip ']'
83
+ }
84
+ else if (s[i] === "(") {
85
+ depth++;
86
+ i++;
87
+ }
88
+ else if (s[i] === ")") {
89
+ depth--;
90
+ i++;
91
+ }
92
+ else {
93
+ i++;
94
+ }
95
+ }
96
+ result += `{param${paramIndex++}}`;
97
+ }
98
+ else {
99
+ result += s[i];
100
+ i++;
101
+ }
102
+ }
103
+ s = result;
104
+ // Bail out if any remaining regex metacharacters.
105
+ // Note: {param0} placeholders are intentional OpenAPI path parameters, so
106
+ // we only reject metacharacters that appear outside of {...} placeholders.
107
+ const withoutPlaceholders = s.replace(/\{param\d+\}/g, "");
108
+ if (/[.*+?^${}()|[\]\\]/.test(withoutPlaceholders))
109
+ return null;
110
+ return s || null;
111
+ }
112
+ return null;
113
+ }
114
+ // ── Parameter extraction ───────────────────────────────────────────────────────
115
+ function extractPathParams(openApiPath) {
116
+ const params = [];
117
+ const re = /\{([^}]+)\}/g;
118
+ let m;
119
+ while ((m = re.exec(openApiPath)) !== null) {
120
+ params.push({
121
+ name: m[1],
122
+ in: "path",
123
+ required: true,
124
+ schema: { type: "string" },
125
+ });
126
+ }
127
+ return params;
128
+ }
129
+ // ── Operation builder ─────────────────────────────────────────────────────────
130
+ function buildOperation(route, method, openApiPath) {
131
+ const params = extractPathParams(openApiPath);
132
+ const tag = deriveTag(openApiPath);
133
+ const op = {
134
+ summary: route.description ?? `${method.toUpperCase()} ${openApiPath}`,
135
+ operationId: `${method}_${openApiPath.replace(/[^a-zA-Z0-9]/g, "_")}`,
136
+ tags: [tag],
137
+ parameters: params.length > 0 ? params : undefined,
138
+ responses: {
139
+ "200": { description: "Success" },
140
+ "400": { description: "Bad request" },
141
+ "401": { description: "Unauthorized" },
142
+ "500": { description: "Internal server error" },
143
+ },
144
+ };
145
+ if (BODY_METHODS.has(method)) {
146
+ op.requestBody = {
147
+ required: false,
148
+ content: {
149
+ "application/json": { schema: {} },
150
+ },
151
+ };
152
+ }
153
+ return op;
154
+ }
155
+ // ── Main generator ─────────────────────────────────────────────────────────────
156
+ /**
157
+ * Generate an OpenAPI 3.1 document from the trellis route registry.
158
+ *
159
+ * Hardening (G4 MEDIUM-3): the generator emits ONLY routes flagged
160
+ * `publicSpec: true`. Routes without the flag (posts, comments, media,
161
+ * ActivityPub, extension-defined routes, etc.) are excluded so the
162
+ * public spec is a curated agent-integration surface rather than a
163
+ * reflection of every registered handler.
164
+ *
165
+ * Routes that cannot be represented as OpenAPI paths (wildcard handlers,
166
+ * complex regex) are silently skipped.
167
+ */
168
+ function generateOpenApiDoc(routes) {
169
+ const paths = {};
170
+ for (const route of routes) {
171
+ if (route.publicSpec !== true)
172
+ continue;
173
+ const openApiPath = routePatternToPath(route.path);
174
+ if (!openApiPath)
175
+ continue;
176
+ const rawMethods = route.method ?? "GET";
177
+ const methods = Array.isArray(rawMethods) ? rawMethods : [rawMethods];
178
+ for (const rawMethod of methods) {
179
+ if (rawMethod === "*")
180
+ continue;
181
+ const method = rawMethod.toLowerCase();
182
+ if (!paths[openApiPath]) {
183
+ paths[openApiPath] = {};
184
+ }
185
+ paths[openApiPath][method] = buildOperation(route, method, openApiPath);
186
+ }
187
+ }
188
+ return {
189
+ openapi: "3.1.0",
190
+ info: {
191
+ title: API_TITLE,
192
+ version: API_VERSION,
193
+ description: API_DESCRIPTION,
194
+ },
195
+ paths,
196
+ components: {
197
+ schemas: {},
198
+ },
199
+ };
200
+ }
201
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../src/lib/openapi/generator.ts"],"names":[],"mappings":"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"}
@@ -43,7 +43,7 @@ export declare class PostHandler {
43
43
  *
44
44
  * PREPARATORY: Uses DataRouter for region-aware post creation.
45
45
  */
46
- createPost(request: Request, session: Session, env: Env, requestContext: RequestContext): Promise<Response>;
46
+ createPost(request: Request, session: Session, env: Env, requestContext: RequestContext, activeTenantId: string): Promise<Response>;
47
47
  /**
48
48
  * Delete a post (soft delete)
49
49
  *
@@ -1 +1 @@
1
- {"version":3,"file":"post-handler.d.ts","sourceRoot":"","sources":["../../src/lib/post-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,4BAA4B,CAAC;AAWzF,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAErE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,GAAG;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,WAAW,CAAC;IAClC,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAChC,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,SAAS,CAAC;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,GAAG,CAAC,EAAE,SAAS;IAK3B;;;;OAIG;IACG,UAAU,CACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,QAAQ,CAAC;IA6gCpB;;;;OAIG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,QAAQ,CAAC;IA8HpB;;;;;;;;;;;;;;;;OAgBG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,QAAQ,CAAC;IAuXpB;;OAEG;YACW,mBAAmB;IAkBjC;;;;OAIG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,QAAQ,CAAC;IAwEpB;;;;OAIG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,QAAQ,CAAC;IA2EpB;;;;OAIG;YACW,mBAAmB;CAiBlC"}
1
+ {"version":3,"file":"post-handler.d.ts","sourceRoot":"","sources":["../../src/lib/post-handler.ts"],"names":[],"mappings":"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"}
@@ -56,7 +56,7 @@ class PostHandler {
56
56
  *
57
57
  * PREPARATORY: Uses DataRouter for region-aware post creation.
58
58
  */
59
- async createPost(request, session, env, requestContext) {
59
+ async createPost(request, session, env, requestContext, activeTenantId) {
60
60
  try {
61
61
  // PREPARATORY: Check if post creation is enabled for this region
62
62
  // Note: Post creation is always enabled by default, but can be disabled via feature flags
@@ -367,16 +367,10 @@ class PostHandler {
367
367
  if (taxonomyTags.length > 0) {
368
368
  try {
369
369
  const { TaxonomyHandler } = await Promise.resolve().then(() => __importStar(require("./taxonomy-handler")));
370
- const { getRequestContext } = await Promise.resolve().then(() => __importStar(require("./tenant-context")));
371
- const { createRequestContext } = await Promise.resolve().then(() => __importStar(require("./request-context")));
372
370
  const { getWrappedDatabase } = await Promise.resolve().then(() => __importStar(require("./database-wrapper-helper")));
373
- // Get tenant ID
374
- const ctx = await createRequestContext(request, env);
375
- const tenantCtx = await getRequestContext(request, ctx.session || null);
376
- const tenantId = tenantCtx.tenant?.id || "trellis";
377
- // Get database and taxonomy handler
371
+ // Get database and taxonomy handler scoped to caller's active tenant
378
372
  const db = getWrappedDatabase(region, env, request);
379
- const taxonomyHandler = new TaxonomyHandler(db, tenantId, env.TAXONOMY_CACHE_KV);
373
+ const taxonomyHandler = new TaxonomyHandler(db, activeTenantId, env.TAXONOMY_CACHE_KV);
380
374
  // Add taxonomy tags
381
375
  await taxonomyHandler.addPostTaxonomyTags(post.id, taxonomyTags, session.userId);
382
376
  }
@@ -624,14 +618,9 @@ class PostHandler {
624
618
  if (taxonomyTags.length > 0) {
625
619
  try {
626
620
  const { TaxonomyHandler } = await Promise.resolve().then(() => __importStar(require("./taxonomy-handler")));
627
- const { getRequestContext } = await Promise.resolve().then(() => __importStar(require("./tenant-context")));
628
- const { createRequestContext } = await Promise.resolve().then(() => __importStar(require("./request-context")));
629
621
  const { getWrappedDatabase } = await Promise.resolve().then(() => __importStar(require("./database-wrapper-helper")));
630
- const ctx = await createRequestContext(request, env);
631
- const tenantCtx = await getRequestContext(request, ctx.session || null);
632
- const tenantId = tenantCtx.tenant?.id || "trellis";
633
622
  const db = getWrappedDatabase(region, env, request);
634
- const taxonomyHandler = new TaxonomyHandler(db, tenantId, env.TAXONOMY_CACHE_KV);
623
+ const taxonomyHandler = new TaxonomyHandler(db, activeTenantId, env.TAXONOMY_CACHE_KV);
635
624
  const tags = await taxonomyHandler.getPostTaxonomyTags(post.id);
636
625
  taxonomyTagsResponse = tags.map((t) => ({
637
626
  taxonId: t.taxonId,