@vira-ui/react 4.0.1 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +88 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -94,11 +94,7 @@ function useViraState(channel, initialOrOptions) {
|
|
|
94
94
|
} catch {
|
|
95
95
|
return "";
|
|
96
96
|
}
|
|
97
|
-
}, [
|
|
98
|
-
handshakeDataOption?.company_id,
|
|
99
|
-
handshakeDataOption?.location_id,
|
|
100
|
-
handshakeDataOption?.employee_id
|
|
101
|
-
]);
|
|
97
|
+
}, [handshakeDataOption]);
|
|
102
98
|
const pool = (0, import_react.useMemo)(() => {
|
|
103
99
|
if (disablePooling) return null;
|
|
104
100
|
return (0, import_core.getViraConnectionPool)({ url: apiUrl, authToken, handshakeData: handshakeDataOption, debug });
|
|
@@ -106,6 +102,16 @@ function useViraState(channel, initialOrOptions) {
|
|
|
106
102
|
(0, import_react.useEffect)(() => {
|
|
107
103
|
if (!channel) return;
|
|
108
104
|
const handleMessage = (msg) => {
|
|
105
|
+
const msgChannel = "channel" in msg ? msg.channel : void 0;
|
|
106
|
+
if (debug) {
|
|
107
|
+
if (msg.type === "diff" && msgChannel === channel) {
|
|
108
|
+
const patchObj = msg.patch;
|
|
109
|
+
const patchKeys = patchObj && typeof patchObj === "object" ? Object.keys(patchObj) : [];
|
|
110
|
+
console.log("[VRP_CLIENT] Diff message received:", { channel, patchKeys });
|
|
111
|
+
} else {
|
|
112
|
+
console.log("[VRP_CLIENT] Message received:", { type: msg.type, channel: msgChannel, myChannel: channel, match: msgChannel === channel });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
109
115
|
switch (msg.type) {
|
|
110
116
|
case "update":
|
|
111
117
|
case "event":
|
|
@@ -130,15 +136,53 @@ function useViraState(channel, initialOrOptions) {
|
|
|
130
136
|
case "diff":
|
|
131
137
|
if (msg.channel === channel && msg.patch) {
|
|
132
138
|
setData((prev) => {
|
|
139
|
+
if (debug) {
|
|
140
|
+
console.log("[VRP_CLIENT] Applying diff:", { channel, patch: msg.patch, prevKeys: prev && typeof prev === "object" ? Object.keys(prev) : [] });
|
|
141
|
+
}
|
|
133
142
|
if (!prev) {
|
|
134
143
|
return msg.patch;
|
|
135
144
|
}
|
|
136
145
|
if (typeof prev === "object" && typeof msg.patch === "object") {
|
|
146
|
+
const patchObj = msg.patch;
|
|
147
|
+
const prevObj = prev;
|
|
148
|
+
const patchKeys = Object.keys(patchObj);
|
|
149
|
+
if (patchKeys.length === 0) {
|
|
150
|
+
if (debug) {
|
|
151
|
+
console.log("[VRP_CLIENT] Empty patch received, ignoring:", { channel });
|
|
152
|
+
}
|
|
153
|
+
return prev;
|
|
154
|
+
}
|
|
155
|
+
const keysToDelete = [];
|
|
156
|
+
for (const key in patchObj) {
|
|
157
|
+
if (patchObj[key] === null || patchObj[key] === void 0) {
|
|
158
|
+
keysToDelete.push(key);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (keysToDelete.length > 0) {
|
|
162
|
+
if (debug) {
|
|
163
|
+
console.log("[VRP_CLIENT] Processing deletions:", { channel, keysToDelete, prevCount: Object.keys(prevObj).length });
|
|
164
|
+
}
|
|
165
|
+
const result = {};
|
|
166
|
+
for (const key in prevObj) {
|
|
167
|
+
if (!keysToDelete.includes(key)) {
|
|
168
|
+
result[key] = prevObj[key];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const key in patchObj) {
|
|
172
|
+
if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== void 0) {
|
|
173
|
+
result[key] = patchObj[key];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (debug) {
|
|
177
|
+
console.log("[VRP_CLIENT] After deletion:", { channel, resultCount: Object.keys(result).length, deletedCount: keysToDelete.length });
|
|
178
|
+
}
|
|
179
|
+
return { ...result };
|
|
180
|
+
}
|
|
137
181
|
let mergedData;
|
|
138
182
|
if (useDeepMerge) {
|
|
139
|
-
mergedData = (0, import_core.deepMerge)(prev,
|
|
183
|
+
mergedData = (0, import_core.deepMerge)(prev, patchObj);
|
|
140
184
|
} else {
|
|
141
|
-
mergedData = { ...prev, ...
|
|
185
|
+
mergedData = { ...prev, ...patchObj };
|
|
142
186
|
}
|
|
143
187
|
return mergedData;
|
|
144
188
|
}
|
|
@@ -149,6 +193,9 @@ function useViraState(channel, initialOrOptions) {
|
|
|
149
193
|
}
|
|
150
194
|
};
|
|
151
195
|
if (pool) {
|
|
196
|
+
if (debug) {
|
|
197
|
+
console.log("[VRP_CLIENT] Subscribing to channel:", channel);
|
|
198
|
+
}
|
|
152
199
|
const unsubChannel = pool.subscribe(channel, handleMessage);
|
|
153
200
|
const unsubStatus = pool.onStatus((status) => {
|
|
154
201
|
setError(status.error);
|
|
@@ -247,9 +294,42 @@ function useViraState(channel, initialOrOptions) {
|
|
|
247
294
|
);
|
|
248
295
|
const sendDiff = (0, import_react.useCallback)(
|
|
249
296
|
(patch, msgId) => {
|
|
297
|
+
if (patch && typeof patch === "object") {
|
|
298
|
+
const patchObj = patch;
|
|
299
|
+
const keysToDelete = [];
|
|
300
|
+
for (const key in patchObj) {
|
|
301
|
+
if (patchObj[key] === null || patchObj[key] === void 0) {
|
|
302
|
+
keysToDelete.push(key);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (keysToDelete.length > 0) {
|
|
306
|
+
if (debug) {
|
|
307
|
+
console.log("[VRP_CLIENT] Optimistic deletion:", { channel, keysToDelete });
|
|
308
|
+
}
|
|
309
|
+
setData((prev) => {
|
|
310
|
+
if (!prev || typeof prev !== "object") return prev;
|
|
311
|
+
const prevObj = prev;
|
|
312
|
+
const result = {};
|
|
313
|
+
for (const key in prevObj) {
|
|
314
|
+
if (!keysToDelete.includes(key)) {
|
|
315
|
+
result[key] = prevObj[key];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const key in patchObj) {
|
|
319
|
+
if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== void 0) {
|
|
320
|
+
result[key] = patchObj[key];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (debug) {
|
|
324
|
+
console.log("[VRP_CLIENT] Optimistic deletion result:", { channel, resultCount: Object.keys(result).length, prevCount: Object.keys(prevObj).length });
|
|
325
|
+
}
|
|
326
|
+
return { ...result };
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
250
330
|
transportRef.current?.sendDiff(patch, msgId ?? generateMsgId());
|
|
251
331
|
},
|
|
252
|
-
[generateMsgId]
|
|
332
|
+
[generateMsgId, channel]
|
|
253
333
|
);
|
|
254
334
|
return {
|
|
255
335
|
data,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/useViraState.ts"],"sourcesContent":["/**\n * @vira-ui/react\n * \n * Vira Framework - React hooks for Vira Reactive Protocol\n * \n * This package provides React hooks for VRP, built on top of @vira-ui/core.\n */\n\nexport {\n useViraState,\n useViraStream,\n} from './useViraState';\nexport type {\n UseViraStateOptions,\n} from './useViraState';\n\n","import { useEffect, useMemo, useRef, useState, useCallback } from 'react';\nimport {\n createViraClient,\n deepMerge,\n getViraConnectionPool,\n type ViraClient,\n type Message,\n type ViraConnectionPool,\n type ViraPoolStatus,\n} from '@vira-ui/core';\n\nexport interface UseViraStateOptions<T = any> {\n /** Initial value for the state */\n initial?: T | null;\n /** Enable msgId support for idempotency */\n enableMsgId?: boolean;\n /** Callback when connection opens */\n onOpen?: () => void;\n /** Callback when connection closes */\n onClose?: (event: CloseEvent) => void;\n /** Callback when connection error occurs */\n onError?: (error: Error) => void;\n /** Use deep merge for diff patches (default: true) */\n deepMerge?: boolean;\n /** API URL (defaults to VITE_API_URL env or 'http://localhost:8080') */\n apiUrl?: string;\n /** Auth token for handshake */\n authToken?: string;\n /** Additional data to send in handshake (e.g., company_id, location_id) */\n handshakeData?: Record<string, any>;\n /** Disable connection pooling (fallback to 1 WS per channel). Default: false */\n disablePooling?: boolean;\n /** Enable debug logs for VRP (console.debug). Default: env VITE_VRP_DEBUG === 'true' */\n debug?: boolean;\n}\n\n/**\n * Unified hook for Vira Reactive Protocol state management.\n * Replaces both useViraState and useViraStream.\n *\n * @example\n * ```tsx\n * // Basic usage\n * const { data, sendUpdate } = useViraState<MyType>('my-channel');\n *\n * // With options\n * const { data, sendUpdate, sendDiff } = useViraState<User>('user:123', {\n * initial: { name: 'Guest' },\n * enableMsgId: true,\n * onOpen: () => console.log('Connected'),\n * deepMerge: true\n * });\n * ```\n */\nexport function useViraState<T = any, C extends string = string>(\n channel: C,\n initialOrOptions?: T | null | UseViraStateOptions<T>\n): {\n /** Current state data */\n data: T | null;\n /** Send an event to the server */\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n /** Send a full update (replaces state) */\n sendUpdate: (payload: T, msgId?: string) => void;\n /** Send a partial diff (merges with current state) */\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n /** Connection status */\n isConnected: boolean;\n /** Connection error, if any */\n error: Error | null;\n} {\n // Parse options (backward compatibility: second param can be initial value or options)\n const options: UseViraStateOptions<T> = useMemo(() => {\n if (initialOrOptions === null || initialOrOptions === undefined) {\n return {};\n }\n // If it's an object with known option keys, treat as options\n if (\n typeof initialOrOptions === 'object' &&\n !Array.isArray(initialOrOptions) &&\n ('enableMsgId' in initialOrOptions ||\n 'onOpen' in initialOrOptions ||\n 'onClose' in initialOrOptions ||\n 'onError' in initialOrOptions ||\n 'deepMerge' in initialOrOptions ||\n 'initial' in initialOrOptions ||\n 'apiUrl' in initialOrOptions ||\n 'authToken' in initialOrOptions ||\n 'handshakeData' in initialOrOptions ||\n 'disablePooling' in initialOrOptions ||\n 'debug' in initialOrOptions)\n ) {\n return initialOrOptions as UseViraStateOptions<T>;\n }\n // Otherwise, treat as initial value (backward compatibility)\n return { initial: initialOrOptions as T | null };\n }, [initialOrOptions]);\n\n const {\n initial = null,\n enableMsgId = false,\n onOpen,\n onClose,\n onError,\n deepMerge: useDeepMerge = true,\n apiUrl: apiUrlOption,\n authToken: authTokenOption,\n handshakeData: handshakeDataOption,\n disablePooling = false,\n debug: debugOption,\n } = options;\n\n const [data, setData] = useState<T | null>(initial);\n const [isConnected, setIsConnected] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n type Transport = {\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n sendUpdate: (payload: T, msgId?: string) => void;\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n };\n\n const transportRef = useRef<Transport | null>(null);\n const clientRef = useRef<ViraClient | null>(null); // legacy non-pooled mode only\n const sessionRef = useRef<string | null>(null);\n const msgIdCounterRef = useRef(0);\n const wasConnectedRef = useRef(false);\n const lastErrorRef = useRef<Error | null>(null);\n\n // Use provided apiUrl or fallback to env or default\n // Note: import.meta is only available in ESM, so we check safely\n const apiUrl = useMemo(() => {\n if (apiUrlOption) return apiUrlOption;\n // Try to get from env if available (Vite/bundler environment)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n if (env?.VITE_API_URL) return env.VITE_API_URL;\n } catch {\n // Ignore if import.meta is not available\n }\n return 'http://localhost:8080';\n }, [apiUrlOption]);\n\n // Get authToken from options or try to get from env\n const authToken = useMemo(() => {\n if (authTokenOption !== undefined) return authTokenOption;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return env?.VITE_AUTH_TOKEN || '';\n } catch {\n return '';\n }\n }, [authTokenOption]);\n\n const debug = useMemo(() => {\n if (debugOption !== undefined) return Boolean(debugOption);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return String(env?.VITE_VRP_DEBUG || '').toLowerCase() === 'true';\n } catch {\n return false;\n }\n }, [debugOption]);\n\n // Create a stable key for handshakeData to avoid unnecessary pool recreation\n // Use values from handshakeData instead of the object reference\n const handshakeDataKey = useMemo(() => {\n if (!handshakeDataOption) return '';\n try {\n return JSON.stringify(handshakeDataOption);\n } catch {\n return '';\n }\n }, [\n handshakeDataOption?.company_id,\n handshakeDataOption?.location_id,\n handshakeDataOption?.employee_id,\n ]);\n \n const pool: ViraConnectionPool | null = useMemo(() => {\n if (disablePooling) return null;\n return getViraConnectionPool({ url: apiUrl, authToken, handshakeData: handshakeDataOption, debug });\n }, [disablePooling, apiUrl, authToken, handshakeDataKey, debug]);\n\n\n\n\n useEffect(() => {\n if (!channel) return;\n\n const handleMessage = (msg: Message) => {\n switch (msg.type) {\n case 'update':\n case 'event':\n if (msg.channel === channel) {\n setData((prev) => {\n if (!prev) {\n return msg.data as T;\n }\n\n if (typeof prev === 'object' && typeof msg.data === 'object') {\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, msg.data as Record<string, any>) as T;\n } else {\n mergedData = { ...(prev as any), ...(msg.data as any) };\n }\n return mergedData;\n }\n\n return msg.data as T;\n });\n }\n break;\n\n case 'diff':\n if (msg.channel === channel && msg.patch) {\n setData((prev) => {\n if (!prev) {\n return msg.patch as T;\n }\n\n if (typeof prev === 'object' && typeof msg.patch === 'object') {\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, msg.patch as Record<string, any>) as T;\n } else {\n mergedData = { ...(prev as any), ...(msg.patch as any) };\n }\n return mergedData;\n }\n\n return prev;\n });\n }\n break;\n }\n };\n\n // --- Pooled mode (default) ---\n if (pool) {\n // Subscribe to messages for this channel\n const unsubChannel = pool.subscribe(channel, handleMessage);\n\n // Track shared connection status\n const unsubStatus = pool.onStatus((status: ViraPoolStatus) => {\n setError(status.error);\n setIsConnected(status.connected);\n\n // Fire callbacks only on transitions\n if (status.connected && !wasConnectedRef.current) {\n wasConnectedRef.current = true;\n onOpen?.();\n }\n if (!status.connected && wasConnectedRef.current) {\n wasConnectedRef.current = false;\n // We don't get a real CloseEvent from pooled status, so we pass a lightweight synthetic object\n const synthetic = (typeof CloseEvent !== 'undefined'\n ? new CloseEvent('close', { code: 1001, reason: 'pooled disconnect' })\n : ({ code: 1001, reason: 'pooled disconnect' } as any)) as any;\n onClose?.(synthetic);\n }\n if (status.error) {\n if (lastErrorRef.current !== status.error) {\n lastErrorRef.current = status.error;\n onError?.(status.error);\n }\n } else {\n lastErrorRef.current = null;\n }\n });\n\n // Wire transport for send* APIs\n transportRef.current = {\n sendEvent: (name, payload, msgId) => pool.sendEvent(channel, name, payload, msgId),\n sendUpdate: (payload, msgId) => pool.sendUpdate(channel, payload, msgId),\n sendDiff: (patch, msgId) => pool.sendDiff(channel, patch, msgId),\n };\n\n return () => {\n unsubStatus();\n unsubChannel();\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }\n\n // --- Legacy mode (1 WS per channel) ---\n const handleConnect = () => {\n setIsConnected(true);\n setError(null);\n if (!wasConnectedRef.current) {\n wasConnectedRef.current = true;\n }\n onOpen?.();\n };\n\n const handleDisconnect = (event?: CloseEvent) => {\n setIsConnected(false);\n wasConnectedRef.current = false;\n onClose?.(event!);\n };\n\n const handleError = (err: Error) => {\n setError(err);\n onError?.(err);\n };\n\n const client = createViraClient({\n url: apiUrl,\n channel,\n onMessage: handleMessage,\n onConnect: handleConnect,\n onDisconnect: handleDisconnect,\n onError: handleError,\n session: sessionRef.current,\n authToken,\n onSessionChange: (newSession: string | null) => {\n sessionRef.current = newSession;\n },\n });\n\n clientRef.current = client;\n transportRef.current = {\n sendEvent: (name, payload, msgId) => client.sendEvent(name, payload, msgId),\n sendUpdate: (payload, msgId) => client.sendUpdate(payload, msgId),\n sendDiff: (patch, msgId) => client.sendDiff(patch, msgId),\n };\n\n return () => {\n client.close();\n clientRef.current = null;\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }, [channel, apiUrl, authToken, onOpen, onClose, onError, useDeepMerge, pool]);\n\n // Generate msgId if enabled\n const generateMsgId = useCallback((): string | undefined => {\n if (!enableMsgId) return undefined;\n msgIdCounterRef.current++;\n return `${channel}:${Date.now()}:${msgIdCounterRef.current}`;\n }, [channel, enableMsgId]);\n\n const sendEvent = useCallback(\n (name: string, payload: any, msgId?: string) => {\n transportRef.current?.sendEvent(name, payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendUpdate = useCallback(\n (payload: T, msgId?: string) => {\n transportRef.current?.sendUpdate(payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendDiff = useCallback(\n (patch: Partial<T>, msgId?: string) => {\n transportRef.current?.sendDiff(patch, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n return {\n data,\n sendEvent,\n sendUpdate,\n sendDiff,\n isConnected,\n error,\n };\n}\n\n/**\n * Legacy hook - use useViraState instead.\n * @deprecated Use useViraState with options instead\n */\nexport function useViraStream<T = any, C extends string = string>(\n channel: C,\n options?: UseViraStateOptions<T>\n) {\n return useViraState<T, C>(channel, { ...options, initial: null });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useViraState.ts"],"sourcesContent":["/**\n * @vira-ui/react\n * \n * Vira Framework - React hooks for Vira Reactive Protocol\n * \n * This package provides React hooks for VRP, built on top of @vira-ui/core.\n */\n\nexport {\n useViraState,\n useViraStream,\n} from './useViraState';\nexport type {\n UseViraStateOptions,\n} from './useViraState';\n\n","import { useEffect, useMemo, useRef, useState, useCallback } from 'react';\nimport {\n createViraClient,\n deepMerge,\n getViraConnectionPool,\n type ViraClient,\n type Message,\n type ViraConnectionPool,\n type ViraPoolStatus,\n} from '@vira-ui/core';\n\nexport interface UseViraStateOptions<T = any> {\n /** Initial value for the state */\n initial?: T | null;\n /** Enable msgId support for idempotency */\n enableMsgId?: boolean;\n /** Callback when connection opens */\n onOpen?: () => void;\n /** Callback when connection closes */\n onClose?: (event: CloseEvent) => void;\n /** Callback when connection error occurs */\n onError?: (error: Error) => void;\n /** Use deep merge for diff patches (default: true) */\n deepMerge?: boolean;\n /** API URL (defaults to VITE_API_URL env or 'http://localhost:8080') */\n apiUrl?: string;\n /** Auth token for handshake */\n authToken?: string;\n /** Additional data to send in handshake (e.g., company_id, location_id) */\n handshakeData?: Record<string, any>;\n /** Disable connection pooling (fallback to 1 WS per channel). Default: false */\n disablePooling?: boolean;\n /** Enable debug logs for VRP (console.debug). Default: env VITE_VRP_DEBUG === 'true' */\n debug?: boolean;\n}\n\n/**\n * Unified hook for Vira Reactive Protocol state management.\n * Replaces both useViraState and useViraStream.\n *\n * @example\n * ```tsx\n * // Basic usage\n * const { data, sendUpdate } = useViraState<MyType>('my-channel');\n *\n * // With options\n * const { data, sendUpdate, sendDiff } = useViraState<User>('user:123', {\n * initial: { name: 'Guest' },\n * enableMsgId: true,\n * onOpen: () => console.log('Connected'),\n * deepMerge: true\n * });\n * ```\n */\nexport function useViraState<T = any, C extends string = string>(\n channel: C,\n initialOrOptions?: T | null | UseViraStateOptions<T>\n): {\n /** Current state data */\n data: T | null;\n /** Send an event to the server */\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n /** Send a full update (replaces state) */\n sendUpdate: (payload: T, msgId?: string) => void;\n /** Send a partial diff (merges with current state) */\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n /** Connection status */\n isConnected: boolean;\n /** Connection error, if any */\n error: Error | null;\n} {\n // Parse options (backward compatibility: second param can be initial value or options)\n const options: UseViraStateOptions<T> = useMemo(() => {\n if (initialOrOptions === null || initialOrOptions === undefined) {\n return {};\n }\n // If it's an object with known option keys, treat as options\n if (\n typeof initialOrOptions === 'object' &&\n !Array.isArray(initialOrOptions) &&\n ('enableMsgId' in initialOrOptions ||\n 'onOpen' in initialOrOptions ||\n 'onClose' in initialOrOptions ||\n 'onError' in initialOrOptions ||\n 'deepMerge' in initialOrOptions ||\n 'initial' in initialOrOptions ||\n 'apiUrl' in initialOrOptions ||\n 'authToken' in initialOrOptions ||\n 'handshakeData' in initialOrOptions ||\n 'disablePooling' in initialOrOptions ||\n 'debug' in initialOrOptions)\n ) {\n return initialOrOptions as UseViraStateOptions<T>;\n }\n // Otherwise, treat as initial value (backward compatibility)\n return { initial: initialOrOptions as T | null };\n }, [initialOrOptions]);\n\n const {\n initial = null,\n enableMsgId = false,\n onOpen,\n onClose,\n onError,\n deepMerge: useDeepMerge = true,\n apiUrl: apiUrlOption,\n authToken: authTokenOption,\n handshakeData: handshakeDataOption,\n disablePooling = false,\n debug: debugOption,\n } = options;\n\n const [data, setData] = useState<T | null>(initial);\n const [isConnected, setIsConnected] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n type Transport = {\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n sendUpdate: (payload: T, msgId?: string) => void;\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n };\n\n const transportRef = useRef<Transport | null>(null);\n const clientRef = useRef<ViraClient | null>(null); // legacy non-pooled mode only\n const sessionRef = useRef<string | null>(null);\n const msgIdCounterRef = useRef(0);\n const wasConnectedRef = useRef(false);\n const lastErrorRef = useRef<Error | null>(null);\n\n // Use provided apiUrl or fallback to env or default\n // Note: import.meta is only available in ESM, so we check safely\n const apiUrl = useMemo(() => {\n if (apiUrlOption) return apiUrlOption;\n // Try to get from env if available (Vite/bundler environment)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n if (env?.VITE_API_URL) return env.VITE_API_URL;\n } catch {\n // Ignore if import.meta is not available\n }\n return 'http://localhost:8080';\n }, [apiUrlOption]);\n\n // Get authToken from options or try to get from env\n const authToken = useMemo(() => {\n if (authTokenOption !== undefined) return authTokenOption;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return env?.VITE_AUTH_TOKEN || '';\n } catch {\n return '';\n }\n }, [authTokenOption]);\n\n const debug = useMemo(() => {\n if (debugOption !== undefined) return Boolean(debugOption);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return String(env?.VITE_VRP_DEBUG || '').toLowerCase() === 'true';\n } catch {\n return false;\n }\n }, [debugOption]);\n\n // Create a stable key for handshakeData to avoid unnecessary pool recreation\n // Use values from handshakeData instead of the object reference\n const handshakeDataKey = useMemo(() => {\n if (!handshakeDataOption) return '';\n try {\n return JSON.stringify(handshakeDataOption);\n } catch {\n return '';\n }\n }, [handshakeDataOption]);\n \n const pool: ViraConnectionPool | null = useMemo(() => {\n if (disablePooling) return null;\n return getViraConnectionPool({ url: apiUrl, authToken, handshakeData: handshakeDataOption, debug });\n }, [disablePooling, apiUrl, authToken, handshakeDataKey, debug]);\n\n\n\n\n useEffect(() => {\n if (!channel) return;\n\n const handleMessage = (msg: Message) => {\n const msgChannel = 'channel' in msg ? msg.channel : undefined;\n if (debug) {\n if (msg.type === 'diff' && msgChannel === channel) {\n const patchObj = msg.patch as any;\n const patchKeys = patchObj && typeof patchObj === 'object' ? Object.keys(patchObj) : [];\n console.log('[VRP_CLIENT] Diff message received:', { channel, patchKeys });\n } else {\n console.log('[VRP_CLIENT] Message received:', { type: msg.type, channel: msgChannel, myChannel: channel, match: msgChannel === channel });\n }\n }\n switch (msg.type) {\n case 'update':\n case 'event':\n if (msg.channel === channel) {\n setData((prev) => {\n if (!prev) {\n return msg.data as T;\n }\n\n if (typeof prev === 'object' && typeof msg.data === 'object') {\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, msg.data as Record<string, any>) as T;\n } else {\n mergedData = { ...(prev as any), ...(msg.data as any) };\n }\n return mergedData;\n }\n\n return msg.data as T;\n });\n }\n break;\n\n case 'diff':\n if (msg.channel === channel && msg.patch) {\n setData((prev) => {\n if (debug) {\n console.log('[VRP_CLIENT] Applying diff:', { channel, patch: msg.patch, prevKeys: prev && typeof prev === 'object' ? Object.keys(prev as any) : [] });\n }\n if (!prev) {\n return msg.patch as T;\n }\n\n if (typeof prev === 'object' && typeof msg.patch === 'object') {\n const patchObj = msg.patch as Record<string, any>;\n const prevObj = prev as Record<string, any>;\n \n // If patch is empty, ignore it (might be a backend issue)\n const patchKeys = Object.keys(patchObj);\n if (patchKeys.length === 0) {\n if (debug) {\n console.log('[VRP_CLIENT] Empty patch received, ignoring:', { channel });\n }\n return prev;\n }\n \n // Check for deletions first (null values in patch)\n const keysToDelete: string[] = [];\n for (const key in patchObj) {\n if (patchObj[key] === null || patchObj[key] === undefined) {\n keysToDelete.push(key);\n }\n }\n \n // If we have deletions, create new object without deleted keys\n if (keysToDelete.length > 0) {\n if (debug) {\n console.log('[VRP_CLIENT] Processing deletions:', { channel, keysToDelete, prevCount: Object.keys(prevObj).length });\n }\n \n const result: Record<string, any> = {};\n // Copy all keys from prevObj except deleted ones\n for (const key in prevObj) {\n if (!keysToDelete.includes(key)) {\n result[key] = prevObj[key];\n }\n }\n // Apply non-null updates from patch\n for (const key in patchObj) {\n if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== undefined) {\n result[key] = patchObj[key];\n }\n }\n \n if (debug) {\n console.log('[VRP_CLIENT] After deletion:', { channel, resultCount: Object.keys(result).length, deletedCount: keysToDelete.length });\n }\n \n // Force new object reference to trigger React re-render\n return { ...result } as T;\n }\n \n // No deletions, just merge updates\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, patchObj) as T;\n } else {\n mergedData = { ...(prev as any), ...patchObj };\n }\n \n return mergedData;\n }\n\n return prev;\n });\n }\n break;\n }\n };\n\n // --- Pooled mode (default) ---\n if (pool) {\n if (debug) {\n console.log('[VRP_CLIENT] Subscribing to channel:', channel);\n }\n // Subscribe to messages for this channel\n const unsubChannel = pool.subscribe(channel, handleMessage);\n\n // Track shared connection status\n const unsubStatus = pool.onStatus((status: ViraPoolStatus) => {\n setError(status.error);\n setIsConnected(status.connected);\n\n // Fire callbacks only on transitions\n if (status.connected && !wasConnectedRef.current) {\n wasConnectedRef.current = true;\n onOpen?.();\n }\n if (!status.connected && wasConnectedRef.current) {\n wasConnectedRef.current = false;\n // We don't get a real CloseEvent from pooled status, so we pass a lightweight synthetic object\n const synthetic = (typeof CloseEvent !== 'undefined'\n ? new CloseEvent('close', { code: 1001, reason: 'pooled disconnect' })\n : ({ code: 1001, reason: 'pooled disconnect' } as any)) as any;\n onClose?.(synthetic);\n }\n if (status.error) {\n if (lastErrorRef.current !== status.error) {\n lastErrorRef.current = status.error;\n onError?.(status.error);\n }\n } else {\n lastErrorRef.current = null;\n }\n });\n\n // Wire transport for send* APIs\n transportRef.current = {\n sendEvent: (name, payload, msgId) => pool.sendEvent(channel, name, payload, msgId),\n sendUpdate: (payload, msgId) => pool.sendUpdate(channel, payload, msgId),\n sendDiff: (patch, msgId) => pool.sendDiff(channel, patch, msgId),\n };\n\n return () => {\n unsubStatus();\n unsubChannel();\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }\n\n // --- Legacy mode (1 WS per channel) ---\n const handleConnect = () => {\n setIsConnected(true);\n setError(null);\n if (!wasConnectedRef.current) {\n wasConnectedRef.current = true;\n }\n onOpen?.();\n };\n\n const handleDisconnect = (event?: CloseEvent) => {\n setIsConnected(false);\n wasConnectedRef.current = false;\n onClose?.(event!);\n };\n\n const handleError = (err: Error) => {\n setError(err);\n onError?.(err);\n };\n\n const client = createViraClient({\n url: apiUrl,\n channel,\n onMessage: handleMessage,\n onConnect: handleConnect,\n onDisconnect: handleDisconnect,\n onError: handleError,\n session: sessionRef.current,\n authToken,\n onSessionChange: (newSession: string | null) => {\n sessionRef.current = newSession;\n },\n });\n\n clientRef.current = client;\n transportRef.current = {\n sendEvent: (name, payload, msgId) => client.sendEvent(name, payload, msgId),\n sendUpdate: (payload, msgId) => client.sendUpdate(payload, msgId),\n sendDiff: (patch, msgId) => client.sendDiff(patch, msgId),\n };\n\n return () => {\n client.close();\n clientRef.current = null;\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }, [channel, apiUrl, authToken, onOpen, onClose, onError, useDeepMerge, pool]);\n\n // Generate msgId if enabled\n const generateMsgId = useCallback((): string | undefined => {\n if (!enableMsgId) return undefined;\n msgIdCounterRef.current++;\n return `${channel}:${Date.now()}:${msgIdCounterRef.current}`;\n }, [channel, enableMsgId]);\n\n const sendEvent = useCallback(\n (name: string, payload: any, msgId?: string) => {\n transportRef.current?.sendEvent(name, payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendUpdate = useCallback(\n (payload: T, msgId?: string) => {\n transportRef.current?.sendUpdate(payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendDiff = useCallback(\n (patch: Partial<T>, msgId?: string) => {\n // Apply optimistic update immediately for deletions\n if (patch && typeof patch === 'object') {\n const patchObj = patch as Record<string, any>;\n const keysToDelete: string[] = [];\n for (const key in patchObj) {\n if (patchObj[key] === null || patchObj[key] === undefined) {\n keysToDelete.push(key);\n }\n }\n if (keysToDelete.length > 0) {\n if (debug) {\n console.log('[VRP_CLIENT] Optimistic deletion:', { channel, keysToDelete });\n }\n setData((prev) => {\n if (!prev || typeof prev !== 'object') return prev;\n const prevObj = prev as Record<string, any>;\n const result: Record<string, any> = {};\n // Copy all keys except deleted ones\n for (const key in prevObj) {\n if (!keysToDelete.includes(key)) {\n result[key] = prevObj[key];\n }\n }\n // Apply non-null updates from patch\n for (const key in patchObj) {\n if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== undefined) {\n result[key] = patchObj[key];\n }\n }\n if (debug) {\n console.log('[VRP_CLIENT] Optimistic deletion result:', { channel, resultCount: Object.keys(result).length, prevCount: Object.keys(prevObj).length });\n }\n // Force new object reference\n return { ...result } as T;\n });\n }\n }\n transportRef.current?.sendDiff(patch, msgId ?? generateMsgId());\n },\n [generateMsgId, channel]\n );\n\n return {\n data,\n sendEvent,\n sendUpdate,\n sendDiff,\n isConnected,\n error,\n };\n}\n\n/**\n * Legacy hook - use useViraState instead.\n * @deprecated Use useViraState with options instead\n */\nexport function useViraStream<T = any, C extends string = string>(\n channel: C,\n options?: UseViraStateOptions<T>\n) {\n return useViraState<T, C>(channel, { ...options, initial: null });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -71,11 +71,7 @@ function useViraState(channel, initialOrOptions) {
|
|
|
71
71
|
} catch {
|
|
72
72
|
return "";
|
|
73
73
|
}
|
|
74
|
-
}, [
|
|
75
|
-
handshakeDataOption?.company_id,
|
|
76
|
-
handshakeDataOption?.location_id,
|
|
77
|
-
handshakeDataOption?.employee_id
|
|
78
|
-
]);
|
|
74
|
+
}, [handshakeDataOption]);
|
|
79
75
|
const pool = useMemo(() => {
|
|
80
76
|
if (disablePooling) return null;
|
|
81
77
|
return getViraConnectionPool({ url: apiUrl, authToken, handshakeData: handshakeDataOption, debug });
|
|
@@ -83,6 +79,16 @@ function useViraState(channel, initialOrOptions) {
|
|
|
83
79
|
useEffect(() => {
|
|
84
80
|
if (!channel) return;
|
|
85
81
|
const handleMessage = (msg) => {
|
|
82
|
+
const msgChannel = "channel" in msg ? msg.channel : void 0;
|
|
83
|
+
if (debug) {
|
|
84
|
+
if (msg.type === "diff" && msgChannel === channel) {
|
|
85
|
+
const patchObj = msg.patch;
|
|
86
|
+
const patchKeys = patchObj && typeof patchObj === "object" ? Object.keys(patchObj) : [];
|
|
87
|
+
console.log("[VRP_CLIENT] Diff message received:", { channel, patchKeys });
|
|
88
|
+
} else {
|
|
89
|
+
console.log("[VRP_CLIENT] Message received:", { type: msg.type, channel: msgChannel, myChannel: channel, match: msgChannel === channel });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
86
92
|
switch (msg.type) {
|
|
87
93
|
case "update":
|
|
88
94
|
case "event":
|
|
@@ -107,15 +113,53 @@ function useViraState(channel, initialOrOptions) {
|
|
|
107
113
|
case "diff":
|
|
108
114
|
if (msg.channel === channel && msg.patch) {
|
|
109
115
|
setData((prev) => {
|
|
116
|
+
if (debug) {
|
|
117
|
+
console.log("[VRP_CLIENT] Applying diff:", { channel, patch: msg.patch, prevKeys: prev && typeof prev === "object" ? Object.keys(prev) : [] });
|
|
118
|
+
}
|
|
110
119
|
if (!prev) {
|
|
111
120
|
return msg.patch;
|
|
112
121
|
}
|
|
113
122
|
if (typeof prev === "object" && typeof msg.patch === "object") {
|
|
123
|
+
const patchObj = msg.patch;
|
|
124
|
+
const prevObj = prev;
|
|
125
|
+
const patchKeys = Object.keys(patchObj);
|
|
126
|
+
if (patchKeys.length === 0) {
|
|
127
|
+
if (debug) {
|
|
128
|
+
console.log("[VRP_CLIENT] Empty patch received, ignoring:", { channel });
|
|
129
|
+
}
|
|
130
|
+
return prev;
|
|
131
|
+
}
|
|
132
|
+
const keysToDelete = [];
|
|
133
|
+
for (const key in patchObj) {
|
|
134
|
+
if (patchObj[key] === null || patchObj[key] === void 0) {
|
|
135
|
+
keysToDelete.push(key);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (keysToDelete.length > 0) {
|
|
139
|
+
if (debug) {
|
|
140
|
+
console.log("[VRP_CLIENT] Processing deletions:", { channel, keysToDelete, prevCount: Object.keys(prevObj).length });
|
|
141
|
+
}
|
|
142
|
+
const result = {};
|
|
143
|
+
for (const key in prevObj) {
|
|
144
|
+
if (!keysToDelete.includes(key)) {
|
|
145
|
+
result[key] = prevObj[key];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const key in patchObj) {
|
|
149
|
+
if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== void 0) {
|
|
150
|
+
result[key] = patchObj[key];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (debug) {
|
|
154
|
+
console.log("[VRP_CLIENT] After deletion:", { channel, resultCount: Object.keys(result).length, deletedCount: keysToDelete.length });
|
|
155
|
+
}
|
|
156
|
+
return { ...result };
|
|
157
|
+
}
|
|
114
158
|
let mergedData;
|
|
115
159
|
if (useDeepMerge) {
|
|
116
|
-
mergedData = deepMerge(prev,
|
|
160
|
+
mergedData = deepMerge(prev, patchObj);
|
|
117
161
|
} else {
|
|
118
|
-
mergedData = { ...prev, ...
|
|
162
|
+
mergedData = { ...prev, ...patchObj };
|
|
119
163
|
}
|
|
120
164
|
return mergedData;
|
|
121
165
|
}
|
|
@@ -126,6 +170,9 @@ function useViraState(channel, initialOrOptions) {
|
|
|
126
170
|
}
|
|
127
171
|
};
|
|
128
172
|
if (pool) {
|
|
173
|
+
if (debug) {
|
|
174
|
+
console.log("[VRP_CLIENT] Subscribing to channel:", channel);
|
|
175
|
+
}
|
|
129
176
|
const unsubChannel = pool.subscribe(channel, handleMessage);
|
|
130
177
|
const unsubStatus = pool.onStatus((status) => {
|
|
131
178
|
setError(status.error);
|
|
@@ -224,9 +271,42 @@ function useViraState(channel, initialOrOptions) {
|
|
|
224
271
|
);
|
|
225
272
|
const sendDiff = useCallback(
|
|
226
273
|
(patch, msgId) => {
|
|
274
|
+
if (patch && typeof patch === "object") {
|
|
275
|
+
const patchObj = patch;
|
|
276
|
+
const keysToDelete = [];
|
|
277
|
+
for (const key in patchObj) {
|
|
278
|
+
if (patchObj[key] === null || patchObj[key] === void 0) {
|
|
279
|
+
keysToDelete.push(key);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (keysToDelete.length > 0) {
|
|
283
|
+
if (debug) {
|
|
284
|
+
console.log("[VRP_CLIENT] Optimistic deletion:", { channel, keysToDelete });
|
|
285
|
+
}
|
|
286
|
+
setData((prev) => {
|
|
287
|
+
if (!prev || typeof prev !== "object") return prev;
|
|
288
|
+
const prevObj = prev;
|
|
289
|
+
const result = {};
|
|
290
|
+
for (const key in prevObj) {
|
|
291
|
+
if (!keysToDelete.includes(key)) {
|
|
292
|
+
result[key] = prevObj[key];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
for (const key in patchObj) {
|
|
296
|
+
if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== void 0) {
|
|
297
|
+
result[key] = patchObj[key];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (debug) {
|
|
301
|
+
console.log("[VRP_CLIENT] Optimistic deletion result:", { channel, resultCount: Object.keys(result).length, prevCount: Object.keys(prevObj).length });
|
|
302
|
+
}
|
|
303
|
+
return { ...result };
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
227
307
|
transportRef.current?.sendDiff(patch, msgId ?? generateMsgId());
|
|
228
308
|
},
|
|
229
|
-
[generateMsgId]
|
|
309
|
+
[generateMsgId, channel]
|
|
230
310
|
);
|
|
231
311
|
return {
|
|
232
312
|
data,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useViraState.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, useCallback } from 'react';\nimport {\n createViraClient,\n deepMerge,\n getViraConnectionPool,\n type ViraClient,\n type Message,\n type ViraConnectionPool,\n type ViraPoolStatus,\n} from '@vira-ui/core';\n\nexport interface UseViraStateOptions<T = any> {\n /** Initial value for the state */\n initial?: T | null;\n /** Enable msgId support for idempotency */\n enableMsgId?: boolean;\n /** Callback when connection opens */\n onOpen?: () => void;\n /** Callback when connection closes */\n onClose?: (event: CloseEvent) => void;\n /** Callback when connection error occurs */\n onError?: (error: Error) => void;\n /** Use deep merge for diff patches (default: true) */\n deepMerge?: boolean;\n /** API URL (defaults to VITE_API_URL env or 'http://localhost:8080') */\n apiUrl?: string;\n /** Auth token for handshake */\n authToken?: string;\n /** Additional data to send in handshake (e.g., company_id, location_id) */\n handshakeData?: Record<string, any>;\n /** Disable connection pooling (fallback to 1 WS per channel). Default: false */\n disablePooling?: boolean;\n /** Enable debug logs for VRP (console.debug). Default: env VITE_VRP_DEBUG === 'true' */\n debug?: boolean;\n}\n\n/**\n * Unified hook for Vira Reactive Protocol state management.\n * Replaces both useViraState and useViraStream.\n *\n * @example\n * ```tsx\n * // Basic usage\n * const { data, sendUpdate } = useViraState<MyType>('my-channel');\n *\n * // With options\n * const { data, sendUpdate, sendDiff } = useViraState<User>('user:123', {\n * initial: { name: 'Guest' },\n * enableMsgId: true,\n * onOpen: () => console.log('Connected'),\n * deepMerge: true\n * });\n * ```\n */\nexport function useViraState<T = any, C extends string = string>(\n channel: C,\n initialOrOptions?: T | null | UseViraStateOptions<T>\n): {\n /** Current state data */\n data: T | null;\n /** Send an event to the server */\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n /** Send a full update (replaces state) */\n sendUpdate: (payload: T, msgId?: string) => void;\n /** Send a partial diff (merges with current state) */\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n /** Connection status */\n isConnected: boolean;\n /** Connection error, if any */\n error: Error | null;\n} {\n // Parse options (backward compatibility: second param can be initial value or options)\n const options: UseViraStateOptions<T> = useMemo(() => {\n if (initialOrOptions === null || initialOrOptions === undefined) {\n return {};\n }\n // If it's an object with known option keys, treat as options\n if (\n typeof initialOrOptions === 'object' &&\n !Array.isArray(initialOrOptions) &&\n ('enableMsgId' in initialOrOptions ||\n 'onOpen' in initialOrOptions ||\n 'onClose' in initialOrOptions ||\n 'onError' in initialOrOptions ||\n 'deepMerge' in initialOrOptions ||\n 'initial' in initialOrOptions ||\n 'apiUrl' in initialOrOptions ||\n 'authToken' in initialOrOptions ||\n 'handshakeData' in initialOrOptions ||\n 'disablePooling' in initialOrOptions ||\n 'debug' in initialOrOptions)\n ) {\n return initialOrOptions as UseViraStateOptions<T>;\n }\n // Otherwise, treat as initial value (backward compatibility)\n return { initial: initialOrOptions as T | null };\n }, [initialOrOptions]);\n\n const {\n initial = null,\n enableMsgId = false,\n onOpen,\n onClose,\n onError,\n deepMerge: useDeepMerge = true,\n apiUrl: apiUrlOption,\n authToken: authTokenOption,\n handshakeData: handshakeDataOption,\n disablePooling = false,\n debug: debugOption,\n } = options;\n\n const [data, setData] = useState<T | null>(initial);\n const [isConnected, setIsConnected] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n type Transport = {\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n sendUpdate: (payload: T, msgId?: string) => void;\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n };\n\n const transportRef = useRef<Transport | null>(null);\n const clientRef = useRef<ViraClient | null>(null); // legacy non-pooled mode only\n const sessionRef = useRef<string | null>(null);\n const msgIdCounterRef = useRef(0);\n const wasConnectedRef = useRef(false);\n const lastErrorRef = useRef<Error | null>(null);\n\n // Use provided apiUrl or fallback to env or default\n // Note: import.meta is only available in ESM, so we check safely\n const apiUrl = useMemo(() => {\n if (apiUrlOption) return apiUrlOption;\n // Try to get from env if available (Vite/bundler environment)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n if (env?.VITE_API_URL) return env.VITE_API_URL;\n } catch {\n // Ignore if import.meta is not available\n }\n return 'http://localhost:8080';\n }, [apiUrlOption]);\n\n // Get authToken from options or try to get from env\n const authToken = useMemo(() => {\n if (authTokenOption !== undefined) return authTokenOption;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return env?.VITE_AUTH_TOKEN || '';\n } catch {\n return '';\n }\n }, [authTokenOption]);\n\n const debug = useMemo(() => {\n if (debugOption !== undefined) return Boolean(debugOption);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return String(env?.VITE_VRP_DEBUG || '').toLowerCase() === 'true';\n } catch {\n return false;\n }\n }, [debugOption]);\n\n // Create a stable key for handshakeData to avoid unnecessary pool recreation\n // Use values from handshakeData instead of the object reference\n const handshakeDataKey = useMemo(() => {\n if (!handshakeDataOption) return '';\n try {\n return JSON.stringify(handshakeDataOption);\n } catch {\n return '';\n }\n }, [\n handshakeDataOption?.company_id,\n handshakeDataOption?.location_id,\n handshakeDataOption?.employee_id,\n ]);\n \n const pool: ViraConnectionPool | null = useMemo(() => {\n if (disablePooling) return null;\n return getViraConnectionPool({ url: apiUrl, authToken, handshakeData: handshakeDataOption, debug });\n }, [disablePooling, apiUrl, authToken, handshakeDataKey, debug]);\n\n\n\n\n useEffect(() => {\n if (!channel) return;\n\n const handleMessage = (msg: Message) => {\n switch (msg.type) {\n case 'update':\n case 'event':\n if (msg.channel === channel) {\n setData((prev) => {\n if (!prev) {\n return msg.data as T;\n }\n\n if (typeof prev === 'object' && typeof msg.data === 'object') {\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, msg.data as Record<string, any>) as T;\n } else {\n mergedData = { ...(prev as any), ...(msg.data as any) };\n }\n return mergedData;\n }\n\n return msg.data as T;\n });\n }\n break;\n\n case 'diff':\n if (msg.channel === channel && msg.patch) {\n setData((prev) => {\n if (!prev) {\n return msg.patch as T;\n }\n\n if (typeof prev === 'object' && typeof msg.patch === 'object') {\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, msg.patch as Record<string, any>) as T;\n } else {\n mergedData = { ...(prev as any), ...(msg.patch as any) };\n }\n return mergedData;\n }\n\n return prev;\n });\n }\n break;\n }\n };\n\n // --- Pooled mode (default) ---\n if (pool) {\n // Subscribe to messages for this channel\n const unsubChannel = pool.subscribe(channel, handleMessage);\n\n // Track shared connection status\n const unsubStatus = pool.onStatus((status: ViraPoolStatus) => {\n setError(status.error);\n setIsConnected(status.connected);\n\n // Fire callbacks only on transitions\n if (status.connected && !wasConnectedRef.current) {\n wasConnectedRef.current = true;\n onOpen?.();\n }\n if (!status.connected && wasConnectedRef.current) {\n wasConnectedRef.current = false;\n // We don't get a real CloseEvent from pooled status, so we pass a lightweight synthetic object\n const synthetic = (typeof CloseEvent !== 'undefined'\n ? new CloseEvent('close', { code: 1001, reason: 'pooled disconnect' })\n : ({ code: 1001, reason: 'pooled disconnect' } as any)) as any;\n onClose?.(synthetic);\n }\n if (status.error) {\n if (lastErrorRef.current !== status.error) {\n lastErrorRef.current = status.error;\n onError?.(status.error);\n }\n } else {\n lastErrorRef.current = null;\n }\n });\n\n // Wire transport for send* APIs\n transportRef.current = {\n sendEvent: (name, payload, msgId) => pool.sendEvent(channel, name, payload, msgId),\n sendUpdate: (payload, msgId) => pool.sendUpdate(channel, payload, msgId),\n sendDiff: (patch, msgId) => pool.sendDiff(channel, patch, msgId),\n };\n\n return () => {\n unsubStatus();\n unsubChannel();\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }\n\n // --- Legacy mode (1 WS per channel) ---\n const handleConnect = () => {\n setIsConnected(true);\n setError(null);\n if (!wasConnectedRef.current) {\n wasConnectedRef.current = true;\n }\n onOpen?.();\n };\n\n const handleDisconnect = (event?: CloseEvent) => {\n setIsConnected(false);\n wasConnectedRef.current = false;\n onClose?.(event!);\n };\n\n const handleError = (err: Error) => {\n setError(err);\n onError?.(err);\n };\n\n const client = createViraClient({\n url: apiUrl,\n channel,\n onMessage: handleMessage,\n onConnect: handleConnect,\n onDisconnect: handleDisconnect,\n onError: handleError,\n session: sessionRef.current,\n authToken,\n onSessionChange: (newSession: string | null) => {\n sessionRef.current = newSession;\n },\n });\n\n clientRef.current = client;\n transportRef.current = {\n sendEvent: (name, payload, msgId) => client.sendEvent(name, payload, msgId),\n sendUpdate: (payload, msgId) => client.sendUpdate(payload, msgId),\n sendDiff: (patch, msgId) => client.sendDiff(patch, msgId),\n };\n\n return () => {\n client.close();\n clientRef.current = null;\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }, [channel, apiUrl, authToken, onOpen, onClose, onError, useDeepMerge, pool]);\n\n // Generate msgId if enabled\n const generateMsgId = useCallback((): string | undefined => {\n if (!enableMsgId) return undefined;\n msgIdCounterRef.current++;\n return `${channel}:${Date.now()}:${msgIdCounterRef.current}`;\n }, [channel, enableMsgId]);\n\n const sendEvent = useCallback(\n (name: string, payload: any, msgId?: string) => {\n transportRef.current?.sendEvent(name, payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendUpdate = useCallback(\n (payload: T, msgId?: string) => {\n transportRef.current?.sendUpdate(payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendDiff = useCallback(\n (patch: Partial<T>, msgId?: string) => {\n transportRef.current?.sendDiff(patch, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n return {\n data,\n sendEvent,\n sendUpdate,\n sendDiff,\n isConnected,\n error,\n };\n}\n\n/**\n * Legacy hook - use useViraState instead.\n * @deprecated Use useViraState with options instead\n */\nexport function useViraStream<T = any, C extends string = string>(\n channel: C,\n options?: UseViraStateOptions<T>\n) {\n return useViraState<T, C>(channel, { ...options, initial: null });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/useViraState.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, useCallback } from 'react';\nimport {\n createViraClient,\n deepMerge,\n getViraConnectionPool,\n type ViraClient,\n type Message,\n type ViraConnectionPool,\n type ViraPoolStatus,\n} from '@vira-ui/core';\n\nexport interface UseViraStateOptions<T = any> {\n /** Initial value for the state */\n initial?: T | null;\n /** Enable msgId support for idempotency */\n enableMsgId?: boolean;\n /** Callback when connection opens */\n onOpen?: () => void;\n /** Callback when connection closes */\n onClose?: (event: CloseEvent) => void;\n /** Callback when connection error occurs */\n onError?: (error: Error) => void;\n /** Use deep merge for diff patches (default: true) */\n deepMerge?: boolean;\n /** API URL (defaults to VITE_API_URL env or 'http://localhost:8080') */\n apiUrl?: string;\n /** Auth token for handshake */\n authToken?: string;\n /** Additional data to send in handshake (e.g., company_id, location_id) */\n handshakeData?: Record<string, any>;\n /** Disable connection pooling (fallback to 1 WS per channel). Default: false */\n disablePooling?: boolean;\n /** Enable debug logs for VRP (console.debug). Default: env VITE_VRP_DEBUG === 'true' */\n debug?: boolean;\n}\n\n/**\n * Unified hook for Vira Reactive Protocol state management.\n * Replaces both useViraState and useViraStream.\n *\n * @example\n * ```tsx\n * // Basic usage\n * const { data, sendUpdate } = useViraState<MyType>('my-channel');\n *\n * // With options\n * const { data, sendUpdate, sendDiff } = useViraState<User>('user:123', {\n * initial: { name: 'Guest' },\n * enableMsgId: true,\n * onOpen: () => console.log('Connected'),\n * deepMerge: true\n * });\n * ```\n */\nexport function useViraState<T = any, C extends string = string>(\n channel: C,\n initialOrOptions?: T | null | UseViraStateOptions<T>\n): {\n /** Current state data */\n data: T | null;\n /** Send an event to the server */\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n /** Send a full update (replaces state) */\n sendUpdate: (payload: T, msgId?: string) => void;\n /** Send a partial diff (merges with current state) */\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n /** Connection status */\n isConnected: boolean;\n /** Connection error, if any */\n error: Error | null;\n} {\n // Parse options (backward compatibility: second param can be initial value or options)\n const options: UseViraStateOptions<T> = useMemo(() => {\n if (initialOrOptions === null || initialOrOptions === undefined) {\n return {};\n }\n // If it's an object with known option keys, treat as options\n if (\n typeof initialOrOptions === 'object' &&\n !Array.isArray(initialOrOptions) &&\n ('enableMsgId' in initialOrOptions ||\n 'onOpen' in initialOrOptions ||\n 'onClose' in initialOrOptions ||\n 'onError' in initialOrOptions ||\n 'deepMerge' in initialOrOptions ||\n 'initial' in initialOrOptions ||\n 'apiUrl' in initialOrOptions ||\n 'authToken' in initialOrOptions ||\n 'handshakeData' in initialOrOptions ||\n 'disablePooling' in initialOrOptions ||\n 'debug' in initialOrOptions)\n ) {\n return initialOrOptions as UseViraStateOptions<T>;\n }\n // Otherwise, treat as initial value (backward compatibility)\n return { initial: initialOrOptions as T | null };\n }, [initialOrOptions]);\n\n const {\n initial = null,\n enableMsgId = false,\n onOpen,\n onClose,\n onError,\n deepMerge: useDeepMerge = true,\n apiUrl: apiUrlOption,\n authToken: authTokenOption,\n handshakeData: handshakeDataOption,\n disablePooling = false,\n debug: debugOption,\n } = options;\n\n const [data, setData] = useState<T | null>(initial);\n const [isConnected, setIsConnected] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n type Transport = {\n sendEvent: (name: string, payload: any, msgId?: string) => void;\n sendUpdate: (payload: T, msgId?: string) => void;\n sendDiff: (patch: Partial<T>, msgId?: string) => void;\n };\n\n const transportRef = useRef<Transport | null>(null);\n const clientRef = useRef<ViraClient | null>(null); // legacy non-pooled mode only\n const sessionRef = useRef<string | null>(null);\n const msgIdCounterRef = useRef(0);\n const wasConnectedRef = useRef(false);\n const lastErrorRef = useRef<Error | null>(null);\n\n // Use provided apiUrl or fallback to env or default\n // Note: import.meta is only available in ESM, so we check safely\n const apiUrl = useMemo(() => {\n if (apiUrlOption) return apiUrlOption;\n // Try to get from env if available (Vite/bundler environment)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n if (env?.VITE_API_URL) return env.VITE_API_URL;\n } catch {\n // Ignore if import.meta is not available\n }\n return 'http://localhost:8080';\n }, [apiUrlOption]);\n\n // Get authToken from options or try to get from env\n const authToken = useMemo(() => {\n if (authTokenOption !== undefined) return authTokenOption;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return env?.VITE_AUTH_TOKEN || '';\n } catch {\n return '';\n }\n }, [authTokenOption]);\n\n const debug = useMemo(() => {\n if (debugOption !== undefined) return Boolean(debugOption);\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (globalThis as any).import?.meta?.env || (globalThis as any).process?.env;\n return String(env?.VITE_VRP_DEBUG || '').toLowerCase() === 'true';\n } catch {\n return false;\n }\n }, [debugOption]);\n\n // Create a stable key for handshakeData to avoid unnecessary pool recreation\n // Use values from handshakeData instead of the object reference\n const handshakeDataKey = useMemo(() => {\n if (!handshakeDataOption) return '';\n try {\n return JSON.stringify(handshakeDataOption);\n } catch {\n return '';\n }\n }, [handshakeDataOption]);\n \n const pool: ViraConnectionPool | null = useMemo(() => {\n if (disablePooling) return null;\n return getViraConnectionPool({ url: apiUrl, authToken, handshakeData: handshakeDataOption, debug });\n }, [disablePooling, apiUrl, authToken, handshakeDataKey, debug]);\n\n\n\n\n useEffect(() => {\n if (!channel) return;\n\n const handleMessage = (msg: Message) => {\n const msgChannel = 'channel' in msg ? msg.channel : undefined;\n if (debug) {\n if (msg.type === 'diff' && msgChannel === channel) {\n const patchObj = msg.patch as any;\n const patchKeys = patchObj && typeof patchObj === 'object' ? Object.keys(patchObj) : [];\n console.log('[VRP_CLIENT] Diff message received:', { channel, patchKeys });\n } else {\n console.log('[VRP_CLIENT] Message received:', { type: msg.type, channel: msgChannel, myChannel: channel, match: msgChannel === channel });\n }\n }\n switch (msg.type) {\n case 'update':\n case 'event':\n if (msg.channel === channel) {\n setData((prev) => {\n if (!prev) {\n return msg.data as T;\n }\n\n if (typeof prev === 'object' && typeof msg.data === 'object') {\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, msg.data as Record<string, any>) as T;\n } else {\n mergedData = { ...(prev as any), ...(msg.data as any) };\n }\n return mergedData;\n }\n\n return msg.data as T;\n });\n }\n break;\n\n case 'diff':\n if (msg.channel === channel && msg.patch) {\n setData((prev) => {\n if (debug) {\n console.log('[VRP_CLIENT] Applying diff:', { channel, patch: msg.patch, prevKeys: prev && typeof prev === 'object' ? Object.keys(prev as any) : [] });\n }\n if (!prev) {\n return msg.patch as T;\n }\n\n if (typeof prev === 'object' && typeof msg.patch === 'object') {\n const patchObj = msg.patch as Record<string, any>;\n const prevObj = prev as Record<string, any>;\n \n // If patch is empty, ignore it (might be a backend issue)\n const patchKeys = Object.keys(patchObj);\n if (patchKeys.length === 0) {\n if (debug) {\n console.log('[VRP_CLIENT] Empty patch received, ignoring:', { channel });\n }\n return prev;\n }\n \n // Check for deletions first (null values in patch)\n const keysToDelete: string[] = [];\n for (const key in patchObj) {\n if (patchObj[key] === null || patchObj[key] === undefined) {\n keysToDelete.push(key);\n }\n }\n \n // If we have deletions, create new object without deleted keys\n if (keysToDelete.length > 0) {\n if (debug) {\n console.log('[VRP_CLIENT] Processing deletions:', { channel, keysToDelete, prevCount: Object.keys(prevObj).length });\n }\n \n const result: Record<string, any> = {};\n // Copy all keys from prevObj except deleted ones\n for (const key in prevObj) {\n if (!keysToDelete.includes(key)) {\n result[key] = prevObj[key];\n }\n }\n // Apply non-null updates from patch\n for (const key in patchObj) {\n if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== undefined) {\n result[key] = patchObj[key];\n }\n }\n \n if (debug) {\n console.log('[VRP_CLIENT] After deletion:', { channel, resultCount: Object.keys(result).length, deletedCount: keysToDelete.length });\n }\n \n // Force new object reference to trigger React re-render\n return { ...result } as T;\n }\n \n // No deletions, just merge updates\n let mergedData;\n if (useDeepMerge) {\n mergedData = deepMerge(prev as Record<string, any>, patchObj) as T;\n } else {\n mergedData = { ...(prev as any), ...patchObj };\n }\n \n return mergedData;\n }\n\n return prev;\n });\n }\n break;\n }\n };\n\n // --- Pooled mode (default) ---\n if (pool) {\n if (debug) {\n console.log('[VRP_CLIENT] Subscribing to channel:', channel);\n }\n // Subscribe to messages for this channel\n const unsubChannel = pool.subscribe(channel, handleMessage);\n\n // Track shared connection status\n const unsubStatus = pool.onStatus((status: ViraPoolStatus) => {\n setError(status.error);\n setIsConnected(status.connected);\n\n // Fire callbacks only on transitions\n if (status.connected && !wasConnectedRef.current) {\n wasConnectedRef.current = true;\n onOpen?.();\n }\n if (!status.connected && wasConnectedRef.current) {\n wasConnectedRef.current = false;\n // We don't get a real CloseEvent from pooled status, so we pass a lightweight synthetic object\n const synthetic = (typeof CloseEvent !== 'undefined'\n ? new CloseEvent('close', { code: 1001, reason: 'pooled disconnect' })\n : ({ code: 1001, reason: 'pooled disconnect' } as any)) as any;\n onClose?.(synthetic);\n }\n if (status.error) {\n if (lastErrorRef.current !== status.error) {\n lastErrorRef.current = status.error;\n onError?.(status.error);\n }\n } else {\n lastErrorRef.current = null;\n }\n });\n\n // Wire transport for send* APIs\n transportRef.current = {\n sendEvent: (name, payload, msgId) => pool.sendEvent(channel, name, payload, msgId),\n sendUpdate: (payload, msgId) => pool.sendUpdate(channel, payload, msgId),\n sendDiff: (patch, msgId) => pool.sendDiff(channel, patch, msgId),\n };\n\n return () => {\n unsubStatus();\n unsubChannel();\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }\n\n // --- Legacy mode (1 WS per channel) ---\n const handleConnect = () => {\n setIsConnected(true);\n setError(null);\n if (!wasConnectedRef.current) {\n wasConnectedRef.current = true;\n }\n onOpen?.();\n };\n\n const handleDisconnect = (event?: CloseEvent) => {\n setIsConnected(false);\n wasConnectedRef.current = false;\n onClose?.(event!);\n };\n\n const handleError = (err: Error) => {\n setError(err);\n onError?.(err);\n };\n\n const client = createViraClient({\n url: apiUrl,\n channel,\n onMessage: handleMessage,\n onConnect: handleConnect,\n onDisconnect: handleDisconnect,\n onError: handleError,\n session: sessionRef.current,\n authToken,\n onSessionChange: (newSession: string | null) => {\n sessionRef.current = newSession;\n },\n });\n\n clientRef.current = client;\n transportRef.current = {\n sendEvent: (name, payload, msgId) => client.sendEvent(name, payload, msgId),\n sendUpdate: (payload, msgId) => client.sendUpdate(payload, msgId),\n sendDiff: (patch, msgId) => client.sendDiff(patch, msgId),\n };\n\n return () => {\n client.close();\n clientRef.current = null;\n transportRef.current = null;\n setIsConnected(false);\n setError(null);\n };\n }, [channel, apiUrl, authToken, onOpen, onClose, onError, useDeepMerge, pool]);\n\n // Generate msgId if enabled\n const generateMsgId = useCallback((): string | undefined => {\n if (!enableMsgId) return undefined;\n msgIdCounterRef.current++;\n return `${channel}:${Date.now()}:${msgIdCounterRef.current}`;\n }, [channel, enableMsgId]);\n\n const sendEvent = useCallback(\n (name: string, payload: any, msgId?: string) => {\n transportRef.current?.sendEvent(name, payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendUpdate = useCallback(\n (payload: T, msgId?: string) => {\n transportRef.current?.sendUpdate(payload, msgId ?? generateMsgId());\n },\n [generateMsgId]\n );\n\n const sendDiff = useCallback(\n (patch: Partial<T>, msgId?: string) => {\n // Apply optimistic update immediately for deletions\n if (patch && typeof patch === 'object') {\n const patchObj = patch as Record<string, any>;\n const keysToDelete: string[] = [];\n for (const key in patchObj) {\n if (patchObj[key] === null || patchObj[key] === undefined) {\n keysToDelete.push(key);\n }\n }\n if (keysToDelete.length > 0) {\n if (debug) {\n console.log('[VRP_CLIENT] Optimistic deletion:', { channel, keysToDelete });\n }\n setData((prev) => {\n if (!prev || typeof prev !== 'object') return prev;\n const prevObj = prev as Record<string, any>;\n const result: Record<string, any> = {};\n // Copy all keys except deleted ones\n for (const key in prevObj) {\n if (!keysToDelete.includes(key)) {\n result[key] = prevObj[key];\n }\n }\n // Apply non-null updates from patch\n for (const key in patchObj) {\n if (!keysToDelete.includes(key) && patchObj[key] !== null && patchObj[key] !== undefined) {\n result[key] = patchObj[key];\n }\n }\n if (debug) {\n console.log('[VRP_CLIENT] Optimistic deletion result:', { channel, resultCount: Object.keys(result).length, prevCount: Object.keys(prevObj).length });\n }\n // Force new object reference\n return { ...result } as T;\n });\n }\n }\n transportRef.current?.sendDiff(patch, msgId ?? generateMsgId());\n },\n [generateMsgId, channel]\n );\n\n return {\n data,\n sendEvent,\n sendUpdate,\n sendDiff,\n isConnected,\n error,\n };\n}\n\n/**\n * Legacy hook - use useViraState instead.\n * @deprecated Use useViraState with options instead\n */\nexport function useViraStream<T = any, C extends string = string>(\n channel: C,\n options?: UseViraStateOptions<T>\n) {\n return useViraState<T, C>(channel, { ...options, initial: null });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vira-ui/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "Vira Framework - React hooks for Vira Reactive Protocol",
|
|
5
5
|
"author": "Vira Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"react": "^18.2.0",
|
|
31
|
-
"@vira-ui/core": "
|
|
31
|
+
"@vira-ui/core": "14.0.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": "^18.2.0"
|