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
|
@@ -1,63 +1,85 @@
|
|
|
1
1
|
import { Buffer } from "buffer";
|
|
2
|
-
import {
|
|
3
|
-
import { awaitStore, getReachableServer, updateCacheStore
|
|
4
|
-
import { RETRIEVAL
|
|
2
|
+
import { deserializeE2E, listenReachableServer, niceHash, normalizeRoute, serializeE2E } from "../../helpers/peripherals";
|
|
3
|
+
import { awaitStore, getReachableServer, updateCacheStore } from "../../helpers/utils";
|
|
4
|
+
import { RETRIEVAL } from "../../helpers/values";
|
|
5
5
|
import { CacheStore, Scoped } from "../../helpers/variables";
|
|
6
6
|
import { awaitRefreshToken } from "../auth/accessor";
|
|
7
|
+
import { simplifyCaughtError } from "simplify-error";
|
|
8
|
+
import { guardObject, Validator } from "guard-object";
|
|
9
|
+
import cloneDeep from "lodash.clonedeep";
|
|
10
|
+
import { serialize } from "entity-serializer";
|
|
7
11
|
|
|
8
12
|
const buildFetchData = (data) => {
|
|
9
|
-
const { ok, type, status, statusText, redirected, url, headers,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
arrayBuffer: async () => Buffer.from(base64, 'base64'),
|
|
14
|
-
json: async () => JSON.parse(await h.text()),
|
|
15
|
-
text: async () => {
|
|
16
|
-
const txt = Buffer.from(base64, 'base64').toString('utf8');
|
|
17
|
-
|
|
18
|
-
if (uglified) {
|
|
19
|
-
const json = deserializeE2E(txt, serverKey, encKey);
|
|
20
|
-
return `${json}`;
|
|
21
|
-
} else return txt;
|
|
22
|
-
},
|
|
23
|
-
clone: () => ({ ...h }),
|
|
24
|
-
type,
|
|
13
|
+
const { ok, type, status, statusText, redirected, url, headers, size, base64 } = data;
|
|
14
|
+
|
|
15
|
+
const response = new Response(Buffer.from(base64, 'base64'), {
|
|
16
|
+
headers: new Headers(headers),
|
|
25
17
|
status,
|
|
26
18
|
statusText,
|
|
27
|
-
redirected,
|
|
28
19
|
url,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
return h;
|
|
34
|
-
}
|
|
20
|
+
size
|
|
21
|
+
});
|
|
35
22
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
shouldCache = (retrieval === RETRIEVAL.DEFAULT ? !disableCache : true) &&
|
|
44
|
-
retrieval !== RETRIEVAL.NO_CACHE_NO_AWAIT,
|
|
45
|
-
reqId = objToUniqueString({
|
|
46
|
-
...init,
|
|
47
|
-
jij: { disableAuth: !!disableAuth, url: input, projectUrl, retrieval }
|
|
23
|
+
Object.entries({ ok, type, url, redirected, size })
|
|
24
|
+
.forEach(([k, v]) => {
|
|
25
|
+
if (response[k] !== v)
|
|
26
|
+
Object.defineProperty(response, k, {
|
|
27
|
+
value: v,
|
|
28
|
+
writable: false
|
|
29
|
+
});
|
|
48
30
|
});
|
|
49
31
|
|
|
50
|
-
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const mfetch = async (input = '', init, config) => {
|
|
36
|
+
const { projectUrl, serverE2E_PublicKey, method, maxRetries = 7, disableCache, accessKey, uglify, extraHeaders } = config;
|
|
37
|
+
const { headers, body } = init || {};
|
|
38
|
+
|
|
39
|
+
if (method !== undefined)
|
|
40
|
+
guardObject({
|
|
41
|
+
enableMinimizer: t => t === undefined || Validator.BOOLEAN(t),
|
|
42
|
+
rawApproach: t => t === undefined || Validator.BOOLEAN(t),
|
|
43
|
+
disableAuth: t => t === undefined || Validator.BOOLEAN(t),
|
|
44
|
+
retrieval: t => t === undefined || Object.values(RETRIEVAL).includes(t)
|
|
45
|
+
}).validate(method);
|
|
46
|
+
|
|
47
|
+
const { retrieval = RETRIEVAL.DEFAULT, enableMinimizer, rawApproach } = method || {};
|
|
48
|
+
const isBaseUrl = Validator.LINK(input);
|
|
49
|
+
const disableAuth = method?.disableAuth || isBaseUrl;
|
|
50
|
+
const shouldCache = (retrieval !== RETRIEVAL.DEFAULT || !disableCache) &&
|
|
51
|
+
retrieval !== RETRIEVAL.NO_CACHE_NO_AWAIT;
|
|
52
|
+
const uglified = !!(!isBaseUrl && uglify);
|
|
53
|
+
|
|
54
|
+
const rawHeader = Object.fromEntries(
|
|
55
|
+
[...new Headers(headers).entries()]
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if ('mtoken' in rawHeader)
|
|
51
59
|
throw '"mtoken" in header is a reserved prop';
|
|
52
60
|
|
|
53
|
-
if ('uglified' in
|
|
61
|
+
if ('uglified' in rawHeader)
|
|
54
62
|
throw '"uglified" in header is a reserved prop';
|
|
55
63
|
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
64
|
+
// if (isBaseUrl && !rawApproach)
|
|
65
|
+
// throw `please set { rawApproach: true } if you're trying to access different endpoint at "${input}"`;
|
|
66
|
+
|
|
67
|
+
if (body !== undefined) {
|
|
68
|
+
if (
|
|
69
|
+
typeof body !== 'string' &&
|
|
70
|
+
!Buffer.isBuffer(body) &&
|
|
71
|
+
!Validator.JSON(body)
|
|
72
|
+
) throw `"body" must be any of string, buffer, object`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const reqId = await niceHash(
|
|
76
|
+
serialize([
|
|
77
|
+
rawHeader,
|
|
78
|
+
body,
|
|
79
|
+
!!disableAuth,
|
|
80
|
+
input
|
|
81
|
+
]).toString('base64')
|
|
82
|
+
);
|
|
61
83
|
|
|
62
84
|
let retries = 0, hasFinalize;
|
|
63
85
|
|
|
@@ -72,7 +94,7 @@ export const mfetch = async (input = '', init = {}, config) => {
|
|
|
72
94
|
|
|
73
95
|
if (enableMinimizer) {
|
|
74
96
|
(Scoped.PendingFetchCollective.pendingResolution[reqId] || []).forEach(e => {
|
|
75
|
-
e(
|
|
97
|
+
e(a, b);
|
|
76
98
|
});
|
|
77
99
|
if (Scoped.PendingFetchCollective.pendingResolution[reqId])
|
|
78
100
|
delete Scoped.PendingFetchCollective.pendingResolution[reqId];
|
|
@@ -83,16 +105,15 @@ export const mfetch = async (input = '', init = {}, config) => {
|
|
|
83
105
|
};
|
|
84
106
|
|
|
85
107
|
await awaitStore();
|
|
86
|
-
const reqData = CacheStore.FetchedStore[reqId]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
const reqData = CacheStore.FetchedStore[projectUrl]?.[reqId];
|
|
109
|
+
const resolveCache = () => {
|
|
110
|
+
finalize({
|
|
111
|
+
...buildFetchData(reqData),
|
|
112
|
+
fromCache: true
|
|
113
|
+
});
|
|
114
|
+
};
|
|
93
115
|
|
|
94
116
|
try {
|
|
95
|
-
|
|
96
117
|
if (retryProcess === 1) {
|
|
97
118
|
if (enableMinimizer) {
|
|
98
119
|
if (Scoped.PendingFetchCollective.pendingProcess[reqId]) {
|
|
@@ -100,8 +121,8 @@ export const mfetch = async (input = '', init = {}, config) => {
|
|
|
100
121
|
Scoped.PendingFetchCollective.pendingResolution[reqId] = [];
|
|
101
122
|
|
|
102
123
|
Scoped.PendingFetchCollective.pendingResolution[reqId].push((a, b) => {
|
|
103
|
-
if (a) resolve(a.result);
|
|
104
|
-
else reject(b);
|
|
124
|
+
if (a) resolve(cloneDeep(a.result));
|
|
125
|
+
else reject(cloneDeep(b));
|
|
105
126
|
});
|
|
106
127
|
return;
|
|
107
128
|
}
|
|
@@ -117,53 +138,56 @@ export const mfetch = async (input = '', init = {}, config) => {
|
|
|
117
138
|
if (!disableAuth && await getReachableServer(projectUrl))
|
|
118
139
|
await awaitRefreshToken(projectUrl);
|
|
119
140
|
|
|
120
|
-
const mtoken = Scoped.AuthJWTToken[projectUrl]
|
|
121
|
-
|
|
122
|
-
initType = extractHeaderItem('content-type', init?.headers);
|
|
141
|
+
const mtoken = Scoped.AuthJWTToken[projectUrl];
|
|
142
|
+
const initType = rawHeader['content-type'];
|
|
123
143
|
|
|
124
|
-
const [reqBuilder, [privateKey]] =
|
|
144
|
+
const [reqBuilder, [privateKey]] = uglified ? await serializeE2E(body, mtoken, serverE2E_PublicKey) : [null, []];
|
|
125
145
|
|
|
126
|
-
const f = await fetch(isBaseUrl ? input : `${
|
|
146
|
+
const f = await fetch(isBaseUrl ? input : `${projectUrl}/${normalizeRoute(input)}`, {
|
|
127
147
|
...isBaseUrl ? {} : { method: 'POST' },
|
|
128
148
|
...init,
|
|
129
149
|
...uglified ? { body: reqBuilder } : {},
|
|
130
150
|
cache: 'no-cache',
|
|
131
151
|
headers: {
|
|
132
|
-
...
|
|
133
|
-
...
|
|
152
|
+
...extraHeaders,
|
|
153
|
+
...isBaseUrl ? {} : { 'content-type': 'application/json' },
|
|
154
|
+
...rawHeader,
|
|
134
155
|
...uglified ? {
|
|
135
156
|
uglified,
|
|
136
|
-
'
|
|
157
|
+
'content-type': 'request/buffer',
|
|
137
158
|
...initType ? { 'init-content-type': initType } : {}
|
|
138
159
|
} : {},
|
|
139
|
-
...(
|
|
160
|
+
...(disableAuth || !mtoken || uglified || isBaseUrl) ? {} : { mtoken },
|
|
140
161
|
...isBaseUrl ? {} : { authorization: `Bearer ${accessKey}` }
|
|
141
162
|
}
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
|
|
163
|
+
});
|
|
164
|
+
const { ok, type, status, statusText, redirected, url, headers, size } = f;
|
|
165
|
+
const simple = headers.get('simple_error');
|
|
145
166
|
|
|
146
167
|
if (!isBaseUrl && simple) throw { simpleError: JSON.parse(simple) };
|
|
147
168
|
|
|
148
|
-
const base64 =
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
headers
|
|
163
|
-
|
|
169
|
+
const base64 = uglified ?
|
|
170
|
+
Buffer.from(await deserializeE2E(await f.arrayBuffer(), serverE2E_PublicKey, privateKey)).toString('base64') :
|
|
171
|
+
Buffer.from(await f.arrayBuffer()).toString('base64');
|
|
172
|
+
|
|
173
|
+
const resObj = {
|
|
174
|
+
base64,
|
|
175
|
+
type,
|
|
176
|
+
status,
|
|
177
|
+
statusText,
|
|
178
|
+
redirected,
|
|
179
|
+
url,
|
|
180
|
+
ok,
|
|
181
|
+
size,
|
|
182
|
+
headers: Object.fromEntries(
|
|
183
|
+
[...headers.entries()]
|
|
184
|
+
)
|
|
185
|
+
};
|
|
164
186
|
|
|
165
187
|
if (shouldCache) {
|
|
166
|
-
CacheStore.FetchedStore[
|
|
188
|
+
if (!CacheStore.FetchedStore[projectUrl])
|
|
189
|
+
CacheStore.FetchedStore[projectUrl] = {};
|
|
190
|
+
CacheStore.FetchedStore[projectUrl][reqId] = cloneDeep(resObj);
|
|
167
191
|
updateCacheStore();
|
|
168
192
|
}
|
|
169
193
|
|
|
@@ -207,24 +231,5 @@ export const mfetch = async (input = '', init = {}, config) => {
|
|
|
207
231
|
}
|
|
208
232
|
});
|
|
209
233
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const extractHeaderItem = (t = '', header) => {
|
|
215
|
-
let k;
|
|
216
|
-
Object.entries(header || {}).forEach(([key, value]) => {
|
|
217
|
-
if (key.toLowerCase() === t.toLowerCase()) k = value;
|
|
218
|
-
});
|
|
219
|
-
return k;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const headerObj = (header) => {
|
|
223
|
-
const h = {};
|
|
224
|
-
|
|
225
|
-
header.forEach((v, k) => {
|
|
226
|
-
h[k] = v;
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
return h;
|
|
230
|
-
}
|
|
234
|
+
return await callFetch();
|
|
235
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import EngineApi from "../../helpers/
|
|
1
|
+
import EngineApi from "../../helpers/engine_api";
|
|
2
2
|
import { encodeBinary, prefixStoragePath } from "../../helpers/peripherals";
|
|
3
3
|
import { Scoped } from "../../helpers/variables";
|
|
4
4
|
import { DeviceEventEmitter, NativeEventEmitter, NativeModules, Platform } from 'react-native';
|
|
5
|
-
import { awaitReachableServer, buildFetchInterface
|
|
5
|
+
import { awaitReachableServer, buildFetchInterface } from "../../helpers/utils";
|
|
6
6
|
import { awaitRefreshToken } from "../auth/accessor";
|
|
7
|
+
import { simplifyError } from "simplify-error";
|
|
7
8
|
|
|
8
9
|
const LINKING_ERROR =
|
|
9
10
|
`The package 'react-native-mosquito-transport' doesn't seem to be linked. Make sure: \n\n` +
|
|
@@ -17,22 +18,23 @@ const RNMTModule = NativeModules.Mosquitodb || (
|
|
|
17
18
|
throw new Error(LINKING_ERROR);
|
|
18
19
|
},
|
|
19
20
|
})
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
);
|
|
22
|
+
const emitter = Platform.OS === 'android' ?
|
|
23
|
+
DeviceEventEmitter : new NativeEventEmitter(RNMTModule);
|
|
23
24
|
|
|
24
25
|
export class MTStorage {
|
|
25
26
|
constructor(config) {
|
|
26
27
|
this.builder = { ...config };
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
downloadFile(link = '', onComplete, destination, onProgress) {
|
|
30
|
+
downloadFile(link = '', onComplete, destination, onProgress, options) {
|
|
31
|
+
const { awaitServer } = options || {};
|
|
30
32
|
let hasFinished, isPaused, hasCancelled;
|
|
31
33
|
|
|
32
|
-
const { projectUrl, accessKey,
|
|
34
|
+
const { projectUrl, accessKey, extraHeaders } = this.builder;
|
|
33
35
|
|
|
34
|
-
if (destination && (
|
|
35
|
-
onComplete?.({ error: 'destination_invalid', message: 'destination
|
|
36
|
+
if (destination && (typeof destination !== 'string' || !destination.trim())) {
|
|
37
|
+
onComplete?.({ error: 'destination_invalid', message: 'destination must be a non-empty string' });
|
|
36
38
|
return () => { };
|
|
37
39
|
}
|
|
38
40
|
if (destination) destination = prefixStoragePath(destination?.trim());
|
|
@@ -46,57 +48,58 @@ export class MTStorage {
|
|
|
46
48
|
}
|
|
47
49
|
link = link.trim();
|
|
48
50
|
|
|
51
|
+
const processID = `${++Scoped.StorageProcessID}`;
|
|
49
52
|
const init = async () => {
|
|
50
|
-
if (
|
|
53
|
+
if (awaitServer) await awaitReachableServer(projectUrl);
|
|
51
54
|
await awaitRefreshToken(projectUrl);
|
|
52
55
|
|
|
53
56
|
if (hasCancelled) return;
|
|
54
57
|
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}),
|
|
74
|
-
resultListener = emitter.addListener('mt-download-status', ({ processID: ref, error, errorDes, result }) => {
|
|
75
|
-
if (processID !== ref) return;
|
|
76
|
-
if (result)
|
|
77
|
-
try {
|
|
78
|
-
result = JSON.parse(result);
|
|
79
|
-
} catch (e) { }
|
|
80
|
-
|
|
81
|
-
const path = result?.file || undefined;
|
|
82
|
-
|
|
83
|
-
if (!hasFinished && !hasCancelled)
|
|
84
|
-
onComplete?.(path ? undefined : (result?.simpleError || { error, errorDes }), path);
|
|
85
|
-
resultListener.remove();
|
|
86
|
-
progressListener.remove();
|
|
87
|
-
hasFinished = true;
|
|
58
|
+
const progressListener = emitter.addListener('mt-download-progress', ({ processID: ref, receivedBtyes, expectedBytes }) => {
|
|
59
|
+
if (processID !== ref || hasFinished || hasCancelled) return;
|
|
60
|
+
onProgress?.({
|
|
61
|
+
receivedBtyes,
|
|
62
|
+
expectedBytes,
|
|
63
|
+
isPaused: !!isPaused,
|
|
64
|
+
pause: () => {
|
|
65
|
+
if (hasFinished || isPaused || hasCancelled) return;
|
|
66
|
+
RNMTModule.pauseDownload(processID);
|
|
67
|
+
isPaused = true;
|
|
68
|
+
},
|
|
69
|
+
resume: () => {
|
|
70
|
+
if (hasFinished || !isPaused || hasCancelled) return;
|
|
71
|
+
RNMTModule.resumeDownload(processID);
|
|
72
|
+
isPaused = false;
|
|
73
|
+
}
|
|
88
74
|
});
|
|
75
|
+
});
|
|
76
|
+
const resultListener = emitter.addListener('mt-download-status', ({ processID: ref, error, errorDes, result }) => {
|
|
77
|
+
if (processID !== ref) return;
|
|
78
|
+
if (result)
|
|
79
|
+
try {
|
|
80
|
+
result = JSON.parse(result);
|
|
81
|
+
} catch (e) { }
|
|
82
|
+
|
|
83
|
+
const path = result?.file || undefined;
|
|
84
|
+
|
|
85
|
+
if (!hasFinished && !hasCancelled)
|
|
86
|
+
onComplete?.(path ? undefined : (result?.simpleError || { error, message: errorDes }), path);
|
|
87
|
+
resultListener.remove();
|
|
88
|
+
progressListener.remove();
|
|
89
|
+
hasFinished = true;
|
|
90
|
+
});
|
|
89
91
|
|
|
90
92
|
RNMTModule.downloadFile({
|
|
91
93
|
url: link,
|
|
92
94
|
authToken: Scoped.AuthJWTToken[projectUrl],
|
|
93
|
-
...
|
|
95
|
+
...destination ? {
|
|
94
96
|
destination: destination.substring('file://'.length),
|
|
95
|
-
destinationDir: `${destination.substring('file://'.length)}`.split('/').
|
|
96
|
-
} : {}
|
|
97
|
+
destinationDir: `${destination.substring('file://'.length)}`.split('/').slice(0, -1).join('/')
|
|
98
|
+
} : {},
|
|
97
99
|
processID,
|
|
98
100
|
urlName: link.split('/').pop(),
|
|
99
|
-
authorization: `Bearer ${encodeBinary(accessKey)}
|
|
101
|
+
authorization: `Bearer ${encodeBinary(accessKey)}`,
|
|
102
|
+
extraHeaders: extraHeaders || {},
|
|
100
103
|
});
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -112,60 +115,64 @@ export class MTStorage {
|
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
|
|
115
|
-
uploadFile(file = '', destination = '', onComplete, onProgress) {
|
|
118
|
+
uploadFile(file = '', destination = '', onComplete, onProgress, options) {
|
|
119
|
+
const { createHash, awaitServer } = options || {};
|
|
116
120
|
let hasFinished, hasCancelled;
|
|
117
121
|
|
|
118
|
-
if (
|
|
122
|
+
if (typeof file !== 'string' || !file.trim()) {
|
|
119
123
|
onComplete?.({ error: 'file_path_invalid', message: 'file must be a non-empty string in uploadFile()' });
|
|
120
124
|
return () => { };
|
|
121
125
|
}
|
|
122
|
-
destination = destination?.trim();
|
|
123
|
-
|
|
124
|
-
const destErr = validateDestination(destination),
|
|
125
|
-
isAsset = (file.startsWith('ph://') || file.startsWith('content://'));
|
|
126
|
+
destination = destination?.trim?.();
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
onComplete?.({ error: 'destination_invalid', message:
|
|
128
|
+
try {
|
|
129
|
+
validateDestination(destination);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
onComplete?.({ error: 'destination_invalid', message: error });
|
|
131
132
|
return () => { };
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
const
|
|
135
|
-
|
|
135
|
+
const isAsset = (file.startsWith('ph://') || file.startsWith('content://'));
|
|
136
|
+
|
|
137
|
+
file = isAsset ? file.trim() : prefixStoragePath(file.trim());
|
|
138
|
+
|
|
139
|
+
const { projectUrl, accessKey, uglify, extraHeaders } = this.builder;
|
|
140
|
+
const processID = `${++Scoped.StorageProcessID}`;
|
|
136
141
|
|
|
137
142
|
const init = async () => {
|
|
138
|
-
if (
|
|
143
|
+
if (awaitServer) await awaitReachableServer(projectUrl);
|
|
139
144
|
await awaitRefreshToken(projectUrl);
|
|
140
145
|
|
|
141
146
|
if (hasCancelled) return;
|
|
142
147
|
const progressListener = emitter.addListener('mt-uploading-progress', ({ processID: ref, sentBtyes, totalBytes }) => {
|
|
143
148
|
if (processID !== ref || hasFinished || hasCancelled) return;
|
|
144
149
|
onProgress?.({ sentBtyes, totalBytes });
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
150
|
+
});
|
|
151
|
+
const resultListener = emitter.addListener('mt-uploading-status', ({ processID: ref, error, errorDes, result }) => {
|
|
152
|
+
if (processID !== ref || hasFinished) return;
|
|
153
|
+
if (result)
|
|
154
|
+
try {
|
|
155
|
+
result = JSON.parse(result);
|
|
156
|
+
} catch (e) { }
|
|
157
|
+
|
|
158
|
+
const downloadUrl = result?.downloadUrl || undefined;
|
|
159
|
+
|
|
160
|
+
if (!hasFinished && !hasCancelled)
|
|
161
|
+
onComplete?.(downloadUrl ? undefined : (result?.simpleError || { error, message: errorDes }), downloadUrl);
|
|
162
|
+
resultListener.remove();
|
|
163
|
+
progressListener.remove();
|
|
164
|
+
hasFinished = true;
|
|
165
|
+
});
|
|
161
166
|
|
|
162
167
|
RNMTModule.uploadFile({
|
|
163
|
-
url: EngineApi._uploadFile(projectUrl),
|
|
168
|
+
url: EngineApi._uploadFile(projectUrl, uglify),
|
|
164
169
|
file: isAsset ? file : file.substring('file://'.length),
|
|
165
170
|
authToken: Scoped.AuthJWTToken[projectUrl],
|
|
171
|
+
createHash: createHash ? 'yes' : 'no',
|
|
166
172
|
destination,
|
|
167
173
|
processID,
|
|
168
|
-
authorization: `Bearer ${encodeBinary(accessKey)}
|
|
174
|
+
authorization: `Bearer ${encodeBinary(accessKey)}`,
|
|
175
|
+
extraHeaders: extraHeaders || {}
|
|
169
176
|
});
|
|
170
177
|
}
|
|
171
178
|
|
|
@@ -186,12 +193,12 @@ export class MTStorage {
|
|
|
186
193
|
}
|
|
187
194
|
|
|
188
195
|
const deleteContent = async (builder, path, isFolder) => {
|
|
189
|
-
const { projectUrl, accessKey } = builder;
|
|
196
|
+
const { projectUrl, accessKey, uglify } = builder;
|
|
190
197
|
|
|
191
198
|
try {
|
|
192
199
|
const r = await (await fetch(
|
|
193
|
-
EngineApi[isFolder ? '_deleteFolder' : '_deleteFile'](projectUrl),
|
|
194
|
-
buildFetchInterface({ path }, accessKey, Scoped.AuthJWTToken[projectUrl], 'DELETE')
|
|
200
|
+
EngineApi[isFolder ? '_deleteFolder' : '_deleteFile'](projectUrl, uglify),
|
|
201
|
+
await buildFetchInterface({ path }, accessKey, Scoped.AuthJWTToken[projectUrl], 'DELETE')
|
|
195
202
|
)).json();
|
|
196
203
|
if (r.simpleError) throw r;
|
|
197
204
|
if (r.status !== 'success') throw 'operation not successful';
|
|
@@ -202,16 +209,18 @@ const deleteContent = async (builder, path, isFolder) => {
|
|
|
202
209
|
}
|
|
203
210
|
|
|
204
211
|
const validateDestination = (t = '') => {
|
|
205
|
-
t
|
|
212
|
+
if (typeof t !== 'string' || !t.trim()) throw 'path must be a non-empty string';
|
|
213
|
+
if (t.startsWith(' ') || t.endsWith(' ')) throw 'path must be trimmed';
|
|
214
|
+
if (t.startsWith('./') || t.startsWith('../')) throw 'path must be absolute';
|
|
215
|
+
if (t.endsWith('/')) throw 'path must not end with "/"';
|
|
216
|
+
if ('?'.split('').some(v => t.includes(v)))
|
|
217
|
+
throw `path must not contain ?`;
|
|
206
218
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let l = '', r;
|
|
219
|
+
t = t.trim();
|
|
220
|
+
let l = '';
|
|
210
221
|
|
|
211
222
|
t.split('').forEach(e => {
|
|
212
|
-
if (e === '/' && l === '/')
|
|
223
|
+
if (e === '/' && l === '/') throw 'invalid destination path, "/" cannot be duplicated side by side';
|
|
213
224
|
l = e;
|
|
214
225
|
});
|
|
215
|
-
|
|
216
|
-
return r;
|
|
217
226
|
};
|
package/src/helpers/EngineApi.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { encodeBinary } from './peripherals';
|
|
2
|
-
|
|
3
|
-
const apis = {
|
|
4
|
-
_readDocument: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._readDocument(baseApi)) : '_readDocument'}`,
|
|
5
|
-
_writeDocument: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._writeDocument(baseApi)) : '_writeDocument'}`,
|
|
6
|
-
_deleteCollection: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._deleteCollection(baseApi)) : '_deleteCollection'}`,
|
|
7
|
-
_queryCollection: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._queryCollection(baseApi)) : '_queryCollection'}`,
|
|
8
|
-
_writeMapDocument: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._writeMapDocument(baseApi)) : '_writeMapDocument'}`,
|
|
9
|
-
_customSignin: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._customSignin(baseApi)) : '_customSignin'}`,
|
|
10
|
-
_customSignup: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._customSignup(baseApi)) : '_customSignup'}`,
|
|
11
|
-
_googleSignin: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._googleSignin(baseApi)) : '_googleSignin'}`,
|
|
12
|
-
_appleSignin: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._appleSignin(baseApi)) : '_appleSignin'}`,
|
|
13
|
-
_facebookSignin: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._facebookSignin(baseApi)) : '_facebookSignin'}`,
|
|
14
|
-
_twitterSignin: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._twitterSignin(baseApi)) : '_twitterSignin'}`,
|
|
15
|
-
_githubSignin: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._githubSignin(baseApi)) : '_githubSignin'}`,
|
|
16
|
-
_signOut: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._signOut(baseApi)) : '_signOut'}`,
|
|
17
|
-
_refreshAuthToken: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._refreshAuthToken(baseApi)) : '_refreshAuthToken'}`,
|
|
18
|
-
_downloadFile: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._downloadFile(baseApi)) : '_downloadFile'}`,
|
|
19
|
-
_uploadFile: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._uploadFile(baseApi)) : '_uploadFile'}`,
|
|
20
|
-
_deleteFile: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._deleteFile(baseApi)) : '_deleteFile'}`,
|
|
21
|
-
_deleteFolder: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._deleteFolder(baseApi)) : '_deleteFolder'}`,
|
|
22
|
-
staticStorage: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis.staticStorage(baseApi)) : 'storage'}`,
|
|
23
|
-
_documentCount: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._documentCount(baseApi)) : '_documentCount'}`,
|
|
24
|
-
_areYouOk: (baseApi, ugly) => `${baseApi}/${ugly ? encodeBinary(apis._areYouOk(baseApi)) : '_areYouOk'}`,
|
|
25
|
-
// static path
|
|
26
|
-
_listenCollection: (ugly) => `${ugly ? encodeBinary(apis._listenCollection()) : '_listenCollection'}`,
|
|
27
|
-
_listenDocument: (ugly) => `${ugly ? encodeBinary(apis._listenDocument()) : '_listenDocument'}`,
|
|
28
|
-
_startDisconnectWriteTask: (ugly) => `${ugly ? encodeBinary(apis._startDisconnectWriteTask()) : '_startDisconnectWriteTask'}`,
|
|
29
|
-
_cancelDisconnectWriteTask: (ugly) => `${ugly ? encodeBinary(apis._cancelDisconnectWriteTask()) : '_cancelDisconnectWriteTask'}`,
|
|
30
|
-
_listenUserVerification: (ugly) => `${ugly ? encodeBinary(apis._listenUserVerification()) : '_listenUserVerification'}`
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default { ...apis };
|