@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,224 @@
1
+ import { sanitizeInput, MAX_CODE_SIZE } from '@mondaydotcomorg/atp-protocol';
2
+ import * as acorn from 'acorn';
3
+ /**
4
+ * CodeValidator validates user code before execution using a whitelist approach.
5
+ * Only explicitly allowed operations and patterns are permitted.
6
+ */
7
+ export class CodeValidator {
8
+ allowedGlobalObjects = new Set([
9
+ 'Array',
10
+ 'Object',
11
+ 'String',
12
+ 'Number',
13
+ 'Boolean',
14
+ 'Date',
15
+ 'Math',
16
+ 'JSON',
17
+ 'Promise',
18
+ 'Map',
19
+ 'Set',
20
+ 'WeakMap',
21
+ 'WeakSet',
22
+ 'Error',
23
+ 'TypeError',
24
+ 'RangeError',
25
+ 'console',
26
+ ]);
27
+ forbiddenPatterns = [
28
+ /\beval\s*\(/,
29
+ /\bnew\s+Function\s*\(/,
30
+ /\bnew\s+AsyncFunction\s*\(/,
31
+ /\bnew\s+GeneratorFunction\s*\(/,
32
+ /\brequire\s*\(/,
33
+ /\bprocess\b/,
34
+ /\bglobal\b/,
35
+ /\bglobalThis\.process\b/,
36
+ /\bglobalThis\.global\b/,
37
+ /\b__dirname\b/,
38
+ /\b__filename\b/,
39
+ /\bmodule\b/,
40
+ /\bexports\b/,
41
+ /\bBuffer\b/,
42
+ // Constructor chain exploits - CRITICAL security issue
43
+ /constructor\s*\[\s*['"`]constructor['"`]\s*\]/,
44
+ /constructor\.constructor/,
45
+ /\['constructor'\]\s*\[\s*['"`]constructor['"`]\s*\]/,
46
+ /\["constructor"\]\s*\[\s*['"`]constructor['"`]\s*\]/,
47
+ /\[`constructor`\]\s*\[\s*['"`]constructor['"`]\s*\]/,
48
+ // Prototype chain manipulation - sandbox escape vectors
49
+ /__proto__/,
50
+ /Object\.getPrototypeOf/,
51
+ /Object\.setPrototypeOf/,
52
+ /Reflect\.construct/,
53
+ /Reflect\.get/,
54
+ /Reflect\.set/,
55
+ // Indirect eval patterns
56
+ /\['eval'\]/,
57
+ /\["eval"\]/,
58
+ /\[`eval`\]/,
59
+ /window\['eval'\]/,
60
+ /this\['eval'\]/,
61
+ ];
62
+ /**
63
+ * Validates code for security and syntax issues.
64
+ * @param code - The code to validate
65
+ * @param config - Execution configuration
66
+ * @returns Validation result with any errors or security issues
67
+ */
68
+ async validate(code, config) {
69
+ const errors = [];
70
+ const warnings = [];
71
+ const securityIssues = [];
72
+ code = sanitizeInput(code, MAX_CODE_SIZE);
73
+ for (const pattern of this.forbiddenPatterns) {
74
+ if (pattern.test(code)) {
75
+ securityIssues.push({
76
+ line: 0,
77
+ issue: `Forbidden pattern detected: ${pattern.source}`,
78
+ risk: 'high',
79
+ });
80
+ }
81
+ }
82
+ this.checkGlobalAccess(code, securityIssues);
83
+ this.validateImports(code, securityIssues);
84
+ this.validateSyntax(code, errors);
85
+ const hasHighRiskIssues = securityIssues.some((issue) => issue.risk === 'high');
86
+ return {
87
+ valid: errors.length === 0 && !hasHighRiskIssues,
88
+ errors: errors.length > 0 ? errors : undefined,
89
+ warnings: warnings.length > 0 ? warnings : undefined,
90
+ securityIssues: securityIssues.length > 0 ? securityIssues : undefined,
91
+ };
92
+ }
93
+ /**
94
+ * Validates JavaScript syntax using acorn parser.
95
+ * @param code - Code to validate
96
+ * @param errors - Array to append syntax errors to
97
+ */
98
+ validateSyntax(code, errors) {
99
+ try {
100
+ acorn.parse(code, {
101
+ ecmaVersion: 2022,
102
+ sourceType: 'script',
103
+ allowAwaitOutsideFunction: true,
104
+ allowReturnOutsideFunction: true,
105
+ });
106
+ }
107
+ catch (scriptError) {
108
+ try {
109
+ acorn.parse(code, {
110
+ ecmaVersion: 2022,
111
+ sourceType: 'module',
112
+ allowAwaitOutsideFunction: true,
113
+ allowReturnOutsideFunction: false,
114
+ });
115
+ }
116
+ catch (moduleError) {
117
+ errors.push({
118
+ line: moduleError.loc?.line ?? 0,
119
+ message: `Syntax error: ${moduleError.message}`,
120
+ severity: 'error',
121
+ });
122
+ }
123
+ }
124
+ }
125
+ /**
126
+ * Checks for unauthorized global object access.
127
+ * @param code - Code to check
128
+ * @param securityIssues - Array to append issues to
129
+ */
130
+ checkGlobalAccess(code, securityIssues) {
131
+ const globalAccessPattern = /\b([A-Z][a-zA-Z0-9]*)\./g;
132
+ let match;
133
+ while ((match = globalAccessPattern.exec(code)) !== null) {
134
+ const globalName = match[1];
135
+ if (globalName &&
136
+ !this.allowedGlobalObjects.has(globalName) &&
137
+ globalName !== 'atp' &&
138
+ globalName !== 'api') {
139
+ securityIssues.push({
140
+ line: 0,
141
+ issue: `Unauthorized global access: ${globalName}`,
142
+ risk: 'medium',
143
+ });
144
+ }
145
+ }
146
+ }
147
+ /**
148
+ * Validates import statements to ensure NO imports are allowed.
149
+ * ALL imports are blocked for security - use injected sandbox globals instead.
150
+ * @param code - Code to validate
151
+ * @param securityIssues - Array to append issues to
152
+ */
153
+ validateImports(code, securityIssues) {
154
+ try {
155
+ const ast = acorn.parse(code, {
156
+ ecmaVersion: 2022,
157
+ sourceType: 'module',
158
+ allowAwaitOutsideFunction: true,
159
+ allowReturnOutsideFunction: true,
160
+ });
161
+ const walk = (node) => {
162
+ if (!node || typeof node !== 'object')
163
+ return;
164
+ if (node.type === 'ImportDeclaration') {
165
+ const importSource = node.source?.value;
166
+ securityIssues.push({
167
+ line: node.loc?.start?.line ?? 0,
168
+ issue: `All imports are blocked for security. Import attempted: ${importSource}. Use injected sandbox globals (api, atp) instead.`,
169
+ risk: 'high',
170
+ });
171
+ }
172
+ if (node.type === 'ImportExpression') {
173
+ securityIssues.push({
174
+ line: node.loc?.start?.line ?? 0,
175
+ issue: `Dynamic import() is not allowed. All imports are blocked for security.`,
176
+ risk: 'high',
177
+ });
178
+ }
179
+ if (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') {
180
+ if (node.source?.value) {
181
+ const exportSource = node.source.value;
182
+ securityIssues.push({
183
+ line: node.loc?.start?.line ?? 0,
184
+ issue: `Re-exports are not allowed. Attempted re-export from: ${exportSource}.`,
185
+ risk: 'high',
186
+ });
187
+ }
188
+ }
189
+ for (const key in node) {
190
+ if (key === 'loc' || key === 'range' || key === 'start' || key === 'end')
191
+ continue;
192
+ const child = node[key];
193
+ if (Array.isArray(child)) {
194
+ child.forEach(walk);
195
+ }
196
+ else if (child && typeof child === 'object') {
197
+ walk(child);
198
+ }
199
+ }
200
+ };
201
+ walk(ast);
202
+ }
203
+ catch (error) {
204
+ const importPattern = /^\s*import\s+.*?\s+from\s+['"](.+?)['"]/gm;
205
+ let match;
206
+ while ((match = importPattern.exec(code)) !== null) {
207
+ const importSource = match[1];
208
+ securityIssues.push({
209
+ line: 0,
210
+ issue: `All imports are blocked for security. Import detected: ${importSource}.`,
211
+ risk: 'high',
212
+ });
213
+ }
214
+ if (/import\s*\(/.test(code)) {
215
+ securityIssues.push({
216
+ line: 0,
217
+ issue: `Dynamic import() is not allowed. All imports are blocked for security.`,
218
+ risk: 'high',
219
+ });
220
+ }
221
+ }
222
+ }
223
+ }
224
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validator/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B;;;GAGG;AACH,MAAM,OAAO,aAAa;IACR,oBAAoB,GAAG,IAAI,GAAG,CAAC;QAC/C,OAAO;QACP,QAAQ;QACR,QAAQ;QACR,QAAQ;QACR,SAAS;QACT,MAAM;QACN,MAAM;QACN,MAAM;QACN,SAAS;QACT,KAAK;QACL,KAAK;QACL,SAAS;QACT,SAAS;QACT,OAAO;QACP,WAAW;QACX,YAAY;QACZ,SAAS;KACT,CAAC,CAAC;IAEc,iBAAiB,GAAG;QACpC,aAAa;QACb,uBAAuB;QACvB,4BAA4B;QAC5B,gCAAgC;QAChC,gBAAgB;QAChB,aAAa;QACb,YAAY;QACZ,yBAAyB;QACzB,wBAAwB;QACxB,eAAe;QACf,gBAAgB;QAChB,YAAY;QACZ,aAAa;QACb,YAAY;QACZ,uDAAuD;QACvD,+CAA+C;QAC/C,0BAA0B;QAC1B,qDAAqD;QACrD,qDAAqD;QACrD,qDAAqD;QACrD,wDAAwD;QACxD,WAAW;QACX,wBAAwB;QACxB,wBAAwB;QACxB,oBAAoB;QACpB,cAAc;QACd,cAAc;QACd,yBAAyB;QACzB,YAAY;QACZ,YAAY;QACZ,YAAY;QACZ,kBAAkB;QAClB,gBAAgB;KAChB,CAAC;IAEF;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,MAAuB;QACnD,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,MAAM,cAAc,GAAoB,EAAE,CAAC;QAE3C,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAE1C,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC9C,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,cAAc,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,CAAC;oBACP,KAAK,EAAE,+BAA+B,OAAO,CAAC,MAAM,EAAE;oBACtD,IAAI,EAAE,MAAM;iBACZ,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAED,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAE7C,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAE3C,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAElC,MAAM,iBAAiB,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QAEhF,OAAO;YACN,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,iBAAiB;YAChD,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YAC9C,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YACpD,cAAc,EAAE,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;SACtE,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,IAAY,EAAE,MAAyB;QAC7D,IAAI,CAAC;YACJ,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;gBACjB,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,QAAQ;gBACpB,yBAAyB,EAAE,IAAI;gBAC/B,0BAA0B,EAAE,IAAI;aAChC,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,WAAgB,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACJ,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;oBACjB,WAAW,EAAE,IAAI;oBACjB,UAAU,EAAE,QAAQ;oBACpB,yBAAyB,EAAE,IAAI;oBAC/B,0BAA0B,EAAE,KAAK;iBACjC,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,WAAgB,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,WAAW,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;oBAChC,OAAO,EAAE,iBAAiB,WAAW,CAAC,OAAO,EAAE;oBAC/C,QAAQ,EAAE,OAAO;iBACjB,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;OAIG;IACK,iBAAiB,CAAC,IAAY,EAAE,cAA+B;QACtE,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;QACvD,IAAI,KAAK,CAAC;QAEV,OAAO,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5B,IACC,UAAU;gBACV,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC;gBAC1C,UAAU,KAAK,KAAK;gBACpB,UAAU,KAAK,KAAK,EACnB,CAAC;gBACF,cAAc,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,CAAC;oBACP,KAAK,EAAE,+BAA+B,UAAU,EAAE;oBAClD,IAAI,EAAE,QAAQ;iBACd,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,eAAe,CAAC,IAAY,EAAE,cAA+B;QACpE,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;gBAC7B,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,QAAQ;gBACpB,yBAAyB,EAAE,IAAI;gBAC/B,0BAA0B,EAAE,IAAI;aAChC,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,CAAC,IAAS,EAAE,EAAE;gBAC1B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;oBAAE,OAAO;gBAE9C,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;oBACvC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;oBACxC,cAAc,CAAC,IAAI,CAAC;wBACnB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC;wBAChC,KAAK,EAAE,2DAA2D,YAAY,oDAAoD;wBAClI,IAAI,EAAE,MAAM;qBACZ,CAAC,CAAC;gBACJ,CAAC;gBAED,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;oBACtC,cAAc,CAAC,IAAI,CAAC;wBACnB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC;wBAChC,KAAK,EAAE,wEAAwE;wBAC/E,IAAI,EAAE,MAAM;qBACZ,CAAC,CAAC;gBACJ,CAAC;gBAED,IAAI,IAAI,CAAC,IAAI,KAAK,wBAAwB,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;oBACpF,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;wBACxB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;wBACvC,cAAc,CAAC,IAAI,CAAC;4BACnB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC;4BAChC,KAAK,EAAE,yDAAyD,YAAY,GAAG;4BAC/E,IAAI,EAAE,MAAM;yBACZ,CAAC,CAAC;oBACJ,CAAC;gBACF,CAAC;gBAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACxB,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,KAAK;wBAAE,SAAS;oBACnF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;oBACxB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBAC1B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBACrB,CAAC;yBAAM,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;wBAC/C,IAAI,CAAC,KAAK,CAAC,CAAC;oBACb,CAAC;gBACF,CAAC;YACF,CAAC,CAAC;YAEF,IAAI,CAAC,GAAG,CAAC,CAAC;QACX,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,aAAa,GAAG,2CAA2C,CAAC;YAClE,IAAI,KAAK,CAAC;YACV,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACpD,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC9B,cAAc,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,CAAC;oBACP,KAAK,EAAE,0DAA0D,YAAY,GAAG;oBAChF,IAAI,EAAE,MAAM;iBACZ,CAAC,CAAC;YACJ,CAAC;YAED,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,cAAc,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,CAAC;oBACP,KAAK,EAAE,wEAAwE;oBAC/E,IAAI,EAAE,MAAM;iBACZ,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;CACD"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@mondaydotcomorg/atp-server",
3
+ "version": "0.17.14",
4
+ "description": "Server implementation for Agent Tool Protocol",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "scripts": {
19
+ "build": "npm run generate:bootstrap && tsc -p tsconfig.json",
20
+ "generate:bootstrap": "tsx scripts/generate-bootstrap.ts",
21
+ "dev": "tsc -p tsconfig.json --watch",
22
+ "clean": "rm -rf dist *.tsbuildinfo",
23
+ "test": "vitest run",
24
+ "lint": "tsc --noEmit"
25
+ },
26
+ "keywords": [
27
+ "agent",
28
+ "protocol",
29
+ "server",
30
+ "ai",
31
+ "llm"
32
+ ],
33
+ "license": "MIT",
34
+ "dependencies": {
35
+ "@babel/generator": "^7.26.0",
36
+ "@babel/parser": "^7.26.0",
37
+ "@babel/traverse": "^7.26.0",
38
+ "@babel/types": "^7.26.0",
39
+ "@mondaydotcomorg/atp-compiler": "0.17.14",
40
+ "@mondaydotcomorg/atp-protocol": "0.17.14",
41
+ "@mondaydotcomorg/atp-provenance": "0.17.14",
42
+ "@mondaydotcomorg/atp-runtime": "0.17.14",
43
+ "@opentelemetry/api": "^1.9.0",
44
+ "@opentelemetry/auto-instrumentations-node": "^0.66.0",
45
+ "@opentelemetry/core": "^2.2.0",
46
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.207.0",
47
+ "@opentelemetry/exporter-trace-otlp-http": "^0.207.0",
48
+ "@opentelemetry/resources": "^2.2.0",
49
+ "@opentelemetry/sdk-node": "^0.207.0",
50
+ "@opentelemetry/semantic-conventions": "^1.37.0",
51
+ "@types/acorn": "^6.0.4",
52
+ "isolated-vm": "5.0.4",
53
+ "js-yaml": "^4.1.0",
54
+ "jsonwebtoken": "^9.0.2",
55
+ "nanoid": "^5.1.6",
56
+ "rate-limiter-flexible": "*"
57
+ },
58
+ "devDependencies": {
59
+ "@types/babel__generator": "^7.6.8",
60
+ "@types/babel__traverse": "^7.20.5",
61
+ "@types/escodegen": "^0.0.10",
62
+ "@types/js-yaml": "^4.0.9",
63
+ "@types/jsonwebtoken": "^9.0.5",
64
+ "@types/node": "^20.11.5",
65
+ "typescript": "^5.3.3",
66
+ "vitest": "^1.2.1"
67
+ }
68
+ }
@@ -0,0 +1,207 @@
1
+ import type { APIGroupConfig, CustomFunctionDef } from '@mondaydotcomorg/atp-protocol';
2
+ import { generateRuntimeTypes } from '../utils/runtime-types.js';
3
+
4
+ /**
5
+ * APIAggregator generates TypeScript type definitions from API configurations.
6
+ * Converts API group definitions into TypeScript declarations for use in code generation.
7
+ */
8
+ export class APIAggregator {
9
+ private apiGroups: APIGroupConfig[];
10
+
11
+ /**
12
+ * Creates a new APIAggregator instance.
13
+ * @param apiGroups - Array of API group configurations
14
+ */
15
+ constructor(apiGroups: APIGroupConfig[]) {
16
+ this.apiGroups = apiGroups;
17
+ }
18
+
19
+ /**
20
+ * Generates TypeScript type definitions for selected API groups.
21
+ * @param selectedGroups - Optional array of group names to include
22
+ * @returns TypeScript definition string
23
+ */
24
+ async generateTypeScript(selectedGroups?: string[]): Promise<string> {
25
+ const groups = selectedGroups
26
+ ? this.apiGroups.filter((g) => selectedGroups.includes(g.name))
27
+ : this.apiGroups;
28
+
29
+ let typescript = `// Agent Tool Protocol Runtime SDK v1.0.0\n\n`;
30
+
31
+ typescript += this.generateRuntimeTypes();
32
+
33
+ for (const group of groups) {
34
+ typescript += `\n// API Group: ${group.name}\n`;
35
+ if (group.functions) {
36
+ for (const func of group.functions) {
37
+ typescript += this.generateFunctionTypes(func, group.name);
38
+ }
39
+ }
40
+ }
41
+
42
+ typescript += this.generateAPINamespace(groups);
43
+
44
+ return typescript;
45
+ }
46
+
47
+ /**
48
+ * Generates TypeScript definitions for the runtime SDK.
49
+ * @returns TypeScript definition string
50
+ */
51
+ private generateRuntimeTypes(): string {
52
+ return generateRuntimeTypes();
53
+ }
54
+
55
+ /**
56
+ * Generates TypeScript types for a single function.
57
+ * @param func - Function definition
58
+ * @param groupName - API group name
59
+ * @returns TypeScript definition string
60
+ */
61
+ private generateFunctionTypes(func: CustomFunctionDef, groupName: string): string {
62
+ const inputTypeName = `${func.name}_Input`;
63
+ const outputTypeName = `${func.name}_Output`;
64
+
65
+ let typescript = `\ninterface ${inputTypeName} {\n`;
66
+ if (func.inputSchema?.properties) {
67
+ const required = func.inputSchema.required || [];
68
+ for (const [key, value] of Object.entries(func.inputSchema.properties)) {
69
+ const prop = value as { type?: string; description?: string };
70
+ const tsType = this.jsonSchemaTypeToTS(prop.type ?? 'any');
71
+ const comment = prop.description ? ` // ${prop.description}` : '';
72
+ const optional = required.includes(key) ? '' : '?';
73
+ typescript += ` ${key}${optional}: ${tsType};${comment}\n`;
74
+ }
75
+ }
76
+ typescript += `}\n`;
77
+
78
+ typescript += `\ninterface ${outputTypeName} {\n`;
79
+ typescript += ` [key: string]: unknown;\n`;
80
+ typescript += `}\n`;
81
+
82
+ return typescript;
83
+ }
84
+
85
+ /**
86
+ * Converts JSON Schema type to TypeScript type.
87
+ * @param type - JSON Schema type string
88
+ * @returns TypeScript type string
89
+ */
90
+ private jsonSchemaTypeToTS(type: string): string {
91
+ switch (type) {
92
+ case 'string':
93
+ return 'string';
94
+ case 'number':
95
+ case 'integer':
96
+ return 'number';
97
+ case 'boolean':
98
+ return 'boolean';
99
+ case 'array':
100
+ return 'unknown[]';
101
+ case 'object':
102
+ return 'Record<string, unknown>';
103
+ default:
104
+ return 'unknown';
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Helper to check if a string is a valid JavaScript identifier
110
+ */
111
+ private isValidIdentifier(name: string): boolean {
112
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
113
+ }
114
+
115
+ /**
116
+ * Helper to safely format a property name for TypeScript type definitions
117
+ * Returns the property name with quotes if needed, or just the name if valid
118
+ */
119
+ private formatPropertyName(name: string): string {
120
+ if (!this.isValidIdentifier(name)) {
121
+ return `'${name}'`;
122
+ }
123
+ return name;
124
+ }
125
+
126
+ /**
127
+ * Generates the API namespace with all function declarations.
128
+ * Handles hierarchical group names (e.g., "github/readOnly" -> api.github.readOnly)
129
+ * @param groups - API groups to include
130
+ * @returns TypeScript definition string
131
+ */
132
+ private generateAPINamespace(groups: APIGroupConfig[]): string {
133
+ interface NestedGroup {
134
+ functions: CustomFunctionDef[];
135
+ subgroups: Map<string, NestedGroup>;
136
+ }
137
+
138
+ const rootGroups = new Map<string, NestedGroup>();
139
+
140
+ for (const group of groups) {
141
+ if (!group.functions || group.functions.length === 0) continue;
142
+
143
+ const parts = group.name.split('/');
144
+ let current = rootGroups;
145
+
146
+ for (let i = 0; i < parts.length; i++) {
147
+ const part = parts[i]!;
148
+
149
+ if (!current.has(part)) {
150
+ current.set(part, { functions: [], subgroups: new Map() });
151
+ }
152
+
153
+ const node = current.get(part)!;
154
+
155
+ if (i === parts.length - 1) {
156
+ node.functions.push(...group.functions);
157
+ }
158
+
159
+ current = node.subgroups;
160
+ }
161
+ }
162
+
163
+ const generateLevel = (groups: Map<string, NestedGroup>, indent: string): string => {
164
+ let ts = '';
165
+
166
+ for (const [name, node] of groups.entries()) {
167
+ if (!name) continue;
168
+ const formattedName = this.formatPropertyName(name);
169
+ ts += `${indent}${formattedName}: {\n`;
170
+
171
+ for (const func of node.functions) {
172
+ if (!func.name) continue;
173
+ const funcName = this.formatPropertyName(func.name);
174
+ const description =
175
+ func.description && typeof func.description === 'string'
176
+ ? func.description.replace(/\n/g, ' ').substring(0, 200)
177
+ : '';
178
+ ts += `${indent} /**\n${indent} * ${description}\n${indent} */\n`;
179
+ ts += `${indent} ${funcName}(params: ${func.name}_Input): Promise<${func.name}_Output>;\n`;
180
+ }
181
+
182
+ if (node.subgroups.size > 0) {
183
+ ts += generateLevel(node.subgroups, indent + ' ');
184
+ }
185
+
186
+ ts += `${indent}};\n`;
187
+ }
188
+
189
+ return ts;
190
+ };
191
+
192
+ let typescript = `\ndeclare const api: {\n`;
193
+ typescript += generateLevel(rootGroups, ' ');
194
+ typescript += `};\n`;
195
+ typescript += `\nexport { api };\n`;
196
+
197
+ return typescript;
198
+ }
199
+
200
+ /**
201
+ * Gets the list of available API group names.
202
+ * @returns Array of API group names
203
+ */
204
+ getApiGroups(): string[] {
205
+ return this.apiGroups.map((g) => g.name);
206
+ }
207
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Client Callback Manager
3
+ *
4
+ * Handles callbacks to clients for LLM, approval, and embedding requests
5
+ */
6
+ import type { ClientServices } from '@mondaydotcomorg/atp-protocol';
7
+
8
+ /**
9
+ * Callback request types
10
+ */
11
+ export type CallbackType = 'llm' | 'approval' | 'embedding';
12
+
13
+ /**
14
+ * Callback request payload
15
+ */
16
+ export interface CallbackRequest {
17
+ type: CallbackType;
18
+ operation: string;
19
+ payload: Record<string, unknown>;
20
+ }
21
+
22
+ /**
23
+ * Registered client information
24
+ */
25
+ interface ClientInfo {
26
+ clientId: string;
27
+ services: ClientServices;
28
+ callbackUrl?: string;
29
+ lastSeen: Date;
30
+ }
31
+
32
+ /**
33
+ * Callback handler function
34
+ */
35
+ export type CallbackHandler = (clientId: string, request: CallbackRequest) => Promise<unknown>;
36
+
37
+ /**
38
+ * Manages client callbacks for provided services
39
+ */
40
+ export class ClientCallbackManager {
41
+ private clients: Map<string, ClientInfo> = new Map();
42
+ private callbackHandler?: CallbackHandler;
43
+ private cleanupInterval?: NodeJS.Timeout;
44
+
45
+ /**
46
+ * Registers a callback handler for client requests
47
+ * @param handler - Function to handle callbacks
48
+ */
49
+ setCallbackHandler(handler: CallbackHandler): void {
50
+ this.callbackHandler = handler;
51
+
52
+ if (!this.cleanupInterval) {
53
+ this.cleanupInterval = setInterval(
54
+ () => {
55
+ const cleaned = this.cleanupStaleClients();
56
+ if (cleaned > 0) {
57
+ console.log(`[ClientCallback] Cleaned up ${cleaned} stale clients`);
58
+ }
59
+ },
60
+ 5 * 60 * 1000
61
+ );
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Registers a client with their provided services
67
+ * @param clientId - Unique client identifier
68
+ * @param services - Services provided by client
69
+ * @param callbackUrl - Optional webhook URL for callbacks
70
+ */
71
+ registerClient(clientId: string, services: ClientServices, callbackUrl?: string): void {
72
+ this.clients.set(clientId, {
73
+ clientId,
74
+ services,
75
+ callbackUrl,
76
+ lastSeen: new Date(),
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Updates client's last seen timestamp
82
+ * @param clientId - Client identifier
83
+ */
84
+ updateClientActivity(clientId: string): void {
85
+ const client = this.clients.get(clientId);
86
+ if (client) {
87
+ client.lastSeen = new Date();
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Checks if client has a specific service
93
+ * @param clientId - Client identifier
94
+ * @param serviceType - Type of service
95
+ * @returns Whether client provides this service
96
+ */
97
+ hasClientService(clientId: string, serviceType: 'llm' | 'approval' | 'embedding'): boolean {
98
+ const client = this.clients.get(clientId);
99
+ if (!client) return false;
100
+
101
+ switch (serviceType) {
102
+ case 'llm':
103
+ return client.services.hasLLM;
104
+ case 'approval':
105
+ return client.services.hasApproval;
106
+ case 'embedding':
107
+ return client.services.hasEmbedding;
108
+ default:
109
+ return false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Gets client information
115
+ * @param clientId - Client identifier
116
+ * @returns Client info or undefined
117
+ */
118
+ getClient(clientId: string): ClientInfo | undefined {
119
+ return this.clients.get(clientId);
120
+ }
121
+
122
+ /**
123
+ * Sends a callback request to a client
124
+ * @param clientId - Client identifier
125
+ * @param request - Callback request
126
+ * @returns Response from client
127
+ */
128
+ async sendCallback(clientId: string, request: CallbackRequest): Promise<unknown> {
129
+ const client = this.clients.get(clientId);
130
+ if (!client) {
131
+ throw new Error(`Client ${clientId} not registered`);
132
+ }
133
+
134
+ if (!this.hasClientService(clientId, request.type)) {
135
+ throw new Error(`Client ${clientId} does not provide ${request.type} service`);
136
+ }
137
+
138
+ if (!this.callbackHandler) {
139
+ throw new Error('No callback handler registered');
140
+ }
141
+
142
+ return await this.callbackHandler(clientId, request);
143
+ }
144
+
145
+ /**
146
+ * Cleans up stale clients (not seen in specified duration)
147
+ * @param maxAge - Maximum age in milliseconds (default: 5 minutes)
148
+ */
149
+ cleanupStaleClients(maxAge: number = 5 * 60 * 1000): number {
150
+ const now = Date.now();
151
+ let cleaned = 0;
152
+
153
+ for (const [clientId, client] of this.clients.entries()) {
154
+ if (now - client.lastSeen.getTime() > maxAge) {
155
+ this.clients.delete(clientId);
156
+ cleaned++;
157
+ }
158
+ }
159
+
160
+ return cleaned;
161
+ }
162
+
163
+ /**
164
+ * Gets all registered clients
165
+ * @returns Array of client information
166
+ */
167
+ getAllClients(): ClientInfo[] {
168
+ return Array.from(this.clients.values());
169
+ }
170
+
171
+ /**
172
+ * Removes a client
173
+ * @param clientId - Client identifier
174
+ */
175
+ unregisterClient(clientId: string): void {
176
+ this.clients.delete(clientId);
177
+ }
178
+
179
+ /**
180
+ * Stops automatic cleanup and clears resources
181
+ */
182
+ destroy(): void {
183
+ if (this.cleanupInterval) {
184
+ clearInterval(this.cleanupInterval);
185
+ this.cleanupInterval = undefined;
186
+ }
187
+ this.clients.clear();
188
+ }
189
+ }
190
+
191
+ export const clientCallbackManager = new ClientCallbackManager();