@01.software/sdk 0.5.0 → 0.5.2

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.
@@ -92,6 +92,9 @@ interface Config {
92
92
  'payload-migrations': PayloadMigration;
93
93
  };
94
94
  collectionsJoins: {
95
+ tenants: {
96
+ members: 'users';
97
+ };
95
98
  products: {
96
99
  variants: 'product-variants';
97
100
  options: 'product-options';
@@ -381,6 +384,14 @@ interface Tenant {
381
384
  enabled?: boolean | null;
382
385
  id?: string | null;
383
386
  }[] | null;
387
+ /**
388
+ * Users connected to this tenant
389
+ */
390
+ members?: {
391
+ docs?: (string | User)[];
392
+ hasNextPage?: boolean;
393
+ totalDocs?: number;
394
+ };
384
395
  updatedAt: string;
385
396
  createdAt: string;
386
397
  }
@@ -1093,15 +1104,6 @@ interface Product {
1093
1104
  * Product weight (g)
1094
1105
  */
1095
1106
  weight?: number | null;
1096
- dimensions?: {
1097
- width?: number | null;
1098
- height?: number | null;
1099
- depth?: number | null;
1100
- };
1101
- /**
1102
- * Digital product (no shipping required)
1103
- */
1104
- isDigital?: boolean | null;
1105
1107
  collections?: {
1106
1108
  docs?: (string | ProductCollection)[];
1107
1109
  hasNextPage?: boolean;
@@ -1375,20 +1377,11 @@ interface ProductVariant {
1375
1377
  weight?: number | null;
1376
1378
  isSoldOut?: boolean | null;
1377
1379
  images?: (string | Image)[] | null;
1378
- dimensions?: {
1379
- width?: number | null;
1380
- height?: number | null;
1381
- depth?: number | null;
1382
- };
1383
1380
  /**
1384
1381
  * External system ID
1385
1382
  */
1386
1383
  externalId?: string | null;
1387
1384
  status?: ('active' | 'inactive') | null;
1388
- /**
1389
- * Sort order
1390
- */
1391
- position?: number | null;
1392
1385
  metadata?: {
1393
1386
  [k: string]: unknown;
1394
1387
  } | unknown[] | string | number | boolean | null;
@@ -1435,10 +1428,6 @@ interface ProductOption {
1435
1428
  * Option-specific weight (g)
1436
1429
  */
1437
1430
  weight?: number | null;
1438
- /**
1439
- * Low stock alert threshold
1440
- */
1441
- lowStockThreshold?: number | null;
1442
1431
  /**
1443
1432
  * External system ID
1444
1433
  */
@@ -2690,7 +2679,7 @@ interface Music {
2690
2679
  */
2691
2680
  artist?: string | null;
2692
2681
  /**
2693
- * Duration in seconds (auto-filled from YouTube)
2682
+ * Duration in seconds (auto-filled)
2694
2683
  */
2695
2684
  duration?: number | null;
2696
2685
  /**
@@ -3072,12 +3061,19 @@ interface FlowNodeType {
3072
3061
  */
3073
3062
  name: string;
3074
3063
  label: string;
3075
- fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'select' | 'toggle';
3064
+ fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle';
3076
3065
  options?: {
3077
3066
  label: string;
3078
3067
  value: string;
3079
3068
  id?: string | null;
3080
3069
  }[] | null;
3070
+ /**
3071
+ * Allow multiple values as an array
3072
+ */
3073
+ hasMany?: boolean | null;
3074
+ /**
3075
+ * For has-many, separate with commas
3076
+ */
3081
3077
  defaultValue?: string | null;
3082
3078
  required?: boolean | null;
3083
3079
  id?: string | null;
@@ -3776,6 +3772,7 @@ interface TenantsSelect<T extends boolean = true> {
3776
3772
  enabled?: T;
3777
3773
  id?: T;
3778
3774
  };
3775
+ members?: T;
3779
3776
  updatedAt?: T;
3780
3777
  createdAt?: T;
3781
3778
  }
@@ -4030,12 +4027,6 @@ interface ProductsSelect<T extends boolean = true> {
4030
4027
  brand?: T;
4031
4028
  shippingPolicy?: T;
4032
4029
  weight?: T;
4033
- dimensions?: T | {
4034
- width?: T;
4035
- height?: T;
4036
- depth?: T;
4037
- };
4038
- isDigital?: T;
4039
4030
  collections?: T;
4040
4031
  sku?: T;
4041
4032
  barcode?: T;
@@ -4080,14 +4071,8 @@ interface ProductVariantsSelect<T extends boolean = true> {
4080
4071
  weight?: T;
4081
4072
  isSoldOut?: T;
4082
4073
  images?: T;
4083
- dimensions?: T | {
4084
- width?: T;
4085
- height?: T;
4086
- depth?: T;
4087
- };
4088
4074
  externalId?: T;
4089
4075
  status?: T;
4090
- position?: T;
4091
4076
  metadata?: T;
4092
4077
  productOptions?: T;
4093
4078
  updatedAt?: T;
@@ -4112,7 +4097,6 @@ interface ProductOptionsSelect<T extends boolean = true> {
4112
4097
  priceAdjustment?: T;
4113
4098
  barcode?: T;
4114
4099
  weight?: T;
4115
- lowStockThreshold?: T;
4116
4100
  externalId?: T;
4117
4101
  metadata?: T;
4118
4102
  updatedAt?: T;
@@ -5118,6 +5102,7 @@ interface FlowNodeTypesSelect<T extends boolean = true> {
5118
5102
  value?: T;
5119
5103
  id?: T;
5120
5104
  };
5105
+ hasMany?: T;
5121
5106
  defaultValue?: T;
5122
5107
  required?: T;
5123
5108
  id?: T;
@@ -92,6 +92,9 @@ interface Config {
92
92
  'payload-migrations': PayloadMigration;
93
93
  };
94
94
  collectionsJoins: {
95
+ tenants: {
96
+ members: 'users';
97
+ };
95
98
  products: {
96
99
  variants: 'product-variants';
97
100
  options: 'product-options';
@@ -381,6 +384,14 @@ interface Tenant {
381
384
  enabled?: boolean | null;
382
385
  id?: string | null;
383
386
  }[] | null;
387
+ /**
388
+ * Users connected to this tenant
389
+ */
390
+ members?: {
391
+ docs?: (string | User)[];
392
+ hasNextPage?: boolean;
393
+ totalDocs?: number;
394
+ };
384
395
  updatedAt: string;
385
396
  createdAt: string;
386
397
  }
@@ -1093,15 +1104,6 @@ interface Product {
1093
1104
  * Product weight (g)
1094
1105
  */
1095
1106
  weight?: number | null;
1096
- dimensions?: {
1097
- width?: number | null;
1098
- height?: number | null;
1099
- depth?: number | null;
1100
- };
1101
- /**
1102
- * Digital product (no shipping required)
1103
- */
1104
- isDigital?: boolean | null;
1105
1107
  collections?: {
1106
1108
  docs?: (string | ProductCollection)[];
1107
1109
  hasNextPage?: boolean;
@@ -1375,20 +1377,11 @@ interface ProductVariant {
1375
1377
  weight?: number | null;
1376
1378
  isSoldOut?: boolean | null;
1377
1379
  images?: (string | Image)[] | null;
1378
- dimensions?: {
1379
- width?: number | null;
1380
- height?: number | null;
1381
- depth?: number | null;
1382
- };
1383
1380
  /**
1384
1381
  * External system ID
1385
1382
  */
1386
1383
  externalId?: string | null;
1387
1384
  status?: ('active' | 'inactive') | null;
1388
- /**
1389
- * Sort order
1390
- */
1391
- position?: number | null;
1392
1385
  metadata?: {
1393
1386
  [k: string]: unknown;
1394
1387
  } | unknown[] | string | number | boolean | null;
@@ -1435,10 +1428,6 @@ interface ProductOption {
1435
1428
  * Option-specific weight (g)
1436
1429
  */
1437
1430
  weight?: number | null;
1438
- /**
1439
- * Low stock alert threshold
1440
- */
1441
- lowStockThreshold?: number | null;
1442
1431
  /**
1443
1432
  * External system ID
1444
1433
  */
@@ -2690,7 +2679,7 @@ interface Music {
2690
2679
  */
2691
2680
  artist?: string | null;
2692
2681
  /**
2693
- * Duration in seconds (auto-filled from YouTube)
2682
+ * Duration in seconds (auto-filled)
2694
2683
  */
2695
2684
  duration?: number | null;
2696
2685
  /**
@@ -3072,12 +3061,19 @@ interface FlowNodeType {
3072
3061
  */
3073
3062
  name: string;
3074
3063
  label: string;
3075
- fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'select' | 'toggle';
3064
+ fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle';
3076
3065
  options?: {
3077
3066
  label: string;
3078
3067
  value: string;
3079
3068
  id?: string | null;
3080
3069
  }[] | null;
3070
+ /**
3071
+ * Allow multiple values as an array
3072
+ */
3073
+ hasMany?: boolean | null;
3074
+ /**
3075
+ * For has-many, separate with commas
3076
+ */
3081
3077
  defaultValue?: string | null;
3082
3078
  required?: boolean | null;
3083
3079
  id?: string | null;
@@ -3776,6 +3772,7 @@ interface TenantsSelect<T extends boolean = true> {
3776
3772
  enabled?: T;
3777
3773
  id?: T;
3778
3774
  };
3775
+ members?: T;
3779
3776
  updatedAt?: T;
3780
3777
  createdAt?: T;
3781
3778
  }
@@ -4030,12 +4027,6 @@ interface ProductsSelect<T extends boolean = true> {
4030
4027
  brand?: T;
4031
4028
  shippingPolicy?: T;
4032
4029
  weight?: T;
4033
- dimensions?: T | {
4034
- width?: T;
4035
- height?: T;
4036
- depth?: T;
4037
- };
4038
- isDigital?: T;
4039
4030
  collections?: T;
4040
4031
  sku?: T;
4041
4032
  barcode?: T;
@@ -4080,14 +4071,8 @@ interface ProductVariantsSelect<T extends boolean = true> {
4080
4071
  weight?: T;
4081
4072
  isSoldOut?: T;
4082
4073
  images?: T;
4083
- dimensions?: T | {
4084
- width?: T;
4085
- height?: T;
4086
- depth?: T;
4087
- };
4088
4074
  externalId?: T;
4089
4075
  status?: T;
4090
- position?: T;
4091
4076
  metadata?: T;
4092
4077
  productOptions?: T;
4093
4078
  updatedAt?: T;
@@ -4112,7 +4097,6 @@ interface ProductOptionsSelect<T extends boolean = true> {
4112
4097
  priceAdjustment?: T;
4113
4098
  barcode?: T;
4114
4099
  weight?: T;
4115
- lowStockThreshold?: T;
4116
4100
  externalId?: T;
4117
4101
  metadata?: T;
4118
4102
  updatedAt?: T;
@@ -5118,6 +5102,7 @@ interface FlowNodeTypesSelect<T extends boolean = true> {
5118
5102
  value?: T;
5119
5103
  id?: T;
5120
5104
  };
5105
+ hasMany?: T;
5121
5106
  defaultValue?: T;
5122
5107
  required?: T;
5123
5108
  id?: T;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/realtime.ts","../src/core/query/realtime-hooks.ts","../src/core/query/realtime.ts","../src/core/client/types.ts","../src/core/query/query-keys.ts"],"sourcesContent":["export { useRealtimeQuery } from './core/query/realtime-hooks'\nexport type {\n UseRealtimeQueryOptions,\n UseRealtimeQueryResult,\n RealtimeEvent,\n} from './core/query/realtime-hooks'\nexport { RealtimeConnection, type RealtimeListener } from './core/query/realtime'\n","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 * clientKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n clientKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { clientKey, getToken, collections, enabled = true } = options\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 || !clientKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n clientKey,\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 }, [clientKey, 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 clientKey: 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-Client-Key': this.clientKey,\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 { Collection, PublicCollection } from '../collection/const'\n\nexport type { Collection, PublicCollection }\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\n/**\n * API URL을 반환합니다.\n * 환경변수 SOFTWARE_API_URL 또는 NEXT_PUBLIC_SOFTWARE_API_URL로 오버라이드 가능.\n * 빌드 시 버전에 따라 기본값 결정: dev 빌드 → api-dev, 정식 → api.01.software\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 clientKey: 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\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\n// ============================================================================\n// API Response Types\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\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, boolean>\n}\n\nexport interface ApiQueryReactOptions {\n keepPreviousData?: 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// ============================================================================\n// Collection Types (re-exported from collection/const)\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'\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/realtime.ts","../src/core/query/realtime-hooks.ts","../src/core/query/realtime.ts","../src/core/client/types.ts","../src/core/query/query-keys.ts"],"sourcesContent":["export { useRealtimeQuery } from './core/query/realtime-hooks'\nexport type {\n UseRealtimeQueryOptions,\n UseRealtimeQueryResult,\n RealtimeEvent,\n} from './core/query/realtime-hooks'\nexport { RealtimeConnection, type RealtimeListener } from './core/query/realtime'\n","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 * clientKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n clientKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { clientKey, getToken, collections, enabled = true } = options\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 || !clientKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n clientKey,\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 }, [clientKey, 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 clientKey: 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-Client-Key': this.clientKey,\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 { Collection, PublicCollection } from '../collection/const'\n\nexport type { Collection, PublicCollection }\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\n/**\n * API URL을 반환합니다.\n * 환경변수 SOFTWARE_API_URL 또는 NEXT_PUBLIC_SOFTWARE_API_URL로 오버라이드 가능.\n * 빌드 시 버전에 따라 기본값 결정: dev 빌드 → api-dev, 정식 → api.01.software\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 clientKey: 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\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\n// ============================================================================\n// API Response Types\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\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, 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// ============================================================================\n// Collection Types (re-exported from collection/const)\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'\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA4C;AAC5C,yBAA+B;;;ACa/B,IAAM,0BAA0B;AAChC,IAAM,sBAAsB;AAC5B,IAAM,2BAA2B;AACjC,IAAM,uBAAuB;AAEtB,IAAM,qBAAN,MAAyB;AAAA,EAQ9B,YACU,SACA,WACA,UACA,aACR;AAJQ;AACA;AACA;AACA;AAXV,SAAQ,kBAA0C;AAClD,SAAQ,mBAAmB;AAC3B,SAAQ,kBAAkB;AAC1B,SAAQ,iBAAuD;AAC/D,SAAQ,YAAY,oBAAI,IAAsB;AAC9C,SAAQ,aAAa;AAAA,EAOlB;AAAA,EAEH,IAAI,YAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAY,IAAkC;AAC5C,SAAK,UAAU,IAAI,EAAE;AACrB,WAAO,MAAM,KAAK,UAAU,OAAO,EAAE;AAAA,EACvC;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,gBAAiB;AAE1B,SAAK,kBAAkB,IAAI,gBAAgB;AAC3C,SAAK,YAAY,KAAK,gBAAgB,MAAM;AAAA,EAC9C;AAAA,EAEA,aAAmB;AACjB,SAAK,aAAa;AAClB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,iBAAiB;AACxB,WAAK,gBAAgB,MAAM;AAC3B,WAAK,kBAAkB;AAAA,IACzB;AACA,SAAK,mBAAmB;AACxB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEc,YAAY,QAAoC;AAAA;AAhEhE;AAiEI,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,CAAC,OAAO;AACV,aAAK;AACL,YAAI,KAAK,mBAAmB,sBAAsB;AAEhD,eAAK,aAAa;AAClB,eAAK,kBAAkB;AACvB;AAAA,QACF;AACA,aAAK,kBAAkB;AACvB;AAAA,MACF;AACA,WAAK,kBAAkB;AAEvB,YAAM,WAAS,UAAK,gBAAL,mBAAkB,UAC7B,gBAAgB,KAAK,YAAY,KAAK,GAAG,CAAC,KAC1C;AACJ,YAAM,MAAM,GAAG,KAAK,OAAO,qBAAqB,MAAM;AAEtD,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,KAAK;AAAA,UAChC,SAAS;AAAA,YACP,gBAAgB,KAAK;AAAA,YACrB,eAAe,UAAU,KAAK;AAAA,UAChC;AAAA,UACA;AAAA,QACF,CAAC;AAED,YAAI,CAAC,SAAS,IAAI;AAChB,cAAI,SAAS,WAAW,KAAK;AAE3B,iBAAK,kBAAkB;AACvB;AAAA,UACF;AACA,gBAAM,IAAI,MAAM,0BAA0B,SAAS,MAAM,EAAE;AAAA,QAC7D;AAEA,YAAI,CAAC,SAAS,MAAM;AAClB,gBAAM,IAAI,MAAM,0BAA0B;AAAA,QAC5C;AAEA,aAAK,aAAa;AAClB,aAAK,mBAAmB;AAExB,cAAM,KAAK,WAAW,SAAS,MAAM,MAAM;AAAA,MAC7C,SAAQ;AACN,YAAI,OAAO,QAAS;AACpB,aAAK,aAAa;AAClB,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF;AAAA;AAAA,EAEc,WACZ,MACA,QACe;AAAA;AAxHnB;AAyHI,YAAM,SAAS,KAAK,UAAU;AAC9B,YAAM,UAAU,IAAI,YAAY;AAChC,UAAI,SAAS;AACb,UAAI,eAAe;AACnB,UAAI,cAAc;AAElB,UAAI;AACF,eAAO,MAAM;AACX,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,cAAI,QAAQ,OAAO,QAAS;AAE5B,oBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,gBAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,oBAAS,WAAM,IAAI,MAAV,YAAe;AAExB,qBAAW,QAAQ,OAAO;AACxB,gBAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,6BAAe,KAAK,MAAM,CAAC;AAAA,YAC7B,WAAW,KAAK,WAAW,QAAQ,GAAG;AACpC,8BAAgB,cAAc,OAAO,MAAM,KAAK,MAAM,CAAC;AAAA,YACzD,WAAW,SAAS,IAAI;AAEtB,kBAAI,iBAAiB,uBAAuB,aAAa;AACvD,oBAAI;AACF,wBAAM,QAAuB,KAAK,MAAM,WAAW;AACnD,6BAAW,YAAY,KAAK,WAAW;AACrC,wBAAI;AACF,+BAAS,KAAK;AAAA,oBAChB,SAAQ;AAAA,oBAER;AAAA,kBACF;AAAA,gBACF,SAAQ;AAAA,gBAER;AAAA,cACF;AACA,6BAAe;AACf,4BAAc;AAAA,YAChB;AAAA,UAEF;AAAA,QACF;AAAA,MACF,SAAQ;AAAA,MAER,UAAE;AACA,eAAO,YAAY;AACnB,aAAK,aAAa;AAClB,YAAI,CAAC,OAAO,SAAS;AACnB,eAAK,kBAAkB;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,eAAgB;AAEzB,UAAM,QAAQ,KAAK;AAAA,MACjB,0BACE,KAAK,IAAI,0BAA0B,KAAK,gBAAgB;AAAA,MAC1D;AAAA,IACF;AACA,SAAK;AAEL,SAAK,iBAAiB,WAAW,MAAM;AACrC,WAAK,iBAAiB;AACtB,WAAK,kBAAkB,IAAI,gBAAgB;AAC3C,WAAK,YAAY,KAAK,gBAAgB,MAAM;AAAA,IAC9C,GAAG,KAAK;AAAA,EACV;AACF;;;AC7KO,SAAS,gBAAwB;AACtC,MAAI,OAAO,YAAY,eAAe,QAAQ,KAAK;AACjD,UAAM,SACJ,QAAQ,IAAI,oBAAoB,QAAQ,IAAI;AAC9C,QAAI,QAAQ;AACV,aAAO,OAAO,QAAQ,OAAO,EAAE;AAAA,IACjC;AAAA,EACF;AACA,SAAO;AACT;;;ACxBO,SAAS,eAA2C,YAAe;AACxE,SAAO;AAAA,IACL,KAAK,CAAC,UAAU;AAAA,IAChB,OAAO,MAAM,CAAC,YAAY,MAAM;AAAA,IAChC,MAAM,CAAC,YAA8B,CAAC,YAAY,QAAQ,OAAO;AAAA,IACjE,SAAS,MAAM,CAAC,YAAY,QAAQ;AAAA,IACpC,QAAQ,CAAC,IAAY,YACnB,CAAC,YAAY,UAAU,IAAI,OAAO;AAAA,IACpC,WAAW,MAAM,CAAC,YAAY,UAAU;AAAA,IACxC,UAAU,CAAC,YACT,CAAC,YAAY,YAAY,OAAO;AAAA,EACpC;AACF;;;AHqBO,SAAS,iBAAiB,SAKN;AACzB,QAAM,EAAE,WAAW,UAAU,aAAa,UAAU,KAAK,IAAI;AAC7D,QAAM,kBAAc,mCAAe;AACnC,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,CAAC,WAAW,YAAY,QAAI,uBAA+B,IAAI;AACrE,QAAM,oBAAgB,qBAAkC,IAAI;AAE5D,8BAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,UAAW;AAE5B,UAAM,UAAU,cAAc;AAC9B,UAAM,OAAO,IAAI;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,kBAAc,UAAU;AAGxB,UAAM,iBAAiB,KAAK,YAAY,CAAC,UAAU;AACjD,mBAAa,KAAK;AAGlB,YAAM,OAAO,eAAe,MAAM,UAA8B;AAChE,kBAAY,kBAAkB,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,IACtD,CAAC;AAGD,UAAM,eAAe,YAAY,MAAM;AACrC,mBAAa,KAAK,SAAS;AAAA,IAC7B,GAAG,GAAI;AAEP,SAAK,QAAQ;AAEb,WAAO,MAAM;AACX,WAAK,WAAW;AAChB,qBAAe;AACf,oBAAc,YAAY;AAC1B,oBAAc,UAAU;AACxB,mBAAa,KAAK;AAAA,IACpB;AAAA,EAEF,GAAG,CAAC,WAAW,SAAS,2CAAa,KAAK,IAAI,CAAC;AAE/C,SAAO,EAAE,WAAW,UAAU;AAChC;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { R as RealtimeEvent } from './realtime-DupPIYx-.cjs';
2
2
  export { a as RealtimeConnection, b as RealtimeListener } from './realtime-DupPIYx-.cjs';
3
- import { P as PublicCollection } from './const-hqVXNZoy.cjs';
4
- import './payload-types-mZpmjJBz.cjs';
3
+ import { P as PublicCollection } from './const-Cy_NaRCl.cjs';
4
+ import './payload-types-JCbsSVeL.cjs';
5
5
 
6
6
  interface UseRealtimeQueryOptions {
7
7
  /** Filter events to specific collections. Empty/undefined = all collections. */
@@ -1,7 +1,7 @@
1
1
  import { R as RealtimeEvent } from './realtime-DupPIYx-.js';
2
2
  export { a as RealtimeConnection, b as RealtimeListener } from './realtime-DupPIYx-.js';
3
- import { P as PublicCollection } from './const-BO4SPN7f.js';
4
- import './payload-types-mZpmjJBz.js';
3
+ import { P as PublicCollection } from './const-C6vryj3j.js';
4
+ import './payload-types-JCbsSVeL.js';
5
5
 
6
6
  interface UseRealtimeQueryOptions {
7
7
  /** Filter events to specific collections. Empty/undefined = all collections. */
@@ -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 * clientKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n clientKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { clientKey, getToken, collections, enabled = true } = options\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 || !clientKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n clientKey,\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 }, [clientKey, 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 clientKey: 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-Client-Key': this.clientKey,\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 { Collection, PublicCollection } from '../collection/const'\n\nexport type { Collection, PublicCollection }\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\n/**\n * API URL을 반환합니다.\n * 환경변수 SOFTWARE_API_URL 또는 NEXT_PUBLIC_SOFTWARE_API_URL로 오버라이드 가능.\n * 빌드 시 버전에 따라 기본값 결정: dev 빌드 → api-dev, 정식 → api.01.software\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 clientKey: 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\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\n// ============================================================================\n// API Response Types\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\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, boolean>\n}\n\nexport interface ApiQueryReactOptions {\n keepPreviousData?: 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// ============================================================================\n// Collection Types (re-exported from collection/const)\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'\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"],"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 * clientKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n clientKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { clientKey, getToken, collections, enabled = true } = options\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 || !clientKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n clientKey,\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 }, [clientKey, 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 clientKey: 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-Client-Key': this.clientKey,\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 { Collection, PublicCollection } from '../collection/const'\n\nexport type { Collection, PublicCollection }\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\n/**\n * API URL을 반환합니다.\n * 환경변수 SOFTWARE_API_URL 또는 NEXT_PUBLIC_SOFTWARE_API_URL로 오버라이드 가능.\n * 빌드 시 버전에 따라 기본값 결정: dev 빌드 → api-dev, 정식 → api.01.software\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 clientKey: 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\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\n// ============================================================================\n// API Response Types\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\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, 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// ============================================================================\n// Collection Types (re-exported from collection/const)\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'\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"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { F as Form } from '../payload-types-mZpmjJBz.cjs';
2
+ import { F as Form } from '../payload-types-JCbsSVeL.cjs';
3
3
  import { RichTextData } from './rich-text.cjs';
4
4
  import '@payloadcms/richtext-lexical';
5
5
  import '@payloadcms/richtext-lexical/lexical';
package/dist/ui/form.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { F as Form } from '../payload-types-mZpmjJBz.js';
2
+ import { F as Form } from '../payload-types-JCbsSVeL.js';
3
3
  import { RichTextData } from './rich-text.js';
4
4
  import '@payloadcms/richtext-lexical';
5
5
  import '@payloadcms/richtext-lexical/lexical';
@@ -1,7 +1,7 @@
1
1
  import React, { CSSProperties } from 'react';
2
2
  import { MuxPlayerProps, MuxPlayerRefAttributes } from '@mux/mux-player-react';
3
3
  export { MuxPlayerRefAttributes as VideoPlayerRef } from '@mux/mux-player-react';
4
- import { V as Video } from '../payload-types-mZpmjJBz.cjs';
4
+ import { V as Video } from '../payload-types-JCbsSVeL.cjs';
5
5
  export { e as VideoGifOptions, V as VideoThumbnailOptions, a as getVideoGif, c as getVideoMp4Url, d as getVideoStoryboard, b as getVideoStreamUrl, g as getVideoThumbnail } from '../video-DbLL8yuc.cjs';
6
6
 
7
7
  interface VideoPlayerCSSProperties extends CSSProperties {
@@ -1,7 +1,7 @@
1
1
  import React, { CSSProperties } from 'react';
2
2
  import { MuxPlayerProps, MuxPlayerRefAttributes } from '@mux/mux-player-react';
3
3
  export { MuxPlayerRefAttributes as VideoPlayerRef } from '@mux/mux-player-react';
4
- import { V as Video } from '../payload-types-mZpmjJBz.js';
4
+ import { V as Video } from '../payload-types-JCbsSVeL.js';
5
5
  export { e as VideoGifOptions, V as VideoThumbnailOptions, a as getVideoGif, c as getVideoMp4Url, d as getVideoStoryboard, b as getVideoStreamUrl, g as getVideoThumbnail } from '../video-DbLL8yuc.js';
6
6
 
7
7
  interface VideoPlayerCSSProperties extends CSSProperties {
@@ -1,5 +1,5 @@
1
- import { C as Collection } from './const-hqVXNZoy.cjs';
2
- import { C as Config } from './payload-types-mZpmjJBz.cjs';
1
+ import { C as Collection } from './const-Cy_NaRCl.cjs';
2
+ import { C as Config } from './payload-types-JCbsSVeL.cjs';
3
3
 
4
4
  type CollectionType<T extends string> = T extends keyof Config['collections'] ? Config['collections'][T] : never;
5
5
 
@@ -1,5 +1,5 @@
1
- import { C as Collection } from './const-BO4SPN7f.js';
2
- import { C as Config } from './payload-types-mZpmjJBz.js';
1
+ import { C as Collection } from './const-C6vryj3j.js';
2
+ import { C as Config } from './payload-types-JCbsSVeL.js';
3
3
 
4
4
  type CollectionType<T extends string> = T extends keyof Config['collections'] ? Config['collections'][T] : never;
5
5
 
@@ -1,3 +1,3 @@
1
- export { a as WebhookEvent, b as WebhookHandler, W as WebhookOperation, c as WebhookOptions, d as createTypedWebhookHandler, h as handleWebhook, i as isValidWebhookEvent } from './webhook-D65mzWt2.cjs';
2
- import './const-hqVXNZoy.cjs';
3
- import './payload-types-mZpmjJBz.cjs';
1
+ export { a as WebhookEvent, b as WebhookHandler, W as WebhookOperation, c as WebhookOptions, d as createTypedWebhookHandler, h as handleWebhook, i as isValidWebhookEvent } from './webhook-CDu_s44-.cjs';
2
+ import './const-Cy_NaRCl.cjs';
3
+ import './payload-types-JCbsSVeL.cjs';
package/dist/webhook.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { a as WebhookEvent, b as WebhookHandler, W as WebhookOperation, c as WebhookOptions, d as createTypedWebhookHandler, h as handleWebhook, i as isValidWebhookEvent } from './webhook-CMi4JRCp.js';
2
- import './const-BO4SPN7f.js';
3
- import './payload-types-mZpmjJBz.js';
1
+ export { a as WebhookEvent, b as WebhookHandler, W as WebhookOperation, c as WebhookOptions, d as createTypedWebhookHandler, h as handleWebhook, i as isValidWebhookEvent } from './webhook-Dd_7Qgaa.js';
2
+ import './const-C6vryj3j.js';
3
+ import './payload-types-JCbsSVeL.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@01.software/sdk",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "01.software SDK",
5
5
  "author": "<office@01.works>",
6
6
  "keywords": [],