@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,129 @@
1
+ import { createHash } from 'node:crypto';
2
+ import type { MiddlewareHandler } from 'hono';
3
+ import type { Env } from '../env.js';
4
+ import type { RuntimeState } from '../state.js';
5
+
6
+ /**
7
+ * Baseline headers on every response (brief §2.6). The CSP applies to HTML
8
+ * we serve (the dashboard SPA) and locks it to self — with hashes for the
9
+ * inline bootstrap script SvelteKit bakes into index.html, computed once at
10
+ * boot. User-uploaded content never renders on this origin (the files
11
+ * module forces attachment for active types), so this CSP is the only HTML
12
+ * policy the origin needs. frame-ancestors 'none' replaces X-Frame-Options.
13
+ */
14
+ export function inlineScriptHashes(html: string): string[] {
15
+ const hashes: string[] = [];
16
+ const re = /<script(?![^>]*\bsrc=)[^>]*>([\s\S]*?)<\/script>/gi;
17
+ let match: RegExpExecArray | null;
18
+ while ((match = re.exec(html)) !== null) {
19
+ const body = match[1] ?? '';
20
+ if (body.trim().length === 0) continue;
21
+ hashes.push(`'sha256-${createHash('sha256').update(body).digest('base64')}'`);
22
+ }
23
+ return hashes;
24
+ }
25
+
26
+ export interface CspOptions {
27
+ /**
28
+ * Extra `frame-src` sources beyond 'self'. A dashboard may preview a resource in
29
+ * a sandboxed iframe whose URL honours VIEWER_BASE_URL (PRDCT-1352, DASH-4):
30
+ * with `default-src 'self'` and no `frame-src`, a split viewer origin made
31
+ * that preview a blank frame with no error anywhere but the console.
32
+ */
33
+ frameSrc?: readonly string[];
34
+ /**
35
+ * Extra `img-src` sources beyond 'self' and `data:`. A dashboard that
36
+ * fetches an image through its API (a request that must carry a header an
37
+ * `<img>` cannot send) shows it from an object URL, and `blob:` must be
38
+ * allowed for that or the browser refuses the picture with no error
39
+ * anywhere but the console. A scheme source here is a tool's declaration,
40
+ * never a chassis default.
41
+ */
42
+ imgSrc?: readonly string[];
43
+ }
44
+
45
+ export function buildCsp(scriptHashes: string[], { frameSrc = [], imgSrc = [] }: CspOptions = {}): string {
46
+ const script = ["'self'", ...scriptHashes].join(' ');
47
+ const frame = ["'self'", ...frameSrc].join(' ');
48
+ const img = ["'self'", 'data:', ...imgSrc].join(' ');
49
+ return [
50
+ "default-src 'self'",
51
+ `script-src ${script}`,
52
+ // Svelte injects component styles at runtime; hashes are impractical there.
53
+ // The two font CDNs the dashboard's app.html links (PRDCT-2308): the
54
+ // Observatory pairing rides Fontshare (Sentient, Synonym) and Google
55
+ // Fonts (Onest) because this repo is slated for the OSS cut and the
56
+ // faces may not be committed. Stylesheets from the two API hosts, the
57
+ // font files from their two file hosts, and nothing else — the
58
+ // dashboard's own origin stays the only script and connect source.
59
+ "style-src 'self' 'unsafe-inline' https://api.fontshare.com https://fonts.googleapis.com",
60
+ `img-src ${img}`,
61
+ "connect-src 'self'",
62
+ "font-src 'self' https://cdn.fontshare.com https://fonts.gstatic.com",
63
+ `frame-src ${frame}`,
64
+ "object-src 'none'",
65
+ "frame-ancestors 'none'",
66
+ "base-uri 'self'",
67
+ "form-action 'self'"
68
+ ].join('; ');
69
+ }
70
+
71
+ export interface SecurityHeaderOptions {
72
+ csp: string;
73
+ state: RuntimeState;
74
+ /**
75
+ * `Strict-Transport-Security` value, or null to send none. Computed once at
76
+ * boot from PUBLIC_BASE_URL + HSTS_MAX_AGE (see {@link hstsValue}) rather
77
+ * than sniffed per request: `X-Forwarded-Proto` is client-controlled unless
78
+ * TRUST_PROXY vouches for it, and this origin issues the session cookie —
79
+ * the operator's declared public scheme is the honest signal.
80
+ */
81
+ hsts?: string | null;
82
+ }
83
+
84
+ /**
85
+ * The HSTS header for this instance, or null when it must not be sent.
86
+ * Only an https PUBLIC_BASE_URL arms it: a browser MUST ignore HSTS received
87
+ * over plain http (RFC 6797 §7.2), and pinning an http-only self-host into
88
+ * https for 180 days would brick it. `HSTS_MAX_AGE=0` is the operator opt-out
89
+ * (e.g. a subdomain that cannot yet serve TLS).
90
+ */
91
+ export function hstsValue(env: Pick<Env, 'PUBLIC_BASE_URL' | 'HSTS_MAX_AGE'>): string | null {
92
+ if (env.HSTS_MAX_AGE <= 0) return null;
93
+ let isHttps = false;
94
+ try {
95
+ isHttps = new URL(env.PUBLIC_BASE_URL).protocol === 'https:';
96
+ } catch {
97
+ isHttps = false;
98
+ }
99
+ if (!isHttps) return null;
100
+ return `max-age=${env.HSTS_MAX_AGE}; includeSubDomains`;
101
+ }
102
+
103
+ export function securityHeaders({ csp, state, hsts }: SecurityHeaderOptions): MiddlewareHandler {
104
+ return async (c, next) => {
105
+ await next();
106
+ c.header('x-content-type-options', 'nosniff');
107
+ // HSTS on EVERY response, not just HTML: the cookie this origin issues is
108
+ // sent with XHR too, so an http downgrade on /api/v1 is the same theft.
109
+ if (hsts && !c.res.headers.has('strict-transport-security')) {
110
+ c.header('strict-transport-security', hsts);
111
+ }
112
+ // Baseline defaults, but NEVER clobber a value a route set for itself:
113
+ // the public viewer (ADR 012) serves user-authored HTML under its own
114
+ // `Content-Security-Policy: sandbox …` + `Referrer-Policy: no-referrer`,
115
+ // and an unconditional overwrite here would silently replace the sandbox
116
+ // CSP with the dashboard CSP — re-opening the session-theft surface the
117
+ // sandbox exists to close (found by the ADR 012 spike; fail-dangerous
118
+ // class, see the ADR's residual-risk #1 and the viewer regression tests).
119
+ if (!c.res.headers.has('referrer-policy')) {
120
+ c.header('referrer-policy', 'strict-origin-when-cross-origin');
121
+ }
122
+ // Draining: ask keep-alive clients to reconnect elsewhere (rolling deploy).
123
+ if (state.draining) c.header('connection', 'close');
124
+ const contentType = c.res.headers.get('content-type') ?? '';
125
+ if (contentType.includes('text/html') && !c.res.headers.has('content-security-policy')) {
126
+ c.header('content-security-policy', csp);
127
+ }
128
+ };
129
+ }
@@ -0,0 +1,2 @@
1
+ export { type Otel, createOtel } from './otel.js';
2
+ export { createMetrics } from './metrics.js';
@@ -0,0 +1,102 @@
1
+ import { collectDefaultMetrics, Gauge, Histogram, Registry } from 'prom-client';
2
+ import type { MiddlewareHandler } from 'hono';
3
+ import { Hono } from 'hono';
4
+ import { sql } from 'drizzle-orm';
5
+ import { files, type Db } from '@antasphere/chassis-db';
6
+ import type PgBoss from 'pg-boss';
7
+ import { constantTimeEquals } from '../constant-time.js';
8
+ import { USAGE_QUEUE } from '../jobs/pgboss.js';
9
+ import { routeLabel } from '../route-label.js';
10
+
11
+ /**
12
+ * Prometheus surface. Route labels use the MATCHED pattern (not the raw
13
+ * path) so label cardinality stays bounded. Queue depth and storage bytes
14
+ * are collected lazily at scrape time.
15
+ */
16
+ export interface Metrics {
17
+ registry: Registry;
18
+ middleware: MiddlewareHandler;
19
+ routes: (token: string | undefined) => Hono;
20
+ }
21
+
22
+ export function createMetrics(db: Db, boss: PgBoss): Metrics {
23
+ const registry = new Registry();
24
+ collectDefaultMetrics({ register: registry });
25
+
26
+ const httpDuration = new Histogram({
27
+ name: 'http_request_duration_seconds',
28
+ help: 'HTTP request latency by route',
29
+ labelNames: ['method', 'route', 'status'] as const,
30
+ buckets: [0.005, 0.02, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5],
31
+ registers: [registry]
32
+ });
33
+
34
+ new Gauge({
35
+ name: 'job_queue_depth',
36
+ help: 'Pending jobs in the usage queue',
37
+ registers: [registry],
38
+ async collect() {
39
+ try {
40
+ this.set((await boss.getQueueSize(USAGE_QUEUE)) ?? 0);
41
+ } catch {
42
+ // queue may not exist yet (api-only role before first worker boot)
43
+ }
44
+ }
45
+ });
46
+
47
+ new Gauge({
48
+ name: 'storage_bytes_total',
49
+ help: 'Bytes referenced by live file rows',
50
+ registers: [registry],
51
+ async collect() {
52
+ const [row] = await db
53
+ .select({ total: sql<string>`coalesce(sum(${files.sizeBytes}), 0)::text` })
54
+ .from(files)
55
+ .where(sql`${files.deletedAt} IS NULL`);
56
+ this.set(Number(row?.total ?? '0'));
57
+ }
58
+ });
59
+
60
+ const middleware: MiddlewareHandler = async (c, next) => {
61
+ const start = performance.now();
62
+ try {
63
+ await next();
64
+ } finally {
65
+ const seconds = (performance.now() - start) / 1000;
66
+ httpDuration.observe(
67
+ {
68
+ method: c.req.method,
69
+ // routeLabel, same as the log line and the span: on the pinned
70
+ // Hono the previous `?? c.req.path` fallback was unreachable
71
+ // (routePath always answers a string here), but a raw-path
72
+ // expression in a label position is exactly what must not come
73
+ // back to life on a version bump — one shared, secret-free
74
+ // label instead (PRIV-1).
75
+ route: routeLabel(c),
76
+ status: String(c.error ? 500 : c.res.status)
77
+ },
78
+ seconds
79
+ );
80
+ }
81
+ };
82
+
83
+ const routes = (token: string | undefined): Hono => {
84
+ const app = new Hono();
85
+ app.get('/metrics', async (c) => {
86
+ // Default-closed: route names, queue depth, and storage totals are not
87
+ // for the open internet. setup.sh generates a METRICS_TOKEN.
88
+ if (!token) {
89
+ return c.text('metrics disabled: set METRICS_TOKEN', 401);
90
+ }
91
+ const auth = c.req.header('authorization') ?? '';
92
+ if (!constantTimeEquals(auth, `Bearer ${token}`)) {
93
+ return c.text('unauthorized', 401);
94
+ }
95
+ c.header('content-type', registry.contentType);
96
+ return c.body(await registry.metrics());
97
+ });
98
+ return app;
99
+ };
100
+
101
+ return { registry, middleware, routes };
102
+ }
@@ -0,0 +1,79 @@
1
+ import { trace, type Tracer } from '@opentelemetry/api';
2
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
3
+ import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
4
+ import { resourceFromAttributes } from '@opentelemetry/resources';
5
+ import type { MiddlewareHandler } from 'hono';
6
+ import type { Env } from '../env.js';
7
+ import type { Logger } from '../logger.js';
8
+ import { routeLabel } from '../route-label.js';
9
+
10
+ /**
11
+ * Tracing with the zero-phone-home default: spans are recorded ONLY when an
12
+ * operator configures OTEL_EXPORTER_OTLP_ENDPOINT — without it no exporter
13
+ * is registered and nothing leaves the instance. The request id rides every
14
+ * span as `request.id`, which is the correlation key across log line, span,
15
+ * and audit row.
16
+ */
17
+ export interface Otel {
18
+ tracer: Tracer;
19
+ middleware: MiddlewareHandler;
20
+ shutdown: () => Promise<void>;
21
+ }
22
+
23
+ export async function createOtel(
24
+ env: Pick<Env, 'OTEL_EXPORTER_OTLP_ENDPOINT' | 'APP_VERSION' | 'EDITION'>,
25
+ logger: Logger,
26
+ options: { serviceName: string }
27
+ ): Promise<Otel> {
28
+ const resource = resourceFromAttributes({
29
+ 'service.name': options.serviceName,
30
+ 'service.version': env.APP_VERSION,
31
+ 'deployment.environment.name': env.EDITION
32
+ });
33
+
34
+ const spanProcessors = [];
35
+ if (env.OTEL_EXPORTER_OTLP_ENDPOINT) {
36
+ const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http');
37
+ spanProcessors.push(
38
+ new BatchSpanProcessor(new OTLPTraceExporter({ url: `${env.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces` }))
39
+ );
40
+ logger.info({ endpoint: env.OTEL_EXPORTER_OTLP_ENDPOINT }, 'otel export enabled');
41
+ }
42
+
43
+ const provider = new NodeTracerProvider({ resource, spanProcessors });
44
+ provider.register();
45
+ const tracer = trace.getTracer(options.serviceName);
46
+
47
+ const middleware: MiddlewareHandler = async (c, next) => {
48
+ // Start with a low-cardinality name (the matched route pattern isn't known
49
+ // until after routing); rename to the pattern in `finally` so span names
50
+ // stay bounded — a raw path with ids would explode span cardinality.
51
+ await tracer.startActiveSpan(`HTTP ${c.req.method}`, async (span) => {
52
+ span.setAttributes({
53
+ 'http.request.method': c.req.method,
54
+ 'request.id': c.get('requestId')
55
+ });
56
+ try {
57
+ await next();
58
+ } finally {
59
+ // The MATCHED ROUTE PATTERN, never the raw path (route-label.ts): a
60
+ // span attribute is exported OFF-INSTANCE, so a `/v/<share secret>`
61
+ // there hands a working capability to the trace backend.
62
+ const route = routeLabel(c);
63
+ span.updateName(`${c.req.method} ${route}`);
64
+ span.setAttributes({
65
+ 'http.route': route,
66
+ 'url.path': route,
67
+ 'http.response.status_code': c.error ? 500 : c.res.status
68
+ });
69
+ span.end();
70
+ }
71
+ });
72
+ };
73
+
74
+ return {
75
+ tracer,
76
+ middleware,
77
+ shutdown: () => provider.shutdown()
78
+ };
79
+ }
@@ -0,0 +1,118 @@
1
+ import { sql, type SQL } from 'drizzle-orm';
2
+ import type { PgColumn, PgTable } from 'drizzle-orm/pg-core';
3
+
4
+ /**
5
+ * Keyset (cursor) pagination over (created_at, id), newest first — the audit
6
+ * route's convention extended to the uuid-keyed tables. Two cursor dialects,
7
+ * one rule: the timestamp's precision never leaves Postgres, because a JS
8
+ * Date round-trip truncates its microseconds and a millisecond-equal
9
+ * boundary row would then be skipped or repeated.
10
+ *
11
+ * - `keysetBefore`: the cursor is the last returned row's plain id, and the
12
+ * timestamp is resolved from that row by subquery at page time. For the
13
+ * tables that never hard-delete a row (members are deactivated, keys and
14
+ * invitations revoked, projects archived): the cursor row is always there.
15
+ * - `keysetBeforeValue`: the cursor CARRIES the timestamp, as the text
16
+ * Postgres itself rendered (`created_at::text`, selected beside the row,
17
+ * never a JS Date), with the id. For a table that hard-deletes rows
18
+ * (project_members): a cursor naming a removed row would compare against
19
+ * NULL under the subquery dialect and end the listing early.
20
+ */
21
+
22
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
23
+
24
+ /**
25
+ * Shared UUID shape check — cursors here, and the id params of the
26
+ * plain-Hono routes that have no contract schema (files content/HEAD): a
27
+ * non-UUID string must be rejected before it reaches Postgres' uuid cast.
28
+ */
29
+ export function isUuid(value: string): boolean {
30
+ return UUID_RE.test(value);
31
+ }
32
+
33
+ /**
34
+ * The cursor row id, or null when absent/malformed. A malformed cursor is
35
+ * silently ignored — the caller serves page 1 (the audit route's
36
+ * `Number('banana')` tolerance).
37
+ */
38
+ export function cursorRowId(cursor: string | undefined): string | null {
39
+ if (!cursor || !isUuid(cursor)) return null;
40
+ return cursor;
41
+ }
42
+
43
+ /**
44
+ * Row-value keyset predicate: everything strictly older than the cursor row,
45
+ * with the cursor row's (created_at, id) resolved by a SQL-side subquery.
46
+ * The subquery is workspace-scoped so a foreign workspace's cursor can never
47
+ * position inside this workspace's ordering. A well-formed-but-unknown id
48
+ * makes the subquery empty → NULL predicate → empty page + nextCursor null;
49
+ * harmless, since cursors are server-issued and these tables never
50
+ * hard-delete rows.
51
+ */
52
+ export function keysetBefore(opts: {
53
+ table: PgTable;
54
+ id: PgColumn;
55
+ createdAt: PgColumn;
56
+ workspaceId: PgColumn;
57
+ cursorId: string;
58
+ workspace: string;
59
+ }): SQL {
60
+ return sql`(${opts.createdAt}, ${opts.id}) < (SELECT ${opts.createdAt}, ${opts.id} FROM ${opts.table} WHERE ${opts.id} = ${opts.cursorId} AND ${opts.workspaceId} = ${opts.workspace})`;
61
+ }
62
+
63
+ /** Slice a limit+1 fetch into the page + the audit-style nextCursor (last id of the page). */
64
+ export function pageOf<T extends { id: string }>(
65
+ rows: T[],
66
+ limit: number
67
+ ): { page: T[]; nextCursor: string | null } {
68
+ const page = rows.slice(0, limit);
69
+ const nextCursor = rows.length > limit ? (page[page.length - 1]?.id ?? null) : null;
70
+ return { page, nextCursor };
71
+ }
72
+
73
+ /**
74
+ * The value-carrying cursor (`keysetBeforeValue`): the row's `created_at` as
75
+ * Postgres rendered it and its id, base64url of `<text>|<id>`. Opaque on the
76
+ * wire like the other dialect; a malformed one is ignored (page 1).
77
+ */
78
+ const TIMESTAMPTZ_TEXT_RE =
79
+ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d{1,6})?[+-]\d{2}(?::\d{2}(?::\d{2})?)?$/;
80
+
81
+ export interface KeysetValueCursor {
82
+ /** `created_at::text`, exactly as Postgres rendered it. */
83
+ createdAt: string;
84
+ id: string;
85
+ }
86
+
87
+ export function encodeKeysetCursor(row: { id: string; createdAtText: string }): string {
88
+ return Buffer.from(`${row.createdAtText}|${row.id}`, 'utf8').toString('base64url');
89
+ }
90
+
91
+ export function decodeKeysetCursor(cursor: string | undefined): KeysetValueCursor | null {
92
+ if (!cursor || cursor.length > 200) return null;
93
+ // Node's base64url decoder never throws (it drops what it cannot read):
94
+ // the guard is the two shape checks below, not the decode.
95
+ const decoded = Buffer.from(cursor, 'base64url').toString('utf8');
96
+ const at = decoded.lastIndexOf('|');
97
+ if (at < 0) return null;
98
+ const createdAt = decoded.slice(0, at);
99
+ const id = decoded.slice(at + 1);
100
+ // Both halves are validated before they reach a Postgres cast: a shape the
101
+ // casts would refuse must answer page 1, never a 500.
102
+ if (!TIMESTAMPTZ_TEXT_RE.test(createdAt) || !isUuid(id)) return null;
103
+ return { createdAt, id };
104
+ }
105
+
106
+ /** The `created_at::text` column to select beside a row that will mint a value cursor. */
107
+ export function createdAtText(createdAt: PgColumn): SQL<string> {
108
+ return sql<string>`${createdAt}::text`;
109
+ }
110
+
111
+ /** `(created_at, id) < (cursor)` with the cursor's own values; `keysetBefore`'s twin for hard-deleting tables. */
112
+ export function keysetBeforeValue(opts: {
113
+ id: PgColumn;
114
+ createdAt: PgColumn;
115
+ cursor: KeysetValueCursor;
116
+ }): SQL {
117
+ return sql`(${opts.createdAt}, ${opts.id}) < (${opts.cursor.createdAt}::timestamptz, ${opts.cursor.id}::uuid)`;
118
+ }
@@ -0,0 +1,140 @@
1
+ import type { Db } from '@antasphere/chassis-db';
2
+ import type {
3
+ EntitlementService,
4
+ IdentityProvider,
5
+ InstanceAuthDescriptor,
6
+ Principal,
7
+ RequestContext,
8
+ UsageSink
9
+ } from '@antasphere/chassis-contract';
10
+ import { HUB_SSO_PROVIDER_ID } from '../identity/hub-sso.js';
11
+ import { HubLiveGate } from '../identity/hub-live-gate.js';
12
+ import type { HubOrgReconciler } from '../identity/hub-reconcile.js';
13
+ import type { PrincipalGate } from '../middleware/auth-context.js';
14
+ import type { HubConfig } from '../env.js';
15
+ import type { Logger } from '../logger.js';
16
+
17
+ /**
18
+ * The edition split (internal/federation.md): one codebase, one Docker image,
19
+ * two seam bindings selected purely by instance config. This module is the
20
+ * ONLY place edition decides which implementations the boot-time registry
21
+ * gets — `oss` binds the local defaults byte-identically; `cloud` rebinds
22
+ * the hub-federating variants here.
23
+ */
24
+
25
+ /**
26
+ * The hub SSO method name the cloud edition advertises in discovery — the
27
+ * better-auth `genericOAuth` providerId registered by identity/hub-sso.ts
28
+ * (its callback lands on /api/v1/auth/oauth2/callback/antasphere, the
29
+ * redirect URI in the hub's TOOL_REGISTRY entry).
30
+ */
31
+ export const HUB_SSO_METHOD = HUB_SSO_PROVIDER_ID;
32
+
33
+ /**
34
+ * The cloud identity binding. Request RESOLUTION stays exactly the local
35
+ * provider's — after the SSO callback mints an ordinary session, every
36
+ * request is sessions + live membership re-check (the live hub gate runs
37
+ * post-resolution in authContext, not here). What changes is the ADVERTISED
38
+ * entrance (D1, hub-only human login):
39
+ *
40
+ * - `antasphere` replaces password/email-otp/google — the login page
41
+ * renders ONLY "Sign in with Antasphere". The local password machinery
42
+ * stays WIRED (hidden, not blocked): the break-glass CLI remains the
43
+ * operator door, and blocking /sign-in/email would dead-end it.
44
+ * - `passwordReset`/`emailChange` are off: credentials and email are the
45
+ * HUB's to manage (D10 re-syncs email at every login); a local reset
46
+ * surface would fight the sync. Since the P8 close (ADR 017) the reset
47
+ * routes don't just report false — they REFUSE on cloud (403; the
48
+ * before-hook in identity/better-auth.ts + the members reset-link mint),
49
+ * so a hub-JIT user can never SET a local password and sidestep SSO.
50
+ * - `twoFactor` is off: the second factor guards local password/OTP
51
+ * sign-ins, which the cloud page no longer offers — MFA is the hub's
52
+ * concern at its own login.
53
+ */
54
+ class HubSsoIdentityProvider implements IdentityProvider {
55
+ constructor(private readonly local: IdentityProvider) {}
56
+
57
+ resolve(ctx: RequestContext): Promise<Principal | null> {
58
+ return this.local.resolve(ctx);
59
+ }
60
+
61
+ describe(): InstanceAuthDescriptor {
62
+ return {
63
+ // Machine entrances are edition-independent; the human entrance is
64
+ // hub-only. 'oauth' stays: every instance is its own OAuth 2.1 AS for
65
+ // /mcp — the hub never appears in the MCP dance.
66
+ methods: [HUB_SSO_METHOD, 'api-key', 'oauth'],
67
+ passwordReset: false,
68
+ emailChange: false,
69
+ twoFactor: false
70
+ };
71
+ }
72
+ }
73
+
74
+ /** The three registry seams the edition owns (events/workspaces are edition-independent). */
75
+ export interface EditionSeams {
76
+ identity: IdentityProvider;
77
+ entitlements: EntitlementService;
78
+ usage: UsageSink;
79
+ }
80
+
81
+ /** What the cloud bindings need beyond the seams themselves. */
82
+ export interface EditionBindingDeps {
83
+ db: Db;
84
+ /**
85
+ * The live org reconciler (identity/hub-reconcile.ts), constructed by
86
+ * boot on cloud — the ONE hub data path, shared by the login pass, the
87
+ * live gate, and the unknown-workspace miss hook.
88
+ */
89
+ reconciler?: HubOrgReconciler | undefined;
90
+ }
91
+
92
+ /**
93
+ * The bound seams plus the cloud-only extra boot wires alongside them: the
94
+ * post-resolution principal gate (authContext). Absent on oss by
95
+ * construction.
96
+ */
97
+ export interface BoundEditionSeams extends EditionSeams {
98
+ principalGate?: PrincipalGate;
99
+ }
100
+
101
+ /**
102
+ * Bind the registry seams for this instance's edition. `hub` is the single
103
+ * switch: null (EDITION=oss) returns the local defaults UNTOUCHED — the
104
+ * self-host edition carries zero hub surface at runtime; a HubConfig
105
+ * (EDITION=cloud, validated at env parse) selects the cloud bindings.
106
+ *
107
+ * Entitlements bind LOCAL on BOTH editions: the live gate refuses a
108
+ * suspended/revoked/unavailable principal at the door, before any handler
109
+ * or entitlement check runs — a hub-wrapping entitlement layer would be a
110
+ * second, redundant enforcement path.
111
+ */
112
+ export function bindEditionSeams(
113
+ hub: HubConfig | null,
114
+ local: EditionSeams,
115
+ logger: Logger,
116
+ deps: EditionBindingDeps
117
+ ): BoundEditionSeams {
118
+ if (!hub) return local;
119
+
120
+ logger.info(
121
+ { hubIssuer: hub.issuerUrl },
122
+ 'EDITION=cloud: hub SSO is the human entrance (identity resolution stays local sessions); ' +
123
+ 'org/membership truth is reconciled live AS THE USER via each user’s own hub grant ' +
124
+ '(internal/federation.md).'
125
+ );
126
+ const gate = deps.reconciler
127
+ ? new HubLiveGate({ db: deps.db, reconciler: deps.reconciler, logger })
128
+ : undefined;
129
+ return {
130
+ // Hub-only entrance advertised; the SSO machinery itself (relying
131
+ // party, JIT, login reconcile) lives in identity/hub-sso.ts and is
132
+ // wired through createAuth — resolution stays local by design.
133
+ identity: new HubSsoIdentityProvider(local.identity),
134
+ entitlements: local.entitlements,
135
+ // D6: usage stays the local sink with a no-op downstream for v1; hub
136
+ // ingest is a one-class downstream swap when it ships (plan §4.3).
137
+ usage: local.usage,
138
+ ...(gate ? { principalGate: gate.assert } : {})
139
+ };
140
+ }
@@ -0,0 +1,47 @@
1
+ import type {
2
+ EntitlementDecision,
3
+ EntitlementService,
4
+ MeteredAction,
5
+ Principal,
6
+ RequestQuota
7
+ } from '@antasphere/chassis-contract';
8
+
9
+ /**
10
+ * Default EntitlementService: everything is allowed, bounded only by
11
+ * instance-level env caps. The cloud/central edition swaps this via the
12
+ * registry for a credits-backed implementation; handlers only ever call
13
+ * `entitlements.check(...)` and never know the difference.
14
+ */
15
+ export interface InstanceCaps {
16
+ maxFileSizeMb: number;
17
+ /** General-API quota defaults: sustained per-minute + 1 s spike cap (env-driven). */
18
+ apiRequestsPerMinute: number;
19
+ apiRequestsBurstPerSecond: number;
20
+ }
21
+
22
+ export class AllowAllEntitlements implements EntitlementService {
23
+ constructor(private readonly caps: InstanceCaps) {}
24
+
25
+ async check(_principal: Principal, action: MeteredAction): Promise<EntitlementDecision> {
26
+ if (action.key === 'files.upload' && action.unit === 'bytes') {
27
+ const max = this.caps.maxFileSizeMb * 1024 * 1024;
28
+ if (action.quantity > max) {
29
+ return { allowed: false, reason: `file exceeds MAX_FILE_SIZE_MB (${this.caps.maxFileSizeMb}MB)` };
30
+ }
31
+ }
32
+ return { allowed: true };
33
+ }
34
+
35
+ /**
36
+ * One flat instance-level quota for every principal. A plan-aware edition
37
+ * returns different values per plan here — the enforcing middleware keys
38
+ * buckets by (quota size, principal), so per-plan variation needs no other
39
+ * change.
40
+ */
41
+ async getRequestQuota(_principal: Principal): Promise<RequestQuota> {
42
+ return {
43
+ perMinute: this.caps.apiRequestsPerMinute,
44
+ burstPerSecond: this.caps.apiRequestsBurstPerSecond
45
+ };
46
+ }
47
+ }