@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,286 @@
1
+ import type { RequestContext, ResolvedServerConfig } from '../core/config.js';
2
+ import type { SandboxExecutor } from '../executor/index.js';
3
+ import type { ExecutionStateManager } from '../execution-state/index.js';
4
+ import type { ClientSessionManager } from '../client-sessions.js';
5
+ import type { AuditSink, AuditEvent } from '@mondaydotcomorg/atp-protocol';
6
+ import { ExecutionStatus, ProvenanceMode } from '@mondaydotcomorg/atp-protocol';
7
+ import { nanoid } from 'nanoid';
8
+ import {
9
+ captureProvenanceSnapshot,
10
+ verifyProvenanceHints,
11
+ type ProvenanceMetadata,
12
+ } from '@mondaydotcomorg/atp-provenance';
13
+ import { emitProvenanceTokens } from '../utils/token-emitter.js';
14
+ import { storeHintMap, clearHintMap } from '../utils/provenance-reattachment.js';
15
+ import { log } from '@mondaydotcomorg/atp-runtime';
16
+
17
+ /**
18
+ * Recursively remove __prov_id__ properties from result
19
+ * Handles both enumerable and non-enumerable properties
20
+ */
21
+ function cleanProvenanceIds(value: unknown): unknown {
22
+ if (value === null || value === undefined) {
23
+ return value;
24
+ }
25
+ if (typeof value !== 'object') {
26
+ return value;
27
+ }
28
+ if (Array.isArray(value)) {
29
+ return value.map((item) => cleanProvenanceIds(item));
30
+ }
31
+ const cleaned: Record<string, unknown> = {};
32
+ // Use Object.getOwnPropertyNames to get ALL properties (including non-enumerable)
33
+ const allKeys = Object.getOwnPropertyNames(value);
34
+ for (const key of allKeys) {
35
+ if (key !== '__prov_id__') {
36
+ cleaned[key] = cleanProvenanceIds((value as Record<string, unknown>)[key]);
37
+ }
38
+ }
39
+ return cleaned;
40
+ }
41
+
42
+ export async function handleExecute(
43
+ ctx: RequestContext,
44
+ executor: SandboxExecutor,
45
+ stateManager: ExecutionStateManager,
46
+ config: ResolvedServerConfig,
47
+ auditSink?: AuditSink,
48
+ sessionManager?: ClientSessionManager
49
+ ): Promise<unknown> {
50
+ const request = ctx.body as any;
51
+ const code = request.code || '';
52
+ const requestConfig = request.config || request.options || {};
53
+
54
+ if (sessionManager && ctx.clientId && ctx.clientId !== 'anonymous') {
55
+ const requestToken = ctx.headers['authorization']?.replace('Bearer ', '');
56
+
57
+ if (!requestToken) {
58
+ log.warn('Execute attempt without token', { clientId: ctx.clientId });
59
+ ctx.throw(401, 'Authentication error: Invalid token or client ID mismatch');
60
+ }
61
+
62
+ const isValid = await sessionManager.verifyClient(ctx.clientId, requestToken);
63
+ if (!isValid) {
64
+ log.warn('Execute attempt with invalid token', { clientId: ctx.clientId });
65
+ ctx.throw(403, 'Authentication error: Invalid token or client ID mismatch');
66
+ }
67
+ }
68
+
69
+ const memoryInBytes =
70
+ requestConfig.memoryLimit || requestConfig.memory || config.execution.memory;
71
+
72
+ let clientServices = requestConfig.clientServices;
73
+ if (sessionManager && ctx.clientId && ctx.clientId !== 'anonymous') {
74
+ try {
75
+ const session = await sessionManager.getSession(ctx.clientId);
76
+ const hasTools = session?.tools && session.tools.length > 0;
77
+
78
+ clientServices = {
79
+ ...clientServices,
80
+ hasTools: hasTools || false,
81
+ };
82
+ } catch (error) {}
83
+ }
84
+
85
+ const executionConfig = {
86
+ timeout: requestConfig.timeout || config.execution.timeout,
87
+ maxMemory: memoryInBytes,
88
+ maxLLMCalls: requestConfig.llmCalls || config.execution.llmCalls,
89
+ allowedAPIs: [],
90
+ allowLLMCalls: true,
91
+ clientServices,
92
+ provenanceMode:
93
+ requestConfig.provenanceMode || config.execution.provenanceMode || ProvenanceMode.NONE,
94
+ securityPolicies: config.execution.securityPolicies || [],
95
+ provenanceHints: requestConfig.provenanceHints,
96
+ };
97
+
98
+ // Verify provenance hints if provided
99
+ let hintMap: Map<string, ProvenanceMetadata> | undefined;
100
+ const prelimExecutionId = nanoid();
101
+ if (
102
+ executionConfig.provenanceHints &&
103
+ executionConfig.provenanceHints.length > 0 &&
104
+ executionConfig.provenanceMode !== ProvenanceMode.NONE &&
105
+ ctx.cache
106
+ ) {
107
+ try {
108
+ // Cap hints at 1000
109
+ if (executionConfig.provenanceHints.length > 1000) {
110
+ log.warn('Provenance hints capped', {
111
+ provided: executionConfig.provenanceHints.length,
112
+ capped: 1000,
113
+ });
114
+ ctx.throw(400, 'Too many provenance hints (max 1000)');
115
+ }
116
+
117
+ hintMap = await verifyProvenanceHints(
118
+ executionConfig.provenanceHints,
119
+ ctx.clientId || 'anonymous',
120
+ prelimExecutionId,
121
+ ctx.cache,
122
+ 1000 // maxHints
123
+ );
124
+
125
+ // Store hint map for this execution
126
+ if (hintMap && hintMap.size > 0) {
127
+ storeHintMap(prelimExecutionId, hintMap);
128
+ }
129
+
130
+ log.info('Provenance hints verified', {
131
+ hintsProvided: executionConfig.provenanceHints.length,
132
+ hintsValid: hintMap.size,
133
+ executionId: prelimExecutionId,
134
+ });
135
+ } catch (error) {
136
+ log.error('Failed to verify provenance hints', { error });
137
+ }
138
+ }
139
+
140
+ const startTime = Date.now();
141
+
142
+ if (auditSink) {
143
+ const startEvent: AuditEvent = {
144
+ eventId: nanoid(),
145
+ timestamp: startTime,
146
+ clientId: ctx.clientId || 'anonymous',
147
+ eventType: 'execution',
148
+ action: 'start',
149
+ code,
150
+ status: 'success',
151
+ };
152
+ await auditSink.write(startEvent).catch(() => {});
153
+ }
154
+
155
+ // Pass the prelimExecutionId so executor can access hints
156
+ const result = await executor.execute(code, executionConfig, ctx.clientId, {
157
+ callbackHistory: [],
158
+ newCallbackResult: undefined,
159
+ executionId: prelimExecutionId,
160
+ });
161
+
162
+ // Emit provenance tokens for completed executions
163
+ if (
164
+ result.status === ExecutionStatus.COMPLETED &&
165
+ executionConfig.provenanceMode &&
166
+ executionConfig.provenanceMode !== ProvenanceMode.NONE &&
167
+ ctx.cache &&
168
+ (result as any).provenanceSnapshot
169
+ ) {
170
+ try {
171
+ log.info('Attempting to emit provenance tokens from snapshot', {
172
+ executionId: result.executionId,
173
+ provenanceMode: executionConfig.provenanceMode,
174
+ hasCache: !!ctx.cache,
175
+ hasSnapshot: !!(result as any).provenanceSnapshot,
176
+ resultType: typeof result.result,
177
+ });
178
+ const tokens = await emitProvenanceTokens(
179
+ result.result,
180
+ ctx.clientId || 'anonymous',
181
+ result.executionId,
182
+ executionConfig.provenanceMode,
183
+ ctx.cache,
184
+ log.child({ executionId: result.executionId }),
185
+ 5000, // maxTokens
186
+ 3600, // tokenTTL (1hr)
187
+ (result as any).provenanceSnapshot // Pass snapshot
188
+ );
189
+ log.info('Provenance tokens emitted', {
190
+ executionId: result.executionId,
191
+ tokenCount: tokens.length,
192
+ });
193
+ if (tokens.length > 0) {
194
+ (result as any).provenanceTokens = tokens;
195
+ }
196
+ } catch (error) {
197
+ log.error('Failed to emit provenance tokens', { error, executionId: result.executionId });
198
+ }
199
+ }
200
+
201
+ // Always clean snapshot and provenance IDs before returning
202
+ delete (result as any).provenanceSnapshot;
203
+ if (result.result && typeof result.result === 'object') {
204
+ const hasProv = '__prov_id__' in result.result;
205
+ (result as any).result = cleanProvenanceIds(result.result);
206
+ const stillHasProv =
207
+ result.result && typeof result.result === 'object' && '__prov_id__' in result.result;
208
+ if (hasProv && !stillHasProv) {
209
+ log.debug('Successfully cleaned __prov_id__ from result');
210
+ } else if (hasProv && stillHasProv) {
211
+ log.warn('Failed to clean __prov_id__ from result!');
212
+ }
213
+ }
214
+
215
+ if (auditSink) {
216
+ const endEvent: AuditEvent = {
217
+ eventId: nanoid(),
218
+ timestamp: Date.now(),
219
+ clientId: ctx.clientId || 'anonymous',
220
+ eventType: 'execution',
221
+ action: result.status === ExecutionStatus.PAUSED ? 'pause' : 'complete',
222
+ resourceId: result.executionId,
223
+ status:
224
+ result.status === ExecutionStatus.COMPLETED
225
+ ? 'success'
226
+ : result.status === ExecutionStatus.FAILED
227
+ ? 'failed'
228
+ : 'paused',
229
+ duration: Date.now() - startTime,
230
+ memoryUsed: result.stats?.memoryUsed,
231
+ llmCallsCount: result.stats?.llmCallsCount,
232
+ error: result.error
233
+ ? {
234
+ message: result.error.message,
235
+ code: result.error.code,
236
+ stack: result.error.stack,
237
+ }
238
+ : undefined,
239
+ };
240
+ await auditSink.write(endEvent).catch(() => {});
241
+ }
242
+
243
+ if (
244
+ result.status === 'paused' &&
245
+ (result.needsCallback || result.needsCallbacks) &&
246
+ result.callbackHistory
247
+ ) {
248
+ if (!ctx.clientId) {
249
+ ctx.throw(400, 'Client ID required for paused executions');
250
+ }
251
+
252
+ const provenanceSnap =
253
+ executionConfig.provenanceMode && executionConfig.provenanceMode !== ProvenanceMode.NONE
254
+ ? captureProvenanceSnapshot(result.executionId)
255
+ : undefined;
256
+
257
+ const callbackRequest =
258
+ result.needsCallback || (result.needsCallbacks && result.needsCallbacks[0]);
259
+
260
+ if (!callbackRequest) {
261
+ ctx.throw(500, 'Invalid paused state: no callback request');
262
+ }
263
+
264
+ await stateManager.pause({
265
+ executionId: result.executionId,
266
+ code: (result as any).transformedCode || code,
267
+ config: executionConfig,
268
+ clientId: ctx.clientId,
269
+ callbackRequest,
270
+ pausedAt: Date.now(),
271
+ callbackHistory: result.callbackHistory,
272
+ currentCallbackIndex: result.callbackHistory.length - 1,
273
+ context: {
274
+ codeTransformed: !!(result as any).transformedCode,
275
+ },
276
+ provenanceState: provenanceSnap,
277
+ });
278
+ }
279
+
280
+ // Cleanup hint map
281
+ if (hintMap && hintMap.size > 0) {
282
+ clearHintMap(prelimExecutionId);
283
+ }
284
+
285
+ return result;
286
+ }
@@ -0,0 +1,18 @@
1
+ import type { RequestContext } from '../core/config.js';
2
+ import type { ExplorerService } from '../explorer/index.js';
3
+
4
+ export async function handleExplore(
5
+ ctx: RequestContext,
6
+ explorerService: ExplorerService
7
+ ): Promise<unknown> {
8
+ const body = ctx.body as { path?: string };
9
+ const path = body.path || '/';
10
+
11
+ const result = explorerService.explore(path);
12
+
13
+ if (!result) {
14
+ ctx.throw(404, `Path not found: ${path}`);
15
+ }
16
+
17
+ return result;
18
+ }
@@ -0,0 +1,53 @@
1
+ import type { RequestContext } from '../core/config.js';
2
+ import type { ClientSessionManager } from '../client-sessions.js';
3
+ import type { AuditSink, AuditEvent } from '@mondaydotcomorg/atp-protocol';
4
+ import { nanoid } from 'nanoid';
5
+ import { log } from '@mondaydotcomorg/atp-runtime';
6
+
7
+ export async function handleInit(
8
+ ctx: RequestContext,
9
+ sessionManager: ClientSessionManager,
10
+ auditSink?: AuditSink
11
+ ): Promise<unknown> {
12
+ const request = ctx.body as any;
13
+
14
+ if (request.tools && Array.isArray(request.tools)) {
15
+ log.info('Client registering tools', {
16
+ toolCount: request.tools.length,
17
+ toolNames: request.tools.map((t: any) => t.name),
18
+ });
19
+
20
+ for (const tool of request.tools) {
21
+ if (!tool.name || typeof tool.name !== 'string') {
22
+ ctx.throw(400, 'Invalid tool definition: name is required');
23
+ }
24
+ if (!tool.description || typeof tool.description !== 'string') {
25
+ ctx.throw(400, `Invalid tool definition for '${tool.name}': description is required`);
26
+ }
27
+ if (!tool.inputSchema || typeof tool.inputSchema !== 'object') {
28
+ ctx.throw(400, `Invalid tool definition for '${tool.name}': inputSchema is required`);
29
+ }
30
+ }
31
+ }
32
+
33
+ const result = await sessionManager.initClient(request || {});
34
+
35
+ if (auditSink) {
36
+ const event: AuditEvent = {
37
+ eventId: nanoid(),
38
+ timestamp: Date.now(),
39
+ clientId: (result as any).clientId,
40
+ eventType: 'client_init',
41
+ action: 'init',
42
+ status: 'success',
43
+ metadata: {
44
+ clientInfo: request.clientInfo,
45
+ toolsRegistered: request.tools ? request.tools.length : 0,
46
+ toolNames: request.tools ? request.tools.map((t: any) => t.name) : [],
47
+ },
48
+ };
49
+ await auditSink.write(event).catch(() => {});
50
+ }
51
+
52
+ return result;
53
+ }
@@ -0,0 +1,316 @@
1
+ import type { RequestContext, ResolvedServerConfig } from '../core/config.js';
2
+ import type { SandboxExecutor } from '../executor/index.js';
3
+ import type { ExecutionStateManager } from '../execution-state/index.js';
4
+ import type { ClientSessionManager } from '../client-sessions.js';
5
+ import { log } from '@mondaydotcomorg/atp-runtime';
6
+ import { ExecutionStatus, ProvenanceMode } from '@mondaydotcomorg/atp-protocol';
7
+ import {
8
+ restoreProvenanceSnapshot,
9
+ captureProvenanceSnapshot,
10
+ createProvenanceProxy,
11
+ markPrimitiveTainted,
12
+ ProvenanceSource,
13
+ type ProvenanceSnapshot,
14
+ type ProvenanceState,
15
+ type SourceMetadata,
16
+ } from '@mondaydotcomorg/atp-provenance';
17
+ import { nanoid } from 'nanoid';
18
+
19
+ /**
20
+ * Tag a callback result with provenance metadata
21
+ */
22
+ function tagCallbackResult(
23
+ callbackRecord: { type: string; operation: string; payload: any },
24
+ result: unknown,
25
+ provenanceMode?: string
26
+ ): unknown {
27
+ // Don't tag if provenance is disabled or not specified
28
+ // ProvenanceMode.NONE is 'none', so just check for falsy or 'none'
29
+ if (!provenanceMode || provenanceMode === ProvenanceMode.NONE) {
30
+ return result;
31
+ }
32
+
33
+ if (result === null || result === undefined) {
34
+ return result;
35
+ }
36
+
37
+ const tagValue = (value: unknown, source: SourceMetadata): unknown => {
38
+ if (value === null || value === undefined) {
39
+ return value;
40
+ }
41
+
42
+ // Primitive: taint it
43
+ if (typeof value === 'string' || typeof value === 'number') {
44
+ const metadata = {
45
+ id: nanoid(),
46
+ source,
47
+ readers: { type: 'public' as const },
48
+ dependencies: [],
49
+ context: {},
50
+ };
51
+ markPrimitiveTainted(value, metadata);
52
+ return value;
53
+ }
54
+
55
+ // Objects/arrays: create provenance proxy
56
+ if (typeof value === 'object') {
57
+ return createProvenanceProxy(value, source, { type: 'public' });
58
+ }
59
+
60
+ return value;
61
+ };
62
+
63
+ // Determine source based on callback type
64
+ if (callbackRecord.type === 'llm') {
65
+ const source: SourceMetadata = {
66
+ type: ProvenanceSource.LLM,
67
+ operation: (callbackRecord.operation as 'call' | 'extract' | 'classify') || 'call',
68
+ timestamp: Date.now(),
69
+ };
70
+ return Array.isArray(result)
71
+ ? result.map((r) => tagValue(r, source))
72
+ : tagValue(result, source);
73
+ }
74
+
75
+ if (callbackRecord.type === 'tool') {
76
+ const source: SourceMetadata = {
77
+ type: ProvenanceSource.TOOL,
78
+ toolName: (callbackRecord.payload as any)?.toolName || 'clientTool',
79
+ apiGroup: (callbackRecord.payload as any)?.namespace || 'client',
80
+ timestamp: Date.now(),
81
+ };
82
+ return Array.isArray(result)
83
+ ? result.map((r) => tagValue(r, source))
84
+ : tagValue(result, source);
85
+ }
86
+
87
+ // No tagging for other callback types
88
+ return result;
89
+ }
90
+
91
+ export async function handleResume(
92
+ ctx: RequestContext,
93
+ executionId: string,
94
+ executor: SandboxExecutor,
95
+ stateManager: ExecutionStateManager,
96
+ serverConfig: ResolvedServerConfig,
97
+ sessionManager?: ClientSessionManager
98
+ ): Promise<unknown> {
99
+ const requestClientId = ctx.headers['x-client-id'] || ctx.clientId;
100
+ const requestToken = ctx.headers['authorization']?.replace('Bearer ', '');
101
+
102
+ if (!requestClientId || !requestToken) {
103
+ log.warn('Resume attempt without authentication', { executionId });
104
+ ctx.throw(401, 'Authentication required');
105
+ }
106
+
107
+ ctx.clientId = requestClientId;
108
+
109
+ if (sessionManager) {
110
+ const isValid = await sessionManager.verifyClient(requestClientId, requestToken);
111
+ if (!isValid) {
112
+ log.warn('Resume attempt with invalid token', { executionId, clientId: requestClientId });
113
+ ctx.throw(403, 'Invalid client credentials');
114
+ }
115
+ }
116
+
117
+ const pausedState = await stateManager.get(executionId);
118
+
119
+ if (!pausedState) {
120
+ ctx.throw(404, 'Not found');
121
+ }
122
+
123
+ if (pausedState.clientId !== requestClientId) {
124
+ log.warn('Resume attempt by unauthorized client', {
125
+ executionId,
126
+ requestClientId,
127
+ ownerClientId: pausedState.clientId,
128
+ });
129
+ ctx.throw(403, 'Unauthorized: execution belongs to different client');
130
+ }
131
+
132
+ log.info('Resume authorized', { executionId, clientId: requestClientId });
133
+
134
+ if (
135
+ pausedState.provenanceState &&
136
+ pausedState.config.provenanceMode &&
137
+ pausedState.config.provenanceMode !== ProvenanceMode.NONE
138
+ ) {
139
+ // Check if it's a ProvenanceSnapshot (with primitives) or old ProvenanceState
140
+ const state = pausedState.provenanceState;
141
+ if ('primitives' in state) {
142
+ // New snapshot format
143
+ restoreProvenanceSnapshot(executionId, state as ProvenanceSnapshot);
144
+ log.info('Provenance snapshot restored', {
145
+ executionId,
146
+ registryEntries: state.registry.length,
147
+ primitiveEntries: state.primitives.length,
148
+ });
149
+ } else {
150
+ // Old state format (backward compat)
151
+ const provenanceMap = new Map<string, any>(state.registry);
152
+ restoreProvenanceSnapshot(executionId, {
153
+ registry: state.registry,
154
+ primitives: [],
155
+ });
156
+ log.info('Provenance state restored (legacy format)', {
157
+ executionId,
158
+ entries: provenanceMap.size,
159
+ });
160
+ }
161
+ }
162
+
163
+ const request = ctx.body as any;
164
+
165
+ let updatedHistory: any[];
166
+ let callbackResult: unknown;
167
+
168
+ const lastRecord = pausedState.callbackHistory[pausedState.currentCallbackIndex];
169
+
170
+ if (!lastRecord) {
171
+ log.error('No callback record found at current index', {
172
+ executionId,
173
+ currentIndex: pausedState.currentCallbackIndex,
174
+ });
175
+ ctx.throw(500, 'Invalid paused state: no callback record');
176
+ }
177
+
178
+ if (request.results) {
179
+ const batchResults = request.results as Array<{ id: string; result: unknown }>;
180
+ log.info('Processing batch callback results', {
181
+ executionId,
182
+ batchCount: batchResults.length,
183
+ });
184
+
185
+ for (const br of batchResults) {
186
+ if (br.result && typeof br.result === 'object' && '__error' in br.result) {
187
+ const errorObj = br.result as { __error: boolean; message: string };
188
+ if (errorObj.message && errorObj.message.includes('service not provided')) {
189
+ log.error('Service provider error in batch', { executionId, error: errorObj.message });
190
+ await stateManager.delete(executionId);
191
+ return {
192
+ executionId,
193
+ status: ExecutionStatus.FAILED,
194
+ error: {
195
+ message: errorObj.message || 'Service not available',
196
+ code: 'SERVICE_NOT_PROVIDED',
197
+ },
198
+ stats: {
199
+ duration: 0,
200
+ memoryUsed: 0,
201
+ llmCallsCount: 0,
202
+ approvalCallsCount: 0,
203
+ },
204
+ };
205
+ }
206
+ }
207
+ }
208
+
209
+ // Tag batch results
210
+ const taggedBatchResults = batchResults.map((br) => ({
211
+ ...br,
212
+ result: tagCallbackResult(lastRecord, br.result, pausedState.config.provenanceMode),
213
+ }));
214
+ callbackResult = taggedBatchResults.map((br) => br.result);
215
+
216
+ updatedHistory = pausedState.callbackHistory.map((record, index) => {
217
+ if (index === pausedState.currentCallbackIndex) {
218
+ return { ...record, result: callbackResult };
219
+ }
220
+ return record;
221
+ });
222
+ } else {
223
+ // Tag single result
224
+ const rawResult = request.result;
225
+
226
+ // Check for service provider errors (not tool errors)
227
+ if (rawResult && typeof rawResult === 'object' && '__error' in rawResult) {
228
+ const errorObj = rawResult as { __error: boolean; message: string };
229
+ // Only fail execution for service provider errors (service not available)
230
+ if (errorObj.message && errorObj.message.includes('service not provided')) {
231
+ log.error('Service provider error', { executionId, error: errorObj.message });
232
+ await stateManager.delete(executionId);
233
+ return {
234
+ executionId,
235
+ status: ExecutionStatus.FAILED,
236
+ error: {
237
+ message: errorObj.message || 'Service not available',
238
+ code: 'SERVICE_NOT_PROVIDED',
239
+ },
240
+ stats: {
241
+ duration: 0,
242
+ memoryUsed: 0,
243
+ llmCallsCount: 0,
244
+ approvalCallsCount: 0,
245
+ },
246
+ };
247
+ }
248
+ }
249
+
250
+ callbackResult = tagCallbackResult(lastRecord, rawResult, pausedState.config.provenanceMode);
251
+
252
+ updatedHistory = pausedState.callbackHistory.map((record, index) => {
253
+ if (index === pausedState.currentCallbackIndex) {
254
+ return { ...record, result: callbackResult };
255
+ }
256
+ return record;
257
+ });
258
+ }
259
+
260
+ const restoredConfig = {
261
+ ...pausedState.config,
262
+ securityPolicies: serverConfig.execution.securityPolicies || [],
263
+ };
264
+
265
+ const result = await executor.execute(pausedState.code, restoredConfig, pausedState.clientId, {
266
+ callbackHistory: updatedHistory,
267
+ newCallbackResult: callbackResult,
268
+ executionId,
269
+ });
270
+
271
+ if (result.status === ExecutionStatus.PAUSED && result.needsCallbacks && result.callbackHistory) {
272
+ const provenanceState =
273
+ pausedState.config.provenanceMode && pausedState.config.provenanceMode !== ProvenanceMode.NONE
274
+ ? captureProvenanceSnapshot(result.executionId)
275
+ : undefined;
276
+
277
+ await stateManager.pause({
278
+ executionId: result.executionId,
279
+ code: pausedState.code,
280
+ config: pausedState.config,
281
+ clientId: pausedState.clientId,
282
+ callbackRequest: result.needsCallbacks[0]!,
283
+ pausedAt: Date.now(),
284
+ callbackHistory: result.callbackHistory,
285
+ currentCallbackIndex: result.callbackHistory.length - 1,
286
+ context: {},
287
+ provenanceState,
288
+ });
289
+ } else if (
290
+ result.status === ExecutionStatus.PAUSED &&
291
+ result.needsCallback &&
292
+ result.callbackHistory
293
+ ) {
294
+ const provenanceState =
295
+ pausedState.config.provenanceMode && pausedState.config.provenanceMode !== ProvenanceMode.NONE
296
+ ? captureProvenanceSnapshot(result.executionId)
297
+ : undefined;
298
+
299
+ await stateManager.pause({
300
+ executionId: result.executionId,
301
+ code: pausedState.code,
302
+ config: pausedState.config,
303
+ clientId: pausedState.clientId,
304
+ callbackRequest: result.needsCallback,
305
+ pausedAt: Date.now(),
306
+ callbackHistory: result.callbackHistory,
307
+ currentCallbackIndex: result.callbackHistory.length - 1,
308
+ context: {},
309
+ provenanceState,
310
+ });
311
+ } else {
312
+ await stateManager.delete(executionId);
313
+ }
314
+
315
+ return result;
316
+ }
@@ -0,0 +1,32 @@
1
+ import type { RequestContext, ResolvedServerConfig } from '../core/config.js';
2
+ import type { SearchEngine } from '../search/index.js';
3
+
4
+ export async function handleSearch(
5
+ ctx: RequestContext,
6
+ searchEngine: SearchEngine,
7
+ config: ResolvedServerConfig
8
+ ): Promise<unknown> {
9
+ const searchOptions = ctx.body as any;
10
+ const results = await searchEngine.search(
11
+ searchOptions,
12
+ ctx.userId,
13
+ ctx.auth,
14
+ config.discovery.scopeFiltering
15
+ );
16
+ return { results };
17
+ }
18
+
19
+ export async function handleSearchQuery(
20
+ ctx: RequestContext,
21
+ searchEngine: SearchEngine,
22
+ config: ResolvedServerConfig
23
+ ): Promise<unknown> {
24
+ const query = ctx.query.query || ctx.query.keyword || '';
25
+ const results = await searchEngine.search(
26
+ { query },
27
+ ctx.userId,
28
+ ctx.auth,
29
+ config.discovery.scopeFiltering
30
+ );
31
+ return { results };
32
+ }