create-cartbase 0.1.16 → 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.
- package/LICENSE +21 -21
- package/README.md +25 -25
- package/dist/index.js +20 -20
- package/package.json +24 -24
- package/template/app/docs/auth.md +105 -105
- package/template/app/docs/carts.md +376 -376
- package/template/app/docs/categories.md +194 -194
- package/template/app/docs/checkout.md +714 -714
- package/template/app/docs/components.md +44 -11
- package/template/app/docs/consent.md +91 -91
- package/template/app/docs/deploy.md +197 -197
- package/template/app/docs/gift-cards.md +153 -153
- package/template/app/docs/metaobjects.md +126 -126
- package/template/app/docs/orders.md +221 -221
- package/template/app/docs/products.md +51 -2
- package/template/app/docs/regions.md +269 -269
- package/template/app/docs/reviews.md +223 -223
- package/template/app/docs/search.md +227 -227
- package/template/app/docs/store.md +47 -47
- package/template/app/docs/subscriptions.md +148 -148
- package/template/app/docs/variables.md +315 -315
- package/template/app/package.json +1 -1
- package/template/app/postcss.config.cjs +11 -11
- package/template/app/src/app/checkout/checkout-page-client.tsx +73 -73
- package/template/app/src/app/checkout/page.tsx +48 -48
- package/template/app/src/app/globals.css +26 -26
- package/template/app/src/app/page.tsx +28 -28
- package/template/app/src/app/products/[handle]/page.tsx +87 -87
- package/template/app/src/app/providers.tsx +64 -64
- package/template/app/src/app/search/page.tsx +23 -23
- package/template/app/src/lib/browser-client.ts +35 -35
- package/template/app/src/lib/config.ts +41 -41
- package/template/app/src/lib/server-client.ts +25 -25
- package/template/app/src/lib/cart-actions.ts +0 -47
|
@@ -1,194 +1,194 @@
|
|
|
1
|
-
# Categories
|
|
2
|
-
|
|
3
|
-
Taxonomy reads for navigation trees and filter UIs. Categories are
|
|
4
|
-
hierarchical (`parent_category_id`) with optional ancestor/descendant tree
|
|
5
|
-
embedding; tags and types are flat value lists whose ids feed the `tag_id` /
|
|
6
|
-
`type_id` filters on product listings and search.
|
|
7
|
-
|
|
8
|
-
SDK module: `@cartbase/storefront/api/categories`.
|
|
9
|
-
|
|
10
|
-
**Visibility:** only ACTIVE, non-internal categories exist on the store
|
|
11
|
-
surface — enforced by the anon RLS policy, so an inactive/internal category
|
|
12
|
-
404s even when retrieved by id.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## GET /api/store/product-categories
|
|
17
|
-
|
|
18
|
-
- **Purpose** — category list / one tree level (pass `parent_category_id`
|
|
19
|
-
to walk levels, or the tree flags to embed whole branches).
|
|
20
|
-
- **Auth** — anon: `x-client-id` required.
|
|
21
|
-
- **Request**
|
|
22
|
-
|
|
23
|
-
```jsonc
|
|
24
|
-
// query (all optional)
|
|
25
|
-
{
|
|
26
|
-
"q": "appa", // case-insensitive substring on name
|
|
27
|
-
"handle": "apparel", // exact
|
|
28
|
-
"parent_category_id": "pcat_…", // children of this category
|
|
29
|
-
"include_ancestors_tree": true, // embed parent_category chains
|
|
30
|
-
"include_descendants_tree": true, // embed category_children recursively
|
|
31
|
-
"limit": 50, // 1–200, default 50
|
|
32
|
-
"offset": 0
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
- **Response** — `{ product_categories, count, offset, limit }`, ordered by
|
|
37
|
-
`rank`:
|
|
38
|
-
|
|
39
|
-
```jsonc
|
|
40
|
-
{
|
|
41
|
-
"product_categories": [
|
|
42
|
-
{
|
|
43
|
-
"id": "pcat_01tst00000000000000000001",
|
|
44
|
-
"name": "Apparel",
|
|
45
|
-
"handle": "apparel",
|
|
46
|
-
"description": null,
|
|
47
|
-
"parent_category_id": null,
|
|
48
|
-
"rank": 0,
|
|
49
|
-
"is_active": true, // always true on the store surface
|
|
50
|
-
"is_internal": false, // always false on the store surface
|
|
51
|
-
"mpath": null,
|
|
52
|
-
"seo_title": null, // null = fall back to name
|
|
53
|
-
"seo_description": null, // null = fall back to description
|
|
54
|
-
"metadata": null,
|
|
55
|
-
"created_at": "2026-07-01T00:00:00.000Z",
|
|
56
|
-
"updated_at": "2026-07-01T00:00:00.000Z",
|
|
57
|
-
// only when include_descendants_tree=true:
|
|
58
|
-
"category_children": [ /* same shape, recursive */ ],
|
|
59
|
-
// only when include_ancestors_tree=true:
|
|
60
|
-
"parent_category": null
|
|
61
|
-
}
|
|
62
|
-
],
|
|
63
|
-
"count": 1, "offset": 0, "limit": 50
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
- **Working curl** — the seeded catalog carries the `apparel` category:
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
CATEGORIES=$(curl -sf "$BASE/api/store/product-categories?handle=apparel" \
|
|
71
|
-
-H "x-client-id: $CLIENT_ID")
|
|
72
|
-
echo "$CATEGORIES" | grep -q '"product_categories"'
|
|
73
|
-
echo "$CATEGORIES" | grep -q '"handle":"apparel"'
|
|
74
|
-
CAT_ID=$(echo "$CATEGORIES" | grep -o '"id":"pcat_[^"]*"' | head -1 | cut -d'"' -f4)
|
|
75
|
-
test -n "$CAT_ID"
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
- **Errors** — 400 `missing_client_id`, 400 `validation_failed`.
|
|
79
|
-
- **SDK** — `listCategories(client, query?)`.
|
|
80
|
-
- **Components** — category navigation tree, breadcrumbs.
|
|
81
|
-
- **Settings** — Admin → Categories: `is_active` / `is_internal` flags,
|
|
82
|
-
rank ordering, SEO overrides.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## GET /api/store/product-categories/:id
|
|
87
|
-
|
|
88
|
-
- **Purpose** — retrieve one category, optionally with its tree (category
|
|
89
|
-
landing page + breadcrumbs in one call).
|
|
90
|
-
- **Auth** — anon: `x-client-id` required.
|
|
91
|
-
- **Request** — query `{ include_ancestors_tree?, include_descendants_tree? }`.
|
|
92
|
-
- **Response** — `{ "product_category": { ... } }` (tree fields only when
|
|
93
|
-
requested; trees contain visible categories only).
|
|
94
|
-
- **Working curl**
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
CATEGORY=$(curl -sf \
|
|
98
|
-
"$BASE/api/store/product-categories/$CAT_ID?include_descendants_tree=true" \
|
|
99
|
-
-H "x-client-id: $CLIENT_ID")
|
|
100
|
-
echo "$CATEGORY" | grep -q '"product_category"'
|
|
101
|
-
echo "$CATEGORY" | grep -q '"category_children"'
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
- **Errors** — 404 `not_found` (unknown, deleted, or inactive/internal —
|
|
105
|
-
RLS hides them even by id).
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
109
|
-
"$BASE/api/store/product-categories/pcat_doesnotexist$RUN" \
|
|
110
|
-
-H "x-client-id: $CLIENT_ID")
|
|
111
|
-
test "$STATUS" = 404
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
- **SDK** — `retrieveCategory(client, categoryId, query?)`.
|
|
115
|
-
- **Components** — category page header, breadcrumbs.
|
|
116
|
-
- **Settings** — as the list.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## GET /api/store/product-tags
|
|
121
|
-
|
|
122
|
-
- **Purpose** — tag list (filter chips). Use the returned ids as `tag_id`
|
|
123
|
-
filters on `/products` and `/products/search`.
|
|
124
|
-
- **Auth** — anon: `x-client-id` required.
|
|
125
|
-
- **Request** — query `{ q?, value?, limit?, offset? }` (`q` substring,
|
|
126
|
-
`value` exact; `limit` 1–200, default 50).
|
|
127
|
-
- **Response** — ordered by value:
|
|
128
|
-
|
|
129
|
-
```jsonc
|
|
130
|
-
{
|
|
131
|
-
"product_tags": [
|
|
132
|
-
{ "id": "ptag_…", "value": "summer", "metadata": null,
|
|
133
|
-
"created_at": "2026-07-01T00:00:00.000Z", "updated_at": "2026-07-01T00:00:00.000Z" }
|
|
134
|
-
],
|
|
135
|
-
"count": 1, "offset": 0, "limit": 50
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
- **Working curl** — the dev tenant seeds no tags, so this asserts the
|
|
140
|
-
envelope (the shape contract), not contents:
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
TAGS=$(curl -sf "$BASE/api/store/product-tags" -H "x-client-id: $CLIENT_ID")
|
|
144
|
-
echo "$TAGS" | grep -q '"product_tags"'
|
|
145
|
-
echo "$TAGS" | grep -q '"count"'
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
- **Errors** — 400 `missing_client_id`, 400 `validation_failed`;
|
|
149
|
-
retrieve (`GET /api/store/product-tags/:id` → `{ "product_tag": …}`) 404s
|
|
150
|
-
on unknown ids:
|
|
151
|
-
|
|
152
|
-
```bash
|
|
153
|
-
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
154
|
-
"$BASE/api/store/product-tags/ptag_doesnotexist$RUN" -H "x-client-id: $CLIENT_ID")
|
|
155
|
-
test "$STATUS" = 404
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
- **SDK** — `listProductTags(client, query?)` /
|
|
159
|
-
`retrieveProductTag(client, tagId)`.
|
|
160
|
-
- **Components** — filter sidebar chips.
|
|
161
|
-
- **Settings** — tags are authored on products in admin.
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## GET /api/store/product-types
|
|
166
|
-
|
|
167
|
-
- **Purpose** — type list; ids feed `type_id` filters on listings/search.
|
|
168
|
-
- **Auth** — anon: `x-client-id` required.
|
|
169
|
-
- **Request** — query `{ q?, value?, limit?, offset? }` (same semantics as
|
|
170
|
-
tags).
|
|
171
|
-
- **Response** — `{ product_types, count, offset, limit }`, rows
|
|
172
|
-
`{ id, value, metadata, created_at, updated_at }`, ordered by value.
|
|
173
|
-
- **Working curl**
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
TYPES=$(curl -sf "$BASE/api/store/product-types" -H "x-client-id: $CLIENT_ID")
|
|
177
|
-
echo "$TYPES" | grep -q '"product_types"'
|
|
178
|
-
echo "$TYPES" | grep -q '"count"'
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
- **Errors** — 400 `missing_client_id`, 400 `validation_failed`; retrieve
|
|
182
|
-
(`GET /api/store/product-types/:id` → `{ "product_type": …}`) 404s on
|
|
183
|
-
unknown ids:
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
187
|
-
"$BASE/api/store/product-types/ptyp_doesnotexist$RUN" -H "x-client-id: $CLIENT_ID")
|
|
188
|
-
test "$STATUS" = 404
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
- **SDK** — `listProductTypes(client, query?)` /
|
|
192
|
-
`retrieveProductType(client, typeId)`.
|
|
193
|
-
- **Components** — filter sidebar.
|
|
194
|
-
- **Settings** — types are authored on products in admin.
|
|
1
|
+
# Categories
|
|
2
|
+
|
|
3
|
+
Taxonomy reads for navigation trees and filter UIs. Categories are
|
|
4
|
+
hierarchical (`parent_category_id`) with optional ancestor/descendant tree
|
|
5
|
+
embedding; tags and types are flat value lists whose ids feed the `tag_id` /
|
|
6
|
+
`type_id` filters on product listings and search.
|
|
7
|
+
|
|
8
|
+
SDK module: `@cartbase/storefront/api/categories`.
|
|
9
|
+
|
|
10
|
+
**Visibility:** only ACTIVE, non-internal categories exist on the store
|
|
11
|
+
surface — enforced by the anon RLS policy, so an inactive/internal category
|
|
12
|
+
404s even when retrieved by id.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## GET /api/store/product-categories
|
|
17
|
+
|
|
18
|
+
- **Purpose** — category list / one tree level (pass `parent_category_id`
|
|
19
|
+
to walk levels, or the tree flags to embed whole branches).
|
|
20
|
+
- **Auth** — anon: `x-client-id` required.
|
|
21
|
+
- **Request**
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
// query (all optional)
|
|
25
|
+
{
|
|
26
|
+
"q": "appa", // case-insensitive substring on name
|
|
27
|
+
"handle": "apparel", // exact
|
|
28
|
+
"parent_category_id": "pcat_…", // children of this category
|
|
29
|
+
"include_ancestors_tree": true, // embed parent_category chains
|
|
30
|
+
"include_descendants_tree": true, // embed category_children recursively
|
|
31
|
+
"limit": 50, // 1–200, default 50
|
|
32
|
+
"offset": 0
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **Response** — `{ product_categories, count, offset, limit }`, ordered by
|
|
37
|
+
`rank`:
|
|
38
|
+
|
|
39
|
+
```jsonc
|
|
40
|
+
{
|
|
41
|
+
"product_categories": [
|
|
42
|
+
{
|
|
43
|
+
"id": "pcat_01tst00000000000000000001",
|
|
44
|
+
"name": "Apparel",
|
|
45
|
+
"handle": "apparel",
|
|
46
|
+
"description": null,
|
|
47
|
+
"parent_category_id": null,
|
|
48
|
+
"rank": 0,
|
|
49
|
+
"is_active": true, // always true on the store surface
|
|
50
|
+
"is_internal": false, // always false on the store surface
|
|
51
|
+
"mpath": null,
|
|
52
|
+
"seo_title": null, // null = fall back to name
|
|
53
|
+
"seo_description": null, // null = fall back to description
|
|
54
|
+
"metadata": null,
|
|
55
|
+
"created_at": "2026-07-01T00:00:00.000Z",
|
|
56
|
+
"updated_at": "2026-07-01T00:00:00.000Z",
|
|
57
|
+
// only when include_descendants_tree=true:
|
|
58
|
+
"category_children": [ /* same shape, recursive */ ],
|
|
59
|
+
// only when include_ancestors_tree=true:
|
|
60
|
+
"parent_category": null
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"count": 1, "offset": 0, "limit": 50
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- **Working curl** — the seeded catalog carries the `apparel` category:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
CATEGORIES=$(curl -sf "$BASE/api/store/product-categories?handle=apparel" \
|
|
71
|
+
-H "x-client-id: $CLIENT_ID")
|
|
72
|
+
echo "$CATEGORIES" | grep -q '"product_categories"'
|
|
73
|
+
echo "$CATEGORIES" | grep -q '"handle":"apparel"'
|
|
74
|
+
CAT_ID=$(echo "$CATEGORIES" | grep -o '"id":"pcat_[^"]*"' | head -1 | cut -d'"' -f4)
|
|
75
|
+
test -n "$CAT_ID"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- **Errors** — 400 `missing_client_id`, 400 `validation_failed`.
|
|
79
|
+
- **SDK** — `listCategories(client, query?)`.
|
|
80
|
+
- **Components** — category navigation tree, breadcrumbs.
|
|
81
|
+
- **Settings** — Admin → Categories: `is_active` / `is_internal` flags,
|
|
82
|
+
rank ordering, SEO overrides.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## GET /api/store/product-categories/:id
|
|
87
|
+
|
|
88
|
+
- **Purpose** — retrieve one category, optionally with its tree (category
|
|
89
|
+
landing page + breadcrumbs in one call).
|
|
90
|
+
- **Auth** — anon: `x-client-id` required.
|
|
91
|
+
- **Request** — query `{ include_ancestors_tree?, include_descendants_tree? }`.
|
|
92
|
+
- **Response** — `{ "product_category": { ... } }` (tree fields only when
|
|
93
|
+
requested; trees contain visible categories only).
|
|
94
|
+
- **Working curl**
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
CATEGORY=$(curl -sf \
|
|
98
|
+
"$BASE/api/store/product-categories/$CAT_ID?include_descendants_tree=true" \
|
|
99
|
+
-H "x-client-id: $CLIENT_ID")
|
|
100
|
+
echo "$CATEGORY" | grep -q '"product_category"'
|
|
101
|
+
echo "$CATEGORY" | grep -q '"category_children"'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- **Errors** — 404 `not_found` (unknown, deleted, or inactive/internal —
|
|
105
|
+
RLS hides them even by id).
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
109
|
+
"$BASE/api/store/product-categories/pcat_doesnotexist$RUN" \
|
|
110
|
+
-H "x-client-id: $CLIENT_ID")
|
|
111
|
+
test "$STATUS" = 404
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- **SDK** — `retrieveCategory(client, categoryId, query?)`.
|
|
115
|
+
- **Components** — category page header, breadcrumbs.
|
|
116
|
+
- **Settings** — as the list.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## GET /api/store/product-tags
|
|
121
|
+
|
|
122
|
+
- **Purpose** — tag list (filter chips). Use the returned ids as `tag_id`
|
|
123
|
+
filters on `/products` and `/products/search`.
|
|
124
|
+
- **Auth** — anon: `x-client-id` required.
|
|
125
|
+
- **Request** — query `{ q?, value?, limit?, offset? }` (`q` substring,
|
|
126
|
+
`value` exact; `limit` 1–200, default 50).
|
|
127
|
+
- **Response** — ordered by value:
|
|
128
|
+
|
|
129
|
+
```jsonc
|
|
130
|
+
{
|
|
131
|
+
"product_tags": [
|
|
132
|
+
{ "id": "ptag_…", "value": "summer", "metadata": null,
|
|
133
|
+
"created_at": "2026-07-01T00:00:00.000Z", "updated_at": "2026-07-01T00:00:00.000Z" }
|
|
134
|
+
],
|
|
135
|
+
"count": 1, "offset": 0, "limit": 50
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- **Working curl** — the dev tenant seeds no tags, so this asserts the
|
|
140
|
+
envelope (the shape contract), not contents:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
TAGS=$(curl -sf "$BASE/api/store/product-tags" -H "x-client-id: $CLIENT_ID")
|
|
144
|
+
echo "$TAGS" | grep -q '"product_tags"'
|
|
145
|
+
echo "$TAGS" | grep -q '"count"'
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- **Errors** — 400 `missing_client_id`, 400 `validation_failed`;
|
|
149
|
+
retrieve (`GET /api/store/product-tags/:id` → `{ "product_tag": …}`) 404s
|
|
150
|
+
on unknown ids:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
154
|
+
"$BASE/api/store/product-tags/ptag_doesnotexist$RUN" -H "x-client-id: $CLIENT_ID")
|
|
155
|
+
test "$STATUS" = 404
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- **SDK** — `listProductTags(client, query?)` /
|
|
159
|
+
`retrieveProductTag(client, tagId)`.
|
|
160
|
+
- **Components** — filter sidebar chips.
|
|
161
|
+
- **Settings** — tags are authored on products in admin.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## GET /api/store/product-types
|
|
166
|
+
|
|
167
|
+
- **Purpose** — type list; ids feed `type_id` filters on listings/search.
|
|
168
|
+
- **Auth** — anon: `x-client-id` required.
|
|
169
|
+
- **Request** — query `{ q?, value?, limit?, offset? }` (same semantics as
|
|
170
|
+
tags).
|
|
171
|
+
- **Response** — `{ product_types, count, offset, limit }`, rows
|
|
172
|
+
`{ id, value, metadata, created_at, updated_at }`, ordered by value.
|
|
173
|
+
- **Working curl**
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
TYPES=$(curl -sf "$BASE/api/store/product-types" -H "x-client-id: $CLIENT_ID")
|
|
177
|
+
echo "$TYPES" | grep -q '"product_types"'
|
|
178
|
+
echo "$TYPES" | grep -q '"count"'
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- **Errors** — 400 `missing_client_id`, 400 `validation_failed`; retrieve
|
|
182
|
+
(`GET /api/store/product-types/:id` → `{ "product_type": …}`) 404s on
|
|
183
|
+
unknown ids:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
|
|
187
|
+
"$BASE/api/store/product-types/ptyp_doesnotexist$RUN" -H "x-client-id: $CLIENT_ID")
|
|
188
|
+
test "$STATUS" = 404
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- **SDK** — `listProductTypes(client, query?)` /
|
|
192
|
+
`retrieveProductType(client, typeId)`.
|
|
193
|
+
- **Components** — filter sidebar.
|
|
194
|
+
- **Settings** — types are authored on products in admin.
|