@01.software/sdk 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/{const-hqVXNZoy.d.cts → const-CDpRB7XK.d.cts} +1 -1
- package/dist/{const-BO4SPN7f.d.ts → const-DQIDvvB-.d.ts} +1 -1
- package/dist/index.cjs +13 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -23
- package/dist/index.d.ts +35 -23
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-mZpmjJBz.d.cts → payload-types-C-keX5go.d.cts} +10 -37
- package/dist/{payload-types-mZpmjJBz.d.ts → payload-types-C-keX5go.d.ts} +10 -37
- 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/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-D65mzWt2.d.cts → webhook-Dqe2_xMx.d.cts} +2 -2
- package/dist/{webhook-CMi4JRCp.d.ts → webhook-DseJdRFT.d.ts} +2 -2
- package/dist/webhook.d.cts +3 -3
- package/dist/webhook.d.ts +3 -3
- package/package.json +3 -3
|
@@ -1093,15 +1093,6 @@ interface Product {
|
|
|
1093
1093
|
* Product weight (g)
|
|
1094
1094
|
*/
|
|
1095
1095
|
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
1096
|
collections?: {
|
|
1106
1097
|
docs?: (string | ProductCollection)[];
|
|
1107
1098
|
hasNextPage?: boolean;
|
|
@@ -1375,20 +1366,11 @@ interface ProductVariant {
|
|
|
1375
1366
|
weight?: number | null;
|
|
1376
1367
|
isSoldOut?: boolean | null;
|
|
1377
1368
|
images?: (string | Image)[] | null;
|
|
1378
|
-
dimensions?: {
|
|
1379
|
-
width?: number | null;
|
|
1380
|
-
height?: number | null;
|
|
1381
|
-
depth?: number | null;
|
|
1382
|
-
};
|
|
1383
1369
|
/**
|
|
1384
1370
|
* External system ID
|
|
1385
1371
|
*/
|
|
1386
1372
|
externalId?: string | null;
|
|
1387
1373
|
status?: ('active' | 'inactive') | null;
|
|
1388
|
-
/**
|
|
1389
|
-
* Sort order
|
|
1390
|
-
*/
|
|
1391
|
-
position?: number | null;
|
|
1392
1374
|
metadata?: {
|
|
1393
1375
|
[k: string]: unknown;
|
|
1394
1376
|
} | unknown[] | string | number | boolean | null;
|
|
@@ -1435,10 +1417,6 @@ interface ProductOption {
|
|
|
1435
1417
|
* Option-specific weight (g)
|
|
1436
1418
|
*/
|
|
1437
1419
|
weight?: number | null;
|
|
1438
|
-
/**
|
|
1439
|
-
* Low stock alert threshold
|
|
1440
|
-
*/
|
|
1441
|
-
lowStockThreshold?: number | null;
|
|
1442
1420
|
/**
|
|
1443
1421
|
* External system ID
|
|
1444
1422
|
*/
|
|
@@ -2690,7 +2668,7 @@ interface Music {
|
|
|
2690
2668
|
*/
|
|
2691
2669
|
artist?: string | null;
|
|
2692
2670
|
/**
|
|
2693
|
-
* Duration in seconds (auto-filled
|
|
2671
|
+
* Duration in seconds (auto-filled)
|
|
2694
2672
|
*/
|
|
2695
2673
|
duration?: number | null;
|
|
2696
2674
|
/**
|
|
@@ -3072,12 +3050,19 @@ interface FlowNodeType {
|
|
|
3072
3050
|
*/
|
|
3073
3051
|
name: string;
|
|
3074
3052
|
label: string;
|
|
3075
|
-
fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'select' | 'toggle';
|
|
3053
|
+
fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle';
|
|
3076
3054
|
options?: {
|
|
3077
3055
|
label: string;
|
|
3078
3056
|
value: string;
|
|
3079
3057
|
id?: string | null;
|
|
3080
3058
|
}[] | null;
|
|
3059
|
+
/**
|
|
3060
|
+
* Allow multiple values as an array
|
|
3061
|
+
*/
|
|
3062
|
+
hasMany?: boolean | null;
|
|
3063
|
+
/**
|
|
3064
|
+
* For has-many, separate with commas
|
|
3065
|
+
*/
|
|
3081
3066
|
defaultValue?: string | null;
|
|
3082
3067
|
required?: boolean | null;
|
|
3083
3068
|
id?: string | null;
|
|
@@ -4030,12 +4015,6 @@ interface ProductsSelect<T extends boolean = true> {
|
|
|
4030
4015
|
brand?: T;
|
|
4031
4016
|
shippingPolicy?: T;
|
|
4032
4017
|
weight?: T;
|
|
4033
|
-
dimensions?: T | {
|
|
4034
|
-
width?: T;
|
|
4035
|
-
height?: T;
|
|
4036
|
-
depth?: T;
|
|
4037
|
-
};
|
|
4038
|
-
isDigital?: T;
|
|
4039
4018
|
collections?: T;
|
|
4040
4019
|
sku?: T;
|
|
4041
4020
|
barcode?: T;
|
|
@@ -4080,14 +4059,8 @@ interface ProductVariantsSelect<T extends boolean = true> {
|
|
|
4080
4059
|
weight?: T;
|
|
4081
4060
|
isSoldOut?: T;
|
|
4082
4061
|
images?: T;
|
|
4083
|
-
dimensions?: T | {
|
|
4084
|
-
width?: T;
|
|
4085
|
-
height?: T;
|
|
4086
|
-
depth?: T;
|
|
4087
|
-
};
|
|
4088
4062
|
externalId?: T;
|
|
4089
4063
|
status?: T;
|
|
4090
|
-
position?: T;
|
|
4091
4064
|
metadata?: T;
|
|
4092
4065
|
productOptions?: T;
|
|
4093
4066
|
updatedAt?: T;
|
|
@@ -4112,7 +4085,6 @@ interface ProductOptionsSelect<T extends boolean = true> {
|
|
|
4112
4085
|
priceAdjustment?: T;
|
|
4113
4086
|
barcode?: T;
|
|
4114
4087
|
weight?: T;
|
|
4115
|
-
lowStockThreshold?: T;
|
|
4116
4088
|
externalId?: T;
|
|
4117
4089
|
metadata?: T;
|
|
4118
4090
|
updatedAt?: T;
|
|
@@ -5118,6 +5090,7 @@ interface FlowNodeTypesSelect<T extends boolean = true> {
|
|
|
5118
5090
|
value?: T;
|
|
5119
5091
|
id?: T;
|
|
5120
5092
|
};
|
|
5093
|
+
hasMany?: T;
|
|
5121
5094
|
defaultValue?: T;
|
|
5122
5095
|
required?: T;
|
|
5123
5096
|
id?: T;
|
|
@@ -1093,15 +1093,6 @@ interface Product {
|
|
|
1093
1093
|
* Product weight (g)
|
|
1094
1094
|
*/
|
|
1095
1095
|
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
1096
|
collections?: {
|
|
1106
1097
|
docs?: (string | ProductCollection)[];
|
|
1107
1098
|
hasNextPage?: boolean;
|
|
@@ -1375,20 +1366,11 @@ interface ProductVariant {
|
|
|
1375
1366
|
weight?: number | null;
|
|
1376
1367
|
isSoldOut?: boolean | null;
|
|
1377
1368
|
images?: (string | Image)[] | null;
|
|
1378
|
-
dimensions?: {
|
|
1379
|
-
width?: number | null;
|
|
1380
|
-
height?: number | null;
|
|
1381
|
-
depth?: number | null;
|
|
1382
|
-
};
|
|
1383
1369
|
/**
|
|
1384
1370
|
* External system ID
|
|
1385
1371
|
*/
|
|
1386
1372
|
externalId?: string | null;
|
|
1387
1373
|
status?: ('active' | 'inactive') | null;
|
|
1388
|
-
/**
|
|
1389
|
-
* Sort order
|
|
1390
|
-
*/
|
|
1391
|
-
position?: number | null;
|
|
1392
1374
|
metadata?: {
|
|
1393
1375
|
[k: string]: unknown;
|
|
1394
1376
|
} | unknown[] | string | number | boolean | null;
|
|
@@ -1435,10 +1417,6 @@ interface ProductOption {
|
|
|
1435
1417
|
* Option-specific weight (g)
|
|
1436
1418
|
*/
|
|
1437
1419
|
weight?: number | null;
|
|
1438
|
-
/**
|
|
1439
|
-
* Low stock alert threshold
|
|
1440
|
-
*/
|
|
1441
|
-
lowStockThreshold?: number | null;
|
|
1442
1420
|
/**
|
|
1443
1421
|
* External system ID
|
|
1444
1422
|
*/
|
|
@@ -2690,7 +2668,7 @@ interface Music {
|
|
|
2690
2668
|
*/
|
|
2691
2669
|
artist?: string | null;
|
|
2692
2670
|
/**
|
|
2693
|
-
* Duration in seconds (auto-filled
|
|
2671
|
+
* Duration in seconds (auto-filled)
|
|
2694
2672
|
*/
|
|
2695
2673
|
duration?: number | null;
|
|
2696
2674
|
/**
|
|
@@ -3072,12 +3050,19 @@ interface FlowNodeType {
|
|
|
3072
3050
|
*/
|
|
3073
3051
|
name: string;
|
|
3074
3052
|
label: string;
|
|
3075
|
-
fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'select' | 'toggle';
|
|
3053
|
+
fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle';
|
|
3076
3054
|
options?: {
|
|
3077
3055
|
label: string;
|
|
3078
3056
|
value: string;
|
|
3079
3057
|
id?: string | null;
|
|
3080
3058
|
}[] | null;
|
|
3059
|
+
/**
|
|
3060
|
+
* Allow multiple values as an array
|
|
3061
|
+
*/
|
|
3062
|
+
hasMany?: boolean | null;
|
|
3063
|
+
/**
|
|
3064
|
+
* For has-many, separate with commas
|
|
3065
|
+
*/
|
|
3081
3066
|
defaultValue?: string | null;
|
|
3082
3067
|
required?: boolean | null;
|
|
3083
3068
|
id?: string | null;
|
|
@@ -4030,12 +4015,6 @@ interface ProductsSelect<T extends boolean = true> {
|
|
|
4030
4015
|
brand?: T;
|
|
4031
4016
|
shippingPolicy?: T;
|
|
4032
4017
|
weight?: T;
|
|
4033
|
-
dimensions?: T | {
|
|
4034
|
-
width?: T;
|
|
4035
|
-
height?: T;
|
|
4036
|
-
depth?: T;
|
|
4037
|
-
};
|
|
4038
|
-
isDigital?: T;
|
|
4039
4018
|
collections?: T;
|
|
4040
4019
|
sku?: T;
|
|
4041
4020
|
barcode?: T;
|
|
@@ -4080,14 +4059,8 @@ interface ProductVariantsSelect<T extends boolean = true> {
|
|
|
4080
4059
|
weight?: T;
|
|
4081
4060
|
isSoldOut?: T;
|
|
4082
4061
|
images?: T;
|
|
4083
|
-
dimensions?: T | {
|
|
4084
|
-
width?: T;
|
|
4085
|
-
height?: T;
|
|
4086
|
-
depth?: T;
|
|
4087
|
-
};
|
|
4088
4062
|
externalId?: T;
|
|
4089
4063
|
status?: T;
|
|
4090
|
-
position?: T;
|
|
4091
4064
|
metadata?: T;
|
|
4092
4065
|
productOptions?: T;
|
|
4093
4066
|
updatedAt?: T;
|
|
@@ -4112,7 +4085,6 @@ interface ProductOptionsSelect<T extends boolean = true> {
|
|
|
4112
4085
|
priceAdjustment?: T;
|
|
4113
4086
|
barcode?: T;
|
|
4114
4087
|
weight?: T;
|
|
4115
|
-
lowStockThreshold?: T;
|
|
4116
4088
|
externalId?: T;
|
|
4117
4089
|
metadata?: T;
|
|
4118
4090
|
updatedAt?: T;
|
|
@@ -5118,6 +5090,7 @@ interface FlowNodeTypesSelect<T extends boolean = true> {
|
|
|
5118
5090
|
value?: T;
|
|
5119
5091
|
id?: T;
|
|
5120
5092
|
};
|
|
5093
|
+
hasMany?: T;
|
|
5121
5094
|
defaultValue?: T;
|
|
5122
5095
|
required?: T;
|
|
5123
5096
|
id?: T;
|
package/dist/realtime.cjs.map
CHANGED
|
@@ -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":"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","names":[]}
|
package/dist/realtime.d.cts
CHANGED
|
@@ -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-
|
|
4
|
-
import './payload-types-
|
|
3
|
+
import { P as PublicCollection } from './const-CDpRB7XK.cjs';
|
|
4
|
+
import './payload-types-C-keX5go.cjs';
|
|
5
5
|
|
|
6
6
|
interface UseRealtimeQueryOptions {
|
|
7
7
|
/** Filter events to specific collections. Empty/undefined = all collections. */
|
package/dist/realtime.d.ts
CHANGED
|
@@ -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-
|
|
4
|
-
import './payload-types-
|
|
3
|
+
import { P as PublicCollection } from './const-DQIDvvB-.js';
|
|
4
|
+
import './payload-types-C-keX5go.js';
|
|
5
5
|
|
|
6
6
|
interface UseRealtimeQueryOptions {
|
|
7
7
|
/** Filter events to specific collections. Empty/undefined = all collections. */
|
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 * 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":[]}
|
package/dist/ui/form.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { F as Form } from '../payload-types-
|
|
2
|
+
import { F as Form } from '../payload-types-C-keX5go.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-
|
|
2
|
+
import { F as Form } from '../payload-types-C-keX5go.js';
|
|
3
3
|
import { RichTextData } from './rich-text.js';
|
|
4
4
|
import '@payloadcms/richtext-lexical';
|
|
5
5
|
import '@payloadcms/richtext-lexical/lexical';
|
package/dist/ui/video.d.cts
CHANGED
|
@@ -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-
|
|
4
|
+
import { V as Video } from '../payload-types-C-keX5go.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 {
|
package/dist/ui/video.d.ts
CHANGED
|
@@ -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-
|
|
4
|
+
import { V as Video } from '../payload-types-C-keX5go.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-
|
|
2
|
-
import { C as Config } from './payload-types-
|
|
1
|
+
import { C as Collection } from './const-CDpRB7XK.cjs';
|
|
2
|
+
import { C as Config } from './payload-types-C-keX5go.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-
|
|
2
|
-
import { C as Config } from './payload-types-
|
|
1
|
+
import { C as Collection } from './const-DQIDvvB-.js';
|
|
2
|
+
import { C as Config } from './payload-types-C-keX5go.js';
|
|
3
3
|
|
|
4
4
|
type CollectionType<T extends string> = T extends keyof Config['collections'] ? Config['collections'][T] : never;
|
|
5
5
|
|
package/dist/webhook.d.cts
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-
|
|
2
|
-
import './const-
|
|
3
|
-
import './payload-types-
|
|
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-Dqe2_xMx.cjs';
|
|
2
|
+
import './const-CDpRB7XK.cjs';
|
|
3
|
+
import './payload-types-C-keX5go.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-
|
|
2
|
-
import './const-
|
|
3
|
-
import './payload-types-
|
|
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-DseJdRFT.js';
|
|
2
|
+
import './const-DQIDvvB-.js';
|
|
3
|
+
import './payload-types-C-keX5go.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@01.software/sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "01.software SDK",
|
|
5
5
|
"author": "<office@01.works>",
|
|
6
6
|
"keywords": [],
|
|
@@ -148,8 +148,8 @@
|
|
|
148
148
|
"shadcn": "^3.6.3",
|
|
149
149
|
"tsup": "^8.3.7",
|
|
150
150
|
"vitest": "^3.2.3",
|
|
151
|
-
"@repo/
|
|
152
|
-
"@repo/
|
|
151
|
+
"@repo/typescript-config": "0.0.0",
|
|
152
|
+
"@repo/eslint-config": "0.0.0"
|
|
153
153
|
},
|
|
154
154
|
"dependencies": {
|
|
155
155
|
"@payloadcms/richtext-lexical": ">=3.78.0",
|