@bevel-software/platform-core-backend 0.20.0 → 0.21.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 (576) hide show
  1. package/dist/core/catalog-cache-invalidation.d.ts +7 -2
  2. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
  3. package/dist/core/catalog-cache-invalidation.js +8 -9
  4. package/dist/core/catalog-cache-invalidation.js.map +1 -1
  5. package/dist/core/core-ports.d.ts +19 -0
  6. package/dist/core/core-ports.d.ts.map +1 -1
  7. package/dist/core/core-ports.js.map +1 -1
  8. package/dist/core/create-core-server.d.ts +2 -0
  9. package/dist/core/create-core-server.d.ts.map +1 -1
  10. package/dist/core/create-core-server.js +23 -105
  11. package/dist/core/create-core-server.js.map +1 -1
  12. package/dist/core/create-core-services.d.ts +30 -5
  13. package/dist/core/create-core-services.d.ts.map +1 -1
  14. package/dist/core/create-core-services.js +136 -81
  15. package/dist/core/create-core-services.js.map +1 -1
  16. package/dist/core/lifecycle.d.ts +74 -28
  17. package/dist/core/lifecycle.d.ts.map +1 -1
  18. package/dist/core/lifecycle.js +157 -20
  19. package/dist/core/lifecycle.js.map +1 -1
  20. package/dist/core/public-config.d.ts +5 -1
  21. package/dist/core/public-config.d.ts.map +1 -1
  22. package/dist/core/public-config.js +7 -5
  23. package/dist/core/public-config.js.map +1 -1
  24. package/dist/core-config.d.ts +95 -1
  25. package/dist/core-config.d.ts.map +1 -1
  26. package/dist/core-config.js +24 -8
  27. package/dist/core-config.js.map +1 -1
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +6 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/modules/access/access-control.service.d.ts +18 -1
  33. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  34. package/dist/modules/access/access-control.service.js +19 -8
  35. package/dist/modules/access/access-control.service.js.map +1 -1
  36. package/dist/modules/access/access.routes.d.ts +2 -1
  37. package/dist/modules/access/access.routes.d.ts.map +1 -1
  38. package/dist/modules/access/access.routes.js +10 -10
  39. package/dist/modules/access/access.routes.js.map +1 -1
  40. package/dist/modules/access/change-read-gate.d.ts +6 -3
  41. package/dist/modules/access/change-read-gate.d.ts.map +1 -1
  42. package/dist/modules/access/change-read-gate.js +9 -6
  43. package/dist/modules/access/change-read-gate.js.map +1 -1
  44. package/dist/modules/access/creator-access.d.ts +4 -2
  45. package/dist/modules/access/creator-access.d.ts.map +1 -1
  46. package/dist/modules/access/creator-access.js +7 -4
  47. package/dist/modules/access/creator-access.js.map +1 -1
  48. package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
  49. package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
  50. package/dist/modules/agent-instructions/read-preamble.js +6 -9
  51. package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
  52. package/dist/modules/auth/account-admission.d.ts +40 -0
  53. package/dist/modules/auth/account-admission.d.ts.map +1 -0
  54. package/dist/modules/auth/account-admission.js +17 -0
  55. package/dist/modules/auth/account-admission.js.map +1 -0
  56. package/dist/modules/auth/account.routes.d.ts.map +1 -1
  57. package/dist/modules/auth/account.routes.js +4 -1
  58. package/dist/modules/auth/account.routes.js.map +1 -1
  59. package/dist/modules/auth/auth.service.d.ts +19 -1
  60. package/dist/modules/auth/auth.service.d.ts.map +1 -1
  61. package/dist/modules/auth/auth.service.js +33 -1
  62. package/dist/modules/auth/auth.service.js.map +1 -1
  63. package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
  64. package/dist/modules/auth/oidc-auth-provider.js +9 -0
  65. package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
  66. package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
  67. package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
  68. package/dist/modules/connection-probe/connection-probe.service.js +10 -2
  69. package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
  70. package/dist/modules/database/advisory-lock.d.ts +17 -0
  71. package/dist/modules/database/advisory-lock.d.ts.map +1 -1
  72. package/dist/modules/database/advisory-lock.js +24 -3
  73. package/dist/modules/database/advisory-lock.js.map +1 -1
  74. package/dist/modules/database/connection.d.ts +67 -2
  75. package/dist/modules/database/connection.d.ts.map +1 -1
  76. package/dist/modules/database/connection.js +118 -12
  77. package/dist/modules/database/connection.js.map +1 -1
  78. package/dist/modules/database/migrate.d.ts +1 -1
  79. package/dist/modules/database/migrate.d.ts.map +1 -1
  80. package/dist/modules/database/migrate.js +27 -3
  81. package/dist/modules/database/migrate.js.map +1 -1
  82. package/dist/modules/kb-fs/branch-name.d.ts +0 -1
  83. package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
  84. package/dist/modules/kb-fs/branch-name.js +3 -3
  85. package/dist/modules/kb-fs/branch-name.js.map +1 -1
  86. package/dist/modules/kb-fs/clone-config.d.ts +9 -8
  87. package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
  88. package/dist/modules/kb-fs/clone-config.js +14 -12
  89. package/dist/modules/kb-fs/clone-config.js.map +1 -1
  90. package/dist/modules/mcp/mcp.service.d.ts +7 -0
  91. package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
  92. package/dist/modules/mcp/mcp.service.js +4 -4
  93. package/dist/modules/mcp/mcp.service.js.map +1 -1
  94. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
  95. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
  96. package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
  97. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
  98. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
  99. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
  100. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
  101. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
  102. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
  103. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
  104. package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
  105. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
  106. package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
  107. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
  108. package/dist/modules/plugins/discovery/native.source.js +4 -2
  109. package/dist/modules/plugins/discovery/native.source.js.map +1 -1
  110. package/dist/modules/plugins/index.d.ts +1 -1
  111. package/dist/modules/plugins/index.d.ts.map +1 -1
  112. package/dist/modules/plugins/index.js +1 -1
  113. package/dist/modules/plugins/index.js.map +1 -1
  114. package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
  115. package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
  116. package/dist/modules/plugins/join-request-jobs.service.js +6 -6
  117. package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
  118. package/dist/modules/plugins/join-requests.service.d.ts +3 -1
  119. package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
  120. package/dist/modules/plugins/join-requests.service.js +9 -8
  121. package/dist/modules/plugins/join-requests.service.js.map +1 -1
  122. package/dist/modules/plugins/plugin-links.d.ts +65 -10
  123. package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
  124. package/dist/modules/plugins/plugin-links.js +136 -31
  125. package/dist/modules/plugins/plugin-links.js.map +1 -1
  126. package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
  127. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
  128. package/dist/modules/plugins/plugin-links.service.js +151 -21
  129. package/dist/modules/plugins/plugin-links.service.js.map +1 -1
  130. package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
  131. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  132. package/dist/modules/plugins/plugin-provision.service.js +33 -26
  133. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  134. package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
  135. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
  136. package/dist/modules/plugins/plugin-rename.service.js +10 -12
  137. package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
  138. package/dist/modules/plugins/plugins.routes.d.ts +3 -0
  139. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  140. package/dist/modules/plugins/plugins.routes.js +45 -15
  141. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  142. package/dist/modules/plugins/plugins.service.d.ts +4 -4
  143. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  144. package/dist/modules/plugins/plugins.service.js +7 -10
  145. package/dist/modules/plugins/plugins.service.js.map +1 -1
  146. package/dist/modules/plugins/teams.routes.d.ts +4 -1
  147. package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
  148. package/dist/modules/plugins/teams.routes.js +11 -9
  149. package/dist/modules/plugins/teams.routes.js.map +1 -1
  150. package/dist/modules/secrets-vault/index.d.ts +1 -1
  151. package/dist/modules/secrets-vault/index.d.ts.map +1 -1
  152. package/dist/modules/secrets-vault/index.js +1 -1
  153. package/dist/modules/secrets-vault/index.js.map +1 -1
  154. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
  155. package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
  156. package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
  157. package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
  158. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
  159. package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
  160. package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
  161. package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
  162. package/dist/modules/settings/deployment-settings.service.d.ts +12 -8
  163. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  164. package/dist/modules/settings/deployment-settings.service.js +20 -22
  165. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  166. package/dist/modules/settings/setup.routes.d.ts +9 -2
  167. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  168. package/dist/modules/settings/setup.routes.js +20 -14
  169. package/dist/modules/settings/setup.routes.js.map +1 -1
  170. package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
  171. package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
  172. package/dist/modules/skills/allowed-tools-check.js +8 -8
  173. package/dist/modules/skills/allowed-tools-check.js.map +1 -1
  174. package/dist/modules/skills/pending-skills.service.d.ts +3 -1
  175. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  176. package/dist/modules/skills/pending-skills.service.js +9 -6
  177. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  178. package/dist/modules/skills/skill-access-requests.routes.d.ts +2 -1
  179. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
  180. package/dist/modules/skills/skill-access-requests.routes.js +6 -6
  181. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
  182. package/dist/modules/skills/skills.routes.d.ts +4 -1
  183. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  184. package/dist/modules/skills/skills.routes.js +4 -4
  185. package/dist/modules/skills/skills.routes.js.map +1 -1
  186. package/dist/modules/skills/skills.service.d.ts +4 -2
  187. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  188. package/dist/modules/skills/skills.service.js +13 -11
  189. package/dist/modules/skills/skills.service.js.map +1 -1
  190. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
  191. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  192. package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
  193. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  194. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
  195. package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
  196. package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
  197. package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
  198. package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
  199. package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
  200. package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
  201. package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
  202. package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
  203. package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
  204. package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
  205. package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
  206. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
  207. package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
  208. package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
  209. package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
  210. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
  211. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  212. package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
  213. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  214. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
  215. package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
  216. package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
  217. package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
  218. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
  219. package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
  220. package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -9
  221. package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
  222. package/dist/modules/workflow/git/git.service.d.ts +11 -5
  223. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  224. package/dist/modules/workflow/git/git.service.js +23 -14
  225. package/dist/modules/workflow/git/git.service.js.map +1 -1
  226. package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
  227. package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
  228. package/dist/modules/workflow/git/node-git-runner.js +35 -5
  229. package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
  230. package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
  231. package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
  232. package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
  233. package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
  234. package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
  235. package/dist/modules/workflow/session-ontology.service.js +6 -2
  236. package/dist/modules/workflow/session-ontology.service.js.map +1 -1
  237. package/dist/modules/workflow/workflow.service.d.ts +8 -3
  238. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  239. package/dist/modules/workflow/workflow.service.js +33 -23
  240. package/dist/modules/workflow/workflow.service.js.map +1 -1
  241. package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
  242. package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
  243. package/dist/modules/workspace/session-ontology.gate.js +3 -3
  244. package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
  245. package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
  246. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
  247. package/dist/modules/workspace/startup/kb-git.js +15 -13
  248. package/dist/modules/workspace/startup/kb-git.js.map +1 -1
  249. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +5 -8
  250. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
  251. package/dist/modules/workspace/startup/kb-startup-runner.js +35 -38
  252. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
  253. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
  254. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
  255. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
  256. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
  257. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
  258. package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
  259. package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
  260. package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
  261. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
  262. package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
  263. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
  264. package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
  265. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
  266. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
  267. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
  268. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
  269. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
  270. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  271. package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
  272. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  273. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
  274. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  275. package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
  276. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  277. package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
  278. package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
  279. package/dist/modules/workspace/startup/steps/template-source.js +10 -6
  280. package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
  281. package/dist/modules/workspace/workspace.routes.d.ts +2 -1
  282. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  283. package/dist/modules/workspace/workspace.routes.js +8 -7
  284. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  285. package/dist/modules/workspace/workspace.service.d.ts +18 -12
  286. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  287. package/dist/modules/workspace/workspace.service.js +32 -28
  288. package/dist/modules/workspace/workspace.service.js.map +1 -1
  289. package/dist/modules/workspace/workspace.tools.d.ts +2 -1
  290. package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
  291. package/dist/modules/workspace/workspace.tools.js +20 -18
  292. package/dist/modules/workspace/workspace.tools.js.map +1 -1
  293. package/dist/modules/workspace/write-denial.d.ts +3 -2
  294. package/dist/modules/workspace/write-denial.d.ts.map +1 -1
  295. package/dist/modules/workspace/write-denial.js +6 -5
  296. package/dist/modules/workspace/write-denial.js.map +1 -1
  297. package/dist/shared/git.contract.d.ts +52 -7
  298. package/dist/shared/git.contract.d.ts.map +1 -1
  299. package/dist/shared/git.contract.js +30 -8
  300. package/dist/shared/git.contract.js.map +1 -1
  301. package/dist/shared/kb-context.d.ts +76 -0
  302. package/dist/shared/kb-context.d.ts.map +1 -0
  303. package/dist/shared/kb-context.js +108 -0
  304. package/dist/shared/kb-context.js.map +1 -0
  305. package/dist/shared/kb-layout.d.ts +3 -2
  306. package/dist/shared/kb-layout.d.ts.map +1 -1
  307. package/dist/shared/kb-layout.js +4 -3
  308. package/dist/shared/kb-layout.js.map +1 -1
  309. package/dist/shared/kb-layout.test.js +35 -27
  310. package/dist/shared/kb-layout.test.js.map +1 -1
  311. package/dist/shared/pending-proposals.d.ts +4 -1
  312. package/dist/shared/pending-proposals.d.ts.map +1 -1
  313. package/dist/shared/pending-proposals.js +3 -4
  314. package/dist/shared/pending-proposals.js.map +1 -1
  315. package/dist/shared/redact-secret.d.ts +5 -5
  316. package/dist/shared/redact-secret.js +5 -5
  317. package/dist/tenancy/index.d.ts +13 -0
  318. package/dist/tenancy/index.d.ts.map +1 -0
  319. package/dist/tenancy/index.js +13 -0
  320. package/dist/tenancy/index.js.map +1 -0
  321. package/dist/tenancy/static-tenant-source.d.ts +98 -0
  322. package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
  323. package/dist/tenancy/static-tenant-source.js +220 -0
  324. package/dist/tenancy/static-tenant-source.js.map +1 -0
  325. package/dist/tenancy/tenant-host.d.ts +80 -0
  326. package/dist/tenancy/tenant-host.d.ts.map +1 -0
  327. package/dist/tenancy/tenant-host.js +217 -0
  328. package/dist/tenancy/tenant-host.js.map +1 -0
  329. package/dist/tenancy/tenant-runtime.d.ts +91 -0
  330. package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
  331. package/dist/tenancy/tenant-runtime.js +174 -0
  332. package/dist/tenancy/tenant-runtime.js.map +1 -0
  333. package/dist/tenancy/tenant-secrets.d.ts +24 -0
  334. package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
  335. package/dist/tenancy/tenant-secrets.js +30 -0
  336. package/dist/tenancy/tenant-secrets.js.map +1 -0
  337. package/dist/tenancy/tenant-source.contract.d.ts +45 -0
  338. package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
  339. package/dist/tenancy/tenant-source.contract.js +21 -0
  340. package/dist/tenancy/tenant-source.contract.js.map +1 -0
  341. package/migrations/0000_core_init.sql +14 -14
  342. package/migrations/0003_deployment_settings.sql +1 -1
  343. package/migrations/0005_github_facade.sql +1 -1
  344. package/migrations/0012_agent_audit.sql +6 -6
  345. package/package.json +3 -3
  346. package/src/__tests__/branch-model.test.ts +7 -6
  347. package/src/__tests__/kb-context.ts +30 -0
  348. package/src/__tests__/kb-layout-config.test.ts +35 -30
  349. package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
  350. package/src/core/__tests__/lifecycle.test.ts +78 -1
  351. package/src/core/__tests__/public-config.test.ts +5 -1
  352. package/src/core/catalog-cache-invalidation.ts +16 -11
  353. package/src/core/core-ports.ts +19 -0
  354. package/src/core/create-core-server.ts +27 -106
  355. package/src/core/create-core-services.ts +180 -95
  356. package/src/core/lifecycle.ts +214 -29
  357. package/src/core/public-config.ts +8 -5
  358. package/src/core-config.ts +107 -8
  359. package/src/index.ts +25 -2
  360. package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
  361. package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
  362. package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
  363. package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
  364. package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
  365. package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
  366. package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
  367. package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
  368. package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
  369. package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
  370. package/src/modules/access/__tests__/creator-access.test.ts +3 -2
  371. package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
  372. package/src/modules/access/access-control.service.ts +20 -6
  373. package/src/modules/access/access.routes.ts +10 -13
  374. package/src/modules/access/change-read-gate.ts +10 -4
  375. package/src/modules/access/creator-access.ts +7 -2
  376. package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
  377. package/src/modules/agent-instructions/read-preamble.ts +10 -12
  378. package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
  379. package/src/modules/auth/__tests__/auth.service.test.ts +60 -0
  380. package/src/modules/auth/account-admission.ts +44 -0
  381. package/src/modules/auth/account.routes.ts +4 -1
  382. package/src/modules/auth/auth.service.ts +33 -1
  383. package/src/modules/auth/oidc-auth-provider.ts +9 -0
  384. package/src/modules/connection-probe/connection-probe.service.ts +7 -1
  385. package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
  386. package/src/modules/database/__tests__/connection.test.ts +98 -0
  387. package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
  388. package/src/modules/database/advisory-lock.ts +28 -4
  389. package/src/modules/database/connection.ts +143 -13
  390. package/src/modules/database/migrate.ts +48 -14
  391. package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
  392. package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
  393. package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
  394. package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
  395. package/src/modules/kb-fs/branch-name.ts +3 -3
  396. package/src/modules/kb-fs/clone-config.ts +15 -12
  397. package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
  398. package/src/modules/mcp/mcp.service.ts +11 -4
  399. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
  400. package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
  401. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
  402. package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
  403. package/src/modules/plugins/__tests__/join-requests.service.test.ts +2 -1
  404. package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
  405. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
  406. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
  407. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
  408. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
  409. package/src/modules/plugins/__tests__/plugins.routes.test.ts +11 -2
  410. package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
  411. package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
  412. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
  413. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
  414. package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
  415. package/src/modules/plugins/discovery/native.source.ts +4 -1
  416. package/src/modules/plugins/index.ts +1 -1
  417. package/src/modules/plugins/join-request-jobs.service.ts +8 -7
  418. package/src/modules/plugins/join-requests.service.ts +7 -7
  419. package/src/modules/plugins/plugin-links.service.ts +192 -19
  420. package/src/modules/plugins/plugin-links.ts +147 -27
  421. package/src/modules/plugins/plugin-provision.service.ts +54 -27
  422. package/src/modules/plugins/plugin-rename.service.ts +10 -10
  423. package/src/modules/plugins/plugins.routes.ts +45 -15
  424. package/src/modules/plugins/plugins.service.ts +7 -11
  425. package/src/modules/plugins/teams.routes.ts +16 -8
  426. package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
  427. package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
  428. package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
  429. package/src/modules/secrets-vault/index.ts +2 -0
  430. package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
  431. package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
  432. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
  433. package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
  434. package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
  435. package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
  436. package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
  437. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
  438. package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
  439. package/src/modules/settings/deployment-settings.service.ts +21 -20
  440. package/src/modules/settings/setup.routes.ts +26 -16
  441. package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
  442. package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
  443. package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
  444. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +2 -1
  445. package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
  446. package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
  447. package/src/modules/skills/allowed-tools-check.ts +7 -6
  448. package/src/modules/skills/pending-skills.service.ts +9 -8
  449. package/src/modules/skills/skill-access-requests.routes.ts +7 -7
  450. package/src/modules/skills/skills.routes.ts +4 -3
  451. package/src/modules/skills/skills.service.ts +13 -9
  452. package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
  453. package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
  454. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
  455. package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
  456. package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
  457. package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
  458. package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
  459. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
  460. package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
  461. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
  462. package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
  463. package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
  464. package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
  465. package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
  466. package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
  467. package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
  468. package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
  469. package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
  470. package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
  471. package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
  472. package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
  473. package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
  474. package/src/modules/workflow/__tests__/apply-failure.test.ts +2 -1
  475. package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
  476. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
  477. package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
  478. package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
  479. package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
  480. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
  481. package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
  482. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +28 -27
  483. package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
  484. package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
  485. package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
  486. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
  487. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
  488. package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +2 -1
  489. package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +2 -1
  490. package/src/modules/workflow/agent-tools/workflow.tools.ts +11 -9
  491. package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
  492. package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
  493. package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
  494. package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
  495. package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
  496. package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
  497. package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
  498. package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
  499. package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
  500. package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
  501. package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
  502. package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
  503. package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
  504. package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
  505. package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
  506. package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
  507. package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
  508. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
  509. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +9 -8
  510. package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
  511. package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
  512. package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
  513. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
  514. package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
  515. package/src/modules/workflow/git/git.service.ts +24 -13
  516. package/src/modules/workflow/git/node-git-runner.ts +37 -4
  517. package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
  518. package/src/modules/workflow/session-ontology.service.ts +7 -2
  519. package/src/modules/workflow/workflow.service.ts +31 -24
  520. package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
  521. package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
  522. package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
  523. package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
  524. package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
  525. package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
  526. package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
  527. package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
  528. package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
  529. package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
  530. package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
  531. package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
  532. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
  533. package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
  534. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
  535. package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
  536. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
  537. package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
  538. package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +2 -1
  539. package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
  540. package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +4 -3
  541. package/src/modules/workspace/__tests__/workspace.tools.test.ts +9 -8
  542. package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
  543. package/src/modules/workspace/session-ontology.gate.ts +6 -4
  544. package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
  545. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +29 -21
  546. package/src/modules/workspace/startup/kb-git.ts +15 -22
  547. package/src/modules/workspace/startup/kb-startup-runner.ts +40 -46
  548. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
  549. package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
  550. package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
  551. package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
  552. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
  553. package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
  554. package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
  555. package/src/modules/workspace/startup/steps/template-source.ts +8 -5
  556. package/src/modules/workspace/workspace.routes.ts +8 -7
  557. package/src/modules/workspace/workspace.service.ts +30 -27
  558. package/src/modules/workspace/workspace.tools.ts +21 -20
  559. package/src/modules/workspace/write-denial.ts +7 -5
  560. package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
  561. package/src/shared/git.contract.ts +70 -8
  562. package/src/shared/kb-context.ts +130 -0
  563. package/src/shared/kb-layout.test.ts +37 -27
  564. package/src/shared/kb-layout.ts +4 -3
  565. package/src/shared/pending-proposals.ts +7 -4
  566. package/src/shared/redact-secret.ts +5 -5
  567. package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
  568. package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
  569. package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
  570. package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
  571. package/src/tenancy/index.ts +35 -0
  572. package/src/tenancy/static-tenant-source.ts +296 -0
  573. package/src/tenancy/tenant-host.ts +261 -0
  574. package/src/tenancy/tenant-runtime.ts +208 -0
  575. package/src/tenancy/tenant-secrets.ts +41 -0
  576. package/src/tenancy/tenant-source.contract.ts +59 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-tenant-source.d.ts","sourceRoot":"","sources":["../../src/tenancy/static-tenant-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,220 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { resolveDatabaseUrl } from '../core-config.js';
4
+ import { DEFAULT_DB_SCHEMA, assertSchemaName } from '../modules/database/connection.js';
5
+ import { DEFAULT_GIT_TIMEOUT_MS } from '../modules/workflow/git/node-git-runner.js';
6
+ import { defaultKbTemplateDir } from '../assets.js';
7
+ import { DEFAULT_GIT_USERNAME } from '../shared/git.contract.js';
8
+ import { deriveTenantSecrets } from './tenant-secrets.js';
9
+ import { loopbackTenantBaseUrl } from './tenant-host.js';
10
+ import { assertTenantSlug, normalizeHost } from './tenant-source.contract.js';
11
+ const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
12
+ const USERNAME_PATTERN = /^[A-Za-z0-9._-]+$/;
13
+ /**
14
+ * A tenant's {@link TenantConfig} from its record and the host's settings:
15
+ * the same values `CoreConfig` reads from the environment, resolved the same
16
+ * way, with the folders and the schema named after the slug so two tenants
17
+ * can never share a path or a table.
18
+ */
19
+ export function tenantConfigFrom(record, settings) {
20
+ const slug = assertTenantSlug(record.slug);
21
+ if (!Array.isArray(record.hosts) || record.hosts.length === 0) {
22
+ throw new Error(`Tenant "${slug}" names no host`);
23
+ }
24
+ const hosts = record.hosts.map(normalizeHost);
25
+ const adminEmail = (record.adminEmail ?? '').trim().toLowerCase();
26
+ if (!EMAIL_PATTERN.test(adminEmail)) {
27
+ throw new Error(`Tenant "${slug}": adminEmail is not a valid email: "${record.adminEmail ?? ''}"`);
28
+ }
29
+ const gitUsername = (record.gitUsername ?? DEFAULT_GIT_USERNAME).trim();
30
+ if (!USERNAME_PATTERN.test(gitUsername)) {
31
+ throw new Error(`Tenant "${slug}": gitUsername must match [A-Za-z0-9._-]+; got "${gitUsername}"`);
32
+ }
33
+ const tenantId = (record.tenantId ?? slug.replace(/-/g, '')).trim().toLowerCase();
34
+ if (!/^[a-z0-9]+$/.test(tenantId)) {
35
+ throw new Error(`Tenant "${slug}": tenantId must be lowercase alphanumeric; got "${tenantId}"`);
36
+ }
37
+ const dbSchema = assertSchemaName(record.dbSchema ?? `t_${slug.replace(/-/g, '_')}`);
38
+ // The default schema is where a single-tenant deployment on the same
39
+ // database keeps its tables and, in drizzle's own schema beside it, its
40
+ // migration ledger; a tenant there would be no tenant at all.
41
+ if (dbSchema === DEFAULT_DB_SCHEMA) {
42
+ throw new Error(`Tenant "${slug}": dbSchema must not be "${DEFAULT_DB_SCHEMA}"; a tenant needs a schema of its own`);
43
+ }
44
+ const adminPassword = record.adminPassword ?? '';
45
+ const loginPasswordEnabled = record.loginPassword ?? adminPassword !== '';
46
+ if (loginPasswordEnabled && !adminPassword) {
47
+ throw new Error(`Tenant "${slug}": loginPassword is on but no adminPassword is set`);
48
+ }
49
+ const publicBackendUrl = (record.publicBackendUrl ?? `https://${hosts[0]}`).trim().replace(/\/+$/, '');
50
+ const publicFrontendUrl = (record.publicFrontendUrl ?? publicBackendUrl).trim().replace(/\/+$/, '');
51
+ for (const [name, value] of [
52
+ ['publicBackendUrl', publicBackendUrl],
53
+ ['publicFrontendUrl', publicFrontendUrl],
54
+ ]) {
55
+ try {
56
+ new URL(value);
57
+ }
58
+ catch {
59
+ throw new Error(`Tenant "${slug}": ${name} is not a valid URL: "${value}"`);
60
+ }
61
+ }
62
+ const secrets = deriveTenantSecrets(settings.masterKey, slug);
63
+ const besideWorkspaces = (name) => path.resolve(settings.workspacesRoot, '..', name, slug);
64
+ const allowedEmailDomains = (record.allowedEmailDomains ?? [])
65
+ .map((d) => d.trim().toLowerCase().replace(/^[@.]+/, ''))
66
+ .filter((d) => d.length > 0);
67
+ const protectedBranches = Array.isArray(record.protectedBranches)
68
+ ? record.protectedBranches.join(',')
69
+ : (record.protectedBranches ?? '');
70
+ // The record's settings, as the environment a single-tenant deployment
71
+ // would pin them in: only what the record names, so the setup screen
72
+ // still collects the rest. Nothing of the host process's environment.
73
+ const settingsEnv = {};
74
+ for (const [name, value] of [
75
+ ['KB_REPO_URL', record.kbRepoUrl],
76
+ ['GIT_TOKEN', record.gitToken],
77
+ ['GIT_USERNAME', record.gitUsername],
78
+ ['KB_DIR_NAME', record.kbDirName],
79
+ ['DEFAULT_BRANCH', record.defaultBranch],
80
+ ['PROTECTED_BRANCHES', protectedBranches],
81
+ ['KB_SYNC_SECRET', record.kbSyncSecret],
82
+ ['OIDC_ISSUER_URL', record.oidc?.issuerUrl],
83
+ ['OIDC_CLIENT_ID', record.oidc?.clientId],
84
+ ['OIDC_CLIENT_SECRET', record.oidc?.clientSecret],
85
+ ['OIDC_SCOPES', record.oidc?.scopes],
86
+ ['OIDC_PROVIDER_LABEL', record.oidc?.providerLabel],
87
+ ['ALLOWED_EMAIL_DOMAINS', allowedEmailDomains.join(',')],
88
+ ]) {
89
+ const trimmed = (value ?? '').trim();
90
+ if (trimmed)
91
+ settingsEnv[name] = trimmed;
92
+ }
93
+ return {
94
+ port: settings.port,
95
+ databaseUrl: settings.databaseUrl,
96
+ dbSchema,
97
+ nodeEnv: settings.nodeEnv,
98
+ tenantId,
99
+ externalApiKeyPrefix: `${tenantId}_`,
100
+ internalTokenPrefix: `${tenantId}-int_`,
101
+ uploadTokenPrefix: `${tenantId}-up_`,
102
+ mcpOAuthTokenPrefix: `${tenantId}-mcp_`,
103
+ workspacesRoot: path.resolve(settings.workspacesRoot, slug),
104
+ backupsRoot: besideWorkspaces('backups'),
105
+ spillRoot: besideWorkspaces('tool-chain-spills'),
106
+ docExtractCacheRoot: besideWorkspaces('doc-extract-cache'),
107
+ jwtSecret: secrets.jwtSecret,
108
+ secretsEncKey: secrets.secretsEncKey,
109
+ internalTokenSecret: secrets.internalTokenSecret,
110
+ adminEmail,
111
+ adminPassword,
112
+ loginPasswordEnabled,
113
+ oidcIssuerUrl: (record.oidc?.issuerUrl ?? '').trim().replace(/\/+$/, ''),
114
+ oidcClientId: (record.oidc?.clientId ?? '').trim(),
115
+ oidcClientSecret: (record.oidc?.clientSecret ?? '').trim(),
116
+ oidcScopes: (record.oidc?.scopes ?? 'openid profile email').trim(),
117
+ oidcProviderLabel: (record.oidc?.providerLabel ?? 'Single sign-on').trim(),
118
+ kbRepoUrl: (record.kbRepoUrl ?? '').trim(),
119
+ kbDirName: (record.kbDirName ?? '').trim(),
120
+ gitUsername,
121
+ gitToken: (record.gitToken ?? '').trim(),
122
+ kbTemplateDir: settings.kbTemplateDir,
123
+ ontologySessionBlock: settings.ontologySessionBlock,
124
+ updateCheckEnabled: settings.updateCheckEnabled,
125
+ allowedEmailDomains,
126
+ trustProxy: settings.trustProxy,
127
+ gitTimeoutMs: settings.gitTimeoutMs,
128
+ publicBackendUrl,
129
+ publicFrontendUrl,
130
+ configuredPublicFrontendUrl: publicFrontendUrl,
131
+ loopbackBaseUrl: loopbackTenantBaseUrl(settings.port, slug),
132
+ settingsEnv,
133
+ };
134
+ }
135
+ /**
136
+ * The reference {@link TenantSource}: every tenant known up front, from a
137
+ * JSON file (`TENANTS_FILE`). Enough for development, tests and a small
138
+ * self-hosted fleet; the cloud app brings its own source over its registry.
139
+ */
140
+ export class StaticTenantSource {
141
+ bySlug = new Map();
142
+ byHost = new Map();
143
+ constructor(records, settings) {
144
+ for (const record of records) {
145
+ const config = tenantConfigFrom(record, settings);
146
+ const descriptor = {
147
+ slug: record.slug,
148
+ hosts: record.hosts.map(normalizeHost),
149
+ config,
150
+ };
151
+ if (this.bySlug.has(descriptor.slug))
152
+ throw new Error(`Tenant "${descriptor.slug}" is listed twice`);
153
+ this.bySlug.set(descriptor.slug, descriptor);
154
+ for (const host of descriptor.hosts) {
155
+ const taken = this.byHost.get(host);
156
+ if (taken)
157
+ throw new Error(`Host "${host}" is claimed by both "${taken.slug}" and "${descriptor.slug}"`);
158
+ this.byHost.set(host, descriptor);
159
+ }
160
+ }
161
+ }
162
+ static async fromFile(file, settings) {
163
+ const text = await fs.readFile(file, 'utf8');
164
+ let parsed;
165
+ try {
166
+ parsed = JSON.parse(text);
167
+ }
168
+ catch (err) {
169
+ throw new Error(`${file} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
170
+ }
171
+ const tenants = parsed?.tenants;
172
+ if (!Array.isArray(tenants))
173
+ throw new Error(`${file} must be an object with a "tenants" array`);
174
+ return new StaticTenantSource(tenants, settings);
175
+ }
176
+ get slugs() {
177
+ return [...this.bySlug.keys()];
178
+ }
179
+ async resolveByHost(host) {
180
+ return this.byHost.get(normalizeHost(host)) ?? null;
181
+ }
182
+ async describe(slug) {
183
+ return this.bySlug.get(slug) ?? null;
184
+ }
185
+ }
186
+ const MAX_TIMER_MS = 2_147_483_647;
187
+ /**
188
+ * The host's settings from the environment: the same variables a
189
+ * single-tenant deployment reads for these facts (`DATABASE_URL` and the
190
+ * `POSTGRES_*` parts, `PORT`, `TRUST_PROXY`, `WORKSPACES_ROOT`,
191
+ * `KB_TEMPLATE_DIR`, `GIT_TIMEOUT_MS`, …), plus the three that only a host
192
+ * has: `TENANTS_FILE`, `TENANT_MASTER_KEY` and `TENANT_IDLE_MINUTES`.
193
+ */
194
+ export function tenantHostEnv(env = process.env) {
195
+ const tenantsFile = (env.TENANTS_FILE || '').trim() || null;
196
+ const masterKey = (env.TENANT_MASTER_KEY || '').trim();
197
+ if (tenantsFile && !masterKey) {
198
+ throw new Error('TENANT_MASTER_KEY is required with TENANTS_FILE — every tenant\'s secrets derive from it. Generate one with: ' +
199
+ `node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"`);
200
+ }
201
+ const gitTimeout = Number(env.GIT_TIMEOUT_MS);
202
+ const idle = Number(env.TENANT_IDLE_MINUTES);
203
+ const domain = (env.DOMAIN || '').trim();
204
+ const workspacesRoot = env.WORKSPACES_ROOT || path.resolve(process.cwd(), 'workspaces');
205
+ return {
206
+ tenantsFile,
207
+ masterKey,
208
+ databaseUrl: resolveDatabaseUrl(env),
209
+ port: parseInt(env.PORT || '3001', 10),
210
+ nodeEnv: env.NODE_ENV || 'development',
211
+ trustProxy: (env.TRUST_PROXY || (domain ? '1' : '')).trim(),
212
+ workspacesRoot,
213
+ kbTemplateDir: env.KB_TEMPLATE_DIR || defaultKbTemplateDir(),
214
+ gitTimeoutMs: Number.isFinite(gitTimeout) && gitTimeout > 0 && gitTimeout <= MAX_TIMER_MS ? gitTimeout : DEFAULT_GIT_TIMEOUT_MS,
215
+ ontologySessionBlock: (env.ONTOLOGY_SESSION_BLOCK ?? 'true').trim().toLowerCase() !== 'false',
216
+ updateCheckEnabled: (env.UPDATE_CHECK ?? 'true').trim().toLowerCase() !== 'false',
217
+ idleMinutes: Number.isFinite(idle) && idle > 0 ? idle : 30,
218
+ };
219
+ }
220
+ //# sourceMappingURL=static-tenant-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-tenant-source.js","sourceRoot":"","sources":["../../src/tenancy/static-tenant-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { type Express } from 'express';
2
+ import type { ProcessConfig } from '../core-config.js';
3
+ import { TenantRuntime, type TenantRuntimeDeps } from './tenant-runtime.js';
4
+ import { type TenantSource } from './tenant-source.contract.js';
5
+ /**
6
+ * The path prefix under which a process reaches ONE of its own tenants over
7
+ * loopback: `http://127.0.0.1:<port>/_tenant/<slug>/api/...`. The MCP proxy
8
+ * and the UTCP manuals it seeds dial the tenant's own REST surface this way,
9
+ * because a loopback request carries no tenant host name and a header cannot
10
+ * ride a UTCP call (the proxy is a passthrough; it reshapes nothing).
11
+ *
12
+ * The host honours the prefix only for a request that came from this
13
+ * machine AND was forwarded by nobody: the socket peer is loopback and there
14
+ * is no `X-Forwarded-For`. A reverse proxy on the same host (nginx, a
15
+ * Coolify proxy) delivers every public request from a loopback socket, and
16
+ * every such proxy adds that header; the process's own dial never does.
17
+ * What the prefix could grant anyone who got past this is only what the
18
+ * tenant's host name grants already — sessions, keys and tokens are per
19
+ * tenant — but the addressing rule is stated so it can be relied on.
20
+ */
21
+ export declare const LOOPBACK_TENANT_PREFIX = "/_tenant";
22
+ /** The base URL a tenant's graph dials itself at — see {@link LOOPBACK_TENANT_PREFIX}. */
23
+ export declare function loopbackTenantBaseUrl(port: number, slug: string): string;
24
+ /** Whether `address` is this machine talking to itself. */
25
+ export declare function isLoopbackAddress(address: string | undefined): boolean;
26
+ /** How a request names its tenant: by the loopback prefix, or by its host. */
27
+ export type TenantSelector = {
28
+ kind: 'slug';
29
+ slug: string;
30
+ rest: string;
31
+ } | {
32
+ kind: 'host';
33
+ host: string;
34
+ };
35
+ /**
36
+ * Which tenant a request is for. The loopback prefix wins, but only from a
37
+ * loopback peer that no proxy forwarded (no `X-Forwarded-For`); everything
38
+ * else is decided by the host name (the `X-Forwarded-Host` a trusted proxy
39
+ * set, else `Host`), lowercase and without its port.
40
+ */
41
+ export declare function selectTenant(req: {
42
+ hostname: string;
43
+ url: string;
44
+ peer: string | undefined;
45
+ forwardedFor?: string | string[] | undefined;
46
+ }): TenantSelector;
47
+ export interface TenantHostOptions {
48
+ source: TenantSource;
49
+ process: ProcessConfig;
50
+ /** The built SPA, served once for every resolved tenant. */
51
+ staticDir?: string;
52
+ /** Minutes without a request after which a tenant's graph is stopped. Default 30; 0 never evicts. */
53
+ idleMinutes?: number;
54
+ /** How long a request waits for an activation in flight before answering 503. Default 60s. */
55
+ activationWaitMs?: number;
56
+ /** Seams for the runtimes the host builds — a suite's fake graphs. */
57
+ runtime?: TenantRuntimeDeps;
58
+ /** How often idle tenants are looked for. Default: once a minute. */
59
+ sweepIntervalMs?: number;
60
+ }
61
+ export interface TenantHost {
62
+ /** The app the process listens on. */
63
+ app: Express;
64
+ /** The runtimes built so far, by slug. */
65
+ runtimes(): ReadonlyMap<string, TenantRuntime>;
66
+ /** Stop every active tenant; the host keeps serving and reactivates on demand. */
67
+ evictAll(): Promise<void>;
68
+ /** Stop the idle sweep and every tenant: the process's shutdown. */
69
+ stop(): Promise<void>;
70
+ }
71
+ /**
72
+ * One Express app in front of many tenants' apps. It answers process health
73
+ * itself, resolves each request to a tenant (see {@link selectTenant}),
74
+ * activates that tenant's graph on first use, hands the request to the
75
+ * tenant's app, and serves the SPA for whatever the tenant's app leaves
76
+ * unhandled. Nothing below it knows there are other tenants: each graph was
77
+ * built by the same composition root a single-tenant deployment uses.
78
+ */
79
+ export declare function createTenantHost(opts: TenantHostOptions): TenantHost;
80
+ //# sourceMappingURL=tenant-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-host.d.ts","sourceRoot":"","sources":["../../src/tenancy/tenant-host.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,OAAO,EAAgB,MAAM,SAAS,CAAC;AAG9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAA6D,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAI3H;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,aAAa,CAAC;AAEjD,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKtE;AAED,8EAA8E;AAC9E,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3G;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;CAC9C,GAAG,cAAc,CAYjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC;IACvB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,GAAG,EAAE,OAAO,CAAC;IACb,0CAA0C;IAC1C,QAAQ,IAAI,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC/C,kFAAkF;IAClF,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,oEAAoE;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAeD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU,CA+IpE"}
@@ -0,0 +1,217 @@
1
+ import express from 'express';
2
+ import path from 'node:path';
3
+ import { isIP } from 'node:net';
4
+ import { GIT_SHA } from '../version.js';
5
+ import { logger } from '../shared/logging.js';
6
+ import { TenantRuntime } from './tenant-runtime.js';
7
+ import { TENANT_SLUG_PATTERN, normalizeHost } from './tenant-source.contract.js';
8
+ const log = logger('tenancy');
9
+ /**
10
+ * The path prefix under which a process reaches ONE of its own tenants over
11
+ * loopback: `http://127.0.0.1:<port>/_tenant/<slug>/api/...`. The MCP proxy
12
+ * and the UTCP manuals it seeds dial the tenant's own REST surface this way,
13
+ * because a loopback request carries no tenant host name and a header cannot
14
+ * ride a UTCP call (the proxy is a passthrough; it reshapes nothing).
15
+ *
16
+ * The host honours the prefix only for a request that came from this
17
+ * machine AND was forwarded by nobody: the socket peer is loopback and there
18
+ * is no `X-Forwarded-For`. A reverse proxy on the same host (nginx, a
19
+ * Coolify proxy) delivers every public request from a loopback socket, and
20
+ * every such proxy adds that header; the process's own dial never does.
21
+ * What the prefix could grant anyone who got past this is only what the
22
+ * tenant's host name grants already — sessions, keys and tokens are per
23
+ * tenant — but the addressing rule is stated so it can be relied on.
24
+ */
25
+ export const LOOPBACK_TENANT_PREFIX = '/_tenant';
26
+ /** The base URL a tenant's graph dials itself at — see {@link LOOPBACK_TENANT_PREFIX}. */
27
+ export function loopbackTenantBaseUrl(port, slug) {
28
+ return `http://127.0.0.1:${port}${LOOPBACK_TENANT_PREFIX}/${slug}`;
29
+ }
30
+ /** Whether `address` is this machine talking to itself. */
31
+ export function isLoopbackAddress(address) {
32
+ if (!address)
33
+ return false;
34
+ const bare = address.startsWith('::ffff:') ? address.slice('::ffff:'.length) : address;
35
+ if (bare === '::1')
36
+ return true;
37
+ return isIP(bare) === 4 && bare.startsWith('127.');
38
+ }
39
+ /**
40
+ * Which tenant a request is for. The loopback prefix wins, but only from a
41
+ * loopback peer that no proxy forwarded (no `X-Forwarded-For`); everything
42
+ * else is decided by the host name (the `X-Forwarded-Host` a trusted proxy
43
+ * set, else `Host`), lowercase and without its port.
44
+ */
45
+ export function selectTenant(req) {
46
+ const forwarded = Array.isArray(req.forwardedFor) ? req.forwardedFor.length > 0 : Boolean(req.forwardedFor);
47
+ if (isLoopbackAddress(req.peer) && !forwarded && req.url.startsWith(`${LOOPBACK_TENANT_PREFIX}/`)) {
48
+ const afterPrefix = req.url.slice(LOOPBACK_TENANT_PREFIX.length + 1);
49
+ const end = afterPrefix.search(/[/?#]/);
50
+ const slug = end === -1 ? afterPrefix : afterPrefix.slice(0, end);
51
+ if (TENANT_SLUG_PATTERN.test(slug)) {
52
+ const rest = end === -1 ? '/' : afterPrefix.slice(end).replace(/^(?=[?#])/, '/');
53
+ return { kind: 'slug', slug, rest };
54
+ }
55
+ }
56
+ return { kind: 'host', host: normalizeHost(req.hostname || '') };
57
+ }
58
+ const DEFAULT_ACTIVATION_WAIT_MS = 60_000;
59
+ const DEFAULT_IDLE_MINUTES = 30;
60
+ const DEFAULT_SWEEP_INTERVAL_MS = 60_000;
61
+ /** `promise`, or `null` once `ms` have passed. */
62
+ function within(promise, ms) {
63
+ let timer;
64
+ const late = new Promise((resolve) => {
65
+ timer = setTimeout(() => resolve(null), ms);
66
+ });
67
+ return Promise.race([promise, late]).finally(() => clearTimeout(timer));
68
+ }
69
+ /**
70
+ * One Express app in front of many tenants' apps. It answers process health
71
+ * itself, resolves each request to a tenant (see {@link selectTenant}),
72
+ * activates that tenant's graph on first use, hands the request to the
73
+ * tenant's app, and serves the SPA for whatever the tenant's app leaves
74
+ * unhandled. Nothing below it knows there are other tenants: each graph was
75
+ * built by the same composition root a single-tenant deployment uses.
76
+ */
77
+ export function createTenantHost(opts) {
78
+ const runtimes = new Map();
79
+ const activationWaitMs = opts.activationWaitMs ?? DEFAULT_ACTIVATION_WAIT_MS;
80
+ const idleMs = (opts.idleMinutes ?? DEFAULT_IDLE_MINUTES) * 60_000;
81
+ const runtimeFor = (descriptor) => {
82
+ let runtime = runtimes.get(descriptor.slug);
83
+ if (!runtime) {
84
+ runtime = new TenantRuntime(descriptor, opts.runtime);
85
+ runtimes.set(descriptor.slug, runtime);
86
+ }
87
+ return runtime;
88
+ };
89
+ const app = express();
90
+ // Forwarded headers are honoured exactly as a single-tenant deployment
91
+ // honours them, and for the same reason: `req.hostname` is what picks the
92
+ // tenant, and behind a proxy it lives in `X-Forwarded-Host`.
93
+ if (opts.process.trustProxy) {
94
+ const raw = opts.process.trustProxy;
95
+ app.set('trust proxy', /^\d+$/.test(raw) ? Number(raw) : raw);
96
+ }
97
+ // The process's own health, before any tenant is involved: a load balancer
98
+ // asks with whatever host name it likes, and a process with no active
99
+ // tenant is still a healthy process.
100
+ app.get('/api/health', (_req, res) => {
101
+ res.json({ status: 'ok', sha: GIT_SHA, timestamp: Date.now(), tenants: runtimes.size });
102
+ });
103
+ app.use(async (req, res, next) => {
104
+ const selector = selectTenant({
105
+ hostname: req.hostname,
106
+ url: req.url,
107
+ peer: req.socket.remoteAddress,
108
+ forwardedFor: req.headers['x-forwarded-for'],
109
+ });
110
+ let descriptor;
111
+ try {
112
+ descriptor =
113
+ selector.kind === 'slug'
114
+ ? await opts.source.describe(selector.slug)
115
+ : await opts.source.resolveByHost(selector.host);
116
+ }
117
+ catch (err) {
118
+ log.error('tenant lookup failed:', { err });
119
+ res.status(503).set('Retry-After', '5').json({ error: 'Tenant lookup failed' });
120
+ return;
121
+ }
122
+ if (!descriptor) {
123
+ if (req.path.startsWith('/api/') || req.path.startsWith(LOOPBACK_TENANT_PREFIX)) {
124
+ res.status(404).json({ error: 'No workspace at this address' });
125
+ }
126
+ else {
127
+ res.status(404).type('text/plain').send('No workspace at this address.');
128
+ }
129
+ return;
130
+ }
131
+ if (selector.kind === 'slug')
132
+ req.url = selector.rest;
133
+ const runtime = runtimeFor(descriptor);
134
+ // Counted from here, before the graph is even asked for, until the
135
+ // response closes however it ends — a 503 below included. An open
136
+ // response is what keeps a tenant from being evicted from under it.
137
+ // Left exactly once: a client that dropped during the tenant lookup
138
+ // above has had its `close` already, and that event will not come
139
+ // again, so the socket is asked directly; a socket destroyed but not
140
+ // yet closed would otherwise be left twice, once here and once by the
141
+ // listener, taking another request's count with it.
142
+ runtime.enter();
143
+ let left = false;
144
+ const leave = () => {
145
+ if (left)
146
+ return;
147
+ left = true;
148
+ runtime.leave();
149
+ };
150
+ res.on('close', leave);
151
+ if (req.socket.destroyed) {
152
+ leave();
153
+ return;
154
+ }
155
+ let graph;
156
+ try {
157
+ graph = await within(runtime.handle(), activationWaitMs);
158
+ }
159
+ catch {
160
+ // Logged by the runtime; the caller learns only that it may try again.
161
+ res.status(503).set('Retry-After', '5').json({ error: 'This workspace could not be started; try again shortly' });
162
+ return;
163
+ }
164
+ if (!graph) {
165
+ res.status(503).set('Retry-After', '5').json({ error: 'This workspace is starting; try again shortly' });
166
+ return;
167
+ }
168
+ graph.app(req, res, next);
169
+ });
170
+ // Whatever a tenant's app left unhandled: the SPA, with the same rule a
171
+ // single-tenant deployment applies to the namespaces that must never
172
+ // resolve to `index.html` (see `createCoreServer`).
173
+ if (opts.staticDir) {
174
+ const frontendDist = opts.staticDir;
175
+ app.use(express.static(frontendDist));
176
+ app.get('{*path}', (req, res) => {
177
+ if (req.path.startsWith('/.well-known/') ||
178
+ req.path.startsWith('/api/') ||
179
+ req.path.startsWith('/login/oauth/')) {
180
+ res.status(404).json({ error: 'Not found' });
181
+ return;
182
+ }
183
+ res.sendFile(path.join(frontendDist, 'index.html'));
184
+ });
185
+ }
186
+ // Idle tenants are stopped on a timer, never on the request that would
187
+ // have been their last: a graph whose last response closed `idleMs` ago,
188
+ // with none still open and no queued commit, is not worth its pool and
189
+ // its lease. `busy()` is what keeps an event stream's tenant alive.
190
+ const sweep = async () => {
191
+ for (const runtime of runtimes.values()) {
192
+ if (runtime.state !== 'active' || runtime.idleFor() < idleMs)
193
+ continue;
194
+ if (await runtime.busy())
195
+ continue;
196
+ await runtime.evict().catch((err) => log.warn(`evicting tenant "${runtime.slug}" failed:`, { err }));
197
+ }
198
+ };
199
+ const sweeper = idleMs > 0
200
+ ? setInterval(() => void sweep(), Math.min(opts.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS, idleMs))
201
+ : null;
202
+ sweeper?.unref();
203
+ const evictAll = async () => {
204
+ await Promise.all([...runtimes.values()].map((runtime) => runtime.evict().catch(() => undefined)));
205
+ };
206
+ return {
207
+ app,
208
+ runtimes: () => runtimes,
209
+ evictAll,
210
+ async stop() {
211
+ if (sweeper)
212
+ clearInterval(sweeper);
213
+ await evictAll();
214
+ },
215
+ };
216
+ }
217
+ //# sourceMappingURL=tenant-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-host.js","sourceRoot":"","sources":["../../src/tenancy/tenant-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import type { Express } from 'express';
2
+ import { type CoreServices } from '../core/create-core-services.js';
3
+ import type { TenantDescriptor } from './tenant-source.contract.js';
4
+ /** A tenant's running graph: its services and the Express app that serves them. */
5
+ export interface TenantGraph {
6
+ core: CoreServices;
7
+ app: Express;
8
+ }
9
+ export type TenantState = 'idle' | 'activating' | 'active' | 'evicting';
10
+ /** The lifecycle seams, so a suite can drive a runtime without a database. */
11
+ export interface TenantRuntimeDeps {
12
+ /** Build and start the graph. Default: `createCoreServices` + `createCoreServer`. */
13
+ activate?: (descriptor: TenantDescriptor) => Promise<TenantGraph>;
14
+ /** Stop a graph. Default: `stopCore`. */
15
+ stop?: (graph: TenantGraph) => Promise<void>;
16
+ /** Whether the graph has work in flight that an eviction would strand. Default: queued commits. */
17
+ busy?: (graph: TenantGraph) => Promise<boolean>;
18
+ now?: () => number;
19
+ /**
20
+ * How long a failed activation is remembered before the next request tries
21
+ * again: `initialMs` after the first failure, doubling per consecutive
22
+ * failure up to `maxMs`. Defaults: 5 s to 60 s.
23
+ */
24
+ retry?: {
25
+ initialMs?: number;
26
+ maxMs?: number;
27
+ };
28
+ }
29
+ /**
30
+ * One tenant's graph, brought up on first use and stopped when the host
31
+ * says so: `idle → activating → active → evicting → idle`.
32
+ *
33
+ * ACTIVATE ONCE. Requests arriving while the graph is being built all await
34
+ * the one activation in flight. A failed activation is remembered for a
35
+ * short, growing window and answered from memory inside it, so a tenant
36
+ * whose remote is down or whose token is wrong costs one clone attempt per
37
+ * window rather than one per request; past the window the next request
38
+ * tries again, since the remote may be back or the token fixed. An eviction
39
+ * that lands mid-activation waits for the activation and then stops what it
40
+ * produced, so a graph is never left running behind an evicted runtime.
41
+ *
42
+ * IN USE MEANS A RESPONSE IS OPEN. The host tells the runtime when it hands
43
+ * a request over and when that response closes, so idleness counts from the
44
+ * last response that ENDED, and a tenant with any response still open — an
45
+ * event stream a browser holds, a clone in flight — is busy and never
46
+ * evicted from under it.
47
+ */
48
+ export declare class TenantRuntime {
49
+ readonly descriptor: TenantDescriptor;
50
+ private graph;
51
+ private activation;
52
+ private eviction;
53
+ private failure;
54
+ private openResponses;
55
+ private lastUsedAt;
56
+ private readonly activate;
57
+ private readonly stopGraph;
58
+ private readonly isBusy;
59
+ private readonly now;
60
+ private readonly retryInitialMs;
61
+ private readonly retryMaxMs;
62
+ constructor(descriptor: TenantDescriptor, deps?: TenantRuntimeDeps);
63
+ /** A request was handed to this tenant; paired with {@link leave} when its response closes. */
64
+ enter(): void;
65
+ /** A response to this tenant closed, however it ended. */
66
+ leave(): void;
67
+ /** Responses handed over and not yet closed. */
68
+ get open(): number;
69
+ get slug(): string;
70
+ get state(): TenantState;
71
+ /** Milliseconds since a request last touched this tenant. */
72
+ idleFor(): number;
73
+ /**
74
+ * The graph, built if it is not running. Every caller of a concurrent
75
+ * first burst gets the same promise; a caller that arrives during an
76
+ * eviction waits for it, then starts the graph afresh.
77
+ */
78
+ handle(): Promise<TenantGraph>;
79
+ /**
80
+ * Whether an eviction would strand something: a response still open, or
81
+ * work the graph reports (queued commits). False when nothing runs.
82
+ */
83
+ busy(): Promise<boolean>;
84
+ /**
85
+ * Stop the graph, if one runs or is being built. Idempotent: a second call
86
+ * joins the eviction under way. Afterwards the runtime is idle and the
87
+ * next {@link handle} builds a fresh graph.
88
+ */
89
+ evict(): Promise<void>;
90
+ }
91
+ //# sourceMappingURL=tenant-runtime.d.ts.map