@openlup/platform 0.15.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.
Files changed (531) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +633 -6
  3. package/dist/communications/accountingDocumentDelivery.d.ts +35 -0
  4. package/dist/communications/accountingDocumentDelivery.js +33 -0
  5. package/dist/communications/authEmailError.d.ts +5 -0
  6. package/dist/communications/authEmailError.js +8 -0
  7. package/dist/communications/authEmailPorts.d.ts +2 -0
  8. package/dist/communications/authEmailPorts.js +1 -0
  9. package/dist/communications/authSendEmailHook.d.ts +35 -0
  10. package/dist/communications/authSendEmailHook.js +250 -0
  11. package/dist/communications/capturedTransactionalDelivery.d.ts +13 -0
  12. package/dist/communications/capturedTransactionalDelivery.js +14 -0
  13. package/dist/communications/communicationSync.d.ts +11 -0
  14. package/dist/communications/communicationSync.js +79 -0
  15. package/dist/communications/communicationSyncWorker.d.ts +68 -0
  16. package/dist/communications/communicationSyncWorker.js +218 -0
  17. package/dist/communications/consentPolicy.d.ts +19 -0
  18. package/dist/communications/consentPolicy.js +43 -0
  19. package/dist/communications/consentPurposeRegistry.d.ts +4 -0
  20. package/dist/communications/consentPurposeRegistry.js +24 -0
  21. package/dist/communications/contracts/abandonedCart.d.ts +27 -0
  22. package/dist/communications/contracts/abandonedCart.js +25 -0
  23. package/dist/communications/contracts/authEmail.d.ts +62 -0
  24. package/dist/communications/contracts/authEmail.js +1 -0
  25. package/dist/communications/contracts/backInStock.d.ts +28 -0
  26. package/dist/communications/contracts/backInStock.js +28 -0
  27. package/dist/communications/contracts/blocks.d.ts +24 -0
  28. package/dist/communications/contracts/blocks.js +23 -0
  29. package/dist/communications/contracts/checkoutExpired.d.ts +22 -0
  30. package/dist/communications/contracts/checkoutExpired.js +25 -0
  31. package/dist/communications/contracts/checkoutRecovery.d.ts +26 -0
  32. package/dist/communications/contracts/checkoutRecovery.js +37 -0
  33. package/dist/communications/contracts/commerceEmailContent.d.ts +176 -0
  34. package/dist/communications/contracts/commerceEmailContent.js +1 -0
  35. package/dist/communications/contracts/commerceEngagementEmailContent.d.ts +95 -0
  36. package/dist/communications/contracts/commerceEngagementEmailContent.js +1 -0
  37. package/dist/communications/contracts/consent.d.ts +12 -0
  38. package/dist/communications/contracts/consent.js +1 -0
  39. package/dist/communications/contracts/email.d.ts +182 -0
  40. package/dist/communications/contracts/email.js +1 -0
  41. package/dist/communications/contracts/guideCard.d.ts +3 -0
  42. package/dist/communications/contracts/guideCard.js +26 -0
  43. package/dist/communications/contracts/index.d.ts +51 -0
  44. package/dist/communications/contracts/index.js +42 -0
  45. package/dist/communications/contracts/inquiryContent.d.ts +32 -0
  46. package/dist/communications/contracts/inquiryContent.js +33 -0
  47. package/dist/communications/contracts/invoiceDocumentContent.d.ts +26 -0
  48. package/dist/communications/contracts/invoiceDocumentContent.js +36 -0
  49. package/dist/communications/contracts/marketingAutomation.d.ts +52 -0
  50. package/dist/communications/contracts/marketingAutomation.js +1 -0
  51. package/dist/communications/contracts/newsletter.d.ts +63 -0
  52. package/dist/communications/contracts/newsletter.js +1 -0
  53. package/dist/communications/contracts/newsletterWebhook.d.ts +26 -0
  54. package/dist/communications/contracts/newsletterWebhook.js +1 -0
  55. package/dist/communications/contracts/optOutContent.d.ts +11 -0
  56. package/dist/communications/contracts/optOutContent.js +17 -0
  57. package/dist/communications/contracts/orderCanceled.d.ts +25 -0
  58. package/dist/communications/contracts/orderCanceled.js +27 -0
  59. package/dist/communications/contracts/orderDraft.d.ts +46 -0
  60. package/dist/communications/contracts/orderDraft.js +46 -0
  61. package/dist/communications/contracts/orderPaid.d.ts +53 -0
  62. package/dist/communications/contracts/orderPaid.js +71 -0
  63. package/dist/communications/contracts/orderRefunded.d.ts +24 -0
  64. package/dist/communications/contracts/orderRefunded.js +27 -0
  65. package/dist/communications/contracts/paymentFailed.d.ts +24 -0
  66. package/dist/communications/contracts/paymentFailed.js +24 -0
  67. package/dist/communications/contracts/publicIntake.d.ts +49 -0
  68. package/dist/communications/contracts/publicIntake.js +1 -0
  69. package/dist/communications/contracts/render.d.ts +2 -0
  70. package/dist/communications/contracts/render.js +229 -0
  71. package/dist/communications/contracts/reorderReminder.d.ts +24 -0
  72. package/dist/communications/contracts/reorderReminder.js +24 -0
  73. package/dist/communications/contracts/returnEmails.d.ts +25 -0
  74. package/dist/communications/contracts/returnEmails.js +62 -0
  75. package/dist/communications/contracts/reviewEffects.d.ts +26 -0
  76. package/dist/communications/contracts/reviewEffects.js +25 -0
  77. package/dist/communications/contracts/reviewRequest.d.ts +26 -0
  78. package/dist/communications/contracts/reviewRequest.js +24 -0
  79. package/dist/communications/contracts/roleNotificationContent.d.ts +25 -0
  80. package/dist/communications/contracts/roleNotificationContent.js +46 -0
  81. package/dist/communications/contracts/shipmentDelivered.d.ts +23 -0
  82. package/dist/communications/contracts/shipmentDelivered.js +24 -0
  83. package/dist/communications/contracts/shipmentDispatched.d.ts +27 -0
  84. package/dist/communications/contracts/shipmentDispatched.js +35 -0
  85. package/dist/communications/contracts/shipmentException.d.ts +21 -0
  86. package/dist/communications/contracts/shipmentException.js +26 -0
  87. package/dist/communications/contracts/subscriptionActivationActionRequired.d.ts +17 -0
  88. package/dist/communications/contracts/subscriptionActivationActionRequired.js +22 -0
  89. package/dist/communications/contracts/subscriptionAddressChanged.d.ts +19 -0
  90. package/dist/communications/contracts/subscriptionAddressChanged.js +25 -0
  91. package/dist/communications/contracts/subscriptionCancelled.d.ts +19 -0
  92. package/dist/communications/contracts/subscriptionCancelled.js +25 -0
  93. package/dist/communications/contracts/subscriptionCycleSkipped.d.ts +25 -0
  94. package/dist/communications/contracts/subscriptionCycleSkipped.js +40 -0
  95. package/dist/communications/contracts/subscriptionDeliveryRescheduled.d.ts +25 -0
  96. package/dist/communications/contracts/subscriptionDeliveryRescheduled.js +39 -0
  97. package/dist/communications/contracts/subscriptionEmailContent.d.ts +145 -0
  98. package/dist/communications/contracts/subscriptionEmailContent.js +1 -0
  99. package/dist/communications/contracts/subscriptionPackageChanged.d.ts +20 -0
  100. package/dist/communications/contracts/subscriptionPackageChanged.js +26 -0
  101. package/dist/communications/contracts/subscriptionPauseReminder.d.ts +23 -0
  102. package/dist/communications/contracts/subscriptionPauseReminder.js +29 -0
  103. package/dist/communications/contracts/subscriptionPaused.d.ts +21 -0
  104. package/dist/communications/contracts/subscriptionPaused.js +25 -0
  105. package/dist/communications/contracts/subscriptionPaymentExpired.d.ts +34 -0
  106. package/dist/communications/contracts/subscriptionPaymentExpired.js +37 -0
  107. package/dist/communications/contracts/subscriptionPaymentFailed.d.ts +49 -0
  108. package/dist/communications/contracts/subscriptionPaymentFailed.js +56 -0
  109. package/dist/communications/contracts/subscriptionPaymentRecovered.d.ts +19 -0
  110. package/dist/communications/contracts/subscriptionPaymentRecovered.js +22 -0
  111. package/dist/communications/contracts/subscriptionRenewalAtRisk.d.ts +36 -0
  112. package/dist/communications/contracts/subscriptionRenewalAtRisk.js +36 -0
  113. package/dist/communications/contracts/subscriptionRenewalUpcoming.d.ts +49 -0
  114. package/dist/communications/contracts/subscriptionRenewalUpcoming.js +43 -0
  115. package/dist/communications/contracts/subscriptionResumed.d.ts +23 -0
  116. package/dist/communications/contracts/subscriptionResumed.js +25 -0
  117. package/dist/communications/contracts/subscriptionWelcome.d.ts +44 -0
  118. package/dist/communications/contracts/subscriptionWelcome.js +45 -0
  119. package/dist/communications/contracts/subscriptionWinback.d.ts +21 -0
  120. package/dist/communications/contracts/subscriptionWinback.js +28 -0
  121. package/dist/communications/contracts/transactionalDelivery.d.ts +42 -0
  122. package/dist/communications/contracts/transactionalDelivery.js +1 -0
  123. package/dist/communications/contracts/types.d.ts +46 -0
  124. package/dist/communications/contracts/types.js +1 -0
  125. package/dist/communications/contribution.d.ts +10 -0
  126. package/dist/communications/contribution.js +24 -0
  127. package/dist/communications/deliveryReconciliation.d.ts +64 -0
  128. package/dist/communications/deliveryReconciliation.js +60 -0
  129. package/dist/communications/emailEgress.d.ts +38 -0
  130. package/dist/communications/emailEgress.js +100 -0
  131. package/dist/communications/emailHealthAssessment.d.ts +39 -0
  132. package/dist/communications/emailHealthAssessment.js +59 -0
  133. package/dist/communications/emailHealthMetricsPort.d.ts +17 -0
  134. package/dist/communications/emailHealthMetricsPort.js +1 -0
  135. package/dist/communications/emailNotificationControl.d.ts +27 -0
  136. package/dist/communications/emailNotificationControl.js +10 -0
  137. package/dist/communications/emailObservation.d.ts +28 -0
  138. package/dist/communications/emailObservation.js +23 -0
  139. package/dist/communications/emailTransport.d.ts +82 -0
  140. package/dist/communications/emailTransport.js +95 -0
  141. package/dist/communications/errors.d.ts +15 -0
  142. package/dist/communications/errors.js +30 -0
  143. package/dist/communications/index.d.ts +46 -0
  144. package/dist/communications/index.js +38 -0
  145. package/dist/communications/integrationEventSignature.d.ts +15 -0
  146. package/dist/communications/integrationEventSignature.js +37 -0
  147. package/dist/communications/managedTransactionalDeliveryStore.d.ts +12 -0
  148. package/dist/communications/managedTransactionalDeliveryStore.js +49 -0
  149. package/dist/communications/nativeOperations.d.ts +79 -0
  150. package/dist/communications/nativeOperations.js +3 -0
  151. package/dist/communications/newsletterIntegrationContracts.d.ts +130 -0
  152. package/dist/communications/newsletterIntegrationContracts.js +128 -0
  153. package/dist/communications/newsletterWebhookPort.d.ts +11 -0
  154. package/dist/communications/newsletterWebhookPort.js +84 -0
  155. package/dist/communications/newsletterWebhookProcessing.d.ts +17 -0
  156. package/dist/communications/newsletterWebhookProcessing.js +71 -0
  157. package/dist/communications/originPolicy.d.ts +40 -0
  158. package/dist/communications/originPolicy.js +100 -0
  159. package/dist/communications/postgresCommunicationSync.d.ts +79 -0
  160. package/dist/communications/postgresCommunicationSync.js +111 -0
  161. package/dist/communications/postgresConsentEvaluator.d.ts +19 -0
  162. package/dist/communications/postgresConsentEvaluator.js +43 -0
  163. package/dist/communications/postgresDeliveryReconciliation.d.ts +3 -0
  164. package/dist/communications/postgresDeliveryReconciliation.js +113 -0
  165. package/dist/communications/postgresNativeOperations.d.ts +13 -0
  166. package/dist/communications/postgresNativeOperations.js +63 -0
  167. package/dist/communications/postgresNotificationRecipients.d.ts +37 -0
  168. package/dist/communications/postgresNotificationRecipients.js +60 -0
  169. package/dist/communications/postgresTransactionalDeliveryStore.d.ts +7 -0
  170. package/dist/communications/postgresTransactionalDeliveryStore.js +55 -0
  171. package/dist/communications/preferencesToken.d.ts +10 -0
  172. package/dist/communications/preferencesToken.js +40 -0
  173. package/dist/communications/publicPreferenceToken.d.ts +24 -0
  174. package/dist/communications/publicPreferenceToken.js +53 -0
  175. package/dist/communications/shipmentNotifications.d.ts +34 -0
  176. package/dist/communications/shipmentNotifications.js +61 -0
  177. package/dist/communications/sql.d.ts +26 -0
  178. package/dist/communications/sql.js +7 -0
  179. package/dist/communications/standardWebhooks.d.ts +14 -0
  180. package/dist/communications/standardWebhooks.js +73 -0
  181. package/dist/communications/status.d.ts +11 -0
  182. package/dist/communications/status.js +36 -0
  183. package/dist/communications/transactionalDelivery.d.ts +19 -0
  184. package/dist/communications/transactionalDelivery.js +96 -0
  185. package/dist/communications/transactionalDeliveryIdentifier.d.ts +3 -0
  186. package/dist/communications/transactionalDeliveryIdentifier.js +6 -0
  187. package/dist/communications/unsubscribeToken.d.ts +77 -0
  188. package/dist/communications/unsubscribeToken.js +150 -0
  189. package/dist/communications/validation.d.ts +2 -0
  190. package/dist/communications/validation.js +3 -0
  191. package/dist/http/index.d.ts +1 -0
  192. package/dist/http/index.js +1 -0
  193. package/dist/http/webhookSignature.d.ts +42 -0
  194. package/dist/http/webhookSignature.js +86 -0
  195. package/dist/identity/adminAuthBinding.d.ts +28 -0
  196. package/dist/identity/adminAuthBinding.js +66 -0
  197. package/dist/identity/adminAuthorization.d.ts +34 -0
  198. package/dist/identity/adminAuthorization.js +72 -0
  199. package/dist/identity/adminContracts.d.ts +70 -0
  200. package/dist/identity/adminContracts.js +43 -0
  201. package/dist/identity/adminMagicLinkHandler.d.ts +39 -0
  202. package/dist/identity/adminMagicLinkHandler.js +94 -0
  203. package/dist/identity/adminMeHandler.d.ts +15 -0
  204. package/dist/identity/adminMeHandler.js +49 -0
  205. package/dist/identity/adminPreflight.d.ts +16 -0
  206. package/dist/identity/adminPreflight.js +38 -0
  207. package/dist/identity/adminUserActionPorts.d.ts +31 -0
  208. package/dist/identity/adminUserActionPorts.js +51 -0
  209. package/dist/identity/adminUserHandlers.d.ts +38 -0
  210. package/dist/identity/adminUserHandlers.js +140 -0
  211. package/dist/identity/authVerifyUrl.d.ts +6 -0
  212. package/dist/identity/authVerifyUrl.js +54 -0
  213. package/dist/identity/contracts/contracts.d.ts +8 -0
  214. package/dist/identity/contracts/contracts.js +2 -0
  215. package/dist/identity/contracts/emailTrust.d.ts +3 -0
  216. package/dist/identity/contracts/emailTrust.js +4 -0
  217. package/dist/identity/contracts/index.d.ts +8 -0
  218. package/dist/identity/contracts/index.js +8 -0
  219. package/dist/identity/contracts/oidc.d.ts +3 -0
  220. package/dist/identity/contracts/oidc.js +9 -0
  221. package/dist/identity/contracts/operatorAuth.d.ts +35 -0
  222. package/dist/identity/contracts/operatorAuth.js +53 -0
  223. package/dist/identity/contracts/operatorInvitations.d.ts +37 -0
  224. package/dist/identity/contracts/operatorInvitations.js +1 -0
  225. package/dist/identity/contracts/ports.d.ts +22 -0
  226. package/dist/identity/contracts/ports.js +1 -0
  227. package/dist/identity/contracts/privacy.d.ts +62 -0
  228. package/dist/identity/contracts/privacy.js +99 -0
  229. package/dist/identity/contracts/providerList.d.ts +3 -0
  230. package/dist/identity/contracts/providerList.js +11 -0
  231. package/dist/identity/contracts/types.d.ts +16 -0
  232. package/dist/identity/contracts/types.js +4 -0
  233. package/dist/identity/contribution.d.ts +8 -0
  234. package/dist/identity/contribution.js +22 -0
  235. package/dist/identity/customerAuth.d.ts +8 -0
  236. package/dist/identity/customerAuth.js +1 -0
  237. package/dist/identity/customerAuthorization.d.ts +5 -0
  238. package/dist/identity/customerAuthorization.js +22 -0
  239. package/dist/identity/customerContracts.d.ts +42 -0
  240. package/dist/identity/customerContracts.js +43 -0
  241. package/dist/identity/customerIdentityBinding.d.ts +44 -0
  242. package/dist/identity/customerIdentityBinding.js +60 -0
  243. package/dist/identity/customerIdentityVerifier.d.ts +8 -0
  244. package/dist/identity/customerIdentityVerifier.js +101 -0
  245. package/dist/identity/customerMagicLinkHandler.d.ts +38 -0
  246. package/dist/identity/customerMagicLinkHandler.js +115 -0
  247. package/dist/identity/customerMeHandler.d.ts +11 -0
  248. package/dist/identity/customerMeHandler.js +46 -0
  249. package/dist/identity/customerPorts.d.ts +4 -0
  250. package/dist/identity/customerPorts.js +1 -0
  251. package/dist/identity/customerSessionBinding.d.ts +38 -0
  252. package/dist/identity/customerSessionBinding.js +80 -0
  253. package/dist/identity/customerSessionIssuer.d.ts +10 -0
  254. package/dist/identity/customerSessionIssuer.js +57 -0
  255. package/dist/identity/customerVerifyOtpHandler.d.ts +8 -0
  256. package/dist/identity/customerVerifyOtpHandler.js +41 -0
  257. package/dist/identity/directOperatorInvitationStore.d.ts +19 -0
  258. package/dist/identity/directOperatorInvitationStore.js +193 -0
  259. package/dist/identity/emailTrustPolicy.d.ts +14 -0
  260. package/dist/identity/emailTrustPolicy.js +16 -0
  261. package/dist/identity/identityPersonalDataContributor.d.ts +7 -0
  262. package/dist/identity/identityPersonalDataContributor.js +46 -0
  263. package/dist/identity/identityReadiness.d.ts +10 -0
  264. package/dist/identity/identityReadiness.js +25 -0
  265. package/dist/identity/index.d.ts +67 -0
  266. package/dist/identity/index.js +66 -0
  267. package/dist/identity/inviteAdminUserUseCase.d.ts +89 -0
  268. package/dist/identity/inviteAdminUserUseCase.js +75 -0
  269. package/dist/identity/jwtLibrary.d.ts +54 -0
  270. package/dist/identity/jwtLibrary.js +1 -0
  271. package/dist/identity/machineActorWriteFence.d.ts +4 -0
  272. package/dist/identity/machineActorWriteFence.js +13 -0
  273. package/dist/identity/magicLinkPorts.d.ts +28 -0
  274. package/dist/identity/magicLinkPorts.js +1 -0
  275. package/dist/identity/managedAccountLinkStore.d.ts +2 -0
  276. package/dist/identity/managedAccountLinkStore.js +93 -0
  277. package/dist/identity/managedAdminAuthVerifier.d.ts +7 -0
  278. package/dist/identity/managedAdminAuthVerifier.js +27 -0
  279. package/dist/identity/managedAdminUserGateways.d.ts +123 -0
  280. package/dist/identity/managedAdminUserGateways.js +127 -0
  281. package/dist/identity/managedClient.d.ts +90 -0
  282. package/dist/identity/managedClient.js +10 -0
  283. package/dist/identity/managedClientAuthLink.d.ts +3 -0
  284. package/dist/identity/managedClientAuthLink.js +115 -0
  285. package/dist/identity/managedCustomerMe.d.ts +13 -0
  286. package/dist/identity/managedCustomerMe.js +30 -0
  287. package/dist/identity/managedEmailTrustPolicy.d.ts +11 -0
  288. package/dist/identity/managedEmailTrustPolicy.js +105 -0
  289. package/dist/identity/managedIdentityVerifier.d.ts +2 -0
  290. package/dist/identity/managedIdentityVerifier.js +16 -0
  291. package/dist/identity/managedPrivacy.d.ts +4 -0
  292. package/dist/identity/managedPrivacy.js +39 -0
  293. package/dist/identity/messages.d.ts +29 -0
  294. package/dist/identity/messages.js +39 -0
  295. package/dist/identity/oidcIdentityVerifier.d.ts +45 -0
  296. package/dist/identity/oidcIdentityVerifier.js +309 -0
  297. package/dist/identity/oidcPrincipal.d.ts +2 -0
  298. package/dist/identity/oidcPrincipal.js +10 -0
  299. package/dist/identity/operatorAdminAuth.d.ts +6 -0
  300. package/dist/identity/operatorAdminAuth.js +13 -0
  301. package/dist/identity/operatorAuthHandlers.d.ts +18 -0
  302. package/dist/identity/operatorAuthHandlers.js +71 -0
  303. package/dist/identity/operatorIdentityVerifier.d.ts +8 -0
  304. package/dist/identity/operatorIdentityVerifier.js +19 -0
  305. package/dist/identity/operatorInvitationLifecycle.d.ts +7 -0
  306. package/dist/identity/operatorInvitationLifecycle.js +15 -0
  307. package/dist/identity/operatorInvitationPorts.d.ts +31 -0
  308. package/dist/identity/operatorInvitationPorts.js +1 -0
  309. package/dist/identity/operatorPorts.d.ts +37 -0
  310. package/dist/identity/operatorPorts.js +1 -0
  311. package/dist/identity/operatorSession.d.ts +13 -0
  312. package/dist/identity/operatorSession.js +31 -0
  313. package/dist/identity/operatorTokenAdminAuth.d.ts +15 -0
  314. package/dist/identity/operatorTokenAdminAuth.js +50 -0
  315. package/dist/identity/personalDataRegistry.d.ts +4 -0
  316. package/dist/identity/personalDataRegistry.js +11 -0
  317. package/dist/identity/platformAdminAuth.d.ts +15 -0
  318. package/dist/identity/platformAdminAuth.js +1 -0
  319. package/dist/identity/ports.d.ts +127 -0
  320. package/dist/identity/ports.js +38 -0
  321. package/dist/identity/postgresAccountLinkStore.d.ts +7 -0
  322. package/dist/identity/postgresAccountLinkStore.js +52 -0
  323. package/dist/identity/postgresCustomerMe.d.ts +3 -0
  324. package/dist/identity/postgresCustomerMe.js +21 -0
  325. package/dist/identity/postgresCustomerRecovery.d.ts +11 -0
  326. package/dist/identity/postgresCustomerRecovery.js +57 -0
  327. package/dist/identity/postgresOperatorIdentity.d.ts +5 -0
  328. package/dist/identity/postgresOperatorIdentity.js +137 -0
  329. package/dist/identity/postgresPrivacy.d.ts +7 -0
  330. package/dist/identity/postgresPrivacy.js +126 -0
  331. package/dist/identity/privacyHandlers.d.ts +10 -0
  332. package/dist/identity/privacyHandlers.js +35 -0
  333. package/dist/identity/privacyPorts.d.ts +72 -0
  334. package/dist/identity/privacyPorts.js +8 -0
  335. package/dist/identity/privacyUseCases.d.ts +5 -0
  336. package/dist/identity/privacyUseCases.js +55 -0
  337. package/dist/identity/reconcileAccountForPrincipal.d.ts +20 -0
  338. package/dist/identity/reconcileAccountForPrincipal.js +66 -0
  339. package/dist/identity/reconcileAccountHandler.d.ts +11 -0
  340. package/dist/identity/reconcileAccountHandler.js +30 -0
  341. package/dist/identity/removeAdminUserUseCase.d.ts +31 -0
  342. package/dist/identity/removeAdminUserUseCase.js +60 -0
  343. package/dist/identity/response.d.ts +3 -0
  344. package/dist/identity/response.js +2 -0
  345. package/dist/identity/sql.d.ts +44 -0
  346. package/dist/identity/sql.js +10 -0
  347. package/package.json +22 -2
  348. package/release-gates.json +63 -8
  349. package/sql/20260807190000_comms_outbox_rail.sql +329 -0
  350. package/sql/20260810120001_transactional_delivery_receipts.sql +209 -0
  351. package/sql/20260810180001_self_host_actor_auth.sql +40 -0
  352. package/sql/20260810204057_customer_identity_read.sql +31 -0
  353. package/sql/20260813120000_communications_control_plane.sql +568 -0
  354. package/sql/20260814090000_customer_selfservice_recovery.sql +477 -0
  355. package/sql/20260901143000_admin_membership_authority_foundation.sql +234 -0
  356. package/sql/20261018120000_identity_operator_invitations.sql +42 -0
  357. package/sql/20261018180000_identity_operator_challenges.sql +56 -0
  358. package/sql/20261018190000_identity_privacy_erasures.sql +15 -0
  359. package/sql/20261019200000_communications_native_operations.sql +68 -0
  360. package/src/communications/accountingDocumentDelivery.ts +63 -0
  361. package/src/communications/authEmailError.ts +10 -0
  362. package/src/communications/authEmailPorts.ts +2 -0
  363. package/src/communications/authSendEmailHook.ts +310 -0
  364. package/src/communications/capturedTransactionalDelivery.ts +29 -0
  365. package/src/communications/communicationSync.ts +96 -0
  366. package/src/communications/communicationSyncWorker.ts +302 -0
  367. package/src/communications/consentPolicy.ts +82 -0
  368. package/src/communications/consentPurposeRegistry.ts +31 -0
  369. package/src/communications/contracts/abandonedCart.ts +64 -0
  370. package/src/communications/contracts/authEmail.ts +73 -0
  371. package/src/communications/contracts/backInStock.ts +69 -0
  372. package/src/communications/contracts/blocks.ts +47 -0
  373. package/src/communications/contracts/checkoutExpired.ts +62 -0
  374. package/src/communications/contracts/checkoutRecovery.ts +68 -0
  375. package/src/communications/contracts/commerceEmailContent.ts +189 -0
  376. package/src/communications/contracts/commerceEngagementEmailContent.ts +106 -0
  377. package/src/communications/contracts/consent.ts +13 -0
  378. package/src/communications/contracts/email.ts +210 -0
  379. package/src/communications/contracts/guideCard.ts +34 -0
  380. package/src/communications/contracts/index.ts +51 -0
  381. package/src/communications/contracts/inquiryContent.ts +53 -0
  382. package/src/communications/contracts/invoiceDocumentContent.ts +57 -0
  383. package/src/communications/contracts/marketingAutomation.ts +45 -0
  384. package/src/communications/contracts/newsletter.ts +78 -0
  385. package/src/communications/contracts/newsletterWebhook.ts +23 -0
  386. package/src/communications/contracts/optOutContent.ts +23 -0
  387. package/src/communications/contracts/orderCanceled.ts +64 -0
  388. package/src/communications/contracts/orderDraft.ts +112 -0
  389. package/src/communications/contracts/orderPaid.ts +147 -0
  390. package/src/communications/contracts/orderRefunded.ts +63 -0
  391. package/src/communications/contracts/paymentFailed.ts +59 -0
  392. package/src/communications/contracts/publicIntake.ts +53 -0
  393. package/src/communications/contracts/render.ts +271 -0
  394. package/src/communications/contracts/reorderReminder.ts +59 -0
  395. package/src/communications/contracts/returnEmails.ts +113 -0
  396. package/src/communications/contracts/reviewEffects.ts +60 -0
  397. package/src/communications/contracts/reviewRequest.ts +59 -0
  398. package/src/communications/contracts/roleNotificationContent.ts +65 -0
  399. package/src/communications/contracts/shipmentDelivered.ts +59 -0
  400. package/src/communications/contracts/shipmentDispatched.ts +77 -0
  401. package/src/communications/contracts/shipmentException.ts +62 -0
  402. package/src/communications/contracts/subscriptionActivationActionRequired.ts +37 -0
  403. package/src/communications/contracts/subscriptionAddressChanged.ts +56 -0
  404. package/src/communications/contracts/subscriptionCancelled.ts +57 -0
  405. package/src/communications/contracts/subscriptionCycleSkipped.ts +80 -0
  406. package/src/communications/contracts/subscriptionDeliveryRescheduled.ts +79 -0
  407. package/src/communications/contracts/subscriptionEmailContent.ts +163 -0
  408. package/src/communications/contracts/subscriptionPackageChanged.ts +59 -0
  409. package/src/communications/contracts/subscriptionPauseReminder.ts +63 -0
  410. package/src/communications/contracts/subscriptionPaused.ts +58 -0
  411. package/src/communications/contracts/subscriptionPaymentExpired.ts +83 -0
  412. package/src/communications/contracts/subscriptionPaymentFailed.ts +117 -0
  413. package/src/communications/contracts/subscriptionPaymentRecovered.ts +50 -0
  414. package/src/communications/contracts/subscriptionRenewalAtRisk.ts +85 -0
  415. package/src/communications/contracts/subscriptionRenewalUpcoming.ts +103 -0
  416. package/src/communications/contracts/subscriptionResumed.ts +60 -0
  417. package/src/communications/contracts/subscriptionWelcome.ts +102 -0
  418. package/src/communications/contracts/subscriptionWinback.ts +62 -0
  419. package/src/communications/contracts/transactionalDelivery.ts +43 -0
  420. package/src/communications/contracts/types.ts +58 -0
  421. package/src/communications/contribution.ts +33 -0
  422. package/src/communications/deliveryReconciliation.ts +108 -0
  423. package/src/communications/emailEgress.ts +111 -0
  424. package/src/communications/emailHealthAssessment.ts +106 -0
  425. package/src/communications/emailHealthMetricsPort.ts +17 -0
  426. package/src/communications/emailNotificationControl.ts +28 -0
  427. package/src/communications/emailObservation.ts +43 -0
  428. package/src/communications/emailTransport.ts +167 -0
  429. package/src/communications/errors.ts +34 -0
  430. package/src/communications/index.ts +46 -0
  431. package/src/communications/integrationEventSignature.ts +49 -0
  432. package/src/communications/managedTransactionalDeliveryStore.ts +59 -0
  433. package/src/communications/nativeOperations.ts +40 -0
  434. package/src/communications/newsletterIntegrationContracts.ts +154 -0
  435. package/src/communications/newsletterWebhookPort.ts +104 -0
  436. package/src/communications/newsletterWebhookProcessing.ts +102 -0
  437. package/src/communications/originPolicy.ts +151 -0
  438. package/src/communications/postgresCommunicationSync.ts +127 -0
  439. package/src/communications/postgresConsentEvaluator.ts +49 -0
  440. package/src/communications/postgresDeliveryReconciliation.ts +101 -0
  441. package/src/communications/postgresNativeOperations.ts +55 -0
  442. package/src/communications/postgresNotificationRecipients.ts +57 -0
  443. package/src/communications/postgresTransactionalDeliveryStore.ts +79 -0
  444. package/src/communications/preferencesToken.ts +62 -0
  445. package/src/communications/publicPreferenceToken.ts +68 -0
  446. package/src/communications/shipmentNotifications.ts +78 -0
  447. package/src/communications/sql.ts +7 -0
  448. package/src/communications/standardWebhooks.ts +84 -0
  449. package/src/communications/status.ts +51 -0
  450. package/src/communications/transactionalDelivery.ts +114 -0
  451. package/src/communications/transactionalDeliveryIdentifier.ts +9 -0
  452. package/src/communications/unsubscribeToken.ts +186 -0
  453. package/src/communications/validation.ts +3 -0
  454. package/src/http/index.ts +1 -0
  455. package/src/http/webhookSignature.ts +96 -0
  456. package/src/identity/adminAuthBinding.ts +76 -0
  457. package/src/identity/adminAuthorization.ts +106 -0
  458. package/src/identity/adminContracts.ts +52 -0
  459. package/src/identity/adminMagicLinkHandler.ts +132 -0
  460. package/src/identity/adminMeHandler.ts +64 -0
  461. package/src/identity/adminPreflight.ts +46 -0
  462. package/src/identity/adminUserActionPorts.ts +78 -0
  463. package/src/identity/adminUserHandlers.ts +174 -0
  464. package/src/identity/authVerifyUrl.ts +56 -0
  465. package/src/identity/contracts/contracts.ts +15 -0
  466. package/src/identity/contracts/emailTrust.ts +5 -0
  467. package/src/identity/contracts/index.ts +8 -0
  468. package/src/identity/contracts/oidc.ts +10 -0
  469. package/src/identity/contracts/operatorAuth.ts +61 -0
  470. package/src/identity/contracts/operatorInvitations.ts +32 -0
  471. package/src/identity/contracts/ports.ts +25 -0
  472. package/src/identity/contracts/privacy.ts +86 -0
  473. package/src/identity/contracts/providerList.ts +13 -0
  474. package/src/identity/contracts/types.ts +25 -0
  475. package/src/identity/contribution.ts +29 -0
  476. package/src/identity/customerAuth.ts +3 -0
  477. package/src/identity/customerAuthorization.ts +38 -0
  478. package/src/identity/customerContracts.ts +52 -0
  479. package/src/identity/customerIdentityBinding.ts +125 -0
  480. package/src/identity/customerIdentityVerifier.ts +141 -0
  481. package/src/identity/customerMagicLinkHandler.ts +171 -0
  482. package/src/identity/customerMeHandler.ts +64 -0
  483. package/src/identity/customerPorts.ts +2 -0
  484. package/src/identity/customerSessionBinding.ts +114 -0
  485. package/src/identity/customerSessionIssuer.ts +71 -0
  486. package/src/identity/customerVerifyOtpHandler.ts +44 -0
  487. package/src/identity/directOperatorInvitationStore.ts +178 -0
  488. package/src/identity/emailTrustPolicy.ts +16 -0
  489. package/src/identity/identityPersonalDataContributor.ts +48 -0
  490. package/src/identity/identityReadiness.ts +26 -0
  491. package/src/identity/index.ts +69 -0
  492. package/src/identity/inviteAdminUserUseCase.ts +134 -0
  493. package/src/identity/jwtLibrary.ts +24 -0
  494. package/src/identity/machineActorWriteFence.ts +19 -0
  495. package/src/identity/magicLinkPorts.ts +7 -0
  496. package/src/identity/managedAccountLinkStore.ts +105 -0
  497. package/src/identity/managedAdminAuthVerifier.ts +40 -0
  498. package/src/identity/managedAdminUserGateways.ts +164 -0
  499. package/src/identity/managedClient.ts +58 -0
  500. package/src/identity/managedClientAuthLink.ts +120 -0
  501. package/src/identity/managedCustomerMe.ts +52 -0
  502. package/src/identity/managedEmailTrustPolicy.ts +90 -0
  503. package/src/identity/managedIdentityVerifier.ts +20 -0
  504. package/src/identity/managedPrivacy.ts +37 -0
  505. package/src/identity/messages.ts +41 -0
  506. package/src/identity/oidcIdentityVerifier.ts +229 -0
  507. package/src/identity/oidcPrincipal.ts +10 -0
  508. package/src/identity/operatorAdminAuth.ts +14 -0
  509. package/src/identity/operatorAuthHandlers.ts +52 -0
  510. package/src/identity/operatorIdentityVerifier.ts +19 -0
  511. package/src/identity/operatorInvitationLifecycle.ts +14 -0
  512. package/src/identity/operatorInvitationPorts.ts +11 -0
  513. package/src/identity/operatorPorts.ts +11 -0
  514. package/src/identity/operatorSession.ts +30 -0
  515. package/src/identity/operatorTokenAdminAuth.ts +79 -0
  516. package/src/identity/personalDataRegistry.ts +8 -0
  517. package/src/identity/platformAdminAuth.ts +7 -0
  518. package/src/identity/ports.ts +158 -0
  519. package/src/identity/postgresAccountLinkStore.ts +49 -0
  520. package/src/identity/postgresCustomerMe.ts +33 -0
  521. package/src/identity/postgresCustomerRecovery.ts +72 -0
  522. package/src/identity/postgresOperatorIdentity.ts +123 -0
  523. package/src/identity/postgresPrivacy.ts +117 -0
  524. package/src/identity/privacyHandlers.ts +33 -0
  525. package/src/identity/privacyPorts.ts +52 -0
  526. package/src/identity/privacyUseCases.ts +48 -0
  527. package/src/identity/reconcileAccountForPrincipal.ts +99 -0
  528. package/src/identity/reconcileAccountHandler.ts +36 -0
  529. package/src/identity/removeAdminUserUseCase.ts +85 -0
  530. package/src/identity/response.ts +3 -0
  531. package/src/identity/sql.ts +10 -0
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 nine experimental entries each bind a declaration snapshot and package-owned smoke tests. The API checker reads this same inventory.
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` |
@@ -19,6 +19,10 @@ It holds the runnable server substrate an OpenLup application composes: the Node
19
19
  | `./job-ledger` | The job-run ledger port, its PostgreSQL and managed (Supabase) adapters, the managed v2/v3 compatibility calls and the location of its SQL |
20
20
  | `./kernel` | The bundle identifiers, descriptors and readiness |
21
21
  | `./composition` | `createBundleComposer`, the Node HTTP binding helpers and `createNodeHost` |
22
+ | `./identity` | Experimental capability: identity engine, authorization, profile readers, session adapters and BFF factories |
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 |
22
26
 
23
27
  ## Scheduled jobs
24
28
 
@@ -81,9 +85,34 @@ failed HEAD; use an upload or list operation to observe an S3 loading refusal.
81
85
 
82
86
  ## Verification
83
87
 
84
- 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 any environment read or provider import in the package source.
85
-
86
- `npm run api:check` compares each of the nine declaration entry graphs with the
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.
89
+
90
+ The module-boundary proof permits one optional `./<module>/contracts` export
91
+ only when that module declares `contracts: true` in `PLATFORM_MODULE_GRAPH` in
92
+ [`eslint.config.js`](../../eslint.config.js). Its `types`, `import` and `default`
93
+ targets follow the module entry shape at `dist/<module>/contracts/index`.
94
+ Contracts files may import only their own contracts subtree through canonical
95
+ relative `.js` paths and exact public `@openlup/core` entries. Both ESLint and
96
+ [`packageBoundary.test.ts`](test/packageBoundary.test.ts) enforce this allowlist
97
+ for static imports and re-exports (including types) and literal `import()`;
98
+ they refuse non-literal `import()` targets. Both checks reserve the identifier
99
+ names `require`, `module`, `exports`, `process`, `globalThis`, `global`,
100
+ `__dirname`, `__filename` and `Buffer` in every value and type position,
101
+ including local and property identifiers, and refuse every use of `import.meta`.
102
+ This rejects loader aliases and wrapped calls regardless of the load target.
103
+ The existing non-literal `require` member-call guard also remains, including
104
+ computed property calls.
105
+ The package test additionally requires every file in the contracts subtree to
106
+ be a scanned `.ts` file, refuses triple-slash type and path references and all
107
+ meta-properties (also `new.target`), and retains member-call `require` detection
108
+ outside contracts. Identity declares this entry; synthetic graphs also exercise these checks.
109
+
110
+
111
+ The job-run ledger SQL asset test verifies a readable, nonempty file within the
112
+ package SQL directory. Its SQL parity tests bind the actual adapter calls to the
113
+ shipped routine signatures; the asset's explanatory header may be edited freely.
114
+
115
+ `npm run api:check` compares every declared entry graph with the
87
116
  committed `api/*.api.md` reports. After building, deliberately regenerate them
88
117
  with `node --experimental-strip-types ./scripts/api-contract.ts --update` from
89
118
  this package, and review the declaration changes.
@@ -120,7 +149,605 @@ phase redirects npm to an empty temporary cache.
120
149
 
121
150
  The composition declarations describe the injected Supabase factory structurally;
122
151
  they do not import the data entry or its PostgreSQL types. The cold proof still
123
- requires all five nonadapter entries to import in fresh processes and compile
152
+ requires all six nonadapter entries (including `./identity/contracts`) to import in fresh processes and compile
124
153
  in both resolution modes with all three optional peers absent.
125
154
 
126
155
  <!-- openlup-doc-impact {"unit":"platform-substrate","digest":"sha256-00994d288cfec0c8dc0ae9aeae2ff542e2e9af2fedcb4dd2dfeb6c99523be92d","reason":"The manifest moves to the 0.15.0 set version with the exact @openlup/core 0.15.0 peer pin. The package surface, settings and verification described here are unchanged by this preparation delta."} -->
156
+
157
+ ## Identity import candidate
158
+
159
+ The OIDC API adds `createOidcIdentityVerifier`,
160
+ `deriveOidcPrincipalId`, `createPostgresAccountLinkStore` and
161
+ `identityOidcReadiness` from `@openlup/platform/identity`, which also exports
162
+ `OIDC_FAILURE_CODES` and `OidcFailureCode` for hosts. The browser-shared
163
+ `@openlup/platform/identity/contracts` entry excludes OIDC refusals.
164
+ Inject the host's selected JWT library through `IdentityJwtLibraryLoader`.
165
+ Discovery and rotating keys load only on verification or readiness. The opt-in
166
+ direct composition uses normal reconcile with an explicit email-trust policy,
167
+ authenticated actor reads and live operator membership. Managed storage requires
168
+ native federation sessions and refuses raw upstream-token composition. Run
169
+ `node tests/postgres/runOidcIdentityConformance.mjs` from the repository root with
170
+ its cached pinned issuer and local prerequisites; the [OIDC recipe](../../docs/platform/IDENTITY.md#real-issuer-oidc-recipe)
171
+ owns timing, refusal, session and certification boundaries. There is no schema or
172
+ default login flow change; existing static session verification and default
173
+ reference/browser flows retain their runtime behaviour.
174
+
175
+ The existing `IdentityJwtLibrary.jwtVerify` contract widens with optional
176
+ `currentDate?: Date` and `clockTolerance?: number` verify options and now returns
177
+ `{ payload: IdentityJwtClaims }`, whose claims interface includes a string index
178
+ signature. **Migration:** hosts implementing or typing their own
179
+ `IdentityJwtLibrary` or `IdentityJwtLibraryLoader` must accept the optional verify
180
+ options and return claims as `IdentityJwtClaims`.
181
+
182
+ The direct operator API adds `createPostgresOperatorIdentityStore`,
183
+ `createOperatorSessionService`, `createOperatorIdentityVerifier`,
184
+ `createOperatorAdminAuth` and `createOperatorAuthHandlers` to `./identity`.
185
+ `./identity/contracts` exposes strict operator challenge/session schemas and
186
+ `OperatorBrowserAuthPort` without a server or provider import. Challenge delivery
187
+ and session signing use the existing structural ports. Operator handlers send
188
+ the padded generic acceptance before awaiting mailbox delivery, keeping delivery
189
+ latency out of the response. Custom HTTP composition uses the session service's
190
+ optional acceptance callback for the same ordering. Restoration reads preserve
191
+ in-flight browser redemption; explicit sign-out still cancels it. Active operator
192
+ login needs no pending invitation and preserves membership and invitation history. The new store's public
193
+ signature exposes no driver types and loads its optional driver only on use.
194
+
195
+ Apply the complete direct catalogue through position 68 before enabling human
196
+ login; `sql/20261018180000_identity_operator_challenges.sql` is its exact projection.
197
+ Configure a distinct operator audience and an adopter deployment route policy:
198
+ the public policy refuses all mounted operator routes, including `me`, with
199
+ `adopter_policy_required` before input or authentication-binding construction. The reference dispatcher accepts a
200
+ session-binding factory through `createReferenceBffDispatch`; use it to compose
201
+ separate operator delivery. Caller-supplied operator handlers retain the same
202
+ policy boundary. The browser hook consumes guarded auth-port notifications rather
203
+ than signing out from a stale post-redemption check. Use the
204
+ explicit bootstrap/prune commands in the [identity guide](../../docs/platform/IDENTITY.md#direct-human-login).
205
+ The bounded reference browser builds do not mount the admin shell; application
206
+ composition must mount the provided pages and hook. First redemption activates the existing invitation and consumes the challenge in
207
+ one transaction. Live membership, not a JWT role, authorizes each request. The
208
+ cold consumer includes both identity entries and the new adapter's missing-peer
209
+ refusal; real concurrency and upgrade proof needs the complete PostgreSQL chain.
210
+
211
+ Creating a client/contact records commerce contact data, not an authentication
212
+ identity. Creating an auth user provisions a principal. Neither a typed address
213
+ nor a soft-account link proves mailbox ownership; reconcile may create a contact
214
+ for an existing authenticated principal without creating that principal.
215
+
216
+ Customer soft-account provisioning now creates unconfirmed auth users
217
+ (`email_confirm:false`). The soft-account linker retains create-first lookup,
218
+ normalized duplicate recovery and conditional linking. Checkout and paid-order
219
+ retry are adopter composition that must call the linker. Failed links retain
220
+ the provisioned identity for retry. Customer magic links keep
221
+ `shouldCreateUser:false`: captured mailbox proof confirms that existing user;
222
+ unknown addresses cannot sign themselves up through this path.
223
+
224
+ The managed link store requires an injected `emailTrustPolicy`, assessed before
225
+ creation or linking an existing identity by email. Unsafe or unavailable settings
226
+ return a non-fatal soft-account refusal (`EMAIL_TRUST_ENVELOPE_REFUSED` or
227
+ `EMAIL_TRUST_SETTINGS_UNAVAILABLE`) without creating an identity or link. Matching
228
+ existing links retain their replay behaviour. The reference adapter binds managed
229
+ settings assessment regardless of the selected bundle.
230
+
231
+ **Migration:** soft-account provisioning requires a trusted envelope: automatic
232
+ email confirmation disabled and every enabled non-email provider explicitly
233
+ declared email-verifying. Automatic signup can otherwise confirm an unconfirmed
234
+ user and issue a session to someone who merely knows the contact's address.
235
+ Pass the policy to `createSupabaseClientAuthLinkStore(client, emailTrustPolicy)`;
236
+ custom `ClientAuthLinkStore` implementations must expose `emailTrustPolicy`.
237
+ An adopter may explicitly bind `createVerifierResultOnlyEmailTrustPolicy()` when
238
+ its own trust boundary supplies the guarantee. Ensure the selected Auth installation can deliver and verify the
239
+ first-login link for an existing unconfirmed user. Run the documented joint local conformance
240
+ command after building core/platform. Existing identities, contact links,
241
+ subscription references and migration history are not rewritten.
242
+
243
+ Managed verification now requires the confirmation timestamp. Email-derived
244
+ reconcile requires an injected `emailTrustPolicy`. Managed hosts share
245
+ `createManagedEmailTrustPolicy` with `identityEmailTrustReadiness`; it reports
246
+ module `identity` using core's existing codes. Hosts retaining verifier-only
247
+ admission explicitly bind `createVerifierResultOnlyEmailTrustPolicy()`.
248
+ See the [identity policy and migration](../../docs/platform/IDENTITY.md#responsibility-and-composition)
249
+ for the empty provider allowlist, cache/deadline, 403/503 failures and the opt-in
250
+ `node tests/postgres/runIdentityEnvelopeConformance.mjs --phase email-trust` and
251
+ `node tests/postgres/runIdentityEnvelopeConformance.mjs --phase joint` prerequisites
252
+ and conformance scope. Both phases replay the committed managed chain, including
253
+ the identity capabilities forward, and prove association under the shipped managed
254
+ reference grants.
255
+ Construction and imports perform no settings read or SDK initialization.
256
+
257
+
258
+ The `./identity` server entry imports the existing identity engine, authorization,
259
+ profile readers, session adapters and BFF factories into one capability. Its
260
+ `./identity/contracts` entry is declared browser-safe and currently exposes the
261
+ customer auth port, value types and provider parser. Runtime-schema extraction
262
+ is pending the contracts-boundary choice described in the
263
+ [identity owner page](../../docs/platform/IDENTITY.md). Both entries remain an
264
+ unpublished development-preview import candidate.
265
+
266
+ Application composition supplies SDK clients/loaders, feature admission, redirect
267
+ policy, rate limiting, messages, sender and deployment URLs. Factories use the
268
+ foundation BFF envelope and accept the application's observed request-ID reader.
269
+ The module depends only on the declared foundation entries, without changing the
270
+ artifact's rail kind. Its schema contribution requires a host-selected inventory;
271
+ its seven SQL files are verbatim projections at canonical positions 11, 12, 29,
272
+ 60, 67, 68 and 69, not an independent migration chain. The owner page maps the characterization
273
+ witnesses and records the remaining evidence.
274
+
275
+ Identity authorizes stored operator roles only when they are `admin` or
276
+ `distributor`; null and unknown values return `FORBIDDEN` (HTTP 403). The reference
277
+ admin-profile reader reports those rows as non-admin, and admin magic links do
278
+ not send for them while retaining the generic accepted response, padding and
279
+ quota. Adopters needing legacy role mapping must do it in their own adapter
280
+ before passing the role to the package; there is no package fallback option.
281
+
282
+ Both managed contact stores match normalized addresses case-insensitively,
283
+ including mixed-case stored contacts. Literal matching uses an anchored, escaped
284
+ `imatch` database prefilter plus an exact `email.trim().toLowerCase()` comparison
285
+ with the normalized input. Unicode regex folding alone cannot establish identity.
286
+ Both lookups select email and fetch at most ten candidates. Soft linking selects
287
+ the oldest accepted contact; reconciliation requires a single accepted contact
288
+ and throws the existing multiple-row error if several remain. A match beyond the
289
+ candidate bound is not selected. Injected structural query clients must implement
290
+ `filter(column, "imatch", value)` and the bounded array query. The direct customer
291
+ challenge already compares `lower(email)` to normalized input; no migration is
292
+ needed.
293
+
294
+ Magic-link factories default to the shared strict origin resolver. Pass
295
+ `redirectOrigins: ["https://example.com", "https://secondary.example.com:8443"]`;
296
+ the first configured origin builds the callback and every entry must be an exact
297
+ HTTP(S) origin, without credentials, a path, query or fragment (a root trailing
298
+ slash is accepted). Request headers never authorize an origin. Missing or invalid
299
+ configuration returns BFF `UPSTREAM_UNAVAILABLE` (503), with details reason
300
+ `magic_link_origin_not_configured`, before provider access. Customer `returnTo`
301
+ is normalized to a same-origin relative path; unsafe targets are omitted for the
302
+ callback's default landing page. An adopter needing its existing policy can keep
303
+ passing `resolveOrigin`; that explicit injection overrides the default. See the
304
+ [identity redirect contract](../../docs/platform/IDENTITY.md#magic-link-redirect-policy)
305
+ for reference configuration and migration.
306
+
307
+
308
+ ### Operator invitations
309
+
310
+ `identity/contracts` exposes distinct direct pending-invitation and managed
311
+ active-membership results. Matching runtime schemas remain in the server entry.
312
+ The admin-action port returns `OperatorInviteResult`, a union of those results.
313
+
314
+ `createDirectOperatorInvitationStore` provides the new pending, active, expired and
315
+ revoked lifecycle in its trusted PostgreSQL transaction lane, including ordered
316
+ membership locks and atomic membership/audit writes. Direct callers inject the
317
+ store and a parsed TTL. `createDirectOperatorIdentityDirectory` commits principal
318
+ creation/reuse separately. Apply the complete direct catalogue through position
319
+ 67; the byte-identical package projection is for inspection and composition, not
320
+ a standalone fresh chain. Direct human acceptance is a trusted command,
321
+ unmounted from machine authentication.
322
+
323
+ Managed hosts use `createInviteAdminUserGateway().activateMembership` in
324
+ `runInviteAdminUserUseCase`. Insertion immediately creates active `admin_users`
325
+ membership with invitation provenance; it omits `is_machine_actor` and relies on
326
+ the database default false. The result carries principal ID, role, active state
327
+ and `MEMBERSHIP_CREATED` or `ALREADY_ACTIVE`, without pending timestamps or an
328
+ invitation ID. Identical repeats and concurrent insert losers return the existing
329
+ membership without a second notification. Role differences conflict; revoked
330
+ members refuse with `MANAGED_REINVITE_UNSUPPORTED`. Failures retain identities
331
+ for retry, including after notification failure. No Auth metadata store,
332
+ first-entry acceptance, expiry or compensation is used. Magic-link eligibility
333
+ requires active membership and a known role. Authorization, removal and admin
334
+ `me` retain their actor bindings without a service key for lifecycle state.
335
+
336
+ **Migration:** direct hosts can adopt the new pending lifecycle by applying
337
+ `20261018120000_identity_operator_invitations` after the existing direct catalogue
338
+ and composing the store, trusted human acceptance and parsed TTL. Existing
339
+ memberships are preserved. Managed immediate activation is retained; managed
340
+ consumers must now parse the structured active result and its
341
+ `MEMBERSHIP_CREATED`/`ALREADY_ACTIVE` codes instead of message-only success.
342
+ Duplicates return existing membership rather than `ALREADY_ADDED`, and
343
+ notification failure returns 503 `INVITATION_NOTIFICATION_FAILED` while keeping
344
+ membership active. Managed pending/expiry remains a compatibility gap requiring
345
+ a separate transactional store and reviewed forward. No managed SQL, RPC or SDK
346
+ dependency is added. See the
347
+ [identity lifecycle owner](../../docs/platform/IDENTITY.md#operator-invitation-lifecycle).
348
+
349
+ The managed chain's identity capabilities forward
350
+ `20261018160000_identity_service_role_capabilities.sql` grants `service_role`
351
+ SELECT(email) and INSERT(id, email, role, membership_state, membership_provenance,
352
+ membership_accepted_at) on `admin_users`.
353
+ The opt-in managed conformance replays the complete committed chain with ambient
354
+ default ACLs removed and adds no grant. It proves immediate activation,
355
+ repeat/concurrent recovery and revoked-member refusal under the shipped grants.
356
+ It does not establish managed/direct lifecycle parity.
357
+
358
+ With a fresh local managed stack running, export its API URL, service key and
359
+ PostgreSQL owner (`supabase_admin`) connection URL as `OPENLUP_MANAGED_CONFORMANCE_URL`,
360
+ `OPENLUP_MANAGED_CONFORMANCE_SERVICE_KEY` and
361
+ `OPENLUP_MANAGED_CONFORMANCE_DATABASE_URL`, then run from the repository root:
362
+
363
+ ```sh
364
+ npm --workspace @openlup/platform run build
365
+ node --import tsx tests/postgres/operatorInvitationManaged.conformance.ts
366
+ ```
367
+
368
+ The module refuses non-loopback endpoints, an already-installed public schema,
369
+ and existing synthetic fixture identities. It retains synthetic identities;
370
+ discard the disposable stack after the run. Its database owner connection must
371
+ be able to replay the committed prerequisites, baseline and ordered forwards.
372
+
373
+ ## Personal data
374
+
375
+ The experimental identity entry exposes `createPersonalDataContributorRegistry`,
376
+ `createIdentityPersonalDataContributor`, `createPrivacyOperations`,
377
+ `exportPersonalData`, `erasePersonalData`, `createPrivacyExportHandler` and
378
+ `createPrivacyEraseHandler`. Browser requests, versioned contributor documents and
379
+ receipts come from `@openlup/platform/identity/contracts`. Register every required
380
+ contributor explicitly, with its owned fields, assessment, erase/retain operation
381
+ and remote/retention obligations. Missing required owners refuse erasure; export
382
+ reports missing coverage. This capability erases identity-owned data only.
383
+
384
+ Direct hosts compose `createPostgresPrivacyUnitOfWork` and
385
+ `createPostgresPrivacyStore` with the identity contributor and their domain vetoes
386
+ using the same executor. The reference subscriptions contributor holds a relation
387
+ lock through commit, refusing active and paused subscriptions without changing
388
+ them. `IdentityPrivacyPolicy.retainedContactFields` names explicit retention
389
+ owners for populated opaque columns; unknown ownership refuses. The reference
390
+ retains lifecycle/acquisition fields, and refuses nonempty metadata or external
391
+ references until an owner declares their disposition.
392
+
393
+ Migration: apply the complete direct catalogue including
394
+ `20261018190000_identity_privacy_erasures` before using privacy or the updated
395
+ customer challenge store. The forward appends one receipt table at position 69
396
+ without grants or stored functions. Direct erasure pseudonymizes identity-owned
397
+ fields, deletes challenges and outstanding invitations, uses guarded membership
398
+ revocation, clears only the selected contact's direct principal link, and commits
399
+ an idempotent audit receipt atomically. Contact IDs and managed auth links never
400
+ change. Failed writes roll back. Retained audit references are pseudonymous, not
401
+ an assertion of anonymization. Already-issued tokens may remain valid until expiry.
402
+ Customer challenge issuance and redemption reject a receipt for either the
403
+ contact or principal under the same transaction-held challenge relation lock as
404
+ erasure, including late challenges inserted after cleanup. Hosts must use the
405
+ package adapters; calling the retained raw challenge SQL functions directly
406
+ bypasses this erasure receipt fence.
407
+
408
+ Managed hosts compose `createManagedPrivacyStore` with their structural service
409
+ client for export. Coverage explicitly excludes inaccessible country and
410
+ identity history/receipt fields. Managed erasure refuses with
411
+ `MANAGED_PRIVACY_ERASURE_UNAVAILABLE`: a managed adopter must provide its own
412
+ erasure path. The committed grants and structural client cannot provide the
413
+ required mutations and atomic receipt. This change adds no managed forward or
414
+ erasure grants. Provider identity is never deleted; any future composed provider
415
+ erasure must disable it after committed local success. The managed refusal here
416
+ occurs before reaching any provider mutation.
417
+
418
+ The reference mounts authenticated human-admin export/erase POSTs and an Admin
419
+ Settings readback panel. Direct and managed mounts require the adopter deployment
420
+ policy under admin mutation risk; the public default returns
421
+ `adopter_policy_required` before body/query reads, and direct mounts also refuse
422
+ before authentication or privacy binding construction. The shipped dispatcher mounts
423
+ both routes for managed bundles even when its caller supplies no routes. After admission,
424
+ exports and receipts stay in memory with no-store
425
+ responses. The maintenance `prune-challenges` command prunes separate bounded
426
+ operator/customer batches. See [identity privacy](../../docs/platform/IDENTITY.md#identity-personal-data)
427
+ for refusals, token limits and retained obligations.
428
+
429
+ The complete direct conformance is included in
430
+ `npm test -- tests/postgres/operatorIdentityUpgrade.test.ts` from the repository
431
+ root after normal setup. A maintainer host resource broker is optional.
432
+ For managed conformance, supply the same three `OPENLUP_MANAGED_CONFORMANCE_*`
433
+ local disposable-stack settings described for operator invitations, with
434
+ `OPENLUP_MANAGED_CONFORMANCE_DATABASE_URL` set to the database owner
435
+ (`supabase_admin`) connection, then run
436
+ `node --experimental-strip-types tests/postgres/identityPrivacyManaged.conformance.ts`.
437
+ Use a fresh public schema and reset the disposable stack between proofs; the
438
+ managed privacy proof replays the committed chain without fixture erasure grants.
439
+ Replay through node-postgres omits only the psql-only pg_dump `\restrict` and
440
+ `\unrestrict` guard lines; all migration SQL remains unchanged.
441
+
442
+
443
+ Reference startup can compose identity through `createReferenceIdentity` and
444
+ `startPublicReferenceServer({ identity })`, with explicit route functions,
445
+ selected adapters, trusted schema/migration observation and the bundle-specific
446
+ inventory. It consumes email-trust readiness before listening, and rejects
447
+ unknown or unsatisfied candidates. Direct reconcile reads the existing actor
448
+ link; direct invite/remove select the pending-invitation stores. The default
449
+ static reference and browser page sets remain unchanged. See the
450
+ [composition contract](../../docs/platform/IDENTITY.md#responsibility-and-composition).
451
+
452
+ Both identity entries already belong to the public export map and build output;
453
+ artifact availability does not imply registry publication or release activation.
454
+ The cold installed-artifact consumer imports both entries without optional peers,
455
+ compiles contracts without driver types, and invokes every driver-owning direct
456
+ identity adapter for its missing-peer refusal. Managed factories consume
457
+ structural clients. Server declarations compile after peer selection. Full
458
+ installed-artifact and database proof require the existing supervisor-run package
459
+ consumer command and an owned disposable database.
460
+
461
+ The managed identity service-role capabilities forward in the committed chain
462
+ supplies client link writes and operator membership insert/email-read
463
+ permissions; the local conformance runners add no fixture grant. No migration is
464
+ added by reference composition.
465
+
466
+
467
+ ## Disposable identity composition
468
+
469
+ The reference application's opt-in identity shell consumes the existing
470
+ `./identity` and `./identity/contracts` exports without changing their maturity
471
+ or publishing a registry version. It reuses the customer/operator pages and
472
+ captured-delivery port, with a private local mailbox and administrator privacy
473
+ panel. Its explicit runtime must supply actual routes and readiness admission;
474
+ the shell refuses a missing composition. See the
475
+ [identity reference guide](../../docs/platform/IDENTITY.md#disposable-identity-reference)
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.