@managesales/storefront 1.0.1 → 1.1.0
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/CHANGELOG.md +58 -0
- package/README.md +230 -103
- package/dist/index.cjs +179 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -1
- package/dist/index.d.ts +88 -1
- package/dist/index.js +179 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,18 @@ function createStorefrontClient(config) {
|
|
|
15
15
|
const fetchFn = config.customFetch ?? globalThis.fetch.bind(globalThis);
|
|
16
16
|
let accessToken = null;
|
|
17
17
|
let refreshToken = null;
|
|
18
|
+
const RETRY_DEFAULTS = {
|
|
19
|
+
retries: 2,
|
|
20
|
+
baseDelayMs: 300,
|
|
21
|
+
maxDelayMs: 4e3,
|
|
22
|
+
retryOnStatus: [408, 425, 429, 500, 502, 503, 504]
|
|
23
|
+
};
|
|
24
|
+
const rc = config.retry === false ? { ...RETRY_DEFAULTS, retries: 0 } : { ...RETRY_DEFAULTS, ...config.retry || {} };
|
|
25
|
+
const IDEMPOTENT = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
26
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
function backoff(attempt) {
|
|
28
|
+
return Math.min(rc.maxDelayMs, Math.round(Math.random() * rc.baseDelayMs * Math.pow(2, attempt)));
|
|
29
|
+
}
|
|
18
30
|
async function request(method, path, options) {
|
|
19
31
|
const url = new URL(`${apiUrl}${path}`);
|
|
20
32
|
if (options?.params) {
|
|
@@ -31,11 +43,32 @@ function createStorefrontClient(config) {
|
|
|
31
43
|
if (options?.body) {
|
|
32
44
|
headers["Content-Type"] = "application/json";
|
|
33
45
|
}
|
|
34
|
-
const
|
|
46
|
+
const fetchOptions = {
|
|
35
47
|
method,
|
|
36
48
|
headers,
|
|
37
49
|
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
38
|
-
}
|
|
50
|
+
};
|
|
51
|
+
let attempt = 0;
|
|
52
|
+
let res;
|
|
53
|
+
while (true) {
|
|
54
|
+
try {
|
|
55
|
+
res = await fetchFn(url.toString(), fetchOptions);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
if (attempt < rc.retries) {
|
|
58
|
+
await sleep(backoff(attempt));
|
|
59
|
+
attempt++;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
if (attempt < rc.retries && rc.retryOnStatus.includes(res.status) && IDEMPOTENT.has(method)) {
|
|
65
|
+
const ra = Number(res.headers.get("retry-after"));
|
|
66
|
+
await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1e3 : backoff(attempt));
|
|
67
|
+
attempt++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
39
72
|
if (res.status === 401 && options?.auth && refreshToken) {
|
|
40
73
|
const refreshed = await refreshSession();
|
|
41
74
|
if (refreshed) {
|
|
@@ -122,7 +155,7 @@ function createStorefrontClient(config) {
|
|
|
122
155
|
const checkout = {
|
|
123
156
|
/** Create a checkout session from cart items */
|
|
124
157
|
async create(items) {
|
|
125
|
-
return request("POST", "/checkout", { body: { items } });
|
|
158
|
+
return request("POST", "/checkout", { body: { lines: items } });
|
|
126
159
|
},
|
|
127
160
|
/** Retrieve an existing checkout session */
|
|
128
161
|
async get(checkoutId) {
|
|
@@ -254,12 +287,152 @@ function createStorefrontClient(config) {
|
|
|
254
287
|
return res.json();
|
|
255
288
|
}
|
|
256
289
|
};
|
|
290
|
+
const CART_KEY = "managesales_cart_" + config.workspaceId;
|
|
291
|
+
const hasLS = () => {
|
|
292
|
+
try {
|
|
293
|
+
return config.persistCart !== false && typeof localStorage !== "undefined";
|
|
294
|
+
} catch {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const loadCart = () => {
|
|
299
|
+
if (!hasLS()) return null;
|
|
300
|
+
try {
|
|
301
|
+
const s = localStorage.getItem(CART_KEY);
|
|
302
|
+
return s ? JSON.parse(s) : null;
|
|
303
|
+
} catch {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const saveCart = (st) => {
|
|
308
|
+
if (!hasLS()) return;
|
|
309
|
+
try {
|
|
310
|
+
localStorage.setItem(CART_KEY, JSON.stringify(st));
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
let __lineSeq = 0;
|
|
315
|
+
const genId = (p) => typeof crypto !== "undefined" && crypto.randomUUID ? p + crypto.randomUUID() : p + Date.now() + "_" + ++__lineSeq;
|
|
316
|
+
const nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
317
|
+
const freshCart = () => ({ id: genId("cart_"), lines: [], createdAt: nowIso(), updatedAt: nowIso() });
|
|
318
|
+
function makeCart(state) {
|
|
319
|
+
const persist = () => {
|
|
320
|
+
state.updatedAt = nowIso();
|
|
321
|
+
saveCart(state);
|
|
322
|
+
};
|
|
323
|
+
const cartObj = {
|
|
324
|
+
get id() {
|
|
325
|
+
return state.id;
|
|
326
|
+
},
|
|
327
|
+
get lines() {
|
|
328
|
+
return state.lines;
|
|
329
|
+
},
|
|
330
|
+
get itemCount() {
|
|
331
|
+
return state.lines.reduce((n, l) => n + l.quantity, 0);
|
|
332
|
+
},
|
|
333
|
+
get subtotal() {
|
|
334
|
+
return state.lines.reduce((s, l) => s + l.unitPrice * l.quantity, 0);
|
|
335
|
+
},
|
|
336
|
+
// Supplying unitPrice alone does not skip the lookup — productName must also be
|
|
337
|
+
// provided, otherwise this falls through to the products.get() network lookup below.
|
|
338
|
+
async addLineItem(input) {
|
|
339
|
+
let line;
|
|
340
|
+
if (input.unitPrice != null && input.productName) {
|
|
341
|
+
line = {
|
|
342
|
+
id: genId("line_"),
|
|
343
|
+
productId: input.productId,
|
|
344
|
+
variantId: input.variantId,
|
|
345
|
+
quantity: input.quantity,
|
|
346
|
+
unitPrice: input.unitPrice,
|
|
347
|
+
productName: input.productName,
|
|
348
|
+
imageUrl: input.imageUrl
|
|
349
|
+
};
|
|
350
|
+
} else {
|
|
351
|
+
const p = await products.get(input.productId);
|
|
352
|
+
const v = input.variantId && Array.isArray(p.variants) ? p.variants.find((x) => x.id === input.variantId) : void 0;
|
|
353
|
+
line = {
|
|
354
|
+
id: genId("line_"),
|
|
355
|
+
productId: input.productId,
|
|
356
|
+
variantId: input.variantId,
|
|
357
|
+
quantity: input.quantity,
|
|
358
|
+
unitPrice: v && v.price != null ? v.price : p.price,
|
|
359
|
+
productName: p.name,
|
|
360
|
+
imageUrl: Array.isArray(p.images) && p.images.length > 0 ? p.images[0].url : void 0
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
const existing = state.lines.find((l) => l.productId === line.productId && l.variantId === line.variantId);
|
|
364
|
+
if (existing) existing.quantity += line.quantity;
|
|
365
|
+
else state.lines.push(line);
|
|
366
|
+
persist();
|
|
367
|
+
return cartObj;
|
|
368
|
+
},
|
|
369
|
+
updateLineItem(lineId, quantity) {
|
|
370
|
+
const l = state.lines.find((x) => x.id === lineId);
|
|
371
|
+
if (l) {
|
|
372
|
+
if (quantity <= 0) state.lines = state.lines.filter((x) => x.id !== lineId);
|
|
373
|
+
else l.quantity = quantity;
|
|
374
|
+
persist();
|
|
375
|
+
}
|
|
376
|
+
return cartObj;
|
|
377
|
+
},
|
|
378
|
+
removeLineItem(lineId) {
|
|
379
|
+
state.lines = state.lines.filter((x) => x.id !== lineId);
|
|
380
|
+
persist();
|
|
381
|
+
return cartObj;
|
|
382
|
+
},
|
|
383
|
+
clear() {
|
|
384
|
+
state.lines = [];
|
|
385
|
+
persist();
|
|
386
|
+
return cartObj;
|
|
387
|
+
},
|
|
388
|
+
async checkout(opts) {
|
|
389
|
+
const session = await checkout.create(
|
|
390
|
+
state.lines.map((l) => ({
|
|
391
|
+
productId: l.productId,
|
|
392
|
+
variantId: l.variantId,
|
|
393
|
+
productName: l.productName,
|
|
394
|
+
quantity: l.quantity,
|
|
395
|
+
unitPrice: l.unitPrice,
|
|
396
|
+
imageUrl: l.imageUrl
|
|
397
|
+
}))
|
|
398
|
+
);
|
|
399
|
+
if (opts && opts.clearOnSuccess) cartObj.clear();
|
|
400
|
+
return session;
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
return cartObj;
|
|
404
|
+
}
|
|
257
405
|
const cart = {
|
|
406
|
+
/** Create a new, empty cart (replaces any persisted cart) */
|
|
407
|
+
create() {
|
|
408
|
+
const st = freshCart();
|
|
409
|
+
saveCart(st);
|
|
410
|
+
return makeCart(st);
|
|
411
|
+
},
|
|
412
|
+
/** Get the current cart — loaded from storage if persisted, otherwise a fresh one */
|
|
413
|
+
current() {
|
|
414
|
+
return makeCart(loadCart() || freshCart());
|
|
415
|
+
},
|
|
258
416
|
/** Recover an abandoned cart by recovery token */
|
|
259
417
|
async recover(token) {
|
|
260
418
|
return request("GET", `/abandoned-carts/recover/${token}`);
|
|
261
419
|
}
|
|
262
420
|
};
|
|
421
|
+
const orders = {
|
|
422
|
+
/** Get customer's order history (delegates to `customer.orders`) */
|
|
423
|
+
list: (params) => customer.orders(params)
|
|
424
|
+
};
|
|
425
|
+
const customers = {
|
|
426
|
+
login: auth.login,
|
|
427
|
+
register: auth.register,
|
|
428
|
+
loginWithGoogle: auth.loginWithGoogle,
|
|
429
|
+
logout: auth.logout,
|
|
430
|
+
isAuthenticated: auth.isAuthenticated,
|
|
431
|
+
setTokens: auth.setTokens,
|
|
432
|
+
me: customer.me,
|
|
433
|
+
orders: customer.orders,
|
|
434
|
+
addresses: customer.addresses
|
|
435
|
+
};
|
|
263
436
|
return {
|
|
264
437
|
store,
|
|
265
438
|
products,
|
|
@@ -270,7 +443,9 @@ function createStorefrontClient(config) {
|
|
|
270
443
|
blog,
|
|
271
444
|
bookings,
|
|
272
445
|
forms,
|
|
273
|
-
cart
|
|
446
|
+
cart,
|
|
447
|
+
orders,
|
|
448
|
+
customers
|
|
274
449
|
};
|
|
275
450
|
}
|
|
276
451
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ManageSales Storefront SDK\n * --------------------------\n * Resource-based client for building online storefronts.\n * Works with any framework: Next.js, Remix, Nuxt, Astro, plain HTML.\n *\n * Usage:\n * import { createStorefrontClient } from \"./managesales-storefront\";\n * const client = createStorefrontClient({ workspaceId: \"<workspace_id>\" });\n * const products = await client.products.list();\n */\n\n// ── Types ──────────────────────────────────────────────────────────\n\nexport interface StorefrontConfig {\n /** Your workspace ID (required) */\n workspaceId: string;\n /** API base URL — defaults to production */\n apiUrl?: string;\n /** Custom fetch implementation (for SSR / edge) */\n customFetch?: typeof fetch;\n /** Default locale for content */\n locale?: string;\n}\n\nexport interface ListParams {\n page?: number;\n limit?: number;\n search?: string;\n sort?: string;\n order?: \"asc\" | \"desc\";\n [key: string]: unknown;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\n// ── Product types ──\n\nexport interface Product {\n id: string;\n name: string;\n slug: string;\n description: string;\n status: string;\n price: number;\n compareAtPrice?: number;\n currency: string;\n images: ProductImage[];\n variants: ProductVariant[];\n category?: { id: string; name: string };\n brand?: { id: string; name: string };\n tags: string[];\n metadata: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ProductImage {\n id: string;\n url: string;\n alt: string;\n position: number;\n}\n\nexport interface ProductVariant {\n id: string;\n name: string;\n sku: string;\n price: number;\n compareAtPrice?: number;\n inventory: number;\n options: Record<string, string>;\n}\n\n// ── Collection types ──\n\nexport interface Collection {\n id: string;\n name: string;\n slug: string;\n description: string;\n image?: string;\n productCount: number;\n}\n\n// ── Cart & Checkout types ──\n\nexport interface CheckoutLineItem {\n productId: string;\n variantId?: string;\n quantity: number;\n}\n\nexport interface CheckoutSession {\n id: string;\n status: \"open\" | \"completed\" | \"expired\";\n items: CheckoutLineItem[];\n subtotal: number;\n tax: number;\n shipping: number;\n discount: number;\n total: number;\n currency: string;\n couponCode?: string;\n}\n\nexport interface Order {\n id: string;\n orderNumber: string;\n status: string;\n total: number;\n currency: string;\n items: OrderItem[];\n createdAt: string;\n}\n\nexport interface OrderItem {\n productId: string;\n name: string;\n quantity: number;\n price: number;\n}\n\n// ── Customer types ──\n\nexport interface Customer {\n id: string;\n email: string;\n name: string;\n phone?: string;\n createdAt: string;\n}\n\nexport interface AuthSession {\n customer: Customer;\n accessToken: string;\n refreshToken: string;\n}\n\nexport interface Address {\n id: string;\n label?: string;\n line1: string;\n line2?: string;\n city: string;\n state: string;\n postalCode: string;\n country: string;\n isDefault: boolean;\n}\n\n// ── Blog types ──\n\nexport interface BlogPost {\n id: string;\n title: string;\n slug: string;\n excerpt: string;\n content: string;\n coverImage?: string;\n tags: string[];\n publishedAt: string;\n}\n\n// ── Booking types ──\n\nexport interface BookableService {\n id: string;\n name: string;\n duration: number;\n price: number;\n description: string;\n}\n\nexport interface TimeSlot {\n start: string;\n end: string;\n available: boolean;\n}\n\nexport interface Booking {\n id: string;\n serviceId: string;\n date: string;\n startTime: string;\n endTime: string;\n status: string;\n customer: { name: string; email: string };\n}\n\n// ── Form types ──\n\nexport interface FormDefinition {\n id: string;\n title: string;\n description: string;\n fields: FormField[];\n}\n\nexport interface FormField {\n id: string;\n type: string;\n label: string;\n required: boolean;\n options?: string[];\n placeholder?: string;\n}\n\n// ── Store config ──\n\nexport interface StoreConfig {\n name: string;\n slug: string;\n logo?: string;\n theme: Record<string, unknown>;\n currency: string;\n locale: string;\n}\n\n// ── SDK Error ──\n\nexport class StorefrontError extends Error {\n status: number;\n code: string;\n details?: unknown;\n\n constructor(status: number, code: string, message: string, details?: unknown) {\n super(message);\n this.name = \"StorefrontError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\n// ── Core client ────────────────────────────────────────────────────\n\nexport function createStorefrontClient(config: StorefrontConfig) {\n const apiUrl = (config.apiUrl ?? \"https://managesales-backend-phase1test.up.railway.app/api/v1\").replace(/\\/$/, \"\");\n const fetchFn = config.customFetch ?? globalThis.fetch.bind(globalThis);\n let accessToken: string | null = null;\n let refreshToken: string | null = null;\n\n // ── Internal helpers ──\n\n async function request<T>(\n method: string,\n path: string,\n options?: {\n body?: unknown;\n params?: Record<string, unknown>;\n auth?: boolean;\n },\n ): Promise<T> {\n const url = new URL(`${apiUrl}${path}`);\n if (options?.params) {\n for (const [k, v] of Object.entries(options.params)) {\n if (v !== undefined && v !== null) url.searchParams.set(k, String(v));\n }\n }\n\n const headers: Record<string, string> = {\n \"X-Workspace-Id\": config.workspaceId,\n };\n\n if (options?.auth && accessToken) {\n headers[\"Authorization\"] = `Bearer ${accessToken}`;\n }\n\n if (options?.body) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const res = await fetchFn(url.toString(), {\n method,\n headers,\n body: options?.body ? JSON.stringify(options.body) : undefined,\n });\n\n // Auto-refresh on 401\n if (res.status === 401 && options?.auth && refreshToken) {\n const refreshed = await refreshSession();\n if (refreshed) {\n headers[\"Authorization\"] = `Bearer ${accessToken}`;\n const retry = await fetchFn(url.toString(), {\n method,\n headers,\n body: options?.body ? JSON.stringify(options.body) : undefined,\n });\n if (!retry.ok) throw await parseError(retry);\n return retry.status === 204 ? (undefined as T) : retry.json();\n }\n }\n\n if (!res.ok) throw await parseError(res);\n return res.status === 204 ? (undefined as T) : res.json();\n }\n\n async function parseError(res: Response): Promise<StorefrontError> {\n try {\n const body = await res.json();\n return new StorefrontError(\n res.status,\n body.code ?? body.error ?? \"UNKNOWN\",\n body.message ?? res.statusText,\n body,\n );\n } catch {\n return new StorefrontError(res.status, \"UNKNOWN\", res.statusText);\n }\n }\n\n async function refreshSession(): Promise<boolean> {\n if (!refreshToken) return false;\n try {\n const res = await fetchFn(`${apiUrl}/storefront/auth/refresh`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Workspace-Id\": config.workspaceId,\n },\n body: JSON.stringify({ refreshToken }),\n });\n if (!res.ok) {\n accessToken = null;\n refreshToken = null;\n return false;\n }\n const data = await res.json();\n accessToken = data.accessToken;\n refreshToken = data.refreshToken;\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Resource namespaces ──────────────────────────────────────────\n\n const store = {\n /** Resolve store config by workspace (returns theme, branding, currency) */\n async resolve(): Promise<StoreConfig> {\n return request(\"GET\", \"/storefront-api/resolve\");\n },\n };\n\n const products = {\n /** List published products with pagination and filters */\n async list(params?: ListParams): Promise<PaginatedResponse<Product>> {\n return request(\"GET\", \"/storefront-api/products\", { params });\n },\n /** Get a single product by ID or slug */\n async get(idOrSlug: string): Promise<Product> {\n return request(\"GET\", `/storefront-api/products/${idOrSlug}`);\n },\n /** Search products (shorthand for list with search param) */\n async search(query: string, params?: ListParams): Promise<PaginatedResponse<Product>> {\n return request(\"GET\", \"/storefront-api/search\", { params: { ...params, q: query } });\n },\n };\n\n const collections = {\n /** List published collections */\n async list(params?: ListParams): Promise<PaginatedResponse<Collection>> {\n return request(\"GET\", \"/storefront-api/collections\", { params });\n },\n /** Get a collection with its products */\n async get(idOrSlug: string): Promise<Collection & { products: Product[] }> {\n return request(\"GET\", `/storefront-api/collections/${idOrSlug}`);\n },\n };\n\n const checkout = {\n /** Create a checkout session from cart items */\n async create(items: CheckoutLineItem[]): Promise<CheckoutSession> {\n return request(\"POST\", \"/checkout\", { body: { items } });\n },\n /** Retrieve an existing checkout session */\n async get(checkoutId: string): Promise<CheckoutSession> {\n return request(\"GET\", `/checkout/${checkoutId}`);\n },\n /** Apply a coupon or discount code */\n async applyCoupon(checkoutId: string, couponCode: string): Promise<CheckoutSession> {\n return request(\"POST\", `/checkout/${checkoutId}/coupon`, { body: { couponCode } });\n },\n /** Complete checkout — process payment and create order */\n async complete(checkoutId: string, payment?: Record<string, unknown>): Promise<Order> {\n return request(\"POST\", `/checkout/${checkoutId}/complete`, { body: payment });\n },\n };\n\n const auth = {\n /** Register a new customer account */\n async register(data: {\n email: string;\n password: string;\n name: string;\n phone?: string;\n }): Promise<AuthSession> {\n const session = await request<AuthSession>(\"POST\", \"/storefront/auth/register\", { body: data });\n accessToken = session.accessToken;\n refreshToken = session.refreshToken;\n return session;\n },\n /** Log in with email + password */\n async login(email: string, password: string): Promise<AuthSession> {\n const session = await request<AuthSession>(\"POST\", \"/storefront/auth/login\", {\n body: { email, password },\n });\n accessToken = session.accessToken;\n refreshToken = session.refreshToken;\n return session;\n },\n /** Log in with Google ID token */\n async loginWithGoogle(idToken: string): Promise<AuthSession> {\n const session = await request<AuthSession>(\"POST\", \"/storefront/auth/google\", {\n body: { idToken },\n });\n accessToken = session.accessToken;\n refreshToken = session.refreshToken;\n return session;\n },\n /** Log out and clear local session */\n async logout(): Promise<void> {\n if (accessToken) {\n try {\n await request(\"POST\", \"/storefront/auth/logout\", { auth: true });\n } catch { /* ignore logout errors */ }\n }\n accessToken = null;\n refreshToken = null;\n },\n /** Refresh the access token */\n async refresh(): Promise<boolean> {\n return refreshSession();\n },\n /** Check if client has a valid session */\n isAuthenticated(): boolean {\n return accessToken !== null;\n },\n /** Manually set tokens (e.g., from SSR or cookie restoration) */\n setTokens(access: string, refresh: string): void {\n accessToken = access;\n refreshToken = refresh;\n },\n };\n\n const customer = {\n /** Get current customer profile */\n async me(): Promise<Customer> {\n return request(\"GET\", \"/storefront/auth/me\", { auth: true });\n },\n /** Get customer's order history */\n async orders(params?: ListParams): Promise<PaginatedResponse<Order>> {\n const me = await request<Customer>(\"GET\", \"/storefront/auth/me\", { auth: true });\n return request(\"GET\", `/storefront-api/customer/${me.id}/orders`, { params, auth: true });\n },\n /** Get customer's saved addresses */\n async addresses(): Promise<Address[]> {\n const me = await request<Customer>(\"GET\", \"/storefront/auth/me\", { auth: true });\n return request(\"GET\", `/storefront-api/customer/${me.id}/addresses`, { auth: true });\n },\n };\n\n const blog = {\n /** List published blog posts */\n async list(params?: ListParams & { tags?: string }): Promise<PaginatedResponse<BlogPost>> {\n return request(\"GET\", \"/storefront-api/blog/posts\", { params });\n },\n /** Get a blog post by slug */\n async get(slug: string): Promise<BlogPost> {\n return request(\"GET\", `/storefront-api/blog/posts/${slug}`);\n },\n };\n\n const bookings = {\n /** List bookable services */\n async services(): Promise<BookableService[]> {\n return request(\"GET\", \"/bookings-public/services\");\n },\n /** List bookable staff */\n async staff(): Promise<Array<{ id: string; name: string; avatar?: string }>> {\n return request(\"GET\", \"/bookings-public/staff\");\n },\n /** Check available time slots */\n async availability(params: {\n serviceId: string;\n date: string;\n staffId?: string;\n }): Promise<TimeSlot[]> {\n return request(\"GET\", \"/bookings-public/availability\", { params });\n },\n /** Create a booking */\n async book(data: {\n serviceId: string;\n date: string;\n startTime: string;\n staffId?: string;\n customer: { name: string; email: string; phone?: string };\n }): Promise<Booking> {\n return request(\"POST\", \"/bookings-public/book\", { body: data });\n },\n };\n\n const forms = {\n /** Get a published form by ID or slug */\n async get(idOrSlug: string): Promise<FormDefinition> {\n return request(\"GET\", `/public/forms/${idOrSlug}`);\n },\n /** Submit form response */\n async submit(formId: string, data: Record<string, unknown>): Promise<{ id: string }> {\n return request(\"POST\", `/public/forms/${formId}/submit`, { body: data });\n },\n /** Upload file for a form file field */\n async uploadFile(formId: string, file: File): Promise<{ url: string }> {\n const formData = new FormData();\n formData.append(\"file\", file);\n const res = await fetchFn(`${apiUrl}/public/forms/${formId}/upload`, {\n method: \"POST\",\n headers: { \"X-Workspace-Id\": config.workspaceId },\n body: formData,\n });\n if (!res.ok) throw await parseError(res);\n return res.json();\n },\n };\n\n const cart = {\n /** Recover an abandoned cart by recovery token */\n async recover(token: string): Promise<CheckoutSession> {\n return request(\"GET\", `/abandoned-carts/recover/${token}`);\n },\n };\n\n // ── Public API ───────────────────────────────────────────────────\n\n return {\n store,\n products,\n collections,\n checkout,\n auth,\n customer,\n blog,\n bookings,\n forms,\n cart,\n };\n}\n\n// ── Type export for TypeScript users ──\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ManageSales Storefront SDK\n * --------------------------\n * Resource-based client for building online storefronts.\n * Works with any framework: Next.js, Remix, Nuxt, Astro, plain HTML.\n *\n * Usage:\n * import { createStorefrontClient } from \"./managesales-storefront\";\n * const client = createStorefrontClient({ workspaceId: \"<workspace_id>\" });\n * const products = await client.products.list();\n */\n\n// ── Types ──────────────────────────────────────────────────────────\n\nexport interface RetryConfig {\n /** Max retry attempts for a failed request (default: 2) */\n retries?: number;\n /** Base delay in ms used for exponential backoff (default: 300) */\n baseDelayMs?: number;\n /** Upper bound for any single backoff delay, in ms (default: 4000) */\n maxDelayMs?: number;\n /** HTTP status codes that are retried, GET/HEAD only (default: [408,425,429,500,502,503,504]) */\n retryOnStatus?: number[];\n}\n\nexport interface StorefrontConfig {\n /** Your workspace ID (required) */\n workspaceId: string;\n /** API base URL — defaults to production */\n apiUrl?: string;\n /** Custom fetch implementation (for SSR / edge) */\n customFetch?: typeof fetch;\n /** Default locale for content */\n locale?: string;\n /**\n * Retry behavior for transient failures (network errors, and 5xx/408/425/429\n * responses on idempotent GET/HEAD requests). Pass `false` to disable retries\n * entirely. Defaults to 2 retries with exponential backoff.\n */\n retry?: RetryConfig | false;\n /**\n * Persist the stateful cart (`client.cart`) to `localStorage` so it survives\n * page reloads. Defaults to `true`. Has no effect in environments without\n * `localStorage` (e.g. Node/SSR) — the cart simply stays in-memory.\n */\n persistCart?: boolean;\n}\n\nexport interface ListParams {\n page?: number;\n limit?: number;\n search?: string;\n sort?: string;\n order?: \"asc\" | \"desc\";\n [key: string]: unknown;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\n// ── Product types ──\n\nexport interface Product {\n id: string;\n name: string;\n slug: string;\n description: string;\n status: string;\n price: number;\n compareAtPrice?: number;\n currency: string;\n images: ProductImage[];\n variants: ProductVariant[];\n category?: { id: string; name: string };\n brand?: { id: string; name: string };\n tags: string[];\n metadata: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ProductImage {\n id: string;\n url: string;\n alt: string;\n position: number;\n}\n\nexport interface ProductVariant {\n id: string;\n name: string;\n sku: string;\n price: number;\n compareAtPrice?: number;\n inventory: number;\n options: Record<string, string>;\n}\n\n// ── Collection types ──\n\nexport interface Collection {\n id: string;\n name: string;\n slug: string;\n description: string;\n image?: string;\n productCount: number;\n}\n\n// ── Cart & Checkout types ──\n\nexport interface CheckoutLineItem {\n productId: string;\n variantId?: string;\n productName: string;\n quantity: number;\n unitPrice: number;\n imageUrl?: string;\n}\n\nexport interface CheckoutSession {\n id: string;\n status: \"open\" | \"completed\" | \"expired\";\n items: CheckoutLineItem[];\n subtotal: number;\n tax: number;\n shipping: number;\n discount: number;\n total: number;\n currency: string;\n couponCode?: string;\n}\n\nexport interface CartLine {\n id: string;\n productId: string;\n variantId?: string;\n quantity: number;\n unitPrice: number;\n productName: string;\n imageUrl?: string;\n}\n\nexport interface CartState {\n id: string;\n lines: CartLine[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface AddCartLineItemInput {\n productId: string;\n variantId?: string;\n quantity: number;\n /** Skip the `products.get` price lookup by supplying these directly */\n unitPrice?: number;\n productName?: string;\n imageUrl?: string;\n}\n\nexport interface StorefrontCart {\n readonly id: string;\n readonly lines: CartLine[];\n readonly itemCount: number;\n readonly subtotal: number;\n /** Adds a line item. Supplying `unitPrice` also requires `productName`, otherwise this falls through to a `products.get` network lookup. */\n addLineItem(input: AddCartLineItemInput): Promise<StorefrontCart>;\n updateLineItem(lineId: string, quantity: number): StorefrontCart;\n removeLineItem(lineId: string): StorefrontCart;\n clear(): StorefrontCart;\n checkout(opts?: { clearOnSuccess?: boolean }): Promise<CheckoutSession>;\n}\n\nexport interface Order {\n id: string;\n orderNumber: string;\n status: string;\n total: number;\n currency: string;\n items: OrderItem[];\n createdAt: string;\n}\n\nexport interface OrderItem {\n productId: string;\n name: string;\n quantity: number;\n price: number;\n}\n\n// ── Customer types ──\n\nexport interface Customer {\n id: string;\n email: string;\n name: string;\n phone?: string;\n createdAt: string;\n}\n\nexport interface AuthSession {\n customer: Customer;\n accessToken: string;\n refreshToken: string;\n}\n\nexport interface Address {\n id: string;\n label?: string;\n line1: string;\n line2?: string;\n city: string;\n state: string;\n postalCode: string;\n country: string;\n isDefault: boolean;\n}\n\n// ── Blog types ──\n\nexport interface BlogPost {\n id: string;\n title: string;\n slug: string;\n excerpt: string;\n content: string;\n coverImage?: string;\n tags: string[];\n publishedAt: string;\n}\n\n// ── Booking types ──\n\nexport interface BookableService {\n id: string;\n name: string;\n duration: number;\n price: number;\n description: string;\n}\n\nexport interface TimeSlot {\n start: string;\n end: string;\n available: boolean;\n}\n\nexport interface Booking {\n id: string;\n serviceId: string;\n date: string;\n startTime: string;\n endTime: string;\n status: string;\n customer: { name: string; email: string };\n}\n\n// ── Form types ──\n\nexport interface FormDefinition {\n id: string;\n title: string;\n description: string;\n fields: FormField[];\n}\n\nexport interface FormField {\n id: string;\n type: string;\n label: string;\n required: boolean;\n options?: string[];\n placeholder?: string;\n}\n\n// ── Store config ──\n\nexport interface StoreConfig {\n name: string;\n slug: string;\n logo?: string;\n theme: Record<string, unknown>;\n currency: string;\n locale: string;\n}\n\n// ── SDK Error ──\n\nexport class StorefrontError extends Error {\n status: number;\n code: string;\n details?: unknown;\n\n constructor(status: number, code: string, message: string, details?: unknown) {\n super(message);\n this.name = \"StorefrontError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\n// ── Core client ────────────────────────────────────────────────────\n\nexport function createStorefrontClient(config: StorefrontConfig) {\n const apiUrl = (config.apiUrl ?? \"https://managesales-backend-phase1test.up.railway.app/api/v1\").replace(/\\/$/, \"\");\n const fetchFn = config.customFetch ?? globalThis.fetch.bind(globalThis);\n let accessToken: string | null = null;\n let refreshToken: string | null = null;\n\n // ── Retry configuration ──\n\n const RETRY_DEFAULTS = {\n retries: 2,\n baseDelayMs: 300,\n maxDelayMs: 4000,\n retryOnStatus: [408, 425, 429, 500, 502, 503, 504],\n };\n const rc =\n config.retry === false\n ? { ...RETRY_DEFAULTS, retries: 0 }\n : { ...RETRY_DEFAULTS, ...(config.retry || {}) };\n const IDEMPOTENT = new Set([\"GET\", \"HEAD\"]);\n const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n function backoff(attempt: number): number {\n return Math.min(rc.maxDelayMs, Math.round(Math.random() * rc.baseDelayMs * Math.pow(2, attempt)));\n }\n\n // ── Internal helpers ──\n\n async function request<T>(\n method: string,\n path: string,\n options?: {\n body?: unknown;\n params?: Record<string, unknown>;\n auth?: boolean;\n },\n ): Promise<T> {\n const url = new URL(`${apiUrl}${path}`);\n if (options?.params) {\n for (const [k, v] of Object.entries(options.params)) {\n if (v !== undefined && v !== null) url.searchParams.set(k, String(v));\n }\n }\n\n const headers: Record<string, string> = {\n \"X-Workspace-Id\": config.workspaceId,\n };\n\n if (options?.auth && accessToken) {\n headers[\"Authorization\"] = `Bearer ${accessToken}`;\n }\n\n if (options?.body) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n body: options?.body ? JSON.stringify(options.body) : undefined,\n };\n\n let attempt = 0;\n let res: Response;\n while (true) {\n try {\n res = await fetchFn(url.toString(), fetchOptions);\n } catch (err) {\n if (attempt < rc.retries) {\n await sleep(backoff(attempt));\n attempt++;\n continue;\n }\n throw err;\n }\n if (attempt < rc.retries && rc.retryOnStatus.includes(res.status) && IDEMPOTENT.has(method)) {\n const ra = Number(res.headers.get(\"retry-after\"));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n attempt++;\n continue;\n }\n break;\n }\n\n // Auto-refresh on 401\n if (res.status === 401 && options?.auth && refreshToken) {\n const refreshed = await refreshSession();\n if (refreshed) {\n headers[\"Authorization\"] = `Bearer ${accessToken}`;\n const retry = await fetchFn(url.toString(), {\n method,\n headers,\n body: options?.body ? JSON.stringify(options.body) : undefined,\n });\n if (!retry.ok) throw await parseError(retry);\n return retry.status === 204 ? (undefined as T) : retry.json();\n }\n }\n\n if (!res.ok) throw await parseError(res);\n return res.status === 204 ? (undefined as T) : res.json();\n }\n\n async function parseError(res: Response): Promise<StorefrontError> {\n try {\n const body = await res.json();\n return new StorefrontError(\n res.status,\n body.code ?? body.error ?? \"UNKNOWN\",\n body.message ?? res.statusText,\n body,\n );\n } catch {\n return new StorefrontError(res.status, \"UNKNOWN\", res.statusText);\n }\n }\n\n async function refreshSession(): Promise<boolean> {\n if (!refreshToken) return false;\n try {\n const res = await fetchFn(`${apiUrl}/storefront/auth/refresh`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Workspace-Id\": config.workspaceId,\n },\n body: JSON.stringify({ refreshToken }),\n });\n if (!res.ok) {\n accessToken = null;\n refreshToken = null;\n return false;\n }\n const data = await res.json();\n accessToken = data.accessToken;\n refreshToken = data.refreshToken;\n return true;\n } catch {\n return false;\n }\n }\n\n // ── Resource namespaces ──────────────────────────────────────────\n\n const store = {\n /** Resolve store config by workspace (returns theme, branding, currency) */\n async resolve(): Promise<StoreConfig> {\n return request(\"GET\", \"/storefront-api/resolve\");\n },\n };\n\n const products = {\n /** List published products with pagination and filters */\n async list(params?: ListParams): Promise<PaginatedResponse<Product>> {\n return request(\"GET\", \"/storefront-api/products\", { params });\n },\n /** Get a single product by ID or slug */\n async get(idOrSlug: string): Promise<Product> {\n return request(\"GET\", `/storefront-api/products/${idOrSlug}`);\n },\n /** Search products (shorthand for list with search param) */\n async search(query: string, params?: ListParams): Promise<PaginatedResponse<Product>> {\n return request(\"GET\", \"/storefront-api/search\", { params: { ...params, q: query } });\n },\n };\n\n const collections = {\n /** List published collections */\n async list(params?: ListParams): Promise<PaginatedResponse<Collection>> {\n return request(\"GET\", \"/storefront-api/collections\", { params });\n },\n /** Get a collection with its products */\n async get(idOrSlug: string): Promise<Collection & { products: Product[] }> {\n return request(\"GET\", `/storefront-api/collections/${idOrSlug}`);\n },\n };\n\n const checkout = {\n /** Create a checkout session from cart items */\n async create(items: CheckoutLineItem[]): Promise<CheckoutSession> {\n return request(\"POST\", \"/checkout\", { body: { lines: items } });\n },\n /** Retrieve an existing checkout session */\n async get(checkoutId: string): Promise<CheckoutSession> {\n return request(\"GET\", `/checkout/${checkoutId}`);\n },\n /** Apply a coupon or discount code */\n async applyCoupon(checkoutId: string, couponCode: string): Promise<CheckoutSession> {\n return request(\"POST\", `/checkout/${checkoutId}/coupon`, { body: { couponCode } });\n },\n /** Complete checkout — process payment and create order */\n async complete(checkoutId: string, payment?: Record<string, unknown>): Promise<Order> {\n return request(\"POST\", `/checkout/${checkoutId}/complete`, { body: payment });\n },\n };\n\n const auth = {\n /** Register a new customer account */\n async register(data: {\n email: string;\n password: string;\n name: string;\n phone?: string;\n }): Promise<AuthSession> {\n const session = await request<AuthSession>(\"POST\", \"/storefront/auth/register\", { body: data });\n accessToken = session.accessToken;\n refreshToken = session.refreshToken;\n return session;\n },\n /** Log in with email + password */\n async login(email: string, password: string): Promise<AuthSession> {\n const session = await request<AuthSession>(\"POST\", \"/storefront/auth/login\", {\n body: { email, password },\n });\n accessToken = session.accessToken;\n refreshToken = session.refreshToken;\n return session;\n },\n /** Log in with Google ID token */\n async loginWithGoogle(idToken: string): Promise<AuthSession> {\n const session = await request<AuthSession>(\"POST\", \"/storefront/auth/google\", {\n body: { idToken },\n });\n accessToken = session.accessToken;\n refreshToken = session.refreshToken;\n return session;\n },\n /** Log out and clear local session */\n async logout(): Promise<void> {\n if (accessToken) {\n try {\n await request(\"POST\", \"/storefront/auth/logout\", { auth: true });\n } catch { /* ignore logout errors */ }\n }\n accessToken = null;\n refreshToken = null;\n },\n /** Refresh the access token */\n async refresh(): Promise<boolean> {\n return refreshSession();\n },\n /** Check if client has a valid session */\n isAuthenticated(): boolean {\n return accessToken !== null;\n },\n /** Manually set tokens (e.g., from SSR or cookie restoration) */\n setTokens(access: string, refresh: string): void {\n accessToken = access;\n refreshToken = refresh;\n },\n };\n\n const customer = {\n /** Get current customer profile */\n async me(): Promise<Customer> {\n return request(\"GET\", \"/storefront/auth/me\", { auth: true });\n },\n /** Get customer's order history */\n async orders(params?: ListParams): Promise<PaginatedResponse<Order>> {\n const me = await request<Customer>(\"GET\", \"/storefront/auth/me\", { auth: true });\n return request(\"GET\", `/storefront-api/customer/${me.id}/orders`, { params, auth: true });\n },\n /** Get customer's saved addresses */\n async addresses(): Promise<Address[]> {\n const me = await request<Customer>(\"GET\", \"/storefront/auth/me\", { auth: true });\n return request(\"GET\", `/storefront-api/customer/${me.id}/addresses`, { auth: true });\n },\n };\n\n const blog = {\n /** List published blog posts */\n async list(params?: ListParams & { tags?: string }): Promise<PaginatedResponse<BlogPost>> {\n return request(\"GET\", \"/storefront-api/blog/posts\", { params });\n },\n /** Get a blog post by slug */\n async get(slug: string): Promise<BlogPost> {\n return request(\"GET\", `/storefront-api/blog/posts/${slug}`);\n },\n };\n\n const bookings = {\n /** List bookable services */\n async services(): Promise<BookableService[]> {\n return request(\"GET\", \"/bookings-public/services\");\n },\n /** List bookable staff */\n async staff(): Promise<Array<{ id: string; name: string; avatar?: string }>> {\n return request(\"GET\", \"/bookings-public/staff\");\n },\n /** Check available time slots */\n async availability(params: {\n serviceId: string;\n date: string;\n staffId?: string;\n }): Promise<TimeSlot[]> {\n return request(\"GET\", \"/bookings-public/availability\", { params });\n },\n /** Create a booking */\n async book(data: {\n serviceId: string;\n date: string;\n startTime: string;\n staffId?: string;\n customer: { name: string; email: string; phone?: string };\n }): Promise<Booking> {\n return request(\"POST\", \"/bookings-public/book\", { body: data });\n },\n };\n\n const forms = {\n /** Get a published form by ID or slug */\n async get(idOrSlug: string): Promise<FormDefinition> {\n return request(\"GET\", `/public/forms/${idOrSlug}`);\n },\n /** Submit form response */\n async submit(formId: string, data: Record<string, unknown>): Promise<{ id: string }> {\n return request(\"POST\", `/public/forms/${formId}/submit`, { body: data });\n },\n /** Upload file for a form file field */\n async uploadFile(formId: string, file: File): Promise<{ url: string }> {\n const formData = new FormData();\n formData.append(\"file\", file);\n const res = await fetchFn(`${apiUrl}/public/forms/${formId}/upload`, {\n method: \"POST\",\n headers: { \"X-Workspace-Id\": config.workspaceId },\n body: formData,\n });\n if (!res.ok) throw await parseError(res);\n return res.json();\n },\n };\n\n // ── Stateful cart (client-side, localStorage-persisted) ──\n\n const CART_KEY = \"managesales_cart_\" + config.workspaceId;\n const hasLS = () => {\n try {\n return config.persistCart !== false && typeof localStorage !== \"undefined\";\n } catch {\n return false;\n }\n };\n const loadCart = (): CartState | null => {\n if (!hasLS()) return null;\n try {\n const s = localStorage.getItem(CART_KEY);\n return s ? JSON.parse(s) : null;\n } catch {\n return null;\n }\n };\n const saveCart = (st: CartState): void => {\n if (!hasLS()) return;\n try {\n localStorage.setItem(CART_KEY, JSON.stringify(st));\n } catch {\n /* ignore persistence errors (quota, privacy mode, etc.) */\n }\n };\n let __lineSeq = 0;\n const genId = (p: string): string =>\n typeof crypto !== \"undefined\" && crypto.randomUUID ? p + crypto.randomUUID() : p + Date.now() + \"_\" + ++__lineSeq;\n const nowIso = (): string => new Date().toISOString();\n const freshCart = (): CartState => ({ id: genId(\"cart_\"), lines: [], createdAt: nowIso(), updatedAt: nowIso() });\n\n function makeCart(state: CartState): StorefrontCart {\n const persist = () => {\n state.updatedAt = nowIso();\n saveCart(state);\n };\n const cartObj: StorefrontCart = {\n get id() {\n return state.id;\n },\n get lines() {\n return state.lines;\n },\n get itemCount() {\n return state.lines.reduce((n, l) => n + l.quantity, 0);\n },\n get subtotal() {\n return state.lines.reduce((s, l) => s + l.unitPrice * l.quantity, 0);\n },\n // Supplying unitPrice alone does not skip the lookup — productName must also be\n // provided, otherwise this falls through to the products.get() network lookup below.\n async addLineItem(input: AddCartLineItemInput): Promise<StorefrontCart> {\n let line: CartLine;\n if (input.unitPrice != null && input.productName) {\n line = {\n id: genId(\"line_\"),\n productId: input.productId,\n variantId: input.variantId,\n quantity: input.quantity,\n unitPrice: input.unitPrice,\n productName: input.productName,\n imageUrl: input.imageUrl,\n };\n } else {\n const p = await products.get(input.productId);\n const v = input.variantId && Array.isArray(p.variants) ? p.variants.find((x) => x.id === input.variantId) : undefined;\n line = {\n id: genId(\"line_\"),\n productId: input.productId,\n variantId: input.variantId,\n quantity: input.quantity,\n unitPrice: v && v.price != null ? v.price : p.price,\n productName: p.name,\n imageUrl: Array.isArray(p.images) && p.images.length > 0 ? p.images[0].url : undefined,\n };\n }\n const existing = state.lines.find((l) => l.productId === line.productId && l.variantId === line.variantId);\n if (existing) existing.quantity += line.quantity;\n else state.lines.push(line);\n persist();\n return cartObj;\n },\n updateLineItem(lineId: string, quantity: number): StorefrontCart {\n const l = state.lines.find((x) => x.id === lineId);\n if (l) {\n if (quantity <= 0) state.lines = state.lines.filter((x) => x.id !== lineId);\n else l.quantity = quantity;\n persist();\n }\n return cartObj;\n },\n removeLineItem(lineId: string): StorefrontCart {\n state.lines = state.lines.filter((x) => x.id !== lineId);\n persist();\n return cartObj;\n },\n clear(): StorefrontCart {\n state.lines = [];\n persist();\n return cartObj;\n },\n async checkout(opts?: { clearOnSuccess?: boolean }): Promise<CheckoutSession> {\n const session = await checkout.create(\n state.lines.map((l) => ({\n productId: l.productId,\n variantId: l.variantId,\n productName: l.productName,\n quantity: l.quantity,\n unitPrice: l.unitPrice,\n imageUrl: l.imageUrl,\n })),\n );\n if (opts && opts.clearOnSuccess) cartObj.clear();\n return session;\n },\n };\n return cartObj;\n }\n\n const cart = {\n /** Create a new, empty cart (replaces any persisted cart) */\n create(): StorefrontCart {\n const st = freshCart();\n saveCart(st);\n return makeCart(st);\n },\n /** Get the current cart — loaded from storage if persisted, otherwise a fresh one */\n current(): StorefrontCart {\n return makeCart(loadCart() || freshCart());\n },\n /** Recover an abandoned cart by recovery token */\n async recover(token: string): Promise<CheckoutSession> {\n return request(\"GET\", `/abandoned-carts/recover/${token}`);\n },\n };\n\n // ── Alias namespaces (convenience wrappers over existing methods) ──\n\n /** Alias for `client.customer.orders` — order history for the logged-in customer */\n const orders = {\n /** Get customer's order history (delegates to `customer.orders`) */\n list: (params?: ListParams): Promise<PaginatedResponse<Order>> => customer.orders(params),\n };\n\n /** Convenience namespace bundling `auth` + `customer` under one name */\n const customers = {\n login: auth.login,\n register: auth.register,\n loginWithGoogle: auth.loginWithGoogle,\n logout: auth.logout,\n isAuthenticated: auth.isAuthenticated,\n setTokens: auth.setTokens,\n me: customer.me,\n orders: customer.orders,\n addresses: customer.addresses,\n };\n\n // ── Public API ───────────────────────────────────────────────────\n\n return {\n store,\n products,\n collections,\n checkout,\n auth,\n customer,\n blog,\n bookings,\n forms,\n cart,\n orders,\n customers,\n };\n}\n\n// ── Type export for TypeScript users ──\n\nexport type StorefrontClient = ReturnType<typeof createStorefrontClient>;\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
* const client = createStorefrontClient({ workspaceId: "<workspace_id>" });
|
|
10
10
|
* const products = await client.products.list();
|
|
11
11
|
*/
|
|
12
|
+
interface RetryConfig {
|
|
13
|
+
/** Max retry attempts for a failed request (default: 2) */
|
|
14
|
+
retries?: number;
|
|
15
|
+
/** Base delay in ms used for exponential backoff (default: 300) */
|
|
16
|
+
baseDelayMs?: number;
|
|
17
|
+
/** Upper bound for any single backoff delay, in ms (default: 4000) */
|
|
18
|
+
maxDelayMs?: number;
|
|
19
|
+
/** HTTP status codes that are retried, GET/HEAD only (default: [408,425,429,500,502,503,504]) */
|
|
20
|
+
retryOnStatus?: number[];
|
|
21
|
+
}
|
|
12
22
|
interface StorefrontConfig {
|
|
13
23
|
/** Your workspace ID (required) */
|
|
14
24
|
workspaceId: string;
|
|
@@ -18,6 +28,18 @@ interface StorefrontConfig {
|
|
|
18
28
|
customFetch?: typeof fetch;
|
|
19
29
|
/** Default locale for content */
|
|
20
30
|
locale?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Retry behavior for transient failures (network errors, and 5xx/408/425/429
|
|
33
|
+
* responses on idempotent GET/HEAD requests). Pass `false` to disable retries
|
|
34
|
+
* entirely. Defaults to 2 retries with exponential backoff.
|
|
35
|
+
*/
|
|
36
|
+
retry?: RetryConfig | false;
|
|
37
|
+
/**
|
|
38
|
+
* Persist the stateful cart (`client.cart`) to `localStorage` so it survives
|
|
39
|
+
* page reloads. Defaults to `true`. Has no effect in environments without
|
|
40
|
+
* `localStorage` (e.g. Node/SSR) — the cart simply stays in-memory.
|
|
41
|
+
*/
|
|
42
|
+
persistCart?: boolean;
|
|
21
43
|
}
|
|
22
44
|
interface ListParams {
|
|
23
45
|
page?: number;
|
|
@@ -84,7 +106,10 @@ interface Collection {
|
|
|
84
106
|
interface CheckoutLineItem {
|
|
85
107
|
productId: string;
|
|
86
108
|
variantId?: string;
|
|
109
|
+
productName: string;
|
|
87
110
|
quantity: number;
|
|
111
|
+
unitPrice: number;
|
|
112
|
+
imageUrl?: string;
|
|
88
113
|
}
|
|
89
114
|
interface CheckoutSession {
|
|
90
115
|
id: string;
|
|
@@ -98,6 +123,44 @@ interface CheckoutSession {
|
|
|
98
123
|
currency: string;
|
|
99
124
|
couponCode?: string;
|
|
100
125
|
}
|
|
126
|
+
interface CartLine {
|
|
127
|
+
id: string;
|
|
128
|
+
productId: string;
|
|
129
|
+
variantId?: string;
|
|
130
|
+
quantity: number;
|
|
131
|
+
unitPrice: number;
|
|
132
|
+
productName: string;
|
|
133
|
+
imageUrl?: string;
|
|
134
|
+
}
|
|
135
|
+
interface CartState {
|
|
136
|
+
id: string;
|
|
137
|
+
lines: CartLine[];
|
|
138
|
+
createdAt: string;
|
|
139
|
+
updatedAt: string;
|
|
140
|
+
}
|
|
141
|
+
interface AddCartLineItemInput {
|
|
142
|
+
productId: string;
|
|
143
|
+
variantId?: string;
|
|
144
|
+
quantity: number;
|
|
145
|
+
/** Skip the `products.get` price lookup by supplying these directly */
|
|
146
|
+
unitPrice?: number;
|
|
147
|
+
productName?: string;
|
|
148
|
+
imageUrl?: string;
|
|
149
|
+
}
|
|
150
|
+
interface StorefrontCart {
|
|
151
|
+
readonly id: string;
|
|
152
|
+
readonly lines: CartLine[];
|
|
153
|
+
readonly itemCount: number;
|
|
154
|
+
readonly subtotal: number;
|
|
155
|
+
/** Adds a line item. Supplying `unitPrice` also requires `productName`, otherwise this falls through to a `products.get` network lookup. */
|
|
156
|
+
addLineItem(input: AddCartLineItemInput): Promise<StorefrontCart>;
|
|
157
|
+
updateLineItem(lineId: string, quantity: number): StorefrontCart;
|
|
158
|
+
removeLineItem(lineId: string): StorefrontCart;
|
|
159
|
+
clear(): StorefrontCart;
|
|
160
|
+
checkout(opts?: {
|
|
161
|
+
clearOnSuccess?: boolean;
|
|
162
|
+
}): Promise<CheckoutSession>;
|
|
163
|
+
}
|
|
101
164
|
interface Order {
|
|
102
165
|
id: string;
|
|
103
166
|
orderNumber: string;
|
|
@@ -307,10 +370,34 @@ declare function createStorefrontClient(config: StorefrontConfig): {
|
|
|
307
370
|
}>;
|
|
308
371
|
};
|
|
309
372
|
cart: {
|
|
373
|
+
/** Create a new, empty cart (replaces any persisted cart) */
|
|
374
|
+
create(): StorefrontCart;
|
|
375
|
+
/** Get the current cart — loaded from storage if persisted, otherwise a fresh one */
|
|
376
|
+
current(): StorefrontCart;
|
|
310
377
|
/** Recover an abandoned cart by recovery token */
|
|
311
378
|
recover(token: string): Promise<CheckoutSession>;
|
|
312
379
|
};
|
|
380
|
+
orders: {
|
|
381
|
+
/** Get customer's order history (delegates to `customer.orders`) */
|
|
382
|
+
list: (params?: ListParams) => Promise<PaginatedResponse<Order>>;
|
|
383
|
+
};
|
|
384
|
+
customers: {
|
|
385
|
+
login: (email: string, password: string) => Promise<AuthSession>;
|
|
386
|
+
register: (data: {
|
|
387
|
+
email: string;
|
|
388
|
+
password: string;
|
|
389
|
+
name: string;
|
|
390
|
+
phone?: string;
|
|
391
|
+
}) => Promise<AuthSession>;
|
|
392
|
+
loginWithGoogle: (idToken: string) => Promise<AuthSession>;
|
|
393
|
+
logout: () => Promise<void>;
|
|
394
|
+
isAuthenticated: () => boolean;
|
|
395
|
+
setTokens: (access: string, refresh: string) => void;
|
|
396
|
+
me: () => Promise<Customer>;
|
|
397
|
+
orders: (params?: ListParams) => Promise<PaginatedResponse<Order>>;
|
|
398
|
+
addresses: () => Promise<Address[]>;
|
|
399
|
+
};
|
|
313
400
|
};
|
|
314
401
|
type StorefrontClient = ReturnType<typeof createStorefrontClient>;
|
|
315
402
|
|
|
316
|
-
export { type Address, type AuthSession, type BlogPost, type BookableService, type Booking, type CheckoutLineItem, type CheckoutSession, type Collection, type Customer, type FormDefinition, type FormField, type ListParams, type Order, type OrderItem, type PaginatedResponse, type Product, type ProductImage, type ProductVariant, type StoreConfig, type StorefrontClient, type StorefrontConfig, StorefrontError, type TimeSlot, createStorefrontClient };
|
|
403
|
+
export { type AddCartLineItemInput, type Address, type AuthSession, type BlogPost, type BookableService, type Booking, type CartLine, type CartState, type CheckoutLineItem, type CheckoutSession, type Collection, type Customer, type FormDefinition, type FormField, type ListParams, type Order, type OrderItem, type PaginatedResponse, type Product, type ProductImage, type ProductVariant, type RetryConfig, type StoreConfig, type StorefrontCart, type StorefrontClient, type StorefrontConfig, StorefrontError, type TimeSlot, createStorefrontClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
* const client = createStorefrontClient({ workspaceId: "<workspace_id>" });
|
|
10
10
|
* const products = await client.products.list();
|
|
11
11
|
*/
|
|
12
|
+
interface RetryConfig {
|
|
13
|
+
/** Max retry attempts for a failed request (default: 2) */
|
|
14
|
+
retries?: number;
|
|
15
|
+
/** Base delay in ms used for exponential backoff (default: 300) */
|
|
16
|
+
baseDelayMs?: number;
|
|
17
|
+
/** Upper bound for any single backoff delay, in ms (default: 4000) */
|
|
18
|
+
maxDelayMs?: number;
|
|
19
|
+
/** HTTP status codes that are retried, GET/HEAD only (default: [408,425,429,500,502,503,504]) */
|
|
20
|
+
retryOnStatus?: number[];
|
|
21
|
+
}
|
|
12
22
|
interface StorefrontConfig {
|
|
13
23
|
/** Your workspace ID (required) */
|
|
14
24
|
workspaceId: string;
|
|
@@ -18,6 +28,18 @@ interface StorefrontConfig {
|
|
|
18
28
|
customFetch?: typeof fetch;
|
|
19
29
|
/** Default locale for content */
|
|
20
30
|
locale?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Retry behavior for transient failures (network errors, and 5xx/408/425/429
|
|
33
|
+
* responses on idempotent GET/HEAD requests). Pass `false` to disable retries
|
|
34
|
+
* entirely. Defaults to 2 retries with exponential backoff.
|
|
35
|
+
*/
|
|
36
|
+
retry?: RetryConfig | false;
|
|
37
|
+
/**
|
|
38
|
+
* Persist the stateful cart (`client.cart`) to `localStorage` so it survives
|
|
39
|
+
* page reloads. Defaults to `true`. Has no effect in environments without
|
|
40
|
+
* `localStorage` (e.g. Node/SSR) — the cart simply stays in-memory.
|
|
41
|
+
*/
|
|
42
|
+
persistCart?: boolean;
|
|
21
43
|
}
|
|
22
44
|
interface ListParams {
|
|
23
45
|
page?: number;
|
|
@@ -84,7 +106,10 @@ interface Collection {
|
|
|
84
106
|
interface CheckoutLineItem {
|
|
85
107
|
productId: string;
|
|
86
108
|
variantId?: string;
|
|
109
|
+
productName: string;
|
|
87
110
|
quantity: number;
|
|
111
|
+
unitPrice: number;
|
|
112
|
+
imageUrl?: string;
|
|
88
113
|
}
|
|
89
114
|
interface CheckoutSession {
|
|
90
115
|
id: string;
|
|
@@ -98,6 +123,44 @@ interface CheckoutSession {
|
|
|
98
123
|
currency: string;
|
|
99
124
|
couponCode?: string;
|
|
100
125
|
}
|
|
126
|
+
interface CartLine {
|
|
127
|
+
id: string;
|
|
128
|
+
productId: string;
|
|
129
|
+
variantId?: string;
|
|
130
|
+
quantity: number;
|
|
131
|
+
unitPrice: number;
|
|
132
|
+
productName: string;
|
|
133
|
+
imageUrl?: string;
|
|
134
|
+
}
|
|
135
|
+
interface CartState {
|
|
136
|
+
id: string;
|
|
137
|
+
lines: CartLine[];
|
|
138
|
+
createdAt: string;
|
|
139
|
+
updatedAt: string;
|
|
140
|
+
}
|
|
141
|
+
interface AddCartLineItemInput {
|
|
142
|
+
productId: string;
|
|
143
|
+
variantId?: string;
|
|
144
|
+
quantity: number;
|
|
145
|
+
/** Skip the `products.get` price lookup by supplying these directly */
|
|
146
|
+
unitPrice?: number;
|
|
147
|
+
productName?: string;
|
|
148
|
+
imageUrl?: string;
|
|
149
|
+
}
|
|
150
|
+
interface StorefrontCart {
|
|
151
|
+
readonly id: string;
|
|
152
|
+
readonly lines: CartLine[];
|
|
153
|
+
readonly itemCount: number;
|
|
154
|
+
readonly subtotal: number;
|
|
155
|
+
/** Adds a line item. Supplying `unitPrice` also requires `productName`, otherwise this falls through to a `products.get` network lookup. */
|
|
156
|
+
addLineItem(input: AddCartLineItemInput): Promise<StorefrontCart>;
|
|
157
|
+
updateLineItem(lineId: string, quantity: number): StorefrontCart;
|
|
158
|
+
removeLineItem(lineId: string): StorefrontCart;
|
|
159
|
+
clear(): StorefrontCart;
|
|
160
|
+
checkout(opts?: {
|
|
161
|
+
clearOnSuccess?: boolean;
|
|
162
|
+
}): Promise<CheckoutSession>;
|
|
163
|
+
}
|
|
101
164
|
interface Order {
|
|
102
165
|
id: string;
|
|
103
166
|
orderNumber: string;
|
|
@@ -307,10 +370,34 @@ declare function createStorefrontClient(config: StorefrontConfig): {
|
|
|
307
370
|
}>;
|
|
308
371
|
};
|
|
309
372
|
cart: {
|
|
373
|
+
/** Create a new, empty cart (replaces any persisted cart) */
|
|
374
|
+
create(): StorefrontCart;
|
|
375
|
+
/** Get the current cart — loaded from storage if persisted, otherwise a fresh one */
|
|
376
|
+
current(): StorefrontCart;
|
|
310
377
|
/** Recover an abandoned cart by recovery token */
|
|
311
378
|
recover(token: string): Promise<CheckoutSession>;
|
|
312
379
|
};
|
|
380
|
+
orders: {
|
|
381
|
+
/** Get customer's order history (delegates to `customer.orders`) */
|
|
382
|
+
list: (params?: ListParams) => Promise<PaginatedResponse<Order>>;
|
|
383
|
+
};
|
|
384
|
+
customers: {
|
|
385
|
+
login: (email: string, password: string) => Promise<AuthSession>;
|
|
386
|
+
register: (data: {
|
|
387
|
+
email: string;
|
|
388
|
+
password: string;
|
|
389
|
+
name: string;
|
|
390
|
+
phone?: string;
|
|
391
|
+
}) => Promise<AuthSession>;
|
|
392
|
+
loginWithGoogle: (idToken: string) => Promise<AuthSession>;
|
|
393
|
+
logout: () => Promise<void>;
|
|
394
|
+
isAuthenticated: () => boolean;
|
|
395
|
+
setTokens: (access: string, refresh: string) => void;
|
|
396
|
+
me: () => Promise<Customer>;
|
|
397
|
+
orders: (params?: ListParams) => Promise<PaginatedResponse<Order>>;
|
|
398
|
+
addresses: () => Promise<Address[]>;
|
|
399
|
+
};
|
|
313
400
|
};
|
|
314
401
|
type StorefrontClient = ReturnType<typeof createStorefrontClient>;
|
|
315
402
|
|
|
316
|
-
export { type Address, type AuthSession, type BlogPost, type BookableService, type Booking, type CheckoutLineItem, type CheckoutSession, type Collection, type Customer, type FormDefinition, type FormField, type ListParams, type Order, type OrderItem, type PaginatedResponse, type Product, type ProductImage, type ProductVariant, type StoreConfig, type StorefrontClient, type StorefrontConfig, StorefrontError, type TimeSlot, createStorefrontClient };
|
|
403
|
+
export { type AddCartLineItemInput, type Address, type AuthSession, type BlogPost, type BookableService, type Booking, type CartLine, type CartState, type CheckoutLineItem, type CheckoutSession, type Collection, type Customer, type FormDefinition, type FormField, type ListParams, type Order, type OrderItem, type PaginatedResponse, type Product, type ProductImage, type ProductVariant, type RetryConfig, type StoreConfig, type StorefrontCart, type StorefrontClient, type StorefrontConfig, StorefrontError, type TimeSlot, createStorefrontClient };
|