@bevel-software/platform-core-backend 0.14.0 → 0.15.1

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 (385) hide show
  1. package/THIRD-PARTY-NOTICES.md +6 -6
  2. package/dist/core/catalog-cache-invalidation.d.ts +29 -0
  3. package/dist/core/catalog-cache-invalidation.d.ts.map +1 -0
  4. package/dist/core/catalog-cache-invalidation.js +71 -0
  5. package/dist/core/catalog-cache-invalidation.js.map +1 -0
  6. package/dist/core/create-core-server.d.ts.map +1 -1
  7. package/dist/core/create-core-server.js +99 -8
  8. package/dist/core/create-core-server.js.map +1 -1
  9. package/dist/core/create-core-services.d.ts +18 -1
  10. package/dist/core/create-core-services.d.ts.map +1 -1
  11. package/dist/core/create-core-services.js +96 -43
  12. package/dist/core/create-core-services.js.map +1 -1
  13. package/dist/modules/access/access-control.interface.d.ts +18 -6
  14. package/dist/modules/access/access-control.interface.d.ts.map +1 -1
  15. package/dist/modules/access/access-control.service.d.ts +26 -1
  16. package/dist/modules/access/access-control.service.d.ts.map +1 -1
  17. package/dist/modules/access/access-control.service.js +213 -71
  18. package/dist/modules/access/access-control.service.js.map +1 -1
  19. package/dist/modules/access/access.routes.d.ts.map +1 -1
  20. package/dist/modules/access/access.routes.js +59 -7
  21. package/dist/modules/access/access.routes.js.map +1 -1
  22. package/dist/modules/access-model/access-grammar.d.ts +51 -1
  23. package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
  24. package/dist/modules/access-model/access-grammar.js +95 -1
  25. package/dist/modules/access-model/access-grammar.js.map +1 -1
  26. package/dist/modules/access-model/group-files.d.ts.map +1 -1
  27. package/dist/modules/access-model/group-files.js +4 -1
  28. package/dist/modules/access-model/group-files.js.map +1 -1
  29. package/dist/modules/access-model/plugin-principals.d.ts +49 -0
  30. package/dist/modules/access-model/plugin-principals.d.ts.map +1 -0
  31. package/dist/modules/access-model/plugin-principals.js +125 -0
  32. package/dist/modules/access-model/plugin-principals.js.map +1 -0
  33. package/dist/modules/database/core-schema.d.ts +326 -0
  34. package/dist/modules/database/core-schema.d.ts.map +1 -1
  35. package/dist/modules/database/core-schema.js +52 -0
  36. package/dist/modules/database/core-schema.js.map +1 -1
  37. package/dist/modules/kb-sync/index.d.ts +6 -0
  38. package/dist/modules/kb-sync/index.d.ts.map +1 -0
  39. package/dist/modules/kb-sync/index.js +5 -0
  40. package/dist/modules/kb-sync/index.js.map +1 -0
  41. package/dist/modules/kb-sync/kb-sync.interface.d.ts +77 -0
  42. package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -0
  43. package/dist/modules/kb-sync/kb-sync.interface.js +2 -0
  44. package/dist/modules/kb-sync/kb-sync.interface.js.map +1 -0
  45. package/dist/modules/kb-sync/kb-sync.routes.d.ts +70 -0
  46. package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -0
  47. package/dist/modules/kb-sync/kb-sync.routes.js +135 -0
  48. package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -0
  49. package/dist/modules/kb-sync/kb-sync.service.d.ts +45 -0
  50. package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -0
  51. package/dist/modules/kb-sync/kb-sync.service.js +183 -0
  52. package/dist/modules/kb-sync/kb-sync.service.js.map +1 -0
  53. package/dist/modules/kb-sync/sync-auth.d.ts +59 -0
  54. package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -0
  55. package/dist/modules/kb-sync/sync-auth.js +62 -0
  56. package/dist/modules/kb-sync/sync-auth.js.map +1 -0
  57. package/dist/modules/kb-sync/sync-payload.d.ts +32 -0
  58. package/dist/modules/kb-sync/sync-payload.d.ts.map +1 -0
  59. package/dist/modules/kb-sync/sync-payload.js +105 -0
  60. package/dist/modules/kb-sync/sync-payload.js.map +1 -0
  61. package/dist/modules/marketplace/git-http.routes.d.ts +42 -0
  62. package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -0
  63. package/dist/modules/marketplace/git-http.routes.js +190 -0
  64. package/dist/modules/marketplace/git-http.routes.js.map +1 -0
  65. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +23 -0
  66. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -0
  67. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +59 -0
  68. package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -0
  69. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts +59 -0
  70. package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts.map +1 -0
  71. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js +96 -0
  72. package/dist/modules/marketplace/github-facade/github-facade-codes.store.js.map +1 -0
  73. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +99 -0
  74. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -0
  75. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +147 -0
  76. package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -0
  77. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts +47 -0
  78. package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -0
  79. package/dist/modules/marketplace/github-facade/github-facade.routes.js +228 -0
  80. package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -0
  81. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +109 -0
  82. package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -0
  83. package/dist/modules/marketplace/github-facade/github-facade.service.js +172 -0
  84. package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -0
  85. package/dist/modules/marketplace/github-facade/index.d.ts +6 -0
  86. package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -0
  87. package/dist/modules/marketplace/github-facade/index.js +6 -0
  88. package/dist/modules/marketplace/github-facade/index.js.map +1 -0
  89. package/dist/modules/marketplace/index.d.ts +4 -0
  90. package/dist/modules/marketplace/index.d.ts.map +1 -0
  91. package/dist/modules/marketplace/index.js +4 -0
  92. package/dist/modules/marketplace/index.js.map +1 -0
  93. package/dist/modules/marketplace/marketplace-repo.service.d.ts +122 -0
  94. package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -0
  95. package/dist/modules/marketplace/marketplace-repo.service.js +300 -0
  96. package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -0
  97. package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
  98. package/dist/modules/mcp/oauth/bevel-oauth-provider.js +4 -0
  99. package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
  100. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +14 -8
  101. package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
  102. package/dist/modules/mcp/oauth/oauth-consent.routes.js +13 -1
  103. package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
  104. package/dist/modules/mcp/oauth/oauth-state.d.ts +13 -2
  105. package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -1
  106. package/dist/modules/mcp/oauth/oauth-state.js +3 -1
  107. package/dist/modules/mcp/oauth/oauth-state.js.map +1 -1
  108. package/dist/modules/plugins/compile/compile-marketplace.d.ts +97 -0
  109. package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -0
  110. package/dist/modules/plugins/compile/compile-marketplace.js +240 -0
  111. package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -0
  112. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +66 -0
  113. package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -0
  114. package/dist/modules/plugins/compile/marketplace-compiler.service.js +132 -0
  115. package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -0
  116. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +37 -0
  117. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -0
  118. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +135 -0
  119. package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -0
  120. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +45 -0
  121. package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -0
  122. package/dist/modules/plugins/discovery/bundle-dialect/registry.js +147 -0
  123. package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -0
  124. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +37 -0
  125. package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -0
  126. package/dist/modules/plugins/discovery/kb-plugin-source.js +107 -0
  127. package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -0
  128. package/dist/modules/plugins/discovery/native.source.d.ts +15 -0
  129. package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -0
  130. package/dist/modules/plugins/discovery/native.source.js +102 -0
  131. package/dist/modules/plugins/discovery/native.source.js.map +1 -0
  132. package/dist/modules/plugins/discovery/plugin-source.d.ts +96 -0
  133. package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -0
  134. package/dist/modules/plugins/discovery/plugin-source.js +2 -0
  135. package/dist/modules/plugins/discovery/plugin-source.js.map +1 -0
  136. package/dist/modules/plugins/index.d.ts +10 -1
  137. package/dist/modules/plugins/index.d.ts.map +1 -1
  138. package/dist/modules/plugins/index.js +8 -0
  139. package/dist/modules/plugins/index.js.map +1 -1
  140. package/dist/modules/plugins/plugin-links.d.ts +66 -0
  141. package/dist/modules/plugins/plugin-links.d.ts.map +1 -0
  142. package/dist/modules/plugins/plugin-links.js +160 -0
  143. package/dist/modules/plugins/plugin-links.js.map +1 -0
  144. package/dist/modules/plugins/plugin-links.service.d.ts +114 -0
  145. package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -0
  146. package/dist/modules/plugins/plugin-links.service.js +304 -0
  147. package/dist/modules/plugins/plugin-links.service.js.map +1 -0
  148. package/dist/modules/plugins/plugin-provision.service.d.ts +39 -3
  149. package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
  150. package/dist/modules/plugins/plugin-provision.service.js +152 -52
  151. package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
  152. package/dist/modules/plugins/plugin-rename.service.d.ts +69 -0
  153. package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -0
  154. package/dist/modules/plugins/plugin-rename.service.js +245 -0
  155. package/dist/modules/plugins/plugin-rename.service.js.map +1 -0
  156. package/dist/modules/plugins/plugins.contract.d.ts +27 -1
  157. package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
  158. package/dist/modules/plugins/plugins.routes.d.ts +7 -1
  159. package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
  160. package/dist/modules/plugins/plugins.routes.js +120 -12
  161. package/dist/modules/plugins/plugins.routes.js.map +1 -1
  162. package/dist/modules/plugins/plugins.service.d.ts +50 -3
  163. package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
  164. package/dist/modules/plugins/plugins.service.js +108 -47
  165. package/dist/modules/plugins/plugins.service.js.map +1 -1
  166. package/dist/modules/settings/deployment-settings.service.d.ts +9 -0
  167. package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
  168. package/dist/modules/settings/deployment-settings.service.js +82 -2
  169. package/dist/modules/settings/deployment-settings.service.js.map +1 -1
  170. package/dist/modules/settings/setup.routes.d.ts +26 -0
  171. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  172. package/dist/modules/settings/setup.routes.js +9 -1
  173. package/dist/modules/settings/setup.routes.js.map +1 -1
  174. package/dist/modules/skills/index.d.ts +1 -0
  175. package/dist/modules/skills/index.d.ts.map +1 -1
  176. package/dist/modules/skills/index.js +1 -0
  177. package/dist/modules/skills/index.js.map +1 -1
  178. package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
  179. package/dist/modules/skills/pending-skills.service.js +9 -4
  180. package/dist/modules/skills/pending-skills.service.js.map +1 -1
  181. package/dist/modules/skills/skill-access-requests.routes.d.ts +38 -0
  182. package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -0
  183. package/dist/modules/skills/skill-access-requests.routes.js +168 -0
  184. package/dist/modules/skills/skill-access-requests.routes.js.map +1 -0
  185. package/dist/modules/skills/skills.contract.d.ts +31 -0
  186. package/dist/modules/skills/skills.contract.d.ts.map +1 -1
  187. package/dist/modules/skills/skills.routes.d.ts +28 -3
  188. package/dist/modules/skills/skills.routes.d.ts.map +1 -1
  189. package/dist/modules/skills/skills.routes.js +42 -3
  190. package/dist/modules/skills/skills.routes.js.map +1 -1
  191. package/dist/modules/skills/skills.service.d.ts +4 -0
  192. package/dist/modules/skills/skills.service.d.ts.map +1 -1
  193. package/dist/modules/skills/skills.service.js +83 -22
  194. package/dist/modules/skills/skills.service.js.map +1 -1
  195. package/dist/modules/tool-auth/external-api-key.interface.d.ts +18 -1
  196. package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
  197. package/dist/modules/tool-auth/external-api-key.interface.js +2 -1
  198. package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
  199. package/dist/modules/tool-auth/external-api-key.service.d.ts +13 -4
  200. package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
  201. package/dist/modules/tool-auth/external-api-key.service.js +26 -9
  202. package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
  203. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +36 -0
  204. package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
  205. package/dist/modules/tool-manuals/mcp-json-discovery.js +130 -92
  206. package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
  207. package/dist/modules/tool-manuals/tool-manuals.service.d.ts +6 -1
  208. package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
  209. package/dist/modules/tool-manuals/tool-manuals.service.js +18 -25
  210. package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
  211. package/dist/modules/workflow/git/git.service.d.ts +40 -2
  212. package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
  213. package/dist/modules/workflow/git/git.service.js +227 -54
  214. package/dist/modules/workflow/git/git.service.js.map +1 -1
  215. package/dist/modules/workflow/git/pull-request.service.d.ts +6 -0
  216. package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
  217. package/dist/modules/workflow/git/pull-request.service.js +8 -0
  218. package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
  219. package/dist/modules/workflow/workflow.service.d.ts +52 -1
  220. package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
  221. package/dist/modules/workflow/workflow.service.js +242 -9
  222. package/dist/modules/workflow/workflow.service.js.map +1 -1
  223. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +35 -0
  224. package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -0
  225. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +121 -0
  226. package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -0
  227. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
  228. package/dist/modules/workspace/startup/steps/seed-tree.js +46 -2
  229. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
  230. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
  231. package/dist/modules/workspace/startup/steps/template-files.step.js +112 -25
  232. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
  233. package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
  234. package/dist/modules/workspace/workspace.routes.js +9 -9
  235. package/dist/modules/workspace/workspace.routes.js.map +1 -1
  236. package/dist/modules/workspace/workspace.service.d.ts +33 -0
  237. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  238. package/dist/modules/workspace/workspace.service.js +110 -16
  239. package/dist/modules/workspace/workspace.service.js.map +1 -1
  240. package/dist/shared/domain-errors.d.ts +20 -0
  241. package/dist/shared/domain-errors.d.ts.map +1 -1
  242. package/dist/shared/domain-errors.js +29 -0
  243. package/dist/shared/domain-errors.js.map +1 -1
  244. package/dist/shared/fs-errors.d.ts +8 -0
  245. package/dist/shared/fs-errors.d.ts.map +1 -0
  246. package/dist/shared/fs-errors.js +11 -0
  247. package/dist/shared/fs-errors.js.map +1 -0
  248. package/dist/shared/fs-walk.d.ts +20 -6
  249. package/dist/shared/fs-walk.d.ts.map +1 -1
  250. package/dist/shared/fs-walk.js +35 -27
  251. package/dist/shared/fs-walk.js.map +1 -1
  252. package/dist/shared/kb-walk.d.ts +52 -0
  253. package/dist/shared/kb-walk.d.ts.map +1 -0
  254. package/dist/shared/kb-walk.js +76 -0
  255. package/dist/shared/kb-walk.js.map +1 -0
  256. package/dist/shared/path-order.d.ts +18 -0
  257. package/dist/shared/path-order.d.ts.map +1 -0
  258. package/dist/shared/path-order.js +35 -0
  259. package/dist/shared/path-order.js.map +1 -0
  260. package/dist/shared/ttl-cache.d.ts +28 -1
  261. package/dist/shared/ttl-cache.d.ts.map +1 -1
  262. package/dist/shared/ttl-cache.js +33 -1
  263. package/dist/shared/ttl-cache.js.map +1 -1
  264. package/kb-template/.bevelignore +1 -1
  265. package/kb-template/AGENTS.md +95 -30
  266. package/kb-template/Skills/.gitkeep +0 -0
  267. package/migrations/0005_github_facade.sql +25 -0
  268. package/migrations/meta/0005_snapshot.json +1717 -0
  269. package/migrations/meta/_journal.json +7 -0
  270. package/package.json +6 -6
  271. package/src/__tests__/kb-layout-config.test.ts +110 -0
  272. package/src/core/__tests__/catalog-cache-invalidation.test.ts +146 -0
  273. package/src/core/catalog-cache-invalidation.ts +92 -0
  274. package/src/core/create-core-server.ts +123 -7
  275. package/src/core/create-core-services.ts +162 -41
  276. package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +86 -0
  277. package/src/modules/access/__tests__/access-control.service.test.ts +19 -3
  278. package/src/modules/access/__tests__/access-plugin-principals.test.ts +368 -0
  279. package/src/modules/access/__tests__/groups-admin.service.test.ts +8 -0
  280. package/src/modules/access/access-control.interface.ts +20 -9
  281. package/src/modules/access/access-control.service.ts +240 -78
  282. package/src/modules/access/access.routes.ts +96 -14
  283. package/src/modules/access-model/__tests__/access-grammar.test.ts +18 -0
  284. package/src/modules/access-model/__tests__/plugin-token-canonical.test.ts +40 -0
  285. package/src/modules/access-model/access-grammar.ts +114 -2
  286. package/src/modules/access-model/group-files.ts +4 -0
  287. package/src/modules/access-model/plugin-principals.ts +137 -0
  288. package/src/modules/database/core-schema.ts +54 -0
  289. package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +297 -0
  290. package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +295 -0
  291. package/src/modules/kb-sync/__tests__/sync-auth.test.ts +118 -0
  292. package/src/modules/kb-sync/__tests__/sync-payload.test.ts +148 -0
  293. package/src/modules/kb-sync/index.ts +19 -0
  294. package/src/modules/kb-sync/kb-sync.interface.ts +79 -0
  295. package/src/modules/kb-sync/kb-sync.routes.ts +197 -0
  296. package/src/modules/kb-sync/kb-sync.service.ts +201 -0
  297. package/src/modules/kb-sync/sync-auth.ts +118 -0
  298. package/src/modules/kb-sync/sync-payload.ts +143 -0
  299. package/src/modules/marketplace/__tests__/github-facade.test.ts +443 -0
  300. package/src/modules/marketplace/__tests__/marketplace-git.test.ts +179 -0
  301. package/src/modules/marketplace/git-http.routes.ts +193 -0
  302. package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +78 -0
  303. package/src/modules/marketplace/github-facade/github-facade-codes.store.ts +145 -0
  304. package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +208 -0
  305. package/src/modules/marketplace/github-facade/github-facade.routes.ts +268 -0
  306. package/src/modules/marketplace/github-facade/github-facade.service.ts +221 -0
  307. package/src/modules/marketplace/github-facade/index.ts +25 -0
  308. package/src/modules/marketplace/index.ts +3 -0
  309. package/src/modules/marketplace/marketplace-repo.service.ts +337 -0
  310. package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -0
  311. package/src/modules/mcp/oauth/oauth-consent.routes.ts +24 -2
  312. package/src/modules/mcp/oauth/oauth-state.ts +15 -3
  313. package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +163 -0
  314. package/src/modules/plugins/__tests__/compile-marketplace.test.ts +294 -0
  315. package/src/modules/plugins/__tests__/plugin-index.service.test.ts +56 -12
  316. package/src/modules/plugins/__tests__/plugin-links.service.test.ts +287 -0
  317. package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +205 -5
  318. package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +394 -0
  319. package/src/modules/plugins/__tests__/plugins.routes.test.ts +80 -33
  320. package/src/modules/plugins/compile/compile-marketplace.ts +403 -0
  321. package/src/modules/plugins/compile/marketplace-compiler.service.ts +150 -0
  322. package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +329 -0
  323. package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +140 -0
  324. package/src/modules/plugins/discovery/bundle-dialect/registry.ts +175 -0
  325. package/src/modules/plugins/discovery/kb-plugin-source.ts +114 -0
  326. package/src/modules/plugins/discovery/native.source.ts +122 -0
  327. package/src/modules/plugins/discovery/plugin-source.ts +99 -0
  328. package/src/modules/plugins/index.ts +10 -0
  329. package/src/modules/plugins/plugin-links.service.ts +363 -0
  330. package/src/modules/plugins/plugin-links.ts +184 -0
  331. package/src/modules/plugins/plugin-provision.service.ts +160 -54
  332. package/src/modules/plugins/plugin-rename.service.ts +298 -0
  333. package/src/modules/plugins/plugins.contract.ts +28 -1
  334. package/src/modules/plugins/plugins.routes.ts +128 -11
  335. package/src/modules/plugins/plugins.service.ts +106 -53
  336. package/src/modules/settings/__tests__/deployment-settings.service.test.ts +57 -0
  337. package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +77 -0
  338. package/src/modules/settings/deployment-settings.service.ts +95 -2
  339. package/src/modules/settings/setup.routes.ts +24 -0
  340. package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +128 -0
  341. package/src/modules/skills/__tests__/skills.service.test.ts +85 -0
  342. package/src/modules/skills/index.ts +1 -0
  343. package/src/modules/skills/pending-skills.service.ts +7 -5
  344. package/src/modules/skills/skill-access-requests.routes.ts +199 -0
  345. package/src/modules/skills/skills.contract.ts +32 -0
  346. package/src/modules/skills/skills.routes.ts +59 -3
  347. package/src/modules/skills/skills.service.ts +84 -22
  348. package/src/modules/tool-auth/external-api-key.interface.ts +20 -1
  349. package/src/modules/tool-auth/external-api-key.service.ts +31 -13
  350. package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +24 -1
  351. package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +2 -0
  352. package/src/modules/tool-manuals/mcp-json-discovery.ts +154 -88
  353. package/src/modules/tool-manuals/tool-manuals.service.ts +14 -23
  354. package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +1 -1
  355. package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +1 -0
  356. package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +2 -2
  357. package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +119 -2
  358. package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +437 -0
  359. package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +3 -3
  360. package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +47 -4
  361. package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +253 -0
  362. package/src/modules/workflow/git/git.service.ts +239 -56
  363. package/src/modules/workflow/git/pull-request.service.ts +9 -0
  364. package/src/modules/workflow/workflow.service.ts +260 -9
  365. package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +6 -7
  366. package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +93 -0
  367. package/src/modules/workspace/__tests__/workspace.service.missing-branch.test.ts +28 -0
  368. package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +42 -12
  369. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +219 -4
  370. package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +129 -0
  371. package/src/modules/workspace/startup/steps/seed-tree.ts +44 -2
  372. package/src/modules/workspace/startup/steps/template-files.step.ts +131 -27
  373. package/src/modules/workspace/workspace.routes.ts +9 -17
  374. package/src/modules/workspace/workspace.service.ts +107 -16
  375. package/src/shared/__tests__/filename.test.ts +0 -0
  376. package/src/shared/__tests__/fs-walk.test.ts +22 -1
  377. package/src/shared/__tests__/kb-walk.test.ts +107 -0
  378. package/src/shared/__tests__/path-order.test.ts +24 -0
  379. package/src/shared/__tests__/ttl-cache.test.ts +55 -0
  380. package/src/shared/domain-errors.ts +29 -0
  381. package/src/shared/fs-errors.ts +10 -0
  382. package/src/shared/fs-walk.ts +38 -23
  383. package/src/shared/kb-walk.ts +95 -0
  384. package/src/shared/path-order.ts +33 -0
  385. package/src/shared/ttl-cache.ts +33 -1
@@ -0,0 +1,105 @@
1
+ import { assertValidBranchName } from '../kb-fs/branch-name.js';
2
+ const HEADS = 'refs/heads/';
3
+ function isRecord(v) {
4
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
5
+ }
6
+ function branchFromRef(ref) {
7
+ if (typeof ref !== 'string' || !ref.startsWith(HEADS))
8
+ return null;
9
+ const name = ref.slice(HEADS.length);
10
+ return isValidBranch(name) ? name : null;
11
+ }
12
+ function isValidBranch(name) {
13
+ try {
14
+ assertValidBranchName(name);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ function unique(names) {
22
+ return [...new Set(names)];
23
+ }
24
+ /**
25
+ * How an invalid explicit entry is echoed back. Only primitives are
26
+ * stringified: `String(obj)` on a JSON object carrying `"toString": 1` throws
27
+ * ("Cannot convert object to primitive value"), which would turn a caller's
28
+ * bad body into our 500.
29
+ */
30
+ function describeInvalid(entry) {
31
+ if (entry === null)
32
+ return 'null';
33
+ switch (typeof entry) {
34
+ case 'string':
35
+ return entry.trim() === '' ? '(empty)' : entry;
36
+ case 'number':
37
+ case 'boolean':
38
+ case 'bigint':
39
+ return String(entry);
40
+ default:
41
+ return Array.isArray(entry) ? '(array)' : '(object)';
42
+ }
43
+ }
44
+ export function parseSyncPayload(body) {
45
+ if (!isRecord(body))
46
+ return { source: 'none', branches: 'all', invalid: [] };
47
+ if ('branches' in body) {
48
+ const raw = body.branches;
49
+ if (!Array.isArray(raw))
50
+ return { source: 'explicit', branches: 'all', invalid: [] };
51
+ const valid = [];
52
+ const invalid = [];
53
+ for (const entry of raw) {
54
+ if (typeof entry !== 'string' || !entry.trim()) {
55
+ invalid.push(describeInvalid(entry));
56
+ continue;
57
+ }
58
+ const name = entry.trim();
59
+ (isValidBranch(name) ? valid : invalid).push(name);
60
+ }
61
+ return { source: 'explicit', branches: unique(valid), invalid };
62
+ }
63
+ // Azure DevOps service hook. `eventType` names the event; the branches sit
64
+ // under `resource` in a per-event shape.
65
+ const eventType = body.eventType;
66
+ if (typeof eventType === 'string' && isRecord(body.resource)) {
67
+ const resource = body.resource;
68
+ if (eventType === 'git.push') {
69
+ const updates = Array.isArray(resource.refUpdates) ? resource.refUpdates : [];
70
+ // A DELETION (new object id all zeros) names its branch too: syncing it
71
+ // is what finds the branch gone and retires the stale clone, instead of
72
+ // leaving it to fail on some unrelated full sync later.
73
+ const branches = updates
74
+ .map((u) => (isRecord(u) ? branchFromRef(u.name) : null))
75
+ .filter((b) => b !== null);
76
+ return { source: 'azure-devops', branches: unique(branches), invalid: [] };
77
+ }
78
+ if (eventType.startsWith('git.pullrequest.')) {
79
+ const branches = [branchFromRef(resource.targetRefName), branchFromRef(resource.sourceRefName)]
80
+ .filter((b) => b !== null);
81
+ return { source: 'azure-devops', branches: unique(branches), invalid: [] };
82
+ }
83
+ }
84
+ // GitLab events all carry `object_kind`. Only a push (or a tag push, which
85
+ // names no branch) is a statement about a ref; anything else with a stray
86
+ // `ref` — a merge request, a pipeline — is not, and takes the "everything"
87
+ // fallback rather than being read as a push of that ref.
88
+ if (typeof body.object_kind === 'string') {
89
+ if (body.object_kind !== 'push' && body.object_kind !== 'tag_push') {
90
+ return { source: 'none', branches: 'all', invalid: [] };
91
+ }
92
+ // A deletion (a push to the null sha) names its branch like any push: the
93
+ // sync finds it gone and retires the clone.
94
+ const branch = branchFromRef(body.ref);
95
+ return { source: 'gitlab', branches: branch ? [branch] : [], invalid: [] };
96
+ }
97
+ // GitHub / Gitea push: `ref` at the top level, no `object_kind`. A deletion
98
+ // (`deleted: true`) names its branch like any push, for the same reason.
99
+ if (typeof body.ref === 'string') {
100
+ const branch = branchFromRef(body.ref);
101
+ return { source: 'github', branches: branch ? [branch] : [], invalid: [] };
102
+ }
103
+ return { source: 'none', branches: 'all', invalid: [] };
104
+ }
105
+ //# sourceMappingURL=sync-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-payload.js","sourceRoot":"","sources":["../../../src/modules/kb-sync/sync-payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import express from 'express';
2
+ import type { AuthUser } from '@bevel-software/platform-shared';
3
+ import type { MarketplaceRepoService } from './marketplace-repo.service.js';
4
+ import '../tool-auth/external-api-key.interface.js';
5
+ /** How a bearer string resolves to a user — the connection-key service's shape. */
6
+ export interface MarketplaceKeyResolver {
7
+ looksLikeExternalApiKey(token: string): boolean;
8
+ verifyAndLoadToken(plaintext: string): Promise<{
9
+ tokenId: string;
10
+ user: AuthUser;
11
+ } | null>;
12
+ }
13
+ /**
14
+ * The per-user marketplace as a git remote:
15
+ *
16
+ * git clone https://key:<connection-key>@<host>/git/marketplace.git
17
+ *
18
+ * Anything that speaks git's smart HTTP protocol — Claude Code, Codex, `npx
19
+ * skills`, plain git — clones a repository whose `main` is the caller's
20
+ * compiled tree. The route authenticates, brings the caller's namespace up to
21
+ * date (`MarketplaceRepoService.ensureCompiled`), and hands the request to
22
+ * `git http-backend` with `GIT_NAMESPACE` set, so git itself serves the
23
+ * protocol and only that namespace's refs exist as far as the client can tell.
24
+ *
25
+ * AUTH: HTTP Basic with the connection key as the password (the username is
26
+ * anything — git sends whatever the URL carried), or the key as a Bearer
27
+ * token. The same keys the MCP endpoint takes, the same service resolving
28
+ * them, and the same metering stamp (`req.externalApiKeyId`), so a key's
29
+ * `lastUsedAt` moves when an agent refreshes its plugins. A 401 challenges
30
+ * with Basic so a client without credentials prompts for them.
31
+ *
32
+ * READ-ONLY: the receive-pack service is refused here by name, and the bare
33
+ * repository pins `http.receivepack=false` for good measure — a push would
34
+ * otherwise be enabled by http-backend the moment REMOTE_USER is set.
35
+ */
36
+ export declare function createMarketplaceGitRoutes(deps: {
37
+ repo: MarketplaceRepoService;
38
+ keys: MarketplaceKeyResolver;
39
+ /** The URL path the router is mounted at, e.g. `/git`. Used for PATH_INFO. */
40
+ mountPath: string;
41
+ }): express.Router;
42
+ //# sourceMappingURL=git-http.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-http.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/marketplace/git-http.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,4CAA4C,CAAC;AAEpD,mFAAmF;AACnF,MAAM,WAAW,sBAAsB;IACrC,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAChD,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAC5F;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,IAAI,EAAE,sBAAsB,CAAC;IAC7B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAwJjB"}
@@ -0,0 +1,190 @@
1
+ import express from 'express';
2
+ import { spawn } from 'node:child_process';
3
+ import '../tool-auth/external-api-key.interface.js'; // Express Request augmentation (req.externalApiKeyId)
4
+ /**
5
+ * The per-user marketplace as a git remote:
6
+ *
7
+ * git clone https://key:<connection-key>@<host>/git/marketplace.git
8
+ *
9
+ * Anything that speaks git's smart HTTP protocol — Claude Code, Codex, `npx
10
+ * skills`, plain git — clones a repository whose `main` is the caller's
11
+ * compiled tree. The route authenticates, brings the caller's namespace up to
12
+ * date (`MarketplaceRepoService.ensureCompiled`), and hands the request to
13
+ * `git http-backend` with `GIT_NAMESPACE` set, so git itself serves the
14
+ * protocol and only that namespace's refs exist as far as the client can tell.
15
+ *
16
+ * AUTH: HTTP Basic with the connection key as the password (the username is
17
+ * anything — git sends whatever the URL carried), or the key as a Bearer
18
+ * token. The same keys the MCP endpoint takes, the same service resolving
19
+ * them, and the same metering stamp (`req.externalApiKeyId`), so a key's
20
+ * `lastUsedAt` moves when an agent refreshes its plugins. A 401 challenges
21
+ * with Basic so a client without credentials prompts for them.
22
+ *
23
+ * READ-ONLY: the receive-pack service is refused here by name, and the bare
24
+ * repository pins `http.receivepack=false` for good measure — a push would
25
+ * otherwise be enabled by http-backend the moment REMOTE_USER is set.
26
+ */
27
+ export function createMarketplaceGitRoutes(deps) {
28
+ const { repo, keys, mountPath } = deps;
29
+ const router = express.Router();
30
+ const repoRoute = `/${repo.repoName}`;
31
+ const challenge = (res, message) => {
32
+ res.setHeader('WWW-Authenticate', 'Basic realm="hexis-marketplace"');
33
+ res.status(401).type('text/plain').send(message);
34
+ };
35
+ /** The connection key out of Basic (`user:key`, `key:` or `:key`) or Bearer. */
36
+ const keyOf = (header) => {
37
+ if (!header)
38
+ return null;
39
+ const space = header.indexOf(' ');
40
+ if (space < 0)
41
+ return null;
42
+ const scheme = header.slice(0, space).toLowerCase();
43
+ const value = header.slice(space + 1).trim();
44
+ if (scheme === 'bearer')
45
+ return value || null;
46
+ if (scheme !== 'basic')
47
+ return null;
48
+ let decoded;
49
+ try {
50
+ decoded = Buffer.from(value, 'base64').toString('utf-8');
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ const colon = decoded.indexOf(':');
56
+ const user = colon < 0 ? decoded : decoded.slice(0, colon);
57
+ const pass = colon < 0 ? '' : decoded.slice(colon + 1);
58
+ // Either half may carry the key: `https://key:<k>@` puts it in the
59
+ // password, `https://<k>@` in the username.
60
+ if (pass && keys.looksLikeExternalApiKey(pass))
61
+ return pass;
62
+ if (user && keys.looksLikeExternalApiKey(user))
63
+ return user;
64
+ return pass || user || null;
65
+ };
66
+ router.all(`${repoRoute}{/*rest}`, async (req, res) => {
67
+ const service = String(req.query.service ?? '');
68
+ const rest = `/${[].concat(req.params.rest ?? []).join('/')}`;
69
+ // Refuse writes before touching anything — by service name on info/refs,
70
+ // and by endpoint on the POST.
71
+ if (service === 'git-receive-pack' || rest === '/git-receive-pack') {
72
+ res.status(403).type('text/plain').send('This repository is read-only.');
73
+ return;
74
+ }
75
+ const key = keyOf(req.headers.authorization);
76
+ if (!key || !keys.looksLikeExternalApiKey(key)) {
77
+ challenge(res, 'A connection key is required: https://key:<connection-key>@<host>/git/marketplace.git');
78
+ return;
79
+ }
80
+ let resolved;
81
+ try {
82
+ resolved = await keys.verifyAndLoadToken(key);
83
+ }
84
+ catch (err) {
85
+ console.error('[marketplace] connection-key verification failed:', err);
86
+ res.status(500).type('text/plain').send('Authentication backend unavailable');
87
+ return;
88
+ }
89
+ if (!resolved) {
90
+ challenge(res, 'Invalid or revoked connection key');
91
+ return;
92
+ }
93
+ req.userId = resolved.user.id;
94
+ req.userEmail = resolved.user.email;
95
+ req.externalApiKeyId = resolved.tokenId;
96
+ let ensured;
97
+ try {
98
+ ensured = await repo.ensureCompiled({ id: resolved.user.id, email: resolved.user.email });
99
+ }
100
+ catch (err) {
101
+ console.error('[marketplace] compile failed:', err);
102
+ res.status(500).type('text/plain').send('Could not prepare your marketplace');
103
+ return;
104
+ }
105
+ // CGI, as git documents it. PATH_INFO is the path below GIT_PROJECT_ROOT
106
+ // — `/marketplace.git/info/refs` — regardless of where we are mounted.
107
+ const query = req.url.includes('?') ? req.url.slice(req.url.indexOf('?') + 1) : '';
108
+ const env = {
109
+ ...process.env,
110
+ GIT_PROJECT_ROOT: repo.projectRoot,
111
+ GIT_HTTP_EXPORT_ALL: '1',
112
+ GIT_NAMESPACE: ensured.namespace,
113
+ PATH_INFO: `${repoRoute}${rest}`,
114
+ REQUEST_METHOD: req.method,
115
+ QUERY_STRING: query,
116
+ CONTENT_TYPE: req.headers['content-type'] ?? '',
117
+ REMOTE_USER: resolved.user.email,
118
+ REMOTE_ADDR: req.ip ?? '',
119
+ SERVER_PROTOCOL: 'HTTP/1.1',
120
+ HTTP_HOST: req.headers.host ?? '',
121
+ SCRIPT_NAME: mountPath,
122
+ };
123
+ if (req.headers['content-length'])
124
+ env.CONTENT_LENGTH = String(req.headers['content-length']);
125
+ if (req.headers['content-encoding'])
126
+ env.HTTP_CONTENT_ENCODING = String(req.headers['content-encoding']);
127
+ if (req.headers['git-protocol'])
128
+ env.HTTP_GIT_PROTOCOL = String(req.headers['git-protocol']);
129
+ const child = spawn('git', ['http-backend'], { env, stdio: ['pipe', 'pipe', 'pipe'] });
130
+ child.stderr.on('data', (chunk) => console.warn(`[marketplace] http-backend: ${chunk.toString('utf-8').trim()}`));
131
+ child.on('error', (err) => {
132
+ console.error('[marketplace] could not run git http-backend:', err);
133
+ if (!res.headersSent)
134
+ res.status(500).type('text/plain').send('git is unavailable');
135
+ });
136
+ req.pipe(child.stdin);
137
+ req.on('aborted', () => child.kill());
138
+ // Parse the CGI header block (`Status:`, `Content-Type:`, …) off stdout,
139
+ // then stream the body straight through.
140
+ let headerBuf = Buffer.alloc(0);
141
+ let headersDone = false;
142
+ // Backpressure: a slow client must not make Node buffer a whole pack. One
143
+ // path for every body write, the remainder of the header chunk included.
144
+ const writeBody = (bytes) => {
145
+ if (!res.write(bytes)) {
146
+ child.stdout.pause();
147
+ res.once('drain', () => child.stdout.resume());
148
+ }
149
+ };
150
+ child.stdout.on('data', (chunk) => {
151
+ if (headersDone) {
152
+ writeBody(chunk);
153
+ return;
154
+ }
155
+ headerBuf = Buffer.concat([headerBuf, chunk]);
156
+ const cut = headerBuf.indexOf('\r\n\r\n') >= 0 ? headerBuf.indexOf('\r\n\r\n') : headerBuf.indexOf('\n\n');
157
+ if (cut < 0)
158
+ return;
159
+ const sepLen = headerBuf.indexOf('\r\n\r\n') >= 0 ? 4 : 2;
160
+ const head = headerBuf.subarray(0, cut).toString('utf-8');
161
+ let status = 200;
162
+ for (const line of head.split(/\r?\n/)) {
163
+ const colon = line.indexOf(':');
164
+ if (colon < 0)
165
+ continue;
166
+ const name = line.slice(0, colon).trim();
167
+ const value = line.slice(colon + 1).trim();
168
+ if (name.toLowerCase() === 'status')
169
+ status = Number.parseInt(value, 10) || 200;
170
+ else
171
+ res.setHeader(name, value);
172
+ }
173
+ res.status(status);
174
+ headersDone = true;
175
+ const body = headerBuf.subarray(cut + sepLen);
176
+ if (body.length > 0)
177
+ writeBody(body);
178
+ });
179
+ child.stdout.on('end', () => {
180
+ if (!headersDone) {
181
+ if (!res.headersSent)
182
+ res.status(502).type('text/plain').send('git http-backend produced no response');
183
+ return;
184
+ }
185
+ res.end();
186
+ });
187
+ });
188
+ return router;
189
+ }
190
+ //# sourceMappingURL=git-http.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-http.routes.js","sourceRoot":"","sources":["../../../src/modules/marketplace/git-http.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,4CAA4C,CAAC,CAAC,sDAAsD;AAQ3G;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAK1C;IACC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IACvC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;IAEtC,MAAM,SAAS,GAAG,CAAC,GAAqB,EAAE,OAAe,EAAE,EAAE;QAC3D,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,iCAAiC,CAAC,CAAC;QACrE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC,CAAC;IAEF,gFAAgF;IAChF,MAAM,KAAK,GAAG,CAAC,MAA0B,EAAiB,EAAE;QAC1D,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,MAAM,KAAK,QAAQ;YAAE,OAAO,KAAK,IAAI,IAAI,CAAC;QAC9C,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACpC,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACvD,mEAAmE;QACnE,4CAA4C;QAC5C,IAAI,IAAI,IAAI,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5D,IAAI,IAAI,IAAI,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5D,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;IAC9B,CAAC,CAAC;IAEF,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACpD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAK,EAAe,CAAC,MAAM,CAAE,GAAG,CAAC,MAAuC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9G,yEAAyE;QACzE,+BAA+B;QAC/B,IAAI,OAAO,KAAK,kBAAkB,IAAI,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACnE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YACzE,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,SAAS,CAAC,GAAG,EAAE,uFAAuF,CAAC,CAAC;YACxG,OAAO;QACT,CAAC;QACD,IAAI,QAAoD,CAAC;QACzD,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,mDAAmD,EAAE,GAAG,CAAC,CAAC;YACxE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,SAAS,CAAC,GAAG,EAAE,mCAAmC,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QACD,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QACpC,GAAG,CAAC,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC;QAExC,IAAI,OAA8B,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;YACpD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,yEAAyE;QACzE,uEAAuE;QACvE,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnF,MAAM,GAAG,GAAsB;YAC7B,GAAG,OAAO,CAAC,GAAG;YACd,gBAAgB,EAAE,IAAI,CAAC,WAAW;YAClC,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,OAAO,CAAC,SAAS;YAChC,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,EAAE;YAChC,cAAc,EAAE,GAAG,CAAC,MAAM;YAC1B,YAAY,EAAE,KAAK;YACnB,YAAY,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE;YAC/C,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK;YAChC,WAAW,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE;YACzB,eAAe,EAAE,UAAU;YAC3B,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE;YACjC,WAAW,EAAE,SAAS;SACvB,CAAC;QACF,IAAI,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC;YAAE,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC9F,IAAI,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC;YAAE,GAAG,CAAC,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;QACzG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC;YAAE,GAAG,CAAC,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;QAE7F,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACvF,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,+BAA+B,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1H,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;YACpE,IAAI,CAAC,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACtF,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtB,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAEtC,yEAAyE;QACzE,yCAAyC;QACzC,IAAI,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,0EAA0E;QAC1E,yEAAyE;QACzE,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE;YAClC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtB,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC,CAAC;QACF,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,IAAI,WAAW,EAAE,CAAC;gBAChB,SAAS,CAAC,KAAK,CAAC,CAAC;gBACjB,OAAO;YACT,CAAC;YACD,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3G,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO;YACpB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC1D,IAAI,MAAM,GAAG,GAAG,CAAC;YACjB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,KAAK,GAAG,CAAC;oBAAE,SAAS;gBACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;gBACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3C,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,QAAQ;oBAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;;oBAC3E,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAClC,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnB,WAAW,GAAG,IAAI,CAAC;YACnB,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;YAC9C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,IAAI,CAAC,GAAG,CAAC,WAAW;oBAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;gBACvG,OAAO;YACT,CAAC;YACD,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import express from 'express';
2
+ import '../../auth/auth.middleware.js';
3
+ import { type GitHubFacadeCredentialsService } from './github-facade-credentials.service.js';
4
+ export interface GitHubFacadeAdminRoutesDeps {
5
+ credentials: GitHubFacadeCredentialsService;
6
+ isAdmin(email: string | undefined): Promise<boolean>;
7
+ /** The deployment's public address; only its host is shown. */
8
+ publicUrl: string;
9
+ /** The marketplace URL people paste — the same one Claude Code clones. */
10
+ marketplaceUrl: string;
11
+ }
12
+ /**
13
+ * What an Owner needs to register this deployment in Claude's admin settings
14
+ * as a GitHub Enterprise Server, in the fields that form has — and the one
15
+ * verb on it, rotate. Admins only: the client secret is what makes claude.ai
16
+ * trust the token exchange. Never cached: after a rotation or a sign-out no
17
+ * copy of the old secrets may linger in a browser or a proxy.
18
+ *
19
+ * GET /api/admin/github-facade the credentials and the two URLs
20
+ * POST /api/admin/github-facade/rotate new credentials, all of them
21
+ */
22
+ export declare function createGitHubFacadeAdminRoutes(deps: GitHubFacadeAdminRoutesDeps): express.Router;
23
+ //# sourceMappingURL=github-facade-admin.routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-facade-admin.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/marketplace/github-facade/github-facade-admin.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,wCAAwC,CAAC;AAEhD,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,8BAA8B,CAAC;IAC5C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,CAmD/F"}
@@ -0,0 +1,59 @@
1
+ import express from 'express';
2
+ import '../../auth/auth.middleware.js'; // Express Request.userId / userEmail augmentation
3
+ import { GitHubFacadeUnavailableError, } from './github-facade-credentials.service.js';
4
+ /**
5
+ * What an Owner needs to register this deployment in Claude's admin settings
6
+ * as a GitHub Enterprise Server, in the fields that form has — and the one
7
+ * verb on it, rotate. Admins only: the client secret is what makes claude.ai
8
+ * trust the token exchange. Never cached: after a rotation or a sign-out no
9
+ * copy of the old secrets may linger in a browser or a proxy.
10
+ *
11
+ * GET /api/admin/github-facade the credentials and the two URLs
12
+ * POST /api/admin/github-facade/rotate new credentials, all of them
13
+ */
14
+ export function createGitHubFacadeAdminRoutes(deps) {
15
+ const router = express.Router();
16
+ const requireAdmin = async (req, res, next) => {
17
+ if (!(await deps.isAdmin(req.userEmail))) {
18
+ res.status(403).json({ error: 'Admins only' });
19
+ return;
20
+ }
21
+ next();
22
+ };
23
+ const describe = async () => {
24
+ const creds = await deps.credentials.ensure();
25
+ return {
26
+ host: new URL(deps.publicUrl).host,
27
+ appId: creds.appId,
28
+ clientId: creds.clientId,
29
+ clientSecret: creds.clientSecret,
30
+ webhookSecret: creds.webhookSecret,
31
+ privateKeyPem: creds.privateKeyPem,
32
+ marketplaceUrl: deps.marketplaceUrl,
33
+ createdAt: creds.createdAt.getTime(),
34
+ rotatedAt: creds.rotatedAt ? creds.rotatedAt.getTime() : null,
35
+ };
36
+ };
37
+ const send = async (res, body) => {
38
+ try {
39
+ const payload = await body();
40
+ res.setHeader('Cache-Control', 'no-store');
41
+ res.json(payload);
42
+ }
43
+ catch (err) {
44
+ if (err instanceof GitHubFacadeUnavailableError) {
45
+ res.status(409).json({ error: err.message });
46
+ return;
47
+ }
48
+ console.error('[github-facade admin]', err);
49
+ res.status(500).json({ error: 'Internal error' });
50
+ }
51
+ };
52
+ router.get('/admin/github-facade', requireAdmin, (_req, res) => send(res, describe));
53
+ router.post('/admin/github-facade/rotate', requireAdmin, (_req, res) => send(res, async () => {
54
+ await deps.credentials.rotate();
55
+ return describe();
56
+ }));
57
+ return router;
58
+ }
59
+ //# sourceMappingURL=github-facade-admin.routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-facade-admin.routes.js","sourceRoot":"","sources":["../../../../src/modules/marketplace/github-facade/github-facade-admin.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,+BAA+B,CAAC,CAAC,kDAAkD;AAC1F,OAAO,EACL,4BAA4B,GAE7B,MAAM,wCAAwC,CAAC;AAWhD;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAAiC;IAC7E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,YAAY,GAA2B,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpE,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;YAC/C,OAAO;QACT,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAC9C,OAAO;YACL,IAAI,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI;YAClC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE;YACpC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI;SAC9D,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,KAAK,EAAE,GAAqB,EAAE,IAA4B,EAAE,EAAE;QACzE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;YAC3C,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;gBAChD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7C,OAAO;YACT,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IAErF,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CACrE,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACnB,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAChC,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,59 @@
1
+ import type { Database } from '../../database/connection.js';
2
+ /**
3
+ * A one-time code the consent page issued, waiting for Anthropic's backend
4
+ * to exchange it. Looked up by the code's hash; the plaintext travels once,
5
+ * in the redirect.
6
+ */
7
+ export interface PendingFacadeCode {
8
+ codeHash: string;
9
+ userId: string;
10
+ clientId: string;
11
+ redirectUri: string;
12
+ expiresAt: Date;
13
+ }
14
+ /**
15
+ * Where pending codes live. The database in production, so the consent
16
+ * finish on one replica and the exchange on another see the same row.
17
+ *
18
+ * The rule "one live code per person" is the TABLE'S: the person is its
19
+ * primary key, so issuing is an upsert — the newest code overwrites the last
20
+ * in one statement, two finishes racing each other cannot both leave a row
21
+ * behind, and the table holds at most one row per user, which goes when the
22
+ * user does. That is the whole bound; nothing here ever sweeps, and no
23
+ * rotation of the client id can strand a row, because the client id is data
24
+ * the exchange checks rather than part of the key. Spending is one
25
+ * conditional update: the first exchange wins, on whichever replica, and
26
+ * every later attempt finds the code spent. Nothing in memory takes part in
27
+ * either guarantee.
28
+ */
29
+ export interface GitHubFacadeCodeStore {
30
+ /** Store a fresh code, replacing whatever the same person had. */
31
+ put(code: PendingFacadeCode): Promise<void>;
32
+ /** The live (unspent, unexpired) code with this hash, without spending it. */
33
+ peek(codeHash: string): Promise<PendingFacadeCode | null>;
34
+ /** Spend the code if it is live; null when it was not (unknown, spent, expired). */
35
+ consume(codeHash: string): Promise<PendingFacadeCode | null>;
36
+ }
37
+ export declare class DbGitHubFacadeCodeStore implements GitHubFacadeCodeStore {
38
+ private readonly db;
39
+ constructor(db: Database);
40
+ put(code: PendingFacadeCode): Promise<void>;
41
+ peek(codeHash: string): Promise<PendingFacadeCode | null>;
42
+ consume(codeHash: string): Promise<PendingFacadeCode | null>;
43
+ }
44
+ /**
45
+ * For tests: the same rules over a map keyed the way the table is. Share one
46
+ * instance to model shared storage. Check-and-mark is synchronous, as the
47
+ * database's conditional update is atomic: two exchanges of one code cannot
48
+ * both win here either.
49
+ */
50
+ export declare class MemoryGitHubFacadeCodeStore implements GitHubFacadeCodeStore {
51
+ private readonly rows;
52
+ put(code: PendingFacadeCode): Promise<void>;
53
+ peek(codeHash: string): Promise<PendingFacadeCode | null>;
54
+ consume(codeHash: string): Promise<PendingFacadeCode | null>;
55
+ /** How many rows the store holds — at most one per person. */
56
+ get size(): number;
57
+ private findLive;
58
+ }
59
+ //# sourceMappingURL=github-facade-codes.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-facade-codes.store.d.ts","sourceRoot":"","sources":["../../../../src/modules/marketplace/github-facade/github-facade-codes.store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,GAAG,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,8EAA8E;IAC9E,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC1D,oFAAoF;IACpF,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CAC9D;AAED,qBAAa,uBAAwB,YAAW,qBAAqB;IACvD,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEnC,GAAG,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAe3C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IASzD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;CAQnE;AAqBD;;;;;GAKG;AACH,qBAAa,2BAA4B,YAAW,qBAAqB;IACvE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsE;IAErF,GAAG,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAKzD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAOlE,8DAA8D;IAC9D,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,QAAQ;CAOjB"}
@@ -0,0 +1,96 @@
1
+ import { and, eq, gt, isNull } from 'drizzle-orm';
2
+ import { githubFacadeCodes } from '../../database/schema.js';
3
+ export class DbGitHubFacadeCodeStore {
4
+ db;
5
+ constructor(db) {
6
+ this.db = db;
7
+ }
8
+ async put(code) {
9
+ const fresh = {
10
+ clientId: code.clientId,
11
+ codeHash: code.codeHash,
12
+ redirectUri: code.redirectUri,
13
+ expiresAt: code.expiresAt,
14
+ consumedAt: null,
15
+ createdAt: new Date(),
16
+ };
17
+ await this.db
18
+ .insert(githubFacadeCodes)
19
+ .values({ userId: code.userId, ...fresh })
20
+ .onConflictDoUpdate({ target: githubFacadeCodes.userId, set: fresh });
21
+ }
22
+ async peek(codeHash) {
23
+ const [row] = await this.db
24
+ .select()
25
+ .from(githubFacadeCodes)
26
+ .where(live(codeHash))
27
+ .limit(1);
28
+ return row ? toPending(row) : null;
29
+ }
30
+ async consume(codeHash) {
31
+ const [row] = await this.db
32
+ .update(githubFacadeCodes)
33
+ .set({ consumedAt: new Date() })
34
+ .where(live(codeHash))
35
+ .returning();
36
+ return row ? toPending(row) : null;
37
+ }
38
+ }
39
+ /** The one definition of "live": this hash, unspent, unexpired. */
40
+ function live(codeHash) {
41
+ return and(eq(githubFacadeCodes.codeHash, codeHash), isNull(githubFacadeCodes.consumedAt), gt(githubFacadeCodes.expiresAt, new Date()));
42
+ }
43
+ function toPending(row) {
44
+ return {
45
+ codeHash: row.codeHash,
46
+ userId: row.userId,
47
+ clientId: row.clientId,
48
+ redirectUri: row.redirectUri,
49
+ expiresAt: row.expiresAt,
50
+ };
51
+ }
52
+ /**
53
+ * For tests: the same rules over a map keyed the way the table is. Share one
54
+ * instance to model shared storage. Check-and-mark is synchronous, as the
55
+ * database's conditional update is atomic: two exchanges of one code cannot
56
+ * both win here either.
57
+ */
58
+ export class MemoryGitHubFacadeCodeStore {
59
+ rows = new Map();
60
+ async put(code) {
61
+ this.rows.set(code.userId, { ...code, consumedAt: null });
62
+ }
63
+ async peek(codeHash) {
64
+ const row = this.findLive(codeHash);
65
+ return row ? strip(row) : null;
66
+ }
67
+ async consume(codeHash) {
68
+ const row = this.findLive(codeHash);
69
+ if (!row)
70
+ return null;
71
+ row.consumedAt = new Date();
72
+ return strip(row);
73
+ }
74
+ /** How many rows the store holds — at most one per person. */
75
+ get size() {
76
+ return this.rows.size;
77
+ }
78
+ findLive(codeHash) {
79
+ const now = Date.now();
80
+ for (const row of this.rows.values()) {
81
+ if (row.codeHash === codeHash && row.consumedAt === null && row.expiresAt.getTime() > now)
82
+ return row;
83
+ }
84
+ return null;
85
+ }
86
+ }
87
+ function strip(row) {
88
+ return {
89
+ codeHash: row.codeHash,
90
+ userId: row.userId,
91
+ clientId: row.clientId,
92
+ redirectUri: row.redirectUri,
93
+ expiresAt: row.expiresAt,
94
+ };
95
+ }
96
+ //# sourceMappingURL=github-facade-codes.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-facade-codes.store.js","sourceRoot":"","sources":["../../../../src/modules/marketplace/github-facade/github-facade-codes.store.ts"],"names":[],"mappings":"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"}