@growupsell/commerce 1.0.0-alpha.2 → 1.0.0-alpha.3
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/{checkout-CwpFl6qt.d.ts → checkout-DDNMdKbR.d.ts} +27 -3
- package/dist/{chunk-AI2CWQ22.js → chunk-BORVKACK.js} +12 -4
- package/dist/chunk-BORVKACK.js.map +1 -0
- package/dist/{chunk-DHBRITDW.js → chunk-HGCKDE7D.js} +16 -8
- package/dist/chunk-HGCKDE7D.js.map +1 -0
- package/dist/{client-D4JNDM6j.d.ts → client-RzekAHeO.d.ts} +2 -9
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/rules/index.d.ts +1 -1
- package/dist/{sku-C3SGyRqT.d.ts → sku-ViHXTvEw.d.ts} +1 -1
- package/dist/stores/index.d.ts +8 -1
- package/dist/stores/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-AI2CWQ22.js.map +0 -1
- package/dist/chunk-DHBRITDW.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http/errors.ts","../src/http/convert.ts","../src/http/blog.ts","../src/http/business.ts","../src/http/cart.ts","../src/http/catalog.ts","../src/http/faq.ts","../src/http/forms.ts","../src/http/helpdesk.ts","../src/http/newsletter.ts","../src/http/push.ts","../src/http/live-support.ts","../src/http/policies.ts","../src/http/productPage.ts","../src/http/products.ts","../src/http/promotions.ts","../src/http/multipart.ts","../src/http/reviews.ts","../src/http/wishlist.ts","../src/http/theme-content.ts","../src/http/customPages.ts","../src/http/session.ts","../src/http/lookup.ts","../src/http/auth.ts","../src/http/customer.ts","../src/http/addresses.ts","../src/http/checkout.ts","../src/http/payments.ts","../src/http/custom-manufacturing.ts","../src/http/subscriptions.ts","../src/http/orders.ts","../src/http/returns.ts","../src/http/exchanges.ts","../src/http/query.ts","../src/http/client.ts"],"sourcesContent":["export type ApiErrorKind = 'http' | 'network' | 'timeout' | 'parse';\n\n/**\n * The single error type every request rejects with, so every app can show the same messages.\n */\nexport class GrowupsellApiError extends Error {\n readonly kind: ApiErrorKind;\n /** HTTP status; undefined when no response arrived (network, timeout). */\n readonly status: number | undefined;\n /** Validation messages per field, as returned by the backend (`non_field_errors` included). */\n readonly fieldErrors: Readonly<Record<string, readonly string[]>>;\n /** The parsed response body, for anything the fields above don't cover. */\n readonly body: unknown;\n /**\n * For a 429 (throttled OTP checks and sends, backend S14): the seconds from `Retry-After`.\n * Null otherwise, and when the header is missing or not a whole number of seconds.\n */\n readonly retryAfterSeconds: number | null;\n\n constructor(init: {\n kind: ApiErrorKind;\n message: string;\n status?: number;\n fieldErrors?: Record<string, string[]>;\n body?: unknown;\n retryAfterSeconds?: number | null;\n }) {\n super(init.message);\n this.name = 'GrowupsellApiError';\n this.kind = init.kind;\n this.status = init.status;\n this.fieldErrors = init.fieldErrors ?? {};\n this.body = init.body;\n this.retryAfterSeconds = init.retryAfterSeconds ?? null;\n }\n}\n\n/**\n * `Retry-After` as seconds. Only the delay-seconds form: the HTTP-date form would need a clock,\n * and the client has none to inject (the backend sends seconds).\n */\nexport function parseRetryAfter(value: string | null | undefined): number | null {\n const text = value?.trim();\n return text && /^\\d+$/.test(text) ? Number(text) : null;\n}\n\n/**\n * Finds the most useful message in a Django REST Framework error body:\n * `{detail}`, `{message}`, `{field: [msg]}`, nested objects, lists or a plain string.\n */\nexport function messageFromBody(body: unknown): string | undefined {\n if (typeof body === 'string') {\n const text = body.trim();\n // An HTML error page (e.g. Django's \"Server Error (500)\") is not a message to show.\n return text && !text.startsWith('<') ? text : undefined;\n }\n if (Array.isArray(body)) return body.length > 0 ? messageFromBody(body[0]) : undefined;\n if (body && typeof body === 'object') {\n const record = body as Record<string, unknown>;\n for (const key of ['detail', 'message']) {\n if (typeof record[key] === 'string' && record[key]) return record[key];\n }\n for (const value of Object.values(record)) {\n // Flags such as `success: false` carry no message.\n if (typeof value === 'boolean' || typeof value === 'number' || value == null) continue;\n const found = messageFromBody(value);\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/** Field validation errors: every key whose value is a message or a list of messages. */\nexport function fieldErrorsFromBody(body: unknown): Record<string, string[]> {\n if (!body || typeof body !== 'object' || Array.isArray(body)) return {};\n const errors: Record<string, string[]> = {};\n for (const [field, value] of Object.entries(body)) {\n if (field === 'detail' || field === 'message') continue;\n if (typeof value === 'string') errors[field] = [value];\n else if (\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((v) => typeof v === 'string')\n ) {\n errors[field] = value;\n }\n }\n return errors;\n}\n","/** Small wire → domain helpers shared by every module. */\n\n/** '' / whitespace / missing → null: the backend fills new rows with empty strings. */\nexport const text = (value: string | null | undefined): string | null =>\n value == null || value.trim() === '' ? null : value;\n\n/** Decimal string or number → number (\"58999.00\" → 58999); null/''/invalid → null. */\nexport const amount = (value: string | number | null | undefined): number | null => {\n if (value == null || value === '') return null;\n const n = typeof value === 'number' ? value : Number(value);\n return Number.isFinite(n) ? n : null;\n};\n","import type {\n BlogAuthor,\n BlogCategory,\n BlogEditor,\n BlogPost,\n BlogPostSummary,\n} from '../types/blog';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireBlogAuthor,\n WireBlogBodyUpdate,\n WireBlogCategory,\n WireBlogListItem,\n WireBlogPost,\n} from './wire/blog';\n\nexport interface BlogApi {\n /** Newest first; all of the business's posts (the backend does not page this list). */\n list(options?: { categorySlug?: string }): Promise<BlogPostSummary[]>;\n /** Throws GrowupsellApiError with status 404 for an unknown slug. */\n get(slug: string): Promise<BlogPost>;\n /** Merchant (theme edit): replaces the post's HTML sections. */\n updateBody(slug: string, body: string[]): Promise<void>;\n}\n\n// Blog list and detail read the business from the header and fail (500) without it. ADR-017.\nconst PUBLIC = { anonymous: true, business: 'required' } as const;\n// The merchant token, without the customer token (an expired one would answer 401).\nconst MERCHANT = { merchant: true, anonymous: true, business: 'required' } as const;\n\nexport function createBlogApi(request: RequestFn): BlogApi {\n return {\n async list(options = {}) {\n const categorySlug = options.categorySlug?.trim();\n const rows = await request<WireBlogListItem[]>('GET', '/blog/list', {\n ...PUBLIC,\n query: categorySlug ? { category_slug: categorySlug } : undefined,\n });\n return rows.map(toBlogPostSummary);\n },\n async get(slug) {\n return toBlogPost(await request<WireBlogPost>('GET', `/blog/get/${path(slug)}`, PUBLIC));\n },\n async updateBody(slug, body) {\n const json: WireBlogBodyUpdate = { body };\n // Answers the `BlogSerializer` row (category as an id, no author): not needed.\n await request('PATCH', `/blog/update/${path(slug)}`, { ...MERCHANT, json });\n },\n };\n}\n\nfunction path(slug: string): string {\n if (!slug.trim()) throw new Error('blog: slug is required.');\n return encodeURIComponent(slug.trim());\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\n/** The editor `token` and the author's email are left out on purpose (S17, S29). */\nexport function toBlogPostSummary(wire: WireBlogListItem): BlogPostSummary {\n return summary(wire, wire.user);\n}\n\nexport function toBlogPost(wire: WireBlogPost): BlogPost {\n return {\n ...summary(wire, wire.created_by),\n body: Array.isArray(wire.body)\n ? wire.body.filter((s): s is string => typeof s === 'string')\n : [],\n editor: EDITORS.includes(wire.editor_type as BlogEditor)\n ? (wire.editor_type as BlogEditor)\n : 'quill',\n };\n}\n\nconst EDITORS: readonly BlogEditor[] = ['quill', 'ckeditor', 'froala'];\n\nfunction summary(\n wire: Omit<WireBlogListItem, 'user' | 'created_by'>,\n author: WireBlogAuthor | null,\n): BlogPostSummary {\n return {\n id: wire.id,\n slug: wire.slug,\n title: wire.title,\n shortDescription: text(wire.short_description),\n image: text(wire.image),\n category: wire.category ? toCategory(wire.category) : null,\n tags: Array.isArray(wire.tags)\n ? wire.tags.filter((t): t is string => typeof t === 'string' && t.trim() !== '')\n : [],\n author: author ? toAuthor(author) : null,\n isPublished: wire.is_published ?? false,\n createdAt: wire.created_at,\n updatedAt: wire.updated_at,\n };\n}\n\nfunction toCategory(wire: WireBlogCategory): BlogCategory {\n return {\n id: wire.id,\n name: text(wire.name),\n slug: wire.slug,\n image: text(wire.image),\n seoDescription: text(wire.seo_description),\n };\n}\n\nfunction toAuthor(wire: WireBlogAuthor): BlogAuthor {\n return { id: wire.id, name: text(wire.name.trim()), photo: text(wire.photo) };\n}\n","import type {\n BankTransferOption,\n Business,\n BusinessMedia,\n BusinessSettings,\n SocialLinks,\n ThemeSettings,\n ThemeSettingsUpdate,\n} from '../types/business';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireBusinessConfig,\n WireBusinessMedia,\n WireBusinessSetting,\n WireBusinessSocialMediaLink,\n WireDirectTransferOption,\n WireThemeSetting,\n WireThemeSettingWrite,\n WireUpdatedThemeSetting,\n} from './wire/business';\n\nexport interface BusinessApi {\n /**\n * The business a storefront domain belongs to. The backend ignores a `:port` and maps\n * `localhost` / `127.0.0.1` to its development business. Call this first: its `id` is the\n * `businessId` every other business-scoped request needs.\n */\n detail(domain: string): Promise<Business>;\n /** Currency and primary domain. */\n settings(): Promise<BusinessSettings>;\n /** Logos. */\n media(): Promise<BusinessMedia>;\n socialLinks(): Promise<SocialLinks>;\n /** Direct bank / UPI transfer options offered at checkout (deleted ones excluded). */\n bankTransferOptions(): Promise<BankTransferOption[]>;\n /**\n * Colours and font, and the theme settings `id` that `client.themeContent` takes as\n * `themeId`. Every storefront page needs it. Public.\n */\n themeSettings(): Promise<ThemeSettings>;\n /**\n * Merchant (manager role): changes the given fields of the merchant's own theme settings and\n * returns the result.\n */\n updateThemeSettings(changes: ThemeSettingsUpdate): Promise<ThemeSettings>;\n}\n\n// These endpoints resolve the business from the `business` header; the catalog-style ones are\n// public, so a lapsed customer login must not break them (ADR-015).\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n// The theme settings update changes the token's own business (`request.user.business`), so it\n// does not need the `business` header (when sent, the backend checks it matches: 403). It\n// leaves the customer token out: an expired one would be a 401 reported as a merchant logout.\nconst MERCHANT = { merchant: true, anonymous: true } as const;\n\nexport function createBusinessApi(request: RequestFn): BusinessApi {\n return {\n async detail(domain) {\n const trimmed = domain.trim();\n if (!trimmed) throw new Error('business.detail: domain is required.');\n const wire = await request<WireBusinessConfig>(\n 'GET',\n `/business/detail/${encodeURIComponent(trimmed)}`,\n { anonymous: true },\n );\n return toBusiness(wire);\n },\n async settings() {\n return toBusinessSettings(\n await request<WireBusinessSetting>('GET', '/business/setting/get', PUBLIC),\n );\n },\n async media() {\n return toBusinessMedia(\n await request<WireBusinessMedia>('GET', '/business/media/get', PUBLIC),\n );\n },\n async socialLinks() {\n return toSocialLinks(\n await request<WireBusinessSocialMediaLink>(\n 'GET',\n '/business/social-media-link/get',\n PUBLIC,\n ),\n );\n },\n async bankTransferOptions() {\n // Needs a customer or an order session (IsManagerOrCustomerOrOrderSessionToken): not anonymous.\n const wire = await request<WireDirectTransferOption[]>(\n 'GET',\n '/business/direct/transfer/list',\n {\n business: 'required',\n },\n );\n return wire.filter((o) => !o.deleted).map(toBankTransferOption);\n },\n async themeSettings() {\n // Without the header the backend fails with a KeyError (500); PUBLIC refuses first.\n return toThemeSettings(\n await request<WireThemeSetting>('GET', '/business/theme/setting/get', PUBLIC),\n );\n },\n async updateThemeSettings(changes) {\n const wire = await request<WireUpdatedThemeSetting>(\n 'PATCH',\n '/business/theme/setting/update',\n { ...MERCHANT, json: toThemeSettingWrite(changes) },\n );\n return toThemeSettings(wire);\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toBusiness(wire: WireBusinessConfig): Business {\n const tag = wire.website_tag;\n return {\n id: wire.id,\n name: wire.name ?? null,\n description: wire.description ?? null,\n legalName: wire.legal_name ?? null,\n gstNumber: wire.gst_number ?? null,\n panNumber: wire.pan_number ?? null,\n isTemplate: wire.is_template ?? false,\n category: wire.category\n ? { id: wire.category.id, name: wire.category.name, type: wire.category.type }\n : null,\n legalForm: wire.legal_forms ? { id: wire.legal_forms.id, name: wire.legal_forms.name } : null,\n features: wire.features.filter((f) => f.is_active !== false).map((f) => f.name),\n googleTagManagerId: tag?.is_active && tag.gtm_container_id ? tag.gtm_container_id : null,\n createdAt: wire.created_at,\n updatedAt: wire.updated_at,\n };\n}\n\nexport function toBusinessSettings(wire: WireBusinessSetting): BusinessSettings {\n return {\n currency: wire.currency\n ? { code: wire.currency.currency_code, symbol: wire.currency.currency_symbol }\n : null,\n domain: text(wire.domain),\n };\n}\n\nfunction toBusinessMedia(wire: WireBusinessMedia): BusinessMedia {\n return { logoSquare: text(wire.logo_square), logoRectangle: text(wire.logo_rectangle) };\n}\n\nfunction toSocialLinks(wire: WireBusinessSocialMediaLink): SocialLinks {\n return {\n facebook: text(wire.facebook),\n instagram: text(wire.instagram),\n twitter: text(wire.twitter),\n telegram: text(wire.telegram),\n whatsapp: text(wire.whatsapp),\n linkedin: text(wire.linkedin),\n };\n}\n\n/** Both answers: the read nests the lookup themes (depth 2), the update sends their ids. */\nexport function toThemeSettings(wire: WireThemeSetting | WireUpdatedThemeSetting): ThemeSettings {\n return {\n id: wire.id,\n // Required by the model; '#CCC' is its default.\n primaryColor: text(wire.primary_color) ?? '#CCC',\n accentColor: text(wire.accent_color),\n fontFamily: text(wire.font_family),\n websiteThemeId: themeId(wire.website_theme),\n appThemeId: themeId(wire.app_theme),\n };\n}\n\nconst themeId = (theme: { id: number } | number | null): number | null =>\n typeof theme === 'number' ? theme : (theme?.id ?? null);\n\n/** Only the fields given: a PATCH leaves the others unchanged. */\nfunction toThemeSettingWrite(changes: ThemeSettingsUpdate): WireThemeSettingWrite {\n const body: WireThemeSettingWrite = {};\n if (changes.primaryColor !== undefined) body.primary_color = changes.primaryColor;\n if (changes.accentColor !== undefined) body.accent_color = changes.accentColor;\n if (changes.fontFamily !== undefined) body.font_family = changes.fontFamily;\n if (changes.websiteThemeId !== undefined) body.website_theme = changes.websiteThemeId;\n if (changes.appThemeId !== undefined) body.app_theme = changes.appThemeId;\n return body;\n}\n\nfunction toBankTransferOption(wire: WireDirectTransferOption): BankTransferOption {\n return {\n id: wire.id,\n type: text(wire.type),\n description: text(wire.description),\n photo: text(wire.photo),\n paymentMethodId: wire.payment_method ?? null,\n };\n}\n","import type {\n AppliedPromoCode,\n Cart,\n CartLine,\n CartTotals,\n DeliveryEstimate,\n OrderType,\n TaxDetails,\n} from '../types/cart';\nimport { amount, text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireCart,\n WireCartAddresses,\n WireCartLineCreate,\n WireCartLineCreated,\n WireCartOfferUpdate,\n WireCartPromoUpdate,\n WireCartTax,\n WireCartTotals,\n WireDeliveryEstimate,\n WireOrderLine,\n WirePromoCode,\n} from './wire/cart';\n\nexport interface CartAddressesInput {\n /** One of the customer's own addresses. */\n shippingAddressId?: number;\n billingAddressId?: number;\n}\n\nexport interface AddCartItemInput {\n skuId: number;\n /** A whole number, 1 or more. */\n quantity: number;\n /** Answers to the product's custom fields (e.g. a ring size). */\n customData?: Record<string, unknown>;\n}\n\n/**\n * The shopper's cart. The backend finds it from the login (`customerToken`) or, for a guest,\n * from the session (`sessionToken`) plus the business; it calculates every total on every\n * change, so refetch the cart with `get()` after a change instead of adjusting totals locally.\n */\nexport interface CartApi {\n /**\n * The cart, with its lines and the backend's totals. Creates the cart on first call (the\n * backend does): call once per screen, not in a loop.\n */\n get(): Promise<Cart>;\n /**\n * Adds a SKU (pick the variant first). Adding a SKU already in the cart adds the quantity to\n * its line, so a repeated request adds twice: disable the button while one is pending.\n * Made-to-order advance products are not added to the cart: use\n * `checkout.createAdvanceOrder()`.\n */\n addItem(input: AddCartItemInput): Promise<{ lineId: number }>;\n /** Sets a line's quantity (`CartLine.id`); 0 removes the line. Safe to repeat. */\n setQuantity(lineId: number, quantity: number): Promise<void>;\n /** Removes a line (`CartLine.id`). */\n removeItem(lineId: number): Promise<void>;\n /**\n * Switches between online payment (`delivery`) and cash on delivery (`cod`); the backend\n * recalculates the delivery charge. Offers apply to `delivery` carts only.\n */\n setOrderType(type: OrderType): Promise<CartTotals>;\n /**\n * Sets the shipping and/or billing address: ids of the logged-in customer's own addresses\n * (another customer's address is a 404). Needs a customer login: guests cannot set addresses.\n */\n setAddresses(\n input: CartAddressesInput,\n ): Promise<{ shippingAddressId: number | null; billingAddressId: number | null }>;\n /**\n * Applies an offer by id (`Offer.id`, from `promotions.eligibleOffers()`), or removes it with\n * `null`. Clears any promo code: offers and promo codes do not combine. Refetch the cart for\n * the new totals.\n */\n applyOffer(offerId: number | null): Promise<void>;\n /**\n * Applies a promo code by id (`PromoCode.id`, from `promotions.promoCode(code)`), or removes\n * it with `null`. Clears any offer. Expired or already redeemed codes are refused (400 with\n * the backend's message). Refetch the cart for the new totals.\n */\n applyPromoCode(promoCodeId: number | null): Promise<void>;\n /**\n * Business tax details for the invoice (legal name, GSTIN). Creates or replaces them, so it\n * is safe to repeat. The backend requires a guest session token here, even for customers.\n */\n setTaxDetails(input: TaxDetails): Promise<TaxDetails>;\n /**\n * A delivery partner's quote for the cart (`Cart.id`). Only meaningful when\n * `cart.deliveryChargeType === 'as_per_delivery_partner'` (otherwise a 400). Without a\n * pincode the backend uses the cart's shipping address. The backend stores the quote in the\n * cart's totals, so refetch the cart afterwards. Slow: the backend asks the partner.\n */\n deliveryEstimate(cartId: number, options?: { pincode?: string }): Promise<DeliveryEstimate>;\n}\n\n// Cart endpoints read `request.business` and work for a logged-in customer or a guest session.\n// Never anonymous: the customer token is what finds the customer's cart.\nconst SHOPPER = { business: 'required', customerOrSession: 'required' } as const;\n\nexport function createCartApi(request: RequestFn): CartApi {\n async function removeItem(lineId: number) {\n await request('DELETE', `/order/cart/product/delete/${lineId}`, SHOPPER);\n }\n\n return {\n async get() {\n return toCart(await request<WireCart>('GET', '/order/cart/get', SHOPPER));\n },\n\n async addItem({ skuId, quantity, customData }) {\n checkQuantity(quantity, 1);\n // Only these keys: the backend would also accept a price, an offer or an advance amount\n // from the client (backend issues S33, S35).\n const json: WireCartLineCreate = { sku: skuId, qty: quantity };\n if (customData) json.custom_data = customData;\n const wire = await request<WireCartLineCreated>('POST', '/order/cart/product/create', {\n ...SHOPPER,\n json,\n });\n return { lineId: wire.id };\n },\n\n async setQuantity(lineId, quantity) {\n checkQuantity(quantity, 0);\n if (quantity === 0) return removeItem(lineId);\n await request('PATCH', `/order/cart/product/update/${lineId}`, {\n ...SHOPPER,\n json: { qty: quantity },\n });\n },\n\n removeItem,\n\n async setOrderType(type) {\n const wire = await request<WireCartTotals>('PATCH', '/order/cart/type/update', {\n ...SHOPPER,\n json: { type },\n });\n return {\n subtotal: amount(wire.total_amount) ?? 0,\n deliveryCharge: amount(wire.delivery_charge) ?? 0,\n payable: amount(wire.final_payable_amount) ?? 0,\n };\n },\n\n async setAddresses({ shippingAddressId, billingAddressId }) {\n if (shippingAddressId == null && billingAddressId == null) {\n throw new TypeError('setAddresses: pass shippingAddressId, billingAddressId or both.');\n }\n const json: WireCartAddresses = {};\n if (shippingAddressId != null) json.shipping_address = shippingAddressId;\n if (billingAddressId != null) json.billing_address = billingAddressId;\n // A guest crashes the view (no `request.customer`): customers only.\n const wire = await request<WireCartAddresses>('PATCH', '/order/cart/address/update', {\n business: 'required',\n customer: 'required',\n json,\n });\n return {\n shippingAddressId: wire.shipping_address ?? null,\n billingAddressId: wire.billing_address ?? null,\n };\n },\n\n async applyOffer(offerId) {\n const json: WireCartOfferUpdate = { offer: offerId };\n await request('PATCH', '/order/cart/offer/update', { ...SHOPPER, json });\n },\n\n async applyPromoCode(promoCodeId) {\n const json: WireCartPromoUpdate = { promo: promoCodeId };\n await request('PATCH', '/order/cart/promo/update', { ...SHOPPER, json });\n },\n\n async setTaxDetails({ legalName, taxNumber }) {\n // `tax/update` is an upsert; `tax/create` fails on a second call (ADR-023, D2). Its\n // permission is `HasSessionToken`: a session token is required even with a login.\n const json: WireCartTax = { legal_name: legalName, tax_number: taxNumber };\n const wire = await request<WireCartTax>('PATCH', '/order/cart/tax/update', {\n business: 'required',\n session: 'required',\n json,\n });\n return { legalName: wire.legal_name, taxNumber: wire.tax_number };\n },\n\n async deliveryEstimate(cartId, options = {}) {\n const wire = await request<WireDeliveryEstimate>(\n 'GET',\n `/order/cart/delivery/charge/info/get/${cartId}`,\n // The backend calls Shiprocket synchronously; a blank pincode is left out.\n { ...SHOPPER, timeoutMs: 30_000, query: { pincode: options.pincode?.trim() } },\n );\n return {\n deliveryCharge: amount(wire.delivery_charge) ?? 0,\n payable: amount(wire.final_payable_amount) ?? 0,\n estimatedDelivery: text(wire.estimate_delivery_day),\n };\n },\n };\n}\n\nfunction checkQuantity(quantity: number, min: number) {\n if (!Number.isInteger(quantity) || quantity < min) {\n throw new RangeError(`Cart quantity must be a whole number of at least ${min}: ${quantity}.`);\n }\n}\n\n// Wire → domain. Exported for tests and for `orders` (not part of the package's public API).\n\nexport function toCart(wire: WireCart): Cart {\n const lines = (wire.products ?? []).map(toCartLine);\n const orderOffer = amount(wire.offer_redeem_amount) ?? 0;\n return {\n id: wire.id,\n type: wire.type,\n lines,\n subtotal: amount(wire.total_amount) ?? 0,\n // The backend stores the offer amount on the order for order-level offers, or on each line\n // for product, category and brand offers (never both).\n offerDiscount: orderOffer > 0 ? orderOffer : sum(lines.map((line) => line.offerDiscount)),\n promoDiscount: amount(wire.promo_redeem_amount) ?? 0,\n deliveryCharge: amount(wire.delivery_charge) ?? 0,\n payable: amount(wire.final_payable_amount) ?? 0,\n deliveryChargeType: wire.delivery_charge_type ?? null,\n offer: wire.offers\n ? { id: wire.offers.id, name: wire.offers.name, couponCode: text(wire.offers.coupon_code) }\n : null,\n promoCode: wire.promo ? toAppliedPromoCode(wire.promo) : null,\n shippingAddressId: idOf(wire.shipping_address),\n billingAddressId: idOf(wire.billing_address),\n advanceAmount: amount(wire.advance_amount),\n };\n}\n\nexport function toCartLine(wire: WireOrderLine): CartLine {\n const { sku } = wire;\n const mrp = sku ? amount(sku.mrp) : null;\n return {\n id: wire.id,\n skuId: sku?.id ?? null,\n productId: sku?.product.id ?? null,\n name: wire.label ?? wire.name ?? '',\n photo: text(wire.photo),\n unitPrice: amount(wire.price) ?? 0,\n // An MRP of 0 means \"not set\", as in products.\n mrp: mrp && mrp > 0 ? mrp : null,\n quantity: wire.qty,\n lineTotal: amount(wire.total) ?? 0,\n offerDiscount: amount(wire.offer_redeem_amount) ?? 0,\n taxPercent: amount(wire.tax),\n maxQuantity: sku ? wire.max_qty : null,\n isDigital: wire.is_digital_product,\n fulfillmentMode: text(wire.fulfillment_mode) ?? 'none',\n customData: wire.custom_data ?? null,\n // The cart serialises the SKU at depth 2, so `selected_variants` are variant rows, not ids\n // (local backend, 2026-11-01): take each row's id.\n variantIds: (sku?.selected_variants ?? []).map((variant) => variant.id),\n };\n}\n\nfunction toAppliedPromoCode(wire: WirePromoCode): AppliedPromoCode {\n return {\n id: wire.id,\n code: wire.code ?? '',\n type: wire.type ?? 'percentage',\n value: amount(wire.value) ?? 0,\n };\n}\n\n/** A nested row's id; a bare id is accepted too (update responses send ids). */\nfunction idOf(value: { id: number } | number | null | undefined): number | null {\n if (value == null) return null;\n return typeof value === 'number' ? value : value.id;\n}\n\nfunction sum(values: number[]): number {\n // Rounded to cents: adding decimal amounts as floats can leave 0.30000000000000004.\n return Math.round(values.reduce((total, value) => total + value, 0) * 100) / 100;\n}\n","import type { Brand, CatalogSettings, Category, CategoryTree } from '../types/catalog';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireProductBrand,\n WireProductBusinessSetting,\n WireProductCategory,\n WireProductCategoryList,\n} from './wire/catalog';\n\nexport interface CatalogApi {\n /**\n * Top-level categories with their sub-categories. With `search`, the categories whose name\n * or description match; when only sub-categories match, their parents with just those\n * sub-categories.\n */\n categories(options?: { search?: string }): Promise<CategoryTree[]>;\n /** One category, without sub-categories. */\n category(id: number): Promise<Category>;\n /** Several categories by id, without sub-categories. An empty list resolves to `[]`. */\n categoriesByIds(ids: readonly number[]): Promise<Category[]>;\n /** Brands; with `categoryIds`, those with products in these categories or their sub-categories. */\n brands(options?: { categoryIds?: readonly number[] }): Promise<Brand[]>;\n /** Which catalog features the merchant has switched on. */\n settings(): Promise<CatalogSettings>;\n}\n\n// Catalog endpoints are public and resolve the business from the `business` header (ADR-017).\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n\nexport function createCatalogApi(request: RequestFn): CatalogApi {\n return {\n async categories(options = {}) {\n const search = options.search?.trim();\n const wire = await request<WireProductCategoryList[]>('GET', '/product/category/list', {\n ...PUBLIC,\n query: { search },\n });\n return wire.map(toCategoryTree);\n },\n async category(id) {\n // The backend does not scope this endpoint to the business, so the header is not needed.\n return toCategory(\n await request<WireProductCategory>('GET', `/product/category/get/${id}`, {\n anonymous: true,\n }),\n );\n },\n async categoriesByIds(ids) {\n // Without ids the backend returns every category; an empty selection means none.\n if (ids.length === 0) return [];\n const wire = await request<WireProductCategory[]>('GET', '/product/category/list/filter', {\n ...PUBLIC,\n query: { ids },\n });\n return wire.map(toCategory);\n },\n async brands(options = {}) {\n const wire = await request<WireProductBrand[]>('GET', '/product/brand/list', {\n ...PUBLIC,\n query: { category_ids: options.categoryIds },\n });\n return wire.map(toBrand);\n },\n async settings() {\n return toCatalogSettings(\n await request<WireProductBusinessSetting>('GET', '/product/business/setting/get', PUBLIC),\n );\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nfunction toCategory(wire: WireProductCategory | WireProductCategoryList): Category {\n return {\n id: wire.id,\n name: wire.name,\n description: text(wire.description),\n photo: text(wire.photo),\n parentId: wire.parent ?? null,\n productCount: wire.product_count,\n };\n}\n\nexport function toCategoryTree(wire: WireProductCategoryList): CategoryTree {\n return { ...toCategory(wire), children: wire.child.map(toCategoryTree) };\n}\n\nfunction toBrand(wire: WireProductBrand): Brand {\n return {\n id: wire.id,\n name: wire.name,\n description: text(wire.description),\n photo: text(wire.photo),\n productCount: wire.product_count,\n };\n}\n\n// Defaults follow the backend model (products.models.ProductBusinessSetting).\nfunction toCatalogSettings(wire: WireProductBusinessSetting): CatalogSettings {\n return {\n reviews: wire.is_active_review ?? true,\n brands: wire.is_active_brand ?? true,\n categories: wire.is_active_category ?? true,\n subscriptions: wire.is_active_subscription ?? true,\n digitalDelivery: wire.enable_digital_delivery ?? false,\n variants: wire.is_active_variants ?? true,\n specifications: wire.is_active_specification ?? true,\n unitTracking: wire.has_product_unit_tracking_info ?? false,\n manufactureAndExpiryDates: wire.has_mfg_expiry_date ?? false,\n };\n}\n","import type { Faq } from '../types/faq';\nimport { text } from './convert';\nimport type { MoveDirection } from './policies';\nimport type { RequestFn } from './types';\nimport type { WireFaq, WireFaqWrite } from './wire/faq';\nimport type { WireMoveBody, WireMoveDone } from './wire/policies';\n\n/** What a merchant writes for one question. */\nexport interface FaqInput {\n question: string;\n /** HTML. */\n answer: string;\n}\n\nexport interface FaqApi {\n /** The questions in display order. Public. */\n list(): Promise<Faq[]>;\n /** Merchant (manager role): adds a question at the end. */\n create(input: FaqInput): Promise<Faq>;\n /** Merchant: changes only the given fields. */\n update(id: number, changes: Partial<FaqInput>): Promise<Faq>;\n /**\n * Merchant: swaps the question with its neighbour. Rejects with a 400 `GrowupsellApiError`\n * when it is already first (`up`) or last (`down`).\n */\n move(id: number, direction: MoveDirection): Promise<void>;\n /** Merchant: removes the question from the list. */\n remove(id: number): Promise<void>;\n}\n\n// Every FAQ view reads the business from the header and fails (500) without it. ADR-017.\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n// The merchant token, without the customer token: an expired customer token would make the\n// backend answer 401, which the client would report as a merchant logout.\nconst MERCHANT = { business: 'required', merchant: true, anonymous: true } as const;\n\nexport function createFaqApi(request: RequestFn): FaqApi {\n return {\n async list() {\n return (await request<WireFaq[]>('GET', '/content/faq/list', PUBLIC)).map(toFaq);\n },\n async create(input) {\n const json: WireFaqWrite = { question: input.question, answer: input.answer };\n return toFaq(await request<WireFaq>('POST', '/content/faq/create', { ...MERCHANT, json }));\n },\n async update(id, changes) {\n const json: WireFaqWrite = {};\n if (changes.question !== undefined) json.question = changes.question;\n if (changes.answer !== undefined) json.answer = changes.answer;\n return toFaq(\n await request<WireFaq>('PATCH', `/content/faq/update/${id}`, { ...MERCHANT, json }),\n );\n },\n async move(id, direction) {\n const json: WireMoveBody = { direction };\n await request<WireMoveDone>('PATCH', `/content/faq/update/${id}`, { ...MERCHANT, json });\n },\n async remove(id) {\n await request('DELETE', `/content/faq/delete/${id}`, MERCHANT);\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toFaq(wire: WireFaq): Faq {\n return {\n id: wire.id,\n question: text(wire.question),\n answer: text(wire.answer),\n displayOrder: wire.display_order,\n };\n}\n","import type { FormField, FormFieldType, FormSummary, FormValue, PublicForm } from '../types/forms';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type { WireForm, WireFormField, WireFormSubmission, WirePublicForm } from './wire/forms';\n\nexport interface FormsApi {\n /** An active form. Throws GrowupsellApiError 404 when it does not exist or is inactive. */\n get(slug: string): Promise<PublicForm>;\n /**\n * Submits the values, keyed by field name. A logged-in customer is attributed automatically.\n * Rejected values come back in the error's `fieldErrors.data`. `image` / `file` fields take a\n * URL string.\n */\n submit(slug: string, values: Record<string, FormValue>): Promise<void>;\n /** Merchant (theme edit): active forms to pick from, newest first. */\n listForMerchant(): Promise<FormSummary[]>;\n}\n\n// Without the business the backend answers 404 \"Business not found.\" for every form. ADR-017.\nconst PUBLIC = { anonymous: true, business: 'required' } as const;\n// The customer token is sent when present: the backend attributes the submission to them.\nconst SUBMIT = { business: 'required' } as const;\n// The merchant token, without the customer token (an expired one would answer 401).\nconst MERCHANT = { merchant: true, anonymous: true, business: 'required' } as const;\n\nexport function createFormsApi(request: RequestFn): FormsApi {\n return {\n async get(slug) {\n return toPublicForm(\n await request<WirePublicForm>('GET', `/forms/public/${path(slug)}`, PUBLIC),\n );\n },\n async submit(slug, values) {\n const json: WireFormSubmission = { data: values };\n await request('POST', `/forms/submit/${path(slug)}`, { ...SUBMIT, json });\n },\n async listForMerchant() {\n // No `limit`: the backend then answers a plain array instead of a page.\n const rows = await request<WireForm[]>('GET', '/forms/list', {\n ...MERCHANT,\n query: { is_active: true },\n });\n return rows.map(toFormSummary);\n },\n };\n}\n\nfunction path(slug: string): string {\n if (!slug.trim()) throw new Error('forms: slug is required.');\n return encodeURIComponent(slug.trim());\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toPublicForm(wire: WirePublicForm): PublicForm {\n const fields = Array.isArray(wire.field_configuration) ? wire.field_configuration : [];\n return {\n id: wire.id,\n slug: wire.slug,\n name: wire.name,\n description: text(wire.description),\n successMessage: text(wire.success_message),\n fields: fields.map(toFormField),\n };\n}\n\nexport function toFormSummary(wire: WireForm): FormSummary {\n return { id: wire.id, name: wire.name, slug: wire.slug };\n}\n\nfunction toFormField(wire: WireFormField): FormField {\n return {\n name: wire.name,\n // The backend only saves the ten known types (`validation.py:4-7`).\n type: wire.type as FormFieldType,\n required: wire.required,\n label: text(wire.label) ?? wire.name.replace(/_/g, ' '),\n options: wire.options?.map((o) => ({ label: o.label, value: o.value })) ?? [],\n };\n}\n","import type { RequestFn } from './types';\nimport type { WireInquiryCreate } from './wire/helpdesk';\n\n/** A contact-us message. */\nexport interface InquiryInput {\n subject: string;\n message: string;\n /** For guests; a logged-in customer is attributed automatically. */\n name?: string;\n email?: string;\n /** International format, e.g. \"+919876543210\" (the backend rejects other formats). */\n phone?: string;\n}\n\nexport interface HelpdeskApi {\n /**\n * Sends a contact-us inquiry; the business may email an acknowledgement to `email`.\n * Rejected values come back in the error's `fieldErrors` (e.g. `phone_number`).\n */\n createInquiry(input: InquiryInput): Promise<void>;\n}\n\n// The view reads the business from the header (500 without it). The customer token is sent\n// when present: the backend attributes the inquiry to them. ADR-017.\nconst CREATE = { business: 'required' } as const;\n\nexport function createHelpdeskApi(request: RequestFn): HelpdeskApi {\n return {\n async createInquiry(input) {\n const title = input.subject.trim();\n const description = input.message.trim();\n if (!title || !description) {\n throw new Error('helpdesk.createInquiry: subject and message are required.');\n }\n // Only these fields: the backend would also accept status, customer, assign_to… (S22).\n const json: WireInquiryCreate = { title, description };\n const name = input.name?.trim();\n const email = input.email?.trim();\n const phone = input.phone?.trim();\n if (name) json.name = name;\n if (email) json.email = email;\n if (phone) json.phone_number = phone;\n await request('POST', '/helpdesk/inquiry/web/create', { ...CREATE, json });\n },\n };\n}\n","import type { RequestFn } from './types';\nimport type { WireNewsletterAnswer, WireSubscribeBody, WireVerifyBody } from './wire/newsletter';\n\n/** Email newsletter sign-up (backend `/subscribers/`). */\nexport interface NewsletterApi {\n /**\n * Emails a one-time code to confirm the address (again, if one is pending). An address that\n * is already subscribed rejects with a 400 `GrowupsellApiError` (\"This email is already\n * subscribed.\").\n */\n subscribe(email: string): Promise<void>;\n /**\n * Confirms the address with the emailed code. A wrong code comes back in `fieldErrors.otp`;\n * an address that never signed up is a 500 from the backend today (C21).\n */\n verify(email: string, otp: string): Promise<void>;\n}\n\n// Public, and both views need the business (500 without it). ADR-017.\nconst PUBLIC = { anonymous: true, business: 'required' } as const;\n\nexport function createNewsletterApi(request: RequestFn): NewsletterApi {\n return {\n async subscribe(email) {\n // Only the email: the backend would also accept `subscribed_email` and others (S24).\n const json: WireSubscribeBody = { email: required(email, 'email') };\n await request<WireNewsletterAnswer>('POST', '/subscribers/create/email', {\n ...PUBLIC,\n json,\n });\n },\n async verify(email, otp) {\n const json: WireVerifyBody = { email: required(email, 'email'), otp: required(otp, 'otp') };\n await request<WireNewsletterAnswer>('PATCH', '/subscribers/email/verify', {\n ...PUBLIC,\n json,\n });\n },\n };\n}\n\nfunction required(value: string, name: string): string {\n const trimmed = value.trim();\n if (!trimmed) throw new Error(`newsletter: ${name} is required.`);\n return trimmed;\n}\n","import type { PushSubscriptionJson } from '../types/push';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireCreatePushAnswer,\n WireCreatePushBody,\n WirePushSubscription,\n WireUnsubscribePushAnswer,\n WireUnsubscribePushBody,\n WireVapidPublicKey,\n} from './wire/push';\n\n/**\n * Web push subscriptions (backend `/subscribers/push/…`). The app does the browser work\n * (permission, service worker, `pushManager.subscribe` with the VAPID key) and passes\n * `PushSubscription.toJSON()` in; the library never touches platform APIs.\n */\nexport interface PushApi {\n /**\n * The server's VAPID public key (base64url), for `pushManager.subscribe`'s\n * `applicationServerKey`. Null when the backend has none configured.\n */\n vapidPublicKey(): Promise<string | null>;\n /**\n * Registers the browser's subscription for the business. When a customer is logged in, the\n * backend links it to the customer (one subscription per customer: a new browser replaces the\n * old one). Safe to repeat: an existing subscription is updated. Rejects without a request\n * (`TypeError`) when `endpoint`, `keys.p256dh` or `keys.auth` is missing.\n */\n subscribe(subscription: PushSubscriptionJson): Promise<void>;\n /**\n * Switches the subscription off for the business. Resolves also when the backend had no such\n * subscription. Call it before `PushSubscription.unsubscribe()` in the browser. Rejects\n * without a request (`TypeError`) like `subscribe`.\n */\n unsubscribe(subscription: PushSubscriptionJson): Promise<void>;\n}\n\n// All three views are `AllowAny` (subscribers/views.py:105-139). Create and unsubscribe read\n// `request.business` (500 without the header, ADR-017). Only create reads the customer, to\n// link the subscription; the other two leave a possibly expired customer token out.\nconst KEY = { anonymous: true } as const;\nconst SUBSCRIBE = { business: 'required' } as const;\nconst UNSUBSCRIBE = { anonymous: true, business: 'required' } as const;\n\nexport function createPushApi(request: RequestFn): PushApi {\n return {\n async vapidPublicKey() {\n const wire = await request<WireVapidPublicKey>(\n 'GET',\n '/subscribers/push/vapid-public-key',\n KEY,\n );\n return text(wire.public_key);\n },\n\n async subscribe(subscription) {\n const json: WireCreatePushBody = { subscription: toWire(subscription, 'subscribe') };\n await request<WireCreatePushAnswer>('POST', '/subscribers/create/push', {\n ...SUBSCRIBE,\n json,\n });\n },\n\n async unsubscribe(subscription) {\n const json: WireUnsubscribePushBody = { subscription: toWire(subscription, 'unsubscribe') };\n await request<WireUnsubscribePushAnswer>('POST', '/subscribers/push/unsubscribe', {\n ...UNSUBSCRIBE,\n json,\n });\n },\n };\n}\n\n/** Only what the backend stores and matches on; the same checks it makes, before sending. */\nfunction toWire(subscription: PushSubscriptionJson, method: string): WirePushSubscription {\n const { endpoint, keys } = subscription;\n const missing = [\n endpoint ? null : 'endpoint',\n keys?.p256dh ? null : 'keys.p256dh',\n keys?.auth ? null : 'keys.auth',\n ].filter((name) => name !== null);\n if (missing.length > 0) {\n throw new TypeError(`push.${method}: the subscription needs ${missing.join(', ')}.`);\n }\n return { endpoint: endpoint!, keys: { p256dh: keys!.p256dh!, auth: keys!.auth! } };\n}\n","import type { LiveSupportWidget } from '../types/live-support';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type { WireLiveSupportWidget } from './wire/live-support';\n\nexport interface LiveSupportApi {\n /** The chat button to show, or null when the merchant turned it off or never set a number. */\n widget(): Promise<LiveSupportWidget | null>;\n}\n\n// Public; the view needs the business (500 without it). ADR-017.\nconst PUBLIC = { anonymous: true, business: 'required' } as const;\n\nexport function createLiveSupportApi(request: RequestFn): LiveSupportApi {\n return {\n async widget() {\n return toLiveSupportWidget(\n await request<WireLiveSupportWidget>(\n 'GET',\n '/website/live-support-widget/config/get',\n PUBLIC,\n ),\n );\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toLiveSupportWidget(wire: WireLiveSupportWidget): LiveSupportWidget | null {\n const number = text(wire.whatsapp_no)?.trim();\n if (!wire.is_active || !number) return null;\n return { channel: 'whatsapp', whatsappNumber: number };\n}\n","import type { Policy, PolicyType } from '../types/policy';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type { WireMoveBody, WireMoveDone, WirePolicy, WirePolicyWrite } from './wire/policies';\n\n/** What a merchant writes for one policy section. */\nexport interface PolicyInput {\n type: PolicyType;\n heading: string;\n /** HTML. */\n description?: string | null;\n}\n\n/** Move a row one place towards the top (`up`) or the bottom (`down`) of its list. */\nexport type MoveDirection = 'up' | 'down';\n\nexport interface PoliciesApi {\n /** Every policy section, or one type's, in display order. Public. */\n list(options?: { type?: PolicyType }): Promise<Policy[]>;\n /** Merchant: adds a section at the end of its type. */\n create(input: PolicyInput): Promise<Policy>;\n /**\n * Merchant: adds several sections at once, in order (e.g. a default policy set). They are\n * numbered after the last section of the first input's type. An empty list sends nothing.\n */\n createMany(inputs: readonly PolicyInput[]): Promise<Policy[]>;\n /** Merchant: changes only the given fields. */\n update(id: number, changes: Partial<PolicyInput>): Promise<Policy>;\n /**\n * Merchant: swaps the section with its neighbour of the same type. Rejects with a 400\n * `GrowupsellApiError` when it is already first (`up`) or last (`down`).\n */\n move(id: number, direction: MoveDirection): Promise<void>;\n /** Merchant: deletes the section for good. */\n remove(id: number): Promise<void>;\n}\n\nconst TYPES: Record<WirePolicy['type'], PolicyType> = {\n privacy_policy: 'privacy',\n terms_of_use: 'terms-of-use',\n cancellations_refunds_policy: 'cancellation-refund',\n shipping_policy: 'shipping',\n warranty_policy: 'warranty',\n};\nconst WIRE_TYPES = Object.fromEntries(\n Object.entries(TYPES).map(([wire, type]) => [type, wire]),\n) as Record<PolicyType, WirePolicy['type']>;\n\n// The list is public and reads the business from the header (500 without it). ADR-017.\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n// Writes need the merchant token. They leave the customer token out: the backend rejects any\n// request with an expired customer token, and that 401 would be reported as a merchant logout.\nconst MERCHANT = { merchant: true, anonymous: true } as const;\n\nexport function createPoliciesApi(request: RequestFn): PoliciesApi {\n return {\n async list(options = {}) {\n const wire = await request<WirePolicy[]>('GET', '/policy_and_terms/list', {\n ...PUBLIC,\n query: { type: options.type && WIRE_TYPES[options.type] },\n });\n return wire.map(toPolicy).filter((p): p is Policy => p !== null);\n },\n async create(input) {\n // The view takes the business from the header (`request.business`): 500 without it.\n const wire = await request<WirePolicy>('POST', '/policy_and_terms/create', {\n ...MERCHANT,\n business: 'required',\n json: toWrite(input),\n });\n return required(wire);\n },\n async createMany(inputs) {\n if (inputs.length === 0) return [];\n // This one takes the business from the merchant's account, so the header is optional.\n const wire = await request<WirePolicy[]>('POST', '/policy_and_terms/bulk/create', {\n ...MERCHANT,\n json: inputs.map(toWrite),\n });\n return wire.map(required);\n },\n async update(id, changes) {\n const wire = await request<WirePolicy>('PUT', `/policy_and_terms/update/${id}`, {\n ...MERCHANT,\n json: toWrite(changes),\n });\n return required(wire);\n },\n async move(id, direction) {\n const body: WireMoveBody = { direction };\n await request<WireMoveDone>('PUT', `/policy_and_terms/update/${id}`, {\n ...MERCHANT,\n json: body,\n });\n },\n async remove(id) {\n await request('DELETE', `/policy_and_terms/delete/${id}`, MERCHANT);\n },\n };\n}\n\nfunction toWrite(input: Partial<PolicyInput>): Partial<WirePolicyWrite> {\n const body: Partial<WirePolicyWrite> = {};\n if (input.type !== undefined) body.type = WIRE_TYPES[input.type];\n if (input.heading !== undefined) body.heading = input.heading;\n if (input.description !== undefined) body.description = input.description;\n return body;\n}\n\n/** A write answers with a type we sent, so it is always known. */\nconst required = (wire: WirePolicy): Policy => toPolicy(wire)!;\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\n/** Null for a type this version does not know yet (the list then leaves it out). */\nexport function toPolicy(wire: WirePolicy): Policy | null {\n const type = TYPES[wire.type];\n if (!type) return null;\n return {\n id: wire.id,\n type,\n heading: wire.heading,\n description: text(wire.description),\n displayOrder: wire.display_order,\n };\n}\n","import type {\n ProductBlock,\n ProductSection,\n ProductSectionItem,\n ProductSectionItemTarget,\n} from '../types/productPage';\nimport type { RequestFn } from './types';\nimport type {\n WireProductBlock,\n WireProductSection,\n WireProductSectionItem,\n} from './wire/productPage';\n\n/**\n * Who sees a new or changed section item:\n * - `'all'`: every variant.\n * - `{ variantIds }`: one SKU, named by its variant options (one per variant type, e.g.\n * `[128 GB, Blue]`). The backend answers 400 if they are not a whole SKU.\n * - `{ variantId }`: every SKU with this variant option.\n */\nexport type ProductSectionItemTargetInput =\n 'all' | { variantIds: readonly number[] } | { variantId: number };\n\nexport interface ProductPageApi {\n /** The product's sections with their items. Public. */\n sections(productId: number): Promise<ProductSection[]>;\n /** The product's slug-keyed blocks (e.g. `hero`, `showcase`), in display order. Public. */\n blocks(productId: number, options?: { slug?: string }): Promise<ProductBlock[]>;\n\n // Merchant actions: they need `merchantToken` (and `businessId`) from credentials().\n\n /** Adds an empty section to the product. */\n createSection(input: { productId: number; title: string }): Promise<ProductSection>;\n /** Deletes a section and its items. */\n deleteSection(id: number): Promise<void>;\n /** Adds an item at the end of a section. `target` defaults to `'all'`. */\n addSectionItem(input: {\n sectionId: number;\n data: unknown;\n target?: ProductSectionItemTargetInput;\n }): Promise<ProductSectionItem>;\n /**\n * Changes an item's data and/or target (left out: unchanged). `sectionId` is the item's\n * section: the backend requires it on every update.\n */\n updateSectionItem(\n id: number,\n input: { sectionId: number; data?: unknown; target?: ProductSectionItemTargetInput },\n ): Promise<ProductSectionItem>;\n /**\n * Swaps the item with its neighbour. Rejects with a 400 when it is already first (`up`) or\n * last (`down`).\n */\n moveSectionItem(id: number, direction: 'up' | 'down'): Promise<void>;\n deleteSectionItem(id: number): Promise<void>;\n /** Adds a block. See `ProductBlock` for the checks the backend makes on `hero`/`showcase`. */\n createBlock(input: { productId: number; slug: string; data: unknown }): Promise<ProductBlock>;\n updateBlock(id: number, input: { slug?: string; data?: unknown }): Promise<ProductBlock>;\n deleteBlock(id: number): Promise<void>;\n}\n\n// Reads are public but resolve the product's business from the `business` header (500\n// without it); `anonymous` so an expired customer login never breaks the product page.\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n// Writes: IsAuthenticated + IsManager with the merchant token. The views scope the row to\n// `request.business` (500 without the header), and the token is checked against that header.\n// No customer token: the backend would answer a stale one with 401 before the merchant check.\nconst MERCHANT = { merchant: true, business: 'required', anonymous: true } as const;\n\n/**\n * The fields that set an item's target. The serializer resolves `selected_variants` to a SKU\n * and clears `variant`; a `variant` clears the SKU. Sending both for `'all'` clears both.\n */\nfunction targetFields(target: ProductSectionItemTargetInput | undefined) {\n if (target === undefined) return {};\n if (target === 'all') return { selected_variants: [], variant: null };\n if ('variantId' in target) return { variant: target.variantId };\n return { selected_variants: target.variantIds, variant: null };\n}\n\nexport function createProductPageApi(request: RequestFn): ProductPageApi {\n /** Create/update responses carry the SKU id only; the variant ids are the ones sent. */\n const sentItem = (wire: WireProductSectionItem, target?: ProductSectionItemTargetInput) => {\n const item = toProductSectionItem(wire);\n if (wire.sku != null && typeof target === 'object' && 'variantIds' in target) {\n item.target = { skuId: wire.sku, variantIds: [...target.variantIds] };\n }\n return item;\n };\n\n return {\n async sections(productId) {\n const wire = await request<WireProductSection[]>(\n 'GET',\n `/product/detail/list/${productId}`,\n PUBLIC,\n );\n return wire.map(toProductSection);\n },\n\n async blocks(productId, options = {}) {\n const wire = await request<WireProductBlock[]>('GET', `/product/content/list/${productId}`, {\n ...PUBLIC,\n query: { slug: options.slug },\n });\n return wire.map(toProductBlock);\n },\n\n async createSection({ productId, title }) {\n return toProductSection(\n await request<WireProductSection>('POST', '/product/detail/create', {\n ...MERCHANT,\n json: { product: productId, title },\n }),\n );\n },\n\n async deleteSection(id) {\n await request('DELETE', `/product/detail/delete/${id}`, MERCHANT);\n },\n\n async addSectionItem({ sectionId, data, target }) {\n const wire = await request<WireProductSectionItem>('POST', '/product/detail/content/create', {\n ...MERCHANT,\n json: { product_detail: sectionId, data, ...targetFields(target) },\n });\n return sentItem(wire, target);\n },\n\n async updateSectionItem(id, { sectionId, data, target }) {\n const wire = await request<WireProductSectionItem>(\n 'PATCH',\n `/product/detail/content/update/${id}`,\n {\n ...MERCHANT,\n json: {\n product_detail: sectionId,\n ...(data === undefined ? {} : { data }),\n ...targetFields(target),\n },\n },\n );\n return sentItem(wire, target);\n },\n\n async moveSectionItem(id, direction) {\n // Answers { status: 'success' }. The storefront also sent the item's data and section;\n // the backend ignores both when `direction` is set.\n await request('PATCH', `/product/detail/content/update/${id}`, {\n ...MERCHANT,\n json: { direction },\n });\n },\n\n async deleteSectionItem(id) {\n await request('DELETE', `/product/detail/content/delete/${id}`, MERCHANT);\n },\n\n async createBlock({ productId, slug, data }) {\n return toProductBlock(\n await request<WireProductBlock>('POST', '/product/content/create', {\n ...MERCHANT,\n json: { product: productId, slug, data },\n }),\n );\n },\n\n async updateBlock(id, { slug, data }) {\n return toProductBlock(\n await request<WireProductBlock>('PATCH', `/product/content/update/${id}`, {\n ...MERCHANT,\n json: { slug, data },\n }),\n );\n },\n\n async deleteBlock(id) {\n await request('DELETE', `/product/content/delete/${id}`, MERCHANT);\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nfunction toTarget(wire: WireProductSectionItem): ProductSectionItemTarget {\n if (wire.sku != null) {\n const variants = wire.selected_variants ?? [];\n return { skuId: wire.sku, variantIds: variants.length ? variants.map((v) => v.id) : null };\n }\n if (wire.variant != null) return { variantId: wire.variant };\n return 'all';\n}\n\nexport function toProductSectionItem(wire: WireProductSectionItem): ProductSectionItem {\n return {\n id: wire.id,\n sectionId: wire.product_detail,\n data: wire.data ?? null,\n order: wire.display_order,\n target: toTarget(wire),\n };\n}\n\nexport function toProductSection(wire: WireProductSection): ProductSection {\n return {\n id: wire.id,\n productId: wire.product,\n title: wire.title,\n // Already ordered by the backend; sorted again so the order never depends on it.\n items: [...wire.content]\n .sort((a, b) => a.display_order - b.display_order)\n .map(toProductSectionItem),\n };\n}\n\nexport function toProductBlock(wire: WireProductBlock): ProductBlock {\n return {\n id: wire.id,\n productId: wire.product,\n slug: wire.slug,\n data: wire.data ?? null,\n order: wire.display_order,\n };\n}\n","import type {\n Page,\n ProductDetail,\n ProductFilterConfig,\n ProductImage,\n ProductListItem,\n ProductOverview,\n ProductSearchOptions,\n ProductSku,\n ProductSort,\n ProductSpecificationGroup,\n SearchSuggestion,\n VariantGroup,\n} from '../types/product';\nimport { text, amount } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireProductDetail,\n WireProductFilterConfig,\n WireProductImage,\n WireProductSearchSku,\n WireProductSku,\n WireProductV2,\n WireSearchSuggestion,\n WireVariantGroup,\n} from './wire/products';\nimport type { WirePage } from './wire/shared';\n\nexport type { ProductSearchOptions, ProductSort };\n\nexport interface ProductsApi {\n /**\n * The product listing: one item per sellable SKU, only products available on the website.\n * Needs a guest session: without one the backend also returns drafts and hidden products.\n */\n search(options?: ProductSearchOptions): Promise<Page<ProductListItem>>;\n /** Products (not SKUs), e.g. for home-page sliders. Only available products. */\n list(options?: {\n ids?: readonly number[];\n categoryIds?: readonly number[];\n limit?: number;\n offset?: number;\n }): Promise<Page<ProductOverview>>;\n detail(id: number): Promise<ProductDetail>;\n /** Price range and specification filters, for the business or one category. */\n filterConfig(options?: { categoryId?: number }): Promise<ProductFilterConfig>;\n /** Variant groups available in these categories (and their sub-categories), for filters. */\n variantFilters(categoryIds: readonly number[]): Promise<VariantGroup[]>;\n /** Quick search suggestions (products and categories) for a search box. */\n suggestions(query: string): Promise<SearchSuggestion[]>;\n}\n\nconst DEFAULT_LIMIT = 20;\nconst SORT: Record<ProductSort, string> = {\n 'price-low-to-high': 'low_to_high',\n 'price-high-to-low': 'high_to_low',\n newest: 'newest_first',\n popularity: 'popularity',\n category: 'category',\n};\n// Catalog endpoints are public and resolve the business from the `business` header (ADR-017).\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n\nexport function createProductsApi(request: RequestFn): ProductsApi {\n return {\n async search(options = {}) {\n const limit = options.limit ?? DEFAULT_LIMIT;\n const offset = options.offset ?? 0;\n const page = await request<WirePage<WireProductSearchSku>>(\n 'GET',\n '/product/sku/list/search',\n {\n ...PUBLIC,\n session: 'required',\n query: {\n status: 'available',\n search: options.search?.trim(),\n category_ids: options.categoryIds,\n brand_ids: options.brandIds,\n variants: options.variantLabels,\n specifications: options.specifications?.length\n ? JSON.stringify(options.specifications)\n : undefined,\n min_price: options.minPrice,\n max_price: options.maxPrice,\n min_discount: options.minDiscountPercent,\n min_rating: options.minRating,\n sort_by: options.sortBy ? SORT[options.sortBy] : undefined,\n limit,\n offset,\n },\n },\n );\n return { items: page.results.map(toProductListItem), total: page.count, offset, limit };\n },\n\n async list(options = {}) {\n const limit = options.limit ?? DEFAULT_LIMIT;\n const offset = options.offset ?? 0;\n const page = await request<WirePage<WireProductV2>>('GET', '/product/base/list', {\n ...PUBLIC,\n // The backend does not hide drafts here by itself; the old storefront never asked it to.\n query: {\n status: 'available',\n ids: options.ids,\n category_ids: options.categoryIds,\n limit,\n offset,\n },\n });\n return { items: page.results.map(toProductOverview), total: page.count, offset, limit };\n },\n\n async detail(id) {\n return toProductDetail(\n await request<WireProductDetail>('GET', `/product/details/${id}`, PUBLIC),\n );\n },\n\n async filterConfig(options = {}) {\n const wire = await request<WireProductFilterConfig>('GET', '/product/filter/config', {\n ...PUBLIC,\n query: { category: options.categoryId },\n });\n return {\n price: { min: wire.price.min, max: wire.price.max },\n specifications: wire.specifications.map((s) => ({\n id: s.id,\n name: s.name,\n type: s.data_type,\n options: s.options,\n })),\n };\n },\n\n async variantFilters(categoryIds) {\n // The backend answers 400 without category ids.\n if (categoryIds.length === 0) return [];\n const wire = await request<WireVariantGroup[]>('GET', '/product/category/filter/variant', {\n ...PUBLIC,\n query: { category_ids: categoryIds },\n });\n return wire.map(toVariantGroup);\n },\n\n async suggestions(query) {\n // The old storefront called the API for an empty search too.\n const word = query.trim();\n if (!word) return [];\n const wire = await request<WireSearchSuggestion[]>(\n 'GET',\n `/product/search/${encodeURIComponent(word)}`,\n PUBLIC,\n );\n return wire.map((s) =>\n s.type === 'product'\n ? {\n type: 'product' as const,\n id: s.id,\n name: s.name,\n categoryName: text(s.category),\n image: text(s.image),\n }\n : { type: 'category' as const, id: s.id, name: s.name },\n );\n },\n };\n}\n\n/** An MRP of 0 means \"not set\". */\nconst mrpOf = (value: string | number | null | undefined): number | null => {\n const n = amount(value);\n return n && n > 0 ? n : null;\n};\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toVariantGroup(wire: WireVariantGroup): VariantGroup {\n return {\n id: wire.variant_type.id,\n name: wire.variant_type.type,\n options: wire.variants\n .filter((v) => !v.deleted)\n .map((v) => ({ id: v.id, label: v.label, available: v.sku_available ?? true })),\n };\n}\n\nfunction toSku(wire: WireProductSku): ProductSku {\n return {\n id: wire.id,\n code: wire.sku,\n slug: wire.url_slug,\n price: amount(wire.selling_price) ?? 0,\n mrp: mrpOf(wire.mrp),\n stockQty: wire.stock_qty ?? 0,\n active: wire.is_active !== false,\n variantIds: wire.selected_variants ?? [],\n };\n}\n\nfunction toImage(wire: WireProductImage): ProductImage {\n return {\n id: wire.id,\n url: wire.photo,\n originalUrl: text(wire.original_photo),\n variantId: wire.variant ?? null,\n skuId: wire.sku ?? null,\n videoUrl: text(wire.link)?.trim() ?? null,\n order: wire.display_order,\n };\n}\n\nconst liveSkus = (skus: WireProductSku[]) => skus.filter((s) => !s.deleted && !s.invalid);\nconst liveImages = (images: WireProductImage[]) =>\n images.filter((i) => !i.deleted).sort((a, b) => a.display_order - b.display_order);\n\nexport function toProductListItem(wire: WireProductSearchSku): ProductListItem {\n const tax = amount(wire.tax);\n return {\n skuId: wire.id,\n productId: wire.product,\n name: wire.name,\n slug: wire.url_slug,\n skuCode: wire.sku,\n photos: wire.photo,\n price: amount(wire.selling_price) ?? 0,\n mrp: mrpOf(wire.mrp),\n stockQty: wire.stock_qty ?? 0,\n taxPercent: tax,\n unit: text(wire.unit),\n variantGroups: (wire.variant ?? []).map(toVariantGroup),\n selectedVariantIds: wire.selected_variants,\n fulfillmentMode: wire.fulfillment_mode,\n hasDigitalDelivery: wire.has_digital_delivery,\n advanceAmount: amount(wire.advance_amount),\n };\n}\n\nfunction toSpecifications(wire: WireProductDetail['specification']): ProductSpecificationGroup[] {\n return Object.entries(wire ?? {})\n .map(([name, items]) => ({\n name: text(name),\n items: items\n .filter((i) => !i.deleted && i.key)\n .map((i) => ({\n key: i.key!.name,\n value: i.value,\n appliesTo: i.sku\n ? { type: 'sku' as const, skuId: i.sku.id }\n : i.variant\n ? { type: 'variant' as const, variantId: i.variant.id }\n : { type: 'all' as const },\n })),\n }))\n .filter((g) => g.items.length > 0);\n}\n\nexport function toProductDetail(wire: WireProductDetail): ProductDetail {\n const policies = wire.product_policies;\n return {\n id: wire.id,\n name: wire.name,\n slug: wire.url_slug,\n description: text(wire.description),\n descriptionFormat: text(wire.description_editor_type),\n categoryId: wire.category ?? null,\n categoryName: text(wire.category_name),\n brandId: wire.brand ?? null,\n taxPercent: amount(wire.tax_percent),\n rating: wire.rating ?? 0,\n reviewCount: wire.total_review ?? 0,\n hasVariants: wire.has_variant ?? (wire.variant ?? []).length > 0,\n images: liveImages(wire.images).map(toImage),\n variantGroups: (wire.variant ?? []).map(toVariantGroup),\n skus: liveSkus(wire.sku).map(toSku),\n specifications: toSpecifications(wire.specification),\n policies: policies\n ? {\n returnDays: policies.return_days,\n replacementDays: policies.replacement_days,\n exchangeDays: policies.exchange_days,\n exchangeEnabled: policies.exchange_enabled,\n warrantyMonths: policies.warranty_months,\n guaranteeMonths: policies.guarantee_months,\n }\n : null,\n availableForSubscription: wire.available_for_subscription ?? false,\n hasDigitalDelivery: wire.has_digital_delivery ?? false,\n fulfillmentMode: wire.fulfillment_mode ?? 'none',\n advanceAmount: amount(wire.advance_amount),\n };\n}\n\nfunction toProductOverview(wire: WireProductV2): ProductOverview {\n return {\n id: wire.id,\n name: wire.name,\n slug: wire.url_slug,\n categoryName: text(wire.category_name),\n images: liveImages(wire.images).map(toImage),\n variantGroups: (wire.variant ?? []).map(toVariantGroup),\n skus: liveSkus(wire.sku).map(toSku),\n priceFrom: amount(wire.starting_from),\n unit: text(wire.unit),\n };\n}\n","import type { Page } from '../types/product';\nimport type { GiftCard, Offer, PromoCode, RewardPointSettings } from '../types/promotions';\nimport { amount, text } from './convert';\nimport { GrowupsellApiError } from './errors';\nimport type { RequestFn } from './types';\nimport type { WirePromoCode } from './wire/cart';\nimport type {\n WireEligibleOffer,\n WireGiftCard,\n WireOffer,\n WireRewardPointSettings,\n} from './wire/promotions';\nimport type { WirePage } from './wire/shared';\n\nexport interface PromotionsApi {\n /**\n * One page of the business's offers. Includes expired and inactive offers, with their coupon\n * codes: for the merchant's theme editor, not for shoppers (use `eligibleOffers()`).\n */\n offers(options?: { limit?: number; offset?: number }): Promise<Page<Offer>>;\n /**\n * The offers the shopper's cart qualifies for now. Empty for a cash-on-delivery cart (the\n * backend only offers them on `delivery` carts). Apply one with `cart.applyOffer(id)`.\n */\n eligibleOffers(): Promise<Offer[]>;\n /**\n * Looks a promo code up (trimmed, upper-cased: codes are stored upper-case). `null` for an\n * unknown or blank code. Check `status` before applying it with `cart.applyPromoCode(id)`.\n */\n promoCode(code: string): Promise<PromoCode | null>;\n /**\n * Checks a gift card's code and PIN. Rejects with a 400 and a field error (`code` or `pin`)\n * when the card is unknown, the PIN is wrong, or the card is used up or expired. The PIN is\n * not kept in the result; pass the card's `id` to checkout.\n */\n validateGiftCard(input: { code: string; pin: string }): Promise<GiftCard>;\n /** The business's reward point configuration. */\n rewardPointSettings(): Promise<RewardPointSettings>;\n}\n\nconst DEFAULT_LIMIT = 20;\n\n// Public, business-scoped: no login needed, so an expired customer token must not break them.\nconst PUBLIC_BUSINESS = { anonymous: true, business: 'required' } as const;\n// Cart-related lookups: a logged-in customer or a guest session, in the business.\nconst SHOPPER = { business: 'required', customerOrSession: 'required' } as const;\n\nexport function createPromotionsApi(request: RequestFn): PromotionsApi {\n return {\n async offers(options = {}) {\n const limit = options.limit ?? DEFAULT_LIMIT;\n const offset = options.offset ?? 0;\n const page = await request<WirePage<WireOffer>>('GET', '/offer/list', {\n ...PUBLIC_BUSINESS,\n query: { limit, offset },\n });\n return { items: page.results.map(toOffer), total: page.count, offset, limit };\n },\n\n async eligibleOffers() {\n const wire = await request<WireEligibleOffer[]>('GET', '/offer/eligibility/list', SHOPPER);\n return wire.map(toOffer);\n },\n\n async promoCode(code) {\n const normalized = code.trim().toUpperCase();\n if (!normalized) return null;\n try {\n const wire = await request<WirePromoCode>('GET', '/promocode/get', {\n ...SHOPPER,\n query: { code: normalized },\n });\n return toPromoCode(wire);\n } catch (error) {\n // \"Not found\" is an expected answer to a lookup (ADR-023). Only the view's JSON 404:\n // a forgotten guest session is an HTML 404 and must reach the session store.\n if (isNotFoundJson(error)) return null;\n throw error;\n }\n },\n\n async validateGiftCard({ code, pin }) {\n // Without the business header the backend looks the code up across every business.\n const wire = await request<WireGiftCard>('POST', '/giftcard/validate', {\n business: 'required',\n json: { code: code.trim(), pin: pin.trim() },\n });\n return toGiftCard(wire);\n },\n\n async rewardPointSettings() {\n return toRewardPointSettings(\n await request<WireRewardPointSettings>(\n 'GET',\n '/reward_points/business/setting/get',\n PUBLIC_BUSINESS,\n ),\n );\n },\n };\n}\n\nfunction isNotFoundJson(error: unknown): boolean {\n return (\n error instanceof GrowupsellApiError &&\n error.status === 404 &&\n typeof error.body === 'object' &&\n error.body !== null\n );\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toOffer(wire: WireOffer | WireEligibleOffer): Offer {\n return {\n id: wire.id,\n name: wire.name,\n description: text(wire.description),\n image: text(wire.image),\n type: wire.type ?? 'percentage',\n percentOff: amount(wire.percentage_of) ?? 0,\n amountOff: amount(wire.discount_upto_price) ?? 0,\n minOrderAmount: amount(wire.min_order_amount) ?? 0,\n startsAt: wire.start_date ?? '',\n endsAt: wire.end_date ?? '',\n couponCode: text(wire.coupon_code),\n scope: wire.only_for ?? 'order',\n isActive: wire.is_active ?? false,\n };\n}\n\n/** Drops the names of the people it was issued to and redeemed by (backend issue S45). */\nexport function toPromoCode(wire: WirePromoCode): PromoCode {\n return {\n id: wire.id,\n code: wire.code ?? '',\n description: text(wire.description),\n type: wire.type ?? 'percentage',\n value: amount(wire.value) ?? 0,\n expiresAt: wire.expire_date,\n status: wire.status,\n };\n}\n\n/** Drops the PIN (sent unmasked) and the holder's details (backend issue S44). */\nexport function toGiftCard(wire: WireGiftCard): GiftCard {\n return {\n id: wire.id,\n code: wire.code,\n amount: amount(wire.amount) ?? 0,\n usedAmount: amount(wire.used_amount) ?? 0,\n issuedAt: wire.created_at,\n };\n}\n\nexport function toRewardPointSettings(wire: WireRewardPointSettings): RewardPointSettings {\n return {\n // Points work on orders only when both switches are on.\n enabled: !!wire.is_active && !!wire.is_active_order_reward,\n pointsPerCurrencyUnit: amount(wire.order_credit_multiplier) ?? 0,\n currencyPerPoint: amount(wire.order_debit_multiplier) ?? 0,\n signupPoints: amount(wire.signup_points) ?? 0,\n };\n}\n","import type { FormDataLike } from './types';\n\n/**\n * A file to upload, passed through to the platform's `FormData` untouched: a `File` or `Blob`\n * on the web, `{ uri, name, type }` in React Native.\n */\nexport type UploadFile = unknown;\n\n/** What this module needs from the runtime; read like `fetch` in client.ts (no DOM types). */\ninterface Runtime {\n FormData?: new () => FormDataLike;\n}\nconst runtime = globalThis as unknown as Runtime;\n\n/**\n * Builds a multipart body with the platform's `FormData` (ADR-023: the library builds upload\n * bodies itself). `undefined` fields and files are skipped; numbers become strings. A file's\n * `fileName` is passed only when given: browsers reject a file name for a non-`Blob` value.\n * Throws when the runtime has no `FormData`, naming `caller` in the message.\n */\nexport function multipart(\n fields: Record<string, string | number | undefined>,\n files: Record<string, { file: UploadFile; fileName?: string } | undefined>,\n caller = 'This upload',\n): FormDataLike {\n if (!runtime.FormData) {\n throw new Error(`${caller}: sending a file needs FormData, which this runtime lacks.`);\n }\n const form = new runtime.FormData();\n for (const [name, value] of Object.entries(fields)) {\n if (value !== undefined) form.append(name, String(value));\n }\n for (const [name, entry] of Object.entries(files)) {\n if (!entry) continue;\n if (entry.fileName === undefined) form.append(name, entry.file);\n else form.append(name, entry.file, entry.fileName);\n }\n return form;\n}\n","import type { Page } from '../types/product';\nimport type { Review, ReviewEligibility, ReviewListItem, ReviewSummary } from '../types/reviews';\nimport { amount, text } from './convert';\nimport { multipart, type UploadFile } from './multipart';\nimport type { RequestFn } from './types';\nimport type {\n WireCanIReview,\n WireReview,\n WireReviewConclusion,\n WireReviewListItem,\n} from './wire/reviews';\nimport type { WirePage } from './wire/shared';\n\n/**\n * A photo to attach: a `File` or `Blob` on the web, `{ uri, name, type }` in React Native.\n * Sent as multipart form data with the platform's `FormData`.\n */\nexport type ReviewPhoto = UploadFile;\n\nexport interface CreateReviewInput {\n /**\n * The logged-in customer's id. The backend takes the author from the request body, not from\n * the login, so it must be sent.\n */\n customerId: number;\n productId: number;\n /** From `eligibility()`: the ordered item the review is for. */\n orderProductId?: number;\n title: string;\n message?: string;\n /** 1 to 5, in steps of 0.5. */\n rating: number;\n photo?: ReviewPhoto;\n}\n\nexport interface UpdateReviewInput {\n title?: string;\n message?: string;\n rating?: number;\n /** Replaces the photo. */\n photo?: ReviewPhoto;\n}\n\nexport interface ReviewsApi {\n /** A product's published reviews (all of them: the backend does not page this list). */\n forProduct(productId: number): Promise<ReviewListItem[]>;\n /** The business's reviews, newest first, e.g. for a home-page slider. */\n latest(options?: {\n /** Only ratings above this, e.g. 3 for 3.5 and up. */\n minRating?: number;\n /** Matches the title, the message and the customer's name. */\n search?: string;\n /** Default 20. */\n limit?: number;\n offset?: number;\n }): Promise<Page<ReviewListItem>>;\n /** Review count, average rating and the number of reviews per star. */\n summary(productId: number): Promise<ReviewSummary>;\n /**\n * Whether the logged-in customer may review a product: they ordered it and have not reviewed\n * it yet. The backend does not enforce this on `create()`: check it first.\n */\n eligibility(productId: number): Promise<ReviewEligibility>;\n create(input: CreateReviewInput): Promise<Review>;\n /** Changes the customer's own review; only the given fields change. */\n update(reviewId: number, changes: UpdateReviewInput): Promise<Review>;\n /** Deletes the customer's own review. */\n remove(reviewId: number): Promise<void>;\n}\n\nconst DEFAULT_LIMIT = 20;\n// Review lists are public. Only the business-wide list and the summary resolve the business\n// from the `business` header (both answer 500 without it).\nconst PUBLIC = { anonymous: true } as const;\nconst PUBLIC_BUSINESS = { anonymous: true, business: 'required' } as const;\nconst CUSTOMER = { customer: 'required' } as const;\n\nexport function createReviewsApi(request: RequestFn): ReviewsApi {\n /** JSON, or multipart form data when a photo is attached. */\n function body(fields: Record<string, string | number | undefined>, photo: ReviewPhoto) {\n if (photo === undefined) {\n return {\n json: Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== undefined)),\n };\n }\n return { formData: multipart(fields, { photo: { file: photo } }, 'Review photo') };\n }\n\n return {\n async forProduct(productId) {\n const wire = await request<WireReviewListItem[]>(\n 'GET',\n `/product/review/list/${productId}`,\n PUBLIC,\n );\n return wire.map(toReviewListItem);\n },\n\n async latest(options = {}) {\n const limit = options.limit ?? DEFAULT_LIMIT;\n const offset = options.offset ?? 0;\n // Always send `limit`: without it the backend skips pagination and returns every review.\n const page = await request<WirePage<WireReviewListItem>>('GET', '/product/review/list', {\n ...PUBLIC_BUSINESS,\n query: {\n rating_gt: options.minRating,\n search: options.search?.trim() || undefined,\n limit,\n offset,\n },\n });\n return { items: page.results.map(toReviewListItem), total: page.count, offset, limit };\n },\n\n async summary(productId) {\n return toReviewSummary(\n await request<WireReviewConclusion>(\n 'GET',\n `/product/review/conclusion/${productId}`,\n PUBLIC_BUSINESS,\n ),\n );\n },\n\n async eligibility(productId) {\n const wire = await request<WireCanIReview>(\n 'GET',\n `/product/can/i/review/${productId}`,\n CUSTOMER,\n );\n return wire.can_i_review\n ? { canReview: true, orderProductId: wire.order_product }\n : { canReview: false, orderProductId: null };\n },\n\n async create(input) {\n const wire = await request<WireReview>('POST', '/product/review/create', {\n ...CUSTOMER,\n ...body(\n {\n customer: input.customerId,\n product: input.productId,\n order_product: input.orderProductId,\n title: input.title,\n message: input.message,\n ratting: input.rating,\n },\n input.photo,\n ),\n });\n return toReview(wire);\n },\n\n async update(reviewId, changes) {\n const wire = await request<WireReview>('PATCH', `/product/review/update/${reviewId}`, {\n ...CUSTOMER,\n ...body(\n { title: changes.title, message: changes.message, ratting: changes.rating },\n changes.photo,\n ),\n });\n return toReview(wire);\n },\n\n async remove(reviewId) {\n // The view filters by `request.business`, so it needs the header (500 without it).\n await request('DELETE', `/product/review/customer/delete/${reviewId}`, {\n ...CUSTOMER,\n business: 'required',\n });\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nfunction toReview(wire: WireReview): Review {\n return {\n id: wire.id,\n productId: wire.product,\n customerId: wire.customer,\n title: wire.title,\n message: text(wire.message),\n photo: text(wire.photo),\n rating: amount(wire.ratting),\n createdAt: wire.created_at,\n };\n}\n\nexport function toReviewListItem(wire: WireReviewListItem): ReviewListItem {\n const reply = wire.reply;\n return {\n ...toReview(wire),\n productName: wire.product_name,\n customerName: text(wire.customer_name),\n customerPhoto: text(wire.customer_photo),\n // The backend also sends the replying staff member's email and phone; not passed on.\n reply: reply\n ? {\n id: reply.id,\n message: reply.message,\n authorName: text(reply.user_name),\n authorPhoto: text(reply.user_photo),\n }\n : null,\n };\n}\n\nexport function toReviewSummary(wire: WireReviewConclusion): ReviewSummary {\n // A long Decimal string such as \"4.333333333333333333\", or 0. Rounded like the product's\n // own `rating` (one decimal).\n const average = amount(wire.average_rating) ?? 0;\n return {\n reviewCount: wire.total_reviews,\n averageRating: Math.round(average * 10) / 10,\n starCounts: {\n 1: wire.total_one_star_reviews,\n 2: wire.total_two_star_reviews,\n 3: wire.total_three_star_reviews,\n 4: wire.total_four_star_reviews,\n 5: wire.total_five_star_reviews,\n },\n };\n}\n","import type { WishlistItem } from '../types/wishlist';\nimport { amount, text } from './convert';\nimport type { RequestFn } from './types';\nimport type { WireWishlistCreated, WireWishlistItem } from './wire/wishlist';\n\nexport interface WishlistApi {\n /** The logged-in customer's saved SKUs. */\n list(): Promise<WishlistItem[]>;\n /**\n * Saves a SKU (not a product: pick the variant first). Rejects with a 400 when the SKU is\n * already saved.\n */\n add(skuId: number): Promise<{ id: number; productId: number }>;\n /** Removes an entry by its wishlist id (`WishlistItem.id`), not by SKU. */\n remove(wishlistId: number): Promise<void>;\n}\n\n// Every wishlist endpoint is for a logged-in customer only (`IsCustomer`); the customer token\n// identifies the customer, so the business header is not needed.\nconst CUSTOMER = { customer: 'required' } as const;\n\nexport function createWishlistApi(request: RequestFn): WishlistApi {\n return {\n async list() {\n const wire = await request<WireWishlistItem[]>('GET', '/product/wishlist/list/', CUSTOMER);\n return wire.map(toWishlistItem);\n },\n\n async add(skuId) {\n const wire = await request<WireWishlistCreated>('POST', '/product/wishlist/create', {\n ...CUSTOMER,\n json: { sku: skuId },\n });\n return { id: wire.id, productId: wire.product };\n },\n\n async remove(wishlistId) {\n await request('DELETE', `/product/wishlist/delete/${wishlistId}`, CUSTOMER);\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toWishlistItem(wire: WireWishlistItem): WishlistItem {\n const { product, sku } = wire;\n const mrp = sku ? amount(sku.mrp) : null;\n return {\n id: wire.id,\n name: wire.label,\n photo: text(wire.photo),\n productId: product.id,\n productSlug: product.url_slug,\n sku: sku\n ? {\n id: sku.id,\n code: sku.sku,\n slug: sku.url_slug,\n price: amount(sku.selling_price) ?? 0,\n // An MRP of 0 means \"not set\".\n mrp: mrp && mrp > 0 ? mrp : null,\n stockQty: sku.stock_qty,\n // As in products: only an explicit `false` deactivates a SKU.\n active: sku.is_active !== false,\n variantIds: sku.selected_variants,\n }\n : null,\n // The backend lists entries whose product or SKU is gone or hidden. Same rule as the\n // storefront listing (ProductSKUSearchView with a guest session).\n available:\n !!sku &&\n !sku.deleted &&\n !sku.invalid &&\n product.is_active &&\n !product.is_draft &&\n !product.deleted &&\n product.available_on.includes('website'),\n fulfillmentMode: text(wire.fulfillment_mode) ?? 'none',\n advanceAmount: amount(wire.advance_amount),\n hasDigitalDelivery: wire.has_digital_delivery,\n };\n}\n","import type {\n ContentImage,\n ContentImageUsage,\n ContentPlatform,\n ThemeContent,\n} from '../types/theme-content';\nimport { GrowupsellApiError } from './errors';\nimport type { FormDataLike, RequestFn } from './types';\nimport type {\n WireContentImage,\n WireThemeContent,\n WireThemeContentAnswer,\n WireThemeContentList,\n WireThemeContentWrite,\n} from './wire/theme-content';\n\n/** An image to upload for theme content. */\nexport interface ContentImageUpload {\n /** An empty form from the platform (`new FormData()`); the library fills it in. */\n form: FormDataLike;\n /** The file: a `Blob`/`File` on the web, `{uri, name, type}` in React Native. */\n file: unknown;\n /** Its name with extension (the backend checks it): jpg, jpeg, png, webp, avif, pdf, mp4, mov, mkv. */\n fileName?: string;\n usage?: ContentImageUsage;\n}\n\nexport interface ThemeContentApi {\n /**\n * One section's document, or null if it was never saved. Public.\n * @param themeId The business's theme settings id (`ThemeSetting.id`).\n * @param slug The section, e.g. `header`, `footer`, `home`.\n */\n get<T = unknown>(themeId: number, slug: string): Promise<ThemeContent<T> | null>;\n /**\n * Several sections in one request: one entry per requested slug, in the same order, null\n * for a section never saved (a slug asked twice is answered twice). No slugs: `[]` without a\n * request. Public.\n * @param themeId The business's theme settings id (`ThemeSetting.id`).\n * @param slugs e.g. `['header', 'footer', 'announcement']`. A slug cannot contain a comma.\n * @example const [header, footer] = await client.themeContent.getMany(id, ['header', 'footer']);\n */\n getMany<T = unknown, const S extends readonly string[] = readonly string[]>(\n themeId: number,\n slugs: S,\n ): Promise<{ -readonly [K in keyof S]: ThemeContent<T> | null }>;\n /**\n * Merchant: saves a section's whole document, creating it on first save. `platform` must be\n * passed in by the app; it is not guessed (ADR-009).\n */\n update<T>(\n themeId: number,\n slug: string,\n content: { platform: ContentPlatform; data: T },\n ): Promise<ThemeContent<T>>;\n /** Merchant (manager role): uploads an image or video to use in theme content. */\n uploadImage(upload: ContentImageUpload): Promise<ContentImage>;\n}\n\nconst USAGES: Record<NonNullable<WireContentImage['related']>, ContentImageUsage> = {\n banner: 'banner',\n slider: 'slider',\n header_logo: 'header-logo',\n footer_logo: 'footer-logo',\n other: 'other',\n};\nconst WIRE_USAGES = Object.fromEntries(\n Object.entries(USAGES).map(([wire, usage]) => [usage, wire]),\n) as Record<ContentImageUsage, NonNullable<WireContentImage['related']>>;\n\n// Every content view reads the business from the header and fails (500) without it. ADR-017.\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n// The merchant token, without the customer token: an expired customer token would make the\n// backend answer 401, which the client would report as a merchant logout.\nconst MERCHANT = { business: 'required', merchant: true, anonymous: true } as const;\n\nexport function createThemeContentApi(request: RequestFn): ThemeContentApi {\n async function getMany(themeId: number, slugs: readonly string[]) {\n // The backend trims each slug and skips repeats, so the answer is matched by slug.\n const keys = slugs.map(listSlug);\n if (keys.length === 0) return [];\n const wire = await request<WireThemeContentList>('GET', `/content/get/${themeId}/v2`, {\n ...PUBLIC,\n query: { slug: [...new Set(keys)] },\n });\n if (!Array.isArray(wire)) {\n throw new GrowupsellApiError({\n kind: 'parse',\n message: 'Expected a list of theme content sections.',\n body: wire,\n });\n }\n const bySlug = new Map(wire.flatMap((row) => (row ? [[row.slug, toThemeContent(row)]] : [])));\n return keys.map((key) => bySlug.get(key) ?? null);\n }\n\n return {\n // The return types are proven by the tests; the implementation works on plain lists.\n getMany: getMany as ThemeContentApi['getMany'],\n async get<T>(themeId: number, slug: string) {\n // `/content/get/{id}/v2` is the multi-slug route, which shadows a section named \"v2\".\n if (slug === 'v2') return (await getMany(themeId, [slug]))[0] as ThemeContent<T> | null;\n const wire = await request<WireThemeContentAnswer>(\n 'GET',\n `/content/get/${themeId}/${segment(slug)}`,\n PUBLIC,\n );\n return toThemeContent(wire) as ThemeContent<T> | null;\n },\n async update<T>(\n themeId: number,\n slug: string,\n content: { platform: ContentPlatform; data: T },\n ) {\n // The body's slug renames the row, so it is always the URL's slug.\n const json: WireThemeContentWrite = { slug, platform: content.platform, data: content.data };\n const wire = await request<WireThemeContent>(\n 'PUT',\n `/content/update/${themeId}/${segment(slug)}`,\n { ...MERCHANT, json },\n );\n return toThemeContent(wire) as ThemeContent<T>;\n },\n async uploadImage(upload) {\n // The backend accepts an upload without a file and stores an empty row.\n if (upload.file == null) throw new Error('themeContent.uploadImage needs a file.');\n upload.form.append('image', upload.file, upload.fileName);\n if (upload.usage) upload.form.append('related', WIRE_USAGES[upload.usage]);\n const wire = await request<WireContentImage>('POST', '/content/images/create', {\n ...MERCHANT,\n formData: upload.form,\n });\n return toContentImage(wire);\n },\n };\n}\n\n/** A path segment: `<str:slug>` matches anything but '/'. */\nfunction segment(slug: string): string {\n if (slug.trim() === '') throw new Error('themeContent: slug is required.');\n return encodeURIComponent(slug);\n}\n\n/** A slug in the `?slug=a,b` list: trimmed (as the backend does), never empty, no comma. */\nfunction listSlug(slug: string): string {\n const trimmed = slug.trim();\n if (trimmed === '') throw new Error('themeContent: slug is required.');\n if (trimmed.includes(',')) throw new Error(`themeContent: slug \"${slug}\" contains a comma.`);\n return trimmed;\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toThemeContent(wire: WireThemeContentAnswer): ThemeContent | null {\n if (!('id' in wire)) return null;\n return {\n id: wire.id,\n themeId: wire.theme,\n slug: wire.slug,\n platform: wire.platform,\n data: wire.data,\n };\n}\n\nexport function toContentImage(wire: WireContentImage): ContentImage {\n if (!wire.image) {\n throw new GrowupsellApiError({\n kind: 'parse',\n message: 'The upload was accepted but no file was stored.',\n body: wire,\n });\n }\n return {\n id: wire.id,\n url: wire.image,\n usage: wire.related ? (USAGES[wire.related] ?? null) : null,\n };\n}\n","import type {\n CustomPage,\n CustomPageContent,\n CustomPageHero,\n CustomPageSection,\n} from '../types/customPages';\nimport { text } from './convert';\nimport { GrowupsellApiError } from './errors';\nimport type { RequestFn } from './types';\nimport type {\n WireCustomPage,\n WireCustomPageContent,\n WireCustomPageContentWrite,\n} from './wire/customPages';\n\n/** A page's whole editable document, as saved by `customPages.updateContent()`. */\nexport interface CustomPageContentInput {\n /** In display order. Saved as given; unknown keys are kept. */\n sections: CustomPageSection[];\n /** `null` removes the hero. */\n hero: CustomPageHero | null;\n}\n\nexport interface CustomPagesApi {\n /**\n * The business's active page at a storefront path (`about-us`, `/company/team/`), or null when\n * there is none (unknown path or inactive page). Public. Paths are case-sensitive; slashes\n * around and between segments are ignored, as the backend does.\n */\n byPath(path: string): Promise<CustomPage | null>;\n /**\n * Merchant (manager role): a page's editable document, inactive pages included. The backend\n * creates an empty document the first time a page is opened.\n */\n content(pageId: number): Promise<CustomPageContent>;\n /**\n * Merchant (manager role): saves a page's sections and hero together and returns the stored\n * document. Both are always sent: saving one alone could drop a hero that an older editor\n * kept among the sections.\n */\n updateContent(pageId: number, input: CustomPageContentInput): Promise<CustomPageContent>;\n}\n\n// Business from the `business` header (400 without it; the `business_id` query alternative is\n// not used, ADR-017). No customer token: an expired one would make every page a 401.\nconst PUBLIC = { business: 'required', anonymous: true } as const;\n// Merchant token without the customer token (see theme-content.ts). The business header is\n// optional here: without it the backend uses the merchant's own business.\nconst MERCHANT = { merchant: true, anonymous: true } as const;\n\n/** Older editors kept the hero as a block with this slug among the sections. */\nconst HERO_BLOCK_SLUG = '__hero_slider';\n\nexport function createCustomPagesApi(request: RequestFn): CustomPagesApi {\n return {\n async byPath(path) {\n const urlPath = normalizePath(path);\n try {\n const wire = await request<WireCustomPage>('GET', '/website/custom-page/public', {\n ...PUBLIC,\n query: { url_path: urlPath },\n });\n return toCustomPage(wire);\n } catch (error) {\n if (error instanceof GrowupsellApiError && error.status === 404) return null;\n throw error;\n }\n },\n async content(pageId) {\n const wire = await request<WireCustomPageContent>(\n 'GET',\n contentPath(pageId, 'content'),\n MERCHANT,\n );\n return toCustomPageContent(wire);\n },\n async updateContent(pageId, input) {\n const path = contentPath(pageId, 'updateContent');\n const json = toContentWrite(input);\n const wire = await request<WireCustomPageContent>('PATCH', path, { ...MERCHANT, json });\n return toCustomPageContent(wire);\n },\n };\n}\n\n/**\n * `PublicCustomPageDetail._normalize_url_path`: `\\` is `/`, empty segments are dropped. Blank\n * segments too: the backend would answer 400 for a blank path or match nothing.\n */\nfunction normalizePath(path: string): string {\n const segments = path.trim().replace(/\\\\/g, '/').split('/');\n const normalized = segments.filter((s) => s.trim() !== '').join('/');\n if (!normalized) throw new Error('customPages.byPath: path is required.');\n return normalized;\n}\n\n/** `<int:page_pk>`: anything else is Django's HTML 404. */\nfunction contentPath(pageId: number, method: string): string {\n if (!Number.isInteger(pageId) || pageId <= 0) {\n throw new Error(`customPages.${method}: page id must be a positive integer.`);\n }\n return `/website/custom-page/${pageId}/content`;\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\n/**\n * A stored hero: `{type, data}` with a non-empty type, or an older slide list (a slider; `[]`\n * is none). Anything else, including the old editor's `{type: null, data: null}`, is none.\n */\nexport function toHero(raw: unknown): CustomPageHero | null {\n if (Array.isArray(raw)) return raw.length > 0 ? { type: 'slider', data: raw } : null;\n if (!isObject(raw)) return null;\n const { type, data } = raw;\n return typeof type === 'string' && type !== '' ? { type, data } : null;\n}\n\n/**\n * The hero and sections of a stored document. `hero_content` wins whenever it is not null,\n * even when it means \"none\"; only without it is an older hero block used. The hero block is\n * never a section, and neither is anything that is not an object.\n */\nfunction toDocument(\n heroContent: unknown,\n blocks: unknown[] | null,\n): { hero: CustomPageHero | null; sections: CustomPageSection[] } {\n const objects = (blocks ?? []).filter(isObject);\n const hero =\n heroContent != null\n ? toHero(heroContent)\n : toHero(objects.find((b) => b.slug === HERO_BLOCK_SLUG)?.content);\n return { hero, sections: objects.filter((b) => b.slug !== HERO_BLOCK_SLUG) };\n}\n\nexport function toCustomPage(wire: WireCustomPage): CustomPage {\n return {\n id: wire.id,\n title: wire.title,\n path: wire.url_path,\n seoTitle: text(wire.seo_title),\n seoDescription: text(wire.seo_description),\n seoKeywords: (wire.seo_keywords ?? []).flatMap((k) =>\n typeof k === 'string' && k.trim() !== '' ? [k.trim()] : [],\n ),\n ...toDocument(wire.hero_content, wire.contents),\n };\n}\n\nexport function toCustomPageContent(wire: WireCustomPageContent): CustomPageContent {\n return {\n id: wire.id,\n pageId: wire.page,\n ...toDocument(wire.hero_content, wire.content),\n createdAt: wire.created_at,\n updatedAt: wire.updated_at,\n };\n}\n\n/** Domain → wire: always the `{type, data}` hero form; the reserved hero block never goes back. */\nexport function toContentWrite(input: CustomPageContentInput): WireCustomPageContentWrite {\n const { hero } = input;\n if (hero && hero.type.trim() === '') {\n throw new Error('customPages.updateContent: the hero type is required.');\n }\n return {\n content: input.sections.filter((s) => isObject(s) && s.slug !== HERO_BLOCK_SLUG),\n hero_content: hero ? { type: hero.type, data: hero.data } : null,\n };\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import type { GuestSession } from '../types/session';\nimport { GrowupsellApiError } from './errors';\nimport type { RequestFn } from './types';\nimport type { WireGuestSession } from './wire/session';\n\nexport interface SessionApi {\n /**\n * Starts a new guest session. Call it when no session is stored, and again when the client\n * reports `onUnauthorized({ kind: 'session', token })`. The library stores nothing: keep the token\n * and return it from `credentials().sessionToken`. There is no logout endpoint.\n */\n create(): Promise<GuestSession>;\n}\n\nexport function createSessionApi(request: RequestFn): SessionApi {\n return {\n async create() {\n // `session: 'omit'`: the backend answers any request carrying an unknown session token\n // with a 404, so the token being replaced must not be sent. `anonymous`: an expired\n // login must not block a new guest session either. Sessions are not business-scoped.\n const wire = await request<WireGuestSession>('POST', '/session/create', {\n anonymous: true,\n session: 'omit',\n json: {},\n });\n return toGuestSession(wire);\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\n/**\n * Throws a `parse` error unless the answer has an id and a non-empty token: a session without\n * a token must never be held or stored (it would be sent as no session at all).\n */\nexport function toGuestSession(wire: WireGuestSession): GuestSession {\n const raw: Partial<Record<keyof WireGuestSession, unknown>> | null =\n wire && typeof wire === 'object' ? wire : null;\n if (typeof raw?.id !== 'number' || typeof raw.session_token !== 'string' || !raw.session_token) {\n throw new GrowupsellApiError({\n kind: 'parse',\n message: 'The new guest session has no token.',\n body: wire,\n });\n }\n return { id: raw.id, token: raw.session_token };\n}\n","import type { Country, CountryState } from '../types/lookup';\nimport type { RequestFn } from './types';\nimport type { WireCountryList, WireCountryState } from './wire/lookup';\n\nexport interface LookupApi {\n /** All countries, or those whose code or name contains `search` (case-insensitive). */\n countries(search?: string): Promise<Country[]>;\n /**\n * The states of a country (`Country.code`). `[]` for a country without states; an unknown\n * code rejects with a 400 on `country`.\n */\n states(countryCode: string): Promise<CountryState[]>;\n}\n\n// Public reference data: no login (an expired customer token would get a 401) and not\n// business-scoped (verified live).\nconst PUBLIC = { anonymous: true } as const;\n\nexport function createLookupApi(request: RequestFn): LookupApi {\n return {\n async countries(search) {\n const wire = await request<WireCountryList>('GET', '/lookup/country/list', {\n ...PUBLIC,\n query: { search },\n });\n return wire.data.map(toCountry);\n },\n\n async states(countryCode) {\n const wire = await request<WireCountryState[]>('GET', '/lookup/country/state/list', {\n ...PUBLIC,\n query: { country: countryCode },\n });\n return wire.map(toCountryState);\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toCountry(wire: WireCountryList['data'][number]): Country {\n return { code: wire.code, name: wire.name };\n}\n\nexport function toCountryState(wire: WireCountryState): CountryState {\n return {\n id: wire.id,\n name: wire.name,\n shortName: wire.short_name,\n code: wire.code,\n country: wire.country,\n };\n}\n","import type { AuthResult, CustomerSettings, SignedInCustomer } from '../types/auth';\nimport type { CustomerProfile } from '../types/customer';\nimport { text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireCustomerProfile,\n WireCustomerSettings,\n WireRegisterPending,\n WireSignedInCustomer,\n} from './wire/auth';\n\nexport interface LoginInput {\n /** A phone number in E.164 (`+919876543210`) or an email, as `settings().authType` allows. */\n username: string;\n password: string;\n}\n\nexport interface VerifyOtpInput {\n /** `customerId` from a `verification-required` result. */\n customerId: number;\n otp: string;\n}\n\n/**\n * Signed-out customer flows: settings, sign-up, login, OTP and password reset. The library\n * stores nothing (ADR-015): keep the token a signed-in result returns. There is no logout\n * endpoint; logging out is forgetting the token.\n */\nexport interface AuthApi {\n /** How this business lets customers sign up and log in. */\n settings(): Promise<CustomerSettings>;\n /**\n * Logs in. Needs a guest session (`session.create()`): the backend moves the guest cart to\n * the customer. An unverified account gets `verification-required` (an OTP was sent).\n */\n login(input: LoginInput): Promise<AuthResult>;\n /** Verifies the account with the OTP and signs the customer in. */\n verifyOtp(input: VerifyOtpInput): Promise<SignedInCustomer>;\n /**\n * Signs up. Needs a guest session, like `login()`. When the business requires verification\n * the result is `verification-required` and an OTP was sent; otherwise `signed-in`.\n */\n register(input: RegisterInput): Promise<AuthResult>;\n /** Sends an OTP to the account's phone or email: for verification and forgotten passwords. */\n sendOtp(username: string): Promise<{ message: string }>;\n /** Sets a new password with an OTP from `sendOtp()`. */\n resetPassword(input: ResetPasswordInput): Promise<{ message: string }>;\n}\n\nexport interface RegisterInput {\n /** Required when `settings().authType` is `email`. */\n email?: string;\n /** E.164. Required when `settings().authType` is `phone`. */\n phone?: string;\n /** At least 8 characters; the backend also applies Django's password rules. */\n password: string;\n type: 'individual' | 'business';\n /** Required for `individual`. */\n firstName?: string;\n /** Required for `individual`. */\n lastName?: string;\n /** Required for `business`. */\n businessName?: string;\n /** Required for `business`. */\n taxNumber?: string;\n referralCode?: string;\n}\n\nexport interface ResetPasswordInput {\n username: string;\n otp: string;\n newPassword: string;\n confirmPassword: string;\n}\n\n// Signed-out flows never send the customer token: an expired one would get a 401 and block\n// logging in again (ADR-017).\nconst SIGNED_OUT = { anonymous: true } as const;\nconst BUSINESS = { ...SIGNED_OUT, business: 'required' } as const;\n\nexport function createAuthApi(request: RequestFn): AuthApi {\n return {\n async settings() {\n const wire = await request<WireCustomerSettings>('GET', '/customer/setting/get', BUSINESS);\n return toSettings(wire);\n },\n\n async login({ username, password }) {\n // The backend crashes on login without a guest session (backend issue C14); the client\n // refuses before sending (ADR-023).\n const wire = await request<WireSignedInCustomer>('POST', '/customer/login', {\n ...BUSINESS,\n session: 'required',\n json: { username, password },\n });\n return toAuthResult(wire, username);\n },\n\n async verifyOtp({ customerId, otp }) {\n // The guest session is sent when there is one, so the guest cart moves to the customer.\n const wire = await request<WireSignedInCustomer>('POST', '/customer/otp/verify', {\n ...SIGNED_OUT,\n json: { otp, customer: customerId },\n });\n // Verifying activates the account and always issues a token (views.VerifyOtp).\n return toSignedIn(wire, wire.token!);\n },\n\n async register(input) {\n // Session: without verification the backend logs the customer in and moves the guest\n // cart (ADR-023).\n const wire = await request<WireSignedInCustomer | WireRegisterPending>(\n 'POST',\n '/customer/register',\n { ...BUSINESS, session: 'required', json: fromRegisterInput(input) },\n );\n return toAuthResult(wire);\n },\n\n async sendOtp(username) {\n const { message } = await request<{ message: string }>('POST', '/customer/otp/resend', {\n ...BUSINESS,\n json: { username },\n });\n return { message };\n },\n\n async resetPassword({ username, otp, newPassword, confirmPassword }) {\n const { message } = await request<{ message: string }>('POST', '/customer/password/reset', {\n ...BUSINESS,\n json: { username, otp, new_password: newPassword, confirm_password: confirmPassword },\n });\n return { message };\n },\n };\n}\n\n/**\n * The register serializer reads `type` and the name keys with `attrs[…]`, so a missing key is\n * a 500 (backend issue C16): every one is always sent, null when not given.\n */\nfunction fromRegisterInput(input: RegisterInput): Record<string, unknown> {\n return {\n ...(input.email !== undefined && { email: input.email }),\n ...(input.phone !== undefined && { phone: input.phone }),\n password: input.password,\n type: input.type,\n first_name: input.firstName ?? null,\n last_name: input.lastName ?? null,\n business_name: input.businessName ?? null,\n tax_number: input.taxNumber ?? null,\n ...(input.referralCode && { referral_code: input.referralCode }),\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toSettings(wire: WireCustomerSettings): CustomerSettings {\n // Missing keys get the backend's model defaults (CustomerConfig).\n return {\n authType: wire.authentication_type ?? 'email',\n allowBusinessSignup: wire.allow_business_signup ?? false,\n requireVerification: wire.require_customer_verification ?? true,\n lastNameRequired: wire.is_last_name_required ?? false,\n };\n}\n\nexport function toCustomerProfile(wire: WireCustomerProfile): CustomerProfile {\n const photo = text(wire.photo);\n return {\n id: wire.id,\n type: wire.type ?? 'individual',\n firstName: text(wire.first_name),\n lastName: text(wire.last_name),\n email: text(wire.email),\n // Sign-up without verification sends `str(None)` for a missing phone.\n phone: wire.phone === 'None' ? null : text(wire.phone),\n businessName: text(wire.business_name),\n taxNumber: text(wire.tax_number),\n // The login dump sends the storage path, not a URL; only a URL is usable.\n photo: photo && /^https?:\\/\\//.test(photo) ? photo : null,\n isActive: wire.is_active ?? false,\n emailVerified: wire.email_verified ?? false,\n phoneVerified: wire.phone_verified ?? false,\n };\n}\n\n/**\n * Login and sign-up answer with the customer and a token, also for an account that still\n * needs its OTP. That token is never given out (ADR-023): only an active account is signed in.\n * `username` is where login sent the OTP; sign-up passes none.\n */\nexport function toAuthResult(\n wire: WireSignedInCustomer | WireRegisterPending,\n username?: string,\n): AuthResult {\n if (wire.is_active && typeof wire.token === 'string') {\n return { status: 'signed-in', session: toSignedIn(wire, wire.token) };\n }\n const profile = toCustomerProfile(wire);\n return {\n status: 'verification-required',\n customerId: wire.id,\n contact: username ?? profile.phone ?? profile.email,\n };\n}\n\nfunction toSignedIn(wire: WireSignedInCustomer, token: string): SignedInCustomer {\n return {\n customer: toCustomerProfile(wire),\n token,\n rewardPoints: wire.reward_points ?? null,\n };\n}\n","import type { CustomerProfile } from '../types/customer';\nimport { toCustomerProfile } from './auth';\nimport type { RequestFn } from './types';\nimport type { WireCustomer, WireEmailChanged, WirePhoneChanged } from './wire/customer';\n\n/** Only the given keys are sent; `null` clears a field. */\nexport interface UpdateProfileInput {\n firstName?: string | null;\n lastName?: string | null;\n businessName?: string | null;\n taxNumber?: string | null;\n}\n\nexport interface ChangePasswordInput {\n oldPassword: string;\n newPassword: string;\n confirmPassword: string;\n}\n\nexport interface ConfirmEmailChangeInput {\n /** The new email, as sent to `requestEmailChange()`. */\n email: string;\n otp: string;\n}\n\nexport interface ConfirmPhoneChangeInput {\n /** The new phone, as sent to `requestPhoneChange()`. */\n phone: string;\n otp: string;\n}\n\n/** The logged-in customer's own account (ADR-023: signed-out flows are in `client.auth`). */\nexport interface CustomerApi {\n /** Changes the name, business name or tax number. `id` is `CustomerProfile.id`. */\n updateProfile(id: number, input: UpdateProfileInput): Promise<CustomerProfile>;\n changePassword(input: ChangePasswordInput): Promise<{ message: string }>;\n /** Sends an OTP to the new email; confirm with `confirmEmailChange()`. */\n requestEmailChange(email: string): Promise<void>;\n confirmEmailChange(\n input: ConfirmEmailChangeInput,\n ): Promise<{ message: string; newEmail: string }>;\n /** Sends an OTP to the new phone (E.164); confirm with `confirmPhoneChange()`. */\n requestPhoneChange(phone: string): Promise<void>;\n confirmPhoneChange(\n input: ConfirmPhoneChangeInput,\n ): Promise<{ message: string; newPhone: string }>;\n}\n\n// Every call is for a logged-in customer (`IsCustomer`). Calls whose view reads\n// `request.business` also need the business header (AttributeError → 500 without it).\nconst CUSTOMER = { customer: 'required' } as const;\nconst CUSTOMER_BUSINESS = { ...CUSTOMER, business: 'required' } as const;\n\nexport function createCustomerApi(request: RequestFn): CustomerApi {\n return {\n async updateProfile(id, input) {\n // Only the name fields: the endpoint also accepts verification flags (backend issue S13).\n const wire = await request<WireCustomer>('PATCH', `/customer/update/${id}`, {\n ...CUSTOMER_BUSINESS,\n json: fromProfileInput(input),\n });\n return toCustomerProfile(wire);\n },\n\n async changePassword({ oldPassword, newPassword, confirmPassword }) {\n const { message } = await request<{ message: string }>('PUT', '/customer/password/update', {\n ...CUSTOMER,\n json: {\n old_password: oldPassword,\n new_password: newPassword,\n confirm_password: confirmPassword,\n },\n });\n return { message };\n },\n\n async requestEmailChange(email) {\n // The response is the OTP row itself; nothing in it is for the app.\n await request('POST', '/customer/email/change/request', {\n ...CUSTOMER_BUSINESS,\n json: { email },\n });\n },\n\n async confirmEmailChange({ email, otp }) {\n const wire = await request<WireEmailChanged>('PUT', '/customer/email/change/verify', {\n ...CUSTOMER,\n json: { email, otp },\n });\n return { message: wire.message, newEmail: wire.new_email };\n },\n\n async requestPhoneChange(phone) {\n await request('POST', '/customer/phone/change/request', {\n ...CUSTOMER_BUSINESS,\n json: { phone },\n });\n },\n\n async confirmPhoneChange({ phone, otp }) {\n const wire = await request<WirePhoneChanged>('PUT', '/customer/phone/change/verify', {\n ...CUSTOMER,\n json: { phone, otp },\n });\n return { message: wire.message, newPhone: wire.new_phone };\n },\n };\n}\n\nfunction fromProfileInput(input: UpdateProfileInput): Record<string, string | null> {\n const body: Record<string, string | null> = {};\n if (input.firstName !== undefined) body.first_name = input.firstName;\n if (input.lastName !== undefined) body.last_name = input.lastName;\n if (input.businessName !== undefined) body.business_name = input.businessName;\n if (input.taxNumber !== undefined) body.tax_number = input.taxNumber;\n return body;\n}\n","import type { Address, AddressInput } from '../types/address';\nimport { amount, text } from './convert';\nimport type { RequestFn } from './types';\nimport type { WireAddress } from './wire/address';\n\nexport interface AddressesApi {\n /** The logged-in customer's addresses, oldest first. */\n list(): Promise<Address[]>;\n create(input: AddressInput): Promise<Address>;\n /**\n * Replaces an address. Use the returned address's id from then on: an address an order\n * already used is kept for that order, and the edit is saved as a copy with a new id.\n */\n update(id: number, input: AddressInput): Promise<Address>;\n /** Deletes an address (kept hidden for orders that used it). */\n remove(id: number): Promise<void>;\n}\n\n// Every address endpoint is for a logged-in customer. Delete also reads the business type\n// (`request.business.category.type`), so it needs the business header.\nconst CUSTOMER = { customer: 'required' } as const;\n\nexport function createAddressesApi(request: RequestFn): AddressesApi {\n return {\n async list() {\n const wire = await request<WireAddress[]>('GET', '/customer/address/list', CUSTOMER);\n return wire.map(toAddress);\n },\n\n async create(input) {\n const wire = await request<WireAddress>('POST', '/customer/address/create', {\n ...CUSTOMER,\n json: fromAddressInput(input),\n });\n return toAddress(wire);\n },\n\n async update(id, input) {\n const wire = await request<WireAddress>('PUT', `/customer/address/update/${id}`, {\n ...CUSTOMER,\n json: fromAddressInput(input),\n });\n return toAddress(wire);\n },\n\n async remove(id) {\n await request('DELETE', `/customer/address/delete/${id}`, {\n ...CUSTOMER,\n business: 'required',\n });\n },\n };\n}\n\n// Wire → domain and back. Exported for tests only (not part of the package's public API).\n\nexport function toAddress(wire: WireAddress): Address {\n return {\n id: wire.id,\n addressLine1: wire.address_line_1,\n addressLine2: wire.address_line_2,\n postalCode: text(wire.postal_code),\n city: wire.city,\n type: wire.type,\n country: text(wire.country),\n state: wire.state ?? null,\n stateName: text(wire.state_name),\n landmark: wire.landmark,\n contactNo: text(wire.contact_no),\n latitude: amount(wire.latitude),\n longitude: amount(wire.longitude),\n isDefault: wire.default ?? false,\n isUsed: wire.is_used,\n };\n}\n\n/**\n * Every key is sent. `default` especially: when it is missing, editing an address an order\n * used changes the hidden original instead of the copy, and the address disappears from the\n * list (backend issue W23).\n */\nexport function fromAddressInput(input: AddressInput): Record<string, unknown> {\n return {\n address_line_1: input.addressLine1,\n address_line_2: input.addressLine2,\n postal_code: input.postalCode ?? '',\n city: input.city,\n type: input.type,\n country: input.country ?? null,\n state: input.state ?? null,\n landmark: input.landmark,\n contact_no: input.contactNo ?? null,\n latitude: input.latitude ?? null,\n longitude: input.longitude ?? null,\n default: input.isDefault ?? false,\n };\n}\n","import type {\n AdvanceOrder,\n CheckoutSettings,\n PendingPayment,\n PlaceOrderResult,\n} from '../types/checkout';\nimport type { OrderType } from '../types/cart';\nimport { amount, text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireChargeRequest,\n WireChargeResponse,\n WireCustomAdvanceRequest,\n WireCustomAdvanceResponse,\n WireOrderBusinessSetting,\n WirePaymentPaidHistory,\n} from './wire/checkout';\n\nexport interface PlaceOrderOptions {\n /**\n * Gift cards to spend, by id (from `promotions.validateGiftCard()`), in this order. Not\n * allowed for cash on delivery.\n */\n giftCardIds?: readonly number[];\n /** Spend the customer's reward points. Not allowed for cash on delivery. */\n useRewardPoints?: boolean;\n}\n\n/** A made-to-order product, ordered on its own (one unit) with an advance payment. */\nexport interface CreateAdvanceOrderInput {\n productId: number;\n /** The variant, when the product has several. */\n skuId?: number;\n /** The product's custom fields, as configured by the merchant. */\n customData?: Record<string, unknown>;\n /** One of the customer's addresses. */\n shippingAddressId: number;\n /** Defaults to the shipping address. */\n billingAddressId?: number;\n /** Default `delivery`. */\n type?: OrderType;\n}\n\nexport interface CheckoutApi {\n /** The business's order settings: cash on delivery, cancellation, quantity limits. */\n settings(): Promise<CheckoutSettings>;\n /**\n * Places the order for the cart `cartId`: spends the gift cards and reward points, creates\n * the payment and takes the cart out of `cart` status. Needs a logged-in customer.\n *\n * - `placed`: nothing left to pay online (cash on delivery, or fully covered by gift cards\n * or points).\n * - `payment-required`: run the payment SDK for `payment.method`, then confirm through\n * `client.payments`.\n *\n * Gift cards and reward points cannot be combined (the backend over-charges the gift cards\n * when both are used): this rejects before sending.\n *\n * One request per cart at a time: calling again for the same cart while a request is in\n * flight returns the same promise (a double tap places one order; the first call's options\n * win). Waits up to 60 s, because the backend books shipments before it answers.\n *\n * **Never retried**, by the library or by you: the backend does not detect a repeated\n * request. After a timeout or network error, read `client.orders.detail(cartId)`: a status\n * other than `cart` means the order was placed.\n */\n placeOrder(cartId: number, options?: PlaceOrderOptions): Promise<PlaceOrderResult>;\n /**\n * Creates the order for a made-to-order product and its advance payment in one step, outside\n * the cart. The advance amount is the product's, set by the merchant: it is never sent. Pay\n * `payment` like a `payment-required` result of `placeOrder`. Needs a logged-in customer.\n * Not idempotent: each call creates an order.\n */\n createAdvanceOrder(input: CreateAdvanceOrderInput): Promise<AdvanceOrder>;\n}\n\n// Public, but the view resolves the business from the header (get_or_create on it).\nconst PUBLIC_BUSINESS = { anonymous: true, business: 'required' } as const;\nconst CUSTOMER_BUSINESS = { business: 'required', customer: 'required' } as const;\n/** Placing an order books Shiprocket shipments synchronously: allow it far more than 15 s. */\nconst PLACE_ORDER_TIMEOUT_MS = 60_000;\n\nexport function createCheckoutApi(request: RequestFn): CheckoutApi {\n // Per client instance: requests in flight, by cart id (ADR-023: no double \"place order\").\n const placing = new Map<number, Promise<PlaceOrderResult>>();\n\n async function charge(cartId: number, options: PlaceOrderOptions): Promise<PlaceOrderResult> {\n // Exactly the two keys the view reads; never `price`, `offers` or `advance_amount`.\n const body: WireChargeRequest = {\n giftcard: [...(options.giftCardIds ?? [])],\n use_reward_points: options.useRewardPoints ?? false,\n };\n const wire = await request<WireChargeResponse>('POST', `/order/charge/delivery/${cartId}`, {\n ...CUSTOMER_BUSINESS,\n timeoutMs: PLACE_ORDER_TIMEOUT_MS,\n json: body,\n });\n // Cash on delivery comes back as \"pay\" with a `cod` row: nothing to pay online.\n if (wire.action === 'done' || wire.payment.type === 'cod') {\n return { status: 'placed', orderId: cartId };\n }\n return { status: 'payment-required', orderId: cartId, payment: toPendingPayment(wire.payment) };\n }\n\n return {\n async settings() {\n return toCheckoutSettings(\n await request<WireOrderBusinessSetting>(\n 'GET',\n '/order/business/setting/get',\n PUBLIC_BUSINESS,\n ),\n );\n },\n\n placeOrder(cartId, options = {}) {\n const inFlight = placing.get(cartId);\n if (inFlight) return inFlight;\n if ((options.giftCardIds?.length ?? 0) > 0 && options.useRewardPoints) {\n return Promise.reject(\n new Error(\n 'placeOrder: gift cards and reward points cannot be combined; choose one (backend issue W36).',\n ),\n );\n }\n const promise = charge(cartId, options).finally(() => placing.delete(cartId));\n placing.set(cartId, promise);\n return promise;\n },\n\n async createAdvanceOrder(input) {\n // Built field by field: nothing else from `input` (no price, offers or advance amount).\n const body: WireCustomAdvanceRequest = {\n product: input.productId,\n sku: input.skuId,\n custom_data: input.customData,\n qty: 1,\n type: input.type,\n shipping_address: input.shippingAddressId,\n billing_address: input.billingAddressId,\n };\n const wire = await request<WireCustomAdvanceResponse>(\n 'POST',\n '/order/custom-advance/create',\n { ...CUSTOMER_BUSINESS, timeoutMs: PLACE_ORDER_TIMEOUT_MS, json: body },\n );\n return { orderId: wire.order_id, payment: toPendingPayment(wire.payment) };\n },\n };\n}\n\n// Wire → domain. Exported for tests and other http modules (not part of the public API).\n\nexport function toCheckoutSettings(wire: WireOrderBusinessSetting): CheckoutSettings {\n return {\n allowCashOnDelivery: wire.allow_cash_on_delivery ?? false,\n allowCancellation: wire.allow_cancellation_from_customer ?? false,\n autoAccept: wire.auto_accept ?? false,\n onlineOrdersEnabled: wire.enable_online_order ?? false,\n deliveryChargeEnabled: wire.delivery_charge ?? false,\n maxQuantityIndividual: wire.max_allowed_qty_for_individual ?? 0,\n maxQuantityBusiness: wire.max_allowed_qty_for_business ?? 0,\n };\n}\n\n/** A payment still to make, from the backend's payment row (also used by exchanges). */\nexport function toPendingPayment(wire: WirePaymentPaidHistory): PendingPayment {\n const method = wire.payment_method?.type ?? null;\n return {\n id: wire.id,\n amount: amount(wire.amount) ?? 0,\n method,\n publicKey: text(wire.payment_method?.payment_key),\n providerOrderId: text(wire.payment_order_key),\n // `payment_key` means something else for every provider; only Stripe's is a client secret.\n clientSecret: method === 'stripe' ? text(wire.payment_key) : null,\n // Razorpay and Stripe rows carry links too, to pages the SDK flows do not use.\n redirectUrl: method === 'phonepe' ? text(wire.payment_url) : null,\n };\n}\n","import type { PendingPayment } from '../types/checkout';\nimport type { PaymentConfirmation } from '../types/payments';\nimport { GrowupsellApiError } from './errors';\nimport { multipart, type UploadFile } from './multipart';\nimport type { RequestFn } from './types';\nimport type {\n WirePaymentStatusUpdate,\n WirePhonePeSuccess,\n WireRazorpaySuccess,\n WireRazorpaySuccessRequest,\n WireStripeSuccess,\n WireStripeSuccessRequest,\n} from './wire/payments';\n\n/** What Razorpay Checkout's `handler` receives on success. */\nexport interface RazorpayResult {\n razorpayPaymentId: string;\n razorpayOrderId: string;\n razorpaySignature: string;\n}\n\n/**\n * Confirms a payment after the provider's SDK or page finished (the `payment` of a\n * `payment-required` result). The backend's answer is only a hint: Razorpay's endpoint says\n * success even when the capture failed, and Stripe's does not check that the intent belongs to\n * the order. **Read `client.orders.detail(orderId)` afterwards for the real payment status.**\n *\n * One request per payment at a time: calling again for the same payment while a confirmation\n * is in flight (a page refresh, a double tap) returns the same promise.\n */\nexport interface PaymentsApi {\n /** After the PhonePe redirect (`/payment-redirect?payment_id=…`): asks PhonePe for the status. */\n confirmPhonePe(paymentId: number): Promise<PaymentConfirmation>;\n /**\n * After Stripe Elements' `confirmPayment`. Sends the pending payment's own PaymentIntent, so\n * an app cannot confirm with another intent. A failed verification is `unpaid`, not an\n * error. Rejects with a `TypeError`, without a request, when `providerOrderId` is missing.\n */\n confirmStripe(\n payment: Pick<PendingPayment, 'id' | 'providerOrderId'>,\n ): Promise<PaymentConfirmation>;\n /** After Razorpay Checkout succeeded: passes Razorpay's result to the backend. */\n confirmRazorpay(payment: Pick<PendingPayment, 'id'>, result: RazorpayResult): Promise<void>;\n /**\n * Direct (bank) transfer: uploads the customer's screenshot of the transfer. The payment\n * becomes `unverified` until the merchant checks it. Needs a logged-in customer.\n * `screenshot`: a `File` or `Blob` on the web, `{ uri, name, type }` in React Native.\n */\n submitTransferProof(paymentId: number, screenshot: UploadFile): Promise<void>;\n}\n\n// The three success views need no login, and a customer token expired during the payment\n// redirect would get a 401 (CustomerApiMiddleware): leave it out. They resolve the business\n// from the header (PhonePe scopes the payment by it; Razorpay crashes without it).\nconst PUBLIC_BUSINESS = { anonymous: true, business: 'required' } as const;\nconst CUSTOMER_BUSINESS = { customer: 'required', business: 'required' } as const;\n/** The message of a failed Stripe verification (payment/views.py:775). */\nconst STRIPE_VERIFICATION_FAILED = 'Payment verification failed';\n\nexport function createPaymentsApi(request: RequestFn): PaymentsApi {\n // Per client instance: confirmations in flight, by provider and payment id.\n const inFlight = new Map<string, Promise<unknown>>();\n function once<T>(key: string, run: () => Promise<T>): Promise<T> {\n const existing = inFlight.get(key);\n if (existing) return existing as Promise<T>;\n const promise = run().finally(() => inFlight.delete(key));\n inFlight.set(key, promise);\n return promise;\n }\n\n return {\n confirmPhonePe(paymentId) {\n return once(`phonepe:${paymentId}`, async () => {\n const wire = await request<WirePhonePeSuccess>(\n 'GET',\n `/payment/phonepe/order/web/success/${paymentId}`,\n PUBLIC_BUSINESS,\n );\n return { status: wire.payment_status === 'paid' ? 'paid' : 'unpaid' };\n });\n },\n\n confirmStripe(payment) {\n const intentId = payment.providerOrderId;\n if (!intentId) {\n return Promise.reject(\n new TypeError('confirmStripe: the payment has no providerOrderId (PaymentIntent id).'),\n );\n }\n return once(`stripe:${payment.id}`, async () => {\n const json: WireStripeSuccessRequest = { payment_intent_id: intentId };\n try {\n await request<WireStripeSuccess>(\n 'POST',\n `/payment/stripe/order/web/success/${payment.id}`,\n { ...PUBLIC_BUSINESS, json },\n );\n return { status: 'paid' };\n } catch (error) {\n if (isStripeVerificationFailure(error)) return { status: 'unpaid' };\n throw error;\n }\n });\n },\n\n confirmRazorpay(payment, result) {\n return once(`razorpay:${payment.id}`, async () => {\n const json: WireRazorpaySuccessRequest = {\n razorpay_payment_id: result.razorpayPaymentId,\n razorpay_order_id: result.razorpayOrderId,\n razorpay_signature: result.razorpaySignature,\n };\n await request<WireRazorpaySuccess>(\n 'POST',\n `/payment/razorpay/order/web/success/${payment.id}`,\n { ...PUBLIC_BUSINESS, json },\n );\n });\n },\n\n submitTransferProof(paymentId, screenshot) {\n return once(`transfer:${paymentId}`, async () => {\n // Only the screenshot: the backend would also write a `status` sent by the customer.\n const formData = multipart(\n {},\n { verification_screenshot: { file: screenshot } },\n 'Transfer proof',\n );\n await request<WirePaymentStatusUpdate>('PATCH', `/payment/status/update/${paymentId}`, {\n ...CUSTOMER_BUSINESS,\n formData,\n });\n });\n },\n };\n}\n\nfunction isStripeVerificationFailure(error: unknown): boolean {\n return (\n error instanceof GrowupsellApiError &&\n error.status === 400 &&\n (error.body as { message?: unknown } | undefined)?.message === STRIPE_VERIFICATION_FAILED\n );\n}\n","import type { UploadedFile } from '../types/custom-manufacturing';\nimport { multipart, type UploadFile } from './multipart';\nimport type { RequestFn } from './types';\nimport type { WireCustomManufacturingUpload } from './wire/custom-manufacturing';\n\nexport interface CustomManufacturingApi {\n /**\n * Uploads a file for an image/file field of a custom-manufacturing form; put `url` in the\n * field's value. `file` is a `File` or `Blob` on the web, `{ uri, name, type }` in React\n * Native. Needs a logged-in customer.\n */\n uploadFile(file: UploadFile, fileName?: string): Promise<UploadedFile>;\n}\n\n// The view reads `request.business` (500 without the header) and allows customers only\n// (or merchants, which the storefront does not use).\nconst CUSTOMER_BUSINESS = { customer: 'required', business: 'required' } as const;\n\nexport function createCustomManufacturingApi(request: RequestFn): CustomManufacturingApi {\n return {\n async uploadFile(file, fileName) {\n if (file == null) throw new Error('customManufacturing.uploadFile needs a file.');\n const wire = await request<WireCustomManufacturingUpload>(\n 'POST',\n '/manufacture/custom-request/customer/upload',\n {\n ...CUSTOMER_BUSINESS,\n formData: multipart({}, { file: { file, fileName } }, 'customManufacturing.uploadFile'),\n },\n );\n if (!wire.url)\n throw new Error('customManufacturing.uploadFile: the backend returned no URL.');\n return { id: wire.id, url: wire.url };\n },\n };\n}\n","import type { Page } from '../types/product';\nimport type {\n InvoicePayment,\n Subscription,\n SubscriptionDelivery,\n SubscriptionHold,\n SubscriptionInterval,\n SubscriptionInvoice,\n SubscriptionStatus,\n Weekday,\n} from '../types/subscriptions';\nimport { toPendingPayment } from './checkout';\nimport { amount, text } from './convert';\nimport type { RequestFn } from './types';\nimport type {\n WireCreateSubscription,\n WireInvoicePaymentResponse,\n WireStatusUpdate,\n WireSubscription,\n WireSubscriptionDelivery,\n WireSubscriptionDetail,\n WireSubscriptionHold,\n WireSubscriptionInterval,\n WireSubscriptionInvoice,\n WireSubscriptionStatus,\n} from './wire/subscriptions';\nimport type { WirePage } from './wire/shared';\n\nexport interface SubscriptionsApi {\n /** The customer's subscriptions, newest first. Default limit 20. */\n list(options?: { limit?: number; offset?: number }): Promise<Page<Subscription>>;\n /** Throws GrowupsellApiError with status 404 for a subscription that is not the customer's. */\n detail(id: number): Promise<Subscription>;\n /** Scheduled and past deliveries, oldest first. */\n deliveries(id: number): Promise<SubscriptionDelivery[]>;\n /** Pause periods, newest first. */\n holds(id: number): Promise<SubscriptionHold[]>;\n invoices(id: number): Promise<SubscriptionInvoice[]>;\n /**\n * Starts (or resumes) paying an invoice, e.g. from the \"pay now\" link in the invoice email.\n * Returns `{status: 'paid'}`, or the payment to make: run the SDK for `payment.method`, then\n * confirm through `client.payments`.\n *\n * Not a read, although the backend serves it as a GET: the first call for an invoice\n * creates a payment and a gateway order; later calls return that same payment until it is\n * paid. Call it only when the shopper chooses to pay, never to prefetch or poll.\n *\n * Every backend failure is a GrowupsellApiError with status 500 and the message\n * \"Something Went Wrong\": unknown invoice, the business has no active online payment\n * method, or the invoice's order is not completed. Show it as \"this invoice cannot be paid\n * online right now\" rather than as a crash.\n */\n payInvoice(invoiceId: number): Promise<InvoicePayment>;\n /**\n * Subscribes the customer to a SKU. The merchant usually has to accept it (status\n * `created` until then). Inputs the backend would silently accept but never deliver\n * (weekly without weekdays) are refused before sending.\n */\n create(input: CreateSubscriptionInput): Promise<Subscription>;\n /** Pauses an accepted, paid or running subscription; future deliveries are removed. */\n hold(id: number): Promise<Subscription>;\n /** Resumes a paused subscription; deliveries are scheduled again. */\n resume(id: number): Promise<Subscription>;\n /** Cancels with the customer's reason (required by the backend). */\n cancel(id: number, reason: string): Promise<Subscription>;\n}\n\nexport interface CreateSubscriptionInput {\n /** The logged-in customer's id: the backend takes it from the body, not from the login. */\n customerId: number;\n /** One of the customer's addresses. */\n addressId: number;\n skuId: number;\n /** Per delivery; at least 1. */\n quantity: number;\n /**\n * The SKU's current selling price (from the product detail). The backend stores and\n * invoices what is sent; it does not look the price up.\n */\n price: number;\n interval: SubscriptionInterval;\n /** ISO dates (YYYY-MM-DD); the start must be after today (the backend checks). */\n startDate: string;\n endDate: string;\n /** Required for 'weekly'; ignored otherwise. */\n weekdays?: Weekday[];\n /** Required for 'monthly': an ISO date whose day is the delivery day. Ignored otherwise. */\n monthDay?: string;\n}\n\nconst DEFAULT_LIMIT = 20;\n// Customer-only. The list and the invoice list read `request.business` (500 without it);\n// sent everywhere so a request is never made for the wrong business.\nconst CUSTOMER = { customer: 'required', business: 'required' } as const;\n\nexport function createSubscriptionsApi(request: RequestFn): SubscriptionsApi {\n return {\n async list(options = {}) {\n const limit = options.limit ?? DEFAULT_LIMIT;\n const offset = options.offset ?? 0;\n // Always send `limit`: without it the backend skips pagination and returns every row.\n const page = await request<WirePage<WireSubscription>>('GET', '/subscription/list', {\n ...CUSTOMER,\n query: { limit, offset },\n });\n return { items: page.results.map(toSubscription), total: page.count, offset, limit };\n },\n\n async detail(id) {\n return toSubscription(\n await request<WireSubscriptionDetail>('GET', `/subscription/detail/${id}`, CUSTOMER),\n );\n },\n\n async deliveries(id) {\n const wire = await request<WireSubscriptionDelivery[]>(\n 'GET',\n `/subscription/delivery/list/${id}`,\n CUSTOMER,\n );\n return wire.map(toSubscriptionDelivery);\n },\n\n async holds(id) {\n const wire = await request<WireSubscriptionHold[]>(\n 'GET',\n `/subscription/hold/history/list/${id}`,\n CUSTOMER,\n );\n return wire.map(toSubscriptionHold);\n },\n\n async invoices(id) {\n const wire = await request<WireSubscriptionInvoice[]>(\n 'GET',\n `/subscription/invoice/list/${id}`,\n CUSTOMER,\n );\n return wire.map(toSubscriptionInvoice);\n },\n\n async payInvoice(invoiceId) {\n // Business required: without it the view looks up the payment method of no business\n // and answers its catch-all 500.\n return toInvoicePayment(\n await request<WireInvoicePaymentResponse>(\n 'GET',\n `/subscription/invoice/get/${invoiceId}`,\n CUSTOMER,\n ),\n );\n },\n\n async create(input) {\n const body = toCreateBody(input);\n return toSubscription(\n await request<WireSubscription>('POST', '/subscription/create', {\n ...CUSTOMER,\n json: body,\n }),\n );\n },\n\n hold: (id) => updateStatus(id, { action: 'hold' }),\n resume: (id) => updateStatus(id, { action: 'resume' }),\n\n async cancel(id, reason) {\n const trimmed = reason?.trim();\n if (!trimmed) throw new Error('subscriptions.cancel needs a reason.');\n return updateStatus(id, { action: 'cancel', decline_message: trimmed });\n },\n };\n\n async function updateStatus(id: number, body: WireStatusUpdate) {\n return toSubscription(\n await request<WireSubscription>('POST', `/subscription/status/update/${id}`, {\n ...CUSTOMER,\n json: body,\n }),\n );\n }\n}\n\nconst WIRE_INTERVAL: Record<SubscriptionInterval, WireSubscriptionInterval> = {\n daily: 'daily',\n 'alternate-day': 'alternate_day',\n weekly: 'weekly',\n monthly: 'monthly',\n};\n\n/**\n * The create body, after the checks the backend lacks or answers badly: weekly without days\n * creates no deliveries (W30); an end before the start, a quantity below 1 and monthly\n * without a day are cheaper to refuse here than to round-trip.\n */\nfunction toCreateBody(input: CreateSubscriptionInput): WireCreateSubscription {\n const fail = (message: string): never => {\n throw new Error(`subscriptions.create: ${message}`);\n };\n if (!Number.isInteger(input.quantity) || input.quantity < 1) {\n fail('quantity must be a whole number of at least 1.');\n }\n // ISO dates compare correctly as strings.\n if (input.endDate < input.startDate) fail('endDate is before startDate.');\n const body: WireCreateSubscription = {\n customer: input.customerId,\n address: input.addressId,\n start_date: input.startDate,\n end_date: input.endDate,\n interval: WIRE_INTERVAL[input.interval],\n products: [{ id: input.skuId, quantity: input.quantity, price: input.price }],\n };\n if (input.interval === 'weekly') {\n if (!input.weekdays?.length) fail('weekly needs at least one weekday.');\n body.selected_days = input.weekdays;\n }\n if (input.interval === 'monthly') {\n if (!input.monthDay)\n fail('monthly needs monthDay (an ISO date whose day is the delivery day).');\n body.month_day = input.monthDay;\n }\n return body;\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nconst STATUS: Record<WireSubscriptionStatus, SubscriptionStatus> = {\n created: 'created',\n accepted: 'accepted',\n paid: 'paid',\n 'in-progress': 'in-progress',\n hold: 'hold',\n completed: 'completed',\n cancelled: 'cancelled',\n decline: 'declined',\n};\n\nconst INTERVAL: Record<WireSubscriptionInterval, SubscriptionInterval> = {\n daily: 'daily',\n alternate_day: 'alternate-day',\n weekly: 'weekly',\n monthly: 'monthly',\n};\n\n/** A JSON array of weekday names, a comma-separated string, or null. */\nfunction weekdays(value: string[] | string | null): Weekday[] {\n if (value == null) return [];\n const names = Array.isArray(value) ? value : value.split(',');\n return names.map((name) => name.trim()).filter((name) => name !== '') as Weekday[];\n}\n\nexport function toSubscription(wire: WireSubscription | WireSubscriptionDetail): Subscription {\n const address = wire.address;\n return {\n id: wire.id,\n number: text(wire.subscription_no),\n // The model defaults to `created`; null only for rows written outside the API.\n status: wire.status ? STATUS[wire.status] : 'created',\n interval: wire.interval ? INTERVAL[wire.interval] : null,\n startDate: wire.start_date,\n endDate: wire.end_date,\n weekdays: weekdays(wire.weekly_days),\n monthDay: wire.month_day,\n // The list sends the address id, the detail the address row.\n addressId: typeof address === 'object' ? (address?.id ?? null) : (address ?? null),\n reason: text(wire.decline_message),\n createdAt: wire.created_at,\n };\n}\n\nexport function toSubscriptionDelivery(wire: WireSubscriptionDelivery): SubscriptionDelivery {\n return {\n id: wire.id,\n date: wire.date,\n status: wire.status,\n items: wire.products.map((p) => ({\n id: p.id,\n skuId: p.sku,\n name: p.product_name,\n quantity: p.qty,\n unit: text(p.unit),\n price: amount(p.price),\n status: p.status,\n removed: p.deleted,\n })),\n };\n}\n\nfunction toSubscriptionHold(wire: WireSubscriptionHold): SubscriptionHold {\n return { id: wire.id, startDate: wire.start_date ?? null, endDate: wire.end_date ?? null };\n}\n\nfunction toInvoicePayment(wire: WireInvoicePaymentResponse): InvoicePayment {\n return wire.action === 'done'\n ? { status: 'paid' }\n : { status: 'payment-required', payment: toPendingPayment(wire.payment) };\n}\n\nexport function toSubscriptionInvoice(wire: WireSubscriptionInvoice): SubscriptionInvoice {\n return {\n id: wire.id,\n orderId: wire.order,\n invoiceNumber: text(wire.invoice_number),\n invoiceDate: wire.invoice_date,\n dueDate: wire.due_date ?? null,\n billingPeriod: wire.billing_period,\n amount: amount(wire.amount),\n paymentStatus: wire.payment?.status ?? 'unpaid',\n };\n}\n","import type {\n InvoiceFormat,\n OrderAddress,\n OrderDetail,\n OrderLine,\n OrderListItem,\n OrderPaymentEntry,\n OrderStatus,\n OrderSummary,\n Shipment,\n TrackingInfo,\n} from '../types/orders';\nimport type { Page } from '../types/product';\nimport { amount, text } from './convert';\nimport type { BinaryResponse, RequestFn } from './types';\nimport type {\n WireOrderAddress,\n WireOrderDetail,\n WireOrderListRow,\n WireOrderSummary,\n WireShipmentGroup,\n WireTracking,\n WireOrderDetailLine,\n} from './wire/orders';\nimport type { WirePaymentPaidHistory } from './wire/checkout';\nimport type { WirePage } from './wire/shared';\n\nexport interface OrderListOptions {\n /** Page size. Default 10. */\n limit?: number;\n offset?: number;\n /** Only orders in these statuses. */\n status?: readonly OrderStatus[];\n /** Matches the order number. */\n search?: string;\n}\n\nexport interface DocumentOptions {\n /** Paper format. Default `a4`. */\n format?: InvoiceFormat;\n}\n\nexport interface CancelCodItemsInput {\n orderId: number;\n /** Lines to cancel (`OrderLine.id`) and how many units of each. */\n items: readonly { orderLineId: number; quantity: number }[];\n /** Shown to the merchant as the order's status message. */\n reason: string;\n}\n\nexport interface OrdersApi {\n /** The logged-in customer's placed orders, newest first. */\n list(options?: OrderListOptions): Promise<Page<OrderListItem>>;\n /**\n * A placed order with its lines, payments and addresses. Rejects with a 404 for an order of\n * another customer. Also the way to check an order after a payment or a timed-out\n * `placeOrder`: a status other than `cart` means it was placed.\n */\n detail(orderId: number): Promise<OrderDetail>;\n /** The light order card the history list shows. */\n summary(orderId: number): Promise<OrderSummary>;\n /** The order's shipments, newest first, each with the lines it carries. */\n shipments(orderId: number): Promise<Shipment[]>;\n /**\n * Partner tracking for a shipment's `trackingNumber`. Rejects with a 400 (no message) for\n * shipments the merchant delivers itself: only Shiprocket shipments can be tracked.\n */\n tracking(trackingNumber: string): Promise<TrackingInfo>;\n /**\n * The order's invoice as PDF bytes (`contentType` `application/pdf`), e.g. to open in a tab\n * or share. Rejects with a 400 \"Invoice not generated yet\" until the merchant invoices it.\n */\n invoice(orderId: number, options?: DocumentOptions): Promise<BinaryResponse>;\n /** E-mails the invoice to the customer instead. */\n emailInvoice(orderId: number, options?: DocumentOptions): Promise<void>;\n /** The credit note of a return (`ReturnRequest.id`) as PDF bytes. */\n creditNote(returnId: number, options?: DocumentOptions): Promise<BinaryResponse>;\n /** E-mails the credit note to the customer instead. */\n emailCreditNote(returnId: number, options?: DocumentOptions): Promise<void>;\n /**\n * Cancels some units, or all, of an accepted cash-on-delivery order. Rejects with a 400 for\n * other orders. Not idempotent: disable the button while it runs. Rejects without a request\n * (`TypeError`, `RangeError`) when `items` is empty, a quantity is below 1 or `reason` is\n * blank.\n */\n cancelCodItems(input: CancelCodItemsInput): Promise<void>;\n}\n\n// Every order endpoint reads `request.business` and is for a logged-in customer.\nconst CUSTOMER = { business: 'required', customer: 'required' } as const;\nconst DEFAULT_LIMIT = 10;\n/** Tracking asks the delivery partner synchronously. */\nconst TRACKING_TIMEOUT_MS = 30_000;\n/** PDFs are rendered on request. */\nconst DOCUMENT_TIMEOUT_MS = 60_000;\n\nexport function createOrdersApi(request: RequestFn): OrdersApi {\n /**\n * Invoice and credit-note endpoints: PDF bytes, or an e-mail to the customer. Always sends\n * `send_to_customer`: without it the backend e-mails.\n */\n function pdf(path: string, options: DocumentOptions = {}) {\n return request<BinaryResponse>('POST', path, {\n ...CUSTOMER,\n query: { send_to_customer: false, invoice_type: options.format ?? 'a4' },\n responseType: 'binary',\n timeoutMs: DOCUMENT_TIMEOUT_MS,\n });\n }\n async function email(path: string, options: DocumentOptions = {}) {\n await request('POST', path, {\n ...CUSTOMER,\n query: { send_to_customer: true, invoice_type: options.format ?? 'a4' },\n timeoutMs: DOCUMENT_TIMEOUT_MS,\n });\n }\n\n return {\n async list(options = {}) {\n const limit = options.limit ?? DEFAULT_LIMIT;\n const offset = options.offset ?? 0;\n // Never `customer_id` or `offer_id`: the backend then lists other customers' orders.\n const wire = await request<WirePage<WireOrderListRow>>('GET', '/order/list', {\n ...CUSTOMER,\n query: { limit, offset, status: options.status, search: options.search },\n });\n return { items: wire.results.map(toOrderListItem), total: wire.count, offset, limit };\n },\n\n async detail(orderId) {\n return toOrderDetail(\n await request<WireOrderDetail>('GET', `/order/detail/${orderId}`, CUSTOMER),\n );\n },\n\n async summary(orderId) {\n return toOrderSummary(\n await request<WireOrderSummary>('GET', `/order/ecommerce/detail/${orderId}`, CUSTOMER),\n );\n },\n\n async shipments(orderId) {\n const wire = await request<WireShipmentGroup[]>(\n 'GET',\n `/order/product/delivery/info/list/${orderId}`,\n CUSTOMER,\n );\n return wire.map(toShipment);\n },\n\n async tracking(trackingNumber) {\n const wire = await request<WireTracking>(\n 'GET',\n `/delivery/order/tracking/info/${encodeURIComponent(trackingNumber)}`,\n { ...CUSTOMER, timeoutMs: TRACKING_TIMEOUT_MS },\n );\n return { trackingUrl: text(wire.tracking_url), events: wire.data };\n },\n\n invoice: (orderId, options) => pdf(`/order/invoice/pdf/send/${orderId}`, options),\n emailInvoice: (orderId, options) => email(`/order/invoice/pdf/send/${orderId}`, options),\n creditNote: (returnId, options) => pdf(`/order/credit/note/pdf/${returnId}`, options),\n emailCreditNote: (returnId, options) => email(`/order/credit/note/pdf/${returnId}`, options),\n\n async cancelCodItems({ orderId, items, reason }) {\n if (items.length === 0) throw new TypeError('cancelCodItems: items must not be empty.');\n if (items.some((item) => !(item.quantity >= 1))) {\n throw new RangeError('cancelCodItems: every quantity must be at least 1.');\n }\n if (reason.trim() === '') throw new TypeError('cancelCodItems: reason must not be blank.');\n await request('POST', '/order/cancel/cod', {\n ...CUSTOMER,\n json: {\n order: orderId,\n order_products: items.map((item) => ({ id: item.orderLineId, qty: item.quantity })),\n status_message: reason,\n },\n });\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\n/** A null status only appears on malformed rows; `created` is the model's first state. */\nconst status = (value: string | null | undefined): OrderStatus => value ?? 'created';\n\nexport function toOrderListItem(wire: WireOrderListRow): OrderListItem {\n return {\n id: wire.id,\n orderNumber: text(wire.order_no),\n type: wire.type,\n status: status(wire.status),\n payable: amount(wire.final_payable_amount) ?? 0,\n placedAt: wire.created_at,\n };\n}\n\nexport function toOrderLine(wire: WireOrderDetailLine): OrderLine {\n return {\n id: wire.id,\n skuId: wire.sku?.id ?? null,\n productId: wire.sku?.product?.id ?? null,\n name: wire.label ?? wire.name ?? '',\n photo: text(wire.photo),\n unitPrice: amount(wire.price) ?? 0,\n quantity: wire.qty,\n lineTotal: amount(wire.total) ?? 0,\n offerDiscount: amount(wire.offer_redeem_amount) ?? 0,\n taxPercent: amount(wire.tax),\n isDigital: wire.is_digital_product,\n customData: wire.custom_data,\n canReplace: wire.can_replace,\n canExchange: wire.can_exchange,\n maxReplaceOrExchangeQuantity: wire.max_qty_for_replace_or_exchange,\n };\n}\n\nexport function toOrderAddress(wire: WireOrderAddress): OrderAddress {\n return {\n id: wire.id,\n line1: text(wire.address_line_1),\n line2: text(wire.address_line_2),\n landmark: text(wire.landmark),\n city: text(wire.city),\n state: text(wire.state_name),\n postalCode: text(wire.postal_code),\n country: text(wire.country),\n type: text(wire.type),\n };\n}\n\nfunction toOrderPaymentEntry(wire: WirePaymentPaidHistory): OrderPaymentEntry {\n return {\n id: wire.id,\n type: text(wire.type),\n amount: amount(wire.amount) ?? 0,\n status: wire.status,\n method: wire.payment_method?.type ?? null,\n label: wire.payment_method_label,\n };\n}\n\nexport function toOrderDetail(wire: WireOrderDetail): OrderDetail {\n const lines = (wire.products ?? []).map(toOrderLine);\n // The backend keeps an order-level offer on the order and a product/category/brand offer on\n // each line (as in the cart; `ListOrderSerializer.get_discount_amount` uses the same rule).\n const orderOffer = amount(wire.offer_redeem_amount) ?? 0;\n const offerDiscount =\n orderOffer > 0 ? orderOffer : lines.reduce((sum, line) => sum + line.offerDiscount, 0);\n return {\n id: wire.id,\n orderNumber: text(wire.order_no),\n invoiceNumber: text(wire.invoice_number),\n type: wire.type,\n status: status(wire.status),\n statusMessage: text(wire.status_message),\n placedAt: wire.created_at,\n lines,\n subtotal: amount(wire.total_amount) ?? 0,\n offerDiscount,\n promoDiscount: amount(wire.promo_redeem_amount) ?? 0,\n deliveryCharge: amount(wire.delivery_charge) ?? 0,\n payable: amount(wire.final_payable_amount) ?? 0,\n shippingAddress: wire.shipping_address ? toOrderAddress(wire.shipping_address) : null,\n billingAddress: wire.billing_address ? toOrderAddress(wire.billing_address) : null,\n payments: (wire.payment_history ?? []).map(toOrderPaymentEntry),\n hasExchangeOrReplacement: wire.has_exchange_or_replacement,\n };\n}\n\nexport function toOrderSummary(wire: WireOrderSummary): OrderSummary {\n return {\n id: wire.id,\n orderNumber: text(wire.order_no),\n invoiceNumber: text(wire.invoice_number),\n status: status(wire.status),\n subtotal: amount(wire.total_amount) ?? 0,\n payable: amount(wire.order_total) ?? 0,\n placedAt: wire.placed_at,\n items: wire.order_products.map((item) => ({\n name: item.product_name ?? '',\n variant: text(item.variant_name),\n photo: text(item.photo),\n quantity: item.qty,\n unitPrice: amount(item.price) ?? 0,\n })),\n deliveryAddress: wire.delivery_address ? toOrderAddress(wire.delivery_address) : null,\n payment: wire.payment\n ? {\n id: wire.payment.id,\n status: wire.payment.status ?? 'unpaid',\n amount: wire.payment.order_amount ?? 0,\n mode: text(wire.payment.mode),\n }\n : null,\n };\n}\n\nexport function toShipment(wire: WireShipmentGroup): Shipment {\n const info = wire.delivery_info;\n return {\n id: info.id,\n partner: text(info.label) ?? 'Self',\n trackingNumber: text(info.tracking_number),\n status: info.status,\n createdAt: info.created_at,\n items: wire.products.map((item) => ({\n orderLineId: item.order_product,\n name: item.product_name ?? '',\n photo: text(item.photo),\n quantity: item.qty,\n })),\n };\n}\n","import type { ReturnableItem, ReturnRequest } from '../types/returns';\nimport { amount, text } from './convert';\nimport type { RequestFn } from './types';\nimport type { WireReturnableItem, WireReturnCreated, WireReturnRequest } from './wire/returns';\n\nexport interface CreateReturnInput {\n orderId: number;\n /** The shopper's reason, shown to the merchant. */\n reason: string;\n items: readonly {\n /** From `eligibleItems()`. */\n orderLineId: number;\n quantity: number;\n /** For serial-tracked products: which units (from `eligibleItems()`). */\n unitTrackingIds?: readonly number[];\n }[];\n}\n\nexport interface ReturnsApi {\n /** The order's lines that can still be returned (digital products never can). */\n eligibleItems(orderId: number): Promise<ReturnableItem[]>;\n /** The order's return requests, newest first. */\n list(orderId: number): Promise<ReturnRequest[]>;\n /**\n * Requests a return; the merchant accepts or declines it. Not idempotent: disable the button\n * while it runs. Rejects without a request (`TypeError`, `RangeError`) when `items` is empty,\n * `reason` is blank or a quantity is below 1. Quantities are not checked against\n * `eligibleItems()` here, and the backend does not check them either: the caller must.\n */\n create(input: CreateReturnInput): Promise<{ id: number }>;\n}\n\n// Every return endpoint reads `request.business` and is for a logged-in customer.\nconst CUSTOMER = { business: 'required', customer: 'required' } as const;\n\nexport function createReturnsApi(request: RequestFn): ReturnsApi {\n return {\n async eligibleItems(orderId) {\n // The backend route ends with a slash; without it Django answers a redirect.\n const wire = await request<WireReturnableItem[]>(\n 'GET',\n `/order/return/eligible/products/${orderId}/`,\n CUSTOMER,\n );\n return wire.map(toReturnableItem);\n },\n\n async list(orderId) {\n const wire = await request<WireReturnRequest[]>(\n 'GET',\n `/order/return/order/list/${orderId}`,\n CUSTOMER,\n );\n return wire.map(toReturnRequest);\n },\n\n async create({ orderId, reason, items }) {\n if (items.length === 0) throw new TypeError('returns.create: items must not be empty.');\n if (items.some((item) => !(item.quantity >= 1))) {\n throw new RangeError('returns.create: every quantity must be at least 1.');\n }\n if (reason.trim() === '') throw new TypeError('returns.create: reason must not be blank.');\n const wire = await request<WireReturnCreated>('POST', '/order/return/customer/create', {\n ...CUSTOMER,\n json: {\n order: orderId,\n requested_message: reason,\n order_products: items.map((item) => ({\n id: item.orderLineId,\n qty: item.quantity,\n ...(item.unitTrackingIds ? { tracking_info_ids: item.unitTrackingIds } : {}),\n })),\n },\n });\n return { id: wire.id };\n },\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toReturnableItem(wire: WireReturnableItem): ReturnableItem {\n return {\n orderLineId: wire.id,\n name: wire.product_name ?? '',\n photo: text(wire.product_photo),\n unitPrice: amount(wire.price) ?? 0,\n maxQuantity: wire.max_returnable_qty,\n unitTrackingIds: wire.unit_tracking_infos.map((unit) => unit.id),\n };\n}\n\nexport function toReturnRequest(wire: WireReturnRequest): ReturnRequest {\n return {\n id: wire.id,\n status: wire.status,\n createdAt: wire.created_at,\n amount: amount(wire.final_amount) ?? 0,\n items: (wire.products ?? []).map((item) => ({\n id: item.id,\n name: item.product_name ?? '',\n quantity: item.qty,\n status: item.status,\n })),\n };\n}\n","import { toPendingPayment } from './checkout';\nimport type {\n ExchangeDetail,\n ExchangeListItem,\n ExchangeResult,\n ExchangeTargetSku,\n ExchangeType,\n} from '../types/returns';\nimport { amount, text } from './convert';\nimport { multipart, type UploadFile } from './multipart';\nimport type { RequestFn, RequestOptions } from './types';\nimport type {\n WireExchangeCreated,\n WireExchangeDetail,\n WireExchangeListItem,\n WireExchangeTargetSku,\n} from './wire/returns';\n\nexport interface CreateExchangeInput {\n orderId: number;\n type: ExchangeType;\n /** The shopper's reason for the whole request. */\n reason?: string;\n items: readonly {\n /** A line with `canReplace` / `canExchange` (`OrderLine.id`). */\n orderLineId: number;\n /** At most `OrderLine.maxReplaceOrExchangeQuantity`. */\n quantity: number;\n /** Required for `exchange`: a sibling SKU of the same product. Ignored for `replace`. */\n targetSkuId?: number;\n /** A reason for this line. */\n reason?: string;\n /** A photo of the item: a `File`/`Blob` on the web, `{ uri, name, type }` in React Native. */\n photo?: UploadFile;\n }[];\n}\n\nexport interface ExchangesApi {\n /**\n * Requests a replacement (same SKU) or an exchange (sibling SKU). When the new SKU costs more\n * and the order was paid online, resolves `payment-required`: collect the payment like a\n * checkout payment. Not idempotent: disable the button while it runs. Rejects without a\n * request (`TypeError`, `RangeError`) when `items` is empty, a quantity is below 1 or an\n * `exchange` item has no `targetSkuId`. Sent as multipart form data when any item has a photo.\n */\n create(input: CreateExchangeInput): Promise<ExchangeResult>;\n /** The order's exchange and replacement requests, newest first. */\n list(orderId: number): Promise<ExchangeListItem[]>;\n /** One request with its lines. Rejects with a 404 for another customer's request. */\n detail(exchangeId: number): Promise<ExchangeDetail>;\n /**\n * The SKUs a bought SKU can be exchanged for (`targetSkuId` in `create`): the product's other\n * active, in-stock variants. Takes the bought SKU's id (`OrderLine.skuId`), not the order line:\n * the backend checks no line eligibility, so offer it only for lines with `canExchange`.\n * Rejects with a 404 when the SKU is unknown or deleted.\n */\n targetSkus(skuId: number): Promise<ExchangeTargetSku[]>;\n}\n\n// Every exchange endpoint reads `request.business` and is for a logged-in customer.\nconst CUSTOMER = { business: 'required', customer: 'required' } as const;\n\nexport function createExchangesApi(request: RequestFn): ExchangesApi {\n return {\n async create(input) {\n const wire = await request<WireExchangeCreated>(\n 'POST',\n '/order/exchange-replacement/customer/create',\n { ...CUSTOMER, ...exchangeBody(input) },\n );\n return toExchangeResult(wire);\n },\n\n async list(orderId) {\n const wire = await request<WireExchangeListItem[]>(\n 'GET',\n `/order/exchange-replacement/list/by/order/${orderId}`,\n CUSTOMER,\n );\n return wire.map(toExchangeListItem);\n },\n\n async detail(exchangeId) {\n return toExchangeDetail(\n await request<WireExchangeDetail>(\n 'GET',\n `/order/exchange-replacement/detail/${exchangeId}`,\n CUSTOMER,\n ),\n );\n },\n\n async targetSkus(skuId) {\n // `IsManagerOrCustomer`; the business header makes the middleware drop another\n // business's customer token (products/views.py:4140, base/middleware.py:46-51).\n const wire = await request<WireExchangeTargetSku[]>(\n 'GET',\n `/product/sku/avail/for/exchange/${skuId}`,\n CUSTOMER,\n );\n return wire.map(toExchangeTargetSku);\n },\n };\n}\n\n/**\n * JSON, or multipart when a photo is attached (`products` as JSON text plus one\n * `request_media_<row index>` file per photo, orders/views.py:4613-4646). Never sends a row\n * `price`: the backend would take it as the settlement price.\n */\nfunction exchangeBody({ orderId, type, reason, items }: CreateExchangeInput): RequestOptions {\n if (items.length === 0) throw new TypeError('exchanges.create: items must not be empty.');\n if (items.some((item) => !(item.quantity >= 1))) {\n throw new RangeError('exchanges.create: every quantity must be at least 1.');\n }\n if (type === 'exchange' && items.some((item) => item.targetSkuId === undefined)) {\n throw new TypeError('exchanges.create: every exchange item needs a targetSkuId.');\n }\n const products = items.map((item) => ({\n order_product_id: item.orderLineId,\n qty: item.quantity,\n ...(type === 'exchange' ? { target_sku_id: item.targetSkuId } : {}),\n ...(item.reason !== undefined ? { requested_message: item.reason } : {}),\n }));\n if (items.every((item) => item.photo === undefined)) {\n return { json: { order_id: orderId, type, requested_message: reason, products } };\n }\n const files = Object.fromEntries(\n items.map((item, index) => [\n `request_media_${index}`,\n item.photo === undefined ? undefined : { file: item.photo },\n ]),\n );\n return {\n formData: multipart(\n { order_id: orderId, type, requested_message: reason, products: JSON.stringify(products) },\n files,\n 'Exchange photo',\n ),\n };\n}\n\n// Wire → domain. Exported for tests only (not part of the package's public API).\n\nexport function toExchangeResult(wire: WireExchangeCreated): ExchangeResult {\n // Cash on delivery: the backend answers `pay` with a `cod` entry, collected on delivery.\n if (wire.action === 'pay' && wire.payment.type !== 'cod') {\n return { status: 'payment-required', id: wire.id, payment: toPendingPayment(wire.payment) };\n }\n return { status: 'submitted', id: wire.id, message: text(wire.message) };\n}\n\nexport function toExchangeTargetSku(wire: WireExchangeTargetSku): ExchangeTargetSku {\n return {\n skuId: wire.id,\n skuCode: wire.sku,\n name: wire.product_name,\n photo: text(wire.product_photo),\n price: amount(wire.price) ?? 0,\n stockQty: wire.stock_qty,\n };\n}\n\nfunction toExchangeListItem(wire: WireExchangeListItem): ExchangeListItem {\n return {\n id: wire.id,\n type: wire.type,\n status: wire.status,\n createdAt: wire.created_at,\n paymentId: wire.payment_id,\n itemCount: wire.products_count,\n };\n}\n\nexport function toExchangeDetail(wire: WireExchangeDetail): ExchangeDetail {\n return {\n ...toExchangeListItem({ ...wire, products_count: wire.products.length }),\n items: wire.products.map((row) => ({\n orderLineId: row.order_product,\n name: text(row.original_sku?.product_name),\n targetSkuId: row.target_sku,\n quantity: row.qty,\n priceDifference: amount(row.price_difference) ?? 0,\n status: row.status,\n })),\n };\n}\n","import type { Query } from './types';\n\n/**\n * Builds `?a=1&b=2` without `URLSearchParams` (incomplete on React Native, ADR-009).\n * Skips `undefined`, `null`, `''` and empty lists. Lists are comma-joined in one parameter,\n * which is how the backend reads them (e.g. `category_ids=1,2,3`).\n */\nexport function buildQuery(query: Query | undefined): string {\n if (!query) return '';\n const parts: string[] = [];\n for (const [key, raw] of Object.entries(query)) {\n if (raw === undefined || raw === null || raw === '') continue;\n let value: string;\n if (Array.isArray(raw)) {\n if (raw.length === 0) continue;\n value = raw.join(',');\n } else {\n value = String(raw);\n }\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n }\n return parts.length > 0 ? `?${parts.join('&')}` : '';\n}\n","import { type BlogApi, createBlogApi } from './blog';\nimport { type BusinessApi, createBusinessApi } from './business';\nimport { type CartApi, createCartApi } from './cart';\nimport { type CatalogApi, createCatalogApi } from './catalog';\nimport { createFaqApi, type FaqApi } from './faq';\nimport { createFormsApi, type FormsApi } from './forms';\nimport { createHelpdeskApi, type HelpdeskApi } from './helpdesk';\nimport { createNewsletterApi, type NewsletterApi } from './newsletter';\nimport { createPushApi, type PushApi } from './push';\nimport { createLiveSupportApi, type LiveSupportApi } from './live-support';\nimport { createPoliciesApi, type PoliciesApi } from './policies';\nimport { createProductPageApi, type ProductPageApi } from './productPage';\nimport { createProductsApi, type ProductsApi } from './products';\nimport { createPromotionsApi, type PromotionsApi } from './promotions';\nimport { createReviewsApi, type ReviewsApi } from './reviews';\nimport { createWishlistApi, type WishlistApi } from './wishlist';\nimport { createThemeContentApi, type ThemeContentApi } from './theme-content';\nimport { createCustomPagesApi, type CustomPagesApi } from './customPages';\nimport { createSessionApi, type SessionApi } from './session';\nimport { createLookupApi, type LookupApi } from './lookup';\nimport { type AuthApi, createAuthApi } from './auth';\nimport { createCustomerApi, type CustomerApi } from './customer';\nimport { type AddressesApi, createAddressesApi } from './addresses';\nimport { type CheckoutApi, createCheckoutApi } from './checkout';\nimport { createPaymentsApi, type PaymentsApi } from './payments';\nimport { createCustomManufacturingApi, type CustomManufacturingApi } from './custom-manufacturing';\nimport { createSubscriptionsApi, type SubscriptionsApi } from './subscriptions';\nimport { createOrdersApi, type OrdersApi } from './orders';\nimport { createReturnsApi, type ReturnsApi } from './returns';\nimport { createExchangesApi, type ExchangesApi } from './exchanges';\nimport {\n fieldErrorsFromBody,\n GrowupsellApiError,\n messageFromBody,\n parseRetryAfter,\n} from './errors';\nimport { buildQuery } from './query';\nimport type {\n BinaryResponse,\n ClientOptions,\n Credentials,\n FetchInitLike,\n FetchLike,\n FetchResponseLike,\n HttpMethod,\n RequestFn,\n RequestOptions,\n UnauthorizedEvent,\n} from './types';\n\nexport interface Client {\n /** Low-level request; prefer the domain modules below. */\n request: RequestFn;\n business: BusinessApi;\n catalog: CatalogApi;\n products: ProductsApi;\n reviews: ReviewsApi;\n wishlist: WishlistApi;\n policies: PoliciesApi;\n faq: FaqApi;\n themeContent: ThemeContentApi;\n /** Merchant-built product-page content: sections and blocks. */\n productPage: ProductPageApi;\n /** Merchant-built storefront pages (e.g. `/about-us`): hero and sections. */\n customPages: CustomPagesApi;\n /** Guest sessions (`x-session-token`). */\n session: SessionApi;\n /** Countries and states for the address form. */\n lookup: LookupApi;\n /** Signed-out customer flows: settings, sign-up, login, OTP, password reset. */\n auth: AuthApi;\n /** The logged-in customer's own account: profile, password, email and phone. */\n customer: CustomerApi;\n /** The logged-in customer's saved addresses. */\n addresses: AddressesApi;\n /** Checkout: order settings, placing the order, made-to-order advance orders. */\n checkout: CheckoutApi;\n /** Confirming payments: PhonePe, Stripe, Razorpay, bank transfer proof. */\n payments: PaymentsApi;\n blog: BlogApi;\n forms: FormsApi;\n helpdesk: HelpdeskApi;\n /** Email newsletter sign-up (backend `/subscribers/`). */\n newsletter: NewsletterApi;\n /** Web push subscriptions; the app does the browser work and passes the subscription in. */\n push: PushApi;\n liveSupport: LiveSupportApi;\n /** File uploads for custom-manufacturing form fields (logged-in customer). */\n customManufacturing: CustomManufacturingApi;\n /** A customer's product subscriptions: deliveries, pauses, invoices. */\n subscriptions: SubscriptionsApi;\n /** The shopper's cart (customer or guest session). */\n cart: CartApi;\n /** Offers, promo codes, gift cards and reward point settings. */\n promotions: PromotionsApi;\n /** The logged-in customer's placed orders: history, shipments, invoices, COD cancellation. */\n orders: OrdersApi;\n /** Return requests of the logged-in customer's orders. */\n returns: ReturnsApi;\n /** Replacement and exchange requests of the logged-in customer's orders. */\n exchanges: ExchangesApi;\n}\n\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\n/**\n * The runtime features this module uses. All exist in browsers, React Native and Node 18+.\n * Read from `globalThis` with local types because `commerce` compiles without DOM/Node types.\n */\ninterface Runtime {\n fetch?: FetchLike;\n setTimeout(handler: () => void, ms: number): unknown;\n clearTimeout(timer: unknown): void;\n AbortController?: new () => { readonly signal: unknown; abort(): void };\n}\nconst runtime = globalThis as unknown as Runtime;\n\n/**\n * Creates an HTTP client for the Growupsell backend (ADR-008, ADR-015).\n * Stateless apart from remembering which rejected token it already reported.\n */\nexport function createClient(options: ClientOptions): Client {\n if (!options.baseURL) throw new Error('createClient: baseURL is required.');\n if (!options.fetch && typeof runtime.fetch !== 'function') {\n throw new Error('createClient: no global fetch in this runtime; pass the `fetch` option.');\n }\n\n const baseURL = options.baseURL.replace(/\\/+$/, '');\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n // Called as a method of globalThis: browsers throw \"Illegal invocation\" for an unbound fetch.\n const doFetch: FetchLike = options.fetch\n ? (url, init) => options.fetch!(url, init as never)\n : (url, init) => runtime.fetch!(url, init);\n const reported: Partial<Record<UnauthorizedEvent['kind'], string>> = {};\n\n async function request<T>(\n method: HttpMethod,\n path: string,\n opts: RequestOptions = {},\n ): Promise<T> {\n const credentials: Credentials = (await options.credentials?.()) ?? {};\n if (\n opts.business === 'required' &&\n (credentials.businessId == null || credentials.businessId === '')\n ) {\n throw new Error(\n `${method} ${path} needs the business: return businessId from credentials().`,\n );\n }\n if (opts.session === 'required' && !credentials.sessionToken) {\n throw new Error(\n `${method} ${path} needs a guest session: return sessionToken from credentials().`,\n );\n }\n if (opts.customer === 'required' && !credentials.customerToken) {\n throw new Error(\n `${method} ${path} needs a logged-in customer: return customerToken from credentials().`,\n );\n }\n if (opts.merchant && !credentials.merchantToken) {\n throw new Error(\n `${method} ${path} is a merchant request: return merchantToken from credentials().`,\n );\n }\n const headers = buildHeaders(credentials, opts);\n const binary = opts.responseType === 'binary';\n if (binary) headers.accept = '*/*';\n // Decided from the headers actually sent, so options that leave a token out count.\n if (\n opts.customerOrSession === 'required' &&\n !headers['x-customer-token'] &&\n !headers['x-session-token']\n ) {\n throw new Error(\n `${method} ${path} needs a customer or a guest session: return customerToken or sessionToken from credentials().`,\n );\n }\n const init: FetchInitLike = { method, headers };\n if (opts.formData) {\n init.body = opts.formData;\n } else if (opts.json !== undefined) {\n headers['content-type'] = 'application/json';\n init.body = JSON.stringify(opts.json);\n }\n\n const url = `${baseURL}/${path.replace(/^\\/+/, '')}${buildQuery(opts.query)}`;\n const res = await send(url, init, opts.timeoutMs ?? timeoutMs, binary);\n const { status, ok, text, data } = res;\n // Any response, successful or not, can say the session is gone (ADR-027).\n if (headers['x-session-token'] && sessionMarkedInvalid(res.headers)) {\n report('session', headers['x-session-token']);\n }\n if (data) return data as T;\n const body = parseBody(text, ok, status);\n\n if (ok) return body as T;\n\n if (status === 401) reportUnauthorized(headers);\n if (isDeadSession(status, body, headers)) report('session', headers['x-session-token']!);\n throw new GrowupsellApiError({\n kind: 'http',\n status,\n message: messageFromBody(body) ?? `Request failed with status ${status}`,\n fieldErrors: fieldErrorsFromBody(body),\n body,\n retryAfterSeconds: status === 429 ? parseRetryAfter(res.headers?.get('retry-after')) : null,\n });\n }\n\n async function send(url: string, init: FetchInitLike, ms: number, binary: boolean) {\n const controller = runtime.AbortController ? new runtime.AbortController() : undefined;\n if (controller) init.signal = controller.signal;\n let timedOut = false;\n let timer: unknown;\n const timeout = new Promise<never>((_, reject) => {\n timer = runtime.setTimeout(() => {\n timedOut = true;\n controller?.abort();\n reject(timeoutError(ms));\n }, ms);\n });\n\n try {\n return await Promise.race([\n doFetch(url, init).then(async (res) => ({\n status: res.status,\n ok: res.ok,\n headers: res.headers,\n // Error responses are read as text even for binary requests: they carry the message.\n text: binary && res.ok ? '' : await res.text(),\n data: binary && res.ok ? await readBinary(res) : undefined,\n })),\n timeout,\n ]);\n } catch (error) {\n if (timedOut) throw timeoutError(ms);\n if (error instanceof GrowupsellApiError) throw error;\n throw new GrowupsellApiError({\n kind: 'network',\n message: error instanceof Error ? error.message : 'Network request failed',\n });\n } finally {\n runtime.clearTimeout(timer);\n }\n }\n\n /** Decides from the headers actually sent which token the backend rejected. */\n function reportUnauthorized(headers: Record<string, string>) {\n const merchant = headers.authorization?.replace(/^Token /, '');\n const customer = headers['x-customer-token'];\n const kind: UnauthorizedEvent['kind'] | undefined = merchant\n ? 'merchant'\n : customer\n ? 'customer'\n : undefined;\n // No token sent: nothing expired, and reacting would risk a login loop.\n if (!kind) return;\n report(kind, (kind === 'merchant' ? merchant : customer)!);\n }\n\n function report(kind: UnauthorizedEvent['kind'], token: string) {\n // Parallel requests with the same rejected token report it once.\n if (reported[kind] === token) return;\n reported[kind] = token;\n options.onUnauthorized?.({ kind, token });\n }\n\n return {\n request,\n business: createBusinessApi(request),\n catalog: createCatalogApi(request),\n products: createProductsApi(request),\n reviews: createReviewsApi(request),\n wishlist: createWishlistApi(request),\n policies: createPoliciesApi(request),\n faq: createFaqApi(request),\n themeContent: createThemeContentApi(request),\n productPage: createProductPageApi(request),\n customPages: createCustomPagesApi(request),\n session: createSessionApi(request),\n lookup: createLookupApi(request),\n auth: createAuthApi(request),\n customer: createCustomerApi(request),\n addresses: createAddressesApi(request),\n checkout: createCheckoutApi(request),\n payments: createPaymentsApi(request),\n blog: createBlogApi(request),\n forms: createFormsApi(request),\n helpdesk: createHelpdeskApi(request),\n newsletter: createNewsletterApi(request),\n push: createPushApi(request),\n liveSupport: createLiveSupportApi(request),\n customManufacturing: createCustomManufacturingApi(request),\n subscriptions: createSubscriptionsApi(request),\n cart: createCartApi(request),\n promotions: createPromotionsApi(request),\n orders: createOrdersApi(request),\n returns: createReturnsApi(request),\n exchanges: createExchangesApi(request),\n };\n}\n\nfunction buildHeaders(credentials: Credentials, opts: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = { accept: 'application/json' };\n if (credentials.businessId != null && credentials.businessId !== '') {\n headers.business = String(credentials.businessId);\n }\n if (credentials.customerToken && !opts.anonymous) {\n headers['x-customer-token'] = credentials.customerToken;\n }\n if (credentials.sessionToken && opts.session !== 'omit') {\n headers['x-session-token'] = credentials.sessionToken;\n }\n if (opts.merchant && credentials.merchantToken) {\n headers.authorization = `Token ${credentials.merchantToken}`;\n }\n return headers;\n}\n\n/**\n * A dead guest session (ADR-023, T1.4 decision 1). The backend looks the `x-session-token` up in its\n * database before any view runs and answers an unknown one with Django's HTML 404 page on\n * every endpoint, public ones included (SessionApiMiddleware; backend issue C15). DRF's own\n * \"not found\" answers are JSON, so a 404 that is not JSON on a request that sent a session\n * token means the session is gone.\n */\nfunction isDeadSession(status: number, body: unknown, headers: Record<string, string>) {\n return status === 404 && typeof body === 'string' && !!headers['x-session-token'];\n}\n\n/**\n * The fixed backend (C15/C27, ADR-027) runs a request with an unknown `x-session-token` as a\n * guest and adds `x-session-status: invalid` to the response. `headers` is optional on\n * custom fetches; without it only the HTML 404 above can tell.\n */\nfunction sessionMarkedInvalid(headers: FetchResponseLike['headers']) {\n return headers?.get('x-session-status')?.trim().toLowerCase() === 'invalid';\n}\n\nfunction parseBody(text: string, ok: boolean, status: number): unknown {\n if (text === '') return undefined;\n try {\n return JSON.parse(text);\n } catch {\n if (!ok) return text; // Error pages are often plain text or HTML.\n throw new GrowupsellApiError({\n kind: 'parse',\n status,\n message: 'The server returned a response that is not valid JSON.',\n body: text,\n });\n }\n}\n\nasync function readBinary(res: FetchResponseLike): Promise<BinaryResponse> {\n if (!res.arrayBuffer) {\n throw new GrowupsellApiError({\n kind: 'parse',\n status: res.status,\n message: 'This fetch cannot read binary responses.',\n });\n }\n return { contentType: res.headers?.get('content-type') ?? null, data: await res.arrayBuffer() };\n}\n\nfunction timeoutError(ms: number) {\n return new GrowupsellApiError({ kind: 'timeout', message: `Request timed out after ${ms} ms` });\n}\n"],"mappings":"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","names":["text","PUBLIC","MERCHANT","PUBLIC","toCategory","PUBLIC","MERCHANT","PUBLIC","MERCHANT","path","PUBLIC","PUBLIC","PUBLIC","MERCHANT","required","PUBLIC","MERCHANT","PUBLIC","DEFAULT_LIMIT","SHOPPER","DEFAULT_LIMIT","PUBLIC","PUBLIC_BUSINESS","CUSTOMER","PUBLIC","MERCHANT","themeId","PUBLIC","MERCHANT","path","PUBLIC","CUSTOMER","CUSTOMER","PUBLIC_BUSINESS","CUSTOMER_BUSINESS","PUBLIC_BUSINESS","CUSTOMER_BUSINESS","CUSTOMER_BUSINESS","DEFAULT_LIMIT","CUSTOMER","CUSTOMER","DEFAULT_LIMIT","path","sum","CUSTOMER","CUSTOMER","runtime","path","status","text"]}
|