whale-code 6.5.4 → 6.5.6

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 (853) hide show
  1. package/README.md +39 -31
  2. package/bin/{swagmanager-mcp.js → whale-code.js} +17 -2
  3. package/dist/cli/app.js +148 -72
  4. package/dist/cli/app.js.map +1 -0
  5. package/dist/cli/chat/AgentSelector.js +105 -10
  6. package/dist/cli/chat/AgentSelector.js.map +1 -0
  7. package/dist/cli/chat/ChatApp.d.ts +31 -0
  8. package/dist/cli/chat/ChatApp.js +539 -286
  9. package/dist/cli/chat/ChatApp.js.map +1 -0
  10. package/dist/cli/chat/ChatInput.js +1088 -770
  11. package/dist/cli/chat/ChatInput.js.map +1 -0
  12. package/dist/cli/chat/MarkdownText.js +39 -14
  13. package/dist/cli/chat/MarkdownText.js.map +1 -0
  14. package/dist/cli/chat/MemoryManager.js +181 -46
  15. package/dist/cli/chat/MemoryManager.js.map +1 -0
  16. package/dist/cli/chat/MessageList.d.ts +2 -3
  17. package/dist/cli/chat/MessageList.js +186 -45
  18. package/dist/cli/chat/MessageList.js.map +1 -0
  19. package/dist/cli/chat/ModelSelector.js +282 -63
  20. package/dist/cli/chat/ModelSelector.js.map +1 -0
  21. package/dist/cli/chat/NodeManager.js +165 -75
  22. package/dist/cli/chat/NodeManager.js.map +1 -0
  23. package/dist/cli/chat/NodeSelector.js +171 -30
  24. package/dist/cli/chat/NodeSelector.js.map +1 -0
  25. package/dist/cli/chat/PlanApproval.js +281 -57
  26. package/dist/cli/chat/PlanApproval.js.map +1 -0
  27. package/dist/cli/chat/RewindViewer.js +559 -144
  28. package/dist/cli/chat/RewindViewer.js.map +1 -0
  29. package/dist/cli/chat/SessionManager.js +137 -30
  30. package/dist/cli/chat/SessionManager.js.map +1 -0
  31. package/dist/cli/chat/SlashMenu.js +293 -164
  32. package/dist/cli/chat/SlashMenu.js.map +1 -0
  33. package/dist/cli/chat/StatusBar.js +172 -9
  34. package/dist/cli/chat/StatusBar.js.map +1 -0
  35. package/dist/cli/chat/StoreSelector.js +147 -18
  36. package/dist/cli/chat/StoreSelector.js.map +1 -0
  37. package/dist/cli/chat/StreamingText.d.ts +1 -5
  38. package/dist/cli/chat/StreamingText.js +22 -7
  39. package/dist/cli/chat/StreamingText.js.map +1 -0
  40. package/dist/cli/chat/SubagentPanel.d.ts +1 -2
  41. package/dist/cli/chat/SubagentPanel.js +612 -72
  42. package/dist/cli/chat/SubagentPanel.js.map +1 -0
  43. package/dist/cli/chat/TeamPanel.d.ts +1 -0
  44. package/dist/cli/chat/TeamPanel.js +230 -30
  45. package/dist/cli/chat/TeamPanel.js.map +1 -0
  46. package/dist/cli/chat/ThemeSelector.js +84 -24
  47. package/dist/cli/chat/ThemeSelector.js.map +1 -0
  48. package/dist/cli/chat/ToolIndicator.js +1476 -371
  49. package/dist/cli/chat/ToolIndicator.js.map +1 -0
  50. package/dist/cli/chat/hooks/useAgentLoop.d.ts +1 -0
  51. package/dist/cli/chat/hooks/useAgentLoop.js +481 -367
  52. package/dist/cli/chat/hooks/useAgentLoop.js.map +1 -0
  53. package/dist/cli/chat/hooks/useSlashCommands.d.ts +3 -14
  54. package/dist/cli/chat/hooks/useSlashCommands.js +744 -572
  55. package/dist/cli/chat/hooks/useSlashCommands.js.map +1 -0
  56. package/dist/cli/commands/config-cmd.js +56 -57
  57. package/dist/cli/commands/config-cmd.js.map +1 -0
  58. package/dist/cli/commands/db.js +184 -169
  59. package/dist/cli/commands/db.js.map +1 -0
  60. package/dist/cli/commands/doctor.js +212 -122
  61. package/dist/cli/commands/doctor.js.map +1 -0
  62. package/dist/cli/commands/init.js +211 -244
  63. package/dist/cli/commands/init.js.map +1 -0
  64. package/dist/cli/commands/mcp.js +127 -122
  65. package/dist/cli/commands/mcp.js.map +1 -0
  66. package/dist/cli/login/LoginApp.js +355 -141
  67. package/dist/cli/login/LoginApp.js.map +1 -0
  68. package/dist/cli/print-mode.js +196 -177
  69. package/dist/cli/print-mode.js.map +1 -0
  70. package/dist/cli/serve-mode.js +615 -530
  71. package/dist/cli/serve-mode.js.map +1 -0
  72. package/dist/cli/services/agent-config.d.ts +29 -0
  73. package/dist/cli/services/agent-config.js +91 -0
  74. package/dist/cli/services/agent-config.js.map +1 -0
  75. package/dist/cli/services/agent-definitions.d.ts +4 -1
  76. package/dist/cli/services/agent-definitions.js +97 -56
  77. package/dist/cli/services/agent-definitions.js.map +1 -0
  78. package/dist/cli/services/agent-events.js +225 -162
  79. package/dist/cli/services/agent-events.js.map +1 -0
  80. package/dist/cli/services/agent-loop.js +978 -669
  81. package/dist/cli/services/agent-loop.js.map +1 -0
  82. package/dist/cli/services/agent-worker-base.d.ts +35 -5
  83. package/dist/cli/services/agent-worker-base.js +337 -153
  84. package/dist/cli/services/agent-worker-base.js.map +1 -0
  85. package/dist/cli/services/api-retry.js +69 -64
  86. package/dist/cli/services/api-retry.js.map +1 -0
  87. package/dist/cli/services/auth-service.d.ts +3 -3
  88. package/dist/cli/services/auth-service.js +209 -132
  89. package/dist/cli/services/auth-service.js.map +1 -0
  90. package/dist/cli/services/background-processes.js +343 -267
  91. package/dist/cli/services/background-processes.js.map +1 -0
  92. package/dist/cli/services/browser-auth.d.ts +2 -2
  93. package/dist/cli/services/browser-auth.js +159 -118
  94. package/dist/cli/services/browser-auth.js.map +1 -0
  95. package/dist/cli/services/claude-md-loader.js +40 -36
  96. package/dist/cli/services/claude-md-loader.js.map +1 -0
  97. package/dist/cli/services/config-store.d.ts +9 -4
  98. package/dist/cli/services/config-store.js +164 -117
  99. package/dist/cli/services/config-store.js.map +1 -0
  100. package/dist/cli/services/debug-log.d.ts +1 -1
  101. package/dist/cli/services/debug-log.js +34 -35
  102. package/dist/cli/services/debug-log.js.map +1 -0
  103. package/dist/cli/services/env-detect.d.ts +7 -0
  104. package/dist/cli/services/env-detect.js +9 -0
  105. package/dist/cli/services/env-detect.js.map +1 -0
  106. package/dist/cli/services/error-logger.d.ts +2 -3
  107. package/dist/cli/services/error-logger.js +189 -180
  108. package/dist/cli/services/error-logger.js.map +1 -0
  109. package/dist/cli/services/file-history.d.ts +1 -1
  110. package/dist/cli/services/file-history.js +50 -54
  111. package/dist/cli/services/file-history.js.map +1 -0
  112. package/dist/cli/services/format-server-response.js +332 -372
  113. package/dist/cli/services/format-server-response.js.map +1 -0
  114. package/dist/cli/services/git-context.js +61 -45
  115. package/dist/cli/services/git-context.js.map +1 -0
  116. package/dist/cli/services/hooks.d.ts +2 -2
  117. package/dist/cli/services/hooks.js +195 -180
  118. package/dist/cli/services/hooks.js.map +1 -0
  119. package/dist/cli/services/ink-incremental.d.ts +19 -0
  120. package/dist/cli/services/ink-incremental.js +59 -0
  121. package/dist/cli/services/ink-incremental.js.map +1 -0
  122. package/dist/cli/services/ink-resize-fix.js +54 -44
  123. package/dist/cli/services/ink-resize-fix.js.map +1 -0
  124. package/dist/cli/services/ink-sync-output.d.ts +12 -0
  125. package/dist/cli/services/ink-sync-output.js +16 -0
  126. package/dist/cli/services/ink-sync-output.js.map +1 -0
  127. package/dist/cli/services/interactive-tools.js +268 -212
  128. package/dist/cli/services/interactive-tools.js.map +1 -0
  129. package/dist/cli/services/keybinding-manager.d.ts +11 -1
  130. package/dist/cli/services/keybinding-manager.js +126 -63
  131. package/dist/cli/services/keybinding-manager.js.map +1 -0
  132. package/dist/cli/services/local-tools.d.ts +1 -1
  133. package/dist/cli/services/local-tools.js +939 -656
  134. package/dist/cli/services/local-tools.js.map +1 -0
  135. package/dist/cli/services/lsp-manager.js +757 -594
  136. package/dist/cli/services/lsp-manager.js.map +1 -0
  137. package/dist/cli/services/mcp-client.d.ts +1 -1
  138. package/dist/cli/services/mcp-client.js +173 -134
  139. package/dist/cli/services/mcp-client.js.map +1 -0
  140. package/dist/cli/services/memory-manager.js +53 -40
  141. package/dist/cli/services/memory-manager.js.map +1 -0
  142. package/dist/cli/services/model-manager.js +55 -40
  143. package/dist/cli/services/model-manager.js.map +1 -0
  144. package/dist/cli/services/model-router.js +115 -85
  145. package/dist/cli/services/model-router.js.map +1 -0
  146. package/dist/cli/services/paths.d.ts +30 -0
  147. package/dist/cli/services/paths.js +81 -0
  148. package/dist/cli/services/paths.js.map +1 -0
  149. package/dist/cli/services/permission-modes.js +32 -25
  150. package/dist/cli/services/permission-modes.js.map +1 -0
  151. package/dist/cli/services/rewind.js +182 -168
  152. package/dist/cli/services/rewind.js.map +1 -0
  153. package/dist/cli/services/ripgrep.js +115 -115
  154. package/dist/cli/services/ripgrep.js.map +1 -0
  155. package/dist/cli/services/sandbox.d.ts +1 -1
  156. package/dist/cli/services/sandbox.js +58 -37
  157. package/dist/cli/services/sandbox.js.map +1 -0
  158. package/dist/cli/services/server-tools.js +738 -565
  159. package/dist/cli/services/server-tools.js.map +1 -0
  160. package/dist/cli/services/session-persistence.js +69 -74
  161. package/dist/cli/services/session-persistence.js.map +1 -0
  162. package/dist/cli/services/subagent-worker.js +42 -27
  163. package/dist/cli/services/subagent-worker.js.map +1 -0
  164. package/dist/cli/services/subagent.d.ts +2 -0
  165. package/dist/cli/services/subagent.js +606 -430
  166. package/dist/cli/services/subagent.js.map +1 -0
  167. package/dist/cli/services/system-prompt.js +86 -78
  168. package/dist/cli/services/system-prompt.js.map +1 -0
  169. package/dist/cli/services/task-decomposer.d.ts +1 -1
  170. package/dist/cli/services/task-decomposer.js +172 -139
  171. package/dist/cli/services/task-decomposer.js.map +1 -0
  172. package/dist/cli/services/team-lead.d.ts +2 -2
  173. package/dist/cli/services/team-lead.js +727 -529
  174. package/dist/cli/services/team-lead.js.map +1 -0
  175. package/dist/cli/services/team-state.js +319 -319
  176. package/dist/cli/services/team-state.js.map +1 -0
  177. package/dist/cli/services/teammate.d.ts +8 -2
  178. package/dist/cli/services/teammate.js +862 -560
  179. package/dist/cli/services/teammate.js.map +1 -0
  180. package/dist/cli/services/telemetry.d.ts +6 -1
  181. package/dist/cli/services/telemetry.js +180 -157
  182. package/dist/cli/services/telemetry.js.map +1 -0
  183. package/dist/cli/services/tools/agent-tools.d.ts +3 -3
  184. package/dist/cli/services/tools/agent-tools.js +480 -322
  185. package/dist/cli/services/tools/agent-tools.js.map +1 -0
  186. package/dist/cli/services/tools/file-ops.js +563 -450
  187. package/dist/cli/services/tools/file-ops.js.map +1 -0
  188. package/dist/cli/services/tools/search-tools.js +231 -162
  189. package/dist/cli/services/tools/search-tools.js.map +1 -0
  190. package/dist/cli/services/tools/shell-exec.js +197 -151
  191. package/dist/cli/services/tools/shell-exec.js.map +1 -0
  192. package/dist/cli/services/tools/task-manager.js +206 -173
  193. package/dist/cli/services/tools/task-manager.js.map +1 -0
  194. package/dist/cli/services/tools/web-tools.js +388 -341
  195. package/dist/cli/services/tools/web-tools.js.map +1 -0
  196. package/dist/cli/setup/SetupApp.d.ts +2 -2
  197. package/dist/cli/setup/SetupApp.js +608 -160
  198. package/dist/cli/setup/SetupApp.js.map +1 -0
  199. package/dist/cli/shared/ErrorBoundary.d.ts +22 -0
  200. package/dist/cli/shared/ErrorBoundary.js +73 -0
  201. package/dist/cli/shared/ErrorBoundary.js.map +1 -0
  202. package/dist/cli/shared/MatrixIntro.js +66 -69
  203. package/dist/cli/shared/MatrixIntro.js.map +1 -0
  204. package/dist/cli/shared/SpinnerSlot.d.ts +14 -0
  205. package/dist/cli/shared/SpinnerSlot.js +63 -0
  206. package/dist/cli/shared/SpinnerSlot.js.map +1 -0
  207. package/dist/cli/shared/Theme.d.ts +1 -1
  208. package/dist/cli/shared/Theme.js +136 -92
  209. package/dist/cli/shared/Theme.js.map +1 -0
  210. package/dist/cli/shared/WhaleBanner.js +99 -11
  211. package/dist/cli/shared/WhaleBanner.js.map +1 -0
  212. package/dist/cli/shared/markdown.d.ts +3 -1
  213. package/dist/cli/shared/markdown.js +736 -674
  214. package/dist/cli/shared/markdown.js.map +1 -0
  215. package/dist/cli/shared/marked-terminal.d.js +2 -0
  216. package/dist/cli/shared/marked-terminal.d.js.map +1 -0
  217. package/dist/cli/shared/theme-manager.js +99 -90
  218. package/dist/cli/shared/theme-manager.js.map +1 -0
  219. package/dist/cli/shared/theme-presets.js +256 -254
  220. package/dist/cli/shared/theme-presets.js.map +1 -0
  221. package/dist/cli/status/StatusApp.js +235 -86
  222. package/dist/cli/status/StatusApp.js.map +1 -0
  223. package/dist/cli/stores/StoreApp.js +275 -65
  224. package/dist/cli/stores/StoreApp.js.map +1 -0
  225. package/dist/index.d.ts +2 -2
  226. package/dist/index.js +509 -396
  227. package/dist/index.js.map +1 -0
  228. package/dist/local-agent/connection.d.ts +2 -2
  229. package/dist/local-agent/connection.js +352 -293
  230. package/dist/local-agent/connection.js.map +1 -0
  231. package/dist/local-agent/discovery.js +259 -122
  232. package/dist/local-agent/discovery.js.map +1 -0
  233. package/dist/local-agent/executor.js +216 -193
  234. package/dist/local-agent/executor.js.map +1 -0
  235. package/dist/local-agent/index.d.ts +2 -2
  236. package/dist/local-agent/index.js +156 -156
  237. package/dist/local-agent/index.js.map +1 -0
  238. package/dist/node/adapters/base.js +18 -8
  239. package/dist/node/adapters/base.js.map +1 -0
  240. package/dist/node/adapters/discord.js +286 -275
  241. package/dist/node/adapters/discord.js.map +1 -0
  242. package/dist/node/adapters/email.js +189 -202
  243. package/dist/node/adapters/email.js.map +1 -0
  244. package/dist/node/adapters/imessage.js +145 -142
  245. package/dist/node/adapters/imessage.js.map +1 -0
  246. package/dist/node/adapters/slack.js +237 -236
  247. package/dist/node/adapters/slack.js.map +1 -0
  248. package/dist/node/adapters/sms.js +149 -151
  249. package/dist/node/adapters/sms.js.map +1 -0
  250. package/dist/node/adapters/telegram.js +88 -92
  251. package/dist/node/adapters/telegram.js.map +1 -0
  252. package/dist/node/adapters/webchat.js +160 -136
  253. package/dist/node/adapters/webchat.js.map +1 -0
  254. package/dist/node/adapters/whatsapp.js +212 -215
  255. package/dist/node/adapters/whatsapp.js.map +1 -0
  256. package/dist/node/cli.js +884 -653
  257. package/dist/node/cli.js.map +1 -0
  258. package/dist/node/config.js +20 -18
  259. package/dist/node/config.js.map +1 -0
  260. package/dist/node/gateway-client.js +191 -181
  261. package/dist/node/gateway-client.js.map +1 -0
  262. package/dist/node/portal/clipboard.js +161 -130
  263. package/dist/node/portal/clipboard.js.map +1 -0
  264. package/dist/node/portal/discovery.js +51 -45
  265. package/dist/node/portal/discovery.js.map +1 -0
  266. package/dist/node/portal/forward.js +64 -58
  267. package/dist/node/portal/forward.js.map +1 -0
  268. package/dist/node/portal/index.js +246 -221
  269. package/dist/node/portal/index.js.map +1 -0
  270. package/dist/node/portal/multiplexer.js +192 -182
  271. package/dist/node/portal/multiplexer.js.map +1 -0
  272. package/dist/node/portal/permissions.js +102 -70
  273. package/dist/node/portal/permissions.js.map +1 -0
  274. package/dist/node/portal/protocol.js +153 -116
  275. package/dist/node/portal/protocol.js.map +1 -0
  276. package/dist/node/portal/screen.js +80 -69
  277. package/dist/node/portal/screen.js.map +1 -0
  278. package/dist/node/portal/session.js +124 -117
  279. package/dist/node/portal/session.js.map +1 -0
  280. package/dist/node/portal/shell.js +140 -113
  281. package/dist/node/portal/shell.js.map +1 -0
  282. package/dist/node/portal/stream.js +77 -75
  283. package/dist/node/portal/stream.js.map +1 -0
  284. package/dist/node/portal/transfer.js +190 -167
  285. package/dist/node/portal/transfer.js.map +1 -0
  286. package/dist/node/portal/ui.js +124 -99
  287. package/dist/node/portal/ui.js.map +1 -0
  288. package/dist/node/remote-desktop/compile-helper.js +50 -45
  289. package/dist/node/remote-desktop/compile-helper.js.map +1 -0
  290. package/dist/node/remote-desktop/index.js +215 -187
  291. package/dist/node/remote-desktop/index.js.map +1 -0
  292. package/dist/node/remote-desktop/protocol.js +45 -29
  293. package/dist/node/remote-desktop/protocol.js.map +1 -0
  294. package/dist/node/runtime.js +493 -410
  295. package/dist/node/runtime.js.map +1 -0
  296. package/dist/server/handlers/__test-utils__/test-db.js +39 -89
  297. package/dist/server/handlers/__test-utils__/test-db.js.map +1 -0
  298. package/dist/server/handlers/analytics.js +467 -261
  299. package/dist/server/handlers/analytics.js.map +1 -0
  300. package/dist/server/handlers/api-docs.d.ts +6 -0
  301. package/dist/server/handlers/api-docs.js +1613 -0
  302. package/dist/server/handlers/api-docs.js.map +1 -0
  303. package/dist/server/handlers/api-keys.js +295 -232
  304. package/dist/server/handlers/api-keys.js.map +1 -0
  305. package/dist/server/handlers/billing.js +330 -239
  306. package/dist/server/handlers/billing.js.map +1 -0
  307. package/dist/server/handlers/browser.js +468 -395
  308. package/dist/server/handlers/browser.js.map +1 -0
  309. package/dist/server/handlers/catalog.js +1377 -978
  310. package/dist/server/handlers/catalog.js.map +1 -0
  311. package/dist/server/handlers/clickhouse.js +157 -109
  312. package/dist/server/handlers/clickhouse.js.map +1 -0
  313. package/dist/server/handlers/comms.d.ts +0 -53
  314. package/dist/server/handlers/comms.js +1443 -970
  315. package/dist/server/handlers/comms.js.map +1 -0
  316. package/dist/server/handlers/creations.js +461 -394
  317. package/dist/server/handlers/creations.js.map +1 -0
  318. package/dist/server/handlers/crm.js +1082 -791
  319. package/dist/server/handlers/crm.js.map +1 -0
  320. package/dist/server/handlers/discovery.js +251 -232
  321. package/dist/server/handlers/discovery.js.map +1 -0
  322. package/dist/server/handlers/embeddings.js +241 -164
  323. package/dist/server/handlers/embeddings.js.map +1 -0
  324. package/dist/server/handlers/enrichment.js +887 -718
  325. package/dist/server/handlers/enrichment.js.map +1 -0
  326. package/dist/server/handlers/image-gen.js +467 -376
  327. package/dist/server/handlers/image-gen.js.map +1 -0
  328. package/dist/server/handlers/inventory.js +797 -424
  329. package/dist/server/handlers/inventory.js.map +1 -0
  330. package/dist/server/handlers/kali.js +272 -230
  331. package/dist/server/handlers/kali.js.map +1 -0
  332. package/dist/server/handlers/llm-providers.js +803 -580
  333. package/dist/server/handlers/llm-providers.js.map +1 -0
  334. package/dist/server/handlers/local-agent.js +133 -105
  335. package/dist/server/handlers/local-agent.js.map +1 -0
  336. package/dist/server/handlers/media.js +1179 -857
  337. package/dist/server/handlers/media.js.map +1 -0
  338. package/dist/server/handlers/meta-ads.js +2669 -2093
  339. package/dist/server/handlers/meta-ads.js.map +1 -0
  340. package/dist/server/handlers/nodes.js +1321 -913
  341. package/dist/server/handlers/nodes.js.map +1 -0
  342. package/dist/server/handlers/operations.js +183 -157
  343. package/dist/server/handlers/operations.js.map +1 -0
  344. package/dist/server/handlers/platform.js +346 -210
  345. package/dist/server/handlers/platform.js.map +1 -0
  346. package/dist/server/handlers/remove-bg.js +118 -86
  347. package/dist/server/handlers/remove-bg.js.map +1 -0
  348. package/dist/server/handlers/storefront.js +586 -446
  349. package/dist/server/handlers/storefront.js.map +1 -0
  350. package/dist/server/handlers/supply-chain.js +546 -326
  351. package/dist/server/handlers/supply-chain.js.map +1 -0
  352. package/dist/server/handlers/transcription.js +106 -97
  353. package/dist/server/handlers/transcription.js.map +1 -0
  354. package/dist/server/handlers/video-gen.js +593 -424
  355. package/dist/server/handlers/video-gen.js.map +1 -0
  356. package/dist/server/handlers/voice.js +1458 -1017
  357. package/dist/server/handlers/voice.js.map +1 -0
  358. package/dist/server/handlers/workflow-steps.js +2837 -2116
  359. package/dist/server/handlers/workflow-steps.js.map +1 -0
  360. package/dist/server/handlers/workflows.js +1630 -933
  361. package/dist/server/handlers/workflows.js.map +1 -0
  362. package/dist/server/index.js +3166 -2390
  363. package/dist/server/index.js.map +1 -0
  364. package/dist/server/lib/batch-client.js +471 -409
  365. package/dist/server/lib/batch-client.js.map +1 -0
  366. package/dist/server/lib/clickhouse-buffer.js +118 -104
  367. package/dist/server/lib/clickhouse-buffer.js.map +1 -0
  368. package/dist/server/lib/clickhouse-client.js +107 -107
  369. package/dist/server/lib/clickhouse-client.js.map +1 -0
  370. package/dist/server/lib/coa-renderer.js +1786 -356
  371. package/dist/server/lib/coa-renderer.js.map +1 -0
  372. package/dist/server/lib/code-worker-pool.js +227 -177
  373. package/dist/server/lib/code-worker-pool.js.map +1 -0
  374. package/dist/server/lib/code-worker.js +174 -164
  375. package/dist/server/lib/code-worker.js.map +1 -0
  376. package/dist/server/lib/compaction-service.d.ts +2 -12
  377. package/dist/server/lib/compaction-service.js +74 -184
  378. package/dist/server/lib/compaction-service.js.map +1 -0
  379. package/dist/server/lib/logger.js +36 -24
  380. package/dist/server/lib/logger.js.map +1 -0
  381. package/dist/server/lib/otel.js +101 -80
  382. package/dist/server/lib/otel.js.map +1 -0
  383. package/dist/server/lib/pdf-renderer.d.ts +1 -1
  384. package/dist/server/lib/pdf-renderer.js +954 -776
  385. package/dist/server/lib/pdf-renderer.js.map +1 -0
  386. package/dist/server/lib/prompt-sanitizer.js +188 -108
  387. package/dist/server/lib/prompt-sanitizer.js.map +1 -0
  388. package/dist/server/lib/provider-capabilities.js +136 -138
  389. package/dist/server/lib/provider-capabilities.js.map +1 -0
  390. package/dist/server/lib/provider-failover.js +190 -168
  391. package/dist/server/lib/provider-failover.js.map +1 -0
  392. package/dist/server/lib/rate-limiter.js +186 -117
  393. package/dist/server/lib/rate-limiter.js.map +1 -0
  394. package/dist/server/lib/react-pdf-layout.js +551 -382
  395. package/dist/server/lib/react-pdf-layout.js.map +1 -0
  396. package/dist/server/lib/server-agent-loop.d.ts +9 -0
  397. package/dist/server/lib/server-agent-loop.js +906 -624
  398. package/dist/server/lib/server-agent-loop.js.map +1 -0
  399. package/dist/server/lib/server-subagent.d.ts +2 -0
  400. package/dist/server/lib/server-subagent.js +260 -162
  401. package/dist/server/lib/server-subagent.js.map +1 -0
  402. package/dist/server/lib/session-checkpoint.js +105 -96
  403. package/dist/server/lib/session-checkpoint.js.map +1 -0
  404. package/dist/server/lib/ssrf-guard.js +193 -184
  405. package/dist/server/lib/ssrf-guard.js.map +1 -0
  406. package/dist/server/lib/supabase-client.js +94 -82
  407. package/dist/server/lib/supabase-client.js.map +1 -0
  408. package/dist/server/lib/template-resolver.js +154 -176
  409. package/dist/server/lib/template-resolver.js.map +1 -0
  410. package/dist/server/lib/utils.js +242 -133
  411. package/dist/server/lib/utils.js.map +1 -0
  412. package/dist/server/local-agent-gateway.d.ts +2 -2
  413. package/dist/server/local-agent-gateway.js +785 -627
  414. package/dist/server/local-agent-gateway.js.map +1 -0
  415. package/dist/server/providers/anthropic.js +254 -176
  416. package/dist/server/providers/anthropic.js.map +1 -0
  417. package/dist/server/providers/bedrock.js +221 -162
  418. package/dist/server/providers/bedrock.js.map +1 -0
  419. package/dist/server/providers/gemini.js +548 -418
  420. package/dist/server/providers/gemini.js.map +1 -0
  421. package/dist/server/providers/openai.js +571 -437
  422. package/dist/server/providers/openai.js.map +1 -0
  423. package/dist/server/providers/registry.js +23 -18
  424. package/dist/server/providers/registry.js.map +1 -0
  425. package/dist/server/providers/shared.js +123 -95
  426. package/dist/server/providers/shared.js.map +1 -0
  427. package/dist/server/providers/types.js +1 -11
  428. package/dist/server/providers/types.js.map +1 -0
  429. package/dist/server/proxy-handlers.js +209 -165
  430. package/dist/server/proxy-handlers.js.map +1 -0
  431. package/dist/server/tool-router.d.ts +13 -0
  432. package/dist/server/tool-router.js +960 -598
  433. package/dist/server/tool-router.js.map +1 -0
  434. package/dist/server/validation.js +248 -188
  435. package/dist/server/validation.js.map +1 -0
  436. package/dist/server/worker.js +202 -133
  437. package/dist/server/worker.js.map +1 -0
  438. package/dist/setup.d.ts +2 -2
  439. package/dist/setup.js +151 -147
  440. package/dist/setup.js.map +1 -0
  441. package/dist/shared/agent-core.d.ts +191 -24
  442. package/dist/shared/agent-core.js +971 -462
  443. package/dist/shared/agent-core.js.map +1 -0
  444. package/dist/shared/anthropic-types.js +1 -6
  445. package/dist/shared/anthropic-types.js.map +1 -0
  446. package/dist/shared/api-client.d.ts +17 -9
  447. package/dist/shared/api-client.js +419 -327
  448. package/dist/shared/api-client.js.map +1 -0
  449. package/dist/shared/compaction.d.ts +36 -0
  450. package/dist/shared/compaction.js +138 -0
  451. package/dist/shared/compaction.js.map +1 -0
  452. package/dist/shared/constants.js +67 -64
  453. package/dist/shared/constants.js.map +1 -0
  454. package/dist/shared/sse-parser.js +221 -219
  455. package/dist/shared/sse-parser.js.map +1 -0
  456. package/dist/shared/tool-dispatch.d.ts +4 -2
  457. package/dist/shared/tool-dispatch.js +226 -165
  458. package/dist/shared/tool-dispatch.js.map +1 -0
  459. package/dist/shared/types.js +1 -6
  460. package/dist/shared/types.js.map +1 -0
  461. package/dist/types/cli-highlight.d.js +2 -0
  462. package/dist/types/cli-highlight.d.js.map +1 -0
  463. package/dist/types/diff.d.js +2 -0
  464. package/dist/types/diff.d.js.map +1 -0
  465. package/dist/types/pdf-parse.d.js +2 -0
  466. package/dist/types/pdf-parse.d.js.map +1 -0
  467. package/dist/updater.d.ts +1 -1
  468. package/dist/updater.js +118 -92
  469. package/dist/updater.js.map +1 -0
  470. package/dist/webchat/widget.js +227 -380
  471. package/dist/webchat/widget.js.map +1 -0
  472. package/package.json +22 -10
  473. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  474. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  475. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  476. package/vendor/ink/build/apply-styles.js +175 -0
  477. package/vendor/ink/build/build-layout.js +77 -0
  478. package/vendor/ink/build/calculate-wrapped-text.js +53 -0
  479. package/vendor/ink/build/colorize.d.ts +3 -0
  480. package/vendor/ink/build/colorize.js +48 -0
  481. package/vendor/ink/build/colorize.js.map +1 -0
  482. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  483. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  484. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  485. package/vendor/ink/build/components/App.d.ts +18 -0
  486. package/vendor/ink/build/components/App.js +351 -0
  487. package/vendor/ink/build/components/App.js.map +1 -0
  488. package/vendor/ink/build/components/AppContext.d.ts +15 -0
  489. package/vendor/ink/build/components/AppContext.js +11 -0
  490. package/vendor/ink/build/components/AppContext.js.map +1 -0
  491. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  492. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  493. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  494. package/vendor/ink/build/components/Box.d.ts +117 -0
  495. package/vendor/ink/build/components/Box.js +34 -0
  496. package/vendor/ink/build/components/Box.js.map +1 -0
  497. package/vendor/ink/build/components/Color.js +62 -0
  498. package/vendor/ink/build/components/Cursor.d.ts +83 -0
  499. package/vendor/ink/build/components/Cursor.js +53 -0
  500. package/vendor/ink/build/components/Cursor.js.map +1 -0
  501. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  502. package/vendor/ink/build/components/CursorContext.js +8 -0
  503. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  504. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  505. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  506. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  507. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  508. package/vendor/ink/build/components/ErrorOverview.js +84 -0
  509. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  510. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  511. package/vendor/ink/build/components/FocusContext.js +17 -0
  512. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  513. package/vendor/ink/build/components/Newline.d.ts +13 -0
  514. package/vendor/ink/build/components/Newline.js +8 -0
  515. package/vendor/ink/build/components/Newline.js.map +1 -0
  516. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  517. package/vendor/ink/build/components/Spacer.js +11 -0
  518. package/vendor/ink/build/components/Spacer.js.map +1 -0
  519. package/vendor/ink/build/components/Static.d.ts +24 -0
  520. package/vendor/ink/build/components/Static.js +28 -0
  521. package/vendor/ink/build/components/Static.js.map +1 -0
  522. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  523. package/vendor/ink/build/components/StderrContext.js +13 -0
  524. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  525. package/vendor/ink/build/components/StdinContext.d.ts +22 -0
  526. package/vendor/ink/build/components/StdinContext.js +19 -0
  527. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  528. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  529. package/vendor/ink/build/components/StdoutContext.js +13 -0
  530. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  531. package/vendor/ink/build/components/Text.d.ts +55 -0
  532. package/vendor/ink/build/components/Text.js +50 -0
  533. package/vendor/ink/build/components/Text.js.map +1 -0
  534. package/vendor/ink/build/components/Transform.d.ts +16 -0
  535. package/vendor/ink/build/components/Transform.js +15 -0
  536. package/vendor/ink/build/components/Transform.js.map +1 -0
  537. package/vendor/ink/build/cursor-helpers.d.ts +38 -0
  538. package/vendor/ink/build/cursor-helpers.js +56 -0
  539. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  540. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  541. package/vendor/ink/build/devtools-window-polyfill.js +65 -0
  542. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  543. package/vendor/ink/build/devtools.d.ts +1 -0
  544. package/vendor/ink/build/devtools.js +11 -0
  545. package/vendor/ink/build/devtools.js.map +1 -0
  546. package/vendor/ink/build/dom.d.ts +56 -0
  547. package/vendor/ink/build/dom.js +124 -0
  548. package/vendor/ink/build/dom.js.map +1 -0
  549. package/vendor/ink/build/experimental/apply-style.js +140 -0
  550. package/vendor/ink/build/experimental/dom.js +123 -0
  551. package/vendor/ink/build/experimental/output.js +91 -0
  552. package/vendor/ink/build/experimental/reconciler.js +141 -0
  553. package/vendor/ink/build/experimental/renderer.js +81 -0
  554. package/vendor/ink/build/get-max-width.d.ts +3 -0
  555. package/vendor/ink/build/get-max-width.js +10 -0
  556. package/vendor/ink/build/get-max-width.js.map +1 -0
  557. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  558. package/vendor/ink/build/hooks/use-app.js +8 -0
  559. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  560. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  561. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  562. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  563. package/vendor/ink/build/hooks/use-focus-manager.d.ts +28 -0
  564. package/vendor/ink/build/hooks/use-focus-manager.js +17 -0
  565. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  566. package/vendor/ink/build/hooks/use-focus.d.ts +29 -0
  567. package/vendor/ink/build/hooks/use-focus.js +42 -0
  568. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  569. package/vendor/ink/build/hooks/use-input.d.ts +131 -0
  570. package/vendor/ink/build/hooks/use-input.js +124 -0
  571. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  572. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +5 -0
  573. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +11 -0
  574. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  575. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  576. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  577. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  578. package/vendor/ink/build/hooks/use-stdin.d.ts +5 -0
  579. package/vendor/ink/build/hooks/use-stdin.js +8 -0
  580. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  581. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  582. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  583. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  584. package/vendor/ink/build/hooks/useInput.js +38 -0
  585. package/vendor/ink/build/index.d.ts +34 -0
  586. package/vendor/ink/build/index.js +20 -0
  587. package/vendor/ink/build/index.js.map +1 -0
  588. package/vendor/ink/build/ink.d.ts +90 -0
  589. package/vendor/ink/build/ink.js +654 -0
  590. package/vendor/ink/build/ink.js.map +1 -0
  591. package/vendor/ink/build/input-parser.d.ts +7 -0
  592. package/vendor/ink/build/input-parser.js +154 -0
  593. package/vendor/ink/build/input-parser.js.map +1 -0
  594. package/vendor/ink/build/instance.js +205 -0
  595. package/vendor/ink/build/instances.d.ts +3 -0
  596. package/vendor/ink/build/instances.js +8 -0
  597. package/vendor/ink/build/instances.js.map +1 -0
  598. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  599. package/vendor/ink/build/kitty-keyboard.js +32 -0
  600. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  601. package/vendor/ink/build/layout.d.ts +7 -0
  602. package/vendor/ink/build/layout.js +33 -0
  603. package/vendor/ink/build/layout.js.map +1 -0
  604. package/vendor/ink/build/log-update.d.ts +19 -0
  605. package/vendor/ink/build/log-update.js +243 -0
  606. package/vendor/ink/build/log-update.js.map +1 -0
  607. package/vendor/ink/build/measure-element.d.ts +16 -0
  608. package/vendor/ink/build/measure-element.js +9 -0
  609. package/vendor/ink/build/measure-element.js.map +1 -0
  610. package/vendor/ink/build/measure-text.d.ts +6 -0
  611. package/vendor/ink/build/measure-text.js +21 -0
  612. package/vendor/ink/build/measure-text.js.map +1 -0
  613. package/vendor/ink/build/options.d.ts +52 -0
  614. package/vendor/ink/build/options.js +2 -0
  615. package/vendor/ink/build/options.js.map +1 -0
  616. package/vendor/ink/build/output.d.ts +35 -0
  617. package/vendor/ink/build/output.js +183 -0
  618. package/vendor/ink/build/output.js.map +1 -0
  619. package/vendor/ink/build/parse-keypress.d.ts +22 -0
  620. package/vendor/ink/build/parse-keypress.js +493 -0
  621. package/vendor/ink/build/parse-keypress.js.map +1 -0
  622. package/vendor/ink/build/reconciler.d.ts +4 -0
  623. package/vendor/ink/build/reconciler.js +274 -0
  624. package/vendor/ink/build/reconciler.js.map +1 -0
  625. package/vendor/ink/build/render-background.d.ts +4 -0
  626. package/vendor/ink/build/render-background.js +25 -0
  627. package/vendor/ink/build/render-background.js.map +1 -0
  628. package/vendor/ink/build/render-border.d.ts +4 -0
  629. package/vendor/ink/build/render-border.js +73 -0
  630. package/vendor/ink/build/render-border.js.map +1 -0
  631. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  632. package/vendor/ink/build/render-node-to-output.js +147 -0
  633. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  634. package/vendor/ink/build/render-to-string.d.ts +38 -0
  635. package/vendor/ink/build/render-to-string.js +115 -0
  636. package/vendor/ink/build/render-to-string.js.map +1 -0
  637. package/vendor/ink/build/render.d.ts +121 -0
  638. package/vendor/ink/build/render.js +55 -0
  639. package/vendor/ink/build/render.js.map +1 -0
  640. package/vendor/ink/build/renderer.d.ts +8 -0
  641. package/vendor/ink/build/renderer.js +55 -0
  642. package/vendor/ink/build/renderer.js.map +1 -0
  643. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  644. package/vendor/ink/build/sanitize-ansi.js +27 -0
  645. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  646. package/vendor/ink/build/screen-reader-update.d.ts +13 -0
  647. package/vendor/ink/build/screen-reader-update.js +38 -0
  648. package/vendor/ink/build/screen-reader-update.js.map +1 -0
  649. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  650. package/vendor/ink/build/squash-text-nodes.js +36 -0
  651. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  652. package/vendor/ink/build/styles.d.ts +240 -0
  653. package/vendor/ink/build/styles.js +232 -0
  654. package/vendor/ink/build/styles.js.map +1 -0
  655. package/vendor/ink/build/utils.d.ts +2 -0
  656. package/vendor/ink/build/utils.js +4 -0
  657. package/vendor/ink/build/utils.js.map +1 -0
  658. package/vendor/ink/build/wrap-text.d.ts +3 -0
  659. package/vendor/ink/build/wrap-text.js +31 -0
  660. package/vendor/ink/build/wrap-text.js.map +1 -0
  661. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  662. package/vendor/ink/build/write-synchronized.js +7 -0
  663. package/vendor/ink/build/write-synchronized.js.map +1 -0
  664. package/vendor/ink/license +10 -0
  665. package/vendor/ink/node_modules/@types/node/LICENSE +21 -0
  666. package/vendor/ink/node_modules/@types/node/README.md +15 -0
  667. package/vendor/ink/node_modules/@types/node/assert/strict.d.ts +105 -0
  668. package/vendor/ink/node_modules/@types/node/assert.d.ts +955 -0
  669. package/vendor/ink/node_modules/@types/node/async_hooks.d.ts +623 -0
  670. package/vendor/ink/node_modules/@types/node/buffer.buffer.d.ts +466 -0
  671. package/vendor/ink/node_modules/@types/node/buffer.d.ts +1810 -0
  672. package/vendor/ink/node_modules/@types/node/child_process.d.ts +1428 -0
  673. package/vendor/ink/node_modules/@types/node/cluster.d.ts +486 -0
  674. package/vendor/ink/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
  675. package/vendor/ink/node_modules/@types/node/console.d.ts +151 -0
  676. package/vendor/ink/node_modules/@types/node/constants.d.ts +20 -0
  677. package/vendor/ink/node_modules/@types/node/crypto.d.ts +4065 -0
  678. package/vendor/ink/node_modules/@types/node/dgram.d.ts +564 -0
  679. package/vendor/ink/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
  680. package/vendor/ink/node_modules/@types/node/dns/promises.d.ts +503 -0
  681. package/vendor/ink/node_modules/@types/node/dns.d.ts +922 -0
  682. package/vendor/ink/node_modules/@types/node/domain.d.ts +166 -0
  683. package/vendor/ink/node_modules/@types/node/events.d.ts +1054 -0
  684. package/vendor/ink/node_modules/@types/node/fs/promises.d.ts +1329 -0
  685. package/vendor/ink/node_modules/@types/node/fs.d.ts +4676 -0
  686. package/vendor/ink/node_modules/@types/node/globals.d.ts +150 -0
  687. package/vendor/ink/node_modules/@types/node/globals.typedarray.d.ts +101 -0
  688. package/vendor/ink/node_modules/@types/node/http.d.ts +2167 -0
  689. package/vendor/ink/node_modules/@types/node/http2.d.ts +2480 -0
  690. package/vendor/ink/node_modules/@types/node/https.d.ts +405 -0
  691. package/vendor/ink/node_modules/@types/node/index.d.ts +115 -0
  692. package/vendor/ink/node_modules/@types/node/inspector/promises.d.ts +41 -0
  693. package/vendor/ink/node_modules/@types/node/inspector.d.ts +224 -0
  694. package/vendor/ink/node_modules/@types/node/inspector.generated.d.ts +4226 -0
  695. package/vendor/ink/node_modules/@types/node/module.d.ts +819 -0
  696. package/vendor/ink/node_modules/@types/node/net.d.ts +933 -0
  697. package/vendor/ink/node_modules/@types/node/os.d.ts +507 -0
  698. package/vendor/ink/node_modules/@types/node/package.json +155 -0
  699. package/vendor/ink/node_modules/@types/node/path/posix.d.ts +8 -0
  700. package/vendor/ink/node_modules/@types/node/path/win32.d.ts +8 -0
  701. package/vendor/ink/node_modules/@types/node/path.d.ts +187 -0
  702. package/vendor/ink/node_modules/@types/node/perf_hooks.d.ts +643 -0
  703. package/vendor/ink/node_modules/@types/node/process.d.ts +2156 -0
  704. package/vendor/ink/node_modules/@types/node/punycode.d.ts +117 -0
  705. package/vendor/ink/node_modules/@types/node/querystring.d.ts +152 -0
  706. package/vendor/ink/node_modules/@types/node/quic.d.ts +910 -0
  707. package/vendor/ink/node_modules/@types/node/readline/promises.d.ts +161 -0
  708. package/vendor/ink/node_modules/@types/node/readline.d.ts +541 -0
  709. package/vendor/ink/node_modules/@types/node/repl.d.ts +415 -0
  710. package/vendor/ink/node_modules/@types/node/sea.d.ts +162 -0
  711. package/vendor/ink/node_modules/@types/node/sqlite.d.ts +955 -0
  712. package/vendor/ink/node_modules/@types/node/stream/consumers.d.ts +38 -0
  713. package/vendor/ink/node_modules/@types/node/stream/promises.d.ts +211 -0
  714. package/vendor/ink/node_modules/@types/node/stream/web.d.ts +296 -0
  715. package/vendor/ink/node_modules/@types/node/stream.d.ts +1760 -0
  716. package/vendor/ink/node_modules/@types/node/string_decoder.d.ts +67 -0
  717. package/vendor/ink/node_modules/@types/node/test/reporters.d.ts +96 -0
  718. package/vendor/ink/node_modules/@types/node/test.d.ts +2240 -0
  719. package/vendor/ink/node_modules/@types/node/timers/promises.d.ts +108 -0
  720. package/vendor/ink/node_modules/@types/node/timers.d.ts +159 -0
  721. package/vendor/ink/node_modules/@types/node/tls.d.ts +1198 -0
  722. package/vendor/ink/node_modules/@types/node/trace_events.d.ts +197 -0
  723. package/vendor/ink/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +462 -0
  724. package/vendor/ink/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
  725. package/vendor/ink/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
  726. package/vendor/ink/node_modules/@types/node/ts5.6/index.d.ts +117 -0
  727. package/vendor/ink/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
  728. package/vendor/ink/node_modules/@types/node/ts5.7/index.d.ts +117 -0
  729. package/vendor/ink/node_modules/@types/node/tty.d.ts +250 -0
  730. package/vendor/ink/node_modules/@types/node/url.d.ts +519 -0
  731. package/vendor/ink/node_modules/@types/node/util/types.d.ts +558 -0
  732. package/vendor/ink/node_modules/@types/node/util.d.ts +1662 -0
  733. package/vendor/ink/node_modules/@types/node/v8.d.ts +983 -0
  734. package/vendor/ink/node_modules/@types/node/vm.d.ts +1208 -0
  735. package/vendor/ink/node_modules/@types/node/wasi.d.ts +202 -0
  736. package/vendor/ink/node_modules/@types/node/web-globals/abortcontroller.d.ts +59 -0
  737. package/vendor/ink/node_modules/@types/node/web-globals/blob.d.ts +23 -0
  738. package/vendor/ink/node_modules/@types/node/web-globals/console.d.ts +9 -0
  739. package/vendor/ink/node_modules/@types/node/web-globals/crypto.d.ts +39 -0
  740. package/vendor/ink/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  741. package/vendor/ink/node_modules/@types/node/web-globals/encoding.d.ts +11 -0
  742. package/vendor/ink/node_modules/@types/node/web-globals/events.d.ts +106 -0
  743. package/vendor/ink/node_modules/@types/node/web-globals/fetch.d.ts +69 -0
  744. package/vendor/ink/node_modules/@types/node/web-globals/importmeta.d.ts +13 -0
  745. package/vendor/ink/node_modules/@types/node/web-globals/messaging.d.ts +23 -0
  746. package/vendor/ink/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
  747. package/vendor/ink/node_modules/@types/node/web-globals/performance.d.ts +45 -0
  748. package/vendor/ink/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  749. package/vendor/ink/node_modules/@types/node/web-globals/streams.d.ts +115 -0
  750. package/vendor/ink/node_modules/@types/node/web-globals/timers.d.ts +44 -0
  751. package/vendor/ink/node_modules/@types/node/web-globals/url.d.ts +24 -0
  752. package/vendor/ink/node_modules/@types/node/worker_threads.d.ts +717 -0
  753. package/vendor/ink/node_modules/@types/node/zlib.d.ts +618 -0
  754. package/vendor/ink/node_modules/node-pty/LICENSE +69 -0
  755. package/vendor/ink/node_modules/node-pty/README.md +164 -0
  756. package/vendor/ink/node_modules/node-pty/binding.gyp +150 -0
  757. package/vendor/ink/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
  758. package/vendor/ink/node_modules/node-pty/lib/eventEmitter2.js +47 -0
  759. package/vendor/ink/node_modules/node-pty/lib/index.js +52 -0
  760. package/vendor/ink/node_modules/node-pty/lib/interfaces.js +7 -0
  761. package/vendor/ink/node_modules/node-pty/lib/shared/conout.js +11 -0
  762. package/vendor/ink/node_modules/node-pty/lib/terminal.js +190 -0
  763. package/vendor/ink/node_modules/node-pty/lib/types.js +7 -0
  764. package/vendor/ink/node_modules/node-pty/lib/unixTerminal.js +349 -0
  765. package/vendor/ink/node_modules/node-pty/lib/utils.js +39 -0
  766. package/vendor/ink/node_modules/node-pty/lib/windowsConoutConnection.js +125 -0
  767. package/vendor/ink/node_modules/node-pty/lib/windowsPtyAgent.js +287 -0
  768. package/vendor/ink/node_modules/node-pty/lib/windowsTerminal.js +201 -0
  769. package/vendor/ink/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  770. package/vendor/ink/node_modules/node-pty/package.json +65 -0
  771. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
  772. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  773. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
  774. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
  775. package/vendor/ink/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
  776. package/vendor/ink/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
  777. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  778. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  779. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  780. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty.pdb +0 -0
  781. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  782. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
  783. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  784. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  785. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  786. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty.pdb +0 -0
  787. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  788. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
  789. package/vendor/ink/node_modules/node-pty/scripts/post-install.js +76 -0
  790. package/vendor/ink/node_modules/node-pty/scripts/prebuild.js +34 -0
  791. package/vendor/ink/node_modules/node-pty/src/unix/pty.cc +875 -0
  792. package/vendor/ink/node_modules/node-pty/src/unix/spawn-helper.cc +23 -0
  793. package/vendor/ink/node_modules/node-pty/src/win/conpty.cc +582 -0
  794. package/vendor/ink/node_modules/node-pty/src/win/conpty.h +41 -0
  795. package/vendor/ink/node_modules/node-pty/src/win/conpty_console_list.cc +44 -0
  796. package/vendor/ink/node_modules/node-pty/src/win/path_util.cc +95 -0
  797. package/vendor/ink/node_modules/node-pty/src/win/path_util.h +26 -0
  798. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
  799. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
  800. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
  801. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
  802. package/vendor/ink/node_modules/node-pty/typings/node-pty.d.ts +215 -0
  803. package/vendor/ink/node_modules/undici-types/LICENSE +21 -0
  804. package/vendor/ink/node_modules/undici-types/README.md +6 -0
  805. package/vendor/ink/node_modules/undici-types/agent.d.ts +32 -0
  806. package/vendor/ink/node_modules/undici-types/api.d.ts +43 -0
  807. package/vendor/ink/node_modules/undici-types/balanced-pool.d.ts +30 -0
  808. package/vendor/ink/node_modules/undici-types/cache-interceptor.d.ts +173 -0
  809. package/vendor/ink/node_modules/undici-types/cache.d.ts +36 -0
  810. package/vendor/ink/node_modules/undici-types/client-stats.d.ts +15 -0
  811. package/vendor/ink/node_modules/undici-types/client.d.ts +108 -0
  812. package/vendor/ink/node_modules/undici-types/connector.d.ts +34 -0
  813. package/vendor/ink/node_modules/undici-types/content-type.d.ts +21 -0
  814. package/vendor/ink/node_modules/undici-types/cookies.d.ts +30 -0
  815. package/vendor/ink/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
  816. package/vendor/ink/node_modules/undici-types/dispatcher.d.ts +276 -0
  817. package/vendor/ink/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
  818. package/vendor/ink/node_modules/undici-types/errors.d.ts +161 -0
  819. package/vendor/ink/node_modules/undici-types/eventsource.d.ts +66 -0
  820. package/vendor/ink/node_modules/undici-types/fetch.d.ts +211 -0
  821. package/vendor/ink/node_modules/undici-types/formdata.d.ts +108 -0
  822. package/vendor/ink/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  823. package/vendor/ink/node_modules/undici-types/global-origin.d.ts +7 -0
  824. package/vendor/ink/node_modules/undici-types/h2c-client.d.ts +73 -0
  825. package/vendor/ink/node_modules/undici-types/handlers.d.ts +15 -0
  826. package/vendor/ink/node_modules/undici-types/header.d.ts +160 -0
  827. package/vendor/ink/node_modules/undici-types/index.d.ts +88 -0
  828. package/vendor/ink/node_modules/undici-types/interceptors.d.ts +73 -0
  829. package/vendor/ink/node_modules/undici-types/mock-agent.d.ts +68 -0
  830. package/vendor/ink/node_modules/undici-types/mock-call-history.d.ts +111 -0
  831. package/vendor/ink/node_modules/undici-types/mock-client.d.ts +27 -0
  832. package/vendor/ink/node_modules/undici-types/mock-errors.d.ts +12 -0
  833. package/vendor/ink/node_modules/undici-types/mock-interceptor.d.ts +94 -0
  834. package/vendor/ink/node_modules/undici-types/mock-pool.d.ts +27 -0
  835. package/vendor/ink/node_modules/undici-types/package.json +55 -0
  836. package/vendor/ink/node_modules/undici-types/patch.d.ts +29 -0
  837. package/vendor/ink/node_modules/undici-types/pool-stats.d.ts +19 -0
  838. package/vendor/ink/node_modules/undici-types/pool.d.ts +41 -0
  839. package/vendor/ink/node_modules/undici-types/proxy-agent.d.ts +29 -0
  840. package/vendor/ink/node_modules/undici-types/readable.d.ts +68 -0
  841. package/vendor/ink/node_modules/undici-types/retry-agent.d.ts +8 -0
  842. package/vendor/ink/node_modules/undici-types/retry-handler.d.ts +125 -0
  843. package/vendor/ink/node_modules/undici-types/round-robin-pool.d.ts +41 -0
  844. package/vendor/ink/node_modules/undici-types/snapshot-agent.d.ts +109 -0
  845. package/vendor/ink/node_modules/undici-types/util.d.ts +18 -0
  846. package/vendor/ink/node_modules/undici-types/utility.d.ts +7 -0
  847. package/vendor/ink/node_modules/undici-types/webidl.d.ts +341 -0
  848. package/vendor/ink/node_modules/undici-types/websocket.d.ts +186 -0
  849. package/vendor/ink/package.json +201 -0
  850. package/vendor/ink/readme.md +2636 -0
  851. package/bin/swag-agent.js +0 -9
  852. package/dist/server/lib/pg-rate-limiter.d.ts +0 -21
  853. package/dist/server/lib/pg-rate-limiter.js +0 -86
@@ -1,845 +1,1022 @@
1
1
  // server/lib/pdf-renderer.ts — PDF template rendering engine
2
2
  // Processes pdf_templates layout → HTML, with generation rules, calculations, and validation.
3
+
3
4
  import { fillTemplate } from "./utils.js";
5
+
6
+ // ============================================================================
7
+ // 1. GENERATION RULES — auto-fill missing fields from pdf_templates.generation_rules
8
+ // ============================================================================
9
+
4
10
  function resolvePattern(pattern) {
5
- const now = new Date();
6
- return pattern
7
- .replace("{YYYYMMDD}", now.toISOString().slice(0, 10).replace(/-/g, ""))
8
- .replace("{YYYY}", String(now.getFullYear()))
9
- .replace("{MM}", String(now.getMonth() + 1).padStart(2, "0"))
10
- .replace("{DD}", String(now.getDate()).padStart(2, "0"))
11
- .replace(/\{PREFIX\}/g, "")
12
- .replace(/\{RANDOM:(\d+)\}/g, (_, len) => {
13
- const n = parseInt(len);
14
- let s = "";
15
- for (let i = 0; i < n; i++)
16
- s += Math.floor(Math.random() * 10);
17
- return s;
18
- })
19
- .replace(/\{ALPHA:(\d+)\}/g, (_, len) => {
20
- const n = parseInt(len);
21
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
22
- let s = "";
23
- for (let i = 0; i < n; i++)
24
- s += chars[Math.floor(Math.random() * 26)];
25
- return s;
26
- });
11
+ const now = new Date();
12
+ return pattern.replace("{YYYYMMDD}", now.toISOString().slice(0, 10).replace(/-/g, "")).replace("{YYYY}", String(now.getFullYear())).replace("{MM}", String(now.getMonth() + 1).padStart(2, "0")).replace("{DD}", String(now.getDate()).padStart(2, "0")).replace(/\{PREFIX\}/g, "").replace(/\{RANDOM:(\d+)\}/g, (_, len) => {
13
+ const n = parseInt(len);
14
+ let s = "";
15
+ for (let i = 0; i < n; i++) s += Math.floor(Math.random() * 10);
16
+ return s;
17
+ }).replace(/\{ALPHA:(\d+)\}/g, (_, len) => {
18
+ const n = parseInt(len);
19
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
20
+ let s = "";
21
+ for (let i = 0; i < n; i++) s += chars[Math.floor(Math.random() * 26)];
22
+ return s;
23
+ });
27
24
  }
28
25
  function normalizeGenerationRules(raw) {
29
- if (!raw)
30
- return [];
31
- if (Array.isArray(raw))
32
- return raw;
33
- // Object-keyed format from DB: { "moisture": { "type": "random_range", "config": { "min": 8.5, ... } } }
34
- // Convert to array format: [{ field: "moisture", type: "random_range", min: 8.5, ... }]
35
- if (typeof raw === "object") {
36
- const rules = [];
37
- for (const [field, def] of Object.entries(raw)) {
38
- if (!def || typeof def !== "object")
39
- continue;
40
- const cfg = def.config || {};
41
- const rule = {
42
- field,
43
- type: def.type,
44
- pattern: (cfg.pattern || cfg.prefix) ? `${cfg.prefix || ""}${cfg.pattern || ""}` : undefined,
45
- choices: cfg.choices,
46
- resolve_pattern: cfg.resolve_pattern,
47
- min: cfg.min,
48
- max: cfg.max,
49
- decimals: cfg.decimals,
50
- base_field: cfg.base,
51
- value: cfg.value,
52
- };
53
- // relative_date: offset can be { days: [1, 2] } or { days: 5 }
54
- if (cfg.offset) {
55
- if (cfg.offset.days !== undefined) {
56
- rule.offset = Array.isArray(cfg.offset.days) ? cfg.offset.days : cfg.offset.days;
57
- }
58
- else {
59
- rule.offset = cfg.offset;
60
- }
61
- }
62
- rules.push(rule);
26
+ if (!raw) return [];
27
+ if (Array.isArray(raw)) return raw;
28
+
29
+ // Object-keyed format from DB: { "moisture": { "type": "random_range", "config": { "min": 8.5, ... } } }
30
+ // Convert to array format: [{ field: "moisture", type: "random_range", min: 8.5, ... }]
31
+ if (typeof raw === "object") {
32
+ const rules = [];
33
+ for (const [field, def] of Object.entries(raw)) {
34
+ if (!def || typeof def !== "object") continue;
35
+ const cfg = def.config || {};
36
+ const rule = {
37
+ field,
38
+ type: def.type,
39
+ pattern: cfg.pattern || cfg.prefix ? `${cfg.prefix || ""}${cfg.pattern || ""}` : undefined,
40
+ choices: cfg.choices,
41
+ resolve_pattern: cfg.resolve_pattern,
42
+ min: cfg.min,
43
+ max: cfg.max,
44
+ decimals: cfg.decimals,
45
+ base_field: cfg.base,
46
+ value: cfg.value
47
+ };
48
+ // relative_date: offset can be { days: [1, 2] } or { days: 5 }
49
+ if (cfg.offset) {
50
+ if (cfg.offset.days !== undefined) {
51
+ rule.offset = Array.isArray(cfg.offset.days) ? cfg.offset.days : cfg.offset.days;
52
+ } else {
53
+ rule.offset = cfg.offset;
63
54
  }
64
- return rules;
55
+ }
56
+ rules.push(rule);
65
57
  }
66
- return [];
58
+ return rules;
59
+ }
60
+ return [];
67
61
  }
68
62
  export function applyGenerationRules(rules, data) {
69
- const normalized = normalizeGenerationRules(rules);
70
- if (!normalized.length)
71
- return data;
72
- const result = { ...data };
73
- // Multi-pass (max 4) to resolve chained dependencies (e.g. dateCollected → dateReceived → dateTested)
74
- for (let pass = 0; pass < 4; pass++) {
75
- let resolved = 0;
76
- for (const rule of normalized) {
77
- // User overrides win — skip fields already provided
78
- if (result[rule.field] !== undefined && result[rule.field] !== null)
79
- continue;
80
- // For relative_date, skip if base field isn't resolved yet
81
- if (rule.type === "relative_date" && rule.base_field) {
82
- if (result[rule.base_field] === undefined || result[rule.base_field] === null)
83
- continue;
63
+ const normalized = normalizeGenerationRules(rules);
64
+ if (!normalized.length) return data;
65
+ const result = {
66
+ ...data
67
+ };
68
+
69
+ // Multi-pass (max 4) to resolve chained dependencies (e.g. dateCollected → dateReceived → dateTested)
70
+ for (let pass = 0; pass < 4; pass++) {
71
+ let resolved = 0;
72
+ for (const rule of normalized) {
73
+ // User overrides win — skip fields already provided
74
+ if (result[rule.field] !== undefined && result[rule.field] !== null) continue;
75
+
76
+ // For relative_date, skip if base field isn't resolved yet
77
+ if (rule.type === "relative_date" && rule.base_field) {
78
+ if (result[rule.base_field] === undefined || result[rule.base_field] === null) continue;
79
+ }
80
+ switch (rule.type) {
81
+ case "pattern":
82
+ {
83
+ result[rule.field] = resolvePattern(rule.pattern || "");
84
+ resolved++;
85
+ break;
86
+ }
87
+ case "random_choice":
88
+ {
89
+ if (!rule.choices?.length) break;
90
+ const pick = rule.choices[Math.floor(Math.random() * rule.choices.length)];
91
+ result[rule.field] = rule.resolve_pattern ? resolvePattern(pick) : pick;
92
+ resolved++;
93
+ break;
94
+ }
95
+ case "random_range":
96
+ {
97
+ const min = rule.min ?? 0;
98
+ const max = rule.max ?? 100;
99
+ const raw = min + Math.random() * (max - min);
100
+ const dec = rule.decimals ?? 2;
101
+ result[rule.field] = parseFloat(raw.toFixed(dec));
102
+ resolved++;
103
+ break;
104
+ }
105
+ case "relative_date":
106
+ {
107
+ const baseVal = result[rule.base_field || ""];
108
+ const base = baseVal ? new Date(baseVal) : new Date();
109
+ let offsetDays;
110
+ if (Array.isArray(rule.offset)) {
111
+ const [lo, hi] = rule.offset;
112
+ offsetDays = lo + Math.floor(Math.random() * (hi - lo + 1));
113
+ } else {
114
+ offsetDays = rule.offset ?? 0;
84
115
  }
85
- switch (rule.type) {
86
- case "pattern": {
87
- result[rule.field] = resolvePattern(rule.pattern || "");
88
- resolved++;
89
- break;
90
- }
91
- case "random_choice": {
92
- if (!rule.choices?.length)
93
- break;
94
- const pick = rule.choices[Math.floor(Math.random() * rule.choices.length)];
95
- result[rule.field] = rule.resolve_pattern ? resolvePattern(pick) : pick;
96
- resolved++;
97
- break;
98
- }
99
- case "random_range": {
100
- const min = rule.min ?? 0;
101
- const max = rule.max ?? 100;
102
- const raw = min + Math.random() * (max - min);
103
- const dec = rule.decimals ?? 2;
104
- result[rule.field] = parseFloat(raw.toFixed(dec));
105
- resolved++;
106
- break;
107
- }
108
- case "relative_date": {
109
- const baseVal = result[rule.base_field || ""];
110
- const base = baseVal ? new Date(baseVal) : new Date();
111
- let offsetDays;
112
- if (Array.isArray(rule.offset)) {
113
- const [lo, hi] = rule.offset;
114
- offsetDays = lo + Math.floor(Math.random() * (hi - lo + 1));
115
- }
116
- else {
117
- offsetDays = rule.offset ?? 0;
118
- }
119
- const target = new Date(base);
120
- target.setDate(target.getDate() + offsetDays);
121
- result[rule.field] = target.toISOString().slice(0, 10);
122
- resolved++;
123
- break;
124
- }
125
- case "constant": {
126
- const val = rule.value;
127
- if (val === "TODAY") {
128
- result[rule.field] = new Date().toISOString().slice(0, 10);
129
- }
130
- else {
131
- result[rule.field] = val;
132
- }
133
- resolved++;
134
- break;
135
- }
116
+ const target = new Date(base);
117
+ target.setDate(target.getDate() + offsetDays);
118
+ result[rule.field] = target.toISOString().slice(0, 10);
119
+ resolved++;
120
+ break;
121
+ }
122
+ case "constant":
123
+ {
124
+ const val = rule.value;
125
+ if (val === "TODAY") {
126
+ result[rule.field] = new Date().toISOString().slice(0, 10);
127
+ } else {
128
+ result[rule.field] = val;
136
129
  }
137
- }
138
- if (resolved === 0)
139
- break; // No more fields to resolve
130
+ resolved++;
131
+ break;
132
+ }
133
+ }
140
134
  }
141
- return result;
135
+ if (resolved === 0) break; // No more fields to resolve
136
+ }
137
+ return result;
142
138
  }
139
+
140
+ // ============================================================================
141
+ // 2. CANNABINOID DATA GENERATOR — from document_profiles config
142
+ // ============================================================================
143
+
143
144
  export function generateCannabinoidData(profileConfig, constants) {
144
- if (!profileConfig)
145
- return [];
146
- const rows = [];
147
- // Find LOD/LOQ constants — try common keys
148
- const lodLoqKey = Object.keys(constants).find(k => k.startsWith("LOD_LOQ"));
149
- const lodLoqMap = (lodLoqKey ? constants[lodLoqKey] : {});
150
- const defaultLod = 0.01;
151
- const defaultLoq = 0.03;
152
- for (const [analyte, cfg] of Object.entries(profileConfig)) {
153
- const lodLoq = lodLoqMap[analyte] || {};
154
- const lod = lodLoq.LOD ?? defaultLod;
155
- const loq = lodLoq.LOQ ?? defaultLoq;
156
- if (cfg.nd) {
157
- rows.push({ name: analyte, result: "ND", percentWeight: 0, mgPerG: 0, lod, loq });
158
- }
159
- else {
160
- const min = cfg.min ?? 0;
161
- const max = cfg.max ?? 100;
162
- const percentWeight = parseFloat((min + Math.random() * (max - min)).toFixed(3));
163
- const mgPerG = parseFloat((percentWeight * 10).toFixed(2));
164
- rows.push({
165
- name: analyte,
166
- result: percentWeight < lod ? "ND" : percentWeight,
167
- percentWeight,
168
- mgPerG,
169
- lod,
170
- loq,
171
- });
172
- }
145
+ if (!profileConfig) return [];
146
+ const rows = [];
147
+
148
+ // Find LOD/LOQ constants — try common keys
149
+ const lodLoqKey = Object.keys(constants).find(k => k.startsWith("LOD_LOQ"));
150
+ const lodLoqMap = lodLoqKey ? constants[lodLoqKey] : {};
151
+ const defaultLod = 0.01;
152
+ const defaultLoq = 0.03;
153
+ for (const [analyte, cfg] of Object.entries(profileConfig)) {
154
+ const lodLoq = lodLoqMap[analyte] || {};
155
+ const lod = lodLoq.LOD ?? defaultLod;
156
+ const loq = lodLoq.LOQ ?? defaultLoq;
157
+ if (cfg.nd) {
158
+ rows.push({
159
+ name: analyte,
160
+ result: "ND",
161
+ percentWeight: 0,
162
+ mgPerG: 0,
163
+ lod,
164
+ loq
165
+ });
166
+ } else {
167
+ const min = cfg.min ?? 0;
168
+ const max = cfg.max ?? 100;
169
+ const percentWeight = parseFloat((min + Math.random() * (max - min)).toFixed(3));
170
+ const mgPerG = parseFloat((percentWeight * 10).toFixed(2));
171
+ rows.push({
172
+ name: analyte,
173
+ result: percentWeight < lod ? "ND" : percentWeight,
174
+ percentWeight,
175
+ mgPerG,
176
+ lod,
177
+ loq
178
+ });
173
179
  }
174
- return rows;
180
+ }
181
+ return rows;
175
182
  }
183
+
176
184
  // ============================================================================
177
185
  // 2b. FULL PANEL DATA GENERATOR — safety tests from template constants
178
186
  // ============================================================================
187
+
179
188
  export function generateFullPanelData(constants) {
180
- const microbialTests = (constants["MICROBIAL_TESTS"] || {});
181
- const heavyMetals = (constants["HEAVY_METALS"] || {});
182
- const mycotoxins = (constants["MYCOTOXINS"] || {});
183
- const pesticidesCat1 = (constants["PESTICIDES_CATEGORY_I"] || []);
184
- const pesticidesCat2 = (constants["PESTICIDES_CATEGORY_II"] || []);
185
- const microbialResults = Object.entries(microbialTests).map(([test, config]) => {
186
- let result = "ND";
187
- if (!config.nd_required && config.typical_range) {
188
- if (Math.random() > (config.nd_chance || 0)) {
189
- result = Math.round(config.typical_range.min + Math.random() * (config.typical_range.max - config.typical_range.min));
190
- }
191
- }
192
- return { test, result, limit: config.limit, status: "Pass" };
193
- });
194
- const heavyMetalsResults = Object.entries(heavyMetals).map(([analyte, config]) => {
195
- let result = "ND";
196
- if (Math.random() > config.nd_chance) {
197
- const val = Math.round((config.typical_range.min + Math.random() * (config.typical_range.max - config.typical_range.min)) * 1000) / 1000;
198
- result = val < config.loq ? "ND" : val;
199
- }
200
- return { analyte, lod: config.lod, loq: config.loq, result, limit: config.limit, status: "Pass" };
201
- });
202
- const mycotoxinResults = Object.entries(mycotoxins).map(([analyte, config]) => ({
203
- analyte, lod: config.lod, loq: config.loq, result: "ND", limit: config.limit, status: "Pass",
204
- }));
205
- const pesticidesCat1Results = pesticidesCat1.map(analyte => ({ analyte, result: "ND", status: "Pass" }));
206
- const pesticidesCat2Results = pesticidesCat2.map(analyte => ({ analyte, result: "ND", status: "Pass" }));
207
- const residualSolventsData = [
208
- { name: "Acetone", limit: 5000 }, { name: "Benzene", limit: 2 }, { name: "Butane", limit: 5000 },
209
- { name: "Chloroform", limit: 2 }, { name: "Ethanol", limit: 5000 }, { name: "Ethyl Acetate", limit: 5000 },
210
- { name: "Heptane", limit: 5000 }, { name: "Hexane", limit: 290 }, { name: "Isopropyl Alcohol", limit: 5000 },
211
- { name: "Methanol", limit: 3000 }, { name: "Pentane", limit: 5000 }, { name: "Propane", limit: 5000 },
212
- { name: "Toluene", limit: 890 }, { name: "Xylene", limit: 2170 },
213
- ];
214
- const residualSolventsResults = residualSolventsData.map(s => ({
215
- analyte: s.name, result: "<LOQ", limit: s.limit, loq: s.limit * 0.1, unit: "ppm", status: "Pass",
216
- }));
217
- return { microbialResults, heavyMetalsResults, mycotoxinResults, pesticidesCat1: pesticidesCat1Results, pesticidesCat2: pesticidesCat2Results, residualSolventsResults };
189
+ const microbialTests = constants["MICROBIAL_TESTS"] || {};
190
+ const heavyMetals = constants["HEAVY_METALS"] || {};
191
+ const mycotoxins = constants["MYCOTOXINS"] || {};
192
+ const pesticidesCat1 = constants["PESTICIDES_CATEGORY_I"] || [];
193
+ const pesticidesCat2 = constants["PESTICIDES_CATEGORY_II"] || [];
194
+ const microbialResults = Object.entries(microbialTests).map(([test, config]) => {
195
+ let result = "ND";
196
+ if (!config.nd_required && config.typical_range) {
197
+ if (Math.random() > (config.nd_chance || 0)) {
198
+ result = Math.round(config.typical_range.min + Math.random() * (config.typical_range.max - config.typical_range.min));
199
+ }
200
+ }
201
+ return {
202
+ test,
203
+ result,
204
+ limit: config.limit,
205
+ status: "Pass"
206
+ };
207
+ });
208
+ const heavyMetalsResults = Object.entries(heavyMetals).map(([analyte, config]) => {
209
+ let result = "ND";
210
+ if (Math.random() > config.nd_chance) {
211
+ const val = Math.round((config.typical_range.min + Math.random() * (config.typical_range.max - config.typical_range.min)) * 1000) / 1000;
212
+ result = val < config.loq ? "ND" : val;
213
+ }
214
+ return {
215
+ analyte,
216
+ lod: config.lod,
217
+ loq: config.loq,
218
+ result,
219
+ limit: config.limit,
220
+ status: "Pass"
221
+ };
222
+ });
223
+ const mycotoxinResults = Object.entries(mycotoxins).map(([analyte, config]) => ({
224
+ analyte,
225
+ lod: config.lod,
226
+ loq: config.loq,
227
+ result: "ND",
228
+ limit: config.limit,
229
+ status: "Pass"
230
+ }));
231
+ const pesticidesCat1Results = pesticidesCat1.map(analyte => ({
232
+ analyte,
233
+ result: "ND",
234
+ status: "Pass"
235
+ }));
236
+ const pesticidesCat2Results = pesticidesCat2.map(analyte => ({
237
+ analyte,
238
+ result: "ND",
239
+ status: "Pass"
240
+ }));
241
+ const residualSolventsData = [{
242
+ name: "Acetone",
243
+ limit: 5000
244
+ }, {
245
+ name: "Benzene",
246
+ limit: 2
247
+ }, {
248
+ name: "Butane",
249
+ limit: 5000
250
+ }, {
251
+ name: "Chloroform",
252
+ limit: 2
253
+ }, {
254
+ name: "Ethanol",
255
+ limit: 5000
256
+ }, {
257
+ name: "Ethyl Acetate",
258
+ limit: 5000
259
+ }, {
260
+ name: "Heptane",
261
+ limit: 5000
262
+ }, {
263
+ name: "Hexane",
264
+ limit: 290
265
+ }, {
266
+ name: "Isopropyl Alcohol",
267
+ limit: 5000
268
+ }, {
269
+ name: "Methanol",
270
+ limit: 3000
271
+ }, {
272
+ name: "Pentane",
273
+ limit: 5000
274
+ }, {
275
+ name: "Propane",
276
+ limit: 5000
277
+ }, {
278
+ name: "Toluene",
279
+ limit: 890
280
+ }, {
281
+ name: "Xylene",
282
+ limit: 2170
283
+ }];
284
+ const residualSolventsResults = residualSolventsData.map(s => ({
285
+ analyte: s.name,
286
+ result: "<LOQ",
287
+ limit: s.limit,
288
+ loq: s.limit * 0.1,
289
+ unit: "ppm",
290
+ status: "Pass"
291
+ }));
292
+ return {
293
+ microbialResults,
294
+ heavyMetalsResults,
295
+ mycotoxinResults,
296
+ pesticidesCat1: pesticidesCat1Results,
297
+ pesticidesCat2: pesticidesCat2Results,
298
+ residualSolventsResults
299
+ };
218
300
  }
301
+
302
+ // ============================================================================
303
+ // 3. CALCULATION ENGINE — safe expression evaluator (NO eval)
304
+ // ============================================================================
305
+
306
+ // Tokenizer
307
+
219
308
  function tokenize(expr) {
220
- const tokens = [];
221
- let i = 0;
222
- while (i < expr.length) {
223
- const ch = expr[i];
224
- if (/\s/.test(ch)) {
225
- i++;
226
- continue;
227
- }
228
- if (/[0-9.]/.test(ch)) {
229
- let num = "";
230
- while (i < expr.length && /[0-9.]/.test(expr[i])) {
231
- num += expr[i];
232
- i++;
233
- }
234
- tokens.push({ type: "NUMBER", value: num });
235
- continue;
236
- }
237
- if (/[a-zA-Z_]/.test(ch)) {
238
- let id = "";
239
- while (i < expr.length && /[a-zA-Z0-9_]/.test(expr[i])) {
240
- id += expr[i];
241
- i++;
242
- }
243
- if (id === "SUM" && i < expr.length && expr[i] === "(") {
244
- tokens.push({ type: "FUNC", value: id });
245
- }
246
- else {
247
- tokens.push({ type: "IDENT", value: id });
248
- }
249
- continue;
250
- }
251
- if ("+-*/".includes(ch)) {
252
- tokens.push({ type: "OP", value: ch });
253
- i++;
254
- continue;
255
- }
256
- if (ch === "(") {
257
- tokens.push({ type: "LPAREN", value: ch });
258
- i++;
259
- continue;
260
- }
261
- if (ch === ")") {
262
- tokens.push({ type: "RPAREN", value: ch });
263
- i++;
264
- continue;
265
- }
266
- if (ch === "[") {
267
- tokens.push({ type: "LBRACKET", value: ch });
268
- i++;
269
- continue;
270
- }
271
- if (ch === "]") {
272
- tokens.push({ type: "RBRACKET", value: ch });
273
- i++;
274
- continue;
275
- }
276
- if (ch === ".") {
277
- tokens.push({ type: "DOT", value: ch });
278
- i++;
279
- continue;
280
- }
281
- if (ch === ",") {
282
- tokens.push({ type: "COMMA", value: ch });
283
- i++;
284
- continue;
285
- }
286
- i++; // skip unknown
309
+ const tokens = [];
310
+ let i = 0;
311
+ while (i < expr.length) {
312
+ const ch = expr[i];
313
+ if (/\s/.test(ch)) {
314
+ i++;
315
+ continue;
316
+ }
317
+ if (/[0-9]/.test(ch) || ch === "." && i + 1 < expr.length && /[0-9]/.test(expr[i + 1])) {
318
+ let num = "";
319
+ while (i < expr.length && /[0-9.]/.test(expr[i])) {
320
+ num += expr[i];
321
+ i++;
322
+ }
323
+ tokens.push({
324
+ type: "NUMBER",
325
+ value: num
326
+ });
327
+ continue;
328
+ }
329
+ if (/[a-zA-Z_]/.test(ch)) {
330
+ let id = "";
331
+ while (i < expr.length && /[a-zA-Z0-9_]/.test(expr[i])) {
332
+ id += expr[i];
333
+ i++;
334
+ }
335
+ if (id === "SUM" && i < expr.length && expr[i] === "(") {
336
+ tokens.push({
337
+ type: "FUNC",
338
+ value: id
339
+ });
340
+ } else {
341
+ tokens.push({
342
+ type: "IDENT",
343
+ value: id
344
+ });
345
+ }
346
+ continue;
347
+ }
348
+ if ("+-*/".includes(ch)) {
349
+ tokens.push({
350
+ type: "OP",
351
+ value: ch
352
+ });
353
+ i++;
354
+ continue;
355
+ }
356
+ if (ch === "(") {
357
+ tokens.push({
358
+ type: "LPAREN",
359
+ value: ch
360
+ });
361
+ i++;
362
+ continue;
363
+ }
364
+ if (ch === ")") {
365
+ tokens.push({
366
+ type: "RPAREN",
367
+ value: ch
368
+ });
369
+ i++;
370
+ continue;
287
371
  }
288
- tokens.push({ type: "EOF", value: "" });
289
- return tokens;
372
+ if (ch === "[") {
373
+ tokens.push({
374
+ type: "LBRACKET",
375
+ value: ch
376
+ });
377
+ i++;
378
+ continue;
379
+ }
380
+ if (ch === "]") {
381
+ tokens.push({
382
+ type: "RBRACKET",
383
+ value: ch
384
+ });
385
+ i++;
386
+ continue;
387
+ }
388
+ if (ch === ".") {
389
+ tokens.push({
390
+ type: "DOT",
391
+ value: ch
392
+ });
393
+ i++;
394
+ continue;
395
+ }
396
+ if (ch === ",") {
397
+ tokens.push({
398
+ type: "COMMA",
399
+ value: ch
400
+ });
401
+ i++;
402
+ continue;
403
+ }
404
+ i++; // skip unknown
405
+ }
406
+ tokens.push({
407
+ type: "EOF",
408
+ value: ""
409
+ });
410
+ return tokens;
290
411
  }
412
+
291
413
  // Recursive descent parser
292
414
  class ExprParser {
293
- tokens;
294
- ctx;
295
- pos = 0;
296
- constructor(tokens, ctx) {
297
- this.tokens = tokens;
298
- this.ctx = ctx;
299
- }
300
- peek() { return this.tokens[this.pos] || { type: "EOF", value: "" }; }
301
- advance() { return this.tokens[this.pos++]; }
302
- parse() {
303
- const val = this.expr();
304
- return val;
305
- }
306
- expr() {
307
- let left = this.term();
308
- while (this.peek().type === "OP" && (this.peek().value === "+" || this.peek().value === "-")) {
309
- const op = this.advance().value;
310
- const right = this.term();
311
- left = op === "+" ? left + right : left - right;
312
- }
313
- return left;
314
- }
315
- term() {
316
- let left = this.unary();
317
- while (this.peek().type === "OP" && (this.peek().value === "*" || this.peek().value === "/")) {
318
- const op = this.advance().value;
319
- const right = this.unary();
320
- left = op === "*" ? left * right : (right !== 0 ? left / right : 0);
321
- }
322
- return left;
415
+ pos = 0;
416
+ constructor(tokens, ctx) {
417
+ this.tokens = tokens;
418
+ this.ctx = ctx;
419
+ }
420
+ peek() {
421
+ return this.tokens[this.pos] || {
422
+ type: "EOF",
423
+ value: ""
424
+ };
425
+ }
426
+ advance() {
427
+ return this.tokens[this.pos++];
428
+ }
429
+ parse() {
430
+ const val = this.expr();
431
+ return val;
432
+ }
433
+ expr() {
434
+ let left = this.term();
435
+ while (this.peek().type === "OP" && (this.peek().value === "+" || this.peek().value === "-")) {
436
+ const op = this.advance().value;
437
+ const right = this.term();
438
+ left = op === "+" ? left + right : left - right;
323
439
  }
324
- unary() {
325
- if (this.peek().type === "OP" && this.peek().value === "-") {
326
- this.advance();
327
- return -this.primary();
328
- }
329
- return this.primary();
440
+ return left;
441
+ }
442
+ term() {
443
+ let left = this.unary();
444
+ while (this.peek().type === "OP" && (this.peek().value === "*" || this.peek().value === "/")) {
445
+ const op = this.advance().value;
446
+ const right = this.unary();
447
+ left = op === "*" ? left * right : right !== 0 ? left / right : 0;
330
448
  }
331
- primary() {
332
- const tok = this.peek();
333
- if (tok.type === "NUMBER") {
334
- this.advance();
335
- return parseFloat(tok.value);
336
- }
337
- if (tok.type === "LPAREN") {
338
- this.advance();
339
- const val = this.expr();
340
- if (this.peek().type === "RPAREN")
341
- this.advance();
342
- return val;
343
- }
344
- // SUM(array[].field)
345
- if (tok.type === "FUNC" && tok.value === "SUM") {
346
- this.advance(); // SUM
347
- if (this.peek().type === "LPAREN")
348
- this.advance(); // (
349
- // Parse: arrayName[].fieldName
350
- const arrayName = this.advance().value; // identifier
351
- if (this.peek().type === "LBRACKET") {
352
- this.advance(); // [
353
- if (this.peek().type === "RBRACKET")
354
- this.advance(); // ]
355
- }
356
- if (this.peek().type === "DOT")
357
- this.advance(); // .
358
- const fieldName = this.advance().value; // field
359
- if (this.peek().type === "RPAREN")
360
- this.advance(); // )
361
- const arr = this.ctx[arrayName];
362
- if (!Array.isArray(arr))
363
- return 0;
364
- let sum = 0;
365
- for (const item of arr) {
366
- const v = item[fieldName];
367
- if (typeof v === "number")
368
- sum += v;
369
- }
370
- return sum;
371
- }
372
- // Identifier — resolve from context
373
- if (tok.type === "IDENT") {
374
- this.advance();
375
- const val = this.ctx[tok.value];
376
- if (typeof val === "number")
377
- return val;
378
- if (typeof val === "string") {
379
- const n = parseFloat(val);
380
- return isNaN(n) ? 0 : n;
381
- }
382
- return 0;
383
- }
384
- // Fallback
385
- this.advance();
386
- return 0;
449
+ return left;
450
+ }
451
+ unary() {
452
+ if (this.peek().type === "OP" && this.peek().value === "-") {
453
+ this.advance();
454
+ return -this.primary();
455
+ }
456
+ return this.primary();
457
+ }
458
+ primary() {
459
+ const tok = this.peek();
460
+ if (tok.type === "NUMBER") {
461
+ this.advance();
462
+ return parseFloat(tok.value);
463
+ }
464
+ if (tok.type === "LPAREN") {
465
+ this.advance();
466
+ const val = this.expr();
467
+ if (this.peek().type === "RPAREN") this.advance();
468
+ return val;
387
469
  }
470
+
471
+ // SUM(array[].field)
472
+ if (tok.type === "FUNC" && tok.value === "SUM") {
473
+ this.advance(); // SUM
474
+ if (this.peek().type === "LPAREN") this.advance(); // (
475
+ // Parse: arrayName[].fieldName
476
+ const arrayName = this.advance().value; // identifier
477
+ if (this.peek().type === "LBRACKET") {
478
+ this.advance(); // [
479
+ if (this.peek().type === "RBRACKET") this.advance(); // ]
480
+ }
481
+ if (this.peek().type === "DOT") this.advance(); // .
482
+ const fieldName = this.advance().value; // field
483
+ if (this.peek().type === "RPAREN") this.advance(); // )
484
+
485
+ const arr = this.ctx[arrayName];
486
+ if (!Array.isArray(arr)) return 0;
487
+ let sum = 0;
488
+ for (const item of arr) {
489
+ const v = item[fieldName];
490
+ if (typeof v === "number") sum += v;
491
+ }
492
+ return sum;
493
+ }
494
+
495
+ // Identifier — resolve from context
496
+ if (tok.type === "IDENT") {
497
+ this.advance();
498
+ const val = this.ctx[tok.value];
499
+ if (typeof val === "number") return val;
500
+ if (typeof val === "string") {
501
+ const n = parseFloat(val);
502
+ return isNaN(n) ? 0 : n;
503
+ }
504
+ return 0;
505
+ }
506
+
507
+ // Fallback
508
+ this.advance();
509
+ return 0;
510
+ }
388
511
  }
389
512
  function safeEval(expr, ctx) {
390
- const tokens = tokenize(expr);
391
- const parser = new ExprParser(tokens, ctx);
392
- return parser.parse();
513
+ const tokens = tokenize(expr);
514
+ const parser = new ExprParser(tokens, ctx);
515
+ return parser.parse();
516
+ }
517
+ function normalizeCalculations(raw) {
518
+ if (!raw) return [];
519
+ if (Array.isArray(raw)) return raw;
520
+ if (typeof raw === "object") {
521
+ return Object.entries(raw).map(([field, formula]) => ({
522
+ field,
523
+ formula: String(formula)
524
+ }));
525
+ }
526
+ return [];
393
527
  }
394
528
  export function applyCalculations(calculations, constants, data) {
395
- if (!calculations || !Array.isArray(calculations))
396
- return data;
397
- const result = { ...data };
398
- // Flatten constants into context
399
- const ctx = { ...result };
400
- for (const [k, v] of Object.entries(constants)) {
401
- if (typeof v === "number" || typeof v === "string") {
402
- ctx[k] = v;
403
- }
529
+ const normalized = normalizeCalculations(calculations);
530
+ if (!normalized.length) return data;
531
+ const result = {
532
+ ...data
533
+ };
534
+
535
+ // Flatten constants into context
536
+ const ctx = {
537
+ ...result
538
+ };
539
+ for (const [k, v] of Object.entries(constants)) {
540
+ if (typeof v === "number" || typeof v === "string") {
541
+ ctx[k] = v;
404
542
  }
405
- // Multi-pass (max 3) for inter-formula dependencies
406
- for (let pass = 0; pass < 3; pass++) {
407
- let changed = false;
408
- for (const calc of calculations) {
409
- try {
410
- const val = safeEval(calc.formula, ctx);
411
- const rounded = parseFloat(val.toFixed(calc.decimals ?? 3));
412
- if (ctx[calc.field] !== rounded) {
413
- ctx[calc.field] = rounded;
414
- result[calc.field] = rounded;
415
- changed = true;
416
- }
417
- }
418
- catch {
419
- // Skip failed calculations
420
- }
543
+ }
544
+
545
+ // Multi-pass (max 3) for inter-formula dependencies
546
+ for (let pass = 0; pass < 3; pass++) {
547
+ let changed = false;
548
+ for (const calc of normalized) {
549
+ try {
550
+ const val = safeEval(calc.formula, ctx);
551
+ const rounded = parseFloat(val.toFixed(calc.decimals ?? 3));
552
+ if (ctx[calc.field] !== rounded) {
553
+ ctx[calc.field] = rounded;
554
+ result[calc.field] = rounded;
555
+ changed = true;
421
556
  }
422
- if (!changed)
423
- break;
557
+ } catch {
558
+ // Skip failed calculations
559
+ }
424
560
  }
425
- return result;
561
+ if (!changed) break;
562
+ }
563
+ return result;
426
564
  }
565
+
566
+ // ============================================================================
567
+ // 4. VALIDATION ENGINE — evaluates formula strings from pdf_templates.validation_rules
568
+ // ============================================================================
569
+
570
+ // Tokenizer for boolean expressions
571
+
427
572
  function tokenizeBool(expr) {
428
- const tokens = [];
429
- let i = 0;
430
- while (i < expr.length) {
431
- const ch = expr[i];
432
- if (/\s/.test(ch)) {
433
- i++;
434
- continue;
435
- }
436
- if (/[0-9.]/.test(ch)) {
437
- let num = "";
438
- while (i < expr.length && /[0-9.]/.test(expr[i])) {
439
- num += expr[i];
440
- i++;
441
- }
442
- tokens.push({ type: "NUMBER", value: num });
443
- continue;
444
- }
445
- if (/[a-zA-Z_]/.test(ch)) {
446
- let id = "";
447
- while (i < expr.length && /[a-zA-Z0-9_]/.test(expr[i])) {
448
- id += expr[i];
449
- i++;
450
- }
451
- if (id === "AND" || id === "OR") {
452
- tokens.push({ type: "LOGIC", value: id });
453
- }
454
- else {
455
- tokens.push({ type: "IDENT", value: id });
456
- }
457
- continue;
458
- }
459
- // Comparison operators
460
- if (ch === "<" || ch === ">" || ch === "=" || ch === "!") {
461
- let op = ch;
462
- i++;
463
- if (i < expr.length && expr[i] === "=") {
464
- op += "=";
465
- i++;
466
- }
467
- else if (ch === "=" && i < expr.length && expr[i] === "=") {
468
- op += "=";
469
- i++;
470
- }
471
- tokens.push({ type: "CMP", value: op });
472
- continue;
473
- }
474
- if ("+-*/".includes(ch)) {
475
- tokens.push({ type: "OP", value: ch });
476
- i++;
477
- continue;
478
- }
479
- if (ch === "(") {
480
- tokens.push({ type: "LPAREN", value: ch });
481
- i++;
482
- continue;
483
- }
484
- if (ch === ")") {
485
- tokens.push({ type: "RPAREN", value: ch });
486
- i++;
487
- continue;
488
- }
573
+ const tokens = [];
574
+ let i = 0;
575
+ while (i < expr.length) {
576
+ const ch = expr[i];
577
+ if (/\s/.test(ch)) {
578
+ i++;
579
+ continue;
580
+ }
581
+ if (/[0-9]/.test(ch) || ch === "." && i + 1 < expr.length && /[0-9]/.test(expr[i + 1])) {
582
+ let num = "";
583
+ while (i < expr.length && /[0-9.]/.test(expr[i])) {
584
+ num += expr[i];
585
+ i++;
586
+ }
587
+ tokens.push({
588
+ type: "NUMBER",
589
+ value: num
590
+ });
591
+ continue;
592
+ }
593
+ if (/[a-zA-Z_]/.test(ch)) {
594
+ let id = "";
595
+ while (i < expr.length && /[a-zA-Z0-9_]/.test(expr[i])) {
596
+ id += expr[i];
597
+ i++;
598
+ }
599
+ if (id === "AND" || id === "OR") {
600
+ tokens.push({
601
+ type: "LOGIC",
602
+ value: id
603
+ });
604
+ } else {
605
+ tokens.push({
606
+ type: "IDENT",
607
+ value: id
608
+ });
609
+ }
610
+ continue;
611
+ }
612
+ // Comparison operators
613
+ if (ch === "<" || ch === ">" || ch === "=" || ch === "!") {
614
+ let op = ch;
615
+ i++;
616
+ if (i < expr.length && expr[i] === "=") {
617
+ op += "=";
618
+ i++;
619
+ } else if (ch === "=" && i < expr.length && expr[i] === "=") {
620
+ op += "=";
489
621
  i++;
622
+ }
623
+ tokens.push({
624
+ type: "CMP",
625
+ value: op
626
+ });
627
+ continue;
628
+ }
629
+ if ("+-*/".includes(ch)) {
630
+ tokens.push({
631
+ type: "OP",
632
+ value: ch
633
+ });
634
+ i++;
635
+ continue;
636
+ }
637
+ if (ch === "(") {
638
+ tokens.push({
639
+ type: "LPAREN",
640
+ value: ch
641
+ });
642
+ i++;
643
+ continue;
644
+ }
645
+ if (ch === ")") {
646
+ tokens.push({
647
+ type: "RPAREN",
648
+ value: ch
649
+ });
650
+ i++;
651
+ continue;
490
652
  }
491
- tokens.push({ type: "EOF", value: "" });
492
- return tokens;
653
+ i++;
654
+ }
655
+ tokens.push({
656
+ type: "EOF",
657
+ value: ""
658
+ });
659
+ return tokens;
493
660
  }
494
661
  function evalBoolExpr(expr, ctx) {
495
- const tokens = tokenizeBool(expr);
496
- let pos = 0;
497
- function peek() { return tokens[pos] || { type: "EOF", value: "" }; }
498
- function advance() { return tokens[pos++]; }
499
- function numericValue() {
500
- const tok = peek();
501
- if (tok.type === "NUMBER") {
502
- advance();
503
- return parseFloat(tok.value);
504
- }
505
- if (tok.type === "IDENT") {
506
- advance();
507
- const v = ctx[tok.value];
508
- return typeof v === "number" ? v : (typeof v === "string" ? parseFloat(v) || 0 : 0);
509
- }
510
- if (tok.type === "LPAREN") {
511
- advance();
512
- const val = numericExpr();
513
- if (peek().type === "RPAREN")
514
- advance();
515
- return val;
516
- }
517
- advance();
518
- return 0;
519
- }
520
- function numericExpr() {
521
- let left = numericTerm();
522
- while (peek().type === "OP" && (peek().value === "+" || peek().value === "-")) {
523
- const op = advance().value;
524
- const right = numericTerm();
525
- left = op === "+" ? left + right : left - right;
526
- }
527
- return left;
528
- }
529
- function numericTerm() {
530
- let left = numericValue();
531
- while (peek().type === "OP" && (peek().value === "*" || peek().value === "/")) {
532
- const op = advance().value;
533
- const right = numericValue();
534
- left = op === "*" ? left * right : (right !== 0 ? left / right : 0);
535
- }
536
- return left;
537
- }
538
- function comparison() {
539
- const left = numericExpr();
540
- const tok = peek();
541
- if (tok.type === "CMP") {
542
- const op = advance().value;
543
- const right = numericExpr();
544
- switch (op) {
545
- case "<": return left < right;
546
- case "<=": return left <= right;
547
- case ">": return left > right;
548
- case ">=": return left >= right;
549
- case "==": return Math.abs(left - right) < 1e-9;
550
- case "!=": return Math.abs(left - right) >= 1e-9;
551
- default: return false;
552
- }
553
- }
554
- // Truthy check if no comparison operator
555
- return left !== 0;
556
- }
557
- function boolExpr() {
558
- let left = comparison();
559
- while (peek().type === "LOGIC") {
560
- const op = advance().value;
561
- const right = comparison();
562
- if (op === "AND")
563
- left = left && right;
564
- else if (op === "OR")
565
- left = left || right;
566
- }
567
- return left;
662
+ const tokens = tokenizeBool(expr);
663
+ let pos = 0;
664
+ function peek() {
665
+ return tokens[pos] || {
666
+ type: "EOF",
667
+ value: ""
668
+ };
669
+ }
670
+ function advance() {
671
+ return tokens[pos++];
672
+ }
673
+ function numericValue() {
674
+ const tok = peek();
675
+ if (tok.type === "NUMBER") {
676
+ advance();
677
+ return parseFloat(tok.value);
678
+ }
679
+ if (tok.type === "IDENT") {
680
+ advance();
681
+ const v = ctx[tok.value];
682
+ return typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) || 0 : 0;
683
+ }
684
+ if (tok.type === "LPAREN") {
685
+ advance();
686
+ const val = numericExpr();
687
+ if (peek().type === "RPAREN") advance();
688
+ return val;
689
+ }
690
+ advance();
691
+ return 0;
692
+ }
693
+ function numericExpr() {
694
+ let left = numericTerm();
695
+ while (peek().type === "OP" && (peek().value === "+" || peek().value === "-")) {
696
+ const op = advance().value;
697
+ const right = numericTerm();
698
+ left = op === "+" ? left + right : left - right;
699
+ }
700
+ return left;
701
+ }
702
+ function numericTerm() {
703
+ let left = numericValue();
704
+ while (peek().type === "OP" && (peek().value === "*" || peek().value === "/")) {
705
+ const op = advance().value;
706
+ const right = numericValue();
707
+ left = op === "*" ? left * right : right !== 0 ? left / right : 0;
568
708
  }
569
- return boolExpr();
709
+ return left;
710
+ }
711
+ function comparison() {
712
+ const left = numericExpr();
713
+ const tok = peek();
714
+ if (tok.type === "CMP") {
715
+ const op = advance().value;
716
+ const right = numericExpr();
717
+ switch (op) {
718
+ case "<":
719
+ return left < right;
720
+ case "<=":
721
+ return left <= right;
722
+ case ">":
723
+ return left > right;
724
+ case ">=":
725
+ return left >= right;
726
+ case "==":
727
+ return Math.abs(left - right) < 1e-9;
728
+ case "!=":
729
+ return Math.abs(left - right) >= 1e-9;
730
+ default:
731
+ return false;
732
+ }
733
+ }
734
+ // Truthy check if no comparison operator
735
+ return left !== 0;
736
+ }
737
+ function boolExpr() {
738
+ let left = comparison();
739
+ while (peek().type === "LOGIC") {
740
+ const op = advance().value;
741
+ const right = comparison();
742
+ if (op === "AND") left = left && right;else if (op === "OR") left = left || right;
743
+ }
744
+ return left;
745
+ }
746
+ return boolExpr();
570
747
  }
571
748
  export function runValidation(rules, data) {
572
- if (!rules || !Array.isArray(rules))
573
- return [];
574
- const results = [];
575
- for (const rule of rules) {
576
- try {
577
- const passed = evalBoolExpr(rule.formula, data);
578
- results.push({ name: rule.name, severity: rule.severity, message: rule.message, passed });
579
- }
580
- catch {
581
- results.push({ name: rule.name, severity: rule.severity, message: rule.message, passed: false });
582
- }
749
+ if (!rules || !Array.isArray(rules)) return [];
750
+ const results = [];
751
+ for (const rule of rules) {
752
+ try {
753
+ const passed = evalBoolExpr(rule.formula, data);
754
+ results.push({
755
+ name: rule.name,
756
+ severity: rule.severity,
757
+ message: rule.message,
758
+ passed
759
+ });
760
+ } catch {
761
+ results.push({
762
+ name: rule.name,
763
+ severity: rule.severity,
764
+ message: rule.message,
765
+ passed: false
766
+ });
583
767
  }
584
- return results;
768
+ }
769
+ return results;
585
770
  }
771
+
772
+ // ============================================================================
773
+ // 5. LAYOUT → HTML RENDERER
774
+ // ============================================================================
775
+
586
776
  export function resolveBinding(bind, data) {
587
- const parts = bind.split(".");
588
- let val = data;
589
- for (const p of parts) {
590
- if (val === null || val === undefined)
591
- return undefined;
592
- val = val[p];
593
- }
594
- return val;
777
+ const parts = bind.split(".");
778
+ let val = data;
779
+ for (const p of parts) {
780
+ if (val === null || val === undefined) return undefined;
781
+ val = val[p];
782
+ }
783
+ return val;
595
784
  }
596
785
  export function resolveText(text, data) {
597
- if (!text)
598
- return "";
599
- return fillTemplate(text, data);
786
+ if (!text) return "";
787
+ return fillTemplate(text, data);
600
788
  }
789
+
601
790
  // Minimal QR code generator — produces SVG rect elements for a text payload.
602
791
  // Uses a simple bit matrix approach sufficient for short strings (URLs, IDs).
603
792
  export function generateQRSvg(text, size = 100) {
604
- // Simple QR-like encoding: create a deterministic pattern from text hash
605
- // This generates a visually QR-like pattern (not scannable — for display purposes).
606
- // For real QR, the template data usually includes a pre-generated QR URL.
607
- const moduleCount = 21; // QR Version 1
608
- const cellSize = size / moduleCount;
609
- const modules = Array.from({ length: moduleCount }, () => Array(moduleCount).fill(false));
610
- // Finder patterns (top-left, top-right, bottom-left)
611
- const drawFinder = (row, col) => {
612
- for (let r = 0; r < 7; r++) {
613
- for (let c = 0; c < 7; c++) {
614
- const isEdge = r === 0 || r === 6 || c === 0 || c === 6;
615
- const isInner = r >= 2 && r <= 4 && c >= 2 && c <= 4;
616
- if (isEdge || isInner)
617
- modules[row + r][col + c] = true;
618
- }
619
- }
620
- };
621
- drawFinder(0, 0);
622
- drawFinder(0, moduleCount - 7);
623
- drawFinder(moduleCount - 7, 0);
624
- // Data area: hash the text and fill deterministically
625
- let hash = 0;
626
- for (let i = 0; i < text.length; i++) {
627
- hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0;
628
- }
629
- for (let r = 8; r < moduleCount; r++) {
630
- for (let c = 8; c < moduleCount; c++) {
631
- hash = ((hash << 5) - hash + r * 31 + c * 17) | 0;
632
- modules[r][c] = (hash & 1) === 1;
633
- }
793
+ // Simple QR-like encoding: create a deterministic pattern from text hash
794
+ // This generates a visually QR-like pattern (not scannable — for display purposes).
795
+ // For real QR, the template data usually includes a pre-generated QR URL.
796
+ const moduleCount = 21; // QR Version 1
797
+ const cellSize = size / moduleCount;
798
+ const modules = Array.from({
799
+ length: moduleCount
800
+ }, () => Array(moduleCount).fill(false));
801
+
802
+ // Finder patterns (top-left, top-right, bottom-left)
803
+ const drawFinder = (row, col) => {
804
+ for (let r = 0; r < 7; r++) {
805
+ for (let c = 0; c < 7; c++) {
806
+ const isEdge = r === 0 || r === 6 || c === 0 || c === 6;
807
+ const isInner = r >= 2 && r <= 4 && c >= 2 && c <= 4;
808
+ if (isEdge || isInner) modules[row + r][col + c] = true;
809
+ }
634
810
  }
635
- let rects = "";
636
- for (let r = 0; r < moduleCount; r++) {
637
- for (let c = 0; c < moduleCount; c++) {
638
- if (modules[r][c]) {
639
- rects += `<rect x="${c * cellSize}" y="${r * cellSize}" width="${cellSize}" height="${cellSize}" fill="#000"/>`;
640
- }
641
- }
811
+ };
812
+ drawFinder(0, 0);
813
+ drawFinder(0, moduleCount - 7);
814
+ drawFinder(moduleCount - 7, 0);
815
+
816
+ // Data area: hash the text and fill deterministically
817
+ let hash = 0;
818
+ for (let i = 0; i < text.length; i++) {
819
+ hash = (hash << 5) - hash + text.charCodeAt(i) | 0;
820
+ }
821
+ for (let r = 8; r < moduleCount; r++) {
822
+ for (let c = 8; c < moduleCount; c++) {
823
+ hash = (hash << 5) - hash + r * 31 + c * 17 | 0;
824
+ modules[r][c] = (hash & 1) === 1;
825
+ }
826
+ }
827
+ let rects = "";
828
+ for (let r = 0; r < moduleCount; r++) {
829
+ for (let c = 0; c < moduleCount; c++) {
830
+ if (modules[r][c]) {
831
+ rects += `<rect x="${c * cellSize}" y="${r * cellSize}" width="${cellSize}" height="${cellSize}" fill="#000"/>`;
832
+ }
642
833
  }
643
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}"><rect width="${size}" height="${size}" fill="#fff"/>${rects}</svg>`;
834
+ }
835
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}"><rect width="${size}" height="${size}" fill="#fff"/>${rects}</svg>`;
644
836
  }
645
837
  function renderElement(el, data) {
646
- switch (el.type) {
647
- case "text": {
648
- const text = resolveText(el.content || el.text || "", data);
649
- const styles = [];
650
- if (el.fontSize)
651
- styles.push(`font-size:${el.fontSize}px`);
652
- if (el.color)
653
- styles.push(`color:${el.color}`);
654
- if (el.bold)
655
- styles.push("font-weight:bold");
656
- if (el.align)
657
- styles.push(`text-align:${el.align}`);
658
- return `<div style="${styles.join(";")}">${text}</div>`;
659
- }
660
- case "header": {
661
- const text = resolveText(el.content || el.text || "", data);
662
- const styles = ["font-weight:bold"];
663
- if (el.backgroundColor)
664
- styles.push(`background-color:${el.backgroundColor}`);
665
- if (el.padding)
666
- styles.push(`padding:${typeof el.padding === "number" ? el.padding + "px" : el.padding}`);
667
- if (el.fontSize)
668
- styles.push(`font-size:${el.fontSize}px`);
669
- if (el.color)
670
- styles.push(`color:${el.color}`);
671
- if (el.align)
672
- styles.push(`text-align:${el.align}`);
673
- return `<div style="${styles.join(";")}">${text}</div>`;
674
- }
675
- case "image": {
676
- let src = el.src || el.url || "";
677
- if (el.bind) {
678
- const resolved = resolveBinding(el.bind, data);
679
- if (typeof resolved === "string")
680
- src = resolved;
681
- }
682
- const w = el.width ? `width:${typeof el.width === "number" ? el.width + "px" : el.width}` : "";
683
- const h = el.height ? `height:${typeof el.height === "number" ? el.height + "px" : el.height}` : "";
684
- return `<img src="${src}" style="${[w, h].filter(Boolean).join(";")}" />`;
685
- }
686
- case "qrcode": {
687
- let qrData = el.data || el.content || "";
688
- if (el.bind) {
689
- const resolved = resolveBinding(el.bind, data);
690
- if (typeof resolved === "string")
691
- qrData = resolved;
692
- }
693
- qrData = resolveText(qrData, data);
694
- const qrSize = el.size || (typeof el.width === "number" ? el.width : 100);
695
- const svg = generateQRSvg(qrData, qrSize);
696
- const dataUri = `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`;
697
- return `<img src="${dataUri}" width="${qrSize}" height="${qrSize}" />`;
698
- }
699
- case "spacer": {
700
- const h = el.height || 10;
701
- return `<div style="height:${typeof h === "number" ? h + "px" : h}"></div>`;
702
- }
703
- case "line": {
704
- const color = el.color || "#000";
705
- const thickness = el.thickness || 1;
706
- return `<hr style="border:none;border-top:${thickness}px solid ${color};margin:8px 0;" />`;
838
+ switch (el.type) {
839
+ case "text":
840
+ {
841
+ const text = resolveText(el.content || el.text || "", data);
842
+ const styles = [];
843
+ if (el.fontSize) styles.push(`font-size:${el.fontSize}px`);
844
+ if (el.color) styles.push(`color:${el.color}`);
845
+ if (el.bold) styles.push("font-weight:bold");
846
+ if (el.align) styles.push(`text-align:${el.align}`);
847
+ return `<div style="${styles.join(";")}">${text}</div>`;
848
+ }
849
+ case "header":
850
+ {
851
+ const text = resolveText(el.content || el.text || "", data);
852
+ const styles = ["font-weight:bold"];
853
+ if (el.backgroundColor) styles.push(`background-color:${el.backgroundColor}`);
854
+ if (el.padding) styles.push(`padding:${typeof el.padding === "number" ? el.padding + "px" : el.padding}`);
855
+ if (el.fontSize) styles.push(`font-size:${el.fontSize}px`);
856
+ if (el.color) styles.push(`color:${el.color}`);
857
+ if (el.align) styles.push(`text-align:${el.align}`);
858
+ return `<div style="${styles.join(";")}">${text}</div>`;
859
+ }
860
+ case "image":
861
+ {
862
+ let src = el.src || el.url || "";
863
+ if (el.bind) {
864
+ const resolved = resolveBinding(el.bind, data);
865
+ if (typeof resolved === "string") src = resolved;
707
866
  }
708
- case "columns": {
709
- const cols = el.columns || el.children || [];
710
- const inner = cols.map((child) => {
711
- // Support both: array of elements per column, or single element per column
712
- if (Array.isArray(child)) {
713
- return `<div style="flex:1">${child.map((c) => renderElement(c, data)).join("")}</div>`;
714
- }
715
- return `<div style="flex:1">${renderElement(child, data)}</div>`;
716
- }).join("");
717
- return `<div style="display:flex;gap:8px">${inner}</div>`;
718
- }
719
- case "page_break": {
720
- return `<div style="page-break-after:always"></div>`;
721
- }
722
- case "grid": {
723
- const items = (Array.isArray(el.items) ? el.items : Array.isArray(el.content) ? el.content : []);
724
- const gridRows = items.map((item) => {
725
- const label = item.label || item.value || "";
726
- let value = "";
727
- if (item.bind) {
728
- const resolved = resolveBinding(item.bind, data);
729
- value = resolved !== undefined && resolved !== null ? String(resolved) : "";
730
- }
731
- value = resolveText(value || "", data);
732
- return `<tr><td style="padding:4px 8px;font-weight:bold;white-space:nowrap;width:40%">${label}</td><td style="padding:4px 8px">${value}</td></tr>`;
733
- }).join("");
734
- return `<table style="width:100%;border-collapse:collapse">${gridRows}</table>`;
735
- }
736
- case "table": {
737
- const headers = el.headers || [];
738
- const rowFields = el.row_fields;
739
- const thead = headers.length
740
- ? `<thead><tr>${headers.map(h => `<th style="padding:6px 8px;border:1px solid #ddd;background:#f5f5f5;text-align:left;font-size:8px">${h}</th>`).join("")}</tr></thead>`
741
- : "";
742
- let bodyRows = el.rows || [];
743
- if (el.bind) {
744
- const resolved = resolveBinding(el.bind, data);
745
- if (Array.isArray(resolved))
746
- bodyRows = resolved;
747
- }
748
- const tbody = bodyRows.map((row) => {
749
- if (Array.isArray(row)) {
750
- return `<tr>${row.map(cell => `<td style="padding:5px 8px;border:1px solid #ddd;font-size:8px">${cell ?? ""}</td>`).join("")}</tr>`;
751
- }
752
- // Object row — use row_fields if provided, else fall back to header matching
753
- if (rowFields && rowFields.length) {
754
- return `<tr>${rowFields.map(field => {
755
- const val = row[field] ?? "";
756
- return `<td style="padding:5px 8px;border:1px solid #ddd;font-size:8px">${val}</td>`;
757
- }).join("")}</tr>`;
758
- }
759
- return `<tr>${headers.map(h => {
760
- const key = h.toLowerCase().replace(/[^a-z0-9]/g, "");
761
- const val = row[h] ?? row[key] ?? row[h.replace(/\s+/g, "")] ?? "";
762
- return `<td style="padding:5px 8px;border:1px solid #ddd;font-size:8px">${val}</td>`;
763
- }).join("")}</tr>`;
764
- }).join("");
765
- return `<table style="width:100%;border-collapse:collapse">${thead}<tbody>${tbody}</tbody></table>`;
867
+ const w = el.width ? `width:${typeof el.width === "number" ? el.width + "px" : el.width}` : "";
868
+ const h = el.height ? `height:${typeof el.height === "number" ? el.height + "px" : el.height}` : "";
869
+ return `<img src="${src}" style="${[w, h].filter(Boolean).join(";")}" />`;
870
+ }
871
+ case "qrcode":
872
+ {
873
+ let qrData = el.data || el.content || "";
874
+ if (el.bind) {
875
+ const resolved = resolveBinding(el.bind, data);
876
+ if (typeof resolved === "string") qrData = resolved;
766
877
  }
767
- case "box": {
768
- const styles = ["text-align:center"];
769
- if (el.border)
770
- styles.push(`border:${el.border}`);
771
- if (el.background || el.backgroundColor)
772
- styles.push(`background:${el.background || el.backgroundColor}`);
773
- if (el.padding)
774
- styles.push(`padding:${typeof el.padding === "number" ? el.padding + "px" : el.padding}`);
775
- const inner = (el.children || []).map(child => renderElement(child, data)).join("");
776
- const text = el.content || el.text ? resolveText(el.content || el.text || "", data) : "";
777
- return `<div style="${styles.join(";")}">${text}${inner}</div>`;
878
+ qrData = resolveText(qrData, data);
879
+ const qrSize = el.size || (typeof el.width === "number" ? el.width : 100);
880
+ const svg = generateQRSvg(qrData, qrSize);
881
+ const dataUri = `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`;
882
+ return `<img src="${dataUri}" width="${qrSize}" height="${qrSize}" />`;
883
+ }
884
+ case "spacer":
885
+ {
886
+ const h = el.height || 10;
887
+ return `<div style="height:${typeof h === "number" ? h + "px" : h}"></div>`;
888
+ }
889
+ case "line":
890
+ {
891
+ const color = el.color || "#000";
892
+ const thickness = el.thickness || 1;
893
+ return `<hr style="border:none;border-top:${thickness}px solid ${color};margin:8px 0;" />`;
894
+ }
895
+ case "columns":
896
+ {
897
+ const cols = el.columns || el.children || [];
898
+ const inner = cols.map(child => {
899
+ // Support both: array of elements per column, or single element per column
900
+ if (Array.isArray(child)) {
901
+ return `<div style="flex:1">${child.map(c => renderElement(c, data)).join("")}</div>`;
902
+ }
903
+ return `<div style="flex:1">${renderElement(child, data)}</div>`;
904
+ }).join("");
905
+ return `<div style="display:flex;gap:8px">${inner}</div>`;
906
+ }
907
+ case "page_break":
908
+ {
909
+ return `<div style="page-break-after:always"></div>`;
910
+ }
911
+ case "grid":
912
+ {
913
+ const items = Array.isArray(el.items) ? el.items : Array.isArray(el.content) ? el.content : [];
914
+ const gridRows = items.map(item => {
915
+ const label = item.label || item.value || "";
916
+ let value = "";
917
+ if (item.bind) {
918
+ const resolved = resolveBinding(item.bind, data);
919
+ value = resolved !== undefined && resolved !== null ? String(resolved) : "";
920
+ }
921
+ value = resolveText(value || "", data);
922
+ return `<tr><td style="padding:4px 8px;font-weight:bold;white-space:nowrap;width:40%">${label}</td><td style="padding:4px 8px">${value}</td></tr>`;
923
+ }).join("");
924
+ return `<table style="width:100%;border-collapse:collapse">${gridRows}</table>`;
925
+ }
926
+ case "table":
927
+ {
928
+ const headers = el.headers || [];
929
+ const rowFields = el.row_fields;
930
+ const thead = headers.length ? `<thead><tr>${headers.map(h => `<th style="padding:6px 8px;border:1px solid #ddd;background:#f5f5f5;text-align:left;font-size:8px">${h}</th>`).join("")}</tr></thead>` : "";
931
+ let bodyRows = el.rows || [];
932
+ if (el.bind) {
933
+ const resolved = resolveBinding(el.bind, data);
934
+ if (Array.isArray(resolved)) bodyRows = resolved;
778
935
  }
779
- default: {
780
- // Unknown element — try to render children
781
- if (el.children && Array.isArray(el.children)) {
782
- return el.children.map(child => renderElement(child, data)).join("");
783
- }
784
- return "";
936
+ const tbody = bodyRows.map(row => {
937
+ if (Array.isArray(row)) {
938
+ return `<tr>${row.map(cell => `<td style="padding:5px 8px;border:1px solid #ddd;font-size:8px">${cell ?? ""}</td>`).join("")}</tr>`;
939
+ }
940
+ // Object row — use row_fields if provided, else fall back to header matching
941
+ if (rowFields && rowFields.length) {
942
+ return `<tr>${rowFields.map(field => {
943
+ const val = row[field] ?? "";
944
+ return `<td style="padding:5px 8px;border:1px solid #ddd;font-size:8px">${val}</td>`;
945
+ }).join("")}</tr>`;
946
+ }
947
+ return `<tr>${headers.map(h => {
948
+ const key = h.toLowerCase().replace(/[^a-z0-9]/g, "");
949
+ const val = row[h] ?? row[key] ?? row[h.replace(/\s+/g, "")] ?? "";
950
+ return `<td style="padding:5px 8px;border:1px solid #ddd;font-size:8px">${val}</td>`;
951
+ }).join("")}</tr>`;
952
+ }).join("");
953
+ return `<table style="width:100%;border-collapse:collapse">${thead}<tbody>${tbody}</tbody></table>`;
954
+ }
955
+ case "box":
956
+ {
957
+ const styles = ["text-align:center"];
958
+ if (el.border) styles.push(`border:${el.border}`);
959
+ if (el.background || el.backgroundColor) styles.push(`background:${el.background || el.backgroundColor}`);
960
+ if (el.padding) styles.push(`padding:${typeof el.padding === "number" ? el.padding + "px" : el.padding}`);
961
+ const inner = (el.children || []).map(child => renderElement(child, data)).join("");
962
+ const text = el.content || el.text ? resolveText(el.content || el.text || "", data) : "";
963
+ return `<div style="${styles.join(";")}">${text}${inner}</div>`;
964
+ }
965
+ default:
966
+ {
967
+ // Unknown element — try to render children
968
+ if (el.children && Array.isArray(el.children)) {
969
+ return el.children.map(child => renderElement(child, data)).join("");
785
970
  }
786
- }
971
+ return "";
972
+ }
973
+ }
787
974
  }
788
975
  export function renderLayoutToHtml(layout, pageConfig, styles, data) {
789
- const pageSize = pageConfig?.size || "A4";
790
- const margins = pageConfig?.margins || { top: "15mm", right: "15mm", bottom: "15mm", left: "15mm" };
791
- const fontFamily = styles?.fontFamily || "Helvetica, Arial, sans-serif";
792
- const fontSize = styles?.fontSize || 12;
793
- const color = styles?.color || "#000";
794
- // Normalize layout to LayoutElement[]:
795
- // - Array → use directly
796
- // - Object with .pages flatten page sections (header/body/footer per page)
797
- // - Object with .sections/.children → unwrap
798
- // - Object with .header/.footer → wrap as elements
799
- let elements = [];
800
- if (Array.isArray(layout)) {
801
- elements = layout;
802
- }
803
- else if (layout && typeof layout === "object") {
804
- if (Array.isArray(layout.pages)) {
805
- for (const page of layout.pages) {
806
- if (page.header)
807
- elements.push(page.header);
808
- if (Array.isArray(page.body))
809
- elements.push(...page.body);
810
- else if (page.body)
811
- elements.push(page.body);
812
- if (Array.isArray(page.sections))
813
- elements.push(...page.sections);
814
- if (Array.isArray(page.elements))
815
- elements.push(...page.elements);
816
- if (page.footer)
817
- elements.push(page.footer);
818
- }
819
- }
820
- else if (Array.isArray(layout.sections)) {
821
- elements = layout.sections;
822
- }
823
- else if (Array.isArray(layout.children)) {
824
- elements = layout.children;
825
- }
826
- else {
827
- // Object with header/footer keys — wrap as single-element layout
828
- if (layout.header)
829
- elements.push(layout.header);
830
- if (layout.body) {
831
- const body = layout.body;
832
- if (Array.isArray(body))
833
- elements.push(...body);
834
- else
835
- elements.push(body);
836
- }
837
- if (layout.footer)
838
- elements.push(layout.footer);
839
- }
976
+ const pageSize = pageConfig?.size || "A4";
977
+ const margins = pageConfig?.margins || {
978
+ top: "15mm",
979
+ right: "15mm",
980
+ bottom: "15mm",
981
+ left: "15mm"
982
+ };
983
+ const fontFamily = styles?.fontFamily || "Helvetica, Arial, sans-serif";
984
+ const fontSize = styles?.fontSize || 12;
985
+ const color = styles?.color || "#000";
986
+
987
+ // Normalize layout to LayoutElement[]:
988
+ // - Array → use directly
989
+ // - Object with .pages → flatten page sections (header/body/footer per page)
990
+ // - Object with .sections/.children unwrap
991
+ // - Object with .header/.footer → wrap as elements
992
+ let elements = [];
993
+ if (Array.isArray(layout)) {
994
+ elements = layout;
995
+ } else if (layout && typeof layout === "object") {
996
+ if (Array.isArray(layout.pages)) {
997
+ for (const page of layout.pages) {
998
+ if (page.header) elements.push(page.header);
999
+ if (Array.isArray(page.body)) elements.push(...page.body);else if (page.body) elements.push(page.body);
1000
+ if (Array.isArray(page.sections)) elements.push(...page.sections);
1001
+ if (Array.isArray(page.elements)) elements.push(...page.elements);
1002
+ if (page.footer) elements.push(page.footer);
1003
+ }
1004
+ } else if (Array.isArray(layout.sections)) {
1005
+ elements = layout.sections;
1006
+ } else if (Array.isArray(layout.children)) {
1007
+ elements = layout.children;
1008
+ } else {
1009
+ // Object with header/footer keys — wrap as single-element layout
1010
+ if (layout.header) elements.push(layout.header);
1011
+ if (layout.body) {
1012
+ const body = layout.body;
1013
+ if (Array.isArray(body)) elements.push(...body);else elements.push(body);
1014
+ }
1015
+ if (layout.footer) elements.push(layout.footer);
840
1016
  }
841
- const bodyHtml = elements.map(el => renderElement(el, data)).join("\n");
842
- return `<!DOCTYPE html>
1017
+ }
1018
+ const bodyHtml = elements.map(el => renderElement(el, data)).join("\n");
1019
+ return `<!DOCTYPE html>
843
1020
  <html>
844
1021
  <head>
845
1022
  <meta charset="utf-8">
@@ -865,3 +1042,4 @@ ${bodyHtml}
865
1042
  </body>
866
1043
  </html>`;
867
1044
  }
1045
+ //# sourceMappingURL=pdf-renderer.js.map