jsynchronous 0.9.3 → 0.9.6
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 +3 -1
- package/jsynchronous-client.d.ts +40 -0
- package/jsynchronous-client.js +35 -22
- package/jsynchronous.d.ts +41 -0
- package/jsynchronous.js +44 -21
- package/package.json +1 -1
- package/tests/selenium/test.js +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,8 @@ Jsynchronous can also handle server->server sync, or (experimentally) browser->s
|
|
|
52
52
|
|
|
53
53
|
# Setting up
|
|
54
54
|
|
|
55
|
+
Follow the [example code snippets](https://github.com/siriusastrebe/jsynchronous/tree/master/examples) for easy integration.
|
|
56
|
+
|
|
55
57
|
Jsynchronous does not lock you into a transportation medium you use whether it be [socket.io](https://socket.io/) [ws](https://www.npmjs.com/package/ws) [Primus](https://www.npmjs.com/package/primus), [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), or [webRTC](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API). Any protocol with eventual in-order delivery works. We will be using [ws](https://www.npmjs.com/package/ws) in this example.
|
|
56
58
|
|
|
57
59
|
The server side setup consists of 3 required steps:
|
|
@@ -255,7 +257,7 @@ $orientation.i = 0; // Will synchronize
|
|
|
255
257
|
$orientation.j = 1; // Will synchronize
|
|
256
258
|
```
|
|
257
259
|
|
|
258
|
-
We recommended you use the prefix ‘$’ or some other convention when you reference a synchronized variable to indicate that assignments to that variable will be sent over the network.
|
|
260
|
+
We recommended you use the prefix ‘$’ or some other convention when you reference a synchronized variable to indicate that the variable is reactive and assignments to that variable will be sent over the network.
|
|
259
261
|
|
|
260
262
|
# Documentation Reference
|
|
261
263
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
type Stand_In = 'object' | 'array';
|
|
2
|
+
type Event = 'changes' | 'snapshot';
|
|
3
|
+
type Event_Changes_Callback = (data: any) => void;
|
|
4
|
+
|
|
5
|
+
export type Synchronized_Variable<Variable_Type> = Variable_Type & {
|
|
6
|
+
$on: (event: Event, callback: Event_Changes_Callback) => void;
|
|
7
|
+
$info: () => {
|
|
8
|
+
client_history: boolean
|
|
9
|
+
counter: number
|
|
10
|
+
handshake: true
|
|
11
|
+
history_length: number
|
|
12
|
+
name: string
|
|
13
|
+
one_way: boolean
|
|
14
|
+
resyncs : number
|
|
15
|
+
rewind : boolean
|
|
16
|
+
rewound : boolean
|
|
17
|
+
snapshots : string[]
|
|
18
|
+
standIn : boolean
|
|
19
|
+
};
|
|
20
|
+
$tart: () => void;
|
|
21
|
+
$listeners: () => any[];
|
|
22
|
+
$napshot: (name: string) => void;
|
|
23
|
+
$rewind: (name: string, counter?: number) => void;
|
|
24
|
+
list: () => string[];
|
|
25
|
+
variables: () => { [key]: string, value: Synchronized_Variable<Variable_Type> };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare function jsynchronous<Variable_Type>(standInType: Stand_In, name?: string): Synchronized_Variable<Variable_Type>;
|
|
29
|
+
|
|
30
|
+
declare namespace jsynchronous {
|
|
31
|
+
export let send: (websocket: any, data: any) => void;
|
|
32
|
+
export const onmessage: (data: any) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default jsynchronous;
|
|
36
|
+
|
|
37
|
+
// export interface jsynchronous {
|
|
38
|
+
// <Synchronized_Variable>(standInType: Stand_In, name: string) => Synchronized_Type;
|
|
39
|
+
// send: (data: any) => void;
|
|
40
|
+
// }
|
package/jsynchronous-client.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
var jsynchronous;
|
|
2
2
|
|
|
3
3
|
function jsynchronousSetup() {
|
|
4
|
+
var ENCODE = false;
|
|
5
|
+
|
|
4
6
|
var TYPE_ENCODINGS = [
|
|
5
7
|
'array',
|
|
6
8
|
'object',
|
|
@@ -11,7 +13,8 @@ function jsynchronousSetup() {
|
|
|
11
13
|
'null',
|
|
12
14
|
'empty',
|
|
13
15
|
'bigint',
|
|
14
|
-
'function'
|
|
16
|
+
'function',
|
|
17
|
+
'date'
|
|
15
18
|
]
|
|
16
19
|
|
|
17
20
|
var OP_ENCODINGS = [
|
|
@@ -40,7 +43,7 @@ function jsynchronousSetup() {
|
|
|
40
43
|
|
|
41
44
|
function onmessage(data) {
|
|
42
45
|
var json = JSON.parse(data);
|
|
43
|
-
var op =
|
|
46
|
+
var op = decodeOp(json[0]);
|
|
44
47
|
var name = json[1];
|
|
45
48
|
|
|
46
49
|
if (op === 'initial') {
|
|
@@ -62,7 +65,7 @@ function jsynchronousSetup() {
|
|
|
62
65
|
if (jsynchronous.send) {
|
|
63
66
|
var uniqueId = 'initial' + name;
|
|
64
67
|
communicateWithBackoff(uniqueId, ['initial', name], function () {
|
|
65
|
-
console.
|
|
68
|
+
console.warn('Unknown jsynchronous variable, requesting initial' + name);
|
|
66
69
|
return jsyncs[name] === undefined;
|
|
67
70
|
}, 2000);
|
|
68
71
|
} else {
|
|
@@ -140,7 +143,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
function newJsynchronous(name, counter, settings, data) {
|
|
143
|
-
var rootType =
|
|
146
|
+
var rootType = decodeType(data[0][1]);
|
|
144
147
|
var jsync = jsyncObject(name, counter, settings);
|
|
145
148
|
var reserved;
|
|
146
149
|
if (settings) reserved = settings.reserved;
|
|
@@ -152,7 +155,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
152
155
|
for (var i=0; i<data.length; i++) {
|
|
153
156
|
var d = data[i];
|
|
154
157
|
var hash = d[0];
|
|
155
|
-
var type =
|
|
158
|
+
var type = decodeType(d[1]);
|
|
156
159
|
var each = d[2];
|
|
157
160
|
var description = createSyncedVariable(hash, type, each, jsync, (i === 0));
|
|
158
161
|
|
|
@@ -249,9 +252,6 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
249
252
|
hash: hash,
|
|
250
253
|
type: type,
|
|
251
254
|
variable: undefined,
|
|
252
|
-
descendants: {}, // key->value corresponds to descendant.hash->[properties]. Follow properties to find descendant
|
|
253
|
-
parents: {}, // key->value corresponds to parentHash->{details: parent, props: []}
|
|
254
|
-
children: {} // key->value corresponds to childHash->{details: child, props: []}
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
if (existing && detailedType(existing.variable) === type) {
|
|
@@ -266,7 +266,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
266
266
|
jsync.objects[hash] = details;
|
|
267
267
|
|
|
268
268
|
enumerate(each, type, function (prop, encoded) {
|
|
269
|
-
var t =
|
|
269
|
+
var t = decodeType(encoded[0])
|
|
270
270
|
var v = encoded[1];
|
|
271
271
|
|
|
272
272
|
if (isPrimitive(t)) {
|
|
@@ -320,7 +320,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
320
320
|
|
|
321
321
|
if (change === null) { continue }
|
|
322
322
|
|
|
323
|
-
var op =
|
|
323
|
+
var op = decodeOp(change[0]);
|
|
324
324
|
var hash = change[1];
|
|
325
325
|
var details;
|
|
326
326
|
var pt;
|
|
@@ -347,7 +347,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
347
347
|
} else if (op === 'new') {
|
|
348
348
|
var type = change[2];
|
|
349
349
|
var each = change[3];
|
|
350
|
-
createSyncedVariable(hash,
|
|
350
|
+
createSyncedVariable(hash, decodeType(type), each, jsync);
|
|
351
351
|
} else if (op === 'end') {
|
|
352
352
|
endObject(details, jsync);
|
|
353
353
|
} else if (op === 'snapshot') {
|
|
@@ -389,7 +389,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
389
389
|
}
|
|
390
390
|
function set(details, prop, newDetails, oldDetails, jsync) {
|
|
391
391
|
var object = details.variable;
|
|
392
|
-
var type =
|
|
392
|
+
var type = decodeType(newDetails[0]);
|
|
393
393
|
var value;
|
|
394
394
|
|
|
395
395
|
if (isPrimitive(type)) {
|
|
@@ -400,7 +400,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
400
400
|
value = childDetails.variable;
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
var oldType =
|
|
403
|
+
var oldType = decodeType(oldDetails[0]);
|
|
404
404
|
var oldValue;
|
|
405
405
|
|
|
406
406
|
if (isPrimitive(oldType)) {
|
|
@@ -414,7 +414,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
414
414
|
}
|
|
415
415
|
function del(details, prop, oldDetails, jsync) {
|
|
416
416
|
var object = details.variable;
|
|
417
|
-
var oldType =
|
|
417
|
+
var oldType = decodeType(oldDetails[0]);
|
|
418
418
|
var oldValue = oldDetails[1];
|
|
419
419
|
|
|
420
420
|
if (isPrimitive(oldType)) {
|
|
@@ -557,6 +557,8 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
557
557
|
return null;
|
|
558
558
|
} else if (type === 'function') {
|
|
559
559
|
return undefined; // Functions are, for now, read-only
|
|
560
|
+
} else if (type === 'date') {
|
|
561
|
+
return new Date(value);
|
|
560
562
|
}
|
|
561
563
|
}
|
|
562
564
|
function detailedType(value) {
|
|
@@ -596,7 +598,8 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
596
598
|
type === 'null' ||
|
|
597
599
|
type === 'empty' ||
|
|
598
600
|
type === 'bigint' ||
|
|
599
|
-
type === 'function'
|
|
601
|
+
type === 'function' || // Functions are, for now, read-only
|
|
602
|
+
type === 'date') {
|
|
600
603
|
return true
|
|
601
604
|
} else {
|
|
602
605
|
return false
|
|
@@ -662,15 +665,25 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
662
665
|
return mirror;
|
|
663
666
|
}
|
|
664
667
|
}
|
|
668
|
+
function decodeOp(number) {
|
|
669
|
+
if (ENCODE) {
|
|
670
|
+
return OP_ENCODINGS[number]
|
|
671
|
+
} else {
|
|
672
|
+
return number
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function decodeType(number) {
|
|
676
|
+
if (ENCODE) {
|
|
677
|
+
return TYPE_ENCODINGS[number];
|
|
678
|
+
} else {
|
|
679
|
+
return number;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
665
683
|
|
|
666
684
|
|
|
667
685
|
function addSynchronizedVariableMethods(jsync, targetVariable, reservedWords) {
|
|
668
686
|
// targetVariable will be details.variable if it's synced. Otherwise it should be a stand-in variable
|
|
669
|
-
for (var key in clientReservedWords) {
|
|
670
|
-
if (typeof targetVariable[key] === 'function') {
|
|
671
|
-
delete targetVariable[key];
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
687
|
if (reservedWords === undefined) reservedWords = {}
|
|
675
688
|
for (var key in clientReservedWords) {
|
|
676
689
|
if (!reservedWords[key]) {
|
|
@@ -754,7 +767,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
754
767
|
});
|
|
755
768
|
}
|
|
756
769
|
}
|
|
757
|
-
function triggerChanges(jsync
|
|
770
|
+
function triggerChanges(jsync) {
|
|
758
771
|
for (var j=0; j<jsync.changesEvents.length; j++) {
|
|
759
772
|
var e = jsync.changesEvents[j];
|
|
760
773
|
var variable = jsync.root.variable;
|
|
@@ -767,7 +780,7 @@ console.log('Unknown jsynchronous variable, requesting initial' + name);
|
|
|
767
780
|
// ----------------------------------------------------------------
|
|
768
781
|
function communicate(op, a, b, c, d) {
|
|
769
782
|
var payload = []
|
|
770
|
-
payload.push(OP_ENCODINGS.indexOf(op));
|
|
783
|
+
payload.push(ENCODE ? OP_ENCODINGS.indexOf(op) : op);
|
|
771
784
|
if (a !== undefined) payload.push(a);
|
|
772
785
|
if (b !== undefined) payload.push(b);
|
|
773
786
|
if (c !== undefined) payload.push(c);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type Event_Changes_Callback = (data: any) => void;
|
|
2
|
+
|
|
3
|
+
export type Synchronized_Variable<Variable_Type> = Variable_Type & {
|
|
4
|
+
$on: (event: Event, callback: Event_Changes_Callback) => void;
|
|
5
|
+
$ync: (websocket: any) => void;
|
|
6
|
+
$unsync: (websocket: any) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type JysnchronousOptions = {
|
|
10
|
+
rewind?: boolean;
|
|
11
|
+
one_way?: boolean;
|
|
12
|
+
send?: (websocket: any, data: any) => void;
|
|
13
|
+
buffer_time?: number;
|
|
14
|
+
client_history?: number;
|
|
15
|
+
history_limit?: number;
|
|
16
|
+
wait?: boolean;
|
|
17
|
+
$ync?: string;
|
|
18
|
+
$unsync?: string;
|
|
19
|
+
$on?: string;
|
|
20
|
+
$tart?: string;
|
|
21
|
+
$listeners?: string;
|
|
22
|
+
$info?: string;
|
|
23
|
+
$napshot?: string;
|
|
24
|
+
$rewind?: string;
|
|
25
|
+
$copy?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type Jsynchronous = {
|
|
29
|
+
<Variable_Type>(initialVariable: Variable_Type, name?: string, options?: JsynchronousOptions): Synchronized_Variable<Variable_Type>;
|
|
30
|
+
send: (websocket: any, data: any) => void;
|
|
31
|
+
onmessage: (websocket: any, data: any) => void;
|
|
32
|
+
list: () => string[];
|
|
33
|
+
variables: () => { [key: string]: Synchronized_Variable<Variable_Type> };
|
|
34
|
+
pausegc: () => void;
|
|
35
|
+
resumegc: () => void;
|
|
36
|
+
rungc: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare const jsynchronous: Jsynchronous;
|
|
40
|
+
|
|
41
|
+
export default jsynchronous;
|
package/jsynchronous.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const ENCODE = false;
|
|
4
|
+
|
|
3
5
|
const TYPE_ENCODINGS = {
|
|
4
6
|
'array': 0,
|
|
5
7
|
'object': 1,
|
|
@@ -10,7 +12,8 @@ const TYPE_ENCODINGS = {
|
|
|
10
12
|
'null': 6,
|
|
11
13
|
'empty': 7,
|
|
12
14
|
'bigint': 8,
|
|
13
|
-
'function': 9
|
|
15
|
+
'function': 9,
|
|
16
|
+
'date': 10
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
const OP_ENCODINGS = {
|
|
@@ -60,7 +63,7 @@ class Change {
|
|
|
60
63
|
}
|
|
61
64
|
encode() {
|
|
62
65
|
const change = [
|
|
63
|
-
|
|
66
|
+
encodeOp(this.operation),
|
|
64
67
|
this.hash,
|
|
65
68
|
this.prop,
|
|
66
69
|
encode(this.value, this.type),
|
|
@@ -82,7 +85,7 @@ class Creation {
|
|
|
82
85
|
}
|
|
83
86
|
encode() {
|
|
84
87
|
const creation = [
|
|
85
|
-
|
|
88
|
+
encodeOp(this.operation),
|
|
86
89
|
this.description[0],
|
|
87
90
|
this.description[1],
|
|
88
91
|
this.description[2]
|
|
@@ -106,7 +109,7 @@ class Deletion {
|
|
|
106
109
|
}
|
|
107
110
|
encode() {
|
|
108
111
|
const deletion = [
|
|
109
|
-
|
|
112
|
+
encodeOp(this.operation),
|
|
110
113
|
this.hash
|
|
111
114
|
]
|
|
112
115
|
return deletion;
|
|
@@ -132,7 +135,7 @@ class Snapshot {
|
|
|
132
135
|
}
|
|
133
136
|
encode() {
|
|
134
137
|
const snapshot = [
|
|
135
|
-
|
|
138
|
+
encodeOp(this.operation),
|
|
136
139
|
this.id,
|
|
137
140
|
this.name
|
|
138
141
|
]
|
|
@@ -272,7 +275,7 @@ class SyncedObject {
|
|
|
272
275
|
describe() {
|
|
273
276
|
const state = [
|
|
274
277
|
this.hash,
|
|
275
|
-
|
|
278
|
+
encodeOp(this.type),
|
|
276
279
|
newCollection(this.type, this.proxy)
|
|
277
280
|
]
|
|
278
281
|
|
|
@@ -435,7 +438,7 @@ class JSynchronous {
|
|
|
435
438
|
}
|
|
436
439
|
|
|
437
440
|
for (let [websocket, listener] of this.listeners) {
|
|
438
|
-
this.send(websocket, JSON.stringify([
|
|
441
|
+
this.send(websocket, JSON.stringify([encodeOp('changes'), this.name, min, max, changes]));
|
|
439
442
|
}
|
|
440
443
|
|
|
441
444
|
// Now that it's sent, the rest is history
|
|
@@ -470,7 +473,7 @@ class JSynchronous {
|
|
|
470
473
|
return c.encode();
|
|
471
474
|
});
|
|
472
475
|
|
|
473
|
-
this.send(websocket, JSON.stringify([
|
|
476
|
+
this.send(websocket, JSON.stringify([encodeOp('changes'), this.name, min, max, changes]));
|
|
474
477
|
}
|
|
475
478
|
}
|
|
476
479
|
}
|
|
@@ -557,7 +560,7 @@ class JSynchronous {
|
|
|
557
560
|
} catch (e) {
|
|
558
561
|
listener.penalty += 5; // Penalize clients heavily if they trigger errors
|
|
559
562
|
console.error("Jsynchronous client->server onmessage error", e);
|
|
560
|
-
jsynchronous.send(websocket, JSON.stringify([
|
|
563
|
+
jsynchronous.send(websocket, JSON.stringify([encodeOp('error'), e.toString()]));
|
|
561
564
|
}
|
|
562
565
|
}
|
|
563
566
|
handshake(websocket, listener, rootHash) {
|
|
@@ -567,7 +570,7 @@ class JSynchronous {
|
|
|
567
570
|
|
|
568
571
|
let secret = listener.secret || randomHash(); // no need to worry about collisions. Secrets aren't shared.
|
|
569
572
|
listener.secret = secret;
|
|
570
|
-
this.send(websocket, JSON.stringify([
|
|
573
|
+
this.send(websocket, JSON.stringify([encodeOp('handshake'), this.name, secret]));
|
|
571
574
|
}
|
|
572
575
|
resync(websocket, listener, json) {
|
|
573
576
|
let secret = json[2];
|
|
@@ -578,17 +581,17 @@ class JSynchronous {
|
|
|
578
581
|
let historyMax = historyMin + (max-min);
|
|
579
582
|
if (historyMin === -1 || historyMax >= this.history.length) {
|
|
580
583
|
// TODO: Hard reset on client
|
|
581
|
-
let payload = [
|
|
584
|
+
let payload = [encodeOp('error'), 'Unable to resync'];
|
|
582
585
|
jsynchronous.send(websocket, JSON.stringify(payload));
|
|
583
586
|
} else {
|
|
584
587
|
let slice = this.history.slice(historyMin, historyMax);
|
|
585
588
|
let encoded = slice.map((h) => h.encode());
|
|
586
|
-
let payload = [
|
|
589
|
+
let payload = [encodeOp('changes'), this.name, min, max-1, encoded];
|
|
587
590
|
this.send(websocket, JSON.stringify(payload));
|
|
588
591
|
}
|
|
589
592
|
} else {
|
|
590
593
|
// TODO: Tear this out, we don't need to be polite to clients that fail the secret check
|
|
591
|
-
let payload = [
|
|
594
|
+
let payload = [encodeOp('error'), 'Secret check failed'];
|
|
592
595
|
jsynchronous.send(websocket, JSON.stringify(payload));
|
|
593
596
|
}
|
|
594
597
|
}
|
|
@@ -712,7 +715,7 @@ class JSynchronous {
|
|
|
712
715
|
}
|
|
713
716
|
|
|
714
717
|
const fullState = [
|
|
715
|
-
|
|
718
|
+
encodeOp('initial'),
|
|
716
719
|
this.name,
|
|
717
720
|
this.counter,
|
|
718
721
|
settings
|
|
@@ -880,7 +883,8 @@ function isPrimitive(detailed) {
|
|
|
880
883
|
detailed === 'bigint' ||
|
|
881
884
|
detailed === 'null' || // Although null is in ECMA an object, we'll consider it a primitive for simplicity
|
|
882
885
|
detailed === 'undefined' ||
|
|
883
|
-
detailed === 'function'
|
|
886
|
+
detailed === 'function' || // For now, functions are just values as far as jsynchronous is concerned
|
|
887
|
+
detailed === 'date') {
|
|
884
888
|
return true;
|
|
885
889
|
} else {
|
|
886
890
|
return false;
|
|
@@ -1020,15 +1024,15 @@ function labelEmpty(source, target) {
|
|
|
1020
1024
|
if (value === undefined) {
|
|
1021
1025
|
allKeys = allKeys || Object.keys(source).map(k => Number(k));
|
|
1022
1026
|
if (binarySearch(allKeys, ((a) => a - i)) === -1) {
|
|
1023
|
-
target[i] = [
|
|
1027
|
+
target[i] = [encodeOp('empty')];
|
|
1024
1028
|
}
|
|
1025
1029
|
}
|
|
1026
1030
|
}
|
|
1027
1031
|
}
|
|
1028
1032
|
|
|
1029
1033
|
function encode(value, type) {
|
|
1030
|
-
// Expects value to be either be a primitive or a syncedObject Proxy
|
|
1031
|
-
const encoded = [
|
|
1034
|
+
// Expects value to be either be a primitive, a date or a syncedObject Proxy
|
|
1035
|
+
const encoded = [encodeOp(type)];
|
|
1032
1036
|
|
|
1033
1037
|
if (isPrimitive(type)) {
|
|
1034
1038
|
const p = encodePrimitive(value, type)
|
|
@@ -1051,6 +1055,7 @@ function encodePrimitive(value, type) {
|
|
|
1051
1055
|
if (type === 'boolean') return !!value ? 1 : 0;
|
|
1052
1056
|
if (type === 'bigint') return String(value);
|
|
1053
1057
|
if (type === 'function') return undefined;
|
|
1058
|
+
if (type === 'date') return value.getTime();
|
|
1054
1059
|
throw `Jsynchronous sanity error - Primitive is unserializable ${type}, ${value}`;
|
|
1055
1060
|
}
|
|
1056
1061
|
function encodeEnumerable(value) {
|
|
@@ -1061,8 +1066,26 @@ function encodeEnumerable(value) {
|
|
|
1061
1066
|
return syncedObject.hash;
|
|
1062
1067
|
}
|
|
1063
1068
|
function getOp(number) {
|
|
1064
|
-
|
|
1065
|
-
|
|
1069
|
+
if (ENCODE) {
|
|
1070
|
+
for (const [key, value] of Object.entries(OP_ENCODINGS)) {
|
|
1071
|
+
if (value === number) return key;
|
|
1072
|
+
}
|
|
1073
|
+
return false;
|
|
1074
|
+
} else {
|
|
1075
|
+
return number;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
function encodeType(type) {
|
|
1079
|
+
if (encode) {
|
|
1080
|
+
return TYPE_ENCODINGS[type];
|
|
1081
|
+
} else {
|
|
1082
|
+
return type;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
function encodeOp(op) {
|
|
1086
|
+
if (ENCODE) {
|
|
1087
|
+
return OP_ENCODINGS[op];
|
|
1088
|
+
} else {
|
|
1089
|
+
return op;
|
|
1066
1090
|
}
|
|
1067
|
-
return false;
|
|
1068
1091
|
}
|
package/package.json
CHANGED
package/tests/selenium/test.js
CHANGED
|
@@ -67,7 +67,7 @@ app.get('/jsynchronous-client.js', (req, res) => {
|
|
|
67
67
|
// ----------------------------------------------------------------
|
|
68
68
|
// Selenium Test
|
|
69
69
|
// ----------------------------------------------------------------
|
|
70
|
-
const browsers = ['firefox'
|
|
70
|
+
const browsers = ['firefox'];
|
|
71
71
|
let drivers = [];
|
|
72
72
|
const runTests = (async () => {
|
|
73
73
|
drivers = await Promise.all(browsers.map((browser) => new Builder().forBrowser(browser).build()));
|