woocommerce-rest-ts-api
Version:
WooCommerce REST API - Type Script Library
8 lines (7 loc) • 48.5 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/index.ts", "../src/types/errors/index.ts", "../src/utils/sanitize.ts", "../src/http/RetryStrategy.ts", "../src/http/Throttler.ts", "../src/http/ErrorNormalizer.ts", "../src/utils/PaginationHelper.ts"],
"sourcesContent": ["import type { RawAxiosRequestHeaders, AxiosRequestConfig } from \"axios\";\nimport crypto from \"node:crypto\";\nimport http from \"node:http\";\nimport https from \"node:https\";\nimport OAuth from \"oauth-1.0a\";\nimport Url from \"url-parse\";\n\n// All types now come from the new modular structure (core/requests/responses/errors/models + barrels)\nimport type {\n WooRestApiMethod,\n IWooRestApiOptions,\n WooRestApiEndpoint,\n OrdersMainParams,\n ProductsMainParams,\n SystemStatusParams,\n CouponsParams,\n CustomersParams,\n DELETE,\n Orders,\n Products,\n Customers,\n Coupons,\n SystemStatus,\n WooCommerceApiResponse,\n} from \"./types/index.js\";\nimport {\n OptionsException,\n} from \"./types/index.js\";\n\n// Reusable abstractions (RequestSanitizer, RetryStrategy, Throttler, ErrorNormalizer)\nimport {\n sanitizePathSegment,\n sanitizeEndpoint,\n sanitizeApiVersion,\n validateBaseUrl,\n} from \"./utils/sanitize.js\";\nimport { createDefaultRetryStrategy, type RetryStrategy } from \"./http/RetryStrategy.js\";\nimport { createThrottler, type Throttler } from \"./http/Throttler.js\";\nimport { normalizeAxiosError } from \"./http/ErrorNormalizer.js\";\n\n// Default keep-alive agents for connection reuse (high-impact perf improvement under load).\n// Users can still fully override via axiosConfig.httpAgent / httpsAgent.\nconst DEFAULT_HTTP_AGENT = new http.Agent({ keepAlive: true, maxSockets: 32 });\nconst DEFAULT_HTTPS_AGENT = new https.Agent({ keepAlive: true, maxSockets: 32 });\n\n// Re-export the full public surface (types + error classes) for consumers + backward compat\nexport type {\n WooRestApiMethod,\n IWooRestApiQuery,\n IWooRestApiOptions,\n WooRestApiEndpoint,\n OrdersMainParams,\n ProductsMainParams,\n SystemStatusParams,\n CouponsParams,\n CustomersParams,\n DELETE,\n Orders,\n Products,\n Customers,\n Coupons,\n SystemStatus,\n WooCommerceApiResponse,\n} from \"./types/index.js\";\nexport { WooCommerceApiError, AuthenticationError, OptionsException } from \"./types/index.js\";\n\n/**\n * Set the axiosConfig property to the axios config object.\n */\nexport type WooRestApiOptions = IWooRestApiOptions<AxiosRequestConfig>;\n\n/**\n * Set all the possible query params for the WooCommerce REST API.\n */\nexport type WooRestApiParams = CouponsParams &\n CustomersParams &\n OrdersMainParams &\n ProductsMainParams &\n SystemStatusParams &\n DELETE;\n\n// Sanitizers are now provided by the reusable RequestSanitizer module (src/utils/sanitize.ts).\n// The functions are pure and throw OptionsException for bad input (path traversal etc).\n\n/**\n * WooCommerce REST API wrapper\n *\n * @param {Object} opt\n */\nexport default class WooCommerceRestApi<T extends WooRestApiOptions> {\n protected _opt: T;\n\n // Composed collaborators (internal DI for modularity + extensibility).\n // These are created from options at construction time. Advanced users can subclass and override\n // protected factory methods if they want to inject custom strategies (while keeping full public BC).\n protected _throttler: Throttler;\n protected _retryStrategy: RetryStrategy;\n\n /**\n * Class constructor.\n *\n * @param {Object} opt\n */\n constructor(opt: T) {\n this._opt = opt;\n\n /**\n * If the class is not instantiated, return a new instance.\n * This is useful for the static methods.\n */\n if (!(this instanceof WooCommerceRestApi)) {\n return new WooCommerceRestApi(opt);\n }\n\n /**\n * Check if the url is defined.\n */\n if (!this._opt.url || this._opt.url === \"\") {\n throw new OptionsException(\"url is required\");\n }\n // SECURITY: validate early (throws OptionsException on bad input)\n validateBaseUrl(this._opt.url);\n\n /**\n * Check if the consumerKey is defined.\n */\n if (!this._opt.consumerKey || this._opt.consumerKey === \"\") {\n throw new OptionsException(\"consumerKey is required\");\n }\n\n /**\n * Check if the consumerSecret is defined.\n */\n if (!this._opt.consumerSecret || this._opt.consumerSecret === \"\") {\n throw new OptionsException(\"consumerSecret is required\");\n }\n\n /**\n * Set default options (also runs sanitization)\n */\n this._setDefaultsOptions(this._opt);\n\n // Create composed strategies (DI)\n this._throttler = createThrottler(this._opt.maxConcurrentRequests);\n this._retryStrategy = createDefaultRetryStrategy(this._opt.retryConfig);\n }\n\n /**\n * Set default options\n *\n * @param {Object} opt\n */\n _setDefaultsOptions(opt: T): void {\n // SECURITY: sanitize critical path segments to block traversal / injection into final REST URL\n const rawPrefix = opt.wpAPIPrefix || \"wp-json\";\n const rawVersion = opt.version || \"wc/v3\";\n\n this._opt.wpAPIPrefix = sanitizePathSegment(rawPrefix, \"wpAPIPrefix\");\n // version legitimately contains one \"/\" (wc/v3); use tolerant sanitizer\n this._opt.version = sanitizeApiVersion(rawVersion);\n\n this._opt.isHttps = /^https/i.test(this._opt.url);\n this._opt.encoding = opt.encoding || \"utf-8\";\n this._opt.queryStringAuth = opt.queryStringAuth || false;\n // Keep in sync with package.json version (woocommerce-rest-ts-api).\n this._opt.classVersion = opt.classVersion || \"8.0.0\";\n }\n\n /**\n * Protected factory hooks for subclass DI / custom strategies (advanced extensibility).\n * Default implementations are created in ctor from options.\n */\n protected createThrottler(max?: number): Throttler {\n return createThrottler(max);\n }\n\n protected createRetryStrategy(cfg?: IWooRestApiOptions[\"retryConfig\"]): RetryStrategy {\n return createDefaultRetryStrategy(cfg);\n }\n\n // Backward-compat thin delegations (tests and power users call these _ methods directly)\n private async _acquireSlot(): Promise<void> {\n return this._throttler.acquire();\n }\n\n private _releaseSlot(): void {\n this._throttler.release();\n }\n\n /**\n * Core axios execution delegated to the (pluggable) RetryStrategy.\n * The strategy encapsulates exp backoff + 429 awareness.\n */\n private async _executeWithRetry(options: AxiosRequestConfig): Promise<import(\"axios\").AxiosResponse> {\n return this._retryStrategy.executeWithRetry(options);\n }\n\n /**\n * Normalize query string for oAuth 1.0a.\n * Nested param flattening lives in callers / URL builders; the legacy\n * commented-out `_parseParamsObject` was dead code and has been removed.\n *\n * @param {String} url\n * @param {Object} params\n *\n * @return {String}\n */\n _normalizeQueryString(\n url: string,\n params: Partial<Record<string, any>>,\n ): string {\n /**\n * Exit if url and params are not defined\n */\n if (url.indexOf(\"?\") === -1 && Object.keys(params).length === 0) {\n return url;\n }\n const query = new Url(url, true).query; // Parse the query string returned by the url\n\n const values = [];\n\n let queryString = \"\";\n\n /**\n * Loop through the params object and push the key and value into the values array\n * Example: values = ['key1=value1', 'key2=value2']\n */\n for (const key in query) {\n values.push(key);\n }\n\n values.sort(); // Sort the values array\n\n for (const i in values) {\n /*\n * If the queryString is not empty, add an ampersand to the end of the string\n */\n if (queryString.length) queryString += \"&\";\n\n /**\n * Add the key and value to the queryString\n */\n queryString +=\n encodeURIComponent(values[i]) +\n \"=\" +\n encodeURIComponent(<string | number | boolean>query[values[i]]);\n }\n /**\n * Replace %5B with [ and %5D with ]\n */\n queryString = queryString.replace(/%5B/g, \"[\").replace(/%5D/g, \"]\");\n\n /**\n * Return the url with the queryString\n */\n const urlObject = url.split(\"?\")[0] + \"?\" + queryString;\n\n return urlObject;\n }\n\n /**\n * Get URL\n *\n * SECURITY: Always sanitizes the endpoint. Uses URL where practical + guards.\n */\n _getUrl(endpoint: string, params: Partial<Record<string, unknown>>): string {\n const safeEndpoint = sanitizeEndpoint(endpoint);\n\n const base = this._opt.url.endsWith(\"/\") ? this._opt.url : this._opt.url + \"/\";\n // Build safely\n let url = `${base}${this._opt.wpAPIPrefix}/${this._opt.version}/${safeEndpoint}`;\n\n // id handling (mutates copy of params for query)\n const q = { ...params };\n if (q.id != null) {\n url = `${url}/${encodeURIComponent(String(q.id))}`;\n delete q.id;\n }\n\n // Query string via safe encoding (no object prototype issues)\n const queryKeys = Object.keys(q);\n if (queryKeys.length > 0) {\n const qs = queryKeys\n .sort() // stable for OAuth if ever used\n .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(String(q[k]))}`)\n .join(\"&\");\n url = `${url}?${qs}`;\n }\n\n // Port injection (rare)\n if (this._opt.port) {\n try {\n const u = new URL(url);\n u.port = String(this._opt.port);\n url = u.toString();\n } catch {\n // fall back to previous behavior using url-parse for weird cases\n const hostname = new Url(url).hostname;\n url = url.replace(hostname, `${hostname}:${this._opt.port}`);\n }\n }\n\n return url;\n }\n\n /**\n * Create Hmac was deprecated fot this version at 16.11.2022\n * Get OAuth 1.0a since it is mandatory for WooCommerce REST API\n * You must use OAuth 1.0a \"one-legged\" authentication to ensure REST API credentials cannot be intercepted by an attacker.\n * Reference: https://woocommerce.github.io/woocommerce-rest-api-docs/#authentication-over-http\n * @return {Object}\n */\n _getOAuth(): OAuth {\n const data = {\n consumer: {\n key: this._opt.consumerKey,\n secret: this._opt.consumerSecret,\n },\n signature_method: \"HMAC-SHA256\",\n hash_function: (base: string, key: string) => {\n return crypto.createHmac(\"sha256\", key).update(base).digest(\"base64\");\n },\n };\n\n return new OAuth(data);\n }\n\n /**\n * Axios request\n * Mount the options to send to axios and send the request.\n *\n * Implements:\n * - Resource limits (maxContentLength / maxBodyLength) to fully mitigate CVE-2026-44488\n * - Default timeout enforcement (30s) for safety\n * - Client-side request throttling via maxConcurrentRequests\n * - Exponential backoff retries with rate-limit (429 / Retry-After) awareness\n *\n * All via _request core + axiosConfig support. Backward compatible.\n *\n * @param {String} method\n * @param {String} endpoint\n * @param {Object} data\n * @param {Object} params\n *\n * @return {Object}\n */\n async _request(\n method: WooRestApiMethod,\n endpoint: string,\n data?: Record<string, unknown>,\n params: Record<string, unknown> = {},\n ): Promise<import(\"axios\").AxiosResponse> {\n const url = this._getUrl(endpoint, params);\n\n const header: RawAxiosRequestHeaders = {\n Accept: \"application/json\",\n };\n if (\n typeof process !== \"undefined\" &&\n Object.prototype.toString.call(process) === \"[object process]\"\n ) {\n header[\"User-Agent\"] =\n \"WooCommerce REST API - TS Client/\" + this._opt.classVersion;\n }\n\n const DEFAULT_MAX_CONTENT_LENGTH = 10 * 1024 * 1024;\n const DEFAULT_MAX_BODY_LENGTH = 10 * 1024 * 1024;\n const DEFAULT_TIMEOUT = 30000;\n\n const axCfg: Record<string, unknown> = (this._opt.axiosConfig as Record<string, unknown>) ?? {};\n const explicitMaxContent = \"maxContentLength\" in axCfg ? (axCfg.maxContentLength as number | undefined) : undefined;\n const explicitMaxBody = \"maxBodyLength\" in axCfg ? (axCfg.maxBodyLength as number | undefined) : undefined;\n const explicitTimeout = \"timeout\" in axCfg ? (axCfg.timeout as number | undefined) : undefined;\n\n // For https we intentionally strip the query string that _getUrl may have appended.\n // We rely on `options.params` (set below) so axios serializes the qs exactly once.\n // This fixes the latent duplication bug (?foo=1&foo=1) that occurred because _getUrl always\n // injected user query and then https path also set options.params.\n // Non-https (OAuth) keeps the full url because the signature must cover the exact query string.\n const axiosUrl = this._opt.isHttps ? url.split(\"?\")[0] : url;\n\n let options: AxiosRequestConfig = {\n url: axiosUrl,\n method,\n responseEncoding: this._opt.encoding,\n timeout: explicitTimeout !== undefined ? explicitTimeout : (this._opt.timeout ?? DEFAULT_TIMEOUT),\n responseType: \"json\",\n headers: { ...header },\n params: {},\n data: data ? JSON.stringify(data) : null,\n // Pre-set limits; may be overridden by explicit axiosConfig below\n maxContentLength: explicitMaxContent !== undefined ? explicitMaxContent : (this._opt.maxContentLength ?? DEFAULT_MAX_CONTENT_LENGTH),\n maxBodyLength: explicitMaxBody !== undefined ? explicitMaxBody : (this._opt.maxBodyLength ?? DEFAULT_MAX_BODY_LENGTH),\n };\n\n /**\n * If isHttps is false, add the query string to the params object\n */\n if (this._opt.isHttps) {\n if (this._opt.queryStringAuth) {\n options.params = {\n consumer_key: this._opt.consumerKey,\n consumer_secret: this._opt.consumerSecret,\n };\n } else {\n options.auth = {\n username: this._opt.consumerKey,\n password: this._opt.consumerSecret,\n };\n }\n\n // Do not leak \"id\" into query string for https path-style resources (id is already in path via _getUrl).\n // Prevents spurious ?id=123 on single-resource calls in addition to the path segment.\n const queryParams = { ...params };\n if (queryParams.id != null) {\n delete queryParams.id;\n }\n options.params = { ...options.params, ...queryParams };\n } else {\n options.params = this._getOAuth().authorize({\n url, // full url (with qs) for correct OAuth signature\n method,\n });\n }\n\n if (options.data) {\n options.headers = {\n ...header,\n \"Content-Type\": `application/json; charset=${this._opt.encoding}`,\n };\n }\n\n // Allow set and override Axios options (user axiosConfig wins for any keys provided).\n options = { ...options, ...this._opt.axiosConfig };\n\n // Apply keep-alive agents if the user did not explicitly provide httpAgent/httpsAgent.\n // This is a high-impact performance improvement for sustained traffic to the same host\n // (connection reuse, reduced handshake/TIME_WAIT overhead). 100% backward compatible:\n // any explicit agent in axiosConfig takes precedence (including setting to null/undefined to disable).\n if (!(\"httpAgent\" in options) && !(\"httpsAgent\" in options) && !(\"agent\" in options)) {\n const isHttpsRequest = /^https:/i.test(String(options.url || \"\"));\n if (isHttpsRequest) {\n (options as any).httpsAgent = (options as any).httpsAgent ?? DEFAULT_HTTPS_AGENT;\n } else {\n (options as any).httpAgent = (options as any).httpAgent ?? DEFAULT_HTTP_AGENT;\n }\n }\n\n // Final safety: if after merge no positive finite timeout is set, enforce default.\n // This provides \"timeout enforcement\". 0 or negative is treated as \"use default\".\n if (options.timeout == null || options.timeout <= 0) {\n options.timeout = DEFAULT_TIMEOUT;\n }\n\n // Final safety clamp on size limits if user did not explicitly set them (incl. via axiosConfig)\n // and they ended up missing/unbounded after merge. Prevents accidental bypass of mitigation.\n if (options.maxContentLength == null || options.maxContentLength < 0) {\n // Only force default when truly unbounded (null/undefined or explicitly -1 was not passed through)\n // If user passed -1 explicitly it will have been set above and survive merge.\n if (explicitMaxContent === undefined) {\n options.maxContentLength = this._opt.maxContentLength ?? DEFAULT_MAX_CONTENT_LENGTH;\n }\n }\n if (options.maxBodyLength == null || options.maxBodyLength < 0) {\n if (explicitMaxBody === undefined) {\n options.maxBodyLength = this._opt.maxBodyLength ?? DEFAULT_MAX_BODY_LENGTH;\n }\n }\n\n // Throttling + retry-protected execution.\n await this._acquireSlot();\n try {\n return await this._executeWithRetry(options);\n } catch (error: unknown) {\n throw normalizeAxiosError(error, { endpoint });\n } finally {\n this._releaseSlot();\n }\n }\n\n /**\n * GET requests\n *\n * @param {String} endpoint\n * @param {Object} params\n *\n * @return {Object}\n */\n get<T = unknown>(\n endpoint: WooRestApiEndpoint,\n params?: Partial<WooRestApiParams>,\n ): Promise<WooCommerceApiResponse<T>> {\n return this._request(\"GET\", endpoint, undefined, params).then(\n (response) => ({\n data: response.data as T,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as WooCommerceApiResponse<T>[\"headers\"],\n }),\n );\n }\n\n post<T = unknown>(\n endpoint: WooRestApiEndpoint,\n data: Record<string, unknown>,\n params?: Partial<WooRestApiParams>,\n ): Promise<WooCommerceApiResponse<T>> {\n return this._request(\"POST\", endpoint, data, params).then((response) => ({\n data: response.data as T,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as WooCommerceApiResponse<T>[\"headers\"],\n }));\n }\n\n put<T = unknown>(\n endpoint: WooRestApiEndpoint,\n data: Record<string, unknown>,\n params?: Partial<WooRestApiParams>,\n ): Promise<WooCommerceApiResponse<T>> {\n return this._request(\"PUT\", endpoint, data, params).then((response) => ({\n data: response.data as T,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as WooCommerceApiResponse<T>[\"headers\"],\n }));\n }\n\n delete<T = unknown>(\n endpoint: WooRestApiEndpoint,\n data: Pick<WooRestApiParams, \"force\">,\n params: Pick<WooRestApiParams, \"id\">,\n ): Promise<WooCommerceApiResponse<T>> {\n return this._request(\"DELETE\", endpoint, data, params).then((response) => ({\n data: response.data as T,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as WooCommerceApiResponse<T>[\"headers\"],\n }));\n }\n\n options<T = unknown>(\n endpoint: WooRestApiEndpoint,\n params?: Partial<WooRestApiParams>,\n ): Promise<WooCommerceApiResponse<T>> {\n return this._request(\"OPTIONS\", endpoint, {}, params).then((response) => ({\n data: response.data as T,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as WooCommerceApiResponse<T>[\"headers\"],\n }));\n }\n\n // Convenience methods (still available for DX; fully typed)\n async getProducts(params?: Record<string, unknown>): Promise<WooCommerceApiResponse<Products[]>> {\n return this.get<Products[]>(\"products\", params);\n }\n\n async getProduct(id: number): Promise<WooCommerceApiResponse<Products>> {\n return this.get<Products>(\"products\", { id });\n }\n\n async createProduct(productData: Partial<Products>): Promise<WooCommerceApiResponse<Products>> {\n return this.post<Products>(\"products\", productData);\n }\n\n async updateProduct(id: number, productData: Partial<Products>): Promise<WooCommerceApiResponse<Products>> {\n return this.put<Products>(\"products\", productData, { id });\n }\n\n async getOrders(params?: Record<string, unknown>): Promise<WooCommerceApiResponse<Orders[]>> {\n return this.get<Orders[]>(\"orders\", params);\n }\n\n async getOrder(id: number): Promise<WooCommerceApiResponse<Orders>> {\n return this.get<Orders>(\"orders\", { id });\n }\n\n async createOrder(orderData: Partial<Orders>): Promise<WooCommerceApiResponse<Orders>> {\n return this.post<Orders>(\"orders\", orderData);\n }\n\n async getCustomers(params?: Partial<CustomersParams>): Promise<WooCommerceApiResponse<Customers[]>> {\n return this.get<Customers[]>(\"customers\", params);\n }\n\n async getCustomer(id: number): Promise<WooCommerceApiResponse<Customers>> {\n return this.get<Customers>(\"customers\", { id });\n }\n\n async getCoupons(params?: Partial<CouponsParams>): Promise<WooCommerceApiResponse<Coupons[]>> {\n return this.get<Coupons[]>(\"coupons\", params);\n }\n\n async getSystemStatus(): Promise<WooCommerceApiResponse<SystemStatus>> {\n return this.get<SystemStatus>(\"system_status\");\n }\n}\n\n// Error classes are now defined in src/types/errors (with proper extends Error) and re-exported above.\n// The old non-Error OptionsException and any-typed WooCommerceApiError have been removed for security + correctness.\n\n// Re-export the new reusable helpers (additive, full backward compat)\nexport { parsePaginationHeaders, collectAllPages, type PaginationInfo } from \"./utils/PaginationHelper.js\";\n", "/**\n * Error types for the WooCommerce REST API client.\n * Proper Error subclasses (no more plain object OptionsException).\n */\n\nexport class WooCommerceApiError extends Error {\n public statusCode?: number;\n public response?: unknown;\n public endpoint?: string;\n\n constructor(\n message: string,\n statusCode?: number,\n response?: unknown,\n endpoint?: string,\n ) {\n super(message);\n this.name = \"WooCommerceApiError\";\n this.statusCode = statusCode;\n this.response = response;\n this.endpoint = endpoint;\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, WooCommerceApiError);\n }\n }\n}\n\nexport class AuthenticationError extends WooCommerceApiError {\n constructor(message = \"Authentication failed\") {\n super(message, 401);\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class OptionsException extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OptionsException\";\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, OptionsException);\n }\n }\n}\n", "/**\n * RequestSanitizer utilities.\n * Extracted for reusability, testability, and to support future HttpClientBase / UrlBuilder.\n * All functions throw OptionsException (proper Error) on invalid input.\n */\n\nimport { OptionsException } from \"../types/index.js\";\nimport type { WooRestApiVersion } from \"../types/options/index.js\";\n\n// Re-export from the single source of truth (src/types/options) for callers that imported from sanitize.\nexport type { WooRestApiVersion } from \"../types/options/index.js\";\n\nconst SAFE_SEGMENT = /^[a-zA-Z0-9._-]+$/;\n\nexport function sanitizePathSegment(segment: string, name: string): string {\n if (typeof segment !== \"string\" || segment.length === 0) {\n throw new OptionsException(`${name} must be a non-empty string`);\n }\n // Check raw input first for obvious traversal attempts (before any collapsing)\n if (segment.includes(\"..\")) {\n throw new OptionsException(`Invalid ${name}: contains path traversal or illegal characters`);\n }\n const cleaned = segment\n .replace(/\\.+/g, \".\")\n .replace(/\\/+/g, \"/\")\n .replace(/^\\/+|\\/+$/g, \"\");\n\n if (cleaned.includes(\"..\") || cleaned.includes(\"/\") || !SAFE_SEGMENT.test(cleaned)) {\n throw new OptionsException(`Invalid ${name}: contains path traversal or illegal characters`);\n }\n return cleaned;\n}\n\nexport function sanitizeEndpoint(endpoint: string): string {\n if (typeof endpoint !== \"string\" || endpoint.length === 0) {\n throw new OptionsException(\"endpoint must be a non-empty string\");\n }\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(endpoint) || endpoint.includes(\"://\") || endpoint.startsWith(\"/\") || endpoint.includes(\"..\") || /[?#]/.test(endpoint)) {\n throw new OptionsException(\"Invalid endpoint: must be a relative path segment without traversal or protocol\");\n }\n const parts = endpoint.split(\"/\").filter(Boolean);\n const safeParts = parts.map((p, i) => sanitizePathSegment(p, `endpoint part[${i}]`));\n return safeParts.join(\"/\");\n}\n\nexport function sanitizeApiVersion(v: string): WooRestApiVersion {\n const cleaned = String(v || \"\").trim().replace(/^\\/+|\\/+$/g, \"\");\n if (cleaned.includes(\"..\") || cleaned.split(\"/\").length > 2 || !/^[a-zA-Z0-9/._-]+$/.test(cleaned)) {\n throw new OptionsException(\"Invalid version: contains path traversal or illegal characters\");\n }\n return cleaned as WooRestApiVersion;\n}\n\nexport function validateBaseUrl(urlStr: string): URL {\n let u: URL;\n try {\n u = new URL(urlStr);\n } catch {\n throw new OptionsException(\"url must be a valid absolute URL (http/https)\");\n }\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") {\n throw new OptionsException(\"url must use http or https protocol\");\n }\n return u;\n}\n", "/**\n * RetryStrategy abstraction.\n * Allows pluggable retry policies (exponential, linear, none, circuit-breaker future, etc).\n * Default implementation: exponential backoff with jitter + special handling for 429 Retry-After.\n * Used by the internal HTTP execution path (and available for HttpClientBase extensions).\n */\n\nimport type { AxiosRequestConfig, AxiosResponse } from \"axios\";\nimport axios from \"axios\";\n\nexport interface RetryConfig {\n retries?: number; // 0 = no retries\n retryDelay?: number; // base delay ms\n retryOn?: number[]; // status codes to retry (in addition to network errors)\n}\n\nexport interface RetryStrategy {\n /**\n * Execute the axios request with the strategy's retry policy.\n * Must throw the last error (or normalized) if all attempts exhausted.\n */\n executeWithRetry(options: AxiosRequestConfig): Promise<AxiosResponse>;\n}\n\nexport class ExponentialBackoffRetryStrategy implements RetryStrategy {\n private readonly config: RetryConfig;\n constructor(cfg: RetryConfig = {}) {\n this.config = cfg;\n }\n\n async executeWithRetry(options: AxiosRequestConfig): Promise<AxiosResponse> {\n const maxRetries = this.config.retries ?? 0;\n const baseDelay = this.config.retryDelay ?? 1000;\n const retryableStatuses: number[] = this.config.retryOn ?? [408, 429, 500, 502, 503, 504];\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await axios(options);\n } catch (error: unknown) {\n lastError = error;\n\n // Narrowing without any\n const err = error as { response?: { status?: number; headers?: Record<string, unknown> }; code?: string; message?: string };\n const status: number | undefined = err.response?.status;\n const isNetworkError = !err.response || err.code === \"ECONNRESET\" || err.code === \"ETIMEDOUT\" || err.code === \"ECONNABORTED\";\n const isRetryableStatus = !status || retryableStatuses.includes(status);\n\n const shouldRetry = attempt < maxRetries && (isNetworkError || isRetryableStatus);\n\n if (!shouldRetry) {\n throw error;\n }\n\n let delay = baseDelay * Math.pow(2, attempt) * (0.5 + Math.random() * 0.5);\n\n // Honor Retry-After on 429 (seconds or HTTP date)\n if (status === 429 && err.response?.headers) {\n const retryAfterHeader = err.response.headers[\"retry-after\"];\n if (retryAfterHeader != null) {\n const asSeconds = parseInt(String(retryAfterHeader), 10);\n if (!Number.isNaN(asSeconds) && asSeconds > 0) {\n delay = Math.max(delay, asSeconds * 1000);\n } else {\n const asDate = new Date(String(retryAfterHeader));\n if (!Number.isNaN(asDate.getTime())) {\n const delta = asDate.getTime() - Date.now();\n if (delta > 0) delay = Math.max(delay, delta);\n }\n }\n }\n }\n\n delay = Math.min(delay, 30000);\n await new Promise((resolve) => setTimeout(resolve, Math.floor(delay)));\n }\n }\n\n throw lastError;\n }\n}\n\n// Convenience factory for the options shape used by IWooRestApiOptions\nexport function createDefaultRetryStrategy(retryConfig?: RetryConfig): RetryStrategy {\n return new ExponentialBackoffRetryStrategy(retryConfig);\n}\n", "/**\n * Throttler / Concurrency limiter.\n * Extracted from the original monolithic throttling logic inside WooCommerceRestApi.\n * Supports DI: you can pass a custom throttler (e.g. for global rate limiting across instances, or token bucket).\n * 0 or negative max = unlimited (backward compatible default).\n */\n\nexport interface Throttler {\n acquire(): Promise<void>;\n release(): void;\n}\n\nexport class ConcurrencyThrottler implements Throttler {\n private current = 0;\n private readonly queue: Array<() => void> = [];\n private readonly maxConcurrent: number;\n\n constructor(maxConcurrent: number) {\n this.maxConcurrent = maxConcurrent;\n }\n\n async acquire(): Promise<void> {\n if (this.maxConcurrent <= 0) {\n return;\n }\n if (this.current < this.maxConcurrent) {\n this.current++;\n return;\n }\n return new Promise<void>((resolve) => {\n this.queue.push(() => {\n this.current++;\n resolve();\n });\n });\n }\n\n release(): void {\n if (this.maxConcurrent <= 0) {\n return;\n }\n this.current = Math.max(0, this.current - 1);\n const next = this.queue.shift();\n if (next) {\n next();\n }\n }\n}\n\nexport function createThrottler(maxConcurrentRequests?: number): Throttler {\n return new ConcurrencyThrottler(maxConcurrentRequests ?? 0);\n}\n", "/**\n * ErrorNormalizer.\n * Central place to convert Axios errors (and other) into our public WooCommerceApiError.\n * Enables consistent error shape, future mapping of more error kinds, and testing.\n */\n\nimport type { AxiosError } from \"axios\";\nimport { WooCommerceApiError } from \"../types/index.js\";\n\nexport interface NormalizedRequestContext {\n endpoint: string;\n}\n\nexport function normalizeAxiosError(error: unknown, context: NormalizedRequestContext): WooCommerceApiError {\n const err = error as AxiosError & { request?: unknown; message?: string };\n\n if (err.response) {\n return new WooCommerceApiError(\n (err.response.data as { message?: string })?.message || err.message || \"API request failed\",\n err.response.status,\n err.response.data,\n context.endpoint,\n );\n } else if (err.request) {\n return new WooCommerceApiError(\n \"Network error: No response received from server\",\n 0,\n null,\n context.endpoint,\n );\n } else {\n return new WooCommerceApiError(\n `Request setup error: ${err.message || \"unknown\"}`,\n 0,\n null,\n context.endpoint,\n );\n }\n}\n", "/**\n * PaginationHelper.\n * Small reusable utility for the common WooCommerce WP REST pagination pattern\n * (x-wp-total, x-wp-totalpages headers + manual page/per_page loops).\n * The library itself stays \"thin client\" (no auto-paging magic that hides rate limits),\n * but this helper makes correct pagination easy and type-safe for callers.\n */\n\nimport type { WooCommerceApiResponse } from \"../types/index.js\";\n\nexport interface PaginationInfo {\n total: number;\n totalPages: number;\n currentPage?: number;\n perPage?: number;\n}\n\nexport function parsePaginationHeaders<T>(response: WooCommerceApiResponse<T>): PaginationInfo {\n const h = response.headers || {};\n const total = Number(h[\"x-wp-total\"] ?? h[\"X-WP-Total\"] ?? 0) || 0;\n const totalPages = Number(h[\"x-wp-totalpages\"] ?? h[\"X-WP-TotalPages\"] ?? 1) || 1;\n return { total, totalPages };\n}\n\n/**\n * Example helper to collect all pages for a list endpoint using the provided fetcher.\n * Stops early if a page returns fewer items than perPage (or on empty).\n * Respects caller-provided per_page (default 10).\n *\n * Usage:\n * const all = await collectAllPages((p) => api.get<Products[]>(\"products\", { per_page: 50, page: p }));\n */\nexport async function collectAllPages<T>(\n fetchPage: (page: number, perPage: number) => Promise<WooCommerceApiResponse<T[]>>,\n options?: { perPage?: number; maxPages?: number },\n): Promise<T[]> {\n const perPage = options?.perPage ?? 10;\n const maxPages = options?.maxPages ?? Infinity;\n const results: T[] = [];\n let page = 1;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n if (page > maxPages) break;\n const res = await fetchPage(page, perPage);\n const items = Array.isArray(res.data) ? res.data : [];\n results.push(...items);\n const info = parsePaginationHeaders(res);\n if (items.length < perPage || page >= info.totalPages) {\n break;\n }\n page += 1;\n }\n return results;\n}\n"],
"mappings": "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",
"names": []
}