react-mirrorstate 0.1.0-alpha.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/connection-manager.d.ts +0 -4
- package/dist/connection-manager.js +0 -36
- package/dist/index.d.ts +2 -1
- package/dist/index.js +11 -20
- package/package.json +7 -2
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# `react-mirrorstate`
|
|
2
|
+
|
|
3
|
+
React hook for bi-directional state synchronization with JSON files on disk.
|
|
4
|
+
|
|
5
|
+
**Note:** Both `react-mirrorstate` and `vite-plugin-mirrorstate` are required to use MirrorState.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install react-mirrorstate vite-plugin-mirrorstate
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
For full documentation, examples, and API reference, see the [main MirrorState repository](https://github.com/szymonkaliski/mirrorstate).
|
|
16
|
+
|
|
17
|
+
## License
|
|
18
|
+
|
|
19
|
+
MIT
|
|
@@ -4,17 +4,13 @@ declare class WebSocketConnectionManager {
|
|
|
4
4
|
private isConnecting;
|
|
5
5
|
private listeners;
|
|
6
6
|
private currentStates;
|
|
7
|
-
private initialized;
|
|
8
7
|
private getWebSocketConfig;
|
|
9
8
|
private buildWebSocketURL;
|
|
10
9
|
connect(): Promise<void>;
|
|
11
|
-
getInlinedInitialStates(): Promise<Record<string, any>>;
|
|
12
|
-
loadInitialStateFromInline(name: string): Promise<any>;
|
|
13
10
|
subscribe(name: string, listener: StateListener): () => void;
|
|
14
11
|
private lastSentState;
|
|
15
12
|
private pendingUpdates;
|
|
16
13
|
updateState(name: string, state: any): void;
|
|
17
|
-
isInitialized(name: string): boolean;
|
|
18
14
|
getCurrentState(name: string): any;
|
|
19
15
|
private notifyListeners;
|
|
20
16
|
}
|
|
@@ -5,7 +5,6 @@ class WebSocketConnectionManager {
|
|
|
5
5
|
isConnecting = false;
|
|
6
6
|
listeners = new Map();
|
|
7
7
|
currentStates = new Map();
|
|
8
|
-
initialized = new Set();
|
|
9
8
|
getWebSocketConfig() {
|
|
10
9
|
try {
|
|
11
10
|
const config = require("virtual:mirrorstate/config");
|
|
@@ -55,7 +54,6 @@ class WebSocketConnectionManager {
|
|
|
55
54
|
const data = JSON.parse(event.data);
|
|
56
55
|
if (data.type === "initialState") {
|
|
57
56
|
this.currentStates.set(data.name, data.state);
|
|
58
|
-
this.initialized.add(data.name);
|
|
59
57
|
this.notifyListeners(data.name, data.state);
|
|
60
58
|
logger(`Initial state loaded: ${data.name}`, data.state);
|
|
61
59
|
}
|
|
@@ -70,29 +68,6 @@ class WebSocketConnectionManager {
|
|
|
70
68
|
}
|
|
71
69
|
};
|
|
72
70
|
}
|
|
73
|
-
async getInlinedInitialStates() {
|
|
74
|
-
try {
|
|
75
|
-
// Import the virtual module with inlined states
|
|
76
|
-
const module = await import("virtual:mirrorstate/initial-states");
|
|
77
|
-
return module.INITIAL_STATES || {};
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
logger("Failed to load virtual module:", error);
|
|
81
|
-
return {};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async loadInitialStateFromInline(name) {
|
|
85
|
-
// Always try to load inlined states - both in dev and production
|
|
86
|
-
const inlinedStates = await this.getInlinedInitialStates();
|
|
87
|
-
const state = inlinedStates[name];
|
|
88
|
-
if (state !== undefined) {
|
|
89
|
-
this.currentStates.set(name, state);
|
|
90
|
-
this.initialized.add(name);
|
|
91
|
-
logger(`Loaded inlined initial state: ${name}`, state);
|
|
92
|
-
return state;
|
|
93
|
-
}
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
71
|
subscribe(name, listener) {
|
|
97
72
|
if (!this.listeners.has(name)) {
|
|
98
73
|
this.listeners.set(name, new Set());
|
|
@@ -104,14 +79,6 @@ class WebSocketConnectionManager {
|
|
|
104
79
|
if (this.currentStates.has(name)) {
|
|
105
80
|
listener(this.currentStates.get(name));
|
|
106
81
|
}
|
|
107
|
-
else {
|
|
108
|
-
// Try to load from inlined states (production) or wait for WebSocket (dev)
|
|
109
|
-
this.loadInitialStateFromInline(name).then((state) => {
|
|
110
|
-
if (state !== undefined) {
|
|
111
|
-
this.notifyListeners(name, state);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
82
|
return () => {
|
|
116
83
|
const nameListeners = this.listeners.get(name);
|
|
117
84
|
if (nameListeners) {
|
|
@@ -152,9 +119,6 @@ class WebSocketConnectionManager {
|
|
|
152
119
|
}, 10);
|
|
153
120
|
this.pendingUpdates.set(name, timeout);
|
|
154
121
|
}
|
|
155
|
-
isInitialized(name) {
|
|
156
|
-
return this.initialized.has(name);
|
|
157
|
-
}
|
|
158
122
|
getCurrentState(name) {
|
|
159
123
|
return this.currentStates.get(name);
|
|
160
124
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { Draft } from "immer";
|
|
2
|
-
export declare function useMirrorState<T>(name: string
|
|
2
|
+
export declare function useMirrorState<T>(name: string): [T | undefined, (updater: (draft: Draft<T>) => void) => void];
|
|
3
|
+
export declare function useMirrorState<T>(name: string, initialValue: T): [T, (updater: (draft: Draft<T>) => void) => void];
|
|
3
4
|
export default useMirrorState;
|
package/dist/index.js
CHANGED
|
@@ -1,35 +1,26 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
1
|
+
import { useEffect, useState, useRef } from "react";
|
|
2
2
|
import { produce } from "immer";
|
|
3
3
|
import { connectionManager } from "./connection-manager";
|
|
4
|
+
import { INITIAL_STATES } from "virtual:mirrorstate/initial-states";
|
|
4
5
|
export function useMirrorState(name, initialValue) {
|
|
5
|
-
const [state, setState] = useState(initialValue);
|
|
6
|
-
const
|
|
7
|
-
// The connection manager handles both WebSocket (dev) and inlined state (production)
|
|
6
|
+
const [state, setState] = useState(() => INITIAL_STATES?.[name] ?? initialValue);
|
|
7
|
+
const hasCreatedFile = useRef(false);
|
|
8
8
|
useEffect(() => {
|
|
9
9
|
// Subscribe to state changes for this name
|
|
10
10
|
const unsubscribe = connectionManager.subscribe(name, (newState) => {
|
|
11
11
|
setState(newState);
|
|
12
|
-
setIsInitialized(true);
|
|
13
12
|
});
|
|
14
|
-
//
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
13
|
+
// If file doesn't exist and initialValue was provided, create it
|
|
14
|
+
if (INITIAL_STATES?.[name] === undefined &&
|
|
15
|
+
initialValue !== undefined &&
|
|
16
|
+
!hasCreatedFile.current) {
|
|
17
|
+
hasCreatedFile.current = true;
|
|
18
|
+
connectionManager.updateState(name, initialValue);
|
|
21
19
|
}
|
|
22
|
-
// Set a timeout to mark as initialized even if no file exists
|
|
23
|
-
const initTimeout = setTimeout(() => {
|
|
24
|
-
if (!isInitialized && !connectionManager.isInitialized(name)) {
|
|
25
|
-
setIsInitialized(true);
|
|
26
|
-
}
|
|
27
|
-
}, 100);
|
|
28
20
|
return () => {
|
|
29
21
|
unsubscribe();
|
|
30
|
-
clearTimeout(initTimeout);
|
|
31
22
|
};
|
|
32
|
-
}, [name,
|
|
23
|
+
}, [name, initialValue]);
|
|
33
24
|
const updateMirrorState = (updater) => {
|
|
34
25
|
setState((prevState) => {
|
|
35
26
|
const newState = produce(prevState, updater);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-mirrorstate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "React library for bidirectional state synchronization with MirrorState",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
],
|
|
17
17
|
"author": "",
|
|
18
18
|
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/szymonkaliski/mirrorstate.git",
|
|
22
|
+
"directory": "packages/react-mirrorstate"
|
|
23
|
+
},
|
|
19
24
|
"dependencies": {
|
|
20
25
|
"debug": "^4.4.1",
|
|
21
26
|
"immer": "^10.0.3"
|
|
@@ -27,7 +32,7 @@
|
|
|
27
32
|
"typescript": "^5.3.3"
|
|
28
33
|
},
|
|
29
34
|
"peerDependencies": {
|
|
30
|
-
"react": "
|
|
35
|
+
"react": ">=18.0.0"
|
|
31
36
|
},
|
|
32
37
|
"files": [
|
|
33
38
|
"dist"
|