@cartbase/storefront 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/package.json +258 -256
- package/src/api/auth.ts +108 -108
- package/src/api/carts.ts +523 -523
- package/src/api/categories.ts +184 -184
- package/src/api/checkout.ts +526 -526
- package/src/api/collections.ts +130 -130
- package/src/api/consent.ts +75 -75
- package/src/api/content.ts +125 -125
- package/src/api/customers.ts +303 -303
- package/src/api/gift-cards.ts +112 -112
- package/src/api/http.ts +180 -180
- package/src/api/index.ts +30 -30
- package/src/api/menus.ts +77 -77
- package/src/api/metaobjects.ts +136 -136
- package/src/api/orders.ts +290 -290
- package/src/api/products.ts +43 -1
- package/src/api/redirects.ts +37 -37
- package/src/api/regions.ts +200 -200
- package/src/api/reviews.ts +259 -259
- package/src/api/search.ts +163 -163
- package/src/api/store.ts +35 -35
- package/src/api/types.ts +91 -91
- package/src/cart-drawer/context.tsx +277 -164
- package/src/cart-drawer/cross-sell-carousel.tsx +211 -211
- package/src/cart-drawer/cross-sell-sidebar.tsx +158 -158
- package/src/cart-drawer/gift-wrap.tsx +82 -82
- package/src/cart-drawer/index.ts +71 -68
- package/src/cart-drawer/item/index.tsx +162 -162
- package/src/cart-drawer/item/quantity.tsx +8 -14
- package/src/cart-drawer/item/upsell.tsx +110 -110
- package/src/cart-drawer/labels.ts +123 -123
- package/src/cart-drawer/mutation-queue.ts +78 -0
- package/src/cart-drawer/notes.tsx +131 -131
- package/src/cart-drawer/sticky-footer.tsx +73 -73
- package/src/cart-drawer/summary-breakdown.tsx +197 -197
- package/src/checkout/address-error-copy.ts +117 -117
- package/src/checkout/boxnow-locker-selector.tsx +410 -410
- package/src/checkout/compare-addresses.ts +40 -40
- package/src/checkout/discount-section.tsx +218 -218
- package/src/checkout/error-copy-codes.ts +63 -63
- package/src/checkout/geocode.ts +154 -154
- package/src/checkout/gift-card-section.tsx +224 -224
- package/src/checkout/index.ts +72 -72
- package/src/checkout/labels.ts +495 -495
- package/src/checkout/payment-button.tsx +372 -372
- package/src/checkout/payment-error-copy.ts +154 -154
- package/src/checkout/promotion-error-copy.ts +91 -91
- package/src/checkout/use-checkout-orchestration.ts +1592 -1592
- package/src/common/country-flag.tsx +52 -52
- package/src/common/country-select.tsx +11 -11
- package/src/common/index.ts +20 -20
- package/src/common/market-select.tsx +57 -57
- package/src/index.ts +12 -12
- package/src/lib/country-name.ts +59 -59
- package/src/lib/get-product-price.ts +133 -133
- package/src/lib/media-image.tsx +39 -39
- package/src/lib/payment-constants.ts +53 -53
- package/src/lib/platform.ts +13 -13
- package/src/lib/price.tsx +39 -39
- package/src/lib/store-api-error.ts +36 -36
- package/src/lib/variant-caption.ts +32 -32
- package/src/locales/bg.ts +467 -467
- package/src/locales/context.ts +37 -37
- package/src/locales/en.ts +26 -26
- package/src/locales/es.ts +466 -466
- package/src/locales/index.ts +19 -19
- package/src/locales/provider.tsx +59 -59
- package/src/locales/types.ts +77 -77
- package/src/order/index.ts +62 -62
- package/src/order/labels.ts +79 -79
- package/src/order/order-totals.tsx +250 -250
- package/src/primitives/select-field.tsx +93 -93
- package/src/products/image-gallery.tsx +43 -43
- package/src/products/index.ts +68 -59
- package/src/products/option-select.tsx +67 -67
- package/src/products/product-actions-wrapper.tsx +63 -62
- package/src/products/product-actions.tsx +151 -150
- package/src/products/product-price.tsx +69 -69
- package/src/products/product-promises.tsx +61 -61
- package/src/products/product-specs.tsx +65 -65
- package/src/products/product-tabs.tsx +123 -123
- package/src/products/product-template.tsx +163 -162
- package/src/products/purchase-options.tsx +130 -130
- package/src/products/sets.ts +110 -0
- package/src/products/use-product-actions.ts +199 -164
- package/src/products/variant-matching.ts +71 -71
- package/src/products/variant-url.ts +74 -74
- package/src/reviews-ui/index.ts +73 -73
- package/src/store/category-template.tsx +136 -136
- package/src/store/index.ts +40 -40
- package/src/tracking/chatgpt-pixel.tsx +99 -99
- package/src/tracking/consent-init.tsx +62 -62
- package/src/tracking/events.ts +348 -348
- package/src/tracking/ga4.tsx +93 -93
- package/src/tracking/google-ads.ts +84 -84
- package/src/tracking/gtm.tsx +60 -60
- package/src/tracking/inline-script.ts +49 -49
- package/src/tracking/oaiq.ts +206 -206
- package/src/tracking/tiktok-pixel.tsx +91 -91
- package/src/tracking/track-init.tsx +56 -56
- package/src/tracking/track-order-purchase.tsx +122 -122
- package/src/tracking/ttq.ts +180 -180
- package/src/tracking/use-tracking-config.ts +54 -54
- package/theme/index.css +25 -25
- package/theme/theme.css +150 -150
- package/theme/tokens.css +106 -106
package/src/api/redirects.ts
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @cartbase/storefront/api/redirects — 404-path URL redirect lookup
|
|
3
|
-
* (seo-listings card 21).
|
|
4
|
-
*
|
|
5
|
-
* Ground truth: src/app/api/store/url-redirects/route.ts +
|
|
6
|
-
* src/lib/content/url-redirects.ts.
|
|
7
|
-
*
|
|
8
|
-
* HOT-PATH RULE: call this ONLY from the storefront's not-found handler
|
|
9
|
-
* (the 404 path) — never on regular page loads. Exact-match lookup,
|
|
10
|
-
* index-covered on (client_id, from_path). When `to_path` is non-null the
|
|
11
|
-
* storefront issues a 301 to it.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { StorefrontClient } from "./http"
|
|
15
|
-
|
|
16
|
-
export interface RedirectLookupResponse {
|
|
17
|
-
/** The path you asked about (echoed). */
|
|
18
|
-
path: string
|
|
19
|
-
/** Redirect target, or null when no redirect exists — render the 404. */
|
|
20
|
-
to_path: string | null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* GET /api/store/url-redirects?path=… — look up a redirect for a missed
|
|
25
|
-
* pathname (e.g. `/products/old-handle`).
|
|
26
|
-
*
|
|
27
|
-
* Auth: anon (x-client-id).
|
|
28
|
-
* Errors: 400 validation_failed (missing/empty path) · 400 missing_client_id.
|
|
29
|
-
* Settings: redirects are created in admin (and automatically on handle
|
|
30
|
-
* renames of products/collections/pages/posts).
|
|
31
|
-
*/
|
|
32
|
-
export async function lookupRedirect(
|
|
33
|
-
client: StorefrontClient,
|
|
34
|
-
path: string
|
|
35
|
-
): Promise<RedirectLookupResponse> {
|
|
36
|
-
return client.get("/api/store/url-redirects", { query: { path } })
|
|
37
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @cartbase/storefront/api/redirects — 404-path URL redirect lookup
|
|
3
|
+
* (seo-listings card 21).
|
|
4
|
+
*
|
|
5
|
+
* Ground truth: src/app/api/store/url-redirects/route.ts +
|
|
6
|
+
* src/lib/content/url-redirects.ts.
|
|
7
|
+
*
|
|
8
|
+
* HOT-PATH RULE: call this ONLY from the storefront's not-found handler
|
|
9
|
+
* (the 404 path) — never on regular page loads. Exact-match lookup,
|
|
10
|
+
* index-covered on (client_id, from_path). When `to_path` is non-null the
|
|
11
|
+
* storefront issues a 301 to it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { StorefrontClient } from "./http"
|
|
15
|
+
|
|
16
|
+
export interface RedirectLookupResponse {
|
|
17
|
+
/** The path you asked about (echoed). */
|
|
18
|
+
path: string
|
|
19
|
+
/** Redirect target, or null when no redirect exists — render the 404. */
|
|
20
|
+
to_path: string | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* GET /api/store/url-redirects?path=… — look up a redirect for a missed
|
|
25
|
+
* pathname (e.g. `/products/old-handle`).
|
|
26
|
+
*
|
|
27
|
+
* Auth: anon (x-client-id).
|
|
28
|
+
* Errors: 400 validation_failed (missing/empty path) · 400 missing_client_id.
|
|
29
|
+
* Settings: redirects are created in admin (and automatically on handle
|
|
30
|
+
* renames of products/collections/pages/posts).
|
|
31
|
+
*/
|
|
32
|
+
export async function lookupRedirect(
|
|
33
|
+
client: StorefrontClient,
|
|
34
|
+
path: string
|
|
35
|
+
): Promise<RedirectLookupResponse> {
|
|
36
|
+
return client.get("/api/store/url-redirects", { query: { path } })
|
|
37
|
+
}
|
package/src/api/regions.ts
CHANGED
|
@@ -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
|
+
}
|