@vandenberghinc/volt 1.2.5 → 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 +5 -1
  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,2276 +0,0 @@
1
- // @ts-nocheck
2
- /**
3
- * @author Daan van den Bergh
4
- * @copyright © 2022 - 2025 Daan van den Bergh. All rights reserved
5
- */
6
- // Imports.
7
- import * as https from "https";
8
- import * as PDFDocument from "pdfkit";
9
- import * as libcrypto from "crypto";
10
- import * as vlib from "@vandenberghinc/vlib";
11
- import { ExternalError } from "../errors/index.js";
12
- import { Status } from "../status.js";
13
- import { Collection } from "../database/collection.js";
14
- import { Utils } from "../utils.js";
15
- /** Nested types for the {@link LineItem} interface. */
16
- export var LineItem;
17
- (function (LineItem) {
18
- /** Validation schema. */
19
- LineItem.Schema = {
20
- product: "string",
21
- item_id: "string",
22
- paddle_prod_id: "string",
23
- quantity: "number",
24
- tax_rate: "number",
25
- tax: "number",
26
- discount: "number",
27
- subtotal: "number",
28
- total: "number",
29
- status: { type: "string", enum: ["paid", "refunded", "refunding"] },
30
- };
31
- })(LineItem || (LineItem = {}));
32
- export const PaymentStatusValues = ['open', 'paid', 'past_due', 'unknown'];
33
- /** Nested types for the {@link Payment} interface. */
34
- export var Payment;
35
- (function (Payment) {
36
- /**
37
- * Check if a payment should be anonymized,
38
- * if so return a public version of the payment.
39
- */
40
- function anonymize(payment) {
41
- if (!payment.uid || payment.uid === "unauth") {
42
- const { billing_details, ...rest } = payment;
43
- return {
44
- ...rest,
45
- billing_details: undefined,
46
- };
47
- }
48
- return payment;
49
- }
50
- Payment.anonymize = anonymize;
51
- })(Payment || (Payment = {}));
52
- // The paddle payments class.
53
- // @todo check if a user can subscribe twice to a sub, should not be allowed for system logic.
54
- // @todo still need to manage the reactivation of a subscription after a chargeback has been reversed.
55
- // @todo still check if a subscription is automatically cancelled by paddle when it is refunded.
56
- /**
57
- * The paddle payments class.
58
- *
59
- * Sandbox env: https://sandbox-vendors.paddle.com
60
- *
61
- * @nav Payments
62
- * @docs
63
- * @deprecated Using stripe from now on.
64
- */
65
- export class Paddle {
66
- type = "paddle";
67
- client_key;
68
- sandbox;
69
- inclusive_tax;
70
- products;
71
- server;
72
- _host;
73
- _headers;
74
- webhook_key;
75
- _has_create_products_permission;
76
- _last_products_db;
77
- _webhook_conf_db;
78
- _sub_db;
79
- _active_sub_db;
80
- _pay_db;
81
- // private _inv_db: Collection;
82
- performance;
83
- constructor({ api_key, client_key, sandbox = false, products = [], inclusive_tax = false, _server, }) {
84
- // Original constructor implementation remains the same
85
- // Verify args.
86
- vlib.schema.validate(arguments[0], {
87
- unknown: false,
88
- throw: true,
89
- parent: "payments",
90
- schema: {
91
- type: { type: "string", default: "paddle" },
92
- api_key: "string",
93
- client_key: "string",
94
- sandbox: { type: "boolean", default: false },
95
- inclusive_tax: { type: "boolean", default: false },
96
- products: "array",
97
- _server: "object",
98
- }
99
- });
100
- // Attributes.
101
- this.client_key = client_key;
102
- this.sandbox = sandbox;
103
- this.inclusive_tax = inclusive_tax;
104
- this.products = products;
105
- this.server = _server;
106
- // Request headers.
107
- this._host = this.sandbox ? "sandbox-api.paddle.com" : "api.paddle.com";
108
- this._headers = {
109
- "Content-Type": "application/json",
110
- "Accept": "application/json",
111
- "Authorization": "Bearer " + api_key,
112
- };
113
- // Extend the csp.
114
- this.server.csp["default-src"] += " https://*.paddle.com/";
115
- this.server.csp["script-src"] += " https://*.paddle.com/ https://*.payments-amazon.com https://*.paypal.com https://*.google.com";
116
- this.server.csp["style-src"] += " https://*.paddle.com/ https://*.media-amazon.com https://*.paypal.com https://*.google.com";
117
- this.server.csp["img-src"] += " https://*.paddle.com/ https://*.media-amazon.com https://*.paypal.com https://*.google.com";
118
- // Create database collections.
119
- this._last_products_db = this.server.db.collection({
120
- name: "Volt.Paddle.LastProducts",
121
- indexes: ["production", "version"],
122
- });
123
- this._webhook_conf_db = this.server.db.collection({
124
- name: "Volt.Paddle.WebhookConfig",
125
- indexes: ["production", "version"],
126
- });
127
- this._sub_db = this.server.db.collection({
128
- name: "Volt.Paddle.Subscriptions",
129
- indexes: ["uid", "id"],
130
- });
131
- this._active_sub_db = this.server.db.collection({
132
- name: "Volt.Paddle.ActiveSubscriptions",
133
- indexes: ["uid", "prod_id"],
134
- });
135
- this._pay_db = this.server.db.collection({
136
- name: "Volt.Paddle.Payments",
137
- indexes: ["uid", "id", "tran_id"],
138
- });
139
- // this._inv_db = this.server.db.collection({
140
- // name: "Volt.Paddle.Invoices",
141
- // indexes: ["uid", "id", "tran_id" ],
142
- // });
143
- /* @performance */ this.performance = new vlib.Performance("Payments performance");
144
- }
145
- // ---------------------------------------------------------
146
- // Products and prices (private).
147
- // ---------------------------------------------------------
148
- // Utils (private).
149
- async _req(method, endpoint, params = null) {
150
- const promise = new Promise((resolve, reject) => {
151
- // Build hostname + path for both relative and absolute endpoints.
152
- const is_get_like = method === "GET" || method === "HEAD";
153
- let hostname = this._host;
154
- let path = endpoint;
155
- try {
156
- if (/^https?:\/\//i.test(endpoint)) {
157
- const u = new URL(endpoint);
158
- hostname = u.hostname;
159
- path = u.pathname + u.search;
160
- }
161
- else if (is_get_like && params != null) {
162
- path = `${endpoint}?${new URLSearchParams(params).toString()}`;
163
- }
164
- }
165
- catch {
166
- // fall back to original host + endpoint
167
- }
168
- // Options.
169
- const options = {
170
- method: method,
171
- hostname,
172
- path,
173
- port: 443,
174
- headers: this._headers,
175
- };
176
- // Make the HTTP request
177
- const request = https.request(options, (response) => {
178
- let data = '';
179
- response.on('data', (chunk) => {
180
- data += chunk;
181
- });
182
- response.on('end', () => {
183
- if (response?.statusCode >= 200 && response?.statusCode < 300) {
184
- try {
185
- resolve(data ? JSON.parse(data) : {});
186
- }
187
- catch (error) {
188
- reject(new Error('Failed to parse response data'));
189
- }
190
- }
191
- else {
192
- if (data == null || data === "") {
193
- return reject(new Paddle.RequestError(`${method}:${endpoint}: Request failed [${response.statusCode}].`, response.statusCode));
194
- }
195
- try {
196
- data = JSON.parse(data);
197
- }
198
- catch (e) {
199
- return reject(new Paddle.RequestError(`${method}:${endpoint}: Request failed [${response.statusCode}].`, response.statusCode));
200
- }
201
- if (data.error == null) {
202
- return reject(new Paddle.RequestError(`${method}:${endpoint}: Request failed [${response.statusCode}].`, response.statusCode));
203
- }
204
- data = data.error;
205
- let errs = "";
206
- if (data.errors) {
207
- errs += ". ";
208
- data.errors.iterate((item) => {
209
- errs += `Field: "${item.field}" ${item.message}. `;
210
- });
211
- errs = errs.substr(0, errs.length - 2);
212
- }
213
- return reject(new Paddle.RequestError(`${method}:${endpoint}: ${data.detail} [${response.statusCode}]${errs}.`, response.statusCode));
214
- }
215
- });
216
- });
217
- // Write body params.
218
- if (!is_get_like && params != null) {
219
- // request.write(JSON.stringify(params));
220
- const requestBody = JSON.stringify(params);
221
- request.setHeader('Content-Length', Buffer.byteLength(requestBody));
222
- request.write(requestBody);
223
- }
224
- // On error.
225
- request.on('error', (error) => {
226
- reject(error);
227
- });
228
- // End.
229
- request.end();
230
- });
231
- // So the traceback still includes the call function of _req.
232
- try {
233
- return await promise;
234
- }
235
- catch (e) {
236
- if (e instanceof Error || e instanceof Paddle.RequestError) {
237
- throw e;
238
- }
239
- throw new Error(e);
240
- }
241
- }
242
- // ---------------------------------------------------------
243
- // Database (private).
244
- // Add or remove a subscription to the user's active subscriptions.
245
- async _add_subscription(uid, prod_id, sub_id) {
246
- await this._active_sub_db.set({ uid, prod_id }, { prod_id, sub_id });
247
- }
248
- async _delete_subscription(uid, prod_id) {
249
- await this._active_sub_db.delete({ uid, prod_id });
250
- }
251
- async _check_subscription(uid, prod_id, load_data = false) {
252
- try {
253
- const doc = await this._active_sub_db.load({ uid, prod_id });
254
- return load_data ? { exists: true, sub_id: doc.sub_id } : true;
255
- }
256
- catch (err) {
257
- if (err instanceof Collection.NotFoundError) {
258
- return load_data ? { exists: false, sub_id: undefined } : false;
259
- }
260
- throw err;
261
- }
262
- }
263
- async _get_active_subscriptions(uid, detailed = false) {
264
- const list = await this._active_sub_db.list({ uid: uid });
265
- if (detailed) {
266
- return list;
267
- }
268
- const products = [];
269
- for (const doc of list) {
270
- products.push(doc.prod_id);
271
- }
272
- return products;
273
- }
274
- async _save_subscription(subscription) {
275
- await this._sub_db.set({
276
- uid: subscription.uid == null ? "unauth" : subscription.uid,
277
- id: subscription.id,
278
- }, subscription);
279
- }
280
- async _load_subscription(id) {
281
- return await this._sub_db.load({ id: id }, { retry: 3 });
282
- }
283
- async _get_subscriptions(uid) {
284
- if (uid === "unauth" || uid == null) {
285
- return [];
286
- }
287
- const list = await this._sub_db.list({ uid: uid });
288
- return list;
289
- }
290
- // Save and delete payments, all failed payments should be deleted from the database.
291
- async _save_payment(payment) {
292
- await this._pay_db.set({
293
- uid: payment.uid == null ? "unauth" : payment.uid,
294
- id: payment.id,
295
- }, payment);
296
- }
297
- async _load_payment(id) {
298
- const uid = id.split("_")[1];
299
- return await this._pay_db.load({ uid, id });
300
- }
301
- async _load_payment_for_public(id) {
302
- return Payment.anonymize(await this._load_payment(id));
303
- }
304
- async _load_payment_by_transaction(tran_id) {
305
- return await this._pay_db.load({ tran_id: tran_id }, { retry: 3 });
306
- }
307
- async _load_payment_by_transaction_for_public(tran_id) {
308
- return Payment.anonymize(await this._load_payment_by_transaction(tran_id));
309
- }
310
- async _delete_payment(id) {
311
- const uid = id.split("_")[1];
312
- await this._pay_db.delete({ uid, id });
313
- }
314
- // Delete all info of a user.
315
- async _delete_user(uid) {
316
- await this._sub_db.delete_many({ uid });
317
- await this._active_sub_db.delete_many({ uid });
318
- await this._pay_db.delete_many({ uid });
319
- // await this._inv_db.delete_all({ uid });
320
- }
321
- // List all active subscriptions.
322
- async _get_all_active_subscriptions() {
323
- return await this._active_sub_db.list_all();
324
- }
325
- // ---------------------------------------------------------
326
- // Overall (private).
327
- // Get product by paddle product id.
328
- _get_product_by_paddle_prod_id(id, throw_err = false) {
329
- let product = null;
330
- for (const p of this.products) {
331
- if (p.is_subscription) {
332
- if (p.plans == null) {
333
- throw Error(`Invalid project "${p.id}" subscription is activated yet no plans are defined.`);
334
- }
335
- for (const plan of p.plans) {
336
- if (plan.paddle_prod_id === id) {
337
- product = plan;
338
- }
339
- }
340
- if (product != null)
341
- break;
342
- }
343
- else if (p.paddle_prod_id === id) {
344
- product = p;
345
- break;
346
- }
347
- }
348
- if (product == null && throw_err) {
349
- throw Error(`Unable to find product "${id}".`);
350
- }
351
- return product;
352
- }
353
- // Get all active products.
354
- async _get_products() {
355
- let response, next = null;
356
- let items = [];
357
- while (true) {
358
- if (next == null) {
359
- response = await this._req("GET", "/products", { status: ["active"], per_page: 100 });
360
- }
361
- else {
362
- response = await this._req("GET", next);
363
- }
364
- items = items.concat(response.data);
365
- if (response.meta.has_more) {
366
- next = response.meta.next;
367
- }
368
- else {
369
- break;
370
- }
371
- }
372
- return items;
373
- }
374
- // Get all active prices.
375
- async _get_prices() {
376
- let response, next = null;
377
- let items = [];
378
- while (true) {
379
- if (next == null) {
380
- response = await this._req("GET", "/prices", { status: ["active"], per_page: 100 });
381
- }
382
- else {
383
- response = await this._req("GET", next);
384
- }
385
- items = items.concat(response.data);
386
- if (response.meta.has_more) {
387
- next = response.meta.next;
388
- }
389
- else {
390
- break;
391
- }
392
- }
393
- return items;
394
- }
395
- // Create or update a product, when existing product is undefined a new product and price will be created.
396
- async _check_product(product, existing_products = [], existing_prices = []) {
397
- // Check create product permission.
398
- const has_create_products_permission = async () => {
399
- if (process.argv.includes("--no-payment-edits")) {
400
- return false;
401
- }
402
- if (this._has_create_products_permission != null) {
403
- return this._has_create_products_permission;
404
- }
405
- const input = await vlib.logging.prompt("Some paddle products have to be edited, do you wish to make these changes? [y/n]: ");
406
- if (["y", "yes", "ok"].includes(input.toLowerCase())) {
407
- this._has_create_products_permission = true;
408
- }
409
- else {
410
- this._has_create_products_permission = false;
411
- }
412
- return this._has_create_products_permission;
413
- };
414
- // Find existing product.
415
- let existing_product = null;
416
- for (const item of existing_products) {
417
- if (item.custom_data.id === product.id) {
418
- existing_product = item;
419
- break;
420
- }
421
- }
422
- // No existing product so create.
423
- if (existing_product == null) {
424
- // Check permission.
425
- if (!await has_create_products_permission()) {
426
- return;
427
- }
428
- // Create product.
429
- this.server.log(0, `Creating product ${product.name}.`);
430
- const created_product = await this._req("POST", "/products", {
431
- name: product.name,
432
- description: product.description,
433
- image_url: product.icon,
434
- tax_category: product.tax_category,
435
- custom_data: { id: product.id },
436
- });
437
- product.paddle_prod_id = created_product.data.id;
438
- // Create price.
439
- this.server.log(0, `Creating a price for product ${product.name}.`);
440
- const created_price = await this._req("POST", "/prices", {
441
- product_id: product.paddle_prod_id,
442
- name: product.name,
443
- description: product.description,
444
- unit_price: { amount: Math.floor(product.price * 100).toString(), currency_code: product.currency },
445
- billing_cycle: product.is_subscription ? { interval: product.interval, frequency: product.frequency } : null,
446
- trial_period: product.is_subscription ? product.trial : null,
447
- tax_mode: this.inclusive_tax ? "internal" : "external",
448
- });
449
- product.price_id = created_price.data.id;
450
- }
451
- // Passed an existing product so check.
452
- else {
453
- // Vars.
454
- product.paddle_prod_id = existing_product.id;
455
- const has_trial = product.is_subscription && product.trial != null;
456
- // Check if the product should be updated.
457
- const update_product = (existing_product.name !== product.name ||
458
- existing_product.description !== product.description ||
459
- existing_product.image_url !== product.icon ||
460
- existing_product.tax_category !== product.tax_category ||
461
- existing_product.status !== "active");
462
- // Update product.
463
- if (update_product) {
464
- if (!await has_create_products_permission()) {
465
- return;
466
- }
467
- this.server.log(0, `Updating product ${product.name}.`);
468
- await this._req("PATCH", `/products/${product.paddle_prod_id}`, {
469
- name: product.name,
470
- description: product.description,
471
- image_url: product.icon,
472
- tax_category: product.tax_category,
473
- custom_data: { id: product.id },
474
- status: "active",
475
- });
476
- }
477
- // Fetch the attached price.
478
- let existing_price = null;
479
- for (const item of existing_prices) {
480
- if (item.product_id === product.paddle_prod_id) {
481
- existing_price = item;
482
- break;
483
- }
484
- }
485
- // Create price.
486
- if (existing_price == null) {
487
- if (!await has_create_products_permission()) {
488
- return;
489
- }
490
- this.server.log(0, `Creating a price for product ${product.name}.`);
491
- const price = await this._req("POST", "/prices", {
492
- product_id: product.paddle_prod_id,
493
- name: product.name,
494
- description: product.description,
495
- unit_price: { amount: Math.floor(product.price * 100).toString(), currency_code: product.currency },
496
- billing_cycle: product.is_subscription ? { interval: product.interval, frequency: product.frequency } : null,
497
- trial_period: product.is_subscription ? product.trial : null,
498
- tax_mode: this.inclusive_tax ? "internal" : "external",
499
- });
500
- product.price_id = price.data.id;
501
- }
502
- // Update price.
503
- else {
504
- // Set id.
505
- product.price_id = existing_price.id;
506
- // Update price.
507
- const update_price = (existing_price.product_id !== product.paddle_prod_id ||
508
- existing_price.name !== product.name ||
509
- existing_price.description !== product.description ||
510
- existing_price.tax_mode !== (this.inclusive_tax ? "internal" : "external") ||
511
- existing_price.unit_price == null ||
512
- existing_price.unit_price.amount !== Math.floor(product.price * 100).toString() ||
513
- existing_price.unit_price.currency_code !== product.currency ||
514
- (product.is_subscription && (existing_price.billing_cycle == null ||
515
- existing_price.billing_cycle.interval !== product.interval ||
516
- existing_price.billing_cycle.frequency !== product.frequency)) ||
517
- (has_trial && (existing_price.trial_period == null ||
518
- existing_price.trial_period.interval !== product.trial?.interval ||
519
- existing_price.trial_period.frequency !== product.trial?.frequency)) ||
520
- existing_price.status !== "active");
521
- // Update price.
522
- if (update_price) {
523
- if (!await has_create_products_permission()) {
524
- return;
525
- }
526
- this.server.log(0, `Updating the price of product ${product.name}.`);
527
- await this._req("PATCH", `/prices/${product.price_id}`, {
528
- // product_id: product.id, // not allowed.
529
- name: product.name,
530
- description: product.description,
531
- unit_price: { amount: Math.floor(product.price * 100).toString(), currency_code: product.currency },
532
- billing_cycle: product.is_subscription ? { interval: product.interval, frequency: product.frequency } : null,
533
- trial_period: product.is_subscription ? product.trial : null,
534
- tax_mode: this.inclusive_tax ? "internal" : "external",
535
- status: "active",
536
- });
537
- }
538
- }
539
- }
540
- }
541
- // Cancel subscription by subscription id.
542
- async _cancel_subscription(id, immediate = false) {
543
- if (id == null) {
544
- throw Error(`Define parameter \"id\".`);
545
- }
546
- // Load subscription object.
547
- const subscription = await this._load_subscription(id);
548
- if (subscription == null) {
549
- throw Error(`Unable to find subscription "${id}".`);
550
- }
551
- // Cancel.
552
- if (subscription.status !== "active") {
553
- throw new ExternalError({
554
- type: "NoActiveSubscriptionError",
555
- message: `This subscription is already cancelled and will become inactive at the end of the billing period.`,
556
- status: Status.bad_request,
557
- });
558
- }
559
- await this._req("POST", `/subscriptions/${subscription.id}/cancel`, {
560
- effective_from: immediate ? "immediately" : null,
561
- });
562
- // Update subscription.
563
- subscription.status = "cancelling";
564
- await this._save_subscription(subscription);
565
- }
566
- // async _cancel_subscription(payment) {
567
- // if (typeof payment === "string") {
568
- // payment = await this._load_payment(payment);
569
- // }
570
- // if (payment.cus_id == null) {
571
- // throw Error(`Payment "${payment.id}" does not have an assigned customer id attribute.`);
572
- // }
573
- // if (payment.sub_id == null) {
574
- // throw Error(`Payment "${payment.id}" does not have an assigned subscription id attribute, it may not be a subscription payment.`);
575
- // }
576
- // if (payment.line_items.length == 0) {
577
- // throw Error(`Payment "${payment.id}" does not contain any line items.`);
578
- // }
579
- // // Cancel.
580
- // const cancellable = [];
581
- // let all_cancelled = null;
582
- // payment.line_items.iterate((item) => {
583
- // const product = this.get_product_sync(item.product);
584
- // if (product.is_subscription) {
585
- // if (item.status === "cancelled" || item.status === "cancelling") {
586
- // if (all_cancelled == null) {
587
- // all_cancelled = true;
588
- // }
589
- // } else if (item.status === "paid" || item.status === "refunding" || item.status === "refunded") {
590
- // all_cancelled = false;
591
- // cancellable.push(item);
592
- // }
593
- // }
594
- // })
595
- // if (all_cancelled) {
596
- // throw new FrontendError(`This subscription is already cancelled and will become inactive at the end of the billing period.`, Status.bad_request);
597
- // }
598
- // if (cancellable.length === 0) {
599
- // throw new FrontendError(`This subscription does not contain any cancellable items, the subscription is likely already cancelled or refunded.`, Status.bad_request);
600
- // }
601
- // await this._req("POST", `/subscriptions/${payment.sub_id}/cancel`, {
602
- // // effective_from: "immediately",
603
- // });
604
- // // Update payment.
605
- // cancellable.iterate((item) => {
606
- // if (item.status === "paid") {
607
- // item.status = "cancelling";
608
- // }
609
- // })
610
- // await this._save_payment(payment);
611
- // /* V1 cancel per product but since the webhook subscription event does not show which sub items are cancelled, this is not possible.
612
- // // Update the subscription items.
613
- // const sub = await this._req("GET", `/subscriptions/${payment.sub_id}`);
614
- // const items = [];
615
- // const cancelled_line_items = [];
616
- // let edits = 0;
617
- // sub.data.items.iterate((sub_item) => {
618
- // // Only for active subscription items.
619
- // if (sub_item.recurring && (sub_item.status === "active" || sub_item.status === "trailing")) {
620
- // // Recurring items.
621
- // const item = payment.line_items.iterate((item) => {
622
- // if (item.paddle_prod_id === sub_item.price.product_id) {
623
- // return item;
624
- // }
625
- // })
626
- // // Item not found, so cancel but do not update status since it is not found.
627
- // if (item == null) {
628
- // console.error(`Unable to find subscription item "${sub_item.price.product_id}" while cancelling. Items: ${JSON.stringify(payment.line_items)}`)
629
- // ++edits;
630
- // }
631
- // // Already cancelling.
632
- // // else if (item.status === "cancelling") {
633
- // // items.push({
634
- // // price_id: sub_item.price.id,
635
- // // quantity: sub_item.quantity,
636
- // // })
637
- // // }
638
- // // Cancel item.
639
- // else if (products == null || products.includes(item.id)) {
640
- // item.status = "cancelling";
641
- // ++edits;
642
- // cancelled_line_items.push(item);
643
- // }
644
- // // Keep item.
645
- // else {
646
- // items.push({
647
- // price_id: sub_item.price.id,
648
- // quantity: sub_item.quantity,
649
- // })
650
- // }
651
- // }
652
- // // Keep all non recurring.
653
- // else if (sub_item.recurring === false) {
654
- // items.push({
655
- // price_id: sub_item.price.id,
656
- // quantity: sub_item.quantity,
657
- // })
658
- // }
659
- // })
660
- // // No edits.
661
- // if (edits === 0) {
662
- // throw Error("This payment does not contain any cancellable subscriptions.");
663
- // }
664
- // // Catch certain error.
665
- // try {
666
- // // Delete the subscription.
667
- // if (items.length === 0) {
668
- // await this._req("POST", `/subscriptions/${payment.sub_id}/cancel`, {});
669
- // }
670
- // // Update the subscription.
671
- // else {
672
- // await this._req("PATCH", `/subscriptions/${payment.sub_id}`, {
673
- // items: items,
674
- // scheduled_change: null,
675
- // proration_billing_mode: "full_next_billing_period",
676
- // });
677
- // }
678
- // } catch (error) {
679
- // if (error.message.indexOf("cannot update subscription, pending scheduled changes") === -1) {
680
- // throw error;
681
- // }
682
- // }
683
- // // Update payment.
684
- // cancelled_line_items.iterate((item) => {
685
- // item.status = "cancelling";
686
- // })
687
- // await this._save_payment(payment);
688
- // */
689
- // }
690
- // Initialize all products.
691
- async _initialize_products({ worker = false, } = {}) {
692
- /* @performance */ let now = this.performance.start();
693
- // Extend and initialize all products.
694
- // Check a payment product / plan product.
695
- const product_ids = [];
696
- let product_index = 0;
697
- const initialize_product = (product) => {
698
- ++product_index;
699
- // Check if the product has a name.
700
- if (product.id == null || product.id === "") {
701
- throw Error(`Product ${product_index} does not have an assigned "id" attribute (string).`);
702
- }
703
- else if (product_ids.includes(product.id)) {
704
- throw Error(`Product ${product_index} has a non unique name "${product.id}".`);
705
- }
706
- product_ids.push(product.id);
707
- // Set the icon absolute url.
708
- if (typeof product.icon === "string" && product.icon.charAt(0) === "/") {
709
- product.icon = `${this.server.full_domain}/${product.icon}`;
710
- }
711
- // Check attributes.
712
- if (typeof product.id !== "string" || product.id === "") {
713
- throw Error(`Product "${product_index}" does not have an assigned "id" attribute (string).`);
714
- }
715
- if (typeof product.name !== "string" || product.name === "") {
716
- throw Error(`Product "${product.id}" does not have an assigned "name" attribute (string).`);
717
- }
718
- if (typeof product.description !== "string" || product.description === "") {
719
- throw Error(`Product "${product.id}" does not have an assigned "description" attribute (string).`);
720
- }
721
- if (typeof product.currency !== "string" || product.currency === "") {
722
- throw Error(`Product "${product.id}" does not have an assigned "currency" attribute (string).`);
723
- }
724
- if (typeof product.price !== "number") {
725
- throw Error(`Product "${product.id}" does not have an assigned "price" attribute (number).`);
726
- }
727
- if (typeof product.tax_category !== "string") {
728
- throw Error(`Product "${product.id}" does not have an assigned "tax_category" attribute (number).`);
729
- }
730
- if (product.is_subscription && typeof product.frequency !== "number") {
731
- throw Error(`Product "${product.id}" does not have an assigned "frequency" attribute (number).`);
732
- }
733
- if (product.is_subscription && typeof product.interval !== "string") {
734
- throw Error(`Product "${product.id}" does not have an assigned "interval" attribute (string).`);
735
- }
736
- };
737
- // Expand the payment products.
738
- let sub_products = 0;
739
- for (const product of this.products) {
740
- if (product.is_subscription) {
741
- // Check plans.
742
- if (!product.plans || !Array.isArray(product.plans)) {
743
- throw Error(`Product "${product_index}" has an incorrect value type for attribute "plans", the valid type is "array".`);
744
- }
745
- // Generate sub id.
746
- product.id = `sub_${sub_products}`;
747
- if (product_ids.includes(product.id)) {
748
- throw Error(`Another product has a reserved name "${product.id}".`);
749
- }
750
- product_ids.push(product.id);
751
- ++sub_products;
752
- // Attributes.
753
- product.is_subscription = true;
754
- // Expand plan attributes.
755
- for (const plan of product.plans) {
756
- plan.is_subscription = true;
757
- plan.subscription_id = product.id;
758
- if (plan.description == null) {
759
- plan.description = product.description;
760
- }
761
- if (plan.currency == null) {
762
- plan.currency = product.currency;
763
- }
764
- if (plan.frequency == null) {
765
- plan.frequency = product.frequency;
766
- }
767
- if (plan.interval == null) {
768
- plan.interval = product.interval;
769
- }
770
- if (plan.tax_category == null) {
771
- plan.tax_category = product.tax_category;
772
- }
773
- if (plan.icon == null) {
774
- plan.icon = product.icon;
775
- }
776
- initialize_product(plan);
777
- }
778
- }
779
- else {
780
- product.is_subscription = false;
781
- initialize_product(product);
782
- }
783
- }
784
- /* @performance */ now = this.performance.end("init-products", now);
785
- // Check registered products.
786
- const last_products = await this._last_products_db.load({ production: this.server.production, version: 1 }, { throw: false });
787
- if (last_products instanceof Error && !(last_products instanceof Collection.NotFoundError))
788
- throw last_products;
789
- if (!(last_products instanceof Collection.NotFoundError) && vlib.Object.deep_eq(last_products.last_products, this.products)) {
790
- for (const item of last_products.product_ids) {
791
- const product = this.get_product_sync(item.id);
792
- if (product != null) {
793
- product.paddle_prod_id = item.paddle_prod_id;
794
- product.price_id = item.price_id;
795
- }
796
- }
797
- /* @performance */ now = this.performance.end("assign-product-ids", now);
798
- }
799
- else if (this.server.offline === false) {
800
- // Get all products and prices.
801
- const existing_products = await this._get_products();
802
- const existing_prices = await this._get_prices();
803
- /* @performance */ now = this.performance.end("get-prices-and-products", now);
804
- // Check all products.
805
- const product_ids = [];
806
- for (const product of this.products) {
807
- if (product.is_subscription) {
808
- for (const plan of product.plans) {
809
- await this._check_product(plan, existing_products, existing_prices);
810
- product_ids.append({
811
- id: plan.id,
812
- paddle_prod_id: plan.paddle_prod_id,
813
- price_id: plan.price_id,
814
- });
815
- }
816
- ;
817
- }
818
- else {
819
- await this._check_product(product, existing_products, existing_prices);
820
- product_ids.append({
821
- id: product.id,
822
- paddle_prod_id: product.paddle_prod_id,
823
- price_id: product.price_id,
824
- });
825
- }
826
- }
827
- ;
828
- /* @performance */ now = this.performance.end("check-products", now);
829
- // Save last products.
830
- await this._last_products_db.set({ production: this.server.production, version: 1 }, {
831
- last_products: vlib.Object.delete_recursively(vlib.Object.deep_copy(this.products), ["paddle_prod_id", "price_id"]),
832
- product_ids: product_ids,
833
- });
834
- /* @performance */ now = this.performance.end("save-products-to-db", now);
835
- }
836
- }
837
- // Initialize the payments.
838
- async _initialize({ worker = false, } = {}) {
839
- // Initialize products.
840
- await this._initialize_products({ worker });
841
- /* @performance */ let now = this.performance.start();
842
- if (!worker) {
843
- // Initialize and verify an order, check if the user is authenticated when subscriptions are present and check if the user is not already subscribed to the same item.
844
- this.server.endpoint({
845
- method: "POST",
846
- endpoint: "/volt/api/v1/payments/init",
847
- content_type: "application/json",
848
- rate_limit: "global",
849
- params: {
850
- items: { type: "array", required: true, value_schema: "object" }, // add schema for items
851
- },
852
- callback: async (stream, params) => {
853
- // Check items.
854
- if (params.items.length === 0) {
855
- return stream.error({ status: Status.bad_request, message: "Shopping cart is empty." });
856
- }
857
- let sub_plan_count = {};
858
- let error = undefined;
859
- for (const item of params.items) {
860
- if (item.product.is_subscription) {
861
- if (stream.uid == null) {
862
- error = "You must be signed-in to purchase a subscription.";
863
- break;
864
- }
865
- if (item.quantity != null && item.quantity > 1) {
866
- error = "Subscriptions have a max quantity of 1.";
867
- break;
868
- }
869
- if (sub_plan_count[item.product.subscription_id] == null) {
870
- sub_plan_count[item.product.subscription_id] = 1;
871
- }
872
- else {
873
- error = "You can not charge two different subscription plans from the same subscription product.";
874
- break;
875
- }
876
- if (await this._check_subscription(stream.uid, item.product.id, false)) {
877
- error = `You are already subscribed to product "${item.product.name}".`;
878
- break;
879
- }
880
- }
881
- }
882
- if (error) {
883
- return stream.error({ status: Status.bad_request, message: error });
884
- }
885
- // Success.
886
- return stream.success({ data: { message: "Successfully initialized the order." } });
887
- }
888
- });
889
- // Get products.
890
- this.server.endpoint({
891
- method: "GET",
892
- endpoint: "/volt/api/v1/payments/products",
893
- content_type: "application/json",
894
- rate_limit: "global",
895
- callback: (stream) => {
896
- return stream.success({ data: this.products });
897
- }
898
- });
899
- // Get payment by id.
900
- this.server.endpoint({
901
- method: "GET",
902
- endpoint: "/volt/api/v1/payments/payment",
903
- content_type: "application/json",
904
- rate_limit: "global",
905
- params: {
906
- id: "string",
907
- },
908
- callback: async (stream, params) => {
909
- return stream.success({
910
- data: await this._load_payment_for_public(params.id),
911
- });
912
- }
913
- });
914
- // Get payments.
915
- this.server.endpoint({
916
- method: "GET",
917
- endpoint: "/volt/api/v1/payments/payments",
918
- content_type: "application/json",
919
- authenticated: true,
920
- rate_limit: "global",
921
- params: {
922
- days: { type: "number", default: 30 },
923
- limit: { type: "number", required: false },
924
- status: { type: "string", required: false, enum: PaymentStatusValues },
925
- },
926
- callback: async (stream, params) => {
927
- return stream.success({
928
- data: await this.get_payments({
929
- uid: stream.uid,
930
- days: params.days,
931
- limit: params.limit,
932
- status: params.status,
933
- })
934
- });
935
- }
936
- });
937
- // Get refundable payments.
938
- this.server.endpoint({
939
- method: "GET",
940
- endpoint: "/volt/api/v1/payments/payments/refundable",
941
- content_type: "application/json",
942
- authenticated: true,
943
- rate_limit: "global",
944
- params: {
945
- days: { type: "number", default: 30 },
946
- limit: { type: "number", required: false },
947
- },
948
- callback: async (stream, params) => {
949
- return stream.success({
950
- data: await this.get_refundable_payments({
951
- uid: stream.uid,
952
- days: params.days,
953
- limit: params.limit,
954
- for_public: true,
955
- })
956
- });
957
- }
958
- });
959
- // Get refunded payments.
960
- this.server.endpoint({
961
- method: "GET",
962
- endpoint: "/volt/api/v1/payments/payments/refunded",
963
- content_type: "application/json",
964
- authenticated: true,
965
- rate_limit: "global",
966
- params: {
967
- days: { type: "number", default: 30 },
968
- limit: { type: "number", required: false },
969
- },
970
- callback: async (stream, params) => {
971
- return stream.success({
972
- data: await this.get_refunded_payments({
973
- uid: stream.uid,
974
- days: params.days,
975
- limit: params.limit,
976
- for_public: true,
977
- })
978
- });
979
- }
980
- });
981
- // Get refunding payments.
982
- this.server.endpoint({
983
- method: "GET",
984
- endpoint: "/volt/api/v1/payments/payments/refunding",
985
- content_type: "application/json",
986
- authenticated: true,
987
- rate_limit: "global",
988
- params: {
989
- days: { type: "number", default: 30 },
990
- limit: { type: "number", required: false },
991
- },
992
- callback: async (stream, params) => {
993
- return stream.success({
994
- data: await this.get_refunding_payments({
995
- uid: stream.uid,
996
- days: params.days,
997
- limit: params.limit,
998
- for_public: true,
999
- })
1000
- });
1001
- }
1002
- });
1003
- // Create a refund.
1004
- this.server.endpoint({
1005
- method: "POST",
1006
- endpoint: "/volt/api/v1/payments/refund",
1007
- content_type: "application/json",
1008
- authenticated: true,
1009
- rate_limit: "global",
1010
- params: {
1011
- payment: { type: ["string", "object"], schema: { id: "string" } },
1012
- line_items: { type: "array", required: false, value_schema: {
1013
- type: "object", schema: LineItem.Schema
1014
- } },
1015
- reason: { type: "string", default: "refund" },
1016
- },
1017
- callback: async (stream, params) => {
1018
- await this.create_refund(typeof params.payment === "string" ? params.payment : params.payment.id, params.line_items, params.reason);
1019
- return stream.success();
1020
- }
1021
- });
1022
- // Cancel a subscription.
1023
- this.server.endpoint({
1024
- method: "DELETE",
1025
- endpoint: "/volt/api/v1/payments/subscription",
1026
- content_type: "application/json",
1027
- authenticated: true,
1028
- rate_limit: "global",
1029
- params: {
1030
- product: "string",
1031
- },
1032
- callback: async (stream, params) => {
1033
- await this.cancel_subscription(stream.uid, params.product);
1034
- return stream.success();
1035
- }
1036
- });
1037
- // Cancel a subscription by payment.
1038
- // {
1039
- // method: "DELETE",
1040
- // endpoint: "/volt/api/v1/payments/subscription_by_payment",
1041
- // content_type: "application/json",
1042
- // authenticated: true,
1043
- // rate_limit: "global",
1044
- // params: {
1045
- // payment: {type: ["string", "object"]},
1046
- // },
1047
- // callback: async (stream, params) => {
1048
- // await this.cancel_subscription_by_payment(params.payment);
1049
- // return stream.success();
1050
- // }
1051
- // },
1052
- // Get active subscriptions.
1053
- this.server.endpoint({
1054
- method: "GET",
1055
- endpoint: "/volt/api/v1/payments/active_subscriptions",
1056
- content_type: "application/json",
1057
- authenticated: true,
1058
- rate_limit: "global",
1059
- callback: async (stream) => {
1060
- return stream.success({
1061
- data: {
1062
- subscriptions: await this.get_active_subscriptions(stream.uid)
1063
- },
1064
- });
1065
- }
1066
- });
1067
- // Is subscribed
1068
- this.server.endpoint({
1069
- method: "GET",
1070
- endpoint: "/volt/api/v1/payments/subscribed",
1071
- content_type: "application/json",
1072
- authenticated: true,
1073
- rate_limit: "global",
1074
- params: {
1075
- product: "string",
1076
- },
1077
- callback: async (stream, params) => {
1078
- return stream.success({
1079
- data: {
1080
- is_subscribed: (await this.is_subscribed(stream.uid, params.product))
1081
- }
1082
- });
1083
- }
1084
- });
1085
- // Webhook.
1086
- if (!this.server.offline) {
1087
- this.server.endpoint(await this._create_webhook());
1088
- }
1089
- }
1090
- /* @performance */ now = this.performance.end("init-endpoints", now);
1091
- // /* @performance */ this.performance.dump();
1092
- }
1093
- // ---------------------------------------------------------
1094
- // Webhook (private).
1095
- // Execute a webhook user defined callback.
1096
- async _exec_user_callback(callback, args) {
1097
- if (callback != null) {
1098
- try {
1099
- let res = callback(args);
1100
- if (res instanceof Promise) {
1101
- res = await res;
1102
- }
1103
- }
1104
- catch (error) {
1105
- console.error(error);
1106
- }
1107
- }
1108
- }
1109
- // Send a payment mail.
1110
- // async _send_payment_mail({payment, subject, attachments = [], mail}) {
1111
- // await this.server.send_mail({
1112
- // recipients: [payment.billing_details.name == null ? payment.billing_details.email : [payment.billing_details.name, payment.billing_details.email]],
1113
- // subject,
1114
- // body: mail.html(),
1115
- // attachments,
1116
- // })
1117
- // }
1118
- // On a successfull payment webhook event.
1119
- async _payment_webhook(data) {
1120
- // ---------------------------------------------------------
1121
- // Get the transaction.
1122
- // Only used in the paid webhook, other parts use the saved payment object.
1123
- // This is required to manage the statuses of payments.
1124
- // Make request.
1125
- let obj = (await this._req("GET", `/transactions/${data.id}`, { include: ["address", "adjustments", "business", "customer"] })).data;
1126
- // Initialize.
1127
- const id = `pay_${obj.custom_data.uid == null ? "unauth" : obj.custom_data.uid}_${vlib.String.random(4)}${Date.now()}`;
1128
- const payment = {
1129
- id: id, // payment id.
1130
- uid: obj.custom_data.uid, // user id,
1131
- cus_id: obj.customer_id, // customer id.
1132
- tran_id: obj.id, // transaction id.
1133
- timestamp: Date.now(),
1134
- status: "unknown", // payment status, possible values are "open" or "paid".
1135
- line_items: [], // cart line items as {quantity: 1, product: "prod_xxx"}.
1136
- billing_details: {
1137
- name: undefined,
1138
- email: undefined,
1139
- business: undefined,
1140
- vat_id: undefined,
1141
- address: undefined,
1142
- city: undefined,
1143
- postal_code: undefined,
1144
- province: undefined,
1145
- country: undefined,
1146
- tax_identifier: undefined,
1147
- },
1148
- };
1149
- // Set business details.
1150
- if (obj.business != null) {
1151
- const b = obj.business;
1152
- if (b != null && b.name != null && b.name.length > 0) {
1153
- payment.billing_details.business = b.name;
1154
- }
1155
- if (b.tax_identifier != null && b.tax_identifier.length > 0) {
1156
- payment.billing_details.tax_identifier = b.tax_identifier;
1157
- }
1158
- if (b.contacts.length > 0) {
1159
- const contact = b.contacts[0];
1160
- payment.billing_details.name = contact.name;
1161
- payment.billing_details.email = contact.email;
1162
- }
1163
- }
1164
- // Set email when not already set.
1165
- if (payment.billing_details.email == null && obj.customer != null && obj.customer.email != null && obj.customer.email.length > 0) {
1166
- payment.billing_details.email = obj.customer.email;
1167
- }
1168
- // Set name when not already set.
1169
- if (payment.billing_details.name == null && obj.custom_data.customer_name != null && obj.custom_data.customer_name != null && obj.custom_data.customer_name.length > 0) {
1170
- payment.billing_details.name = obj.custom_data.customer_name;
1171
- }
1172
- // Set address details.
1173
- if (obj.address != null) {
1174
- const a = obj.address;
1175
- if (a.first_line != null && a.first_line.length > 0) {
1176
- payment.billing_details.address = a.first_line;
1177
- }
1178
- if (a.city != null && a.city.length > 0) {
1179
- payment.billing_details.city = a.city;
1180
- }
1181
- if (a.postal_code != null && a.postal_code.length > 0) {
1182
- payment.billing_details.postal_code = a.postal_code;
1183
- }
1184
- if (a.region != null && a.region.length > 0) {
1185
- payment.billing_details.province = a.region;
1186
- }
1187
- if (a.country_code != null && a.country_code.length > 0) {
1188
- payment.billing_details.country = a.country_code;
1189
- }
1190
- }
1191
- // Set the status.
1192
- switch (obj.status) {
1193
- case "draft":
1194
- case "ready":
1195
- payment.status = "open";
1196
- break;
1197
- case "billed":
1198
- case "paid":
1199
- case "completed":
1200
- payment.status = "paid";
1201
- break;
1202
- case "past_due":
1203
- payment.status = "past_due";
1204
- break;
1205
- default:
1206
- this.server.log.error(`Payment Webhook: Unknown payment status "${obj.status}".`);
1207
- payment.status = "unknown";
1208
- break;
1209
- }
1210
- // Set line items.
1211
- obj.details.line_items.iterate((item) => {
1212
- payment.line_items.push({
1213
- product: item.product.custom_data.id, // product id, keep as id since we do not want to save the product object to the database since this can change.
1214
- item_id: item.id, // transaction item id.
1215
- paddle_prod_id: item.product.id, // paddle product id.
1216
- quantity: item.quantity,
1217
- tax_rate: parseFloat(item.tax_rate),
1218
- tax: item.totals.tax / 100, // should not be changed to unit totals, since mails and invoices depend on this behaviour, just divide by quantity.
1219
- discount: item.totals.discount / 100, // should not be changed to unit totals, since mails and invoices depend on this behaviour, just divide by quantity.
1220
- subtotal: item.totals.subtotal / 100, // should not be changed to unit totals, since mails and invoices depend on this behaviour, just divide by quantity.
1221
- total: item.totals.total / 100, // should not be changed to unit totals, since mails and invoices depend on this behaviour, just divide by quantity.
1222
- status: "paid", // can be "paid", "refunded", "refunding".
1223
- });
1224
- });
1225
- // Parse refunds.
1226
- if (obj.adustments != null) {
1227
- obj.adustments.iterate((adj) => {
1228
- switch (adj.action) {
1229
- case "refund":
1230
- case "chargeback":
1231
- // case "chargeback_warning":
1232
- for (const adj_item of adj.items) {
1233
- for (const item of payment.line_items) {
1234
- if (adj_item.item_id === item.item_id) {
1235
- item.status = "refunded";
1236
- break;
1237
- }
1238
- }
1239
- }
1240
- break;
1241
- case "chargeback_reversal":
1242
- for (const adj_item of adj.items) {
1243
- for (const item of payment.line_items) {
1244
- if (adj_item.item_id === item.item_id) {
1245
- item.status = "paid";
1246
- break;
1247
- }
1248
- }
1249
- }
1250
- break;
1251
- default:
1252
- break;
1253
- }
1254
- });
1255
- }
1256
- // Save the payment object in the database.
1257
- await this._save_payment(payment);
1258
- // ---------------------------------------------------------
1259
- // Process the payment.
1260
- const { uid } = payment;
1261
- // Check the payment line items.
1262
- for (const item of payment.line_items) {
1263
- const product = this.get_product_sync(item.product, false);
1264
- // @todo REFUND PAYMENT SINCE PRODUCT WAS NOT FOUND SO NO WAY OF DELIVERY.
1265
- // Refund the payment since there is no way of delivery.
1266
- // 1) Product not found.
1267
- // 2) No subscription id found from the webhook data.
1268
- if (product == null) {
1269
- continue;
1270
- }
1271
- // Subscription.
1272
- else if (product.is_subscription) {
1273
- // No need to activate the sub, this is already handled by the sub activated webhook.
1274
- //
1275
- // Cancel the other subscriptions plans that are part of this product.
1276
- // The `create_payment()` function makes sure there are not multiple subscription plans of the same subscription product charged in a single request.
1277
- const subscription = await this.get_product(product.subscription_id, true);
1278
- for (const plan of subscription?.plans ?? []) {
1279
- if (plan.id != product.id) {
1280
- const { exists, sub_id } = await this._check_subscription(uid, plan.id);
1281
- if (exists) {
1282
- this.server.log(0, `Cancelling subscription "${plan.id}" due too downgrade/upgrade to "${product.id}" of user "${payment.uid}".`);
1283
- // @todo cancel sub by sub id.
1284
- await this._cancel_subscription(sub_id);
1285
- }
1286
- }
1287
- }
1288
- // No need to execute the callback, this is already handled by the sub activated webhook.
1289
- //
1290
- }
1291
- // One time payment.
1292
- else {
1293
- // Execute callback.
1294
- await this._exec_user_callback(this.server.on_payment, { product, payment });
1295
- }
1296
- }
1297
- // Send an email to the user.
1298
- // try {
1299
- // await this._send_payment_mail({
1300
- // payment,
1301
- // subject: "Payment Successful",
1302
- // mail: this.server.on_payment_mail({payment}),
1303
- // attachments: [this.generate_invoice_sync(payment)],
1304
- // });
1305
- // } catch (error) {
1306
- // console.error(error);
1307
- // }
1308
- }
1309
- // On subscription activated webhook event.
1310
- // Even though the payment webhook could take care of this, still keep it seperated for customization, and possibly a new activation in certain scenerario's perhaps past due invoice, not sure just in case.
1311
- async _subscription_webhook(data) {
1312
- // Vars.
1313
- const uid = data.custom_data.uid;
1314
- const subscription = {
1315
- uid,
1316
- id: data.id,
1317
- cus_id: data.customer_id, // customer id.
1318
- status: "active", // can be "active", "cancelling", "cancelled".
1319
- plans: [],
1320
- };
1321
- // Check the subscription line items.
1322
- for (const item of data.items) {
1323
- const product = this._get_product_by_paddle_prod_id(item.price.product_id, false);
1324
- // Product not found or no sub id found, nothing to do here, the payment webhook already handles this scenario.
1325
- if (product == null) {
1326
- this.server.log.error(`Subscription webhook [#sub1]: Unable to find product with id ${item.price.product_id}. This is a serious error which causes a non activated subscription for a paid transaction. You should manually cancel the subscription. Event: ${JSON.stringify(data, null, 4)}.`);
1327
- continue;
1328
- }
1329
- // Subscription.
1330
- else if (product.is_subscription) {
1331
- // Add to plans.
1332
- subscription.plans.append(product.id);
1333
- // Active the user's subscription in the database.
1334
- this.server.log(0, `Activating subscription "${product.id}" of user "${subscription.uid}".`);
1335
- await this._add_subscription(uid, product.id, subscription.id);
1336
- // No need to cancel other subs, this is already handled by the payment webhook.
1337
- // Execute callback.
1338
- await this._exec_user_callback(this.server.on_subscription, { product, subscription });
1339
- }
1340
- }
1341
- // Save subscription.
1342
- await this._save_subscription(subscription);
1343
- // No need to send mail, payment webhook already handles this.
1344
- }
1345
- // On a subscription cancelled webhook event.
1346
- async _subscription_cancelled_webhook(data) {
1347
- // Vars.
1348
- const subscription = await this._load_subscription(data.id);
1349
- // Delete subscriptions made by this subscription.
1350
- for (const plan_id of subscription.plans) {
1351
- await this._delete_subscription(subscription.uid, plan_id);
1352
- this.server.log(0, `Deactivating subscription "${plan_id}" of user "${subscription.uid}".`);
1353
- }
1354
- // Update database.
1355
- subscription.status = "cancelled";
1356
- await this._save_subscription(subscription);
1357
- // Execute callback.
1358
- await this._exec_user_callback(this.server.on_cancellation, { subscription });
1359
- // Send an email to the user.
1360
- // try {
1361
- // await this._send_payment_mail({
1362
- // payment,
1363
- // subject: "Cancellation Successful",
1364
- // mail: this.server.on_cancellation_mail({payment, line_items}),
1365
- // });
1366
- // } catch (error) {
1367
- // console.error(error);
1368
- // }
1369
- }
1370
- // On a adjustment (refunds) updated webhook event.
1371
- async _adjustment_webhook(data) {
1372
- // Refund or chageback.
1373
- const is_refund = data.action === "refund";
1374
- const is_chargeback = data.action === "chargeback";
1375
- if (is_refund || is_chargeback) {
1376
- if (data.status === "pending_approval") {
1377
- return;
1378
- }
1379
- const is_approved = data.status === "approved";
1380
- // Vars.
1381
- const payment = await this._load_payment_by_transaction(data.transaction_id);
1382
- // Get and update line items.
1383
- const line_items = [], cancel_products = [];
1384
- for (const adj_item of data.items) {
1385
- for (const item of payment.line_items) {
1386
- if (item.item_id === adj_item.item_id) {
1387
- item.status = is_approved ? "refunded" : "paid";
1388
- cancel_products.push(item.product);
1389
- line_items.push(item);
1390
- break;
1391
- }
1392
- }
1393
- }
1394
- // Manage subscriptions.
1395
- if (payment.sub_id != null && is_approved) {
1396
- await this._cancel_subscription(payment.sub_id, true);
1397
- }
1398
- // Update database.
1399
- if (line_items.length > 0) {
1400
- await this._save_payment(payment);
1401
- }
1402
- // Execute callback.
1403
- if (is_approved) {
1404
- this.server.log(0, `Refunded items of payment "${payment.id}" of user "${payment.uid}".`);
1405
- await this._exec_user_callback(is_refund ? this.server.on_refund : this.server.on_chargeback, { payment, line_items });
1406
- // try {
1407
- // await this._send_payment_mail({
1408
- // payment,
1409
- // subject: "Successful " + (is_refund ? "Refund" : "Chargeback"),
1410
- // mail: is_refund ? this.server.on_refund_mail({payment, line_items}) : this.server.on_chargeback_mail({payment, line_items}),
1411
- // });
1412
- // } catch (error) {
1413
- // console.error(error);
1414
- // }
1415
- }
1416
- else {
1417
- this.server.log(0, `Refund denied for items of payment ${payment.id} of user "${payment.uid}".`);
1418
- await this._exec_user_callback(is_refund ? this.server.on_failed_refund : this.server.on_failed_chargeback, { payment, line_items });
1419
- // try {
1420
- // await this._send_payment_mail({
1421
- // payment,
1422
- // subject: "Failed " + (is_refund ? "Refund" : "Chargeback"),
1423
- // mail: is_refund ? this.server.on_failed_refund_mail({payment, line_items}) : this.server.on_failed_chargeback_mail({payment, line_items}),
1424
- // });
1425
- // } catch (error) {
1426
- // console.error(error);
1427
- // }
1428
- }
1429
- }
1430
- // Chargeback reversal.
1431
- else if (data.action === "chargeback_reverse" && data.status === "reversed") {
1432
- // Vars.
1433
- const payment = await this._load_payment_by_transaction(data.transaction_id);
1434
- // Log reactivation subscriptions on chargeback reverse.
1435
- if (payment.sub_id != null) {
1436
- this.server.log(0, `Chargeback reversed for payment ${payment.id} from user "${payment.uid}".`);
1437
- // @todo.
1438
- }
1439
- // Get and update line items.
1440
- let line_items = [];
1441
- for (const adj_item of data.items) {
1442
- for (const item of payment.line_items) {
1443
- if (item.item_id === adj_item.item_id) {
1444
- item.status = "paid";
1445
- line_items.push(item);
1446
- }
1447
- }
1448
- }
1449
- // Update database.
1450
- if (line_items.length > 0) {
1451
- await this._save_payment(payment);
1452
- }
1453
- }
1454
- }
1455
- // Create and register the webhook endpoint.
1456
- async _create_webhook() {
1457
- /* @performance */ const now = this.performance.start();
1458
- // Register the webhook.
1459
- const webhook_settings = {
1460
- description: "volt webhook",
1461
- destination: `${this.server.full_domain}/volt/payments/webhook`,
1462
- type: "url",
1463
- subscribed_events: [
1464
- // "transaction.billed",
1465
- // "transaction.canceled",
1466
- // "transaction.completed",
1467
- // "transaction.created",
1468
- "transaction.paid",
1469
- // "transaction.past_due",
1470
- // "transaction.payment_failed",
1471
- // "transaction.ready",
1472
- // "transaction.updated",
1473
- "subscription.activated",
1474
- "subscription.canceled",
1475
- // "subscription.created",
1476
- // "subscription.imported",
1477
- // "subscription.past_due",
1478
- "subscription.paused",
1479
- "subscription.resumed",
1480
- "subscription.trialing",
1481
- // "subscription.updated",
1482
- "adjustment.updated",
1483
- ],
1484
- };
1485
- const hashed_webhook_settings = this.server.hash(webhook_settings);
1486
- // Register webhook.
1487
- const register_webhook = async () => {
1488
- this.server.log(0, "Registering payments webhook.");
1489
- const response = await this._req("POST", "/notification-settings", webhook_settings);
1490
- this.webhook_key = response.data.endpoint_secret_key;
1491
- await this._webhook_conf_db.set({ production: this.server.production, version: 1 }, {
1492
- id: response.data.id,
1493
- key: this.webhook_key,
1494
- hash: this.server.hash(webhook_settings),
1495
- });
1496
- };
1497
- // For speeding up the restart process we store the hash of the previous webhook under a temporary document.
1498
- const home_dir = vlib.Path.home().join(".volt/cache");
1499
- if (!home_dir.exists()) {
1500
- home_dir.mkdir({ recursive: true });
1501
- }
1502
- const cached_local_hash_file = home_dir.join(`paddle_webhook_${this.server.production ? "live" : "sandbox"}.hash`);
1503
- const cached_local_hash = cached_local_hash_file.exists() ? (await cached_local_hash_file.load()) : null;
1504
- if (cached_local_hash !== hashed_webhook_settings) {
1505
- // Load webhook doc.
1506
- const webhook_doc = await this._webhook_conf_db.load({ production: this.server.production, version: 1 }, { throw: false });
1507
- if (webhook_doc instanceof Error && !(webhook_doc instanceof Collection.NotFoundError)) {
1508
- throw webhook_doc;
1509
- }
1510
- // Webhook registered.
1511
- if (!(webhook_doc instanceof Collection.NotFoundError)) {
1512
- this.webhook_key = webhook_doc.key;
1513
- // Check update required.
1514
- if (webhook_doc.hash !== hashed_webhook_settings) {
1515
- this.server.log(0, `Checking payments webhook.`);
1516
- // Check update required.
1517
- const webhook_id = webhook_doc.id;
1518
- let registered;
1519
- try {
1520
- registered = await this._req("GET", `/notification-settings/${webhook_id}`);
1521
- }
1522
- catch (error) {
1523
- if (error.status === 404 || error.status_code === 404) {
1524
- registered = undefined;
1525
- await register_webhook();
1526
- }
1527
- else {
1528
- throw error;
1529
- }
1530
- }
1531
- if (registered) {
1532
- const item = registered.data;
1533
- const patch = (() => {
1534
- if (item.active !== true ||
1535
- item.destination !== webhook_settings.destination ||
1536
- item.type !== webhook_settings.type ||
1537
- item.description !== webhook_settings.description ||
1538
- item.subscribed_events.length != webhook_settings.subscribed_events.length) {
1539
- return true;
1540
- }
1541
- let has_subscribed_event_missing = false;
1542
- for (const x of webhook_settings.subscribed_events) {
1543
- let found = false;
1544
- for (const y of item.subscribed_events) {
1545
- if (x === y.name) {
1546
- found = true;
1547
- break;
1548
- }
1549
- }
1550
- if (found === false) {
1551
- has_subscribed_event_missing = true;
1552
- break;
1553
- }
1554
- }
1555
- return has_subscribed_event_missing;
1556
- })();
1557
- // Update.
1558
- if (patch === true) {
1559
- this.server.log(0, "Updating payments webhook.");
1560
- await this._req("PATCH", `/notification-settings/${webhook_id}`, { ...webhook_settings, active: true });
1561
- }
1562
- // Save new hash.
1563
- await this._webhook_conf_db.set({ production: this.server.production, version: 1 }, { hash: this.server.hash(webhook_settings) });
1564
- }
1565
- }
1566
- }
1567
- // Register webhook.
1568
- else {
1569
- await register_webhook();
1570
- }
1571
- // Save the new hash.
1572
- await cached_local_hash_file.save(hashed_webhook_settings);
1573
- }
1574
- // Ip whitelist.
1575
- const ip_whitelist = [
1576
- // Live.
1577
- "34.232.58.13",
1578
- "34.195.105.136",
1579
- "34.237.3.244",
1580
- "35.155.119.135",
1581
- "52.11.166.252",
1582
- "34.212.5.7",
1583
- // Sandbox.
1584
- "34.194.127.46",
1585
- "54.234.237.108",
1586
- "3.208.120.145",
1587
- "44.226.236.210",
1588
- "44.241.183.62",
1589
- "100.20.172.113",
1590
- ];
1591
- /* @performance */ this.server.performance.end("create-payments-webhook", now);
1592
- // Create the endpoint.
1593
- return {
1594
- method: "POST",
1595
- endpoint: "/volt/api/v1/payments/webhook",
1596
- content_type: "application/json",
1597
- rate_limit: undefined,
1598
- callback: async (stream) => {
1599
- // Ip whitelist.
1600
- if (ip_whitelist.includes(stream.ip) === false) {
1601
- this.server.log(0, `POST:/volt/payments/webhook: Warning: Blocking non whitelisted ip "${stream.ip}".`);
1602
- return stream.error({ status: Status.unauthorized });
1603
- }
1604
- // Verify.
1605
- const full_signature = stream.headers["paddle-signature"];
1606
- if (full_signature == null) {
1607
- this.server.log(0, "POST:/volt/payments/webhook: Error: No paddle signature found in the request headers.");
1608
- return stream.error({ status: Status.unauthorized, data: { error: "Webhook signature verification failed." } });
1609
- }
1610
- const ts_index = full_signature.indexOf(";");
1611
- const ts = full_signature.substr(3, ts_index - 3);
1612
- const signature = full_signature.substr(ts_index + 4);
1613
- const digest = libcrypto.createHmac("sha256", this.webhook_key).update(`${ts}:${stream.body}`).digest("hex");
1614
- if (libcrypto.timingSafeEqual(Buffer.from(digest, "hex"), Buffer.from(signature, "hex")) !== true) {
1615
- this.server.log(0, "POST:/volt/payments/webhook: Error: Webhook signature verification failed.");
1616
- return stream.error({ status: Status.unauthorized, data: { error: "Webhook signature verification failed." } });
1617
- }
1618
- // Process items.
1619
- const event = JSON.parse(stream.body);
1620
- switch (event.event_type) {
1621
- // Paid transaction.
1622
- // https://developer.paddle.com/webhooks/transactions/transaction-paid
1623
- case "transaction.paid":
1624
- await this._payment_webhook(event.data);
1625
- break;
1626
- // Subscription activated.
1627
- // https://developer.paddle.com/webhooks/subscriptions/subscription-activated
1628
- case "subscription.activated":
1629
- case "subscription.trialing":
1630
- case "subscription.resumed":
1631
- await this._subscription_webhook(event.data);
1632
- break;
1633
- // Subscription canceled.
1634
- // https://developer.paddle.com/webhooks/subscriptions/subscription-canceled
1635
- case "subscription.canceled":
1636
- case "subscription.paused":
1637
- await this._subscription_cancelled_webhook(event.data);
1638
- break;
1639
- // Adjustment updated (refunds).
1640
- // https://developer.paddle.com/webhooks/subscriptions/subscription-canceled
1641
- case "adjustment.updated":
1642
- await this._adjustment_webhook(event.data);
1643
- break;
1644
- // Default.
1645
- default: break;
1646
- }
1647
- // Success.
1648
- stream.success({ data: { message: "OK" } });
1649
- },
1650
- };
1651
- }
1652
- async get_product(id, throw_err = false) {
1653
- return this.get_product_sync(id, throw_err);
1654
- }
1655
- get_product_sync(id, throw_err = false) {
1656
- let product = null;
1657
- for (const p of this.products) {
1658
- if (p.is_subscription) {
1659
- if (p.id === id) {
1660
- product = p;
1661
- break;
1662
- }
1663
- for (const plan of p.plans) {
1664
- if (plan.id === id) {
1665
- product = plan;
1666
- break;
1667
- }
1668
- }
1669
- }
1670
- else if (p.id === id) {
1671
- product = p;
1672
- break;
1673
- }
1674
- }
1675
- if (product == null && throw_err) {
1676
- throw Error(`Unable to find product "${id}".`);
1677
- }
1678
- return product;
1679
- }
1680
- /* @docs:
1681
- @title: Get Payment.
1682
- @desc: Get a payment by id.
1683
- @param:
1684
- @name: id
1685
- @required: true
1686
- @type: string
1687
- @desc: The id of the payment.
1688
- */
1689
- async get_payment(id, opts) {
1690
- if (opts?.for_public) {
1691
- return await this._load_payment_for_public(id);
1692
- }
1693
- return await this._load_payment(id);
1694
- }
1695
- /* @docs:
1696
- @title: Get Refunded Payments.
1697
- @desc:
1698
- Get all payments.
1699
-
1700
- All failed payments are no longer stored in the database.
1701
- @param:
1702
- @name: uid
1703
- @cached: Users:uid:param
1704
- @param:
1705
- @name: days
1706
- @type: number
1707
- @desc: Retrieve payments from the last amount of days.
1708
- @param:
1709
- @name: limit
1710
- @type: number
1711
- @desc: Limit the amount of response payment objects.
1712
- @param:
1713
- @name: status
1714
- @type: string, array[string]
1715
- @desc: Filter the payments by status. Be aware that the line items of a payment also have a status with possible values of `open`, `cancelled`, `refunding` or `refunded.`
1716
- @enum:
1717
- @value: "open"
1718
- @desc: Payments that are still open and unpaid.
1719
- @enum:
1720
- @value: "paid"
1721
- @desc: Payments that are paid.
1722
- */
1723
- async get_payments({ uid, days = 30, limit = 10_000, status = undefined, for_public, }) {
1724
- // Get path.
1725
- const query = {
1726
- uid,
1727
- };
1728
- if (days != null) {
1729
- const since = new Date();
1730
- since.setHours(0, 0, 0, 0);
1731
- query.timestamp = { $gte: Math.floor(since.getTime() - (3600 * 24 * 1000 * days)) };
1732
- }
1733
- if (Array.isArray(status)) {
1734
- query.status = { $in: status };
1735
- }
1736
- else if (typeof status === "string") {
1737
- query.status = status;
1738
- }
1739
- const payments = await this._pay_db.list(query, { limit });
1740
- // Sort.
1741
- payments.sort((a, b) => b.timestamp - a.timestamp);
1742
- // Response.
1743
- return (for_public
1744
- ? payments.map(p => Payment.anonymize(p))
1745
- : payments);
1746
- }
1747
- /* @docs:
1748
- @title: Get Refundable Payments.
1749
- @desc: Get all payments that are refundable.
1750
- @param:
1751
- @name: uid
1752
- @cached: Users:uid:param
1753
- @param:
1754
- @name: days
1755
- @type: number
1756
- @desc: Retrieve payments from the last amount of days.
1757
- @param:
1758
- @name: limit
1759
- @type: number
1760
- @desc: Limit the amount of response payment objects.
1761
- */
1762
- async get_refundable_payments({ uid, days = 30, limit = undefined, for_public, }) {
1763
- const out = [];
1764
- const all_payments = await this.get_payments({ uid, days, limit, status: "paid", for_public });
1765
- for (const pmt of all_payments) {
1766
- const refundable = pmt.line_items.filter((li) => li.status === "paid" && li.total > 0);
1767
- if (refundable.length > 0) {
1768
- out.push({ ...pmt, line_items: refundable });
1769
- }
1770
- }
1771
- return out;
1772
- }
1773
- /* @docs:
1774
- @title: Get Refunded Payments.
1775
- @desc: Get all payments that are successfully refunded.
1776
- @param:
1777
- @name: uid
1778
- @cached: Users:uid:param
1779
- @param:
1780
- @name: days
1781
- @type: number
1782
- @desc: Retrieve payments from the last amount of days.
1783
- @param:
1784
- @name: limit
1785
- @type: number
1786
- @desc: Limit the amount of response payment objects.
1787
- */
1788
- async get_refunded_payments({ uid, days = 30, limit = undefined, for_public, }) {
1789
- const out = [];
1790
- const all_payments = await this.get_payments({ uid, days, limit, status: "paid", for_public });
1791
- for (const pmt of all_payments) {
1792
- const refundable = pmt.line_items.filter((li) => li.status === "refunded" && li.total > 0);
1793
- if (refundable.length > 0) {
1794
- out.push({ ...pmt, line_items: refundable });
1795
- }
1796
- }
1797
- return out;
1798
- }
1799
- /* @docs:
1800
- @title: Get Refunding Payments.
1801
- @desc: Get all payments that are currently in the refunding process.
1802
- @param:
1803
- @name: uid
1804
- @cached: Users:uid:param
1805
- @param:
1806
- @name: days
1807
- @type: number
1808
- @desc: Retrieve payments from the last amount of days.
1809
- @param:
1810
- @name: limit
1811
- @type: number
1812
- @desc: Limit the amount of response payment objects.
1813
- */
1814
- async get_refunding_payments({ uid, days = undefined, limit = undefined, for_public, }) {
1815
- const out = [];
1816
- const all_payments = await this.get_payments({ uid, days, limit, status: "paid", for_public });
1817
- for (const pmt of all_payments) {
1818
- const refundable = pmt.line_items.filter((li) => li.status === "refunding" && li.total > 0);
1819
- if (refundable.length > 0) {
1820
- out.push({ ...pmt, line_items: refundable });
1821
- }
1822
- }
1823
- return out;
1824
- }
1825
- /* @docs:
1826
- @title: Refund Payment.
1827
- @desc: Refund a payment based on the payment id.
1828
- @warning: Refunding a subscription will also cancel all other subscriptions that were created by the same payment request.
1829
- @param:
1830
- @name: payment
1831
- @required: true
1832
- @type: number
1833
- @desc: The id of the payment object or the payment object itself.
1834
- @param:
1835
- @name: line_items
1836
- @type: array[object]
1837
- @desc: The line items to refund, these must be retrieved from the original payment line items otherwise it may cause undefined behaviour. When undefined the entire payment will be refunded.
1838
- @param:
1839
- @name: reason
1840
- @type: string
1841
- @desc: The refund reason for internal analytics.
1842
- */
1843
- async create_refund(payment, line_items = undefined, reason = "refund") {
1844
- // Load payment.
1845
- // The payment must be loaded from the database in case the line items or anything were edited by the user, such as dropping all non refundable line items.
1846
- if (typeof payment === "string") {
1847
- payment = await this._load_payment(payment);
1848
- }
1849
- else {
1850
- payment = await this._load_payment(payment.id);
1851
- }
1852
- // When no line items are defined than refund everything.
1853
- if (line_items == null) {
1854
- line_items = payment.line_items;
1855
- }
1856
- // Check empty line items.
1857
- if (line_items.length === 0) {
1858
- throw Error("No refund line items array is empty.");
1859
- }
1860
- // Parse line items.
1861
- const items = [];
1862
- const item_ids = [];
1863
- for (const item of line_items) {
1864
- // Skip when the item is already being refunded.
1865
- if (item.status === "refunded" || item.status === "refunding") { // || item.status === "cancelled" || item.status === "cancelling"
1866
- continue;
1867
- }
1868
- // Add to structured line items.
1869
- item_ids.push(item.item_id);
1870
- items.push({
1871
- item_id: item.item_id,
1872
- type: "full", // partial refudings are not supported per line item since there is no convenient way to keep track of how much is refunded.
1873
- });
1874
- }
1875
- // Check empty line items.
1876
- if (items.length === 0) {
1877
- throw Error("This payment no longer has any refundable line items.");
1878
- }
1879
- // Make request.
1880
- const response = await this._req("POST", `/adjustments`, {
1881
- action: "refund",
1882
- transaction_id: payment.tran_id,
1883
- reason,
1884
- items,
1885
- custom_data: {
1886
- uid: payment.uid,
1887
- }
1888
- });
1889
- if (response.data.status === "rejected") {
1890
- throw Error("This payment is no longer refundable.");
1891
- }
1892
- else if (response.data.status === "approved") {
1893
- for (const item of payment.line_items) {
1894
- if (line_items.find((i) => i.item_id === item.item_id)) {
1895
- item.status = "refunded";
1896
- }
1897
- }
1898
- }
1899
- else {
1900
- for (const item of payment.line_items) {
1901
- if (line_items.find((i) => i.item_id === item.item_id)) {
1902
- item.status = "refunding";
1903
- }
1904
- }
1905
- }
1906
- // Update the payment object.
1907
- await this._save_payment(payment);
1908
- }
1909
- /* @docs:
1910
- @title: Cancel Subscription.
1911
- @desc: Cancel a subscription based on the retrieved payment object or id.
1912
- @warning: Cancelling a subscription will also cancel all other subscriptions that were created by the same payment request.
1913
- @param:
1914
- @name: uid
1915
- @cached: Users:uid:param
1916
- @param:
1917
- @name: products
1918
- @required: true
1919
- @type: string, array[string, object]
1920
- @desc: The product to cancel, the product ids to cancel or the product objects to cancel.
1921
- */
1922
- async cancel_subscription(uid, products, _throw_no_cancelled_err = true) {
1923
- if (products == null) {
1924
- throw new Error("Parameter \"products\" should be a defined value of type \"array[string, object]\".");
1925
- }
1926
- if (typeof products === "string") {
1927
- products = [products];
1928
- }
1929
- let cancelled = [];
1930
- for (let product of products) {
1931
- if (typeof product === "object") {
1932
- product = product.id;
1933
- }
1934
- const { exists, sub_id } = await this._check_subscription(uid, product);
1935
- if (exists && cancelled.includes(sub_id) === false) {
1936
- await this._cancel_subscription(sub_id);
1937
- cancelled.push(sub_id);
1938
- }
1939
- }
1940
- ;
1941
- if (_throw_no_cancelled_err && cancelled.length === 0) {
1942
- throw new ExternalError({
1943
- type: "NoCancellableSubscriptions",
1944
- message: "No cancellable subscriptions found.",
1945
- status: Status.bad_request,
1946
- });
1947
- }
1948
- }
1949
- /* @docs:
1950
- @title: Cancel subscription by subscription id.
1951
- @desc: Cancel a subscription based on the retrieved subscription object or id.
1952
- @warning: Cancelling a subscription will also cancel all other subscriptions that were created by the same payment request.
1953
- @param:
1954
- @name: subscription
1955
- @required: true
1956
- @type: string, object
1957
- @desc: The retrieved subscription object or the subscription's id.
1958
- @param:
1959
- @name: immediate
1960
- @type: boolean
1961
- @desc: Immediately cancel the subscription, or wait till the end of the billing cycle.
1962
- */
1963
- async cancel_subscription_by_id(subscription, immediate = false) {
1964
- if (typeof subscription === "object") {
1965
- subscription = subscription.id;
1966
- }
1967
- return await this._cancel_subscription(subscription, immediate);
1968
- }
1969
- /* @docs:
1970
- @title: Get active subscriptions
1971
- @desc: Get the active subscriptions of a user.
1972
- @param:
1973
- @name: uid
1974
- @cached: Users:uid:param
1975
- */
1976
- async get_active_subscriptions(uid) {
1977
- return await this._get_active_subscriptions(uid);
1978
- }
1979
- /* @docs:
1980
- @title: Get all subscriptions
1981
- @desc: Get all subscriptions of a user, active and inactive.
1982
- @param:
1983
- @name: uid
1984
- @cached: Users:uid:param
1985
- */
1986
- async get_subscriptions(uid) {
1987
- return await this._get_subscriptions(uid);
1988
- }
1989
- /* @docs:
1990
- @title: Is Subscribed
1991
- @desc: Check if a user is subscribed to a product.
1992
- @param:
1993
- @name: uid
1994
- @cached: Users:uid:param
1995
- @param:
1996
- @name: product
1997
- @required: true
1998
- @type: string
1999
- @desc: The product id.
2000
- */
2001
- async is_subscribed(uid, product) {
2002
- return await this._check_subscription(uid, product, false);
2003
- }
2004
- /* @docs:
2005
- @title: Generate Invoice
2006
- @desc:
2007
- Generate an invoice for a paid payment.
2008
-
2009
- By default an invoice is already generated when a payment has been paid.
2010
- @param:
2011
- @name: payment
2012
- @required: true
2013
- @type: object
2014
- @desc: The payment object.
2015
- @return:
2016
- @type: Promise
2017
- @desc: This function returns a promise to the invoice pdf in bytes.
2018
- */
2019
- async generate_invoice(payment) {
2020
- // Check arg..
2021
- if (payment == null || typeof payment !== "object") {
2022
- throw Error(`Parameter "payment" should be a defined value of type "object".`);
2023
- }
2024
- // Vars.
2025
- let currency;
2026
- let subtotal = 0;
2027
- let subtotal_tax = 0;
2028
- let total = 0;
2029
- for (const item of payment.line_items) {
2030
- if (typeof item.product === "string") {
2031
- item.product = this.get_product_sync(item.product, true);
2032
- }
2033
- if (currency == null) {
2034
- const c = Utils.get_currency_symbol(item.product.currency);
2035
- if (c == null) {
2036
- throw new Error(`Unable to determine the currency symbol for "${item.product.currency}".`);
2037
- }
2038
- currency = c;
2039
- }
2040
- subtotal += item.subtotal;
2041
- subtotal_tax += item.tax;
2042
- total += item.total;
2043
- }
2044
- let total_due = payment.status === "open" ? total : 0;
2045
- let doc = new PDFDocument({ size: "A4", margin: 50 });
2046
- let expanded_payment = payment;
2047
- /* Doc vars. */
2048
- let top_offset = 57;
2049
- let spacing = 10;
2050
- // Wrapper func.
2051
- const gen_text = (text, x, y = null, opts = null, _spacing = null) => {
2052
- if (y == null) {
2053
- y = top_offset;
2054
- }
2055
- else {
2056
- top_offset = y;
2057
- }
2058
- if (_spacing == null) {
2059
- _spacing = spacing;
2060
- }
2061
- doc.text(text, x, y, opts);
2062
- top_offset += doc.heightOfString(text, x, y, opts) + (_spacing == null ? spacing : _spacing);
2063
- };
2064
- const gen_col_text = (text, x, opts = null, is_last = false, _spacing = 2) => {
2065
- doc.text(text, x, top_offset, opts);
2066
- if (is_last) {
2067
- top_offset += doc.heightOfString(text, x, top_offset, opts) + (_spacing == null ? spacing : _spacing);
2068
- }
2069
- else {
2070
- return doc.heightOfString(text, x, top_offset, opts);
2071
- }
2072
- };
2073
- const gen_divider = (_spacing = null) => {
2074
- doc
2075
- .strokeColor("#aaaaaa")
2076
- .lineWidth(1)
2077
- .moveTo(50, top_offset)
2078
- .lineTo(550, top_offset)
2079
- .stroke();
2080
- top_offset += 1 + (_spacing == null ? spacing : _spacing);
2081
- };
2082
- const gen_line_item = ({ name = "", desc = "", unit_cost = "", quantity = "", total_cost = "" }) => {
2083
- const items = [
2084
- [0.25, name],
2085
- [0.35, desc],
2086
- [0.4 / 3, unit_cost],
2087
- [0.4 / 3, quantity],
2088
- [0.4 / 3, total_cost],
2089
- ];
2090
- let x = 50;
2091
- let max_height = 0;
2092
- const full_width = (550 - 50) - (10 * 4);
2093
- // Get max height.
2094
- for (const item of items) {
2095
- max_height = Math.max(max_height, doc.heightOfString(item[1], x, top_offset, { width: full_width * item[0], align: "left" }));
2096
- x += (full_width * item[0]) + 10;
2097
- }
2098
- // Check if a new page should be added.
2099
- if (top_offset + max_height + 10 > doc.page.height - 50) {
2100
- doc.addPage();
2101
- top_offset = 50;
2102
- }
2103
- // Add items.
2104
- x = 50;
2105
- for (const item of items) {
2106
- gen_col_text(item[1], x, { width: full_width * item[0], align: "left" });
2107
- x += (full_width * item[0]) + 10;
2108
- }
2109
- // Add top offset.
2110
- top_offset += max_height + spacing;
2111
- };
2112
- const format_date = (date) => {
2113
- return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
2114
- };
2115
- // Header.
2116
- doc.fillColor("#444444");
2117
- doc.fontSize(20);
2118
- if (this.server.company.stroke_icon_path != null) {
2119
- doc.image(this.server.company.stroke_icon_path, 50, top_offset - 2, { width: 60 });
2120
- }
2121
- else {
2122
- if (this.server.company.icon_path != null) {
2123
- doc.image(this.server.company.icon_path, 50, top_offset - 2, { width: 18 });
2124
- }
2125
- gen_text(this.server.company.legal_name, 50 + 18 + 10);
2126
- }
2127
- top_offset += 15;
2128
- // From (left).
2129
- const start_top_offset = top_offset;
2130
- doc.fillColor("#444444");
2131
- doc.fontSize(10);
2132
- doc.font("Helvetica-Bold");
2133
- gen_text("From", 50, null, null, 3);
2134
- doc.font("Helvetica");
2135
- gen_text(this.server.company.legal_name, 50, null, { align: "left" }, 2);
2136
- gen_text(`${this.server.company.street}, ${this.server.company.postal_code}`, 50, null, { align: "left" }, 2);
2137
- gen_text(`${this.server.company.city}, ${this.server.company.province}, ${this.server.company.country}`, 50, null, { align: "left" }, 2);
2138
- gen_text(`VAT ID: ${this.server.company.tax_id}`, 50, null, { align: "left" }, 2);
2139
- const left_top_offset = top_offset;
2140
- // Invoice details (right).
2141
- top_offset = start_top_offset;
2142
- doc.fillColor("#444444");
2143
- doc.fontSize(10);
2144
- doc.font("Helvetica-Bold");
2145
- gen_text("Invoice details", 550 - (150 + 10 + 80), null, null, 3);
2146
- doc.font("Helvetica");
2147
- for (const item of [
2148
- ["Invoice:", expanded_payment.id],
2149
- ["Date of issue:", format_date(new Date())],
2150
- ]) {
2151
- gen_col_text(item[0], 550 - (150 + 10 + 80), { width: 80 });
2152
- gen_col_text(item[1], 550 - 150, { width: 150 }, true);
2153
- }
2154
- // Go down.
2155
- top_offset = Math.max(top_offset, left_top_offset) + 25;
2156
- // Billing details.
2157
- doc.fillColor("#444444");
2158
- doc.fontSize(10);
2159
- doc.font("Helvetica-Bold");
2160
- gen_text("Billing Details", 50, null, null, 3);
2161
- doc.font("Helvetica");
2162
- if (expanded_payment.billing_details.business != null) {
2163
- gen_text(`${expanded_payment.billing_details.business}`, 50, null, { align: "left" }, 2);
2164
- }
2165
- else {
2166
- gen_text(`${expanded_payment.billing_details.name}`, 50, null, { align: "left" }, 2);
2167
- }
2168
- gen_text(expanded_payment.billing_details.email, 50, null, { align: "left" }, 2);
2169
- gen_text(`${expanded_payment.billing_details.address}`, 50, null, { align: "left" }, 2);
2170
- gen_text(`${expanded_payment.billing_details.city}, ${expanded_payment.billing_details.province}, ${expanded_payment.billing_details.country}`, 50, null, { align: "left" }, 2);
2171
- if (expanded_payment.billing_details.vat_id != null) {
2172
- gen_text(`${expanded_payment.billing_details.vat_id}`, 50, null, { align: "left" }, 2);
2173
- }
2174
- // Go down.
2175
- top_offset += 35;
2176
- // Line items.
2177
- doc.font("Helvetica-Bold");
2178
- gen_line_item({
2179
- name: "Item",
2180
- desc: "Description",
2181
- unit_cost: "Unit Cost",
2182
- quantity: "Quantity",
2183
- total_cost: "Line Total",
2184
- });
2185
- top_offset -= spacing * 0.5;
2186
- doc.font("Helvetica");
2187
- gen_divider();
2188
- for (const item of expanded_payment.line_items) {
2189
- gen_line_item({
2190
- name: item.product.name,
2191
- desc: item.product.description,
2192
- unit_cost: `${currency} ${(item.subtotal / item.quantity).toFixed(2)}`,
2193
- quantity: item.quantity.toString(),
2194
- total_cost: `${currency} ${item.total.toFixed(2)}`,
2195
- });
2196
- top_offset += 10;
2197
- gen_divider();
2198
- }
2199
- ;
2200
- gen_line_item({ unit_cost: "Subtotal:", total_cost: `${currency} ${subtotal.toFixed(2)}` });
2201
- top_offset -= (spacing - 3);
2202
- gen_line_item({ unit_cost: "Taxes:", total_cost: `${currency} ${subtotal_tax.toFixed(2)}` });
2203
- top_offset -= (spacing - 3);
2204
- gen_line_item({ unit_cost: "Total:", total_cost: `${currency} ${total.toFixed(2)}` });
2205
- top_offset -= (spacing - 3);
2206
- doc.font("Helvetica-Bold");
2207
- gen_line_item({ unit_cost: "Total Due:", total_cost: `${currency} ${total_due.toFixed(2)}` });
2208
- top_offset -= (spacing - 3);
2209
- // Write to file.
2210
- // doc.end();
2211
- // doc.pipe(fs.createWriteStream(path.str()));
2212
- // return path;
2213
- // Get as bytes.
2214
- const chunks = [];
2215
- return await new Promise((resolve, reject) => {
2216
- doc.on("data", (chunk) => chunks.push(chunk));
2217
- doc.on("end", () => resolve(Buffer.concat(chunks)));
2218
- doc.on("error", (err) => reject(err));
2219
- doc.end();
2220
- });
2221
- // const stream = doc.pipe(blobstream());
2222
- // doc.end();
2223
- // return new Promise((resolve, reject) => {
2224
- // stream.on('finish', () => {
2225
- // const bytes = stream.toBuffer();
2226
- // resolve(bytes);
2227
- // });
2228
- // stream.on('error', (error) => {
2229
- // reject(error);
2230
- // });
2231
- // });
2232
- }
2233
- // ---------------------------------------------------------
2234
- // Development.
2235
- // Cancel all subscriptions to clear development environment.
2236
- async dev_cancel_all_subscriptions() {
2237
- if (!this.sandbox) {
2238
- throw new Error("This function is only for a sandbox environment.");
2239
- }
2240
- // Fetch.
2241
- let subs = [], after = null;
2242
- while (true) {
2243
- const response = await this._req("GET", "/subscriptions", after == null ? { per_page: 100 } : { per_page: 100, after });
2244
- subs = subs.concat(response.data);
2245
- if (!response.meta.has_more) {
2246
- break;
2247
- }
2248
- after = subs.last().id;
2249
- }
2250
- // Cancel.
2251
- for (const sub of subs) {
2252
- if (sub.status === "active") {
2253
- this.server.log("Cancelling subscription ", sub.id);
2254
- await this._req("POST", `/subscriptions/${sub.id}/cancel`, {
2255
- effective_from: "immediately",
2256
- });
2257
- }
2258
- }
2259
- }
2260
- }
2261
- /** Nested types for the {@link Paddle} class */
2262
- (function (Paddle) {
2263
- /** Paddle api request error. */
2264
- class RequestError extends Error {
2265
- status_code;
2266
- constructor(err, status_code) {
2267
- super(err);
2268
- this.status_code = status_code;
2269
- }
2270
- }
2271
- Paddle.RequestError = RequestError;
2272
- })(Paddle || (Paddle = {}));
2273
- // APPLY_FIX
2274
- /**
2275
- * @todo if undeprecate: ASK claude to audit.
2276
- */