@shoppexio/storefront 1.0.76 → 1.0.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/customer.cjs +1 -1
- package/dist/customer.cjs.map +1 -1
- package/dist/customer.d.cts +1 -1
- package/dist/customer.d.ts +1 -1
- package/dist/customer.js +1 -1
- package/dist/customer.js.map +1 -1
- package/dist/index.cjs +12 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/customer.d.cts
CHANGED
|
@@ -115,7 +115,7 @@ interface HeadlessCustomerNotificationPreferencesPatch {
|
|
|
115
115
|
paymentIssueEmails?: boolean;
|
|
116
116
|
}
|
|
117
117
|
interface HeadlessCustomerReplacementOptions {
|
|
118
|
-
lineItemId
|
|
118
|
+
lineItemId: string;
|
|
119
119
|
reason: string;
|
|
120
120
|
idempotencyKey?: string;
|
|
121
121
|
}
|
package/dist/customer.d.ts
CHANGED
|
@@ -115,7 +115,7 @@ interface HeadlessCustomerNotificationPreferencesPatch {
|
|
|
115
115
|
paymentIssueEmails?: boolean;
|
|
116
116
|
}
|
|
117
117
|
interface HeadlessCustomerReplacementOptions {
|
|
118
|
-
lineItemId
|
|
118
|
+
lineItemId: string;
|
|
119
119
|
reason: string;
|
|
120
120
|
idempotencyKey?: string;
|
|
121
121
|
}
|
package/dist/customer.js
CHANGED
|
@@ -419,7 +419,7 @@ var HeadlessCustomerClient = class {
|
|
|
419
419
|
method: "POST",
|
|
420
420
|
authenticated: true,
|
|
421
421
|
body: {
|
|
422
|
-
line_item_id: options.lineItemId
|
|
422
|
+
line_item_id: options.lineItemId,
|
|
423
423
|
reason: options.reason,
|
|
424
424
|
...options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}
|
|
425
425
|
},
|
package/dist/customer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../sdk/src/headless-customer.ts"],"sourcesContent":["/**\n * Browser client for a customer account hosted outside Shoppex.\n *\n * The publishable key identifies the merchant and the dashboard origin\n * allowlist authorizes the browser origin. OTP verification returns a separate\n * short-lived `hcs_` token; the SDK never exposes Shoppex's BetterAuth token.\n */\nimport {\n customerLoyaltyRedeemSchema,\n customerLoyaltySchema,\n customerPortalAffiliateSummarySchema,\n customerPortalAffiliateStatsSchema,\n customerPortalAffiliateCreateLinkSchema,\n customerPortalAvatarSchema,\n customerPortalDashboardSchema,\n customerPortalEmailPreferencesSchema,\n customerPortalEmailPreferencesUpdateSchema,\n customerPortalFavoriteMutationSchema,\n customerPortalFavoritesSchema,\n customerPortalInvoiceDetailSchema,\n customerPortalLicenseResetSchema,\n customerPortalLicenseRenewalSchema,\n customerPortalMeSchema,\n customerPortalNotificationPreferencesSchema,\n customerPortalOrderReviewSchema,\n customerPortalPaginatedInvoicesSchema,\n customerPortalProfileUpdateSchema,\n customerPortalSubscriptionBillingHistorySchema,\n customerPortalSubscriptionCancelSchema,\n customerPortalSubscriptionStatusSchema,\n customerPortalSupportCreateSchema,\n customerPortalSupportTicketDetailSchema,\n customerPortalWalletTopupQuoteSchema,\n customerPortalWalletTopupResultSchema,\n customerReplacementEligibilitySchema,\n customerReplacementRequestSchema,\n customerResellerApiKeysSchema,\n customerResellerCatalogSchema,\n customerResellerEnrollmentSchema,\n customerResellerOrderSchema,\n customerResellerOrdersSchema,\n customerResellerQuoteSchema,\n customerResellerSummarySchema,\n customerResellerTopupSchema,\n customerResellerWalletSchema,\n customerWarrantyClaimSchema,\n customerWarrantyListSchema,\n type CustomerLoyaltyRedeemWire,\n type CustomerLoyaltyWire,\n type CustomerPortalAffiliateSummaryWire,\n type CustomerPortalAffiliateStatsWire,\n type CustomerPortalAffiliateCreateLinkWire,\n type CustomerPortalAvatarWire,\n type CustomerPortalDashboardWire,\n type CustomerPortalEmailPreferencesUpdateWire,\n type CustomerPortalEmailPreferencesWire,\n type CustomerPortalFavoriteMutationWire,\n type CustomerPortalFavoritesWire,\n type CustomerPortalLicenseResetWire,\n type CustomerPortalLicenseRenewalWire,\n type CustomerPortalNotificationPreferencesWire,\n type CustomerPortalOrderReviewWire,\n type CustomerPortalProfileUpdateWire,\n type CustomerPortalSubscriptionBillingHistoryWire,\n type CustomerPortalSubscriptionCancelWire,\n type CustomerPortalSubscriptionStatusWire,\n type CustomerPortalSupportCreateWire,\n type CustomerPortalSupportTicketDetailWire,\n type CustomerPortalWalletTopupQuoteWire,\n type CustomerPortalWalletTopupResultWire,\n type CustomerReplacementEligibilityWire,\n type CustomerReplacementRequestWire,\n type CustomerResellerApiKeysWire,\n type CustomerResellerCatalogWire,\n type CustomerResellerEnrollmentWire,\n type CustomerResellerOrderWire,\n type CustomerResellerOrdersWire,\n type CustomerResellerQuoteWire,\n type CustomerResellerSummaryWire,\n type CustomerResellerTopupWire,\n type CustomerResellerWalletWire,\n type CustomerWarrantyClaimWire,\n type CustomerWarrantyListWire,\n} from '@shoppex/contracts/customer-portal-wire';\n\nconst DEFAULT_API_ORIGIN = 'https://api.shoppex.io';\nconst SESSION_STORAGE_PREFIX = 'shoppex_headless_customer_session:';\n\ninterface CustomerPayloadSchema<T> {\n safeParse(value: unknown): { success: true; data: T } | { success: false };\n}\n\ninterface ApiEnvelope<T> {\n status: number;\n data: T | null;\n error: string | null;\n message?: string | null;\n error_code?: string | null;\n}\n\ninterface StoredSession {\n accessToken: string;\n expiresAt: string;\n savedAt: number;\n}\n\nexport interface HeadlessCustomerClientConfig {\n /** Shop slug or Shoppex storefront domain. */\n shop: string;\n /** Existing Headless Checkout publishable key (`pk_live_` / `pk_test_`). */\n publishableKey: string;\n /** API origin override. Defaults to https://api.shoppex.io. */\n apiBaseUrl?: string;\n /** Optional fetch override for tests or compatible runtimes. */\n fetchImpl?: typeof fetch;\n /** Optional session storage override. Defaults to browser sessionStorage. */\n storage?: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;\n /** Optional persistent storage override. Defaults to browser localStorage. */\n persistentStorage?: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;\n}\n\nexport interface HeadlessCustomerSession {\n accessToken: string;\n expiresAt: string;\n}\n\nexport interface HeadlessCustomerVerifyOptions {\n /** Persist the customer session across browser restarts for up to 30 days. */\n rememberMe?: boolean;\n}\n\nexport interface HeadlessCustomerOrdersQuery {\n page?: number;\n limit?: number;\n status?: string;\n search?: string;\n}\n\nexport interface HeadlessCustomerDownload {\n blob: Blob;\n filename: string | null;\n contentType: string | null;\n}\n\ntype HeadlessCustomerDashboardDeliverable =\n CustomerPortalDashboardWire['deliverables'][number] & {\n /** Pass this value with `invoice_uniqid` to `customer.download()`. */\n downloadIndex?: number | null;\n };\n\nexport type HeadlessCustomerDashboard = Omit<CustomerPortalDashboardWire, 'deliverables'> & {\n deliverables: HeadlessCustomerDashboardDeliverable[];\n};\nexport type HeadlessCustomerProfileUpdate = CustomerPortalProfileUpdateWire;\nexport type HeadlessCustomerAvatar = CustomerPortalAvatarWire;\nexport type HeadlessCustomerEmailPreferences = CustomerPortalEmailPreferencesWire;\nexport type HeadlessCustomerEmailPreferencesUpdate = CustomerPortalEmailPreferencesUpdateWire;\nexport type HeadlessCustomerNotificationPreferences = CustomerPortalNotificationPreferencesWire;\nexport type HeadlessCustomerOrderReview = CustomerPortalOrderReviewWire;\nexport type HeadlessCustomerFavorites = CustomerPortalFavoritesWire;\nexport type HeadlessCustomerFavoriteMutation = CustomerPortalFavoriteMutationWire;\nexport type HeadlessCustomerAffiliate = CustomerPortalAffiliateSummaryWire;\nexport type HeadlessCustomerAffiliateStats = CustomerPortalAffiliateStatsWire;\nexport type HeadlessCustomerAffiliateLink = CustomerPortalAffiliateCreateLinkWire;\nexport type HeadlessCustomerTicket = CustomerPortalSupportTicketDetailWire;\nexport type HeadlessCustomerTicketCreateResult = CustomerPortalSupportCreateWire;\nexport type HeadlessCustomerLicenseReset = CustomerPortalLicenseResetWire;\nexport type HeadlessCustomerLicenseRenewal = CustomerPortalLicenseRenewalWire;\nexport type HeadlessCustomerWalletTopupQuote = CustomerPortalWalletTopupQuoteWire;\nexport type HeadlessCustomerWalletTopup = CustomerPortalWalletTopupResultWire;\nexport type HeadlessCustomerSubscriptionBillingHistory = CustomerPortalSubscriptionBillingHistoryWire;\nexport type HeadlessCustomerSubscriptionCancel = CustomerPortalSubscriptionCancelWire;\nexport type HeadlessCustomerSubscriptionStatus = CustomerPortalSubscriptionStatusWire;\nexport type HeadlessCustomerLoyalty = CustomerLoyaltyWire;\nexport type HeadlessCustomerLoyaltyRedeem = CustomerLoyaltyRedeemWire;\nexport type HeadlessCustomerWarranties = CustomerWarrantyListWire;\nexport type HeadlessCustomerWarrantyClaim = CustomerWarrantyClaimWire;\nexport type HeadlessCustomerReplacementEligibility = CustomerReplacementEligibilityWire;\nexport type HeadlessCustomerReplacementRequest = CustomerReplacementRequestWire;\nexport type HeadlessCustomerReseller = CustomerResellerSummaryWire;\nexport type HeadlessCustomerResellerEnrollment = CustomerResellerEnrollmentWire;\nexport type HeadlessCustomerResellerCatalog = CustomerResellerCatalogWire;\nexport type HeadlessCustomerResellerQuote = CustomerResellerQuoteWire;\nexport type HeadlessCustomerResellerOrders = CustomerResellerOrdersWire;\nexport type HeadlessCustomerResellerOrder = CustomerResellerOrderWire;\nexport type HeadlessCustomerResellerWallet = CustomerResellerWalletWire;\nexport type HeadlessCustomerResellerApiKeys = CustomerResellerApiKeysWire;\nexport type HeadlessCustomerResellerTopup = CustomerResellerTopupWire;\n\nexport interface HeadlessCustomerTicketInput {\n title?: string;\n message: string;\n invoiceId?: string;\n}\n\nexport interface HeadlessCustomerOrderReviewInput {\n score: 1 | 3 | 5;\n message: string;\n}\n\nexport interface HeadlessCustomerAffiliateLinkInput {\n code: string;\n label: string;\n requestedRevenuePercent?: number | null;\n requestedCustomerDiscountPercent?: number | null;\n}\n\nexport interface HeadlessCustomerSubscriptionCancelOptions {\n cancelAtPeriodEnd?: boolean;\n reason?: string | null;\n}\n\nexport interface HeadlessCustomerEmailPreferencesPatch {\n globalUnsubscribed?: boolean;\n listSubscriptions?: Array<{ listId: string; subscribed: boolean }>;\n}\n\nexport interface HeadlessCustomerNotificationPreferencesPatch {\n orderCreatedEmails?: boolean;\n orderCompletedEmails?: boolean;\n paymentIssueEmails?: boolean;\n}\n\nexport interface HeadlessCustomerReplacementOptions {\n lineItemId?: string | null;\n reason: string;\n idempotencyKey?: string;\n}\n\nexport interface HeadlessCustomerResellerCatalogQuery {\n search?: string;\n page?: number;\n perPage?: number;\n}\n\nexport interface HeadlessCustomerResellerOrdersQuery {\n page?: number;\n perPage?: number;\n}\n\nexport interface HeadlessCustomerResellerOrderItem {\n productId: string;\n variantId?: string;\n quantity: number;\n}\n\n/** Public DTOs mirror the producer-owned schemas imported above. Passing each\n * schema into `request<T>` makes TypeScript reject drift in required fields. */\nexport interface HeadlessCustomerMe {\n customer: {\n id: string | null;\n email: string;\n name: string;\n avatar_url: string | null;\n joined_at: string | null;\n };\n shop: {\n id: string;\n slug: string;\n name: string;\n currency: string;\n branding: {\n logo_url: string | null;\n primary_color: string;\n secondary_color: string;\n accent_color: string;\n };\n };\n}\n\ntype HeadlessCustomerMeWire = HeadlessCustomerMe & { token: string | null };\n\nexport interface HeadlessCustomerOrderSummary {\n uniqid: string;\n status: string;\n total: string;\n totalDisplay: string | null;\n currency: string;\n createdAt: string;\n lineItems: Array<{\n productTitle: string | null;\n quantity: number;\n product: {\n attachment_imageId: { cloudflareImageId: string | null } | null;\n } | null;\n }>;\n}\n\nexport interface HeadlessCustomerOrders {\n invoices: HeadlessCustomerOrderSummary[];\n pagination: {\n page: number;\n limit: number;\n total: number;\n has_more: boolean;\n };\n}\n\nexport interface HeadlessCustomerPayment {\n gateway: string;\n displayName: string | null;\n cryptoGateway?: string | null;\n blockchain: string | null;\n cryptoAddress: string | null;\n apmMethod: string | null;\n}\n\nexport interface HeadlessCustomerOrder {\n id: string;\n uniqid: string;\n status: string;\n statusDetails: string | null;\n total: string;\n totalDisplay: string | null;\n subtotal: string;\n discount: string;\n discountDisplay: string | null;\n tax: string;\n taxPercentage: string;\n currency: string;\n createdAt: string;\n updatedAt: string;\n gatewayUpdatedAt: string | null;\n customFields: Record<string, unknown> | null;\n balancePaidAmount: string;\n currentPaymentAttemptId: string | null;\n lineItems: Array<{\n id: string;\n productTitle: string;\n productType: string;\n variantTitle: string | null;\n unitPrice: string;\n quantity: number;\n total: string;\n deliveryText: string | null;\n deliverySummary: {\n codes: string[];\n links: Array<{\n label: string;\n value: string;\n /** External URL for non-Shoppex links. Portal-only download URLs are removed. */\n href?: string | null;\n /** Pass this value to `customer.download(orderId, downloadIndex)`. */\n downloadIndex?: number | null;\n }>;\n notes: string[];\n serials: Array<{ value: string; is_replacement: boolean; is_replaced: boolean }>;\n } | null;\n deliveredAt: string | null;\n deliveryStatus: 'PENDING' | 'AWAITING_FULFILLMENT' | 'DELIVERED' | 'FAILED';\n customFields: Record<string, unknown> | null;\n product: {\n uniqid: string;\n slug: string | null;\n serviceText: string | null;\n attachment_imageId: { cloudflareImageId: string | null } | null;\n } | null;\n }>;\n currentPayment: HeadlessCustomerPayment | null;\n payments: HeadlessCustomerPayment[];\n}\n\nexport class HeadlessCustomerError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly code?: string | null,\n ) {\n super(message);\n this.name = 'HeadlessCustomerError';\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseStoredSession(value: string | null): StoredSession | null {\n if (!value) return null;\n try {\n const parsed: unknown = JSON.parse(value);\n if (\n !isRecord(parsed)\n || typeof parsed.accessToken !== 'string'\n || !parsed.accessToken.startsWith('hcs_')\n || typeof parsed.expiresAt !== 'string'\n || typeof parsed.savedAt !== 'number'\n || !Number.isFinite(parsed.savedAt)\n ) {\n return null;\n }\n const expiresAtMs = Date.parse(parsed.expiresAt);\n if (!Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now()) return null;\n return { accessToken: parsed.accessToken, expiresAt: parsed.expiresAt, savedAt: parsed.savedAt };\n } catch {\n return null;\n }\n}\n\nfunction readFilename(header: string | null): string | null {\n if (!header) return null;\n const utf8Match = header.match(/filename\\*=UTF-8''([^;]+)/i);\n if (utf8Match?.[1]) {\n try {\n return decodeURIComponent(utf8Match[1]);\n } catch {\n return utf8Match[1];\n }\n }\n return header.match(/filename=\"([^\"]+)\"/i)?.[1] ?? null;\n}\n\nfunction readPortalDownloadIndex(href: string | null | undefined): number | null {\n // Only relative URLs are owned by the Shoppex customer portal. An external\n // site may legitimately use the same pathname and must remain an external link.\n if (!href?.startsWith('/api/customer/')) return null;\n try {\n const url = new URL(href, 'https://headless-customer.invalid');\n if (!/^\\/api\\/customer\\/invoice\\/[^/]+\\/download$/.test(url.pathname)) return null;\n const rawIndex = url.searchParams.get('file_index');\n if (rawIndex === null || !/^\\d+$/.test(rawIndex)) return null;\n const index = Number(rawIndex);\n return Number.isSafeInteger(index) ? index : null;\n } catch {\n return null;\n }\n}\n\nfunction readBrowserStorage(name: 'sessionStorage' | 'localStorage'):\n Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null {\n try {\n return typeof window === 'undefined' ? null : window[name];\n } catch {\n return null;\n }\n}\n\nexport class HeadlessCustomerClient {\n private readonly base: string;\n private readonly shop: string;\n private readonly publishableKey: string;\n private readonly fetchImpl: typeof fetch;\n private readonly storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null;\n private readonly persistentStorage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null;\n private readonly storageKey: string;\n private memorySession: StoredSession | null = null;\n\n constructor(config: HeadlessCustomerClientConfig) {\n if (!config.shop.trim()) throw new Error('HeadlessCustomerClient requires a shop.');\n if (!config.publishableKey.trim()) {\n throw new Error('HeadlessCustomerClient requires a publishableKey.');\n }\n this.shop = config.shop.trim();\n this.publishableKey = config.publishableKey.trim();\n this.base = (config.apiBaseUrl ?? DEFAULT_API_ORIGIN).replace(/\\/+$/, '');\n this.fetchImpl = config.fetchImpl ?? globalThis.fetch?.bind(globalThis);\n if (!this.fetchImpl) throw new Error('No fetch implementation available; pass fetchImpl.');\n this.storage = config.storage ?? readBrowserStorage('sessionStorage');\n this.persistentStorage = config.persistentStorage ?? readBrowserStorage('localStorage');\n this.storageKey = `${SESSION_STORAGE_PREFIX}${this.shop}`;\n }\n\n getSession(): HeadlessCustomerSession | null {\n const candidates: StoredSession[] = this.memorySession ? [this.memorySession] : [];\n if (this.storage) {\n try {\n const stored = parseStoredSession(this.storage.getItem(this.storageKey));\n if (stored) candidates.push(stored);\n } catch {\n // Continue with memory and persistent storage.\n }\n }\n if (this.persistentStorage) {\n try {\n const stored = parseStoredSession(this.persistentStorage.getItem(this.storageKey));\n if (stored) candidates.push(stored);\n } catch {\n // Continue with the other available stores.\n }\n }\n\n const stored = candidates.sort((left, right) => right.savedAt - left.savedAt)[0] ?? null;\n\n if (!stored) {\n this.clearSession();\n return null;\n }\n this.memorySession = stored;\n return { accessToken: stored.accessToken, expiresAt: stored.expiresAt };\n }\n\n clearSession(): void {\n this.memorySession = null;\n try {\n this.storage?.removeItem(this.storageKey);\n } catch {\n // Privacy-restricted browsers may reject storage access. Memory is still cleared.\n }\n try {\n this.persistentStorage?.removeItem(this.storageKey);\n } catch {\n // The two stores are cleared independently so one rejected access cannot block the other.\n }\n }\n\n private saveSession(session: HeadlessCustomerSession, rememberMe: boolean): void {\n const storedSession: StoredSession = { ...session, savedAt: Date.now() };\n this.memorySession = storedSession;\n const target = rememberMe ? this.persistentStorage : this.storage;\n const other = rememberMe ? this.storage : this.persistentStorage;\n try {\n target?.setItem(this.storageKey, JSON.stringify(storedSession));\n } catch {\n // Keep the session for this client instance when browser storage is unavailable.\n }\n try {\n other?.removeItem(this.storageKey);\n } catch {\n // A stale session in the other storage cannot override the in-memory session.\n }\n }\n\n private url(path: string, query: Record<string, string | undefined> = {}): string {\n const url = new URL(`${this.base}/v1/customer${path}`);\n url.searchParams.set('shop', this.shop);\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== '') url.searchParams.set(key, value);\n }\n return url.toString();\n }\n\n private async request<T>(\n path: string,\n options: {\n method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\n body?: unknown;\n formData?: FormData;\n authenticated?: boolean;\n schema?: CustomerPayloadSchema<T>;\n query?: Record<string, string | undefined>;\n } = {},\n ): Promise<T> {\n if (options.body !== undefined && options.formData !== undefined) {\n throw new Error('Customer requests cannot send JSON and FormData together.');\n }\n const session = options.authenticated ? this.getSession() : null;\n if (options.authenticated && !session) {\n throw new HeadlessCustomerError(401, 'Customer session is missing or expired.', 'UNAUTHORIZED');\n }\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n 'x-shoppex-publishable-key': this.publishableKey,\n ...(options.body === undefined ? {} : { 'content-type': 'application/json' }),\n ...(session ? { authorization: `Bearer ${session.accessToken}` } : {}),\n };\n const requestBody = options.formData ?? (\n options.body === undefined ? undefined : JSON.stringify(options.body)\n );\n const response = await this.fetchImpl(this.url(path, options.query), {\n method: options.method ?? 'GET',\n headers,\n ...(requestBody === undefined ? {} : { body: requestBody }),\n cache: 'no-store',\n });\n\n let envelope: ApiEnvelope<unknown> | null = null;\n try {\n envelope = await response.json() as ApiEnvelope<unknown>;\n } catch {\n // Report a stable transport error below.\n }\n if (!response.ok || !envelope || envelope.error) {\n if (response.status === 401 && options.authenticated) this.clearSession();\n throw new HeadlessCustomerError(\n response.status,\n envelope?.error ?? `Request failed (${response.status})`,\n envelope?.error_code ?? null,\n );\n }\n\n if (!options.schema) return envelope.data as T;\n const parsed = options.schema.safeParse(envelope.data);\n if (!parsed.success) {\n throw new HeadlessCustomerError(response.status, 'Customer API response did not match the expected contract.');\n }\n return parsed.data;\n }\n\n private async requestFile(\n path: string,\n query: Record<string, string | undefined> = {},\n options: { rejectHtml?: boolean } = {},\n ): Promise<HeadlessCustomerDownload> {\n const session = this.getSession();\n if (!session) {\n throw new HeadlessCustomerError(401, 'Customer session is missing or expired.', 'UNAUTHORIZED');\n }\n\n const response = await this.fetchImpl(this.url(path, query), {\n method: 'GET',\n headers: {\n 'x-shoppex-publishable-key': this.publishableKey,\n authorization: `Bearer ${session.accessToken}`,\n },\n cache: 'no-store',\n });\n if (!response.ok) {\n if (response.status === 401) this.clearSession();\n let message = `Download failed (${response.status})`;\n try {\n const body = await response.json() as ApiEnvelope<unknown>;\n if (body.error) message = body.error;\n } catch {\n // Keep the stable status-based error.\n }\n throw new HeadlessCustomerError(response.status, message);\n }\n\n const contentType = response.headers.get('content-type');\n if (options.rejectHtml && contentType?.toLowerCase().startsWith('text/html')) {\n throw new HeadlessCustomerError(\n 502,\n 'Shoppex returned an unsafe aggregate download response.',\n 'UNSAFE_DOWNLOAD_RESPONSE',\n );\n }\n\n return {\n blob: await response.blob(),\n filename: readFilename(response.headers.get('content-disposition')),\n contentType,\n };\n }\n\n requestOtp(email: string): Promise<{ requested: boolean }> {\n return this.request('/auth/otp/request', {\n method: 'POST',\n body: { shop: this.shop, email },\n });\n }\n\n async verifyOtp(\n email: string,\n otp: string,\n options: HeadlessCustomerVerifyOptions = {},\n ): Promise<HeadlessCustomerSession> {\n const data = await this.request<{ access_token: string; expires_at: string }>('/auth/otp/verify', {\n method: 'POST',\n body: { shop: this.shop, email, otp, remember_me: options.rememberMe ?? false },\n });\n const expiresAtMs = typeof data?.expires_at === 'string' ? Date.parse(data.expires_at) : Number.NaN;\n if (\n typeof data?.access_token !== 'string'\n || !data.access_token.startsWith('hcs_')\n || typeof data.expires_at !== 'string'\n || !Number.isFinite(expiresAtMs)\n || expiresAtMs <= Date.now()\n ) {\n throw new HeadlessCustomerError(200, 'Customer API response did not match the expected contract.');\n }\n const session = { accessToken: data.access_token, expiresAt: data.expires_at };\n this.saveSession(session, options.rememberMe ?? false);\n return session;\n }\n\n async me(): Promise<HeadlessCustomerMe> {\n const data = await this.request<HeadlessCustomerMeWire>('/me', {\n authenticated: true,\n schema: customerPortalMeSchema,\n });\n if (data.token !== null) {\n // A raw BetterAuth token here would bypass the external route allowlist.\n // Reject the response instead of handing that credential to merchant JS.\n throw new HeadlessCustomerError(200, 'Customer API response did not match the expected contract.');\n }\n return { customer: data.customer, shop: data.shop };\n }\n\n async dashboard(): Promise<HeadlessCustomerDashboard> {\n const dashboard = await this.request<CustomerPortalDashboardWire>('/dashboard', {\n authenticated: true,\n schema: customerPortalDashboardSchema,\n });\n return {\n ...dashboard,\n deliverables: dashboard.deliverables.map((deliverable) => {\n const downloadIndex = readPortalDownloadIndex(deliverable.href);\n return downloadIndex === null\n ? deliverable\n : { ...deliverable, href: null, downloadIndex };\n }),\n };\n }\n\n updateProfile(input: { name: string }): Promise<HeadlessCustomerProfileUpdate> {\n return this.request('/profile', {\n method: 'POST',\n authenticated: true,\n body: { name: input.name },\n schema: customerPortalProfileUpdateSchema,\n });\n }\n\n updateAvatar(file: File): Promise<HeadlessCustomerAvatar> {\n const formData = new FormData();\n formData.append('file', file);\n return this.request('/profile/avatar', {\n method: 'POST',\n authenticated: true,\n formData,\n schema: customerPortalAvatarSchema,\n });\n }\n\n removeAvatar(): Promise<HeadlessCustomerAvatar> {\n return this.request('/profile/avatar', {\n method: 'DELETE',\n authenticated: true,\n schema: customerPortalAvatarSchema,\n });\n }\n\n emailPreferences(): Promise<HeadlessCustomerEmailPreferences> {\n return this.request('/email-marketing/preferences', {\n authenticated: true,\n schema: customerPortalEmailPreferencesSchema,\n });\n }\n\n updateEmailPreferences(\n patch: HeadlessCustomerEmailPreferencesPatch,\n ): Promise<HeadlessCustomerEmailPreferencesUpdate> {\n return this.request('/email-marketing/preferences', {\n method: 'PATCH',\n authenticated: true,\n body: {\n ...(patch.globalUnsubscribed === undefined\n ? {}\n : { global_unsubscribed: patch.globalUnsubscribed }),\n list_subscriptions: (patch.listSubscriptions ?? []).map((item) => ({\n list_id: item.listId,\n subscribed: item.subscribed,\n })),\n },\n schema: customerPortalEmailPreferencesUpdateSchema,\n });\n }\n\n notificationPreferences(): Promise<HeadlessCustomerNotificationPreferences> {\n return this.request('/notification-preferences', {\n authenticated: true,\n schema: customerPortalNotificationPreferencesSchema,\n });\n }\n\n updateNotificationPreferences(\n patch: HeadlessCustomerNotificationPreferencesPatch,\n ): Promise<HeadlessCustomerNotificationPreferences> {\n return this.request('/notification-preferences', {\n method: 'PATCH',\n authenticated: true,\n body: {\n ...(patch.orderCreatedEmails === undefined\n ? {}\n : { order_created_emails: patch.orderCreatedEmails }),\n ...(patch.orderCompletedEmails === undefined\n ? {}\n : { order_completed_emails: patch.orderCompletedEmails }),\n ...(patch.paymentIssueEmails === undefined\n ? {}\n : { payment_issue_emails: patch.paymentIssueEmails }),\n },\n schema: customerPortalNotificationPreferencesSchema,\n });\n }\n\n orders(options: HeadlessCustomerOrdersQuery = {}): Promise<HeadlessCustomerOrders> {\n return this.request<HeadlessCustomerOrders>('/invoices', {\n authenticated: true,\n schema: customerPortalPaginatedInvoicesSchema,\n query: {\n page: options.page === undefined ? undefined : String(options.page),\n limit: options.limit === undefined ? undefined : String(options.limit),\n status: options.status,\n q: options.search,\n },\n });\n }\n\n async order(id: string): Promise<HeadlessCustomerOrder> {\n const order = await this.request<HeadlessCustomerOrder>(`/invoice/${encodeURIComponent(id)}`, {\n authenticated: true,\n schema: customerPortalInvoiceDetailSchema,\n });\n return {\n ...order,\n lineItems: order.lineItems.map((lineItem) => ({\n ...lineItem,\n deliverySummary: lineItem.deliverySummary\n ? {\n ...lineItem.deliverySummary,\n links: lineItem.deliverySummary.links.map((link) => {\n const downloadIndex = readPortalDownloadIndex(link.href);\n return downloadIndex === null\n ? link\n : { ...link, href: null, downloadIndex };\n }),\n }\n : null,\n })),\n };\n }\n\n orderReview(orderId: string): Promise<HeadlessCustomerOrderReview> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/review`, {\n authenticated: true,\n schema: customerPortalOrderReviewSchema,\n });\n }\n\n submitOrderReview(\n orderId: string,\n input: HeadlessCustomerOrderReviewInput,\n ): Promise<HeadlessCustomerOrderReview> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/review`, {\n method: 'POST',\n authenticated: true,\n body: {\n score: input.score,\n message: input.message,\n },\n schema: customerPortalOrderReviewSchema,\n });\n }\n\n invoicePdf(orderId: string): Promise<HeadlessCustomerDownload> {\n return this.requestFile(`/invoices/${encodeURIComponent(orderId)}/pdf`);\n }\n\n replacementEligibility(\n orderId: string,\n lineItemId?: string,\n ): Promise<HeadlessCustomerReplacementEligibility> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/replacement-eligibility`, {\n authenticated: true,\n query: { line_item_id: lineItemId },\n schema: customerReplacementEligibilitySchema,\n });\n }\n\n requestReplacement(\n orderId: string,\n options: HeadlessCustomerReplacementOptions,\n ): Promise<HeadlessCustomerReplacementRequest> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/replacement-requests`, {\n method: 'POST',\n authenticated: true,\n body: {\n line_item_id: options.lineItemId ?? null,\n reason: options.reason,\n ...(options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}),\n },\n schema: customerReplacementRequestSchema,\n });\n }\n\n async download(orderId: string, fileIndex: number): Promise<HeadlessCustomerDownload> {\n if (!Number.isSafeInteger(fileIndex) || fileIndex < 0) {\n throw new HeadlessCustomerError(\n 400,\n 'download requires a non-negative integer fileIndex from order().deliverySummary.links.',\n 'INVALID_FILE_INDEX',\n );\n }\n return this.requestFile(\n `/invoice/${encodeURIComponent(orderId)}/download`,\n { file_index: String(fileIndex) },\n { rejectHtml: true },\n );\n }\n\n resetLicenseHwid(licenseId: string): Promise<HeadlessCustomerLicenseReset> {\n return this.request(`/licenses/${encodeURIComponent(licenseId)}/reset-hwid`, {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerPortalLicenseResetSchema,\n });\n }\n\n renewLicense(licenseId: string): Promise<HeadlessCustomerLicenseRenewal> {\n return this.request(`/licenses/${encodeURIComponent(licenseId)}/renew`, {\n method: 'POST',\n authenticated: true,\n // This established route requires shop in the body. The shared headless\n // gate independently verifies the same shop from the query and key.\n body: { shop: this.shop },\n schema: customerPortalLicenseRenewalSchema,\n });\n }\n\n walletTopupQuote(): Promise<HeadlessCustomerWalletTopupQuote> {\n return this.request('/wallet/topup-quote', {\n authenticated: true,\n schema: customerPortalWalletTopupQuoteSchema,\n });\n }\n\n createWalletTopup(amount: string): Promise<HeadlessCustomerWalletTopup> {\n return this.request('/wallet/topup', {\n method: 'POST',\n authenticated: true,\n body: { amount },\n schema: customerPortalWalletTopupResultSchema,\n });\n }\n\n subscriptionBillingHistory(\n subscriptionId: string,\n ): Promise<HeadlessCustomerSubscriptionBillingHistory> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/billing-history`, {\n authenticated: true,\n schema: customerPortalSubscriptionBillingHistorySchema,\n });\n }\n\n cancelSubscription(\n subscriptionId: string,\n options: HeadlessCustomerSubscriptionCancelOptions = {},\n ): Promise<HeadlessCustomerSubscriptionCancel> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/cancel`, {\n method: 'POST',\n authenticated: true,\n body: {\n ...(options.cancelAtPeriodEnd === undefined\n ? {}\n : { cancel_at_period_end: options.cancelAtPeriodEnd }),\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n },\n schema: customerPortalSubscriptionCancelSchema,\n });\n }\n\n pauseSubscription(subscriptionId: string): Promise<HeadlessCustomerSubscriptionStatus> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/pause`, {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerPortalSubscriptionStatusSchema,\n });\n }\n\n resumeSubscription(subscriptionId: string): Promise<HeadlessCustomerSubscriptionStatus> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/resume`, {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerPortalSubscriptionStatusSchema,\n });\n }\n\n loyalty(): Promise<HeadlessCustomerLoyalty> {\n return this.request('/loyalty', {\n authenticated: true,\n schema: customerLoyaltySchema,\n });\n }\n\n redeemLoyaltyPoints(input: {\n points: number;\n idempotencyKey: string;\n }): Promise<HeadlessCustomerLoyaltyRedeem> {\n return this.request('/loyalty/redeem', {\n method: 'POST',\n authenticated: true,\n body: { points: input.points, idempotency_key: input.idempotencyKey },\n schema: customerLoyaltyRedeemSchema,\n });\n }\n\n warranties(invoiceId?: string): Promise<HeadlessCustomerWarranties> {\n return this.request('/warranties', {\n authenticated: true,\n query: { invoice: invoiceId },\n schema: customerWarrantyListSchema,\n });\n }\n\n claimWarranty(warrantyId: string, message?: string): Promise<HeadlessCustomerWarrantyClaim> {\n return this.request(`/warranties/${encodeURIComponent(warrantyId)}/claim`, {\n method: 'POST',\n authenticated: true,\n body: message ? { message } : {},\n schema: customerWarrantyClaimSchema,\n });\n }\n\n favorites(): Promise<HeadlessCustomerFavorites> {\n return this.request('/favorites', {\n authenticated: true,\n schema: customerPortalFavoritesSchema,\n });\n }\n\n addFavorite(productId: string): Promise<HeadlessCustomerFavoriteMutation> {\n return this.request(`/favorites/${encodeURIComponent(productId)}`, {\n method: 'PUT',\n authenticated: true,\n schema: customerPortalFavoriteMutationSchema,\n });\n }\n\n removeFavorite(productId: string): Promise<HeadlessCustomerFavoriteMutation> {\n return this.request(`/favorites/${encodeURIComponent(productId)}`, {\n method: 'DELETE',\n authenticated: true,\n schema: customerPortalFavoriteMutationSchema,\n });\n }\n\n affiliate(): Promise<HeadlessCustomerAffiliate> {\n return this.request('/affiliate', {\n authenticated: true,\n schema: customerPortalAffiliateSummarySchema,\n });\n }\n\n affiliateStats(input?: { days?: number }): Promise<HeadlessCustomerAffiliateStats> {\n return this.request('/affiliate/stats', {\n authenticated: true,\n schema: customerPortalAffiliateStatsSchema,\n query: input?.days === undefined ? {} : { days: String(input.days) },\n });\n }\n\n createAffiliateLink(\n input: HeadlessCustomerAffiliateLinkInput,\n ): Promise<HeadlessCustomerAffiliateLink> {\n return this.request('/affiliate/links', {\n method: 'POST',\n authenticated: true,\n body: {\n shop: this.shop,\n code: input.code,\n label: input.label,\n ...(input.requestedRevenuePercent === undefined\n ? {}\n : { requested_affiliate_revenue_percent: input.requestedRevenuePercent }),\n ...(input.requestedCustomerDiscountPercent === undefined\n ? {}\n : { requested_affiliate_customer_discount_percent: input.requestedCustomerDiscountPercent }),\n },\n schema: customerPortalAffiliateCreateLinkSchema,\n });\n }\n\n createTicket(input: HeadlessCustomerTicketInput): Promise<HeadlessCustomerTicketCreateResult> {\n return this.request('/tickets', {\n method: 'POST',\n authenticated: true,\n body: {\n ...(input.title === undefined ? {} : { title: input.title }),\n message: input.message,\n ...(input.invoiceId === undefined ? {} : { invoice_id: input.invoiceId }),\n },\n schema: customerPortalSupportCreateSchema,\n });\n }\n\n ticket(ticketId: string): Promise<HeadlessCustomerTicket> {\n return this.request(`/tickets/${encodeURIComponent(ticketId)}`, {\n authenticated: true,\n schema: customerPortalSupportTicketDetailSchema,\n });\n }\n\n async replyToTicket(ticketId: string, message: string): Promise<void> {\n await this.request<null>(`/tickets/${encodeURIComponent(ticketId)}/reply`, {\n method: 'POST',\n authenticated: true,\n body: { message },\n });\n }\n\n reseller(): Promise<HeadlessCustomerReseller> {\n return this.request('/reseller', {\n authenticated: true,\n schema: customerResellerSummarySchema,\n });\n }\n\n applyForReseller(note?: string): Promise<HeadlessCustomerResellerEnrollment> {\n return this.request('/reseller/apply', {\n method: 'POST',\n authenticated: true,\n body: note === undefined ? {} : { note },\n schema: customerResellerEnrollmentSchema,\n });\n }\n\n enrollAsReseller(): Promise<HeadlessCustomerResellerEnrollment> {\n return this.request('/reseller/enroll', {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerResellerEnrollmentSchema,\n });\n }\n\n acceptResellerInvite(token: string): Promise<HeadlessCustomerResellerEnrollment> {\n return this.request('/reseller/accept-invite', {\n method: 'POST',\n authenticated: true,\n body: { token },\n schema: customerResellerEnrollmentSchema,\n });\n }\n\n resellerCatalog(\n options: HeadlessCustomerResellerCatalogQuery = {},\n ): Promise<HeadlessCustomerResellerCatalog> {\n return this.request('/reseller/catalog', {\n authenticated: true,\n query: {\n search: options.search,\n page: options.page === undefined ? undefined : String(options.page),\n per_page: options.perPage === undefined ? undefined : String(options.perPage),\n },\n schema: customerResellerCatalogSchema,\n });\n }\n\n quoteResellerOrder(\n items: HeadlessCustomerResellerOrderItem[],\n ): Promise<HeadlessCustomerResellerQuote> {\n return this.request('/reseller/orders/quote', {\n method: 'POST',\n authenticated: true,\n body: {\n items: items.map((item) => ({\n product_id: item.productId,\n ...(item.variantId === undefined ? {} : { variant_id: item.variantId }),\n quantity: item.quantity,\n })),\n },\n schema: customerResellerQuoteSchema,\n });\n }\n\n resellerOrders(\n options: HeadlessCustomerResellerOrdersQuery = {},\n ): Promise<HeadlessCustomerResellerOrders> {\n return this.request('/reseller/orders', {\n authenticated: true,\n query: {\n page: options.page === undefined ? undefined : String(options.page),\n per_page: options.perPage === undefined ? undefined : String(options.perPage),\n },\n schema: customerResellerOrdersSchema,\n });\n }\n\n resellerOrder(orderId: string): Promise<HeadlessCustomerResellerOrder> {\n return this.request(`/reseller/orders/${encodeURIComponent(orderId)}`, {\n authenticated: true,\n schema: customerResellerOrderSchema,\n });\n }\n\n resellerWallet(): Promise<HeadlessCustomerResellerWallet> {\n return this.request('/reseller/wallet', {\n authenticated: true,\n schema: customerResellerWalletSchema,\n });\n }\n\n resellerTopupQuote(): Promise<HeadlessCustomerWalletTopupQuote> {\n return this.request('/reseller/wallet/topup-quote', {\n authenticated: true,\n schema: customerPortalWalletTopupQuoteSchema,\n });\n }\n\n createResellerTopup(amount: string): Promise<HeadlessCustomerResellerTopup> {\n return this.request('/reseller/wallet/topup', {\n method: 'POST',\n authenticated: true,\n body: { amount },\n schema: customerResellerTopupSchema,\n });\n }\n\n resellerApiKeys(): Promise<HeadlessCustomerResellerApiKeys> {\n return this.request('/reseller/api-keys', {\n authenticated: true,\n schema: customerResellerApiKeysSchema,\n });\n }\n\n async logout(): Promise<void> {\n if (!this.getSession()) return;\n try {\n await this.request<null>('/auth/logout', { method: 'POST', authenticated: true });\n } catch (error) {\n if (error instanceof HeadlessCustomerError && error.status === 401) {\n // The server already considers the credential invalid. request() also\n // clears it, so logout is complete from the buyer's perspective.\n return;\n }\n // Keep the local token after a transient failure so the caller can retry\n // server-side revocation instead of leaving an unreachable live session.\n throw error;\n }\n this.clearSession();\n }\n}\n\nexport function createCustomerClient(config: HeadlessCustomerClientConfig): HeadlessCustomerClient {\n return new HeadlessCustomerClient(config);\n}\n"],"mappings":"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","names":["stored"]}
|
|
1
|
+
{"version":3,"sources":["../../sdk/src/headless-customer.ts"],"sourcesContent":["/**\n * Browser client for a customer account hosted outside Shoppex.\n *\n * The publishable key identifies the merchant and the dashboard origin\n * allowlist authorizes the browser origin. OTP verification returns a separate\n * short-lived `hcs_` token; the SDK never exposes Shoppex's BetterAuth token.\n */\nimport {\n customerLoyaltyRedeemSchema,\n customerLoyaltySchema,\n customerPortalAffiliateSummarySchema,\n customerPortalAffiliateStatsSchema,\n customerPortalAffiliateCreateLinkSchema,\n customerPortalAvatarSchema,\n customerPortalDashboardSchema,\n customerPortalEmailPreferencesSchema,\n customerPortalEmailPreferencesUpdateSchema,\n customerPortalFavoriteMutationSchema,\n customerPortalFavoritesSchema,\n customerPortalInvoiceDetailSchema,\n customerPortalLicenseResetSchema,\n customerPortalLicenseRenewalSchema,\n customerPortalMeSchema,\n customerPortalNotificationPreferencesSchema,\n customerPortalOrderReviewSchema,\n customerPortalPaginatedInvoicesSchema,\n customerPortalProfileUpdateSchema,\n customerPortalSubscriptionBillingHistorySchema,\n customerPortalSubscriptionCancelSchema,\n customerPortalSubscriptionStatusSchema,\n customerPortalSupportCreateSchema,\n customerPortalSupportTicketDetailSchema,\n customerPortalWalletTopupQuoteSchema,\n customerPortalWalletTopupResultSchema,\n customerReplacementEligibilitySchema,\n customerReplacementRequestSchema,\n customerResellerApiKeysSchema,\n customerResellerCatalogSchema,\n customerResellerEnrollmentSchema,\n customerResellerOrderSchema,\n customerResellerOrdersSchema,\n customerResellerQuoteSchema,\n customerResellerSummarySchema,\n customerResellerTopupSchema,\n customerResellerWalletSchema,\n customerWarrantyClaimSchema,\n customerWarrantyListSchema,\n type CustomerLoyaltyRedeemWire,\n type CustomerLoyaltyWire,\n type CustomerPortalAffiliateSummaryWire,\n type CustomerPortalAffiliateStatsWire,\n type CustomerPortalAffiliateCreateLinkWire,\n type CustomerPortalAvatarWire,\n type CustomerPortalDashboardWire,\n type CustomerPortalEmailPreferencesUpdateWire,\n type CustomerPortalEmailPreferencesWire,\n type CustomerPortalFavoriteMutationWire,\n type CustomerPortalFavoritesWire,\n type CustomerPortalLicenseResetWire,\n type CustomerPortalLicenseRenewalWire,\n type CustomerPortalNotificationPreferencesWire,\n type CustomerPortalOrderReviewWire,\n type CustomerPortalProfileUpdateWire,\n type CustomerPortalSubscriptionBillingHistoryWire,\n type CustomerPortalSubscriptionCancelWire,\n type CustomerPortalSubscriptionStatusWire,\n type CustomerPortalSupportCreateWire,\n type CustomerPortalSupportTicketDetailWire,\n type CustomerPortalWalletTopupQuoteWire,\n type CustomerPortalWalletTopupResultWire,\n type CustomerReplacementEligibilityWire,\n type CustomerReplacementRequestWire,\n type CustomerResellerApiKeysWire,\n type CustomerResellerCatalogWire,\n type CustomerResellerEnrollmentWire,\n type CustomerResellerOrderWire,\n type CustomerResellerOrdersWire,\n type CustomerResellerQuoteWire,\n type CustomerResellerSummaryWire,\n type CustomerResellerTopupWire,\n type CustomerResellerWalletWire,\n type CustomerWarrantyClaimWire,\n type CustomerWarrantyListWire,\n} from '@shoppex/contracts/customer-portal-wire';\n\nconst DEFAULT_API_ORIGIN = 'https://api.shoppex.io';\nconst SESSION_STORAGE_PREFIX = 'shoppex_headless_customer_session:';\n\ninterface CustomerPayloadSchema<T> {\n safeParse(value: unknown): { success: true; data: T } | { success: false };\n}\n\ninterface ApiEnvelope<T> {\n status: number;\n data: T | null;\n error: string | null;\n message?: string | null;\n error_code?: string | null;\n}\n\ninterface StoredSession {\n accessToken: string;\n expiresAt: string;\n savedAt: number;\n}\n\nexport interface HeadlessCustomerClientConfig {\n /** Shop slug or Shoppex storefront domain. */\n shop: string;\n /** Existing Headless Checkout publishable key (`pk_live_` / `pk_test_`). */\n publishableKey: string;\n /** API origin override. Defaults to https://api.shoppex.io. */\n apiBaseUrl?: string;\n /** Optional fetch override for tests or compatible runtimes. */\n fetchImpl?: typeof fetch;\n /** Optional session storage override. Defaults to browser sessionStorage. */\n storage?: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;\n /** Optional persistent storage override. Defaults to browser localStorage. */\n persistentStorage?: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;\n}\n\nexport interface HeadlessCustomerSession {\n accessToken: string;\n expiresAt: string;\n}\n\nexport interface HeadlessCustomerVerifyOptions {\n /** Persist the customer session across browser restarts for up to 30 days. */\n rememberMe?: boolean;\n}\n\nexport interface HeadlessCustomerOrdersQuery {\n page?: number;\n limit?: number;\n status?: string;\n search?: string;\n}\n\nexport interface HeadlessCustomerDownload {\n blob: Blob;\n filename: string | null;\n contentType: string | null;\n}\n\ntype HeadlessCustomerDashboardDeliverable =\n CustomerPortalDashboardWire['deliverables'][number] & {\n /** Pass this value with `invoice_uniqid` to `customer.download()`. */\n downloadIndex?: number | null;\n };\n\nexport type HeadlessCustomerDashboard = Omit<CustomerPortalDashboardWire, 'deliverables'> & {\n deliverables: HeadlessCustomerDashboardDeliverable[];\n};\nexport type HeadlessCustomerProfileUpdate = CustomerPortalProfileUpdateWire;\nexport type HeadlessCustomerAvatar = CustomerPortalAvatarWire;\nexport type HeadlessCustomerEmailPreferences = CustomerPortalEmailPreferencesWire;\nexport type HeadlessCustomerEmailPreferencesUpdate = CustomerPortalEmailPreferencesUpdateWire;\nexport type HeadlessCustomerNotificationPreferences = CustomerPortalNotificationPreferencesWire;\nexport type HeadlessCustomerOrderReview = CustomerPortalOrderReviewWire;\nexport type HeadlessCustomerFavorites = CustomerPortalFavoritesWire;\nexport type HeadlessCustomerFavoriteMutation = CustomerPortalFavoriteMutationWire;\nexport type HeadlessCustomerAffiliate = CustomerPortalAffiliateSummaryWire;\nexport type HeadlessCustomerAffiliateStats = CustomerPortalAffiliateStatsWire;\nexport type HeadlessCustomerAffiliateLink = CustomerPortalAffiliateCreateLinkWire;\nexport type HeadlessCustomerTicket = CustomerPortalSupportTicketDetailWire;\nexport type HeadlessCustomerTicketCreateResult = CustomerPortalSupportCreateWire;\nexport type HeadlessCustomerLicenseReset = CustomerPortalLicenseResetWire;\nexport type HeadlessCustomerLicenseRenewal = CustomerPortalLicenseRenewalWire;\nexport type HeadlessCustomerWalletTopupQuote = CustomerPortalWalletTopupQuoteWire;\nexport type HeadlessCustomerWalletTopup = CustomerPortalWalletTopupResultWire;\nexport type HeadlessCustomerSubscriptionBillingHistory = CustomerPortalSubscriptionBillingHistoryWire;\nexport type HeadlessCustomerSubscriptionCancel = CustomerPortalSubscriptionCancelWire;\nexport type HeadlessCustomerSubscriptionStatus = CustomerPortalSubscriptionStatusWire;\nexport type HeadlessCustomerLoyalty = CustomerLoyaltyWire;\nexport type HeadlessCustomerLoyaltyRedeem = CustomerLoyaltyRedeemWire;\nexport type HeadlessCustomerWarranties = CustomerWarrantyListWire;\nexport type HeadlessCustomerWarrantyClaim = CustomerWarrantyClaimWire;\nexport type HeadlessCustomerReplacementEligibility = CustomerReplacementEligibilityWire;\nexport type HeadlessCustomerReplacementRequest = CustomerReplacementRequestWire;\nexport type HeadlessCustomerReseller = CustomerResellerSummaryWire;\nexport type HeadlessCustomerResellerEnrollment = CustomerResellerEnrollmentWire;\nexport type HeadlessCustomerResellerCatalog = CustomerResellerCatalogWire;\nexport type HeadlessCustomerResellerQuote = CustomerResellerQuoteWire;\nexport type HeadlessCustomerResellerOrders = CustomerResellerOrdersWire;\nexport type HeadlessCustomerResellerOrder = CustomerResellerOrderWire;\nexport type HeadlessCustomerResellerWallet = CustomerResellerWalletWire;\nexport type HeadlessCustomerResellerApiKeys = CustomerResellerApiKeysWire;\nexport type HeadlessCustomerResellerTopup = CustomerResellerTopupWire;\n\nexport interface HeadlessCustomerTicketInput {\n title?: string;\n message: string;\n invoiceId?: string;\n}\n\nexport interface HeadlessCustomerOrderReviewInput {\n score: 1 | 3 | 5;\n message: string;\n}\n\nexport interface HeadlessCustomerAffiliateLinkInput {\n code: string;\n label: string;\n requestedRevenuePercent?: number | null;\n requestedCustomerDiscountPercent?: number | null;\n}\n\nexport interface HeadlessCustomerSubscriptionCancelOptions {\n cancelAtPeriodEnd?: boolean;\n reason?: string | null;\n}\n\nexport interface HeadlessCustomerEmailPreferencesPatch {\n globalUnsubscribed?: boolean;\n listSubscriptions?: Array<{ listId: string; subscribed: boolean }>;\n}\n\nexport interface HeadlessCustomerNotificationPreferencesPatch {\n orderCreatedEmails?: boolean;\n orderCompletedEmails?: boolean;\n paymentIssueEmails?: boolean;\n}\n\nexport interface HeadlessCustomerReplacementOptions {\n lineItemId: string;\n reason: string;\n idempotencyKey?: string;\n}\n\nexport interface HeadlessCustomerResellerCatalogQuery {\n search?: string;\n page?: number;\n perPage?: number;\n}\n\nexport interface HeadlessCustomerResellerOrdersQuery {\n page?: number;\n perPage?: number;\n}\n\nexport interface HeadlessCustomerResellerOrderItem {\n productId: string;\n variantId?: string;\n quantity: number;\n}\n\n/** Public DTOs mirror the producer-owned schemas imported above. Passing each\n * schema into `request<T>` makes TypeScript reject drift in required fields. */\nexport interface HeadlessCustomerMe {\n customer: {\n id: string | null;\n email: string;\n name: string;\n avatar_url: string | null;\n joined_at: string | null;\n };\n shop: {\n id: string;\n slug: string;\n name: string;\n currency: string;\n branding: {\n logo_url: string | null;\n primary_color: string;\n secondary_color: string;\n accent_color: string;\n };\n };\n}\n\ntype HeadlessCustomerMeWire = HeadlessCustomerMe & { token: string | null };\n\nexport interface HeadlessCustomerOrderSummary {\n uniqid: string;\n status: string;\n total: string;\n totalDisplay: string | null;\n currency: string;\n createdAt: string;\n lineItems: Array<{\n productTitle: string | null;\n quantity: number;\n product: {\n attachment_imageId: { cloudflareImageId: string | null } | null;\n } | null;\n }>;\n}\n\nexport interface HeadlessCustomerOrders {\n invoices: HeadlessCustomerOrderSummary[];\n pagination: {\n page: number;\n limit: number;\n total: number;\n has_more: boolean;\n };\n}\n\nexport interface HeadlessCustomerPayment {\n gateway: string;\n displayName: string | null;\n cryptoGateway?: string | null;\n blockchain: string | null;\n cryptoAddress: string | null;\n apmMethod: string | null;\n}\n\nexport interface HeadlessCustomerOrder {\n id: string;\n uniqid: string;\n status: string;\n statusDetails: string | null;\n total: string;\n totalDisplay: string | null;\n subtotal: string;\n discount: string;\n discountDisplay: string | null;\n tax: string;\n taxPercentage: string;\n currency: string;\n createdAt: string;\n updatedAt: string;\n gatewayUpdatedAt: string | null;\n customFields: Record<string, unknown> | null;\n balancePaidAmount: string;\n currentPaymentAttemptId: string | null;\n lineItems: Array<{\n id: string;\n productTitle: string;\n productType: string;\n variantTitle: string | null;\n unitPrice: string;\n quantity: number;\n total: string;\n deliveryText: string | null;\n deliverySummary: {\n codes: string[];\n links: Array<{\n label: string;\n value: string;\n /** External URL for non-Shoppex links. Portal-only download URLs are removed. */\n href?: string | null;\n /** Pass this value to `customer.download(orderId, downloadIndex)`. */\n downloadIndex?: number | null;\n }>;\n notes: string[];\n serials: Array<{ value: string; is_replacement: boolean; is_replaced: boolean }>;\n } | null;\n deliveredAt: string | null;\n deliveryStatus: 'PENDING' | 'AWAITING_FULFILLMENT' | 'DELIVERED' | 'FAILED';\n customFields: Record<string, unknown> | null;\n product: {\n uniqid: string;\n slug: string | null;\n serviceText: string | null;\n attachment_imageId: { cloudflareImageId: string | null } | null;\n } | null;\n }>;\n currentPayment: HeadlessCustomerPayment | null;\n payments: HeadlessCustomerPayment[];\n}\n\nexport class HeadlessCustomerError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly code?: string | null,\n ) {\n super(message);\n this.name = 'HeadlessCustomerError';\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseStoredSession(value: string | null): StoredSession | null {\n if (!value) return null;\n try {\n const parsed: unknown = JSON.parse(value);\n if (\n !isRecord(parsed)\n || typeof parsed.accessToken !== 'string'\n || !parsed.accessToken.startsWith('hcs_')\n || typeof parsed.expiresAt !== 'string'\n || typeof parsed.savedAt !== 'number'\n || !Number.isFinite(parsed.savedAt)\n ) {\n return null;\n }\n const expiresAtMs = Date.parse(parsed.expiresAt);\n if (!Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now()) return null;\n return { accessToken: parsed.accessToken, expiresAt: parsed.expiresAt, savedAt: parsed.savedAt };\n } catch {\n return null;\n }\n}\n\nfunction readFilename(header: string | null): string | null {\n if (!header) return null;\n const utf8Match = header.match(/filename\\*=UTF-8''([^;]+)/i);\n if (utf8Match?.[1]) {\n try {\n return decodeURIComponent(utf8Match[1]);\n } catch {\n return utf8Match[1];\n }\n }\n return header.match(/filename=\"([^\"]+)\"/i)?.[1] ?? null;\n}\n\nfunction readPortalDownloadIndex(href: string | null | undefined): number | null {\n // Only relative URLs are owned by the Shoppex customer portal. An external\n // site may legitimately use the same pathname and must remain an external link.\n if (!href?.startsWith('/api/customer/')) return null;\n try {\n const url = new URL(href, 'https://headless-customer.invalid');\n if (!/^\\/api\\/customer\\/invoice\\/[^/]+\\/download$/.test(url.pathname)) return null;\n const rawIndex = url.searchParams.get('file_index');\n if (rawIndex === null || !/^\\d+$/.test(rawIndex)) return null;\n const index = Number(rawIndex);\n return Number.isSafeInteger(index) ? index : null;\n } catch {\n return null;\n }\n}\n\nfunction readBrowserStorage(name: 'sessionStorage' | 'localStorage'):\n Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null {\n try {\n return typeof window === 'undefined' ? null : window[name];\n } catch {\n return null;\n }\n}\n\nexport class HeadlessCustomerClient {\n private readonly base: string;\n private readonly shop: string;\n private readonly publishableKey: string;\n private readonly fetchImpl: typeof fetch;\n private readonly storage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null;\n private readonly persistentStorage: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null;\n private readonly storageKey: string;\n private memorySession: StoredSession | null = null;\n\n constructor(config: HeadlessCustomerClientConfig) {\n if (!config.shop.trim()) throw new Error('HeadlessCustomerClient requires a shop.');\n if (!config.publishableKey.trim()) {\n throw new Error('HeadlessCustomerClient requires a publishableKey.');\n }\n this.shop = config.shop.trim();\n this.publishableKey = config.publishableKey.trim();\n this.base = (config.apiBaseUrl ?? DEFAULT_API_ORIGIN).replace(/\\/+$/, '');\n this.fetchImpl = config.fetchImpl ?? globalThis.fetch?.bind(globalThis);\n if (!this.fetchImpl) throw new Error('No fetch implementation available; pass fetchImpl.');\n this.storage = config.storage ?? readBrowserStorage('sessionStorage');\n this.persistentStorage = config.persistentStorage ?? readBrowserStorage('localStorage');\n this.storageKey = `${SESSION_STORAGE_PREFIX}${this.shop}`;\n }\n\n getSession(): HeadlessCustomerSession | null {\n const candidates: StoredSession[] = this.memorySession ? [this.memorySession] : [];\n if (this.storage) {\n try {\n const stored = parseStoredSession(this.storage.getItem(this.storageKey));\n if (stored) candidates.push(stored);\n } catch {\n // Continue with memory and persistent storage.\n }\n }\n if (this.persistentStorage) {\n try {\n const stored = parseStoredSession(this.persistentStorage.getItem(this.storageKey));\n if (stored) candidates.push(stored);\n } catch {\n // Continue with the other available stores.\n }\n }\n\n const stored = candidates.sort((left, right) => right.savedAt - left.savedAt)[0] ?? null;\n\n if (!stored) {\n this.clearSession();\n return null;\n }\n this.memorySession = stored;\n return { accessToken: stored.accessToken, expiresAt: stored.expiresAt };\n }\n\n clearSession(): void {\n this.memorySession = null;\n try {\n this.storage?.removeItem(this.storageKey);\n } catch {\n // Privacy-restricted browsers may reject storage access. Memory is still cleared.\n }\n try {\n this.persistentStorage?.removeItem(this.storageKey);\n } catch {\n // The two stores are cleared independently so one rejected access cannot block the other.\n }\n }\n\n private saveSession(session: HeadlessCustomerSession, rememberMe: boolean): void {\n const storedSession: StoredSession = { ...session, savedAt: Date.now() };\n this.memorySession = storedSession;\n const target = rememberMe ? this.persistentStorage : this.storage;\n const other = rememberMe ? this.storage : this.persistentStorage;\n try {\n target?.setItem(this.storageKey, JSON.stringify(storedSession));\n } catch {\n // Keep the session for this client instance when browser storage is unavailable.\n }\n try {\n other?.removeItem(this.storageKey);\n } catch {\n // A stale session in the other storage cannot override the in-memory session.\n }\n }\n\n private url(path: string, query: Record<string, string | undefined> = {}): string {\n const url = new URL(`${this.base}/v1/customer${path}`);\n url.searchParams.set('shop', this.shop);\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== '') url.searchParams.set(key, value);\n }\n return url.toString();\n }\n\n private async request<T>(\n path: string,\n options: {\n method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\n body?: unknown;\n formData?: FormData;\n authenticated?: boolean;\n schema?: CustomerPayloadSchema<T>;\n query?: Record<string, string | undefined>;\n } = {},\n ): Promise<T> {\n if (options.body !== undefined && options.formData !== undefined) {\n throw new Error('Customer requests cannot send JSON and FormData together.');\n }\n const session = options.authenticated ? this.getSession() : null;\n if (options.authenticated && !session) {\n throw new HeadlessCustomerError(401, 'Customer session is missing or expired.', 'UNAUTHORIZED');\n }\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n 'x-shoppex-publishable-key': this.publishableKey,\n ...(options.body === undefined ? {} : { 'content-type': 'application/json' }),\n ...(session ? { authorization: `Bearer ${session.accessToken}` } : {}),\n };\n const requestBody = options.formData ?? (\n options.body === undefined ? undefined : JSON.stringify(options.body)\n );\n const response = await this.fetchImpl(this.url(path, options.query), {\n method: options.method ?? 'GET',\n headers,\n ...(requestBody === undefined ? {} : { body: requestBody }),\n cache: 'no-store',\n });\n\n let envelope: ApiEnvelope<unknown> | null = null;\n try {\n envelope = await response.json() as ApiEnvelope<unknown>;\n } catch {\n // Report a stable transport error below.\n }\n if (!response.ok || !envelope || envelope.error) {\n if (response.status === 401 && options.authenticated) this.clearSession();\n throw new HeadlessCustomerError(\n response.status,\n envelope?.error ?? `Request failed (${response.status})`,\n envelope?.error_code ?? null,\n );\n }\n\n if (!options.schema) return envelope.data as T;\n const parsed = options.schema.safeParse(envelope.data);\n if (!parsed.success) {\n throw new HeadlessCustomerError(response.status, 'Customer API response did not match the expected contract.');\n }\n return parsed.data;\n }\n\n private async requestFile(\n path: string,\n query: Record<string, string | undefined> = {},\n options: { rejectHtml?: boolean } = {},\n ): Promise<HeadlessCustomerDownload> {\n const session = this.getSession();\n if (!session) {\n throw new HeadlessCustomerError(401, 'Customer session is missing or expired.', 'UNAUTHORIZED');\n }\n\n const response = await this.fetchImpl(this.url(path, query), {\n method: 'GET',\n headers: {\n 'x-shoppex-publishable-key': this.publishableKey,\n authorization: `Bearer ${session.accessToken}`,\n },\n cache: 'no-store',\n });\n if (!response.ok) {\n if (response.status === 401) this.clearSession();\n let message = `Download failed (${response.status})`;\n try {\n const body = await response.json() as ApiEnvelope<unknown>;\n if (body.error) message = body.error;\n } catch {\n // Keep the stable status-based error.\n }\n throw new HeadlessCustomerError(response.status, message);\n }\n\n const contentType = response.headers.get('content-type');\n if (options.rejectHtml && contentType?.toLowerCase().startsWith('text/html')) {\n throw new HeadlessCustomerError(\n 502,\n 'Shoppex returned an unsafe aggregate download response.',\n 'UNSAFE_DOWNLOAD_RESPONSE',\n );\n }\n\n return {\n blob: await response.blob(),\n filename: readFilename(response.headers.get('content-disposition')),\n contentType,\n };\n }\n\n requestOtp(email: string): Promise<{ requested: boolean }> {\n return this.request('/auth/otp/request', {\n method: 'POST',\n body: { shop: this.shop, email },\n });\n }\n\n async verifyOtp(\n email: string,\n otp: string,\n options: HeadlessCustomerVerifyOptions = {},\n ): Promise<HeadlessCustomerSession> {\n const data = await this.request<{ access_token: string; expires_at: string }>('/auth/otp/verify', {\n method: 'POST',\n body: { shop: this.shop, email, otp, remember_me: options.rememberMe ?? false },\n });\n const expiresAtMs = typeof data?.expires_at === 'string' ? Date.parse(data.expires_at) : Number.NaN;\n if (\n typeof data?.access_token !== 'string'\n || !data.access_token.startsWith('hcs_')\n || typeof data.expires_at !== 'string'\n || !Number.isFinite(expiresAtMs)\n || expiresAtMs <= Date.now()\n ) {\n throw new HeadlessCustomerError(200, 'Customer API response did not match the expected contract.');\n }\n const session = { accessToken: data.access_token, expiresAt: data.expires_at };\n this.saveSession(session, options.rememberMe ?? false);\n return session;\n }\n\n async me(): Promise<HeadlessCustomerMe> {\n const data = await this.request<HeadlessCustomerMeWire>('/me', {\n authenticated: true,\n schema: customerPortalMeSchema,\n });\n if (data.token !== null) {\n // A raw BetterAuth token here would bypass the external route allowlist.\n // Reject the response instead of handing that credential to merchant JS.\n throw new HeadlessCustomerError(200, 'Customer API response did not match the expected contract.');\n }\n return { customer: data.customer, shop: data.shop };\n }\n\n async dashboard(): Promise<HeadlessCustomerDashboard> {\n const dashboard = await this.request<CustomerPortalDashboardWire>('/dashboard', {\n authenticated: true,\n schema: customerPortalDashboardSchema,\n });\n return {\n ...dashboard,\n deliverables: dashboard.deliverables.map((deliverable) => {\n const downloadIndex = readPortalDownloadIndex(deliverable.href);\n return downloadIndex === null\n ? deliverable\n : { ...deliverable, href: null, downloadIndex };\n }),\n };\n }\n\n updateProfile(input: { name: string }): Promise<HeadlessCustomerProfileUpdate> {\n return this.request('/profile', {\n method: 'POST',\n authenticated: true,\n body: { name: input.name },\n schema: customerPortalProfileUpdateSchema,\n });\n }\n\n updateAvatar(file: File): Promise<HeadlessCustomerAvatar> {\n const formData = new FormData();\n formData.append('file', file);\n return this.request('/profile/avatar', {\n method: 'POST',\n authenticated: true,\n formData,\n schema: customerPortalAvatarSchema,\n });\n }\n\n removeAvatar(): Promise<HeadlessCustomerAvatar> {\n return this.request('/profile/avatar', {\n method: 'DELETE',\n authenticated: true,\n schema: customerPortalAvatarSchema,\n });\n }\n\n emailPreferences(): Promise<HeadlessCustomerEmailPreferences> {\n return this.request('/email-marketing/preferences', {\n authenticated: true,\n schema: customerPortalEmailPreferencesSchema,\n });\n }\n\n updateEmailPreferences(\n patch: HeadlessCustomerEmailPreferencesPatch,\n ): Promise<HeadlessCustomerEmailPreferencesUpdate> {\n return this.request('/email-marketing/preferences', {\n method: 'PATCH',\n authenticated: true,\n body: {\n ...(patch.globalUnsubscribed === undefined\n ? {}\n : { global_unsubscribed: patch.globalUnsubscribed }),\n list_subscriptions: (patch.listSubscriptions ?? []).map((item) => ({\n list_id: item.listId,\n subscribed: item.subscribed,\n })),\n },\n schema: customerPortalEmailPreferencesUpdateSchema,\n });\n }\n\n notificationPreferences(): Promise<HeadlessCustomerNotificationPreferences> {\n return this.request('/notification-preferences', {\n authenticated: true,\n schema: customerPortalNotificationPreferencesSchema,\n });\n }\n\n updateNotificationPreferences(\n patch: HeadlessCustomerNotificationPreferencesPatch,\n ): Promise<HeadlessCustomerNotificationPreferences> {\n return this.request('/notification-preferences', {\n method: 'PATCH',\n authenticated: true,\n body: {\n ...(patch.orderCreatedEmails === undefined\n ? {}\n : { order_created_emails: patch.orderCreatedEmails }),\n ...(patch.orderCompletedEmails === undefined\n ? {}\n : { order_completed_emails: patch.orderCompletedEmails }),\n ...(patch.paymentIssueEmails === undefined\n ? {}\n : { payment_issue_emails: patch.paymentIssueEmails }),\n },\n schema: customerPortalNotificationPreferencesSchema,\n });\n }\n\n orders(options: HeadlessCustomerOrdersQuery = {}): Promise<HeadlessCustomerOrders> {\n return this.request<HeadlessCustomerOrders>('/invoices', {\n authenticated: true,\n schema: customerPortalPaginatedInvoicesSchema,\n query: {\n page: options.page === undefined ? undefined : String(options.page),\n limit: options.limit === undefined ? undefined : String(options.limit),\n status: options.status,\n q: options.search,\n },\n });\n }\n\n async order(id: string): Promise<HeadlessCustomerOrder> {\n const order = await this.request<HeadlessCustomerOrder>(`/invoice/${encodeURIComponent(id)}`, {\n authenticated: true,\n schema: customerPortalInvoiceDetailSchema,\n });\n return {\n ...order,\n lineItems: order.lineItems.map((lineItem) => ({\n ...lineItem,\n deliverySummary: lineItem.deliverySummary\n ? {\n ...lineItem.deliverySummary,\n links: lineItem.deliverySummary.links.map((link) => {\n const downloadIndex = readPortalDownloadIndex(link.href);\n return downloadIndex === null\n ? link\n : { ...link, href: null, downloadIndex };\n }),\n }\n : null,\n })),\n };\n }\n\n orderReview(orderId: string): Promise<HeadlessCustomerOrderReview> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/review`, {\n authenticated: true,\n schema: customerPortalOrderReviewSchema,\n });\n }\n\n submitOrderReview(\n orderId: string,\n input: HeadlessCustomerOrderReviewInput,\n ): Promise<HeadlessCustomerOrderReview> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/review`, {\n method: 'POST',\n authenticated: true,\n body: {\n score: input.score,\n message: input.message,\n },\n schema: customerPortalOrderReviewSchema,\n });\n }\n\n invoicePdf(orderId: string): Promise<HeadlessCustomerDownload> {\n return this.requestFile(`/invoices/${encodeURIComponent(orderId)}/pdf`);\n }\n\n replacementEligibility(\n orderId: string,\n lineItemId?: string,\n ): Promise<HeadlessCustomerReplacementEligibility> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/replacement-eligibility`, {\n authenticated: true,\n query: { line_item_id: lineItemId },\n schema: customerReplacementEligibilitySchema,\n });\n }\n\n requestReplacement(\n orderId: string,\n options: HeadlessCustomerReplacementOptions,\n ): Promise<HeadlessCustomerReplacementRequest> {\n return this.request(`/invoices/${encodeURIComponent(orderId)}/replacement-requests`, {\n method: 'POST',\n authenticated: true,\n body: {\n line_item_id: options.lineItemId,\n reason: options.reason,\n ...(options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}),\n },\n schema: customerReplacementRequestSchema,\n });\n }\n\n async download(orderId: string, fileIndex: number): Promise<HeadlessCustomerDownload> {\n if (!Number.isSafeInteger(fileIndex) || fileIndex < 0) {\n throw new HeadlessCustomerError(\n 400,\n 'download requires a non-negative integer fileIndex from order().deliverySummary.links.',\n 'INVALID_FILE_INDEX',\n );\n }\n return this.requestFile(\n `/invoice/${encodeURIComponent(orderId)}/download`,\n { file_index: String(fileIndex) },\n { rejectHtml: true },\n );\n }\n\n resetLicenseHwid(licenseId: string): Promise<HeadlessCustomerLicenseReset> {\n return this.request(`/licenses/${encodeURIComponent(licenseId)}/reset-hwid`, {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerPortalLicenseResetSchema,\n });\n }\n\n renewLicense(licenseId: string): Promise<HeadlessCustomerLicenseRenewal> {\n return this.request(`/licenses/${encodeURIComponent(licenseId)}/renew`, {\n method: 'POST',\n authenticated: true,\n // This established route requires shop in the body. The shared headless\n // gate independently verifies the same shop from the query and key.\n body: { shop: this.shop },\n schema: customerPortalLicenseRenewalSchema,\n });\n }\n\n walletTopupQuote(): Promise<HeadlessCustomerWalletTopupQuote> {\n return this.request('/wallet/topup-quote', {\n authenticated: true,\n schema: customerPortalWalletTopupQuoteSchema,\n });\n }\n\n createWalletTopup(amount: string): Promise<HeadlessCustomerWalletTopup> {\n return this.request('/wallet/topup', {\n method: 'POST',\n authenticated: true,\n body: { amount },\n schema: customerPortalWalletTopupResultSchema,\n });\n }\n\n subscriptionBillingHistory(\n subscriptionId: string,\n ): Promise<HeadlessCustomerSubscriptionBillingHistory> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/billing-history`, {\n authenticated: true,\n schema: customerPortalSubscriptionBillingHistorySchema,\n });\n }\n\n cancelSubscription(\n subscriptionId: string,\n options: HeadlessCustomerSubscriptionCancelOptions = {},\n ): Promise<HeadlessCustomerSubscriptionCancel> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/cancel`, {\n method: 'POST',\n authenticated: true,\n body: {\n ...(options.cancelAtPeriodEnd === undefined\n ? {}\n : { cancel_at_period_end: options.cancelAtPeriodEnd }),\n ...(options.reason === undefined ? {} : { reason: options.reason }),\n },\n schema: customerPortalSubscriptionCancelSchema,\n });\n }\n\n pauseSubscription(subscriptionId: string): Promise<HeadlessCustomerSubscriptionStatus> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/pause`, {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerPortalSubscriptionStatusSchema,\n });\n }\n\n resumeSubscription(subscriptionId: string): Promise<HeadlessCustomerSubscriptionStatus> {\n return this.request(`/subscriptions/${encodeURIComponent(subscriptionId)}/resume`, {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerPortalSubscriptionStatusSchema,\n });\n }\n\n loyalty(): Promise<HeadlessCustomerLoyalty> {\n return this.request('/loyalty', {\n authenticated: true,\n schema: customerLoyaltySchema,\n });\n }\n\n redeemLoyaltyPoints(input: {\n points: number;\n idempotencyKey: string;\n }): Promise<HeadlessCustomerLoyaltyRedeem> {\n return this.request('/loyalty/redeem', {\n method: 'POST',\n authenticated: true,\n body: { points: input.points, idempotency_key: input.idempotencyKey },\n schema: customerLoyaltyRedeemSchema,\n });\n }\n\n warranties(invoiceId?: string): Promise<HeadlessCustomerWarranties> {\n return this.request('/warranties', {\n authenticated: true,\n query: { invoice: invoiceId },\n schema: customerWarrantyListSchema,\n });\n }\n\n claimWarranty(warrantyId: string, message?: string): Promise<HeadlessCustomerWarrantyClaim> {\n return this.request(`/warranties/${encodeURIComponent(warrantyId)}/claim`, {\n method: 'POST',\n authenticated: true,\n body: message ? { message } : {},\n schema: customerWarrantyClaimSchema,\n });\n }\n\n favorites(): Promise<HeadlessCustomerFavorites> {\n return this.request('/favorites', {\n authenticated: true,\n schema: customerPortalFavoritesSchema,\n });\n }\n\n addFavorite(productId: string): Promise<HeadlessCustomerFavoriteMutation> {\n return this.request(`/favorites/${encodeURIComponent(productId)}`, {\n method: 'PUT',\n authenticated: true,\n schema: customerPortalFavoriteMutationSchema,\n });\n }\n\n removeFavorite(productId: string): Promise<HeadlessCustomerFavoriteMutation> {\n return this.request(`/favorites/${encodeURIComponent(productId)}`, {\n method: 'DELETE',\n authenticated: true,\n schema: customerPortalFavoriteMutationSchema,\n });\n }\n\n affiliate(): Promise<HeadlessCustomerAffiliate> {\n return this.request('/affiliate', {\n authenticated: true,\n schema: customerPortalAffiliateSummarySchema,\n });\n }\n\n affiliateStats(input?: { days?: number }): Promise<HeadlessCustomerAffiliateStats> {\n return this.request('/affiliate/stats', {\n authenticated: true,\n schema: customerPortalAffiliateStatsSchema,\n query: input?.days === undefined ? {} : { days: String(input.days) },\n });\n }\n\n createAffiliateLink(\n input: HeadlessCustomerAffiliateLinkInput,\n ): Promise<HeadlessCustomerAffiliateLink> {\n return this.request('/affiliate/links', {\n method: 'POST',\n authenticated: true,\n body: {\n shop: this.shop,\n code: input.code,\n label: input.label,\n ...(input.requestedRevenuePercent === undefined\n ? {}\n : { requested_affiliate_revenue_percent: input.requestedRevenuePercent }),\n ...(input.requestedCustomerDiscountPercent === undefined\n ? {}\n : { requested_affiliate_customer_discount_percent: input.requestedCustomerDiscountPercent }),\n },\n schema: customerPortalAffiliateCreateLinkSchema,\n });\n }\n\n createTicket(input: HeadlessCustomerTicketInput): Promise<HeadlessCustomerTicketCreateResult> {\n return this.request('/tickets', {\n method: 'POST',\n authenticated: true,\n body: {\n ...(input.title === undefined ? {} : { title: input.title }),\n message: input.message,\n ...(input.invoiceId === undefined ? {} : { invoice_id: input.invoiceId }),\n },\n schema: customerPortalSupportCreateSchema,\n });\n }\n\n ticket(ticketId: string): Promise<HeadlessCustomerTicket> {\n return this.request(`/tickets/${encodeURIComponent(ticketId)}`, {\n authenticated: true,\n schema: customerPortalSupportTicketDetailSchema,\n });\n }\n\n async replyToTicket(ticketId: string, message: string): Promise<void> {\n await this.request<null>(`/tickets/${encodeURIComponent(ticketId)}/reply`, {\n method: 'POST',\n authenticated: true,\n body: { message },\n });\n }\n\n reseller(): Promise<HeadlessCustomerReseller> {\n return this.request('/reseller', {\n authenticated: true,\n schema: customerResellerSummarySchema,\n });\n }\n\n applyForReseller(note?: string): Promise<HeadlessCustomerResellerEnrollment> {\n return this.request('/reseller/apply', {\n method: 'POST',\n authenticated: true,\n body: note === undefined ? {} : { note },\n schema: customerResellerEnrollmentSchema,\n });\n }\n\n enrollAsReseller(): Promise<HeadlessCustomerResellerEnrollment> {\n return this.request('/reseller/enroll', {\n method: 'POST',\n authenticated: true,\n body: {},\n schema: customerResellerEnrollmentSchema,\n });\n }\n\n acceptResellerInvite(token: string): Promise<HeadlessCustomerResellerEnrollment> {\n return this.request('/reseller/accept-invite', {\n method: 'POST',\n authenticated: true,\n body: { token },\n schema: customerResellerEnrollmentSchema,\n });\n }\n\n resellerCatalog(\n options: HeadlessCustomerResellerCatalogQuery = {},\n ): Promise<HeadlessCustomerResellerCatalog> {\n return this.request('/reseller/catalog', {\n authenticated: true,\n query: {\n search: options.search,\n page: options.page === undefined ? undefined : String(options.page),\n per_page: options.perPage === undefined ? undefined : String(options.perPage),\n },\n schema: customerResellerCatalogSchema,\n });\n }\n\n quoteResellerOrder(\n items: HeadlessCustomerResellerOrderItem[],\n ): Promise<HeadlessCustomerResellerQuote> {\n return this.request('/reseller/orders/quote', {\n method: 'POST',\n authenticated: true,\n body: {\n items: items.map((item) => ({\n product_id: item.productId,\n ...(item.variantId === undefined ? {} : { variant_id: item.variantId }),\n quantity: item.quantity,\n })),\n },\n schema: customerResellerQuoteSchema,\n });\n }\n\n resellerOrders(\n options: HeadlessCustomerResellerOrdersQuery = {},\n ): Promise<HeadlessCustomerResellerOrders> {\n return this.request('/reseller/orders', {\n authenticated: true,\n query: {\n page: options.page === undefined ? undefined : String(options.page),\n per_page: options.perPage === undefined ? undefined : String(options.perPage),\n },\n schema: customerResellerOrdersSchema,\n });\n }\n\n resellerOrder(orderId: string): Promise<HeadlessCustomerResellerOrder> {\n return this.request(`/reseller/orders/${encodeURIComponent(orderId)}`, {\n authenticated: true,\n schema: customerResellerOrderSchema,\n });\n }\n\n resellerWallet(): Promise<HeadlessCustomerResellerWallet> {\n return this.request('/reseller/wallet', {\n authenticated: true,\n schema: customerResellerWalletSchema,\n });\n }\n\n resellerTopupQuote(): Promise<HeadlessCustomerWalletTopupQuote> {\n return this.request('/reseller/wallet/topup-quote', {\n authenticated: true,\n schema: customerPortalWalletTopupQuoteSchema,\n });\n }\n\n createResellerTopup(amount: string): Promise<HeadlessCustomerResellerTopup> {\n return this.request('/reseller/wallet/topup', {\n method: 'POST',\n authenticated: true,\n body: { amount },\n schema: customerResellerTopupSchema,\n });\n }\n\n resellerApiKeys(): Promise<HeadlessCustomerResellerApiKeys> {\n return this.request('/reseller/api-keys', {\n authenticated: true,\n schema: customerResellerApiKeysSchema,\n });\n }\n\n async logout(): Promise<void> {\n if (!this.getSession()) return;\n try {\n await this.request<null>('/auth/logout', { method: 'POST', authenticated: true });\n } catch (error) {\n if (error instanceof HeadlessCustomerError && error.status === 401) {\n // The server already considers the credential invalid. request() also\n // clears it, so logout is complete from the buyer's perspective.\n return;\n }\n // Keep the local token after a transient failure so the caller can retry\n // server-side revocation instead of leaving an unreachable live session.\n throw error;\n }\n this.clearSession();\n }\n}\n\nexport function createCustomerClient(config: HeadlessCustomerClientConfig): HeadlessCustomerClient {\n return new HeadlessCustomerClient(config);\n}\n"],"mappings":"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","names":["stored"]}
|
package/dist/index.cjs
CHANGED
|
@@ -17026,6 +17026,18 @@ var publicInvoiceWireSchema = external_exports.object({
|
|
|
17026
17026
|
* the reader: this schema is not it.
|
|
17027
17027
|
*/
|
|
17028
17028
|
coupon_applied: external_exports.boolean().optional(),
|
|
17029
|
+
/**
|
|
17030
|
+
* How much of the order the applied coupon reaches, in lines — null when it
|
|
17031
|
+
* covers every line or no coupon is on the order. Counts only, so nothing
|
|
17032
|
+
* about which products the merchant scoped the code to leaves the server.
|
|
17033
|
+
* The discount line already shows the reduced amount; this is what lets the
|
|
17034
|
+
* checkout say "applied to 1 of 3 items" instead of leaving a smaller-than-
|
|
17035
|
+
* advertised discount to read as a broken code.
|
|
17036
|
+
*/
|
|
17037
|
+
coupon_scope: external_exports.object({
|
|
17038
|
+
eligible_line_count: external_exports.number(),
|
|
17039
|
+
line_count: external_exports.number()
|
|
17040
|
+
}).nullable().optional(),
|
|
17029
17041
|
crypto_mode: external_exports.string().nullable().optional(),
|
|
17030
17042
|
crypto_transactions: external_exports.array(cryptoTransactionSchema).optional(),
|
|
17031
17043
|
currency: external_exports.string().nullable(),
|