@mondaydotcomorg/atp-server 0.17.14

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 (307) hide show
  1. package/README.md +489 -0
  2. package/dist/aggregator/index.d.ts +59 -0
  3. package/dist/aggregator/index.d.ts.map +1 -0
  4. package/dist/aggregator/index.js +171 -0
  5. package/dist/aggregator/index.js.map +1 -0
  6. package/dist/callback/index.d.ts +98 -0
  7. package/dist/callback/index.d.ts.map +1 -0
  8. package/dist/callback/index.js +136 -0
  9. package/dist/callback/index.js.map +1 -0
  10. package/dist/client-sessions.d.ts +82 -0
  11. package/dist/client-sessions.d.ts.map +1 -0
  12. package/dist/client-sessions.js +174 -0
  13. package/dist/client-sessions.js.map +1 -0
  14. package/dist/controllers/definitions.controller.d.ts +4 -0
  15. package/dist/controllers/definitions.controller.d.ts.map +1 -0
  16. package/dist/controllers/definitions.controller.js +11 -0
  17. package/dist/controllers/definitions.controller.js.map +1 -0
  18. package/dist/controllers/execute.controller.d.ts +18 -0
  19. package/dist/controllers/execute.controller.d.ts.map +1 -0
  20. package/dist/controllers/execute.controller.js +122 -0
  21. package/dist/controllers/execute.controller.js.map +1 -0
  22. package/dist/controllers/info.controller.d.ts +3 -0
  23. package/dist/controllers/info.controller.d.ts.map +1 -0
  24. package/dist/controllers/info.controller.js +13 -0
  25. package/dist/controllers/info.controller.js.map +1 -0
  26. package/dist/controllers/resume.controller.d.ts +11 -0
  27. package/dist/controllers/resume.controller.d.ts.map +1 -0
  28. package/dist/controllers/resume.controller.js +61 -0
  29. package/dist/controllers/resume.controller.js.map +1 -0
  30. package/dist/controllers/search.controller.d.ts +4 -0
  31. package/dist/controllers/search.controller.d.ts.map +1 -0
  32. package/dist/controllers/search.controller.js +7 -0
  33. package/dist/controllers/search.controller.js.map +1 -0
  34. package/dist/controllers/stream.controller.d.ts +19 -0
  35. package/dist/controllers/stream.controller.d.ts.map +1 -0
  36. package/dist/controllers/stream.controller.js +141 -0
  37. package/dist/controllers/stream.controller.js.map +1 -0
  38. package/dist/core/config.d.ts +161 -0
  39. package/dist/core/config.d.ts.map +1 -0
  40. package/dist/core/config.js +7 -0
  41. package/dist/core/config.js.map +1 -0
  42. package/dist/core/http.d.ts +4 -0
  43. package/dist/core/http.d.ts.map +1 -0
  44. package/dist/core/http.js +17 -0
  45. package/dist/core/http.js.map +1 -0
  46. package/dist/create-server.d.ts +120 -0
  47. package/dist/create-server.d.ts.map +1 -0
  48. package/dist/create-server.js +423 -0
  49. package/dist/create-server.js.map +1 -0
  50. package/dist/execution-state/index.d.ts +95 -0
  51. package/dist/execution-state/index.d.ts.map +1 -0
  52. package/dist/execution-state/index.js +128 -0
  53. package/dist/execution-state/index.js.map +1 -0
  54. package/dist/executor/ast-provenance-bridge.d.ts +12 -0
  55. package/dist/executor/ast-provenance-bridge.d.ts.map +1 -0
  56. package/dist/executor/ast-provenance-bridge.js +66 -0
  57. package/dist/executor/ast-provenance-bridge.js.map +1 -0
  58. package/dist/executor/ast-tracking-runtime.d.ts +7 -0
  59. package/dist/executor/ast-tracking-runtime.d.ts.map +1 -0
  60. package/dist/executor/ast-tracking-runtime.js +559 -0
  61. package/dist/executor/ast-tracking-runtime.js.map +1 -0
  62. package/dist/executor/bootstrap-generated.d.ts +32 -0
  63. package/dist/executor/bootstrap-generated.d.ts.map +1 -0
  64. package/dist/executor/bootstrap-generated.js +90 -0
  65. package/dist/executor/bootstrap-generated.js.map +1 -0
  66. package/dist/executor/compiler-config.d.ts +32 -0
  67. package/dist/executor/compiler-config.d.ts.map +1 -0
  68. package/dist/executor/compiler-config.js +99 -0
  69. package/dist/executor/compiler-config.js.map +1 -0
  70. package/dist/executor/constants.d.ts +4 -0
  71. package/dist/executor/constants.d.ts.map +1 -0
  72. package/dist/executor/constants.js +4 -0
  73. package/dist/executor/constants.js.map +1 -0
  74. package/dist/executor/error-handler.d.ts +9 -0
  75. package/dist/executor/error-handler.d.ts.map +1 -0
  76. package/dist/executor/error-handler.js +95 -0
  77. package/dist/executor/error-handler.js.map +1 -0
  78. package/dist/executor/execution-error-handler.d.ts +7 -0
  79. package/dist/executor/execution-error-handler.d.ts.map +1 -0
  80. package/dist/executor/execution-error-handler.js +136 -0
  81. package/dist/executor/execution-error-handler.js.map +1 -0
  82. package/dist/executor/executor.d.ts +20 -0
  83. package/dist/executor/executor.d.ts.map +1 -0
  84. package/dist/executor/executor.js +452 -0
  85. package/dist/executor/executor.js.map +1 -0
  86. package/dist/executor/index.d.ts +4 -0
  87. package/dist/executor/index.d.ts.map +1 -0
  88. package/dist/executor/index.js +3 -0
  89. package/dist/executor/index.js.map +1 -0
  90. package/dist/executor/resume-handler.d.ts +9 -0
  91. package/dist/executor/resume-handler.d.ts.map +1 -0
  92. package/dist/executor/resume-handler.js +22 -0
  93. package/dist/executor/resume-handler.js.map +1 -0
  94. package/dist/executor/sandbox-builder.d.ts +29 -0
  95. package/dist/executor/sandbox-builder.d.ts.map +1 -0
  96. package/dist/executor/sandbox-builder.js +538 -0
  97. package/dist/executor/sandbox-builder.js.map +1 -0
  98. package/dist/executor/sandbox-injector.d.ts +7 -0
  99. package/dist/executor/sandbox-injector.d.ts.map +1 -0
  100. package/dist/executor/sandbox-injector.js +293 -0
  101. package/dist/executor/sandbox-injector.js.map +1 -0
  102. package/dist/executor/types.d.ts +21 -0
  103. package/dist/executor/types.d.ts.map +1 -0
  104. package/dist/executor/types.js +2 -0
  105. package/dist/executor/types.js.map +1 -0
  106. package/dist/explorer/index.d.ts +69 -0
  107. package/dist/explorer/index.d.ts.map +1 -0
  108. package/dist/explorer/index.js +228 -0
  109. package/dist/explorer/index.js.map +1 -0
  110. package/dist/handlers/definitions.handler.d.ts +3 -0
  111. package/dist/handlers/definitions.handler.d.ts.map +1 -0
  112. package/dist/handlers/definitions.handler.js +11 -0
  113. package/dist/handlers/definitions.handler.js.map +1 -0
  114. package/dist/handlers/execute.handler.d.ts +7 -0
  115. package/dist/handlers/execute.handler.d.ts.map +1 -0
  116. package/dist/handlers/execute.handler.js +225 -0
  117. package/dist/handlers/execute.handler.js.map +1 -0
  118. package/dist/handlers/explorer.handler.d.ts +4 -0
  119. package/dist/handlers/explorer.handler.d.ts.map +1 -0
  120. package/dist/handlers/explorer.handler.js +10 -0
  121. package/dist/handlers/explorer.handler.js.map +1 -0
  122. package/dist/handlers/init.handler.d.ts +5 -0
  123. package/dist/handlers/init.handler.d.ts.map +1 -0
  124. package/dist/handlers/init.handler.js +41 -0
  125. package/dist/handlers/init.handler.js.map +1 -0
  126. package/dist/handlers/resume.handler.d.ts +6 -0
  127. package/dist/handlers/resume.handler.d.ts.map +1 -0
  128. package/dist/handlers/resume.handler.js +256 -0
  129. package/dist/handlers/resume.handler.js.map +1 -0
  130. package/dist/handlers/search.handler.d.ts +5 -0
  131. package/dist/handlers/search.handler.d.ts.map +1 -0
  132. package/dist/handlers/search.handler.js +11 -0
  133. package/dist/handlers/search.handler.js.map +1 -0
  134. package/dist/http/request-handler.d.ts +15 -0
  135. package/dist/http/request-handler.d.ts.map +1 -0
  136. package/dist/http/request-handler.js +94 -0
  137. package/dist/http/request-handler.js.map +1 -0
  138. package/dist/http/router.d.ts +4 -0
  139. package/dist/http/router.d.ts.map +1 -0
  140. package/dist/http/router.js +32 -0
  141. package/dist/http/router.js.map +1 -0
  142. package/dist/index.d.ts +10 -0
  143. package/dist/index.d.ts.map +1 -0
  144. package/dist/index.js +8 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/instrumentation/index.d.ts +5 -0
  147. package/dist/instrumentation/index.d.ts.map +1 -0
  148. package/dist/instrumentation/index.js +5 -0
  149. package/dist/instrumentation/index.js.map +1 -0
  150. package/dist/instrumentation/serializer.d.ts +61 -0
  151. package/dist/instrumentation/serializer.d.ts.map +1 -0
  152. package/dist/instrumentation/serializer.js +334 -0
  153. package/dist/instrumentation/serializer.js.map +1 -0
  154. package/dist/instrumentation/state-manager.d.ts +61 -0
  155. package/dist/instrumentation/state-manager.d.ts.map +1 -0
  156. package/dist/instrumentation/state-manager.js +205 -0
  157. package/dist/instrumentation/state-manager.js.map +1 -0
  158. package/dist/instrumentation/transformer.d.ts +9 -0
  159. package/dist/instrumentation/transformer.d.ts.map +1 -0
  160. package/dist/instrumentation/transformer.js +70 -0
  161. package/dist/instrumentation/transformer.js.map +1 -0
  162. package/dist/instrumentation/types.d.ts +59 -0
  163. package/dist/instrumentation/types.d.ts.map +1 -0
  164. package/dist/instrumentation/types.js +5 -0
  165. package/dist/instrumentation/types.js.map +1 -0
  166. package/dist/middleware/audit.d.ts +18 -0
  167. package/dist/middleware/audit.d.ts.map +1 -0
  168. package/dist/middleware/audit.js +76 -0
  169. package/dist/middleware/audit.js.map +1 -0
  170. package/dist/openapi/index.d.ts +133 -0
  171. package/dist/openapi/index.d.ts.map +1 -0
  172. package/dist/openapi/index.js +235 -0
  173. package/dist/openapi/index.js.map +1 -0
  174. package/dist/openapi-loader.d.ts +87 -0
  175. package/dist/openapi-loader.d.ts.map +1 -0
  176. package/dist/openapi-loader.js +491 -0
  177. package/dist/openapi-loader.js.map +1 -0
  178. package/dist/routes/index.d.ts +21 -0
  179. package/dist/routes/index.d.ts.map +1 -0
  180. package/dist/routes/index.js +47 -0
  181. package/dist/routes/index.js.map +1 -0
  182. package/dist/search/index.d.ts +48 -0
  183. package/dist/search/index.d.ts.map +1 -0
  184. package/dist/search/index.js +156 -0
  185. package/dist/search/index.js.map +1 -0
  186. package/dist/security/index.d.ts +2 -0
  187. package/dist/security/index.d.ts.map +1 -0
  188. package/dist/security/index.js +2 -0
  189. package/dist/security/index.js.map +1 -0
  190. package/dist/shutdown.d.ts +19 -0
  191. package/dist/shutdown.d.ts.map +1 -0
  192. package/dist/shutdown.js +87 -0
  193. package/dist/shutdown.js.map +1 -0
  194. package/dist/utils/banner.d.ts +12 -0
  195. package/dist/utils/banner.d.ts.map +1 -0
  196. package/dist/utils/banner.js +18 -0
  197. package/dist/utils/banner.js.map +1 -0
  198. package/dist/utils/context.d.ts +16 -0
  199. package/dist/utils/context.d.ts.map +1 -0
  200. package/dist/utils/context.js +44 -0
  201. package/dist/utils/context.js.map +1 -0
  202. package/dist/utils/error.d.ts +8 -0
  203. package/dist/utils/error.d.ts.map +1 -0
  204. package/dist/utils/error.js +17 -0
  205. package/dist/utils/error.js.map +1 -0
  206. package/dist/utils/hint-based-instrumentation.d.ts +14 -0
  207. package/dist/utils/hint-based-instrumentation.d.ts.map +1 -0
  208. package/dist/utils/hint-based-instrumentation.js +84 -0
  209. package/dist/utils/hint-based-instrumentation.js.map +1 -0
  210. package/dist/utils/index.d.ts +8 -0
  211. package/dist/utils/index.d.ts.map +1 -0
  212. package/dist/utils/index.js +8 -0
  213. package/dist/utils/index.js.map +1 -0
  214. package/dist/utils/info.d.ts +20 -0
  215. package/dist/utils/info.d.ts.map +1 -0
  216. package/dist/utils/info.js +15 -0
  217. package/dist/utils/info.js.map +1 -0
  218. package/dist/utils/provenance-reattachment.d.ts +32 -0
  219. package/dist/utils/provenance-reattachment.d.ts.map +1 -0
  220. package/dist/utils/provenance-reattachment.js +115 -0
  221. package/dist/utils/provenance-reattachment.js.map +1 -0
  222. package/dist/utils/request.d.ts +21 -0
  223. package/dist/utils/request.d.ts.map +1 -0
  224. package/dist/utils/request.js +44 -0
  225. package/dist/utils/request.js.map +1 -0
  226. package/dist/utils/response.d.ts +30 -0
  227. package/dist/utils/response.d.ts.map +1 -0
  228. package/dist/utils/response.js +53 -0
  229. package/dist/utils/response.js.map +1 -0
  230. package/dist/utils/runtime-types.d.ts +6 -0
  231. package/dist/utils/runtime-types.d.ts.map +1 -0
  232. package/dist/utils/runtime-types.js +14 -0
  233. package/dist/utils/runtime-types.js.map +1 -0
  234. package/dist/utils/schema.d.ts +9 -0
  235. package/dist/utils/schema.d.ts.map +1 -0
  236. package/dist/utils/schema.js +13 -0
  237. package/dist/utils/schema.js.map +1 -0
  238. package/dist/utils/token-emitter.d.ts +21 -0
  239. package/dist/utils/token-emitter.d.ts.map +1 -0
  240. package/dist/utils/token-emitter.js +129 -0
  241. package/dist/utils/token-emitter.js.map +1 -0
  242. package/dist/validator/index.d.ts +36 -0
  243. package/dist/validator/index.d.ts.map +1 -0
  244. package/dist/validator/index.js +224 -0
  245. package/dist/validator/index.js.map +1 -0
  246. package/package.json +68 -0
  247. package/src/aggregator/index.ts +207 -0
  248. package/src/callback/index.ts +191 -0
  249. package/src/client-sessions.ts +234 -0
  250. package/src/controllers/definitions.controller.ts +19 -0
  251. package/src/controllers/execute.controller.ts +166 -0
  252. package/src/controllers/info.controller.ts +14 -0
  253. package/src/controllers/resume.controller.ts +92 -0
  254. package/src/controllers/search.controller.ts +16 -0
  255. package/src/controllers/stream.controller.ts +190 -0
  256. package/src/core/config.ts +180 -0
  257. package/src/core/http.ts +21 -0
  258. package/src/create-server.ts +536 -0
  259. package/src/execution-state/index.ts +204 -0
  260. package/src/executor/ast-provenance-bridge.ts +80 -0
  261. package/src/executor/ast-tracking-runtime.ts +558 -0
  262. package/src/executor/bootstrap-generated.ts +90 -0
  263. package/src/executor/compiler-config.ts +146 -0
  264. package/src/executor/constants.ts +5 -0
  265. package/src/executor/error-handler.ts +118 -0
  266. package/src/executor/execution-error-handler.ts +178 -0
  267. package/src/executor/executor.ts +631 -0
  268. package/src/executor/index.ts +3 -0
  269. package/src/executor/resume-handler.ts +39 -0
  270. package/src/executor/sandbox-builder.ts +684 -0
  271. package/src/executor/sandbox-injector.ts +345 -0
  272. package/src/executor/types.ts +22 -0
  273. package/src/explorer/index.ts +297 -0
  274. package/src/handlers/definitions.handler.ts +13 -0
  275. package/src/handlers/execute.handler.ts +286 -0
  276. package/src/handlers/explorer.handler.ts +18 -0
  277. package/src/handlers/init.handler.ts +53 -0
  278. package/src/handlers/resume.handler.ts +316 -0
  279. package/src/handlers/search.handler.ts +32 -0
  280. package/src/http/request-handler.ts +117 -0
  281. package/src/http/router.ts +29 -0
  282. package/src/index.ts +60 -0
  283. package/src/instrumentation/index.ts +4 -0
  284. package/src/instrumentation/serializer.ts +421 -0
  285. package/src/instrumentation/state-manager.ts +237 -0
  286. package/src/instrumentation/transformer.ts +84 -0
  287. package/src/instrumentation/types.ts +76 -0
  288. package/src/middleware/audit.ts +101 -0
  289. package/src/openapi/index.ts +378 -0
  290. package/src/openapi-loader.ts +744 -0
  291. package/src/routes/index.ts +93 -0
  292. package/src/search/index.ts +216 -0
  293. package/src/security/index.ts +1 -0
  294. package/src/shutdown.ts +108 -0
  295. package/src/utils/banner.ts +25 -0
  296. package/src/utils/context.ts +58 -0
  297. package/src/utils/error.ts +25 -0
  298. package/src/utils/hint-based-instrumentation.ts +99 -0
  299. package/src/utils/index.ts +15 -0
  300. package/src/utils/info.ts +31 -0
  301. package/src/utils/provenance-reattachment.ts +144 -0
  302. package/src/utils/request.ts +53 -0
  303. package/src/utils/response.ts +69 -0
  304. package/src/utils/runtime-types.ts +14 -0
  305. package/src/utils/schema.ts +18 -0
  306. package/src/utils/token-emitter.ts +182 -0
  307. package/src/validator/index.ts +253 -0
@@ -0,0 +1,744 @@
1
+ import type {
2
+ APIGroupConfig,
3
+ CustomFunctionDef,
4
+ AuthProvider,
5
+ AuthConfig,
6
+ BearerAuthConfig,
7
+ BasicAuthConfig,
8
+ APIKeyAuthConfig,
9
+ } from '@mondaydotcomorg/atp-protocol';
10
+ import { readFile } from 'node:fs/promises';
11
+ import yaml from 'js-yaml';
12
+
13
+ /**
14
+ * Base HTTP API specification (common to both OpenAPI and Swagger)
15
+ */
16
+ interface BaseAPISpec {
17
+ info: {
18
+ title: string;
19
+ version: string;
20
+ description?: string;
21
+ };
22
+ paths: Record<string, Record<string, OpenAPIOperation>>;
23
+ security?: Array<Record<string, string[]>>;
24
+ }
25
+
26
+ /**
27
+ * OpenAPI 3.0+ specification structure
28
+ */
29
+ interface OpenAPISpec extends BaseAPISpec {
30
+ openapi: string;
31
+ servers?: Array<{ url: string; description?: string }>;
32
+ components?: {
33
+ schemas?: Record<string, OpenAPISchema>;
34
+ securitySchemes?: Record<string, OpenAPISecurityScheme>;
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Swagger 2.0 specification structure
40
+ */
41
+ interface Swagger2Spec extends BaseAPISpec {
42
+ swagger: string;
43
+ host?: string;
44
+ basePath?: string;
45
+ schemes?: Array<'http' | 'https' | 'ws' | 'wss'>;
46
+ consumes?: string[];
47
+ produces?: string[];
48
+ definitions?: Record<string, OpenAPISchema>;
49
+ securityDefinitions?: Record<string, OpenAPISecurityScheme>;
50
+ }
51
+
52
+ /**
53
+ * Union type for all supported API specification formats
54
+ */
55
+ type APISpec = OpenAPISpec | Swagger2Spec;
56
+
57
+ interface OpenAPIOperation {
58
+ operationId?: string;
59
+ summary?: string;
60
+ description?: string;
61
+ tags?: string[];
62
+ deprecated?: boolean;
63
+ parameters?: Array<OpenAPIParameter>;
64
+ requestBody?: OpenAPIRequestBody;
65
+ responses?: Record<string, OpenAPIResponse>;
66
+ security?: Array<Record<string, string[]>>;
67
+ 'x-destructive'?: boolean;
68
+ 'x-requires-approval'?: boolean;
69
+ 'x-risk-level'?: 'low' | 'medium' | 'high' | 'critical';
70
+ 'x-confirm-prompt'?: string;
71
+ [key: string]: unknown;
72
+ }
73
+
74
+ interface OpenAPIParameter {
75
+ name: string;
76
+ in: 'query' | 'header' | 'path' | 'cookie';
77
+ required?: boolean;
78
+ schema?: OpenAPISchema;
79
+ description?: string;
80
+ }
81
+
82
+ interface OpenAPIRequestBody {
83
+ required?: boolean;
84
+ content?: Record<string, { schema?: OpenAPISchema }>;
85
+ }
86
+
87
+ interface OpenAPIResponse {
88
+ description?: string;
89
+ content?: Record<string, { schema?: OpenAPISchema }>;
90
+ }
91
+
92
+ interface OpenAPISchema {
93
+ type?: string;
94
+ properties?: Record<string, OpenAPISchema>;
95
+ items?: OpenAPISchema;
96
+ required?: string[];
97
+ enum?: string[];
98
+ $ref?: string;
99
+ description?: string;
100
+ [key: string]: unknown;
101
+ }
102
+
103
+ interface OpenAPISecurityScheme {
104
+ type: 'apiKey' | 'http' | 'oauth2' | 'openIdConnect';
105
+ description?: string;
106
+ name?: string;
107
+ in?: 'query' | 'header' | 'cookie';
108
+ scheme?: string;
109
+ bearerFormat?: string;
110
+ flows?: Record<string, unknown>;
111
+ }
112
+
113
+ /**
114
+ * Options for loading OpenAPI spec
115
+ */
116
+ export interface LoadOpenAPIOptions {
117
+ /** API group name */
118
+ name?: string;
119
+
120
+ /** Filter operations */
121
+ filter?: {
122
+ /** Include only these tags */
123
+ tags?: string[];
124
+ /** Include only paths matching these patterns */
125
+ paths?: string[];
126
+ /** Exclude paths matching these patterns */
127
+ exclude?: string[];
128
+ /** Include only these HTTP methods */
129
+ methods?: string[];
130
+ /** Custom filter function */
131
+ operation?: (op: OpenAPIOperation, path: string, method: string) => boolean;
132
+ };
133
+
134
+ /** Override descriptions for better LLM understanding */
135
+ descriptions?: Record<string, string>;
136
+
137
+ /** Annotation mapping */
138
+ annotations?: {
139
+ /** Map OpenAPI extensions to annotations */
140
+ fromExtensions?: Record<string, string>;
141
+ /** Global annotations for all operations */
142
+ global?: Record<string, unknown>;
143
+ /** Per-operation annotations */
144
+ operations?: Record<string, Record<string, unknown>>;
145
+ };
146
+
147
+ /** Auth provider (optional, uses server's if not provided) */
148
+ authProvider?: AuthProvider;
149
+
150
+ /** Base URL override (if different from spec servers) */
151
+ baseURL?: string;
152
+ }
153
+
154
+ /**
155
+ * Type guard to check if spec is OpenAPI 3.0+
156
+ */
157
+ function isOpenAPI3(spec: APISpec): spec is OpenAPISpec {
158
+ return 'openapi' in spec;
159
+ }
160
+
161
+ /**
162
+ * Type guard to check if spec is Swagger 2.0
163
+ */
164
+ function isSwagger2(spec: APISpec): spec is Swagger2Spec {
165
+ return 'swagger' in spec;
166
+ }
167
+
168
+ /**
169
+ * Load OpenAPI specification and convert to ATP API group
170
+ */
171
+ export async function loadOpenAPI(
172
+ source: string,
173
+ options: LoadOpenAPIOptions = {}
174
+ ): Promise<APIGroupConfig> {
175
+ const spec = await loadSpec(source);
176
+
177
+ const name = options.name || spec.info.title.toLowerCase().replace(/\s+/g, '-');
178
+
179
+ let baseURL = options.baseURL;
180
+ if (!baseURL) {
181
+ if (isOpenAPI3(spec) && spec.servers && spec.servers[0]) {
182
+ baseURL = spec.servers[0].url;
183
+ }
184
+ else if (isSwagger2(spec) && spec.host) {
185
+ const scheme = spec.schemes?.[0] || 'https';
186
+ const host = spec.host;
187
+ const basePath = spec.basePath || '';
188
+ baseURL = `${scheme}://${host}${basePath}`;
189
+ } else {
190
+ baseURL = '';
191
+ }
192
+ }
193
+
194
+ // Detect auth first so we can pass it to handlers
195
+ const auth = detectAuth(spec, options.authProvider);
196
+
197
+ const functions: CustomFunctionDef[] = [];
198
+
199
+ for (const [path, methods] of Object.entries(spec.paths)) {
200
+ for (const [method, operation] of Object.entries(methods)) {
201
+ if (['parameters', 'servers', 'summary', 'description'].includes(method)) {
202
+ continue;
203
+ }
204
+
205
+ if (!shouldIncludeOperation(operation, path, method, options.filter)) {
206
+ continue;
207
+ }
208
+
209
+ const func = convertOperation(path, method, operation, spec, baseURL, options, auth);
210
+
211
+ if (func) {
212
+ functions.push(func);
213
+ }
214
+ }
215
+ }
216
+
217
+ return {
218
+ name,
219
+ type: 'openapi',
220
+ functions,
221
+ auth,
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Load OpenAPI spec from file or URL
227
+ */
228
+ async function loadSpec(source: string): Promise<APISpec> {
229
+ let content: string;
230
+ let isYaml = false;
231
+
232
+ if (source.startsWith('http://') || source.startsWith('https://')) {
233
+ const response = await fetch(source);
234
+ if (!response.ok) {
235
+ throw new Error(`Failed to load OpenAPI spec from ${source}: ${response.statusText}`);
236
+ }
237
+ content = await response.text();
238
+ const contentType = response.headers.get('content-type');
239
+ isYaml =
240
+ contentType?.includes('yaml') ||
241
+ contentType?.includes('yml') ||
242
+ source.endsWith('.yaml') ||
243
+ source.endsWith('.yml');
244
+ } else {
245
+ content = await readFile(source, 'utf-8');
246
+ isYaml = source.endsWith('.yaml') || source.endsWith('.yml');
247
+ }
248
+
249
+ try {
250
+ if (isYaml) {
251
+ return yaml.load(content) as OpenAPISpec;
252
+ } else {
253
+ try {
254
+ return JSON.parse(content);
255
+ } catch {
256
+ return yaml.load(content) as OpenAPISpec;
257
+ }
258
+ }
259
+ } catch (error) {
260
+ throw new Error(`Failed to parse OpenAPI spec: ${(error as Error).message}`);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Check if operation should be included based on filters
266
+ */
267
+ function shouldIncludeOperation(
268
+ operation: OpenAPIOperation,
269
+ path: string,
270
+ method: string,
271
+ filter?: LoadOpenAPIOptions['filter']
272
+ ): boolean {
273
+ if (!filter) return true;
274
+
275
+ if (filter.tags && filter.tags.length > 0) {
276
+ if (!operation.tags || !operation.tags.some((t) => filter.tags!.includes(t))) {
277
+ return false;
278
+ }
279
+ }
280
+
281
+ if (filter.paths && filter.paths.length > 0) {
282
+ if (!filter.paths.some((pattern) => matchPathPattern(path, pattern))) {
283
+ return false;
284
+ }
285
+ }
286
+
287
+ if (filter.exclude && filter.exclude.length > 0) {
288
+ if (filter.exclude.some((pattern) => matchPathPattern(path, pattern))) {
289
+ return false;
290
+ }
291
+ }
292
+
293
+ if (filter.methods && filter.methods.length > 0) {
294
+ if (!filter.methods.includes(method.toUpperCase())) {
295
+ return false;
296
+ }
297
+ }
298
+
299
+ if (operation.deprecated) {
300
+ return false;
301
+ }
302
+
303
+ if (filter.operation) {
304
+ return filter.operation(operation, path, method);
305
+ }
306
+
307
+ return true;
308
+ }
309
+
310
+ /**
311
+ * Match path against pattern (supports wildcards)
312
+ */
313
+ function matchPathPattern(path: string, pattern: string): boolean {
314
+ const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
315
+
316
+ return new RegExp(`^${regexPattern}$`).test(path);
317
+ }
318
+
319
+ /**
320
+ * Convert OpenAPI operation to ATP function
321
+ */
322
+ function convertOperation(
323
+ path: string,
324
+ method: string,
325
+ operation: OpenAPIOperation,
326
+ spec: APISpec,
327
+ baseURL: string,
328
+ options: LoadOpenAPIOptions,
329
+ auth?: AuthConfig
330
+ ): CustomFunctionDef | null {
331
+ const functionName = operation.operationId || `${method}_${path.replace(/[^a-zA-Z0-9]/g, '_')}`;
332
+
333
+ const operationKey = `${method.toUpperCase()} ${path}`;
334
+ const description =
335
+ options.descriptions?.[operationKey] ||
336
+ operation.summary ||
337
+ operation.description ||
338
+ `${method.toUpperCase()} ${path}`;
339
+
340
+ const inputSchema = buildInputSchema(operation, spec) as any;
341
+ const outputSchema = buildOutputSchema(operation, spec) as any;
342
+
343
+ const annotations = extractAnnotations(operation, operationKey, options.annotations);
344
+
345
+ const handler = async (params: unknown) => {
346
+ // Build the actual HTTP request
347
+ const input = (params as Record<string, any>) || {};
348
+ let requestPath = path;
349
+ const queryParams: Record<string, string> = {};
350
+ let body: any = undefined;
351
+ const headers: Record<string, string> = {
352
+ 'Content-Type': 'application/json',
353
+ };
354
+
355
+ // Add authentication
356
+ if (auth) {
357
+ if (auth.scheme === 'bearer' && auth.envVar) {
358
+ // Try authProvider first, fallback to process.env
359
+ let token: string | null = null;
360
+ if (options.authProvider) {
361
+ token = await options.authProvider.getCredential(auth.envVar);
362
+ console.log(
363
+ `[AUTH DEBUG] Got token from authProvider for ${auth.envVar}: ${token ? 'YES (' + token.substring(0, 20) + '...)' : 'NO'}`
364
+ );
365
+ }
366
+ if (!token) {
367
+ token = process.env[auth.envVar] || null;
368
+ console.log(
369
+ `[AUTH DEBUG] Got token from process.env[${auth.envVar}]: ${token ? 'YES (' + token.substring(0, 20) + '...)' : 'NO'}`
370
+ );
371
+ }
372
+
373
+ if (token) {
374
+ headers['Authorization'] = `Bearer ${token}`;
375
+ } else {
376
+ console.warn(
377
+ `[AUTH WARNING] ${auth.envVar} not found! Set it in authProvider or environment.`
378
+ );
379
+ }
380
+ } else if (auth.scheme === 'basic') {
381
+ let username: string | null = null;
382
+ let password: string | null = null;
383
+
384
+ if (options.authProvider && auth.usernameEnvVar && auth.passwordEnvVar) {
385
+ username = await options.authProvider.getCredential(auth.usernameEnvVar);
386
+ password = await options.authProvider.getCredential(auth.passwordEnvVar);
387
+ }
388
+ if (!username && auth.usernameEnvVar) {
389
+ username = process.env[auth.usernameEnvVar] || null;
390
+ }
391
+ if (!password && auth.passwordEnvVar) {
392
+ password = process.env[auth.passwordEnvVar] || null;
393
+ }
394
+
395
+ if (username && password) {
396
+ const credentials = Buffer.from(`${username}:${password}`).toString('base64');
397
+ headers['Authorization'] = `Basic ${credentials}`;
398
+ }
399
+ } else if (auth.scheme === 'apiKey') {
400
+ let apiKey: string | null = null;
401
+ const apiKeyEnvVar = auth.envVar || 'API_KEY';
402
+ if (options.authProvider) {
403
+ apiKey = await options.authProvider.getCredential(apiKeyEnvVar);
404
+ }
405
+ if (!apiKey) {
406
+ apiKey = process.env[apiKeyEnvVar] || null;
407
+ }
408
+
409
+ if (apiKey) {
410
+ if (auth.in === 'header') {
411
+ headers[auth.name] = apiKey;
412
+ } else if (auth.in === 'query') {
413
+ queryParams[auth.name] = apiKey;
414
+ }
415
+ }
416
+ }
417
+ }
418
+
419
+ // Replace path parameters
420
+ if (operation.parameters) {
421
+ for (const param of operation.parameters) {
422
+ if (param.in === 'path' && input[param.name]) {
423
+ requestPath = requestPath.replace(
424
+ `{${param.name}}`,
425
+ encodeURIComponent(String(input[param.name]))
426
+ );
427
+ } else if (param.in === 'query' && input[param.name] !== undefined) {
428
+ queryParams[param.name] = String(input[param.name]);
429
+ } else if (param.in === 'header' && input[param.name]) {
430
+ headers[param.name] = String(input[param.name]);
431
+ }
432
+ }
433
+ }
434
+
435
+ // Add request body if present
436
+ if (operation.requestBody && ['post', 'put', 'patch'].includes(method.toLowerCase())) {
437
+ // Collect body properties
438
+ const bodyParams: Record<string, any> = {};
439
+ if (operation.parameters) {
440
+ const paramNames = operation.parameters.map((p) => p.name);
441
+ for (const key in input) {
442
+ if (!paramNames.includes(key)) {
443
+ bodyParams[key] = input[key];
444
+ }
445
+ }
446
+ } else {
447
+ Object.assign(bodyParams, input);
448
+ }
449
+ if (Object.keys(bodyParams).length > 0) {
450
+ body = bodyParams;
451
+ }
452
+ }
453
+
454
+ // Build URL with query params
455
+ if (!baseURL) {
456
+ throw new Error(
457
+ `No baseURL configured for OpenAPI spec. Check that the spec has a 'servers' section with a valid URL.`
458
+ );
459
+ }
460
+
461
+ const baseUrlObj = new URL(baseURL);
462
+ const basePath = baseUrlObj.pathname.replace(/\/$/, '');
463
+ const fullPath = basePath + requestPath;
464
+ const url = new URL(fullPath, baseUrlObj.origin);
465
+
466
+ for (const [key, value] of Object.entries(queryParams)) {
467
+ url.searchParams.append(key, value);
468
+ }
469
+
470
+ // Make the HTTP request
471
+ try {
472
+ const response = await fetch(url.toString(), {
473
+ method: method.toUpperCase(),
474
+ headers,
475
+ body: body ? JSON.stringify(body) : undefined,
476
+ });
477
+
478
+ if (!response.ok) {
479
+ const errorText = await response.text();
480
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
481
+ }
482
+
483
+ // Handle 204 No Content
484
+ if (response.status === 204) {
485
+ return { success: true };
486
+ }
487
+
488
+ const contentType = response.headers.get('content-type');
489
+ if (contentType?.includes('application/json')) {
490
+ const text = await response.text();
491
+ // Handle empty response body
492
+ if (!text || text.trim() === '') {
493
+ return { success: true };
494
+ }
495
+ return JSON.parse(text);
496
+ } else {
497
+ return await response.text();
498
+ }
499
+ } catch (error: any) {
500
+ throw new Error(`Failed to execute ${method.toUpperCase()} ${path}: ${error.message}`);
501
+ }
502
+ };
503
+
504
+ return {
505
+ name: functionName,
506
+ description,
507
+ inputSchema,
508
+ outputSchema,
509
+ handler,
510
+ keywords: operation.tags || [],
511
+ };
512
+ }
513
+
514
+ /**
515
+ * Build input JSON schema from parameters and requestBody
516
+ */
517
+ function buildInputSchema(operation: OpenAPIOperation, spec: APISpec): unknown {
518
+ const properties: Record<string, unknown> = {};
519
+ const required: string[] = [];
520
+
521
+ if (operation.parameters) {
522
+ for (const param of operation.parameters) {
523
+ if (param.schema) {
524
+ properties[param.name] = resolveSchema(param.schema, spec);
525
+ if (param.required) {
526
+ required.push(param.name);
527
+ }
528
+ }
529
+ }
530
+ }
531
+
532
+ if (operation.requestBody?.content?.['application/json']?.schema) {
533
+ const bodySchema = resolveSchema(
534
+ operation.requestBody.content['application/json'].schema,
535
+ spec
536
+ );
537
+
538
+ if (typeof bodySchema === 'object' && bodySchema !== null && 'properties' in bodySchema) {
539
+ Object.assign(properties, (bodySchema as any).properties);
540
+ if ('required' in bodySchema && Array.isArray((bodySchema as any).required)) {
541
+ required.push(...(bodySchema as any).required);
542
+ }
543
+ }
544
+ }
545
+
546
+ return {
547
+ type: 'object',
548
+ properties,
549
+ required: required.length > 0 ? required : undefined,
550
+ };
551
+ }
552
+
553
+ /**
554
+ * Build output JSON schema from responses
555
+ */
556
+ function buildOutputSchema(operation: OpenAPIOperation, spec: APISpec): unknown | undefined {
557
+ const successResponse =
558
+ operation.responses?.['200'] ||
559
+ operation.responses?.['201'] ||
560
+ operation.responses?.['default'];
561
+
562
+ if (!successResponse?.content?.['application/json']?.schema) {
563
+ return undefined;
564
+ }
565
+
566
+ return resolveSchema(successResponse.content['application/json'].schema, spec, new Set());
567
+ }
568
+
569
+ /**
570
+ * Resolve schema references ($ref) with circular reference detection
571
+ */
572
+ function resolveSchema(
573
+ schema: OpenAPISchema,
574
+ spec: APISpec,
575
+ visited: Set<string> = new Set()
576
+ ): unknown {
577
+ if (schema.$ref) {
578
+ // Check for circular reference
579
+ if (visited.has(schema.$ref)) {
580
+ // Return a placeholder for circular references
581
+ return { type: 'object', description: 'Circular reference: ' + schema.$ref };
582
+ }
583
+
584
+ const refPath = schema.$ref.split('/').slice(1);
585
+ let resolved: unknown = spec;
586
+
587
+ for (const part of refPath) {
588
+ resolved = (resolved as Record<string, unknown>)?.[part];
589
+ }
590
+
591
+ if (resolved) {
592
+ visited.add(schema.$ref);
593
+ const result = resolveSchema(resolved as OpenAPISchema, spec, visited);
594
+ visited.delete(schema.$ref);
595
+ return result;
596
+ }
597
+ }
598
+
599
+ const jsonSchema: Record<string, unknown> = { type: schema.type || 'object' };
600
+
601
+ if (schema.properties) {
602
+ const properties: Record<string, unknown> = {};
603
+ for (const [key, value] of Object.entries(schema.properties)) {
604
+ properties[key] = resolveSchema(value, spec, visited);
605
+ }
606
+ jsonSchema.properties = properties;
607
+ }
608
+
609
+ if (schema.items) {
610
+ jsonSchema.items = resolveSchema(schema.items, spec, visited);
611
+ }
612
+
613
+ if (schema.required) {
614
+ jsonSchema.required = schema.required;
615
+ }
616
+
617
+ if (schema.enum) {
618
+ jsonSchema.enum = schema.enum;
619
+ }
620
+
621
+ if (schema.description) {
622
+ jsonSchema.description = schema.description;
623
+ }
624
+
625
+ return jsonSchema;
626
+ }
627
+
628
+ /**
629
+ * Extract annotations from OpenAPI extensions
630
+ */
631
+ function extractAnnotations(
632
+ operation: OpenAPIOperation,
633
+ operationKey: string,
634
+ annotationOptions?: LoadOpenAPIOptions['annotations']
635
+ ): Record<string, unknown> {
636
+ const annotations: Record<string, unknown> = {};
637
+
638
+ if (annotationOptions?.global) {
639
+ Object.assign(annotations, annotationOptions.global);
640
+ }
641
+
642
+ if (annotationOptions?.operations?.[operationKey]) {
643
+ Object.assign(annotations, annotationOptions.operations[operationKey]);
644
+ }
645
+
646
+ if (annotationOptions?.fromExtensions) {
647
+ for (const [extensionKey, annotationKey] of Object.entries(annotationOptions.fromExtensions)) {
648
+ if (extensionKey in operation) {
649
+ annotations[annotationKey] = operation[extensionKey];
650
+ }
651
+ }
652
+ } else {
653
+ if (operation['x-destructive']) {
654
+ annotations.destructive = operation['x-destructive'];
655
+ }
656
+ if (operation['x-requires-approval']) {
657
+ annotations.requiresApproval = operation['x-requires-approval'];
658
+ }
659
+ if (operation['x-risk-level']) {
660
+ annotations.risk = operation['x-risk-level'];
661
+ }
662
+ if (operation['x-confirm-prompt']) {
663
+ annotations.confirmPrompt = operation['x-confirm-prompt'];
664
+ }
665
+ }
666
+
667
+ return annotations;
668
+ }
669
+
670
+ /**
671
+ * Detect authentication from OpenAPI securitySchemes or Swagger securityDefinitions
672
+ */
673
+ function detectAuth(spec: APISpec, authProvider?: AuthProvider): AuthConfig | undefined {
674
+ let schemeName: string | undefined;
675
+
676
+ // Try to get scheme from security requirements
677
+ if (spec.security && spec.security.length > 0) {
678
+ const securityReq = spec.security[0];
679
+ if (securityReq) {
680
+ schemeName = Object.keys(securityReq)[0];
681
+ }
682
+ }
683
+
684
+ const securitySchemes = isOpenAPI3(spec)
685
+ ? spec.components?.securitySchemes
686
+ : isSwagger2(spec)
687
+ ? spec.securityDefinitions
688
+ : undefined;
689
+
690
+ if (!schemeName && securitySchemes) {
691
+ const schemes = Object.keys(securitySchemes);
692
+ if (schemes.length > 0) {
693
+ schemeName = schemes[0];
694
+ console.log(
695
+ `[AUTH] No security requirements found, using first securityScheme: ${schemeName}`
696
+ );
697
+ }
698
+ }
699
+
700
+ if (!schemeName || !securitySchemes) {
701
+ return undefined;
702
+ }
703
+
704
+ const scheme = securitySchemes[schemeName];
705
+ if (!scheme) {
706
+ return undefined;
707
+ }
708
+
709
+ // Get API name for environment variable prefix
710
+ const apiName = spec.info.title.toUpperCase().replace(/[^A-Z0-9]/g, '_');
711
+
712
+ switch (scheme.type) {
713
+ case 'http':
714
+ if (scheme.scheme === 'bearer') {
715
+ const authConfig: BearerAuthConfig = {
716
+ scheme: 'bearer',
717
+ envVar: `${apiName}_TOKEN`,
718
+ };
719
+ console.log(`[AUTH] Detected Bearer token auth: envVar=${authConfig.envVar}`);
720
+ return authConfig;
721
+ } else if (scheme.scheme === 'basic') {
722
+ const authConfig: BasicAuthConfig = {
723
+ scheme: 'basic',
724
+ usernameEnvVar: `${apiName}_USERNAME`,
725
+ passwordEnvVar: `${apiName}_PASSWORD`,
726
+ };
727
+ console.log(
728
+ `[AUTH] Detected Basic auth: username=${authConfig.usernameEnvVar}, password=${authConfig.passwordEnvVar}`
729
+ );
730
+ return authConfig;
731
+ }
732
+ break;
733
+ case 'apiKey': {
734
+ const authConfig: APIKeyAuthConfig = {
735
+ scheme: 'apiKey',
736
+ in: scheme.in === 'query' ? 'query' : 'header',
737
+ name: scheme.name || 'X-API-Key',
738
+ envVar: `${apiName}_API_KEY`,
739
+ };
740
+ return authConfig;
741
+ }
742
+ }
743
+ return undefined;
744
+ }