@wildo-ai/saas-website 1.1.5 → 1.1.6

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 (182) hide show
  1. package/dist/esm/astro/blog-post-bridge.d.ts +9 -0
  2. package/dist/esm/astro/blog-post-bridge.d.ts.map +1 -1
  3. package/dist/esm/astro/blog-post-bridge.js +10 -5
  4. package/dist/esm/astro/blog-post-bridge.js.map +1 -1
  5. package/dist/esm/astro/bridge-runtime.d.ts +25 -6
  6. package/dist/esm/astro/bridge-runtime.d.ts.map +1 -1
  7. package/dist/esm/astro/bridge-runtime.js +10 -6
  8. package/dist/esm/astro/bridge-runtime.js.map +1 -1
  9. package/dist/esm/astro/label-pack-loader.d.ts +4 -4
  10. package/dist/esm/astro/label-pack-loader.d.ts.map +1 -1
  11. package/dist/esm/astro/label-pack-loader.js +9 -4
  12. package/dist/esm/astro/label-pack-loader.js.map +1 -1
  13. package/dist/esm/astro/robots-renderer.d.ts +9 -8
  14. package/dist/esm/astro/robots-renderer.d.ts.map +1 -1
  15. package/dist/esm/astro/robots-renderer.js +15 -15
  16. package/dist/esm/astro/robots-renderer.js.map +1 -1
  17. package/dist/esm/astro/website-page-head.renderer.d.ts +1 -1
  18. package/dist/esm/astro/website-page-head.renderer.d.ts.map +1 -1
  19. package/dist/esm/astro/website-page-head.renderer.js +2 -1
  20. package/dist/esm/astro/website-page-head.renderer.js.map +1 -1
  21. package/dist/esm/astro/website-site-context.d.ts +5 -2
  22. package/dist/esm/astro/website-site-context.d.ts.map +1 -1
  23. package/dist/esm/astro/website-site-context.js.map +1 -1
  24. package/dist/esm/companion-exports.d.ts +8 -15
  25. package/dist/esm/companion-exports.d.ts.map +1 -1
  26. package/dist/esm/companion-exports.js +8 -15
  27. package/dist/esm/companion-exports.js.map +1 -1
  28. package/dist/esm/config/define-website-config.d.ts +3 -2
  29. package/dist/esm/config/define-website-config.d.ts.map +1 -1
  30. package/dist/esm/config/define-website-config.js +10 -10
  31. package/dist/esm/config/define-website-config.js.map +1 -1
  32. package/dist/esm/config/load-website-config.d.ts +6 -0
  33. package/dist/esm/config/load-website-config.d.ts.map +1 -1
  34. package/dist/esm/config/load-website-config.js +18 -9
  35. package/dist/esm/config/load-website-config.js.map +1 -1
  36. package/dist/esm/config/load-website-pricing-catalog.d.ts +13 -0
  37. package/dist/esm/config/load-website-pricing-catalog.d.ts.map +1 -0
  38. package/dist/esm/config/load-website-pricing-catalog.js +34 -0
  39. package/dist/esm/config/load-website-pricing-catalog.js.map +1 -0
  40. package/dist/esm/config/load-website-site-context.d.ts +53 -0
  41. package/dist/esm/config/load-website-site-context.d.ts.map +1 -0
  42. package/dist/esm/config/load-website-site-context.js +98 -0
  43. package/dist/esm/config/load-website-site-context.js.map +1 -0
  44. package/dist/esm/config-loader.d.ts +2 -0
  45. package/dist/esm/config-loader.d.ts.map +1 -1
  46. package/dist/esm/config-loader.js +2 -0
  47. package/dist/esm/config-loader.js.map +1 -1
  48. package/dist/esm/core/anonymous-session/InboundContactForm.d.ts +26 -6
  49. package/dist/esm/core/anonymous-session/InboundContactForm.d.ts.map +1 -1
  50. package/dist/esm/core/anonymous-session/InboundContactForm.js +51 -33
  51. package/dist/esm/core/anonymous-session/InboundContactForm.js.map +1 -1
  52. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts +11 -0
  53. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts.map +1 -1
  54. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js +15 -4
  55. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js.map +1 -1
  56. package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts +14 -2
  57. package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts.map +1 -1
  58. package/dist/esm/core/anonymous-session/website-anonymous-session-client.js +34 -4
  59. package/dist/esm/core/anonymous-session/website-anonymous-session-client.js.map +1 -1
  60. package/dist/esm/core/anonymous-session/website-submission-challenge.d.ts +36 -0
  61. package/dist/esm/core/anonymous-session/website-submission-challenge.d.ts.map +1 -0
  62. package/dist/esm/core/anonymous-session/website-submission-challenge.js +69 -0
  63. package/dist/esm/core/anonymous-session/website-submission-challenge.js.map +1 -0
  64. package/dist/esm/core/consent/WebsiteConsentBanner.d.ts.map +1 -1
  65. package/dist/esm/core/consent/WebsiteConsentBanner.js +11 -10
  66. package/dist/esm/core/consent/WebsiteConsentBanner.js.map +1 -1
  67. package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts +25 -5
  68. package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts.map +1 -1
  69. package/dist/esm/core/contexts/WebsiteRuntimeContext.js.map +1 -1
  70. package/dist/esm/core/contexts/useWebsiteRuntime.d.ts +18 -0
  71. package/dist/esm/core/contexts/useWebsiteRuntime.d.ts.map +1 -1
  72. package/dist/esm/core/contexts/useWebsiteRuntime.js +28 -2
  73. package/dist/esm/core/contexts/useWebsiteRuntime.js.map +1 -1
  74. package/dist/esm/core/external-providers/WebsiteProviderComponent.d.ts +57 -0
  75. package/dist/esm/core/external-providers/WebsiteProviderComponent.d.ts.map +1 -0
  76. package/dist/esm/core/external-providers/WebsiteProviderComponent.js +56 -0
  77. package/dist/esm/core/external-providers/WebsiteProviderComponent.js.map +1 -0
  78. package/dist/esm/core/external-providers/provider-component-registry.website.d.ts +63 -0
  79. package/dist/esm/core/external-providers/provider-component-registry.website.d.ts.map +1 -0
  80. package/dist/esm/core/external-providers/provider-component-registry.website.js +68 -0
  81. package/dist/esm/core/external-providers/provider-component-registry.website.js.map +1 -0
  82. package/dist/esm/core/external-providers/useWebsiteProviderComponent.d.ts +36 -0
  83. package/dist/esm/core/external-providers/useWebsiteProviderComponent.d.ts.map +1 -0
  84. package/dist/esm/core/external-providers/useWebsiteProviderComponent.js +59 -0
  85. package/dist/esm/core/external-providers/useWebsiteProviderComponent.js.map +1 -0
  86. package/dist/esm/core/external-providers/useWebsiteProviderScripts.d.ts +15 -5
  87. package/dist/esm/core/external-providers/useWebsiteProviderScripts.d.ts.map +1 -1
  88. package/dist/esm/core/external-providers/useWebsiteProviderScripts.js +39 -24
  89. package/dist/esm/core/external-providers/useWebsiteProviderScripts.js.map +1 -1
  90. package/dist/esm/core/external-providers/website-provider-sdk-activations.d.ts +11 -0
  91. package/dist/esm/core/external-providers/website-provider-sdk-activations.d.ts.map +1 -0
  92. package/dist/esm/core/external-providers/website-provider-sdk-activations.js +14 -0
  93. package/dist/esm/core/external-providers/website-provider-sdk-activations.js.map +1 -0
  94. package/dist/esm/core/factories/define-website-section.d.ts +3 -3
  95. package/dist/esm/core/factories/define-website-section.js +3 -3
  96. package/dist/esm/core/factories/define-website-section.js.map +1 -1
  97. package/dist/esm/core/layouts/WebsitePageLayout.d.ts.map +1 -1
  98. package/dist/esm/core/layouts/WebsitePageLayout.js +10 -7
  99. package/dist/esm/core/layouts/WebsitePageLayout.js.map +1 -1
  100. package/dist/esm/index.d.ts +30 -65
  101. package/dist/esm/index.d.ts.map +1 -1
  102. package/dist/esm/index.js +30 -65
  103. package/dist/esm/index.js.map +1 -1
  104. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts +35 -6
  105. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts.map +1 -1
  106. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js +39 -5
  107. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js.map +1 -1
  108. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.d.ts +32 -0
  109. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.d.ts.map +1 -0
  110. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.js +36 -0
  111. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.js.map +1 -0
  112. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts +6 -5
  113. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts.map +1 -1
  114. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js +8 -7
  115. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js.map +1 -1
  116. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts +14 -7
  117. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts.map +1 -1
  118. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js +14 -7
  119. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js.map +1 -1
  120. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.d.ts +57 -0
  121. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.d.ts.map +1 -0
  122. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.js +76 -0
  123. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.js.map +1 -0
  124. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts +23 -0
  125. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts.map +1 -1
  126. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js +20 -2
  127. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js.map +1 -1
  128. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts +7 -5
  129. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts.map +1 -1
  130. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js.map +1 -1
  131. package/dist/tsconfig.build.tsbuildinfo +1 -1
  132. package/package.json +5 -5
  133. package/src/__tests__/bundle-isolation.test.ts +19 -22
  134. package/src/astro/__tests__/blog-post-bridge.test.tsx +18 -2
  135. package/src/astro/__tests__/bridge-runtime.test.tsx +21 -3
  136. package/src/astro/__tests__/label-pack-loader.test.ts +7 -4
  137. package/src/astro/blog-post-bridge.tsx +19 -5
  138. package/src/astro/bridge-runtime.tsx +35 -11
  139. package/src/astro/label-pack-loader.ts +8 -4
  140. package/src/astro/robots-renderer.ts +15 -15
  141. package/src/astro/website-page-head.renderer.ts +2 -2
  142. package/src/astro/website-site-context.ts +5 -2
  143. package/src/companion-exports.ts +8 -15
  144. package/src/config/__tests__/website-build-origins.test.ts +52 -0
  145. package/src/config/define-website-config.ts +10 -10
  146. package/src/config/load-website-config.ts +25 -14
  147. package/src/config/load-website-pricing-catalog.ts +52 -0
  148. package/src/config/load-website-site-context.ts +145 -0
  149. package/src/config-loader.ts +2 -0
  150. package/src/core/__tests__/contexts.test.tsx +20 -1
  151. package/src/core/__tests__/website-consent.test.tsx +2 -1
  152. package/src/core/anonymous-session/InboundContactForm.tsx +100 -45
  153. package/src/core/anonymous-session/__tests__/InboundContactForm.labels.test.tsx +108 -0
  154. package/src/core/anonymous-session/__tests__/InboundContactForm.submission-challenge.test.tsx +139 -0
  155. package/src/core/anonymous-session/inbound-contact-form.schema.ts +16 -4
  156. package/src/core/anonymous-session/website-anonymous-session-client.ts +39 -4
  157. package/src/core/anonymous-session/website-submission-challenge.ts +99 -0
  158. package/src/core/consent/WebsiteConsentBanner.tsx +11 -10
  159. package/src/core/contexts/WebsiteRuntimeContext.tsx +25 -5
  160. package/src/core/contexts/useWebsiteRuntime.ts +33 -2
  161. package/src/core/external-providers/WebsiteProviderComponent.tsx +153 -0
  162. package/src/core/external-providers/__tests__/frontend-provider-registry.website.test.ts +4 -0
  163. package/src/core/external-providers/__tests__/website-provider-component.test.tsx +238 -0
  164. package/src/core/external-providers/__tests__/website-provider-sdks.test.tsx +72 -0
  165. package/src/core/external-providers/provider-component-registry.website.ts +115 -0
  166. package/src/core/external-providers/useWebsiteProviderComponent.ts +76 -0
  167. package/src/core/external-providers/useWebsiteProviderScripts.ts +56 -37
  168. package/src/core/external-providers/website-provider-sdk-activations.ts +23 -0
  169. package/src/core/factories/define-website-section.ts +3 -3
  170. package/src/core/layouts/WebsitePageLayout.tsx +11 -6
  171. package/src/index.ts +31 -65
  172. package/src/schemas/__tests__/design-token-css-property.test.ts +72 -0
  173. package/src/schemas/__tests__/pricing-offer-structured-data.test.ts +122 -0
  174. package/src/schemas/__tests__/structured-data-reconciliation.test.ts +35 -0
  175. package/src/schemas/design-tokens/website-design-tokens.shared.schemas.ts +45 -5
  176. package/src/schemas/label-keys/__tests__/scaffolded-consent-label-pack.parity.test.ts +12 -0
  177. package/src/schemas/label-keys/website-provider-component-label-keys.schemas.ts +40 -0
  178. package/src/schemas/manifests/website-root-config.shared.schemas.ts +10 -9
  179. package/src/schemas/sections/website-section-definition.shared.schemas.ts +14 -7
  180. package/src/schemas/structured-data/pricing-offer-structured-data.shared.ts +144 -0
  181. package/src/schemas/structured-data/structured-data-reconciliation.shared.ts +46 -1
  182. package/src/schemas/structured-data/website-structured-data.shared.schemas.ts +7 -5
@@ -1,7 +1,8 @@
1
1
  import React, { type ComponentType, type ReactNode } from 'react';
2
- import type { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';
2
+ import type { AvailableLanguage, PublicPricingCatalog } from '@wildo-ai/saas-models/public-runtime';
3
3
  import type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';
4
4
  import type { FrontendWebsiteProviderRegistry } from '../external-providers/frontend-provider-registry.website';
5
+ import type { WebsiteProviderComponentRegistry } from '../external-providers/provider-component-registry.website';
5
6
  import type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';
6
7
  import type { WebsiteNavigationConfig } from '../../schemas/manifests/website-root-config.shared.schemas';
7
8
  import type { LabelPack } from '../../schemas/validators/label-pack.validator';
@@ -9,10 +10,10 @@ import type { LabelPack } from '../../schemas/validators/label-pack.validator';
9
10
  * @wildo_source:part:start saas.website.runtime.context facet:layer:core facet:family:website
10
11
  *
11
12
  * `WebsiteRuntimeContext` — site-wide runtime state for the marketing
12
- * surface. Created **once per page render** by the host adapter
13
- * (Phase 5 `WebsitePageBridge.astro` reads `WebsiteRootConfig` and the
14
- * resolved label pack from disk and calls
15
- * `<WebsiteRuntimeContextProvider value={…}>` around the page tree).
13
+ * surface. Created **once per page render** by the host adapter: the
14
+ * page's `.astro` frontmatter loads the site context and the resolved label
15
+ * pack, and its bridge island (`createWebsitePageBridgeIsland`) calls
16
+ * `<WebsiteRuntimeContextProvider value={…}>` around the page tree.
16
17
  *
17
18
  * **Why "runtime" and not "config"**: the values here are the
18
19
  * locale-resolved subset of `WebsiteRootConfig` — only the active
@@ -149,6 +150,14 @@ export interface WebsiteRuntimeContextValue {
149
150
  * catalog for analytics / captcha / browser-monitoring slices.
150
151
  */
151
152
  frontendProviderRegistry?: FrontendWebsiteProviderRegistry;
153
+ /**
154
+ * Components the live providers contribute, keyed `capability:providerRef` (#1703) — the same
155
+ * registry the application builds, from the same `components` declaration. Built by the page bridge
156
+ * once per island from `frontendProviderRegistry`; read through `useWebsiteProviderComponent` and
157
+ * rendered by `WebsiteProviderComponent`. Optional for the same reason as the registry above: a
158
+ * provider-free site, or a test runtime, has none, and every slot then renders nothing.
159
+ */
160
+ providerComponentRegistry?: WebsiteProviderComponentRegistry;
152
161
  /**
153
162
  * Replaces the framework's visitor consent panel (#534). Reads `useWebsiteConsent()`; see
154
163
  * `WebsiteConsentBanner` for the three properties a replacement must keep. Absent uses the default.
@@ -170,6 +179,17 @@ export interface WebsiteRuntimeContextValue {
170
179
  * silently failing to submit.
171
180
  */
172
181
  apiOrigin?: string;
182
+ /**
183
+ * The application's public pricing catalogue (#1835), derived at build time from the billing
184
+ * catalogue the backend sells from — so a pricing section states the prices the application
185
+ * actually charges instead of a hand copy of them. Node-loaded
186
+ * (`loadWebsitePricingCatalog` on `/config-loader`) and carried as an island prop for the
187
+ * reason `appOrigin` above is. Read it with `useWebsitePricingCatalog()`.
188
+ *
189
+ * Optional because only pricing pages need it; a section that reads it on a page that did not
190
+ * pass it fails loudly rather than rendering no plans.
191
+ */
192
+ pricingCatalog?: PublicPricingCatalog;
173
193
  }
174
194
  /**
175
195
  * Bare React context. Default `null` — `useWebsiteRuntime()` throws
@@ -1 +1 @@
1
- {"version":3,"file":"WebsiteRuntimeContext.d.ts","sourceRoot":"","sources":["../../../../../src/core/contexts/WebsiteRuntimeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAiB,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAE9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kEAAkE,CAAC;AAC5G,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,0DAA0D,CAAC;AAChH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oDAAoD,CAAC;AAC1F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4DAA4D,CAAC;AAC1G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;;;;OASG;IACH,aAAa,EAAE,iBAAiB,CAAC;IACjC;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,EAAE,SAAS,CAAC;IACrB;;;;;OAKG;IACH,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;;OAMG;IACH,UAAU,EAAE,uBAAuB,CAAC;IACpC;;;;;;;;;;;;;;;OAeG;IACH,yBAAyB,EAAE,eAAe,CAAC;IAC3C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,+BAA+B,CAAC;IAC3D;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,aAAa,CAAC;IACvC;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAC3B,CAAC;AAEzD,MAAM,WAAW,kCAAkC;IACjD,KAAK,EAAE,0BAA0B,CAAC;IAClC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GACT,EAAE,kCAAkC,GAAG,SAAS,CAMhD;yBATe,6BAA6B;;;AAW7C,0DAA0D"}
1
+ {"version":3,"file":"WebsiteRuntimeContext.d.ts","sourceRoot":"","sources":["../../../../../src/core/contexts/WebsiteRuntimeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAiB,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEpG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kEAAkE,CAAC;AAC5G,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,0DAA0D,CAAC;AAChH,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,2DAA2D,CAAC;AAClH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oDAAoD,CAAC;AAC1F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4DAA4D,CAAC;AAC1G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;;;;OASG;IACH,aAAa,EAAE,iBAAiB,CAAC;IACjC;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,EAAE,SAAS,CAAC;IACrB;;;;;OAKG;IACH,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;;OAMG;IACH,UAAU,EAAE,uBAAuB,CAAC;IACpC;;;;;;;;;;;;;;;OAeG;IACH,yBAAyB,EAAE,eAAe,CAAC;IAC3C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,+BAA+B,CAAC;IAC3D;;;;;;OAMG;IACH,yBAAyB,CAAC,EAAE,gCAAgC,CAAC;IAC7D;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,aAAa,CAAC;IACvC;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAC3B,CAAC;AAEzD,MAAM,WAAW,kCAAkC;IACjD,KAAK,EAAE,0BAA0B,CAAC;IAClC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GACT,EAAE,kCAAkC,GAAG,SAAS,CAMhD;yBATe,6BAA6B;;;AAW7C,0DAA0D"}
@@ -1 +1 @@
1
- {"version":3,"file":"WebsiteRuntimeContext.js","sourceRoot":"","sources":["../../../../../src/core/contexts/WebsiteRuntimeContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAsC,MAAM,OAAO,CAAC;AAiLjF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,aAAa,CAAoC,IAAI,CAAC,CAAC;AAOzD;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GAC2B;IACnC,OAAO,CACL,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACzC,QAAQ,GACsB,CAClC,CAAC;AACJ,CAAC;AACD,6BAA6B,CAAC,WAAW,GAAG,+BAA+B,CAAC","sourcesContent":["import React, { createContext, type ComponentType, type ReactNode } from 'react';\n\nimport type { AvailableLanguage } from '@wildo-ai/saas-models/public-runtime';\n\nimport type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';\nimport type { FrontendWebsiteProviderRegistry } from '../external-providers/frontend-provider-registry.website';\nimport type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';\nimport type { WebsiteNavigationConfig } from '../../schemas/manifests/website-root-config.shared.schemas';\nimport type { LabelPack } from '../../schemas/validators/label-pack.validator';\n\n/**\n * @wildo_source:part:start saas.website.runtime.context facet:layer:core facet:family:website\n *\n * `WebsiteRuntimeContext` — site-wide runtime state for the marketing\n * surface. Created **once per page render** by the host adapter\n * (Phase 5 `WebsitePageBridge.astro` reads `WebsiteRootConfig` and the\n * resolved label pack from disk and calls\n * `<WebsiteRuntimeContextProvider value={…}>` around the page tree).\n *\n * **Why \"runtime\" and not \"config\"**: the values here are the\n * locale-resolved subset of `WebsiteRootConfig` — only the active\n * locale's label pack travels with the React tree (the other locales\n * live in their own per-locale static builds). A `*Config` name would\n * suggest the full multi-locale surface is in scope.\n *\n * **Three pieces of state**:\n *\n * - `locale` — the currently-rendering locale. Sections that need\n * locale-aware formatting (number/date in marketing copy is rare\n * but legitimate) read it via `useWebsiteRuntime()`.\n * - `labelPack` — the locale-resolved flat key→string map, validated\n * against the manifest by `validateLabelPackAgainstManifest` at\n * build start. Consumed by `useWebsiteLabel` and\n * `useWebsiteLabelByKey`.\n * - `designTokens` — the `WebsiteDesignTokens` from\n * `WebsiteRootConfig.designTokens`. Consumed by\n * `useWebsiteDesignTokens` and by the Phase 5 CSS emitter that\n * materializes them as `--website-*` custom properties on the\n * `<WebsitePageLayout>` root.\n * - `navigation` — the `WebsiteNavigationConfig` from\n * `WebsiteRootConfig.navigation`. Carried in the runtime context\n * (rather than as a separate `WebsiteNavigationContext`) because\n * `<WebsitePageLayout>` already reads runtime state and\n * header/footer slots are inseparable from \"the site is rendering\n * right now\". A second context for two component refs would split\n * the host-adapter's wiring surface without buying isolation.\n * - `frontendProviderRegistry` — optional website-facing public provider\n * registry hydrated from the materialized provider artifact for the\n * concrete `STATIC_WEBSITE` service. This keeps analytics / captcha /\n * browser-monitoring integrations on the same frontend-provider\n * contract the SaaS app now uses, instead of inventing a website-only\n * metadata seam.\n *\n * **Why the hook lives in a separate file**: React Fast Refresh only\n * preserves state for a module whose every export is a component, so\n * a module mixing components with plain functions loses its HMR\n * boundary. This file holds the two things that must be identical\n * objects at runtime — the context and the provider component that\n * writes it — while `useWebsiteRuntime` sits alone in\n * `useWebsiteRuntime.ts`. A section author editing a component that\n * merely READS the runtime therefore never remounts the provider.\n *\n * Until 2026-09-09 this paragraph described a different arrangement:\n * that only the bare context was kept here and the provider lived in\n * a file of its own. No such file has ever existed — the provider is\n * exported below — and splitting it out would be the wrong shape\n * anyway, since `useContext` matches on object identity.\n * prose-referent-waiver: the retired file name is quoted only to retire it.\n * The claim named `WebsiteRuntimeContextProvider.tsx`.\n */\nexport interface WebsiteRuntimeContextValue {\n /**\n * The currently-rendering locale. Marketing-site routing emits one\n * static build per locale (D8), so this value is constant per build\n * — never re-renders mid-session.\n */\n locale: AvailableLanguage;\n /**\n * The site's default locale (mirrors `WebsiteRootConfig.defaultLocale`).\n * Carried in the runtime context so client-tier components — namely\n * `WebsiteInternalLink` (Phase 6 fix H-β) — can compute the correct\n * locale-prefixed pathname (`/pricing` on the EN site,\n * `/fr/pricing` on the FR site) without re-importing the root\n * config. Plumbing it through the runtime keeps the routing rule\n * a framework-internal concern: section authors NEVER hand-prefix\n * paths.\n */\n defaultLocale: AvailableLanguage;\n /**\n * Origin of the application this marketing site sends visitors INTO — the\n * marketing → product handoff target, authored once as\n * `WildoMarketingWebsiteConfig.appOrigin` (#493).\n *\n * Carried here for exactly the reason `defaultLocale` above is: a\n * `wildo.website.config.ts` is Node-loaded and therefore invisible to a\n * client island, so before this a site resolved the app origin a SECOND\n * time from a public build-time environment variable it could read in the\n * browser — one host authored twice, in two files, with no mechanical link\n * between the copies. That is how a marketing site comes to point at the\n * wrong environment: a defect nobody notices until a customer follows the\n * link.\n *\n * Threading it through the runtime keeps the handoff a framework-internal\n * concern, the same way threading `defaultLocale` kept locale-prefixing one:\n * section authors never hand-assemble the product URL, and there is one\n * place to change it.\n */\n appOrigin?: string;\n /**\n * Flat `Record<string, string>` label pack for the active locale.\n * Lookup keys MUST be fully-composed `website.<page>.<section>.<slot>`\n * strings; consumers that hold leaf paths use `useWebsiteLabel(leaf)`\n * which composes the full key against the page+section context.\n */\n labelPack: LabelPack;\n /**\n * Design-token bundle for the active site. Same object referenced\n * by `WebsiteRootConfig.designTokens`; passed by reference (not\n * cloned) so token-aware components can rely on referential\n * stability across renders.\n */\n designTokens: WebsiteDesignTokens;\n /**\n * Site-wide navigation slot bindings (header / footer components).\n * Same object referenced by `WebsiteRootConfig.navigation`. Read\n * by `<WebsitePageLayout>` to render the chrome around each page's\n * `<main>` content; per-page `header` / `footer` props on\n * `<WebsitePageLayout>` override these defaults.\n */\n navigation: WebsiteNavigationConfig;\n /**\n * Fully-composed label key the framework reads to render the\n * \"Skip to main content\" affordance as the FIRST focusable element\n * on every page (Phase 6 third audit fix M-α). Mirrors\n * `WebsiteRootConfig.skipToMainContentLabelKey`. Carried in the\n * runtime context (NOT re-derived from the root config inside\n * `WebsitePageLayout`) for two reasons:\n * - The layout is a client-tier React component; it cannot import\n * the consumer's `WEBSITE_ROOT_CONFIG` symbol without dragging\n * server-only code (manifest registry, page components) into\n * the client bundle.\n * - Threading the key through the runtime keeps the layout's\n * contract symmetric with how every other localized text on the\n * page is sourced (label pack + key), so the skip link is\n * translated automatically without any per-locale branching.\n */\n skipToMainContentLabelKey: WebsiteLabelKey;\n /**\n * Website-facing public providers for the active static website\n * service. Optional so older tests and provider-free sites can omit\n * it, but when present it is the canonical frontend-safe provider\n * catalog for analytics / captcha / browser-monitoring slices.\n */\n frontendProviderRegistry?: FrontendWebsiteProviderRegistry;\n /**\n * Replaces the framework's visitor consent panel (#534). Reads `useWebsiteConsent()`; see\n * `WebsiteConsentBanner` for the three properties a replacement must keep. Absent uses the default.\n * Closed over by the bridge rather than passed as an island prop, like `navigation`, because a\n * component cannot cross Astro's serialization boundary.\n */\n consentBannerComponent?: ComponentType;\n /**\n * Backend API origin (WITHOUT a trailing slash) that anonymous-capture\n * sections POST to when constructing a `WebsiteAnonymousSessionClient`\n * (lead / draft-note forms). Sourced from\n * `WildoMarketingWebsiteConfig.apiOrigin` and passed as a\n * JSON-serializable island prop (the `.astro` page resolves the\n * per-environment value and forwards it).\n *\n * Optional because only pages that host an anonymous-capture section\n * need it — brochure pages omit it. A capture section that reads\n * `undefined` here surfaces a loud misconfiguration rather than\n * silently failing to submit.\n */\n apiOrigin?: string;\n}\n\n/**\n * Bare React context. Default `null` — `useWebsiteRuntime()` throws\n * with a clear error message when invoked outside of\n * `<WebsiteRuntimeContextProvider>`. The defensive throw is preferred\n * over a silent default value so a missing provider is detected at\n * the first hook call rather than at render time when a missing\n * label silently renders as the key string.\n */\nexport const WebsiteRuntimeContext: React.Context<WebsiteRuntimeContextValue | null> =\n createContext<WebsiteRuntimeContextValue | null>(null);\n\nexport interface WebsiteRuntimeContextProviderProps {\n value: WebsiteRuntimeContextValue;\n children: ReactNode;\n}\n\n/**\n * Provider component. Authored as a thin wrapper so consumers do NOT\n * have to import `WebsiteRuntimeContext.Provider` directly — the\n * provider component carries the documented authoring API and is the\n * Fast-Refresh-stable surface section authors compose against.\n */\nexport function WebsiteRuntimeContextProvider({\n value,\n children,\n}: WebsiteRuntimeContextProviderProps): ReactNode {\n return (\n <WebsiteRuntimeContext.Provider value={value}>\n {children}\n </WebsiteRuntimeContext.Provider>\n );\n}\nWebsiteRuntimeContextProvider.displayName = 'WebsiteRuntimeContextProvider';\n/** @wildo_source:part:end saas.website.runtime.context */\n"]}
1
+ {"version":3,"file":"WebsiteRuntimeContext.js","sourceRoot":"","sources":["../../../../../src/core/contexts/WebsiteRuntimeContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAsC,MAAM,OAAO,CAAC;AAqMjF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,aAAa,CAAoC,IAAI,CAAC,CAAC;AAOzD;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAC5C,KAAK,EACL,QAAQ,GAC2B;IACnC,OAAO,CACL,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACzC,QAAQ,GACsB,CAClC,CAAC;AACJ,CAAC;AACD,6BAA6B,CAAC,WAAW,GAAG,+BAA+B,CAAC","sourcesContent":["import React, { createContext, type ComponentType, type ReactNode } from 'react';\n\nimport type { AvailableLanguage, PublicPricingCatalog } from '@wildo-ai/saas-models/public-runtime';\n\nimport type { WebsiteDesignTokens } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';\nimport type { FrontendWebsiteProviderRegistry } from '../external-providers/frontend-provider-registry.website';\nimport type { WebsiteProviderComponentRegistry } from '../external-providers/provider-component-registry.website';\nimport type { WebsiteLabelKey } from '../../schemas/label-keys/website-label-key.schemas';\nimport type { WebsiteNavigationConfig } from '../../schemas/manifests/website-root-config.shared.schemas';\nimport type { LabelPack } from '../../schemas/validators/label-pack.validator';\n\n/**\n * @wildo_source:part:start saas.website.runtime.context facet:layer:core facet:family:website\n *\n * `WebsiteRuntimeContext` — site-wide runtime state for the marketing\n * surface. Created **once per page render** by the host adapter: the\n * page's `.astro` frontmatter loads the site context and the resolved label\n * pack, and its bridge island (`createWebsitePageBridgeIsland`) calls\n * `<WebsiteRuntimeContextProvider value={…}>` around the page tree.\n *\n * **Why \"runtime\" and not \"config\"**: the values here are the\n * locale-resolved subset of `WebsiteRootConfig` — only the active\n * locale's label pack travels with the React tree (the other locales\n * live in their own per-locale static builds). A `*Config` name would\n * suggest the full multi-locale surface is in scope.\n *\n * **Three pieces of state**:\n *\n * - `locale` — the currently-rendering locale. Sections that need\n * locale-aware formatting (number/date in marketing copy is rare\n * but legitimate) read it via `useWebsiteRuntime()`.\n * - `labelPack` — the locale-resolved flat key→string map, validated\n * against the manifest by `validateLabelPackAgainstManifest` at\n * build start. Consumed by `useWebsiteLabel` and\n * `useWebsiteLabelByKey`.\n * - `designTokens` — the `WebsiteDesignTokens` from\n * `WebsiteRootConfig.designTokens`. Consumed by\n * `useWebsiteDesignTokens` and by the Phase 5 CSS emitter that\n * materializes them as `--website-*` custom properties on the\n * `<WebsitePageLayout>` root.\n * - `navigation` — the `WebsiteNavigationConfig` from\n * `WebsiteRootConfig.navigation`. Carried in the runtime context\n * (rather than as a separate `WebsiteNavigationContext`) because\n * `<WebsitePageLayout>` already reads runtime state and\n * header/footer slots are inseparable from \"the site is rendering\n * right now\". A second context for two component refs would split\n * the host-adapter's wiring surface without buying isolation.\n * - `frontendProviderRegistry` — optional website-facing public provider\n * registry hydrated from the materialized provider artifact for the\n * concrete `STATIC_WEBSITE` service. This keeps analytics / captcha /\n * browser-monitoring integrations on the same frontend-provider\n * contract the SaaS app now uses, instead of inventing a website-only\n * metadata seam.\n *\n * **Why the hook lives in a separate file**: React Fast Refresh only\n * preserves state for a module whose every export is a component, so\n * a module mixing components with plain functions loses its HMR\n * boundary. This file holds the two things that must be identical\n * objects at runtime — the context and the provider component that\n * writes it — while `useWebsiteRuntime` sits alone in\n * `useWebsiteRuntime.ts`. A section author editing a component that\n * merely READS the runtime therefore never remounts the provider.\n *\n * Until 2026-09-09 this paragraph described a different arrangement:\n * that only the bare context was kept here and the provider lived in\n * a file of its own. No such file has ever existed — the provider is\n * exported below — and splitting it out would be the wrong shape\n * anyway, since `useContext` matches on object identity.\n * prose-referent-waiver: the retired file name is quoted only to retire it.\n * The claim named `WebsiteRuntimeContextProvider.tsx`.\n */\nexport interface WebsiteRuntimeContextValue {\n /**\n * The currently-rendering locale. Marketing-site routing emits one\n * static build per locale (D8), so this value is constant per build\n * — never re-renders mid-session.\n */\n locale: AvailableLanguage;\n /**\n * The site's default locale (mirrors `WebsiteRootConfig.defaultLocale`).\n * Carried in the runtime context so client-tier components — namely\n * `WebsiteInternalLink` (Phase 6 fix H-β) — can compute the correct\n * locale-prefixed pathname (`/pricing` on the EN site,\n * `/fr/pricing` on the FR site) without re-importing the root\n * config. Plumbing it through the runtime keeps the routing rule\n * a framework-internal concern: section authors NEVER hand-prefix\n * paths.\n */\n defaultLocale: AvailableLanguage;\n /**\n * Origin of the application this marketing site sends visitors INTO — the\n * marketing → product handoff target, authored once as\n * `WildoMarketingWebsiteConfig.appOrigin` (#493).\n *\n * Carried here for exactly the reason `defaultLocale` above is: a\n * `wildo.website.config.ts` is Node-loaded and therefore invisible to a\n * client island, so before this a site resolved the app origin a SECOND\n * time from a public build-time environment variable it could read in the\n * browser — one host authored twice, in two files, with no mechanical link\n * between the copies. That is how a marketing site comes to point at the\n * wrong environment: a defect nobody notices until a customer follows the\n * link.\n *\n * Threading it through the runtime keeps the handoff a framework-internal\n * concern, the same way threading `defaultLocale` kept locale-prefixing one:\n * section authors never hand-assemble the product URL, and there is one\n * place to change it.\n */\n appOrigin?: string;\n /**\n * Flat `Record<string, string>` label pack for the active locale.\n * Lookup keys MUST be fully-composed `website.<page>.<section>.<slot>`\n * strings; consumers that hold leaf paths use `useWebsiteLabel(leaf)`\n * which composes the full key against the page+section context.\n */\n labelPack: LabelPack;\n /**\n * Design-token bundle for the active site. Same object referenced\n * by `WebsiteRootConfig.designTokens`; passed by reference (not\n * cloned) so token-aware components can rely on referential\n * stability across renders.\n */\n designTokens: WebsiteDesignTokens;\n /**\n * Site-wide navigation slot bindings (header / footer components).\n * Same object referenced by `WebsiteRootConfig.navigation`. Read\n * by `<WebsitePageLayout>` to render the chrome around each page's\n * `<main>` content; per-page `header` / `footer` props on\n * `<WebsitePageLayout>` override these defaults.\n */\n navigation: WebsiteNavigationConfig;\n /**\n * Fully-composed label key the framework reads to render the\n * \"Skip to main content\" affordance as the FIRST focusable element\n * on every page (Phase 6 third audit fix M-α). Mirrors\n * `WebsiteRootConfig.skipToMainContentLabelKey`. Carried in the\n * runtime context (NOT re-derived from the root config inside\n * `WebsitePageLayout`) for two reasons:\n * - The layout is a client-tier React component; it cannot import\n * the consumer's `WEBSITE_ROOT_CONFIG` symbol without dragging\n * server-only code (manifest registry, page components) into\n * the client bundle.\n * - Threading the key through the runtime keeps the layout's\n * contract symmetric with how every other localized text on the\n * page is sourced (label pack + key), so the skip link is\n * translated automatically without any per-locale branching.\n */\n skipToMainContentLabelKey: WebsiteLabelKey;\n /**\n * Website-facing public providers for the active static website\n * service. Optional so older tests and provider-free sites can omit\n * it, but when present it is the canonical frontend-safe provider\n * catalog for analytics / captcha / browser-monitoring slices.\n */\n frontendProviderRegistry?: FrontendWebsiteProviderRegistry;\n /**\n * Components the live providers contribute, keyed `capability:providerRef` (#1703) — the same\n * registry the application builds, from the same `components` declaration. Built by the page bridge\n * once per island from `frontendProviderRegistry`; read through `useWebsiteProviderComponent` and\n * rendered by `WebsiteProviderComponent`. Optional for the same reason as the registry above: a\n * provider-free site, or a test runtime, has none, and every slot then renders nothing.\n */\n providerComponentRegistry?: WebsiteProviderComponentRegistry;\n /**\n * Replaces the framework's visitor consent panel (#534). Reads `useWebsiteConsent()`; see\n * `WebsiteConsentBanner` for the three properties a replacement must keep. Absent uses the default.\n * Closed over by the bridge rather than passed as an island prop, like `navigation`, because a\n * component cannot cross Astro's serialization boundary.\n */\n consentBannerComponent?: ComponentType;\n /**\n * Backend API origin (WITHOUT a trailing slash) that anonymous-capture\n * sections POST to when constructing a `WebsiteAnonymousSessionClient`\n * (lead / draft-note forms). Sourced from\n * `WildoMarketingWebsiteConfig.apiOrigin` and passed as a\n * JSON-serializable island prop (the `.astro` page resolves the\n * per-environment value and forwards it).\n *\n * Optional because only pages that host an anonymous-capture section\n * need it — brochure pages omit it. A capture section that reads\n * `undefined` here surfaces a loud misconfiguration rather than\n * silently failing to submit.\n */\n apiOrigin?: string;\n /**\n * The application's public pricing catalogue (#1835), derived at build time from the billing\n * catalogue the backend sells from — so a pricing section states the prices the application\n * actually charges instead of a hand copy of them. Node-loaded\n * (`loadWebsitePricingCatalog` on `/config-loader`) and carried as an island prop for the\n * reason `appOrigin` above is. Read it with `useWebsitePricingCatalog()`.\n *\n * Optional because only pricing pages need it; a section that reads it on a page that did not\n * pass it fails loudly rather than rendering no plans.\n */\n pricingCatalog?: PublicPricingCatalog;\n}\n\n/**\n * Bare React context. Default `null` — `useWebsiteRuntime()` throws\n * with a clear error message when invoked outside of\n * `<WebsiteRuntimeContextProvider>`. The defensive throw is preferred\n * over a silent default value so a missing provider is detected at\n * the first hook call rather than at render time when a missing\n * label silently renders as the key string.\n */\nexport const WebsiteRuntimeContext: React.Context<WebsiteRuntimeContextValue | null> =\n createContext<WebsiteRuntimeContextValue | null>(null);\n\nexport interface WebsiteRuntimeContextProviderProps {\n value: WebsiteRuntimeContextValue;\n children: ReactNode;\n}\n\n/**\n * Provider component. Authored as a thin wrapper so consumers do NOT\n * have to import `WebsiteRuntimeContext.Provider` directly — the\n * provider component carries the documented authoring API and is the\n * Fast-Refresh-stable surface section authors compose against.\n */\nexport function WebsiteRuntimeContextProvider({\n value,\n children,\n}: WebsiteRuntimeContextProviderProps): ReactNode {\n return (\n <WebsiteRuntimeContext.Provider value={value}>\n {children}\n </WebsiteRuntimeContext.Provider>\n );\n}\nWebsiteRuntimeContextProvider.displayName = 'WebsiteRuntimeContextProvider';\n/** @wildo_source:part:end saas.website.runtime.context */\n"]}
@@ -1,3 +1,4 @@
1
+ import type { PublicPricingCatalog } from '@wildo-ai/saas-models/public-runtime';
1
2
  import { type WebsiteRuntimeContextValue } from './WebsiteRuntimeContext';
2
3
  /**
3
4
  * @wildo_source:part:start saas.website.use-runtime.hook facet:layer:core facet:family:website
@@ -16,4 +17,21 @@ import { type WebsiteRuntimeContextValue } from './WebsiteRuntimeContext';
16
17
  */
17
18
  export declare function useWebsiteRuntime(): WebsiteRuntimeContextValue;
18
19
  /** @wildo_source:part:end saas.website.use-runtime.hook */
20
+ /**
21
+ * @wildo_source:part:start saas.website.use-pricing-catalog.hook facet:layer:core facet:family:website facet:audience:app-developer
22
+ *
23
+ * `useWebsitePricingCatalog()` — the application's public pricing catalogue, for a pricing section.
24
+ *
25
+ * The plans, their prices, which one is recommended, how much of each price may be stated, and which
26
+ * are announced but not yet on sale — all derived at build time from the billing catalogue the
27
+ * backend sells from. A pricing section renders from THIS and never keeps its own copy of a price:
28
+ * a copy is a price that will disagree with the one the application charges.
29
+ *
30
+ * Throws when the page did not pass the catalogue to its bridge island: a pricing section with no
31
+ * plans would silently state that the application sells nothing. The page's `.astro` frontmatter
32
+ * loads it with `loadWebsitePricingCatalog()` from `@wildo-ai/saas-website/config-loader` and passes
33
+ * it as the island's `pricingCatalog` prop.
34
+ */
35
+ export declare function useWebsitePricingCatalog(): PublicPricingCatalog;
36
+ /** @wildo_source:part:end saas.website.use-pricing-catalog.hook */
19
37
  //# sourceMappingURL=useWebsiteRuntime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useWebsiteRuntime.d.ts","sourceRoot":"","sources":["../../../../../src/core/contexts/useWebsiteRuntime.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,IAAI,0BAA0B,CAU9D;AACD,2DAA2D"}
1
+ {"version":3,"file":"useWebsiteRuntime.d.ts","sourceRoot":"","sources":["../../../../../src/core/contexts/useWebsiteRuntime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,IAAI,0BAA0B,CAW9D;AACD,2DAA2D;AAE3D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,IAAI,oBAAoB,CAU/D;AACD,mEAAmE"}
@@ -19,10 +19,36 @@ export function useWebsiteRuntime() {
19
19
  const value = useContext(WebsiteRuntimeContext);
20
20
  if (value === null) {
21
21
  throw new Error('[useWebsiteRuntime] must be called inside <WebsiteRuntimeContextProvider>. ' +
22
- 'In Astro pages this is provided by `WebsitePageBridge.astro` — make sure ' +
23
- 'your page imports the bridge instead of rendering React components directly.');
22
+ 'In Astro pages this is provided by the page\'s bridge island (`createWebsitePageBridgeIsland` ' +
23
+ 'from @wildo-ai/saas-website/astro-island) — make sure the page renders its bridge instead of ' +
24
+ 'rendering React components directly.');
24
25
  }
25
26
  return value;
26
27
  }
27
28
  /** @wildo_source:part:end saas.website.use-runtime.hook */
29
+ /**
30
+ * @wildo_source:part:start saas.website.use-pricing-catalog.hook facet:layer:core facet:family:website facet:audience:app-developer
31
+ *
32
+ * `useWebsitePricingCatalog()` — the application's public pricing catalogue, for a pricing section.
33
+ *
34
+ * The plans, their prices, which one is recommended, how much of each price may be stated, and which
35
+ * are announced but not yet on sale — all derived at build time from the billing catalogue the
36
+ * backend sells from. A pricing section renders from THIS and never keeps its own copy of a price:
37
+ * a copy is a price that will disagree with the one the application charges.
38
+ *
39
+ * Throws when the page did not pass the catalogue to its bridge island: a pricing section with no
40
+ * plans would silently state that the application sells nothing. The page's `.astro` frontmatter
41
+ * loads it with `loadWebsitePricingCatalog()` from `@wildo-ai/saas-website/config-loader` and passes
42
+ * it as the island's `pricingCatalog` prop.
43
+ */
44
+ export function useWebsitePricingCatalog() {
45
+ const { pricingCatalog } = useWebsiteRuntime();
46
+ if (pricingCatalog === undefined) {
47
+ throw new Error('[useWebsitePricingCatalog] this page did not pass a pricing catalogue to its bridge island. In the page\'s '
48
+ + '`.astro` frontmatter, load it with `await loadWebsitePricingCatalog()` (the @wildo-ai/saas-website/config-loader '
49
+ + 'subpath) and pass `pricingCatalog={pricingCatalog}` to the island.');
50
+ }
51
+ return pricingCatalog;
52
+ }
53
+ /** @wildo_source:part:end saas.website.use-pricing-catalog.hook */
28
54
  //# sourceMappingURL=useWebsiteRuntime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useWebsiteRuntime.js","sourceRoot":"","sources":["../../../../../src/core/contexts/useWebsiteRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,EACL,qBAAqB,GAEtB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAChD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC3E,2EAA2E;YAC3E,8EAA8E,CACjF,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AACD,2DAA2D","sourcesContent":["import { useContext } from 'react';\n\nimport {\n WebsiteRuntimeContext,\n type WebsiteRuntimeContextValue,\n} from './WebsiteRuntimeContext';\n\n/**\n * @wildo_source:part:start saas.website.use-runtime.hook facet:layer:core facet:family:website\n *\n * `useWebsiteRuntime()` — read access to the\n * `WebsiteRuntimeContextValue`. Throws if invoked outside of a\n * `<WebsiteRuntimeContextProvider>` so a missing host adapter is\n * detected at the first hook call (fail-loud).\n *\n * Section authors usually do NOT call this directly — prefer the\n * higher-level hooks (`useWebsiteLabel`, `useWebsiteLabelByKey`,\n * `useWebsiteDesignTokens`) which expose only the slice they need.\n * Direct access is reserved for layout primitives and locale-aware\n * formatters that legitimately need the active locale or the raw\n * label pack.\n */\nexport function useWebsiteRuntime(): WebsiteRuntimeContextValue {\n const value = useContext(WebsiteRuntimeContext);\n if (value === null) {\n throw new Error(\n '[useWebsiteRuntime] must be called inside <WebsiteRuntimeContextProvider>. ' +\n 'In Astro pages this is provided by `WebsitePageBridge.astro` — make sure ' +\n 'your page imports the bridge instead of rendering React components directly.',\n );\n }\n return value;\n}\n/** @wildo_source:part:end saas.website.use-runtime.hook */\n"]}
1
+ {"version":3,"file":"useWebsiteRuntime.js","sourceRoot":"","sources":["../../../../../src/core/contexts/useWebsiteRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAInC,OAAO,EACL,qBAAqB,GAEtB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAChD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC3E,gGAAgG;YAChG,+FAA+F;YAC/F,sCAAsC,CACzC,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AACD,2DAA2D;AAE3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB;IACtC,MAAM,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAC/C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,6GAA6G;cACzG,mHAAmH;cACnH,oEAAoE,CACzE,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AACD,mEAAmE","sourcesContent":["import { useContext } from 'react';\n\nimport type { PublicPricingCatalog } from '@wildo-ai/saas-models/public-runtime';\n\nimport {\n WebsiteRuntimeContext,\n type WebsiteRuntimeContextValue,\n} from './WebsiteRuntimeContext';\n\n/**\n * @wildo_source:part:start saas.website.use-runtime.hook facet:layer:core facet:family:website\n *\n * `useWebsiteRuntime()` — read access to the\n * `WebsiteRuntimeContextValue`. Throws if invoked outside of a\n * `<WebsiteRuntimeContextProvider>` so a missing host adapter is\n * detected at the first hook call (fail-loud).\n *\n * Section authors usually do NOT call this directly — prefer the\n * higher-level hooks (`useWebsiteLabel`, `useWebsiteLabelByKey`,\n * `useWebsiteDesignTokens`) which expose only the slice they need.\n * Direct access is reserved for layout primitives and locale-aware\n * formatters that legitimately need the active locale or the raw\n * label pack.\n */\nexport function useWebsiteRuntime(): WebsiteRuntimeContextValue {\n const value = useContext(WebsiteRuntimeContext);\n if (value === null) {\n throw new Error(\n '[useWebsiteRuntime] must be called inside <WebsiteRuntimeContextProvider>. ' +\n 'In Astro pages this is provided by the page\\'s bridge island (`createWebsitePageBridgeIsland` ' +\n 'from @wildo-ai/saas-website/astro-island) — make sure the page renders its bridge instead of ' +\n 'rendering React components directly.',\n );\n }\n return value;\n}\n/** @wildo_source:part:end saas.website.use-runtime.hook */\n\n/**\n * @wildo_source:part:start saas.website.use-pricing-catalog.hook facet:layer:core facet:family:website facet:audience:app-developer\n *\n * `useWebsitePricingCatalog()` — the application's public pricing catalogue, for a pricing section.\n *\n * The plans, their prices, which one is recommended, how much of each price may be stated, and which\n * are announced but not yet on sale — all derived at build time from the billing catalogue the\n * backend sells from. A pricing section renders from THIS and never keeps its own copy of a price:\n * a copy is a price that will disagree with the one the application charges.\n *\n * Throws when the page did not pass the catalogue to its bridge island: a pricing section with no\n * plans would silently state that the application sells nothing. The page's `.astro` frontmatter\n * loads it with `loadWebsitePricingCatalog()` from `@wildo-ai/saas-website/config-loader` and passes\n * it as the island's `pricingCatalog` prop.\n */\nexport function useWebsitePricingCatalog(): PublicPricingCatalog {\n const { pricingCatalog } = useWebsiteRuntime();\n if (pricingCatalog === undefined) {\n throw new Error(\n '[useWebsitePricingCatalog] this page did not pass a pricing catalogue to its bridge island. In the page\\'s '\n + '`.astro` frontmatter, load it with `await loadWebsitePricingCatalog()` (the @wildo-ai/saas-website/config-loader '\n + 'subpath) and pass `pricingCatalog={pricingCatalog}` to the island.',\n );\n }\n return pricingCatalog;\n}\n/** @wildo_source:part:end saas.website.use-pricing-catalog.hook */\n"]}
@@ -0,0 +1,57 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { ConsentPurpose, ProviderCapability } from '@wildo-ai/saas-models/public-runtime';
3
+ /**
4
+ * @wildo_source:part:start saas.website.provider-component.slot facet:layer:core facet:family:website
5
+ *
6
+ * `<WebsiteProviderComponent>` — places ONE provider's component on a website page (#1703): an
7
+ * address lookup on a contact form, a vendor widget on a marketing page. The component comes from the
8
+ * provider's own `components[capability]` declaration, the same one the application reads, through
9
+ * the website's provider-component registry.
10
+ *
11
+ * What it guarantees, so a page does not have to:
12
+ *
13
+ * - **Nothing of the vendor reaches the static HTML.** The component loads from an effect, which never
14
+ * runs during the Astro server render, and the registry itself refuses to load where there is no
15
+ * browser document. The server renders only the reserved box.
16
+ * - **No layout shift.** `reservedMinHeight` applies to the box in EVERY state — the server
17
+ * placeholder, loading, the refusals and the loaded component — so the page does not jump when the
18
+ * component arrives. Set it to the component's rendered height.
19
+ * - **The vendor's scripts load with the component**, not on every page: the layout injects at startup
20
+ * only the scripts of providers that contribute no component.
21
+ * - **Consent before download.** A provider resting on a purpose the visitor has not granted downloads
22
+ * nothing; the box states that the feature is off, names the purposes it rests on, and offers the
23
+ * consent panel (`openSettings`). Granting there loads the component in place.
24
+ * - **Announced, and operable by keyboard.** The box holds a `role="status"` live region from the first
25
+ * render, so a refusal is announced when it appears; the consent button sits outside it, so it is not
26
+ * read out as part of the message, and is a real button.
27
+ * - **A failure says so.** A component that could not load renders the site's `unavailable` wording,
28
+ * never a blank. A provider that offers no component here (left off in this environment) renders the
29
+ * empty box, since there is nothing to retry.
30
+ *
31
+ * The words come from the site's label pack: `website.chrome.provider-component.consent-required` and
32
+ * `.unavailable` are framework-owned keys every pack must carry, and the purpose names and the button
33
+ * reuse the consent panel's keys. Pass `renderConsentRequired` to word the refusal in the page's own
34
+ * chrome instead; it receives the missing purposes and the action that opens the panel, and then owns
35
+ * its own announcement.
36
+ *
37
+ * It does not choose a provider. Pass the ref the page chose — `useWebsiteProviderComponentChoices`
38
+ * lists the candidates — or `undefined` while nothing is chosen.
39
+ */
40
+ export interface WebsiteProviderComponentProps<TProps extends object> {
41
+ /** The capability the component fills, e.g. `FRONTEND_ADDRESS_LOOKUP`. */
42
+ capability: ProviderCapability;
43
+ /** The provider the page chose, or `undefined` while nothing is chosen. */
44
+ providerRef: string | undefined;
45
+ /** The props the loaded component receives — the capability's slot contract. */
46
+ componentProps: TProps;
47
+ /** CSS length reserved for the box in every state, so the page does not shift when the component loads. */
48
+ reservedMinHeight?: string;
49
+ /** Replaces the default consent-required state. */
50
+ renderConsentRequired?: (input: {
51
+ missingPurposes: readonly ConsentPurpose[];
52
+ openConsentSettings: () => void;
53
+ }) => ReactNode;
54
+ }
55
+ export declare function WebsiteProviderComponent<TProps extends object>({ capability, providerRef, componentProps, reservedMinHeight, renderConsentRequired, }: WebsiteProviderComponentProps<TProps>): ReactNode;
56
+ /** @wildo_source:part:end saas.website.provider-component.slot */
57
+ //# sourceMappingURL=WebsiteProviderComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteProviderComponent.d.ts","sourceRoot":"","sources":["../../../../../src/core/external-providers/WebsiteProviderComponent.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AA6D/F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,WAAW,6BAA6B,CAAC,MAAM,SAAS,MAAM;IAClE,0EAA0E;IAC1E,UAAU,EAAE,kBAAkB,CAAC;IAC/B,2EAA2E;IAC3E,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IACvB,2GAA2G;IAC3G,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,SAAS,cAAc,EAAE,CAAC;QAAC,mBAAmB,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC;CAC/H;AAED,wBAAgB,wBAAwB,CAAC,MAAM,SAAS,MAAM,EAAE,EAC9D,UAAU,EACV,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,qBAAqB,GACtB,EAAE,6BAA6B,CAAC,MAAM,CAAC,GAAG,SAAS,CAgCnD;AACD,kEAAkE"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ProviderComponentStatus } from '@wildo-ai/external-connectors-public/website';
3
+ import { websiteDesignTokenCssVar } from '../../schemas/design-tokens/website-design-tokens.shared.schemas.js';
4
+ import { WebsiteConsentLabelSlot, websiteConsentLabelKey, websiteConsentPurposeLabelKey, } from '../../schemas/label-keys/website-consent-label-keys.schemas.js';
5
+ import { WebsiteProviderComponentLabelSlot, websiteProviderComponentLabelKey, } from '../../schemas/label-keys/website-provider-component-label-keys.schemas.js';
6
+ import { useWebsiteConsent } from '../consent/useWebsiteConsent.js';
7
+ import { useWebsiteLabelByKey } from '../hooks/useWebsiteLabel.js';
8
+ import { useWebsiteProviderComponent } from './useWebsiteProviderComponent.js';
9
+ const STATE_STYLE = {
10
+ display: 'flex',
11
+ flexDirection: 'column',
12
+ gap: '0.5rem',
13
+ padding: '0.75rem',
14
+ border: `1px solid ${websiteDesignTokenCssVar('colors', 'border', '#ccc')}`,
15
+ borderRadius: websiteDesignTokenCssVar('radii', 'md', '0.375rem'),
16
+ };
17
+ const BUTTON_STYLE = {
18
+ alignSelf: 'flex-start',
19
+ padding: '0.5rem 1rem',
20
+ borderRadius: websiteDesignTokenCssVar('radii', 'md', '0.375rem'),
21
+ border: `1px solid ${websiteDesignTokenCssVar('colors', 'border', '#ccc')}`,
22
+ background: websiteDesignTokenCssVar('colors', 'background', '#fff'),
23
+ color: websiteDesignTokenCssVar('colors', 'foreground', '#000'),
24
+ cursor: 'pointer',
25
+ };
26
+ function PurposeName({ purpose }) {
27
+ return _jsx("li", { "data-website-provider-component-purpose": purpose, children: useWebsiteLabelByKey(websiteConsentPurposeLabelKey(purpose)) });
28
+ }
29
+ /**
30
+ * The words announced for a refusal. Rendered INTO the always-present live region, so a screen reader
31
+ * announces the change when it happens; a region inserted already filled is often not announced at all.
32
+ */
33
+ function RefusalStatement({ status, missingPurposes }) {
34
+ const consentRequired = useWebsiteLabelByKey(websiteProviderComponentLabelKey(WebsiteProviderComponentLabelSlot.CONSENT_REQUIRED));
35
+ const unavailable = useWebsiteLabelByKey(websiteProviderComponentLabelKey(WebsiteProviderComponentLabelSlot.UNAVAILABLE));
36
+ if (status === ProviderComponentStatus.UNAVAILABLE)
37
+ return _jsx("p", { style: { margin: 0 }, children: unavailable });
38
+ return (_jsxs(_Fragment, { children: [_jsx("p", { style: { margin: 0 }, children: consentRequired }), _jsx("ul", { style: { margin: 0 }, children: missingPurposes.map((purpose) => _jsx(PurposeName, { purpose: purpose }, purpose)) })] }));
39
+ }
40
+ function ManageConsentButton({ onClick }) {
41
+ return _jsx("button", { type: "button", style: BUTTON_STYLE, onClick: onClick, children: useWebsiteLabelByKey(websiteConsentLabelKey(WebsiteConsentLabelSlot.MANAGE)) });
42
+ }
43
+ export function WebsiteProviderComponent({ capability, providerRef, componentProps, reservedMinHeight, renderConsentRequired, }) {
44
+ const consent = useWebsiteConsent();
45
+ const { status, Component, missingConsentPurposes } = useWebsiteProviderComponent(capability, providerRef);
46
+ const isReady = status === ProviderComponentStatus.READY && Component !== null;
47
+ const isConsentRequired = status === ProviderComponentStatus.CONSENT_REQUIRED;
48
+ const isUnavailable = status === ProviderComponentStatus.UNAVAILABLE;
49
+ const useDefaultRefusal = isUnavailable || (isConsentRequired && renderConsentRequired === undefined);
50
+ // The registry cannot know a capability's props; the page states them through `componentProps`.
51
+ const Loaded = isReady ? Component : null;
52
+ return (_jsxs("div", { "data-website-provider-component": capability, "data-website-provider-component-state": status, "aria-busy": status === ProviderComponentStatus.LOADING ? true : undefined, style: reservedMinHeight !== undefined ? { minHeight: reservedMinHeight } : undefined, children: [Loaded !== null ? _jsx(Loaded, { ...componentProps }) : null, isConsentRequired && renderConsentRequired !== undefined
53
+ ? renderConsentRequired({ missingPurposes: missingConsentPurposes, openConsentSettings: consent.openSettings })
54
+ : null, Loaded === null ? (_jsxs("div", { style: useDefaultRefusal ? STATE_STYLE : undefined, children: [_jsx("div", { role: "status", children: useDefaultRefusal ? _jsx(RefusalStatement, { status: status, missingPurposes: missingConsentPurposes }) : null }), isConsentRequired && renderConsentRequired === undefined ? _jsx(ManageConsentButton, { onClick: consent.openSettings }) : null] })) : null] }));
55
+ }
56
+ //# sourceMappingURL=WebsiteProviderComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebsiteProviderComponent.js","sourceRoot":"","sources":["../../../../../src/core/external-providers/WebsiteProviderComponent.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAGvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,kEAAkE,CAAC;AAC5G,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,6BAA6B,GAC9B,MAAM,6DAA6D,CAAC;AACrE,OAAO,EACL,iCAAiC,EACjC,gCAAgC,GACjC,MAAM,wEAAwE,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E,MAAM,WAAW,GAAwB;IACvC,OAAO,EAAE,MAAM;IACf,aAAa,EAAE,QAAQ;IACvB,GAAG,EAAE,QAAQ;IACb,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,aAAa,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE;IAC3E,YAAY,EAAE,wBAAwB,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC;CAClE,CAAC;AAEF,MAAM,YAAY,GAAwB;IACxC,SAAS,EAAE,YAAY;IACvB,OAAO,EAAE,aAAa;IACtB,YAAY,EAAE,wBAAwB,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC;IACjE,MAAM,EAAE,aAAa,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE;IAC3E,UAAU,EAAE,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC;IACpE,KAAK,EAAE,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC;IAC/D,MAAM,EAAE,SAAS;CAClB,CAAC;AAEF,SAAS,WAAW,CAAC,EAAE,OAAO,EAA+B;IAC3D,OAAO,wDAA6C,OAAO,YAAG,oBAAoB,CAAC,6BAA6B,CAAC,OAAO,CAAC,CAAC,GAAM,CAAC;AACnI,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,EAAE,MAAM,EAAE,eAAe,EAAmF;IACpI,MAAM,eAAe,GAAG,oBAAoB,CAAC,gCAAgC,CAAC,iCAAiC,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACnI,MAAM,WAAW,GAAG,oBAAoB,CAAC,gCAAgC,CAAC,iCAAiC,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1H,IAAI,MAAM,KAAK,uBAAuB,CAAC,WAAW;QAAE,OAAO,YAAG,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,YAAG,WAAW,GAAK,CAAC;IACtG,OAAO,CACL,8BACE,YAAG,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,YAAG,eAAe,GAAK,EAC9C,aAAI,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,YACrB,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAC,WAAW,IAAe,OAAO,EAAE,OAAO,IAAzB,OAAO,CAAsB,CAAC,GAC/E,IACJ,CACJ,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAE,OAAO,EAA2B;IAC/D,OAAO,iBAAQ,IAAI,EAAC,QAAQ,EAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,YAAG,oBAAoB,CAAC,sBAAsB,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC,GAAU,CAAC;AAC9J,CAAC;AAoDD,MAAM,UAAU,wBAAwB,CAAwB,EAC9D,UAAU,EACV,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,qBAAqB,GACiB;IACtC,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,sBAAsB,EAAE,GAAG,2BAA2B,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAE3G,MAAM,OAAO,GAAG,MAAM,KAAK,uBAAuB,CAAC,KAAK,IAAI,SAAS,KAAK,IAAI,CAAC;IAC/E,MAAM,iBAAiB,GAAG,MAAM,KAAK,uBAAuB,CAAC,gBAAgB,CAAC;IAC9E,MAAM,aAAa,GAAG,MAAM,KAAK,uBAAuB,CAAC,WAAW,CAAC;IACrE,MAAM,iBAAiB,GAAG,aAAa,IAAI,CAAC,iBAAiB,IAAI,qBAAqB,KAAK,SAAS,CAAC,CAAC;IACtG,gGAAgG;IAChG,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,SAAoD,CAAC,CAAC,CAAC,IAAI,CAAC;IAEtF,OAAO,CACL,kDACmC,UAAU,2CACJ,MAAM,eAClC,MAAM,KAAK,uBAAuB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EACxE,KAAK,EAAE,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,SAAS,aAEpF,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,KAAC,MAAM,OAAK,cAAc,GAAI,CAAC,CAAC,CAAC,IAAI,EACvD,iBAAiB,IAAI,qBAAqB,KAAK,SAAS;gBACvD,CAAC,CAAC,qBAAqB,CAAC,EAAE,eAAe,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;gBAC/G,CAAC,CAAC,IAAI,EACP,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CACjB,eAAK,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,aACrD,cAAK,IAAI,EAAC,QAAQ,YACf,iBAAiB,CAAC,CAAC,CAAC,KAAC,gBAAgB,IAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,sBAAsB,GAAI,CAAC,CAAC,CAAC,IAAI,GACrG,EACL,iBAAiB,IAAI,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC,KAAC,mBAAmB,IAAC,OAAO,EAAE,OAAO,CAAC,YAAY,GAAI,CAAC,CAAC,CAAC,IAAI,IACrH,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC","sourcesContent":["import React, { type ReactNode } from 'react';\nimport { ProviderComponentStatus } from '@wildo-ai/external-connectors-public/website';\nimport type { ConsentPurpose, ProviderCapability } from '@wildo-ai/saas-models/public-runtime';\n\nimport { websiteDesignTokenCssVar } from '../../schemas/design-tokens/website-design-tokens.shared.schemas';\nimport {\n WebsiteConsentLabelSlot,\n websiteConsentLabelKey,\n websiteConsentPurposeLabelKey,\n} from '../../schemas/label-keys/website-consent-label-keys.schemas';\nimport {\n WebsiteProviderComponentLabelSlot,\n websiteProviderComponentLabelKey,\n} from '../../schemas/label-keys/website-provider-component-label-keys.schemas';\nimport { useWebsiteConsent } from '../consent/useWebsiteConsent';\nimport { useWebsiteLabelByKey } from '../hooks/useWebsiteLabel';\nimport { useWebsiteProviderComponent } from './useWebsiteProviderComponent';\n\nconst STATE_STYLE: React.CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n padding: '0.75rem',\n border: `1px solid ${websiteDesignTokenCssVar('colors', 'border', '#ccc')}`,\n borderRadius: websiteDesignTokenCssVar('radii', 'md', '0.375rem'),\n};\n\nconst BUTTON_STYLE: React.CSSProperties = {\n alignSelf: 'flex-start',\n padding: '0.5rem 1rem',\n borderRadius: websiteDesignTokenCssVar('radii', 'md', '0.375rem'),\n border: `1px solid ${websiteDesignTokenCssVar('colors', 'border', '#ccc')}`,\n background: websiteDesignTokenCssVar('colors', 'background', '#fff'),\n color: websiteDesignTokenCssVar('colors', 'foreground', '#000'),\n cursor: 'pointer',\n};\n\nfunction PurposeName({ purpose }: { purpose: ConsentPurpose }): ReactNode {\n return <li data-website-provider-component-purpose={purpose}>{useWebsiteLabelByKey(websiteConsentPurposeLabelKey(purpose))}</li>;\n}\n\n/**\n * The words announced for a refusal. Rendered INTO the always-present live region, so a screen reader\n * announces the change when it happens; a region inserted already filled is often not announced at all.\n */\nfunction RefusalStatement({ status, missingPurposes }: { status: ProviderComponentStatus; missingPurposes: readonly ConsentPurpose[] }): ReactNode {\n const consentRequired = useWebsiteLabelByKey(websiteProviderComponentLabelKey(WebsiteProviderComponentLabelSlot.CONSENT_REQUIRED));\n const unavailable = useWebsiteLabelByKey(websiteProviderComponentLabelKey(WebsiteProviderComponentLabelSlot.UNAVAILABLE));\n if (status === ProviderComponentStatus.UNAVAILABLE) return <p style={{ margin: 0 }}>{unavailable}</p>;\n return (\n <>\n <p style={{ margin: 0 }}>{consentRequired}</p>\n <ul style={{ margin: 0 }}>\n {missingPurposes.map((purpose) => <PurposeName key={purpose} purpose={purpose} />)}\n </ul>\n </>\n );\n}\n\nfunction ManageConsentButton({ onClick }: { onClick: () => void }): ReactNode {\n return <button type=\"button\" style={BUTTON_STYLE} onClick={onClick}>{useWebsiteLabelByKey(websiteConsentLabelKey(WebsiteConsentLabelSlot.MANAGE))}</button>;\n}\n\n/**\n * @wildo_source:part:start saas.website.provider-component.slot facet:layer:core facet:family:website\n *\n * `<WebsiteProviderComponent>` — places ONE provider's component on a website page (#1703): an\n * address lookup on a contact form, a vendor widget on a marketing page. The component comes from the\n * provider's own `components[capability]` declaration, the same one the application reads, through\n * the website's provider-component registry.\n *\n * What it guarantees, so a page does not have to:\n *\n * - **Nothing of the vendor reaches the static HTML.** The component loads from an effect, which never\n * runs during the Astro server render, and the registry itself refuses to load where there is no\n * browser document. The server renders only the reserved box.\n * - **No layout shift.** `reservedMinHeight` applies to the box in EVERY state — the server\n * placeholder, loading, the refusals and the loaded component — so the page does not jump when the\n * component arrives. Set it to the component's rendered height.\n * - **The vendor's scripts load with the component**, not on every page: the layout injects at startup\n * only the scripts of providers that contribute no component.\n * - **Consent before download.** A provider resting on a purpose the visitor has not granted downloads\n * nothing; the box states that the feature is off, names the purposes it rests on, and offers the\n * consent panel (`openSettings`). Granting there loads the component in place.\n * - **Announced, and operable by keyboard.** The box holds a `role=\"status\"` live region from the first\n * render, so a refusal is announced when it appears; the consent button sits outside it, so it is not\n * read out as part of the message, and is a real button.\n * - **A failure says so.** A component that could not load renders the site's `unavailable` wording,\n * never a blank. A provider that offers no component here (left off in this environment) renders the\n * empty box, since there is nothing to retry.\n *\n * The words come from the site's label pack: `website.chrome.provider-component.consent-required` and\n * `.unavailable` are framework-owned keys every pack must carry, and the purpose names and the button\n * reuse the consent panel's keys. Pass `renderConsentRequired` to word the refusal in the page's own\n * chrome instead; it receives the missing purposes and the action that opens the panel, and then owns\n * its own announcement.\n *\n * It does not choose a provider. Pass the ref the page chose — `useWebsiteProviderComponentChoices`\n * lists the candidates — or `undefined` while nothing is chosen.\n */\nexport interface WebsiteProviderComponentProps<TProps extends object> {\n /** The capability the component fills, e.g. `FRONTEND_ADDRESS_LOOKUP`. */\n capability: ProviderCapability;\n /** The provider the page chose, or `undefined` while nothing is chosen. */\n providerRef: string | undefined;\n /** The props the loaded component receives — the capability's slot contract. */\n componentProps: TProps;\n /** CSS length reserved for the box in every state, so the page does not shift when the component loads. */\n reservedMinHeight?: string;\n /** Replaces the default consent-required state. */\n renderConsentRequired?: (input: { missingPurposes: readonly ConsentPurpose[]; openConsentSettings: () => void }) => ReactNode;\n}\n\nexport function WebsiteProviderComponent<TProps extends object>({\n capability,\n providerRef,\n componentProps,\n reservedMinHeight,\n renderConsentRequired,\n}: WebsiteProviderComponentProps<TProps>): ReactNode {\n const consent = useWebsiteConsent();\n const { status, Component, missingConsentPurposes } = useWebsiteProviderComponent(capability, providerRef);\n\n const isReady = status === ProviderComponentStatus.READY && Component !== null;\n const isConsentRequired = status === ProviderComponentStatus.CONSENT_REQUIRED;\n const isUnavailable = status === ProviderComponentStatus.UNAVAILABLE;\n const useDefaultRefusal = isUnavailable || (isConsentRequired && renderConsentRequired === undefined);\n // The registry cannot know a capability's props; the page states them through `componentProps`.\n const Loaded = isReady ? (Component as unknown as React.ComponentType<TProps>) : null;\n\n return (\n <div\n data-website-provider-component={capability}\n data-website-provider-component-state={status}\n aria-busy={status === ProviderComponentStatus.LOADING ? true : undefined}\n style={reservedMinHeight !== undefined ? { minHeight: reservedMinHeight } : undefined}\n >\n {Loaded !== null ? <Loaded {...componentProps} /> : null}\n {isConsentRequired && renderConsentRequired !== undefined\n ? renderConsentRequired({ missingPurposes: missingConsentPurposes, openConsentSettings: consent.openSettings })\n : null}\n {Loaded === null ? (\n <div style={useDefaultRefusal ? STATE_STYLE : undefined}>\n <div role=\"status\">\n {useDefaultRefusal ? <RefusalStatement status={status} missingPurposes={missingConsentPurposes} /> : null}\n </div>\n {isConsentRequired && renderConsentRequired === undefined ? <ManageConsentButton onClick={consent.openSettings} /> : null}\n </div>\n ) : null}\n </div>\n );\n}\n/** @wildo_source:part:end saas.website.provider-component.slot */\n"]}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The website's provider-component registry (#1703): the SAME registry the application builds, from
3
+ * the SAME `components` declaration, over the website's live provider modules.
4
+ *
5
+ * A provider declares its components once, on its frontend module. Before this, the website facet
6
+ * type accepted `components` and nothing on the website read it, so a contact form could not host an
7
+ * address lookup (#561) and a marketing page could not host any provider component at all. The
8
+ * registry is `createProviderComponentRegistry` from `@wildo-ai/external-connectors-public/website`
9
+ * — keyed `capability:providerRef`, consent-gated, script-before-component and browser-only — and
10
+ * this file only feeds it the website's two inputs:
11
+ *
12
+ * - the HYDRATED website provider registry (both channels joined, so a provider not live for this
13
+ * website service contributes no component);
14
+ * - the loaders the site's facet library contributes for components an engine provider module
15
+ * declares but cannot import (the module lives in a renderer-free package), handed in through the
16
+ * page bridge's `providerComponentLoaders` rather than through module-level state, because the
17
+ * bridge is the website's one construction site and can carry it explicitly.
18
+ *
19
+ * Nothing is loaded here. A component loads when a `WebsiteProviderComponent` slot asks for it, from
20
+ * an effect — never during the Astro server render.
21
+ */
22
+ import { type ComponentType } from 'react';
23
+ import { type ProviderComponentDiagnostic, type ProviderComponentLoaderContribution, type ProviderComponentRegistry } from '@wildo-ai/external-connectors-public/website';
24
+ import type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';
25
+ import { type FrontendWebsiteProviderRegistry, type GeneratedWebsiteProviderModules } from './frontend-provider-registry.website';
26
+ /** A component type the website's registry hands back once loaded. */
27
+ export type WebsiteProviderComponentType = ComponentType<never>;
28
+ /** The website's provider-component registry: the shared registry, holding React components. */
29
+ export type WebsiteProviderComponentRegistry = ProviderComponentRegistry<WebsiteProviderComponentType>;
30
+ export interface CreateWebsiteProviderComponentRegistryInput {
31
+ /** The hydrated website provider registry; absent on a site with no providers. */
32
+ readonly providerRegistry: FrontendWebsiteProviderRegistry | undefined;
33
+ /** Loaders the site's facet library contributes for engine-declared components. */
34
+ readonly providerComponentLoaders?: Iterable<ProviderComponentLoaderContribution>;
35
+ /**
36
+ * Where a registration or load problem is reported. Defaults to `console.warn`: the website runtime
37
+ * has no logger service, and a provider component that cannot be offered is a developer-facing fact
38
+ * that must not be silent.
39
+ */
40
+ readonly onDiagnostic?: (diagnostic: ProviderComponentDiagnostic) => void;
41
+ }
42
+ /** Builds the website's provider-component registry from its live provider modules. */
43
+ export declare function createWebsiteProviderComponentRegistry(input: CreateWebsiteProviderComponentRegistryInput): WebsiteProviderComponentRegistry;
44
+ /** What a page bridge builds once per island: the hydrated provider registry and its component registry. */
45
+ export interface WebsiteProviderRegistries {
46
+ readonly frontendProviderRegistry: FrontendWebsiteProviderRegistry;
47
+ readonly providerComponentRegistry: WebsiteProviderComponentRegistry;
48
+ }
49
+ /**
50
+ * Builds both registries for a page bridge, MEMOISED on their inputs.
51
+ *
52
+ * Memoised because the component registry caches each loaded component: a registry rebuilt on every
53
+ * render would forget what it loaded, hand every slot a new registry identity, and make each slot's
54
+ * load effect run again — a download loop. The inputs are an island prop (`frontendProviders`, fixed
55
+ * for the island's life) and two module-load-time bridge dependencies, so in practice this builds
56
+ * once per island.
57
+ */
58
+ export declare function useWebsiteProviderRegistries(input: {
59
+ readonly frontendProviders: FrontendProvidersBlock | undefined;
60
+ readonly frontendProviderModules: GeneratedWebsiteProviderModules | undefined;
61
+ readonly providerComponentLoaders: Iterable<ProviderComponentLoaderContribution> | undefined;
62
+ }): WebsiteProviderRegistries;
63
+ //# sourceMappingURL=provider-component-registry.website.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-component-registry.website.d.ts","sourceRoot":"","sources":["../../../../../src/core/external-providers/provider-component-registry.website.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAIL,KAAK,2BAA2B,EAChC,KAAK,mCAAmC,EACxC,KAAK,yBAAyB,EAC/B,MAAM,8CAA8C,CAAC;AAEtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAEnF,OAAO,EAEL,KAAK,+BAA+B,EACpC,KAAK,+BAA+B,EACrC,MAAM,sCAAsC,CAAC;AAE9C,sEAAsE;AACtE,MAAM,MAAM,4BAA4B,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;AAEhE,gGAAgG;AAChG,MAAM,MAAM,gCAAgC,GAAG,yBAAyB,CAAC,4BAA4B,CAAC,CAAC;AAEvG,MAAM,WAAW,2CAA2C;IAC1D,kFAAkF;IAClF,QAAQ,CAAC,gBAAgB,EAAE,+BAA+B,GAAG,SAAS,CAAC;IACvE,mFAAmF;IACnF,QAAQ,CAAC,wBAAwB,CAAC,EAAE,QAAQ,CAAC,mCAAmC,CAAC,CAAC;IAClF;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC3E;AAWD,uFAAuF;AACvF,wBAAgB,sCAAsC,CACpD,KAAK,EAAE,2CAA2C,GACjD,gCAAgC,CAOlC;AAED,4GAA4G;AAC5G,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,wBAAwB,EAAE,+BAA+B,CAAC;IACnE,QAAQ,CAAC,yBAAyB,EAAE,gCAAgC,CAAC;CACtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,QAAQ,CAAC,iBAAiB,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,uBAAuB,EAAE,+BAA+B,GAAG,SAAS,CAAC;IAC9E,QAAQ,CAAC,wBAAwB,EAAE,QAAQ,CAAC,mCAAmC,CAAC,GAAG,SAAS,CAAC;CAC9F,GAAG,yBAAyB,CAe5B"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The website's provider-component registry (#1703): the SAME registry the application builds, from
3
+ * the SAME `components` declaration, over the website's live provider modules.
4
+ *
5
+ * A provider declares its components once, on its frontend module. Before this, the website facet
6
+ * type accepted `components` and nothing on the website read it, so a contact form could not host an
7
+ * address lookup (#561) and a marketing page could not host any provider component at all. The
8
+ * registry is `createProviderComponentRegistry` from `@wildo-ai/external-connectors-public/website`
9
+ * — keyed `capability:providerRef`, consent-gated, script-before-component and browser-only — and
10
+ * this file only feeds it the website's two inputs:
11
+ *
12
+ * - the HYDRATED website provider registry (both channels joined, so a provider not live for this
13
+ * website service contributes no component);
14
+ * - the loaders the site's facet library contributes for components an engine provider module
15
+ * declares but cannot import (the module lives in a renderer-free package), handed in through the
16
+ * page bridge's `providerComponentLoaders` rather than through module-level state, because the
17
+ * bridge is the website's one construction site and can carry it explicitly.
18
+ *
19
+ * Nothing is loaded here. A component loads when a `WebsiteProviderComponent` slot asks for it, from
20
+ * an effect — never during the Astro server render.
21
+ */
22
+ import { useMemo } from 'react';
23
+ import { collectProviderComponentRegistrations, createProviderComponentRegistry, indexProviderComponentLoaderContributions, } from '@wildo-ai/external-connectors-public/website';
24
+ import { createFrontendWebsiteProviderRegistry, } from './frontend-provider-registry.website.js';
25
+ function warnProviderComponentDiagnostic(diagnostic) {
26
+ // Reported in the BROWSER only. The registry is built during the server render or prerender too, once per
27
+ // page, and a declaration nothing can load would otherwise fill the build log with one warning per page
28
+ // for a fact the first page already stated. The browser is where somebody can see and act on it.
29
+ if (typeof document === 'undefined')
30
+ return;
31
+ // eslint-disable-next-line no-console
32
+ console.warn(`[wildo-provider-component] ${diagnostic.kind}: ${diagnostic.message}`);
33
+ }
34
+ /** Builds the website's provider-component registry from its live provider modules. */
35
+ export function createWebsiteProviderComponentRegistry(input) {
36
+ const onDiagnostic = input.onDiagnostic ?? warnProviderComponentDiagnostic;
37
+ const registrations = collectProviderComponentRegistrations(input.providerRegistry?.modules.values() ?? [], {
38
+ contributedLoaders: indexProviderComponentLoaderContributions(input.providerComponentLoaders),
39
+ onDiagnostic,
40
+ });
41
+ return createProviderComponentRegistry({ registrations, onDiagnostic });
42
+ }
43
+ /**
44
+ * Builds both registries for a page bridge, MEMOISED on their inputs.
45
+ *
46
+ * Memoised because the component registry caches each loaded component: a registry rebuilt on every
47
+ * render would forget what it loaded, hand every slot a new registry identity, and make each slot's
48
+ * load effect run again — a download loop. The inputs are an island prop (`frontendProviders`, fixed
49
+ * for the island's life) and two module-load-time bridge dependencies, so in practice this builds
50
+ * once per island.
51
+ */
52
+ export function useWebsiteProviderRegistries(input) {
53
+ const { frontendProviders, frontendProviderModules, providerComponentLoaders } = input;
54
+ return useMemo(() => {
55
+ const frontendProviderRegistry = createFrontendWebsiteProviderRegistry({
56
+ entries: frontendProviders,
57
+ modules: frontendProviderModules,
58
+ });
59
+ return {
60
+ frontendProviderRegistry,
61
+ providerComponentRegistry: createWebsiteProviderComponentRegistry({
62
+ providerRegistry: frontendProviderRegistry,
63
+ ...(providerComponentLoaders !== undefined ? { providerComponentLoaders } : {}),
64
+ }),
65
+ };
66
+ }, [frontendProviders, frontendProviderModules, providerComponentLoaders]);
67
+ }
68
+ //# sourceMappingURL=provider-component-registry.website.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-component-registry.website.js","sourceRoot":"","sources":["../../../../../src/core/external-providers/provider-component-registry.website.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,OAAO,EAAsB,MAAM,OAAO,CAAC;AACpD,OAAO,EACL,qCAAqC,EACrC,+BAA+B,EAC/B,yCAAyC,GAI1C,MAAM,8CAA8C,CAAC;AAItD,OAAO,EACL,qCAAqC,GAGtC,MAAM,sCAAsC,CAAC;AAqB9C,SAAS,+BAA+B,CAAC,UAAuC;IAC9E,0GAA0G;IAC1G,wGAAwG;IACxG,iGAAiG;IACjG,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC5C,sCAAsC;IACtC,OAAO,CAAC,IAAI,CAAC,8BAA8B,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;AACvF,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,sCAAsC,CACpD,KAAkD;IAElD,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,IAAI,+BAA+B,CAAC;IAC3E,MAAM,aAAa,GAAG,qCAAqC,CAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;QAC1G,kBAAkB,EAAE,yCAAyC,CAAC,KAAK,CAAC,wBAAwB,CAAC;QAC7F,YAAY;KACb,CAAC,CAAC;IACH,OAAO,+BAA+B,CAA+B,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC;AACxG,CAAC;AAQD;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAI5C;IACC,MAAM,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,GAAG,KAAK,CAAC;IACvF,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,wBAAwB,GAAG,qCAAqC,CAAC;YACrE,OAAO,EAAE,iBAAiB;YAC1B,OAAO,EAAE,uBAAuB;SACjC,CAAC,CAAC;QACH,OAAO;YACL,wBAAwB;YACxB,yBAAyB,EAAE,sCAAsC,CAAC;gBAChE,gBAAgB,EAAE,wBAAwB;gBAC1C,GAAG,CAAC,wBAAwB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,wBAAwB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChF,CAAC;SACH,CAAC;IACJ,CAAC,EAAE,CAAC,iBAAiB,EAAE,uBAAuB,EAAE,wBAAwB,CAAC,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["/**\n * The website's provider-component registry (#1703): the SAME registry the application builds, from\n * the SAME `components` declaration, over the website's live provider modules.\n *\n * A provider declares its components once, on its frontend module. Before this, the website facet\n * type accepted `components` and nothing on the website read it, so a contact form could not host an\n * address lookup (#561) and a marketing page could not host any provider component at all. The\n * registry is `createProviderComponentRegistry` from `@wildo-ai/external-connectors-public/website`\n * — keyed `capability:providerRef`, consent-gated, script-before-component and browser-only — and\n * this file only feeds it the website's two inputs:\n *\n * - the HYDRATED website provider registry (both channels joined, so a provider not live for this\n * website service contributes no component);\n * - the loaders the site's facet library contributes for components an engine provider module\n * declares but cannot import (the module lives in a renderer-free package), handed in through the\n * page bridge's `providerComponentLoaders` rather than through module-level state, because the\n * bridge is the website's one construction site and can carry it explicitly.\n *\n * Nothing is loaded here. A component loads when a `WebsiteProviderComponent` slot asks for it, from\n * an effect — never during the Astro server render.\n */\n\nimport { useMemo, type ComponentType } from 'react';\nimport {\n collectProviderComponentRegistrations,\n createProviderComponentRegistry,\n indexProviderComponentLoaderContributions,\n type ProviderComponentDiagnostic,\n type ProviderComponentLoaderContribution,\n type ProviderComponentRegistry,\n} from '@wildo-ai/external-connectors-public/website';\n\nimport type { FrontendProvidersBlock } from '@wildo-ai/saas-models/public-runtime';\n\nimport {\n createFrontendWebsiteProviderRegistry,\n type FrontendWebsiteProviderRegistry,\n type GeneratedWebsiteProviderModules,\n} from './frontend-provider-registry.website';\n\n/** A component type the website's registry hands back once loaded. */\nexport type WebsiteProviderComponentType = ComponentType<never>;\n\n/** The website's provider-component registry: the shared registry, holding React components. */\nexport type WebsiteProviderComponentRegistry = ProviderComponentRegistry<WebsiteProviderComponentType>;\n\nexport interface CreateWebsiteProviderComponentRegistryInput {\n /** The hydrated website provider registry; absent on a site with no providers. */\n readonly providerRegistry: FrontendWebsiteProviderRegistry | undefined;\n /** Loaders the site's facet library contributes for engine-declared components. */\n readonly providerComponentLoaders?: Iterable<ProviderComponentLoaderContribution>;\n /**\n * Where a registration or load problem is reported. Defaults to `console.warn`: the website runtime\n * has no logger service, and a provider component that cannot be offered is a developer-facing fact\n * that must not be silent.\n */\n readonly onDiagnostic?: (diagnostic: ProviderComponentDiagnostic) => void;\n}\n\nfunction warnProviderComponentDiagnostic(diagnostic: ProviderComponentDiagnostic): void {\n // Reported in the BROWSER only. The registry is built during the server render or prerender too, once per\n // page, and a declaration nothing can load would otherwise fill the build log with one warning per page\n // for a fact the first page already stated. The browser is where somebody can see and act on it.\n if (typeof document === 'undefined') return;\n // eslint-disable-next-line no-console\n console.warn(`[wildo-provider-component] ${diagnostic.kind}: ${diagnostic.message}`);\n}\n\n/** Builds the website's provider-component registry from its live provider modules. */\nexport function createWebsiteProviderComponentRegistry(\n input: CreateWebsiteProviderComponentRegistryInput,\n): WebsiteProviderComponentRegistry {\n const onDiagnostic = input.onDiagnostic ?? warnProviderComponentDiagnostic;\n const registrations = collectProviderComponentRegistrations(input.providerRegistry?.modules.values() ?? [], {\n contributedLoaders: indexProviderComponentLoaderContributions(input.providerComponentLoaders),\n onDiagnostic,\n });\n return createProviderComponentRegistry<WebsiteProviderComponentType>({ registrations, onDiagnostic });\n}\n\n/** What a page bridge builds once per island: the hydrated provider registry and its component registry. */\nexport interface WebsiteProviderRegistries {\n readonly frontendProviderRegistry: FrontendWebsiteProviderRegistry;\n readonly providerComponentRegistry: WebsiteProviderComponentRegistry;\n}\n\n/**\n * Builds both registries for a page bridge, MEMOISED on their inputs.\n *\n * Memoised because the component registry caches each loaded component: a registry rebuilt on every\n * render would forget what it loaded, hand every slot a new registry identity, and make each slot's\n * load effect run again — a download loop. The inputs are an island prop (`frontendProviders`, fixed\n * for the island's life) and two module-load-time bridge dependencies, so in practice this builds\n * once per island.\n */\nexport function useWebsiteProviderRegistries(input: {\n readonly frontendProviders: FrontendProvidersBlock | undefined;\n readonly frontendProviderModules: GeneratedWebsiteProviderModules | undefined;\n readonly providerComponentLoaders: Iterable<ProviderComponentLoaderContribution> | undefined;\n}): WebsiteProviderRegistries {\n const { frontendProviders, frontendProviderModules, providerComponentLoaders } = input;\n return useMemo(() => {\n const frontendProviderRegistry = createFrontendWebsiteProviderRegistry({\n entries: frontendProviders,\n modules: frontendProviderModules,\n });\n return {\n frontendProviderRegistry,\n providerComponentRegistry: createWebsiteProviderComponentRegistry({\n providerRegistry: frontendProviderRegistry,\n ...(providerComponentLoaders !== undefined ? { providerComponentLoaders } : {}),\n }),\n };\n }, [frontendProviders, frontendProviderModules, providerComponentLoaders]);\n}\n"]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Reading provider-contributed components on the website (#1703) — the website's counterpart of the
3
+ * application's `useProviderComponentChoices` / `useProviderComponent`, over the same registry and
4
+ * the same status vocabulary (`ProviderComponentStatus`).
5
+ *
6
+ * Two differences from the application, both about WHO answers:
7
+ *
8
+ * - the consent grant is the VISITOR's decision from `WebsiteConsentContext`, not a signed-in
9
+ * person's stored preference;
10
+ * - nothing starts before that decision has been read from storage (`isResolved`). The server render
11
+ * and the first client render read no storage, and asking the registry then would report a
12
+ * consent-required state to a visitor who already agreed, flashing the refusal on every page.
13
+ *
14
+ * Neither hook picks a provider: when several providers offer a component for one capability,
15
+ * choosing is the page's job.
16
+ */
17
+ import { type ProviderComponentLoadState } from '@wildo-ai/external-connectors-public/website';
18
+ import type { ProviderCapability } from '@wildo-ai/saas-models/public-runtime';
19
+ import type { WebsiteProviderComponentType } from './provider-component-registry.website';
20
+ /** What `useWebsiteProviderComponent` returns: the shared load state, holding a React component. */
21
+ export type WebsiteProviderComponentState = ProviderComponentLoadState<WebsiteProviderComponentType>;
22
+ /**
23
+ * The providers that are BOTH live for this website service and carry a component for this
24
+ * capability, in the order the service declared them. Synchronous, so a page can render its choice
25
+ * on the first frame.
26
+ */
27
+ export declare function useWebsiteProviderComponentChoices(capability: ProviderCapability): ReadonlyArray<string>;
28
+ /**
29
+ * Loads one provider's component for a capability, once the visitor's consent decision is known.
30
+ *
31
+ * Pass `undefined` for the ref while nothing is chosen. The load runs in an effect, so it never runs
32
+ * during the Astro server render; `CONSENT_REQUIRED` means nothing of the provider was downloaded,
33
+ * and granting the missing purposes through the consent panel loads it without a re-mount.
34
+ */
35
+ export declare function useWebsiteProviderComponent(capability: ProviderCapability, providerRef: string | undefined): WebsiteProviderComponentState;
36
+ //# sourceMappingURL=useWebsiteProviderComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWebsiteProviderComponent.d.ts","sourceRoot":"","sources":["../../../../../src/core/external-providers/useWebsiteProviderComponent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAI/E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AAE1F,oGAAoG;AACpG,MAAM,MAAM,6BAA6B,GAAG,0BAA0B,CAAC,4BAA4B,CAAC,CAAC;AAErG;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAGxG;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,6BAA6B,CAuB/B"}