@simpleapps-com/augur-server 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/environment.ts","../src/cache/redis-client.ts","../src/sdk-call.ts","../src/server-query-client.ts"],"sourcesContent":["/**\n * Environment detection that works across server, client, and containers.\n *\n * Priority:\n * 1. DEPLOYMENT_ENV (\"dev\" → staging, \"live\" → production)\n * 2. Server-side NODE_ENV fallback\n * 3. Client-side hostname detection\n */\nfunction getEnvironment(): \"development\" | \"staging\" | \"production\" {\n const deploymentEnv = process.env.DEPLOYMENT_ENV;\n if (deploymentEnv === \"dev\") return \"staging\";\n if (deploymentEnv === \"live\") return \"production\";\n\n if (typeof window === \"undefined\") {\n if (process.env.NODE_ENV === \"development\") return \"development\";\n return \"production\";\n }\n\n const host = window.location.hostname;\n if (host.includes(\"localhost\") || host.includes(\"127.0.0.1\"))\n return \"development\";\n if (host.includes(\"agr-hosting.dev\")) return \"staging\";\n return \"production\";\n}\n\nexport const env = getEnvironment();\nexport const isDev = env === \"development\";\nexport const isStaging = env === \"staging\";\nexport const isProduction = env === \"production\";\n","import type Redis from \"ioredis\";\nimport { isDev, isStaging } from \"../environment\";\n\nconst CIRCUIT_BREAKER_THRESHOLD = 5;\nconst CIRCUIT_BREAKER_RESET_MS = 60_000;\n\ninterface RedisGlobalState {\n client: Redis | null;\n consecutiveFailures: number;\n circuitOpenUntil: number;\n}\n\nconst g = globalThis as unknown as { __redisState?: RedisGlobalState };\nif (!g.__redisState) {\n g.__redisState = {\n client: null,\n consecutiveFailures: 0,\n circuitOpenUntil: 0,\n };\n}\nconst state = g.__redisState;\n\nconst debugEnabled = isDev || isStaging;\n\nfunction log(...args: unknown[]) {\n if (debugEnabled) {\n console.log(\"[Redis]\", ...args);\n }\n}\n\nfunction isCircuitOpen(): boolean {\n if (state.circuitOpenUntil === 0) return false;\n if (Date.now() >= state.circuitOpenUntil) {\n state.circuitOpenUntil = 0;\n state.consecutiveFailures = 0;\n log(\"Circuit breaker reset -- retrying Redis\");\n return false;\n }\n return true;\n}\n\nfunction recordFailure() {\n state.consecutiveFailures++;\n if (state.consecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD) {\n state.circuitOpenUntil = Date.now() + CIRCUIT_BREAKER_RESET_MS;\n log(\n `Circuit breaker OPEN -- skipping Redis for ${CIRCUIT_BREAKER_RESET_MS / 1000}s`,\n );\n }\n}\n\nfunction recordSuccess() {\n state.consecutiveFailures = 0;\n}\n\nfunction getRedisUrl(): string | undefined {\n const containerRedis = process.env.REDIS_SERVERS;\n if (containerRedis) return `redis://${containerRedis}`;\n\n if (isDev) return process.env.REDIS_URL_DEV;\n if (isStaging) return process.env.REDIS_URL_STAGING;\n return process.env.REDIS_URL_PROD;\n}\n\nasync function getClient(): Promise<Redis | null> {\n if (state.client) return state.client;\n\n const url = getRedisUrl();\n if (!url) {\n log(\"No REDIS_URL -- cache disabled\");\n return null;\n }\n\n try {\n // Dynamic import so the built ESM output doesn't use esbuild's __require\n // shim, which breaks in pure ESM environments (Next.js 16 + Turbopack).\n // ioredis is CJS-only; Node wraps its module.exports as { default }.\n const { default: IORedis } = await import(\"ioredis\");\n\n state.client = new IORedis(url, {\n maxRetriesPerRequest: 1,\n connectTimeout: 3000,\n lazyConnect: true,\n enableOfflineQueue: false,\n });\n\n state.client.on(\"error\", (err: Error) => {\n log(\"Connection error:\", err.message);\n recordFailure();\n });\n\n state.client.on(\"connect\", () => log(\"Connected\"));\n\n state.client.connect().catch(() => {\n /* handled by error event */\n });\n\n return state.client;\n } catch {\n log(\"Failed to create client (ioredis not installed?)\");\n return null;\n }\n}\n\nexport async function cacheGet(key: string): Promise<string | null> {\n if (isCircuitOpen()) return null;\n\n const client = await getClient();\n if (!client) return null;\n\n try {\n const value = await client.get(key);\n recordSuccess();\n return value;\n } catch {\n recordFailure();\n return null;\n }\n}\n\nexport async function cacheSet(\n key: string,\n value: string,\n ttlSeconds: number,\n): Promise<void> {\n if (isCircuitOpen()) return;\n\n const client = await getClient();\n if (!client) return;\n\n try {\n await client.setex(key, ttlSeconds, value);\n recordSuccess();\n } catch {\n recordFailure();\n }\n}\n\nexport function getCircuitState(): \"closed\" | \"open\" {\n return isCircuitOpen() ? \"open\" : \"closed\";\n}\n\nexport function isRedisConnected(): boolean {\n return state.client?.status === \"ready\";\n}\n","/**\n * Calls an Augur SDK method, forwarding all arguments with full type safety.\n *\n * With augur-api >= 0.9.6, SDK methods properly declare their `CacheParams`\n * option (including `edgeCache`), so this wrapper preserves both parameter\n * and return-type inference end-to-end.\n *\n * @example\n * ```ts\n * const result = await sdkCall(\n * augurServices.items.invMast.get,\n * invMastUid,\n * { edgeCache: 4 },\n * );\n * ```\n */\nexport async function sdkCall<TArgs extends unknown[], TResult>(\n method: (...args: TArgs) => Promise<TResult>,\n ...args: TArgs\n): Promise<TResult> {\n return method(...args);\n}\n","import { cache } from \"react\";\nimport { QueryClient } from \"@tanstack/react-query\";\nimport { CACHE_CONFIG } from \"@simpleapps-com/augur-utils\";\n\n/**\n * Creates a server-side query client optimised for prefetching.\n *\n * - No persistence (server-only)\n * - Longer cache times for prefetched data\n * - No retries (fail fast on server)\n * - No refetching (server renders are one-shot)\n */\nexport function createServerQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: CACHE_CONFIG.STATIC.staleTime,\n gcTime: CACHE_CONFIG.STATIC.staleTime,\n retry: 0,\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n },\n },\n });\n}\n\n/**\n * Returns a per-request singleton QueryClient for React Server Components.\n *\n * React's `cache()` deduplicates calls within a single server request,\n * so each request gets its own QueryClient while avoiding the cross-request\n * state leakage that a module-level singleton would cause.\n */\nexport const getServerQueryClient = cache(\n (): QueryClient => createServerQueryClient(),\n);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/environment.ts","../src/cache/redis-client.ts","../src/sdk-call.ts","../src/cache/with-cache.ts","../src/actions/pricing.ts","../src/actions/items.ts","../src/actions/commerce.ts","../src/actions/orders.ts","../src/actions/search.ts","../src/actions/shipping.ts","../src/actions/joomla.ts"],"sourcesContent":["/**\n * Environment detection that works across server, client, and containers.\n *\n * Priority:\n * 1. DEPLOYMENT_ENV (\"dev\" → staging, \"live\" → production)\n * 2. Server-side NODE_ENV fallback\n * 3. Client-side hostname detection\n */\nfunction getEnvironment(): \"development\" | \"staging\" | \"production\" {\n const deploymentEnv = process.env.DEPLOYMENT_ENV;\n if (deploymentEnv === \"dev\") return \"staging\";\n if (deploymentEnv === \"live\") return \"production\";\n\n if (typeof window === \"undefined\") {\n if (process.env.NODE_ENV === \"development\") return \"development\";\n return \"production\";\n }\n\n const host = window.location.hostname;\n if (host.includes(\"localhost\") || host.includes(\"127.0.0.1\"))\n return \"development\";\n if (host.includes(\"agr-hosting.dev\")) return \"staging\";\n return \"production\";\n}\n\nexport const env = getEnvironment();\nexport const isDev = env === \"development\";\nexport const isStaging = env === \"staging\";\nexport const isProduction = env === \"production\";\n","import type Redis from \"ioredis\";\nimport { isDev, isStaging } from \"../environment\";\n\nconst CIRCUIT_BREAKER_THRESHOLD = 5;\nconst CIRCUIT_BREAKER_RESET_MS = 60_000;\n\ninterface RedisGlobalState {\n client: Redis | null;\n consecutiveFailures: number;\n circuitOpenUntil: number;\n}\n\nconst g = globalThis as unknown as { __redisState?: RedisGlobalState };\nif (!g.__redisState) {\n g.__redisState = {\n client: null,\n consecutiveFailures: 0,\n circuitOpenUntil: 0,\n };\n}\nconst state = g.__redisState;\n\nconst debugEnabled = isDev || isStaging;\n\nfunction log(...args: unknown[]) {\n if (debugEnabled) {\n console.log(\"[Redis]\", ...args);\n }\n}\n\nfunction isCircuitOpen(): boolean {\n if (state.circuitOpenUntil === 0) return false;\n if (Date.now() >= state.circuitOpenUntil) {\n state.circuitOpenUntil = 0;\n state.consecutiveFailures = 0;\n log(\"Circuit breaker reset -- retrying Redis\");\n return false;\n }\n return true;\n}\n\nfunction recordFailure() {\n state.consecutiveFailures++;\n if (state.consecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD) {\n state.circuitOpenUntil = Date.now() + CIRCUIT_BREAKER_RESET_MS;\n log(\n `Circuit breaker OPEN -- skipping Redis for ${CIRCUIT_BREAKER_RESET_MS / 1000}s`,\n );\n }\n}\n\nfunction recordSuccess() {\n state.consecutiveFailures = 0;\n}\n\nfunction getRedisUrl(): string | undefined {\n const containerRedis = process.env.REDIS_SERVERS;\n if (containerRedis) return `redis://${containerRedis}`;\n\n if (isDev) return process.env.REDIS_URL_DEV;\n if (isStaging) return process.env.REDIS_URL_STAGING;\n return process.env.REDIS_URL_PROD;\n}\n\nasync function getClient(): Promise<Redis | null> {\n if (state.client) return state.client;\n\n const url = getRedisUrl();\n if (!url) {\n log(\"No REDIS_URL -- cache disabled\");\n return null;\n }\n\n try {\n // Dynamic import so the built ESM output doesn't use esbuild's __require\n // shim, which breaks in pure ESM environments (Next.js 16 + Turbopack).\n // ioredis is CJS-only; Node wraps its module.exports as { default }.\n const { default: IORedis } = await import(\"ioredis\");\n\n state.client = new IORedis(url, {\n maxRetriesPerRequest: 1,\n connectTimeout: 3000,\n lazyConnect: true,\n enableOfflineQueue: false,\n });\n\n state.client.on(\"error\", (err: Error) => {\n log(\"Connection error:\", err.message);\n recordFailure();\n });\n\n state.client.on(\"connect\", () => log(\"Connected\"));\n\n state.client.connect().catch(() => {\n /* handled by error event */\n });\n\n return state.client;\n } catch {\n log(\"Failed to create client (ioredis not installed?)\");\n return null;\n }\n}\n\nexport async function cacheGet(key: string): Promise<string | null> {\n if (isCircuitOpen()) return null;\n\n const client = await getClient();\n if (!client) return null;\n\n try {\n const value = await client.get(key);\n recordSuccess();\n return value;\n } catch {\n recordFailure();\n return null;\n }\n}\n\nexport async function cacheSet(\n key: string,\n value: string,\n ttlSeconds: number,\n): Promise<void> {\n if (isCircuitOpen()) return;\n\n const client = await getClient();\n if (!client) return;\n\n try {\n await client.setex(key, ttlSeconds, value);\n recordSuccess();\n } catch {\n recordFailure();\n }\n}\n\nexport function getCircuitState(): \"closed\" | \"open\" {\n return isCircuitOpen() ? \"open\" : \"closed\";\n}\n\nexport function isRedisConnected(): boolean {\n return state.client?.status === \"ready\";\n}\n","/**\n * Calls an Augur SDK method, forwarding all arguments with full type safety.\n *\n * With augur-api >= 0.9.6, SDK methods properly declare their `CacheParams`\n * option (including `edgeCache`), so this wrapper preserves both parameter\n * and return-type inference end-to-end.\n *\n * @example\n * ```ts\n * const result = await sdkCall(\n * augurServices.items.invMast.get,\n * invMastUid,\n * { edgeCache: 4 },\n * );\n * ```\n */\nexport async function sdkCall<TArgs extends unknown[], TResult>(\n method: (...args: TArgs) => Promise<TResult>,\n ...args: TArgs\n): Promise<TResult> {\n return method(...args);\n}\n","import { cacheGet, cacheSet } from \"./redis-client\";\n\n/**\n * FNV-1a 32-bit hash. Same implementation as augur-hooks/cache-helper\n * so cache keys are identical across client and server.\n */\nfunction fnv1a(str: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return (h >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * JSON.stringify with sorted object keys for deterministic cache keys.\n * Same implementation as augur-hooks/stable-stringify.\n */\nfunction stableStringify(value: unknown): string {\n if (value === null || value === undefined) return JSON.stringify(value);\n if (typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const entries = keys.map(\n (key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`,\n );\n return `{${entries.join(\",\")}}`;\n}\n\n/**\n * Server-side cache wrapper using augur-server's Redis client.\n *\n * Uses the same cache key format as augur-hooks' `withCache`:\n * `${prefix}sdk:${methodPath}:${fnv1a(stableStringify(keyArgs))}`\n *\n * This means server-side cached data can be read by client-side hooks\n * (and vice versa) when using the same prefix and method path.\n *\n * @param prefix Cache key prefix (e.g. \"ampro:\"). Empty string if none.\n * @param redisTtl Redis TTL in seconds. 0 or undefined = skip caching.\n * @param methodPath Dot-separated SDK method path (e.g. \"pricing.priceEngine.get\").\n * @param fn The async function to cache.\n * @param keyArgs Values to hash for the cache key.\n */\nexport async function withServerCache<T>(\n prefix: string,\n redisTtl: number | undefined,\n methodPath: string,\n fn: () => Promise<T>,\n ...keyArgs: unknown[]\n): Promise<T> {\n if (!redisTtl) return fn();\n\n const key = `${prefix}sdk:${methodPath}:${fnv1a(stableStringify(keyArgs))}`;\n\n try {\n const cached = await cacheGet(key);\n if (cached != null) return JSON.parse(cached) as T;\n } catch {\n /* Redis read error — fall through to SDK call */\n }\n\n const result = await fn();\n\n try {\n cacheSet(key, JSON.stringify(result), redisTtl).catch(() => {});\n /* v8 ignore next 3 -- defensive guard for non-serializable data */\n } catch {\n /* Non-serializable or write error — skip caching */\n }\n\n return result;\n}\n","import type { TPriceData, TTax, TTaxItem } from \"@simpleapps-com/augur-utils\";\nimport { withServerCache } from \"../cache/with-cache\";\n\n/**\n * The subset of augur-api used by pricing actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface PricingApiClient {\n pricing: {\n priceEngine: {\n get: (params: Record<string, unknown>) => Promise<{ data: TPriceData }>;\n };\n taxEngine: {\n create: (params: Record<string, unknown>) => Promise<{ data: TTax }>;\n };\n };\n}\n\nexport interface PricingActionsConfig {\n /** Default customer ID when none is provided by the caller. */\n defaultCustomerId?: string | number;\n /** Cache key prefix (e.g. \"ampro:\"). Default: \"\". */\n cachePrefix?: string;\n /** CDN edge cache value passed to SDK. Default: 2 (hours). */\n edgeCache?: number;\n /** Redis TTL for price lookups in seconds. Default: 3600 (1 hour). */\n redisTtl?: number;\n /** Redis TTL for tax lookups in seconds. Default: 1800 (30 min). */\n taxRedisTtl?: number;\n}\n\nexport interface PricingActions {\n getItemPrice: (\n itemId: string,\n customerId?: string | number,\n quantity?: number,\n ) => Promise<TPriceData>;\n\n batchGetItemPrices: (\n itemIds: string[],\n customerId?: string | number,\n quantity?: number,\n ) => Promise<Record<string, TPriceData>>;\n\n getTaxEstimate: (\n customerId: string | number,\n postalCode: string,\n items: TTaxItem[],\n ) => Promise<TTax>;\n}\n\nfunction resolveCustomerId(\n explicit: string | number | undefined,\n fallback: string | number | undefined,\n): number {\n const raw = explicit ?? fallback;\n const num = Number(raw);\n return num > 0 ? num : 0;\n}\n\n/**\n * Creates server-side pricing actions with Redis caching and edge cache support.\n *\n * Uses `withServerCache` which produces cache keys compatible with augur-hooks'\n * `withCache`, so server-prefetched data is shared with client-side hooks.\n *\n * @example\n * ```ts\n * // lib/pricing-actions.ts\n * import { createPricingActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const pricingActions = createPricingActions(getAugurClient(), {\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * cachePrefix: \"ampro:\",\n * });\n *\n * // In a server component:\n * const price = await pricingActions.getItemPrice(\"ITEM-1\");\n * const prices = await pricingActions.batchGetItemPrices([\"ITEM-1\", \"ITEM-2\"]);\n * ```\n */\nexport function createPricingActions(\n api: PricingApiClient,\n config: PricingActionsConfig = {},\n): PricingActions {\n const {\n defaultCustomerId,\n cachePrefix = \"\",\n edgeCache = 2,\n redisTtl = 3600,\n taxRedisTtl = 1800,\n } = config;\n\n async function getItemPrice(\n itemId: string,\n customerId?: string | number,\n quantity = 1,\n ): Promise<TPriceData> {\n const custId = resolveCustomerId(customerId, defaultCustomerId);\n const params = { customerId: custId, itemId, quantity, edgeCache };\n\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"pricing.priceEngine.get\",\n async () => {\n const response = await api.pricing.priceEngine.get(params);\n return response.data;\n },\n params,\n );\n }\n\n async function batchGetItemPrices(\n itemIds: string[],\n customerId?: string | number,\n quantity = 1,\n ): Promise<Record<string, TPriceData>> {\n const results = await Promise.all(\n itemIds.map((id) => getItemPrice(id, customerId, quantity)\n .then((data) => [id, data] as const)\n .catch(() => [id, null] as const)),\n );\n\n const out: Record<string, TPriceData> = {};\n for (const [id, data] of results) {\n if (data) out[id] = data;\n }\n return out;\n }\n\n async function getTaxEstimate(\n customerId: string | number,\n postalCode: string,\n items: TTaxItem[],\n ): Promise<TTax> {\n const custId = resolveCustomerId(customerId, defaultCustomerId);\n const params = { customerId: custId, postalCode, items };\n\n return withServerCache(\n cachePrefix,\n taxRedisTtl,\n \"pricing.taxEngine.create\",\n async () => {\n const response = await api.pricing.taxEngine.create(params);\n return response.data;\n },\n params,\n );\n }\n\n return { getItemPrice, batchGetItemPrices, getTaxEstimate };\n}\n","import type {\n TAttribute,\n TCategory,\n TInvMast,\n TInvMastDoc,\n TItemAccessory,\n TStock,\n TStockData,\n} from \"@simpleapps-com/augur-utils\";\nimport { withServerCache } from \"../cache/with-cache\";\n\n/**\n * The subset of augur-api used by item actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface ItemsApiClient {\n items: {\n categories: {\n get: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: TCategory }>;\n lookup: {\n get: (params: Record<string, unknown>) => Promise<{ data: unknown }>;\n };\n items: {\n list: (params: Record<string, unknown>) => Promise<{ data: unknown }>;\n };\n attributes: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: { attributes: TAttribute[] } }>;\n };\n };\n invMast: {\n get: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: TInvMast }>;\n doc: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: TInvMastDoc }>;\n };\n stock: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: TStock }>;\n };\n faq: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: unknown[] }>;\n };\n invSub: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: unknown[] }>;\n };\n invAccessory: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: TItemAccessory[] }>;\n };\n similar: {\n list: (\n uid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: unknown[] }>;\n };\n };\n };\n}\n\nexport interface ItemActionsConfig {\n /** Cache key prefix (e.g. \"ampro:\"). Default: \"\". */\n cachePrefix?: string;\n /** CDN edge cache value for most calls. Default: 1 (hour). */\n edgeCache?: number;\n /** CDN edge cache for rarely-changing data like FAQs. Default: 8 (hours). */\n longEdgeCache?: number;\n /** Redis TTL for most calls in seconds. Default: 3600 (1 hour). */\n redisTtl?: number;\n /** Redis TTL for rarely-changing data in seconds. Default: 28800 (8 hours). */\n longRedisTtl?: number;\n}\n\nexport interface ItemActions {\n // Category operations\n itemCategoryLookup: (path: string) => Promise<unknown>;\n getItemCategory: (\n uid: number,\n options?: Record<string, unknown>,\n ) => Promise<TCategory>;\n getCategoryItems: (\n uid: number,\n filters: Record<string, unknown>,\n ) => Promise<unknown>;\n getItemAttributes: (categoryUid: number) => Promise<TAttribute[]>;\n\n // Inventory operations\n getInvMast: (uid: number) => Promise<TInvMast>;\n getInvMastDoc: (params: {\n invMastUid?: number;\n itemId?: string;\n }) => Promise<TInvMastDoc>;\n getStock: (invMastUid: number) => Promise<TStockData[]>;\n getStockCompanySummary: (\n invMastUid: number,\n ) => Promise<Record<string, number>>;\n\n // Item extras\n getItemFaqs: (invMastUid: number) => Promise<unknown[]>;\n getItemSubstitutes: (invMastUid: number) => Promise<unknown[]>;\n getItemAccessories: (invMastUid: number) => Promise<TItemAccessory[]>;\n getSimilarItems: (invMastUid: number) => Promise<unknown[]>;\n\n // Batch operations\n batchGetInvMastDocs: (\n params: { invMastUid?: number; itemId?: string }[],\n ) => Promise<Record<string, TInvMastDoc>>;\n batchGetStockData: (\n invMastUids: number[],\n ) => Promise<Record<number, TStockData[]>>;\n}\n\n/**\n * Creates server-side item actions with Redis caching and edge cache support.\n *\n * Uses `withServerCache` which produces cache keys compatible with augur-hooks'\n * `withCache`, so server-prefetched data is shared with client-side hooks.\n *\n * @example\n * ```ts\n * // lib/item-actions.ts\n * import { createItemActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const itemActions = createItemActions(getAugurClient(), {\n * cachePrefix: \"ampro:\",\n * });\n *\n * // In a server component:\n * const category = await itemActions.getItemCategory(123);\n * const doc = await itemActions.getInvMastDoc({ itemId: \"ITEM-1\" });\n * ```\n */\nexport function createItemActions(\n api: ItemsApiClient,\n config: ItemActionsConfig = {},\n): ItemActions {\n const {\n cachePrefix = \"\",\n edgeCache = 1,\n longEdgeCache = 8,\n redisTtl = 3600,\n longRedisTtl = 28800,\n } = config;\n\n // ---------------------------------------------------------------------------\n // Category operations\n // ---------------------------------------------------------------------------\n\n async function itemCategoryLookup(path: string): Promise<unknown> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.categories.lookup.get\",\n async () => {\n const response = await api.items.categories.lookup.get({\n path,\n edgeCache,\n });\n return response.data;\n },\n path,\n );\n }\n\n async function getItemCategory(\n uid: number,\n options?: Record<string, unknown>,\n ): Promise<TCategory> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.categories.get\",\n async () => {\n const response = await api.items.categories.get(uid, {\n ...options,\n edgeCache,\n });\n return response.data;\n },\n uid,\n options,\n );\n }\n\n async function getCategoryItems(\n uid: number,\n filters: Record<string, unknown>,\n ): Promise<unknown> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.categories.items.list\",\n async () => {\n const response = await api.items.categories.items.list({\n ...filters,\n itemCategoryUid: uid,\n edgeCache,\n });\n return response.data;\n },\n uid,\n filters,\n );\n }\n\n async function getItemAttributes(\n categoryUid: number,\n ): Promise<TAttribute[]> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.categories.attributes.list\",\n async () => {\n const response = await api.items.categories.attributes.list(\n categoryUid,\n { edgeCache },\n );\n return response.data.attributes;\n },\n categoryUid,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Inventory operations\n // ---------------------------------------------------------------------------\n\n async function getInvMast(uid: number): Promise<TInvMast> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.invMast.get\",\n async () => {\n const response = await api.items.invMast.get(uid, { edgeCache: 4 });\n return response.data;\n },\n uid,\n );\n }\n\n async function getInvMastDoc(params: {\n invMastUid?: number;\n itemId?: string;\n }): Promise<TInvMastDoc> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.invMast.doc.list\",\n async () => {\n const response = await api.items.invMast.doc.list(\n params.invMastUid ?? 0,\n { itemId: params.itemId, edgeCache: 4 },\n );\n return response.data;\n },\n params.invMastUid,\n params.itemId,\n );\n }\n\n async function getStock(invMastUid: number): Promise<TStockData[]> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.invMast.stock.list\",\n async () => {\n const response = await api.items.invMast.stock.list(invMastUid, {\n edgeCache,\n });\n return response.data?.stockData;\n },\n invMastUid,\n );\n }\n\n async function getStockCompanySummary(\n invMastUid: number,\n ): Promise<Record<string, number>> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.invMast.stock.list.companySummary\",\n async () => {\n const response = await api.items.invMast.stock.list(invMastUid, {\n edgeCache,\n });\n return response.data?.companySummary;\n },\n invMastUid,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Item extras\n // ---------------------------------------------------------------------------\n\n async function getItemFaqs(invMastUid: number): Promise<unknown[]> {\n return withServerCache(\n cachePrefix,\n longRedisTtl,\n \"items.invMast.faq.list\",\n async () => {\n const response = await api.items.invMast.faq.list(invMastUid, {\n edgeCache: longEdgeCache,\n });\n return response.data;\n },\n invMastUid,\n );\n }\n\n async function getItemSubstitutes(invMastUid: number): Promise<unknown[]> {\n return withServerCache(\n cachePrefix,\n longRedisTtl,\n \"items.invMast.invSub.list\",\n async () => {\n const response = await api.items.invMast.invSub.list(invMastUid, {\n edgeCache: longEdgeCache,\n });\n return response.data;\n },\n invMastUid,\n );\n }\n\n async function getItemAccessories(\n invMastUid: number,\n ): Promise<TItemAccessory[]> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"items.invMast.invAccessory.list\",\n async () => {\n const response = await api.items.invMast.invAccessory.list(\n invMastUid,\n { edgeCache },\n );\n return response.data;\n },\n invMastUid,\n );\n }\n\n async function getSimilarItems(invMastUid: number): Promise<unknown[]> {\n return withServerCache(\n cachePrefix,\n longRedisTtl,\n \"items.invMast.similar.list\",\n async () => {\n const response = await api.items.invMast.similar.list(invMastUid, {\n edgeCache: longEdgeCache,\n });\n return response.data;\n },\n invMastUid,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Batch operations\n // ---------------------------------------------------------------------------\n\n async function batchGetInvMastDocs(\n params: { invMastUid?: number; itemId?: string }[],\n ): Promise<Record<string, TInvMastDoc>> {\n const results = await Promise.all(\n params.map((p) =>\n getInvMastDoc(p)\n .then((data) => [p.itemId ?? String(p.invMastUid), data] as const)\n .catch(() => [p.itemId ?? String(p.invMastUid), undefined] as const),\n ),\n );\n\n const out: Record<string, TInvMastDoc> = {};\n for (const [key, data] of results) {\n if (data) out[key] = data;\n }\n return out;\n }\n\n async function batchGetStockData(\n invMastUids: number[],\n ): Promise<Record<number, TStockData[]>> {\n const results = await Promise.all(\n invMastUids.map((uid) =>\n getStock(uid)\n .then((data) => [uid, data] as const)\n .catch(() => [uid, undefined] as const),\n ),\n );\n\n const out: Record<number, TStockData[]> = {};\n for (const [uid, data] of results) {\n if (data) out[uid] = data;\n }\n return out;\n }\n\n return {\n itemCategoryLookup,\n getItemCategory,\n getCategoryItems,\n getItemAttributes,\n getInvMast,\n getInvMastDoc,\n getStock,\n getStockCompanySummary,\n getItemFaqs,\n getItemSubstitutes,\n getItemAccessories,\n getSimilarItems,\n batchGetInvMastDocs,\n batchGetStockData,\n };\n}\n","import type { TCartLine, TCartLookUp } from \"@simpleapps-com/augur-utils\";\n\n/**\n * The subset of augur-api used by commerce actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface CommerceApiClient {\n commerce: {\n cartHdr: {\n lookup: {\n get: (\n params: Record<string, unknown>,\n ) => Promise<{ data: TCartLookUp }>;\n };\n alsoBought: {\n get: (\n cartHdrUid: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: unknown[] }>;\n };\n };\n cartLine: {\n get: (cartHdrUid: number) => Promise<{ data: TCartLine[] }>;\n add: {\n create: (\n cartHdrUid: number,\n params: Record<string, unknown>,\n ) => Promise<{ data: unknown }>;\n };\n update: {\n create: (\n cartHdrUid: number,\n params: Record<string, unknown>,\n ) => Promise<{ data: unknown }>;\n };\n delete: (cartHdrUid: number) => Promise<{ data: unknown }>;\n };\n checkout: {\n create: (params: Record<string, unknown>) => Promise<{ data: unknown }>;\n };\n };\n}\n\nexport interface CommerceActionsConfig {\n defaultContactId?: string | number;\n defaultCustomerId?: string | number;\n /** Optional UOM conversion function. E.g. (uom) => uom === \"EA\" ? \"EACH\" : uom */\n convertUnitOfMeasure?: (uom: string) => string;\n}\n\nexport interface CommerceActions {\n cartHdrLookup: (params: {\n userId?: string | number;\n cartToken?: string;\n contactId?: string | number;\n customerId?: string | number;\n }) => Promise<TCartLookUp>;\n\n getCartLines: (cartHdrUid: number) => Promise<TCartLine[]>;\n\n addToCart: (\n cartHdrUid: number,\n items: {\n itemId: string;\n quantity: number;\n unitOfMeasure: string;\n }[],\n ) => Promise<unknown>;\n\n updateCartLines: (\n cartHdrUid: number,\n lines: {\n lineNo: number;\n quantity: number;\n unitOfMeasure: string;\n }[],\n ) => Promise<unknown>;\n\n deleteCartItems: (cartHdrUid: number) => Promise<void>;\n\n getCartAlsoBought: (cartHdrUid: number) => Promise<unknown[]>;\n\n checkoutOrder: (\n cartHdrUid: number,\n data: Record<string, unknown>,\n ) => Promise<unknown>;\n}\n\n/**\n * Creates server-side commerce actions for cart operations.\n *\n * Unlike pricing actions, commerce actions do NOT use caching because\n * cart operations are real-time and must always reflect current state.\n *\n * @example\n * ```ts\n * // lib/commerce-actions.ts\n * import { createCommerceActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const commerceActions = createCommerceActions(getAugurClient(), {\n * defaultContactId: process.env.NEXT_PUBLIC_DEFAULT_CONTACT_ID,\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * convertUnitOfMeasure: (uom) => uom === \"EA\" ? \"EACH\" : uom,\n * });\n *\n * // In a server action:\n * const cart = await commerceActions.cartHdrLookup({ userId: 123 });\n * const lines = await commerceActions.getCartLines(cart.cartHdrUid);\n * ```\n */\nexport function createCommerceActions(\n api: CommerceApiClient,\n config: CommerceActionsConfig = {},\n): CommerceActions {\n const { defaultContactId, defaultCustomerId, convertUnitOfMeasure } = config;\n\n async function cartHdrLookup(params: {\n userId?: string | number;\n cartToken?: string;\n contactId?: string | number;\n customerId?: string | number;\n }): Promise<TCartLookUp> {\n const lookupParams: Record<string, unknown> = { ...params };\n if (lookupParams.contactId == null && defaultContactId != null) {\n lookupParams.contactId = defaultContactId;\n }\n if (lookupParams.customerId == null && defaultCustomerId != null) {\n lookupParams.customerId = defaultCustomerId;\n }\n const response = await api.commerce.cartHdr.lookup.get(lookupParams);\n return response.data;\n }\n\n async function getCartLines(\n cartHdrUid: number,\n ): Promise<TCartLine[]> {\n const response = await api.commerce.cartLine.get(cartHdrUid);\n return response.data;\n }\n\n async function addToCart(\n cartHdrUid: number,\n items: { itemId: string; quantity: number; unitOfMeasure: string }[],\n ): Promise<unknown> {\n try {\n const mappedItems = items.map((item) => ({\n ...item,\n unitOfMeasure: convertUnitOfMeasure\n ? convertUnitOfMeasure(item.unitOfMeasure)\n : item.unitOfMeasure,\n }));\n const response = await api.commerce.cartLine.add.create(\n cartHdrUid,\n { items: mappedItems },\n );\n return response.data;\n } catch {\n return undefined;\n }\n }\n\n async function updateCartLines(\n cartHdrUid: number,\n lines: { lineNo: number; quantity: number; unitOfMeasure: string }[],\n ): Promise<unknown> {\n try {\n const mappedLines = lines.map((line) => ({\n ...line,\n unitOfMeasure: convertUnitOfMeasure\n ? convertUnitOfMeasure(line.unitOfMeasure)\n : line.unitOfMeasure,\n }));\n const response = await api.commerce.cartLine.update.create(\n cartHdrUid,\n { lines: mappedLines },\n );\n return response.data;\n } catch {\n return undefined;\n }\n }\n\n async function deleteCartItems(cartHdrUid: number): Promise<void> {\n try {\n await api.commerce.cartLine.delete(cartHdrUid);\n } catch {\n // fire and forget — returns void either way\n }\n }\n\n async function getCartAlsoBought(\n cartHdrUid: number,\n ): Promise<unknown[]> {\n const response = await api.commerce.cartHdr.alsoBought.get(cartHdrUid);\n return response.data;\n }\n\n async function checkoutOrder(\n cartHdrUid: number,\n data: Record<string, unknown>,\n ): Promise<unknown> {\n try {\n const response = await api.commerce.checkout.create({\n ...data,\n cartHdrUid,\n });\n return response.data;\n } catch {\n return undefined;\n }\n }\n\n return {\n cartHdrLookup,\n getCartLines,\n addToCart,\n updateCartLines,\n deleteCartItems,\n getCartAlsoBought,\n checkoutOrder,\n };\n}\n","import { withServerCache } from \"../cache/with-cache\";\n\n/**\n * The subset of augur-api used by order actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface OrderApiClient {\n orders: {\n oeHdr: {\n doc: {\n get: (params: Record<string, unknown>) => Promise<{ data: unknown }>;\n };\n };\n };\n}\n\nexport interface OrderActionsConfig {\n /** Cache key prefix (e.g. \"ampro:\"). Default: \"\". */\n cachePrefix?: string;\n /** CDN edge cache value passed to SDK. Default: 1 (hour). */\n edgeCache?: number;\n /** Redis TTL for order doc lookups in seconds. Default: 3600 (1 hour). */\n redisTtl?: number;\n}\n\nexport interface OrderActions {\n getOrderDoc: (\n orderNo: string,\n zipCode: string,\n ) => Promise<unknown>;\n}\n\n/**\n * Creates server-side order actions with Redis caching and edge cache support.\n *\n * Uses `withServerCache` which produces cache keys compatible with augur-hooks'\n * `withCache`, so server-prefetched data is shared with client-side hooks.\n *\n * @example\n * ```ts\n * // lib/order-actions.ts\n * import { createOrderActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const orderActions = createOrderActions(getAugurClient(), {\n * cachePrefix: \"ampro:\",\n * });\n *\n * // In a server component:\n * const doc = await orderActions.getOrderDoc(\"12345\", \"90210\");\n * ```\n */\nexport function createOrderActions(\n api: OrderApiClient,\n config: OrderActionsConfig = {},\n): OrderActions {\n const { cachePrefix = \"\", edgeCache = 1, redisTtl = 3600 } = config;\n\n async function getOrderDoc(\n orderNo: string,\n zipCode: string,\n ): Promise<unknown> {\n const params = { orderNo, zipCode, edgeCache };\n\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"orders.oeHdr.doc.get\",\n async () => {\n const response = await api.orders.oeHdr.doc.get(params);\n return response.data;\n },\n params,\n );\n }\n\n return { getOrderDoc };\n}\n","import type { TAttribute, TProductItem } from \"@simpleapps-com/augur-utils\";\nimport { withServerCache } from \"../cache/with-cache\";\n\n/**\n * The subset of augur-api used by search actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface SearchApiClient {\n openSearch: {\n itemSearch: {\n list: (\n params: Record<string, unknown>,\n ) => Promise<{ data: { items: TProductItem[]; totalResults: number } }>;\n attributes: {\n list: (\n params: Record<string, unknown>,\n ) => Promise<{ data: { attributes: TAttribute[] } }>;\n };\n };\n suggestions: {\n suggest: {\n list: (\n params: Record<string, unknown>,\n ) => Promise<{\n data: { data: unknown[]; total: number; totalResults: number };\n }>;\n };\n };\n };\n}\n\nexport interface SearchActionsConfig {\n /** Cache key prefix (e.g. \"ampro:\"). Default: \"\". */\n cachePrefix?: string;\n /** CDN edge cache value passed to SDK. Default: 1 (hour). */\n edgeCache?: number;\n /** Redis TTL for search lookups in seconds. Default: 3600 (1 hour). */\n redisTtl?: number;\n /** Default source fields for item search. Default: \"display_desc\". */\n defaultSourceFields?: string;\n}\n\n/** Paginated response for infinite scroll. */\nexport interface SearchPage {\n data: TProductItem[];\n total: number;\n nextCursor?: number;\n}\n\nexport interface SearchActions {\n getSearchAttributes: (q: string) => Promise<TAttribute[]>;\n\n getSearchSuggestions: (\n q: string,\n limit?: number,\n offset?: number,\n ) => Promise<{ data: unknown[]; total: number; totalResults: number }>;\n\n itemSearch: (\n filters: {\n q: string;\n limit: number;\n offset: number;\n sortBy?: string;\n filters?: [string, string][];\n },\n itemCategoryUid?: number | string,\n ) => Promise<{ items: TProductItem[]; totalResults: number }>;\n\n itemSearchInfinite: (\n filters: {\n q: string;\n limit: number;\n sortBy?: string;\n filters?: [string, string][];\n },\n itemCategoryUid?: number | string,\n pageParam?: number,\n ) => Promise<SearchPage>;\n}\n\n/**\n * Creates server-side search actions with Redis caching and edge cache support.\n *\n * Uses `withServerCache` which produces cache keys compatible with augur-hooks'\n * `withCache`, so server-prefetched data is shared with client-side hooks.\n *\n * @example\n * ```ts\n * // lib/search-actions.ts\n * import { createSearchActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const searchActions = createSearchActions(getAugurClient(), {\n * cachePrefix: \"ampro:\",\n * });\n *\n * // In a server component:\n * const attrs = await searchActions.getSearchAttributes(\"widget\");\n * const results = await searchActions.itemSearch({ q: \"widget\", limit: 20, offset: 0 });\n * ```\n */\nexport function createSearchActions(\n api: SearchApiClient,\n config: SearchActionsConfig = {},\n): SearchActions {\n const {\n cachePrefix = \"\",\n edgeCache = 1,\n redisTtl = 3600,\n defaultSourceFields = \"display_desc\",\n } = config;\n\n async function getSearchAttributes(q: string): Promise<TAttribute[]> {\n const params = { q, edgeCache };\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"openSearch.itemSearch.attributes.list\",\n async () => {\n const response =\n await api.openSearch.itemSearch.attributes.list(params);\n return response.data.attributes;\n },\n q,\n );\n }\n\n async function getSearchSuggestions(\n q: string,\n limit?: number,\n offset?: number,\n ): Promise<{ data: unknown[]; total: number; totalResults: number }> {\n const params: Record<string, unknown> = { q, edgeCache };\n if (limit !== undefined) params.size = limit;\n if (offset !== undefined) params.from = offset;\n\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"openSearch.suggestions.suggest.list\",\n async () => {\n const response =\n await api.openSearch.suggestions.suggest.list(params);\n return response.data;\n },\n q,\n );\n }\n\n async function itemSearch(\n filters: {\n q: string;\n limit: number;\n offset: number;\n sortBy?: string;\n filters?: [string, string][];\n },\n itemCategoryUid?: number | string,\n ): Promise<{ items: TProductItem[]; totalResults: number }> {\n const params: Record<string, unknown> = {\n q: filters.q,\n searchType: \"query\",\n size: filters.limit,\n from: filters.offset,\n sortBy: filters.sortBy,\n classId5List: itemCategoryUid\n ? String(itemCategoryUid)\n : undefined,\n filters: filters.filters?.length\n ? JSON.stringify(filters.filters)\n : undefined,\n sourceFieldsList: defaultSourceFields,\n edgeCache,\n };\n\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"openSearch.itemSearch.list\",\n async () => {\n const response = await api.openSearch.itemSearch.list(params);\n return response.data;\n },\n filters,\n itemCategoryUid,\n );\n }\n\n async function itemSearchInfinite(\n filters: {\n q: string;\n limit: number;\n sortBy?: string;\n filters?: [string, string][];\n },\n itemCategoryUid?: number | string,\n pageParam = 0,\n ): Promise<SearchPage> {\n const params: Record<string, unknown> = {\n q: filters.q,\n searchType: \"query\",\n size: filters.limit,\n from: pageParam,\n sortBy: filters.sortBy,\n classId5List: itemCategoryUid\n ? String(itemCategoryUid)\n : undefined,\n filters: filters.filters?.length\n ? JSON.stringify(filters.filters)\n : undefined,\n sourceFieldsList: defaultSourceFields,\n edgeCache,\n };\n\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"openSearch.itemSearch.list\",\n async () => {\n const response = await api.openSearch.itemSearch.list(params);\n const { items, totalResults } = response.data;\n const nextOffset = pageParam + filters.limit;\n return {\n data: items,\n total: totalResults,\n nextCursor:\n nextOffset < totalResults ? nextOffset : undefined,\n };\n },\n filters,\n itemCategoryUid,\n pageParam,\n );\n }\n\n return {\n getSearchAttributes,\n getSearchSuggestions,\n itemSearch,\n itemSearchInfinite,\n };\n}\n","import { withServerCache } from \"../cache/with-cache\";\n\nexport interface ShippingAddress {\n address1: string;\n city: string;\n state: string;\n postalCode: string;\n country?: string;\n}\n\n/**\n * The subset of augur-api used by shipping actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface ShippingApiClient {\n ups: {\n ratesShop: {\n get: (params: Record<string, unknown>) => Promise<{ data: unknown }>;\n };\n };\n}\n\nexport interface ShippingActionsConfig {\n /** Warehouse/origin address for rate calculations. */\n fromAddress: ShippingAddress;\n /** UPS service codes to filter results. Default: undefined (return all). */\n defaultServiceCodes?: string[];\n /** Cache key prefix (e.g. \"ampro:\"). Default: \"\". */\n cachePrefix?: string;\n /** CDN edge cache value passed to SDK. Default: 1 (hour). */\n edgeCache?: number;\n /** Redis TTL for shipping rate lookups in seconds. Default: 3600 (1 hour). */\n redisTtl?: number;\n}\n\nexport interface ShippingActions {\n getShippingRates: (\n toAddress: ShippingAddress,\n weight: number,\n serviceCodes?: string[],\n ) => Promise<unknown>;\n}\n\n/**\n * Creates server-side shipping actions with Redis caching and edge cache support.\n *\n * Uses `withServerCache` which produces cache keys compatible with augur-hooks'\n * `withCache`, so server-prefetched data is shared with client-side hooks.\n *\n * @example\n * ```ts\n * // lib/shipping-actions.ts\n * import { createShippingActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const shippingActions = createShippingActions(getAugurClient(), {\n * fromAddress: {\n * address1: \"123 Warehouse Ln\",\n * city: \"Chicago\",\n * state: \"IL\",\n * postalCode: \"60601\",\n * },\n * });\n *\n * // In a server component:\n * const rates = await shippingActions.getShippingRates(\n * { address1: \"456 Main St\", city: \"Denver\", state: \"CO\", postalCode: \"80202\" },\n * 5.0,\n * );\n * ```\n */\nexport function createShippingActions(\n api: ShippingApiClient,\n config: ShippingActionsConfig,\n): ShippingActions {\n const {\n fromAddress,\n defaultServiceCodes,\n cachePrefix = \"\",\n edgeCache = 1,\n redisTtl = 3600,\n } = config;\n\n async function getShippingRates(\n toAddress: ShippingAddress,\n weight: number,\n serviceCodes?: string[],\n ): Promise<unknown> {\n const params = {\n fromAddress,\n toAddress: { ...toAddress, country: toAddress.country ?? \"US\" },\n weight,\n serviceCodes: serviceCodes ?? defaultServiceCodes,\n edgeCache,\n };\n\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"ups.ratesShop.get\",\n async () => {\n const response = await api.ups.ratesShop.get(params);\n return response.data;\n },\n params,\n );\n }\n\n return { getShippingRates };\n}\n","import { withServerCache } from \"../cache/with-cache\";\n\n/**\n * The subset of augur-api used by Joomla content actions.\n * Avoids importing the full SDK type so augur-server stays lightweight.\n */\nexport interface JoomlaApiClient {\n joomla: {\n content: {\n doc: {\n get: (\n articleId: number,\n params?: Record<string, unknown>,\n ) => Promise<{ data: unknown }>;\n };\n list: (\n params?: Record<string, unknown>,\n ) => Promise<{ data: unknown[] }>;\n };\n };\n}\n\nexport interface JoomlaActionsConfig {\n /** Cache key prefix (e.g. \"ampro:\"). Default: \"\". */\n cachePrefix?: string;\n /** CDN edge cache value passed to SDK. Default: 1 (hour). */\n edgeCache?: number;\n /** Redis TTL for Joomla lookups in seconds. Default: 3600 (1 hour). */\n redisTtl?: number;\n}\n\nexport interface JoomlaActions {\n getJoomlaContent: (articleId: number) => Promise<unknown>;\n getJoomlaContentList: (\n params?: Record<string, unknown>,\n ) => Promise<unknown[]>;\n}\n\n/**\n * Creates server-side Joomla content actions with Redis caching and edge cache support.\n *\n * Uses `withServerCache` which produces cache keys compatible with augur-hooks'\n * `withCache`, so server-prefetched data is shared with client-side hooks.\n *\n * @example\n * ```ts\n * // lib/joomla-actions.ts\n * import { createJoomlaActions } from \"@simpleapps-com/augur-server\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const joomlaActions = createJoomlaActions(getAugurClient(), {\n * cachePrefix: \"ampro:\",\n * });\n *\n * // In a server component:\n * const article = await joomlaActions.getJoomlaContent(42);\n * const articles = await joomlaActions.getJoomlaContentList({ catid: 5 });\n * ```\n */\nexport function createJoomlaActions(\n api: JoomlaApiClient,\n config: JoomlaActionsConfig = {},\n): JoomlaActions {\n const { cachePrefix = \"\", edgeCache = 1, redisTtl = 3600 } = config;\n\n async function getJoomlaContent(\n articleId: number,\n ): Promise<unknown> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"joomla.content.doc.get\",\n async () => {\n const response = await api.joomla.content.doc.get(articleId, {\n edgeCache,\n });\n return response.data;\n },\n articleId,\n );\n }\n\n async function getJoomlaContentList(\n params?: Record<string, unknown>,\n ): Promise<unknown[]> {\n return withServerCache(\n cachePrefix,\n redisTtl,\n \"joomla.content.list\",\n async () => {\n const response = await api.joomla.content.list({\n ...params,\n edgeCache,\n });\n return response.data;\n },\n params,\n );\n }\n\n return { getJoomlaContent, getJoomlaContentList };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,78 @@
1
+ import * as _simpleapps_com_augur_hooks_server from '@simpleapps-com/augur-hooks/server';
2
+ import { PageData, AugurApiClient } from '@simpleapps-com/augur-hooks/server';
3
+ export { CacheConfig } from '@simpleapps-com/augur-hooks/server';
4
+ import { TItemsFilters, TJoomlaContentFilters } from '@simpleapps-com/augur-utils';
5
+
6
+ /** Options for item category prefetch. */
7
+ interface PrefetchItemCategoryApiOptions {
8
+ childrenFilter?: string;
9
+ childrenLimit?: number;
10
+ childrenOffset?: number;
11
+ classId5List?: string;
12
+ filters?: Record<string, string>;
13
+ orderBy?: string;
14
+ path?: string;
15
+ productCollection?: string;
16
+ rootItemCategoryId?: string;
17
+ }
18
+ /** Configuration for createPrefetchUtilities. */
19
+ interface PrefetchConfig {
20
+ /** Cache configuration passed through to query options. */
21
+ cache?: _simpleapps_com_augur_hooks_server.CacheConfig;
22
+ /** Default customer ID for pricing prefetch. */
23
+ defaultCustomerId?: string | number;
24
+ }
25
+ /** Prefetch utilities returned by createPrefetchUtilities. */
26
+ interface PrefetchUtilities {
27
+ prefetchItemPrice: (itemId: string, customerId?: string | number, quantity?: number) => Promise<void>;
28
+ prefetchBatchItemPrices: (itemIds: string[], customerId?: string | number, quantity?: number) => Promise<void>;
29
+ prefetchProductListingPrices: (itemIds: string[], customerId?: string | number, maxItems?: number) => Promise<void>;
30
+ prefetchItemCategory: (itemCategoryUid: number, apiOptions?: PrefetchItemCategoryApiOptions) => Promise<void>;
31
+ prefetchInvMast: (invMastUid: number, itemId: string) => Promise<void>;
32
+ prefetchInvMastStock: (invMastUid: number | string) => Promise<void>;
33
+ prefetchItemDetails: (itemId: number | string) => Promise<void>;
34
+ prefetchItemAttributes: (itemCategoryUid: number | string) => Promise<void>;
35
+ prefetchProductSearch: (pageData: PageData) => Promise<void>;
36
+ prefetchJoomlaContent: (articleId: number | string) => Promise<void>;
37
+ prefetchInvMastDoc: (invMastUid: number, itemId: string, includePricing?: "Y" | "N") => Promise<void>;
38
+ prefetchProductCategory: (itemCategoryUid: number | string) => Promise<void>;
39
+ prefetchCategoryItemsFirstPage: (itemCategoryUid: number, itemsFilters: TItemsFilters) => Promise<void>;
40
+ prefetchSearchResultsFirstPage: (itemsFilters: TItemsFilters, itemCategoryUid?: number | string) => Promise<void>;
41
+ prefetchJoomlaContentList: (categoryId: number | string, filters?: Partial<TJoomlaContentFilters>) => Promise<void>;
42
+ }
43
+ /**
44
+ * Creates SSR prefetch utilities that pre-populate the React Query cache
45
+ * during server rendering. Eliminates loading states on first paint.
46
+ *
47
+ * Uses the same query keys as augur-hooks so client-side hooks hydrate
48
+ * instantly from prefetched data — no duplicate requests.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * // lib/prefetch.ts
53
+ * import { createPrefetchUtilities } from "@simpleapps-com/augur-server/prefetch";
54
+ * import { getAugurClient } from "./augur-client";
55
+ *
56
+ * export const prefetch = createPrefetchUtilities(getAugurClient(), {
57
+ * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,
58
+ * cache: augurCache,
59
+ * });
60
+ *
61
+ * // In a server component:
62
+ * export default async function ItemPage({ params }: { params: { id: string } }) {
63
+ * await prefetch.prefetchItemPrice(params.id);
64
+ * await prefetch.prefetchItemDetails(params.id);
65
+ * return <ItemDetail itemId={params.id} />;
66
+ * }
67
+ *
68
+ * // Batch prefetch for listing pages:
69
+ * export default async function CategoryPage() {
70
+ * const itemIds = await getItemIdsForCategory(categoryId);
71
+ * await prefetch.prefetchBatchItemPrices(itemIds);
72
+ * return <ProductGrid items={itemIds} />;
73
+ * }
74
+ * ```
75
+ */
76
+ declare function createPrefetchUtilities(api: AugurApiClient, config?: PrefetchConfig): PrefetchUtilities;
77
+
78
+ export { type PrefetchConfig, type PrefetchItemCategoryApiOptions, type PrefetchUtilities, createPrefetchUtilities };
@@ -0,0 +1,149 @@
1
+ import {
2
+ getServerQueryClient
3
+ } from "./chunk-I7EWYSPA.js";
4
+
5
+ // src/prefetch.ts
6
+ import {
7
+ getItemPriceKey,
8
+ getItemPriceOptions,
9
+ getItemCategoryOptions,
10
+ getInvMastOptions,
11
+ getInvMastDocOptions,
12
+ getInvMastStockOptions,
13
+ getItemDetailsOptions,
14
+ getItemAttributesOptions,
15
+ getProductCategoryOptions,
16
+ getProductSearchOptions,
17
+ getCategoryItemsInfiniteOptions,
18
+ getItemSearchInfiniteOptions,
19
+ getJoomlaContentOptions,
20
+ getJoomlaContentListOptions
21
+ } from "@simpleapps-com/augur-hooks/server";
22
+ function createPrefetchUtilities(api, config = {}) {
23
+ const { cache, defaultCustomerId } = config;
24
+ function getQueryClient() {
25
+ return getServerQueryClient();
26
+ }
27
+ function resolveCustomerId(explicit) {
28
+ return explicit ?? defaultCustomerId;
29
+ }
30
+ async function prefetchItemPrice(itemId, customerId, quantity = 1) {
31
+ const qc = getQueryClient();
32
+ const custId = resolveCustomerId(customerId);
33
+ const options = getItemPriceOptions(api, itemId, custId, quantity, cache);
34
+ await qc.prefetchQuery(options);
35
+ }
36
+ async function prefetchBatchItemPrices(itemIds, customerId, quantity = 1) {
37
+ const qc = getQueryClient();
38
+ const custId = resolveCustomerId(customerId);
39
+ const results = await Promise.all(
40
+ itemIds.map((id) => {
41
+ const options = getItemPriceOptions(api, id, custId, quantity, cache);
42
+ return options.queryFn().then((data) => [id, data]).catch(() => [id, null]);
43
+ })
44
+ );
45
+ for (const [id, data] of results) {
46
+ if (data) {
47
+ qc.setQueryData(
48
+ getItemPriceKey(id, custId, quantity),
49
+ data
50
+ );
51
+ }
52
+ }
53
+ }
54
+ async function prefetchProductListingPrices(itemIds, customerId, maxItems) {
55
+ const limited = maxItems ? itemIds.slice(0, maxItems) : itemIds;
56
+ await prefetchBatchItemPrices(limited, customerId);
57
+ }
58
+ async function prefetchItemCategory(itemCategoryUid, apiOptions) {
59
+ const qc = getQueryClient();
60
+ const options = getItemCategoryOptions(api, itemCategoryUid, apiOptions, cache);
61
+ await qc.prefetchQuery(options);
62
+ }
63
+ async function prefetchInvMast(invMastUid, itemId) {
64
+ const qc = getQueryClient();
65
+ const options = getInvMastOptions(api, invMastUid, itemId, cache);
66
+ await qc.prefetchQuery(options);
67
+ }
68
+ async function prefetchInvMastStock(invMastUid) {
69
+ const qc = getQueryClient();
70
+ const options = getInvMastStockOptions(api, invMastUid, cache);
71
+ await qc.prefetchQuery(options);
72
+ }
73
+ async function prefetchItemDetails(itemId) {
74
+ const qc = getQueryClient();
75
+ const options = getItemDetailsOptions(api, itemId, cache);
76
+ await qc.prefetchQuery(options);
77
+ }
78
+ async function prefetchItemAttributes(itemCategoryUid) {
79
+ const qc = getQueryClient();
80
+ const options = getItemAttributesOptions(api, itemCategoryUid, cache);
81
+ await qc.prefetchQuery(options);
82
+ }
83
+ async function prefetchProductSearch(pageData) {
84
+ const qc = getQueryClient();
85
+ const options = getProductSearchOptions(api, pageData, cache);
86
+ await qc.prefetchQuery(options);
87
+ }
88
+ async function prefetchJoomlaContent(articleId) {
89
+ const qc = getQueryClient();
90
+ const options = getJoomlaContentOptions(api, articleId, cache);
91
+ await qc.prefetchQuery(options);
92
+ }
93
+ async function prefetchInvMastDoc(invMastUid, itemId, includePricing = "N") {
94
+ const qc = getQueryClient();
95
+ const options = getInvMastDocOptions(api, invMastUid, itemId, includePricing, cache);
96
+ await qc.prefetchQuery(options);
97
+ }
98
+ async function prefetchProductCategory(itemCategoryUid) {
99
+ const qc = getQueryClient();
100
+ const options = getProductCategoryOptions(api, itemCategoryUid, cache);
101
+ await qc.prefetchQuery(options);
102
+ }
103
+ async function prefetchCategoryItemsFirstPage(itemCategoryUid, itemsFilters) {
104
+ const qc = getQueryClient();
105
+ const options = getCategoryItemsInfiniteOptions(
106
+ api,
107
+ itemCategoryUid,
108
+ itemsFilters,
109
+ cache
110
+ );
111
+ await qc.prefetchInfiniteQuery({ ...options, pages: 1 });
112
+ }
113
+ async function prefetchSearchResultsFirstPage(itemsFilters, itemCategoryUid) {
114
+ const qc = getQueryClient();
115
+ const options = getItemSearchInfiniteOptions(
116
+ api,
117
+ itemsFilters,
118
+ itemCategoryUid,
119
+ cache
120
+ );
121
+ await qc.prefetchInfiniteQuery({ ...options, pages: 1 });
122
+ }
123
+ async function prefetchJoomlaContentList(categoryId, filters) {
124
+ const qc = getQueryClient();
125
+ const options = getJoomlaContentListOptions(api, categoryId, filters, cache);
126
+ await qc.prefetchQuery(options);
127
+ }
128
+ return {
129
+ prefetchItemPrice,
130
+ prefetchBatchItemPrices,
131
+ prefetchProductListingPrices,
132
+ prefetchItemCategory,
133
+ prefetchInvMast,
134
+ prefetchInvMastStock,
135
+ prefetchItemDetails,
136
+ prefetchItemAttributes,
137
+ prefetchProductSearch,
138
+ prefetchInvMastDoc,
139
+ prefetchProductCategory,
140
+ prefetchCategoryItemsFirstPage,
141
+ prefetchSearchResultsFirstPage,
142
+ prefetchJoomlaContent,
143
+ prefetchJoomlaContentList
144
+ };
145
+ }
146
+ export {
147
+ createPrefetchUtilities
148
+ };
149
+ //# sourceMappingURL=prefetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prefetch.ts"],"sourcesContent":["import type { QueryClient } from \"@tanstack/react-query\";\nimport {\n getItemPriceKey,\n getItemPriceOptions,\n getItemCategoryOptions,\n getInvMastOptions,\n getInvMastDocOptions,\n getInvMastStockOptions,\n getItemDetailsOptions,\n getItemAttributesOptions,\n getProductCategoryOptions,\n getProductSearchOptions,\n getCategoryItemsInfiniteOptions,\n getItemSearchInfiniteOptions,\n getJoomlaContentOptions,\n getJoomlaContentListOptions,\n} from \"@simpleapps-com/augur-hooks/server\";\nimport type {\n AugurApiClient,\n PageData,\n} from \"@simpleapps-com/augur-hooks/server\";\nimport type {\n TItemsFilters,\n TJoomlaContentFilters,\n} from \"@simpleapps-com/augur-utils\";\nimport { getServerQueryClient } from \"./server-query-client\";\n\n/**\n * Cache configuration for prefetch utilities.\n * Re-exports the CacheConfig shape from augur-hooks so consumers\n * don't need a separate import.\n */\nexport type { CacheConfig } from \"@simpleapps-com/augur-hooks/server\";\n\n/** Options for item category prefetch. */\nexport interface PrefetchItemCategoryApiOptions {\n childrenFilter?: string;\n childrenLimit?: number;\n childrenOffset?: number;\n classId5List?: string;\n filters?: Record<string, string>;\n orderBy?: string;\n path?: string;\n productCollection?: string;\n rootItemCategoryId?: string;\n}\n\n/** Configuration for createPrefetchUtilities. */\nexport interface PrefetchConfig {\n /** Cache configuration passed through to query options. */\n cache?: import(\"@simpleapps-com/augur-hooks/server\").CacheConfig;\n /** Default customer ID for pricing prefetch. */\n defaultCustomerId?: string | number;\n}\n\n/** Prefetch utilities returned by createPrefetchUtilities. */\nexport interface PrefetchUtilities {\n prefetchItemPrice: (\n itemId: string,\n customerId?: string | number,\n quantity?: number,\n ) => Promise<void>;\n\n prefetchBatchItemPrices: (\n itemIds: string[],\n customerId?: string | number,\n quantity?: number,\n ) => Promise<void>;\n\n prefetchProductListingPrices: (\n itemIds: string[],\n customerId?: string | number,\n maxItems?: number,\n ) => Promise<void>;\n\n prefetchItemCategory: (\n itemCategoryUid: number,\n apiOptions?: PrefetchItemCategoryApiOptions,\n ) => Promise<void>;\n\n prefetchInvMast: (\n invMastUid: number,\n itemId: string,\n ) => Promise<void>;\n\n prefetchInvMastStock: (\n invMastUid: number | string,\n ) => Promise<void>;\n\n prefetchItemDetails: (\n itemId: number | string,\n ) => Promise<void>;\n\n prefetchItemAttributes: (\n itemCategoryUid: number | string,\n ) => Promise<void>;\n\n prefetchProductSearch: (\n pageData: PageData,\n ) => Promise<void>;\n\n prefetchJoomlaContent: (\n articleId: number | string,\n ) => Promise<void>;\n\n prefetchInvMastDoc: (\n invMastUid: number,\n itemId: string,\n includePricing?: \"Y\" | \"N\",\n ) => Promise<void>;\n\n prefetchProductCategory: (\n itemCategoryUid: number | string,\n ) => Promise<void>;\n\n prefetchCategoryItemsFirstPage: (\n itemCategoryUid: number,\n itemsFilters: TItemsFilters,\n ) => Promise<void>;\n\n prefetchSearchResultsFirstPage: (\n itemsFilters: TItemsFilters,\n itemCategoryUid?: number | string,\n ) => Promise<void>;\n\n prefetchJoomlaContentList: (\n categoryId: number | string,\n filters?: Partial<TJoomlaContentFilters>,\n ) => Promise<void>;\n}\n\n/**\n * Creates SSR prefetch utilities that pre-populate the React Query cache\n * during server rendering. Eliminates loading states on first paint.\n *\n * Uses the same query keys as augur-hooks so client-side hooks hydrate\n * instantly from prefetched data — no duplicate requests.\n *\n * @example\n * ```ts\n * // lib/prefetch.ts\n * import { createPrefetchUtilities } from \"@simpleapps-com/augur-server/prefetch\";\n * import { getAugurClient } from \"./augur-client\";\n *\n * export const prefetch = createPrefetchUtilities(getAugurClient(), {\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * cache: augurCache,\n * });\n *\n * // In a server component:\n * export default async function ItemPage({ params }: { params: { id: string } }) {\n * await prefetch.prefetchItemPrice(params.id);\n * await prefetch.prefetchItemDetails(params.id);\n * return <ItemDetail itemId={params.id} />;\n * }\n *\n * // Batch prefetch for listing pages:\n * export default async function CategoryPage() {\n * const itemIds = await getItemIdsForCategory(categoryId);\n * await prefetch.prefetchBatchItemPrices(itemIds);\n * return <ProductGrid items={itemIds} />;\n * }\n * ```\n */\nexport function createPrefetchUtilities(\n api: AugurApiClient,\n config: PrefetchConfig = {},\n): PrefetchUtilities {\n const { cache, defaultCustomerId } = config;\n\n function getQueryClient(): QueryClient {\n return getServerQueryClient();\n }\n\n function resolveCustomerId(\n explicit: string | number | undefined,\n ): string | number | undefined {\n return explicit ?? defaultCustomerId;\n }\n\n async function prefetchItemPrice(\n itemId: string,\n customerId?: string | number,\n quantity = 1,\n ): Promise<void> {\n const qc = getQueryClient();\n const custId = resolveCustomerId(customerId);\n const options = getItemPriceOptions(api, itemId, custId, quantity, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchBatchItemPrices(\n itemIds: string[],\n customerId?: string | number,\n quantity = 1,\n ): Promise<void> {\n const qc = getQueryClient();\n const custId = resolveCustomerId(customerId);\n\n // Fetch all prices in parallel\n const results = await Promise.all(\n itemIds.map((id) => {\n const options = getItemPriceOptions(api, id, custId, quantity, cache);\n return options\n .queryFn()\n .then((data) => [id, data] as const)\n .catch(() => [id, null] as const);\n }),\n );\n\n // Populate individual query caches so each component finds its data\n for (const [id, data] of results) {\n if (data) {\n qc.setQueryData(\n getItemPriceKey(id, custId, quantity),\n data,\n );\n }\n }\n }\n\n async function prefetchProductListingPrices(\n itemIds: string[],\n customerId?: string | number,\n maxItems?: number,\n ): Promise<void> {\n const limited = maxItems ? itemIds.slice(0, maxItems) : itemIds;\n await prefetchBatchItemPrices(limited, customerId);\n }\n\n async function prefetchItemCategory(\n itemCategoryUid: number,\n apiOptions?: PrefetchItemCategoryApiOptions,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getItemCategoryOptions(api, itemCategoryUid, apiOptions, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchInvMast(\n invMastUid: number,\n itemId: string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getInvMastOptions(api, invMastUid, itemId, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchInvMastStock(\n invMastUid: number | string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getInvMastStockOptions(api, invMastUid, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchItemDetails(\n itemId: number | string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getItemDetailsOptions(api, itemId, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchItemAttributes(\n itemCategoryUid: number | string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getItemAttributesOptions(api, itemCategoryUid, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchProductSearch(\n pageData: PageData,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getProductSearchOptions(api, pageData, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchJoomlaContent(\n articleId: number | string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getJoomlaContentOptions(api, articleId, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchInvMastDoc(\n invMastUid: number,\n itemId: string,\n includePricing: \"Y\" | \"N\" = \"N\",\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getInvMastDocOptions(api, invMastUid, itemId, includePricing, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchProductCategory(\n itemCategoryUid: number | string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getProductCategoryOptions(api, itemCategoryUid, cache);\n await qc.prefetchQuery(options);\n }\n\n async function prefetchCategoryItemsFirstPage(\n itemCategoryUid: number,\n itemsFilters: TItemsFilters,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getCategoryItemsInfiniteOptions(\n api, itemCategoryUid, itemsFilters, cache,\n );\n await qc.prefetchInfiniteQuery({ ...options, pages: 1 });\n }\n\n async function prefetchSearchResultsFirstPage(\n itemsFilters: TItemsFilters,\n itemCategoryUid?: number | string,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getItemSearchInfiniteOptions(\n api, itemsFilters, itemCategoryUid, cache,\n );\n await qc.prefetchInfiniteQuery({ ...options, pages: 1 });\n }\n\n async function prefetchJoomlaContentList(\n categoryId: number | string,\n filters?: Partial<TJoomlaContentFilters>,\n ): Promise<void> {\n const qc = getQueryClient();\n const options = getJoomlaContentListOptions(api, categoryId, filters, cache);\n await qc.prefetchQuery(options);\n }\n\n return {\n prefetchItemPrice,\n prefetchBatchItemPrices,\n prefetchProductListingPrices,\n prefetchItemCategory,\n prefetchInvMast,\n prefetchInvMastStock,\n prefetchItemDetails,\n prefetchItemAttributes,\n prefetchProductSearch,\n prefetchInvMastDoc,\n prefetchProductCategory,\n prefetchCategoryItemsFirstPage,\n prefetchSearchResultsFirstPage,\n prefetchJoomlaContent,\n prefetchJoomlaContentList,\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simpleapps-com/augur-server",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Server-side utilities for Augur ecommerce sites (Redis caching, SDK helpers, auth)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,6 +22,10 @@
22
22
  "types": "./dist/query.d.ts",
23
23
  "import": "./dist/query.js"
24
24
  },
25
+ "./prefetch": {
26
+ "types": "./dist/prefetch.d.ts",
27
+ "import": "./dist/prefetch.js"
28
+ },
25
29
  "./next-auth": {
26
30
  "types": "./next-auth.d.ts"
27
31
  }
@@ -33,7 +37,7 @@
33
37
  ],
34
38
  "dependencies": {
35
39
  "valibot": "^1.0.0",
36
- "@simpleapps-com/augur-utils": "0.2.3"
40
+ "@simpleapps-com/augur-utils": "0.2.5"
37
41
  },
38
42
  "peerDependencies": {
39
43
  "@simpleapps-com/augur-api": "^0.9.6",
@@ -41,7 +45,8 @@
41
45
  "ioredis": "^5.9.0",
42
46
  "next": ">=16.0.0",
43
47
  "next-auth": "5.0.0-beta.30",
44
- "react": "^19.0.0"
48
+ "react": "^19.0.0",
49
+ "@simpleapps-com/augur-hooks": "0.2.5"
45
50
  },
46
51
  "peerDependenciesMeta": {
47
52
  "ioredis": {
@@ -49,6 +54,9 @@
49
54
  },
50
55
  "next-auth": {
51
56
  "optional": true
57
+ },
58
+ "@simpleapps-com/augur-hooks": {
59
+ "optional": true
52
60
  }
53
61
  },
54
62
  "devDependencies": {
@@ -60,7 +68,8 @@
60
68
  "react": "^19.0.0",
61
69
  "tsup": "^8.5.0",
62
70
  "vitest": "^3.2.0",
63
- "@augur-packages/tsconfig": "0.0.0"
71
+ "@augur-packages/tsconfig": "0.0.0",
72
+ "@simpleapps-com/augur-hooks": "0.2.5"
64
73
  },
65
74
  "scripts": {
66
75
  "build": "tsup",