react-native-mosquito-transport 0.0.19 → 0.0.21
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 +4 -0
- package/.jshintrc +16 -0
- package/README.md +75 -1
- package/TODO +8 -1
- package/ios/Mosquitodb.swift +14 -1
- package/package.json +13 -13
- package/src/helpers/engine_api.js +39 -0
- package/src/helpers/peripherals.js +73 -127
- package/src/helpers/utils.js +48 -19
- package/src/helpers/values.js +8 -47
- package/src/helpers/variables.js +14 -6
- package/src/index.d.ts +103 -43
- package/src/index.js +171 -96
- package/src/products/auth/accessor.js +97 -36
- package/src/products/auth/index.js +151 -82
- package/src/products/database/accessor.js +720 -223
- package/src/products/database/bson.js +16 -0
- package/src/products/database/counter.js +16 -0
- package/src/products/database/index.js +303 -190
- package/src/products/database/types.js +1 -1
- package/src/products/database/validator.js +517 -254
- package/src/products/http_callable/index.js +111 -106
- package/src/products/storage/index.js +97 -88
- package/src/helpers/EngineApi.js +0 -33
package/.jshintignore
ADDED
package/.jshintrc
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
"URL": true
|
|
15
|
+
}
|
|
16
|
+
}
|
package/README.md
CHANGED
|
@@ -1 +1,75 @@
|
|
|
1
|
-
# react-native-mosquito-transport
|
|
1
|
+
# react-native-mosquito-transport
|
|
2
|
+
|
|
3
|
+
React native javascript sdk for [mosquito-transport](https://github.com/brainbehindx/mosquito-transport).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install react-native-mosquito-transport --save
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
or using yarn
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
yarn add react-native-mosquito-transport
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import RNMosquitoTransport from "react-native-mosquito-transport";
|
|
21
|
+
|
|
22
|
+
RNMosquitoTransport.initializeCache({
|
|
23
|
+
cachePassword: "****",
|
|
24
|
+
cacheProtocol: "sqlite",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const mclient = new RNMosquitoTransport({
|
|
28
|
+
projectUrl: "http://localhost:3444",
|
|
29
|
+
accessKey: "SERVER_ACCESS_KEY",
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Additional Documentations
|
|
34
|
+
|
|
35
|
+
- [RNMosquitoTransport Constructor](#RNMosquitoTransportConstructor)
|
|
36
|
+
- [dbName](#dbName)
|
|
37
|
+
- [dbUrl](#dbUrl)
|
|
38
|
+
- [projectUrl](#projectUrl)
|
|
39
|
+
- [disableCache](#disableCache)
|
|
40
|
+
- [accessKey](#accessKey)
|
|
41
|
+
- [maxRetries](#maxRetries)
|
|
42
|
+
- [enableE2E_Encryption](#enableE2E_Encryption)
|
|
43
|
+
- [serverE2E_PublicKey](#serverE2E_PublicKey)
|
|
44
|
+
- [extraHeaders](#extraHeaders)
|
|
45
|
+
- [castBSON](#castBSON)
|
|
46
|
+
- [RNMosquitoTransport Methods](#RNMosquitoTransportMethods)
|
|
47
|
+
- [initialCache](#initialCache)
|
|
48
|
+
- [getDatabase](#getDatabase)
|
|
49
|
+
- [collection](#collection)
|
|
50
|
+
- [auth](#auth)
|
|
51
|
+
- [storage](#storage)
|
|
52
|
+
- [fetchHttp](#fetchHttp)
|
|
53
|
+
- [listenReachableServer](#listenReachableServer)
|
|
54
|
+
- [getSocket](#getSocket)
|
|
55
|
+
- [batchWrite](#batchWrite)
|
|
56
|
+
- [TIMESTAMP](#TIMESTAMP)
|
|
57
|
+
- [AUTH_PROVIDER_ID](#AUTH_PROVIDER_ID)
|
|
58
|
+
- [DOCUMENT_EXTRACTION](#DOCUMENT_EXTRACTION)
|
|
59
|
+
- [GEO_JSON](#GEO_JSON)
|
|
60
|
+
- [FIND_GEO_JSON](#FIND_GEO_JSON)
|
|
61
|
+
- [DoNotEncrypt](#DoNotEncrypt)
|
|
62
|
+
|
|
63
|
+
## RNMosquitoTransport Constructor
|
|
64
|
+
|
|
65
|
+
### dbName
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
### dbUrl
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
### projectUrl
|
|
72
|
+
|
|
73
|
+
this is the base url of
|
|
74
|
+
|
|
75
|
+
### disableCache
|
package/TODO
CHANGED
|
@@ -3,4 +3,11 @@
|
|
|
3
3
|
- reauthenticate
|
|
4
4
|
- change `Object` in d.ts to [key: string]: any
|
|
5
5
|
- add `getServerTimeOffset` method
|
|
6
|
-
- change null to undefined in `value`
|
|
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`
|
|
10
|
+
- minimize extraction data
|
|
11
|
+
- change `collection().onDisconnect()` to `collection().socket().onDisconnect()` and `collection().socket().onConnect()`
|
|
12
|
+
- add `_foreign_doc` to d.ts
|
|
13
|
+
- tree shake dependencies
|
package/ios/Mosquitodb.swift
CHANGED
|
@@ -95,11 +95,18 @@ class MosquitodbUploadTask: NSObject, URLSessionDataDelegate {
|
|
|
95
95
|
|
|
96
96
|
var request = URLRequest(url: URL(string: url)!)
|
|
97
97
|
request.httpMethod = "POST"
|
|
98
|
+
|
|
99
|
+
if let extraHeaders = options["extraHeaders"] as? [[String: String]] {
|
|
100
|
+
for (key, value) in extraHeaders {
|
|
101
|
+
request.setValue(value, forHTTPHeaderField: key)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
98
104
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
|
99
105
|
request.setValue(authorization, forHTTPHeaderField: "Authorization")
|
|
100
106
|
if options["authToken"] != nil {
|
|
101
107
|
request.setValue(options["authToken"] as? String, forHTTPHeaderField: "Mosquito-Token")
|
|
102
108
|
}
|
|
109
|
+
request.setValue(options["createHash"] as? String, forHTTPHeaderField: "hash-upload");
|
|
103
110
|
request.setValue("buffer/upload", forHTTPHeaderField: "Content-Type")
|
|
104
111
|
request.setValue(destination, forHTTPHeaderField: "Mosquito-Destination")
|
|
105
112
|
|
|
@@ -187,6 +194,12 @@ class MosquitodbDownloadTask: NSObject, URLSessionDownloadDelegate {
|
|
|
187
194
|
|
|
188
195
|
var request = URLRequest(url: URL(string: url)!)
|
|
189
196
|
request.httpMethod = "POST"
|
|
197
|
+
|
|
198
|
+
if let extraHeaders = options["extraHeaders"] as? [[String: String]] {
|
|
199
|
+
for (key, value) in extraHeaders {
|
|
200
|
+
request.setValue(value, forHTTPHeaderField: key)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
190
203
|
request.setValue(authorization, forHTTPHeaderField: "Authorization")
|
|
191
204
|
if options["authToken"] != nil {
|
|
192
205
|
request.setValue(options["authToken"] as? String, forHTTPHeaderField: "Mosquito-Token")
|
|
@@ -249,7 +262,7 @@ class MosquitodbDownloadTask: NSObject, URLSessionDownloadDelegate {
|
|
|
249
262
|
"result": "{\"file\": \"\(dest)\"}"
|
|
250
263
|
]
|
|
251
264
|
])
|
|
252
|
-
}else{
|
|
265
|
+
} else {
|
|
253
266
|
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
|
254
267
|
let urlName = mainOptions["urlName"] as! String
|
|
255
268
|
let destDir = documentsURL.appendingPathComponent("mosquito-transport")
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mosquito-transport",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "React native javascript sdk for mosquito-transport (https://github.com/
|
|
3
|
+
"version": "0.0.21",
|
|
4
|
+
"description": "React native javascript sdk for mosquito-transport (https://github.com/brainbehindx/mosquito-transport)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
9
|
},
|
|
9
10
|
"repository": {
|
|
10
11
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/
|
|
12
|
+
"url": "git+https://github.com/brainbehindx/react-native-mosquito-transport.git"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"mosquito-transport",
|
|
@@ -22,23 +23,22 @@
|
|
|
22
23
|
"author": "Anthony Onabanjo <deflexable@gmail.com> (https://github.com/deflexable)",
|
|
23
24
|
"license": "MIT",
|
|
24
25
|
"bugs": {
|
|
25
|
-
"url": "https://github.com/
|
|
26
|
+
"url": "https://github.com/brainbehindx/react-native-mosquito-transport/issues"
|
|
26
27
|
},
|
|
27
|
-
"homepage": "https://github.com/
|
|
28
|
+
"homepage": "https://github.com/brainbehindx/react-native-mosquito-transport#readme",
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@
|
|
30
|
-
"
|
|
30
|
+
"@turf/turf": "^7.1.0",
|
|
31
|
+
"bson": "^6.8.0",
|
|
31
32
|
"buffer": "^6.0.3",
|
|
32
33
|
"crypto-js": "^4.2.0",
|
|
33
|
-
"
|
|
34
|
-
"guard-object": "^1.
|
|
35
|
-
"
|
|
34
|
+
"entity-serializer": "^1.0.2",
|
|
35
|
+
"guard-object": "^1.1.3",
|
|
36
|
+
"lodash.clonedeep": "^4.5.0",
|
|
36
37
|
"lodash.get": "^4.4.2",
|
|
37
|
-
"lodash.isequal": "^4.5.0",
|
|
38
38
|
"lodash.set": "^4.3.2",
|
|
39
39
|
"lodash.unset": "^4.5.2",
|
|
40
40
|
"react-native-get-random-values": "^1.9.0",
|
|
41
|
-
"
|
|
41
|
+
"simplify-error": "^1.0.1",
|
|
42
42
|
"socket.io-client": "^4.6.2",
|
|
43
43
|
"subscription-listener": "^1.1.2",
|
|
44
44
|
"tweetnacl": "^1.0.3"
|
|
@@ -47,4 +47,4 @@
|
|
|
47
47
|
"react": "*",
|
|
48
48
|
"react-native": "*"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|
|
@@ -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,129 +3,44 @@ 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";
|
|
7
|
+
import { deserialize, serialize } from "entity-serializer";
|
|
6
8
|
|
|
7
9
|
const { encrypt, decrypt } = aes_pkg;
|
|
8
10
|
const { box, randomBytes } = naclPkg;
|
|
9
11
|
|
|
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
12
|
export const listenReachableServer = (callback, projectUrl) => {
|
|
102
13
|
let lastValue;
|
|
103
14
|
return ServerReachableListener.listenTo(projectUrl, t => {
|
|
104
15
|
if (typeof t === 'boolean' && t !== lastValue) callback?.(t);
|
|
105
16
|
}, true);
|
|
106
|
-
}
|
|
17
|
+
};
|
|
107
18
|
|
|
108
19
|
export const prefixStoragePath = (path, prefix = 'file:///') => {
|
|
109
|
-
|
|
20
|
+
let cleanedPath = path.replace(/^[^/]+:\/{1,3}/, '');
|
|
110
21
|
|
|
111
|
-
|
|
22
|
+
// Continuously remove any remaining protocol patterns until none are left
|
|
23
|
+
while (/^[^/]+:\/{1,3}/.test(cleanedPath)) {
|
|
24
|
+
cleanedPath = cleanedPath.replace(/^[^/]+:\/{1,3}/, '');
|
|
25
|
+
}
|
|
112
26
|
|
|
113
|
-
|
|
114
|
-
|
|
27
|
+
// Remove any leading slashes after protocol removal
|
|
28
|
+
cleanedPath = cleanedPath.replace(/^\/+/, '');
|
|
115
29
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return r === url ? '' : r;
|
|
119
|
-
}
|
|
30
|
+
return `${prefix}${cleanedPath}`;
|
|
31
|
+
};
|
|
120
32
|
|
|
121
33
|
export const niceTry = (promise) => new Promise(async resolve => {
|
|
122
|
-
|
|
123
34
|
try {
|
|
124
35
|
const r = await promise();
|
|
125
36
|
resolve(r);
|
|
126
37
|
} catch (e) { resolve(); }
|
|
127
38
|
});
|
|
128
39
|
|
|
40
|
+
export const normalizeRoute = (route = '') => route.split('').map((v, i, a) =>
|
|
41
|
+
((!i && v === '/') || (i === a.length - 1 && v === '/') || (i && a[i - 1] === '/' && v === '/')) ? '' : v
|
|
42
|
+
).join('');
|
|
43
|
+
|
|
129
44
|
export const shuffleArray = (n) => {
|
|
130
45
|
const array = [...n];
|
|
131
46
|
let currentIndex = array.length, randomIndex;
|
|
@@ -143,56 +58,87 @@ export const shuffleArray = (n) => {
|
|
|
143
58
|
}
|
|
144
59
|
|
|
145
60
|
export function sortArrayByObjectKey(arr = [], key) {
|
|
146
|
-
return arr.
|
|
61
|
+
return arr.sort(function (a, b) {
|
|
147
62
|
const left = getLodash(a, key),
|
|
148
63
|
right = getLodash(b, key);
|
|
149
64
|
|
|
150
65
|
return (left > right) ? 1 : (left < right) ? -1 : 0;
|
|
151
66
|
});
|
|
152
|
-
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export async function niceHash(str) {
|
|
70
|
+
try {
|
|
71
|
+
// Convert the string to a Uint8Array
|
|
72
|
+
const encoder = new TextEncoder();
|
|
73
|
+
const data = encoder.encode(str);
|
|
74
|
+
|
|
75
|
+
// Use the Web Crypto API to compute the hash
|
|
76
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
77
|
+
|
|
78
|
+
// Convert the ArrayBuffer to a hex string for readability
|
|
79
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
80
|
+
const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
|
|
81
|
+
|
|
82
|
+
// Convert to base64
|
|
83
|
+
return Buffer.from(hashHex, 'hex').toString('base64');
|
|
84
|
+
} catch (_) {
|
|
85
|
+
return str;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const sameInstance = (var1, var2) => {
|
|
90
|
+
try {
|
|
91
|
+
return var1.constructor === var2.constructor &&
|
|
92
|
+
Object.getPrototypeOf(var1) === Object.getPrototypeOf(var2)
|
|
93
|
+
} catch (_) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
153
97
|
|
|
154
98
|
export const encryptString = (txt, password, iv) => {
|
|
155
99
|
return encrypt(txt, `${password || ''}${iv || ''}`).toString();
|
|
156
|
-
}
|
|
100
|
+
};
|
|
157
101
|
|
|
158
102
|
export const decryptString = (txt, password, iv) => {
|
|
159
103
|
return decrypt(txt, `${password || ''}${iv || ''}`).toString(Utf8Encoder);
|
|
160
|
-
}
|
|
104
|
+
};
|
|
161
105
|
|
|
162
|
-
export const serializeE2E = (data, auth_token, serverPublicKey) => {
|
|
106
|
+
export const serializeE2E = async (data, auth_token, serverPublicKey) => {
|
|
163
107
|
const pair = box.keyPair(),
|
|
164
|
-
nonce = randomBytes(box.nonceLength)
|
|
165
|
-
pubBase64 = Buffer.from(pair.publicKey).toString('base64'),
|
|
166
|
-
nonceBase64 = Buffer.from(nonce).toString('base64');
|
|
108
|
+
nonce = randomBytes(box.nonceLength);
|
|
167
109
|
|
|
168
110
|
return [
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
111
|
+
serialize([
|
|
112
|
+
pair.publicKey,
|
|
113
|
+
nonce,
|
|
114
|
+
Buffer.from(
|
|
115
|
+
box(
|
|
116
|
+
serialize([
|
|
117
|
+
data,
|
|
118
|
+
auth_token
|
|
119
|
+
]),
|
|
120
|
+
nonce,
|
|
121
|
+
serverPublicKey,
|
|
122
|
+
pair.secretKey
|
|
123
|
+
)
|
|
178
124
|
)
|
|
179
|
-
)
|
|
125
|
+
]),
|
|
180
126
|
[pair.secretKey, pair.publicKey]
|
|
181
127
|
];
|
|
182
|
-
}
|
|
128
|
+
};
|
|
183
129
|
|
|
184
|
-
export const deserializeE2E = (data, serverPublicKey, clientPrivateKey) => {
|
|
185
|
-
const [binaryNonce, binaryData] = data
|
|
130
|
+
export const deserializeE2E = async (data, serverPublicKey, clientPrivateKey) => {
|
|
131
|
+
const [binaryNonce, binaryData] = deserialize(data),
|
|
186
132
|
baseArray = box.open(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
133
|
+
binaryData,
|
|
134
|
+
binaryNonce,
|
|
135
|
+
serverPublicKey,
|
|
190
136
|
clientPrivateKey
|
|
191
137
|
);
|
|
192
138
|
|
|
193
139
|
if (!baseArray) throw 'Decrypting e2e message failed';
|
|
194
|
-
return
|
|
195
|
-
}
|
|
140
|
+
return deserialize(baseArray);
|
|
141
|
+
};
|
|
196
142
|
|
|
197
143
|
export const encodeBinary = (s) => Buffer.from(s, 'utf8').toString('base64');
|
|
198
144
|
export const decodeBinary = (s) => Buffer.from(s, 'base64').toString('utf8');
|
package/src/helpers/utils.js
CHANGED
|
@@ -3,14 +3,28 @@ import { ServerReachableListener, StoreReadyListener } from "./listeners";
|
|
|
3
3
|
import { CACHE_PROTOCOL, CACHE_STORAGE_PATH, DEFAULT_CACHE_PASSWORD, LOCAL_STORAGE_PATH } from "./values";
|
|
4
4
|
import { CacheStore, Scoped } from "./variables";
|
|
5
5
|
import { decryptString, encryptString, niceTry, serializeE2E } from "./peripherals";
|
|
6
|
+
import { deserializeBSON, serializeToBase64 } from "../products/database/bson";
|
|
7
|
+
import { trySendPendingWrite } from "../products/database";
|
|
8
|
+
import { deserialize } from "entity-serializer";
|
|
6
9
|
|
|
7
|
-
export const updateCacheStore = () => {
|
|
8
|
-
const { cachePassword = DEFAULT_CACHE_PASSWORD, cacheProtocol = CACHE_PROTOCOL.ASYNC_STORAGE, io } = Scoped.ReleaseCacheData;
|
|
10
|
+
export const updateCacheStore = (timer = 300) => {
|
|
11
|
+
const { cachePassword = DEFAULT_CACHE_PASSWORD, cacheProtocol = CACHE_PROTOCOL.ASYNC_STORAGE, io, promoteCache } = Scoped.ReleaseCacheData;
|
|
9
12
|
|
|
10
13
|
clearTimeout(Scoped.cacheStorageReducer);
|
|
11
14
|
Scoped.cacheStorageReducer = setTimeout(() => {
|
|
15
|
+
const { AuthStore, EmulatedAuth, PendingAuthPurge, DatabaseStore, PendingWrites, ...restStore } = CacheStore;
|
|
16
|
+
|
|
12
17
|
const txt = encryptString(
|
|
13
|
-
JSON.stringify({
|
|
18
|
+
JSON.stringify({
|
|
19
|
+
AuthStore,
|
|
20
|
+
EmulatedAuth,
|
|
21
|
+
PendingAuthPurge,
|
|
22
|
+
...promoteCache ? {
|
|
23
|
+
DatabaseStore: serializeToBase64(DatabaseStore),
|
|
24
|
+
PendingWrites: serializeToBase64(PendingWrites)
|
|
25
|
+
} : {},
|
|
26
|
+
...promoteCache ? restStore : {}
|
|
27
|
+
}),
|
|
14
28
|
cachePassword,
|
|
15
29
|
cachePassword
|
|
16
30
|
);
|
|
@@ -19,12 +33,14 @@ export const updateCacheStore = () => {
|
|
|
19
33
|
io.output(txt);
|
|
20
34
|
} else if (cacheProtocol === CACHE_PROTOCOL.ASYNC_STORAGE) {
|
|
21
35
|
AsyncStorage.setItem(CACHE_STORAGE_PATH, txt);
|
|
36
|
+
} else if (cacheProtocol === CACHE_PROTOCOL.SQLITE) {
|
|
37
|
+
console.error('unsupported protocol "sqlite"');
|
|
22
38
|
} else {
|
|
23
39
|
const fs = require('react-native-fs');
|
|
24
40
|
fs.writeFile(LOCAL_STORAGE_PATH(), txt, 'utf8');
|
|
25
41
|
}
|
|
26
|
-
},
|
|
27
|
-
}
|
|
42
|
+
}, timer);
|
|
43
|
+
};
|
|
28
44
|
|
|
29
45
|
export const releaseCacheStore = async (builder) => {
|
|
30
46
|
const { cachePassword = DEFAULT_CACHE_PASSWORD, cacheProtocol = CACHE_PROTOCOL.ASYNC_STORAGE, io } = builder;
|
|
@@ -41,17 +57,26 @@ export const releaseCacheStore = async (builder) => {
|
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
const j = JSON.parse(decryptString(txt || '', cachePassword, cachePassword) || '{}');
|
|
60
|
+
const projectList = new Set([]);
|
|
44
61
|
|
|
45
62
|
Object.entries(j).forEach(([k, v]) => {
|
|
46
|
-
|
|
63
|
+
if (['DatabaseStore', 'PendingWrites'].includes(k)) {
|
|
64
|
+
CacheStore[k] = deserializeBSON(v);
|
|
65
|
+
} else CacheStore[k] = v;
|
|
66
|
+
projectList.add(k);
|
|
47
67
|
});
|
|
48
68
|
Object.entries(CacheStore.AuthStore).forEach(([key, value]) => {
|
|
49
69
|
Scoped.AuthJWTToken[key] = value?.token;
|
|
50
70
|
});
|
|
71
|
+
projectList.forEach(projectUrl => {
|
|
72
|
+
if (Scoped.IS_CONNECTED[projectUrl])
|
|
73
|
+
trySendPendingWrite(projectUrl);
|
|
74
|
+
});
|
|
51
75
|
Scoped.IsStoreReady = true;
|
|
52
76
|
StoreReadyListener.dispatch('_', 'ready');
|
|
53
|
-
|
|
54
|
-
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const getPrefferTime = () => Date.now() + (Scoped.serverTimeOffset || 0);
|
|
55
80
|
|
|
56
81
|
export const awaitStore = () => new Promise(resolve => {
|
|
57
82
|
if (Scoped.IsStoreReady) {
|
|
@@ -92,26 +117,30 @@ export const getReachableServer = (projectUrl) => new Promise(resolve => {
|
|
|
92
117
|
}, true);
|
|
93
118
|
});
|
|
94
119
|
|
|
95
|
-
export const buildFetchInterface = ({ body, accessKey, authToken, method, uglify, serverE2E_PublicKey }) => {
|
|
120
|
+
export const buildFetchInterface = async ({ body, accessKey, authToken, method, uglify, serverE2E_PublicKey, extraHeaders }) => {
|
|
96
121
|
if (!uglify) body = JSON.stringify({ ...body });
|
|
97
|
-
const [plate, keyPair] = uglify ? serializeE2E(body, authToken, serverE2E_PublicKey) : [undefined, []];
|
|
122
|
+
const [plate, keyPair] = uglify ? await serializeE2E(body, authToken, serverE2E_PublicKey) : [undefined, []];
|
|
98
123
|
|
|
99
124
|
return [{
|
|
100
125
|
body: uglify ? plate : body,
|
|
101
126
|
cache: 'no-cache',
|
|
102
127
|
headers: {
|
|
103
|
-
'Content-type': uglify ? '
|
|
128
|
+
'Content-type': uglify ? 'request/buffer' : 'application/json',
|
|
104
129
|
'Authorization': accessKey,
|
|
105
|
-
...(
|
|
130
|
+
...(authToken && !uglify) ? { 'Mosquito-Token': authToken } : {},
|
|
131
|
+
...extraHeaders
|
|
106
132
|
},
|
|
107
133
|
method: method || 'POST'
|
|
108
134
|
}, keyPair];
|
|
109
135
|
};
|
|
110
136
|
|
|
111
|
-
export const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
137
|
+
export const buildFetchResult = async (fetchRef, ugly) => {
|
|
138
|
+
if (ugly) {
|
|
139
|
+
const [data, simpleError] = deserialize(await fetchRef.arrayBuffer());
|
|
140
|
+
if (simpleError) throw simpleError;
|
|
141
|
+
return data;
|
|
142
|
+
}
|
|
143
|
+
const json = await fetchRef.json();
|
|
144
|
+
if (json.simpleError) throw json;
|
|
145
|
+
return json;
|
|
146
|
+
};
|