@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/dist/index.js CHANGED
@@ -13,6 +13,18 @@ function createStorefrontClient(config) {
13
13
  const fetchFn = config.customFetch ?? globalThis.fetch.bind(globalThis);
14
14
  let accessToken = null;
15
15
  let refreshToken = null;
16
+ const RETRY_DEFAULTS = {
17
+ retries: 2,
18
+ baseDelayMs: 300,
19
+ maxDelayMs: 4e3,
20
+ retryOnStatus: [408, 425, 429, 500, 502, 503, 504]
21
+ };
22
+ const rc = config.retry === false ? { ...RETRY_DEFAULTS, retries: 0 } : { ...RETRY_DEFAULTS, ...config.retry || {} };
23
+ const IDEMPOTENT = /* @__PURE__ */ new Set(["GET", "HEAD"]);
24
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
25
+ function backoff(attempt) {
26
+ return Math.min(rc.maxDelayMs, Math.round(Math.random() * rc.baseDelayMs * Math.pow(2, attempt)));
27
+ }
16
28
  async function request(method, path, options) {
17
29
  const url = new URL(`${apiUrl}${path}`);
18
30
  if (options?.params) {
@@ -29,11 +41,32 @@ function createStorefrontClient(config) {
29
41
  if (options?.body) {
30
42
  headers["Content-Type"] = "application/json";
31
43
  }
32
- const res = await fetchFn(url.toString(), {
44
+ const fetchOptions = {
33
45
  method,
34
46
  headers,
35
47
  body: options?.body ? JSON.stringify(options.body) : void 0
36
- });
48
+ };
49
+ let attempt = 0;
50
+ let res;
51
+ while (true) {
52
+ try {
53
+ res = await fetchFn(url.toString(), fetchOptions);
54
+ } catch (err) {
55
+ if (attempt < rc.retries) {
56
+ await sleep(backoff(attempt));
57
+ attempt++;
58
+ continue;
59
+ }
60
+ throw err;
61
+ }
62
+ if (attempt < rc.retries && rc.retryOnStatus.includes(res.status) && IDEMPOTENT.has(method)) {
63
+ const ra = Number(res.headers.get("retry-after"));
64
+ await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1e3 : backoff(attempt));
65
+ attempt++;
66
+ continue;
67
+ }
68
+ break;
69
+ }
37
70
  if (res.status === 401 && options?.auth && refreshToken) {
38
71
  const refreshed = await refreshSession();
39
72
  if (refreshed) {
@@ -120,7 +153,7 @@ function createStorefrontClient(config) {
120
153
  const checkout = {
121
154
  /** Create a checkout session from cart items */
122
155
  async create(items) {
123
- return request("POST", "/checkout", { body: { items } });
156
+ return request("POST", "/checkout", { body: { lines: items } });
124
157
  },
125
158
  /** Retrieve an existing checkout session */
126
159
  async get(checkoutId) {
@@ -252,12 +285,152 @@ function createStorefrontClient(config) {
252
285
  return res.json();
253
286
  }
254
287
  };
288
+ const CART_KEY = "managesales_cart_" + config.workspaceId;
289
+ const hasLS = () => {
290
+ try {
291
+ return config.persistCart !== false && typeof localStorage !== "undefined";
292
+ } catch {
293
+ return false;
294
+ }
295
+ };
296
+ const loadCart = () => {
297
+ if (!hasLS()) return null;
298
+ try {
299
+ const s = localStorage.getItem(CART_KEY);
300
+ return s ? JSON.parse(s) : null;
301
+ } catch {
302
+ return null;
303
+ }
304
+ };
305
+ const saveCart = (st) => {
306
+ if (!hasLS()) return;
307
+ try {
308
+ localStorage.setItem(CART_KEY, JSON.stringify(st));
309
+ } catch {
310
+ }
311
+ };
312
+ let __lineSeq = 0;
313
+ const genId = (p) => typeof crypto !== "undefined" && crypto.randomUUID ? p + crypto.randomUUID() : p + Date.now() + "_" + ++__lineSeq;
314
+ const nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
315
+ const freshCart = () => ({ id: genId("cart_"), lines: [], createdAt: nowIso(), updatedAt: nowIso() });
316
+ function makeCart(state) {
317
+ const persist = () => {
318
+ state.updatedAt = nowIso();
319
+ saveCart(state);
320
+ };
321
+ const cartObj = {
322
+ get id() {
323
+ return state.id;
324
+ },
325
+ get lines() {
326
+ return state.lines;
327
+ },
328
+ get itemCount() {
329
+ return state.lines.reduce((n, l) => n + l.quantity, 0);
330
+ },
331
+ get subtotal() {
332
+ return state.lines.reduce((s, l) => s + l.unitPrice * l.quantity, 0);
333
+ },
334
+ // Supplying unitPrice alone does not skip the lookup — productName must also be
335
+ // provided, otherwise this falls through to the products.get() network lookup below.
336
+ async addLineItem(input) {
337
+ let line;
338
+ if (input.unitPrice != null && input.productName) {
339
+ line = {
340
+ id: genId("line_"),
341
+ productId: input.productId,
342
+ variantId: input.variantId,
343
+ quantity: input.quantity,
344
+ unitPrice: input.unitPrice,
345
+ productName: input.productName,
346
+ imageUrl: input.imageUrl
347
+ };
348
+ } else {
349
+ const p = await products.get(input.productId);
350
+ const v = input.variantId && Array.isArray(p.variants) ? p.variants.find((x) => x.id === input.variantId) : void 0;
351
+ line = {
352
+ id: genId("line_"),
353
+ productId: input.productId,
354
+ variantId: input.variantId,
355
+ quantity: input.quantity,
356
+ unitPrice: v && v.price != null ? v.price : p.price,
357
+ productName: p.name,
358
+ imageUrl: Array.isArray(p.images) && p.images.length > 0 ? p.images[0].url : void 0
359
+ };
360
+ }
361
+ const existing = state.lines.find((l) => l.productId === line.productId && l.variantId === line.variantId);
362
+ if (existing) existing.quantity += line.quantity;
363
+ else state.lines.push(line);
364
+ persist();
365
+ return cartObj;
366
+ },
367
+ updateLineItem(lineId, quantity) {
368
+ const l = state.lines.find((x) => x.id === lineId);
369
+ if (l) {
370
+ if (quantity <= 0) state.lines = state.lines.filter((x) => x.id !== lineId);
371
+ else l.quantity = quantity;
372
+ persist();
373
+ }
374
+ return cartObj;
375
+ },
376
+ removeLineItem(lineId) {
377
+ state.lines = state.lines.filter((x) => x.id !== lineId);
378
+ persist();
379
+ return cartObj;
380
+ },
381
+ clear() {
382
+ state.lines = [];
383
+ persist();
384
+ return cartObj;
385
+ },
386
+ async checkout(opts) {
387
+ const session = await checkout.create(
388
+ state.lines.map((l) => ({
389
+ productId: l.productId,
390
+ variantId: l.variantId,
391
+ productName: l.productName,
392
+ quantity: l.quantity,
393
+ unitPrice: l.unitPrice,
394
+ imageUrl: l.imageUrl
395
+ }))
396
+ );
397
+ if (opts && opts.clearOnSuccess) cartObj.clear();
398
+ return session;
399
+ }
400
+ };
401
+ return cartObj;
402
+ }
255
403
  const cart = {
404
+ /** Create a new, empty cart (replaces any persisted cart) */
405
+ create() {
406
+ const st = freshCart();
407
+ saveCart(st);
408
+ return makeCart(st);
409
+ },
410
+ /** Get the current cart — loaded from storage if persisted, otherwise a fresh one */
411
+ current() {
412
+ return makeCart(loadCart() || freshCart());
413
+ },
256
414
  /** Recover an abandoned cart by recovery token */
257
415
  async recover(token) {
258
416
  return request("GET", `/abandoned-carts/recover/${token}`);
259
417
  }
260
418
  };
419
+ const orders = {
420
+ /** Get customer's order history (delegates to `customer.orders`) */
421
+ list: (params) => customer.orders(params)
422
+ };
423
+ const customers = {
424
+ login: auth.login,
425
+ register: auth.register,
426
+ loginWithGoogle: auth.loginWithGoogle,
427
+ logout: auth.logout,
428
+ isAuthenticated: auth.isAuthenticated,
429
+ setTokens: auth.setTokens,
430
+ me: customer.me,
431
+ orders: customer.orders,
432
+ addresses: customer.addresses
433
+ };
261
434
  return {
262
435
  store,
263
436
  products,
@@ -268,7 +441,9 @@ function createStorefrontClient(config) {
268
441
  blog,
269
442
  bookings,
270
443
  forms,
271
- cart
444
+ cart,
445
+ orders,
446
+ customers
272
447
  };
273
448
  }
274
449
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","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.js","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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managesales/storefront",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
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,