create-cartbase 0.1.0 → 0.1.2
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/dist/index.js +3 -3
- package/package.json +1 -1
- package/template/app/docs/BUILD-A-STOREFRONT.md +6 -6
- package/template/app/docs/README.md +77 -76
- package/template/app/docs/auth.md +1 -1
- package/template/app/docs/carts.md +6 -6
- package/template/app/docs/categories.md +1 -1
- package/template/app/docs/checkout.md +127 -76
- package/template/app/docs/collections.md +1 -1
- package/template/app/docs/components.md +59 -60
- package/template/app/docs/consent.md +1 -1
- package/template/app/docs/content.md +1 -1
- package/template/app/docs/customers.md +1 -1
- package/template/app/docs/deploy.md +5 -5
- package/template/app/docs/gift-cards.md +1 -1
- package/template/app/docs/integrations.md +1 -1
- package/template/app/docs/menus.md +1 -1
- package/template/app/docs/metaobjects.md +1 -1
- package/template/app/docs/orders.md +1 -1
- package/template/app/docs/platform.md +126 -0
- package/template/app/docs/products.md +1 -1
- package/template/app/docs/redirects.md +1 -1
- package/template/app/docs/regions.md +5 -6
- package/template/app/docs/reviews.md +1 -1
- package/template/app/docs/search.md +1 -1
- package/template/app/docs/subscriptions.md +1 -1
- package/template/app/docs/variables.md +315 -0
- package/template/app/next-env.d.ts +6 -0
- package/template/app/next.config.ts +3 -3
- package/template/app/package.json +1 -1
- package/template/app/smoke.mjs +1 -1
- package/template/app/src/app/checkout/checkout-page-client.tsx +26 -10
- package/template/app/src/app/checkout/mypos-demo-tab.tsx +101 -0
- package/template/app/src/app/checkout/page.tsx +5 -6
- package/template/app/src/app/layout.tsx +113 -105
- package/template/app/src/app/order/[id]/confirmed/page.tsx +5 -4
- package/template/app/src/lib/cart-actions.ts +47 -43
- package/template/app/src/lib/config.ts +10 -5
- package/template/app/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Components
|
|
1
|
+
# Components
|
|
2
2
|
|
|
3
3
|
The component layer of `@cartbase/storefront`: what each family ships, the SDK
|
|
4
4
|
calls it requires, the admin settings that change its behavior, and its mount
|
|
@@ -20,8 +20,7 @@ app's CSS; no component hardcodes a color.
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## Family: tracking (`@cartbase/storefront/tracking/*`)
|
|
24
|
-
|
|
23
|
+
## Family: tracking (`@cartbase/storefront/tracking/*`)
|
|
25
24
|
Meta Pixel + GA4 + Rybbit + Consent Mode v2. The Cartbase split of duties:
|
|
26
25
|
**this package fires client events and writes attribution; server-side CAPI /
|
|
27
26
|
GA4 Measurement Protocol sending is Cartbase-backend-owned** (the
|
|
@@ -154,8 +153,7 @@ Meta side) and `gtag('set','user_data',…)`. Call alongside
|
|
|
154
153
|
|
|
155
154
|
---
|
|
156
155
|
|
|
157
|
-
## Family: primitives (`@cartbase/storefront/primitives/*`)
|
|
158
|
-
|
|
156
|
+
## Family: primitives (`@cartbase/storefront/primitives/*`)
|
|
159
157
|
Generic shadcn-style building blocks. No SDK calls, no admin settings —
|
|
160
158
|
pure UI over the theme tokens.
|
|
161
159
|
|
|
@@ -172,8 +170,7 @@ pure UI over the theme tokens.
|
|
|
172
170
|
|
|
173
171
|
---
|
|
174
172
|
|
|
175
|
-
## Family: lib (`@cartbase/storefront/lib/*`)
|
|
176
|
-
|
|
173
|
+
## Family: lib (`@cartbase/storefront/lib/*`)
|
|
177
174
|
Pure helpers — no React except `dual-price`, no fetches. The SDK never
|
|
178
175
|
invents server truths: prices/totals arrive computed from the API
|
|
179
176
|
(`variant.calculated_price`, `cart.total`); these helpers only select and
|
|
@@ -195,7 +192,7 @@ format.
|
|
|
195
192
|
- `lib/get-product-price` — `getProductPrice({product, variantId})` /
|
|
196
193
|
`getPricesForVariant` → formatted `VariantPrice` (cheapest + selected)
|
|
197
194
|
from server-computed `calculated_price`. Reads Cartbase's flat
|
|
198
|
-
`price_list_type` with
|
|
195
|
+
`price_list_type` with a legacy nested shape as fallback. Affected by:
|
|
199
196
|
price lists / B2B pricing context (what `calculated_price` contains),
|
|
200
197
|
currency + region query context.
|
|
201
198
|
- `lib/get-percentage-diff` — sale badge math.
|
|
@@ -204,21 +201,23 @@ format.
|
|
|
204
201
|
- `lib/sort-products` — client-side re-sort of a fetched page
|
|
205
202
|
(`price_asc|price_desc|created_at`); the API's `order` param stays the
|
|
206
203
|
authority for paginated listings.
|
|
207
|
-
- `lib/payment-constants` — `isStripeLike` / `isPaypal`
|
|
208
|
-
`paymentInfoMap`.
|
|
209
|
-
(
|
|
210
|
-
`
|
|
211
|
-
|
|
204
|
+
- `lib/payment-constants` — `isStripeLike` / `isPaypal` +
|
|
205
|
+
`paymentInfoMap`. Two tender shapes since the pp_* kill: a processor
|
|
206
|
+
`provider_id` (`pp_stripe` exact, code truth
|
|
207
|
+
`src/lib/stripe/providers.ts`, plus legacy Medusa-era prefixes as
|
|
208
|
+
fallbacks) or a merchant METHOD rendered by its snapshot NAME — a
|
|
209
|
+
method never has a provider id to bucket. Affected by: connected
|
|
210
|
+
processors + enabled methods + checkout rules (which entries ever
|
|
211
|
+
reach the client).
|
|
212
212
|
- `lib/store-api-error` — `storeApiError(err)`: display-boundary normalizer
|
|
213
|
-
(capitalized message + terminal period)
|
|
213
|
+
(capitalized message + terminal period).
|
|
214
214
|
Catch `StoreApiError` directly instead when branching on `status`/`code`.
|
|
215
215
|
- `lib/hooks/use-intersection`, `lib/hooks/use-toggle-state` — viewport +
|
|
216
216
|
toggle micro-hooks (client).
|
|
217
217
|
|
|
218
218
|
---
|
|
219
219
|
|
|
220
|
-
## Family: checkout (`@cartbase/storefront/checkout/*`)
|
|
221
|
-
|
|
220
|
+
## Family: checkout (`@cartbase/storefront/checkout/*`)
|
|
222
221
|
The full checkout page family, production-proven (deferred-
|
|
223
222
|
intent architecture — no payment session exists until Buy click) onto the
|
|
224
223
|
Cartbase orchestration endpoints. The flow every component serves
|
|
@@ -227,7 +226,7 @@ Cartbase orchestration endpoints. The flow every component serves
|
|
|
227
226
|
```
|
|
228
227
|
listShippingOptions(cart_id) + listPaymentProviders(cart_id) (render pickers)
|
|
229
228
|
→ Buy click → prepareCheckout (ONE atomic, compensated call)
|
|
230
|
-
→ pp_stripe: stripe.confirmPayment(client_secret) |
|
|
229
|
+
→ pp_stripe: stripe.confirmPayment(client_secret) | merchant method: skip
|
|
231
230
|
→ completeCart → navigate to the confirmed page
|
|
232
231
|
```
|
|
233
232
|
|
|
@@ -264,21 +263,24 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
264
263
|
call REACTIVELY from Elements `loaderror` only), `carts.completeCart`.
|
|
265
264
|
- **Props contract** — `{client, cart, customer, availableShippingMethods,
|
|
266
265
|
availablePaymentMethods, countryCode?, countries?, paymentMethodFilter?,
|
|
267
|
-
|
|
266
|
+
orderConfirmedPath?, onOrderPlaced?,
|
|
268
267
|
resolveTrackingMetadata?, logError?}`. `countries` is caller-supplied
|
|
269
|
-
(Cartbase regions embed NO countries array).
|
|
270
|
-
|
|
271
|
-
`logError` replaces the legacy log writers
|
|
272
|
-
points preserved). Returns the full orchestration
|
|
273
|
-
(`performBuyClick`, `optimisticTotal(Cents)`, `deliveryReady`, …).
|
|
268
|
+
(Cartbase regions embed NO countries array). Fee prediction is never
|
|
269
|
+
hardcoded: each method LISTING entry carries its own
|
|
270
|
+
`fee_amount`/`fee_label`. `logError` replaces the legacy log writers
|
|
271
|
+
(all production log points preserved). Returns the full orchestration
|
|
272
|
+
surface (`performBuyClick`, `optimisticTotal(Cents)`, `deliveryReady`, …).
|
|
274
273
|
- **Cartbase specifics** — zero-remainder gift path: `prepareCheckout`
|
|
275
|
-
returning `client_secret:null` + `provider_id:null`
|
|
276
|
-
completes on the gift session
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
`
|
|
274
|
+
returning `client_secret:null` + `provider_id:null` +
|
|
275
|
+
`payment_method_id:null` SKIPS Stripe and completes on the gift session
|
|
276
|
+
([gift-cards.md](gift-cards.md)). Processors are `pp_stripe` exactly;
|
|
277
|
+
merchant methods list as `{payment_method_id, name, kind, instructions,
|
|
278
|
+
fee_amount, fee_label}` entries — the COD-kind method wins the offline
|
|
279
|
+
tab, else the first manual method. The charged fee reads the cart-level
|
|
280
|
+
`payment_method_fee_total` decoration.
|
|
280
281
|
- **Settings** — checkout rules (filter the listings + complete guard),
|
|
281
|
-
|
|
282
|
+
the methods' own fee configuration (Payments settings), Stripe
|
|
283
|
+
credentials, gift cards, `accounts_mode`.
|
|
282
284
|
|
|
283
285
|
### `<CheckoutClient />` — `checkout/checkout-client`
|
|
284
286
|
|
|
@@ -303,7 +305,7 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
303
305
|
`StripeElementsScope` mounts `<Elements mode:"payment">` where needed
|
|
304
306
|
(`passthrough` renders children scope-less on COD-only stores);
|
|
305
307
|
`StripeContext` boolean = "Stripe.js ready".
|
|
306
|
-
- **SDK calls** — none (env: `NEXT_PUBLIC_STRIPE_KEY
|
|
308
|
+
- **SDK calls** — none (env: `NEXT_PUBLIC_STRIPE_KEY`; legacy env names
|
|
307
309
|
kept as fallbacks).
|
|
308
310
|
- **Mount rules** — `PaymentWrapper` wraps the page ONCE with
|
|
309
311
|
`amount={optimisticTotalCents}` (cents at this Stripe boundary only);
|
|
@@ -383,11 +385,11 @@ code-first through the error-copy maps, never raw API strings.
|
|
|
383
385
|
badge. `LineItemCard` is the standalone card variant.
|
|
384
386
|
- **SDK calls** — `carts.updateLineItem` (quantity); child widgets below.
|
|
385
387
|
Totals are rendered STRAIGHT from the cart decoration: `item_total`,
|
|
386
|
-
`shipping_total`, `
|
|
388
|
+
`shipping_total`, `payment_method_fee_total`/`payment_method_fee_label`, `discount_total`,
|
|
387
389
|
`tax_total`, `total`, `gift_card_total`, `gift_card_remainder`.
|
|
388
390
|
- **Props contract** — `{client, cart, optimisticShippingCost,
|
|
389
391
|
onOptimisticShippingClear?, optimisticCodFee?, onOptimisticCodFeeClear?,
|
|
390
|
-
|
|
392
|
+
methodFeeLabel?, showGiftCards?, onCartChange?}`. Optimistic values clear
|
|
391
393
|
automatically once the server cart catches up.
|
|
392
394
|
- **Settings** — COD integration (fee row), gift cards, promotions.
|
|
393
395
|
|
|
@@ -445,8 +447,7 @@ extra modules beyond the per-file exports, imported from
|
|
|
445
447
|
|
|
446
448
|
---
|
|
447
449
|
|
|
448
|
-
## Family: cart-drawer (`@cartbase/storefront/cart-drawer/*`)
|
|
449
|
-
|
|
450
|
+
## Family: cart-drawer (`@cartbase/storefront/cart-drawer/*`)
|
|
450
451
|
Sliding cart UI, production-proven layout. All
|
|
451
452
|
components are `"use client"`. Money is EUR decimal major units everywhere
|
|
452
453
|
(cart totals are SERVER truth from the decorated cart — components render,
|
|
@@ -570,8 +571,8 @@ Domain doc for every call: [carts.md](carts.md); gift-card tender:
|
|
|
570
571
|
- **Purpose** — full totals breakdown rendered EXACTLY from the decorated
|
|
571
572
|
cart: `subtotal`, `discount_total` (>0, negated for display),
|
|
572
573
|
`shipping_total` (once a shipping method is set; 0 renders FREE; before
|
|
573
|
-
that "calculated at checkout"), `tax_total` (>0), `
|
|
574
|
-
labeled by the server's `
|
|
574
|
+
that "calculated at checkout"), `tax_total` (>0), `payment_method_fee_total` (>0,
|
|
575
|
+
labeled by the server's `payment_method_fee_label`), `total`, then one row per
|
|
575
576
|
applied gift card (masked `last4`, negated; a depleted card stays listed
|
|
576
577
|
at 0) and `gift_card_remainder` — what the remainder provider charges.
|
|
577
578
|
Row selection is the pure `selectSummaryRows(cart)` (unit-tested).
|
|
@@ -609,8 +610,7 @@ Domain doc for every call: [carts.md](carts.md); gift-card tender:
|
|
|
609
610
|
|
|
610
611
|
---
|
|
611
612
|
|
|
612
|
-
## Family: products (`@cartbase/storefront/products/*`)
|
|
613
|
-
|
|
613
|
+
## Family: products (`@cartbase/storefront/products/*`)
|
|
614
614
|
The PDP + product-card family, production-proven. All prices
|
|
615
615
|
render the SERVER-computed `variant.calculated_price` via
|
|
616
616
|
`lib/get-product-price` (Cartbase's flat `price_list_type` wire shape) — no
|
|
@@ -668,7 +668,7 @@ components read copy only through the context or explicit `labels` props).
|
|
|
668
668
|
`optionsAsKeymap` / `optionsMatch` / `findMatchingVariant` — the
|
|
669
669
|
option-choice → variant resolution extracted from product-actions, reading
|
|
670
670
|
Cartbase's option-value LINK shape (`variant.options[].value.{option_id,value}`)
|
|
671
|
-
with
|
|
671
|
+
with a legacy flat-row fallback. Unit-tested
|
|
672
672
|
(tests/unit/storefront-catalog.test.ts).
|
|
673
673
|
|
|
674
674
|
### `<ImageGallery images />` — `products/image-gallery`
|
|
@@ -754,8 +754,7 @@ with the Medusa flat-row fallback. Unit-tested
|
|
|
754
754
|
`ProductLabelsProvider` for i18n; `addToCart`/`openCart` seams as on
|
|
755
755
|
`ProductActions`.
|
|
756
756
|
|
|
757
|
-
## Family: store (`@cartbase/storefront/store/*`)
|
|
758
|
-
|
|
757
|
+
## Family: store (`@cartbase/storefront/store/*`)
|
|
759
758
|
The listing family: paginated grids, sort, collection/category/search
|
|
760
759
|
templates. Sorting discipline: the API's `order` param is the authority for
|
|
761
760
|
paginated listings; client-side re-sort (`lib/sort-products`) exists ONLY
|
|
@@ -859,9 +858,9 @@ search UIs (chips, drawers) that want the same URL contract.
|
|
|
859
858
|
|
|
860
859
|
---
|
|
861
860
|
|
|
862
|
-
## Family: order (`@cartbase/storefront/order/*`)
|
|
863
|
-
|
|
864
|
-
|
|
861
|
+
## Family: order (`@cartbase/storefront/order/*`)
|
|
862
|
+
Order confirmation + account order views, production-proven. Some
|
|
863
|
+
platforms ship ONE `StoreOrder` object carrying computed line
|
|
865
864
|
totals, order totals, shipping methods and payments; Cartbase splits those
|
|
866
865
|
across surfaces, so the family takes them as separate props — the Cartbase
|
|
867
866
|
`StoreOrderDetail` (`api/orders`) carries items as version-pivot rows
|
|
@@ -893,7 +892,7 @@ component also takes a `labels` prop pick.
|
|
|
893
892
|
rybbit, deduped by `order.display_id`) is APP-OWNED: fire it from the
|
|
894
893
|
confirmation route exactly once per order per the tracking family's
|
|
895
894
|
dedupe contract — the template deliberately does NOT fire it.
|
|
896
|
-
- **Settings** — COD settings (fee row presence + `
|
|
895
|
+
- **Settings** — COD settings (fee row presence + `payment_method_fee_label`),
|
|
897
896
|
checkout rules (which provider ids appear), store locales (labels pack).
|
|
898
897
|
|
|
899
898
|
### `<OrderConfirmationHeader order />` — `order/order-confirmation-header`
|
|
@@ -916,19 +915,19 @@ component also takes a `labels` prop pick.
|
|
|
916
915
|
COD fees are never line items, so on pure Cartbase data the filter is a
|
|
917
916
|
no-op safety net. Newest-first sort by `createdAt` when present.
|
|
918
917
|
|
|
919
|
-
### `<OrderTotals totals currencyCode items?
|
|
918
|
+
### `<OrderTotals totals currencyCode items? methodFeeLabel? />` — `order/order-totals`
|
|
920
919
|
|
|
921
920
|
- **Purpose** — the money breakdown: Subtotal / Shipping (FREE badge at
|
|
922
921
|
0) / COD fee / Discount (negated) / Tax / Total, all via `DualPrice`.
|
|
923
922
|
- **Data seam** — `OrderTotalsSource` (the decorated cart satisfies it:
|
|
924
923
|
`item_subtotal`, `shipping_subtotal`, `discount_total`, `tax_total`,
|
|
925
|
-
`total`, `
|
|
924
|
+
`total`, `payment_method_fee_total`, `payment_method_fee_label`); the summary snapshot adapts
|
|
926
925
|
via `orderTotalsFromSummary`. Row policy is the pure, unit-tested
|
|
927
|
-
`selectOrderTotalsRows`: native `
|
|
926
|
+
`selectOrderTotalsRows`: native `payment_method_fee_total` wins over a legacy fee
|
|
928
927
|
LINE; a legacy fee line's net is subtracted from the visible subtotal
|
|
929
|
-
(v2.3.1 production fix); COD label preference `
|
|
930
|
-
server `
|
|
931
|
-
- **Settings** — COD settings (`
|
|
928
|
+
(v2.3.1 production fix); COD label preference `methodFeeLabel` prop →
|
|
929
|
+
server `payment_method_fee_label` → fee-line title → `labels.paymentMethodFee`.
|
|
930
|
+
- **Settings** — COD settings (`payment_method_fee_total`/`payment_method_fee_label`),
|
|
932
931
|
promotions (discount row).
|
|
933
932
|
|
|
934
933
|
### `<OrderAddressCard order />` — `order/order-address-card`
|
|
@@ -953,11 +952,13 @@ component also takes a `labels` prop pick.
|
|
|
953
952
|
|
|
954
953
|
### `<OrderPaymentCard providerId cardLast4? />` — `order/order-payment-card`
|
|
955
954
|
|
|
956
|
-
- Payment method card; `resolvePaymentTitle
|
|
957
|
-
`
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
955
|
+
- Payment method card; `resolvePaymentTitle(providerId, titles,
|
|
956
|
+
methodName?)` — the method's merchant NAME wins verbatim when present
|
|
957
|
+
(the snapshot from session data); otherwise the processor id buckets
|
|
958
|
+
via `lib/payment-constants` (`pp_stripe` = card) through the locale
|
|
959
|
+
pack, falling back to `paymentInfoMap` then the raw id. Payment
|
|
960
|
+
internals never cross the Cartbase store surface — both arrive via
|
|
961
|
+
props from checkout state.
|
|
961
962
|
|
|
962
963
|
### `<OrderTimeline fulfillmentStatus? />` — `order/order-timeline`
|
|
963
964
|
|
|
@@ -974,8 +975,7 @@ component also takes a `labels` prop pick.
|
|
|
974
975
|
|
|
975
976
|
---
|
|
976
977
|
|
|
977
|
-
## Family: common (`@cartbase/storefront/common/*`)
|
|
978
|
-
|
|
978
|
+
## Family: common (`@cartbase/storefront/common/*`)
|
|
979
979
|
Shared storefront chrome, production-proven.
|
|
980
980
|
|
|
981
981
|
### `<LocalizedLink href … />` — `common/localized-link`
|
|
@@ -1027,8 +1027,7 @@ Shared storefront chrome, production-proven.
|
|
|
1027
1027
|
|
|
1028
1028
|
---
|
|
1029
1029
|
|
|
1030
|
-
## Family: reviews-ui (`@cartbase/storefront/reviews-ui`)
|
|
1031
|
-
|
|
1030
|
+
## Family: reviews-ui (`@cartbase/storefront/reviews-ui`)
|
|
1032
1031
|
Verified-purchase review components, ported from a production storefront,
|
|
1033
1032
|
over `api/reviews`. ONE barrel export seam: everything imports from
|
|
1034
1033
|
`@cartbase/storefront/reviews-ui`. Endpoint truth:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Deploy
|
|
1
|
+
# Deploy
|
|
2
2
|
|
|
3
3
|
Cartbase builds and hosts your storefront. You send the app's source files
|
|
4
4
|
— one snapshot of the whole project — and Cartbase turns it into a
|
|
@@ -25,7 +25,7 @@ headers the rest of this corpus uses. In practice you'll deploy through
|
|
|
25
25
|
the admin UI (**Storefront** in the sidebar), the Cartbase CLI, or an
|
|
26
26
|
agent connection — all three are wrappers over exactly these calls.
|
|
27
27
|
Users who belong to several stores name the target store with an
|
|
28
|
-
`x-
|
|
28
|
+
`x-cartbase-store: <client-id>` header.
|
|
29
29
|
|
|
30
30
|
## What a deploy is
|
|
31
31
|
|
|
@@ -62,9 +62,9 @@ anyway):
|
|
|
62
62
|
|
|
63
63
|
| Variable | Value |
|
|
64
64
|
|---|---|
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
65
|
+
| `NEXT_PUBLIC_CARTBASE_URL` | The store's API origin |
|
|
66
|
+
| `NEXT_PUBLIC_CARTBASE_CLIENT_ID` | The store's client id |
|
|
67
|
+
| `NEXT_PUBLIC_CARTBASE_PUBLISHABLE_KEY` | The store's publishable key, when one exists |
|
|
68
68
|
|
|
69
69
|
Only these public values ever reach a storefront build — secret keys are
|
|
70
70
|
never injected, so code that expects one is a design error.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Platform fingerprints
|
|
2
|
+
|
|
3
|
+
Every Cartbase-powered storefront emits a small, deliberate set of signals
|
|
4
|
+
so platform-detection tools (Wappalyzer, BuiltWith) classify the site as
|
|
5
|
+
**Ecommerce** — the same mechanism Shopify uses (`window.Shopify`,
|
|
6
|
+
`X-ShopId`, `_shopify_s`). Full spec: `docs/cards/platform-fingerprints.md`.
|
|
7
|
+
Category discipline: these are the ONLY signals emitted — nothing that
|
|
8
|
+
reads as a framework, CMS, or website builder, and NEVER on `/api/admin/*`.
|
|
9
|
+
|
|
10
|
+
SDK modules: `@cartbase/storefront/platform`, `@cartbase/storefront/lib/cookie-names`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Response header — `x-cartbase-version`
|
|
15
|
+
|
|
16
|
+
- **Purpose** — every `/api/store/*` response carries the platform version,
|
|
17
|
+
so a single HTTP response proves the platform without loading a page.
|
|
18
|
+
- **Auth** — none required to observe the header; it's stamped regardless
|
|
19
|
+
of whether the underlying call succeeds or errors (both `withLogging`
|
|
20
|
+
return paths).
|
|
21
|
+
- **Value** — the platform's own semver (`src/lib/platform/identity.ts` →
|
|
22
|
+
`PLATFORM_VERSION`).
|
|
23
|
+
- **Scope** — `/api/store/*` only. `/api/admin/*` never carries it (admin
|
|
24
|
+
is not a storefront).
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# A successful call carries the header.
|
|
28
|
+
HEADERS=$(curl -sfD - -o /dev/null "$BASE/api/store/consent" -H "x-client-id: $CLIENT_ID")
|
|
29
|
+
echo "$HEADERS" | grep -qi '^x-cartbase-version: '
|
|
30
|
+
|
|
31
|
+
# An ERROR response (missing x-client-id → 400 missing_client_id) still
|
|
32
|
+
# carries it — the fingerprint is not a happy-path-only afterthought.
|
|
33
|
+
ERR_HEADERS=$(curl -sD - -o /dev/null "$BASE/api/store/consent")
|
|
34
|
+
echo "$ERR_HEADERS" | grep -qi '^x-cartbase-version: '
|
|
35
|
+
|
|
36
|
+
# Admin surface never carries it (even though the same withLogging wrapper
|
|
37
|
+
# runs the admin route too, once auth resolves).
|
|
38
|
+
ADMIN_HEADERS=$(curl -sD - -o /dev/null "$BASE/api/admin/users/me")
|
|
39
|
+
! echo "$ADMIN_HEADERS" | grep -qi '^x-cartbase-version: '
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Meta tag — `<meta name="generator" content="Cartbase" />`
|
|
45
|
+
|
|
46
|
+
- **Purpose** — the classic "what built this site" signal, read by every
|
|
47
|
+
detection tool's HTML scanner.
|
|
48
|
+
- **SDK** — `createStorefrontMetadata(overrides?: Metadata): Metadata`
|
|
49
|
+
(`@cartbase/storefront/platform`). Call it in the root layout instead of
|
|
50
|
+
hand-writing `export const metadata` — `generator` always resolves to
|
|
51
|
+
`PLATFORM_NAME` ("Cartbase") and cannot be shadowed by a stray key in
|
|
52
|
+
`overrides` (the helper's own assignment applies AFTER the spread).
|
|
53
|
+
- **Components** — every storefront's `app/layout.tsx` (see
|
|
54
|
+
`examples/storefront/src/app/layout.tsx` for the reference wiring).
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// app/layout.tsx
|
|
58
|
+
import { createStorefrontMetadata } from "@cartbase/storefront/platform"
|
|
59
|
+
|
|
60
|
+
export const metadata: Metadata = createStorefrontMetadata({
|
|
61
|
+
title: "My Store",
|
|
62
|
+
description: "...",
|
|
63
|
+
})
|
|
64
|
+
// → renders <meta name="generator" content="Cartbase" /> on every page
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This is a build-time Next.js Metadata API call, not a store-API endpoint —
|
|
68
|
+
no curl to demonstrate; verified by
|
|
69
|
+
`tests/unit/storefront-lib.test.ts` ("platform — generator metadata +
|
|
70
|
+
window.Cartbase").
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## JS global — `window.Cartbase`
|
|
75
|
+
|
|
76
|
+
- **Purpose** — the strongest detector signal (how `window.Shopify` works):
|
|
77
|
+
a synchronous inline script sets `window.Cartbase = {version, storeId}`
|
|
78
|
+
before hydration.
|
|
79
|
+
- **Shape** — `{ version: string, storeId: string }`. No PII, no email, no
|
|
80
|
+
secret — store id + platform version only.
|
|
81
|
+
- **SDK** — `<PlatformInit storeId={...} />` (`@cartbase/storefront/platform`),
|
|
82
|
+
a server component shaped exactly like `<ConsentInit />`
|
|
83
|
+
(`@cartbase/storefront/tracking/consent-init`): one synchronous inline
|
|
84
|
+
`<script>`, mounted once near the top of `<body>`.
|
|
85
|
+
- **Components** — mount once per app, next to `<ConsentInit />`. Never
|
|
86
|
+
mount in an admin bundle.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// app/layout.tsx, inside <body>, first children:
|
|
90
|
+
<ConsentInit />
|
|
91
|
+
<PlatformInit storeId={CARTBASE_CLIENT_ID} />
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Also build-time/render-only — no store-API curl to demonstrate; the exact
|
|
95
|
+
script shape (`window.Cartbase={"version":"...","storeId":"..."};`, no
|
|
96
|
+
extra keys) is verified by `tests/unit/storefront-lib.test.ts`.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Cookies — `_cartbase_cart` (was `_barter_cart_id`)
|
|
101
|
+
|
|
102
|
+
- **Purpose** — the cart-id cookie. The app still OWNS *setting* it (the
|
|
103
|
+
SDK never persists the cart — see [carts.md](carts.md)); the library
|
|
104
|
+
owns the NAME so every consumer emits the same fingerprint instead of
|
|
105
|
+
inventing its own prefix.
|
|
106
|
+
- **SDK** — `CART_COOKIE`, `LEGACY_CART_COOKIE`, `readCartCookie(get)`
|
|
107
|
+
(`@cartbase/storefront/lib/cookie-names`). `readCartCookie` prefers the
|
|
108
|
+
new name and falls back to the legacy `_barter_cart_id` name, so an
|
|
109
|
+
existing visitor's cart survives the rename. Every WRITE uses the new
|
|
110
|
+
name only.
|
|
111
|
+
- **`SESSION_COOKIE` (`_cartbase_session`)** — the name is reserved for a
|
|
112
|
+
future cookie-backed customer session. Nothing sets it today: auth is
|
|
113
|
+
pure Bearer-JWT, persisted by the consuming app (see
|
|
114
|
+
[auth.md](auth.md)). Defined now so a future session mechanism launches
|
|
115
|
+
with the fingerprint-correct name.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { CART_COOKIE, readCartCookie } from "@cartbase/storefront/lib/cookie-names"
|
|
119
|
+
|
|
120
|
+
const cartId = readCartCookie((name) => jar.get(name)?.value) // reads either name
|
|
121
|
+
jar.set(CART_COOKIE, cart.id, { path: "/", maxAge: THIRTY_DAYS }) // writes the new name only
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
No store-API curl to demonstrate (this is a client-cookie contract, not a
|
|
125
|
+
server response); verified by `tests/unit/storefront-lib.test.ts`
|
|
126
|
+
("platform — cookie names + back-compat read").
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Regions
|
|
1
|
+
# Regions
|
|
2
2
|
|
|
3
3
|
Catalog-context primitives a storefront resolves at boot: regions feed the
|
|
4
4
|
pricing context (`region_id` → region currency), currencies tell you what the
|
|
@@ -29,8 +29,8 @@ SDK module: `@cartbase/storefront/api/regions`.
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
- **Response** — ordered by name. NOTE: Cartbase regions carry NO embedded
|
|
32
|
-
`countries` array
|
|
33
|
-
|
|
32
|
+
`countries` array — country/tax scope lives server-side in
|
|
33
|
+
`tax_regions`.
|
|
34
34
|
|
|
35
35
|
```jsonc
|
|
36
36
|
{
|
|
@@ -202,6 +202,5 @@ echo "$LOCALES" | grep -q '"en"'
|
|
|
202
202
|
- **Errors** — 400 `missing_client_id`.
|
|
203
203
|
- **SDK** — `listLocales(client)`.
|
|
204
204
|
- **Components** — locale switcher; `StorefrontClient`'s `getLocale` hook.
|
|
205
|
-
- **Settings** — Admin → Settings → Store → locales (
|
|
206
|
-
|
|
207
|
-
global locale catalog).
|
|
205
|
+
- **Settings** — Admin → Settings → Store → locales (each store manages
|
|
206
|
+
its own locale list in `store_locales`).
|