@endora-commerce/mod-newsletter 0.100.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/LICENSE +21 -0
- package/README.md +66 -0
- package/dist/admin/api/newsletter-client.d.ts +64 -0
- package/dist/admin/api/newsletter-client.d.ts.map +1 -0
- package/dist/admin/api/newsletter-client.js +71 -0
- package/dist/admin/api/newsletter-client.js.map +1 -0
- package/dist/admin/email-variables.d.ts +21 -0
- package/dist/admin/email-variables.d.ts.map +1 -0
- package/dist/admin/email-variables.js +48 -0
- package/dist/admin/email-variables.js.map +1 -0
- package/dist/admin/index.d.ts +44 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +149 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/AutomationBuilder.d.ts +8 -0
- package/dist/admin/pages/AutomationBuilder.d.ts.map +1 -0
- package/dist/admin/pages/AutomationBuilder.js +131 -0
- package/dist/admin/pages/AutomationBuilder.js.map +1 -0
- package/dist/admin/pages/AutomationsPage.d.ts +8 -0
- package/dist/admin/pages/AutomationsPage.d.ts.map +1 -0
- package/dist/admin/pages/AutomationsPage.js +43 -0
- package/dist/admin/pages/AutomationsPage.js.map +1 -0
- package/dist/admin/pages/BlocksPage.d.ts +8 -0
- package/dist/admin/pages/BlocksPage.d.ts.map +1 -0
- package/dist/admin/pages/BlocksPage.js +110 -0
- package/dist/admin/pages/BlocksPage.js.map +1 -0
- package/dist/admin/pages/CampaignEditor.d.ts +8 -0
- package/dist/admin/pages/CampaignEditor.d.ts.map +1 -0
- package/dist/admin/pages/CampaignEditor.js +144 -0
- package/dist/admin/pages/CampaignEditor.js.map +1 -0
- package/dist/admin/pages/CampaignStats.d.ts +8 -0
- package/dist/admin/pages/CampaignStats.d.ts.map +1 -0
- package/dist/admin/pages/CampaignStats.js +45 -0
- package/dist/admin/pages/CampaignStats.js.map +1 -0
- package/dist/admin/pages/CampaignsPage.d.ts +8 -0
- package/dist/admin/pages/CampaignsPage.d.ts.map +1 -0
- package/dist/admin/pages/CampaignsPage.js +28 -0
- package/dist/admin/pages/CampaignsPage.js.map +1 -0
- package/dist/admin/pages/ProviderSettingsPage.d.ts +8 -0
- package/dist/admin/pages/ProviderSettingsPage.d.ts.map +1 -0
- package/dist/admin/pages/ProviderSettingsPage.js +64 -0
- package/dist/admin/pages/ProviderSettingsPage.js.map +1 -0
- package/dist/admin/pages/SubscribersPage.d.ts +8 -0
- package/dist/admin/pages/SubscribersPage.d.ts.map +1 -0
- package/dist/admin/pages/SubscribersPage.js +55 -0
- package/dist/admin/pages/SubscribersPage.js.map +1 -0
- package/dist/admin/pages/TagsPage.d.ts +8 -0
- package/dist/admin/pages/TagsPage.d.ts.map +1 -0
- package/dist/admin/pages/TagsPage.js +114 -0
- package/dist/admin/pages/TagsPage.js.map +1 -0
- package/dist/backend/entities/newsletter-automation-run.entity.d.ts +19 -0
- package/dist/backend/entities/newsletter-automation-run.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-automation-run.entity.js +72 -0
- package/dist/backend/entities/newsletter-automation-run.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-automation.entity.d.ts +22 -0
- package/dist/backend/entities/newsletter-automation.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-automation.entity.js +86 -0
- package/dist/backend/entities/newsletter-automation.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-campaign-subscriber.entity.d.ts +6 -0
- package/dist/backend/entities/newsletter-campaign-subscriber.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-campaign-subscriber.entity.js +30 -0
- package/dist/backend/entities/newsletter-campaign-subscriber.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-campaign.entity.d.ts +22 -0
- package/dist/backend/entities/newsletter-campaign.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-campaign.entity.js +102 -0
- package/dist/backend/entities/newsletter-campaign.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-custom-field.entity.d.ts +12 -0
- package/dist/backend/entities/newsletter-custom-field.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-custom-field.entity.js +53 -0
- package/dist/backend/entities/newsletter-custom-field.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-email-block-sales-channel.entity.d.ts +7 -0
- package/dist/backend/entities/newsletter-email-block-sales-channel.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-email-block-sales-channel.entity.js +35 -0
- package/dist/backend/entities/newsletter-email-block-sales-channel.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-email-block.entity.d.ts +21 -0
- package/dist/backend/entities/newsletter-email-block.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-email-block.entity.js +78 -0
- package/dist/backend/entities/newsletter-email-block.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-engagement-event.entity.d.ts +12 -0
- package/dist/backend/entities/newsletter-engagement-event.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-engagement-event.entity.js +54 -0
- package/dist/backend/entities/newsletter-engagement-event.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-send-record.entity.d.ts +23 -0
- package/dist/backend/entities/newsletter-send-record.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-send-record.entity.js +89 -0
- package/dist/backend/entities/newsletter-send-record.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-subscriber-tag.entity.d.ts +6 -0
- package/dist/backend/entities/newsletter-subscriber-tag.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-subscriber-tag.entity.js +31 -0
- package/dist/backend/entities/newsletter-subscriber-tag.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-subscriber.entity.d.ts +63 -0
- package/dist/backend/entities/newsletter-subscriber.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-subscriber.entity.js +147 -0
- package/dist/backend/entities/newsletter-subscriber.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-suppression.entity.d.ts +14 -0
- package/dist/backend/entities/newsletter-suppression.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-suppression.entity.js +51 -0
- package/dist/backend/entities/newsletter-suppression.entity.js.map +1 -0
- package/dist/backend/entities/newsletter-tag.entity.d.ts +12 -0
- package/dist/backend/entities/newsletter-tag.entity.d.ts.map +1 -0
- package/dist/backend/entities/newsletter-tag.entity.js +53 -0
- package/dist/backend/entities/newsletter-tag.entity.js.map +1 -0
- package/dist/backend/index.d.ts +120 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +139 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +114 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +171 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +27 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +118 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.self.d.ts +15 -0
- package/dist/backend/routes.self.d.ts.map +1 -0
- package/dist/backend/routes.self.js +28 -0
- package/dist/backend/routes.self.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +24 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +79 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/audience-resolver.d.ts +20 -0
- package/dist/backend/services/audience-resolver.d.ts.map +1 -0
- package/dist/backend/services/audience-resolver.js +41 -0
- package/dist/backend/services/audience-resolver.js.map +1 -0
- package/dist/backend/services/automation.service.d.ts +58 -0
- package/dist/backend/services/automation.service.d.ts.map +1 -0
- package/dist/backend/services/automation.service.js +301 -0
- package/dist/backend/services/automation.service.js.map +1 -0
- package/dist/backend/services/campaign-dispatch.service.d.ts +50 -0
- package/dist/backend/services/campaign-dispatch.service.d.ts.map +1 -0
- package/dist/backend/services/campaign-dispatch.service.js +130 -0
- package/dist/backend/services/campaign-dispatch.service.js.map +1 -0
- package/dist/backend/services/campaign.service.d.ts +40 -0
- package/dist/backend/services/campaign.service.d.ts.map +1 -0
- package/dist/backend/services/campaign.service.js +195 -0
- package/dist/backend/services/campaign.service.js.map +1 -0
- package/dist/backend/services/consent-block-seeder.d.ts +30 -0
- package/dist/backend/services/consent-block-seeder.d.ts.map +1 -0
- package/dist/backend/services/consent-block-seeder.js +52 -0
- package/dist/backend/services/consent-block-seeder.js.map +1 -0
- package/dist/backend/services/content.service.d.ts +52 -0
- package/dist/backend/services/content.service.d.ts.map +1 -0
- package/dist/backend/services/content.service.js +48 -0
- package/dist/backend/services/content.service.js.map +1 -0
- package/dist/backend/services/custom-field.service.d.ts +16 -0
- package/dist/backend/services/custom-field.service.d.ts.map +1 -0
- package/dist/backend/services/custom-field.service.js +67 -0
- package/dist/backend/services/custom-field.service.js.map +1 -0
- package/dist/backend/services/email-block.service.d.ts +26 -0
- package/dist/backend/services/email-block.service.d.ts.map +1 -0
- package/dist/backend/services/email-block.service.js +120 -0
- package/dist/backend/services/email-block.service.js.map +1 -0
- package/dist/backend/services/opt-in.service.d.ts +25 -0
- package/dist/backend/services/opt-in.service.d.ts.map +1 -0
- package/dist/backend/services/opt-in.service.js +46 -0
- package/dist/backend/services/opt-in.service.js.map +1 -0
- package/dist/backend/services/provider/console-provider.d.ts +32 -0
- package/dist/backend/services/provider/console-provider.d.ts.map +1 -0
- package/dist/backend/services/provider/console-provider.js +31 -0
- package/dist/backend/services/provider/console-provider.js.map +1 -0
- package/dist/backend/services/provider/provider-registry.d.ts +51 -0
- package/dist/backend/services/provider/provider-registry.d.ts.map +1 -0
- package/dist/backend/services/provider/provider-registry.js +84 -0
- package/dist/backend/services/provider/provider-registry.js.map +1 -0
- package/dist/backend/services/provider/smtp-provider.d.ts +30 -0
- package/dist/backend/services/provider/smtp-provider.d.ts.map +1 -0
- package/dist/backend/services/provider/smtp-provider.js +42 -0
- package/dist/backend/services/provider/smtp-provider.js.map +1 -0
- package/dist/backend/services/provider-admin.service.d.ts +39 -0
- package/dist/backend/services/provider-admin.service.d.ts.map +1 -0
- package/dist/backend/services/provider-admin.service.js +59 -0
- package/dist/backend/services/provider-admin.service.js.map +1 -0
- package/dist/backend/services/provider-admin.types.d.ts +6 -0
- package/dist/backend/services/provider-admin.types.d.ts.map +1 -0
- package/dist/backend/services/provider-admin.types.js +2 -0
- package/dist/backend/services/provider-admin.types.js.map +1 -0
- package/dist/backend/services/queues/newsletter-queues.d.ts +34 -0
- package/dist/backend/services/queues/newsletter-queues.d.ts.map +1 -0
- package/dist/backend/services/queues/newsletter-queues.js +58 -0
- package/dist/backend/services/queues/newsletter-queues.js.map +1 -0
- package/dist/backend/services/self.service.d.ts +17 -0
- package/dist/backend/services/self.service.d.ts.map +1 -0
- package/dist/backend/services/self.service.js +44 -0
- package/dist/backend/services/self.service.js.map +1 -0
- package/dist/backend/services/stats.service.d.ts +10 -0
- package/dist/backend/services/stats.service.d.ts.map +1 -0
- package/dist/backend/services/stats.service.js +45 -0
- package/dist/backend/services/stats.service.js.map +1 -0
- package/dist/backend/services/subscriber-admin.service.d.ts +26 -0
- package/dist/backend/services/subscriber-admin.service.d.ts.map +1 -0
- package/dist/backend/services/subscriber-admin.service.js +163 -0
- package/dist/backend/services/subscriber-admin.service.js.map +1 -0
- package/dist/backend/services/subscriber.service.d.ts +91 -0
- package/dist/backend/services/subscriber.service.d.ts.map +1 -0
- package/dist/backend/services/subscriber.service.js +280 -0
- package/dist/backend/services/subscriber.service.js.map +1 -0
- package/dist/backend/services/tag.service.d.ts +16 -0
- package/dist/backend/services/tag.service.d.ts.map +1 -0
- package/dist/backend/services/tag.service.js +79 -0
- package/dist/backend/services/tag.service.js.map +1 -0
- package/dist/backend/services/token.helper.d.ts +32 -0
- package/dist/backend/services/token.helper.d.ts.map +1 -0
- package/dist/backend/services/token.helper.js +76 -0
- package/dist/backend/services/token.helper.js.map +1 -0
- package/dist/backend/services/tracking.service.d.ts +14 -0
- package/dist/backend/services/tracking.service.d.ts.map +1 -0
- package/dist/backend/services/tracking.service.js +45 -0
- package/dist/backend/services/tracking.service.js.map +1 -0
- package/dist/manifest.d.ts +192 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +211 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260629T200954_newsletter_init.d.ts +6 -0
- package/dist/migrations/20260629T200954_newsletter_init.d.ts.map +1 -0
- package/dist/migrations/20260629T200954_newsletter_init.js +261 -0
- package/dist/migrations/20260629T200954_newsletter_init.js.map +1 -0
- package/dist/migrations/20260830T212736_newsletter_organization_attribution.d.ts +116 -0
- package/dist/migrations/20260830T212736_newsletter_organization_attribution.d.ts.map +1 -0
- package/dist/migrations/20260830T212736_newsletter_organization_attribution.js +186 -0
- package/dist/migrations/20260830T212736_newsletter_organization_attribution.js.map +1 -0
- package/dist/migrations/20260903T101752_newsletter_namespace_block_names.d.ts +6 -0
- package/dist/migrations/20260903T101752_newsletter_namespace_block_names.d.ts.map +1 -0
- package/dist/migrations/20260903T101752_newsletter_namespace_block_names.js +58 -0
- package/dist/migrations/20260903T101752_newsletter_namespace_block_names.js.map +1 -0
- package/dist/migrations/20260912T125702_newsletter_subscriber_tenant_scope_index.d.ts +23 -0
- package/dist/migrations/20260912T125702_newsletter_subscriber_tenant_scope_index.d.ts.map +1 -0
- package/dist/migrations/20260912T125702_newsletter_subscriber_tenant_scope_index.js +27 -0
- package/dist/migrations/20260912T125702_newsletter_subscriber_tenant_scope_index.js.map +1 -0
- package/dist/migrations/index.d.ts +30 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +35 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/newsletter.md +94 -0
- package/i18n/en.json +27 -0
- package/i18n/pl.json +27 -0
- package/package.json +119 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { NewsletterSendMessage, NewsletterSendProvider } from '@endora-commerce/contracts';
|
|
2
|
+
export interface SmtpProviderConfig {
|
|
3
|
+
host: string;
|
|
4
|
+
port: number;
|
|
5
|
+
secure: boolean;
|
|
6
|
+
username: string;
|
|
7
|
+
/** Decrypted secret (from Settings `secret` value type). */
|
|
8
|
+
password: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Bulk SMTP provider (feature 048, research R7). Built on the already-present
|
|
12
|
+
* `nodemailer`, it reaches Amazon SES (SMTP interface), Mailgun, Postmark, or
|
|
13
|
+
* any relay. This transport is OWNED by the newsletter module and is
|
|
14
|
+
* independent of the transactional `email` module's mailer. Throughput
|
|
15
|
+
* throttling is applied by the BullMQ send-worker limiter, not here.
|
|
16
|
+
*/
|
|
17
|
+
export declare class SmtpProvider implements NewsletterSendProvider {
|
|
18
|
+
private readonly transport;
|
|
19
|
+
constructor(config: SmtpProviderConfig);
|
|
20
|
+
send(msg: NewsletterSendMessage): Promise<{
|
|
21
|
+
providerMessageId?: string;
|
|
22
|
+
}>;
|
|
23
|
+
verify(): Promise<{
|
|
24
|
+
ok: true;
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
error: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=smtp-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smtp-provider.d.ts","sourceRoot":"","sources":["../../../../src/backend/services/provider/smtp-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEhG,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,qBAAa,YAAa,YAAW,sBAAsB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;gBAE5B,MAAM,EAAE,kBAAkB;IAShC,IAAI,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAczE,MAAM,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAQrE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import nodemailer, {} from 'nodemailer';
|
|
2
|
+
/**
|
|
3
|
+
* Bulk SMTP provider (feature 048, research R7). Built on the already-present
|
|
4
|
+
* `nodemailer`, it reaches Amazon SES (SMTP interface), Mailgun, Postmark, or
|
|
5
|
+
* any relay. This transport is OWNED by the newsletter module and is
|
|
6
|
+
* independent of the transactional `email` module's mailer. Throughput
|
|
7
|
+
* throttling is applied by the BullMQ send-worker limiter, not here.
|
|
8
|
+
*/
|
|
9
|
+
export class SmtpProvider {
|
|
10
|
+
transport;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.transport = nodemailer.createTransport({
|
|
13
|
+
host: config.host,
|
|
14
|
+
port: config.port,
|
|
15
|
+
secure: config.secure,
|
|
16
|
+
auth: config.username ? { user: config.username, pass: config.password } : undefined,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async send(msg) {
|
|
20
|
+
const from = msg.fromName ? `"${msg.fromName}" <${msg.fromEmail}>` : msg.fromEmail;
|
|
21
|
+
const info = await this.transport.sendMail({
|
|
22
|
+
from,
|
|
23
|
+
to: msg.to,
|
|
24
|
+
subject: msg.subject,
|
|
25
|
+
text: msg.text,
|
|
26
|
+
html: msg.html,
|
|
27
|
+
messageId: msg.messageId,
|
|
28
|
+
headers: msg.headers,
|
|
29
|
+
});
|
|
30
|
+
return { providerMessageId: info.messageId ?? msg.messageId };
|
|
31
|
+
}
|
|
32
|
+
async verify() {
|
|
33
|
+
try {
|
|
34
|
+
await this.transport.verify();
|
|
35
|
+
return { ok: true };
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=smtp-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smtp-provider.js","sourceRoot":"","sources":["../../../../src/backend/services/provider/smtp-provider.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,EAAE,EAAoB,MAAM,YAAY,CAAC;AAY1D;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IACN,SAAS,CAAc;IAExC,YAAY,MAA0B;QACpC,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,eAAe,CAAC;YAC1C,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS;SACrF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAA0B;QACnC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;QACnF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;YACzC,IAAI;YACJ,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC,CAAC;QACH,OAAO,EAAE,iBAAiB,EAAE,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,MAAM;QACV,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC9B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAChF,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ProviderConfig, type PutProviderRequest } from '@endora-commerce/contracts';
|
|
2
|
+
import type { SettingsReadPort } from '@endora-commerce/platform/kernel';
|
|
3
|
+
import type { AdminAuditContext } from './provider-admin.types.js';
|
|
4
|
+
import type { NewsletterProviderRegistry } from './provider/provider-registry.js';
|
|
5
|
+
/** Minimal write surface of the Settings admin service used here. */
|
|
6
|
+
export interface SettingsWriter {
|
|
7
|
+
setValueForAllChannels(code: string, rawValue: unknown, expectedVersion: string | null, actor: AdminAuditContext): Promise<unknown>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Provider configuration admin (feature 048, US7; feature 058). The SMTP
|
|
11
|
+
* connection + credentials now live in a reusable `email_adapter` credential
|
|
12
|
+
* configuration referenced by `newsletter.email_credentials` (managed on the
|
|
13
|
+
* Credentials / Settings screen). This surface manages only the non-credential
|
|
14
|
+
* sender + throttle config, and exposes a `test()` that resolves the referenced
|
|
15
|
+
* provider and verifies it.
|
|
16
|
+
*/
|
|
17
|
+
export declare class NewsletterProviderAdminService {
|
|
18
|
+
private readonly settings;
|
|
19
|
+
private readonly writer;
|
|
20
|
+
private readonly providers;
|
|
21
|
+
constructor(settings: SettingsReadPort, writer: SettingsWriter, providers: NewsletterProviderRegistry);
|
|
22
|
+
/**
|
|
23
|
+
* Platform-wide reads (feature 072, D-41), the exact mirror of this class's
|
|
24
|
+
* own writes: `putConfig` below goes through `setValueForAllChannels`, so
|
|
25
|
+
* reading at a channel could only ever return what the global tier already
|
|
26
|
+
* holds — when it did not throw on a sentinel channel id first.
|
|
27
|
+
*/
|
|
28
|
+
private str;
|
|
29
|
+
private num;
|
|
30
|
+
getConfig(): Promise<ProviderConfig>;
|
|
31
|
+
putConfig(input: PutProviderRequest, actor: AdminAuditContext): Promise<ProviderConfig>;
|
|
32
|
+
test(): Promise<{
|
|
33
|
+
ok: true;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
error: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=provider-admin.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-admin.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/provider-admin.service.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACpH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAElF,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,sBAAsB,CACpB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,8BAA8B;IAEvC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,0BAA0B;IAGxD;;;;;OAKG;IACH,OAAO,CAAC,GAAG;IAGX,OAAO,CAAC,GAAG;IAIL,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;IAapC,SAAS,CAAC,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IAYvF,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAInE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { NEWSLETTER_SETTING_CODES } from '@endora-commerce/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* Provider configuration admin (feature 048, US7; feature 058). The SMTP
|
|
5
|
+
* connection + credentials now live in a reusable `email_adapter` credential
|
|
6
|
+
* configuration referenced by `newsletter.email_credentials` (managed on the
|
|
7
|
+
* Credentials / Settings screen). This surface manages only the non-credential
|
|
8
|
+
* sender + throttle config, and exposes a `test()` that resolves the referenced
|
|
9
|
+
* provider and verifies it.
|
|
10
|
+
*/
|
|
11
|
+
export class NewsletterProviderAdminService {
|
|
12
|
+
settings;
|
|
13
|
+
writer;
|
|
14
|
+
providers;
|
|
15
|
+
constructor(settings, writer, providers) {
|
|
16
|
+
this.settings = settings;
|
|
17
|
+
this.writer = writer;
|
|
18
|
+
this.providers = providers;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Platform-wide reads (feature 072, D-41), the exact mirror of this class's
|
|
22
|
+
* own writes: `putConfig` below goes through `setValueForAllChannels`, so
|
|
23
|
+
* reading at a channel could only ever return what the global tier already
|
|
24
|
+
* holds — when it did not throw on a sentinel channel id first.
|
|
25
|
+
*/
|
|
26
|
+
str(code) {
|
|
27
|
+
return this.settings.get(code, null, z.string()).catch(() => '');
|
|
28
|
+
}
|
|
29
|
+
num(code, fallback) {
|
|
30
|
+
return this.settings.get(code, null, z.number()).catch(() => fallback);
|
|
31
|
+
}
|
|
32
|
+
async getConfig() {
|
|
33
|
+
const C = NEWSLETTER_SETTING_CODES;
|
|
34
|
+
const [fromEmail, fromName, rate] = await Promise.all([
|
|
35
|
+
this.str(C.SENDER_FROM_EMAIL),
|
|
36
|
+
this.str(C.SENDER_FROM_NAME),
|
|
37
|
+
this.num(C.RATE_LIMIT_PER_SECOND, 14),
|
|
38
|
+
]);
|
|
39
|
+
return {
|
|
40
|
+
sender: { fromEmail, fromName },
|
|
41
|
+
rateLimitPerSecond: rate,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async putConfig(input, actor) {
|
|
45
|
+
const C = NEWSLETTER_SETTING_CODES;
|
|
46
|
+
const w = (code, value) => this.writer.setValueForAllChannels(code, value, null, actor);
|
|
47
|
+
await Promise.all([
|
|
48
|
+
w(C.SENDER_FROM_EMAIL, input.sender.fromEmail),
|
|
49
|
+
w(C.SENDER_FROM_NAME, input.sender.fromName),
|
|
50
|
+
w(C.RATE_LIMIT_PER_SECOND, input.rateLimitPerSecond),
|
|
51
|
+
]);
|
|
52
|
+
return this.getConfig();
|
|
53
|
+
}
|
|
54
|
+
async test() {
|
|
55
|
+
const provider = await this.providers.resolveProvider();
|
|
56
|
+
return provider.verify();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=provider-admin.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-admin.service.js","sourceRoot":"","sources":["../../../src/backend/services/provider-admin.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAgD,MAAM,4BAA4B,CAAC;AAepH;;;;;;;GAOG;AACH,MAAM,OAAO,8BAA8B;IAEtB;IACA;IACA;IAHnB,YACmB,QAA0B,EAC1B,MAAsB,EACtB,SAAqC;QAFrC,aAAQ,GAAR,QAAQ,CAAkB;QAC1B,WAAM,GAAN,MAAM,CAAgB;QACtB,cAAS,GAAT,SAAS,CAA4B;IACrD,CAAC;IAEJ;;;;;OAKG;IACK,GAAG,CAAC,IAAY;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IACO,GAAG,CAAC,IAAY,EAAE,QAAgB;QACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,CAAC,GAAG,wBAAwB,CAAC;QACnC,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACpD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,qBAAqB,EAAE,EAAE,CAAC;SACtC,CAAC,CAAC;QACH,OAAO;YACL,MAAM,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;YAC/B,kBAAkB,EAAE,IAAI;SACzB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAAyB,EAAE,KAAwB;QACjE,MAAM,CAAC,GAAG,wBAAwB,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,KAAc,EAAoB,EAAE,CAC3D,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/D,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;YAC9C,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;YAC5C,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE,KAAK,CAAC,kBAAkB,CAAC;SACrD,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;QACxD,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-admin.types.d.ts","sourceRoot":"","sources":["../../../src/backend/services/provider-admin.types.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-admin.types.js","sourceRoot":"","sources":["../../../src/backend/services/provider-admin.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Queue, Worker, type Processor, type QueueOptions, type WorkerOptions } from 'bullmq';
|
|
2
|
+
import type { Redis } from 'ioredis';
|
|
3
|
+
/**
|
|
4
|
+
* BullMQ queues for newsletter dispatch (feature 048, Principle X). Durable,
|
|
5
|
+
* Redis-backed, atomic-claim + idempotent handlers (the unique send-record row),
|
|
6
|
+
* producer-only-enqueue, and consumed by the separable `worker.ts` entrypoint.
|
|
7
|
+
*
|
|
8
|
+
* - `newsletter.campaign.plan` — one job per send/scheduled-fire; resolves the
|
|
9
|
+
* audience and claims + enqueues per-recipient send jobs.
|
|
10
|
+
* - `newsletter.send` — one job per claimed recipient; renders + dispatches.
|
|
11
|
+
* - `newsletter.automation.step` — one job per (run, step); send or delayed wait.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CAMPAIGN_PLAN_QUEUE = "newsletter.campaign.plan";
|
|
14
|
+
export declare const SEND_QUEUE = "newsletter.send";
|
|
15
|
+
export declare const AUTOMATION_STEP_QUEUE = "newsletter.automation.step";
|
|
16
|
+
export interface CampaignPlanJobData {
|
|
17
|
+
campaignId: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SendJobData {
|
|
20
|
+
recordId: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AutomationStepJobData {
|
|
23
|
+
runId: string;
|
|
24
|
+
stepIndex: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function createCampaignPlanQueue(redis: Redis, o?: Partial<QueueOptions>): Queue<CampaignPlanJobData>;
|
|
27
|
+
export declare function createSendQueue(redis: Redis, o?: Partial<QueueOptions>): Queue<SendJobData>;
|
|
28
|
+
export declare function createAutomationStepQueue(redis: Redis, o?: Partial<QueueOptions>): Queue<AutomationStepJobData>;
|
|
29
|
+
export declare function createCampaignPlanWorker(redis: Redis, processor: Processor<CampaignPlanJobData>, overrides?: Partial<WorkerOptions>): Worker<CampaignPlanJobData>;
|
|
30
|
+
export declare function createSendWorker(redis: Redis, processor: Processor<SendJobData>,
|
|
31
|
+
/** Per-second throughput cap (provider throttle, FR-033). */
|
|
32
|
+
ratePerSecond: number, overrides?: Partial<WorkerOptions>): Worker<SendJobData>;
|
|
33
|
+
export declare function createAutomationStepWorker(redis: Redis, processor: Processor<AutomationStepJobData>, overrides?: Partial<WorkerOptions>): Worker<AutomationStepJobData>;
|
|
34
|
+
//# sourceMappingURL=newsletter-queues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"newsletter-queues.d.ts","sourceRoot":"","sources":["../../../../src/backend/services/queues/newsletter-queues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC9F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGrC;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,6BAA6B,CAAC;AAC9D,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAC5C,eAAO,MAAM,qBAAqB,+BAA+B,CAAC;AAElE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAaD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAE3G;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAE3F;AACD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,KAAK,EACZ,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GACxB,KAAK,CAAC,qBAAqB,CAAC,CAE9B;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,mBAAmB,CAAC,EACzC,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GACjC,MAAM,CAAC,mBAAmB,CAAC,CAM7B;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,WAAW,CAAC;AACjC,6DAA6D;AAC7D,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GACjC,MAAM,CAAC,WAAW,CAAC,CAOrB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,qBAAqB,CAAC,EAC3C,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GACjC,MAAM,CAAC,qBAAqB,CAAC,CAM/B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Queue, Worker } from 'bullmq';
|
|
2
|
+
import { enterSystemScope } from '@endora-commerce/platform/kernel';
|
|
3
|
+
/**
|
|
4
|
+
* BullMQ queues for newsletter dispatch (feature 048, Principle X). Durable,
|
|
5
|
+
* Redis-backed, atomic-claim + idempotent handlers (the unique send-record row),
|
|
6
|
+
* producer-only-enqueue, and consumed by the separable `worker.ts` entrypoint.
|
|
7
|
+
*
|
|
8
|
+
* - `newsletter.campaign.plan` — one job per send/scheduled-fire; resolves the
|
|
9
|
+
* audience and claims + enqueues per-recipient send jobs.
|
|
10
|
+
* - `newsletter.send` — one job per claimed recipient; renders + dispatches.
|
|
11
|
+
* - `newsletter.automation.step` — one job per (run, step); send or delayed wait.
|
|
12
|
+
*/
|
|
13
|
+
export const CAMPAIGN_PLAN_QUEUE = 'newsletter.campaign.plan';
|
|
14
|
+
export const SEND_QUEUE = 'newsletter.send';
|
|
15
|
+
export const AUTOMATION_STEP_QUEUE = 'newsletter.automation.step';
|
|
16
|
+
const DEFAULT_JOB_OPTIONS = {
|
|
17
|
+
attempts: 5,
|
|
18
|
+
backoff: { type: 'exponential', delay: 2_000 },
|
|
19
|
+
removeOnComplete: { count: 1_000 },
|
|
20
|
+
removeOnFail: { count: 5_000 },
|
|
21
|
+
};
|
|
22
|
+
function makeQueue(name, redis, overrides) {
|
|
23
|
+
return new Queue(name, { connection: redis, defaultJobOptions: DEFAULT_JOB_OPTIONS, ...overrides });
|
|
24
|
+
}
|
|
25
|
+
export function createCampaignPlanQueue(redis, o) {
|
|
26
|
+
return makeQueue(CAMPAIGN_PLAN_QUEUE, redis, o);
|
|
27
|
+
}
|
|
28
|
+
export function createSendQueue(redis, o) {
|
|
29
|
+
return makeQueue(SEND_QUEUE, redis, o);
|
|
30
|
+
}
|
|
31
|
+
export function createAutomationStepQueue(redis, o) {
|
|
32
|
+
return makeQueue(AUTOMATION_STEP_QUEUE, redis, o);
|
|
33
|
+
}
|
|
34
|
+
export function createCampaignPlanWorker(redis, processor, overrides) {
|
|
35
|
+
return new Worker(CAMPAIGN_PLAN_QUEUE, (job) => enterSystemScope('newsletter campaign-plan', () => processor(job)), {
|
|
36
|
+
connection: redis,
|
|
37
|
+
concurrency: 4,
|
|
38
|
+
...overrides,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export function createSendWorker(redis, processor,
|
|
42
|
+
/** Per-second throughput cap (provider throttle, FR-033). */
|
|
43
|
+
ratePerSecond, overrides) {
|
|
44
|
+
return new Worker(SEND_QUEUE, (job) => enterSystemScope('newsletter send', () => processor(job)), {
|
|
45
|
+
connection: redis,
|
|
46
|
+
concurrency: 8,
|
|
47
|
+
limiter: { max: Math.max(1, ratePerSecond), duration: 1_000 },
|
|
48
|
+
...overrides,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function createAutomationStepWorker(redis, processor, overrides) {
|
|
52
|
+
return new Worker(AUTOMATION_STEP_QUEUE, (job) => enterSystemScope('newsletter automation-step', () => processor(job)), {
|
|
53
|
+
connection: redis,
|
|
54
|
+
concurrency: 4,
|
|
55
|
+
...overrides,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=newsletter-queues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"newsletter-queues.js","sourceRoot":"","sources":["../../../../src/backend/services/queues/newsletter-queues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAyD,MAAM,QAAQ,CAAC;AAG9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAC9D,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAC5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAalE,MAAM,mBAAmB,GAAG;IAC1B,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,EAAE,IAAI,EAAE,aAAsB,EAAE,KAAK,EAAE,KAAK,EAAE;IACvD,gBAAgB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;IAClC,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;CAC/B,CAAC;AAEF,SAAS,SAAS,CAAI,IAAY,EAAE,KAAY,EAAE,SAAiC;IACjF,OAAO,IAAI,KAAK,CAAI,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAY,EAAE,CAAyB;IAC7E,OAAO,SAAS,CAAsB,mBAAmB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACvE,CAAC;AACD,MAAM,UAAU,eAAe,CAAC,KAAY,EAAE,CAAyB;IACrE,OAAO,SAAS,CAAc,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACtD,CAAC;AACD,MAAM,UAAU,yBAAyB,CACvC,KAAY,EACZ,CAAyB;IAEzB,OAAO,SAAS,CAAwB,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,KAAY,EACZ,SAAyC,EACzC,SAAkC;IAElC,OAAO,IAAI,MAAM,CAAsB,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE;QACvI,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,CAAC;QACd,GAAG,SAAS;KACb,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAY,EACZ,SAAiC;AACjC,6DAA6D;AAC7D,aAAqB,EACrB,SAAkC;IAElC,OAAO,IAAI,MAAM,CAAc,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE;QAC7G,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7D,GAAG,SAAS;KACb,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,KAAY,EACZ,SAA2C,EAC3C,SAAkC;IAElC,OAAO,IAAI,MAAM,CAAwB,qBAAqB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,4BAA4B,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE;QAC7I,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,CAAC;QACd,GAAG,SAAS;KACb,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { SelfNewsletterStatus } from '@endora-commerce/contracts';
|
|
3
|
+
import type { NewsletterSubscriberService } from './subscriber.service.js';
|
|
4
|
+
/** Customer self-service newsletter view (feature 048, US9). */
|
|
5
|
+
export declare class NewsletterSelfService {
|
|
6
|
+
private readonly emFactory;
|
|
7
|
+
private readonly subscribers;
|
|
8
|
+
constructor(emFactory: () => EntityManager, subscribers: NewsletterSubscriberService);
|
|
9
|
+
getStatus(email: string): Promise<SelfNewsletterStatus>;
|
|
10
|
+
subscribe(email: string, customerAccountId: string, tags?: string[], customFields?: Record<string, string | number | boolean | null>): Promise<{
|
|
11
|
+
status: 'pending' | 'active';
|
|
12
|
+
}>;
|
|
13
|
+
unsubscribe(email: string, reason?: string): Promise<{
|
|
14
|
+
ok: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=self.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/self.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAIvE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE3E,gEAAgE;AAChE,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,SAAS,EAAE,MAAM,aAAa,EAC9B,WAAW,EAAE,2BAA2B;IAGrD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAcvD,SAAS,CACb,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,MAAM,EACzB,IAAI,CAAC,EAAE,MAAM,EAAE,EACf,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,GAC9D,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;KAAE,CAAC;IAWtC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;CAM5E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { NewsletterSubscriber } from '../entities/newsletter-subscriber.entity.js';
|
|
2
|
+
import { NewsletterTag } from '../entities/newsletter-tag.entity.js';
|
|
3
|
+
import { NewsletterSubscriberTag } from '../entities/newsletter-subscriber-tag.entity.js';
|
|
4
|
+
/** Customer self-service newsletter view (feature 048, US9). */
|
|
5
|
+
export class NewsletterSelfService {
|
|
6
|
+
emFactory;
|
|
7
|
+
subscribers;
|
|
8
|
+
constructor(emFactory, subscribers) {
|
|
9
|
+
this.emFactory = emFactory;
|
|
10
|
+
this.subscribers = subscribers;
|
|
11
|
+
}
|
|
12
|
+
async getStatus(email) {
|
|
13
|
+
const em = this.emFactory();
|
|
14
|
+
const sub = await em.findOne(NewsletterSubscriber, { email: email.toLowerCase() });
|
|
15
|
+
if (!sub)
|
|
16
|
+
return { subscribed: false, status: null, tags: [], canManage: true };
|
|
17
|
+
const links = await em.find(NewsletterSubscriberTag, { subscriberId: sub.id });
|
|
18
|
+
const tags = await em.find(NewsletterTag, { id: { $in: links.map((l) => l.tagId) } });
|
|
19
|
+
return {
|
|
20
|
+
subscribed: sub.status === 'active',
|
|
21
|
+
status: sub.status,
|
|
22
|
+
tags: tags.map((t) => ({ code: t.code, name: t.name })),
|
|
23
|
+
canManage: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async subscribe(email, customerAccountId, tags, customFields) {
|
|
27
|
+
return this.subscribers.subscribe({
|
|
28
|
+
email,
|
|
29
|
+
salesChannelId: null,
|
|
30
|
+
source: 'account',
|
|
31
|
+
customerAccountId,
|
|
32
|
+
...(tags ? { tags } : {}),
|
|
33
|
+
...(customFields ? { customFields } : {}),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async unsubscribe(email, reason) {
|
|
37
|
+
const em = this.emFactory();
|
|
38
|
+
const sub = await em.findOne(NewsletterSubscriber, { email: email.toLowerCase() });
|
|
39
|
+
if (!sub)
|
|
40
|
+
return { ok: true };
|
|
41
|
+
return this.subscribers.unsubscribe(sub.id, reason);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=self.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self.service.js","sourceRoot":"","sources":["../../../src/backend/services/self.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAG1F,gEAAgE;AAChE,MAAM,OAAO,qBAAqB;IAEb;IACA;IAFnB,YACmB,SAA8B,EAC9B,WAAwC;QADxC,cAAS,GAAT,SAAS,CAAqB;QAC9B,gBAAW,GAAX,WAAW,CAA6B;IACxD,CAAC;IAEJ,KAAK,CAAC,SAAS,CAAC,KAAa;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAChF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/E,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACtF,OAAO;YACL,UAAU,EAAE,GAAG,CAAC,MAAM,KAAK,QAAQ;YACnC,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACvD,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAa,EACb,iBAAyB,EACzB,IAAe,EACf,YAA+D;QAE/D,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;YAChC,KAAK;YACL,cAAc,EAAE,IAAI;YACpB,MAAM,EAAE,SAAS;YACjB,iBAAiB;YACjB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,MAAe;QAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { CampaignStats } from '@endora-commerce/contracts';
|
|
3
|
+
/** Campaign / automation engagement statistics (feature 048, US6). */
|
|
4
|
+
export declare class NewsletterStatsService {
|
|
5
|
+
private readonly emFactory;
|
|
6
|
+
constructor(emFactory: () => EntityManager);
|
|
7
|
+
campaignStats(campaignId: string): Promise<CampaignStats>;
|
|
8
|
+
private perLink;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=stats.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/stats.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAQhE,sEAAsE;AACtE,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;YAuBjD,OAAO;CAetB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { NewsletterSendRecord } from '../entities/newsletter-send-record.entity.js';
|
|
2
|
+
import { NewsletterEngagementEvent } from '../entities/newsletter-engagement-event.entity.js';
|
|
3
|
+
function rate(n, d) {
|
|
4
|
+
return d > 0 ? Math.round((n / d) * 1000) / 1000 : 0;
|
|
5
|
+
}
|
|
6
|
+
/** Campaign / automation engagement statistics (feature 048, US6). */
|
|
7
|
+
export class NewsletterStatsService {
|
|
8
|
+
emFactory;
|
|
9
|
+
constructor(emFactory) {
|
|
10
|
+
this.emFactory = emFactory;
|
|
11
|
+
}
|
|
12
|
+
async campaignStats(campaignId) {
|
|
13
|
+
const em = this.emFactory();
|
|
14
|
+
const records = await em.find(NewsletterSendRecord, { campaignId });
|
|
15
|
+
const sent = records.filter((r) => r.status === 'sent').length;
|
|
16
|
+
const failed = records.filter((r) => r.status === 'failed' || r.status === 'bounced' || r.status === 'complained').length;
|
|
17
|
+
const opened = records.filter((r) => r.openedAt !== null).length;
|
|
18
|
+
const clicked = records.filter((r) => r.clickCount > 0).length;
|
|
19
|
+
const recordIds = records.map((r) => r.id);
|
|
20
|
+
const perLinkClicks = recordIds.length > 0 ? await this.perLink(em, recordIds) : [];
|
|
21
|
+
return {
|
|
22
|
+
sent,
|
|
23
|
+
delivered: sent,
|
|
24
|
+
failed,
|
|
25
|
+
opened,
|
|
26
|
+
clicked,
|
|
27
|
+
openRate: rate(opened, sent),
|
|
28
|
+
clickRate: rate(clicked, sent),
|
|
29
|
+
perLinkClicks,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async perLink(em, recordIds) {
|
|
33
|
+
const events = await em.find(NewsletterEngagementEvent, {
|
|
34
|
+
sendRecordId: { $in: recordIds },
|
|
35
|
+
type: 'click',
|
|
36
|
+
});
|
|
37
|
+
const counts = new Map();
|
|
38
|
+
for (const e of events) {
|
|
39
|
+
const url = e.url ?? '';
|
|
40
|
+
counts.set(url, (counts.get(url) ?? 0) + 1);
|
|
41
|
+
}
|
|
42
|
+
return [...counts.entries()].map(([url, clicks]) => ({ url, clicks }));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=stats.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.service.js","sourceRoot":"","sources":["../../../src/backend/services/stats.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAE9F,SAAS,IAAI,CAAC,CAAS,EAAE,CAAS;IAChC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,sEAAsE;AACtE,MAAM,OAAO,sBAAsB;IACJ;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,KAAK,CAAC,aAAa,CAAC,UAAkB;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;QAC/D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,MAAM,CAAC;QAC1H,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;QACjE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAE/D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAEpF,OAAO;YACL,IAAI;YACJ,SAAS,EAAE,IAAI;YACf,MAAM;YACN,MAAM;YACN,OAAO;YACP,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;YAC5B,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;YAC9B,aAAa;SACd,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,EAAiB,EACjB,SAAmB;QAEnB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE;YACtD,YAAY,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE;YAChC,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACzE,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type SubscriberDetail, type SubscriberListQuery, type SubscriberListResponse, type SubscriberStatus } from '@endora-commerce/contracts';
|
|
3
|
+
import type { AuditPort } from '@endora-commerce/platform/kernel';
|
|
4
|
+
/** Filter fields shared by list + export (explicit `| undefined` for exactOptionalPropertyTypes). */
|
|
5
|
+
export interface SubscriberFilter {
|
|
6
|
+
status?: SubscriberStatus | undefined;
|
|
7
|
+
tag?: string | undefined;
|
|
8
|
+
channel?: string | undefined;
|
|
9
|
+
q?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Admin subscriber list / detail / lifecycle / CSV export (feature 048, US3). */
|
|
12
|
+
export declare class NewsletterSubscriberAdminService {
|
|
13
|
+
private readonly emFactory;
|
|
14
|
+
private readonly auditLog?;
|
|
15
|
+
constructor(emFactory: () => EntityManager, auditLog?: AuditPort | undefined);
|
|
16
|
+
private buildWhere;
|
|
17
|
+
private tagsFor;
|
|
18
|
+
list(query: SubscriberListQuery): Promise<SubscriberListResponse>;
|
|
19
|
+
getDetail(id: string): Promise<SubscriberDetail>;
|
|
20
|
+
deactivate(id: string, expectedVersion: number): Promise<SubscriberDetail>;
|
|
21
|
+
remove(id: string): Promise<void>;
|
|
22
|
+
exportCsv(query: SubscriberFilter): Promise<string>;
|
|
23
|
+
private toSummary;
|
|
24
|
+
private toDetail;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=subscriber-admin.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriber-admin.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/subscriber-admin.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAEtB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAMlE,qGAAqG;AACrG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxB;AAQD,kFAAkF;AAClF,qBAAa,gCAAgC;IAEzC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBADT,SAAS,EAAE,MAAM,aAAa,EAC9B,QAAQ,CAAC,EAAE,SAAS,YAAA;YAGzB,UAAU;YAaV,OAAO;IAiBf,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiBjE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQhD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqB1E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjC,SAAS,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBzD,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,QAAQ;CAajB"}
|