@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
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,90 @@ SemVer promise.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.17.0]
|
|
12
|
+
|
|
13
|
+
- Publishable on the npm `latest` dist-tag as `0.17.0`, from tag
|
|
14
|
+
`openlup-platform-v0.17.0`.
|
|
15
|
+
|
|
16
|
+
- Add experimental `./communications` and browser-safe
|
|
17
|
+
`./communications/contracts`, plus generic capped raw-body, hex-HMAC and
|
|
18
|
+
constant-time comparison helpers in the existing `./http` entry. Compose neutral
|
|
19
|
+
transport/results/capture, rendering/content, independent Auth verification,
|
|
20
|
+
receipt/observation, polling/reconciliation, consent and membership sync engines.
|
|
21
|
+
Provider clients, protocol/key mapping, copy and activation remain host-owned.
|
|
22
|
+
- Require explicit egress admission for supported injected network senders.
|
|
23
|
+
Guarded transports validate fresh host decisions, redirect sink sends and
|
|
24
|
+
suppress drops before network entry; provider names grant no admission.
|
|
25
|
+
Capture remains local acceptance. Preserve the maintained reference transport
|
|
26
|
+
through its trusted composition bridge and keep Auth/provider verification separate.
|
|
27
|
+
- Add Polish/English invoice, role, opt-out and inquiry default-content factories
|
|
28
|
+
with whole-copy injection. Preserve implicit Polish invoice and existing role
|
|
29
|
+
expectations; EN invoice is construction-time opt-in. Reference opt-out page
|
|
30
|
+
copy, EN legacy/error text, document language and escaping change deliberately.
|
|
31
|
+
Pure inquiry rendering activates no sender. See the
|
|
32
|
+
[B1/B2 expectation inventory](../../docs/platform/plans/oss-m04-communications-triggers.md#b1-egress-boundary).
|
|
33
|
+
- Add an opt-in immutable composition-time purpose registry with mandatory
|
|
34
|
+
classification and finite legacy defaults. Registration grants no consent,
|
|
35
|
+
provider activation or managed schema permission; custom-purpose persistence
|
|
36
|
+
stays with the host. Add neutral newsletter processing and marketing ports
|
|
37
|
+
without a runner or a new public purpose.
|
|
38
|
+
- Add four bounded native store groups: delivery observation/readback, existing-rail
|
|
39
|
+
membership sync, operator notification recipients and durable consent decisions.
|
|
40
|
+
Append CREATE-only direct catalogue position 70,
|
|
41
|
+
`20261019200000_communications_native_operations.sql`, and its exact sparse
|
|
42
|
+
projection. Standard factory lanes refuse unsafe effective privileges.
|
|
43
|
+
Sync uses `public.outbox_events`; the sidecar is not another executor.
|
|
44
|
+
- Compose selected native readback and atomic signed-token preferences with Core
|
|
45
|
+
readiness, explicit provider/binding identities and host-supplied clocks and
|
|
46
|
+
schedules. Add distinct opt-in operator evidence and installed substitute-provider
|
|
47
|
+
proof. Captured, network-accepted and membership-synced are not delivered.
|
|
48
|
+
Native consent excludes managed 16-hour / 2-day / 4-week caps and legacy
|
|
49
|
+
contact-touching, and is not a send-time fence. No default cadence, deployment
|
|
50
|
+
activation, full native general sender or UI package capability is added.
|
|
51
|
+
[T07 destinations](../../docs/platform/plans/oss-m04-communications-triggers.md#t07-destination-matrix)
|
|
52
|
+
remain explicitly open with their owning modules.
|
|
53
|
+
- @openlup/platform size growth: added the reviewed neutral communications runtime and browser content contracts, bounded native stores and SQL projection, and their API/adoption documentation.
|
|
54
|
+
|
|
55
|
+
Migration: `0.16.0` did not export communications. Upgrade the complete package
|
|
56
|
+
set to `0.17.0` for the exact core peers, then explicitly select and bind the new
|
|
57
|
+
experimental capability. Existing non-communications entries retain their contracts.
|
|
58
|
+
The host retains renderer/copy, environment, origin, egress, provider protocol,
|
|
59
|
+
credentials and schedule ownership. The generic HTTP helpers do not replace the
|
|
60
|
+
independent Auth Standard Webhooks or provider-specific verification protocols.
|
|
61
|
+
|
|
62
|
+
Install the complete selected direct canonical catalogue through position 70
|
|
63
|
+
before selecting native stores. `COMMUNICATIONS_MIGRATIONS` projects positions
|
|
64
|
+
2, 9, 20 and 70; never reapply these sparse files over an existing canonical
|
|
65
|
+
history or treat them as a standalone chain. Preserve managed/private lineage
|
|
66
|
+
and custom-purpose persistence: registering a purpose does not expand managed
|
|
67
|
+
CHECKs. Thread the same registered purpose union and registry through selected
|
|
68
|
+
policy, token, newsletter and store bindings; omitted arguments retain finite
|
|
69
|
+
legacy defaults and existing signing bytes.
|
|
70
|
+
|
|
71
|
+
`registerNativeSyncWorkInTransaction` is a trusted host transaction seam. Its
|
|
72
|
+
caller-owned executor must already hold the lane's safe effective privileges;
|
|
73
|
+
this function does not check those privileges. The caller owns the transaction
|
|
74
|
+
and must commit or roll back permission, sidecar and existing-rail effects
|
|
75
|
+
atomically. Use a safely admitted lane; the helper grants no provider or claim
|
|
76
|
+
authority. Standard native sync factory transactions check
|
|
77
|
+
`public.communication_native_sync_state`, `public.outbox_events` and
|
|
78
|
+
`public.communication_recipient_consents`.
|
|
79
|
+
|
|
80
|
+
Custom native stores must provide binding-scoped `findByMessageId`, bounded
|
|
81
|
+
`listEvidence` (1–100) and atomic `registerPreference` as declared by the new
|
|
82
|
+
surface. Supply explicit provider/binding identities and full catalogue admission.
|
|
83
|
+
Hosts preserving older opt-out page bytes retain their own presentation binding;
|
|
84
|
+
token purposes, verification and existing HTTP status/header semantics remain.
|
|
85
|
+
See the [package composition guidance](README.md#communications-import).
|
|
86
|
+
|
|
87
|
+
Growth reading: +61.4% against the retained initial `0.16.0` baseline (256,973
|
|
88
|
+
packed bytes), measured before S1 notes at 414,808 bytes; final S1 measurements
|
|
89
|
+
are recorded in the programme evidence. No cap is changed. Baseline evidence
|
|
90
|
+
(2026-10-20): the published `0.16.0` tarball is 257,434 packed bytes, SHA256
|
|
91
|
+
`030756175d61279aab0ae7b26b27783e08467ec93673f5623d19d0b7fc436463`.
|
|
92
|
+
S1 option B retains the initial release-gates baseline rather than replacing it
|
|
93
|
+
with this observed registry identity.
|
|
94
|
+
|
|
11
95
|
## [0.16.0]
|
|
12
96
|
|
|
13
97
|
- Publishable on the npm `latest` dist-tag as `0.16.0`, from tag
|
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ It holds the runnable server substrate an OpenLup application composes: the Node
|
|
|
6
6
|
|
|
7
7
|
## Package surface
|
|
8
8
|
|
|
9
|
-
`release-gates.json` declares kind `rail`: this foundation provides runtime infrastructure over core ports, matching the architecture's rail responsibility. Its
|
|
9
|
+
`release-gates.json` declares kind `rail`: this foundation provides runtime infrastructure over core ports, matching the architecture's rail responsibility. Its thirteen experimental entries each bind a declaration snapshot and package-owned smoke tests. The API checker reads this same inventory.
|
|
10
10
|
|
|
11
11
|
| Export | Contents |
|
|
12
12
|
| --- | --- |
|
|
13
|
-
| `./http` | Node request adaptation, deadlines, security headers and static documents, and `createNodeHttpRuntime` with its fixed request order |
|
|
13
|
+
| `./http` | Generic capped raw-body reader, hex HMAC and constant-time token comparison; Node request adaptation, deadlines, security headers and static documents, and `createNodeHttpRuntime` with its fixed request order |
|
|
14
14
|
| `./bff` | `createBffDispatcher`, `lazyBffRoute`, the hosted router URL rewrite, the response envelope (`createBffResponder`), the observed request context and the health route |
|
|
15
15
|
| `./scheduler` | Transport-neutral scheduled jobs (`ScheduledJob`, the job registry, the lease-aware runner and the authenticated HTTP cron entry), path-declared jobs from configuration, the node-cron scheduler with per-job advisory locks, hosted cron verification, the cron entrypoint guard (it compares the presented bearer token with `CRON_SECRET` in constant time) and direct job bindings |
|
|
16
16
|
| `./blob` | Filesystem, S3-compatible, Supabase Storage and Vercel Blob adapters, and `bindBlobPort` |
|
|
@@ -21,6 +21,8 @@ It holds the runnable server substrate an OpenLup application composes: the Node
|
|
|
21
21
|
| `./composition` | `createBundleComposer`, the Node HTTP binding helpers and `createNodeHost` |
|
|
22
22
|
| `./identity` | Experimental capability: identity engine, authorization, profile readers, session adapters and BFF factories |
|
|
23
23
|
| `./identity/contracts` | Experimental capability: browser-safe customer auth port, value types and provider parser |
|
|
24
|
+
| `./communications` | Experimental existing public consent/status, newsletter sync, Auth email hook, transport contracts/capture, observation/polling orchestration, standard webhook verification and delivery receipts; host-selected rendering, egress, protocol mapping and control policy |
|
|
25
|
+
| `./communications/contracts` | Pure renderer, block builders, copy-injected commerce/subscription factories and email/newsletter/Auth/intake/receipt types; no Zod, Node or provider runtime imports |
|
|
24
26
|
|
|
25
27
|
## Scheduled jobs
|
|
26
28
|
|
|
@@ -83,7 +85,7 @@ failed HEAD; use an upload or list operation to observe an S3 loading refusal.
|
|
|
83
85
|
|
|
84
86
|
## Verification
|
|
85
87
|
|
|
86
|
-
This package's tests are part of the repository's required test selection; from this directory, `npm test` runs them alone. The tests rewrite the originating application's characterization with neutral names and synthetic data, and a boundary test refuses
|
|
88
|
+
This package's tests are part of the repository's required test selection; from this directory, `npm test` runs them alone. The tests rewrite the originating application's characterization with neutral names and synthetic data, and a boundary test refuses environment reads and provider imports outside its explicit `pg` adapter and `@aws-sdk/client-s3` blob-client allowlist. Follow [repository testing](../../CONTRIBUTING.md#test-scope-and-diagnostics) for placement, setup and speed rules.
|
|
87
89
|
|
|
88
90
|
The module-boundary proof permits one optional `./<module>/contracts` export
|
|
89
91
|
only when that module declares `contracts: true` in `PLATFORM_MODULE_GRAPH` in
|
|
@@ -110,7 +112,7 @@ The job-run ledger SQL asset test verifies a readable, nonempty file within the
|
|
|
110
112
|
package SQL directory. Its SQL parity tests bind the actual adapter calls to the
|
|
111
113
|
shipped routine signatures; the asset's explanatory header may be edited freely.
|
|
112
114
|
|
|
113
|
-
`npm run api:check` compares
|
|
115
|
+
`npm run api:check` compares every declared entry graph with the
|
|
114
116
|
committed `api/*.api.md` reports. After building, deliberately regenerate them
|
|
115
117
|
with `node --experimental-strip-types ./scripts/api-contract.ts --update` from
|
|
116
118
|
this package, and review the declaration changes.
|
|
@@ -425,7 +427,8 @@ operator/customer batches. See [identity privacy](../../docs/platform/IDENTITY.m
|
|
|
425
427
|
for refusals, token limits and retained obligations.
|
|
426
428
|
|
|
427
429
|
The complete direct conformance is included in
|
|
428
|
-
`
|
|
430
|
+
`npm test -- tests/postgres/operatorIdentityUpgrade.test.ts` from the repository
|
|
431
|
+
root after normal setup. A maintainer host resource broker is optional.
|
|
429
432
|
For managed conformance, supply the same three `OPENLUP_MANAGED_CONFORMANCE_*`
|
|
430
433
|
local disposable-stack settings described for operator invitations, with
|
|
431
434
|
`OPENLUP_MANAGED_CONFORMANCE_DATABASE_URL` set to the database owner
|
|
@@ -471,3 +474,280 @@ panel. Its explicit runtime must supply actual routes and readiness admission;
|
|
|
471
474
|
the shell refuses a missing composition. See the
|
|
472
475
|
[identity reference guide](../../docs/platform/IDENTITY.md#disposable-identity-reference)
|
|
473
476
|
for both-bundle commands, the committed managed grants and installation limits.
|
|
477
|
+
|
|
478
|
+
## Communications import
|
|
479
|
+
|
|
480
|
+
For adoption from `0.16.0`, follow the [0.17.0 Migration guidance](CHANGELOG.md#0170)
|
|
481
|
+
for the complete package set, canonical SQL installation and host-owned bindings.
|
|
482
|
+
|
|
483
|
+
M04 P1 relocates the existing public implementation without changing its reference
|
|
484
|
+
outputs. The reference shims bind the existing renderer, egress resolver, origin
|
|
485
|
+
defaults, delivery-shaping policy and receipt transaction lane. The package does
|
|
486
|
+
not select a deployment, mount a route or schedule another executor.
|
|
487
|
+
`createCommunicationsContribution` requires the host's version and schema
|
|
488
|
+
inventory; supplied handlers, schedules, routes and ports describe only that
|
|
489
|
+
host's selection.
|
|
490
|
+
|
|
491
|
+
`COMMUNICATIONS_MIGRATIONS` projects three existing canonical units byte for byte:
|
|
492
|
+
comms outbox (position 2), transactional receipts (9) and communications control
|
|
493
|
+
plane (20). This sparse list is not a standalone migration chain. Apply the full
|
|
494
|
+
selected canonical prefix through its existing runner; importing the module does
|
|
495
|
+
not apply SQL or advertise missing managed/direct capabilities.
|
|
496
|
+
|
|
497
|
+
Browser previews retain their reference renderer, content defaults and template
|
|
498
|
+
policy. The Auth hook receives that same renderer through its reference shim.
|
|
499
|
+
The standard Auth webhook and the maintained HTTP mail provider verifiers keep their separate signature
|
|
500
|
+
formats and clocks; the generic helper added to `./http` replaces neither.
|
|
501
|
+
E2 is applied: the payment webhook module delegates these five generic helpers.
|
|
502
|
+
`readRawBody` is the same package function object with its original declared
|
|
503
|
+
`(req: VercelRequest) => Promise<string>` signature; the other four exports are
|
|
504
|
+
plain re-exports. The payment provider verification and its replay tolerance stay local.
|
|
505
|
+
The maintained mail transport, credentials, callback verification/mapping,
|
|
506
|
+
poll read/mapping, timeline and send-ledger adapters remain in reference source.
|
|
507
|
+
B1 changes only the four raw-injection guard sites in the reference delivery
|
|
508
|
+
adapters and the approved invoice test fixture; the concrete client and all
|
|
509
|
+
other vendor-directory files retain the comparison-base bytes. The package exposes
|
|
510
|
+
transport/result contracts and capture without a concrete mail factory.
|
|
511
|
+
The type-only `CommunicationProvider<Provider>` and `EmailMessageReadModel<Provider>`
|
|
512
|
+
accept host vocabulary; reference types retain their original literal.
|
|
513
|
+
|
|
514
|
+
`createGuardedEmailTransport({ providerKind, policy, send })` is the network
|
|
515
|
+
adapter constructor. At each send it awaits a fresh host policy, validates the
|
|
516
|
+
whole decision and enters the sender only for a coherent `production`,
|
|
517
|
+
`sandbox_direct` or `sandbox_sink` decision. The sender receives the effective
|
|
518
|
+
recipient and a frozen context with intended recipient, host-selected credential,
|
|
519
|
+
mode, reason and environment tag. It must consume that context when selecting
|
|
520
|
+
credentials and emitting provider metadata. The package reads no environment and
|
|
521
|
+
contains no provider client. Missing/throwing policy, unknown modes, mismatched
|
|
522
|
+
recipients/tags, blank credentials or unsupported fields fail with status zero,
|
|
523
|
+
no identifier and bounded error codes. Reasons are lower-case token codes up to
|
|
524
|
+
80 characters. One unadorned `local@domain.example` recipient mailbox is required;
|
|
525
|
+
whitespace, lists, display names and local-only domains are refused on this new
|
|
526
|
+
alternate-transport policy boundary.
|
|
527
|
+
|
|
528
|
+
`blocked` returns failure; explicit `drop` returns terminal suppression with no
|
|
529
|
+
send, no identifier and an ineligible sent timestamp. Arbitrary injected objects
|
|
530
|
+
are refused by `guardEmailTransport`; a provider name or copied capture shape
|
|
531
|
+
cannot establish admission. Package-created capture retains its ordered envelopes
|
|
532
|
+
and synthetic identifiers with no network effect. Capture acceptance remains
|
|
533
|
+
local acceptance, never evidence of external delivery.
|
|
534
|
+
|
|
535
|
+
`admitPolicyEnforcedEmailTransport` is the trusted host bridge for a transport
|
|
536
|
+
that already enforces egress internally, as the maintained reference client does.
|
|
537
|
+
The package registry owns its identity; this bridge performs no second routing
|
|
538
|
+
or credential decision. It is a composition trust boundary, not a sandbox for
|
|
539
|
+
host code: callers must not admit an unguarded network sender. New adapters should
|
|
540
|
+
use the validating constructor above. The reference default retains its original
|
|
541
|
+
sink/drop policy, key selection, optional payload fields, headers, signal and
|
|
542
|
+
result/error semantics. `createAuthEmailTransport` preserves the Auth envelope
|
|
543
|
+
mapping and admission; raw Auth closures are refused before their send method.
|
|
544
|
+
Admin/control and required-audit ordering stay at their existing callers.
|
|
545
|
+
No egress result authorizes a subscription-state or delivery-cycle mutation.
|
|
546
|
+
|
|
547
|
+
`processEmailObservation` accepts already authenticated, decoded and environment-admitted
|
|
548
|
+
input. It looks up a local send, constructs evidence only when found, applies one
|
|
549
|
+
observation and records best-effort telemetry. Lookup and apply failures propagate.
|
|
550
|
+
`runDeliveryReconciliation` polls candidates sequentially, rotates every non-404
|
|
551
|
+
read, and delegates consecutive failed-404 abandonment at threshold three to the
|
|
552
|
+
store. Rotation failure is counted without dropping delivery truth; apply failure
|
|
553
|
+
continues the batch. Candidate-query, read and not-found-store throws propagate.
|
|
554
|
+
The host classifies protocol snapshots after rotation and passes recipient/evidence
|
|
555
|
+
through unchanged. The existing reference domain entry points use both engines;
|
|
556
|
+
routes and schedules remain the same.
|
|
557
|
+
|
|
558
|
+
Neither engine writes suppression or subscription state. Both callback and poll
|
|
559
|
+
composition retain `communication_update_email_delivery_from_provider` as the
|
|
560
|
+
single durable convergence/suppression writer. These ports add no in-memory
|
|
561
|
+
replay authority, database store or second executor. Legacy transport identifier
|
|
562
|
+
fields remain compatibility residue; new ports use `messageId`.
|
|
563
|
+
|
|
564
|
+
`createCommunicationPurposeRegistry` composes immutable exact identifiers with a
|
|
565
|
+
mandatory `marketing` or `non-marketing` classification. Its built-ins cannot be
|
|
566
|
+
redeclared. Existing policy, token and newsletter schema calls keep their finite
|
|
567
|
+
defaults. Passing a registry to policy evaluation, token verification or
|
|
568
|
+
`createNewsletterIntegrationSchemas` recognizes its identifiers without granting
|
|
569
|
+
permission. Custom marketing purposes still require a grant and respect
|
|
570
|
+
suppression; built-in tester pause and permission rules stay in force.
|
|
571
|
+
|
|
572
|
+
`createRegisteredPublicPreferenceTokenPort` requires an explicit host persistence
|
|
573
|
+
function and passes the exact purpose and frozen classification to it. It creates
|
|
574
|
+
no sync event. Stock managed permission and newsletter-sync tables retain their
|
|
575
|
+
finite CHECKs; registering a purpose does not expand those stores. Additional
|
|
576
|
+
persistence and schema requirements belong to the adopter. No new purpose, table,
|
|
577
|
+
migration, preference UI, URL or default fan-out is installed.
|
|
578
|
+
|
|
579
|
+
`processNewsletterWebhookEvent` supplies the existing event → permission →
|
|
580
|
+
settlement sequence behind neutral ports. Reference HTTP admission and signature
|
|
581
|
+
mapping stay local. Explicit registered purposes survive permission writes;
|
|
582
|
+
purpose-less feedback still targets exactly the two existing marketing purposes.
|
|
583
|
+
Verified opt-in, suppression and replay rules are unchanged. Registered dispatch
|
|
584
|
+
checks the batch's purposes before provider effects and retains claim tokens,
|
|
585
|
+
echo and capability skips, retry behavior and counters. Sync-settled and accepted
|
|
586
|
+
receipts are distinct from delivered evidence. Existing job admission, binding,
|
|
587
|
+
leases, finish-run linkage and operator readback retain their host composition.
|
|
588
|
+
No shared sender pipeline is added: required audit and best-effort send paths
|
|
589
|
+
keep their distinct ordering and failure semantics.
|
|
590
|
+
|
|
591
|
+
`MarketingAutomationProviderPort` and `MarketingAutomationStorePort` describe
|
|
592
|
+
explicit scope, claim/generation fences, admission/deadlines, idempotency,
|
|
593
|
+
observations/history and ambiguity/backoff. The synthetic substitute-provider
|
|
594
|
+
conformance suite is an executable contract, not an installed worker or a remote
|
|
595
|
+
provider certification. Evidence carries opaque references; remote feedback does
|
|
596
|
+
not grant local consent. No trigger catalogue, schedule or provider activation
|
|
597
|
+
is supplied.
|
|
598
|
+
|
|
599
|
+
The required selection retains the moved-code witnesses and neutral package
|
|
600
|
+
characterization tests. The package W1 hook reader witnesses the Auth composition;
|
|
601
|
+
provider-specific reference test paths remain in the complete suite. The
|
|
602
|
+
[M04 ledger](../../docs/platform/plans/oss-m04-communications-triggers.md#verification-ledger)
|
|
603
|
+
records counted cases, separate boundary iterations and local timing provenance.
|
|
604
|
+
The clean-commit artifact gate enforces all merged caps, including the owner-read, measured limit on the complete contracts entry. Artifact admission still needs a
|
|
605
|
+
clean supervisor commit.
|
|
606
|
+
See the [M04 plan](../../docs/platform/plans/oss-m04-communications-triggers.md)
|
|
607
|
+
for scope, later waves and verification limits.
|
|
608
|
+
|
|
609
|
+
## Package artifact limits
|
|
610
|
+
|
|
611
|
+
The monorepo's package artifact checker enforces this package's
|
|
612
|
+
`release-gates.json` caps and packed content allowlist. Only
|
|
613
|
+
`--release-set <version>` checks compressed growth against the last released
|
|
614
|
+
baseline, with explanations in the new set's changelog section and release body. Its browser-safe `./identity/contracts` export also has a minified+gzip cap. See the
|
|
615
|
+
[package artifact policy](https://github.com/openlup/openlup/blob/main/.github/VERSIONING_AND_EOL.md#package-artifact-limits)
|
|
616
|
+
for measured sizes, current caps, the S1 baseline refresh and refusal remedies.
|
|
617
|
+
Artifact checks require a clean package directory; `--manifest-only` supplies no
|
|
618
|
+
artifact evidence.
|
|
619
|
+
|
|
620
|
+
### Pure email content and browser rendering
|
|
621
|
+
|
|
622
|
+
`./communications/contracts` now exports `renderEmail`, the nine existing block
|
|
623
|
+
constructors, `guideCardBlock` and per-template content factories.
|
|
624
|
+
Each `create*ContentFactory` binds host-selected copy plus only the pure helpers
|
|
625
|
+
it uses: order-reference formatting, payment-cause wording or marketing footer.
|
|
626
|
+
Localized review routes remain in the reference helper.
|
|
627
|
+
In P3 no copy pack, brand, locale choice, environment reader, provider client or
|
|
628
|
+
sending policy moved into this entry. B2 adds the explicit neutral defaults below. The existing email DTOs remain its canonical types.
|
|
629
|
+
Reference `petName` compatibility inputs are translated to neutral `contextName`
|
|
630
|
+
by their existing facades. Complete subjects, preheaders, ordered blocks and
|
|
631
|
+
HTML/text remain byte-identical, including omitted and explicit optional fields.
|
|
632
|
+
|
|
633
|
+
Browser previews continue through those facades to contracts values only. Auth
|
|
634
|
+
uses its existing server hook factory with the same host renderer injection;
|
|
635
|
+
its inactive public content binding still refuses with 503. Standard Auth,
|
|
636
|
+
mail callback, integration-event and generic HTTP verification remain separate
|
|
637
|
+
policies with their existing raw-byte and replay behavior. No crypto refactor,
|
|
638
|
+
new entry, dependency or graph edge is part of P3.
|
|
639
|
+
|
|
640
|
+
The contracts conformance test compiles the complete entry with no Node types
|
|
641
|
+
and checks its value inventory and import closure. The cold consumer repeats the
|
|
642
|
+
exact inventory and renders with fetch forbidden and optional peers absent,
|
|
643
|
+
retaining all other consumer checks. Browser size measures every runtime export
|
|
644
|
+
of the built entry through `browserEntryBytes`; it never measures a tree-shaken
|
|
645
|
+
consumer subset. See the M04 ledger for the measured size, owner-read cap and
|
|
646
|
+
working-tree versus signed-candidate evidence limits.
|
|
647
|
+
|
|
648
|
+
P3's complete built contracts entry measures **5,992 B minified+gzip**;
|
|
649
|
+
the owner-read cap is **11,776 B**, rounded to the nearest 512 B at about
|
|
650
|
+
twice that measurement. Only this browser limit changes. Existing pack classes,
|
|
651
|
+
other browser limits and clean-candidate artifact checks remain binding.
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
M04 B2 adds four default factories in this same pure contracts entry:
|
|
655
|
+
`createInvoiceDocumentContentFactory`, `createRoleNotificationContentFactory`,
|
|
656
|
+
`createInquiryContentFactory` and `createOptOutContentFactory`. Each accepts an
|
|
657
|
+
optional complete bilingual copy replacement; each content call takes an explicit
|
|
658
|
+
`pl`/`en` locale. Invoice takes resolved order/document references, kind and account
|
|
659
|
+
URL; role takes role, operator URL and optional pending expiry. Inquiry builds
|
|
660
|
+
receipt/notice blocks from caller details, signoff and URL without sending or
|
|
661
|
+
promising a response time. Opt-out returns display strings for seven outcomes;
|
|
662
|
+
it verifies no token and writes no consent. Hosts own brand, locale selection,
|
|
663
|
+
URLs, policy and delivery.
|
|
664
|
+
|
|
665
|
+
The reference invoice adapter defaults to its byte-identical Polish output; explicit
|
|
666
|
+
construction locale EN maps to `/account?sekcja=orders`, while the production
|
|
667
|
+
composition still omits locale. All existing role outputs remain identical.
|
|
668
|
+
The reference opt-out page now selects Polish/EN throughout, escapes display values,
|
|
669
|
+
and uses neutral selected-communications/service-message wording. Its methods,
|
|
670
|
+
verification, purpose allowlist, durable RPC, headers and statuses are unchanged.
|
|
671
|
+
Generic inquiry is only a pure binding; the existing private-label sender stays
|
|
672
|
+
unchanged. Invoice/role gain Polish canon previews; no sender/registry activation.
|
|
673
|
+
See the [complete B2 expectation ledger](../../docs/platform/plans/oss-m04-communications-triggers.md#b2-changed-expectations-and-preservation)
|
|
674
|
+
and [default conformance tests](test/communications/contentDefaults.test.ts).
|
|
675
|
+
The measured B2 contracts entry is 8,210 B minified+gzip under the unchanged
|
|
676
|
+
11,776 B cap; this is a local built-entry measurement, not release admission.
|
|
677
|
+
|
|
678
|
+
### Native communications operations (development preview)
|
|
679
|
+
|
|
680
|
+
The server entry `@openlup/platform/communications` additionally exports
|
|
681
|
+
`createPostgresDeliveryReconciliationPort`, `createPostgresCommunicationSyncStore`,
|
|
682
|
+
`createPostgresNotificationRecipientsPort` and `createPostgresConsentEvaluator`.
|
|
683
|
+
Install the complete canonical manifest through position 70 before selecting
|
|
684
|
+
these factories. `COMMUNICATIONS_MIGRATIONS` now projects positions 2, 9, 20 and
|
|
685
|
+
70; it remains a sparse inventory, not an installer. Missing schema/configuration
|
|
686
|
+
is an error, never an empty queue or an allow decision.
|
|
687
|
+
|
|
688
|
+
Each factory owns a capability-local, role-free transaction lane and lazy `pg`
|
|
689
|
+
pool, with `close()` for host cleanup. Only a trusted host may hold these owner
|
|
690
|
+
credentials. Effective PUBLIC/browser table, column and inherited privileges
|
|
691
|
+
cause refusal; the CREATE-only forward intentionally changes no old ACL or role.
|
|
692
|
+
Do not expose a factory or its database lane to browser callers. The directory
|
|
693
|
+
requires a verified active human operator, live communications authorization and
|
|
694
|
+
absence of machine authority in the same transaction as each operation.
|
|
695
|
+
|
|
696
|
+
A host registers `evidence: "network_accepted"` only after actual network
|
|
697
|
+
acceptance, with a unique source key and binding. Capture is never registered as
|
|
698
|
+
a network target. Polls and admitted callbacks call the same `applyObservation`
|
|
699
|
+
writer; observation-key replay must preserve the immutable fact. Readback keeps
|
|
700
|
+
acceptance, observed state, attempt/404 counts and abandonment separate. Only
|
|
701
|
+
three consecutive 404s abandon a candidate; abandonment is not failed/delivered.
|
|
702
|
+
Bounce/complaint writes the authoritative fingerprint's suppression atomically.
|
|
703
|
+
No subscription or renewal state is changed.
|
|
704
|
+
|
|
705
|
+
For newsletter sync, inject `rail: db => createPostgresOutboxStore(db)` from
|
|
706
|
+
`@openlup/outbox/postgres` in host composition. `db` is the current transaction,
|
|
707
|
+
so claim commits before I/O and rail ack and sidecar settlement commit together.
|
|
708
|
+
`registerWork` creates one existing-outbox identity for a source and target
|
|
709
|
+
binding. Successive preferences for one contact/target share the rail aggregate,
|
|
710
|
+
so newer work cannot overtake older unprocessed work. Configure a distinct
|
|
711
|
+
binding per target/provider, and exclude
|
|
712
|
+
`nativeSyncEventType(binding)` from generic dispatch registries. Invoke only
|
|
713
|
+
`runCommunicationSyncDispatch` with an explicit neutral membership provider.
|
|
714
|
+
The sidecar cannot claim work and has no lease or drainer. A membership settlement
|
|
715
|
+
records sync progress, never email delivery; remote exactly-once effects are not
|
|
716
|
+
promised across a process crash. There is no automatic backfill or activation.
|
|
717
|
+
|
|
718
|
+
Native consent evaluates registered P4 policy against the authoritative native
|
|
719
|
+
permission and persists the decision before returning its id. Admin notices need
|
|
720
|
+
an active source-bound notification recipient. Optional `testerPaused` reads
|
|
721
|
+
host-owned authoritative pause state inside that transaction; omitted means no
|
|
722
|
+
pause policy. The capability explicitly declares `managedFrequencyCaps: false`,
|
|
723
|
+
`legacyContactTouching: false`, `sendTimeFence: false`: managed 16-hour / 2-day /
|
|
724
|
+
4-week caps and legacy contact-touching are excluded. Evaluation does not fence a
|
|
725
|
+
later send against changed consent. Custom-purpose persistence remains host-owned.
|
|
726
|
+
|
|
727
|
+
The [callable reference binding](../../server/runtime/communications/communicationsLifecycleBinding.ts)
|
|
728
|
+
selects only `PLATFORM_BUNDLE=node-postgres` with `DATABASE_URL`; it closes pools
|
|
729
|
+
on success/failure and supplies no network/provider default. Existing managed
|
|
730
|
+
HTTP cron/UI routes retain their existing composition. See the
|
|
731
|
+
[B3 expectation inventory](../../docs/platform/plans/oss-m04-communications-triggers.md#b3-native-stores)
|
|
732
|
+
and [real-PG witnesses](../../tests/postgres/communicationsNative.test.ts).
|
|
733
|
+
|
|
734
|
+
C-compose extends the native delivery store with binding-scoped `findByMessageId`
|
|
735
|
+
and bounded `listEvidence({limit})` (1–100). Existing observation/replay and polling
|
|
736
|
+
methods retain their behavior. `registerPreference` on the native sync store
|
|
737
|
+
commits an authoritative denied/suppressed permission and default-purpose sync
|
|
738
|
+
work together; tester permission adds no marketing work. The trusted
|
|
739
|
+
`registerNativeSyncWorkInTransaction` helper contains the same registration SQL
|
|
740
|
+
used by `registerWork`; standalone input validation still precedes database entry.
|
|
741
|
+
This helper is a trusted host transaction seam: its caller-owned executor must
|
|
742
|
+
already hold the lane's safe effective privileges; the function does not check
|
|
743
|
+
them. Standard native sync factory transactions check
|
|
744
|
+
`public.communication_native_sync_state`, `public.outbox_events` and
|
|
745
|
+
`public.communication_recipient_consents`. The caller owns the transaction and
|
|
746
|
+
must commit or roll back permission, sidecar and existing-rail effects atomically.
|
|
747
|
+
Use a safely admitted lane; the helper grants no claim token or provider authority.
|
|
748
|
+
|
|
749
|
+
Reference composition remains outside the package: actual installed factories,
|
|
750
|
+
Core readiness, explicit provider ports and host-supplied schedules. Native
|
|
751
|
+
readback and signed-token bridges do not promise managed frequency caps, legacy
|
|
752
|
+
tester-source parity, a send-time fence or a full native network sender. The
|
|
753
|
+
opt-in browser profile adds no npm entry or UI package export.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sealed transport boundary for handing an accounting document to its recipient.
|
|
3
|
+
*
|
|
4
|
+
* The kernel exercises the whole capability up to this line: a document is owed, registered with
|
|
5
|
+
* whatever authority the market has, queued, claimed and settled against a receipt. What crosses
|
|
6
|
+
* the line is one opaque hand-off, and this adapter is the deliberately inert implementation of
|
|
7
|
+
* it -- deterministic, and leaving the installation by no route at all.
|
|
8
|
+
*
|
|
9
|
+
* It is FAIL CLOSED, and that is the whole design. An installation that has declared no delivery
|
|
10
|
+
* channel gets a refusal, never a silent success: a boundary whose default answer is "fine" is
|
|
11
|
+
* how a deployment discovers months later that nothing was ever handed to anyone.
|
|
12
|
+
*/
|
|
13
|
+
export type CapturedDocumentDeliveryCommand = {
|
|
14
|
+
readonly deliveryId: string;
|
|
15
|
+
readonly recipientReference: string;
|
|
16
|
+
};
|
|
17
|
+
export type CapturedDocumentDeliveryPort = {
|
|
18
|
+
deliver(command: CapturedDocumentDeliveryCommand): Promise<{
|
|
19
|
+
readonly receiptReference: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
export type CapturedDocumentDeliveryResolution = {
|
|
23
|
+
readonly port: CapturedDocumentDeliveryPort;
|
|
24
|
+
readonly refused?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
readonly port?: undefined;
|
|
27
|
+
readonly refused: string;
|
|
28
|
+
};
|
|
29
|
+
/** The one marker that opens the boundary. Anything else, including its absence, is a refusal. */
|
|
30
|
+
export declare const CAPTURED_DOCUMENT_DELIVERY_CHANNEL = "captured";
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the boundary for one installation. The environment is the only input, and every path
|
|
33
|
+
* that is not an explicit declaration of the captured channel ends in a named refusal.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveCapturedDocumentDelivery(env: Record<string, string | undefined>): CapturedDocumentDeliveryResolution;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** The one marker that opens the boundary. Anything else, including its absence, is a refusal. */
|
|
3
|
+
export const CAPTURED_DOCUMENT_DELIVERY_CHANNEL = "captured";
|
|
4
|
+
const CHANNEL_KEY = "PLATFORM_DOCUMENT_DELIVERY_CHANNEL";
|
|
5
|
+
const reference = (command) => `captured:${createHash("sha256")
|
|
6
|
+
.update(`${command.deliveryId}::${command.recipientReference}`)
|
|
7
|
+
.digest("hex")
|
|
8
|
+
.slice(0, 32)}`;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the boundary for one installation. The environment is the only input, and every path
|
|
11
|
+
* that is not an explicit declaration of the captured channel ends in a named refusal.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveCapturedDocumentDelivery(env) {
|
|
14
|
+
const declared = env[CHANNEL_KEY]?.trim().toLowerCase() ?? "";
|
|
15
|
+
if (declared === "")
|
|
16
|
+
return { refused: "document_delivery_channel_undeclared" };
|
|
17
|
+
if (declared !== CAPTURED_DOCUMENT_DELIVERY_CHANNEL) {
|
|
18
|
+
return { refused: "document_delivery_channel_unsupported" };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
port: {
|
|
22
|
+
async deliver(command) {
|
|
23
|
+
if (typeof command.deliveryId !== "string" || command.deliveryId.trim() === "") {
|
|
24
|
+
throw new Error("document_delivery_command_invalid");
|
|
25
|
+
}
|
|
26
|
+
if (typeof command.recipientReference !== "string" || command.recipientReference.trim() === "") {
|
|
27
|
+
throw new Error("document_delivery_recipient_missing");
|
|
28
|
+
}
|
|
29
|
+
return { receiptReference: reference(command) };
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Typed refusal used by public/default composition when product copy is absent. */
|
|
2
|
+
export class AuthEmailContentUnavailableError extends Error {
|
|
3
|
+
code = "auth_email_content_unavailable";
|
|
4
|
+
constructor() {
|
|
5
|
+
super("Auth email content unavailable");
|
|
6
|
+
this.name = "AuthEmailContentUnavailableError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AuthEmailContentUnavailableError } from "./authEmailError.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Auth Send Email hook. Live, not a candidate.
|
|
3
|
+
*
|
|
4
|
+
* Supabase Auth targets `/api/auth-send-email` in staging and production - the
|
|
5
|
+
* hooks were repointed here on 2026-09-04 and the hosted Edge Functions were
|
|
6
|
+
* undeployed the same day, so this owns the raw-stream, signature, render/send
|
|
7
|
+
* and ledger contract for every magic link, recovery and confirmation the
|
|
8
|
+
* product sends. Rotating its signing secret is a human-only control-plane act.
|
|
9
|
+
*/
|
|
10
|
+
import type { HttpRequest as VercelRequest, HttpResponse as VercelResponse } from "../http/index.js";
|
|
11
|
+
import type { EmailBrand, EmailRenderer } from "./contracts/email.js";
|
|
12
|
+
import { type AuthEmailContentPort, type AuthEmailPersistencePort, type AuthEmailTransportPort } from "./authEmailPorts.js";
|
|
13
|
+
export interface AuthSendEmailHookDeps {
|
|
14
|
+
transport: AuthEmailTransportPort;
|
|
15
|
+
persistence: AuthEmailPersistencePort;
|
|
16
|
+
content: AuthEmailContentPort;
|
|
17
|
+
fromEmail: string;
|
|
18
|
+
hookSecret: string;
|
|
19
|
+
authServiceUrl: string;
|
|
20
|
+
/** App-layer defaults injected at composition; no brand/env ownership lives here. */
|
|
21
|
+
defaultOrigin: string;
|
|
22
|
+
productionEmailHosts: string[];
|
|
23
|
+
legacyBaseUrl?: string | null;
|
|
24
|
+
emailBrandForOrigin: (origin: string) => EmailBrand;
|
|
25
|
+
defaultSandboxRecipient: string;
|
|
26
|
+
defaultRedirectTo?: string;
|
|
27
|
+
env: Record<string, string | undefined>;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
}
|
|
30
|
+
export interface AuthEmailHookHost {
|
|
31
|
+
renderEmail: EmailRenderer;
|
|
32
|
+
readObservedEnvironment: (env: Record<string, string | undefined>) => string;
|
|
33
|
+
readHiddenPreviewEnabled: (env: Record<string, string | undefined>) => boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function createAuthSendEmailHookCandidate(deps: AuthSendEmailHookDeps, host: AuthEmailHookHost): (req: VercelRequest, res: VercelResponse) => Promise<void>;
|