@openora/core 0.4.1-canary.129 → 0.4.1-canary.130
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/.tsbuildinfo +1 -1
- package/dist/admin-console/__tests__/backoffice.service.int.test.js +1 -0
- package/dist/admin-console/__tests__/backoffice.service.int.test.js.map +1 -1
- package/dist/admin-console/plugin.d.ts +2 -2
- package/dist/admin-console/service/backoffice.service.d.ts +3 -0
- package/dist/admin-console/service/backoffice.service.d.ts.map +1 -1
- package/dist/analytics/plugin.d.ts +2 -2
- package/dist/audit/plugin.d.ts +2 -2
- package/dist/casino/gaming/plugin.d.ts +2 -2
- package/dist/casino/lobby/plugin.d.ts +2 -2
- package/dist/cms/plugin.d.ts +2 -2
- package/dist/compliance/__tests__/rg.router.int.test.js +4 -2
- package/dist/compliance/__tests__/rg.router.int.test.js.map +1 -1
- package/dist/compliance/__tests__/rg.service.int.test.js +42 -17
- package/dist/compliance/__tests__/rg.service.int.test.js.map +1 -1
- package/dist/compliance/plugin.d.ts +2 -2
- package/dist/compliance/plugin.d.ts.map +1 -1
- package/dist/compliance/plugin.js +3 -5
- package/dist/compliance/plugin.js.map +1 -1
- package/dist/compliance/service/rg-self-service.service.d.ts.map +1 -1
- package/dist/compliance/service/rg-self-service.service.js +2 -2
- package/dist/compliance/service/rg-self-service.service.js.map +1 -1
- package/dist/compliance/service/rg.service.d.ts +6 -8
- package/dist/compliance/service/rg.service.d.ts.map +1 -1
- package/dist/compliance/service/rg.service.js +43 -29
- package/dist/compliance/service/rg.service.js.map +1 -1
- package/dist/contracts/adapters/admin-user-directory.d.ts +1 -0
- package/dist/contracts/adapters/admin-user-directory.d.ts.map +1 -1
- package/dist/contracts/adapters/admin-user-directory.js.map +1 -1
- package/dist/contracts/adapters/audit.d.ts +1 -1
- package/dist/contracts/adapters/audit.d.ts.map +1 -1
- package/dist/contracts/adapters/audit.js.map +1 -1
- package/dist/contracts/adapters/email-template.d.ts +6 -48
- package/dist/contracts/adapters/email-template.d.ts.map +1 -1
- package/dist/contracts/adapters/email-template.js +0 -58
- package/dist/contracts/adapters/email-template.js.map +1 -1
- package/dist/contracts/adapters/index.d.ts +4 -6
- package/dist/contracts/adapters/index.d.ts.map +1 -1
- package/dist/contracts/adapters/index.js +2 -3
- package/dist/contracts/adapters/index.js.map +1 -1
- package/dist/contracts/adapters/mail.d.ts +30 -0
- package/dist/contracts/adapters/mail.d.ts.map +1 -0
- package/dist/contracts/adapters/mail.js +4 -0
- package/dist/contracts/adapters/mail.js.map +1 -0
- package/dist/contracts/schemas/common.d.ts +1 -0
- package/dist/contracts/schemas/common.d.ts.map +1 -1
- package/dist/contracts/schemas/common.js +11 -0
- package/dist/contracts/schemas/common.js.map +1 -1
- package/dist/contracts/schemas/index.d.ts +1 -0
- package/dist/contracts/schemas/index.d.ts.map +1 -1
- package/dist/contracts/schemas/index.js +1 -0
- package/dist/contracts/schemas/index.js.map +1 -1
- package/dist/contracts/schemas/mail.d.ts +166 -0
- package/dist/contracts/schemas/mail.d.ts.map +1 -0
- package/dist/contracts/schemas/mail.js +74 -0
- package/dist/contracts/schemas/mail.js.map +1 -0
- package/dist/engagement/chat/__tests__/chat.service.int.test.js +4 -0
- package/dist/engagement/chat/__tests__/chat.service.int.test.js.map +1 -1
- package/dist/engagement/chat/plugin.d.ts +2 -2
- package/dist/engagement/chat-commands/plugin.d.ts +2 -2
- package/dist/engagement/notifications/__tests__/chat-room-notifications.int.test.js +8 -11
- package/dist/engagement/notifications/__tests__/chat-room-notifications.int.test.js.map +1 -1
- package/dist/engagement/notifications/__tests__/notification-event-map.test.js +76 -39
- package/dist/engagement/notifications/__tests__/notification-event-map.test.js.map +1 -1
- package/dist/engagement/notifications/plugin.d.ts +8 -7
- package/dist/engagement/notifications/plugin.d.ts.map +1 -1
- package/dist/engagement/notifications/plugin.js +102 -86
- package/dist/engagement/notifications/plugin.js.map +1 -1
- package/dist/engagement/social/plugin.d.ts +2 -2
- package/dist/fx/exchange-rate/plugin.d.ts +2 -2
- package/dist/iam/__tests__/iam.service.int.test.js +53 -46
- package/dist/iam/__tests__/iam.service.int.test.js.map +1 -1
- package/dist/iam/plugin.d.ts +3 -2
- package/dist/iam/plugin.d.ts.map +1 -1
- package/dist/iam/plugin.js +3 -2
- package/dist/iam/plugin.js.map +1 -1
- package/dist/iam/service/iam.service.d.ts +3 -3
- package/dist/iam/service/iam.service.d.ts.map +1 -1
- package/dist/iam/service/iam.service.js +11 -7
- package/dist/iam/service/iam.service.js.map +1 -1
- package/dist/mail/__tests__/default-email-template-renderer.test.d.ts.map +1 -0
- package/dist/mail/__tests__/default-email-template-renderer.test.js +119 -0
- package/dist/mail/__tests__/default-email-template-renderer.test.js.map +1 -0
- package/dist/mail/__tests__/mail.service.test.d.ts +2 -0
- package/dist/mail/__tests__/mail.service.test.d.ts.map +1 -0
- package/dist/mail/__tests__/mail.service.test.js +215 -0
- package/dist/mail/__tests__/mail.service.test.js.map +1 -0
- package/dist/mail/adapters/default-email-template-renderer.d.ts +5 -0
- package/dist/mail/adapters/default-email-template-renderer.d.ts.map +1 -0
- package/dist/mail/adapters/default-email-template-renderer.js +107 -0
- package/dist/mail/adapters/default-email-template-renderer.js.map +1 -0
- package/dist/mail/adapters/stdout-email-sender.d.ts +5 -0
- package/dist/mail/adapters/stdout-email-sender.d.ts.map +1 -0
- package/dist/mail/adapters/stdout-email-sender.js +8 -0
- package/dist/mail/adapters/stdout-email-sender.js.map +1 -0
- package/dist/mail/contract/index.d.ts +120 -0
- package/dist/mail/contract/index.d.ts.map +1 -0
- package/dist/mail/contract/index.js +17 -0
- package/dist/mail/contract/index.js.map +1 -0
- package/dist/mail/index.d.ts +5 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +5 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/plugin.d.ts +181 -0
- package/dist/mail/plugin.d.ts.map +1 -0
- package/dist/mail/plugin.js +66 -0
- package/dist/mail/plugin.js.map +1 -0
- package/dist/mail/service/mail-payload.service.d.ts +8 -0
- package/dist/mail/service/mail-payload.service.d.ts.map +1 -0
- package/dist/mail/service/mail-payload.service.js +43 -0
- package/dist/mail/service/mail-payload.service.js.map +1 -0
- package/dist/mail/service/mail.service.d.ts +30 -0
- package/dist/mail/service/mail.service.d.ts.map +1 -0
- package/dist/mail/service/mail.service.js +152 -0
- package/dist/mail/service/mail.service.js.map +1 -0
- package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js +0 -4
- package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js.map +1 -1
- package/dist/pam/identity/__tests__/identity.registration-gates.int.test.js +0 -4
- package/dist/pam/identity/__tests__/identity.registration-gates.int.test.js.map +1 -1
- package/dist/pam/identity/__tests__/identity.service.int.test.js +13 -4
- package/dist/pam/identity/__tests__/identity.service.int.test.js.map +1 -1
- package/dist/pam/identity/admin-user-directory.d.ts +4 -0
- package/dist/pam/identity/admin-user-directory.d.ts.map +1 -1
- package/dist/pam/identity/admin-user-directory.js +1 -0
- package/dist/pam/identity/admin-user-directory.js.map +1 -1
- package/dist/pam/identity/plugin.d.ts +3 -2
- package/dist/pam/identity/plugin.d.ts.map +1 -1
- package/dist/pam/identity/plugin.js +3 -9
- package/dist/pam/identity/plugin.js.map +1 -1
- package/dist/pam/identity/service/identity.service.d.ts +5 -7
- package/dist/pam/identity/service/identity.service.d.ts.map +1 -1
- package/dist/pam/identity/service/identity.service.js +40 -23
- package/dist/pam/identity/service/identity.service.js.map +1 -1
- package/dist/pam/player-management/plugin.d.ts +2 -2
- package/dist/pam/player-note/plugin.d.ts +2 -2
- package/dist/pam/profile/plugin.d.ts +2 -2
- package/dist/pam/shared/__tests__/shared-mappers.test.js +6 -0
- package/dist/pam/shared/__tests__/shared-mappers.test.js.map +1 -1
- package/dist/pam/shared/language.d.ts.map +1 -1
- package/dist/pam/shared/language.js +6 -0
- package/dist/pam/shared/language.js.map +1 -1
- package/dist/pam/tag/plugin.d.ts +2 -2
- package/dist/server/auth/__tests__/auth.test.js +45 -50
- package/dist/server/auth/__tests__/auth.test.js.map +1 -1
- package/dist/server/auth/auth.d.ts +7 -8
- package/dist/server/auth/auth.d.ts.map +1 -1
- package/dist/server/auth/auth.js +10 -20
- package/dist/server/auth/auth.js.map +1 -1
- package/dist/server/auth/index.d.ts +1 -1
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/plugin-host/core-plugins.d.ts.map +1 -1
- package/dist/server/plugin-host/core-plugins.js +1 -0
- package/dist/server/plugin-host/core-plugins.js.map +1 -1
- package/dist/server/runtime/core-token-catalog.d.ts +2 -2
- package/dist/server/runtime/core-token-catalog.js +3 -3
- package/dist/server/runtime/core-token-catalog.js.map +1 -1
- package/dist/server/runtime/create-app.d.ts.map +1 -1
- package/dist/server/runtime/create-app.js +7 -7
- package/dist/server/runtime/create-app.js.map +1 -1
- package/dist/wallet/plugin.d.ts +2 -2
- package/generators/src/config.ts +1 -2
- package/package.json +21 -1
- package/dist/contracts/adapters/email.d.ts +0 -17
- package/dist/contracts/adapters/email.d.ts.map +0 -1
- package/dist/contracts/adapters/email.js +0 -10
- package/dist/contracts/adapters/email.js.map +0 -1
- package/dist/contracts/adapters/notification.d.ts +0 -13
- package/dist/contracts/adapters/notification.d.ts.map +0 -1
- package/dist/contracts/adapters/notification.js +0 -10
- package/dist/contracts/adapters/notification.js.map +0 -1
- package/dist/engagement/notifications/adapters/mock/mock-notification-adapter.d.ts +0 -5
- package/dist/engagement/notifications/adapters/mock/mock-notification-adapter.d.ts.map +0 -1
- package/dist/engagement/notifications/adapters/mock/mock-notification-adapter.js +0 -6
- package/dist/engagement/notifications/adapters/mock/mock-notification-adapter.js.map +0 -1
- package/dist/pam/identity/adapters/__tests__/default-email-template-renderer.test.d.ts.map +0 -1
- package/dist/pam/identity/adapters/__tests__/default-email-template-renderer.test.js +0 -33
- package/dist/pam/identity/adapters/__tests__/default-email-template-renderer.test.js.map +0 -1
- package/dist/pam/identity/adapters/default-email-template-renderer.d.ts +0 -8
- package/dist/pam/identity/adapters/default-email-template-renderer.d.ts.map +0 -1
- package/dist/pam/identity/adapters/default-email-template-renderer.js +0 -7
- package/dist/pam/identity/adapters/default-email-template-renderer.js.map +0 -1
- /package/dist/{pam/identity/adapters → mail}/__tests__/default-email-template-renderer.test.d.ts +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { formatMoneyAmount, } from '@openora/core/contracts';
|
|
2
|
+
const DEFAULT_LOCALE = 'en';
|
|
3
|
+
const escapeHtml = (value) => value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
4
|
+
const textToHtml = (text) => text
|
|
5
|
+
.split(/\n{2,}/)
|
|
6
|
+
.map((block) => `<p>${escapeHtml(block).replace(/\n/g, '<br>')}</p>`)
|
|
7
|
+
.join('\n');
|
|
8
|
+
const DATE_FORMAT_OPTS = { dateStyle: 'long', timeStyle: 'short', timeZone: 'UTC' };
|
|
9
|
+
const dateFormatter = (locale) => {
|
|
10
|
+
try {
|
|
11
|
+
return new Intl.DateTimeFormat(locale, DATE_FORMAT_OPTS);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return new Intl.DateTimeFormat(DEFAULT_LOCALE, DATE_FORMAT_OPTS);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const formatEmailDate = (iso, locale) => iso === null ? 'further notice' : `${dateFormatter(locale).format(new Date(iso))} UTC`;
|
|
18
|
+
const formatMoney = (amount, currency) => `${formatMoneyAmount(amount)} ${currency}`;
|
|
19
|
+
const PLAIN_EMAIL_TEMPLATES = {
|
|
20
|
+
verifyEmail: (data) => ({
|
|
21
|
+
subject: 'Verify your email',
|
|
22
|
+
text: `Your email verification code is: ${data.otp}`,
|
|
23
|
+
}),
|
|
24
|
+
resetPasswordOtp: (data) => ({
|
|
25
|
+
subject: 'Reset your password',
|
|
26
|
+
text: `Your password reset code is: ${data.otp}`,
|
|
27
|
+
}),
|
|
28
|
+
adminResetPasswordOtp: (data) => ({
|
|
29
|
+
subject: 'Password reset requested by an administrator',
|
|
30
|
+
text: `An administrator requested a password reset for your account. Your reset code is: ${data.otp}`,
|
|
31
|
+
}),
|
|
32
|
+
existingAccountSignUp: (data) => ({
|
|
33
|
+
subject: 'You already have an account',
|
|
34
|
+
text: `Someone tried to create an account with this email address. ` +
|
|
35
|
+
`You already have one, so no new account was created. ` +
|
|
36
|
+
`If it was you, sign in as usual - or use this code to reset your password: ${data.otp}`,
|
|
37
|
+
}),
|
|
38
|
+
rgLimitUpdated: (data) => {
|
|
39
|
+
const value = data.amount !== null
|
|
40
|
+
? formatMoney(data.amount, data.currency ?? '')
|
|
41
|
+
: `${data.minutes} minutes`;
|
|
42
|
+
return {
|
|
43
|
+
subject: 'Your gambling limit was updated',
|
|
44
|
+
text: `A ${data.period} ${data.type} limit of ${value.trim()} is now active on your account.`,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
rgCoolingOffActivated: (data, locale) => ({
|
|
48
|
+
subject: 'Your cooling-off period has started',
|
|
49
|
+
text: `A cooling-off period is active on your account until ${formatEmailDate(data.expiresAt, locale)}.\n\nYou will not be able to log in or place bets until then.`,
|
|
50
|
+
}),
|
|
51
|
+
rgCoolingOffLifted: () => ({
|
|
52
|
+
subject: 'Your cooling-off period has ended',
|
|
53
|
+
text: 'Your cooling-off period has been ended and you can log in again.',
|
|
54
|
+
}),
|
|
55
|
+
rgSelfExclusionActivated: (data, locale) => ({
|
|
56
|
+
subject: 'Your self-exclusion has started',
|
|
57
|
+
text: data.isPermanent
|
|
58
|
+
? 'Your account has been permanently self-excluded and you will not be able to log in.'
|
|
59
|
+
: `Your account is self-excluded until ${formatEmailDate(data.expiresAt, locale)}.\n\nYou will not be able to log in until then.`,
|
|
60
|
+
}),
|
|
61
|
+
rgSelfExclusionLifted: () => ({
|
|
62
|
+
subject: 'Your self-exclusion has been lifted',
|
|
63
|
+
text: 'Your self-exclusion has been lifted and you can log in again.',
|
|
64
|
+
}),
|
|
65
|
+
withdrawalApproved: (data, locale) => ({
|
|
66
|
+
subject: 'Your withdrawal was approved',
|
|
67
|
+
text: `Your withdrawal of ${formatMoney(data.amount, data.currency)} has been approved and is being processed.\n\n` +
|
|
68
|
+
`Transaction: ${data.transactionId}\nDate: ${formatEmailDate(data.occurredAt, locale)}`,
|
|
69
|
+
}),
|
|
70
|
+
withdrawalRejected: (data, locale) => ({
|
|
71
|
+
subject: 'Your withdrawal was rejected',
|
|
72
|
+
text: `Your withdrawal of ${formatMoney(data.amount, data.currency)} was rejected and the funds were returned to your balance.\n\n` +
|
|
73
|
+
`Transaction: ${data.transactionId}\nDate: ${formatEmailDate(data.occurredAt, locale)}` +
|
|
74
|
+
(data.reason ? `\nReason: ${data.reason}` : ''),
|
|
75
|
+
}),
|
|
76
|
+
kycResubmissionRequested: (data) => ({
|
|
77
|
+
subject: 'Document resubmission required',
|
|
78
|
+
text: `An admin has requested you resubmit your verification documents.` +
|
|
79
|
+
(data.reason ? ` Reason: ${data.reason}.` : ''),
|
|
80
|
+
}),
|
|
81
|
+
adminInvitation: (data, locale) => ({
|
|
82
|
+
subject: 'You have been invited as an administrator',
|
|
83
|
+
text: `Your admin invitation token: ${data.token}. It expires at ${formatEmailDate(data.expiresAt, locale)}.`,
|
|
84
|
+
}),
|
|
85
|
+
securityLoginAlert: (data, locale) => ({
|
|
86
|
+
subject: 'New sign-in to your account',
|
|
87
|
+
text: `A new sign-in to your account was detected on ${formatEmailDate(data.occurredAt, locale)}.\n\n` +
|
|
88
|
+
`If this was not you, secure your account immediately.`,
|
|
89
|
+
}),
|
|
90
|
+
securityWithdrawalRequested: (data, locale) => ({
|
|
91
|
+
subject: 'Withdrawal requested on your account',
|
|
92
|
+
text: `A withdrawal of ${formatMoney(data.amount, data.currency)} was requested on your account and is pending review.\n\n` +
|
|
93
|
+
`Transaction: ${data.transactionId}\nDate: ${formatEmailDate(data.occurredAt, locale)}\n\n` +
|
|
94
|
+
`If this was not you, secure your account immediately.`,
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
const renderDefaultEmail = (template, locale) => {
|
|
98
|
+
const plain = PLAIN_EMAIL_TEMPLATES[template.key];
|
|
99
|
+
const { subject, text } = plain(template.data, locale);
|
|
100
|
+
return { subject, text, html: textToHtml(text) };
|
|
101
|
+
};
|
|
102
|
+
export class DefaultEmailTemplateRenderer {
|
|
103
|
+
render(template, locale) {
|
|
104
|
+
return renderDefaultEmail(template, locale);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=default-email-template-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-email-template-renderer.js","sourceRoot":"","sources":["../../../src/mail/adapters/default-email-template-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdout-email-sender.d.ts","sourceRoot":"","sources":["../../../src/mail/adapters/stdout-email-sender.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI7E,qBAAa,iBAAkB,YAAW,eAAe;IACjD,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAMjD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createLogger } from '@openora/core/server';
|
|
2
|
+
const logger = createLogger('mail');
|
|
3
|
+
export class StdoutEmailSender {
|
|
4
|
+
async send(message) {
|
|
5
|
+
logger.info({ to: message.to, subject: message.subject, bytes: message.html.length }, 'mock email delivery (no EMAIL_SENDER overlay bound)');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=stdout-email-sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdout-email-sender.js","sourceRoot":"","sources":["../../../src/mail/adapters/stdout-email-sender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAEpC,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,IAAI,CAAC,OAAqB;QAC9B,MAAM,CAAC,IAAI,CACT,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EACxE,qDAAqD,CACtD,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
export declare const MAIL_SEND_QUEUE: import("@openora/core/contracts").QueueName;
|
|
3
|
+
export declare const MailRecipientSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4
|
+
kind: z.ZodLiteral<"user">;
|
|
5
|
+
userId: z.ZodUUID;
|
|
6
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
7
|
+
kind: z.ZodLiteral<"address">;
|
|
8
|
+
email: z.ZodEmail;
|
|
9
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>], "kind">;
|
|
11
|
+
export type MailRecipient = z.infer<typeof MailRecipientSchema>;
|
|
12
|
+
export declare const MailSendJobSchema: z.ZodObject<{
|
|
13
|
+
recipient: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
14
|
+
kind: z.ZodLiteral<"user">;
|
|
15
|
+
userId: z.ZodUUID;
|
|
16
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
17
|
+
kind: z.ZodLiteral<"address">;
|
|
18
|
+
email: z.ZodEmail;
|
|
19
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>], "kind">;
|
|
21
|
+
template: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
22
|
+
key: z.ZodLiteral<"verifyEmail">;
|
|
23
|
+
data: z.ZodObject<{
|
|
24
|
+
otp: z.ZodString;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
27
|
+
key: z.ZodLiteral<"resetPasswordOtp">;
|
|
28
|
+
data: z.ZodObject<{
|
|
29
|
+
otp: z.ZodString;
|
|
30
|
+
email: z.ZodEmail;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
33
|
+
key: z.ZodLiteral<"adminResetPasswordOtp">;
|
|
34
|
+
data: z.ZodObject<{
|
|
35
|
+
otp: z.ZodString;
|
|
36
|
+
email: z.ZodEmail;
|
|
37
|
+
}, z.core.$strip>;
|
|
38
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
39
|
+
key: z.ZodLiteral<"existingAccountSignUp">;
|
|
40
|
+
data: z.ZodObject<{
|
|
41
|
+
otp: z.ZodString;
|
|
42
|
+
email: z.ZodEmail;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
45
|
+
key: z.ZodLiteral<"rgLimitUpdated">;
|
|
46
|
+
data: z.ZodObject<{
|
|
47
|
+
period: z.ZodString;
|
|
48
|
+
type: z.ZodString;
|
|
49
|
+
amount: z.ZodNullable<z.ZodString>;
|
|
50
|
+
currency: z.ZodNullable<z.ZodString>;
|
|
51
|
+
minutes: z.ZodNullable<z.ZodNumber>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
54
|
+
key: z.ZodLiteral<"rgCoolingOffActivated">;
|
|
55
|
+
data: z.ZodObject<{
|
|
56
|
+
expiresAt: z.ZodISODateTime;
|
|
57
|
+
}, z.core.$strip>;
|
|
58
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
59
|
+
key: z.ZodLiteral<"rgCoolingOffLifted">;
|
|
60
|
+
data: z.ZodObject<{}, z.core.$strip>;
|
|
61
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
62
|
+
key: z.ZodLiteral<"rgSelfExclusionActivated">;
|
|
63
|
+
data: z.ZodObject<{
|
|
64
|
+
expiresAt: z.ZodNullable<z.ZodISODateTime>;
|
|
65
|
+
isPermanent: z.ZodBoolean;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
68
|
+
key: z.ZodLiteral<"rgSelfExclusionLifted">;
|
|
69
|
+
data: z.ZodObject<{}, z.core.$strip>;
|
|
70
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
71
|
+
key: z.ZodLiteral<"withdrawalApproved">;
|
|
72
|
+
data: z.ZodObject<{
|
|
73
|
+
amount: z.ZodString;
|
|
74
|
+
currency: z.ZodString;
|
|
75
|
+
transactionId: z.ZodUUID;
|
|
76
|
+
occurredAt: z.ZodISODateTime;
|
|
77
|
+
}, z.core.$strip>;
|
|
78
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
79
|
+
key: z.ZodLiteral<"withdrawalRejected">;
|
|
80
|
+
data: z.ZodObject<{
|
|
81
|
+
reason: z.ZodNullable<z.ZodString>;
|
|
82
|
+
amount: z.ZodString;
|
|
83
|
+
currency: z.ZodString;
|
|
84
|
+
transactionId: z.ZodUUID;
|
|
85
|
+
occurredAt: z.ZodISODateTime;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
88
|
+
key: z.ZodLiteral<"kycResubmissionRequested">;
|
|
89
|
+
data: z.ZodObject<{
|
|
90
|
+
reason: z.ZodNullable<z.ZodString>;
|
|
91
|
+
}, z.core.$strip>;
|
|
92
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
93
|
+
key: z.ZodLiteral<"adminInvitation">;
|
|
94
|
+
data: z.ZodObject<{
|
|
95
|
+
token: z.ZodString;
|
|
96
|
+
expiresAt: z.ZodISODateTime;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
99
|
+
key: z.ZodLiteral<"securityLoginAlert">;
|
|
100
|
+
data: z.ZodObject<{
|
|
101
|
+
occurredAt: z.ZodISODateTime;
|
|
102
|
+
}, z.core.$strip>;
|
|
103
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
104
|
+
key: z.ZodLiteral<"securityWithdrawalRequested">;
|
|
105
|
+
data: z.ZodObject<{
|
|
106
|
+
amount: z.ZodString;
|
|
107
|
+
currency: z.ZodString;
|
|
108
|
+
transactionId: z.ZodUUID;
|
|
109
|
+
occurredAt: z.ZodISODateTime;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
}, z.core.$strip>], "key">;
|
|
112
|
+
}, z.core.$strip>;
|
|
113
|
+
export type MailSendJob = z.infer<typeof MailSendJobSchema>;
|
|
114
|
+
export declare const EncryptedMailSendJobSchema: z.ZodObject<{
|
|
115
|
+
ciphertext: z.ZodString;
|
|
116
|
+
iv: z.ZodString;
|
|
117
|
+
tag: z.ZodString;
|
|
118
|
+
}, z.core.$strip>;
|
|
119
|
+
export type EncryptedMailSendJob = z.infer<typeof EncryptedMailSendJobSchema>;
|
|
120
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mail/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAGzB,eAAO,MAAM,eAAe,6CAAqB,CAAC;AAElD,eAAO,MAAM,mBAAmB;;;;;;;2BAG9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAG5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,0BAA0B;;;;iBAIrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { MailTemplateSchema, UuidSchema, queue } from '@openora/core/contracts';
|
|
3
|
+
export const MAIL_SEND_QUEUE = queue('mail-send');
|
|
4
|
+
export const MailRecipientSchema = z.discriminatedUnion('kind', [
|
|
5
|
+
z.object({ kind: z.literal('user'), userId: UuidSchema }),
|
|
6
|
+
z.object({ kind: z.literal('address'), email: z.email(), locale: z.string().optional() }),
|
|
7
|
+
]);
|
|
8
|
+
export const MailSendJobSchema = z.object({
|
|
9
|
+
recipient: MailRecipientSchema,
|
|
10
|
+
template: MailTemplateSchema,
|
|
11
|
+
});
|
|
12
|
+
export const EncryptedMailSendJobSchema = z.object({
|
|
13
|
+
ciphertext: z.string().min(1),
|
|
14
|
+
iv: z.string().min(1),
|
|
15
|
+
tag: z.string().min(1),
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mail/contract/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEhF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;AAElD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC9D,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACzD,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;CAC1F,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,SAAS,EAAE,mBAAmB;IAC9B,QAAQ,EAAE,kBAAkB;CAC7B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACvB,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { MailService, type MailServiceDeps } from './service/mail.service.js';
|
|
2
|
+
export { DefaultEmailTemplateRenderer } from './adapters/default-email-template-renderer.js';
|
|
3
|
+
export { StdoutEmailSender } from './adapters/stdout-email-sender.js';
|
|
4
|
+
export { MAIL_SEND_QUEUE, EncryptedMailSendJobSchema, MailSendJobSchema, MailRecipientSchema, type EncryptedMailSendJob, type MailSendJob, type MailRecipient, } from './contract/index.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mail/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,+CAA+C,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,WAAW,EAChB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { MailService } from './service/mail.service.js';
|
|
2
|
+
export { DefaultEmailTemplateRenderer } from './adapters/default-email-template-renderer.js';
|
|
3
|
+
export { StdoutEmailSender } from './adapters/stdout-email-sender.js';
|
|
4
|
+
export { MAIL_SEND_QUEUE, EncryptedMailSendJobSchema, MailSendJobSchema, MailRecipientSchema, } from './contract/index.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mail/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAwB,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,+CAA+C,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,GAIpB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
readonly id: "mail";
|
|
3
|
+
readonly register: (ctx: import("@openora/core/server").PluginContext<{
|
|
4
|
+
ADMIN_GAME_REPORTING: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminGameReporting>;
|
|
5
|
+
ADMIN_GUARD: import("@openora/core/contracts").Token<import("@openora/core/server").AdminGuard>;
|
|
6
|
+
ADMIN_PERMISSION_RESOLVER: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminPermissionResolver>;
|
|
7
|
+
ADMIN_PLAYER_ACTIVITY: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminPlayerActivity>;
|
|
8
|
+
ADMIN_ROLE_ASSIGNMENT_DIRECTORY: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminRoleAssignmentDirectory>;
|
|
9
|
+
ADMIN_SECURITY_POLICY: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminSecurityPolicy>;
|
|
10
|
+
ADMIN_USER_DIRECTORY: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminUserDirectory>;
|
|
11
|
+
ADMIN_WALLET_REPORTING: import("@openora/core/contracts").Token<import("@openora/core/contracts").AdminWalletReporting>;
|
|
12
|
+
AUDIT_WRITER: import("@openora/core/contracts").SealedToken<import("@openora/core/contracts").AuditWritePort>;
|
|
13
|
+
AUTH_SESSION: import("@openora/core/contracts").Token<import("@openora/core/server").SessionResolver>;
|
|
14
|
+
CACHE: import("@openora/core/contracts").Token<import("@openora/core/contracts").CacheAdapter>;
|
|
15
|
+
CHAT_BLOCK_WRITER: import("@openora/core/contracts").Token<import("@openora/core/contracts").ChatBlockWriter>;
|
|
16
|
+
CHAT_MODERATION: import("@openora/core/contracts").Token<import("@openora/core/contracts").ChatModeration, string>;
|
|
17
|
+
CHAT_REALTIME_CLIENT_AUTHORIZER: import("@openora/core/contracts").Token<import("@openora/core/contracts").RealtimeClientAuthorizer>;
|
|
18
|
+
CHAT_REALTIME_TRANSPORT: import("@openora/core/contracts").Token<import("@openora/core/contracts").RealtimeTransport>;
|
|
19
|
+
CHAT_ROOM_ACCESS: import("@openora/core/contracts").Token<import("@openora/core/contracts").ChatRoomAccess>;
|
|
20
|
+
CHAT_SYSTEM_WRITER: import("@openora/core/contracts").Token<import("@openora/core/contracts").ChatSystemWriter, string>;
|
|
21
|
+
DRIZZLE: import("@openora/core/contracts").Token<import("@openora/core/server").DrizzleService>;
|
|
22
|
+
EMAIL_SENDER: import("@openora/core/contracts").Token<import("@openora/core/contracts").EmailSenderPort>;
|
|
23
|
+
EMAIL_TEMPLATE_RENDERER: import("@openora/core/contracts").Token<import("@openora/core/contracts").EmailTemplateRenderer>;
|
|
24
|
+
ERROR_TRACKING: import("@openora/core/contracts").Token<import("@openora/core/contracts").ErrorTrackingAdapter>;
|
|
25
|
+
EVENT_BUS: import("@openora/core/contracts").Token<import("@openora/core/server").EventBus>;
|
|
26
|
+
EXCHANGE_RATE_READER: import("@openora/core/contracts").Token<import("@openora/core/contracts").ExchangeRateReader>;
|
|
27
|
+
CRYPTO_EXCHANGE_RATE_PROVIDER: import("@openora/core/contracts").Token<import("@openora/core/contracts").ExchangeRateProvider>;
|
|
28
|
+
FIAT_EXCHANGE_RATE_PROVIDER: import("@openora/core/contracts").Token<import("@openora/core/contracts").ExchangeRateProvider>;
|
|
29
|
+
SWAP_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").SwapAdapter>;
|
|
30
|
+
SWAP_WEBHOOK_VERIFIER: import("@openora/core/contracts").Token<import("@openora/core/contracts").SwapWebhookVerifier>;
|
|
31
|
+
GAME_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").GameAdapter>;
|
|
32
|
+
GEO_CHECK_COMMANDS: import("@openora/core/contracts").Token<import("@openora/core/contracts").GeoCheckCommands>;
|
|
33
|
+
GEO_IP_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").GeoIpAdapter>;
|
|
34
|
+
IDENTITY_OPTIONS: import("@openora/core/contracts").Token<import("@openora/core/contracts").IdentityServiceOptions>;
|
|
35
|
+
IDENTITY_READER: import("@openora/core/contracts").Token<import("@openora/core/contracts").IdentityReader, string>;
|
|
36
|
+
IGAMING_CONFIG: import("@openora/core/contracts").Token<{
|
|
37
|
+
branding: {
|
|
38
|
+
name: string;
|
|
39
|
+
themePreset?: string | undefined;
|
|
40
|
+
supportEmail?: string | undefined;
|
|
41
|
+
};
|
|
42
|
+
currencies: string[];
|
|
43
|
+
jurisdictions: string[];
|
|
44
|
+
blockedCountries: string[];
|
|
45
|
+
limits: {
|
|
46
|
+
maxDepositPerDay?: number | undefined;
|
|
47
|
+
maxDepositPerMonth?: number | undefined;
|
|
48
|
+
maxLossPerDay?: number | undefined;
|
|
49
|
+
maxStakePerBet?: number | undefined;
|
|
50
|
+
sessionReminderMinutes?: number | undefined;
|
|
51
|
+
};
|
|
52
|
+
providers: {
|
|
53
|
+
payment?: string | undefined;
|
|
54
|
+
kyc?: string | undefined;
|
|
55
|
+
geoIp?: string | undefined;
|
|
56
|
+
aggregator?: string | undefined;
|
|
57
|
+
notification?: string | undefined;
|
|
58
|
+
};
|
|
59
|
+
enabledModules?: string[] | undefined;
|
|
60
|
+
}, string>;
|
|
61
|
+
JOB_QUEUE: import("@openora/core/contracts").Token<import("@openora/core/contracts").JobQueueAdapter>;
|
|
62
|
+
KYC_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").KycAdapter>;
|
|
63
|
+
KYC_STATUS_WRITER: import("@openora/core/contracts").Token<import("@openora/core/contracts").KycStatusWriter>;
|
|
64
|
+
KYC_WEBHOOK_VERIFIER: import("@openora/core/contracts").Token<import("@openora/core/contracts").KycWebhookVerifier>;
|
|
65
|
+
LOGIN_ENFORCEMENT: import("@openora/core/contracts").Token<import("@openora/core/contracts").LoginEnforcementPort>;
|
|
66
|
+
MAIL_DISPATCH: import("@openora/core/contracts").Token<import("@openora/core/contracts").MailDispatchPort>;
|
|
67
|
+
MESSAGE_BROKER: import("@openora/core/contracts").Token<import("@openora/core/contracts").MessageBrokerAdapter>;
|
|
68
|
+
OUTBOX: import("@openora/core/contracts").Token<import("@openora/core/contracts").OutboxWriter>;
|
|
69
|
+
PAYMENT_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").PaymentAdapter>;
|
|
70
|
+
PAYMENT_PROVIDERS: import("@openora/core/contracts").Token<import("@openora/core/contracts").PaymentProviderRegistry>;
|
|
71
|
+
PAYMENT_WEBHOOK_VERIFIER: import("@openora/core/contracts").Token<import("@openora/core/contracts").PaymentWebhookVerifier>;
|
|
72
|
+
PLATFORM_CONFIG: import("@openora/core/contracts").Token<{
|
|
73
|
+
features: Record<string, boolean>;
|
|
74
|
+
brands: {
|
|
75
|
+
id: string;
|
|
76
|
+
name: string;
|
|
77
|
+
themePreset?: string | undefined;
|
|
78
|
+
themeOverrides?: Record<string, string> | undefined;
|
|
79
|
+
}[];
|
|
80
|
+
rgLimits: Record<string, {
|
|
81
|
+
maxDepositPerDay?: number | undefined;
|
|
82
|
+
maxDepositPerMonth?: number | undefined;
|
|
83
|
+
maxLossPerDay?: number | undefined;
|
|
84
|
+
maxStakePerBet?: number | undefined;
|
|
85
|
+
sessionReminderMinutes?: number | undefined;
|
|
86
|
+
}>;
|
|
87
|
+
responsibleGambling: {
|
|
88
|
+
limitIncreaseCooldownHours: number;
|
|
89
|
+
limitChangeConfirmationWindowHours: number;
|
|
90
|
+
};
|
|
91
|
+
chat: {
|
|
92
|
+
allowedAttachmentHosts: string[];
|
|
93
|
+
moderationExpiry?: {
|
|
94
|
+
cron: string;
|
|
95
|
+
} | undefined;
|
|
96
|
+
};
|
|
97
|
+
adminSecurity: {
|
|
98
|
+
requireTwoFactor: boolean;
|
|
99
|
+
bindSessionToDevice: boolean;
|
|
100
|
+
trustedDeviceDays: number;
|
|
101
|
+
ipChangePolicy: "any" | "country" | "off";
|
|
102
|
+
twoFactorLockout: {
|
|
103
|
+
maxAttempts: number;
|
|
104
|
+
durationMs: number;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
cms: {
|
|
108
|
+
allowedBannerImageHosts: string[];
|
|
109
|
+
};
|
|
110
|
+
activeBrand?: string | undefined;
|
|
111
|
+
kyc?: {
|
|
112
|
+
gateWithdrawals: boolean;
|
|
113
|
+
provider?: string | undefined;
|
|
114
|
+
webhookSecretEnv?: string | undefined;
|
|
115
|
+
reverifyThresholds?: Record<string, string> | undefined;
|
|
116
|
+
} | undefined;
|
|
117
|
+
autoWithdrawal?: {
|
|
118
|
+
enabled: boolean;
|
|
119
|
+
dailyCapAmount?: string | undefined;
|
|
120
|
+
dailyCapCount?: number | undefined;
|
|
121
|
+
} | undefined;
|
|
122
|
+
wallet?: {
|
|
123
|
+
cryptoCurrencies?: string[] | undefined;
|
|
124
|
+
treasuryRefs?: Record<string, string> | undefined;
|
|
125
|
+
sweep?: {
|
|
126
|
+
cron: string;
|
|
127
|
+
feeMultiple: string;
|
|
128
|
+
batchSize: number;
|
|
129
|
+
concurrency: number;
|
|
130
|
+
unknownAfterMinutes: number;
|
|
131
|
+
staleRunAfterMinutes: number;
|
|
132
|
+
} | undefined;
|
|
133
|
+
reconciliation?: {
|
|
134
|
+
cron: string;
|
|
135
|
+
lookbackHours: number;
|
|
136
|
+
batchSize: number;
|
|
137
|
+
stuckAfterMinutes: number;
|
|
138
|
+
staleRunAfterMinutes: number;
|
|
139
|
+
alertThreshold: number;
|
|
140
|
+
} | undefined;
|
|
141
|
+
} | undefined;
|
|
142
|
+
exchangeRate?: {
|
|
143
|
+
pivot: string;
|
|
144
|
+
freshTtlMs: number;
|
|
145
|
+
hardMaxAgeMs: number;
|
|
146
|
+
providerTimeoutMs: number;
|
|
147
|
+
} | undefined;
|
|
148
|
+
registration?: {
|
|
149
|
+
termsVersion: string;
|
|
150
|
+
requireEmailVerification: boolean;
|
|
151
|
+
} | undefined;
|
|
152
|
+
notifications?: {
|
|
153
|
+
retention?: {
|
|
154
|
+
days: number;
|
|
155
|
+
cron: string;
|
|
156
|
+
} | undefined;
|
|
157
|
+
} | undefined;
|
|
158
|
+
supportedLanguages?: string[] | undefined;
|
|
159
|
+
displayCurrencies?: string[] | undefined;
|
|
160
|
+
}, string>;
|
|
161
|
+
PLAYER_ACTIVITY_TRACKER: import("@openora/core/contracts").Token<import("@openora/core/contracts").PlayerActivityTracker>;
|
|
162
|
+
PLAYER_PROVISIONING: import("@openora/core/contracts").Token<import("@openora/core/contracts").PlayerProvisioning>;
|
|
163
|
+
PLAYER_TAGS: import("@openora/core/contracts").Token<import("@openora/core/contracts").PlayerTags>;
|
|
164
|
+
PLAY_ELIGIBILITY: import("@openora/core/contracts").Token<import("@openora/core/contracts").PlayEligibilityPort>;
|
|
165
|
+
RATE_LIMITER: import("@openora/core/contracts").Token<import("@openora/core/contracts").RateLimiterAdapter<`register:${string}` | `login:${string}` | `enable2fa:${string}` | `verify2fa:${string}` | `disable2fa:${string}` | `pwreset-req:${string}` | `pwreset-verify:${string}` | `pwreset:${string}` | `change-password:${string}` | `email-verify:${string}` | `verify-email:${string}` | `wallet-mutation:${string}` | `wallet-webhook:${string}` | `chat-room-join:${string}` | `chat-send:${string}` | `report-access-denied:${string}`>>;
|
|
166
|
+
REALTIME_CLIENT_AUTHORIZER: import("@openora/core/contracts").Token<import("@openora/core/contracts").RealtimeClientAuthorizer>;
|
|
167
|
+
REALTIME_TRANSPORT: import("@openora/core/contracts").Token<import("@openora/core/contracts").RealtimeTransport>;
|
|
168
|
+
RG_LIMITS: import("@openora/core/contracts").Token<import("@openora/core/contracts").RgLimitsPort>;
|
|
169
|
+
RNG_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").RngAdapter>;
|
|
170
|
+
SESSION_COMMANDS: import("@openora/core/contracts").Token<import("@openora/core/contracts").SessionCommands>;
|
|
171
|
+
USER_COMMANDS: import("@openora/core/contracts").Token<import("@openora/core/contracts").UserCommands>;
|
|
172
|
+
SMS_ADAPTER: import("@openora/core/contracts").Token<import("@openora/core/contracts").SmsAdapter>;
|
|
173
|
+
SOCIAL_COMMANDS: import("@openora/core/contracts").Token<import("@openora/core/contracts").SocialCommands>;
|
|
174
|
+
TAG_EVALUATION_COMMANDS: import("@openora/core/contracts").Token<import("@openora/core/contracts").TagEvaluationCommands>;
|
|
175
|
+
WALLET_ASSET_CATALOG: import("@openora/core/contracts").Token<import("@openora/core/contracts").WalletAssetCatalog, string>;
|
|
176
|
+
WALLET_COMMANDS: import("@openora/core/contracts").Token<import("@openora/core/contracts").WalletCommands>;
|
|
177
|
+
WALLET_READER: import("@openora/core/contracts").Token<import("@openora/core/contracts").WalletReader, string>;
|
|
178
|
+
}>) => void;
|
|
179
|
+
};
|
|
180
|
+
export default _default;
|
|
181
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/mail/plugin.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,wBAiE8C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ADMIN_USER_DIRECTORY, AUDIT_WRITER, EMAIL_SENDER, EMAIL_TEMPLATE_RENDERER, JOB_QUEUE, MAIL_DISPATCH, } from '@openora/core/contracts';
|
|
2
|
+
import { createLogger } from '@openora/core/server';
|
|
3
|
+
import { MailService } from './service/mail.service.js';
|
|
4
|
+
import { MIN_MAIL_ENCRYPTION_SECRET_LENGTH } from './service/mail-payload.service.js';
|
|
5
|
+
import { DefaultEmailTemplateRenderer } from './adapters/default-email-template-renderer.js';
|
|
6
|
+
import { StdoutEmailSender } from './adapters/stdout-email-sender.js';
|
|
7
|
+
import { EncryptedMailSendJobSchema, MAIL_SEND_QUEUE } from './contract/index.js';
|
|
8
|
+
const logger = createLogger('mail');
|
|
9
|
+
export default {
|
|
10
|
+
id: 'mail',
|
|
11
|
+
register(ctx) {
|
|
12
|
+
const encryptionSecret = process.env['AUTH_SECRET'] ?? '';
|
|
13
|
+
if (encryptionSecret.length < MIN_MAIL_ENCRYPTION_SECRET_LENGTH) {
|
|
14
|
+
throw new Error(`mail: AUTH_SECRET must be at least ${MIN_MAIL_ENCRYPTION_SECRET_LENGTH} characters - mail-send job payloads (OTPs, invitation tokens) are encrypted with it`);
|
|
15
|
+
}
|
|
16
|
+
let svcRef = null;
|
|
17
|
+
const mailService = (c) => (svcRef ??= new MailService({
|
|
18
|
+
sender: c.get(EMAIL_SENDER),
|
|
19
|
+
renderer: c.get(EMAIL_TEMPLATE_RENDERER),
|
|
20
|
+
directory: c.get(ADMIN_USER_DIRECTORY),
|
|
21
|
+
jobQueue: c.get(JOB_QUEUE),
|
|
22
|
+
audit: c.has(AUDIT_WRITER) ? c.get(AUDIT_WRITER) : null,
|
|
23
|
+
encryptionSecret,
|
|
24
|
+
}));
|
|
25
|
+
ctx.provide(EMAIL_SENDER, () => new StdoutEmailSender());
|
|
26
|
+
ctx.provide(EMAIL_TEMPLATE_RENDERER, () => new DefaultEmailTemplateRenderer());
|
|
27
|
+
ctx.provide(MAIL_DISPATCH, (c) => {
|
|
28
|
+
const svc = mailService(c);
|
|
29
|
+
return {
|
|
30
|
+
toUser: (input) => svc.enqueueToUser(input),
|
|
31
|
+
toAddress: (input) => svc.enqueueToAddress(input),
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
ctx.routers.add('mail', (c) => {
|
|
35
|
+
if (c.get(EMAIL_SENDER) instanceof StdoutEmailSender) {
|
|
36
|
+
const msg = 'mail: no EMAIL_SENDER overlay bound. StdoutEmailSender only logs metadata and never ' +
|
|
37
|
+
'delivers - bind a real EMAIL_SENDER (SMTP/SES/Postmark) in an overlay loaded after the mail plugin.';
|
|
38
|
+
if (process.env['NODE_ENV'] === 'production') {
|
|
39
|
+
throw new Error(msg);
|
|
40
|
+
}
|
|
41
|
+
logger.warn(msg);
|
|
42
|
+
}
|
|
43
|
+
mailService(c);
|
|
44
|
+
return {};
|
|
45
|
+
});
|
|
46
|
+
ctx.jobs.worker({
|
|
47
|
+
queue: MAIL_SEND_QUEUE,
|
|
48
|
+
schema: EncryptedMailSendJobSchema,
|
|
49
|
+
options: { concurrency: 5 },
|
|
50
|
+
handler: async ({ payload, attempt }) => {
|
|
51
|
+
if (!svcRef) {
|
|
52
|
+
throw new Error('mail: service not constructed yet');
|
|
53
|
+
}
|
|
54
|
+
await svcRef.deliverEncrypted(payload, attempt);
|
|
55
|
+
},
|
|
56
|
+
onDeadLetter: (jobCtx, error) => {
|
|
57
|
+
if (!svcRef) {
|
|
58
|
+
logger.error({ err: error }, 'mail delivery exhausted retries before service init');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
return svcRef.onEncryptedDeliveryExhausted(jobCtx.payload, error, jobCtx.attempt);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/mail/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type EncryptedMailSendJob, type MailSendJob } from '../contract/index.js';
|
|
2
|
+
export declare const MIN_MAIL_ENCRYPTION_SECRET_LENGTH = 32;
|
|
3
|
+
export type MailPayloadCipher = {
|
|
4
|
+
encrypt(job: MailSendJob): EncryptedMailSendJob;
|
|
5
|
+
decrypt(job: EncryptedMailSendJob): MailSendJob;
|
|
6
|
+
};
|
|
7
|
+
export declare function createMailPayloadCipher(secret: string): MailPayloadCipher;
|
|
8
|
+
//# sourceMappingURL=mail-payload.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mail-payload.service.d.ts","sourceRoot":"","sources":["../../../src/mail/service/mail-payload.service.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAI9B,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,oBAAoB,CAAC;IAChD,OAAO,CAAC,GAAG,EAAE,oBAAoB,GAAG,WAAW,CAAC;CACjD,CAAC;AAOF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAiCzE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, hkdfSync, randomBytes } from 'node:crypto';
|
|
2
|
+
import { MailSendJobSchema, } from '../contract/index.js';
|
|
3
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
4
|
+
const IV_BYTES = 12;
|
|
5
|
+
export const MIN_MAIL_ENCRYPTION_SECRET_LENGTH = 32;
|
|
6
|
+
const MAIL_PAYLOAD_KEY_INFO = 'openora:mail-payload:v1';
|
|
7
|
+
const toKey = (secret) => Buffer.from(hkdfSync('sha256', secret, Buffer.alloc(0), MAIL_PAYLOAD_KEY_INFO, 32));
|
|
8
|
+
export function createMailPayloadCipher(secret) {
|
|
9
|
+
if (secret.length < MIN_MAIL_ENCRYPTION_SECRET_LENGTH) {
|
|
10
|
+
throw new Error('AUTH_SECRET must have at least 32 characters to encrypt mail jobs');
|
|
11
|
+
}
|
|
12
|
+
const key = toKey(secret);
|
|
13
|
+
return {
|
|
14
|
+
encrypt(job) {
|
|
15
|
+
const iv = randomBytes(IV_BYTES);
|
|
16
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
17
|
+
const ciphertext = Buffer.concat([
|
|
18
|
+
cipher.update(JSON.stringify(job), 'utf8'),
|
|
19
|
+
cipher.final(),
|
|
20
|
+
]).toString('base64url');
|
|
21
|
+
return {
|
|
22
|
+
ciphertext,
|
|
23
|
+
iv: iv.toString('base64url'),
|
|
24
|
+
tag: cipher.getAuthTag().toString('base64url'),
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
decrypt(job) {
|
|
28
|
+
try {
|
|
29
|
+
const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(job.iv, 'base64url'));
|
|
30
|
+
decipher.setAuthTag(Buffer.from(job.tag, 'base64url'));
|
|
31
|
+
const plaintext = Buffer.concat([
|
|
32
|
+
decipher.update(Buffer.from(job.ciphertext, 'base64url')),
|
|
33
|
+
decipher.final(),
|
|
34
|
+
]).toString('utf8');
|
|
35
|
+
return MailSendJobSchema.parse(JSON.parse(plaintext));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
throw new Error('mail job payload could not be decrypted');
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=mail-payload.service.js.map
|