@vandenberghinc/volt 1.1.2

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 (451) hide show
  1. package/.vrepo +28 -0
  2. package/.vscode/tasks.json +87 -0
  3. package/README.md +67 -0
  4. package/backend/dist/cjs/blacklist.d.ts +10 -0
  5. package/backend/dist/cjs/blacklist.js +53 -0
  6. package/backend/dist/cjs/cli.d.ts +2 -0
  7. package/backend/dist/cjs/cli.js +263 -0
  8. package/backend/dist/cjs/database.d.ts +364 -0
  9. package/backend/dist/cjs/database.js +1962 -0
  10. package/backend/dist/cjs/endpoint.d.ts +57 -0
  11. package/backend/dist/cjs/endpoint.js +425 -0
  12. package/backend/dist/cjs/file_watcher.d.ts +44 -0
  13. package/backend/dist/cjs/file_watcher.js +348 -0
  14. package/backend/dist/cjs/frontend.d.ts +13 -0
  15. package/backend/dist/cjs/frontend.js +30 -0
  16. package/backend/dist/cjs/image_endpoint.d.ts +24 -0
  17. package/backend/dist/cjs/image_endpoint.js +210 -0
  18. package/backend/dist/cjs/logger.d.ts +5 -0
  19. package/backend/dist/cjs/logger.js +16 -0
  20. package/backend/dist/cjs/meta.d.ts +50 -0
  21. package/backend/dist/cjs/meta.js +153 -0
  22. package/backend/dist/cjs/mutex.d.ts +24 -0
  23. package/backend/dist/cjs/mutex.js +52 -0
  24. package/backend/dist/cjs/package.json +1 -0
  25. package/backend/dist/cjs/payments/paddle.d.ts +161 -0
  26. package/backend/dist/cjs/payments/paddle.js +2301 -0
  27. package/backend/dist/cjs/plugins/browser.d.ts +36 -0
  28. package/backend/dist/cjs/plugins/browser.js +183 -0
  29. package/backend/dist/cjs/plugins/communication.d.ts +70 -0
  30. package/backend/dist/cjs/plugins/communication.js +177 -0
  31. package/backend/dist/cjs/plugins/css.d.ts +10 -0
  32. package/backend/dist/cjs/plugins/css.js +71 -0
  33. package/backend/dist/cjs/plugins/mail.d.ts +277 -0
  34. package/backend/dist/cjs/plugins/mail.js +1419 -0
  35. package/backend/dist/cjs/plugins/pdf.d.ts +757 -0
  36. package/backend/dist/cjs/plugins/pdf.js +1694 -0
  37. package/backend/dist/cjs/plugins/thread_monitor.d.ts +18 -0
  38. package/backend/dist/cjs/plugins/thread_monitor.js +127 -0
  39. package/backend/dist/cjs/plugins/ts/compiler.d.ts +132 -0
  40. package/backend/dist/cjs/plugins/ts/compiler.js +944 -0
  41. package/backend/dist/cjs/plugins/ts/preprocessing.d.ts +14 -0
  42. package/backend/dist/cjs/plugins/ts/preprocessing.js +762 -0
  43. package/backend/dist/cjs/rate_limit.d.ts +65 -0
  44. package/backend/dist/cjs/rate_limit.js +463 -0
  45. package/backend/dist/cjs/request.deprc.d.ts +48 -0
  46. package/backend/dist/cjs/request.deprc.js +572 -0
  47. package/backend/dist/cjs/response.deprc.d.ts +55 -0
  48. package/backend/dist/cjs/response.deprc.js +275 -0
  49. package/backend/dist/cjs/server.d.ts +311 -0
  50. package/backend/dist/cjs/server.js +3475 -0
  51. package/backend/dist/cjs/splash_screen.d.ts +35 -0
  52. package/backend/dist/cjs/splash_screen.js +152 -0
  53. package/backend/dist/cjs/status.d.ts +60 -0
  54. package/backend/dist/cjs/status.js +199 -0
  55. package/backend/dist/cjs/stream.d.ts +75 -0
  56. package/backend/dist/cjs/stream.js +954 -0
  57. package/backend/dist/cjs/users.d.ts +111 -0
  58. package/backend/dist/cjs/users.js +1945 -0
  59. package/backend/dist/cjs/utils.d.ts +27 -0
  60. package/backend/dist/cjs/utils.js +329 -0
  61. package/backend/dist/cjs/view.d.ts +52 -0
  62. package/backend/dist/cjs/view.js +568 -0
  63. package/backend/dist/cjs/vinc.d.ts +2 -0
  64. package/backend/dist/cjs/vinc.dev.d.ts +2 -0
  65. package/backend/dist/cjs/vinc.dev.js +42 -0
  66. package/backend/dist/cjs/vinc.js +42 -0
  67. package/backend/dist/cjs/volt.d.ts +15 -0
  68. package/backend/dist/cjs/volt.js +64 -0
  69. package/backend/dist/css/adyen.css +92 -0
  70. package/backend/dist/css/volt.css +65 -0
  71. package/backend/dist/esm/blacklist.d.ts +10 -0
  72. package/backend/dist/esm/blacklist.js +49 -0
  73. package/backend/dist/esm/cli.d.ts +2 -0
  74. package/backend/dist/esm/cli.js +228 -0
  75. package/backend/dist/esm/database.d.ts +364 -0
  76. package/backend/dist/esm/database.js +1957 -0
  77. package/backend/dist/esm/endpoint.d.ts +57 -0
  78. package/backend/dist/esm/endpoint.js +421 -0
  79. package/backend/dist/esm/file_watcher.d.ts +44 -0
  80. package/backend/dist/esm/file_watcher.js +313 -0
  81. package/backend/dist/esm/frontend.d.ts +13 -0
  82. package/backend/dist/esm/frontend.js +27 -0
  83. package/backend/dist/esm/image_endpoint.d.ts +24 -0
  84. package/backend/dist/esm/image_endpoint.js +206 -0
  85. package/backend/dist/esm/logger.d.ts +5 -0
  86. package/backend/dist/esm/logger.js +13 -0
  87. package/backend/dist/esm/meta.d.ts +50 -0
  88. package/backend/dist/esm/meta.js +149 -0
  89. package/backend/dist/esm/mutex.d.ts +24 -0
  90. package/backend/dist/esm/mutex.js +48 -0
  91. package/backend/dist/esm/payments/paddle.d.ts +161 -0
  92. package/backend/dist/esm/payments/paddle.js +2261 -0
  93. package/backend/dist/esm/plugins/browser.d.ts +36 -0
  94. package/backend/dist/esm/plugins/browser.js +176 -0
  95. package/backend/dist/esm/plugins/communication.d.ts +70 -0
  96. package/backend/dist/esm/plugins/communication.js +169 -0
  97. package/backend/dist/esm/plugins/css.d.ts +10 -0
  98. package/backend/dist/esm/plugins/css.js +64 -0
  99. package/backend/dist/esm/plugins/mail.d.ts +277 -0
  100. package/backend/dist/esm/plugins/mail.js +1403 -0
  101. package/backend/dist/esm/plugins/pdf.d.ts +757 -0
  102. package/backend/dist/esm/plugins/pdf.js +1694 -0
  103. package/backend/dist/esm/plugins/thread_monitor.d.ts +18 -0
  104. package/backend/dist/esm/plugins/thread_monitor.js +120 -0
  105. package/backend/dist/esm/plugins/ts/compiler.d.ts +132 -0
  106. package/backend/dist/esm/plugins/ts/compiler.js +907 -0
  107. package/backend/dist/esm/plugins/ts/preprocessing.d.ts +14 -0
  108. package/backend/dist/esm/plugins/ts/preprocessing.js +724 -0
  109. package/backend/dist/esm/rate_limit.d.ts +65 -0
  110. package/backend/dist/esm/rate_limit.js +425 -0
  111. package/backend/dist/esm/request.deprc.d.ts +48 -0
  112. package/backend/dist/esm/request.deprc.js +572 -0
  113. package/backend/dist/esm/response.deprc.d.ts +55 -0
  114. package/backend/dist/esm/response.deprc.js +275 -0
  115. package/backend/dist/esm/server.d.ts +311 -0
  116. package/backend/dist/esm/server.js +3435 -0
  117. package/backend/dist/esm/splash_screen.d.ts +35 -0
  118. package/backend/dist/esm/splash_screen.js +148 -0
  119. package/backend/dist/esm/status.d.ts +60 -0
  120. package/backend/dist/esm/status.js +196 -0
  121. package/backend/dist/esm/stream.d.ts +75 -0
  122. package/backend/dist/esm/stream.js +947 -0
  123. package/backend/dist/esm/users.d.ts +111 -0
  124. package/backend/dist/esm/users.js +1908 -0
  125. package/backend/dist/esm/utils.d.ts +27 -0
  126. package/backend/dist/esm/utils.js +324 -0
  127. package/backend/dist/esm/view.d.ts +52 -0
  128. package/backend/dist/esm/view.js +561 -0
  129. package/backend/dist/esm/vinc.d.ts +2 -0
  130. package/backend/dist/esm/vinc.dev.d.ts +2 -0
  131. package/backend/dist/esm/vinc.dev.js +6 -0
  132. package/backend/dist/esm/vinc.js +6 -0
  133. package/backend/dist/esm/volt.d.ts +15 -0
  134. package/backend/dist/esm/volt.js +23 -0
  135. package/backend/dist/esm-dev/blacklist.d.ts +10 -0
  136. package/backend/dist/esm-dev/blacklist.js +49 -0
  137. package/backend/dist/esm-dev/cli.d.ts +2 -0
  138. package/backend/dist/esm-dev/cli.js +228 -0
  139. package/backend/dist/esm-dev/database.d.ts +364 -0
  140. package/backend/dist/esm-dev/database.js +1957 -0
  141. package/backend/dist/esm-dev/endpoint.d.ts +57 -0
  142. package/backend/dist/esm-dev/endpoint.js +421 -0
  143. package/backend/dist/esm-dev/file_watcher.d.ts +44 -0
  144. package/backend/dist/esm-dev/file_watcher.js +313 -0
  145. package/backend/dist/esm-dev/frontend.d.ts +13 -0
  146. package/backend/dist/esm-dev/frontend.js +27 -0
  147. package/backend/dist/esm-dev/image_endpoint.d.ts +24 -0
  148. package/backend/dist/esm-dev/image_endpoint.js +206 -0
  149. package/backend/dist/esm-dev/logger.d.ts +5 -0
  150. package/backend/dist/esm-dev/logger.js +13 -0
  151. package/backend/dist/esm-dev/meta.d.ts +50 -0
  152. package/backend/dist/esm-dev/meta.js +149 -0
  153. package/backend/dist/esm-dev/mutex.d.ts +24 -0
  154. package/backend/dist/esm-dev/mutex.js +48 -0
  155. package/backend/dist/esm-dev/payments/paddle.d.ts +161 -0
  156. package/backend/dist/esm-dev/payments/paddle.js +2261 -0
  157. package/backend/dist/esm-dev/plugins/browser.d.ts +36 -0
  158. package/backend/dist/esm-dev/plugins/browser.js +176 -0
  159. package/backend/dist/esm-dev/plugins/communication.d.ts +70 -0
  160. package/backend/dist/esm-dev/plugins/communication.js +169 -0
  161. package/backend/dist/esm-dev/plugins/css.d.ts +10 -0
  162. package/backend/dist/esm-dev/plugins/css.js +64 -0
  163. package/backend/dist/esm-dev/plugins/mail.d.ts +277 -0
  164. package/backend/dist/esm-dev/plugins/mail.js +1403 -0
  165. package/backend/dist/esm-dev/plugins/pdf.d.ts +757 -0
  166. package/backend/dist/esm-dev/plugins/pdf.js +1694 -0
  167. package/backend/dist/esm-dev/plugins/thread_monitor.d.ts +18 -0
  168. package/backend/dist/esm-dev/plugins/thread_monitor.js +120 -0
  169. package/backend/dist/esm-dev/plugins/ts/compiler.d.ts +132 -0
  170. package/backend/dist/esm-dev/plugins/ts/compiler.js +907 -0
  171. package/backend/dist/esm-dev/plugins/ts/preprocessing.d.ts +14 -0
  172. package/backend/dist/esm-dev/plugins/ts/preprocessing.js +724 -0
  173. package/backend/dist/esm-dev/rate_limit.d.ts +65 -0
  174. package/backend/dist/esm-dev/rate_limit.js +425 -0
  175. package/backend/dist/esm-dev/request.deprc.d.ts +48 -0
  176. package/backend/dist/esm-dev/request.deprc.js +572 -0
  177. package/backend/dist/esm-dev/response.deprc.d.ts +55 -0
  178. package/backend/dist/esm-dev/response.deprc.js +275 -0
  179. package/backend/dist/esm-dev/server.d.ts +311 -0
  180. package/backend/dist/esm-dev/server.js +3435 -0
  181. package/backend/dist/esm-dev/splash_screen.d.ts +35 -0
  182. package/backend/dist/esm-dev/splash_screen.js +148 -0
  183. package/backend/dist/esm-dev/status.d.ts +60 -0
  184. package/backend/dist/esm-dev/status.js +196 -0
  185. package/backend/dist/esm-dev/stream.d.ts +75 -0
  186. package/backend/dist/esm-dev/stream.js +947 -0
  187. package/backend/dist/esm-dev/users.d.ts +111 -0
  188. package/backend/dist/esm-dev/users.js +1908 -0
  189. package/backend/dist/esm-dev/utils.d.ts +27 -0
  190. package/backend/dist/esm-dev/utils.js +324 -0
  191. package/backend/dist/esm-dev/view.d.ts +52 -0
  192. package/backend/dist/esm-dev/view.js +561 -0
  193. package/backend/dist/esm-dev/vinc.d.ts +2 -0
  194. package/backend/dist/esm-dev/vinc.dev.d.ts +2 -0
  195. package/backend/dist/esm-dev/vinc.dev.js +6 -0
  196. package/backend/dist/esm-dev/vinc.js +6 -0
  197. package/backend/dist/esm-dev/volt.d.ts +15 -0
  198. package/backend/dist/esm-dev/volt.js +23 -0
  199. package/backend/src/blacklist.ts +69 -0
  200. package/backend/src/cli.js +245 -0
  201. package/backend/src/database.ts +2241 -0
  202. package/backend/src/endpoint.ts +494 -0
  203. package/backend/src/file_watcher.ts +359 -0
  204. package/backend/src/frontend.ts +35 -0
  205. package/backend/src/globals.d.ts +8 -0
  206. package/backend/src/image_endpoint.ts +258 -0
  207. package/backend/src/logger.ts +18 -0
  208. package/backend/src/meta.ts +202 -0
  209. package/backend/src/mutex.ts +51 -0
  210. package/backend/src/payments/paddle.ts +2659 -0
  211. package/backend/src/plugins/browser.ts +188 -0
  212. package/backend/src/plugins/communication.ts +204 -0
  213. package/backend/src/plugins/css.ts +84 -0
  214. package/backend/src/plugins/fonts/Menlo-Bold.ttf +0 -0
  215. package/backend/src/plugins/fonts/Menlo-Regular.ttf +0 -0
  216. package/backend/src/plugins/mail.ts +1720 -0
  217. package/backend/src/plugins/pdf.js +1932 -0
  218. package/backend/src/plugins/thread_monitor.ts +164 -0
  219. package/backend/src/plugins/ts/compiler.ts +1242 -0
  220. package/backend/src/plugins/ts/preprocessing.ts +812 -0
  221. package/backend/src/rate_limit.ts +503 -0
  222. package/backend/src/request.deprc.js +626 -0
  223. package/backend/src/response.deprc.js +354 -0
  224. package/backend/src/server.ts +4149 -0
  225. package/backend/src/splash_screen.ts +192 -0
  226. package/backend/src/status.ts +199 -0
  227. package/backend/src/stream.ts +1070 -0
  228. package/backend/src/users.ts +2077 -0
  229. package/backend/src/utils.ts +359 -0
  230. package/backend/src/view.ts +655 -0
  231. package/backend/src/vinc.dev.js +6 -0
  232. package/backend/src/vinc.ts +6 -0
  233. package/backend/src/volt.js +25 -0
  234. package/backend/tsconfig.cjs.json +29 -0
  235. package/backend/tsconfig.esm.dev.json +34 -0
  236. package/backend/tsconfig.esm.json +30 -0
  237. package/backend/tsconfig.json +2 -0
  238. package/frontend/compile.js +436 -0
  239. package/frontend/dist/elements/base.d.ts +9891 -0
  240. package/frontend/dist/elements/base.js +8818 -0
  241. package/frontend/dist/elements/module.d.ts +16 -0
  242. package/frontend/dist/elements/module.js +178 -0
  243. package/frontend/dist/modules/array.d.ts +37 -0
  244. package/frontend/dist/modules/array.js +284 -0
  245. package/frontend/dist/modules/auth.d.ts +45 -0
  246. package/frontend/dist/modules/auth.js +138 -0
  247. package/frontend/dist/modules/colors.d.ts +26 -0
  248. package/frontend/dist/modules/colors.js +340 -0
  249. package/frontend/dist/modules/compression.d.ts +6 -0
  250. package/frontend/dist/modules/compression.js +999 -0
  251. package/frontend/dist/modules/cookies.d.ts +17 -0
  252. package/frontend/dist/modules/cookies.js +166 -0
  253. package/frontend/dist/modules/date.d.ts +142 -0
  254. package/frontend/dist/modules/date.js +493 -0
  255. package/frontend/dist/modules/events.d.ts +7 -0
  256. package/frontend/dist/modules/events.js +90 -0
  257. package/frontend/dist/modules/google.d.ts +10 -0
  258. package/frontend/dist/modules/google.js +53 -0
  259. package/frontend/dist/modules/meta.d.ts +9 -0
  260. package/frontend/dist/modules/meta.js +45 -0
  261. package/frontend/dist/modules/mutex.d.ts +8 -0
  262. package/frontend/dist/modules/mutex.js +52 -0
  263. package/frontend/dist/modules/number.d.ts +12 -0
  264. package/frontend/dist/modules/number.js +8 -0
  265. package/frontend/dist/modules/object.d.ts +50 -0
  266. package/frontend/dist/modules/object.js +147 -0
  267. package/frontend/dist/modules/paddle.d.ts +1403 -0
  268. package/frontend/dist/modules/paddle.js +2641 -0
  269. package/frontend/dist/modules/scheme.d.ts +207 -0
  270. package/frontend/dist/modules/scheme.js +649 -0
  271. package/frontend/dist/modules/settings.d.ts +3 -0
  272. package/frontend/dist/modules/settings.js +4 -0
  273. package/frontend/dist/modules/statics.d.ts +4 -0
  274. package/frontend/dist/modules/statics.js +45 -0
  275. package/frontend/dist/modules/string.d.ts +163 -0
  276. package/frontend/dist/modules/string.js +291 -0
  277. package/frontend/dist/modules/support.d.ts +18 -0
  278. package/frontend/dist/modules/support.js +102 -0
  279. package/frontend/dist/modules/themes.d.ts +8 -0
  280. package/frontend/dist/modules/themes.js +17 -0
  281. package/frontend/dist/modules/user.d.ts +58 -0
  282. package/frontend/dist/modules/user.js +279 -0
  283. package/frontend/dist/modules/utils.d.ts +58 -0
  284. package/frontend/dist/modules/utils.js +1159 -0
  285. package/frontend/dist/types/gradient.d.ts +12 -0
  286. package/frontend/dist/types/gradient.js +79 -0
  287. package/frontend/dist/ui/border_button.d.ts +177 -0
  288. package/frontend/dist/ui/border_button.js +235 -0
  289. package/frontend/dist/ui/button.d.ts +42 -0
  290. package/frontend/dist/ui/button.js +114 -0
  291. package/frontend/dist/ui/canvas.d.ts +56 -0
  292. package/frontend/dist/ui/canvas.js +411 -0
  293. package/frontend/dist/ui/checkbox.d.ts +72 -0
  294. package/frontend/dist/ui/checkbox.js +277 -0
  295. package/frontend/dist/ui/code.d.ts +232 -0
  296. package/frontend/dist/ui/code.js +977 -0
  297. package/frontend/dist/ui/color.d.ts +1 -0
  298. package/frontend/dist/ui/color.js +110 -0
  299. package/frontend/dist/ui/context_menu.d.ts +30 -0
  300. package/frontend/dist/ui/context_menu.js +211 -0
  301. package/frontend/dist/ui/css.d.ts +10 -0
  302. package/frontend/dist/ui/css.js +44 -0
  303. package/frontend/dist/ui/divider.d.ts +18 -0
  304. package/frontend/dist/ui/divider.js +82 -0
  305. package/frontend/dist/ui/dropdown.d.ts +115 -0
  306. package/frontend/dist/ui/dropdown.js +446 -0
  307. package/frontend/dist/ui/for_each.d.ts +38 -0
  308. package/frontend/dist/ui/for_each.js +97 -0
  309. package/frontend/dist/ui/form.d.ts +25 -0
  310. package/frontend/dist/ui/form.js +227 -0
  311. package/frontend/dist/ui/frame_modes.d.ts +28 -0
  312. package/frontend/dist/ui/frame_modes.js +116 -0
  313. package/frontend/dist/ui/google_map.d.ts +31 -0
  314. package/frontend/dist/ui/google_map.js +111 -0
  315. package/frontend/dist/ui/gradient.d.ts +24 -0
  316. package/frontend/dist/ui/gradient.js +115 -0
  317. package/frontend/dist/ui/image.d.ts +138 -0
  318. package/frontend/dist/ui/image.js +570 -0
  319. package/frontend/dist/ui/input.d.ts +316 -0
  320. package/frontend/dist/ui/input.js +1187 -0
  321. package/frontend/dist/ui/link.d.ts +39 -0
  322. package/frontend/dist/ui/link.js +146 -0
  323. package/frontend/dist/ui/list.d.ts +33 -0
  324. package/frontend/dist/ui/list.js +161 -0
  325. package/frontend/dist/ui/loader_button.d.ts +108 -0
  326. package/frontend/dist/ui/loader_button.js +207 -0
  327. package/frontend/dist/ui/loaders.d.ts +60 -0
  328. package/frontend/dist/ui/loaders.js +150 -0
  329. package/frontend/dist/ui/popup.d.ts +84 -0
  330. package/frontend/dist/ui/popup.js +331 -0
  331. package/frontend/dist/ui/pseudo.d.ts +16 -0
  332. package/frontend/dist/ui/pseudo.js +81 -0
  333. package/frontend/dist/ui/scroller.d.ts +131 -0
  334. package/frontend/dist/ui/scroller.js +1251 -0
  335. package/frontend/dist/ui/slider.d.ts +35 -0
  336. package/frontend/dist/ui/slider.js +203 -0
  337. package/frontend/dist/ui/spacer.d.ts +20 -0
  338. package/frontend/dist/ui/spacer.js +83 -0
  339. package/frontend/dist/ui/span.d.ts +11 -0
  340. package/frontend/dist/ui/span.js +75 -0
  341. package/frontend/dist/ui/stack.d.ts +123 -0
  342. package/frontend/dist/ui/stack.js +344 -0
  343. package/frontend/dist/ui/steps.d.ts +72 -0
  344. package/frontend/dist/ui/steps.js +306 -0
  345. package/frontend/dist/ui/style.d.ts +12 -0
  346. package/frontend/dist/ui/style.js +78 -0
  347. package/frontend/dist/ui/switch.d.ts +44 -0
  348. package/frontend/dist/ui/switch.js +280 -0
  349. package/frontend/dist/ui/table.d.ts +118 -0
  350. package/frontend/dist/ui/table.js +411 -0
  351. package/frontend/dist/ui/tabs.d.ts +85 -0
  352. package/frontend/dist/ui/tabs.js +392 -0
  353. package/frontend/dist/ui/text.d.ts +19 -0
  354. package/frontend/dist/ui/text.js +88 -0
  355. package/frontend/dist/ui/theme.d.ts +25 -0
  356. package/frontend/dist/ui/theme.js +237 -0
  357. package/frontend/dist/ui/title.d.ts +36 -0
  358. package/frontend/dist/ui/title.js +127 -0
  359. package/frontend/dist/ui/ui.d.ts +38 -0
  360. package/frontend/dist/ui/ui.js +41 -0
  361. package/frontend/dist/ui/view.d.ts +25 -0
  362. package/frontend/dist/ui/view.js +93 -0
  363. package/frontend/dist/volt.d.ts +22 -0
  364. package/frontend/dist/volt.js +27 -0
  365. package/frontend/exports.json +1340 -0
  366. package/frontend/src/css/adyen.css +92 -0
  367. package/frontend/src/css/volt.css +65 -0
  368. package/frontend/src/elements/base.ts +16790 -0
  369. package/frontend/src/elements/module.ts +184 -0
  370. package/frontend/src/elements/types.d.ts +155 -0
  371. package/frontend/src/modules/array.ts +366 -0
  372. package/frontend/src/modules/auth.ts +188 -0
  373. package/frontend/src/modules/colors.ts +449 -0
  374. package/frontend/src/modules/compression.ts +67 -0
  375. package/frontend/src/modules/cookies.ts +182 -0
  376. package/frontend/src/modules/date.js +535 -0
  377. package/frontend/src/modules/date.ts +583 -0
  378. package/frontend/src/modules/events.ts +96 -0
  379. package/frontend/src/modules/google.ts +60 -0
  380. package/frontend/src/modules/meta.ts +59 -0
  381. package/frontend/src/modules/mutex.ts +59 -0
  382. package/frontend/src/modules/number.ts +20 -0
  383. package/frontend/src/modules/object.ts +212 -0
  384. package/frontend/src/modules/paddle.ts +2990 -0
  385. package/frontend/src/modules/scheme.ts +740 -0
  386. package/frontend/src/modules/settings.ts +5 -0
  387. package/frontend/src/modules/statics.ts +47 -0
  388. package/frontend/src/modules/string.ts +500 -0
  389. package/frontend/src/modules/support.ts +118 -0
  390. package/frontend/src/modules/themes.ts +24 -0
  391. package/frontend/src/modules/user.ts +321 -0
  392. package/frontend/src/modules/utils.ts +1260 -0
  393. package/frontend/src/static/admin/admin.png +0 -0
  394. package/frontend/src/static/admin/password.webp +0 -0
  395. package/frontend/src/static/icons/copy.webp +0 -0
  396. package/frontend/src/static/payments/arrow.long.webp +0 -0
  397. package/frontend/src/static/payments/arrow.long2.webp +0 -0
  398. package/frontend/src/static/payments/cancelled.webp +0 -0
  399. package/frontend/src/static/payments/check.sign.webp +0 -0
  400. package/frontend/src/static/payments/check.webp +0 -0
  401. package/frontend/src/static/payments/close.webp +0 -0
  402. package/frontend/src/static/payments/error.webp +0 -0
  403. package/frontend/src/static/payments/exclamation.webp +0 -0
  404. package/frontend/src/static/payments/minus.webp +0 -0
  405. package/frontend/src/static/payments/party.webp +0 -0
  406. package/frontend/src/static/payments/plus.webp +0 -0
  407. package/frontend/src/static/payments/shopping_cart.webp +0 -0
  408. package/frontend/src/static/payments/trash.webp +0 -0
  409. package/frontend/src/types/global.d.ts +4 -0
  410. package/frontend/src/types/gradient.ts +87 -0
  411. package/frontend/src/ui/any_element.d.ts +5 -0
  412. package/frontend/src/ui/border_button.ts +320 -0
  413. package/frontend/src/ui/button.ts +62 -0
  414. package/frontend/src/ui/canvas.ts +431 -0
  415. package/frontend/src/ui/checkbox.ts +284 -0
  416. package/frontend/src/ui/code.ts +1049 -0
  417. package/frontend/src/ui/color.ts +117 -0
  418. package/frontend/src/ui/context_menu.ts +194 -0
  419. package/frontend/src/ui/css.ts +57 -0
  420. package/frontend/src/ui/divider.ts +28 -0
  421. package/frontend/src/ui/dropdown.ts +503 -0
  422. package/frontend/src/ui/for_each.ts +71 -0
  423. package/frontend/src/ui/form.ts +208 -0
  424. package/frontend/src/ui/frame_modes.ts +140 -0
  425. package/frontend/src/ui/google_map.ts +70 -0
  426. package/frontend/src/ui/gradient.ts +73 -0
  427. package/frontend/src/ui/image.ts +587 -0
  428. package/frontend/src/ui/input.ts +1284 -0
  429. package/frontend/src/ui/link.ts +77 -0
  430. package/frontend/src/ui/list.ts +88 -0
  431. package/frontend/src/ui/loader_button.ts +192 -0
  432. package/frontend/src/ui/loaders.ts +126 -0
  433. package/frontend/src/ui/popup.ts +370 -0
  434. package/frontend/src/ui/pseudo.ts +33 -0
  435. package/frontend/src/ui/scroller.ts +1324 -0
  436. package/frontend/src/ui/slider.ts +215 -0
  437. package/frontend/src/ui/spacer.ts +29 -0
  438. package/frontend/src/ui/span.ts +23 -0
  439. package/frontend/src/ui/stack.ts +238 -0
  440. package/frontend/src/ui/steps.ts +334 -0
  441. package/frontend/src/ui/style.ts +26 -0
  442. package/frontend/src/ui/switch.ts +286 -0
  443. package/frontend/src/ui/table.ts +323 -0
  444. package/frontend/src/ui/tabs.ts +441 -0
  445. package/frontend/src/ui/text.ts +38 -0
  446. package/frontend/src/ui/theme.ts +279 -0
  447. package/frontend/src/ui/title.ts +64 -0
  448. package/frontend/src/ui/ui.ts +47 -0
  449. package/frontend/src/ui/view.ts +44 -0
  450. package/frontend/src/volt.ts +31 -0
  451. package/package.json +58 -0
@@ -0,0 +1,1957 @@
1
+ /*
2
+ * Author: Daan van den Bergh
3
+ * Copyright: © 2022 - 2024 Daan van den Bergh.
4
+ */
5
+ // ---------------------------------------------------------
6
+ // Libraries.
7
+ import { spawn } from "child_process";
8
+ import { deserialize, serialize } from "bson";
9
+ import { MongoClient } from 'mongodb';
10
+ import { logger, LogSource } from "./logger.js";
11
+ import { vlib } from "/Users/administrator/persistance/private/dev/vinc/volt/backend/./src/vinc.dev.js";
12
+ const log_source = new LogSource("Database");
13
+ // ---------------------------------------------------------
14
+ // Collection.
15
+ // Path based collection, so "myfile", "mydir/myfile".
16
+ // @warning: The "path" param must always be allowed to be an object or string, also for the UIDCollection class.
17
+ // @warning: THE DATABASE COLLECTION SHOULD ALSO ACCEPT OBJECTS FOR PATHS.
18
+ /* @docs:
19
+ @nav: Backend
20
+ @chapter: Database
21
+ @title: Collection
22
+ @desc: The database collection class.
23
+ @note: The document attribute `_path` is a reserved index attribute for the path of the document.
24
+ @attribute:
25
+ @name: col
26
+ @desc: The native mongodb collection.
27
+ */
28
+ class Collection {
29
+ // Static attributes.
30
+ static chunk_size = 1024 * 1024 * 4; // 4MB chunks, lower is better for frequent updates.
31
+ static constructor_scheme = {
32
+ name: "string",
33
+ uid_based: "boolean",
34
+ ttl: { type: "number", default: null },
35
+ indexes: {
36
+ type: "array",
37
+ default: [],
38
+ value_scheme: {
39
+ type: ["string", "object"],
40
+ scheme: {
41
+ key: { type: "string", required: (data) => data.key == null && data.keys == null },
42
+ keys: {
43
+ type: ["string", "array"],
44
+ required: (data) => data.key == null && data.keys == null, value_scheme: "string",
45
+ postprocess: (keys) => typeof keys === "string" ? [keys] : keys,
46
+ },
47
+ options: { type: "object", required: false },
48
+ commit_quorom: { type: "object", required: false },
49
+ forced: { type: "boolean", default: false },
50
+ },
51
+ postprocess: (info) => {
52
+ if (typeof info === "string")
53
+ return { keys: [info] };
54
+ if (typeof info === "object" && info.key) {
55
+ info.keys = info.key;
56
+ delete info.key;
57
+ return info;
58
+ }
59
+ return info;
60
+ },
61
+ },
62
+ },
63
+ };
64
+ // Instance attributes
65
+ col;
66
+ name;
67
+ uid_based;
68
+ ttl;
69
+ ttl_enabled;
70
+ constructor(name, collection, ttl = null, indexes = [], uid_based = false) {
71
+ // Verify scheme.
72
+ ({ indexes, ttl } = vlib.Scheme.verify({
73
+ object: {
74
+ name,
75
+ indexes,
76
+ ttl,
77
+ uid_based,
78
+ },
79
+ check_unknown: true,
80
+ scheme: Collection.constructor_scheme,
81
+ }));
82
+ // Attributes.
83
+ this.name = name;
84
+ this.col = collection;
85
+ this.uid_based = uid_based;
86
+ this.ttl = ttl;
87
+ this.ttl_enabled = typeof ttl === "number";
88
+ // Create default indexes.
89
+ if (uid_based) {
90
+ this.col.createIndex({ _path: 1, _uid: 1 });
91
+ }
92
+ else {
93
+ this.col.createIndex({ _path: 1 });
94
+ }
95
+ // Create ttl index.
96
+ if (this.ttl_enabled) {
97
+ this.col.dropIndex("_ttl_timestamp_1")
98
+ .catch(err => {
99
+ if (err.codeName !== 'IndexNotFound') {
100
+ throw err;
101
+ }
102
+ })
103
+ .then(() => {
104
+ this.col.createIndex({ _ttl_timestamp: 1 }, { expireAfterSeconds: parseInt(String(this.ttl / 1000)) });
105
+ });
106
+ }
107
+ // Create indexes.
108
+ if (Array.isArray(indexes) && indexes.length > 0) {
109
+ for (const index of indexes) {
110
+ this.create_index({
111
+ keys: index.keys,
112
+ options: index.options,
113
+ commit_quorum: index.commit_quorum,
114
+ forced: index.forced,
115
+ });
116
+ }
117
+ }
118
+ }
119
+ // Handle file response.
120
+ _process_doc(doc) {
121
+ if (doc == null) {
122
+ return null;
123
+ }
124
+ else if (doc._content != null) {
125
+ return doc._content;
126
+ }
127
+ return doc;
128
+ }
129
+ // Chunked methods.
130
+ async _load_chunked(path, find_opts) {
131
+ let query = typeof path === "string" ?
132
+ { _path: path, chunk: { $gte: 0 } } :
133
+ { ...path, chunk: { $gte: 0 } };
134
+ const chunks_cursor = this.col.find(query, find_opts).sort({ chunk: 1 });
135
+ const chunks = await chunks_cursor.toArray();
136
+ if (chunks.length === 0) {
137
+ return null;
138
+ }
139
+ const buffer = Buffer.concat(chunks.map(chunk => chunk.data.buffer));
140
+ return deserialize(buffer);
141
+ }
142
+ async _save_chunked(path, content) {
143
+ // Serialize.
144
+ const buffer = serialize(content);
145
+ const new_chunk_count = Math.ceil(buffer.length / Collection.chunk_size);
146
+ // Retrieve the old chunk count
147
+ const ref_query = typeof path === "string" ?
148
+ { _path: path, chunk: -1 } :
149
+ { ...path, chunk: -1 };
150
+ const object_ref = await this.col.findOne(ref_query);
151
+ const old_chunk_count = object_ref ? object_ref.chunks : 0;
152
+ // Update chunks.
153
+ const bulk_ops = [];
154
+ for (let i = 0; i < buffer.length; i += Collection.chunk_size) {
155
+ let query, update;
156
+ if (typeof path === "string") {
157
+ query = {
158
+ _path: path,
159
+ chunk: i / Collection.chunk_size,
160
+ };
161
+ update = {
162
+ chunk: i / Collection.chunk_size,
163
+ data: buffer.slice(i, i + Collection.chunk_size)
164
+ };
165
+ }
166
+ else {
167
+ query = {
168
+ ...path,
169
+ chunk: i / Collection.chunk_size,
170
+ };
171
+ update = {
172
+ chunk: i / Collection.chunk_size,
173
+ data: buffer.slice(i, i + Collection.chunk_size)
174
+ };
175
+ }
176
+ const full_update = {
177
+ $set: update,
178
+ };
179
+ if (this.ttl_enabled) {
180
+ full_update["$setOnInsert"] = { _ttl_timestamp: new Date() };
181
+ }
182
+ bulk_ops.push({
183
+ updateOne: {
184
+ filter: query,
185
+ update: full_update,
186
+ upsert: true
187
+ }
188
+ });
189
+ }
190
+ // Update reference.
191
+ const full_update = {
192
+ $set: {
193
+ chunk: -1,
194
+ chunks: new_chunk_count,
195
+ },
196
+ };
197
+ if (this.ttl_enabled) {
198
+ full_update["$setOnInsert"] = { _ttl_timestamp: new Date() };
199
+ }
200
+ bulk_ops.push({
201
+ updateOne: {
202
+ filter: ref_query,
203
+ update: full_update,
204
+ upsert: true
205
+ }
206
+ });
207
+ // Write.
208
+ await this.col.bulkWrite(bulk_ops, { ordered: true });
209
+ // Delete any excess chunks if the new chunk count is less than the old chunk count
210
+ if (new_chunk_count < old_chunk_count) {
211
+ ref_query.chunk = { $gte: new_chunk_count };
212
+ await this.col.deleteMany(ref_query);
213
+ }
214
+ }
215
+ /* @docs:
216
+ @title: Create index
217
+ @description: Creates indexes on collections.
218
+ @return:
219
+ Returns the document that was found or `null` when no document is found.
220
+ @parameter:
221
+ @name: keys
222
+ @desc: The `keys` argument for the orignal mongodb `createIndex()` function.
223
+ @parameter:
224
+ @name: options
225
+ @desc: The `options` argument for the orignal mongodb `createIndex()` function.
226
+ @parameter:
227
+ @name: commitQuorum
228
+ @desc: The `commitQuorum` argument for the orignal mongodb `createIndex()` function.
229
+ */
230
+ async create_index({ keys, options = null, commit_quorum = null, forced = false }) {
231
+ let keys_obj = {};
232
+ if (typeof keys === "string") {
233
+ keys_obj = {};
234
+ keys_obj[keys] = 1;
235
+ }
236
+ else if (Array.isArray(keys)) {
237
+ keys_obj = {};
238
+ for (const key of keys) {
239
+ keys_obj[key] = 1;
240
+ }
241
+ }
242
+ else if (keys == null || typeof keys !== "object") {
243
+ vlib.Scheme.throw_invalid_type("keys", keys, ["string", "string[]", "object"], true);
244
+ }
245
+ else {
246
+ keys_obj = keys;
247
+ }
248
+ // Drop index.
249
+ if (forced) {
250
+ try {
251
+ await this.col.dropIndex(options?.name ??
252
+ Object.entries(keys_obj)
253
+ .map(([key, value]) => `${key}_${value}`)
254
+ .join('_'));
255
+ }
256
+ catch (err) {
257
+ if (err.codeName !== 'IndexNotFound') {
258
+ throw err;
259
+ }
260
+ }
261
+ }
262
+ // Create index.
263
+ // @ts-ignore
264
+ return await this.col.createIndex(keys_obj, options || {}, commit_quorum);
265
+ }
266
+ /* @docs:
267
+ * @title: Find
268
+ * @description: Find a document by a query.
269
+ * @return:
270
+ * Returns the document that was found or `null` when no document is found.
271
+ * @parameter:
272
+ * @name: query
273
+ * @desc: The query options.
274
+ * @type: object
275
+ */
276
+ async find(query) {
277
+ try {
278
+ return this._process_doc(await this.col.findOne(query));
279
+ }
280
+ catch (error) {
281
+ console.error(error);
282
+ throw new Error('Encountered an error while finding the document.');
283
+ }
284
+ }
285
+ /* @docs:
286
+ * @title: Exists
287
+ * @description: Check if a document exists.
288
+ * @parameter:
289
+ * @name: path
290
+ * @description: The database path to the document.
291
+ * @type: string
292
+ */
293
+ async exists(path) {
294
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
295
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
296
+ }
297
+ try {
298
+ const doc = await this.col.findOne(typeof path === "object" ? path : { _path: path }, { projection: { _id: 1 } });
299
+ return doc != null;
300
+ }
301
+ catch (error) {
302
+ console.error(error);
303
+ throw new Error('Encountered an error while checking if the document exists.');
304
+ }
305
+ }
306
+ /* @docs:
307
+ * @title: Load
308
+ * @description: Load data by path.
309
+ * @return:
310
+ * Returns the loaded document.
311
+ *
312
+ * Returns the `def` parameter when the data does not exist, keep in mind that when parameter `def` is an object it could be a reference to a defined variable.
313
+ * @parameter:
314
+ * @name: path
315
+ * @description: The database path to the document.
316
+ * @type: string
317
+ * @parameter:
318
+ * @name: opts
319
+ * @desc: Additional options.
320
+ * @type: null, object
321
+ * @attribute:
322
+ * @name: default
323
+ * @description:
324
+ * The default data to be returned when the data does not exist.
325
+ *
326
+ * When the type of attribute `default` is `object` then the keys that do not exist in the loaded object, but do exist in the default object will be inserted into the loaded object.
327
+ * @type: null, object
328
+ * @attribute:
329
+ * @name: chunked
330
+ * @description: Load a chunked document.
331
+ * @type: null, object
332
+ * @attribute:
333
+ * @name: attributes
334
+ * @description: The attributes to load.
335
+ * @type: null, string[]
336
+ */
337
+ async load(path, opts = null) {
338
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
339
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
340
+ }
341
+ try {
342
+ // Get attributes.
343
+ let find_opts;
344
+ if (opts) {
345
+ if (opts.projection) {
346
+ find_opts = { projection: opts.projection };
347
+ }
348
+ else if (opts.attributes) {
349
+ find_opts = { projection: {
350
+ _id: 1,
351
+ _path: 1,
352
+ _uid: 1,
353
+ } };
354
+ opts.attributes.forEach((i) => {
355
+ if (find_opts?.projection) {
356
+ find_opts.projection[i] = 1;
357
+ }
358
+ });
359
+ }
360
+ }
361
+ // Load doc.
362
+ let doc;
363
+ if (opts != null && opts.chunked === true) {
364
+ doc = await this._load_chunked(path, find_opts);
365
+ }
366
+ else {
367
+ // Load.
368
+ doc = await this.col.findOne(typeof path === "object" ? path : { _path: path }, find_opts);
369
+ this.clean(doc);
370
+ }
371
+ // Process doc.
372
+ doc = this._process_doc(doc);
373
+ // Handle default.
374
+ if (doc == null) {
375
+ if (opts != null && opts.default !== undefined) {
376
+ return opts.default;
377
+ }
378
+ return null;
379
+ }
380
+ // Insert default keys.
381
+ else if (opts != null && typeof opts.default === "object" && opts.default != null && Array.isArray(opts.default) === false) {
382
+ const set_defaults = (obj, defaults) => {
383
+ Object.keys(defaults).forEach((key) => {
384
+ if (obj[key] === undefined) {
385
+ obj[key] = defaults[key];
386
+ }
387
+ else if (typeof obj[key] === "object" && !Array.isArray(obj[key]) && obj[key] != null &&
388
+ typeof defaults[key] === "object" && !Array.isArray(defaults[key]) && defaults[key] != null) {
389
+ set_defaults(obj[key], defaults[key]);
390
+ }
391
+ });
392
+ };
393
+ set_defaults(doc, opts.default);
394
+ }
395
+ // Response.
396
+ return doc;
397
+ }
398
+ catch (error) {
399
+ console.error(error);
400
+ throw new Error('Encountered an error while loading the document.');
401
+ }
402
+ }
403
+ /* @docs:
404
+ * @title: Save
405
+ * @description: Save data by path. When the document already exists this function only updates the specified content attributes.
406
+ * @return:
407
+ * Returns the updated document.
408
+ * @parameter:
409
+ * @name: path
410
+ * @description: The database path to the document.
411
+ * @type: string
412
+ * @parameter:
413
+ * @name: data
414
+ * @description: The data to save.
415
+ * @type: null, boolean, number, string, array, object
416
+ * @parameter:
417
+ * @name: opts
418
+ * @desc: Additional options.
419
+ * @type: null, object
420
+ * @attribute:
421
+ * @name: chunked
422
+ * @description: Chunk the document into multiple documents, therefore documents larger than 16MB are supported.
423
+ * @warning: Currently this option is only supported for types `object` and `array`.
424
+ * @default: false
425
+ * @type: boolean
426
+ * @attribute:
427
+ * @name: bulk
428
+ * @description: Get a bulk operation object, so several operations can be executed in bulk.
429
+ * @default: false
430
+ * @type: boolean
431
+ * @attribute:
432
+ * @name: set
433
+ * @description: By default the $set attribute is used for the content, with `opts.set` disabled you can create your own instructions. The `content` attribute must reflect this.
434
+ * @warning: This does not work in combination with `opts.chunked`.
435
+ * @default: true
436
+ * @type: boolean
437
+ */
438
+ async save(path, content, opts = null) {
439
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
440
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
441
+ }
442
+ try {
443
+ // Vars.
444
+ let doc, set;
445
+ // Create set.
446
+ if (typeof content === "object" && Array.isArray(content) == false && content != null) {
447
+ delete content._id;
448
+ delete content._path;
449
+ delete content._uid;
450
+ delete content._ttl_timestamp;
451
+ set = content;
452
+ }
453
+ else {
454
+ set = { _content: content };
455
+ }
456
+ // Save chunked.
457
+ if (opts != null && opts.chunked === true) {
458
+ await this._save_chunked(path, set);
459
+ }
460
+ // Save as single doc.
461
+ else {
462
+ // Apply $set rules.
463
+ if (opts == null || (opts.set !== false)) {
464
+ set = { $set: set };
465
+ }
466
+ // Apply TTL.
467
+ if (this.ttl_enabled) {
468
+ if (set["$setOnInsert"] === undefined) {
469
+ set["$setOnInsert"] = {};
470
+ set["$setOnInsert"]._ttl_timestamp = new Date();
471
+ }
472
+ else if (set["$setOnInsert"] != null && typeof set["$setOnInsert"] === "object") {
473
+ set["$setOnInsert"]._ttl_timestamp = new Date();
474
+ }
475
+ else {
476
+ throw new Error(`Undefined behaviour: Unable to assign the $setOnInsert data for ttl control.`);
477
+ }
478
+ }
479
+ // Bulk operation.
480
+ if (opts != null && opts.bulk) {
481
+ return {
482
+ updateOne: {
483
+ filter: typeof path === "object" ? path : { _path: path },
484
+ update: set,
485
+ upsert: true,
486
+ }
487
+ };
488
+ }
489
+ // Normal operation.
490
+ else {
491
+ await this.col.updateOne(typeof path === "object" ? path : { _path: path }, set, { upsert: true });
492
+ }
493
+ }
494
+ // Response.
495
+ return content;
496
+ }
497
+ catch (error) {
498
+ console.error(error);
499
+ throw new Error('Encountered an error while updating the document.');
500
+ }
501
+ }
502
+ // List.
503
+ /* @docs:
504
+ * @title: List
505
+ * @description: List all child documents of directory path.
506
+ * @parameter:
507
+ * @name: path
508
+ * @description: The database directory path.
509
+ * @type: string
510
+ * @parameter:
511
+ * @name: options
512
+ * @description: List options.
513
+ * @type: object
514
+ * @attribute:
515
+ * @name: process
516
+ * @description: Process the document. By default saved non object data will be stored under `_content`. Processing checks this attribute and uses that content instead when it is detected.
517
+ * @type: boolean
518
+ * @default: true
519
+ * @attribute:
520
+ * @name: projection
521
+ * @description: The data attributes to retrieve, when left undefined all attributes are retrieved.
522
+ * @type: object
523
+ * @default: undefined
524
+ */
525
+ async list(path, options = {}) {
526
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
527
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
528
+ }
529
+ if (typeof path === "string") {
530
+ while (path.length > 0 && path.charAt(path.length - 1) === "/") {
531
+ path = path.substr(0, path.length - 1);
532
+ }
533
+ if (path.length == 0) {
534
+ throw Error("Invalid path.");
535
+ }
536
+ path = { _path: { $regex: `^${path}/` } };
537
+ }
538
+ else if (path._path) {
539
+ let _path = path._path;
540
+ while (_path.length > 0 && _path.charAt(_path.length - 1) === "/") {
541
+ _path = _path.substr(0, _path.length - 1);
542
+ }
543
+ if (_path.length == 0) {
544
+ throw Error("Invalid path.");
545
+ }
546
+ path._path = { $regex: `^${_path}/` };
547
+ }
548
+ try {
549
+ const docs = await this.col.find(path, { projection: options.projection }).toArray();
550
+ if (options.process === false) {
551
+ return docs;
552
+ }
553
+ return docs.map((doc) => this._process_doc(doc));
554
+ }
555
+ catch (error) {
556
+ console.error(error);
557
+ throw new Error('Encountered an error while listing all documents.');
558
+ }
559
+ }
560
+ /* @docs:
561
+ * @title: List Query
562
+ * @description: List all documents of the collection based on a query.
563
+ * @parameter:
564
+ * @name: query
565
+ * @desc: The query options.
566
+ * @type: object
567
+ * @parameter:
568
+ * @name: options
569
+ * @description: List options.
570
+ * @type: object
571
+ * @attribute:
572
+ * @name: process
573
+ * @description: Process the document. By default saved non object data will be stored under `_content`. Processing checks this attribute and uses that content instead when it is detected.
574
+ * @type: boolean
575
+ * @default: true
576
+ * @attribute:
577
+ * @name: projection
578
+ * @description: The data attributes to retrieve, when left undefined all attributes are retrieved.
579
+ * @type: object
580
+ * @default: undefined
581
+ */
582
+ async list_query(query = {}, options = {}) {
583
+ try {
584
+ const docs = await this.col.find(query, { projection: options.projection }).toArray();
585
+ if (options.process === false) {
586
+ return docs;
587
+ }
588
+ return docs.map((doc) => this._process_doc(doc)); // list as array since the user might have used a path object width different attributes so dict is not reliable.
589
+ }
590
+ catch (error) {
591
+ console.error(error);
592
+ throw new Error('Encountered an error while listing all documents.');
593
+ }
594
+ }
595
+ /* @docs:
596
+ * @title: List All
597
+ * @description: List all documents of the collection, optionally per uid.
598
+ * @parameter:
599
+ * @name: query
600
+ * @ignore: true
601
+ * @parameter:
602
+ * @name: options
603
+ * @description: List options.
604
+ * @type: object
605
+ * @attribute:
606
+ * @name: process
607
+ * @description: Process the document. By default saved non object data will be stored under `_content`. Processing checks this attribute and uses that content instead when it is detected.
608
+ * @type: boolean
609
+ * @default: true
610
+ * @attribute:
611
+ * @name: projection
612
+ * @description: The data attributes to retrieve, when left undefined all attributes are retrieved.
613
+ * @type: object
614
+ * @default: undefined
615
+ */
616
+ async list_all(query = {}, options = {}) {
617
+ let docs;
618
+ if (this.uid_based) {
619
+ docs = await this.col.find(query, { projection: options.projection }).toArray();
620
+ }
621
+ else {
622
+ docs = await this.col.find(query, { projection: options.projection }).toArray();
623
+ }
624
+ if (options.process === false) {
625
+ return docs;
626
+ }
627
+ return docs.map((doc) => this._process_doc(doc)); // list as array since the user might have used a path object width different attributes so dict is not reliable.
628
+ }
629
+ /* @docs:
630
+ * @title: Delete
631
+ * @description: Delete a document of the collection by path.
632
+ * @parameter:
633
+ * @name: path
634
+ * @description: The database path to the document.
635
+ * @type: string
636
+ * @parameter:
637
+ * @name: opts
638
+ * @desc: Additional options.
639
+ * @type: null, object
640
+ * @attribute:
641
+ * @name: chunked
642
+ * @description: Delete a chunked document.
643
+ * @default: false
644
+ * @type: boolean
645
+ * @attribute:
646
+ * @name: bulk
647
+ * @description: Get a bulk operation object, so several operations can be executed in bulk.
648
+ * @default: false
649
+ * @type: boolean
650
+ */
651
+ async delete(path, opts = null) {
652
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
653
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
654
+ }
655
+ try {
656
+ if (opts != null && opts.chunked === true) {
657
+ if (opts.bulk) {
658
+ return { deleteMany: { filter: typeof path === "object" ? path : { _path: path } } };
659
+ }
660
+ else {
661
+ await this.col.deleteMany(typeof path === "object" ? path : { _path: path });
662
+ }
663
+ }
664
+ else {
665
+ if (opts != null && opts.bulk) {
666
+ return { deleteOne: { filter: typeof path === "object" ? path : { _path: path } } };
667
+ }
668
+ else {
669
+ await this.col.deleteOne(typeof path === "object" ? path : { _path: path });
670
+ }
671
+ }
672
+ }
673
+ catch (error) {
674
+ console.error(error);
675
+ throw new Error('Encountered an error while deleting.');
676
+ }
677
+ }
678
+ /* @docs:
679
+ * @title: Delete Query
680
+ * @description: Delete a document of the collection by query.
681
+ * @parameter:
682
+ * @name: query
683
+ * @description: The query object.
684
+ * @type: object
685
+ */
686
+ async delete_query(query = {}) {
687
+ if (typeof query !== "object" || query == null || Object.keys(query).length === 0) {
688
+ throw Error(`Parameter "query" has an invalid type "${typeof query}", the valid type is "object".`);
689
+ }
690
+ if (Object.keys(query).length === 0) {
691
+ throw Error(`Parameter "query" is an empty object.`);
692
+ }
693
+ return await this.col.deleteMany(query);
694
+ }
695
+ // Delete all.
696
+ async delete_all(path) {
697
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
698
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
699
+ }
700
+ try {
701
+ await this.col.deleteMany(typeof path === "object" ? path : { _path: path });
702
+ }
703
+ catch (error) {
704
+ console.error(error);
705
+ throw new Error('Encountered an error while deleting.');
706
+ }
707
+ }
708
+ /* @docs:
709
+ * @title: Delete Collection
710
+ * @description: Delete all documents of from the collection.
711
+ */
712
+ async delete_collection() {
713
+ await this.col.deleteMany();
714
+ await this.col.drop();
715
+ }
716
+ /* @docs:
717
+ * @title: Clean document
718
+ * @description: Clean a document from all default system attributes.
719
+ */
720
+ clean(doc) {
721
+ if (doc == null) {
722
+ return doc;
723
+ }
724
+ if (typeof doc === "object") {
725
+ delete doc._id;
726
+ delete doc._path;
727
+ if (this.uid_based) {
728
+ delete doc._uid;
729
+ }
730
+ if (this.ttl_enabled) {
731
+ delete doc._ttl_timestamp;
732
+ }
733
+ }
734
+ return doc;
735
+ }
736
+ /** Write bulk operations. */
737
+ async bulk_operations(operations = []) {
738
+ return await this.col.bulkWrite(operations, { ordered: true });
739
+ }
740
+ }
741
+ // ---------------------------------------------------------
742
+ // UID based collection.
743
+ // @warning: The "path" param must always be allowed to be an object or string, also for the UIDCollection class.
744
+ // @warning: THE DATABASE COLLECTION SHOULD ALSO ACCEPT OBJECTS FOR PATHS.
745
+ /* @docs:
746
+ @nav: Backend
747
+ @chapter: Database
748
+ @title: UID Collection
749
+ @desc: The UID based database collection class.
750
+ @note: The document attribute `_uid` is a reserved index attribute for the user id of the document.
751
+ @note: The document attribute `_path` is a reserved index attribute for the path of the document.
752
+ @attribute:
753
+ @name: col
754
+ @desc: The native mongodb collection.
755
+ */
756
+ class UIDCollection {
757
+ _col;
758
+ col;
759
+ constructor(name, collection, indexes = [], ttl = null) {
760
+ this._col = new Collection(name, collection, ttl, indexes, true);
761
+ this.col = this._col.col;
762
+ }
763
+ /* @docs:
764
+ @title: Create index
765
+ @description: Creates indexes on collections.
766
+ @return:
767
+ Returns the document that was found or `null` when no document is found.
768
+ @parameter:
769
+ @name: keys
770
+ @desc: The `keys` argument for the orignal mongodb `createIndex()` function.
771
+ @parameter:
772
+ @name: options
773
+ @desc: The `options` argument for the orignal mongodb `createIndex()` function.
774
+ @parameter:
775
+ @name: commitQuorum
776
+ @desc: The `commitQuorum` argument for the orignal mongodb `createIndex()` function.
777
+ */
778
+ async create_index({ keys, options = null, commit_quorum = null }) {
779
+ return this._col.create_index({ keys, options, commit_quorum });
780
+ }
781
+ /* @docs:
782
+ * @title: Find
783
+ * @description: Find a document by a query.
784
+ * @return:
785
+ * Returns the document that was found or `null` when no document is found.
786
+ * @parameter:
787
+ * @name: uid
788
+ * @cached: Users:uid:param
789
+ * @required: false
790
+ * @parameter:
791
+ * @name: query
792
+ * @desc: The query options.
793
+ * @type: object
794
+ */
795
+ async find(uid = null, query = {}) {
796
+ if (uid != null) {
797
+ query._uid = uid;
798
+ }
799
+ return await this._col.find(query);
800
+ }
801
+ /* @docs:
802
+ * @title: Exists
803
+ * @description: Check if a document exists.
804
+ * @parameter:
805
+ * @name: uid
806
+ * @cached: Users:uid:param
807
+ * @parameter:
808
+ * @name: path
809
+ * @description: The database path to the document.
810
+ * @type: string, object
811
+ */
812
+ async exists(uid, path) {
813
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
814
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
815
+ }
816
+ if (typeof uid !== "string") {
817
+ throw Error(`Parameter "uid" has an invalid type "${typeof uid}", the valid type is "string".`);
818
+ }
819
+ if (typeof path === "object") {
820
+ return await this._col.exists({ ...path, _uid: uid });
821
+ }
822
+ else {
823
+ return await this._col.exists({ _path: path, _uid: uid });
824
+ }
825
+ }
826
+ /* @docs:
827
+ * @title: Load
828
+ * @description: Load data by user id and path.
829
+ * @return:
830
+ * Returns the loaded document.
831
+ *
832
+ * Returns the `def` parameter when the data does not exist, keep in mind that when parameter `def` is an object it could be a reference to a defined variable.
833
+ * @parameter:
834
+ * @name: uid
835
+ * @cached: Users:uid:param
836
+ * @parameter:
837
+ * @name: path
838
+ * @description: The database path to the document.
839
+ * @type: string, object
840
+ * @parameter:
841
+ * @name: opts
842
+ * @desc: Additional options.
843
+ * @type: null, object
844
+ * @attribute:
845
+ * @name: default
846
+ * @description:
847
+ * The default data to be returned when the data does not exist.
848
+ *
849
+ * When the type of attribute `default` is `object` then the keys that do not exist in the loaded object, but do exist in the default object will be inserted into the loaded object.
850
+ * @type: null, object
851
+ */
852
+ async load(uid, path, opts = null) {
853
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
854
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
855
+ }
856
+ if (typeof uid !== "string") {
857
+ throw Error(`Parameter "uid" has an invalid type "${typeof uid}", the valid type is "string".`);
858
+ }
859
+ if (typeof path === "object") {
860
+ return await this._col.load({ ...path, _uid: uid }, opts);
861
+ }
862
+ else {
863
+ return await this._col.load({ _path: path, _uid: uid }, opts);
864
+ }
865
+ }
866
+ /* @docs:
867
+ * @title: Save
868
+ * @description: Save data by user id and path. When the document already exists this function only updates the specified content attributes.
869
+ * @return:
870
+ * Returns the updated document.
871
+ * @parameter:
872
+ * @name: uid
873
+ * @cached: Users:uid:param
874
+ * @parameter:
875
+ * @name: path
876
+ * @description: The database path to the document.
877
+ * @type: string, object
878
+ * @parameter:
879
+ * @name: data
880
+ * @description: The data to save.
881
+ * @type: null, boolean, number, string, array, object
882
+ * @parameter:
883
+ * @name: opts
884
+ * @desc: Additional options.
885
+ * @type: null, object
886
+ * @attribute:
887
+ * @name: chunked
888
+ * @description: Chunk the document into multiple documents, therefore documents larger than 16MB are supported.
889
+ * @warning: Currently this option is only supported for types `object` and `array`.
890
+ * @default: false
891
+ * @type: boolean
892
+ * @attribute:
893
+ * @name: bulk
894
+ * @description: Get a bulk operation object, so several operations can be executed in bulk.
895
+ * @default: false
896
+ * @type: boolean
897
+ * @attribute:
898
+ * @name: set
899
+ * @description: By default the $set attribute is used for the content, with `opts.set` disabled you can create your own instructions. The `content` attribute must reflect this.
900
+ * @warning: This does not work in combination with `opts.chunked`.
901
+ * @default: true
902
+ * @type: boolean
903
+ */
904
+ async save(uid, path, content, opts = null) {
905
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
906
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
907
+ }
908
+ if (typeof uid !== "string") {
909
+ throw Error(`Parameter "uid" has an invalid type "${typeof uid}", the valid type is "string".`);
910
+ }
911
+ if (typeof path === "object") {
912
+ return await this._col.save({ ...path, _uid: uid }, content, opts);
913
+ }
914
+ else {
915
+ return await this._col.save({ _path: path, _uid: uid }, content, opts);
916
+ }
917
+ }
918
+ /* @docs:
919
+ * @title: List
920
+ * @description: List all child documents of directory path.
921
+ * @parameter:
922
+ * @name: uid
923
+ * @cached: Users:uid:param
924
+ * @parameter:
925
+ * @name: path
926
+ * @description: The database directory path.
927
+ * @type: string, object
928
+ * @parameter:
929
+ * @name: options
930
+ * @description: List options.
931
+ * @type: object
932
+ * @attribute:
933
+ * @name: process
934
+ * @description: Process the document. By default saved non object data will be stored under `_content`. Processing checks this attribute and uses that content instead when it is detected.
935
+ * @type: boolean
936
+ * @default: true
937
+ * @attribute:
938
+ * @name: projection
939
+ * @description: The data attributes to retrieve, when left undefined all attributes are retrieved.
940
+ * @type: object
941
+ * @default: undefined
942
+ */
943
+ async list(uid, path, options = {}) {
944
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
945
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
946
+ }
947
+ if (typeof uid !== "string") {
948
+ throw Error(`Parameter "uid" has an invalid type "${typeof uid}", the valid type is "string".`);
949
+ }
950
+ if (typeof path === "object") {
951
+ return await this._col.list({ ...path, _uid: uid }, options);
952
+ }
953
+ else {
954
+ return await this._col.list({ _path: path, _uid: uid }, options);
955
+ }
956
+ }
957
+ /* @docs:
958
+ * @title: List Query
959
+ * @description: List all documents of the collection based on a query.
960
+ * @parameter:
961
+ * @name: query
962
+ * @desc: The query options.
963
+ * @type: object
964
+ * @parameter:
965
+ * @name: options
966
+ * @description: List options.
967
+ * @type: object
968
+ * @attribute:
969
+ * @name: process
970
+ * @description: Process the document. By default saved non object data will be stored under `_content`. Processing checks this attribute and uses that content instead when it is detected.
971
+ * @type: boolean
972
+ * @default: true
973
+ * @attribute:
974
+ * @name: projection
975
+ * @description: The data attributes to retrieve, when left undefined all attributes are retrieved.
976
+ * @type: object
977
+ * @default: undefined
978
+ */
979
+ async list_query(query = {}, options = {}) {
980
+ return await this._col.list_query(query, options);
981
+ }
982
+ /* @docs:
983
+ * @title: List All
984
+ * @description: List all documents of the collection, optionally per uid.
985
+ * @parameter:
986
+ * @name: uid
987
+ * @cached: Users:uid:param
988
+ * @parameter:
989
+ * @name: options
990
+ * @description: List options.
991
+ * @type: object
992
+ * @attribute:
993
+ * @name: process
994
+ * @description: Process the document. By default saved non object data will be stored under `_content`. Processing checks this attribute and uses that content instead when it is detected.
995
+ * @type: boolean
996
+ * @default: true
997
+ * @attribute:
998
+ * @name: projection
999
+ * @description: The data attributes to retrieve, when left undefined all attributes are retrieved.
1000
+ * @type: object
1001
+ * @default: undefined
1002
+ */
1003
+ async list_all(uid = null, options = {}) {
1004
+ if (uid == null) {
1005
+ return await this._col.list_all({}, options);
1006
+ }
1007
+ else {
1008
+ return await this._col.list_all({ _uid: uid }, options);
1009
+ }
1010
+ }
1011
+ /* @docs:
1012
+ * @title: Delete
1013
+ * @description: Delete a document of the collection by uid and path.
1014
+ * @parameter:
1015
+ * @name: uid
1016
+ * @cached: Users:uid:param
1017
+ * @parameter:
1018
+ * @name: path
1019
+ * @description: The database path to the document.
1020
+ * @type: string, object
1021
+ * @parameter:
1022
+ * @name: opts
1023
+ * @desc: Additional options.
1024
+ * @type: null, object
1025
+ * @attribute:
1026
+ * @name: chunked
1027
+ * @description: Delete a chunked document.
1028
+ * @default: false
1029
+ * @type: boolean
1030
+ * @attribute:
1031
+ * @name: bulk
1032
+ * @description: Get a bulk operation object, so several operations can be executed in bulk.
1033
+ * @default: false
1034
+ * @type: boolean
1035
+ */
1036
+ async delete(uid, path, opts = null) {
1037
+ if (typeof path !== "string" && (typeof path !== "object" || path == null)) {
1038
+ throw Error(`Parameter "path" has an invalid type "${typeof path}", the valid type is "string".`);
1039
+ }
1040
+ if (typeof uid !== "string") {
1041
+ throw Error(`Parameter "uid" has an invalid type "${typeof uid}", the valid type is "string".`);
1042
+ }
1043
+ if (typeof path === "object") {
1044
+ return await this._col.delete({ ...path, _uid: uid }, opts);
1045
+ }
1046
+ else {
1047
+ return await this._col.delete({ _path: path, _uid: uid }, opts);
1048
+ }
1049
+ }
1050
+ /* @docs:
1051
+ * @title: Delete Query
1052
+ * @description: Delete a document of the collection by query.
1053
+ * @parameter:
1054
+ * @name: query
1055
+ * @description: The query object.
1056
+ * @type: object
1057
+ */
1058
+ async delete_query(query) {
1059
+ if (typeof query !== "object" || query == null || Object.keys(query).length === 0) {
1060
+ throw Error(`Parameter "query" has an invalid type "${typeof query}", the valid type is "object".`);
1061
+ }
1062
+ if (Object.keys(query).length === 0) {
1063
+ throw Error(`Parameter "query" is an empty object.`);
1064
+ }
1065
+ return await this._col.delete_query(query);
1066
+ }
1067
+ // Delete all.
1068
+ async delete_all(uid, path = null) {
1069
+ if (typeof uid !== "string") {
1070
+ throw Error(`Parameter "uid" has an invalid type "${typeof uid}", the valid type is "string".`);
1071
+ }
1072
+ if (path == null) {
1073
+ return await this._col.delete_all({ _uid: uid });
1074
+ }
1075
+ else if (typeof path === "object") {
1076
+ return await this._col.delete_all({ ...path, _uid: uid });
1077
+ }
1078
+ else {
1079
+ return await this._col.delete_all({ _path: path, _uid: uid });
1080
+ }
1081
+ }
1082
+ /* @docs:
1083
+ * @title: Delete Collection
1084
+ * @description: Delete all documents of from the collection.
1085
+ */
1086
+ async delete_collection() {
1087
+ await this._col.delete_collection();
1088
+ }
1089
+ /* @docs:
1090
+ * @title: Clean document
1091
+ * @description: Clean a document from all default system attributes.
1092
+ */
1093
+ clean(doc) {
1094
+ return this._col.clean(doc);
1095
+ }
1096
+ /** Write bulk operations. */
1097
+ async bulk_operations(operations = []) {
1098
+ return await this.col.bulkWrite(operations, { ordered: true });
1099
+ }
1100
+ }
1101
+ // ---------------------------------------------------------
1102
+ // Database.
1103
+ /* @docs:
1104
+ @nav: Backend
1105
+ @chapter: Database
1106
+ @title: Database
1107
+ @desc:
1108
+ The MongoDB database class, accessable under `Server.db`.
1109
+
1110
+ The database class can be utilized in two ways.
1111
+
1112
+ 1. You only provide the `uri` parameter to access an already running mongodb database.
1113
+
1114
+ 2. You provide parameters `config` and `start_args` to start and optionally create the database.
1115
+
1116
+ @warning:
1117
+ Do not forget to enable TLS when using the `config` parameter.
1118
+ @param:
1119
+ @name: uri
1120
+ @desc: The mongodb server uri.
1121
+ @type: string
1122
+ @param:
1123
+ @name: source
1124
+ @desc: The source path of the database directory, by default path `$server_source/.db` will be used.
1125
+ @type: null, string
1126
+ @param:
1127
+ @name: config
1128
+ @desc: The json data for the mongodb config file.
1129
+ @type: null, string
1130
+ @param:
1131
+ @name: start_args
1132
+ @desc: The mongod database start command arguments.
1133
+ @type: null, array[string]
1134
+ @param:
1135
+ @name: client
1136
+ @desc: The MongoClient options.
1137
+ @type: null, object
1138
+ */
1139
+ class Database {
1140
+ static constructor_scheme = {
1141
+ uri: { type: "string", default: null },
1142
+ source: { type: "string", default: null },
1143
+ config: { type: "object", default: {} },
1144
+ start_args: { type: "array", default: [] },
1145
+ client: { type: "object", default: {} },
1146
+ collections: { type: "array", default: [], value_scheme: {
1147
+ type: ["string", "object"],
1148
+ preprocess: (info) => typeof info === "string" ? { name: info } : info,
1149
+ scheme: {
1150
+ name: Collection.constructor_scheme.name,
1151
+ ttl: Collection.constructor_scheme.ttl,
1152
+ indexes: Collection.constructor_scheme.indexes,
1153
+ },
1154
+ } },
1155
+ uid_collections: { type: "array", default: [], value_scheme: {
1156
+ type: ["string", "object"],
1157
+ preprocess: (info) => typeof info === "string" ? { name: info } : info,
1158
+ scheme: {
1159
+ name: Collection.constructor_scheme.name,
1160
+ ttl: Collection.constructor_scheme.ttl,
1161
+ indexes: Collection.constructor_scheme.indexes,
1162
+ },
1163
+ } },
1164
+ preview: { type: "boolean", default: true },
1165
+ preview_ip_whitelist: { type: "array", default: [] },
1166
+ daemon: { type: ["object", "boolean"], default: {} },
1167
+ _server: "object",
1168
+ };
1169
+ uri;
1170
+ preview;
1171
+ preview_ip_whitelist;
1172
+ client_opts;
1173
+ config;
1174
+ source; // Using vlib.Path type
1175
+ start_args;
1176
+ _collections;
1177
+ _uid_collections;
1178
+ server;
1179
+ client;
1180
+ collections;
1181
+ proc;
1182
+ daemon;
1183
+ db;
1184
+ constructor({ uri = null, source = null, config = null, start_args = [], client = null, collections = [], uid_collections = [], preview = true, preview_ip_whitelist = [], daemon = {}, _server, }) {
1185
+ // Checks.
1186
+ if (_server.is_primary && uri == null) {
1187
+ ({ uri, config, start_args, config, client } = vlib.Scheme.verify({
1188
+ object: arguments[0],
1189
+ check_unknown: true,
1190
+ scheme: Database.constructor_scheme
1191
+ }));
1192
+ }
1193
+ // Arguments.
1194
+ this.uri = uri;
1195
+ this.preview = preview;
1196
+ this.preview_ip_whitelist = preview_ip_whitelist;
1197
+ this.client_opts = client;
1198
+ this.config = config || {};
1199
+ this.source = source != null ? new vlib.Path(source) : _server.source.join(".db");
1200
+ this.start_args = start_args;
1201
+ this._collections = collections;
1202
+ this._uid_collections = uid_collections;
1203
+ this.server = _server;
1204
+ // Attributes.
1205
+ this.client = null;
1206
+ this.collections = {};
1207
+ // Initialize the service daemon.
1208
+ if (this.server.daemon && daemon !== false) {
1209
+ const log_source = this.server.source.join(".logs");
1210
+ if (!log_source.exists()) {
1211
+ log_source.mkdir_sync();
1212
+ }
1213
+ this.daemon = new vlib.Daemon({
1214
+ name: this.server.daemon.name + ".mongodb",
1215
+ user: daemon.user || this.server.daemon.user,
1216
+ group: daemon.group || this.server.daemon.group,
1217
+ command: "mongod",
1218
+ cwd: this.server.daemon.cwd,
1219
+ args: ["--config", this.source.join("mongod.json").str(), ...this.start_args],
1220
+ env: daemon.env || this.server.daemon.env,
1221
+ description: daemon.description || `Service daemon for the mongo database of website ${this.server.domain}.`,
1222
+ auto_restart: true,
1223
+ logs: daemon.logs || log_source.join("logs.mongodb").str(),
1224
+ errors: daemon.errors || log_source.join("errors.mongodb").str(),
1225
+ });
1226
+ }
1227
+ }
1228
+ // Database preview.
1229
+ _initialize_db_preview() {
1230
+ /*
1231
+ if (this.preview && this.server.production === false) {
1232
+ this.server.endpoint(
1233
+
1234
+ // Database preview.
1235
+ {
1236
+ method: "GET" ,
1237
+ endpoint: "/volt/db/preview",
1238
+ view: {
1239
+ callback: () => {
1240
+ volt.utils.on_load(async () => {
1241
+
1242
+ // Style theme.
1243
+ const style = {
1244
+ // bg: "#151721",
1245
+ // sub_bg: "#191B28",
1246
+ // tag_bg: "#1C203A",
1247
+ // div_bg: "#282B40",
1248
+ // fg: "#FFFFFF",
1249
+ // sub_fg: "#FFFFFF99",
1250
+ // tag_fg: "#FFFFFF",
1251
+
1252
+ bg: "#F6F8F8",
1253
+ sub_bg: "#FFFFFF",
1254
+ tag_bg: "#F6F8F8",
1255
+ div_bg: "#00000010",
1256
+ fg: "#32334F",
1257
+ sub_fg: "#31344599",
1258
+ tag_fg: "#313445",
1259
+ };
1260
+
1261
+ // List all collections.
1262
+ const collections = (await volt.utils.request({url: "/volt/db/collections"})).collections;
1263
+
1264
+ // Render a list.
1265
+ const prev_lists = [];
1266
+ function RenderList ({
1267
+ title,
1268
+ list,
1269
+ doc = null,
1270
+ add_prev = true,
1271
+ }) {
1272
+ if (add_prev) {
1273
+ prev_lists.append({title, list, doc});
1274
+ }
1275
+
1276
+ // Object view.
1277
+ const obj_view = VStack();
1278
+ const refresh_obj_view = () => {
1279
+ obj_view.inner_html("");
1280
+ let index = 0;
1281
+ obj_view.append(
1282
+ ForEach(list, (key, value) => {
1283
+ ++index;
1284
+ let current_key = key;
1285
+ let value_type = Array.isArray(value) ? "array" : value == null ? "null" : typeof value;
1286
+ if (Array.isArray(value)) {
1287
+ value = JSON.stringify(value, null, 4)
1288
+ }
1289
+
1290
+ // Key input.
1291
+ const key_input = Input("key")
1292
+ .value(key)
1293
+ .font_family("'Menlo', 'Consolas', monospace")
1294
+ .color(style.sub_fg)
1295
+ .font_size(14)
1296
+ .padding(0)
1297
+ .readonly(key === "_path" || key === "_uid" || key === "uid")
1298
+ .on_mouse_over(e => e.color(style.fg))
1299
+ .on_mouse_out(e => e.color(style.sub_fg))
1300
+ .on_render((e) => e.width(e.text_width(key)))
1301
+ .on_input((e) => {
1302
+ if (key != current_key) {
1303
+ list[e.value()] = list[current_key];
1304
+ delete list[current_key];
1305
+ current_key = e.value();
1306
+ }
1307
+ e.width(e.text_width(current_key));
1308
+ });
1309
+
1310
+ // Value input.
1311
+ const value_input = Input("value")
1312
+ .value(value == null ? "null" : value)
1313
+ .font_family("'Menlo', 'Consolas', monospace")
1314
+ .color(style.sub_fg)
1315
+ .display("inline-block")
1316
+ .width("fit-content")
1317
+ .font_size(14)
1318
+ .readonly(key === "_path" || key === "_uid")
1319
+ .stretch(true)
1320
+ .on_mouse_over(e => e.color(style.fg))
1321
+ .on_mouse_out(e => e.color(style.sub_fg))
1322
+ .on_input(() => {
1323
+ clearTimeout(value_input.timeout)
1324
+ value_input.timeout = setTimeout(update_value, 500);
1325
+ })
1326
+
1327
+ // Type select.
1328
+ const type_select = ExtendedSelect({items: ["null", "boolean", "number", "string", "array", "object"]})
1329
+ .center()
1330
+ .margin(0)
1331
+ .max_width(73)
1332
+ .color(style.sub_fg)
1333
+ .font_size(14)
1334
+ .border_radius(10)
1335
+ .background(style.tag_bg)
1336
+ .border_color(style.div_bg)
1337
+ .value(value_type)
1338
+ .container
1339
+ .padding(2.5, 5)
1340
+ .parent();
1341
+
1342
+ // Update the list after edits.
1343
+ const update_value = () => {
1344
+ const type = type_select.value();
1345
+ const value = value_input.value();
1346
+ if (type === "null") {
1347
+ list[current_key] = null;
1348
+ value_input.value(list[current_key].toString());
1349
+ }
1350
+ else if (type === "boolean") {
1351
+ list[current_key] = value == "true" || value == "True" || value == "TRUE" || value == "1";
1352
+ value_input.value(list[current_key].toString());
1353
+ }
1354
+ else if (type === "number") {
1355
+ if (value.indexOf(".") === -1) {
1356
+ list[current_key] = paseInt(value);
1357
+ } else {
1358
+ list[current_key] = paseFloat(value);
1359
+ }
1360
+ if (isNaN(list[key_input.key])) {
1361
+ list[current_key] = 0;
1362
+ }
1363
+ value_input.value(list[current_key].toString());
1364
+ }
1365
+ else if (type === "string") {
1366
+ list[current_key] = value;
1367
+ }
1368
+ else if (type === "object") {
1369
+ list[current_key] = JSON.parse(value);
1370
+ }
1371
+ }
1372
+
1373
+ // Row.
1374
+ const row = HStack(
1375
+ key_input,
1376
+ Text(" : ")
1377
+ .white_space("pre")
1378
+ .font_family("'Menlo', 'Consolas', monospace")
1379
+ .color(style.sub_fg)
1380
+ .font_size(14),
1381
+ value_input,
1382
+ type_select,
1383
+
1384
+ index < Object.keys(list).length ? null : VStack("add")
1385
+ .background(style.tag_bg)
1386
+ .padding(5, 12.5)
1387
+ .border_radius(10)
1388
+ .font_size(13)
1389
+ .color("#3B8553")
1390
+ .margin_left(10)
1391
+ .border(1, style.div_bg)
1392
+ .on_click(() => {
1393
+ list["_new"] = "";
1394
+ refresh_obj_view();
1395
+ }),
1396
+
1397
+ VStack("delete")
1398
+ .background(style.tag_bg)
1399
+ .color("#B2321E")
1400
+ .padding(5, 12.5)
1401
+ .border_radius(10)
1402
+ .font_size(13)
1403
+ .margin_left(10)
1404
+ .border(1, style.div_bg)
1405
+ .on_click(async () => {
1406
+ }),
1407
+ )
1408
+ .center_vertical()
1409
+ .padding(7.5, 0)
1410
+ if (volt.utils.is_obj(value)) {
1411
+ row.on_click(() => RenderList({title: `${title}.${key}`, list: value}));
1412
+ }
1413
+ return [
1414
+ row,
1415
+ Divider().background(style.div_bg),
1416
+ ]
1417
+ })
1418
+ );
1419
+ }
1420
+
1421
+ // Add.
1422
+ preview.inner_html("");
1423
+ preview.append(
1424
+ Scroller(
1425
+ VStack(
1426
+ HStack(
1427
+ Title("Database")
1428
+ .font_family("'Menlo', 'Consolas', monospace")
1429
+ .font_size(12)
1430
+ .color(style.tag_fg)
1431
+ .background(style.tag_bg)
1432
+ .padding(5, 12.5)
1433
+ .border_radius(10)
1434
+ .margin(0, 0, 0, 0)
1435
+ .border(1, style.div_bg)
1436
+ .width("fit-content"),
1437
+
1438
+ Spacer(),
1439
+
1440
+ doc == null ? null : Button("Update")
1441
+ .background(style.tag_bg)
1442
+ .color("#3B8553")
1443
+ .padding(5, 12.5)
1444
+ .margin_right(10)
1445
+ .border_radius(10)
1446
+ .border(1, style.div_bg)
1447
+ .on_click(() => {
1448
+ // --prev_lists.length;
1449
+ // const last = prev_lists[prev_lists.length - 1];
1450
+ // RenderList({...last, add_prev: false})
1451
+ }),
1452
+
1453
+ doc == null ? null : Button("Delete")
1454
+ .background(style.tag_bg)
1455
+ .color("#B2321E")
1456
+ .padding(5, 12.5)
1457
+ .margin_right(10)
1458
+ .border_radius(10)
1459
+ .border(1, style.div_bg)
1460
+ .on_click(async () => {
1461
+ volt.utils.request({
1462
+ method: "DELETE",
1463
+ url: "/volt/db/document",
1464
+ data: doc,
1465
+ })
1466
+ --prev_lists.length;
1467
+ const last = prev_lists[prev_lists.length - 1];
1468
+
1469
+ const __name = doc.uid != null ? `${doc.uid}:${doc.id}` : doc.id
1470
+ const filtered_list = [];
1471
+ last.list.iterate((item) => {
1472
+ if (item.__name !== __name) {
1473
+ filtered_list.append(item);
1474
+ }
1475
+ })
1476
+ last.list = filtered_list;
1477
+ RenderList({...last, add_prev: false})
1478
+ }),
1479
+
1480
+ prev_lists.length == 1 ? null : Button("Prev")
1481
+ .background(style.tag_bg)
1482
+ .color(style.tag_fg)
1483
+ .padding(5, 12.5)
1484
+ .border_radius(10)
1485
+ .border(1, style.div_bg)
1486
+ .on_click(() => {
1487
+ --prev_lists.length;
1488
+ const last = prev_lists[prev_lists.length - 1];
1489
+ RenderList({...last, add_prev: false})
1490
+ }),
1491
+ ),
1492
+
1493
+ Title(title)
1494
+ .font_family("'Menlo', 'Consolas', monospace")
1495
+ .font_size(18)
1496
+ .color(style.fg)
1497
+ .margin(15, 0),
1498
+
1499
+ Divider().background(style.div_bg),
1500
+
1501
+ Array.isArray(list)
1502
+ ? ForEach(list, (item) => {
1503
+ return [
1504
+ VStack(
1505
+ Text(item.__name)
1506
+ .font_family("'Menlo', 'Consolas', monospace")
1507
+ .color(style.sub_fg)
1508
+ .font_size(14)
1509
+ .on_mouse_over(e => e.color(style.fg))
1510
+ .on_mouse_out(e => e.color(style.sub_fg))
1511
+ )
1512
+ .padding(7.5, 0)
1513
+ .on_click(item.__click),
1514
+
1515
+ Divider().background(style.div_bg),
1516
+ ]
1517
+ })
1518
+ : () => {refresh_obj_view(); return obj_view}
1519
+ )
1520
+ .margin(25, 50)
1521
+ .padding(25, 25)
1522
+ .background(style.sub_bg)
1523
+ .border_radius(10)
1524
+ .box_shadow("0px 0px 5px #00000090")
1525
+ )
1526
+ .font_family("Helvetica, sans-serif")
1527
+ .background(style.bg)
1528
+ .frame("100%", "100%")
1529
+ )
1530
+ }
1531
+
1532
+ // Render the collections.
1533
+ const RenderCollections = () => {
1534
+ RenderList({title: "/", list: collections.iterate_append((item) => {
1535
+ return {
1536
+ __name: `${item}/`,
1537
+ __click: () => RenderCollection(item),
1538
+ }
1539
+ })})
1540
+ }
1541
+
1542
+ // Render a collection.
1543
+ const RenderCollection = async (collection) => {
1544
+ const documents = (await volt.utils.request({url: "/volt/db/documents", data: {collection}})).documents;
1545
+ RenderList({title: `${collection}/`, list: documents.iterate_append((item) => {
1546
+ return {
1547
+ __name: item._uid != null ? `${item._uid}:${item._path}` : item._path,
1548
+ __click: () => RenderDocument(collection, item._path, item._uid),
1549
+ }
1550
+ })})
1551
+ }
1552
+
1553
+ // Render a document.
1554
+ const RenderDocument = async (collection, path, uid = null) => {
1555
+ let doc = (await volt.utils.request({url: "/volt/db/document", data: {collection, path, uid}})).document
1556
+ if (Array.isArray(doc)) {
1557
+ doc = {_content: doc};
1558
+ }
1559
+ RenderList({
1560
+ title: uid != null ? `${collection}/${uid}:${path}` : `${collection}/${path}`,
1561
+ list: doc,
1562
+ doc: {collection, uid, path},
1563
+ })
1564
+ }
1565
+
1566
+ // Stack.
1567
+ const preview = VStack()
1568
+ .position(0, 0, 0, 0);
1569
+
1570
+ // Render all collections.
1571
+ RenderCollections();
1572
+
1573
+ // Response.
1574
+ return preview;
1575
+
1576
+ });
1577
+ }
1578
+ }
1579
+ },
1580
+
1581
+ // Get collections.
1582
+ {
1583
+ method: "GET",
1584
+ endpoint: "/volt/db/collections",
1585
+ content_type: "application/json",
1586
+ rate_limit: "global",
1587
+ callback: async (stream) => {
1588
+
1589
+ // Check ip whitelist.
1590
+ if (!this.preview_ip_whitelist.includes(stream.ip)) {
1591
+ return stream.error({status: Status.forbidden});
1592
+ }
1593
+
1594
+ // Sign in.
1595
+ return stream.success({data: {
1596
+ message: "Successfully retrieved all collections.",
1597
+ collections: await this.get_collections(),
1598
+ }});
1599
+ }
1600
+ },
1601
+
1602
+ // Get collection documents.
1603
+ {
1604
+ method: "GET",
1605
+ endpoint: "/volt/db/documents",
1606
+ content_type: "application/json",
1607
+ rate_limit: "global",
1608
+ params: {
1609
+ collection: "string",
1610
+ },
1611
+ callback: async (stream, params) => {
1612
+
1613
+ // Check ip whitelist.
1614
+ if (!this.preview_ip_whitelist.includes(stream.ip)) {
1615
+ return stream.error({status: Status.forbidden});
1616
+ }
1617
+
1618
+ // Check collection.
1619
+ let col;
1620
+ if ((col = this.collections[params.collection]) == null) {
1621
+ return stream.error({data: {error: `Invalid collection "${params.collection}".`}})
1622
+ }
1623
+
1624
+ // Load docs.
1625
+ let docs = await col.list_all();
1626
+
1627
+ // Sign in.
1628
+ return stream.success({data: {
1629
+ message: "Successfully loaded the document.",
1630
+ documents: docs,
1631
+ }});
1632
+ }
1633
+ },
1634
+
1635
+ // Get document.
1636
+ {
1637
+ method: "GET",
1638
+ endpoint: "/volt/db/document",
1639
+ content_type: "application/json",
1640
+ rate_limit: "global",
1641
+ params: {
1642
+ collection: "string",
1643
+ path: ["string", "object"],
1644
+ uid: {type: ["string", "null"], default: null},
1645
+ },
1646
+ callback: async (stream, params) => {
1647
+
1648
+ // Check ip whitelist.
1649
+ if (!this.preview_ip_whitelist.includes(stream.ip)) {
1650
+ return stream.error({status: Status.forbidden});
1651
+ }
1652
+
1653
+ // Check collection.
1654
+ let col;
1655
+ if ((col = this.collections[params.collection]) == null) {
1656
+ return stream.error({data: {error: `Invalid collection "${params.collection}".`}})
1657
+ }
1658
+
1659
+ // Load doc.
1660
+ let doc;
1661
+ if (params.uid == null) {
1662
+ doc = await col.load(params.path);
1663
+ } else {
1664
+ doc = await col.load(params.uid, params.path);
1665
+ }
1666
+
1667
+ // Sign in.
1668
+ return stream.success({data: {
1669
+ message: "Successfully loaded the document.",
1670
+ document: doc,
1671
+ }});
1672
+ }
1673
+ },
1674
+
1675
+ // Delete document.
1676
+ {
1677
+ method: "DELETE",
1678
+ endpoint: "/volt/db/document",
1679
+ content_type: "application/json",
1680
+ rate_limit: "global",
1681
+ params: {
1682
+ collection: "string",
1683
+ path: ["string", "object"],
1684
+ uid: {type: ["string", "null"], default: null},
1685
+ },
1686
+ callback: async (stream, params) => {
1687
+
1688
+ // Check ip whitelist.
1689
+ if (!this.preview_ip_whitelist.includes(stream.ip)) {
1690
+ return stream.error({status: Status.forbidden});
1691
+ }
1692
+
1693
+ // Check collection.
1694
+ let col;
1695
+ if ((col = this.collections[params.collection]) == null) {
1696
+ return stream.error({data: {error: `Invalid collection "${params.collection}".`}})
1697
+ }
1698
+
1699
+ // Load doc.
1700
+ let doc;
1701
+ if (params.uid == null) {
1702
+ doc = await col.delete(params.path);
1703
+ } else {
1704
+ doc = await col.delete(params.uid, params.path);
1705
+ }
1706
+
1707
+ // Sign in.
1708
+ return stream.success({data: {
1709
+ message: "Successfully deleted the document.",
1710
+ }});
1711
+ }
1712
+ },
1713
+
1714
+ // Update document.
1715
+ {
1716
+ method: "PATCH",
1717
+ endpoint: "/volt/db/document",
1718
+ content_type: "application/json",
1719
+ rate_limit: "global",
1720
+ params: {
1721
+ collection: "string",
1722
+ path: ["string", "object"],
1723
+ uid: {type: ["string", "null"], default: null},
1724
+ content: "object",
1725
+ },
1726
+ callback: async (stream, params) => {
1727
+
1728
+ // Check ip whitelist.
1729
+ if (!this.preview_ip_whitelist.includes(stream.ip)) {
1730
+ return stream.error({status: Status.forbidden});
1731
+ }
1732
+
1733
+ // Check collection.
1734
+ let col;
1735
+ if ((col = this.collections[params.collection]) == null) {
1736
+ return stream.error({data: {error: `Invalid collection "${params.collection}".`}})
1737
+ }
1738
+
1739
+ // Load doc.
1740
+ let doc;
1741
+ if (params.uid == null) {
1742
+ doc = await col.save(params.path, params.content);
1743
+ } else {
1744
+ doc = await col.save(params.uid, params.path, params.content);
1745
+ }
1746
+
1747
+ // Sign in.
1748
+ return stream.success({data: {
1749
+ message: "Successfully updated the document.",
1750
+ }});
1751
+ }
1752
+ },
1753
+ )
1754
+ }
1755
+ */
1756
+ }
1757
+ // Connect.
1758
+ async connect() {
1759
+ try {
1760
+ await this.client?.connect();
1761
+ if (this.client) {
1762
+ this.db = this.client.db();
1763
+ }
1764
+ }
1765
+ catch (error) {
1766
+ console.error(error);
1767
+ throw new Error('Error connecting to the database');
1768
+ }
1769
+ }
1770
+ // Initialize.
1771
+ async initialize() {
1772
+ // Set default config.
1773
+ if (this.config.systemLog === undefined) {
1774
+ this.config.systemLog = {};
1775
+ }
1776
+ this.config.systemLog.path = this.source.join("mongod.log").str();
1777
+ if (this.config.systemLog.destination === undefined) {
1778
+ this.config.systemLog.destination = "file";
1779
+ }
1780
+ if (this.config.systemLog.logAppend === undefined) {
1781
+ this.config.systemLog.logAppend = true;
1782
+ }
1783
+ if (this.config.systemLog.logRotate === undefined) {
1784
+ this.config.systemLog.logRotate = "reopen";
1785
+ }
1786
+ if (this.config.systemLog.verbosity === undefined) {
1787
+ this.config.systemLog.verbosity = this.server.production ? 0 : 1;
1788
+ }
1789
+ if (this.config.storage === undefined) {
1790
+ this.config.storage = {};
1791
+ }
1792
+ const db_path = this.source.join("db");
1793
+ this.config.storage.dbPath = db_path.str();
1794
+ if (!db_path.exists()) {
1795
+ db_path.mkdir_sync();
1796
+ }
1797
+ if (this.config.processManagement === undefined) {
1798
+ this.config.processManagement = {};
1799
+ }
1800
+ this.config.processManagement.pidFilePath = this.source.join("mongod.pid").str();
1801
+ if (this.config.net === undefined) {
1802
+ this.config.net = {};
1803
+ }
1804
+ if (this.config.net.port === undefined) {
1805
+ this.config.net.port = 27017;
1806
+ }
1807
+ if (this.config.net.bindIp === undefined) {
1808
+ this.config.net.bindIp = "127.0.0.1";
1809
+ }
1810
+ // Mode 2: Start database.
1811
+ if (this.server.is_primary && this.uri == null) {
1812
+ // Create the database.
1813
+ if (!this.source.exists()) {
1814
+ this.source.mkdir_sync();
1815
+ }
1816
+ // Set the uri.
1817
+ if (this.uri == null) {
1818
+ this.uri = `mongodb://${this.config.net.bindIp}:${this.config.net.port}/main`;
1819
+ }
1820
+ // Save the config.
1821
+ const config_path = this.source.join("mongod.json");
1822
+ config_path.save_sync(JSON.stringify(this.config));
1823
+ // Start the database.
1824
+ this.proc = spawn("mongod", ["--config", config_path.str(), ...this.start_args], {
1825
+ stdio: "pipe",
1826
+ detached: true,
1827
+ env: { ...process.env },
1828
+ });
1829
+ this.proc.stdout?.on('data', (data) => {
1830
+ console.log(data.toString());
1831
+ });
1832
+ this.proc.stderr?.on('data', (data) => {
1833
+ console.error(data.toString());
1834
+ });
1835
+ this.proc.on("error", (code, signal) => {
1836
+ console.error(`MongoDB crashed with error signal ${signal}.`);
1837
+ process.exit(code);
1838
+ });
1839
+ }
1840
+ // Assign URI.
1841
+ else if (!this.server.is_primary && this.uri == null) {
1842
+ this.uri = `mongodb://${this.config.net.bindIp}:${this.config.net.port}/main`;
1843
+ }
1844
+ // Initialize client.
1845
+ if (this.uri) {
1846
+ this.client = new MongoClient(this.uri, this.client_opts || {});
1847
+ }
1848
+ // Connect.
1849
+ await this.connect();
1850
+ // Create collections.
1851
+ this._collections.forEach((info) => {
1852
+ if (this[info.name] !== undefined) {
1853
+ throw Error(`Unable to initialize database collection "${info.name}", this attribute name is already used.`);
1854
+ }
1855
+ if (Array.isArray(info.indexes)) {
1856
+ for (const index of info.indexes) {
1857
+ if (index != null && typeof index === "object") {
1858
+ index.forced = true;
1859
+ }
1860
+ }
1861
+ }
1862
+ this[info.name] = this.create_collection(info);
1863
+ });
1864
+ this._uid_collections.forEach((info) => {
1865
+ if (this[info.name] !== undefined) {
1866
+ throw Error(`Unable to initialize database collection "${info.name}", this attribute name is already used.`);
1867
+ }
1868
+ if (Array.isArray(info.indexes)) {
1869
+ for (const index of info.indexes) {
1870
+ if (index != null && typeof index === "object") {
1871
+ index.forced = true;
1872
+ }
1873
+ }
1874
+ }
1875
+ this[info.name] = this.create_uid_collection(info);
1876
+ });
1877
+ }
1878
+ // Close.
1879
+ async close() {
1880
+ logger.log(0, log_source, "Stopping the database.");
1881
+ await this.client?.close();
1882
+ }
1883
+ /* @docs:
1884
+ * @title: Create Collection
1885
+ * @description: Create a database collection.
1886
+ */
1887
+ create_collection(info) {
1888
+ // Set name by single string argument.
1889
+ let name;
1890
+ let indexes = [];
1891
+ let ttl = null;
1892
+ if (typeof info === "string") {
1893
+ name = info;
1894
+ }
1895
+ else {
1896
+ name = info.name;
1897
+ indexes = info.indexes || [];
1898
+ ttl = info.ttl || null;
1899
+ }
1900
+ // Check collection.
1901
+ if (name in this.collections) {
1902
+ throw Error(`Collection "${name}" is already initialized.`);
1903
+ }
1904
+ const col = new Collection(name, this.db.collection(name), ttl, indexes);
1905
+ this.collections[name] = col;
1906
+ return col;
1907
+ }
1908
+ /* @docs:
1909
+ * @title: Create UID Based Collection
1910
+ * @description: Create a UID based database collection.
1911
+ */
1912
+ create_uid_collection(info) {
1913
+ // Set name by single string argument.
1914
+ let name;
1915
+ let indexes = [];
1916
+ let ttl = null;
1917
+ if (typeof info === "string") {
1918
+ name = info;
1919
+ }
1920
+ else {
1921
+ name = info.name;
1922
+ indexes = info.indexes || [];
1923
+ ttl = info.ttl || null;
1924
+ }
1925
+ // Check collection.
1926
+ if (name in this.collections) {
1927
+ throw Error(`Collection "${name}" is already initialized.`);
1928
+ }
1929
+ const col = new UIDCollection(name, this.db.collection(name), indexes, ttl);
1930
+ this.collections[name] = col;
1931
+ return col;
1932
+ }
1933
+ /* @docs:
1934
+ * @title: Get Collections
1935
+ * @description: Get the names of the initializated database collections.
1936
+ */
1937
+ async get_collections() {
1938
+ const created = Object.keys(this.collections);
1939
+ const database = (await this.db.listCollections().toArray()).map((item) => item.name);
1940
+ return created.concat(database)
1941
+ .filter((value, index, self) => self.indexOf(value) === index)
1942
+ .sort((a, b) => {
1943
+ const result = a.toLowerCase().localeCompare(b.toLowerCase());
1944
+ if (a.startsWith('_') && b.startsWith('_')) {
1945
+ return result;
1946
+ }
1947
+ if (a.startsWith('_')) {
1948
+ return 1;
1949
+ }
1950
+ if (b.startsWith('_')) {
1951
+ return -1;
1952
+ }
1953
+ return result;
1954
+ });
1955
+ }
1956
+ }
1957
+ export { Collection, UIDCollection, Database };