@openlup/platform 0.16.0 → 0.17.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/CHANGELOG.md +84 -0
- package/README.md +285 -5
- package/dist/communications/accountingDocumentDelivery.d.ts +35 -0
- package/dist/communications/accountingDocumentDelivery.js +33 -0
- package/dist/communications/authEmailError.d.ts +5 -0
- package/dist/communications/authEmailError.js +8 -0
- package/dist/communications/authEmailPorts.d.ts +2 -0
- package/dist/communications/authEmailPorts.js +1 -0
- package/dist/communications/authSendEmailHook.d.ts +35 -0
- package/dist/communications/authSendEmailHook.js +250 -0
- package/dist/communications/capturedTransactionalDelivery.d.ts +13 -0
- package/dist/communications/capturedTransactionalDelivery.js +14 -0
- package/dist/communications/communicationSync.d.ts +11 -0
- package/dist/communications/communicationSync.js +79 -0
- package/dist/communications/communicationSyncWorker.d.ts +68 -0
- package/dist/communications/communicationSyncWorker.js +218 -0
- package/dist/communications/consentPolicy.d.ts +19 -0
- package/dist/communications/consentPolicy.js +43 -0
- package/dist/communications/consentPurposeRegistry.d.ts +4 -0
- package/dist/communications/consentPurposeRegistry.js +24 -0
- package/dist/communications/contracts/abandonedCart.d.ts +27 -0
- package/dist/communications/contracts/abandonedCart.js +25 -0
- package/dist/communications/contracts/authEmail.d.ts +62 -0
- package/dist/communications/contracts/authEmail.js +1 -0
- package/dist/communications/contracts/backInStock.d.ts +28 -0
- package/dist/communications/contracts/backInStock.js +28 -0
- package/dist/communications/contracts/blocks.d.ts +24 -0
- package/dist/communications/contracts/blocks.js +23 -0
- package/dist/communications/contracts/checkoutExpired.d.ts +22 -0
- package/dist/communications/contracts/checkoutExpired.js +25 -0
- package/dist/communications/contracts/checkoutRecovery.d.ts +26 -0
- package/dist/communications/contracts/checkoutRecovery.js +37 -0
- package/dist/communications/contracts/commerceEmailContent.d.ts +176 -0
- package/dist/communications/contracts/commerceEmailContent.js +1 -0
- package/dist/communications/contracts/commerceEngagementEmailContent.d.ts +95 -0
- package/dist/communications/contracts/commerceEngagementEmailContent.js +1 -0
- package/dist/communications/contracts/consent.d.ts +12 -0
- package/dist/communications/contracts/consent.js +1 -0
- package/dist/communications/contracts/email.d.ts +182 -0
- package/dist/communications/contracts/email.js +1 -0
- package/dist/communications/contracts/guideCard.d.ts +3 -0
- package/dist/communications/contracts/guideCard.js +26 -0
- package/dist/communications/contracts/index.d.ts +51 -0
- package/dist/communications/contracts/index.js +42 -0
- package/dist/communications/contracts/inquiryContent.d.ts +32 -0
- package/dist/communications/contracts/inquiryContent.js +33 -0
- package/dist/communications/contracts/invoiceDocumentContent.d.ts +26 -0
- package/dist/communications/contracts/invoiceDocumentContent.js +36 -0
- package/dist/communications/contracts/marketingAutomation.d.ts +52 -0
- package/dist/communications/contracts/marketingAutomation.js +1 -0
- package/dist/communications/contracts/newsletter.d.ts +63 -0
- package/dist/communications/contracts/newsletter.js +1 -0
- package/dist/communications/contracts/newsletterWebhook.d.ts +26 -0
- package/dist/communications/contracts/newsletterWebhook.js +1 -0
- package/dist/communications/contracts/optOutContent.d.ts +11 -0
- package/dist/communications/contracts/optOutContent.js +17 -0
- package/dist/communications/contracts/orderCanceled.d.ts +25 -0
- package/dist/communications/contracts/orderCanceled.js +27 -0
- package/dist/communications/contracts/orderDraft.d.ts +46 -0
- package/dist/communications/contracts/orderDraft.js +46 -0
- package/dist/communications/contracts/orderPaid.d.ts +53 -0
- package/dist/communications/contracts/orderPaid.js +71 -0
- package/dist/communications/contracts/orderRefunded.d.ts +24 -0
- package/dist/communications/contracts/orderRefunded.js +27 -0
- package/dist/communications/contracts/paymentFailed.d.ts +24 -0
- package/dist/communications/contracts/paymentFailed.js +24 -0
- package/dist/communications/contracts/publicIntake.d.ts +49 -0
- package/dist/communications/contracts/publicIntake.js +1 -0
- package/dist/communications/contracts/render.d.ts +2 -0
- package/dist/communications/contracts/render.js +229 -0
- package/dist/communications/contracts/reorderReminder.d.ts +24 -0
- package/dist/communications/contracts/reorderReminder.js +24 -0
- package/dist/communications/contracts/returnEmails.d.ts +25 -0
- package/dist/communications/contracts/returnEmails.js +62 -0
- package/dist/communications/contracts/reviewEffects.d.ts +26 -0
- package/dist/communications/contracts/reviewEffects.js +25 -0
- package/dist/communications/contracts/reviewRequest.d.ts +26 -0
- package/dist/communications/contracts/reviewRequest.js +24 -0
- package/dist/communications/contracts/roleNotificationContent.d.ts +25 -0
- package/dist/communications/contracts/roleNotificationContent.js +46 -0
- package/dist/communications/contracts/shipmentDelivered.d.ts +23 -0
- package/dist/communications/contracts/shipmentDelivered.js +24 -0
- package/dist/communications/contracts/shipmentDispatched.d.ts +27 -0
- package/dist/communications/contracts/shipmentDispatched.js +35 -0
- package/dist/communications/contracts/shipmentException.d.ts +21 -0
- package/dist/communications/contracts/shipmentException.js +26 -0
- package/dist/communications/contracts/subscriptionActivationActionRequired.d.ts +17 -0
- package/dist/communications/contracts/subscriptionActivationActionRequired.js +22 -0
- package/dist/communications/contracts/subscriptionAddressChanged.d.ts +19 -0
- package/dist/communications/contracts/subscriptionAddressChanged.js +25 -0
- package/dist/communications/contracts/subscriptionCancelled.d.ts +19 -0
- package/dist/communications/contracts/subscriptionCancelled.js +25 -0
- package/dist/communications/contracts/subscriptionCycleSkipped.d.ts +25 -0
- package/dist/communications/contracts/subscriptionCycleSkipped.js +40 -0
- package/dist/communications/contracts/subscriptionDeliveryRescheduled.d.ts +25 -0
- package/dist/communications/contracts/subscriptionDeliveryRescheduled.js +39 -0
- package/dist/communications/contracts/subscriptionEmailContent.d.ts +145 -0
- package/dist/communications/contracts/subscriptionEmailContent.js +1 -0
- package/dist/communications/contracts/subscriptionPackageChanged.d.ts +20 -0
- package/dist/communications/contracts/subscriptionPackageChanged.js +26 -0
- package/dist/communications/contracts/subscriptionPauseReminder.d.ts +23 -0
- package/dist/communications/contracts/subscriptionPauseReminder.js +29 -0
- package/dist/communications/contracts/subscriptionPaused.d.ts +21 -0
- package/dist/communications/contracts/subscriptionPaused.js +25 -0
- package/dist/communications/contracts/subscriptionPaymentExpired.d.ts +34 -0
- package/dist/communications/contracts/subscriptionPaymentExpired.js +37 -0
- package/dist/communications/contracts/subscriptionPaymentFailed.d.ts +49 -0
- package/dist/communications/contracts/subscriptionPaymentFailed.js +56 -0
- package/dist/communications/contracts/subscriptionPaymentRecovered.d.ts +19 -0
- package/dist/communications/contracts/subscriptionPaymentRecovered.js +22 -0
- package/dist/communications/contracts/subscriptionRenewalAtRisk.d.ts +36 -0
- package/dist/communications/contracts/subscriptionRenewalAtRisk.js +36 -0
- package/dist/communications/contracts/subscriptionRenewalUpcoming.d.ts +49 -0
- package/dist/communications/contracts/subscriptionRenewalUpcoming.js +43 -0
- package/dist/communications/contracts/subscriptionResumed.d.ts +23 -0
- package/dist/communications/contracts/subscriptionResumed.js +25 -0
- package/dist/communications/contracts/subscriptionWelcome.d.ts +44 -0
- package/dist/communications/contracts/subscriptionWelcome.js +45 -0
- package/dist/communications/contracts/subscriptionWinback.d.ts +21 -0
- package/dist/communications/contracts/subscriptionWinback.js +28 -0
- package/dist/communications/contracts/transactionalDelivery.d.ts +42 -0
- package/dist/communications/contracts/transactionalDelivery.js +1 -0
- package/dist/communications/contracts/types.d.ts +46 -0
- package/dist/communications/contracts/types.js +1 -0
- package/dist/communications/contribution.d.ts +10 -0
- package/dist/communications/contribution.js +24 -0
- package/dist/communications/deliveryReconciliation.d.ts +64 -0
- package/dist/communications/deliveryReconciliation.js +60 -0
- package/dist/communications/emailEgress.d.ts +38 -0
- package/dist/communications/emailEgress.js +100 -0
- package/dist/communications/emailHealthAssessment.d.ts +39 -0
- package/dist/communications/emailHealthAssessment.js +59 -0
- package/dist/communications/emailHealthMetricsPort.d.ts +17 -0
- package/dist/communications/emailHealthMetricsPort.js +1 -0
- package/dist/communications/emailNotificationControl.d.ts +27 -0
- package/dist/communications/emailNotificationControl.js +10 -0
- package/dist/communications/emailObservation.d.ts +28 -0
- package/dist/communications/emailObservation.js +23 -0
- package/dist/communications/emailTransport.d.ts +82 -0
- package/dist/communications/emailTransport.js +95 -0
- package/dist/communications/errors.d.ts +15 -0
- package/dist/communications/errors.js +30 -0
- package/dist/communications/index.d.ts +46 -0
- package/dist/communications/index.js +38 -0
- package/dist/communications/integrationEventSignature.d.ts +15 -0
- package/dist/communications/integrationEventSignature.js +37 -0
- package/dist/communications/managedTransactionalDeliveryStore.d.ts +12 -0
- package/dist/communications/managedTransactionalDeliveryStore.js +49 -0
- package/dist/communications/nativeOperations.d.ts +79 -0
- package/dist/communications/nativeOperations.js +3 -0
- package/dist/communications/newsletterIntegrationContracts.d.ts +130 -0
- package/dist/communications/newsletterIntegrationContracts.js +128 -0
- package/dist/communications/newsletterWebhookPort.d.ts +11 -0
- package/dist/communications/newsletterWebhookPort.js +84 -0
- package/dist/communications/newsletterWebhookProcessing.d.ts +17 -0
- package/dist/communications/newsletterWebhookProcessing.js +71 -0
- package/dist/communications/originPolicy.d.ts +40 -0
- package/dist/communications/originPolicy.js +100 -0
- package/dist/communications/postgresCommunicationSync.d.ts +79 -0
- package/dist/communications/postgresCommunicationSync.js +111 -0
- package/dist/communications/postgresConsentEvaluator.d.ts +19 -0
- package/dist/communications/postgresConsentEvaluator.js +43 -0
- package/dist/communications/postgresDeliveryReconciliation.d.ts +3 -0
- package/dist/communications/postgresDeliveryReconciliation.js +113 -0
- package/dist/communications/postgresNativeOperations.d.ts +13 -0
- package/dist/communications/postgresNativeOperations.js +63 -0
- package/dist/communications/postgresNotificationRecipients.d.ts +37 -0
- package/dist/communications/postgresNotificationRecipients.js +60 -0
- package/dist/communications/postgresTransactionalDeliveryStore.d.ts +7 -0
- package/dist/communications/postgresTransactionalDeliveryStore.js +55 -0
- package/dist/communications/preferencesToken.d.ts +10 -0
- package/dist/communications/preferencesToken.js +40 -0
- package/dist/communications/publicPreferenceToken.d.ts +24 -0
- package/dist/communications/publicPreferenceToken.js +53 -0
- package/dist/communications/shipmentNotifications.d.ts +34 -0
- package/dist/communications/shipmentNotifications.js +61 -0
- package/dist/communications/sql.d.ts +26 -0
- package/dist/communications/sql.js +7 -0
- package/dist/communications/standardWebhooks.d.ts +14 -0
- package/dist/communications/standardWebhooks.js +73 -0
- package/dist/communications/status.d.ts +11 -0
- package/dist/communications/status.js +36 -0
- package/dist/communications/transactionalDelivery.d.ts +19 -0
- package/dist/communications/transactionalDelivery.js +96 -0
- package/dist/communications/transactionalDeliveryIdentifier.d.ts +3 -0
- package/dist/communications/transactionalDeliveryIdentifier.js +6 -0
- package/dist/communications/unsubscribeToken.d.ts +77 -0
- package/dist/communications/unsubscribeToken.js +150 -0
- package/dist/communications/validation.d.ts +2 -0
- package/dist/communications/validation.js +3 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +1 -0
- package/dist/http/webhookSignature.d.ts +42 -0
- package/dist/http/webhookSignature.js +86 -0
- package/package.json +12 -2
- package/release-gates.json +41 -8
- package/sql/20260807190000_comms_outbox_rail.sql +329 -0
- package/sql/20260810120001_transactional_delivery_receipts.sql +209 -0
- package/sql/20260813120000_communications_control_plane.sql +568 -0
- package/sql/20261019200000_communications_native_operations.sql +68 -0
- package/src/communications/accountingDocumentDelivery.ts +63 -0
- package/src/communications/authEmailError.ts +10 -0
- package/src/communications/authEmailPorts.ts +2 -0
- package/src/communications/authSendEmailHook.ts +310 -0
- package/src/communications/capturedTransactionalDelivery.ts +29 -0
- package/src/communications/communicationSync.ts +96 -0
- package/src/communications/communicationSyncWorker.ts +302 -0
- package/src/communications/consentPolicy.ts +82 -0
- package/src/communications/consentPurposeRegistry.ts +31 -0
- package/src/communications/contracts/abandonedCart.ts +64 -0
- package/src/communications/contracts/authEmail.ts +73 -0
- package/src/communications/contracts/backInStock.ts +69 -0
- package/src/communications/contracts/blocks.ts +47 -0
- package/src/communications/contracts/checkoutExpired.ts +62 -0
- package/src/communications/contracts/checkoutRecovery.ts +68 -0
- package/src/communications/contracts/commerceEmailContent.ts +189 -0
- package/src/communications/contracts/commerceEngagementEmailContent.ts +106 -0
- package/src/communications/contracts/consent.ts +13 -0
- package/src/communications/contracts/email.ts +210 -0
- package/src/communications/contracts/guideCard.ts +34 -0
- package/src/communications/contracts/index.ts +51 -0
- package/src/communications/contracts/inquiryContent.ts +53 -0
- package/src/communications/contracts/invoiceDocumentContent.ts +57 -0
- package/src/communications/contracts/marketingAutomation.ts +45 -0
- package/src/communications/contracts/newsletter.ts +78 -0
- package/src/communications/contracts/newsletterWebhook.ts +23 -0
- package/src/communications/contracts/optOutContent.ts +23 -0
- package/src/communications/contracts/orderCanceled.ts +64 -0
- package/src/communications/contracts/orderDraft.ts +112 -0
- package/src/communications/contracts/orderPaid.ts +147 -0
- package/src/communications/contracts/orderRefunded.ts +63 -0
- package/src/communications/contracts/paymentFailed.ts +59 -0
- package/src/communications/contracts/publicIntake.ts +53 -0
- package/src/communications/contracts/render.ts +271 -0
- package/src/communications/contracts/reorderReminder.ts +59 -0
- package/src/communications/contracts/returnEmails.ts +113 -0
- package/src/communications/contracts/reviewEffects.ts +60 -0
- package/src/communications/contracts/reviewRequest.ts +59 -0
- package/src/communications/contracts/roleNotificationContent.ts +65 -0
- package/src/communications/contracts/shipmentDelivered.ts +59 -0
- package/src/communications/contracts/shipmentDispatched.ts +77 -0
- package/src/communications/contracts/shipmentException.ts +62 -0
- package/src/communications/contracts/subscriptionActivationActionRequired.ts +37 -0
- package/src/communications/contracts/subscriptionAddressChanged.ts +56 -0
- package/src/communications/contracts/subscriptionCancelled.ts +57 -0
- package/src/communications/contracts/subscriptionCycleSkipped.ts +80 -0
- package/src/communications/contracts/subscriptionDeliveryRescheduled.ts +79 -0
- package/src/communications/contracts/subscriptionEmailContent.ts +163 -0
- package/src/communications/contracts/subscriptionPackageChanged.ts +59 -0
- package/src/communications/contracts/subscriptionPauseReminder.ts +63 -0
- package/src/communications/contracts/subscriptionPaused.ts +58 -0
- package/src/communications/contracts/subscriptionPaymentExpired.ts +83 -0
- package/src/communications/contracts/subscriptionPaymentFailed.ts +117 -0
- package/src/communications/contracts/subscriptionPaymentRecovered.ts +50 -0
- package/src/communications/contracts/subscriptionRenewalAtRisk.ts +85 -0
- package/src/communications/contracts/subscriptionRenewalUpcoming.ts +103 -0
- package/src/communications/contracts/subscriptionResumed.ts +60 -0
- package/src/communications/contracts/subscriptionWelcome.ts +102 -0
- package/src/communications/contracts/subscriptionWinback.ts +62 -0
- package/src/communications/contracts/transactionalDelivery.ts +43 -0
- package/src/communications/contracts/types.ts +58 -0
- package/src/communications/contribution.ts +33 -0
- package/src/communications/deliveryReconciliation.ts +108 -0
- package/src/communications/emailEgress.ts +111 -0
- package/src/communications/emailHealthAssessment.ts +106 -0
- package/src/communications/emailHealthMetricsPort.ts +17 -0
- package/src/communications/emailNotificationControl.ts +28 -0
- package/src/communications/emailObservation.ts +43 -0
- package/src/communications/emailTransport.ts +167 -0
- package/src/communications/errors.ts +34 -0
- package/src/communications/index.ts +46 -0
- package/src/communications/integrationEventSignature.ts +49 -0
- package/src/communications/managedTransactionalDeliveryStore.ts +59 -0
- package/src/communications/nativeOperations.ts +40 -0
- package/src/communications/newsletterIntegrationContracts.ts +154 -0
- package/src/communications/newsletterWebhookPort.ts +104 -0
- package/src/communications/newsletterWebhookProcessing.ts +102 -0
- package/src/communications/originPolicy.ts +151 -0
- package/src/communications/postgresCommunicationSync.ts +127 -0
- package/src/communications/postgresConsentEvaluator.ts +49 -0
- package/src/communications/postgresDeliveryReconciliation.ts +101 -0
- package/src/communications/postgresNativeOperations.ts +55 -0
- package/src/communications/postgresNotificationRecipients.ts +57 -0
- package/src/communications/postgresTransactionalDeliveryStore.ts +79 -0
- package/src/communications/preferencesToken.ts +62 -0
- package/src/communications/publicPreferenceToken.ts +68 -0
- package/src/communications/shipmentNotifications.ts +78 -0
- package/src/communications/sql.ts +7 -0
- package/src/communications/standardWebhooks.ts +84 -0
- package/src/communications/status.ts +51 -0
- package/src/communications/transactionalDelivery.ts +114 -0
- package/src/communications/transactionalDeliveryIdentifier.ts +9 -0
- package/src/communications/unsubscribeToken.ts +186 -0
- package/src/communications/validation.ts +3 -0
- package/src/http/index.ts +1 -0
- package/src/http/webhookSignature.ts +96 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export type NewsletterProviderKind = string;
|
|
2
|
+
export type NewsletterMarketingPurpose = "marketing_launch_offer" | "marketing_newsletter";
|
|
3
|
+
export type NewsletterSyncEventType = "subscribe" | "update" | "unsubscribe" | "suppress";
|
|
4
|
+
export type NewsletterWebhookEventType = "subscribe" | "update" | "unsubscribe" | "suppress" | "complaint" | "bounce" | "email_change" | "profile_update" | "ignored";
|
|
5
|
+
export type NewsletterProviderCapabilityKey = "subscribe" | "unsubscribe" | "suppress" | "unsuppress" | "doubleOptIn" | "emailChange" | "listMembership" | "webhookIdempotency" | "retryAfter";
|
|
6
|
+
export type NewsletterProviderCapabilities = Record<NewsletterProviderCapabilityKey, boolean>;
|
|
7
|
+
export interface NewsletterWebhookEvent<Purpose extends string = NewsletterMarketingPurpose> {
|
|
8
|
+
providerKind: NewsletterProviderKind;
|
|
9
|
+
providerEventId: string;
|
|
10
|
+
eventType: NewsletterWebhookEventType;
|
|
11
|
+
email: string | null;
|
|
12
|
+
remoteProfileId: string | null;
|
|
13
|
+
remoteListId: string | null;
|
|
14
|
+
purpose: Purpose | null;
|
|
15
|
+
explicitOptInEvidence: boolean;
|
|
16
|
+
doubleOptInStatus: "confirmed" | "pending" | "unknown";
|
|
17
|
+
occurredAt: string | null;
|
|
18
|
+
rawPayload: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface NewsletterSyncEvent<Purpose extends string = NewsletterMarketingPurpose> {
|
|
21
|
+
id: string;
|
|
22
|
+
claimToken: string;
|
|
23
|
+
contactId: string;
|
|
24
|
+
normalizedEmail: string;
|
|
25
|
+
eventType: NewsletterSyncEventType;
|
|
26
|
+
purpose: Purpose;
|
|
27
|
+
payload: Record<string, unknown>;
|
|
28
|
+
attemptCount: number;
|
|
29
|
+
originProviderKind?: NewsletterProviderKind | null;
|
|
30
|
+
originProviderEventId?: string | null;
|
|
31
|
+
remoteProfileId?: string | null;
|
|
32
|
+
remoteListId?: string | null;
|
|
33
|
+
}
|
|
34
|
+
export type NewsletterSyncOutcome = {
|
|
35
|
+
status: "sent";
|
|
36
|
+
remoteProfileId?: string | null;
|
|
37
|
+
responseSummary?: Record<string, unknown>;
|
|
38
|
+
} | {
|
|
39
|
+
status: "skipped";
|
|
40
|
+
reason: string;
|
|
41
|
+
responseSummary?: Record<string, unknown>;
|
|
42
|
+
} | {
|
|
43
|
+
status: "retry";
|
|
44
|
+
reason: string;
|
|
45
|
+
retryAfterSeconds?: number;
|
|
46
|
+
};
|
|
47
|
+
export interface NewsletterSyncProviderPort<Purpose extends string = NewsletterMarketingPurpose> {
|
|
48
|
+
readonly providerKind: string;
|
|
49
|
+
readonly capabilities: NewsletterProviderCapabilities;
|
|
50
|
+
sync(event: NewsletterSyncEvent<Purpose>): Promise<NewsletterSyncOutcome>;
|
|
51
|
+
reconcile?(): Promise<NewsletterSyncReconcileOutcome>;
|
|
52
|
+
}
|
|
53
|
+
export type NewsletterSyncReconcileOutcome = {
|
|
54
|
+
status: "skipped";
|
|
55
|
+
reason: string;
|
|
56
|
+
responseSummary?: Record<string, unknown>;
|
|
57
|
+
} | {
|
|
58
|
+
status: "checked";
|
|
59
|
+
checked: number;
|
|
60
|
+
updated: number;
|
|
61
|
+
failures: number;
|
|
62
|
+
responseSummary?: Record<string, unknown>;
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { NewsletterMarketingPurpose, NewsletterWebhookEvent } from "./newsletter.js";
|
|
2
|
+
export type NormalizedNewsletterWebhookEvent<Purpose extends string = NewsletterMarketingPurpose> = NewsletterWebhookEvent<Purpose>;
|
|
3
|
+
export interface NewsletterWebhookPort<Purpose extends string = NewsletterMarketingPurpose> {
|
|
4
|
+
recordProviderEvent(input: NewsletterWebhookEvent<Purpose> & {
|
|
5
|
+
state: "unknown" | "granted" | "denied" | "suppressed" | null;
|
|
6
|
+
processingStatus: "received" | "ignored";
|
|
7
|
+
}): Promise<{
|
|
8
|
+
providerEventId: string;
|
|
9
|
+
contactId: string | null;
|
|
10
|
+
inserted: boolean;
|
|
11
|
+
}>;
|
|
12
|
+
recordPermission(input: {
|
|
13
|
+
contactId: string;
|
|
14
|
+
providerKind: string;
|
|
15
|
+
providerEventId: string;
|
|
16
|
+
purpose: Purpose;
|
|
17
|
+
state: "granted" | "suppressed";
|
|
18
|
+
reason: string;
|
|
19
|
+
metadata: Record<string, unknown>;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
markProviderEvent(input: {
|
|
22
|
+
providerEventId: string;
|
|
23
|
+
status: "processed" | "ignored" | "failed";
|
|
24
|
+
metadata: Record<string, unknown>;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Locale } from "./email.js";
|
|
2
|
+
export type OptOutOutcome = "invalid_link" | "marketing_applied" | "missing_information" | "not_found" | "legacy_applied" | "legacy_replay" | "error";
|
|
3
|
+
export interface OptOutContent {
|
|
4
|
+
title: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
export type OptOutCopy = Record<OptOutOutcome, Record<Locale, OptOutContent>>;
|
|
8
|
+
/** Display only; the caller independently verifies and durably records opt-out. */
|
|
9
|
+
export declare function createOptOutContentFactory(copy?: OptOutCopy): {
|
|
10
|
+
optOutContent: (locale: Locale, outcome: OptOutOutcome, supportEmail: string) => OptOutContent;
|
|
11
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const defaults = {
|
|
2
|
+
invalid_link: { pl: { "title": "Link nieprawidłowy lub wygasł", "message": "Nie udało się przetworzyć tej prośby. Skopiuj pełny link z wiadomości lub napisz na {supportEmail}." }, en: { "title": "Invalid or expired link", "message": "We couldn't process this request. Copy the full link from the email or email {supportEmail}." } },
|
|
3
|
+
marketing_applied: { pl: { "title": "Wypisano", "message": "Nie będziesz już otrzymywać tych wiadomości marketingowych. Wiadomości potrzebne do obsługi konta, zamówień, płatności i subskrypcji mogą nadal przychodzić." }, en: { "title": "You're unsubscribed", "message": "You won't receive these marketing emails anymore. Messages needed to manage your account, orders, payments and subscriptions may still arrive." } },
|
|
4
|
+
missing_information: { pl: { "title": "Brakuje danych", "message": "Nieprawidłowy link do wypisania." }, en: { "title": "Missing information", "message": "This unsubscribe link is incomplete." } },
|
|
5
|
+
not_found: { pl: { "title": "Nie znaleziono", "message": "Nie znaleziono takiego zgłoszenia." }, en: { "title": "Not found", "message": "We couldn't find this request." } },
|
|
6
|
+
legacy_applied: { pl: { "title": "Wypisano", "message": "Zapisaliśmy Twoją rezygnację z wybranych wiadomości. Wiadomości potrzebne do obsługi konta, zamówień, płatności i subskrypcji mogą nadal przychodzić." }, en: { "title": "You're unsubscribed", "message": "We've recorded your opt-out from the selected messages. Messages needed to manage your account, orders, payments and subscriptions may still arrive." } },
|
|
7
|
+
legacy_replay: { pl: { "title": "Już wypisano", "message": "Twoja rezygnacja z wybranych wiadomości jest już zapisana. Wiadomości potrzebne do obsługi konta, zamówień, płatności i subskrypcji mogą nadal przychodzić." }, en: { "title": "Already unsubscribed", "message": "Your opt-out from the selected messages is already recorded. Messages needed to manage your account, orders, payments and subscriptions may still arrive." } },
|
|
8
|
+
error: { pl: { "title": "Błąd", "message": "Coś poszło nie tak. Spróbuj ponownie później." }, en: { "title": "Error", "message": "Something went wrong. Try again later." } },
|
|
9
|
+
};
|
|
10
|
+
/** Display only; the caller independently verifies and durably records opt-out. */
|
|
11
|
+
export function createOptOutContentFactory(copy = defaults) {
|
|
12
|
+
function optOutContent(locale, outcome, supportEmail) {
|
|
13
|
+
const c = copy[outcome][locale];
|
|
14
|
+
return { title: c.title, message: c.message.split("{supportEmail}").join(supportEmail) };
|
|
15
|
+
}
|
|
16
|
+
return { optOutContent };
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CommerceEmailContent } from "./commerceEmailContent.js";
|
|
2
|
+
import type { Locale } from "./email.js";
|
|
3
|
+
import { type EmailBlock } from "./blocks.js";
|
|
4
|
+
export interface OrderCanceledEmailVars {
|
|
5
|
+
firstName: string | null;
|
|
6
|
+
orderId: string;
|
|
7
|
+
/** Formatted gross total, e.g. "129,99 zł", or null when unknown. */
|
|
8
|
+
amountLabel: string | null;
|
|
9
|
+
/** Absolute CTA URL (back to shop); null/absent → no button. */
|
|
10
|
+
ctaUrl?: string | null;
|
|
11
|
+
/** Optional context name for the selected return note. */
|
|
12
|
+
contextName?: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface OrderCanceledEmailContent {
|
|
15
|
+
subject: string;
|
|
16
|
+
preheader: string;
|
|
17
|
+
blocks: EmailBlock[];
|
|
18
|
+
}
|
|
19
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
20
|
+
export declare function createOrderCanceledContentFactory(input: {
|
|
21
|
+
commerceEmailContent: Pick<CommerceEmailContent, "orderCanceled" | "orderRefPrefix">;
|
|
22
|
+
formatCustomerOrderReference: (orderId: string, prefix: string) => string;
|
|
23
|
+
}): {
|
|
24
|
+
orderCanceledEmailContent: (locale: Locale, vars: OrderCanceledEmailVars, signoff: string) => OrderCanceledEmailContent;
|
|
25
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { accentBox, button, heading, paragraph, } from "./blocks.js";
|
|
2
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
3
|
+
export function createOrderCanceledContentFactory(input) {
|
|
4
|
+
const { commerceEmailContent, formatCustomerOrderReference } = input;
|
|
5
|
+
function orderCanceledEmailContent(locale, vars, signoff) {
|
|
6
|
+
const copy = commerceEmailContent.orderCanceled[locale];
|
|
7
|
+
const orderRef = formatCustomerOrderReference(vars.orderId, commerceEmailContent.orderRefPrefix);
|
|
8
|
+
const blocks = [
|
|
9
|
+
heading(copy.heading),
|
|
10
|
+
paragraph(copy.greeting(vars.firstName)),
|
|
11
|
+
paragraph(copy.intro(orderRef)),
|
|
12
|
+
accentBox(copy.details(vars.amountLabel), { label: copy.detailsLabel }),
|
|
13
|
+
paragraph(copy.returnNote(vars.contextName ?? null)),
|
|
14
|
+
];
|
|
15
|
+
if (vars.ctaUrl) {
|
|
16
|
+
blocks.push(button(copy.cta, vars.ctaUrl));
|
|
17
|
+
}
|
|
18
|
+
blocks.push(paragraph(copy.outro));
|
|
19
|
+
blocks.push(paragraph(signoff));
|
|
20
|
+
return {
|
|
21
|
+
subject: copy.subject(orderRef),
|
|
22
|
+
preheader: copy.preheader,
|
|
23
|
+
blocks,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { orderCanceledEmailContent };
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CommerceEmailContent } from "./commerceEmailContent.js";
|
|
2
|
+
import type { Locale } from "./email.js";
|
|
3
|
+
import { type EmailBlock } from "./blocks.js";
|
|
4
|
+
export interface OrderDraftLineItem {
|
|
5
|
+
/** Resolved, localized product name (or slug/sku fallback). */
|
|
6
|
+
name: string;
|
|
7
|
+
quantity: number;
|
|
8
|
+
/** Formatted gross line total, e.g. "129,98 zł"; "" when price unknown. */
|
|
9
|
+
lineTotalLabel: string;
|
|
10
|
+
}
|
|
11
|
+
export interface OrderDraftTotals {
|
|
12
|
+
/** null → omit the subtotal row (value unknown); never alias the grand total. */
|
|
13
|
+
subtotalLabel: string | null;
|
|
14
|
+
/** Already sign-prefixed, e.g. "-20,00 zł"; null → no discount row. */
|
|
15
|
+
discountLabel: string | null;
|
|
16
|
+
totalLabel: string;
|
|
17
|
+
}
|
|
18
|
+
export interface OrderDraftEmailVars {
|
|
19
|
+
firstName: string | null;
|
|
20
|
+
/** Technical order id from outbox, e.g. "order_<uuid>". */
|
|
21
|
+
orderId: string;
|
|
22
|
+
/** Itemized order lines (name × qty + line total). */
|
|
23
|
+
items: OrderDraftLineItem[];
|
|
24
|
+
/** Money breakdown, or null when totals are unknown. */
|
|
25
|
+
totals: OrderDraftTotals | null;
|
|
26
|
+
/** Absolute CTA URL back to the configurator; null/absent → no button. */
|
|
27
|
+
ctaUrl?: string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Dog's name from the owner's survey, when known. Drives an optional warm
|
|
30
|
+
* closing line. Absent/null (e.g. anonymous drafts) → the line is omitted.
|
|
31
|
+
* Never inflect the copy by gender: the name doesn't reveal it.
|
|
32
|
+
*/
|
|
33
|
+
contextName?: string | null;
|
|
34
|
+
}
|
|
35
|
+
export interface OrderDraftEmailContent {
|
|
36
|
+
subject: string;
|
|
37
|
+
preheader: string;
|
|
38
|
+
blocks: EmailBlock[];
|
|
39
|
+
}
|
|
40
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
41
|
+
export declare function createOrderDraftContentFactory(input: {
|
|
42
|
+
commerceEmailContent: Pick<CommerceEmailContent, "orderDraft" | "orderRefPrefix">;
|
|
43
|
+
formatCustomerOrderReference: (orderId: string, prefix: string) => string;
|
|
44
|
+
}): {
|
|
45
|
+
orderDraftEmailContent: (locale: Locale, vars: OrderDraftEmailVars, signoff: string) => OrderDraftEmailContent;
|
|
46
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { button, dataTable, heading, list, paragraph, } from "./blocks.js";
|
|
2
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
3
|
+
export function createOrderDraftContentFactory(input) {
|
|
4
|
+
const { commerceEmailContent, formatCustomerOrderReference } = input;
|
|
5
|
+
function itemLine(item) {
|
|
6
|
+
const base = `${item.quantity}× ${item.name}`;
|
|
7
|
+
return item.lineTotalLabel ? `${base} – ${item.lineTotalLabel}` : base;
|
|
8
|
+
}
|
|
9
|
+
function orderDraftEmailContent(locale, vars, signoff) {
|
|
10
|
+
const copy = commerceEmailContent.orderDraft[locale];
|
|
11
|
+
const orderRef = formatCustomerOrderReference(vars.orderId, commerceEmailContent.orderRefPrefix);
|
|
12
|
+
const blocks = [
|
|
13
|
+
heading(copy.heading),
|
|
14
|
+
paragraph(copy.greeting(vars.firstName)),
|
|
15
|
+
paragraph(copy.intro(orderRef)),
|
|
16
|
+
];
|
|
17
|
+
blocks.push(vars.items.length > 0
|
|
18
|
+
? list(vars.items.map(itemLine))
|
|
19
|
+
: paragraph(copy.noItems));
|
|
20
|
+
if (vars.totals) {
|
|
21
|
+
const rows = [];
|
|
22
|
+
if (vars.totals.subtotalLabel) {
|
|
23
|
+
rows.push({ label: copy.subtotalLabel, value: vars.totals.subtotalLabel });
|
|
24
|
+
}
|
|
25
|
+
if (vars.totals.discountLabel) {
|
|
26
|
+
rows.push({ label: copy.discountRowLabel, value: vars.totals.discountLabel });
|
|
27
|
+
}
|
|
28
|
+
rows.push({ label: copy.totalLabel, value: vars.totals.totalLabel });
|
|
29
|
+
blocks.push(dataTable(rows));
|
|
30
|
+
}
|
|
31
|
+
if (vars.ctaUrl) {
|
|
32
|
+
blocks.push(button(copy.cta, vars.ctaUrl));
|
|
33
|
+
}
|
|
34
|
+
blocks.push(paragraph(copy.outro));
|
|
35
|
+
if (vars.contextName) {
|
|
36
|
+
blocks.push(paragraph(copy.personalizedClosing(vars.contextName)));
|
|
37
|
+
}
|
|
38
|
+
blocks.push(paragraph(signoff));
|
|
39
|
+
return {
|
|
40
|
+
subject: copy.subject(orderRef),
|
|
41
|
+
preheader: copy.preheader,
|
|
42
|
+
blocks,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { orderDraftEmailContent };
|
|
46
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { CommerceEmailContent } from "./commerceEmailContent.js";
|
|
2
|
+
import type { Locale } from "./email.js";
|
|
3
|
+
import { type EmailBlock } from "./blocks.js";
|
|
4
|
+
export interface OrderPaidLineItem {
|
|
5
|
+
name: string;
|
|
6
|
+
quantity: number;
|
|
7
|
+
lineTotalLabel: string;
|
|
8
|
+
}
|
|
9
|
+
export interface OrderPaidTotals {
|
|
10
|
+
/** null → omit the subtotal row (value unknown); never alias the grand total. */
|
|
11
|
+
subtotalLabel: string | null;
|
|
12
|
+
discountLabel: string | null;
|
|
13
|
+
totalLabel: string;
|
|
14
|
+
firstSubscription?: {
|
|
15
|
+
catalogLabel: string;
|
|
16
|
+
productPayableLabel: string;
|
|
17
|
+
shippingLabel: string | null;
|
|
18
|
+
shippingFree: boolean;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface OrderPaidEmailVars {
|
|
22
|
+
firstName: string | null;
|
|
23
|
+
orderId: string;
|
|
24
|
+
/** "one_time" | "subscription_cycle" (free-form); drives the intro framing. */
|
|
25
|
+
mode: string;
|
|
26
|
+
items: OrderPaidLineItem[];
|
|
27
|
+
totals: OrderPaidTotals | null;
|
|
28
|
+
/** Absolute CTA URL to the customer's order/account; null/absent → no button. */
|
|
29
|
+
ctaUrl?: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Absolute URL of the shop terms (which include the §10 withdrawal-right
|
|
32
|
+
* section and the model withdrawal form). Renders the consumer-law footer
|
|
33
|
+
* link; the fine-print paragraph itself is always included (durable-medium
|
|
34
|
+
* confirmation duty, art. 21 ustawy o prawach konsumenta).
|
|
35
|
+
*/
|
|
36
|
+
termsUrl?: string | null;
|
|
37
|
+
/** Optional context name for the selected post-receipt note. */
|
|
38
|
+
contextName?: string | null;
|
|
39
|
+
/** Adopter-formatted, already-localized note about the parcel; null or absent renders nothing. */
|
|
40
|
+
parcelNote?: string | null;
|
|
41
|
+
}
|
|
42
|
+
export interface OrderPaidEmailContent {
|
|
43
|
+
subject: string;
|
|
44
|
+
preheader: string;
|
|
45
|
+
blocks: EmailBlock[];
|
|
46
|
+
}
|
|
47
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
48
|
+
export declare function createOrderPaidContentFactory(input: {
|
|
49
|
+
commerceEmailContent: Pick<CommerceEmailContent, "orderPaid" | "orderRefPrefix">;
|
|
50
|
+
formatCustomerOrderReference: (orderId: string, prefix: string) => string;
|
|
51
|
+
}): {
|
|
52
|
+
orderPaidEmailContent: (locale: Locale, vars: OrderPaidEmailVars, signoff: string) => OrderPaidEmailContent;
|
|
53
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { button, dataTable, heading, linkParagraph, list, paragraph, } from "./blocks.js";
|
|
2
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
3
|
+
export function createOrderPaidContentFactory(input) {
|
|
4
|
+
const { commerceEmailContent, formatCustomerOrderReference } = input;
|
|
5
|
+
function itemLine(item) {
|
|
6
|
+
const base = `${item.quantity}× ${item.name}`;
|
|
7
|
+
return item.lineTotalLabel ? `${base} – ${item.lineTotalLabel}` : base;
|
|
8
|
+
}
|
|
9
|
+
function orderPaidEmailContent(locale, vars, signoff) {
|
|
10
|
+
const copy = commerceEmailContent.orderPaid[locale];
|
|
11
|
+
const orderRef = formatCustomerOrderReference(vars.orderId, commerceEmailContent.orderRefPrefix);
|
|
12
|
+
const intro = vars.mode === "subscription_cycle"
|
|
13
|
+
? copy.introSubscription(orderRef)
|
|
14
|
+
: copy.introOneTime(orderRef);
|
|
15
|
+
const blocks = [
|
|
16
|
+
heading(copy.heading),
|
|
17
|
+
paragraph(copy.greeting(vars.firstName)),
|
|
18
|
+
paragraph(intro),
|
|
19
|
+
];
|
|
20
|
+
blocks.push(vars.items.length > 0 ? list(vars.items.map(itemLine)) : paragraph(copy.noItems));
|
|
21
|
+
if (vars.parcelNote)
|
|
22
|
+
blocks.push(paragraph(vars.parcelNote));
|
|
23
|
+
if (vars.totals) {
|
|
24
|
+
const rows = [];
|
|
25
|
+
if (vars.totals.firstSubscription) {
|
|
26
|
+
rows.push({ label: copy.catalogProductsLabel, value: vars.totals.firstSubscription.catalogLabel });
|
|
27
|
+
if (vars.totals.discountLabel) {
|
|
28
|
+
rows.push({ label: copy.firstSubscriptionDiscountRowLabel, value: vars.totals.discountLabel });
|
|
29
|
+
}
|
|
30
|
+
rows.push({ label: copy.productPayableLabel, value: vars.totals.firstSubscription.productPayableLabel });
|
|
31
|
+
if (vars.totals.firstSubscription.shippingFree) {
|
|
32
|
+
rows.push({ label: copy.shippingLabel, value: copy.shippingFree });
|
|
33
|
+
}
|
|
34
|
+
else if (vars.totals.firstSubscription.shippingLabel) {
|
|
35
|
+
rows.push({ label: copy.shippingLabel, value: vars.totals.firstSubscription.shippingLabel });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (vars.totals.subtotalLabel) {
|
|
39
|
+
rows.push({ label: copy.subtotalLabel, value: vars.totals.subtotalLabel });
|
|
40
|
+
}
|
|
41
|
+
if (!vars.totals.firstSubscription && vars.totals.discountLabel) {
|
|
42
|
+
rows.push({ label: copy.discountRowLabel, value: vars.totals.discountLabel });
|
|
43
|
+
}
|
|
44
|
+
rows.push({
|
|
45
|
+
label: vars.totals.firstSubscription ? copy.finalPaidLabel : copy.totalLabel,
|
|
46
|
+
value: vars.totals.totalLabel,
|
|
47
|
+
});
|
|
48
|
+
blocks.push(dataTable(rows));
|
|
49
|
+
}
|
|
50
|
+
// Selected post-receipt copy is shown for both one-time and subscription-cycle
|
|
51
|
+
// receipts, without changing the payment or delivery facts around it.
|
|
52
|
+
blocks.push(paragraph(copy.receiptNote(vars.contextName ?? null)));
|
|
53
|
+
if (vars.ctaUrl) {
|
|
54
|
+
blocks.push(button(copy.cta, vars.ctaUrl));
|
|
55
|
+
}
|
|
56
|
+
blocks.push(paragraph(copy.outro));
|
|
57
|
+
// Durable-medium confirmation (art. 21 uPK): the receipt must carry the
|
|
58
|
+
// withdrawal-right information alongside a link to the full terms + form.
|
|
59
|
+
blocks.push(paragraph(copy.withdrawalNotice, { muted: true }));
|
|
60
|
+
if (vars.termsUrl) {
|
|
61
|
+
blocks.push(linkParagraph(copy.withdrawalLinkLabel, vars.termsUrl, { muted: true }));
|
|
62
|
+
}
|
|
63
|
+
blocks.push(paragraph(signoff));
|
|
64
|
+
return {
|
|
65
|
+
subject: copy.subject(orderRef),
|
|
66
|
+
preheader: copy.preheader,
|
|
67
|
+
blocks,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return { orderPaidEmailContent };
|
|
71
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CommerceEmailContent } from "./commerceEmailContent.js";
|
|
2
|
+
import type { Locale } from "./email.js";
|
|
3
|
+
import { type EmailBlock } from "./blocks.js";
|
|
4
|
+
export interface OrderRefundedEmailVars {
|
|
5
|
+
firstName: string | null;
|
|
6
|
+
brandName: string;
|
|
7
|
+
orderId: string;
|
|
8
|
+
/** Formatted gross refund total, e.g. "129,99 zł", or null when unknown. */
|
|
9
|
+
amountLabel: string | null;
|
|
10
|
+
/** Absolute CTA URL (back to shop); null/absent → no button. */
|
|
11
|
+
ctaUrl?: string | null;
|
|
12
|
+
}
|
|
13
|
+
export interface OrderRefundedEmailContent {
|
|
14
|
+
subject: string;
|
|
15
|
+
preheader: string;
|
|
16
|
+
blocks: EmailBlock[];
|
|
17
|
+
}
|
|
18
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
19
|
+
export declare function createOrderRefundedContentFactory(input: {
|
|
20
|
+
commerceEmailContent: Pick<CommerceEmailContent, "orderRefunded" | "orderRefPrefix">;
|
|
21
|
+
formatCustomerOrderReference: (orderId: string, prefix: string) => string;
|
|
22
|
+
}): {
|
|
23
|
+
orderRefundedEmailContent: (locale: Locale, vars: OrderRefundedEmailVars, signoff: string) => OrderRefundedEmailContent;
|
|
24
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { accentBox, button, heading, paragraph, } from "./blocks.js";
|
|
2
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
3
|
+
export function createOrderRefundedContentFactory(input) {
|
|
4
|
+
const { commerceEmailContent, formatCustomerOrderReference } = input;
|
|
5
|
+
function orderRefundedEmailContent(locale, vars, signoff) {
|
|
6
|
+
const copy = commerceEmailContent.orderRefunded[locale];
|
|
7
|
+
const orderRef = formatCustomerOrderReference(vars.orderId, commerceEmailContent.orderRefPrefix);
|
|
8
|
+
const blocks = [
|
|
9
|
+
heading(copy.heading),
|
|
10
|
+
paragraph(copy.greeting(vars.firstName)),
|
|
11
|
+
paragraph(copy.intro(orderRef)),
|
|
12
|
+
accentBox(copy.details(vars.amountLabel), { label: copy.detailsLabel }),
|
|
13
|
+
paragraph(copy.returnNote(vars.brandName)),
|
|
14
|
+
];
|
|
15
|
+
if (vars.ctaUrl) {
|
|
16
|
+
blocks.push(button(copy.cta, vars.ctaUrl));
|
|
17
|
+
}
|
|
18
|
+
blocks.push(paragraph(copy.outro));
|
|
19
|
+
blocks.push(paragraph(signoff));
|
|
20
|
+
return {
|
|
21
|
+
subject: copy.subject(orderRef),
|
|
22
|
+
preheader: copy.preheader,
|
|
23
|
+
blocks,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { orderRefundedEmailContent };
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CommerceEmailContent } from "./commerceEmailContent.js";
|
|
2
|
+
import type { Locale } from "./email.js";
|
|
3
|
+
import { type EmailBlock } from "./blocks.js";
|
|
4
|
+
export interface PaymentFailedEmailVars {
|
|
5
|
+
firstName: string | null;
|
|
6
|
+
orderId: string;
|
|
7
|
+
/** Formatted gross total, e.g. "129,99 zł", or null when unknown. */
|
|
8
|
+
amountLabel: string | null;
|
|
9
|
+
mode: "subscription_cycle" | "one_time";
|
|
10
|
+
/** Absolute tokenized /konto/... recovery URL for the same order context. */
|
|
11
|
+
recoveryUrl: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PaymentFailedEmailContent {
|
|
14
|
+
subject: string;
|
|
15
|
+
preheader: string;
|
|
16
|
+
blocks: EmailBlock[];
|
|
17
|
+
}
|
|
18
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
19
|
+
export declare function createPaymentFailedContentFactory(input: {
|
|
20
|
+
commerceEmailContent: Pick<CommerceEmailContent, "paymentFailed" | "orderRefPrefix">;
|
|
21
|
+
formatCustomerOrderReference: (orderId: string, prefix: string) => string;
|
|
22
|
+
}): {
|
|
23
|
+
paymentFailedEmailContent: (locale: Locale, vars: PaymentFailedEmailVars, signoff: string) => PaymentFailedEmailContent;
|
|
24
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { accentBox, button, heading, paragraph, } from "./blocks.js";
|
|
2
|
+
/** Bind host-selected copy and pure helpers without provider or environment access. */
|
|
3
|
+
export function createPaymentFailedContentFactory(input) {
|
|
4
|
+
const { commerceEmailContent, formatCustomerOrderReference } = input;
|
|
5
|
+
function paymentFailedEmailContent(locale, vars, signoff) {
|
|
6
|
+
const copy = commerceEmailContent.paymentFailed[locale];
|
|
7
|
+
const orderRef = formatCustomerOrderReference(vars.orderId, commerceEmailContent.orderRefPrefix);
|
|
8
|
+
const blocks = [
|
|
9
|
+
heading(copy.heading),
|
|
10
|
+
paragraph(copy.greeting(vars.firstName)),
|
|
11
|
+
paragraph(copy.intro(orderRef)),
|
|
12
|
+
accentBox(copy.details(vars.amountLabel, vars.mode), { label: copy.detailsLabel }),
|
|
13
|
+
button(copy.cta, vars.recoveryUrl),
|
|
14
|
+
];
|
|
15
|
+
blocks.push(paragraph(copy.outro));
|
|
16
|
+
blocks.push(paragraph(signoff));
|
|
17
|
+
return {
|
|
18
|
+
subject: copy.subject(orderRef),
|
|
19
|
+
preheader: copy.preheader,
|
|
20
|
+
blocks,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { paymentFailedEmailContent };
|
|
24
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Delivery seam for public intake capabilities. */
|
|
2
|
+
export type PublicIntakeDeliveryPurpose = "transactional" | "admin_notification";
|
|
3
|
+
export type PublicIntakeRecipientKind = "external_contact" | "admin_internal";
|
|
4
|
+
export interface PublicIntakePolicyDecision {
|
|
5
|
+
allowed: boolean;
|
|
6
|
+
reason: string;
|
|
7
|
+
decisionId: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface PublicIntakeDeliveryResult {
|
|
10
|
+
/** The delivery implementation returned a durable message identifier. */
|
|
11
|
+
accepted: boolean;
|
|
12
|
+
messageId: string | null;
|
|
13
|
+
/** A policy or explicit no-egress terminal outcome. */
|
|
14
|
+
skip: string | null;
|
|
15
|
+
/** A non-sent terminal outcome, including an ambiguous provider acceptance. */
|
|
16
|
+
error: string | null;
|
|
17
|
+
}
|
|
18
|
+
export interface PublicIntakeDeliveryMessage {
|
|
19
|
+
sender: string;
|
|
20
|
+
to: string;
|
|
21
|
+
subject: string;
|
|
22
|
+
html: string;
|
|
23
|
+
text?: string;
|
|
24
|
+
replyTo?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface PublicIntakeDeliveryPort {
|
|
27
|
+
evaluatePolicy(input: {
|
|
28
|
+
email: string | null | undefined;
|
|
29
|
+
purpose: PublicIntakeDeliveryPurpose;
|
|
30
|
+
source: string;
|
|
31
|
+
recipientKind: PublicIntakeRecipientKind;
|
|
32
|
+
sourceTable?: "b2b_inquiries";
|
|
33
|
+
sourceId?: string | null;
|
|
34
|
+
metadata: Record<string, unknown>;
|
|
35
|
+
}): Promise<PublicIntakePolicyDecision>;
|
|
36
|
+
deliver(input: {
|
|
37
|
+
source: string;
|
|
38
|
+
templateSlug: string;
|
|
39
|
+
policyDecisionId: string | null;
|
|
40
|
+
dedupeKey: string;
|
|
41
|
+
purpose: PublicIntakeDeliveryPurpose;
|
|
42
|
+
triggerEvent: string;
|
|
43
|
+
recipientEmail: string;
|
|
44
|
+
aggregateType: string;
|
|
45
|
+
aggregateId: string;
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
message: PublicIntakeDeliveryMessage;
|
|
48
|
+
}): Promise<PublicIntakeDeliveryResult>;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|