@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,277 @@
1
+ import { RateLimiterMemory, RateLimiterRedis, RateLimiterRes } from 'rate-limiter-flexible';
2
+ import { getConnInfo } from '@hono/node-server/conninfo';
3
+ /**
4
+ * Auth-surface rate limits (ours, not Better Auth's built-in): login, OTP
5
+ * sends, invitation acceptance, setup attempts, API-key verification
6
+ * failures. Memory backend per replica by default; Redis when REDIS_URL is
7
+ * set so limits hold across replicas (Profile B).
8
+ */
9
+ /** Workspace-creation attempts one person gets per hour; an address gets ten times that. */
10
+ export const WORKSPACE_CREATE_PER_PERSON = 60;
11
+ /**
12
+ * The chassis buckets plus the TOOL's own (`toolBuckets`, name → declaration),
13
+ * all built by the same `make`: one store (Redis when REDIS_URL is set, memory
14
+ * otherwise), one key-prefix scheme. A tool bucket can never take a chassis
15
+ * bucket's name — the type refuses it.
16
+ */
17
+ export async function createRateLimiters(env, logger, toolBuckets) {
18
+ let make;
19
+ if (env.REDIS_URL) {
20
+ const { Redis } = await import('ioredis');
21
+ const client = new Redis(env.REDIS_URL, { enableOfflineQueue: false });
22
+ client.on('error', (err) => logger.error({ err }, 'redis rate-limit store error'));
23
+ make = (prefix, points, duration) => new RateLimiterRedis({
24
+ storeClient: client,
25
+ keyPrefix: `rl:${prefix}`,
26
+ points,
27
+ duration,
28
+ // If Redis blips, fail open to memory rather than dropping requests.
29
+ insuranceLimiter: new RateLimiterMemory({ points, duration })
30
+ });
31
+ logger.info('rate limiting backed by redis');
32
+ }
33
+ else {
34
+ make = (prefix, points, duration) => new RateLimiterMemory({ keyPrefix: `rl:${prefix}`, points, duration });
35
+ }
36
+ const chassis = {
37
+ login: make('login', 10, 15 * 60),
38
+ otp: make('otp', 5, 10 * 60),
39
+ invitationAccept: make('inv-accept', 10, 60 * 60),
40
+ setup: make('setup', 5, 60 * 60),
41
+ apiKeyFailures: make('key-fail', 20, 15 * 60),
42
+ cliConnect: make('cli-connect', Math.max(1, env.CLI_CONNECT_IP_LIMIT_PER_15_MIN ?? 300), 15 * 60),
43
+ oauthRegister: make('oauth-dcr', 10, 60 * 60),
44
+ oauthToken: make('oauth-token', 60, 60),
45
+ // Per ADDRESS: an event's teams' agents share one venue address (2026-10-01: ten times 120).
46
+ mcp: make('mcp', 1200, 60),
47
+ passwordReset: make('pw-reset', 5, 10 * 60),
48
+ workspaceExport: make('ws-export', 5, 600),
49
+ breakGlass: make('break-glass', 10, 60 * 60),
50
+ workspaceCreate: make('ws-create', WORKSPACE_CREATE_PER_PERSON, 60 * 60),
51
+ workspaceCreateAddress: make('ws-create-ip', WORKSPACE_CREATE_PER_PERSON * 10, 60 * 60),
52
+ openapiDoc: make('openapi', 60, 60),
53
+ demoRedeem: make('demo-redeem', 20, 15 * 60)
54
+ };
55
+ // The tool's buckets are built after the chassis ones, in declaration order.
56
+ const tool = {};
57
+ for (const [name, d] of Object.entries(toolBuckets ?? {})) {
58
+ tool[name] = make(d.prefix, d.points, d.durationSec);
59
+ }
60
+ return { ...chassis, ...tool, make };
61
+ }
62
+ /**
63
+ * Client identity for buckets and audit. x-forwarded-for is only believed
64
+ * when TRUST_PROXY says a proxy we control sets it; otherwise the socket
65
+ * address wins and spoofed headers are ignored. We read the RIGHTMOST hop —
66
+ * the one appended (or set) by the trusted proxy itself; the leftmost is
67
+ * client-claimed and spoofable whenever the proxy appends rather than
68
+ * overwrites. Note the compose caveat: without a proxy, Docker NAT can
69
+ * collapse external clients onto one address — per-IP limits are only as
70
+ * granular as what the socket sees.
71
+ */
72
+ export function makeClientIp(trustProxy) {
73
+ return (c) => {
74
+ if (trustProxy) {
75
+ const hops = c.req.header('x-forwarded-for')?.split(',');
76
+ const xff = hops?.[hops.length - 1]?.trim();
77
+ if (xff)
78
+ return xff;
79
+ }
80
+ try {
81
+ return getConnInfo(c).remote.address ?? 'unknown';
82
+ }
83
+ catch {
84
+ // No socket (tests via app.request()) — one shared bucket.
85
+ return 'unknown';
86
+ }
87
+ };
88
+ }
89
+ const RATE_LIMITED_BODY = {
90
+ error: { code: 'rate_limited', message: 'Too many requests, slow down' }
91
+ };
92
+ export function rateLimit(limiter, clientIp, extraKeys, options = {}) {
93
+ const consumeOn = options.consumeOn ?? 'arrival';
94
+ return async (c, next) => {
95
+ const keys = [clientIp(c), ...(extraKeys ? await extraKeys(c) : [])];
96
+ if (consumeOn === 'arrival') {
97
+ try {
98
+ for (const key of keys) {
99
+ await limiter.consume(key);
100
+ }
101
+ }
102
+ catch {
103
+ return c.json(RATE_LIMITED_BODY, 429);
104
+ }
105
+ return next();
106
+ }
107
+ // Failure-only: read the buckets (no consume) and refuse an exhausted one
108
+ // BEFORE the handler, so a drained wall still costs an attacker nothing to
109
+ // hit and no credential check runs. Backend errors fail open, matching
110
+ // every other limiter here.
111
+ for (const key of keys) {
112
+ const state = await limiter.get(key).catch(() => null);
113
+ if (state && state.remainingPoints <= 0 && state.msBeforeNext > 0) {
114
+ return c.json(RATE_LIMITED_BODY, 429);
115
+ }
116
+ }
117
+ await next();
118
+ // 4xx/5xx = the credential was not accepted. Better Auth answers 401 for a
119
+ // bad password, 400 for a malformed attempt, 403 for a refused origin —
120
+ // all of them are attempts that must cost. A 429 is not: it is a wall
121
+ // behind this one (the library's own 3-per-10-seconds on `/sign-in*`)
122
+ // saying "slow down", no credential was judged. Counting it let a burst of
123
+ // ordinary sign-ins from one address (a room behind one public IP) spend
124
+ // this 15-minute wall in seconds (PRDCT-2830, PRDCT-2848).
125
+ if (c.res.status >= 400 && c.res.status !== 429) {
126
+ for (const key of keys) {
127
+ await limiter.consume(key).catch(() => { });
128
+ }
129
+ }
130
+ };
131
+ }
132
+ /**
133
+ * Per-email key for OTP sends and password login (per IP AND per email): the
134
+ * email key keeps per-account protection intact when NAT or a rotating
135
+ * attacker collapses/expands the IP dimension.
136
+ */
137
+ export async function emailKeyOf(c) {
138
+ try {
139
+ const body = (await c.req.raw.clone().json());
140
+ if (body?.email && typeof body.email === 'string') {
141
+ return [`email:${body.email.toLowerCase().trim()}`];
142
+ }
143
+ }
144
+ catch {
145
+ // non-JSON body — the IP key alone applies
146
+ }
147
+ return [];
148
+ }
149
+ /** RateLimit draft headers + the X- legacy mirror; reset values are delta seconds. */
150
+ export function quotaHeaderEntries(d) {
151
+ const remaining = String(Math.max(0, d.remaining));
152
+ const reset = String(Math.max(0, d.resetSeconds));
153
+ const limit = String(d.limit);
154
+ return [
155
+ ['RateLimit-Limit', limit],
156
+ ['RateLimit-Remaining', remaining],
157
+ ['RateLimit-Reset', reset],
158
+ ['X-RateLimit-Limit', limit],
159
+ ['X-RateLimit-Remaining', remaining],
160
+ ['X-RateLimit-Reset', reset]
161
+ ];
162
+ }
163
+ /**
164
+ * Bucket key for the general API quota, derived ONLY from the authenticated
165
+ * principal — never from a client-supplied header, so a caller can neither
166
+ * rotate its own bucket nor fill another principal's. Two API keys of the
167
+ * same user are separate buckets (a leaked key can be throttled/revoked
168
+ * without starving the owner's other integrations); the same user's session
169
+ * is a third.
170
+ */
171
+ export function principalBucketKey(p) {
172
+ if (p.via === 'api_key')
173
+ return `key:${p.apiKeyId ?? p.userId}`;
174
+ if (p.via === 'oauth')
175
+ return `oauth:${p.userId}`;
176
+ return `session:${p.userId}`;
177
+ }
178
+ /**
179
+ * Per-principal request quota over the shared rate-limit backend. Two buckets
180
+ * per principal: a sustained per-minute window (the quota agents budget
181
+ * against — headers describe this one) and a 1-second spike cap that smooths
182
+ * thundering herds without burning sustained points on rejected spikes.
183
+ *
184
+ * Limits come from EntitlementService.getRequestQuota so a plan-aware edition
185
+ * varies them per principal; limiter instances are created lazily per
186
+ * distinct quota size (a product has a handful of plans, not thousands) and
187
+ * the size is part of the store prefix, so a plan change moves the principal
188
+ * to a fresh bucket instead of misreading the old counter.
189
+ *
190
+ * Failure posture matches the auth-surface limiters: Redis outages fall back
191
+ * to the per-replica insurance limiter inside `make`; any other backend or
192
+ * entitlement failure logs and FAILS OPEN (availability over throttling — the
193
+ * quota is a cost control, not an authz boundary; authz stays fail-closed).
194
+ */
195
+ export function createRequestQuota({ entitlements, make, logger }) {
196
+ const sustained = new Map();
197
+ const burst = new Map();
198
+ const limiterFor = (cache, prefix, points, durationSec) => {
199
+ let limiter = cache.get(points);
200
+ if (!limiter) {
201
+ limiter = make(`${prefix}:${points}`, points, durationSec);
202
+ cache.set(points, limiter);
203
+ }
204
+ return limiter;
205
+ };
206
+ return {
207
+ async consume(principal) {
208
+ let perMinute;
209
+ let burstPerSecond;
210
+ try {
211
+ ({ perMinute, burstPerSecond } = await entitlements.getRequestQuota(principal));
212
+ }
213
+ catch (err) {
214
+ logger.error({ err }, 'request quota lookup failed — allowing request');
215
+ return null;
216
+ }
217
+ // Guard a product's custom (non-TS-checked) EntitlementService returning
218
+ // a non-numeric quota: a bare `undefined` would slip past `<= 0` and hand
219
+ // rate-limiter-flexible `points: undefined` (a surprise 4/min). Fail open.
220
+ if (!Number.isFinite(perMinute) || !Number.isFinite(burstPerSecond)) {
221
+ logger.error({ perMinute, burstPerSecond }, 'request quota returned a non-numeric value — allowing request');
222
+ return null;
223
+ }
224
+ if (perMinute <= 0)
225
+ return null; // 0 = unlimited, a conscious operator opt-out
226
+ const key = principalBucketKey(principal);
227
+ const sustainedLimiter = limiterFor(sustained, 'apiq', perMinute, 60);
228
+ // Spike cap first: a rejected burst must not burn sustained points —
229
+ // the 1 s bucket self-heals and the minute budget stays intact.
230
+ if (burstPerSecond > 0) {
231
+ try {
232
+ await limiterFor(burst, 'apiq-burst', burstPerSecond, 1).consume(key);
233
+ }
234
+ catch (rejection) {
235
+ if (!(rejection instanceof RateLimiterRes)) {
236
+ logger.error({ err: rejection }, 'rate-limit backend failure — allowing request');
237
+ return null;
238
+ }
239
+ // Report the sustained bucket's state (read-only) so headers stay
240
+ // meaningful; the retry hint comes from the 1 s burst window.
241
+ const state = await sustainedLimiter.get(key).catch(() => null);
242
+ return {
243
+ ok: false,
244
+ limit: perMinute,
245
+ remaining: state ? Math.max(0, state.remainingPoints) : perMinute,
246
+ resetSeconds: Math.ceil((state?.msBeforeNext ?? 0) / 1000),
247
+ retryAfterSeconds: Math.max(1, Math.ceil(rejection.msBeforeNext / 1000))
248
+ };
249
+ }
250
+ }
251
+ try {
252
+ const res = await sustainedLimiter.consume(key);
253
+ return {
254
+ ok: true,
255
+ limit: perMinute,
256
+ remaining: res.remainingPoints,
257
+ resetSeconds: Math.ceil(res.msBeforeNext / 1000)
258
+ };
259
+ }
260
+ catch (rejection) {
261
+ if (!(rejection instanceof RateLimiterRes)) {
262
+ logger.error({ err: rejection }, 'rate-limit backend failure — allowing request');
263
+ return null;
264
+ }
265
+ const retry = Math.max(1, Math.ceil(rejection.msBeforeNext / 1000));
266
+ return {
267
+ ok: false,
268
+ limit: perMinute,
269
+ remaining: 0,
270
+ resetSeconds: retry,
271
+ retryAfterSeconds: retry
272
+ };
273
+ }
274
+ }
275
+ };
276
+ }
277
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ import type { Logger } from '../logger.js';
3
+ declare module 'hono' {
4
+ interface ContextVariableMap {
5
+ requestId: string;
6
+ logger: Logger;
7
+ }
8
+ }
9
+ export declare function requestId(base: Logger): MiddlewareHandler;
10
+ //# sourceMappingURL=request-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../../src/middleware/request-id.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB;CACF;AAYD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA+BzD"}
@@ -0,0 +1,42 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { routeLabel } from '../route-label.js';
3
+ /**
4
+ * First middleware in the chain: binds a request id (propagated from
5
+ * x-request-id when a proxy already assigned one) and a child logger carrying
6
+ * it, and writes the completion log line with latency. Everything downstream
7
+ * (traces, audit entries) reuses this id, which is what makes one request
8
+ * followable across log, trace, and audit.
9
+ */
10
+ /** Propagated ids must be sane: bounded length, log-safe charset. */
11
+ const REQUEST_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
12
+ export function requestId(base) {
13
+ return async (c, next) => {
14
+ const incoming = c.req.header('x-request-id');
15
+ const id = incoming && REQUEST_ID_RE.test(incoming) ? incoming : randomUUID();
16
+ const log = base.child({ requestId: id });
17
+ c.set('requestId', id);
18
+ c.set('logger', log);
19
+ c.header('x-request-id', id);
20
+ const start = performance.now();
21
+ try {
22
+ await next();
23
+ }
24
+ finally {
25
+ const latencyMs = Math.round((performance.now() - start) * 100) / 100;
26
+ log.info({
27
+ method: c.req.method,
28
+ // The MATCHED ROUTE PATTERN, never the raw URL path — see
29
+ // route-label.ts. On THIS repo that is not hypothetical: the public
30
+ // viewer is `/v/:secret`, so logging c.req.path wrote every live
31
+ // share-link capability into the log stream, where redaction (which
32
+ // keys off object properties) can do nothing about one opaque
33
+ // string. Read after next() so routing has resolved.
34
+ path: routeLabel(c),
35
+ status: c.error ? 500 : c.res.status,
36
+ latencyMs,
37
+ ...(c.error ? { failed: true } : {})
38
+ }, 'request');
39
+ }
40
+ };
41
+ }
42
+ //# sourceMappingURL=request-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.js","sourceRoot":"","sources":["../../src/middleware/request-id.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAS/C;;;;;;GAMG;AACH,qEAAqE;AACrE,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAE9C,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,EAAE,GAAG,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;QAC9E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACvB,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACrB,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YACtE,GAAG,CAAC,IAAI,CACN;gBACE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;gBACpB,0DAA0D;gBAC1D,oEAAoE;gBACpE,iEAAiE;gBACjE,oEAAoE;gBACpE,8DAA8D;gBAC9D,qDAAqD;gBACrD,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;gBACnB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM;gBACpC,SAAS;gBACT,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrC,EACD,SAAS,CACV,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Fail-closed endpoint allowlist for machine principals (API keys now, OAuth
3
+ * bearer tokens in M6). Ported from a predecessor template's oauth-scopes.ts.
4
+ *
5
+ * Machine principals are deliberately MORE restricted than the user they
6
+ * belong to: they can only reach endpoints listed here, each behind its
7
+ * scope. Anything not listed returns null and the gate 403s — new endpoints
8
+ * are unreachable to keys/tokens until someone consciously opens them.
9
+ * Session principals are role-gated instead and never pass through this.
10
+ *
11
+ * Pure logic (no I/O) so it stays unit-testable. The chassis owns the
12
+ * MECHANISM and the rules of its own endpoints; the scope NAMES and the rules
13
+ * of the tool's endpoints are the tool's (`createScopeAllowlist`).
14
+ */
15
+ export declare function looksLikeJwt(token: string): boolean;
16
+ /**
17
+ * One tool rule: the scope a machine principal needs for this request, or
18
+ * null when the rule does not speak about it (the next rule is asked; no rule
19
+ * speaking = denied).
20
+ */
21
+ export type ScopeRule<S extends string> = (path: string, method: string, isRead: boolean) => S | null;
22
+ export interface ScopeAllowlistOptions<S extends string> {
23
+ /** The tool's scope behind the chassis READ surfaces (`/me`, the files reads). */
24
+ read: S;
25
+ /** The tool's scope behind the chassis MUTATIONS (files writes, the CLI key self-revoke). */
26
+ write: S;
27
+ /** The tool's dedicated opt-in scope for the full-workspace export. */
28
+ dataExport: S;
29
+ /** The tool's own rules, asked in order AFTER the chassis rules. */
30
+ rules: ReadonlyArray<ScopeRule<S>>;
31
+ }
32
+ export declare function createScopeAllowlist<S extends string>({ read, write, dataExport, rules }: ScopeAllowlistOptions<S>): (path: string, method: string) => S | null;
33
+ //# sourceMappingURL=scopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../../src/middleware/scopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC;AAEtG,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,MAAM;IACrD,kFAAkF;IAClF,IAAI,EAAE,CAAC,CAAC;IACR,6FAA6F;IAC7F,KAAK,EAAE,CAAC,CAAC;IACT,uEAAuE;IACvE,UAAU,EAAE,CAAC,CAAC;IACd,oEAAoE;IACpE,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC;AAqDD,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EAAE,EACrD,IAAI,EACJ,KAAK,EACL,UAAU,EACV,KAAK,EACN,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC,GAAG,IAAI,CAyDvE"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Fail-closed endpoint allowlist for machine principals (API keys now, OAuth
3
+ * bearer tokens in M6). Ported from a predecessor template's oauth-scopes.ts.
4
+ *
5
+ * Machine principals are deliberately MORE restricted than the user they
6
+ * belong to: they can only reach endpoints listed here, each behind its
7
+ * scope. Anything not listed returns null and the gate 403s — new endpoints
8
+ * are unreachable to keys/tokens until someone consciously opens them.
9
+ * Session principals are role-gated instead and never pass through this.
10
+ *
11
+ * Pure logic (no I/O) so it stays unit-testable. The chassis owns the
12
+ * MECHANISM and the rules of its own endpoints; the scope NAMES and the rules
13
+ * of the tool's endpoints are the tool's (`createScopeAllowlist`).
14
+ */
15
+ export function looksLikeJwt(token) {
16
+ return token.split('.').length === 3;
17
+ }
18
+ /**
19
+ * Builds the allowlist function: the chassis rules FIRST, then the tool's
20
+ * rules in order, and `null` (the gate's 403 `endpoint_not_allowed`) when
21
+ * nothing matched — fail-closed by construction.
22
+ */
23
+ /**
24
+ * The chassis project routes a machine principal may reach, EXACT shapes only:
25
+ * reads under the read scope, writes under the write scope. Anything else
26
+ * under `/projects` answers null HERE, so a tool's own route on a project (its
27
+ * link to the project, say) is the tool's rule to open, and an unknown shape
28
+ * stays closed.
29
+ */
30
+ const PROJECT_ID = '[0-9a-fA-F-]{36}';
31
+ const PROJECT_RE = new RegExp(`^/api/v1/projects/${PROJECT_ID}$`);
32
+ const PROJECT_ARCHIVE_RE = new RegExp(`^/api/v1/projects/${PROJECT_ID}/(?:archive|unarchive)$`);
33
+ const PROJECT_MEMBERS_RE = new RegExp(`^/api/v1/projects/${PROJECT_ID}/members$`);
34
+ const PROJECT_MEMBER_RE = new RegExp(`^/api/v1/projects/${PROJECT_ID}/members/[^/]+$`);
35
+ const PROJECT_TEAM_RE = new RegExp(`^/api/v1/projects/${PROJECT_ID}/teams/${PROJECT_ID}$`);
36
+ function projectAccess(path, method) {
37
+ if (path === '/api/v1/projects')
38
+ return method === 'GET' ? 'read' : method === 'POST' ? 'write' : null;
39
+ if (PROJECT_RE.test(path))
40
+ return method === 'GET' ? 'read' : method === 'PATCH' ? 'write' : null;
41
+ if (PROJECT_ARCHIVE_RE.test(path))
42
+ return method === 'POST' ? 'write' : null;
43
+ if (PROJECT_MEMBERS_RE.test(path))
44
+ return method === 'GET' ? 'read' : method === 'POST' ? 'write' : null;
45
+ if (PROJECT_MEMBER_RE.test(path))
46
+ return method === 'PATCH' || method === 'DELETE' ? 'write' : null;
47
+ if (PROJECT_TEAM_RE.test(path))
48
+ return method === 'PATCH' || method === 'DELETE' ? 'write' : null;
49
+ return null;
50
+ }
51
+ /**
52
+ * The chassis team routes a machine principal may reach (PRDCT-2813), EXACT
53
+ * shapes only, the projects' pattern: the reads under the read scope, the
54
+ * writes under the write scope, the handler's owner-or-admin check staying
55
+ * the authority (and the hub-managed gate the refusal in a hub-origin
56
+ * workspace). A person is named by their user id in the path, never by a
57
+ * membership id.
58
+ */
59
+ const TEAM_RE = new RegExp(`^/api/v1/teams/${PROJECT_ID}$`);
60
+ const TEAM_MEMBERS_RE = new RegExp(`^/api/v1/teams/${PROJECT_ID}/members$`);
61
+ const TEAM_MEMBER_RE = new RegExp(`^/api/v1/teams/${PROJECT_ID}/members/[^/]+$`);
62
+ function teamAccess(path, method) {
63
+ if (path === '/api/v1/teams')
64
+ return method === 'GET' ? 'read' : method === 'POST' ? 'write' : null;
65
+ if (TEAM_RE.test(path)) {
66
+ return method === 'GET' ? 'read' : method === 'PATCH' || method === 'DELETE' ? 'write' : null;
67
+ }
68
+ if (TEAM_MEMBERS_RE.test(path))
69
+ return method === 'GET' ? 'read' : method === 'POST' ? 'write' : null;
70
+ if (TEAM_MEMBER_RE.test(path))
71
+ return method === 'DELETE' ? 'write' : null;
72
+ return null;
73
+ }
74
+ export function createScopeAllowlist({ read, write, dataExport, rules }) {
75
+ return function requiredScopeFor(path, method) {
76
+ const isRead = method === 'GET' || method === 'HEAD';
77
+ if (path === '/api/v1/me' && isRead)
78
+ return read;
79
+ // Files: the substrate machine callers actually need (agents pushing and
80
+ // pulling artifacts). Reads → the read scope, mutations → the write scope.
81
+ if (path === '/api/v1/files' || path.startsWith('/api/v1/files/')) {
82
+ return isRead ? read : write;
83
+ }
84
+ // CLI logout self-revoke (api/cli-auth.ts): the ONE /cli/auth route open
85
+ // to machines — DELETE revokes exactly the PRESENTING key. Safe to open
86
+ // because the route names no key (no id parameter): the handler acts only
87
+ // on principal.apiKeyId, resolved from the presented secret, and refuses
88
+ // every non-key principal — so the widest possible effect is a credential
89
+ // revoking ITSELF. The write scope because revocation is a mutation
90
+ // and every CLI-minted key carries it (mirrors the hub's account:write
91
+ // entry). Exact path + method match: any OTHER method on the path, and
92
+ // the PUBLIC mint routes (/cli/auth/request, /cli/auth/complete — which
93
+ // never reach this gate anyway), stay fail-closed.
94
+ if (path === '/api/v1/cli/auth/key' && method === 'DELETE')
95
+ return write;
96
+ // The person's default workspace (api/workspaces.ts, PRDCT-2815): a
97
+ // setting of the PERSON a credential stands for, which the CLI sets.
98
+ // The route names no workspace and acts on the caller's own membership
99
+ // rows only; a key pinned to one workspace is refused by the handler.
100
+ // Exact path + method: nothing else under /me opens with it.
101
+ if (path === '/api/v1/me/default-workspace' && method === 'PUT')
102
+ return write;
103
+ // Full-workspace export: a dedicated opt-in scope, NEVER the read scope — any
104
+ // admin read key would otherwise be a whole-tenant exfiltration tool.
105
+ // (Account deletion, DELETE /members/{id}, stays deliberately UNLISTED:
106
+ // machines 403 fail-closed; deleting people is a session-only act.
107
+ // Break-glass, /admin/break-glass/*, is likewise deliberately UNLISTED:
108
+ // superadmin recovery is a human session act — a key or token whose owner
109
+ // is on SUPERADMIN_EMAILS still 403s here, fail-closed. Never list it.)
110
+ if (path === '/api/v1/workspace/export' && isRead)
111
+ return dataExport;
112
+ // Projects: each route listed by its exact shape and method (above).
113
+ const project = projectAccess(path, method);
114
+ if (project !== null)
115
+ return project === 'read' ? read : write;
116
+ // Teams: the same discipline (above).
117
+ const team = teamAccess(path, method);
118
+ if (team !== null)
119
+ return team === 'read' ? read : write;
120
+ for (const rule of rules) {
121
+ const needed = rule(path, method, isRead);
122
+ if (needed !== null)
123
+ return needed;
124
+ }
125
+ // Deliberately UNLISTED chassis surfaces (fail-closed 403 for
126
+ // keys/tokens), like break-glass:
127
+ // - /sso/logout (cloud) — single logout is a BROWSER act: a machine
128
+ // credential must never be able to end its user's sessions. Never
129
+ // list it.
130
+ // - POST /workspaces — creating a workspace (on cloud: an organization at
131
+ // the hub, as the user) is a HUMAN act from the dashboard. A key or a
132
+ // token must never be able to mint tenants for its holder; the handler
133
+ // re-checks `via === 'session'` on top (api/workspaces.ts). Never list it.
134
+ // - /me/onboarding/dismiss (cloud) — the first-run welcome is a browser
135
+ // concern; machines carry no banner to dismiss.
136
+ return null;
137
+ };
138
+ }
139
+ //# sourceMappingURL=scopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../src/middleware/scopes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ import type { Env } from '../env.js';
3
+ import type { RuntimeState } from '../state.js';
4
+ /**
5
+ * Baseline headers on every response (brief §2.6). The CSP applies to HTML
6
+ * we serve (the dashboard SPA) and locks it to self — with hashes for the
7
+ * inline bootstrap script SvelteKit bakes into index.html, computed once at
8
+ * boot. User-uploaded content never renders on this origin (the files
9
+ * module forces attachment for active types), so this CSP is the only HTML
10
+ * policy the origin needs. frame-ancestors 'none' replaces X-Frame-Options.
11
+ */
12
+ export declare function inlineScriptHashes(html: string): string[];
13
+ export interface CspOptions {
14
+ /**
15
+ * Extra `frame-src` sources beyond 'self'. A dashboard may preview a resource in
16
+ * a sandboxed iframe whose URL honours VIEWER_BASE_URL (PRDCT-1352, DASH-4):
17
+ * with `default-src 'self'` and no `frame-src`, a split viewer origin made
18
+ * that preview a blank frame with no error anywhere but the console.
19
+ */
20
+ frameSrc?: readonly string[];
21
+ /**
22
+ * Extra `img-src` sources beyond 'self' and `data:`. A dashboard that
23
+ * fetches an image through its API (a request that must carry a header an
24
+ * `<img>` cannot send) shows it from an object URL, and `blob:` must be
25
+ * allowed for that or the browser refuses the picture with no error
26
+ * anywhere but the console. A scheme source here is a tool's declaration,
27
+ * never a chassis default.
28
+ */
29
+ imgSrc?: readonly string[];
30
+ }
31
+ export declare function buildCsp(scriptHashes: string[], { frameSrc, imgSrc }?: CspOptions): string;
32
+ export interface SecurityHeaderOptions {
33
+ csp: string;
34
+ state: RuntimeState;
35
+ /**
36
+ * `Strict-Transport-Security` value, or null to send none. Computed once at
37
+ * boot from PUBLIC_BASE_URL + HSTS_MAX_AGE (see {@link hstsValue}) rather
38
+ * than sniffed per request: `X-Forwarded-Proto` is client-controlled unless
39
+ * TRUST_PROXY vouches for it, and this origin issues the session cookie —
40
+ * the operator's declared public scheme is the honest signal.
41
+ */
42
+ hsts?: string | null;
43
+ }
44
+ /**
45
+ * The HSTS header for this instance, or null when it must not be sent.
46
+ * Only an https PUBLIC_BASE_URL arms it: a browser MUST ignore HSTS received
47
+ * over plain http (RFC 6797 §7.2), and pinning an http-only self-host into
48
+ * https for 180 days would brick it. `HSTS_MAX_AGE=0` is the operator opt-out
49
+ * (e.g. a subdomain that cannot yet serve TLS).
50
+ */
51
+ export declare function hstsValue(env: Pick<Env, 'PUBLIC_BASE_URL' | 'HSTS_MAX_AGE'>): string | null;
52
+ export declare function securityHeaders({ csp, state, hsts }: SecurityHeaderOptions): MiddlewareHandler;
53
+ //# sourceMappingURL=security-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUzD;AAED,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,QAAa,EAAE,MAAW,EAAE,GAAE,UAAe,GAAG,MAAM,CAwBxG;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;IACpB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,iBAAiB,GAAG,cAAc,CAAC,GAAG,MAAM,GAAG,IAAI,CAU3F;AAED,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,qBAAqB,GAAG,iBAAiB,CA0B9F"}