@managesales/storefront 1.0.0 → 1.0.1

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 (2) hide show
  1. package/README.md +274 -36
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,77 +1,315 @@
1
1
  # @managesales/storefront
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@managesales/storefront.svg)](https://www.npmjs.com/package/@managesales/storefront)
4
+ [![license](https://img.shields.io/npm/l/@managesales/storefront.svg)](./LICENSE)
5
+ [![types](https://img.shields.io/npm/types/@managesales/storefront.svg)](#typescript-support)
6
+ [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](#browser--node-support)
7
+
3
8
  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**.
9
+ API** — think Shopify's Storefront API client, for ManageSales. Browse products, run checkout, and
10
+ manage customer accounts with a typed, ergonomic client instead of hand-rolled `fetch` calls.
11
+
12
+ - 🧩 **Resource namespaces** — `client.products`, `client.checkout`, `client.customer`, …
13
+ - 🔐 **Auth built in** — customer login + automatic access-token refresh
14
+ - 📦 **Zero runtime dependencies** — one small file, uses the platform `fetch`
15
+ - 🟦 **Fully typed** — ships `.d.ts`; responses and params are typed end to end
16
+ - 🌐 **Runs everywhere** — dual ESM + CommonJS, browser / Node 18+ / Deno / Bun / edge
17
+
18
+ ---
19
+
20
+ ## Table of contents
21
+
22
+ - [What is this?](#what-is-this)
23
+ - [Installation](#installation)
24
+ - [Quick start](#quick-start-30-seconds)
25
+ - [Create a client](#create-a-client)
26
+ - [Products](#products)
27
+ - [Collections](#collections)
28
+ - [Cart & checkout](#cart--checkout)
29
+ - [Authentication](#authentication)
30
+ - [Customer account](#customer-account)
31
+ - [Error handling](#error-handling)
32
+ - [More resources](#more-resources)
33
+ - [TypeScript support](#typescript-support)
34
+ - [Browser & Node support](#browser--node-support)
35
+ - [No-npm alternative](#no-npm-alternative)
36
+ - [License](#license)
37
+
38
+ ---
6
39
 
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.
40
+ ## What is this?
10
41
 
11
- ## Install
42
+ `@managesales/storefront` is the official client SDK for the **ManageSales Storefront API** — the
43
+ public, customer-facing API behind a ManageSales store. Use it to build a custom storefront
44
+ (product pages, search, cart, checkout, customer login) in any JavaScript/TypeScript framework,
45
+ while the SDK handles request headers, workspace scoping, error parsing, pagination, and token
46
+ refresh for you.
47
+
48
+ It talks to the same API you can also reach directly over HTTP (`/storefront-api/*`) — the SDK is
49
+ just the typed, batteries-included way to do it.
50
+
51
+ ## Installation
12
52
 
13
53
  ```bash
14
54
  npm install @managesales/storefront
15
- # or: pnpm add @managesales/storefront / yarn add @managesales/storefront
55
+ # pnpm add @managesales/storefront
56
+ # yarn add @managesales/storefront
57
+ # bun add @managesales/storefront
16
58
  ```
17
59
 
18
- ## Usage
60
+ ## Quick start (30 seconds)
19
61
 
20
62
  ```ts
21
63
  import { createStorefrontClient } from "@managesales/storefront";
22
64
 
23
65
  const client = createStorefrontClient({
24
- workspaceId: "ws_123", // requiredidentifies your storefront
66
+ workspaceId: "ws_123", // your store's workspace ID Settings API
25
67
  });
26
68
 
27
- const products = await client.products.list();
69
+ // Browse products no authentication required
70
+ const { data: products, total } = await client.products.list({ limit: 12 });
71
+ console.log(`${total} products`, products);
28
72
  ```
29
73
 
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:
74
+ That's it public catalog data needs no auth. Add [authentication](#authentication) only when
75
+ customers log in.
76
+
77
+ ## Create a client
32
78
 
33
79
  ```ts
80
+ import { createStorefrontClient } from "@managesales/storefront";
81
+
34
82
  const client = createStorefrontClient({
35
83
  workspaceId: "ws_123",
36
- apiUrl: "https://your-backend.example.com/api/v1",
37
84
  });
38
85
  ```
39
86
 
40
- For SSR / edge runtimes you can inject a custom `fetch`:
87
+ | Option | Type | Required | Description |
88
+ |--------|------|----------|-------------|
89
+ | `workspaceId` | `string` | ✅ | Identifies your store. Found in **Settings → API**. |
90
+ | `apiUrl` | `string` | — | Backend base URL **including** the `/api/v1` prefix. Defaults to ManageSales cloud; override for self-hosted/staging/local. |
91
+ | `customFetch` | `typeof fetch` | — | Inject a `fetch` implementation for SSR/edge runtimes or Node < 18. |
92
+ | `locale` | `string` | — | Default locale for localized content (e.g. `"en"`). |
93
+
94
+ ```ts
95
+ // Point at your own backend and inject a custom fetch:
96
+ const client = createStorefrontClient({
97
+ workspaceId: "ws_123",
98
+ apiUrl: "https://api.mystore.com/api/v1",
99
+ customFetch: fetch,
100
+ locale: "en",
101
+ });
102
+ ```
103
+
104
+ ## Products
105
+
106
+ ```ts
107
+ // List with pagination, search, and sorting
108
+ const { data: products, total } = await client.products.list({
109
+ page: 1,
110
+ limit: 20,
111
+ search: "red shoes",
112
+ sort: "price",
113
+ order: "asc",
114
+ });
115
+
116
+ // Product details — by ID or slug
117
+ const product = await client.products.get("leather-jacket");
118
+ console.log(product.name, product.price, product.variants);
119
+
120
+ // Full-text search
121
+ const { data: results } = await client.products.search("organic cotton");
122
+ ```
123
+
124
+ ## Collections
125
+
126
+ ```ts
127
+ // List collections
128
+ const { data: collections } = await client.collections.list();
129
+
130
+ // Get a collection with its products
131
+ const summer = await client.collections.get("summer-sale");
132
+ console.log(summer.name, summer.products.length);
133
+ ```
134
+
135
+ ## Cart & checkout
136
+
137
+ The SDK models a cart as a set of checkout line items. Assemble items in your UI, create a checkout
138
+ session, optionally apply a coupon, then complete it.
139
+
140
+ ```ts
141
+ // 1. Create a checkout from cart line items
142
+ const session = await client.checkout.create([
143
+ { productId: "prod_123", variantId: "var_456", quantity: 2 },
144
+ { productId: "prod_789", quantity: 1 },
145
+ ]);
146
+
147
+ // 2. Re-fetch a session (e.g. after a page reload)
148
+ const current = await client.checkout.get(session.id);
149
+
150
+ // 3. Apply a coupon
151
+ const discounted = await client.checkout.applyCoupon(session.id, "SAVE10");
152
+ console.log("Discount:", discounted.discount, "Total:", discounted.total);
153
+
154
+ // 4. Complete the purchase
155
+ const order = await client.checkout.complete(session.id, {
156
+ paymentMethod: "card",
157
+ token: "tok_visa_xxx",
158
+ });
159
+ console.log("Order placed:", order.orderNumber);
160
+ ```
161
+
162
+ **Abandoned-cart recovery** — turn a recovery link back into a checkout session:
163
+
164
+ ```ts
165
+ // URL: https://yourstore.com/recover?token=abc123
166
+ const token = new URLSearchParams(location.search).get("token")!;
167
+ const recovered = await client.cart.recover(token);
168
+ ```
169
+
170
+ ## Authentication
171
+
172
+ Most storefront pages need **no auth**. When a customer logs in, the SDK stores the access + refresh
173
+ tokens internally and refreshes them automatically on `401` — you never handle tokens by hand.
174
+
175
+ ```ts
176
+ // Register
177
+ const session = await client.auth.register({
178
+ email: "jane@example.com",
179
+ password: "SecurePass123!",
180
+ name: "Jane Doe",
181
+ });
182
+
183
+ // Login
184
+ await client.auth.login("jane@example.com", "SecurePass123!");
185
+
186
+ // Google OAuth (pass a Google ID token)
187
+ await client.auth.loginWithGoogle(googleIdToken);
188
+
189
+ // Check state / log out
190
+ if (client.auth.isAuthenticated()) {
191
+ /* show account menu */
192
+ }
193
+ await client.auth.logout();
194
+ ```
195
+
196
+ ### Server-side (recommended)
197
+
198
+ For production, run the SDK on your server (Next.js route handlers, Express, etc.) with httpOnly
199
+ cookies so tokens never reach the browser. Restore a session from cookies with `setTokens`:
200
+
201
+ ```ts
202
+ // app/api/storefront/[...path]/route.ts
203
+ import { createStorefrontClient } from "@managesales/storefront";
204
+ import { cookies } from "next/headers";
205
+
206
+ export async function GET() {
207
+ const client = createStorefrontClient({ workspaceId: "ws_123" });
208
+
209
+ const access = cookies().get("sf_access_token")?.value;
210
+ const refresh = cookies().get("sf_refresh_token")?.value;
211
+ if (access && refresh) client.auth.setTokens(access, refresh);
212
+
213
+ const products = await client.products.list({ limit: 20 });
214
+ return Response.json(products);
215
+ }
216
+ ```
217
+
218
+ ## Customer account
219
+
220
+ Requires a logged-in session (see [Authentication](#authentication)).
41
221
 
42
222
  ```ts
43
- createStorefrontClient({ workspaceId: "ws_123", customFetch: fetch });
223
+ const me = await client.customer.me(); // profile
224
+ const { data: orders } = await client.customer.orders({ page: 1 }); // order history
225
+ const addresses = await client.customer.addresses(); // saved addresses
44
226
  ```
45
227
 
46
- Errors thrown by the client are instances of `StorefrontError` (exposes `status` and the API
47
- message), so you can branch on failures precisely.
228
+ ## Error handling
229
+
230
+ Every non-2xx response throws a `StorefrontError` with structured fields, so you can branch
231
+ precisely:
232
+
233
+ ```ts
234
+ import { StorefrontError } from "@managesales/storefront";
235
+
236
+ try {
237
+ await client.products.get("does-not-exist");
238
+ } catch (err) {
239
+ if (err instanceof StorefrontError) {
240
+ console.log(err.status); // 404
241
+ console.log(err.code); // "NOT_FOUND"
242
+ console.log(err.message); // "Product not found"
243
+ console.log(err.details); // full error body from the API
244
+ } else {
245
+ throw err; // network / unexpected
246
+ }
247
+ }
248
+ ```
249
+
250
+ ## More resources
251
+
252
+ The client also exposes `client.blog`, `client.bookings`, and `client.forms`:
253
+
254
+ ```ts
255
+ const { data: posts } = await client.blog.list({ limit: 10 });
256
+ const post = await client.blog.get("how-to-style-leather");
257
+
258
+ const services = await client.bookings.services();
259
+ const slots = await client.bookings.availability({ serviceId: "svc_1", date: "2026-08-15" });
260
+ const booking = await client.bookings.book({
261
+ serviceId: "svc_1",
262
+ date: "2026-08-15",
263
+ startTime: "10:00",
264
+ customer: { name: "Jane Doe", email: "jane@example.com" },
265
+ });
266
+
267
+ const form = await client.forms.get("contact-us");
268
+ await client.forms.submit(form.id, { name: "Jane", email: "jane@example.com", message: "Hi!" });
269
+ ```
270
+
271
+ ## TypeScript support
272
+
273
+ Written in TypeScript and shipped with declaration files — no `@types/*` package needed. Params and
274
+ responses are fully typed, including generics like `PaginatedResponse<Product>`:
275
+
276
+ ```ts
277
+ import {
278
+ createStorefrontClient,
279
+ StorefrontError,
280
+ type StorefrontConfig,
281
+ type Product,
282
+ type PaginatedResponse,
283
+ } from "@managesales/storefront";
284
+
285
+ const config: StorefrontConfig = { workspaceId: "ws_123" };
286
+ const client = createStorefrontClient(config);
287
+
288
+ const page: PaginatedResponse<Product> = await client.products.list();
289
+ ```
48
290
 
49
- ## Works everywhere
291
+ ## Browser & Node support
50
292
 
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`).
293
+ - **Zero dependencies** — uses the platform's global `fetch`.
294
+ - **Node.js ≥ 18** (global `fetch`). On older Node, pass `customFetch` (e.g. `undici`).
295
+ - **Browsers** — all modern evergreen browsers.
296
+ - **Deno, Bun, and edge runtimes** (Cloudflare Workers, Vercel Edge) — supported; inject
297
+ `customFetch` where a global isn't available.
298
+ - **Module formats** — ships both **ESM** (`import`) and **CommonJS** (`require`).
54
299
 
55
- ## Maintainers
300
+ ## No-npm alternative
56
301
 
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.
302
+ Prefer not to add a dependency? The exact same client is served as a single file — download it from
303
+ **Developers SDKs** in the app, or curl it:
62
304
 
63
305
  ```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
306
+ curl -o managesales-storefront.ts \
307
+ "https://managesales-backend-phase1test.up.railway.app/api/v1/sdk/storefront.ts"
66
308
  ```
67
309
 
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.
310
+ Then `import { createStorefrontClient } from "./managesales-storefront"`. The npm package, the curl
311
+ endpoint, and the in-app download are all generated from one source, so they're always identical.
74
312
 
75
313
  ## License
76
314
 
77
- Apache-2.0. See [LICENSE](./LICENSE).
315
+ [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.1",
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",