@atomic-solutions/woocommerce-react 0.1.0 → 0.1.1

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.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var react = require('react');
4
- var woocommerceUtils = require('@atomic-solutions/woocommerce-utils');
4
+ var woocommerceApiClient = require('@atomic-solutions/woocommerce-api-client');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
7
  // src/provider/WooCommerceStoreProvider.tsx
@@ -338,7 +338,7 @@ function WooCommerceStoreProvider({
338
338
  const cartHeadersAdapter = react.useRef(createCartHeadersAdapter());
339
339
  const client = react.useMemo(() => {
340
340
  const normalizedUrl = normalizeStoreUrl(config.storeUrl);
341
- return woocommerceUtils.createClient({
341
+ return woocommerceApiClient.createClient({
342
342
  baseURL: normalizedUrl,
343
343
  storeApiVersion: "v1",
344
344
  cartHeaders: cartHeadersAdapter.current,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/events/EventContext.ts","../../src/provider/WooCommerceContext.ts","../../src/provider/WooCommerceProvider.tsx","../../src/provider/WooCommerceStoreContext.ts","../../src/provider/types.ts","../../src/guardrails/storeValidator.ts","../../src/guardrails/rateLimiter.ts","../../src/provider/WooCommerceStoreProvider.tsx"],"names":["createContext","useMemo","jsx","useState","useEffect","useRef","createClient","useCallback","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Event context for emitting WooCommerce events\n */\n\nimport { createContext, useContext } from 'react';\n\nimport type { WooCommerceEventHandler } from './types';\n\n/**\n * Context for the event emitter function\n */\nexport const EventContext = createContext<WooCommerceEventHandler | null>(null);\n\n/**\n * Hook to get the event emitter from context\n *\n * Returns null if no onEvent handler is configured (which is valid)\n */\nexport const useEventEmitter = (): WooCommerceEventHandler | null => {\n return useContext(EventContext);\n};\n","/**\n * WooCommerce context\n */\n\nimport { createContext } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-utils';\n\nimport type { QueryKeys } from '../hooks/queryKeys';\n\n/**\n * WooCommerce context value\n */\nexport interface WooCommerceContextValue {\n client: WooCommerceClient;\n queryKeys: QueryKeys;\n}\n\n/**\n * WooCommerce context for accessing client and query keys from hooks\n */\nexport const WooCommerceContext = createContext<WooCommerceContextValue | null>(null);\n","/**\n * WooCommerce provider component\n *\n * Provides WooCommerce client to child components via React Context.\n * Does NOT provide QueryClientProvider - consumers must wrap this with their own.\n */\n\nimport React, { useMemo } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-utils';\n\nimport { EventContext } from '../events/EventContext';\nimport type { WooCommerceEventHandler } from '../events/types';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport { WooCommerceContext } from './WooCommerceContext';\n\n/**\n * WooCommerce provider props\n */\nexport interface WooCommerceProviderProps {\n /** WooCommerce client instance */\n client: WooCommerceClient;\n\n /** Query keys instance created with createQueryKeys() */\n queryKeys: QueryKeys;\n\n /**\n * Event handler for all store events\n *\n * Centralize notifications, analytics, and side effects in one place.\n *\n * @example\n * ```tsx\n * <WooCommerceProvider\n * client={client}\n * queryKeys={queryKeys}\n * onEvent={(event) => {\n * if (event.status === 'error') {\n * showErrorToast(event.error.message);\n * return;\n * }\n *\n * switch (event.type) {\n * case 'cart:item_added':\n * showSuccessToast(`Added ${event.data.item.name}`);\n * break;\n * case 'cart:item_removed':\n * showSuccessToast('Item removed');\n * break;\n * case 'checkout:processed':\n * showSuccessToast('Order placed!');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onEvent?: WooCommerceEventHandler;\n\n /** Child components */\n children: React.ReactNode;\n}\n\n/**\n * WooCommerce provider\n *\n * Provides WooCommerce client and query keys to child components via context.\n *\n * **Important:** This provider does NOT wrap QueryClientProvider.\n * You must provide your own QueryClientProvider higher in the tree.\n *\n * @example\n * ```tsx\n * import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n * import { WooCommerceProvider, createClient, createQueryKeys } from '@atomic-solutions/react-woocommerce';\n *\n * const queryClient = new QueryClient();\n * const wooClient = createClient({ ... });\n * const queryKeys = createQueryKeys(['my-app']); // Custom prefix\n *\n * function App() {\n * return (\n * <QueryClientProvider client={queryClient}>\n * <WooCommerceProvider client={wooClient} queryKeys={queryKeys}>\n * <YourApp />\n * </WooCommerceProvider>\n * </QueryClientProvider>\n * );\n * }\n * ```\n */\nexport const WooCommerceProvider: React.FC<WooCommerceProviderProps> = ({\n client,\n queryKeys,\n onEvent,\n children,\n}) => {\n const contextValue = useMemo(() => ({ client, queryKeys }), [client, queryKeys]);\n\n return (\n <WooCommerceContext.Provider value={contextValue}>\n <EventContext.Provider value={onEvent ?? null}>{children}</EventContext.Provider>\n </WooCommerceContext.Provider>\n );\n};\n","import { createContext } from 'react';\n\nimport type { StoreContextValue } from './types';\n\n/**\n * Context for accessing store configuration and state\n *\n * @internal Use the useStore hook instead of accessing this directly\n */\nexport const WooCommerceStoreContext = createContext<StoreContextValue | null>(null);\n\nWooCommerceStoreContext.displayName = 'WooCommerceStoreContext';\n","import type { WooCommerceEventHandler } from '../events/types';\n\n/**\n * Store feature configuration\n */\nexport interface StoreFeatures {\n /** Enable authentication screens (default: false) */\n auth?: boolean;\n /** Enable wishlist functionality (default: false) */\n wishlist?: boolean;\n /** Show product reviews (default: true) */\n reviews?: boolean;\n /** Enable search functionality (default: true) */\n search?: boolean;\n /** Show category navigation (default: true) */\n categories?: boolean;\n}\n\n/**\n * Theme configuration for the store\n */\nexport interface StoreTheme {\n /** Primary brand color (e.g., \"#007AFF\") */\n primary?: string;\n /** Secondary brand color */\n secondary?: string;\n /** Color mode */\n mode?: 'light' | 'dark' | 'auto';\n /** Custom fonts */\n fonts?: {\n heading?: string;\n body?: string;\n };\n}\n\n/**\n * Localization and currency configuration\n */\nexport interface StoreLocale {\n /** BCP 47 locale tag for Intl formatting (e.g., \"en-US\", \"bs-BA\") */\n localeTag?: string;\n /** Currency code (e.g., \"USD\", \"EUR\", \"BAM\") */\n currency?: string;\n /** Currency symbol position */\n currencyPosition?: 'before' | 'after';\n /** Thousands separator (e.g., \",\") */\n thousandsSeparator?: string;\n /** Decimal separator (e.g., \".\") */\n decimalSeparator?: string;\n /** Number of decimal places */\n decimals?: number;\n}\n\n/**\n * Function to transform image URLs (e.g., for custom sizing, CDN, optimization)\n */\nexport type ImageUrlTransformer = (\n url: string,\n size: 'thumbnail' | 'medium' | 'large' | 'full'\n) => string;\n\n/**\n * Rate limiting configuration\n */\nexport interface RateLimitConfig {\n /** Maximum requests per minute (default: 60) */\n requestsPerMinute?: number;\n /** Maximum requests per second (default: 10) */\n requestsPerSecond?: number;\n /** Burst limit for temporary spikes (default: 20) */\n burstLimit?: number;\n}\n\n/**\n * Guardrails configuration to prevent abuse\n */\nexport interface StoreGuardrails {\n /** Validate that the URL is a valid WooCommerce store (default: true) */\n validateStore?: boolean;\n /** Rate limiting configuration */\n rateLimit?: RateLimitConfig;\n /** Optional license key for production usage tracking */\n licenseKey?: string;\n}\n\n/**\n * Store validation result\n */\nexport interface StoreValidationResult {\n /** Whether the store is valid */\n valid: boolean;\n /** Store name (if available) */\n storeName?: string;\n /** Normalized store URL */\n storeUrl?: string;\n /** WooCommerce version (if detectable) */\n wcVersion?: string;\n /** Error message if validation failed */\n error?: string;\n}\n\n/**\n * Main store configuration\n */\nexport interface StoreConfig {\n /**\n * WooCommerce store URL\n * @example \"https://mystore.com\" or \"https://mystore.com/wp-json\"\n */\n storeUrl: string;\n\n /** Feature toggles */\n features?: StoreFeatures;\n\n /** Theme customization */\n theme?: StoreTheme;\n\n /** Localization settings */\n locale?: StoreLocale;\n\n /** Guardrails configuration */\n guardrails?: StoreGuardrails;\n\n /** Event handler for WooCommerce events */\n onEvent?: WooCommerceEventHandler;\n\n /** Enable debug logging (default: false in production) */\n debug?: boolean;\n\n /**\n * Custom image URL transformer for optimization\n * Use this to add CDN prefixes, size suffixes, or custom transformations\n *\n * @example\n * ```ts\n * imageUrlTransformer: (url, size) => {\n * // Add PNG optimization for ma-native\n * if (url.endsWith('.png') && !url.includes('unnamed.png')) {\n * return url.replace('.png', '-300x300.png');\n * }\n * return url;\n * }\n * ```\n */\n imageUrlTransformer?: ImageUrlTransformer;\n\n /** Fallback image URL when products have no images */\n fallbackImageUrl?: string;\n}\n\n/**\n * Store context value available via useStore hook\n */\nexport interface StoreContextValue {\n /** Current store configuration */\n config: StoreConfig;\n /** Whether the store has been validated */\n isValidated: boolean;\n /** Whether validation is in progress */\n isValidating: boolean;\n /** Validation error (if any) */\n validationError?: string;\n /** Store validation result */\n validationResult?: StoreValidationResult;\n /** Re-validate the store connection */\n revalidate: () => Promise<void>;\n}\n\n/**\n * Default store configuration values\n */\nexport const DEFAULT_STORE_CONFIG: Required<\n Pick<StoreConfig, 'features' | 'locale' | 'guardrails' | 'debug'>\n> = {\n features: {\n auth: false,\n wishlist: false,\n reviews: true,\n search: true,\n categories: true,\n },\n locale: {\n localeTag: 'en-US',\n currency: 'USD',\n currencyPosition: 'before',\n thousandsSeparator: ',',\n decimalSeparator: '.',\n decimals: 2,\n },\n guardrails: {\n validateStore: true,\n rateLimit: {\n requestsPerMinute: 60,\n requestsPerSecond: 10,\n burstLimit: 20,\n },\n },\n debug: process.env.NODE_ENV !== 'production',\n};\n","import type { StoreValidationResult } from '../provider/types';\n\n/**\n * Normalizes a store URL to ensure consistent format\n *\n * @param url - Raw URL input from user\n * @returns Normalized URL with /wp-json suffix\n *\n * @example\n * normalizeStoreUrl(\"https://mystore.com\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/wp-json\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"mystore.com\") // \"https://mystore.com/wp-json\"\n */\nexport function normalizeStoreUrl(url: string): string {\n let normalized = url.trim();\n\n // Add https:// if no protocol\n if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {\n normalized = `https://${normalized}`;\n }\n\n // Remove trailing slash\n normalized = normalized.replace(/\\/+$/, '');\n\n // Remove /wp-json if present (we'll add it consistently)\n normalized = normalized.replace(/\\/wp-json\\/?$/, '');\n\n return `${normalized}/wp-json`;\n}\n\n/**\n * Extracts the base URL from a normalized store URL\n *\n * @param normalizedUrl - URL that ends with /wp-json\n * @returns Base URL without /wp-json suffix\n */\nexport function getBaseUrl(normalizedUrl: string): string {\n return normalizedUrl.replace(/\\/wp-json\\/?$/, '');\n}\n\n/**\n * Validates that a URL points to a valid WooCommerce store\n *\n * This function performs the following checks:\n * 1. Normalizes the URL format\n * 2. Checks if the WooCommerce Store API is accessible\n * 3. Verifies the response structure\n *\n * @param url - Store URL to validate\n * @param options - Validation options\n * @returns Validation result with store details or error\n *\n * @example\n * const result = await validateWooCommerceStore(\"https://mystore.com\");\n * if (result.valid) {\n * console.log(`Connected to ${result.storeName}`);\n * } else {\n * console.error(`Failed: ${result.error}`);\n * }\n */\nexport async function validateWooCommerceStore(\n url: string,\n options: {\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Allow localhost URLs (default: true in development) */\n allowLocalhost?: boolean;\n } = {}\n): Promise<StoreValidationResult> {\n const { timeout = 10000, allowLocalhost = process.env.NODE_ENV !== 'production' } = options;\n\n try {\n // 1. Basic URL validation\n const normalizedUrl = normalizeStoreUrl(url);\n const baseUrl = getBaseUrl(normalizedUrl);\n\n // Check for localhost in production\n const isLocalhost = baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1');\n if (isLocalhost && !allowLocalhost) {\n return {\n valid: false,\n error: 'Localhost URLs are not allowed in production',\n };\n }\n\n // 2. Check WooCommerce Store API v1\n const storeApiUrl = `${normalizedUrl}/wc/store/v1`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n let response: Response;\n try {\n response = await fetch(storeApiUrl, {\n method: 'GET',\n headers: {\n 'User-Agent': '@atomic-solutions/react-native-woocommerce',\n Accept: 'application/json',\n },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Handle various response codes\n if (response.status === 404) {\n return {\n valid: false,\n error:\n 'WooCommerce Store API not found. Ensure WooCommerce is installed and REST API is enabled.',\n };\n }\n\n if (response.status === 401 || response.status === 403) {\n return {\n valid: false,\n error: 'Access denied. Check that the REST API is publicly accessible for the Store API.',\n };\n }\n\n if (!response.ok) {\n return {\n valid: false,\n error: `Unexpected response: ${response.status} ${response.statusText}`,\n };\n }\n\n // 3. Try to get store info from the root endpoint\n let storeName: string | undefined;\n let wcVersion: string | undefined;\n\n try {\n const rootResponse = await fetch(normalizedUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (rootResponse.ok) {\n const rootData = (await rootResponse.json()) as {\n name?: string;\n namespaces?: string[];\n };\n storeName = rootData.name;\n\n // Check for WooCommerce namespaces\n if (rootData.namespaces) {\n const hasWcNamespace = rootData.namespaces.some(\n (ns) => ns.startsWith('wc/') || ns === 'wc'\n );\n if (!hasWcNamespace) {\n return {\n valid: false,\n error: 'WooCommerce REST API namespace not found. Is WooCommerce installed?',\n };\n }\n }\n }\n } catch {\n // Root endpoint info is optional, continue without it\n }\n\n return {\n valid: true,\n storeName: storeName || 'WooCommerce Store',\n storeUrl: normalizedUrl,\n wcVersion,\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n return {\n valid: false,\n error: `Connection timed out after ${timeout}ms`,\n };\n }\n\n // Network errors\n if (error.message.includes('Network request failed')) {\n return {\n valid: false,\n error: 'Unable to connect to the store. Check the URL and your internet connection.',\n };\n }\n\n return {\n valid: false,\n error: error.message,\n };\n }\n\n return {\n valid: false,\n error: 'An unexpected error occurred while validating the store',\n };\n }\n}\n\n/**\n * Quick check if a URL looks like a valid WooCommerce store URL\n * Does NOT make network requests - just validates format\n *\n * @param url - URL to check\n * @returns Whether the URL format is valid\n */\nexport function isValidStoreUrlFormat(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n return false;\n }\n\n try {\n const normalized = normalizeStoreUrl(trimmed);\n new URL(normalized); // Will throw if invalid\n return true;\n } catch {\n return false;\n }\n}\n","import type { RateLimitConfig } from '../provider/types';\n\n/**\n * Default rate limit configuration\n */\nconst DEFAULT_CONFIG: Required<RateLimitConfig> = {\n requestsPerSecond: 10,\n requestsPerMinute: 60,\n burstLimit: 20,\n};\n\n/**\n * Token bucket rate limiter for client-side request throttling\n *\n * Uses a token bucket algorithm that allows burst traffic while\n * enforcing an average rate limit over time.\n *\n * @example\n * const limiter = new RateLimiter({ requestsPerSecond: 10 });\n *\n * // In axios interceptor\n * axios.interceptors.request.use(async (config) => {\n * await limiter.acquire();\n * return config;\n * });\n */\nexport class RateLimiter {\n private tokens: number;\n private lastRefill: number;\n private readonly maxTokens: number;\n private readonly refillRate: number; // tokens per millisecond\n private readonly queue: Array<{\n resolve: () => void;\n reject: (error: Error) => void;\n }> = [];\n private isProcessing = false;\n\n constructor(config: RateLimitConfig = {}) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n this.maxTokens = mergedConfig.burstLimit;\n this.tokens = this.maxTokens;\n this.refillRate = mergedConfig.requestsPerSecond / 1000;\n this.lastRefill = Date.now();\n }\n\n /**\n * Refills tokens based on elapsed time\n */\n private refill(): void {\n const now = Date.now();\n const elapsed = now - this.lastRefill;\n const tokensToAdd = elapsed * this.refillRate;\n\n this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);\n this.lastRefill = now;\n }\n\n /**\n * Process queued requests\n */\n private async processQueue(): Promise<void> {\n if (this.isProcessing) {\n return;\n }\n\n this.isProcessing = true;\n\n while (this.queue.length > 0) {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n const request = this.queue.shift();\n request?.resolve();\n } else {\n // Calculate wait time until we have a token\n const waitTime = Math.ceil((1 - this.tokens) / this.refillRate);\n await this.sleep(waitTime);\n }\n }\n\n this.isProcessing = false;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Acquire a token before making a request\n * Returns immediately if tokens available, otherwise queues the request\n *\n * @returns Promise that resolves when request can proceed\n */\n acquire(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n resolve();\n } else {\n this.queue.push({ resolve, reject });\n this.processQueue();\n }\n });\n }\n\n /**\n * Try to acquire a token without waiting\n *\n * @returns true if token was acquired, false if rate limited\n */\n tryAcquire(): boolean {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n\n return false;\n }\n\n /**\n * Get current number of available tokens\n */\n getAvailableTokens(): number {\n this.refill();\n return Math.floor(this.tokens);\n }\n\n /**\n * Get number of queued requests\n */\n getQueueLength(): number {\n return this.queue.length;\n }\n\n /**\n * Clear all queued requests (rejects them)\n */\n clearQueue(): void {\n while (this.queue.length > 0) {\n const request = this.queue.shift();\n request?.reject(new Error('Rate limiter queue cleared'));\n }\n }\n\n /**\n * Reset the rate limiter to initial state\n */\n reset(): void {\n this.clearQueue();\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n }\n}\n\n/**\n * Singleton rate limiter instance\n * Can be configured once at app startup\n */\nlet globalRateLimiter: RateLimiter | null = null;\n\n/**\n * Get or create the global rate limiter instance\n *\n * @param config - Optional config (only used on first call)\n */\nexport function getGlobalRateLimiter(config?: RateLimitConfig): RateLimiter {\n if (!globalRateLimiter) {\n globalRateLimiter = new RateLimiter(config);\n }\n return globalRateLimiter;\n}\n\n/**\n * Configure the global rate limiter\n * Creates a new instance with the provided config\n *\n * @param config - Rate limit configuration\n */\nexport function configureGlobalRateLimiter(config: RateLimitConfig): void {\n if (globalRateLimiter) {\n globalRateLimiter.clearQueue();\n }\n globalRateLimiter = new RateLimiter(config);\n}\n\n/**\n * Reset the global rate limiter to defaults\n */\nexport function resetGlobalRateLimiter(): void {\n globalRateLimiter?.clearQueue();\n globalRateLimiter = null;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { createClient, type WooCommerceClient } from '@atomic-solutions/woocommerce-utils';\n\nimport { WooCommerceProvider } from '..';\nimport {\n configureGlobalRateLimiter,\n getGlobalRateLimiter,\n normalizeStoreUrl,\n validateWooCommerceStore,\n} from '../guardrails';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport {\n DEFAULT_STORE_CONFIG,\n type StoreConfig,\n type StoreContextValue,\n type StoreValidationResult,\n} from './types';\nimport { WooCommerceStoreContext } from './WooCommerceStoreContext';\n\n// Package version for User-Agent header\nconst PACKAGE_VERSION = '0.1.0';\n\n/**\n * Cart headers adapter for storing nonce and cart token\n * Uses a simple in-memory store for now\n */\nfunction createCartHeadersAdapter() {\n let headers: { nonce?: string; cartToken?: string } = {};\n\n return {\n get: async () => headers,\n save: async (newHeaders: { nonce?: string; cartToken?: string }) => {\n headers = { ...headers, ...newHeaders };\n },\n clear: async () => {\n headers = {};\n },\n };\n}\n\nexport interface WooCommerceStoreProviderProps {\n /**\n * Store configuration\n */\n config: StoreConfig;\n\n /**\n * Query keys instance created with createQueryKeys()\n */\n queryKeys: QueryKeys;\n\n /**\n * Children components\n */\n children: ReactNode;\n\n /**\n * Skip store validation (useful for testing)\n * @default false\n */\n skipValidation?: boolean;\n\n /**\n * Fallback UI to show while validating store\n * @default null\n */\n loadingFallback?: ReactNode;\n\n /**\n * Error UI to show when validation fails\n * If not provided, children will still render with validation error in context\n */\n errorFallback?: (error: string, retry: () => void) => ReactNode;\n}\n\n/**\n * WooCommerce Store Provider\n *\n * Main provider component that wraps your app and provides:\n * - Store configuration context\n * - WooCommerce client via woocommerce-utils\n * - Store validation\n * - Rate limiting\n *\n * @example\n * ```tsx\n * <WooCommerceStoreProvider\n * config={{\n * storeUrl: \"https://mystore.com\",\n * theme: { primary: \"#007AFF\" },\n * }}\n * >\n * <App />\n * </WooCommerceStoreProvider>\n * ```\n */\nexport function WooCommerceStoreProvider({\n config,\n queryKeys,\n children,\n skipValidation = false,\n loadingFallback = null,\n errorFallback,\n}: WooCommerceStoreProviderProps) {\n const [isValidating, setIsValidating] = useState(!skipValidation);\n const [isValidated, setIsValidated] = useState(skipValidation);\n const [validationResult, setValidationResult] = useState<StoreValidationResult | undefined>(\n skipValidation ? { valid: true, storeUrl: normalizeStoreUrl(config.storeUrl) } : undefined\n );\n const [validationError, setValidationError] = useState<string | undefined>();\n\n // Merge config with defaults\n const mergedConfig = useMemo(\n () => ({\n ...config,\n features: { ...DEFAULT_STORE_CONFIG.features, ...config.features },\n locale: { ...DEFAULT_STORE_CONFIG.locale, ...config.locale },\n guardrails: { ...DEFAULT_STORE_CONFIG.guardrails, ...config.guardrails },\n debug: config.debug ?? DEFAULT_STORE_CONFIG.debug,\n }),\n [config]\n );\n\n // Configure rate limiter\n useEffect(() => {\n if (mergedConfig.guardrails.rateLimit) {\n configureGlobalRateLimiter(mergedConfig.guardrails.rateLimit);\n }\n }, [mergedConfig.guardrails.rateLimit]);\n\n // Create cart headers adapter\n const cartHeadersAdapter = useRef(createCartHeadersAdapter());\n\n // Create WooCommerce client\n const client = useMemo<WooCommerceClient>(() => {\n const normalizedUrl = normalizeStoreUrl(config.storeUrl);\n\n return createClient({\n baseURL: normalizedUrl,\n storeApiVersion: 'v1',\n cartHeaders: cartHeadersAdapter.current,\n validationMode: 'warn',\n debug: mergedConfig.debug,\n headers: {\n 'User-Agent': `@atomic-solutions/react-native-woocommerce/${PACKAGE_VERSION}`,\n 'X-WC-Client': 'atomic-woocommerce',\n 'X-WC-Client-Version': PACKAGE_VERSION,\n },\n onRequest: async (requestConfig) => {\n // Apply rate limiting\n const rateLimiter = getGlobalRateLimiter();\n await rateLimiter.acquire();\n return requestConfig;\n },\n onError: (error) => {\n if (mergedConfig.debug) {\n console.error('[WooCommerceStore] API Error:', error);\n }\n },\n });\n }, [config.storeUrl, mergedConfig.debug]);\n\n // Validation function\n const validateStore = useCallback(async () => {\n if (skipValidation) {\n return;\n }\n\n setIsValidating(true);\n setValidationError(undefined);\n\n try {\n const result = await validateWooCommerceStore(config.storeUrl, {\n allowLocalhost: process.env.NODE_ENV !== 'production',\n });\n\n setValidationResult(result);\n\n if (result.valid) {\n setIsValidated(true);\n setValidationError(undefined);\n\n if (mergedConfig.debug) {\n console.log('[WooCommerceStore] Connected to:', result.storeName);\n }\n } else {\n setIsValidated(false);\n setValidationError(result.error);\n\n if (mergedConfig.debug) {\n console.warn('[WooCommerceStore] Validation failed:', result.error);\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n setValidationError(errorMessage);\n setIsValidated(false);\n } finally {\n setIsValidating(false);\n }\n }, [config.storeUrl, skipValidation, mergedConfig.debug]);\n\n // Run validation on mount and when storeUrl changes\n useEffect(() => {\n if (mergedConfig.guardrails.validateStore) {\n validateStore();\n } else {\n setIsValidated(true);\n setIsValidating(false);\n }\n }, [validateStore, mergedConfig.guardrails.validateStore]);\n\n // Context value\n const contextValue = useMemo<StoreContextValue>(\n () => ({\n config: mergedConfig,\n isValidated,\n isValidating,\n validationError,\n validationResult,\n revalidate: validateStore,\n }),\n [mergedConfig, isValidated, isValidating, validationError, validationResult, validateStore]\n );\n\n // Show loading fallback while validating\n if (isValidating && loadingFallback) {\n return <>{loadingFallback}</>;\n }\n\n // Show error fallback if validation failed and fallback is provided\n if (validationError && errorFallback) {\n return <>{errorFallback(validationError, validateStore)}</>;\n }\n\n return (\n <WooCommerceStoreContext.Provider value={contextValue}>\n <WooCommerceProvider client={client} queryKeys={queryKeys} onEvent={config.onEvent}>\n {children}\n </WooCommerceProvider>\n </WooCommerceStoreContext.Provider>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/events/EventContext.ts","../../src/provider/WooCommerceContext.ts","../../src/provider/WooCommerceProvider.tsx","../../src/provider/WooCommerceStoreContext.ts","../../src/provider/types.ts","../../src/guardrails/storeValidator.ts","../../src/guardrails/rateLimiter.ts","../../src/provider/WooCommerceStoreProvider.tsx"],"names":["createContext","useMemo","jsx","useState","useEffect","useRef","createClient","useCallback","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Event context for emitting WooCommerce events\n */\n\nimport { createContext, useContext } from 'react';\n\nimport type { WooCommerceEventHandler } from './types';\n\n/**\n * Context for the event emitter function\n */\nexport const EventContext = createContext<WooCommerceEventHandler | null>(null);\n\n/**\n * Hook to get the event emitter from context\n *\n * Returns null if no onEvent handler is configured (which is valid)\n */\nexport const useEventEmitter = (): WooCommerceEventHandler | null => {\n return useContext(EventContext);\n};\n","/**\n * WooCommerce context\n */\n\nimport { createContext } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-api-client';\n\nimport type { QueryKeys } from '../hooks/queryKeys';\n\n/**\n * WooCommerce context value\n */\nexport interface WooCommerceContextValue {\n client: WooCommerceClient;\n queryKeys: QueryKeys;\n}\n\n/**\n * WooCommerce context for accessing client and query keys from hooks\n */\nexport const WooCommerceContext = createContext<WooCommerceContextValue | null>(null);\n","/**\n * WooCommerce provider component\n *\n * Provides WooCommerce client to child components via React Context.\n * Does NOT provide QueryClientProvider - consumers must wrap this with their own.\n */\n\nimport React, { useMemo } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-api-client';\n\nimport { EventContext } from '../events/EventContext';\nimport type { WooCommerceEventHandler } from '../events/types';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport { WooCommerceContext } from './WooCommerceContext';\n\n/**\n * WooCommerce provider props\n */\nexport interface WooCommerceProviderProps {\n /** WooCommerce client instance */\n client: WooCommerceClient;\n\n /** Query keys instance created with createQueryKeys() */\n queryKeys: QueryKeys;\n\n /**\n * Event handler for all store events\n *\n * Centralize notifications, analytics, and side effects in one place.\n *\n * @example\n * ```tsx\n * <WooCommerceProvider\n * client={client}\n * queryKeys={queryKeys}\n * onEvent={(event) => {\n * if (event.status === 'error') {\n * showErrorToast(event.error.message);\n * return;\n * }\n *\n * switch (event.type) {\n * case 'cart:item_added':\n * showSuccessToast(`Added ${event.data.item.name}`);\n * break;\n * case 'cart:item_removed':\n * showSuccessToast('Item removed');\n * break;\n * case 'checkout:processed':\n * showSuccessToast('Order placed!');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onEvent?: WooCommerceEventHandler;\n\n /** Child components */\n children: React.ReactNode;\n}\n\n/**\n * WooCommerce provider\n *\n * Provides WooCommerce client and query keys to child components via context.\n *\n * **Important:** This provider does NOT wrap QueryClientProvider.\n * You must provide your own QueryClientProvider higher in the tree.\n *\n * @example\n * ```tsx\n * import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n * import { WooCommerceProvider, createClient, createQueryKeys } from '@atomic-solutions/react-woocommerce';\n *\n * const queryClient = new QueryClient();\n * const wooClient = createClient({ ... });\n * const queryKeys = createQueryKeys(['my-app']); // Custom prefix\n *\n * function App() {\n * return (\n * <QueryClientProvider client={queryClient}>\n * <WooCommerceProvider client={wooClient} queryKeys={queryKeys}>\n * <YourApp />\n * </WooCommerceProvider>\n * </QueryClientProvider>\n * );\n * }\n * ```\n */\nexport const WooCommerceProvider: React.FC<WooCommerceProviderProps> = ({\n client,\n queryKeys,\n onEvent,\n children,\n}) => {\n const contextValue = useMemo(() => ({ client, queryKeys }), [client, queryKeys]);\n\n return (\n <WooCommerceContext.Provider value={contextValue}>\n <EventContext.Provider value={onEvent ?? null}>{children}</EventContext.Provider>\n </WooCommerceContext.Provider>\n );\n};\n","import { createContext } from 'react';\n\nimport type { StoreContextValue } from './types';\n\n/**\n * Context for accessing store configuration and state\n *\n * @internal Use the useStore hook instead of accessing this directly\n */\nexport const WooCommerceStoreContext = createContext<StoreContextValue | null>(null);\n\nWooCommerceStoreContext.displayName = 'WooCommerceStoreContext';\n","import type { WooCommerceEventHandler } from '../events/types';\n\n/**\n * Store feature configuration\n */\nexport interface StoreFeatures {\n /** Enable authentication screens (default: false) */\n auth?: boolean;\n /** Enable wishlist functionality (default: false) */\n wishlist?: boolean;\n /** Show product reviews (default: true) */\n reviews?: boolean;\n /** Enable search functionality (default: true) */\n search?: boolean;\n /** Show category navigation (default: true) */\n categories?: boolean;\n}\n\n/**\n * Theme configuration for the store\n */\nexport interface StoreTheme {\n /** Primary brand color (e.g., \"#007AFF\") */\n primary?: string;\n /** Secondary brand color */\n secondary?: string;\n /** Color mode */\n mode?: 'light' | 'dark' | 'auto';\n /** Custom fonts */\n fonts?: {\n heading?: string;\n body?: string;\n };\n}\n\n/**\n * Localization and currency configuration\n */\nexport interface StoreLocale {\n /** BCP 47 locale tag for Intl formatting (e.g., \"en-US\", \"bs-BA\") */\n localeTag?: string;\n /** Currency code (e.g., \"USD\", \"EUR\", \"BAM\") */\n currency?: string;\n /** Currency symbol position */\n currencyPosition?: 'before' | 'after';\n /** Thousands separator (e.g., \",\") */\n thousandsSeparator?: string;\n /** Decimal separator (e.g., \".\") */\n decimalSeparator?: string;\n /** Number of decimal places */\n decimals?: number;\n}\n\n/**\n * Function to transform image URLs (e.g., for custom sizing, CDN, optimization)\n */\nexport type ImageUrlTransformer = (\n url: string,\n size: 'thumbnail' | 'medium' | 'large' | 'full'\n) => string;\n\n/**\n * Rate limiting configuration\n */\nexport interface RateLimitConfig {\n /** Maximum requests per minute (default: 60) */\n requestsPerMinute?: number;\n /** Maximum requests per second (default: 10) */\n requestsPerSecond?: number;\n /** Burst limit for temporary spikes (default: 20) */\n burstLimit?: number;\n}\n\n/**\n * Guardrails configuration to prevent abuse\n */\nexport interface StoreGuardrails {\n /** Validate that the URL is a valid WooCommerce store (default: true) */\n validateStore?: boolean;\n /** Rate limiting configuration */\n rateLimit?: RateLimitConfig;\n /** Optional license key for production usage tracking */\n licenseKey?: string;\n}\n\n/**\n * Store validation result\n */\nexport interface StoreValidationResult {\n /** Whether the store is valid */\n valid: boolean;\n /** Store name (if available) */\n storeName?: string;\n /** Normalized store URL */\n storeUrl?: string;\n /** WooCommerce version (if detectable) */\n wcVersion?: string;\n /** Error message if validation failed */\n error?: string;\n}\n\n/**\n * Main store configuration\n */\nexport interface StoreConfig {\n /**\n * WooCommerce store URL\n * @example \"https://mystore.com\" or \"https://mystore.com/wp-json\"\n */\n storeUrl: string;\n\n /** Feature toggles */\n features?: StoreFeatures;\n\n /** Theme customization */\n theme?: StoreTheme;\n\n /** Localization settings */\n locale?: StoreLocale;\n\n /** Guardrails configuration */\n guardrails?: StoreGuardrails;\n\n /** Event handler for WooCommerce events */\n onEvent?: WooCommerceEventHandler;\n\n /** Enable debug logging (default: false in production) */\n debug?: boolean;\n\n /**\n * Custom image URL transformer for optimization\n * Use this to add CDN prefixes, size suffixes, or custom transformations\n *\n * @example\n * ```ts\n * imageUrlTransformer: (url, size) => {\n * // Add PNG optimization for ma-native\n * if (url.endsWith('.png') && !url.includes('unnamed.png')) {\n * return url.replace('.png', '-300x300.png');\n * }\n * return url;\n * }\n * ```\n */\n imageUrlTransformer?: ImageUrlTransformer;\n\n /** Fallback image URL when products have no images */\n fallbackImageUrl?: string;\n}\n\n/**\n * Store context value available via useStore hook\n */\nexport interface StoreContextValue {\n /** Current store configuration */\n config: StoreConfig;\n /** Whether the store has been validated */\n isValidated: boolean;\n /** Whether validation is in progress */\n isValidating: boolean;\n /** Validation error (if any) */\n validationError?: string;\n /** Store validation result */\n validationResult?: StoreValidationResult;\n /** Re-validate the store connection */\n revalidate: () => Promise<void>;\n}\n\n/**\n * Default store configuration values\n */\nexport const DEFAULT_STORE_CONFIG: Required<\n Pick<StoreConfig, 'features' | 'locale' | 'guardrails' | 'debug'>\n> = {\n features: {\n auth: false,\n wishlist: false,\n reviews: true,\n search: true,\n categories: true,\n },\n locale: {\n localeTag: 'en-US',\n currency: 'USD',\n currencyPosition: 'before',\n thousandsSeparator: ',',\n decimalSeparator: '.',\n decimals: 2,\n },\n guardrails: {\n validateStore: true,\n rateLimit: {\n requestsPerMinute: 60,\n requestsPerSecond: 10,\n burstLimit: 20,\n },\n },\n debug: process.env.NODE_ENV !== 'production',\n};\n","import type { StoreValidationResult } from '../provider/types';\n\n/**\n * Normalizes a store URL to ensure consistent format\n *\n * @param url - Raw URL input from user\n * @returns Normalized URL with /wp-json suffix\n *\n * @example\n * normalizeStoreUrl(\"https://mystore.com\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/wp-json\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"mystore.com\") // \"https://mystore.com/wp-json\"\n */\nexport function normalizeStoreUrl(url: string): string {\n let normalized = url.trim();\n\n // Add https:// if no protocol\n if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {\n normalized = `https://${normalized}`;\n }\n\n // Remove trailing slash\n normalized = normalized.replace(/\\/+$/, '');\n\n // Remove /wp-json if present (we'll add it consistently)\n normalized = normalized.replace(/\\/wp-json\\/?$/, '');\n\n return `${normalized}/wp-json`;\n}\n\n/**\n * Extracts the base URL from a normalized store URL\n *\n * @param normalizedUrl - URL that ends with /wp-json\n * @returns Base URL without /wp-json suffix\n */\nexport function getBaseUrl(normalizedUrl: string): string {\n return normalizedUrl.replace(/\\/wp-json\\/?$/, '');\n}\n\n/**\n * Validates that a URL points to a valid WooCommerce store\n *\n * This function performs the following checks:\n * 1. Normalizes the URL format\n * 2. Checks if the WooCommerce Store API is accessible\n * 3. Verifies the response structure\n *\n * @param url - Store URL to validate\n * @param options - Validation options\n * @returns Validation result with store details or error\n *\n * @example\n * const result = await validateWooCommerceStore(\"https://mystore.com\");\n * if (result.valid) {\n * console.log(`Connected to ${result.storeName}`);\n * } else {\n * console.error(`Failed: ${result.error}`);\n * }\n */\nexport async function validateWooCommerceStore(\n url: string,\n options: {\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Allow localhost URLs (default: true in development) */\n allowLocalhost?: boolean;\n } = {}\n): Promise<StoreValidationResult> {\n const { timeout = 10000, allowLocalhost = process.env.NODE_ENV !== 'production' } = options;\n\n try {\n // 1. Basic URL validation\n const normalizedUrl = normalizeStoreUrl(url);\n const baseUrl = getBaseUrl(normalizedUrl);\n\n // Check for localhost in production\n const isLocalhost = baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1');\n if (isLocalhost && !allowLocalhost) {\n return {\n valid: false,\n error: 'Localhost URLs are not allowed in production',\n };\n }\n\n // 2. Check WooCommerce Store API v1\n const storeApiUrl = `${normalizedUrl}/wc/store/v1`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n let response: Response;\n try {\n response = await fetch(storeApiUrl, {\n method: 'GET',\n headers: {\n 'User-Agent': '@atomic-solutions/react-native-woocommerce',\n Accept: 'application/json',\n },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Handle various response codes\n if (response.status === 404) {\n return {\n valid: false,\n error:\n 'WooCommerce Store API not found. Ensure WooCommerce is installed and REST API is enabled.',\n };\n }\n\n if (response.status === 401 || response.status === 403) {\n return {\n valid: false,\n error: 'Access denied. Check that the REST API is publicly accessible for the Store API.',\n };\n }\n\n if (!response.ok) {\n return {\n valid: false,\n error: `Unexpected response: ${response.status} ${response.statusText}`,\n };\n }\n\n // 3. Try to get store info from the root endpoint\n let storeName: string | undefined;\n let wcVersion: string | undefined;\n\n try {\n const rootResponse = await fetch(normalizedUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (rootResponse.ok) {\n const rootData = (await rootResponse.json()) as {\n name?: string;\n namespaces?: string[];\n };\n storeName = rootData.name;\n\n // Check for WooCommerce namespaces\n if (rootData.namespaces) {\n const hasWcNamespace = rootData.namespaces.some(\n (ns) => ns.startsWith('wc/') || ns === 'wc'\n );\n if (!hasWcNamespace) {\n return {\n valid: false,\n error: 'WooCommerce REST API namespace not found. Is WooCommerce installed?',\n };\n }\n }\n }\n } catch {\n // Root endpoint info is optional, continue without it\n }\n\n return {\n valid: true,\n storeName: storeName || 'WooCommerce Store',\n storeUrl: normalizedUrl,\n wcVersion,\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n return {\n valid: false,\n error: `Connection timed out after ${timeout}ms`,\n };\n }\n\n // Network errors\n if (error.message.includes('Network request failed')) {\n return {\n valid: false,\n error: 'Unable to connect to the store. Check the URL and your internet connection.',\n };\n }\n\n return {\n valid: false,\n error: error.message,\n };\n }\n\n return {\n valid: false,\n error: 'An unexpected error occurred while validating the store',\n };\n }\n}\n\n/**\n * Quick check if a URL looks like a valid WooCommerce store URL\n * Does NOT make network requests - just validates format\n *\n * @param url - URL to check\n * @returns Whether the URL format is valid\n */\nexport function isValidStoreUrlFormat(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n return false;\n }\n\n try {\n const normalized = normalizeStoreUrl(trimmed);\n new URL(normalized); // Will throw if invalid\n return true;\n } catch {\n return false;\n }\n}\n","import type { RateLimitConfig } from '../provider/types';\n\n/**\n * Default rate limit configuration\n */\nconst DEFAULT_CONFIG: Required<RateLimitConfig> = {\n requestsPerSecond: 10,\n requestsPerMinute: 60,\n burstLimit: 20,\n};\n\n/**\n * Token bucket rate limiter for client-side request throttling\n *\n * Uses a token bucket algorithm that allows burst traffic while\n * enforcing an average rate limit over time.\n *\n * @example\n * const limiter = new RateLimiter({ requestsPerSecond: 10 });\n *\n * // In axios interceptor\n * axios.interceptors.request.use(async (config) => {\n * await limiter.acquire();\n * return config;\n * });\n */\nexport class RateLimiter {\n private tokens: number;\n private lastRefill: number;\n private readonly maxTokens: number;\n private readonly refillRate: number; // tokens per millisecond\n private readonly queue: Array<{\n resolve: () => void;\n reject: (error: Error) => void;\n }> = [];\n private isProcessing = false;\n\n constructor(config: RateLimitConfig = {}) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n this.maxTokens = mergedConfig.burstLimit;\n this.tokens = this.maxTokens;\n this.refillRate = mergedConfig.requestsPerSecond / 1000;\n this.lastRefill = Date.now();\n }\n\n /**\n * Refills tokens based on elapsed time\n */\n private refill(): void {\n const now = Date.now();\n const elapsed = now - this.lastRefill;\n const tokensToAdd = elapsed * this.refillRate;\n\n this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);\n this.lastRefill = now;\n }\n\n /**\n * Process queued requests\n */\n private async processQueue(): Promise<void> {\n if (this.isProcessing) {\n return;\n }\n\n this.isProcessing = true;\n\n while (this.queue.length > 0) {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n const request = this.queue.shift();\n request?.resolve();\n } else {\n // Calculate wait time until we have a token\n const waitTime = Math.ceil((1 - this.tokens) / this.refillRate);\n await this.sleep(waitTime);\n }\n }\n\n this.isProcessing = false;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Acquire a token before making a request\n * Returns immediately if tokens available, otherwise queues the request\n *\n * @returns Promise that resolves when request can proceed\n */\n acquire(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n resolve();\n } else {\n this.queue.push({ resolve, reject });\n this.processQueue();\n }\n });\n }\n\n /**\n * Try to acquire a token without waiting\n *\n * @returns true if token was acquired, false if rate limited\n */\n tryAcquire(): boolean {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n\n return false;\n }\n\n /**\n * Get current number of available tokens\n */\n getAvailableTokens(): number {\n this.refill();\n return Math.floor(this.tokens);\n }\n\n /**\n * Get number of queued requests\n */\n getQueueLength(): number {\n return this.queue.length;\n }\n\n /**\n * Clear all queued requests (rejects them)\n */\n clearQueue(): void {\n while (this.queue.length > 0) {\n const request = this.queue.shift();\n request?.reject(new Error('Rate limiter queue cleared'));\n }\n }\n\n /**\n * Reset the rate limiter to initial state\n */\n reset(): void {\n this.clearQueue();\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n }\n}\n\n/**\n * Singleton rate limiter instance\n * Can be configured once at app startup\n */\nlet globalRateLimiter: RateLimiter | null = null;\n\n/**\n * Get or create the global rate limiter instance\n *\n * @param config - Optional config (only used on first call)\n */\nexport function getGlobalRateLimiter(config?: RateLimitConfig): RateLimiter {\n if (!globalRateLimiter) {\n globalRateLimiter = new RateLimiter(config);\n }\n return globalRateLimiter;\n}\n\n/**\n * Configure the global rate limiter\n * Creates a new instance with the provided config\n *\n * @param config - Rate limit configuration\n */\nexport function configureGlobalRateLimiter(config: RateLimitConfig): void {\n if (globalRateLimiter) {\n globalRateLimiter.clearQueue();\n }\n globalRateLimiter = new RateLimiter(config);\n}\n\n/**\n * Reset the global rate limiter to defaults\n */\nexport function resetGlobalRateLimiter(): void {\n globalRateLimiter?.clearQueue();\n globalRateLimiter = null;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { createClient, type WooCommerceClient } from '@atomic-solutions/woocommerce-api-client';\n\nimport { WooCommerceProvider } from '..';\nimport {\n configureGlobalRateLimiter,\n getGlobalRateLimiter,\n normalizeStoreUrl,\n validateWooCommerceStore,\n} from '../guardrails';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport {\n DEFAULT_STORE_CONFIG,\n type StoreConfig,\n type StoreContextValue,\n type StoreValidationResult,\n} from './types';\nimport { WooCommerceStoreContext } from './WooCommerceStoreContext';\n\n// Package version for User-Agent header\nconst PACKAGE_VERSION = '0.1.0';\n\n/**\n * Cart headers adapter for storing nonce and cart token\n * Uses a simple in-memory store for now\n */\nfunction createCartHeadersAdapter() {\n let headers: { nonce?: string; cartToken?: string } = {};\n\n return {\n get: async () => headers,\n save: async (newHeaders: { nonce?: string; cartToken?: string }) => {\n headers = { ...headers, ...newHeaders };\n },\n clear: async () => {\n headers = {};\n },\n };\n}\n\nexport interface WooCommerceStoreProviderProps {\n /**\n * Store configuration\n */\n config: StoreConfig;\n\n /**\n * Query keys instance created with createQueryKeys()\n */\n queryKeys: QueryKeys;\n\n /**\n * Children components\n */\n children: ReactNode;\n\n /**\n * Skip store validation (useful for testing)\n * @default false\n */\n skipValidation?: boolean;\n\n /**\n * Fallback UI to show while validating store\n * @default null\n */\n loadingFallback?: ReactNode;\n\n /**\n * Error UI to show when validation fails\n * If not provided, children will still render with validation error in context\n */\n errorFallback?: (error: string, retry: () => void) => ReactNode;\n}\n\n/**\n * WooCommerce Store Provider\n *\n * Main provider component that wraps your app and provides:\n * - Store configuration context\n * - WooCommerce client via woocommerce-utils\n * - Store validation\n * - Rate limiting\n *\n * @example\n * ```tsx\n * <WooCommerceStoreProvider\n * config={{\n * storeUrl: \"https://mystore.com\",\n * theme: { primary: \"#007AFF\" },\n * }}\n * >\n * <App />\n * </WooCommerceStoreProvider>\n * ```\n */\nexport function WooCommerceStoreProvider({\n config,\n queryKeys,\n children,\n skipValidation = false,\n loadingFallback = null,\n errorFallback,\n}: WooCommerceStoreProviderProps) {\n const [isValidating, setIsValidating] = useState(!skipValidation);\n const [isValidated, setIsValidated] = useState(skipValidation);\n const [validationResult, setValidationResult] = useState<StoreValidationResult | undefined>(\n skipValidation ? { valid: true, storeUrl: normalizeStoreUrl(config.storeUrl) } : undefined\n );\n const [validationError, setValidationError] = useState<string | undefined>();\n\n // Merge config with defaults\n const mergedConfig = useMemo(\n () => ({\n ...config,\n features: { ...DEFAULT_STORE_CONFIG.features, ...config.features },\n locale: { ...DEFAULT_STORE_CONFIG.locale, ...config.locale },\n guardrails: { ...DEFAULT_STORE_CONFIG.guardrails, ...config.guardrails },\n debug: config.debug ?? DEFAULT_STORE_CONFIG.debug,\n }),\n [config]\n );\n\n // Configure rate limiter\n useEffect(() => {\n if (mergedConfig.guardrails.rateLimit) {\n configureGlobalRateLimiter(mergedConfig.guardrails.rateLimit);\n }\n }, [mergedConfig.guardrails.rateLimit]);\n\n // Create cart headers adapter\n const cartHeadersAdapter = useRef(createCartHeadersAdapter());\n\n // Create WooCommerce client\n const client = useMemo<WooCommerceClient>(() => {\n const normalizedUrl = normalizeStoreUrl(config.storeUrl);\n\n return createClient({\n baseURL: normalizedUrl,\n storeApiVersion: 'v1',\n cartHeaders: cartHeadersAdapter.current,\n validationMode: 'warn',\n debug: mergedConfig.debug,\n headers: {\n 'User-Agent': `@atomic-solutions/react-native-woocommerce/${PACKAGE_VERSION}`,\n 'X-WC-Client': 'atomic-woocommerce',\n 'X-WC-Client-Version': PACKAGE_VERSION,\n },\n onRequest: async (requestConfig) => {\n // Apply rate limiting\n const rateLimiter = getGlobalRateLimiter();\n await rateLimiter.acquire();\n return requestConfig;\n },\n onError: (error) => {\n if (mergedConfig.debug) {\n console.error('[WooCommerceStore] API Error:', error);\n }\n },\n });\n }, [config.storeUrl, mergedConfig.debug]);\n\n // Validation function\n const validateStore = useCallback(async () => {\n if (skipValidation) {\n return;\n }\n\n setIsValidating(true);\n setValidationError(undefined);\n\n try {\n const result = await validateWooCommerceStore(config.storeUrl, {\n allowLocalhost: process.env.NODE_ENV !== 'production',\n });\n\n setValidationResult(result);\n\n if (result.valid) {\n setIsValidated(true);\n setValidationError(undefined);\n\n if (mergedConfig.debug) {\n console.log('[WooCommerceStore] Connected to:', result.storeName);\n }\n } else {\n setIsValidated(false);\n setValidationError(result.error);\n\n if (mergedConfig.debug) {\n console.warn('[WooCommerceStore] Validation failed:', result.error);\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n setValidationError(errorMessage);\n setIsValidated(false);\n } finally {\n setIsValidating(false);\n }\n }, [config.storeUrl, skipValidation, mergedConfig.debug]);\n\n // Run validation on mount and when storeUrl changes\n useEffect(() => {\n if (mergedConfig.guardrails.validateStore) {\n validateStore();\n } else {\n setIsValidated(true);\n setIsValidating(false);\n }\n }, [validateStore, mergedConfig.guardrails.validateStore]);\n\n // Context value\n const contextValue = useMemo<StoreContextValue>(\n () => ({\n config: mergedConfig,\n isValidated,\n isValidating,\n validationError,\n validationResult,\n revalidate: validateStore,\n }),\n [mergedConfig, isValidated, isValidating, validationError, validationResult, validateStore]\n );\n\n // Show loading fallback while validating\n if (isValidating && loadingFallback) {\n return <>{loadingFallback}</>;\n }\n\n // Show error fallback if validation failed and fallback is provided\n if (validationError && errorFallback) {\n return <>{errorFallback(validationError, validateStore)}</>;\n }\n\n return (\n <WooCommerceStoreContext.Provider value={contextValue}>\n <WooCommerceProvider client={client} queryKeys={queryKeys} onEvent={config.onEvent}>\n {children}\n </WooCommerceProvider>\n </WooCommerceStoreContext.Provider>\n );\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { i as StoreConfig, Q as QueryKeys, j as StoreContextValue } from '../types-wgwJGLQ-.cjs';
5
- export { D as DEFAULT_STORE_CONFIG, I as ImageUrlTransformer, R as RateLimitConfig, k as StoreFeatures, l as StoreGuardrails, S as StoreLocale, m as StoreTheme, a as StoreValidationResult } from '../types-wgwJGLQ-.cjs';
6
- import '@atomic-solutions/woocommerce-utils';
4
+ import { i as StoreConfig, Q as QueryKeys, j as StoreContextValue } from '../types-BDwpAWoN.cjs';
5
+ export { D as DEFAULT_STORE_CONFIG, I as ImageUrlTransformer, R as RateLimitConfig, k as StoreFeatures, l as StoreGuardrails, S as StoreLocale, m as StoreTheme, a as StoreValidationResult } from '../types-BDwpAWoN.cjs';
6
+ import '@atomic-solutions/woocommerce-api-client';
7
7
 
8
8
  interface WooCommerceStoreProviderProps {
9
9
  config: StoreConfig;
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { i as StoreConfig, Q as QueryKeys, j as StoreContextValue } from '../types-wgwJGLQ-.js';
5
- export { D as DEFAULT_STORE_CONFIG, I as ImageUrlTransformer, R as RateLimitConfig, k as StoreFeatures, l as StoreGuardrails, S as StoreLocale, m as StoreTheme, a as StoreValidationResult } from '../types-wgwJGLQ-.js';
6
- import '@atomic-solutions/woocommerce-utils';
4
+ import { i as StoreConfig, Q as QueryKeys, j as StoreContextValue } from '../types-BDwpAWoN.js';
5
+ export { D as DEFAULT_STORE_CONFIG, I as ImageUrlTransformer, R as RateLimitConfig, k as StoreFeatures, l as StoreGuardrails, S as StoreLocale, m as StoreTheme, a as StoreValidationResult } from '../types-BDwpAWoN.js';
6
+ import '@atomic-solutions/woocommerce-api-client';
7
7
 
8
8
  interface WooCommerceStoreProviderProps {
9
9
  config: StoreConfig;
@@ -1,5 +1,5 @@
1
1
  import { createContext, useState, useMemo, useEffect, useRef, useCallback } from 'react';
2
- import { createClient } from '@atomic-solutions/woocommerce-utils';
2
+ import { createClient } from '@atomic-solutions/woocommerce-api-client';
3
3
  import { jsx, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  // src/provider/WooCommerceStoreProvider.tsx
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/events/EventContext.ts","../../src/provider/WooCommerceContext.ts","../../src/provider/WooCommerceProvider.tsx","../../src/provider/WooCommerceStoreContext.ts","../../src/provider/types.ts","../../src/guardrails/storeValidator.ts","../../src/guardrails/rateLimiter.ts","../../src/provider/WooCommerceStoreProvider.tsx"],"names":["createContext","useMemo","jsx"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Event context for emitting WooCommerce events\n */\n\nimport { createContext, useContext } from 'react';\n\nimport type { WooCommerceEventHandler } from './types';\n\n/**\n * Context for the event emitter function\n */\nexport const EventContext = createContext<WooCommerceEventHandler | null>(null);\n\n/**\n * Hook to get the event emitter from context\n *\n * Returns null if no onEvent handler is configured (which is valid)\n */\nexport const useEventEmitter = (): WooCommerceEventHandler | null => {\n return useContext(EventContext);\n};\n","/**\n * WooCommerce context\n */\n\nimport { createContext } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-utils';\n\nimport type { QueryKeys } from '../hooks/queryKeys';\n\n/**\n * WooCommerce context value\n */\nexport interface WooCommerceContextValue {\n client: WooCommerceClient;\n queryKeys: QueryKeys;\n}\n\n/**\n * WooCommerce context for accessing client and query keys from hooks\n */\nexport const WooCommerceContext = createContext<WooCommerceContextValue | null>(null);\n","/**\n * WooCommerce provider component\n *\n * Provides WooCommerce client to child components via React Context.\n * Does NOT provide QueryClientProvider - consumers must wrap this with their own.\n */\n\nimport React, { useMemo } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-utils';\n\nimport { EventContext } from '../events/EventContext';\nimport type { WooCommerceEventHandler } from '../events/types';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport { WooCommerceContext } from './WooCommerceContext';\n\n/**\n * WooCommerce provider props\n */\nexport interface WooCommerceProviderProps {\n /** WooCommerce client instance */\n client: WooCommerceClient;\n\n /** Query keys instance created with createQueryKeys() */\n queryKeys: QueryKeys;\n\n /**\n * Event handler for all store events\n *\n * Centralize notifications, analytics, and side effects in one place.\n *\n * @example\n * ```tsx\n * <WooCommerceProvider\n * client={client}\n * queryKeys={queryKeys}\n * onEvent={(event) => {\n * if (event.status === 'error') {\n * showErrorToast(event.error.message);\n * return;\n * }\n *\n * switch (event.type) {\n * case 'cart:item_added':\n * showSuccessToast(`Added ${event.data.item.name}`);\n * break;\n * case 'cart:item_removed':\n * showSuccessToast('Item removed');\n * break;\n * case 'checkout:processed':\n * showSuccessToast('Order placed!');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onEvent?: WooCommerceEventHandler;\n\n /** Child components */\n children: React.ReactNode;\n}\n\n/**\n * WooCommerce provider\n *\n * Provides WooCommerce client and query keys to child components via context.\n *\n * **Important:** This provider does NOT wrap QueryClientProvider.\n * You must provide your own QueryClientProvider higher in the tree.\n *\n * @example\n * ```tsx\n * import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n * import { WooCommerceProvider, createClient, createQueryKeys } from '@atomic-solutions/react-woocommerce';\n *\n * const queryClient = new QueryClient();\n * const wooClient = createClient({ ... });\n * const queryKeys = createQueryKeys(['my-app']); // Custom prefix\n *\n * function App() {\n * return (\n * <QueryClientProvider client={queryClient}>\n * <WooCommerceProvider client={wooClient} queryKeys={queryKeys}>\n * <YourApp />\n * </WooCommerceProvider>\n * </QueryClientProvider>\n * );\n * }\n * ```\n */\nexport const WooCommerceProvider: React.FC<WooCommerceProviderProps> = ({\n client,\n queryKeys,\n onEvent,\n children,\n}) => {\n const contextValue = useMemo(() => ({ client, queryKeys }), [client, queryKeys]);\n\n return (\n <WooCommerceContext.Provider value={contextValue}>\n <EventContext.Provider value={onEvent ?? null}>{children}</EventContext.Provider>\n </WooCommerceContext.Provider>\n );\n};\n","import { createContext } from 'react';\n\nimport type { StoreContextValue } from './types';\n\n/**\n * Context for accessing store configuration and state\n *\n * @internal Use the useStore hook instead of accessing this directly\n */\nexport const WooCommerceStoreContext = createContext<StoreContextValue | null>(null);\n\nWooCommerceStoreContext.displayName = 'WooCommerceStoreContext';\n","import type { WooCommerceEventHandler } from '../events/types';\n\n/**\n * Store feature configuration\n */\nexport interface StoreFeatures {\n /** Enable authentication screens (default: false) */\n auth?: boolean;\n /** Enable wishlist functionality (default: false) */\n wishlist?: boolean;\n /** Show product reviews (default: true) */\n reviews?: boolean;\n /** Enable search functionality (default: true) */\n search?: boolean;\n /** Show category navigation (default: true) */\n categories?: boolean;\n}\n\n/**\n * Theme configuration for the store\n */\nexport interface StoreTheme {\n /** Primary brand color (e.g., \"#007AFF\") */\n primary?: string;\n /** Secondary brand color */\n secondary?: string;\n /** Color mode */\n mode?: 'light' | 'dark' | 'auto';\n /** Custom fonts */\n fonts?: {\n heading?: string;\n body?: string;\n };\n}\n\n/**\n * Localization and currency configuration\n */\nexport interface StoreLocale {\n /** BCP 47 locale tag for Intl formatting (e.g., \"en-US\", \"bs-BA\") */\n localeTag?: string;\n /** Currency code (e.g., \"USD\", \"EUR\", \"BAM\") */\n currency?: string;\n /** Currency symbol position */\n currencyPosition?: 'before' | 'after';\n /** Thousands separator (e.g., \",\") */\n thousandsSeparator?: string;\n /** Decimal separator (e.g., \".\") */\n decimalSeparator?: string;\n /** Number of decimal places */\n decimals?: number;\n}\n\n/**\n * Function to transform image URLs (e.g., for custom sizing, CDN, optimization)\n */\nexport type ImageUrlTransformer = (\n url: string,\n size: 'thumbnail' | 'medium' | 'large' | 'full'\n) => string;\n\n/**\n * Rate limiting configuration\n */\nexport interface RateLimitConfig {\n /** Maximum requests per minute (default: 60) */\n requestsPerMinute?: number;\n /** Maximum requests per second (default: 10) */\n requestsPerSecond?: number;\n /** Burst limit for temporary spikes (default: 20) */\n burstLimit?: number;\n}\n\n/**\n * Guardrails configuration to prevent abuse\n */\nexport interface StoreGuardrails {\n /** Validate that the URL is a valid WooCommerce store (default: true) */\n validateStore?: boolean;\n /** Rate limiting configuration */\n rateLimit?: RateLimitConfig;\n /** Optional license key for production usage tracking */\n licenseKey?: string;\n}\n\n/**\n * Store validation result\n */\nexport interface StoreValidationResult {\n /** Whether the store is valid */\n valid: boolean;\n /** Store name (if available) */\n storeName?: string;\n /** Normalized store URL */\n storeUrl?: string;\n /** WooCommerce version (if detectable) */\n wcVersion?: string;\n /** Error message if validation failed */\n error?: string;\n}\n\n/**\n * Main store configuration\n */\nexport interface StoreConfig {\n /**\n * WooCommerce store URL\n * @example \"https://mystore.com\" or \"https://mystore.com/wp-json\"\n */\n storeUrl: string;\n\n /** Feature toggles */\n features?: StoreFeatures;\n\n /** Theme customization */\n theme?: StoreTheme;\n\n /** Localization settings */\n locale?: StoreLocale;\n\n /** Guardrails configuration */\n guardrails?: StoreGuardrails;\n\n /** Event handler for WooCommerce events */\n onEvent?: WooCommerceEventHandler;\n\n /** Enable debug logging (default: false in production) */\n debug?: boolean;\n\n /**\n * Custom image URL transformer for optimization\n * Use this to add CDN prefixes, size suffixes, or custom transformations\n *\n * @example\n * ```ts\n * imageUrlTransformer: (url, size) => {\n * // Add PNG optimization for ma-native\n * if (url.endsWith('.png') && !url.includes('unnamed.png')) {\n * return url.replace('.png', '-300x300.png');\n * }\n * return url;\n * }\n * ```\n */\n imageUrlTransformer?: ImageUrlTransformer;\n\n /** Fallback image URL when products have no images */\n fallbackImageUrl?: string;\n}\n\n/**\n * Store context value available via useStore hook\n */\nexport interface StoreContextValue {\n /** Current store configuration */\n config: StoreConfig;\n /** Whether the store has been validated */\n isValidated: boolean;\n /** Whether validation is in progress */\n isValidating: boolean;\n /** Validation error (if any) */\n validationError?: string;\n /** Store validation result */\n validationResult?: StoreValidationResult;\n /** Re-validate the store connection */\n revalidate: () => Promise<void>;\n}\n\n/**\n * Default store configuration values\n */\nexport const DEFAULT_STORE_CONFIG: Required<\n Pick<StoreConfig, 'features' | 'locale' | 'guardrails' | 'debug'>\n> = {\n features: {\n auth: false,\n wishlist: false,\n reviews: true,\n search: true,\n categories: true,\n },\n locale: {\n localeTag: 'en-US',\n currency: 'USD',\n currencyPosition: 'before',\n thousandsSeparator: ',',\n decimalSeparator: '.',\n decimals: 2,\n },\n guardrails: {\n validateStore: true,\n rateLimit: {\n requestsPerMinute: 60,\n requestsPerSecond: 10,\n burstLimit: 20,\n },\n },\n debug: process.env.NODE_ENV !== 'production',\n};\n","import type { StoreValidationResult } from '../provider/types';\n\n/**\n * Normalizes a store URL to ensure consistent format\n *\n * @param url - Raw URL input from user\n * @returns Normalized URL with /wp-json suffix\n *\n * @example\n * normalizeStoreUrl(\"https://mystore.com\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/wp-json\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"mystore.com\") // \"https://mystore.com/wp-json\"\n */\nexport function normalizeStoreUrl(url: string): string {\n let normalized = url.trim();\n\n // Add https:// if no protocol\n if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {\n normalized = `https://${normalized}`;\n }\n\n // Remove trailing slash\n normalized = normalized.replace(/\\/+$/, '');\n\n // Remove /wp-json if present (we'll add it consistently)\n normalized = normalized.replace(/\\/wp-json\\/?$/, '');\n\n return `${normalized}/wp-json`;\n}\n\n/**\n * Extracts the base URL from a normalized store URL\n *\n * @param normalizedUrl - URL that ends with /wp-json\n * @returns Base URL without /wp-json suffix\n */\nexport function getBaseUrl(normalizedUrl: string): string {\n return normalizedUrl.replace(/\\/wp-json\\/?$/, '');\n}\n\n/**\n * Validates that a URL points to a valid WooCommerce store\n *\n * This function performs the following checks:\n * 1. Normalizes the URL format\n * 2. Checks if the WooCommerce Store API is accessible\n * 3. Verifies the response structure\n *\n * @param url - Store URL to validate\n * @param options - Validation options\n * @returns Validation result with store details or error\n *\n * @example\n * const result = await validateWooCommerceStore(\"https://mystore.com\");\n * if (result.valid) {\n * console.log(`Connected to ${result.storeName}`);\n * } else {\n * console.error(`Failed: ${result.error}`);\n * }\n */\nexport async function validateWooCommerceStore(\n url: string,\n options: {\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Allow localhost URLs (default: true in development) */\n allowLocalhost?: boolean;\n } = {}\n): Promise<StoreValidationResult> {\n const { timeout = 10000, allowLocalhost = process.env.NODE_ENV !== 'production' } = options;\n\n try {\n // 1. Basic URL validation\n const normalizedUrl = normalizeStoreUrl(url);\n const baseUrl = getBaseUrl(normalizedUrl);\n\n // Check for localhost in production\n const isLocalhost = baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1');\n if (isLocalhost && !allowLocalhost) {\n return {\n valid: false,\n error: 'Localhost URLs are not allowed in production',\n };\n }\n\n // 2. Check WooCommerce Store API v1\n const storeApiUrl = `${normalizedUrl}/wc/store/v1`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n let response: Response;\n try {\n response = await fetch(storeApiUrl, {\n method: 'GET',\n headers: {\n 'User-Agent': '@atomic-solutions/react-native-woocommerce',\n Accept: 'application/json',\n },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Handle various response codes\n if (response.status === 404) {\n return {\n valid: false,\n error:\n 'WooCommerce Store API not found. Ensure WooCommerce is installed and REST API is enabled.',\n };\n }\n\n if (response.status === 401 || response.status === 403) {\n return {\n valid: false,\n error: 'Access denied. Check that the REST API is publicly accessible for the Store API.',\n };\n }\n\n if (!response.ok) {\n return {\n valid: false,\n error: `Unexpected response: ${response.status} ${response.statusText}`,\n };\n }\n\n // 3. Try to get store info from the root endpoint\n let storeName: string | undefined;\n let wcVersion: string | undefined;\n\n try {\n const rootResponse = await fetch(normalizedUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (rootResponse.ok) {\n const rootData = (await rootResponse.json()) as {\n name?: string;\n namespaces?: string[];\n };\n storeName = rootData.name;\n\n // Check for WooCommerce namespaces\n if (rootData.namespaces) {\n const hasWcNamespace = rootData.namespaces.some(\n (ns) => ns.startsWith('wc/') || ns === 'wc'\n );\n if (!hasWcNamespace) {\n return {\n valid: false,\n error: 'WooCommerce REST API namespace not found. Is WooCommerce installed?',\n };\n }\n }\n }\n } catch {\n // Root endpoint info is optional, continue without it\n }\n\n return {\n valid: true,\n storeName: storeName || 'WooCommerce Store',\n storeUrl: normalizedUrl,\n wcVersion,\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n return {\n valid: false,\n error: `Connection timed out after ${timeout}ms`,\n };\n }\n\n // Network errors\n if (error.message.includes('Network request failed')) {\n return {\n valid: false,\n error: 'Unable to connect to the store. Check the URL and your internet connection.',\n };\n }\n\n return {\n valid: false,\n error: error.message,\n };\n }\n\n return {\n valid: false,\n error: 'An unexpected error occurred while validating the store',\n };\n }\n}\n\n/**\n * Quick check if a URL looks like a valid WooCommerce store URL\n * Does NOT make network requests - just validates format\n *\n * @param url - URL to check\n * @returns Whether the URL format is valid\n */\nexport function isValidStoreUrlFormat(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n return false;\n }\n\n try {\n const normalized = normalizeStoreUrl(trimmed);\n new URL(normalized); // Will throw if invalid\n return true;\n } catch {\n return false;\n }\n}\n","import type { RateLimitConfig } from '../provider/types';\n\n/**\n * Default rate limit configuration\n */\nconst DEFAULT_CONFIG: Required<RateLimitConfig> = {\n requestsPerSecond: 10,\n requestsPerMinute: 60,\n burstLimit: 20,\n};\n\n/**\n * Token bucket rate limiter for client-side request throttling\n *\n * Uses a token bucket algorithm that allows burst traffic while\n * enforcing an average rate limit over time.\n *\n * @example\n * const limiter = new RateLimiter({ requestsPerSecond: 10 });\n *\n * // In axios interceptor\n * axios.interceptors.request.use(async (config) => {\n * await limiter.acquire();\n * return config;\n * });\n */\nexport class RateLimiter {\n private tokens: number;\n private lastRefill: number;\n private readonly maxTokens: number;\n private readonly refillRate: number; // tokens per millisecond\n private readonly queue: Array<{\n resolve: () => void;\n reject: (error: Error) => void;\n }> = [];\n private isProcessing = false;\n\n constructor(config: RateLimitConfig = {}) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n this.maxTokens = mergedConfig.burstLimit;\n this.tokens = this.maxTokens;\n this.refillRate = mergedConfig.requestsPerSecond / 1000;\n this.lastRefill = Date.now();\n }\n\n /**\n * Refills tokens based on elapsed time\n */\n private refill(): void {\n const now = Date.now();\n const elapsed = now - this.lastRefill;\n const tokensToAdd = elapsed * this.refillRate;\n\n this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);\n this.lastRefill = now;\n }\n\n /**\n * Process queued requests\n */\n private async processQueue(): Promise<void> {\n if (this.isProcessing) {\n return;\n }\n\n this.isProcessing = true;\n\n while (this.queue.length > 0) {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n const request = this.queue.shift();\n request?.resolve();\n } else {\n // Calculate wait time until we have a token\n const waitTime = Math.ceil((1 - this.tokens) / this.refillRate);\n await this.sleep(waitTime);\n }\n }\n\n this.isProcessing = false;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Acquire a token before making a request\n * Returns immediately if tokens available, otherwise queues the request\n *\n * @returns Promise that resolves when request can proceed\n */\n acquire(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n resolve();\n } else {\n this.queue.push({ resolve, reject });\n this.processQueue();\n }\n });\n }\n\n /**\n * Try to acquire a token without waiting\n *\n * @returns true if token was acquired, false if rate limited\n */\n tryAcquire(): boolean {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n\n return false;\n }\n\n /**\n * Get current number of available tokens\n */\n getAvailableTokens(): number {\n this.refill();\n return Math.floor(this.tokens);\n }\n\n /**\n * Get number of queued requests\n */\n getQueueLength(): number {\n return this.queue.length;\n }\n\n /**\n * Clear all queued requests (rejects them)\n */\n clearQueue(): void {\n while (this.queue.length > 0) {\n const request = this.queue.shift();\n request?.reject(new Error('Rate limiter queue cleared'));\n }\n }\n\n /**\n * Reset the rate limiter to initial state\n */\n reset(): void {\n this.clearQueue();\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n }\n}\n\n/**\n * Singleton rate limiter instance\n * Can be configured once at app startup\n */\nlet globalRateLimiter: RateLimiter | null = null;\n\n/**\n * Get or create the global rate limiter instance\n *\n * @param config - Optional config (only used on first call)\n */\nexport function getGlobalRateLimiter(config?: RateLimitConfig): RateLimiter {\n if (!globalRateLimiter) {\n globalRateLimiter = new RateLimiter(config);\n }\n return globalRateLimiter;\n}\n\n/**\n * Configure the global rate limiter\n * Creates a new instance with the provided config\n *\n * @param config - Rate limit configuration\n */\nexport function configureGlobalRateLimiter(config: RateLimitConfig): void {\n if (globalRateLimiter) {\n globalRateLimiter.clearQueue();\n }\n globalRateLimiter = new RateLimiter(config);\n}\n\n/**\n * Reset the global rate limiter to defaults\n */\nexport function resetGlobalRateLimiter(): void {\n globalRateLimiter?.clearQueue();\n globalRateLimiter = null;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { createClient, type WooCommerceClient } from '@atomic-solutions/woocommerce-utils';\n\nimport { WooCommerceProvider } from '..';\nimport {\n configureGlobalRateLimiter,\n getGlobalRateLimiter,\n normalizeStoreUrl,\n validateWooCommerceStore,\n} from '../guardrails';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport {\n DEFAULT_STORE_CONFIG,\n type StoreConfig,\n type StoreContextValue,\n type StoreValidationResult,\n} from './types';\nimport { WooCommerceStoreContext } from './WooCommerceStoreContext';\n\n// Package version for User-Agent header\nconst PACKAGE_VERSION = '0.1.0';\n\n/**\n * Cart headers adapter for storing nonce and cart token\n * Uses a simple in-memory store for now\n */\nfunction createCartHeadersAdapter() {\n let headers: { nonce?: string; cartToken?: string } = {};\n\n return {\n get: async () => headers,\n save: async (newHeaders: { nonce?: string; cartToken?: string }) => {\n headers = { ...headers, ...newHeaders };\n },\n clear: async () => {\n headers = {};\n },\n };\n}\n\nexport interface WooCommerceStoreProviderProps {\n /**\n * Store configuration\n */\n config: StoreConfig;\n\n /**\n * Query keys instance created with createQueryKeys()\n */\n queryKeys: QueryKeys;\n\n /**\n * Children components\n */\n children: ReactNode;\n\n /**\n * Skip store validation (useful for testing)\n * @default false\n */\n skipValidation?: boolean;\n\n /**\n * Fallback UI to show while validating store\n * @default null\n */\n loadingFallback?: ReactNode;\n\n /**\n * Error UI to show when validation fails\n * If not provided, children will still render with validation error in context\n */\n errorFallback?: (error: string, retry: () => void) => ReactNode;\n}\n\n/**\n * WooCommerce Store Provider\n *\n * Main provider component that wraps your app and provides:\n * - Store configuration context\n * - WooCommerce client via woocommerce-utils\n * - Store validation\n * - Rate limiting\n *\n * @example\n * ```tsx\n * <WooCommerceStoreProvider\n * config={{\n * storeUrl: \"https://mystore.com\",\n * theme: { primary: \"#007AFF\" },\n * }}\n * >\n * <App />\n * </WooCommerceStoreProvider>\n * ```\n */\nexport function WooCommerceStoreProvider({\n config,\n queryKeys,\n children,\n skipValidation = false,\n loadingFallback = null,\n errorFallback,\n}: WooCommerceStoreProviderProps) {\n const [isValidating, setIsValidating] = useState(!skipValidation);\n const [isValidated, setIsValidated] = useState(skipValidation);\n const [validationResult, setValidationResult] = useState<StoreValidationResult | undefined>(\n skipValidation ? { valid: true, storeUrl: normalizeStoreUrl(config.storeUrl) } : undefined\n );\n const [validationError, setValidationError] = useState<string | undefined>();\n\n // Merge config with defaults\n const mergedConfig = useMemo(\n () => ({\n ...config,\n features: { ...DEFAULT_STORE_CONFIG.features, ...config.features },\n locale: { ...DEFAULT_STORE_CONFIG.locale, ...config.locale },\n guardrails: { ...DEFAULT_STORE_CONFIG.guardrails, ...config.guardrails },\n debug: config.debug ?? DEFAULT_STORE_CONFIG.debug,\n }),\n [config]\n );\n\n // Configure rate limiter\n useEffect(() => {\n if (mergedConfig.guardrails.rateLimit) {\n configureGlobalRateLimiter(mergedConfig.guardrails.rateLimit);\n }\n }, [mergedConfig.guardrails.rateLimit]);\n\n // Create cart headers adapter\n const cartHeadersAdapter = useRef(createCartHeadersAdapter());\n\n // Create WooCommerce client\n const client = useMemo<WooCommerceClient>(() => {\n const normalizedUrl = normalizeStoreUrl(config.storeUrl);\n\n return createClient({\n baseURL: normalizedUrl,\n storeApiVersion: 'v1',\n cartHeaders: cartHeadersAdapter.current,\n validationMode: 'warn',\n debug: mergedConfig.debug,\n headers: {\n 'User-Agent': `@atomic-solutions/react-native-woocommerce/${PACKAGE_VERSION}`,\n 'X-WC-Client': 'atomic-woocommerce',\n 'X-WC-Client-Version': PACKAGE_VERSION,\n },\n onRequest: async (requestConfig) => {\n // Apply rate limiting\n const rateLimiter = getGlobalRateLimiter();\n await rateLimiter.acquire();\n return requestConfig;\n },\n onError: (error) => {\n if (mergedConfig.debug) {\n console.error('[WooCommerceStore] API Error:', error);\n }\n },\n });\n }, [config.storeUrl, mergedConfig.debug]);\n\n // Validation function\n const validateStore = useCallback(async () => {\n if (skipValidation) {\n return;\n }\n\n setIsValidating(true);\n setValidationError(undefined);\n\n try {\n const result = await validateWooCommerceStore(config.storeUrl, {\n allowLocalhost: process.env.NODE_ENV !== 'production',\n });\n\n setValidationResult(result);\n\n if (result.valid) {\n setIsValidated(true);\n setValidationError(undefined);\n\n if (mergedConfig.debug) {\n console.log('[WooCommerceStore] Connected to:', result.storeName);\n }\n } else {\n setIsValidated(false);\n setValidationError(result.error);\n\n if (mergedConfig.debug) {\n console.warn('[WooCommerceStore] Validation failed:', result.error);\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n setValidationError(errorMessage);\n setIsValidated(false);\n } finally {\n setIsValidating(false);\n }\n }, [config.storeUrl, skipValidation, mergedConfig.debug]);\n\n // Run validation on mount and when storeUrl changes\n useEffect(() => {\n if (mergedConfig.guardrails.validateStore) {\n validateStore();\n } else {\n setIsValidated(true);\n setIsValidating(false);\n }\n }, [validateStore, mergedConfig.guardrails.validateStore]);\n\n // Context value\n const contextValue = useMemo<StoreContextValue>(\n () => ({\n config: mergedConfig,\n isValidated,\n isValidating,\n validationError,\n validationResult,\n revalidate: validateStore,\n }),\n [mergedConfig, isValidated, isValidating, validationError, validationResult, validateStore]\n );\n\n // Show loading fallback while validating\n if (isValidating && loadingFallback) {\n return <>{loadingFallback}</>;\n }\n\n // Show error fallback if validation failed and fallback is provided\n if (validationError && errorFallback) {\n return <>{errorFallback(validationError, validateStore)}</>;\n }\n\n return (\n <WooCommerceStoreContext.Provider value={contextValue}>\n <WooCommerceProvider client={client} queryKeys={queryKeys} onEvent={config.onEvent}>\n {children}\n </WooCommerceProvider>\n </WooCommerceStoreContext.Provider>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/events/EventContext.ts","../../src/provider/WooCommerceContext.ts","../../src/provider/WooCommerceProvider.tsx","../../src/provider/WooCommerceStoreContext.ts","../../src/provider/types.ts","../../src/guardrails/storeValidator.ts","../../src/guardrails/rateLimiter.ts","../../src/provider/WooCommerceStoreProvider.tsx"],"names":["createContext","useMemo","jsx"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Event context for emitting WooCommerce events\n */\n\nimport { createContext, useContext } from 'react';\n\nimport type { WooCommerceEventHandler } from './types';\n\n/**\n * Context for the event emitter function\n */\nexport const EventContext = createContext<WooCommerceEventHandler | null>(null);\n\n/**\n * Hook to get the event emitter from context\n *\n * Returns null if no onEvent handler is configured (which is valid)\n */\nexport const useEventEmitter = (): WooCommerceEventHandler | null => {\n return useContext(EventContext);\n};\n","/**\n * WooCommerce context\n */\n\nimport { createContext } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-api-client';\n\nimport type { QueryKeys } from '../hooks/queryKeys';\n\n/**\n * WooCommerce context value\n */\nexport interface WooCommerceContextValue {\n client: WooCommerceClient;\n queryKeys: QueryKeys;\n}\n\n/**\n * WooCommerce context for accessing client and query keys from hooks\n */\nexport const WooCommerceContext = createContext<WooCommerceContextValue | null>(null);\n","/**\n * WooCommerce provider component\n *\n * Provides WooCommerce client to child components via React Context.\n * Does NOT provide QueryClientProvider - consumers must wrap this with their own.\n */\n\nimport React, { useMemo } from 'react';\nimport type { WooCommerceClient } from '@atomic-solutions/woocommerce-api-client';\n\nimport { EventContext } from '../events/EventContext';\nimport type { WooCommerceEventHandler } from '../events/types';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport { WooCommerceContext } from './WooCommerceContext';\n\n/**\n * WooCommerce provider props\n */\nexport interface WooCommerceProviderProps {\n /** WooCommerce client instance */\n client: WooCommerceClient;\n\n /** Query keys instance created with createQueryKeys() */\n queryKeys: QueryKeys;\n\n /**\n * Event handler for all store events\n *\n * Centralize notifications, analytics, and side effects in one place.\n *\n * @example\n * ```tsx\n * <WooCommerceProvider\n * client={client}\n * queryKeys={queryKeys}\n * onEvent={(event) => {\n * if (event.status === 'error') {\n * showErrorToast(event.error.message);\n * return;\n * }\n *\n * switch (event.type) {\n * case 'cart:item_added':\n * showSuccessToast(`Added ${event.data.item.name}`);\n * break;\n * case 'cart:item_removed':\n * showSuccessToast('Item removed');\n * break;\n * case 'checkout:processed':\n * showSuccessToast('Order placed!');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onEvent?: WooCommerceEventHandler;\n\n /** Child components */\n children: React.ReactNode;\n}\n\n/**\n * WooCommerce provider\n *\n * Provides WooCommerce client and query keys to child components via context.\n *\n * **Important:** This provider does NOT wrap QueryClientProvider.\n * You must provide your own QueryClientProvider higher in the tree.\n *\n * @example\n * ```tsx\n * import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n * import { WooCommerceProvider, createClient, createQueryKeys } from '@atomic-solutions/react-woocommerce';\n *\n * const queryClient = new QueryClient();\n * const wooClient = createClient({ ... });\n * const queryKeys = createQueryKeys(['my-app']); // Custom prefix\n *\n * function App() {\n * return (\n * <QueryClientProvider client={queryClient}>\n * <WooCommerceProvider client={wooClient} queryKeys={queryKeys}>\n * <YourApp />\n * </WooCommerceProvider>\n * </QueryClientProvider>\n * );\n * }\n * ```\n */\nexport const WooCommerceProvider: React.FC<WooCommerceProviderProps> = ({\n client,\n queryKeys,\n onEvent,\n children,\n}) => {\n const contextValue = useMemo(() => ({ client, queryKeys }), [client, queryKeys]);\n\n return (\n <WooCommerceContext.Provider value={contextValue}>\n <EventContext.Provider value={onEvent ?? null}>{children}</EventContext.Provider>\n </WooCommerceContext.Provider>\n );\n};\n","import { createContext } from 'react';\n\nimport type { StoreContextValue } from './types';\n\n/**\n * Context for accessing store configuration and state\n *\n * @internal Use the useStore hook instead of accessing this directly\n */\nexport const WooCommerceStoreContext = createContext<StoreContextValue | null>(null);\n\nWooCommerceStoreContext.displayName = 'WooCommerceStoreContext';\n","import type { WooCommerceEventHandler } from '../events/types';\n\n/**\n * Store feature configuration\n */\nexport interface StoreFeatures {\n /** Enable authentication screens (default: false) */\n auth?: boolean;\n /** Enable wishlist functionality (default: false) */\n wishlist?: boolean;\n /** Show product reviews (default: true) */\n reviews?: boolean;\n /** Enable search functionality (default: true) */\n search?: boolean;\n /** Show category navigation (default: true) */\n categories?: boolean;\n}\n\n/**\n * Theme configuration for the store\n */\nexport interface StoreTheme {\n /** Primary brand color (e.g., \"#007AFF\") */\n primary?: string;\n /** Secondary brand color */\n secondary?: string;\n /** Color mode */\n mode?: 'light' | 'dark' | 'auto';\n /** Custom fonts */\n fonts?: {\n heading?: string;\n body?: string;\n };\n}\n\n/**\n * Localization and currency configuration\n */\nexport interface StoreLocale {\n /** BCP 47 locale tag for Intl formatting (e.g., \"en-US\", \"bs-BA\") */\n localeTag?: string;\n /** Currency code (e.g., \"USD\", \"EUR\", \"BAM\") */\n currency?: string;\n /** Currency symbol position */\n currencyPosition?: 'before' | 'after';\n /** Thousands separator (e.g., \",\") */\n thousandsSeparator?: string;\n /** Decimal separator (e.g., \".\") */\n decimalSeparator?: string;\n /** Number of decimal places */\n decimals?: number;\n}\n\n/**\n * Function to transform image URLs (e.g., for custom sizing, CDN, optimization)\n */\nexport type ImageUrlTransformer = (\n url: string,\n size: 'thumbnail' | 'medium' | 'large' | 'full'\n) => string;\n\n/**\n * Rate limiting configuration\n */\nexport interface RateLimitConfig {\n /** Maximum requests per minute (default: 60) */\n requestsPerMinute?: number;\n /** Maximum requests per second (default: 10) */\n requestsPerSecond?: number;\n /** Burst limit for temporary spikes (default: 20) */\n burstLimit?: number;\n}\n\n/**\n * Guardrails configuration to prevent abuse\n */\nexport interface StoreGuardrails {\n /** Validate that the URL is a valid WooCommerce store (default: true) */\n validateStore?: boolean;\n /** Rate limiting configuration */\n rateLimit?: RateLimitConfig;\n /** Optional license key for production usage tracking */\n licenseKey?: string;\n}\n\n/**\n * Store validation result\n */\nexport interface StoreValidationResult {\n /** Whether the store is valid */\n valid: boolean;\n /** Store name (if available) */\n storeName?: string;\n /** Normalized store URL */\n storeUrl?: string;\n /** WooCommerce version (if detectable) */\n wcVersion?: string;\n /** Error message if validation failed */\n error?: string;\n}\n\n/**\n * Main store configuration\n */\nexport interface StoreConfig {\n /**\n * WooCommerce store URL\n * @example \"https://mystore.com\" or \"https://mystore.com/wp-json\"\n */\n storeUrl: string;\n\n /** Feature toggles */\n features?: StoreFeatures;\n\n /** Theme customization */\n theme?: StoreTheme;\n\n /** Localization settings */\n locale?: StoreLocale;\n\n /** Guardrails configuration */\n guardrails?: StoreGuardrails;\n\n /** Event handler for WooCommerce events */\n onEvent?: WooCommerceEventHandler;\n\n /** Enable debug logging (default: false in production) */\n debug?: boolean;\n\n /**\n * Custom image URL transformer for optimization\n * Use this to add CDN prefixes, size suffixes, or custom transformations\n *\n * @example\n * ```ts\n * imageUrlTransformer: (url, size) => {\n * // Add PNG optimization for ma-native\n * if (url.endsWith('.png') && !url.includes('unnamed.png')) {\n * return url.replace('.png', '-300x300.png');\n * }\n * return url;\n * }\n * ```\n */\n imageUrlTransformer?: ImageUrlTransformer;\n\n /** Fallback image URL when products have no images */\n fallbackImageUrl?: string;\n}\n\n/**\n * Store context value available via useStore hook\n */\nexport interface StoreContextValue {\n /** Current store configuration */\n config: StoreConfig;\n /** Whether the store has been validated */\n isValidated: boolean;\n /** Whether validation is in progress */\n isValidating: boolean;\n /** Validation error (if any) */\n validationError?: string;\n /** Store validation result */\n validationResult?: StoreValidationResult;\n /** Re-validate the store connection */\n revalidate: () => Promise<void>;\n}\n\n/**\n * Default store configuration values\n */\nexport const DEFAULT_STORE_CONFIG: Required<\n Pick<StoreConfig, 'features' | 'locale' | 'guardrails' | 'debug'>\n> = {\n features: {\n auth: false,\n wishlist: false,\n reviews: true,\n search: true,\n categories: true,\n },\n locale: {\n localeTag: 'en-US',\n currency: 'USD',\n currencyPosition: 'before',\n thousandsSeparator: ',',\n decimalSeparator: '.',\n decimals: 2,\n },\n guardrails: {\n validateStore: true,\n rateLimit: {\n requestsPerMinute: 60,\n requestsPerSecond: 10,\n burstLimit: 20,\n },\n },\n debug: process.env.NODE_ENV !== 'production',\n};\n","import type { StoreValidationResult } from '../provider/types';\n\n/**\n * Normalizes a store URL to ensure consistent format\n *\n * @param url - Raw URL input from user\n * @returns Normalized URL with /wp-json suffix\n *\n * @example\n * normalizeStoreUrl(\"https://mystore.com\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"https://mystore.com/wp-json\") // \"https://mystore.com/wp-json\"\n * normalizeStoreUrl(\"mystore.com\") // \"https://mystore.com/wp-json\"\n */\nexport function normalizeStoreUrl(url: string): string {\n let normalized = url.trim();\n\n // Add https:// if no protocol\n if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {\n normalized = `https://${normalized}`;\n }\n\n // Remove trailing slash\n normalized = normalized.replace(/\\/+$/, '');\n\n // Remove /wp-json if present (we'll add it consistently)\n normalized = normalized.replace(/\\/wp-json\\/?$/, '');\n\n return `${normalized}/wp-json`;\n}\n\n/**\n * Extracts the base URL from a normalized store URL\n *\n * @param normalizedUrl - URL that ends with /wp-json\n * @returns Base URL without /wp-json suffix\n */\nexport function getBaseUrl(normalizedUrl: string): string {\n return normalizedUrl.replace(/\\/wp-json\\/?$/, '');\n}\n\n/**\n * Validates that a URL points to a valid WooCommerce store\n *\n * This function performs the following checks:\n * 1. Normalizes the URL format\n * 2. Checks if the WooCommerce Store API is accessible\n * 3. Verifies the response structure\n *\n * @param url - Store URL to validate\n * @param options - Validation options\n * @returns Validation result with store details or error\n *\n * @example\n * const result = await validateWooCommerceStore(\"https://mystore.com\");\n * if (result.valid) {\n * console.log(`Connected to ${result.storeName}`);\n * } else {\n * console.error(`Failed: ${result.error}`);\n * }\n */\nexport async function validateWooCommerceStore(\n url: string,\n options: {\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /** Allow localhost URLs (default: true in development) */\n allowLocalhost?: boolean;\n } = {}\n): Promise<StoreValidationResult> {\n const { timeout = 10000, allowLocalhost = process.env.NODE_ENV !== 'production' } = options;\n\n try {\n // 1. Basic URL validation\n const normalizedUrl = normalizeStoreUrl(url);\n const baseUrl = getBaseUrl(normalizedUrl);\n\n // Check for localhost in production\n const isLocalhost = baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1');\n if (isLocalhost && !allowLocalhost) {\n return {\n valid: false,\n error: 'Localhost URLs are not allowed in production',\n };\n }\n\n // 2. Check WooCommerce Store API v1\n const storeApiUrl = `${normalizedUrl}/wc/store/v1`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n let response: Response;\n try {\n response = await fetch(storeApiUrl, {\n method: 'GET',\n headers: {\n 'User-Agent': '@atomic-solutions/react-native-woocommerce',\n Accept: 'application/json',\n },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Handle various response codes\n if (response.status === 404) {\n return {\n valid: false,\n error:\n 'WooCommerce Store API not found. Ensure WooCommerce is installed and REST API is enabled.',\n };\n }\n\n if (response.status === 401 || response.status === 403) {\n return {\n valid: false,\n error: 'Access denied. Check that the REST API is publicly accessible for the Store API.',\n };\n }\n\n if (!response.ok) {\n return {\n valid: false,\n error: `Unexpected response: ${response.status} ${response.statusText}`,\n };\n }\n\n // 3. Try to get store info from the root endpoint\n let storeName: string | undefined;\n let wcVersion: string | undefined;\n\n try {\n const rootResponse = await fetch(normalizedUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (rootResponse.ok) {\n const rootData = (await rootResponse.json()) as {\n name?: string;\n namespaces?: string[];\n };\n storeName = rootData.name;\n\n // Check for WooCommerce namespaces\n if (rootData.namespaces) {\n const hasWcNamespace = rootData.namespaces.some(\n (ns) => ns.startsWith('wc/') || ns === 'wc'\n );\n if (!hasWcNamespace) {\n return {\n valid: false,\n error: 'WooCommerce REST API namespace not found. Is WooCommerce installed?',\n };\n }\n }\n }\n } catch {\n // Root endpoint info is optional, continue without it\n }\n\n return {\n valid: true,\n storeName: storeName || 'WooCommerce Store',\n storeUrl: normalizedUrl,\n wcVersion,\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n return {\n valid: false,\n error: `Connection timed out after ${timeout}ms`,\n };\n }\n\n // Network errors\n if (error.message.includes('Network request failed')) {\n return {\n valid: false,\n error: 'Unable to connect to the store. Check the URL and your internet connection.',\n };\n }\n\n return {\n valid: false,\n error: error.message,\n };\n }\n\n return {\n valid: false,\n error: 'An unexpected error occurred while validating the store',\n };\n }\n}\n\n/**\n * Quick check if a URL looks like a valid WooCommerce store URL\n * Does NOT make network requests - just validates format\n *\n * @param url - URL to check\n * @returns Whether the URL format is valid\n */\nexport function isValidStoreUrlFormat(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n return false;\n }\n\n try {\n const normalized = normalizeStoreUrl(trimmed);\n new URL(normalized); // Will throw if invalid\n return true;\n } catch {\n return false;\n }\n}\n","import type { RateLimitConfig } from '../provider/types';\n\n/**\n * Default rate limit configuration\n */\nconst DEFAULT_CONFIG: Required<RateLimitConfig> = {\n requestsPerSecond: 10,\n requestsPerMinute: 60,\n burstLimit: 20,\n};\n\n/**\n * Token bucket rate limiter for client-side request throttling\n *\n * Uses a token bucket algorithm that allows burst traffic while\n * enforcing an average rate limit over time.\n *\n * @example\n * const limiter = new RateLimiter({ requestsPerSecond: 10 });\n *\n * // In axios interceptor\n * axios.interceptors.request.use(async (config) => {\n * await limiter.acquire();\n * return config;\n * });\n */\nexport class RateLimiter {\n private tokens: number;\n private lastRefill: number;\n private readonly maxTokens: number;\n private readonly refillRate: number; // tokens per millisecond\n private readonly queue: Array<{\n resolve: () => void;\n reject: (error: Error) => void;\n }> = [];\n private isProcessing = false;\n\n constructor(config: RateLimitConfig = {}) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n this.maxTokens = mergedConfig.burstLimit;\n this.tokens = this.maxTokens;\n this.refillRate = mergedConfig.requestsPerSecond / 1000;\n this.lastRefill = Date.now();\n }\n\n /**\n * Refills tokens based on elapsed time\n */\n private refill(): void {\n const now = Date.now();\n const elapsed = now - this.lastRefill;\n const tokensToAdd = elapsed * this.refillRate;\n\n this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);\n this.lastRefill = now;\n }\n\n /**\n * Process queued requests\n */\n private async processQueue(): Promise<void> {\n if (this.isProcessing) {\n return;\n }\n\n this.isProcessing = true;\n\n while (this.queue.length > 0) {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n const request = this.queue.shift();\n request?.resolve();\n } else {\n // Calculate wait time until we have a token\n const waitTime = Math.ceil((1 - this.tokens) / this.refillRate);\n await this.sleep(waitTime);\n }\n }\n\n this.isProcessing = false;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Acquire a token before making a request\n * Returns immediately if tokens available, otherwise queues the request\n *\n * @returns Promise that resolves when request can proceed\n */\n acquire(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n resolve();\n } else {\n this.queue.push({ resolve, reject });\n this.processQueue();\n }\n });\n }\n\n /**\n * Try to acquire a token without waiting\n *\n * @returns true if token was acquired, false if rate limited\n */\n tryAcquire(): boolean {\n this.refill();\n\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n\n return false;\n }\n\n /**\n * Get current number of available tokens\n */\n getAvailableTokens(): number {\n this.refill();\n return Math.floor(this.tokens);\n }\n\n /**\n * Get number of queued requests\n */\n getQueueLength(): number {\n return this.queue.length;\n }\n\n /**\n * Clear all queued requests (rejects them)\n */\n clearQueue(): void {\n while (this.queue.length > 0) {\n const request = this.queue.shift();\n request?.reject(new Error('Rate limiter queue cleared'));\n }\n }\n\n /**\n * Reset the rate limiter to initial state\n */\n reset(): void {\n this.clearQueue();\n this.tokens = this.maxTokens;\n this.lastRefill = Date.now();\n }\n}\n\n/**\n * Singleton rate limiter instance\n * Can be configured once at app startup\n */\nlet globalRateLimiter: RateLimiter | null = null;\n\n/**\n * Get or create the global rate limiter instance\n *\n * @param config - Optional config (only used on first call)\n */\nexport function getGlobalRateLimiter(config?: RateLimitConfig): RateLimiter {\n if (!globalRateLimiter) {\n globalRateLimiter = new RateLimiter(config);\n }\n return globalRateLimiter;\n}\n\n/**\n * Configure the global rate limiter\n * Creates a new instance with the provided config\n *\n * @param config - Rate limit configuration\n */\nexport function configureGlobalRateLimiter(config: RateLimitConfig): void {\n if (globalRateLimiter) {\n globalRateLimiter.clearQueue();\n }\n globalRateLimiter = new RateLimiter(config);\n}\n\n/**\n * Reset the global rate limiter to defaults\n */\nexport function resetGlobalRateLimiter(): void {\n globalRateLimiter?.clearQueue();\n globalRateLimiter = null;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { createClient, type WooCommerceClient } from '@atomic-solutions/woocommerce-api-client';\n\nimport { WooCommerceProvider } from '..';\nimport {\n configureGlobalRateLimiter,\n getGlobalRateLimiter,\n normalizeStoreUrl,\n validateWooCommerceStore,\n} from '../guardrails';\nimport type { QueryKeys } from '../hooks/queryKeys';\nimport {\n DEFAULT_STORE_CONFIG,\n type StoreConfig,\n type StoreContextValue,\n type StoreValidationResult,\n} from './types';\nimport { WooCommerceStoreContext } from './WooCommerceStoreContext';\n\n// Package version for User-Agent header\nconst PACKAGE_VERSION = '0.1.0';\n\n/**\n * Cart headers adapter for storing nonce and cart token\n * Uses a simple in-memory store for now\n */\nfunction createCartHeadersAdapter() {\n let headers: { nonce?: string; cartToken?: string } = {};\n\n return {\n get: async () => headers,\n save: async (newHeaders: { nonce?: string; cartToken?: string }) => {\n headers = { ...headers, ...newHeaders };\n },\n clear: async () => {\n headers = {};\n },\n };\n}\n\nexport interface WooCommerceStoreProviderProps {\n /**\n * Store configuration\n */\n config: StoreConfig;\n\n /**\n * Query keys instance created with createQueryKeys()\n */\n queryKeys: QueryKeys;\n\n /**\n * Children components\n */\n children: ReactNode;\n\n /**\n * Skip store validation (useful for testing)\n * @default false\n */\n skipValidation?: boolean;\n\n /**\n * Fallback UI to show while validating store\n * @default null\n */\n loadingFallback?: ReactNode;\n\n /**\n * Error UI to show when validation fails\n * If not provided, children will still render with validation error in context\n */\n errorFallback?: (error: string, retry: () => void) => ReactNode;\n}\n\n/**\n * WooCommerce Store Provider\n *\n * Main provider component that wraps your app and provides:\n * - Store configuration context\n * - WooCommerce client via woocommerce-utils\n * - Store validation\n * - Rate limiting\n *\n * @example\n * ```tsx\n * <WooCommerceStoreProvider\n * config={{\n * storeUrl: \"https://mystore.com\",\n * theme: { primary: \"#007AFF\" },\n * }}\n * >\n * <App />\n * </WooCommerceStoreProvider>\n * ```\n */\nexport function WooCommerceStoreProvider({\n config,\n queryKeys,\n children,\n skipValidation = false,\n loadingFallback = null,\n errorFallback,\n}: WooCommerceStoreProviderProps) {\n const [isValidating, setIsValidating] = useState(!skipValidation);\n const [isValidated, setIsValidated] = useState(skipValidation);\n const [validationResult, setValidationResult] = useState<StoreValidationResult | undefined>(\n skipValidation ? { valid: true, storeUrl: normalizeStoreUrl(config.storeUrl) } : undefined\n );\n const [validationError, setValidationError] = useState<string | undefined>();\n\n // Merge config with defaults\n const mergedConfig = useMemo(\n () => ({\n ...config,\n features: { ...DEFAULT_STORE_CONFIG.features, ...config.features },\n locale: { ...DEFAULT_STORE_CONFIG.locale, ...config.locale },\n guardrails: { ...DEFAULT_STORE_CONFIG.guardrails, ...config.guardrails },\n debug: config.debug ?? DEFAULT_STORE_CONFIG.debug,\n }),\n [config]\n );\n\n // Configure rate limiter\n useEffect(() => {\n if (mergedConfig.guardrails.rateLimit) {\n configureGlobalRateLimiter(mergedConfig.guardrails.rateLimit);\n }\n }, [mergedConfig.guardrails.rateLimit]);\n\n // Create cart headers adapter\n const cartHeadersAdapter = useRef(createCartHeadersAdapter());\n\n // Create WooCommerce client\n const client = useMemo<WooCommerceClient>(() => {\n const normalizedUrl = normalizeStoreUrl(config.storeUrl);\n\n return createClient({\n baseURL: normalizedUrl,\n storeApiVersion: 'v1',\n cartHeaders: cartHeadersAdapter.current,\n validationMode: 'warn',\n debug: mergedConfig.debug,\n headers: {\n 'User-Agent': `@atomic-solutions/react-native-woocommerce/${PACKAGE_VERSION}`,\n 'X-WC-Client': 'atomic-woocommerce',\n 'X-WC-Client-Version': PACKAGE_VERSION,\n },\n onRequest: async (requestConfig) => {\n // Apply rate limiting\n const rateLimiter = getGlobalRateLimiter();\n await rateLimiter.acquire();\n return requestConfig;\n },\n onError: (error) => {\n if (mergedConfig.debug) {\n console.error('[WooCommerceStore] API Error:', error);\n }\n },\n });\n }, [config.storeUrl, mergedConfig.debug]);\n\n // Validation function\n const validateStore = useCallback(async () => {\n if (skipValidation) {\n return;\n }\n\n setIsValidating(true);\n setValidationError(undefined);\n\n try {\n const result = await validateWooCommerceStore(config.storeUrl, {\n allowLocalhost: process.env.NODE_ENV !== 'production',\n });\n\n setValidationResult(result);\n\n if (result.valid) {\n setIsValidated(true);\n setValidationError(undefined);\n\n if (mergedConfig.debug) {\n console.log('[WooCommerceStore] Connected to:', result.storeName);\n }\n } else {\n setIsValidated(false);\n setValidationError(result.error);\n\n if (mergedConfig.debug) {\n console.warn('[WooCommerceStore] Validation failed:', result.error);\n }\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n setValidationError(errorMessage);\n setIsValidated(false);\n } finally {\n setIsValidating(false);\n }\n }, [config.storeUrl, skipValidation, mergedConfig.debug]);\n\n // Run validation on mount and when storeUrl changes\n useEffect(() => {\n if (mergedConfig.guardrails.validateStore) {\n validateStore();\n } else {\n setIsValidated(true);\n setIsValidating(false);\n }\n }, [validateStore, mergedConfig.guardrails.validateStore]);\n\n // Context value\n const contextValue = useMemo<StoreContextValue>(\n () => ({\n config: mergedConfig,\n isValidated,\n isValidating,\n validationError,\n validationResult,\n revalidate: validateStore,\n }),\n [mergedConfig, isValidated, isValidating, validationError, validationResult, validateStore]\n );\n\n // Show loading fallback while validating\n if (isValidating && loadingFallback) {\n return <>{loadingFallback}</>;\n }\n\n // Show error fallback if validation failed and fallback is provided\n if (validationError && errorFallback) {\n return <>{errorFallback(validationError, validateStore)}</>;\n }\n\n return (\n <WooCommerceStoreContext.Provider value={contextValue}>\n <WooCommerceProvider client={client} queryKeys={queryKeys} onEvent={config.onEvent}>\n {children}\n </WooCommerceProvider>\n </WooCommerceStoreContext.Provider>\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Cart, WooCommerceApiError, CartItem, Checkout, StoreApiOrder, ProductParams } from '@atomic-solutions/woocommerce-utils';
1
+ import { Cart, WooCommerceApiError, CartItem, Checkout, StoreApiOrder, ProductParams } from '@atomic-solutions/woocommerce-api-client';
2
2
 
3
3
  type WooCommerceEventType = 'cart:item_added' | 'cart:item_removed' | 'cart:item_updated' | 'cart:coupon_applied' | 'cart:coupon_removed' | 'cart:customer_updated' | 'cart:shipping_selected' | 'checkout:processed' | 'order:fetched';
4
4
  interface BaseSuccessEvent<T extends WooCommerceEventType, D> {
@@ -55,33 +55,33 @@ declare const createQueryKeys: (prefix?: string[]) => {
55
55
  page: number;
56
56
  per_page: number;
57
57
  type?: "simple" | "grouped" | "external" | "variable" | "variation" | undefined;
58
- status?: "pending" | "any" | "draft" | "private" | "publish" | undefined;
58
+ status?: "publish" | "draft" | "pending" | "private" | "any" | undefined;
59
+ order?: "asc" | "desc" | undefined;
60
+ orderby?: "date" | "id" | "slug" | "include" | "title" | "popularity" | "rating" | "menu_order" | "price" | "date_modified" | undefined;
61
+ slug?: string | undefined;
62
+ parent?: number[] | undefined;
59
63
  search?: string | undefined;
60
64
  exclude?: number[] | undefined;
61
65
  include?: number[] | undefined;
62
- slug?: string | undefined;
63
- rating?: number[] | undefined;
64
- order?: "asc" | "desc" | undefined;
65
- orderby?: "include" | "date" | "id" | "title" | "slug" | "popularity" | "rating" | "menu_order" | "price" | "date_modified" | undefined;
66
- featured?: boolean | undefined;
67
- category?: string | undefined;
68
- tag?: string | undefined;
69
- stock_status?: ("instock" | "outofstock" | "onbackorder")[] | undefined;
70
- on_sale?: boolean | undefined;
71
- min_price?: string | undefined;
72
- max_price?: string | undefined;
73
66
  after?: string | undefined;
74
67
  before?: string | undefined;
68
+ rating?: number[] | undefined;
75
69
  modified_after?: string | undefined;
76
70
  modified_before?: string | undefined;
71
+ featured?: boolean | undefined;
77
72
  catalog_visibility?: "search" | "any" | "visible" | "catalog" | "hidden" | undefined;
73
+ stock_status?: ("instock" | "outofstock" | "onbackorder")[] | undefined;
78
74
  attributes?: {
79
75
  attribute: string;
80
76
  slug?: string[] | undefined;
81
77
  term_id?: number[] | undefined;
82
78
  operator?: "in" | "not_in" | "and" | undefined;
83
79
  }[] | undefined;
84
- parent?: number[] | undefined;
80
+ on_sale?: boolean | undefined;
81
+ category?: string | undefined;
82
+ tag?: string | undefined;
83
+ min_price?: string | undefined;
84
+ max_price?: string | undefined;
85
85
  parent_exclude?: number[] | undefined;
86
86
  category_operator?: "in" | "not_in" | "and" | undefined;
87
87
  tag_operator?: "in" | "not_in" | "and" | undefined;
@@ -1,4 +1,4 @@
1
- import { Cart, WooCommerceApiError, CartItem, Checkout, StoreApiOrder, ProductParams } from '@atomic-solutions/woocommerce-utils';
1
+ import { Cart, WooCommerceApiError, CartItem, Checkout, StoreApiOrder, ProductParams } from '@atomic-solutions/woocommerce-api-client';
2
2
 
3
3
  type WooCommerceEventType = 'cart:item_added' | 'cart:item_removed' | 'cart:item_updated' | 'cart:coupon_applied' | 'cart:coupon_removed' | 'cart:customer_updated' | 'cart:shipping_selected' | 'checkout:processed' | 'order:fetched';
4
4
  interface BaseSuccessEvent<T extends WooCommerceEventType, D> {
@@ -55,33 +55,33 @@ declare const createQueryKeys: (prefix?: string[]) => {
55
55
  page: number;
56
56
  per_page: number;
57
57
  type?: "simple" | "grouped" | "external" | "variable" | "variation" | undefined;
58
- status?: "pending" | "any" | "draft" | "private" | "publish" | undefined;
58
+ status?: "publish" | "draft" | "pending" | "private" | "any" | undefined;
59
+ order?: "asc" | "desc" | undefined;
60
+ orderby?: "date" | "id" | "slug" | "include" | "title" | "popularity" | "rating" | "menu_order" | "price" | "date_modified" | undefined;
61
+ slug?: string | undefined;
62
+ parent?: number[] | undefined;
59
63
  search?: string | undefined;
60
64
  exclude?: number[] | undefined;
61
65
  include?: number[] | undefined;
62
- slug?: string | undefined;
63
- rating?: number[] | undefined;
64
- order?: "asc" | "desc" | undefined;
65
- orderby?: "include" | "date" | "id" | "title" | "slug" | "popularity" | "rating" | "menu_order" | "price" | "date_modified" | undefined;
66
- featured?: boolean | undefined;
67
- category?: string | undefined;
68
- tag?: string | undefined;
69
- stock_status?: ("instock" | "outofstock" | "onbackorder")[] | undefined;
70
- on_sale?: boolean | undefined;
71
- min_price?: string | undefined;
72
- max_price?: string | undefined;
73
66
  after?: string | undefined;
74
67
  before?: string | undefined;
68
+ rating?: number[] | undefined;
75
69
  modified_after?: string | undefined;
76
70
  modified_before?: string | undefined;
71
+ featured?: boolean | undefined;
77
72
  catalog_visibility?: "search" | "any" | "visible" | "catalog" | "hidden" | undefined;
73
+ stock_status?: ("instock" | "outofstock" | "onbackorder")[] | undefined;
78
74
  attributes?: {
79
75
  attribute: string;
80
76
  slug?: string[] | undefined;
81
77
  term_id?: number[] | undefined;
82
78
  operator?: "in" | "not_in" | "and" | undefined;
83
79
  }[] | undefined;
84
- parent?: number[] | undefined;
80
+ on_sale?: boolean | undefined;
81
+ category?: string | undefined;
82
+ tag?: string | undefined;
83
+ min_price?: string | undefined;
84
+ max_price?: string | undefined;
85
85
  parent_exclude?: number[] | undefined;
86
86
  category_operator?: "in" | "not_in" | "and" | undefined;
87
87
  tag_operator?: "in" | "not_in" | "and" | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomic-solutions/woocommerce-react",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "React Query hooks and provider for WooCommerce Store API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",