draken 0.1.6 → 0.2.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 (301) hide show
  1. package/ACCEPTANCE.md +31 -0
  2. package/CHANGELOG.md +33 -0
  3. package/CONTRIBUTING.md +129 -0
  4. package/MEMORY.md +98 -0
  5. package/PERSONA.md +67 -0
  6. package/README.md +156 -78
  7. package/SETUP.md +111 -0
  8. package/SOURCES.md +75 -0
  9. package/TRAY.md +54 -0
  10. package/VOICE.md +118 -0
  11. package/dist/auth/middleware.d.ts +3 -1
  12. package/dist/auth/middleware.d.ts.map +1 -1
  13. package/dist/auth/middleware.js +20 -15
  14. package/dist/auth/middleware.js.map +1 -1
  15. package/dist/cli.js +77 -113
  16. package/dist/cli.js.map +1 -1
  17. package/dist/db/agent-migration.d.ts +7 -0
  18. package/dist/db/agent-migration.d.ts.map +1 -0
  19. package/dist/db/agent-migration.js +36 -0
  20. package/dist/db/agent-migration.js.map +1 -0
  21. package/dist/db/evidence.d.ts +37 -0
  22. package/dist/db/evidence.d.ts.map +1 -0
  23. package/dist/db/evidence.js +110 -0
  24. package/dist/db/evidence.js.map +1 -0
  25. package/dist/db/pointer-migration.d.ts +7 -0
  26. package/dist/db/pointer-migration.d.ts.map +1 -0
  27. package/dist/db/pointer-migration.js +117 -0
  28. package/dist/db/pointer-migration.js.map +1 -0
  29. package/dist/db/retained-text.d.ts +8 -0
  30. package/dist/db/retained-text.d.ts.map +1 -0
  31. package/dist/db/retained-text.js +36 -0
  32. package/dist/db/retained-text.js.map +1 -0
  33. package/dist/db/schema.d.ts +1 -5
  34. package/dist/db/schema.d.ts.map +1 -1
  35. package/dist/db/schema.js +200 -55
  36. package/dist/db/schema.js.map +1 -1
  37. package/dist/db/snapshot-pointers.d.ts +5 -0
  38. package/dist/db/snapshot-pointers.d.ts.map +1 -0
  39. package/dist/db/snapshot-pointers.js +174 -0
  40. package/dist/db/snapshot-pointers.js.map +1 -0
  41. package/dist/memory/automatic.d.ts +38 -0
  42. package/dist/memory/automatic.d.ts.map +1 -0
  43. package/dist/memory/automatic.js +155 -0
  44. package/dist/memory/automatic.js.map +1 -0
  45. package/dist/memory/context.d.ts +12 -0
  46. package/dist/memory/context.d.ts.map +1 -0
  47. package/dist/memory/context.js +59 -0
  48. package/dist/memory/context.js.map +1 -0
  49. package/dist/memory/embedding-pool.d.ts +28 -0
  50. package/dist/memory/embedding-pool.d.ts.map +1 -0
  51. package/dist/memory/embedding-pool.js +135 -0
  52. package/dist/memory/embedding-pool.js.map +1 -0
  53. package/dist/memory/embedding-worker.d.ts +2 -0
  54. package/dist/memory/embedding-worker.d.ts.map +1 -0
  55. package/dist/memory/embedding-worker.js +32 -0
  56. package/dist/memory/embedding-worker.js.map +1 -0
  57. package/dist/memory/index.d.ts +26 -0
  58. package/dist/memory/index.d.ts.map +1 -0
  59. package/dist/memory/index.js +283 -0
  60. package/dist/memory/index.js.map +1 -0
  61. package/dist/memory/model.d.ts +15 -0
  62. package/dist/memory/model.d.ts.map +1 -0
  63. package/dist/memory/model.js +152 -0
  64. package/dist/memory/model.js.map +1 -0
  65. package/dist/memory/service.d.ts +8 -0
  66. package/dist/memory/service.d.ts.map +1 -0
  67. package/dist/memory/service.js +217 -0
  68. package/dist/memory/service.js.map +1 -0
  69. package/dist/memory/sources.d.ts +15 -0
  70. package/dist/memory/sources.d.ts.map +1 -0
  71. package/dist/memory/sources.js +87 -0
  72. package/dist/memory/sources.js.map +1 -0
  73. package/dist/memory/stamps.d.ts +13 -0
  74. package/dist/memory/stamps.d.ts.map +1 -0
  75. package/dist/memory/stamps.js +101 -0
  76. package/dist/memory/stamps.js.map +1 -0
  77. package/dist/memory/storage.d.ts +5 -0
  78. package/dist/memory/storage.d.ts.map +1 -0
  79. package/dist/memory/storage.js +107 -0
  80. package/dist/memory/storage.js.map +1 -0
  81. package/dist/memory/types.d.ts +68 -0
  82. package/dist/memory/types.d.ts.map +1 -0
  83. package/dist/memory/types.js +8 -0
  84. package/dist/memory/types.js.map +1 -0
  85. package/dist/memory/worker.d.ts +2 -0
  86. package/dist/memory/worker.d.ts.map +1 -0
  87. package/dist/memory/worker.js +82 -0
  88. package/dist/memory/worker.js.map +1 -0
  89. package/dist/npm-cli.d.ts +4 -0
  90. package/dist/npm-cli.d.ts.map +1 -0
  91. package/dist/npm-cli.js +36 -0
  92. package/dist/npm-cli.js.map +1 -0
  93. package/dist/pi/runtime.d.ts +34 -0
  94. package/dist/pi/runtime.d.ts.map +1 -0
  95. package/dist/pi/runtime.js +210 -0
  96. package/dist/pi/runtime.js.map +1 -0
  97. package/dist/pi/setup.d.ts +5 -0
  98. package/dist/pi/setup.d.ts.map +1 -0
  99. package/dist/pi/setup.js +147 -0
  100. package/dist/pi/setup.js.map +1 -0
  101. package/dist/routes/auth.d.ts.map +1 -1
  102. package/dist/routes/auth.js +3 -1
  103. package/dist/routes/auth.js.map +1 -1
  104. package/dist/routes/live-voice.d.ts +3 -0
  105. package/dist/routes/live-voice.d.ts.map +1 -0
  106. package/dist/routes/live-voice.js +49 -0
  107. package/dist/routes/live-voice.js.map +1 -0
  108. package/dist/routes/{browse.d.ts → memory.d.ts} +1 -1
  109. package/dist/routes/memory.d.ts.map +1 -0
  110. package/dist/routes/memory.js +18 -0
  111. package/dist/routes/memory.js.map +1 -0
  112. package/dist/routes/{tasks.d.ts → sync.d.ts} +1 -1
  113. package/dist/routes/sync.d.ts.map +1 -0
  114. package/dist/routes/sync.js +127 -0
  115. package/dist/routes/sync.js.map +1 -0
  116. package/dist/routes/{projects.d.ts → voice.d.ts} +1 -1
  117. package/dist/routes/voice.d.ts.map +1 -0
  118. package/dist/routes/voice.js +35 -0
  119. package/dist/routes/voice.js.map +1 -0
  120. package/dist/server-state.d.ts +30 -0
  121. package/dist/server-state.d.ts.map +1 -0
  122. package/dist/server-state.js +113 -0
  123. package/dist/server-state.js.map +1 -0
  124. package/dist/server-status.d.ts +7 -0
  125. package/dist/server-status.d.ts.map +1 -0
  126. package/dist/server-status.js +34 -0
  127. package/dist/server-status.js.map +1 -0
  128. package/dist/server.d.ts +5 -1
  129. package/dist/server.d.ts.map +1 -1
  130. package/dist/server.js +148 -46
  131. package/dist/server.js.map +1 -1
  132. package/dist/sources/adapters.d.ts +15 -0
  133. package/dist/sources/adapters.d.ts.map +1 -0
  134. package/dist/sources/adapters.js +159 -0
  135. package/dist/sources/adapters.js.map +1 -0
  136. package/dist/sources/registry.d.ts +17 -0
  137. package/dist/sources/registry.d.ts.map +1 -0
  138. package/dist/sources/registry.js +56 -0
  139. package/dist/sources/registry.js.map +1 -0
  140. package/dist/sync/collector.d.ts +3 -0
  141. package/dist/sync/collector.d.ts.map +1 -0
  142. package/dist/sync/collector.js +284 -0
  143. package/dist/sync/collector.js.map +1 -0
  144. package/dist/sync/cost.d.ts +7 -0
  145. package/dist/sync/cost.d.ts.map +1 -0
  146. package/dist/sync/cost.js +31 -0
  147. package/dist/sync/cost.js.map +1 -0
  148. package/dist/sync/jsonl.d.ts +34 -0
  149. package/dist/sync/jsonl.d.ts.map +1 -0
  150. package/dist/sync/jsonl.js +161 -0
  151. package/dist/sync/jsonl.js.map +1 -0
  152. package/dist/sync/manager.d.ts +12 -0
  153. package/dist/sync/manager.d.ts.map +1 -0
  154. package/dist/sync/manager.js +211 -0
  155. package/dist/sync/manager.js.map +1 -0
  156. package/dist/sync/normalize.d.ts +22 -0
  157. package/dist/sync/normalize.d.ts.map +1 -0
  158. package/dist/sync/normalize.js +107 -0
  159. package/dist/sync/normalize.js.map +1 -0
  160. package/dist/sync/pi-output.d.ts +33 -0
  161. package/dist/sync/pi-output.d.ts.map +1 -0
  162. package/dist/sync/pi-output.js +186 -0
  163. package/dist/sync/pi-output.js.map +1 -0
  164. package/dist/sync/pi.d.ts +15 -0
  165. package/dist/sync/pi.d.ts.map +1 -0
  166. package/dist/sync/pi.js +149 -0
  167. package/dist/sync/pi.js.map +1 -0
  168. package/dist/sync/recap.d.ts +25 -0
  169. package/dist/sync/recap.d.ts.map +1 -0
  170. package/dist/sync/recap.js +118 -0
  171. package/dist/sync/recap.js.map +1 -0
  172. package/dist/sync/references.d.ts +10 -0
  173. package/dist/sync/references.d.ts.map +1 -0
  174. package/dist/sync/references.js +50 -0
  175. package/dist/sync/references.js.map +1 -0
  176. package/dist/sync/source-files.d.ts +16 -0
  177. package/dist/sync/source-files.d.ts.map +1 -0
  178. package/dist/sync/source-files.js +56 -0
  179. package/dist/sync/source-files.js.map +1 -0
  180. package/dist/sync/store.d.ts +36 -0
  181. package/dist/sync/store.d.ts.map +1 -0
  182. package/dist/sync/store.js +359 -0
  183. package/dist/sync/store.js.map +1 -0
  184. package/dist/sync/summary-budget.d.ts +19 -0
  185. package/dist/sync/summary-budget.d.ts.map +1 -0
  186. package/dist/sync/summary-budget.js +39 -0
  187. package/dist/sync/summary-budget.js.map +1 -0
  188. package/dist/sync/tree.d.ts +69 -0
  189. package/dist/sync/tree.d.ts.map +1 -0
  190. package/dist/sync/tree.js +599 -0
  191. package/dist/sync/tree.js.map +1 -0
  192. package/dist/tray/controller.d.ts +51 -0
  193. package/dist/tray/controller.d.ts.map +1 -0
  194. package/dist/tray/controller.js +178 -0
  195. package/dist/tray/controller.js.map +1 -0
  196. package/dist/tray/launcher.d.ts +3 -0
  197. package/dist/tray/launcher.d.ts.map +1 -0
  198. package/dist/tray/launcher.js +47 -0
  199. package/dist/tray/launcher.js.map +1 -0
  200. package/dist/tray/native.d.ts +12 -0
  201. package/dist/tray/native.d.ts.map +1 -0
  202. package/dist/tray/native.js +93 -0
  203. package/dist/tray/native.js.map +1 -0
  204. package/dist/tray/processes.d.ts +5 -0
  205. package/dist/tray/processes.d.ts.map +1 -0
  206. package/dist/tray/processes.js +99 -0
  207. package/dist/tray/processes.js.map +1 -0
  208. package/dist/tray/worker.d.ts +4 -0
  209. package/dist/tray/worker.d.ts.map +1 -0
  210. package/dist/tray/worker.js +150 -0
  211. package/dist/tray/worker.js.map +1 -0
  212. package/dist/types.d.ts +212 -20
  213. package/dist/types.d.ts.map +1 -1
  214. package/dist/voice/continuation.d.ts +25 -0
  215. package/dist/voice/continuation.d.ts.map +1 -0
  216. package/dist/voice/continuation.js +94 -0
  217. package/dist/voice/continuation.js.map +1 -0
  218. package/dist/voice/legacy-history.d.ts +5 -0
  219. package/dist/voice/legacy-history.d.ts.map +1 -0
  220. package/dist/voice/legacy-history.js +34 -0
  221. package/dist/voice/legacy-history.js.map +1 -0
  222. package/dist/voice/live-context.d.ts +14 -0
  223. package/dist/voice/live-context.d.ts.map +1 -0
  224. package/dist/voice/live-context.js +137 -0
  225. package/dist/voice/live-context.js.map +1 -0
  226. package/dist/voice/live.d.ts +37 -0
  227. package/dist/voice/live.d.ts.map +1 -0
  228. package/dist/voice/live.js +448 -0
  229. package/dist/voice/live.js.map +1 -0
  230. package/package.json +49 -16
  231. package/public/assets/index-CYz_kpAp.js +126 -0
  232. package/public/assets/index-DmRid5xE.css +1 -0
  233. package/public/assets/index-Ymd62i3g.js +40 -0
  234. package/public/assets/persona-C_m1CVKe.css +1 -0
  235. package/public/assets/persona-XbLvCqRT.js +1 -0
  236. package/public/assets/scene-CBV2oPhA.js +3854 -0
  237. package/public/index.html +6 -8
  238. package/public/persona/THREE-LICENSE.txt +21 -0
  239. package/public/persona/call-poster.webp +0 -0
  240. package/public/persona/reference.jpg +0 -0
  241. package/public/persona/sample.wav +0 -0
  242. package/public/persona.html +7 -0
  243. package/runtime/pi/package-lock.json +1549 -0
  244. package/runtime/pi/package.json +12 -0
  245. package/tests/fixtures/voice-question.wav +0 -0
  246. package/tray/assets/error.ico +0 -0
  247. package/tray/assets/error.png +0 -0
  248. package/tray/assets/running.ico +0 -0
  249. package/tray/assets/running.png +0 -0
  250. package/tray/assets/starting.ico +0 -0
  251. package/tray/assets/starting.png +0 -0
  252. package/tray/assets/stopped.ico +0 -0
  253. package/tray/assets/stopped.png +0 -0
  254. package/tray/assets/stopping.ico +0 -0
  255. package/tray/assets/stopping.png +0 -0
  256. package/tray/macos.js +72 -0
  257. package/tray/windows.ps1 +104 -0
  258. package/voice/realtime/README.md +84 -0
  259. package/voice/realtime/backend.mjs +81 -0
  260. package/voice/realtime/native.mjs +210 -0
  261. package/voice/realtime/peer.d.mts +15 -0
  262. package/voice/realtime/peer.mjs +116 -0
  263. package/voice/realtime/probe-browser.mjs +81 -0
  264. package/voice/realtime/probe-server.mjs +86 -0
  265. package/voice/realtime/probe.html +11 -0
  266. package/voice/realtime/probe.mjs +42 -0
  267. package/voice/realtime/rpc.mjs +118 -0
  268. package/voice/realtime/setup.mjs +32 -0
  269. package/voice/tls.mjs +49 -0
  270. package/dist/db/queries.d.ts +0 -16
  271. package/dist/db/queries.d.ts.map +0 -1
  272. package/dist/db/queries.js +0 -91
  273. package/dist/db/queries.js.map +0 -1
  274. package/dist/docker/dockerfile.d.ts +0 -50
  275. package/dist/docker/dockerfile.d.ts.map +0 -1
  276. package/dist/docker/dockerfile.js +0 -160
  277. package/dist/docker/dockerfile.js.map +0 -1
  278. package/dist/docker/manager.d.ts +0 -42
  279. package/dist/docker/manager.d.ts.map +0 -1
  280. package/dist/docker/manager.js +0 -421
  281. package/dist/docker/manager.js.map +0 -1
  282. package/dist/git/status.d.ts +0 -76
  283. package/dist/git/status.d.ts.map +0 -1
  284. package/dist/git/status.js +0 -332
  285. package/dist/git/status.js.map +0 -1
  286. package/dist/routes/browse.d.ts.map +0 -1
  287. package/dist/routes/browse.js +0 -49
  288. package/dist/routes/browse.js.map +0 -1
  289. package/dist/routes/git.d.ts +0 -9
  290. package/dist/routes/git.d.ts.map +0 -1
  291. package/dist/routes/git.js +0 -338
  292. package/dist/routes/git.js.map +0 -1
  293. package/dist/routes/projects.d.ts.map +0 -1
  294. package/dist/routes/projects.js +0 -220
  295. package/dist/routes/projects.js.map +0 -1
  296. package/dist/routes/tasks.d.ts.map +0 -1
  297. package/dist/routes/tasks.js +0 -313
  298. package/dist/routes/tasks.js.map +0 -1
  299. package/draken.dockerfile.template +0 -18
  300. package/public/assets/index-3ngsG5kF.css +0 -1
  301. package/public/assets/index-B3YSD0ee.js +0 -252
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const schema_1 = require("../db/schema");
5
+ const runtime_1 = require("../pi/runtime");
6
+ const collector_1 = require("../sync/collector");
7
+ const store_1 = require("../sync/store");
8
+ const manager_1 = require("../sync/manager");
9
+ const automatic_1 = require("../memory/automatic");
10
+ const router = (0, express_1.Router)();
11
+ const route = (handler) => (req, res, next) => { Promise.resolve().then(() => handler(req, res)).catch(next); };
12
+ function id(req) {
13
+ const value = Number(req.params.id);
14
+ if (!Number.isSafeInteger(value) || value < 1)
15
+ throw new store_1.HttpError(400, 'Invalid sync ID');
16
+ return value;
17
+ }
18
+ function text(value, name, max = 4000) {
19
+ if (typeof value !== 'string' || value.length > max)
20
+ throw new store_1.HttpError(400, `${name} must be text of at most ${max} characters`);
21
+ return value.trim();
22
+ }
23
+ router.get('/setup', route(async (req, res) => {
24
+ if (Object.keys(req.query).some(key => key !== 'refresh') || (req.query.refresh !== undefined && req.query.refresh !== '1'))
25
+ throw new store_1.HttpError(400, 'Unknown setup status option');
26
+ res.json({ pi: await (0, runtime_1.piSetupStatus)(req.query.refresh === '1'), data_dir: (0, schema_1.getDataDir)() });
27
+ }));
28
+ router.get('/settings/auto-index', route((_req, res) => res.json((0, automatic_1.autoIndexSettings)())));
29
+ router.patch('/settings/auto-index', route((req, res) => {
30
+ if (!req.body || Array.isArray(req.body) || Object.keys(req.body).length !== 1 || !Object.hasOwn(req.body, 'enabled'))
31
+ throw new store_1.HttpError(400, 'Only enabled is accepted');
32
+ res.json((0, automatic_1.setAutoIndex)(req.body.enabled));
33
+ }));
34
+ router.use((req, _res, next) => { if (['POST', 'PATCH', 'DELETE'].includes(req.method))
35
+ (0, automatic_1.yieldBackgroundIndexing)(); next(); });
36
+ router.get('/home', route((req, res) => {
37
+ const before = req.query.before === undefined ? undefined : Number(req.query.before);
38
+ if (before !== undefined && (!Number.isSafeInteger(before) || before < 1))
39
+ throw new store_1.HttpError(400, 'Invalid history cursor');
40
+ res.json((0, store_1.homeOverview)(before));
41
+ }));
42
+ let starting = false;
43
+ router.post('/syncs/start-call', route(async (req, res) => {
44
+ const requestId = req.body?.request_id;
45
+ if (typeof requestId !== 'string' || !/^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/.test(requestId))
46
+ throw new store_1.HttpError(400, 'A request ID is required');
47
+ // One scan/start operation at a time, including the async indexing interval.
48
+ if (starting)
49
+ throw new store_1.HttpError(409, 'A sync is already being prepared');
50
+ const prior = (0, schema_1.getDb)().prepare('SELECT sync_id FROM sync_presentations WHERE request_id=?').get(requestId);
51
+ if (prior) {
52
+ res.status(202).json({ sync: (0, store_1.getSync)(prior.sync_id), scan: { files: 0, added: 0, warnings: [] } });
53
+ return;
54
+ }
55
+ if (store_1.busySyncs.size || store_1.activeVoiceSyncs.size)
56
+ throw new store_1.HttpError(409, 'End the active call or wait for preparation before starting another sync.');
57
+ starting = true;
58
+ try {
59
+ const setup = await (0, runtime_1.piSetupStatus)(true);
60
+ if (setup.state !== 'configured')
61
+ throw new store_1.HttpError(503, setup.message);
62
+ const scan = await (0, collector_1.scanSessions)(), sync = (0, store_1.startConversationSync)(requestId);
63
+ res.status(202).json({ sync: (0, manager_1.launchReply)(sync.id), scan });
64
+ }
65
+ finally {
66
+ starting = false;
67
+ }
68
+ }));
69
+ router.post('/syncs/:id/recap', route((req, res) => res.status(202).json((0, manager_1.launchRecap)(id(req)))));
70
+ router.get('/overview', route((_req, res) => res.json((0, store_1.overview)())));
71
+ router.patch('/agents/:agent', route((req, res) => {
72
+ if (!req.body || Array.isArray(req.body) || Object.keys(req.body).length !== 1 || typeof req.body.enabled !== 'boolean')
73
+ throw new store_1.HttpError(400, 'Only boolean enabled is accepted');
74
+ res.json((0, store_1.setAgentEnabled)(String(req.params.agent), req.body.enabled));
75
+ }));
76
+ router.post('/scan', route(async (_req, res) => res.json(await (0, collector_1.scanSessions)())));
77
+ router.patch('/sessions/:sessionId', route((req, res) => {
78
+ if (typeof req.body?.included !== 'boolean')
79
+ throw new store_1.HttpError(400, 'included must be a boolean');
80
+ (0, store_1.setIncluded)(String(req.params.sessionId), req.body.included);
81
+ res.json((0, store_1.overview)());
82
+ }));
83
+ router.post('/syncs', route(async (req, res) => {
84
+ const since = req.body?.history_since;
85
+ if (since !== undefined && since !== null && typeof since !== 'string')
86
+ throw new store_1.HttpError(400, 'history_since must be a date string or null');
87
+ const scan = await (0, collector_1.scanSessions)();
88
+ res.json({ sync: (0, store_1.startSync)(since), scan });
89
+ }));
90
+ router.get('/syncs/:id', route((req, res) => res.json((0, store_1.getSync)(id(req)))));
91
+ router.get('/syncs/:id/progress', route((req, res) => res.json((0, store_1.getProgress)(id(req)))));
92
+ router.get('/syncs/:id/tree/:key', route((req, res) => res.json((0, store_1.getTreeNode)(id(req), String(req.params.key)))));
93
+ router.post('/syncs/:id/expand', route(async (req, res) => {
94
+ const scan = await (0, collector_1.scanSessions)();
95
+ res.json({ sync: (0, store_1.expandSnapshot)(id(req)), scan });
96
+ }));
97
+ router.patch('/syncs/:id/models', route((req, res) => {
98
+ res.json((0, store_1.configureModels)(id(req), {
99
+ summary: text(req.body?.summary, 'Summary model', 200),
100
+ final: text(req.body?.final, 'Final model', 200),
101
+ max_invocations: req.body?.max_invocations,
102
+ }));
103
+ }));
104
+ router.post('/syncs/:id/cancel', route((req, res) => {
105
+ (0, manager_1.cancelReply)(id(req));
106
+ res.status(202).json((0, store_1.getProgress)(id(req)));
107
+ }));
108
+ router.patch('/syncs/:id/notes', route((req, res) => {
109
+ res.json((0, store_1.saveNotes)(id(req), text(req.body?.decisions, 'Decisions'), text(req.body?.carry_forward, 'Carry forward')));
110
+ }));
111
+ router.post('/syncs/:id/briefing', route((req, res) => {
112
+ res.status(202).json((0, manager_1.launchReply)(id(req)));
113
+ }));
114
+ router.post('/syncs/:id/messages', route((req, res) => {
115
+ const question = text(req.body?.message, 'Message');
116
+ if (!question)
117
+ throw new store_1.HttpError(400, 'Message cannot be empty');
118
+ if (Object.keys(req.body).some(key => key !== 'message'))
119
+ throw new store_1.HttpError(400, 'Unknown discussion option. Refresh the page.');
120
+ res.status(202).json((0, manager_1.launchReply)(id(req), question));
121
+ }));
122
+ router.post('/syncs/:id/complete', route((req, res) => {
123
+ res.json((0, store_1.completeSync)(id(req), text(req.body?.decisions, 'Decisions'), text(req.body?.carry_forward, 'Carry forward'), req.body?.reviewed === true));
124
+ }));
125
+ router.post('/syncs/:id/discard', route((req, res) => res.json((0, store_1.discardSync)(id(req)))));
126
+ exports.default = router;
127
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=projects.d.ts.map
3
+ //# sourceMappingURL=voice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../../src/routes/voice.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAsBxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = require("express");
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const crypto_1 = require("crypto");
9
+ const store_1 = require("../sync/store");
10
+ const legacy_history_1 = require("../voice/legacy-history");
11
+ const live_1 = require("../voice/live");
12
+ const live_voice_1 = __importDefault(require("./live-voice"));
13
+ const router = (0, express_1.Router)();
14
+ const route = (handler) => (req, res, next) => { Promise.resolve().then(() => handler(req, res)).catch(next); };
15
+ router.use('/live', live_voice_1.default);
16
+ router.get('/status', route(async (_req, res) => res.json({
17
+ ...await (0, live_1.liveStatus)(),
18
+ certificateAvailable: Boolean(process.env.DRAKEN_TLS_CA && fs_1.default.existsSync(process.env.DRAKEN_TLS_CA)),
19
+ })));
20
+ router.get('/certificate', route((_req, res) => {
21
+ if (!process.env.DRAKEN_TLS_CA)
22
+ throw new store_1.HttpError(404, 'No local certificate download is configured');
23
+ // Re-encode only the public certificate; never serve a key or an arbitrary source file.
24
+ const certificate = new crypto_1.X509Certificate(fs_1.default.readFileSync(process.env.DRAKEN_TLS_CA));
25
+ res.set({ 'Content-Type': 'application/x-x509-ca-cert', 'Content-Disposition': 'attachment; filename="draken-local-root.crt"', 'X-Content-Type-Options': 'nosniff' });
26
+ res.send(certificate.raw);
27
+ }));
28
+ router.get('/syncs/:syncId/history', route((req, res) => {
29
+ const syncId = Number(req.params.syncId);
30
+ if (!Number.isSafeInteger(syncId) || syncId < 1)
31
+ throw new store_1.HttpError(400, 'Invalid sync ID');
32
+ res.json([...(0, legacy_history_1.legacyCallHistory)(syncId), ...(0, live_1.liveHistory)(syncId)].sort((a, b) => b.started_at.localeCompare(a.started_at)).slice(0, 10));
33
+ }));
34
+ exports.default = router;
35
+ //# sourceMappingURL=voice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.js","sourceRoot":"","sources":["../../src/routes/voice.ts"],"names":[],"mappings":";;;;;AAAA,qCAAkE;AAClE,4CAAoB;AACpB,mCAAyC;AACzC,yCAA0C;AAC1C,4DAA4D;AAC5D,wCAAwD;AACxD,8DAAsC;AAEtC,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AACxB,MAAM,KAAK,GAAG,CAAC,OAAoE,EAAE,EAAE,CACrF,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAExH,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,oBAAU,CAAC,CAAC;AAChC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;IACxD,GAAG,MAAM,IAAA,iBAAU,GAAE;IACrB,oBAAoB,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;CACrG,CAAC,CAAC,CAAC,CAAC;AACL,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa;QAAE,MAAM,IAAI,iBAAS,CAAC,GAAG,EAAE,6CAA6C,CAAC,CAAC;IACxG,wFAAwF;IACxF,MAAM,WAAW,GAAG,IAAI,wBAAe,CAAC,YAAE,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IACpF,GAAG,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,8CAA8C,EAAE,wBAAwB,EAAE,SAAS,EAAE,CAAC,CAAC;IACtK,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC,CAAC;AACJ,MAAM,CAAC,GAAG,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,iBAAS,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IAC7F,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAA,kCAAiB,EAAC,MAAM,CAAC,EAAE,GAAG,IAAA,kBAAW,EAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACzI,CAAC,CAAC,CAAC,CAAC;AAEJ,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,30 @@
1
+ /** Last successful bind, not a claim that the process is still alive. Kept after
2
+ * shutdown so status can check the same address; a live instance match is required. */
3
+ export declare function rememberServer(instance: string, http: {
4
+ address: string;
5
+ port: number;
6
+ }, https?: {
7
+ address: string;
8
+ port: number;
9
+ }): {
10
+ url: string;
11
+ open: string;
12
+ instance: string;
13
+ };
14
+ /** Where a new server would bind with this process's environment, not saved state. */
15
+ export declare function configuredServerTarget(): {
16
+ url: string;
17
+ open: string;
18
+ instance: undefined;
19
+ };
20
+ export declare function recordedServerTarget(): {
21
+ url: string;
22
+ open: string;
23
+ instance: string;
24
+ } | undefined;
25
+ export declare function serverTarget(): {
26
+ url: string;
27
+ open: string;
28
+ instance: string | undefined;
29
+ };
30
+ //# sourceMappingURL=server-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-state.d.ts","sourceRoot":"","sources":["../src/server-state.ts"],"names":[],"mappings":"AAqDA;uFACuF;AACvF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;EAOlI;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB;;;;EAKrC;AAED,wBAAgB,oBAAoB;;;;cAGnC;AAED,wBAAgB,YAAY;;;;EAa3B"}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.rememberServer = rememberServer;
7
+ exports.configuredServerTarget = configuredServerTarget;
8
+ exports.recordedServerTarget = recordedServerTarget;
9
+ exports.serverTarget = serverTarget;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const net_1 = require("net");
13
+ const crypto_1 = require("crypto");
14
+ const schema_1 = require("./db/schema");
15
+ const stateFile = () => path_1.default.join((0, schema_1.getDataDir)(), 'server-state.json');
16
+ const idPattern = /^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/;
17
+ function endpoint(host, port, secure = false) {
18
+ if (!Number.isInteger(port) || port < 1 || port > 65535)
19
+ throw new Error('Invalid status port');
20
+ const local = host === '0.0.0.0' ? '127.0.0.1' : host === '::' ? '::1' : host;
21
+ const address = local.includes(':') && !local.startsWith('[') ? `[${local}]` : local;
22
+ const value = new URL(`${secure ? 'https' : 'http'}://${address}:${port}`);
23
+ if (value.username || value.password || value.pathname !== '/' || value.search || value.hash)
24
+ throw new Error('Invalid status address');
25
+ return value.origin;
26
+ }
27
+ function readState() {
28
+ let fd;
29
+ try {
30
+ if (fs_1.default.lstatSync(stateFile()).isSymbolicLink())
31
+ throw new Error('Invalid server record');
32
+ fd = fs_1.default.openSync(stateFile(), fs_1.default.constants.O_RDONLY | (fs_1.default.constants.O_NOFOLLOW || 0));
33
+ const stat = fs_1.default.fstatSync(fd);
34
+ if (!stat.isFile() || stat.size > 4096)
35
+ throw new Error('Invalid server record');
36
+ const bytes = Buffer.alloc(4097), length = fs_1.default.readSync(fd, bytes, 0, bytes.length, 0);
37
+ if (length > 4096)
38
+ throw new Error('Invalid server record');
39
+ const value = JSON.parse(bytes.subarray(0, length).toString('utf8'));
40
+ if (value.version !== 1 || typeof value.instance !== 'string' || !idPattern.test(value.instance) || !Number.isSafeInteger(value.pid) || value.pid < 1
41
+ || typeof value.started_at !== 'string' || !Number.isFinite(Date.parse(value.started_at)))
42
+ throw new Error('Invalid server record');
43
+ for (const [key, protocol] of [['http_url', 'http:'], ['https_url', 'https:']]) {
44
+ if (key === 'https_url' && value[key] === null)
45
+ continue;
46
+ if (typeof value[key] !== 'string' || value[key].length > 256)
47
+ throw new Error('Invalid server record');
48
+ const url = new URL(value[key]);
49
+ // Saved addresses come from the actual bound sockets, never arbitrary URLs
50
+ // or dashboard input. Explicit operator overrides may still use DNS names.
51
+ if (url.protocol !== protocol || url.port === '0' || !(0, net_1.isIP)(url.hostname.replace(/^\[|\]$/g, '')) || url.origin !== value[key])
52
+ throw new Error('Invalid server record');
53
+ }
54
+ return value;
55
+ }
56
+ catch (error) {
57
+ if (error.code === 'ENOENT')
58
+ return;
59
+ throw new Error('The saved server address is invalid. Check server-state.json in DRAKEN_DATA_DIR, or supply an explicit DRAKEN_HOST/DRAKEN_PORT override.');
60
+ }
61
+ finally {
62
+ if (fd !== undefined)
63
+ fs_1.default.closeSync(fd);
64
+ }
65
+ }
66
+ /** Last successful bind, not a claim that the process is still alive. Kept after
67
+ * shutdown so status can check the same address; a live instance match is required. */
68
+ function rememberServer(instance, http, https) {
69
+ const state = { version: 1, instance, pid: process.pid, http_url: endpoint(http.address, http.port),
70
+ https_url: https ? endpoint(https.address, https.port, true) : null, started_at: new Date().toISOString() };
71
+ const temp = path_1.default.join((0, schema_1.getDataDir)(), `.server-state-${(0, crypto_1.randomUUID)()}.tmp`);
72
+ try {
73
+ fs_1.default.writeFileSync(temp, JSON.stringify(state) + '\n', { mode: 0o600, flag: 'wx' });
74
+ fs_1.default.renameSync(temp, stateFile());
75
+ }
76
+ finally {
77
+ fs_1.default.rmSync(temp, { force: true });
78
+ }
79
+ return { url: state.http_url, open: state.https_url || state.http_url, instance };
80
+ }
81
+ /** Where a new server would bind with this process's environment, not saved state. */
82
+ function configuredServerTarget() {
83
+ const host = process.env.DRAKEN_HOST || '127.0.0.1';
84
+ const url = endpoint(host, Number(process.env.DRAKEN_PORT || 40333));
85
+ return { url, open: process.env.DRAKEN_HTTPS_PORT && process.env.DRAKEN_HTTPS_PORT !== '0'
86
+ ? endpoint(host, Number(process.env.DRAKEN_HTTPS_PORT), true) : url, instance: undefined };
87
+ }
88
+ function recordedServerTarget() {
89
+ const saved = readState();
90
+ return saved ? { url: saved.http_url, open: saved.https_url || saved.http_url, instance: saved.instance } : undefined;
91
+ }
92
+ function serverTarget() {
93
+ const explicit = Boolean(process.env.DRAKEN_HOST || process.env.DRAKEN_PORT);
94
+ let saved;
95
+ try {
96
+ saved = readState();
97
+ }
98
+ catch (error) {
99
+ if (!explicit)
100
+ throw error;
101
+ }
102
+ if (explicit) {
103
+ const last = saved && new URL(saved.http_url);
104
+ const host = process.env.DRAKEN_HOST || last?.hostname || '127.0.0.1';
105
+ const port = Number(process.env.DRAKEN_PORT || last?.port || (last ? '80' : '40333'));
106
+ const url = endpoint(host, port), same = url === saved?.http_url;
107
+ return { url, open: same ? saved.https_url || url : url, instance: same ? saved.instance : undefined };
108
+ }
109
+ if (saved)
110
+ return { url: saved.http_url, open: saved.https_url || saved.http_url, instance: saved.instance };
111
+ return { url: 'http://127.0.0.1:40333', open: 'http://127.0.0.1:40333', instance: undefined };
112
+ }
113
+ //# sourceMappingURL=server-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-state.js","sourceRoot":"","sources":["../src/server-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { serverTarget } from './server-state';
2
+ export type ServerTarget = ReturnType<typeof serverTarget>;
3
+ /** Connectivity only. Never obtains credentials, follows redirects, or calls models. */
4
+ export declare function probeServer(target: ServerTarget): Promise<{
5
+ instance?: string;
6
+ }>;
7
+ //# sourceMappingURL=server-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-status.d.ts","sourceRoot":"","sources":["../src/server-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AAE3D,wFAAwF;AACxF,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBtF"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.probeServer = probeServer;
4
+ /** Connectivity only. Never obtains credentials, follows redirects, or calls models. */
5
+ async function probeServer(target) {
6
+ const response = await fetch(target.url + '/api/auth/status', { signal: AbortSignal.timeout(2500), redirect: 'error' });
7
+ if (!response.ok || !response.body) {
8
+ await response.body?.cancel();
9
+ throw new Error('Server did not respond as Draken');
10
+ }
11
+ const reader = response.body.getReader(), chunks = [];
12
+ let size = 0;
13
+ try {
14
+ for (;;) {
15
+ const part = await reader.read();
16
+ if (part.done)
17
+ break;
18
+ size += part.value.byteLength;
19
+ if (size > 8192)
20
+ throw new Error('Oversized server status');
21
+ chunks.push(part.value);
22
+ }
23
+ const identity = JSON.parse(Buffer.concat(chunks).toString('utf8'));
24
+ if (identity.application !== 'draken')
25
+ throw new Error('Server did not respond as Draken');
26
+ if (target.instance && identity.instance !== target.instance)
27
+ throw new Error('Different server instance');
28
+ return { instance: typeof identity.instance === 'string' ? identity.instance : undefined };
29
+ }
30
+ finally {
31
+ await reader.cancel().catch(() => { });
32
+ }
33
+ }
34
+ //# sourceMappingURL=server-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-status.js","sourceRoot":"","sources":["../src/server-status.ts"],"names":[],"mappings":";;AAKA,kCAgBC;AAjBD,wFAAwF;AACjF,KAAK,UAAU,WAAW,CAAC,MAAoB;IACpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,GAAG,kBAAkB,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACxH,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAAC,CAAC;IAC3H,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,GAAiB,EAAE,CAAC;IAAC,IAAI,IAAI,GAAG,CAAC,CAAC;IAClF,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAAC,IAAI,IAAI,CAAC,IAAI;gBAAE,MAAM;YACvD,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;YAC9B,IAAI,IAAI,GAAG,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACpE,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC3F,IAAI,MAAM,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3G,OAAO,EAAE,QAAQ,EAAE,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IAC7F,CAAC;YAAS,CAAC;QAAC,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAAC,CAAC;AACtD,CAAC"}
package/dist/server.d.ts CHANGED
@@ -1,2 +1,6 @@
1
- export {};
1
+ export declare function createApp(options?: {
2
+ staticDir?: string;
3
+ instanceId?: string;
4
+ }): import("express-serve-static-core").Express;
5
+ export declare function startServer(trayOwned?: boolean): void;
2
6
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAoBA,wBAAgB,SAAS,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,+CAkClF;AAED,wBAAgB,WAAW,CAAC,SAAS,UAAQ,GAAG,IAAI,CA8DnD"}
package/dist/server.js CHANGED
@@ -3,58 +3,160 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createApp = createApp;
7
+ exports.startServer = startServer;
6
8
  const express_1 = __importDefault(require("express"));
7
9
  const path_1 = __importDefault(require("path"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const https_1 = __importDefault(require("https"));
12
+ const crypto_1 = require("crypto");
13
+ const server_state_1 = require("./server-state");
8
14
  const schema_1 = require("./db/schema");
9
15
  const middleware_1 = require("./auth/middleware");
10
- const manager_1 = require("./docker/manager");
11
16
  const auth_1 = __importDefault(require("./routes/auth"));
12
- const projects_1 = __importDefault(require("./routes/projects"));
13
- const tasks_1 = __importDefault(require("./routes/tasks"));
14
- const browse_1 = __importDefault(require("./routes/browse"));
15
- const git_1 = __importDefault(require("./routes/git"));
16
- const PORT = 40333;
17
- // Validate configurations early - will throw if required vars are missing
18
- try {
19
- // Validate Draken web auth (DRAKEN_USERNAME, DRAKEN_PASSWORD, DRAKEN_JWT_SECRET)
17
+ const sync_1 = __importDefault(require("./routes/sync"));
18
+ const memory_1 = __importDefault(require("./routes/memory"));
19
+ const service_1 = require("./memory/service");
20
+ const automatic_1 = require("./memory/automatic");
21
+ const voice_1 = __importDefault(require("./routes/voice"));
22
+ const legacy_history_1 = require("./voice/legacy-history");
23
+ const live_1 = require("./voice/live");
24
+ const store_1 = require("./sync/store");
25
+ const manager_1 = require("./sync/manager");
26
+ const runtime_1 = require("./pi/runtime");
27
+ function createApp(options = {}) {
28
+ const app = (0, express_1.default)();
29
+ app.locals.drakenInstance = options.instanceId;
30
+ const staticDir = options.staticDir || path_1.default.join(__dirname, '../public');
31
+ app.disable('x-powered-by');
32
+ app.use(express_1.default.json({ limit: '32kb' }));
33
+ app.use('/api', (req, res, next) => {
34
+ // This local application exposes private transcripts. No cross-origin API access.
35
+ if (req.headers.origin) {
36
+ try {
37
+ if (new URL(req.headers.origin).host !== req.headers.host)
38
+ return res.status(403).json({ error: 'Cross-origin requests are not allowed' });
39
+ }
40
+ catch {
41
+ return res.status(403).json({ error: 'Invalid origin' });
42
+ }
43
+ }
44
+ if (req.headers['sec-fetch-site'] === 'cross-site')
45
+ return res.status(403).json({ error: 'Cross-site requests are not allowed' });
46
+ if ((0, middleware_1.isNoAuthMode)()) {
47
+ const hostname = (req.headers.host || '').replace(/:\d+$/, '');
48
+ if (!['localhost', '127.0.0.1', '[::1]'].includes(hostname))
49
+ return res.status(403).json({ error: 'Local mode requires a loopback host' });
50
+ }
51
+ res.setHeader('Cache-Control', 'no-store');
52
+ next();
53
+ });
54
+ app.use('/api/auth', auth_1.default);
55
+ app.use('/api/voice', middleware_1.authMiddleware, voice_1.default);
56
+ app.use('/api/memory', middleware_1.authMiddleware, memory_1.default);
57
+ app.use('/api', middleware_1.authMiddleware, sync_1.default);
58
+ app.use('/api', (_req, res) => res.status(404).json({ error: 'API route not found' }));
59
+ app.use(express_1.default.static(staticDir));
60
+ app.get('*', (_req, res) => res.sendFile(path_1.default.join(staticDir, 'index.html')));
61
+ app.use((error, _req, res, _next) => {
62
+ const status = error instanceof store_1.HttpError ? error.status : error.status === 400 || error.status === 413 ? error.status : 500;
63
+ if (status === 500)
64
+ console.error('Draken request failed:', error.message);
65
+ res.status(status).json({ error: status === 500 ? 'Internal error. See the local server log.' : error.message });
66
+ });
67
+ return app;
68
+ }
69
+ function startServer(trayOwned = false) {
70
+ if (trayOwned && (!process.send || !process.connected))
71
+ throw new Error('The tray launcher disconnected. No server was started.');
20
72
  (0, middleware_1.validateAuthConfig)();
21
- // Validate Claude auth (OAuth credentials or ANTHROPIC_API_KEY)
22
- (0, manager_1.validateClaudeAuth)();
73
+ (0, live_1.validateVoiceConfig)();
74
+ const host = process.env.DRAKEN_HOST || '127.0.0.1';
75
+ const port = Number(process.env.DRAKEN_PORT || 40333);
76
+ if (!Number.isInteger(port) || port < 1 || port > 65535)
77
+ throw new Error('DRAKEN_PORT must be between 1 and 65535');
78
+ if ((0, middleware_1.isNoAuthMode)() && !(0, middleware_1.isLoopbackHost)(host)) {
79
+ throw new Error('No-auth mode may only bind to loopback. Configure authentication before exposing Draken.');
80
+ }
81
+ const httpsPort = Number(process.env.DRAKEN_HTTPS_PORT || 0);
82
+ if (!Number.isInteger(httpsPort) || httpsPort < 0 || httpsPort > 65535 || (httpsPort !== 0 && httpsPort === port))
83
+ throw new Error('DRAKEN_HTTPS_PORT must be a different valid port');
84
+ const tls = httpsPort ? { cert: fs_1.default.readFileSync(process.env.DRAKEN_TLS_CERT || ''), key: fs_1.default.readFileSync(process.env.DRAKEN_TLS_KEY || '') } : null;
85
+ // Bind before recovery: a second launch on an occupied port must not mark the
86
+ // actual server's active runs/calls interrupted or mutate its database.
87
+ let ready = false, listening = 0, stopping = false;
88
+ const instanceId = (0, crypto_1.randomUUID)();
89
+ const app = (0, express_1.default)();
90
+ app.use((_req, res, next) => ready ? next() : res.status(503).json({ error: 'Draken is starting or stopping.' }));
91
+ app.use(createApp({ instanceId }));
92
+ const bound = () => {
93
+ if (++listening !== (tls ? 2 : 1) || stopping)
94
+ return;
95
+ try {
96
+ (0, schema_1.getDb)();
97
+ (0, store_1.recoverInterruptedRuns)();
98
+ (0, legacy_history_1.recoverLegacyCalls)();
99
+ (0, live_1.recoverLiveCalls)();
100
+ const httpAddress = server.address(), secureAddress = secureServer?.address();
101
+ if (!httpAddress || typeof httpAddress === 'string' || typeof secureAddress === 'string')
102
+ throw new Error('Cannot record the listening address');
103
+ const target = (0, server_state_1.rememberServer)(instanceId, httpAddress, secureAddress || undefined);
104
+ ready = true;
105
+ if (trayOwned)
106
+ process.send({ type: 'draken-ready', target }, error => { if (error)
107
+ shutdown(1); });
108
+ const display = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
109
+ console.log(`Draken sync running at http://${display}:${port}`);
110
+ if (tls)
111
+ console.log(`Draken voice page: https://${display}:${httpsPort}`);
112
+ console.log((trayOwned ? 'Managed by Draken tray. Use its menu to stop the server; closing the browser does not.\n' : 'Keep this terminal open. Ctrl+C stops the server; closing the browser does not.\n') + 'First use / missing pi: draken setup → draken login (inside pi, type /login, then /quit).\nAlready have pi? Keep your configured installation; draken doctor checks summary setup.\nVoice: draken voice setup → draken voice login (separate ChatGPT sign-in).\nUse the same server user and environment for these commands. Select history in Settings → Agents & sessions, then Sync with Draken.\nCheck server connectivity with draken status. No startup login, model download, provider call or microphone capture is performed.');
113
+ (0, automatic_1.startBackgroundIndexing)();
114
+ }
115
+ catch (error) {
116
+ console.error(error instanceof Error ? error.message : 'Draken startup failed');
117
+ shutdown(1);
118
+ }
119
+ };
120
+ const secureServer = tls ? https_1.default.createServer(tls, app).listen(httpsPort, host, bound) : null;
121
+ const server = app.listen(port, host, bound);
122
+ const shutdown = (code = 0) => {
123
+ if (stopping)
124
+ return;
125
+ stopping = true;
126
+ ready = false;
127
+ const backgroundStopped = (0, automatic_1.stopBackgroundIndexing)();
128
+ (0, manager_1.stopManagerProcesses)();
129
+ (0, service_1.stopHistory)();
130
+ secureServer?.close();
131
+ const closed = new Promise(resolve => server.close(() => resolve()));
132
+ void Promise.all([closed, (0, live_1.stopLiveCalls)(), backgroundStopped, (0, runtime_1.stopPiChecks)()]).finally(() => { (0, schema_1.closeDb)(); process.exit(code); });
133
+ setTimeout(() => process.exit(code), 6500).unref();
134
+ };
135
+ const failed = (error) => {
136
+ console.error(error.code === 'EADDRINUSE' ? 'Draken could not bind: a configured port is already in use. Run draken status; do not start a second server.' : `Draken could not listen (${error.code || 'unknown error'}). Check the bind address, ports and server log.`);
137
+ shutdown(1);
138
+ };
139
+ server.once('error', failed);
140
+ secureServer?.once('error', failed);
141
+ if (trayOwned) {
142
+ // Only the owning child-process IPC channel can request this. There is no
143
+ // HTTP shutdown endpoint, PID-file kill, or Windows forced termination.
144
+ process.on('message', (message) => {
145
+ if (message?.type === 'draken-shutdown' && message.instance === instanceId)
146
+ shutdown();
147
+ });
148
+ process.once('disconnect', () => shutdown());
149
+ }
150
+ process.once('SIGINT', () => shutdown());
151
+ process.once('SIGTERM', () => shutdown());
23
152
  }
24
- catch (err) {
25
- console.error('\n' + err.message + '\n');
26
- process.exit(1);
153
+ if (require.main === module) {
154
+ try {
155
+ startServer();
156
+ }
157
+ catch (error) {
158
+ console.error(error instanceof Error ? error.message : error);
159
+ process.exitCode = 1;
160
+ }
27
161
  }
28
- const app = (0, express_1.default)();
29
- // Middleware
30
- app.use(express_1.default.json());
31
- app.use(express_1.default.static(path_1.default.join(__dirname, '../public')));
32
- // Auth routes (public - no auth required)
33
- app.use('/api/auth', auth_1.default);
34
- // Protected API Routes (auth required if configured)
35
- app.use('/api/projects', middleware_1.authMiddleware, projects_1.default);
36
- app.use('/api/tasks', middleware_1.authMiddleware, tasks_1.default);
37
- app.use('/api/browse', middleware_1.authMiddleware, browse_1.default);
38
- app.use('/api/git', middleware_1.authMiddleware, git_1.default);
39
- // Client-side routing - serve index.html for all non-API routes
40
- app.get('*', (req, res) => {
41
- res.sendFile(path_1.default.join(__dirname, '../public/index.html'));
42
- });
43
- // Initialize database
44
- (0, schema_1.getDb)();
45
- // Graceful shutdown
46
- process.on('SIGINT', () => {
47
- console.log('\nShutting down...');
48
- (0, schema_1.closeDb)();
49
- process.exit(0);
50
- });
51
- process.on('SIGTERM', () => {
52
- console.log('\nShutting down...');
53
- (0, schema_1.closeDb)();
54
- process.exit(0);
55
- });
56
- // Start server
57
- app.listen(PORT, () => {
58
- console.log(`Draken dashboard running at http://localhost:${PORT}`);
59
- });
60
162
  //# sourceMappingURL=server.js.map