@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,133 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { projects } from '@antasphere/chassis-db';
3
+ /**
4
+ * THE project access rule, stated once. A tool links its own resources to
5
+ * projects through a table of its own, and asks ONE question of the chassis:
6
+ * "does this principal hold a grant of at least `<role>` on the project in
7
+ * this column?". The chassis routes (`api/projects.ts`) ask the same question
8
+ * through the same builder, so a tool cannot drift from them.
9
+ *
10
+ * What the predicate carries, and every clause is load-bearing:
11
+ *
12
+ * - **The guest refusal.** An `origin='guest'` membership exists for
13
+ * principal resolution only (D2): it is never a project member. Refused on
14
+ * the PRINCIPAL (`false`, no query at all) AND on the membership row the
15
+ * grant rides on (`origin <> 'guest'`), so a stray row is inert.
16
+ * - **The live membership.** The grant is read THROUGH its
17
+ * `workspace_members` row: same user, same workspace as the request,
18
+ * `is_active`. A deleted membership took the grant with it (the foreign
19
+ * key's cascade); a deactivated one resolves no principal at all.
20
+ * - **One workspace.** The project belongs to the request's workspace and to
21
+ * the membership's. A request never spans workspaces (ADR 014).
22
+ * - **The role ladder.** `manager` contains `editor` contains `viewer`.
23
+ * - **A team's grant (PRDCT-2794).** A person seated in a team that holds a
24
+ * place on the project holds the team's role, on the same live membership
25
+ * row; their effective role is the highest of their own grant and their
26
+ * teams'. A seat or a grant removed is felt on the next request.
27
+ * - **The operator view.** A workspace owner or admin acts as a manager on
28
+ * every project of the workspace (ADR 006), which is why a project with no
29
+ * manager stays manageable and there is no last-manager guard.
30
+ * - **The archived-write rule.** `access: 'write'` is off while the project
31
+ * is archived, for everyone, the operator included. A READ stays.
32
+ *
33
+ * Callers answer 404, never 403, when a READ predicate is false: a project a
34
+ * principal cannot read must not reveal its existence.
35
+ */
36
+ const LADDER = {
37
+ viewer: ['viewer', 'editor', 'manager'],
38
+ editor: ['editor', 'manager'],
39
+ manager: ['manager']
40
+ };
41
+ /**
42
+ * A boolean SQL expression over `projectId`, a column (or expression) of the
43
+ * CALLER's query that holds a project id: the tool's link table column, or
44
+ * `projects.id` itself. The aliases are prefixed so they cannot collide with
45
+ * the ones of the query the predicate is embedded in.
46
+ *
47
+ * **Pass a QUALIFIED reference when the predicate lands in a SELECT LIST.**
48
+ * drizzle renders a column object of a single-table select WITHOUT its table
49
+ * name there (`"id"`), and inside this subquery a bare `"id"` binds to the
50
+ * subquery's own tables: ambiguous at best, always-true at worst. A raw
51
+ * `sql\`"link_table"."project_id"\`` (or `PROJECTS_ID` below) is immune; a
52
+ * column object is safe in a WHERE, where drizzle always qualifies it.
53
+ */
54
+ export function projectGrantPredicate(principal, projectId, opts) {
55
+ if (principal.origin === 'guest')
56
+ return sql `false`;
57
+ const live = opts.access === 'write' ? sql `AND prj_pr.archived_at IS NULL` : sql ``;
58
+ if (principal.role === 'owner' || principal.role === 'admin') {
59
+ return sql `EXISTS (
60
+ SELECT 1 FROM projects prj_pr
61
+ WHERE prj_pr.id = ${projectId}
62
+ AND prj_pr.workspace_id = ${principal.workspaceId}
63
+ ${live}
64
+ )`;
65
+ }
66
+ const roles = sql.join(LADDER[opts.atLeast].map((role) => sql `${role}`), sql `, `);
67
+ // Two ways to hold a grant, judged on the SAME live membership row: the
68
+ // person's own entry (`project_members`), or the entry of a team the person
69
+ // is seated in (`project_teams` through `workspace_team_members`, PRDCT-2794).
70
+ // The team's workspace is checked against the membership's like the
71
+ // project's, so a seat can never reach across workspaces; the effective
72
+ // role is the highest of the two, which the ladder's IN list yields.
73
+ return sql `EXISTS (
74
+ SELECT 1
75
+ FROM workspace_members prj_wm
76
+ JOIN projects prj_pr ON prj_pr.workspace_id = prj_wm.workspace_id
77
+ WHERE prj_pr.id = ${projectId}
78
+ AND prj_wm.user_id = ${principal.userId}
79
+ AND prj_wm.workspace_id = ${principal.workspaceId}
80
+ AND prj_wm.is_active
81
+ AND prj_wm.origin <> 'guest'
82
+ ${live}
83
+ AND (
84
+ EXISTS (
85
+ SELECT 1 FROM project_members prj_pm
86
+ WHERE prj_pm.project_id = prj_pr.id
87
+ AND prj_pm.member_id = prj_wm.id
88
+ AND prj_pm.role IN (${roles})
89
+ )
90
+ OR EXISTS (
91
+ SELECT 1
92
+ FROM project_teams prj_pt
93
+ JOIN workspace_team_members prj_tm ON prj_tm.team_id = prj_pt.team_id
94
+ JOIN workspace_teams prj_t ON prj_t.id = prj_pt.team_id
95
+ WHERE prj_pt.project_id = prj_pr.id
96
+ AND prj_tm.member_id = prj_wm.id
97
+ AND prj_t.workspace_id = prj_wm.workspace_id
98
+ AND prj_pt.role IN (${roles})
99
+ )
100
+ )
101
+ )`;
102
+ }
103
+ /** `projects.id`, always qualified: safe in a select list as in a WHERE (see above). */
104
+ export const PROJECTS_ID = sql.raw('"projects"."id"');
105
+ /**
106
+ * The caller's effective role on a project AS A SQL EXPRESSION over a project
107
+ * id column: `manager`, `editor`, `viewer`, or NULL (no read). Built from the
108
+ * predicate above, never beside it. Archive-blind on purpose: a role is a
109
+ * READ fact, and whether an act is allowed on an archived project is the
110
+ * act's own question (`access: 'write'`, or the route's 409).
111
+ */
112
+ export function projectRoleExpression(principal, projectId) {
113
+ const has = (atLeast) => projectGrantPredicate(principal, projectId, { atLeast, access: 'read' });
114
+ return sql `CASE
115
+ WHEN ${has('manager')} THEN 'manager'
116
+ WHEN ${has('editor')} THEN 'editor'
117
+ WHEN ${has('viewer')} THEN 'viewer'
118
+ END`;
119
+ }
120
+ /**
121
+ * The effective role of `principal` on one project of the request's
122
+ * workspace, or null. **null = 404**: no such project here, or a project the
123
+ * principal cannot read; the two must stay indistinguishable to the caller.
124
+ */
125
+ export async function projectRole(conn, principal, projectId) {
126
+ const rows = await conn
127
+ .select({ role: projectRoleExpression(principal, PROJECTS_ID) })
128
+ .from(projects)
129
+ .where(sql `${projects.id} = ${projectId} AND ${projects.workspaceId} = ${principal.workspaceId}`)
130
+ .limit(1);
131
+ return rows[0]?.role ?? null;
132
+ }
133
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/projects/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAA6B,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAe,MAAM,wBAAwB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,MAAM,GAAgD;IAC1D,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,OAAO,EAAE,CAAC,SAAS,CAAC;CACrB,CAAC;AASF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAwE,EACxE,SAAqB,EACrB,IAAyB;IAEzB,IAAI,SAAS,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,GAAG,CAAA,OAAO,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAA,gCAAgC,CAAC,CAAC,CAAC,GAAG,CAAA,EAAE,CAAC;IACnF,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC7D,OAAO,GAAG,CAAA;;0BAEY,SAAS;oCACC,SAAS,CAAC,WAAW;UAC/C,IAAI;MACR,CAAC;IACL,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CACpB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAA,GAAG,IAAI,EAAE,CAAC,EAChD,GAAG,CAAA,IAAI,CACR,CAAC;IACF,wEAAwE;IACxE,4EAA4E;IAC5E,+EAA+E;IAC/E,oEAAoE;IACpE,wEAAwE;IACxE,qEAAqE;IACrE,OAAO,GAAG,CAAA;;;;wBAIY,SAAS;6BACJ,SAAS,CAAC,MAAM;kCACX,SAAS,CAAC,WAAW;;;QAG/C,IAAI;;;;;;kCAMsB,KAAK;;;;;;;;;;kCAUL,KAAK;;;IAGnC,CAAC;AACL,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,WAAW,GAAQ,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAwE,EACxE,SAAqB;IAErB,MAAM,GAAG,GAAG,CAAC,OAAoB,EAAE,EAAE,CACnC,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3E,OAAO,GAAG,CAAoB;WACrB,GAAG,CAAC,SAAS,CAAC;WACd,GAAG,CAAC,QAAQ,CAAC;WACb,GAAG,CAAC,QAAQ,CAAC;MAClB,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,SAAwE,EACxE,SAAiB;IAEjB,MAAM,IAAI,GAAG,MAAM,IAAI;SACpB,MAAM,CAAC,EAAE,IAAI,EAAE,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;SAC/D,IAAI,CAAC,QAAQ,CAAC;SACd,KAAK,CAAC,GAAG,CAAA,GAAG,QAAQ,CAAC,EAAE,MAAM,SAAS,QAAQ,QAAQ,CAAC,WAAW,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC;SAChG,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PROJECTS_ID, projectGrantPredicate, projectRole, projectRoleExpression, type ProjectGrantOptions } from './access.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,qBAAqB,EACrB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PROJECTS_ID, projectGrantPredicate, projectRole, projectRoleExpression } from './access.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/projects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,qBAAqB,EAEtB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { Context } from 'hono';
2
+ /**
3
+ * The low-cardinality, secret-free label for a request, used by BOTH the
4
+ * completion log line and the trace span.
5
+ *
6
+ * The raw `c.req.path` must never reach the log stream or a span attribute.
7
+ * Path segments are request data like any other: the moment a route puts a
8
+ * capability in the URL — a share secret, a one-time token, an invitation
9
+ * code — every log sink, every trace backend, and every operator with
10
+ * `docker logs` holds a working credential, and the redaction list cannot
11
+ * help (it keys off object properties, and `path` is one opaque string).
12
+ * Logging the MATCHED ROUTE PATTERN instead (`/v/:secret`, not
13
+ * `/v/9f3c…`) keeps the line just as useful for debugging and cardinality
14
+ * bounded, and it is secret-free by construction for every route that will
15
+ * ever be added.
16
+ *
17
+ * `routePath` is only populated once routing has run, so callers must read
18
+ * this AFTER `await next()`. Unmatched requests have no pattern to report:
19
+ * they get the literal `(unmatched)` rather than the attacker-controlled URL
20
+ * they probed with.
21
+ */
22
+ export declare function routeLabel(c: Context): string;
23
+ //# sourceMappingURL=route-label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-label.d.ts","sourceRoot":"","sources":["../src/route-label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAM7C"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The low-cardinality, secret-free label for a request, used by BOTH the
3
+ * completion log line and the trace span.
4
+ *
5
+ * The raw `c.req.path` must never reach the log stream or a span attribute.
6
+ * Path segments are request data like any other: the moment a route puts a
7
+ * capability in the URL — a share secret, a one-time token, an invitation
8
+ * code — every log sink, every trace backend, and every operator with
9
+ * `docker logs` holds a working credential, and the redaction list cannot
10
+ * help (it keys off object properties, and `path` is one opaque string).
11
+ * Logging the MATCHED ROUTE PATTERN instead (`/v/:secret`, not
12
+ * `/v/9f3c…`) keeps the line just as useful for debugging and cardinality
13
+ * bounded, and it is secret-free by construction for every route that will
14
+ * ever be added.
15
+ *
16
+ * `routePath` is only populated once routing has run, so callers must read
17
+ * this AFTER `await next()`. Unmatched requests have no pattern to report:
18
+ * they get the literal `(unmatched)` rather than the attacker-controlled URL
19
+ * they probed with.
20
+ */
21
+ export function routeLabel(c) {
22
+ const matched = c.req.routePath;
23
+ // Hono answers '/*' for a catch-all match and for no match at all; neither
24
+ // says anything the pattern doesn't, and both are safe to report as-is.
25
+ if (!matched)
26
+ return '(unmatched)';
27
+ return matched;
28
+ }
29
+ //# sourceMappingURL=route-label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-label.js","sourceRoot":"","sources":["../src/route-label.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;IAChC,2EAA2E;IAC3E,wEAAwE;IACxE,IAAI,CAAC,OAAO;QAAE,OAAO,aAAa,CAAC;IACnC,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { Hono } from 'hono';
2
+ import type { RuntimeState } from '../state.js';
3
+ /**
4
+ * /healthz — liveness. No dependencies: answers 200 whenever the event loop
5
+ * runs, so orchestrators never restart a replica that is merely waiting on
6
+ * the database.
7
+ *
8
+ * /readyz — readiness. 503 until env is parsed, migrations are applied (or
9
+ * confirmed current), and the DB is reachable; 503 again while draining; and
10
+ * 503 whenever the backing store stops being writable.
11
+ *
12
+ * That last clause is the whole point of `probeStorage`. Readiness used to be
13
+ * a boot-time boolean, so the storage probe ran exactly once, at startup: an
14
+ * instance whose /data volume was emptied, unmounted or turned read-only
15
+ * after boot — the state a failed restore leaves behind — kept answering 200
16
+ * and kept taking traffic it could not serve. Readiness has to be a live
17
+ * claim about the dependencies, not a memory of them.
18
+ */
19
+ export interface HealthDeps {
20
+ /** Re-probe the backing store. Must throw when it is not writable. */
21
+ probeStorage?: () => Promise<void>;
22
+ /** How long a SUCCESSFUL probe is trusted before it re-runs. */
23
+ storageProbeTtlMs?: number;
24
+ /** Called with the probe failure so it lands in the logs. */
25
+ onStorageFailure?: (err: unknown) => void;
26
+ /** Injectable clock (tests). */
27
+ now?: () => number;
28
+ }
29
+ export declare function healthRoutes(state: RuntimeState, deps?: HealthDeps): Hono;
30
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AASD,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,GAAE,UAAe,GAAG,IAAI,CAyC7E"}
@@ -0,0 +1,54 @@
1
+ import { Hono } from 'hono';
2
+ /**
3
+ * Successes are cached briefly so a fast readiness poll does not become a
4
+ * PUT+DELETE per second against S3. Failures are NEVER cached: the next
5
+ * request re-probes, so recovery is observed immediately.
6
+ */
7
+ const DEFAULT_STORAGE_PROBE_TTL_MS = 10_000;
8
+ export function healthRoutes(state, deps = {}) {
9
+ const app = new Hono();
10
+ const { probeStorage, onStorageFailure } = deps;
11
+ const ttlMs = deps.storageProbeTtlMs ?? DEFAULT_STORAGE_PROBE_TTL_MS;
12
+ const now = deps.now ?? (() => Date.now());
13
+ let trustedUntil = 0;
14
+ let inflight = null;
15
+ /** Resolves to the failure, or null when storage is reachable. */
16
+ function checkStorage() {
17
+ if (!probeStorage)
18
+ return Promise.resolve(null);
19
+ if (now() < trustedUntil)
20
+ return Promise.resolve(null);
21
+ // One probe at a time: a burst of readiness polls must not fan out into a
22
+ // burst of writes against the store.
23
+ const pending = (inflight ??= (async () => {
24
+ try {
25
+ await probeStorage();
26
+ trustedUntil = now() + ttlMs;
27
+ return null;
28
+ }
29
+ catch (err) {
30
+ trustedUntil = 0;
31
+ onStorageFailure?.(err);
32
+ return err ?? new Error('storage probe failed');
33
+ }
34
+ finally {
35
+ inflight = null;
36
+ }
37
+ })());
38
+ return pending;
39
+ }
40
+ app.get('/healthz', (c) => c.json({ status: 'ok' }));
41
+ app.get('/readyz', async (c) => {
42
+ if (state.draining)
43
+ return c.json({ status: 'unavailable', reason: 'draining' }, 503);
44
+ if (!state.ready)
45
+ return c.json({ status: 'unavailable', reason: state.reason }, 503);
46
+ // The reason stays coarse on purpose: /readyz is unauthenticated and a
47
+ // driver's error text carries bucket names and filesystem paths.
48
+ if (await checkStorage())
49
+ return c.json({ status: 'unavailable', reason: 'storage' }, 503);
50
+ return c.json({ status: 'ready' });
51
+ });
52
+ return app;
53
+ }
54
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AA8B5B;;;;GAIG;AACH,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAE5C,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,OAAmB,EAAE;IACrE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,IAAI,4BAA4B,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAE3C,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,QAAQ,GAA4B,IAAI,CAAC;IAE7C,kEAAkE;IAClE,SAAS,YAAY;QACnB,IAAI,CAAC,YAAY;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,GAAG,EAAE,GAAG,YAAY;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvD,0EAA0E;QAC1E,qCAAqC;QACrC,MAAM,OAAO,GAAG,CAAC,QAAQ,KAAK,CAAC,KAAK,IAAI,EAAE;YACxC,IAAI,CAAC;gBACH,MAAM,YAAY,EAAE,CAAC;gBACrB,YAAY,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;gBAC7B,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,YAAY,GAAG,CAAC,CAAC;gBACjB,gBAAgB,EAAE,CAAC,GAAG,CAAC,CAAC;gBACxB,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAClD,CAAC;oBAAS,CAAC;gBACT,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,CAAC;QACN,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,IAAI,KAAK,CAAC,QAAQ;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC;QACtF,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;QACtF,uEAAuE;QACvE,iEAAiE;QACjE,IAAI,MAAM,YAAY,EAAE;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3F,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { healthRoutes } from './health.js';
2
+ export { wellKnownRoutes } from './wellknown.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { healthRoutes } from './health.js';
2
+ export { wellKnownRoutes } from './wellknown.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Hono } from 'hono';
2
+ import { type Auth } from '../identity/better-auth.js';
3
+ export interface WellKnownDeps {
4
+ auth: Auth;
5
+ publicBaseUrl: string;
6
+ instanceName?: string;
7
+ /** The tool's OAuth scope list, as registered with the provider: what `scopes_supported` advertises. */
8
+ oauthScopes: readonly string[];
9
+ }
10
+ export declare function wellKnownRoutes({ auth, publicBaseUrl, oauthScopes }: WellKnownDeps): Hono;
11
+ //# sourceMappingURL=wellknown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wellknown.d.ts","sourceRoot":"","sources":["../../src/routes/wellknown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAK1C,OAAO,EAAkB,KAAK,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAoBvE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wGAAwG;IACxG,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,EAAE,aAAa,GAAG,IAAI,CAiCzF"}
@@ -0,0 +1,45 @@
1
+ import { Hono } from 'hono';
2
+ import { oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata } from '@better-auth/oauth-provider';
3
+ import { mcpResourceUrl } from '../identity/better-auth.js';
4
+ /**
5
+ * Root-level OAuth discovery surface.
6
+ *
7
+ * The oauthProvider plugin serves RFC 8414 / OIDC discovery under the
8
+ * /api/v1/auth base path, but clients resolve discovery from the ISSUER (the
9
+ * bare origin — jwt.issuer in identity/better-auth.ts), so the same documents
10
+ * must exist at the origin root. RFC 9728 protected-resource metadata is ours:
11
+ * it points the 401-challenged MCP client at this same origin as its
12
+ * authorization server. All documents are public by design and fetched
13
+ * cross-origin by browser-based MCP hosts — wide-open CORS is correct.
14
+ */
15
+ const CORS_HEADERS = {
16
+ 'Access-Control-Allow-Origin': '*',
17
+ 'Access-Control-Allow-Methods': 'GET, OPTIONS',
18
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization, mcp-protocol-version',
19
+ 'Access-Control-Max-Age': '86400'
20
+ };
21
+ export function wellKnownRoutes({ auth, publicBaseUrl, oauthScopes }) {
22
+ const app = new Hono();
23
+ const asMetadata = oauthProviderAuthServerMetadata(auth, {
24
+ headers: { ...CORS_HEADERS, 'Cache-Control': 'public, max-age=3600' }
25
+ });
26
+ const oidcMetadata = oauthProviderOpenIdConfigMetadata(auth, {
27
+ headers: { ...CORS_HEADERS, 'Cache-Control': 'public, max-age=3600' }
28
+ });
29
+ app.get('/.well-known/oauth-authorization-server', (c) => asMetadata(c.req.raw));
30
+ app.get('/.well-known/openid-configuration', (c) => oidcMetadata(c.req.raw));
31
+ // RFC 9728: served at the origin level AND at the path-aware derivation
32
+ // (clients insert /.well-known/oauth-protected-resource between origin and
33
+ // the resource path /mcp) — both return the same document.
34
+ const protectedResource = (c) => c.json({
35
+ resource: mcpResourceUrl(publicBaseUrl),
36
+ authorization_servers: [publicBaseUrl],
37
+ scopes_supported: [...oauthScopes],
38
+ bearer_methods_supported: ['header']
39
+ }, 200, { ...CORS_HEADERS, 'Cache-Control': 'public, max-age=3600' });
40
+ app.get('/.well-known/oauth-protected-resource', (c) => protectedResource(c));
41
+ app.get('/.well-known/oauth-protected-resource/mcp', (c) => protectedResource(c));
42
+ app.options('/.well-known/*', (c) => c.body(null, 204, { ...CORS_HEADERS }));
43
+ return app;
44
+ }
45
+ //# sourceMappingURL=wellknown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wellknown.js","sourceRoot":"","sources":["../../src/routes/wellknown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,+BAA+B,EAC/B,iCAAiC,EAClC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAa,MAAM,4BAA4B,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,MAAM,YAAY,GAAG;IACnB,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,cAAc;IAC9C,8BAA8B,EAAE,mDAAmD;IACnF,wBAAwB,EAAE,OAAO;CACzB,CAAC;AAUX,MAAM,UAAU,eAAe,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAiB;IACjF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,MAAM,UAAU,GAAG,+BAA+B,CAAC,IAAI,EAAE;QACvD,OAAO,EAAE,EAAE,GAAG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE;KACtE,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,iCAAiC,CAAC,IAAI,EAAE;QAC3D,OAAO,EAAE,EAAE,GAAG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE;KACtE,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,yCAAyC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACjF,GAAG,CAAC,GAAG,CAAC,mCAAmC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAE7E,wEAAwE;IACxE,2EAA2E;IAC3E,2DAA2D;IAC3D,MAAM,iBAAiB,GAAG,CAAC,CAAU,EAAE,EAAE,CACvC,CAAC,CAAC,IAAI,CACJ;QACE,QAAQ,EAAE,cAAc,CAAC,aAAa,CAAC;QACvC,qBAAqB,EAAE,CAAC,aAAa,CAAC;QACtC,gBAAgB,EAAE,CAAC,GAAG,WAAW,CAAC;QAClC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACrC,EACD,GAAG,EACH,EAAE,GAAG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAC7D,CAAC;IACJ,GAAG,CAAC,GAAG,CAAC,uCAAuC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,GAAG,CAAC,GAAG,CAAC,2CAA2C,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAElF,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC;IAE7E,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { Logger } from './logger.js';
2
+ /**
3
+ * Resolve the auth secret: prefer AUTH_SECRET from the environment; otherwise
4
+ * persist a generated one under DATA_DIR (n8n-style zero-config first run).
5
+ * The file is written 0600 and reused on every subsequent boot, so sessions
6
+ * survive restarts even when the operator never set a secret.
7
+ */
8
+ export declare function resolveAuthSecret(envSecret: string | undefined, dataDir: string, log: Logger): Promise<string>;
9
+ /** Where a boot-generated setup token lives until the instance is claimed. */
10
+ export declare function generatedSetupTokenPath(dataDir: string): string;
11
+ /**
12
+ * The credential POST /api/v1/setup REQUIRES (PRDCT-1347, audit A7). The
13
+ * first-boot claim decides who owns the instance, so it can never be free:
14
+ *
15
+ * - `SETUP_TOKEN` set → that is the token (setup.sh writes one);
16
+ * - instance already set up → nothing to claim, no token needed (null);
17
+ * - otherwise → a token is generated ONCE into `$DATA_DIR/setup-token`
18
+ * (0600, atomic write, reused on every later boot until the claim) and
19
+ * printed to the container log, so the `docker run` / plain
20
+ * `docker compose up` paths — which never go through setup.sh — still
21
+ * produce an instance claimable only with a secret. The file is removed
22
+ * once setup completes (see clearGeneratedSetupToken).
23
+ *
24
+ * Optional-when-set was the hole: a minimal-env container answered the
25
+ * claim with 201 and no credential at all.
26
+ */
27
+ export declare function resolveSetupToken(envToken: string | undefined, dataDir: string, alreadySetUp: boolean, log: Logger): Promise<string | null>;
28
+ /** Best-effort removal of the generated token once the claim has succeeded. */
29
+ export declare function clearGeneratedSetupToken(dataDir: string): Promise<void>;
30
+ //# sourceMappingURL=secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret.d.ts","sourceRoot":"","sources":["../src/secret.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoCxB;AAED,+EAA+E;AAC/E,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7E"}
package/dist/secret.js ADDED
@@ -0,0 +1,97 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ /**
5
+ * Resolve the auth secret: prefer AUTH_SECRET from the environment; otherwise
6
+ * persist a generated one under DATA_DIR (n8n-style zero-config first run).
7
+ * The file is written 0600 and reused on every subsequent boot, so sessions
8
+ * survive restarts even when the operator never set a secret.
9
+ */
10
+ export async function resolveAuthSecret(envSecret, dataDir, log) {
11
+ if (envSecret)
12
+ return envSecret;
13
+ const secretPath = join(dataDir, 'secret');
14
+ try {
15
+ const existing = (await readFile(secretPath, 'utf8')).trim();
16
+ if (existing.length >= 32)
17
+ return existing;
18
+ log.warn({ secretPath }, 'existing secret file is too short — regenerating');
19
+ }
20
+ catch {
21
+ // no secret file yet
22
+ }
23
+ const secret = randomBytes(32).toString('hex');
24
+ await mkdir(dataDir, { recursive: true });
25
+ // Write + rename (same dir → atomic) so a crash mid-write never leaves a
26
+ // truncated secret that a later boot would accept and lock everyone out.
27
+ const tmpPath = join(dataDir, `.secret.${randomBytes(6).toString('hex')}.tmp`);
28
+ try {
29
+ await writeFile(tmpPath, secret + '\n', { mode: 0o600 });
30
+ await rename(tmpPath, secretPath);
31
+ }
32
+ catch (err) {
33
+ await rm(tmpPath, { force: true });
34
+ throw err;
35
+ }
36
+ log.warn({ secretPath }, 'AUTH_SECRET was not set — generated one into the data volume. ' +
37
+ 'Set AUTH_SECRET explicitly for multi-replica deployments; all replicas must share it.');
38
+ return secret;
39
+ }
40
+ /** Where a boot-generated setup token lives until the instance is claimed. */
41
+ export function generatedSetupTokenPath(dataDir) {
42
+ return join(dataDir, 'setup-token');
43
+ }
44
+ /**
45
+ * The credential POST /api/v1/setup REQUIRES (PRDCT-1347, audit A7). The
46
+ * first-boot claim decides who owns the instance, so it can never be free:
47
+ *
48
+ * - `SETUP_TOKEN` set → that is the token (setup.sh writes one);
49
+ * - instance already set up → nothing to claim, no token needed (null);
50
+ * - otherwise → a token is generated ONCE into `$DATA_DIR/setup-token`
51
+ * (0600, atomic write, reused on every later boot until the claim) and
52
+ * printed to the container log, so the `docker run` / plain
53
+ * `docker compose up` paths — which never go through setup.sh — still
54
+ * produce an instance claimable only with a secret. The file is removed
55
+ * once setup completes (see clearGeneratedSetupToken).
56
+ *
57
+ * Optional-when-set was the hole: a minimal-env container answered the
58
+ * claim with 201 and no credential at all.
59
+ */
60
+ export async function resolveSetupToken(envToken, dataDir, alreadySetUp, log) {
61
+ if (envToken)
62
+ return envToken;
63
+ if (alreadySetUp)
64
+ return null;
65
+ const tokenPath = generatedSetupTokenPath(dataDir);
66
+ try {
67
+ const existing = (await readFile(tokenPath, 'utf8')).trim();
68
+ if (existing.length >= 16) {
69
+ log.warn({ tokenPath }, `SETUP_TOKEN is not set — the setup wizard requires the token generated at first boot: ${existing}`);
70
+ return existing;
71
+ }
72
+ log.warn({ tokenPath }, 'existing setup-token file is too short — regenerating');
73
+ }
74
+ catch {
75
+ // no token file yet
76
+ }
77
+ const token = randomBytes(16).toString('hex');
78
+ await mkdir(dataDir, { recursive: true });
79
+ const tmpPath = join(dataDir, `.setup-token.${randomBytes(6).toString('hex')}.tmp`);
80
+ try {
81
+ await writeFile(tmpPath, token + '\n', { mode: 0o600 });
82
+ await rename(tmpPath, tokenPath);
83
+ }
84
+ catch (err) {
85
+ await rm(tmpPath, { force: true });
86
+ throw err;
87
+ }
88
+ log.warn({ tokenPath }, 'SETUP_TOKEN was not set — generated one for the first-boot setup wizard. ' +
89
+ `Use this token to claim the instance: ${token} ` +
90
+ '(also readable inside the container at that path; set SETUP_TOKEN explicitly to choose your own)');
91
+ return token;
92
+ }
93
+ /** Best-effort removal of the generated token once the claim has succeeded. */
94
+ export async function clearGeneratedSetupToken(dataDir) {
95
+ await rm(generatedSetupTokenPath(dataDir), { force: true });
96
+ }
97
+ //# sourceMappingURL=secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret.js","sourceRoot":"","sources":["../src/secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAA6B,EAC7B,OAAe,EACf,GAAW;IAEX,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7D,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE;YAAE,OAAO,QAAQ,CAAC;QAC3C,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,kDAAkD,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnC,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,GAAG,CAAC,IAAI,CACN,EAAE,UAAU,EAAE,EACd,gEAAgE;QAC9D,uFAAuF,CAC1F,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,OAAO,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAA4B,EAC5B,OAAe,EACf,YAAqB,EACrB,GAAW;IAEX,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,YAAY;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,SAAS,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CACN,EAAE,SAAS,EAAE,EACb,yFAAyF,QAAQ,EAAE,CACpG,CAAC;YACF,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,uDAAuD,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,oBAAoB;IACtB,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,gBAAgB,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpF,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnC,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,GAAG,CAAC,IAAI,CACN,EAAE,SAAS,EAAE,EACb,2EAA2E;QACzE,yCAAyC,KAAK,IAAI;QAClD,kGAAkG,CACrG,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAe;IAC5D,MAAM,EAAE,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Transport guard for the one-shot first-boot wizard (PLT-10).
3
+ *
4
+ * `POST /api/v1/setup` carries the owner's password and the setup token. Over
5
+ * plaintext HTTP to a non-loopback origin both cross the network in the clear
6
+ * — and this is the single request that decides who owns the instance. The
7
+ * documented no-domain install path used to walk operators straight into
8
+ * exactly that, so the server refuses instead of trusting the runbook.
9
+ *
10
+ * Loopback is fine: nothing leaves the host, which is what makes the
11
+ * `ssh -L` tunnel a legitimate way to finish setup on a server with no TLS
12
+ * yet. `https` is fine anywhere. Everything else needs the conscious
13
+ * `ALLOW_INSECURE_SETUP=true` opt-in.
14
+ */
15
+ export declare function isSecureSetupOrigin(publicBaseUrl: string): boolean;
16
+ /**
17
+ * `URL.hostname` KEEPS the brackets around an IPv6 literal (`[::1]`), so they
18
+ * are stripped here. IPv4 loopback is the whole 127.0.0.0/8 block, not just
19
+ * 127.0.0.1. Exported for the demo sign-in's host rule
20
+ * (identity/demo-pass-rules.ts): one loopback test for the whole server.
21
+ */
22
+ export declare function isLoopbackHost(hostname: string): boolean;
23
+ //# sourceMappingURL=setup-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-transport.d.ts","sourceRoot":"","sources":["../src/setup-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAWlE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAYxD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Transport guard for the one-shot first-boot wizard (PLT-10).
3
+ *
4
+ * `POST /api/v1/setup` carries the owner's password and the setup token. Over
5
+ * plaintext HTTP to a non-loopback origin both cross the network in the clear
6
+ * — and this is the single request that decides who owns the instance. The
7
+ * documented no-domain install path used to walk operators straight into
8
+ * exactly that, so the server refuses instead of trusting the runbook.
9
+ *
10
+ * Loopback is fine: nothing leaves the host, which is what makes the
11
+ * `ssh -L` tunnel a legitimate way to finish setup on a server with no TLS
12
+ * yet. `https` is fine anywhere. Everything else needs the conscious
13
+ * `ALLOW_INSECURE_SETUP=true` opt-in.
14
+ */
15
+ export function isSecureSetupOrigin(publicBaseUrl) {
16
+ let url;
17
+ try {
18
+ url = new URL(publicBaseUrl);
19
+ }
20
+ catch {
21
+ // Unparseable never reaches here (the env schema validates a URL), and a
22
+ // guard that cannot read the origin must fail closed.
23
+ return false;
24
+ }
25
+ if (url.protocol === 'https:')
26
+ return true;
27
+ return isLoopbackHost(url.hostname);
28
+ }
29
+ /**
30
+ * `URL.hostname` KEEPS the brackets around an IPv6 literal (`[::1]`), so they
31
+ * are stripped here. IPv4 loopback is the whole 127.0.0.0/8 block, not just
32
+ * 127.0.0.1. Exported for the demo sign-in's host rule
33
+ * (identity/demo-pass-rules.ts): one loopback test for the whole server.
34
+ */
35
+ export function isLoopbackHost(hostname) {
36
+ let host = hostname.toLowerCase();
37
+ if (host.startsWith('[') && host.endsWith(']'))
38
+ host = host.slice(1, -1);
39
+ if (host === 'localhost' || host.endsWith('.localhost'))
40
+ return true;
41
+ if (host === '::1' || host === '0:0:0:0:0:0:0:1')
42
+ return true;
43
+ const v4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
44
+ if (v4) {
45
+ const octets = v4.slice(1).map(Number);
46
+ if (octets.some((o) => o > 255))
47
+ return false;
48
+ return octets[0] === 127;
49
+ }
50
+ return false;
51
+ }
52
+ //# sourceMappingURL=setup-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-transport.js","sourceRoot":"","sources":["../src/setup-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CAAC,aAAqB;IACvD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,sDAAsD;QACtD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzE,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAC9D,MAAM,EAAE,GAAG,8CAA8C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrE,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC9C,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}