90dc-core 1.19.3 → 1.19.4

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 (297) hide show
  1. package/package.json +1 -1
  2. package/dist/index.js +0 -43
  3. package/dist/index.js.map +0 -1
  4. package/dist/lib/Errors/AppError.js +0 -104
  5. package/dist/lib/Errors/AppError.js.map +0 -1
  6. package/dist/lib/Errors/Errors.js +0 -42
  7. package/dist/lib/Errors/Errors.js.map +0 -1
  8. package/dist/lib/classes/Database.js +0 -154
  9. package/dist/lib/classes/Database.js.map +0 -1
  10. package/dist/lib/classes/Redis.js +0 -63
  11. package/dist/lib/classes/Redis.js.map +0 -1
  12. package/dist/lib/clients/EmailClient.js +0 -188
  13. package/dist/lib/clients/EmailClient.js.map +0 -1
  14. package/dist/lib/clients/FirebasePushNotificationClient.js +0 -688
  15. package/dist/lib/clients/FirebasePushNotificationClient.js.map +0 -1
  16. package/dist/lib/clients/ImagesClient.js +0 -271
  17. package/dist/lib/clients/ImagesClient.js.map +0 -1
  18. package/dist/lib/clients/MailingClient.js +0 -84
  19. package/dist/lib/clients/MailingClient.js.map +0 -1
  20. package/dist/lib/clients/PushNotificationClient.js +0 -478
  21. package/dist/lib/clients/PushNotificationClient.js.map +0 -1
  22. package/dist/lib/clients/types/email.types.js +0 -3
  23. package/dist/lib/clients/types/email.types.js.map +0 -1
  24. package/dist/lib/clients/types/images.types.js +0 -3
  25. package/dist/lib/clients/types/images.types.js.map +0 -1
  26. package/dist/lib/clients/types/mailing.types.js +0 -3
  27. package/dist/lib/clients/types/mailing.types.js.map +0 -1
  28. package/dist/lib/config/ConfigValidator.js +0 -162
  29. package/dist/lib/config/ConfigValidator.js.map +0 -1
  30. package/dist/lib/controllers/BaseController.js +0 -64
  31. package/dist/lib/controllers/BaseController.js.map +0 -1
  32. package/dist/lib/db/migrations/20260330000000-create-user-progress-photos.js +0 -60
  33. package/dist/lib/db/migrations/20260330000000-create-user-progress-photos.js.map +0 -1
  34. package/dist/lib/dbmodels/coaching/Answer.js +0 -51
  35. package/dist/lib/dbmodels/coaching/Answer.js.map +0 -1
  36. package/dist/lib/dbmodels/coaching/ClientNote.js +0 -75
  37. package/dist/lib/dbmodels/coaching/ClientNote.js.map +0 -1
  38. package/dist/lib/dbmodels/coaching/ClientTag.js +0 -45
  39. package/dist/lib/dbmodels/coaching/ClientTag.js.map +0 -1
  40. package/dist/lib/dbmodels/coaching/Question.js +0 -60
  41. package/dist/lib/dbmodels/coaching/Question.js.map +0 -1
  42. package/dist/lib/dbmodels/coaching/Questionnaire.js +0 -39
  43. package/dist/lib/dbmodels/coaching/Questionnaire.js.map +0 -1
  44. package/dist/lib/dbmodels/coaching/QuestionnaireResponse.js +0 -42
  45. package/dist/lib/dbmodels/coaching/QuestionnaireResponse.js.map +0 -1
  46. package/dist/lib/dbmodels/coaching/WeeklyCheckIn.js +0 -69
  47. package/dist/lib/dbmodels/coaching/WeeklyCheckIn.js.map +0 -1
  48. package/dist/lib/dbmodels/coaching/WeightRecord.js +0 -49
  49. package/dist/lib/dbmodels/coaching/WeightRecord.js.map +0 -1
  50. package/dist/lib/dbmodels/diet/DietDay.js +0 -50
  51. package/dist/lib/dbmodels/diet/DietDay.js.map +0 -1
  52. package/dist/lib/dbmodels/diet/DietMeal.js +0 -74
  53. package/dist/lib/dbmodels/diet/DietMeal.js.map +0 -1
  54. package/dist/lib/dbmodels/diet/DietMealCompletion.js +0 -69
  55. package/dist/lib/dbmodels/diet/DietMealCompletion.js.map +0 -1
  56. package/dist/lib/dbmodels/diet/DietMealRecipe.js +0 -67
  57. package/dist/lib/dbmodels/diet/DietMealRecipe.js.map +0 -1
  58. package/dist/lib/dbmodels/diet/DietMealRecipeIngredient.js +0 -46
  59. package/dist/lib/dbmodels/diet/DietMealRecipeIngredient.js.map +0 -1
  60. package/dist/lib/dbmodels/diet/DietProgram.js +0 -98
  61. package/dist/lib/dbmodels/diet/DietProgram.js.map +0 -1
  62. package/dist/lib/dbmodels/diet/Ingredient.js +0 -88
  63. package/dist/lib/dbmodels/diet/Ingredient.js.map +0 -1
  64. package/dist/lib/dbmodels/diet/IngredientTag.js +0 -64
  65. package/dist/lib/dbmodels/diet/IngredientTag.js.map +0 -1
  66. package/dist/lib/dbmodels/diet/IngredientTags.js +0 -29
  67. package/dist/lib/dbmodels/diet/IngredientTags.js.map +0 -1
  68. package/dist/lib/dbmodels/diet/Recipe.js +0 -173
  69. package/dist/lib/dbmodels/diet/Recipe.js.map +0 -1
  70. package/dist/lib/dbmodels/diet/RecipeIngredient.js +0 -78
  71. package/dist/lib/dbmodels/diet/RecipeIngredient.js.map +0 -1
  72. package/dist/lib/dbmodels/diet/RecipeTag.js +0 -44
  73. package/dist/lib/dbmodels/diet/RecipeTag.js.map +0 -1
  74. package/dist/lib/dbmodels/diet/RecipeTags.js +0 -24
  75. package/dist/lib/dbmodels/diet/RecipeTags.js.map +0 -1
  76. package/dist/lib/dbmodels/diet/ShoppingList.js +0 -69
  77. package/dist/lib/dbmodels/diet/ShoppingList.js.map +0 -1
  78. package/dist/lib/dbmodels/diet/ShoppingListItem.js +0 -66
  79. package/dist/lib/dbmodels/diet/ShoppingListItem.js.map +0 -1
  80. package/dist/lib/dbmodels/diet/TranslatedRecipe.js +0 -122
  81. package/dist/lib/dbmodels/diet/TranslatedRecipe.js.map +0 -1
  82. package/dist/lib/dbmodels/diet/TranslatedRecipeTag.js +0 -47
  83. package/dist/lib/dbmodels/diet/TranslatedRecipeTag.js.map +0 -1
  84. package/dist/lib/dbmodels/diet/TranslatedRecipeTags.js +0 -24
  85. package/dist/lib/dbmodels/diet/TranslatedRecipeTags.js.map +0 -1
  86. package/dist/lib/dbmodels/diet/UserDietPreferences.js +0 -85
  87. package/dist/lib/dbmodels/diet/UserDietPreferences.js.map +0 -1
  88. package/dist/lib/dbmodels/gamification/Badge.js +0 -62
  89. package/dist/lib/dbmodels/gamification/Badge.js.map +0 -1
  90. package/dist/lib/dbmodels/gamification/StreaksLog.js +0 -37
  91. package/dist/lib/dbmodels/gamification/StreaksLog.js.map +0 -1
  92. package/dist/lib/dbmodels/gamification/TranslatedBadge.js +0 -45
  93. package/dist/lib/dbmodels/gamification/TranslatedBadge.js.map +0 -1
  94. package/dist/lib/dbmodels/gamification/xpAndLeaderboards/UserRankHistory.js +0 -48
  95. package/dist/lib/dbmodels/gamification/xpAndLeaderboards/UserRankHistory.js.map +0 -1
  96. package/dist/lib/dbmodels/gamification/xpAndLeaderboards/XpEvent.js +0 -53
  97. package/dist/lib/dbmodels/gamification/xpAndLeaderboards/XpEvent.js.map +0 -1
  98. package/dist/lib/dbmodels/gamification/xpAndLeaderboards/XpTransaction.js +0 -68
  99. package/dist/lib/dbmodels/gamification/xpAndLeaderboards/XpTransaction.js.map +0 -1
  100. package/dist/lib/dbmodels/index.js +0 -288
  101. package/dist/lib/dbmodels/index.js.map +0 -1
  102. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgram.d.ts +0 -32
  103. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgram.d.ts.map +0 -1
  104. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgram.js +0 -155
  105. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgram.js.map +0 -1
  106. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgramWebContent.d.ts +0 -22
  107. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgramWebContent.d.ts.map +0 -1
  108. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgramWebContent.js +0 -108
  109. package/dist/lib/dbmodels/nonconsprogram/NonConsumableProgramWebContent.js.map +0 -1
  110. package/dist/lib/dbmodels/nonconsprogram/TranslatedConsumableProgram.d.ts +0 -20
  111. package/dist/lib/dbmodels/nonconsprogram/TranslatedConsumableProgram.d.ts.map +0 -1
  112. package/dist/lib/dbmodels/nonconsprogram/TranslatedConsumableProgram.js +0 -97
  113. package/dist/lib/dbmodels/nonconsprogram/TranslatedConsumableProgram.js.map +0 -1
  114. package/dist/lib/dbmodels/nonconsprogram/TranslatedNonConsumableProgramWebContent.d.ts +0 -22
  115. package/dist/lib/dbmodels/nonconsprogram/TranslatedNonConsumableProgramWebContent.d.ts.map +0 -1
  116. package/dist/lib/dbmodels/nonconsprogram/TranslatedNonConsumableProgramWebContent.js +0 -115
  117. package/dist/lib/dbmodels/nonconsprogram/TranslatedNonConsumableProgramWebContent.js.map +0 -1
  118. package/dist/lib/dbmodels/nonconsprogram/UserNonConsumableProgram.d.ts +0 -7
  119. package/dist/lib/dbmodels/nonconsprogram/UserNonConsumableProgram.d.ts.map +0 -1
  120. package/dist/lib/dbmodels/nonconsprogram/UserNonConsumableProgram.js +0 -41
  121. package/dist/lib/dbmodels/nonconsprogram/UserNonConsumableProgram.js.map +0 -1
  122. package/dist/lib/dbmodels/notifications/NotificationModels.js +0 -38
  123. package/dist/lib/dbmodels/notifications/NotificationModels.js.map +0 -1
  124. package/dist/lib/dbmodels/notifications/TranslatedNotification.js +0 -45
  125. package/dist/lib/dbmodels/notifications/TranslatedNotification.js.map +0 -1
  126. package/dist/lib/dbmodels/program/Challenge.d.ts +0 -13
  127. package/dist/lib/dbmodels/program/Challenge.d.ts.map +0 -1
  128. package/dist/lib/dbmodels/program/Challenge.js +0 -63
  129. package/dist/lib/dbmodels/program/Challenge.js.map +0 -1
  130. package/dist/lib/dbmodels/program/ChallengeBlueprint.js +0 -75
  131. package/dist/lib/dbmodels/program/ChallengeBlueprint.js.map +0 -1
  132. package/dist/lib/dbmodels/program/CircularProgramDraft.js +0 -82
  133. package/dist/lib/dbmodels/program/CircularProgramDraft.js.map +0 -1
  134. package/dist/lib/dbmodels/program/CoachExerciseNote.js +0 -61
  135. package/dist/lib/dbmodels/program/CoachExerciseNote.js.map +0 -1
  136. package/dist/lib/dbmodels/program/CustomProgramBlueprint.js +0 -84
  137. package/dist/lib/dbmodels/program/CustomProgramBlueprint.js.map +0 -1
  138. package/dist/lib/dbmodels/program/CustomStrengthTest.js +0 -55
  139. package/dist/lib/dbmodels/program/CustomStrengthTest.js.map +0 -1
  140. package/dist/lib/dbmodels/program/CustomStrengthTestExercises.js +0 -69
  141. package/dist/lib/dbmodels/program/CustomStrengthTestExercises.js.map +0 -1
  142. package/dist/lib/dbmodels/program/CustomWorkoutBlueprint.js +0 -58
  143. package/dist/lib/dbmodels/program/CustomWorkoutBlueprint.js.map +0 -1
  144. package/dist/lib/dbmodels/program/Exercise.d.ts +0 -23
  145. package/dist/lib/dbmodels/program/Exercise.d.ts.map +0 -1
  146. package/dist/lib/dbmodels/program/Exercise.js +0 -101
  147. package/dist/lib/dbmodels/program/Exercise.js.map +0 -1
  148. package/dist/lib/dbmodels/program/ExerciseModels.d.ts +0 -28
  149. package/dist/lib/dbmodels/program/ExerciseModels.d.ts.map +0 -1
  150. package/dist/lib/dbmodels/program/ExerciseModels.js +0 -149
  151. package/dist/lib/dbmodels/program/ExerciseModels.js.map +0 -1
  152. package/dist/lib/dbmodels/program/Program.d.ts +0 -15
  153. package/dist/lib/dbmodels/program/Program.d.ts.map +0 -1
  154. package/dist/lib/dbmodels/program/Program.js +0 -76
  155. package/dist/lib/dbmodels/program/Program.js.map +0 -1
  156. package/dist/lib/dbmodels/program/ProgressEntry.d.ts +0 -26
  157. package/dist/lib/dbmodels/program/ProgressEntry.d.ts.map +0 -1
  158. package/dist/lib/dbmodels/program/ProgressEntry.js +0 -77
  159. package/dist/lib/dbmodels/program/ProgressEntry.js.map +0 -1
  160. package/dist/lib/dbmodels/program/RestDay.js +0 -33
  161. package/dist/lib/dbmodels/program/RestDay.js.map +0 -1
  162. package/dist/lib/dbmodels/program/StrengthTest.d.ts +0 -10
  163. package/dist/lib/dbmodels/program/StrengthTest.d.ts.map +0 -1
  164. package/dist/lib/dbmodels/program/StrengthTest.js +0 -39
  165. package/dist/lib/dbmodels/program/StrengthTest.js.map +0 -1
  166. package/dist/lib/dbmodels/program/StrengthTestExercise.d.ts +0 -15
  167. package/dist/lib/dbmodels/program/StrengthTestExercise.d.ts.map +0 -1
  168. package/dist/lib/dbmodels/program/StrengthTestExercise.js +0 -72
  169. package/dist/lib/dbmodels/program/StrengthTestExercise.js.map +0 -1
  170. package/dist/lib/dbmodels/program/StrengthTestSession.js +0 -73
  171. package/dist/lib/dbmodels/program/StrengthTestSession.js.map +0 -1
  172. package/dist/lib/dbmodels/program/Superset.d.ts +0 -13
  173. package/dist/lib/dbmodels/program/Superset.d.ts.map +0 -1
  174. package/dist/lib/dbmodels/program/Superset.js +0 -46
  175. package/dist/lib/dbmodels/program/Superset.js.map +0 -1
  176. package/dist/lib/dbmodels/program/ThirtyDayChallenge.js +0 -70
  177. package/dist/lib/dbmodels/program/ThirtyDayChallenge.js.map +0 -1
  178. package/dist/lib/dbmodels/program/ThirtyDayChallengeStrengthTest.js +0 -55
  179. package/dist/lib/dbmodels/program/ThirtyDayChallengeStrengthTest.js.map +0 -1
  180. package/dist/lib/dbmodels/program/TranslatedChallenge.d.ts +0 -15
  181. package/dist/lib/dbmodels/program/TranslatedChallenge.d.ts.map +0 -1
  182. package/dist/lib/dbmodels/program/TranslatedChallenge.js +0 -69
  183. package/dist/lib/dbmodels/program/TranslatedChallenge.js.map +0 -1
  184. package/dist/lib/dbmodels/program/TranslatedExerciseModel.d.ts +0 -25
  185. package/dist/lib/dbmodels/program/TranslatedExerciseModel.d.ts.map +0 -1
  186. package/dist/lib/dbmodels/program/TranslatedExerciseModel.js +0 -123
  187. package/dist/lib/dbmodels/program/TranslatedExerciseModel.js.map +0 -1
  188. package/dist/lib/dbmodels/program/TranslatedStrengthTest.d.ts +0 -12
  189. package/dist/lib/dbmodels/program/TranslatedStrengthTest.d.ts.map +0 -1
  190. package/dist/lib/dbmodels/program/TranslatedStrengthTest.js +0 -45
  191. package/dist/lib/dbmodels/program/TranslatedStrengthTest.js.map +0 -1
  192. package/dist/lib/dbmodels/program/TranslatedStrengthTestExercise.d.ts +0 -16
  193. package/dist/lib/dbmodels/program/TranslatedStrengthTestExercise.d.ts.map +0 -1
  194. package/dist/lib/dbmodels/program/TranslatedStrengthTestExercise.js +0 -78
  195. package/dist/lib/dbmodels/program/TranslatedStrengthTestExercise.js.map +0 -1
  196. package/dist/lib/dbmodels/program/UserChallenge.d.ts +0 -10
  197. package/dist/lib/dbmodels/program/UserChallenge.d.ts.map +0 -1
  198. package/dist/lib/dbmodels/program/UserChallenge.js +0 -47
  199. package/dist/lib/dbmodels/program/UserChallenge.js.map +0 -1
  200. package/dist/lib/dbmodels/program/UserExerciseNote.js +0 -61
  201. package/dist/lib/dbmodels/program/UserExerciseNote.js.map +0 -1
  202. package/dist/lib/dbmodels/program/UserStrengthTests.d.ts +0 -11
  203. package/dist/lib/dbmodels/program/UserStrengthTests.d.ts.map +0 -1
  204. package/dist/lib/dbmodels/program/UserStrengthTests.js +0 -54
  205. package/dist/lib/dbmodels/program/UserStrengthTests.js.map +0 -1
  206. package/dist/lib/dbmodels/program/Workout.d.ts +0 -14
  207. package/dist/lib/dbmodels/program/Workout.d.ts.map +0 -1
  208. package/dist/lib/dbmodels/program/Workout.js +0 -66
  209. package/dist/lib/dbmodels/program/Workout.js.map +0 -1
  210. package/dist/lib/dbmodels/program/WorkoutCompletion.js +0 -65
  211. package/dist/lib/dbmodels/program/WorkoutCompletion.js.map +0 -1
  212. package/dist/lib/dbmodels/program/WorkoutSession.js +0 -93
  213. package/dist/lib/dbmodels/program/WorkoutSession.js.map +0 -1
  214. package/dist/lib/dbmodels/subscription/Subscription.d.ts +0 -19
  215. package/dist/lib/dbmodels/subscription/Subscription.d.ts.map +0 -1
  216. package/dist/lib/dbmodels/subscription/Subscription.js +0 -91
  217. package/dist/lib/dbmodels/subscription/Subscription.js.map +0 -1
  218. package/dist/lib/dbmodels/subscription/SubscriptionEvent.js +0 -79
  219. package/dist/lib/dbmodels/subscription/SubscriptionEvent.js.map +0 -1
  220. package/dist/lib/dbmodels/subscription/SubscriptionLog.d.ts +0 -9
  221. package/dist/lib/dbmodels/subscription/SubscriptionLog.d.ts.map +0 -1
  222. package/dist/lib/dbmodels/subscription/SubscriptionLog.js +0 -42
  223. package/dist/lib/dbmodels/subscription/SubscriptionLog.js.map +0 -1
  224. package/dist/lib/dbmodels/subscription/SubscriptionRefund.js +0 -92
  225. package/dist/lib/dbmodels/subscription/SubscriptionRefund.js.map +0 -1
  226. package/dist/lib/dbmodels/user/DeviceTokens.js +0 -34
  227. package/dist/lib/dbmodels/user/DeviceTokens.js.map +0 -1
  228. package/dist/lib/dbmodels/user/PersistedUser.d.ts +0 -43
  229. package/dist/lib/dbmodels/user/PersistedUser.d.ts.map +0 -1
  230. package/dist/lib/dbmodels/user/PersistedUser.js +0 -237
  231. package/dist/lib/dbmodels/user/PersistedUser.js.map +0 -1
  232. package/dist/lib/dbmodels/user/UserAddons.js +0 -26
  233. package/dist/lib/dbmodels/user/UserAddons.js.map +0 -1
  234. package/dist/lib/dbmodels/user/UserBadges.js +0 -63
  235. package/dist/lib/dbmodels/user/UserBadges.js.map +0 -1
  236. package/dist/lib/dbmodels/user/UserCoach.js +0 -40
  237. package/dist/lib/dbmodels/user/UserCoach.js.map +0 -1
  238. package/dist/lib/dbmodels/user/UserDiscount.js +0 -24
  239. package/dist/lib/dbmodels/user/UserDiscount.js.map +0 -1
  240. package/dist/lib/dbmodels/user/UserOptions.js +0 -34
  241. package/dist/lib/dbmodels/user/UserOptions.js.map +0 -1
  242. package/dist/lib/dbmodels/user/UserProgressPhoto.js +0 -59
  243. package/dist/lib/dbmodels/user/UserProgressPhoto.js.map +0 -1
  244. package/dist/lib/dbmodels/user/UserStreaks.js +0 -64
  245. package/dist/lib/dbmodels/user/UserStreaks.js.map +0 -1
  246. package/dist/lib/dbmodels/user/UsersFriends.js +0 -46
  247. package/dist/lib/dbmodels/user/UsersFriends.js.map +0 -1
  248. package/dist/lib/enums/ProgramEnums.d.ts +0 -18
  249. package/dist/lib/enums/ProgramEnums.d.ts.map +0 -1
  250. package/dist/lib/enums/ProgramEnums.js +0 -22
  251. package/dist/lib/enums/ProgramEnums.js.map +0 -1
  252. package/dist/lib/enums/ProgramTemplates.js +0 -738
  253. package/dist/lib/enums/ProgramTemplates.js.map +0 -1
  254. package/dist/lib/middlewares/ErrorMiddleware.js +0 -141
  255. package/dist/lib/middlewares/ErrorMiddleware.js.map +0 -1
  256. package/dist/lib/middlewares/ValidationMiddleware.js +0 -24
  257. package/dist/lib/middlewares/ValidationMiddleware.js.map +0 -1
  258. package/dist/lib/models/BlueprintInterfaces.js +0 -3
  259. package/dist/lib/models/BlueprintInterfaces.js.map +0 -1
  260. package/dist/lib/models/ExerciseInterfaces.d.ts +0 -68
  261. package/dist/lib/models/ExerciseInterfaces.d.ts.map +0 -1
  262. package/dist/lib/models/ExerciseInterfaces.js +0 -3
  263. package/dist/lib/models/ExerciseInterfaces.js.map +0 -1
  264. package/dist/lib/models/NotificationInterfaces.js +0 -11
  265. package/dist/lib/models/NotificationInterfaces.js.map +0 -1
  266. package/dist/lib/models/ProgramInterfaces.js +0 -3
  267. package/dist/lib/models/ProgramInterfaces.js.map +0 -1
  268. package/dist/lib/models/UserInterfaces.js +0 -3
  269. package/dist/lib/models/UserInterfaces.js.map +0 -1
  270. package/dist/lib/models/WorkoutInterfaces.js +0 -3
  271. package/dist/lib/models/WorkoutInterfaces.js.map +0 -1
  272. package/dist/lib/scripts/cli.js +0 -82
  273. package/dist/lib/scripts/cli.js.map +0 -1
  274. package/dist/lib/scripts/populate-exercise-thumbnails.js +0 -64
  275. package/dist/lib/scripts/populate-exercise-thumbnails.js.map +0 -1
  276. package/dist/lib/scripts/setup-database.js +0 -43
  277. package/dist/lib/scripts/setup-database.js.map +0 -1
  278. package/dist/lib/scripts/verify-indexes.js +0 -94
  279. package/dist/lib/scripts/verify-indexes.js.map +0 -1
  280. package/dist/lib/testing/testFixtures.js +0 -520
  281. package/dist/lib/testing/testFixtures.js.map +0 -1
  282. package/dist/lib/testing/testHelpers.js +0 -149
  283. package/dist/lib/testing/testHelpers.js.map +0 -1
  284. package/dist/lib/utils/AuthenticationUtil.js +0 -481
  285. package/dist/lib/utils/AuthenticationUtil.js.map +0 -1
  286. package/dist/lib/utils/Logger.js +0 -242
  287. package/dist/lib/utils/Logger.js.map +0 -1
  288. package/dist/lib/utils/NotificationClient.js +0 -371
  289. package/dist/lib/utils/NotificationClient.js.map +0 -1
  290. package/dist/lib/utils/NotificationsUtil.js +0 -95
  291. package/dist/lib/utils/NotificationsUtil.js.map +0 -1
  292. package/dist/lib/utils/SecretManager.js +0 -107
  293. package/dist/lib/utils/SecretManager.js.map +0 -1
  294. package/dist/lib/utils/SentryUtil.js +0 -140
  295. package/dist/lib/utils/SentryUtil.js.map +0 -1
  296. package/dist/lib/utils/imageValidation.js +0 -31
  297. package/dist/lib/utils/imageValidation.js.map +0 -1
@@ -1,688 +0,0 @@
1
- /**
2
- * Firebase Push Notification Client
3
- *
4
- * Industry-standard implementation using Firebase Admin SDK for:
5
- * - iOS (APNs via FCM)
6
- * - Android (FCM)
7
- *
8
- * Features:
9
- * - Multicast messaging (up to 500 tokens per request)
10
- * - Topic-based messaging for efficient broadcasting
11
- * - Automatic token validation and cleanup
12
- * - Built-in retry logic and error handling
13
- * - Message delivery tracking
14
- * - Type-safe API
15
- */ import admin from "firebase-admin";
16
- import { CommonSchemas } from "../config/ConfigValidator.js";
17
- import { ExternalAPIError } from "../Errors/AppError.js";
18
- import { Log } from "../utils/Logger.js";
19
- import { SecretManager } from "../utils/SecretManager.js";
20
- import { DeviceTokens } from "../dbmodels/user/DeviceTokens.js";
21
- import { PersistedUser } from "../dbmodels/user/PersistedUser.js";
22
- import { NotificationModels } from "../dbmodels/notifications/NotificationModels.js";
23
- import { TranslatedNotification } from "../dbmodels/notifications/TranslatedNotification.js";
24
- export class FirebasePushNotificationClient {
25
- static instance;
26
- static initPromise = null;
27
- logger = Log.getInstance().extend("firebase-push");
28
- app = null;
29
- serviceAccount = null;
30
- constructor(_config, serviceAccount){
31
- // config parameter kept for backward compatibility but not used (FCM config comes from Secret Manager)
32
- this.serviceAccount = serviceAccount;
33
- this.initializeApp();
34
- }
35
- static async getInstance() {
36
- if (FirebasePushNotificationClient.instance) {
37
- return FirebasePushNotificationClient.instance;
38
- }
39
- // If already initializing, wait for that to complete
40
- if (FirebasePushNotificationClient.initPromise) {
41
- return FirebasePushNotificationClient.initPromise;
42
- }
43
- // Start initialization
44
- FirebasePushNotificationClient.initPromise = (async ()=>{
45
- // Parse config (mostly for optional APNs fields, FCM comes from Secret Manager)
46
- const parsedConfig = CommonSchemas.pushNotification.parse(process.env);
47
- const serviceAccount = await FirebasePushNotificationClient.loadServiceAccount();
48
- FirebasePushNotificationClient.instance = new FirebasePushNotificationClient(parsedConfig, serviceAccount);
49
- FirebasePushNotificationClient.initPromise = null;
50
- return FirebasePushNotificationClient.instance;
51
- })();
52
- return FirebasePushNotificationClient.initPromise;
53
- }
54
- static async loadServiceAccount() {
55
- const logger = Log.getInstance().extend("firebase-push");
56
- const PROJECT_ID = "1033066542238";
57
- const SECRET_NAME = "firebase_new_key";
58
- try {
59
- // Check if FIREBASE_SERVICE_ACCOUNT_KEY env variable is set (for local development)
60
- const localKeyPath = process.env.FIREBASE_SERVICE_ACCOUNT_KEY;
61
- if (localKeyPath) {
62
- const fs = await import("node:fs/promises");
63
- const serviceAccountJson = await fs.readFile(localKeyPath, "utf-8");
64
- const serviceAccount = JSON.parse(serviceAccountJson);
65
- logger.info("Firebase service account loaded from local file");
66
- return serviceAccount;
67
- }
68
- // Production: Load from Secret Manager using shared utility
69
- // This provides better error handling, caching, and reuses the client instance
70
- logger.info("Loading Firebase service account from Secret Manager", {
71
- projectId: PROJECT_ID,
72
- secretName: SECRET_NAME
73
- });
74
- const serviceAccount = await SecretManager.loadSecretJSON(SECRET_NAME, PROJECT_ID);
75
- logger.info("Firebase service account loaded successfully from Secret Manager", {
76
- projectId: serviceAccount.project_id,
77
- clientEmail: serviceAccount.client_email
78
- });
79
- return serviceAccount;
80
- } catch (error) {
81
- logger.error("Failed to load Firebase service account", {
82
- error: error instanceof Error ? error.message : String(error),
83
- stack: error instanceof Error ? error.stack : undefined
84
- });
85
- throw new ExternalAPIError("Failed to load Firebase credentials", `Error: ${error instanceof Error ? error.message : String(error)}`);
86
- }
87
- }
88
- static resetInstance() {
89
- FirebasePushNotificationClient.instance?.shutdown();
90
- FirebasePushNotificationClient.instance = undefined;
91
- FirebasePushNotificationClient.initPromise = null;
92
- }
93
- initializeApp() {
94
- try {
95
- // Check if app already exists
96
- if (admin.apps?.length && admin.apps.length > 0) {
97
- this.app = admin.app();
98
- this.logger.info("Using existing Firebase app");
99
- return;
100
- }
101
- if (!this.serviceAccount) {
102
- throw new Error("Service account not loaded");
103
- }
104
- // Validate service account has all required fields
105
- if (!this.serviceAccount.project_id || !this.serviceAccount.client_email || !this.serviceAccount.private_key) {
106
- throw new Error("Invalid service account: missing required fields");
107
- }
108
- this.logger.info("Initializing Firebase Admin SDK", {
109
- projectId: this.serviceAccount.project_id,
110
- clientEmail: this.serviceAccount.client_email
111
- });
112
- this.app = admin.initializeApp({
113
- credential: admin.credential.cert(this.serviceAccount)
114
- });
115
- this.logger.info("Firebase Admin SDK initialized successfully");
116
- } catch (error) {
117
- this.logger.error("Failed to initialize Firebase Admin SDK", {
118
- error
119
- });
120
- throw new ExternalAPIError("Failed to initialize Firebase", `Error: ${String(error)}`);
121
- }
122
- }
123
- shutdown() {
124
- if (this.app) {
125
- this.app.delete().catch((error)=>{
126
- this.logger.error("Error shutting down Firebase app", {
127
- error
128
- });
129
- });
130
- this.app = null;
131
- }
132
- }
133
- /**
134
- * Detect if a token is a legacy APN token (hex format, 64 characters)
135
- */ isLegacyAPNToken(token) {
136
- // Legacy APN tokens are 64 hex characters (sometimes with spaces or angle brackets)
137
- const cleanToken = token.replace(/[<>\s]/g, '');
138
- return /^[0-9a-fA-F]{64}$/.test(cleanToken);
139
- }
140
- /**
141
- * Send notifications using multicast (up to 500 tokens at once)
142
- * Automatically handles token validation and cleanup
143
- */ async sendMulticast(tokens, notification, platform) {
144
- if (tokens.length === 0) {
145
- return {
146
- successCount: 0,
147
- failureCount: 0,
148
- invalidTokens: []
149
- };
150
- }
151
- const messaging = admin.messaging();
152
- const invalidTokens = [];
153
- let successCount = 0;
154
- let failureCount = 0;
155
- // Detect if any tokens are legacy APN tokens
156
- const hasLegacyAPNTokens = tokens.some((token)=>this.isLegacyAPNToken(token));
157
- const isIOSPlatform = platform === "ios" || hasLegacyAPNTokens;
158
- if (hasLegacyAPNTokens) {
159
- this.logger.info("Detected legacy APN tokens in batch", {
160
- totalTokens: tokens.length,
161
- legacyCount: tokens.filter((t)=>this.isLegacyAPNToken(t)).length
162
- });
163
- }
164
- // Firebase allows max 500 tokens per multicast
165
- const BATCH_SIZE = 500;
166
- for(let i = 0; i < tokens.length; i += BATCH_SIZE){
167
- const batch = tokens.slice(i, i + BATCH_SIZE);
168
- const message = {
169
- tokens: batch,
170
- notification: {
171
- title: notification.title,
172
- body: notification.body,
173
- ...notification.imageUrl && {
174
- imageUrl: notification.imageUrl
175
- }
176
- },
177
- data: notification.data || {},
178
- ...isIOSPlatform && {
179
- apns: {
180
- payload: {
181
- aps: {
182
- sound: notification.sound || "default",
183
- ...notification.badge !== undefined && {
184
- badge: notification.badge
185
- },
186
- contentAvailable: true
187
- }
188
- },
189
- fcmOptions: {
190
- ...notification.imageUrl && {
191
- imageUrl: notification.imageUrl
192
- }
193
- }
194
- }
195
- },
196
- ...platform === "android" && {
197
- android: {
198
- priority: "high",
199
- notification: {
200
- sound: notification.sound || "default",
201
- channelId: "default",
202
- ...notification.imageUrl && {
203
- imageUrl: notification.imageUrl
204
- }
205
- }
206
- }
207
- }
208
- };
209
- try {
210
- const response = await messaging.sendEachForMulticast(message);
211
- successCount += response.successCount;
212
- failureCount += response.failureCount;
213
- // Identify and collect invalid tokens
214
- response.responses.forEach((resp, idx)=>{
215
- if (!resp.success && resp.error) {
216
- const errorCode = resp.error.code;
217
- // Token is invalid or unregistered
218
- if (errorCode === "messaging/invalid-registration-token" || errorCode === "messaging/registration-token-not-registered") {
219
- invalidTokens.push(batch[idx]);
220
- }
221
- this.logger.warn("Message send failed", {
222
- token: batch[idx],
223
- error: resp.error.message,
224
- code: errorCode
225
- });
226
- }
227
- });
228
- this.logger.info("Multicast batch sent", {
229
- batchSize: batch.length,
230
- successCount: response.successCount,
231
- failureCount: response.failureCount
232
- });
233
- } catch (error) {
234
- this.logger.error("Multicast send error", {
235
- error,
236
- batchSize: batch.length
237
- });
238
- failureCount += batch.length;
239
- }
240
- }
241
- // Clean up invalid tokens from database
242
- if (invalidTokens.length > 0) {
243
- await this.removeInvalidTokens(invalidTokens);
244
- }
245
- return {
246
- successCount,
247
- failureCount,
248
- invalidTokens
249
- };
250
- }
251
- /**
252
- * Remove invalid device tokens from database
253
- */ async removeInvalidTokens(tokens) {
254
- try {
255
- const deleted = await DeviceTokens.destroy({
256
- where: {
257
- deviceToken: tokens
258
- }
259
- });
260
- this.logger.info("Removed invalid tokens from database", {
261
- count: deleted,
262
- tokens: tokens.length
263
- });
264
- } catch (error) {
265
- this.logger.error("Failed to remove invalid tokens", {
266
- error
267
- });
268
- }
269
- }
270
- /**
271
- * Send notification to specific device tokens
272
- */ async sendToTokens(tokens, platform, notification) {
273
- if (tokens.length === 0) {
274
- this.logger.warn("No tokens provided, skipping notification");
275
- return {
276
- successCount: 0,
277
- failureCount: 0,
278
- invalidTokens: []
279
- };
280
- }
281
- this.logger.info("Sending notification to tokens", {
282
- tokenCount: tokens.length,
283
- platform,
284
- title: notification.title
285
- });
286
- return await this.sendMulticast(tokens, notification, platform);
287
- }
288
- /**
289
- * Send notification to a single user (all their devices)
290
- */ async sendToUser(params) {
291
- this.logger.info("Sending notification to user", {
292
- userUuid: params.userUuid
293
- });
294
- const deviceTokens = await DeviceTokens.findAll({
295
- where: {
296
- userUuid: params.userUuid
297
- },
298
- attributes: [
299
- "deviceToken",
300
- "platform"
301
- ]
302
- });
303
- if (deviceTokens.length === 0) {
304
- this.logger.warn("No device tokens found for user", {
305
- userUuid: params.userUuid
306
- });
307
- return {
308
- successCount: 0,
309
- failureCount: 0,
310
- invalidTokens: []
311
- };
312
- }
313
- // Separate tokens by platform, also detecting legacy APN tokens
314
- const iosTokens = deviceTokens.filter((dt)=>dt.platform === "ios" || this.isLegacyAPNToken(dt.deviceToken)).map((dt)=>dt.deviceToken);
315
- const androidTokens = deviceTokens.filter((dt)=>dt.platform === "android" && !this.isLegacyAPNToken(dt.deviceToken)).map((dt)=>dt.deviceToken);
316
- const legacyAPNCount = deviceTokens.filter((dt)=>this.isLegacyAPNToken(dt.deviceToken)).length;
317
- if (legacyAPNCount > 0) {
318
- this.logger.info("Found legacy APN tokens for user", {
319
- userUuid: params.userUuid,
320
- legacyTokenCount: legacyAPNCount
321
- });
322
- }
323
- const [iosResult, androidResult] = await Promise.all([
324
- iosTokens.length > 0 ? this.sendToTokens(iosTokens, "ios", params.notification) : Promise.resolve({
325
- successCount: 0,
326
- failureCount: 0,
327
- invalidTokens: []
328
- }),
329
- androidTokens.length > 0 ? this.sendToTokens(androidTokens, "android", params.notification) : Promise.resolve({
330
- successCount: 0,
331
- failureCount: 0,
332
- invalidTokens: []
333
- })
334
- ]);
335
- return {
336
- successCount: iosResult.successCount + androidResult.successCount,
337
- failureCount: iosResult.failureCount + androidResult.failureCount,
338
- invalidTokens: [
339
- ...iosResult.invalidTokens,
340
- ...androidResult.invalidTokens
341
- ]
342
- };
343
- }
344
- /**
345
- * Send notification to multiple users
346
- */ async sendToUsers(params) {
347
- this.logger.info("Sending notification to multiple users", {
348
- count: params.userUuids.length
349
- });
350
- const deviceTokens = await DeviceTokens.findAll({
351
- where: {
352
- userUuid: params.userUuids
353
- },
354
- attributes: [
355
- "deviceToken",
356
- "platform"
357
- ]
358
- });
359
- if (deviceTokens.length === 0) {
360
- this.logger.warn("No device tokens found for users");
361
- return {
362
- successCount: 0,
363
- failureCount: 0,
364
- invalidTokens: []
365
- };
366
- }
367
- // Separate tokens by platform, also detecting legacy APN tokens
368
- const iosTokens = deviceTokens.filter((dt)=>dt.platform === "ios" || this.isLegacyAPNToken(dt.deviceToken)).map((dt)=>dt.deviceToken);
369
- const androidTokens = deviceTokens.filter((dt)=>dt.platform === "android" && !this.isLegacyAPNToken(dt.deviceToken)).map((dt)=>dt.deviceToken);
370
- const legacyAPNCount = deviceTokens.filter((dt)=>this.isLegacyAPNToken(dt.deviceToken)).length;
371
- if (legacyAPNCount > 0) {
372
- this.logger.info("Found legacy APN tokens for users", {
373
- legacyTokenCount: legacyAPNCount
374
- });
375
- }
376
- const [iosResult, androidResult] = await Promise.all([
377
- iosTokens.length > 0 ? this.sendToTokens(iosTokens, "ios", params.notification) : Promise.resolve({
378
- successCount: 0,
379
- failureCount: 0,
380
- invalidTokens: []
381
- }),
382
- androidTokens.length > 0 ? this.sendToTokens(androidTokens, "android", params.notification) : Promise.resolve({
383
- successCount: 0,
384
- failureCount: 0,
385
- invalidTokens: []
386
- })
387
- ]);
388
- return {
389
- successCount: iosResult.successCount + androidResult.successCount,
390
- failureCount: iosResult.failureCount + androidResult.failureCount,
391
- invalidTokens: [
392
- ...iosResult.invalidTokens,
393
- ...androidResult.invalidTokens
394
- ]
395
- };
396
- }
397
- /**
398
- * Subscribe users to a topic for efficient group messaging
399
- */ async subscribeToTopic(tokens, topic) {
400
- if (tokens.length === 0) {
401
- return {
402
- successCount: 0,
403
- failureCount: 0
404
- };
405
- }
406
- this.logger.info("Subscribing tokens to topic", {
407
- tokenCount: tokens.length,
408
- topic
409
- });
410
- try {
411
- const response = await admin.messaging().subscribeToTopic(tokens, topic);
412
- this.logger.info("Topic subscription complete", {
413
- successCount: response.successCount,
414
- failureCount: response.failureCount,
415
- topic
416
- });
417
- return {
418
- successCount: response.successCount,
419
- failureCount: response.failureCount
420
- };
421
- } catch (error) {
422
- this.logger.error("Topic subscription error", {
423
- error,
424
- topic
425
- });
426
- throw new ExternalAPIError("Failed to subscribe to topic", `Topic: ${topic}, Error: ${String(error)}`);
427
- }
428
- }
429
- /**
430
- * Send notification to a topic (efficient for large groups)
431
- */ async sendToTopic(params) {
432
- this.logger.info("Sending notification to topic", {
433
- topic: params.topic
434
- });
435
- const message = {
436
- topic: params.topic,
437
- notification: {
438
- title: params.notification.title,
439
- body: params.notification.body,
440
- ...params.notification.imageUrl && {
441
- imageUrl: params.notification.imageUrl
442
- }
443
- },
444
- data: params.notification.data || {},
445
- apns: {
446
- payload: {
447
- aps: {
448
- sound: params.notification.sound || "default",
449
- ...params.notification.badge !== undefined && {
450
- badge: params.notification.badge
451
- },
452
- contentAvailable: true
453
- }
454
- }
455
- },
456
- android: {
457
- priority: "high",
458
- notification: {
459
- sound: params.notification.sound || "default",
460
- channelId: "default"
461
- }
462
- }
463
- };
464
- try {
465
- const messageId = await admin.messaging().send(message);
466
- this.logger.info("Topic notification sent", {
467
- topic: params.topic,
468
- messageId
469
- });
470
- return {
471
- messageId
472
- };
473
- } catch (error) {
474
- this.logger.error("Topic send error", {
475
- error,
476
- topic: params.topic
477
- });
478
- throw new ExternalAPIError("Failed to send topic notification", `Topic: ${params.topic}, Error: ${String(error)}`);
479
- }
480
- }
481
- /**
482
- * Send notification using a template
483
- */ async sendTemplateToUser(params) {
484
- this.logger.info("Sending template notification to user", {
485
- userUuid: params.userUuid,
486
- notificationType: params.notificationType,
487
- language: params.language
488
- });
489
- const includeOptions = {
490
- model: TranslatedNotification,
491
- as: "translations",
492
- required: false
493
- };
494
- if (params.language) {
495
- includeOptions.where = {
496
- language: params.language
497
- };
498
- }
499
- const template = await NotificationModels.findOne({
500
- where: {
501
- type: params.notificationType
502
- },
503
- include: [
504
- includeOptions
505
- ]
506
- });
507
- if (!template) {
508
- throw new ExternalAPIError("Notification template not found", `Type: ${params.notificationType}`);
509
- }
510
- const translation = template.translations?.find((t)=>t.language === params.language);
511
- let text = translation?.text || template.text;
512
- if (params.data) {
513
- Object.entries(params.data).forEach(([key, value])=>{
514
- text = text.replace(new RegExp(`{{${key}}}`, "g"), value);
515
- });
516
- }
517
- return await this.sendToUser({
518
- userUuid: params.userUuid,
519
- notification: {
520
- title: params.notificationType,
521
- body: text,
522
- ...params.data && {
523
- data: params.data
524
- }
525
- }
526
- });
527
- }
528
- /**
529
- * Send templated notification to multiple users
530
- */ async sendTemplateToUsers(params) {
531
- this.logger.info("Sending template notification to multiple users", {
532
- count: params.userUuids.length,
533
- notificationType: params.notificationType
534
- });
535
- const includeOptions = {
536
- model: TranslatedNotification,
537
- as: "translations",
538
- required: false
539
- };
540
- if (params.language) {
541
- includeOptions.where = {
542
- language: params.language
543
- };
544
- }
545
- const template = await NotificationModels.findOne({
546
- where: {
547
- type: params.notificationType
548
- },
549
- include: [
550
- includeOptions
551
- ]
552
- });
553
- if (!template) {
554
- throw new ExternalAPIError("Notification template not found", `Type: ${params.notificationType}`);
555
- }
556
- const translation = template.translations?.find((t)=>t.language === params.language);
557
- let text = translation?.text || template.text;
558
- if (params.data) {
559
- Object.entries(params.data).forEach(([key, value])=>{
560
- text = text.replace(new RegExp(`{{${key}}}`, "g"), value);
561
- });
562
- }
563
- return await this.sendToUsers({
564
- userUuids: params.userUuids,
565
- notification: {
566
- title: params.notificationType,
567
- body: text,
568
- ...params.data && {
569
- data: params.data
570
- }
571
- }
572
- });
573
- }
574
- /**
575
- * Send notification to all users (uses topic for efficiency)
576
- * Consider subscribing users to an "all_users" topic for better performance
577
- */ async sendToAllUsers(params) {
578
- const batchSize = params.batchSize || 1000;
579
- let offset = 0;
580
- let totalSent = 0;
581
- this.logger.info("Starting broadcast notification", {
582
- batchSize
583
- });
584
- while(true){
585
- const deviceTokens = await DeviceTokens.findAll({
586
- limit: batchSize,
587
- offset,
588
- attributes: [
589
- "deviceToken",
590
- "platform"
591
- ]
592
- });
593
- if (deviceTokens.length === 0) {
594
- break;
595
- }
596
- const iosTokens = deviceTokens.filter((dt)=>dt.platform === "ios").map((dt)=>dt.deviceToken);
597
- const androidTokens = deviceTokens.filter((dt)=>dt.platform === "android").map((dt)=>dt.deviceToken);
598
- const [iosResult, androidResult] = await Promise.all([
599
- iosTokens.length > 0 ? this.sendToTokens(iosTokens, "ios", params.notification) : Promise.resolve({
600
- successCount: 0,
601
- failureCount: 0,
602
- invalidTokens: []
603
- }),
604
- androidTokens.length > 0 ? this.sendToTokens(androidTokens, "android", params.notification) : Promise.resolve({
605
- successCount: 0,
606
- failureCount: 0,
607
- invalidTokens: []
608
- })
609
- ]);
610
- totalSent += iosResult.successCount + androidResult.successCount;
611
- offset += batchSize;
612
- this.logger.info("Broadcast batch sent", {
613
- batchSent: iosResult.successCount + androidResult.successCount,
614
- totalSent
615
- });
616
- }
617
- this.logger.info("Broadcast notification complete", {
618
- totalSent
619
- });
620
- return {
621
- totalSent
622
- };
623
- }
624
- /**
625
- * Send notification to a user group
626
- * Recommended: Use topics instead for better performance
627
- */ async sendToGroup(params) {
628
- const batchSize = params.batchSize || 1000;
629
- let offset = 0;
630
- let totalSent = 0;
631
- this.logger.info("Starting group notification", {
632
- group: params.group,
633
- batchSize
634
- });
635
- while(true){
636
- const users = await PersistedUser.findAll({
637
- where: {
638
- subscriptionType: params.group
639
- },
640
- include: [
641
- {
642
- model: DeviceTokens,
643
- as: "deviceTokens",
644
- attributes: [
645
- "deviceToken",
646
- "platform"
647
- ]
648
- }
649
- ],
650
- limit: batchSize,
651
- offset
652
- });
653
- if (users.length === 0) {
654
- break;
655
- }
656
- const allTokens = users.flatMap((user)=>user.deviceTokens || []);
657
- const iosTokens = allTokens.filter((dt)=>dt.platform === "ios").map((dt)=>dt.deviceToken);
658
- const androidTokens = allTokens.filter((dt)=>dt.platform === "android").map((dt)=>dt.deviceToken);
659
- const [iosResult, androidResult] = await Promise.all([
660
- iosTokens.length > 0 ? this.sendToTokens(iosTokens, "ios", params.notification) : Promise.resolve({
661
- successCount: 0,
662
- failureCount: 0,
663
- invalidTokens: []
664
- }),
665
- androidTokens.length > 0 ? this.sendToTokens(androidTokens, "android", params.notification) : Promise.resolve({
666
- successCount: 0,
667
- failureCount: 0,
668
- invalidTokens: []
669
- })
670
- ]);
671
- totalSent += iosResult.successCount + androidResult.successCount;
672
- offset += batchSize;
673
- this.logger.info("Group batch sent", {
674
- batchSent: iosResult.successCount + androidResult.successCount,
675
- totalSent
676
- });
677
- }
678
- this.logger.info("Group notification complete", {
679
- totalSent,
680
- group: params.group
681
- });
682
- return {
683
- totalSent
684
- };
685
- }
686
- }
687
-
688
- //# sourceMappingURL=FirebasePushNotificationClient.js.map