@nodetool-ai/websocket 0.8.1 → 0.8.3

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 (471) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/chat-turn-registry.d.ts +2 -1
  3. package/dist/chat-turn-registry.d.ts.map +1 -1
  4. package/dist/chat-turn-registry.js +8 -1
  5. package/dist/chat-turn-registry.js.map +1 -1
  6. package/dist/collection-api.d.ts.map +1 -1
  7. package/dist/collection-api.js +41 -6
  8. package/dist/collection-api.js.map +1 -1
  9. package/dist/custom-providers.d.ts.map +1 -1
  10. package/dist/custom-providers.js +6 -1
  11. package/dist/custom-providers.js.map +1 -1
  12. package/dist/error-traces.d.ts +56 -0
  13. package/dist/error-traces.d.ts.map +1 -0
  14. package/dist/error-traces.js +179 -0
  15. package/dist/error-traces.js.map +1 -0
  16. package/dist/example-workflows.d.ts.map +1 -1
  17. package/dist/example-workflows.js +6 -0
  18. package/dist/example-workflows.js.map +1 -1
  19. package/dist/fake-runtime.d.ts +41 -6
  20. package/dist/fake-runtime.d.ts.map +1 -1
  21. package/dist/fake-runtime.js +247 -16
  22. package/dist/fake-runtime.js.map +1 -1
  23. package/dist/file-api.d.ts.map +1 -1
  24. package/dist/file-api.js +6 -8
  25. package/dist/file-api.js.map +1 -1
  26. package/dist/generation-recovery.d.ts.map +1 -1
  27. package/dist/generation-recovery.js +32 -7
  28. package/dist/generation-recovery.js.map +1 -1
  29. package/dist/headless-job-runner.d.ts.map +1 -1
  30. package/dist/headless-job-runner.js +5 -1
  31. package/dist/headless-job-runner.js.map +1 -1
  32. package/dist/http-api.d.ts +3 -1
  33. package/dist/http-api.d.ts.map +1 -1
  34. package/dist/http-api.js +66 -9
  35. package/dist/http-api.js.map +1 -1
  36. package/dist/http-body-schemas.d.ts +2 -0
  37. package/dist/http-body-schemas.d.ts.map +1 -1
  38. package/dist/http-body-schemas.js +8 -1
  39. package/dist/http-body-schemas.js.map +1 -1
  40. package/dist/index.d.ts +0 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +0 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/interrupted-jobs.d.ts +14 -0
  45. package/dist/interrupted-jobs.d.ts.map +1 -0
  46. package/dist/interrupted-jobs.js +28 -0
  47. package/dist/interrupted-jobs.js.map +1 -0
  48. package/dist/lib/admin.d.ts +7 -0
  49. package/dist/lib/admin.d.ts.map +1 -0
  50. package/dist/lib/admin.js +20 -0
  51. package/dist/lib/admin.js.map +1 -0
  52. package/dist/lib/app-debug-service.js +1 -1
  53. package/dist/lib/app-debug-service.js.map +1 -1
  54. package/dist/lib/app-instances-service.d.ts +1319 -0
  55. package/dist/lib/app-instances-service.d.ts.map +1 -0
  56. package/dist/lib/app-instances-service.js +377 -0
  57. package/dist/lib/app-instances-service.js.map +1 -0
  58. package/dist/lib/app-project-export.d.ts +12 -0
  59. package/dist/lib/app-project-export.d.ts.map +1 -0
  60. package/dist/lib/app-project-export.js +42 -0
  61. package/dist/lib/app-project-export.js.map +1 -0
  62. package/dist/lib/app-run-cancellation.d.ts +4 -0
  63. package/dist/lib/app-run-cancellation.d.ts.map +1 -0
  64. package/dist/lib/app-run-cancellation.js +28 -0
  65. package/dist/lib/app-run-cancellation.js.map +1 -0
  66. package/dist/lib/applications-service.d.ts +182 -1
  67. package/dist/lib/applications-service.d.ts.map +1 -1
  68. package/dist/lib/applications-service.js +27 -6
  69. package/dist/lib/applications-service.js.map +1 -1
  70. package/dist/lib/asset-export.d.ts +6 -2
  71. package/dist/lib/asset-export.d.ts.map +1 -1
  72. package/dist/lib/asset-export.js +15 -7
  73. package/dist/lib/asset-export.js.map +1 -1
  74. package/dist/lib/asset-paths.d.ts +7 -11
  75. package/dist/lib/asset-paths.d.ts.map +1 -1
  76. package/dist/lib/asset-paths.js +8 -56
  77. package/dist/lib/asset-paths.js.map +1 -1
  78. package/dist/lib/asset-response.d.ts.map +1 -1
  79. package/dist/lib/asset-response.js +3 -1
  80. package/dist/lib/asset-response.js.map +1 -1
  81. package/dist/lib/audio-peaks.d.ts.map +1 -1
  82. package/dist/lib/audio-peaks.js +5 -1
  83. package/dist/lib/audio-peaks.js.map +1 -1
  84. package/dist/lib/bridge.d.ts.map +1 -1
  85. package/dist/lib/bridge.js.map +1 -1
  86. package/dist/lib/cloud-profile.d.ts +10 -0
  87. package/dist/lib/cloud-profile.d.ts.map +1 -0
  88. package/dist/lib/cloud-profile.js +13 -0
  89. package/dist/lib/cloud-profile.js.map +1 -0
  90. package/dist/lib/document-model-interfaces.d.ts.map +1 -1
  91. package/dist/lib/document-model-interfaces.js +9 -8
  92. package/dist/lib/document-model-interfaces.js.map +1 -1
  93. package/dist/lib/example-apps.d.ts +9 -0
  94. package/dist/lib/example-apps.d.ts.map +1 -1
  95. package/dist/lib/example-apps.js +61 -14
  96. package/dist/lib/example-apps.js.map +1 -1
  97. package/dist/lib/http-tracing.d.ts +12 -0
  98. package/dist/lib/http-tracing.d.ts.map +1 -0
  99. package/dist/lib/http-tracing.js +81 -0
  100. package/dist/lib/http-tracing.js.map +1 -0
  101. package/dist/lib/http-user-id.d.ts +2 -0
  102. package/dist/lib/http-user-id.d.ts.map +1 -0
  103. package/dist/lib/http-user-id.js +4 -0
  104. package/dist/lib/http-user-id.js.map +1 -0
  105. package/dist/lib/json-body.d.ts +11 -0
  106. package/dist/lib/json-body.d.ts.map +1 -0
  107. package/dist/lib/json-body.js +13 -0
  108. package/dist/lib/json-body.js.map +1 -0
  109. package/dist/lib/media.d.ts +1 -6
  110. package/dist/lib/media.d.ts.map +1 -1
  111. package/dist/lib/media.js +8 -44
  112. package/dist/lib/media.js.map +1 -1
  113. package/dist/lib/public-routes.d.ts +22 -0
  114. package/dist/lib/public-routes.d.ts.map +1 -1
  115. package/dist/lib/public-routes.js +41 -0
  116. package/dist/lib/public-routes.js.map +1 -1
  117. package/dist/lib/public-workflow-share.d.ts +31 -0
  118. package/dist/lib/public-workflow-share.d.ts.map +1 -0
  119. package/dist/lib/public-workflow-share.js +88 -0
  120. package/dist/lib/public-workflow-share.js.map +1 -0
  121. package/dist/lib/python-metadata-roots.d.ts +27 -0
  122. package/dist/lib/python-metadata-roots.d.ts.map +1 -0
  123. package/dist/lib/python-metadata-roots.js +92 -0
  124. package/dist/lib/python-metadata-roots.js.map +1 -0
  125. package/dist/lib/run-trace-live-delivery.d.ts +25 -0
  126. package/dist/lib/run-trace-live-delivery.d.ts.map +1 -0
  127. package/dist/lib/run-trace-live-delivery.js +91 -0
  128. package/dist/lib/run-trace-live-delivery.js.map +1 -0
  129. package/dist/lib/runtime-detection.d.ts +1 -1
  130. package/dist/lib/runtime-detection.d.ts.map +1 -1
  131. package/dist/lib/runtime-detection.js +2 -1
  132. package/dist/lib/runtime-detection.js.map +1 -1
  133. package/dist/lib/server-auth-token.d.ts +18 -0
  134. package/dist/lib/server-auth-token.d.ts.map +1 -0
  135. package/dist/lib/server-auth-token.js +28 -0
  136. package/dist/lib/server-auth-token.js.map +1 -0
  137. package/dist/lib/test-ui-run-routes.d.ts +8 -0
  138. package/dist/lib/test-ui-run-routes.d.ts.map +1 -0
  139. package/dist/lib/test-ui-run-routes.js +42 -0
  140. package/dist/lib/test-ui-run-routes.js.map +1 -0
  141. package/dist/lib/thumbnail.d.ts.map +1 -1
  142. package/dist/lib/thumbnail.js +12 -9
  143. package/dist/lib/thumbnail.js.map +1 -1
  144. package/dist/lib/timeline-bundle.d.ts +159 -16
  145. package/dist/lib/timeline-bundle.d.ts.map +1 -1
  146. package/dist/lib/timeline-bundle.js +34 -6
  147. package/dist/lib/timeline-bundle.js.map +1 -1
  148. package/dist/lib/timeline-media-export.d.ts +18 -0
  149. package/dist/lib/timeline-media-export.d.ts.map +1 -0
  150. package/dist/lib/timeline-media-export.js +66 -0
  151. package/dist/lib/timeline-media-export.js.map +1 -0
  152. package/dist/lib/timeline-premiere-import.d.ts +24 -0
  153. package/dist/lib/timeline-premiere-import.d.ts.map +1 -0
  154. package/dist/lib/timeline-premiere-import.js +102 -0
  155. package/dist/lib/timeline-premiere-import.js.map +1 -0
  156. package/dist/lib/timeline-premiere.d.ts +38 -0
  157. package/dist/lib/timeline-premiere.d.ts.map +1 -0
  158. package/dist/lib/timeline-premiere.js +87 -0
  159. package/dist/lib/timeline-premiere.js.map +1 -0
  160. package/dist/lib/video-proxy.d.ts.map +1 -1
  161. package/dist/lib/video-proxy.js +3 -2
  162. package/dist/lib/video-proxy.js.map +1 -1
  163. package/dist/lib/workflow-service.d.ts.map +1 -1
  164. package/dist/lib/workflow-service.js +4 -1
  165. package/dist/lib/workflow-service.js.map +1 -1
  166. package/dist/mcp-agent-tools.d.ts.map +1 -1
  167. package/dist/mcp-agent-tools.js +95 -162
  168. package/dist/mcp-agent-tools.js.map +1 -1
  169. package/dist/mcp-client-config.d.ts +64 -0
  170. package/dist/mcp-client-config.d.ts.map +1 -0
  171. package/dist/mcp-client-config.js +353 -0
  172. package/dist/mcp-client-config.js.map +1 -0
  173. package/dist/mcp-server.d.ts +7 -0
  174. package/dist/mcp-server.d.ts.map +1 -1
  175. package/dist/mcp-server.js +163 -16
  176. package/dist/mcp-server.js.map +1 -1
  177. package/dist/mcp-skill-prompts.d.ts +23 -0
  178. package/dist/mcp-skill-prompts.d.ts.map +1 -0
  179. package/dist/mcp-skill-prompts.js +91 -0
  180. package/dist/mcp-skill-prompts.js.map +1 -0
  181. package/dist/mcp-tool-deps.d.ts.map +1 -1
  182. package/dist/mcp-tool-deps.js +8 -1
  183. package/dist/mcp-tool-deps.js.map +1 -1
  184. package/dist/models-api.d.ts +10 -0
  185. package/dist/models-api.d.ts.map +1 -1
  186. package/dist/models-api.js +29 -2
  187. package/dist/models-api.js.map +1 -1
  188. package/dist/node-registry-setup.d.ts +1 -1
  189. package/dist/node-registry-setup.d.ts.map +1 -1
  190. package/dist/node-registry-setup.js +21 -114
  191. package/dist/node-registry-setup.js.map +1 -1
  192. package/dist/oauth-api.d.ts.map +1 -1
  193. package/dist/oauth-api.js +45 -23
  194. package/dist/oauth-api.js.map +1 -1
  195. package/dist/openai-api.d.ts.map +1 -1
  196. package/dist/openai-api.js +10 -2
  197. package/dist/openai-api.js.map +1 -1
  198. package/dist/plugins/websocket.d.ts.map +1 -1
  199. package/dist/plugins/websocket.js +27 -59
  200. package/dist/plugins/websocket.js.map +1 -1
  201. package/dist/python-bridge-gate.d.ts +28 -0
  202. package/dist/python-bridge-gate.d.ts.map +1 -0
  203. package/dist/python-bridge-gate.js +36 -0
  204. package/dist/python-bridge-gate.js.map +1 -0
  205. package/dist/routes/app-runs.d.ts +4 -0
  206. package/dist/routes/app-runs.d.ts.map +1 -0
  207. package/dist/routes/app-runs.js +173 -0
  208. package/dist/routes/app-runs.js.map +1 -0
  209. package/dist/routes/applications.d.ts +1 -0
  210. package/dist/routes/applications.d.ts.map +1 -1
  211. package/dist/routes/applications.js +24 -0
  212. package/dist/routes/applications.js.map +1 -1
  213. package/dist/routes/assets.d.ts.map +1 -1
  214. package/dist/routes/assets.js +31 -41
  215. package/dist/routes/assets.js.map +1 -1
  216. package/dist/routes/config.d.ts.map +1 -1
  217. package/dist/routes/config.js +6 -0
  218. package/dist/routes/config.js.map +1 -1
  219. package/dist/routes/documents.d.ts.map +1 -1
  220. package/dist/routes/documents.js +24 -0
  221. package/dist/routes/documents.js.map +1 -1
  222. package/dist/routes/fal-pricing-estimate.d.ts.map +1 -1
  223. package/dist/routes/fal-pricing-estimate.js +2 -0
  224. package/dist/routes/fal-pricing-estimate.js.map +1 -1
  225. package/dist/routes/files.d.ts.map +1 -1
  226. package/dist/routes/files.js +2 -0
  227. package/dist/routes/files.js.map +1 -1
  228. package/dist/routes/games.d.ts +38 -0
  229. package/dist/routes/games.d.ts.map +1 -0
  230. package/dist/routes/games.js +158 -0
  231. package/dist/routes/games.js.map +1 -0
  232. package/dist/routes/integrations.d.ts.map +1 -1
  233. package/dist/routes/integrations.js +22 -26
  234. package/dist/routes/integrations.js.map +1 -1
  235. package/dist/routes/js-scripts.d.ts +10 -4
  236. package/dist/routes/js-scripts.d.ts.map +1 -1
  237. package/dist/routes/js-scripts.js +451 -69
  238. package/dist/routes/js-scripts.js.map +1 -1
  239. package/dist/routes/nodes.d.ts.map +1 -1
  240. package/dist/routes/nodes.js +34 -1
  241. package/dist/routes/nodes.js.map +1 -1
  242. package/dist/routes/public-shared-workflows.d.ts +16 -0
  243. package/dist/routes/public-shared-workflows.d.ts.map +1 -0
  244. package/dist/routes/public-shared-workflows.js +55 -0
  245. package/dist/routes/public-shared-workflows.js.map +1 -0
  246. package/dist/routes/run-spans.d.ts +4 -0
  247. package/dist/routes/run-spans.d.ts.map +1 -0
  248. package/dist/routes/run-spans.js +53 -0
  249. package/dist/routes/run-spans.js.map +1 -0
  250. package/dist/routes/storage.d.ts.map +1 -1
  251. package/dist/routes/storage.js +2 -0
  252. package/dist/routes/storage.js.map +1 -1
  253. package/dist/routes/storyboards.d.ts.map +1 -1
  254. package/dist/routes/storyboards.js +6 -3
  255. package/dist/routes/storyboards.js.map +1 -1
  256. package/dist/routes/timeline-fonts.d.ts +22 -0
  257. package/dist/routes/timeline-fonts.d.ts.map +1 -1
  258. package/dist/routes/timeline-fonts.js +138 -7
  259. package/dist/routes/timeline-fonts.js.map +1 -1
  260. package/dist/routes/timelines.d.ts +8 -4
  261. package/dist/routes/timelines.d.ts.map +1 -1
  262. package/dist/routes/timelines.js +209 -16
  263. package/dist/routes/timelines.js.map +1 -1
  264. package/dist/screenshot-docs-seed.d.ts +24 -0
  265. package/dist/screenshot-docs-seed.d.ts.map +1 -0
  266. package/dist/screenshot-docs-seed.js +414 -0
  267. package/dist/screenshot-docs-seed.js.map +1 -0
  268. package/dist/screenshot-projects.d.ts.map +1 -1
  269. package/dist/screenshot-projects.js +9 -9
  270. package/dist/screenshot-projects.js.map +1 -1
  271. package/dist/screenshot-server.js +114 -20
  272. package/dist/screenshot-server.js.map +1 -1
  273. package/dist/sdk/sdk-model-download-service.d.ts.map +1 -1
  274. package/dist/sdk/sdk-model-download-service.js +5 -2
  275. package/dist/sdk/sdk-model-download-service.js.map +1 -1
  276. package/dist/server.js +173 -109
  277. package/dist/server.js.map +1 -1
  278. package/dist/session/app-run-fold.d.ts +7 -0
  279. package/dist/session/app-run-fold.d.ts.map +1 -0
  280. package/dist/session/app-run-fold.js +45 -0
  281. package/dist/session/app-run-fold.js.map +1 -0
  282. package/dist/session/chat-prompt.d.ts.map +1 -1
  283. package/dist/session/chat-prompt.js +37 -15
  284. package/dist/session/chat-prompt.js.map +1 -1
  285. package/dist/session/chat-turn.d.ts +11 -0
  286. package/dist/session/chat-turn.d.ts.map +1 -1
  287. package/dist/session/chat-turn.js +270 -116
  288. package/dist/session/chat-turn.js.map +1 -1
  289. package/dist/session/commands.d.ts +14 -0
  290. package/dist/session/commands.d.ts.map +1 -1
  291. package/dist/session/commands.js +119 -14
  292. package/dist/session/commands.js.map +1 -1
  293. package/dist/session/inference.d.ts +30 -2
  294. package/dist/session/inference.d.ts.map +1 -1
  295. package/dist/session/inference.js +165 -16
  296. package/dist/session/inference.js.map +1 -1
  297. package/dist/session/job-execution.d.ts +7 -1
  298. package/dist/session/job-execution.d.ts.map +1 -1
  299. package/dist/session/job-execution.js +329 -42
  300. package/dist/session/job-execution.js.map +1 -1
  301. package/dist/session/model-interfaces.d.ts +2 -1
  302. package/dist/session/model-interfaces.d.ts.map +1 -1
  303. package/dist/session/model-interfaces.js +1 -0
  304. package/dist/session/model-interfaces.js.map +1 -1
  305. package/dist/storage-api.d.ts +0 -4
  306. package/dist/storage-api.d.ts.map +1 -1
  307. package/dist/storage-api.js +3 -26
  308. package/dist/storage-api.js.map +1 -1
  309. package/dist/storage-retention.d.ts +5 -0
  310. package/dist/storage-retention.d.ts.map +1 -1
  311. package/dist/storage-retention.js +22 -1
  312. package/dist/storage-retention.js.map +1 -1
  313. package/dist/test-ui-server.d.ts +11 -0
  314. package/dist/test-ui-server.d.ts.map +1 -1
  315. package/dist/test-ui-server.js +84 -6
  316. package/dist/test-ui-server.js.map +1 -1
  317. package/dist/timeline-generation-recovery.d.ts +4 -0
  318. package/dist/timeline-generation-recovery.d.ts.map +1 -0
  319. package/dist/timeline-generation-recovery.js +72 -0
  320. package/dist/timeline-generation-recovery.js.map +1 -0
  321. package/dist/triggers/dispatcher.d.ts.map +1 -1
  322. package/dist/triggers/dispatcher.js +26 -6
  323. package/dist/triggers/dispatcher.js.map +1 -1
  324. package/dist/triggers/file-watch.d.ts.map +1 -1
  325. package/dist/triggers/file-watch.js +35 -19
  326. package/dist/triggers/file-watch.js.map +1 -1
  327. package/dist/triggers/scheduler.d.ts.map +1 -1
  328. package/dist/triggers/scheduler.js +7 -5
  329. package/dist/triggers/scheduler.js.map +1 -1
  330. package/dist/triggers/stores.js +8 -8
  331. package/dist/triggers/stores.js.map +1 -1
  332. package/dist/triggers/webhook-route.js +2 -2
  333. package/dist/triggers/webhook-route.js.map +1 -1
  334. package/dist/trpc/error-formatter.d.ts.map +1 -1
  335. package/dist/trpc/error-formatter.js +2 -1
  336. package/dist/trpc/error-formatter.js.map +1 -1
  337. package/dist/trpc/error-logging.d.ts +10 -0
  338. package/dist/trpc/error-logging.d.ts.map +1 -1
  339. package/dist/trpc/error-logging.js +21 -0
  340. package/dist/trpc/error-logging.js.map +1 -1
  341. package/dist/trpc/router.d.ts +100 -31028
  342. package/dist/trpc/router.d.ts.map +1 -1
  343. package/dist/trpc/router.js +12 -3
  344. package/dist/trpc/router.js.map +1 -1
  345. package/dist/trpc/routers/app-instances.d.ts +2332 -0
  346. package/dist/trpc/routers/app-instances.d.ts.map +1 -0
  347. package/dist/trpc/routers/app-instances.js +52 -0
  348. package/dist/trpc/routers/app-instances.js.map +1 -0
  349. package/dist/trpc/routers/app-runs.d.ts +1120 -0
  350. package/dist/trpc/routers/app-runs.d.ts.map +1 -0
  351. package/dist/trpc/routers/app-runs.js +28 -0
  352. package/dist/trpc/routers/app-runs.js.map +1 -0
  353. package/dist/trpc/routers/applications.d.ts +1102 -0
  354. package/dist/trpc/routers/applications.d.ts.map +1 -1
  355. package/dist/trpc/routers/applications.js +5 -2
  356. package/dist/trpc/routers/applications.js.map +1 -1
  357. package/dist/trpc/routers/assets.d.ts +18 -0
  358. package/dist/trpc/routers/assets.d.ts.map +1 -1
  359. package/dist/trpc/routers/assets.js +20 -5
  360. package/dist/trpc/routers/assets.js.map +1 -1
  361. package/dist/trpc/routers/bug-reports.d.ts +33 -0
  362. package/dist/trpc/routers/bug-reports.d.ts.map +1 -0
  363. package/dist/trpc/routers/bug-reports.js +69 -0
  364. package/dist/trpc/routers/bug-reports.js.map +1 -0
  365. package/dist/trpc/routers/collections.d.ts.map +1 -1
  366. package/dist/trpc/routers/collections.js +16 -10
  367. package/dist/trpc/routers/collections.js.map +1 -1
  368. package/dist/trpc/routers/credits.d.ts.map +1 -1
  369. package/dist/trpc/routers/credits.js +11 -1
  370. package/dist/trpc/routers/credits.js.map +1 -1
  371. package/dist/trpc/routers/documents.d.ts.map +1 -1
  372. package/dist/trpc/routers/documents.js +8 -2
  373. package/dist/trpc/routers/documents.js.map +1 -1
  374. package/dist/trpc/routers/error-traces.d.ts +132 -0
  375. package/dist/trpc/routers/error-traces.d.ts.map +1 -0
  376. package/dist/trpc/routers/error-traces.js +118 -0
  377. package/dist/trpc/routers/error-traces.js.map +1 -0
  378. package/dist/trpc/routers/extension.d.ts +3 -3
  379. package/dist/trpc/routers/extension.d.ts.map +1 -1
  380. package/dist/trpc/routers/extension.js +13 -9
  381. package/dist/trpc/routers/extension.js.map +1 -1
  382. package/dist/trpc/routers/gameDraftHistory.d.ts +7 -0
  383. package/dist/trpc/routers/gameDraftHistory.d.ts.map +1 -0
  384. package/dist/trpc/routers/gameDraftHistory.js +40 -0
  385. package/dist/trpc/routers/gameDraftHistory.js.map +1 -0
  386. package/dist/trpc/routers/games.d.ts +59974 -5414
  387. package/dist/trpc/routers/games.d.ts.map +1 -1
  388. package/dist/trpc/routers/games.js +531 -136
  389. package/dist/trpc/routers/games.js.map +1 -1
  390. package/dist/trpc/routers/jobs.d.ts +42 -0
  391. package/dist/trpc/routers/jobs.d.ts.map +1 -1
  392. package/dist/trpc/routers/jobs.js +89 -4
  393. package/dist/trpc/routers/jobs.js.map +1 -1
  394. package/dist/trpc/routers/js-scripts.d.ts.map +1 -1
  395. package/dist/trpc/routers/js-scripts.js +18 -2
  396. package/dist/trpc/routers/js-scripts.js.map +1 -1
  397. package/dist/trpc/routers/mcp-config.d.ts +3 -1
  398. package/dist/trpc/routers/mcp-config.d.ts.map +1 -1
  399. package/dist/trpc/routers/mcp-config.js +46 -208
  400. package/dist/trpc/routers/mcp-config.js.map +1 -1
  401. package/dist/trpc/routers/messages.d.ts +10 -0
  402. package/dist/trpc/routers/messages.d.ts.map +1 -1
  403. package/dist/trpc/routers/messages.js +16 -2
  404. package/dist/trpc/routers/messages.js.map +1 -1
  405. package/dist/trpc/routers/models.d.ts +130 -0
  406. package/dist/trpc/routers/models.d.ts.map +1 -1
  407. package/dist/trpc/routers/models.js +119 -61
  408. package/dist/trpc/routers/models.js.map +1 -1
  409. package/dist/trpc/routers/packs.d.ts.map +1 -1
  410. package/dist/trpc/routers/packs.js +18 -4
  411. package/dist/trpc/routers/packs.js.map +1 -1
  412. package/dist/trpc/routers/projects.d.ts +66 -2
  413. package/dist/trpc/routers/projects.d.ts.map +1 -1
  414. package/dist/trpc/routers/projects.js +19 -2
  415. package/dist/trpc/routers/projects.js.map +1 -1
  416. package/dist/trpc/routers/runs.d.ts +472 -0
  417. package/dist/trpc/routers/runs.d.ts.map +1 -0
  418. package/dist/trpc/routers/runs.js +40 -0
  419. package/dist/trpc/routers/runs.js.map +1 -0
  420. package/dist/trpc/routers/settings.d.ts +3 -0
  421. package/dist/trpc/routers/settings.d.ts.map +1 -1
  422. package/dist/trpc/routers/settings.js +32 -5
  423. package/dist/trpc/routers/settings.js.map +1 -1
  424. package/dist/trpc/routers/sketch.d.ts +44 -0
  425. package/dist/trpc/routers/sketch.d.ts.map +1 -1
  426. package/dist/trpc/routers/sketch.js +2 -2
  427. package/dist/trpc/routers/sketch.js.map +1 -1
  428. package/dist/trpc/routers/storyboards.d.ts +903 -1
  429. package/dist/trpc/routers/storyboards.d.ts.map +1 -1
  430. package/dist/trpc/routers/storyboards.js +8 -5
  431. package/dist/trpc/routers/storyboards.js.map +1 -1
  432. package/dist/trpc/routers/threads.d.ts.map +1 -1
  433. package/dist/trpc/routers/threads.js +8 -2
  434. package/dist/trpc/routers/threads.js.map +1 -1
  435. package/dist/trpc/routers/timeline.d.ts +647 -63
  436. package/dist/trpc/routers/timeline.d.ts.map +1 -1
  437. package/dist/trpc/routers/timeline.js +193 -4
  438. package/dist/trpc/routers/timeline.js.map +1 -1
  439. package/dist/trpc/routers/triggers.d.ts.map +1 -1
  440. package/dist/trpc/routers/triggers.js +18 -3
  441. package/dist/trpc/routers/triggers.js.map +1 -1
  442. package/dist/trpc/routers/users.d.ts +3 -2
  443. package/dist/trpc/routers/users.d.ts.map +1 -1
  444. package/dist/trpc/routers/users.js +25 -27
  445. package/dist/trpc/routers/users.js.map +1 -1
  446. package/dist/trpc/routers/worker.d.ts +10 -9
  447. package/dist/trpc/routers/worker.d.ts.map +1 -1
  448. package/dist/trpc/routers/worker.js +40 -16
  449. package/dist/trpc/routers/worker.js.map +1 -1
  450. package/dist/trpc/routers/workflows.d.ts +202 -3
  451. package/dist/trpc/routers/workflows.d.ts.map +1 -1
  452. package/dist/trpc/routers/workflows.js +72 -12
  453. package/dist/trpc/routers/workflows.js.map +1 -1
  454. package/dist/trpc/sandbox-coverage.d.ts.map +1 -1
  455. package/dist/trpc/sandbox-coverage.js +119 -0
  456. package/dist/trpc/sandbox-coverage.js.map +1 -1
  457. package/dist/websocket-client-session.d.ts +4 -2
  458. package/dist/websocket-client-session.d.ts.map +1 -1
  459. package/dist/websocket-client-session.js +23 -3
  460. package/dist/websocket-client-session.js.map +1 -1
  461. package/dist/worker-settings-env.d.ts +23 -0
  462. package/dist/worker-settings-env.d.ts.map +1 -0
  463. package/dist/worker-settings-env.js +47 -0
  464. package/dist/worker-settings-env.js.map +1 -0
  465. package/dist/workflow-interface-service.d.ts +7 -0
  466. package/dist/workflow-interface-service.d.ts.map +1 -1
  467. package/package.json +58 -41
  468. package/dist/extension-cdp-bridge.d.ts +0 -85
  469. package/dist/extension-cdp-bridge.d.ts.map +0 -1
  470. package/dist/extension-cdp-bridge.js +0 -163
  471. package/dist/extension-cdp-bridge.js.map +0 -1
package/dist/server.js CHANGED
@@ -6,21 +6,23 @@
6
6
  * An HTTP→HTTPS redirect server starts on port 80 when TLS is active.
7
7
  * Connect the CLI with: npm run chat -- --url ws://localhost:7777/ws
8
8
  */
9
- import { startGenerationReconcileWorker, sweepInterruptedGenerations } from "@nodetool-ai/execution";
9
+ import { ensureRunTraceTelemetry, startGenerationReconcileWorker, sweepInterruptedGenerations } from "@nodetool-ai/execution";
10
10
  import { join, resolve, dirname } from "node:path";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
13
- import { spawnSync } from "node:child_process";
14
13
  import { createServer as createHttpServer } from "node:http";
14
+ import { flushCompileCache } from "node:module";
15
15
  import crypto from "node:crypto";
16
16
  import { createLogger, configureLogging, getDefaultDbPath, getPostgresDatabaseUrl, loadEnvironment } from "@nodetool-ai/config";
17
17
  import { registerTransformersJsProvider } from "@nodetool-ai/transformers-js-provider";
18
+ import { registerWhisperCppProviders } from "@nodetool-ai/whisper-cpp";
18
19
  import { setCodeNodeAgentsModule } from "@nodetool-ai/base-nodes";
19
20
  import * as agentsModule from "@nodetool-ai/agents";
20
21
  import { bootstrapNodeRegistry, mergePythonBridgeMetadata } from "./node-registry-setup.js";
21
22
  import { corsOriginDelegate } from "./cors.js";
22
23
  import { zipExtensionDist } from "./lib/extension-dist.js";
23
- import { isPublicAuthExemptRoute } from "./lib/public-routes.js";
24
+ import { isPublicAuthExemptRoute, isStaticAppRequest, routedPathname } from "./lib/public-routes.js";
25
+ import { matchesServerAuthToken, resolveServerAuthToken } from "./lib/server-auth-token.js";
24
26
  import { isWebSocketUpgrade, denyUnauthorized, denyDraining } from "./lib/ws-upgrade.js";
25
27
  import { isDraining, startDrain } from "./drain.js";
26
28
  import { chatTurnRegistry } from "./chat-turn-registry.js";
@@ -28,18 +30,22 @@ import { jobRunRegistry } from "./job-run-registry.js";
28
30
  import { replayUpgradeToOwner } from "./lib/fly-replay.js";
29
31
  import { startJobCancelPoller } from "./job-control.js";
30
32
  import { resolveTrustLocalhost, isLoopbackAddress, parseTrustedProxies, parseTrustedLocalNetworks, isTrustedLocalAddress } from "./lib/localhost-trust.js";
31
- import { initTelemetry, shutdownTelemetry, createPythonBridge, WebsocketPythonBridge, SwappableBridge, logPythonWorkerStderr } from "@nodetool-ai/runtime";
33
+ import { registerHttpTracing } from "./lib/http-tracing.js";
34
+ import { shutdownTelemetry, createPythonBridge, WebsocketPythonBridge, SwappableBridge, logPythonWorkerStderr } from "@nodetool-ai/runtime";
32
35
  import { deriveKey, getMasterKey, initMasterKey } from "@nodetool-ai/security";
33
36
  import { setDefaultModelInterfaces } from "@nodetool-ai/runtime";
34
37
  import { serverModelInterfaces } from "./websocket-client-session.js";
35
38
  import { WorkerManager, attachWorkerActivityHeartbeat, startReaper } from "@nodetool-ai/compute";
36
- import { getSecret, AccessToken, getWorkerProfile, initDb, initPostgresDb, isAccessToken, McpOauthClient, MCP_OAUTH_ACCESS_TOKEN_PREFIX, migrateSqliteDb, runSeeds } from "@nodetool-ai/models";
39
+ import { getSecret, getRegisteredRunTrace, AccessToken, getWorkerProfile, initDb, initPostgresDb, isAccessToken, McpOauthClient, MCP_OAUTH_ACCESS_TOKEN_PREFIX, migrateSqliteDb, runSeeds } from "@nodetool-ai/models";
40
+ import { applyTransformersJsCacheSetting, resolveWorkerSettingsEnv } from "./worker-settings-env.js";
37
41
  import { isMcpHttpEnabled, MCP_ENABLE_FLAG } from "./lib/mcp-mount.js";
38
42
  import { authenticateMcpAccessToken, mcpBearerChallenge } from "./oauth/gate.js";
39
43
  import { registerPythonProviders, relayWorkerDownload } from "./models-api.js";
44
+ import { createProviderRegistrar } from "./python-bridge-gate.js";
40
45
  import { syncCustomProviderRegistry } from "./custom-providers.js";
41
- import { runAutomaticStorageCleanup } from "./storage-retention.js";
46
+ import { runScheduledStorageCleanup } from "./storage-retention.js";
42
47
  import { createGenerationRecoveryWorker } from "./generation-recovery.js";
48
+ import { sweepInterruptedJobs } from "./interrupted-jobs.js";
43
49
  /** User id the auth middleware assigns in local (no-account) mode. */
44
50
  const LOCAL_USER_ID = "1";
45
51
  /** How long an MCP OAuth client nobody ever approved is kept before the
@@ -53,7 +59,7 @@ import fastifyCors from "@fastify/cors";
53
59
  import fastifyRateLimit from "@fastify/rate-limit";
54
60
  import fastifyStatic from "@fastify/static";
55
61
  import { packWebSocketMessage } from "./messagepack.js";
56
- import { SupabaseAuthProvider, LocalAuthProvider, DelegatedTokenProvider, isDelegatedToken, AppSessionTokenProvider, isAppSessionToken } from "@nodetool-ai/auth";
62
+ import { SupabaseAuthProvider, LocalAuthProvider, DelegatedTokenProvider, isDelegatedToken, AppSessionTokenProvider, isAppSessionToken, FileUserManager } from "@nodetool-ai/auth";
57
63
  import { fastifyTRPCPlugin } from "@trpc/server/adapters/fastify";
58
64
  import { appRouter } from "./trpc/router.js";
59
65
  import { createContextFactory } from "./trpc/context.js";
@@ -89,7 +95,10 @@ import { initWorkspaceChangeEvents, initWorkspaceStorage } from "./lib/workflow-
89
95
  import filesRoutes from "./routes/files.js";
90
96
  import collectionsRoutes from "./routes/collections.js";
91
97
  import applicationsRoutes from "./routes/applications.js";
98
+ import appRunsRoutes from "./routes/app-runs.js";
99
+ import runSpansRoutes from "./routes/run-spans.js";
92
100
  import publicAppRoutes from "./routes/public-apps.js";
101
+ import publicSharedWorkflowRoutes from "./routes/public-shared-workflows.js";
93
102
  import { appDeploymentsEnabled } from "./lib/app-deployment-service.js";
94
103
  import accountRoutes from "./routes/account.js";
95
104
  import jsScriptsRoutes from "./routes/js-scripts.js";
@@ -98,6 +107,7 @@ import timelineAudioBakeRoutes from "./routes/timeline-audio-bake.js";
98
107
  import timelineIsolateSubjectRoutes from "./routes/timeline-isolate-subject.js";
99
108
  import timelineTrackObjectRoutes from "./routes/timeline-track-object.js";
100
109
  import storyboardsRoutes from "./routes/storyboards.js";
110
+ import gamesRoutes from "./routes/games.js";
101
111
  import timelinesRoutes from "./routes/timelines.js";
102
112
  import documentsRoutes from "./routes/documents.js";
103
113
  import sandboxModulesRoutes from "./routes/sandbox-modules.js";
@@ -110,8 +120,11 @@ import kieWebhookRoute from "./routes/kie-webhook.js";
110
120
  import falWebhookRoute from "./routes/fal-webhook.js";
111
121
  import atlasCloudWebhookRoute from "./routes/atlascloud-webhook.js";
112
122
  import { createIntegrationRoutes } from "./routes/integrations.js";
113
- import { isNonEmptyString, isString } from "./lib/wire-values.js";
114
- import { logTrpcRequestError } from "./trpc/error-logging.js";
123
+ import { isString } from "./lib/wire-values.js";
124
+ import { logTrpcRequestError, traceTrpcRequestError } from "./trpc/error-logging.js";
125
+ import { captureError, startErrorTraceMaintenance } from "./error-traces.js";
126
+ import { detectPipMetadataRoots } from "./lib/python-metadata-roots.js";
127
+ import { getSetting } from "./settings-registry.js";
115
128
  // @llamaindex/liteparse bundles a webpack pdf.js whose `isNodeJS` heuristic
116
129
  // resolves to false inside Electron utilityProcess (process.type === "utility"),
117
130
  // causing it to take browser-only code paths that reference the global `document`
@@ -145,15 +158,19 @@ const log = createLogger("nodetool.websocket.server");
145
158
  // initialises eagerly, but an explicit call here picks up any env mutations
146
159
  // made by the process launcher before this point).
147
160
  configureLogging();
148
- await initTelemetry();
161
+ // The Python interpreter scan runs while telemetry starts and the database
162
+ // opens and migrates. The node registry below is the first reader.
163
+ const pipMetadataRoots = detectPipMetadataRoots();
164
+ await ensureRunTraceTelemetry();
149
165
  const startupT0 = performance.now();
150
166
  /**
151
- * When this process started. A generation row still `running` from before
152
- * this moment belongs to a process that is gone, and the sweep closes it
153
- * (docs/media-generation-tracking-design.md § 6.3).
167
+ * When this process started. A generation or job row still in flight from
168
+ * before this moment belongs to a process that is gone, and the startup sweeps
169
+ * close it (docs/media-generation-tracking-design.md § 6.3).
154
170
  */
155
171
  const PROCESS_STARTED_AT = new Date().toISOString();
156
172
  let stopGenerationReconcileWorker = null;
173
+ let stopErrorTraceMaintenance = null;
157
174
  function startupMs() {
158
175
  return `${(performance.now() - startupT0).toFixed(0)}ms`;
159
176
  }
@@ -174,10 +191,7 @@ async function notifyPythonBridgeResourceChanges(app, pythonBridge) {
174
191
  resource_type: "metadata",
175
192
  resource: { id: "nodes", etag: String(Date.now()) }
176
193
  });
177
- const registered = await registerPythonProviders(pythonBridge);
178
- if (registered.length > 0) {
179
- log.info(`Registered Python providers: ${registered.join(", ")}`);
180
- }
194
+ const registered = await registerPythonProvidersOnce();
181
195
  const discoveredProviders = await pythonBridge.listProviders();
182
196
  const registeredProviders = new Set(registered);
183
197
  for (const provider of discoveredProviders) {
@@ -243,7 +257,33 @@ try {
243
257
  // that need provider credentials bind their own `(key) => getSecret(key,
244
258
  // userId)` closure when invoking provider APIs — there is no shared
245
259
  // global resolver.
246
- await initMasterKey();
260
+ //
261
+ // A machine with no keychain (a container, CI, a server without a D-Bus
262
+ // session) cannot unlock the store. The server still starts, the way the
263
+ // CLI commands do: provider keys from the environment keep working, and
264
+ // only reading or writing a stored secret fails. Exiting here made
265
+ // `npx @nodetool-ai/cli serve` unusable on every headless machine.
266
+ try {
267
+ await initMasterKey();
268
+ }
269
+ catch (err) {
270
+ log.warn("Secret store is locked: stored secrets are unavailable, and provider " +
271
+ "keys are read from the environment. Set SECRETS_MASTER_KEY to a " +
272
+ "base64-encoded 32-byte key to enable the store.", { error: err instanceof Error ? err.message : String(err) });
273
+ }
274
+ // Transformers.js fixes its cache directory on first import, which happens
275
+ // after this point, so a directory saved in Settings must be applied now.
276
+ try {
277
+ const tjsCacheDir = await applyTransformersJsCacheSetting(LOCAL_USER_ID);
278
+ if (tjsCacheDir) {
279
+ log.info("Transformers.js cache directory from Settings", { path: tjsCacheDir });
280
+ }
281
+ }
282
+ catch (err) {
283
+ log.warn("Could not read TRANSFORMERS_JS_CACHE_DIR from Settings", {
284
+ error: err instanceof Error ? err.message : String(err)
285
+ });
286
+ }
247
287
  // Bookkeeping for media generations: close the rows a restart orphaned, and
248
288
  // keep refining estimates into billed amounts while the server runs.
249
289
  void sweepInterruptedGenerations(PROCESS_STARTED_AT).catch((err) => {
@@ -251,11 +291,19 @@ try {
251
291
  error: err instanceof Error ? err.message : String(err)
252
292
  });
253
293
  });
294
+ void sweepInterruptedJobs(PROCESS_STARTED_AT, {
295
+ sharedDatabase: Boolean(postgresDatabaseUrl)
296
+ }).catch((err) => {
297
+ log.warn("Interrupted-job sweep failed", {
298
+ error: err instanceof Error ? err.message : String(err)
299
+ });
300
+ });
254
301
  stopGenerationReconcileWorker = startGenerationReconcileWorker({
255
302
  resolveSecret: (key, userId) => getSecret(key, userId)
256
303
  });
304
+ stopErrorTraceMaintenance = startErrorTraceMaintenance();
257
305
  const runHistoryCleanup = () => {
258
- void runAutomaticStorageCleanup(LOCAL_USER_ID)
306
+ void runScheduledStorageCleanup(LOCAL_USER_ID)
259
307
  .then((result) => {
260
308
  if (result && result.total > 0) {
261
309
  log.info("Cleaned retained workflow and run history", result);
@@ -310,73 +358,7 @@ try {
310
358
  catch (err) {
311
359
  log.warn("Custom provider sync failed (non-fatal)", err instanceof Error ? err : new Error(String(err)));
312
360
  }
313
- // ---------------------------------------------------------------------------
314
- // Python pip metadata root detection
315
- // ---------------------------------------------------------------------------
316
- function detectPipMetadataRoots() {
317
- const script = `
318
- import json, pathlib, subprocess, sys
319
- roots = set()
320
- try:
321
- # Discover all nodetool-* packages
322
- list_proc = subprocess.run(
323
- [sys.executable, "-m", "pip", "list", "--format=json"],
324
- capture_output=True, text=True, check=False,
325
- )
326
- pkg_names = [
327
- p["name"] for p in json.loads(list_proc.stdout or "[]")
328
- if p["name"].startswith("nodetool-")
329
- ] or ["nodetool-core", "nodetool-base"]
330
- proc = subprocess.run(
331
- [sys.executable, "-m", "pip", "show", "-f"] + pkg_names,
332
- capture_output=True, text=True, check=False,
333
- )
334
- output = proc.stdout or ""
335
- except Exception:
336
- output = ""
337
- location = None
338
- in_files = False
339
- for raw in output.splitlines():
340
- line = raw.rstrip("\\n")
341
- if line.startswith("Name: "):
342
- location = None; in_files = False; continue
343
- if line.startswith("Location: "):
344
- location = line.split(":", 1)[1].strip(); continue
345
- if line.startswith("Editable project location: "):
346
- editable = line.split(":", 1)[1].strip()
347
- if editable: roots.add(editable)
348
- continue
349
- if line.startswith("Files:"): in_files = True; continue
350
- if line.startswith("---"):
351
- location = None; in_files = False; continue
352
- if not in_files or not location or not line.startswith(" "): continue
353
- rel = line.strip().replace("\\\\", "/")
354
- if "package_metadata" not in rel: continue
355
- abs_path = (pathlib.Path(location) / rel).resolve()
356
- metadata_dir = abs_path if abs_path.is_dir() else abs_path.parent
357
- roots.add(str(metadata_dir))
358
- print(json.dumps(sorted(roots)))
359
- `;
360
- for (const python of ["python3", "python"]) {
361
- const proc = spawnSync(python, ["-c", script], {
362
- encoding: "utf8",
363
- stdio: ["ignore", "pipe", "ignore"]
364
- });
365
- if (proc.status !== 0 || !proc.stdout)
366
- continue;
367
- try {
368
- const roots = JSON.parse(proc.stdout.trim());
369
- if (Array.isArray(roots)) {
370
- return roots.filter((p) => isNonEmptyString(p) && existsSync(p));
371
- }
372
- }
373
- catch {
374
- // try next python executable
375
- }
376
- }
377
- return [];
378
- }
379
- const metadataRoots = detectPipMetadataRoots();
361
+ const metadataRoots = await pipMetadataRoots;
380
362
  // Also scan local TS node packages that have nodetool/package_metadata
381
363
  const localPackagesDir = resolve(dirname(fileURLToPath(import.meta.url)), "../../");
382
364
  if (existsSync(localPackagesDir)) {
@@ -419,6 +401,7 @@ log.info(`Node registry ready [${startupMs()}]`);
419
401
  setCodeNodeAgentsModule(agentsModule);
420
402
  if (process.env["NODETOOL_ENV"] !== "production") {
421
403
  registerTransformersJsProvider();
404
+ registerWhisperCppProviders();
422
405
  }
423
406
  // ---------------------------------------------------------------------------
424
407
  // Python bridge
@@ -426,7 +409,8 @@ if (process.env["NODETOOL_ENV"] !== "production") {
426
409
  const localBridge = createPythonBridge({
427
410
  workerArgs: process.env["NODETOOL_WORKER_NAMESPACES"]
428
411
  ? ["--namespaces", process.env["NODETOOL_WORKER_NAMESPACES"]]
429
- : []
412
+ : [],
413
+ workerEnv: () => resolveWorkerSettingsEnv(LOCAL_USER_ID)
430
414
  });
431
415
  // The ONE stable bridge reference handed to every consumer. It delegates to the
432
416
  // local bridge by default; attaching a worker swaps in a dedicated WebSocket
@@ -435,6 +419,19 @@ const localBridge = createPythonBridge({
435
419
  // stable and re-emits its target's events, consumers never re-read it and
436
420
  // listeners are wired exactly once.
437
421
  const pythonBridge = new SwappableBridge(localBridge);
422
+ /**
423
+ * Python-only providers (`huggingface-local`) exist only once the worker has
424
+ * listed them. A run that selects one must wait for this, not just for the
425
+ * connection: registration follows the connect, and a run that arrives in
426
+ * between is refused for an unknown provider.
427
+ */
428
+ const registerPythonProvidersOnce = createProviderRegistrar(async () => {
429
+ const registered = await registerPythonProviders(pythonBridge);
430
+ if (registered.length > 0) {
431
+ log.info(`Registered Python providers: ${registered.join(", ")}`);
432
+ }
433
+ return registered;
434
+ });
438
435
  let pythonBridgeReady = false;
439
436
  // Worker bridge bookkeeping so it can be closed after swapping away. Only the
440
437
  // remote WebSocket bridge is tracked here; the local stdio bridge is owned by
@@ -642,12 +639,30 @@ const serverOptions = {
642
639
  }
643
640
  };
644
641
  const app = Fastify(httpsOptions ? { https: httpsOptions, ...serverOptions } : serverOptions);
642
+ // First hook, so every later hook and handler runs inside the request span.
645
643
  // ---------------------------------------------------------------------------
646
644
  // Request ID correlation
647
645
  // ---------------------------------------------------------------------------
648
646
  app.addHook("onRequest", async (request) => {
649
647
  request.log.info({ reqId: request.id, method: request.method, url: request.url }, "incoming request");
650
648
  });
649
+ // A REST handler that throws a 5xx leaves a redacted trace. 4xx errors are
650
+ // the caller's mistake and are not traced.
651
+ app.addHook("onError", async (request, _reply, error) => {
652
+ const status = error.statusCode ?? 500;
653
+ if (status < 500)
654
+ return;
655
+ captureError(error, {
656
+ source: "http",
657
+ userId: request.userId ?? null,
658
+ context: {
659
+ route: request.routeOptions.url ?? request.url.split("?")[0],
660
+ method: request.method,
661
+ http_status: status,
662
+ request_id: request.id
663
+ }
664
+ });
665
+ });
651
666
  app.addHook("onSend", async (request, reply) => {
652
667
  reply.header("X-Request-Id", request.id);
653
668
  // Baseline security response headers. The web app's CSP lives in a `<meta>`
@@ -739,6 +754,18 @@ if (enforceAuth && trustLocalhost) {
739
754
  const trustLocalNetworks = enforceAuth
740
755
  ? []
741
756
  : parseTrustedLocalNetworks(process.env["NODETOOL_TRUST_LOCAL_NETWORKS"]);
757
+ // The bearer token `nodetool deploy` starts a container with. Local mode only,
758
+ // like the trusted networks above: Supabase mode needs a real login.
759
+ const serverAuthToken = enforceAuth
760
+ ? null
761
+ : resolveServerAuthToken(process.env["SERVER_AUTH_TOKEN"]);
762
+ // API users created with `nodetool deploy users-add` (the tRPC users router)
763
+ // live in USERS_FILE. Local mode only, for the same reason as the token above.
764
+ const apiUsers = enforceAuth ? null : new FileUserManager();
765
+ if (enforceAuth && process.env["SERVER_AUTH_TOKEN"]) {
766
+ log.warn("SERVER_AUTH_TOKEN is set while auth is enforced (Supabase mode); it is " +
767
+ "ignored. Clients must sign in.");
768
+ }
742
769
  if (enforceAuth && process.env["NODETOOL_TRUST_LOCAL_NETWORKS"]) {
743
770
  log.warn("NODETOOL_TRUST_LOCAL_NETWORKS is set while auth is enforced (Supabase " +
744
771
  "mode); it is ignored so every request must present a valid token.");
@@ -790,22 +817,16 @@ app.addHook("onRequest", async (req, reply) => {
790
817
  if (req.method === "OPTIONS")
791
818
  return;
792
819
  // Public routes — no auth required (still rate-limited globally above).
793
- const pathname = req.url.split("?")[0];
794
- if (isPublicAuthExemptRoute(pathname, req.method) ||
795
- (isSdkV1DiscoveryRequest(pathname, req.method) &&
796
- !isSdkV1AuthenticationRequired(process.env, enforceAuth))) {
820
+ // Match the decoded path the router uses, or `/%61pi/...` skips auth.
821
+ const pathname = routedPathname(req.url);
822
+ if (pathname !== null &&
823
+ (isPublicAuthExemptRoute(pathname, req.method) ||
824
+ (isSdkV1DiscoveryRequest(pathname, req.method) &&
825
+ !isSdkV1AuthenticationRequired(process.env, enforceAuth)))) {
797
826
  return;
798
827
  }
799
- // Static frontend assets don't require auth (served by fastifyStatic)
800
- // `GET /mcp` is the MCP SSE stream, not a static asset — it must go through
801
- // auth so the mount can bind the session's user.
802
- if (hasStaticApp &&
803
- req.method === "GET" &&
804
- !pathname.startsWith("/api") &&
805
- !pathname.startsWith("/ws") &&
806
- !pathname.startsWith("/v1") &&
807
- !pathname.startsWith("/trpc") &&
808
- !pathname.startsWith("/mcp")) {
828
+ // Static frontend assets don't require auth (served by fastifyStatic).
829
+ if (hasStaticApp && isStaticAppRequest(pathname, req.method)) {
809
830
  return;
810
831
  }
811
832
  // req.ip reflects X-Forwarded-For only when the request arrived through a
@@ -871,9 +892,8 @@ app.addHook("onRequest", async (req, reply) => {
871
892
  // application it may act on, and its whole point is that it reaches nothing
872
893
  // else — so the confinement is applied right here, at the door, rather than
873
894
  // trusted to every handler downstream. `/ws` is the only path it opens: the
874
- // run transport, and exactly that path — `/ws/download` and `/ws/extension`
875
- // are model downloads and the browser-extension bridge, neither of which a
876
- // visitor to somebody's app has any business opening. The public app routes
895
+ // run transport, and exactly that path — `/ws/download` is model downloads,
896
+ // which a visitor to somebody's app has no business opening. The public app routes
877
897
  // need no token at all (they are auth-exempt above), and every other path —
878
898
  // tRPC, the REST library, assets, settings — is refused, because the
879
899
  // owner's account is not what the visitor was given a link to.
@@ -915,7 +935,7 @@ app.addHook("onRequest", async (req, reply) => {
915
935
  // /mcp gets a WWW-Authenticate challenge on every unauthenticated/invalid
916
936
  // denial below it — but only when the OAuth flow can actually complete
917
937
  // (see mcpBearerChallenge). Every other path is unaffected.
918
- const challenge = pathname.startsWith("/mcp")
938
+ const challenge = pathname?.startsWith("/mcp")
919
939
  ? mcpBearerChallenge()
920
940
  : undefined;
921
941
  if (supabaseMode) {
@@ -932,8 +952,27 @@ app.addHook("onRequest", async (req, reply) => {
932
952
  req.authToken = token;
933
953
  return;
934
954
  }
955
+ if (matchesServerAuthToken(token, serverAuthToken)) {
956
+ req.userId = "1";
957
+ req.authToken = token;
958
+ return;
959
+ }
960
+ const apiUser = token && apiUsers ? await apiUsers.verifyToken(token) : null;
961
+ if (apiUser) {
962
+ req.userId = apiUser.id;
963
+ req.authToken = token;
964
+ return;
965
+ }
935
966
  denyUnauthorized(req, reply, { error: "Remote access requires authentication" }, challenge);
936
967
  });
968
+ registerHttpTracing(app, {
969
+ async authorizeTraceParent(request, parent) {
970
+ if (!request.userId || request.appSession) {
971
+ return false;
972
+ }
973
+ return Boolean(await getRegisteredRunTrace(request.userId, parent.traceId));
974
+ }
975
+ });
937
976
  // Multi-instance only: a handshake asking to resume a run that another machine
938
977
  // owns is answered with a fly-replay instruction instead of being accepted
939
978
  // here, so the client reconnects onto the process holding the run's session.
@@ -1176,12 +1215,18 @@ await app.register(fastifyTRPCPlugin, {
1176
1215
  // flag the server rejects POST-to-query with 405, leaving panels empty.
1177
1216
  allowMethodOverride: true,
1178
1217
  maxBatchSize: TRPC_MAX_BATCH_SIZE,
1179
- onError({ path, error, req }) {
1218
+ onError({ path, error, req, ctx }) {
1180
1219
  logTrpcRequestError(log, {
1181
1220
  path,
1182
1221
  error,
1183
1222
  requestId: req.id
1184
1223
  });
1224
+ traceTrpcRequestError({
1225
+ path,
1226
+ error,
1227
+ requestId: req.id,
1228
+ userId: ctx?.userId
1229
+ });
1185
1230
  }
1186
1231
  }
1187
1232
  });
@@ -1194,8 +1239,10 @@ await app.register(websocketPlugin, {
1194
1239
  workerManager,
1195
1240
  getPythonBridgeReady,
1196
1241
  ensurePythonBridge: async () => {
1197
- if (getPythonBridgeReady())
1242
+ if (getPythonBridgeReady()) {
1243
+ await registerPythonProvidersOnce();
1198
1244
  return;
1245
+ }
1199
1246
  log.info(`Lazily starting Python bridge [${startupMs()}]`);
1200
1247
  try {
1201
1248
  await pythonBridge.ensureConnected();
@@ -1233,6 +1280,8 @@ await app.register(websocketPlugin, {
1233
1280
  log.warn(`Failed to fetch Python bridge status [${startupMs()}]`, err instanceof Error ? err : new Error(String(err)));
1234
1281
  });
1235
1282
  logPythonBridgeDiagnostics("connected");
1283
+ // The run that asked for the bridge may select a Python-only provider.
1284
+ await registerPythonProvidersOnce();
1236
1285
  notifyPythonBridgeResourceChanges(app, pythonBridge).catch((err) => {
1237
1286
  log.warn("Failed to notify Python bridge resource changes", err instanceof Error ? err : new Error(String(err)));
1238
1287
  });
@@ -1269,14 +1318,18 @@ initWorkspaceStorage();
1269
1318
  initWorkspaceChangeEvents();
1270
1319
  await app.register(filesRoutes, routeOpts);
1271
1320
  await app.register(collectionsRoutes, routeOpts);
1321
+ await app.register(appRunsRoutes);
1322
+ await app.register(runSpansRoutes);
1272
1323
  await app.register(applicationsRoutes, routeOpts);
1273
1324
  await app.register(publicAppRoutes, { appSessionSigningKey });
1325
+ await app.register(publicSharedWorkflowRoutes);
1274
1326
  await app.register(jsScriptsRoutes, routeOpts);
1275
1327
  await app.register(timelineAnimationRoutes, routeOpts);
1276
1328
  await app.register(timelineAudioBakeRoutes, routeOpts);
1277
1329
  await app.register(timelineIsolateSubjectRoutes, routeOpts);
1278
1330
  await app.register(timelineTrackObjectRoutes, routeOpts);
1279
1331
  await app.register(storyboardsRoutes, routeOpts);
1332
+ await app.register(gamesRoutes, routeOpts);
1280
1333
  await app.register(timelinesRoutes, routeOpts);
1281
1334
  // PDF/DOCX text extraction for script and screenplay imports. Stores
1282
1335
  // nothing and needs no apiOptions.
@@ -1463,6 +1516,10 @@ app.listen({ port, host }, (err) => {
1463
1516
  }
1464
1517
  log.info(`Server listening on ${proto}://${host}:${port} [${startupMs()}]`);
1465
1518
  log.info(`WebSocket endpoint: ${tlsEnabled ? "wss" : "ws"}://${host}:${port}/ws`);
1519
+ // When the launcher sets NODE_COMPILE_CACHE, Node writes the V8 code cache
1520
+ // only on a clean exit. Writing it once startup has compiled the server keeps
1521
+ // it for the next start even when this process is killed. No-op otherwise.
1522
+ flushCompileCache();
1466
1523
  });
1467
1524
  // ---------------------------------------------------------------------------
1468
1525
  // Triggers — durable wakeup service, dispatcher, and ingestion adapters
@@ -1562,6 +1619,7 @@ async function shutdown(signal) {
1562
1619
  clearInterval(generationRecoveryTimer);
1563
1620
  stopJobCancelPoller();
1564
1621
  stopGenerationReconcileWorker?.();
1622
+ stopErrorTraceMaintenance?.();
1565
1623
  try {
1566
1624
  await triggerServices.stop();
1567
1625
  }
@@ -1592,8 +1650,14 @@ process.on("SIGUSR2", () => {
1592
1650
  if (process.platform === "win32") {
1593
1651
  process.on("SIGBREAK", () => void shutdown("SIGBREAK"));
1594
1652
  }
1595
- // Start Python bridge eagerly if a worker is available.
1596
- if (pythonBridge.isAvailable()) {
1653
+ // Start the Python bridge eagerly if a worker is available, unless the user
1654
+ // chose to start it on first use. Runs that need it start it through
1655
+ // `ensurePythonBridge` either way.
1656
+ const pythonOnDemand = (await getSetting("NODETOOL_PYTHON_ON_DEMAND")) === "true";
1657
+ if (pythonBridge.isAvailable() && pythonOnDemand) {
1658
+ log.info("Python bridge starts on first use (NODETOOL_PYTHON_ON_DEMAND=true)");
1659
+ }
1660
+ else if (pythonBridge.isAvailable()) {
1597
1661
  log.info(`Starting Python bridge eagerly [${startupMs()}]`);
1598
1662
  pythonBridge
1599
1663
  .ensureConnected()