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.
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/clients/EmailClient.d.ts +15 -34
- package/dist/lib/clients/EmailClient.d.ts.map +1 -1
- package/dist/lib/clients/EmailClient.js +41 -7
- package/dist/lib/clients/EmailClient.js.map +1 -1
- package/dist/lib/clients/ImagesClient.d.ts +17 -0
- package/dist/lib/clients/ImagesClient.d.ts.map +1 -0
- package/dist/lib/clients/ImagesClient.js +116 -0
- package/dist/lib/clients/ImagesClient.js.map +1 -0
- package/dist/lib/clients/MailingClient.d.ts +21 -0
- package/dist/lib/clients/MailingClient.d.ts.map +1 -0
- package/dist/lib/clients/MailingClient.js +84 -0
- package/dist/lib/clients/MailingClient.js.map +1 -0
- package/dist/lib/clients/types/email.types.d.ts +41 -0
- package/dist/lib/clients/types/email.types.d.ts.map +1 -0
- package/dist/lib/clients/types/email.types.js +3 -0
- package/dist/lib/clients/types/email.types.js.map +1 -0
- package/dist/lib/clients/types/images.types.d.ts +21 -0
- package/dist/lib/clients/types/images.types.d.ts.map +1 -0
- package/dist/lib/clients/types/images.types.js +3 -0
- package/dist/lib/clients/types/images.types.js.map +1 -0
- package/dist/lib/clients/types/mailing.types.d.ts +10 -0
- package/dist/lib/clients/types/mailing.types.d.ts.map +1 -0
- package/dist/lib/clients/types/mailing.types.js +3 -0
- package/dist/lib/clients/types/mailing.types.js.map +1 -0
- package/dist/lib/dbmodels/program/CircularProgramDraft.d.ts +1 -0
- package/dist/lib/dbmodels/program/CircularProgramDraft.d.ts.map +1 -1
- package/dist/lib/dbmodels/program/CircularProgramDraft.js.map +1 -1
- package/dist/lib/dbmodels/program/Exercise.d.ts +1 -0
- package/dist/lib/dbmodels/program/Exercise.d.ts.map +1 -1
- package/dist/lib/dbmodels/program/Exercise.js +7 -0
- package/dist/lib/dbmodels/program/Exercise.js.map +1 -1
- package/dist/lib/dbmodels/program/ProgressEntry.d.ts +1 -0
- package/dist/lib/dbmodels/program/ProgressEntry.d.ts.map +1 -1
- package/dist/lib/dbmodels/program/ProgressEntry.js +7 -0
- package/dist/lib/dbmodels/program/ProgressEntry.js.map +1 -1
- package/dist/lib/scripts/sequelize.config.cjs +2 -1
- package/dist/lib/scripts/verify-indexes.d.ts +13 -0
- package/dist/lib/scripts/verify-indexes.d.ts.map +1 -0
- package/dist/lib/scripts/verify-indexes.js +94 -0
- package/dist/lib/scripts/verify-indexes.js.map +1 -0
- package/dist/lib/utils/NotificationClient.d.ts +7 -0
- package/dist/lib/utils/NotificationClient.d.ts.map +1 -1
- package/dist/lib/utils/NotificationClient.js +23 -0
- package/dist/lib/utils/NotificationClient.js.map +1 -1
- package/package.json +2 -1
- package/dist/lib/scripts/migrations/20250117000001-create-extensions.js +0 -21
- package/dist/lib/scripts/migrations/20250117000001-create-extensions.js.map +0 -1
- package/dist/lib/scripts/migrations/20250126000001-add-index-exercises-supersetUuid.js +0 -41
- package/dist/lib/scripts/migrations/20250126000001-add-index-exercises-supersetUuid.js.map +0 -1
- package/dist/lib/scripts/migrations/20260115000000-add-workout-session-unique-constraint.js +0 -45
- 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
|
|
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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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":"
|
|
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
|
-
|
|
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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"}
|