@openlup/platform 0.27.0 → 0.29.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 (232) hide show
  1. package/CHANGELOG.md +386 -127
  2. package/README.md +251 -9
  3. package/dist/account-support/accountReadFacade.d.ts +8 -0
  4. package/dist/account-support/accountReadFacade.js +10 -0
  5. package/dist/account-support/accountReadModels.d.ts +69 -0
  6. package/dist/account-support/accountReadModels.js +272 -0
  7. package/dist/account-support/bindings.d.ts +23 -0
  8. package/dist/account-support/bindings.js +16 -0
  9. package/dist/account-support/contracts/account.d.ts +281 -0
  10. package/dist/account-support/contracts/account.js +1 -0
  11. package/dist/account-support/contracts/capabilities.d.ts +44 -0
  12. package/dist/account-support/contracts/capabilities.js +1 -0
  13. package/dist/account-support/contracts/commands.d.ts +307 -0
  14. package/dist/account-support/contracts/commands.js +1 -0
  15. package/dist/account-support/contracts/customer360.d.ts +154 -0
  16. package/dist/account-support/contracts/customer360.js +1 -0
  17. package/dist/account-support/contracts/index.d.ts +10 -0
  18. package/dist/account-support/contracts/index.js +1 -0
  19. package/dist/account-support/contracts/invoice.d.ts +79 -0
  20. package/dist/account-support/contracts/invoice.js +1 -0
  21. package/dist/account-support/contracts/operator.d.ts +289 -0
  22. package/dist/account-support/contracts/operator.js +1 -0
  23. package/dist/account-support/contribution.d.ts +24 -0
  24. package/dist/account-support/contribution.js +22 -0
  25. package/dist/account-support/customer360.d.ts +106 -0
  26. package/dist/account-support/customer360.js +163 -0
  27. package/dist/account-support/customerAccountReadDiagnostics.d.ts +11 -0
  28. package/dist/account-support/customerAccountReadDiagnostics.js +71 -0
  29. package/dist/account-support/index.d.ts +26 -0
  30. package/dist/account-support/index.js +15 -0
  31. package/dist/account-support/invoiceAccess.d.ts +57 -0
  32. package/dist/account-support/invoiceAccess.js +40 -0
  33. package/dist/account-support/migrations.d.ts +14 -0
  34. package/dist/account-support/migrations.js +7 -0
  35. package/dist/account-support/operatorAuthority.d.ts +67 -0
  36. package/dist/account-support/operatorAuthority.js +379 -0
  37. package/dist/account-support/operatorRecovery.d.ts +66 -0
  38. package/dist/account-support/operatorRecovery.js +129 -0
  39. package/dist/account-support/orderHistory.d.ts +50 -0
  40. package/dist/account-support/orderHistory.js +188 -0
  41. package/dist/account-support/paymentMethodComposition.d.ts +5 -0
  42. package/dist/account-support/paymentMethodComposition.js +4 -0
  43. package/dist/account-support/postgresOperatorAuthority.d.ts +16 -0
  44. package/dist/account-support/postgresOperatorAuthority.js +93 -0
  45. package/dist/account-support/selfService.d.ts +6 -0
  46. package/dist/account-support/selfService.js +81 -0
  47. package/dist/account-support/subscriptionCommandCodec.d.ts +10 -0
  48. package/dist/account-support/subscriptionCommandCodec.js +38 -0
  49. package/dist/catalog/draftSchemas.d.ts +1 -1
  50. package/dist/catalog/foundationSchemas.d.ts +3 -3
  51. package/dist/catalog/resolvedSkuProjection.d.ts +2 -2
  52. package/dist/catalog/sellableSchemas.d.ts +2 -2
  53. package/dist/commerce/checkoutCommandSchemas.d.ts +2 -2
  54. package/dist/commerce/checkoutResumeSchemas.d.ts +6 -6
  55. package/dist/commerce/checkoutSchemas.d.ts +12 -12
  56. package/dist/commerce/commerceReturnsPort.d.ts +2 -2
  57. package/dist/commerce/configuratorIntentSchemas.d.ts +2 -2
  58. package/dist/commerce/contractPrimitives.d.ts +8 -8
  59. package/dist/commerce/customerDefaultsSnapshotSchemas.d.ts +4 -4
  60. package/dist/commerce/model/omsReadModelHelpers.d.ts +4 -4
  61. package/dist/commerce/offerAvailabilitySchemas.d.ts +1 -1
  62. package/dist/commerce/oms/omsContractBase.d.ts +15 -15
  63. package/dist/commerce/oms/omsContractReadAuxSchemas.d.ts +11 -11
  64. package/dist/commerce/oms/omsContractReadSchemas.d.ts +121 -121
  65. package/dist/commerce/oms/omsContractRequests.d.ts +13 -13
  66. package/dist/commerce/oms/omsControlPlane.d.ts +22 -22
  67. package/dist/commerce/oms/omsFulfillmentContractSchemas.d.ts +12 -12
  68. package/dist/commerce/oms/omsFulfillmentDebugSchemas.d.ts +12 -12
  69. package/dist/commerce/orderReviewContracts.d.ts +33 -33
  70. package/dist/commerce/outboxEventSchemas.d.ts +4 -4
  71. package/dist/commerce/schemas.d.ts +21 -21
  72. package/dist/commerce/server/orderReviewHandlers.d.ts +10 -10
  73. package/dist/communications/consentPurposeRegistry.d.ts +1 -1
  74. package/dist/communications/newsletterIntegrationContracts.d.ts +8 -8
  75. package/dist/composition/accountSupportContribution.d.ts +18 -0
  76. package/dist/composition/accountSupportContribution.js +21 -0
  77. package/dist/composition/index.d.ts +2 -0
  78. package/dist/composition/index.js +2 -0
  79. package/dist/composition/marketingContribution.d.ts +21 -0
  80. package/dist/composition/marketingContribution.js +29 -0
  81. package/dist/fulfillment/handlerSchemas.d.ts +40 -40
  82. package/dist/identity/customerContracts.d.ts +2 -2
  83. package/dist/invoicing/snapshot.d.ts +1 -1
  84. package/dist/marketing/acquisitionCaseSchemas.d.ts +103 -0
  85. package/dist/marketing/acquisitionCaseSchemas.js +53 -0
  86. package/dist/marketing/acquisitionEvidenceSchemas.d.ts +105 -0
  87. package/dist/marketing/acquisitionEvidenceSchemas.js +55 -0
  88. package/dist/marketing/analytics/dataLayer.d.ts +18 -0
  89. package/dist/marketing/analytics/dataLayer.js +111 -0
  90. package/dist/marketing/analytics/noop.d.ts +9 -0
  91. package/dist/marketing/analytics/noop.js +8 -0
  92. package/dist/marketing/analytics/purchaseFacts.d.ts +4 -0
  93. package/dist/marketing/analytics/purchaseFacts.js +69 -0
  94. package/dist/marketing/analytics/routePolicy.d.ts +10 -0
  95. package/dist/marketing/analytics/routePolicy.js +59 -0
  96. package/dist/marketing/consentEvidence.d.ts +8 -0
  97. package/dist/marketing/consentEvidence.js +32 -0
  98. package/dist/marketing/contactLegal.d.ts +14 -0
  99. package/dist/marketing/contactLegal.js +19 -0
  100. package/dist/marketing/contracts/acquisition.d.ts +88 -0
  101. package/dist/marketing/contracts/acquisition.js +1 -0
  102. package/dist/marketing/contracts/acquisitionPorts.d.ts +49 -0
  103. package/dist/marketing/contracts/acquisitionPorts.js +1 -0
  104. package/dist/marketing/contracts/analytics.d.ts +144 -0
  105. package/dist/marketing/contracts/analytics.js +1 -0
  106. package/dist/marketing/contracts/contactLegal.d.ts +53 -0
  107. package/dist/marketing/contracts/contactLegal.js +1 -0
  108. package/dist/marketing/contracts/index.d.ts +6 -0
  109. package/dist/marketing/contracts/index.js +1 -0
  110. package/dist/marketing/contracts/prelaunch.d.ts +39 -0
  111. package/dist/marketing/contracts/prelaunch.js +1 -0
  112. package/dist/marketing/index.d.ts +16 -0
  113. package/dist/marketing/index.js +14 -0
  114. package/dist/marketing/prelaunchAcquisitionSchemas.d.ts +116 -0
  115. package/dist/marketing/prelaunchAcquisitionSchemas.js +51 -0
  116. package/dist/marketing/seo/jsonLd.d.ts +157 -0
  117. package/dist/marketing/seo/jsonLd.js +127 -0
  118. package/dist/marketing/seo/metadata.d.ts +41 -0
  119. package/dist/marketing/seo/metadata.js +36 -0
  120. package/dist/marketing/seo/serializeJsonLd.d.ts +1 -0
  121. package/dist/marketing/seo/serializeJsonLd.js +6 -0
  122. package/dist/marketing/seo/urls.d.ts +14 -0
  123. package/dist/marketing/seo/urls.js +23 -0
  124. package/dist/marketing/server/acquisitionCaseDirect.d.ts +4 -0
  125. package/dist/marketing/server/acquisitionCaseDirect.js +88 -0
  126. package/dist/marketing/server/acquisitionCaseHandlers.d.ts +28 -0
  127. package/dist/marketing/server/acquisitionCaseHandlers.js +40 -0
  128. package/dist/marketing/server/acquisitionCasePorts.d.ts +42 -0
  129. package/dist/marketing/server/acquisitionCasePorts.js +1 -0
  130. package/dist/marketing/server/acquisitionEvidenceDirect.d.ts +5 -0
  131. package/dist/marketing/server/acquisitionEvidenceDirect.js +100 -0
  132. package/dist/marketing/server/analyticsContext.d.ts +3 -0
  133. package/dist/marketing/server/analyticsContext.js +65 -0
  134. package/dist/marketing/server/analyticsContextPorts.d.ts +31 -0
  135. package/dist/marketing/server/analyticsContextPorts.js +1 -0
  136. package/dist/marketing/server/bindings.d.ts +14 -0
  137. package/dist/marketing/server/bindings.js +18 -0
  138. package/dist/marketing/server/directPorts.d.ts +26 -0
  139. package/dist/marketing/server/directPorts.js +1 -0
  140. package/dist/marketing/server/index.d.ts +14 -0
  141. package/dist/marketing/server/index.js +11 -0
  142. package/dist/marketing/server/postgres/acquisitionCaseRoutines.d.ts +10 -0
  143. package/dist/marketing/server/postgres/acquisitionCaseRoutines.js +204 -0
  144. package/dist/marketing/server/postgres/acquisitionEvidenceRoutines.d.ts +10 -0
  145. package/dist/marketing/server/postgres/acquisitionEvidenceRoutines.js +107 -0
  146. package/dist/marketing/server/postgres/index.d.ts +3 -0
  147. package/dist/marketing/server/postgres/index.js +3 -0
  148. package/dist/marketing/server/prelaunchAcquisitionDirect.d.ts +4 -0
  149. package/dist/marketing/server/prelaunchAcquisitionDirect.js +122 -0
  150. package/dist/marketing/server/privacyContributor.d.ts +66 -0
  151. package/dist/marketing/server/privacyContributor.js +87 -0
  152. package/dist/marketing/server/research/adminSurveyResponsesHandler.d.ts +9 -0
  153. package/dist/marketing/server/research/adminSurveyResponsesHandler.js +53 -0
  154. package/dist/marketing/server/research/managedSurveyResponseSubmit.d.ts +39 -0
  155. package/dist/marketing/server/research/managedSurveyResponseSubmit.js +102 -0
  156. package/dist/marketing/server/research/surveyResponseSubmitHandler.d.ts +8 -0
  157. package/dist/marketing/server/research/surveyResponseSubmitHandler.js +41 -0
  158. package/dist/marketing/validation.d.ts +2 -0
  159. package/dist/marketing/validation.js +3 -0
  160. package/dist/pricing/acquisitionQuoteBinding.d.ts +1 -1
  161. package/dist/pricing/catalogFactsSchemas.d.ts +1 -1
  162. package/dist/pricing/quotePromotionEvidence.d.ts +1 -1
  163. package/dist/pricing/quoteSchemas.d.ts +56 -56
  164. package/dist/promotions/adminPromotionCodesContracts.d.ts +30 -30
  165. package/dist/promotions/adminPromotionsContracts.d.ts +14 -14
  166. package/package.json +32 -2
  167. package/release-gates.json +99 -4
  168. package/sql/20261026120000_account_support_operator_authority.sql +693 -0
  169. package/src/account-support/accountReadFacade.ts +15 -0
  170. package/src/account-support/accountReadModels.ts +371 -0
  171. package/src/account-support/bindings.ts +28 -0
  172. package/src/account-support/contracts/account.ts +306 -0
  173. package/src/account-support/contracts/capabilities.ts +30 -0
  174. package/src/account-support/contracts/commands.ts +243 -0
  175. package/src/account-support/contracts/customer360.ts +150 -0
  176. package/src/account-support/contracts/index.ts +141 -0
  177. package/src/account-support/contracts/invoice.ts +44 -0
  178. package/src/account-support/contracts/operator.ts +123 -0
  179. package/src/account-support/contribution.ts +35 -0
  180. package/src/account-support/customer360.ts +268 -0
  181. package/src/account-support/customerAccountReadDiagnostics.ts +83 -0
  182. package/src/account-support/index.ts +72 -0
  183. package/src/account-support/invoiceAccess.ts +63 -0
  184. package/src/account-support/migrations.ts +7 -0
  185. package/src/account-support/operatorAuthority.ts +393 -0
  186. package/src/account-support/operatorRecovery.ts +136 -0
  187. package/src/account-support/orderHistory.ts +309 -0
  188. package/src/account-support/paymentMethodComposition.ts +8 -0
  189. package/src/account-support/postgresOperatorAuthority.ts +92 -0
  190. package/src/account-support/selfService.ts +83 -0
  191. package/src/account-support/subscriptionCommandCodec.ts +48 -0
  192. package/src/composition/accountSupportContribution.ts +28 -0
  193. package/src/composition/index.ts +2 -0
  194. package/src/composition/marketingContribution.ts +37 -0
  195. package/src/marketing/acquisitionCaseSchemas.ts +75 -0
  196. package/src/marketing/acquisitionEvidenceSchemas.ts +72 -0
  197. package/src/marketing/analytics/dataLayer.ts +100 -0
  198. package/src/marketing/analytics/noop.ts +14 -0
  199. package/src/marketing/analytics/purchaseFacts.ts +63 -0
  200. package/src/marketing/analytics/routePolicy.ts +55 -0
  201. package/src/marketing/consentEvidence.ts +36 -0
  202. package/src/marketing/contactLegal.ts +22 -0
  203. package/src/marketing/contracts/acquisition.ts +50 -0
  204. package/src/marketing/contracts/acquisitionPorts.ts +48 -0
  205. package/src/marketing/contracts/analytics.ts +88 -0
  206. package/src/marketing/contracts/contactLegal.ts +41 -0
  207. package/src/marketing/contracts/index.ts +17 -0
  208. package/src/marketing/contracts/prelaunch.ts +15 -0
  209. package/src/marketing/index.ts +16 -0
  210. package/src/marketing/prelaunchAcquisitionSchemas.ts +64 -0
  211. package/src/marketing/seo/jsonLd.ts +153 -0
  212. package/src/marketing/seo/metadata.ts +62 -0
  213. package/src/marketing/seo/serializeJsonLd.ts +6 -0
  214. package/src/marketing/seo/urls.ts +34 -0
  215. package/src/marketing/server/acquisitionCaseDirect.ts +67 -0
  216. package/src/marketing/server/acquisitionCaseHandlers.ts +57 -0
  217. package/src/marketing/server/acquisitionCasePorts.ts +42 -0
  218. package/src/marketing/server/acquisitionEvidenceDirect.ts +76 -0
  219. package/src/marketing/server/analyticsContext.ts +55 -0
  220. package/src/marketing/server/analyticsContextPorts.ts +28 -0
  221. package/src/marketing/server/bindings.ts +27 -0
  222. package/src/marketing/server/directPorts.ts +27 -0
  223. package/src/marketing/server/index.ts +14 -0
  224. package/src/marketing/server/postgres/acquisitionCaseRoutines.ts +218 -0
  225. package/src/marketing/server/postgres/acquisitionEvidenceRoutines.ts +103 -0
  226. package/src/marketing/server/postgres/index.ts +3 -0
  227. package/src/marketing/server/prelaunchAcquisitionDirect.ts +121 -0
  228. package/src/marketing/server/privacyContributor.ts +123 -0
  229. package/src/marketing/server/research/adminSurveyResponsesHandler.ts +78 -0
  230. package/src/marketing/server/research/managedSurveyResponseSubmit.ts +158 -0
  231. package/src/marketing/server/research/surveyResponseSubmitHandler.ts +57 -0
  232. package/src/marketing/validation.ts +3 -0
package/README.md CHANGED
@@ -10,18 +10,27 @@ Development preview. This package is part of the publishable set with core and o
10
10
 
11
11
  It holds the runnable server substrate an OpenLup application composes: the Node HTTP runtime, BFF dispatch, scheduling and job leases, blob storage, data gateways, the node-postgres migration runner and bundle composition. Ports and their contracts stay in `@openlup/core/platform-runtime`.
12
12
 
13
- For the prepared `0.27.0` set, read the [adjacent-release migration and known
14
- limitations](CHANGELOG.md#0270) before selecting optional services. Experimental
13
+ For the prepared `0.29.0` set, read the [adjacent-release migration and known
14
+ limitations](CHANGELOG.md#0290) before selecting optional services. Experimental
15
+ M13 marketing uses browser-safe `./marketing`, type-only browser-safe
16
+ `./marketing/contracts`, and Node-only `./marketing/server` and
17
+ `./marketing/server/postgres`. Marketing contributions and bindings remain
18
+ inert and default-off. Experimental
19
+ account/support APIs use `./account-support` and the type-only
20
+ `./account-support/contracts`; reference bindings remain inert and default-off.
21
+ Apply the M12 support-authority forwards after complete same-rail predecessors
22
+ and follow the email-correction admission, claim, identity-commit and settlement
23
+ migration notes before replacing retired callers. Experimental
15
24
  commerce schemas and ports use `./commerce` and `./commerce/contracts`;
16
25
  handlers, adapters and checkout engines use the Node-only `./commerce/server`.
17
26
  The commerce contribution and reference binding remain inert and default-off.
18
- Install the complete native chain through position 86
19
- (`20261024184600_subscription_retry_candidate_payment_filter.sql`); M11 adds no
20
- native SQL. Sparse SQL projections are not an install chain. Native runtime
27
+ Install the complete native chain through the M12 support-authority forward
28
+ (`20261026120000_account_support_operator_authority.sql`). Sparse SQL projections
29
+ are not an install chain. Native runtime
21
30
  roles need the ATP/exposure EXECUTE and underlying SELECT grants described in
22
31
  the release notes.
23
- Managed hosts apply the complete prefix through `20261025110000`, including
24
- M11's nine forwards for preference/return ownership, operator receipts,
32
+ Managed hosts apply the complete prefix through `20261026120100`, including
33
+ the current support-authority forward and M11's nine forwards for preference/return ownership, operator receipts,
25
34
  acquisition/finalize admission, ATP preview and starter graduation. Legacy
26
35
  omitted-country input uses the configured settlement region; neutral commands
27
36
  require explicit country. Starter graduation admits 14, 21 or 28 days; rollback
@@ -45,7 +54,7 @@ Adopters must not activate unselected or unready invoicing; installation and
45
54
  inert contributions register no runner, worker, route or schedule.
46
55
  M06 managed-host proof classes remain pending in the
47
56
  [M06 parity ledger](../../docs/platform/plans/oss-m06-stock-reservations-delivery.md#parity-pending-rows).
48
- Size comparison uses the published `0.26.0` tarball. Preparation and offline
57
+ Size comparison uses the published `0.28.0` tarball. Preparation and offline
49
58
  adapter evidence grant no publication or provider-account certification.
50
59
 
51
60
  Longer module recipes live in the [platform package reference](../../docs/platform/PLATFORM_PACKAGE_REFERENCE.md).
@@ -88,6 +97,12 @@ timestamp used in the webhook's idempotency key.
88
97
  | `./inventory` | Experimental schemas/ports, handlers, native stores, projection, injected forecast and SQL descriptor; `./inventory/contracts` DTOs. |
89
98
  | `./catalog` | Experimental neutral catalog schemas, drafts, reads, media source packs and publication ports |
90
99
  | `./catalog/contracts` | Dependency-free catalog DTOs, media resolver, authority and canonicalization helpers |
100
+ | `./marketing/server` | Node-only acquisition handlers, direct read/evidence factories and research orchestration without `pg`; host responder, authorization, binding and notification copy |
101
+ | `./marketing/server/postgres` | Acquisition case and research evidence PostgreSQL port factories; requires the existing optional `pg` peer |
102
+ | `./marketing/server` (analytics context) | Injected analytics context handler with host persistence, capability and identity bindings |
103
+ | `./marketing`, `./marketing/contracts` | Browser-safe acquisition history, portable prelaunch, survey evidence and newsletter consent schemas; type-only DTOs and acquisition/research ports |
104
+ | `./marketing`, `./marketing/contracts` (analytics) | Browser-safe acquisition and research schemas, injected analytics, paid purchase and consent-time facts; type-only DTOs and ports |
105
+ | `./marketing`, `./marketing/contracts` (SEO and content slots) | Browser-safe JSON-LD serialization and graph builders, URL/hreflang helpers, ordered head data and contact/legal projections; type-only organization, contact, legal-document and privacy-processor content slots |
91
106
  | `./commerce`, `./commerce/contracts` | Browser-safe neutral commerce schema cores, generic ports and pure contract helpers |
92
107
  | `./commerce/server` | Node-only OMS, returns, native reviews/media and hosted-feedback handlers/adapters and order-detail composition, email consumers, dispatch registry, paid-fulfillment binding and checkout compensation, checkout handlers, runtime and shared paid-order saga |
93
108
  | `./pricing` | Experimental price authority, quote computation/handlers, offer projection/cache, readiness and policy tokens |
@@ -98,6 +113,135 @@ timestamp used in the webhook's idempotency key.
98
113
  | `./shipping` | Experimental delivery ports, injected-schema handlers, summary/evidence; native flat-rate port + Core schema readiness |
99
114
  | `./shipping/contracts` | Type-only delivery, pickup-point, summary and evidence DTOs |
100
115
 
116
+ ## Marketing contracts
117
+
118
+ `./marketing` provides acquisition address references, historical case projections,
119
+ list/count reads, portable prelaunch list/detail schemas, idempotency keys, survey submission/evidence/list schemas and
120
+ newsletter consent events/responses. Reference compatibility shims forward the
121
+ same schema objects and load the reference validation wrapper before package
122
+ schemas. The marketing runtime entry configures the shared Zod instance in
123
+ jitless mode before constructing schemas, preserving CSP-safe initialization
124
+ for direct imports as well as reference facades, like the pricing, catalog and
125
+ communications entries. The type-only `./marketing/contracts` entry has no
126
+ runtime initialization. The rich prelaunch DTO and case submit/transition schemas remain application-owned
127
+ and are excluded from the browser entries. The shared
128
+ `acquisitionOpaqueReferenceSchema` lets those retained contracts reuse the exact
129
+ reference syntax. No entry registers a route automatically.
130
+
131
+ `./marketing/contracts` exports only types. Explicit acquisition DTO shapes are
132
+ checked against the runtime schema inference by an executed TypeScript equality
133
+ witness. Reachable case ports expose list, get, active count and close; the app
134
+ uses the server-only compatibility port for its retired methods. Evidence ports retain survey submission,
135
+ survey listing and consent application. Port types are also forwarded through
136
+ the runtime entry, following the commerce boundary. Both entries forward research schemas or types from the compatibility
137
+ owner, `@openlup/core/marketing/research`; runtime schemas retain object identity.
138
+ Case locale remains `en|pl`, matching the persisted constraint. Widening it requires
139
+ a separate migration. Historical wire values remain unchanged.
140
+
141
+ The source and built entries have browser graph proofs. The root test runner
142
+ selects `test/marketing/`; the installed consumer checks both public entries,
143
+ compiles typed usage and refuses deep imports. Kiosk and research reference
144
+ contracts/ports continue to consume the core export. The app owns its admin
145
+ response client and host composition.
146
+
147
+ `./marketing/server` owns acquisition case handlers, list/count and prelaunch
148
+ list/detail factories, survey evidence submit/list and consent application,
149
+ research submit/admin handlers and managed survey orchestration without loading
150
+ `pg`. Select `./marketing/server/postgres` for the two PostgreSQL port factories
151
+ after installing the existing optional `pg` peer. Hosts inject the BFF responder,
152
+ authorization and binding resolvers. Direct case reads receive the host bundle
153
+ predicate at their original guard; prelaunch and evidence dispatch stays in the
154
+ host. Notification HTML and subject are injected separately, preserving
155
+ HTML rendering before the subject clock read. The reference owns retired
156
+ route refusals, raw signed consent ingress and notification copy. PostgreSQL
157
+ SQL, role selection and transaction/pool handling remain unchanged. The
158
+ server-only compatibility command types do not expose retired admission schemas.
159
+
160
+ Analytics facts share these browser-safe entries. `createNoopAnalytics` implements
161
+ Core's existing analytics port; deployment and advertising defaults remain inert.
162
+ `AnalyticsEventMap<StepName>` retains the host's literal step vocabulary, with
163
+ `string` as the neutral default. Private transport ownership fields and envelopes
164
+ remain host extensions. Types are forwarded type-only by `./marketing/contracts`.
165
+
166
+ `createAnalyticsDataLayer` owns loader readiness per instance and accepts the host's
167
+ browser/storage access, consent key and change event, `consentSignalNames`, event
168
+ prefix, container reader and deployment callback. `consentSignalNames` supplies
169
+ one `analytics` wire name and the ordered `advertising` wire names. Without it,
170
+ no consent command is pushed and optional event admission returns false, even
171
+ with browser access, a container and stored consent; deployment attempts remain
172
+ independent. Consent commands seed default before update and
173
+ use array-like arguments; advertising grants read marketing consent at push time.
174
+ Revocation denies every signal. Sinks are attempted independently with failure
175
+ isolation and no replay of observations made before consent. Admission booleans
176
+ mean synchronous local acceptance only, never delivery or business acknowledgement.
177
+
178
+ `createAnalyticsRoutePolicy` requires public paths, redirect sources and all
179
+ sensitive-path sets. Its optional-route predicate preserves broad eligibility;
180
+ deployment URL sanitization admits exact public paths and safe campaign values.
181
+ `projectPaidPurchase` consumes only structural paid-recap facts, preserving
182
+ allocation/grouping, the item cap and ordered suppression reasons without an
183
+ ambient currency policy. `selectMarketingHistoricalConsentTime` selects exact
184
+ native chronology only after host authorization, without changing the local
185
+ grant. The reference retains its narrower checkout-kind admission and all wire
186
+ names. [Purchase equivalence](../../src/checkout/machine/purchasePayloadEquivalence.test.ts)
187
+ and the package analytics witnesses pin these boundaries.
188
+
189
+ `createAnalyticsContextHandler` in `./marketing/server` accepts a required BFF
190
+ responder, enable reader, persistence resolver, access-token reader, trusted-subject
191
+ resolver, capability mint/hash functions, historical cookie name and `clientIdField`.
192
+ The host supplies the client-id wire field name through `clientIdField`; the strict
193
+ request also keeps `granted` and `explicitGrant`. Grants require a client
194
+ id and existing revoked contexts require an explicit new grant for replacement.
195
+ Only token hashes reach persistence. Enrollment uses only the server-verified
196
+ subject, and invalid bearer grants refuse before writes. Cookie attributes and
197
+ method/flag/origin/schema refusal order are preserved. The host owns flag and
198
+ RPC names, gateway authority, route mounting and observability. Persistence
199
+ operations must reject on failure; null persistence refuses as unavailable.
200
+ There is no default persistence, portable SQL or reference route for this handler.
201
+ An `active` result is a local context fact, never delivery, and telemetry context
202
+ failure never gates commerce. The [context witness](test/marketing/analyticsContext.test.ts)
203
+ exercises the factory through synthetic host bindings.
204
+
205
+ `./marketing` also provides browser-safe JSON-LD serialization and graph builders,
206
+ route URL/hreflang helpers, an ordered head descriptor and plain contact/legal
207
+ projections. Applications supply identity, origin, routes, locales, images and
208
+ content; the descriptor is plain data for a host head manager. The type-only
209
+ `./marketing/contracts` entry exports shared organization facts and contact,
210
+ legal-document and privacy-processor shapes, also forwarded as types by the
211
+ runtime entry. The package supplies no document wording, processor inventory or
212
+ content policy. The [marketing recipe](../../docs/platform/PLATFORM_PACKAGE_REFERENCE.md#marketing-seo-and-content-slots)
213
+ owns the mechanics and installed-artifact proof.
214
+
215
+ ## Marketing composition
216
+
217
+ `./composition` exports `createMarketingContribution`, an inert descriptor for
218
+ the `marketing` capability's `./marketing`, `./marketing/contracts` and
219
+ `./marketing/server` entries, with a runtime dependency on `identity/contracts`
220
+ for obligation validation.
221
+ Supply already-bound operations and host schema requirements. Ports, routes and
222
+ triggers share the supplied functions; null ports remain required for Core
223
+ readiness, and handlers retain only registration descriptors. Duplicate handler,
224
+ schedule or route identities refuse. Construction invokes no callable and
225
+ installs no worker, route or schedule. See the
226
+ [composition contract](../../docs/platform/ARCHITECTURE_AND_EXTENSIONS.md#contributions-seams-and-readiness)
227
+ for the host admission boundary.
228
+
229
+ `./marketing/server` also exports `createMarketingPrivacyContributor` and
230
+ `createMarketingPrivacyBindings`. Explicit enablement and both complete owner
231
+ ports select one contributor; its `exportPersonalData`, `assessErasure` and
232
+ `eraseOrRetain` callables can be passed directly to `createMarketingContribution`.
233
+ Missing ownership makes coverage unavailable and erasure unresolved. Identity
234
+ owns assessment ordering, subscription vetoes, receipt replay and transaction
235
+ rollback; the marketing fence runs only during `eraseOrRetain`. Provider request
236
+ acceptance never proves deletion. The reference leaves marketing unselected,
237
+ so its marketing privacy coverage remains an open gap. See the
238
+ [privacy composition recipe](../../docs/platform/PLATFORM_PACKAGE_REFERENCE.md#marketing-server-composition).
239
+
240
+ The contributor and binding declarations use identity contract types and local
241
+ structural interfaces compatible with identity's `PersonalDataContributor`.
242
+ They do not reference identity's main entry; `./marketing/server` compiles without
243
+ `pg` or `@types/pg`. Select `./marketing/server/postgres` explicitly for those ports.
244
+
101
245
  ## Commerce contracts
102
246
 
103
247
  `./composition` exports the inert `createCommerceContribution` for the installed
@@ -251,7 +395,7 @@ SQL (class (b) retention): native uses 14 days and the contributed managed profi
251
395
  uses 21 days. There is no TypeScript delay parameter or SQL change.
252
396
  The reference browser contract facades initialize their shared Zod instance in
253
397
  jitless mode before loading package schemas, preserving CSP-safe construction.
254
- The package contracts add no global Zod configuration side effect. Browser
398
+ The commerce package contracts add no global Zod configuration side effect. Browser
255
399
  conformance bundles the complete commerce entry and both reference facades
256
400
  without externals; the raw-upload source is a failing browser control, while
257
401
  the complete server entry bundles for Node.
@@ -1041,3 +1185,101 @@ legacy fallback and forward-only migration limits are owned by the
1041
1185
  [M09 migration section](../../docs/platform/DATA_AND_MIGRATIONS.md#m09-invoicing-forward-design-and-control-approval).
1042
1186
 
1043
1187
  OMS read projections are optional. Omitting the host health classifier preserves the original unprojected empty health snapshot (`ok`, no reasons or evidence IDs); it does not evaluate provider health. The reference composition injects its existing classifier and evidence readers.
1188
+
1189
+ ## Account and support contracts
1190
+
1191
+ Experimental `@openlup/platform/account-support` supplies `createAccountReadFacade`
1192
+ and the unchanged account-read diagnostic helpers. Inject account and order owner
1193
+ ports; delegation preserves their arguments, receivers, results, nulls and thrown
1194
+ failures. Authentication, authorization and private profile/market projection stay
1195
+ with the host. Importing this entry selects no driver or capability.
1196
+
1197
+ `account-support/contracts` is type-only and browser-safe. It declares account,
1198
+ Customer 360, self-service command, operator recovery and invoice-access envelopes
1199
+ with explicit capability flags. These declarations do not install their services.
1200
+ The [account/support reference](../../docs/platform/PLATFORM_PACKAGE_REFERENCE.md#account-and-support-contracts)
1201
+ owns the available boundary and later-phase limits.
1202
+
1203
+ R2 adds `readAccountSnapshot` with the two-stage fan-out and a store-level recent
1204
+ 20-order request, stored-money order history/detail, Customer 360 projections
1205
+ and M09 invoice history/PDF delegation. `createInvoiceAccess` checks the requested
1206
+ document against the owned account/order history before resolving its ticket or
1207
+ reading PDF bytes; foreign or unknown documents return `{ kind: "denied" }`. Select pricing, captured line
1208
+ presentation, private extensions and fulfillment evidence through typed host
1209
+ ports. Missing evidence stays unknown; owner refusals retain their distinctions.
1210
+ The default-off reference selections and host-fed read views are unmounted.
1211
+ Native Customer 360 uses the existing authorized PostgreSQL support reader;
1212
+ account/history/invoice drivers still require explicit host selection.
1213
+ Subscription pointer enrichment preserves optional nullable `paymentMethodKind`:
1214
+ selected-empty evidence is null, while unread evidence is omitted. Reference
1215
+ line presentation explicitly picks the declared display keys before projection.
1216
+
1217
+ `createCustomer360ReadFacade({ authorize, journey, summary, diagnostics })`
1218
+ requires `authorize(): Promise<boolean>` before every method's source read.
1219
+ Refused callers receive `{ kind: "denied" }`; authorized delegates preserve
1220
+ arguments, results, nulls and thrown failures. The reference binding supplies
1221
+ that authorization once per call, before opening either support scope.
1222
+
1223
+ The [account/support reference](../../docs/platform/PLATFORM_PACKAGE_REFERENCE.md#account-and-support-contracts)
1224
+ owns the available R1 boundary and later-phase limits.
1225
+
1226
+
1227
+ R3 adds `createSelfServiceCommandFacade({ context, capabilities, ...lanes })`,
1228
+ returning `SelfServiceCommandFacade` with required host capabilities and every
1229
+ managedSubscription, nativeLegacySubscription, subscriptionControl, typed/raw,
1230
+ profile, paymentMethod, commerce and recovery output lane. Input lanes are optional.
1231
+ Unselected methods return `{ supported: false, refusalCode }`; paymentMethod uses
1232
+ the host paymentMethodSetup refusal by identity, commerce uses commerceRecovery,
1233
+ and other lanes use a frozen host_binding_required refusal. Every lane guards
1234
+ the principal; typed/raw lanes require a supplied clientId equal to context.clientId.
1235
+ The trailing `ControlSnapshot = unknown` generic retains the control snapshot type.
1236
+ Native legacy routing preserves
1237
+ explicit pause and ownership before bundle quote validation. Owner results,
1238
+ refusals and nulls retain identity. Supported paymentMethodSetup requires a
1239
+ paymentMethod lane; supported commerceRecovery/configuredPurchase require commerce.
1240
+ Supported genericBundleCommands/commandBoundReceipts require a selected subscription
1241
+ command lane. Missing required lanes refuse customer_self_service_lane_configuration_required.
1242
+ `encodeNativeSubscriptionCommand`, `decodeNativeSubscriptionPreview` and
1243
+ `createNativeSubscriptionDriver` retain the raw owner protocol and apply key;
1244
+ apply never previews. `createPaymentMethodComposition` adapts generic M07
1245
+ setupMethod to paymentMethod.execute without owner imports. Native repair is a
1246
+ [registered follow-up](../../docs/platform/plans/oss-m12-account-support.md#follow-up-register).
1247
+ The default-off reference binding mounts nothing; browser key retention and
1248
+ native profile/start remain unselected.
1249
+
1250
+
1251
+ R4 adds `createOperatorRecovery`, `createManagedOperatorAuthority`,
1252
+ `createPostgresOperatorAuthority`, `operatorAuthorityCapabilities`,
1253
+ `moveIdentityForEmailCorrection`, `executeOperatorAccountLink`, `linkThenApply`
1254
+ and `ACCOUNT_SUPPORT_MIGRATIONS`. The host injects its transaction/RPC and identity
1255
+ ports, verified human operator and recovery-path policy. Recovery token generation
1256
+ and SHA-256 hashing use the runtime Web Crypto API without a Node import; the
1257
+ host may still inject its opaque-token generator. Managed email admission
1258
+ and claim precede identity mutation and settlement. Native lifecycle commands
1259
+ delegate to M10, with actual optional owner receipts and named unavailable
1260
+ subcases. Link-then-action reports a completed link separately when the second
1261
+ command refuses or fails. The reference binding is default-off and unmounted;
1262
+ no import provisions authority or activates a route.
1263
+
1264
+ R5a adds `createAccountSupportBindings` and `createAccountSupportServices` here,
1265
+ and `createAccountSupportContribution` in `/composition`. Supply already bound
1266
+ R1–R4/owner operations for one explicit managed/native graph, host capabilities
1267
+ and a readiness observer. Each distinct callable receives one guard shared by
1268
+ its service, port and route aliases; each entrance re-observes readiness. Disabled
1269
+ construction calls no observer. Refusals are `disabled`, `schema_unknown` and
1270
+ `schema_unsatisfied`; owner results and thrown failures pass through unchanged.
1271
+ A null selected operation remains a required port without an executable binding.
1272
+ The separate injected commerce record uses `commerce(key, ...args)` and returns
1273
+ `{ kind: "unsupported", code: "host_binding_required" }` for a null record/member.
1274
+ The reference host may select real M11 checkout/recovery, ATP and existing effect
1275
+ descriptors by supplying its already-built selection through `commerceOwner`
1276
+ and its existing registry through `commerceRegistry`. R5b does not construct M11
1277
+ or import its adapters; the host supplies the complete account/M11/ATP schema
1278
+ and matching enablement/readiness. Keep capability flags unsupported until
1279
+ their owner callables are bound. This adds no package export or owner import to
1280
+ account-support contracts. One M11 result is forwarded without rewrapping its
1281
+ guarded services; unknown stock, unsupported options and handler outcomes retain
1282
+ their owner meaning. Contribution descriptors install no routes, handlers,
1283
+ schedules or workers. See the
1284
+ [reference recipe](../../docs/platform/RUNTIME_AND_SELF_HOSTING.md#opt-in-disposable-subscription-reference)
1285
+ for the host's schema and transport obligations.
@@ -0,0 +1,8 @@
1
+ import type { AccountReadPort } from "./contracts/index.js";
2
+ /** Pure delegation to selected owner reads. Authorization, defaults, diagnostics,
3
+ * private fields and transport refusal mapping remain with the injected owners.
4
+ */
5
+ export declare function createAccountReadFacade<Account, OrderList, OrderDetail>(ports: {
6
+ account: Pick<AccountReadPort<Account, OrderList, OrderDetail>, "getAccount">;
7
+ orders: Pick<AccountReadPort<Account, OrderList, OrderDetail>, "listOrders" | "getOrderDetail">;
8
+ }): AccountReadPort<Account, OrderList, OrderDetail>;
@@ -0,0 +1,10 @@
1
+ /** Pure delegation to selected owner reads. Authorization, defaults, diagnostics,
2
+ * private fields and transport refusal mapping remain with the injected owners.
3
+ */
4
+ export function createAccountReadFacade(ports) {
5
+ return {
6
+ getAccount(userId) { return ports.account.getAccount(userId); },
7
+ listOrders(userId, input) { return ports.orders.listOrders(userId, input); },
8
+ getOrderDetail(userId, orderId) { return ports.orders.getOrderDetail(userId, orderId); },
9
+ };
10
+ }
@@ -0,0 +1,69 @@
1
+ import type { AccountActionRequired, AccountSnapshot, AccountSubscription, AccountSubscriptionLine, AccountOrderSummary } from "./contracts/account.js";
2
+ import type { SubscriptionPaymentMethodStatus } from "./contracts/commands.js";
3
+ export declare const CUSTOMER_ACCOUNT_V2_CONTRACT_VERSION: "customer.account.v3";
4
+ type Row = Record<string, unknown>;
5
+ export interface CustomerSubscriptionEligibilityInput {
6
+ subscriptionId: string;
7
+ status: AccountSubscription["status"];
8
+ nextCycleAt: string | null;
9
+ editCutoffAt: string | null;
10
+ paymentMethodKind: string | null;
11
+ paymentMethodRefPresent: boolean;
12
+ paymentMethodStatus?: SubscriptionPaymentMethodStatus;
13
+ }
14
+ export interface CustomerSubscriptionEligibility {
15
+ canEdit: boolean;
16
+ reason: AccountSubscription["editBlockedReason"];
17
+ }
18
+ export interface SubscriptionActionState {
19
+ subscriptionId: string;
20
+ orderId: string | null;
21
+ blockedReason: AccountActionRequired["blockedReason"];
22
+ failureCause: AccountActionRequired["failureCause"];
23
+ recoveryEligible: boolean;
24
+ dueAt: string | null;
25
+ nextRetryAt: string | null;
26
+ }
27
+ export interface AccountReadSources<Extension, ChargeEvidence = AccountSubscription["nextCharge"], PaymentEvidence = unknown> {
28
+ readExtension(clientId: string): Promise<Extension>;
29
+ /** The selected store applies the bound BEFORE visibility filtering. */
30
+ readSubscriptionRows(clientId: string, limit: number): Promise<Row[]>;
31
+ readAddresses(clientId: string): Promise<AccountSnapshot["addresses"]>;
32
+ readOrdererProfiles(clientId: string): Promise<AccountSnapshot["ordererProfiles"]>;
33
+ readPaymentPreferences(clientId: string): Promise<AccountSnapshot["paymentPreferences"]>;
34
+ readDeliveryPreferences(clientId: string): Promise<AccountSnapshot["deliveryPreferences"]>;
35
+ readOrders(clientId: string, limit: number): Promise<{
36
+ orders: AccountOrderSummary[];
37
+ }>;
38
+ readEvents(clientId: string): Promise<AccountSnapshot["events"]>;
39
+ readSubscriptionLines(ids: string[]): Promise<Map<string, AccountSubscriptionLine[]>>;
40
+ readSubscriptionBlockers(ids: string[], nextCycles: Map<string, string | null>): Promise<Map<string, NonNullable<AccountSubscription["editBlockedReason"]>>>;
41
+ readPauseWindows(ids: string[]): Promise<Map<string, Pick<AccountSubscription, "pausePreset" | "pauseStartedAt" | "pauseEndsAt">>>;
42
+ readPaymentEvidence(ids: string[]): Promise<Map<string, PaymentEvidence>>;
43
+ /** Owner interprets M08 refusal; unsupported MUST throw, never return an empty Map. */
44
+ readDeliveryAlignments(nextCycles: Map<string, string | null>): Promise<Map<string, {
45
+ state: "protected" | "aligned";
46
+ }>>;
47
+ readNextCharges(rows: Row[]): Promise<Map<string, ChargeEvidence>>;
48
+ readActionStates(ids: string[]): Promise<Map<string, SubscriptionActionState>>;
49
+ }
50
+ export interface AccountReadProjectionPolicy<ChargeEvidence = AccountSubscription["nextCharge"], PaymentEvidence = unknown> {
51
+ paymentMethodStatus(input: {
52
+ clientId: string;
53
+ clientEmail: string | null;
54
+ row: Row;
55
+ evidence: PaymentEvidence | undefined;
56
+ }): SubscriptionPaymentMethodStatus;
57
+ canUsePaymentMethodForRenewal(status: SubscriptionPaymentMethodStatus): boolean;
58
+ packageSummary(lines: AccountSubscriptionLine[], constraint: unknown): string | null;
59
+ /** Pricing authority selects payable-cycle/acquisition shipping precedence. */
60
+ withNextCharge(recurring: AccountSubscription["recurringPrice"], next: ChargeEvidence | undefined): Pick<AccountSubscription, "recurringPrice" | "nextCharge">;
61
+ }
62
+ /** Two observation stages, including the original nested subscription fan-out. Auth/ownership precedes this call. */
63
+ export declare function readAccountSnapshot<Extension, ChargeEvidence, PaymentEvidence>(sources: AccountReadSources<Extension, ChargeEvidence, PaymentEvidence>, policy: AccountReadProjectionPolicy<ChargeEvidence, PaymentEvidence>, client: Row): Promise<AccountSnapshot<Extension>>;
64
+ export declare function isCustomerVisibleSubscription(row: Row): boolean;
65
+ export declare function recurringPrice(lines: AccountSubscriptionLine[]): AccountSubscription["recurringPrice"];
66
+ export declare function editCutoff(nextCycleAt: string | null, editWindowHours: number | null): string | null;
67
+ export declare function computeEditState(input: CustomerSubscriptionEligibilityInput, blockers: ReadonlyMap<string, NonNullable<AccountSubscription["editBlockedReason"]>>, canUse: AccountReadProjectionPolicy["canUsePaymentMethodForRenewal"]): CustomerSubscriptionEligibility;
68
+ export declare function buildActionRequired(subscriptions: AccountSubscription[], orders: AccountOrderSummary[], states: Map<string, SubscriptionActionState> | undefined, canUse: AccountReadProjectionPolicy["canUsePaymentMethodForRenewal"]): AccountActionRequired[];
69
+ export {};