@resolveio/server-lib 22.3.221 → 22.3.222

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 (745) hide show
  1. package/ai/assistant-core-heuristics.d.ts +11 -0
  2. package/ai/assistant-core-heuristics.js +356 -0
  3. package/ai/assistant-core-heuristics.js.map +1 -0
  4. package/ai/resolveio-platform-intelligence-memory-corpus.d.ts +3 -0
  5. package/ai/resolveio-platform-intelligence-memory-corpus.js +214 -0
  6. package/ai/resolveio-platform-intelligence-memory-corpus.js.map +1 -0
  7. package/ai/resolveio-platform-intelligence-memory.d.ts +20 -0
  8. package/ai/resolveio-platform-intelligence-memory.js +341 -0
  9. package/ai/resolveio-platform-intelligence-memory.js.map +1 -0
  10. package/{src/ai/resolveio-platform-intelligence-types.ts → ai/resolveio-platform-intelligence-types.d.ts} +15 -20
  11. package/ai/resolveio-platform-intelligence-types.js +4 -0
  12. package/ai/resolveio-platform-intelligence-types.js.map +1 -0
  13. package/ai/resolveio-platform-intelligence.d.ts +6 -0
  14. package/ai/resolveio-platform-intelligence.js +463 -0
  15. package/ai/resolveio-platform-intelligence.js.map +1 -0
  16. package/client-server-app.d.ts +1 -0
  17. package/client-server-app.js +68 -0
  18. package/client-server-app.js.map +1 -0
  19. package/collections/ai-run.collection.d.ts +3 -0
  20. package/collections/ai-run.collection.js +170 -0
  21. package/collections/ai-run.collection.js.map +1 -0
  22. package/collections/ai-terminal-conversation.collection.d.ts +2 -0
  23. package/collections/ai-terminal-conversation.collection.js +140 -0
  24. package/collections/ai-terminal-conversation.collection.js.map +1 -0
  25. package/collections/ai-terminal-issue-report.collection.d.ts +2 -0
  26. package/collections/ai-terminal-issue-report.collection.js +148 -0
  27. package/collections/ai-terminal-issue-report.collection.js.map +1 -0
  28. package/collections/ai-terminal-message.collection.d.ts +2 -0
  29. package/collections/ai-terminal-message.collection.js +121 -0
  30. package/collections/ai-terminal-message.collection.js.map +1 -0
  31. package/collections/app-setting.collection.d.ts +3 -0
  32. package/collections/app-setting.collection.js +103 -0
  33. package/collections/app-setting.collection.js.map +1 -0
  34. package/collections/app-status.collection.d.ts +3 -0
  35. package/collections/app-status.collection.js +57 -0
  36. package/collections/app-status.collection.js.map +1 -0
  37. package/collections/communication-metric.collection.d.ts +2 -0
  38. package/collections/communication-metric.collection.js +133 -0
  39. package/collections/communication-metric.collection.js.map +1 -0
  40. package/collections/counter.collection.d.ts +3 -0
  41. package/collections/counter.collection.js +56 -0
  42. package/collections/counter.collection.js.map +1 -0
  43. package/collections/cron-job-history.collection.d.ts +3 -0
  44. package/collections/cron-job-history.collection.js +137 -0
  45. package/collections/cron-job-history.collection.js.map +1 -0
  46. package/collections/cron-job.collection.d.ts +3 -0
  47. package/collections/cron-job.collection.js +92 -0
  48. package/collections/cron-job.collection.js.map +1 -0
  49. package/collections/customer-notification.collection.d.ts +3 -0
  50. package/collections/customer-notification.collection.js +130 -0
  51. package/collections/customer-notification.collection.js.map +1 -0
  52. package/collections/customer-portal-password.collection.d.ts +3 -0
  53. package/collections/customer-portal-password.collection.js +75 -0
  54. package/collections/customer-portal-password.collection.js.map +1 -0
  55. package/collections/email-history.collection.d.ts +3 -0
  56. package/collections/email-history.collection.js +134 -0
  57. package/collections/email-history.collection.js.map +1 -0
  58. package/collections/email-verified.collection.d.ts +3 -0
  59. package/collections/email-verified.collection.js +62 -0
  60. package/collections/email-verified.collection.js.map +1 -0
  61. package/collections/file.collection.d.ts +3 -0
  62. package/collections/file.collection.js +74 -0
  63. package/collections/file.collection.js.map +1 -0
  64. package/collections/flag-update.collection.d.ts +3 -0
  65. package/collections/flag-update.collection.js +57 -0
  66. package/collections/flag-update.collection.js.map +1 -0
  67. package/collections/flag.collection.d.ts +3 -0
  68. package/collections/flag.collection.js +57 -0
  69. package/collections/flag.collection.js.map +1 -0
  70. package/collections/log-method-latency.collection.d.ts +3 -0
  71. package/collections/log-method-latency.collection.js +77 -0
  72. package/collections/log-method-latency.collection.js.map +1 -0
  73. package/collections/log-subscription.collection.d.ts +3 -0
  74. package/collections/log-subscription.collection.js +80 -0
  75. package/collections/log-subscription.collection.js.map +1 -0
  76. package/collections/log.collection.d.ts +3 -0
  77. package/collections/log.collection.js +93 -0
  78. package/collections/log.collection.js.map +1 -0
  79. package/collections/logged-in-users.collection.d.ts +3 -0
  80. package/collections/logged-in-users.collection.js +67 -0
  81. package/collections/logged-in-users.collection.js.map +1 -0
  82. package/collections/monitor-cpu.collection.d.ts +3 -0
  83. package/collections/monitor-cpu.collection.js +65 -0
  84. package/collections/monitor-cpu.collection.js.map +1 -0
  85. package/collections/monitor-function.collection.d.ts +3 -0
  86. package/collections/monitor-function.collection.js +74 -0
  87. package/collections/monitor-function.collection.js.map +1 -0
  88. package/collections/monitor-memory.collection.d.ts +3 -0
  89. package/collections/monitor-memory.collection.js +77 -0
  90. package/collections/monitor-memory.collection.js.map +1 -0
  91. package/collections/monitor-mongo.collection.d.ts +3 -0
  92. package/collections/monitor-mongo.collection.js +71 -0
  93. package/collections/monitor-mongo.collection.js.map +1 -0
  94. package/collections/notification.collection.d.ts +3 -0
  95. package/collections/notification.collection.js +57 -0
  96. package/collections/notification.collection.js.map +1 -0
  97. package/collections/openai-usage-ledger.collection.d.ts +2 -0
  98. package/collections/openai-usage-ledger.collection.js +188 -0
  99. package/collections/openai-usage-ledger.collection.js.map +1 -0
  100. package/collections/report-builder-dashboard-builder.collection.d.ts +3 -0
  101. package/collections/report-builder-dashboard-builder.collection.js +109 -0
  102. package/collections/report-builder-dashboard-builder.collection.js.map +1 -0
  103. package/collections/report-builder-library.collection.d.ts +3 -0
  104. package/collections/report-builder-library.collection.js +87 -0
  105. package/collections/report-builder-library.collection.js.map +1 -0
  106. package/collections/report-builder-report.collection.d.ts +4 -0
  107. package/collections/report-builder-report.collection.js +184 -0
  108. package/collections/report-builder-report.collection.js.map +1 -0
  109. package/collections/user-group.collection.d.ts +4 -0
  110. package/collections/user-group.collection.js +89 -0
  111. package/collections/user-group.collection.js.map +1 -0
  112. package/collections/user-guide.collection.d.ts +3 -0
  113. package/collections/user-guide.collection.js +57 -0
  114. package/collections/user-guide.collection.js.map +1 -0
  115. package/collections/user.collection.d.ts +4 -0
  116. package/collections/user.collection.js +180 -0
  117. package/collections/user.collection.js.map +1 -0
  118. package/cron/cron.d.ts +14 -0
  119. package/cron/cron.js +216 -0
  120. package/cron/cron.js.map +1 -0
  121. package/fixtures/cron-jobs.d.ts +1 -0
  122. package/fixtures/cron-jobs.js +150 -0
  123. package/fixtures/cron-jobs.js.map +1 -0
  124. package/fixtures/init.d.ts +1 -0
  125. package/fixtures/init.js +91 -0
  126. package/fixtures/init.js.map +1 -0
  127. package/http/auth.d.ts +2 -0
  128. package/http/auth.js +951 -0
  129. package/http/auth.js.map +1 -0
  130. package/http/health.d.ts +1 -0
  131. package/http/health.js +11 -0
  132. package/http/health.js.map +1 -0
  133. package/http/home.d.ts +1 -0
  134. package/http/home.js +134 -0
  135. package/http/home.js.map +1 -0
  136. package/http/slow-query-publication.d.ts +2 -0
  137. package/http/slow-query-publication.js +99 -0
  138. package/http/slow-query-publication.js.map +1 -0
  139. package/index.d.ts +1 -0
  140. package/index.js +19 -0
  141. package/index.js.map +1 -0
  142. package/managers/ai-assistant-codex-manager.manager.d.ts +67 -0
  143. package/managers/ai-assistant-codex-manager.manager.js +1113 -0
  144. package/managers/ai-assistant-codex-manager.manager.js.map +1 -0
  145. package/managers/ai-run-evidence.manager.d.ts +36 -0
  146. package/managers/ai-run-evidence.manager.js +377 -0
  147. package/managers/ai-run-evidence.manager.js.map +1 -0
  148. package/managers/communication-metric.manager.d.ts +16 -0
  149. package/managers/communication-metric.manager.js +134 -0
  150. package/managers/communication-metric.manager.js.map +1 -0
  151. package/managers/cron.manager.d.ts +20 -0
  152. package/managers/cron.manager.js +534 -0
  153. package/managers/cron.manager.js.map +1 -0
  154. package/managers/customer-notification-content.manager.d.ts +55 -0
  155. package/managers/customer-notification-content.manager.js +158 -0
  156. package/managers/customer-notification-content.manager.js.map +1 -0
  157. package/managers/diagnostic-manager-bootstrap.d.ts +9 -0
  158. package/managers/diagnostic-manager-bootstrap.js +260 -0
  159. package/managers/diagnostic-manager-bootstrap.js.map +1 -0
  160. package/managers/error-auto-fix.manager.d.ts +149 -0
  161. package/managers/error-auto-fix.manager.js +3064 -0
  162. package/managers/error-auto-fix.manager.js.map +1 -0
  163. package/managers/local-log.manager.d.ts +18 -0
  164. package/managers/local-log.manager.js +88 -0
  165. package/managers/local-log.manager.js.map +1 -0
  166. package/managers/method.manager.d.ts +84 -0
  167. package/managers/method.manager.js +1964 -0
  168. package/managers/method.manager.js.map +1 -0
  169. package/managers/mongo.manager.d.ts +224 -0
  170. package/managers/mongo.manager.js +5000 -0
  171. package/managers/mongo.manager.js.map +1 -0
  172. package/managers/monitor.manager.d.ts +70 -0
  173. package/managers/monitor.manager.js +550 -0
  174. package/managers/monitor.manager.js.map +1 -0
  175. package/managers/openai-usage-ledger.manager.d.ts +30 -0
  176. package/managers/openai-usage-ledger.manager.js +142 -0
  177. package/managers/openai-usage-ledger.manager.js.map +1 -0
  178. package/managers/slow-query-verifier.manager.d.ts +144 -0
  179. package/managers/slow-query-verifier.manager.js +3857 -0
  180. package/managers/slow-query-verifier.manager.js.map +1 -0
  181. package/managers/slow-query.manager.d.ts +28 -0
  182. package/managers/slow-query.manager.js +468 -0
  183. package/managers/slow-query.manager.js.map +1 -0
  184. package/managers/subscription.manager.d.ts +169 -0
  185. package/managers/subscription.manager.js +3434 -0
  186. package/managers/subscription.manager.js.map +1 -0
  187. package/managers/websocket.manager.d.ts +73 -0
  188. package/managers/websocket.manager.js +673 -0
  189. package/managers/websocket.manager.js.map +1 -0
  190. package/managers/worker-dispatcher.manager.d.ts +120 -0
  191. package/managers/worker-dispatcher.manager.js +1266 -0
  192. package/managers/worker-dispatcher.manager.js.map +1 -0
  193. package/managers/worker-server.manager.d.ts +35 -0
  194. package/managers/worker-server.manager.js +582 -0
  195. package/managers/worker-server.manager.js.map +1 -0
  196. package/methods/accounts.d.ts +2 -0
  197. package/methods/accounts.js +624 -0
  198. package/methods/accounts.js.map +1 -0
  199. package/methods/ai-terminal.d.ts +458 -0
  200. package/methods/ai-terminal.js +27991 -0
  201. package/methods/ai-terminal.js.map +1 -0
  202. package/methods/app-settings.d.ts +2 -0
  203. package/methods/app-settings.js +169 -0
  204. package/methods/app-settings.js.map +1 -0
  205. package/methods/aws.d.ts +2 -0
  206. package/methods/aws.js +877 -0
  207. package/methods/aws.js.map +1 -0
  208. package/methods/collections.d.ts +2 -0
  209. package/methods/collections.js +719 -0
  210. package/methods/collections.js.map +1 -0
  211. package/methods/counters.d.ts +2 -0
  212. package/methods/counters.js +113 -0
  213. package/methods/counters.js.map +1 -0
  214. package/methods/cron-jobs.d.ts +2 -0
  215. package/methods/cron-jobs.js +2475 -0
  216. package/methods/cron-jobs.js.map +1 -0
  217. package/methods/customer-notifications.d.ts +2 -0
  218. package/methods/customer-notifications.js +528 -0
  219. package/methods/customer-notifications.js.map +1 -0
  220. package/methods/diagnostics.d.ts +2 -0
  221. package/methods/diagnostics.js +703 -0
  222. package/methods/diagnostics.js.map +1 -0
  223. package/methods/flag-updates.d.ts +2 -0
  224. package/methods/flag-updates.js +8 -0
  225. package/methods/flag-updates.js.map +1 -0
  226. package/methods/flags.d.ts +2 -0
  227. package/methods/flags.js +8 -0
  228. package/methods/flags.js.map +1 -0
  229. package/methods/logs.d.ts +2 -0
  230. package/methods/logs.js +751 -0
  231. package/methods/logs.js.map +1 -0
  232. package/methods/mongo-explorer.d.ts +2 -0
  233. package/methods/mongo-explorer.js +1808 -0
  234. package/methods/mongo-explorer.js.map +1 -0
  235. package/methods/monitor.d.ts +2 -0
  236. package/methods/monitor.js +543 -0
  237. package/methods/monitor.js.map +1 -0
  238. package/methods/pdf.d.ts +2 -0
  239. package/methods/pdf.js +1216 -0
  240. package/methods/pdf.js.map +1 -0
  241. package/methods/publications.d.ts +1 -0
  242. package/methods/publications.js +183 -0
  243. package/methods/publications.js.map +1 -0
  244. package/methods/report-builder.d.ts +2 -0
  245. package/methods/report-builder.js +3094 -0
  246. package/methods/report-builder.js.map +1 -0
  247. package/methods/support.d.ts +2 -0
  248. package/methods/support.js +430 -0
  249. package/methods/support.js.map +1 -0
  250. package/models/ai-run.model.d.ts +19 -0
  251. package/models/ai-run.model.js +4 -0
  252. package/models/ai-run.model.js.map +1 -0
  253. package/models/ai-terminal-conversation.model.d.ts +17 -0
  254. package/models/ai-terminal-conversation.model.js +4 -0
  255. package/models/ai-terminal-conversation.model.js.map +1 -0
  256. package/models/ai-terminal-issue-report.model.d.ts +19 -0
  257. package/models/ai-terminal-issue-report.model.js +4 -0
  258. package/models/ai-terminal-issue-report.model.js.map +1 -0
  259. package/models/ai-terminal-message.model.d.ts +22 -0
  260. package/models/ai-terminal-message.model.js +4 -0
  261. package/models/ai-terminal-message.model.js.map +1 -0
  262. package/models/app-setting.model.d.ts +16 -0
  263. package/models/app-setting.model.js +4 -0
  264. package/models/app-setting.model.js.map +1 -0
  265. package/{src/models/app-status.model.ts → models/app-status.model.d.ts} +2 -3
  266. package/models/app-status.model.js +4 -0
  267. package/models/app-status.model.js.map +1 -0
  268. package/{src/models/billing-logged-in-users.model.ts → models/billing-logged-in-users.model.d.ts} +4 -5
  269. package/models/billing-logged-in-users.model.js +4 -0
  270. package/models/billing-logged-in-users.model.js.map +1 -0
  271. package/models/collection-document.model.d.ts +21 -0
  272. package/models/collection-document.model.js +4 -0
  273. package/models/collection-document.model.js.map +1 -0
  274. package/models/communication-metric.model.d.ts +20 -0
  275. package/models/communication-metric.model.js +4 -0
  276. package/models/communication-metric.model.js.map +1 -0
  277. package/{src/models/counter.model.ts → models/counter.model.d.ts} +3 -4
  278. package/models/counter.model.js +4 -0
  279. package/models/counter.model.js.map +1 -0
  280. package/models/cron-job-history.model.d.ts +15 -0
  281. package/models/cron-job-history.model.js +4 -0
  282. package/models/cron-job-history.model.js.map +1 -0
  283. package/models/cron-job.model.d.ts +14 -0
  284. package/models/cron-job.model.js +4 -0
  285. package/models/cron-job.model.js.map +1 -0
  286. package/models/customer-notification.model.d.ts +26 -0
  287. package/models/customer-notification.model.js +4 -0
  288. package/models/customer-notification.model.js.map +1 -0
  289. package/models/customer-portal-password.model.d.ts +11 -0
  290. package/models/customer-portal-password.model.js +4 -0
  291. package/models/customer-portal-password.model.js.map +1 -0
  292. package/models/dialog.model.d.ts +23 -0
  293. package/models/dialog.model.js +4 -0
  294. package/models/dialog.model.js.map +1 -0
  295. package/models/email-history.model.d.ts +32 -0
  296. package/{src/models/email-history.model.ts → models/email-history.model.js} +4 -36
  297. package/models/email-history.model.js.map +1 -0
  298. package/{src/models/email-verified.model.ts → models/email-verified.model.d.ts} +5 -6
  299. package/models/email-verified.model.js +4 -0
  300. package/models/email-verified.model.js.map +1 -0
  301. package/{src/models/file.model.ts → models/file.model.d.ts} +7 -8
  302. package/models/file.model.js +4 -0
  303. package/models/file.model.js.map +1 -0
  304. package/{src/models/flag-update.model.ts → models/flag-update.model.d.ts} +3 -4
  305. package/models/flag-update.model.js +4 -0
  306. package/models/flag-update.model.js.map +1 -0
  307. package/{src/models/flag.model.ts → models/flag.model.d.ts} +3 -4
  308. package/models/flag.model.js +4 -0
  309. package/models/flag.model.js.map +1 -0
  310. package/models/log-method-latency.model.d.ts +10 -0
  311. package/models/log-method-latency.model.js +4 -0
  312. package/models/log-method-latency.model.js.map +1 -0
  313. package/{src/models/log-subscription.model.ts → models/log-subscription.model.d.ts} +9 -11
  314. package/models/log-subscription.model.js +4 -0
  315. package/models/log-subscription.model.js.map +1 -0
  316. package/models/log.model.d.ts +17 -0
  317. package/models/log.model.js +4 -0
  318. package/models/log.model.js.map +1 -0
  319. package/{src/models/logged-in-users.model.ts → models/logged-in-users.model.d.ts} +5 -6
  320. package/models/logged-in-users.model.js +4 -0
  321. package/models/logged-in-users.model.js.map +1 -0
  322. package/{src/models/method-response.model.ts → models/method-response.model.d.ts} +6 -7
  323. package/models/method-response.model.js +4 -0
  324. package/models/method-response.model.js.map +1 -0
  325. package/models/method.model.d.ts +26 -0
  326. package/models/method.model.js +4 -0
  327. package/models/method.model.js.map +1 -0
  328. package/{src/models/monitor-cpu.model.ts → models/monitor-cpu.model.d.ts} +7 -9
  329. package/models/monitor-cpu.model.js +4 -0
  330. package/models/monitor-cpu.model.js.map +1 -0
  331. package/models/monitor-function.model.d.ts +14 -0
  332. package/models/monitor-function.model.js +4 -0
  333. package/models/monitor-function.model.js.map +1 -0
  334. package/models/monitor-memory.model.d.ts +15 -0
  335. package/models/monitor-memory.model.js +4 -0
  336. package/models/monitor-memory.model.js.map +1 -0
  337. package/models/monitor-mongo.model.d.ts +13 -0
  338. package/models/monitor-mongo.model.js +4 -0
  339. package/models/monitor-mongo.model.js.map +1 -0
  340. package/{src/models/notification.model.ts → models/notification.model.d.ts} +4 -6
  341. package/models/notification.model.js +4 -0
  342. package/models/notification.model.js.map +1 -0
  343. package/models/openai-usage-ledger.model.d.ts +30 -0
  344. package/models/openai-usage-ledger.model.js +4 -0
  345. package/models/openai-usage-ledger.model.js.map +1 -0
  346. package/models/pagination.model.d.ts +11 -0
  347. package/models/pagination.model.js +28 -0
  348. package/models/pagination.model.js.map +1 -0
  349. package/models/permission.model.d.ts +12 -0
  350. package/models/permission.model.js +4 -0
  351. package/models/permission.model.js.map +1 -0
  352. package/models/report-builder-dashboard-builder.model.d.ts +25 -0
  353. package/models/report-builder-dashboard-builder.model.js +4 -0
  354. package/models/report-builder-dashboard-builder.model.js.map +1 -0
  355. package/models/report-builder-library.model.d.ts +17 -0
  356. package/models/report-builder-library.model.js +4 -0
  357. package/models/report-builder-library.model.js.map +1 -0
  358. package/models/report-builder-report.model.d.ts +121 -0
  359. package/models/report-builder-report.model.js +4 -0
  360. package/models/report-builder-report.model.js.map +1 -0
  361. package/models/report-builder.model.d.ts +61 -0
  362. package/models/report-builder.model.js +4 -0
  363. package/models/report-builder.model.js.map +1 -0
  364. package/models/select-data-label.model.d.ts +9 -0
  365. package/models/select-data-label.model.js +4 -0
  366. package/models/select-data-label.model.js.map +1 -0
  367. package/models/server-message.model.d.ts +32 -0
  368. package/models/server-message.model.js +4 -0
  369. package/models/server-message.model.js.map +1 -0
  370. package/models/slow-query-report.model.d.ts +23 -0
  371. package/models/slow-query-report.model.js +4 -0
  372. package/models/slow-query-report.model.js.map +1 -0
  373. package/models/subscription.model.d.ts +31 -0
  374. package/models/subscription.model.js +4 -0
  375. package/models/subscription.model.js.map +1 -0
  376. package/models/support-ticket.model.d.ts +87 -0
  377. package/models/support-ticket.model.js +4 -0
  378. package/models/support-ticket.model.js.map +1 -0
  379. package/models/user-group.model.d.ts +20 -0
  380. package/models/user-group.model.js +4 -0
  381. package/models/user-group.model.js.map +1 -0
  382. package/{src/models/user-guide.model.ts → models/user-guide.model.d.ts} +4 -5
  383. package/models/user-guide.model.js +4 -0
  384. package/models/user-guide.model.js.map +1 -0
  385. package/models/user.model.d.ts +84 -0
  386. package/models/user.model.js +4 -0
  387. package/models/user.model.js.map +1 -0
  388. package/package.json +1 -1
  389. package/private/images/ResolveIO.png +0 -0
  390. package/public_api.js +127 -0
  391. package/public_api.js.map +1 -0
  392. package/publications/ai-terminal.d.ts +1 -0
  393. package/publications/ai-terminal.js +122 -0
  394. package/publications/ai-terminal.js.map +1 -0
  395. package/publications/app-settings.d.ts +2 -0
  396. package/publications/app-settings.js +28 -0
  397. package/publications/app-settings.js.map +1 -0
  398. package/publications/app-status.d.ts +2 -0
  399. package/publications/app-status.js +16 -0
  400. package/publications/app-status.js.map +1 -0
  401. package/publications/cron-jobs.d.ts +2 -0
  402. package/publications/cron-jobs.js +88 -0
  403. package/publications/cron-jobs.js.map +1 -0
  404. package/publications/customer-notifications.d.ts +2 -0
  405. package/publications/customer-notifications.js +161 -0
  406. package/publications/customer-notifications.js.map +1 -0
  407. package/publications/files.d.ts +2 -0
  408. package/publications/files.js +36 -0
  409. package/publications/files.js.map +1 -0
  410. package/publications/flags-update.d.ts +2 -0
  411. package/publications/flags-update.js +22 -0
  412. package/publications/flags-update.js.map +1 -0
  413. package/publications/flags.d.ts +2 -0
  414. package/publications/flags.js +22 -0
  415. package/publications/flags.js.map +1 -0
  416. package/publications/logs.d.ts +2 -0
  417. package/publications/logs.js +164 -0
  418. package/publications/logs.js.map +1 -0
  419. package/publications/notifications.d.ts +2 -0
  420. package/publications/notifications.js +16 -0
  421. package/publications/notifications.js.map +1 -0
  422. package/publications/report-builder-dashboard-builders.d.ts +2 -0
  423. package/publications/report-builder-dashboard-builders.js +42 -0
  424. package/publications/report-builder-dashboard-builders.js.map +1 -0
  425. package/publications/report-builder-libraries.d.ts +2 -0
  426. package/publications/report-builder-libraries.js +90 -0
  427. package/publications/report-builder-libraries.js.map +1 -0
  428. package/publications/report-builder-reports.d.ts +2 -0
  429. package/publications/report-builder-reports.js +50 -0
  430. package/publications/report-builder-reports.js.map +1 -0
  431. package/publications/super-admin.d.ts +2 -0
  432. package/publications/super-admin.js +16 -0
  433. package/publications/super-admin.js.map +1 -0
  434. package/publications/user-groups.d.ts +1 -0
  435. package/publications/user-groups.js +16 -0
  436. package/publications/user-groups.js.map +1 -0
  437. package/publications/user-guides.d.ts +1 -0
  438. package/publications/user-guides.js +16 -0
  439. package/publications/user-guides.js.map +1 -0
  440. package/resolveio-server-app.d.ts +70 -0
  441. package/resolveio-server-app.js +801 -0
  442. package/resolveio-server-app.js.map +1 -0
  443. package/server-app.d.ts +228 -0
  444. package/server-app.js +3566 -0
  445. package/server-app.js.map +1 -0
  446. package/services/codex-client.d.ts +128 -0
  447. package/services/codex-client.js +1629 -0
  448. package/services/codex-client.js.map +1 -0
  449. package/services/openai-client.d.ts +46 -0
  450. package/services/openai-client.js +318 -0
  451. package/services/openai-client.js.map +1 -0
  452. package/types/error-report.d.ts +25 -0
  453. package/types/error-report.js +4 -0
  454. package/types/error-report.js.map +1 -0
  455. package/types/slow-query-report.d.ts +27 -0
  456. package/types/slow-query-report.js +6 -0
  457. package/types/slow-query-report.js.map +1 -0
  458. package/util/ai-qa-policy.d.ts +124 -0
  459. package/util/ai-qa-policy.js +736 -0
  460. package/util/ai-qa-policy.js.map +1 -0
  461. package/util/ai-run-evidence-adapters.d.ts +109 -0
  462. package/util/ai-run-evidence-adapters.js +7234 -0
  463. package/util/ai-run-evidence-adapters.js.map +1 -0
  464. package/util/ai-run-evidence-dashboard.d.ts +88 -0
  465. package/util/ai-run-evidence-dashboard.js +343 -0
  466. package/util/ai-run-evidence-dashboard.js.map +1 -0
  467. package/util/ai-run-evidence-eval.d.ts +86 -0
  468. package/util/ai-run-evidence-eval.js +1018 -0
  469. package/util/ai-run-evidence-eval.js.map +1 -0
  470. package/util/ai-run-evidence.d.ts +244 -0
  471. package/util/ai-run-evidence.js +1096 -0
  472. package/util/ai-run-evidence.js.map +1 -0
  473. package/util/ai-runner-artifacts.d.ts +82 -0
  474. package/util/ai-runner-artifacts.js +713 -0
  475. package/util/ai-runner-artifacts.js.map +1 -0
  476. package/util/ai-runner-manager-autopilot.d.ts +210 -0
  477. package/util/ai-runner-manager-autopilot.js +642 -0
  478. package/util/ai-runner-manager-autopilot.js.map +1 -0
  479. package/util/ai-runner-manager-policy.d.ts +807 -0
  480. package/util/ai-runner-manager-policy.js +3501 -0
  481. package/util/ai-runner-manager-policy.js.map +1 -0
  482. package/util/ai-runner-qa-auth.d.ts +5 -0
  483. package/util/ai-runner-qa-auth.js +839 -0
  484. package/util/ai-runner-qa-auth.js.map +1 -0
  485. package/util/ai-runner-qa-tools.d.ts +26 -0
  486. package/util/ai-runner-qa-tools.js +3520 -0
  487. package/util/ai-runner-qa-tools.js.map +1 -0
  488. package/util/aicoder-runner-v6.d.ts +426 -0
  489. package/util/aicoder-runner-v6.js +2464 -0
  490. package/util/aicoder-runner-v6.js.map +1 -0
  491. package/util/common.d.ts +31 -0
  492. package/util/common.js +683 -0
  493. package/util/common.js.map +1 -0
  494. package/util/customer-portal-password.d.ts +13 -0
  495. package/util/customer-portal-password.js +209 -0
  496. package/util/customer-portal-password.js.map +1 -0
  497. package/util/error-reporter.d.ts +52 -0
  498. package/util/error-reporter.js +326 -0
  499. package/util/error-reporter.js.map +1 -0
  500. package/util/error-tracking.d.ts +13 -0
  501. package/util/error-tracking.js +120 -0
  502. package/util/error-tracking.js.map +1 -0
  503. package/util/openai-usage-cost.d.ts +6 -0
  504. package/util/openai-usage-cost.js +103 -0
  505. package/util/openai-usage-cost.js.map +1 -0
  506. package/util/report-builder-unwinds.d.ts +15 -0
  507. package/util/report-builder-unwinds.js +156 -0
  508. package/util/report-builder-unwinds.js.map +1 -0
  509. package/util/runner-process-janitor.d.ts +27 -0
  510. package/util/runner-process-janitor.js +208 -0
  511. package/util/runner-process-janitor.js.map +1 -0
  512. package/util/schema-report-builder.d.ts +6 -0
  513. package/util/schema-report-builder.js +481 -0
  514. package/util/schema-report-builder.js.map +1 -0
  515. package/util/slow-query-reporter.d.ts +28 -0
  516. package/util/slow-query-reporter.js +226 -0
  517. package/util/slow-query-reporter.js.map +1 -0
  518. package/util/subscription-dependency-context.d.ts +34 -0
  519. package/util/subscription-dependency-context.js +1283 -0
  520. package/util/subscription-dependency-context.js.map +1 -0
  521. package/util/support-runner-v5.d.ts +1426 -0
  522. package/util/support-runner-v5.js +7643 -0
  523. package/util/support-runner-v5.js.map +1 -0
  524. package/util/tokenizer.d.ts +5 -0
  525. package/util/tokenizer.js +41 -0
  526. package/util/tokenizer.js.map +1 -0
  527. package/workers/codex-runner.worker.d.ts +1 -0
  528. package/workers/codex-runner.worker.js +192 -0
  529. package/workers/codex-runner.worker.js.map +1 -0
  530. package/.nodemon.json +0 -5
  531. package/.vscode/settings.json +0 -21
  532. package/AGENTS.md +0 -195
  533. package/README.md +0 -22
  534. package/build_package.sh +0 -5
  535. package/compileDTS.pl +0 -64
  536. package/docs/ai-assistant-nightly-eval.md +0 -65
  537. package/docs/ai-assistant-preflight-checklist.md +0 -23
  538. package/docs/ai-assistant-report-builder-bridge-playbook.md +0 -115
  539. package/eslint-plugin-custom/index.js +0 -7
  540. package/eslint-plugin-custom/rules/no-filter-zero-index.js +0 -44
  541. package/eslint.config.js +0 -103
  542. package/gulpfile.js +0 -216
  543. package/methodAndPublicationListGenerator.py +0 -375
  544. package/mongodbensurers.js +0 -2
  545. package/mongostop.js +0 -3
  546. package/scripts/cleanup-bypassed-callmethod-logs.js +0 -616
  547. package/settings.development.json +0 -25
  548. package/settings.development.redacted.json +0 -25
  549. package/src/.env +0 -12
  550. package/src/ai/assistant-core-heuristics.ts +0 -379
  551. package/src/ai/resolveio-platform-intelligence-memory-corpus.ts +0 -185
  552. package/src/ai/resolveio-platform-intelligence-memory.ts +0 -325
  553. package/src/ai/resolveio-platform-intelligence.ts +0 -462
  554. package/src/client-server-app.ts +0 -12
  555. package/src/collections/ai-run.collection.ts +0 -117
  556. package/src/collections/ai-terminal-conversation.collection.ts +0 -91
  557. package/src/collections/ai-terminal-issue-report.collection.ts +0 -99
  558. package/src/collections/ai-terminal-message.collection.ts +0 -77
  559. package/src/collections/app-setting.collection.ts +0 -104
  560. package/src/collections/app-status.collection.ts +0 -58
  561. package/src/collections/communication-metric.collection.ts +0 -84
  562. package/src/collections/counter.collection.ts +0 -56
  563. package/src/collections/cron-job-history.collection.ts +0 -94
  564. package/src/collections/cron-job.collection.ts +0 -92
  565. package/src/collections/customer-notification.collection.ts +0 -131
  566. package/src/collections/customer-portal-password.collection.ts +0 -76
  567. package/src/collections/email-history.collection.ts +0 -134
  568. package/src/collections/email-verified.collection.ts +0 -62
  569. package/src/collections/file.collection.ts +0 -74
  570. package/src/collections/flag-update.collection.ts +0 -57
  571. package/src/collections/flag.collection.ts +0 -57
  572. package/src/collections/log-method-latency.collection.ts +0 -77
  573. package/src/collections/log-subscription.collection.ts +0 -80
  574. package/src/collections/log.collection.ts +0 -93
  575. package/src/collections/logged-in-users.collection.ts +0 -67
  576. package/src/collections/monitor-cpu.collection.ts +0 -65
  577. package/src/collections/monitor-function.collection.ts +0 -74
  578. package/src/collections/monitor-memory.collection.ts +0 -77
  579. package/src/collections/monitor-mongo.collection.ts +0 -71
  580. package/src/collections/notification.collection.ts +0 -57
  581. package/src/collections/openai-usage-ledger.collection.ts +0 -131
  582. package/src/collections/report-builder-dashboard-builder.collection.ts +0 -109
  583. package/src/collections/report-builder-library.collection.ts +0 -89
  584. package/src/collections/report-builder-report.collection.ts +0 -184
  585. package/src/collections/user-group.collection.ts +0 -89
  586. package/src/collections/user-guide.collection.ts +0 -57
  587. package/src/collections/user.collection.ts +0 -181
  588. package/src/cron/cron.ts +0 -117
  589. package/src/fixtures/cron-jobs.ts +0 -95
  590. package/src/fixtures/init.ts +0 -35
  591. package/src/http/auth.ts +0 -818
  592. package/src/http/health.ts +0 -7
  593. package/src/http/home.ts +0 -90
  594. package/src/http/slow-query-publication.ts +0 -49
  595. package/src/index.ts +0 -1
  596. package/src/managers/ai-assistant-codex-manager.manager.ts +0 -1131
  597. package/src/managers/ai-run-evidence.manager.ts +0 -264
  598. package/src/managers/communication-metric.manager.ts +0 -82
  599. package/src/managers/cron.manager.ts +0 -333
  600. package/src/managers/customer-notification-content.manager.ts +0 -236
  601. package/src/managers/diagnostic-manager-bootstrap.ts +0 -165
  602. package/src/managers/error-auto-fix.manager.ts +0 -2767
  603. package/src/managers/local-log.manager.ts +0 -113
  604. package/src/managers/method.manager.ts +0 -1857
  605. package/src/managers/mongo.manager.ts +0 -4575
  606. package/src/managers/monitor.manager.ts +0 -507
  607. package/src/managers/openai-usage-ledger.manager.ts +0 -112
  608. package/src/managers/slow-query-verifier.manager.ts +0 -3590
  609. package/src/managers/slow-query.manager.ts +0 -519
  610. package/src/managers/subscription.manager.ts +0 -3128
  611. package/src/managers/websocket.manager.ts +0 -746
  612. package/src/managers/worker-dispatcher.manager.ts +0 -1360
  613. package/src/managers/worker-server.manager.ts +0 -536
  614. package/src/methods/accounts.ts +0 -532
  615. package/src/methods/ai-terminal.ts +0 -29070
  616. package/src/methods/app-settings.ts +0 -114
  617. package/src/methods/aws.ts +0 -649
  618. package/src/methods/collections.ts +0 -641
  619. package/src/methods/counters.ts +0 -69
  620. package/src/methods/cron-jobs.ts +0 -2614
  621. package/src/methods/customer-notifications.ts +0 -458
  622. package/src/methods/diagnostics.ts +0 -616
  623. package/src/methods/flag-updates.ts +0 -7
  624. package/src/methods/flags.ts +0 -7
  625. package/src/methods/logs.ts +0 -657
  626. package/src/methods/mongo-explorer.ts +0 -1880
  627. package/src/methods/monitor.ts +0 -540
  628. package/src/methods/pdf.ts +0 -1236
  629. package/src/methods/publications.ts +0 -129
  630. package/src/methods/report-builder.ts +0 -3300
  631. package/src/methods/support.ts +0 -335
  632. package/src/models/ai-run.model.ts +0 -27
  633. package/src/models/ai-terminal-conversation.model.ts +0 -19
  634. package/src/models/ai-terminal-issue-report.model.ts +0 -21
  635. package/src/models/ai-terminal-message.model.ts +0 -24
  636. package/src/models/app-setting.model.ts +0 -17
  637. package/src/models/collection-document.model.ts +0 -24
  638. package/src/models/communication-metric.model.ts +0 -23
  639. package/src/models/cron-job-history.model.ts +0 -16
  640. package/src/models/cron-job.model.ts +0 -15
  641. package/src/models/customer-notification.model.ts +0 -28
  642. package/src/models/customer-portal-password.model.ts +0 -12
  643. package/src/models/dialog.model.ts +0 -25
  644. package/src/models/log-method-latency.model.ts +0 -11
  645. package/src/models/log.model.ts +0 -19
  646. package/src/models/method.model.ts +0 -25
  647. package/src/models/monitor-function.model.ts +0 -16
  648. package/src/models/monitor-memory.model.ts +0 -17
  649. package/src/models/monitor-mongo.model.ts +0 -15
  650. package/src/models/openai-usage-ledger.model.ts +0 -56
  651. package/src/models/pagination.model.ts +0 -35
  652. package/src/models/permission.model.ts +0 -14
  653. package/src/models/report-builder-dashboard-builder.model.ts +0 -29
  654. package/src/models/report-builder-library.model.ts +0 -20
  655. package/src/models/report-builder-report.model.ts +0 -136
  656. package/src/models/report-builder.model.ts +0 -68
  657. package/src/models/select-data-label.model.ts +0 -9
  658. package/src/models/server-message.model.ts +0 -31
  659. package/src/models/slow-query-report.model.ts +0 -23
  660. package/src/models/subscription.model.ts +0 -73
  661. package/src/models/support-ticket.model.ts +0 -104
  662. package/src/models/user-group.model.ts +0 -24
  663. package/src/models/user.model.ts +0 -96
  664. package/src/private/images/ResolveIO.png +0 -0
  665. package/src/publications/ai-terminal.ts +0 -73
  666. package/src/publications/app-settings.ts +0 -25
  667. package/src/publications/app-status.ts +0 -13
  668. package/src/publications/cron-jobs.ts +0 -40
  669. package/src/publications/customer-notifications.ts +0 -101
  670. package/src/publications/files.ts +0 -33
  671. package/src/publications/flags-update.ts +0 -19
  672. package/src/publications/flags.ts +0 -19
  673. package/src/publications/logs.ts +0 -163
  674. package/src/publications/notifications.ts +0 -13
  675. package/src/publications/report-builder-dashboard-builders.ts +0 -39
  676. package/src/publications/report-builder-libraries.ts +0 -41
  677. package/src/publications/report-builder-reports.ts +0 -47
  678. package/src/publications/super-admin.ts +0 -13
  679. package/src/publications/user-groups.ts +0 -12
  680. package/src/publications/user-guides.ts +0 -12
  681. package/src/resolveio-server-app.ts +0 -617
  682. package/src/server-app.ts +0 -3354
  683. package/src/services/codex-client.ts +0 -1231
  684. package/src/services/openai-client.ts +0 -265
  685. package/src/types/error-report.ts +0 -26
  686. package/src/types/js-tiktoken.d.ts +0 -11
  687. package/src/types/slow-query-report.ts +0 -28
  688. package/src/util/ai-qa-policy.ts +0 -925
  689. package/src/util/ai-run-evidence-adapters.ts +0 -8347
  690. package/src/util/ai-run-evidence-dashboard.ts +0 -323
  691. package/src/util/ai-run-evidence-eval.ts +0 -1057
  692. package/src/util/ai-run-evidence.ts +0 -1430
  693. package/src/util/ai-runner-artifacts.ts +0 -586
  694. package/src/util/ai-runner-manager-autopilot.ts +0 -961
  695. package/src/util/ai-runner-manager-policy.ts +0 -5011
  696. package/src/util/ai-runner-qa-auth.ts +0 -838
  697. package/src/util/ai-runner-qa-tools.ts +0 -3536
  698. package/src/util/aicoder-runner-v6.ts +0 -3121
  699. package/src/util/common.ts +0 -649
  700. package/src/util/customer-portal-password.ts +0 -183
  701. package/src/util/error-reporter.ts +0 -332
  702. package/src/util/error-tracking.ts +0 -79
  703. package/src/util/openai-usage-cost.ts +0 -114
  704. package/src/util/report-builder-unwinds.ts +0 -180
  705. package/src/util/runner-process-janitor.ts +0 -219
  706. package/src/util/schema-report-builder.ts +0 -448
  707. package/src/util/slow-query-reporter.ts +0 -216
  708. package/src/util/subscription-dependency-context.ts +0 -1096
  709. package/src/util/support-runner-v5.ts +0 -10040
  710. package/src/util/tokenizer.ts +0 -38
  711. package/src/workers/codex-runner.worker.ts +0 -142
  712. package/start_server.sh +0 -5
  713. package/tests/ai-assistant-corpus-build.ts +0 -484
  714. package/tests/ai-assistant-corpus-replay-e2e.ts +0 -774
  715. package/tests/ai-assistant-data-parity-e2e.ts +0 -1989
  716. package/tests/ai-assistant-eval-triage.ts +0 -831
  717. package/tests/ai-assistant-openai-e2e.ts +0 -1061
  718. package/tests/ai-assistant-openai-git-e2e.ts +0 -155
  719. package/tests/ai-assistant-preflight-matrix.ts +0 -215
  720. package/tests/ai-assistant-routing-eval.test.ts +0 -585
  721. package/tests/ai-assistant-snf-live-eval.ts +0 -975
  722. package/tests/ai-assistant-utils.test.ts +0 -4834
  723. package/tests/ai-manager-autopilot-snapshot.test.ts +0 -193
  724. package/tests/ai-manager-recovery-checkpoint.test.ts +0 -1383
  725. package/tests/ai-run-eval.test.ts +0 -132
  726. package/tests/ai-run-evidence.test.ts +0 -3773
  727. package/tests/ai-runner-contract.test.ts +0 -515
  728. package/tests/aicoder-runner-v6.test.ts +0 -822
  729. package/tests/error-reporter.test.ts +0 -145
  730. package/tests/method-publication-generator.test.ts +0 -46
  731. package/tests/report-builder-linking.test.ts +0 -79
  732. package/tests/resolveio-platform-intelligence.test.ts +0 -352
  733. package/tests/server-app-cron-owner.test.ts +0 -127
  734. package/tests/subscription-connect-race.test.ts +0 -158
  735. package/tests/subscription-dependency-context.test.ts +0 -324
  736. package/tests/subscription-manager-collection-tracking.test.ts +0 -86
  737. package/tests/subscription-manager-invalidation.test.ts +0 -86
  738. package/tests/support-runner-v5.test.ts +0 -3201
  739. package/tsconfig.json +0 -34
  740. /package/{src/private → private}/email-templates/enrollment.html +0 -0
  741. /package/{src/private → private}/email-templates/forgot-password.html +0 -0
  742. /package/{src/private → private}/email-templates/support-ticket-deleted.html +0 -0
  743. /package/{src/private → private}/email-templates/support-ticket-modified.html +0 -0
  744. /package/{src/private → private}/email-templates/support-ticket.html +0 -0
  745. /package/{src/public_api.ts → public_api.d.ts} +0 -0
@@ -1,4575 +0,0 @@
1
- import { AggregateOptions, AggregationCursor, BulkWriteOptions, BulkWriteResult, ChangeStream, ChangeStreamOptions, Collection, CollectionInfo, CommandOperationOptions, CountDocumentsOptions, CreateCollectionOptions, CreateIndexesOptions, DeleteOptions, DeleteResult, FindCursor, FindOneAndDeleteOptions, FindOneAndReplaceOptions, FindOneAndUpdateOptions, FindOptions, IndexDescription, IndexDescriptionCompact, IndexInformationOptions, InsertOneOptions, ListIndexesCursor, ListIndexesOptions, OptionalUnlessRequiredId, RenameOptions, ReplaceOptions, UpdateOptions, UpdateResult } from 'mongodb';
2
- import * as NodeCache from 'node-cache';
3
- import SimpleSchema from 'simpl-schema';
4
- import { Users } from '../collections/user.collection';
5
- import { CollectionDocument, Document } from '../models/collection-document.model';
6
- import { LookupTables } from '../models/report-builder.model';
7
- import { UserModel } from '../models/user.model';
8
- import { ResolveIOServer } from '../resolveio-server-app';
9
- import { buildRbLookups, buildRbSchema, dateReviver, deepCopy, getBinarySize, getMongoMergeUpdatedDoc, objectIdHexString } from '../util/common';
10
- import { saveCustomerPortalPassword } from '../util/customer-portal-password';
11
- import { SlowQueryReporter } from '../util/slow-query-reporter';
12
- import { getPublicationContext, QueryMeta, recordAggregateDependencies, recordDependencyResult } from '../util/subscription-dependency-context';
13
- import { MonitorMongo } from './monitor.manager';
14
- const crypto = require('crypto');
15
- const scmp = require('scmp');
16
- const v8 = require('v8');
17
- const { AsyncLocalStorage } = require('async_hooks');
18
- const asyncLocalStorage = new AsyncLocalStorage();
19
-
20
- function resolveHeapLimitBytes(): number {
21
- const stats = v8.getHeapStatistics();
22
- if (stats && typeof stats.heap_size_limit === 'number') {
23
- return stats.heap_size_limit;
24
- }
25
-
26
- if (stats && typeof stats.total_available_size === 'number') {
27
- return stats.total_available_size;
28
- }
29
-
30
- return 0;
31
- }
32
-
33
- function buildQueryMetaFromFindOptions(options?: FindOptions): QueryMeta {
34
- if (!options) {
35
- return null;
36
- }
37
-
38
- const meta: QueryMeta = {};
39
-
40
- if (typeof options.limit === 'number') {
41
- meta.limit = options.limit;
42
- }
43
-
44
- if (typeof options.skip === 'number') {
45
- meta.skip = options.skip;
46
- }
47
-
48
- if (options.sort) {
49
- meta.sort = deepCopy(options.sort);
50
- }
51
-
52
- return Object.keys(meta).length ? meta : null;
53
- }
54
-
55
- type MongoManagerFindOptions = FindOptions;
56
-
57
- function stripManagedVersionFields(update: any): void {
58
- if (!update) {
59
- return;
60
- }
61
-
62
- for (const operator of ['$set', '$setOnInsert']) {
63
- const modifier = update[operator];
64
- if (modifier && typeof modifier === 'object' && '__v' in modifier) {
65
- delete modifier.__v;
66
- if (Object.keys(modifier).length === 0) {
67
- delete update[operator];
68
- }
69
- }
70
- }
71
- }
72
-
73
- // export declare interface MongoManagerFilterOperators<T> extends Document {
74
- export declare interface MongoManagerFilterParamaterOperators<P> {
75
- $eq?: P;
76
- $gt?: P;
77
- $gte?: P;
78
- $in?: [P] extends [Array<any>] ? P : P[];
79
- $lt?: P;
80
- $lte?: P;
81
- $ne?: P;
82
- $nin?: [P] extends [Array<any>] ? P : P[];
83
- $not?: P extends string ? MongoManagerFilterParamaterOperators<P> | RegExpConstructor : MongoManagerFilterParamaterOperators<P>;
84
- $exists?: boolean;
85
- $expr?: any[]
86
- $regex?: P extends string ? RegExpConstructor | string : never;
87
- $options?: P extends string ? string : never;
88
- $geoIntersects?: {
89
- $geometry: Document;
90
- };
91
- $geoWithin?: Document;
92
- $near?: Document;
93
- $nearSphere?: Document;
94
- $maxDistance?: number;
95
- $all?: any[];
96
- $elemMatch?: Document;
97
- $size?: P extends any[] ? number : never;
98
- }
99
-
100
- export declare interface MongoManagerFilterOperators<T> extends Document { //TODO: Remove extends document when I get answer on S.O.
101
- $and?: MongoManagerFilter<T>[] | MongoManagerFilterOperators<T>;
102
- $nor?: MongoManagerFilter<T>[] | MongoManagerFilterOperators<T>;
103
- $or?: MongoManagerFilter<T>[] | MongoManagerFilterOperators<T>;
104
- $text?: {
105
- $search: string;
106
- $language?: string;
107
- $caseSensitive?: boolean;
108
- $diacriticSensitive?: boolean;
109
- };
110
- // eslint-disable-next-line no-unused-vars
111
- $where?: string | ((this: T) => boolean);
112
- $comment?: string | Document;
113
- }
114
-
115
- // function isDotStringRegExp(obj: Object, dotKey: string): boolean {
116
- // let keyData = dotKey.split('.');
117
- // let objData = obj;
118
-
119
- // for (let i = 0; i < keyData.length; i++) {
120
- // let key = keyData[i];
121
- // if (objData.hasOwnProperty(key)) {
122
- // objData = objData[key];
123
-
124
- // if (i === keyData.length - 1) {
125
- // return true;
126
- // }
127
- // }
128
- // else {
129
- // return false;
130
- // }
131
- // }
132
- // }
133
-
134
- // export declare type MongoManagerDotStringFilter<T> = {
135
- // [key: string]: (isDotStringRegExp(T, key) ? any : never);
136
- // };
137
-
138
- export declare type MongoManagerFilter<T> = {
139
- [P in keyof T]?: T[P] | MongoManagerFilterParamaterOperators<T[P]>;
140
- };
141
-
142
- export declare type MongoManagerUnsetFilter<T> = {
143
- // eslint-disable-next-line no-unused-vars
144
- [P in keyof T]?: number | boolean;
145
- };
146
-
147
- export declare type MongoManagerIncFilter<T> = {
148
- // eslint-disable-next-line no-unused-vars
149
- [P in keyof T]?: number;
150
- };
151
-
152
- export declare type MongoManagerRenameFilter<T> = {
153
- // eslint-disable-next-line no-unused-vars
154
- [P in keyof T]?: string;
155
- };
156
-
157
- export declare type MongoManagerArrayFilter<T> = {
158
- // eslint-disable-next-line no-unused-vars
159
- [P in keyof T]?: any; // can refine if needed
160
- };
161
-
162
- export declare type MongoManagerCurrentDateFilter<T> = {
163
- // eslint-disable-next-line no-unused-vars
164
- [P in keyof T]?: true | { $type: 'date' | 'timestamp' };
165
- };
166
-
167
- export declare type MongoManagerUpdateFilter<T> = {
168
- $set?: MongoManagerFilter<T> | Document;
169
- $unset?: MongoManagerUnsetFilter<T> | Document;
170
- $inc?: MongoManagerIncFilter<T> | Document;
171
- $setOnInsert?: MongoManagerFilter<T> | Document;
172
- $push?: MongoManagerArrayFilter<T> | Document;
173
- $pull?: MongoManagerArrayFilter<T> | Document;
174
- $addToSet?: MongoManagerArrayFilter<T> | Document;
175
- $min?: MongoManagerIncFilter<T> | Document;
176
- $max?: MongoManagerIncFilter<T> | Document;
177
- $currentDate?: MongoManagerCurrentDateFilter<T> | Document;
178
- $mul?: MongoManagerIncFilter<T> | Document;
179
- $rename?: MongoManagerRenameFilter<T>;
180
- };
181
-
182
- export class MongoManager {
183
- private _collections: MongoManagerCollection<CollectionDocument>[] = [];
184
- private _nodeCache;
185
- private _cacheMap: { collections: string[], key: string }[] = [];
186
- private _operationInProgress: Map<string, { promise: Promise<any>, invalidatedDuringExecution: boolean, collections: string[] }> = new Map();
187
- private _heapSize = resolveHeapLimitBytes();
188
- private _heapLimit: number;
189
- private _serverCollections: (CollectionInfo | Pick<CollectionInfo, 'name' | 'type'>)[] = [];
190
- private _isWorkersEnabled = false;
191
- private _isWorkerInstance = false;
192
- private _watchedDatabases: string[] = [];
193
- private _mainDatabaseName = '';
194
- private _changeStream: ChangeStream | null = null;
195
- private _changeStreamRestartTimeout: NodeJS.Timeout | null = null;
196
-
197
- constructor() {}
198
-
199
- static async create() {
200
- const mongoManager = new MongoManager();
201
- await mongoManager.initialize();
202
- return mongoManager;
203
- }
204
-
205
- private async initialize() {
206
- this._nodeCache = new NodeCache({ stdTTL: 0, checkperiod: 0 });
207
-
208
- this._isWorkersEnabled = process.env.IS_WORKERS_ENABLED === 'true';
209
- this._isWorkerInstance = process.env.IS_WORKER_INSTANCE === 'true';
210
- this._mainDatabaseName = ResolveIOServer.getServerConfig() ? ResolveIOServer.getServerConfig()['DATABASE'] : '';
211
- this._watchedDatabases = this.resolveWatchedDatabases();
212
- this.setCacheLimit();
213
-
214
- if (this._isWorkersEnabled && this._isWorkerInstance) {
215
- await this.setupChangeStream();
216
- }
217
-
218
- let collections = await ResolveIOServer.getMainDB().listCollections().toArray();
219
- this._serverCollections = collections;
220
- }
221
-
222
- private resolveWatchedDatabases(): string[] {
223
- const config = ResolveIOServer.getServerConfig ? ResolveIOServer.getServerConfig() : null;
224
- const watchSet = new Set<string>();
225
-
226
- if (this._mainDatabaseName) {
227
- watchSet.add(this._mainDatabaseName);
228
- }
229
-
230
- const configValue = config ? config['WATCH_DATABASES'] : null;
231
-
232
- if (Array.isArray(configValue)) {
233
- for (const value of configValue) {
234
- if (typeof value === 'string' && value.trim()) {
235
- watchSet.add(value.trim());
236
- }
237
- }
238
- }
239
- else if (typeof configValue === 'string' && configValue.trim()) {
240
- configValue.split(',').map(a => a.trim()).filter(a => a.length).forEach(a => watchSet.add(a));
241
- }
242
-
243
- const envValue = process.env.MONGO_WATCH_DATABASES;
244
- if (envValue) {
245
- envValue.split(',').map(a => a.trim()).filter(a => a.length).forEach(a => watchSet.add(a));
246
- }
247
-
248
- return Array.from(watchSet.values());
249
- }
250
-
251
- public getWatchedDatabases(): string[] {
252
- return this._watchedDatabases;
253
- }
254
-
255
- oneTimeTransaction<T>(fn: () => Promise<T>): Promise<T> {
256
- return asyncLocalStorage.run({}, async () => {
257
- let attempt = 0;
258
- const maxRetries = 4;
259
- while (true) {
260
- const session = ResolveIOServer.getMongoConnection().startSession();
261
- const store = asyncLocalStorage.getStore();
262
- if (store) {
263
- store.session = session;
264
- }
265
- try {
266
- let result: T | undefined;
267
- await session.withTransaction(async () => {
268
- result = await fn();
269
- return result;
270
- });
271
- return result as T;
272
- }
273
- catch (err) {
274
- if (!this.shouldRetryTransactionError(err) || attempt >= maxRetries) {
275
- throw err;
276
- }
277
- if (this.shouldRetryConnectionError(err)) {
278
- try {
279
- await ResolveIOServer.requestMongoReconnect('mongo-transaction-retry', err);
280
- }
281
- catch {}
282
- }
283
- attempt += 1;
284
- const jitter = Math.floor(Math.random() * 60);
285
- await this.delay((120 * attempt) + jitter);
286
- }
287
- finally {
288
- try {
289
- await session.endSession();
290
- }
291
- catch {}
292
- const activeStore = asyncLocalStorage.getStore();
293
- if (activeStore) {
294
- delete activeStore.session;
295
- }
296
- }
297
- }
298
- });
299
- }
300
-
301
- getSession() {
302
- const store = asyncLocalStorage.getStore();
303
- return store ? store.session : null;
304
- }
305
-
306
- runWithoutSession<T>(fn: () => Promise<T> | T): Promise<T> {
307
- return asyncLocalStorage.run({}, async () => {
308
- return await fn();
309
- });
310
- }
311
-
312
- private setCacheLimit() {
313
- if (this._isWorkersEnabled) {
314
- this._heapLimit = this._isWorkerInstance ? this._heapSize * 0.8 : this._heapSize * 0.4;
315
- }
316
- else {
317
- this._heapLimit = this._heapSize * 0.3;
318
- }
319
- }
320
-
321
- getServerCollections() {
322
- return this._serverCollections;
323
- }
324
-
325
- async registerCollection(collection: MongoManagerCollection<CollectionDocument>) {
326
- if (
327
- collection.collectionOptions &&
328
- collection.collectionOptions.timeseries &&
329
- collection.collectionOptions.timeseries.timeField &&
330
- this._serverCollections.some(a => a.name === collection.collectionName && a.type === 'collection')
331
- ) {
332
- await ResolveIOServer.getMainDB().dropCollection(collection.collectionName);
333
- await this.createCollection(collection);
334
- }
335
-
336
- this._collections.push(collection);
337
- }
338
-
339
- async createCollection(collection: MongoManagerCollection<CollectionDocument>) {
340
- await ResolveIOServer.getMainDB().createCollection(collection.collectionName, collection.collectionOptions);
341
- }
342
-
343
- collections() {
344
- return this._collections;
345
- }
346
-
347
- collection(collectionName: string): MongoManagerCollection<CollectionDocument> | MongoManagerUserCollection<CollectionDocument> {
348
- return this._collections.find(a => a.collectionName === collectionName);
349
- }
350
-
351
- private async delay(ms: number) {
352
- // eslint-disable-next-line no-restricted-syntax
353
- return new Promise(resolve => setTimeout(resolve, ms));
354
- }
355
-
356
- private hasMongoErrorLabel(err: any, label: string): boolean {
357
- if (!err || !label) {
358
- return false;
359
- }
360
- if (typeof err.hasErrorLabel === 'function') {
361
- try {
362
- if (err.hasErrorLabel(label)) {
363
- return true;
364
- }
365
- }
366
- catch {}
367
- }
368
- if (Array.isArray(err.errorLabels) && err.errorLabels.includes(label)) {
369
- return true;
370
- }
371
- return false;
372
- }
373
-
374
- private shouldRetryWriteConflict(err: any): boolean {
375
- if (!err) {
376
- return false;
377
- }
378
- if (err.code === 112 || err.codeName === 'WriteConflict') {
379
- return true;
380
- }
381
- const message = String(err.message || '');
382
- return /write conflict/i.test(message) || /yielding is disabled/i.test(message);
383
- }
384
-
385
- private shouldRetryTransactionError(err: any): boolean {
386
- if (!err) {
387
- return false;
388
- }
389
- if (this.shouldRetryWriteConflict(err) || this.shouldRetryWaitQueueTimeout(err) || this.shouldRetryConnectionError(err)) {
390
- return true;
391
- }
392
- return this.hasMongoErrorLabel(err, 'TransientTransactionError')
393
- || this.hasMongoErrorLabel(err, 'UnknownTransactionCommitResult');
394
- }
395
-
396
- private shouldRetryWaitQueueTimeout(err: any): boolean {
397
- if (!err) {
398
- return false;
399
- }
400
-
401
- if (err.name === 'MongoWaitQueueTimeoutError' || err.codeName === 'MongoWaitQueueTimeoutError') {
402
- return true;
403
- }
404
-
405
- return typeof err.message === 'string' && err.message.includes('Timed out while checking out a connection from connection pool');
406
- }
407
-
408
- private shouldRetryConnectionError(err: any): boolean {
409
- if (!err) {
410
- return false;
411
- }
412
-
413
- const name = String(err.name || err.codeName || '');
414
- if (
415
- name === 'MongoPoolClearedError'
416
- || name === 'MongoNetworkError'
417
- || name === 'MongoNetworkTimeoutError'
418
- || name === 'MongoServerSelectionError'
419
- || name === 'MongoTopologyClosedError'
420
- || name === 'MongoNotConnectedError'
421
- || name === 'MongoClientClosedError'
422
- ) {
423
- return true;
424
- }
425
-
426
- const message = String(err.message || '');
427
- return /connection pool .* was cleared/i.test(message)
428
- || /topology is closed/i.test(message)
429
- || /client was closed/i.test(message)
430
- || /not connected/i.test(message)
431
- || /server selection timed out/i.test(message)
432
- || /econnrefused|econnreset|etimedout|ehostunreach/i.test(message);
433
- }
434
-
435
- private async retryRead<TResult>(operation: () => Promise<TResult>, options?: { session?: any }): Promise<TResult> {
436
- if (options && options.session && typeof options.session.inTransaction === 'function' && options.session.inTransaction()) {
437
- return operation();
438
- }
439
-
440
- let attempt = 0;
441
- const maxRetries = 2;
442
-
443
- while (true) {
444
- try {
445
- return await operation();
446
- }
447
- catch (err) {
448
- const shouldRetry = this.shouldRetryWaitQueueTimeout(err) || this.shouldRetryConnectionError(err);
449
- if (!shouldRetry || attempt >= maxRetries) {
450
- throw err;
451
- }
452
- if (this.shouldRetryConnectionError(err)) {
453
- try {
454
- await ResolveIOServer.requestMongoReconnect('mongo-read-retry', err);
455
- }
456
- catch {}
457
- }
458
-
459
- attempt += 1;
460
- await this.delay(100 * attempt);
461
- }
462
- }
463
- }
464
-
465
- public async find<T extends CollectionDocument>(
466
- collectionName: string,
467
- filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {},
468
- options?: MongoManagerFindOptions
469
- ): Promise<T[]> {
470
- // eslint-disable-next-line no-unused-vars
471
- let { session, ...safeOptions } = options || {};
472
- const cacheKey = this.generateCacheKey([collectionName], 'find', [filter, safeOptions]);
473
- let result = this.getFromCache(cacheKey);
474
- if (result !== undefined) {
475
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
476
- console.log(new Date(), 'Mongo Find - Cache', collectionName);
477
- }
478
- recordDependencyResult(collectionName, result, { filter, meta: buildQueryMetaFromFindOptions(safeOptions) });
479
- return result;
480
- }
481
-
482
- if (this._operationInProgress.has(cacheKey)) {
483
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
484
- console.log(new Date(), 'Mongo Find - Already running', collectionName);
485
- }
486
- return this._operationInProgress.get(cacheKey).promise;
487
- }
488
-
489
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
490
- console.log(new Date(), 'Mongo Find - Running', collectionName);
491
- }
492
-
493
- const operation = this.executeFind<T>(collectionName, filter, options, cacheKey);
494
- this._operationInProgress.set(cacheKey, {
495
- promise: operation,
496
- invalidatedDuringExecution: false,
497
- collections: [collectionName]
498
- });
499
-
500
- await operation.finally(() => {
501
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
502
- console.log(new Date(), 'Mongo Find - Done', collectionName);
503
- }
504
-
505
- this._operationInProgress.delete(cacheKey);
506
- });
507
-
508
- return operation;
509
- }
510
-
511
- private async executeFind<T extends CollectionDocument>(
512
- collectionName: string,
513
- filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>,
514
- options: MongoManagerFindOptions | undefined,
515
- cacheKey: string
516
- ): Promise<T[]> {
517
- let result;
518
- const collection = ResolveIOServer.getMainDB().collection(collectionName);
519
-
520
- // eslint-disable-next-line no-unused-vars
521
- let { session, ...safeOptions } = options || {};
522
- const pubContext = getPublicationContext();
523
- const monitor = MonitorMongo.create('find', collectionName, JSON.stringify([filter, safeOptions]));
524
- const queryStart = Date.now();
525
-
526
- try {
527
- result = await this.retryRead(() => collection.find<T>(<any>filter, options).toArray(), options);
528
- }
529
- catch (err) {
530
- console.log(JSON.stringify([new Date(), 'Error Execute Find', collectionName, filter, safeOptions, {
531
- code: err.code,
532
- codeName: err.codeName,
533
- message: err.message,
534
- stack: err.stack
535
- }], null, 2));
536
-
537
- err.message = `Error in Execute Find: ${collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
538
- throw err;
539
- }
540
- finally {
541
- const durationMs = Date.now() - queryStart;
542
- await monitor.finish();
543
- SlowQueryReporter.reportSlowQueryFireAndForget({
544
- collection: collectionName,
545
- filter,
546
- options: safeOptions,
547
- durationMs,
548
- queryType: 'find',
549
- notes: 'MongoManager executeFind',
550
- publication: pubContext.publication,
551
- subscriptionData: pubContext.subscriptionData,
552
- userId: pubContext.userId
553
- });
554
- }
555
-
556
- recordDependencyResult(collectionName, result, { filter, meta: buildQueryMetaFromFindOptions(safeOptions) });
557
-
558
- if (!this._operationInProgress.get(cacheKey).invalidatedDuringExecution) {
559
- this.addToCache([collectionName], cacheKey, result);
560
- }
561
-
562
- return result;
563
- }
564
-
565
- // FindOne Operation
566
- public async findOne<T extends CollectionDocument>(
567
- collectionName: string,
568
- filter: MongoManagerFilter<T> | MongoManagerFilterOperators<T> = {},
569
- options?: MongoManagerFindOptions
570
- ): Promise<T> {
571
- // eslint-disable-next-line no-unused-vars
572
- let { session, ...safeOptions } = options || {};
573
- const cacheKey = this.generateCacheKey([collectionName], 'findOne', [filter, safeOptions]);
574
- let result = this.getFromCache(cacheKey);
575
- if (result !== undefined) {
576
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
577
- console.log(new Date(), 'Mongo FindOne - Cache', collectionName);
578
- }
579
-
580
- recordDependencyResult(collectionName, result, { filter, meta: buildQueryMetaFromFindOptions(safeOptions) });
581
-
582
- return result;
583
- }
584
-
585
- if (this._operationInProgress.has(cacheKey)) {
586
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
587
- console.log(new Date(), 'Mongo FindOne - Already running', collectionName);
588
- }
589
-
590
- return this._operationInProgress.get(cacheKey).promise;
591
- }
592
-
593
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
594
- console.log(new Date(), 'Mongo FindOne - Running', collectionName);
595
- }
596
-
597
- const operation = this.executeFindOne<T>(collectionName, filter, options, cacheKey);
598
- this._operationInProgress.set(cacheKey, {
599
- promise: operation,
600
- invalidatedDuringExecution: false,
601
- collections: [collectionName]
602
- });
603
-
604
- await operation.finally(() => {
605
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
606
- console.log(new Date(), 'Mongo FindOne - Done', collectionName);
607
- }
608
-
609
- this._operationInProgress.delete(cacheKey);
610
- });
611
-
612
- return operation;
613
- }
614
-
615
- private async executeFindOne<T extends CollectionDocument>(
616
- collectionName: string,
617
- filter: MongoManagerFilter<T> | MongoManagerFilterOperators<T>,
618
- options: MongoManagerFindOptions | undefined,
619
- cacheKey: string
620
- ): Promise<T> {
621
- let result;
622
- const collection = ResolveIOServer.getMainDB().collection(collectionName);
623
-
624
- // eslint-disable-next-line no-unused-vars
625
- let { session, ...safeOptions } = options || {};
626
- const pubContext = getPublicationContext();
627
- const monitor = MonitorMongo.create('findOne', collectionName, JSON.stringify([filter, safeOptions]));
628
- const queryStart = Date.now();
629
-
630
- try {
631
- result = await this.retryRead(() => collection.findOne<T>(<any>filter, options || undefined), options);
632
- }
633
- catch (err) {
634
- console.log(JSON.stringify([new Date(), 'Error Execute Find One', collectionName, filter, safeOptions, {
635
- code: err.code,
636
- codeName: err.codeName,
637
- message: err.message,
638
- stack: err.stack
639
- }], null, 2));
640
-
641
- err.message = `Error in Execute Find One: ${collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
642
- throw err;
643
- }
644
- finally {
645
- const durationMs = Date.now() - queryStart;
646
- await monitor.finish();
647
- SlowQueryReporter.reportSlowQueryFireAndForget({
648
- collection: collectionName,
649
- filter,
650
- options: safeOptions,
651
- durationMs,
652
- queryType: 'findOne',
653
- notes: 'MongoManager executeFindOne',
654
- publication: pubContext.publication,
655
- subscriptionData: pubContext.subscriptionData,
656
- userId: pubContext.userId
657
- });
658
- }
659
-
660
- recordDependencyResult(collectionName, result, { filter, meta: buildQueryMetaFromFindOptions(safeOptions) });
661
-
662
- if (!this._operationInProgress.get(cacheKey).invalidatedDuringExecution) {
663
- this.addToCache([collectionName], cacheKey, result);
664
- }
665
-
666
- return result;
667
- }
668
-
669
- // Aggregate Operation
670
- public async aggregate<T extends CollectionDocument>(
671
- collectionName: string,
672
- pipeline: any[],
673
- options?: AggregateOptions
674
- ): Promise<any[]> {
675
- const collections = [collectionName, ...pipeline.flatMap(stage => stage.$lookup?.from ? [stage.$lookup.from] : [])];
676
-
677
- // eslint-disable-next-line no-unused-vars
678
- let { session, ...safeOptions } = options || {};
679
- const cacheKey = this.generateCacheKey(collections, 'aggregate', [pipeline, safeOptions]);
680
- let result = this.getFromCache(cacheKey);
681
- if (result !== undefined) {
682
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
683
- console.log(new Date(), 'Mongo Agg - Cache', collections);
684
- }
685
- recordAggregateDependencies(collectionName, pipeline, result);
686
- return result;
687
- }
688
-
689
- if (this._operationInProgress.has(cacheKey)) {
690
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
691
- console.log(new Date(), 'Mongo Agg - Already running', collections);
692
- }
693
-
694
- return this._operationInProgress.get(cacheKey).promise;
695
- }
696
-
697
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
698
- console.log(new Date(), 'Mongo Agg - Running', collections);
699
- }
700
-
701
- const operation = this.executeAggregate<T>(collectionName, pipeline, options, cacheKey, collections);
702
- this._operationInProgress.set(cacheKey, {
703
- promise: operation,
704
- invalidatedDuringExecution: false,
705
- collections: collections
706
- });
707
-
708
- await operation.finally(() => {
709
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
710
- console.log(new Date(), 'Mongo Agg - Done', collections);
711
- }
712
-
713
- this._operationInProgress.delete(cacheKey);
714
- });
715
-
716
- return operation;
717
- }
718
-
719
- private async executeAggregate<T extends CollectionDocument>(
720
- collectionName: string,
721
- pipeline: any[],
722
- options: AggregateOptions | undefined,
723
- cacheKey: string,
724
- collections: string[]
725
- ): Promise<any[]> {
726
- let result;
727
- const collection = ResolveIOServer.getMainDB().collection(collectionName);
728
-
729
- // eslint-disable-next-line no-unused-vars
730
- let { session, ...safeOptions } = options || {};
731
- const pubContext = getPublicationContext();
732
- const monitor = MonitorMongo.create('aggregate', collectionName, JSON.stringify([pipeline, safeOptions]));
733
- const queryStart = Date.now();
734
-
735
- try {
736
- result = await this.retryRead(() => collection.aggregate<T>(pipeline, options).toArray(), options);
737
- }
738
- catch (err) {
739
- console.log(JSON.stringify([new Date(), 'Error Execute Aggregate', collectionName, pipeline, collections, safeOptions, {
740
- code: err.code,
741
- codeName: err.codeName,
742
- message: err.message,
743
- stack: err.stack
744
- }], null, 2));
745
-
746
- err.message = `Error in Execute Aggregate: ${collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
747
- throw err;
748
- }
749
- finally {
750
- const durationMs = Date.now() - queryStart;
751
- await monitor.finish();
752
- SlowQueryReporter.reportSlowQueryFireAndForget({
753
- collection: collectionName,
754
- pipeline,
755
- options: safeOptions,
756
- durationMs,
757
- queryType: 'aggregate',
758
- notes: 'MongoManager executeAggregate',
759
- publication: pubContext.publication,
760
- subscriptionData: pubContext.subscriptionData,
761
- userId: pubContext.userId
762
- });
763
- }
764
-
765
- recordAggregateDependencies(collectionName, pipeline, result);
766
-
767
- if (!this._operationInProgress.get(cacheKey).invalidatedDuringExecution) {
768
- this.addToCache(collections, cacheKey, result);
769
- }
770
-
771
- return result;
772
- }
773
-
774
- public async countDocuments<T extends CollectionDocument>(
775
- collectionName: string,
776
- filter: MongoManagerFilter<T> | MongoManagerFilterOperators<T> = {},
777
- options?: CountDocumentsOptions
778
- ): Promise<number> {
779
- // eslint-disable-next-line no-unused-vars
780
- let { session, ...safeOptions } = options || {};
781
- const cacheKey = this.generateCacheKey([collectionName], 'countDocuments', [filter, safeOptions]);
782
- let result = this.getFromCache(cacheKey);
783
- if (result !== undefined) {
784
- recordDependencyResult(collectionName, result, { filter });
785
- return result;
786
- }
787
-
788
- if (this._operationInProgress.has(cacheKey)) {
789
- return this._operationInProgress.get(cacheKey).promise;
790
- }
791
-
792
- const operation = this.executeCountDocuments<T>(collectionName, filter, options, cacheKey);
793
- this._operationInProgress.set(cacheKey, {
794
- promise: operation,
795
- invalidatedDuringExecution: false,
796
- collections: [collectionName]
797
- });
798
-
799
- await operation.finally(() => this._operationInProgress.delete(cacheKey));
800
-
801
- return operation;
802
- }
803
-
804
- private async executeCountDocuments<T extends CollectionDocument>(
805
- collectionName: string,
806
- filter: MongoManagerFilter<T> | MongoManagerFilterOperators<T>,
807
- options: CountDocumentsOptions,
808
- cacheKey: string
809
- ): Promise<number> {
810
- let result;
811
- const collection = ResolveIOServer.getMainDB().collection(collectionName);
812
-
813
- // eslint-disable-next-line no-unused-vars
814
- let { session, ...safeOptions } = options || {};
815
- const pubContext = getPublicationContext();
816
- const monitor = MonitorMongo.create('countDocuments', collectionName, JSON.stringify([filter, safeOptions]));
817
- const queryStart = Date.now();
818
-
819
- try {
820
- result = await this.retryRead(() => collection.countDocuments(<any>filter, options || undefined), options);
821
- }
822
- catch (err) {
823
- console.log(JSON.stringify([new Date(), 'Error Execute Count Documents', collectionName, filter, safeOptions, {
824
- code: err.code,
825
- codeName: err.codeName,
826
- message: err.message,
827
- stack: err.stack
828
- }], null, 2));
829
-
830
- err.message = `Error in Execute Count Documents: ${collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
831
- throw err;
832
- }
833
- finally {
834
- const durationMs = Date.now() - queryStart;
835
- await monitor.finish();
836
- SlowQueryReporter.reportSlowQueryFireAndForget({
837
- collection: collectionName,
838
- filter,
839
- options: safeOptions,
840
- durationMs,
841
- queryType: 'countDocuments',
842
- notes: 'MongoManager executeCountDocuments',
843
- publication: pubContext.publication,
844
- subscriptionData: pubContext.subscriptionData,
845
- userId: pubContext.userId
846
- });
847
- }
848
-
849
- recordDependencyResult(collectionName, result, { filter });
850
-
851
- if (!this._operationInProgress.get(cacheKey).invalidatedDuringExecution) {
852
- this.addToCache([collectionName], cacheKey, result);
853
- }
854
-
855
- return result;
856
- }
857
-
858
- // Cache and Invalidation Setup
859
- private generateCacheKey(collections: string[], functionName: string, args: any[]): string {
860
- const keyString = JSON.stringify({ collections, functionName, args });
861
- return crypto.createHash('sha256').update(keyString).digest('hex');
862
- }
863
-
864
- private getFromCache(cacheKey: string): any | undefined {
865
- try {
866
- const cachedData = this._nodeCache.get(cacheKey);
867
- if (cachedData) {
868
- return JSON.parse(cachedData, dateReviver);
869
- }
870
- }
871
- catch {
872
- this._nodeCache.del(cacheKey);
873
- }
874
-
875
- return undefined;
876
- }
877
-
878
- private addToCache(collections: string[], cacheKey: string, data: any) {
879
- if (getBinarySize(JSON.stringify(data)) < 1000000 &&
880
- !collections.includes('logs') &&
881
- !collections.find(a => a.endsWith('.versions')) &&
882
- !collections.find(a => a.startsWith('monitor-'))
883
- ) {
884
- let nodeCacheSize = this._nodeCache.getStats().vsize;
885
-
886
- if (nodeCacheSize > this._heapLimit) {
887
- let deleteCount = 0;
888
- const keys = this._nodeCache.keys();
889
-
890
- for (const key of keys) {
891
- this._nodeCache.del(key);
892
- deleteCount += 1;
893
-
894
- nodeCacheSize = this._nodeCache.getStats().vsize;
895
-
896
- if (nodeCacheSize < this._heapLimit * 0.75) {
897
- break;
898
- }
899
- }
900
-
901
- console.log('Query Cache: ' + 'Too Big, - Deleted: ' + deleteCount + ' - ' + nodeCacheSize);
902
- }
903
-
904
- this._nodeCache.set(cacheKey, JSON.stringify(data));
905
- this._cacheMap.push({ collections, key: cacheKey });
906
- }
907
- }
908
-
909
- public invalidateQueryCache(collection: string, bypassLocalOplog = false) {
910
- const collectionCacheMap = this._cacheMap.filter(a => a.collections.includes(collection));
911
-
912
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
913
- console.log(new Date(), 'Mongo Invalidate Cache', collection);
914
- }
915
-
916
- for (const cacheMap of collectionCacheMap) {
917
- this._nodeCache.del(cacheMap.key);
918
-
919
- if (this._operationInProgress.has(cacheMap.key)) {
920
- this._operationInProgress.get(cacheMap.key).invalidatedDuringExecution = true;
921
-
922
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
923
- console.log(new Date(), 'Mongo Invalidated During Execution', cacheMap.collections);
924
- }
925
- }
926
- }
927
-
928
- // eslint-disable-next-line no-unused-vars
929
- for (const [key, operation] of this._operationInProgress.entries()) {
930
- if (operation.collections.includes(collection)) {
931
- operation.invalidatedDuringExecution = true;
932
-
933
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
934
- console.log(new Date(), 'Mongo Invalidated During Execution (No cache)', operation.collections);
935
- }
936
- }
937
- }
938
-
939
- this._cacheMap = this._cacheMap.filter(a => !a.collections.includes(collection));
940
-
941
- if (!bypassLocalOplog && ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getUseLocalOplog()) {
942
- ResolveIOServer.getMainServer().getSubscriptionManager().notifyLocalOplog(collection, 'update');
943
- }
944
- }
945
-
946
- public clearQueryCache(reason?: string) {
947
- if (ResolveIOServer.getMainServer().getSubscriptionManager() && ResolveIOServer.getMainServer().getSubscriptionManager().getEnableDebug()) {
948
- console.log(new Date(), 'Mongo Clear Cache', reason || '');
949
- }
950
-
951
- try {
952
- this._nodeCache.flushAll();
953
- }
954
- catch {
955
- // ignore flush errors
956
- }
957
-
958
- this._cacheMap = [];
959
-
960
- // Mark all in-flight ops invalidated so they don't repopulate cache with stale data.
961
- // eslint-disable-next-line no-unused-vars
962
- for (const [key, operation] of this._operationInProgress.entries()) {
963
- operation.invalidatedDuringExecution = true;
964
- }
965
- }
966
-
967
- public async handleMongoReconnect(reason: string): Promise<void> {
968
- this.clearQueryCache(`mongo-reconnect:${reason}`);
969
-
970
- if (this._isWorkersEnabled && this._isWorkerInstance) {
971
- try {
972
- await this.setupChangeStream();
973
- }
974
- catch (error) {
975
- console.log(new Date(), 'Mongo handle reconnect: change stream restart failed', reason, error);
976
- this.scheduleChangeStreamRestart();
977
- }
978
- }
979
- }
980
-
981
- private async setupChangeStream() {
982
- if (!this._isWorkersEnabled || !this._isWorkerInstance) {
983
- return;
984
- }
985
-
986
- if (this._changeStreamRestartTimeout) {
987
- clearTimeout(this._changeStreamRestartTimeout);
988
- this._changeStreamRestartTimeout = null;
989
- }
990
-
991
- await this.teardownChangeStream(true);
992
-
993
- const client = ResolveIOServer.getMongoConnection();
994
-
995
- if (!client) {
996
- this.scheduleChangeStreamRestart();
997
- return;
998
- }
999
-
1000
- const watchDatabases = this._watchedDatabases.length ? this._watchedDatabases : (this._mainDatabaseName ? [this._mainDatabaseName] : []);
1001
-
1002
- const pipeline = [
1003
- {
1004
- $match: {
1005
- $and: [
1006
- ...(watchDatabases.length ? [{ 'ns.db': { $in: watchDatabases } }] : []),
1007
- {'ns.coll': { $nin: [
1008
- 'log-method-latencies',
1009
- 'log-subscriptions',
1010
- 'logs',
1011
- 'counters',
1012
- 'cron-job-histories',
1013
- 'email-histories',
1014
- 'qb-soap-request-histories',
1015
- 'qb-soap-request-responses',
1016
- 'qb-soap-requests',
1017
- 'qb-soap-retries',
1018
- 'subscription-manager-resume-tokens'
1019
- ] }},
1020
- {'ns.coll': { $not: /.*\.versions$/ }},
1021
- {'ns.coll': { $not: /^monitor-/ }},
1022
- ]
1023
- },
1024
- },
1025
- ];
1026
-
1027
- let changeStream: ChangeStream;
1028
-
1029
- try {
1030
- changeStream = client.watch(pipeline, { fullDocument: 'updateLookup' });
1031
- }
1032
- catch (err) {
1033
- console.log(new Date(), 'Mongo change stream setup failed. Restarting...', err);
1034
- this.scheduleChangeStreamRestart();
1035
- return;
1036
- }
1037
-
1038
- this._changeStream = changeStream;
1039
-
1040
- changeStream.on('change', (change: any) => {
1041
- if (change['ns'] && change['ns'].coll) {
1042
- const collectionName = change['ns'].coll;
1043
- const collection = this.collection(collectionName);
1044
-
1045
- if (collection) {
1046
- this.invalidateQueryCache(collectionName);
1047
- }
1048
- }
1049
- });
1050
-
1051
- changeStream.on('error', async error => {
1052
- await this.handleChangeStreamFailure('error', error);
1053
- });
1054
-
1055
- changeStream.on('close', async () => {
1056
- await this.handleChangeStreamFailure('close');
1057
- });
1058
- }
1059
-
1060
- private async teardownChangeStream(forceClose: boolean) {
1061
- if (!this._changeStream) {
1062
- return;
1063
- }
1064
-
1065
- const currentStream = this._changeStream;
1066
- this._changeStream = null;
1067
-
1068
- currentStream.removeAllListeners();
1069
-
1070
- if (forceClose) {
1071
- try {
1072
- await currentStream.close();
1073
- }
1074
- catch (err) {
1075
- console.log(new Date(), 'Mongo change stream close failed', err);
1076
- }
1077
- }
1078
- }
1079
-
1080
- private async handleChangeStreamFailure(reason: 'error' | 'close', error?: unknown) {
1081
- if (reason === 'error') {
1082
- console.log(new Date(), 'Mongo change stream error. Restart...', error);
1083
- await this.teardownChangeStream(true);
1084
- }
1085
- else {
1086
- console.log(new Date(), 'Mongo change stream closed. Restarting...');
1087
- await this.teardownChangeStream(false);
1088
- }
1089
-
1090
- this.scheduleChangeStreamRestart();
1091
- }
1092
-
1093
- private scheduleChangeStreamRestart(delayMs = 5000) {
1094
- if (this._changeStreamRestartTimeout) {
1095
- return;
1096
- }
1097
-
1098
- this._changeStreamRestartTimeout = setTimeout(async () => {
1099
- this._changeStreamRestartTimeout = null;
1100
-
1101
- try {
1102
- await this.setupChangeStream();
1103
- }
1104
- catch (err) {
1105
- console.log(new Date(), 'Mongo change stream restart failed. Retrying...', err);
1106
- this.scheduleChangeStreamRestart(Math.min(delayMs * 2, 60000));
1107
- }
1108
- }, delayMs);
1109
- }
1110
- }
1111
-
1112
- export class MongoManagerModel<T extends CollectionDocument> {
1113
- collection_main: MongoManagerCollection<T> | MongoManagerUserCollection<T> = null;
1114
- collection_version: MongoManagerCollection<T> | MongoManagerUserCollection<T> = null;
1115
-
1116
- constructor() {}
1117
-
1118
- static create<T>(options: MongoManagerCollectionOptions): MongoManagerModel<T> {
1119
- const mongoManagerModel = new MongoManagerModel<T>();
1120
- mongoManagerModel.initialize(options);
1121
- return mongoManagerModel;
1122
- }
1123
-
1124
- private initialize(options: MongoManagerCollectionOptions) {
1125
- if (options.collectionName === 'users') {
1126
- this.collection_main = MongoManagerUserCollection.create(options) as MongoManagerUserCollection<T>;
1127
- }
1128
- else {
1129
- this.collection_main = MongoManagerCollection.create(options) as MongoManagerCollection<T>;
1130
- }
1131
-
1132
- if (options.useVersionCollection) {
1133
- this.collection_main.useVersions = true;
1134
-
1135
- let versionSchema = deepCopy(options.schema);
1136
- versionSchema._id = versionSchema._id || {};
1137
- versionSchema._id.type = 'Object';
1138
- versionSchema._id.blackbox = true;
1139
-
1140
- let versionOptions: MongoManagerCollectionOptions = {
1141
- collectionName: options.collectionName + '.versions',
1142
- schema: versionSchema,
1143
- useVersionCollection: false,
1144
- useReportBuilder: false,
1145
- reportBuilderLookupTables: [],
1146
- timestamps: true,
1147
- createLogs: false,
1148
- checkSchema: false,
1149
- collectionOptions: null,
1150
- skipCache: true,
1151
- bypassSession: true
1152
- };
1153
-
1154
- if (options.collectionName === 'users') {
1155
- this.collection_version = MongoManagerUserCollection.create(versionOptions) as MongoManagerUserCollection<T>;
1156
- }
1157
- else {
1158
- this.collection_version = MongoManagerCollection.create(versionOptions) as MongoManagerCollection<T>;
1159
- }
1160
-
1161
- setImmediate(async () => {
1162
- await this.collection_version.createIndex({'_id._id': 1, '_id.__v': 1});
1163
- });
1164
-
1165
- this.collection_main.versionCollection = options.collectionName + '.versions';
1166
- }
1167
- }
1168
- }
1169
-
1170
- export interface MongoManagerCollectionOptions {
1171
- collectionName: string;
1172
- schema: object;
1173
- useVersionCollection: boolean;
1174
- useReportBuilder: boolean;
1175
- reportBuilderLookupTables: LookupTables[]
1176
- timestamps: boolean;
1177
- createLogs: boolean;
1178
- checkSchema: boolean;
1179
- collectionOptions: CreateCollectionOptions;
1180
- skipCache?: boolean;
1181
- bypassSession?: boolean;
1182
- searchFields?: string[];
1183
- }
1184
-
1185
- export class MongoManagerCollection<T extends CollectionDocument> {
1186
- collectionName = '';
1187
- checkSchema = false;
1188
- simplschema = null;
1189
- rbSchema = null;
1190
- timestamps = false;
1191
- useVersions = false;
1192
- versionCollection = '';
1193
- createLogs = true;
1194
- useRB = false;
1195
- collectionOptions: CreateCollectionOptions;
1196
- skipCache = false;
1197
- bypassSession = false;
1198
-
1199
- constructor() {}
1200
-
1201
- static create(options: MongoManagerCollectionOptions) {
1202
- const mongoManagerCollection = new MongoManagerCollection();
1203
- mongoManagerCollection.initialize(options);
1204
- return mongoManagerCollection;
1205
- }
1206
-
1207
- initialize(options: MongoManagerCollectionOptions) {
1208
- this.collectionName = options.collectionName;
1209
- this.simplschema = new SimpleSchema(options.schema);
1210
- this.timestamps = options.timestamps;
1211
- this.createLogs = options.createLogs;
1212
- this.checkSchema = options.checkSchema;
1213
- this.collectionOptions = options.collectionOptions;
1214
- this.skipCache = options.skipCache || false;
1215
- this.bypassSession = options.bypassSession || false;
1216
-
1217
- if (options.useReportBuilder) {
1218
- this.useRB = true;
1219
- let schemaCopy = deepCopy(options.schema);
1220
- let rbSchema = buildRbLookups(options.reportBuilderLookupTables, schemaCopy, []);
1221
- this.rbSchema = buildRbSchema(rbSchema);
1222
- }
1223
-
1224
- const retryDelayMs = 250;
1225
- const registerWhenReady = async () => {
1226
- if (ResolveIOServer && ResolveIOServer.getMainServer() && ResolveIOServer.getMongoManager() && ResolveIOServer.getMongoManager().getServerCollections().length) {
1227
- await ResolveIOServer.getMongoManager().registerCollection(this);
1228
- return;
1229
- }
1230
- setTimeout(registerWhenReady, retryDelayMs);
1231
- };
1232
- setTimeout(registerWhenReady, retryDelayMs);
1233
- }
1234
-
1235
- // Method to extract index name from error message
1236
- extractIndexNameFromError(errorMessage) {
1237
- let regexPattern = /Index already exists with a different name: (\S+)/;
1238
- let matches = errorMessage.match(regexPattern);
1239
-
1240
- if (!matches || matches.length <= 1) {
1241
- // If the first pattern doesn't match, try the second pattern
1242
- regexPattern = /existing index:.*name: "([^"]+)"/;
1243
- matches = errorMessage.match(regexPattern);
1244
- }
1245
-
1246
- return matches && matches.length > 1 ? matches[1] : null;
1247
- }
1248
-
1249
- private shouldRetryWriteConflict(err: any): boolean {
1250
- if (!err) {
1251
- return false;
1252
- }
1253
-
1254
- if (err.code === 112 || err.codeName === 'WriteConflict') {
1255
- return true;
1256
- }
1257
-
1258
- const message = String(err.message || '');
1259
- return /write conflict/i.test(message) || /yielding is disabled/i.test(message);
1260
- }
1261
-
1262
- private shouldRetryWaitQueueTimeout(err: any): boolean {
1263
- if (!err) {
1264
- return false;
1265
- }
1266
-
1267
- if (err.name === 'MongoWaitQueueTimeoutError' || err.codeName === 'MongoWaitQueueTimeoutError') {
1268
- return true;
1269
- }
1270
-
1271
- return typeof err.message === 'string' && err.message.includes('Timed out while checking out a connection from connection pool');
1272
- }
1273
-
1274
- private shouldRetryConnectionError(err: any): boolean {
1275
- if (!err) {
1276
- return false;
1277
- }
1278
-
1279
- const name = String(err.name || err.codeName || '');
1280
- if (
1281
- name === 'MongoPoolClearedError'
1282
- || name === 'MongoNetworkError'
1283
- || name === 'MongoNetworkTimeoutError'
1284
- || name === 'MongoServerSelectionError'
1285
- || name === 'MongoTopologyClosedError'
1286
- || name === 'MongoNotConnectedError'
1287
- || name === 'MongoClientClosedError'
1288
- ) {
1289
- return true;
1290
- }
1291
-
1292
- const message = String(err.message || '');
1293
- return /connection pool .* was cleared/i.test(message)
1294
- || /topology is closed/i.test(message)
1295
- || /client was closed/i.test(message)
1296
- || /not connected/i.test(message)
1297
- || /server selection timed out/i.test(message)
1298
- || /econnrefused|econnreset|etimedout|ehostunreach/i.test(message);
1299
- }
1300
-
1301
- private async delay(ms: number) {
1302
- // eslint-disable-next-line no-restricted-syntax
1303
- return new Promise(resolve => setTimeout(resolve, ms));
1304
- }
1305
-
1306
- private async retryWrite<TResult>(operation: () => Promise<TResult>, options?: { session?: any }): Promise<TResult> {
1307
- if (options && options.session && typeof options.session.inTransaction === 'function' && options.session.inTransaction()) {
1308
- return operation();
1309
- }
1310
-
1311
- let attempt = 0;
1312
- const configuredMaxRetries = Number(process.env.MONGO_WRITE_RETRY_MAX || 8);
1313
- const maxRetries = Number.isFinite(configuredMaxRetries) && configuredMaxRetries >= 0
1314
- ? Math.min(Math.floor(configuredMaxRetries), 20)
1315
- : 8;
1316
- const configuredBaseDelay = Number(process.env.MONGO_WRITE_RETRY_BASE_MS || 120);
1317
- const baseDelayMs = Number.isFinite(configuredBaseDelay) && configuredBaseDelay > 0
1318
- ? Math.min(Math.floor(configuredBaseDelay), 5000)
1319
- : 120;
1320
-
1321
- while (true) {
1322
- try {
1323
- return await operation();
1324
- }
1325
- catch (err) {
1326
- const shouldRetry = this.shouldRetryWriteConflict(err) || this.shouldRetryWaitQueueTimeout(err) || this.shouldRetryConnectionError(err);
1327
- if (!shouldRetry || attempt >= maxRetries) {
1328
- throw err;
1329
- }
1330
- if (this.shouldRetryConnectionError(err)) {
1331
- try {
1332
- await ResolveIOServer.requestMongoReconnect(`mongo-collection-write-retry:${this.collectionName}`, err);
1333
- }
1334
- catch {}
1335
- }
1336
-
1337
- attempt += 1;
1338
- const backoff = Math.min(5000, baseDelayMs * (2 ** (attempt - 1)));
1339
- const jitter = Math.floor(Math.random() * 90);
1340
- await this.delay(backoff + jitter);
1341
- }
1342
- }
1343
- }
1344
-
1345
- private async retryRead<TResult>(operation: () => Promise<TResult>, options?: { session?: any }): Promise<TResult> {
1346
- if (options && options.session && typeof options.session.inTransaction === 'function' && options.session.inTransaction()) {
1347
- return operation();
1348
- }
1349
-
1350
- let attempt = 0;
1351
- const maxRetries = 2;
1352
-
1353
- while (true) {
1354
- try {
1355
- return await operation();
1356
- }
1357
- catch (err) {
1358
- const shouldRetry = this.shouldRetryWaitQueueTimeout(err) || this.shouldRetryConnectionError(err);
1359
- if (!shouldRetry || attempt >= maxRetries) {
1360
- throw err;
1361
- }
1362
- if (this.shouldRetryConnectionError(err)) {
1363
- try {
1364
- await ResolveIOServer.requestMongoReconnect(`mongo-collection-read-retry:${this.collectionName}`, err);
1365
- }
1366
- catch {}
1367
- }
1368
-
1369
- attempt += 1;
1370
- await this.delay(100 * attempt);
1371
- }
1372
- }
1373
- }
1374
-
1375
- async aggregate(pipeline: object[], options?: AggregateOptions, skipCache = false, bypassSession = false) : Promise<any[]> {
1376
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
1377
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
1378
- if (!options) {
1379
- options = {
1380
- session: mongoSession
1381
- };
1382
- }
1383
- else {
1384
- options.session = mongoSession;
1385
- }
1386
- }
1387
-
1388
- if (!skipCache && !this.skipCache) {
1389
- return ResolveIOServer.getMongoManager().aggregate(this.collectionName, pipeline, options || undefined);
1390
- }
1391
- else {
1392
- // eslint-disable-next-line no-unused-vars
1393
- let { session, ...safeOptions } = options || {};
1394
- let monitor = MonitorMongo.create('aggregate', this.collectionName, JSON.stringify([pipeline, safeOptions]));
1395
-
1396
- try {
1397
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options).toArray();
1398
- recordAggregateDependencies(this.collectionName, pipeline, res);
1399
- return res;
1400
- }
1401
- catch (err) {
1402
- console.log(JSON.stringify([new Date(), 'Error Aggregate', this.collectionName, pipeline, safeOptions, {
1403
- code: err.code,
1404
- codeName: err.codeName,
1405
- message: err.message,
1406
- stack: err.stack
1407
- }], null, 2));
1408
-
1409
- err.message = `Error in Aggregate: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
1410
- throw err;
1411
- }
1412
- finally {
1413
- await monitor.finish();
1414
- }
1415
- }
1416
- }
1417
-
1418
- async aggregateCount(pipeline: object[], options?: AggregateOptions, bypassSession = false) : Promise<number> {
1419
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
1420
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
1421
- if (!options) {
1422
- options = {
1423
- session: mongoSession
1424
- };
1425
- }
1426
- else {
1427
- options.session = mongoSession;
1428
- }
1429
- }
1430
-
1431
- // eslint-disable-next-line no-unused-vars
1432
- let { session, ...safeOptions } = options || {};
1433
- let monitor = MonitorMongo.create('aggregateCount', this.collectionName, JSON.stringify([pipeline, safeOptions]));
1434
-
1435
- try {
1436
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options).toArray();
1437
- recordAggregateDependencies(this.collectionName, pipeline, res);
1438
- return res.length;
1439
- }
1440
- catch (err) {
1441
- console.log(JSON.stringify([new Date(), 'Error Aggregate Count', this.collectionName, pipeline, safeOptions, {
1442
- code: err.code,
1443
- codeName: err.codeName,
1444
- message: err.message,
1445
- stack: err.stack
1446
- }], null, 2));
1447
-
1448
- err.message = `Error in Aggregate Count: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
1449
- throw err;
1450
- }
1451
- finally {
1452
- await monitor.finish();
1453
- }
1454
- }
1455
-
1456
- aggregateCursor(pipeline: object[], options?: AggregateOptions, bypassSession = false): AggregationCursor {
1457
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
1458
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
1459
- if (!options) {
1460
- options = {
1461
- session: mongoSession
1462
- };
1463
- }
1464
- else {
1465
- options.session = mongoSession;
1466
- }
1467
- }
1468
-
1469
- // eslint-disable-next-line no-unused-vars
1470
- let { session, ...safeOptions } = options || {};
1471
- let monitor = MonitorMongo.create('aggregateCursor', this.collectionName, JSON.stringify([pipeline, safeOptions]));
1472
- let cursor = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options || undefined);
1473
- cursor.on('close', async ev => {
1474
- await monitor.finish();
1475
- return ev;
1476
- });
1477
-
1478
- return cursor;
1479
- }
1480
-
1481
- aggregateStream(pipeline: object[], options?: AggregateOptions, streamOptions?: any, bypassSession = false) {
1482
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
1483
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
1484
- if (!options) {
1485
- options = {
1486
- session: mongoSession
1487
- };
1488
- }
1489
- else {
1490
- options.session = mongoSession;
1491
- }
1492
- }
1493
-
1494
- // eslint-disable-next-line no-unused-vars
1495
- let { session, ...safeOptions } = options || {};
1496
- let monitor = MonitorMongo.create('aggregateStream', this.collectionName, JSON.stringify([pipeline, safeOptions, streamOptions]));
1497
- let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).aggregate(pipeline, options).stream().on('close', async ev => {
1498
- await monitor.finish();
1499
- return ev;
1500
- });
1501
-
1502
- return stream;
1503
- }
1504
-
1505
- async bulkWrite(
1506
- operations: any[],
1507
- options?: BulkWriteOptions,
1508
- bypassCheckSchema = false,
1509
- bypassLogs = false,
1510
- bypassVersions = false,
1511
- bypassSession = false
1512
- ): Promise<BulkWriteResult> {
1513
- if (!operations.length) {
1514
- return null;
1515
- }
1516
-
1517
- const BATCH_SIZE = 1000;
1518
- let opIndex = 0;
1519
-
1520
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
1521
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
1522
- if (!options) {
1523
- options = {session: mongoSession};
1524
- }
1525
- else {
1526
- options.session = mongoSession;
1527
- }
1528
- }
1529
-
1530
- let { session, ...safeOptions } = options || {};
1531
-
1532
- while (opIndex < operations.length) {
1533
- const batchOps = operations.slice(opIndex, opIndex + BATCH_SIZE);
1534
-
1535
- // Initialize arrays for logs and version operations
1536
- const logs = [];
1537
- const versionOps = [];
1538
-
1539
- for (const op of batchOps) {
1540
- const opType = Object.keys(op)[0];
1541
- const doc = op[opType];
1542
-
1543
- // Skip validation if bypassCheckSchema is true
1544
- if (this.checkSchema && !bypassCheckSchema) {
1545
- const validationContext = this.simplschema.newContext();
1546
- let isValid: boolean;
1547
-
1548
- if (opType === 'insertOne') {
1549
- isValid = validationContext.validate(doc.document);
1550
- }
1551
- else if (opType === 'replaceOne') {
1552
- isValid = validationContext.validate(doc.replacement);
1553
- }
1554
- else if (opType === 'updateOne' || opType === 'updateMany') {
1555
- // For updates, validate the update modifier
1556
- isValid = validationContext.validate(doc.update, { modifier: true });
1557
- }
1558
- else if (opType === 'deleteOne' || opType === 'deleteMany') {
1559
- // No validation needed for deletes
1560
- isValid = true;
1561
- }
1562
- else {
1563
- throw new Error(`Unsupported operation type: ${opType}`);
1564
- }
1565
-
1566
- if (!isValid) {
1567
- throw new Error(
1568
- `Schema validation failed for ${opType}: ${JSON.stringify(validationContext.validationErrors(), null, 2)}`
1569
- );
1570
- }
1571
- }
1572
-
1573
- // Now proceed to process the operations
1574
-
1575
- if (opType === 'insertOne') {
1576
- // If this.timestamps is true, set createdAt and updatedAt
1577
- if (this.timestamps) {
1578
- if (!doc.document.createdAt) {
1579
- doc.document.createdAt = new Date();
1580
- }
1581
-
1582
- if (!doc.document.updatedAt) {
1583
- doc.document.updatedAt = new Date();
1584
- }
1585
- }
1586
-
1587
- // Prepare log entry
1588
- if (!bypassLogs && this.createLogs) {
1589
- logs.push({
1590
- _id: objectIdHexString(),
1591
- type: 'document',
1592
- collection: this.collectionName,
1593
- id_document: doc.document._id || objectIdHexString(),
1594
- payload:
1595
- getBinarySize(JSON.stringify(doc.document)) < 1000000
1596
- ? JSON.stringify(doc.document, null, 2)
1597
- : 'Too Big',
1598
- method: 'insertOne',
1599
- id_user: '', // Add user info if available
1600
- user: '',
1601
- messageId: 0,
1602
- route: '',
1603
- createdAt: new Date(),
1604
- });
1605
- }
1606
-
1607
- // Since we might have modified doc.document, update the operation
1608
- op[opType].document = doc.document;
1609
- }
1610
- else if (opType === 'updateOne' || opType === 'updateMany') {
1611
- // If this.timestamps is true, add updatedAt
1612
- if (this.timestamps) {
1613
- if (!doc.update.$set) {
1614
- doc.update.$set = {};
1615
- }
1616
- doc.update.$set.updatedAt = new Date();
1617
- }
1618
-
1619
- // If this.useVersions is true, increment __v
1620
- if (!bypassVersions && this.useVersions) {
1621
- if (!doc.update.$inc) {
1622
- doc.update.$inc = {};
1623
- }
1624
- doc.update.$inc.__v = 1;
1625
- }
1626
-
1627
- // Prepare log entry
1628
- if (!bypassLogs && this.createLogs) {
1629
- logs.push({
1630
- _id: objectIdHexString(),
1631
- type: 'document',
1632
- collection: this.collectionName,
1633
- id_document: doc.filter._id || null,
1634
- payload:
1635
- getBinarySize(JSON.stringify(doc.update)) < 1000000
1636
- ? JSON.stringify(doc.update, null, 2)
1637
- : 'Too Big',
1638
- method: opType,
1639
- id_user: '', // Add user info if available
1640
- user: '',
1641
- messageId: 0,
1642
- route: '',
1643
- instance_index: process.env.NODE_APP_INSTANCE || '0',
1644
- createdAt: new Date()
1645
- });
1646
- }
1647
-
1648
- // For versioning, store the filter to fetch the document later
1649
- if (!bypassVersions && this.useVersions) {
1650
- versionOps.push({
1651
- filter: doc.filter,
1652
- });
1653
- }
1654
-
1655
- // No need to modify the operation further
1656
- }
1657
- else if (opType === 'replaceOne') {
1658
- // If this.timestamps is true, set updatedAt
1659
- if (this.timestamps) {
1660
- doc.replacement.updatedAt = new Date();
1661
- }
1662
-
1663
- // If this.useVersions is true, increment __v
1664
- if (!bypassVersions && this.useVersions) {
1665
- doc.replacement.__v = (doc.replacement.__v || 0) + 1;
1666
- }
1667
-
1668
- // Prepare log entry
1669
- if (!bypassLogs && this.createLogs) {
1670
- logs.push({
1671
- _id: objectIdHexString(),
1672
- type: 'document',
1673
- collection: this.collectionName,
1674
- id_document: doc.filter._id || null,
1675
- payload:
1676
- getBinarySize(JSON.stringify(doc.replacement)) < 1000000
1677
- ? JSON.stringify(doc.replacement, null, 2)
1678
- : 'Too Big',
1679
- method: 'replaceOne',
1680
- id_user: '', // Add user info if available
1681
- user: '',
1682
- messageId: 0,
1683
- route: '',
1684
- createdAt: new Date(),
1685
- });
1686
- }
1687
-
1688
- // For versioning, store the filter to fetch the document later
1689
- if (!bypassVersions && this.useVersions) {
1690
- versionOps.push({
1691
- filter: doc.filter,
1692
- });
1693
- }
1694
-
1695
- // Since we might have modified doc.replacement, update the operation
1696
- op[opType].replacement = doc.replacement;
1697
- }
1698
- else if (opType === 'deleteOne' || opType === 'deleteMany') {
1699
- // Prepare log entry
1700
- if (!bypassLogs && this.createLogs) {
1701
- logs.push({
1702
- _id: objectIdHexString(),
1703
- type: 'document',
1704
- collection: this.collectionName,
1705
- id_document: doc.filter._id || null,
1706
- payload:
1707
- getBinarySize(JSON.stringify(doc.filter)) < 1000000
1708
- ? JSON.stringify(doc.filter, null, 2)
1709
- : 'Too Big',
1710
- method: opType,
1711
- id_user: '', // Add user info if available
1712
- user: '',
1713
- messageId: 0,
1714
- route: '',
1715
- createdAt: new Date(),
1716
- });
1717
- }
1718
-
1719
- // For versioning, store the filter to fetch the document later
1720
- if (!bypassVersions && this.useVersions) {
1721
- versionOps.push({
1722
- filter: doc.filter,
1723
- });
1724
- }
1725
-
1726
- // No need to modify the operation
1727
- }
1728
- else {
1729
- throw new Error(`Unsupported operation type: ${opType}`);
1730
- }
1731
- }
1732
-
1733
- let affectedDocs = [];
1734
-
1735
- // Handle versioning
1736
- if (!bypassVersions && this.useVersions && versionOps.length > 0) {
1737
- try {
1738
- // Fetch the affected documents
1739
- const versionFilters = versionOps.map((v) => v.filter);
1740
-
1741
- if (versionFilters.length) {
1742
- affectedDocs = await ResolveIOServer.getMainDB().collection(this.collectionName).find({ $or: versionFilters }, {session}).toArray();
1743
- }
1744
-
1745
- // Prepare version documents
1746
- const versionInserts = affectedDocs.map((doc) => ({
1747
- insertOne: {
1748
- document: {
1749
- ...doc,
1750
- _id: { _id: doc._id, __v: doc.__v },
1751
- },
1752
- },
1753
- }));
1754
-
1755
- // Insert versions in bulk
1756
- if (versionInserts.length > 0) {
1757
- try {
1758
- await ResolveIOServer.getMainDB().collection(this.versionCollection).bulkWrite(<any>versionInserts);
1759
- }
1760
- catch {}
1761
- }
1762
- }
1763
- catch {}
1764
- }
1765
-
1766
- // Execute bulkWrite
1767
- const monitor = MonitorMongo.create('bulkWrite', this.collectionName, JSON.stringify([batchOps, safeOptions]));
1768
-
1769
- try {
1770
- await this.retryWrite(
1771
- () => ResolveIOServer.getMainDB().collection(this.collectionName).bulkWrite(batchOps, options || undefined),
1772
- options
1773
- );
1774
- }
1775
- catch (err) {
1776
- console.log(JSON.stringify([new Date(), 'Error Bulk Write', this.collectionName, operations, safeOptions, {
1777
- code: err.code,
1778
- codeName: err.codeName,
1779
- message: err.message,
1780
- stack: err.stack
1781
- }], null, 2));
1782
-
1783
- err.message = `Error in Bulk Write: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
1784
- throw err;
1785
- }
1786
- finally {
1787
- await monitor.finish();
1788
- }
1789
-
1790
- // Insert logs in bulk
1791
- if (!bypassLogs && this.createLogs && logs.length > 0) {
1792
- if (
1793
- ResolveIOServer.shouldWriteLogsOffline()
1794
- ) {
1795
- ResolveIOServer.getLocalLogManager().writeLogs(logs.map(a => {
1796
- return {
1797
- type: 'log',
1798
- data: a
1799
- };
1800
- }));
1801
- }
1802
- else {
1803
- let bwOptions = null;
1804
- bwOptions = {session, ordered: false};
1805
-
1806
- await ResolveIOServer.getMainDB().collection('logs').bulkWrite(logs.map(a => {
1807
- a.client = 'ResolveIO';
1808
- a.instance = ResolveIOServer.getInstanceHost();
1809
-
1810
- return {
1811
- insertOne: {
1812
- document: a
1813
- }
1814
- };
1815
- }), bwOptions);
1816
- }
1817
- }
1818
-
1819
- if (!bypassVersions && this.useVersions) {
1820
- try {
1821
- // Delete old versions beyond the latest 5
1822
- const affectedDocIds = affectedDocs.map((doc) => doc._id);
1823
-
1824
- const pipeline = [
1825
- {
1826
- $match: { '_id._id': { $in: affectedDocIds } },
1827
- },
1828
- {
1829
- $sort: { '_id._id': 1, '_id.__v': -1 },
1830
- },
1831
- {
1832
- $group: {
1833
- _id: '$_id._id',
1834
- versions: { $push: '$_id' },
1835
- },
1836
- },
1837
- {
1838
- $project: {
1839
- versionsToDelete: { $slice: ['$versions', 5, { $size: '$versions' }] },
1840
- },
1841
- },
1842
- { $unwind: '$versionsToDelete' },
1843
- {
1844
- $replaceRoot: { newRoot: { _id: '$versionsToDelete' } },
1845
- },
1846
- ];
1847
-
1848
- const oldVersions = await ResolveIOServer.getMainDB().collection(this.versionCollection).aggregate(pipeline).toArray();
1849
-
1850
- if (oldVersions.length > 0) {
1851
- await ResolveIOServer.getMainDB().collection(this.versionCollection).deleteMany({ _id: { $in: oldVersions.map((v) => v._id) } });
1852
- }
1853
- }
1854
- catch {}
1855
- }
1856
-
1857
- opIndex += BATCH_SIZE;
1858
-
1859
- // Yield to the event loop
1860
- // eslint-disable-next-line no-restricted-syntax
1861
- await new Promise((resolve) => setImmediate(resolve));
1862
-
1863
- // Invalidate cache
1864
- if (!this.skipCache) {
1865
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
1866
- }
1867
- }
1868
-
1869
- return { ok: 1 } as BulkWriteResult; // Adjust return value as per your requirements
1870
- }
1871
-
1872
- async countDocuments(
1873
- filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {},
1874
- options?: CountDocumentsOptions,
1875
- skipCache = false
1876
- ): Promise<number> {
1877
-
1878
- // ********* COUNTS ARE NOT SUPPORTED IN MONGO SESSIONS! ***************
1879
-
1880
- // eslint-disable-next-line no-unused-vars
1881
- let { session, ...safeOptions } = options || {};
1882
-
1883
- // Check if the filter is empty
1884
- const isUnfiltered = Object.keys(filter).length === 0;
1885
-
1886
- if (isUnfiltered) {
1887
- // Use collection stats for an unfiltered count
1888
- return ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).estimatedDocumentCount(safeOptions);
1889
- }
1890
- else if (!skipCache && !this.skipCache) {
1891
- // Use cached count if skipCache is false
1892
- return ResolveIOServer.getMongoManager().countDocuments(this.collectionName, filter, safeOptions);
1893
- }
1894
- else {
1895
- // Fallback to direct countDocuments call with monitoring if skipCache is true
1896
-
1897
- let monitor = MonitorMongo.create('countDocuments', this.collectionName, JSON.stringify([filter, safeOptions]));
1898
-
1899
- try {
1900
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).countDocuments(<any>filter, safeOptions);
1901
- return res;
1902
- }
1903
- catch (err) {
1904
- console.log(JSON.stringify([new Date(), 'Error Count Documents', this.collectionName, filter, safeOptions, {
1905
- code: err.code,
1906
- codeName: err.codeName,
1907
- message: err.message,
1908
- stack: err.stack
1909
- }], null, 2));
1910
-
1911
- err.message = `Error in Count Documents: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
1912
- throw err;
1913
- }
1914
- finally {
1915
- await monitor.finish();
1916
- }
1917
- }
1918
- }
1919
-
1920
- //Helper Function (1 or Many) - Not Real Mongo Function
1921
- create(f_docs: T | T[], options?: InsertOneOptions | BulkWriteOptions): Promise<T | T[]> {
1922
- if (!Array.isArray(f_docs)) {
1923
- return this.insertOne(f_docs, <InsertOneOptions>options);
1924
- }
1925
- else if (f_docs.length === 1) {
1926
- return this.insertOne(f_docs[0], <InsertOneOptions>options);
1927
- }
1928
-
1929
- return this.insertMany(f_docs, <BulkWriteOptions>options);
1930
- }
1931
-
1932
- async createIndex(fieldOrSpec: any, options?: CreateIndexesOptions): Promise<string> {
1933
- // Check if index already exists based on the key
1934
-
1935
- try {
1936
- const dbCollection = ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions);
1937
- const existingIndexes = await dbCollection.indexes();
1938
-
1939
- // Check if an index with the same key already exists
1940
- const indexExists = existingIndexes.some(index =>
1941
- JSON.stringify(index.key) === JSON.stringify(fieldOrSpec)
1942
- );
1943
-
1944
- if (indexExists) {
1945
- return 'Index already exists'; // Skip creation if index exists
1946
- }
1947
-
1948
- return await dbCollection.createIndex(fieldOrSpec, options || undefined);
1949
- }
1950
- catch {}
1951
-
1952
- return 'Index creation queued';
1953
- }
1954
-
1955
- async createIndexes(indexSpecs: IndexDescription[], options?: CreateIndexesOptions): Promise<string[]> {
1956
- try {
1957
- const dbCollection = ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions);
1958
- const existingIndexes = await dbCollection.indexes();
1959
-
1960
- // Filter out indexes that already exist based on the key
1961
- const indexesToCreate = indexSpecs.filter(indexSpec =>
1962
- !existingIndexes.some(existingIndex =>
1963
- JSON.stringify(existingIndex.key) === JSON.stringify(indexSpec.key)
1964
- )
1965
- );
1966
-
1967
- // If no new indexes to create, resolve early
1968
- if (indexesToCreate.length === 0) {
1969
- return ['All indexes already exist'];
1970
- }
1971
-
1972
- return await dbCollection.createIndexes(indexesToCreate, options || undefined);
1973
- }
1974
- catch {}
1975
-
1976
- return ['Index creation queued'];
1977
- }
1978
-
1979
- async deleteMany(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: DeleteOptions, bypassLogs = false, bypassSession = false): Promise<DeleteResult> {
1980
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
1981
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
1982
- if (!options) {
1983
- options = {session: mongoSession};
1984
- }
1985
- else {
1986
- options.session = mongoSession;
1987
- }
1988
- }
1989
-
1990
- let { session, ...safeOptions } = options || {};
1991
-
1992
- if ((this.createLogs && !bypassLogs) || this.useVersions) {
1993
- let docs = await this.find(filter, {session});
1994
-
1995
- for (let i = 0; i < docs.length; i++) {
1996
- let doc = docs[i];
1997
-
1998
- if (this.createLogs && !bypassLogs) {
1999
- if (
2000
- ResolveIOServer.shouldWriteLogsOffline()
2001
- ) {
2002
- ResolveIOServer.getLocalLogManager().writeLog({
2003
- type: 'log',
2004
- data: {
2005
- _id: objectIdHexString(),
2006
- type: 'document',
2007
- collection: this.collectionName,
2008
- id_document: doc._id,
2009
- payload: getBinarySize(JSON.stringify([doc, filter, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, safeOptions], null, 2) : 'Too Big',
2010
- method: 'deleteMany',
2011
- id_user: '',
2012
- user: '',
2013
- messageId: 0,
2014
- route: '',
2015
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2016
- createdAt: new Date()
2017
- }
2018
- });
2019
- }
2020
- else {
2021
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
2022
- _id: objectIdHexString(),
2023
- type: 'document',
2024
- collection: this.collectionName,
2025
- id_document: doc._id,
2026
- payload: getBinarySize(JSON.stringify([doc, filter, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, safeOptions], null, 2) : 'Too Big',
2027
- method: 'deleteMany',
2028
- id_user: '',
2029
- user: '',
2030
- messageId: 0,
2031
- route: '',
2032
- client: 'ResolveIO',
2033
- instance: ResolveIOServer.getInstanceHost(),
2034
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2035
- createdAt: new Date()
2036
- }, {session});
2037
- }
2038
- }
2039
-
2040
- if (this.useVersions) {
2041
- try {
2042
- let versionDoc = deepCopy(doc);
2043
- versionDoc._id = {_id: doc._id, __v: doc.__v};
2044
-
2045
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
2046
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 1}}]});
2047
- }
2048
- catch {}
2049
- }
2050
- }
2051
- }
2052
-
2053
- let monitor = MonitorMongo.create('deleteMany', this.collectionName, JSON.stringify([filter, safeOptions]));
2054
-
2055
- try {
2056
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).deleteMany(<any>filter, options || undefined);
2057
- if (!this.skipCache) {
2058
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2059
- }
2060
-
2061
- return res;
2062
- }
2063
- catch (err) {
2064
- console.log(JSON.stringify([new Date(), 'Error Delete Many', this.collectionName, filter, safeOptions, {
2065
- code: err.code,
2066
- codeName: err.codeName,
2067
- message: err.message,
2068
- stack: err.stack
2069
- }], null, 2));
2070
-
2071
- err.message = `Error in Delete Many: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2072
- throw err;
2073
- }
2074
- finally {
2075
- await monitor.finish();
2076
- }
2077
- }
2078
-
2079
- async deleteOne(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOneAndDeleteOptions, bypassLogs = false, bypassSession = false): Promise<DeleteResult> {
2080
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2081
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2082
- if (!options) {
2083
- options = {session: mongoSession};
2084
- }
2085
- else {
2086
- options.session = mongoSession;
2087
- }
2088
- }
2089
-
2090
- let { session, ...safeOptions } = options || {};
2091
-
2092
- if (this.createLogs && !bypassLogs) {
2093
- let monitor = MonitorMongo.create('findOneAndDelete', this.collectionName, JSON.stringify([filter, safeOptions]));
2094
-
2095
- try {
2096
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).deleteOne(<any>filter, options || undefined);
2097
- let doc = await this.findOne(filter, options || undefined);
2098
-
2099
- if (doc) {
2100
- if (this.createLogs && !bypassLogs) {
2101
- if (
2102
- ResolveIOServer.shouldWriteLogsOffline()
2103
- ) {
2104
- ResolveIOServer.getLocalLogManager().writeLog({
2105
- type: 'log',
2106
- data: {
2107
- _id: objectIdHexString(),
2108
- type: 'document',
2109
- collection: this.collectionName,
2110
- id_document: doc._id as string,
2111
- payload: getBinarySize(JSON.stringify([doc, filter, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, safeOptions], null, 2) : 'Too Big',
2112
- method: 'deleteOne',
2113
- id_user: '',
2114
- user: '',
2115
- messageId: 0,
2116
- route: '',
2117
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2118
- createdAt: new Date()
2119
- }
2120
- });
2121
- }
2122
- else {
2123
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
2124
- _id: objectIdHexString(),
2125
- type: 'document',
2126
- collection: this.collectionName,
2127
- id_document: doc._id as string,
2128
- payload: getBinarySize(JSON.stringify([doc, filter, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, safeOptions], null, 2) : 'Too Big',
2129
- method: 'deleteOne',
2130
- id_user: '',
2131
- user: '',
2132
- messageId: 0,
2133
- route: '',
2134
- client: 'ResolveIO',
2135
- instance: ResolveIOServer.getInstanceHost(),
2136
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2137
- createdAt: new Date()
2138
- }, {session});
2139
- }
2140
- }
2141
-
2142
- if (this.useVersions) {
2143
- try {
2144
- let versionDoc = deepCopy(doc);
2145
- versionDoc._id = {_id: doc._id, __v: doc.__v};
2146
-
2147
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
2148
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 1}}]});
2149
- }
2150
- catch {}
2151
- }
2152
-
2153
- if (!this.skipCache) {
2154
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2155
- }
2156
- }
2157
-
2158
- return res;
2159
- }
2160
- catch (err) {
2161
- console.log(JSON.stringify([new Date(), 'Error Delete One (Find One And Delete)', this.collectionName, filter, safeOptions, {
2162
- code: err.code,
2163
- codeName: err.codeName,
2164
- message: err.message,
2165
- stack: err.stack
2166
- }], null, 2));
2167
-
2168
- err.message = `Error in Delete One (Find One And Delete): ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2169
- throw err;
2170
- }
2171
- finally {
2172
- await monitor.finish();
2173
- }
2174
- }
2175
- else {
2176
- let monitor = MonitorMongo.create('deleteOne', this.collectionName, JSON.stringify([filter, safeOptions]));
2177
-
2178
- try {
2179
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).deleteOne(<any>filter, options || undefined);
2180
- if (!this.skipCache) {
2181
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2182
- }
2183
- return res;
2184
- }
2185
- catch (err) {
2186
- console.log(JSON.stringify([new Date(), 'Error Delete One', this.collectionName, filter, safeOptions, {
2187
- code: err.code,
2188
- codeName: err.codeName,
2189
- message: err.message,
2190
- stack: err.stack
2191
- }], null, 2));
2192
-
2193
- err.message = `Error in Delete One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2194
- throw err;
2195
- }
2196
- finally {
2197
- await monitor.finish();
2198
- }
2199
- }
2200
- }
2201
-
2202
- async distinct(key: string, filter?: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, options?: CommandOperationOptions, bypassSession = false): Promise<T[]> {
2203
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2204
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2205
- if (!options) {
2206
- options = {
2207
- session: mongoSession
2208
- };
2209
- }
2210
- else {
2211
- options.session = mongoSession;
2212
- }
2213
- }
2214
-
2215
- // eslint-disable-next-line no-unused-vars
2216
- let { session, ...safeOptions } = options || {};
2217
-
2218
- let monitor = MonitorMongo.create('distinct', this.collectionName, JSON.stringify([key, filter, safeOptions]));
2219
-
2220
- try {
2221
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).distinct(key, <any>filter, options || undefined);
2222
- return res;
2223
- }
2224
- catch (err) {
2225
- console.log(JSON.stringify([new Date(), 'Error Distinct', this.collectionName, filter, safeOptions, {
2226
- code: err.code,
2227
- codeName: err.codeName,
2228
- message: err.message,
2229
- stack: err.stack
2230
- }], null, 2));
2231
-
2232
- err.message = `Error in Distinct: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2233
- throw err;
2234
- }
2235
- finally {
2236
- await monitor.finish();
2237
- }
2238
- }
2239
-
2240
- async drop(options?: CommandOperationOptions, bypassSession = false): Promise<boolean> {
2241
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2242
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2243
- if (!options) {
2244
- options = {
2245
- session: mongoSession
2246
- };
2247
- }
2248
- else {
2249
- options.session = mongoSession;
2250
- }
2251
- }
2252
-
2253
- // eslint-disable-next-line no-unused-vars
2254
- let { session, ...safeOptions } = options || {};
2255
-
2256
- let monitor = MonitorMongo.create('drop', this.collectionName, JSON.stringify([safeOptions]));
2257
-
2258
- try {
2259
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).drop(options);
2260
- return res;
2261
- }
2262
- catch (err) {
2263
- console.log(JSON.stringify([new Date(), 'Error Drop Collection', this.collectionName, safeOptions, {
2264
- code: err.code,
2265
- codeName: err.codeName,
2266
- message: err.message,
2267
- stack: err.stack
2268
- }], null, 2));
2269
-
2270
- err.message = `Error in Drop Collection: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2271
- throw err;
2272
- }
2273
- finally {
2274
- await monitor.finish();
2275
- }
2276
- }
2277
-
2278
- async dropIndex(indexName: string, options?: CommandOperationOptions, bypassSession = false): Promise<Document> {
2279
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2280
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2281
- if (!options) {
2282
- options = {
2283
- session: mongoSession
2284
- };
2285
- }
2286
- else {
2287
- options.session = mongoSession;
2288
- }
2289
- }
2290
-
2291
- // eslint-disable-next-line no-unused-vars
2292
- let { session, ...safeOptions } = options || {};
2293
-
2294
- let monitor = MonitorMongo.create('dropIndex', this.collectionName, JSON.stringify([indexName, safeOptions]));
2295
-
2296
- try {
2297
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).dropIndex(indexName, options || undefined);
2298
- return <Document>res;
2299
- }
2300
- catch (err) {
2301
- console.log(JSON.stringify([new Date(), 'Error Drop Index', this.collectionName, indexName, safeOptions, {
2302
- code: err.code,
2303
- codeName: err.codeName,
2304
- message: err.message,
2305
- stack: err.stack
2306
- }], null, 2));
2307
-
2308
- err.message = `Error in Drop Index: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2309
- throw err;
2310
- }
2311
- finally {
2312
- await monitor.finish();
2313
- }
2314
- }
2315
-
2316
- async dropIndexes(options?: CommandOperationOptions, bypassSession = false): Promise<boolean> {
2317
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2318
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2319
- if (!options) {
2320
- options = {
2321
- session: mongoSession
2322
- };
2323
- }
2324
- else {
2325
- options.session = mongoSession;
2326
- }
2327
- }
2328
-
2329
- // eslint-disable-next-line no-unused-vars
2330
- let { session, ...safeOptions } = options || {};
2331
-
2332
- let monitor = MonitorMongo.create('dropIndexes', this.collectionName, JSON.stringify([safeOptions]));
2333
-
2334
- try {
2335
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).dropIndexes(options);
2336
- return res;
2337
- }
2338
- catch (err) {
2339
- console.log(JSON.stringify([new Date(), 'Error Drop Indexes', this.collectionName, safeOptions, {
2340
- code: err.code,
2341
- codeName: err.codeName,
2342
- message: err.message,
2343
- stack: err.stack
2344
- }], null, 2));
2345
-
2346
- err.message = `Error in Drop Indexes: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2347
- throw err;
2348
- }
2349
- finally {
2350
- await monitor.finish();
2351
- }
2352
- }
2353
-
2354
- async find(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: MongoManagerFindOptions, skipCache = false, bypassSession = false): Promise<T[]> {
2355
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2356
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2357
- if (!options) {
2358
- options = {
2359
- session: mongoSession
2360
- };
2361
- }
2362
- else {
2363
- options.session = mongoSession;
2364
- }
2365
- }
2366
-
2367
- // eslint-disable-next-line no-unused-vars
2368
- let { session, ...safeOptions } = options || {};
2369
-
2370
- if (!skipCache && !this.skipCache) {
2371
- return ResolveIOServer.getMongoManager().find(this.collectionName, filter, options || undefined);
2372
- }
2373
- else {
2374
- let monitor = MonitorMongo.create('find', this.collectionName, JSON.stringify([filter, safeOptions]));
2375
-
2376
- try {
2377
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find<T>(<any>filter, options).toArray();
2378
- recordDependencyResult(this.collectionName, res, { filter, meta: buildQueryMetaFromFindOptions(safeOptions) });
2379
- return res;
2380
- }
2381
- catch (err) {
2382
- console.log(JSON.stringify([new Date(), 'Error Find', this.collectionName, filter, safeOptions, {
2383
- code: err.code,
2384
- codeName: err.codeName,
2385
- message: err.message,
2386
- stack: err.stack
2387
- }], null, 2));
2388
-
2389
- err.message = `Error in Find: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2390
- throw err;
2391
- }
2392
- finally {
2393
- await monitor.finish();
2394
- }
2395
- }
2396
- }
2397
-
2398
- async findById(id: string, options?: MongoManagerFindOptions, skipCache = false, bypassSession = false): Promise<T> {
2399
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2400
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2401
- if (!options) {
2402
- options = {
2403
- session: mongoSession
2404
- };
2405
- }
2406
- else {
2407
- options.session = mongoSession;
2408
- }
2409
- }
2410
-
2411
- // eslint-disable-next-line no-unused-vars
2412
- let { session, ...safeOptions } = options || {};
2413
-
2414
- if (!skipCache && !this.skipCache) {
2415
- return ResolveIOServer.getMongoManager().findOne<T>(this.collectionName, {_id: id}, options || undefined);
2416
- }
2417
- else {
2418
- let monitor = MonitorMongo.create('findById', this.collectionName, JSON.stringify([{_id: id}, safeOptions]));
2419
-
2420
- try {
2421
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOne<T>(<any>{_id: id}, options || undefined);
2422
- recordDependencyResult(this.collectionName, res, { filter: { _id: id }, meta: buildQueryMetaFromFindOptions(safeOptions) });
2423
- return res;
2424
- }
2425
- catch (err) {
2426
- console.log(JSON.stringify([new Date(), 'Error Find By ID', this.collectionName, id, safeOptions, {
2427
- code: err.code,
2428
- codeName: err.codeName,
2429
- message: err.message,
2430
- stack: err.stack
2431
- }], null, 2));
2432
-
2433
- err.message = `Error in Find By ID: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2434
- throw err;
2435
- }
2436
- finally {
2437
- await monitor.finish();
2438
- }
2439
- }
2440
- }
2441
-
2442
- async findCount(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: MongoManagerFindOptions, bypassSession = false): Promise<Number> {
2443
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2444
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2445
- if (!options) {
2446
- options = {
2447
- session: mongoSession
2448
- };
2449
- }
2450
- else {
2451
- options.session = mongoSession;
2452
- }
2453
- }
2454
-
2455
- // eslint-disable-next-line no-unused-vars
2456
- let { session, ...safeOptions } = options || {};
2457
-
2458
- let monitor = MonitorMongo.create('findCount', this.collectionName, JSON.stringify([filter, safeOptions]));
2459
-
2460
- try {
2461
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find(<any>filter, options).count();
2462
- recordDependencyResult(this.collectionName, res, { filter });
2463
- return res;
2464
- }
2465
- catch (err) {
2466
- console.log(JSON.stringify([new Date(), 'Error Find Count', this.collectionName, filter, safeOptions, {
2467
- code: err.code,
2468
- codeName: err.codeName,
2469
- message: err.message,
2470
- stack: err.stack
2471
- }], null, 2));
2472
-
2473
- err.message = `Error in Find Count: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2474
- throw err;
2475
- }
2476
- finally {
2477
- await monitor.finish();
2478
- }
2479
- }
2480
-
2481
- findCursor(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: MongoManagerFindOptions, bypassSession = false): FindCursor {
2482
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2483
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2484
- if (!options) {
2485
- options = {session: mongoSession};
2486
- }
2487
- else {
2488
- options.session = mongoSession;
2489
- }
2490
- }
2491
-
2492
- // eslint-disable-next-line no-unused-vars
2493
- let { session, ...safeOptions } = options || {};
2494
-
2495
- let monitor = MonitorMongo.create('findCursor', this.collectionName, JSON.stringify([filter, safeOptions]));
2496
- let cursor = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find(<any>filter, options || undefined);
2497
- cursor.on('close', async ev => {
2498
- await monitor.finish();
2499
- cursor.removeAllListeners();
2500
- return ev;
2501
- });
2502
-
2503
- return cursor;
2504
- }
2505
-
2506
- findStream(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: MongoManagerFindOptions, streamOptions?: any, bypassSession = false) {
2507
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2508
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2509
- if (!options) {
2510
- options = {session: mongoSession};
2511
- }
2512
- else {
2513
- options.session = mongoSession;
2514
- }
2515
- }
2516
-
2517
- // eslint-disable-next-line no-unused-vars
2518
- let { session, ...safeOptions } = options || {};
2519
-
2520
- let monitor = MonitorMongo.create('findStream', this.collectionName, JSON.stringify([filter, safeOptions, streamOptions]));
2521
- let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).find(<any>filter, options).stream().on('close', async ev => {
2522
- await monitor.finish();
2523
- return ev;
2524
- });
2525
-
2526
- return stream;
2527
- }
2528
-
2529
- async findOne(filter: MongoManagerFilter<T> | MongoManagerFilterOperators<T> = {}, options?: MongoManagerFindOptions, skipCache = false, bypassSession = false): Promise<T> {
2530
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2531
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2532
- if (!options) {
2533
- options = {
2534
- session: mongoSession
2535
- };
2536
- }
2537
- else {
2538
- options.session = mongoSession;
2539
- }
2540
- }
2541
-
2542
- if (!skipCache && !this.skipCache) {
2543
- return ResolveIOServer.getMongoManager().findOne(this.collectionName, filter, options || undefined);
2544
- }
2545
- else {
2546
- // eslint-disable-next-line no-unused-vars
2547
- let { session, ...safeOptions } = options || {};
2548
-
2549
- let monitor = MonitorMongo.create('findOne', this.collectionName, JSON.stringify([filter, safeOptions]));
2550
-
2551
- try {
2552
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOne<T>(<any>filter, options || undefined);
2553
- recordDependencyResult(this.collectionName, res, { filter });
2554
- return res;
2555
- }
2556
- catch (err) {
2557
- console.log(JSON.stringify([new Date(), 'Error Find One', this.collectionName, filter, safeOptions, {
2558
- code: err.code,
2559
- codeName: err.codeName,
2560
- message: err.message,
2561
- stack: err.stack
2562
- }], null, 2));
2563
-
2564
- err.message = `Error in Find One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2565
- throw err;
2566
- }
2567
- finally {
2568
- await monitor.finish();
2569
- }
2570
- }
2571
- }
2572
-
2573
- async findOneAndDelete(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, options?: FindOneAndDeleteOptions, bypassLogs = false, bypassSession = false): Promise<T> {
2574
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2575
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2576
- if (!options) {
2577
- options = {session: mongoSession};
2578
- }
2579
- else {
2580
- options.session = mongoSession;
2581
- }
2582
- }
2583
-
2584
- let { session, ...safeOptions } = options || {};
2585
-
2586
- let monitor = MonitorMongo.create('findOneAndDelete', this.collectionName, JSON.stringify([filter, safeOptions]));
2587
-
2588
- try {
2589
- let doc = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndDelete(<any>filter, options) as T;
2590
-
2591
- if (doc) {
2592
- if (this.createLogs && !bypassLogs) {
2593
- if (
2594
- ResolveIOServer.shouldWriteLogsOffline()
2595
- ) {
2596
- ResolveIOServer.getLocalLogManager().writeLog({
2597
- type: 'log',
2598
- data: {
2599
- _id: objectIdHexString(),
2600
- type: 'document',
2601
- collection: this.collectionName,
2602
- id_document: doc._id as string,
2603
- payload: getBinarySize(JSON.stringify([doc, filter, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, safeOptions], null, 2) : 'Too Big',
2604
- method: 'findOneAndDelete',
2605
- id_user: '',
2606
- user: '',
2607
- messageId: 0,
2608
- route: '',
2609
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2610
- createdAt: new Date()
2611
- }
2612
- });
2613
- }
2614
- else {
2615
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
2616
- _id: objectIdHexString(),
2617
- type: 'document',
2618
- collection: this.collectionName,
2619
- id_document: doc._id as string,
2620
- payload: getBinarySize(JSON.stringify([doc, filter, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, safeOptions], null, 2) : 'Too Big',
2621
- method: 'findOneAndDelete',
2622
- id_user: '',
2623
- user: '',
2624
- messageId: 0,
2625
- route: '',
2626
- client: 'ResolveIO',
2627
- instance: ResolveIOServer.getInstanceHost(),
2628
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2629
- createdAt: new Date()
2630
- }, {session});
2631
- }
2632
- }
2633
-
2634
- if (this.useVersions) {
2635
- try {
2636
- let versionDoc = deepCopy(doc);
2637
- versionDoc._id = {_id: doc._id, __v: doc.__v};
2638
-
2639
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
2640
- }
2641
- catch {}
2642
- }
2643
-
2644
- if (!this.skipCache) {
2645
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2646
- }
2647
-
2648
- return <T>doc;
2649
- }
2650
- else {
2651
- return null;
2652
- }
2653
- }
2654
- catch (err) {
2655
- console.log(JSON.stringify([new Date(), 'Error Find One And Delete', this.collectionName, filter, safeOptions, {
2656
- code: err.code,
2657
- codeName: err.codeName,
2658
- message: err.message,
2659
- stack: err.stack
2660
- }], null, 2));
2661
-
2662
- err.message = `Error in Find One And Delete: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2663
- throw err;
2664
- }
2665
- finally {
2666
- await monitor.finish();
2667
- }
2668
- }
2669
-
2670
- async findOneAndReplace(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, replacement: T, options?: FindOneAndReplaceOptions, bypassLogs = false, bypassCheckSchema = false, bypassSession = false): Promise<T> {
2671
- if (this.checkSchema && !bypassCheckSchema) {
2672
- const validation = this.simplschema.newContext();
2673
- const isValid = validation.validate(replacement);
2674
-
2675
- if (!isValid) {
2676
- console.log(new Date(), this.collectionName, 'Schema Errors - findOneAndReplace', validation.validationErrors());
2677
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on findOneAndReplace - ' + this.collectionName, JSON.stringify([validation.validationErrors(), replacement], null, 2));
2678
- throw new Error(JSON.stringify(validation.validationErrors(), null, 2));
2679
- }
2680
- }
2681
-
2682
- let date = new Date();
2683
-
2684
- if (this.timestamps) {
2685
- replacement.updatedAt = date;
2686
- }
2687
-
2688
- if (options && options.upsert) {
2689
- if (!replacement._id) {
2690
- replacement._id = objectIdHexString();
2691
- }
2692
-
2693
- if (this.useVersions) {
2694
- replacement.__v = 0;
2695
- }
2696
-
2697
- if (this.timestamps && !replacement.createdAt) {
2698
- replacement.createdAt = date;
2699
- }
2700
- }
2701
-
2702
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2703
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2704
- if (!options) {
2705
- options = {session: mongoSession};
2706
- }
2707
- else {
2708
- options.session = mongoSession;
2709
- }
2710
- }
2711
-
2712
- let { session, ...safeOptions } = options || {};
2713
-
2714
- let monitor = MonitorMongo.create('findOneAndReplace', this.collectionName, JSON.stringify([filter, replacement, safeOptions]));
2715
-
2716
- try {
2717
- let doc = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndReplace(<any>filter, replacement, options) as T;
2718
-
2719
- if (doc) {
2720
- if (this.createLogs && !bypassLogs) {
2721
- if (
2722
- ResolveIOServer.shouldWriteLogsOffline()
2723
- ) {
2724
- ResolveIOServer.getLocalLogManager().writeLog({
2725
- type: 'log',
2726
- data: {
2727
- _id: objectIdHexString(),
2728
- type: 'document',
2729
- collection: this.collectionName,
2730
- id_document: doc._id as string,
2731
- payload: getBinarySize(JSON.stringify([doc, filter, replacement, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, replacement, safeOptions], null, 2) : 'Too Big',
2732
- method: 'findOneAndReplace',
2733
- id_user: '',
2734
- user: '',
2735
- messageId: 0,
2736
- route: '',
2737
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2738
- createdAt: new Date()
2739
- }
2740
- });
2741
- }
2742
- else {
2743
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
2744
- _id: objectIdHexString(),
2745
- type: 'document',
2746
- collection: this.collectionName,
2747
- id_document: doc._id as string,
2748
- payload: getBinarySize(JSON.stringify([doc, filter, replacement, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, replacement, safeOptions], null, 2) : 'Too Big',
2749
- method: 'findOneAndReplace',
2750
- id_user: '',
2751
- user: '',
2752
- messageId: 0,
2753
- route: '',
2754
- client: 'ResolveIO',
2755
- instance: ResolveIOServer.getInstanceHost(),
2756
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2757
- createdAt: new Date()
2758
- }, {session});
2759
- }
2760
- }
2761
-
2762
- if (this.useVersions) {
2763
- try {
2764
- let versionDoc = deepCopy(doc);
2765
- versionDoc._id = {_id: doc._id, __v: doc.__v};
2766
-
2767
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
2768
- }
2769
- catch {}
2770
- }
2771
-
2772
- if (!this.skipCache) {
2773
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2774
- }
2775
-
2776
- return <T>doc;
2777
- }
2778
- else {
2779
- return null;
2780
- }
2781
- }
2782
- catch (err) {
2783
- console.log(JSON.stringify([new Date(), 'Error Find One And Replace', this.collectionName, filter, safeOptions, {
2784
- code: err.code,
2785
- codeName: err.codeName,
2786
- message: err.message,
2787
- stack: err.stack
2788
- }], null, 2));
2789
-
2790
- err.message = `Error in Find One And Replace: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2791
- throw err;
2792
- }
2793
- finally {
2794
- await monitor.finish();
2795
- }
2796
- }
2797
-
2798
- async findOneAndUpdate(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T> = {}, update: MongoManagerUpdateFilter<T>, options?: FindOneAndUpdateOptions, bypassLogs = false, bypassCheckSchema = false, bypassSession = false): Promise<T> {
2799
- if (this.checkSchema && !bypassCheckSchema) {
2800
- const validation = this.simplschema.newContext();
2801
- const isValid = validation.validate(update, {modifier: true});
2802
-
2803
- if (!isValid) {
2804
- console.log(new Date(), this.collectionName, 'Schema Errors - findOneAndUpdate', validation.validationErrors());
2805
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on findOneAndUpdate - ' + this.collectionName, JSON.stringify([validation.validationErrors(), update], null, 2));
2806
- throw new Error(JSON.stringify(validation.validationErrors(), null, 2));
2807
- }
2808
- }
2809
-
2810
- if (this.timestamps) {
2811
- let date = new Date();
2812
-
2813
- if (!update.$set) {
2814
- update.$set = <any>{updatedAt: date};
2815
- }
2816
- else {
2817
- update.$set.updatedAt = date;
2818
- }
2819
- }
2820
-
2821
- if (options && options.upsert) {
2822
- if (!update.$setOnInsert) {
2823
- if (this.timestamps) {
2824
- update.$setOnInsert = <any>{
2825
- _id: objectIdHexString(),
2826
- createdAt: new Date()
2827
- };
2828
- }
2829
- else {
2830
- update.$setOnInsert = <any>{
2831
- _id: objectIdHexString()
2832
- };
2833
- }
2834
- }
2835
- else {
2836
- if (!update.$setOnInsert._id) {
2837
- update.$setOnInsert._id = objectIdHexString();
2838
- }
2839
-
2840
- if (this.timestamps && !update.$setOnInsert.createdAt) {
2841
- update.$setOnInsert.createdAt = new Date();
2842
- }
2843
- }
2844
- }
2845
-
2846
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
2847
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
2848
- if (!options) {
2849
- options = {session: mongoSession};
2850
- }
2851
- else {
2852
- options.session = mongoSession;
2853
- }
2854
- }
2855
-
2856
-
2857
- let { session, ...safeOptions } = options || {};
2858
-
2859
- let monitor = MonitorMongo.create('findOneAndUpdate', this.collectionName, JSON.stringify([filter, update, safeOptions]));
2860
-
2861
- try {
2862
- let doc = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).findOneAndUpdate(<any>filter, <any>update, options) as T;
2863
-
2864
- if (doc) {
2865
- if (this.createLogs && !bypassLogs) {
2866
- if (
2867
- ResolveIOServer.shouldWriteLogsOffline()
2868
- ) {
2869
- ResolveIOServer.getLocalLogManager().writeLog({
2870
- type: 'log',
2871
- data: {
2872
- _id: objectIdHexString(),
2873
- type: 'document',
2874
- collection: this.collectionName,
2875
- id_document: <string>doc._id,
2876
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
2877
- method: 'findOneAndUpdate',
2878
- id_user: '',
2879
- user: '',
2880
- messageId: 0,
2881
- route: '',
2882
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2883
- createdAt: new Date()
2884
- }
2885
- });
2886
- }
2887
- else {
2888
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
2889
- _id: objectIdHexString(),
2890
- type: 'document',
2891
- collection: this.collectionName,
2892
- id_document: <string>doc._id,
2893
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
2894
- method: 'findOneAndUpdate',
2895
- id_user: '',
2896
- user: '',
2897
- messageId: 0,
2898
- route: '',
2899
- client: 'ResolveIO',
2900
- instance: ResolveIOServer.getInstanceHost(),
2901
- instance_index: process.env.NODE_APP_INSTANCE || '0',
2902
- createdAt: new Date()
2903
- }, {session});
2904
- }
2905
- }
2906
-
2907
- if (this.useVersions) {
2908
- try {
2909
- let versionDoc = deepCopy(doc);
2910
- versionDoc._id = {_id: doc._id, __v: doc.__v};
2911
-
2912
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
2913
- }
2914
- catch {}
2915
- }
2916
-
2917
- if (!this.skipCache) {
2918
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
2919
- }
2920
-
2921
- return <T>doc;
2922
- }
2923
- else {
2924
- return null;
2925
- }
2926
- }
2927
- catch (err) {
2928
- console.log(JSON.stringify([new Date(), 'Error Find One And Update', this.collectionName, filter, safeOptions, {
2929
- code: err.code,
2930
- codeName: err.codeName,
2931
- message: err.message,
2932
- stack: err.stack
2933
- }], null, 2));
2934
-
2935
- err.message = `Error in Find One And Update: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2936
- throw err;
2937
- }
2938
- finally {
2939
- await monitor.finish();
2940
- }
2941
- }
2942
-
2943
- async indexes(options: IndexInformationOptions): Promise<IndexDescriptionCompact | IndexDescriptionCompact[]> {
2944
- // eslint-disable-next-line no-unused-vars
2945
- let { session, ...safeOptions } = options || {};
2946
-
2947
- let monitor = MonitorMongo.create('indexes', this.collectionName, JSON.stringify([safeOptions]));
2948
-
2949
- try {
2950
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).indexes(options);
2951
- return res;
2952
- }
2953
- catch (err) {
2954
- console.log(JSON.stringify([new Date(), 'Error Indexes', this.collectionName, safeOptions, {
2955
- code: err.code,
2956
- codeName: err.codeName,
2957
- message: err.message,
2958
- stack: err.stack
2959
- }], null, 2));
2960
-
2961
- err.message = `Error in Indexes: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2962
- throw err;
2963
- }
2964
- finally {
2965
- await monitor.finish();
2966
- }
2967
- }
2968
-
2969
- async indexExists(indexes: string | string[], options?: IndexInformationOptions): Promise<boolean> {
2970
- // eslint-disable-next-line no-unused-vars
2971
- let { session, ...safeOptions } = options || {};
2972
-
2973
- let monitor = MonitorMongo.create('indexExists', this.collectionName, JSON.stringify([indexes, safeOptions]));
2974
-
2975
- try {
2976
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).indexExists(indexes, options || undefined);
2977
- return res;
2978
- }
2979
- catch (err) {
2980
- console.log(JSON.stringify([new Date(), 'Error Index Exists', this.collectionName, indexes, safeOptions, {
2981
- code: err.code,
2982
- codeName: err.codeName,
2983
- message: err.message,
2984
- stack: err.stack
2985
- }], null, 2));
2986
-
2987
- err.message = `Error in Index Exists: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
2988
- throw err;
2989
- }
2990
- finally {
2991
- await monitor.finish();
2992
- }
2993
- }
2994
-
2995
- async insertMany(docs: T[], options?: BulkWriteOptions, bypassLogs = false, bypassCheckSchema = false, bypassMonitor = false, bypassSession = false): Promise<T[]> {
2996
- if (!docs.length) {
2997
- return [];
2998
- }
2999
-
3000
- let validationResults = [];
3001
-
3002
- if (this.checkSchema && !bypassCheckSchema) {
3003
- for (let doc of docs) {
3004
- const validation = this.simplschema.newContext();
3005
- const isValid = validation.validate(doc);
3006
-
3007
- if (!isValid) {
3008
- console.log(new Date(), this.collectionName, 'Schema Errors - insertMany', validation.validationErrors());
3009
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on insertMany - ' + this.collectionName, JSON.stringify([validation.validationErrors(), doc], null, 2));
3010
- validationResults.push(false);
3011
- }
3012
- else {
3013
- validationResults.push(true);
3014
- }
3015
- }
3016
- }
3017
-
3018
- let validDocs = this.checkSchema ? docs.filter((a, idx) => validationResults[idx]) : docs;
3019
-
3020
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3021
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3022
- if (!options) {
3023
- options = {session: mongoSession};
3024
- }
3025
- else {
3026
- options.session = mongoSession;
3027
- }
3028
- }
3029
-
3030
-
3031
- let { session, ...safeOptions } = options || {};
3032
-
3033
- for (let i = 0; i < validDocs.length; i++) {
3034
- let doc = validDocs[i];
3035
-
3036
- if (!doc._id) {
3037
- doc._id = objectIdHexString();
3038
- }
3039
-
3040
- if (this.timestamps) {
3041
- let date = new Date();
3042
-
3043
- if (!doc.createdAt) {
3044
- doc.createdAt = date;
3045
- }
3046
-
3047
- if (!doc.updatedAt) {
3048
- doc.updatedAt = date;
3049
- }
3050
- }
3051
-
3052
- if (this.useVersions && !doc.hasOwnProperty('__v')) {
3053
- doc.__v = 0;
3054
- }
3055
-
3056
- if (this.createLogs && !bypassLogs) {
3057
- if (
3058
- ResolveIOServer.shouldWriteLogsOffline()
3059
- ) {
3060
- ResolveIOServer.getLocalLogManager().writeLog({
3061
- type: 'log',
3062
- data: {
3063
- _id: objectIdHexString(),
3064
- type: 'document',
3065
- collection: this.collectionName,
3066
- id_document: doc._id,
3067
- payload: getBinarySize(JSON.stringify([doc, safeOptions])) < 1000000 ? JSON.stringify([doc, safeOptions], null, 2) : 'Too Big',
3068
- method: 'insertMany',
3069
- id_user: '',
3070
- user: '',
3071
- messageId: 0,
3072
- route: '',
3073
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3074
- createdAt: new Date()
3075
- }
3076
- });
3077
- }
3078
- else {
3079
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3080
- _id: objectIdHexString(),
3081
- type: 'document',
3082
- collection: this.collectionName,
3083
- id_document: doc._id,
3084
- payload: getBinarySize(JSON.stringify([doc, safeOptions])) < 1000000 ? JSON.stringify([doc, safeOptions], null, 2) : 'Too Big',
3085
- method: 'insertMany',
3086
- id_user: '',
3087
- user: '',
3088
- messageId: 0,
3089
- route: '',
3090
- client: 'ResolveIO',
3091
- instance: ResolveIOServer.getInstanceHost(),
3092
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3093
- createdAt: new Date()
3094
- }, {session});
3095
- }
3096
- }
3097
- }
3098
-
3099
- if (validDocs.length) {
3100
- let monitor = null;
3101
-
3102
- if (!bypassMonitor) {
3103
- monitor = MonitorMongo.create('insertMany', this.collectionName, JSON.stringify([validDocs, safeOptions]));
3104
- }
3105
-
3106
- try {
3107
- await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).insertMany(<OptionalUnlessRequiredId<T>[]>validDocs, options || undefined), options);
3108
- if (!this.skipCache) {
3109
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3110
- }
3111
- return validDocs;
3112
- }
3113
- catch (err) {
3114
- console.log(JSON.stringify([new Date(), 'Error Insert Many', this.collectionName, docs, safeOptions, {
3115
- code: err.code,
3116
- codeName: err.codeName,
3117
- message: err.message,
3118
- stack: err.stack
3119
- }], null, 2));
3120
-
3121
- err.message = `Error in Insert Many: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3122
- throw err;
3123
- }
3124
- finally {
3125
- if (monitor) {
3126
- monitor.finish();
3127
- }
3128
- }
3129
- }
3130
-
3131
- return [];
3132
- }
3133
-
3134
- async insertOne(doc: T, options?: InsertOneOptions, bypassLogs = false, bypassCheckSchema = false, bypassSession = false): Promise<T> {
3135
- if (!doc._id) {
3136
- doc._id = objectIdHexString();
3137
- }
3138
-
3139
- if (this.checkSchema && !bypassCheckSchema) {
3140
- const validation = this.simplschema.newContext();
3141
- const isValid = validation.validate(doc);
3142
-
3143
- if (!isValid) {
3144
- console.log(new Date(), this.collectionName, 'Schema Errors - insertOne', validation.validationErrors());
3145
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on insertOne - ' + this.collectionName, JSON.stringify([validation.validationErrors(), doc], null, 2));
3146
- throw new Error(JSON.stringify(validation.validationErrors(), null, 2));
3147
- }
3148
- }
3149
-
3150
- if (this.timestamps) {
3151
- let date = new Date();
3152
-
3153
- if (!doc.createdAt) {
3154
- doc.createdAt = date;
3155
- }
3156
-
3157
- if (!doc.updatedAt) {
3158
- doc.updatedAt = date;
3159
- }
3160
- }
3161
-
3162
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3163
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3164
- if (!options) {
3165
- options = {session: mongoSession};
3166
- }
3167
- else {
3168
- options.session = mongoSession;
3169
- }
3170
- }
3171
-
3172
-
3173
- let { session, ...safeOptions } = options || {};
3174
-
3175
- if (this.createLogs && !bypassLogs) {
3176
- if (
3177
- ResolveIOServer.shouldWriteLogsOffline()
3178
- ) {
3179
- ResolveIOServer.getLocalLogManager().writeLog({
3180
- type: 'log',
3181
- data: {
3182
- _id: objectIdHexString(),
3183
- type: 'document',
3184
- collection: this.collectionName,
3185
- id_document: doc._id,
3186
- payload: getBinarySize(JSON.stringify([doc, safeOptions])) < 1000000 ? JSON.stringify([doc, safeOptions], null, 2) : 'Too Big',
3187
- method: 'insertOne',
3188
- id_user: '',
3189
- user: '',
3190
- messageId: 0,
3191
- route: '',
3192
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3193
- createdAt: new Date()
3194
- }
3195
- });
3196
- }
3197
- else {
3198
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3199
- _id: objectIdHexString(),
3200
- type: 'document',
3201
- collection: this.collectionName,
3202
- id_document: doc._id,
3203
- payload: getBinarySize(JSON.stringify([doc, safeOptions])) < 1000000 ? JSON.stringify([doc, safeOptions], null, 2) : 'Too Big',
3204
- method: 'insertOne',
3205
- id_user: '',
3206
- user: '',
3207
- messageId: 0,
3208
- route: '',
3209
- client: 'ResolveIO',
3210
- instance: ResolveIOServer.getInstanceHost(),
3211
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3212
- createdAt: new Date()
3213
- }, {session});
3214
- }
3215
- }
3216
-
3217
- if (this.useVersions && !doc.hasOwnProperty('__v')) {
3218
- doc.__v = 0;
3219
- }
3220
-
3221
- let monitor = MonitorMongo.create('insertOne', this.collectionName, JSON.stringify([doc, safeOptions]));
3222
-
3223
- try {
3224
- await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).insertOne(<OptionalUnlessRequiredId<T>>doc, options || undefined), options);
3225
- if (!this.skipCache) {
3226
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3227
- }
3228
-
3229
- return doc;
3230
- }
3231
- catch(err) {
3232
- console.log(JSON.stringify([new Date(), 'Error Insert One', this.collectionName, doc, safeOptions, {
3233
- code: err.code,
3234
- codeName: err.codeName,
3235
- message: err.message,
3236
- stack: err.stack
3237
- }], null, 2));
3238
-
3239
- err.message = `Error in Insert One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3240
- throw err;
3241
- }
3242
- finally {
3243
- await monitor.finish();
3244
- }
3245
- }
3246
-
3247
- listIndexes(options?: ListIndexesOptions, bypassSession = false): ListIndexesCursor {
3248
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3249
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3250
- if (!options) {
3251
- options = {session: mongoSession};
3252
- }
3253
- else {
3254
- options.session = mongoSession;
3255
- }
3256
- }
3257
-
3258
- // eslint-disable-next-line no-unused-vars
3259
- let { session, ...safeOptions } = options || {};
3260
-
3261
- let monitor = MonitorMongo.create('listIndexes', this.collectionName, JSON.stringify([safeOptions]));
3262
- let cursor = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).listIndexes(options);
3263
- cursor.on('close', async ev => {
3264
- await monitor.finish();
3265
- return ev;
3266
- });
3267
-
3268
- return cursor;
3269
- }
3270
-
3271
- async rename(newName: string, options?: RenameOptions, bypassSession = false): Promise<Collection<Document>> {
3272
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3273
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3274
- if (!options) {
3275
- options = {
3276
- session: mongoSession
3277
- };
3278
- }
3279
- else {
3280
- options.session = mongoSession;
3281
- }
3282
- }
3283
-
3284
- // eslint-disable-next-line no-unused-vars
3285
- let { session, ...safeOptions } = options || {};
3286
-
3287
- let monitor = MonitorMongo.create('rename', this.collectionName, JSON.stringify([newName, safeOptions]));
3288
- try {
3289
- let res = await ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).rename(newName, options || undefined);
3290
- return res;
3291
- }
3292
- catch (err) {
3293
- console.log(JSON.stringify([new Date(), 'Error Rename', this.collectionName, newName, safeOptions, {
3294
- code: err.code,
3295
- codeName: err.codeName,
3296
- message: err.message,
3297
- stack: err.stack
3298
- }], null, 2));
3299
-
3300
- err.message = `Error in Rename: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3301
- throw err;
3302
- }
3303
- finally {
3304
- await monitor.finish();
3305
- }
3306
- }
3307
-
3308
- async replaceOne(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, replacement: T, options?: ReplaceOptions, bypassLogs = false, bypassCheckSchema = false, doc: T = null, bypassSession = false) : Promise<UpdateResult> {
3309
- if (this.checkSchema && !bypassCheckSchema) {
3310
- const validation = this.simplschema.newContext();
3311
- const isValid = validation.validate(replacement);
3312
-
3313
- if (!isValid) {
3314
- console.log(new Date(), this.collectionName, 'Schema Errors - replaceOne', validation.validationErrors());
3315
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on replaceOne - ' + this.collectionName, JSON.stringify([validation.validationErrors(), replacement], null, 2));
3316
- throw new Error(JSON.stringify(validation.validationErrors(), null, 2));
3317
- }
3318
- }
3319
-
3320
- let date = new Date();
3321
-
3322
- if (this.timestamps) {
3323
- replacement.updatedAt = date;
3324
- }
3325
-
3326
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3327
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3328
- if (!options) {
3329
- options = {session: mongoSession};
3330
- }
3331
- else {
3332
- options.session = mongoSession;
3333
- }
3334
-
3335
- // console.log('Replace One', 'Has Session', this.collectionName, JSON.stringify(filter, null, 2), JSON.stringify(replacement, null, 2));
3336
- }
3337
- else {
3338
- // console.log('Replace One', 'No Session', this.collectionName, JSON.stringify(filter, null, 2), JSON.stringify(replacement, null, 2));
3339
- }
3340
-
3341
-
3342
- let { session, ...safeOptions } = options || {};
3343
-
3344
- if (this.useVersions) {
3345
- if (!doc) {
3346
- doc = await this.findOne(<any>filter, {session}, true);
3347
- }
3348
-
3349
- if (doc) {
3350
- if (this.timestamps && !replacement.createdAt && doc.createdAt) {
3351
- replacement.createdAt = doc.createdAt;
3352
- }
3353
-
3354
- if (doc.__v === replacement.__v) {
3355
- try {
3356
- replacement.__v += 1;
3357
-
3358
- let versionDoc = deepCopy(doc);
3359
- versionDoc._id = {_id: doc._id, __v: doc.__v};
3360
-
3361
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
3362
-
3363
- if (doc.__v >= 4) {
3364
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 4}}]});
3365
- }
3366
- }
3367
- catch {}
3368
-
3369
- if (this.createLogs && !bypassLogs) {
3370
- if (
3371
- ResolveIOServer.shouldWriteLogsOffline()
3372
- ) {
3373
- ResolveIOServer.getLocalLogManager().writeLog({
3374
- type: 'log',
3375
- data: {
3376
- _id: objectIdHexString(),
3377
- type: 'document',
3378
- collection: this.collectionName,
3379
- id_document: doc._id,
3380
- payload: getBinarySize(JSON.stringify([doc, filter, replacement, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, replacement, safeOptions], null, 2) : 'Too Big',
3381
- method: 'replaceOne',
3382
- id_user: '',
3383
- user: '',
3384
- messageId: 0,
3385
- route: '',
3386
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3387
- createdAt: new Date()
3388
- }
3389
- });
3390
- }
3391
- else {
3392
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3393
- _id: objectIdHexString(),
3394
- type: 'document',
3395
- collection: this.collectionName,
3396
- id_document: doc._id,
3397
- payload: getBinarySize(JSON.stringify([doc, filter, replacement, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, replacement, safeOptions], null, 2) : 'Too Big',
3398
- method: 'replaceOne',
3399
- id_user: '',
3400
- user: '',
3401
- messageId: 0,
3402
- route: '',
3403
- client: 'ResolveIO',
3404
- instance: ResolveIOServer.getInstanceHost(),
3405
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3406
- createdAt: new Date()
3407
- }, {session});
3408
- }
3409
- }
3410
-
3411
- let monitor = MonitorMongo.create('replaceOne', this.collectionName, JSON.stringify([filter, replacement, safeOptions]));
3412
-
3413
- try {
3414
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options), options);
3415
- if (!this.skipCache) {
3416
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3417
- }
3418
- return res;
3419
- }
3420
- catch (err) {
3421
- console.log(JSON.stringify([new Date(), 'Error Replace One', this.collectionName, filter, replacement, safeOptions, {
3422
- code: err.code,
3423
- codeName: err.codeName,
3424
- message: err.message,
3425
- stack: err.stack
3426
- }], null, 2));
3427
-
3428
- err.message = `Error in Replace One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3429
- throw err;
3430
- }
3431
- finally {
3432
- await monitor.finish();
3433
- }
3434
- }
3435
- else {
3436
- console.log('invalid version - ' + this.collectionName, doc.__v, replacement.__v);
3437
-
3438
- let prevDoc = await ResolveIOServer.getMongoManager().collection(this.versionCollection).findOne({
3439
- _id: <any>{
3440
- _id: doc._id,
3441
- __v: replacement.__v
3442
- }
3443
- }, null, true);
3444
-
3445
- if (prevDoc) {
3446
- let docId = doc._id;
3447
- let docVersion = doc.__v;
3448
- let updatedDoc: T = getMongoMergeUpdatedDoc(replacement, doc, prevDoc);
3449
- updatedDoc._id = docId;
3450
- updatedDoc.__v = docVersion + 1;
3451
-
3452
- if (this.createLogs && !bypassLogs) {
3453
- if (
3454
- ResolveIOServer.shouldWriteLogsOffline()
3455
- ) {
3456
- ResolveIOServer.getLocalLogManager().writeLog({
3457
- type: 'log',
3458
- data: {
3459
- _id: objectIdHexString(),
3460
- type: 'document',
3461
- collection: this.collectionName,
3462
- id_document: docId,
3463
- payload: getBinarySize(JSON.stringify(['invalidVersion - merge', doc, filter, updatedDoc, safeOptions])) < 1000000 ? JSON.stringify(['invalidVersion - merge', doc, filter, updatedDoc, safeOptions], null, 2) : 'Too Big',
3464
- method: 'replaceOne',
3465
- id_user: '',
3466
- user: '',
3467
- messageId: 0,
3468
- route: '',
3469
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3470
- createdAt: new Date()
3471
- }
3472
- });
3473
- }
3474
- else {
3475
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3476
- _id: objectIdHexString(),
3477
- type: 'document',
3478
- collection: this.collectionName,
3479
- id_document: docId,
3480
- payload: getBinarySize(JSON.stringify(['invalidVersion - merge', doc, filter, updatedDoc, safeOptions])) < 1000000 ? JSON.stringify(['invalidVersion - merge', doc, filter, updatedDoc, safeOptions], null, 2) : 'Too Big',
3481
- method: 'replaceOne',
3482
- id_user: '',
3483
- user: '',
3484
- messageId: 0,
3485
- route: '',
3486
- client: 'ResolveIO',
3487
- instance: ResolveIOServer.getInstanceHost(),
3488
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3489
- createdAt: new Date()
3490
- }, {session});
3491
- }
3492
- }
3493
-
3494
- let monitor = MonitorMongo.create('replaceOne', this.collectionName, JSON.stringify([filter, updatedDoc, safeOptions]));
3495
-
3496
- try {
3497
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, updatedDoc, options), options);
3498
- if (!this.skipCache) {
3499
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3500
- }
3501
- return res;
3502
- }
3503
- catch (err) {
3504
- console.log(JSON.stringify([new Date(), 'Error Replace One', this.collectionName, filter, replacement, safeOptions, {
3505
- code: err.code,
3506
- codeName: err.codeName,
3507
- message: err.message,
3508
- stack: err.stack
3509
- }], null, 2));
3510
-
3511
- err.message = `Error in Replace One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3512
- throw err;
3513
- }
3514
- finally {
3515
- await monitor.finish();
3516
- }
3517
- }
3518
- else {
3519
- throw new Error('Error in Replace One: Invalid Version And Could Not Find History - DB: ' + doc.__v + ', Trying to update with :' + replacement.__v);
3520
- }
3521
- }
3522
- }
3523
- else if (options && options.upsert) {
3524
- if (this.timestamps) {
3525
- replacement.createdAt = date;
3526
- }
3527
-
3528
- if (!replacement._id) {
3529
- replacement._id = objectIdHexString();
3530
- }
3531
-
3532
- replacement.__v = 0;
3533
-
3534
- if (this.createLogs && !bypassLogs) {
3535
- if (
3536
- ResolveIOServer.shouldWriteLogsOffline()
3537
- ) {
3538
- ResolveIOServer.getLocalLogManager().writeLog({
3539
- type: 'log',
3540
- data: {
3541
- _id: objectIdHexString(),
3542
- type: 'document',
3543
- collection: this.collectionName,
3544
- id_document: replacement._id,
3545
- payload: getBinarySize(JSON.stringify(['upsert', filter, replacement, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, replacement, safeOptions], null, 2) : 'Too Big',
3546
- method: 'replaceOne',
3547
- id_user: '',
3548
- user: '',
3549
- messageId: 0,
3550
- route: '',
3551
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3552
- createdAt: new Date()
3553
- }
3554
- });
3555
- }
3556
- else {
3557
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3558
- _id: objectIdHexString(),
3559
- type: 'document',
3560
- collection: this.collectionName,
3561
- id_document: replacement._id,
3562
- payload: getBinarySize(JSON.stringify(['upsert', filter, replacement, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, replacement, safeOptions], null, 2) : 'Too Big',
3563
- method: 'replaceOne',
3564
- id_user: '',
3565
- user: '',
3566
- messageId: 0,
3567
- route: '',
3568
- client: 'ResolveIO',
3569
- instance: ResolveIOServer.getInstanceHost(),
3570
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3571
- createdAt: new Date()
3572
- }, {session});
3573
- }
3574
- }
3575
-
3576
- let monitor = MonitorMongo.create('replaceOne', this.collectionName, JSON.stringify([filter, replacement, safeOptions]));
3577
-
3578
- try {
3579
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options), options);
3580
- if (!this.skipCache) {
3581
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3582
- }
3583
- return res;
3584
- }
3585
- catch (err) {
3586
- console.log(JSON.stringify([new Date(), 'Error Replace One', this.collectionName, filter, replacement, safeOptions, {
3587
- code: err.code,
3588
- codeName: err.codeName,
3589
- message: err.message,
3590
- stack: err.stack
3591
- }], null, 2));
3592
-
3593
- err.message = `Error in Replace One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3594
- throw err;
3595
- }
3596
- finally {
3597
- await monitor.finish();
3598
- }
3599
- }
3600
- else {
3601
- return {
3602
- acknowledged: false,
3603
- matchedCount: 0,
3604
- modifiedCount: 0,
3605
- upsertedCount: 0,
3606
- upsertedId: null
3607
- };
3608
- }
3609
- }
3610
- else {
3611
- if (options && options.upsert) {
3612
- if (this.timestamps && !replacement.createdAt) {
3613
- replacement.createdAt = date;
3614
- }
3615
-
3616
- if (!replacement._id) {
3617
- replacement._id = objectIdHexString();
3618
- }
3619
-
3620
- replacement.__v = 0;
3621
- }
3622
-
3623
- if (this.createLogs && !bypassLogs) {
3624
- if (!options) {
3625
- options = <FindOneAndReplaceOptions>{returnDocument: 'before'};
3626
- }
3627
- else {
3628
- (<FindOneAndReplaceOptions>options).returnDocument = 'before';
3629
- }
3630
-
3631
-
3632
- let { session, ...safeOptions } = options || {};
3633
-
3634
- let monitor = MonitorMongo.create('findOneAndReplace', this.collectionName, JSON.stringify([filter, replacement, safeOptions]));
3635
-
3636
- try {
3637
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options), options);
3638
-
3639
- let doc = await this.findOne(filter, options || undefined);
3640
-
3641
- if (doc) {
3642
- if (
3643
- ResolveIOServer.shouldWriteLogsOffline()
3644
- ) {
3645
- ResolveIOServer.getLocalLogManager().writeLog({
3646
- type: 'log',
3647
- data: {
3648
- _id: objectIdHexString(),
3649
- type: 'document',
3650
- collection: this.collectionName,
3651
- id_document: <string>doc._id,
3652
- payload: getBinarySize(JSON.stringify([doc, filter, replacement, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, replacement, safeOptions], null, 2) : 'Too Big',
3653
- method: 'replaceOne',
3654
- id_user: '',
3655
- user: '',
3656
- messageId: 0,
3657
- route: '',
3658
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3659
- createdAt: new Date()
3660
- }
3661
- });
3662
- }
3663
- else {
3664
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3665
- _id: objectIdHexString(),
3666
- type: 'document',
3667
- collection: this.collectionName,
3668
- id_document: <string>doc._id,
3669
- payload: getBinarySize(JSON.stringify([doc, filter, replacement, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, replacement, safeOptions], null, 2) : 'Too Big',
3670
- method: 'replaceOne',
3671
- id_user: '',
3672
- user: '',
3673
- messageId: 0,
3674
- route: '',
3675
- client: 'ResolveIO',
3676
- instance: ResolveIOServer.getInstanceHost(),
3677
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3678
- createdAt: new Date()
3679
- }, {session});
3680
- }
3681
- }
3682
- else {
3683
- if (
3684
- ResolveIOServer.shouldWriteLogsOffline()
3685
- ) {
3686
- ResolveIOServer.getLocalLogManager().writeLog({
3687
- type: 'log',
3688
- data: {
3689
- _id: objectIdHexString(),
3690
- type: 'document',
3691
- collection: this.collectionName,
3692
- id_document: replacement._id,
3693
- payload: getBinarySize(JSON.stringify(['upsert', filter, replacement, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, replacement, safeOptions], null, 2) : 'Too Big',
3694
- method: 'replaceOne',
3695
- id_user: '',
3696
- user: '',
3697
- messageId: 0,
3698
- route: '',
3699
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3700
- createdAt: new Date()
3701
- }
3702
- });
3703
- }
3704
- else {
3705
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3706
- _id: objectIdHexString(),
3707
- type: 'document',
3708
- collection: this.collectionName,
3709
- id_document: replacement._id,
3710
- payload: getBinarySize(JSON.stringify(['upsert', filter, replacement, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, replacement, safeOptions], null, 2) : 'Too Big',
3711
- method: 'replaceOne',
3712
- id_user: '',
3713
- user: '',
3714
- messageId: 0,
3715
- route: '',
3716
- client: 'ResolveIO',
3717
- instance: ResolveIOServer.getInstanceHost(),
3718
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3719
- createdAt: new Date()
3720
- }, {session});
3721
- }
3722
- }
3723
-
3724
- if (!this.skipCache) {
3725
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3726
- }
3727
-
3728
- return res;
3729
- }
3730
- catch (err) {
3731
- console.log(JSON.stringify([new Date(), 'Error Replace One (Find One And Replace)', this.collectionName, filter, safeOptions, {
3732
- code: err.code,
3733
- codeName: err.codeName,
3734
- message: err.message,
3735
- stack: err.stack
3736
- }], null, 2));
3737
-
3738
- err.message = `Error in Replace One (Find One And Replace): ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3739
- throw err;
3740
- }
3741
- finally {
3742
- await monitor.finish();
3743
- }
3744
- }
3745
- else {
3746
- let monitor = MonitorMongo.create('replaceOne', this.collectionName, JSON.stringify([filter, replacement, safeOptions]));
3747
-
3748
- try {
3749
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).replaceOne(<any>filter, replacement, options), options);
3750
- if (!this.skipCache) {
3751
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3752
- }
3753
- return res;
3754
- }
3755
- catch (err) {
3756
- console.log(JSON.stringify([new Date(), 'Error Replace One', this.collectionName, filter, replacement, safeOptions, {
3757
- code: err.code,
3758
- codeName: err.codeName,
3759
- message: err.message,
3760
- stack: err.stack
3761
- }], null, 2));
3762
-
3763
- err.message = `Error in Replace One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3764
- throw err;
3765
- }
3766
- finally {
3767
- await monitor.finish();
3768
- }
3769
- }
3770
- }
3771
- }
3772
-
3773
- async updateMany(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, update: MongoManagerUpdateFilter<T>, options?: UpdateOptions, bypassLogs = false, bypassCheckSchema = false, bypassVersions = false, bypassSession = false) : Promise<UpdateResult> {
3774
- const isEmptyUpdate = !update.$set && !update.$unset && !update.$inc && !update.$setOnInsert && !update.$push && !update.$pull && !update.$addToSet && !update.$min && !update.$max && !update.$currentDate && !update.$mul && !update.$rename;
3775
-
3776
- const allEmpty =
3777
- isEmptyUpdate ||
3778
- Object.values(update).every(op => {
3779
- if (!op) {
3780
- return true;
3781
- }
3782
-
3783
- for (let key in op) {
3784
- if (Object.prototype.hasOwnProperty.call(op, key)) {
3785
- return false;
3786
- }
3787
- }
3788
-
3789
- return true;
3790
- });
3791
-
3792
- if (allEmpty) {
3793
- return {
3794
- acknowledged: false,
3795
- matchedCount: 0,
3796
- modifiedCount: 0,
3797
- upsertedCount: 0,
3798
- upsertedId: null
3799
- };
3800
- }
3801
-
3802
- if (this.timestamps) {
3803
- let date = new Date();
3804
-
3805
- if (!update.$set) {
3806
- update.$set = <any>{updatedAt: date};
3807
- }
3808
- else {
3809
- update.$set.updatedAt = date;
3810
- }
3811
- }
3812
-
3813
- if (this.checkSchema && !bypassCheckSchema) {
3814
- const validation = this.simplschema.newContext();
3815
- const isValid = validation.validate(update, {modifier: true});
3816
-
3817
- if (!isValid) {
3818
- console.log(new Date(), this.collectionName, 'Schema Errors - updateMany', validation.validationErrors());
3819
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on updateMany - ' + this.collectionName, JSON.stringify([validation.validationErrors(), update], null, 2));
3820
- throw new Error(JSON.stringify(validation.validationErrors(), null, 2));
3821
- }
3822
- }
3823
-
3824
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3825
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3826
- if (!options) {
3827
- options = {session: mongoSession};
3828
- }
3829
- else {
3830
- options.session = mongoSession;
3831
- }
3832
- }
3833
-
3834
-
3835
- let { session, ...safeOptions } = options || {};
3836
-
3837
- if ((this.useVersions && !bypassVersions) || (this.createLogs && !bypassLogs)) {
3838
- let docs = await this.find(filter, {session});
3839
-
3840
- for (let i = 0; i < docs.length; i++) {
3841
- let doc = docs[i];
3842
-
3843
- if (this.createLogs && !bypassLogs) {
3844
- if (
3845
- ResolveIOServer.shouldWriteLogsOffline()
3846
- ) {
3847
- ResolveIOServer.getLocalLogManager().writeLog({
3848
- type: 'log',
3849
- data: {
3850
- _id: objectIdHexString(),
3851
- type: 'document',
3852
- collection: this.collectionName,
3853
- id_document: doc._id,
3854
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
3855
- method: 'updateMany',
3856
- id_user: '',
3857
- user: '',
3858
- messageId: 0,
3859
- route: '',
3860
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3861
- createdAt: new Date()
3862
- }
3863
- });
3864
- }
3865
- else {
3866
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
3867
- _id: objectIdHexString(),
3868
- type: 'document',
3869
- collection: this.collectionName,
3870
- id_document: doc._id,
3871
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
3872
- method: 'updateMany',
3873
- id_user: '',
3874
- user: '',
3875
- messageId: 0,
3876
- route: '',
3877
- client: 'ResolveIO',
3878
- instance: ResolveIOServer.getInstanceHost(),
3879
- instance_index: process.env.NODE_APP_INSTANCE || '0',
3880
- createdAt: new Date()
3881
- }, {session});
3882
- }
3883
- }
3884
-
3885
- if (this.useVersions) {
3886
- try {
3887
- let versionDoc = deepCopy(doc);
3888
- versionDoc._id = {_id: doc._id, __v: doc.__v};
3889
-
3890
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
3891
-
3892
- if (doc.__v >= 4) {
3893
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 4}}]});
3894
- }
3895
- }
3896
- catch {}
3897
-
3898
- if (!update.$inc) {
3899
- update.$inc = {};
3900
- }
3901
-
3902
- if (typeof update.$inc.__v !== 'number') {
3903
- update.$inc.__v = 1;
3904
- }
3905
-
3906
- // Managed versioned collections own __v updates.
3907
- stripManagedVersionFields(update);
3908
- }
3909
- }
3910
- }
3911
-
3912
- let monitor = MonitorMongo.create('updateMany', this.collectionName, JSON.stringify([filter, update, safeOptions]));
3913
-
3914
- try {
3915
- let res = await this.retryWrite<UpdateResult>(() => ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateMany(<any>filter, <any>update, options), options);
3916
- if (!this.skipCache) {
3917
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
3918
- }
3919
-
3920
- return res;
3921
- }
3922
- catch (err) {
3923
- console.log(JSON.stringify([new Date(), 'Error Update Many', this.collectionName, filter, update, safeOptions, {
3924
- code: err.code,
3925
- codeName: err.codeName,
3926
- message: err.message,
3927
- stack: err.stack
3928
- }], null, 2));
3929
-
3930
- err.message = `Error in Update Many: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
3931
- throw err;
3932
- }
3933
- finally {
3934
- await monitor.finish();
3935
- }
3936
- }
3937
-
3938
- async updateOne(filter: MongoManagerFilter<T> & MongoManagerFilterOperators<T>, update: MongoManagerUpdateFilter<T>, options?: UpdateOptions, bypassLogs = false, bypassCheckSchema = false, bypassSession = false) : Promise<UpdateResult> {
3939
- if (this.checkSchema && !bypassCheckSchema) {
3940
- const validation = this.simplschema.newContext();
3941
- const isValid = validation.validate(update, {modifier: true});
3942
-
3943
- if (!isValid) {
3944
- console.log(new Date(), this.collectionName, 'Schema Errors - updateOne', validation.validationErrors());
3945
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('insertErrorLog', 'Schema Failed on updateOne - ' + this.collectionName, JSON.stringify([validation.validationErrors(), update], null, 2));
3946
- throw new Error(JSON.stringify(validation.validationErrors(), null, 2));
3947
- }
3948
- }
3949
-
3950
- const isEmptyUpdate = !update.$set && !update.$unset && !update.$inc && !update.$setOnInsert && !update.$push && !update.$pull && !update.$addToSet && !update.$min && !update.$max && !update.$currentDate && !update.$mul && !update.$rename;
3951
-
3952
- const allEmpty =
3953
- isEmptyUpdate ||
3954
- Object.values(update).every(op => {
3955
- if (!op) {
3956
- return true;
3957
- }
3958
-
3959
- for (let key in op) {
3960
- if (Object.prototype.hasOwnProperty.call(op, key)) {
3961
- return false;
3962
- }
3963
- }
3964
-
3965
- return true;
3966
- });
3967
-
3968
- if (allEmpty) {
3969
- return {
3970
- acknowledged: false,
3971
- matchedCount: 0,
3972
- modifiedCount: 0,
3973
- upsertedCount: 0,
3974
- upsertedId: null
3975
- };
3976
- }
3977
-
3978
-
3979
- let date = new Date();
3980
-
3981
- if (this.timestamps) {
3982
- if (!update.$set) {
3983
- update.$set = <any>{updatedAt: date};
3984
- }
3985
- else {
3986
- update.$set.updatedAt = date;
3987
- }
3988
- }
3989
-
3990
- const mongoSession = ResolveIOServer.getMongoManager().getSession();
3991
-
3992
- if (mongoSession && !bypassSession && !this.bypassSession && (!options || ((!options.readPreference || options.readPreference === 'primary') && !options.session))) {
3993
- if (!options) {
3994
- options = {session: mongoSession};
3995
- }
3996
- else {
3997
- options.session = mongoSession;
3998
- }
3999
- // console.log('Update One', 'Has Session', this.collectionName, JSON.stringify(filter, null, 2), JSON.stringify(update, null, 2));
4000
- }
4001
- else {
4002
- // console.log('Update One', 'No Session', this.collectionName, JSON.stringify(filter, null, 2), JSON.stringify(update, null, 2));
4003
- }
4004
-
4005
- let { session, ...safeOptions } = options || {};
4006
-
4007
- if (this.useVersions) {
4008
- let doc = await this.findOne(filter, {session}, true);
4009
-
4010
- if (doc) {
4011
- if (this.createLogs && !bypassLogs) {
4012
- if (
4013
- ResolveIOServer.shouldWriteLogsOffline()
4014
- ) {
4015
- ResolveIOServer.getLocalLogManager().writeLog({
4016
- type: 'log',
4017
- data: {
4018
- _id: objectIdHexString(),
4019
- type: 'document',
4020
- collection: this.collectionName,
4021
- id_document: doc._id,
4022
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
4023
- method: 'updateOne',
4024
- id_user: '',
4025
- user: '',
4026
- messageId: 0,
4027
- route: '',
4028
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4029
- createdAt: new Date()
4030
- }
4031
- });
4032
- }
4033
- else {
4034
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
4035
- _id: objectIdHexString(),
4036
- type: 'document',
4037
- collection: this.collectionName,
4038
- id_document: doc._id,
4039
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
4040
- method: 'updateOne',
4041
- id_user: '',
4042
- user: '',
4043
- messageId: 0,
4044
- route: '',
4045
- client: 'ResolveIO',
4046
- instance: ResolveIOServer.getInstanceHost(),
4047
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4048
- createdAt: new Date()
4049
- }, {session});
4050
- }
4051
- }
4052
-
4053
- try {
4054
- let versionDoc = deepCopy(doc);
4055
- versionDoc._id = {_id: doc._id, __v: doc.__v};
4056
-
4057
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).replaceOne(<any>{_id: { _id: doc._id, __v: doc.__v}}, versionDoc, {upsert: true});
4058
-
4059
- if (doc.__v >= 4) {
4060
- await ResolveIOServer.getMongoManager().collection(this.versionCollection).deleteMany(<any>{$and: [{'_id._id': doc._id}, {'_id.__v': {$lt: doc.__v - 4}}]});
4061
- }
4062
- }
4063
- catch {}
4064
-
4065
- if (!update.$inc) {
4066
- update.$inc = {};
4067
- }
4068
-
4069
- if (typeof update.$inc.__v !== 'number') {
4070
- update.$inc.__v = 1;
4071
- }
4072
-
4073
- // Managed versioned collections own __v updates.
4074
- stripManagedVersionFields(update);
4075
-
4076
- let monitor = MonitorMongo.create('updateOne', this.collectionName, JSON.stringify([filter, update, safeOptions]));
4077
-
4078
- try {
4079
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, <any>update, options || undefined), options);
4080
- if (!this.skipCache) {
4081
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
4082
- }
4083
- return res;
4084
- }
4085
- catch (err) {
4086
- console.log(JSON.stringify([new Date(), 'Error Update One', this.collectionName, filter, update, safeOptions, {
4087
- code: err.code,
4088
- codeName: err.codeName,
4089
- message: err.message,
4090
- stack: err.stack
4091
- }], null, 2));
4092
-
4093
- err.message = `Error in Update One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
4094
- throw err;
4095
- }
4096
- finally {
4097
- await monitor.finish();
4098
- }
4099
- }
4100
- else if (options && options.upsert) {
4101
- if (!update.$setOnInsert) {
4102
- if (this.timestamps) {
4103
- update.$setOnInsert = <any>{
4104
- _id: objectIdHexString(),
4105
- __v: 0,
4106
- createdAt: new Date()
4107
- };
4108
- }
4109
- else {
4110
- update.$setOnInsert = <any>{
4111
- _id: objectIdHexString(),
4112
- __v: 0
4113
- };
4114
- }
4115
- }
4116
- else {
4117
- if (!update.$setOnInsert._id) {
4118
- update.$setOnInsert._id = objectIdHexString();
4119
- }
4120
-
4121
- if (this.timestamps && !update.$setOnInsert.createdAt) {
4122
- update.$setOnInsert.createdAt = new Date();
4123
- }
4124
- }
4125
-
4126
- if (this.createLogs && !bypassLogs) {
4127
- if (
4128
- ResolveIOServer.shouldWriteLogsOffline()
4129
- ) {
4130
- ResolveIOServer.getLocalLogManager().writeLog({
4131
- type: 'log',
4132
- data: {
4133
- _id: objectIdHexString(),
4134
- type: 'document',
4135
- collection: this.collectionName,
4136
- id_document: update.$setOnInsert._id,
4137
- payload: getBinarySize(JSON.stringify(['upsert', filter, update, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, update, safeOptions], null, 2) : 'Too Big',
4138
- method: 'updateOne',
4139
- id_user: '',
4140
- user: '',
4141
- messageId: 0,
4142
- route: '',
4143
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4144
- createdAt: new Date()
4145
- }
4146
- });
4147
- }
4148
- else {
4149
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
4150
- _id: objectIdHexString(),
4151
- type: 'document',
4152
- collection: this.collectionName,
4153
- id_document: update.$setOnInsert._id,
4154
- payload: getBinarySize(JSON.stringify(['upsert', filter, update, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, update, safeOptions], null, 2) : 'Too Big',
4155
- method: 'updateOne',
4156
- id_user: '',
4157
- user: '',
4158
- messageId: 0,
4159
- route: '',
4160
- client: 'ResolveIO',
4161
- instance: ResolveIOServer.getInstanceHost(),
4162
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4163
- createdAt: new Date()
4164
- }, {session});
4165
- }
4166
- }
4167
-
4168
- let monitor = MonitorMongo.create('updateOne', this.collectionName, JSON.stringify([filter, update, safeOptions]));
4169
-
4170
- try {
4171
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, <any>update, options || undefined), options);
4172
- if (!this.skipCache) {
4173
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
4174
- }
4175
- return res;
4176
- }
4177
- catch (err) {
4178
- console.log(JSON.stringify([new Date(), 'Error Update One', this.collectionName, filter, safeOptions, {
4179
- code: err.code,
4180
- codeName: err.codeName,
4181
- message: err.message,
4182
- stack: err.stack
4183
- }], null, 2));
4184
-
4185
- err.message = `Error in Update One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
4186
- throw err;
4187
- }
4188
- finally {
4189
- await monitor.finish();
4190
- }
4191
- }
4192
- else {
4193
- return {
4194
- acknowledged: false,
4195
- matchedCount: 0,
4196
- modifiedCount: 0,
4197
- upsertedCount: 0,
4198
- upsertedId: null
4199
- };
4200
- }
4201
- }
4202
- else {
4203
- if (options && options.upsert) {
4204
- if (!update.$setOnInsert) {
4205
- if (this.timestamps) {
4206
- update.$setOnInsert = <any>{
4207
- _id: objectIdHexString(),
4208
- createdAt: new Date()
4209
- };
4210
- }
4211
- else {
4212
- update.$setOnInsert = <any>{
4213
- _id: objectIdHexString()
4214
- };
4215
- }
4216
- }
4217
- else {
4218
- if (!update.$setOnInsert._id) {
4219
- update.$setOnInsert._id = objectIdHexString();
4220
- }
4221
-
4222
- if (this.timestamps && !update.$setOnInsert.createdAt) {
4223
- update.$setOnInsert.createdAt = new Date();
4224
- }
4225
- }
4226
- }
4227
-
4228
- if (this.createLogs && !bypassLogs) {
4229
- if (!options) {
4230
- options = <FindOneAndUpdateOptions>{returnDocument: 'before'};
4231
- }
4232
- else {
4233
- (<FindOneAndUpdateOptions>options).returnDocument = 'before';
4234
- }
4235
-
4236
- let monitor = MonitorMongo.create('findOneAndUpdate', this.collectionName, JSON.stringify([filter, update, safeOptions]));
4237
-
4238
- try {
4239
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, <any>update, options || undefined), options);
4240
-
4241
- let doc = await this.findOne(filter, options || undefined);
4242
-
4243
- if (doc) {
4244
- if (
4245
- ResolveIOServer.shouldWriteLogsOffline()
4246
- ) {
4247
- ResolveIOServer.getLocalLogManager().writeLog({
4248
- type: 'log',
4249
- data: {
4250
- _id: objectIdHexString(),
4251
- type: 'document',
4252
- collection: this.collectionName,
4253
- id_document: <any>doc._id,
4254
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
4255
- method: 'updateOne',
4256
- id_user: '',
4257
- user: '',
4258
- messageId: 0,
4259
- route: '',
4260
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4261
- createdAt: new Date()
4262
- }
4263
- });
4264
- }
4265
- else {
4266
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
4267
- _id: objectIdHexString(),
4268
- type: 'document',
4269
- collection: this.collectionName,
4270
- id_document: <any>doc._id,
4271
- payload: getBinarySize(JSON.stringify([doc, filter, update, safeOptions])) < 1000000 ? JSON.stringify([doc, filter, update, safeOptions], null, 2) : 'Too Big',
4272
- method: 'updateOne',
4273
- id_user: '',
4274
- user: '',
4275
- messageId: 0,
4276
- route: '',
4277
- client: 'ResolveIO',
4278
- instance: ResolveIOServer.getInstanceHost(),
4279
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4280
- createdAt: new Date()
4281
- }, {session});
4282
- }
4283
-
4284
- return res;
4285
- }
4286
- else if (update.$setOnInsert) {
4287
- if (
4288
- ResolveIOServer.shouldWriteLogsOffline()
4289
- ) {
4290
- ResolveIOServer.getLocalLogManager().writeLog({
4291
- type: 'log',
4292
- data: {
4293
- _id: objectIdHexString(),
4294
- type: 'document',
4295
- collection: this.collectionName,
4296
- id_document: update.$setOnInsert._id,
4297
- payload: getBinarySize(JSON.stringify(['upsert', filter, update, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, update, safeOptions], null, 2) : 'Too Big',
4298
- method: 'updateOne',
4299
- id_user: '',
4300
- user: '',
4301
- messageId: 0,
4302
- route: '',
4303
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4304
- createdAt: new Date()
4305
- }
4306
- });
4307
- }
4308
- else {
4309
- await ResolveIOServer.getMainDB().collection('logs').insertOne(<any>{
4310
- _id: objectIdHexString(),
4311
- type: 'document',
4312
- collection: this.collectionName,
4313
- id_document: update.$setOnInsert._id,
4314
- payload: getBinarySize(JSON.stringify(['upsert', filter, update, safeOptions])) < 1000000 ? JSON.stringify(['upsert', filter, update, safeOptions], null, 2) : 'Too Big',
4315
- method: 'updateOne',
4316
- id_user: '',
4317
- user: '',
4318
- messageId: 0,
4319
- route: '',
4320
- client: 'ResolveIO',
4321
- instance: ResolveIOServer.getInstanceHost(),
4322
- instance_index: process.env.NODE_APP_INSTANCE || '0',
4323
- createdAt: new Date()
4324
- });
4325
- }
4326
-
4327
- if (!this.skipCache) {
4328
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
4329
- }
4330
- }
4331
-
4332
- return res;
4333
- }
4334
- catch (err) {
4335
- console.log(JSON.stringify([new Date(), 'Error Update One (Find One And Update)', this.collectionName, filter, safeOptions, {
4336
- code: err.code,
4337
- codeName: err.codeName,
4338
- message: err.message,
4339
- stack: err.stack
4340
- }], null, 2));
4341
-
4342
- err.message = `Error in Update One (Find One And Update): ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
4343
- throw err;
4344
- }
4345
- finally {
4346
- await monitor.finish();
4347
- }
4348
- }
4349
- else {
4350
- let monitor = MonitorMongo.create('updateOne', this.collectionName, JSON.stringify([filter, update, safeOptions]));
4351
-
4352
- try {
4353
- let res = await this.retryWrite(() => ResolveIOServer.getMainDB().collection(this.collectionName, this.collectionOptions).updateOne(<any>filter, <any>update, options || undefined), options);
4354
- if (!this.skipCache) {
4355
- ResolveIOServer.getMongoManager().invalidateQueryCache(this.collectionName);
4356
- }
4357
- return res;
4358
- }
4359
- catch (err) {
4360
- console.log(JSON.stringify([new Date(), 'Error Update One', this.collectionName, filter, update, safeOptions, {
4361
- code: err.code,
4362
- codeName: err.codeName,
4363
- message: err.message,
4364
- stack: err.stack
4365
- }], null, 2));
4366
-
4367
- err.message = `Error in Update One: ${this.collectionName} => ${err.codeName || 'NoCodeName'} => ${err.message}`;
4368
- throw err;
4369
- }
4370
- finally {
4371
- await monitor.finish();
4372
- }
4373
- }
4374
- }
4375
- }
4376
-
4377
- watchCollection(pipeline = [], options?: ChangeStreamOptions, bypassSession = false): ChangeStream<T> {
4378
- const session = ResolveIOServer.getMongoManager().getSession();
4379
- if (session && !bypassSession && !this.bypassSession) {
4380
- if (!options) {
4381
- options = {session};
4382
- }
4383
- else {
4384
- options.session = session;
4385
- }
4386
- }
4387
-
4388
- let stream = ResolveIOServer.getMainDB().collection<T>(this.collectionName, this.collectionOptions).watch(pipeline, options || undefined);
4389
- return <ChangeStream<T>>stream;
4390
- }
4391
- }
4392
-
4393
- export class MongoManagerUserCollection<T extends CollectionDocument> extends MongoManagerCollection<T> {
4394
- static create(options: MongoManagerCollectionOptions) {
4395
- const mongoManagerCollection = new MongoManagerUserCollection();
4396
- mongoManagerCollection.initialize(options);
4397
- return mongoManagerCollection;
4398
- }
4399
-
4400
- async authenticate(user: UserModel, password: string): Promise<{data: UserModel, error: string}> {
4401
- const attemptsInterval = Math.pow(100, Math.log(user.attempts + 1));
4402
- const calculatedInterval = attemptsInterval < 300000 ? attemptsInterval : 300000;
4403
-
4404
- if (user.last) {
4405
- if (Date.now() - user.last.getTime() < calculatedInterval) {
4406
- user.last = new Date();
4407
- await Users.updateOne({_id: user._id}, {$set: {last: user.last}});
4408
- return {
4409
- data: null,
4410
- error: 'Attempt Too Soon'
4411
- };
4412
- }
4413
- }
4414
- else {
4415
- user.last = new Date();
4416
- }
4417
-
4418
- if (user.attempts >= 5) {
4419
- return {
4420
- data: null,
4421
- error: 'Too Many Attempts'
4422
- };
4423
- }
4424
-
4425
- if (!user.salt) {
4426
- return {
4427
- data: null,
4428
- error: 'No Salt Value Stored'
4429
- };
4430
- }
4431
-
4432
- try {
4433
- let hashBuffer = await pbkdf2Promisified(password, user.salt, {
4434
- iterations: 25000,
4435
- keylen: 512,
4436
- digestAlgorithm: 'sha256'
4437
- });
4438
-
4439
- if (scmp(hashBuffer, Buffer.from(user.hash, 'hex'))) {
4440
- user.last = new Date();
4441
- user.attempts = 0;
4442
- await Users.updateOne({_id: user._id}, {$set: {last: user.last, attempts: user.attempts}});
4443
-
4444
- return {
4445
- data: user,
4446
- error: ''
4447
- };
4448
- }
4449
- else {
4450
- user.last = new Date();
4451
- user.attempts = user.attempts + 1;
4452
- await Users.updateOne({_id: user._id}, {$set: {last: user.last, attempts: user.attempts}});
4453
-
4454
- if (user.attempts >= 5) {
4455
- return {
4456
- data: null,
4457
- error: 'Too Many Attempts'
4458
- };
4459
- }
4460
- else {
4461
- return {
4462
- data: null,
4463
- error: 'Invalid Username And Password'
4464
- };
4465
- }
4466
- }
4467
- }
4468
- catch (err) {
4469
- err.message = `Error in User Authenticate: ${JSON.stringify(user, null, 2)} - ${err.message}`;
4470
- throw err;
4471
- }
4472
- }
4473
-
4474
- serializeUser() {
4475
- return (user, cb) => {
4476
- cb(null, user.username);
4477
- };
4478
- }
4479
-
4480
- deserializeUser() {
4481
- return async (username) => {
4482
- return Users.findOne({username: username});
4483
- };
4484
- }
4485
-
4486
- async setPassword(user: UserModel, password: string) {
4487
- if (!user) {
4488
- throw new Error('Error In User Set Password: No User');
4489
- }
4490
- else if (!password) {
4491
- throw new Error('Error In User Set Password: No Password');
4492
- }
4493
- else {
4494
- let saltBuffer = await randomBytes(32);
4495
- let salt = saltBuffer.toString('hex');
4496
- try {
4497
- let hashRaw = await pbkdf2Promisified(password, salt, {
4498
- iterations: 25000,
4499
- keylen: 512,
4500
- digestAlgorithm: 'sha256'
4501
- });
4502
- let hash = Buffer.from(hashRaw, 'binary').toString('hex');
4503
-
4504
- const res = await Users.updateOne({_id: user._id}, {$set: {hash: hash, salt: salt, services: {}, attempts: 0}});
4505
- await saveCustomerPortalPassword(user, password);
4506
- return res;
4507
- }
4508
- catch (err) {
4509
- err.message = `Error in User Set Password: ${JSON.stringify(user, null, 2)} - ${err.message}`;
4510
- throw err;
4511
- }
4512
- }
4513
- };
4514
-
4515
- async changePassword(user, oldPassword, newPassword) {
4516
- if (!user) {
4517
- throw new Error('Error in User Change Password: Missing User');
4518
- }
4519
- else if (!oldPassword || !newPassword) {
4520
- throw new Error('Error in User Change Password: Missing Password');
4521
- }
4522
- else {
4523
- let authUser = await this.authenticate(user, oldPassword);
4524
-
4525
- if (!authUser['data']) {
4526
- throw authUser['error'];
4527
- }
4528
- else {
4529
- return this.setPassword(user, newPassword);
4530
- }
4531
- }
4532
- }
4533
-
4534
- async register(user, password) {
4535
- if (!user.username) {
4536
- throw new Error('Error in User Register: Missing Username');
4537
- }
4538
- else {
4539
- let dbUser = await Users.findOne({username: user.username});
4540
-
4541
- if (dbUser) {
4542
- throw new Error('Error in User Register: Username Exists');
4543
- }
4544
- else {
4545
- dbUser = await Users.findOne({email: user.email});
4546
-
4547
- if (dbUser) {
4548
- throw new Error('Error in User Register: Email Exists');
4549
- }
4550
- else {
4551
- user.setPassword(password);
4552
- return user;
4553
- }
4554
- }
4555
- }
4556
- }
4557
-
4558
- resetAttempts(user: UserModel) {
4559
- return Users.updateOne({_id: user._id}, {$set: {attempts: 0}});
4560
- }
4561
- }
4562
-
4563
- function pbkdf2(password, salt, options, callback) {
4564
- crypto.pbkdf2(password, salt, options.iterations, options.keylen, options.digestAlgorithm, callback);
4565
- };
4566
-
4567
- function pbkdf2Promisified(password, salt, options): Promise<any> {
4568
- // eslint-disable-next-line no-restricted-syntax
4569
- return new Promise((resolve, reject) => pbkdf2(password, salt, options, (err, hashRaw) => (err ? reject(err) : resolve(hashRaw))));
4570
- }
4571
-
4572
- function randomBytes(saltlen): Promise<Buffer> {
4573
- // eslint-disable-next-line no-restricted-syntax
4574
- return new Promise((resolve, reject) => crypto.randomBytes(saltlen, (err, saltBuffer) => (err ? reject(err) : resolve(saltBuffer))));
4575
- }