@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,75 @@
1
+ import { count, eq, lt, desc } from 'drizzle-orm';
2
+ import { auditListRoute } from '@antasphere/chassis-contract/routes';
3
+ import { auditLog, user as userTable } from '@antasphere/chassis-db';
4
+ import { requireRole } from '../middleware/auth-context.js';
5
+ import { auditFilterConditions, auditWhere, cursorId } from '../audit/filters.js';
6
+ export function registerAuditRoutes(api, db) {
7
+ api.use('/audit', requireRole('admin'));
8
+ api.openapi(auditListRoute, async (c) => {
9
+ const principal = c.get('principal');
10
+ const query = c.req.valid('query');
11
+ const { limit } = query;
12
+ // SECURITY: the scope is the caller's workspace and nothing in the
13
+ // query can widen it; every filter narrows within it, as a bound
14
+ // parameter (audit/filters.ts). The cursor stays the last row id, so
15
+ // a page is "the next `limit` rows older than the cursor that match
16
+ // the same filters": a client that changes a filter starts over.
17
+ const scope = eq(auditLog.workspaceId, principal.workspaceId);
18
+ const filters = auditFilterConditions(query);
19
+ const cursor = cursorId(query.cursor);
20
+ const where = auditWhere(scope, filters, cursor !== null ? lt(auditLog.id, cursor) : null);
21
+ const rows = await db
22
+ .select({
23
+ id: auditLog.id,
24
+ actorUserId: auditLog.actorUserId,
25
+ actorEmail: userTable.email,
26
+ actorVia: auditLog.actorVia,
27
+ apiKeyId: auditLog.apiKeyId,
28
+ action: auditLog.action,
29
+ resourceType: auditLog.resourceType,
30
+ resourceId: auditLog.resourceId,
31
+ requestId: auditLog.requestId,
32
+ ip: auditLog.ip,
33
+ metadata: auditLog.metadata,
34
+ createdAt: auditLog.createdAt
35
+ })
36
+ .from(auditLog)
37
+ .leftJoin(userTable, eq(auditLog.actorUserId, userTable.id))
38
+ .where(where)
39
+ .orderBy(desc(auditLog.id))
40
+ .limit(limit + 1);
41
+ // The total is counted once per listing, on the first page: the count
42
+ // walks the same join and WHERE without the cursor, and a client keeps
43
+ // the figure while it loads the pages after.
44
+ let total = null;
45
+ if (cursor === null) {
46
+ const [counted] = await db
47
+ .select({ n: count() })
48
+ .from(auditLog)
49
+ .leftJoin(userTable, eq(auditLog.actorUserId, userTable.id))
50
+ .where(auditWhere(scope, filters, null));
51
+ total = counted?.n ?? 0;
52
+ }
53
+ const page = rows.slice(0, limit);
54
+ const nextCursor = rows.length > limit ? String(page[page.length - 1]?.id ?? '') : null;
55
+ return c.json({
56
+ entries: page.map((r) => ({
57
+ id: r.id,
58
+ actorUserId: r.actorUserId,
59
+ actorEmail: r.actorEmail,
60
+ actorVia: r.actorVia,
61
+ apiKeyId: r.apiKeyId,
62
+ action: r.action,
63
+ resourceType: r.resourceType,
64
+ resourceId: r.resourceId,
65
+ requestId: r.requestId,
66
+ ip: r.ip,
67
+ metadata: r.metadata,
68
+ createdAt: r.createdAt.toISOString()
69
+ })),
70
+ nextCursor,
71
+ total
72
+ }, 200);
73
+ });
74
+ }
75
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/api/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { OpenAPIHono } from '@hono/zod-openapi';
2
+ import { type Db } from '@antasphere/chassis-db';
3
+ import type { Auth } from '../identity/better-auth.js';
4
+ import type { AuditService } from '../audit/service.js';
5
+ import type { Logger } from '../logger.js';
6
+ /**
7
+ * Break-glass superadmin recovery (ADR 010) — the instance-level recovery
8
+ * surface for the per-tenant hosting model. Two capabilities only:
9
+ *
10
+ * - claim-ownership: make the calling superadmin (or a named existing user)
11
+ * an ACTIVE OWNER of a workspace — creating the membership when absent,
12
+ * reactivating and promoting when present. It ADDS an owner and never
13
+ * removes one, so the migration-0009 last-owner trigger is satisfied by
14
+ * construction. The target workspace is explicit (`workspaceId`) once the
15
+ * instance runs several (ADR 014); a single-workspace instance keeps the
16
+ * old no-argument call.
17
+ * - reset-2fa: clear a locked-out user's second factor (the recovery ADR 009
18
+ * deferred to manual DB surgery). User-level — needs no workspace; its
19
+ * audit row is instance-attributed.
20
+ *
21
+ * SAFETY MODEL (a bug here = full instance compromise — keep all of it):
22
+ *
23
+ * - Off by default: superadmin exists ONLY while SUPERADMIN_EMAILS is set.
24
+ * - Session-only, twice over: these paths are deliberately UNLISTED in the
25
+ * fail-closed scope allowlist (middleware/scopes.ts), so machine
26
+ * principals 403 before reaching the handlers; AND the handlers resolve
27
+ * the Better Auth session directly — a request without a session cookie
28
+ * can never qualify, whatever headers it carries.
29
+ * - Verified email required: an allowlisted address that was never proven
30
+ * (invitation copyable-link accounts are unverified) does NOT match.
31
+ * - Identity is re-read from the DB by session user id — never derived from
32
+ * any header, body field, or client-supplied value.
33
+ * - No requireAuth()/requireRole() gate: the recovering operator may hold a
34
+ * session with NO membership (principal resolves to null), which is
35
+ * exactly the state break-glass exists to fix. The handlers do their own
36
+ * authentication and are exempted from the generic audit middleware
37
+ * because they write their own richer rows (see audit/service.ts).
38
+ */
39
+ export interface BreakGlassRouteDeps {
40
+ db: Db;
41
+ auth: Auth;
42
+ audit: AuditService;
43
+ logger: Logger;
44
+ /** Raw SUPERADMIN_EMAILS value (already validated by the env schema). */
45
+ superadminEmails: string | undefined;
46
+ }
47
+ export declare function registerBreakGlassRoutes(api: OpenAPIHono, deps: BreakGlassRouteDeps): void;
48
+ //# sourceMappingURL=break-glass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"break-glass.d.ts","sourceRoot":"","sources":["../../src/api/break-glass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAOrD,OAAO,EAA8D,KAAK,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAC7G,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,EAAE,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AASD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAsO1F"}
@@ -0,0 +1,217 @@
1
+ import { and, eq } from 'drizzle-orm';
2
+ import { breakGlassClaimOwnershipRoute, breakGlassResetTwoFactorRoute } from '@antasphere/chassis-contract/routes';
3
+ import { twoFactor, user as userTable, workspaceMembers, workspaces } from '@antasphere/chassis-db';
4
+ import { parseSuperadminEmails } from '../accounts/superadmin.js';
5
+ const err = (code, message) => ({ error: { code, message } });
6
+ export function registerBreakGlassRoutes(api, deps) {
7
+ const { db, auth, audit, logger } = deps;
8
+ const allowlist = parseSuperadminEmails(deps.superadminEmails);
9
+ /**
10
+ * Resolve the caller as a superadmin. One uniform `forbidden` for every
11
+ * rejection reason (dormant, not listed, unverified) so the endpoint is
12
+ * not an oracle for the allowlist's contents.
13
+ */
14
+ const resolveSuperadmin = async (c) => {
15
+ // Session-only: the verified session identity, never a header or bearer.
16
+ // Machine credentials died at the fail-closed scope gate already; a
17
+ // cookieless request has no session and stops here.
18
+ const session = await auth.api.getSession({ headers: c.req.raw.headers });
19
+ if (!session?.user)
20
+ return { kind: 'unauthenticated' };
21
+ if (allowlist.size === 0)
22
+ return { kind: 'forbidden' };
23
+ // Fresh row by session user id — email + verification state are read
24
+ // from the database, not trusted from session claims.
25
+ const [u] = await db
26
+ .select({
27
+ id: userTable.id,
28
+ email: userTable.email,
29
+ emailVerified: userTable.emailVerified,
30
+ name: userTable.name
31
+ })
32
+ .from(userTable)
33
+ .where(eq(userTable.id, session.user.id))
34
+ .limit(1);
35
+ if (!u)
36
+ return { kind: 'forbidden' };
37
+ if (!allowlist.has(u.email.toLowerCase()))
38
+ return { kind: 'forbidden' };
39
+ if (!u.emailVerified)
40
+ return { kind: 'forbidden' };
41
+ return { kind: 'ok', caller: { userId: u.id, email: u.email, name: u.name } };
42
+ };
43
+ /**
44
+ * The workspace an owner-claim targets (ADR 014). Explicit `workspaceId`
45
+ * wins; omitted, it resolves ONLY while the instance runs a single
46
+ * workspace — with several, recovery must name its target (400
47
+ * workspace_required), never guess one.
48
+ */
49
+ const resolveTargetWorkspace = async (explicit) => {
50
+ if (explicit) {
51
+ const [ws] = await db
52
+ .select({ id: workspaces.id })
53
+ .from(workspaces)
54
+ .where(eq(workspaces.id, explicit))
55
+ .limit(1);
56
+ return ws ? { kind: 'ok', id: ws.id } : { kind: 'not_found' };
57
+ }
58
+ const rows = await db.select({ id: workspaces.id }).from(workspaces).limit(2);
59
+ const [only] = rows;
60
+ if (!only)
61
+ return { kind: 'not_setup' };
62
+ if (rows.length > 1)
63
+ return { kind: 'ambiguous' };
64
+ return { kind: 'ok', id: only.id };
65
+ };
66
+ api.openapi(breakGlassClaimOwnershipRoute, async (c) => {
67
+ const resolved = await resolveSuperadmin(c);
68
+ if (resolved.kind === 'unauthenticated') {
69
+ return c.json(err('unauthenticated', 'Authentication required'), 401);
70
+ }
71
+ if (resolved.kind === 'forbidden') {
72
+ return c.json(err('forbidden', 'Break-glass is not available to this caller'), 403);
73
+ }
74
+ const caller = resolved.caller;
75
+ const body = c.req.valid('json');
76
+ const targetWs = await resolveTargetWorkspace(body.workspaceId);
77
+ if (targetWs.kind === 'not_setup') {
78
+ return c.json(err('not_setup', 'This instance has not completed setup'), 409);
79
+ }
80
+ if (targetWs.kind === 'not_found') {
81
+ return c.json(err('not_found', 'Target workspace not found'), 404);
82
+ }
83
+ if (targetWs.kind === 'ambiguous') {
84
+ return c.json(err('workspace_required', 'This instance has several workspaces — pass workspaceId explicitly'), 400);
85
+ }
86
+ const ws = { id: targetWs.id };
87
+ // Target: a named existing user, or the calling superadmin.
88
+ let target = { userId: caller.userId, email: caller.email };
89
+ if (body.userId) {
90
+ const [t] = await db
91
+ .select({ id: userTable.id, email: userTable.email })
92
+ .from(userTable)
93
+ .where(eq(userTable.id, body.userId))
94
+ .limit(1);
95
+ if (!t)
96
+ return c.json(err('not_found', 'Target user not found'), 404);
97
+ target = { userId: t.id, email: t.email };
98
+ }
99
+ const [before] = await db
100
+ .select({
101
+ id: workspaceMembers.id,
102
+ role: workspaceMembers.role,
103
+ isActive: workspaceMembers.isActive
104
+ })
105
+ .from(workspaceMembers)
106
+ .where(and(eq(workspaceMembers.workspaceId, ws.id), eq(workspaceMembers.userId, target.userId)))
107
+ .limit(1);
108
+ // Additive by construction: create-or-promote to an ACTIVE OWNER. The
109
+ // 0009 last-owner trigger only rejects operations that REMOVE the last
110
+ // active owner — adding one is always legal, including the first owner
111
+ // of an ownerless workspace.
112
+ const [after] = await db
113
+ .insert(workspaceMembers)
114
+ // origin='local' on BOTH paths (BG-1, PRDCT-1356): a break-glass owner
115
+ // is the tool's own business, never hub truth. Left at 'hub' (the
116
+ // conflict path once kept the row's old origin), the cloud reconciler's
117
+ // deactivation sweep — which targets origin='hub' rows the hub no
118
+ // longer asserts — undid the recovery ~12 s later.
119
+ .values({ workspaceId: ws.id, userId: target.userId, role: 'owner', isActive: true, origin: 'local' })
120
+ .onConflictDoUpdate({
121
+ target: [workspaceMembers.workspaceId, workspaceMembers.userId],
122
+ set: { role: 'owner', isActive: true, origin: 'local' }
123
+ })
124
+ .returning({ id: workspaceMembers.id });
125
+ if (!after)
126
+ throw new Error('break-glass ownership upsert returned no row');
127
+ logger.warn({
128
+ superadminUserId: caller.userId,
129
+ superadminEmail: caller.email,
130
+ targetUserId: target.userId,
131
+ targetEmail: target.email,
132
+ workspaceId: ws.id
133
+ }, 'BREAK-GLASS: workspace ownership claimed');
134
+ await audit.write({
135
+ workspaceId: ws.id,
136
+ principal: { userId: caller.userId, via: 'session' },
137
+ action: 'break_glass.claim_ownership',
138
+ resourceType: 'member',
139
+ resourceId: after.id,
140
+ requestId: c.get('requestId'),
141
+ metadata: {
142
+ superadminUserId: caller.userId,
143
+ superadminEmail: caller.email,
144
+ targetUserId: target.userId,
145
+ targetEmail: target.email,
146
+ before: before ? { role: before.role, isActive: before.isActive } : null,
147
+ after: { role: 'owner', isActive: true },
148
+ created: !before
149
+ }
150
+ });
151
+ return c.json({
152
+ memberId: after.id,
153
+ userId: target.userId,
154
+ email: target.email,
155
+ workspaceId: ws.id,
156
+ role: 'owner',
157
+ isActive: true,
158
+ created: !before
159
+ }, 200);
160
+ });
161
+ api.openapi(breakGlassResetTwoFactorRoute, async (c) => {
162
+ const resolved = await resolveSuperadmin(c);
163
+ if (resolved.kind === 'unauthenticated') {
164
+ return c.json(err('unauthenticated', 'Authentication required'), 401);
165
+ }
166
+ if (resolved.kind === 'forbidden') {
167
+ return c.json(err('forbidden', 'Break-glass is not available to this caller'), 403);
168
+ }
169
+ const caller = resolved.caller;
170
+ const { userId } = c.req.valid('json');
171
+ const [target] = await db
172
+ .select({
173
+ id: userTable.id,
174
+ email: userTable.email,
175
+ twoFactorEnabled: userTable.twoFactorEnabled
176
+ })
177
+ .from(userTable)
178
+ .where(eq(userTable.id, userId))
179
+ .limit(1);
180
+ if (!target)
181
+ return c.json(err('not_found', 'Target user not found'), 404);
182
+ // Clear the factor: the two_factor row (secret + backup codes) and the
183
+ // user flag. Idempotent — resetting an unenrolled user is a no-op 200.
184
+ const removed = await db
185
+ .delete(twoFactor)
186
+ .where(eq(twoFactor.userId, target.id))
187
+ .returning({ id: twoFactor.id });
188
+ await db.update(userTable).set({ twoFactorEnabled: false }).where(eq(userTable.id, target.id));
189
+ const hadTwoFactor = removed.length > 0 || target.twoFactorEnabled === true;
190
+ logger.warn({
191
+ superadminUserId: caller.userId,
192
+ superadminEmail: caller.email,
193
+ targetUserId: target.id,
194
+ targetEmail: target.email,
195
+ hadTwoFactor
196
+ }, 'BREAK-GLASS: two-factor reset');
197
+ // INSTANCE-attributed (workspace_id NULL, ADR 014): a second factor is a
198
+ // user property, not any workspace's — the row needs no workspace home.
199
+ await audit.write({
200
+ workspaceId: null,
201
+ principal: { userId: caller.userId, via: 'session' },
202
+ action: 'break_glass.reset_two_factor',
203
+ resourceType: 'user',
204
+ resourceId: target.id,
205
+ requestId: c.get('requestId'),
206
+ metadata: {
207
+ superadminUserId: caller.userId,
208
+ superadminEmail: caller.email,
209
+ targetUserId: target.id,
210
+ targetEmail: target.email,
211
+ hadTwoFactor
212
+ }
213
+ });
214
+ return c.json({ userId: target.id, hadTwoFactor }, 200);
215
+ });
216
+ }
217
+ //# sourceMappingURL=break-glass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"break-glass.js","sourceRoot":"","sources":["../../src/api/break-glass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import type { OpenAPIHono } from '@hono/zod-openapi';
2
+ import type { ScopeRoutes } from './scope-routes.js';
3
+ import { type Db } from '@antasphere/chassis-db';
4
+ import type { Auth } from '../identity/better-auth.js';
5
+ import type { HubSsoService } from '../identity/hub-sso.js';
6
+ import type { ApiKeyService } from '../apikeys/service.js';
7
+ import type { AuditService } from '../audit/service.js';
8
+ import type { EmailDriver } from '../email/driver.js';
9
+ import type { Logger } from '../logger.js';
10
+ /**
11
+ * Browserless CLI/agent auth (the tool CLI's `auth login-*` flow):
12
+ *
13
+ * POST /cli/auth/request → email a 6-digit sign-in OTP
14
+ * POST /cli/auth/complete → verify the OTP, mint an API key
15
+ *
16
+ * Built ENTIRELY on the existing email-OTP primitive — no new credential
17
+ * machinery. `request` delegates to the emailOTP plugin's
18
+ * send-verification-otp (type "sign-in"); with the instance's
19
+ * `disableSignUp: true` an unknown email gets a generic success and NO mail
20
+ * (the plugin deletes the pending code — no enumeration oracle, no user
21
+ * minted). `complete` delegates to the plugin's sign-in endpoint, whose
22
+ * verification is atomic and attempt-limited (3 per code); with
23
+ * `disableSignUp` an unknown email fails exactly like a wrong code. So the
24
+ * closed-signup invariant (the three switches) is untouched: this surface
25
+ * can only ever sign in accounts that already exist (setup owner, workspace
26
+ * invitation, collaborator claim).
27
+ *
28
+ * On success the sign-in's throwaway session is used server-side only: mint
29
+ * the key (the tool's read + write scopes — the agent surface, never its
30
+ * export scope), DELETE the session, and return the key once. The
31
+ * "sessions only mint keys" rule holds in spirit: the mint is bound to a
32
+ * fresh, fully verified interactive sign-in, not to a machine credential
33
+ * (machine principals can't even reach these paths — they are unlisted in
34
+ * the scope allowlist and 403 fail-closed).
35
+ *
36
+ * 2FA-enrolled users are REJECTED (403 two_factor_required): the config
37
+ * hooks.after in identity/better-auth.ts parks their OTP sign-in behind the
38
+ * TOTP step, which a browserless flow cannot complete — they mint keys in
39
+ * the dashboard instead. Never bypass that hook here.
40
+ *
41
+ * Without a delivering email driver both endpoints answer 400
42
+ * otp_unavailable (the emailOTP plugin is not even registered then) —
43
+ * self-hosters without SMTP paste a dashboard-minted key (the CLI's `login`).
44
+ *
45
+ * On EDITION=cloud (hubSso present) BOTH mint endpoints refuse outright —
46
+ * 403 cli_otp_disabled, checked BEFORE the mailer/plugin checks so a
47
+ * mailerless cloud instance steers to `antasphere login` too. This is the
48
+ * CLI half of the D1 hub-only entrance closure (the human half is the
49
+ * emailOTP sign-in refusal in identity/better-auth.ts): every cloud
50
+ * credential — human session AND machine key — must trace through the hub
51
+ * so its audit log is the complete access record. Cloud CLI keys are minted
52
+ * by `antasphere login` + /sso/cli-connect (api/sso-connect.ts) instead.
53
+ * oss keeps this flow unchanged.
54
+ *
55
+ * DELETE /cli/auth/key (the CLI's `logout`) stays OPEN on both editions: it
56
+ * revokes exactly the PRESENTING key — revocation narrows access and is the
57
+ * cleanup path every mint above needs.
58
+ *
59
+ * Rate limits (api/index.ts): request rides the OTP wall (per IP + email),
60
+ * complete rides the login wall (per IP + email).
61
+ */
62
+ export interface CliAuthRouteDeps {
63
+ db: Db;
64
+ auth: Auth;
65
+ email: EmailDriver;
66
+ apiKeys: ApiKeyService;
67
+ audit: AuditService;
68
+ logger: Logger;
69
+ /**
70
+ * Cloud presence switch (internal/federation.md, D1 hub-only login): when set
71
+ * (EDITION=cloud boots only), the OTP mint pair refuses 403
72
+ * cli_otp_disabled. Only the boolean presence is consulted — the service
73
+ * itself is never called from this module. The self-revoke is unaffected.
74
+ */
75
+ hubSso?: HubSsoService | undefined;
76
+ /** The CLI key's fixed grant — the agent surface, never the export scope. */
77
+ cliKeyScopes: readonly string[];
78
+ /** The tool's instantiation of the scope-carrying mint route. */
79
+ routes: Pick<ScopeRoutes, 'cliAuthCompleteRoute'>;
80
+ /** The tool's name in the cloud refusal sentence (`identity.displayName`). */
81
+ displayName: string;
82
+ }
83
+ export declare function registerCliAuthRoutes(api: OpenAPIHono, deps: CliAuthRouteDeps): void;
84
+ //# sourceMappingURL=cli-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-auth.d.ts","sourceRoot":"","sources":["../../src/api/cli-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAA2B,KAAK,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,EAAE,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACnC,6EAA6E;IAC7E,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,iEAAiE;IACjE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC;IAClD,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;CACrB;AAoBD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAuMpF"}
@@ -0,0 +1,177 @@
1
+ import { and, eq, isNull, sql } from 'drizzle-orm';
2
+ import { cliAuthRequestRoute, cliAuthRevokeRoute } from '@antasphere/chassis-contract/routes';
3
+ import { apiKeys as apiKeysTable } from '@antasphere/chassis-db';
4
+ import { resolveMembership } from '../identity/resolve-membership.js';
5
+ const err = (code, message) => ({ error: { code, message } });
6
+ /** better-auth APIError carries { body: { code, message } }; match by code. */
7
+ function betterAuthErrorCode(e) {
8
+ const body = e?.body;
9
+ return typeof body?.code === 'string' ? body.code : null;
10
+ }
11
+ export function registerCliAuthRoutes(api, deps) {
12
+ const { db, auth, email, apiKeys, audit, logger, hubSso, cliKeyScopes } = deps;
13
+ const { cliAuthCompleteRoute } = deps.routes;
14
+ const otpApi = auth.api;
15
+ /** The D1 cloud refusal — identical on both mint routes, checked FIRST. */
16
+ const cloudRefusal = () => err('cli_otp_disabled', 'This instance signs in through the Antasphere hub — run `antasphere login` once; ' +
17
+ `the ${deps.displayName} CLI then connects automatically`);
18
+ api.openapi(cliAuthRequestRoute, async (c) => {
19
+ if (hubSso)
20
+ return c.json(cloudRefusal(), 403);
21
+ if (!email.delivers || !otpApi.sendVerificationOTP) {
22
+ return c.json(err('otp_unavailable', 'This instance has no email driver — sign in to the dashboard and mint an API key instead'), 400);
23
+ }
24
+ const body = c.req.valid('json');
25
+ try {
26
+ // Generic success either way; the plugin sends only to existing
27
+ // accounts (disableSignUp) — deliberately not observable here.
28
+ await otpApi.sendVerificationOTP({ body: { email: body.email, type: 'sign-in' } });
29
+ }
30
+ catch (cause) {
31
+ // INVALID_EMAIL can't happen (contract-validated); anything else is internal.
32
+ logger.error({ err: cause }, 'cli-auth: OTP send failed');
33
+ return c.json(err('internal', 'Could not send the sign-in code — try again'), 500);
34
+ }
35
+ return c.json({ sent: true }, 200);
36
+ });
37
+ api.openapi(cliAuthCompleteRoute, async (c) => {
38
+ if (hubSso)
39
+ return c.json(cloudRefusal(), 403);
40
+ if (!email.delivers || !otpApi.signInEmailOTP) {
41
+ return c.json(err('otp_unavailable', 'This instance has no email driver — sign in to the dashboard and mint an API key instead'), 400);
42
+ }
43
+ const body = c.req.valid('json');
44
+ let signedIn;
45
+ try {
46
+ signedIn = await otpApi.signInEmailOTP({ body: { email: body.email, otp: body.otp } });
47
+ }
48
+ catch (cause) {
49
+ const code = betterAuthErrorCode(cause);
50
+ if (code === 'TOO_MANY_ATTEMPTS') {
51
+ return c.json(err('too_many_attempts', 'Too many wrong codes — request a fresh one'), 429);
52
+ }
53
+ // INVALID_OTP covers wrong code AND unknown account (disableSignUp);
54
+ // OTP_EXPIRED joins them — one uniform 401, no enumeration.
55
+ if (code === 'INVALID_OTP' || code === 'OTP_EXPIRED' || code === 'USER_NOT_FOUND') {
56
+ return c.json(err('invalid_otp', 'The code is wrong, expired, or not for this email'), 401);
57
+ }
58
+ logger.error({ err: cause }, 'cli-auth: OTP sign-in failed');
59
+ return c.json(err('internal', 'Sign-in failed — try again'), 500);
60
+ }
61
+ // The 2FA hook (identity/better-auth.ts) parks enrolled users behind the
62
+ // TOTP step and answers { twoFactorRedirect } with no session. A
63
+ // browserless flow cannot complete that dance — refuse, never bypass.
64
+ if (!('token' in signedIn)) {
65
+ return c.json(err('two_factor_required', 'This account has two-factor auth enabled — sign in to the dashboard and mint an API key there'), 403);
66
+ }
67
+ const { token: sessionToken, user } = signedIn;
68
+ const dropSession = async () => {
69
+ try {
70
+ const authCtx = await auth.$context;
71
+ await authCtx.internalAdapter.deleteSession(sessionToken);
72
+ }
73
+ catch (cause) {
74
+ // Advisory: the session was never handed out; expiry bounds the residue.
75
+ logger.warn({ err: cause }, 'cli-auth: throwaway session cleanup failed');
76
+ }
77
+ };
78
+ // Same live-membership discipline as every credential path: no active
79
+ // membership, no key (e.g. a deactivated member's account still signs in
80
+ // at the Better Auth layer but has no standing on this instance). The
81
+ // key is USER-SCOPED by default (user-scoped credential model): it acts
82
+ // as its holder and the target workspace is a per-request parameter.
83
+ // `workspaceId` in the body is an optional PIN — a requested workspace
84
+ // the account is not an active member of answers the SAME uniform 403
85
+ // as having none at all (no oracle about other workspaces).
86
+ const membership = await resolveMembership(db, user.id, body.workspaceId ?? null);
87
+ if (!membership) {
88
+ await dropSession();
89
+ return c.json(err('no_membership', 'This account has no active membership on this instance'), 403);
90
+ }
91
+ const pinnedWorkspaceId = body.workspaceId ?? null;
92
+ const name = body.keyName ?? `CLI login ${new Date().toISOString().slice(0, 10)}`;
93
+ const expiresAt = body.expiresInDays ? new Date(Date.now() + body.expiresInDays * 86_400_000) : null;
94
+ const minted = await apiKeys.mint({
95
+ workspaceId: pinnedWorkspaceId,
96
+ createdBy: user.id,
97
+ name,
98
+ scopes: [...cliKeyScopes],
99
+ expiresAt
100
+ });
101
+ await dropSession();
102
+ const [row] = await db.select().from(apiKeysTable).where(eq(apiKeysTable.id, minted.id)).limit(1);
103
+ if (!row) {
104
+ return c.json(err('internal', 'Key mint failed — try again'), 500);
105
+ }
106
+ // This path is principal-less (public route), so the audit middleware
107
+ // cannot attribute it — write the row directly, like /setup does. An
108
+ // unpinned mint is a USER-credential event with no one workspace home:
109
+ // the row is instance-attributed (workspaceId null, like the orphan
110
+ // purge); a pinned mint lands in the pinned workspace's trail.
111
+ await audit.write({
112
+ workspaceId: pinnedWorkspaceId,
113
+ principal: { userId: user.id, via: 'session' },
114
+ action: 'apikey.create',
115
+ resourceType: 'api_key',
116
+ resourceId: minted.id,
117
+ requestId: c.get('requestId'),
118
+ metadata: {
119
+ name,
120
+ scopes: [...cliKeyScopes],
121
+ via: 'cli_otp',
122
+ workspaceId: pinnedWorkspaceId,
123
+ expiresAt: expiresAt?.toISOString() ?? null
124
+ }
125
+ });
126
+ return c.json({
127
+ key: minted.key,
128
+ apiKey: {
129
+ id: row.id,
130
+ name: row.name,
131
+ keyId: row.keyId,
132
+ scopes: row.scopes,
133
+ workspaceId: row.workspaceId,
134
+ createdBy: row.createdBy,
135
+ createdAt: row.createdAt.toISOString(),
136
+ lastUsedAt: row.lastUsedAt?.toISOString() ?? null,
137
+ revokedAt: row.revokedAt?.toISOString() ?? null,
138
+ expiresAt: row.expiresAt?.toISOString() ?? null
139
+ },
140
+ user: { id: user.id, email: user.email, name: user.name },
141
+ workspaceId: pinnedWorkspaceId
142
+ }, 201);
143
+ });
144
+ // CLI logout: revoke exactly the PRESENTING key — possession is the
145
+ // authority to kill itself. The ONE /cli/auth route open to machine
146
+ // principals (scope allowlist, the tool's write scope — every CLI-minted key
147
+ // carries it); there is no id parameter, so no OTHER key is nameable, and
148
+ // the handler acts only on principal.apiKeyId, which the credential
149
+ // resolver derived from the presented secret. Sessions are refused — the
150
+ // dashboard (DELETE /api-keys/{id}) is their key-management surface — and
151
+ // so are OAuth bearers (no apiKeyId). Deliberately edition-independent:
152
+ // on cloud, the CLI's `logout --org` must be able to kill the
153
+ // /sso/cli-connect-minted key server-side (revocation narrows access; the
154
+ // D1 closure is about MINTING).
155
+ api.openapi(cliAuthRevokeRoute, async (c) => {
156
+ const principal = c.get('principal');
157
+ if (!principal)
158
+ return c.json(err('unauthenticated', 'Authentication required'), 401);
159
+ if (principal.via !== 'api_key' || !principal.apiKeyId) {
160
+ return c.json(err('forbidden', 'Only an API key can revoke itself — use the dashboard for key management'), 403);
161
+ }
162
+ await db
163
+ .update(apiKeysTable)
164
+ .set({ revokedAt: sql `now()` })
165
+ .where(and(eq(apiKeysTable.id, principal.apiKeyId), isNull(apiKeysTable.revokedAt)));
166
+ // The generic audit middleware writes the row (machine mutation) — hand
167
+ // it the semantics instead of double-writing.
168
+ c.set('audit', {
169
+ action: 'apikey.revoke',
170
+ resourceType: 'api_key',
171
+ resourceId: principal.apiKeyId,
172
+ metadata: { via: 'cli_logout' }
173
+ });
174
+ return c.json({ revoked: true, id: principal.apiKeyId }, 200);
175
+ });
176
+ }
177
+ //# sourceMappingURL=cli-auth.js.map