remote-state-sync 1.0.1 → 1.0.3
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.d.ts +11 -7
- package/dist/index.js +41 -29
- package/package.json +8 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
import { SuperJSONResult } from 'superjson';
|
|
1
2
|
import Nanobus from 'nanobus';
|
|
2
3
|
import { Ref, ShallowRef } from '@vue/reactivity';
|
|
3
4
|
|
|
4
5
|
type PatchOperation = 'set' | 'delete' | 'clear' | 'add';
|
|
5
6
|
interface Patch {
|
|
6
7
|
op: PatchOperation;
|
|
8
|
+
key: string;
|
|
7
9
|
path: (string | number)[];
|
|
8
10
|
value?: unknown;
|
|
9
11
|
}
|
|
10
12
|
interface SyncOptions {
|
|
11
|
-
snapshotGetter: (namespace: string) => Promise<
|
|
13
|
+
snapshotGetter: (namespace: string) => Promise<SyncSnapshot>;
|
|
12
14
|
}
|
|
13
15
|
type SyncUpdater<T> = (state: T) => T | void;
|
|
14
16
|
type SyncBusDefinition = {
|
|
15
17
|
update: (namespace: string, patches: Patch[]) => void;
|
|
18
|
+
register: (namespace: string) => void;
|
|
16
19
|
};
|
|
17
20
|
type ReceiverItemBusDefinition<T> = {
|
|
18
21
|
update: (newValue: T, oldValue: T, patches: Patch[]) => void;
|
|
19
22
|
};
|
|
23
|
+
type SyncSnapshot = SuperJSONResult;
|
|
20
24
|
|
|
21
25
|
declare class SyncProvider {
|
|
22
26
|
private namespaces;
|
|
23
|
-
bus: Nanobus<SyncBusDefinition>;
|
|
27
|
+
readonly bus: Nanobus<SyncBusDefinition>;
|
|
24
28
|
constructor();
|
|
25
29
|
register(namespace: string): SyncNamespaceProvider;
|
|
26
|
-
getStateSnapshot(namespace: string):
|
|
30
|
+
getStateSnapshot(namespace: string): SyncSnapshot;
|
|
27
31
|
}
|
|
28
32
|
declare class SyncNamespaceProvider {
|
|
29
33
|
readonly namespace: string;
|
|
@@ -33,7 +37,7 @@ declare class SyncNamespaceProvider {
|
|
|
33
37
|
private emitTimeout;
|
|
34
38
|
constructor(namespace: string, bus: Nanobus<SyncBusDefinition>);
|
|
35
39
|
sync<T>(key: string, initialValue?: T): SyncItemProvider<T>;
|
|
36
|
-
getSnapshot():
|
|
40
|
+
getSnapshot(): SyncSnapshot;
|
|
37
41
|
private queuePatch;
|
|
38
42
|
private emitPatches;
|
|
39
43
|
}
|
|
@@ -58,7 +62,7 @@ declare class SyncNamespaceReceiver {
|
|
|
58
62
|
readonly namespace: string;
|
|
59
63
|
private snapshot;
|
|
60
64
|
private items;
|
|
61
|
-
constructor(namespace: string, snapshot:
|
|
65
|
+
constructor(namespace: string, snapshot: SyncSnapshot);
|
|
62
66
|
sync<T>(key: string): SyncItemReceiver<T>;
|
|
63
67
|
applyPatches(patches: Patch[]): void;
|
|
64
68
|
private applyPatchToObject;
|
|
@@ -68,7 +72,7 @@ declare class SyncItemReceiver<T> {
|
|
|
68
72
|
private value;
|
|
69
73
|
private _ref;
|
|
70
74
|
private _shallowRef;
|
|
71
|
-
bus: Nanobus<ReceiverItemBusDefinition<T>>;
|
|
75
|
+
readonly bus: Nanobus<ReceiverItemBusDefinition<T>>;
|
|
72
76
|
constructor(key: string, initialValue: T);
|
|
73
77
|
on(event: 'update', cb: (newValue: T, oldValue: T, patches: Patch[]) => void): void;
|
|
74
78
|
toValue(): T;
|
|
@@ -79,4 +83,4 @@ declare class SyncItemReceiver<T> {
|
|
|
79
83
|
dispose(): void;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
export { type Patch, type PatchOperation, type ReceiverItemBusDefinition, type SyncBusDefinition, SyncItemProvider, SyncItemReceiver, SyncNamespaceProvider, SyncNamespaceReceiver, type SyncOptions, SyncProvider, SyncReceiver, type SyncUpdater };
|
|
86
|
+
export { type Patch, type PatchOperation, type ReceiverItemBusDefinition, type SyncBusDefinition, SyncItemProvider, SyncItemReceiver, SyncNamespaceProvider, SyncNamespaceReceiver, type SyncOptions, SyncProvider, SyncReceiver, type SyncSnapshot, type SyncUpdater };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/provider.ts
|
|
2
2
|
import Nanobus from "nanobus";
|
|
3
|
+
import SuperJSON from "superjson";
|
|
3
4
|
|
|
4
5
|
// src/utils.ts
|
|
5
6
|
function isObject(val) {
|
|
@@ -53,19 +54,19 @@ function clearValue(current) {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
// src/proxy.ts
|
|
56
|
-
function createDeepProxy(target, path, onPatch) {
|
|
57
|
+
function createDeepProxy(target, rootKey, path, onPatch) {
|
|
57
58
|
if (!shouldProxy(target)) {
|
|
58
59
|
return target;
|
|
59
60
|
}
|
|
60
61
|
if (target instanceof Map) {
|
|
61
|
-
return createMapProxy(target, path, onPatch);
|
|
62
|
+
return createMapProxy(target, rootKey, path, onPatch);
|
|
62
63
|
}
|
|
63
64
|
if (target instanceof Set) {
|
|
64
|
-
return createSetProxy(target, path, onPatch);
|
|
65
|
+
return createSetProxy(target, rootKey, path, onPatch);
|
|
65
66
|
}
|
|
66
|
-
return createObjectProxy(target, path, onPatch);
|
|
67
|
+
return createObjectProxy(target, rootKey, path, onPatch);
|
|
67
68
|
}
|
|
68
|
-
function createObjectProxy(target, path, onPatch) {
|
|
69
|
+
function createObjectProxy(target, rootKey, path, onPatch) {
|
|
69
70
|
const handler = {
|
|
70
71
|
get(obj, prop, receiver) {
|
|
71
72
|
const value = Reflect.get(obj, prop, receiver);
|
|
@@ -73,7 +74,7 @@ function createObjectProxy(target, path, onPatch) {
|
|
|
73
74
|
return value;
|
|
74
75
|
}
|
|
75
76
|
if (shouldProxy(value)) {
|
|
76
|
-
return createDeepProxy(value, [...path, prop], onPatch);
|
|
77
|
+
return createDeepProxy(value, rootKey, [...path, prop], onPatch);
|
|
77
78
|
}
|
|
78
79
|
return value;
|
|
79
80
|
},
|
|
@@ -85,6 +86,7 @@ function createObjectProxy(target, path, onPatch) {
|
|
|
85
86
|
if (success) {
|
|
86
87
|
onPatch({
|
|
87
88
|
op: "set",
|
|
89
|
+
key: rootKey,
|
|
88
90
|
path: [...path, prop],
|
|
89
91
|
value
|
|
90
92
|
});
|
|
@@ -99,6 +101,7 @@ function createObjectProxy(target, path, onPatch) {
|
|
|
99
101
|
if (success) {
|
|
100
102
|
onPatch({
|
|
101
103
|
op: "delete",
|
|
104
|
+
key: rootKey,
|
|
102
105
|
path: [...path, prop]
|
|
103
106
|
});
|
|
104
107
|
}
|
|
@@ -107,7 +110,7 @@ function createObjectProxy(target, path, onPatch) {
|
|
|
107
110
|
};
|
|
108
111
|
return new Proxy(target, handler);
|
|
109
112
|
}
|
|
110
|
-
function createMapProxy(target, path, onPatch) {
|
|
113
|
+
function createMapProxy(target, rootKey, path, onPatch) {
|
|
111
114
|
const handler = {
|
|
112
115
|
get(obj, prop) {
|
|
113
116
|
const value = Reflect.get(obj, prop);
|
|
@@ -120,6 +123,7 @@ function createMapProxy(target, path, onPatch) {
|
|
|
120
123
|
const result = obj.set(key, val);
|
|
121
124
|
onPatch({
|
|
122
125
|
op: "set",
|
|
126
|
+
key: rootKey,
|
|
123
127
|
path: [...path, key],
|
|
124
128
|
value: val
|
|
125
129
|
});
|
|
@@ -133,6 +137,7 @@ function createMapProxy(target, path, onPatch) {
|
|
|
133
137
|
if (hasKey) {
|
|
134
138
|
onPatch({
|
|
135
139
|
op: "delete",
|
|
140
|
+
key: rootKey,
|
|
136
141
|
path: [...path, key]
|
|
137
142
|
});
|
|
138
143
|
}
|
|
@@ -145,6 +150,7 @@ function createMapProxy(target, path, onPatch) {
|
|
|
145
150
|
const result = obj.clear();
|
|
146
151
|
onPatch({
|
|
147
152
|
op: "clear",
|
|
153
|
+
key: rootKey,
|
|
148
154
|
path
|
|
149
155
|
});
|
|
150
156
|
return result;
|
|
@@ -155,7 +161,7 @@ function createMapProxy(target, path, onPatch) {
|
|
|
155
161
|
return function(key) {
|
|
156
162
|
const getVal = obj.get(key);
|
|
157
163
|
if (shouldProxy(getVal)) {
|
|
158
|
-
return createDeepProxy(getVal, [...path, key], onPatch);
|
|
164
|
+
return createDeepProxy(getVal, rootKey, [...path, key], onPatch);
|
|
159
165
|
}
|
|
160
166
|
return getVal;
|
|
161
167
|
};
|
|
@@ -167,7 +173,7 @@ function createMapProxy(target, path, onPatch) {
|
|
|
167
173
|
};
|
|
168
174
|
return new Proxy(target, handler);
|
|
169
175
|
}
|
|
170
|
-
function createSetProxy(target, path, onPatch) {
|
|
176
|
+
function createSetProxy(target, rootKey, path, onPatch) {
|
|
171
177
|
const handler = {
|
|
172
178
|
get(obj, prop) {
|
|
173
179
|
const value = Reflect.get(obj, prop);
|
|
@@ -182,6 +188,7 @@ function createSetProxy(target, path, onPatch) {
|
|
|
182
188
|
if (!hasVal) {
|
|
183
189
|
onPatch({
|
|
184
190
|
op: "add",
|
|
191
|
+
key: rootKey,
|
|
185
192
|
// For set, we don't have a key to navigate, but we can pass the value
|
|
186
193
|
// In a true Sync scenario, Set diffing is tricky. Path is just the Set itself.
|
|
187
194
|
path,
|
|
@@ -198,6 +205,7 @@ function createSetProxy(target, path, onPatch) {
|
|
|
198
205
|
if (hasVal) {
|
|
199
206
|
onPatch({
|
|
200
207
|
op: "delete",
|
|
208
|
+
key: rootKey,
|
|
201
209
|
path,
|
|
202
210
|
// Similarly, deleting from set happens at Set boundary
|
|
203
211
|
value: val
|
|
@@ -213,6 +221,7 @@ function createSetProxy(target, path, onPatch) {
|
|
|
213
221
|
const result = obj.clear();
|
|
214
222
|
onPatch({
|
|
215
223
|
op: "clear",
|
|
224
|
+
key: rootKey,
|
|
216
225
|
path
|
|
217
226
|
});
|
|
218
227
|
return result;
|
|
@@ -239,9 +248,10 @@ var SyncProvider = class {
|
|
|
239
248
|
}
|
|
240
249
|
const ns = new SyncNamespaceProvider(namespace, this.bus);
|
|
241
250
|
this.namespaces.set(namespace, ns);
|
|
251
|
+
this.bus.emit("register", namespace);
|
|
242
252
|
return ns;
|
|
243
253
|
}
|
|
244
|
-
|
|
254
|
+
getStateSnapshot(namespace) {
|
|
245
255
|
const ns = this.namespaces.get(namespace);
|
|
246
256
|
if (!ns) {
|
|
247
257
|
throw new Error(`Namespace ${namespace} not found`);
|
|
@@ -272,7 +282,7 @@ var SyncNamespaceProvider = class {
|
|
|
272
282
|
for (const [key, item] of this.items.entries()) {
|
|
273
283
|
snapshot[key] = item.toValue();
|
|
274
284
|
}
|
|
275
|
-
return snapshot;
|
|
285
|
+
return SuperJSON.serialize(snapshot);
|
|
276
286
|
}
|
|
277
287
|
queuePatch(patch) {
|
|
278
288
|
this.queuedPatches.push(patch);
|
|
@@ -316,16 +326,18 @@ var SyncItemProvider = class {
|
|
|
316
326
|
setValue(newVal) {
|
|
317
327
|
this.onPatch({
|
|
318
328
|
op: "set",
|
|
319
|
-
|
|
329
|
+
key: this.key,
|
|
330
|
+
path: [],
|
|
320
331
|
value: newVal
|
|
321
332
|
});
|
|
322
|
-
this.value = createDeepProxy(newVal,
|
|
333
|
+
this.value = createDeepProxy(newVal, this.key, [], this.onPatch);
|
|
323
334
|
}
|
|
324
335
|
};
|
|
325
336
|
|
|
326
337
|
// src/receiver.ts
|
|
327
338
|
import Nanobus2 from "nanobus";
|
|
328
339
|
import { shallowRef, ref, triggerRef } from "@vue/reactivity";
|
|
340
|
+
import SuperJSON2 from "superjson";
|
|
329
341
|
var SyncReceiver = class {
|
|
330
342
|
constructor(options) {
|
|
331
343
|
this.options = options;
|
|
@@ -357,7 +369,8 @@ var SyncNamespaceReceiver = class {
|
|
|
357
369
|
if (this.items.has(key)) {
|
|
358
370
|
return this.items.get(key);
|
|
359
371
|
}
|
|
360
|
-
const
|
|
372
|
+
const snapshot = SuperJSON2.deserialize(this.snapshot);
|
|
373
|
+
const val = snapshot[key];
|
|
361
374
|
const item = new SyncItemReceiver(key, val);
|
|
362
375
|
this.items.set(key, item);
|
|
363
376
|
return item;
|
|
@@ -365,8 +378,7 @@ var SyncNamespaceReceiver = class {
|
|
|
365
378
|
applyPatches(patches) {
|
|
366
379
|
const affectedItems = /* @__PURE__ */ new Map();
|
|
367
380
|
for (const patch of patches) {
|
|
368
|
-
|
|
369
|
-
const key = patch.path[0];
|
|
381
|
+
const key = patch.key;
|
|
370
382
|
const item = this.items.get(key);
|
|
371
383
|
if (item) {
|
|
372
384
|
if (!affectedItems.has(item)) {
|
|
@@ -384,9 +396,9 @@ var SyncNamespaceReceiver = class {
|
|
|
384
396
|
}
|
|
385
397
|
}
|
|
386
398
|
applyPatchToObject(obj, patch) {
|
|
387
|
-
|
|
399
|
+
const fullPath = [patch.key, ...patch.path];
|
|
388
400
|
if (patch.op === "clear" || patch.op === "add") {
|
|
389
|
-
const target = navigatePath(obj,
|
|
401
|
+
const target = navigatePath(obj, fullPath, 0, fullPath.length);
|
|
390
402
|
if (patch.op === "clear") {
|
|
391
403
|
clearValue(target);
|
|
392
404
|
} else {
|
|
@@ -394,8 +406,8 @@ var SyncNamespaceReceiver = class {
|
|
|
394
406
|
}
|
|
395
407
|
return;
|
|
396
408
|
}
|
|
397
|
-
const current = navigatePath(obj,
|
|
398
|
-
const lastKey =
|
|
409
|
+
const current = navigatePath(obj, fullPath, 0, fullPath.length - 1);
|
|
410
|
+
const lastKey = fullPath[fullPath.length - 1];
|
|
399
411
|
if (patch.op === "set") {
|
|
400
412
|
setValueAtPath(current, lastKey, patch.value);
|
|
401
413
|
} else if (patch.op === "delete") {
|
|
@@ -431,7 +443,7 @@ var SyncItemReceiver = class {
|
|
|
431
443
|
return this._shallowRef;
|
|
432
444
|
}
|
|
433
445
|
applyPatch(patch) {
|
|
434
|
-
if (patch.path.length ===
|
|
446
|
+
if (patch.path.length === 0) {
|
|
435
447
|
if (patch.op === "set") {
|
|
436
448
|
this.value = patch.value;
|
|
437
449
|
if (this._ref) this._ref.value = patch.value;
|
|
@@ -441,41 +453,41 @@ var SyncItemReceiver = class {
|
|
|
441
453
|
}
|
|
442
454
|
const lastKey = patch.path[patch.path.length - 1];
|
|
443
455
|
if (patch.op === "set") {
|
|
444
|
-
const current = navigatePath(this.value, patch.path,
|
|
456
|
+
const current = navigatePath(this.value, patch.path, 0, patch.path.length - 1);
|
|
445
457
|
const refCurrent = navigatePath(
|
|
446
458
|
this._ref ? this._ref.value : null,
|
|
447
459
|
patch.path,
|
|
448
|
-
|
|
460
|
+
0,
|
|
449
461
|
patch.path.length - 1
|
|
450
462
|
);
|
|
451
463
|
setValueAtPath(current, lastKey, patch.value);
|
|
452
464
|
setValueAtPath(refCurrent, lastKey, patch.value);
|
|
453
465
|
} else if (patch.op === "delete") {
|
|
454
|
-
const current = navigatePath(this.value, patch.path,
|
|
466
|
+
const current = navigatePath(this.value, patch.path, 0, patch.path.length - 1);
|
|
455
467
|
const refCurrent = navigatePath(
|
|
456
468
|
this._ref ? this._ref.value : null,
|
|
457
469
|
patch.path,
|
|
458
|
-
|
|
470
|
+
0,
|
|
459
471
|
patch.path.length - 1
|
|
460
472
|
);
|
|
461
473
|
deleteValueAtPath(current, lastKey);
|
|
462
474
|
deleteValueAtPath(refCurrent, lastKey);
|
|
463
475
|
} else if (patch.op === "add") {
|
|
464
|
-
const target = navigatePath(this.value, patch.path,
|
|
476
|
+
const target = navigatePath(this.value, patch.path, 0, patch.path.length);
|
|
465
477
|
const refTarget = navigatePath(
|
|
466
478
|
this._ref ? this._ref.value : null,
|
|
467
479
|
patch.path,
|
|
468
|
-
|
|
480
|
+
0,
|
|
469
481
|
patch.path.length
|
|
470
482
|
);
|
|
471
483
|
addValueToSet(target, patch.value);
|
|
472
484
|
addValueToSet(refTarget, patch.value);
|
|
473
485
|
} else if (patch.op === "clear") {
|
|
474
|
-
const target = navigatePath(this.value, patch.path,
|
|
486
|
+
const target = navigatePath(this.value, patch.path, 0, patch.path.length);
|
|
475
487
|
const refTarget = navigatePath(
|
|
476
488
|
this._ref ? this._ref.value : null,
|
|
477
489
|
patch.path,
|
|
478
|
-
|
|
490
|
+
0,
|
|
479
491
|
patch.path.length
|
|
480
492
|
);
|
|
481
493
|
clearValue(target);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remote-state-sync",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A lightweight, fully type-safe unidirectional remote state synchronization library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -26,9 +26,11 @@
|
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
27
27
|
"exports": {
|
|
28
28
|
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
29
30
|
"import": "./dist/index.js",
|
|
30
|
-
"
|
|
31
|
-
}
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
32
34
|
},
|
|
33
35
|
"files": [
|
|
34
36
|
"dist"
|
|
@@ -66,6 +68,7 @@
|
|
|
66
68
|
},
|
|
67
69
|
"dependencies": {
|
|
68
70
|
"@vue/reactivity": "^3.5.28",
|
|
69
|
-
"nanobus": "^4.5.0"
|
|
71
|
+
"nanobus": "^4.5.0",
|
|
72
|
+
"superjson": "^2.2.6"
|
|
70
73
|
}
|
|
71
|
-
}
|
|
74
|
+
}
|