@vandenberghinc/volt 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (489) hide show
  1. package/frontend/assets/admin/admin.png +0 -0
  2. package/frontend/assets/admin/password.webp +0 -0
  3. package/frontend/assets/icons/arrow.v1.webp +0 -0
  4. package/frontend/assets/icons/copy.webp +0 -0
  5. package/frontend/assets/payments/arrow.long.webp +0 -0
  6. package/frontend/assets/payments/arrow.long2.webp +0 -0
  7. package/frontend/assets/payments/cancelled.webp +0 -0
  8. package/frontend/assets/payments/check.sign.webp +0 -0
  9. package/frontend/assets/payments/check.webp +0 -0
  10. package/frontend/assets/payments/close.webp +0 -0
  11. package/frontend/assets/payments/error.webp +0 -0
  12. package/frontend/assets/payments/exclamation.webp +0 -0
  13. package/frontend/assets/payments/minus.webp +0 -0
  14. package/frontend/assets/payments/party.webp +0 -0
  15. package/frontend/assets/payments/plus.webp +0 -0
  16. package/frontend/assets/payments/shopping_cart.webp +0 -0
  17. package/frontend/assets/payments/trash.webp +0 -0
  18. package/package.json +6 -2
  19. package/.libris/config.json +0 -82
  20. package/backend/dist/cjs/backend/src/blacklist.d.ts +0 -12
  21. package/backend/dist/cjs/backend/src/blacklist.js +0 -78
  22. package/backend/dist/cjs/backend/src/cli.d.ts +0 -2
  23. package/backend/dist/cjs/backend/src/cli.js +0 -198
  24. package/backend/dist/cjs/backend/src/database/collection.d.ts +0 -1765
  25. package/backend/dist/cjs/backend/src/database/collection.js +0 -3301
  26. package/backend/dist/cjs/backend/src/database/database.d.ts +0 -92
  27. package/backend/dist/cjs/backend/src/database/database.js +0 -170
  28. package/backend/dist/cjs/backend/src/database/document.d.ts +0 -1
  29. package/backend/dist/cjs/backend/src/database/document.js +0 -15
  30. package/backend/dist/cjs/backend/src/database/filters/filters.d.ts +0 -6
  31. package/backend/dist/cjs/backend/src/database/filters/filters.js +0 -15
  32. package/backend/dist/cjs/backend/src/database/filters/strict_filter.d.ts +0 -223
  33. package/backend/dist/cjs/backend/src/database/filters/strict_filter.js +0 -15
  34. package/backend/dist/cjs/backend/src/database/filters/strict_filter_test.d.ts +0 -1
  35. package/backend/dist/cjs/backend/src/database/filters/strict_filter_test.js +0 -443
  36. package/backend/dist/cjs/backend/src/database/filters/strict_filter_test_v0.d.ts +0 -1
  37. package/backend/dist/cjs/backend/src/database/filters/strict_filter_test_v0.js +0 -15
  38. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v0.d.ts +0 -50
  39. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v0.js +0 -15
  40. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v1.d.ts +0 -76
  41. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v1.js +0 -15
  42. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v2.d.ts +0 -75
  43. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v2.js +0 -15
  44. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v3.d.ts +0 -219
  45. package/backend/dist/cjs/backend/src/database/filters/strict_filter_v3.js +0 -15
  46. package/backend/dist/cjs/backend/src/database/filters/strict_update_filter.d.ts +0 -165
  47. package/backend/dist/cjs/backend/src/database/filters/strict_update_filter.js +0 -15
  48. package/backend/dist/cjs/backend/src/database/filters/strict_update_filter_test.d.ts +0 -5
  49. package/backend/dist/cjs/backend/src/database/filters/strict_update_filter_test.js +0 -355
  50. package/backend/dist/cjs/backend/src/database/flatten.d.ts +0 -78
  51. package/backend/dist/cjs/backend/src/database/flatten.js +0 -53
  52. package/backend/dist/cjs/backend/src/database/flatten_test.d.ts +0 -1
  53. package/backend/dist/cjs/backend/src/database/flatten_test.js +0 -175
  54. package/backend/dist/cjs/backend/src/database/quota/quoata_v2.d.ts +0 -533
  55. package/backend/dist/cjs/backend/src/database/quota/quoata_v2.js +0 -1046
  56. package/backend/dist/cjs/backend/src/database/quota/quota.d.ts +0 -551
  57. package/backend/dist/cjs/backend/src/database/quota/quota.js +0 -1108
  58. package/backend/dist/cjs/backend/src/database/quota/quota_v1.d.ts +0 -534
  59. package/backend/dist/cjs/backend/src/database/quota/quota_v1.js +0 -1087
  60. package/backend/dist/cjs/backend/src/database/quota/safe_int.d.ts +0 -412
  61. package/backend/dist/cjs/backend/src/database/quota/safe_int.js +0 -745
  62. package/backend/dist/cjs/backend/src/endpoint.d.ts +0 -346
  63. package/backend/dist/cjs/backend/src/endpoint.js +0 -468
  64. package/backend/dist/cjs/backend/src/errors/index.d.ts +0 -7
  65. package/backend/dist/cjs/backend/src/errors/index.js +0 -25
  66. package/backend/dist/cjs/backend/src/errors/internal_external.d.ts +0 -52
  67. package/backend/dist/cjs/backend/src/errors/internal_external.js +0 -95
  68. package/backend/dist/cjs/backend/src/errors/invalid_usage_error.d.ts +0 -41
  69. package/backend/dist/cjs/backend/src/errors/invalid_usage_error.js +0 -47
  70. package/backend/dist/cjs/backend/src/errors/system_error.d.ts +0 -261
  71. package/backend/dist/cjs/backend/src/errors/system_error.js +0 -436
  72. package/backend/dist/cjs/backend/src/events.d.ts +0 -97
  73. package/backend/dist/cjs/backend/src/events.js +0 -15
  74. package/backend/dist/cjs/backend/src/frontend.d.ts +0 -11
  75. package/backend/dist/cjs/backend/src/frontend.js +0 -37
  76. package/backend/dist/cjs/backend/src/image_endpoint.d.ts +0 -44
  77. package/backend/dist/cjs/backend/src/image_endpoint.js +0 -185
  78. package/backend/dist/cjs/backend/src/index.d.ts +0 -23
  79. package/backend/dist/cjs/backend/src/index.js +0 -70
  80. package/backend/dist/cjs/backend/src/logger.d.ts +0 -5
  81. package/backend/dist/cjs/backend/src/logger.js +0 -15
  82. package/backend/dist/cjs/backend/src/meta.d.ts +0 -112
  83. package/backend/dist/cjs/backend/src/meta.js +0 -181
  84. package/backend/dist/cjs/backend/src/payments/paddle.d.ts +0 -329
  85. package/backend/dist/cjs/backend/src/payments/paddle.js +0 -1996
  86. package/backend/dist/cjs/backend/src/payments/stripe/checkout.d.ts +0 -113
  87. package/backend/dist/cjs/backend/src/payments/stripe/checkout.js +0 -295
  88. package/backend/dist/cjs/backend/src/payments/stripe/customers.d.ts +0 -17
  89. package/backend/dist/cjs/backend/src/payments/stripe/customers.js +0 -164
  90. package/backend/dist/cjs/backend/src/payments/stripe/error.d.ts +0 -74
  91. package/backend/dist/cjs/backend/src/payments/stripe/error.js +0 -64
  92. package/backend/dist/cjs/backend/src/payments/stripe/events.d.ts +0 -155
  93. package/backend/dist/cjs/backend/src/payments/stripe/events.js +0 -15
  94. package/backend/dist/cjs/backend/src/payments/stripe/meters.d.ts +0 -105
  95. package/backend/dist/cjs/backend/src/payments/stripe/meters.js +0 -230
  96. package/backend/dist/cjs/backend/src/payments/stripe/payment_methods.d.ts +0 -58
  97. package/backend/dist/cjs/backend/src/payments/stripe/payment_methods.js +0 -109
  98. package/backend/dist/cjs/backend/src/payments/stripe/products.d.ts +0 -519
  99. package/backend/dist/cjs/backend/src/payments/stripe/products.js +0 -650
  100. package/backend/dist/cjs/backend/src/payments/stripe/stripe.d.ts +0 -215
  101. package/backend/dist/cjs/backend/src/payments/stripe/stripe.js +0 -468
  102. package/backend/dist/cjs/backend/src/payments/stripe/subscriptions.d.ts +0 -172
  103. package/backend/dist/cjs/backend/src/payments/stripe/subscriptions.js +0 -557
  104. package/backend/dist/cjs/backend/src/payments/stripe/utils.d.ts +0 -63
  105. package/backend/dist/cjs/backend/src/payments/stripe/utils.js +0 -118
  106. package/backend/dist/cjs/backend/src/payments/stripe/webhooks.d.ts +0 -105
  107. package/backend/dist/cjs/backend/src/payments/stripe/webhooks.js +0 -627
  108. package/backend/dist/cjs/backend/src/plugins/browser.d.ts +0 -1
  109. package/backend/dist/cjs/backend/src/plugins/browser.js +0 -15
  110. package/backend/dist/cjs/backend/src/plugins/communication.d.ts +0 -70
  111. package/backend/dist/cjs/backend/src/plugins/communication.js +0 -196
  112. package/backend/dist/cjs/backend/src/plugins/mail/mail.d.ts +0 -255
  113. package/backend/dist/cjs/backend/src/plugins/mail/mail.js +0 -381
  114. package/backend/dist/cjs/backend/src/plugins/mail/ui.d.ts +0 -297
  115. package/backend/dist/cjs/backend/src/plugins/mail/ui.js +0 -1370
  116. package/backend/dist/cjs/backend/src/plugins/pdf.d.ts +0 -1
  117. package/backend/dist/cjs/backend/src/plugins/pdf.js +0 -1456
  118. package/backend/dist/cjs/backend/src/plugins/thread_monitor.d.ts +0 -18
  119. package/backend/dist/cjs/backend/src/plugins/thread_monitor.js +0 -116
  120. package/backend/dist/cjs/backend/src/rate_limit.d.ts +0 -148
  121. package/backend/dist/cjs/backend/src/rate_limit.js +0 -543
  122. package/backend/dist/cjs/backend/src/route.d.ts +0 -39
  123. package/backend/dist/cjs/backend/src/route.js +0 -172
  124. package/backend/dist/cjs/backend/src/server.d.ts +0 -502
  125. package/backend/dist/cjs/backend/src/server.js +0 -1713
  126. package/backend/dist/cjs/backend/src/server.old.d.ts +0 -594
  127. package/backend/dist/cjs/backend/src/server.old.js +0 -2058
  128. package/backend/dist/cjs/backend/src/splash_screen.d.ts +0 -93
  129. package/backend/dist/cjs/backend/src/splash_screen.js +0 -119
  130. package/backend/dist/cjs/backend/src/status.d.ts +0 -89
  131. package/backend/dist/cjs/backend/src/status.js +0 -211
  132. package/backend/dist/cjs/backend/src/stream.d.ts +0 -494
  133. package/backend/dist/cjs/backend/src/stream.js +0 -1370
  134. package/backend/dist/cjs/backend/src/users.d.ts +0 -926
  135. package/backend/dist/cjs/backend/src/users.js +0 -2223
  136. package/backend/dist/cjs/backend/src/utils.d.ts +0 -22
  137. package/backend/dist/cjs/backend/src/utils.js +0 -626
  138. package/backend/dist/cjs/backend/src/view.d.ts +0 -115
  139. package/backend/dist/cjs/backend/src/view.js +0 -519
  140. package/backend/dist/cjs/backend/src/vinc.d.ts +0 -6
  141. package/backend/dist/cjs/backend/src/vinc.js +0 -40
  142. package/backend/dist/cjs/backend/src/volt.d.ts +0 -24
  143. package/backend/dist/cjs/backend/src/volt.js +0 -72
  144. package/backend/dist/cjs/frontend/src/modules/request.d.ts +0 -70
  145. package/backend/dist/cjs/frontend/src/modules/request.js +0 -99
  146. package/backend/dist/cjs/package.json +0 -1
  147. package/backend/dist/esm/backend/src/blacklist.d.ts +0 -12
  148. package/backend/dist/esm/backend/src/blacklist.js +0 -52
  149. package/backend/dist/esm/backend/src/cli.d.ts +0 -2
  150. package/backend/dist/esm/backend/src/cli.js +0 -211
  151. package/backend/dist/esm/backend/src/database/collection.d.ts +0 -1765
  152. package/backend/dist/esm/backend/src/database/collection.js +0 -3779
  153. package/backend/dist/esm/backend/src/database/database.d.ts +0 -92
  154. package/backend/dist/esm/backend/src/database/database.js +0 -214
  155. package/backend/dist/esm/backend/src/database/document.d.ts +0 -1
  156. package/backend/dist/esm/backend/src/database/document.js +0 -558
  157. package/backend/dist/esm/backend/src/database/filters/filters.d.ts +0 -6
  158. package/backend/dist/esm/backend/src/database/filters/filters.js +0 -1
  159. package/backend/dist/esm/backend/src/database/filters/strict_filter.d.ts +0 -223
  160. package/backend/dist/esm/backend/src/database/filters/strict_filter.js +0 -3
  161. package/backend/dist/esm/backend/src/database/filters/strict_filter_test.d.ts +0 -1
  162. package/backend/dist/esm/backend/src/database/filters/strict_filter_test.js +0 -505
  163. package/backend/dist/esm/backend/src/database/filters/strict_filter_test_v0.d.ts +0 -1
  164. package/backend/dist/esm/backend/src/database/filters/strict_filter_test_v0.js +0 -712
  165. package/backend/dist/esm/backend/src/database/filters/strict_filter_v0.d.ts +0 -50
  166. package/backend/dist/esm/backend/src/database/filters/strict_filter_v0.js +0 -5
  167. package/backend/dist/esm/backend/src/database/filters/strict_filter_v1.d.ts +0 -76
  168. package/backend/dist/esm/backend/src/database/filters/strict_filter_v1.js +0 -44
  169. package/backend/dist/esm/backend/src/database/filters/strict_filter_v2.d.ts +0 -75
  170. package/backend/dist/esm/backend/src/database/filters/strict_filter_v2.js +0 -5
  171. package/backend/dist/esm/backend/src/database/filters/strict_filter_v3.d.ts +0 -219
  172. package/backend/dist/esm/backend/src/database/filters/strict_filter_v3.js +0 -1
  173. package/backend/dist/esm/backend/src/database/filters/strict_update_filter.d.ts +0 -165
  174. package/backend/dist/esm/backend/src/database/filters/strict_update_filter.js +0 -5
  175. package/backend/dist/esm/backend/src/database/filters/strict_update_filter_test.d.ts +0 -5
  176. package/backend/dist/esm/backend/src/database/filters/strict_update_filter_test.js +0 -415
  177. package/backend/dist/esm/backend/src/database/flatten.d.ts +0 -78
  178. package/backend/dist/esm/backend/src/database/flatten.js +0 -22
  179. package/backend/dist/esm/backend/src/database/flatten_test.d.ts +0 -1
  180. package/backend/dist/esm/backend/src/database/flatten_test.js +0 -174
  181. package/backend/dist/esm/backend/src/database/quota/quoata_v2.d.ts +0 -533
  182. package/backend/dist/esm/backend/src/database/quota/quoata_v2.js +0 -1155
  183. package/backend/dist/esm/backend/src/database/quota/quota.d.ts +0 -551
  184. package/backend/dist/esm/backend/src/database/quota/quota.js +0 -1219
  185. package/backend/dist/esm/backend/src/database/quota/quota_v1.d.ts +0 -534
  186. package/backend/dist/esm/backend/src/database/quota/quota_v1.js +0 -1242
  187. package/backend/dist/esm/backend/src/database/quota/safe_int.d.ts +0 -412
  188. package/backend/dist/esm/backend/src/database/quota/safe_int.js +0 -810
  189. package/backend/dist/esm/backend/src/endpoint.d.ts +0 -346
  190. package/backend/dist/esm/backend/src/endpoint.js +0 -479
  191. package/backend/dist/esm/backend/src/errors/index.d.ts +0 -7
  192. package/backend/dist/esm/backend/src/errors/index.js +0 -7
  193. package/backend/dist/esm/backend/src/errors/internal_external.d.ts +0 -52
  194. package/backend/dist/esm/backend/src/errors/internal_external.js +0 -86
  195. package/backend/dist/esm/backend/src/errors/invalid_usage_error.d.ts +0 -41
  196. package/backend/dist/esm/backend/src/errors/invalid_usage_error.js +0 -33
  197. package/backend/dist/esm/backend/src/errors/system_error.d.ts +0 -261
  198. package/backend/dist/esm/backend/src/errors/system_error.js +0 -444
  199. package/backend/dist/esm/backend/src/events.d.ts +0 -97
  200. package/backend/dist/esm/backend/src/events.js +0 -5
  201. package/backend/dist/esm/backend/src/frontend.d.ts +0 -11
  202. package/backend/dist/esm/backend/src/frontend.js +0 -12
  203. package/backend/dist/esm/backend/src/image_endpoint.d.ts +0 -44
  204. package/backend/dist/esm/backend/src/image_endpoint.js +0 -196
  205. package/backend/dist/esm/backend/src/index.d.ts +0 -23
  206. package/backend/dist/esm/backend/src/index.js +0 -26
  207. package/backend/dist/esm/backend/src/logger.d.ts +0 -5
  208. package/backend/dist/esm/backend/src/logger.js +0 -8
  209. package/backend/dist/esm/backend/src/meta.d.ts +0 -112
  210. package/backend/dist/esm/backend/src/meta.js +0 -152
  211. package/backend/dist/esm/backend/src/payments/paddle.d.ts +0 -329
  212. package/backend/dist/esm/backend/src/payments/paddle.js +0 -2276
  213. package/backend/dist/esm/backend/src/payments/stripe/checkout.d.ts +0 -113
  214. package/backend/dist/esm/backend/src/payments/stripe/checkout.js +0 -356
  215. package/backend/dist/esm/backend/src/payments/stripe/customers.d.ts +0 -17
  216. package/backend/dist/esm/backend/src/payments/stripe/customers.js +0 -193
  217. package/backend/dist/esm/backend/src/payments/stripe/error.d.ts +0 -74
  218. package/backend/dist/esm/backend/src/payments/stripe/error.js +0 -51
  219. package/backend/dist/esm/backend/src/payments/stripe/events.d.ts +0 -155
  220. package/backend/dist/esm/backend/src/payments/stripe/events.js +0 -5
  221. package/backend/dist/esm/backend/src/payments/stripe/meters.d.ts +0 -105
  222. package/backend/dist/esm/backend/src/payments/stripe/meters.js +0 -318
  223. package/backend/dist/esm/backend/src/payments/stripe/payment_methods.d.ts +0 -58
  224. package/backend/dist/esm/backend/src/payments/stripe/payment_methods.js +0 -135
  225. package/backend/dist/esm/backend/src/payments/stripe/products.d.ts +0 -519
  226. package/backend/dist/esm/backend/src/payments/stripe/products.js +0 -896
  227. package/backend/dist/esm/backend/src/payments/stripe/stripe.d.ts +0 -215
  228. package/backend/dist/esm/backend/src/payments/stripe/stripe.js +0 -464
  229. package/backend/dist/esm/backend/src/payments/stripe/subscriptions.d.ts +0 -172
  230. package/backend/dist/esm/backend/src/payments/stripe/subscriptions.js +0 -754
  231. package/backend/dist/esm/backend/src/payments/stripe/utils.d.ts +0 -63
  232. package/backend/dist/esm/backend/src/payments/stripe/utils.js +0 -131
  233. package/backend/dist/esm/backend/src/payments/stripe/webhooks.d.ts +0 -105
  234. package/backend/dist/esm/backend/src/payments/stripe/webhooks.js +0 -752
  235. package/backend/dist/esm/backend/src/plugins/browser.d.ts +0 -1
  236. package/backend/dist/esm/backend/src/plugins/browser.js +0 -170
  237. package/backend/dist/esm/backend/src/plugins/communication.d.ts +0 -70
  238. package/backend/dist/esm/backend/src/plugins/communication.js +0 -169
  239. package/backend/dist/esm/backend/src/plugins/mail/mail.d.ts +0 -255
  240. package/backend/dist/esm/backend/src/plugins/mail/mail.js +0 -396
  241. package/backend/dist/esm/backend/src/plugins/mail/ui.d.ts +0 -297
  242. package/backend/dist/esm/backend/src/plugins/mail/ui.js +0 -1400
  243. package/backend/dist/esm/backend/src/plugins/pdf.d.ts +0 -1
  244. package/backend/dist/esm/backend/src/plugins/pdf.js +0 -1694
  245. package/backend/dist/esm/backend/src/plugins/thread_monitor.d.ts +0 -18
  246. package/backend/dist/esm/backend/src/plugins/thread_monitor.js +0 -120
  247. package/backend/dist/esm/backend/src/rate_limit.d.ts +0 -148
  248. package/backend/dist/esm/backend/src/rate_limit.js +0 -667
  249. package/backend/dist/esm/backend/src/route.d.ts +0 -39
  250. package/backend/dist/esm/backend/src/route.js +0 -222
  251. package/backend/dist/esm/backend/src/server.d.ts +0 -502
  252. package/backend/dist/esm/backend/src/server.js +0 -2034
  253. package/backend/dist/esm/backend/src/server.old.d.ts +0 -594
  254. package/backend/dist/esm/backend/src/server.old.js +0 -2630
  255. package/backend/dist/esm/backend/src/splash_screen.d.ts +0 -93
  256. package/backend/dist/esm/backend/src/splash_screen.js +0 -156
  257. package/backend/dist/esm/backend/src/status.d.ts +0 -89
  258. package/backend/dist/esm/backend/src/status.js +0 -213
  259. package/backend/dist/esm/backend/src/stream.d.ts +0 -494
  260. package/backend/dist/esm/backend/src/stream.js +0 -1611
  261. package/backend/dist/esm/backend/src/users.d.ts +0 -926
  262. package/backend/dist/esm/backend/src/users.js +0 -2423
  263. package/backend/dist/esm/backend/src/utils.d.ts +0 -22
  264. package/backend/dist/esm/backend/src/utils.js +0 -463
  265. package/backend/dist/esm/backend/src/view.d.ts +0 -115
  266. package/backend/dist/esm/backend/src/view.js +0 -584
  267. package/backend/dist/esm/backend/src/vinc.d.ts +0 -6
  268. package/backend/dist/esm/backend/src/vinc.js +0 -6
  269. package/backend/dist/esm/backend/src/volt.d.ts +0 -24
  270. package/backend/dist/esm/backend/src/volt.js +0 -27
  271. package/backend/dist/esm/frontend/src/modules/request.d.ts +0 -70
  272. package/backend/dist/esm/frontend/src/modules/request.js +0 -117
  273. package/backend/old/file_watcher.ts +0 -359
  274. package/backend/old/request.deprc.js +0 -626
  275. package/backend/old/response.deprc.js +0 -354
  276. package/frontend/dist/backend/src/database/collection.d.ts +0 -1765
  277. package/frontend/dist/backend/src/database/collection.js +0 -3779
  278. package/frontend/dist/backend/src/database/database.d.ts +0 -92
  279. package/frontend/dist/backend/src/database/database.js +0 -214
  280. package/frontend/dist/backend/src/database/filters/filters.d.ts +0 -6
  281. package/frontend/dist/backend/src/database/filters/filters.js +0 -1
  282. package/frontend/dist/backend/src/database/filters/strict_filter.d.ts +0 -223
  283. package/frontend/dist/backend/src/database/filters/strict_filter.js +0 -3
  284. package/frontend/dist/backend/src/database/filters/strict_update_filter.d.ts +0 -165
  285. package/frontend/dist/backend/src/database/filters/strict_update_filter.js +0 -5
  286. package/frontend/dist/backend/src/database/flatten.d.ts +0 -78
  287. package/frontend/dist/backend/src/database/flatten.js +0 -22
  288. package/frontend/dist/backend/src/endpoint.d.ts +0 -346
  289. package/frontend/dist/backend/src/endpoint.js +0 -479
  290. package/frontend/dist/backend/src/errors/index.d.ts +0 -7
  291. package/frontend/dist/backend/src/errors/index.js +0 -7
  292. package/frontend/dist/backend/src/errors/internal_external.d.ts +0 -52
  293. package/frontend/dist/backend/src/errors/internal_external.js +0 -86
  294. package/frontend/dist/backend/src/errors/invalid_usage_error.d.ts +0 -41
  295. package/frontend/dist/backend/src/errors/invalid_usage_error.js +0 -33
  296. package/frontend/dist/backend/src/errors/system_error.d.ts +0 -261
  297. package/frontend/dist/backend/src/errors/system_error.js +0 -444
  298. package/frontend/dist/backend/src/events.d.ts +0 -97
  299. package/frontend/dist/backend/src/events.js +0 -5
  300. package/frontend/dist/backend/src/frontend.d.ts +0 -11
  301. package/frontend/dist/backend/src/frontend.js +0 -12
  302. package/frontend/dist/backend/src/image_endpoint.d.ts +0 -44
  303. package/frontend/dist/backend/src/image_endpoint.js +0 -196
  304. package/frontend/dist/backend/src/meta.d.ts +0 -112
  305. package/frontend/dist/backend/src/meta.js +0 -152
  306. package/frontend/dist/backend/src/payments/paddle.d.ts +0 -329
  307. package/frontend/dist/backend/src/payments/paddle.js +0 -2276
  308. package/frontend/dist/backend/src/payments/stripe/checkout.d.ts +0 -113
  309. package/frontend/dist/backend/src/payments/stripe/checkout.js +0 -356
  310. package/frontend/dist/backend/src/payments/stripe/customers.d.ts +0 -17
  311. package/frontend/dist/backend/src/payments/stripe/customers.js +0 -193
  312. package/frontend/dist/backend/src/payments/stripe/error.d.ts +0 -74
  313. package/frontend/dist/backend/src/payments/stripe/error.js +0 -51
  314. package/frontend/dist/backend/src/payments/stripe/events.d.ts +0 -155
  315. package/frontend/dist/backend/src/payments/stripe/events.js +0 -5
  316. package/frontend/dist/backend/src/payments/stripe/meters.d.ts +0 -105
  317. package/frontend/dist/backend/src/payments/stripe/meters.js +0 -318
  318. package/frontend/dist/backend/src/payments/stripe/payment_methods.d.ts +0 -58
  319. package/frontend/dist/backend/src/payments/stripe/payment_methods.js +0 -135
  320. package/frontend/dist/backend/src/payments/stripe/products.d.ts +0 -519
  321. package/frontend/dist/backend/src/payments/stripe/products.js +0 -896
  322. package/frontend/dist/backend/src/payments/stripe/stripe.d.ts +0 -215
  323. package/frontend/dist/backend/src/payments/stripe/stripe.js +0 -464
  324. package/frontend/dist/backend/src/payments/stripe/subscriptions.d.ts +0 -172
  325. package/frontend/dist/backend/src/payments/stripe/subscriptions.js +0 -754
  326. package/frontend/dist/backend/src/payments/stripe/utils.d.ts +0 -63
  327. package/frontend/dist/backend/src/payments/stripe/utils.js +0 -131
  328. package/frontend/dist/backend/src/payments/stripe/webhooks.d.ts +0 -105
  329. package/frontend/dist/backend/src/payments/stripe/webhooks.js +0 -752
  330. package/frontend/dist/backend/src/plugins/mail/mail.d.ts +0 -255
  331. package/frontend/dist/backend/src/plugins/mail/mail.js +0 -396
  332. package/frontend/dist/backend/src/plugins/mail/ui.d.ts +0 -297
  333. package/frontend/dist/backend/src/plugins/mail/ui.js +0 -1400
  334. package/frontend/dist/backend/src/rate_limit.d.ts +0 -148
  335. package/frontend/dist/backend/src/rate_limit.js +0 -667
  336. package/frontend/dist/backend/src/route.d.ts +0 -39
  337. package/frontend/dist/backend/src/route.js +0 -222
  338. package/frontend/dist/backend/src/server.d.ts +0 -502
  339. package/frontend/dist/backend/src/server.js +0 -2034
  340. package/frontend/dist/backend/src/splash_screen.d.ts +0 -93
  341. package/frontend/dist/backend/src/splash_screen.js +0 -156
  342. package/frontend/dist/backend/src/status.d.ts +0 -89
  343. package/frontend/dist/backend/src/status.js +0 -213
  344. package/frontend/dist/backend/src/stream.d.ts +0 -494
  345. package/frontend/dist/backend/src/stream.js +0 -1611
  346. package/frontend/dist/backend/src/users.d.ts +0 -926
  347. package/frontend/dist/backend/src/users.js +0 -2423
  348. package/frontend/dist/backend/src/utils.d.ts +0 -22
  349. package/frontend/dist/backend/src/utils.js +0 -463
  350. package/frontend/dist/backend/src/view.d.ts +0 -115
  351. package/frontend/dist/backend/src/view.js +0 -584
  352. package/frontend/dist/frontend/src/elements/base.d.ts +0 -3743
  353. package/frontend/dist/frontend/src/elements/base.js +0 -12151
  354. package/frontend/dist/frontend/src/elements/module.d.ts +0 -95
  355. package/frontend/dist/frontend/src/elements/module.js +0 -216
  356. package/frontend/dist/frontend/src/elements/register_element.d.ts +0 -3
  357. package/frontend/dist/frontend/src/elements/register_element.js +0 -22
  358. package/frontend/dist/frontend/src/elements/resize_query_manager.d.ts +0 -0
  359. package/frontend/dist/frontend/src/elements/resize_query_manager.js +0 -150
  360. package/frontend/dist/frontend/src/elements/types.d.ts +0 -52
  361. package/frontend/dist/frontend/src/elements/types.js +0 -5
  362. package/frontend/dist/frontend/src/index.d.ts +0 -21
  363. package/frontend/dist/frontend/src/index.js +0 -29
  364. package/frontend/dist/frontend/src/modules/attachment.d.ts +0 -126
  365. package/frontend/dist/frontend/src/modules/attachment.js +0 -306
  366. package/frontend/dist/frontend/src/modules/auth.d.ts +0 -44
  367. package/frontend/dist/frontend/src/modules/auth.js +0 -80
  368. package/frontend/dist/frontend/src/modules/color.d.ts +0 -160
  369. package/frontend/dist/frontend/src/modules/color.js +0 -316
  370. package/frontend/dist/frontend/src/modules/compression.d.ts +0 -39
  371. package/frontend/dist/frontend/src/modules/compression.js +0 -102
  372. package/frontend/dist/frontend/src/modules/cookies.d.ts +0 -44
  373. package/frontend/dist/frontend/src/modules/cookies.js +0 -143
  374. package/frontend/dist/frontend/src/modules/events.d.ts +0 -31
  375. package/frontend/dist/frontend/src/modules/events.js +0 -79
  376. package/frontend/dist/frontend/src/modules/google.d.ts +0 -23
  377. package/frontend/dist/frontend/src/modules/google.js +0 -52
  378. package/frontend/dist/frontend/src/modules/meta.d.ts +0 -14
  379. package/frontend/dist/frontend/src/modules/meta.js +0 -48
  380. package/frontend/dist/frontend/src/modules/paddle.d.ts +0 -1207
  381. package/frontend/dist/frontend/src/modules/paddle.js +0 -2594
  382. package/frontend/dist/frontend/src/modules/request.d.ts +0 -70
  383. package/frontend/dist/frontend/src/modules/request.js +0 -117
  384. package/frontend/dist/frontend/src/modules/settings.d.ts +0 -3
  385. package/frontend/dist/frontend/src/modules/settings.js +0 -5
  386. package/frontend/dist/frontend/src/modules/statics.d.ts +0 -21
  387. package/frontend/dist/frontend/src/modules/statics.js +0 -43
  388. package/frontend/dist/frontend/src/modules/stripe/cart.d.ts +0 -112
  389. package/frontend/dist/frontend/src/modules/stripe/cart.js +0 -321
  390. package/frontend/dist/frontend/src/modules/stripe/checkout.d.ts +0 -7
  391. package/frontend/dist/frontend/src/modules/stripe/checkout.js +0 -37
  392. package/frontend/dist/frontend/src/modules/stripe/index.m.d.ts +0 -6
  393. package/frontend/dist/frontend/src/modules/stripe/index.m.js +0 -6
  394. package/frontend/dist/frontend/src/modules/stripe/payments.d.ts +0 -58
  395. package/frontend/dist/frontend/src/modules/stripe/payments.js +0 -92
  396. package/frontend/dist/frontend/src/modules/support.d.ts +0 -30
  397. package/frontend/dist/frontend/src/modules/support.js +0 -53
  398. package/frontend/dist/frontend/src/modules/theme.d.ts +0 -133
  399. package/frontend/dist/frontend/src/modules/theme.js +0 -406
  400. package/frontend/dist/frontend/src/modules/themes.d.ts +0 -12
  401. package/frontend/dist/frontend/src/modules/themes.js +0 -22
  402. package/frontend/dist/frontend/src/modules/user.d.ts +0 -164
  403. package/frontend/dist/frontend/src/modules/user.js +0 -270
  404. package/frontend/dist/frontend/src/modules/utils.d.ts +0 -176
  405. package/frontend/dist/frontend/src/modules/utils.js +0 -569
  406. package/frontend/dist/frontend/src/types/gradient.d.ts +0 -29
  407. package/frontend/dist/frontend/src/types/gradient.js +0 -79
  408. package/frontend/dist/frontend/src/ui/border_button.d.ts +0 -94
  409. package/frontend/dist/frontend/src/ui/border_button.js +0 -228
  410. package/frontend/dist/frontend/src/ui/button.d.ts +0 -241
  411. package/frontend/dist/frontend/src/ui/button.js +0 -682
  412. package/frontend/dist/frontend/src/ui/canvas.d.ts +0 -138
  413. package/frontend/dist/frontend/src/ui/canvas.js +0 -444
  414. package/frontend/dist/frontend/src/ui/checkbox.d.ts +0 -74
  415. package/frontend/dist/frontend/src/ui/checkbox.js +0 -321
  416. package/frontend/dist/frontend/src/ui/code.d.ts +0 -235
  417. package/frontend/dist/frontend/src/ui/code.js +0 -1007
  418. package/frontend/dist/frontend/src/ui/context_menu.d.ts +0 -36
  419. package/frontend/dist/frontend/src/ui/context_menu.js +0 -205
  420. package/frontend/dist/frontend/src/ui/css.d.ts +0 -16
  421. package/frontend/dist/frontend/src/ui/css.js +0 -48
  422. package/frontend/dist/frontend/src/ui/divider.d.ts +0 -15
  423. package/frontend/dist/frontend/src/ui/divider.js +0 -78
  424. package/frontend/dist/frontend/src/ui/dropdown.d.ts +0 -176
  425. package/frontend/dist/frontend/src/ui/dropdown.js +0 -481
  426. package/frontend/dist/frontend/src/ui/for_each.d.ts +0 -37
  427. package/frontend/dist/frontend/src/ui/for_each.js +0 -92
  428. package/frontend/dist/frontend/src/ui/form.d.ts +0 -34
  429. package/frontend/dist/frontend/src/ui/form.js +0 -233
  430. package/frontend/dist/frontend/src/ui/frame_modes.d.ts +0 -37
  431. package/frontend/dist/frontend/src/ui/frame_modes.js +0 -108
  432. package/frontend/dist/frontend/src/ui/google_map.d.ts +0 -24
  433. package/frontend/dist/frontend/src/ui/google_map.js +0 -106
  434. package/frontend/dist/frontend/src/ui/gradient.d.ts +0 -25
  435. package/frontend/dist/frontend/src/ui/gradient.js +0 -131
  436. package/frontend/dist/frontend/src/ui/image.d.ts +0 -111
  437. package/frontend/dist/frontend/src/ui/image.js +0 -576
  438. package/frontend/dist/frontend/src/ui/input.d.ts +0 -392
  439. package/frontend/dist/frontend/src/ui/input.js +0 -1201
  440. package/frontend/dist/frontend/src/ui/link.d.ts +0 -25
  441. package/frontend/dist/frontend/src/ui/link.js +0 -140
  442. package/frontend/dist/frontend/src/ui/list.d.ts +0 -37
  443. package/frontend/dist/frontend/src/ui/list.js +0 -170
  444. package/frontend/dist/frontend/src/ui/loader_button.d.ts +0 -80
  445. package/frontend/dist/frontend/src/ui/loader_button.js +0 -193
  446. package/frontend/dist/frontend/src/ui/loaders.d.ts +0 -57
  447. package/frontend/dist/frontend/src/ui/loaders.js +0 -157
  448. package/frontend/dist/frontend/src/ui/popup.d.ts +0 -94
  449. package/frontend/dist/frontend/src/ui/popup.js +0 -510
  450. package/frontend/dist/frontend/src/ui/pseudo.d.ts +0 -44
  451. package/frontend/dist/frontend/src/ui/pseudo.js +0 -154
  452. package/frontend/dist/frontend/src/ui/scroller.d.ts +0 -105
  453. package/frontend/dist/frontend/src/ui/scroller.js +0 -1253
  454. package/frontend/dist/frontend/src/ui/slider.d.ts +0 -45
  455. package/frontend/dist/frontend/src/ui/slider.js +0 -217
  456. package/frontend/dist/frontend/src/ui/spacer.d.ts +0 -15
  457. package/frontend/dist/frontend/src/ui/spacer.js +0 -78
  458. package/frontend/dist/frontend/src/ui/span.d.ts +0 -15
  459. package/frontend/dist/frontend/src/ui/span.js +0 -73
  460. package/frontend/dist/frontend/src/ui/stack.d.ts +0 -66
  461. package/frontend/dist/frontend/src/ui/stack.js +0 -335
  462. package/frontend/dist/frontend/src/ui/steps.d.ts +0 -131
  463. package/frontend/dist/frontend/src/ui/steps.js +0 -308
  464. package/frontend/dist/frontend/src/ui/style.d.ts +0 -17
  465. package/frontend/dist/frontend/src/ui/style.js +0 -73
  466. package/frontend/dist/frontend/src/ui/switch.d.ts +0 -69
  467. package/frontend/dist/frontend/src/ui/switch.js +0 -357
  468. package/frontend/dist/frontend/src/ui/table.d.ts +0 -100
  469. package/frontend/dist/frontend/src/ui/table.js +0 -405
  470. package/frontend/dist/frontend/src/ui/tabs.d.ts +0 -111
  471. package/frontend/dist/frontend/src/ui/tabs.js +0 -424
  472. package/frontend/dist/frontend/src/ui/text.d.ts +0 -15
  473. package/frontend/dist/frontend/src/ui/text.js +0 -83
  474. package/frontend/dist/frontend/src/ui/title.d.ts +0 -91
  475. package/frontend/dist/frontend/src/ui/title.js +0 -272
  476. package/frontend/dist/frontend/src/ui/ui.d.ts +0 -35
  477. package/frontend/dist/frontend/src/ui/ui.js +0 -38
  478. package/frontend/dist/frontend/src/ui/view.d.ts +0 -15
  479. package/frontend/dist/frontend/src/ui/view.js +0 -88
  480. package/frontend/dist/frontend/src/volt.d.ts +0 -20
  481. package/frontend/dist/frontend/src/volt.js +0 -27
  482. package/frontend/examples/theme/theme.ts +0 -58
  483. package/frontend/tools/bundle_d_ts.js +0 -71
  484. package/frontend/tools/convert_to_jsdoc_input.txt +0 -9452
  485. package/frontend/tools/convert_to_jsdoc_output.txt +0 -7626
  486. package/frontend/tools/convert_to_jsdoc_tmp.js +0 -345
  487. package/frontend/tools/scan_mixed_imports.js +0 -69
  488. /package/frontend/{dist/frontend/src/css → css}/adyen.css +0 -0
  489. /package/frontend/{dist/frontend/src/css → css}/volt.css +0 -0
@@ -1,2630 +0,0 @@
1
- // @ts-nocheck
2
- /**
3
- * @author Daan van den Bergh
4
- * @copyright © 2022 - 2025 Daan van den Bergh.
5
- */
6
- import { fileURLToPath } from 'url';
7
- import * as path from 'path';
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- // ---------------------------------------------------------
11
- // Libraries.
12
- import * as http from "http";
13
- import * as http2 from "http2";
14
- import * as crypto from "crypto";
15
- import libcluster from 'cluster';
16
- import * as os from 'os';
17
- import * as vlib from "@vandenberghinc/vlib";
18
- const { debug } = vlib;
19
- // ---------------------------------------------------------
20
- // Imports.
21
- import { Utils } from "./utils.js";
22
- import { Meta } from './meta.js';
23
- import * as MailUI from './plugins/mail/ui.js';
24
- import { Mail } from "./plugins/mail/mail.js";
25
- import { Status } from "./status.js";
26
- import { Endpoint } from "./endpoint.js";
27
- import { ImageEndpoint } from "./image_endpoint.js";
28
- import { Stream } from "./stream.js";
29
- import { Database } from "./database/database.js";
30
- import { Users } from "./users.js";
31
- import { RateLimits, RateLimitServer, RateLimitClient } from "./rate_limit.js";
32
- import { Route } from "./route.js";
33
- import { ExternalError } from './errors/internal_external.js';
34
- /**
35
- * The server class.
36
- * @note Automatically runs on HTTP/HTTPS depending on the constructor options.
37
- *
38
- * @nav Server
39
- * @docs
40
- */
41
- export class Server {
42
- // ---------------------------------------------------------
43
- // Static attributes.
44
- // ---------------------------------------------------------
45
- /**
46
- * A temporary directory which holds the cached endpoint data.
47
- * For instance if we bundle JS then we save it to file and serve it from the file,
48
- * similar for transformed image endpoints.
49
- *
50
- * Note that upon each server start, we should clear this cache and remove all files inside this dir.
51
- */
52
- endpoint_cache_dir;
53
- // ---------------------------------------------------------
54
- // Attributes.
55
- // ---------------------------------------------------------
56
- /** The binded ip address. */
57
- ip;
58
- /** The binded http port. */
59
- port;
60
- /** The binded https port. */
61
- https_port;
62
- /** The raw domain. */
63
- domain;
64
- /** The full domain name with http/https depending if tls is enabled. */
65
- full_domain;
66
- /** The persistent storage source directory. */
67
- source;
68
- /** Is the primary thread. */
69
- is_primary;
70
- /** Is in production mode. */
71
- production;
72
- /** The company information. */
73
- company;
74
- /** The default meta information. */
75
- meta;
76
- /** Is running in offline mode. */
77
- offline;
78
- /** The database instance. */
79
- db;
80
- /** The rate limit instance. */
81
- rate_limit;
82
- /** The added endpoints. */
83
- endpoints = new Map();
84
- /** The added error endpoints. */
85
- err_endpoints = new Map();
86
- /** A record of keys used for hashing. */
87
- keys = {};
88
- /** Alias for the `Status` module. */
89
- status;
90
- /** Alias for the `RateLimits` module. */
91
- rate_limits;
92
- /** The file logger. */
93
- log;
94
- /** The users instance. */
95
- users;
96
- /** The payments instance. */
97
- payments;
98
- /** Daemon instance to manage a live daemon. */
99
- daemon;
100
- /** The mail instance. */
101
- mail;
102
- // Public for internal use:
103
- csp;
104
- statics_aspect_ratios;
105
- google_tag;
106
- rate_limit_api_key;
107
- performance;
108
- /** The events map @internal */
109
- events = new vlib.Events();
110
- // Private.
111
- favicon;
112
- statics;
113
- _user_keys_opts;
114
- additional_sitemap_endpoints;
115
- tls;
116
- default_headers;
117
- http;
118
- https;
119
- threading;
120
- // Private ollections.
121
- _keys_db;
122
- _sys_keys_db;
123
- _website_status_db;
124
- /**
125
- * Construct a new server instance.
126
- * @docs
127
- */
128
- constructor({ ip = "127.0.0.1", port, // leave undefined for blank detection.
129
- domain, is_primary = true, source, database, statics = [], favicon, company, meta = new Meta(), tls, mail, rate_limit = {
130
- server: {
131
- ip: undefined,
132
- port: RateLimitServer.default_port,
133
- https: undefined,
134
- },
135
- client: {
136
- ip: undefined,
137
- port: RateLimitServer.default_port,
138
- url: undefined,
139
- },
140
- }, keys = [], payments, default_headers, google_tag = undefined, users, production = false, threading = {
141
- enabled: false,
142
- threads: undefined,
143
- }, offline = false, additional_sitemap_endpoints = [], log_level = 0, daemon = false,
144
- // admin = {
145
- // password: null,
146
- // ips: [],
147
- // },
148
- // ts = {
149
- // compiler_opts: {},
150
- // output: undefined,
151
- // },
152
- // browser_preview = undefined,
153
- }) {
154
- // // Verify args.
155
- // vlib.schema.validate(arguments[0], {
156
- // throw: true,
157
- // error_prefix: "Server: ", unknown: false,
158
- // schema: {
159
- // ip: { type: "string", required: false },
160
- // port: { type: "number", required: false },
161
- // domain: "string",
162
- // statics: { type: "array", default: [] },
163
- // is_primary: { type: "boolean", default: true },
164
- // source: "string",
165
- // database: {
166
- // type: ["string", "object"],
167
- // required: true,
168
- // scheme: { ...(Database.constructor_scheme as any), _server: undefined },
169
- // },
170
- // favicon: { type: "string", required: false },
171
- // company: {
172
- // type: "object",
173
- // default: {},
174
- // scheme: {
175
- // name: "string",
176
- // legal_name: "string",
177
- // street: "string",
178
- // house_number: "string",
179
- // postal_code: "string",
180
- // city: "string",
181
- // province: "string",
182
- // country: "string",
183
- // country_code: "string",
184
- // tax_id: { type: "string", default: null },
185
- // icon: { type: "string", default: null },
186
- // icon_path: { type: "string", default: null },
187
- // stroke_icon: { type: "string", default: null },
188
- // stroke_icon_path: { type: "string", default: null },
189
- // }
190
- // },
191
- // meta: { type: "object", required: false },
192
- // tls: {
193
- // type: ["object"],
194
- // required: false,
195
- // scheme: {
196
- // cert: "string",
197
- // key: "string",
198
- // ca: { type: "string", default: null },
199
- // passphrase: { type: "string", default: null },
200
- // }
201
- // },
202
- // rate_limit: {
203
- // type: ["boolean", "object"],
204
- // default: false,
205
- // scheme: {
206
- // server: {
207
- // type: "object", default: {}, scheme: {
208
- // ip: { type: "string", default: null },
209
- // port: { type: "number", default: RateLimitServer.default_port },
210
- // https: { type: "object", default: null },
211
- // }
212
- // },
213
- // client: {
214
- // type: "object", default: {}, scheme: {
215
- // ip: { type: "string", default: null },
216
- // port: { type: "number", default: RateLimitServer.default_port },
217
- // url: { type: "string", default: null },
218
- // }
219
- // },
220
- // },
221
- // },
222
- // keys: { type: "array", default: [] },
223
- // smtp: { type: ["null", "object"], required: false },
224
- // mail_style: {
225
- // type: "object",
226
- // required: false,
227
- // scheme: {
228
- // font: { type: "string", default: '"Helvetica", sans-serif' },
229
- // title_fg: { type: "string", default: "#121B23" },
230
- // subtitle_fg: { type: "string", default: "#121B23" },
231
- // text_fg: { type: "string", default: "#1F2F3D" },
232
- // button_fg: { type: "string", default: "#FFFFFF" },
233
- // footer_fg: { type: "string", default: "#686B80" },
234
- // bg: { type: "string", default: "#EEEEEE" },
235
- // widget_bg: { type: "string", default: "#FFFFFF" },
236
- // button_bg: { type: "string", default: "#421959" },
237
- // widget_border: { type: "string", default: "#E6E6E6" },
238
- // divider_bg: { type: "string", default: "#E6E6E6" },
239
- // }
240
- // },
241
- // payments: { type: ["null", "object"], required: false },
242
- // default_headers: { type: ["null", "object"], required: false },
243
- // google_tag: { type: "string", required: false },
244
- // token_expiration: { type: "number", required: false },
245
- // enable_2fa: { type: "boolean", required: false },
246
- // enable_account_activation: { type: "boolean", required: false },
247
- // production: { type: "boolean", required: false },
248
- // multiprocessing: { type: "boolean", required: false, default: true },
249
- // processes: { type: "number", required: false, default: null },
250
- // offline: { type: "boolean", default: false },
251
- // additional_sitemap_endpoints: { type: "array", default: [] },
252
- // log_level: { type: "number", default: 0 },
253
- // daemon: { type: ["object", "boolean"], default: {} },
254
- // // admin: {type: "object", default: {}, attributes: {
255
- // // ips: {type: "array", default: []},
256
- // // password: {
257
- // // type: "string",
258
- // // verify: (param: string, attrs) => (param.length < 10 ? `Parameter "Server.admin.password" must have a length of at least 10 characters.` : undefined),
259
- // // },
260
- // // }},
261
- // // ts: {
262
- // // type: "object",
263
- // // required: false,
264
- // // scheme: {
265
- // // compiler_opts: {type: "object", default: {}},
266
- // // output: "string",
267
- // // },
268
- // // },
269
- // // browser_preview: {type: ["string", "undefined"], required: false, default: undefined},
270
- // },
271
- // });
272
- // Assign attributes directly.
273
- if (production || port == null) {
274
- this.port = 80;
275
- this.https_port = 443;
276
- }
277
- else {
278
- this.port = port;
279
- this.https_port = port + 1;
280
- }
281
- this.ip = ip ?? "127.0.0.1";
282
- this.is_primary = is_primary && libcluster.isPrimary;
283
- this.source = new vlib.Path(source);
284
- this.favicon = favicon;
285
- this.google_tag = google_tag;
286
- this.production = production;
287
- this.company = company;
288
- this.offline = offline;
289
- this._user_keys_opts = keys;
290
- this.additional_sitemap_endpoints = additional_sitemap_endpoints;
291
- this.tls = tls;
292
- // this.admin = admin as AdminConfig;
293
- // Set threading.
294
- if (typeof threading === "boolean") {
295
- this.threading = {
296
- enabled: threading,
297
- threads: os.cpus().length,
298
- };
299
- }
300
- else {
301
- this.threading = {
302
- enabled: threading.enabled ?? true,
303
- threads: threading.threads ?? os.cpus().length,
304
- };
305
- }
306
- // Module aliases.
307
- this.status = Status;
308
- this.rate_limits = RateLimits;
309
- /* @performance */ this.performance = new vlib.Performance("Server performance");
310
- // Create logs directory.
311
- const log_source = this.source.join("logs");
312
- if (!log_source.exists()) {
313
- log_source.mkdir_sync({ recursive: true });
314
- }
315
- this.log = new vlib.logging.FileLogger({
316
- level: log_level,
317
- log_path: log_source.join("logs").str(),
318
- error_path: log_source.join("errors").str(),
319
- });
320
- // Check source.
321
- if (!this.source.exists()) {
322
- throw Error(`Source directory "${this.source.str()}" does not exist.`);
323
- }
324
- this.source = this.source.abs();
325
- // Set domain.
326
- this.domain = domain.replace("https://", "").replace("http://", "");
327
- while (this.domain.length > 0 && this.domain.charAt(this.domain.length - 1) === "/") {
328
- this.domain = this.domain.substr(0, this.domain.length - 1);
329
- }
330
- // Set full domain.
331
- this.full_domain = `http${this.tls ? "s" : ""}://${this.domain}`;
332
- while (this.full_domain.endsWith("/")) {
333
- this.full_domain = this.full_domain.slice(0, -1);
334
- }
335
- // Set endpoint cache.
336
- this.endpoint_cache_dir = new vlib.Path("/tmp/volt_server_endpoint_cache/" + this.hash(this.domain));
337
- // Set statics.
338
- this.statics = statics;
339
- this.statics_aspect_ratios = new Map();
340
- // Add the default static to statics.
341
- const volt_assets_path = new vlib.Path(`${__dirname}/../../../../../frontend/src/assets/`);
342
- if (!volt_assets_path.exists()) {
343
- this.log.warning(`${vlib.Color.yellow_bold("Warning")}: Could not find volt assets directory at "${volt_assets_path.abs().str()}". Please create a GitHub issue to report this.`);
344
- }
345
- this.statics.push({
346
- path: volt_assets_path.str(),
347
- endpoint: "/volt/assets",
348
- });
349
- // Set meta.
350
- if (!(meta instanceof Meta)) {
351
- meta = new Meta(meta);
352
- }
353
- if (favicon != null && meta.favicon == null) {
354
- meta.favicon = this.full_domain + "/favicon.ico";
355
- }
356
- if (favicon != null && meta.image == null) {
357
- meta.image = this.full_domain + "/favicon.ico";
358
- }
359
- else if (meta.image != null && !meta.image.startsWith("http")) {
360
- meta.image = this.full_domain + meta.image;
361
- }
362
- this.meta = meta;
363
- // Default headers.
364
- const base_default_headers = {
365
- // Cache correctness for CORS/preflight:
366
- "Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
367
- // Safer default than same-origin, still keeps useful referrers:
368
- "Referrer-Policy": "strict-origin-when-cross-origin",
369
- "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
370
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
371
- // Let browsers read our rate-limit hint:
372
- "Access-Control-Expose-Headers": "X-RateLimit-Reset",
373
- "X-Content-Type-Options": "nosniff",
374
- "X-Frame-Options": "DENY",
375
- // Helpful isolation defaults (safe for most apps):
376
- "Cross-Origin-Opener-Policy": "same-origin",
377
- "Cross-Origin-Resource-Policy": "same-site",
378
- // If you need SharedArrayBuffer, add COEP below (can break some embeds):
379
- // "Cross-Origin-Embedder-Policy": "require-corp",
380
- "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload",
381
- // Lock down powerful APIs by default.
382
- // If you need one on a third-party origin, add it beside (self).
383
- "Permissions-Policy": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=(), hid=(), serial=(), xr-spatial-tracking=(), display-capture=(), screen-wake-lock=(), sync-xhr=(), publickey-credentials-get=(self), encrypted-media=(self), autoplay=(self 'https://www.youtube-nocookie.com') fullscreen=(self 'https://www.youtube-nocookie.com'), browsing-topics=()",
384
- // Do NOT set Allow-Origin / Credentials statically; set them per-request below.
385
- // "X-XSS-Protection": "1; mode=block", // deprecated
386
- };
387
- const default_csp = {
388
- "default-src": "'self'",
389
- "base-uri": "'none'",
390
- "object-src": "'none'",
391
- "form-action": "'self'",
392
- "frame-ancestors": "'none'",
393
- // Keep GA images; drop explicit http:// to avoid mixed content.
394
- "img-src": "'self' data: blob: https://*.google-analytics.com",
395
- "script-src": "'self' https://ajax.googleapis.com https://www.googletagmanager.com https://*.google-analytics.com",
396
- // Needed for GA/GTAG beacons/fetch:
397
- "connect-src": "'self' https://*.google-analytics.com",
398
- "style-src": "'self'",
399
- "font-src": "'self' data:",
400
- // Auto-upgrade stray http URLs where possible:
401
- "upgrade-insecure-requests": "",
402
- };
403
- if (default_headers == null) {
404
- this.csp = default_csp;
405
- this.default_headers = { ...base_default_headers };
406
- }
407
- else {
408
- if (default_headers["Content-Security-Policy"] != null && typeof default_headers["Content-Security-Policy"] !== "object") {
409
- throw Error("The Content-Security-Policy of the default headers must be an object with values for each csp key, e.g. \"{'script-src': '...'}\".");
410
- }
411
- this.csp = default_headers["Content-Security-Policy"] != null ? default_headers["Content-Security-Policy"] : default_csp;
412
- Object.keys(base_default_headers).forEach(key => {
413
- if (default_headers[key] === undefined) {
414
- default_headers[key] = base_default_headers[key];
415
- }
416
- });
417
- this.default_headers = default_headers;
418
- }
419
- if (!this.tls) {
420
- // Always drop HSTS if TLS is not active.
421
- delete this.default_headers["Strict-Transport-Security"];
422
- }
423
- // Initialize payments.
424
- if (payments) {
425
- // if (payments.type === "paddle") {
426
- // this.payments = new Paddle({
427
- // _server: this,
428
- // ...payments,
429
- // })
430
- // } else {
431
- throw Error(`Invalid payment processor type "${payments.type}", valid types are ["paddle"].`);
432
- // }
433
- }
434
- // Initialize the service daemon.
435
- // Must be initialized before initializing the database.
436
- if (daemon !== false) {
437
- const log_source = this.source.join("daemon");
438
- if (!log_source.exists()) {
439
- log_source.mkdir_sync({ recursive: true });
440
- }
441
- this.daemon = new vlib.Daemon({
442
- name: this.domain.replaceAll(".", ""),
443
- logs: daemon.logs || log_source.join("logs").str(),
444
- errors: daemon.errors || log_source.join("errors").str(),
445
- ...daemon,
446
- // user: (daemon as Record<string, any>).user || os.userInfo().username,
447
- // group: (daemon as Record<string, any>).group || null,
448
- // command: "volt --service --start",
449
- // cwd: this.source.str(),
450
- // args: (daemon as Record<string, any>).args || [],
451
- // env: (daemon as Record<string, any>).env || {},
452
- // description: (daemon as Record<string, any>).description || `Service daemon for website ${this.domain}.`,
453
- // auto_restart: true,
454
- });
455
- }
456
- // Initialize the database class.
457
- if (typeof database === "string") {
458
- this.db = new Database({ uri: database, _server: this });
459
- }
460
- else {
461
- this.db = new Database({ ...database, _server: this });
462
- }
463
- // Database collections.
464
- this._keys_db = this.db.collection({
465
- name: "Volt.Keys",
466
- indexes: ["id"],
467
- });
468
- this._sys_keys_db = this.db.collection({
469
- name: "Volt.SystemKeys",
470
- indexes: ["id"],
471
- });
472
- this._website_status_db = this.db.collection({
473
- name: "Volt.WebsiteStatus",
474
- indexes: ["id"],
475
- });
476
- // Initialize the users class.
477
- this.users = new Users({
478
- support_recipient: mail?.smtp.sender, // ensure we assign the support recipient, so we dont need to define `this.mail` beforehand.
479
- ...users, // override support recipient if provided,
480
- _server: this,
481
- });
482
- // The mail instance.
483
- if (mail) {
484
- this.mail = new Mail(mail);
485
- }
486
- // The rate limit server/client.
487
- if (rate_limit) {
488
- if (this.is_primary) {
489
- this.rate_limit = new RateLimitServer({ ...(rate_limit.server ?? {}), _server: this });
490
- }
491
- else {
492
- if (rate_limit.server?.https) {
493
- rate_limit.client.https = true;
494
- }
495
- this.rate_limit = new RateLimitClient({ ...(rate_limit.client ?? {}), _server: this });
496
- }
497
- }
498
- }
499
- // ---------------------------------------------------------
500
- // Utils.
501
- /** Get a content type (MIME) from a file extension. */
502
- /**
503
- * Get a content type (MIME) from a file extension. The file extension should include the leading dot, e.g. ".html".
504
- * @docs
505
- */
506
- get_content_type(extension) {
507
- return Utils.mime_type(extension) ?? "application/octet-stream";
508
- }
509
- /**
510
- * Set the logging verbosity level.
511
- * @docs
512
- */
513
- set_log_level(level) {
514
- this.log.level.set(level);
515
- }
516
- // ---------------------------------------------------------
517
- // Crypto (private).
518
- /**
519
- * Generate a cryptographically secure random key as a hex string.
520
- * @docs
521
- */
522
- generate_crypto_key(length = 32) {
523
- return crypto.randomBytes(length).toString('hex');
524
- }
525
- /**
526
- * Create an HMAC hash using the provided key and data.
527
- * @docs
528
- */
529
- hmac(key, data, algo = "sha256") {
530
- const hmac = crypto.createHmac(algo, key);
531
- hmac.update(data);
532
- return hmac.digest("hex");
533
- }
534
- // /** Create an HMAC hash using the server's master hash key. */
535
- // hmac_with_master(data: string): string {
536
- // if (!this._master_hash_key) {
537
- // throw new Error("Hash key not initialized");
538
- // }
539
- // const hmac = crypto.createHmac("sha256", this._master_hash_key);
540
- // hmac.update(data);
541
- // return hmac.digest("hex");
542
- // }
543
- /**
544
- * Create a hash (no key) of the given data using the specified algorithm.
545
- * @docs
546
- */
547
- hash(data, algo = "sha256") {
548
- if (typeof data !== "string") {
549
- data = JSON.stringify(data);
550
- }
551
- return crypto.createHash(algo).update(data).digest('hex');
552
- }
553
- // ---------------------------------------------------------
554
- // Headers (private).
555
- // Initialize the default headers.
556
- _init_default_headers() {
557
- let csp = [];
558
- Object.entries(this.csp).forEach(([key, value]) => {
559
- csp.push(key);
560
- if (typeof value === "string" && value.length > 0) {
561
- csp.push(" ");
562
- csp.push(value);
563
- }
564
- csp.push(";");
565
- });
566
- this.default_headers["Content-Security-Policy"] = csp.join("");
567
- }
568
- // Add header defaults.
569
- _set_header_defaults(stream) {
570
- stream.set_headers(this.default_headers);
571
- const origin = stream.headers.origin;
572
- if (origin) {
573
- const same_http = `http://${this.domain}`;
574
- const same_https = `https://${this.domain}`;
575
- if (origin === same_http || origin === same_https) {
576
- stream.set_header("Access-Control-Allow-Origin", origin);
577
- stream.set_header("Access-Control-Allow-Credentials", "true");
578
- }
579
- else {
580
- stream.set_header("Access-Control-Allow-Origin", "*");
581
- // Do not send Access-Control-Allow-Credentials with a wildcard origin.
582
- }
583
- // Improve preflight reflection for caches and correctness.
584
- const req_hdrs = stream.headers["access-control-request-headers"];
585
- if (req_hdrs)
586
- stream.set_header("Access-Control-Allow-Headers", String(req_hdrs));
587
- const req_method = stream.headers["access-control-request-method"];
588
- if (req_method)
589
- stream.set_header("Access-Control-Allow-Methods", String(req_method));
590
- }
591
- }
592
- // ---------------------------------------------------------
593
- // Endpoints (private).
594
- // Create default endpoints.
595
- _create_default_endpoints() {
596
- // Add favicon.
597
- if (this.favicon != null) {
598
- const favicon = new vlib.Path(this.favicon);
599
- if (favicon.exists() === false) {
600
- throw Error(`Specified favicon path "${favicon}" does not exist.`);
601
- }
602
- this.endpoint({
603
- method: "GET",
604
- endpoint: "/favicon.ico",
605
- data: favicon.load_sync({ type: "buffer" }),
606
- content_type: this.get_content_type(favicon.extension()),
607
- _is_static: true,
608
- server: this,
609
- });
610
- }
611
- // Create status endpoint.
612
- const status_dir = this.source.join(".status");
613
- if (!status_dir.exists()) {
614
- status_dir.mkdir_sync({ recursive: true });
615
- }
616
- const status_key_path = status_dir.join("key");
617
- let status_key;
618
- if (!status_key_path.exists()) {
619
- status_key = this.generate_crypto_key(32);
620
- status_key_path.save_sync(status_key);
621
- }
622
- else {
623
- status_key = status_key_path.load_sync();
624
- }
625
- this.endpoint({
626
- method: "GET",
627
- endpoint: "/.status",
628
- content_type: "application/json",
629
- params: {
630
- key: "string",
631
- },
632
- callback: async (stream, params) => {
633
- // Check key.
634
- if (params.key !== status_key) {
635
- return stream.send({
636
- status: 403,
637
- headers: { "Content-Type": "text/plain" },
638
- data: "Access Denied",
639
- });
640
- }
641
- // Default status info.
642
- const status = {};
643
- status.ip = this.ip;
644
- if (this.http) {
645
- status.http_port = this.port;
646
- }
647
- if (this.https) {
648
- status.https_port = this.https_port;
649
- }
650
- // Load data.
651
- const data = await this._website_status_db.load({ id: "status" }, {
652
- default: {
653
- id: "status",
654
- running_since: undefined,
655
- running_threads: 0,
656
- total_threads: 0,
657
- }
658
- });
659
- Object.assign(status, data);
660
- // Response.
661
- return stream.send({
662
- status: 200,
663
- headers: { "Content-Type": "application/json" },
664
- data: status,
665
- });
666
- },
667
- });
668
- }
669
- // Create the sitemap endpoint.
670
- async _create_sitemap() {
671
- // Logs.
672
- this.log(2, "Creating sitemap.");
673
- let sitemap = "";
674
- sitemap += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
675
- sitemap += "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
676
- for (const endpoint of this.endpoints.values()) {
677
- if (endpoint.allow_sitemap) {
678
- if (endpoint.route.is_regex)
679
- continue; // skip regex routes
680
- const ep = encodeURI(endpoint.route.endpoint_str.startsWith("/")
681
- ? endpoint.route.endpoint_str
682
- : `/${endpoint.route.endpoint_str}`);
683
- sitemap += `<url>\n <loc>${this.full_domain}${ep}</loc>\n</url>\n`;
684
- }
685
- }
686
- this.additional_sitemap_endpoints.forEach((endpoint) => {
687
- while (endpoint.length > 0 && endpoint.charAt(0) === "/") {
688
- endpoint = endpoint.substr(1);
689
- }
690
- sitemap += `<url>\n <loc>${this.full_domain}/${endpoint}</loc>\n</url>\n`;
691
- });
692
- sitemap += "</urlset>\n";
693
- this.endpoint({
694
- method: "GET",
695
- endpoint: "/sitemap.xml",
696
- data: sitemap,
697
- content_type: "application/xml",
698
- _compress: false,
699
- });
700
- }
701
- // Create the robots.txt endpoint.
702
- async _create_robots_txt() {
703
- // Logs.
704
- this.log(2, "Creating robots.txt.");
705
- // Proceed.
706
- let robots = "User-agent: *\n";
707
- let disallowed = 0;
708
- for (const endpoint of this.endpoints.values()) {
709
- if (!endpoint.allow_robots) {
710
- robots += `Disallow: ${endpoint.route.endpoint_str}\n`; // @todo not compatiable with regex endpoints
711
- disallowed++;
712
- }
713
- }
714
- if (disallowed === 0) {
715
- robots += `Disallow: \n`;
716
- }
717
- robots += `\nSitemap: ${this.full_domain}/sitemap.xml`;
718
- this.endpoint({
719
- method: "GET",
720
- endpoint: "/robots.txt",
721
- content_type: "text/plain",
722
- data: robots,
723
- _compress: false,
724
- });
725
- }
726
- // Create admin endpoint.
727
- // @deprecated use MongoDB Atlas instead!
728
- /* private _create_admin_endpoint(): void {
729
-
730
- // Logs.
731
- this.log(2, "Creating admin endpoint.");
732
-
733
- // Add admin tokens.
734
- this.admin.tokens = [];
735
-
736
- // Verify token.
737
- const verify_token = (token: string): boolean => {
738
- const now = Date.now();
739
- let new_tokens: Array<{token: string, expiration: number}> = [];
740
- let verified = false;
741
- this.admin.tokens!.forEach((i) => {
742
- if (now < i.expiration) {
743
- if (i.token === token) {
744
- verified = true;
745
- }
746
- new_tokens.push(i);
747
- }
748
- })
749
- this.admin.tokens = new_tokens;
750
- return verified;
751
- }
752
-
753
- // Admin data.
754
- this.endpoint({
755
- method: "POST",
756
- endpoint: "/admin/auth",
757
- content_type: "application/json",
758
- rate_limit: {
759
- group: "volt.admin.auth",
760
- limit: 5,
761
- interval: 60,
762
- },
763
- params: {
764
- password: "string",
765
- },
766
- ip_whitelist: this.admin.ips,
767
- callback: async (stream: Stream, params: {password: string}) => {
768
- // Check key.
769
- if (params.password !== this.admin.password) {
770
- return stream.send({
771
- status: 403,
772
- headers: {"Content-Type": "text/plain"},
773
- data: "Access Denied",
774
- })
775
- }
776
-
777
- // Generate token.
778
- const token = {
779
- token: String.random(32),
780
- expiration: Date.now() + 3600 * 1000,
781
- };
782
- this.admin.tokens!.push(token)
783
-
784
- // Response.
785
- return stream.send({
786
- status: 200,
787
- headers: {"Content-Type": "application/json"},
788
- data: token,
789
- })
790
- },
791
- })
792
-
793
- // Admin data.
794
- this.endpoint({
795
- method: "GET",
796
- endpoint: "/admin/data",
797
- content_type: "application/json",
798
- rate_limit: "global",
799
- params: {
800
- token: "string",
801
- },
802
- ip_whitelist: this.admin.ips,
803
- callback: async (stream: Stream, params: {token: string}) => {
804
- // Verify token.
805
- if (!verify_token(params.token)) {
806
- return stream.send({
807
- status: 403,
808
- headers: {"Content-Type": "text/plain"},
809
- data: "Access Denied",
810
- })
811
- }
812
-
813
- // Data.
814
- const data: Record<string, any> = {};
815
-
816
- // Parse subscriptions.
817
- const subscriptions = await this.payments._get_all_active_subscriptions();
818
- data.subscriptions = subscriptions.length;
819
-
820
- // Load data.
821
- const status = await this._sys_db.load("status", {
822
- default: {
823
- running_since: null,
824
- running_threads: 0,
825
- total_threads: 0,
826
- }
827
- });
828
- Object.assign(data, status);
829
-
830
- // System data.
831
- data.cpu_usage = vlib.System.cpu_usage();
832
- data.memory_usage = vlib.System.memory_usage();
833
- data.network_usage = await vlib.System.network_usage();
834
-
835
- // Users.
836
- data.users = (await this.users.list()).length;
837
-
838
- // Response.
839
- return stream.send({
840
- status: 200,
841
- headers: {"Content-Type": "application/json"},
842
- data: data,
843
- })
844
- },
845
- })
846
-
847
- // Admin view.
848
- this.endpoint({
849
- method: "GET",
850
- endpoint: "/admin",
851
- content_type: "application/json",
852
- rate_limit: "global",
853
- params: {
854
- password: "string",
855
- },
856
- ip_whitelist: this.admin.ips,
857
- sitemap: false,
858
- robots: false,
859
- view: {
860
- templates: {
861
- DOMAIN: this.domain,
862
- },
863
- callback: () => {
864
- // Style.
865
- const style = {
866
- bg: "#F2F3F6",
867
- sub_bg: "#FAFAFA",
868
- fg: "#000000",
869
- sub_fg: "#9099B4",
870
- border: "#D6D6D6",
871
- tint: "#64B878", //"#8EB8EB", //"#4E9CF7",
872
- }
873
-
874
- // ... rest of the admin view implementation remains the same as it's client-side JavaScript ...
875
- },
876
- },
877
- })
878
- } */
879
- // Initialize statics.
880
- async _initialize_statics() {
881
- // Logs.
882
- this.log(2, "Initializing static directories.");
883
- // Static paths for the file watcher.
884
- const static_paths = [];
885
- // Add static file.
886
- const add_static_file = async (path, // vlib.Path type
887
- endpoint, cache = true) => {
888
- // Logs.
889
- // this.log(3, "Adding static file " + path.str())
890
- // Add to static paths.
891
- static_paths.push(path.str());
892
- // console.log("Add static file", endpoint, path.str())
893
- // Image endpoint with supported transformation.
894
- if (ImageEndpoint.supported_images.has(path.extension())) {
895
- const e = new ImageEndpoint({
896
- endpoint,
897
- path,
898
- cache,
899
- rate_limit: "global",
900
- _is_static: true,
901
- });
902
- const aspect_ratio = await e.get_aspect_ratio();
903
- if (aspect_ratio != null) {
904
- this.statics_aspect_ratios.set(e.route.endpoint_str, aspect_ratio);
905
- }
906
- this.endpoint(e);
907
- }
908
- // Default static endpoint.
909
- else {
910
- // Create endpoint.
911
- this.endpoint(new Endpoint({
912
- method: "GET",
913
- endpoint,
914
- cache,
915
- rate_limit: "global",
916
- file_path: path,
917
- _is_static: true,
918
- }));
919
- }
920
- };
921
- // Initialize statics.
922
- const add_static = async (opts) => {
923
- if (opts == null) {
924
- return;
925
- }
926
- if (typeof opts === "object") {
927
- this.log(3, "Adding static directory " + opts.path);
928
- // Check object.
929
- vlib.schema.validate(opts, {
930
- unknown: false,
931
- throw: true,
932
- schema: {
933
- path: "string",
934
- endpoint: { type: "string", default: null },
935
- cache: { type: ["boolean", "number"], default: true },
936
- endpoints_cache: { type: "object", default: {} },
937
- exclude: { type: "array", default: [] },
938
- }
939
- });
940
- // Vars.
941
- const paths = [];
942
- const source = new vlib.Path(opts.path).abs();
943
- if (!source.exists()) {
944
- this.log(1, `Static path "${source.str()}" does not exist; skipping.`);
945
- return;
946
- }
947
- const source_len = source.str().length;
948
- const is_dir = source.is_dir();
949
- // Is excluded.
950
- const exclude = [/\.DS_Store$/, /\.cache(?:\/|$)/, /\.old(?:\/|$)/, /\.ignore$/, ...(opts.exclude || [])];
951
- const is_excluded = (p) => {
952
- const s = typeof p === "string" ? p : p.str();
953
- return exclude.some(pattern => pattern instanceof RegExp ? pattern.test(s) : s === String(pattern));
954
- };
955
- // Initialize endpoint.
956
- opts.endpoint = opts.endpoint || `/${source.full_name()}`;
957
- if (opts.endpoint.charAt(0) != "/") {
958
- opts.endpoint = "/" + opts.endpoint;
959
- }
960
- while (opts.endpoint.charAt(opts.endpoint.length - 1) == "/") {
961
- opts.endpoint = opts.endpoint.slice(0, -1);
962
- }
963
- // Not a directory.
964
- if (!is_dir) {
965
- return await add_static_file(source, opts.endpoint, opts.cache);
966
- }
967
- // First extract all paths recursively.
968
- // non recursive to ignore .old etc dirs.
969
- const read_dir = async (path) => {
970
- const dir_paths = await path.paths();
971
- const promises = [];
972
- for (let i = 0; i < dir_paths.length; i++) {
973
- if (!is_excluded(dir_paths[i])) {
974
- // @todo excluded does not work `.old` etc is still included and DS_Store.
975
- if (dir_paths[i].is_dir()) {
976
- promises.push(read_dir(dir_paths[i]));
977
- }
978
- else {
979
- paths.push(dir_paths[i]);
980
- }
981
- }
982
- }
983
- ;
984
- await Promise.all(promises);
985
- };
986
- if (is_dir) {
987
- await read_dir(source);
988
- }
989
- // Convert paths into a static object.
990
- for (const path of paths) {
991
- const endpoint = `${opts.endpoint}${path.str().substr(source_len)}`;
992
- await add_static_file(path, endpoint, opts.endpoints_cache === undefined ? opts.cache : opts.endpoints_cache[endpoint] ?? opts.cache);
993
- }
994
- }
995
- else if (typeof opts === "string") {
996
- await add_static({ path: opts });
997
- }
998
- };
999
- // Iterate.
1000
- for (let i = 0; i < this.statics.length; i++) {
1001
- if (this.statics[i] instanceof vlib.Path) {
1002
- this.statics[i] = this.statics[i].str();
1003
- }
1004
- await add_static(this.statics[i]);
1005
- }
1006
- // Response.
1007
- return static_paths;
1008
- }
1009
- /** Initialize the system and user defined keys. */
1010
- async _initialize_keys() {
1011
- // Await database initialization.
1012
- const start = Date.now();
1013
- await this._db_init_promise;
1014
- /* @performance */ this.performance.end("_initialize_keys():await-db-init", start);
1015
- // Load system keys.
1016
- const sys_keys = await this._sys_keys_db.load({ id: "sys_keys" }, {
1017
- default: {
1018
- id: "sys_keys",
1019
- rate_limit_api_key: undefined,
1020
- }
1021
- });
1022
- let perform_sys_keys_save = false;
1023
- // Check rate limit api key.
1024
- if (sys_keys.rate_limit_api_key == null) {
1025
- this.rate_limit_api_key = this.generate_crypto_key(32);
1026
- sys_keys.rate_limit_api_key = this.rate_limit_api_key;
1027
- perform_sys_keys_save = true;
1028
- }
1029
- else {
1030
- this.rate_limit_api_key = sys_keys.rate_limit_api_key;
1031
- }
1032
- // Save.
1033
- if (perform_sys_keys_save) {
1034
- await this._sys_keys_db.set({ id: "sys_keys" }, sys_keys);
1035
- }
1036
- // Check user defined crypto keys.
1037
- const user_keys = await this._keys_db.load({ id: "user_keys" }, {
1038
- default: {
1039
- id: "user_keys",
1040
- keys: {},
1041
- }
1042
- });
1043
- let perform_user_keys_save = false;
1044
- for (const key of this._user_keys_opts) {
1045
- const name = typeof key === "string" ? key : key.name;
1046
- if (user_keys[name]) {
1047
- this.keys[name] = user_keys[name];
1048
- }
1049
- else {
1050
- perform_user_keys_save = true;
1051
- if (typeof key === "string") {
1052
- if (!key) {
1053
- throw Error(`Crypto key "${key}" is an invalid key name.`);
1054
- }
1055
- const generated_key = this.generate_crypto_key(32);
1056
- user_keys.keys[key] = generated_key;
1057
- this.keys[key] = generated_key;
1058
- }
1059
- else {
1060
- if (!key.name) {
1061
- throw Error(`Crypto key "${key.name}" is an invalid key name.`);
1062
- }
1063
- if (key.length == null) {
1064
- throw Error(`Crypto key "${key.name}" does not contain a "length" attribute.`);
1065
- }
1066
- if (typeof key.length !== "number") {
1067
- throw Error(`Crypto key "${key.name}" has an invalid type for attribute "length", the valid type is "number".`);
1068
- }
1069
- const generated_key = this.generate_crypto_key(key.length);
1070
- user_keys.keys[key.name] = generated_key;
1071
- this.keys[key.name] = generated_key;
1072
- }
1073
- }
1074
- }
1075
- if (perform_user_keys_save) {
1076
- await this._keys_db.set({ id: "user_keys" }, user_keys);
1077
- }
1078
- }
1079
- /**
1080
- * Checks if an endpoint route already exists.
1081
- * @param method HTTP method
1082
- * @param endpoint String path or RegExp
1083
- */
1084
- _check_duplicate_route(route) {
1085
- const e = this.find_endpoint(route);
1086
- if (e) {
1087
- throw new Error(`Duplicate "${route.method}:${route.endpoint_str}" endpoint route, it is already defined by endpoint "${e.id}".`);
1088
- }
1089
- }
1090
- // Serve a client.
1091
- // @todo implement rate limiting.
1092
- // @todo save internal server errors.
1093
- async _serve(http2_stream, headers, req, res) {
1094
- try {
1095
- // Convert stream.
1096
- const stream = new Stream(http2_stream, headers, req, res);
1097
- // Vars.
1098
- let endpoint;
1099
- let method;
1100
- let endpoint_url;
1101
- // Log endpoint result.
1102
- const log_endpoint_result = (message, status) => {
1103
- let log_level = endpoint && endpoint.is_static ? 3 : 0;
1104
- if (status == null) {
1105
- status = stream.status_code;
1106
- }
1107
- this.log(log_level, `${method}:${endpoint_url}: ${message ? message : Status.get_description(status ?? "unknown")} [${status}] (${stream.ip}).`);
1108
- };
1109
- // Serve error endpoint.
1110
- const serve_error_endpoint = async (status_code) => {
1111
- // Get default response.
1112
- const is_api_endpoint = endpoint && endpoint.callback != null;
1113
- let default_response;
1114
- switch (status_code) {
1115
- case 400:
1116
- default_response = {
1117
- status: 400,
1118
- headers: { "Content-Type": is_api_endpoint ? "application/json" : "text/plain" },
1119
- data: is_api_endpoint ? { error: "Bad Request" } : "Bad Request",
1120
- };
1121
- break;
1122
- case 403:
1123
- default_response = {
1124
- status: 403,
1125
- headers: { "Content-Type": is_api_endpoint ? "application/json" : "text/plain" },
1126
- data: is_api_endpoint ? { error: "Access Denied" } : "Access Denied",
1127
- };
1128
- break;
1129
- case 404:
1130
- default_response = {
1131
- status: 404,
1132
- headers: { "Content-Type": is_api_endpoint ? "application/json" : "text/plain" },
1133
- data: is_api_endpoint ? { error: "Not Found" } : "Not Found",
1134
- };
1135
- break;
1136
- case 500:
1137
- default:
1138
- default_response = {
1139
- status: 500,
1140
- headers: { "Content-Type": is_api_endpoint ? "application/json" : "text/plain" },
1141
- data: is_api_endpoint ? { error: "Internal Server Error" } : "Internal Server Error",
1142
- };
1143
- break;
1144
- }
1145
- // Serve error endpoint or default response.
1146
- if (!this.err_endpoints.has(status_code)) {
1147
- stream.send(default_response);
1148
- }
1149
- else {
1150
- const err_endpoint = this.err_endpoints.get(status_code);
1151
- // if (typeof err_endpoint === "function") {
1152
- // const res = await err_endpoint({
1153
- // status: status_code,
1154
- // });
1155
- // if (res instanceof Endpoint) {
1156
- // err_endpoint = res;
1157
- // } else {
1158
- // err_endpoint = new Endpoint(res);
1159
- // }
1160
- // err_endpoint._initialize(this);
1161
- // }
1162
- try {
1163
- await err_endpoint.serve({ stream, status: status_code });
1164
- }
1165
- catch (err) {
1166
- this.log.error(`Error endpoint ${status_code}: `, err);
1167
- stream.send(default_response);
1168
- }
1169
- }
1170
- };
1171
- // Check ip against blacklist.
1172
- // if (!this.offline && this.blacklist !== undefined && !this.blacklist.verify(stream.ip)) {
1173
- // await serve_error_endpoint(403);
1174
- // this.log_endpoint_result();
1175
- // return;
1176
- // }
1177
- // Check if the request matches any of the defined endpoints.
1178
- method = stream.method;
1179
- endpoint_url = stream.endpoint;
1180
- // endpoint = this._find_endpoint(endpoint_url, method);
1181
- // Find endpoint manually so the optional path params can be extracted.
1182
- this.log(3, "Searching for endpoint: ", `${method}:${endpoint_url}`);
1183
- endpoint = this.endpoints.get(`${method}:${endpoint_url}`);
1184
- if (!endpoint) {
1185
- // Check regex endpoints.
1186
- const route = new Route(method, endpoint_url);
1187
- for (const e of this.endpoints.values()) {
1188
- if (e.route.is_regex) {
1189
- const matched_params = e.route.match(route);
1190
- if (matched_params !== false) {
1191
- this.log(3, "Matched regex route: ", e.route.id);
1192
- endpoint = e;
1193
- // insert path params into the stream when not already defined.
1194
- Object.keys(matched_params).walk((k) => {
1195
- if (stream.params[k] == null) {
1196
- stream.params[k] = matched_params[k];
1197
- }
1198
- });
1199
- break;
1200
- }
1201
- }
1202
- }
1203
- }
1204
- else {
1205
- this.log(3, "Matched route: ", endpoint.route.id);
1206
- }
1207
- // No endpoint found.
1208
- if (!endpoint) {
1209
- // Check OPTIONS request.
1210
- if (method === "OPTIONS") {
1211
- const original_method = stream.headers['access-control-request-method'];
1212
- const original_endpoint = this.find_endpoint(endpoint_url, original_method);
1213
- if (original_endpoint) {
1214
- // Set headers.
1215
- this._set_header_defaults(stream);
1216
- original_endpoint._set_headers(stream);
1217
- // Send.
1218
- stream.send({ status: Status.no_content });
1219
- log_endpoint_result();
1220
- return;
1221
- }
1222
- }
1223
- // Respond with 404.
1224
- await serve_error_endpoint(404);
1225
- log_endpoint_result();
1226
- return;
1227
- }
1228
- // ------------------------------------------
1229
- // Header & options
1230
- // Set all headers so we can send options.
1231
- // Set default headers.
1232
- this._set_header_defaults(stream);
1233
- // Serve options request.
1234
- if (method === "OPTIONS") {
1235
- try {
1236
- await endpoint._serve_options(stream);
1237
- }
1238
- catch (err) {
1239
- this.log.error(`${method}:${endpoint_url}: `, err);
1240
- if (!stream.destroyed && !stream.finished) {
1241
- await serve_error_endpoint(500);
1242
- log_endpoint_result();
1243
- }
1244
- return;
1245
- }
1246
- log_endpoint_result();
1247
- return;
1248
- }
1249
- // Check rate limit.
1250
- if (!this.offline && this.production && this.rate_limit !== undefined && endpoint.rate_limit_groups.length > 0) {
1251
- const result = await this.rate_limit.limit(stream.ip, endpoint.rate_limit_groups);
1252
- if (result != null) {
1253
- stream.send({
1254
- status: 429,
1255
- headers: {
1256
- "Content-Type": "text/plain",
1257
- "X-RateLimit-Reset": result,
1258
- },
1259
- data: `Rate limit exceeded, please try again in ${Math.floor((result - Date.now()) / 1000)} seconds.`,
1260
- });
1261
- log_endpoint_result();
1262
- return;
1263
- }
1264
- }
1265
- // Parse the request parameters.
1266
- try {
1267
- await stream.join();
1268
- }
1269
- catch (err) {
1270
- this.log.error(`${method}:${endpoint_url}: `, err);
1271
- await serve_error_endpoint(500);
1272
- log_endpoint_result();
1273
- return;
1274
- }
1275
- try {
1276
- stream._parse_params();
1277
- }
1278
- catch (err) {
1279
- this.log.error(`${method}:${endpoint_url}: `, err);
1280
- await serve_error_endpoint(400);
1281
- log_endpoint_result();
1282
- return;
1283
- }
1284
- // Do not authenticate on static endpoints, unless "authenticated" flag is somehow enabled.
1285
- if (!endpoint.is_static || endpoint.authenticated) {
1286
- // Always perform authentication so the stream.uid will also be assigned even when the endpoint is not authenticated.
1287
- const auth_result = await this.users._authenticate(stream);
1288
- // Reset cookies when authentication has failed.
1289
- if (auth_result != null && !endpoint.is_static) {
1290
- this.users._reset_cookies(stream);
1291
- }
1292
- // When the endpoint has a view or is text/html then redirect to signin page.
1293
- if (auth_result != null && !endpoint.is_static && (endpoint.view != null || endpoint.content_type === "text/html")) {
1294
- stream.set_header("Location", `/signin?next=${encodeURIComponent(stream.endpoint)}`);
1295
- }
1296
- // When the endpoint is authenticated and the authentication has failed then send the error response.
1297
- if (auth_result != null && endpoint.authenticated) {
1298
- stream.send(auth_result);
1299
- log_endpoint_result();
1300
- return;
1301
- }
1302
- }
1303
- // Serve endpoint.
1304
- try {
1305
- await endpoint.serve({ stream });
1306
- }
1307
- catch (err) {
1308
- this.log.error(`${method}:${endpoint_url}: `, err);
1309
- if (!stream.destroyed && !stream.finished) {
1310
- await serve_error_endpoint(500);
1311
- log_endpoint_result();
1312
- }
1313
- return;
1314
- }
1315
- // Check if the response has been sent.
1316
- if (!stream.finished) {
1317
- this.log.error(`${method}:${endpoint_url}: `, "Unfinished response.");
1318
- await serve_error_endpoint(500);
1319
- log_endpoint_result();
1320
- return;
1321
- }
1322
- // Log.
1323
- log_endpoint_result();
1324
- }
1325
- catch (err) {
1326
- this.log.error(err);
1327
- }
1328
- }
1329
- // ---------------------------------------------------------
1330
- // Server (private).
1331
- /** The promise of database initialization and connecting. */
1332
- _db_init_promise;
1333
- /** Is initialized. */
1334
- _initialized = false;
1335
- /** Is initialized by a worker. */
1336
- _initialized_by_worker = false;
1337
- /**
1338
- * Initialize the server.
1339
- * @returns A promise that resolves when the server has been initialized.
1340
- * @docs
1341
- */
1342
- async initialize({ worker = false, } = {}) {
1343
- // Already initialized.
1344
- if (this._initialized) {
1345
- return;
1346
- }
1347
- this._initialized = true;
1348
- this._initialized_by_worker = worker;
1349
- // Logs.
1350
- this.log(1, "Initializing server.");
1351
- /* @performance */ const initialize_start = Date.now();
1352
- /* @performance */ this.performance.start();
1353
- // Initialize the database & connect first since this takes the longest.
1354
- this._db_init_promise = (async () => {
1355
- /* @performance */ let start = Date.now();
1356
- await this.db.initialize();
1357
- /* @performance */ this.performance.end("init-db", start);
1358
- /* @performance */ start = Date.now();
1359
- await this.db.connect();
1360
- /* @performance */ this.performance.end("connect-db", start);
1361
- })();
1362
- // Remove and create the endpoint cache dir.
1363
- if (this.endpoint_cache_dir.exists()) {
1364
- await this.endpoint_cache_dir.del({ recursive: true });
1365
- }
1366
- await this.endpoint_cache_dir.mkdir({ recursive: true });
1367
- // Create HTTPS server.
1368
- if (!worker) {
1369
- if (this.tls) {
1370
- this.https = http2.createSecureServer({
1371
- key: new vlib.Path(this.tls.key).load_sync({ encoding: 'utf8' }),
1372
- cert: new vlib.Path(this.tls.cert).load_sync({ encoding: 'utf8' }),
1373
- ca: this.tls.ca == null ? undefined : new vlib.Path(this.tls.ca).load_sync({ encoding: 'utf8' }),
1374
- passphrase: this.tls.passphrase,
1375
- allowHTTP1: true,
1376
- });
1377
- this.https.on('stream', (stream, headers) => {
1378
- this._serve(stream, headers, undefined, undefined);
1379
- });
1380
- // HTTP/1.1 (compatibility 'request' is also emitted for HTTP/2; filter it out)
1381
- this.https.on("request", (req, res) => {
1382
- if (req.httpVersionMajor === 1) {
1383
- this._serve(undefined, undefined, req, res);
1384
- }
1385
- });
1386
- }
1387
- // Payments require HTTPS in production.
1388
- else if (this.production && this.payments) {
1389
- throw Error("Accepting payments in production mode requires HTTPS.");
1390
- }
1391
- /* @performance */ this.performance.end("create-https-server");
1392
- // Create http server.
1393
- if (this.tls) {
1394
- // Redirect HTTP requests to HTTPS.
1395
- this.http = http.createServer((request, response) => {
1396
- const reqUrl = typeof request.url === "string" ? request.url : "/";
1397
- // Build redirect using the canonical configured domain, not the untrusted Host header.
1398
- const location = `https://${this.domain}${reqUrl}`;
1399
- // 308 preserves method and body; safe for non-GET as well.
1400
- response.writeHead(308, { Location: location });
1401
- response.end();
1402
- });
1403
- }
1404
- else {
1405
- // Serve http.
1406
- this.http = http.createServer((req, res) => {
1407
- this._serve(undefined, undefined, req, res);
1408
- });
1409
- }
1410
- /* @performance */ this.performance.end("create-http-server");
1411
- // Initialize default headers.
1412
- this._init_default_headers();
1413
- /* @performance */ this.performance.end("init-default-headers");
1414
- // Create default endpoints.
1415
- this._create_default_endpoints();
1416
- /* @performance */ this.performance.end("create-default-endpoints");
1417
- // Create admin endpoints.
1418
- // this._create_admin_endpoint();
1419
- // /* @performance */ this.performance.end("create-admin-endpoints");
1420
- // Create static endpoints.
1421
- await this._initialize_statics();
1422
- /* @performance */ this.performance.end("_initialize_statics()");
1423
- }
1424
- /**
1425
- * Initialize keys.
1426
- * Its required to await this in case no keys exist.
1427
- * If in this case a user would perform any key requiring operations inside an
1428
- * "initialize" callback, then it would not yet be created.
1429
- */
1430
- await this._initialize_keys();
1431
- /* @performance */ this.performance.end("load-keys");
1432
- // Add promises using the database.
1433
- const promises = [];
1434
- /* @performance */ this.performance.start();
1435
- // Initialize users.
1436
- promises.push(this.users._initialize({ worker }));
1437
- // /* @performance */ this.performance.end("users._initialize()");
1438
- // Payments.
1439
- if (this.payments !== undefined) {
1440
- if (this.payments.type === "stripe") {
1441
- promises.push(this.payments.initialize());
1442
- }
1443
- // else if (this.payments.type === "paddle") {
1444
- // promises.push(this.payments._initialize({ worker }));
1445
- // }
1446
- else {
1447
- // @ts-expect-error
1448
- this.payments.type.toString();
1449
- throw Error(`Unsupported payments provider "${this.payments.type}".`);
1450
- }
1451
- // /* @performance */ this.performance.end("payments._initialize()");
1452
- }
1453
- if (!worker) {
1454
- // Create sitemap when it does not exist.
1455
- // Must be done at the end of initialization func since some funcs might still create endpoints.
1456
- if (this.find_endpoint("/sitemap.xml") == null) {
1457
- promises.push(this._create_sitemap());
1458
- // /* @performance */ this.performance.end("_create_sitemap()");
1459
- }
1460
- // Create robots.txt when it does not exist.
1461
- // Must be done at the end of initialization func since some funcs might still create endpoints.
1462
- if (this.find_endpoint("/robots.txt") == null) {
1463
- promises.push(this._create_robots_txt());
1464
- // /* @performance */ this.performance.end("_create_robots_txt()");
1465
- }
1466
- }
1467
- // Get the icon and stroke icon file paths when defined.
1468
- if (this.company.stroke_icon || this.company.icon) {
1469
- for (const endpoint of this.endpoints.values()) {
1470
- if (this.company.stroke_icon_path == null && endpoint.route.endpoint === this.company.stroke_icon) {
1471
- this.company.stroke_icon_path = endpoint.file_path?.str() || undefined;
1472
- }
1473
- if (this.company.icon_path == null && endpoint.route.endpoint === this.company.icon) {
1474
- this.company.icon_path = endpoint.file_path?.str() || undefined;
1475
- }
1476
- }
1477
- if (this.company.stroke_icon != null && this.company.stroke_icon_path == null) {
1478
- throw Error(`Unable to find the company's stroke icon endpoint "${this.company.stroke_icon}", consider defining the "company.stroke_icon_path" property.`);
1479
- }
1480
- if (this.company.icon != null && this.company.icon_path == null) {
1481
- throw Error(`Unable to find the company's icon endpoint "${this.company.icon}", consider defining the "company.icon_path" property.`);
1482
- }
1483
- }
1484
- // Await all promises.
1485
- await Promise.all(promises);
1486
- /* @performance */ this.performance.end("awaiting-promise-list");
1487
- // Initialize all endpoints.
1488
- if (!worker) {
1489
- this.performance.start();
1490
- for (const endpoint of this.endpoints.values()) {
1491
- endpoint._initialize(this);
1492
- }
1493
- for (const endpoint of this.err_endpoints.values()) {
1494
- endpoint._initialize(this);
1495
- }
1496
- /* @performance */ this.performance.end("initialize-endpoints");
1497
- }
1498
- // On initialize callbacks.
1499
- for (const callback of this.events.get("initialize")) {
1500
- await callback({ worker });
1501
- }
1502
- /* @performance */ this.performance.end("on-initialize-callbacks");
1503
- /* @performance */ this.performance.end("initialize()", initialize_start);
1504
- }
1505
- find_endpoint(endpoint, method) {
1506
- let route;
1507
- if (endpoint instanceof Route) {
1508
- route = endpoint;
1509
- endpoint = route.endpoint_str;
1510
- method = route.method;
1511
- }
1512
- method ??= "GET";
1513
- const result = this.endpoints.get(`${method}:${endpoint}`);
1514
- if (!result) {
1515
- if (!route)
1516
- route = new Route(method, endpoint);
1517
- for (const e of this.endpoints.values()) {
1518
- if (e.route.is_regex && e.route.match(route)) {
1519
- return e;
1520
- }
1521
- }
1522
- }
1523
- return result;
1524
- }
1525
- // ---------------------------------------------------------
1526
- // Server.
1527
- /**
1528
- * Start the server.
1529
- *
1530
- * @example
1531
- * {Start}
1532
- * Start the server.
1533
- * ```
1534
- * const server = new volt.Server({ ... });
1535
- * await server.start();
1536
- * ```
1537
- * @docs
1538
- */
1539
- async start() {
1540
- // If we are initialized by a worker then throw an error.
1541
- if (this._initialized_by_worker) {
1542
- throw Error("Cannot start the server when it is initialized as a worker by 'Server.initialize({ worker: true })'.");
1543
- }
1544
- // Always initialize, even when forking.
1545
- await this.initialize();
1546
- // On production also exec the endpoint production init.
1547
- if (this.production) {
1548
- for (const endpoint of this.endpoints.values()) {
1549
- if (endpoint.view) {
1550
- await endpoint.view.production_initialize();
1551
- }
1552
- }
1553
- }
1554
- // Start the rate limiting client/server, also when forking.
1555
- if (this.rate_limit) {
1556
- /* @performance */ this.performance.start();
1557
- await this.rate_limit.start();
1558
- /* @performance */ this.performance.end("init-rate-limit");
1559
- }
1560
- // Production & Master.
1561
- let forked = false;
1562
- if (this.production && this.threading.enabled && libcluster.isPrimary && this.threading.threads > 1) {
1563
- this.log(0, `Starting ${this.threading.threads} threads.`);
1564
- // Vars.
1565
- let active_threads = 0;
1566
- const thread_ids = {};
1567
- const restart_limiters = {};
1568
- // Start thread.
1569
- const start_thread = (thread_id, restart = false) => {
1570
- // Fork.
1571
- const worker = libcluster.fork();
1572
- // Log.
1573
- this.log(restart ? 0 : 1, `Starting thread ${worker.process.pid}.`);
1574
- // Cache thread id.
1575
- thread_ids[worker.process.pid] = thread_id;
1576
- // Increment active threads.
1577
- ++active_threads;
1578
- };
1579
- // Fork workers.
1580
- for (let i = 0; i < this.threading.threads; i++) {
1581
- // Generate thread id.
1582
- let thread_id;
1583
- while ((thread_id = vlib.String.random(8)) && Object.values(thread_ids).includes(thread_id)) { }
1584
- // Create limiter.
1585
- restart_limiters[thread_id] = new vlib.TimeLimiter({ limit: 3, duration: 60 * 1000 });
1586
- // Start thread.
1587
- start_thread(thread_id);
1588
- }
1589
- // Save status.
1590
- await this._website_status_db.set({ id: "status" }, {
1591
- running_since: Date.now(),
1592
- total_threads: active_threads,
1593
- running_threads: active_threads,
1594
- });
1595
- // On exit.
1596
- libcluster.addListener('exit', async (worker, code, signal) => {
1597
- // Fetch thread id.
1598
- const thread_id = thread_ids[worker.process.pid];
1599
- delete thread_ids[worker.process.pid];
1600
- // Logs.
1601
- this.log.error(`Thread ${worker.process.pid} crashed.`);
1602
- // Restart with limit.
1603
- const limiter = restart_limiters[thread_id];
1604
- if (limiter != null && limiter.limit()) {
1605
- --active_threads;
1606
- start_thread(thread_id, true);
1607
- }
1608
- // Reached limit, shutdown thread.
1609
- else {
1610
- this.log.error(`Thread ${worker.process.pid} is being shut down due to its periodic restart limit.`);
1611
- --active_threads;
1612
- await this._website_status_db.save({ id: "status" }, { $inc: { running_threads: -1 } });
1613
- if (active_threads === 0) {
1614
- this.log.error(`All threads died, stopping server.`);
1615
- process.exit(0);
1616
- }
1617
- }
1618
- });
1619
- // Close the database connections on master.
1620
- await this.db.close();
1621
- //
1622
- // Ensure we dont spawn server listener here, to keep correct architecture.
1623
- //
1624
- }
1625
- else {
1626
- forked = this.production && this.threading.enabled;
1627
- // Load worker class modules.
1628
- // if (libcluster.isWorker) {
1629
- // const worker = new WorkerClass();
1630
- // worker.start();
1631
- // }
1632
- // Callbacks.
1633
- let is_running = false;
1634
- const on_running = () => {
1635
- if (!is_running) {
1636
- is_running = true;
1637
- if (this.https !== undefined) {
1638
- this.log(0, `Running on http://${this.ip}:${this.port} and https://${this.ip}:${this.https_port}.`);
1639
- }
1640
- else {
1641
- this.log(0, `Running on http://${this.ip}:${this.port}.`);
1642
- }
1643
- }
1644
- };
1645
- const on_error = (error) => {
1646
- if (error.syscall !== 'listen') {
1647
- throw error;
1648
- }
1649
- switch (error.code) {
1650
- case 'EACCES':
1651
- console.error(`Error: Address ${this.ip}:${this.port} requires elevated privileges.`);
1652
- process.exit(1);
1653
- break;
1654
- case 'EADDRINUSE':
1655
- console.error(`Error: Address ${this.ip}:${this.port} is already in use.`);
1656
- process.exit(1);
1657
- break;
1658
- default:
1659
- throw error;
1660
- }
1661
- };
1662
- // Listen.
1663
- this.http.listen(this.port, this.ip === "*" ? undefined : this.ip, on_running);
1664
- this.http.on("error", on_error);
1665
- if (this.https !== undefined) {
1666
- this.https.listen(this.https_port, this.ip === "*" ? undefined : this.ip, on_running);
1667
- this.https.on("error", on_error);
1668
- }
1669
- // Set signals.
1670
- let graceful_shutdown_shutting_down = false;
1671
- const graceful_shutdown = async () => {
1672
- if (graceful_shutdown_shutting_down)
1673
- return;
1674
- graceful_shutdown_shutting_down = true;
1675
- try {
1676
- await this.stop();
1677
- }
1678
- catch (e) {
1679
- this.log.error("Shutdown error:", e);
1680
- }
1681
- finally {
1682
- process.exit(0);
1683
- }
1684
- };
1685
- process.on('SIGTERM', graceful_shutdown);
1686
- process.on('SIGINT', graceful_shutdown);
1687
- // Send running message.
1688
- if (process.env.VOLT_FILE_WATCHER === "1") {
1689
- new vlib.Path(process.env.VOLT_STARTED_FILE).save_sync("1");
1690
- }
1691
- // Start browser.
1692
- // if (this.browser_preview) {
1693
- // await this.browser_preview.start();
1694
- // await this.browser_preview.navigate(this.full_domain);
1695
- // }
1696
- /* @performance */ this.performance.end("listen");
1697
- }
1698
- // On start callbacks.
1699
- this.performance.start();
1700
- for (const callback of this.events.get("start")) {
1701
- const res = callback({ forked });
1702
- if (res instanceof Promise) {
1703
- await res;
1704
- }
1705
- }
1706
- /* @performance */ this.performance.end("on-start-callbacks");
1707
- // Start browser preview on primary node.
1708
- // if (this.browser_preview && !forked) {
1709
- // await this.browser_preview.start();
1710
- // await this.browser_preview.navigate(this.full_domain);
1711
- // }
1712
- /* @performance */
1713
- console.log(this.performance.dump());
1714
- // console.log(this.performance.dump(v => v >= 50));
1715
- // debug(2, () => this.performance.dump(v => v >= 50));
1716
- }
1717
- /**
1718
- * Stop the server.
1719
- * @note After stopping the server we can no longer restart the server.
1720
- *
1721
- * @example
1722
- * {Stop}
1723
- * Stop the server.
1724
- * ```
1725
- * const server = new volt.Server({ ... });
1726
- * await server.start();
1727
- * ...
1728
- * await server.stop();
1729
- * ```
1730
- *
1731
- * @docs
1732
- */
1733
- async stop() {
1734
- this.log(0, "Stopping the server...");
1735
- // On stop callbacks.
1736
- for (const callback of this.events.get("stop")) {
1737
- const res = callback();
1738
- if (res instanceof Promise) {
1739
- await res;
1740
- }
1741
- }
1742
- // Stop rate limit.
1743
- if (this.rate_limit) {
1744
- await this.rate_limit.stop();
1745
- }
1746
- // Stop sockets.
1747
- if (this.https)
1748
- this.https.close();
1749
- if (this.http)
1750
- this.http.close();
1751
- await this.db.close();
1752
- // Stop the logger.
1753
- this.log.stop();
1754
- // No longer initialized.
1755
- this._initialized = false;
1756
- // setTimeout(() => {
1757
- // thread_monitor.dump_active_resources({
1758
- // // min_age: 5000,
1759
- // // exclude_types: ['TIMERWRAP'],
1760
- // include_internal: false
1761
- // });
1762
- // }, 6000);
1763
- }
1764
- // ---------------------------------------------------------
1765
- // Events.
1766
- /**
1767
- * Add an event callback.
1768
- * See {@link Events} for more info.
1769
- * @docs
1770
- */
1771
- on(name, callback) {
1772
- this.events.add(name, callback);
1773
- return this;
1774
- }
1775
- /**
1776
- * Remove an event callback.
1777
- * See {@link Events} for more info.
1778
- * @docs
1779
- */
1780
- off(name, callback) {
1781
- this.events.remove(name, callback);
1782
- return this;
1783
- }
1784
- // ---------------------------------------------------------
1785
- // Endpoints.
1786
- /**
1787
- * Add a single endpoint.
1788
- * Only supports a single endpoint due to parameter inference.
1789
- * @note An error is thrown when the endpoint route already exists.
1790
- * @template Response User inputted response type that will be returned as response, optionaly typing used for consistency.
1791
- * @template S system template for inferring the endpoint callback parameters.
1792
- * @param endpoint The endpoint or endpoint options to add.
1793
- * @returns A registered endpoint object that can for instance be used to infer the endpoint parameters.
1794
- *
1795
- * @docs
1796
- */
1797
- endpoint(endpoint) {
1798
- const e = endpoint instanceof Endpoint ? endpoint : new Endpoint(endpoint);
1799
- this._check_duplicate_route(e.route);
1800
- this.endpoints.set(e.route.id, e);
1801
- return {
1802
- Params: undefined,
1803
- method: e.route.method,
1804
- Method: e.route.method,
1805
- endpoint: e.route.endpoint,
1806
- Endpoint: e.route.endpoint,
1807
- route: e.route,
1808
- };
1809
- }
1810
- /**
1811
- * Add an endpoint per error status code.
1812
- * @param status_code
1813
- * The status code of the error.
1814
- *
1815
- * The supported status codes are:
1816
- * * `*` For all errors not specifically defined.
1817
- * * `status >= 400`
1818
- * @param endpoint The error endpoint or error endpoint options.
1819
- *
1820
- * @note
1821
- * Best practice is to define a universal `/error` endpoint using `Endpoint.templates` to render the error details.
1822
- * Then this endpoint can be cloned using `Endpoint.clone()` and defined with specific template values per status code.
1823
- *
1824
- * @docs
1825
- */
1826
- error_endpoint(status_code, endpoint) {
1827
- let e;
1828
- if (endpoint instanceof Endpoint) {
1829
- e = endpoint;
1830
- }
1831
- else {
1832
- e = new Endpoint({
1833
- ...endpoint,
1834
- method: "GET",
1835
- endpoint: `/error/${status_code}`,
1836
- });
1837
- }
1838
- // we dont check the route since we dont need methods and endpoints to be unique here.
1839
- // this._check_duplicate_route(e.route);
1840
- if (status_code === "*") {
1841
- Object.values(Status).forEach(status => {
1842
- if (typeof status === "number" && status >= 400 && !this.err_endpoints.has(status)) {
1843
- this.err_endpoints.set(status, e);
1844
- }
1845
- });
1846
- }
1847
- else {
1848
- this.err_endpoints.set(status_code, e);
1849
- }
1850
- return this;
1851
- }
1852
- // ---------------------------------------------------------
1853
- // Content Security Policy.
1854
- /**
1855
- * Add an url to the Content-Security-Policy. This function does not overwrite the existing key's value.
1856
- * @warning This function no longer has any effect when `Server.start()` has been called.
1857
- * @param key The Content-Security-Policy key, e.g. `script-src`.
1858
- * @param value The value to add to the Content-Security-Policy key.
1859
- * @example
1860
- * ...
1861
- * server.add_csp("script-src", "somewebsite.com");
1862
- * server.add_csp("upgrade-insecure-requests");
1863
- * @docs
1864
- */
1865
- add_csp(key, value = null) {
1866
- if (this.csp[key] === undefined) {
1867
- this.csp[key] = "";
1868
- }
1869
- if (Array.isArray(value)) {
1870
- value.forEach((v) => {
1871
- if (typeof v === "string" && v.length > 0) {
1872
- this.csp[key] += " " + v.trim();
1873
- }
1874
- });
1875
- }
1876
- else if (typeof value === "string" && value.length > 0) {
1877
- this.csp[key] += " " + value.trim();
1878
- }
1879
- }
1880
- // Remove a csp.
1881
- /**
1882
- * Remove an url from the Content-Security-Policy. This function does not overwrite the existing key's value.
1883
- * @warning This function no longer has any effect when `Server.start()` has been called.
1884
- * @param key The Content-Security-Policy key, e.g. `script-src`.
1885
- * @param value The value to remove from the Content-Security-Policy key.
1886
- * @example
1887
- * ...
1888
- * server.remove_csp("script-src", "somewebsite.com");
1889
- * server.remove_csp("upgrade-insecure-requests");
1890
- * @docs
1891
- */
1892
- remove_csp(key, value = null) {
1893
- if (this.csp[key] === undefined) {
1894
- return;
1895
- }
1896
- if (typeof value === "string" && value.length > 0) {
1897
- this.csp[key] = this.csp[key].replaceAll(value, "");
1898
- }
1899
- else {
1900
- delete this.csp[key];
1901
- }
1902
- }
1903
- // Delete a csp key.
1904
- /**
1905
- * Delete an key from the Content-Security-Policy.
1906
- * @warning This function no longer has any effect when `Server.start()` has been called.
1907
- * @param key The Content-Security-Policy key, e.g. `script-src`.
1908
- * @example
1909
- * ...
1910
- * server.del_csp("script-src");
1911
- * server.del_csp("upgrade-insecure-requests");
1912
- * @docs
1913
- */
1914
- del_csp(key) {
1915
- delete this.csp[key];
1916
- }
1917
- // ---------------------------------------------------------
1918
- // Status.
1919
- /**
1920
- * This function is meant to be used when the server is in production mode, it will make an API request to your server through the defined `Server.domain` parameter.
1921
- * @note This function can be called without initializing the server.
1922
- * @param type The wanted output type. Either an `object` or a `string` type for CLI purposes.
1923
- * @docs
1924
- */
1925
- async fetch_status(type = "object") {
1926
- // Load key.
1927
- const key_path = this.source.join(".status/key");
1928
- if (!key_path.exists()) {
1929
- throw new Error("No status key has been generated yet. Start your server first.");
1930
- }
1931
- const key = key_path.load_sync();
1932
- // Make request.
1933
- const { body: status } = await vlib.request({
1934
- host: this.domain,
1935
- endpoint: "/.status",
1936
- method: "GET",
1937
- params: { key },
1938
- query: true,
1939
- json: true,
1940
- });
1941
- // String type.
1942
- if (type === "string") {
1943
- if (status.running_since != null) {
1944
- status.running_since = new vlib.Date(status.running_since).format("%d-%m-%y %H:%M:%S");
1945
- }
1946
- let str = `${this.domain}:\n`;
1947
- Object.keys(status).forEach((key) => {
1948
- str += ` * ${key}: ${status[key]}\n`;
1949
- });
1950
- str = str.substr(0, str.length - 1);
1951
- return str;
1952
- }
1953
- // Response.
1954
- return status;
1955
- }
1956
- // ---------------------------------------------------------
1957
- // TLS.
1958
- /**
1959
- * Generate a key and csr for tls.
1960
- * @docs
1961
- */
1962
- async generate_ssl_key({ output_path, ec = true, }) {
1963
- // Args.
1964
- if (output_path == null) {
1965
- throw Error("Define parameter \"path\".");
1966
- }
1967
- // Paths.
1968
- const key = new vlib.Path(output_path);
1969
- if (key.exists()) {
1970
- throw Error(`Key path "${key.str()}" already exists, remove the file manually to continue.`);
1971
- }
1972
- // Generate the private key using the EC parameters file
1973
- const proc = new vlib.Proc();
1974
- await proc.start({
1975
- command: "openssl",
1976
- args: ec
1977
- ? ["ecparam", "-genkey", "-name", "secp384r1", "-out", key.str()]
1978
- : ["genpkey", "-algorithm", "RSA", "-pkeyopt", "rsa_keygen_bits:2048", "-out", key.str()],
1979
- opts: { stdio: "inherit" },
1980
- });
1981
- if (proc.exit_status != 0) {
1982
- throw Error(`Encountered an error while generating the private key [${proc.exit_status}]: ${proc.err}`);
1983
- }
1984
- }
1985
- /**
1986
- * Generate a csr for tls.
1987
- * @docs
1988
- */
1989
- async generate_csr({ output_path, key_path, name, domain, organization_unit, country_code, province, city, }) {
1990
- // Args.
1991
- if (key_path == null) {
1992
- throw Error("Define parameter \"key_path\".");
1993
- }
1994
- if (organization_unit == null) {
1995
- throw Error("Define parameter \"organization_unit\".");
1996
- }
1997
- // Paths.
1998
- const key = new vlib.Path(key_path);
1999
- if (!key.exists()) {
2000
- throw Error(`Key path "${key.str()}" does not exist.`);
2001
- }
2002
- const csr = new vlib.Path(output_path);
2003
- if (csr.exists()) {
2004
- throw Error(`CSR path "${csr.str()}" already exists, remove the file manually to continue.`);
2005
- }
2006
- // Generate the CSR using the generated private key
2007
- const proc = new vlib.Proc();
2008
- await proc.start({
2009
- command: "openssl",
2010
- args: [
2011
- "req", "-new", "-key", key.str(), "-out", csr.str(),
2012
- "-subj",
2013
- `/C=${country_code}/ST=${province}/L=${city}/O=${name}/OU=${organization_unit}/CN=${domain}`
2014
- ],
2015
- opts: { stdio: "inherit" },
2016
- });
2017
- if (proc.exit_status != 0) {
2018
- throw Error(`Encountered an error while generating the CSR [${proc.exit_status}]: ${proc.err}`);
2019
- }
2020
- this.log(0, `Generated the tls key with CSR for domain "${this.domain}".`);
2021
- }
2022
- // ---------------------------------------------------------
2023
- // DEPRECATED
2024
- // these will all be removed and replaced when using stripe instead of paddle.
2025
- /** Called for each product in a successful one-time payment. Override to implement your logic. */
2026
- async on_payment({ product, payment }) { }
2027
- /** Called for each product in a successful subscription. Override to implement your logic. */
2028
- async on_subscription({ product, payment }) { }
2029
- // On failed one-time or recurring payment.
2030
- // async on_failed_payment({ payment }: { payment: any }): Promise<void> {}
2031
- /** Called when a cancellation succeeds. Override to implement your logic. */
2032
- async on_cancellation({ payment, line_items }) { }
2033
- // On failed cancellation.
2034
- // async on_failed_cancellation({ payment, line_items }: { payment: any; line_items: any[] }): Promise<void> {}
2035
- /** Called when a refund succeeds. The line items array are the items that were refunded. */
2036
- async on_refund({ payment, line_items }) { }
2037
- /** Called when a refund fails. The line items array are the items where the refund failed. */
2038
- async on_failed_refund({ payment, line_items }) { }
2039
- /** Called when a chargeback occurs. The line items array are the items that were charged back. */
2040
- async on_chargeback({ payment, line_items }) { }
2041
- /** Called when a chargeback fails. The line items array are the items where the chargeback failed. */
2042
- async on_failed_chargeback({ payment, line_items }) { }
2043
- // Mail template.
2044
- /** Build the base email layout used by the various transactional email builders. */
2045
- _mail_template({ max_width = 400, children = [], }) {
2046
- this.assert_mail();
2047
- const style = this.mail.style;
2048
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2049
- // Create header.
2050
- let header;
2051
- if (this.company.stroke_icon != null) {
2052
- header = [
2053
- Image(`${this.full_domain}${this.company.stroke_icon ?? ""}`).height(16),
2054
- ];
2055
- }
2056
- else if (this.company.icon != null) {
2057
- header = [
2058
- Image(`${this.full_domain}${this.company.icon ?? ""}`).frame(20, 40),
2059
- ];
2060
- }
2061
- if (header) {
2062
- header = Table(TableRow(...header)
2063
- .wrap(true)
2064
- .center()
2065
- .center_vertical()).margin_bottom(15);
2066
- }
2067
- // Create mail.
2068
- return MailUI.Mail(Table(TableData(Table(
2069
- // Header.
2070
- header,
2071
- // Widget.
2072
- Table(...children)
2073
- .background_color(style.widget_bg ?? "")
2074
- .border(`1px solid ${style.widget_border ?? ""}`)
2075
- .border_radius("10px")
2076
- .padding(40, 25, 25, 25)
2077
- .margin(0),
2078
- // Copyright.
2079
- Table(TableRow(Text(`Copyright © ${new Date().getFullYear()} ${this.company.name}, ${this.company.legal_name} All Rights Included.\n` +
2080
- `${this.company.street} ${this.company.house_number}, ${this.company.postal_code}, ${this.company.city}, ${this.company.province}, ${this.company.country}.\n` +
2081
- (this.company.tax_id == null ? "" : `VAT ID ${this.company.tax_id}`))
2082
- .white_space("pre")
2083
- .display("inline-block")
2084
- .font_size(11)
2085
- .color(style.footer_fg)
2086
- .margin(0)).center().center_vertical()).margin(0, 0, 10, 0)).max_width(max_width)).center()).padding(25, 20, 25, 20)).font_family(style.font).background(style.bg);
2087
- }
2088
- // Render payment line items.
2089
- /** Helper that renders a list of payment line items for use in transactional emails. */
2090
- _render_mail_payment_line_items({ payment, line_items, show_total_due = false }) {
2091
- if (!this.payments)
2092
- throw new Error("Payments not initialized");
2093
- this.assert_mail();
2094
- // Shortcuts.
2095
- const style = this.mail.style;
2096
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2097
- // Render payment line item for a mail.
2098
- const _render_mail_payment_line_item = ({ name, desc, unit_cost, quantity, total_cost, font_weight = "normal", divider = true, color = style.text_fg, }) => {
2099
- return [
2100
- Table(TableRow(TableData(Text(name)
2101
- .color(color)
2102
- .font_size(14)
2103
- .text_wrap("wrap")
2104
- .overflow_wrap("break-word")
2105
- .word_wrap("break-word")
2106
- .font_weight(font_weight)).width("25%").margin_right(10), TableData(Text(desc)
2107
- .color(color)
2108
- .font_size(14)
2109
- .text_wrap("wrap")
2110
- .overflow_wrap("break-word")
2111
- .word_wrap("break-word")
2112
- .font_weight(font_weight)).width("35%").margin_right(10), TableData(Text(unit_cost)
2113
- .color(color)
2114
- .font_size(14)
2115
- .text_wrap("wrap")
2116
- .overflow_wrap("break-word")
2117
- .word_wrap("break-word")
2118
- .font_weight(font_weight)).fixed_width("13.32%").margin_right(10), TableData(Text(quantity)
2119
- .color(color)
2120
- .font_size(14)
2121
- .text_wrap("wrap")
2122
- .overflow_wrap("break-word")
2123
- .word_wrap("break-word")
2124
- .font_weight(font_weight)).fixed_width("13.32%").margin_right(10), TableData(Text(total_cost)
2125
- .color(color)
2126
- .font_size(14)
2127
- .text_wrap("wrap")
2128
- .overflow_wrap("break-word")
2129
- .word_wrap("break-word")
2130
- .font_weight(font_weight)).fixed_width("13.32%")).width("100%").styles({ "vertical-align": "baseline" })).width("100%"),
2131
- !divider
2132
- ? null
2133
- : TableRow(TableData(VStack()
2134
- .background_color(style.text_fg)
2135
- .frame("100%", 1)
2136
- .margin(5, 0, 10, 0)).frame("100%", 1)).width("100%"),
2137
- ];
2138
- };
2139
- // Render a divider.
2140
- const render_divider = () => {
2141
- return TableRow(TableData(VStack()
2142
- .background_color(style.divider_bg)
2143
- .frame("100%", 1)
2144
- .margin(5, 0, 10, 0)).frame("100%", 1)).width("100%");
2145
- };
2146
- // Vars.
2147
- let currency;
2148
- let subtotal = 0;
2149
- let subtotal_tax = 0;
2150
- let total = 0;
2151
- payment.line_items.walk((item) => {
2152
- if (!this.payments)
2153
- throw new Error("Payments not initialized");
2154
- if (typeof item.product === "string") {
2155
- item.product = this.payments.get_product_sync(item.product);
2156
- }
2157
- if (currency == null) {
2158
- const c = Utils.get_currency_symbol(item.product.currency);
2159
- if (c == null) {
2160
- this.log.error(`Failed to create a payment mail: `, new Error(`Unable to determine the currency of payment "${payment.id}".`));
2161
- }
2162
- currency = c ?? "?";
2163
- }
2164
- subtotal += item.subtotal;
2165
- subtotal_tax += item.tax;
2166
- total += item.total;
2167
- });
2168
- let total_due = payment.status === "open" ? total : 0;
2169
- return [
2170
- render_divider(),
2171
- line_items.map((item, index) => {
2172
- return Table(TableRow(TableData(Image(item.product.icon)
2173
- .frame(35, 35)
2174
- .margin_right(15)).width("auto"), TableData(Table(Text(item.product.name)
2175
- .color(style.title_fg)
2176
- .font_size(14)
2177
- .font_weight("bold")
2178
- .margin(0)
2179
- .ellipsis_overflow(true), Text(item.product.description)
2180
- .color(style.text_fg)
2181
- .font_size(14)
2182
- .margin(0)
2183
- .ellipsis_overflow(true))).width("100%"), TableData(Text(`${currency} ${item.subtotal.toFixed(2)}`)
2184
- .color(style.title_fg)
2185
- .font_size(14)
2186
- .font_weight("bold")
2187
- .margin(0)
2188
- .white_space("nowrap")).width("100%")).wrap(true).leading_vertical().width("100%")).width("100%");
2189
- }),
2190
- render_divider(),
2191
- Table([
2192
- ["Subtotal:", `${currency} ${subtotal.toFixed(2)}`],
2193
- ["Tax:", `${currency} ${subtotal_tax.toFixed(2)}`],
2194
- ["Total:", `${currency} ${total.toFixed(2)}`],
2195
- ].map((item) => {
2196
- return TableRow(TableData().width("100%"), TableData(Text(item[0])
2197
- .color(style.title_fg)
2198
- .font_size(14)
2199
- .ellipsis_overflow(true)
2200
- .font_weight("bold")).min_width(75), TableData(Text(item[1])
2201
- .color(style.title_fg)
2202
- .font_size(14)
2203
- .white_space("nowrap")
2204
- .font_weight("bold"))
2205
- // .min_width(50)
2206
- ).wrap(true);
2207
- // .text_align("right")
2208
- })),
2209
- ];
2210
- }
2211
- /** Assert mail is configured. */
2212
- assert_mail() {
2213
- if (!this.mail) {
2214
- throw new ExternalError({ message: "Mail is not configured." });
2215
- }
2216
- }
2217
- /**
2218
- * Build the 2FA verification email content.
2219
- */
2220
- on_2fa_mail({ code, username, email, date, ip, device }) {
2221
- this.assert_mail();
2222
- const style = this.mail.style;
2223
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2224
- return this._mail_template({
2225
- max_width: 400,
2226
- children: [
2227
- // Title.
2228
- TableRow(Title("Verification Required")
2229
- .color(style.title_fg)
2230
- .width("fit-content")
2231
- .font_size(26)).center(),
2232
- // Text.
2233
- TableRow(Text("Please confirm your request with this 2FA code.")
2234
- .center()
2235
- .margin(10, 0, 20, 0)
2236
- .color(style.text_fg)
2237
- .font_size(18)),
2238
- // Auth info.
2239
- [
2240
- ["Username", username],
2241
- ["Email", email],
2242
- ["Date", date],
2243
- ["Ip Address", ip],
2244
- ["Device", device],
2245
- ].map((item) => {
2246
- return [
2247
- TableRow(VStack()
2248
- .margin_right(7.5)
2249
- // .background("linear-gradient(135deg, #4830C4, #6E399E, #421959)")
2250
- .background_color(style.text_fg)
2251
- .border_radius("50%")
2252
- .frame(5, 5), Text(`<span style='font-weight: 600'>${item[0]}:</span> ${item[1]}`)
2253
- .color(style.text_fg)
2254
- .font_size(16)
2255
- .text_wrap("wrap")
2256
- .overflow_wrap("break-word")
2257
- .word_wrap("break-word")).wrap(true).center_vertical(),
2258
- TableRow().fixed_frame(5, 5),
2259
- ];
2260
- }),
2261
- // 2FA code.
2262
- TableRow(Text(code)
2263
- .background(style.button_bg)
2264
- .border_radius("10px")
2265
- .padding(10, 15)
2266
- .center()
2267
- .color(style.button_fg)
2268
- .width("100%")
2269
- .margin(20, 0, 0, 0)),
2270
- // Text.
2271
- TableRow(Text("This 2FA code will be valid for 5 minutes.")
2272
- .color(style.text_fg)
2273
- .font_style("italic")
2274
- .font_size(12)
2275
- .margin_top(20)
2276
- .center()),
2277
- ],
2278
- });
2279
- }
2280
- /**
2281
- * Build the successful payment email content.
2282
- */
2283
- on_payment_mail({ payment }) {
2284
- this.assert_mail();
2285
- // Shortcuts.
2286
- const style = this.mail.style;
2287
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2288
- // Create mail.
2289
- return this._mail_template({
2290
- max_width: 600,
2291
- children: [
2292
- // Title.
2293
- TableRow(Title("Successful Payment")
2294
- .color(style.title_fg)
2295
- .width("fit-content")
2296
- .font_size(26)).center(),
2297
- // Text.
2298
- TableRow(Text("We're delighted to inform you that your payment has been successfully processed. Thank you for your purchase.")
2299
- .margin(10, 0, 20, 0)
2300
- .color(style.text_fg)
2301
- .font_size(16)
2302
- .center()),
2303
- // Image.
2304
- TableRow(Image(`${this.full_domain}/volt/assets/payments/party.png`)
2305
- .frame(60, 60)
2306
- .margin(0, 0, 30, 0)).center(),
2307
- // Title.
2308
- TableRow(Title("Order Summary")
2309
- .color(style.subtitle_fg)
2310
- .font_size(18)
2311
- .margin(0)),
2312
- TableRow(Text("A summary of your order can be found below or in the attached invoice PDF.")
2313
- .margin(5, 0, 20, 0)
2314
- .color(style.text_fg)
2315
- .font_size(16)),
2316
- // Line items.
2317
- this._render_mail_payment_line_items({ payment, line_items: payment.line_items, show_total_due: true }),
2318
- // Bottom spacing.
2319
- VStack()
2320
- .margin_bottom(15)
2321
- ],
2322
- });
2323
- }
2324
- /**
2325
- * Build the failed payment email content.
2326
- */
2327
- on_failed_payment_mail({ payment }) {
2328
- this.assert_mail();
2329
- // Shortcuts.
2330
- const style = this.mail.style;
2331
- const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
2332
- // Create mail.
2333
- return this._mail_template({
2334
- max_width: 800,
2335
- children: [
2336
- // Title.
2337
- TableRow(Title("Payment Failed")
2338
- .color(style.title_fg)
2339
- .width("fit-content")
2340
- .font_size(26)).center(),
2341
- // Text.
2342
- TableRow(Text("We regret to inform you that your payment could not be processed successfully. We understand the inconvenience this may cause. Please try again, or contact customer support if the problem persists.")
2343
- .margin(10, 0, 20, 0)
2344
- .color(style.text_fg)
2345
- .font_size(16)
2346
- .center()),
2347
- // Image.
2348
- TableRow(ImageMask(`${this.full_domain}/volt/assets/payments/error.png`)
2349
- .frame(40, 40)
2350
- .mask_color("#E8454E")
2351
- .margin(0, 0, 30, 0)).center(),
2352
- // Title.
2353
- TableRow(Title("Order Summary")
2354
- .color(style.subtitle_fg)
2355
- .font_size(18)
2356
- .margin(0)),
2357
- TableRow(Text("A summary of your failed order can be found below.")
2358
- .margin(5, 0, 20, 0)
2359
- .color(style.text_fg)
2360
- .font_size(16)),
2361
- // Line items.
2362
- this._render_mail_payment_line_items({ payment, line_items: payment.line_items }),
2363
- // Bottom spacing.
2364
- VStack()
2365
- .margin_bottom(15)
2366
- ],
2367
- });
2368
- }
2369
- // On cancellation mail.
2370
- /** Build the successful cancellation email content. */
2371
- on_cancellation_mail({ payment, line_items }) {
2372
- this.assert_mail();
2373
- // Shortcuts.
2374
- const style = this.mail.style;
2375
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2376
- // Create mail.
2377
- return this._mail_template({
2378
- max_width: 800,
2379
- children: [
2380
- // Title.
2381
- TableRow(Title("Successful Cancellation")
2382
- .color(style.title_fg)
2383
- .width("fit-content")
2384
- .font_size(26)).center(),
2385
- // Text.
2386
- TableRow(Text("Your recent cancellation request has been successfully processed.")
2387
- .margin(10, 0, 20, 0)
2388
- .color(style.text_fg)
2389
- .font_size(16)
2390
- .center()),
2391
- // Image.
2392
- TableRow(Image(`${this.full_domain}/volt/assets/payments/check.png`)
2393
- .frame(40, 40)
2394
- .margin(0, 0, 30, 0)).center(),
2395
- // Title.
2396
- TableRow(Title("Cancelled Summary")
2397
- .color(style.subtitle_fg)
2398
- .font_size(18)
2399
- .margin(0)),
2400
- TableRow(Text("A summary of your cancelled products.")
2401
- .margin(5, 0, 20, 0)
2402
- .color(style.text_fg)
2403
- .font_size(16)),
2404
- // Line items.
2405
- this._render_mail_payment_line_items({ payment, line_items }),
2406
- // Bottom spacing.
2407
- VStack()
2408
- .margin_bottom(15)
2409
- ],
2410
- });
2411
- }
2412
- // On refund mail.
2413
- /** Build the failed cancellation email content. */
2414
- on_failed_cancellation_mail({ payment }) {
2415
- this.assert_mail();
2416
- // Shortcuts.
2417
- const style = this.mail.style;
2418
- const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
2419
- // Create mail.
2420
- return this._mail_template({
2421
- max_width: 800,
2422
- children: [
2423
- // Title.
2424
- TableRow(Title("Cancellation Failed")
2425
- .color(style.title_fg)
2426
- .width("fit-content")
2427
- .font_size(26)).center(),
2428
- // Text.
2429
- TableRow(Text("We regret to inform you that your recent cancellation request has encountered an issue and could not be processed successfully. We understand the inconvenience this may cause. If you believe you are eligible for a cancellation, please try again or contact customer support.")
2430
- .margin(10, 0, 20, 0)
2431
- .color(style.text_fg)
2432
- .font_size(16)
2433
- .center()).center(),
2434
- // Image.
2435
- TableRow(ImageMask(`${this.full_domain}/volt/assets/payments/error.png`)
2436
- .frame(40, 40)
2437
- .mask_color("#E8454E")
2438
- .margin(0, 0, 30, 0)).center(),
2439
- // Title.
2440
- TableRow(Title("Cancellation Summary")
2441
- .color(style.subtitle_fg)
2442
- .font_size(18)
2443
- .margin(0)),
2444
- TableRow(Text("A summary of your cancellation request.")
2445
- .margin(5, 0, 20, 0)
2446
- .color(style.text_fg)
2447
- .font_size(16)),
2448
- // Line items.
2449
- this._render_mail_payment_line_items({ payment, line_items: payment.line_items }),
2450
- // Bottom spacing.
2451
- VStack()
2452
- .margin_bottom(15)
2453
- ],
2454
- });
2455
- }
2456
- // On refund mail.
2457
- /** Build the successful refund email content. */
2458
- on_refund_mail({ payment, line_items }) {
2459
- this.assert_mail();
2460
- // Shortcuts.
2461
- const style = this.mail.style;
2462
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2463
- // Create mail.
2464
- return this._mail_template({
2465
- max_width: 800,
2466
- children: [
2467
- // Title.
2468
- TableRow(Title("Chargeback Successful")
2469
- .color(style.title_fg)
2470
- .width("fit-content")
2471
- .font_size(26)).center(),
2472
- // Text.
2473
- TableRow(Text("We're delighted to inform you that your recent refund request has been successfully processed. The charged amount will soon be credited back to your account.")
2474
- .margin(10, 0, 20, 0)
2475
- .color(style.text_fg)
2476
- .font_size(16)
2477
- .center()),
2478
- // Image.
2479
- TableRow(Image(`${this.full_domain}/volt/assets/payments/party.png`)
2480
- .frame(60, 60)
2481
- .margin(0, 0, 30, 0)).center(),
2482
- // Title.
2483
- TableRow(Title("Refund Summary")
2484
- .color(style.subtitle_fg)
2485
- .font_size(18)
2486
- .margin(0)),
2487
- TableRow(Text("A summary of your refunded products.")
2488
- .margin(5, 0, 20, 0)
2489
- .color(style.text_fg)
2490
- .font_size(16)),
2491
- // Line items.
2492
- this._render_mail_payment_line_items({ payment, line_items }),
2493
- // Bottom spacing.
2494
- VStack()
2495
- .margin_bottom(15)
2496
- ],
2497
- });
2498
- }
2499
- // On refund mail.
2500
- /** Build the failed refund email content. */
2501
- on_failed_refund_mail({ payment, line_items }) {
2502
- this.assert_mail();
2503
- // Shortcuts.
2504
- const style = this.mail.style;
2505
- const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
2506
- // Create mail.
2507
- return this._mail_template({
2508
- max_width: 800,
2509
- children: [
2510
- // Title.
2511
- TableRow(Title("Refund Failed")
2512
- .color(style.title_fg)
2513
- .width("fit-content")
2514
- .font_size(26)).center(),
2515
- // Text.
2516
- TableRow(Text("We regret to inform you that your recent refund request has encountered an issue and could not be processed successfully. We understand the inconvenience this may cause. If you believe you are eligible for a refund, please try again or contact customer support.")
2517
- .margin(10, 0, 20, 0)
2518
- .color(style.text_fg)
2519
- .font_size(16)
2520
- .center()).center(),
2521
- // Image.
2522
- TableRow(ImageMask(`${this.full_domain}/volt/assets/payments/error.png`)
2523
- .frame(40, 40)
2524
- .mask_color("#E8454E")
2525
- .margin(0, 0, 30, 0)).center(),
2526
- // Title.
2527
- TableRow(Title("Refund Summary")
2528
- .color(style.subtitle_fg)
2529
- .font_size(18)
2530
- .margin(0)),
2531
- TableRow(Text("A summary of your refund request.")
2532
- .margin(5, 0, 20, 0)
2533
- .color(style.text_fg)
2534
- .font_size(16)),
2535
- // Line items.
2536
- this._render_mail_payment_line_items({ payment, line_items }),
2537
- // Bottom spacing.
2538
- VStack()
2539
- .margin_bottom(15)
2540
- ],
2541
- });
2542
- }
2543
- // On refund mail.
2544
- /** Build the successful chargeback email content. */
2545
- on_chargeback_mail({ payment, line_items }) {
2546
- this.assert_mail();
2547
- // Shortcuts.
2548
- const style = this.mail.style;
2549
- const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
2550
- // Create mail.
2551
- return this._mail_template({
2552
- max_width: 800,
2553
- children: [
2554
- // Title.
2555
- TableRow(Title("Successful Refund")
2556
- .color(style.title_fg)
2557
- .width("fit-content")
2558
- .font_size(26)).center(),
2559
- // Text.
2560
- TableRow(Text("We're delighted to inform you that your recent chargeback request has been successfully processed. The charged amount will soon be credited back to your account.")
2561
- .margin(10, 0, 20, 0)
2562
- .color(style.text_fg)
2563
- .font_size(16)
2564
- .center()),
2565
- // Image.
2566
- TableRow(Image(`${this.full_domain}/volt/assets/payments/party.png`)
2567
- .frame(60, 60)
2568
- .margin(0, 0, 30, 0)).center(),
2569
- // Title.
2570
- TableRow(Title("Chargeback Summary")
2571
- .color(style.subtitle_fg)
2572
- .font_size(18)
2573
- .margin(0)),
2574
- TableRow(Text("A summary of the items charged back.")
2575
- .margin(5, 0, 20, 0)
2576
- .color(style.text_fg)
2577
- .font_size(16)),
2578
- // Line items.
2579
- this._render_mail_payment_line_items({ payment, line_items }),
2580
- // Bottom spacing.
2581
- VStack()
2582
- .margin_bottom(15)
2583
- ],
2584
- });
2585
- }
2586
- // On refund mail.
2587
- /** Build the failed chargeback email content. */
2588
- on_failed_chargeback_mail({ payment, line_items }) {
2589
- this.assert_mail();
2590
- // Shortcuts.
2591
- const style = this.mail.style;
2592
- const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
2593
- // Create mail.
2594
- return this._mail_template({
2595
- max_width: 800,
2596
- children: [
2597
- // Title.
2598
- TableRow(Title("Chargeback Failed")
2599
- .color(style.title_fg)
2600
- .width("fit-content")
2601
- .font_size(26)).center(),
2602
- // Text.
2603
- TableRow(Text("We regret to inform you that your recent chargeback request has been declined.")
2604
- .margin(10, 0, 20, 0)
2605
- .color(style.text_fg)
2606
- .font_size(16)
2607
- .center()).center(),
2608
- // Image.
2609
- TableRow(ImageMask(`${this.full_domain}/volt/assets/payments/error.png`)
2610
- .frame(40, 40)
2611
- .mask_color("#E8454E")
2612
- .margin(0, 0, 30, 0)).center(),
2613
- // Title.
2614
- TableRow(Title("Chargeback Summary")
2615
- .color(style.subtitle_fg)
2616
- .font_size(18)
2617
- .margin(0)),
2618
- TableRow(Text("A summary of your chargeback request.")
2619
- .margin(5, 0, 20, 0)
2620
- .color(style.text_fg)
2621
- .font_size(16)),
2622
- // Line items.
2623
- this._render_mail_payment_line_items({ payment, line_items }),
2624
- // Bottom spacing.
2625
- VStack()
2626
- .margin_bottom(15)
2627
- ],
2628
- });
2629
- }
2630
- }