@vtex/faststore 0.0.5 → 0.0.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 (232) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/actions.json +181 -0
  3. package/dist/catalog.json +1543 -495
  4. package/dist/client.d.ts +2 -1
  5. package/dist/client.js +2 -1
  6. package/dist/components.d.ts +28 -7
  7. package/dist/components.js +31 -12
  8. package/dist/docs/access-code-sign-in.md +1 -1
  9. package/dist/docs/address-summary.md +24 -3
  10. package/dist/docs/alert-dialog.md +204 -0
  11. package/dist/docs/billing-address.md +284 -0
  12. package/dist/docs/card-entry.md +250 -0
  13. package/dist/docs/cardholder-document.md +142 -0
  14. package/dist/docs/client-preferences-fieldset.md +148 -0
  15. package/dist/docs/client-preferences.md +2 -1
  16. package/dist/docs/client-profile-fieldset.md +184 -0
  17. package/dist/docs/client-profile.md +1 -1
  18. package/dist/docs/document-field.md +58 -4
  19. package/dist/docs/field.md +317 -0
  20. package/dist/docs/form.md +307 -0
  21. package/dist/docs/identity-edit.md +6 -6
  22. package/dist/docs/identity-summary.md +5 -5
  23. package/dist/docs/installments.md +248 -0
  24. package/dist/docs/my-account-profile.md +1 -0
  25. package/dist/docs/order-placed-payment-summary.md +138 -0
  26. package/dist/docs/payment-method-badges.md +232 -0
  27. package/dist/docs/payment-methods.md +1 -0
  28. package/dist/docs/payment.md +218 -0
  29. package/dist/docs/phone-field.md +58 -4
  30. package/dist/docs/place-order.md +157 -0
  31. package/dist/docs/save-card.md +186 -0
  32. package/dist/docs/saved-cards.md +218 -0
  33. package/dist/docs/select.md +465 -0
  34. package/dist/docs/shipping-address.md +110 -258
  35. package/dist/index.d.ts +4 -1
  36. package/dist/internal/client.d.ts +3 -1
  37. package/dist/internal/client.js +3 -1
  38. package/dist/matter/access-code-sign-in/access-code-sign-in.js +9 -8
  39. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
  40. package/dist/matter/billing-address/billing-address.d.ts +165 -0
  41. package/dist/matter/billing-address/billing-address.js +408 -0
  42. package/dist/matter/billing-address/billing-address.js.map +1 -0
  43. package/dist/matter/card-entry/card-capture.d.ts +25 -0
  44. package/dist/matter/card-entry/card-capture.js +25 -0
  45. package/dist/matter/card-entry/card-capture.js.map +1 -0
  46. package/dist/matter/card-entry/card-entry.d.ts +120 -0
  47. package/dist/matter/card-entry/card-entry.js +832 -0
  48. package/dist/matter/card-entry/card-entry.js.map +1 -0
  49. package/dist/matter/cardholder-document/cardholder-document.d.ts +45 -0
  50. package/dist/matter/cardholder-document/cardholder-document.js +70 -0
  51. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -0
  52. package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +77 -0
  53. package/dist/matter/client-preferences/client-preferences-fieldset.js +299 -0
  54. package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -0
  55. package/dist/matter/client-preferences/client-preferences.d.ts +3 -5
  56. package/dist/matter/client-preferences/client-preferences.js +6 -6
  57. package/dist/matter/client-preferences/client-preferences.js.map +1 -1
  58. package/dist/matter/client-profile/client-profile.d.ts +4 -6
  59. package/dist/matter/client-profile/client-profile.js +9 -6
  60. package/dist/matter/client-profile/client-profile.js.map +1 -1
  61. package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -0
  62. package/dist/matter/client-profile-form/client-profile-fieldset.js +488 -0
  63. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -0
  64. package/dist/matter/identity-edit/identity-edit.js +2 -2
  65. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  66. package/dist/matter/identity-summary/identity-summary.js +2 -2
  67. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  68. package/dist/matter/installments/installments-select.d.ts +42 -0
  69. package/dist/matter/installments/installments-select.js +167 -0
  70. package/dist/matter/installments/installments-select.js.map +1 -0
  71. package/dist/matter/installments/installments.d.ts +58 -0
  72. package/dist/matter/installments/installments.js +176 -0
  73. package/dist/matter/installments/installments.js.map +1 -0
  74. package/dist/matter/installments/use-installments-selection.d.ts +29 -0
  75. package/dist/matter/installments/use-installments-selection.js +95 -0
  76. package/dist/matter/installments/use-installments-selection.js.map +1 -0
  77. package/dist/matter/my-account-profile/my-account-profile.js +4 -4
  78. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  79. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +63 -0
  80. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +305 -0
  81. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -0
  82. package/dist/matter/payment/payment-card-capture.d.ts +19 -0
  83. package/dist/matter/payment/payment-card-capture.js +129 -0
  84. package/dist/matter/payment/payment-card-capture.js.map +1 -0
  85. package/dist/matter/payment/payment-controller.d.ts +24 -0
  86. package/dist/matter/payment/payment-controller.js +107 -0
  87. package/dist/matter/payment/payment-controller.js.map +1 -0
  88. package/dist/matter/payment/payment-method-badges.d.ts +57 -0
  89. package/dist/matter/payment/payment-method-badges.js +192 -0
  90. package/dist/matter/payment/payment-method-badges.js.map +1 -0
  91. package/dist/matter/payment/payment.d.ts +89 -0
  92. package/dist/matter/payment/payment.js +263 -0
  93. package/dist/matter/payment/payment.js.map +1 -0
  94. package/dist/matter/payment/use-payment-method-selection.d.ts +302 -0
  95. package/dist/matter/payment/use-payment-method-selection.js +458 -0
  96. package/dist/matter/payment/use-payment-method-selection.js.map +1 -0
  97. package/dist/matter/payment/use-payment-submit-gate.d.ts +111 -0
  98. package/dist/matter/payment/use-payment-submit-gate.js +144 -0
  99. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -0
  100. package/dist/matter/place-order/place-order.d.ts +74 -0
  101. package/dist/matter/place-order/place-order.js +379 -0
  102. package/dist/matter/place-order/place-order.js.map +1 -0
  103. package/dist/matter/product-list/product-list.d.ts +1 -0
  104. package/dist/matter/product-list/product-list.js.map +1 -1
  105. package/dist/matter/product-shelf/product-shelf.d.ts +1 -0
  106. package/dist/matter/product-shelf/product-shelf.js +2 -0
  107. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  108. package/dist/matter/region/region.js +1 -1
  109. package/dist/matter/region/region.js.map +1 -1
  110. package/dist/matter/save-card/save-card.d.ts +49 -0
  111. package/dist/matter/save-card/save-card.js +188 -0
  112. package/dist/matter/save-card/save-card.js.map +1 -0
  113. package/dist/matter/saved-cards/saved-cards.d.ts +79 -0
  114. package/dist/matter/saved-cards/saved-cards.js +387 -0
  115. package/dist/matter/saved-cards/saved-cards.js.map +1 -0
  116. package/dist/matter/shipping-address/country-descriptors.js +20 -10
  117. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  118. package/dist/matter/shipping-address/shipping-address.d.ts +113 -174
  119. package/dist/matter/shipping-address/shipping-address.js +480 -791
  120. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  121. package/dist/matter/variant-selector/variant-selector.js +1 -1
  122. package/dist/particles/address-summary/address-summary.d.ts +24 -0
  123. package/dist/particles/address-summary/address-summary.js +83 -2
  124. package/dist/particles/address-summary/address-summary.js.map +1 -1
  125. package/dist/particles/alert-dialog/alert-dialog.d.ts +68 -0
  126. package/dist/particles/alert-dialog/alert-dialog.js +187 -0
  127. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -0
  128. package/dist/particles/checkbox/checkbox.d.ts +7 -3
  129. package/dist/particles/checkbox/checkbox.js +4 -1
  130. package/dist/particles/checkbox/checkbox.js.map +1 -1
  131. package/dist/particles/document-field/document-field.d.ts +48 -5
  132. package/dist/particles/document-field/document-field.js +189 -32
  133. package/dist/particles/document-field/document-field.js.map +1 -1
  134. package/dist/particles/field/bound-field-registry.js +52 -0
  135. package/dist/particles/field/bound-field-registry.js.map +1 -0
  136. package/dist/particles/field/field.d.ts +116 -0
  137. package/dist/particles/field/field.js +497 -6
  138. package/dist/particles/field/field.js.map +1 -1
  139. package/dist/particles/fieldset/fieldset.js +2 -2
  140. package/dist/particles/fieldset/fieldset.js.map +1 -1
  141. package/dist/particles/form/form.d.ts +104 -0
  142. package/dist/particles/form/form.js +485 -0
  143. package/dist/particles/form/form.js.map +1 -0
  144. package/dist/particles/phone-field/phone-field.d.ts +38 -10
  145. package/dist/particles/phone-field/phone-field.js +183 -39
  146. package/dist/particles/phone-field/phone-field.js.map +1 -1
  147. package/dist/particles/postal-code-field/postal-code-field.js +2 -2
  148. package/dist/particles/postal-code-field/postal-code-field.js.map +1 -1
  149. package/dist/particles/select/field-select.d.ts +43 -0
  150. package/dist/particles/select/field-select.js +150 -0
  151. package/dist/particles/select/field-select.js.map +1 -0
  152. package/dist/particles/select/select.d.ts +2 -0
  153. package/dist/particles/select/select.js.map +1 -1
  154. package/dist/particles/shared/compose-refs.js +21 -0
  155. package/dist/particles/shared/compose-refs.js.map +1 -0
  156. package/dist/schema.graphql +701 -2
  157. package/dist/sdk/actions/analytics-action-provider.d.ts +15 -0
  158. package/dist/sdk/actions/analytics-action-provider.js +19 -0
  159. package/dist/sdk/actions/analytics-action-provider.js.map +1 -0
  160. package/dist/sdk/actions/index.d.ts +3 -1
  161. package/dist/sdk/actions/index.js +3 -1
  162. package/dist/sdk/actions/payment-action-provider.d.ts +22 -0
  163. package/dist/sdk/actions/payment-action-provider.js +26 -0
  164. package/dist/sdk/actions/payment-action-provider.js.map +1 -0
  165. package/dist/sdk/actions/types.d.ts +6 -2
  166. package/dist/sdk/analytics/analytics-destination.d.ts +43 -0
  167. package/dist/sdk/analytics/analytics-destination.js +90 -0
  168. package/dist/sdk/analytics/analytics-destination.js.map +1 -0
  169. package/dist/sdk/analytics/use-analytics-actions.d.ts +57 -0
  170. package/dist/sdk/analytics/use-analytics-actions.js +108 -0
  171. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -0
  172. package/dist/sdk/cart/use-cart-actions.js +1 -1
  173. package/dist/sdk/data/entity-resolution-context.js +31 -0
  174. package/dist/sdk/data/entity-resolution-context.js.map +1 -0
  175. package/dist/sdk/data/entity-subscriber.js +18 -8
  176. package/dist/sdk/data/entity-subscriber.js.map +1 -1
  177. package/dist/sdk/data/index.js +1 -0
  178. package/dist/sdk/data/page-reactive-data-root.d.ts +36 -0
  179. package/dist/sdk/data/page-reactive-data-root.js +4 -2
  180. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  181. package/dist/sdk/data/reactive-data-provider.js +7 -3
  182. package/dist/sdk/data/reactive-data-provider.js.map +1 -1
  183. package/dist/sdk/data/reactive-list-item-data-provider.js +12 -4
  184. package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
  185. package/dist/sdk/data/use-reactive-data-settled.js +39 -0
  186. package/dist/sdk/data/use-reactive-data-settled.js.map +1 -0
  187. package/dist/sdk/data/use-reactive-entity.js +5 -1
  188. package/dist/sdk/data/use-reactive-entity.js.map +1 -1
  189. package/dist/sdk/generated/fragment-types.js +2 -0
  190. package/dist/sdk/generated/fragment-types.js.map +1 -1
  191. package/dist/sdk/generated/graphql.js.map +1 -1
  192. package/dist/sdk/i18n/messages/en-US.js +3 -0
  193. package/dist/sdk/i18n/messages/en-US.json +3 -0
  194. package/dist/sdk/i18n/messages/en-US.json.d.ts +3 -0
  195. package/dist/sdk/i18n/messages/es-ES.js +3 -0
  196. package/dist/sdk/i18n/messages/es-ES.json +3 -0
  197. package/dist/sdk/i18n/messages/pt-BR.js +3 -0
  198. package/dist/sdk/i18n/messages/pt-BR.json +3 -0
  199. package/dist/sdk/identity/use-identity-actions.js +3 -2
  200. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  201. package/dist/sdk/payment/gateway-origin.js +35 -0
  202. package/dist/sdk/payment/gateway-origin.js.map +1 -0
  203. package/dist/sdk/payment/gateway.d.ts +85 -0
  204. package/dist/sdk/payment/gateway.js +183 -0
  205. package/dist/sdk/payment/gateway.js.map +1 -0
  206. package/dist/sdk/payment/operations.d.ts +52 -0
  207. package/dist/sdk/payment/operations.js +223 -0
  208. package/dist/sdk/payment/operations.js.map +1 -0
  209. package/dist/sdk/payment/security-code-mask.js +71 -0
  210. package/dist/sdk/payment/security-code-mask.js.map +1 -0
  211. package/dist/sdk/payment/submission-registry.d.ts +33 -0
  212. package/dist/sdk/payment/submission-registry.js +58 -0
  213. package/dist/sdk/payment/submission-registry.js.map +1 -0
  214. package/dist/sdk/payment/use-payment-actions.d.ts +78 -0
  215. package/dist/sdk/payment/use-payment-actions.js +276 -0
  216. package/dist/sdk/payment/use-payment-actions.js.map +1 -0
  217. package/dist/sdk/payment/use-place-order.d.ts +65 -0
  218. package/dist/sdk/payment/use-place-order.js +640 -0
  219. package/dist/sdk/payment/use-place-order.js.map +1 -0
  220. package/dist/sdk/shipping/use-shipping-actions.js +1 -1
  221. package/dist/utils/loggable-error-name.js +49 -0
  222. package/dist/utils/loggable-error-name.js.map +1 -0
  223. package/dist/utils/resolve-authored-copy.js +18 -0
  224. package/dist/utils/resolve-authored-copy.js.map +1 -0
  225. package/dist/utils/substitute-template.js +33 -0
  226. package/dist/utils/substitute-template.js.map +1 -0
  227. package/package.json +2 -1
  228. package/src/styles/tailwind.css +34 -0
  229. package/dist/docs/client-profile-form.md +0 -192
  230. package/dist/matter/client-profile-form/client-profile-form.d.ts +0 -126
  231. package/dist/matter/client-profile-form/client-profile-form.js +0 -662
  232. package/dist/matter/client-profile-form/client-profile-form.js.map +0 -1
@@ -0,0 +1,15 @@
1
+ import { ActionProviderProps } from "./inject-actions.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/sdk/actions/analytics-action-provider.d.ts
4
+ export type AnalyticsActionProviderProps = ActionProviderProps;
5
+ /**
6
+ * Compiler-emitted runtime wrapper for the `analytics` action namespace. The compiler wraps every
7
+ * element whose definition declares `actions: { analytics: [...] }` with
8
+ * `<AnalyticsActionProvider methods={[...]}>`, calls `useAnalyticsActions` once, narrows the
9
+ * surface to the declared `methods`, and publishes it through `ActionsOverrideContext` (merging with
10
+ * any outer namespace provider, per `useInjectActions`) for `useActionsOverride` to read further
11
+ * down. A namespace a component does not declare is never wrapped, so its hook is never called.
12
+ */
13
+ export declare function AnalyticsActionProvider(props: AnalyticsActionProviderProps): ReactNode;
14
+ //#endregion
15
+ //# sourceMappingURL=analytics-action-provider.d.ts.map
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { useAnalyticsActions } from "../analytics/use-analytics-actions.js";
3
+ import { useInjectActions } from "./inject-actions.js";
4
+ //#region src/sdk/actions/analytics-action-provider.tsx
5
+ /**
6
+ * Compiler-emitted runtime wrapper for the `analytics` action namespace. The compiler wraps every
7
+ * element whose definition declares `actions: { analytics: [...] }` with
8
+ * `<AnalyticsActionProvider methods={[...]}>`, calls `useAnalyticsActions` once, narrows the
9
+ * surface to the declared `methods`, and publishes it through `ActionsOverrideContext` (merging with
10
+ * any outer namespace provider, per `useInjectActions`) for `useActionsOverride` to read further
11
+ * down. A namespace a component does not declare is never wrapped, so its hook is never called.
12
+ */
13
+ function AnalyticsActionProvider(props) {
14
+ return useInjectActions("analytics", useAnalyticsActions(), props);
15
+ }
16
+ //#endregion
17
+ export { AnalyticsActionProvider };
18
+
19
+ //# sourceMappingURL=analytics-action-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-action-provider.js","names":[],"sources":["../../../src/sdk/actions/analytics-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { useAnalyticsActions } from '../analytics/use-analytics-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type AnalyticsActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `analytics` action namespace. The compiler wraps every\n * element whose definition declares `actions: { analytics: [...] }` with\n * `<AnalyticsActionProvider methods={[...]}>`, calls `useAnalyticsActions` once, narrows the\n * surface to the declared `methods`, and publishes it through `ActionsOverrideContext` (merging with\n * any outer namespace provider, per `useInjectActions`) for `useActionsOverride` to read further\n * down. A namespace a component does not declare is never wrapped, so its hook is never called.\n */\nexport function AnalyticsActionProvider(props: AnalyticsActionProviderProps): ReactNode {\n return useInjectActions('analytics', useAnalyticsActions(), props);\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,SAAgB,wBAAwB,OAAgD;CACtF,OAAO,iBAAiB,aAAa,oBAAoB,GAAG,KAAK;AACnE"}
@@ -1,7 +1,9 @@
1
1
  import { ComponentActions } from "./types.js";
2
+ import { AnalyticsActionProvider, AnalyticsActionProviderProps } from "./analytics-action-provider.js";
2
3
  import { CartActionProvider, CartActionProviderProps } from "./cart-action-provider.js";
3
4
  import { IdentityActionProvider, IdentityActionProviderProps } from "./identity-action-provider.js";
5
+ import { PaymentActionProvider, PaymentActionProviderProps } from "./payment-action-provider.js";
4
6
  import { RegionActionProvider, RegionActionProviderProps } from "./region-action-provider.js";
5
7
  import { SessionActionProvider, SessionActionProviderProps } from "./session-action-provider.js";
6
8
  import { ShippingActionProvider, ShippingActionProviderProps } from "./shipping-action-provider.js";
7
- export { CartActionProvider, type CartActionProviderProps, IdentityActionProvider, type IdentityActionProviderProps, RegionActionProvider, type RegionActionProviderProps, SessionActionProvider, type SessionActionProviderProps, ShippingActionProvider, type ShippingActionProviderProps };
9
+ export { AnalyticsActionProvider, type AnalyticsActionProviderProps, CartActionProvider, type CartActionProviderProps, IdentityActionProvider, type IdentityActionProviderProps, PaymentActionProvider, type PaymentActionProviderProps, RegionActionProvider, type RegionActionProviderProps, SessionActionProvider, type SessionActionProviderProps, ShippingActionProvider, type ShippingActionProviderProps };
@@ -1,6 +1,8 @@
1
+ import { AnalyticsActionProvider } from "./analytics-action-provider.js";
1
2
  import { CartActionProvider } from "./cart-action-provider.js";
2
3
  import { IdentityActionProvider } from "./identity-action-provider.js";
4
+ import { PaymentActionProvider } from "./payment-action-provider.js";
3
5
  import { RegionActionProvider } from "./region-action-provider.js";
4
6
  import { SessionActionProvider } from "./session-action-provider.js";
5
7
  import { ShippingActionProvider } from "./shipping-action-provider.js";
6
- export { CartActionProvider, IdentityActionProvider, RegionActionProvider, SessionActionProvider, ShippingActionProvider };
8
+ export { AnalyticsActionProvider, CartActionProvider, IdentityActionProvider, PaymentActionProvider, RegionActionProvider, SessionActionProvider, ShippingActionProvider };
@@ -0,0 +1,22 @@
1
+ import { ActionProviderProps } from "./inject-actions.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/sdk/actions/payment-action-provider.d.ts
4
+ export type PaymentActionProviderProps = ActionProviderProps;
5
+ /**
6
+ * Compiler-emitted runtime wrapper for the `payment` action namespace. The compiler wraps every
7
+ * element whose definition declares `actions: { payment: [...] }` with
8
+ * `<PaymentActionProvider methods={[...]}>`, calls `usePaymentActions` once, narrows the surface to
9
+ * the declared `methods`, and publishes it through `ActionsOverrideContext` (merging with any outer
10
+ * namespace provider, per `useInjectActions`) for `useActionsOverride` to read further down. A
11
+ * namespace a component does not declare is never wrapped, so its hook is never called
12
+ * (specs/actions.md FR-6).
13
+ *
14
+ * Narrowing matters more here than elsewhere: a component that declares only `setMethod` never receives
15
+ * `sendPayments`, because its own provider replaces the whole `payment` namespace an outer provider
16
+ * published (specs/payment-action-namespace.md, Decision 5). Context does not narrow a component that
17
+ * declares no `payment` method at all: rendered inside one that does, it can read the outer set
18
+ * (specs/sfs-3395-action-provider-context-delivery.md, Decision 2).
19
+ */
20
+ export declare function PaymentActionProvider(props: PaymentActionProviderProps): ReactNode;
21
+ //#endregion
22
+ //# sourceMappingURL=payment-action-provider.d.ts.map
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { useInjectActions } from "./inject-actions.js";
3
+ import { usePaymentActions } from "../payment/use-payment-actions.js";
4
+ //#region src/sdk/actions/payment-action-provider.tsx
5
+ /**
6
+ * Compiler-emitted runtime wrapper for the `payment` action namespace. The compiler wraps every
7
+ * element whose definition declares `actions: { payment: [...] }` with
8
+ * `<PaymentActionProvider methods={[...]}>`, calls `usePaymentActions` once, narrows the surface to
9
+ * the declared `methods`, and publishes it through `ActionsOverrideContext` (merging with any outer
10
+ * namespace provider, per `useInjectActions`) for `useActionsOverride` to read further down. A
11
+ * namespace a component does not declare is never wrapped, so its hook is never called
12
+ * (specs/actions.md FR-6).
13
+ *
14
+ * Narrowing matters more here than elsewhere: a component that declares only `setMethod` never receives
15
+ * `sendPayments`, because its own provider replaces the whole `payment` namespace an outer provider
16
+ * published (specs/payment-action-namespace.md, Decision 5). Context does not narrow a component that
17
+ * declares no `payment` method at all: rendered inside one that does, it can read the outer set
18
+ * (specs/sfs-3395-action-provider-context-delivery.md, Decision 2).
19
+ */
20
+ function PaymentActionProvider(props) {
21
+ return useInjectActions("payment", usePaymentActions(), props);
22
+ }
23
+ //#endregion
24
+ export { PaymentActionProvider };
25
+
26
+ //# sourceMappingURL=payment-action-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment-action-provider.js","names":[],"sources":["../../../src/sdk/actions/payment-action-provider.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { usePaymentActions } from '../payment/use-payment-actions.js';\nimport { type ActionProviderProps, useInjectActions } from './inject-actions.js';\n\nexport type PaymentActionProviderProps = ActionProviderProps;\n\n/**\n * Compiler-emitted runtime wrapper for the `payment` action namespace. The compiler wraps every\n * element whose definition declares `actions: { payment: [...] }` with\n * `<PaymentActionProvider methods={[...]}>`, calls `usePaymentActions` once, narrows the surface to\n * the declared `methods`, and publishes it through `ActionsOverrideContext` (merging with any outer\n * namespace provider, per `useInjectActions`) for `useActionsOverride` to read further down. A\n * namespace a component does not declare is never wrapped, so its hook is never called\n * (specs/actions.md FR-6).\n *\n * Narrowing matters more here than elsewhere: a component that declares only `setMethod` never receives\n * `sendPayments`, because its own provider replaces the whole `payment` namespace an outer provider\n * published (specs/payment-action-namespace.md, Decision 5). Context does not narrow a component that\n * declares no `payment` method at all: rendered inside one that does, it can read the outer set\n * (specs/sfs-3395-action-provider-context-delivery.md, Decision 2).\n */\nexport function PaymentActionProvider(props: PaymentActionProviderProps): ReactNode {\n return useInjectActions('payment', usePaymentActions(), props);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,sBAAsB,OAA8C;CAClF,OAAO,iBAAiB,WAAW,kBAAkB,GAAG,KAAK;AAC/D"}
@@ -1,5 +1,7 @@
1
+ import { AnalyticsActions } from "../analytics/use-analytics-actions.js";
1
2
  import { CartActions } from "../cart/use-cart-actions.js";
2
3
  import { IdentityActions } from "../identity/use-identity-actions.js";
4
+ import { PaymentActions } from "../payment/use-payment-actions.js";
3
5
  import { RegionActions } from "../region/use-region-actions.js";
4
6
  import { SessionActions } from "../session/use-session-actions.js";
5
7
  import { ShippingActions } from "../shipping/use-shipping-actions.js";
@@ -7,12 +9,14 @@ import { ShippingActions } from "../shipping/use-shipping-actions.js";
7
9
  /**
8
10
  * The `$actions` prop the compiler injects (and `mockAction` builds for tests). Each namespace is
9
11
  * optional and each method is optional within it, because a component only receives the methods it
10
- * declared under `actions: { ... }`. Ships the `cart`, `identity`, `region`, `session`, and
11
- * `shipping` namespaces.
12
+ * declared under `actions: { ... }`. Ships the `analytics`, `cart`, `identity`, `payment`, `region`,
13
+ * `session`, and `shipping` namespaces.
12
14
  */
13
15
  export type ComponentActions = {
16
+ analytics?: Partial<AnalyticsActions>;
14
17
  cart?: Partial<CartActions>;
15
18
  identity?: Partial<IdentityActions>;
19
+ payment?: Partial<PaymentActions>;
16
20
  region?: Partial<RegionActions>;
17
21
  session?: Partial<SessionActions>;
18
22
  shipping?: Partial<ShippingActions>;
@@ -0,0 +1,43 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/sdk/analytics/analytics-destination.d.ts
3
+ /**
4
+ * Configurable analytics destination (specs/make-the-analytics-destination-configurable-for.md;
5
+ * credit-card epic T120; RFC `docs/features/credit-card/rfc.md` § D14 — Analytics events
6
+ * (cross-cutting)). `use-analytics-actions.ts`'s `pushToDataLayer` used to hardcode
7
+ * `window.dataLayer`. This module narrows "configurable destination" to the *name* of the
8
+ * `window` array the two standard payment events (`add_payment_info`, `purchase`) are pushed to —
9
+ * not a vendor id, not a transport, not a fan-out list. The payload and its GA4 shape are
10
+ * unchanged; only the array it lands in differs.
11
+ *
12
+ * Resolution precedence: the nearest `AnalyticsDestinationProvider` -> the build-inlined
13
+ * `process.env.NEXT_PUBLIC_ANALYTICS_DESTINATION` -> `DEFAULT_ANALYTICS_DESTINATION`. Resolution
14
+ * happens at call time, inside `track` (see `use-analytics-actions.ts`) — never once at module
15
+ * scope — so a build-time env change and a test's `vi.stubEnv` are both observed without a remount.
16
+ *
17
+ * A destination that is not a plain identifier, or that names `__proto__` / `constructor` /
18
+ * `prototype`, is never written to `window`: it is rejected, logged once, and resolution falls
19
+ * back to the default instead. A misconfiguration can only cost an analytics event — it can never
20
+ * block payment submission or order placement, the same invariant `use-analytics-actions.ts`
21
+ * already holds.
22
+ */
23
+ /** The name of the `window` property the standard analytics events are pushed to. */
24
+ export type AnalyticsDestination = string;
25
+ export type AnalyticsDestinationProviderProps = Readonly<{
26
+ /**
27
+ * The `window` property name events are pushed to. Must be a build-time or merchant-authored
28
+ * constant — never wire this from user input. The identifier pattern and denylist block the
29
+ * known prototype-pollution keys, but a value that passes validation could still name a live,
30
+ * load-bearing global (`__NEXT_P`, `_gaq`, or a merchant queue with a hijacked `push`).
31
+ */
32
+ destination: AnalyticsDestination;
33
+ children: ReactNode;
34
+ }>;
35
+ /**
36
+ * Publishes a destination to the subtree — for a host that renders the components by hand (an
37
+ * embedder, a Storybook story, a test) and wants to supply or override the destination in React
38
+ * rather than through the build. Optional: an unprovided tree is the normal case, and the nearest
39
+ * provider wins over any outer one.
40
+ */
41
+ export declare function AnalyticsDestinationProvider({ destination, children }: AnalyticsDestinationProviderProps): ReactNode;
42
+ //#endregion
43
+ //# sourceMappingURL=analytics-destination.d.ts.map
@@ -0,0 +1,90 @@
1
+ "use client";
2
+ import { createContext, useContext } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/sdk/analytics/analytics-destination.tsx
5
+ /** The sink every store used before this task, and the fallback for anything invalid. */
6
+ const DEFAULT_ANALYTICS_DESTINATION = "dataLayer";
7
+ /** A plain property name: no dots, no dashes, no spaces, no leading digit. */
8
+ const DESTINATION_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
9
+ /** Never written to `window`, whatever the build says. */
10
+ const UNSAFE_DESTINATION_KEYS = [
11
+ "__proto__",
12
+ "constructor",
13
+ "prototype"
14
+ ];
15
+ /**
16
+ * A plain, safe `window` property name: matches the identifier pattern and is absent from the
17
+ * unsafe-key denylist. Operates on the value exactly as given — trimming, and treating
18
+ * empty-after-trim as unset, are `resolveAnalyticsDestination`'s job, not this predicate's.
19
+ */
20
+ function isValidAnalyticsDestination(value) {
21
+ return DESTINATION_PATTERN.test(value) && !UNSAFE_DESTINATION_KEYS.some((unsafeKey) => unsafeKey === value);
22
+ }
23
+ /**
24
+ * Returns the first non-empty-after-trim candidate in precedence order — `override`, then the
25
+ * build-inlined env var — together with whether that candidate is valid. Resolution never walks
26
+ * past that first configured candidate: an invalid `override` is never rescued by a valid env
27
+ * var, it falls straight through to `resolveAnalyticsDestination`'s default, exactly like an
28
+ * invalid env var with no override does. Validation itself is `isValidAnalyticsDestination`'s
29
+ * job — this function only picks which single candidate gets validated.
30
+ */
31
+ function firstConfiguredCandidate(override) {
32
+ const envValue = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_ANALYTICS_DESTINATION : void 0;
33
+ for (const candidate of [override, envValue]) {
34
+ if (candidate === void 0) continue;
35
+ const trimmed = candidate.trim();
36
+ if (trimmed.length === 0) continue;
37
+ return {
38
+ value: trimmed,
39
+ valid: isValidAnalyticsDestination(trimmed)
40
+ };
41
+ }
42
+ }
43
+ /**
44
+ * Precedence: `override` (context) -> NEXT_PUBLIC_ANALYTICS_DESTINATION -> DEFAULT.
45
+ * Trims; treats empty-after-trim as unset. A present-but-invalid value logs once via
46
+ * console.error and resolves to DEFAULT. Never throws.
47
+ *
48
+ * `hasLoggedRejection`, when passed, is a mutable latch: the first rejection while it is `false`
49
+ * logs and flips it to `true`; every later rejection while it stays `true` is silent. Omit it —
50
+ * every direct/unit-test call does — to log every rejection. `useAnalyticsActions` is the only
51
+ * caller that owns one, scoped to its own hook instance via `useRef`, so "logs once" means once
52
+ * per mounted `useAnalyticsActions()`, not once for the whole page.
53
+ */
54
+ function resolveAnalyticsDestination(options) {
55
+ const outcome = firstConfiguredCandidate(options?.override);
56
+ if (outcome === void 0) return DEFAULT_ANALYTICS_DESTINATION;
57
+ if (outcome.valid) return outcome.value;
58
+ const hasLoggedRejection = options?.hasLoggedRejection;
59
+ if (!hasLoggedRejection?.current) {
60
+ const message = `[analytics.track] ${JSON.stringify(outcome.value)} is not a valid analytics destination; falling back to ${JSON.stringify(DEFAULT_ANALYTICS_DESTINATION)}`;
61
+ console.error(message);
62
+ if (hasLoggedRejection) hasLoggedRejection.current = true;
63
+ }
64
+ return DEFAULT_ANALYTICS_DESTINATION;
65
+ }
66
+ /**
67
+ * Private, so the only read is `useAnalyticsDestination` — which, unlike `useStorefrontContext`,
68
+ * never throws when unprovided: an unprovided tree is the normal case here, not a bug.
69
+ */
70
+ const AnalyticsDestinationContext = createContext(void 0);
71
+ /**
72
+ * Publishes a destination to the subtree — for a host that renders the components by hand (an
73
+ * embedder, a Storybook story, a test) and wants to supply or override the destination in React
74
+ * rather than through the build. Optional: an unprovided tree is the normal case, and the nearest
75
+ * provider wins over any outer one.
76
+ */
77
+ function AnalyticsDestinationProvider({ destination, children }) {
78
+ return /* @__PURE__ */ jsx(AnalyticsDestinationContext.Provider, {
79
+ value: destination,
80
+ children
81
+ });
82
+ }
83
+ /** The nearest provided destination, or `undefined` when no provider is in the tree. Never throws. */
84
+ function useAnalyticsDestination() {
85
+ return useContext(AnalyticsDestinationContext);
86
+ }
87
+ //#endregion
88
+ export { AnalyticsDestinationProvider, DEFAULT_ANALYTICS_DESTINATION, isValidAnalyticsDestination, resolveAnalyticsDestination, useAnalyticsDestination };
89
+
90
+ //# sourceMappingURL=analytics-destination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-destination.js","names":[],"sources":["../../../src/sdk/analytics/analytics-destination.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, type ReactNode, useContext } from 'react';\n\n/**\n * Configurable analytics destination (specs/make-the-analytics-destination-configurable-for.md;\n * credit-card epic T120; RFC `docs/features/credit-card/rfc.md` § D14 — Analytics events\n * (cross-cutting)). `use-analytics-actions.ts`'s `pushToDataLayer` used to hardcode\n * `window.dataLayer`. This module narrows \"configurable destination\" to the *name* of the\n * `window` array the two standard payment events (`add_payment_info`, `purchase`) are pushed to —\n * not a vendor id, not a transport, not a fan-out list. The payload and its GA4 shape are\n * unchanged; only the array it lands in differs.\n *\n * Resolution precedence: the nearest `AnalyticsDestinationProvider` -> the build-inlined\n * `process.env.NEXT_PUBLIC_ANALYTICS_DESTINATION` -> `DEFAULT_ANALYTICS_DESTINATION`. Resolution\n * happens at call time, inside `track` (see `use-analytics-actions.ts`) — never once at module\n * scope — so a build-time env change and a test's `vi.stubEnv` are both observed without a remount.\n *\n * A destination that is not a plain identifier, or that names `__proto__` / `constructor` /\n * `prototype`, is never written to `window`: it is rejected, logged once, and resolution falls\n * back to the default instead. A misconfiguration can only cost an analytics event — it can never\n * block payment submission or order placement, the same invariant `use-analytics-actions.ts`\n * already holds.\n */\n\n/** The name of the `window` property the standard analytics events are pushed to. */\nexport type AnalyticsDestination = string;\n\n/** The sink every store used before this task, and the fallback for anything invalid. */\nexport const DEFAULT_ANALYTICS_DESTINATION = 'dataLayer';\n\n/** A plain property name: no dots, no dashes, no spaces, no leading digit. */\nconst DESTINATION_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/** Never written to `window`, whatever the build says. */\nconst UNSAFE_DESTINATION_KEYS = ['__proto__', 'constructor', 'prototype'] as const;\n\n/**\n * A plain, safe `window` property name: matches the identifier pattern and is absent from the\n * unsafe-key denylist. Operates on the value exactly as given — trimming, and treating\n * empty-after-trim as unset, are `resolveAnalyticsDestination`'s job, not this predicate's.\n */\nexport function isValidAnalyticsDestination(value: string): boolean {\n return DESTINATION_PATTERN.test(value) && !UNSAFE_DESTINATION_KEYS.some((unsafeKey) => unsafeKey === value);\n}\n\n/** The first configured candidate in precedence order, paired with whether it is valid. */\ntype CandidateOutcome = Readonly<{ value: string; valid: boolean }>;\n\n/**\n * Returns the first non-empty-after-trim candidate in precedence order — `override`, then the\n * build-inlined env var — together with whether that candidate is valid. Resolution never walks\n * past that first configured candidate: an invalid `override` is never rescued by a valid env\n * var, it falls straight through to `resolveAnalyticsDestination`'s default, exactly like an\n * invalid env var with no override does. Validation itself is `isValidAnalyticsDestination`'s\n * job — this function only picks which single candidate gets validated.\n */\nfunction firstConfiguredCandidate(override: string | undefined): CandidateOutcome | undefined {\n // `typeof process !== 'undefined'` guards a client bundle with no `process` shim at all (a\n // Vite/Rollup/esbuild embedder, US-2's stated host) — unlike a direct read, `typeof` never\n // throws when the identifier doesn't exist at all. The member expression itself stays literal\n // so Next's build-time inlining can still statically replace it (Decision 5).\n const envValue = typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_ANALYTICS_DESTINATION : undefined;\n\n for (const candidate of [override, envValue]) {\n if (candidate === undefined) continue;\n const trimmed = candidate.trim();\n if (trimmed.length === 0) continue;\n return { value: trimmed, valid: isValidAnalyticsDestination(trimmed) };\n }\n return undefined;\n}\n\n/**\n * Precedence: `override` (context) -> NEXT_PUBLIC_ANALYTICS_DESTINATION -> DEFAULT.\n * Trims; treats empty-after-trim as unset. A present-but-invalid value logs once via\n * console.error and resolves to DEFAULT. Never throws.\n *\n * `hasLoggedRejection`, when passed, is a mutable latch: the first rejection while it is `false`\n * logs and flips it to `true`; every later rejection while it stays `true` is silent. Omit it —\n * every direct/unit-test call does — to log every rejection. `useAnalyticsActions` is the only\n * caller that owns one, scoped to its own hook instance via `useRef`, so \"logs once\" means once\n * per mounted `useAnalyticsActions()`, not once for the whole page.\n */\nexport function resolveAnalyticsDestination(options?: {\n override?: string;\n hasLoggedRejection?: { current: boolean };\n}): AnalyticsDestination {\n const outcome = firstConfiguredCandidate(options?.override);\n if (outcome === undefined) return DEFAULT_ANALYTICS_DESTINATION;\n if (outcome.valid) return outcome.value;\n\n const hasLoggedRejection = options?.hasLoggedRejection;\n if (!hasLoggedRejection?.current) {\n const message =\n `[analytics.track] ${JSON.stringify(outcome.value)} is not a valid analytics destination; ` +\n `falling back to ${JSON.stringify(DEFAULT_ANALYTICS_DESTINATION)}`;\n console.error(message);\n if (hasLoggedRejection) hasLoggedRejection.current = true;\n }\n return DEFAULT_ANALYTICS_DESTINATION;\n}\n\nexport type AnalyticsDestinationProviderProps = Readonly<{\n /**\n * The `window` property name events are pushed to. Must be a build-time or merchant-authored\n * constant — never wire this from user input. The identifier pattern and denylist block the\n * known prototype-pollution keys, but a value that passes validation could still name a live,\n * load-bearing global (`__NEXT_P`, `_gaq`, or a merchant queue with a hijacked `push`).\n */\n destination: AnalyticsDestination;\n children: ReactNode;\n}>;\n\n/**\n * Private, so the only read is `useAnalyticsDestination` — which, unlike `useStorefrontContext`,\n * never throws when unprovided: an unprovided tree is the normal case here, not a bug.\n */\nconst AnalyticsDestinationContext = createContext<AnalyticsDestination | undefined>(undefined);\n\n/**\n * Publishes a destination to the subtree — for a host that renders the components by hand (an\n * embedder, a Storybook story, a test) and wants to supply or override the destination in React\n * rather than through the build. Optional: an unprovided tree is the normal case, and the nearest\n * provider wins over any outer one.\n */\nexport function AnalyticsDestinationProvider({ destination, children }: AnalyticsDestinationProviderProps): ReactNode {\n return <AnalyticsDestinationContext.Provider value={destination}>{children}</AnalyticsDestinationContext.Provider>;\n}\n\n/** The nearest provided destination, or `undefined` when no provider is in the tree. Never throws. */\nexport function useAnalyticsDestination(): AnalyticsDestination | undefined {\n return useContext(AnalyticsDestinationContext);\n}\n"],"mappings":";;;;;AA6BA,MAAa,gCAAgC;;AAG7C,MAAM,sBAAsB;;AAG5B,MAAM,0BAA0B;CAAC;CAAa;CAAe;AAAW;;;;;;AAOxE,SAAgB,4BAA4B,OAAwB;CAClE,OAAO,oBAAoB,KAAK,KAAK,KAAK,CAAC,wBAAwB,MAAM,cAAc,cAAc,KAAK;AAC5G;;;;;;;;;AAaA,SAAS,yBAAyB,UAA4D;CAK5F,MAAM,WAAW,OAAO,YAAY,cAAc,QAAQ,IAAI,oCAAoC,KAAA;CAElG,KAAK,MAAM,aAAa,CAAC,UAAU,QAAQ,GAAG;EAC5C,IAAI,cAAc,KAAA,GAAW;EAC7B,MAAM,UAAU,UAAU,KAAK;EAC/B,IAAI,QAAQ,WAAW,GAAG;EAC1B,OAAO;GAAE,OAAO;GAAS,OAAO,4BAA4B,OAAO;EAAE;CACvE;AAEF;;;;;;;;;;;;AAaA,SAAgB,4BAA4B,SAGnB;CACvB,MAAM,UAAU,yBAAyB,SAAS,QAAQ;CAC1D,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,IAAI,QAAQ,OAAO,OAAO,QAAQ;CAElC,MAAM,qBAAqB,SAAS;CACpC,IAAI,CAAC,oBAAoB,SAAS;EAChC,MAAM,UACJ,qBAAqB,KAAK,UAAU,QAAQ,KAAK,EAAE,yDAChC,KAAK,UAAU,6BAA6B;EACjE,QAAQ,MAAM,OAAO;EACrB,IAAI,oBAAoB,mBAAmB,UAAU;CACvD;CACA,OAAO;AACT;;;;;AAiBA,MAAM,8BAA8B,cAAgD,KAAA,CAAS;;;;;;;AAQ7F,SAAgB,6BAA6B,EAAE,aAAa,YAA0D;CACpH,OAAO,oBAAC,4BAA4B,UAA7B;EAAsC,OAAO;EAAc;CAA+C,CAAA;AACnH;;AAGA,SAAgB,0BAA4D;CAC1E,OAAO,WAAW,2BAA2B;AAC/C"}
@@ -0,0 +1,57 @@
1
+ import "../../core/dist/index.js";
2
+ //#region src/sdk/analytics/use-analytics-actions.d.ts
3
+ /**
4
+ * The `analytics` action namespace (specs/analytics-events.md) — a dispatcher-flavor namespace
5
+ * (docs/storefront-core/adr-0010-actions-own-the-write-side.md; docs/storefront-core/rfc-actions.md
6
+ * § "Three binding flavors") that pushes the two standard payment analytics events,
7
+ * `add_payment_info` and `purchase`, to a `window` array — `window.dataLayer` by default, the
8
+ * GTM/GA4-recognizable event convention. It never touches the Apollo cache, never issues a GraphQL
9
+ * operation, and never throws: a broken tag-manager script can never block payment submission or
10
+ * order placement.
11
+ *
12
+ * The destination array is configurable at build time
13
+ * (specs/make-the-analytics-destination-configurable-for.md; T120) — see
14
+ * `./analytics-destination.js` for the resolution precedence, validation, and the
15
+ * `AnalyticsDestinationProvider`. The pushed entry's shape is a data *contract* (a well-known
16
+ * browser-global array shape), not a *provider* — no vendor SDK, no server call. A future
17
+ * platform/foundation epic may replace this sink with a real `AnalyticsContext`; the
18
+ * `track(event: AnalyticsEvent): void` signature and `AnalyticsActions` type are the stable public
19
+ * contract every call site depends on until then (US-4).
20
+ */
21
+ export type AnalyticsMoney = Readonly<{
22
+ amount: number;
23
+ currencyCode: string;
24
+ }>;
25
+ export type AnalyticsLineItem = Readonly<{
26
+ sku: string;
27
+ name: string;
28
+ price: AnalyticsMoney;
29
+ quantity: number;
30
+ }>;
31
+ /** Dispatched by T7's CardEntry, before opening the transaction. */
32
+ export type AddPaymentInfoEvent = Readonly<{
33
+ name: 'add_payment_info';
34
+ value: AnalyticsMoney;
35
+ /**
36
+ * Derived from the selected method's `groupName` at the moment this fires (T140, Decision 5).
37
+ * Optional because the event fires on the cart total, before a method is necessarily selected —
38
+ * omitted rather than a guessed literal, so a downstream consumer never reads a false payment kind.
39
+ * `toEcommercePayload` below drops the corresponding key entirely when this is absent.
40
+ */
41
+ paymentType?: 'Credit Card' | 'Debit Card';
42
+ items?: readonly AnalyticsLineItem[];
43
+ }>;
44
+ /** Dispatched by T13's usePlaceOrder, after a successful gateway callback. */
45
+ export type PurchaseEvent = Readonly<{
46
+ name: 'purchase';
47
+ transactionId: string;
48
+ value: AnalyticsMoney;
49
+ items?: readonly AnalyticsLineItem[];
50
+ }>;
51
+ export type AnalyticsEvent = AddPaymentInfoEvent | PurchaseEvent;
52
+ export type AnalyticsActions = Readonly<{
53
+ /** Push a standard analytics event to window.dataLayer. Fire-and-forget; never throws. */
54
+ track: (event: AnalyticsEvent) => void;
55
+ }>;
56
+ //#endregion
57
+ //# sourceMappingURL=use-analytics-actions.d.ts.map
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ import { defineActions } from "../../core/dist/actions/registry.js";
3
+ import "../../core/dist/index.js";
4
+ import { DEFAULT_ANALYTICS_DESTINATION, resolveAnalyticsDestination, useAnalyticsDestination } from "./analytics-destination.js";
5
+ import { useCallback, useMemo, useRef } from "react";
6
+ //#region src/sdk/analytics/use-analytics-actions.ts
7
+ function toEcommerceItems(items) {
8
+ return (items ?? []).map((item) => ({
9
+ item_id: item.sku,
10
+ item_name: item.name,
11
+ price: item.price.amount,
12
+ quantity: item.quantity
13
+ }));
14
+ }
15
+ function toEcommercePayload(event) {
16
+ if (event.name === "add_payment_info") return {
17
+ currency: event.value.currencyCode,
18
+ value: event.value.amount,
19
+ ...event.paymentType !== void 0 ? { payment_type: event.paymentType } : {},
20
+ items: toEcommerceItems(event.items)
21
+ };
22
+ return {
23
+ transaction_id: event.transactionId,
24
+ currency: event.value.currencyCode,
25
+ value: event.value.amount,
26
+ items: toEcommerceItems(event.items)
27
+ };
28
+ }
29
+ function pushToDataLayer(event, destination) {
30
+ if (typeof window === "undefined") return;
31
+ let layer = Reflect.get(window, destination);
32
+ if (layer === void 0) {
33
+ layer = [];
34
+ Reflect.set(window, destination, layer);
35
+ } else if (!Array.isArray(layer)) {
36
+ console.error(`[analytics.track] window.${destination} already exists and is not an array; the event was dropped`);
37
+ return;
38
+ }
39
+ layer.push({
40
+ event: event.name,
41
+ ecommerce: toEcommercePayload(event)
42
+ });
43
+ }
44
+ /**
45
+ * The `analytics` namespace hook. Registered with the first-party action registry via
46
+ * `analyticsActions` below; the compiler-emitted `AnalyticsActionProvider` calls it and threads
47
+ * the narrowed methods into each consumer's `$actions.analytics`. Dispatcher flavor: no
48
+ * `useMutation`, no cache read or write (ADR-0010). Fire-and-forget — `track` never throws, so a
49
+ * broken tag-manager script can never block payment submission or order placement.
50
+ */
51
+ function useAnalyticsActions() {
52
+ const override = useAnalyticsDestination();
53
+ const hasLoggedRejectionRef = useRef(false);
54
+ const track = useCallback((event) => {
55
+ if (typeof window === "undefined") return;
56
+ let destination = DEFAULT_ANALYTICS_DESTINATION;
57
+ try {
58
+ destination = resolveAnalyticsDestination({
59
+ override,
60
+ hasLoggedRejection: hasLoggedRejectionRef
61
+ });
62
+ pushToDataLayer(event, destination);
63
+ } catch (error) {
64
+ console.error(`[analytics.track] window.${destination} push failed`, error);
65
+ }
66
+ }, [override]);
67
+ return useMemo(() => ({ track }), [track]);
68
+ }
69
+ defineActions({
70
+ namespace: "analytics",
71
+ description: "Dispatcher-flavor namespace that pushes standard add_payment_info / purchase events to window.dataLayer. Never touches the Apollo cache.",
72
+ provider: {
73
+ name: "AnalyticsActionProvider",
74
+ importPath: "@vtex/faststore/internal/client"
75
+ },
76
+ methods: { track: {
77
+ description: "Push a standard analytics event (add_payment_info | purchase) to window.dataLayer. Fire-and-forget; never throws.",
78
+ payload: [
79
+ {
80
+ name: "name",
81
+ type: "string"
82
+ },
83
+ {
84
+ name: "currencyCode",
85
+ type: "string"
86
+ },
87
+ {
88
+ name: "amount",
89
+ type: "number"
90
+ },
91
+ {
92
+ name: "paymentType",
93
+ type: "string",
94
+ optional: true
95
+ },
96
+ {
97
+ name: "transactionId",
98
+ type: "string",
99
+ optional: true
100
+ }
101
+ ]
102
+ } },
103
+ use: useAnalyticsActions
104
+ });
105
+ //#endregion
106
+ export { useAnalyticsActions };
107
+
108
+ //# sourceMappingURL=use-analytics-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-analytics-actions.js","names":[],"sources":["../../../src/sdk/analytics/use-analytics-actions.ts"],"sourcesContent":["'use client';\n\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo, useRef } from 'react';\nimport {\n type AnalyticsDestination,\n DEFAULT_ANALYTICS_DESTINATION,\n resolveAnalyticsDestination,\n useAnalyticsDestination,\n} from './analytics-destination.js';\n\n/**\n * The `analytics` action namespace (specs/analytics-events.md) — a dispatcher-flavor namespace\n * (docs/storefront-core/adr-0010-actions-own-the-write-side.md; docs/storefront-core/rfc-actions.md\n * § \"Three binding flavors\") that pushes the two standard payment analytics events,\n * `add_payment_info` and `purchase`, to a `window` array — `window.dataLayer` by default, the\n * GTM/GA4-recognizable event convention. It never touches the Apollo cache, never issues a GraphQL\n * operation, and never throws: a broken tag-manager script can never block payment submission or\n * order placement.\n *\n * The destination array is configurable at build time\n * (specs/make-the-analytics-destination-configurable-for.md; T120) — see\n * `./analytics-destination.js` for the resolution precedence, validation, and the\n * `AnalyticsDestinationProvider`. The pushed entry's shape is a data *contract* (a well-known\n * browser-global array shape), not a *provider* — no vendor SDK, no server call. A future\n * platform/foundation epic may replace this sink with a real `AnalyticsContext`; the\n * `track(event: AnalyticsEvent): void` signature and `AnalyticsActions` type are the stable public\n * contract every call site depends on until then (US-4).\n */\n\nexport type AnalyticsMoney = Readonly<{\n amount: number;\n currencyCode: string;\n}>;\n\nexport type AnalyticsLineItem = Readonly<{\n sku: string;\n name: string;\n price: AnalyticsMoney;\n quantity: number;\n}>;\n\n/** Dispatched by T7's CardEntry, before opening the transaction. */\nexport type AddPaymentInfoEvent = Readonly<{\n name: 'add_payment_info';\n value: AnalyticsMoney;\n /**\n * Derived from the selected method's `groupName` at the moment this fires (T140, Decision 5).\n * Optional because the event fires on the cart total, before a method is necessarily selected —\n * omitted rather than a guessed literal, so a downstream consumer never reads a false payment kind.\n * `toEcommercePayload` below drops the corresponding key entirely when this is absent.\n */\n paymentType?: 'Credit Card' | 'Debit Card';\n items?: readonly AnalyticsLineItem[];\n}>;\n\n/** Dispatched by T13's usePlaceOrder, after a successful gateway callback. */\nexport type PurchaseEvent = Readonly<{\n name: 'purchase';\n transactionId: string;\n value: AnalyticsMoney;\n items?: readonly AnalyticsLineItem[];\n}>;\n\nexport type AnalyticsEvent = AddPaymentInfoEvent | PurchaseEvent;\n\nexport type AnalyticsActions = Readonly<{\n /** Push a standard analytics event to window.dataLayer. Fire-and-forget; never throws. */\n track: (event: AnalyticsEvent) => void;\n}>;\n\n/** The shape pushed onto window.dataLayer — GTM/GA4's own event convention. */\nexport type AnalyticsDataLayerEvent = Readonly<{\n event: 'add_payment_info' | 'purchase';\n ecommerce: Record<string, unknown>;\n}>;\n\nfunction toEcommerceItems(items: readonly AnalyticsLineItem[] | undefined) {\n return (items ?? []).map((item) => ({\n item_id: item.sku,\n item_name: item.name,\n price: item.price.amount,\n quantity: item.quantity,\n }));\n}\n\nfunction toEcommercePayload(event: AnalyticsEvent): Record<string, unknown> {\n if (event.name === 'add_payment_info') {\n return {\n currency: event.value.currencyCode,\n value: event.value.amount,\n // T140, Decision 5: the key itself must be absent when `paymentType` is, not merely `undefined`\n // — `pushToDataLayer` pushes this object as-is with no serialization step to strip it, and\n // `'payment_type' in ecommerce` would otherwise still report true.\n ...(event.paymentType !== undefined ? { payment_type: event.paymentType } : {}),\n items: toEcommerceItems(event.items),\n };\n }\n return {\n transaction_id: event.transactionId,\n currency: event.value.currencyCode,\n value: event.value.amount,\n items: toEcommerceItems(event.items),\n };\n}\n\n// `Reflect.get`/`Reflect.set` below match `storefront-provider.tsx`'s existing pattern for a\n// dynamic `window` key — they are not a security mechanism. `Reflect.set(target, k, v)` invokes\n// an inherited setter and creates no own property, exactly like `window[k] = v` would; it adds no\n// hardening on its own. What actually blocks prototype pollution is\n// `isValidAnalyticsDestination`'s denylist and identifier pattern, checked by the caller before\n// `destination` ever reaches this function, plus the non-array guard immediately below.\n//\n// The cast below, not a `declare global` augmentation of `Window`, is what keeps this typed: a\n// global augmentation here would ship inside this package's own `.d.ts` output and hand every\n// consumer's `window.dataLayer` this package's narrow event union, wrong for a store that also\n// pushes its own GTM events (packages/components/scripts/dist-type-boundary.test.ts). `destination`\n// is a runtime string anyway — `Window` has nothing to look up a dynamic key against — so the local\n// cast is also the only type-safe option, not merely the non-leaking one.\nfunction pushToDataLayer(event: AnalyticsEvent, destination: AnalyticsDestination): void {\n if (typeof window === 'undefined') return;\n\n let layer = Reflect.get(window, destination) as AnalyticsDataLayerEvent[] | undefined;\n if (layer === undefined) {\n layer = [];\n Reflect.set(window, destination, layer);\n } else if (!Array.isArray(layer)) {\n console.error(`[analytics.track] window.${destination} already exists and is not an array; the event was dropped`);\n return;\n }\n\n layer.push({ event: event.name, ecommerce: toEcommercePayload(event) });\n}\n\n/**\n * The `analytics` namespace hook. Registered with the first-party action registry via\n * `analyticsActions` below; the compiler-emitted `AnalyticsActionProvider` calls it and threads\n * the narrowed methods into each consumer's `$actions.analytics`. Dispatcher flavor: no\n * `useMutation`, no cache read or write (ADR-0010). Fire-and-forget — `track` never throws, so a\n * broken tag-manager script can never block payment submission or order placement.\n */\nexport function useAnalyticsActions(): AnalyticsActions {\n const override = useAnalyticsDestination();\n // Scoped to this hook instance, not the module: \"logs once\" means once per mounted\n // `useAnalyticsActions()`, so two independent call sites each still get their own first warning.\n const hasLoggedRejectionRef = useRef(false);\n\n const track = useCallback<AnalyticsActions['track']>(\n (event) => {\n // The SSR guard runs before any destination resolution is attempted — not just before the\n // write. Preserved from the pre-T120 behaviour (US-3, \"SSR — no destination resolution\n // attempted at all\").\n if (typeof window === 'undefined') return;\n let destination: AnalyticsDestination = DEFAULT_ANALYTICS_DESTINATION;\n try {\n destination = resolveAnalyticsDestination({\n override,\n hasLoggedRejection: hasLoggedRejectionRef,\n });\n pushToDataLayer(event, destination);\n } catch (error) {\n console.error(`[analytics.track] window.${destination} push failed`, error);\n }\n },\n [override],\n );\n\n return useMemo(() => ({ track }), [track]);\n}\n\n/**\n * Declares the `analytics` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`, `shippingActions`). The\n * native catalog builder (`scripts/build-catalog.mjs`) statically reads this call to emit\n * `actions.json`; at runtime `AnalyticsActionProvider` calls `useAnalyticsActions` directly.\n *\n * The `payload` below is a flattened, best-effort scalar approximation of `AnalyticsEvent` for\n * catalog/docs tooling: `ActionPayloadField.type` supports only scalar primitives and cannot\n * express a discriminated union or a nested `items` array. The TS `AnalyticsEvent` union above is\n * the source of truth for the real call shape.\n */\nexport const analyticsActions = defineActions({\n namespace: 'analytics',\n description:\n 'Dispatcher-flavor namespace that pushes standard add_payment_info / purchase events to window.dataLayer. Never touches the Apollo cache.',\n provider: { name: 'AnalyticsActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n track: {\n description:\n 'Push a standard analytics event (add_payment_info | purchase) to window.dataLayer. Fire-and-forget; never throws.',\n payload: [\n { name: 'name', type: 'string' },\n { name: 'currencyCode', type: 'string' },\n { name: 'amount', type: 'number' },\n { name: 'paymentType', type: 'string', optional: true },\n { name: 'transactionId', type: 'string', optional: true },\n ],\n },\n },\n use: useAnalyticsActions,\n});\n"],"mappings":";;;;;;AA6EA,SAAS,iBAAiB,OAAiD;CACzE,QAAQ,SAAS,CAAC,EAAA,CAAG,KAAK,UAAU;EAClC,SAAS,KAAK;EACd,WAAW,KAAK;EAChB,OAAO,KAAK,MAAM;EAClB,UAAU,KAAK;CACjB,EAAE;AACJ;AAEA,SAAS,mBAAmB,OAAgD;CAC1E,IAAI,MAAM,SAAS,oBACjB,OAAO;EACL,UAAU,MAAM,MAAM;EACtB,OAAO,MAAM,MAAM;EAInB,GAAI,MAAM,gBAAgB,KAAA,IAAY,EAAE,cAAc,MAAM,YAAY,IAAI,CAAC;EAC7E,OAAO,iBAAiB,MAAM,KAAK;CACrC;CAEF,OAAO;EACL,gBAAgB,MAAM;EACtB,UAAU,MAAM,MAAM;EACtB,OAAO,MAAM,MAAM;EACnB,OAAO,iBAAiB,MAAM,KAAK;CACrC;AACF;AAeA,SAAS,gBAAgB,OAAuB,aAAyC;CACvF,IAAI,OAAO,WAAW,aAAa;CAEnC,IAAI,QAAQ,QAAQ,IAAI,QAAQ,WAAW;CAC3C,IAAI,UAAU,KAAA,GAAW;EACvB,QAAQ,CAAC;EACT,QAAQ,IAAI,QAAQ,aAAa,KAAK;CACxC,OAAO,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;EAChC,QAAQ,MAAM,4BAA4B,YAAY,2DAA2D;EACjH;CACF;CAEA,MAAM,KAAK;EAAE,OAAO,MAAM;EAAM,WAAW,mBAAmB,KAAK;CAAE,CAAC;AACxE;;;;;;;;AASA,SAAgB,sBAAwC;CACtD,MAAM,WAAW,wBAAwB;CAGzC,MAAM,wBAAwB,OAAO,KAAK;CAE1C,MAAM,QAAQ,aACX,UAAU;EAIT,IAAI,OAAO,WAAW,aAAa;EACnC,IAAI,cAAoC;EACxC,IAAI;GACF,cAAc,4BAA4B;IACxC;IACA,oBAAoB;GACtB,CAAC;GACD,gBAAgB,OAAO,WAAW;EACpC,SAAS,OAAO;GACd,QAAQ,MAAM,4BAA4B,YAAY,eAAe,KAAK;EAC5E;CACF,GACA,CAAC,QAAQ,CACX;CAEA,OAAO,eAAe,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC;AAC3C;AAagC,cAAc;CAC5C,WAAW;CACX,aACE;CACF,UAAU;EAAE,MAAM;EAA2B,YAAY;CAAkC;CAC3F,SAAS,EACP,OAAO;EACL,aACE;EACF,SAAS;GACP;IAAE,MAAM;IAAQ,MAAM;GAAS;GAC/B;IAAE,MAAM;IAAgB,MAAM;GAAS;GACvC;IAAE,MAAM;IAAU,MAAM;GAAS;GACjC;IAAE,MAAM;IAAe,MAAM;IAAU,UAAU;GAAK;GACtD;IAAE,MAAM;IAAiB,MAAM;IAAU,UAAU;GAAK;EAC1D;CACF,EACF;CACA,KAAK;AACP,CAAC"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { defineActions } from "../../core/dist/actions/registry.js";
3
3
  import "../../core/dist/index.js";
4
- import { cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, orderFormIdVar } from "../state/cart.js";
5
4
  import { CART_COUPON_APPLY, CART_COUPON_REMOVE, CART_ITEMS_REMOVE, CART_ITEM_ADD, CART_ITEM_QUANTITY_DECREASE, CART_ITEM_QUANTITY_INCREASE, CART_ITEM_REMOVE, CART_VALIDATE, CartFragment } from "./operations.js";
5
+ import { cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, orderFormIdVar } from "../state/cart.js";
6
6
  import { buildOptimisticDecrease, buildOptimisticIncrease, buildOptimisticRemove, buildOptimisticRemoveItems } from "./optimistic.js";
7
7
  import { markAvailabilityFresh, trackCartWrite } from "./write-gate.js";
8
8
  import { useApolloClient, useMutation } from "@apollo/client/react";
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { createContext, useContext } from "react";
3
+ //#region src/sdk/data/entity-resolution-context.ts
4
+ /**
5
+ * Is the `$data` reaching this subtree the cache's own answer for the entity the page query
6
+ * currently points at, or the server-rendered `fallbackData` standing in for one?
7
+ *
8
+ * `DataOverrideContext` carries the slice and cannot carry this: a fallback slice and a resolved
9
+ * one are the same shape, and an entity whose saved values are genuinely absent looks exactly like
10
+ * an entity whose cache read regressed. Only `useReactiveEntity` knows which of the two it just
11
+ * handed down, so it is the one that publishes here — see its `resolved` return.
12
+ *
13
+ * Default `true`: with no reactive provider above, nothing is outstanding. Storybook, unit tests and
14
+ * any tree handing `$data` over as a plain prop read the default and gate nothing, exactly as they
15
+ * do with `useReactiveDataSettled`.
16
+ */
17
+ const EntityResolutionContext = createContext(true);
18
+ /**
19
+ * Every entity slice composed into this subtree's `$data` is the cache's own answer.
20
+ *
21
+ * Unlike `useReactiveDataSettled`, this is not latched: it re-arms on its own whenever the entity
22
+ * ref moves or its cache read stops being complete, which is the whole point — a latched page-level
23
+ * signal cannot tell a form that the data under it has gone back to being a placeholder.
24
+ */
25
+ function useEntityDataResolved() {
26
+ return useContext(EntityResolutionContext);
27
+ }
28
+ //#endregion
29
+ export { EntityResolutionContext, useEntityDataResolved };
30
+
31
+ //# sourceMappingURL=entity-resolution-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-resolution-context.js","names":[],"sources":["../../../src/sdk/data/entity-resolution-context.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Is the `$data` reaching this subtree the cache's own answer for the entity the page query\n * currently points at, or the server-rendered `fallbackData` standing in for one?\n *\n * `DataOverrideContext` carries the slice and cannot carry this: a fallback slice and a resolved\n * one are the same shape, and an entity whose saved values are genuinely absent looks exactly like\n * an entity whose cache read regressed. Only `useReactiveEntity` knows which of the two it just\n * handed down, so it is the one that publishes here — see its `resolved` return.\n *\n * Default `true`: with no reactive provider above, nothing is outstanding. Storybook, unit tests and\n * any tree handing `$data` over as a plain prop read the default and gate nothing, exactly as they\n * do with `useReactiveDataSettled`.\n */\nexport const EntityResolutionContext = createContext<boolean>(true);\n\n/**\n * Every entity slice composed into this subtree's `$data` is the cache's own answer.\n *\n * Unlike `useReactiveDataSettled`, this is not latched: it re-arms on its own whenever the entity\n * ref moves or its cache read stops being complete, which is the whole point — a latched page-level\n * signal cannot tell a form that the data under it has gone back to being a placeholder.\n */\nexport function useEntityDataResolved(): boolean {\n return useContext(EntityResolutionContext);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAa,0BAA0B,cAAuB,IAAI;;;;;;;;AASlE,SAAgB,wBAAiC;CAC/C,OAAO,WAAW,uBAAuB;AAC3C"}
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import { DataOverrideContext } from "./data-override-context.js";
3
+ import { EntityResolutionContext } from "./entity-resolution-context.js";
3
4
  import { useReactiveEntity } from "./use-reactive-entity.js";
4
- import { useContext } from "react";
5
+ import { useContext, useMemo } from "react";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  //#region src/sdk/data/entity-subscriber.tsx
7
8
  /**
@@ -12,14 +13,23 @@ import { jsx } from "react/jsx-runtime";
12
13
  */
13
14
  function EntitySubscriber({ entityFragment, fragmentName, rootField, fallbackData, reset, children }) {
14
15
  const outer = useContext(DataOverrideContext);
15
- const resolved = useReactiveEntity(entityFragment, fragmentName, rootField, fallbackData);
16
- const value = reset ? { [rootField]: resolved } : {
16
+ const outerResolved = useContext(EntityResolutionContext);
17
+ const { data, resolved } = useReactiveEntity(entityFragment, fragmentName, rootField, fallbackData);
18
+ const value = useMemo(() => reset ? { [rootField]: data } : {
17
19
  ...outer && typeof outer === "object" ? outer : {},
18
- [rootField]: resolved
19
- };
20
- return /* @__PURE__ */ jsx(DataOverrideContext, {
21
- value,
22
- children
20
+ [rootField]: data
21
+ }, [
22
+ reset,
23
+ rootField,
24
+ data,
25
+ outer
26
+ ]);
27
+ return /* @__PURE__ */ jsx(EntityResolutionContext, {
28
+ value: reset ? resolved : outerResolved && resolved,
29
+ children: /* @__PURE__ */ jsx(DataOverrideContext, {
30
+ value,
31
+ children
32
+ })
23
33
  });
24
34
  }
25
35
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"entity-subscriber.js","names":[],"sources":["../../../src/sdk/data/entity-subscriber.tsx"],"sourcesContent":["'use client';\n\nimport type { DocumentNode } from '@apollo/client';\nimport type { ReactNode } from 'react';\nimport { useContext } from 'react';\nimport { DataOverrideContext } from './data-override-context.js';\nimport { useReactiveEntity } from './use-reactive-entity.js';\n\nexport type EntitySubscriberProps = Readonly<{\n /** Derived `fragment <X>_<EntityType> on <EntityType>` document emitted by the compiler. */\n entityFragment: DocumentNode;\n /** Name of the derived fragment, passed to `useFragment`. */\n fragmentName: string;\n /** Top-level field of the page query (e.g. 'cart') used to extract the entity ref, and the key\n * under which the resolved slice is merged into the composed `$data` object. */\n rootField: string;\n /** Server-rendered fragment payload; used until the cache resolves a complete entity slice. */\n fallbackData: unknown;\n /**\n * When `true`, RESETS the context to `{ [rootField]: resolved }`, discarding any outer\n * `DataOverrideContext` value — this is the outermost subscriber of a component's nested stack,\n * and prevents a parent component's `$data` from leaking into this component's descendants. When\n * `false`, merges this subscriber's slice into the SAME-stack outer value instead.\n */\n reset: boolean;\n children: ReactNode;\n}>;\n\n/**\n * Per-entity subscriber used internally by `MultipleReactiveDataProvider` to compose several\n * entities' cache slices into one keyed `$data` object for a single component. Resolves its own\n * slice exactly like `ReactiveDataProvider` (see `useReactiveEntity`), then merges it under\n * `rootField` into the outer `DataOverrideContext` value.\n */\nexport function EntitySubscriber({\n entityFragment,\n fragmentName,\n rootField,\n fallbackData,\n reset,\n children,\n}: EntitySubscriberProps): ReactNode {\n const outer = useContext(DataOverrideContext);\n const resolved = useReactiveEntity(entityFragment, fragmentName, rootField, fallbackData);\n\n const value = reset\n ? { [rootField]: resolved }\n : { ...(outer && typeof outer === 'object' ? outer : {}), [rootField]: resolved };\n\n return <DataOverrideContext value={value}>{children}</DataOverrideContext>;\n}\n"],"mappings":";;;;;;;;;;;;AAkCA,SAAgB,iBAAiB,EAC/B,gBACA,cACA,WACA,cACA,OACA,YACmC;CACnC,MAAM,QAAQ,WAAW,mBAAmB;CAC5C,MAAM,WAAW,kBAAkB,gBAAgB,cAAc,WAAW,YAAY;CAExF,MAAM,QAAQ,QACV,GAAG,YAAY,SAAS,IACxB;EAAE,GAAI,SAAS,OAAO,UAAU,WAAW,QAAQ,CAAC;GAAK,YAAY;CAAS;CAElF,OAAO,oBAAC,qBAAD;EAA4B;EAAQ;CAA8B,CAAA;AAC3E"}
1
+ {"version":3,"file":"entity-subscriber.js","names":[],"sources":["../../../src/sdk/data/entity-subscriber.tsx"],"sourcesContent":["'use client';\n\nimport type { DocumentNode } from '@apollo/client';\nimport type { ReactNode } from 'react';\nimport { useContext, useMemo } from 'react';\nimport { DataOverrideContext } from './data-override-context.js';\nimport { EntityResolutionContext } from './entity-resolution-context.js';\nimport { useReactiveEntity } from './use-reactive-entity.js';\n\nexport type EntitySubscriberProps = Readonly<{\n /** Derived `fragment <X>_<EntityType> on <EntityType>` document emitted by the compiler. */\n entityFragment: DocumentNode;\n /** Name of the derived fragment, passed to `useFragment`. */\n fragmentName: string;\n /** Top-level field of the page query (e.g. 'cart') used to extract the entity ref, and the key\n * under which the resolved slice is merged into the composed `$data` object. */\n rootField: string;\n /** Server-rendered fragment payload; used until the cache resolves a complete entity slice. */\n fallbackData: unknown;\n /**\n * When `true`, RESETS the context to `{ [rootField]: resolved }`, discarding any outer\n * `DataOverrideContext` value — this is the outermost subscriber of a component's nested stack,\n * and prevents a parent component's `$data` from leaking into this component's descendants. When\n * `false`, merges this subscriber's slice into the SAME-stack outer value instead.\n */\n reset: boolean;\n children: ReactNode;\n}>;\n\n/**\n * Per-entity subscriber used internally by `MultipleReactiveDataProvider` to compose several\n * entities' cache slices into one keyed `$data` object for a single component. Resolves its own\n * slice exactly like `ReactiveDataProvider` (see `useReactiveEntity`), then merges it under\n * `rootField` into the outer `DataOverrideContext` value.\n */\nexport function EntitySubscriber({\n entityFragment,\n fragmentName,\n rootField,\n fallbackData,\n reset,\n children,\n}: EntitySubscriberProps): ReactNode {\n const outer = useContext(DataOverrideContext);\n const outerResolved = useContext(EntityResolutionContext);\n const { data, resolved } = useReactiveEntity(entityFragment, fragmentName, rootField, fallbackData);\n\n // Memoised because this object is the context value: a fresh identity on every render makes every\n // consumer below re-render, and in a form that is every keystroke. Its two sibling providers pass a\n // stable reference already.\n const value = useMemo(\n () => (reset ? { [rootField]: data } : { ...(outer && typeof outer === 'object' ? outer : {}), [rootField]: data }),\n [reset, rootField, data, outer],\n );\n\n // Mirrors the data merge exactly: the composed `$data` is resolved only when every slice merged\n // into it is. `reset` discards the outer verdict for the same reason it discards the outer value —\n // that verdict belongs to an ancestor component's own entities, not to this component's.\n const resolution = reset ? resolved : outerResolved && resolved;\n\n return (\n <EntityResolutionContext value={resolution}>\n <DataOverrideContext value={value}>{children}</DataOverrideContext>\n </EntityResolutionContext>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAmCA,SAAgB,iBAAiB,EAC/B,gBACA,cACA,WACA,cACA,OACA,YACmC;CACnC,MAAM,QAAQ,WAAW,mBAAmB;CAC5C,MAAM,gBAAgB,WAAW,uBAAuB;CACxD,MAAM,EAAE,MAAM,aAAa,kBAAkB,gBAAgB,cAAc,WAAW,YAAY;CAKlG,MAAM,QAAQ,cACL,QAAQ,GAAG,YAAY,KAAK,IAAI;EAAE,GAAI,SAAS,OAAO,UAAU,WAAW,QAAQ,CAAC;GAAK,YAAY;CAAK,GACjH;EAAC;EAAO;EAAW;EAAM;CAAK,CAChC;CAOA,OACE,oBAAC,yBAAD;EAAyB,OAHR,QAAQ,WAAW,iBAAiB;EAInD,UAAA,oBAAC,qBAAD;GAA4B;GAAQ;EAA8B,CAAA;CAC3C,CAAA;AAE7B"}
@@ -2,6 +2,7 @@ import { DataOverrideContext, useDataOverride } from "./data-override-context.js
2
2
  import { HotDataProvider } from "./hot-data-provider.js";
3
3
  import { ListItemRefContext, useListItemRef } from "./list-item-ref-context.js";
4
4
  import { PageReactiveDataRoot, ReactiveRootContext } from "./page-reactive-data-root.js";
5
+ import "./entity-resolution-context.js";
5
6
  import { MultipleReactiveDataProvider } from "./multiple-reactive-data-provider.js";
6
7
  import { ReactiveDataProvider } from "./reactive-data-provider.js";
7
8
  import { ReactiveListItemDataProvider } from "./reactive-list-item-data-provider.js";