@antasphere/chassis-server 1.0.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 (798) hide show
  1. package/LICENSE +82 -0
  2. package/dist/accounts/deletion.d.ts +163 -0
  3. package/dist/accounts/deletion.d.ts.map +1 -0
  4. package/dist/accounts/deletion.js +360 -0
  5. package/dist/accounts/deletion.js.map +1 -0
  6. package/dist/accounts/erasure-log.d.ts +66 -0
  7. package/dist/accounts/erasure-log.d.ts.map +1 -0
  8. package/dist/accounts/erasure-log.js +117 -0
  9. package/dist/accounts/erasure-log.js.map +1 -0
  10. package/dist/accounts/index.d.ts +6 -0
  11. package/dist/accounts/index.d.ts.map +1 -0
  12. package/dist/accounts/index.js +6 -0
  13. package/dist/accounts/index.js.map +1 -0
  14. package/dist/accounts/mint-refusal.d.ts +47 -0
  15. package/dist/accounts/mint-refusal.d.ts.map +1 -0
  16. package/dist/accounts/mint-refusal.js +59 -0
  17. package/dist/accounts/mint-refusal.js.map +1 -0
  18. package/dist/accounts/signup-duplicate.d.ts +14 -0
  19. package/dist/accounts/signup-duplicate.d.ts.map +1 -0
  20. package/dist/accounts/signup-duplicate.js +25 -0
  21. package/dist/accounts/signup-duplicate.js.map +1 -0
  22. package/dist/accounts/superadmin.d.ts +27 -0
  23. package/dist/accounts/superadmin.d.ts.map +1 -0
  24. package/dist/accounts/superadmin.js +46 -0
  25. package/dist/accounts/superadmin.js.map +1 -0
  26. package/dist/api/apikeys.d.ts +14 -0
  27. package/dist/api/apikeys.d.ts.map +1 -0
  28. package/dist/api/apikeys.js +124 -0
  29. package/dist/api/apikeys.js.map +1 -0
  30. package/dist/api/audit.d.ts +4 -0
  31. package/dist/api/audit.d.ts.map +1 -0
  32. package/dist/api/audit.js +75 -0
  33. package/dist/api/audit.js.map +1 -0
  34. package/dist/api/break-glass.d.ts +48 -0
  35. package/dist/api/break-glass.d.ts.map +1 -0
  36. package/dist/api/break-glass.js +217 -0
  37. package/dist/api/break-glass.js.map +1 -0
  38. package/dist/api/cli-auth.d.ts +84 -0
  39. package/dist/api/cli-auth.d.ts.map +1 -0
  40. package/dist/api/cli-auth.js +177 -0
  41. package/dist/api/cli-auth.js.map +1 -0
  42. package/dist/api/create-api.d.ts +123 -0
  43. package/dist/api/create-api.d.ts.map +1 -0
  44. package/dist/api/create-api.js +1165 -0
  45. package/dist/api/create-api.js.map +1 -0
  46. package/dist/api/demo-passes.d.ts +45 -0
  47. package/dist/api/demo-passes.d.ts.map +1 -0
  48. package/dist/api/demo-passes.js +143 -0
  49. package/dist/api/demo-passes.js.map +1 -0
  50. package/dist/api/errors.d.ts +5 -0
  51. package/dist/api/errors.d.ts.map +1 -0
  52. package/dist/api/errors.js +5 -0
  53. package/dist/api/errors.js.map +1 -0
  54. package/dist/api/export.d.ts +63 -0
  55. package/dist/api/export.d.ts.map +1 -0
  56. package/dist/api/export.js +393 -0
  57. package/dist/api/export.js.map +1 -0
  58. package/dist/api/files.d.ts +40 -0
  59. package/dist/api/files.d.ts.map +1 -0
  60. package/dist/api/files.js +150 -0
  61. package/dist/api/files.js.map +1 -0
  62. package/dist/api/index.d.ts +17 -0
  63. package/dist/api/index.d.ts.map +1 -0
  64. package/dist/api/index.js +17 -0
  65. package/dist/api/index.js.map +1 -0
  66. package/dist/api/invitations.d.ts +50 -0
  67. package/dist/api/invitations.d.ts.map +1 -0
  68. package/dist/api/invitations.js +313 -0
  69. package/dist/api/invitations.js.map +1 -0
  70. package/dist/api/members.d.ts +25 -0
  71. package/dist/api/members.d.ts.map +1 -0
  72. package/dist/api/members.js +522 -0
  73. package/dist/api/members.js.map +1 -0
  74. package/dist/api/onboarding.d.ts +26 -0
  75. package/dist/api/onboarding.d.ts.map +1 -0
  76. package/dist/api/onboarding.js +23 -0
  77. package/dist/api/onboarding.js.map +1 -0
  78. package/dist/api/openapi-doc.d.ts +21 -0
  79. package/dist/api/openapi-doc.d.ts.map +1 -0
  80. package/dist/api/openapi-doc.js +25 -0
  81. package/dist/api/openapi-doc.js.map +1 -0
  82. package/dist/api/projects.d.ts +24 -0
  83. package/dist/api/projects.d.ts.map +1 -0
  84. package/dist/api/projects.js +624 -0
  85. package/dist/api/projects.js.map +1 -0
  86. package/dist/api/scope-routes.d.ts +12 -0
  87. package/dist/api/scope-routes.d.ts.map +1 -0
  88. package/dist/api/scope-routes.js +2 -0
  89. package/dist/api/scope-routes.js.map +1 -0
  90. package/dist/api/sso-connect.d.ts +70 -0
  91. package/dist/api/sso-connect.d.ts.map +1 -0
  92. package/dist/api/sso-connect.js +164 -0
  93. package/dist/api/sso-connect.js.map +1 -0
  94. package/dist/api/sso-logout.d.ts +41 -0
  95. package/dist/api/sso-logout.d.ts.map +1 -0
  96. package/dist/api/sso-logout.js +34 -0
  97. package/dist/api/sso-logout.js.map +1 -0
  98. package/dist/api/teams.d.ts +43 -0
  99. package/dist/api/teams.d.ts.map +1 -0
  100. package/dist/api/teams.js +447 -0
  101. package/dist/api/teams.js.map +1 -0
  102. package/dist/api/workspaces.d.ts +114 -0
  103. package/dist/api/workspaces.d.ts.map +1 -0
  104. package/dist/api/workspaces.js +462 -0
  105. package/dist/api/workspaces.js.map +1 -0
  106. package/dist/apikeys/index.d.ts +3 -0
  107. package/dist/apikeys/index.d.ts.map +1 -0
  108. package/dist/apikeys/index.js +3 -0
  109. package/dist/apikeys/index.js.map +1 -0
  110. package/dist/apikeys/peppers.d.ts +53 -0
  111. package/dist/apikeys/peppers.d.ts.map +1 -0
  112. package/dist/apikeys/peppers.js +97 -0
  113. package/dist/apikeys/peppers.js.map +1 -0
  114. package/dist/apikeys/service.d.ts +56 -0
  115. package/dist/apikeys/service.d.ts.map +1 -0
  116. package/dist/apikeys/service.js +196 -0
  117. package/dist/apikeys/service.js.map +1 -0
  118. package/dist/app.d.ts +65 -0
  119. package/dist/app.d.ts.map +1 -0
  120. package/dist/app.js +142 -0
  121. package/dist/app.js.map +1 -0
  122. package/dist/audit/filters.d.ts +38 -0
  123. package/dist/audit/filters.d.ts.map +1 -0
  124. package/dist/audit/filters.js +97 -0
  125. package/dist/audit/filters.js.map +1 -0
  126. package/dist/audit/index.d.ts +3 -0
  127. package/dist/audit/index.d.ts.map +1 -0
  128. package/dist/audit/index.js +3 -0
  129. package/dist/audit/index.js.map +1 -0
  130. package/dist/audit/service.d.ts +65 -0
  131. package/dist/audit/service.d.ts.map +1 -0
  132. package/dist/audit/service.js +103 -0
  133. package/dist/audit/service.js.map +1 -0
  134. package/dist/boot.d.ts +8 -0
  135. package/dist/boot.d.ts.map +1 -0
  136. package/dist/boot.js +822 -0
  137. package/dist/boot.js.map +1 -0
  138. package/dist/constant-time.d.ts +3 -0
  139. package/dist/constant-time.d.ts.map +1 -0
  140. package/dist/constant-time.js +10 -0
  141. package/dist/constant-time.js.map +1 -0
  142. package/dist/email/driver.d.ts +16 -0
  143. package/dist/email/driver.d.ts.map +1 -0
  144. package/dist/email/driver.js +136 -0
  145. package/dist/email/driver.js.map +1 -0
  146. package/dist/email/index.d.ts +4 -0
  147. package/dist/email/index.d.ts.map +1 -0
  148. package/dist/email/index.js +4 -0
  149. package/dist/email/index.js.map +1 -0
  150. package/dist/email/shell.d.ts +72 -0
  151. package/dist/email/shell.d.ts.map +1 -0
  152. package/dist/email/shell.js +146 -0
  153. package/dist/email/shell.js.map +1 -0
  154. package/dist/email/templates.d.ts +83 -0
  155. package/dist/email/templates.d.ts.map +1 -0
  156. package/dist/email/templates.js +96 -0
  157. package/dist/email/templates.js.map +1 -0
  158. package/dist/entitlements/check.d.ts +140 -0
  159. package/dist/entitlements/check.d.ts.map +1 -0
  160. package/dist/entitlements/check.js +276 -0
  161. package/dist/entitlements/check.js.map +1 -0
  162. package/dist/entitlements/clock-skew.d.ts +27 -0
  163. package/dist/entitlements/clock-skew.d.ts.map +1 -0
  164. package/dist/entitlements/clock-skew.js +58 -0
  165. package/dist/entitlements/clock-skew.js.map +1 -0
  166. package/dist/entitlements/gate.d.ts +113 -0
  167. package/dist/entitlements/gate.d.ts.map +1 -0
  168. package/dist/entitlements/gate.js +430 -0
  169. package/dist/entitlements/gate.js.map +1 -0
  170. package/dist/entitlements/hub-machine-token.d.ts +83 -0
  171. package/dist/entitlements/hub-machine-token.d.ts.map +1 -0
  172. package/dist/entitlements/hub-machine-token.js +175 -0
  173. package/dist/entitlements/hub-machine-token.js.map +1 -0
  174. package/dist/entitlements/hub-subject.d.ts +32 -0
  175. package/dist/entitlements/hub-subject.d.ts.map +1 -0
  176. package/dist/entitlements/hub-subject.js +68 -0
  177. package/dist/entitlements/hub-subject.js.map +1 -0
  178. package/dist/entitlements/index.d.ts +9 -0
  179. package/dist/entitlements/index.d.ts.map +1 -0
  180. package/dist/entitlements/index.js +9 -0
  181. package/dist/entitlements/index.js.map +1 -0
  182. package/dist/entitlements/poster.d.ts +81 -0
  183. package/dist/entitlements/poster.d.ts.map +1 -0
  184. package/dist/entitlements/poster.js +169 -0
  185. package/dist/entitlements/poster.js.map +1 -0
  186. package/dist/entitlements/profiles.d.ts +121 -0
  187. package/dist/entitlements/profiles.d.ts.map +1 -0
  188. package/dist/entitlements/profiles.js +212 -0
  189. package/dist/entitlements/profiles.js.map +1 -0
  190. package/dist/entitlements/slot.d.ts +33 -0
  191. package/dist/entitlements/slot.d.ts.map +1 -0
  192. package/dist/entitlements/slot.js +75 -0
  193. package/dist/entitlements/slot.js.map +1 -0
  194. package/dist/env.d.ts +293 -0
  195. package/dist/env.d.ts.map +1 -0
  196. package/dist/env.js +383 -0
  197. package/dist/env.js.map +1 -0
  198. package/dist/files/http.d.ts +23 -0
  199. package/dist/files/http.d.ts.map +1 -0
  200. package/dist/files/http.js +66 -0
  201. package/dist/files/http.js.map +1 -0
  202. package/dist/files/index.d.ts +5 -0
  203. package/dist/files/index.d.ts.map +1 -0
  204. package/dist/files/index.js +5 -0
  205. package/dist/files/index.js.map +1 -0
  206. package/dist/files/serve.d.ts +43 -0
  207. package/dist/files/serve.d.ts.map +1 -0
  208. package/dist/files/serve.js +71 -0
  209. package/dist/files/serve.js.map +1 -0
  210. package/dist/files/service.d.ts +69 -0
  211. package/dist/files/service.d.ts.map +1 -0
  212. package/dist/files/service.js +188 -0
  213. package/dist/files/service.js.map +1 -0
  214. package/dist/files/spool.d.ts +21 -0
  215. package/dist/files/spool.d.ts.map +1 -0
  216. package/dist/files/spool.js +47 -0
  217. package/dist/files/spool.js.map +1 -0
  218. package/dist/identity/better-auth.d.ts +3927 -0
  219. package/dist/identity/better-auth.d.ts.map +1 -0
  220. package/dist/identity/better-auth.js +896 -0
  221. package/dist/identity/better-auth.js.map +1 -0
  222. package/dist/identity/demo-pass-plugin.d.ts +29 -0
  223. package/dist/identity/demo-pass-plugin.d.ts.map +1 -0
  224. package/dist/identity/demo-pass-plugin.js +88 -0
  225. package/dist/identity/demo-pass-plugin.js.map +1 -0
  226. package/dist/identity/demo-pass-rules.d.ts +84 -0
  227. package/dist/identity/demo-pass-rules.d.ts.map +1 -0
  228. package/dist/identity/demo-pass-rules.js +223 -0
  229. package/dist/identity/demo-pass-rules.js.map +1 -0
  230. package/dist/identity/demo-pass.d.ts +159 -0
  231. package/dist/identity/demo-pass.d.ts.map +1 -0
  232. package/dist/identity/demo-pass.js +319 -0
  233. package/dist/identity/demo-pass.js.map +1 -0
  234. package/dist/identity/hub-grant.d.ts +182 -0
  235. package/dist/identity/hub-grant.d.ts.map +1 -0
  236. package/dist/identity/hub-grant.js +594 -0
  237. package/dist/identity/hub-grant.js.map +1 -0
  238. package/dist/identity/hub-jwt.d.ts +22 -0
  239. package/dist/identity/hub-jwt.d.ts.map +1 -0
  240. package/dist/identity/hub-jwt.js +77 -0
  241. package/dist/identity/hub-jwt.js.map +1 -0
  242. package/dist/identity/hub-live-gate.d.ts +17 -0
  243. package/dist/identity/hub-live-gate.d.ts.map +1 -0
  244. package/dist/identity/hub-live-gate.js +146 -0
  245. package/dist/identity/hub-live-gate.js.map +1 -0
  246. package/dist/identity/hub-logout.d.ts +88 -0
  247. package/dist/identity/hub-logout.d.ts.map +1 -0
  248. package/dist/identity/hub-logout.js +158 -0
  249. package/dist/identity/hub-logout.js.map +1 -0
  250. package/dist/identity/hub-projection.d.ts +103 -0
  251. package/dist/identity/hub-projection.d.ts.map +1 -0
  252. package/dist/identity/hub-projection.js +130 -0
  253. package/dist/identity/hub-projection.js.map +1 -0
  254. package/dist/identity/hub-reconcile.d.ts +151 -0
  255. package/dist/identity/hub-reconcile.d.ts.map +1 -0
  256. package/dist/identity/hub-reconcile.js +400 -0
  257. package/dist/identity/hub-reconcile.js.map +1 -0
  258. package/dist/identity/hub-sso.d.ts +363 -0
  259. package/dist/identity/hub-sso.d.ts.map +1 -0
  260. package/dist/identity/hub-sso.js +536 -0
  261. package/dist/identity/hub-sso.js.map +1 -0
  262. package/dist/identity/hub-user-client.d.ts +222 -0
  263. package/dist/identity/hub-user-client.d.ts.map +1 -0
  264. package/dist/identity/hub-user-client.js +406 -0
  265. package/dist/identity/hub-user-client.js.map +1 -0
  266. package/dist/identity/index.d.ts +13 -0
  267. package/dist/identity/index.d.ts.map +1 -0
  268. package/dist/identity/index.js +13 -0
  269. package/dist/identity/index.js.map +1 -0
  270. package/dist/identity/oauth-jwt.d.ts +32 -0
  271. package/dist/identity/oauth-jwt.d.ts.map +1 -0
  272. package/dist/identity/oauth-jwt.js +122 -0
  273. package/dist/identity/oauth-jwt.js.map +1 -0
  274. package/dist/identity/resolve-membership.d.ts +28 -0
  275. package/dist/identity/resolve-membership.d.ts.map +1 -0
  276. package/dist/identity/resolve-membership.js +69 -0
  277. package/dist/identity/resolve-membership.js.map +1 -0
  278. package/dist/identity/signing-key.d.ts +49 -0
  279. package/dist/identity/signing-key.d.ts.map +1 -0
  280. package/dist/identity/signing-key.js +144 -0
  281. package/dist/identity/signing-key.js.map +1 -0
  282. package/dist/index.d.ts +21 -0
  283. package/dist/index.d.ts.map +1 -0
  284. package/dist/index.js +11 -0
  285. package/dist/index.js.map +1 -0
  286. package/dist/invitations/index.d.ts +2 -0
  287. package/dist/invitations/index.d.ts.map +1 -0
  288. package/dist/invitations/index.js +2 -0
  289. package/dist/invitations/index.js.map +1 -0
  290. package/dist/invitations/service.d.ts +36 -0
  291. package/dist/invitations/service.d.ts.map +1 -0
  292. package/dist/invitations/service.js +122 -0
  293. package/dist/invitations/service.js.map +1 -0
  294. package/dist/jobs/index.d.ts +3 -0
  295. package/dist/jobs/index.d.ts.map +1 -0
  296. package/dist/jobs/index.js +3 -0
  297. package/dist/jobs/index.js.map +1 -0
  298. package/dist/jobs/pgboss.d.ts +119 -0
  299. package/dist/jobs/pgboss.d.ts.map +1 -0
  300. package/dist/jobs/pgboss.js +521 -0
  301. package/dist/jobs/pgboss.js.map +1 -0
  302. package/dist/jobs/timers.d.ts +127 -0
  303. package/dist/jobs/timers.d.ts.map +1 -0
  304. package/dist/jobs/timers.js +228 -0
  305. package/dist/jobs/timers.js.map +1 -0
  306. package/dist/logger.d.ts +17 -0
  307. package/dist/logger.d.ts.map +1 -0
  308. package/dist/logger.js +64 -0
  309. package/dist/logger.js.map +1 -0
  310. package/dist/mcp/errors.d.ts +37 -0
  311. package/dist/mcp/errors.d.ts.map +1 -0
  312. package/dist/mcp/errors.js +77 -0
  313. package/dist/mcp/errors.js.map +1 -0
  314. package/dist/mcp/http.d.ts +35 -0
  315. package/dist/mcp/http.d.ts.map +1 -0
  316. package/dist/mcp/http.js +80 -0
  317. package/dist/mcp/http.js.map +1 -0
  318. package/dist/mcp/index.d.ts +8 -0
  319. package/dist/mcp/index.d.ts.map +1 -0
  320. package/dist/mcp/index.js +8 -0
  321. package/dist/mcp/index.js.map +1 -0
  322. package/dist/mcp/inputs.d.ts +19 -0
  323. package/dist/mcp/inputs.d.ts.map +1 -0
  324. package/dist/mcp/inputs.js +28 -0
  325. package/dist/mcp/inputs.js.map +1 -0
  326. package/dist/mcp/projects.d.ts +31 -0
  327. package/dist/mcp/projects.d.ts.map +1 -0
  328. package/dist/mcp/projects.js +315 -0
  329. package/dist/mcp/projects.js.map +1 -0
  330. package/dist/mcp/server.d.ts +52 -0
  331. package/dist/mcp/server.d.ts.map +1 -0
  332. package/dist/mcp/server.js +93 -0
  333. package/dist/mcp/server.js.map +1 -0
  334. package/dist/mcp/teams.d.ts +7 -0
  335. package/dist/mcp/teams.d.ts.map +1 -0
  336. package/dist/mcp/teams.js +62 -0
  337. package/dist/mcp/teams.js.map +1 -0
  338. package/dist/mcp/tool-kit.d.ts +67 -0
  339. package/dist/mcp/tool-kit.d.ts.map +1 -0
  340. package/dist/mcp/tool-kit.js +74 -0
  341. package/dist/mcp/tool-kit.js.map +1 -0
  342. package/dist/members/removal.d.ts +95 -0
  343. package/dist/members/removal.d.ts.map +1 -0
  344. package/dist/members/removal.js +143 -0
  345. package/dist/members/removal.js.map +1 -0
  346. package/dist/middleware/auth-body.d.ts +25 -0
  347. package/dist/middleware/auth-body.d.ts.map +1 -0
  348. package/dist/middleware/auth-body.js +55 -0
  349. package/dist/middleware/auth-body.js.map +1 -0
  350. package/dist/middleware/auth-context.d.ts +170 -0
  351. package/dist/middleware/auth-context.d.ts.map +1 -0
  352. package/dist/middleware/auth-context.js +251 -0
  353. package/dist/middleware/auth-context.js.map +1 -0
  354. package/dist/middleware/body-cap.d.ts +17 -0
  355. package/dist/middleware/body-cap.d.ts.map +1 -0
  356. package/dist/middleware/body-cap.js +31 -0
  357. package/dist/middleware/body-cap.js.map +1 -0
  358. package/dist/middleware/body-refusal.d.ts +20 -0
  359. package/dist/middleware/body-refusal.d.ts.map +1 -0
  360. package/dist/middleware/body-refusal.js +5 -0
  361. package/dist/middleware/body-refusal.js.map +1 -0
  362. package/dist/middleware/cross-site.d.ts +61 -0
  363. package/dist/middleware/cross-site.d.ts.map +1 -0
  364. package/dist/middleware/cross-site.js +59 -0
  365. package/dist/middleware/cross-site.js.map +1 -0
  366. package/dist/middleware/hub-managed.d.ts +45 -0
  367. package/dist/middleware/hub-managed.d.ts.map +1 -0
  368. package/dist/middleware/hub-managed.js +56 -0
  369. package/dist/middleware/hub-managed.js.map +1 -0
  370. package/dist/middleware/idempotency.d.ts +14 -0
  371. package/dist/middleware/idempotency.d.ts.map +1 -0
  372. package/dist/middleware/idempotency.js +222 -0
  373. package/dist/middleware/idempotency.js.map +1 -0
  374. package/dist/middleware/index.d.ts +12 -0
  375. package/dist/middleware/index.d.ts.map +1 -0
  376. package/dist/middleware/index.js +12 -0
  377. package/dist/middleware/index.js.map +1 -0
  378. package/dist/middleware/json-depth.d.ts +32 -0
  379. package/dist/middleware/json-depth.d.ts.map +1 -0
  380. package/dist/middleware/json-depth.js +80 -0
  381. package/dist/middleware/json-depth.js.map +1 -0
  382. package/dist/middleware/no-store.d.ts +21 -0
  383. package/dist/middleware/no-store.d.ts.map +1 -0
  384. package/dist/middleware/no-store.js +32 -0
  385. package/dist/middleware/no-store.js.map +1 -0
  386. package/dist/middleware/oauth-public.d.ts +16 -0
  387. package/dist/middleware/oauth-public.d.ts.map +1 -0
  388. package/dist/middleware/oauth-public.js +50 -0
  389. package/dist/middleware/oauth-public.js.map +1 -0
  390. package/dist/middleware/rate-limit.d.ts +182 -0
  391. package/dist/middleware/rate-limit.d.ts.map +1 -0
  392. package/dist/middleware/rate-limit.js +277 -0
  393. package/dist/middleware/rate-limit.js.map +1 -0
  394. package/dist/middleware/request-id.d.ts +10 -0
  395. package/dist/middleware/request-id.d.ts.map +1 -0
  396. package/dist/middleware/request-id.js +42 -0
  397. package/dist/middleware/request-id.js.map +1 -0
  398. package/dist/middleware/scopes.d.ts +33 -0
  399. package/dist/middleware/scopes.d.ts.map +1 -0
  400. package/dist/middleware/scopes.js +139 -0
  401. package/dist/middleware/scopes.js.map +1 -0
  402. package/dist/middleware/security-headers.d.ts +53 -0
  403. package/dist/middleware/security-headers.d.ts.map +1 -0
  404. package/dist/middleware/security-headers.js +96 -0
  405. package/dist/middleware/security-headers.js.map +1 -0
  406. package/dist/observability/index.d.ts +3 -0
  407. package/dist/observability/index.d.ts.map +1 -0
  408. package/dist/observability/index.js +3 -0
  409. package/dist/observability/index.js.map +1 -0
  410. package/dist/observability/metrics.d.ts +17 -0
  411. package/dist/observability/metrics.d.ts.map +1 -0
  412. package/dist/observability/metrics.js +82 -0
  413. package/dist/observability/metrics.js.map +1 -0
  414. package/dist/observability/otel.d.ts +20 -0
  415. package/dist/observability/otel.d.ts.map +1 -0
  416. package/dist/observability/otel.js +54 -0
  417. package/dist/observability/otel.js.map +1 -0
  418. package/dist/pagination.d.ts +57 -0
  419. package/dist/pagination.d.ts.map +1 -0
  420. package/dist/pagination.js +90 -0
  421. package/dist/pagination.js.map +1 -0
  422. package/dist/platform/edition.d.ts +57 -0
  423. package/dist/platform/edition.d.ts.map +1 -0
  424. package/dist/platform/edition.js +90 -0
  425. package/dist/platform/edition.js.map +1 -0
  426. package/dist/platform/entitlements.d.ts +26 -0
  427. package/dist/platform/entitlements.d.ts.map +1 -0
  428. package/dist/platform/entitlements.js +28 -0
  429. package/dist/platform/entitlements.js.map +1 -0
  430. package/dist/platform/events.d.ts +87 -0
  431. package/dist/platform/events.d.ts.map +1 -0
  432. package/dist/platform/events.js +32 -0
  433. package/dist/platform/events.js.map +1 -0
  434. package/dist/platform/index.d.ts +8 -0
  435. package/dist/platform/index.d.ts.map +1 -0
  436. package/dist/platform/index.js +8 -0
  437. package/dist/platform/index.js.map +1 -0
  438. package/dist/platform/local-identity.d.ts +39 -0
  439. package/dist/platform/local-identity.d.ts.map +1 -0
  440. package/dist/platform/local-identity.js +87 -0
  441. package/dist/platform/local-identity.js.map +1 -0
  442. package/dist/platform/registry.d.ts +23 -0
  443. package/dist/platform/registry.d.ts.map +1 -0
  444. package/dist/platform/registry.js +5 -0
  445. package/dist/platform/registry.js.map +1 -0
  446. package/dist/platform/usage.d.ts +11 -0
  447. package/dist/platform/usage.d.ts.map +1 -0
  448. package/dist/platform/usage.js +12 -0
  449. package/dist/platform/usage.js.map +1 -0
  450. package/dist/platform/workspaces.d.ts +25 -0
  451. package/dist/platform/workspaces.d.ts.map +1 -0
  452. package/dist/platform/workspaces.js +44 -0
  453. package/dist/platform/workspaces.js.map +1 -0
  454. package/dist/projects/access.d.ts +40 -0
  455. package/dist/projects/access.d.ts.map +1 -0
  456. package/dist/projects/access.js +133 -0
  457. package/dist/projects/access.js.map +1 -0
  458. package/dist/projects/index.d.ts +2 -0
  459. package/dist/projects/index.d.ts.map +1 -0
  460. package/dist/projects/index.js +2 -0
  461. package/dist/projects/index.js.map +1 -0
  462. package/dist/route-label.d.ts +23 -0
  463. package/dist/route-label.d.ts.map +1 -0
  464. package/dist/route-label.js +29 -0
  465. package/dist/route-label.js.map +1 -0
  466. package/dist/routes/health.d.ts +30 -0
  467. package/dist/routes/health.d.ts.map +1 -0
  468. package/dist/routes/health.js +54 -0
  469. package/dist/routes/health.js.map +1 -0
  470. package/dist/routes/index.d.ts +3 -0
  471. package/dist/routes/index.d.ts.map +1 -0
  472. package/dist/routes/index.js +3 -0
  473. package/dist/routes/index.js.map +1 -0
  474. package/dist/routes/wellknown.d.ts +11 -0
  475. package/dist/routes/wellknown.d.ts.map +1 -0
  476. package/dist/routes/wellknown.js +45 -0
  477. package/dist/routes/wellknown.js.map +1 -0
  478. package/dist/secret.d.ts +30 -0
  479. package/dist/secret.d.ts.map +1 -0
  480. package/dist/secret.js +97 -0
  481. package/dist/secret.js.map +1 -0
  482. package/dist/setup-transport.d.ts +23 -0
  483. package/dist/setup-transport.d.ts.map +1 -0
  484. package/dist/setup-transport.js +52 -0
  485. package/dist/setup-transport.js.map +1 -0
  486. package/dist/state.d.ts +21 -0
  487. package/dist/state.d.ts.map +1 -0
  488. package/dist/state.js +4 -0
  489. package/dist/state.js.map +1 -0
  490. package/dist/storage/driver.d.ts +38 -0
  491. package/dist/storage/driver.d.ts.map +1 -0
  492. package/dist/storage/driver.js +14 -0
  493. package/dist/storage/driver.js.map +1 -0
  494. package/dist/storage/factory.d.ts +4 -0
  495. package/dist/storage/factory.d.ts.map +1 -0
  496. package/dist/storage/factory.js +20 -0
  497. package/dist/storage/factory.js.map +1 -0
  498. package/dist/storage/index.d.ts +4 -0
  499. package/dist/storage/index.d.ts.map +1 -0
  500. package/dist/storage/index.js +4 -0
  501. package/dist/storage/index.js.map +1 -0
  502. package/dist/storage/local.d.ts +21 -0
  503. package/dist/storage/local.d.ts.map +1 -0
  504. package/dist/storage/local.js +88 -0
  505. package/dist/storage/local.js.map +1 -0
  506. package/dist/storage/s3.d.ts +29 -0
  507. package/dist/storage/s3.d.ts.map +1 -0
  508. package/dist/storage/s3.js +82 -0
  509. package/dist/storage/s3.js.map +1 -0
  510. package/dist/testing/fake-hub.d.ts +425 -0
  511. package/dist/testing/fake-hub.d.ts.map +1 -0
  512. package/dist/testing/fake-hub.js +1074 -0
  513. package/dist/testing/fake-hub.js.map +1 -0
  514. package/dist/testing/helpers.d.ts +124 -0
  515. package/dist/testing/helpers.d.ts.map +1 -0
  516. package/dist/testing/helpers.js +174 -0
  517. package/dist/testing/helpers.js.map +1 -0
  518. package/dist/testing/index.d.ts +12 -0
  519. package/dist/testing/index.d.ts.map +1 -0
  520. package/dist/testing/index.js +12 -0
  521. package/dist/testing/index.js.map +1 -0
  522. package/dist/testing/setup-origins.d.ts +21 -0
  523. package/dist/testing/setup-origins.d.ts.map +1 -0
  524. package/dist/testing/setup-origins.js +57 -0
  525. package/dist/testing/setup-origins.js.map +1 -0
  526. package/dist/testing/sso-helpers.d.ts +43 -0
  527. package/dist/testing/sso-helpers.d.ts.map +1 -0
  528. package/dist/testing/sso-helpers.js +159 -0
  529. package/dist/testing/sso-helpers.js.map +1 -0
  530. package/dist/tool-definition.d.ts +382 -0
  531. package/dist/tool-definition.d.ts.map +1 -0
  532. package/dist/tool-definition.js +46 -0
  533. package/dist/tool-definition.js.map +1 -0
  534. package/dist/util/index.d.ts +8 -0
  535. package/dist/util/index.d.ts.map +1 -0
  536. package/dist/util/index.js +8 -0
  537. package/dist/util/index.js.map +1 -0
  538. package/package.json +161 -0
  539. package/src/accounts/deletion.ts +389 -0
  540. package/src/accounts/erasure-log.ts +140 -0
  541. package/src/accounts/index.ts +5 -0
  542. package/src/accounts/mint-refusal.ts +67 -0
  543. package/src/accounts/signup-duplicate.ts +21 -0
  544. package/src/accounts/superadmin.ts +46 -0
  545. package/src/api/apikeys.ts +147 -0
  546. package/src/api/audit.ts +83 -0
  547. package/src/api/break-glass.ts +294 -0
  548. package/src/api/cli-auth.ts +308 -0
  549. package/src/api/create-api.ts +1403 -0
  550. package/src/api/demo-passes.ts +207 -0
  551. package/src/api/errors.ts +13 -0
  552. package/src/api/export.ts +482 -0
  553. package/src/api/files.ts +200 -0
  554. package/src/api/index.ts +29 -0
  555. package/src/api/invitations.ts +396 -0
  556. package/src/api/members.ts +617 -0
  557. package/src/api/onboarding.ts +50 -0
  558. package/src/api/openapi-doc.ts +34 -0
  559. package/src/api/projects.ts +788 -0
  560. package/src/api/scope-routes.ts +12 -0
  561. package/src/api/sso-connect.ts +246 -0
  562. package/src/api/sso-logout.ts +76 -0
  563. package/src/api/teams.ts +575 -0
  564. package/src/api/workspaces.ts +649 -0
  565. package/src/apikeys/index.ts +2 -0
  566. package/src/apikeys/peppers.ts +118 -0
  567. package/src/apikeys/service.ts +223 -0
  568. package/src/app.ts +228 -0
  569. package/src/audit/filters.ts +101 -0
  570. package/src/audit/index.ts +9 -0
  571. package/src/audit/service.ts +154 -0
  572. package/src/boot.ts +953 -0
  573. package/src/constant-time.ts +9 -0
  574. package/src/email/driver.ts +139 -0
  575. package/src/email/index.ts +26 -0
  576. package/src/email/shell.ts +201 -0
  577. package/src/email/templates.ts +184 -0
  578. package/src/entitlements/check.ts +435 -0
  579. package/src/entitlements/clock-skew.ts +58 -0
  580. package/src/entitlements/gate.ts +636 -0
  581. package/src/entitlements/hub-machine-token.ts +205 -0
  582. package/src/entitlements/hub-subject.ts +77 -0
  583. package/src/entitlements/index.ts +37 -0
  584. package/src/entitlements/poster.ts +265 -0
  585. package/src/entitlements/profiles.ts +303 -0
  586. package/src/entitlements/slot.ts +105 -0
  587. package/src/env.ts +456 -0
  588. package/src/files/http.ts +77 -0
  589. package/src/files/index.ts +4 -0
  590. package/src/files/serve.ts +115 -0
  591. package/src/files/service.ts +209 -0
  592. package/src/files/spool.ts +58 -0
  593. package/src/identity/better-auth.ts +1103 -0
  594. package/src/identity/demo-pass-plugin.ts +121 -0
  595. package/src/identity/demo-pass-rules.ts +229 -0
  596. package/src/identity/demo-pass.ts +390 -0
  597. package/src/identity/hub-grant.ts +704 -0
  598. package/src/identity/hub-jwt.ts +78 -0
  599. package/src/identity/hub-live-gate.ts +167 -0
  600. package/src/identity/hub-logout.ts +174 -0
  601. package/src/identity/hub-projection.ts +251 -0
  602. package/src/identity/hub-reconcile.ts +572 -0
  603. package/src/identity/hub-sso.ts +696 -0
  604. package/src/identity/hub-user-client.ts +554 -0
  605. package/src/identity/index.ts +56 -0
  606. package/src/identity/oauth-jwt.ts +128 -0
  607. package/src/identity/resolve-membership.ts +104 -0
  608. package/src/identity/signing-key.ts +164 -0
  609. package/src/index.ts +65 -0
  610. package/src/invitations/index.ts +1 -0
  611. package/src/invitations/service.ts +171 -0
  612. package/src/jobs/index.ts +25 -0
  613. package/src/jobs/pgboss.ts +594 -0
  614. package/src/jobs/timers.ts +287 -0
  615. package/src/logger.ts +67 -0
  616. package/src/mcp/errors.ts +111 -0
  617. package/src/mcp/http.ts +129 -0
  618. package/src/mcp/index.ts +28 -0
  619. package/src/mcp/inputs.ts +33 -0
  620. package/src/mcp/projects.ts +480 -0
  621. package/src/mcp/server.ts +174 -0
  622. package/src/mcp/teams.ts +97 -0
  623. package/src/mcp/tool-kit.ts +148 -0
  624. package/src/members/removal.ts +216 -0
  625. package/src/middleware/auth-body.ts +58 -0
  626. package/src/middleware/auth-context.ts +384 -0
  627. package/src/middleware/body-cap.ts +33 -0
  628. package/src/middleware/body-refusal.ts +23 -0
  629. package/src/middleware/cross-site.ts +122 -0
  630. package/src/middleware/hub-managed.ts +61 -0
  631. package/src/middleware/idempotency.ts +264 -0
  632. package/src/middleware/index.ts +33 -0
  633. package/src/middleware/json-depth.ts +74 -0
  634. package/src/middleware/no-store.ts +30 -0
  635. package/src/middleware/oauth-public.ts +54 -0
  636. package/src/middleware/rate-limit.ts +432 -0
  637. package/src/middleware/request-id.ts +54 -0
  638. package/src/middleware/scopes.ts +150 -0
  639. package/src/middleware/security-headers.ts +129 -0
  640. package/src/observability/index.ts +2 -0
  641. package/src/observability/metrics.ts +102 -0
  642. package/src/observability/otel.ts +79 -0
  643. package/src/pagination.ts +118 -0
  644. package/src/platform/edition.ts +140 -0
  645. package/src/platform/entitlements.ts +47 -0
  646. package/src/platform/events.ts +71 -0
  647. package/src/platform/index.ts +7 -0
  648. package/src/platform/local-identity.ts +90 -0
  649. package/src/platform/registry.ts +28 -0
  650. package/src/platform/usage.ts +13 -0
  651. package/src/platform/workspaces.ts +41 -0
  652. package/src/projects/access.ts +160 -0
  653. package/src/projects/index.ts +7 -0
  654. package/src/route-label.ts +29 -0
  655. package/src/routes/health.ts +79 -0
  656. package/src/routes/index.ts +2 -0
  657. package/src/routes/wellknown.ts +67 -0
  658. package/src/secret.ts +115 -0
  659. package/src/setup-transport.ts +46 -0
  660. package/src/state.ts +23 -0
  661. package/src/storage/driver.ts +48 -0
  662. package/src/storage/factory.ts +34 -0
  663. package/src/storage/index.ts +3 -0
  664. package/src/storage/local.ts +93 -0
  665. package/src/storage/s3.ts +109 -0
  666. package/src/testing/fake-hub.ts +1316 -0
  667. package/src/testing/helpers.ts +254 -0
  668. package/src/testing/index.ts +11 -0
  669. package/src/testing/setup-origins.ts +58 -0
  670. package/src/testing/sso-helpers.ts +178 -0
  671. package/src/tool-definition.ts +463 -0
  672. package/src/util/index.ts +17 -0
  673. package/test/fixtures/onboarding-backfill.sql +13 -0
  674. package/test/fixtures/operator-user-id-backfill.sql +18 -0
  675. package/test/host/dr-lib.sh +253 -0
  676. package/test/host/drizzle/0000_chassis_baseline.sql +438 -0
  677. package/test/host/drizzle/0001_last_owner_guard.sql +42 -0
  678. package/test/host/drizzle/meta/0000_snapshot.json +3566 -0
  679. package/test/host/drizzle/meta/_journal.json +20 -0
  680. package/test/host/drizzle.config.ts +17 -0
  681. package/test/host/identity.ts +41 -0
  682. package/test/host/minimal-host.ts +35 -0
  683. package/test/host/minimal-tool.ts +123 -0
  684. package/test/integration/account-oracle-uniformity.test.ts +284 -0
  685. package/test/integration/account-recovery.test.ts +236 -0
  686. package/test/integration/account.test.ts +120 -0
  687. package/test/integration/api-quota.test.ts +208 -0
  688. package/test/integration/apikey-expiry.test.ts +178 -0
  689. package/test/integration/apikey-pepper-rotation.test.ts +190 -0
  690. package/test/integration/boot-posture.test.ts +169 -0
  691. package/test/integration/break-glass.test.ts +484 -0
  692. package/test/integration/cloud-lifecycle.test.ts +233 -0
  693. package/test/integration/credential-boundaries.test.ts +195 -0
  694. package/test/integration/default-workspace.test.ts +414 -0
  695. package/test/integration/demo-pass-rules.test.ts +332 -0
  696. package/test/integration/demo-pass.test.ts +1222 -0
  697. package/test/integration/dr-verify-real-dump.test.ts +154 -0
  698. package/test/integration/edition.test.ts +868 -0
  699. package/test/integration/email-change.test.ts +394 -0
  700. package/test/integration/empty-tool.test.ts +267 -0
  701. package/test/integration/entitlements-null-hook.test.ts +187 -0
  702. package/test/integration/entitlements.test.ts +693 -0
  703. package/test/integration/export-entries.test.ts +321 -0
  704. package/test/integration/files.test.ts +320 -0
  705. package/test/integration/first-boot-claim.test.ts +131 -0
  706. package/test/integration/gdpr.test.ts +532 -0
  707. package/test/integration/helpers.ts +29 -0
  708. package/test/integration/hub-grant.test.ts +505 -0
  709. package/test/integration/hub-live-gate.test.ts +612 -0
  710. package/test/integration/hub-managed-membership.test.ts +559 -0
  711. package/test/integration/hub-org-selector.test.ts +281 -0
  712. package/test/integration/hub-reconcile.test.ts +646 -0
  713. package/test/integration/hub-sso.test.ts +704 -0
  714. package/test/integration/hub-teams.test.ts +771 -0
  715. package/test/integration/idempotency.test.ts +261 -0
  716. package/test/integration/invite-verification.test.ts +210 -0
  717. package/test/integration/last-owner-race.test.ts +263 -0
  718. package/test/integration/m9-fixes.test.ts +290 -0
  719. package/test/integration/mcp-projects.test.ts +463 -0
  720. package/test/integration/member-removal-race.test.ts +466 -0
  721. package/test/integration/member-removal.test.ts +794 -0
  722. package/test/integration/oauth-mcp.test.ts +477 -0
  723. package/test/integration/oauth-workspace.test.ts +371 -0
  724. package/test/integration/observability.test.ts +183 -0
  725. package/test/integration/onboarding.test.ts +268 -0
  726. package/test/integration/orphan-purge.test.ts +451 -0
  727. package/test/integration/pagination.test.ts +344 -0
  728. package/test/integration/platform-core.test.ts +305 -0
  729. package/test/integration/platform.test.ts +246 -0
  730. package/test/integration/pool-survives-restart.test.ts +80 -0
  731. package/test/integration/projects-cloud.test.ts +193 -0
  732. package/test/integration/projects.test.ts +1310 -0
  733. package/test/integration/security-fixes.test.ts +190 -0
  734. package/test/integration/setup-transport.test.ts +118 -0
  735. package/test/integration/signin-wall.test.ts +103 -0
  736. package/test/integration/signing-key-rotation.test.ts +349 -0
  737. package/test/integration/sso-helpers.ts +15 -0
  738. package/test/integration/sso-logout.test.ts +283 -0
  739. package/test/integration/teams-cloud.test.ts +194 -0
  740. package/test/integration/teams.test.ts +551 -0
  741. package/test/integration/timers.test.ts +377 -0
  742. package/test/integration/two-factor.test.ts +301 -0
  743. package/test/integration/usage-window.test.ts +161 -0
  744. package/test/integration/workspace-create-cloud.test.ts +523 -0
  745. package/test/integration/workspace-create.test.ts +510 -0
  746. package/test/integration/workspace-scoping.test.ts +530 -0
  747. package/test/integration/zz-adv-replay-owner.test.ts +205 -0
  748. package/test/unit/apikey-peppers.test.ts +110 -0
  749. package/test/unit/apikey-prefix.test.ts +34 -0
  750. package/test/unit/audit-filters.test.ts +135 -0
  751. package/test/unit/auth-origins.test.ts +92 -0
  752. package/test/unit/body-cap.test.ts +84 -0
  753. package/test/unit/clock-skew.test.ts +68 -0
  754. package/test/unit/cross-site.test.ts +166 -0
  755. package/test/unit/declared-credits.test.ts +13 -0
  756. package/test/unit/demo-pass-rules.test.ts +192 -0
  757. package/test/unit/email-driver.test.ts +127 -0
  758. package/test/unit/end-pool.test.ts +181 -0
  759. package/test/unit/entitlement-check.test.ts +492 -0
  760. package/test/unit/entitlement-gate.test.ts +1333 -0
  761. package/test/unit/entitlement-profiles.test.ts +289 -0
  762. package/test/unit/erasure-log.test.ts +72 -0
  763. package/test/unit/error-mapping.test.ts +89 -0
  764. package/test/unit/export-entries.test.ts +85 -0
  765. package/test/unit/export-sanitize.test.ts +27 -0
  766. package/test/unit/files-head-route.test.ts +155 -0
  767. package/test/unit/files-http.test.ts +97 -0
  768. package/test/unit/head-rewrite.test.ts +72 -0
  769. package/test/unit/hub-create-org.test.ts +181 -0
  770. package/test/unit/hub-jwt.test.ts +93 -0
  771. package/test/unit/hub-sso-params.test.ts +39 -0
  772. package/test/unit/hub-subject.test.ts +83 -0
  773. package/test/unit/idempotency-crypto.test.ts +45 -0
  774. package/test/unit/json-depth.test.ts +88 -0
  775. package/test/unit/logger-redaction.test.ts +66 -0
  776. package/test/unit/mcp-errors.test.ts +110 -0
  777. package/test/unit/mcp-inputs.test.ts +106 -0
  778. package/test/unit/mcp-project-hints.test.ts +26 -0
  779. package/test/unit/no-store.test.ts +49 -0
  780. package/test/unit/no-tool-migration-filename.test.ts +70 -0
  781. package/test/unit/observability.test.ts +64 -0
  782. package/test/unit/openapi-doc.test.ts +93 -0
  783. package/test/unit/rate-limit-consume-on.test.ts +76 -0
  784. package/test/unit/rate-limit.test.ts +39 -0
  785. package/test/unit/readyz-storage.test.ts +157 -0
  786. package/test/unit/request-quota.test.ts +146 -0
  787. package/test/unit/scopes.test.ts +66 -0
  788. package/test/unit/security-headers.test.ts +131 -0
  789. package/test/unit/serve-content-type.test.ts +74 -0
  790. package/test/unit/setup-transport.test.ts +29 -0
  791. package/test/unit/storage-local.test.ts +53 -0
  792. package/test/unit/superadmin.test.ts +32 -0
  793. package/test/unit/timers.test.ts +287 -0
  794. package/test/unit/tool-definition-guards.test.ts +166 -0
  795. package/test/unit/tool-entitlements-guard.test.ts +168 -0
  796. package/test/unit/usage-poster.test.ts +542 -0
  797. package/test/unit/usage-window.test.ts +48 -0
  798. package/test/unit/workspace-create-audit.test.ts +48 -0
@@ -0,0 +1,371 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
2
+ import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';
3
+ import { serve, type ServerType } from '@hono/node-server';
4
+ import { createServer } from 'node:net';
5
+ import { createHash, randomBytes } from 'node:crypto';
6
+ import { exportJWK, generateKeyPair, SignJWT } from 'jose';
7
+ import { OauthJwtVerifier } from '@antasphere/chassis-server/identity';
8
+ import type { Auth } from '@antasphere/chassis-server/identity';
9
+ import {
10
+ createDatabase,
11
+ createTestApp,
12
+ extractCookie,
13
+ readJson,
14
+ startPostgres,
15
+ type TestApp,
16
+ SETUP_TOKEN,
17
+ host
18
+ } from './helpers.js';
19
+
20
+ /**
21
+ * OAuth grants under the user-scoped credential model: consent is "act as
22
+ * you" — issuance requires only a live user with ≥1 active membership, the
23
+ * minted JWT carries NO workspace claim, and the workspace each request
24
+ * targets is a per-request parameter (X-Workspace-Id) authorized against the
25
+ * user's own live memberships. The consent-workspace parking endpoint is
26
+ * gone, and a legacy workspace_id claim is never an authorization input.
27
+ */
28
+ const OWNER = {
29
+ email: 'oauth-multi@ws.test',
30
+ name: 'OAuth Multi',
31
+ password: 'a-long-owner-password-123'
32
+ };
33
+ const BOB = { email: 'oauth-bob@ws.test', name: 'OAuth Bob', password: 'a-long-bob-password-1234' };
34
+ const REDIRECT_URI = 'http://127.0.0.1:39218/callback';
35
+
36
+ let container: StartedPostgreSqlContainer;
37
+ let app: TestApp;
38
+ let server: ServerType;
39
+ let base = '';
40
+ let ownerCookie = '';
41
+ let bobCookie = '';
42
+ let ownerId = '';
43
+ let bobId = '';
44
+ let w1 = '';
45
+ let w2 = '';
46
+ let w3 = ''; // Bob's sole workspace
47
+ let clientId = '';
48
+
49
+ const WS_HEADER = 'x-workspace-id';
50
+
51
+ function b64url(buf: Buffer): string {
52
+ return buf.toString('base64url');
53
+ }
54
+
55
+ function jwtPayload(token: string): Record<string, unknown> {
56
+ return JSON.parse(Buffer.from(token.split('.')[1]!, 'base64url').toString());
57
+ }
58
+
59
+ async function freePort(): Promise<number> {
60
+ return new Promise((resolve, reject) => {
61
+ const srv = createServer();
62
+ srv.listen(0, '127.0.0.1', () => {
63
+ const address = srv.address();
64
+ if (address === null || typeof address === 'string') {
65
+ reject(new Error('no port'));
66
+ return;
67
+ }
68
+ srv.close(() => resolve(address.port));
69
+ });
70
+ });
71
+ }
72
+
73
+ async function signIn(email: string, password: string): Promise<string> {
74
+ const res = await fetch(`${base}/api/v1/auth/sign-in/email`, {
75
+ method: 'POST',
76
+ headers: { 'content-type': 'application/json' },
77
+ body: JSON.stringify({ email, password })
78
+ });
79
+ expect(res.status).toBe(200);
80
+ return extractCookie(res);
81
+ }
82
+
83
+ /** GET /oauth2/authorize → the redirect target (302 or JSON shape). */
84
+ async function authorize(cookie: string): Promise<{ location: string; verifier: string }> {
85
+ const verifier = b64url(randomBytes(48));
86
+ const challenge = b64url(createHash('sha256').update(verifier).digest());
87
+ const params = new URLSearchParams({
88
+ response_type: 'code',
89
+ client_id: clientId,
90
+ redirect_uri: REDIRECT_URI,
91
+ scope: `openid offline_access ${host.scopes.read} ${host.scopes.write}`,
92
+ state: 'ws-state',
93
+ code_challenge: challenge,
94
+ code_challenge_method: 'S256',
95
+ resource: `${base}/mcp`
96
+ });
97
+ const res = await fetch(`${base}/api/v1/auth/oauth2/authorize?${params}`, {
98
+ headers: { cookie },
99
+ redirect: 'manual'
100
+ });
101
+ let location: string;
102
+ if (res.status === 302) {
103
+ location = res.headers.get('location') ?? '';
104
+ } else {
105
+ expect(res.status).toBe(200);
106
+ const body = await readJson(res);
107
+ expect(body.redirect).toBe(true);
108
+ location = body.url;
109
+ }
110
+ return { location, verifier };
111
+ }
112
+
113
+ /** POST the signed query back as consent, returning the code redirect URL. */
114
+ async function consent(cookie: string, consentLocation: string): Promise<Response> {
115
+ const signedQuery = consentLocation.split('?')[1] ?? '';
116
+ return fetch(`${base}/api/v1/auth/oauth2/consent`, {
117
+ method: 'POST',
118
+ headers: { cookie, 'content-type': 'application/json' },
119
+ body: JSON.stringify({ accept: true, oauth_query: signedQuery })
120
+ });
121
+ }
122
+
123
+ async function exchange(code: string, verifier: string): Promise<Response> {
124
+ return fetch(`${base}/api/v1/auth/oauth2/token`, {
125
+ method: 'POST',
126
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
127
+ body: new URLSearchParams({
128
+ grant_type: 'authorization_code',
129
+ code,
130
+ redirect_uri: REDIRECT_URI,
131
+ client_id: clientId,
132
+ code_verifier: verifier,
133
+ resource: `${base}/mcp`
134
+ })
135
+ });
136
+ }
137
+
138
+ async function refresh(refreshToken: string): Promise<Response> {
139
+ return fetch(`${base}/api/v1/auth/oauth2/token`, {
140
+ method: 'POST',
141
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
142
+ body: new URLSearchParams({
143
+ grant_type: 'refresh_token',
144
+ refresh_token: refreshToken,
145
+ client_id: clientId,
146
+ resource: `${base}/mcp`
147
+ })
148
+ });
149
+ }
150
+
151
+ /** Full dance for a cookie: authorize (+consent when asked) → code → tokens. */
152
+ async function dance(cookie: string): Promise<{ accessToken: string; refreshToken: string }> {
153
+ const { location, verifier } = await authorize(cookie);
154
+ let codeUrl: URL;
155
+ if (location.includes('/oauth/consent?')) {
156
+ const consented = await consent(cookie, location);
157
+ expect(consented.status).toBe(200);
158
+ const body = await readJson(consented);
159
+ codeUrl = new URL(body.redirect_uri ?? body.url ?? '');
160
+ } else {
161
+ codeUrl = new URL(location); // silent re-authorize (existing consent)
162
+ }
163
+ expect(codeUrl.origin + codeUrl.pathname).toBe(REDIRECT_URI);
164
+ const code = codeUrl.searchParams.get('code');
165
+ expect(code).toBeTruthy();
166
+ const token = await exchange(code!, verifier);
167
+ expect(token.status).toBe(200);
168
+ const grant = await readJson(token);
169
+ expect(grant.access_token.split('.')).toHaveLength(3);
170
+ return { accessToken: grant.access_token, refreshToken: grant.refresh_token };
171
+ }
172
+
173
+ beforeAll(async () => {
174
+ container = await startPostgres();
175
+ const dbUrl = await createDatabase(container, 'oauth_ws');
176
+ const port = await freePort();
177
+ base = `http://127.0.0.1:${port}`;
178
+ app = await createTestApp(dbUrl, { PUBLIC_BASE_URL: base });
179
+ server = serve({ fetch: app.app.fetch, port, hostname: '127.0.0.1' });
180
+
181
+ const setup = await fetch(`${base}/api/v1/setup`, {
182
+ method: 'POST',
183
+ headers: { 'content-type': 'application/json' },
184
+ body: JSON.stringify({ setupToken: SETUP_TOKEN, instanceName: 'OAuth WS One', owner: OWNER })
185
+ });
186
+ expect(setup.status).toBe(201);
187
+ w1 = (await readJson(setup)).workspaceId;
188
+
189
+ ownerCookie = await signIn(OWNER.email, OWNER.password);
190
+ const me = await readJson(await fetch(`${base}/api/v1/me`, { headers: { cookie: ownerCookie } }));
191
+ ownerId = me.user.id;
192
+ w2 = (await app.registry.workspaces.create('OAuth WS Two', ownerId)).workspaceId;
193
+
194
+ const bob = await app.auth.api.signUpEmail({
195
+ body: { email: BOB.email, password: BOB.password, name: BOB.name }
196
+ });
197
+ bobId = bob.user.id;
198
+ w3 = (await app.registry.workspaces.create('Bob WS', bobId)).workspaceId;
199
+ bobCookie = await signIn(BOB.email, BOB.password);
200
+
201
+ const register = await fetch(`${base}/api/v1/auth/oauth2/register`, {
202
+ method: 'POST',
203
+ headers: { 'content-type': 'application/json' },
204
+ body: JSON.stringify({
205
+ client_name: 'ws-binding-client',
206
+ redirect_uris: [REDIRECT_URI],
207
+ token_endpoint_auth_method: 'none',
208
+ grant_types: ['authorization_code', 'refresh_token'],
209
+ response_types: ['code']
210
+ })
211
+ });
212
+ expect([200, 201]).toContain(register.status);
213
+ clientId = (await readJson(register)).client_id;
214
+
215
+ // The workspaces need distinguishable data for the org-as-parameter tests.
216
+ for (const [ws, name] of [
217
+ [w1, 'w1-oauth.txt'],
218
+ [w2, 'w2-oauth.txt']
219
+ ] as const) {
220
+ const up = await fetch(`${base}/api/v1/files?name=${name}`, {
221
+ method: 'POST',
222
+ headers: { cookie: ownerCookie, 'content-type': 'text/plain', [WS_HEADER]: ws },
223
+ body: `${name} bytes`
224
+ });
225
+ expect(up.status).toBe(201);
226
+ }
227
+ }, 240_000);
228
+
229
+ afterAll(async () => {
230
+ await new Promise<void>((resolve) => server?.close(() => resolve()));
231
+ await app?.stop();
232
+ await container?.stop();
233
+ });
234
+
235
+ describe('claimless issuance ("act as you")', () => {
236
+ let ownerTokens: { accessToken: string; refreshToken: string };
237
+
238
+ it('a multi-workspace user gets ONE grant with NO workspace claim', async () => {
239
+ ownerTokens = await dance(ownerCookie);
240
+ const payload = jwtPayload(ownerTokens.accessToken);
241
+ expect(payload.workspace_id).toBeUndefined();
242
+ expect(payload.role).toBeUndefined();
243
+ expect(payload.email).toBe(OWNER.email);
244
+ expect(payload.sub).toBe(ownerId);
245
+ });
246
+
247
+ it('refresh re-mints stay claimless (and rotate)', async () => {
248
+ const res = await refresh(ownerTokens.refreshToken);
249
+ expect(res.status).toBe(200);
250
+ const grant = await readJson(res);
251
+ expect(grant.refresh_token).not.toBe(ownerTokens.refreshToken);
252
+ const payload = jwtPayload(grant.access_token);
253
+ expect(payload.workspace_id).toBeUndefined();
254
+ expect(payload.email).toBe(OWNER.email);
255
+ ownerTokens = { accessToken: grant.access_token, refreshToken: grant.refresh_token };
256
+ });
257
+
258
+ it('org as a parameter: the ONE token reaches each workspace via X-Workspace-Id', async () => {
259
+ const auth = { authorization: `Bearer ${ownerTokens.accessToken}` };
260
+ // No selector → the default rule (oldest membership, w1).
261
+ const meDefault = await readJson(await fetch(`${base}/api/v1/me`, { headers: auth }));
262
+ expect(meDefault.activeWorkspaceId).toBe(w1);
263
+ // Every credential kind lists ALL memberships with explicit flags.
264
+ expect(meDefault.workspaces.map((w: { id: string }) => w.id)).toEqual([w1, w2]);
265
+ expect(meDefault.workspaces.every((w: { default: boolean }) => w.default === false)).toBe(true);
266
+
267
+ const filesW1 = await readJson(await fetch(`${base}/api/v1/files`, { headers: auth }));
268
+ expect(filesW1.files.map((f: { originalName: string }) => f.originalName)).toEqual(['w1-oauth.txt']);
269
+ const filesW2 = await readJson(
270
+ await fetch(`${base}/api/v1/files`, { headers: { ...auth, [WS_HEADER]: w2 } })
271
+ );
272
+ expect(filesW2.files.map((f: { originalName: string }) => f.originalName)).toEqual(['w2-oauth.txt']);
273
+
274
+ // A workspace the user does NOT belong to fails closed — same 401 as a
275
+ // nonexistent one (no oracle), and same for a malformed selector.
276
+ for (const target of [w3, '00000000-0000-4000-8000-000000000000', 'not-a-uuid']) {
277
+ const res = await fetch(`${base}/api/v1/me`, { headers: { ...auth, [WS_HEADER]: target } });
278
+ expect(res.status, target).toBe(401);
279
+ }
280
+ });
281
+
282
+ it('issuance fails closed for a user with NO active membership left', async () => {
283
+ const bobTokens = await dance(bobCookie);
284
+ // The 0009 last-owner trigger forbids deactivating the sole owner — seed
285
+ // a sibling owner first; this test is about the issuance gate.
286
+ const siblingId = `sibling-${bobId}`;
287
+ await app.db.pool.query(
288
+ `INSERT INTO "user" (id, name, email, email_verified) VALUES ($1, 'Sibling Owner', $2, true)`,
289
+ [siblingId, `sibling-${Date.now()}@oauthws.test`]
290
+ );
291
+ await app.db.pool.query(
292
+ `INSERT INTO workspace_members (workspace_id, user_id, role, is_active) VALUES ($1, $2, 'owner', true)`,
293
+ [w3, siblingId]
294
+ );
295
+ await app.db.pool.query(
296
+ `UPDATE workspace_members SET is_active = false WHERE user_id = $1 AND workspace_id = $2`,
297
+ [bobId, w3]
298
+ );
299
+ try {
300
+ // The refresh grant re-runs the issuance gate and refuses…
301
+ const res = await refresh(bobTokens.refreshToken);
302
+ expect(res.ok).toBe(false);
303
+ expect(JSON.stringify(await readJson(res).catch(() => ({})))).toContain('access_denied');
304
+ // …and the still-unexpired access token dies at the live re-check.
305
+ const me = await fetch(`${base}/api/v1/me`, {
306
+ headers: { authorization: `Bearer ${bobTokens.accessToken}` }
307
+ });
308
+ expect(me.status).toBe(401);
309
+ } finally {
310
+ await app.db.pool.query(
311
+ `UPDATE workspace_members SET is_active = true WHERE user_id = $1 AND workspace_id = $2`,
312
+ [bobId, w3]
313
+ );
314
+ await app.db.pool.query(`DELETE FROM workspace_members WHERE user_id = $1`, [siblingId]);
315
+ await app.db.pool.query(`DELETE FROM "user" WHERE id = $1`, [siblingId]);
316
+ }
317
+ });
318
+ });
319
+
320
+ describe('the consent-workspace machinery is gone', () => {
321
+ it('POST /oauth/consent-workspace no longer exists (JSON 404, both credential kinds)', async () => {
322
+ const asSession = await fetch(`${base}/api/v1/oauth/consent-workspace`, {
323
+ method: 'POST',
324
+ headers: { cookie: ownerCookie, 'content-type': 'application/json' },
325
+ body: JSON.stringify({ workspaceId: w1 })
326
+ });
327
+ expect(asSession.status).toBe(404);
328
+ expect((await readJson(asSession)).error.code).toBe('not_found');
329
+ });
330
+ });
331
+
332
+ describe('claimless-JWT resolution (OauthJwtVerifier)', () => {
333
+ it('resolves by SELECTOR, defaults deterministically, and ignores workspace claims', async () => {
334
+ const { publicKey, privateKey } = await generateKeyPair('RS256');
335
+ const jwk = { ...(await exportJWK(publicKey)), alg: 'RS256', kid: 'ws-test' };
336
+ const fakeAuth = { api: { getJwks: async () => ({ keys: [jwk] }) } } as unknown as Auth;
337
+ const verifier = new OauthJwtVerifier(fakeAuth, app.db.db, base);
338
+
339
+ const sign = (sub: string, workspaceClaim?: string) =>
340
+ new SignJWT({
341
+ scope: host.scopes.read,
342
+ ...(workspaceClaim ? { workspace_id: workspaceClaim } : {})
343
+ })
344
+ .setProtectedHeader({ alg: 'RS256', kid: 'ws-test' })
345
+ .setIssuer(base)
346
+ .setAudience(`${base}/mcp`)
347
+ .setSubject(sub)
348
+ .setIssuedAt()
349
+ .setExpirationTime('5m')
350
+ .sign(privateKey);
351
+
352
+ // The selector picks the membership…
353
+ const selected = await verifier.resolve(await sign(ownerId), w2);
354
+ expect(selected?.workspaceId).toBe(w2);
355
+ // …absent, the multi-workspace user resolves to the deterministic
356
+ // default (the old claimless fail-closed rule died with claims)…
357
+ const defaulted = await verifier.resolve(await sign(ownerId), null);
358
+ expect(defaulted?.workspaceId).toBe(w1);
359
+ // …and a legacy workspace_id CLAIM is never an authorization input: it
360
+ // neither selects (default still wins) nor grants (a foreign claim
361
+ // cannot reach the workspace).
362
+ const claimIgnored = await verifier.resolve(await sign(ownerId, w2), null);
363
+ expect(claimIgnored?.workspaceId).toBe(w1);
364
+ const foreignClaim = await verifier.resolve(await sign(bobId, w1), null);
365
+ expect(foreignClaim?.workspaceId).toBe(w3);
366
+ // A selector naming a workspace the subject does not belong to → null.
367
+ expect(await verifier.resolve(await sign(bobId), w1)).toBeNull();
368
+ // A malformed selector never reaches the uuid cast → null, not a 500.
369
+ expect(await verifier.resolve(await sign(ownerId), 'not-a-uuid')).toBeNull();
370
+ });
371
+ });
@@ -0,0 +1,183 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
2
+ import type { StartedPostgreSqlContainer } from '@testcontainers/postgresql';
3
+ import type { UsageEvent } from '@antasphere/chassis-contract';
4
+ import { desc } from 'drizzle-orm';
5
+ import { auditLog } from '@antasphere/chassis-db';
6
+ import {
7
+ createDatabase,
8
+ createTestApp,
9
+ extractCookie,
10
+ startPostgres,
11
+ type TestApp,
12
+ host
13
+ } from './helpers.js';
14
+
15
+ /**
16
+ * M5: metrics scrapeable + populated, security headers everywhere,
17
+ * request-id correlation across log/audit, and the usage pipeline running
18
+ * end-to-end through pg-boss into the downstream sink.
19
+ *
20
+ * (The PRIV-1 pin on the viewer's `/v/:secret` metrics label is the tool's: the
21
+ * tool's app keeps it, `apps/server/test/integration/observability-viewer.test.ts`.)
22
+ */
23
+
24
+ const OWNER = { email: 'owner@obs.test', name: 'Obs Owner', password: 'obs-owner-password-123' };
25
+
26
+ let container: StartedPostgreSqlContainer;
27
+ let app: TestApp;
28
+ let cookie: string;
29
+ const receivedUsage: UsageEvent[] = [];
30
+ /** What the worker handed the downstream: whole batches, and how many single emits (expected none). */
31
+ const batches: UsageEvent[][] = [];
32
+ let singles = 0;
33
+
34
+ const json = (body: unknown) => ({
35
+ method: 'POST',
36
+ headers: { 'content-type': 'application/json' },
37
+ body: JSON.stringify(body)
38
+ });
39
+
40
+ beforeAll(async () => {
41
+ container = await startPostgres();
42
+ app = await createTestApp(
43
+ await createDatabase(container, 'obs'),
44
+ { METRICS_TOKEN: 'obs-metrics-token' },
45
+ {
46
+ usageDownstream: {
47
+ async emit(event) {
48
+ singles += 1;
49
+ receivedUsage.push(event);
50
+ },
51
+ async emitBatch(events) {
52
+ batches.push([...events]);
53
+ receivedUsage.push(...events);
54
+ }
55
+ }
56
+ }
57
+ );
58
+ await app.app.request(
59
+ '/api/v1/setup',
60
+ json({ setupToken: 'integration-test-setup-token', instanceName: 'Obs', owner: OWNER })
61
+ );
62
+ const signIn = await app.app.request(
63
+ '/api/v1/auth/sign-in/email',
64
+ json({ email: OWNER.email, password: OWNER.password })
65
+ );
66
+ cookie = extractCookie(signIn);
67
+ });
68
+
69
+ afterAll(async () => {
70
+ await app?.stop();
71
+ await container?.stop();
72
+ });
73
+
74
+ describe('security headers', () => {
75
+ it('sets nosniff + referrer policy on API responses', async () => {
76
+ const res = await app.app.request('/api/v1/instance');
77
+ expect(res.headers.get('x-content-type-options')).toBe('nosniff');
78
+ expect(res.headers.get('referrer-policy')).toBe('strict-origin-when-cross-origin');
79
+ });
80
+
81
+ it('locks HTML responses behind the CSP (frame-ancestors none)', async () => {
82
+ const res = await app.app.request('/some-spa-route');
83
+ const csp = res.headers.get('content-security-policy');
84
+ expect(csp).toBeTruthy();
85
+ expect(csp).toContain("frame-ancestors 'none'");
86
+ expect(csp).toContain("default-src 'self'");
87
+ });
88
+ });
89
+
90
+ describe('metrics', () => {
91
+ it('scrapes populated http metrics after traffic (with the token)', async () => {
92
+ await app.app.request('/api/v1/instance');
93
+ const res = await app.app.request('/metrics', {
94
+ headers: { authorization: 'Bearer obs-metrics-token' }
95
+ });
96
+ expect(res.status).toBe(200);
97
+ const body = await res.text();
98
+ expect(body).toContain('http_request_duration_seconds_bucket');
99
+ expect(body).toContain('/api/v1/instance');
100
+ expect(body).toContain('job_queue_depth');
101
+ expect(body).toContain('storage_bytes_total');
102
+ expect(body).toContain('process_cpu_user_seconds_total');
103
+ });
104
+
105
+ it('enforces METRICS_TOKEN when configured', async () => {
106
+ const denied = await app.app.request('/metrics');
107
+ expect(denied.status).toBe(401);
108
+ const wrong = await app.app.request('/metrics', {
109
+ headers: { authorization: 'Bearer not-the-token' }
110
+ });
111
+ expect(wrong.status).toBe(401);
112
+ });
113
+
114
+ it('is disabled (401) by default when no METRICS_TOKEN is set', async () => {
115
+ const url = await createDatabase(container, 'obs_notoken');
116
+ const openApp = await createTestApp(url);
117
+ try {
118
+ const res = await openApp.app.request('/metrics');
119
+ expect(res.status).toBe(401);
120
+ expect(await res.text()).toContain('METRICS_TOKEN');
121
+ } finally {
122
+ await openApp.stop();
123
+ }
124
+ });
125
+ });
126
+
127
+ describe('request-id correlation (exit criterion 11)', () => {
128
+ it('one request id flows response header → audit row', async () => {
129
+ const res = await app.app.request('/api/v1/api-keys', {
130
+ ...json({ name: 'corr key', scopes: [host.scopes.read] }),
131
+ headers: { 'content-type': 'application/json', cookie, 'x-request-id': 'corr-test-0001' }
132
+ });
133
+ expect(res.status).toBe(201);
134
+ expect(res.headers.get('x-request-id')).toBe('corr-test-0001');
135
+
136
+ const [row] = await app.db.db.select().from(auditLog).orderBy(desc(auditLog.id)).limit(1);
137
+ expect(row?.requestId).toBe('corr-test-0001');
138
+ // The same id is stamped on the request's OTel span as `request.id`
139
+ // (observability/otel.ts) and on the pino line as `requestId`.
140
+ });
141
+ });
142
+
143
+ describe('usage pipeline end-to-end (seam proof)', () => {
144
+ it('an event handed to the sink reaches the downstream via pg-boss; an oss upload hands it nothing', async () => {
145
+ // The self-hosted edition is unmetered by construction (the billing rail,
146
+ // PRDCT-2626): the entitlement gate emits no event on oss, so an upload
147
+ // leaves the queue untouched...
148
+ const res = await app.app.request('/api/v1/files?name=usage.txt', {
149
+ method: 'POST',
150
+ headers: { 'content-type': 'text/plain', cookie },
151
+ body: 'metered bytes'
152
+ });
153
+ expect(res.status).toBe(201);
154
+ await new Promise((r) => setTimeout(r, 2_500)); // longer than the worker's poll
155
+ expect(receivedUsage).toEqual([]);
156
+
157
+ // ...while the durable pipeline itself (the sink → pg-boss → the
158
+ // downstream, what the cloud poster rides) stays proven from the seam:
159
+ // the worker hands the drained batch WHOLE to a downstream that takes
160
+ // batches (one hub post per batch, never one per event).
161
+ const event: UsageEvent = {
162
+ id: '01JZZZZZZZZZZZZZZZZZZZZZZ0',
163
+ meter: 'files.upload',
164
+ actionKey: 'files.upload',
165
+ quantity: 13,
166
+ unit: 'bytes',
167
+ occurredAt: new Date().toISOString(),
168
+ workspaceId: '00000000-0000-0000-0000-000000000000',
169
+ accountRef: '77777777-aaaa-4bbb-8ccc-000000000obs',
170
+ userId: null,
171
+ via: 'session',
172
+ source: { instanceId: '01JZZZZZZZZZZZZZZZZZZZZZZ1', edition: 'oss', version: 'test' }
173
+ };
174
+ await app.registry.usage.emit(event);
175
+ const deadline = Date.now() + 15_000;
176
+ while (receivedUsage.length === 0 && Date.now() < deadline) {
177
+ await new Promise((r) => setTimeout(r, 250));
178
+ }
179
+ expect(receivedUsage).toEqual([event]);
180
+ expect(batches).toEqual([[event]]);
181
+ expect(singles).toBe(0);
182
+ }, 30_000);
183
+ });