@cartbase/storefront 0.20.0 → 0.20.1

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 (99) hide show
  1. package/LICENSE +21 -21
  2. package/package.json +258 -258
  3. package/src/api/auth.ts +108 -108
  4. package/src/api/carts.ts +523 -523
  5. package/src/api/categories.ts +184 -184
  6. package/src/api/checkout.ts +526 -526
  7. package/src/api/collections.ts +130 -130
  8. package/src/api/consent.ts +75 -75
  9. package/src/api/content.ts +125 -125
  10. package/src/api/customers.ts +303 -303
  11. package/src/api/gift-cards.ts +112 -112
  12. package/src/api/http.ts +180 -180
  13. package/src/api/index.ts +30 -30
  14. package/src/api/menus.ts +77 -77
  15. package/src/api/metaobjects.ts +136 -136
  16. package/src/api/orders.ts +290 -290
  17. package/src/api/redirects.ts +37 -37
  18. package/src/api/regions.ts +200 -200
  19. package/src/api/search.ts +163 -163
  20. package/src/api/store.ts +35 -35
  21. package/src/api/types.ts +91 -91
  22. package/src/cart-drawer/context.tsx +778 -778
  23. package/src/cart-drawer/cross-sell-carousel.tsx +211 -211
  24. package/src/cart-drawer/cross-sell-sidebar.tsx +158 -158
  25. package/src/cart-drawer/gift-wrap.tsx +82 -82
  26. package/src/cart-drawer/item/index.tsx +162 -162
  27. package/src/cart-drawer/item/upsell.tsx +110 -110
  28. package/src/cart-drawer/labels.ts +123 -123
  29. package/src/cart-drawer/mutation-queue.ts +78 -78
  30. package/src/cart-drawer/notes.tsx +131 -131
  31. package/src/cart-drawer/sticky-footer.tsx +73 -73
  32. package/src/cart-drawer/summary-breakdown.tsx +197 -197
  33. package/src/checkout/address-error-copy.ts +117 -117
  34. package/src/checkout/boxnow-locker-selector.tsx +410 -410
  35. package/src/checkout/compare-addresses.ts +40 -40
  36. package/src/checkout/discount-section.tsx +218 -218
  37. package/src/checkout/error-copy-codes.ts +63 -63
  38. package/src/checkout/geocode.ts +154 -154
  39. package/src/checkout/gift-card-section.tsx +224 -224
  40. package/src/checkout/index.ts +72 -72
  41. package/src/checkout/labels.ts +495 -495
  42. package/src/checkout/payment-button.tsx +372 -372
  43. package/src/checkout/payment-error-copy.ts +154 -154
  44. package/src/checkout/promotion-error-copy.ts +91 -91
  45. package/src/common/country-flag.tsx +52 -52
  46. package/src/common/country-select.tsx +11 -11
  47. package/src/common/index.ts +20 -20
  48. package/src/common/market-select.tsx +57 -57
  49. package/src/index.ts +12 -12
  50. package/src/lib/country-name.ts +59 -59
  51. package/src/lib/get-product-price.ts +133 -133
  52. package/src/lib/media-image.tsx +39 -39
  53. package/src/lib/payment-constants.ts +53 -53
  54. package/src/lib/platform.ts +13 -13
  55. package/src/lib/price.tsx +39 -39
  56. package/src/lib/store-api-error.ts +36 -36
  57. package/src/lib/variant-caption.ts +32 -32
  58. package/src/locales/context.ts +37 -37
  59. package/src/locales/en.ts +26 -26
  60. package/src/locales/index.ts +19 -19
  61. package/src/locales/provider.tsx +59 -59
  62. package/src/locales/types.ts +77 -77
  63. package/src/order/index.ts +62 -62
  64. package/src/order/labels.ts +79 -79
  65. package/src/order/order-totals.tsx +250 -250
  66. package/src/primitives/select-field.tsx +93 -93
  67. package/src/products/image-gallery.tsx +43 -43
  68. package/src/products/option-select.tsx +67 -67
  69. package/src/products/product-info.tsx +5 -5
  70. package/src/products/product-price.tsx +69 -69
  71. package/src/products/product-promises.tsx +61 -61
  72. package/src/products/product-specs.tsx +65 -65
  73. package/src/products/product-tabs.tsx +123 -123
  74. package/src/products/purchase-options.tsx +130 -130
  75. package/src/products/sets.ts +110 -110
  76. package/src/products/variant-matching.ts +71 -71
  77. package/src/products/variant-url.ts +74 -74
  78. package/src/reviews-ui/lightbox-state.ts +46 -46
  79. package/src/reviews-ui/review-header.tsx +166 -166
  80. package/src/reviews-ui/review-lightbox.tsx +271 -271
  81. package/src/reviews-ui/review-list.tsx +193 -193
  82. package/src/reviews-ui/review-widget.tsx +219 -218
  83. package/src/reviews-ui/widget-options.ts +55 -55
  84. package/src/store/category-template.tsx +136 -136
  85. package/src/store/index.ts +40 -40
  86. package/src/tracking/chatgpt-pixel.tsx +99 -99
  87. package/src/tracking/consent-init.tsx +62 -62
  88. package/src/tracking/events.ts +348 -348
  89. package/src/tracking/ga4.tsx +93 -93
  90. package/src/tracking/google-ads.ts +84 -84
  91. package/src/tracking/gtm.tsx +60 -60
  92. package/src/tracking/inline-script.ts +49 -49
  93. package/src/tracking/oaiq.ts +206 -206
  94. package/src/tracking/tiktok-pixel.tsx +91 -91
  95. package/src/tracking/track-init.tsx +56 -56
  96. package/src/tracking/track-order-purchase.tsx +122 -122
  97. package/src/tracking/ttq.ts +180 -180
  98. package/src/tracking/use-tracking-config.ts +54 -54
  99. package/theme/index.css +25 -25
@@ -1,200 +1,200 @@
1
- /**
2
- * @cartbase/storefront/api/regions — regions, countries, currencies, locales.
3
- *
4
- * Catalog-context primitives every storefront resolves at boot: which
5
- * regions exist (→ `region_id` for the pricing context), which countries the
6
- * store sells to, which currencies it has enabled, which locales it serves.
7
- * All endpoints are anon reads (`x-client-id` scoping via RLS). Docs:
8
- * docs/storefront/regions.md.
9
- */
10
- import type { StorefrontClient } from "./http"
11
- import type { IsoDateString, ListEnvelope, PaginationQuery } from "./types"
12
-
13
- /**
14
- * A store region (`barter_commerce.regions` row). NOTE: Cartbase regions carry
15
- * NO embedded `countries` array on the store surface (divergence from
16
- * Medusa's Store API — tax scoping is by `tax_regions` server-side). The
17
- * countries are their own call, `listCountries`, and each row carries the
18
- * `region_id` it belongs to.
19
- */
20
- export interface StoreRegion {
21
- id: string
22
- name: string
23
- /** Lowercase ISO currency, e.g. "eur" — feeds the pricing context. */
24
- currency_code: string
25
- automatic_taxes: boolean
26
- metadata: Record<string, unknown> | null
27
- created_at: IsoDateString
28
- updated_at: IsoDateString
29
- }
30
-
31
- /** Shared-catalog currency row, scoped to the store's enabled set on list. */
32
- export interface StoreCurrency {
33
- /** Lowercase ISO code, e.g. "eur". */
34
- code: string
35
- name: string
36
- symbol: string
37
- symbol_native: string | null
38
- decimal_digits: number
39
- rounding: number
40
- created_at: IsoDateString
41
- updated_at: IsoDateString
42
- }
43
-
44
- /**
45
- * A country a shopper may choose (`barter_commerce.countries` row, the store's
46
- * own tenant catalogue).
47
- */
48
- export interface StoreCountry {
49
- /** Lowercase ISO-3166 alpha-2, e.g. "bg" — the value a cart address takes. */
50
- iso_2: string
51
- /** What a shopper reads, e.g. "Bulgaria". The code is never shown as copy. */
52
- display_name: string
53
- /** The catalogue's uppercase form, e.g. "BULGARIA". */
54
- name: string
55
- /** The region this country belongs to, null when the store has not placed it. */
56
- region_id: string | null
57
- }
58
-
59
- export interface ListCountriesQuery extends PaginationQuery {
60
- /** Case-insensitive substring match on the displayed name. */
61
- q?: string
62
- }
63
-
64
- export interface CountryListResponse extends ListEnvelope {
65
- countries: StoreCountry[]
66
- /**
67
- * True when this list IS the store's Markets declaration; false when the
68
- * store has declared nothing and this is the whole ISO catalogue.
69
- */
70
- restricted: boolean
71
- }
72
-
73
- export interface ListRegionsQuery extends PaginationQuery {
74
- /** Case-insensitive substring match on region name. */
75
- q?: string
76
- /** Exact match (lowercased server-side). */
77
- currency_code?: string
78
- }
79
-
80
- export interface RegionListResponse extends ListEnvelope {
81
- regions: StoreRegion[]
82
- }
83
-
84
- export interface RegionResponse {
85
- region: StoreRegion
86
- }
87
-
88
- export interface ListCurrenciesQuery extends PaginationQuery {
89
- /** Exact code match (lowercased server-side). */
90
- code?: string
91
- }
92
-
93
- export interface CurrencyListResponse extends ListEnvelope {
94
- currencies: StoreCurrency[]
95
- }
96
-
97
- export interface CurrencyResponse {
98
- currency: StoreCurrency
99
- }
100
-
101
- export interface LocaleListResponse {
102
- /** Locale codes, store default first, then alphabetical (e.g. ["en","bg"]). */
103
- locales: string[]
104
- }
105
-
106
- /**
107
- * List the store's regions, ordered by name.
108
- *
109
- * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`,
110
- * 400 `validation_failed`. Settings: regions are created in
111
- * Admin → Settings → Regions; `limit` 1–200 (default 50).
112
- */
113
- export async function listRegions(
114
- client: StorefrontClient,
115
- query?: ListRegionsQuery
116
- ): Promise<RegionListResponse> {
117
- return client.get("/api/store/regions", { query: { ...query } })
118
- }
119
-
120
- /**
121
- * Retrieve one region by id.
122
- *
123
- * Auth: anon (`x-client-id`). Errors: 404 `not_found` (unknown id,
124
- * soft-deleted, or another tenant's region — invisible, not forbidden).
125
- */
126
- export async function retrieveRegion(
127
- client: StorefrontClient,
128
- regionId: string
129
- ): Promise<RegionResponse> {
130
- return client.get(`/api/store/regions/${encodeURIComponent(regionId)}`)
131
- }
132
-
133
- /**
134
- * List the countries a shopper may choose at checkout, ordered by the name
135
- * they read.
136
- *
137
- * THE RULE IS THE PLATFORM'S, NOT THE STOREFRONT'S: the store's own Markets
138
- * decide where it sells, and a store that has decided nothing yet sells to
139
- * the whole world. So this answers with the countries the store's regions
140
- * declare, and with the whole 250-entry catalogue when it declares none;
141
- * `restricted` says which you got. A storefront therefore never hardcodes a
142
- * country list, and never has to invent a fallback of its own.
143
- *
144
- * `useCheckoutOrchestration` calls this for you when you do not pass it a
145
- * `countries` list, so a new store offers every country with no wiring at
146
- * all. Pass your own list only to override the store's answer.
147
- *
148
- * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`,
149
- * 400 `validation_failed`. Settings: Admin → Settings → Markets → Regions,
150
- * where a region owns its countries; `limit` 1–300 (default 300, so one
151
- * call carries the entire catalogue).
152
- */
153
- export async function listCountries(
154
- client: StorefrontClient,
155
- query?: ListCountriesQuery
156
- ): Promise<CountryListResponse> {
157
- return client.get("/api/store/countries", { query: { ...query } })
158
- }
159
-
160
- /**
161
- * List the currencies ENABLED on this store (the `store_currencies` link
162
- * filters the shared currency catalog). A store with none enabled returns an
163
- * empty list, ordered by code.
164
- *
165
- * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`,
166
- * 400 `validation_failed`. Settings: Admin → Settings → Store → currencies.
167
- */
168
- export async function listCurrencies(
169
- client: StorefrontClient,
170
- query?: ListCurrenciesQuery
171
- ): Promise<CurrencyListResponse> {
172
- return client.get("/api/store/currencies", { query: { ...query } })
173
- }
174
-
175
- /**
176
- * Retrieve one currency by code (case-insensitive).
177
- *
178
- * Auth: anon (`x-client-id`). Errors: 404 `not_found`.
179
- *
180
- * CODE-TRUTH NOTE: unlike the list, the single read is NOT filtered by the
181
- * store's enabled set — any currency in the shared catalog resolves. Treat
182
- * the list as the authority on what the store supports.
183
- */
184
- export async function retrieveCurrency(
185
- client: StorefrontClient,
186
- code: string
187
- ): Promise<CurrencyResponse> {
188
- return client.get(`/api/store/currencies/${encodeURIComponent(code)}`)
189
- }
190
-
191
- /**
192
- * List the store's supported locale codes (default locale first). Use to
193
- * build the storefront language switcher and to set the client's `x-locale`.
194
- *
195
- * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`.
196
- * Settings: Admin → Settings → Store → locales (per-store store_locales).
197
- */
198
- export async function listLocales(client: StorefrontClient): Promise<LocaleListResponse> {
199
- return client.get("/api/store/locales")
200
- }
1
+ /**
2
+ * @cartbase/storefront/api/regions — regions, countries, currencies, locales.
3
+ *
4
+ * Catalog-context primitives every storefront resolves at boot: which
5
+ * regions exist (→ `region_id` for the pricing context), which countries the
6
+ * store sells to, which currencies it has enabled, which locales it serves.
7
+ * All endpoints are anon reads (`x-client-id` scoping via RLS). Docs:
8
+ * docs/storefront/regions.md.
9
+ */
10
+ import type { StorefrontClient } from "./http"
11
+ import type { IsoDateString, ListEnvelope, PaginationQuery } from "./types"
12
+
13
+ /**
14
+ * A store region (`barter_commerce.regions` row). NOTE: Cartbase regions carry
15
+ * NO embedded `countries` array on the store surface (divergence from
16
+ * Medusa's Store API — tax scoping is by `tax_regions` server-side). The
17
+ * countries are their own call, `listCountries`, and each row carries the
18
+ * `region_id` it belongs to.
19
+ */
20
+ export interface StoreRegion {
21
+ id: string
22
+ name: string
23
+ /** Lowercase ISO currency, e.g. "eur" — feeds the pricing context. */
24
+ currency_code: string
25
+ automatic_taxes: boolean
26
+ metadata: Record<string, unknown> | null
27
+ created_at: IsoDateString
28
+ updated_at: IsoDateString
29
+ }
30
+
31
+ /** Shared-catalog currency row, scoped to the store's enabled set on list. */
32
+ export interface StoreCurrency {
33
+ /** Lowercase ISO code, e.g. "eur". */
34
+ code: string
35
+ name: string
36
+ symbol: string
37
+ symbol_native: string | null
38
+ decimal_digits: number
39
+ rounding: number
40
+ created_at: IsoDateString
41
+ updated_at: IsoDateString
42
+ }
43
+
44
+ /**
45
+ * A country a shopper may choose (`barter_commerce.countries` row, the store's
46
+ * own tenant catalogue).
47
+ */
48
+ export interface StoreCountry {
49
+ /** Lowercase ISO-3166 alpha-2, e.g. "bg" — the value a cart address takes. */
50
+ iso_2: string
51
+ /** What a shopper reads, e.g. "Bulgaria". The code is never shown as copy. */
52
+ display_name: string
53
+ /** The catalogue's uppercase form, e.g. "BULGARIA". */
54
+ name: string
55
+ /** The region this country belongs to, null when the store has not placed it. */
56
+ region_id: string | null
57
+ }
58
+
59
+ export interface ListCountriesQuery extends PaginationQuery {
60
+ /** Case-insensitive substring match on the displayed name. */
61
+ q?: string
62
+ }
63
+
64
+ export interface CountryListResponse extends ListEnvelope {
65
+ countries: StoreCountry[]
66
+ /**
67
+ * True when this list IS the store's Markets declaration; false when the
68
+ * store has declared nothing and this is the whole ISO catalogue.
69
+ */
70
+ restricted: boolean
71
+ }
72
+
73
+ export interface ListRegionsQuery extends PaginationQuery {
74
+ /** Case-insensitive substring match on region name. */
75
+ q?: string
76
+ /** Exact match (lowercased server-side). */
77
+ currency_code?: string
78
+ }
79
+
80
+ export interface RegionListResponse extends ListEnvelope {
81
+ regions: StoreRegion[]
82
+ }
83
+
84
+ export interface RegionResponse {
85
+ region: StoreRegion
86
+ }
87
+
88
+ export interface ListCurrenciesQuery extends PaginationQuery {
89
+ /** Exact code match (lowercased server-side). */
90
+ code?: string
91
+ }
92
+
93
+ export interface CurrencyListResponse extends ListEnvelope {
94
+ currencies: StoreCurrency[]
95
+ }
96
+
97
+ export interface CurrencyResponse {
98
+ currency: StoreCurrency
99
+ }
100
+
101
+ export interface LocaleListResponse {
102
+ /** Locale codes, store default first, then alphabetical (e.g. ["en","bg"]). */
103
+ locales: string[]
104
+ }
105
+
106
+ /**
107
+ * List the store's regions, ordered by name.
108
+ *
109
+ * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`,
110
+ * 400 `validation_failed`. Settings: regions are created in
111
+ * Admin → Settings → Regions; `limit` 1–200 (default 50).
112
+ */
113
+ export async function listRegions(
114
+ client: StorefrontClient,
115
+ query?: ListRegionsQuery
116
+ ): Promise<RegionListResponse> {
117
+ return client.get("/api/store/regions", { query: { ...query } })
118
+ }
119
+
120
+ /**
121
+ * Retrieve one region by id.
122
+ *
123
+ * Auth: anon (`x-client-id`). Errors: 404 `not_found` (unknown id,
124
+ * soft-deleted, or another tenant's region — invisible, not forbidden).
125
+ */
126
+ export async function retrieveRegion(
127
+ client: StorefrontClient,
128
+ regionId: string
129
+ ): Promise<RegionResponse> {
130
+ return client.get(`/api/store/regions/${encodeURIComponent(regionId)}`)
131
+ }
132
+
133
+ /**
134
+ * List the countries a shopper may choose at checkout, ordered by the name
135
+ * they read.
136
+ *
137
+ * THE RULE IS THE PLATFORM'S, NOT THE STOREFRONT'S: the store's own Markets
138
+ * decide where it sells, and a store that has decided nothing yet sells to
139
+ * the whole world. So this answers with the countries the store's regions
140
+ * declare, and with the whole 250-entry catalogue when it declares none;
141
+ * `restricted` says which you got. A storefront therefore never hardcodes a
142
+ * country list, and never has to invent a fallback of its own.
143
+ *
144
+ * `useCheckoutOrchestration` calls this for you when you do not pass it a
145
+ * `countries` list, so a new store offers every country with no wiring at
146
+ * all. Pass your own list only to override the store's answer.
147
+ *
148
+ * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`,
149
+ * 400 `validation_failed`. Settings: Admin → Settings → Markets → Regions,
150
+ * where a region owns its countries; `limit` 1–300 (default 300, so one
151
+ * call carries the entire catalogue).
152
+ */
153
+ export async function listCountries(
154
+ client: StorefrontClient,
155
+ query?: ListCountriesQuery
156
+ ): Promise<CountryListResponse> {
157
+ return client.get("/api/store/countries", { query: { ...query } })
158
+ }
159
+
160
+ /**
161
+ * List the currencies ENABLED on this store (the `store_currencies` link
162
+ * filters the shared currency catalog). A store with none enabled returns an
163
+ * empty list, ordered by code.
164
+ *
165
+ * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`,
166
+ * 400 `validation_failed`. Settings: Admin → Settings → Store → currencies.
167
+ */
168
+ export async function listCurrencies(
169
+ client: StorefrontClient,
170
+ query?: ListCurrenciesQuery
171
+ ): Promise<CurrencyListResponse> {
172
+ return client.get("/api/store/currencies", { query: { ...query } })
173
+ }
174
+
175
+ /**
176
+ * Retrieve one currency by code (case-insensitive).
177
+ *
178
+ * Auth: anon (`x-client-id`). Errors: 404 `not_found`.
179
+ *
180
+ * CODE-TRUTH NOTE: unlike the list, the single read is NOT filtered by the
181
+ * store's enabled set — any currency in the shared catalog resolves. Treat
182
+ * the list as the authority on what the store supports.
183
+ */
184
+ export async function retrieveCurrency(
185
+ client: StorefrontClient,
186
+ code: string
187
+ ): Promise<CurrencyResponse> {
188
+ return client.get(`/api/store/currencies/${encodeURIComponent(code)}`)
189
+ }
190
+
191
+ /**
192
+ * List the store's supported locale codes (default locale first). Use to
193
+ * build the storefront language switcher and to set the client's `x-locale`.
194
+ *
195
+ * Auth: anon (`x-client-id`). Errors: 400 `missing_client_id`.
196
+ * Settings: Admin → Settings → Store → locales (per-store store_locales).
197
+ */
198
+ export async function listLocales(client: StorefrontClient): Promise<LocaleListResponse> {
199
+ return client.get("/api/store/locales")
200
+ }