@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,234 @@
1
+ /**
2
+ * Client Session Management
3
+ */
4
+ import { randomBytes } from 'node:crypto';
5
+ import { nanoid } from 'nanoid';
6
+ import jwt from 'jsonwebtoken';
7
+ import type { CacheProvider, ClientToolDefinition } from '@mondaydotcomorg/atp-protocol';
8
+
9
+ export interface ClientSession {
10
+ clientId: string;
11
+ createdAt: number;
12
+ expiresAt: number;
13
+ clientInfo?: {
14
+ name?: string;
15
+ version?: string;
16
+ [key: string]: unknown;
17
+ };
18
+ guidance?: string;
19
+ /** Client-provided tool definitions */
20
+ tools?: ClientToolDefinition[];
21
+ }
22
+
23
+ export interface ClientInitRequest {
24
+ clientInfo?: {
25
+ name?: string;
26
+ version?: string;
27
+ [key: string]: unknown;
28
+ };
29
+ guidance?: string;
30
+ /** Client tool definitions to register */
31
+ tools?: ClientToolDefinition[];
32
+ }
33
+
34
+ export interface ClientInitResponse {
35
+ clientId: string;
36
+ token: string;
37
+ expiresAt: number;
38
+ tokenRotateAt?: number;
39
+ }
40
+
41
+ /**
42
+ * Client session manager with JWT-based authentication
43
+ */
44
+ export class ClientSessionManager {
45
+ private cache?: CacheProvider;
46
+ private inMemorySessions: Map<string, ClientSession> = new Map();
47
+ private cleanupTimers: Map<string, NodeJS.Timeout> = new Map();
48
+ private tokenTTL: number;
49
+ private jwtSecret: string;
50
+
51
+ constructor(options: { cache?: CacheProvider; tokenTTL: number; tokenRotation: number }) {
52
+ this.cache = options.cache;
53
+ this.tokenTTL = options.tokenTTL;
54
+
55
+ const secret = process.env.ATP_JWT_SECRET;
56
+ if (!secret) {
57
+ throw new Error(
58
+ 'ATP_JWT_SECRET environment variable is required. Generate one with: openssl rand -base64 32'
59
+ );
60
+ }
61
+
62
+ this.jwtSecret = secret;
63
+ }
64
+
65
+ /**
66
+ * Initialize a new client session
67
+ */
68
+ async initClient(request: ClientInitRequest): Promise<ClientInitResponse> {
69
+ const clientId = this.generateClientId();
70
+
71
+ const now = Date.now();
72
+ const expiresAt = now + this.tokenTTL;
73
+ const tokenRotateAt = now + this.tokenTTL / 2;
74
+
75
+ const token = this.generateToken(clientId);
76
+
77
+ const session: ClientSession = {
78
+ clientId,
79
+ createdAt: now,
80
+ expiresAt,
81
+ clientInfo: request.clientInfo,
82
+ guidance: request.guidance,
83
+ tools: request.tools || [],
84
+ };
85
+
86
+ if (this.cache) {
87
+ const ttlSeconds = Math.floor(this.tokenTTL / 1000);
88
+ await this.cache.set(`session:${clientId}`, session, ttlSeconds);
89
+ } else {
90
+ this.inMemorySessions.set(clientId, session);
91
+ this.scheduleCleanup(clientId, this.tokenTTL);
92
+ }
93
+
94
+ return {
95
+ clientId,
96
+ token,
97
+ expiresAt,
98
+ tokenRotateAt,
99
+ };
100
+ }
101
+
102
+ /**
103
+ * Verify client token (JWT-based, stateless)
104
+ */
105
+ async verifyClient(clientId: string, token: string): Promise<boolean> {
106
+ try {
107
+ // Prevent algorithm confusion attacks - only allow HS256
108
+ const decoded = jwt.verify(token, this.jwtSecret, {
109
+ algorithms: ['HS256'],
110
+ }) as { clientId: string; type: string };
111
+
112
+ if (decoded.clientId !== clientId || decoded.type !== 'client') {
113
+ return false;
114
+ }
115
+
116
+ const session = await this.getSession(clientId);
117
+ return session !== null;
118
+ } catch (error) {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Get client session
125
+ */
126
+ async getSession(clientId: string): Promise<ClientSession | null> {
127
+ let session: ClientSession | null = null;
128
+
129
+ if (this.cache) {
130
+ session = await this.cache.get<ClientSession>(`session:${clientId}`);
131
+ } else {
132
+ session = this.inMemorySessions.get(clientId) || null;
133
+ }
134
+
135
+ if (!session) {
136
+ return null;
137
+ }
138
+
139
+ if (Date.now() > session.expiresAt) {
140
+ if (this.cache) {
141
+ await this.cache.delete(`session:${clientId}`);
142
+ } else {
143
+ this.inMemorySessions.delete(clientId);
144
+ }
145
+ return null;
146
+ }
147
+
148
+ return session;
149
+ }
150
+
151
+ /**
152
+ * Revoke client session
153
+ */
154
+ async revokeClient(clientId: string): Promise<void> {
155
+ if (this.cache) {
156
+ await this.cache.delete(`session:${clientId}`);
157
+ } else {
158
+ this.inMemorySessions.delete(clientId);
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Generate cryptographically secure client ID
164
+ */
165
+ private generateClientId(): string {
166
+ const random = randomBytes(16).toString('hex');
167
+ return `cli_${random}`;
168
+ }
169
+
170
+ /**
171
+ * Generate JWT token for client
172
+ */
173
+ generateToken(clientId: string): string {
174
+ return jwt.sign(
175
+ {
176
+ clientId,
177
+ type: 'client',
178
+ jti: nanoid(),
179
+ },
180
+ this.jwtSecret,
181
+ {
182
+ expiresIn: 3600,
183
+ }
184
+ );
185
+ }
186
+
187
+ /**
188
+ * Schedule cleanup of expired in-memory session
189
+ */
190
+ private scheduleCleanup(clientId: string, ttl: number): void {
191
+ const existingTimer = this.cleanupTimers.get(clientId);
192
+ if (existingTimer) {
193
+ clearTimeout(existingTimer);
194
+ }
195
+
196
+ const timer = setTimeout(() => {
197
+ this.inMemorySessions.delete(clientId);
198
+ this.cleanupTimers.delete(clientId);
199
+ }, ttl);
200
+
201
+ this.cleanupTimers.set(clientId, timer);
202
+ }
203
+
204
+ /**
205
+ * Manually cleanup a session (useful for tests and explicit cleanup)
206
+ */
207
+ async cleanup(clientId: string): Promise<void> {
208
+ const timer = this.cleanupTimers.get(clientId);
209
+ if (timer) {
210
+ clearTimeout(timer);
211
+ this.cleanupTimers.delete(clientId);
212
+ }
213
+
214
+ if (this.cache) {
215
+ await this.cache.delete(`session:${clientId}`);
216
+ } else {
217
+ this.inMemorySessions.delete(clientId);
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Cleanup all sessions (useful for shutdown)
223
+ */
224
+ async cleanupAll(): Promise<void> {
225
+ for (const timer of this.cleanupTimers.values()) {
226
+ clearTimeout(timer);
227
+ }
228
+ this.cleanupTimers.clear();
229
+
230
+ if (!this.cache) {
231
+ this.inMemorySessions.clear();
232
+ }
233
+ }
234
+ }
@@ -0,0 +1,19 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { APIAggregator } from '../aggregator/index.js';
3
+ import { sendJson } from '../utils/response.js';
4
+
5
+ export async function handleDefinitions(
6
+ req: IncomingMessage,
7
+ res: ServerResponse,
8
+ aggregator: APIAggregator,
9
+ url: URL
10
+ ): Promise<void> {
11
+ const apiGroups = url.searchParams.get('apiGroups')?.split(',');
12
+ const typescript = await aggregator.generateTypeScript(apiGroups);
13
+
14
+ sendJson(res, {
15
+ typescript,
16
+ apiGroups: aggregator.getApiGroups(),
17
+ version: '1.0.0',
18
+ });
19
+ }
@@ -0,0 +1,166 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { ExecutionConfig } from '@mondaydotcomorg/atp-protocol';
3
+ import { ExecutionErrorCode, sanitizeInput, MAX_CODE_SIZE } from '@mondaydotcomorg/atp-protocol';
4
+ import type { CodeValidator } from '../validator/index.js';
5
+ import type { SandboxExecutor } from '../executor/index.js';
6
+ import type { ExecutionStateManager } from '../execution-state/index.js';
7
+ import type { AuditConfig } from '../middleware/audit.js';
8
+ import { auditExecution } from '../middleware/audit.js';
9
+ import { clientCallbackManager } from '../callback/index.js';
10
+ import { nanoid } from 'nanoid';
11
+ import type { log } from '@mondaydotcomorg/atp-runtime';
12
+
13
+ interface ExecuteContext {
14
+ validator: CodeValidator;
15
+ executor: SandboxExecutor;
16
+ stateManager: ExecutionStateManager;
17
+ auditConfig?: AuditConfig;
18
+ defaultTimeout: number;
19
+ defaultMemoryLimit: number;
20
+ defaultLLMCallLimit: number;
21
+ }
22
+
23
+ export async function handleExecute(
24
+ req: IncomingMessage,
25
+ res: ServerResponse,
26
+ context: ExecuteContext,
27
+ body: string,
28
+ clientId: string | undefined,
29
+ logger: ReturnType<typeof log.child>
30
+ ): Promise<void> {
31
+ let request: { code: string; config?: Partial<ExecutionConfig> };
32
+
33
+ try {
34
+ request = JSON.parse(body);
35
+ } catch (error) {
36
+ logger.warn('Invalid request body', { error });
37
+ res.writeHead(400, { 'Content-Type': 'application/json' });
38
+ res.end(
39
+ JSON.stringify({
40
+ error: 'Invalid request body',
41
+ message: error instanceof Error ? error.message : 'Failed to parse request',
42
+ })
43
+ );
44
+ return;
45
+ }
46
+
47
+ request.code = sanitizeInput(request.code, MAX_CODE_SIZE);
48
+
49
+ if (clientId && request.config?.clientServices) {
50
+ clientCallbackManager.registerClient(clientId, request.config.clientServices);
51
+ logger.info('Client services registered', {
52
+ clientId,
53
+ services: request.config.clientServices,
54
+ });
55
+ }
56
+
57
+ if (clientId) {
58
+ clientCallbackManager.updateClientActivity(clientId);
59
+ }
60
+
61
+ const executionConfig: ExecutionConfig = {
62
+ timeout: request.config?.timeout ?? context.defaultTimeout,
63
+ maxMemory: request.config?.maxMemory ?? context.defaultMemoryLimit,
64
+ maxLLMCalls: request.config?.maxLLMCalls ?? context.defaultLLMCallLimit,
65
+ allowedAPIs: request.config?.allowedAPIs ?? [],
66
+ allowLLMCalls: request.config?.allowLLMCalls ?? true,
67
+ clientServices: request.config?.clientServices,
68
+ provenanceMode: request.config?.provenanceMode,
69
+ securityPolicies: request.config?.securityPolicies,
70
+ provenanceHints: request.config?.provenanceHints,
71
+ };
72
+
73
+ logger.info('Validating code for execution', {
74
+ codeLength: request.code.length,
75
+ timeout: executionConfig.timeout,
76
+ clientServices: executionConfig.clientServices,
77
+ });
78
+
79
+ const validationResult = await context.validator.validate(request.code, executionConfig);
80
+
81
+ if (!validationResult.valid) {
82
+ logger.warn('Code validation failed', {
83
+ errors: validationResult.errors?.length,
84
+ securityIssues: validationResult.securityIssues?.length,
85
+ });
86
+
87
+ const hasSecurityIssues =
88
+ validationResult.securityIssues && validationResult.securityIssues.length > 0;
89
+
90
+ res.writeHead(200, { 'Content-Type': 'application/json' });
91
+ res.end(
92
+ JSON.stringify({
93
+ executionId: nanoid(),
94
+ status: hasSecurityIssues ? 'security_violation' : 'validation_failed',
95
+ error: {
96
+ message: 'Code validation failed',
97
+ code: hasSecurityIssues
98
+ ? ExecutionErrorCode.SECURITY_VIOLATION
99
+ : ExecutionErrorCode.VALIDATION_FAILED,
100
+ context: {
101
+ errors: validationResult.errors,
102
+ securityIssues: validationResult.securityIssues,
103
+ },
104
+ retryable: false,
105
+ suggestion: hasSecurityIssues
106
+ ? 'Remove forbidden operations and use only allowed APIs'
107
+ : 'Fix syntax errors and validation issues in your code',
108
+ },
109
+ stats: {
110
+ duration: 0,
111
+ memoryUsed: 0,
112
+ llmCallsCount: 0,
113
+ approvalCallsCount: 0,
114
+ httpCallsCount: 0,
115
+ },
116
+ })
117
+ );
118
+ return;
119
+ }
120
+
121
+ logger.info('Executing code in sandbox');
122
+ const result = await context.executor.execute(request.code, executionConfig, clientId);
123
+
124
+ logger.info('Code execution completed', {
125
+ executionId: result.executionId,
126
+ status: result.status,
127
+ duration: result.stats.duration,
128
+ memoryUsed: result.stats.memoryUsed,
129
+ llmCalls: result.stats.llmCallsCount,
130
+ approvalCalls: result.stats.approvalCallsCount,
131
+ });
132
+
133
+ if (result.status === 'paused' && result.needsCallback && clientId && result.callbackHistory) {
134
+ await context.stateManager.pause({
135
+ executionId: result.executionId,
136
+ code: request.code,
137
+ config: executionConfig,
138
+ clientId,
139
+ callbackRequest: result.needsCallback,
140
+ pausedAt: Date.now(),
141
+ callbackHistory: result.callbackHistory,
142
+ currentCallbackIndex: result.callbackHistory.length - 1,
143
+ context: {},
144
+ });
145
+
146
+ logger.info('Execution state saved', {
147
+ executionId: result.executionId,
148
+ callbackType: result.needsCallback.type,
149
+ storage: context.stateManager.getStorageType(),
150
+ historyLength: result.callbackHistory.length,
151
+ });
152
+ }
153
+
154
+ if (context.auditConfig?.enabled) {
155
+ await auditExecution({
156
+ executionId: result.executionId,
157
+ apiKey: (req as any).apiKey,
158
+ ip: req.socket.remoteAddress,
159
+ code: request.code,
160
+ result,
161
+ });
162
+ }
163
+
164
+ res.writeHead(200, { 'Content-Type': 'application/json' });
165
+ res.end(JSON.stringify(result));
166
+ }
@@ -0,0 +1,14 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { sendJson } from '../utils/response.js';
3
+
4
+ export async function handleInfo(req: IncomingMessage, res: ServerResponse): Promise<void> {
5
+ sendJson(res, {
6
+ version: '1.0.0',
7
+ capabilities: {
8
+ execution: true,
9
+ search: true,
10
+ streaming: true,
11
+ llmCalls: true,
12
+ },
13
+ });
14
+ }
@@ -0,0 +1,92 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { SandboxExecutor } from '../executor/index.js';
3
+ import type { ExecutionStateManager } from '../execution-state/index.js';
4
+ import type { log } from '@mondaydotcomorg/atp-runtime';
5
+
6
+ interface ResumeContext {
7
+ executor: SandboxExecutor;
8
+ stateManager: ExecutionStateManager;
9
+ }
10
+
11
+ export async function handleResume(
12
+ req: IncomingMessage,
13
+ res: ServerResponse,
14
+ context: ResumeContext,
15
+ executionId: string,
16
+ body: string,
17
+ logger: ReturnType<typeof log.child>
18
+ ): Promise<void> {
19
+ logger.info('Resuming paused execution', { executionId });
20
+
21
+ const pausedState = await context.stateManager.get(executionId);
22
+
23
+ if (!pausedState) {
24
+ logger.warn('Execution not found or expired', { executionId });
25
+ res.writeHead(404, { 'Content-Type': 'application/json' });
26
+ res.end(JSON.stringify({ error: 'Execution not found or expired' }));
27
+ return;
28
+ }
29
+
30
+ const { result: callbackResult } = JSON.parse(body) as { result: unknown };
31
+
32
+ logger.info('Client callback result received', {
33
+ executionId,
34
+ callbackType: pausedState.callbackRequest.type,
35
+ operation: pausedState.callbackRequest.operation,
36
+ });
37
+
38
+ const updatedHistory = pausedState.callbackHistory.map((record, index) => {
39
+ if (index === pausedState.currentCallbackIndex) {
40
+ return { ...record, result: callbackResult };
41
+ }
42
+ return record;
43
+ });
44
+
45
+ logger.info('Re-executing with replay', {
46
+ executionId,
47
+ historyLength: updatedHistory.length,
48
+ });
49
+
50
+ const result = await context.executor.execute(
51
+ pausedState.code,
52
+ pausedState.config,
53
+ pausedState.clientId,
54
+ {
55
+ callbackHistory: updatedHistory,
56
+ newCallbackResult: callbackResult,
57
+ executionId,
58
+ }
59
+ );
60
+
61
+ logger.info('Resumed execution completed', {
62
+ executionId: result.executionId,
63
+ status: result.status,
64
+ duration: result.stats.duration,
65
+ });
66
+
67
+ if (result.status === 'paused' && result.needsCallback && result.callbackHistory) {
68
+ await context.stateManager.pause({
69
+ executionId: result.executionId,
70
+ code: pausedState.code,
71
+ config: pausedState.config,
72
+ clientId: pausedState.clientId,
73
+ callbackRequest: result.needsCallback,
74
+ pausedAt: Date.now(),
75
+ callbackHistory: result.callbackHistory,
76
+ currentCallbackIndex: result.callbackHistory.length - 1,
77
+ context: {},
78
+ });
79
+
80
+ logger.info('Execution paused again (multi-callback)', {
81
+ executionId: result.executionId,
82
+ callbackType: result.needsCallback.type,
83
+ totalCallbacks: result.callbackHistory.length,
84
+ });
85
+ } else {
86
+ await context.stateManager.delete(executionId);
87
+ logger.debug('Execution state cleaned up', { executionId });
88
+ }
89
+
90
+ res.writeHead(200, { 'Content-Type': 'application/json' });
91
+ res.end(JSON.stringify(result));
92
+ }
@@ -0,0 +1,16 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { SearchOptions } from '@mondaydotcomorg/atp-protocol';
3
+ import type { SearchEngine } from '../search/index.js';
4
+ import { sendJson } from '../utils/response.js';
5
+
6
+ export async function handleSearch(
7
+ req: IncomingMessage,
8
+ res: ServerResponse,
9
+ searchEngine: SearchEngine,
10
+ body: string
11
+ ): Promise<void> {
12
+ const searchOptions = JSON.parse(body) as SearchOptions;
13
+ const results = await searchEngine.search(searchOptions);
14
+
15
+ sendJson(res, { results });
16
+ }