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.
Files changed (34) 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 +44 -11
  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/package.json +1 -1
  23. package/template/app/postcss.config.cjs +11 -11
  24. package/template/app/src/app/checkout/checkout-page-client.tsx +73 -73
  25. package/template/app/src/app/checkout/page.tsx +48 -48
  26. package/template/app/src/app/globals.css +26 -26
  27. package/template/app/src/app/page.tsx +28 -28
  28. package/template/app/src/app/products/[handle]/page.tsx +87 -87
  29. package/template/app/src/app/providers.tsx +64 -64
  30. package/template/app/src/app/search/page.tsx +23 -23
  31. package/template/app/src/lib/browser-client.ts +35 -35
  32. package/template/app/src/lib/config.ts +41 -41
  33. package/template/app/src/lib/server-client.ts +25 -25
  34. package/template/app/src/lib/cart-actions.ts +0 -47
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Cartbase
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cartbase
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,25 +1,25 @@
1
- # create-cartbase
2
-
3
- Scaffold a storefront on the [Cartbase](https://cartbase.net) commerce
4
- platform. One input: your store's publishable key, handed out on the
5
- **Storefront** page of your Cartbase admin.
6
-
7
- ```bash
8
- npx create-cartbase@latest my-store --key pk_…
9
- # or
10
- npm create cartbase my-store -- --key pk_…
11
- bun create cartbase my-store --key pk_…
12
- ```
13
-
14
- You get a working Next.js storefront wired to your store through
15
- `@cartbase/storefront`, styled, with the **complete platform docs
16
- included in `docs/`** and a `CLAUDE.md` brief. Hand the folder to a
17
- coding agent and it has everything it needs offline. `--url` points the
18
- app at a local or staging platform; without it the app talks to the
19
- platform. Deploy with the
20
- [`cartbase`](https://www.npmjs.com/package/cartbase) CLI: `cartbase login`,
21
- then `cartbase deploy`.
22
-
23
- Run it in a folder of its own. Inside an existing project, Next.js takes
24
- that project's folder as the workspace root; the scaffold notices and
25
- prints the one line to add to `next.config.ts` if that is what you meant.
1
+ # create-cartbase
2
+
3
+ Scaffold a storefront on the [Cartbase](https://cartbase.net) commerce
4
+ platform. One input: your store's publishable key, handed out on the
5
+ **Storefront** page of your Cartbase admin.
6
+
7
+ ```bash
8
+ npx create-cartbase@latest my-store --key pk_…
9
+ # or
10
+ npm create cartbase my-store -- --key pk_…
11
+ bun create cartbase my-store --key pk_…
12
+ ```
13
+
14
+ You get a working Next.js storefront wired to your store through
15
+ `@cartbase/storefront`, styled, with the **complete platform docs
16
+ included in `docs/`** and a `CLAUDE.md` brief. Hand the folder to a
17
+ coding agent and it has everything it needs offline. `--url` points the
18
+ app at a local or staging platform; without it the app talks to the
19
+ platform. Deploy with the
20
+ [`cartbase`](https://www.npmjs.com/package/cartbase) CLI: `cartbase login`,
21
+ then `cartbase deploy`.
22
+
23
+ Run it in a folder of its own. Inside an existing project, Next.js takes
24
+ that project's folder as the workspace root; the scaffold notices and
25
+ prints the one line to add to `next.config.ts` if that is what you meant.
package/dist/index.js CHANGED
@@ -53,13 +53,13 @@ function envFile(input) {
53
53
  function main() {
54
54
  const { dir, flags } = parseArgs(process.argv.slice(2));
55
55
  if (!dir || flags.get("help") === true) {
56
- console.log(`create-cartbase — scaffold a Cartbase storefront
57
-
58
- Usage:
59
- npx create-cartbase@latest <directory> --key <pk_…>
60
-
61
- The key is your store's publishable key (Cartbase admin, Storefront page).
62
- Given as a flag it is written into .env.local; otherwise a placeholder is.
56
+ console.log(`create-cartbase — scaffold a Cartbase storefront
57
+
58
+ Usage:
59
+ npx create-cartbase@latest <directory> --key <pk_…>
60
+
61
+ The key is your store's publishable key (Cartbase admin, Storefront page).
62
+ Given as a flag it is written into .env.local; otherwise a placeholder is.
63
63
  --url points at a local or staging platform; the default is the platform.`);
64
64
  process.exitCode = dir ? 0 : 1;
65
65
  return;
@@ -86,21 +86,21 @@ Given as a flag it is written into .env.local; otherwise a placeholder is.
86
86
  // A store scaffolded inside another project inherits that project's
87
87
  // workspace root in Next's eyes; said once, here, while it is cheap to move.
88
88
  const enclosing = findEnclosingProject(target);
89
- console.log(`
90
- Created ${path.basename(target)}/
91
-
92
- Next steps:
93
- cd ${dir}
89
+ console.log(`
90
+ Created ${path.basename(target)}/
91
+
92
+ Next steps:
93
+ cd ${dir}
94
94
  bun install (or npm install)${key
95
95
  ? ""
96
- : `
97
- open .env.local and paste your store's publishable key
98
- (Cartbase admin, Storefront page)`}
99
- bun run dev
100
-
101
- The complete storefront reference is in docs/ — hand CLAUDE.md (or
102
- AGENTS.md) to your coding agent and it has everything. Deploy with the
103
- Cartbase CLI: cartbase login, then cartbase deploy.
96
+ : `
97
+ open .env.local and paste your store's publishable key
98
+ (Cartbase admin, Storefront page)`}
99
+ bun run dev
100
+
101
+ The complete storefront reference is in docs/ — hand CLAUDE.md (or
102
+ AGENTS.md) to your coding agent and it has everything. Deploy with the
103
+ Cartbase CLI: cartbase login, then cartbase deploy.
104
104
  ${enclosing ? `\n${enclosingProjectNote(target, enclosing)}\n` : ""}`);
105
105
  }
106
106
  main();
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
- {
2
- "name": "create-cartbase",
3
- "version": "0.1.16",
4
- "description": "Scaffold a Cartbase storefront: npm create cartbase my-store",
5
- "license": "MIT",
6
- "type": "module",
7
- "bin": {
8
- "create-cartbase": "./dist/index.js"
9
- },
10
- "files": [
11
- "dist",
12
- "template"
13
- ],
14
- "scripts": {
15
- "build": "bun scripts/build-template.mjs && tsc -p tsconfig.json",
16
- "prepack": "bun scripts/build-template.mjs && tsc -p tsconfig.json"
17
- },
18
- "engines": {
19
- "node": ">=20"
20
- },
21
- "devDependencies": {
22
- "typescript": "^5"
23
- }
24
- }
1
+ {
2
+ "name": "create-cartbase",
3
+ "version": "0.1.17",
4
+ "description": "Scaffold a Cartbase storefront: npm create cartbase my-store",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "create-cartbase": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "template"
13
+ ],
14
+ "scripts": {
15
+ "build": "bun scripts/build-template.mjs && tsc -p tsconfig.json",
16
+ "prepack": "bun scripts/build-template.mjs && tsc -p tsconfig.json"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5"
23
+ }
24
+ }
@@ -1,105 +1,105 @@
1
- # Auth
2
-
3
- Passwordless email-code login (customer-accounts card, Shopify Customer
4
- Account API direction). Two calls: **request** emails a 6-digit code,
5
- **verify** exchanges it for a session. Password login
6
- (`supabase.auth.signInWithPassword` client-side) stays available and yields
7
- an equivalent JWT — nothing here is needed for it.
8
-
9
- ## The session discipline (one rule)
10
-
11
- `verify` mints a **real Supabase session**. Its `access_token` is the SAME
12
- `authorization: Bearer <jwt>` every `/api/store/*` route accepts — wire it
13
- into `StorefrontClient` once and every customer surface (customers/me,
14
- orders, documents, cart attach) is authenticated:
15
-
16
- ```jsonc
17
- // new StorefrontClient({ baseUrl, clientId, getAuthToken: () => storedAccessToken })
18
- ```
19
-
20
- Persist `access_token` + `refresh_token`; refresh client-side with the
21
- Supabase SDK (`setSession` → `refreshSession`) — the Cartbase API does not
22
- proxy token refresh. `expires_in` is seconds; `expires_at` epoch-seconds.
23
-
24
- ## Server-enforced security posture (the SDK adds nothing)
25
-
26
- - Request NEVER reveals whether the email is registered — `{ok: true}`
27
- always (no enumeration oracle). The code exists ONLY in the sent email.
28
- - Codes: hashed at rest, TTL **10 min**, single-use, one live code per
29
- email (a new request supersedes prior codes), **5-wrong-attempt lockout**.
30
- - Rate limits per 15-min window: **5 requests per email**, **20 per IP** →
31
- `429 rate_limited` — the only distinguishable request failure.
32
- - Every verify failure — wrong code, expired, consumed, locked out, unknown
33
- email — is the SAME `401 invalid_code`.
34
-
35
- ## POST /api/store/auth/code/request — step 1
36
-
37
- - **Purpose**: email a 6-digit one-time login code. First-time emails
38
- register lazily at VERIFY, not here.
39
- - **Auth**: anon (`x-client-id` only).
40
- - **Request**: `{email: string}`.
41
- - **Response**: `{ok: true}` — always, by design.
42
- - **Errors**: `429 rate_limited` · `400 validation_failed` (malformed
43
- email) · `400 missing_client_id`.
44
- - **SDK**: `auth.requestLoginCode(client, {email})`
45
- - **Components**: login form (account pages family).
46
- - **Settings**: the `auth-code` notification template carries the code.
47
-
48
- ```bash
49
- # The request contract: {ok:true}, nothing else — no code echo, no
50
- # registered-or-not oracle. RUN-stamped email → no rate-limit collisions.
51
- curl -sf -X POST "$BASE/api/store/auth/code/request" \
52
- -H "x-client-id: $CLIENT_ID" -H "content-type: application/json" \
53
- -d '{"email": "doc-auth-'$RUN'@doc.test"}' \
54
- | grep -q '^{"ok":true}$'
55
- ```
56
-
57
- ## POST /api/store/auth/code/verify — step 2
58
-
59
- - **Purpose**: exchange (email, code) for a session. This is ALSO
60
- passwordless **registration** — a first-time email lazy-creates the
61
- customer (`account_status` per store policy) and triggers the welcome
62
- email.
63
- - **Auth**: anon (`x-client-id` only).
64
- - **Request**: `{email: string, code: string}` — code is exactly 6 digits
65
- (leading zeros count; any other shape → `400 validation_failed`).
66
- - **Response**:
67
-
68
- ```jsonc
69
- {
70
- "access_token": "eyJ…", // the Bearer JWT for every store route
71
- "refresh_token": "…",
72
- "expires_in": 3600, // seconds
73
- "expires_at": 1789300000, // epoch seconds (may be absent)
74
- "token_type": "bearer",
75
- "customer": { /* full customer + addresses — see customers.md */ }
76
- }
77
- ```
78
-
79
- - **Errors**: `401 invalid_code` (every auth failure, generic) ·
80
- `400 validation_failed` · `400 missing_client_id`.
81
- - **SDK**: `auth.verifyLoginCode(client, {email, code})`
82
- - **Components**: code-entry form (account pages family).
83
- - **Settings**: store approval policy (new-customer `account_status`);
84
- `account-welcome` template.
85
-
86
- ```bash
87
- # The 401 invalid_code contract — a well-formed but wrong code against the
88
- # RUN-stamped email (its real code lives only in the email we never read).
89
- STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
90
- -X POST "$BASE/api/store/auth/code/verify" \
91
- -H "x-client-id: $CLIENT_ID" -H "content-type: application/json" \
92
- -d '{"email": "doc-auth-'$RUN'@doc.test", "code": "000000"}')
93
- test "$STATUS" = 401
94
- curl -s -X POST "$BASE/api/store/auth/code/verify" \
95
- -H "x-client-id: $CLIENT_ID" -H "content-type: application/json" \
96
- -d '{"email": "doc-auth-'$RUN'@doc.test", "code": "000000"}' \
97
- | grep -q '"code":"invalid_code"'
98
- ```
99
-
100
- > Cleanup note: the code rows this doc creates are single-per-run
101
- > (RUN-stamped email), superseded on any later request and dead after the
102
- > 10-minute TTL — there is no store-surface delete for them by design (they
103
- > are the auth trail). The happy-path session mint is exercised with a real
104
- > inbox-free code by `tests/store/customer-accounts-auth.test.ts` and the
105
- > SDK contract test (server-side code issue via the lib).
1
+ # Auth
2
+
3
+ Passwordless email-code login (customer-accounts card, Shopify Customer
4
+ Account API direction). Two calls: **request** emails a 6-digit code,
5
+ **verify** exchanges it for a session. Password login
6
+ (`supabase.auth.signInWithPassword` client-side) stays available and yields
7
+ an equivalent JWT — nothing here is needed for it.
8
+
9
+ ## The session discipline (one rule)
10
+
11
+ `verify` mints a **real Supabase session**. Its `access_token` is the SAME
12
+ `authorization: Bearer <jwt>` every `/api/store/*` route accepts — wire it
13
+ into `StorefrontClient` once and every customer surface (customers/me,
14
+ orders, documents, cart attach) is authenticated:
15
+
16
+ ```jsonc
17
+ // new StorefrontClient({ baseUrl, clientId, getAuthToken: () => storedAccessToken })
18
+ ```
19
+
20
+ Persist `access_token` + `refresh_token`; refresh client-side with the
21
+ Supabase SDK (`setSession` → `refreshSession`) — the Cartbase API does not
22
+ proxy token refresh. `expires_in` is seconds; `expires_at` epoch-seconds.
23
+
24
+ ## Server-enforced security posture (the SDK adds nothing)
25
+
26
+ - Request NEVER reveals whether the email is registered — `{ok: true}`
27
+ always (no enumeration oracle). The code exists ONLY in the sent email.
28
+ - Codes: hashed at rest, TTL **10 min**, single-use, one live code per
29
+ email (a new request supersedes prior codes), **5-wrong-attempt lockout**.
30
+ - Rate limits per 15-min window: **5 requests per email**, **20 per IP** →
31
+ `429 rate_limited` — the only distinguishable request failure.
32
+ - Every verify failure — wrong code, expired, consumed, locked out, unknown
33
+ email — is the SAME `401 invalid_code`.
34
+
35
+ ## POST /api/store/auth/code/request — step 1
36
+
37
+ - **Purpose**: email a 6-digit one-time login code. First-time emails
38
+ register lazily at VERIFY, not here.
39
+ - **Auth**: anon (`x-client-id` only).
40
+ - **Request**: `{email: string}`.
41
+ - **Response**: `{ok: true}` — always, by design.
42
+ - **Errors**: `429 rate_limited` · `400 validation_failed` (malformed
43
+ email) · `400 missing_client_id`.
44
+ - **SDK**: `auth.requestLoginCode(client, {email})`
45
+ - **Components**: login form (account pages family).
46
+ - **Settings**: the `auth-code` notification template carries the code.
47
+
48
+ ```bash
49
+ # The request contract: {ok:true}, nothing else — no code echo, no
50
+ # registered-or-not oracle. RUN-stamped email → no rate-limit collisions.
51
+ curl -sf -X POST "$BASE/api/store/auth/code/request" \
52
+ -H "x-client-id: $CLIENT_ID" -H "content-type: application/json" \
53
+ -d '{"email": "doc-auth-'$RUN'@doc.test"}' \
54
+ | grep -q '^{"ok":true}$'
55
+ ```
56
+
57
+ ## POST /api/store/auth/code/verify — step 2
58
+
59
+ - **Purpose**: exchange (email, code) for a session. This is ALSO
60
+ passwordless **registration** — a first-time email lazy-creates the
61
+ customer (`account_status` per store policy) and triggers the welcome
62
+ email.
63
+ - **Auth**: anon (`x-client-id` only).
64
+ - **Request**: `{email: string, code: string}` — code is exactly 6 digits
65
+ (leading zeros count; any other shape → `400 validation_failed`).
66
+ - **Response**:
67
+
68
+ ```jsonc
69
+ {
70
+ "access_token": "eyJ…", // the Bearer JWT for every store route
71
+ "refresh_token": "…",
72
+ "expires_in": 3600, // seconds
73
+ "expires_at": 1789300000, // epoch seconds (may be absent)
74
+ "token_type": "bearer",
75
+ "customer": { /* full customer + addresses — see customers.md */ }
76
+ }
77
+ ```
78
+
79
+ - **Errors**: `401 invalid_code` (every auth failure, generic) ·
80
+ `400 validation_failed` · `400 missing_client_id`.
81
+ - **SDK**: `auth.verifyLoginCode(client, {email, code})`
82
+ - **Components**: code-entry form (account pages family).
83
+ - **Settings**: store approval policy (new-customer `account_status`);
84
+ `account-welcome` template.
85
+
86
+ ```bash
87
+ # The 401 invalid_code contract — a well-formed but wrong code against the
88
+ # RUN-stamped email (its real code lives only in the email we never read).
89
+ STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
90
+ -X POST "$BASE/api/store/auth/code/verify" \
91
+ -H "x-client-id: $CLIENT_ID" -H "content-type: application/json" \
92
+ -d '{"email": "doc-auth-'$RUN'@doc.test", "code": "000000"}')
93
+ test "$STATUS" = 401
94
+ curl -s -X POST "$BASE/api/store/auth/code/verify" \
95
+ -H "x-client-id: $CLIENT_ID" -H "content-type: application/json" \
96
+ -d '{"email": "doc-auth-'$RUN'@doc.test", "code": "000000"}' \
97
+ | grep -q '"code":"invalid_code"'
98
+ ```
99
+
100
+ > Cleanup note: the code rows this doc creates are single-per-run
101
+ > (RUN-stamped email), superseded on any later request and dead after the
102
+ > 10-minute TTL — there is no store-surface delete for them by design (they
103
+ > are the auth trail). The happy-path session mint is exercised with a real
104
+ > inbox-free code by `tests/store/customer-accounts-auth.test.ts` and the
105
+ > SDK contract test (server-side code issue via the lib).