backend-manager 5.0.38 → 5.0.40

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 (311) hide show
  1. package/.claude/settings.local.json +3 -2
  2. package/.codeclimate.yml +32 -0
  3. package/CHANGELOG.md +25 -0
  4. package/CLAUDE.md +106 -12
  5. package/README.md +106 -7
  6. package/REFACTOR-BEM-API.md +76 -0
  7. package/REFACTOR-MIDDLEWARE.md +62 -0
  8. package/REFACTOR-PAYMENT.md +61 -0
  9. package/TODO.md +149 -0
  10. package/bin/bem +1 -1
  11. package/package.json +11 -10
  12. package/src/cli/commands/base-command.js +129 -0
  13. package/src/cli/commands/deploy.js +0 -5
  14. package/src/cli/commands/emulators.js +90 -0
  15. package/src/cli/commands/index.js +2 -0
  16. package/src/cli/commands/serve.js +5 -7
  17. package/src/cli/commands/setup-tests/emulators-config.js +79 -0
  18. package/src/cli/commands/setup-tests/env-file.js +109 -0
  19. package/src/cli/commands/setup-tests/env-runtime-config-deprecated.js +45 -0
  20. package/src/cli/commands/setup-tests/firestore-rules-file.js +11 -5
  21. package/src/cli/commands/setup-tests/gitignore.js +99 -18
  22. package/src/cli/commands/setup-tests/helpers/merge-line-files.js +181 -0
  23. package/src/cli/commands/setup-tests/hosting-folder.js +3 -3
  24. package/src/cli/commands/setup-tests/hosting-rewrites.js +1 -1
  25. package/src/cli/commands/setup-tests/index.js +10 -8
  26. package/src/cli/commands/setup-tests/legacy-tests-cleanup.js +43 -0
  27. package/src/cli/commands/setup-tests/npm-project-scripts.js +45 -0
  28. package/src/cli/commands/setup.js +12 -10
  29. package/src/cli/commands/test.js +201 -11
  30. package/src/cli/commands/watch.js +121 -0
  31. package/src/cli/{cli-refactored.js → index.js} +14 -0
  32. package/src/manager/cron/daily/ghostii-auto-publisher.js +278 -0
  33. package/src/manager/cron/daily/reset-usage.js +140 -0
  34. package/src/manager/cron/daily.js +54 -0
  35. package/src/manager/events/auth/before-create.js +52 -0
  36. package/src/manager/events/auth/before-signin.js +42 -0
  37. package/src/manager/events/auth/on-create.js +270 -0
  38. package/src/manager/events/auth/on-delete.js +94 -0
  39. package/src/manager/events/firestore/notifications/on-write.js +77 -0
  40. package/src/manager/functions/{core → _legacy}/actions/create-post-handler.js +17 -16
  41. package/src/manager/functions/{core → _legacy}/actions/generate-uuid.js +1 -1
  42. package/src/manager/functions/{core → _legacy}/actions/sign-up-handler.js +6 -6
  43. package/src/manager/functions/{core → _legacy}/admin/create-post.js +3 -4
  44. package/src/manager/functions/core/actions/api/admin/create-post.js +1 -1
  45. package/src/manager/functions/core/actions/api/admin/database-write.js +1 -1
  46. package/src/manager/functions/core/actions/api/admin/edit-post.js +12 -3
  47. package/src/manager/functions/core/actions/api/admin/get-stats.js +9 -0
  48. package/src/manager/functions/core/actions/api/admin/send-email.js +416 -192
  49. package/src/manager/functions/core/actions/api/admin/send-notification.js +66 -8
  50. package/src/manager/functions/core/actions/api/admin/sync-users.js +2 -2
  51. package/src/manager/functions/core/actions/api/admin/write-repo-content.js +11 -3
  52. package/src/manager/functions/core/actions/api/general/add-marketing-contact.js +604 -0
  53. package/src/manager/functions/core/actions/api/general/fetch-post.js +10 -1
  54. package/src/manager/functions/core/actions/api/general/generate-uuid.js +1 -1
  55. package/src/manager/functions/core/actions/api/general/remove-marketing-contact.js +234 -0
  56. package/src/manager/functions/core/actions/api/general/send-email.js +9 -5
  57. package/src/manager/functions/core/actions/api/special/setup-electron-manager-client.js +2 -3
  58. package/src/manager/functions/core/actions/api/test/health.js +24 -0
  59. package/src/manager/functions/core/actions/api/user/create-custom-token.js +1 -3
  60. package/src/manager/functions/core/actions/api/user/delete.js +2 -2
  61. package/src/manager/functions/core/actions/api/user/get-active-sessions.js +2 -4
  62. package/src/manager/functions/core/actions/api/user/get-subscription-info.js +7 -8
  63. package/src/manager/functions/core/actions/api/user/oauth2.js +1 -1
  64. package/src/manager/functions/core/actions/api/user/regenerate-api-keys.js +1 -2
  65. package/src/manager/functions/core/actions/api/user/sign-out-all-sessions.js +2 -3
  66. package/src/manager/functions/core/actions/api/user/sign-up.js +182 -57
  67. package/src/manager/functions/core/actions/api/user/submit-feedback.js +1 -2
  68. package/src/manager/functions/core/actions/api.js +44 -12
  69. package/src/manager/helpers/analytics.js +1 -1
  70. package/src/manager/helpers/api-manager.js +4 -4
  71. package/src/manager/helpers/assistant.js +7 -2
  72. package/src/manager/helpers/event-middleware.js +74 -0
  73. package/src/manager/helpers/middleware.js +26 -23
  74. package/src/manager/helpers/settings.js +17 -13
  75. package/src/manager/helpers/subscription-resolver-new.js +44 -45
  76. package/src/manager/helpers/subscription-resolver.js +44 -45
  77. package/src/manager/helpers/usage.js +1 -4
  78. package/src/manager/helpers/user.js +84 -66
  79. package/src/manager/index.js +61 -77
  80. package/src/manager/libraries/disposable-domains.json +839 -0
  81. package/src/manager/routes/admin/backup/post.js +105 -0
  82. package/src/manager/routes/admin/cron/post.js +37 -0
  83. package/src/manager/routes/admin/database/get.js +33 -0
  84. package/src/manager/routes/admin/database/post.js +32 -0
  85. package/src/manager/routes/admin/email/post.js +451 -0
  86. package/src/manager/routes/admin/firestore/get.js +33 -0
  87. package/src/manager/routes/admin/firestore/post.js +54 -0
  88. package/src/manager/routes/admin/firestore/query/post.js +126 -0
  89. package/src/manager/routes/admin/hook/post.js +83 -0
  90. package/src/manager/routes/admin/notification/post.js +260 -0
  91. package/src/manager/routes/admin/payment/post.js +56 -0
  92. package/src/manager/routes/admin/post/post.js +301 -0
  93. package/src/manager/routes/admin/post/put.js +136 -0
  94. package/src/manager/routes/admin/post/templates/post.html +15 -0
  95. package/src/manager/routes/admin/repo/content/post.js +102 -0
  96. package/src/manager/routes/admin/stats/get.js +213 -0
  97. package/src/manager/routes/admin/users/sync/post.js +119 -0
  98. package/src/manager/routes/content/post/get.js +104 -0
  99. package/src/manager/routes/firebase/providers/get.js +80 -0
  100. package/src/manager/routes/general/email/post.js +99 -0
  101. package/src/manager/routes/general/email/templates/download-app-link.js +25 -0
  102. package/src/manager/routes/general/uuid/post.js +34 -0
  103. package/src/manager/routes/handler/post/post.js +131 -0
  104. package/src/manager/routes/index.js +4 -20
  105. package/src/manager/routes/marketing/contact/delete.js +207 -0
  106. package/src/manager/routes/marketing/contact/post.js +504 -0
  107. package/src/manager/routes/restart/index.js +10 -22
  108. package/src/manager/routes/special/electron-client/post.js +72 -0
  109. package/src/manager/routes/test/authenticate/get.js +8 -0
  110. package/src/manager/routes/test/health/get.js +13 -0
  111. package/src/manager/routes/test/index.js +2 -26
  112. package/src/manager/routes/test/lab/post.js +17 -0
  113. package/src/manager/routes/test/redirect/get.js +9 -0
  114. package/src/manager/routes/test/schema/post.js +20 -0
  115. package/src/manager/routes/test/usage/post.js +50 -0
  116. package/src/manager/routes/test/webhook/post.js +21 -0
  117. package/src/manager/routes/user/api-keys/post.js +49 -0
  118. package/src/manager/routes/user/delete.js +71 -0
  119. package/src/manager/routes/user/feedback/post.js +85 -0
  120. package/src/manager/routes/user/get.js +14 -0
  121. package/src/manager/routes/user/oauth2/post.js +323 -0
  122. package/src/manager/routes/user/oauth2/providers/discord.js +47 -0
  123. package/src/manager/routes/user/oauth2/providers/google.js +38 -0
  124. package/src/manager/routes/user/sessions/delete.js +93 -0
  125. package/src/manager/routes/user/sessions/get.js +38 -0
  126. package/src/manager/routes/user/settings/validate/post.js +85 -0
  127. package/src/manager/routes/user/signup/post.js +185 -0
  128. package/src/manager/routes/user/subscription/get.js +61 -0
  129. package/src/manager/routes/user/token/post.js +28 -0
  130. package/src/manager/schemas/admin/backup/post.js +6 -0
  131. package/src/manager/schemas/admin/cron/post.js +6 -0
  132. package/src/manager/schemas/admin/database/get.js +7 -0
  133. package/src/manager/schemas/admin/database/post.js +12 -0
  134. package/src/manager/schemas/admin/email/post.js +20 -0
  135. package/src/manager/schemas/admin/firestore/get.js +7 -0
  136. package/src/manager/schemas/admin/firestore/post.js +22 -0
  137. package/src/manager/schemas/admin/firestore/query/post.js +7 -0
  138. package/src/manager/schemas/admin/hook/post.js +6 -0
  139. package/src/manager/schemas/admin/notification/post.js +21 -0
  140. package/src/manager/schemas/admin/payment/post.js +6 -0
  141. package/src/manager/schemas/admin/post/post.js +20 -0
  142. package/src/manager/schemas/admin/post/put.js +11 -0
  143. package/src/manager/schemas/admin/repo/content/post.js +10 -0
  144. package/src/manager/schemas/admin/stats/get.js +7 -0
  145. package/src/manager/schemas/admin/users/sync/post.js +6 -0
  146. package/src/manager/schemas/content/post/get.js +6 -0
  147. package/src/manager/schemas/firebase/providers/get.js +6 -0
  148. package/src/manager/schemas/general/email/post.js +8 -0
  149. package/src/manager/schemas/general/uuid/post.js +22 -0
  150. package/src/manager/schemas/handler/post/post.js +11 -0
  151. package/src/manager/schemas/marketing/contact/delete.js +7 -0
  152. package/src/manager/schemas/marketing/contact/post.js +13 -0
  153. package/src/manager/schemas/restart/index.js +6 -13
  154. package/src/manager/schemas/special/electron-client/post.js +9 -0
  155. package/src/manager/schemas/test/authenticate/get.js +1 -0
  156. package/src/manager/schemas/test/health/get.js +1 -0
  157. package/src/manager/schemas/test/index.js +6 -13
  158. package/src/manager/schemas/test/lab/post.js +1 -0
  159. package/src/manager/schemas/test/redirect/get.js +7 -0
  160. package/src/manager/schemas/test/schema/post.js +145 -0
  161. package/src/manager/schemas/test/usage/post.js +7 -0
  162. package/src/manager/schemas/test/webhook/post.js +17 -0
  163. package/src/manager/schemas/user/api-keys/post.js +12 -0
  164. package/src/manager/schemas/user/delete.js +7 -0
  165. package/src/manager/schemas/user/feedback/post.js +22 -0
  166. package/src/manager/schemas/user/get.js +1 -0
  167. package/src/manager/schemas/user/oauth2/post.js +77 -0
  168. package/src/manager/schemas/user/sessions/delete.js +12 -0
  169. package/src/manager/schemas/user/sessions/get.js +12 -0
  170. package/src/manager/schemas/user/settings/validate/post.js +22 -0
  171. package/src/manager/schemas/user/signup/post.js +22 -0
  172. package/src/manager/schemas/user/subscription/get.js +7 -0
  173. package/src/manager/schemas/user/token/post.js +7 -0
  174. package/src/test/run-tests.js +51 -0
  175. package/src/test/runner.js +820 -0
  176. package/src/test/test-accounts.js +456 -0
  177. package/src/test/utils/assertions.js +189 -0
  178. package/src/test/utils/firestore-rules-client.js +284 -0
  179. package/src/test/utils/http-client.js +251 -0
  180. package/templates/_.env +31 -0
  181. package/templates/_.gitignore +54 -0
  182. package/templates/firestore.rules +3 -3
  183. package/test/_init/accounts-validation.js +58 -0
  184. package/test/_legacy/ai/index.js +231 -0
  185. package/test/_legacy/ai/test.jpg +0 -0
  186. package/test/_legacy/ai/test.pdf +0 -0
  187. package/test/_legacy/cli-commands.test.js +224 -0
  188. package/test/_legacy/index.js +31 -0
  189. package/test/_legacy/payment-resolver/chargebee/orders/refunded.json +0 -0
  190. package/test/_legacy/payment-resolver/chargebee/orders/unpaid.json +98 -0
  191. package/test/_legacy/payment-resolver/chargebee/subscriptions/active.json +578 -0
  192. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-in-trial.json +38 -0
  193. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-skipped-to-active.json +135 -0
  194. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-active-to-cancelled.json +42 -0
  195. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-active.json +44 -0
  196. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-cancelled.json +39 -0
  197. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-refund.json +143 -0
  198. package/test/_legacy/payment-resolver/chargebee/subscriptions/trial-to-suspended.json +48 -0
  199. package/test/_legacy/payment-resolver/coinbase/orders/regular.json +204 -0
  200. package/test/_legacy/payment-resolver/coinbase/subscriptions/cancelled.json +204 -0
  201. package/test/_legacy/payment-resolver/coinbase/subscriptions/paid-2.json +125 -0
  202. package/test/_legacy/payment-resolver/index.js +1558 -0
  203. package/test/_legacy/payment-resolver/paypal/orders/refunded.json +0 -0
  204. package/test/_legacy/payment-resolver/paypal/orders/regular.json +120 -0
  205. package/test/_legacy/payment-resolver/paypal/subscriptions/active-refund-previous-stmnt.json +323 -0
  206. package/test/_legacy/payment-resolver/paypal/subscriptions/active.json +192 -0
  207. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-in-trial.json +125 -0
  208. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-not-complete.json +76 -0
  209. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-overdue-2.json +114 -0
  210. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-payment-overdue.json +114 -0
  211. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-active-to-cancelled.json +111 -0
  212. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-active.json +132 -0
  213. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-cancelled.json +107 -0
  214. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-expired.json +91 -0
  215. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-refund.json +147 -0
  216. package/test/_legacy/payment-resolver/paypal/subscriptions/trial-to-suspended.json +120 -0
  217. package/test/_legacy/payment-resolver/stripe/orders/refunded.json +0 -0
  218. package/test/_legacy/payment-resolver/stripe/orders/regular.json +91 -0
  219. package/test/_legacy/payment-resolver/stripe/subscriptions/active.json +421 -0
  220. package/test/_legacy/payment-resolver/stripe/subscriptions/trial-in-trial.json +349 -0
  221. package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-active-failed-authorization.json +430 -0
  222. package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-active.json +319 -0
  223. package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-cancelled.json +319 -0
  224. package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-refund.json +414 -0
  225. package/test/_legacy/payment-resolver/stripe/subscriptions/trial-to-suspended.json +319 -0
  226. package/test/_legacy/payment-resolver/stripe/subscriptions/unsure.json +339 -0
  227. package/test/_legacy/test-new +1178 -0
  228. package/test/_legacy/test.md +89 -0
  229. package/test/_legacy/usage.js +170 -0
  230. package/test/_legacy/user.js +31 -0
  231. package/test/functions/admin/database-read.js +148 -0
  232. package/test/functions/admin/database-write.js +173 -0
  233. package/test/functions/admin/edit-post.js +366 -0
  234. package/test/functions/admin/firestore-query.js +221 -0
  235. package/test/functions/admin/firestore-read.js +144 -0
  236. package/test/functions/admin/firestore-write.js +116 -0
  237. package/test/functions/admin/get-stats.js +115 -0
  238. package/test/functions/admin/send-email.js +206 -0
  239. package/test/functions/admin/send-notification.js +208 -0
  240. package/test/functions/admin/write-repo-content.js +223 -0
  241. package/test/functions/general/add-marketing-contact.js +373 -0
  242. package/test/functions/general/fetch-post.js +54 -0
  243. package/test/functions/general/generate-uuid.js +114 -0
  244. package/test/functions/test/authenticate.js +64 -0
  245. package/test/functions/user/create-custom-token.js +73 -0
  246. package/test/functions/user/delete.js +135 -0
  247. package/test/functions/user/get-active-sessions.js +111 -0
  248. package/test/functions/user/get-subscription-info.js +105 -0
  249. package/test/functions/user/regenerate-api-keys.js +156 -0
  250. package/test/functions/user/resolve.js +52 -0
  251. package/test/functions/user/sign-out-all-sessions.js +94 -0
  252. package/test/functions/user/sign-up.js +214 -0
  253. package/test/functions/user/submit-feedback.js +104 -0
  254. package/test/functions/user/validate-settings.js +82 -0
  255. package/test/routes/admin/database.js +144 -0
  256. package/test/routes/admin/email.js +163 -0
  257. package/test/routes/admin/firestore-query.js +217 -0
  258. package/test/routes/admin/firestore.js +141 -0
  259. package/test/routes/admin/notification.js +198 -0
  260. package/test/routes/admin/post.js +366 -0
  261. package/test/routes/admin/repo-content.js +223 -0
  262. package/test/routes/admin/stats.js +112 -0
  263. package/test/routes/content/post.js +54 -0
  264. package/test/routes/general/uuid.js +115 -0
  265. package/test/routes/marketing/contact.js +375 -0
  266. package/test/routes/test/authenticate.js +59 -0
  267. package/test/routes/test/schema.js +554 -0
  268. package/test/routes/test/usage.js +228 -0
  269. package/test/routes/user/api-keys.js +156 -0
  270. package/test/routes/user/delete.js +136 -0
  271. package/test/routes/user/feedback.js +104 -0
  272. package/test/routes/user/sessions.js +199 -0
  273. package/test/routes/user/settings-validate.js +82 -0
  274. package/test/routes/user/signup.js +214 -0
  275. package/test/routes/user/subscription.js +105 -0
  276. package/test/routes/user/token.js +73 -0
  277. package/test/routes/user/user.js +153 -0
  278. package/test/rules/notifications.js +410 -0
  279. package/test/rules/user.js +366 -0
  280. package/_backup/analytics copy.js +0 -217
  281. package/_backup/assistant-old-auth.js +0 -116
  282. package/_backup/create-post-old.js +0 -215
  283. package/_backup/get-providers copy.js +0 -154
  284. package/firebase-debug.log +0 -444
  285. package/src/cli/cli.js +0 -1435
  286. package/src/cli/commands/setup-tests/backend-manager-tests-file.js +0 -23
  287. package/src/cli/commands/setup-tests/env-runtime-config.js +0 -68
  288. package/src/cli/commands/setup-tests/npm-dist-script.js +0 -20
  289. package/src/cli/commands/setup-tests/npm-start-script.js +0 -20
  290. package/src/manager/functions/core/actions/api/handler/create-post.js +0 -146
  291. package/src/manager/functions/core/actions/api/test/create-test-accounts.js +0 -27
  292. package/src/manager/functions/core/actions/api/user/sign-up copy.js +0 -544
  293. package/src/manager/functions/core/cron/daily/ghostii-auto-publisher.js +0 -376
  294. package/src/manager/functions/core/cron/daily/reset-usage.js +0 -173
  295. package/src/manager/functions/core/cron/daily.js +0 -114
  296. package/src/manager/functions/core/events/auth/before-create.js +0 -124
  297. package/src/manager/functions/core/events/auth/before-signin.js +0 -62
  298. package/src/manager/functions/core/events/auth/on-create copy.js +0 -121
  299. package/src/manager/functions/core/events/auth/on-create.js +0 -564
  300. package/src/manager/functions/core/events/auth/on-delete.js +0 -72
  301. package/src/manager/functions/core/events/firestore/notifications/on-write.js +0 -118
  302. package/src/manager/functions/test/create-test-accounts.js +0 -144
  303. package/templates/backend-manager-tests.js +0 -153
  304. package/templates/gitignore.md +0 -4
  305. /package/src/manager/functions/{core → _legacy}/admin/firestore-write.js +0 -0
  306. /package/src/manager/functions/{core → _legacy}/admin/get-stats.js +0 -0
  307. /package/src/manager/functions/{core → _legacy}/admin/query.js +0 -0
  308. /package/src/manager/functions/{core → _legacy}/admin/send-notification.js +0 -0
  309. /package/src/manager/functions/{core/actions/api → _legacy}/template.js +0 -0
  310. /package/src/manager/functions/{test → _legacy/test}/authenticate.js +0 -0
  311. /package/src/manager/functions/{test → _legacy/test}/webhook.js +0 -0
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(rg:*)"
4
+ "Bash(rg:*)",
5
+ "Bash(mkdir:*)"
5
6
  ],
6
7
  "deny": []
7
8
  }
8
- }
9
+ }
@@ -0,0 +1,32 @@
1
+ version: "2" # required to adjust maintainability checks
2
+ checks:
3
+ # argument-count:
4
+ # config:
5
+ # threshold: 4
6
+ # complex-logic:
7
+ # config:
8
+ # threshold: 4
9
+ # file-lines:
10
+ # config:
11
+ # threshold: 250
12
+ # method-complexity:
13
+ # config:
14
+ # threshold: 5
15
+ # method-count:
16
+ # config:
17
+ # threshold: 20
18
+ method-lines:
19
+ config:
20
+ threshold: 200
21
+ # nested-control-flow:
22
+ # config:
23
+ # threshold: 4
24
+ # return-statements:
25
+ # config:
26
+ # threshold: 4
27
+ # similar-code:
28
+ # config:
29
+ # threshold: # language-specific defaults. an override will affect all languages.
30
+ identical-code:
31
+ config:
32
+ threshold: 10
package/CHANGELOG.md CHANGED
@@ -14,6 +14,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
14
14
  - `Fixed` for any bug fixes.
15
15
  - `Security` in case of vulnerabilities.
16
16
 
17
+ # [5.0.39] - 2025-01-12
18
+ ### Added
19
+ - New test infrastructure with Firebase emulator support for reliable, isolated testing.
20
+ - Test runner with emulator auto-detection and startup.
21
+ - Test types: standalone, suite (sequential with shared state), group (independent).
22
+ - Built-in test accounts with SSOT configuration (basic, admin, premium-active, etc.).
23
+ - Firestore security rules testing support.
24
+ - HTTP client with auth helpers (`http.as('admin').command()`).
25
+ - Rich assertion library (`isSuccess`, `isError`, `hasProperty`, etc.).
26
+ - New `bm emulators` command for standalone emulator management.
27
+ - Enhanced `bm test` with path filtering and parallel test support.
28
+
29
+ ### Changed
30
+ - Reorganized test files to `test/functions/` with `admin/`, `user/`, `general/` categories.
31
+ - Standardized auth test naming to `unauthenticated-rejected`.
32
+ - Auth rejection tests moved to end of test files (before cleanup).
33
+
34
+ ### Fixed
35
+ - Changed unauthenticated API error from 500 to 401 with proper "Authentication required" message.
36
+
37
+ ### Removed
38
+ - Removed legacy test files (moved to `test/_legacy/`).
39
+ - Removed deprecated CLI files and templates.
40
+ - Consolidated test account creation from API endpoint to test runner.
41
+
17
42
  # [5.0.31] - 2025-01-17
18
43
  ### Changed
19
44
  - Refactored CLI to modular command architecture with individual command classes and test files for better maintainability.
package/CLAUDE.md CHANGED
@@ -71,7 +71,7 @@ src/
71
71
  routes/ # Built-in routes
72
72
  schemas/ # Built-in schemas
73
73
  cli/
74
- cli-refactored.js # CLI entry point
74
+ index.js # CLI entry point
75
75
  commands/ # CLI commands
76
76
  templates/
77
77
  backend-manager-config.json # Config template
@@ -384,19 +384,112 @@ Manager.handlers.bm_api = function (mod, position) {
384
384
 
385
385
  ## Testing
386
386
 
387
+ ### Running Tests
387
388
  ```bash
388
- # Run all tests
389
- npm test
390
-
391
- # Test files are in test/
392
- test/
393
- cli-commands.test.js
394
- usage.js
395
- user.js
396
- payment-resolver/
397
- ai/
389
+ # Option 1: Two terminals
390
+ npx bm emulators # Terminal 1 - keeps emulators running
391
+ npx bm test # Terminal 2 - runs tests
392
+
393
+ # Option 2: Single command (auto-starts emulators)
394
+ npx bm test
395
+ ```
396
+
397
+ ### Filtering Tests
398
+ ```bash
399
+ npx bm test rules/ # Run rules tests (both BEM and project)
400
+ npx bm test bem:rules/ # Only BEM's rules tests
401
+ npx bm test project:rules/ # Only project's rules tests
402
+ npx bm test user/ admin/ # Multiple paths
398
403
  ```
399
404
 
405
+ ### Test Locations
406
+ - **BEM core tests:** `test/`
407
+ - **Project tests:** `functions/test/bem/`
408
+
409
+ Use `bem:` or `project:` prefix to filter by source.
410
+
411
+ ### Test Types
412
+
413
+ | Type | Use When | Behavior |
414
+ |------|----------|----------|
415
+ | Standalone | Single logical test | Runs once |
416
+ | Suite (`type: 'suite'`) | Sequential dependent tests | Shared state, stops on failure |
417
+ | Group (`type: 'group'`) | Multiple independent tests | Continues on failure |
418
+
419
+ ### Standalone Test
420
+ ```javascript
421
+ module.exports = {
422
+ description: 'Test name',
423
+ auth: 'none', // none, user, admin, premium-active, premium-expired
424
+ timeout: 10000,
425
+ async run({ http, assert, accounts, firestore, state, waitFor }) { },
426
+ async cleanup({ ... }) { }, // Optional
427
+ };
428
+ ```
429
+
430
+ ### Suite (Sequential with Shared State)
431
+ ```javascript
432
+ module.exports = {
433
+ description: 'Suite name',
434
+ type: 'suite',
435
+ tests: [
436
+ { name: 'step-1', async run({ state }) { state.value = 'shared'; } },
437
+ { name: 'step-2', async run({ state }) { /* state.value available */ } },
438
+ ],
439
+ };
440
+ ```
441
+
442
+ ### Group (Independent Tests)
443
+ ```javascript
444
+ module.exports = {
445
+ description: 'Group name',
446
+ type: 'group',
447
+ tests: [
448
+ { name: 'test-1', auth: 'admin', async run({ http, assert }) { } },
449
+ { name: 'test-2', auth: 'none', async run({ http, assert }) { } },
450
+ ],
451
+ };
452
+ ```
453
+
454
+ ### Context Object
455
+ | Property | Description |
456
+ |----------|-------------|
457
+ | `http` | HTTP client (`http.command()`, `http.as('admin').command()`) |
458
+ | `assert` | Assertion helpers (see below) |
459
+ | `accounts` | Test accounts `{ basic, admin, premium-active, ... }` |
460
+ | `firestore` | Direct DB access (`get`, `set`, `delete`, `exists`) |
461
+ | `state` | Shared state (suites only) |
462
+ | `waitFor` | Polling helper `waitFor(condition, timeout, interval)` |
463
+
464
+ ### Assert Methods
465
+ ```javascript
466
+ assert.ok(value, message) // Truthy
467
+ assert.equal(a, b, message) // Strict equality
468
+ assert.notEqual(a, b, message) // Not equal
469
+ assert.deepEqual(a, b, message) // Deep equality
470
+ assert.match(value, /regex/, message) // Regex match
471
+ assert.isSuccess(response, message) // Response success
472
+ assert.isError(response, code, message) // Response error with code
473
+ assert.hasProperty(obj, 'path.to.prop', msg) // Property exists
474
+ assert.propertyEquals(obj, 'path', value, msg) // Property value
475
+ assert.isType(value, 'string', message) // Type check
476
+ assert.contains(array, value, message) // Array includes
477
+ assert.inRange(value, min, max, message) // Number range
478
+ assert.fail(message) // Explicit fail
479
+ ```
480
+
481
+ ### Auth Levels
482
+ `none`, `user`/`basic`, `admin`, `premium-active`, `premium-expired`
483
+
484
+ ### Key Test Files
485
+ | File | Purpose |
486
+ |------|---------|
487
+ | `src/test/runner.js` | Test runner |
488
+ | `test/` | BEM core tests |
489
+ | `src/test/utils/assertions.js` | Assert helpers |
490
+ | `src/test/utils/http-client.js` | HTTP client |
491
+ | `src/test/test-accounts.js` | Test account definitions |
492
+
400
493
  ## Common Mistakes to Avoid
401
494
 
402
495
  1. **Don't modify Manager internals directly** - Use factory methods and public APIs
@@ -428,13 +521,14 @@ test/
428
521
  | Batch utilities | `src/manager/helpers/utilities.js` |
429
522
  | Main API handler | `src/manager/functions/core/actions/api.js` |
430
523
  | Config template | `templates/backend-manager-config.json` |
431
- | CLI entry | `src/cli/cli-refactored.js` |
524
+ | CLI entry | `src/cli/index.js` |
432
525
 
433
526
  ## Environment Detection
434
527
 
435
528
  ```javascript
436
529
  assistant.isDevelopment() // true when ENVIRONMENT !== 'production' or in emulator
437
530
  assistant.isProduction() // true when ENVIRONMENT === 'production'
531
+ assistant.isTesting() // true when running tests (via npx bm test)
438
532
  ```
439
533
 
440
534
  ## Response Headers
package/README.md CHANGED
@@ -359,7 +359,7 @@ The main API endpoint accepts commands in the format `category:action`:
359
359
  | `general` | `generate-uuid`, `send-email`, `fetch-post` |
360
360
  | `handler` | `create-post` |
361
361
  | `firebase` | `get-providers` |
362
- | `test` | `authenticate`, `create-test-accounts`, `webhook`, `lab`, `redirect` |
362
+ | `test` | `authenticate`, `webhook`, `lab`, `redirect` |
363
363
  | `special` | `setup-electron-manager-client` |
364
364
 
365
365
  ### Auth Events
@@ -447,6 +447,7 @@ assistant.debug('Debug message');
447
447
  // Environment
448
448
  assistant.isDevelopment(); // true in emulator
449
449
  assistant.isProduction(); // true in production
450
+ assistant.isTesting(); // true when running tests
450
451
 
451
452
  // File uploads
452
453
  const { fields, files } = await assistant.parseMultipartFormData();
@@ -737,7 +738,8 @@ npx backend-manager <command>
737
738
  | `bem setup` | Run Firebase project setup and validation |
738
739
  | `bem serve` | Start local Firebase emulator |
739
740
  | `bem deploy` | Deploy functions to Firebase |
740
- | `bem test` | Run test suite |
741
+ | `bem test [paths...]` | Run integration tests |
742
+ | `bem emulators` | Start Firebase emulators (keep-alive mode) |
741
743
  | `bem version`, `bem v` | Show BEM version |
742
744
  | `bem clear` | Clear cache and temp files |
743
745
  | `bem install`, `bem i` | Install BEM (local or production) |
@@ -747,14 +749,11 @@ npx backend-manager <command>
747
749
 
748
750
  ## Environment Variables
749
751
 
752
+ Set these in your `functions/.env` file:
753
+
750
754
  | Variable | Description |
751
755
  |----------|-------------|
752
- | `FIREBASE_CONFIG` | Firebase project config (auto-set by Firebase) |
753
- | `RUNTIME_CONFIG` | BEM runtime config (JSON5 format) |
754
756
  | `BACKEND_MANAGER_KEY` | Admin authentication key |
755
- | `ENVIRONMENT` | `'production'` or `'development'` |
756
- | `GOOGLE_APPLICATION_CREDENTIALS` | Path to service account JSON |
757
- | `HCAPTCHA_SECRET` | hCaptcha secret for usage validation |
758
757
 
759
758
  ## Response Headers
760
759
 
@@ -764,6 +763,106 @@ BEM attaches metadata to responses:
764
763
  bm-properties: {"code":200,"tag":"functionName/executionId","usage":{...},"schema":{...}}
765
764
  ```
766
765
 
766
+ ## Testing
767
+
768
+ BEM includes an integration test framework that runs against Firebase emulators.
769
+
770
+ ### Running Tests
771
+
772
+ ```bash
773
+ # Option 1: Two terminals (recommended for development)
774
+ npx bm emulators # Terminal 1 - keeps emulators running
775
+ npx bm test # Terminal 2 - runs tests
776
+
777
+ # Option 2: Single command (auto-starts emulators, shuts down after)
778
+ npx bm test
779
+ ```
780
+
781
+ ### Filtering Tests
782
+
783
+ ```bash
784
+ npx bm test rules/ # Run rules tests (both BEM and project)
785
+ npx bm test bem:rules/ # Only BEM's rules tests
786
+ npx bm test project:rules/ # Only project's rules tests
787
+ npx bm test user/ admin/ # Multiple paths
788
+ ```
789
+
790
+ ### Test Locations
791
+
792
+ - **BEM core tests:** `test/`
793
+ - **Project tests:** `functions/test/bem/`
794
+
795
+ Use `bem:` or `project:` prefix to filter by source.
796
+
797
+ ### Writing Tests
798
+
799
+ **Suite** - Sequential tests with shared state (stops on first failure):
800
+
801
+ ```javascript
802
+ // test/functions/user/sign-up.js
803
+ module.exports = {
804
+ description: 'User signup flow with affiliate tracking',
805
+ type: 'suite',
806
+ tests: [
807
+ {
808
+ name: 'verify-referrer-exists',
809
+ async run({ firestore, assert, state, accounts }) {
810
+ state.referrerUid = accounts.referrer.uid;
811
+ const doc = await firestore.get(`users/${state.referrerUid}`);
812
+ assert.ok(doc, 'Referrer should exist');
813
+ },
814
+ },
815
+ {
816
+ name: 'call-user-signup-with-affiliate',
817
+ async run({ http, assert, state }) {
818
+ const response = await http.as('referred').command('user:sign-up', {
819
+ attribution: { affiliate: { code: 'TESTREF' } },
820
+ });
821
+ assert.isSuccess(response);
822
+ },
823
+ },
824
+ ],
825
+ };
826
+ ```
827
+
828
+ **Group** - Independent tests (continues even if one fails):
829
+
830
+ ```javascript
831
+ // test/functions/admin/firestore-write.js
832
+ module.exports = {
833
+ description: 'Admin Firestore write operation',
834
+ type: 'group',
835
+ tests: [
836
+ {
837
+ name: 'admin-auth-succeeds',
838
+ auth: 'admin',
839
+ async run({ http, assert }) {
840
+ const response = await http.command('admin:firestore-write', {
841
+ path: '_test/doc',
842
+ document: { test: 'value' },
843
+ });
844
+ assert.isSuccess(response);
845
+ },
846
+ },
847
+ {
848
+ name: 'unauthenticated-rejected',
849
+ auth: 'none',
850
+ async run({ http, assert }) {
851
+ const response = await http.command('admin:firestore-write', {
852
+ path: '_test/doc',
853
+ document: { test: 'value' },
854
+ });
855
+ assert.isError(response, 401);
856
+ },
857
+ },
858
+ ],
859
+ };
860
+ ```
861
+
862
+ **Auth levels:** `none`, `user`/`basic`, `admin`, `premium-active`, `premium-expired`
863
+
864
+ See `CLAUDE.md` for complete test API documentation.
865
+
767
866
  ## Final Words
768
867
 
769
868
  If you are still having difficulty, we would love for you to post a question to [the Backend Manager issues page](https://github.com/itw-creative-works/backend-manager/issues). It is much easier to answer questions that include your code and relevant files! So if you can provide them, we'd be extremely grateful (and more likely to help you find the answer!)
@@ -0,0 +1,76 @@
1
+ We need to do a pretty significatn refactor of our BEM API now.
2
+
3
+ Since that was orignally implemented, I built a much better process for hading incoming http requests. That is, the route/schema system found here:
4
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/helpers/assistant.js
5
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/helpers/middleware.js
6
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/helpers/settings.js
7
+
8
+ You can see an example of it in our consuming project:
9
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/functions/index.js
10
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/functions/routes/example/index.js
11
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/functions/schemas/example/index.js
12
+
13
+ We built a single unified bem_api function that handles all http requests in a single place, and then routes them, see here:
14
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/index.js
15
+ .https.onRequest(async (req, res) => self._process((new (require(`${core}/actions/api.js`))()).init(self, { req: req, res: res, })));
16
+
17
+ We should refactor this system to USE THE NEW ROUTE/SCHEMA SYSTEM rather than the old way of doing things. This will make it much easier to maintain and extend in the future.
18
+
19
+ We can start with a simple one like:
20
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/functions/core/actions/api/general/generate-uuid.js
21
+
22
+ and once we perfect that we can move on to the others.
23
+
24
+ For each BEM refactor, we should create a route and a schema for the expected input. As you can see, BEM APIs epect a command and payload in the body, requiring it to be a POST operation. I would like to rebuild this system to be more proper, so that each BEM api can be GET, POST, etc as appropriate.
25
+
26
+ Previously:
27
+ request('/backend-manager', {
28
+ method: 'POST',
29
+ body: {
30
+ command: 'generate-uuid',
31
+ payload: { ... }
32
+ }
33
+ })
34
+
35
+ but i think it owud be more intuitive if going forward we just had endpoints like:
36
+ request('/backend-manager/general:uuid', {
37
+ method: 'POST',
38
+ body: { ... }
39
+ })
40
+ OR
41
+ request('/backend-manager/general/uuid', {
42
+ method: 'POST',
43
+ body: { ... }
44
+ })
45
+
46
+ Im not sure how we can do this to be backwards compatible with existing BEM API consumers, but it does need to be backwards compatible.
47
+
48
+ If you look at the firebase.json in the consuming project we can see that
49
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/firebase.json
50
+ {
51
+ "source": "/backend-manager",
52
+ "function": "bm_api"
53
+ },
54
+
55
+ So maybe we could make it:
56
+ {
57
+ "source": "/backend-manager/**",
58
+ "function": "bm_api"
59
+ },
60
+ and then parse the route inside the bem_api function to determine which route/schema to use, falling back to the old system if the route is just /backend-manager with a "command" in the body, and then use the new route/schema system if the path is /backend-manager/something?
61
+
62
+ Either way, i think we need a minimal intermediary step where we determine which one to use based on the incoming request and then either just route to the old one or route to the new "middleware", "settings", route/schema system
63
+
64
+ I would like each new route to have a great name clearly indicating its purpose, the method should be appropriate for the action (GET for fetches, POST for creates, etc) and the schema should be well defined for each route.
65
+
66
+ Since we can build this new API system however we want, i also expect you to rewrite and refactor the BEM api endppints to be kickass, modern, and well designed.
67
+
68
+ Also, certain VERBS should be removed from the actual file/function names since they are implied by the HTTP method. For example, instead of having a generate-uuid.js file, we could just have uuid.js since the POST method implies that we are generating/creating a new one, or insetad of add-marketing-contact we could just have marketing-contact.js since the POST method implies adding a new one and GET would imply fetching them.
69
+
70
+ Next, some fucntions have a lot crammed isnide them that could use some separation. For example, in add-marketing-contact.js we have code for handling multiple email providers (SendGrid, Beehiiv) all jammed into a single file. I think we should refactor this to have a separate file for each provider in subfolder that handles the specifics of that provider, and then the main route file just calls those provider-specific files as needed. This will make it much easier to maintain and extend in the future as we add more providers.
71
+
72
+ Also, sometimes there are two endpoints that should be combined,for example
73
+ * /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/functions/core/actions/api/general/add-marketing-contact.js
74
+ * /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/functions/core/actions/api/general/remove-marketing-contact.js
75
+ These could be combined into a single marketing-contact.js file that handles both adding and removing based on the HTTP method (POST for add, DELETE for remove). This will make the API more RESTful and easier to understand.
76
+
@@ -0,0 +1,62 @@
1
+ MIDDLEWARE REFACTOR
2
+ We have a system where we handle incoming requests using a route/schema system found here:
3
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/helpers/assistant.js
4
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/helpers/middleware.js
5
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/backend-manager/src/manager/helpers/settings.js
6
+
7
+ You can see an example of it in our consuming project:
8
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/functions/index.js
9
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/functions/routes/example/index.js
10
+ /Users/ian/Developer/Repositories/ITW-Creative-Works/ultimate-jekyll-backend/functions/schemas/example/index.js
11
+
12
+ I have some ideas iw as thinking about and id like to know your thoughts:
13
+ * new design so that each route is modern JS that does a single export instead of exportting a class with an init() and a main() method.
14
+ * schema system currently uses the user's plan when designing the schma like
15
+ module.exports = function (assistant) {
16
+ return {
17
+ // DEFAULTS
18
+ ['defaults']: {
19
+ key: {
20
+ types: ['string'],
21
+ value: undefined,
22
+ default: '',
23
+ required: false,
24
+ min: 0,
25
+ max: 2048,
26
+ },
27
+ },
28
+
29
+ // Premium plan
30
+ ['premium']: {
31
+ key: {
32
+ types: ['string'],
33
+ value: undefined,
34
+ default: 'premium-default',
35
+ required: false,
36
+ min: 0,
37
+ max: 4096,
38
+ },
39
+ }
40
+ };
41
+ }
42
+
43
+ however it hink we should instead eliminate the toplevel plan/default system and code each plan changes into the individual keys like:
44
+ const schema = {
45
+ id: {
46
+ types: ['string'],
47
+ value: () => assistant.Manager.Utilities().randomId(),
48
+ required: false,
49
+ },
50
+ feature: {
51
+ types: ['string'],
52
+ default: '',
53
+ required: true,
54
+ min: 1,
55
+ max: 4,
56
+ },
57
+ };
58
+
59
+ // Adjust schema based on plan
60
+ if (assistant.user.plan === 'premium') {
61
+ schema.feature.max = 8;
62
+ }
@@ -0,0 +1,61 @@
1
+ PAYMETN SYSTEM REFACTOR
2
+ Question
3
+ Propose a schema for storing user's subscription data in their firestore user document. Currently the user looks like this
4
+ users/{uid}
5
+ {
6
+ auth: {
7
+ uid: string,
8
+ email: string,
9
+ },
10
+ roles: {
11
+ admin: boolean,
12
+ },
13
+ ... (other stuff that is not really relevant)
14
+ }
15
+ I will be using a variety of payment processors including Stripe and PayPal, so I need a flexible way to store subscription data that can work with multiple providers.
16
+ Before inserting the subscription data, we wil need to receive the processor webhooks.
17
+ We will be keeping track of the subcsription data in the user doc AS WELL AS a dedicated subscription doc where we can have more information
18
+ Thus, the user doc doesnt need to contain the entire subscription Object, just enough to grant the user access to premium features in the backend or frontend as well as display important info in the user's account page like next billing date, plan name, status, anything else that is important.
19
+ Also, since we will be checking subscription status often, I thought it would be nice to store 2 main objects:
20
+ 1. the original subscirpiton object from the payment provider, unmodified
21
+ 2. a unified and standardized subscription object that we define, so that when checking subscription status we dont have to deal with the differences between payment providers (both for displaying info and for checking status/plan/etc to grant access when making requests or on the frontend)
22
+ We could store BOTH in both the user doc and the subscription doc, or only store the unified object in the user doc and both in the subscription doc.
23
+
24
+ For our standardized Object, we should be able to get the current plan and whether the subscription is active or not EXTREMELY easily. LIke a single if statement, allowing us to grant access if if the user is premium or whatever.
25
+
26
+ However, i would like it to be flexible enough so that we can show something like:
27
+ - User is on premium plan and paid up --> grant access to premium features, show "You are Premium and your next billing date is X"
28
+ - User is on premium plan but payment failed --> restrict access to premium features, show "Your payment failed, please update your payment method"
29
+ - User was on premium plan but cancelled --> restrict access to premium features, show "You WERE premium but it was cancelled so now youre on Free plan"
30
+ - User was on premium plan but cancellation is pending --> grant access to premium features, show "You are Premium until X date when your plan will be cancelled"
31
+ - User is on trial --> grant access to premium features, show "You are on a free trial that ends on X date"
32
+ So essentially we need a way to be able to determine all of these different scenarios EASILY (SINGLE IF STATEMENT)
33
+
34
+ I know all payment proivders are different and ahve different concepts of how exaclty a subscirption is active, cancelled, past due, trialing, etc but we need to come up with a unified way of representing this data in our standardized object so that we can easily check status and display info regardless of payment provider.
35
+
36
+ Like, i i think stripe you can "cancel at period end" and thus the sub will not actually be cancelled until the end of the billing period, but paypal might be slightly different.
37
+
38
+ BEM API ENDPOINTS
39
+ * For our payment system to work, we shoudl implemnt some BEM API endpoints to create, listen for webhooks, and manage subscriptions.
40
+ * anytime there is an aciton that handles multiple payment providers, we should have the entryppoint import a file for each provider, where each provider handles the request in its own way, but STILL STANDARDIZED and similar across all providers.
41
+
42
+ backend-manager/payments/intent
43
+ * handle creating payment intents or equivalent in other providers
44
+ * various checks like
45
+ * is the user currently subscribed? if so block
46
+ * is the user allowed to have a trial (havent had one before)? if not block their trial
47
+ * validate their gcaptcha token. block if invalid or missing
48
+ * create the payment intent or equivalent at "payments-intents/{id}" in firestore
49
+
50
+ backend-manager/payments/webhook (or something similar)
51
+ * handle receiving webhooks from payment providers to update subscription status
52
+ * different file for processing each paymnt processor (returning some comon things like the event id)
53
+ * various checks like
54
+ * verify the webhook by checking the querystring for the BEM token (same as .env BACKEND_MANAGER_KEY)
55
+ * check for payment-webhooks/{id} doc to see if we already processed this webhook (id is provided by the payment provider in the webhook payload)
56
+ * Immediately save the raw webhook data to "payments-webhooks/{id}" in firestore so we can return a 200 as soon as possible. THe webhook will be processed in a firestore function trigger onWrite for that doc (status === pending)
57
+
58
+ Firestore trigger for payments-webhooks/{id}
59
+ * process the webhook data and update the user's subscription data in both their user doc and their subscription doc
60
+ * various checks like
61
+ * if status === completed, do nothing