@amodalai/runtime 0.1.0

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 (277) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.last_build +0 -0
  3. package/dist/src/agent/agent-runner.d.ts +13 -0
  4. package/dist/src/agent/agent-runner.js +827 -0
  5. package/dist/src/agent/agent-runner.js.map +1 -0
  6. package/dist/src/agent/agent-runner.test.d.ts +6 -0
  7. package/dist/src/agent/agent-runner.test.js +552 -0
  8. package/dist/src/agent/agent-runner.test.js.map +1 -0
  9. package/dist/src/agent/agent-types.d.ts +57 -0
  10. package/dist/src/agent/agent-types.js +17 -0
  11. package/dist/src/agent/agent-types.js.map +1 -0
  12. package/dist/src/agent/agent-types.test.d.ts +6 -0
  13. package/dist/src/agent/agent-types.test.js +44 -0
  14. package/dist/src/agent/agent-types.test.js.map +1 -0
  15. package/dist/src/agent/automation-bridge.d.ts +24 -0
  16. package/dist/src/agent/automation-bridge.js +24 -0
  17. package/dist/src/agent/automation-bridge.js.map +1 -0
  18. package/dist/src/agent/automation-bridge.test.d.ts +6 -0
  19. package/dist/src/agent/automation-bridge.test.js +67 -0
  20. package/dist/src/agent/automation-bridge.test.js.map +1 -0
  21. package/dist/src/agent/config-watcher.d.ts +20 -0
  22. package/dist/src/agent/config-watcher.js +68 -0
  23. package/dist/src/agent/config-watcher.js.map +1 -0
  24. package/dist/src/agent/config-watcher.test.d.ts +6 -0
  25. package/dist/src/agent/config-watcher.test.js +83 -0
  26. package/dist/src/agent/config-watcher.test.js.map +1 -0
  27. package/dist/src/agent/custom-tools-e2e.test.d.ts +6 -0
  28. package/dist/src/agent/custom-tools-e2e.test.js +566 -0
  29. package/dist/src/agent/custom-tools-e2e.test.js.map +1 -0
  30. package/dist/src/agent/local-server.d.ts +15 -0
  31. package/dist/src/agent/local-server.js +158 -0
  32. package/dist/src/agent/local-server.js.map +1 -0
  33. package/dist/src/agent/local-server.test.d.ts +6 -0
  34. package/dist/src/agent/local-server.test.js +126 -0
  35. package/dist/src/agent/local-server.test.js.map +1 -0
  36. package/dist/src/agent/proactive/delivery.d.ts +21 -0
  37. package/dist/src/agent/proactive/delivery.js +68 -0
  38. package/dist/src/agent/proactive/delivery.js.map +1 -0
  39. package/dist/src/agent/proactive/delivery.test.d.ts +6 -0
  40. package/dist/src/agent/proactive/delivery.test.js +65 -0
  41. package/dist/src/agent/proactive/delivery.test.js.map +1 -0
  42. package/dist/src/agent/proactive/proactive-runner.d.ts +76 -0
  43. package/dist/src/agent/proactive/proactive-runner.js +201 -0
  44. package/dist/src/agent/proactive/proactive-runner.js.map +1 -0
  45. package/dist/src/agent/proactive/proactive-runner.test.d.ts +6 -0
  46. package/dist/src/agent/proactive/proactive-runner.test.js +265 -0
  47. package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -0
  48. package/dist/src/agent/request-helper.d.ts +16 -0
  49. package/dist/src/agent/request-helper.js +87 -0
  50. package/dist/src/agent/request-helper.js.map +1 -0
  51. package/dist/src/agent/routes/automations.d.ts +19 -0
  52. package/dist/src/agent/routes/automations.js +58 -0
  53. package/dist/src/agent/routes/automations.js.map +1 -0
  54. package/dist/src/agent/routes/automations.test.d.ts +6 -0
  55. package/dist/src/agent/routes/automations.test.js +117 -0
  56. package/dist/src/agent/routes/automations.test.js.map +1 -0
  57. package/dist/src/agent/routes/chat.d.ts +35 -0
  58. package/dist/src/agent/routes/chat.js +88 -0
  59. package/dist/src/agent/routes/chat.js.map +1 -0
  60. package/dist/src/agent/routes/chat.test.d.ts +6 -0
  61. package/dist/src/agent/routes/chat.test.js +115 -0
  62. package/dist/src/agent/routes/chat.test.js.map +1 -0
  63. package/dist/src/agent/routes/inspect.d.ts +12 -0
  64. package/dist/src/agent/routes/inspect.js +40 -0
  65. package/dist/src/agent/routes/inspect.js.map +1 -0
  66. package/dist/src/agent/routes/inspect.test.d.ts +6 -0
  67. package/dist/src/agent/routes/inspect.test.js +80 -0
  68. package/dist/src/agent/routes/inspect.test.js.map +1 -0
  69. package/dist/src/agent/routes/stores.d.ts +20 -0
  70. package/dist/src/agent/routes/stores.js +137 -0
  71. package/dist/src/agent/routes/stores.js.map +1 -0
  72. package/dist/src/agent/routes/stores.test.d.ts +6 -0
  73. package/dist/src/agent/routes/stores.test.js +191 -0
  74. package/dist/src/agent/routes/stores.test.js.map +1 -0
  75. package/dist/src/agent/routes/task.d.ts +11 -0
  76. package/dist/src/agent/routes/task.js +116 -0
  77. package/dist/src/agent/routes/task.js.map +1 -0
  78. package/dist/src/agent/routes/task.test.d.ts +6 -0
  79. package/dist/src/agent/routes/task.test.js +91 -0
  80. package/dist/src/agent/routes/task.test.js.map +1 -0
  81. package/dist/src/agent/routes/webhooks.d.ts +17 -0
  82. package/dist/src/agent/routes/webhooks.js +53 -0
  83. package/dist/src/agent/routes/webhooks.js.map +1 -0
  84. package/dist/src/agent/routes/webhooks.test.d.ts +6 -0
  85. package/dist/src/agent/routes/webhooks.test.js +100 -0
  86. package/dist/src/agent/routes/webhooks.test.js.map +1 -0
  87. package/dist/src/agent/session-manager.d.ts +72 -0
  88. package/dist/src/agent/session-manager.js +214 -0
  89. package/dist/src/agent/session-manager.js.map +1 -0
  90. package/dist/src/agent/session-manager.test.d.ts +6 -0
  91. package/dist/src/agent/session-manager.test.js +145 -0
  92. package/dist/src/agent/session-manager.test.js.map +1 -0
  93. package/dist/src/agent/shell-executor-local.d.ts +16 -0
  94. package/dist/src/agent/shell-executor-local.js +51 -0
  95. package/dist/src/agent/shell-executor-local.js.map +1 -0
  96. package/dist/src/agent/shell-executor-local.test.d.ts +6 -0
  97. package/dist/src/agent/shell-executor-local.test.js +46 -0
  98. package/dist/src/agent/shell-executor-local.test.js.map +1 -0
  99. package/dist/src/agent/snapshot-server.d.ts +38 -0
  100. package/dist/src/agent/snapshot-server.js +114 -0
  101. package/dist/src/agent/snapshot-server.js.map +1 -0
  102. package/dist/src/agent/stores-e2e.test.d.ts +6 -0
  103. package/dist/src/agent/stores-e2e.test.js +433 -0
  104. package/dist/src/agent/stores-e2e.test.js.map +1 -0
  105. package/dist/src/agent/tool-context-builder.d.ts +11 -0
  106. package/dist/src/agent/tool-context-builder.js +84 -0
  107. package/dist/src/agent/tool-context-builder.js.map +1 -0
  108. package/dist/src/agent/tool-context-builder.test.d.ts +6 -0
  109. package/dist/src/agent/tool-context-builder.test.js +152 -0
  110. package/dist/src/agent/tool-context-builder.test.js.map +1 -0
  111. package/dist/src/agent/tool-executor-local.d.ts +15 -0
  112. package/dist/src/agent/tool-executor-local.js +74 -0
  113. package/dist/src/agent/tool-executor-local.js.map +1 -0
  114. package/dist/src/agent/tool-executor-local.test.d.ts +6 -0
  115. package/dist/src/agent/tool-executor-local.test.js +116 -0
  116. package/dist/src/agent/tool-executor-local.test.js.map +1 -0
  117. package/dist/src/agent/tool-harness-template.d.ts +23 -0
  118. package/dist/src/agent/tool-harness-template.js +94 -0
  119. package/dist/src/agent/tool-harness-template.js.map +1 -0
  120. package/dist/src/agent/user-context-fetcher.d.ts +25 -0
  121. package/dist/src/agent/user-context-fetcher.js +79 -0
  122. package/dist/src/agent/user-context-fetcher.js.map +1 -0
  123. package/dist/src/agent/user-context-fetcher.test.d.ts +6 -0
  124. package/dist/src/agent/user-context-fetcher.test.js +121 -0
  125. package/dist/src/agent/user-context-fetcher.test.js.map +1 -0
  126. package/dist/src/audit/audit-client.d.ts +46 -0
  127. package/dist/src/audit/audit-client.js +83 -0
  128. package/dist/src/audit/audit-client.js.map +1 -0
  129. package/dist/src/cron/heartbeat-runner.d.ts +24 -0
  130. package/dist/src/cron/heartbeat-runner.js +87 -0
  131. package/dist/src/cron/heartbeat-runner.js.map +1 -0
  132. package/dist/src/cron/heartbeat-runner.test.d.ts +6 -0
  133. package/dist/src/cron/heartbeat-runner.test.js +120 -0
  134. package/dist/src/cron/heartbeat-runner.test.js.map +1 -0
  135. package/dist/src/cron/heartbeat-scheduler.d.ts +26 -0
  136. package/dist/src/cron/heartbeat-scheduler.js +54 -0
  137. package/dist/src/cron/heartbeat-scheduler.js.map +1 -0
  138. package/dist/src/cron/heartbeat-scheduler.test.d.ts +6 -0
  139. package/dist/src/cron/heartbeat-scheduler.test.js +61 -0
  140. package/dist/src/cron/heartbeat-scheduler.test.js.map +1 -0
  141. package/dist/src/index.d.ts +24 -0
  142. package/dist/src/index.js +118 -0
  143. package/dist/src/index.js.map +1 -0
  144. package/dist/src/middleware/auth.d.ts +40 -0
  145. package/dist/src/middleware/auth.js +135 -0
  146. package/dist/src/middleware/auth.js.map +1 -0
  147. package/dist/src/middleware/auth.test.d.ts +6 -0
  148. package/dist/src/middleware/auth.test.js +268 -0
  149. package/dist/src/middleware/auth.test.js.map +1 -0
  150. package/dist/src/middleware/error-handler.d.ts +20 -0
  151. package/dist/src/middleware/error-handler.js +48 -0
  152. package/dist/src/middleware/error-handler.js.map +1 -0
  153. package/dist/src/middleware/error-handler.test.d.ts +6 -0
  154. package/dist/src/middleware/error-handler.test.js +68 -0
  155. package/dist/src/middleware/error-handler.test.js.map +1 -0
  156. package/dist/src/middleware/request-validation.d.ts +13 -0
  157. package/dist/src/middleware/request-validation.js +26 -0
  158. package/dist/src/middleware/request-validation.js.map +1 -0
  159. package/dist/src/middleware/request-validation.test.d.ts +6 -0
  160. package/dist/src/middleware/request-validation.test.js +57 -0
  161. package/dist/src/middleware/request-validation.test.js.map +1 -0
  162. package/dist/src/output/email-output.d.ts +10 -0
  163. package/dist/src/output/email-output.js +12 -0
  164. package/dist/src/output/email-output.js.map +1 -0
  165. package/dist/src/output/output-router.d.ts +12 -0
  166. package/dist/src/output/output-router.js +36 -0
  167. package/dist/src/output/output-router.js.map +1 -0
  168. package/dist/src/output/output-router.test.d.ts +6 -0
  169. package/dist/src/output/output-router.test.js +132 -0
  170. package/dist/src/output/output-router.test.js.map +1 -0
  171. package/dist/src/output/slack-output.d.ts +10 -0
  172. package/dist/src/output/slack-output.js +54 -0
  173. package/dist/src/output/slack-output.js.map +1 -0
  174. package/dist/src/output/webhook-output.d.ts +10 -0
  175. package/dist/src/output/webhook-output.js +25 -0
  176. package/dist/src/output/webhook-output.js.map +1 -0
  177. package/dist/src/routes/ai-stream.d.ts +159 -0
  178. package/dist/src/routes/ai-stream.js +309 -0
  179. package/dist/src/routes/ai-stream.js.map +1 -0
  180. package/dist/src/routes/ai-stream.test.d.ts +6 -0
  181. package/dist/src/routes/ai-stream.test.js +586 -0
  182. package/dist/src/routes/ai-stream.test.js.map +1 -0
  183. package/dist/src/routes/ask-user-response.d.ts +30 -0
  184. package/dist/src/routes/ask-user-response.js +61 -0
  185. package/dist/src/routes/ask-user-response.js.map +1 -0
  186. package/dist/src/routes/ask-user-response.test.d.ts +6 -0
  187. package/dist/src/routes/ask-user-response.test.js +88 -0
  188. package/dist/src/routes/ask-user-response.test.js.map +1 -0
  189. package/dist/src/routes/chat-stream.d.ts +14 -0
  190. package/dist/src/routes/chat-stream.js +84 -0
  191. package/dist/src/routes/chat-stream.js.map +1 -0
  192. package/dist/src/routes/chat-stream.test.d.ts +6 -0
  193. package/dist/src/routes/chat-stream.test.js +155 -0
  194. package/dist/src/routes/chat-stream.test.js.map +1 -0
  195. package/dist/src/routes/chat.d.ts +13 -0
  196. package/dist/src/routes/chat.js +55 -0
  197. package/dist/src/routes/chat.js.map +1 -0
  198. package/dist/src/routes/chat.test.d.ts +6 -0
  199. package/dist/src/routes/chat.test.js +99 -0
  200. package/dist/src/routes/chat.test.js.map +1 -0
  201. package/dist/src/routes/health.d.ts +13 -0
  202. package/dist/src/routes/health.js +23 -0
  203. package/dist/src/routes/health.js.map +1 -0
  204. package/dist/src/routes/health.test.d.ts +6 -0
  205. package/dist/src/routes/health.test.js +45 -0
  206. package/dist/src/routes/health.test.js.map +1 -0
  207. package/dist/src/routes/sessions.d.ts +14 -0
  208. package/dist/src/routes/sessions.js +82 -0
  209. package/dist/src/routes/sessions.js.map +1 -0
  210. package/dist/src/routes/webhooks.d.ts +13 -0
  211. package/dist/src/routes/webhooks.js +43 -0
  212. package/dist/src/routes/webhooks.js.map +1 -0
  213. package/dist/src/routes/webhooks.test.d.ts +6 -0
  214. package/dist/src/routes/webhooks.test.js +80 -0
  215. package/dist/src/routes/webhooks.test.js.map +1 -0
  216. package/dist/src/routes/widget-actions.d.ts +49 -0
  217. package/dist/src/routes/widget-actions.js +78 -0
  218. package/dist/src/routes/widget-actions.js.map +1 -0
  219. package/dist/src/server.d.ts +31 -0
  220. package/dist/src/server.js +129 -0
  221. package/dist/src/server.js.map +1 -0
  222. package/dist/src/server.test.d.ts +6 -0
  223. package/dist/src/server.test.js +153 -0
  224. package/dist/src/server.test.js.map +1 -0
  225. package/dist/src/session/history-converter.d.ts +21 -0
  226. package/dist/src/session/history-converter.js +59 -0
  227. package/dist/src/session/history-converter.js.map +1 -0
  228. package/dist/src/session/history-converter.test.d.ts +6 -0
  229. package/dist/src/session/history-converter.test.js +130 -0
  230. package/dist/src/session/history-converter.test.js.map +1 -0
  231. package/dist/src/session/session-manager.d.ts +117 -0
  232. package/dist/src/session/session-manager.js +480 -0
  233. package/dist/src/session/session-manager.js.map +1 -0
  234. package/dist/src/session/session-manager.test.d.ts +6 -0
  235. package/dist/src/session/session-manager.test.js +586 -0
  236. package/dist/src/session/session-manager.test.js.map +1 -0
  237. package/dist/src/session/session-runner.d.ts +30 -0
  238. package/dist/src/session/session-runner.js +771 -0
  239. package/dist/src/session/session-runner.js.map +1 -0
  240. package/dist/src/session/session-runner.test.d.ts +6 -0
  241. package/dist/src/session/session-runner.test.js +842 -0
  242. package/dist/src/session/session-runner.test.js.map +1 -0
  243. package/dist/src/stores/index.d.ts +8 -0
  244. package/dist/src/stores/index.js +9 -0
  245. package/dist/src/stores/index.js.map +1 -0
  246. package/dist/src/stores/key-resolver.d.ts +21 -0
  247. package/dist/src/stores/key-resolver.js +30 -0
  248. package/dist/src/stores/key-resolver.js.map +1 -0
  249. package/dist/src/stores/key-resolver.test.d.ts +6 -0
  250. package/dist/src/stores/key-resolver.test.js +31 -0
  251. package/dist/src/stores/key-resolver.test.js.map +1 -0
  252. package/dist/src/stores/pglite-store-backend.d.ts +36 -0
  253. package/dist/src/stores/pglite-store-backend.js +227 -0
  254. package/dist/src/stores/pglite-store-backend.js.map +1 -0
  255. package/dist/src/stores/pglite-store-backend.test.d.ts +6 -0
  256. package/dist/src/stores/pglite-store-backend.test.js +150 -0
  257. package/dist/src/stores/pglite-store-backend.test.js.map +1 -0
  258. package/dist/src/stores/ttl-resolver.d.ts +24 -0
  259. package/dist/src/stores/ttl-resolver.js +64 -0
  260. package/dist/src/stores/ttl-resolver.js.map +1 -0
  261. package/dist/src/stores/ttl-resolver.test.d.ts +6 -0
  262. package/dist/src/stores/ttl-resolver.test.js +68 -0
  263. package/dist/src/stores/ttl-resolver.test.js.map +1 -0
  264. package/dist/src/types.d.ts +227 -0
  265. package/dist/src/types.js +50 -0
  266. package/dist/src/types.js.map +1 -0
  267. package/dist/src/types.test.d.ts +6 -0
  268. package/dist/src/types.test.js +68 -0
  269. package/dist/src/types.test.js.map +1 -0
  270. package/dist/src/utils/jwt-verify.d.ts +20 -0
  271. package/dist/src/utils/jwt-verify.js +34 -0
  272. package/dist/src/utils/jwt-verify.js.map +1 -0
  273. package/dist/src/utils/jwt-verify.test.d.ts +6 -0
  274. package/dist/src/utils/jwt-verify.test.js +156 -0
  275. package/dist/src/utils/jwt-verify.test.js.map +1 -0
  276. package/dist/tsconfig.tsbuildinfo +1 -0
  277. package/package.json +51 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import type { SessionManager } from '../session/session-manager.js';
8
+ export interface HealthRouterOptions {
9
+ sessionManager: SessionManager;
10
+ version?: string;
11
+ startedAt: number;
12
+ }
13
+ export declare function createHealthRouter(options: HealthRouterOptions): Router;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ export function createHealthRouter(options) {
8
+ const router = Router();
9
+ router.get('/health', (_req, res) => {
10
+ res.json({
11
+ status: 'ok',
12
+ uptime_ms: Date.now() - options.startedAt,
13
+ active_sessions: options.sessionManager.size,
14
+ });
15
+ });
16
+ router.get('/version', (_req, res) => {
17
+ res.json({
18
+ version: options.version ?? 'unknown',
19
+ });
20
+ });
21
+ return router;
22
+ }
23
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/routes/health.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AASjC,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC7D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QAClC,GAAG,CAAC,IAAI,CAAC;YACP,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS;YACzC,eAAe,EAAE,OAAO,CAAC,cAAc,CAAC,IAAI;SAC7C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACnC,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,SAAS;SACtC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { describe, it, expect } from 'vitest';
7
+ import express from 'express';
8
+ import request from 'supertest';
9
+ import { createHealthRouter } from './health.js';
10
+ function createApp() {
11
+ const app = express();
12
+ const sessionManager = { size: 3 };
13
+ app.use(createHealthRouter({
14
+ sessionManager: sessionManager,
15
+ version: '1.0.0',
16
+ startedAt: Date.now() - 5000,
17
+ }));
18
+ return app;
19
+ }
20
+ describe('GET /health', () => {
21
+ it('returns 200 with status ok', async () => {
22
+ const res = await request(createApp()).get('/health');
23
+ expect(res.status).toBe(200);
24
+ expect(res.body.status).toBe('ok');
25
+ expect(res.body.active_sessions).toBe(3);
26
+ expect(res.body.uptime_ms).toBeGreaterThan(0);
27
+ });
28
+ });
29
+ describe('GET /version', () => {
30
+ it('returns 200 with version', async () => {
31
+ const res = await request(createApp()).get('/version');
32
+ expect(res.status).toBe(200);
33
+ expect(res.body.version).toBe('1.0.0');
34
+ });
35
+ it('returns unknown when no version provided', async () => {
36
+ const app = express();
37
+ app.use(createHealthRouter({
38
+ sessionManager: { size: 0 },
39
+ startedAt: Date.now(),
40
+ }));
41
+ const res = await request(app).get('/version');
42
+ expect(res.body.version).toBe('unknown');
43
+ });
44
+ });
45
+ //# sourceMappingURL=health.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.test.js","sourceRoot":"","sources":["../../../src/routes/health.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,cAAc,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACnC,GAAG,CAAC,GAAG,CACL,kBAAkB,CAAC;QACjB,cAAc,EAAE,cAAuB;QACvC,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI;KAC7B,CAAC,CACH,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CACL,kBAAkB,CAAC;YACjB,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,EAAW;YACpC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CACH,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ export interface SessionsRouterOptions {
8
+ platformApiUrl: string;
9
+ }
10
+ /**
11
+ * Proxy routes for session history.
12
+ * Forwards to platform-api /api/tenants/{tenantId}/sessions endpoints.
13
+ */
14
+ export declare function createSessionsRouter(options: SessionsRouterOptions): Router;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import { getAuthContext } from '../middleware/auth.js';
8
+ /**
9
+ * Proxy routes for session history.
10
+ * Forwards to platform-api /api/tenants/{tenantId}/sessions endpoints.
11
+ */
12
+ export function createSessionsRouter(options) {
13
+ const router = Router();
14
+ // List sessions for the authenticated tenant
15
+ router.get('/sessions/history', async (req, res, next) => {
16
+ try {
17
+ const auth = getAuthContext(res);
18
+ if (!auth?.tenantId || !auth.token) {
19
+ res.status(401).json({ error: { code: 'UNAUTHORIZED', message: 'Missing auth context' } });
20
+ return;
21
+ }
22
+ const tagsParam = req.query['tags'];
23
+ const qs = tagsParam ? `?tags=${String(tagsParam)}` : '';
24
+ const url = `${options.platformApiUrl}/api/tenants/${auth.tenantId}/sessions${qs}`;
25
+ const response = await fetch(url, {
26
+ headers: { Authorization: `Bearer ${auth.token}` },
27
+ });
28
+ const data = await response.json();
29
+ res.status(response.status).json(data);
30
+ }
31
+ catch (err) {
32
+ next(err);
33
+ }
34
+ });
35
+ // Get a single session with full messages
36
+ router.get('/sessions/history/:id', async (req, res, next) => {
37
+ try {
38
+ const auth = getAuthContext(res);
39
+ if (!auth?.tenantId || !auth.token) {
40
+ res.status(401).json({ error: { code: 'UNAUTHORIZED', message: 'Missing auth context' } });
41
+ return;
42
+ }
43
+ const sessionId = req.params['id'];
44
+ const url = `${options.platformApiUrl}/api/tenants/${auth.tenantId}/sessions/${sessionId}`;
45
+ const response = await fetch(url, {
46
+ headers: { Authorization: `Bearer ${auth.token}` },
47
+ });
48
+ const data = await response.json();
49
+ res.status(response.status).json(data);
50
+ }
51
+ catch (err) {
52
+ next(err);
53
+ }
54
+ });
55
+ // Update session tags/title
56
+ router.patch('/sessions/history/:id', async (req, res, next) => {
57
+ try {
58
+ const auth = getAuthContext(res);
59
+ if (!auth?.tenantId || !auth.token) {
60
+ res.status(401).json({ error: { code: 'UNAUTHORIZED', message: 'Missing auth context' } });
61
+ return;
62
+ }
63
+ const sessionId = req.params['id'];
64
+ const url = `${options.platformApiUrl}/api/tenants/${auth.tenantId}/sessions/${sessionId}`;
65
+ const response = await fetch(url, {
66
+ method: 'PATCH',
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ Authorization: `Bearer ${auth.token}`,
70
+ },
71
+ body: JSON.stringify(req.body),
72
+ });
73
+ const data = await response.json();
74
+ res.status(response.status).json(data);
75
+ }
76
+ catch (err) {
77
+ next(err);
78
+ }
79
+ });
80
+ return router;
81
+ }
82
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../../src/routes/sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import type { AutomationDefinition } from '@amodalai/core';
8
+ import type { AutomationRunnerFn } from '../cron/heartbeat-runner.js';
9
+ export interface WebhookRouterOptions {
10
+ automations: AutomationDefinition[];
11
+ runAutomation: AutomationRunnerFn;
12
+ }
13
+ export declare function createWebhookRouter(options: WebhookRouterOptions): Router;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import { WebhookPayloadSchema } from '../types.js';
8
+ import { validate } from '../middleware/request-validation.js';
9
+ import { AppError } from '../middleware/error-handler.js';
10
+ export function createWebhookRouter(options) {
11
+ const router = Router();
12
+ // Build a lookup map: webhook source name → automation definition
13
+ const webhookAutomations = new Map();
14
+ for (const a of options.automations) {
15
+ if (a.trigger.type === 'webhook') {
16
+ webhookAutomations.set(a.name, a);
17
+ }
18
+ }
19
+ router.post('/webhooks/:name', validate(WebhookPayloadSchema), async (req, res, next) => {
20
+ try {
21
+ const { name } = req.params;
22
+ if (!name) {
23
+ throw new AppError(400, 'MISSING_NAME', 'Automation name is required');
24
+ }
25
+ const automation = webhookAutomations.get(name);
26
+ if (!automation) {
27
+ throw new AppError(404, 'AUTOMATION_NOT_FOUND', `No webhook automation named "${name}"`);
28
+ }
29
+ // Run automation asynchronously — respond 202 immediately
30
+ const payload = req.body.data;
31
+ void options.runAutomation(automation, payload);
32
+ res.status(202).json({
33
+ accepted: true,
34
+ automation: name,
35
+ });
36
+ }
37
+ catch (err) {
38
+ next(err);
39
+ }
40
+ });
41
+ return router;
42
+ }
43
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/routes/webhooks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAQ1D,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,kEAAkE;IAClE,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAgC,CAAC;IACnE,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,QAAQ,CAAC,oBAAoB,CAAC,EAC9B,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;YAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,6BAA6B,CAAC,CAAC;YACzE,CAAC;YAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,QAAQ,CAChB,GAAG,EACH,sBAAsB,EACtB,gCAAgC,IAAI,GAAG,CACxC,CAAC;YACJ,CAAC;YAED,0DAA0D;YAC1D,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9B,KAAK,OAAO,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAEhD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export {};
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import express from 'express';
8
+ import request from 'supertest';
9
+ import { createWebhookRouter } from './webhooks.js';
10
+ import { errorHandler } from '../middleware/error-handler.js';
11
+ function makeAutomation(name, triggerType = 'webhook') {
12
+ return {
13
+ name,
14
+ trigger: triggerType === 'cron'
15
+ ? { type: 'cron', schedule: '*/5 * * * *' }
16
+ : { type: 'webhook', source: name },
17
+ prompt: `Handle ${name}`,
18
+ tools: ['tool1'],
19
+ skills: ['*'],
20
+ output: { channel: 'slack', target: 'https://hooks.slack.com/abc' },
21
+ allow_writes: false,
22
+ };
23
+ }
24
+ describe('POST /webhooks/:name', () => {
25
+ let mockRunAutomation;
26
+ let automations;
27
+ beforeEach(() => {
28
+ mockRunAutomation = vi.fn().mockResolvedValue({
29
+ automation: 'test-webhook',
30
+ response: 'done',
31
+ tool_calls: [],
32
+ output_sent: true,
33
+ duration_ms: 100,
34
+ });
35
+ automations = [
36
+ makeAutomation('test-webhook', 'webhook'),
37
+ makeAutomation('cron-only', 'cron'),
38
+ ];
39
+ });
40
+ function createApp() {
41
+ const app = express();
42
+ app.use(express.json());
43
+ app.use(createWebhookRouter({
44
+ automations,
45
+ runAutomation: mockRunAutomation,
46
+ }));
47
+ app.use(errorHandler);
48
+ return app;
49
+ }
50
+ it('accepts a known webhook automation with 202', async () => {
51
+ const res = await request(createApp())
52
+ .post('/webhooks/test-webhook')
53
+ .send({});
54
+ expect(res.status).toBe(202);
55
+ expect(res.body.accepted).toBe(true);
56
+ expect(res.body.automation).toBe('test-webhook');
57
+ expect(mockRunAutomation).toHaveBeenCalledOnce();
58
+ });
59
+ it('passes payload data to automation runner', async () => {
60
+ await request(createApp())
61
+ .post('/webhooks/test-webhook')
62
+ .send({ data: { device_id: '42' } });
63
+ const callArgs = mockRunAutomation.mock.calls[0];
64
+ expect(callArgs[1]).toEqual({ device_id: '42' });
65
+ });
66
+ it('returns 404 for unknown automation name', async () => {
67
+ const res = await request(createApp())
68
+ .post('/webhooks/nonexistent')
69
+ .send({});
70
+ expect(res.status).toBe(404);
71
+ expect(res.body.error.code).toBe('AUTOMATION_NOT_FOUND');
72
+ });
73
+ it('returns 404 for cron-only automation', async () => {
74
+ const res = await request(createApp())
75
+ .post('/webhooks/cron-only')
76
+ .send({});
77
+ expect(res.status).toBe(404);
78
+ });
79
+ });
80
+ //# sourceMappingURL=webhooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.test.js","sourceRoot":"","sources":["../../../src/routes/webhooks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import { z } from 'zod';
8
+ import type { SessionManager } from '../session/session-manager.js';
9
+ declare const WidgetActionSchema: z.ZodDiscriminatedUnion<"action", [z.ZodObject<{
10
+ action: z.ZodLiteral<"credential_saved">;
11
+ connection_name: z.ZodString;
12
+ }, "strip", z.ZodTypeAny, {
13
+ action: "credential_saved";
14
+ connection_name: string;
15
+ }, {
16
+ action: "credential_saved";
17
+ connection_name: string;
18
+ }>, z.ZodObject<{
19
+ action: z.ZodLiteral<"approved">;
20
+ resource_type: z.ZodString;
21
+ preview_id: z.ZodString;
22
+ }, "strip", z.ZodTypeAny, {
23
+ action: "approved";
24
+ resource_type: string;
25
+ preview_id: string;
26
+ }, {
27
+ action: "approved";
28
+ resource_type: string;
29
+ preview_id: string;
30
+ }>]>;
31
+ export type WidgetAction = z.infer<typeof WidgetActionSchema>;
32
+ export interface WidgetActionsRouterOptions {
33
+ sessionManager: SessionManager;
34
+ }
35
+ /**
36
+ * Construct the synthetic user message for a widget action.
37
+ * The chat widget sends this as a follow-up user message so the
38
+ * agent knows the user acted on the widget.
39
+ */
40
+ export declare function buildSyntheticMessage(action: WidgetAction): string;
41
+ /**
42
+ * POST /chat/sessions/:session_id/widget-action
43
+ *
44
+ * Accepts user actions from input widgets (credential-input, document-preview).
45
+ * Validates the action and returns a synthetic message that the chat widget
46
+ * should send as a follow-up user message.
47
+ */
48
+ export declare function createWidgetActionsRouter(options: WidgetActionsRouterOptions): Router;
49
+ export {};
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { Router } from 'express';
7
+ import { z } from 'zod';
8
+ const WidgetActionSchema = z.discriminatedUnion('action', [
9
+ z.object({
10
+ action: z.literal('credential_saved'),
11
+ connection_name: z.string().min(1),
12
+ }),
13
+ z.object({
14
+ action: z.literal('approved'),
15
+ resource_type: z.string().min(1),
16
+ preview_id: z.string().min(1),
17
+ }),
18
+ ]);
19
+ /**
20
+ * Construct the synthetic user message for a widget action.
21
+ * The chat widget sends this as a follow-up user message so the
22
+ * agent knows the user acted on the widget.
23
+ */
24
+ export function buildSyntheticMessage(action) {
25
+ if (action.action === 'credential_saved') {
26
+ return `Credentials for ${action.connection_name} have been saved.`;
27
+ }
28
+ return `I've approved the ${action.resource_type} '${action.preview_id}'.`;
29
+ }
30
+ /**
31
+ * POST /chat/sessions/:session_id/widget-action
32
+ *
33
+ * Accepts user actions from input widgets (credential-input, document-preview).
34
+ * Validates the action and returns a synthetic message that the chat widget
35
+ * should send as a follow-up user message.
36
+ */
37
+ export function createWidgetActionsRouter(options) {
38
+ const router = Router();
39
+ router.post('/chat/sessions/:session_id/widget-action', (req, res, next) => {
40
+ try {
41
+ const sessionId = req.params['session_id'];
42
+ if (!sessionId) {
43
+ res.status(400).json({
44
+ error: { code: 'MISSING_SESSION_ID', message: 'session_id is required' },
45
+ });
46
+ return;
47
+ }
48
+ const parsed = WidgetActionSchema.safeParse(req.body);
49
+ if (!parsed.success) {
50
+ res.status(400).json({
51
+ error: {
52
+ code: 'INVALID_ACTION',
53
+ message: parsed.error.errors.map((e) => e.message).join(', '),
54
+ },
55
+ });
56
+ return;
57
+ }
58
+ // Verify session exists
59
+ const session = options.sessionManager.get(sessionId);
60
+ if (!session) {
61
+ res.status(404).json({
62
+ error: { code: 'SESSION_NOT_FOUND', message: `Session '${sessionId}' not found` },
63
+ });
64
+ return;
65
+ }
66
+ const syntheticMessage = buildSyntheticMessage(parsed.data);
67
+ res.json({
68
+ ok: true,
69
+ message: syntheticMessage,
70
+ });
71
+ }
72
+ catch (err) {
73
+ next(err);
74
+ }
75
+ });
76
+ return router;
77
+ }
78
+ //# sourceMappingURL=widget-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-actions.js","sourceRoot":"","sources":["../../../src/routes/widget-actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import type { Express } from 'express';
7
+ import type http from 'node:http';
8
+ import type { ConfigParameters } from '@amodalai/core';
9
+ import type { ServerConfig } from './types.js';
10
+ export interface ServerInstance {
11
+ app: Express;
12
+ start: () => Promise<http.Server>;
13
+ stop: () => Promise<void>;
14
+ }
15
+ export interface CreateServerOptions {
16
+ /** Base ConfigParameters for session creation */
17
+ baseParams: Partial<ConfigParameters>;
18
+ /** Server configuration */
19
+ config: ServerConfig;
20
+ /** Version string for /version endpoint */
21
+ version?: string;
22
+ /** Platform API URL for API key validation (if set, enables auth middleware) */
23
+ platformApiUrl?: string;
24
+ /** JWKS URL for JWT verification (defaults to platformApiUrl/.well-known/jwks.json) */
25
+ jwksUrl?: string;
26
+ }
27
+ /**
28
+ * Create the Express server with all routes, session management,
29
+ * automation scheduling, and graceful shutdown.
30
+ */
31
+ export declare function createServer(options: CreateServerOptions): ServerInstance;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import express from 'express';
7
+ import { errorHandler } from './middleware/error-handler.js';
8
+ import { createAuthMiddleware } from './middleware/auth.js';
9
+ import { createHealthRouter } from './routes/health.js';
10
+ import { createChatRouter } from './routes/chat.js';
11
+ import { createChatStreamRouter } from './routes/chat-stream.js';
12
+ import { createWebhookRouter } from './routes/webhooks.js';
13
+ import { createWidgetActionsRouter } from './routes/widget-actions.js';
14
+ import { createAskUserResponseRouter } from './routes/ask-user-response.js';
15
+ import { createSessionsRouter } from './routes/sessions.js';
16
+ import { createAIStreamRouter } from './routes/ai-stream.js';
17
+ import { SessionManager } from './session/session-manager.js';
18
+ import { createAutomationRunner } from './cron/heartbeat-runner.js';
19
+ import { AutomationScheduler } from './cron/heartbeat-scheduler.js';
20
+ import { AuditClient } from './audit/audit-client.js';
21
+ /**
22
+ * Create the Express server with all routes, session management,
23
+ * automation scheduling, and graceful shutdown.
24
+ */
25
+ export function createServer(options) {
26
+ const { baseParams, config } = options;
27
+ const startedAt = Date.now();
28
+ // --- Session management ---
29
+ const sessionManager = new SessionManager({
30
+ baseParams,
31
+ ttlMs: config.sessionTtlMs,
32
+ platformApiUrl: options.platformApiUrl,
33
+ });
34
+ // --- Audit client (batching HTTP poster to platform API) ---
35
+ const auditClient = options.platformApiUrl
36
+ ? new AuditClient({ platformApiUrl: options.platformApiUrl })
37
+ : undefined;
38
+ // --- Automation runner ---
39
+ const runAutomation = createAutomationRunner({ sessionManager, auditClient });
40
+ // --- Automation scheduler (cron) ---
41
+ const automationScheduler = new AutomationScheduler();
42
+ // --- Express app ---
43
+ const app = express();
44
+ // CORS middleware
45
+ const corsOrigin = config.corsOrigin ?? '*';
46
+ app.use((_req, res, next) => {
47
+ res.header('Access-Control-Allow-Origin', corsOrigin);
48
+ res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
49
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
50
+ res.header('Access-Control-Expose-Headers', 'x-vercel-ai-ui-message-stream');
51
+ if (_req.method === 'OPTIONS') {
52
+ res.sendStatus(204);
53
+ return;
54
+ }
55
+ next();
56
+ });
57
+ app.use(express.json());
58
+ // Routes
59
+ app.use(createHealthRouter({
60
+ sessionManager,
61
+ version: options.version,
62
+ startedAt,
63
+ }));
64
+ // Auth middleware for chat routes (if platform API URL is configured)
65
+ if (options.platformApiUrl) {
66
+ const authMiddleware = createAuthMiddleware({
67
+ platformApiUrl: options.platformApiUrl,
68
+ jwksUrl: options.jwksUrl,
69
+ });
70
+ app.use('/chat', authMiddleware);
71
+ app.use('/chat/stream', authMiddleware);
72
+ app.use('/sessions', authMiddleware);
73
+ }
74
+ app.use(createChatRouter({ sessionManager, auditClient }));
75
+ app.use(createChatStreamRouter({ sessionManager, auditClient, platformApiUrl: options.platformApiUrl }));
76
+ app.use(createAIStreamRouter({ sessionManager, auditClient, platformApiUrl: options.platformApiUrl }));
77
+ app.use(createWidgetActionsRouter({ sessionManager }));
78
+ app.use(createAskUserResponseRouter({ sessionManager }));
79
+ // Session history proxy routes (requires platform API URL)
80
+ if (options.platformApiUrl) {
81
+ app.use(createSessionsRouter({ platformApiUrl: options.platformApiUrl }));
82
+ }
83
+ app.use(createWebhookRouter({
84
+ automations: config.automations,
85
+ runAutomation,
86
+ }));
87
+ // Error handler (must be last)
88
+ app.use(errorHandler);
89
+ let server = null;
90
+ return {
91
+ app,
92
+ async start() {
93
+ // Start cron automations
94
+ automationScheduler.start(config.automations, runAutomation);
95
+ return new Promise((resolve) => {
96
+ const httpServer = app.listen(config.port, config.host, () => {
97
+ process.stderr.write(`[INFO] Server listening on ${config.host}:${config.port}\n`);
98
+ resolve(httpServer);
99
+ });
100
+ server = httpServer;
101
+ });
102
+ },
103
+ async stop() {
104
+ // Stop cron jobs
105
+ automationScheduler.stop();
106
+ // Close HTTP server
107
+ if (server) {
108
+ const s = server;
109
+ await new Promise((resolve, reject) => {
110
+ s.close((err) => {
111
+ if (err)
112
+ reject(err);
113
+ else
114
+ resolve();
115
+ });
116
+ });
117
+ server = null;
118
+ }
119
+ // Drain audit entries
120
+ if (auditClient) {
121
+ await auditClient.shutdown();
122
+ }
123
+ // Drain sessions
124
+ await sessionManager.shutdown();
125
+ process.stderr.write('[INFO] Server stopped\n');
126
+ },
127
+ };
128
+ }
129
+ //# sourceMappingURL=server.js.map