90dc-core 1.16.27 → 1.18.0

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 (55) hide show
  1. package/dist/index.d.ts +5 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +6 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/clients/EmailClient.d.ts +15 -34
  6. package/dist/lib/clients/EmailClient.d.ts.map +1 -1
  7. package/dist/lib/clients/EmailClient.js +41 -7
  8. package/dist/lib/clients/EmailClient.js.map +1 -1
  9. package/dist/lib/clients/ImagesClient.d.ts +17 -0
  10. package/dist/lib/clients/ImagesClient.d.ts.map +1 -0
  11. package/dist/lib/clients/ImagesClient.js +116 -0
  12. package/dist/lib/clients/ImagesClient.js.map +1 -0
  13. package/dist/lib/clients/MailingClient.d.ts +21 -0
  14. package/dist/lib/clients/MailingClient.d.ts.map +1 -0
  15. package/dist/lib/clients/MailingClient.js +84 -0
  16. package/dist/lib/clients/MailingClient.js.map +1 -0
  17. package/dist/lib/clients/types/email.types.d.ts +41 -0
  18. package/dist/lib/clients/types/email.types.d.ts.map +1 -0
  19. package/dist/lib/clients/types/email.types.js +3 -0
  20. package/dist/lib/clients/types/email.types.js.map +1 -0
  21. package/dist/lib/clients/types/images.types.d.ts +21 -0
  22. package/dist/lib/clients/types/images.types.d.ts.map +1 -0
  23. package/dist/lib/clients/types/images.types.js +3 -0
  24. package/dist/lib/clients/types/images.types.js.map +1 -0
  25. package/dist/lib/clients/types/mailing.types.d.ts +10 -0
  26. package/dist/lib/clients/types/mailing.types.d.ts.map +1 -0
  27. package/dist/lib/clients/types/mailing.types.js +3 -0
  28. package/dist/lib/clients/types/mailing.types.js.map +1 -0
  29. package/dist/lib/dbmodels/program/CircularProgramDraft.d.ts +1 -0
  30. package/dist/lib/dbmodels/program/CircularProgramDraft.d.ts.map +1 -1
  31. package/dist/lib/dbmodels/program/CircularProgramDraft.js.map +1 -1
  32. package/dist/lib/dbmodels/program/Exercise.d.ts +1 -0
  33. package/dist/lib/dbmodels/program/Exercise.d.ts.map +1 -1
  34. package/dist/lib/dbmodels/program/Exercise.js +7 -0
  35. package/dist/lib/dbmodels/program/Exercise.js.map +1 -1
  36. package/dist/lib/dbmodels/program/ProgressEntry.d.ts +1 -0
  37. package/dist/lib/dbmodels/program/ProgressEntry.d.ts.map +1 -1
  38. package/dist/lib/dbmodels/program/ProgressEntry.js +7 -0
  39. package/dist/lib/dbmodels/program/ProgressEntry.js.map +1 -1
  40. package/dist/lib/scripts/sequelize.config.cjs +2 -1
  41. package/dist/lib/scripts/verify-indexes.d.ts +13 -0
  42. package/dist/lib/scripts/verify-indexes.d.ts.map +1 -0
  43. package/dist/lib/scripts/verify-indexes.js +94 -0
  44. package/dist/lib/scripts/verify-indexes.js.map +1 -0
  45. package/dist/lib/utils/NotificationClient.d.ts +7 -0
  46. package/dist/lib/utils/NotificationClient.d.ts.map +1 -1
  47. package/dist/lib/utils/NotificationClient.js +23 -0
  48. package/dist/lib/utils/NotificationClient.js.map +1 -1
  49. package/package.json +2 -1
  50. package/dist/lib/scripts/migrations/20250117000001-create-extensions.js +0 -21
  51. package/dist/lib/scripts/migrations/20250117000001-create-extensions.js.map +0 -1
  52. package/dist/lib/scripts/migrations/20250126000001-add-index-exercises-supersetUuid.js +0 -41
  53. package/dist/lib/scripts/migrations/20250126000001-add-index-exercises-supersetUuid.js.map +0 -1
  54. package/dist/lib/scripts/migrations/20260115000000-add-workout-session-unique-constraint.js +0 -45
  55. package/dist/lib/scripts/migrations/20260115000000-add-workout-session-unique-constraint.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -5,9 +5,13 @@ export * from "./lib/models/UserInterfaces.js";
5
5
  export * from "./lib/models/NotificationInterfaces.js";
6
6
  export * from "./lib/dbmodels/index.js";
7
7
  export { EmailClient } from "./lib/clients/EmailClient.js";
8
+ export { ImagesClient } from "./lib/clients/ImagesClient.js";
9
+ export { MailingClient } from "./lib/clients/MailingClient.js";
8
10
  export { PushNotificationClient } from "./lib/clients/PushNotificationClient.js";
9
11
  export { FirebasePushNotificationClient } from "./lib/clients/FirebasePushNotificationClient.js";
10
- export type { SendTemplateEmailRequest, BatchTemplateEmailRequest, EmailResponse, } from "./lib/clients/EmailClient.js";
12
+ export * as EmailTypes from "./lib/clients/types/email.types.js";
13
+ export * as ImagesTypes from "./lib/clients/types/images.types.js";
14
+ export * as MailingTypes from "./lib/clients/types/mailing.types.js";
11
15
  export type { NotificationPayload } from "./lib/clients/PushNotificationClient.js";
12
16
  export { AuthenticationUtil } from "./lib/utils/AuthenticationUtil.js";
13
17
  export { NotificationsUtil } from "./lib/utils/NotificationsUtil.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,yBAAyB,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAChG,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,GACd,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAGlF,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,aAAa,EACb,UAAU,EACV,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,IAAI,EACJ,UAAU,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,+BAA+B,CAAA;AAGtC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EACL,eAAe,GAChB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAG5F,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAGvF,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAC,cAAc,EAAE,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,yBAAyB,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAGhG,OAAO,KAAK,UAAU,MAAM,oCAAoC,CAAA;AAChE,OAAO,KAAK,WAAW,MAAM,qCAAqC,CAAA;AAClE,OAAO,KAAK,YAAY,MAAM,sCAAsC,CAAA;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAGlF,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,aAAa,EACb,UAAU,EACV,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,IAAI,EACJ,UAAU,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,+BAA+B,CAAA;AAGtC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EACL,eAAe,GAChB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAG5F,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAGvF,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAC,cAAc,EAAE,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAA"}
package/dist/index.js CHANGED
@@ -8,8 +8,14 @@ export * from "./lib/models/NotificationInterfaces.js";
8
8
  export * from "./lib/dbmodels/index.js";
9
9
  //Clients
10
10
  export { EmailClient } from "./lib/clients/EmailClient.js";
11
+ export { ImagesClient } from "./lib/clients/ImagesClient.js";
12
+ export { MailingClient } from "./lib/clients/MailingClient.js";
11
13
  export { PushNotificationClient } from "./lib/clients/PushNotificationClient.js";
12
14
  export { FirebasePushNotificationClient } from "./lib/clients/FirebasePushNotificationClient.js";
15
+ //Client Types (namespace imports)
16
+ export * as EmailTypes from "./lib/clients/types/email.types.js";
17
+ export * as ImagesTypes from "./lib/clients/types/images.types.js";
18
+ export * as MailingTypes from "./lib/clients/types/mailing.types.js";
13
19
  //Utils
14
20
  export { AuthenticationUtil } from "./lib/utils/AuthenticationUtil.js";
15
21
  export { NotificationsUtil } from "./lib/utils/NotificationsUtil.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models - Export all models and model arrays\nexport * from \"./lib/dbmodels/index.js\"\n\n//Clients\nexport { EmailClient } from \"./lib/clients/EmailClient.js\"\nexport { PushNotificationClient } from \"./lib/clients/PushNotificationClient.js\"\nexport { FirebasePushNotificationClient } from \"./lib/clients/FirebasePushNotificationClient.js\"\nexport type {\n SendTemplateEmailRequest,\n BatchTemplateEmailRequest,\n EmailResponse,\n} from \"./lib/clients/EmailClient.js\"\nexport type { NotificationPayload } from \"./lib/clients/PushNotificationClient.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\nexport {SecretManager} from \"./lib/utils/SecretManager.js\"\nexport {\n initializeSentry,\n isSentryEnabled,\n scrubObject,\n captureRequestBody,\n extractUserContext,\n buildRequestContext,\n buildResponseContext,\n reportErrorToSentry,\n reportMessageToSentry,\n type ErrorReportOptions,\n type SeverityLevel,\n} from \"./lib/utils/SentryUtil.js\"\n\n//Testing Utilities\nexport {\n createMockContext,\n createMockUser,\n createAuthenticatedContext,\n mockDatabase,\n flushPromises,\n assertions,\n executeRoute,\n type BaseContext,\n type AuthenticatedContext,\n type RouterContext,\n type RouterMiddleware,\n type RouterLayer,\n type RouterLike,\n type SequelizeModelMethods,\n} from \"./lib/testing/testHelpers.js\"\n\n// Testing Fixtures\nexport {\n TEST_UUIDS,\n TEST_DATES,\n TEST_DATA,\n isValidUUID,\n generateTestEmail,\n createTestUser,\n createTestCoach,\n createTestHeadCoach,\n createTestFinanceUser,\n createTestAdmin,\n createTestClient,\n wait,\n freezeTime,\n testAssertions,\n mockResponses,\n isObject,\n isArray,\n} from \"./lib/testing/testFixtures.js\"\n\n//Config\nexport {\n ConfigValidator,\n BaseConfigSchema,\n CommonSchemas,\n createConfig,\n ConfigurationError,\n type BaseConfig\n} from \"./lib/config/ConfigValidator.js\"\n\n//Errors\nexport {\n AppError,\n ValidationError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n UnprocessableEntityError,\n RateLimitError,\n InternalServerError,\n ServiceUnavailableError,\n DatabaseError,\n ExternalAPIError,\n isAppError,\n isOperationalError,\n toAppError\n} from \"./lib/Errors/AppError.js\"\n\n//Middlewares\nexport {\n ErrorMiddleware,\n} from \"./lib/middlewares/ErrorMiddleware.js\"\nexport { validate, type ValidationConfig } from \"./lib/middlewares/ValidationMiddleware.js\";\n\n//Controllers\nexport { BaseController, type RouteConfig } from \"./lib/controllers/BaseController.js\";\n\n\nexport {RedisClient} from \"./lib/classes/Redis.js\"\nexport {DatabaseClient, type DatabaseConfig} from \"./lib/classes/Database.js\""],"names":["EmailClient","PushNotificationClient","FirebasePushNotificationClient","AuthenticationUtil","NotificationsUtil","NotificationClient","Log","SecretManager","initializeSentry","isSentryEnabled","scrubObject","captureRequestBody","extractUserContext","buildRequestContext","buildResponseContext","reportErrorToSentry","reportMessageToSentry","createMockContext","createMockUser","createAuthenticatedContext","mockDatabase","flushPromises","assertions","executeRoute","TEST_UUIDS","TEST_DATES","TEST_DATA","isValidUUID","generateTestEmail","createTestUser","createTestCoach","createTestHeadCoach","createTestFinanceUser","createTestAdmin","createTestClient","wait","freezeTime","testAssertions","mockResponses","isObject","isArray","ConfigValidator","BaseConfigSchema","CommonSchemas","createConfig","ConfigurationError","AppError","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","ErrorMiddleware","validate","BaseController","RedisClient","DatabaseClient"],"mappings":"AAAA,YAAY;AACZ,cAAc,oCAAoC;AAClD,cAAc,qCAAqC;AACnD,cAAc,oCAAoC;AAClD,cAAc,iCAAiC;AAC/C,cAAc,yCAAyC;AAEvD,gDAAgD;AAChD,cAAc,iBAAyB;AAEvC,SAAS;AACT,SAASA,WAAW,QAAQ,+BAA8B;AAC1D,SAASC,sBAAsB,QAAQ,0CAAyC;AAChF,SAASC,8BAA8B,QAAQ,kDAAiD;AAQhG,OAAO;AACP,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,GAAG,QAAO,wBAAuB;AACzC,SAAQC,aAAa,QAAO,+BAA8B;AAC1D,SACEC,gBAAgB,EAChBC,eAAe,EACfC,WAAW,EACXC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,EACnBC,oBAAoB,EACpBC,mBAAmB,EACnBC,qBAAqB,QAGhB,4BAA2B;AAElC,mBAAmB;AACnB,SACEC,iBAAiB,EACjBC,cAAc,EACdC,0BAA0B,EAC1BC,YAAY,EACZC,aAAa,EACbC,UAAU,EACVC,YAAY,QAQP,+BAA8B;AAErC,mBAAmB;AACnB,SACEC,UAAU,EACVC,UAAU,EACVC,SAAS,EACTC,WAAW,EACXC,iBAAiB,EACjBC,cAAc,EACdC,eAAe,EACfC,mBAAmB,EACnBC,qBAAqB,EACrBC,eAAe,EACfC,gBAAgB,EAChBC,IAAI,EACJC,UAAU,EACVC,cAAc,EACdC,aAAa,EACbC,QAAQ,EACRC,OAAO,QACF,gCAA+B;AAEtC,QAAQ;AACR,SACEC,eAAe,EACfC,gBAAgB,EAChBC,aAAa,EACbC,YAAY,EACZC,kBAAkB,QAEb,kCAAiC;AAExC,QAAQ;AACR,SACEC,QAAQ,EACRC,eAAe,EACfC,mBAAmB,EACnBC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,wBAAwB,EACxBC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,EACvBC,aAAa,EACbC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,UAAU,QACL,2BAA0B;AAEjC,aAAa;AACb,SACEC,eAAe,QACV,uCAAsC;AAC7C,SAASC,QAAQ,QAA+B,4CAA4C;AAE5F,aAAa;AACb,SAASC,cAAc,QAA0B,sCAAsC;AAGvF,SAAQC,WAAW,QAAO,yBAAwB;AAClD,SAAQC,cAAc,QAA4B,4BAA2B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models - Export all models and model arrays\nexport * from \"./lib/dbmodels/index.js\"\n\n//Clients\nexport { EmailClient } from \"./lib/clients/EmailClient.js\"\nexport { ImagesClient } from \"./lib/clients/ImagesClient.js\"\nexport { MailingClient } from \"./lib/clients/MailingClient.js\"\nexport { PushNotificationClient } from \"./lib/clients/PushNotificationClient.js\"\nexport { FirebasePushNotificationClient } from \"./lib/clients/FirebasePushNotificationClient.js\"\n\n//Client Types (namespace imports)\nexport * as EmailTypes from \"./lib/clients/types/email.types.js\"\nexport * as ImagesTypes from \"./lib/clients/types/images.types.js\"\nexport * as MailingTypes from \"./lib/clients/types/mailing.types.js\"\nexport type { NotificationPayload } from \"./lib/clients/PushNotificationClient.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\nexport {SecretManager} from \"./lib/utils/SecretManager.js\"\nexport {\n initializeSentry,\n isSentryEnabled,\n scrubObject,\n captureRequestBody,\n extractUserContext,\n buildRequestContext,\n buildResponseContext,\n reportErrorToSentry,\n reportMessageToSentry,\n type ErrorReportOptions,\n type SeverityLevel,\n} from \"./lib/utils/SentryUtil.js\"\n\n//Testing Utilities\nexport {\n createMockContext,\n createMockUser,\n createAuthenticatedContext,\n mockDatabase,\n flushPromises,\n assertions,\n executeRoute,\n type BaseContext,\n type AuthenticatedContext,\n type RouterContext,\n type RouterMiddleware,\n type RouterLayer,\n type RouterLike,\n type SequelizeModelMethods,\n} from \"./lib/testing/testHelpers.js\"\n\n// Testing Fixtures\nexport {\n TEST_UUIDS,\n TEST_DATES,\n TEST_DATA,\n isValidUUID,\n generateTestEmail,\n createTestUser,\n createTestCoach,\n createTestHeadCoach,\n createTestFinanceUser,\n createTestAdmin,\n createTestClient,\n wait,\n freezeTime,\n testAssertions,\n mockResponses,\n isObject,\n isArray,\n} from \"./lib/testing/testFixtures.js\"\n\n//Config\nexport {\n ConfigValidator,\n BaseConfigSchema,\n CommonSchemas,\n createConfig,\n ConfigurationError,\n type BaseConfig\n} from \"./lib/config/ConfigValidator.js\"\n\n//Errors\nexport {\n AppError,\n ValidationError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n UnprocessableEntityError,\n RateLimitError,\n InternalServerError,\n ServiceUnavailableError,\n DatabaseError,\n ExternalAPIError,\n isAppError,\n isOperationalError,\n toAppError\n} from \"./lib/Errors/AppError.js\"\n\n//Middlewares\nexport {\n ErrorMiddleware,\n} from \"./lib/middlewares/ErrorMiddleware.js\"\nexport { validate, type ValidationConfig } from \"./lib/middlewares/ValidationMiddleware.js\";\n\n//Controllers\nexport { BaseController, type RouteConfig } from \"./lib/controllers/BaseController.js\";\n\n\nexport {RedisClient} from \"./lib/classes/Redis.js\"\nexport {DatabaseClient, type DatabaseConfig} from \"./lib/classes/Database.js\""],"names":["EmailClient","ImagesClient","MailingClient","PushNotificationClient","FirebasePushNotificationClient","EmailTypes","ImagesTypes","MailingTypes","AuthenticationUtil","NotificationsUtil","NotificationClient","Log","SecretManager","initializeSentry","isSentryEnabled","scrubObject","captureRequestBody","extractUserContext","buildRequestContext","buildResponseContext","reportErrorToSentry","reportMessageToSentry","createMockContext","createMockUser","createAuthenticatedContext","mockDatabase","flushPromises","assertions","executeRoute","TEST_UUIDS","TEST_DATES","TEST_DATA","isValidUUID","generateTestEmail","createTestUser","createTestCoach","createTestHeadCoach","createTestFinanceUser","createTestAdmin","createTestClient","wait","freezeTime","testAssertions","mockResponses","isObject","isArray","ConfigValidator","BaseConfigSchema","CommonSchemas","createConfig","ConfigurationError","AppError","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","ErrorMiddleware","validate","BaseController","RedisClient","DatabaseClient"],"mappings":"AAAA,YAAY;AACZ,cAAc,oCAAoC;AAClD,cAAc,qCAAqC;AACnD,cAAc,oCAAoC;AAClD,cAAc,iCAAiC;AAC/C,cAAc,yCAAyC;AAEvD,gDAAgD;AAChD,cAAc,iBAAyB;AAEvC,SAAS;AACT,SAASA,WAAW,QAAQ,+BAA8B;AAC1D,SAASC,YAAY,QAAQ,gCAA+B;AAC5D,SAASC,aAAa,QAAQ,iCAAgC;AAC9D,SAASC,sBAAsB,QAAQ,0CAAyC;AAChF,SAASC,8BAA8B,QAAQ,kDAAiD;AAEhG,kCAAkC;AAClC,OAAO,KAAKC,UAAU,MAAM,qCAAoC;AAChE,OAAO,KAAKC,WAAW,MAAM,sCAAqC;AAClE,OAAO,KAAKC,YAAY,MAAM,uCAAsC;AAGpE,OAAO;AACP,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,GAAG,QAAO,wBAAuB;AACzC,SAAQC,aAAa,QAAO,+BAA8B;AAC1D,SACEC,gBAAgB,EAChBC,eAAe,EACfC,WAAW,EACXC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,EACnBC,oBAAoB,EACpBC,mBAAmB,EACnBC,qBAAqB,QAGhB,4BAA2B;AAElC,mBAAmB;AACnB,SACEC,iBAAiB,EACjBC,cAAc,EACdC,0BAA0B,EAC1BC,YAAY,EACZC,aAAa,EACbC,UAAU,EACVC,YAAY,QAQP,+BAA8B;AAErC,mBAAmB;AACnB,SACEC,UAAU,EACVC,UAAU,EACVC,SAAS,EACTC,WAAW,EACXC,iBAAiB,EACjBC,cAAc,EACdC,eAAe,EACfC,mBAAmB,EACnBC,qBAAqB,EACrBC,eAAe,EACfC,gBAAgB,EAChBC,IAAI,EACJC,UAAU,EACVC,cAAc,EACdC,aAAa,EACbC,QAAQ,EACRC,OAAO,QACF,gCAA+B;AAEtC,QAAQ;AACR,SACEC,eAAe,EACfC,gBAAgB,EAChBC,aAAa,EACbC,YAAY,EACZC,kBAAkB,QAEb,kCAAiC;AAExC,QAAQ;AACR,SACEC,QAAQ,EACRC,eAAe,EACfC,mBAAmB,EACnBC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,wBAAwB,EACxBC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,EACvBC,aAAa,EACbC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,UAAU,QACL,2BAA0B;AAEjC,aAAa;AACb,SACEC,eAAe,QACV,uCAAsC;AAC7C,SAASC,QAAQ,QAA+B,4CAA4C;AAE5F,aAAa;AACb,SAASC,cAAc,QAA0B,sCAAsC;AAGvF,SAAQC,WAAW,QAAO,yBAAwB;AAClD,SAAQC,cAAc,QAA4B,4BAA2B"}
@@ -1,44 +1,25 @@
1
- export interface SendTemplateEmailRequest {
2
- to: string | string[];
3
- templateAlias: string | number;
4
- templateModel: Record<string, any>;
5
- cc?: string | string[];
6
- bcc?: string | string[];
7
- replyTo?: string;
8
- tag?: string;
9
- metadata?: Record<string, string>;
10
- trackOpens?: boolean;
11
- trackLinks?: "None" | "HtmlAndText" | "HtmlOnly" | "TextOnly";
12
- }
13
- export interface BatchTemplateEmailRequest {
14
- emails: Array<{
15
- to: string;
16
- templateAlias: string | number;
17
- templateModel: Record<string, any>;
18
- tag?: string;
19
- metadata?: Record<string, string>;
20
- }>;
21
- }
22
- export interface EmailResponse {
23
- messageId: string;
24
- to: string;
25
- submittedAt: string;
26
- errorCode?: number;
27
- message?: string;
28
- }
1
+ import type * as t from "./types/email.types.js";
29
2
  export declare class EmailClient {
30
3
  private static instance;
31
4
  private client;
32
5
  private config;
33
6
  private logger;
34
- private constructor();
7
+ constructor(config: t.Config);
8
+ /** @deprecated Use `new EmailClient(config)` instead. Still used in 90dc-coaching (WebhookService). */
35
9
  static getInstance(): EmailClient;
10
+ /** @deprecated Use `new EmailClient(config)` instead. Still used in 90dc-coaching (WebhookService). */
36
11
  static resetInstance(): void;
37
- sendWithTemplate(request: SendTemplateEmailRequest): Promise<EmailResponse>;
38
- sendBatchWithTemplate(request: BatchTemplateEmailRequest): Promise<EmailResponse[]>;
39
- sendPasswordReset(to: string, resetToken: string, userName: string): Promise<EmailResponse>;
40
- sendEmailConfirmation(to: string, confirmToken: string, userName: string): Promise<EmailResponse>;
41
- sendWelcome(to: string, userName: string): Promise<EmailResponse>;
12
+ sendWithTemplate(request: t.SendTemplateEmailRequest): Promise<t.EmailResponse>;
13
+ /** Currently unused across all services. */
14
+ sendBatchWithTemplate(request: t.BatchTemplateEmailRequest): Promise<t.EmailResponse[]>;
15
+ /** Currently unused across all services. Duplicates MailingClient methods. */
16
+ sendPasswordReset(to: string, resetToken: string, userName: string): Promise<t.EmailResponse>;
17
+ /** Currently unused across all services. Duplicates MailingClient methods. */
18
+ sendEmailConfirmation(to: string, confirmToken: string, userName: string): Promise<t.EmailResponse>;
19
+ /** Currently unused across all services. Duplicates MailingClient methods. */
20
+ sendWelcome(to: string, userName: string): Promise<t.EmailResponse>;
21
+ /** Currently unused. Added for MailingClient.sendExportsEmail() (plain text email via Postmark /email endpoint). */
22
+ sendEmail(request: t.SendEmailRequest): Promise<t.EmailResponse>;
42
23
  private handleError;
43
24
  }
44
25
  //# sourceMappingURL=EmailClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmailClient.d.ts","sourceRoot":"","sources":["../../../src/lib/clients/EmailClient.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,UAAU,CAAC;CAC/D;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;QAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACnC,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IACrC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,MAAM,CAA4C;IAE1D,OAAO;WAaO,WAAW,IAAI,WAAW;WAQ1B,aAAa,IAAI,IAAI;IAItB,gBAAgB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IAyC3E,qBAAqB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAsCnF,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAa3F,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAajG,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS9E,OAAO,CAAC,WAAW;CAwBpB"}
1
+ {"version":3,"file":"EmailClient.d.ts","sourceRoot":"","sources":["../../../src/lib/clients/EmailClient.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,CAAC,MAAM,wBAAwB,CAAC;AAEjD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IACrC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAA4C;gBAG9C,MAAM,EAAE,CAAC,CAAC,MAAM;IAa1B,uGAAuG;WAC3F,WAAW,IAAI,WAAW;IAQxC,uGAAuG;WACzF,aAAa,IAAI,IAAI;IAItB,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,wBAAwB,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;IAyC5F,4CAA4C;IAC/B,qBAAqB,CAAC,OAAO,EAAE,CAAC,CAAC,yBAAyB,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAsCpG,8EAA8E;IACjE,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;IAa1G,8EAA8E;IACjE,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;IAahH,8EAA8E;IACjE,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;IAShF,oHAAoH;IACvG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,gBAAgB,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;IAuC7E,OAAO,CAAC,WAAW;CAwBpB"}
@@ -19,14 +19,14 @@ export class EmailClient {
19
19
  }
20
20
  });
21
21
  }
22
- static getInstance() {
22
+ /** @deprecated Use `new EmailClient(config)` instead. Still used in 90dc-coaching (WebhookService). */ static getInstance() {
23
23
  if (!EmailClient.instance) {
24
24
  const config = CommonSchemas.postmark.parse(process.env);
25
25
  EmailClient.instance = new EmailClient(config);
26
26
  }
27
27
  return EmailClient.instance;
28
28
  }
29
- static resetInstance() {
29
+ /** @deprecated Use `new EmailClient(config)` instead. Still used in 90dc-coaching (WebhookService). */ static resetInstance() {
30
30
  EmailClient.instance = undefined;
31
31
  }
32
32
  async sendWithTemplate(request) {
@@ -65,7 +65,7 @@ export class EmailClient {
65
65
  this.handleError(error, "sendWithTemplate");
66
66
  }
67
67
  }
68
- async sendBatchWithTemplate(request) {
68
+ /** Currently unused across all services. */ async sendBatchWithTemplate(request) {
69
69
  try {
70
70
  this.logger.info("Sending batch templated emails", {
71
71
  count: request.emails.length
@@ -74,7 +74,7 @@ export class EmailClient {
74
74
  Messages: request.emails.map((email)=>({
75
75
  From: this.config.POSTMARK_FROM_EMAIL,
76
76
  To: email.to,
77
- TemplateAlies: email.templateAlias,
77
+ TemplateAlias: email.templateAlias,
78
78
  TemplateModel: email.templateModel,
79
79
  ReplyTo: this.config.POSTMARK_REPLY_TO_EMAIL,
80
80
  Tag: email.tag,
@@ -98,7 +98,7 @@ export class EmailClient {
98
98
  this.handleError(error, "sendBatchWithTemplate");
99
99
  }
100
100
  }
101
- async sendPasswordReset(to, resetToken, userName) {
101
+ /** Currently unused across all services. Duplicates MailingClient methods. */ async sendPasswordReset(to, resetToken, userName) {
102
102
  return this.sendWithTemplate({
103
103
  to,
104
104
  templateAlias: "password-reset",
@@ -110,7 +110,7 @@ export class EmailClient {
110
110
  tag: "password-reset"
111
111
  });
112
112
  }
113
- async sendEmailConfirmation(to, confirmToken, userName) {
113
+ /** Currently unused across all services. Duplicates MailingClient methods. */ async sendEmailConfirmation(to, confirmToken, userName) {
114
114
  return this.sendWithTemplate({
115
115
  to,
116
116
  templateAlias: "email-confirmation",
@@ -122,7 +122,7 @@ export class EmailClient {
122
122
  tag: "email-confirmation"
123
123
  });
124
124
  }
125
- async sendWelcome(to, userName) {
125
+ /** Currently unused across all services. Duplicates MailingClient methods. */ async sendWelcome(to, userName) {
126
126
  return this.sendWithTemplate({
127
127
  to,
128
128
  templateAlias: "welcome",
@@ -132,6 +132,40 @@ export class EmailClient {
132
132
  tag: "welcome"
133
133
  });
134
134
  }
135
+ /** Currently unused. Added for MailingClient.sendExportsEmail() (plain text email via Postmark /email endpoint). */ async sendEmail(request) {
136
+ try {
137
+ this.logger.info("Sending plain email", {
138
+ to: request.to,
139
+ subject: request.subject
140
+ });
141
+ const payload = {
142
+ From: this.config.POSTMARK_FROM_EMAIL,
143
+ To: request.to,
144
+ Subject: request.subject,
145
+ TextBody: request.textBody,
146
+ HtmlBody: request.htmlBody,
147
+ ReplyTo: request.replyTo || this.config.POSTMARK_REPLY_TO_EMAIL,
148
+ Tag: request.tag,
149
+ Metadata: request.metadata,
150
+ TrackOpens: true,
151
+ TrackLinks: "HtmlAndText"
152
+ };
153
+ const response = await this.client.post("/email", payload);
154
+ this.logger.info("Plain email sent successfully", {
155
+ messageId: response.data.MessageID,
156
+ to: response.data.To
157
+ });
158
+ return {
159
+ messageId: response.data.MessageID,
160
+ to: response.data.To,
161
+ submittedAt: response.data.SubmittedAt,
162
+ errorCode: response.data.ErrorCode,
163
+ message: response.data.Message
164
+ };
165
+ } catch (error) {
166
+ this.handleError(error, "sendEmail");
167
+ }
168
+ }
135
169
  handleError(error, method) {
136
170
  if (axios.isAxiosError(error)) {
137
171
  const status = error.response?.status;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/clients/EmailClient.ts"],"sourcesContent":["import axios, { type AxiosInstance } from \"axios\";\nimport { z } from \"zod\";\nimport { CommonSchemas } from \"../config/ConfigValidator.js\";\nimport { ExternalAPIError } from \"../Errors/AppError.js\";\nimport { Log } from \"../utils/Logger.js\";\n\ntype PostmarkConfig = z.infer<typeof CommonSchemas.postmark>;\n\nexport interface SendTemplateEmailRequest {\n to: string | string[];\n templateAlias: string | number;\n templateModel: Record<string, any>;\n cc?: string | string[];\n bcc?: string | string[];\n replyTo?: string;\n tag?: string;\n metadata?: Record<string, string>;\n trackOpens?: boolean;\n trackLinks?: \"None\" | \"HtmlAndText\" | \"HtmlOnly\" | \"TextOnly\";\n}\n\nexport interface BatchTemplateEmailRequest {\n emails: Array<{\n to: string;\n templateAlias: string | number;\n templateModel: Record<string, any>;\n tag?: string;\n metadata?: Record<string, string>;\n }>;\n}\n\nexport interface EmailResponse {\n messageId: string;\n to: string;\n submittedAt: string;\n errorCode?: number;\n message?: string;\n}\n\nexport class EmailClient {\n private static instance: EmailClient;\n private client: AxiosInstance;\n private config: PostmarkConfig;\n private logger = Log.getInstance().extend(\"email-client\");\n\n private constructor(config: PostmarkConfig) {\n this.config = config;\n this.client = axios.create({\n baseURL: \"https://api.postmarkapp.com\",\n timeout: config.POSTMARK_TIMEOUT_MS,\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Postmark-Server-Token\": config.POSTMARK_API_KEY,\n },\n });\n }\n\n public static getInstance(): EmailClient {\n if (!EmailClient.instance) {\n const config = CommonSchemas.postmark.parse(process.env);\n EmailClient.instance = new EmailClient(config);\n }\n return EmailClient.instance;\n }\n\n public static resetInstance(): void {\n EmailClient.instance = undefined as any;\n }\n\n public async sendWithTemplate(request: SendTemplateEmailRequest): Promise<EmailResponse> {\n try {\n this.logger.info(\"Sending templated email\", {\n to: request.to,\n templateAlias: request.templateAlias,\n tag: request.tag,\n });\n\n const payload = {\n From: this.config.POSTMARK_FROM_EMAIL,\n To: Array.isArray(request.to) ? request.to.join(\",\") : request.to,\n TemplateAlias: request.templateAlias,\n TemplateModel: request.templateModel,\n Cc: request.cc ? (Array.isArray(request.cc) ? request.cc.join(\",\") : request.cc) : undefined,\n Bcc: request.bcc ? (Array.isArray(request.bcc) ? request.bcc.join(\",\") : request.bcc) : undefined,\n ReplyTo: request.replyTo || this.config.POSTMARK_REPLY_TO_EMAIL,\n Tag: request.tag,\n Metadata: request.metadata,\n TrackOpens: request.trackOpens ?? true,\n TrackLinks: request.trackLinks ?? \"HtmlAndText\",\n };\n\n const response = await this.client.post(\"/email/withTemplate\", payload);\n\n this.logger.info(\"Email sent successfully\", {\n messageId: response.data.MessageID,\n to: response.data.To,\n });\n\n return {\n messageId: response.data.MessageID,\n to: response.data.To,\n submittedAt: response.data.SubmittedAt,\n errorCode: response.data.ErrorCode,\n message: response.data.Message,\n };\n } catch (error) {\n this.handleError(error, \"sendWithTemplate\");\n }\n }\n\n public async sendBatchWithTemplate(request: BatchTemplateEmailRequest): Promise<EmailResponse[]> {\n try {\n this.logger.info(\"Sending batch templated emails\", {\n count: request.emails.length,\n });\n\n const payload = {\n Messages: request.emails.map((email) => ({\n From: this.config.POSTMARK_FROM_EMAIL,\n To: email.to,\n TemplateAlies: email.templateAlias,\n TemplateModel: email.templateModel,\n ReplyTo: this.config.POSTMARK_REPLY_TO_EMAIL,\n Tag: email.tag,\n Metadata: email.metadata,\n TrackOpens: true,\n TrackLinks: \"HtmlAndText\",\n })),\n };\n\n const response = await this.client.post(\"/email/batchWithTemplates\", payload);\n\n this.logger.info(\"Batch emails sent\", {\n count: response.data.length,\n });\n\n return response.data.map((item: any) => ({\n messageId: item.MessageID,\n to: item.To,\n submittedAt: item.SubmittedAt,\n errorCode: item.ErrorCode,\n message: item.Message,\n }));\n } catch (error) {\n this.handleError(error, \"sendBatchWithTemplate\");\n }\n }\n\n public async sendPasswordReset(to: string, resetToken: string, userName: string): Promise<EmailResponse> {\n return this.sendWithTemplate({\n to,\n templateAlias: \"password-reset\",\n templateModel: {\n userName,\n resetToken,\n resetLink: `https://yourapp.com/reset/${resetToken}`,\n },\n tag: \"password-reset\",\n });\n }\n\n public async sendEmailConfirmation(to: string, confirmToken: string, userName: string): Promise<EmailResponse> {\n return this.sendWithTemplate({\n to,\n templateAlias: \"email-confirmation\",\n templateModel: {\n userName,\n confirmToken,\n confirmLink: `https://yourapp.com/confirm/${confirmToken}`,\n },\n tag: \"email-confirmation\",\n });\n }\n\n public async sendWelcome(to: string, userName: string): Promise<EmailResponse> {\n return this.sendWithTemplate({\n to,\n templateAlias: \"welcome\",\n templateModel: { userName },\n tag: \"welcome\",\n });\n }\n\n private handleError(error: unknown, method: string): never {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const data = error.response?.data;\n\n this.logger.error(`Postmark API error in ${method}`, {\n status,\n errorCode: data?.ErrorCode,\n message: data?.Message,\n requestUrl: error.config?.url,\n });\n\n throw new ExternalAPIError(\n `Postmark API error: ${data?.Message || error.message}`,\n `Service: Postmark, Method: ${method}, Status: ${status}, ErrorCode: ${data?.ErrorCode}`\n );\n }\n\n this.logger.error(`Unexpected error in ${method}`, { error });\n throw new ExternalAPIError(\n `Email sending failed: ${error}`,\n `Service: Postmark, Method: ${method}`\n );\n }\n}\n"],"names":["axios","CommonSchemas","ExternalAPIError","Log","EmailClient","instance","client","config","logger","getInstance","extend","create","baseURL","timeout","POSTMARK_TIMEOUT_MS","headers","Accept","POSTMARK_API_KEY","postmark","parse","process","env","resetInstance","undefined","sendWithTemplate","request","info","to","templateAlias","tag","payload","From","POSTMARK_FROM_EMAIL","To","Array","isArray","join","TemplateAlias","TemplateModel","templateModel","Cc","cc","Bcc","bcc","ReplyTo","replyTo","POSTMARK_REPLY_TO_EMAIL","Tag","Metadata","metadata","TrackOpens","trackOpens","TrackLinks","trackLinks","response","post","messageId","data","MessageID","submittedAt","SubmittedAt","errorCode","ErrorCode","message","Message","error","handleError","sendBatchWithTemplate","count","emails","length","Messages","map","email","TemplateAlies","item","sendPasswordReset","resetToken","userName","resetLink","sendEmailConfirmation","confirmToken","confirmLink","sendWelcome","method","isAxiosError","status","requestUrl","url"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/lib/clients/EmailClient.ts"],"sourcesContent":["import axios, { type AxiosInstance } from \"axios\";\nimport { CommonSchemas } from \"../config/ConfigValidator.js\";\nimport { ExternalAPIError } from \"../Errors/AppError.js\";\nimport { Log } from \"../utils/Logger.js\";\nimport type * as t from \"./types/email.types.js\";\n\nexport class EmailClient {\n private static instance: EmailClient;\n private client: AxiosInstance;\n private config: t.Config;\n private logger = Log.getInstance().extend(\"email-client\");\n\n\n constructor(config: t.Config) {\n this.config = config;\n this.client = axios.create({\n baseURL: \"https://api.postmarkapp.com\",\n timeout: config.POSTMARK_TIMEOUT_MS,\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Postmark-Server-Token\": config.POSTMARK_API_KEY,\n },\n });\n }\n\n /** @deprecated Use `new EmailClient(config)` instead. Still used in 90dc-coaching (WebhookService). */\n public static getInstance(): EmailClient {\n if (!EmailClient.instance) {\n const config = CommonSchemas.postmark.parse(process.env);\n EmailClient.instance = new EmailClient(config);\n }\n return EmailClient.instance;\n }\n\n /** @deprecated Use `new EmailClient(config)` instead. Still used in 90dc-coaching (WebhookService). */\n public static resetInstance(): void {\n EmailClient.instance = undefined as any;\n }\n\n public async sendWithTemplate(request: t.SendTemplateEmailRequest): Promise<t.EmailResponse> {\n try {\n this.logger.info(\"Sending templated email\", {\n to: request.to,\n templateAlias: request.templateAlias,\n tag: request.tag,\n });\n\n const payload = {\n From: this.config.POSTMARK_FROM_EMAIL,\n To: Array.isArray(request.to) ? request.to.join(\",\") : request.to,\n TemplateAlias: request.templateAlias,\n TemplateModel: request.templateModel,\n Cc: request.cc ? (Array.isArray(request.cc) ? request.cc.join(\",\") : request.cc) : undefined,\n Bcc: request.bcc ? (Array.isArray(request.bcc) ? request.bcc.join(\",\") : request.bcc) : undefined,\n ReplyTo: request.replyTo || this.config.POSTMARK_REPLY_TO_EMAIL,\n Tag: request.tag,\n Metadata: request.metadata,\n TrackOpens: request.trackOpens ?? true,\n TrackLinks: request.trackLinks ?? \"HtmlAndText\",\n };\n\n const response = await this.client.post(\"/email/withTemplate\", payload);\n\n this.logger.info(\"Email sent successfully\", {\n messageId: response.data.MessageID,\n to: response.data.To,\n });\n\n return {\n messageId: response.data.MessageID,\n to: response.data.To,\n submittedAt: response.data.SubmittedAt,\n errorCode: response.data.ErrorCode,\n message: response.data.Message,\n };\n } catch (error) {\n this.handleError(error, \"sendWithTemplate\");\n }\n }\n\n /** Currently unused across all services. */\n public async sendBatchWithTemplate(request: t.BatchTemplateEmailRequest): Promise<t.EmailResponse[]> {\n try {\n this.logger.info(\"Sending batch templated emails\", {\n count: request.emails.length,\n });\n\n const payload = {\n Messages: request.emails.map((email) => ({\n From: this.config.POSTMARK_FROM_EMAIL,\n To: email.to,\n TemplateAlias: email.templateAlias,\n TemplateModel: email.templateModel,\n ReplyTo: this.config.POSTMARK_REPLY_TO_EMAIL,\n Tag: email.tag,\n Metadata: email.metadata,\n TrackOpens: true,\n TrackLinks: \"HtmlAndText\",\n })),\n };\n\n const response = await this.client.post(\"/email/batchWithTemplates\", payload);\n\n this.logger.info(\"Batch emails sent\", {\n count: response.data.length,\n });\n\n return response.data.map((item: any) => ({\n messageId: item.MessageID,\n to: item.To,\n submittedAt: item.SubmittedAt,\n errorCode: item.ErrorCode,\n message: item.Message,\n }));\n } catch (error) {\n this.handleError(error, \"sendBatchWithTemplate\");\n }\n }\n\n /** Currently unused across all services. Duplicates MailingClient methods. */\n public async sendPasswordReset(to: string, resetToken: string, userName: string): Promise<t.EmailResponse> {\n return this.sendWithTemplate({\n to,\n templateAlias: \"password-reset\",\n templateModel: {\n userName,\n resetToken,\n resetLink: `https://yourapp.com/reset/${resetToken}`,\n },\n tag: \"password-reset\",\n });\n }\n\n /** Currently unused across all services. Duplicates MailingClient methods. */\n public async sendEmailConfirmation(to: string, confirmToken: string, userName: string): Promise<t.EmailResponse> {\n return this.sendWithTemplate({\n to,\n templateAlias: \"email-confirmation\",\n templateModel: {\n userName,\n confirmToken,\n confirmLink: `https://yourapp.com/confirm/${confirmToken}`,\n },\n tag: \"email-confirmation\",\n });\n }\n\n /** Currently unused across all services. Duplicates MailingClient methods. */\n public async sendWelcome(to: string, userName: string): Promise<t.EmailResponse> {\n return this.sendWithTemplate({\n to,\n templateAlias: \"welcome\",\n templateModel: { userName },\n tag: \"welcome\",\n });\n }\n\n /** Currently unused. Added for MailingClient.sendExportsEmail() (plain text email via Postmark /email endpoint). */\n public async sendEmail(request: t.SendEmailRequest): Promise<t.EmailResponse> {\n try {\n this.logger.info(\"Sending plain email\", {\n to: request.to,\n subject: request.subject,\n });\n\n const payload = {\n From: this.config.POSTMARK_FROM_EMAIL,\n To: request.to,\n Subject: request.subject,\n TextBody: request.textBody,\n HtmlBody: request.htmlBody,\n ReplyTo: request.replyTo || this.config.POSTMARK_REPLY_TO_EMAIL,\n Tag: request.tag,\n Metadata: request.metadata,\n TrackOpens: true,\n TrackLinks: \"HtmlAndText\",\n };\n\n const response = await this.client.post(\"/email\", payload);\n\n this.logger.info(\"Plain email sent successfully\", {\n messageId: response.data.MessageID,\n to: response.data.To,\n });\n\n return {\n messageId: response.data.MessageID,\n to: response.data.To,\n submittedAt: response.data.SubmittedAt,\n errorCode: response.data.ErrorCode,\n message: response.data.Message,\n };\n } catch (error) {\n this.handleError(error, \"sendEmail\");\n }\n }\n\n private handleError(error: unknown, method: string): never {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const data = error.response?.data;\n\n this.logger.error(`Postmark API error in ${method}`, {\n status,\n errorCode: data?.ErrorCode,\n message: data?.Message,\n requestUrl: error.config?.url,\n });\n\n throw new ExternalAPIError(\n `Postmark API error: ${data?.Message || error.message}`,\n `Service: Postmark, Method: ${method}, Status: ${status}, ErrorCode: ${data?.ErrorCode}`\n );\n }\n\n this.logger.error(`Unexpected error in ${method}`, { error });\n throw new ExternalAPIError(\n `Email sending failed: ${error}`,\n `Service: Postmark, Method: ${method}`\n );\n }\n}\n"],"names":["axios","CommonSchemas","ExternalAPIError","Log","EmailClient","instance","client","config","logger","getInstance","extend","create","baseURL","timeout","POSTMARK_TIMEOUT_MS","headers","Accept","POSTMARK_API_KEY","postmark","parse","process","env","resetInstance","undefined","sendWithTemplate","request","info","to","templateAlias","tag","payload","From","POSTMARK_FROM_EMAIL","To","Array","isArray","join","TemplateAlias","TemplateModel","templateModel","Cc","cc","Bcc","bcc","ReplyTo","replyTo","POSTMARK_REPLY_TO_EMAIL","Tag","Metadata","metadata","TrackOpens","trackOpens","TrackLinks","trackLinks","response","post","messageId","data","MessageID","submittedAt","SubmittedAt","errorCode","ErrorCode","message","Message","error","handleError","sendBatchWithTemplate","count","emails","length","Messages","map","email","item","sendPasswordReset","resetToken","userName","resetLink","sendEmailConfirmation","confirmToken","confirmLink","sendWelcome","sendEmail","subject","Subject","TextBody","textBody","HtmlBody","htmlBody","method","isAxiosError","status","requestUrl","url"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type * as t from "./types/images.types.js";
2
+ export declare class ImagesClient {
3
+ private bucket;
4
+ private logger;
5
+ constructor(config: t.Config);
6
+ saveImage(base64: string, name: string): Promise<void>;
7
+ getImage(name: string): Promise<string | undefined>;
8
+ saveAvatar(userUuid: string, base64: string): Promise<void>;
9
+ getAvatar(userUuid: string): Promise<string | undefined>;
10
+ saveProgressPhoto(userUuid: string, day: number, programId: string, base64: string): Promise<void>;
11
+ getProgressPhotos(userUuid: string, programId: string): Promise<t.ProgressPhoto[]>;
12
+ saveRecipePhotos(input: t.SaveRecipePhotosInput): Promise<void>;
13
+ getRecipePhotos(recipeUuid: string): Promise<t.RecipePhotos | undefined>;
14
+ private base64ToBuffer;
15
+ private handleError;
16
+ }
17
+ //# sourceMappingURL=ImagesClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImagesClient.d.ts","sourceRoot":"","sources":["../../../src/lib/clients/ImagesClient.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,CAAC,MAAM,yBAAyB,CAAC;AAalD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA6C;gBAE/C,MAAM,EAAE,CAAC,CAAC,MAAM;IAKf,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAkBnD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIxD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAalF,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,GAAG,SAAS,CAAC;IAiBrF,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,WAAW;CAOpB"}
@@ -0,0 +1,116 @@
1
+ import admin from "firebase-admin";
2
+ import { ExternalAPIError } from "../Errors/AppError.js";
3
+ import { Log } from "../utils/Logger.js";
4
+ const PROGRESS_DAYS = [
5
+ 1,
6
+ 30,
7
+ 60,
8
+ 90
9
+ ];
10
+ const RECIPE_PHOTO_TYPES = [
11
+ "ingredients",
12
+ "cover",
13
+ "method"
14
+ ];
15
+ const imageName = {
16
+ avatar: (userUuid)=>`${userUuid}--avatar.png`,
17
+ progress: (userUuid, day, programId)=>`${userUuid}--${day}day--${programId}.png`,
18
+ recipe: (recipeUuid, type)=>`${recipeUuid}--${type}.png`
19
+ };
20
+ export class ImagesClient {
21
+ bucket;
22
+ logger = Log.getInstance().extend("images-client");
23
+ constructor(config){
24
+ const app = config.firebaseApp ?? admin.app();
25
+ this.bucket = app.storage().bucket(config.storageBucket);
26
+ }
27
+ async saveImage(base64, name) {
28
+ try {
29
+ this.logger.info("Saving image", {
30
+ name
31
+ });
32
+ const buffer = this.base64ToBuffer(base64);
33
+ const file = this.bucket.file(name);
34
+ await file.save(buffer, {
35
+ contentType: "image/png"
36
+ });
37
+ this.logger.info("Image saved successfully", {
38
+ name
39
+ });
40
+ } catch (error) {
41
+ this.handleError(error, "saveImage");
42
+ }
43
+ }
44
+ async getImage(name) {
45
+ try {
46
+ this.logger.info("Getting image", {
47
+ name
48
+ });
49
+ const file = this.bucket.file(name);
50
+ const [exists] = await file.exists();
51
+ if (!exists) {
52
+ return undefined;
53
+ }
54
+ const [contents] = await file.download();
55
+ return "data:image/jpeg;base64," + contents.toString("base64");
56
+ } catch (error) {
57
+ this.logger.error(`Failed to get image: ${name}`, {
58
+ error
59
+ });
60
+ return undefined;
61
+ }
62
+ }
63
+ async saveAvatar(userUuid, base64) {
64
+ await this.saveImage(base64, imageName.avatar(userUuid));
65
+ }
66
+ async getAvatar(userUuid) {
67
+ return this.getImage(imageName.avatar(userUuid));
68
+ }
69
+ async saveProgressPhoto(userUuid, day, programId, base64) {
70
+ await this.saveImage(base64, imageName.progress(userUuid, day, programId));
71
+ }
72
+ async getProgressPhotos(userUuid, programId) {
73
+ const photos = [];
74
+ for (const day of PROGRESS_DAYS){
75
+ const base64 = await this.getImage(imageName.progress(userUuid, day, programId));
76
+ if (base64) {
77
+ photos.push({
78
+ day,
79
+ base64
80
+ });
81
+ }
82
+ }
83
+ return photos;
84
+ }
85
+ async saveRecipePhotos(input) {
86
+ await Promise.all([
87
+ this.saveImage(input.ingredientBase64, imageName.recipe(input.recipeUuid, "ingredients")),
88
+ this.saveImage(input.coverBase64, imageName.recipe(input.recipeUuid, "cover")),
89
+ this.saveImage(input.methodBase64, imageName.recipe(input.recipeUuid, "method"))
90
+ ]);
91
+ }
92
+ async getRecipePhotos(recipeUuid) {
93
+ const results = await Promise.all(RECIPE_PHOTO_TYPES.map((type)=>this.getImage(imageName.recipe(recipeUuid, type))));
94
+ if (results.every((r)=>!r)) {
95
+ return undefined;
96
+ }
97
+ // BUG: cover/method swapped — preserved from original ImageController.ts to keep backward compat with frontend
98
+ return {
99
+ ingredientBase64: results[0] ?? "",
100
+ methodBase64: results[1] ?? "",
101
+ coverBase64: results[2] ?? ""
102
+ };
103
+ }
104
+ base64ToBuffer(base64) {
105
+ const data = base64.includes(",") ? base64.split(",")[1] : base64;
106
+ return Buffer.from(data, "base64");
107
+ }
108
+ handleError(error, method) {
109
+ this.logger.error(`Firebase Storage error in ${method}`, {
110
+ error
111
+ });
112
+ throw new ExternalAPIError(`Firebase Storage error: ${error instanceof Error ? error.message : String(error)}`, `Service: Firebase Storage, Method: ${method}`);
113
+ }
114
+ }
115
+
116
+ //# sourceMappingURL=ImagesClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/clients/ImagesClient.ts"],"sourcesContent":["import admin from \"firebase-admin\";\nimport { Bucket } from \"@google-cloud/storage\";\nimport { ExternalAPIError } from \"../Errors/AppError.js\";\nimport { Log } from \"../utils/Logger.js\";\nimport type * as t from \"./types/images.types.js\";\n\nconst PROGRESS_DAYS = [1, 30, 60, 90];\n\ntype RecipePhotoType = \"ingredients\" | \"cover\" | \"method\";\nconst RECIPE_PHOTO_TYPES: RecipePhotoType[] = [\"ingredients\", \"cover\", \"method\"];\n\nconst imageName = {\n avatar: (userUuid: string) => `${userUuid}--avatar.png`,\n progress: (userUuid: string, day: number, programId: string) => `${userUuid}--${day}day--${programId}.png`,\n recipe: (recipeUuid: string, type: RecipePhotoType) => `${recipeUuid}--${type}.png`,\n};\n\nexport class ImagesClient {\n private bucket: Bucket;\n private logger = Log.getInstance().extend(\"images-client\");\n\n constructor(config: t.Config) {\n const app = config.firebaseApp ?? admin.app();\n this.bucket = app.storage().bucket(config.storageBucket);\n }\n\n public async saveImage(base64: string, name: string): Promise<void> {\n try {\n this.logger.info(\"Saving image\", { name });\n\n const buffer = this.base64ToBuffer(base64);\n const file = this.bucket.file(name);\n await file.save(buffer, { contentType: \"image/png\" });\n\n this.logger.info(\"Image saved successfully\", { name });\n } catch (error) {\n this.handleError(error, \"saveImage\");\n }\n }\n\n public async getImage(name: string): Promise<string | undefined> {\n try {\n this.logger.info(\"Getting image\", { name });\n\n const file = this.bucket.file(name);\n const [exists] = await file.exists();\n if (!exists) {\n return undefined;\n }\n\n const [contents] = await file.download();\n return \"data:image/jpeg;base64,\" + contents.toString(\"base64\");\n } catch (error) {\n this.logger.error(`Failed to get image: ${name}`, { error });\n return undefined;\n }\n }\n\n public async saveAvatar(userUuid: string, base64: string): Promise<void> {\n await this.saveImage(base64, imageName.avatar(userUuid));\n }\n\n public async getAvatar(userUuid: string): Promise<string | undefined> {\n return this.getImage(imageName.avatar(userUuid));\n }\n\n public async saveProgressPhoto(userUuid: string, day: number, programId: string, base64: string): Promise<void> {\n await this.saveImage(base64, imageName.progress(userUuid, day, programId));\n }\n\n public async getProgressPhotos(userUuid: string, programId: string): Promise<t.ProgressPhoto[]> {\n const photos: t.ProgressPhoto[] = [];\n\n for (const day of PROGRESS_DAYS) {\n const base64 = await this.getImage(imageName.progress(userUuid, day, programId));\n if (base64) {\n photos.push({ day, base64 });\n }\n }\n\n return photos;\n }\n\n public async saveRecipePhotos(input: t.SaveRecipePhotosInput): Promise<void> {\n await Promise.all([\n this.saveImage(input.ingredientBase64, imageName.recipe(input.recipeUuid, \"ingredients\")),\n this.saveImage(input.coverBase64, imageName.recipe(input.recipeUuid, \"cover\")),\n this.saveImage(input.methodBase64, imageName.recipe(input.recipeUuid, \"method\")),\n ]);\n }\n\n public async getRecipePhotos(recipeUuid: string): Promise<t.RecipePhotos | undefined> {\n const results = await Promise.all(\n RECIPE_PHOTO_TYPES.map((type) => this.getImage(imageName.recipe(recipeUuid, type)))\n );\n\n if (results.every((r) => !r)) {\n return undefined;\n }\n\n // BUG: cover/method swapped — preserved from original ImageController.ts to keep backward compat with frontend\n return {\n ingredientBase64: results[0] ?? \"\",\n methodBase64: results[1] ?? \"\",\n coverBase64: results[2] ?? \"\",\n };\n }\n\n private base64ToBuffer(base64: string): Buffer {\n const data = base64.includes(\",\") ? base64.split(\",\")[1]! : base64;\n return Buffer.from(data, \"base64\");\n }\n\n private handleError(error: unknown, method: string): never {\n this.logger.error(`Firebase Storage error in ${method}`, { error });\n throw new ExternalAPIError(\n `Firebase Storage error: ${error instanceof Error ? error.message : String(error)}`,\n `Service: Firebase Storage, Method: ${method}`\n );\n }\n}\n"],"names":["admin","ExternalAPIError","Log","PROGRESS_DAYS","RECIPE_PHOTO_TYPES","imageName","avatar","userUuid","progress","day","programId","recipe","recipeUuid","type","ImagesClient","bucket","logger","getInstance","extend","config","app","firebaseApp","storage","storageBucket","saveImage","base64","name","info","buffer","base64ToBuffer","file","save","contentType","error","handleError","getImage","exists","undefined","contents","download","toString","saveAvatar","getAvatar","saveProgressPhoto","getProgressPhotos","photos","push","saveRecipePhotos","input","Promise","all","ingredientBase64","coverBase64","methodBase64","getRecipePhotos","results","map","every","r","data","includes","split","Buffer","from","method","Error","message","String"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type * as t from "./types/mailing.types.js";
2
+ export declare class MailingClient {
3
+ private emailClient;
4
+ private receiverEmail;
5
+ private logger;
6
+ constructor(config: t.Config);
7
+ private send;
8
+ sendEmailConfirmation(email: string, token: string): Promise<void>;
9
+ sendPasswordRecovery(email: string, token: string): Promise<void>;
10
+ sendPasswordRecoveryForPlatform(email: string, token: string): Promise<void>;
11
+ sendPasswordChange(email: string, token: string): Promise<void>;
12
+ sendEmailReminder(email: string, templateAlias: string): Promise<void>;
13
+ sendChallengeEmail(email: string, name: string): Promise<void>;
14
+ sendDeleteAccountEmail(email: string, token: string): Promise<void>;
15
+ sendExportsEmail(subject: string, textBody: string): Promise<void>;
16
+ sendShopifyEmail(input: t.ShopifyEmailInput): Promise<void>;
17
+ sendAndroidFreeTrialEmail(email: string): Promise<void>;
18
+ sendAppleFreeTrialEmail(email: string): Promise<void>;
19
+ static generateDiscountCode(email: string): string;
20
+ }
21
+ //# sourceMappingURL=MailingClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MailingClient.d.ts","sourceRoot":"","sources":["../../../src/lib/clients/MailingClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,CAAC,MAAM,0BAA0B,CAAC;AAEnD,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAA8C;gBAEhD,MAAM,EAAE,CAAC,CAAC,MAAM;YAKd,IAAI;IAKX,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAIlD,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAIjD,+BAA+B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAI5D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAI/C,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;IAItD,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAI9C,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAI7C,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUxE,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,iBAAiB;IAI3C,yBAAyB,CAAC,KAAK,EAAE,MAAM;IAIvC,uBAAuB,CAAC,KAAK,EAAE,MAAM;WAI9B,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAM1D"}
@@ -0,0 +1,84 @@
1
+ import { createHash } from "node:crypto";
2
+ import { Log } from "../utils/Logger.js";
3
+ export class MailingClient {
4
+ emailClient;
5
+ receiverEmail;
6
+ logger = Log.getInstance().extend("mailing-client");
7
+ constructor(config){
8
+ this.emailClient = config.emailClient;
9
+ this.receiverEmail = config.receiverEmail;
10
+ }
11
+ async send(email, templateAlias, templateModel, tag) {
12
+ await this.emailClient.sendWithTemplate({
13
+ to: email,
14
+ templateAlias,
15
+ templateModel,
16
+ tag
17
+ });
18
+ this.logger.info(`Sent ${tag} email to ${email}`);
19
+ }
20
+ sendEmailConfirmation(email, token) {
21
+ return this.send(email, "confirm-email", {
22
+ token
23
+ }, "confirm-email");
24
+ }
25
+ sendPasswordRecovery(email, token) {
26
+ return this.send(email, "restore-password", {
27
+ token
28
+ }, "restore-password");
29
+ }
30
+ sendPasswordRecoveryForPlatform(email, token) {
31
+ return this.send(email, "recover-password-platform", {
32
+ token
33
+ }, "recover-password-platform");
34
+ }
35
+ sendPasswordChange(email, token) {
36
+ return this.send(email, "change-password", {
37
+ token
38
+ }, "change-password");
39
+ }
40
+ sendEmailReminder(email, templateAlias) {
41
+ return this.send(email, templateAlias, {
42
+ discount: MailingClient.generateDiscountCode(email)
43
+ }, "email-reminder");
44
+ }
45
+ sendChallengeEmail(email, name) {
46
+ return this.send(email, "accept-challenge", {
47
+ name
48
+ }, "accept-challenge");
49
+ }
50
+ sendDeleteAccountEmail(email, token) {
51
+ return this.send(email, "delete-account", {
52
+ token
53
+ }, "delete-account");
54
+ }
55
+ async sendExportsEmail(subject, textBody) {
56
+ await this.emailClient.sendEmail({
57
+ to: this.receiverEmail,
58
+ subject,
59
+ textBody,
60
+ tag: "exports"
61
+ });
62
+ this.logger.info(`Sent exports email to ${this.receiverEmail}`);
63
+ }
64
+ sendShopifyEmail(input) {
65
+ return this.send(input.email, "shopify-welcome", {
66
+ email: input.email,
67
+ password: input.password
68
+ }, "shopify-welcome");
69
+ }
70
+ sendAndroidFreeTrialEmail(email) {
71
+ return this.send(email, "AndroidFreeTrialExtention", {}, "android-free-trial");
72
+ }
73
+ sendAppleFreeTrialEmail(email) {
74
+ return this.send(email, "IosFreeTrialExtention", {}, "apple-free-trial");
75
+ }
76
+ static generateDiscountCode(email) {
77
+ const hash = createHash("sha256").update(email).digest("hex").toUpperCase();
78
+ const letters = hash.replace(/[^A-Z]/g, "").substring(0, 4);
79
+ const digits = hash.replace(/[^0-9]/g, "").substring(0, 2);
80
+ return (letters + digits).substring(0, 6);
81
+ }
82
+ }
83
+
84
+ //# sourceMappingURL=MailingClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/clients/MailingClient.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { Log } from \"../utils/Logger.js\";\nimport type { EmailClient } from \"./EmailClient.js\";\nimport type * as t from \"./types/mailing.types.js\";\n\nexport class MailingClient {\n private emailClient: EmailClient;\n private receiverEmail: string;\n private logger = Log.getInstance().extend(\"mailing-client\");\n\n constructor(config: t.Config) {\n this.emailClient = config.emailClient;\n this.receiverEmail = config.receiverEmail;\n }\n\n private async send(email: string, templateAlias: string, templateModel: Record<string, any>, tag: string): Promise<void> {\n await this.emailClient.sendWithTemplate({ to: email, templateAlias, templateModel, tag });\n this.logger.info(`Sent ${tag} email to ${email}`);\n }\n\n public sendEmailConfirmation(email: string, token: string) {\n return this.send(email, \"confirm-email\", { token }, \"confirm-email\");\n }\n\n public sendPasswordRecovery(email: string, token: string) {\n return this.send(email, \"restore-password\", { token }, \"restore-password\");\n }\n\n public sendPasswordRecoveryForPlatform(email: string, token: string) {\n return this.send(email, \"recover-password-platform\", { token }, \"recover-password-platform\");\n }\n\n public sendPasswordChange(email: string, token: string) {\n return this.send(email, \"change-password\", { token }, \"change-password\");\n }\n\n public sendEmailReminder(email: string, templateAlias: string) {\n return this.send(email, templateAlias, { discount: MailingClient.generateDiscountCode(email) }, \"email-reminder\");\n }\n\n public sendChallengeEmail(email: string, name: string) {\n return this.send(email, \"accept-challenge\", { name }, \"accept-challenge\");\n }\n\n public sendDeleteAccountEmail(email: string, token: string) {\n return this.send(email, \"delete-account\", { token }, \"delete-account\");\n }\n\n public async sendExportsEmail(subject: string, textBody: string): Promise<void> {\n await this.emailClient.sendEmail({\n to: this.receiverEmail,\n subject,\n textBody,\n tag: \"exports\",\n });\n this.logger.info(`Sent exports email to ${this.receiverEmail}`);\n }\n\n public sendShopifyEmail(input: t.ShopifyEmailInput) {\n return this.send(input.email, \"shopify-welcome\", { email: input.email, password: input.password }, \"shopify-welcome\");\n }\n\n public sendAndroidFreeTrialEmail(email: string) {\n return this.send(email, \"AndroidFreeTrialExtention\", {}, \"android-free-trial\");\n }\n\n public sendAppleFreeTrialEmail(email: string) {\n return this.send(email, \"IosFreeTrialExtention\", {}, \"apple-free-trial\");\n }\n\n public static generateDiscountCode(email: string): string {\n const hash = createHash(\"sha256\").update(email).digest(\"hex\").toUpperCase();\n const letters = hash.replace(/[^A-Z]/g, \"\").substring(0, 4);\n const digits = hash.replace(/[^0-9]/g, \"\").substring(0, 2);\n return (letters + digits).substring(0, 6);\n }\n}\n"],"names":["createHash","Log","MailingClient","emailClient","receiverEmail","logger","getInstance","extend","config","send","email","templateAlias","templateModel","tag","sendWithTemplate","to","info","sendEmailConfirmation","token","sendPasswordRecovery","sendPasswordRecoveryForPlatform","sendPasswordChange","sendEmailReminder","discount","generateDiscountCode","sendChallengeEmail","name","sendDeleteAccountEmail","sendExportsEmail","subject","textBody","sendEmail","sendShopifyEmail","input","password","sendAndroidFreeTrialEmail","sendAppleFreeTrialEmail","hash","update","digest","toUpperCase","letters","replace","substring","digits"],"mappings":"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"}