@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.
- package/README.md +125 -1
- package/dist/analytics/react.cjs.map +1 -1
- package/dist/analytics/react.js.map +1 -1
- package/dist/analytics.cjs.map +1 -1
- package/dist/analytics.js.map +1 -1
- package/dist/{const-C0GlmeJ_.d.cts → const-DAjQYNuM.d.ts} +4 -4
- package/dist/{const-D-xucnw4.d.ts → const-Dsixdi6z.d.cts} +4 -4
- package/dist/index.cjs +626 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -8
- package/dist/index.d.ts +19 -8
- package/dist/index.js +626 -13
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-BPvUmPAq.d.cts → payload-types-Ci-ZA7aM.d.cts} +153 -73
- package/dist/{payload-types-BPvUmPAq.d.ts → payload-types-Ci-ZA7aM.d.ts} +153 -73
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js.map +1 -1
- package/dist/{server-n3xK4Nks.d.cts → server-C0C8dtms.d.cts} +331 -12
- package/dist/{server-_zvihptw.d.ts → server-Cv0Q4dPQ.d.ts} +331 -12
- package/dist/server.cjs +68 -4
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +68 -4
- package/dist/server.js.map +1 -1
- package/dist/{types-BLdthWiW.d.ts → types-BWq_WlbB.d.ts} +1 -1
- package/dist/{types-DzWNu9pw.d.cts → types-zKjATmDK.d.cts} +1 -1
- package/dist/ui/canvas/server.cjs.map +1 -1
- package/dist/ui/canvas/server.js.map +1 -1
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.d.cts +3 -3
- package/dist/webhook.d.ts +3 -3
- package/package.json +1 -1
package/dist/realtime.js.map
CHANGED
|
@@ -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-
|
|
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-
|
|
7
|
-
import { P as PublicCollection, d as ServerCollection } from './const-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
|
|
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>):
|
|
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
|
|
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 };
|