@01.software/sdk 0.27.0 → 0.29.0

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.
Files changed (40) hide show
  1. package/README.md +125 -1
  2. package/dist/analytics/react.cjs.map +1 -1
  3. package/dist/analytics/react.js.map +1 -1
  4. package/dist/analytics.cjs.map +1 -1
  5. package/dist/analytics.js.map +1 -1
  6. package/dist/{const-C0GlmeJ_.d.cts → const-DAjQYNuM.d.ts} +4 -4
  7. package/dist/{const-D-xucnw4.d.ts → const-Dsixdi6z.d.cts} +4 -4
  8. package/dist/index.cjs +626 -13
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +19 -8
  11. package/dist/index.d.ts +19 -8
  12. package/dist/index.js +626 -13
  13. package/dist/index.js.map +1 -1
  14. package/dist/{payload-types-BPvUmPAq.d.cts → payload-types-Ci-ZA7aM.d.cts} +153 -73
  15. package/dist/{payload-types-BPvUmPAq.d.ts → payload-types-Ci-ZA7aM.d.ts} +153 -73
  16. package/dist/realtime.cjs.map +1 -1
  17. package/dist/realtime.d.cts +2 -2
  18. package/dist/realtime.d.ts +2 -2
  19. package/dist/realtime.js.map +1 -1
  20. package/dist/{server-n3xK4Nks.d.cts → server-C0C8dtms.d.cts} +331 -12
  21. package/dist/{server-_zvihptw.d.ts → server-Cv0Q4dPQ.d.ts} +331 -12
  22. package/dist/server.cjs +68 -4
  23. package/dist/server.cjs.map +1 -1
  24. package/dist/server.d.cts +4 -4
  25. package/dist/server.d.ts +4 -4
  26. package/dist/server.js +68 -4
  27. package/dist/server.js.map +1 -1
  28. package/dist/{types-BLdthWiW.d.ts → types-BWq_WlbB.d.ts} +1 -1
  29. package/dist/{types-DzWNu9pw.d.cts → types-zKjATmDK.d.cts} +1 -1
  30. package/dist/ui/canvas/server.cjs.map +1 -1
  31. package/dist/ui/canvas/server.js.map +1 -1
  32. package/dist/ui/canvas.cjs.map +1 -1
  33. package/dist/ui/canvas.js.map +1 -1
  34. package/dist/ui/form.d.cts +1 -1
  35. package/dist/ui/form.d.ts +1 -1
  36. package/dist/ui/video.d.cts +1 -1
  37. package/dist/ui/video.d.ts +1 -1
  38. package/dist/webhook.d.cts +3 -3
  39. package/dist/webhook.d.ts +3 -3
  40. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/query/realtime-hooks.ts","../src/core/query/realtime.ts","../src/core/client/types.ts","../src/core/query/query-keys.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { RealtimeConnection, type RealtimeEvent } from './realtime'\nimport { resolveApiUrl, type PublicCollection } from '../client/types'\nimport { collectionKeys } from './query-keys'\n\nexport type { RealtimeEvent }\n\nexport interface UseRealtimeQueryOptions {\n /** Filter events to specific collections. Empty/undefined = all collections. */\n collections?: PublicCollection[]\n /** Enable/disable the SSE connection. Default: true. */\n enabled?: boolean\n}\n\nexport interface UseRealtimeQueryResult {\n /** Whether the SSE connection is currently active. */\n connected: boolean\n /** The last received event, or null. */\n lastEvent: RealtimeEvent | null\n}\n\n/**\n * React hook that subscribes to real-time collection change events via SSE.\n * Automatically invalidates React Query cache when changes are detected.\n *\n * @example\n * ```tsx\n * const { connected } = useRealtimeQuery({\n * publishableKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n publishableKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { getToken, collections, enabled = true } = options\n const publishableKey = options.publishableKey\n const queryClient = useQueryClient()\n const [connected, setConnected] = useState(false)\n const [lastEvent, setLastEvent] = useState<RealtimeEvent | null>(null)\n const connectionRef = useRef<RealtimeConnection | null>(null)\n\n useEffect(() => {\n if (!enabled || !publishableKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n publishableKey,\n getToken,\n collections,\n )\n connectionRef.current = conn\n\n // Listen for events and invalidate queries\n const removeListener = conn.addListener((event) => {\n setLastEvent(event)\n\n // Invalidate all queries for the changed collection\n const keys = collectionKeys(event.collection as PublicCollection)\n queryClient.invalidateQueries({ queryKey: keys.all })\n })\n\n // Track connection state\n const pollInterval = setInterval(() => {\n setConnected(conn.connected)\n }, 1000)\n\n conn.connect()\n\n return () => {\n conn.disconnect()\n removeListener()\n clearInterval(pollInterval)\n connectionRef.current = null\n setConnected(false)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [publishableKey, enabled, collections?.join(',')])\n\n return { connected, lastEvent }\n}\n","/**\n * Fetch-based SSE connection manager for real-time collection change events.\n * Uses fetch + ReadableStream to support custom auth headers (unlike native EventSource).\n */\n\nexport interface RealtimeEvent {\n collection: string\n operation: string\n id: string | null\n timestamp: string\n}\n\nexport type RealtimeListener = (event: RealtimeEvent) => void\n\nconst INITIAL_RECONNECT_DELAY = 1_000\nconst MAX_RECONNECT_DELAY = 30_000\nconst RECONNECT_BACKOFF_FACTOR = 2\nconst MAX_NO_TOKEN_RETRIES = 5\n\nexport class RealtimeConnection {\n private abortController: AbortController | null = null\n private reconnectAttempt = 0\n private noTokenAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private listeners = new Set<RealtimeListener>()\n private _connected = false\n\n constructor(\n private baseUrl: string,\n private publishableKey: string,\n private getToken: () => string | null,\n private collections?: string[],\n ) {}\n\n get connected(): boolean {\n return this._connected\n }\n\n addListener(fn: RealtimeListener): () => void {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n\n connect(): void {\n if (this.abortController) return // Already connecting/connected\n\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }\n\n disconnect(): void {\n this._connected = false\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n if (this.abortController) {\n this.abortController.abort()\n this.abortController = null\n }\n this.reconnectAttempt = 0\n this.noTokenAttempts = 0\n }\n\n private async startStream(signal: AbortSignal): Promise<void> {\n const token = this.getToken()\n if (!token) {\n this.noTokenAttempts++\n if (this.noTokenAttempts >= MAX_NO_TOKEN_RETRIES) {\n // Stop reconnecting — no token available after multiple attempts\n this._connected = false\n this.abortController = null\n return\n }\n this.scheduleReconnect()\n return\n }\n this.noTokenAttempts = 0\n\n const params = this.collections?.length\n ? `?collections=${this.collections.join(',')}`\n : ''\n const url = `${this.baseUrl}/api/events/stream${params}`\n\n try {\n const response = await fetch(url, {\n headers: {\n 'X-Publishable-Key': this.publishableKey,\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n\n if (!response.ok) {\n if (response.status === 401) {\n // Token expired — try reconnecting (will get fresh token)\n this.scheduleReconnect()\n return\n }\n throw new Error(`SSE connection failed: ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('SSE response has no body')\n }\n\n this._connected = true\n this.reconnectAttempt = 0\n\n await this.readStream(response.body, signal)\n } catch {\n if (signal.aborted) return // Intentional disconnect\n this._connected = false\n this.scheduleReconnect()\n }\n }\n\n private async readStream(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n ): Promise<void> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let currentEvent = ''\n let currentData = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done || signal.aborted) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? '' // Keep incomplete last line in buffer\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7)\n } else if (line.startsWith('data: ')) {\n currentData += (currentData ? '\\n' : '') + line.slice(6)\n } else if (line === '') {\n // Empty line = end of event\n if (currentEvent === 'collection:change' && currentData) {\n try {\n const event: RealtimeEvent = JSON.parse(currentData)\n for (const listener of this.listeners) {\n try {\n listener(event)\n } catch {\n // Listener error — ignore\n }\n }\n } catch {\n // Malformed JSON — ignore\n }\n }\n currentEvent = ''\n currentData = ''\n }\n // Ignore comment lines (: heartbeat)\n }\n }\n } catch {\n // Stream read error\n } finally {\n reader.releaseLock()\n this._connected = false\n if (!signal.aborted) {\n this.scheduleReconnect()\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n const delay = Math.min(\n INITIAL_RECONNECT_DELAY *\n Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),\n MAX_RECONNECT_DELAY,\n )\n this.reconnectAttempt++\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }, delay)\n }\n}\n","import type { Sort, Where } from 'payload'\n\nimport type {\n Collection,\n PublicCollection,\n ServerCollection,\n ServerOnlyCollection,\n} from '../collection/const'\n\nexport type {\n Collection,\n PublicCollection,\n ServerCollection,\n ServerOnlyCollection,\n}\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\nexport function resolveApiUrl(): string {\n if (typeof process !== 'undefined' && process.env) {\n const envUrl =\n process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL\n if (envUrl) {\n return envUrl.replace(/\\/$/, '')\n }\n }\n return __DEFAULT_API_URL__\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface ClientConfig {\n publishableKey: string\n /**\n * Customer authentication options.\n * Used to initialize CustomerAuth on Client.\n */\n customer?: {\n /**\n * Persist token in localStorage. Defaults to `true`.\n * - `true` (default): uses key `'customer-token'`\n * - `string`: uses the given string as localStorage key\n * - `false`: disables persistence (token/onTokenChange used instead)\n *\n * Handles SSR safely (no-op on server).\n * When enabled, `token` and `onTokenChange` are ignored.\n */\n persist?: boolean | string\n /** Initial token (e.g. from SSR cookie) */\n token?: string\n /** Called when token changes (login/logout) — use to persist in localStorage/cookie */\n onTokenChange?: (token: string | null) => void\n }\n}\n\n// Server client: requires both publishableKey (for CDN routing + rate limit +\n// monthly quota enforcement via the edge proxy) and secretKey (sk01_ opaque\n// bearer token, the authentication credential).\n// The proxy keys its tenant lookup off `X-Publishable-Key`, so omitting\n// publishableKey would silently bypass rate limiting and plan-based quota\n// enforcement.\nexport interface ClientServerConfig extends ClientConfig {\n secretKey: string\n}\n\nexport interface ClientMetadata {\n userAgent?: string\n timestamp: number\n}\n\nexport interface ClientState {\n metadata: ClientMetadata\n}\n\nexport interface PaginationMeta {\n page: number\n limit: number\n totalDocs: number\n totalPages: number\n hasNextPage: boolean\n hasPrevPage: boolean\n pagingCounter: number\n prevPage: number | null\n nextPage: number | null\n}\n\n// ============================================================================\n// Payload CMS Native Response Types\n// ============================================================================\n\n/**\n * Payload CMS Find (List) Response\n * GET /api/{collection}\n */\nexport interface PayloadFindResponse<T = unknown> {\n docs: T[]\n totalDocs: number\n limit: number\n totalPages: number\n page: number\n pagingCounter: number\n hasPrevPage: boolean\n hasNextPage: boolean\n prevPage: number | null\n nextPage: number | null\n}\n\n/**\n * Payload CMS Create/Update Response\n * POST /api/{collection}\n * PATCH /api/{collection}/{id}\n */\nexport interface PayloadMutationResponse<T = unknown> {\n message: string\n doc: T\n errors?: unknown[]\n}\n\n// ============================================================================\n// Query Options\n// ============================================================================\n\n/**\n * Do NOT replace with `Pick<FindOptions>` from `payload`. Payload's generic\n * types (`JoinQuery<TSlug>`, `PopulateType`) depend on `PayloadTypes` module\n * augmentation; external SDK consumers who skip that get degenerate types\n * (`never` / `{}`). Only non-generic `Sort`/`Where` are safe to import.\n * Excluded vs native: Local-API-only fields, `locale`/`fallbackLocale`.\n */\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, boolean>\n /** Per-collection field selection for populated relationships (keyed by collection slug) */\n populate?: Record<string, boolean | Record<string, boolean>>\n /** Join field control: pagination/filter per join, or false to disable */\n joins?:\n | Record<\n string,\n | {\n limit?: number\n page?: number\n sort?: string\n where?: Where\n count?: boolean\n }\n | false\n >\n | false\n /** Set to `false` to skip the count query — returns docs without totalDocs/totalPages */\n pagination?: boolean\n /** Include draft versions (access control still applies on the server) */\n draft?: boolean\n /** Include soft-deleted documents (requires `trash` enabled on the collection) */\n trash?: boolean\n}\n\n// ============================================================================\n// Debug & Retry Configuration\n// ============================================================================\n\nexport interface DebugConfig {\n logRequests?: boolean\n logResponses?: boolean\n logErrors?: boolean\n}\n\nexport interface RetryConfig {\n maxRetries?: number\n retryableStatuses?: number[]\n retryDelay?: (attempt: number) => number\n}\n\n// ============================================================================\n// Type Utilities\n// ============================================================================\n\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\nexport type ExtractArrayType<T> = T extends (infer U)[] ? U : never\n","import type { PublicCollection, ApiQueryOptions } from '../client/types'\nimport type { ProductListingGroupsQueryOptions } from './query-hooks'\n\nexport function collectionKeys<T extends PublicCollection>(collection: T) {\n return {\n all: [collection] as const,\n lists: () => [collection, 'list'] as const,\n list: (options?: ApiQueryOptions) => [collection, 'list', options] as const,\n details: () => [collection, 'detail'] as const,\n detail: (id: string, options?: ApiQueryOptions) =>\n [collection, 'detail', id, options] as const,\n infinites: () => [collection, 'infinite'] as const,\n infinite: (options?: Omit<ApiQueryOptions, 'page'>) =>\n [collection, 'infinite', options] as const,\n }\n}\n\nexport const customerKeys = {\n all: ['customer'] as const,\n me: () => ['customer', 'me'] as const,\n}\n\nexport const productKeys = {\n listingGroups: (options?: ProductListingGroupsQueryOptions) =>\n ['products', 'listing-groups', 'list', options] as const,\n listingGroupsInfinite: (\n options?: Omit<ProductListingGroupsQueryOptions, 'page' | 'limit'>,\n ) =>\n ['products', 'listing-groups', 'infinite', options] as const,\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/core/query/realtime-hooks.ts","../src/core/query/realtime.ts","../src/core/client/types.ts","../src/core/query/query-keys.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { RealtimeConnection, type RealtimeEvent } from './realtime'\nimport { resolveApiUrl, type PublicCollection } from '../client/types'\nimport { collectionKeys } from './query-keys'\n\nexport type { RealtimeEvent }\n\nexport interface UseRealtimeQueryOptions {\n /** Filter events to specific collections. Empty/undefined = all collections. */\n collections?: PublicCollection[]\n /** Enable/disable the SSE connection. Default: true. */\n enabled?: boolean\n}\n\nexport interface UseRealtimeQueryResult {\n /** Whether the SSE connection is currently active. */\n connected: boolean\n /** The last received event, or null. */\n lastEvent: RealtimeEvent | null\n}\n\n/**\n * React hook that subscribes to real-time collection change events via SSE.\n * Automatically invalidates React Query cache when changes are detected.\n *\n * @example\n * ```tsx\n * const { connected } = useRealtimeQuery({\n * publishableKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n publishableKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { getToken, collections, enabled = true } = options\n const publishableKey = options.publishableKey\n const queryClient = useQueryClient()\n const [connected, setConnected] = useState(false)\n const [lastEvent, setLastEvent] = useState<RealtimeEvent | null>(null)\n const connectionRef = useRef<RealtimeConnection | null>(null)\n\n useEffect(() => {\n if (!enabled || !publishableKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n publishableKey,\n getToken,\n collections,\n )\n connectionRef.current = conn\n\n // Listen for events and invalidate queries\n const removeListener = conn.addListener((event) => {\n setLastEvent(event)\n\n // Invalidate all queries for the changed collection\n const keys = collectionKeys(event.collection as PublicCollection)\n queryClient.invalidateQueries({ queryKey: keys.all })\n })\n\n // Track connection state\n const pollInterval = setInterval(() => {\n setConnected(conn.connected)\n }, 1000)\n\n conn.connect()\n\n return () => {\n conn.disconnect()\n removeListener()\n clearInterval(pollInterval)\n connectionRef.current = null\n setConnected(false)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [publishableKey, enabled, collections?.join(',')])\n\n return { connected, lastEvent }\n}\n","/**\n * Fetch-based SSE connection manager for real-time collection change events.\n * Uses fetch + ReadableStream to support custom auth headers (unlike native EventSource).\n */\n\nexport interface RealtimeEvent {\n collection: string\n operation: string\n id: string | null\n timestamp: string\n}\n\nexport type RealtimeListener = (event: RealtimeEvent) => void\n\nconst INITIAL_RECONNECT_DELAY = 1_000\nconst MAX_RECONNECT_DELAY = 30_000\nconst RECONNECT_BACKOFF_FACTOR = 2\nconst MAX_NO_TOKEN_RETRIES = 5\n\nexport class RealtimeConnection {\n private abortController: AbortController | null = null\n private reconnectAttempt = 0\n private noTokenAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private listeners = new Set<RealtimeListener>()\n private _connected = false\n\n constructor(\n private baseUrl: string,\n private publishableKey: string,\n private getToken: () => string | null,\n private collections?: string[],\n ) {}\n\n get connected(): boolean {\n return this._connected\n }\n\n addListener(fn: RealtimeListener): () => void {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n\n connect(): void {\n if (this.abortController) return // Already connecting/connected\n\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }\n\n disconnect(): void {\n this._connected = false\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n if (this.abortController) {\n this.abortController.abort()\n this.abortController = null\n }\n this.reconnectAttempt = 0\n this.noTokenAttempts = 0\n }\n\n private async startStream(signal: AbortSignal): Promise<void> {\n const token = this.getToken()\n if (!token) {\n this.noTokenAttempts++\n if (this.noTokenAttempts >= MAX_NO_TOKEN_RETRIES) {\n // Stop reconnecting — no token available after multiple attempts\n this._connected = false\n this.abortController = null\n return\n }\n this.scheduleReconnect()\n return\n }\n this.noTokenAttempts = 0\n\n const params = this.collections?.length\n ? `?collections=${this.collections.join(',')}`\n : ''\n const url = `${this.baseUrl}/api/events/stream${params}`\n\n try {\n const response = await fetch(url, {\n headers: {\n 'X-Publishable-Key': this.publishableKey,\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n\n if (!response.ok) {\n if (response.status === 401) {\n // Token expired — try reconnecting (will get fresh token)\n this.scheduleReconnect()\n return\n }\n throw new Error(`SSE connection failed: ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('SSE response has no body')\n }\n\n this._connected = true\n this.reconnectAttempt = 0\n\n await this.readStream(response.body, signal)\n } catch {\n if (signal.aborted) return // Intentional disconnect\n this._connected = false\n this.scheduleReconnect()\n }\n }\n\n private async readStream(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n ): Promise<void> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let currentEvent = ''\n let currentData = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done || signal.aborted) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? '' // Keep incomplete last line in buffer\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7)\n } else if (line.startsWith('data: ')) {\n currentData += (currentData ? '\\n' : '') + line.slice(6)\n } else if (line === '') {\n // Empty line = end of event\n if (currentEvent === 'collection:change' && currentData) {\n try {\n const event: RealtimeEvent = JSON.parse(currentData)\n for (const listener of this.listeners) {\n try {\n listener(event)\n } catch {\n // Listener error — ignore\n }\n }\n } catch {\n // Malformed JSON — ignore\n }\n }\n currentEvent = ''\n currentData = ''\n }\n // Ignore comment lines (: heartbeat)\n }\n }\n } catch {\n // Stream read error\n } finally {\n reader.releaseLock()\n this._connected = false\n if (!signal.aborted) {\n this.scheduleReconnect()\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n const delay = Math.min(\n INITIAL_RECONNECT_DELAY *\n Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),\n MAX_RECONNECT_DELAY,\n )\n this.reconnectAttempt++\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }, delay)\n }\n}\n","import type { Sort, Where } from 'payload'\n\nimport type {\n Collection,\n PublicCollection,\n ServerCollection,\n ServerOnlyCollection,\n} from '../collection/const'\n\nexport type {\n Collection,\n PublicCollection,\n ServerCollection,\n ServerOnlyCollection,\n}\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\nexport function resolveApiUrl(): string {\n if (typeof process !== 'undefined' && process.env) {\n const envUrl =\n process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL\n if (envUrl) {\n return envUrl.replace(/\\/$/, '')\n }\n }\n return __DEFAULT_API_URL__\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface ClientConfig {\n publishableKey: string\n /**\n * Customer authentication options.\n * Used to initialize CustomerAuth on Client.\n */\n customer?: {\n /**\n * Persist token in localStorage. Defaults to `true`.\n * - `true` (default): uses key `'customer-token'`\n * - `string`: uses the given string as localStorage key\n * - `false`: disables persistence (token/onTokenChange used instead)\n *\n * Handles SSR safely (no-op on server).\n * When enabled, `token` and `onTokenChange` are ignored.\n */\n persist?: boolean | string\n /** Initial token (e.g. from SSR cookie) */\n token?: string\n /** Called when token changes (login/logout) — use to persist in localStorage/cookie */\n onTokenChange?: (token: string | null) => void\n }\n}\n\n// Server client: requires both publishableKey (for CDN routing + rate limit +\n// monthly quota enforcement via the edge proxy) and secretKey (sk01_ opaque\n// bearer token, the authentication credential).\n// The proxy keys its tenant lookup off `X-Publishable-Key`, so omitting\n// publishableKey would silently bypass rate limiting and plan-based quota\n// enforcement.\nexport interface ClientServerConfig extends ClientConfig {\n secretKey: string\n}\n\nexport interface ClientMetadata {\n userAgent?: string\n timestamp: number\n}\n\nexport interface ClientState {\n metadata: ClientMetadata\n}\n\nexport interface PaginationMeta {\n page: number\n limit: number\n totalDocs: number\n totalPages: number\n hasNextPage: boolean\n hasPrevPage: boolean\n pagingCounter: number\n prevPage: number | null\n nextPage: number | null\n}\n\n// ============================================================================\n// Payload CMS Native Response Types\n// ============================================================================\n\n/**\n * Payload CMS Find (List) Response\n * GET /api/{collection}\n */\nexport interface PayloadFindResponse<T = unknown> {\n docs: T[]\n totalDocs: number\n limit: number\n totalPages: number\n page: number\n pagingCounter: number\n hasPrevPage: boolean\n hasNextPage: boolean\n prevPage: number | null\n nextPage: number | null\n}\n\n/**\n * Payload CMS Create/Update Response\n * POST /api/{collection}\n * PATCH /api/{collection}/{id}\n */\nexport interface PayloadMutationResponse<T = unknown> {\n message: string\n doc: T\n errors?: unknown[]\n}\n\n// ============================================================================\n// Query Options\n// ============================================================================\n\n/**\n * Do NOT replace with `Pick<FindOptions>` from `payload`. Payload's generic\n * types (`JoinQuery<TSlug>`, `PopulateType`) depend on `PayloadTypes` module\n * augmentation; external SDK consumers who skip that get degenerate types\n * (`never` / `{}`). Only non-generic `Sort`/`Where` are safe to import.\n * Excluded vs native: Local-API-only fields, `locale`/`fallbackLocale`.\n */\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n /**\n * Filter documents. Id-based relation filters (`where: { product: { equals: id } }`) are the\n * most reliable pattern. Dotted-path relation filters (`where: { 'product.slug': { equals } }`)\n * are Payload-native but may silently return empty when access control restricts the related\n * document or when the relation is polymorphic. String shorthand (`where: { slug: 'x' }`)\n * silently matches nothing — always use `{ slug: { equals: 'x' } }`.\n */\n where?: Where\n /**\n * Controls how deeply relationship fields are populated. This is the primary control for\n * populating relationships like `category`, `images`, `brand`. The configured Payload default\n * applies when unset.\n */\n depth?: number\n select?: Record<string, boolean>\n /**\n * Controls which fields are returned for already-populated relationships, keyed by collection\n * slug. Does NOT control which relationships to populate — that is `depth`.\n *\n * @example\n * // depth: 2 populates category; populate trims which fields come back\n * populate: { categories: { title: true, slug: true } }\n */\n populate?: Record<string, boolean | Record<string, boolean>>\n /**\n * Controls Payload `type: 'join'` virtual reverse-relation fields only (pagination, sort,\n * filter, count per join field, or `false` to disable all join-field population).\n *\n * Does NOT populate normal relationship fields like `category`, `images`, or `brand`.\n * For normal relationship population use `depth` (and optionally `populate` for field\n * selection).\n *\n * Pass `joins: false` to disable all join-field population — useful for lightweight list\n * queries where join fields are not needed.\n *\n * @example\n * // `article-authors` has a `type: 'join'` field `articles` (reverse-relation)\n * joins: { articles: { limit: 10, sort: '-publishedAt' } }\n *\n * // depth: 2 populates product.category — joins has no effect on this\n * depth: 2\n *\n * // Disable all join-field population\n * joins: false\n */\n joins?:\n | Record<\n string,\n | {\n limit?: number\n page?: number\n sort?: string\n where?: Where\n count?: boolean\n }\n | false\n >\n | false\n /** Set to `false` to skip the count query — returns docs without totalDocs/totalPages */\n pagination?: boolean\n /** Include draft versions (access control still applies on the server) */\n draft?: boolean\n /** Include soft-deleted documents (requires `trash` enabled on the collection) */\n trash?: boolean\n}\n\n// ============================================================================\n// Debug & Retry Configuration\n// ============================================================================\n\nexport interface DebugConfig {\n logRequests?: boolean\n logResponses?: boolean\n logErrors?: boolean\n}\n\nexport interface RetryConfig {\n maxRetries?: number\n retryableStatuses?: number[]\n retryDelay?: (attempt: number) => number\n}\n\n// ============================================================================\n// Type Utilities\n// ============================================================================\n\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\nexport type ExtractArrayType<T> = T extends (infer U)[] ? U : never\n","import type { PublicCollection, ApiQueryOptions } from '../client/types'\nimport type { ProductListingGroupsQueryOptions } from './query-hooks'\n\nexport function collectionKeys<T extends PublicCollection>(collection: T) {\n return {\n all: [collection] as const,\n lists: () => [collection, 'list'] as const,\n list: (options?: ApiQueryOptions) => [collection, 'list', options] as const,\n details: () => [collection, 'detail'] as const,\n detail: (id: string, options?: ApiQueryOptions) =>\n [collection, 'detail', id, options] as const,\n infinites: () => [collection, 'infinite'] as const,\n infinite: (options?: Omit<ApiQueryOptions, 'page'>) =>\n [collection, 'infinite', options] as const,\n }\n}\n\nexport const customerKeys = {\n all: ['customer'] as const,\n me: () => ['customer', 'me'] as const,\n}\n\nexport const productKeys = {\n listingGroups: (options?: ProductListingGroupsQueryOptions) =>\n ['products', 'listing-groups', 'list', options] as const,\n listingGroupsInfinite: (\n options?: Omit<ProductListingGroupsQueryOptions, 'page' | 'limit'>,\n ) =>\n ['products', 'listing-groups', 'infinite', options] as const,\n detail: (params: { slug: string } | { id: string }) =>\n ['products', 'detail', params] as const,\n detailAll: () => ['products', 'detail'] as const,\n}\n"],"mappings":"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","names":[]}
@@ -1,10 +1,10 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { QueryClient, InfiniteData } from '@tanstack/react-query';
3
- import { O as Order, d as Cart, e as CartItem, f as Product, l as OrderItem, m as Transaction, n as Fulfillment, o as Return } from './payload-types-BPvUmPAq.cjs';
2
+ import { QueryClient, InfiniteData, UseQueryResult } from '@tanstack/react-query';
3
+ import { O as Order, d as Cart, e as CartItem, f as Product, l as OrderItem, m as Transaction, n as Fulfillment, o as Return } from './payload-types-Ci-ZA7aM.cjs';
4
4
  import { Sort, Where } from 'payload';
5
5
  import { Metadata } from 'next';
6
- import { C as CollectionType } from './types-DzWNu9pw.cjs';
7
- import { P as PublicCollection, d as ServerCollection } from './const-C0GlmeJ_.cjs';
6
+ import { C as CollectionType } from './types-zKjATmDK.cjs';
7
+ import { P as PublicCollection, d as ServerCollection } from './const-Dsixdi6z.cjs';
8
8
 
9
9
  declare function resolveApiUrl(): string;
10
10
  interface ClientConfig {
@@ -88,12 +88,51 @@ interface ApiQueryOptions {
88
88
  page?: number;
89
89
  limit?: number;
90
90
  sort?: Sort;
91
+ /**
92
+ * Filter documents. Id-based relation filters (`where: { product: { equals: id } }`) are the
93
+ * most reliable pattern. Dotted-path relation filters (`where: { 'product.slug': { equals } }`)
94
+ * are Payload-native but may silently return empty when access control restricts the related
95
+ * document or when the relation is polymorphic. String shorthand (`where: { slug: 'x' }`)
96
+ * silently matches nothing — always use `{ slug: { equals: 'x' } }`.
97
+ */
91
98
  where?: Where;
99
+ /**
100
+ * Controls how deeply relationship fields are populated. This is the primary control for
101
+ * populating relationships like `category`, `images`, `brand`. The configured Payload default
102
+ * applies when unset.
103
+ */
92
104
  depth?: number;
93
105
  select?: Record<string, boolean>;
94
- /** Per-collection field selection for populated relationships (keyed by collection slug) */
106
+ /**
107
+ * Controls which fields are returned for already-populated relationships, keyed by collection
108
+ * slug. Does NOT control which relationships to populate — that is `depth`.
109
+ *
110
+ * @example
111
+ * // depth: 2 populates category; populate trims which fields come back
112
+ * populate: { categories: { title: true, slug: true } }
113
+ */
95
114
  populate?: Record<string, boolean | Record<string, boolean>>;
96
- /** Join field control: pagination/filter per join, or false to disable */
115
+ /**
116
+ * Controls Payload `type: 'join'` virtual reverse-relation fields only (pagination, sort,
117
+ * filter, count per join field, or `false` to disable all join-field population).
118
+ *
119
+ * Does NOT populate normal relationship fields like `category`, `images`, or `brand`.
120
+ * For normal relationship population use `depth` (and optionally `populate` for field
121
+ * selection).
122
+ *
123
+ * Pass `joins: false` to disable all join-field population — useful for lightweight list
124
+ * queries where join fields are not needed.
125
+ *
126
+ * @example
127
+ * // `article-authors` has a `type: 'join'` field `articles` (reverse-relation)
128
+ * joins: { articles: { limit: 10, sort: '-publishedAt' } }
129
+ *
130
+ * // depth: 2 populates product.category — joins has no effect on this
131
+ * depth: 2
132
+ *
133
+ * // Disable all join-field population
134
+ * joins: false
135
+ */
97
136
  joins?: Record<string, {
98
137
  limit?: number;
99
138
  page?: number;
@@ -850,9 +889,7 @@ type EntityID = string;
850
889
  type RelationshipValue = string | number | null | undefined | {
851
890
  id?: string | number | null;
852
891
  };
853
- type MediaValue = {
854
- id?: EntityID | null;
855
- } | EntityID | null | undefined;
892
+ type MediaValue = ProductDetailMedia | null | undefined;
856
893
  interface ProductOptionValueShape {
857
894
  id?: string | number | null;
858
895
  option?: RelationshipValue;
@@ -867,6 +904,7 @@ interface ProductOptionValueShape {
867
904
  interface ProductOptionShape {
868
905
  id?: string | number | null;
869
906
  title?: string | null;
907
+ slug?: string | null;
870
908
  _order?: string | null;
871
909
  '_product-options_options_order'?: string | null;
872
910
  values?: {
@@ -894,6 +932,7 @@ interface ProductListingProductShape {
894
932
  type ProductOptionMatrixValue = {
895
933
  id: string;
896
934
  optionId: string;
935
+ optionSlug: string;
897
936
  label: string;
898
937
  slug: string | null;
899
938
  swatchColor?: string | null;
@@ -904,6 +943,7 @@ type ProductOptionMatrixValue = {
904
943
  type ProductOptionMatrixOption = {
905
944
  id: string;
906
945
  title: string;
946
+ slug: string;
907
947
  order: string;
908
948
  values: ProductOptionMatrixValue[];
909
949
  };
@@ -911,14 +951,18 @@ type ProductOptionMatrixVariant<TVariant extends ProductVariantShape = ProductVa
911
951
  id: string;
912
952
  optionValueIds: string[];
913
953
  optionValueByOptionId: Map<string, string>;
954
+ optionValueByOptionSlug: Map<string, string>;
914
955
  source: TVariant;
915
956
  };
916
957
  type ProductOptionMatrix<TVariant extends ProductVariantShape = ProductVariantShape> = {
917
958
  options: ProductOptionMatrixOption[];
918
959
  optionIds: string[];
960
+ optionSlugs: string[];
919
961
  optionById: Map<string, ProductOptionMatrixOption>;
962
+ optionBySlug: Map<string, ProductOptionMatrixOption>;
920
963
  valueById: Map<string, ProductOptionMatrixValue>;
921
964
  valueToOptionId: Map<string, string>;
965
+ valueToOptionSlug: Map<string, string>;
922
966
  variants: ProductOptionMatrixVariant<TVariant>[];
923
967
  };
924
968
  type ProductListingProjection = {
@@ -945,14 +989,90 @@ type ProductListingGroup<TVariant extends ProductVariantShape = ProductVariantSh
945
989
  variants: TVariant[];
946
990
  listing: ProductListingProjection;
947
991
  };
992
+ type ProductSelectionByOptionValue = string | number | null | undefined | {
993
+ valueId?: string | number | null;
994
+ valueSlug?: string | null;
995
+ };
996
+ type ProductSelectionInput = {
997
+ variantId?: string | number | null;
998
+ byOptionSlug?: Record<string, ProductSelectionByOptionValue>;
999
+ byOptionId?: Record<string, ProductSelectionByOptionValue>;
1000
+ valueIds?: Iterable<unknown>;
1001
+ search?: string | URLSearchParams | URL | null;
1002
+ };
1003
+ type NormalizedProductSelection = {
1004
+ byOptionSlug: Record<string, string>;
1005
+ byOptionId: Record<string, string>;
1006
+ valueIds: string[];
1007
+ variantId: string | null;
1008
+ };
1009
+ type LegacyProductSelectionParamEvent = {
1010
+ optionId: string;
1011
+ optionSlug: string;
1012
+ valueSlug: string;
1013
+ searchParam: string;
1014
+ };
1015
+ type ProductSelectionCodecOptions = {
1016
+ onLegacyOptionIdParam?: (event: LegacyProductSelectionParamEvent) => void;
1017
+ };
1018
+ type ProductSelectionAvailableValue = {
1019
+ valueId: string;
1020
+ value: string;
1021
+ slug: string;
1022
+ selected: boolean;
1023
+ available: boolean;
1024
+ swatchColor?: string | null;
1025
+ thumbnail?: MediaValue;
1026
+ images?: MediaValue[] | null;
1027
+ };
1028
+ type ProductSelectionResolution = {
1029
+ normalizedSelection: NormalizedProductSelection;
1030
+ selectedVariant: ProductDetailVariant | null;
1031
+ matchingVariants: ProductDetailVariant[];
1032
+ partialVariants: ProductDetailVariant[];
1033
+ availableValuesByOptionSlug: Record<string, ProductSelectionAvailableValue[]>;
1034
+ availableValuesByOptionId: Record<string, ProductSelectionAvailableValue[]>;
1035
+ allOptionsSelected: boolean;
1036
+ price: {
1037
+ min: number | null;
1038
+ max: number | null;
1039
+ compareAtMin: number | null;
1040
+ compareAtMax: number | null;
1041
+ isRange: boolean;
1042
+ };
1043
+ media: {
1044
+ primaryImage: ProductDetailMedia | null;
1045
+ images: ProductDetailMedia[];
1046
+ };
1047
+ stock: {
1048
+ availableForSale: boolean;
1049
+ isUnlimited: boolean;
1050
+ stock: number | null;
1051
+ reservedStock: number | null;
1052
+ availableStock: number | null;
1053
+ };
1054
+ };
1055
+ declare class ProductSelectionCodecError extends Error {
1056
+ code: string;
1057
+ constructor(message: string);
1058
+ }
948
1059
  declare function buildProductOptionMatrix<TVariant extends ProductVariantShape = ProductVariantShape>({ options, variants, }: {
949
1060
  options: ProductOptionShape[];
950
1061
  variants?: TVariant[];
951
1062
  }): ProductOptionMatrix<TVariant>;
1063
+ declare function buildProductOptionMatrixFromDetail(detail: ProductDetail): ProductOptionMatrix<ProductDetailVariant>;
952
1064
  declare function getSelectedValueByOptionId<TVariant extends ProductVariantShape = ProductVariantShape>(matrix: ProductOptionMatrix<TVariant>, selectedValueIds: Iterable<unknown>): Map<string, string>;
953
1065
  declare function normalizeSelectedValueIds<TVariant extends ProductVariantShape = ProductVariantShape>(matrix: ProductOptionMatrix<TVariant>, selectedValueIds: Iterable<unknown>): string[];
954
1066
  declare function getAvailableOptionValues<TVariant extends ProductVariantShape = ProductVariantShape>(matrix: ProductOptionMatrix<TVariant>, optionId: string, selectedValueIds: Iterable<unknown>): ProductOptionMatrixValue[];
955
1067
  declare function resolveVariantForSelection<TVariant extends ProductVariantShape = ProductVariantShape>(matrix: ProductOptionMatrix<TVariant>, selectedValueIds: Iterable<unknown>): ProductOptionMatrixVariant<TVariant> | undefined;
1068
+ declare function normalizeProductSelection(detail: ProductDetail, selection?: ProductSelectionInput, options?: ProductSelectionCodecOptions): NormalizedProductSelection;
1069
+ declare function parseProductSelection(detail: ProductDetail, search: string | URLSearchParams | URL | null | undefined, options?: ProductSelectionCodecOptions): NormalizedProductSelection;
1070
+ declare function stringifyProductSelection(detail: ProductDetail, selection?: ProductSelectionInput, options?: ProductSelectionCodecOptions): string;
1071
+ declare function createProductSelectionCodec(detail: ProductDetail, options?: ProductSelectionCodecOptions): {
1072
+ parse: (search: string | URLSearchParams | URL | null | undefined) => NormalizedProductSelection;
1073
+ stringify: (selection?: ProductSelectionInput) => string;
1074
+ };
1075
+ declare function resolveProductSelection(detail: ProductDetail, selection?: ProductSelectionInput, options?: ProductSelectionCodecOptions): ProductSelectionResolution;
956
1076
  declare function buildProductListingProjection(product: ProductListingProductShape | null | undefined, variants: ProductVariantShape[]): ProductListingProjection;
957
1077
  /**
958
1078
  * Builds product-first listing groups for one primary option.
@@ -998,6 +1118,170 @@ type ProductListingGroupsItem = {
998
1118
  type ProductListingGroupsResponse = {
999
1119
  docs: ProductListingGroupsItem[];
1000
1120
  };
1121
+ type ProductDetailParams = {
1122
+ slug: string;
1123
+ } | {
1124
+ id: string;
1125
+ };
1126
+ interface ProductDetailVariantOptionValue {
1127
+ optionId: string | number;
1128
+ optionSlug: string;
1129
+ valueId: string | number;
1130
+ valueSlug: string;
1131
+ value?: string | null;
1132
+ }
1133
+ type ProductDetailMedia = string | number | {
1134
+ id?: string | number | null;
1135
+ url?: string | null;
1136
+ alt?: string | null;
1137
+ width?: number | null;
1138
+ height?: number | null;
1139
+ };
1140
+ interface ProductDetailVariant {
1141
+ id: string | number;
1142
+ optionKey: string;
1143
+ title?: string | null;
1144
+ displayName: string;
1145
+ sku?: string | null;
1146
+ price: number;
1147
+ compareAtPrice?: number | null;
1148
+ stock: number;
1149
+ reservedStock: number;
1150
+ isUnlimited: boolean;
1151
+ isActive: boolean;
1152
+ thumbnail?: ProductDetailMedia | null;
1153
+ images?: ProductDetailMedia[];
1154
+ optionValues: ProductDetailVariantOptionValue[];
1155
+ }
1156
+ interface ProductDetailOptionValue {
1157
+ id: string | number;
1158
+ value: string;
1159
+ slug: string;
1160
+ swatchColor?: string | null;
1161
+ thumbnail?: ProductDetailMedia | null;
1162
+ images?: ProductDetailMedia[] | null;
1163
+ }
1164
+ interface ProductDetailOption {
1165
+ id: string | number;
1166
+ title: string;
1167
+ slug: string;
1168
+ values: ProductDetailOptionValue[];
1169
+ }
1170
+ interface ProductDetailBrand {
1171
+ id: string | number;
1172
+ name: string;
1173
+ slug?: string | null;
1174
+ logo?: unknown | null;
1175
+ }
1176
+ interface ProductDetailCategory {
1177
+ id: string | number;
1178
+ title: string;
1179
+ slug?: string | null;
1180
+ }
1181
+ interface ProductDetailTag {
1182
+ id: string | number;
1183
+ title: string;
1184
+ slug?: string | null;
1185
+ }
1186
+ interface ProductDetailImage {
1187
+ id: string | number;
1188
+ url?: string | null;
1189
+ alt?: string | null;
1190
+ width?: number | null;
1191
+ height?: number | null;
1192
+ }
1193
+ interface ProductDetailVideo {
1194
+ id: string | number;
1195
+ url?: string | null;
1196
+ }
1197
+ interface ProductDetailListing {
1198
+ minPrice?: number | null;
1199
+ maxPrice?: number | null;
1200
+ minCompareAtPrice?: number | null;
1201
+ maxCompareAtPrice?: number | null;
1202
+ isPriceRange?: boolean | null;
1203
+ primaryImage?: ProductDetailMedia | null;
1204
+ availableForSale?: boolean | null;
1205
+ selectionHintVariant?: string | number | null;
1206
+ }
1207
+ interface ProductDetail {
1208
+ product: {
1209
+ id: string | number;
1210
+ slug: string;
1211
+ title: string;
1212
+ subtitle?: string | null;
1213
+ description?: string | null;
1214
+ content?: unknown;
1215
+ publishedAt?: string | null;
1216
+ status: string;
1217
+ totalInventory: number;
1218
+ totalVariants: number;
1219
+ hasOnlyDefaultVariant: boolean;
1220
+ };
1221
+ variants: ProductDetailVariant[];
1222
+ options: ProductDetailOption[];
1223
+ brand: ProductDetailBrand | null;
1224
+ categories: ProductDetailCategory[];
1225
+ tags: ProductDetailTag[];
1226
+ images: ProductDetailImage[];
1227
+ videos: ProductDetailVideo[];
1228
+ listing: ProductDetailListing;
1229
+ }
1230
+ type ProductUpsertOptionValueInput = {
1231
+ id?: string;
1232
+ value: string;
1233
+ slug?: string;
1234
+ swatchColor?: string | null;
1235
+ thumbnail?: string | null;
1236
+ images?: string[];
1237
+ metadata?: unknown;
1238
+ };
1239
+ type ProductUpsertOptionInput = {
1240
+ id?: string;
1241
+ title: string;
1242
+ slug?: string;
1243
+ values: ProductUpsertOptionValueInput[];
1244
+ };
1245
+ type ProductUpsertVariantOptionValue = string | {
1246
+ valueSlug?: string;
1247
+ valueId?: string;
1248
+ value?: string;
1249
+ };
1250
+ type ProductUpsertVariantInput = {
1251
+ id?: string;
1252
+ optionValues?: Record<string, ProductUpsertVariantOptionValue> | string[];
1253
+ sku?: string | null;
1254
+ title?: string | null;
1255
+ price: number;
1256
+ compareAtPrice?: number | null;
1257
+ stock?: number;
1258
+ isUnlimited?: boolean;
1259
+ weight?: number | null;
1260
+ requiresShipping?: boolean;
1261
+ barcode?: string | null;
1262
+ externalId?: string | null;
1263
+ isActive?: boolean;
1264
+ thumbnail?: string | null;
1265
+ images?: string[];
1266
+ metadata?: unknown;
1267
+ };
1268
+ type ProductUpsertParams = {
1269
+ product: Record<string, unknown> & {
1270
+ id?: string;
1271
+ title?: string;
1272
+ };
1273
+ options?: ProductUpsertOptionInput[];
1274
+ variants?: ProductUpsertVariantInput[];
1275
+ };
1276
+ type ProductUpsertResponse = {
1277
+ ok: true;
1278
+ product: Product;
1279
+ } | {
1280
+ ok: false;
1281
+ failedEntity: 'product' | 'option' | 'option-value' | 'variant';
1282
+ failedIndex?: number;
1283
+ message: string;
1284
+ };
1001
1285
  declare class ProductApi extends BaseApi {
1002
1286
  constructor(options: ProductApiOptions);
1003
1287
  /**
@@ -1007,6 +1291,20 @@ declare class ProductApi extends BaseApi {
1007
1291
  */
1008
1292
  stockCheck(params: StockCheckParams): Promise<StockCheckResponse>;
1009
1293
  listingGroups(params: ListingGroupsParams): Promise<ProductListingGroupsResponse>;
1294
+ /**
1295
+ * Fetch full product detail by slug or id.
1296
+ * Returns `null` on 404 regardless of reason (`not_found` / `not_published` /
1297
+ * `tenant_mismatch` / `feature_disabled`). For the reason behind a null,
1298
+ * inspect `client.lastRequestId` against backend logs.
1299
+ */
1300
+ detail(params: ProductDetailParams): Promise<ProductDetail | null>;
1301
+ /**
1302
+ * Atomically create or update a product together with its options,
1303
+ * option-values, and variants in a single transaction. Mirrors Shopify's
1304
+ * `productSet` shape and is the canonical write path for the MCP
1305
+ * `product-upsert` tool.
1306
+ */
1307
+ upsert(params: ProductUpsertParams): Promise<ProductUpsertResponse>;
1010
1308
  }
1011
1309
 
1012
1310
  type DiscountApiOptions = ServerApiOptions;
@@ -1196,6 +1494,8 @@ declare class ServerCommerceClient {
1196
1494
  readonly product: {
1197
1495
  stockCheck: (params: StockCheckParams) => Promise<StockCheckResponse>;
1198
1496
  listingGroups: (params: ListingGroupsParams) => Promise<ProductListingGroupsResponse>;
1497
+ detail: (params: ProductDetailParams) => Promise<ProductDetail | null>;
1498
+ upsert: (params: ProductUpsertParams) => Promise<ProductUpsertResponse>;
1199
1499
  };
1200
1500
  readonly cart: {
1201
1501
  get: (cartId: string) => Promise<Cart>;
@@ -1371,9 +1671,15 @@ type ReadOnlyQueryHooks = Omit<QueryHooks, 'useCreate' | 'useUpdate' | 'useRemov
1371
1671
  * Composes CollectionHooks + CustomerHooks into a single API surface.
1372
1672
  * All methods are delegated; no logic lives here.
1373
1673
  */
1674
+ interface ProductDetailCallable {
1675
+ product: {
1676
+ detail: (params: ProductDetailParams) => Promise<ProductDetail | null>;
1677
+ };
1678
+ }
1374
1679
  declare class QueryHooks extends CollectionHooks {
1375
1680
  private _customer;
1376
- constructor(queryClient: QueryClient, collectionClient: CollectionClient, customerAuth?: CustomerAuth);
1681
+ private _commerce?;
1682
+ constructor(queryClient: QueryClient, collectionClient: CollectionClient, customerAuth?: CustomerAuth, commerceClient?: ProductDetailCallable);
1377
1683
  useCustomerMe: CustomerHooks['useCustomerMe'];
1378
1684
  useCustomerLogin: CustomerHooks['useCustomerLogin'];
1379
1685
  useCustomerRegister: CustomerHooks['useCustomerRegister'];
@@ -1388,7 +1694,7 @@ declare class QueryHooks extends CollectionHooks {
1388
1694
  setCustomerData: CustomerHooks['setCustomerData'];
1389
1695
  useProductListingGroupsQuery<TData = PayloadFindResponse<ProductListingGroupsItem>>(params: {
1390
1696
  options?: ProductListingGroupsQueryOptions;
1391
- }, options?: QueryOptions<PayloadFindResponse<ProductListingGroupsItem>, TData>): _tanstack_react_query.UseQueryResult<_tanstack_react_query.NoInfer<TData>, Error>;
1697
+ }, options?: QueryOptions<PayloadFindResponse<ProductListingGroupsItem>, TData>): UseQueryResult<_tanstack_react_query.NoInfer<TData>, Error>;
1392
1698
  useSuspenseProductListingGroupsQuery<TData = PayloadFindResponse<ProductListingGroupsItem>>(params: {
1393
1699
  options?: ProductListingGroupsQueryOptions;
1394
1700
  }, options?: SuspenseQueryOptions<PayloadFindResponse<ProductListingGroupsItem>, TData>): _tanstack_react_query.UseSuspenseQueryResult<TData, Error>;
@@ -1412,6 +1718,19 @@ declare class QueryHooks extends CollectionHooks {
1412
1718
  pages?: number;
1413
1719
  staleTime?: number;
1414
1720
  }): Promise<void>;
1721
+ useProductDetail(params: {
1722
+ slug: string;
1723
+ } | {
1724
+ id: string;
1725
+ }, options?: {
1726
+ enabled?: boolean;
1727
+ }): UseQueryResult<ProductDetail | null>;
1728
+ useProductDetailBySlug(slug: string, options?: {
1729
+ enabled?: boolean;
1730
+ }): UseQueryResult<ProductDetail | null>;
1731
+ useProductDetailById(id: string, options?: {
1732
+ enabled?: boolean;
1733
+ }): UseQueryResult<ProductDetail | null>;
1415
1734
  }
1416
1735
 
1417
1736
  declare class ServerClient {
@@ -1440,4 +1759,4 @@ declare class ServerClient {
1440
1759
  */
1441
1760
  declare function createServerClient(options: ClientServerConfig): ServerClient;
1442
1761
 
1443
- export { type CustomerLoginData as $, type AddItemParams as A, type BanCustomerParams as B, CustomerAuth as C, CollectionClient as D, type CollectionDetailQueryParams as E, CollectionHooks as F, type CollectionInfiniteQueryParams as G, CollectionQueryBuilder as H, type CollectionQueryParams as I, type CommunityBan as J, type CommunityClientOptions as K, type ListingGroupsParams as L, type CommunityPost as M, ConfigError as N, type ConfirmPaymentParams as O, type ProductListingGroupsResponse as P, type ConfirmPaymentResponse as Q, type RemoveItemParams as R, type StockCheckParams as S, ConflictError as T, type UpdateItemParams as U, type ValidateDiscountParams as V, type CreateFulfillmentParams as W, type CreateOrderParams as X, type CreateReturnParams as Y, type CustomerAuthResponse as Z, CustomerHooks as _, type CustomerAuthOptions as a, type UpdateReturnParams as a$, type CustomerProfile as a0, type CustomerRefreshResponse as a1, type CustomerRegisterData as a2, type CustomerRegisterResponse as a3, type CustomerSnapshot as a4, type DebugConfig as a5, type DeepPartial as a6, DiscountApi as a7, type DiscountApiOptions as a8, type ExtractArrayType as a9, QueryHooks as aA, type QueryOptions as aB, RateLimitError as aC, type ReadOnlyQueryBuilder as aD, type RequestOptions as aE, type RetryConfig as aF, type ReturnItem as aG, type ReturnReason as aH, type ReturnWithRefundParams as aI, SDKError as aJ, type ServerApiOptions as aK, ServerClient as aL, ServerCollectionClient as aM, ServerCollectionQueryBuilder as aN, ServerCommerceClient as aO, type ServerCommerceClientOptions as aP, ServiceUnavailableError as aQ, ShippingApi as aR, type ShippingApiOptions as aS, type StockCheckResult as aT, type SuspenseInfiniteQueryOptions as aU, type SuspenseQueryOptions as aV, TimeoutError as aW, type UnbanCustomerParams as aX, type UpdateFulfillmentParams as aY, type UpdateOrderParams as aZ, type UpdateProfileData as a_, type GenerateMetadataOptions as aa, GoneError as ab, type InfiniteQueryOptions as ac, ModerationApi as ad, type ModerationApiOptions as ae, NetworkError as af, NotFoundError as ag, OrderApi as ah, type OrderApiOptions as ai, type PaginationMeta as aj, type PayloadMutationResponse as ak, PermissionError as al, ProductApi as am, type ProductApiOptions as an, type ProductListingGroup as ao, type ProductListingGroupSummary as ap, type ProductListingGroupsItem as aq, type ProductListingProductShape as ar, type ProductListingProjection as as, type ProductOptionMatrix as at, type ProductOptionMatrixOption as au, type ProductOptionMatrixValue as av, type ProductOptionMatrixVariant as aw, type ProductOptionShape as ax, type ProductOptionValueShape as ay, type ProductVariantShape as az, type StockCheckResponse as b, type UpdateTransactionParams as b0, UsageLimitError as b1, ValidationError as b2, buildProductListingGroupsByOption as b3, buildProductListingProjection as b4, buildProductOptionMatrix as b5, createAuthError as b6, createConflictError as b7, createNotFoundError as b8, createPermissionError as b9, createRateLimitError as ba, createServerClient as bb, getAvailableOptionValues as bc, getSelectedValueByOptionId as bd, isApiError as be, isAuthError as bf, isConfigError as bg, isConflictError as bh, isGoneError as bi, isNetworkError as bj, isNotFoundError as bk, isPermissionError as bl, isRateLimitError as bm, isSDKError as bn, isServiceUnavailableError as bo, isTimeoutError as bp, isUsageLimitError as bq, isValidationError as br, normalizeSelectedValueIds as bs, resolveApiUrl as bt, resolveVariantForSelection as bu, type ApplyDiscountParams as c, type RemoveDiscountParams as d, type ClearCartParams as e, type CheckoutParams as f, type PayloadFindResponse as g, type ValidateDiscountResult as h, type CalculateShippingParams as i, type CalculateShippingResult as j, type ApiQueryOptions as k, type ProductListingGroupsQueryOptions as l, CommunityClient as m, type ReadOnlyQueryHooks as n, ReadOnlyCollectionClient as o, type ClientState as p, type ClientConfig as q, ApiError as r, AuthError as s, BaseApi as t, type BulkImportFulfillmentsParams as u, type BulkImportFulfillmentsResponse as v, CartApi as w, type CartApiOptions as x, type ClientMetadata as y, type ClientServerConfig as z };
1762
+ export { type CustomerAuthResponse as $, type AddItemParams as A, type BanCustomerParams as B, CustomerAuth as C, type ClientMetadata as D, type ClientServerConfig as E, CollectionClient as F, type CollectionDetailQueryParams as G, CollectionHooks as H, type CollectionInfiniteQueryParams as I, CollectionQueryBuilder as J, type CollectionQueryParams as K, type ListingGroupsParams as L, type CommunityBan as M, type CommunityClientOptions as N, type CommunityPost as O, type ProductListingGroupsResponse as P, ConfigError as Q, type RemoveItemParams as R, type StockCheckParams as S, type ConfirmPaymentParams as T, type UpdateItemParams as U, type ValidateDiscountParams as V, type ConfirmPaymentResponse as W, ConflictError as X, type CreateFulfillmentParams as Y, type CreateOrderParams as Z, type CreateReturnParams as _, type CustomerAuthOptions as a, type ReturnItem as a$, CustomerHooks as a0, type CustomerLoginData as a1, type CustomerProfile as a2, type CustomerRefreshResponse as a3, type CustomerRegisterData as a4, type CustomerRegisterResponse as a5, type CustomerSnapshot as a6, type DebugConfig as a7, type DeepPartial as a8, DiscountApi as a9, type ProductDetailVariant as aA, type ProductDetailVariantOptionValue as aB, type ProductDetailVideo as aC, type ProductListingGroup as aD, type ProductListingGroupSummary as aE, type ProductListingGroupsItem as aF, type ProductListingProductShape as aG, type ProductListingProjection as aH, type ProductOptionMatrix as aI, type ProductOptionMatrixOption as aJ, type ProductOptionMatrixValue as aK, type ProductOptionMatrixVariant as aL, type ProductOptionShape as aM, type ProductOptionValueShape as aN, type ProductSelectionAvailableValue as aO, type ProductSelectionByOptionValue as aP, ProductSelectionCodecError as aQ, type ProductSelectionCodecOptions as aR, type ProductSelectionInput as aS, type ProductSelectionResolution as aT, type ProductVariantShape as aU, QueryHooks as aV, type QueryOptions as aW, RateLimitError as aX, type ReadOnlyQueryBuilder as aY, type RequestOptions as aZ, type RetryConfig as a_, type DiscountApiOptions as aa, type ExtractArrayType as ab, type GenerateMetadataOptions as ac, GoneError as ad, type InfiniteQueryOptions as ae, type LegacyProductSelectionParamEvent as af, ModerationApi as ag, type ModerationApiOptions as ah, NetworkError as ai, type NormalizedProductSelection as aj, NotFoundError as ak, OrderApi as al, type OrderApiOptions as am, type PaginationMeta as an, type PayloadMutationResponse as ao, PermissionError as ap, ProductApi as aq, type ProductApiOptions as ar, type ProductDetailBrand as as, type ProductDetailCategory as at, type ProductDetailImage as au, type ProductDetailListing as av, type ProductDetailMedia as aw, type ProductDetailOption as ax, type ProductDetailOptionValue as ay, type ProductDetailTag as az, type StockCheckResponse as b, type ReturnReason as b0, type ReturnWithRefundParams as b1, SDKError as b2, type ServerApiOptions as b3, ServerClient as b4, ServerCollectionClient as b5, ServerCollectionQueryBuilder as b6, ServerCommerceClient as b7, type ServerCommerceClientOptions as b8, ServiceUnavailableError as b9, getSelectedValueByOptionId as bA, isApiError as bB, isAuthError as bC, isConfigError as bD, isConflictError as bE, isGoneError as bF, isNetworkError as bG, isNotFoundError as bH, isPermissionError as bI, isRateLimitError as bJ, isSDKError as bK, isServiceUnavailableError as bL, isTimeoutError as bM, isUsageLimitError as bN, isValidationError as bO, normalizeProductSelection as bP, normalizeSelectedValueIds as bQ, parseProductSelection as bR, resolveApiUrl as bS, resolveProductSelection as bT, resolveVariantForSelection as bU, stringifyProductSelection as bV, ShippingApi as ba, type ShippingApiOptions as bb, type StockCheckResult as bc, type SuspenseInfiniteQueryOptions as bd, type SuspenseQueryOptions as be, TimeoutError as bf, type UnbanCustomerParams as bg, type UpdateFulfillmentParams as bh, type UpdateOrderParams as bi, type UpdateProfileData as bj, type UpdateReturnParams as bk, type UpdateTransactionParams as bl, UsageLimitError as bm, ValidationError as bn, buildProductListingGroupsByOption as bo, buildProductListingProjection as bp, buildProductOptionMatrix as bq, buildProductOptionMatrixFromDetail as br, createAuthError as bs, createConflictError as bt, createNotFoundError as bu, createPermissionError as bv, createProductSelectionCodec as bw, createRateLimitError as bx, createServerClient as by, getAvailableOptionValues as bz, type ProductDetailParams as c, type ProductDetail as d, type ApplyDiscountParams as e, type RemoveDiscountParams as f, type ClearCartParams as g, type CheckoutParams as h, type PayloadFindResponse as i, type ValidateDiscountResult as j, type CalculateShippingParams as k, type CalculateShippingResult as l, type ApiQueryOptions as m, type ProductListingGroupsQueryOptions as n, CommunityClient as o, type ReadOnlyQueryHooks as p, ReadOnlyCollectionClient as q, type ClientState as r, type ClientConfig as s, ApiError as t, AuthError as u, BaseApi as v, type BulkImportFulfillmentsParams as w, type BulkImportFulfillmentsResponse as x, CartApi as y, type CartApiOptions as z };