@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,97 @@
1
+ /**
2
+ * Versioned API-key peppers — the seam that lets API keys survive an
3
+ * AUTH_SECRET rotation (ADR 008).
4
+ *
5
+ * Version 1 is ALWAYS the pepper that hashed keys before versioning existed:
6
+ * the resolved auth secret, used verbatim as `sha256(secret + pepper)`. With
7
+ * no `API_KEY_PEPPERS` set the registry is exactly `{ 1: authSecret }` and
8
+ * new keys mint at version 1 — byte-identical to the pre-versioning
9
+ * behaviour, nothing to migrate.
10
+ *
11
+ * `API_KEY_PEPPERS` supplies additional versions as `<version>:<secret>`
12
+ * entries joined by `;` (e.g. `1:<old secret>;2:<new pepper>`). Entries
13
+ * override the defaults, so pinning `1:<value>` freezes version 1
14
+ * independently of the live AUTH_SECRET — the first step of the rotation
15
+ * runbook in internal/security-runbooks.md. LOUD RULE: whenever version 1 is pinned, its
16
+ * value MUST be the historical AUTH_SECRET-derived pepper (the secret that
17
+ * was live when the version-1 keys were minted), or every existing key stops
18
+ * resolving. New keys always mint under the HIGHEST version in the registry.
19
+ *
20
+ * Resolution looks up the pepper by the key row's stored `pepper_version`
21
+ * and FAILS CLOSED on a version the registry does not contain — same 401 as
22
+ * a revoked key, never a fallback to another pepper.
23
+ */
24
+ /** `pepper_version` is a Postgres smallint. */
25
+ export const MAX_PEPPER_VERSION = 32767;
26
+ /** Peppers hold the same bar as AUTH_SECRET. */
27
+ const MIN_PEPPER_LENGTH = 32;
28
+ /**
29
+ * Parse the `API_KEY_PEPPERS` value into a version→secret map. Throws a
30
+ * readable Error on any malformed entry — surfaced by the env schema, so a
31
+ * bad value refuses boot instead of silently mis-hashing keys.
32
+ */
33
+ export function parseApiKeyPeppers(raw) {
34
+ const map = new Map();
35
+ // Trailing/duplicated separators are operator noise, not errors.
36
+ const entries = raw
37
+ .split(';')
38
+ .map((e) => e.trim())
39
+ .filter((e) => e.length > 0);
40
+ if (entries.length === 0) {
41
+ throw new Error('API_KEY_PEPPERS is set but contains no <version>:<secret> entries');
42
+ }
43
+ for (const entry of entries) {
44
+ // Split at the FIRST colon only — the secret itself may contain colons.
45
+ const colon = entry.indexOf(':');
46
+ if (colon <= 0) {
47
+ throw new Error(`API_KEY_PEPPERS entry "${describeEntry(entry)}" is not <version>:<secret>`);
48
+ }
49
+ const versionPart = entry.slice(0, colon).trim();
50
+ const secret = entry.slice(colon + 1);
51
+ if (!/^[0-9]+$/.test(versionPart)) {
52
+ // A reversed `<secret>:<version>` entry makes versionPart the whole
53
+ // secret — truncate so a misconfiguration doesn't echo it to stderr.
54
+ throw new Error(`API_KEY_PEPPERS version "${describeEntry(versionPart)}" is not a positive integer`);
55
+ }
56
+ const version = Number(versionPart);
57
+ if (version < 1 || version > MAX_PEPPER_VERSION) {
58
+ throw new Error(`API_KEY_PEPPERS version ${version} is out of range (1..${MAX_PEPPER_VERSION})`);
59
+ }
60
+ if (map.has(version)) {
61
+ throw new Error(`API_KEY_PEPPERS defines version ${version} twice`);
62
+ }
63
+ if (secret.length < MIN_PEPPER_LENGTH) {
64
+ throw new Error(`API_KEY_PEPPERS version ${version} secret is shorter than ${MIN_PEPPER_LENGTH} characters`);
65
+ }
66
+ map.set(version, secret);
67
+ }
68
+ return map;
69
+ }
70
+ /** Error context that never echoes a possible secret: version side only. */
71
+ function describeEntry(entry) {
72
+ const head = entry.slice(0, Math.min(8, entry.length));
73
+ return entry.length > 8 ? `${head}…` : head;
74
+ }
75
+ /**
76
+ * Build the registry from the resolved auth secret plus the optional
77
+ * `API_KEY_PEPPERS` value (already format-validated by the env schema; this
78
+ * re-parses so direct callers get the same guarantees).
79
+ */
80
+ export function buildPepperRegistry(authSecret, apiKeyPeppers) {
81
+ const peppers = new Map([[1, authSecret]]);
82
+ let v1Pinned = false;
83
+ if (apiKeyPeppers !== undefined) {
84
+ const parsed = parseApiKeyPeppers(apiKeyPeppers);
85
+ v1Pinned = parsed.has(1);
86
+ for (const [version, secret] of parsed)
87
+ peppers.set(version, secret);
88
+ }
89
+ const current = Math.max(...peppers.keys());
90
+ return {
91
+ current,
92
+ v1Pinned,
93
+ get: (version) => peppers.get(version),
94
+ versions: [...peppers.keys()].sort((a, b) => a - b)
95
+ };
96
+ }
97
+ //# sourceMappingURL=peppers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peppers.js","sourceRoot":"","sources":["../../src/apikeys/peppers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { type Db } from '@antasphere/chassis-db';
2
+ import type { Principal } from '@antasphere/chassis-contract';
3
+ import { type OnWorkspaceMiss } from '../identity/resolve-membership.js';
4
+ import type { PepperRegistry } from './peppers.js';
5
+ /**
6
+ * A VALID pinned key presented with an X-Workspace-Id naming a different
7
+ * workspace — a client bug or a confused-deputy attempt. Distinct from a
8
+ * plain resolution miss (null → 401) so the middleware can answer the loud
9
+ * 403 the pinned model always answered.
10
+ */
11
+ export declare class WorkspaceMismatchError extends Error {
12
+ constructor();
13
+ }
14
+ export interface MintedKey {
15
+ id: string;
16
+ keyId: string;
17
+ /** The full key — returned once, never stored. */
18
+ key: string;
19
+ }
20
+ export declare class ApiKeyService {
21
+ private readonly db;
22
+ private readonly peppers;
23
+ /** The tool's key prefix, without the underscore (`identity.apiKeyPrefix`). Required: no chassis default. */
24
+ private readonly prefix;
25
+ /** Cloud only: one cached reconcile on a well-formed selector miss. */
26
+ private readonly onWorkspaceMiss?;
27
+ private readonly keyRe;
28
+ constructor(db: Db, peppers: PepperRegistry,
29
+ /** The tool's key prefix, without the underscore (`identity.apiKeyPrefix`). Required: no chassis default. */
30
+ prefix: string,
31
+ /** Cloud only: one cached reconcile on a well-formed selector miss. */
32
+ onWorkspaceMiss?: OnWorkspaceMiss | undefined);
33
+ /** Distinguishes an API-key credential from other bearers (the shape only, no lookup). */
34
+ readonly isToken: (token: string) => boolean;
35
+ mint(opts: {
36
+ /** Optional workspace PIN — omitted/null mints a user-scoped key. */
37
+ workspaceId?: string | null;
38
+ createdBy: string;
39
+ name: string;
40
+ scopes: string[];
41
+ expiresAt?: Date | null;
42
+ }): Promise<MintedKey>;
43
+ /**
44
+ * Resolve a presented key to a live principal, or null. The key dies with
45
+ * its creator: a live active membership is required (same re-check
46
+ * discipline as sessions).
47
+ *
48
+ * `requested` is the request's X-Workspace-Id (or null). An UNPINNED key
49
+ * selects with it exactly like a session (fail closed on non-membership);
50
+ * a PINNED key always resolves its pin and THROWS WorkspaceMismatchError
51
+ * when `requested` names a different workspace — never silently serves
52
+ * the pinned one.
53
+ */
54
+ resolve(token: string, requested: string | null): Promise<Principal | null>;
55
+ }
56
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/apikeys/service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAiCnD;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAKhD;AAQD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,aAAa;IAItB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,6GAA6G;IAC7G,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IARnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAGZ,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,cAAc;IACxC,6GAA6G;IAC5F,MAAM,EAAE,MAAM;IAC/B,uEAAuE;IACtD,eAAe,CAAC,EAAE,eAAe,GAAG,SAAS;IAMhE,0FAA0F;IAC1F,QAAQ,CAAC,OAAO,GAAI,OAAO,MAAM,KAAG,OAAO,CAA2B;IAEhE,IAAI,CAAC,IAAI,EAAE;QACf,qEAAqE;QACrE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;KACzB,GAAG,OAAO,CAAC,SAAS,CAAC;IAyBtB;;;;;;;;;;OAUG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;CA6FlF"}
@@ -0,0 +1,196 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ import { and, eq, gt, isNull, or, sql } from 'drizzle-orm';
3
+ import { apiKeys } from '@antasphere/chassis-db';
4
+ import { isWorkspaceSelector, resolveMembership } from '../identity/resolve-membership.js';
5
+ /**
6
+ * API keys: `<prefix>_<keyId8>_<secret>`.
7
+ *
8
+ * The prefix is the TOOL's (`identity.apiKeyPrefix`, e.g. a product called
9
+ * Acme might use `acm`): a constructor value with no default, so the chassis
10
+ * spells none. The shape is fixed: keyId gives an O(1)
11
+ * indexed lookup, the secret is stored as sha256(secret + pepper) and
12
+ * compared constant-time. The pepper defaults to the server auth secret, so
13
+ * a leaked database alone cannot validate keys — and it is VERSIONED
14
+ * (peppers.ts, ADR 008): each row records the pepper version that hashed it,
15
+ * mint uses the registry's current version, and resolution uses the stored
16
+ * version's pepper or fails closed. Keys are minted by sessions only.
17
+ *
18
+ * A key is a USER credential (user-scoped credential model): it acts as its
19
+ * creator, and the target workspace resolves per request through the shared
20
+ * resolveMembership rule — the X-Workspace-Id header, else the creator's
21
+ * default membership. `workspace_id` on the row is an OPTIONAL PIN (least
22
+ * privilege, and the grandfathered binding of pre-model-change keys): a
23
+ * pinned key resolves ONLY its pinned workspace, and a request naming a
24
+ * DIFFERENT one is rejected loudly (WorkspaceMismatchError → 403).
25
+ */
26
+ const KEY_ID_BYTES = 6; // 8 chars base64url
27
+ const SECRET_BYTES = 32; // 43 chars base64url
28
+ /** The prefix is a literal in the pattern: every RegExp metacharacter in it is escaped. */
29
+ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
30
+ /** The key shape for one prefix: `<prefix>_<keyId8>_<secret>`, two capture groups. */
31
+ const keyPattern = (prefix) => new RegExp(`^${escapeRegExp(prefix)}_([A-Za-z0-9_-]{8})_([A-Za-z0-9_-]{20,})$`);
32
+ /**
33
+ * A VALID pinned key presented with an X-Workspace-Id naming a different
34
+ * workspace — a client bug or a confused-deputy attempt. Distinct from a
35
+ * plain resolution miss (null → 401) so the middleware can answer the loud
36
+ * 403 the pinned model always answered.
37
+ */
38
+ export class WorkspaceMismatchError extends Error {
39
+ constructor() {
40
+ super('This credential is pinned to a different workspace');
41
+ this.name = 'WorkspaceMismatchError';
42
+ }
43
+ }
44
+ function hashSecret(secret, pepper) {
45
+ return createHash('sha256')
46
+ .update(secret + pepper)
47
+ .digest('hex');
48
+ }
49
+ export class ApiKeyService {
50
+ db;
51
+ peppers;
52
+ prefix;
53
+ onWorkspaceMiss;
54
+ keyRe;
55
+ constructor(db, peppers,
56
+ /** The tool's key prefix, without the underscore (`identity.apiKeyPrefix`). Required: no chassis default. */
57
+ prefix,
58
+ /** Cloud only: one cached reconcile on a well-formed selector miss. */
59
+ onWorkspaceMiss) {
60
+ this.db = db;
61
+ this.peppers = peppers;
62
+ this.prefix = prefix;
63
+ this.onWorkspaceMiss = onWorkspaceMiss;
64
+ if (!prefix)
65
+ throw new Error('ApiKeyService: the key prefix is required');
66
+ this.keyRe = keyPattern(prefix);
67
+ }
68
+ /** Distinguishes an API-key credential from other bearers (the shape only, no lookup). */
69
+ isToken = (token) => this.keyRe.test(token);
70
+ async mint(opts) {
71
+ const keyId = randomBytes(KEY_ID_BYTES).toString('base64url');
72
+ const secret = randomBytes(SECRET_BYTES).toString('base64url');
73
+ // Mint always hashes under the CURRENT pepper version and records which
74
+ // one, so resolution can keep verifying old keys across pepper rotations.
75
+ const pepperVersion = this.peppers.current;
76
+ const pepper = this.peppers.get(pepperVersion);
77
+ if (pepper === undefined)
78
+ throw new Error(`pepper registry has no current version ${pepperVersion}`);
79
+ const [row] = await this.db
80
+ .insert(apiKeys)
81
+ .values({
82
+ workspaceId: opts.workspaceId ?? null,
83
+ keyId,
84
+ secretHash: hashSecret(secret, pepper),
85
+ pepperVersion,
86
+ name: opts.name,
87
+ scopes: opts.scopes,
88
+ createdBy: opts.createdBy,
89
+ expiresAt: opts.expiresAt ?? null
90
+ })
91
+ .returning({ id: apiKeys.id });
92
+ if (!row)
93
+ throw new Error('api key insert failed');
94
+ return { id: row.id, keyId, key: `${this.prefix}_${keyId}_${secret}` };
95
+ }
96
+ /**
97
+ * Resolve a presented key to a live principal, or null. The key dies with
98
+ * its creator: a live active membership is required (same re-check
99
+ * discipline as sessions).
100
+ *
101
+ * `requested` is the request's X-Workspace-Id (or null). An UNPINNED key
102
+ * selects with it exactly like a session (fail closed on non-membership);
103
+ * a PINNED key always resolves its pin and THROWS WorkspaceMismatchError
104
+ * when `requested` names a different workspace — never silently serves
105
+ * the pinned one.
106
+ */
107
+ async resolve(token, requested) {
108
+ const match = this.keyRe.exec(token);
109
+ if (!match)
110
+ return null;
111
+ const [, keyId, secret] = match;
112
+ if (!keyId || !secret)
113
+ return null;
114
+ const [row] = await this.db
115
+ .select({
116
+ id: apiKeys.id,
117
+ secretHash: apiKeys.secretHash,
118
+ pepperVersion: apiKeys.pepperVersion,
119
+ workspaceId: apiKeys.workspaceId,
120
+ scopes: apiKeys.scopes,
121
+ createdBy: apiKeys.createdBy,
122
+ expiresAt: apiKeys.expiresAt
123
+ })
124
+ .from(apiKeys)
125
+ .where(and(eq(apiKeys.keyId, keyId), isNull(apiKeys.revokedAt),
126
+ // Expired = same lookup miss as revoked — one fail-closed 401, no
127
+ // behavioural fork. DB clock, not app clock.
128
+ or(isNull(apiKeys.expiresAt), gt(apiKeys.expiresAt, sql `now()`))))
129
+ .limit(1);
130
+ if (!row)
131
+ return null;
132
+ // Verify under the pepper version THIS row was hashed with — never the
133
+ // current one, never a fallback. An unknown version (e.g. the operator
134
+ // dropped a retired pepper from API_KEY_PEPPERS while such keys remain)
135
+ // FAILS CLOSED: same null → same 401 as a revoked or expired key.
136
+ const pepper = this.peppers.get(row.pepperVersion);
137
+ if (pepper === undefined)
138
+ return null;
139
+ const presented = Buffer.from(hashSecret(secret, pepper), 'hex');
140
+ const stored = Buffer.from(row.secretHash, 'hex');
141
+ if (presented.length !== stored.length || !timingSafeEqual(presented, stored))
142
+ return null;
143
+ // Live membership through the shared selection rule. A pinned key's pin
144
+ // IS the selector (fail-closed on the live membership, as always); an
145
+ // unpinned key selects like a session. Guest capability limits (D2) bind
146
+ // machine credentials too — the origin of the LIVE membership rides the
147
+ // principal, and accountRef carries the projection id the cloud live
148
+ // gate keys on (internal/federation.md).
149
+ const selector = row.workspaceId ?? requested;
150
+ let member = await resolveMembership(this.db, row.createdBy, selector);
151
+ if (!member && selector && this.onWorkspaceMiss && isWorkspaceSelector(selector)) {
152
+ // Unknown-workspace retry (cloud): the KEY verified above — the miss
153
+ // may be a hub org granted since the last reconcile pass. One cached
154
+ // reconcile, one re-run of the SAME lookup — no recursion. Covers the
155
+ // pin too: a pinned key into a freshly granted hub org resolves.
156
+ await this.onWorkspaceMiss(row.createdBy, selector);
157
+ member = await resolveMembership(this.db, row.createdBy, selector);
158
+ }
159
+ if (!member)
160
+ return null;
161
+ // A valid PINNED key + a header naming another workspace: reject loudly
162
+ // (the pre-model-change contract). Checked after the membership resolves
163
+ // so a dead key/membership stays the uniform 401, exactly as before. The
164
+ // header may name the pinned workspace by its LOCAL id or by the id of
165
+ // the hub organization it projects (the resolved row's accountRef,
166
+ // PRDCT-2947): both are the same workspace, neither is a mismatch.
167
+ if (row.workspaceId && requested) {
168
+ const named = requested.toLowerCase();
169
+ const isPin = named === row.workspaceId.toLowerCase() ||
170
+ (member.accountRef !== null && named === member.accountRef.toLowerCase());
171
+ if (!isPin)
172
+ throw new WorkspaceMismatchError();
173
+ }
174
+ // Advisory only — never correctness-load-bearing (statelessness invariant).
175
+ void this.db
176
+ .update(apiKeys)
177
+ .set({ lastUsedAt: sql `now()` })
178
+ .where(eq(apiKeys.id, row.id))
179
+ .catch(() => { });
180
+ return {
181
+ userId: row.createdBy,
182
+ email: member.email,
183
+ name: member.name,
184
+ workspaceId: member.workspaceId,
185
+ role: member.role,
186
+ origin: member.origin,
187
+ via: 'api_key',
188
+ scopes: new Set(row.scopes),
189
+ apiKeyId: row.id,
190
+ ...(row.expiresAt ? { apiKeyExpiresAt: row.expiresAt.toISOString() } : {}),
191
+ ...(member.accountRef ? { accountRef: member.accountRef } : {}),
192
+ ...(row.workspaceId ? { pinned: true } : {})
193
+ };
194
+ }
195
+ }
196
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/apikeys/service.ts"],"names":[],"mappings":"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"}
package/dist/app.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ import { Hono } from 'hono';
2
+ import type { MiddlewareHandler } from 'hono';
3
+ import type { OpenAPIHono } from '@hono/zod-openapi';
4
+ import type { Logger } from './logger.js';
5
+ import type { RuntimeState } from './util/index.js';
6
+ export interface AppDeps {
7
+ logger: Logger;
8
+ state: RuntimeState;
9
+ /** Directory holding the built dashboard SPA. */
10
+ publicDir: string;
11
+ /** The tool's name on the no-dashboard page, title and heading alike (`identity.displayName`). */
12
+ displayName: string;
13
+ /** The versioned API, mounted at /api/v1. */
14
+ api: OpenAPIHono;
15
+ /** The bundled MCP endpoint, mounted at /mcp (M6). */
16
+ mcp?: Hono;
17
+ /** Root-level OAuth discovery documents (/.well-known/*, M6). */
18
+ wellKnown?: Hono;
19
+ /**
20
+ * The tool's public routes (e.g. a public share-link viewer,
21
+ * /v/{secret}, Phase 4 / ADR 012). Mounted in the public-route slot:
22
+ * OUTSIDE /api/v1, outside the auth/scope middleware — token recipients
23
+ * are anonymous, the path secret is the whole credential, and every
24
+ * user-content response it emits is locked under `CSP: sandbox` (see
25
+ * viewer/routes.ts in the app).
26
+ */
27
+ publicRoutes?: Hono | undefined;
28
+ /** Observability middlewares + the /metrics route (M5). */
29
+ metricsMiddleware?: MiddlewareHandler;
30
+ metricsRoutes?: Hono;
31
+ otelMiddleware?: MiddlewareHandler;
32
+ /**
33
+ * Live readiness probe for the backing store (routes/health.ts). Omitted =
34
+ * /readyz keeps reporting the boot-time storage result forever.
35
+ */
36
+ probeStorage?: () => Promise<void>;
37
+ /** `Strict-Transport-Security` value (security-headers.ts `hstsValue`); null/absent = no HSTS. */
38
+ hsts?: string | null;
39
+ /**
40
+ * The tool's root middleware, installed after the metrics middleware and
41
+ * BEFORE every mount. E.g. a tool with VIEWER_BASE_URL (PRDCT-1352): when
42
+ * present, the host gate (middleware/host-gate.ts in the app) — the viewer
43
+ * hostname answers only `/v/*`, `/api/v1/viewer/*` and the probes, every
44
+ * other hostname redirects `/v/*` there. Absent = single-origin behaviour,
45
+ * gate not installed.
46
+ */
47
+ rootMiddleware?: MiddlewareHandler | undefined;
48
+ /** Extra `frame-src` origins of the dashboard CSP (e.g. a tool's viewer origin, for the preview). */
49
+ cspFrameSrc?: readonly string[] | undefined;
50
+ /** Extra `img-src` sources of the dashboard CSP (e.g. `blob:` for a tool whose dashboard shows images it fetched). */
51
+ cspImgSrc?: readonly string[] | undefined;
52
+ }
53
+ /**
54
+ * The SQLSTATE of a thrown Postgres error, when it is one. node-postgres puts
55
+ * it on `.code`; drizzle re-throws the same object untouched.
56
+ */
57
+ export declare function postgresErrorCode(error: unknown): string | undefined;
58
+ /**
59
+ * Assemble the single Hono app. Route precedence is load-bearing and fixed:
60
+ * health → (api, mcp, well-known — mounted here as the platform grows) →
61
+ * static assets → SPA index fallback LAST. A slot deliberately remains open
62
+ * before the fallback for products that add public content routes.
63
+ */
64
+ export declare function createApp({ logger, state, publicDir, displayName, api, mcp, wellKnown, publicRoutes, metricsMiddleware, metricsRoutes, otelMiddleware, probeStorage, hsts, rootMiddleware, cspFrameSrc, cspImgSrc }: AppDeps): Promise<Hono>;
65
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IACpB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,GAAG,EAAE,WAAW,CAAC;IACjB,sDAAsD;IACtD,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,iEAAiE;IACjE,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAChC,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,kGAAkG;IAClG,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC/C,qGAAqG;IACrG,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5C,sHAAsH;IACtH,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC3C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIpE;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,EAC9B,MAAM,EACN,KAAK,EACL,SAAS,EACT,WAAW,EACX,GAAG,EACH,GAAG,EACH,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,IAAI,EACJ,cAAc,EACd,WAAW,EACX,SAAS,EACV,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAqIzB"}
package/dist/app.js ADDED
@@ -0,0 +1,142 @@
1
+ import { Hono } from 'hono';
2
+ import { HTTPException } from 'hono/http-exception';
3
+ import { serveStatic } from '@hono/node-server/serve-static';
4
+ import { readFile } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { requestId } from './middleware/index.js';
7
+ import { buildCsp, inlineScriptHashes, securityHeaders } from './middleware/index.js';
8
+ import { healthRoutes } from './routes/index.js';
9
+ /**
10
+ * The SQLSTATE of a thrown Postgres error, when it is one. node-postgres puts
11
+ * it on `.code`; drizzle re-throws the same object untouched.
12
+ */
13
+ export function postgresErrorCode(error) {
14
+ if (typeof error !== 'object' || error === null)
15
+ return undefined;
16
+ const code = error.code;
17
+ return typeof code === 'string' ? code : undefined;
18
+ }
19
+ /**
20
+ * Assemble the single Hono app. Route precedence is load-bearing and fixed:
21
+ * health → (api, mcp, well-known — mounted here as the platform grows) →
22
+ * static assets → SPA index fallback LAST. A slot deliberately remains open
23
+ * before the fallback for products that add public content routes.
24
+ */
25
+ export async function createApp({ logger, state, publicDir, displayName, api, mcp, wellKnown, publicRoutes, metricsMiddleware, metricsRoutes, otelMiddleware, probeStorage, hsts, rootMiddleware, cspFrameSrc, cspImgSrc }) {
26
+ const app = new Hono();
27
+ // The SPA fallback is read first: its inline bootstrap script hashes feed
28
+ // the CSP that guards every HTML response.
29
+ let indexHtml = null;
30
+ try {
31
+ indexHtml = await readFile(join(publicDir, 'index.html'), 'utf8');
32
+ }
33
+ catch {
34
+ logger.warn({ publicDir }, 'no dashboard build found — serving a placeholder at /');
35
+ }
36
+ const csp = buildCsp(indexHtml ? inlineScriptHashes(indexHtml) : [], {
37
+ frameSrc: [...(cspFrameSrc ?? [])],
38
+ imgSrc: [...(cspImgSrc ?? [])]
39
+ });
40
+ app.use('*', requestId(logger));
41
+ app.use('*', securityHeaders({ csp, state, hsts: hsts ?? null }));
42
+ // PRDCT-1809: a fail-closed boot verdict closes the whole surface — the
43
+ // operator-facing probes stay so the verdict is visible (/readyz carries
44
+ // the reason) and the process is not restarted into the same state.
45
+ app.use('*', async (c, next) => {
46
+ if (state.closed === null)
47
+ return next();
48
+ const path = c.req.path;
49
+ if (path === '/healthz' || path === '/readyz' || path === '/metrics')
50
+ return next();
51
+ return c.json({
52
+ error: {
53
+ code: 'service_closed',
54
+ message: 'This instance refuses to serve until an operator resolves a boot verdict; see /readyz'
55
+ }
56
+ }, 503);
57
+ });
58
+ if (otelMiddleware)
59
+ app.use('*', otelMiddleware);
60
+ if (metricsMiddleware)
61
+ app.use('*', metricsMiddleware);
62
+ // PRDCT-1352: the viewer-origin host gate, BEFORE every mount below — the
63
+ // boundary between the two hostnames must be decided before any route
64
+ // (and any cookie-reading middleware) runs.
65
+ if (rootMiddleware)
66
+ app.use('*', rootMiddleware);
67
+ // Uncaught handler errors: log with the request id, answer the wire shape.
68
+ app.onError((error, c) => {
69
+ // Malformed request bodies first: Hono's body validators throw
70
+ // HTTPException(400) on unparseable JSON ("Malformed JSON in request
71
+ // body") or broken multipart BEFORE zod runs, so the zod-openapi
72
+ // defaultHook never sees them — and Hono routes a thrown error straight
73
+ // here from the throwing handler's own dispatch frame, so an upstream
74
+ // try/catch middleware never observes it either. This is therefore THE
75
+ // seam: map the framework's 400s to the wire shape with a stable
76
+ // machine code instead of amplifying a pre-auth-reachable client
77
+ // mistake into a 500 + an error-level log. Only hono's validators throw
78
+ // HTTPException(400) on this app (the MCP sub-app handles its own).
79
+ if (error instanceof HTTPException && error.status === 400) {
80
+ const isJson = error.message.includes('JSON');
81
+ return c.json({
82
+ error: {
83
+ code: isJson ? 'invalid_json' : 'invalid_body',
84
+ message: isJson ? 'Request body is not valid JSON' : 'Malformed request body'
85
+ }
86
+ }, 400);
87
+ }
88
+ // A NUL byte (or any byte the server encoding cannot represent) that
89
+ // reaches Postgres inside a text value raises 22021 / 22P05. It is a
90
+ // CLIENT mistake, anonymously drivable on every free-text sink, but the
91
+ // pg error object carries the offending statement AND its bound
92
+ // parameters — so left alone it becomes a 500 whose error-level log line
93
+ // prints the SQL and the values. Contract-level `noNulString` rejects the
94
+ // known sinks at validation time; this is the backstop for the ones a
95
+ // product forgets, and it must answer 400 with no log.
96
+ const pgCode = postgresErrorCode(error);
97
+ if (pgCode === '22021' || pgCode === '22P05') {
98
+ return c.json({
99
+ error: {
100
+ code: 'invalid_characters',
101
+ message: 'Request contains characters that cannot be stored (e.g. a NUL byte)'
102
+ }
103
+ }, 400);
104
+ }
105
+ // JSON.stringify is recursive: a deeply nested body blows the V8 stack
106
+ // (`RangeError`) or exceeds the maximum string length. Both are client
107
+ // input, not server faults. middleware/json-depth.ts rejects these at the
108
+ // edge; this is the backstop for anything that builds a deep structure
109
+ // downstream. Narrow on the two known messages — a RangeError from
110
+ // anywhere else is a real bug and must stay a 500.
111
+ if (error instanceof RangeError &&
112
+ /maximum call stack size exceeded|invalid string length/i.test(error.message)) {
113
+ return c.json({ error: { code: 'payload_too_deep', message: 'Request payload is nested too deeply' } }, 400);
114
+ }
115
+ (c.get('logger') ?? logger).error({ err: error }, 'unhandled error');
116
+ return c.json({ error: { code: 'internal', message: 'Internal server error' } }, 500);
117
+ });
118
+ app.route('/', healthRoutes(state, {
119
+ ...(probeStorage ? { probeStorage } : {}),
120
+ onStorageFailure: (err) => logger.error({ err }, 'storage probe failed — reporting not ready')
121
+ }));
122
+ if (metricsRoutes)
123
+ app.route('/', metricsRoutes);
124
+ app.route('/api/v1', api);
125
+ if (mcp)
126
+ app.route('/mcp', mcp);
127
+ if (wellKnown)
128
+ app.route('/', wellKnown);
129
+ // The public-route slot: the share-link viewer lives here — before the
130
+ // static assets and the SPA fallback, after every credentialed surface.
131
+ if (publicRoutes)
132
+ app.route('/', publicRoutes);
133
+ app.use('*', serveStatic({ root: publicDir }));
134
+ app.get('*', (c) => {
135
+ if (indexHtml)
136
+ return c.html(indexHtml);
137
+ return c.html(`<!doctype html><title>${displayName}</title><h1>${displayName} API is running</h1>` +
138
+ '<p>No dashboard build found. API health: <a href="/healthz">/healthz</a></p>');
139
+ });
140
+ return app;
141
+ }
142
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type SQL } from 'drizzle-orm';
2
+ import { type AuditListQuery, type AuditVia } from '@antasphere/chassis-contract';
3
+ /**
4
+ * The audit list's WHERE, from the validated query. Every value arrives as
5
+ * a bound parameter (drizzle's `eq`/`like`/`ilike` never interpolate), and
6
+ * the free-text ones are escaped as LIKE patterns first, so a `%` or `_` in
7
+ * what the admin typed matches itself rather than anything.
8
+ */
9
+ /** A LIKE pattern for "contains this text", the wildcards of the text itself escaped. */
10
+ export declare function escapeLike(value: string): string;
11
+ /**
12
+ * The `action` list, split and de-duplicated: an item ending in `.` is a
13
+ * family (a prefix), any other item is one action. The contract has already
14
+ * bounded the count and the alphabet; empty items are dropped here.
15
+ */
16
+ export declare function parseActionList(value: string): {
17
+ exact: string[];
18
+ families: string[];
19
+ };
20
+ /** The `actorVia` list, split and de-duplicated (the contract pinned the alphabet). */
21
+ export declare function parseViaList(value: string): AuditVia[];
22
+ /**
23
+ * The cursor, or null when absent, malformed or out of range. Malformed
24
+ * cursors serve page 1; out-of-range ones are refused the same way, since
25
+ * Number('99999999999999999999') is finite but past bigint precision, and
26
+ * sending it to the `lt(id, …)` comparison overflows in Postgres.
27
+ * Safe-integer is the honest bound for a JS-roundtripped bigserial id.
28
+ */
29
+ export declare function cursorId(cursor: string | undefined): number | null;
30
+ /**
31
+ * The filter conditions (the workspace scope and the cursor are the
32
+ * caller's): one AND-ed list, each member a parameterised comparison.
33
+ * Returns an empty list when nothing filters.
34
+ */
35
+ export declare function auditFilterConditions(query: AuditListQuery): SQL[];
36
+ /** The whole WHERE: the scope, the filters, and the keyset cursor when there is one. */
37
+ export declare function auditWhere(scope: SQL, filters: SQL[], cursor: SQL | null): SQL;
38
+ //# sourceMappingURL=filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../src/audit/filters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAsB,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGtG;;;;;GAKG;AAEH,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAUtF;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAItD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,GAAG,EAAE,CAqClE;AAED,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,GAAG,CAG9E"}