create-cartbase 0.1.13 → 0.1.15
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/README.md +4 -0
- package/dist/enclosing-project.js +82 -0
- package/dist/index.js +5 -1
- package/package.json +1 -1
- package/template/app/docs/BUILD-A-STOREFRONT.md +8 -4
- package/template/app/docs/collections.md +167 -167
- package/template/app/docs/components.md +1290 -1211
- package/template/app/docs/consent.md +18 -8
- package/template/app/docs/customers.md +6 -8
- package/template/app/docs/integrations.md +4 -2
- package/template/app/docs/products.md +316 -306
- package/template/app/package.json +1 -1
- package/template/app/src/app/layout.tsx +11 -7
- package/template/app/src/app/order/[id]/confirmed/page.tsx +4 -0
- package/template/app/src/app/page.tsx +4 -1
- package/template/app/src/app/products/[handle]/page.tsx +15 -2
- package/template/app/src/app/providers.tsx +37 -27
- package/template/app/src/app/search/page.tsx +4 -1
- package/template/app/src/lib/config.ts +11 -0
|
@@ -7,10 +7,18 @@ the payload is complete and renderable even for an unconfigured store
|
|
|
7
7
|
|
|
8
8
|
## Storefront wiring (the trap that matters)
|
|
9
9
|
|
|
10
|
-
- Mount `<ConsentInit>` as the **first child of
|
|
11
|
-
synchronous Consent Mode v2 DEFAULT and must
|
|
12
|
-
(async default = first-hit
|
|
13
|
-
(RSC) and inline
|
|
10
|
+
- Mount `<ConsentInit required={consent.enabled}>` as the **first child of
|
|
11
|
+
`<body>`** — it sets the synchronous Consent Mode v2 DEFAULT and must
|
|
12
|
+
**never wait on this fetch in the browser** (async default = first-hit
|
|
13
|
+
consent race). Resolve this config server-side (RSC) and inline the
|
|
14
|
+
setting into the document; the prop is required, a layout without it
|
|
15
|
+
does not compile.
|
|
16
|
+
- **The switch decides the default; a stored choice wins.** `enabled: true`
|
|
17
|
+
is a store that collects consent: every visitor starts DENIED until they
|
|
18
|
+
choose on the banner. `enabled: false` is a store with no consent gate:
|
|
19
|
+
every visitor starts GRANTED, and every configured pixel fires. Either
|
|
20
|
+
way a choice already in the `_1c_consent` cookie is what counts, so a
|
|
21
|
+
visitor who declined keeps that decision if the banner is switched off.
|
|
14
22
|
- Render the built-in banner only when `enabled && mode === "builtin"`.
|
|
15
23
|
- `mode: "external"` = the merchant's CMP owns the UI and must write the
|
|
16
24
|
same `_1c_consent` cookie (or call `setConsent()`) — all Cartbase-side tag
|
|
@@ -18,8 +26,9 @@ the payload is complete and renderable even for an unconfigured store
|
|
|
18
26
|
- Choices persist 12 months in the cookie. Rybbit (platform analytics)
|
|
19
27
|
stays outside consent by design.
|
|
20
28
|
- Pair with [integrations.md](integrations.md): `tracking.consent_required`
|
|
21
|
-
mirrors `enabled` here
|
|
22
|
-
|
|
29
|
+
mirrors `enabled` here, and `<StorefrontTags>` hands it to every pixel
|
|
30
|
+
that gates its own SDK (Meta, TikTok, ChatGPT). Google reads the
|
|
31
|
+
`<ConsentInit>` default.
|
|
23
32
|
|
|
24
33
|
## GET /api/store/consent — the CMP config
|
|
25
34
|
|
|
@@ -58,8 +67,9 @@ the payload is complete and renderable even for an unconfigured store
|
|
|
58
67
|
succeeds (a corrupt/missing stored config degrades to defaults, never to
|
|
59
68
|
a broken banner).
|
|
60
69
|
- **SDK**: `consent.getConsent(client)`
|
|
61
|
-
- **Components**: `<ConsentInit
|
|
62
|
-
layout privacyHref
|
|
70
|
+
- **Components**: `<ConsentInit required={consent.enabled}>` +
|
|
71
|
+
`<ConsentBanner copy={copy[locale]} layout privacyHref
|
|
72
|
+
rejectOnFirstLayer>` (consent family; reference impl
|
|
63
73
|
`src/components/storefront/consent/`).
|
|
64
74
|
- **Settings**: admin → Settings → Consent (enabled/mode/layout/
|
|
65
75
|
privacy_href/copy per locale).
|
|
@@ -71,7 +71,6 @@ test "$STATUS" = 401
|
|
|
71
71
|
{
|
|
72
72
|
"customer": {
|
|
73
73
|
"id": "uuid",
|
|
74
|
-
"client_id": "uuid",
|
|
75
74
|
"email": "maria@example.com",
|
|
76
75
|
"first_name": "Maria",
|
|
77
76
|
"last_name": "Petrova",
|
|
@@ -81,17 +80,19 @@ test "$STATUS" = 401
|
|
|
81
80
|
"vat_number": null,
|
|
82
81
|
"has_account": true,
|
|
83
82
|
"account_status": "approved", // "pending" | "approved" — B2B gating
|
|
84
|
-
"tags": [], // admin-only labels; read-only here
|
|
85
83
|
"metadata": null,
|
|
86
|
-
"created_by": null,
|
|
87
84
|
"created_at": "ISO-8601",
|
|
88
85
|
"updated_at": "ISO-8601",
|
|
89
|
-
"deleted_at": null,
|
|
90
86
|
"addresses": [ /* CustomerAddress[], created_at asc — shape below */ ]
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
```
|
|
94
90
|
|
|
91
|
+
Named columns only (2026-09-14): the tenant id, the staff member who
|
|
92
|
+
created the row, the payment provider's customer id, the soft-delete
|
|
93
|
+
stamp and the merchant's tags about the customer are not part of this
|
|
94
|
+
payload.
|
|
95
|
+
|
|
95
96
|
- **Errors**: `401 unauthenticated` · `400 missing_client_id`.
|
|
96
97
|
- **SDK**: `customers.getMe(client)`
|
|
97
98
|
- **Components**: account dashboard / header account state.
|
|
@@ -121,7 +122,6 @@ curl -s "$BASE/api/store/customers/me" -H "x-client-id: $CLIENT_ID" \
|
|
|
121
122
|
"company_eik": "123456789", // loose format — foreign B2B customers exist
|
|
122
123
|
"vat_number": "BG123456789",
|
|
123
124
|
"metadata": {}
|
|
124
|
-
// "tags" are admin-only — the server STRIPS them from this body.
|
|
125
125
|
}
|
|
126
126
|
```
|
|
127
127
|
|
|
@@ -145,7 +145,6 @@ curl -s "$BASE/api/store/customers/me" -H "x-client-id: $CLIENT_ID" \
|
|
|
145
145
|
"addresses": [
|
|
146
146
|
{
|
|
147
147
|
"id": "uuid",
|
|
148
|
-
"client_id": "uuid",
|
|
149
148
|
"customer_id": "uuid",
|
|
150
149
|
"address_name": "Home",
|
|
151
150
|
"first_name": "Maria",
|
|
@@ -162,8 +161,7 @@ curl -s "$BASE/api/store/customers/me" -H "x-client-id: $CLIENT_ID" \
|
|
|
162
161
|
"is_default_shipping": true,
|
|
163
162
|
"metadata": null,
|
|
164
163
|
"created_at": "ISO-8601",
|
|
165
|
-
"updated_at": "ISO-8601"
|
|
166
|
-
"deleted_at": null
|
|
164
|
+
"updated_at": "ISO-8601"
|
|
167
165
|
}
|
|
168
166
|
],
|
|
169
167
|
"count": 1,
|
|
@@ -76,8 +76,10 @@ key-by-key.
|
|
|
76
76
|
config); consent settings drive `tracking.consent_required`; Rybbit is
|
|
77
77
|
deliberately ABSENT (platform analytics, not a tenant integration).
|
|
78
78
|
|
|
79
|
-
Tracking wiring contract:
|
|
80
|
-
|
|
79
|
+
Tracking wiring contract: `consent_required` is the store's consent switch
|
|
80
|
+
and decides every tag's default (see [consent.md](consent.md)): true starts
|
|
81
|
+
a visitor denied until they choose, false starts them granted, and a stored
|
|
82
|
+
choice wins either way. `<StorefrontTags>` applies it; Purchase events MUST use
|
|
81
83
|
`eventID = "purchase_" + order.display_id` so Meta dedupes browser Pixel vs
|
|
82
84
|
server CAPI, and `event_id = "tt_purchase_" + order.display_id` for TikTok;
|
|
83
85
|
write TrackingAttribution keys into `cart.metadata` (consent-gated) so
|