create-cartbase 0.1.15 → 0.1.17

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 (35) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +25 -25
  3. package/dist/index.js +20 -20
  4. package/package.json +24 -24
  5. package/template/app/docs/auth.md +105 -105
  6. package/template/app/docs/carts.md +376 -376
  7. package/template/app/docs/categories.md +194 -194
  8. package/template/app/docs/checkout.md +714 -714
  9. package/template/app/docs/components.md +50 -13
  10. package/template/app/docs/consent.md +91 -91
  11. package/template/app/docs/deploy.md +197 -197
  12. package/template/app/docs/gift-cards.md +153 -153
  13. package/template/app/docs/metaobjects.md +126 -126
  14. package/template/app/docs/orders.md +221 -221
  15. package/template/app/docs/products.md +51 -2
  16. package/template/app/docs/regions.md +269 -269
  17. package/template/app/docs/reviews.md +223 -223
  18. package/template/app/docs/search.md +227 -227
  19. package/template/app/docs/store.md +47 -47
  20. package/template/app/docs/subscriptions.md +148 -148
  21. package/template/app/docs/variables.md +315 -315
  22. package/template/app/next.config.ts +6 -4
  23. package/template/app/package.json +1 -1
  24. package/template/app/postcss.config.cjs +11 -11
  25. package/template/app/src/app/checkout/checkout-page-client.tsx +73 -73
  26. package/template/app/src/app/checkout/page.tsx +48 -48
  27. package/template/app/src/app/globals.css +26 -26
  28. package/template/app/src/app/page.tsx +28 -28
  29. package/template/app/src/app/products/[handle]/page.tsx +87 -87
  30. package/template/app/src/app/providers.tsx +64 -64
  31. package/template/app/src/app/search/page.tsx +23 -23
  32. package/template/app/src/lib/browser-client.ts +35 -35
  33. package/template/app/src/lib/config.ts +41 -41
  34. package/template/app/src/lib/server-client.ts +25 -25
  35. package/template/app/src/lib/cart-actions.ts +0 -47
@@ -1,269 +1,269 @@
1
- # Regions
2
-
3
- Catalog-context primitives a storefront resolves at boot: regions feed the
4
- pricing context (`region_id` → region currency), currencies tell you what the
5
- store has enabled, locales drive the language switcher and the client's
6
- `x-locale` header. All reads are anonymous. Money is EUR decimal major units
7
- everywhere.
8
-
9
- SDK module: `@cartbase/storefront/api/regions`.
10
-
11
- ---
12
-
13
- ## GET /api/store/regions
14
-
15
- - **Purpose** — list the store's regions; a storefront usually picks one at
16
- boot (or by shopper choice) and passes its id/currency as the pricing
17
- context on catalog reads.
18
- - **Auth** — anon: `x-client-id` required.
19
- - **Request** — `GET /api/store/regions`
20
-
21
- ```jsonc
22
- // query (all optional)
23
- {
24
- "q": "bulg", // case-insensitive substring on name
25
- "currency_code": "eur", // exact match, lowercased server-side
26
- "limit": 50, // 1–200, default 50
27
- "offset": 0
28
- }
29
- ```
30
-
31
- - **Response** — ordered by name. NOTE: Cartbase regions carry NO embedded
32
- `countries` array — country/tax scope lives server-side in
33
- `tax_regions`.
34
-
35
- ```jsonc
36
- {
37
- "regions": [
38
- {
39
- "id": "reg_01tst000000000000000000001",
40
- "name": "Bulgaria",
41
- "currency_code": "eur", // lowercase — feeds the pricing context
42
- "automatic_taxes": true,
43
- "metadata": null,
44
- "created_at": "2026-07-01T00:00:00.000Z",
45
- "updated_at": "2026-07-01T00:00:00.000Z"
46
- }
47
- ],
48
- "count": 1,
49
- "offset": 0,
50
- "limit": 50
51
- }
52
- ```
53
-
54
- - **Working curl**
55
-
56
- ```bash
57
- REGIONS=$(curl -sf "$BASE/api/store/regions" -H "x-client-id: $CLIENT_ID")
58
- echo "$REGIONS" | grep -q '"regions"'
59
- echo "$REGIONS" | grep -q '"count"'
60
- REGION_ID=$(echo "$REGIONS" | grep -o '"id":"reg_[^"]*"' | head -1 | cut -d'"' -f4)
61
- test -n "$REGION_ID"
62
- ```
63
-
64
- - **Errors** — 400 `missing_client_id` (header absent/empty),
65
- 400 `validation_failed` (bad limit/offset).
66
- - **SDK** — `listRegions(client, query?)`.
67
- - **Components** — region/currency selector (see components.md).
68
- - **Settings** — Admin → Settings → Regions.
69
-
70
- ```bash
71
- # Auth contract: no x-client-id → 400 missing_client_id
72
- STATUS=$(curl -s -o /dev/null -w '%{http_code}' "$BASE/api/store/regions")
73
- test "$STATUS" = 400
74
- curl -s "$BASE/api/store/regions" | grep -q '"code":"missing_client_id"'
75
- ```
76
-
77
- ---
78
-
79
- ## GET /api/store/regions/:id
80
-
81
- - **Purpose** — retrieve one region (e.g. re-hydrate the shopper's stored
82
- choice).
83
- - **Auth** — anon: `x-client-id` required.
84
- - **Request** — `GET /api/store/regions/{region_id}` — no query.
85
- - **Response** — `{ "region": { ...same shape as the list rows... } }`
86
- - **Working curl**
87
-
88
- ```bash
89
- REGION=$(curl -sf "$BASE/api/store/regions/$REGION_ID" -H "x-client-id: $CLIENT_ID")
90
- echo "$REGION" | grep -q '"region"'
91
- echo "$REGION" | grep -q '"currency_code"'
92
- ```
93
-
94
- - **Errors** — 404 `not_found` (unknown id, soft-deleted, or another
95
- tenant's region — invisible, not forbidden).
96
-
97
- ```bash
98
- STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
99
- "$BASE/api/store/regions/reg_doesnotexist$RUN" -H "x-client-id: $CLIENT_ID")
100
- test "$STATUS" = 404
101
- curl -s "$BASE/api/store/regions/reg_doesnotexist$RUN" \
102
- -H "x-client-id: $CLIENT_ID" | grep -q '"code":"not_found"'
103
- ```
104
-
105
- - **SDK** — `retrieveRegion(client, regionId)`.
106
- - **Components** — region/currency selector.
107
- - **Settings** — Admin → Settings → Regions.
108
-
109
- ---
110
-
111
- ## GET /api/store/countries
112
-
113
- - **Purpose** — the countries a shopper may choose at checkout.
114
-
115
- **The rule is the platform's, not your storefront's.** The store's own
116
- Markets decide where it sells, and a store that has decided nothing yet
117
- sells to the whole world. So this endpoint answers with:
118
-
119
- - the countries the store's regions declare, when it has declared any
120
- (`"restricted": true`), or
121
- - the whole 250-entry ISO catalogue, when it has declared none
122
- (`"restricted": false`).
123
-
124
- Either way your code hardcodes no country list and invents no fallback of
125
- its own. A merchant changes the answer in Admin → Settings → Markets →
126
- Regions, where a region owns its countries.
127
-
128
- ```jsonc
129
- // query (all optional)
130
- {
131
- "q": "bulg", // case-insensitive substring on the displayed name
132
- "limit": 300, // 1–300, default 300 — the whole catalogue in one call
133
- "offset": 0
134
- }
135
- ```
136
-
137
- - **Response** — ordered by `display_name`, the name a shopper reads.
138
-
139
- ```jsonc
140
- {
141
- "countries": [
142
- {
143
- "iso_2": "bg", // lowercase alpha-2: the cart address value
144
- "display_name": "Bulgaria", // what a shopper reads
145
- "name": "BULGARIA", // the catalogue's uppercase form
146
- "region_id": "reg_01..." // null when the store has not placed it
147
- }
148
- ],
149
- "count": 250,
150
- "offset": 0,
151
- "limit": 300,
152
- "restricted": false
153
- }
154
- ```
155
-
156
- ```bash
157
- # every country the store offers, and which of the two lists you received
158
- curl -s "$BASE/api/store/countries" -H "x-client-id: $CLIENT_ID" \
159
- | grep -q '"restricted"'
160
- ```
161
-
162
- - **SDK** — `listCountries(client, query?)` from
163
- `@cartbase/storefront/api/regions`.
164
- - **Components** — the checkout address form's country select.
165
- `useCheckoutOrchestration` CALLS THIS FOR YOU when you do not pass a
166
- `countries` list, so a new store offers every country with no wiring;
167
- pass your own list only to override the store's answer. The chosen
168
- country's flag is drawn by `CountryFlag`
169
- (`@cartbase/storefront/common/country-flag`).
170
- - **Settings** — Admin → Settings → Markets → Regions.
171
-
172
- ---
173
-
174
- ## GET /api/store/currencies
175
-
176
- - **Purpose** — list the currencies ENABLED on this store (the shared
177
- currency catalog filtered by the store's `store_currencies` links). Use
178
- for formatting metadata (symbol, decimal digits).
179
- - **Auth** — anon: `x-client-id` required.
180
- - **Request** — query `{ code?, limit?, offset? }` (`code` exact,
181
- lowercased; `limit` 1–200, default 50).
182
- - **Response** — ordered by code; a store with no enabled currencies
183
- returns an empty list.
184
-
185
- ```jsonc
186
- {
187
- "currencies": [
188
- {
189
- "code": "eur",
190
- "name": "Euro",
191
- "symbol": "€",
192
- "symbol_native": "€",
193
- "decimal_digits": 2,
194
- "rounding": 0,
195
- "created_at": "2026-07-01T00:00:00.000Z",
196
- "updated_at": "2026-07-01T00:00:00.000Z"
197
- }
198
- ],
199
- "count": 1,
200
- "offset": 0,
201
- "limit": 50
202
- }
203
- ```
204
-
205
- - **Working curl**
206
-
207
- ```bash
208
- CURRENCIES=$(curl -sf "$BASE/api/store/currencies" -H "x-client-id: $CLIENT_ID")
209
- echo "$CURRENCIES" | grep -q '"currencies"'
210
- echo "$CURRENCIES" | grep -q '"code":"eur"' # the dev store enables EUR
211
- ```
212
-
213
- - **Errors** — 400 `missing_client_id`, 400 `validation_failed`.
214
- - **SDK** — `listCurrencies(client, query?)`.
215
- - **Components** — price formatting helpers.
216
- - **Settings** — Admin → Settings → Store → currencies (enable/disable +
217
- default).
218
-
219
- ---
220
-
221
- ## GET /api/store/currencies/:code
222
-
223
- - **Purpose** — retrieve one currency by code (case-insensitive).
224
- - **Auth** — anon: `x-client-id` required.
225
- - **Request** — `GET /api/store/currencies/{code}` — no query.
226
- - **Response** — `{ "currency": { ...same shape as the list rows... } }`
227
- - **Working curl**
228
-
229
- ```bash
230
- CURRENCY=$(curl -sf "$BASE/api/store/currencies/eur" -H "x-client-id: $CLIENT_ID")
231
- echo "$CURRENCY" | grep -q '"currency"'
232
- echo "$CURRENCY" | grep -q '"symbol"'
233
- ```
234
-
235
- - **Errors** — 404 `not_found`.
236
- - **CODE-TRUTH NOTE** — unlike the list, the single read is NOT filtered by
237
- the store's enabled set: any currency in the shared catalog resolves.
238
- Treat the LIST as the authority on what the store supports.
239
- - **SDK** — `retrieveCurrency(client, code)`.
240
- - **Components** — price formatting helpers.
241
- - **Settings** — Admin → Settings → Store → currencies.
242
-
243
- ---
244
-
245
- ## GET /api/store/locales
246
-
247
- - **Purpose** — the store's supported locale codes; drives the language
248
- switcher and the value your client sends as `x-locale`.
249
- - **Auth** — anon: `x-client-id` required.
250
- - **Request** — no query.
251
- - **Response** — default locale FIRST, then alphabetical:
252
-
253
- ```jsonc
254
- { "locales": ["en", "bg"] }
255
- ```
256
-
257
- - **Working curl**
258
-
259
- ```bash
260
- LOCALES=$(curl -sf "$BASE/api/store/locales" -H "x-client-id: $CLIENT_ID")
261
- echo "$LOCALES" | grep -q '"locales"'
262
- echo "$LOCALES" | grep -q '"en"'
263
- ```
264
-
265
- - **Errors** — 400 `missing_client_id`.
266
- - **SDK** — `listLocales(client)`.
267
- - **Components** — locale switcher; `StorefrontClient`'s `getLocale` hook.
268
- - **Settings** — Admin → Settings → Store → locales (each store manages
269
- its own locale list in `store_locales`).
1
+ # Regions
2
+
3
+ Catalog-context primitives a storefront resolves at boot: regions feed the
4
+ pricing context (`region_id` → region currency), currencies tell you what the
5
+ store has enabled, locales drive the language switcher and the client's
6
+ `x-locale` header. All reads are anonymous. Money is EUR decimal major units
7
+ everywhere.
8
+
9
+ SDK module: `@cartbase/storefront/api/regions`.
10
+
11
+ ---
12
+
13
+ ## GET /api/store/regions
14
+
15
+ - **Purpose** — list the store's regions; a storefront usually picks one at
16
+ boot (or by shopper choice) and passes its id/currency as the pricing
17
+ context on catalog reads.
18
+ - **Auth** — anon: `x-client-id` required.
19
+ - **Request** — `GET /api/store/regions`
20
+
21
+ ```jsonc
22
+ // query (all optional)
23
+ {
24
+ "q": "bulg", // case-insensitive substring on name
25
+ "currency_code": "eur", // exact match, lowercased server-side
26
+ "limit": 50, // 1–200, default 50
27
+ "offset": 0
28
+ }
29
+ ```
30
+
31
+ - **Response** — ordered by name. NOTE: Cartbase regions carry NO embedded
32
+ `countries` array — country/tax scope lives server-side in
33
+ `tax_regions`.
34
+
35
+ ```jsonc
36
+ {
37
+ "regions": [
38
+ {
39
+ "id": "reg_01tst000000000000000000001",
40
+ "name": "Bulgaria",
41
+ "currency_code": "eur", // lowercase — feeds the pricing context
42
+ "automatic_taxes": true,
43
+ "metadata": null,
44
+ "created_at": "2026-07-01T00:00:00.000Z",
45
+ "updated_at": "2026-07-01T00:00:00.000Z"
46
+ }
47
+ ],
48
+ "count": 1,
49
+ "offset": 0,
50
+ "limit": 50
51
+ }
52
+ ```
53
+
54
+ - **Working curl**
55
+
56
+ ```bash
57
+ REGIONS=$(curl -sf "$BASE/api/store/regions" -H "x-client-id: $CLIENT_ID")
58
+ echo "$REGIONS" | grep -q '"regions"'
59
+ echo "$REGIONS" | grep -q '"count"'
60
+ REGION_ID=$(echo "$REGIONS" | grep -o '"id":"reg_[^"]*"' | head -1 | cut -d'"' -f4)
61
+ test -n "$REGION_ID"
62
+ ```
63
+
64
+ - **Errors** — 400 `missing_client_id` (header absent/empty),
65
+ 400 `validation_failed` (bad limit/offset).
66
+ - **SDK** — `listRegions(client, query?)`.
67
+ - **Components** — region/currency selector (see components.md).
68
+ - **Settings** — Admin → Settings → Regions.
69
+
70
+ ```bash
71
+ # Auth contract: no x-client-id → 400 missing_client_id
72
+ STATUS=$(curl -s -o /dev/null -w '%{http_code}' "$BASE/api/store/regions")
73
+ test "$STATUS" = 400
74
+ curl -s "$BASE/api/store/regions" | grep -q '"code":"missing_client_id"'
75
+ ```
76
+
77
+ ---
78
+
79
+ ## GET /api/store/regions/:id
80
+
81
+ - **Purpose** — retrieve one region (e.g. re-hydrate the shopper's stored
82
+ choice).
83
+ - **Auth** — anon: `x-client-id` required.
84
+ - **Request** — `GET /api/store/regions/{region_id}` — no query.
85
+ - **Response** — `{ "region": { ...same shape as the list rows... } }`
86
+ - **Working curl**
87
+
88
+ ```bash
89
+ REGION=$(curl -sf "$BASE/api/store/regions/$REGION_ID" -H "x-client-id: $CLIENT_ID")
90
+ echo "$REGION" | grep -q '"region"'
91
+ echo "$REGION" | grep -q '"currency_code"'
92
+ ```
93
+
94
+ - **Errors** — 404 `not_found` (unknown id, soft-deleted, or another
95
+ tenant's region — invisible, not forbidden).
96
+
97
+ ```bash
98
+ STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
99
+ "$BASE/api/store/regions/reg_doesnotexist$RUN" -H "x-client-id: $CLIENT_ID")
100
+ test "$STATUS" = 404
101
+ curl -s "$BASE/api/store/regions/reg_doesnotexist$RUN" \
102
+ -H "x-client-id: $CLIENT_ID" | grep -q '"code":"not_found"'
103
+ ```
104
+
105
+ - **SDK** — `retrieveRegion(client, regionId)`.
106
+ - **Components** — region/currency selector.
107
+ - **Settings** — Admin → Settings → Regions.
108
+
109
+ ---
110
+
111
+ ## GET /api/store/countries
112
+
113
+ - **Purpose** — the countries a shopper may choose at checkout.
114
+
115
+ **The rule is the platform's, not your storefront's.** The store's own
116
+ Markets decide where it sells, and a store that has decided nothing yet
117
+ sells to the whole world. So this endpoint answers with:
118
+
119
+ - the countries the store's regions declare, when it has declared any
120
+ (`"restricted": true`), or
121
+ - the whole 250-entry ISO catalogue, when it has declared none
122
+ (`"restricted": false`).
123
+
124
+ Either way your code hardcodes no country list and invents no fallback of
125
+ its own. A merchant changes the answer in Admin → Settings → Markets →
126
+ Regions, where a region owns its countries.
127
+
128
+ ```jsonc
129
+ // query (all optional)
130
+ {
131
+ "q": "bulg", // case-insensitive substring on the displayed name
132
+ "limit": 300, // 1–300, default 300 — the whole catalogue in one call
133
+ "offset": 0
134
+ }
135
+ ```
136
+
137
+ - **Response** — ordered by `display_name`, the name a shopper reads.
138
+
139
+ ```jsonc
140
+ {
141
+ "countries": [
142
+ {
143
+ "iso_2": "bg", // lowercase alpha-2: the cart address value
144
+ "display_name": "Bulgaria", // what a shopper reads
145
+ "name": "BULGARIA", // the catalogue's uppercase form
146
+ "region_id": "reg_01..." // null when the store has not placed it
147
+ }
148
+ ],
149
+ "count": 250,
150
+ "offset": 0,
151
+ "limit": 300,
152
+ "restricted": false
153
+ }
154
+ ```
155
+
156
+ ```bash
157
+ # every country the store offers, and which of the two lists you received
158
+ curl -s "$BASE/api/store/countries" -H "x-client-id: $CLIENT_ID" \
159
+ | grep -q '"restricted"'
160
+ ```
161
+
162
+ - **SDK** — `listCountries(client, query?)` from
163
+ `@cartbase/storefront/api/regions`.
164
+ - **Components** — the checkout address form's country select.
165
+ `useCheckoutOrchestration` CALLS THIS FOR YOU when you do not pass a
166
+ `countries` list, so a new store offers every country with no wiring;
167
+ pass your own list only to override the store's answer. The chosen
168
+ country's flag is drawn by `CountryFlag`
169
+ (`@cartbase/storefront/common/country-flag`).
170
+ - **Settings** — Admin → Settings → Markets → Regions.
171
+
172
+ ---
173
+
174
+ ## GET /api/store/currencies
175
+
176
+ - **Purpose** — list the currencies ENABLED on this store (the shared
177
+ currency catalog filtered by the store's `store_currencies` links). Use
178
+ for formatting metadata (symbol, decimal digits).
179
+ - **Auth** — anon: `x-client-id` required.
180
+ - **Request** — query `{ code?, limit?, offset? }` (`code` exact,
181
+ lowercased; `limit` 1–200, default 50).
182
+ - **Response** — ordered by code; a store with no enabled currencies
183
+ returns an empty list.
184
+
185
+ ```jsonc
186
+ {
187
+ "currencies": [
188
+ {
189
+ "code": "eur",
190
+ "name": "Euro",
191
+ "symbol": "€",
192
+ "symbol_native": "€",
193
+ "decimal_digits": 2,
194
+ "rounding": 0,
195
+ "created_at": "2026-07-01T00:00:00.000Z",
196
+ "updated_at": "2026-07-01T00:00:00.000Z"
197
+ }
198
+ ],
199
+ "count": 1,
200
+ "offset": 0,
201
+ "limit": 50
202
+ }
203
+ ```
204
+
205
+ - **Working curl**
206
+
207
+ ```bash
208
+ CURRENCIES=$(curl -sf "$BASE/api/store/currencies" -H "x-client-id: $CLIENT_ID")
209
+ echo "$CURRENCIES" | grep -q '"currencies"'
210
+ echo "$CURRENCIES" | grep -q '"code":"eur"' # the dev store enables EUR
211
+ ```
212
+
213
+ - **Errors** — 400 `missing_client_id`, 400 `validation_failed`.
214
+ - **SDK** — `listCurrencies(client, query?)`.
215
+ - **Components** — price formatting helpers.
216
+ - **Settings** — Admin → Settings → Store → currencies (enable/disable +
217
+ default).
218
+
219
+ ---
220
+
221
+ ## GET /api/store/currencies/:code
222
+
223
+ - **Purpose** — retrieve one currency by code (case-insensitive).
224
+ - **Auth** — anon: `x-client-id` required.
225
+ - **Request** — `GET /api/store/currencies/{code}` — no query.
226
+ - **Response** — `{ "currency": { ...same shape as the list rows... } }`
227
+ - **Working curl**
228
+
229
+ ```bash
230
+ CURRENCY=$(curl -sf "$BASE/api/store/currencies/eur" -H "x-client-id: $CLIENT_ID")
231
+ echo "$CURRENCY" | grep -q '"currency"'
232
+ echo "$CURRENCY" | grep -q '"symbol"'
233
+ ```
234
+
235
+ - **Errors** — 404 `not_found`.
236
+ - **CODE-TRUTH NOTE** — unlike the list, the single read is NOT filtered by
237
+ the store's enabled set: any currency in the shared catalog resolves.
238
+ Treat the LIST as the authority on what the store supports.
239
+ - **SDK** — `retrieveCurrency(client, code)`.
240
+ - **Components** — price formatting helpers.
241
+ - **Settings** — Admin → Settings → Store → currencies.
242
+
243
+ ---
244
+
245
+ ## GET /api/store/locales
246
+
247
+ - **Purpose** — the store's supported locale codes; drives the language
248
+ switcher and the value your client sends as `x-locale`.
249
+ - **Auth** — anon: `x-client-id` required.
250
+ - **Request** — no query.
251
+ - **Response** — default locale FIRST, then alphabetical:
252
+
253
+ ```jsonc
254
+ { "locales": ["en", "bg"] }
255
+ ```
256
+
257
+ - **Working curl**
258
+
259
+ ```bash
260
+ LOCALES=$(curl -sf "$BASE/api/store/locales" -H "x-client-id: $CLIENT_ID")
261
+ echo "$LOCALES" | grep -q '"locales"'
262
+ echo "$LOCALES" | grep -q '"en"'
263
+ ```
264
+
265
+ - **Errors** — 400 `missing_client_id`.
266
+ - **SDK** — `listLocales(client)`.
267
+ - **Components** — locale switcher; `StorefrontClient`'s `getLocale` hook.
268
+ - **Settings** — Admin → Settings → Store → locales (each store manages
269
+ its own locale list in `store_locales`).