mosquito-transport-js 0.2.7 → 0.2.9
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/.jshintignore +2 -0
- package/.jshintrc +15 -0
- package/TODO +6 -1
- package/package.json +7 -7
- package/src/helpers/broadcaster.js +53 -0
- package/src/helpers/engine_api.js +39 -0
- package/src/helpers/peripherals.js +46 -107
- package/src/helpers/utils.js +30 -17
- package/src/helpers/values.js +3 -42
- package/src/helpers/variables.js +13 -6
- package/src/index.d.ts +33 -11
- package/src/index.js +139 -109
- package/src/products/auth/accessor.js +20 -16
- package/src/products/auth/index.js +50 -42
- package/src/products/database/accessor.js +759 -229
- package/src/products/database/bson.js +16 -0
- package/src/products/database/counter.js +16 -0
- package/src/products/database/index.js +265 -164
- package/src/products/database/types.js +1 -1
- package/src/products/database/validator.js +495 -254
- package/src/products/http_callable/index.js +99 -102
- package/src/products/storage/index.js +35 -38
- package/src/helpers/EngineApi.js +0 -33
package/.jshintignore
ADDED
package/.jshintrc
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"undef": true, // Warns on variables used before declaration
|
|
3
|
+
"esversion": 12,
|
|
4
|
+
"globals": {
|
|
5
|
+
"process": true,
|
|
6
|
+
"clearTimeout": true,
|
|
7
|
+
"setTimeout": true,
|
|
8
|
+
"console": true,
|
|
9
|
+
"Buffer": true,
|
|
10
|
+
"clearInterval": true,
|
|
11
|
+
"setInterval": true,
|
|
12
|
+
"AbortController": true,
|
|
13
|
+
"URLSearchParams": true
|
|
14
|
+
}
|
|
15
|
+
}
|
package/TODO
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
- fix local cache query on sqlite and fs
|
|
2
2
|
- fix and add all mongodb query and update operator
|
|
3
3
|
- reauthenticate
|
|
4
|
-
- change `Object` in d.ts to [key: string]: any
|
|
4
|
+
- change `Object` in d.ts to [key: string]: any
|
|
5
|
+
- add `getServerTimeOffset` method
|
|
6
|
+
- change null to undefined in `value`
|
|
7
|
+
- `provide functionality to add extra header to MT instance (all outgoing request)`
|
|
8
|
+
- borrowToken
|
|
9
|
+
- `add sqlite`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mosquito-transport-js",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Javascript web sdk for mosquito-transport (https://github.com/deflexable/mosquito-transport)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -28,18 +28,18 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/brainbehindx/mosquito-transport-js#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
31
|
+
"@turf/turf": "^7.1.0",
|
|
32
|
+
"bson": "^6.8.0",
|
|
33
33
|
"buffer": "^6.0.3",
|
|
34
34
|
"crypto-js": "^4.2.0",
|
|
35
|
-
"
|
|
36
|
-
"guard-object": "^1.0.7",
|
|
35
|
+
"guard-object": "^1.1.0",
|
|
37
36
|
"json-buffer": "^3.0.1",
|
|
37
|
+
"lodash.clonedeep": "^4.5.0",
|
|
38
38
|
"lodash.get": "^4.4.2",
|
|
39
|
-
"lodash.isequal": "^4.5.0",
|
|
40
39
|
"lodash.set": "^4.3.2",
|
|
41
40
|
"lodash.unset": "^4.5.2",
|
|
42
41
|
"set-large-timeout": "^1.0.1",
|
|
42
|
+
"simplify-error": "^1.0.1",
|
|
43
43
|
"socket.io-client": "^4.6.2",
|
|
44
44
|
"subscription-listener": "^1.1.2",
|
|
45
45
|
"tweetnacl": "^1.0.3"
|
|
@@ -57,4 +57,4 @@
|
|
|
57
57
|
"engines": {
|
|
58
58
|
"node": ">=14"
|
|
59
59
|
}
|
|
60
|
-
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { initTokenRefresher, triggerAuthToken } from "../products/auth/accessor";
|
|
2
|
+
import { notifyDatabaseNodeChanges, revertChanges, syncCache } from "../products/database/accessor";
|
|
3
|
+
import { deserializeBSON } from "../products/database/bson";
|
|
4
|
+
import { TokenRefreshListener } from "./listeners";
|
|
5
|
+
import { awaitStore } from "./utils";
|
|
6
|
+
import { CacheStore, Scoped } from "./variables";
|
|
7
|
+
|
|
8
|
+
const InstanceID = `${Math.random()}`;
|
|
9
|
+
const broadcaster = new BroadcastChannel('MT_BROADCASTER');
|
|
10
|
+
|
|
11
|
+
broadcaster.onmessage = async (e) => {
|
|
12
|
+
const { kind, context, data } = JSON.parse(e.data);
|
|
13
|
+
if (context === InstanceID) return;
|
|
14
|
+
await awaitStore();
|
|
15
|
+
|
|
16
|
+
if (kind === 'auth') {
|
|
17
|
+
const { projectUrl, authData } = data;
|
|
18
|
+
CacheStore.AuthStore[projectUrl] = authData;
|
|
19
|
+
Scoped.AuthJWTToken[projectUrl] = authData?.token;
|
|
20
|
+
TokenRefreshListener.dispatch(projectUrl);
|
|
21
|
+
triggerAuthToken(projectUrl);
|
|
22
|
+
initTokenRefresher(Scoped.InitializedProject[projectUrl]);
|
|
23
|
+
} else if (kind === 'database-sync') {
|
|
24
|
+
// only if cache protocol is in-memory
|
|
25
|
+
const { builder, result, writeId } = data;
|
|
26
|
+
const { editions, pathChanges } = syncCache(builder, deserializeBSON(result)._);
|
|
27
|
+
Scoped.broadcastedWrites[writeId] = { editions, builder };
|
|
28
|
+
notifyDatabaseNodeChanges(builder, pathChanges);
|
|
29
|
+
} else if (kind === 'database-revert') {
|
|
30
|
+
// only if cache protocol is in-memory
|
|
31
|
+
const { writeId, revert } = data;
|
|
32
|
+
if (!Scoped.broadcastedWrites[writeId]) return;
|
|
33
|
+
|
|
34
|
+
const { editions, builder } = Scoped.broadcastedWrites[writeId];
|
|
35
|
+
if (revert) {
|
|
36
|
+
const pathChanges = revertChanges(builder, editions);
|
|
37
|
+
notifyDatabaseNodeChanges(builder, pathChanges);
|
|
38
|
+
}
|
|
39
|
+
delete Scoped.broadcastedWrites[writeId];
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const sendMessage = (event, data) => {
|
|
44
|
+
broadcaster.postMessage(
|
|
45
|
+
JSON.stringify({
|
|
46
|
+
kind: event,
|
|
47
|
+
context: InstanceID,
|
|
48
|
+
data
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default sendMessage;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { encodeBinary } from './peripherals';
|
|
2
|
+
|
|
3
|
+
const EngineApiBase = (baseApi, ugly, path) => {
|
|
4
|
+
const url = new URL(baseApi);
|
|
5
|
+
if (ugly) {
|
|
6
|
+
url.pathname = `/e2e/${encodeBinary(path)}`;
|
|
7
|
+
} else url.pathname = path;
|
|
8
|
+
return url.href;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const apis = {
|
|
12
|
+
_readDocument: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_readDocument'),
|
|
13
|
+
_queryCollection: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_queryCollection'),
|
|
14
|
+
_documentCount: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_documentCount'),
|
|
15
|
+
_writeDocument: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_writeDocument'),
|
|
16
|
+
_writeMapDocument: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_writeMapDocument'),
|
|
17
|
+
_customSignin: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_customSignin'),
|
|
18
|
+
_customSignup: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_customSignup'),
|
|
19
|
+
_googleSignin: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_googleSignin'),
|
|
20
|
+
_appleSignin: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_appleSignin'),
|
|
21
|
+
_facebookSignin: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_facebookSignin'),
|
|
22
|
+
_twitterSignin: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_twitterSignin'),
|
|
23
|
+
_githubSignin: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_githubSignin'),
|
|
24
|
+
_signOut: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_signOut'),
|
|
25
|
+
_refreshAuthToken: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_refreshAuthToken'),
|
|
26
|
+
_uploadFile: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_uploadFile'),
|
|
27
|
+
_deleteFile: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_deleteFile'),
|
|
28
|
+
_deleteFolder: (baseApi, ugly) => EngineApiBase(baseApi, ugly, '_deleteFolder'),
|
|
29
|
+
staticStorage: (baseApi) => `${baseApi}/storage`,
|
|
30
|
+
_areYouOk: (baseApi) => `${baseApi}/_areYouOk`,
|
|
31
|
+
// static path
|
|
32
|
+
_listenCollection: (ugly) => ugly ? encodeBinary(apis._listenCollection()) : '_listenCollection',
|
|
33
|
+
_listenDocument: (ugly) => ugly ? encodeBinary(apis._listenDocument()) : '_listenDocument',
|
|
34
|
+
_startDisconnectWriteTask: (ugly) => ugly ? encodeBinary(apis._startDisconnectWriteTask()) : '_startDisconnectWriteTask',
|
|
35
|
+
_cancelDisconnectWriteTask: (ugly) => ugly ? encodeBinary(apis._cancelDisconnectWriteTask()) : '_cancelDisconnectWriteTask',
|
|
36
|
+
_listenUserVerification: (ugly) => ugly ? encodeBinary(apis._listenUserVerification()) : '_listenUserVerification'
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default { ...apis };
|
|
@@ -3,123 +3,33 @@ import { ServerReachableListener } from "./listeners";
|
|
|
3
3
|
import aes_pkg from 'crypto-js/aes.js';
|
|
4
4
|
import Utf8Encoder from 'crypto-js/enc-utf8.js';
|
|
5
5
|
import naclPkg from 'tweetnacl';
|
|
6
|
+
import getLodash from "lodash.get";
|
|
6
7
|
|
|
7
8
|
const { encrypt, decrypt } = aes_pkg;
|
|
8
9
|
const { box, randomBytes } = naclPkg;
|
|
9
10
|
|
|
10
|
-
export const simplifyError = (error, message) => ({
|
|
11
|
-
simpleError: { error, message }
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export const simplifyCaughtError = (e) => e?.simpleError ? e : simplifyError('unexpected_error', `${e}`);
|
|
15
|
-
|
|
16
|
-
export const everyEntrie = (obj, callback) => {
|
|
17
|
-
if (typeof obj !== 'object' || Array.isArray(obj)) return;
|
|
18
|
-
oEntries(obj).forEach(e => {
|
|
19
|
-
callback?.(e);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const flatEntries = (obj) => oEntries(obj);
|
|
24
|
-
|
|
25
|
-
export const flatRawEntries = () => oEntries(obj, false);
|
|
26
|
-
|
|
27
|
-
export const oEntries = (obj, includeObj = true) => {
|
|
28
|
-
let o = [];
|
|
29
|
-
|
|
30
|
-
Object.entries(obj).forEach(e => {
|
|
31
|
-
o.push(e);
|
|
32
|
-
if (e[1] && typeof e[1] === 'object' && !Array.isArray(e[1])) {
|
|
33
|
-
o = [...o, ...oEntries(e[1])];
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
return o.filter(v => includeObj || typeof v[1] !== 'object' || Array.isArray(v[1]));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export const IS_RAW_OBJECT = (e) => e && typeof e === 'object' && !Array.isArray(e) && !(e instanceof Date);
|
|
41
|
-
|
|
42
|
-
export const IS_WHOLE_NUMBER = (v) => typeof v === 'number' && !`${v}`.includes('.');
|
|
43
|
-
|
|
44
|
-
export const IS_DECIMAL_NUMBER = (v) => typeof v === 'number' && `${v}`.includes('.');
|
|
45
|
-
|
|
46
|
-
export const queryEntries = (obj, lastPath = '', exceptions = [], seperator = '.') => {
|
|
47
|
-
let o = [];
|
|
48
|
-
const isArraySeperator = Array.isArray(lastPath);
|
|
49
|
-
|
|
50
|
-
Object.entries(obj).forEach(([key, value]) => {
|
|
51
|
-
if (IS_RAW_OBJECT(value) && !exceptions.includes(key)) {
|
|
52
|
-
o = [
|
|
53
|
-
...o,
|
|
54
|
-
...queryEntries(
|
|
55
|
-
value,
|
|
56
|
-
isArraySeperator ? [...lastPath, key] : `${lastPath}${key}${seperator}`,
|
|
57
|
-
exceptions,
|
|
58
|
-
seperator
|
|
59
|
-
)
|
|
60
|
-
];
|
|
61
|
-
} else o.push(isArraySeperator ? [[...lastPath, key], value] : [`${lastPath}${key}`, value]);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return o;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export const objToUniqueString = (obj) => {
|
|
68
|
-
const keys = [],
|
|
69
|
-
values = [];
|
|
70
|
-
|
|
71
|
-
if (Array.isArray(obj)) {
|
|
72
|
-
obj.forEach(e => {
|
|
73
|
-
if (IS_RAW_OBJECT(e)) {
|
|
74
|
-
queryEntries(e).map(([k, v]) => {
|
|
75
|
-
keys.push(k);
|
|
76
|
-
values.push(v);
|
|
77
|
-
});
|
|
78
|
-
} else keys.push(Array.isArray(e) ? JSON.stringify(e) : `${e}`);
|
|
79
|
-
});
|
|
80
|
-
} else if (!IS_RAW_OBJECT(obj))
|
|
81
|
-
return `${obj}`;
|
|
82
|
-
else
|
|
83
|
-
queryEntries(obj).map(([k, v]) => {
|
|
84
|
-
keys.push(k);
|
|
85
|
-
values.push(v);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return [
|
|
89
|
-
...keys.sort(),
|
|
90
|
-
...values.map(v => `${Array.isArray(v) ? JSON.stringify(v) : v}`).sort()
|
|
91
|
-
].join(',');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export const cloneInstance = (v) => {
|
|
95
|
-
if (v && typeof v === 'object') {
|
|
96
|
-
return Array.isArray(v) ? [...v] : { ...v };
|
|
97
|
-
}
|
|
98
|
-
return v;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
11
|
export const listenReachableServer = (callback, projectUrl) => {
|
|
102
12
|
let lastValue;
|
|
103
13
|
return ServerReachableListener.listenTo(projectUrl, t => {
|
|
104
14
|
if (typeof t === 'boolean' && t !== lastValue) callback?.(t);
|
|
105
15
|
}, true);
|
|
106
|
-
}
|
|
16
|
+
};
|
|
107
17
|
|
|
108
18
|
export const prefixStoragePath = (path, prefix = 'file:///') => {
|
|
109
|
-
|
|
19
|
+
let cleanedPath = path.replace(/^[^/]+:\/{1,3}/, '');
|
|
110
20
|
|
|
111
|
-
|
|
21
|
+
// Continuously remove any remaining protocol patterns until none are left
|
|
22
|
+
while (/^[^/]+:\/{1,3}/.test(cleanedPath)) {
|
|
23
|
+
cleanedPath = cleanedPath.replace(/^[^/]+:\/{1,3}/, '');
|
|
24
|
+
}
|
|
112
25
|
|
|
113
|
-
|
|
114
|
-
|
|
26
|
+
// Remove any leading slashes after protocol removal
|
|
27
|
+
cleanedPath = cleanedPath.replace(/^\/+/, '');
|
|
115
28
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return r === url ? '' : r;
|
|
119
|
-
}
|
|
29
|
+
return `${prefix}${cleanedPath}`;
|
|
30
|
+
};
|
|
120
31
|
|
|
121
32
|
export const niceTry = (promise) => new Promise(async resolve => {
|
|
122
|
-
|
|
123
33
|
try {
|
|
124
34
|
const r = await promise();
|
|
125
35
|
resolve(r);
|
|
@@ -143,21 +53,50 @@ export const shuffleArray = (n) => {
|
|
|
143
53
|
}
|
|
144
54
|
|
|
145
55
|
export function sortArrayByObjectKey(arr = [], key) {
|
|
146
|
-
return arr.
|
|
56
|
+
return arr.sort(function (a, b) {
|
|
147
57
|
const left = getLodash(a, key),
|
|
148
58
|
right = getLodash(b, key);
|
|
149
59
|
|
|
150
60
|
return (left > right) ? 1 : (left < right) ? -1 : 0;
|
|
151
61
|
});
|
|
152
|
-
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export async function niceHash(str) {
|
|
65
|
+
try {
|
|
66
|
+
// Convert the string to a Uint8Array
|
|
67
|
+
const encoder = new TextEncoder();
|
|
68
|
+
const data = encoder.encode(str);
|
|
69
|
+
|
|
70
|
+
// Use the Web Crypto API to compute the hash
|
|
71
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
72
|
+
|
|
73
|
+
// Convert the ArrayBuffer to a hex string for readability
|
|
74
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
75
|
+
const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
|
|
76
|
+
|
|
77
|
+
// Convert to base64
|
|
78
|
+
return Buffer.from(hashHex, 'hex').toString('base64');
|
|
79
|
+
} catch (_) {
|
|
80
|
+
return str;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const sameInstance = (var1, var2) => {
|
|
85
|
+
try {
|
|
86
|
+
return var1.constructor === var2.constructor &&
|
|
87
|
+
Object.getPrototypeOf(var1) === Object.getPrototypeOf(var2)
|
|
88
|
+
} catch (_) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
153
92
|
|
|
154
93
|
export const encryptString = (txt, password, iv) => {
|
|
155
94
|
return encrypt(txt, `${password || ''}${iv || ''}`).toString();
|
|
156
|
-
}
|
|
95
|
+
};
|
|
157
96
|
|
|
158
97
|
export const decryptString = (txt, password, iv) => {
|
|
159
98
|
return decrypt(txt, `${password || ''}${iv || ''}`).toString(Utf8Encoder);
|
|
160
|
-
}
|
|
99
|
+
};
|
|
161
100
|
|
|
162
101
|
export const serializeE2E = (data, auth_token, serverPublicKey) => {
|
|
163
102
|
const pair = box.keyPair(),
|
|
@@ -179,7 +118,7 @@ export const serializeE2E = (data, auth_token, serverPublicKey) => {
|
|
|
179
118
|
).toString('base64')}`,
|
|
180
119
|
[pair.secretKey, pair.publicKey]
|
|
181
120
|
];
|
|
182
|
-
}
|
|
121
|
+
};
|
|
183
122
|
|
|
184
123
|
export const deserializeE2E = (data, serverPublicKey, clientPrivateKey) => {
|
|
185
124
|
const [binaryNonce, binaryData] = data.split('.'),
|
|
@@ -192,7 +131,7 @@ export const deserializeE2E = (data, serverPublicKey, clientPrivateKey) => {
|
|
|
192
131
|
|
|
193
132
|
if (!baseArray) throw 'Decrypting e2e message failed';
|
|
194
133
|
return JSON.parse(Buffer.from(baseArray).toString('utf8'))[0];
|
|
195
|
-
}
|
|
134
|
+
};
|
|
196
135
|
|
|
197
136
|
export const encodeBinary = (s) => Buffer.from(s, 'utf8').toString('base64');
|
|
198
137
|
export const decodeBinary = (s) => Buffer.from(s, 'base64').toString('utf8');
|
package/src/helpers/utils.js
CHANGED
|
@@ -2,19 +2,31 @@ import { ServerReachableListener, StoreReadyListener } from "./listeners";
|
|
|
2
2
|
import { CACHE_PROTOCOL, CACHE_STORAGE_PATH, DEFAULT_CACHE_PASSWORD } from "./values";
|
|
3
3
|
import { CacheStore, Scoped } from "./variables";
|
|
4
4
|
import { decryptString, encryptString, serializeE2E } from "./peripherals";
|
|
5
|
+
import { deserializeBSON, serializeToBase64 } from "../products/database/bson";
|
|
6
|
+
import { trySendPendingWrite } from "../products/database";
|
|
5
7
|
|
|
6
|
-
export const updateCacheStore = () => {
|
|
8
|
+
export const updateCacheStore = (timer = 300) => {
|
|
7
9
|
try { window } catch (_) { return; }
|
|
8
10
|
const {
|
|
9
11
|
cachePassword = DEFAULT_CACHE_PASSWORD,
|
|
10
12
|
cacheProtocol = CACHE_PROTOCOL.LOCAL_STORAGE,
|
|
11
|
-
io
|
|
13
|
+
io,
|
|
14
|
+
promoteCache
|
|
12
15
|
} = Scoped.ReleaseCacheData;
|
|
13
16
|
|
|
14
17
|
clearTimeout(Scoped.cacheStorageReducer);
|
|
15
18
|
Scoped.cacheStorageReducer = setTimeout(() => {
|
|
19
|
+
const { AuthStore, DatabaseStore, PendingWrites, ...restStore } = CacheStore;
|
|
20
|
+
|
|
16
21
|
const txt = encryptString(
|
|
17
|
-
JSON.stringify({
|
|
22
|
+
JSON.stringify({
|
|
23
|
+
AuthStore,
|
|
24
|
+
...promoteCache ? {
|
|
25
|
+
DatabaseStore: serializeToBase64(DatabaseStore),
|
|
26
|
+
PendingWrites: serializeToBase64(PendingWrites)
|
|
27
|
+
} : {},
|
|
28
|
+
...promoteCache ? restStore : {}
|
|
29
|
+
}),
|
|
18
30
|
cachePassword,
|
|
19
31
|
cachePassword
|
|
20
32
|
);
|
|
@@ -24,8 +36,8 @@ export const updateCacheStore = () => {
|
|
|
24
36
|
} else if (cacheProtocol === CACHE_PROTOCOL.LOCAL_STORAGE) {
|
|
25
37
|
window.localStorage.setItem(CACHE_STORAGE_PATH, txt);
|
|
26
38
|
}
|
|
27
|
-
},
|
|
28
|
-
}
|
|
39
|
+
}, timer);
|
|
40
|
+
};
|
|
29
41
|
|
|
30
42
|
export const releaseCacheStore = async (builder) => {
|
|
31
43
|
try { window } catch (_) { return; }
|
|
@@ -44,17 +56,26 @@ export const releaseCacheStore = async (builder) => {
|
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
const j = JSON.parse(decryptString(txt || '', cachePassword, cachePassword) || '{}');
|
|
59
|
+
const projectList = new Set([]);
|
|
47
60
|
|
|
48
61
|
Object.entries(j).forEach(([k, v]) => {
|
|
49
|
-
|
|
62
|
+
if (['DatabaseStore', 'PendingWrites'].includes(k)) {
|
|
63
|
+
CacheStore[k] = deserializeBSON(v);
|
|
64
|
+
} else CacheStore[k] = v;
|
|
65
|
+
projectList.add(k);
|
|
50
66
|
});
|
|
51
67
|
Object.entries(CacheStore.AuthStore).forEach(([key, value]) => {
|
|
52
68
|
Scoped.AuthJWTToken[key] = value?.token;
|
|
53
69
|
});
|
|
70
|
+
projectList.forEach(projectUrl => {
|
|
71
|
+
if (Scoped.IS_CONNECTED[projectUrl])
|
|
72
|
+
trySendPendingWrite(projectUrl);
|
|
73
|
+
});
|
|
54
74
|
Scoped.IsStoreReady = true;
|
|
55
75
|
StoreReadyListener.dispatch('_', 'ready');
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const getPrefferTime = () => Date.now() + (Scoped.serverTimeOffset || 0);
|
|
58
79
|
|
|
59
80
|
export const awaitStore = () => new Promise(resolve => {
|
|
60
81
|
if (Scoped.IsStoreReady) {
|
|
@@ -109,12 +130,4 @@ export const buildFetchInterface = ({ body, accessKey, authToken, method, uglify
|
|
|
109
130
|
},
|
|
110
131
|
method: method || 'POST'
|
|
111
132
|
}, keyPair];
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export const simplifyError = (error, message) => ({
|
|
115
|
-
simpleError: { error, message }
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
export const validateRequestMethod = (method) => {
|
|
119
|
-
// TODO:
|
|
120
|
-
}
|
|
133
|
+
};
|
package/src/helpers/values.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { encodeBinary } from './peripherals';
|
|
2
2
|
|
|
3
3
|
export const CACHE_STORAGE_PATH = encodeBinary('MOSQUITO_TRANSPORT_FREEZER'),
|
|
4
|
-
DEFAULT_CACHE_PASSWORD = encodeBinary('MOSQUITO_TRANSPORT_CACHE_PASSWORD')
|
|
5
|
-
DEFAULT_DB_NAME = 'DEFAULT_DB',
|
|
6
|
-
DEFAULT_DB_URL = 'mongodb://127.0.0.1:27017',
|
|
7
|
-
DEFAULT_ENCRYPT_IV = '****';
|
|
4
|
+
DEFAULT_CACHE_PASSWORD = encodeBinary('MOSQUITO_TRANSPORT_CACHE_PASSWORD');
|
|
8
5
|
|
|
9
6
|
export const CACHE_PROTOCOL = {
|
|
10
7
|
LOCAL_STORAGE: 'local-storage'
|
|
@@ -16,7 +13,8 @@ export const RETRIEVAL = {
|
|
|
16
13
|
STICKY_RELOAD: 'sticky-reload',
|
|
17
14
|
DEFAULT: 'default',
|
|
18
15
|
CACHE_NO_AWAIT: 'cache-no-await',
|
|
19
|
-
NO_CACHE_NO_AWAIT: 'no-cache-no-await'
|
|
16
|
+
NO_CACHE_NO_AWAIT: 'no-cache-no-await',
|
|
17
|
+
NO_CACHE_AWAIT: 'no-cache-await'
|
|
20
18
|
};
|
|
21
19
|
|
|
22
20
|
export const DELIVERY = {
|
|
@@ -28,43 +26,6 @@ export const DELIVERY = {
|
|
|
28
26
|
CACHE_NO_AWAIT: 'cache-no-await'
|
|
29
27
|
};
|
|
30
28
|
|
|
31
|
-
export const WRITE_OPS = {
|
|
32
|
-
$SET: '$set',
|
|
33
|
-
$PUSH: '$push',
|
|
34
|
-
$PULL: '$pull',
|
|
35
|
-
$UNSET: '$unset',
|
|
36
|
-
$INC: '$inc',
|
|
37
|
-
$MAX: '$max',
|
|
38
|
-
$MIN: '$min',
|
|
39
|
-
$MUL: '$mul',
|
|
40
|
-
$RENAME: '$rename',
|
|
41
|
-
$SET_ON_INSERT: '$setOnInsert'
|
|
42
|
-
};
|
|
43
|
-
export const WRITE_OPS_LIST = Object.values(WRITE_OPS);
|
|
44
|
-
|
|
45
|
-
export const READ_OPS = {
|
|
46
|
-
$IN: '$in',
|
|
47
|
-
$ALL: '$all',
|
|
48
|
-
$NIN: '$nin',
|
|
49
|
-
$GT: '$gt',
|
|
50
|
-
$GTE: '$gte',
|
|
51
|
-
$LT: '$lt',
|
|
52
|
-
$LTE: '$lte',
|
|
53
|
-
$TEXT: '$text',
|
|
54
|
-
// $EQ: '$eq',
|
|
55
|
-
// $REGEX: '$regex',
|
|
56
|
-
// $EXISTS: '$exists',
|
|
57
|
-
$NEAR: '$near',
|
|
58
|
-
$TYPE: '$type',
|
|
59
|
-
$SIZE: '$size',
|
|
60
|
-
// $NE: '$ne'
|
|
61
|
-
};
|
|
62
|
-
export const READ_OPS_LIST = Object.values(READ_OPS);
|
|
63
|
-
|
|
64
|
-
export const Regexs = {
|
|
65
|
-
LINK: () => /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
|
|
66
|
-
};
|
|
67
|
-
|
|
68
29
|
export const AUTH_PROVIDER_ID = {
|
|
69
30
|
GOOGLE: 'google.com',
|
|
70
31
|
FACEBOOK: 'facebook.com',
|
package/src/helpers/variables.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
|
|
1
2
|
export const Scoped = {
|
|
3
|
+
serverTimeOffset: undefined,
|
|
2
4
|
PendingIte: 0,
|
|
3
5
|
AnyProcessIte: 0,
|
|
4
6
|
IS_CONNECTED: {},
|
|
@@ -19,16 +21,21 @@ export const Scoped = {
|
|
|
19
21
|
PendingDbReadCollective: {
|
|
20
22
|
pendingProcess: {},
|
|
21
23
|
pendingResolution: {}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
+
},
|
|
25
|
+
ActiveDatabaseListeners: {},
|
|
26
|
+
OutgoingWrites: {},
|
|
27
|
+
/**
|
|
28
|
+
* @type {Promise<any> | undefined}
|
|
29
|
+
*/
|
|
30
|
+
dispatchingWritesPromise: undefined,
|
|
31
|
+
broadcastedWrites: {}
|
|
32
|
+
};
|
|
24
33
|
|
|
25
34
|
export const CacheStore = {
|
|
26
35
|
DatabaseStore: {},
|
|
27
|
-
DatabaseRecords: {},
|
|
28
36
|
DatabaseCountResult: {},
|
|
37
|
+
DatabaseStats: {},
|
|
29
38
|
AuthStore: {},
|
|
30
39
|
PendingWrites: {},
|
|
31
40
|
FetchedStore: {}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const CacheConstant = { ...CacheStore };
|
|
41
|
+
};
|
package/src/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
interface MTConfig {
|
|
2
2
|
dbName?: string;
|
|
3
3
|
dbUrl?: string;
|
|
4
|
-
heapMemory?: number;
|
|
5
4
|
projectUrl: string;
|
|
6
5
|
disableCache?: boolean;
|
|
7
6
|
accessKey: string;
|
|
7
|
+
/**
|
|
8
|
+
* maximum numbers of attempts to retry sending a request
|
|
9
|
+
*/
|
|
8
10
|
maxRetries?: number;
|
|
9
11
|
/**
|
|
10
12
|
* setting this to true will encrypt all outgoing and incoming request. This enables end-to-end encryption using [Tweetnacl](https://github.com/dchest/tweetnacl-js) and to prevent request interception by browser extensions, network intermediaries or other hijacking tools
|
|
@@ -14,6 +16,12 @@ interface MTConfig {
|
|
|
14
16
|
* this is the base64 public key for end-to-end encryption on the server
|
|
15
17
|
*/
|
|
16
18
|
serverE2E_PublicKey?: string;
|
|
19
|
+
/**
|
|
20
|
+
* true to deserialize BSON values to their Node.js closest equivalent types
|
|
21
|
+
*
|
|
22
|
+
* @default true
|
|
23
|
+
*/
|
|
24
|
+
castBSON?: boolean;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
interface GetDatabase {
|
|
@@ -34,7 +42,7 @@ export function GEO_JSON(latitude: latitude, longitude: longitude): {
|
|
|
34
42
|
};
|
|
35
43
|
|
|
36
44
|
export function FIND_GEO_JSON(coordinates: [latitude, longitude], offSetMeters: number, centerMeters?: number): {
|
|
37
|
-
$
|
|
45
|
+
$nearSphere: {
|
|
38
46
|
$geometry: {
|
|
39
47
|
type: "Point",
|
|
40
48
|
coordinates: [longitude, latitude]
|
|
@@ -76,7 +84,7 @@ interface ReleaseCacheOption_IO {
|
|
|
76
84
|
* emits mosquito-transport internal data
|
|
77
85
|
*/
|
|
78
86
|
output: (data: string) => void;
|
|
79
|
-
}
|
|
87
|
+
};
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
interface ReleaseCacheOption {
|
|
@@ -88,7 +96,18 @@ interface ReleaseCacheOption {
|
|
|
88
96
|
* select the mechanism for storing data locally
|
|
89
97
|
* - local-storage: uses [@react-native-async-storage/async-storage]() for storing data
|
|
90
98
|
*/
|
|
91
|
-
cacheProtocol?: 'local-storage';
|
|
99
|
+
cacheProtocol?: 'local-storage' | 'indexdb';
|
|
100
|
+
/**
|
|
101
|
+
* the maximum database size
|
|
102
|
+
*/
|
|
103
|
+
heapMemory?: number;
|
|
104
|
+
/**
|
|
105
|
+
* true to cache database and {@link MosquitoTransport.fetchHttp} data.
|
|
106
|
+
* the value only applies to in-memory storage protocol such as `io` and `local-storage`
|
|
107
|
+
*
|
|
108
|
+
* @default false
|
|
109
|
+
*/
|
|
110
|
+
promoteCache?: boolean;
|
|
92
111
|
}
|
|
93
112
|
|
|
94
113
|
interface MTSocket {
|
|
@@ -243,7 +262,7 @@ interface WriteConfig {
|
|
|
243
262
|
delivery?: Delievery;
|
|
244
263
|
}
|
|
245
264
|
|
|
246
|
-
type Retrieval = 'sticky' | 'sticky-no-await' | 'sticky-reload' | 'default' | 'cache-no-await' | 'no-cache-no-await';
|
|
265
|
+
type Retrieval = 'sticky' | 'sticky-no-await' | 'sticky-reload' | 'default' | 'cache-no-await' | 'no-cache-no-await' | 'no-cache-await';
|
|
247
266
|
|
|
248
267
|
interface GetConfig {
|
|
249
268
|
excludeFields?: string | string[];
|
|
@@ -252,17 +271,19 @@ interface GetConfig {
|
|
|
252
271
|
/**
|
|
253
272
|
* This property determines how requested data is being access and handled
|
|
254
273
|
*
|
|
255
|
-
* - default:
|
|
274
|
+
* - default: will try getting fresh data from server if server is reachable, else we check if local data exists and return it, if no local data exist we await for client->server connectivity, then try getting the data, return it and cache it for future need. ⚠️ This respect disableCache value
|
|
256
275
|
*
|
|
257
276
|
* - sticky: if local data exists for the specified query, such data is returned and no-ops afterwards. If no local data is found, we await for client->server connectivity and try to get fresh data from serve, return the data and cache it for future need. ⚠️ This does not respect disableCache value
|
|
258
277
|
*
|
|
259
|
-
* - sticky-no-await: if local data exists for the specified query, such data is returned and no-ops afterwards. If no local data is found,
|
|
278
|
+
* - sticky-no-await: if local data exists for the specified query, such data is returned and no-ops afterwards. If no local data is found, will try to get fresh data from serve, we throw an error if server is not reachable else if server returns requested data, we return such data and cache it for future need. ⚠️ This does not respect disableCache value
|
|
279
|
+
*
|
|
280
|
+
* - sticky-reload: if local data exists for the specified query, such data is returned, then will try getting fresh data from the server and caching it for future need. If no local data is found, we await for client->server connectivity and try to get fresh data from serve, return the data and cache it for future need
|
|
260
281
|
*
|
|
261
|
-
* -
|
|
282
|
+
* - cache-no-await: will try getting fresh data from server if server is reachable, else we check if local data exists and return it, if no local data exist we throw an error
|
|
262
283
|
*
|
|
263
|
-
* - cache-no-await:
|
|
284
|
+
* - no-cache-no-await: will try getting fresh data from server if server is reachable, else we throw an error
|
|
264
285
|
*
|
|
265
|
-
* - no-cache-
|
|
286
|
+
* - no-cache-await: will try getting fresh data from server when server is reachable and the result won't be cache
|
|
266
287
|
*
|
|
267
288
|
* To learn and see more examples on this, Please visit https://brainbehindx.com/mosquito-transport/docs/reading_data/retrieval
|
|
268
289
|
*/
|
|
@@ -417,11 +438,12 @@ declare type Base64String = string;
|
|
|
417
438
|
|
|
418
439
|
interface ReqOptions {
|
|
419
440
|
awaitServer?: boolean;
|
|
441
|
+
createHash?: boolean;
|
|
420
442
|
}
|
|
421
443
|
|
|
422
444
|
interface MTStorage {
|
|
423
445
|
downloadFile: (link: string, onComplete?: (error?: ErrorResponse, filepath?: string) => void, destination?: string, onProgress?: (stats: DownloadProgressStats) => void) => () => void;
|
|
424
|
-
uploadFile: (file: Base64String | Blob | Buffer, destination: string, onComplete?: (error?: ErrorResponse, downloadUrl?: string) => void, onProgress?: (stats: UploadProgressStats) => void, options?: ReqOptions) => () => void;
|
|
446
|
+
uploadFile: (file: Base64String | Blob | Buffer | File, destination: string, onComplete?: (error?: ErrorResponse, downloadUrl?: string) => void, onProgress?: (stats: UploadProgressStats) => void, options?: ReqOptions) => () => void;
|
|
425
447
|
deleteFile: (path: string) => Promise<void>;
|
|
426
448
|
deleteFolder: (folder: string) => Promise<void>;
|
|
427
449
|
}
|