flow-frame-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. package/README.md +64 -0
  2. package/dist/Dockerfile +86 -0
  3. package/dist/GPU_DEPLOYMENT_README.md +324 -0
  4. package/dist/OPS_AGENT_README.md +174 -0
  5. package/dist/README-H100-VM.md +192 -0
  6. package/dist/README-worker-pools.md +231 -0
  7. package/dist/README.md +8 -0
  8. package/dist/WEB-ELEMENT-REQUESTS-README.md +302 -0
  9. package/dist/append.d.ts +3 -0
  10. package/dist/append.d.ts.map +1 -0
  11. package/dist/append.js +42 -0
  12. package/dist/append.js.map +1 -0
  13. package/dist/audioRoutes.d.ts +2 -0
  14. package/dist/audioRoutes.d.ts.map +1 -0
  15. package/dist/audioRoutes.js +97 -0
  16. package/dist/audioRoutes.js.map +1 -0
  17. package/dist/augment-parallel.d.ts +6 -0
  18. package/dist/augment-parallel.d.ts.map +1 -0
  19. package/dist/augment-parallel.js +128 -0
  20. package/dist/augment-parallel.js.map +1 -0
  21. package/dist/augment-worker.d.ts +2 -0
  22. package/dist/augment-worker.d.ts.map +1 -0
  23. package/dist/augment-worker.js +100 -0
  24. package/dist/augment-worker.js.map +1 -0
  25. package/dist/browerRoutes.d.ts +2 -0
  26. package/dist/browerRoutes.d.ts.map +1 -0
  27. package/dist/browerRoutes.js +323 -0
  28. package/dist/browerRoutes.js.map +1 -0
  29. package/dist/browser-utils/utils.d.ts +6 -0
  30. package/dist/browser-utils/utils.d.ts.map +1 -0
  31. package/dist/browser-utils/utils.js +133 -0
  32. package/dist/browser-utils/utils.js.map +1 -0
  33. package/dist/capture_training_data_endpoints.d.ts +158 -0
  34. package/dist/capture_training_data_endpoints.d.ts.map +1 -0
  35. package/dist/capture_training_data_endpoints.js +1812 -0
  36. package/dist/capture_training_data_endpoints.js.map +1 -0
  37. package/dist/config.json +28 -0
  38. package/dist/configEndpoints.d.ts +2 -0
  39. package/dist/configEndpoints.d.ts.map +1 -0
  40. package/dist/configEndpoints.js +459 -0
  41. package/dist/configEndpoints.js.map +1 -0
  42. package/dist/constants.d.ts +109 -0
  43. package/dist/constants.d.ts.map +1 -0
  44. package/dist/constants.js +110 -0
  45. package/dist/constants.js.map +1 -0
  46. package/dist/docs/workflow_nodes.md +257 -0
  47. package/dist/download.d.ts +11 -0
  48. package/dist/download.d.ts.map +1 -0
  49. package/dist/download.js +31 -0
  50. package/dist/download.js.map +1 -0
  51. package/dist/download.py +61 -0
  52. package/dist/ecosystem.config.json +63 -0
  53. package/dist/email-body-extractor.d.ts +20 -0
  54. package/dist/email-body-extractor.d.ts.map +1 -0
  55. package/dist/email-body-extractor.js +103 -0
  56. package/dist/email-body-extractor.js.map +1 -0
  57. package/dist/express_util.d.ts +2 -0
  58. package/dist/express_util.d.ts.map +1 -0
  59. package/dist/express_util.js +30 -0
  60. package/dist/express_util.js.map +1 -0
  61. package/dist/extension/background.d.ts +2 -0
  62. package/dist/extension/background.d.ts.map +1 -0
  63. package/dist/extension/background.js +268 -0
  64. package/dist/extension/background.js.map +1 -0
  65. package/dist/extension/manifest.json +19 -0
  66. package/dist/extensionUtils.d.ts +2 -0
  67. package/dist/extensionUtils.d.ts.map +1 -0
  68. package/dist/extensionUtils.js +48 -0
  69. package/dist/extensionUtils.js.map +1 -0
  70. package/dist/filter-gmail-poller/README.md +320 -0
  71. package/dist/filter-gmail-poller/demo.d.ts +2 -0
  72. package/dist/filter-gmail-poller/demo.d.ts.map +1 -0
  73. package/dist/filter-gmail-poller/demo.js +79 -0
  74. package/dist/filter-gmail-poller/demo.js.map +1 -0
  75. package/dist/filter-gmail-poller/example-existing-app.d.ts +2 -0
  76. package/dist/filter-gmail-poller/example-existing-app.d.ts.map +1 -0
  77. package/dist/filter-gmail-poller/example-existing-app.js +72 -0
  78. package/dist/filter-gmail-poller/example-existing-app.js.map +1 -0
  79. package/dist/filter-gmail-poller/filter-gmail-poller.d.ts +160 -0
  80. package/dist/filter-gmail-poller/filter-gmail-poller.d.ts.map +1 -0
  81. package/dist/filter-gmail-poller/filter-gmail-poller.js +1048 -0
  82. package/dist/filter-gmail-poller/filter-gmail-poller.js.map +1 -0
  83. package/dist/filter-gmail-poller/index.d.ts +3 -0
  84. package/dist/filter-gmail-poller/index.d.ts.map +1 -0
  85. package/dist/filter-gmail-poller/index.js +18 -0
  86. package/dist/filter-gmail-poller/index.js.map +1 -0
  87. package/dist/filter-gmail-poller/manual-test.d.ts +2 -0
  88. package/dist/filter-gmail-poller/manual-test.d.ts.map +1 -0
  89. package/dist/filter-gmail-poller/manual-test.js +70 -0
  90. package/dist/filter-gmail-poller/manual-test.js.map +1 -0
  91. package/dist/filter-gmail-poller/poller-prompts.d.ts +12 -0
  92. package/dist/filter-gmail-poller/poller-prompts.d.ts.map +1 -0
  93. package/dist/filter-gmail-poller/poller-prompts.js +330 -0
  94. package/dist/filter-gmail-poller/poller-prompts.js.map +1 -0
  95. package/dist/filter-gmail-poller/test.js +69 -0
  96. package/dist/flowframe-auto-firebase-adminsdk.json +13 -0
  97. package/dist/gmail-poller/README-microsoft-email-poller.md +203 -0
  98. package/dist/gmail-poller/README.md +129 -0
  99. package/dist/gmail-poller/example.d.ts +5 -0
  100. package/dist/gmail-poller/example.d.ts.map +1 -0
  101. package/dist/gmail-poller/example.js +83 -0
  102. package/dist/gmail-poller/example.js.map +1 -0
  103. package/dist/gmail-poller/gmail-poller.d.ts +82 -0
  104. package/dist/gmail-poller/gmail-poller.d.ts.map +1 -0
  105. package/dist/gmail-poller/gmail-poller.js +455 -0
  106. package/dist/gmail-poller/gmail-poller.js.map +1 -0
  107. package/dist/gmail-poller/manual-test.d.ts +2 -0
  108. package/dist/gmail-poller/manual-test.d.ts.map +1 -0
  109. package/dist/gmail-poller/manual-test.js +37 -0
  110. package/dist/gmail-poller/manual-test.js.map +1 -0
  111. package/dist/gmail-poller/microsoft-email-example.d.ts +8 -0
  112. package/dist/gmail-poller/microsoft-email-example.d.ts.map +1 -0
  113. package/dist/gmail-poller/microsoft-email-example.js +58 -0
  114. package/dist/gmail-poller/microsoft-email-example.js.map +1 -0
  115. package/dist/gmail-poller/microsoft-email-poller.d.ts +73 -0
  116. package/dist/gmail-poller/microsoft-email-poller.d.ts.map +1 -0
  117. package/dist/gmail-poller/microsoft-email-poller.js +346 -0
  118. package/dist/gmail-poller/microsoft-email-poller.js.map +1 -0
  119. package/dist/gmail-poller/setup-auth.d.ts +3 -0
  120. package/dist/gmail-poller/setup-auth.d.ts.map +1 -0
  121. package/dist/gmail-poller/setup-auth.js +36 -0
  122. package/dist/gmail-poller/setup-auth.js.map +1 -0
  123. package/dist/gmail-poller/test.js +36 -0
  124. package/dist/index.d.ts +10 -0
  125. package/dist/index.d.ts.map +1 -0
  126. package/dist/index.js +28 -0
  127. package/dist/index.js.map +1 -0
  128. package/dist/inference/augment_levels.d.ts +2 -0
  129. package/dist/inference/augment_levels.d.ts.map +1 -0
  130. package/dist/inference/augment_levels.js +1 -0
  131. package/dist/inference/augment_levels.js.map +1 -0
  132. package/dist/inference/capture-overlay.d.ts +13 -0
  133. package/dist/inference/capture-overlay.d.ts.map +1 -0
  134. package/dist/inference/capture-overlay.js +355 -0
  135. package/dist/inference/capture-overlay.js.map +1 -0
  136. package/dist/inference/capturescreenshot.d.ts +12 -0
  137. package/dist/inference/capturescreenshot.d.ts.map +1 -0
  138. package/dist/inference/capturescreenshot.js +157 -0
  139. package/dist/inference/capturescreenshot.js.map +1 -0
  140. package/dist/jsonHandler.d.ts +37 -0
  141. package/dist/jsonHandler.d.ts.map +1 -0
  142. package/dist/jsonHandler.js +191 -0
  143. package/dist/jsonHandler.js.map +1 -0
  144. package/dist/localStorage.json +11 -0
  145. package/dist/media_data_endpoints.d.ts +2 -0
  146. package/dist/media_data_endpoints.d.ts.map +1 -0
  147. package/dist/media_data_endpoints.js +102 -0
  148. package/dist/media_data_endpoints.js.map +1 -0
  149. package/dist/operations/blender-ops.d.ts +4 -0
  150. package/dist/operations/blender-ops.d.ts.map +1 -0
  151. package/dist/operations/blender-ops.js +55 -0
  152. package/dist/operations/blender-ops.js.map +1 -0
  153. package/dist/operations.d.ts +34 -0
  154. package/dist/operations.d.ts.map +1 -0
  155. package/dist/operations.js +1514 -0
  156. package/dist/operations.js.map +1 -0
  157. package/dist/pdfRoutes.d.ts +2 -0
  158. package/dist/pdfRoutes.d.ts.map +1 -0
  159. package/dist/pdfRoutes.js +56 -0
  160. package/dist/pdfRoutes.js.map +1 -0
  161. package/dist/peers.d.ts +9 -0
  162. package/dist/peers.d.ts.map +1 -0
  163. package/dist/peers.js +70 -0
  164. package/dist/peers.js.map +1 -0
  165. package/dist/playparser.d.ts +2 -0
  166. package/dist/playparser.d.ts.map +1 -0
  167. package/dist/playparser.js +281 -0
  168. package/dist/playparser.js.map +1 -0
  169. package/dist/process.d.ts +4 -0
  170. package/dist/process.d.ts.map +1 -0
  171. package/dist/process.js +375 -0
  172. package/dist/process.js.map +1 -0
  173. package/dist/promptRoutes.d.ts +7 -0
  174. package/dist/promptRoutes.d.ts.map +1 -0
  175. package/dist/promptRoutes.js +68 -0
  176. package/dist/promptRoutes.js.map +1 -0
  177. package/dist/queueManager.d.ts +23 -0
  178. package/dist/queueManager.d.ts.map +1 -0
  179. package/dist/queueManager.js +96 -0
  180. package/dist/queueManager.js.map +1 -0
  181. package/dist/run-flow.d.ts +8 -0
  182. package/dist/run-flow.d.ts.map +1 -0
  183. package/dist/run-flow.js +220 -0
  184. package/dist/run-flow.js.map +1 -0
  185. package/dist/scraper.d.ts +2 -0
  186. package/dist/scraper.d.ts.map +1 -0
  187. package/dist/scraper.js +75 -0
  188. package/dist/scraper.js.map +1 -0
  189. package/dist/scraper_endpoints.d.ts +2 -0
  190. package/dist/scraper_endpoints.d.ts.map +1 -0
  191. package/dist/scraper_endpoints.js +40 -0
  192. package/dist/scraper_endpoints.js.map +1 -0
  193. package/dist/server.d.ts +2 -0
  194. package/dist/server.d.ts.map +1 -0
  195. package/dist/server.js +528 -0
  196. package/dist/server.js.map +1 -0
  197. package/dist/services/ModelContext.d.ts +7 -0
  198. package/dist/services/ModelContext.d.ts.map +1 -0
  199. package/dist/services/ModelContext.js +7 -0
  200. package/dist/services/ModelContext.js.map +1 -0
  201. package/dist/services/agenticUiPlanner.d.ts +27 -0
  202. package/dist/services/agenticUiPlanner.d.ts.map +1 -0
  203. package/dist/services/agenticUiPlanner.js +161 -0
  204. package/dist/services/agenticUiPlanner.js.map +1 -0
  205. package/dist/services/apiKeyService.d.ts +3 -0
  206. package/dist/services/apiKeyService.d.ts.map +1 -0
  207. package/dist/services/apiKeyService.js +7 -0
  208. package/dist/services/apiKeyService.js.map +1 -0
  209. package/dist/services/audioService.d.ts +10 -0
  210. package/dist/services/audioService.d.ts.map +1 -0
  211. package/dist/services/audioService.js +140 -0
  212. package/dist/services/audioService.js.map +1 -0
  213. package/dist/services/autoPromptOptimizer.d.ts +44 -0
  214. package/dist/services/autoPromptOptimizer.d.ts.map +1 -0
  215. package/dist/services/autoPromptOptimizer.js +344 -0
  216. package/dist/services/autoPromptOptimizer.js.map +1 -0
  217. package/dist/services/autoPromptOptimizer.manual-test.d.ts +2 -0
  218. package/dist/services/autoPromptOptimizer.manual-test.d.ts.map +1 -0
  219. package/dist/services/autoPromptOptimizer.manual-test.js +27 -0
  220. package/dist/services/autoPromptOptimizer.manual-test.js.map +1 -0
  221. package/dist/services/chainExecutor.d.ts +26 -0
  222. package/dist/services/chainExecutor.d.ts.map +1 -0
  223. package/dist/services/chainExecutor.js +399 -0
  224. package/dist/services/chainExecutor.js.map +1 -0
  225. package/dist/services/classifyImageQuestion.d.ts +55 -0
  226. package/dist/services/classifyImageQuestion.d.ts.map +1 -0
  227. package/dist/services/classifyImageQuestion.js +428 -0
  228. package/dist/services/classifyImageQuestion.js.map +1 -0
  229. package/dist/services/configuration/executor.d.ts +3 -0
  230. package/dist/services/configuration/executor.d.ts.map +1 -0
  231. package/dist/services/configuration/executor.js +795 -0
  232. package/dist/services/configuration/executor.js.map +1 -0
  233. package/dist/services/error.d.ts +13 -0
  234. package/dist/services/error.d.ts.map +1 -0
  235. package/dist/services/error.js +34 -0
  236. package/dist/services/error.js.map +1 -0
  237. package/dist/services/executor.d.ts +11 -0
  238. package/dist/services/executor.d.ts.map +1 -0
  239. package/dist/services/executor.js +1587 -0
  240. package/dist/services/executor.js.map +1 -0
  241. package/dist/services/extractPdf.d.ts +26 -0
  242. package/dist/services/extractPdf.d.ts.map +1 -0
  243. package/dist/services/extractPdf.js +256 -0
  244. package/dist/services/extractPdf.js.map +1 -0
  245. package/dist/services/generateJsTransformFromPrompt.d.ts +11 -0
  246. package/dist/services/generateJsTransformFromPrompt.d.ts.map +1 -0
  247. package/dist/services/generateJsTransformFromPrompt.js +328 -0
  248. package/dist/services/generateJsTransformFromPrompt.js.map +1 -0
  249. package/dist/services/localizeFirebaseMedia.d.ts +20 -0
  250. package/dist/services/localizeFirebaseMedia.d.ts.map +1 -0
  251. package/dist/services/localizeFirebaseMedia.js +135 -0
  252. package/dist/services/localizeFirebaseMedia.js.map +1 -0
  253. package/dist/services/polyfill_canvas.d.ts +2 -0
  254. package/dist/services/polyfill_canvas.d.ts.map +1 -0
  255. package/dist/services/polyfill_canvas.js +19 -0
  256. package/dist/services/polyfill_canvas.js.map +1 -0
  257. package/dist/services/promptRoutes.d.ts +7 -0
  258. package/dist/services/promptRoutes.d.ts.map +1 -0
  259. package/dist/services/promptRoutes.js +70 -0
  260. package/dist/services/promptRoutes.js.map +1 -0
  261. package/dist/services/runPrompt.d.ts +29 -0
  262. package/dist/services/runPrompt.d.ts.map +1 -0
  263. package/dist/services/runPrompt.js +232 -0
  264. package/dist/services/runPrompt.js.map +1 -0
  265. package/dist/services/schemaInference.d.ts +2 -0
  266. package/dist/services/schemaInference.d.ts.map +1 -0
  267. package/dist/services/schemaInference.js +17 -0
  268. package/dist/services/schemaInference.js.map +1 -0
  269. package/dist/services/self-learning/api.d.ts +2 -0
  270. package/dist/services/self-learning/api.d.ts.map +1 -0
  271. package/dist/services/self-learning/api.js +84 -0
  272. package/dist/services/self-learning/api.js.map +1 -0
  273. package/dist/services/self-learning/autolearn.d.ts +23 -0
  274. package/dist/services/self-learning/autolearn.d.ts.map +1 -0
  275. package/dist/services/self-learning/autolearn.js +308 -0
  276. package/dist/services/self-learning/autolearn.js.map +1 -0
  277. package/dist/services/self-learning/discover.d.ts +11 -0
  278. package/dist/services/self-learning/discover.d.ts.map +1 -0
  279. package/dist/services/self-learning/discover.js +446 -0
  280. package/dist/services/self-learning/discover.js.map +1 -0
  281. package/dist/services/self-learning/image.d.ts +10 -0
  282. package/dist/services/self-learning/image.d.ts.map +1 -0
  283. package/dist/services/self-learning/image.js +38 -0
  284. package/dist/services/self-learning/image.js.map +1 -0
  285. package/dist/services/self-learning/injest.d.ts +25 -0
  286. package/dist/services/self-learning/injest.d.ts.map +1 -0
  287. package/dist/services/self-learning/injest.js +110 -0
  288. package/dist/services/self-learning/injest.js.map +1 -0
  289. package/dist/services/self-learning/learn.d.ts +2 -0
  290. package/dist/services/self-learning/learn.d.ts.map +1 -0
  291. package/dist/services/self-learning/learn.js +145 -0
  292. package/dist/services/self-learning/learn.js.map +1 -0
  293. package/dist/services/self-learning/matcher.d.ts +2 -0
  294. package/dist/services/self-learning/matcher.d.ts.map +1 -0
  295. package/dist/services/self-learning/matcher.js +38 -0
  296. package/dist/services/self-learning/matcher.js.map +1 -0
  297. package/dist/services/self-learning/openai.d.ts +8 -0
  298. package/dist/services/self-learning/openai.d.ts.map +1 -0
  299. package/dist/services/self-learning/openai.js +97 -0
  300. package/dist/services/self-learning/openai.js.map +1 -0
  301. package/dist/services/self-learning/phash.d.ts +5 -0
  302. package/dist/services/self-learning/phash.d.ts.map +1 -0
  303. package/dist/services/self-learning/phash.js +68 -0
  304. package/dist/services/self-learning/phash.js.map +1 -0
  305. package/dist/services/self-learning/recognize.d.ts +17 -0
  306. package/dist/services/self-learning/recognize.d.ts.map +1 -0
  307. package/dist/services/self-learning/recognize.js +116 -0
  308. package/dist/services/self-learning/recognize.js.map +1 -0
  309. package/dist/services/self-learning/record_transition.d.ts +8 -0
  310. package/dist/services/self-learning/record_transition.d.ts.map +1 -0
  311. package/dist/services/self-learning/record_transition.js +20 -0
  312. package/dist/services/self-learning/record_transition.js.map +1 -0
  313. package/dist/services/self-learning/registry.d.ts +4 -0
  314. package/dist/services/self-learning/registry.d.ts.map +1 -0
  315. package/dist/services/self-learning/registry.js +19 -0
  316. package/dist/services/self-learning/registry.js.map +1 -0
  317. package/dist/services/self-learning/schema.d.ts +114 -0
  318. package/dist/services/self-learning/schema.d.ts.map +1 -0
  319. package/dist/services/self-learning/schema.js +70 -0
  320. package/dist/services/self-learning/schema.js.map +1 -0
  321. package/dist/services/self-learning/schemaStrictify.d.ts +2 -0
  322. package/dist/services/self-learning/schemaStrictify.d.ts.map +1 -0
  323. package/dist/services/self-learning/schemaStrictify.js +34 -0
  324. package/dist/services/self-learning/schemaStrictify.js.map +1 -0
  325. package/dist/services/self-learning/transition_graph.d.ts +6 -0
  326. package/dist/services/self-learning/transition_graph.d.ts.map +1 -0
  327. package/dist/services/self-learning/transition_graph.js +83 -0
  328. package/dist/services/self-learning/transition_graph.js.map +1 -0
  329. package/dist/services/self-learning/transition_log.d.ts +3 -0
  330. package/dist/services/self-learning/transition_log.d.ts.map +1 -0
  331. package/dist/services/self-learning/transition_log.js +42 -0
  332. package/dist/services/self-learning/transition_log.js.map +1 -0
  333. package/dist/services/self-learning/util.d.ts +3 -0
  334. package/dist/services/self-learning/util.d.ts.map +1 -0
  335. package/dist/services/self-learning/util.js +11 -0
  336. package/dist/services/self-learning/util.js.map +1 -0
  337. package/dist/services/stepByStepAiPlanner.d.ts +39 -0
  338. package/dist/services/stepByStepAiPlanner.d.ts.map +1 -0
  339. package/dist/services/stepByStepAiPlanner.js +379 -0
  340. package/dist/services/stepByStepAiPlanner.js.map +1 -0
  341. package/dist/services/test-genjs.js +39 -0
  342. package/dist/services/test-genjs.manual-test.d.ts +2 -0
  343. package/dist/services/test-genjs.manual-test.d.ts.map +1 -0
  344. package/dist/services/test-genjs.manual-test.js +40 -0
  345. package/dist/services/test-genjs.manual-test.js.map +1 -0
  346. package/dist/services/uiMapPathFinder.d.ts +13 -0
  347. package/dist/services/uiMapPathFinder.d.ts.map +1 -0
  348. package/dist/services/uiMapPathFinder.js +79 -0
  349. package/dist/services/uiMapPathFinder.js.map +1 -0
  350. package/dist/services/uiMapService.d.ts +26 -0
  351. package/dist/services/uiMapService.d.ts.map +1 -0
  352. package/dist/services/uiMapService.js +275 -0
  353. package/dist/services/uiMapService.js.map +1 -0
  354. package/dist/services/uiPlanner.d.ts +54 -0
  355. package/dist/services/uiPlanner.d.ts.map +1 -0
  356. package/dist/services/uiPlanner.js +558 -0
  357. package/dist/services/uiPlanner.js.map +1 -0
  358. package/dist/services/utilityFunctions.d.ts +80 -0
  359. package/dist/services/utilityFunctions.d.ts.map +1 -0
  360. package/dist/services/utilityFunctions.js +352 -0
  361. package/dist/services/utilityFunctions.js.map +1 -0
  362. package/dist/services/variableGenerator.d.ts +39 -0
  363. package/dist/services/variableGenerator.d.ts.map +1 -0
  364. package/dist/services/variableGenerator.js +157 -0
  365. package/dist/services/variableGenerator.js.map +1 -0
  366. package/dist/services/workflow/build-workflow.d.ts +49 -0
  367. package/dist/services/workflow/build-workflow.d.ts.map +1 -0
  368. package/dist/services/workflow/build-workflow.js +119 -0
  369. package/dist/services/workflow/build-workflow.js.map +1 -0
  370. package/dist/standardRoutes.d.ts +2 -0
  371. package/dist/standardRoutes.d.ts.map +1 -0
  372. package/dist/standardRoutes.js +1495 -0
  373. package/dist/standardRoutes.js.map +1 -0
  374. package/dist/stepWorkflowRoutes.d.ts +2 -0
  375. package/dist/stepWorkflowRoutes.d.ts.map +1 -0
  376. package/dist/stepWorkflowRoutes.js +1007 -0
  377. package/dist/stepWorkflowRoutes.js.map +1 -0
  378. package/dist/storage.d.ts +19 -0
  379. package/dist/storage.d.ts.map +1 -0
  380. package/dist/storage.docker.json +61 -0
  381. package/dist/storage.js +131 -0
  382. package/dist/storage.js.map +1 -0
  383. package/dist/storage.json +78 -0
  384. package/dist/storage_cache/boxes.json +48 -0
  385. package/dist/storage_cache/suno_state.json +3 -0
  386. package/dist/suno_download.d.ts +11 -0
  387. package/dist/suno_download.d.ts.map +1 -0
  388. package/dist/suno_download.js +33 -0
  389. package/dist/suno_download.js.map +1 -0
  390. package/dist/suno_download.py +119 -0
  391. package/dist/test-web-element-requests.d.ts +6 -0
  392. package/dist/test-web-element-requests.d.ts.map +1 -0
  393. package/dist/test-web-element-requests.js +114 -0
  394. package/dist/test-web-element-requests.js.map +1 -0
  395. package/dist/test_pdf_render.d.ts +2 -0
  396. package/dist/test_pdf_render.d.ts.map +1 -0
  397. package/dist/test_pdf_render.js +50 -0
  398. package/dist/test_pdf_render.js.map +1 -0
  399. package/dist/training_data_viewer_endpoints.d.ts +2 -0
  400. package/dist/training_data_viewer_endpoints.d.ts.map +1 -0
  401. package/dist/training_data_viewer_endpoints.js +141 -0
  402. package/dist/training_data_viewer_endpoints.js.map +1 -0
  403. package/dist/utils.d.ts +353 -0
  404. package/dist/utils.d.ts.map +1 -0
  405. package/dist/utils.js +1517 -0
  406. package/dist/utils.js.map +1 -0
  407. package/dist/vm-h100.env.template +55 -0
  408. package/dist/web-element-requests.d.ts +102 -0
  409. package/dist/web-element-requests.d.ts.map +1 -0
  410. package/dist/web-element-requests.js +278 -0
  411. package/dist/web-element-requests.js.map +1 -0
  412. package/dist/workflowRoutes.d.ts +2 -0
  413. package/dist/workflowRoutes.d.ts.map +1 -0
  414. package/dist/workflowRoutes.js +441 -0
  415. package/dist/workflowRoutes.js.map +1 -0
  416. package/package.json +109 -0
@@ -0,0 +1,1048 @@
1
+ import { google } from 'googleapis';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { authenticate } from '@google-cloud/local-auth';
6
+ import express from 'express';
7
+ import cors from 'cors';
8
+ import os from 'os';
9
+ import { extractPdf } from '../services/extractPdf.js';
10
+ import { ensureDir, get } from '../utils.js';
11
+ import { KEYS } from '../constants.js';
12
+ // ES module equivalent of __dirname
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ // Gmail API scopes
16
+ const DEFAULT_SCOPES = [
17
+ 'https://www.googleapis.com/auth/gmail.readonly',
18
+ 'https://www.googleapis.com/auth/gmail.modify',
19
+ 'https://www.googleapis.com/auth/gmail.labels'
20
+ ];
21
+ const TEXT_MIME_PREFIXES = ['text/', 'application/json', 'application/xml'];
22
+ const TEXT_EXTENSIONS = ['.txt', '.md', '.csv', '.json', '.xml', '.log'];
23
+ class FilterGmailPoller {
24
+ static instance = null;
25
+ constructor(configPath = './config.json') {
26
+ this.configPath = configPath;
27
+ this.config = null;
28
+ this.gmail = null;
29
+ this.isAuthenticated = false;
30
+ this.pollingInterval = null;
31
+ this.emails = []; // In-memory storage for filtered emails
32
+ this.app = null;
33
+ this.server = null;
34
+ }
35
+ /**
36
+ * Load configuration from JSON file
37
+ */
38
+ async loadConfig() {
39
+ try {
40
+ const configData = await fs.readFile(this.configPath, 'utf8');
41
+ this.config = JSON.parse(configData);
42
+ console.log('โœ… Configuration loaded successfully');
43
+ return this.config;
44
+ }
45
+ catch (error) {
46
+ console.error('โŒ Error loading configuration:', error);
47
+ throw error;
48
+ }
49
+ }
50
+ /**
51
+ * Authenticate with Gmail API
52
+ */
53
+ async authenticate() {
54
+ try {
55
+ const credentialsPath = path.resolve(__dirname, this.config.gmail.credentialsPath);
56
+ const auth = await authenticate({
57
+ keyfilePath: credentialsPath,
58
+ scopes: this.config.gmail.scopes || DEFAULT_SCOPES,
59
+ });
60
+ this.gmail = google.gmail({ version: 'v1', auth });
61
+ this.isAuthenticated = true;
62
+ console.log('โœ… Gmail authentication successful');
63
+ }
64
+ catch (error) {
65
+ console.error('โŒ Gmail authentication failed:', error);
66
+ throw error;
67
+ }
68
+ }
69
+ /**
70
+ * Check if email subject starts with the configured prefix
71
+ */
72
+ matchesFilter(email) {
73
+ const subject = this.getEmailSubject(email);
74
+ const prefix = this.config.filter.subjectPrefix;
75
+ return subject && subject.startsWith(prefix);
76
+ }
77
+ /**
78
+ * Extract and decode email body from Gmail message
79
+ * @param {Object} email - Gmail message object
80
+ * @param {string} [preferredType='text/plain'] - Preferred MIME type ('text/plain' or 'text/html')
81
+ * @returns {string} - Decoded email body as string
82
+ */
83
+ extractEmailBody(email, preferredType = 'text/plain') {
84
+ if (!email || !email.payload) {
85
+ return '';
86
+ }
87
+ try {
88
+ // Function to recursively find body in message parts
89
+ const findBodyInParts = (parts, preferredType) => {
90
+ for (const part of parts) {
91
+ // Check if this part has the body we want
92
+ if (part.mimeType === preferredType && part.body && part.body.data) {
93
+ return part.body.data;
94
+ }
95
+ // If this part has sub-parts, search recursively
96
+ if (part.parts && part.parts.length > 0) {
97
+ const found = findBodyInParts(part.parts, preferredType);
98
+ if (found)
99
+ return found;
100
+ }
101
+ }
102
+ return null;
103
+ };
104
+ let bodyData = null;
105
+ // First try to find the preferred type
106
+ if (email.payload.parts && email.payload.parts.length > 0) {
107
+ bodyData = findBodyInParts(email.payload.parts, preferredType);
108
+ }
109
+ // If preferred type not found and we want plain text, try HTML as fallback
110
+ if (!bodyData && preferredType === 'text/plain') {
111
+ if (email.payload.parts && email.payload.parts.length > 0) {
112
+ bodyData = findBodyInParts(email.payload.parts, 'text/html');
113
+ }
114
+ }
115
+ // If still not found, check the root payload body
116
+ if (!bodyData && email.payload.body && email.payload.body.data) {
117
+ bodyData = email.payload.body.data;
118
+ }
119
+ // If we found body data, decode it
120
+ if (bodyData) {
121
+ // Gmail uses URL-safe base64, convert to regular base64 first
122
+ const regularBase64 = bodyData.replace(/-/g, '+').replace(/_/g, '/');
123
+ // Decode from base64 to string
124
+ const decodedBody = Buffer.from(regularBase64, 'base64').toString('utf-8');
125
+ return decodedBody;
126
+ }
127
+ return '';
128
+ }
129
+ catch (error) {
130
+ console.error('โŒ Error extracting email body:', error);
131
+ return '';
132
+ }
133
+ }
134
+ /**
135
+ * Extract subject from email headers
136
+ */
137
+ getEmailSubject(email) {
138
+ if (!email.payload || !email.payload.headers)
139
+ return '';
140
+ const subjectHeader = email.payload.headers.find(header => header.name.toLowerCase() === 'subject');
141
+ return subjectHeader ? subjectHeader.value : '';
142
+ }
143
+ /**
144
+ * Resolve a Gmail label ID by its display name
145
+ */
146
+ async getLabelIdByName(labelName) {
147
+ if (!labelName) {
148
+ return null;
149
+ }
150
+ const labels = await this.getLabels();
151
+ const lower = labelName.toLowerCase();
152
+ const match = labels.find(label => label.name.toLowerCase() === lower);
153
+ if (!match) {
154
+ console.warn(`โš ๏ธ Label not found: ${labelName}`);
155
+ return null;
156
+ }
157
+ return match.id;
158
+ }
159
+ /**
160
+ * Determine which label IDs to use when querying Gmail
161
+ */
162
+ async getFilterLabelIds() {
163
+ if (!this.config || !this.config.filter) {
164
+ return ['INBOX'];
165
+ }
166
+ const { labelIds, labelNames, labelName } = this.config.filter;
167
+ if (Array.isArray(labelIds) && labelIds.length > 0) {
168
+ return labelIds;
169
+ }
170
+ const names = [];
171
+ if (labelName) {
172
+ names.push(labelName);
173
+ }
174
+ if (Array.isArray(labelNames)) {
175
+ names.push(...labelNames);
176
+ }
177
+ if (names.length === 0) {
178
+ return ['INBOX'];
179
+ }
180
+ const availableLabels = await this.getLabels();
181
+ const lookup = new Map(availableLabels.map(label => [label.name.toLowerCase(), label.id]));
182
+ const resolved = names
183
+ .map(name => {
184
+ const id = lookup.get(name.toLowerCase());
185
+ if (!id) {
186
+ console.warn(`โš ๏ธ Configured label "${name}" not found in Gmail`);
187
+ }
188
+ return id;
189
+ })
190
+ .filter(Boolean);
191
+ return resolved.length > 0 ? resolved : ['INBOX'];
192
+ }
193
+ /**
194
+ * Get all labels
195
+ */
196
+ async getLabels() {
197
+ if (!this.isAuthenticated) {
198
+ throw new Error('Not authenticated with Gmail');
199
+ }
200
+ try {
201
+ const response = await this.gmail.users.labels.list({
202
+ userId: 'me'
203
+ });
204
+ return response.data.labels || [];
205
+ }
206
+ catch (error) {
207
+ console.error('โŒ Error getting labels:', error);
208
+ throw error;
209
+ }
210
+ }
211
+ /**
212
+ * Create new label/folder
213
+ */
214
+ async createLabel(labelName) {
215
+ if (!this.isAuthenticated) {
216
+ throw new Error('Not authenticated with Gmail');
217
+ }
218
+ try {
219
+ // Add human delay
220
+ await this.delay(this.getHumanDelay());
221
+ const response = await this.gmail.users.labels.create({
222
+ userId: 'me',
223
+ requestBody: {
224
+ name: labelName,
225
+ labelListVisibility: 'labelShow',
226
+ messageListVisibility: 'show'
227
+ }
228
+ });
229
+ console.log(`๐Ÿ“ Created label: ${labelName}`);
230
+ return response.data;
231
+ }
232
+ catch (error) {
233
+ console.error('โŒ Error creating label:', error);
234
+ throw error;
235
+ }
236
+ }
237
+ /**
238
+ * Find or create label
239
+ */
240
+ async findOrCreateLabel(labelName) {
241
+ const labels = await this.getLabels();
242
+ const existingLabel = labels.find(label => label.name === labelName);
243
+ if (existingLabel) {
244
+ return existingLabel;
245
+ }
246
+ return await this.createLabel(labelName);
247
+ }
248
+ /**
249
+ * Get human-like delay
250
+ */
251
+ getHumanDelay() {
252
+ const min = 1000; // 1 second minimum delay
253
+ const max = 3000; // 3 seconds maximum delay
254
+ return Math.random() * (max - min) + min;
255
+ }
256
+ /**
257
+ * Get full email details
258
+ */
259
+ async getEmailDetails(messageId) {
260
+ if (!this.isAuthenticated) {
261
+ throw new Error('Not authenticated with Gmail');
262
+ }
263
+ try {
264
+ // Add human delay
265
+ await this.delay(this.getHumanDelay());
266
+ const response = await this.gmail.users.messages.get({
267
+ userId: 'me',
268
+ id: messageId,
269
+ format: 'full'
270
+ });
271
+ const enriched = await this.includeAttachmentsInBody(response.data);
272
+ return enriched;
273
+ }
274
+ catch (error) {
275
+ console.error('โŒ Error getting email details:', error);
276
+ throw error;
277
+ }
278
+ }
279
+ /**
280
+ * Move email to different label/folder
281
+ */
282
+ async moveEmail(messageId, targetLabelId, removeLabelIds = []) {
283
+ if (!this.isAuthenticated) {
284
+ throw new Error('Not authenticated with Gmail');
285
+ }
286
+ try {
287
+ // Add human delay
288
+ await this.delay(this.getHumanDelay());
289
+ const response = await this.gmail.users.messages.modify({
290
+ userId: 'me',
291
+ id: messageId,
292
+ requestBody: {
293
+ addLabelIds: [targetLabelId],
294
+ removeLabelIds: removeLabelIds
295
+ }
296
+ });
297
+ console.log(`๐Ÿ“ฆ Moved email ${messageId} to label ${targetLabelId}`);
298
+ return response.data;
299
+ }
300
+ catch (error) {
301
+ console.error('โŒ Error moving email:', error);
302
+ throw error;
303
+ }
304
+ }
305
+ /**
306
+ * Utility delay function
307
+ */
308
+ delay(ms) {
309
+ return new Promise(resolve => setTimeout(resolve, ms));
310
+ }
311
+ /**
312
+ * Ensure a folder/label exists by name
313
+ * Returns the label object (existing or newly created)
314
+ */
315
+ async ensureFolderExists(folderName) {
316
+ if (!this.isAuthenticated) {
317
+ console.log('๐Ÿ” Not authenticated, authenticating now...');
318
+ await this.authenticate();
319
+ }
320
+ try {
321
+ const label = await this.findOrCreateLabel(folderName);
322
+ console.log(`๐Ÿ“ Folder "${folderName}" is ready (ID: ${label.id})`);
323
+ return label;
324
+ }
325
+ catch (error) {
326
+ console.error(`โŒ Error ensuring folder "${folderName}" exists:`, error);
327
+ throw error;
328
+ }
329
+ }
330
+ /**
331
+ * Move an email to a specific folder by name
332
+ * Automatically ensures the folder exists before moving
333
+ */
334
+ async moveEmailToFolder(messageId, folderName, removeFromInbox = true) {
335
+ if (!this.isAuthenticated) {
336
+ console.log('๐Ÿ” Not authenticated, authenticating now...');
337
+ await this.authenticate();
338
+ }
339
+ try {
340
+ // Ensure the folder exists
341
+ const targetLabel = await this.ensureFolderExists(folderName);
342
+ // Prepare label IDs to remove (typically INBOX if requested)
343
+ const removeLabelIds = removeFromInbox ? ['INBOX'] : [];
344
+ // Move the email
345
+ const result = await this.moveEmail(messageId, targetLabel.id, removeLabelIds);
346
+ console.log(`๐Ÿ“ฆ Moved email ${messageId} to folder "${folderName}"`);
347
+ return result;
348
+ }
349
+ catch (error) {
350
+ console.error(`โŒ Error moving email ${messageId} to folder "${folderName}":`, error);
351
+ throw error;
352
+ }
353
+ }
354
+ /**
355
+ * Step through emails manually with pagination
356
+ * Ensures authentication and allows controlled processing of emails
357
+ * Honors the configured filter (subject prefix)
358
+ */
359
+ async stepThroughEmails(options = {}) {
360
+ // Ensure authentication
361
+ if (!this.isAuthenticated) {
362
+ console.log('๐Ÿ” Not authenticated, authenticating now...');
363
+ await this.authenticate();
364
+ }
365
+ const { query = '', labelIds = null, folderName = null, maxResults = 10, pageToken = null, includeDetails = true } = options;
366
+ let effectiveLabelIds = labelIds;
367
+ if (!effectiveLabelIds || effectiveLabelIds.length === 0) {
368
+ if (folderName) {
369
+ const labelId = await this.getLabelIdByName(folderName);
370
+ if (!labelId) {
371
+ throw new Error(`Label "${folderName}" not found`);
372
+ }
373
+ effectiveLabelIds = [labelId];
374
+ }
375
+ else {
376
+ effectiveLabelIds = await this.getFilterLabelIds();
377
+ }
378
+ }
379
+ try {
380
+ // Get message list with pagination
381
+ const listOptions = {
382
+ userId: 'me',
383
+ q: query,
384
+ maxResults: maxResults,
385
+ pageToken: pageToken
386
+ };
387
+ if (effectiveLabelIds && effectiveLabelIds.length > 0) {
388
+ listOptions.labelIds = effectiveLabelIds;
389
+ }
390
+ const listResponse = await this.gmail.users.messages.list(listOptions);
391
+ const messages = listResponse.data.messages || [];
392
+ console.log(`๐Ÿ“ง Found ${messages.length} messages (page token: ${listResponse.data.nextPageToken || 'none'})`);
393
+ let emailDetails = [];
394
+ let filteredCount = 0;
395
+ if (includeDetails && messages.length > 0) {
396
+ // Get full details for each message and apply filter
397
+ for (const message of messages) {
398
+ const details = await this.getEmailDetails(message.id);
399
+ // Check if email matches our filter
400
+ if (this.matchesFilter(details)) {
401
+ emailDetails.push(details);
402
+ filteredCount++;
403
+ if (this.config.logging.enableConsole) {
404
+ console.log(`โœ… Filtered email matches: ${this.getEmailSubject(details)}`);
405
+ }
406
+ }
407
+ else {
408
+ if (this.config.logging.enableConsole) {
409
+ console.log(`โŒ Filtered email doesn't match: ${this.getEmailSubject(details)}`);
410
+ }
411
+ }
412
+ }
413
+ }
414
+ console.log(`๐ŸŽฏ After filtering: ${filteredCount} emails match the prefix "${this.config.filter.subjectPrefix}"`);
415
+ return {
416
+ messages: includeDetails ? emailDetails : messages, // Note: if includeDetails=false, we can't filter
417
+ nextPageToken: listResponse.data.nextPageToken,
418
+ hasMore: !!listResponse.data.nextPageToken,
419
+ totalMessages: messages.length,
420
+ filteredMessages: filteredCount,
421
+ subjectPrefix: this.config.filter.subjectPrefix
422
+ };
423
+ }
424
+ catch (error) {
425
+ console.error('โŒ Error stepping through emails:', error);
426
+ throw error;
427
+ }
428
+ }
429
+ /**
430
+ * Add email to memory (keeping only the most recent N emails)
431
+ */
432
+ addEmailToMemory(email) {
433
+ // Add timestamp for sorting
434
+ const emailWithTimestamp = {
435
+ ...email,
436
+ filteredAt: new Date().toISOString(),
437
+ subject: this.getEmailSubject(email)
438
+ };
439
+ // Add to beginning of array (most recent first)
440
+ this.emails.unshift(emailWithTimestamp);
441
+ // Keep only the configured maximum number of emails
442
+ if (this.emails.length > this.config.filter.maxEmailsInMemory) {
443
+ this.emails = this.emails.slice(0, this.config.filter.maxEmailsInMemory);
444
+ }
445
+ if (this.config.logging.enableConsole) {
446
+ console.log(`๐Ÿ“ง Added filtered email: ${emailWithTimestamp.subject}`);
447
+ }
448
+ }
449
+ /**
450
+ * Poll for new emails and filter them
451
+ */
452
+ async pollAndFilter() {
453
+ if (!this.isAuthenticated) {
454
+ throw new Error('Not authenticated with Gmail');
455
+ }
456
+ try {
457
+ const labelIds = await this.getFilterLabelIds();
458
+ // Poll for recent emails (last 24 hours to avoid too much data)
459
+ const query = `newer_than:1d`;
460
+ const listOptions = {
461
+ userId: 'me',
462
+ q: query,
463
+ maxResults: 50
464
+ };
465
+ if (labelIds && labelIds.length > 0) {
466
+ listOptions.labelIds = labelIds;
467
+ }
468
+ const response = await this.gmail.users.messages.list(listOptions);
469
+ const messages = response.data.messages || [];
470
+ if (this.config.logging.enableConsole) {
471
+ console.log(`๐Ÿ“ง Found ${messages.length} recent messages`);
472
+ }
473
+ // Process each message
474
+ for (const message of messages) {
475
+ try {
476
+ const emailDetails = await this.gmail.users.messages.get({
477
+ userId: 'me',
478
+ id: message.id,
479
+ format: 'full'
480
+ });
481
+ // Check if email matches our filter
482
+ if (this.matchesFilter(emailDetails.data)) {
483
+ this.addEmailToMemory(emailDetails.data);
484
+ }
485
+ }
486
+ catch (error) {
487
+ console.error(`โŒ Error processing message ${message.id}:`, error);
488
+ }
489
+ // Small delay between processing emails
490
+ await this.delay(100);
491
+ }
492
+ }
493
+ catch (error) {
494
+ console.error('โŒ Error polling emails:', error);
495
+ throw error;
496
+ }
497
+ }
498
+ /**
499
+ * Start the polling process
500
+ */
501
+ async startPolling() {
502
+ // Authenticate on first polling start if not already authenticated
503
+ if (!this.isAuthenticated) {
504
+ console.log('๐Ÿ” Authenticating with Gmail...');
505
+ await this.authenticateOnce();
506
+ }
507
+ console.log('๐Ÿš€ Starting Filter Gmail Poller...');
508
+ console.log(`๐Ÿ“ง Filtering emails with prefix: "${this.config.filter.subjectPrefix}"`);
509
+ console.log(`โฐ Polling interval: ${this.config.filter.pollingIntervalMs}ms`);
510
+ console.log(`๐Ÿ’พ Max emails in memory: ${this.config.filter.maxEmailsInMemory}`);
511
+ const poll = async () => {
512
+ try {
513
+ await this.pollAndFilter();
514
+ }
515
+ catch (error) {
516
+ console.error('โŒ Polling error:', error);
517
+ }
518
+ // Schedule next poll
519
+ this.pollingInterval = setTimeout(poll, this.config.filter.pollingIntervalMs);
520
+ };
521
+ // Start polling immediately
522
+ await poll();
523
+ }
524
+ /**
525
+ * Stop the polling process
526
+ */
527
+ stopPolling() {
528
+ if (this.pollingInterval) {
529
+ clearTimeout(this.pollingInterval);
530
+ this.pollingInterval = null;
531
+ console.log('โน๏ธ Polling stopped');
532
+ }
533
+ }
534
+ /**
535
+ * Start the API server or integrate with existing Express app
536
+ * @param {Object} [existingApp] - Optional existing Express app to integrate with
537
+ */
538
+ async startAPIServer(existingApp = null) {
539
+ // Use existing app or create new one
540
+ this.app = existingApp || express();
541
+ // Only add middleware if we created the app (to avoid conflicts)
542
+ if (!existingApp) {
543
+ this.app.use(cors());
544
+ this.app.use(express.json());
545
+ }
546
+ console.log('๐Ÿ”ง Setting up API routes...');
547
+ // API Routes
548
+ this.app.get('/api/emails', (req, res) => {
549
+ try {
550
+ const limit = parseInt(req.query.limit) || this.config.filter.maxEmailsInMemory;
551
+ const emails = this.emails.slice(0, limit);
552
+ res.json({
553
+ success: true,
554
+ count: emails.length,
555
+ emails: emails,
556
+ config: {
557
+ subjectPrefix: this.config.filter.subjectPrefix,
558
+ maxEmailsInMemory: this.config.filter.maxEmailsInMemory
559
+ }
560
+ });
561
+ }
562
+ catch (error) {
563
+ res.status(500).json({
564
+ success: false,
565
+ error: error.message
566
+ });
567
+ }
568
+ });
569
+ this.app.get('/api/emails/:id', (req, res) => {
570
+ try {
571
+ const email = this.emails.find(e => e.id === req.params.id);
572
+ if (!email) {
573
+ return res.status(404).json({
574
+ success: false,
575
+ error: 'Email not found'
576
+ });
577
+ }
578
+ res.json({
579
+ success: true,
580
+ email: email
581
+ });
582
+ }
583
+ catch (error) {
584
+ res.status(500).json({
585
+ success: false,
586
+ error: error.message
587
+ });
588
+ }
589
+ });
590
+ this.app.get('/api/stats', (req, res) => {
591
+ res.json({
592
+ success: true,
593
+ stats: {
594
+ totalEmails: this.emails.length,
595
+ maxEmails: this.config.filter.maxEmailsInMemory,
596
+ subjectPrefix: this.config.filter.subjectPrefix,
597
+ pollingInterval: this.config.filter.pollingIntervalMs,
598
+ isPolling: this.pollingInterval !== null,
599
+ lastPoll: new Date().toISOString()
600
+ }
601
+ });
602
+ });
603
+ this.app.get('/api/health', (req, res) => {
604
+ res.json({
605
+ success: true,
606
+ status: 'healthy',
607
+ timestamp: new Date().toISOString()
608
+ });
609
+ });
610
+ // GET endpoint to read current configuration
611
+ this.app.get('/api/config', (req, res) => {
612
+ res.json({
613
+ success: true,
614
+ config: this.config,
615
+ timestamp: new Date().toISOString()
616
+ });
617
+ });
618
+ // POST endpoint to start polling
619
+ this.app.post('/api/polling/start', async (req, res) => {
620
+ try {
621
+ await this.startPolling();
622
+ res.json({
623
+ success: true,
624
+ message: 'Polling started successfully',
625
+ isPolling: true,
626
+ timestamp: new Date().toISOString()
627
+ });
628
+ }
629
+ catch (error) {
630
+ res.status(500).json({
631
+ success: false,
632
+ error: error.message
633
+ });
634
+ }
635
+ });
636
+ // POST endpoint to stop polling
637
+ this.app.post('/api/polling/stop', (req, res) => {
638
+ try {
639
+ this.stopPolling();
640
+ res.json({
641
+ success: true,
642
+ message: 'Polling stopped successfully',
643
+ isPolling: false,
644
+ timestamp: new Date().toISOString()
645
+ });
646
+ }
647
+ catch (error) {
648
+ res.status(500).json({
649
+ success: false,
650
+ error: error.message
651
+ });
652
+ }
653
+ });
654
+ // GET endpoint to check polling status
655
+ this.app.get('/api/polling/status', (req, res) => {
656
+ res.json({
657
+ success: true,
658
+ isPolling: this.pollingInterval !== null,
659
+ isAuthenticated: this.isAuthenticated,
660
+ timestamp: new Date().toISOString()
661
+ });
662
+ });
663
+ // GET endpoint to check if polling is active (simple boolean response)
664
+ this.app.get('/api/polling', (req, res) => {
665
+ res.json({
666
+ isPolling: this.pollingInterval !== null,
667
+ // return number of emails in memory for convenience
668
+ numEmailsInMemory: this.emails.length
669
+ });
670
+ });
671
+ // PUT endpoint to update filter configuration
672
+ this.app.put('/api/config/filter', async (req, res) => {
673
+ try {
674
+ const updates = req.body;
675
+ // Validate input
676
+ const allowedFields = ['subjectPrefix', 'maxEmailsInMemory', 'pollingIntervalMs', 'labelIds', 'labelNames', 'labelName'];
677
+ const invalidFields = Object.keys(updates).filter(key => !allowedFields.includes(key));
678
+ if (invalidFields.length > 0) {
679
+ return res.status(400).json({
680
+ success: false,
681
+ error: `Invalid fields: ${invalidFields.join(', ')}. Allowed: ${allowedFields.join(', ')}`
682
+ });
683
+ }
684
+ // Update configuration
685
+ const result = await this.updateFilterConfig(updates);
686
+ if (result.success) {
687
+ res.json({
688
+ success: true,
689
+ message: 'Filter configuration updated successfully',
690
+ updated: result.updated,
691
+ pollingRestarted: result.pollingRestarted,
692
+ newConfig: result.newConfig
693
+ });
694
+ }
695
+ else {
696
+ res.status(500).json(result);
697
+ }
698
+ }
699
+ catch (error) {
700
+ res.status(500).json({
701
+ success: false,
702
+ error: error.message
703
+ });
704
+ }
705
+ });
706
+ // Only start server if we created the app (not using existing app)
707
+ if (!existingApp) {
708
+ return new Promise((resolve, reject) => {
709
+ try {
710
+ this.server = this.app.listen(this.config.api.port, this.config.api.host, () => {
711
+ console.log(`๐ŸŒ API server started on http://${this.config.api.host}:${this.config.api.port}`);
712
+ console.log(`๐Ÿ“Š Available endpoints:`);
713
+ console.log(` GET /api/emails - Get filtered emails`);
714
+ console.log(` GET /api/emails/:id - Get specific email`);
715
+ console.log(` GET /api/stats - Get poller statistics`);
716
+ console.log(` GET /api/health - Health check`);
717
+ console.log(` PUT /api/config/filter - Update filter configuration`);
718
+ resolve();
719
+ });
720
+ }
721
+ catch (error) {
722
+ reject(error);
723
+ }
724
+ });
725
+ }
726
+ else {
727
+ console.log(`๐Ÿ”— Filter Gmail Poller routes added to existing Express app`);
728
+ console.log(`๐Ÿ“Š Available endpoints:`);
729
+ console.log(` GET /api/emails - Get filtered emails`);
730
+ console.log(` GET /api/emails/:id - Get specific email`);
731
+ console.log(` GET /api/stats - Get poller statistics`);
732
+ console.log(` GET /api/health - Health check`);
733
+ console.log(` PUT /api/config/filter - Update filter configuration`);
734
+ return Promise.resolve();
735
+ }
736
+ }
737
+ /**
738
+ * Stop the API server (only if we created it)
739
+ */
740
+ stopAPIServer() {
741
+ if (this.server) {
742
+ this.server.close();
743
+ this.server = null;
744
+ console.log('๐ŸŒ API server stopped');
745
+ }
746
+ else if (this.app) {
747
+ console.log('๐Ÿ”— Filter Gmail Poller routes removed from Express app');
748
+ // Note: We don't remove routes from existing apps as Express doesn't provide
749
+ // a built-in way to remove routes. The routes will remain active.
750
+ }
751
+ }
752
+ /**
753
+ * Authenticate with Gmail API (only once)
754
+ */
755
+ async authenticateOnce() {
756
+ if (this.isAuthenticated) {
757
+ console.log('โœ… Already authenticated');
758
+ return;
759
+ }
760
+ try {
761
+ await this.authenticate();
762
+ }
763
+ catch (error) {
764
+ console.error('โŒ Authentication failed:', error);
765
+ throw error;
766
+ }
767
+ }
768
+ /**
769
+ * Initialize and start everything (without auto-starting polling)
770
+ * @param {Object} [existingApp] - Optional existing Express app to integrate with
771
+ */
772
+ async initialize(existingApp = null) {
773
+ try {
774
+ console.log('๐ŸŽฏ Initializing Filter Gmail Poller...');
775
+ // Load configuration
776
+ await this.loadConfig();
777
+ // Start API server (pass existing app if provided)
778
+ await this.startAPIServer(existingApp);
779
+ console.log('โœ… Filter Gmail Poller initialized successfully!');
780
+ console.log('๐Ÿ’ก Use startPolling() to begin polling (authentication will occur then)');
781
+ // Handle graceful shutdown (only if we created our own server)
782
+ if (!existingApp) {
783
+ process.on('SIGINT', () => {
784
+ console.log('\n๐Ÿ›‘ Shutting down...');
785
+ this.stopPolling();
786
+ this.stopAPIServer();
787
+ process.exit(0);
788
+ });
789
+ }
790
+ }
791
+ catch (error) {
792
+ console.error('โŒ Failed to initialize Filter Gmail Poller:', error);
793
+ throw error;
794
+ }
795
+ }
796
+ /**
797
+ * Initialize and start everything (legacy method - now calls initialize)
798
+ * @param {Object} [existingApp] - Optional existing Express app to integrate with
799
+ */
800
+ async start(existingApp = null) {
801
+ await this.initialize(existingApp);
802
+ // Optionally start polling immediately for backward compatibility
803
+ await this.startPolling();
804
+ }
805
+ /**
806
+ * Utility delay function
807
+ */
808
+ delay(ms) {
809
+ return new Promise(resolve => setTimeout(resolve, ms));
810
+ }
811
+ /**
812
+ * Get current emails (for testing/debugging)
813
+ */
814
+ getEmails() {
815
+ return this.emails;
816
+ }
817
+ /**
818
+ * Update filter configuration parameters
819
+ * @param {Object} updates - Configuration updates
820
+ * @param {string} [updates.subjectPrefix] - New subject prefix
821
+ * @param {number} [updates.maxEmailsInMemory] - New maximum emails in memory
822
+ * @param {number} [updates.pollingIntervalMs] - New polling interval in milliseconds
823
+ */
824
+ async updateFilterConfig(updates) {
825
+ try {
826
+ const oldConfig = { ...this.config.filter };
827
+ let configChanged = false;
828
+ let pollingRestartNeeded = false;
829
+ // Update subject prefix
830
+ if (updates.subjectPrefix !== undefined) {
831
+ this.config.filter.subjectPrefix = updates.subjectPrefix;
832
+ configChanged = true;
833
+ // Clear existing emails since they may no longer match the new filter
834
+ this.clearEmails();
835
+ console.log(`๐Ÿ“ง Updated subject prefix to: "${updates.subjectPrefix}" (cleared existing emails)`);
836
+ }
837
+ // Update max emails in memory
838
+ if (updates.maxEmailsInMemory !== undefined) {
839
+ const newMax = Math.max(1, updates.maxEmailsInMemory); // Ensure at least 1
840
+ this.config.filter.maxEmailsInMemory = newMax;
841
+ configChanged = true;
842
+ // Trim existing emails if necessary
843
+ if (this.emails.length > newMax) {
844
+ this.emails = this.emails.slice(0, newMax);
845
+ console.log(`๐Ÿงน Trimmed emails to ${newMax} (removed ${this.emails.length - newMax} old emails)`);
846
+ }
847
+ console.log(`๐Ÿ’พ Updated max emails in memory to: ${newMax}`);
848
+ }
849
+ // Update label IDs explicitly
850
+ if (updates.labelIds !== undefined) {
851
+ const newLabelIds = Array.isArray(updates.labelIds) ? updates.labelIds : [updates.labelIds];
852
+ this.config.filter.labelIds = newLabelIds.filter(Boolean);
853
+ configChanged = true;
854
+ console.log(`๐Ÿท๏ธ Updated label IDs to: ${this.config.filter.labelIds.join(', ') || 'none'}`);
855
+ }
856
+ // Update label names
857
+ if (updates.labelNames !== undefined) {
858
+ const newLabelNames = Array.isArray(updates.labelNames) ? updates.labelNames : [updates.labelNames];
859
+ this.config.filter.labelNames = newLabelNames.filter(Boolean);
860
+ configChanged = true;
861
+ console.log(`๐Ÿท๏ธ Updated label names to: ${this.config.filter.labelNames.join(', ') || 'none'}`);
862
+ }
863
+ if (updates.labelName !== undefined) {
864
+ this.config.filter.labelName = updates.labelName || '';
865
+ configChanged = true;
866
+ console.log(`๐Ÿท๏ธ Updated label name to: ${this.config.filter.labelName || 'none'}`);
867
+ }
868
+ // Update polling interval
869
+ if (updates.pollingIntervalMs !== undefined) {
870
+ const newInterval = Math.max(5000, updates.pollingIntervalMs); // Minimum 5 seconds
871
+ this.config.filter.pollingIntervalMs = newInterval;
872
+ configChanged = true;
873
+ pollingRestartNeeded = true;
874
+ console.log(`โฐ Updated polling interval to: ${newInterval}ms`);
875
+ }
876
+ // Save updated config to file
877
+ if (configChanged) {
878
+ await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
879
+ console.log('๐Ÿ’พ Configuration saved to file');
880
+ // Restart polling if interval changed
881
+ if (pollingRestartNeeded && this.pollingInterval) {
882
+ console.log('๐Ÿ”„ Restarting polling with new interval...');
883
+ this.stopPolling();
884
+ await this.startPolling();
885
+ }
886
+ }
887
+ return {
888
+ success: true,
889
+ updated: configChanged,
890
+ pollingRestarted: pollingRestartNeeded,
891
+ newConfig: this.config.filter
892
+ };
893
+ }
894
+ catch (error) {
895
+ console.error('โŒ Error updating filter config:', error);
896
+ return {
897
+ success: false,
898
+ error: error.message
899
+ };
900
+ }
901
+ }
902
+ /**
903
+ * Clear all emails from memory
904
+ */
905
+ clearEmails() {
906
+ this.emails = [];
907
+ console.log('๐Ÿงน Cleared all emails from memory');
908
+ }
909
+ isTextMimeType(mimeType = '') {
910
+ return TEXT_MIME_PREFIXES.some(prefix => mimeType.startsWith(prefix));
911
+ }
912
+ isTextExtension(filename = '') {
913
+ const lower = filename.toLowerCase();
914
+ return TEXT_EXTENSIONS.some(ext => lower.endsWith(ext));
915
+ }
916
+ decodeToBuffer(data = '') {
917
+ const normalized = data.replace(/-/g, '+').replace(/_/g, '/');
918
+ return Buffer.from(normalized, 'base64');
919
+ }
920
+ encodeToBase64Url(str = '') {
921
+ return Buffer.from(str, 'utf8')
922
+ .toString('base64')
923
+ .replace(/\+/g, '-')
924
+ .replace(/\//g, '_')
925
+ .replace(/=+$/g, '');
926
+ }
927
+ collectAttachmentParts(part, attachments = []) {
928
+ if (!part) {
929
+ return attachments;
930
+ }
931
+ if (part.filename && part.body && (part.body.attachmentId || part.body.data)) {
932
+ attachments.push(part);
933
+ }
934
+ if (Array.isArray(part.parts)) {
935
+ part.parts.forEach(child => this.collectAttachmentParts(child, attachments));
936
+ }
937
+ return attachments;
938
+ }
939
+ async fetchAttachmentBuffer(messageId, attachmentId) {
940
+ if (!attachmentId) {
941
+ return Buffer.alloc(0);
942
+ }
943
+ const attachment = await this.gmail.users.messages.attachments.get({
944
+ userId: 'me',
945
+ messageId,
946
+ id: attachmentId
947
+ });
948
+ return this.decodeToBuffer(attachment.data?.data || '');
949
+ }
950
+ async parsePdfAttachment(buffer, messageId, filename = 'attachment.pdf') {
951
+ try {
952
+ const pdfFolder = get(KEYS.pdf_folder_path);
953
+ // Use configured folder or a temp folder for extraction
954
+ const outDir = pdfFolder
955
+ ? path.join(pdfFolder, messageId)
956
+ : path.join(os.tmpdir(), 'story-gen-pdf', messageId);
957
+ // Ensure directory exists
958
+ await ensureDir(outDir);
959
+ // Save the original PDF if we have a configured folder
960
+ if (pdfFolder) {
961
+ const savePath = path.join(outDir, filename);
962
+ try {
963
+ await fs.access(savePath);
964
+ console.log(`โš ๏ธ PDF file already exists at: ${savePath}, skipping save.`);
965
+ }
966
+ catch {
967
+ await fs.writeFile(savePath, buffer);
968
+ console.log(`๐Ÿ’พ Saved PDF attachment to: ${savePath}`);
969
+ }
970
+ }
971
+ console.log(`๐Ÿ“„ Extracting PDF content to: ${outDir}`);
972
+ const result = await extractPdf({
973
+ pdfBuffer: buffer,
974
+ outDir: outDir,
975
+ extractText: true,
976
+ extractImages: false,
977
+ renderPages: false
978
+ });
979
+ const fullText = Object.values(result.textByPage || {}).join('\n');
980
+ console.log(`๐Ÿ“„ Extracted ${result.numPages} pages and ${result.images?.length || 0} images`);
981
+ return fullText.trim() || null;
982
+ }
983
+ catch (error) {
984
+ console.warn(`Failed to parse PDF attachment ${filename}:`, error);
985
+ return null;
986
+ }
987
+ }
988
+ async extractAttachmentText(messageId, part) {
989
+ const mimeType = part.mimeType || '';
990
+ const filename = part.filename || '';
991
+ console.log(`๐Ÿ“Ž Extracting attachment: ${filename} (${mimeType}) from message ${messageId}`);
992
+ let buffer;
993
+ if (part.body?.data) {
994
+ buffer = this.decodeToBuffer(part.body.data);
995
+ }
996
+ else if (part.body?.attachmentId) {
997
+ buffer = await this.fetchAttachmentBuffer(messageId, part.body.attachmentId);
998
+ }
999
+ if (!buffer || !buffer.length) {
1000
+ return null;
1001
+ }
1002
+ if (this.isTextMimeType(mimeType) || this.isTextExtension(filename)) {
1003
+ return buffer.toString('utf8').trim();
1004
+ }
1005
+ if (mimeType === 'application/pdf' || filename.toLowerCase().endsWith('.pdf')) {
1006
+ console.log(`๐Ÿ“„ Parsing PDF attachment: ${filename}`);
1007
+ return await this.parsePdfAttachment(buffer, messageId, filename || 'attachment.pdf');
1008
+ }
1009
+ return null;
1010
+ }
1011
+ async includeAttachmentsInBody(message) {
1012
+ if (!message || !message.payload) {
1013
+ return message;
1014
+ }
1015
+ const attachments = this.collectAttachmentParts(message.payload, []);
1016
+ if (!attachments.length) {
1017
+ return message;
1018
+ }
1019
+ const attachmentSections = [];
1020
+ for (const attachment of attachments) {
1021
+ const text = await this.extractAttachmentText(message.id, attachment);
1022
+ if (text) {
1023
+ attachmentSections.push(`Attachment: ${attachment.filename || attachment.mimeType}\n${text}`);
1024
+ }
1025
+ }
1026
+ if (!attachmentSections.length) {
1027
+ return message;
1028
+ }
1029
+ const combined = attachmentSections.join('\n\n');
1030
+ message.attachmentText = combined;
1031
+ const textPart = {
1032
+ mimeType: 'text/plain',
1033
+ filename: 'attachments.txt',
1034
+ body: {
1035
+ data: this.encodeToBase64Url(`\n\n--- Attachments ---\n${combined}`)
1036
+ }
1037
+ };
1038
+ if (Array.isArray(message.payload.parts)) {
1039
+ message.payload.parts.push(textPart);
1040
+ }
1041
+ else {
1042
+ message.payload.parts = [textPart];
1043
+ }
1044
+ return message;
1045
+ }
1046
+ }
1047
+ export default FilterGmailPoller;
1048
+ //# sourceMappingURL=filter-gmail-poller.js.map