@managesales/storefront 1.0.0 → 1.0.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +327 -38
  3. package/package.json +2 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@managesales/storefront`. This project adheres to
4
+ [Semantic Versioning](https://semver.org).
5
+
6
+ ## 1.0.2 — 2026-07-11
7
+
8
+ ### Docs
9
+ - Rewrote the README as a full developer landing page: human-readable title and tagline, feature
10
+ overview, all-package-manager install, a copy-paste quick start, a complete **API organization**
11
+ reference, framework examples (React / Next.js / Node.js), server-side auth (SSR) guide, error
12
+ handling, TypeScript guide, a **Versioning** policy, and this changelog.
13
+
14
+ ## 1.0.1 — 2026-07-11
15
+
16
+ ### Docs
17
+ - Expanded the README with per-resource examples and browser/Node runtime support notes.
18
+
19
+ ## 1.0.0 — 2026-07-11
20
+
21
+ ### Added
22
+ - Initial public release. Resource-based Storefront SDK with namespaces for products, collections,
23
+ checkout, cart recovery, auth, customer, blog, bookings, and forms.
24
+ - Built-in customer auth with automatic access-token refresh on `401`.
25
+ - `StorefrontError` class exposing `status`, `code`, `message`, and `details`.
26
+ - Dual ESM + CommonJS builds with bundled TypeScript declarations. Zero runtime dependencies.
package/README.md CHANGED
@@ -1,77 +1,366 @@
1
- # @managesales/storefront
1
+ # ManageSales Storefront SDK
2
2
 
3
- Resource-based TypeScript client for building online storefronts on the **ManageSales Storefront
4
- API** — like Shopify's Storefront API client. Built-in auth, automatic token refresh, typed
5
- responses, and **zero runtime dependencies**.
3
+ **Build custom storefronts on top of the ManageSales Commerce Platform.**
6
4
 
7
- > The same client is also available without npm: `curl` it from the backend at
8
- > `GET /api/v1/sdk/storefront.ts`, or download it from **Developers → SDKs** in the app. All three
9
- > surfaces are generated from one source, so they're always identical.
5
+ [![npm version](https://img.shields.io/npm/v/@managesales/storefront.svg)](https://www.npmjs.com/package/@managesales/storefront)
6
+ [![license](https://img.shields.io/npm/l/@managesales/storefront.svg)](./LICENSE)
7
+ [![types](https://img.shields.io/npm/types/@managesales/storefront.svg)](#typescript-support)
8
+ [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](#browser--node-support)
10
9
 
11
- ## Install
10
+ `@managesales/storefront` is a typed, resource-based client for the ManageSales Storefront API —
11
+ like Shopify's Storefront client, for ManageSales. Everything you need to ship a storefront:
12
+
13
+ - 🛍️ **Products** — list, search, and fetch details
14
+ - 🗂️ **Collections** — browse categories and their products
15
+ - 👤 **Customers** — registration, login, profile, order history
16
+ - 🛒 **Checkout** — line items, coupons, complete purchases (+ abandoned-cart recovery)
17
+ - 🔎 **Search** — full-text product search
18
+ - 🟦 **TypeScript** — first-class types, no `@types` needed
19
+ - ⚡ **SSR-ready** — inject a custom `fetch`; server-side auth pattern built in
20
+ - 📦 **Zero dependencies** — one small file, dual ESM + CommonJS
21
+
22
+ ---
23
+
24
+ ## Table of contents
25
+
26
+ - [Installation](#installation)
27
+ - [Quick start](#quick-start)
28
+ - [API organization](#api-organization)
29
+ - [Create a client](#create-a-client)
30
+ - [Products & search](#products--search)
31
+ - [Collections](#collections)
32
+ - [Cart & checkout](#cart--checkout)
33
+ - [Authentication](#authentication)
34
+ - [Customer account](#customer-account)
35
+ - [Error handling](#error-handling)
36
+ - [TypeScript support](#typescript-support)
37
+ - [Framework examples](#framework-examples)
38
+ - [Browser & Node support](#browser--node-support)
39
+ - [Versioning](#versioning)
40
+ - [Changelog](#changelog)
41
+ - [No-npm alternative](#no-npm-alternative)
42
+ - [License](#license)
43
+
44
+ ## Installation
12
45
 
13
46
  ```bash
14
47
  npm install @managesales/storefront
15
- # or: pnpm add @managesales/storefront / yarn add @managesales/storefront
48
+ pnpm add @managesales/storefront
49
+ yarn add @managesales/storefront
50
+ bun add @managesales/storefront
16
51
  ```
17
52
 
18
- ## Usage
53
+ ## Quick start
54
+
55
+ Copy-paste, add your workspace ID, and you're fetching live catalog data — no auth required:
19
56
 
20
57
  ```ts
21
58
  import { createStorefrontClient } from "@managesales/storefront";
22
59
 
23
60
  const client = createStorefrontClient({
24
- workspaceId: "ws_123", // requiredidentifies your storefront
61
+ workspaceId: "ws_123", // your store Settings API
25
62
  });
26
63
 
27
- const products = await client.products.list();
64
+ const { data: products } = await client.products.list({ limit: 12 });
65
+ console.log(products);
28
66
  ```
29
67
 
30
- The backend URL defaults to production. Point it elsewhere (self-hosted, staging, local) at runtime
31
- — the URL must include the `/api/v1` prefix:
68
+ ## API organization
69
+
70
+ Every resource is a namespace on the client. Public resources need no auth; customer resources
71
+ require a logged-in session.
72
+
73
+ ```ts
74
+ // Catalog (public)
75
+ client.products.list(params?) // paginated list
76
+ client.products.get(idOrSlug) // product details
77
+ client.products.search(query, params?) // full-text search
78
+ client.collections.list(params?)
79
+ client.collections.get(idOrSlug) // collection + its products
80
+
81
+ // Cart & checkout (public)
82
+ client.checkout.create(lineItems) // start a checkout from line items
83
+ client.checkout.get(checkoutId)
84
+ client.checkout.applyCoupon(checkoutId, code)
85
+ client.checkout.complete(checkoutId, payment?)
86
+ client.cart.recover(token) // rebuild a checkout from a recovery link
87
+
88
+ // Auth & customer (customer session)
89
+ client.auth.register({ email, password, name })
90
+ client.auth.login(email, password)
91
+ client.auth.loginWithGoogle(idToken)
92
+ client.auth.logout()
93
+ client.auth.isAuthenticated()
94
+ client.auth.setTokens(access, refresh) // restore a session (e.g. from cookies)
95
+ client.customer.me()
96
+ client.customer.orders(params?) // order history
97
+ client.customer.addresses()
98
+
99
+ // Content (public)
100
+ client.blog.list(params?) / client.blog.get(slug)
101
+ client.bookings.services() / client.bookings.availability(params) / client.bookings.book(data)
102
+ client.forms.get(idOrSlug) / client.forms.submit(formId, data) / client.forms.uploadFile(formId, file)
103
+ ```
104
+
105
+ ## Create a client
106
+
107
+ ```ts
108
+ const client = createStorefrontClient({
109
+ workspaceId: "ws_123",
110
+ });
111
+ ```
112
+
113
+ | Option | Type | Required | Description |
114
+ |--------|------|----------|-------------|
115
+ | `workspaceId` | `string` | ✅ | Identifies your store. Found in **Settings → API**. |
116
+ | `apiUrl` | `string` | — | Backend base URL **including** the `/api/v1` prefix. Defaults to ManageSales cloud; override for self-hosted / staging / local. |
117
+ | `customFetch` | `typeof fetch` | — | Inject a `fetch` for SSR / edge runtimes or Node < 18. |
118
+ | `locale` | `string` | — | Default locale for localized content (e.g. `"en"`). |
32
119
 
33
120
  ```ts
34
121
  const client = createStorefrontClient({
35
122
  workspaceId: "ws_123",
36
- apiUrl: "https://your-backend.example.com/api/v1",
123
+ apiUrl: "https://api.mystore.com/api/v1",
124
+ customFetch: fetch,
125
+ locale: "en",
126
+ });
127
+ ```
128
+
129
+ ## Products & search
130
+
131
+ ```ts
132
+ // List with pagination, search, and sorting
133
+ const { data: products, total } = await client.products.list({
134
+ page: 1,
135
+ limit: 20,
136
+ search: "red shoes",
137
+ sort: "price",
138
+ order: "asc",
37
139
  });
140
+
141
+ // Product details — by ID or slug
142
+ const product = await client.products.get("leather-jacket");
143
+ console.log(product.name, product.price, product.variants);
144
+
145
+ // Full-text search
146
+ const { data: results } = await client.products.search("organic cotton");
147
+ ```
148
+
149
+ ## Collections
150
+
151
+ ```ts
152
+ const { data: collections } = await client.collections.list();
153
+
154
+ const summer = await client.collections.get("summer-sale");
155
+ console.log(summer.name, summer.products.length); // collection + its products
156
+ ```
157
+
158
+ ## Cart & checkout
159
+
160
+ Assemble line items in your UI, create a checkout session, optionally apply a coupon, then complete
161
+ it:
162
+
163
+ ```ts
164
+ // 1. Create a checkout from line items
165
+ const session = await client.checkout.create([
166
+ { productId: "prod_123", variantId: "var_456", quantity: 2 },
167
+ { productId: "prod_789", quantity: 1 },
168
+ ]);
169
+
170
+ // 2. Re-fetch a session (e.g. after a reload)
171
+ const current = await client.checkout.get(session.id);
172
+
173
+ // 3. Apply a coupon
174
+ const discounted = await client.checkout.applyCoupon(session.id, "SAVE10");
175
+ console.log(discounted.discount, discounted.total);
176
+
177
+ // 4. Complete the purchase
178
+ const order = await client.checkout.complete(session.id, {
179
+ paymentMethod: "card",
180
+ token: "tok_visa_xxx",
181
+ });
182
+ console.log("Order placed:", order.orderNumber);
183
+ ```
184
+
185
+ **Abandoned-cart recovery** — turn a recovery link back into a checkout session:
186
+
187
+ ```ts
188
+ const token = new URLSearchParams(location.search).get("token")!;
189
+ const recovered = await client.cart.recover(token);
190
+ ```
191
+
192
+ ## Authentication
193
+
194
+ Most pages need **no auth**. When a customer logs in, the SDK stores the access + refresh tokens and
195
+ **auto-refreshes on `401`** — you never handle tokens by hand.
196
+
197
+ ```ts
198
+ await client.auth.register({ email: "jane@example.com", password: "SecurePass123!", name: "Jane Doe" });
199
+ await client.auth.login("jane@example.com", "SecurePass123!");
200
+ await client.auth.loginWithGoogle(googleIdToken); // pass a Google ID token
201
+
202
+ if (client.auth.isAuthenticated()) { /* show account menu */ }
203
+ await client.auth.logout();
204
+ ```
205
+
206
+ ### Server-side (recommended)
207
+
208
+ For production, run the SDK on your server with httpOnly cookies so tokens never reach the browser.
209
+ Restore a session with `setTokens`:
210
+
211
+ ```ts
212
+ // app/api/storefront/[...path]/route.ts (Next.js)
213
+ import { createStorefrontClient } from "@managesales/storefront";
214
+ import { cookies } from "next/headers";
215
+
216
+ export async function GET() {
217
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
218
+
219
+ const access = cookies().get("sf_access_token")?.value;
220
+ const refresh = cookies().get("sf_refresh_token")?.value;
221
+ if (access && refresh) client.auth.setTokens(access, refresh);
222
+
223
+ const products = await client.products.list({ limit: 20 });
224
+ return Response.json(products);
225
+ }
226
+ ```
227
+
228
+ ## Customer account
229
+
230
+ Requires a logged-in session.
231
+
232
+ ```ts
233
+ const me = await client.customer.me(); // profile
234
+ const { data: orders } = await client.customer.orders({ page: 1 }); // order history
235
+ const addresses = await client.customer.addresses(); // saved addresses
236
+ ```
237
+
238
+ ## Error handling
239
+
240
+ Every non-2xx response throws a `StorefrontError` with structured fields:
241
+
242
+ ```ts
243
+ import { StorefrontError } from "@managesales/storefront";
244
+
245
+ try {
246
+ await client.products.get("does-not-exist");
247
+ } catch (err) {
248
+ if (err instanceof StorefrontError) {
249
+ console.log(err.status); // 404
250
+ console.log(err.code); // "NOT_FOUND"
251
+ console.log(err.message); // "Product not found"
252
+ console.log(err.details); // full error body from the API
253
+ } else {
254
+ throw err; // network / unexpected
255
+ }
256
+ }
257
+ ```
258
+
259
+ > **Resilience:** the client automatically retries a request **once** with a refreshed token when a
260
+ > `401` indicates an expired access token. It does not retry on network/5xx errors — wrap calls in
261
+ > your own retry policy if you need that.
262
+
263
+ ## TypeScript support
264
+
265
+ Written in TypeScript and shipped with declaration files — no `@types/*` package. Params and
266
+ responses are fully typed, including generics like `PaginatedResponse<Product>`:
267
+
268
+ ```ts
269
+ import {
270
+ createStorefrontClient,
271
+ StorefrontError,
272
+ type StorefrontConfig,
273
+ type Product,
274
+ type PaginatedResponse,
275
+ } from "@managesales/storefront";
276
+
277
+ const config: StorefrontConfig = { workspaceId: "ws_123" };
278
+ const client = createStorefrontClient(config);
279
+
280
+ const page: PaginatedResponse<Product> = await client.products.list();
38
281
  ```
39
282
 
40
- For SSR / edge runtimes you can inject a custom `fetch`:
283
+ ## Framework examples
284
+
285
+ **React**
286
+
287
+ ```tsx
288
+ import { useEffect, useState } from "react";
289
+ import { createStorefrontClient, type Product } from "@managesales/storefront";
290
+
291
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
292
+
293
+ export function ProductGrid() {
294
+ const [products, setProducts] = useState<Product[]>([]);
295
+ useEffect(() => {
296
+ client.products.list({ limit: 12 }).then((res) => setProducts(res.data));
297
+ }, []);
298
+ return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
299
+ }
300
+ ```
301
+
302
+ **Next.js (Server Component)**
303
+
304
+ ```tsx
305
+ // app/page.tsx
306
+ import { createStorefrontClient } from "@managesales/storefront";
307
+
308
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
309
+
310
+ export default async function Home() {
311
+ const { data: products } = await client.products.list({ limit: 12 });
312
+ return <ProductGrid products={products} />;
313
+ }
314
+ ```
315
+
316
+ **Node.js**
41
317
 
42
318
  ```ts
43
- createStorefrontClient({ workspaceId: "ws_123", customFetch: fetch });
319
+ import { createStorefrontClient } from "@managesales/storefront";
320
+
321
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
322
+
323
+ const { data } = await client.products.list({ page: 1, limit: 20 });
324
+ console.log(data);
44
325
  ```
45
326
 
46
- Errors thrown by the client are instances of `StorefrontError` (exposes `status` and the API
47
- message), so you can branch on failures precisely.
327
+ ## Browser & Node support
328
+
329
+ - **Zero dependencies** — uses the platform's global `fetch`.
330
+ - **Node.js ≥ 18** (global `fetch`). On older Node, pass `customFetch` (e.g. `undici`).
331
+ - **Browsers** — all modern evergreen browsers.
332
+ - **Deno, Bun, edge runtimes** (Cloudflare Workers, Vercel Edge) — supported; inject `customFetch`
333
+ where a global isn't available.
334
+ - **Module formats** — ships both **ESM** (`import`) and **CommonJS** (`require`).
335
+
336
+ ## Versioning
337
+
338
+ Follows [Semantic Versioning](https://semver.org):
339
+
340
+ - **patch** (`x.y.Z`) — docs and bug fixes, no API change
341
+ - **minor** (`x.Y.z`) — additive, backward-compatible API
342
+ - **major** (`X.y.z`) — breaking changes to the client surface
343
+
344
+ The SDK version tracks the ManageSales Storefront API contract it targets. See the
345
+ [Changelog](#changelog).
48
346
 
49
- ## Works everywhere
347
+ ## Changelog
50
348
 
51
- Ships dual **ESM + CommonJS** builds with type declarations — usable from Next.js, Remix, Nuxt,
52
- Astro, plain Node (`import` or `require`), Vite, and the browser. Requires Node ≥ 18 (for global
53
- `fetch`).
349
+ See [CHANGELOG.md](./CHANGELOG.md) for release notes.
54
350
 
55
- ## Maintainers
351
+ ## No-npm alternative
56
352
 
57
- This package is **generated**, not hand-written. `src/index.ts` is produced by
58
- `scripts/generate.ts`, which calls the canonical `generateStorefrontSdk` function in the backend
59
- (`backend/src/modules/storefront/sdk/storefront-sdk-source.ts`) — the exact same function that
60
- serves `GET /api/v1/sdk/storefront.ts`. This guarantees the npm package, the curl endpoint, and the
61
- in-app Download never drift.
353
+ Prefer no dependency? The identical client is served as a single file download it from
354
+ **Developers SDKs** in the app, or curl it:
62
355
 
63
356
  ```bash
64
- npm run build # regenerate src/index.ts from the backend, then compile to dist/
65
- npm publish # requires the @managesales npm org + an automation token
357
+ curl -o managesales-storefront.ts \
358
+ "https://managesales-backend-phase1test.up.railway.app/api/v1/sdk/storefront.ts"
66
359
  ```
67
360
 
68
- - Bump the version in **both** `package.json` and the backend's `STOREFRONT_SDK_VERSION`; the build
69
- fails fast if they disagree.
70
- - Override the baked default backend URL at build time with `PUBLIC_API_URL` (must include
71
- `/api/v1`).
72
- - The build imports the generator across the monorepo. If this package is ever extracted to its own
73
- repo, vendor `storefront-sdk-source.ts` into `scripts/` instead.
361
+ Then `import { createStorefrontClient } from "./managesales-storefront"`. The npm package, the curl
362
+ endpoint, and the in-app download are generated from one source, so they're always identical.
74
363
 
75
364
  ## License
76
365
 
77
- Apache-2.0. See [LICENSE](./LICENSE).
366
+ [Apache-2.0](./LICENSE) © ManageSales
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managesales/storefront",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Resource-based TypeScript client for building storefronts on the ManageSales Storefront API. Zero runtime dependencies, built-in auth and token refresh.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -16,6 +16,7 @@
16
16
  "files": [
17
17
  "dist",
18
18
  "README.md",
19
+ "CHANGELOG.md",
19
20
  "LICENSE"
20
21
  ],
21
22
  "sideEffects": false,