@oscharko-dev/keiko-server 0.2.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 (509) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/assistant-response.d.ts +6 -0
  3. package/dist/assistant-response.d.ts.map +1 -0
  4. package/dist/assistant-response.js +12 -0
  5. package/dist/browser.d.ts +11 -0
  6. package/dist/browser.d.ts.map +1 -0
  7. package/dist/browser.js +245 -0
  8. package/dist/chat-handlers.d.ts +48 -0
  9. package/dist/chat-handlers.d.ts.map +1 -0
  10. package/dist/chat-handlers.js +821 -0
  11. package/dist/chat-stream-handlers.d.ts +4 -0
  12. package/dist/chat-stream-handlers.d.ts.map +1 -0
  13. package/dist/chat-stream-handlers.js +136 -0
  14. package/dist/conversation-prompt.d.ts +8 -0
  15. package/dist/conversation-prompt.d.ts.map +1 -0
  16. package/dist/conversation-prompt.js +36 -0
  17. package/dist/conversation-validation.d.ts +26 -0
  18. package/dist/conversation-validation.d.ts.map +1 -0
  19. package/dist/conversation-validation.js +125 -0
  20. package/dist/credentialPersistence.d.ts +23 -0
  21. package/dist/credentialPersistence.d.ts.map +1 -0
  22. package/dist/credentialPersistence.js +93 -0
  23. package/dist/credentialVault.d.ts +30 -0
  24. package/dist/credentialVault.d.ts.map +1 -0
  25. package/dist/credentialVault.js +206 -0
  26. package/dist/csp.d.ts +3 -0
  27. package/dist/csp.d.ts.map +1 -0
  28. package/dist/csp.js +75 -0
  29. package/dist/deps.d.ts +78 -0
  30. package/dist/deps.d.ts.map +1 -0
  31. package/dist/deps.js +457 -0
  32. package/dist/editor/agentRoutes.d.ts +7 -0
  33. package/dist/editor/agentRoutes.d.ts.map +1 -0
  34. package/dist/editor/agentRoutes.js +197 -0
  35. package/dist/editor/assuredGateRunner.d.ts +36 -0
  36. package/dist/editor/assuredGateRunner.d.ts.map +1 -0
  37. package/dist/editor/assuredGateRunner.js +100 -0
  38. package/dist/editor/assuredPreFilter.d.ts +34 -0
  39. package/dist/editor/assuredPreFilter.d.ts.map +1 -0
  40. package/dist/editor/assuredPreFilter.js +134 -0
  41. package/dist/editor/assuredPreFilterRunner.d.ts +31 -0
  42. package/dist/editor/assuredPreFilterRunner.d.ts.map +1 -0
  43. package/dist/editor/assuredPreFilterRunner.js +312 -0
  44. package/dist/editor/builtinLanguageProviders.d.ts +6 -0
  45. package/dist/editor/builtinLanguageProviders.d.ts.map +1 -0
  46. package/dist/editor/builtinLanguageProviders.js +221 -0
  47. package/dist/editor/codingContext.d.ts +12 -0
  48. package/dist/editor/codingContext.d.ts.map +1 -0
  49. package/dist/editor/codingContext.js +121 -0
  50. package/dist/editor/codingContextEvidence.d.ts +7 -0
  51. package/dist/editor/codingContextEvidence.d.ts.map +1 -0
  52. package/dist/editor/codingContextEvidence.js +52 -0
  53. package/dist/editor/codingContextProviders.d.ts +36 -0
  54. package/dist/editor/codingContextProviders.d.ts.map +1 -0
  55. package/dist/editor/codingContextProviders.js +348 -0
  56. package/dist/editor/completionModelEvidence.d.ts +16 -0
  57. package/dist/editor/completionModelEvidence.d.ts.map +1 -0
  58. package/dist/editor/completionModelEvidence.js +50 -0
  59. package/dist/editor/completionRoutes.d.ts +37 -0
  60. package/dist/editor/completionRoutes.d.ts.map +1 -0
  61. package/dist/editor/completionRoutes.js +411 -0
  62. package/dist/editor/contextRoutes.d.ts +6 -0
  63. package/dist/editor/contextRoutes.d.ts.map +1 -0
  64. package/dist/editor/contextRoutes.js +411 -0
  65. package/dist/editor/disposableAssuredExecution.d.ts +22 -0
  66. package/dist/editor/disposableAssuredExecution.d.ts.map +1 -0
  67. package/dist/editor/disposableAssuredExecution.js +57 -0
  68. package/dist/editor/editorCompletionModel.d.ts +47 -0
  69. package/dist/editor/editorCompletionModel.d.ts.map +1 -0
  70. package/dist/editor/editorCompletionModel.js +156 -0
  71. package/dist/editor/editorInlineCompletionModel.d.ts +34 -0
  72. package/dist/editor/editorInlineCompletionModel.d.ts.map +1 -0
  73. package/dist/editor/editorInlineCompletionModel.js +112 -0
  74. package/dist/editor/editorModelTokenBudget.d.ts +46 -0
  75. package/dist/editor/editorModelTokenBudget.d.ts.map +1 -0
  76. package/dist/editor/editorModelTokenBudget.js +121 -0
  77. package/dist/editor/inlineCompletionRateLimiter.d.ts +19 -0
  78. package/dist/editor/inlineCompletionRateLimiter.d.ts.map +1 -0
  79. package/dist/editor/inlineCompletionRateLimiter.js +46 -0
  80. package/dist/editor/inlineCompletionRoutes.d.ts +26 -0
  81. package/dist/editor/inlineCompletionRoutes.d.ts.map +1 -0
  82. package/dist/editor/inlineCompletionRoutes.js +404 -0
  83. package/dist/editor/inlineCompletionTelemetryEvidence.d.ts +5 -0
  84. package/dist/editor/inlineCompletionTelemetryEvidence.d.ts.map +1 -0
  85. package/dist/editor/inlineCompletionTelemetryEvidence.js +42 -0
  86. package/dist/editor/languageCancellation.d.ts +19 -0
  87. package/dist/editor/languageCancellation.d.ts.map +1 -0
  88. package/dist/editor/languageCancellation.js +48 -0
  89. package/dist/editor/languageProvider.d.ts +39 -0
  90. package/dist/editor/languageProvider.d.ts.map +1 -0
  91. package/dist/editor/languageProvider.js +11 -0
  92. package/dist/editor/languageRoutes.d.ts +15 -0
  93. package/dist/editor/languageRoutes.d.ts.map +1 -0
  94. package/dist/editor/languageRoutes.js +106 -0
  95. package/dist/editor/languageSanitize.d.ts +8 -0
  96. package/dist/editor/languageSanitize.d.ts.map +1 -0
  97. package/dist/editor/languageSanitize.js +101 -0
  98. package/dist/editor/languageService.d.ts +36 -0
  99. package/dist/editor/languageService.d.ts.map +1 -0
  100. package/dist/editor/languageService.js +93 -0
  101. package/dist/editor/languageServiceHost.d.ts +14 -0
  102. package/dist/editor/languageServiceHost.d.ts.map +1 -0
  103. package/dist/editor/languageServiceHost.js +242 -0
  104. package/dist/editor/localKnowledgeRetrieval.d.ts +21 -0
  105. package/dist/editor/localKnowledgeRetrieval.d.ts.map +1 -0
  106. package/dist/editor/localKnowledgeRetrieval.js +44 -0
  107. package/dist/editor/patchApplyEvidence.d.ts +21 -0
  108. package/dist/editor/patchApplyEvidence.d.ts.map +1 -0
  109. package/dist/editor/patchApplyEvidence.js +87 -0
  110. package/dist/editor/patchApplyRoutes.d.ts +16 -0
  111. package/dist/editor/patchApplyRoutes.d.ts.map +1 -0
  112. package/dist/editor/patchApplyRoutes.js +307 -0
  113. package/dist/editor/postApplyVerification.d.ts +42 -0
  114. package/dist/editor/postApplyVerification.d.ts.map +1 -0
  115. package/dist/editor/postApplyVerification.js +177 -0
  116. package/dist/editor/testGenerationEvidence.d.ts +6 -0
  117. package/dist/editor/testGenerationEvidence.d.ts.map +1 -0
  118. package/dist/editor/testGenerationEvidence.js +72 -0
  119. package/dist/editor/testGenerationPatch.d.ts +10 -0
  120. package/dist/editor/testGenerationPatch.d.ts.map +1 -0
  121. package/dist/editor/testGenerationPatch.js +66 -0
  122. package/dist/editor/testGenerationRoutes.d.ts +21 -0
  123. package/dist/editor/testGenerationRoutes.d.ts.map +1 -0
  124. package/dist/editor/testGenerationRoutes.js +254 -0
  125. package/dist/editor/testGenerationRunner.d.ts +23 -0
  126. package/dist/editor/testGenerationRunner.d.ts.map +1 -0
  127. package/dist/editor/testGenerationRunner.js +120 -0
  128. package/dist/editor/textOffsets.d.ts +6 -0
  129. package/dist/editor/textOffsets.d.ts.map +1 -0
  130. package/dist/editor/textOffsets.js +82 -0
  131. package/dist/editor/typescriptLanguageProvider.d.ts +3 -0
  132. package/dist/editor/typescriptLanguageProvider.d.ts.map +1 -0
  133. package/dist/editor/typescriptLanguageProvider.js +217 -0
  134. package/dist/evidence.d.ts +28 -0
  135. package/dist/evidence.d.ts.map +1 -0
  136. package/dist/evidence.js +145 -0
  137. package/dist/files-deny.d.ts +3 -0
  138. package/dist/files-deny.d.ts.map +1 -0
  139. package/dist/files-deny.js +12 -0
  140. package/dist/files.d.ts +97 -0
  141. package/dist/files.d.ts.map +1 -0
  142. package/dist/files.js +733 -0
  143. package/dist/gateway-setup.d.ts +10 -0
  144. package/dist/gateway-setup.d.ts.map +1 -0
  145. package/dist/gateway-setup.js +896 -0
  146. package/dist/governed-workflow.d.ts +17 -0
  147. package/dist/governed-workflow.d.ts.map +1 -0
  148. package/dist/governed-workflow.js +147 -0
  149. package/dist/grounded-answer.d.ts +12 -0
  150. package/dist/grounded-answer.d.ts.map +1 -0
  151. package/dist/grounded-answer.js +69 -0
  152. package/dist/grounded-context-index.d.ts +25 -0
  153. package/dist/grounded-context-index.d.ts.map +1 -0
  154. package/dist/grounded-context-index.js +169 -0
  155. package/dist/grounded-document-evidence.d.ts +28 -0
  156. package/dist/grounded-document-evidence.d.ts.map +1 -0
  157. package/dist/grounded-document-evidence.js +430 -0
  158. package/dist/grounded-handoff.d.ts +4 -0
  159. package/dist/grounded-handoff.d.ts.map +1 -0
  160. package/dist/grounded-handoff.js +445 -0
  161. package/dist/grounded-orchestrator.d.ts +43 -0
  162. package/dist/grounded-orchestrator.d.ts.map +1 -0
  163. package/dist/grounded-orchestrator.js +1445 -0
  164. package/dist/grounded-prompt.d.ts +2 -0
  165. package/dist/grounded-prompt.d.ts.map +1 -0
  166. package/dist/grounded-prompt.js +17 -0
  167. package/dist/grounded-qa-hybrid.d.ts +36 -0
  168. package/dist/grounded-qa-hybrid.d.ts.map +1 -0
  169. package/dist/grounded-qa-hybrid.js +762 -0
  170. package/dist/grounded-qa-multi-source.d.ts +38 -0
  171. package/dist/grounded-qa-multi-source.d.ts.map +1 -0
  172. package/dist/grounded-qa-multi-source.js +461 -0
  173. package/dist/grounded-qa.d.ts +45 -0
  174. package/dist/grounded-qa.d.ts.map +1 -0
  175. package/dist/grounded-qa.js +877 -0
  176. package/dist/grounded-rerank.d.ts +26 -0
  177. package/dist/grounded-rerank.d.ts.map +1 -0
  178. package/dist/grounded-rerank.js +72 -0
  179. package/dist/grounded-turn-registry.d.ts +23 -0
  180. package/dist/grounded-turn-registry.d.ts.map +1 -0
  181. package/dist/grounded-turn-registry.js +102 -0
  182. package/dist/headers.d.ts +3 -0
  183. package/dist/headers.d.ts.map +1 -0
  184. package/dist/headers.js +22 -0
  185. package/dist/host-check.d.ts +3 -0
  186. package/dist/host-check.d.ts.map +1 -0
  187. package/dist/host-check.js +58 -0
  188. package/dist/index.d.ts +26 -0
  189. package/dist/index.d.ts.map +1 -0
  190. package/dist/index.js +33 -0
  191. package/dist/load-csp.d.ts +3 -0
  192. package/dist/load-csp.d.ts.map +1 -0
  193. package/dist/load-csp.js +100 -0
  194. package/dist/local-knowledge-grounded-qa.d.ts +42 -0
  195. package/dist/local-knowledge-grounded-qa.d.ts.map +1 -0
  196. package/dist/local-knowledge-grounded-qa.js +678 -0
  197. package/dist/local-knowledge-handlers.d.ts +24 -0
  198. package/dist/local-knowledge-handlers.d.ts.map +1 -0
  199. package/dist/local-knowledge-handlers.js +1285 -0
  200. package/dist/local-knowledge-indexing-registry.d.ts +13 -0
  201. package/dist/local-knowledge-indexing-registry.d.ts.map +1 -0
  202. package/dist/local-knowledge-indexing-registry.js +53 -0
  203. package/dist/localKnowledgeKeyProvider.d.ts +11 -0
  204. package/dist/localKnowledgeKeyProvider.d.ts.map +1 -0
  205. package/dist/localKnowledgeKeyProvider.js +48 -0
  206. package/dist/memory-audit-event-builders.d.ts +21 -0
  207. package/dist/memory-audit-event-builders.d.ts.map +1 -0
  208. package/dist/memory-audit-event-builders.js +187 -0
  209. package/dist/memory-audit-handler.d.ts +23 -0
  210. package/dist/memory-audit-handler.d.ts.map +1 -0
  211. package/dist/memory-audit-handler.js +191 -0
  212. package/dist/memory-capture-policy.d.ts +10 -0
  213. package/dist/memory-capture-policy.d.ts.map +1 -0
  214. package/dist/memory-capture-policy.js +44 -0
  215. package/dist/memory-consolidation-handlers.d.ts +6 -0
  216. package/dist/memory-consolidation-handlers.d.ts.map +1 -0
  217. package/dist/memory-consolidation-handlers.js +491 -0
  218. package/dist/memory-consolidation-registry.d.ts +47 -0
  219. package/dist/memory-consolidation-registry.d.ts.map +1 -0
  220. package/dist/memory-consolidation-registry.js +106 -0
  221. package/dist/memory-conv-handlers.d.ts +8 -0
  222. package/dist/memory-conv-handlers.d.ts.map +1 -0
  223. package/dist/memory-conv-handlers.js +369 -0
  224. package/dist/memory-conversation-context.d.ts +13 -0
  225. package/dist/memory-conversation-context.d.ts.map +1 -0
  226. package/dist/memory-conversation-context.js +22 -0
  227. package/dist/memory-diagnostics.d.ts +29 -0
  228. package/dist/memory-diagnostics.d.ts.map +1 -0
  229. package/dist/memory-diagnostics.js +122 -0
  230. package/dist/memory-embedding.d.ts +21 -0
  231. package/dist/memory-embedding.d.ts.map +1 -0
  232. package/dist/memory-embedding.js +264 -0
  233. package/dist/memory-handlers.d.ts +19 -0
  234. package/dist/memory-handlers.d.ts.map +1 -0
  235. package/dist/memory-handlers.js +1204 -0
  236. package/dist/memory-maintenance-handlers.d.ts +35 -0
  237. package/dist/memory-maintenance-handlers.d.ts.map +1 -0
  238. package/dist/memory-maintenance-handlers.js +219 -0
  239. package/dist/memory-record-builders.d.ts +4 -0
  240. package/dist/memory-record-builders.d.ts.map +1 -0
  241. package/dist/memory-record-builders.js +19 -0
  242. package/dist/memory-retention.d.ts +31 -0
  243. package/dist/memory-retention.d.ts.map +1 -0
  244. package/dist/memory-retention.js +151 -0
  245. package/dist/memory-retrieval-signals.d.ts +12 -0
  246. package/dist/memory-retrieval-signals.d.ts.map +1 -0
  247. package/dist/memory-retrieval-signals.js +100 -0
  248. package/dist/memory-salience.d.ts +12 -0
  249. package/dist/memory-salience.d.ts.map +1 -0
  250. package/dist/memory-salience.js +154 -0
  251. package/dist/memory-scope-sanitizer.d.ts +6 -0
  252. package/dist/memory-scope-sanitizer.d.ts.map +1 -0
  253. package/dist/memory-scope-sanitizer.js +106 -0
  254. package/dist/memory-target-resolver.d.ts +4 -0
  255. package/dist/memory-target-resolver.d.ts.map +1 -0
  256. package/dist/memory-target-resolver.js +73 -0
  257. package/dist/memory-workflow-port.d.ts +14 -0
  258. package/dist/memory-workflow-port.d.ts.map +1 -0
  259. package/dist/memory-workflow-port.js +186 -0
  260. package/dist/private-json.d.ts +3 -0
  261. package/dist/private-json.d.ts.map +1 -0
  262. package/dist/private-json.js +62 -0
  263. package/dist/promptEnhancer/index.d.ts +3 -0
  264. package/dist/promptEnhancer/index.d.ts.map +1 -0
  265. package/dist/promptEnhancer/index.js +5 -0
  266. package/dist/promptEnhancer/orchestrate.d.ts +2 -0
  267. package/dist/promptEnhancer/orchestrate.d.ts.map +1 -0
  268. package/dist/promptEnhancer/orchestrate.js +5 -0
  269. package/dist/promptEnhancer/routes.d.ts +9 -0
  270. package/dist/promptEnhancer/routes.d.ts.map +1 -0
  271. package/dist/promptEnhancer/routes.js +205 -0
  272. package/dist/qualityIntelligence/capsuleAdapter.d.ts +27 -0
  273. package/dist/qualityIntelligence/capsuleAdapter.d.ts.map +1 -0
  274. package/dist/qualityIntelligence/capsuleAdapter.js +57 -0
  275. package/dist/qualityIntelligence/connectorAuthorization.d.ts +22 -0
  276. package/dist/qualityIntelligence/connectorAuthorization.d.ts.map +1 -0
  277. package/dist/qualityIntelligence/connectorAuthorization.js +35 -0
  278. package/dist/qualityIntelligence/connectorErrors.d.ts +16 -0
  279. package/dist/qualityIntelligence/connectorErrors.d.ts.map +1 -0
  280. package/dist/qualityIntelligence/connectorErrors.js +56 -0
  281. package/dist/qualityIntelligence/connectorRoutes.d.ts +7 -0
  282. package/dist/qualityIntelligence/connectorRoutes.d.ts.map +1 -0
  283. package/dist/qualityIntelligence/connectorRoutes.js +167 -0
  284. package/dist/qualityIntelligence/editRoutes.d.ts +5 -0
  285. package/dist/qualityIntelligence/editRoutes.d.ts.map +1 -0
  286. package/dist/qualityIntelligence/editRoutes.js +293 -0
  287. package/dist/qualityIntelligence/exportAssembly.d.ts +22 -0
  288. package/dist/qualityIntelligence/exportAssembly.d.ts.map +1 -0
  289. package/dist/qualityIntelligence/exportAssembly.js +352 -0
  290. package/dist/qualityIntelligence/exportRoutes.d.ts +5 -0
  291. package/dist/qualityIntelligence/exportRoutes.d.ts.map +1 -0
  292. package/dist/qualityIntelligence/exportRoutes.js +320 -0
  293. package/dist/qualityIntelligence/figma/figmaConcurrency.d.ts +8 -0
  294. package/dist/qualityIntelligence/figma/figmaConcurrency.d.ts.map +1 -0
  295. package/dist/qualityIntelligence/figma/figmaConcurrency.js +34 -0
  296. package/dist/qualityIntelligence/figma/figmaConnector.d.ts +65 -0
  297. package/dist/qualityIntelligence/figma/figmaConnector.d.ts.map +1 -0
  298. package/dist/qualityIntelligence/figma/figmaConnector.js +184 -0
  299. package/dist/qualityIntelligence/figma/figmaConnectorAudit.d.ts +52 -0
  300. package/dist/qualityIntelligence/figma/figmaConnectorAudit.d.ts.map +1 -0
  301. package/dist/qualityIntelligence/figma/figmaConnectorAudit.js +63 -0
  302. package/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts +31 -0
  303. package/dist/qualityIntelligence/figma/figmaConnectorErrors.d.ts.map +1 -0
  304. package/dist/qualityIntelligence/figma/figmaConnectorErrors.js +220 -0
  305. package/dist/qualityIntelligence/figma/figmaConnectorMetrics.d.ts +44 -0
  306. package/dist/qualityIntelligence/figma/figmaConnectorMetrics.d.ts.map +1 -0
  307. package/dist/qualityIntelligence/figma/figmaConnectorMetrics.js +49 -0
  308. package/dist/qualityIntelligence/figma/figmaConsent.d.ts +39 -0
  309. package/dist/qualityIntelligence/figma/figmaConsent.d.ts.map +1 -0
  310. package/dist/qualityIntelligence/figma/figmaConsent.js +62 -0
  311. package/dist/qualityIntelligence/figma/figmaHttpPort.d.ts +28 -0
  312. package/dist/qualityIntelligence/figma/figmaHttpPort.d.ts.map +1 -0
  313. package/dist/qualityIntelligence/figma/figmaHttpPort.js +70 -0
  314. package/dist/qualityIntelligence/figma/figmaObservedActions.d.ts +49 -0
  315. package/dist/qualityIntelligence/figma/figmaObservedActions.d.ts.map +1 -0
  316. package/dist/qualityIntelligence/figma/figmaObservedActions.js +89 -0
  317. package/dist/qualityIntelligence/figma/figmaReadiness.d.ts +32 -0
  318. package/dist/qualityIntelligence/figma/figmaReadiness.d.ts.map +1 -0
  319. package/dist/qualityIntelligence/figma/figmaReadiness.js +67 -0
  320. package/dist/qualityIntelligence/figma/figmaRenderPort.d.ts +29 -0
  321. package/dist/qualityIntelligence/figma/figmaRenderPort.d.ts.map +1 -0
  322. package/dist/qualityIntelligence/figma/figmaRenderPort.js +93 -0
  323. package/dist/qualityIntelligence/figma/figmaResnapshot.d.ts +28 -0
  324. package/dist/qualityIntelligence/figma/figmaResnapshot.d.ts.map +1 -0
  325. package/dist/qualityIntelligence/figma/figmaResnapshot.js +38 -0
  326. package/dist/qualityIntelligence/figma/figmaRetry.d.ts +31 -0
  327. package/dist/qualityIntelligence/figma/figmaRetry.d.ts.map +1 -0
  328. package/dist/qualityIntelligence/figma/figmaRetry.js +62 -0
  329. package/dist/qualityIntelligence/figma/figmaScopeRef.d.ts +9 -0
  330. package/dist/qualityIntelligence/figma/figmaScopeRef.d.ts.map +1 -0
  331. package/dist/qualityIntelligence/figma/figmaScopeRef.js +18 -0
  332. package/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts +86 -0
  333. package/dist/qualityIntelligence/figma/figmaScopedPagination.d.ts.map +1 -0
  334. package/dist/qualityIntelligence/figma/figmaScopedPagination.js +308 -0
  335. package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts +31 -0
  336. package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.d.ts.map +1 -0
  337. package/dist/qualityIntelligence/figma/figmaSnapshotBuilder.js +314 -0
  338. package/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts +18 -0
  339. package/dist/qualityIntelligence/figma/figmaSnapshotHash.d.ts.map +1 -0
  340. package/dist/qualityIntelligence/figma/figmaSnapshotHash.js +63 -0
  341. package/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts +65 -0
  342. package/dist/qualityIntelligence/figma/figmaSnapshotTypes.d.ts.map +1 -0
  343. package/dist/qualityIntelligence/figma/figmaSnapshotTypes.js +13 -0
  344. package/dist/qualityIntelligence/figma/figmaTokenSource.d.ts +9 -0
  345. package/dist/qualityIntelligence/figma/figmaTokenSource.d.ts.map +1 -0
  346. package/dist/qualityIntelligence/figma/figmaTokenSource.js +61 -0
  347. package/dist/qualityIntelligence/figma/figmaTokenStore.d.ts +19 -0
  348. package/dist/qualityIntelligence/figma/figmaTokenStore.d.ts.map +1 -0
  349. package/dist/qualityIntelligence/figma/figmaTokenStore.js +156 -0
  350. package/dist/qualityIntelligence/figma/figmaUrl.d.ts +6 -0
  351. package/dist/qualityIntelligence/figma/figmaUrl.d.ts.map +1 -0
  352. package/dist/qualityIntelligence/figma/figmaUrl.js +36 -0
  353. package/dist/qualityIntelligence/figma/index.d.ts +20 -0
  354. package/dist/qualityIntelligence/figma/index.d.ts.map +1 -0
  355. package/dist/qualityIntelligence/figma/index.js +26 -0
  356. package/dist/qualityIntelligence/figmaCodegenRoutes.d.ts +28 -0
  357. package/dist/qualityIntelligence/figmaCodegenRoutes.d.ts.map +1 -0
  358. package/dist/qualityIntelligence/figmaCodegenRoutes.js +165 -0
  359. package/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts +55 -0
  360. package/dist/qualityIntelligence/figmaSnapshotAdapter.d.ts.map +1 -0
  361. package/dist/qualityIntelligence/figmaSnapshotAdapter.js +219 -0
  362. package/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts +64 -0
  363. package/dist/qualityIntelligence/figmaSnapshotOrchestration.d.ts.map +1 -0
  364. package/dist/qualityIntelligence/figmaSnapshotOrchestration.js +203 -0
  365. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +112 -0
  366. package/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -0
  367. package/dist/qualityIntelligence/figmaSnapshotRoutes.js +1063 -0
  368. package/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts +19 -0
  369. package/dist/qualityIntelligence/figmaSnapshotScreenIds.d.ts.map +1 -0
  370. package/dist/qualityIntelligence/figmaSnapshotScreenIds.js +75 -0
  371. package/dist/qualityIntelligence/generationPort.d.ts +15 -0
  372. package/dist/qualityIntelligence/generationPort.d.ts.map +1 -0
  373. package/dist/qualityIntelligence/generationPort.js +185 -0
  374. package/dist/qualityIntelligence/handoffErrors.d.ts +9 -0
  375. package/dist/qualityIntelligence/handoffErrors.d.ts.map +1 -0
  376. package/dist/qualityIntelligence/handoffErrors.js +21 -0
  377. package/dist/qualityIntelligence/handoffRoutes.d.ts +15 -0
  378. package/dist/qualityIntelligence/handoffRoutes.d.ts.map +1 -0
  379. package/dist/qualityIntelligence/handoffRoutes.js +341 -0
  380. package/dist/qualityIntelligence/index.d.ts +17 -0
  381. package/dist/qualityIntelligence/index.d.ts.map +1 -0
  382. package/dist/qualityIntelligence/index.js +36 -0
  383. package/dist/qualityIntelligence/judgePort.d.ts +30 -0
  384. package/dist/qualityIntelligence/judgePort.d.ts.map +1 -0
  385. package/dist/qualityIntelligence/judgePort.js +326 -0
  386. package/dist/qualityIntelligence/modelSelection.d.ts +58 -0
  387. package/dist/qualityIntelligence/modelSelection.d.ts.map +1 -0
  388. package/dist/qualityIntelligence/modelSelection.js +148 -0
  389. package/dist/qualityIntelligence/reCheckRoutes.d.ts +6 -0
  390. package/dist/qualityIntelligence/reCheckRoutes.d.ts.map +1 -0
  391. package/dist/qualityIntelligence/reCheckRoutes.js +1157 -0
  392. package/dist/qualityIntelligence/retentionEnforcement.d.ts +13 -0
  393. package/dist/qualityIntelligence/retentionEnforcement.d.ts.map +1 -0
  394. package/dist/qualityIntelligence/retentionEnforcement.js +47 -0
  395. package/dist/qualityIntelligence/retentionRoutes.d.ts +8 -0
  396. package/dist/qualityIntelligence/retentionRoutes.d.ts.map +1 -0
  397. package/dist/qualityIntelligence/retentionRoutes.js +74 -0
  398. package/dist/qualityIntelligence/reviewRoutes.d.ts +5 -0
  399. package/dist/qualityIntelligence/reviewRoutes.d.ts.map +1 -0
  400. package/dist/qualityIntelligence/reviewRoutes.js +145 -0
  401. package/dist/qualityIntelligence/reviewStore.d.ts +75 -0
  402. package/dist/qualityIntelligence/reviewStore.d.ts.map +1 -0
  403. package/dist/qualityIntelligence/reviewStore.js +170 -0
  404. package/dist/qualityIntelligence/runExecution.d.ts +36 -0
  405. package/dist/qualityIntelligence/runExecution.d.ts.map +1 -0
  406. package/dist/qualityIntelligence/runExecution.js +180 -0
  407. package/dist/qualityIntelligence/runIngestion.d.ts +70 -0
  408. package/dist/qualityIntelligence/runIngestion.d.ts.map +1 -0
  409. package/dist/qualityIntelligence/runIngestion.js +1235 -0
  410. package/dist/qualityIntelligence/runRegistry.d.ts +31 -0
  411. package/dist/qualityIntelligence/runRegistry.d.ts.map +1 -0
  412. package/dist/qualityIntelligence/runRegistry.js +66 -0
  413. package/dist/qualityIntelligence/runRoutes.d.ts +16 -0
  414. package/dist/qualityIntelligence/runRoutes.d.ts.map +1 -0
  415. package/dist/qualityIntelligence/runRoutes.js +357 -0
  416. package/dist/qualityIntelligence/traceabilityRoutes.d.ts +5 -0
  417. package/dist/qualityIntelligence/traceabilityRoutes.d.ts.map +1 -0
  418. package/dist/qualityIntelligence/traceabilityRoutes.js +173 -0
  419. package/dist/qualityIntelligence/uiRoutes.d.ts +7 -0
  420. package/dist/qualityIntelligence/uiRoutes.d.ts.map +1 -0
  421. package/dist/qualityIntelligence/uiRoutes.js +336 -0
  422. package/dist/read-handlers.d.ts +9 -0
  423. package/dist/read-handlers.d.ts.map +1 -0
  424. package/dist/read-handlers.js +265 -0
  425. package/dist/relationship-handlers.d.ts +191 -0
  426. package/dist/relationship-handlers.d.ts.map +1 -0
  427. package/dist/relationship-handlers.js +0 -0
  428. package/dist/routes.d.ts +37 -0
  429. package/dist/routes.d.ts.map +1 -0
  430. package/dist/routes.js +507 -0
  431. package/dist/run-engine.d.ts +25 -0
  432. package/dist/run-engine.d.ts.map +1 -0
  433. package/dist/run-engine.js +385 -0
  434. package/dist/run-handlers.d.ts +9 -0
  435. package/dist/run-handlers.d.ts.map +1 -0
  436. package/dist/run-handlers.js +465 -0
  437. package/dist/run-request.d.ts +17 -0
  438. package/dist/run-request.d.ts.map +1 -0
  439. package/dist/run-request.js +219 -0
  440. package/dist/runs.d.ts +47 -0
  441. package/dist/runs.d.ts.map +1 -0
  442. package/dist/runs.js +100 -0
  443. package/dist/server.d.ts +13 -0
  444. package/dist/server.d.ts.map +1 -0
  445. package/dist/server.js +152 -0
  446. package/dist/sink.d.ts +28 -0
  447. package/dist/sink.d.ts.map +1 -0
  448. package/dist/sink.js +80 -0
  449. package/dist/sse-write.d.ts +9 -0
  450. package/dist/sse-write.d.ts.map +1 -0
  451. package/dist/sse-write.js +26 -0
  452. package/dist/sse.d.ts +8 -0
  453. package/dist/sse.d.ts.map +1 -0
  454. package/dist/sse.js +27 -0
  455. package/dist/static.d.ts +5 -0
  456. package/dist/static.d.ts.map +1 -0
  457. package/dist/static.js +76 -0
  458. package/dist/store/chats.d.ts +17 -0
  459. package/dist/store/chats.d.ts.map +1 -0
  460. package/dist/store/chats.js +624 -0
  461. package/dist/store/db.d.ts +11 -0
  462. package/dist/store/db.d.ts.map +1 -0
  463. package/dist/store/db.js +203 -0
  464. package/dist/store/errors.d.ts +13 -0
  465. package/dist/store/errors.d.ts.map +1 -0
  466. package/dist/store/errors.js +30 -0
  467. package/dist/store/index.d.ts +7 -0
  468. package/dist/store/index.d.ts.map +1 -0
  469. package/dist/store/index.js +6 -0
  470. package/dist/store/messages.d.ts +8 -0
  471. package/dist/store/messages.d.ts.map +1 -0
  472. package/dist/store/messages.js +149 -0
  473. package/dist/store/paths.d.ts +5 -0
  474. package/dist/store/paths.d.ts.map +1 -0
  475. package/dist/store/paths.js +84 -0
  476. package/dist/store/projects.d.ts +8 -0
  477. package/dist/store/projects.d.ts.map +1 -0
  478. package/dist/store/projects.js +59 -0
  479. package/dist/store/relationship-audit.d.ts +42 -0
  480. package/dist/store/relationship-audit.d.ts.map +1 -0
  481. package/dist/store/relationship-audit.js +155 -0
  482. package/dist/store/relationships.d.ts +191 -0
  483. package/dist/store/relationships.d.ts.map +1 -0
  484. package/dist/store/relationships.js +724 -0
  485. package/dist/store/schema.d.ts +4 -0
  486. package/dist/store/schema.d.ts.map +1 -0
  487. package/dist/store/schema.js +220 -0
  488. package/dist/store/types.d.ts +29 -0
  489. package/dist/store/types.d.ts.map +1 -0
  490. package/dist/store/types.js +8 -0
  491. package/dist/store/validation.d.ts +7 -0
  492. package/dist/store/validation.d.ts.map +1 -0
  493. package/dist/store/validation.js +117 -0
  494. package/dist/store-handlers.d.ts +17 -0
  495. package/dist/store-handlers.d.ts.map +1 -0
  496. package/dist/store-handlers.js +872 -0
  497. package/dist/terminal-errors.d.ts +22 -0
  498. package/dist/terminal-errors.d.ts.map +1 -0
  499. package/dist/terminal-errors.js +45 -0
  500. package/dist/terminal-evidence.d.ts +21 -0
  501. package/dist/terminal-evidence.d.ts.map +1 -0
  502. package/dist/terminal-evidence.js +65 -0
  503. package/dist/terminal-routes.d.ts +10 -0
  504. package/dist/terminal-routes.d.ts.map +1 -0
  505. package/dist/terminal-routes.js +219 -0
  506. package/dist/terminal.d.ts +68 -0
  507. package/dist/terminal.d.ts.map +1 -0
  508. package/dist/terminal.js +855 -0
  509. package/package.json +52 -0
@@ -0,0 +1,896 @@
1
+ // First-run gateway setup for non-technical UI users. The browser provides a base URL, API token,
2
+ // and optionally a Figma PAT; the loopback BFF builds the local provider config, performs a real
3
+ // chat-completions smoke call, stores the resulting config on disk with private permissions, and
4
+ // updates the in-memory runtime config without exposing credentials back to the browser.
5
+ import { resolveEvidenceDir } from "@oscharko-dev/keiko-evidence";
6
+ import { apiKeyHeaderValue, ConfigInvalidError, DEFAULT_API_KEY_HEADER_NAME, Gateway, createDefaultChatCapability, listConfiguredCapabilities, normalizeApiKeyHeaderName, parseGatewayConfig, toSafeObject, validateBaseUrl, } from "@oscharko-dev/keiko-model-gateway";
7
+ import { gatewayFetch, readJsonCapped } from "@oscharko-dev/keiko-model-gateway/internal/http";
8
+ import { redact } from "@oscharko-dev/keiko-security";
9
+ import { errorBody } from "./routes.js";
10
+ import { currentGatewayConfig, currentGatewayEgressConfig } from "./deps.js";
11
+ import { CONVERSATION_SYSTEM_PROMPT } from "./conversation-prompt.js";
12
+ import { classifyFigmaTransportError, FigmaConnectorError, } from "./qualityIntelligence/figma/figmaConnectorErrors.js";
13
+ import { classifyTokenFailure } from "./qualityIntelligence/figma/figmaTokenSource.js";
14
+ import { persistSealedGatewayConfig } from "./credentialPersistence.js";
15
+ const MAX_BODY_BYTES = 64_000;
16
+ // Issue #144: exported so discovery-normalization tests can pin the slice cap
17
+ // without hardcoding the number. The discovery surface is a public seam.
18
+ export const MAX_DISCOVERED_MODELS = 100;
19
+ const MAX_DEPLOYMENT_NAMES = 100;
20
+ const MAX_MODEL_ID_LENGTH = 160;
21
+ const DISCOVERED_MODEL_SMOKE_TIMEOUT_MS = 15_000;
22
+ const DEPLOYMENT_SMOKE_TIMEOUT_MS = 30_000;
23
+ const FIGMA_CREDENTIAL_SMOKE_TIMEOUT_MS = 15_000;
24
+ const FIGMA_CREDENTIAL_SMOKE_RESPONSE_BYTES = 64_000;
25
+ const SETUP_SMOKE_CONCURRENCY = 4;
26
+ const CHAT_COMPATIBLE_MODES = new Set(["chat", "completion", "responses"]);
27
+ const EMBEDDING_ID_PATTERN = /(?:^|[-_/. ])(?:text-)?embed(?:ding)?s?(?:[-_/. ]|$)|ada-002(?:$|[-_/. ])/i;
28
+ class BodyTooLargeError extends Error {
29
+ constructor() {
30
+ super("request body too large");
31
+ this.name = "BodyTooLargeError";
32
+ }
33
+ }
34
+ function isRecord(value) {
35
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36
+ }
37
+ function isRouteResult(value) {
38
+ return isRecord(value) && typeof value.status === "number";
39
+ }
40
+ function readBody(req) {
41
+ return new Promise((resolve, reject) => {
42
+ const chunks = [];
43
+ let total = 0;
44
+ let capped = false;
45
+ req.on("data", (chunk) => {
46
+ total += chunk.length;
47
+ if (total > MAX_BODY_BYTES) {
48
+ if (!capped) {
49
+ capped = true;
50
+ chunks.length = 0;
51
+ reject(new BodyTooLargeError());
52
+ req.resume();
53
+ }
54
+ return;
55
+ }
56
+ chunks.push(chunk);
57
+ });
58
+ req.on("end", () => {
59
+ if (!capped) {
60
+ resolve(Buffer.concat(chunks).toString("utf8"));
61
+ }
62
+ });
63
+ req.on("error", reject);
64
+ });
65
+ }
66
+ function normalizeBaseUrl(raw) {
67
+ let value = raw.trim().replace(/\/+$/u, "");
68
+ if (value.endsWith("/chat/completions")) {
69
+ value = value.slice(0, -"/chat/completions".length).replace(/\/+$/u, "");
70
+ }
71
+ return value;
72
+ }
73
+ function candidateBaseUrls(baseUrl) {
74
+ const primary = normalizeBaseUrl(baseUrl);
75
+ const candidates = [primary];
76
+ try {
77
+ const url = new URL(primary);
78
+ if (url.hostname.endsWith(".services.ai.azure.com")) {
79
+ const openAiV1 = `${url.origin}/openai/v1`;
80
+ if (url.pathname === "" || url.pathname === "/") {
81
+ candidates.push(`${url.origin}/openai/v1`);
82
+ }
83
+ else if (primary.endsWith("/openai")) {
84
+ candidates.push(`${primary}/v1`);
85
+ }
86
+ else if (primary !== openAiV1 && !primary.endsWith("/openai/v1")) {
87
+ candidates.push(openAiV1);
88
+ }
89
+ }
90
+ else if (!primary.endsWith("/v1")) {
91
+ candidates.push(`${primary}/v1`);
92
+ }
93
+ }
94
+ catch {
95
+ if (!primary.endsWith("/v1")) {
96
+ candidates.push(`${primary}/v1`);
97
+ }
98
+ }
99
+ return Array.from(new Set(candidates));
100
+ }
101
+ function isAzureFoundryBaseUrl(baseUrl) {
102
+ try {
103
+ const url = new URL(baseUrl);
104
+ return url.hostname.endsWith(".services.ai.azure.com");
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ function providerRaw(modelId, baseUrl, apiKey, options = {}) {
111
+ const defaultCapability = options.embeddingModelIds?.includes(modelId) === true
112
+ ? createDefaultEmbeddingCapabilityForSetup(modelId)
113
+ : createDefaultChatCapability(modelId);
114
+ return {
115
+ modelId,
116
+ baseUrl,
117
+ apiKey,
118
+ apiKeyHeaderName: options.apiKeyHeaderName ?? DEFAULT_API_KEY_HEADER_NAME,
119
+ capability: options.imageInputModelIds?.includes(modelId) === true
120
+ ? { ...defaultCapability, supportsImageInput: true }
121
+ : defaultCapability,
122
+ timeoutMs: options.timeoutMs ?? 30_000,
123
+ maxRetries: options.maxRetries ?? 2,
124
+ retryBaseDelayMs: options.retryBaseDelayMs ?? 500,
125
+ };
126
+ }
127
+ function isLikelyEmbeddingModelId(modelId) {
128
+ return EMBEDDING_ID_PATTERN.test(modelId);
129
+ }
130
+ function createDefaultEmbeddingCapabilityForSetup(modelId) {
131
+ return {
132
+ id: modelId,
133
+ kind: "embedding",
134
+ contextWindow: 8_191,
135
+ maxOutputTokens: 0,
136
+ toolCalling: false,
137
+ structuredOutput: false,
138
+ streaming: false,
139
+ supportsImageInput: false,
140
+ supportsDocumentInput: false,
141
+ workflowEligible: false,
142
+ costClass: "low",
143
+ latencyClass: "fast",
144
+ throughputHint: "runtime-configured embedding endpoint",
145
+ preferredUseCases: ["Embeddings"],
146
+ knownLimitations: [
147
+ "Runtime-configured capability; validate against the target endpoint before production use",
148
+ ],
149
+ };
150
+ }
151
+ function mergeChatAndEmbeddingModelIds(chatModelIds, deploymentNames) {
152
+ const merged = [...chatModelIds];
153
+ const seen = new Set(merged);
154
+ for (const modelId of deploymentNames) {
155
+ if (!isLikelyEmbeddingModelId(modelId) || seen.has(modelId)) {
156
+ continue;
157
+ }
158
+ seen.add(modelId);
159
+ merged.push(modelId);
160
+ }
161
+ return merged;
162
+ }
163
+ function embeddingModelIdsFromDeployments(deploymentNames) {
164
+ return deploymentNames.filter(isLikelyEmbeddingModelId);
165
+ }
166
+ function buildRawConfig(baseUrl, apiKey, modelIds, options = {}) {
167
+ return {
168
+ providers: modelIds.map((modelId) => providerRaw(modelId, baseUrl, apiKey, options)),
169
+ circuitBreaker: { failureThreshold: 5, cooldownMs: 30_000, halfOpenProbes: 2 },
170
+ };
171
+ }
172
+ function currentImageInputModelIds(config) {
173
+ return (config?.capabilities
174
+ ?.filter((capability) => capability.kind === "chat" && capability.supportsImageInput)
175
+ .map((capability) => capability.id) ?? []);
176
+ }
177
+ function rawConfigFromCurrent(config, figmaAccessToken) {
178
+ return {
179
+ providers: config.providers.map((provider) => {
180
+ const capability = config.capabilities?.find((item) => item.id === provider.modelId);
181
+ return {
182
+ modelId: provider.modelId,
183
+ baseUrl: provider.baseUrl,
184
+ apiKey: provider.apiKey,
185
+ apiKeyHeaderName: provider.apiKeyHeaderName ?? DEFAULT_API_KEY_HEADER_NAME,
186
+ timeoutMs: provider.timeoutMs,
187
+ maxRetries: provider.maxRetries,
188
+ retryBaseDelayMs: provider.retryBaseDelayMs,
189
+ ...(capability === undefined ? {} : { capability }),
190
+ };
191
+ }),
192
+ circuitBreaker: config.circuitBreaker,
193
+ ...(config.capabilities === undefined ? {} : { capabilities: config.capabilities }),
194
+ ...(config.grounding === undefined ? {} : { grounding: config.grounding }),
195
+ ...(figmaAccessToken === undefined ? {} : { figma: { accessToken: figmaAccessToken } }),
196
+ };
197
+ }
198
+ function withInheritedEgress(rawConfig, egress) {
199
+ if (egress === undefined || Object.hasOwn(rawConfig, "egress")) {
200
+ return rawConfig;
201
+ }
202
+ return { ...rawConfig, egress };
203
+ }
204
+ function modelsEndpoint(baseUrl) {
205
+ return `${baseUrl}/models`;
206
+ }
207
+ function modelInfoEndpointCandidates(baseUrl) {
208
+ const normalized = normalizeBaseUrl(baseUrl);
209
+ return [`${normalized}/model/info`];
210
+ }
211
+ function apiKeyHeaders(apiKey, apiKeyHeaderName) {
212
+ return { [apiKeyHeaderName]: apiKeyHeaderValue(apiKeyHeaderName, apiKey) };
213
+ }
214
+ function hasDisallowedModelIdCharacter(id) {
215
+ for (let index = 0; index < id.length; index += 1) {
216
+ const code = id.charCodeAt(index);
217
+ if (code <= 31 || code === 127) {
218
+ return true;
219
+ }
220
+ }
221
+ return false;
222
+ }
223
+ function isUsableModelId(id) {
224
+ return id.length > 0 && id.length <= MAX_MODEL_ID_LENGTH && !hasDisallowedModelIdCharacter(id);
225
+ }
226
+ function modelIdFromKnownFields(item) {
227
+ for (const field of ["id", "model_name", "model", "deployment_name", "deploymentName"]) {
228
+ const value = item[field];
229
+ if (typeof value === "string") {
230
+ const id = value.trim();
231
+ if (isUsableModelId(id)) {
232
+ return id;
233
+ }
234
+ }
235
+ }
236
+ return undefined;
237
+ }
238
+ function nestedRecord(value, key) {
239
+ const nested = value[key];
240
+ return isRecord(nested) ? nested : undefined;
241
+ }
242
+ function modelModeFromDiscoveryItem(item) {
243
+ const modelInfo = nestedRecord(item, "model_info");
244
+ const litellmParams = nestedRecord(item, "litellm_params");
245
+ const candidates = [item.mode, modelInfo?.mode, litellmParams?.mode];
246
+ for (const candidate of candidates) {
247
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
248
+ return candidate.trim().toLowerCase();
249
+ }
250
+ }
251
+ return undefined;
252
+ }
253
+ // Issue #144: exported as part of the discovery-normalization seam so a
254
+ // sibling test file can drive it with synthetic payloads. Behaviour unchanged
255
+ // — only the visibility is widened.
256
+ export function isExplicitlyNonChatModel(item) {
257
+ const capabilities = isRecord(item.capabilities) ? item.capabilities : undefined;
258
+ if (capabilities?.chat_completion === false) {
259
+ return true;
260
+ }
261
+ const mode = modelModeFromDiscoveryItem(item);
262
+ return mode !== undefined && !CHAT_COMPATIBLE_MODES.has(mode);
263
+ }
264
+ // Issue #144: exported as part of the discovery-normalization seam. Behaviour
265
+ // unchanged. Returns undefined for unknown/non-record/non-chat/malformed input
266
+ // so callers can drop the entry silently and keep healthy peers.
267
+ export function modelIdFromDiscoveryItem(item) {
268
+ if (!isRecord(item) || isExplicitlyNonChatModel(item)) {
269
+ return undefined;
270
+ }
271
+ return modelIdFromKnownFields(item);
272
+ }
273
+ // Issue #144: exported as part of the discovery-normalization seam. Behaviour
274
+ // unchanged. Throws on schema-level malformation (no data array) and on the
275
+ // "every entry filtered" terminal case so the caller (production path) returns
276
+ // an honest error rather than a silently-empty model list.
277
+ export function parseModelList(payload) {
278
+ if (!isRecord(payload) || !Array.isArray(payload.data)) {
279
+ throw new Error("model discovery response must contain a data array");
280
+ }
281
+ const ids = [];
282
+ for (const item of payload.data) {
283
+ const id = modelIdFromDiscoveryItem(item);
284
+ if (id !== undefined) {
285
+ ids.push(id);
286
+ }
287
+ }
288
+ const unique = Array.from(new Set(ids));
289
+ if (unique.length === 0) {
290
+ throw new Error("model discovery returned no model ids");
291
+ }
292
+ return unique.slice(0, MAX_DISCOVERED_MODELS);
293
+ }
294
+ // Issue #144 AC #4: the public discovery-normalization seam. Test target. Pure
295
+ // wrapper around `parseModelList` so the AC ("Discovery handles additional
296
+ // customer gateway models without requiring code changes for each model name")
297
+ // can be pinned against a stable export name even if the internal helper is
298
+ // reshaped later.
299
+ export function normalizeDiscoveryPayload(payload) {
300
+ return parseModelList(payload);
301
+ }
302
+ async function fetchDiscoveryJson(url, apiKey, apiKeyHeaderName, egress) {
303
+ const response = await gatewayFetch(url, {
304
+ method: "GET",
305
+ headers: apiKeyHeaders(apiKey, apiKeyHeaderName),
306
+ signal: AbortSignal.timeout(30_000),
307
+ ...(egress !== undefined ? { egress } : {}),
308
+ });
309
+ if (!response.ok) {
310
+ throw new Error(`model discovery returned HTTP ${String(response.status)}`);
311
+ }
312
+ try {
313
+ return await readJsonCapped(response);
314
+ }
315
+ catch {
316
+ throw new Error("model discovery response was not readable JSON");
317
+ }
318
+ }
319
+ async function discoverLiteLlmModelInfo(baseUrl, apiKey, apiKeyHeaderName, egress) {
320
+ for (const endpoint of modelInfoEndpointCandidates(baseUrl)) {
321
+ try {
322
+ return parseModelList(await fetchDiscoveryJson(endpoint, apiKey, apiKeyHeaderName, egress));
323
+ }
324
+ catch {
325
+ // /model/info is a LiteLLM-specific enrichment endpoint. If it is absent or blocked,
326
+ // continue with OpenAI-compatible /models discovery so customer gateways are not broken.
327
+ }
328
+ }
329
+ return undefined;
330
+ }
331
+ async function defaultGatewayModelDiscovery(baseUrl, apiKey, apiKeyHeaderName = DEFAULT_API_KEY_HEADER_NAME, egress) {
332
+ const litellmModels = await discoverLiteLlmModelInfo(baseUrl, apiKey, apiKeyHeaderName, egress);
333
+ if (litellmModels !== undefined) {
334
+ return litellmModels;
335
+ }
336
+ return parseModelList(await fetchDiscoveryJson(modelsEndpoint(baseUrl), apiKey, apiKeyHeaderName, egress));
337
+ }
338
+ function deploymentNameValues(value) {
339
+ if (typeof value === "string") {
340
+ return value.split(/[\n,]/u);
341
+ }
342
+ if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
343
+ return value;
344
+ }
345
+ return undefined;
346
+ }
347
+ function normalizeDeploymentNames(values) {
348
+ return Array.from(new Set(values.map((item) => item.trim()).filter((item) => item.length > 0)));
349
+ }
350
+ function parseDeploymentNames(value) {
351
+ if (value === undefined) {
352
+ return [];
353
+ }
354
+ const values = deploymentNameValues(value);
355
+ if (values === undefined) {
356
+ return {
357
+ status: 400,
358
+ body: errorBody("BAD_REQUEST", "deploymentNames must be a string or an array of strings."),
359
+ };
360
+ }
361
+ const names = normalizeDeploymentNames(values);
362
+ if (names.length > MAX_DEPLOYMENT_NAMES) {
363
+ return {
364
+ status: 400,
365
+ body: errorBody("BAD_REQUEST", "deploymentNames exceeds the model setup limit."),
366
+ };
367
+ }
368
+ if (names.some((name) => !isUsableModelId(name))) {
369
+ return {
370
+ status: 400,
371
+ body: errorBody("BAD_REQUEST", "deploymentNames contains an invalid model id."),
372
+ };
373
+ }
374
+ return names;
375
+ }
376
+ function parseImageInputModelIds(value) {
377
+ if (value === undefined) {
378
+ return [];
379
+ }
380
+ const values = deploymentNameValues(value);
381
+ if (values === undefined) {
382
+ return {
383
+ status: 400,
384
+ body: errorBody("BAD_REQUEST", "imageInputModelIds must be a string or an array of strings."),
385
+ };
386
+ }
387
+ const names = normalizeDeploymentNames(values);
388
+ if (names.length > MAX_DEPLOYMENT_NAMES) {
389
+ return {
390
+ status: 400,
391
+ body: errorBody("BAD_REQUEST", "imageInputModelIds exceeds the model setup limit."),
392
+ };
393
+ }
394
+ if (names.some((name) => !isUsableModelId(name))) {
395
+ return {
396
+ status: 400,
397
+ body: errorBody("BAD_REQUEST", "imageInputModelIds contains an invalid model id."),
398
+ };
399
+ }
400
+ return names;
401
+ }
402
+ function validateSetupConnection(baseUrl, apiKey, apiKeyHeaderName, env) {
403
+ try {
404
+ parseGatewayConfig(buildRawConfig(baseUrl, apiKey, ["setup-validation"], { apiKeyHeaderName }), env);
405
+ return undefined;
406
+ }
407
+ catch (error) {
408
+ if (error instanceof ConfigInvalidError) {
409
+ return { status: 400, body: errorBody("BAD_REQUEST", error.message) };
410
+ }
411
+ throw error;
412
+ }
413
+ }
414
+ // Issue #144: pure smoke-test loop extracted from `defaultGatewaySetupTester`
415
+ // for testability. Concurrency is a parameter so callers (tests) can pin peak
416
+ // in-flight count deterministically. Original-order preservation among
417
+ // survivors is part of the observable contract — pinned by gateway-setup tests
418
+ // that assert tested-model-id order matches input order with failed entries
419
+ // dropped.
420
+ //
421
+ // Throws with the exact error message that `defaultGatewaySetupTester` has
422
+ // always thrown so existing call sites and tests keep compiling.
423
+ export async function smokeTestCandidates(candidates, probe, concurrency) {
424
+ const tested = Array(candidates.length).fill(undefined);
425
+ let next = 0;
426
+ async function worker() {
427
+ while (next < candidates.length) {
428
+ const index = next;
429
+ next += 1;
430
+ const modelId = candidates[index];
431
+ if (modelId === undefined) {
432
+ continue;
433
+ }
434
+ try {
435
+ await probe(modelId);
436
+ tested[index] = modelId;
437
+ }
438
+ catch {
439
+ // Probe rejection is the documented signal that this candidate is not
440
+ // chat-callable. We drop it silently so healthy peers still surface.
441
+ }
442
+ }
443
+ }
444
+ const workerCount = Math.max(1, Math.min(concurrency, candidates.length));
445
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
446
+ const accepted = tested.filter((modelId) => modelId !== undefined);
447
+ if (accepted.length === 0) {
448
+ throw new Error("no discovered model accepted the chat-completions smoke test");
449
+ }
450
+ return accepted;
451
+ }
452
+ async function defaultGatewaySetupTester(config, candidateModelIds) {
453
+ const gateway = new Gateway(config);
454
+ return smokeTestCandidates(candidateModelIds, async (modelId) => {
455
+ await gateway.chat({
456
+ modelId,
457
+ messages: [
458
+ { role: "system", content: CONVERSATION_SYSTEM_PROMPT },
459
+ { role: "user", content: "Reply with exactly: OK" },
460
+ ],
461
+ });
462
+ }, SETUP_SMOKE_CONCURRENCY);
463
+ }
464
+ const FIGMA_ME_ENDPOINT = "https://api.figma.com/v1/me";
465
+ function figmaReason(body) {
466
+ if (!isRecord(body))
467
+ return undefined;
468
+ const reason = body.err ?? body.message;
469
+ return typeof reason === "string" ? reason : undefined;
470
+ }
471
+ async function defaultFigmaCredentialTester(accessToken, egress) {
472
+ try {
473
+ const response = await gatewayFetch(FIGMA_ME_ENDPOINT, {
474
+ method: "GET",
475
+ headers: {
476
+ Accept: "application/json",
477
+ "X-Figma-Token": accessToken,
478
+ },
479
+ redirect: "manual",
480
+ signal: AbortSignal.timeout(FIGMA_CREDENTIAL_SMOKE_TIMEOUT_MS),
481
+ ...(egress !== undefined ? { egress } : {}),
482
+ });
483
+ let body;
484
+ try {
485
+ body = await readJsonCapped(response, FIGMA_CREDENTIAL_SMOKE_RESPONSE_BYTES);
486
+ }
487
+ catch {
488
+ throw new FigmaConnectorError("FIGMA_RESPONSE_TOO_LARGE");
489
+ }
490
+ if (!response.ok) {
491
+ throw classifyTokenFailure(response.status, figmaReason(body));
492
+ }
493
+ if (!isRecord(body)) {
494
+ throw new FigmaConnectorError("FIGMA_INTERNAL");
495
+ }
496
+ }
497
+ catch (error) {
498
+ if (error instanceof FigmaConnectorError) {
499
+ throw error;
500
+ }
501
+ throw new FigmaConnectorError(classifyFigmaTransportError(error));
502
+ }
503
+ }
504
+ // Seals the verified raw config's secrets into their local vaults and writes a credential-free
505
+ // keiko.config.json (Issue #1320). `deps.evidenceDir` is the resolved evidence root used by the
506
+ // encrypted Figma PAT vault; it is resolved defensively so persistence never depends on the optional
507
+ // field being pre-populated.
508
+ function persistGatewayConfig(raw, storagePath, deps) {
509
+ persistSealedGatewayConfig(raw, {
510
+ env: deps.env,
511
+ storagePath,
512
+ evidenceDir: resolveEvidenceDir(deps.evidenceDir, deps.env),
513
+ });
514
+ }
515
+ function normalizeSetupApiKeyHeaderName(value) {
516
+ try {
517
+ return normalizeApiKeyHeaderName(value, "apiKeyHeaderName", DEFAULT_API_KEY_HEADER_NAME);
518
+ }
519
+ catch (error) {
520
+ if (error instanceof ConfigInvalidError) {
521
+ return { status: 400, body: errorBody("BAD_REQUEST", error.message) };
522
+ }
523
+ throw error;
524
+ }
525
+ }
526
+ function readSetupModelLists(raw) {
527
+ const deploymentNames = parseDeploymentNames(raw.deploymentNames);
528
+ if (isRouteResult(deploymentNames)) {
529
+ return deploymentNames;
530
+ }
531
+ const imageInputModelIds = parseImageInputModelIds(raw.imageInputModelIds);
532
+ if (isRouteResult(imageInputModelIds)) {
533
+ return imageInputModelIds;
534
+ }
535
+ return { deploymentNames, imageInputModelIds };
536
+ }
537
+ function optionalSetupSecret(value, path) {
538
+ if (value === undefined) {
539
+ return undefined;
540
+ }
541
+ if (typeof value !== "string") {
542
+ return { status: 400, body: errorBody("BAD_REQUEST", `${path} must be a string.`) };
543
+ }
544
+ const trimmed = value.trim();
545
+ return trimmed.length === 0 ? undefined : trimmed;
546
+ }
547
+ function hasNonBlankStringField(raw, key) {
548
+ const value = raw[key];
549
+ return typeof value === "string" && value.trim().length > 0;
550
+ }
551
+ function hasNonEmptyListField(raw, key) {
552
+ const value = raw[key];
553
+ if (typeof value === "string") {
554
+ return normalizeDeploymentNames(deploymentNameValues(value) ?? []).length > 0;
555
+ }
556
+ return Array.isArray(value) && value.some((item) => typeof item === "string" && item.trim());
557
+ }
558
+ function shouldPreserveExisting(raw, current) {
559
+ return raw.preserveExisting === true && current !== undefined;
560
+ }
561
+ function firstProvider(current) {
562
+ return current?.providers[0];
563
+ }
564
+ function trimmedSubmittedString(raw, key) {
565
+ const value = raw[key];
566
+ if (typeof value !== "string")
567
+ return undefined;
568
+ const trimmed = value.trim();
569
+ return trimmed.length === 0 ? undefined : trimmed;
570
+ }
571
+ function submittedOrInheritedString(raw, key, inherited, preserveExisting) {
572
+ return trimmedSubmittedString(raw, key) ?? (preserveExisting ? (inherited ?? "") : "");
573
+ }
574
+ function setupApiKeyHeaderSource(raw, provider, preserveExisting) {
575
+ if (raw.apiKeyHeaderName !== undefined || !preserveExisting) {
576
+ return raw.apiKeyHeaderName;
577
+ }
578
+ return provider?.apiKeyHeaderName ?? DEFAULT_API_KEY_HEADER_NAME;
579
+ }
580
+ function readSetupGatewayCredentials(raw, env, current, preserveExisting) {
581
+ const provider = firstProvider(current);
582
+ const baseUrl = submittedOrInheritedString(raw, "baseUrl", provider?.baseUrl, preserveExisting);
583
+ const apiKey = submittedOrInheritedString(raw, "apiKey", provider?.apiKey, preserveExisting);
584
+ if (baseUrl.length === 0 || apiKey.length === 0) {
585
+ return { status: 400, body: errorBody("BAD_REQUEST", "baseUrl and apiKey are required.") };
586
+ }
587
+ const apiKeyHeaderSource = setupApiKeyHeaderSource(raw, provider, preserveExisting);
588
+ const apiKeyHeaderName = normalizeSetupApiKeyHeaderName(apiKeyHeaderSource);
589
+ if (isRouteResult(apiKeyHeaderName)) {
590
+ return apiKeyHeaderName;
591
+ }
592
+ const invalidConnection = validateSetupConnection(baseUrl, apiKey, apiKeyHeaderName, env);
593
+ if (invalidConnection !== undefined) {
594
+ return invalidConnection;
595
+ }
596
+ return { baseUrl, apiKey, apiKeyHeaderName };
597
+ }
598
+ function resolveSetupModelLists(modelLists, current, preserveExisting) {
599
+ const existing = preserveExisting ? current : undefined;
600
+ return {
601
+ deploymentNames: existing !== undefined && modelLists.deploymentNames.length === 0
602
+ ? existing.providers.map((item) => item.modelId)
603
+ : modelLists.deploymentNames,
604
+ imageInputModelIds: existing !== undefined && modelLists.imageInputModelIds.length === 0
605
+ ? currentImageInputModelIds(existing)
606
+ : modelLists.imageInputModelIds,
607
+ };
608
+ }
609
+ function setupRequiresGatewayVerification(raw, preserveExisting) {
610
+ return (!preserveExisting ||
611
+ hasNonBlankStringField(raw, "baseUrl") ||
612
+ hasNonBlankStringField(raw, "apiKey") ||
613
+ hasNonBlankStringField(raw, "apiKeyHeaderName") ||
614
+ hasNonEmptyListField(raw, "deploymentNames") ||
615
+ hasNonEmptyListField(raw, "imageInputModelIds"));
616
+ }
617
+ function readSetupRequest(raw, env, current) {
618
+ if (!isRecord(raw)) {
619
+ return { status: 400, body: errorBody("BAD_REQUEST", "Request body must be a JSON object.") };
620
+ }
621
+ const preserveExisting = shouldPreserveExisting(raw, current);
622
+ const credentials = readSetupGatewayCredentials(raw, env, current, preserveExisting);
623
+ if (isRouteResult(credentials)) {
624
+ return credentials;
625
+ }
626
+ const modelLists = readSetupModelLists(raw);
627
+ if (isRouteResult(modelLists)) {
628
+ return modelLists;
629
+ }
630
+ const figmaAccessToken = optionalSetupSecret(raw.figmaAccessToken, "figmaAccessToken");
631
+ if (isRouteResult(figmaAccessToken)) {
632
+ return figmaAccessToken;
633
+ }
634
+ const resolvedModelLists = resolveSetupModelLists(modelLists, current, preserveExisting);
635
+ return {
636
+ ...credentials,
637
+ deploymentNames: resolvedModelLists.deploymentNames,
638
+ imageInputModelIds: resolvedModelLists.imageInputModelIds,
639
+ figmaAccessToken: figmaAccessToken ?? current?.figma?.accessToken,
640
+ verifyGateway: setupRequiresGatewayVerification(raw, preserveExisting),
641
+ verifyFigmaCredential: figmaAccessToken !== undefined,
642
+ };
643
+ }
644
+ function safeError(error, secrets) {
645
+ const concreteSecrets = secrets.filter((secret) => secret !== undefined);
646
+ if (error instanceof Error) {
647
+ return redact(error.message, concreteSecrets);
648
+ }
649
+ return "Gateway setup failed.";
650
+ }
651
+ function assertImageInputModelsWereTested(imageInputModelIds, testedModelIds) {
652
+ if (imageInputModelIds.length === 0)
653
+ return;
654
+ const tested = new Set(testedModelIds);
655
+ if (imageInputModelIds.some((modelId) => !tested.has(modelId))) {
656
+ throw new Error("imageInputModelIds must match tested chat-callable model ids.");
657
+ }
658
+ }
659
+ function validationConfigForSetup(input) {
660
+ const validationRawConfig = buildRawConfig(input.baseUrl, input.apiKey, ["setup-validation"], {
661
+ apiKeyHeaderName: input.apiKeyHeaderName,
662
+ imageInputModelIds: input.imageInputModelIds,
663
+ });
664
+ return parseGatewayConfig(withInheritedEgress(validationRawConfig, input.egress), input.env);
665
+ }
666
+ async function candidateModelIdsForSetup(input, validationConfig) {
667
+ return input.deploymentNames.length > 0
668
+ ? input.deploymentNames
669
+ : input.discovery(input.baseUrl, input.apiKey, input.apiKeyHeaderName, validationConfig.egress);
670
+ }
671
+ function finalRawConfigForSetup(input, testedModelIds) {
672
+ const embeddingModelIds = embeddingModelIdsFromDeployments(input.deploymentNames);
673
+ const configuredModelIds = mergeChatAndEmbeddingModelIds(testedModelIds, input.deploymentNames);
674
+ const rawConfig = buildRawConfig(input.baseUrl, input.apiKey, configuredModelIds, {
675
+ apiKeyHeaderName: input.apiKeyHeaderName,
676
+ imageInputModelIds: input.imageInputModelIds,
677
+ embeddingModelIds,
678
+ });
679
+ return {
680
+ ...rawConfig,
681
+ ...(input.current?.grounding === undefined ? {} : { grounding: input.current.grounding }),
682
+ ...(input.figmaAccessToken === undefined
683
+ ? {}
684
+ : { figma: { accessToken: input.figmaAccessToken } }),
685
+ };
686
+ }
687
+ function skippedModelIdsForSetup(candidateModelIds, testedModelIds, deploymentNames) {
688
+ const acceptedModelIds = new Set([
689
+ ...testedModelIds,
690
+ ...embeddingModelIdsFromDeployments(deploymentNames),
691
+ ]);
692
+ return candidateModelIds.filter((modelId) => !acceptedModelIds.has(modelId));
693
+ }
694
+ async function verifySetupCandidate(input) {
695
+ // Defence-in-depth: never send the credential to a candidate URL that has not passed the same
696
+ // scheme/credential/loopback validation as the originally submitted base URL.
697
+ validateBaseUrl(input.baseUrl, "candidate");
698
+ const validationConfig = validationConfigForSetup(input);
699
+ const candidateModelIds = await candidateModelIdsForSetup(input, validationConfig);
700
+ const smokeTimeoutMs = input.deploymentNames.length > 0
701
+ ? DEPLOYMENT_SMOKE_TIMEOUT_MS
702
+ : DISCOVERED_MODEL_SMOKE_TIMEOUT_MS;
703
+ const candidateRawConfig = buildRawConfig(input.baseUrl, input.apiKey, candidateModelIds, {
704
+ apiKeyHeaderName: input.apiKeyHeaderName,
705
+ timeoutMs: smokeTimeoutMs,
706
+ // One retry (not zero) so a single transient blip — 429 rate-limit, brief timeout, momentary
707
+ // content-filter — does not permanently exclude an otherwise-working model from the setup and
708
+ // brand it to the user as incompatible. Still bounded so setup latency stays predictable.
709
+ maxRetries: 1,
710
+ imageInputModelIds: input.imageInputModelIds,
711
+ });
712
+ const candidateConfig = parseGatewayConfig(withInheritedEgress(candidateRawConfig, input.egress), input.env);
713
+ const testedModelIds = await input.tester(candidateConfig, candidateModelIds);
714
+ assertImageInputModelsWereTested(input.imageInputModelIds, testedModelIds);
715
+ const rawConfigWithOptionalBlocks = finalRawConfigForSetup(input, testedModelIds);
716
+ const config = parseGatewayConfig(withInheritedEgress(rawConfigWithOptionalBlocks, input.egress), input.env);
717
+ return {
718
+ rawConfig: rawConfigWithOptionalBlocks,
719
+ config,
720
+ testedModelIds,
721
+ skippedModelIds: skippedModelIdsForSetup(candidateModelIds, testedModelIds, input.deploymentNames),
722
+ };
723
+ }
724
+ function setupSuccessResult(config, testedModelIds, skippedModelIds) {
725
+ const testedModelId = testedModelIds[0] ?? "unknown";
726
+ return {
727
+ status: 200,
728
+ body: {
729
+ ok: true,
730
+ testedModelId,
731
+ testedModelIds,
732
+ skippedModelIds,
733
+ providerCount: config.providers.length,
734
+ models: listConfiguredCapabilities(config),
735
+ config: toSafeObject(config),
736
+ },
737
+ };
738
+ }
739
+ function setupFailureResult(errors) {
740
+ return {
741
+ status: 502,
742
+ body: errorBody("GATEWAY_SETUP_FAILED", `Credentials could not be verified. ${errors.join(" ")}`),
743
+ };
744
+ }
745
+ function figmaFailureStatus(code) {
746
+ switch (code) {
747
+ case "FIGMA_TOKEN_INVALID":
748
+ case "FIGMA_TOKEN_EXPIRED":
749
+ case "FIGMA_TOKEN_REVOKED":
750
+ case "FIGMA_INSUFFICIENT_SCOPE":
751
+ case "FIGMA_CONSENT_REQUIRED":
752
+ return 400;
753
+ case "FIGMA_RATE_LIMITED":
754
+ return 429;
755
+ default:
756
+ return 502;
757
+ }
758
+ }
759
+ function figmaCredentialFailureResult(error, request) {
760
+ if (error instanceof FigmaConnectorError) {
761
+ return {
762
+ status: figmaFailureStatus(error.code),
763
+ body: errorBody(error.code, error.message),
764
+ };
765
+ }
766
+ return {
767
+ status: 502,
768
+ body: errorBody("FIGMA_EGRESS_FAILED", safeError(error, [request.figmaAccessToken, request.apiKey, request.baseUrl])),
769
+ };
770
+ }
771
+ async function verifySubmittedFigmaCredential(request, deps) {
772
+ if (!request.verifyFigmaCredential || request.figmaAccessToken === undefined) {
773
+ return undefined;
774
+ }
775
+ const tester = deps.figmaCredentialTester ?? defaultFigmaCredentialTester;
776
+ try {
777
+ await tester(request.figmaAccessToken, currentGatewayEgressConfig(deps));
778
+ return undefined;
779
+ }
780
+ catch (error) {
781
+ return figmaCredentialFailureResult(error, request);
782
+ }
783
+ }
784
+ function deploymentNamesRequiredResult() {
785
+ return {
786
+ status: 400,
787
+ body: errorBody("GATEWAY_DEPLOYMENTS_REQUIRED", "Azure AI Foundry endpoints require deployment names from the Deployments tab."),
788
+ };
789
+ }
790
+ async function readJsonSetupBody(ctx) {
791
+ let bodyText;
792
+ try {
793
+ bodyText = await readBody(ctx.req);
794
+ }
795
+ catch (error) {
796
+ if (error instanceof BodyTooLargeError) {
797
+ return {
798
+ status: 413,
799
+ body: errorBody("PAYLOAD_TOO_LARGE", "Request body exceeds the size limit."),
800
+ };
801
+ }
802
+ throw error;
803
+ }
804
+ try {
805
+ return { parsed: JSON.parse(bodyText) };
806
+ }
807
+ catch {
808
+ return { status: 400, body: errorBody("BAD_REQUEST", "Request body is not valid JSON.") };
809
+ }
810
+ }
811
+ function gatewayUnavailableResult() {
812
+ return {
813
+ status: 500,
814
+ body: errorBody("GATEWAY_SETUP_UNAVAILABLE", "Gateway setup is unavailable."),
815
+ };
816
+ }
817
+ async function trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery, current) {
818
+ const verified = await verifySetupCandidate({
819
+ baseUrl,
820
+ apiKey: request.apiKey,
821
+ apiKeyHeaderName: request.apiKeyHeaderName,
822
+ deploymentNames: request.deploymentNames,
823
+ imageInputModelIds: request.imageInputModelIds,
824
+ tester,
825
+ discovery,
826
+ env: deps.env,
827
+ egress: currentGatewayEgressConfig(deps),
828
+ figmaAccessToken: request.figmaAccessToken,
829
+ current,
830
+ });
831
+ persistGatewayConfig(verified.rawConfig, gatewayConfig.storagePath, deps);
832
+ gatewayConfig.set(verified.config, true);
833
+ return setupSuccessResult(verified.config, verified.testedModelIds, verified.skippedModelIds);
834
+ }
835
+ function setupCandidateError(error, request, baseUrl) {
836
+ return safeError(error, [request.apiKey, request.baseUrl, baseUrl, request.figmaAccessToken]);
837
+ }
838
+ function saveExistingConfigUpdate(request, current, deps, gatewayConfig) {
839
+ const rawConfig = rawConfigFromCurrent(current, request.figmaAccessToken);
840
+ const config = parseGatewayConfig(withInheritedEgress(rawConfig, currentGatewayEgressConfig(deps)), deps.env);
841
+ persistGatewayConfig(rawConfig, gatewayConfig.storagePath, deps);
842
+ gatewayConfig.set(config, true);
843
+ return setupSuccessResult(config, config.providers.map((provider) => provider.modelId), []);
844
+ }
845
+ async function verifyAndSaveExistingConfigUpdate(request, current, deps, gatewayConfig) {
846
+ const figmaFailure = await verifySubmittedFigmaCredential(request, deps);
847
+ if (figmaFailure !== undefined) {
848
+ return figmaFailure;
849
+ }
850
+ return saveExistingConfigUpdate(request, current, deps, gatewayConfig);
851
+ }
852
+ function shouldRequireDeploymentNames(request, baseUrlCandidates) {
853
+ return (request.deploymentNames.length === 0 &&
854
+ baseUrlCandidates.some((baseUrl) => isAzureFoundryBaseUrl(baseUrl)));
855
+ }
856
+ async function verifyAndSaveGatewaySetup(request, current, deps, gatewayConfig) {
857
+ const tester = deps.gatewaySetupTester ?? defaultGatewaySetupTester;
858
+ const discovery = deps.gatewayModelDiscovery ?? defaultGatewayModelDiscovery;
859
+ const figmaFailure = await verifySubmittedFigmaCredential(request, deps);
860
+ if (figmaFailure !== undefined) {
861
+ return figmaFailure;
862
+ }
863
+ const baseUrlCandidates = candidateBaseUrls(request.baseUrl);
864
+ if (shouldRequireDeploymentNames(request, baseUrlCandidates)) {
865
+ return deploymentNamesRequiredResult();
866
+ }
867
+ const errors = [];
868
+ for (const baseUrl of baseUrlCandidates) {
869
+ try {
870
+ return await trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery, current);
871
+ }
872
+ catch (error) {
873
+ errors.push(`candidate ${String(errors.length + 1)}: ${setupCandidateError(error, request, baseUrl)}`);
874
+ }
875
+ }
876
+ return setupFailureResult(errors);
877
+ }
878
+ export async function handleGatewaySetup(ctx, deps) {
879
+ if (deps.gatewayConfig === undefined) {
880
+ return gatewayUnavailableResult();
881
+ }
882
+ const { gatewayConfig } = deps;
883
+ const current = currentGatewayConfig(deps);
884
+ const bodyResult = await readJsonSetupBody(ctx);
885
+ if ("status" in bodyResult) {
886
+ return bodyResult;
887
+ }
888
+ const request = readSetupRequest(bodyResult.parsed, deps.env, current);
889
+ if ("status" in request) {
890
+ return request;
891
+ }
892
+ if (!request.verifyGateway && current !== undefined) {
893
+ return verifyAndSaveExistingConfigUpdate(request, current, deps, gatewayConfig);
894
+ }
895
+ return verifyAndSaveGatewaySetup(request, current, deps, gatewayConfig);
896
+ }