@crdt-sync/react 0.1.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 +31 -1
- package/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.js +96 -4
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +60 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +20 -4
- package/dist/useCrdtState.d.ts +0 -8
- package/dist/useCrdtState.js +0 -105
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ export function RobotDashboard() {
|
|
|
40
40
|
{
|
|
41
41
|
robot: { speed: 0, active: true } // Initial State
|
|
42
42
|
}
|
|
43
|
+
// Optionally, you can pass a `{ wasmUrl }` here if your bundler needs it!
|
|
43
44
|
);
|
|
44
45
|
|
|
45
46
|
if (status === 'connecting') {
|
|
@@ -84,15 +85,44 @@ export function RobotDashboard() {
|
|
|
84
85
|
|
|
85
86
|
## API Reference
|
|
86
87
|
|
|
87
|
-
### `useCrdtState<T>(url: string, initialState: T)`
|
|
88
|
+
### `useCrdtState<T>(url: string, initialState: T, options?: UseCrdtStateOptions)`
|
|
88
89
|
|
|
89
90
|
Accepts a TypeScript generic `T` that extends `Record<string, unknown>`.
|
|
90
91
|
|
|
91
92
|
#### Parameters:
|
|
92
93
|
- `url` (`string`): The WebSocket URL to connect to the backend sync service.
|
|
93
94
|
- `initialState` (`T`): The default state to build the proxy structure over.
|
|
95
|
+
- `options` (`UseCrdtStateOptions`): Configuration options.
|
|
96
|
+
- `wasmUrl` (`string`, optional): A custom URL to load the `crdt_sync_bg.wasm` file from.
|
|
94
97
|
|
|
95
98
|
#### Returns (`UseCrdtStateResult<T>`):
|
|
96
99
|
- `state`: The plain Javascript object representation of your state. You should use `state` for reading values when rendering.
|
|
97
100
|
- `proxy`: The `CrdtStateProxy` object. You **must** perform all mutations on `proxy.state`. Mutating `state` directly will not trigger network events.
|
|
98
101
|
- `status`: Connective status indicator (`'connecting'` | `'open'` | `'error'`).
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Troubleshooting
|
|
106
|
+
|
|
107
|
+
### `CompileError: WebAssembly.instantiate(): expected magic word...`
|
|
108
|
+
|
|
109
|
+
If you are using Vite, Webpack, or a similar modern bundler, your dev server might intercept the internal WebAssembly file request and incorrectly serve your `index.html` fallback instead.
|
|
110
|
+
|
|
111
|
+
To resolve this, explicitly load the `.wasm` file using your bundler's native asset import mechanism (e.g., the `?url` suffix in Vite) and supply it to the hook:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { useCrdtState } from '@crdt-sync/react';
|
|
115
|
+
// 1. Tell Vite to treat the WASM as a static URL asset
|
|
116
|
+
import wasmUrl from '@crdt-sync/core/pkg/web/crdt_sync_bg.wasm?url';
|
|
117
|
+
|
|
118
|
+
export function App() {
|
|
119
|
+
const { state } = useCrdtState(
|
|
120
|
+
'ws://localhost:8080',
|
|
121
|
+
{ count: 0 },
|
|
122
|
+
// 2. Explicitly provide the URL to the hook
|
|
123
|
+
{ wasmUrl }
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
return <div>{state.count}</div>;
|
|
127
|
+
}
|
|
128
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CrdtStateProxy } from '@crdt-sync/core';
|
|
2
|
+
|
|
3
|
+
type CrdtStatus = 'connecting' | 'open' | 'error';
|
|
4
|
+
interface UseCrdtStateResult<T> {
|
|
5
|
+
state: T;
|
|
6
|
+
proxy: CrdtStateProxy | null;
|
|
7
|
+
status: CrdtStatus;
|
|
8
|
+
}
|
|
9
|
+
interface UseCrdtStateOptions {
|
|
10
|
+
wasmUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function useCrdtState<T extends Record<string, unknown>>(url: string, initialState: T, options?: UseCrdtStateOptions): UseCrdtStateResult<T>;
|
|
13
|
+
|
|
14
|
+
export { type CrdtStatus, type UseCrdtStateOptions, type UseCrdtStateResult, useCrdtState };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { CrdtStateProxy } from '@crdt-sync/core';
|
|
2
|
+
|
|
3
|
+
type CrdtStatus = 'connecting' | 'open' | 'error';
|
|
4
|
+
interface UseCrdtStateResult<T> {
|
|
5
|
+
state: T;
|
|
6
|
+
proxy: CrdtStateProxy | null;
|
|
7
|
+
status: CrdtStatus;
|
|
8
|
+
}
|
|
9
|
+
interface UseCrdtStateOptions {
|
|
10
|
+
wasmUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function useCrdtState<T extends Record<string, unknown>>(url: string, initialState: T, options?: UseCrdtStateOptions): UseCrdtStateResult<T>;
|
|
13
|
+
|
|
14
|
+
export { type CrdtStatus, type UseCrdtStateOptions, type UseCrdtStateResult, useCrdtState };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
useCrdtState: () => useCrdtState
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/useCrdtState.ts
|
|
38
|
+
var import_react = require("react");
|
|
39
|
+
var import_core = require("@crdt-sync/core");
|
|
40
|
+
var import_crdt_sync = __toESM(require("@crdt-sync/core/pkg/web/crdt_sync.js"));
|
|
41
|
+
function useCrdtState(url, initialState, options) {
|
|
42
|
+
const [proxy, setProxy] = (0, import_react.useState)(null);
|
|
43
|
+
const [status, setStatus] = (0, import_react.useState)("connecting");
|
|
44
|
+
const [, setTick] = (0, import_react.useState)(0);
|
|
45
|
+
const [initialRef] = (0, import_react.useState)(initialState);
|
|
46
|
+
(0, import_react.useEffect)(() => {
|
|
47
|
+
let active = true;
|
|
48
|
+
let manager = null;
|
|
49
|
+
let currentProxy = null;
|
|
50
|
+
async function setup() {
|
|
51
|
+
try {
|
|
52
|
+
await (0, import_crdt_sync.default)(options?.wasmUrl);
|
|
53
|
+
if (!active) return;
|
|
54
|
+
const clientId = "client-" + Math.random().toString(36).substring(2, 11);
|
|
55
|
+
const store = new import_crdt_sync.WasmStateStore(clientId);
|
|
56
|
+
currentProxy = new import_core.CrdtStateProxy(store);
|
|
57
|
+
for (const [key, value] of Object.entries(initialRef)) {
|
|
58
|
+
currentProxy.state[key] = value;
|
|
59
|
+
}
|
|
60
|
+
if (!active) return;
|
|
61
|
+
setProxy(currentProxy);
|
|
62
|
+
const ws = new WebSocket(url);
|
|
63
|
+
ws.onopen = () => {
|
|
64
|
+
if (active) setStatus("open");
|
|
65
|
+
};
|
|
66
|
+
ws.onerror = () => {
|
|
67
|
+
if (active) setStatus("error");
|
|
68
|
+
};
|
|
69
|
+
ws.onclose = () => {
|
|
70
|
+
if (active) setStatus("connecting");
|
|
71
|
+
};
|
|
72
|
+
manager = new import_core.WebSocketManager(store, currentProxy, ws);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error("Failed to initialize CRDT sync:", err);
|
|
75
|
+
if (active) setStatus("error");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
setup();
|
|
79
|
+
return () => {
|
|
80
|
+
active = false;
|
|
81
|
+
if (manager) manager.disconnect();
|
|
82
|
+
};
|
|
83
|
+
}, [url, initialRef]);
|
|
84
|
+
(0, import_react.useEffect)(() => {
|
|
85
|
+
if (!proxy) return;
|
|
86
|
+
return proxy.onUpdate(() => {
|
|
87
|
+
setTick((t) => t + 1);
|
|
88
|
+
});
|
|
89
|
+
}, [proxy]);
|
|
90
|
+
const state = proxy ? proxy.state : initialRef;
|
|
91
|
+
return { state, proxy, status };
|
|
92
|
+
}
|
|
93
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
94
|
+
0 && (module.exports = {
|
|
95
|
+
useCrdtState
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useCrdtState.ts"],"sourcesContent":["export { useCrdtState } from './useCrdtState';\nexport type { CrdtStatus, UseCrdtStateResult, UseCrdtStateOptions } from './useCrdtState';\n","import { useState, useEffect } from 'react';\nimport { CrdtStateProxy, WebSocketManager } from '@crdt-sync/core';\n// @ts-ignore: Wasm module will be generated during the full build\nimport init, { WasmStateStore } from '@crdt-sync/core/pkg/web/crdt_sync.js';\n\nexport type CrdtStatus = 'connecting' | 'open' | 'error';\n\nexport interface UseCrdtStateResult<T> {\n state: T;\n proxy: CrdtStateProxy | null;\n status: CrdtStatus;\n}\n\nexport interface UseCrdtStateOptions {\n wasmUrl?: string;\n}\n\nexport function useCrdtState<T extends Record<string, unknown>>(\n url: string,\n initialState: T,\n options?: UseCrdtStateOptions\n): UseCrdtStateResult<T> {\n const [proxy, setProxy] = useState<CrdtStateProxy | null>(null);\n const [status, setStatus] = useState<CrdtStatus>('connecting');\n const [, setTick] = useState(0);\n\n // Note: we're ignoring initialState updates (this behaves like useState).\n const [initialRef] = useState(initialState);\n\n useEffect(() => {\n let active = true;\n let manager: WebSocketManager | null = null;\n let currentProxy: CrdtStateProxy | null = null;\n\n async function setup() {\n try {\n await init(options?.wasmUrl);\n if (!active) return;\n\n // Create a unique client ID\n const clientId = 'client-' + Math.random().toString(36).substring(2, 11);\n const store = new WasmStateStore(clientId);\n\n currentProxy = new CrdtStateProxy(store);\n\n // Initialize state\n for (const [key, value] of Object.entries(initialRef)) {\n currentProxy.state[key] = value;\n }\n\n if (!active) return;\n setProxy(currentProxy);\n\n const ws = new WebSocket(url);\n\n ws.onopen = () => {\n if (active) setStatus('open');\n };\n\n ws.onerror = () => {\n if (active) setStatus('error');\n };\n\n ws.onclose = () => {\n if (active) setStatus('connecting');\n };\n\n manager = new WebSocketManager(store, currentProxy, ws as any);\n } catch (err) {\n console.error('Failed to initialize CRDT sync:', err);\n if (active) setStatus('error');\n }\n }\n\n setup();\n\n return () => {\n active = false;\n if (manager) manager.disconnect();\n };\n }, [url, initialRef]);\n\n useEffect(() => {\n if (!proxy) return;\n\n // Subscribe to proxy updates to trigger React re-renders.\n return proxy.onUpdate(() => {\n setTick(t => t + 1);\n });\n }, [proxy]);\n\n const state = proxy ? (proxy.state as T) : initialRef;\n\n return { state, proxy, status };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAoC;AACpC,kBAAiD;AAEjD,uBAAqC;AAc9B,SAAS,aACZ,KACA,cACA,SACqB;AACrB,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAgC,IAAI;AAC9D,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAqB,YAAY;AAC7D,QAAM,CAAC,EAAE,OAAO,QAAI,uBAAS,CAAC;AAG9B,QAAM,CAAC,UAAU,QAAI,uBAAS,YAAY;AAE1C,8BAAU,MAAM;AACZ,QAAI,SAAS;AACb,QAAI,UAAmC;AACvC,QAAI,eAAsC;AAE1C,mBAAe,QAAQ;AACnB,UAAI;AACA,kBAAM,iBAAAA,SAAK,SAAS,OAAO;AAC3B,YAAI,CAAC,OAAQ;AAGb,cAAM,WAAW,YAAY,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACvE,cAAM,QAAQ,IAAI,gCAAe,QAAQ;AAEzC,uBAAe,IAAI,2BAAe,KAAK;AAGvC,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACnD,uBAAa,MAAM,GAAG,IAAI;AAAA,QAC9B;AAEA,YAAI,CAAC,OAAQ;AACb,iBAAS,YAAY;AAErB,cAAM,KAAK,IAAI,UAAU,GAAG;AAE5B,WAAG,SAAS,MAAM;AACd,cAAI,OAAQ,WAAU,MAAM;AAAA,QAChC;AAEA,WAAG,UAAU,MAAM;AACf,cAAI,OAAQ,WAAU,OAAO;AAAA,QACjC;AAEA,WAAG,UAAU,MAAM;AACf,cAAI,OAAQ,WAAU,YAAY;AAAA,QACtC;AAEA,kBAAU,IAAI,6BAAiB,OAAO,cAAc,EAAS;AAAA,MACjE,SAAS,KAAK;AACV,gBAAQ,MAAM,mCAAmC,GAAG;AACpD,YAAI,OAAQ,WAAU,OAAO;AAAA,MACjC;AAAA,IACJ;AAEA,UAAM;AAEN,WAAO,MAAM;AACT,eAAS;AACT,UAAI,QAAS,SAAQ,WAAW;AAAA,IACpC;AAAA,EACJ,GAAG,CAAC,KAAK,UAAU,CAAC;AAEpB,8BAAU,MAAM;AACZ,QAAI,CAAC,MAAO;AAGZ,WAAO,MAAM,SAAS,MAAM;AACxB,cAAQ,OAAK,IAAI,CAAC;AAAA,IACtB,CAAC;AAAA,EACL,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,QAAQ,QAAS,MAAM,QAAc;AAE3C,SAAO,EAAE,OAAO,OAAO,OAAO;AAClC;","names":["init"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/useCrdtState.ts
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { CrdtStateProxy, WebSocketManager } from "@crdt-sync/core";
|
|
4
|
+
import init, { WasmStateStore } from "@crdt-sync/core/pkg/web/crdt_sync.js";
|
|
5
|
+
function useCrdtState(url, initialState, options) {
|
|
6
|
+
const [proxy, setProxy] = useState(null);
|
|
7
|
+
const [status, setStatus] = useState("connecting");
|
|
8
|
+
const [, setTick] = useState(0);
|
|
9
|
+
const [initialRef] = useState(initialState);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
let active = true;
|
|
12
|
+
let manager = null;
|
|
13
|
+
let currentProxy = null;
|
|
14
|
+
async function setup() {
|
|
15
|
+
try {
|
|
16
|
+
await init(options?.wasmUrl);
|
|
17
|
+
if (!active) return;
|
|
18
|
+
const clientId = "client-" + Math.random().toString(36).substring(2, 11);
|
|
19
|
+
const store = new WasmStateStore(clientId);
|
|
20
|
+
currentProxy = new CrdtStateProxy(store);
|
|
21
|
+
for (const [key, value] of Object.entries(initialRef)) {
|
|
22
|
+
currentProxy.state[key] = value;
|
|
23
|
+
}
|
|
24
|
+
if (!active) return;
|
|
25
|
+
setProxy(currentProxy);
|
|
26
|
+
const ws = new WebSocket(url);
|
|
27
|
+
ws.onopen = () => {
|
|
28
|
+
if (active) setStatus("open");
|
|
29
|
+
};
|
|
30
|
+
ws.onerror = () => {
|
|
31
|
+
if (active) setStatus("error");
|
|
32
|
+
};
|
|
33
|
+
ws.onclose = () => {
|
|
34
|
+
if (active) setStatus("connecting");
|
|
35
|
+
};
|
|
36
|
+
manager = new WebSocketManager(store, currentProxy, ws);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error("Failed to initialize CRDT sync:", err);
|
|
39
|
+
if (active) setStatus("error");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
setup();
|
|
43
|
+
return () => {
|
|
44
|
+
active = false;
|
|
45
|
+
if (manager) manager.disconnect();
|
|
46
|
+
};
|
|
47
|
+
}, [url, initialRef]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!proxy) return;
|
|
50
|
+
return proxy.onUpdate(() => {
|
|
51
|
+
setTick((t) => t + 1);
|
|
52
|
+
});
|
|
53
|
+
}, [proxy]);
|
|
54
|
+
const state = proxy ? proxy.state : initialRef;
|
|
55
|
+
return { state, proxy, status };
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
useCrdtState
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/useCrdtState.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { CrdtStateProxy, WebSocketManager } from '@crdt-sync/core';\n// @ts-ignore: Wasm module will be generated during the full build\nimport init, { WasmStateStore } from '@crdt-sync/core/pkg/web/crdt_sync.js';\n\nexport type CrdtStatus = 'connecting' | 'open' | 'error';\n\nexport interface UseCrdtStateResult<T> {\n state: T;\n proxy: CrdtStateProxy | null;\n status: CrdtStatus;\n}\n\nexport interface UseCrdtStateOptions {\n wasmUrl?: string;\n}\n\nexport function useCrdtState<T extends Record<string, unknown>>(\n url: string,\n initialState: T,\n options?: UseCrdtStateOptions\n): UseCrdtStateResult<T> {\n const [proxy, setProxy] = useState<CrdtStateProxy | null>(null);\n const [status, setStatus] = useState<CrdtStatus>('connecting');\n const [, setTick] = useState(0);\n\n // Note: we're ignoring initialState updates (this behaves like useState).\n const [initialRef] = useState(initialState);\n\n useEffect(() => {\n let active = true;\n let manager: WebSocketManager | null = null;\n let currentProxy: CrdtStateProxy | null = null;\n\n async function setup() {\n try {\n await init(options?.wasmUrl);\n if (!active) return;\n\n // Create a unique client ID\n const clientId = 'client-' + Math.random().toString(36).substring(2, 11);\n const store = new WasmStateStore(clientId);\n\n currentProxy = new CrdtStateProxy(store);\n\n // Initialize state\n for (const [key, value] of Object.entries(initialRef)) {\n currentProxy.state[key] = value;\n }\n\n if (!active) return;\n setProxy(currentProxy);\n\n const ws = new WebSocket(url);\n\n ws.onopen = () => {\n if (active) setStatus('open');\n };\n\n ws.onerror = () => {\n if (active) setStatus('error');\n };\n\n ws.onclose = () => {\n if (active) setStatus('connecting');\n };\n\n manager = new WebSocketManager(store, currentProxy, ws as any);\n } catch (err) {\n console.error('Failed to initialize CRDT sync:', err);\n if (active) setStatus('error');\n }\n }\n\n setup();\n\n return () => {\n active = false;\n if (manager) manager.disconnect();\n };\n }, [url, initialRef]);\n\n useEffect(() => {\n if (!proxy) return;\n\n // Subscribe to proxy updates to trigger React re-renders.\n return proxy.onUpdate(() => {\n setTick(t => t + 1);\n });\n }, [proxy]);\n\n const state = proxy ? (proxy.state as T) : initialRef;\n\n return { state, proxy, status };\n}\n"],"mappings":";AAAA,SAAS,UAAU,iBAAiB;AACpC,SAAS,gBAAgB,wBAAwB;AAEjD,OAAO,QAAQ,sBAAsB;AAc9B,SAAS,aACZ,KACA,cACA,SACqB;AACrB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAgC,IAAI;AAC9D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAqB,YAAY;AAC7D,QAAM,CAAC,EAAE,OAAO,IAAI,SAAS,CAAC;AAG9B,QAAM,CAAC,UAAU,IAAI,SAAS,YAAY;AAE1C,YAAU,MAAM;AACZ,QAAI,SAAS;AACb,QAAI,UAAmC;AACvC,QAAI,eAAsC;AAE1C,mBAAe,QAAQ;AACnB,UAAI;AACA,cAAM,KAAK,SAAS,OAAO;AAC3B,YAAI,CAAC,OAAQ;AAGb,cAAM,WAAW,YAAY,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACvE,cAAM,QAAQ,IAAI,eAAe,QAAQ;AAEzC,uBAAe,IAAI,eAAe,KAAK;AAGvC,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACnD,uBAAa,MAAM,GAAG,IAAI;AAAA,QAC9B;AAEA,YAAI,CAAC,OAAQ;AACb,iBAAS,YAAY;AAErB,cAAM,KAAK,IAAI,UAAU,GAAG;AAE5B,WAAG,SAAS,MAAM;AACd,cAAI,OAAQ,WAAU,MAAM;AAAA,QAChC;AAEA,WAAG,UAAU,MAAM;AACf,cAAI,OAAQ,WAAU,OAAO;AAAA,QACjC;AAEA,WAAG,UAAU,MAAM;AACf,cAAI,OAAQ,WAAU,YAAY;AAAA,QACtC;AAEA,kBAAU,IAAI,iBAAiB,OAAO,cAAc,EAAS;AAAA,MACjE,SAAS,KAAK;AACV,gBAAQ,MAAM,mCAAmC,GAAG;AACpD,YAAI,OAAQ,WAAU,OAAO;AAAA,MACjC;AAAA,IACJ;AAEA,UAAM;AAEN,WAAO,MAAM;AACT,eAAS;AACT,UAAI,QAAS,SAAQ,WAAW;AAAA,IACpC;AAAA,EACJ,GAAG,CAAC,KAAK,UAAU,CAAC;AAEpB,YAAU,MAAM;AACZ,QAAI,CAAC,MAAO;AAGZ,WAAO,MAAM,SAAS,MAAM;AACxB,cAAQ,OAAK,IAAI,CAAC;AAAA,IACtB,CAAC;AAAA,EACL,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,QAAQ,QAAS,MAAM,QAAc;AAE3C,SAAO,EAAE,OAAO,OAAO,OAAO;AAClC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,26 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crdt-sync/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "React hook adapter for crdt-sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"files": [
|
|
8
16
|
"dist"
|
|
9
17
|
],
|
|
10
18
|
"scripts": {
|
|
11
|
-
"build": "
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"test": "vitest run"
|
|
12
21
|
},
|
|
13
22
|
"peerDependencies": {
|
|
14
23
|
"react": ">=16.8",
|
|
15
24
|
"react-dom": ">=16.8"
|
|
16
25
|
},
|
|
17
26
|
"dependencies": {
|
|
18
|
-
"@crdt-sync/core": "
|
|
27
|
+
"@crdt-sync/core": "^0.2.0"
|
|
19
28
|
},
|
|
20
29
|
"devDependencies": {
|
|
30
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
31
|
+
"@testing-library/react": "^16.3.2",
|
|
32
|
+
"@testing-library/user-event": "^14.6.1",
|
|
21
33
|
"@types/react": "^18.0.0",
|
|
22
34
|
"@types/react-dom": "^18.0.0",
|
|
23
|
-
"
|
|
35
|
+
"happy-dom": "^20.7.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"typescript": "^5.4.5",
|
|
38
|
+
"vitest": "^4.0.18",
|
|
39
|
+
"vitest-websocket-mock": "^0.5.0"
|
|
24
40
|
},
|
|
25
41
|
"license": "MIT"
|
|
26
42
|
}
|
package/dist/useCrdtState.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { CrdtStateProxy } from '@crdt-sync/core';
|
|
2
|
-
export type CrdtStatus = 'connecting' | 'open' | 'error';
|
|
3
|
-
export interface UseCrdtStateResult<T> {
|
|
4
|
-
state: T;
|
|
5
|
-
proxy: CrdtStateProxy | null;
|
|
6
|
-
status: CrdtStatus;
|
|
7
|
-
}
|
|
8
|
-
export declare function useCrdtState<T extends Record<string, unknown>>(url: string, initialState: T): UseCrdtStateResult<T>;
|
package/dist/useCrdtState.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.useCrdtState = useCrdtState;
|
|
37
|
-
const react_1 = require("react");
|
|
38
|
-
const core_1 = require("@crdt-sync/core");
|
|
39
|
-
// @ts-ignore: Wasm module will be generated during the full build
|
|
40
|
-
const crdt_sync_js_1 = __importStar(require("@crdt-sync/core/pkg/web/crdt_sync.js"));
|
|
41
|
-
function useCrdtState(url, initialState) {
|
|
42
|
-
const [proxy, setProxy] = (0, react_1.useState)(null);
|
|
43
|
-
const [status, setStatus] = (0, react_1.useState)('connecting');
|
|
44
|
-
const [, setTick] = (0, react_1.useState)(0);
|
|
45
|
-
// Note: we're ignoring initialState updates (this behaves like useState).
|
|
46
|
-
const [initialRef] = (0, react_1.useState)(initialState);
|
|
47
|
-
(0, react_1.useEffect)(() => {
|
|
48
|
-
let active = true;
|
|
49
|
-
let manager = null;
|
|
50
|
-
let currentProxy = null;
|
|
51
|
-
async function setup() {
|
|
52
|
-
try {
|
|
53
|
-
await (0, crdt_sync_js_1.default)();
|
|
54
|
-
if (!active)
|
|
55
|
-
return;
|
|
56
|
-
// Create a unique client ID
|
|
57
|
-
const clientId = 'client-' + Math.random().toString(36).substring(2, 11);
|
|
58
|
-
const store = new crdt_sync_js_1.WasmStateStore(clientId);
|
|
59
|
-
currentProxy = new core_1.CrdtStateProxy(store);
|
|
60
|
-
// Initialize state
|
|
61
|
-
for (const [key, value] of Object.entries(initialRef)) {
|
|
62
|
-
currentProxy.state[key] = value;
|
|
63
|
-
}
|
|
64
|
-
if (!active)
|
|
65
|
-
return;
|
|
66
|
-
setProxy(currentProxy);
|
|
67
|
-
const ws = new WebSocket(url);
|
|
68
|
-
ws.onopen = () => {
|
|
69
|
-
if (active)
|
|
70
|
-
setStatus('open');
|
|
71
|
-
};
|
|
72
|
-
ws.onerror = () => {
|
|
73
|
-
if (active)
|
|
74
|
-
setStatus('error');
|
|
75
|
-
};
|
|
76
|
-
ws.onclose = () => {
|
|
77
|
-
if (active)
|
|
78
|
-
setStatus('connecting');
|
|
79
|
-
};
|
|
80
|
-
manager = new core_1.WebSocketManager(store, currentProxy, ws);
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
console.error('Failed to initialize CRDT sync:', err);
|
|
84
|
-
if (active)
|
|
85
|
-
setStatus('error');
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
setup();
|
|
89
|
-
return () => {
|
|
90
|
-
active = false;
|
|
91
|
-
if (manager)
|
|
92
|
-
manager.disconnect();
|
|
93
|
-
};
|
|
94
|
-
}, [url, initialRef]);
|
|
95
|
-
(0, react_1.useEffect)(() => {
|
|
96
|
-
if (!proxy)
|
|
97
|
-
return;
|
|
98
|
-
// Subscribe to proxy updates to trigger React re-renders.
|
|
99
|
-
return proxy.onUpdate(() => {
|
|
100
|
-
setTick(t => t + 1);
|
|
101
|
-
});
|
|
102
|
-
}, [proxy]);
|
|
103
|
-
const state = proxy ? proxy.state : initialRef;
|
|
104
|
-
return { state, proxy, status };
|
|
105
|
-
}
|