react-native-mosquito-transport 0.0.21 → 0.0.22
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 -7
- package/TODO +18 -8
- package/ios/Mosquitodb.swift +0 -4
- package/package.json +7 -7
- package/src/helpers/engine_api.js +2 -7
- package/src/helpers/peripherals.js +7 -31
- package/src/helpers/purger.js +264 -0
- package/src/helpers/sqlite_manager.js +138 -0
- package/src/helpers/utils.js +63 -43
- package/src/helpers/values.js +5 -20
- package/src/helpers/variables.js +36 -10
- package/src/index.d.ts +97 -56
- package/src/index.js +42 -38
- package/src/products/auth/accessor.js +10 -11
- package/src/products/auth/index.js +13 -28
- package/src/products/database/accessor.js +429 -165
- package/src/products/database/counter.js +12 -10
- package/src/products/database/index.js +177 -162
- package/src/products/database/types.js +1 -0
- package/src/products/database/validator.js +1 -1
- package/src/products/http_callable/accessor.js +72 -0
- package/src/products/http_callable/counter.js +11 -0
- package/src/products/http_callable/index.js +57 -66
- package/src/products/storage/index.js +20 -13
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import getLodash from "lodash/get";
|
|
2
|
+
import setLodash from 'lodash/set';
|
|
1
3
|
import { CacheStore } from "../../helpers/variables";
|
|
4
|
+
import { serializeToBase64 } from "./bson";
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
export const incrementDatabaseSize = (projectUrl, doc) => {
|
|
6
|
+
export const incrementDatabaseSize = (builder, path, size) => incrementDatabaseSizeCore(CacheStore.DatabaseStats, builder, path, size);
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
export const incrementDatabaseSizeCore = (baseObj, builder, path, size = 0) => {
|
|
9
|
+
const { projectUrl, dbUrl, dbName } = builder;
|
|
10
|
+
baseObj._db_size += size;
|
|
7
11
|
|
|
8
|
-
|
|
12
|
+
const node = [projectUrl, dbUrl, dbName, path];
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
const b4 = getLodash(baseObj.database, node, 0);
|
|
15
|
+
setLodash(baseObj.database, node, b4 + size);
|
|
16
|
+
}
|
|
11
17
|
|
|
12
|
-
const
|
|
13
|
-
// if (!CacheStore.DatabaseStats[projectUrl])
|
|
14
|
-
// CacheStore.DatabaseStats[projectUrl] = 0;
|
|
15
|
-
// CacheStore.DatabaseStats[projectUrl] += size;
|
|
16
|
-
};
|
|
18
|
+
export const docSize = doc => doc ? serializeToBase64({ _: doc }).length : 0;
|
|
@@ -4,15 +4,14 @@ import { DatabaseRecordsListener } from "../../helpers/listeners";
|
|
|
4
4
|
import { deserializeE2E, listenReachableServer, niceTry, serializeE2E } from "../../helpers/peripherals";
|
|
5
5
|
import { awaitStore, buildFetchInterface, buildFetchResult, getReachableServer } from "../../helpers/utils";
|
|
6
6
|
import { CacheStore, Scoped } from "../../helpers/variables";
|
|
7
|
-
import { addPendingWrites, generateRecordID, getRecord, insertRecord, listenQueryEntry, removePendingWrite, validateWriteValue } from "./accessor";
|
|
7
|
+
import { addPendingWrites, generateRecordID, getCountQuery, getRecord, insertCountQuery, insertRecord, listenQueryEntry, removePendingWrite, validateWriteValue } from "./accessor";
|
|
8
8
|
import { validateCollectionName, validateFilter, validateFindConfig, validateFindObject, validateListenFindConfig } from "./validator";
|
|
9
9
|
import { awaitRefreshToken, listenToken } from "../auth/accessor";
|
|
10
10
|
import { DELIVERY, RETRIEVAL } from "../../helpers/values";
|
|
11
|
-
import setLodash from 'lodash.set';
|
|
12
11
|
import { ObjectId } from "bson";
|
|
13
12
|
import { guardObject, Validator } from "guard-object";
|
|
14
13
|
import { simplifyCaughtError } from "simplify-error";
|
|
15
|
-
import cloneDeep from "lodash
|
|
14
|
+
import cloneDeep from "lodash/cloneDeep";
|
|
16
15
|
import { deserializeBSON, serializeToBase64 } from "./bson";
|
|
17
16
|
|
|
18
17
|
export class MTCollection {
|
|
@@ -67,19 +66,6 @@ export class MTCollection {
|
|
|
67
66
|
get: (config) => findObject({ ...this.builder, command: { findOne } }, config)
|
|
68
67
|
});
|
|
69
68
|
|
|
70
|
-
onDisconnect = () => ({
|
|
71
|
-
setOne: (value) => initOnDisconnectionTask({ ...this.builder }, value, 'setOne'),
|
|
72
|
-
setMany: (value) => initOnDisconnectionTask({ ...this.builder }, value, 'setMany'),
|
|
73
|
-
updateOne: (find = {}, value) => initOnDisconnectionTask({ ...this.builder, command: { find } }, value, 'updateOne'),
|
|
74
|
-
updateMany: (find = {}, value) => initOnDisconnectionTask({ ...this.builder, command: { find } }, value, 'updateMany'),
|
|
75
|
-
mergeOne: (find = {}, value) => initOnDisconnectionTask({ ...this.builder, command: { find } }, value, 'mergeOne'),
|
|
76
|
-
mergeMany: (find = {}, value) => initOnDisconnectionTask({ ...this.builder, command: { find } }, value, 'mergeMany'),
|
|
77
|
-
deleteOne: (find = {}) => initOnDisconnectionTask({ ...this.builder, command: { find } }, undefined, 'deleteOne'),
|
|
78
|
-
deleteMany: (find = {}) => initOnDisconnectionTask({ ...this.builder, command: { find } }, undefined, 'deleteMany'),
|
|
79
|
-
replaceOne: (find = {}, value) => initOnDisconnectionTask({ ...this.builder, command: { find } }, value, 'replaceOne'),
|
|
80
|
-
putOne: (find = {}, value) => initOnDisconnectionTask({ ...this.builder, command: { find } }, value, 'putOne')
|
|
81
|
-
});
|
|
82
|
-
|
|
83
69
|
setOne = (value, config) => commitData(this.builder, value, 'setOne', config);
|
|
84
70
|
|
|
85
71
|
setMany = (value, config) => commitData(this.builder, value, 'setMany', config);
|
|
@@ -115,6 +101,26 @@ export class MTCollection {
|
|
|
115
101
|
deleteMany = (find = {}, config) => commitData({ ...this.builder, find }, undefined, 'deleteMany', config);
|
|
116
102
|
};
|
|
117
103
|
|
|
104
|
+
export const onCollectionConnect = (builder) => ({
|
|
105
|
+
...collectionIO(data => ({
|
|
106
|
+
...initCollectionIO({ connectData: data, builder }),
|
|
107
|
+
onDisconnect: () => collectionIO(data2 =>
|
|
108
|
+
initCollectionIO({ connectData: data, disconnectData: data2, builder })
|
|
109
|
+
)
|
|
110
|
+
})),
|
|
111
|
+
onDisconnect: () => collectionIO(data =>
|
|
112
|
+
initCollectionIO({ disconnectData: data, builder })
|
|
113
|
+
)
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const collectionIO = (caller) => ({
|
|
117
|
+
batchWrite: (map, config) => caller({ value: map, config })
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const initCollectionIO = (data) => ({
|
|
121
|
+
start: () => initOnDisconnectionTask(data)
|
|
122
|
+
});
|
|
123
|
+
|
|
118
124
|
export const batchWrite = (builder, map, config) => commitData({ ...builder }, map, 'batchWrite', config);
|
|
119
125
|
|
|
120
126
|
const {
|
|
@@ -130,9 +136,9 @@ const {
|
|
|
130
136
|
} = EngineApi;
|
|
131
137
|
|
|
132
138
|
const listenDocument = (callback, onError, builder, config) => {
|
|
133
|
-
const { projectUrl, wsPrefix, serverE2E_PublicKey, baseUrl, dbUrl, dbName,
|
|
139
|
+
const { projectUrl, wsPrefix, serverE2E_PublicKey, baseUrl, dbUrl, dbName, path, disableCache, command, uglify, extraHeaders, castBSON } = builder;
|
|
134
140
|
const { find, findOne, sort, direction, limit } = command;
|
|
135
|
-
const { disableAuth } = config || {};
|
|
141
|
+
const { disableAuth, episode } = config || {};
|
|
136
142
|
const shouldCache = !disableCache;
|
|
137
143
|
const processId = `${++Scoped.AnyProcessIte}`;
|
|
138
144
|
let accessId;
|
|
@@ -145,7 +151,6 @@ const listenDocument = (callback, onError, builder, config) => {
|
|
|
145
151
|
hasRespond,
|
|
146
152
|
cacheListener,
|
|
147
153
|
socket,
|
|
148
|
-
wasDisconnected,
|
|
149
154
|
lastToken = Scoped.AuthJWTToken[projectUrl] || null,
|
|
150
155
|
lastInitRef = 0,
|
|
151
156
|
connectedListener,
|
|
@@ -159,7 +164,7 @@ const listenDocument = (callback, onError, builder, config) => {
|
|
|
159
164
|
};
|
|
160
165
|
|
|
161
166
|
if (shouldCache) {
|
|
162
|
-
accessId = generateRecordID(builder, config).then(hash => {
|
|
167
|
+
accessId = generateRecordID(builder, config, true).then(hash => {
|
|
163
168
|
if (hasCancelled) return hash;
|
|
164
169
|
cacheListener = listenQueryEntry(snapshot => {
|
|
165
170
|
if (!Scoped.IS_CONNECTED[projectUrl]) dispatchSnapshot(snapshot);
|
|
@@ -193,24 +198,25 @@ const listenDocument = (callback, onError, builder, config) => {
|
|
|
193
198
|
direction,
|
|
194
199
|
limit
|
|
195
200
|
}),
|
|
196
|
-
dbName,
|
|
197
|
-
dbUrl
|
|
201
|
+
...dbName ? { dbName } : undefined,
|
|
202
|
+
...dbUrl ? { dbUrl } : undefined
|
|
198
203
|
};
|
|
199
204
|
|
|
200
|
-
const [encPlate, [privateKey]] = uglify ? await serializeE2E({
|
|
205
|
+
const [encPlate, [privateKey]] = uglify ? await serializeE2E({ _body: authObj }, mtoken, serverE2E_PublicKey) : ['', []];
|
|
201
206
|
|
|
202
207
|
socket = io(`${wsPrefix}://${baseUrl}`, {
|
|
203
208
|
transports: ['websocket', 'polling', 'flashsocket'],
|
|
204
209
|
extraHeaders,
|
|
205
|
-
auth:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
+
auth: {
|
|
211
|
+
...uglify ? { e2e: encPlate.toString('base64') } : {
|
|
212
|
+
_body: authObj,
|
|
213
|
+
...mtoken ? { mtoken } : {}
|
|
214
|
+
},
|
|
215
|
+
_m_internal: true,
|
|
216
|
+
_m_route: (findOne ? _listenDocument : _listenCollection)(uglify)
|
|
210
217
|
}
|
|
211
218
|
});
|
|
212
219
|
|
|
213
|
-
socket.emit((findOne ? _listenDocument : _listenCollection)(uglify));
|
|
214
220
|
socket.on('mSnapshot', async ([err, snapshot]) => {
|
|
215
221
|
hasRespond = true;
|
|
216
222
|
if (err) {
|
|
@@ -219,20 +225,12 @@ const listenDocument = (callback, onError, builder, config) => {
|
|
|
219
225
|
} else console.error('unhandled listen for:', { path, find }, ' error:', err);
|
|
220
226
|
} else {
|
|
221
227
|
if (uglify) snapshot = await deserializeE2E(snapshot, serverE2E_PublicKey, privateKey);
|
|
222
|
-
snapshot = deserializeBSON(snapshot)._;
|
|
228
|
+
snapshot = hydrateForeignDoc(deserializeBSON(snapshot)._);
|
|
223
229
|
dispatchSnapshot(snapshot);
|
|
224
230
|
|
|
225
|
-
if (shouldCache) insertRecord(builder, config, await accessId, snapshot);
|
|
231
|
+
if (shouldCache) insertRecord(builder, config, await accessId, snapshot, episode);
|
|
226
232
|
}
|
|
227
233
|
});
|
|
228
|
-
|
|
229
|
-
socket.on('connect', () => {
|
|
230
|
-
if (wasDisconnected) socket.emit((findOne ? _listenDocument : _listenCollection)(uglify));
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
socket.on('disconnect', () => {
|
|
234
|
-
wasDisconnected = true;
|
|
235
|
-
});
|
|
236
234
|
};
|
|
237
235
|
|
|
238
236
|
init();
|
|
@@ -240,10 +238,10 @@ const listenDocument = (callback, onError, builder, config) => {
|
|
|
240
238
|
const tokenListener = listenToken(t => {
|
|
241
239
|
if ((t || null) !== lastToken) {
|
|
242
240
|
socket?.close?.();
|
|
243
|
-
|
|
241
|
+
socket = undefined;
|
|
244
242
|
init();
|
|
245
243
|
}
|
|
246
|
-
lastToken = t;
|
|
244
|
+
lastToken = t || null;
|
|
247
245
|
}, projectUrl);
|
|
248
246
|
|
|
249
247
|
return () => {
|
|
@@ -256,17 +254,30 @@ const listenDocument = (callback, onError, builder, config) => {
|
|
|
256
254
|
}
|
|
257
255
|
};
|
|
258
256
|
|
|
259
|
-
const initOnDisconnectionTask = (builder,
|
|
260
|
-
const { projectUrl, wsPrefix, baseUrl, serverE2E_PublicKey, dbUrl, dbName,
|
|
261
|
-
const { find } = command || {};
|
|
257
|
+
const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
|
|
258
|
+
const { projectUrl, wsPrefix, baseUrl, serverE2E_PublicKey, dbUrl, dbName, extraHeaders, uglify } = builder;
|
|
262
259
|
const disableAuth = false;
|
|
263
260
|
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
[connectData, disconnectData].forEach((e) => {
|
|
262
|
+
if (e) {
|
|
263
|
+
if (e.config !== undefined)
|
|
264
|
+
guardObject({
|
|
265
|
+
stepping: t => t === undefined || Validator.BOOLEAN(t)
|
|
266
|
+
}).validate(e.config);
|
|
267
|
+
|
|
268
|
+
cleanBatchWrite(e.value).forEach(e => {
|
|
269
|
+
const { scope, find, value, path } = e;
|
|
270
|
+
validateCollectionName(path);
|
|
271
|
+
validateWriteValue({ find, value, type: scope });
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
});
|
|
266
275
|
|
|
267
276
|
let hasCancelled,
|
|
277
|
+
/**
|
|
278
|
+
* @type {import('socket.io-client').Socket}
|
|
279
|
+
*/
|
|
268
280
|
socket,
|
|
269
|
-
wasDisconnected,
|
|
270
281
|
lastToken = Scoped.AuthJWTToken[projectUrl] || null,
|
|
271
282
|
lastInitRef = 0;
|
|
272
283
|
|
|
@@ -276,68 +287,64 @@ const initOnDisconnectionTask = (builder, value, type) => {
|
|
|
276
287
|
if (hasCancelled || processID !== lastInitRef) return;
|
|
277
288
|
|
|
278
289
|
const mtoken = disableAuth ? undefined : Scoped.AuthJWTToken[projectUrl];
|
|
290
|
+
const makeObj = (d) => ({
|
|
291
|
+
...d?.config,
|
|
292
|
+
value: serializeToBase64({ _: cleanBatchWrite(d.value) })
|
|
293
|
+
});
|
|
294
|
+
|
|
279
295
|
const authObj = {
|
|
280
|
-
commands:
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
dbName,
|
|
287
|
-
dbUrl
|
|
296
|
+
commands: {
|
|
297
|
+
...connectData ? { connectTask: makeObj(connectData) } : {},
|
|
298
|
+
...disconnectData ? { disconnectTask: makeObj(disconnectData) } : {}
|
|
299
|
+
},
|
|
300
|
+
...dbName ? { dbName } : undefined,
|
|
301
|
+
...dbUrl ? { dbUrl } : undefined
|
|
288
302
|
};
|
|
289
303
|
|
|
290
304
|
socket = io(`${wsPrefix}://${baseUrl}`, {
|
|
291
305
|
transports: ['websocket', 'polling', 'flashsocket'],
|
|
292
306
|
extraHeaders,
|
|
293
|
-
auth:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
_m_internal: true
|
|
307
|
+
auth: {
|
|
308
|
+
...uglify ? {
|
|
309
|
+
e2e: (await serializeE2E({ _body: authObj }, mtoken, serverE2E_PublicKey))[0].toString('base64')
|
|
310
|
+
} : {
|
|
311
|
+
...mtoken ? { mtoken } : {},
|
|
312
|
+
_body: authObj
|
|
313
|
+
},
|
|
314
|
+
_m_internal: true,
|
|
315
|
+
_m_route: _startDisconnectWriteTask(uglify)
|
|
301
316
|
}
|
|
302
317
|
});
|
|
303
|
-
socket.emit(_startDisconnectWriteTask(uglify));
|
|
304
|
-
|
|
305
|
-
socket.on('connect', () => {
|
|
306
|
-
if (wasDisconnected) socket.emit(_startDisconnectWriteTask(uglify));
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
socket.on('disconnect', () => {
|
|
310
|
-
wasDisconnected = true;
|
|
311
|
-
});
|
|
312
318
|
};
|
|
313
319
|
|
|
314
320
|
init();
|
|
315
321
|
|
|
316
|
-
const tokenListener = listenToken(async t => {
|
|
322
|
+
const tokenListener = disableAuth ? undefined : listenToken(async t => {
|
|
317
323
|
if ((t || null) !== lastToken) {
|
|
318
324
|
if (socket) {
|
|
319
|
-
await niceTry(() => socket.timeout(7000).emitWithAck(_cancelDisconnectWriteTask(uglify)));
|
|
320
325
|
socket.close();
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
init();
|
|
326
|
+
socket = undefined;
|
|
327
|
+
setTimeout(init, 500);
|
|
328
|
+
} else init();
|
|
324
329
|
}
|
|
325
330
|
lastToken = t;
|
|
326
331
|
}, projectUrl);
|
|
327
332
|
|
|
328
333
|
return () => {
|
|
329
334
|
if (hasCancelled) return;
|
|
330
|
-
tokenListener();
|
|
331
|
-
if (socket)
|
|
332
|
-
niceTry(() => socket.timeout(7000).emitWithAck(_cancelDisconnectWriteTask(uglify))).then(() => {
|
|
333
|
-
socket.close();
|
|
334
|
-
});
|
|
335
335
|
hasCancelled = true;
|
|
336
|
+
tokenListener?.();
|
|
337
|
+
if (socket) {
|
|
338
|
+
const thisSocket = socket;
|
|
339
|
+
return niceTry(() => thisSocket.timeout(5000).emitWithAck(_cancelDisconnectWriteTask(uglify))).finally(() => {
|
|
340
|
+
thisSocket.close();
|
|
341
|
+
});
|
|
342
|
+
}
|
|
336
343
|
};
|
|
337
344
|
};
|
|
338
345
|
|
|
339
346
|
const countCollection = async (builder, config) => {
|
|
340
|
-
const { projectUrl, serverE2E_PublicKey, dbUrl, dbName,
|
|
347
|
+
const { projectUrl, serverE2E_PublicKey, dbUrl, dbName, maxRetries = 1, uglify, extraHeaders, path, disableCache, command = {} } = builder;
|
|
341
348
|
const { find } = command;
|
|
342
349
|
const { disableAuth } = config || {};
|
|
343
350
|
const accessId = await generateRecordID({ ...builder, countDoc: true }, config);
|
|
@@ -368,10 +375,9 @@ const countCollection = async (builder, config) => {
|
|
|
368
375
|
const [reqBuilder, [privateKey]] = await buildFetchInterface({
|
|
369
376
|
body: {
|
|
370
377
|
commands: { path, find: serializeToBase64(find) },
|
|
371
|
-
dbName,
|
|
372
|
-
dbUrl
|
|
378
|
+
...dbName ? { dbName } : undefined,
|
|
379
|
+
...dbUrl ? { dbUrl } : undefined
|
|
373
380
|
},
|
|
374
|
-
accessKey,
|
|
375
381
|
...disableAuth ? {} : { authToken: Scoped.AuthJWTToken[projectUrl] },
|
|
376
382
|
serverE2E_PublicKey,
|
|
377
383
|
uglify,
|
|
@@ -382,12 +388,11 @@ const countCollection = async (builder, config) => {
|
|
|
382
388
|
|
|
383
389
|
const f = uglify ? await deserializeE2E(data, serverE2E_PublicKey, privateKey) : data;
|
|
384
390
|
|
|
385
|
-
if (!disableCache)
|
|
386
|
-
setLodash(CacheStore.DatabaseCountResult, [projectUrl, dbUrl, dbName, accessId], f.result);
|
|
387
|
-
|
|
388
391
|
finalize(f.result);
|
|
392
|
+
|
|
393
|
+
if (!disableCache) insertCountQuery(builder, accessId, f.result);
|
|
389
394
|
} catch (e) {
|
|
390
|
-
const b4Data =
|
|
395
|
+
const b4Data = await getCountQuery(builder, accessId).catch(() => null);
|
|
391
396
|
|
|
392
397
|
if (e?.simpleError) {
|
|
393
398
|
finalize(undefined, e.simpleError);
|
|
@@ -424,26 +429,40 @@ const stripUndefined = o => Object.fromEntries(
|
|
|
424
429
|
Object.entries(o).filter(v => v[1] !== undefined)
|
|
425
430
|
);
|
|
426
431
|
|
|
432
|
+
const hydrateForeignDoc = ({ data, doc_holder }) => {
|
|
433
|
+
const isList = Array.isArray(data);
|
|
434
|
+
const filled = (isList ? data : [data]).map(v => {
|
|
435
|
+
if (v?._foreign_doc) {
|
|
436
|
+
v._foreign_doc = Array.isArray(v._foreign_doc)
|
|
437
|
+
? v._foreign_doc.map(k => doc_holder[k])
|
|
438
|
+
: doc_holder[v._foreign_doc];
|
|
439
|
+
}
|
|
440
|
+
return v;
|
|
441
|
+
});
|
|
442
|
+
return isList ? filled : filled[0];
|
|
443
|
+
}
|
|
444
|
+
|
|
427
445
|
const transformBSON = (d, castBSON) => {
|
|
428
446
|
if (castBSON) return d && deserializeBSON(serializeToBase64({ _: d }), true)._;
|
|
429
447
|
return cloneDeep(d);
|
|
430
448
|
};
|
|
431
449
|
|
|
432
450
|
const findObject = async (builder, config) => {
|
|
433
|
-
const { projectUrl, serverE2E_PublicKey, dbUrl, dbName,
|
|
451
|
+
const { projectUrl, serverE2E_PublicKey, dbUrl, dbName, maxRetries = 1, path, disableCache = false, uglify, extraHeaders, command, castBSON } = builder;
|
|
452
|
+
const pureConfig = stripRequestConfig(config);
|
|
453
|
+
validateFindObject(command);
|
|
454
|
+
validateFindConfig(config);
|
|
455
|
+
validateCollectionName(path);
|
|
456
|
+
|
|
434
457
|
const { find, findOne, sort, direction, limit, random } = command;
|
|
435
458
|
const { retrieval = RETRIEVAL.DEFAULT, episode = 0, disableAuth, disableMinimizer } = config || {};
|
|
436
459
|
const enableMinimizer = !disableMinimizer;
|
|
437
|
-
const accessId = await generateRecordID(builder, config);
|
|
438
|
-
const processAccessId = `${accessId}${projectUrl}${dbUrl}${dbName}${retrieval}`;
|
|
439
|
-
const getRecordData = () => getRecord(builder,
|
|
460
|
+
const accessId = await generateRecordID(builder, config, true);
|
|
461
|
+
const processAccessId = `${accessId}_${limit}_${episode}_${projectUrl}_${dbUrl}_${dbName}_${retrieval}_${disableCache}`;
|
|
462
|
+
const getRecordData = () => getRecord(builder, accessId, episode);
|
|
440
463
|
const shouldCache = (retrieval !== RETRIEVAL.DEFAULT || !disableCache) &&
|
|
441
464
|
![RETRIEVAL.NO_CACHE_NO_AWAIT, RETRIEVAL.NO_CACHE_AWAIT].includes(retrieval);
|
|
442
465
|
|
|
443
|
-
const pureConfig = stripRequestConfig(config);
|
|
444
|
-
validateFindObject(command);
|
|
445
|
-
validateFindConfig(config);
|
|
446
|
-
validateCollectionName(path);
|
|
447
466
|
await awaitStore();
|
|
448
467
|
|
|
449
468
|
let retries = 0, hasFinalize;
|
|
@@ -453,10 +472,7 @@ const findObject = async (builder, config) => {
|
|
|
453
472
|
instantProcess = retryProcess === 1;
|
|
454
473
|
|
|
455
474
|
const finalize = (a, b) => {
|
|
456
|
-
const res = (instantProcess && a) ?
|
|
457
|
-
(a.liveResult || a.liveResult === null) ?
|
|
458
|
-
transformBSON(a.liveResult || undefined, castBSON) :
|
|
459
|
-
transformBSON(a.episode[episode], castBSON) : a;
|
|
475
|
+
const res = (instantProcess && a) ? transformBSON(a[0] || undefined, castBSON) : a;
|
|
460
476
|
|
|
461
477
|
if (a) {
|
|
462
478
|
resolve(instantProcess ? cloneDeep(res) : a);
|
|
@@ -465,35 +481,33 @@ const findObject = async (builder, config) => {
|
|
|
465
481
|
hasFinalize = true;
|
|
466
482
|
|
|
467
483
|
if (enableMinimizer) {
|
|
468
|
-
(Scoped.PendingDbReadCollective
|
|
484
|
+
const resolutionList = (Scoped.PendingDbReadCollective[processAccessId] || []).slice(0);
|
|
485
|
+
|
|
486
|
+
if (Scoped.PendingDbReadCollective[processAccessId])
|
|
487
|
+
delete Scoped.PendingDbReadCollective[processAccessId];
|
|
488
|
+
|
|
489
|
+
resolutionList.forEach(e => {
|
|
469
490
|
e(a ? { result: res } : undefined, b);
|
|
470
491
|
});
|
|
471
|
-
if (Scoped.PendingDbReadCollective.pendingResolution[processAccessId])
|
|
472
|
-
delete Scoped.PendingDbReadCollective.pendingResolution[processAccessId];
|
|
473
|
-
|
|
474
|
-
if (Scoped.PendingDbReadCollective.pendingProcess[processAccessId])
|
|
475
|
-
delete Scoped.PendingDbReadCollective.pendingProcess[processAccessId];
|
|
476
492
|
}
|
|
477
493
|
};
|
|
478
494
|
|
|
479
495
|
try {
|
|
480
496
|
if (instantProcess) {
|
|
481
497
|
if (enableMinimizer) {
|
|
482
|
-
if (Scoped.PendingDbReadCollective
|
|
483
|
-
|
|
484
|
-
Scoped.PendingDbReadCollective.pendingResolution[processAccessId] = [];
|
|
485
|
-
|
|
486
|
-
Scoped.PendingDbReadCollective.pendingResolution[processAccessId].push((a, b) => {
|
|
498
|
+
if (Scoped.PendingDbReadCollective[processAccessId]) {
|
|
499
|
+
Scoped.PendingDbReadCollective[processAccessId].push((a, b) => {
|
|
487
500
|
if (a) resolve(cloneDeep(a.result));
|
|
488
501
|
else reject(cloneDeep(b));
|
|
489
502
|
});
|
|
490
503
|
return;
|
|
491
504
|
}
|
|
492
|
-
Scoped.PendingDbReadCollective
|
|
505
|
+
Scoped.PendingDbReadCollective[processAccessId] = [];
|
|
493
506
|
}
|
|
494
507
|
|
|
495
|
-
|
|
496
|
-
|
|
508
|
+
const staleData = await getRecordData();
|
|
509
|
+
if (retrieval.startsWith('sticky') && staleData) {
|
|
510
|
+
finalize(staleData);
|
|
497
511
|
if (retrieval !== RETRIEVAL.STICKY_RELOAD) return;
|
|
498
512
|
}
|
|
499
513
|
}
|
|
@@ -512,10 +526,9 @@ const findObject = async (builder, config) => {
|
|
|
512
526
|
limit,
|
|
513
527
|
random
|
|
514
528
|
}),
|
|
515
|
-
dbName,
|
|
516
|
-
dbUrl
|
|
529
|
+
...dbName ? { dbName } : undefined,
|
|
530
|
+
...dbUrl ? { dbUrl } : undefined
|
|
517
531
|
},
|
|
518
|
-
accessKey,
|
|
519
532
|
authToken: disableAuth ? undefined : Scoped.AuthJWTToken[projectUrl],
|
|
520
533
|
serverE2E_PublicKey,
|
|
521
534
|
uglify,
|
|
@@ -524,14 +537,16 @@ const findObject = async (builder, config) => {
|
|
|
524
537
|
|
|
525
538
|
const data = await buildFetchResult(await fetch((findOne ? _readDocument : _queryCollection)(projectUrl, uglify), reqBuilder), uglify);
|
|
526
539
|
|
|
527
|
-
const result =
|
|
540
|
+
const result = hydrateForeignDoc(
|
|
541
|
+
deserializeBSON((uglify ? await deserializeE2E(data, serverE2E_PublicKey, privateKey) : data).result)._
|
|
542
|
+
);
|
|
528
543
|
|
|
529
|
-
if (shouldCache) insertRecord(builder, config, accessId, result);
|
|
530
|
-
finalize(
|
|
544
|
+
if (shouldCache) insertRecord(builder, config, accessId, result, episode);
|
|
545
|
+
finalize([result]);
|
|
531
546
|
} catch (e) {
|
|
532
547
|
let thisRecord;
|
|
533
|
-
const getThisRecord = async () => thisRecord ? thisRecord
|
|
534
|
-
(thisRecord =
|
|
548
|
+
const getThisRecord = async () => thisRecord ? thisRecord[0] :
|
|
549
|
+
(thisRecord = [await getRecordData()])[0];
|
|
535
550
|
|
|
536
551
|
if (e?.simpleError) {
|
|
537
552
|
finalize(undefined, e?.simpleError);
|
|
@@ -543,10 +558,14 @@ const findObject = async (builder, config) => {
|
|
|
543
558
|
finalize(undefined, simplifyCaughtError(e).simpleError);
|
|
544
559
|
} else if (
|
|
545
560
|
shouldCache &&
|
|
546
|
-
[
|
|
561
|
+
[
|
|
562
|
+
RETRIEVAL.DEFAULT,
|
|
563
|
+
RETRIEVAL.CACHE_NO_AWAIT,
|
|
564
|
+
RETRIEVAL.CACHE_AWAIT
|
|
565
|
+
].includes(retrieval) &&
|
|
547
566
|
await getThisRecord()
|
|
548
567
|
) {
|
|
549
|
-
finalize(
|
|
568
|
+
finalize(await getThisRecord());
|
|
550
569
|
} else if (retries > maxRetries) {
|
|
551
570
|
finalize(undefined, { error: 'retry_limit_exceeded', message: `retry exceed limit(${maxRetries})` });
|
|
552
571
|
} else {
|
|
@@ -563,7 +582,7 @@ const findObject = async (builder, config) => {
|
|
|
563
582
|
}
|
|
564
583
|
});
|
|
565
584
|
|
|
566
|
-
return await readValue();
|
|
585
|
+
return (await readValue());
|
|
567
586
|
};
|
|
568
587
|
|
|
569
588
|
const transformNullRecursively = obj => Object.fromEntries(
|
|
@@ -572,6 +591,17 @@ const transformNullRecursively = obj => Object.fromEntries(
|
|
|
572
591
|
)
|
|
573
592
|
);
|
|
574
593
|
|
|
594
|
+
const cleanBatchWrite = (value) => cloneDeep(value).map(v => {
|
|
595
|
+
if (Validator.OBJECT(v?.value)) {
|
|
596
|
+
v.value = transformNullRecursively(v.value);
|
|
597
|
+
} else if (Array.isArray(v?.value)) {
|
|
598
|
+
v.value = v.value.map(e =>
|
|
599
|
+
Validator.OBJECT(e) ? transformNullRecursively(e) : e
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
return v;
|
|
603
|
+
});
|
|
604
|
+
|
|
575
605
|
const commitData = async (builder, value, type, config) => {
|
|
576
606
|
// transform undefined
|
|
577
607
|
if (Validator.OBJECT(value)) {
|
|
@@ -579,28 +609,17 @@ const commitData = async (builder, value, type, config) => {
|
|
|
579
609
|
} else if (type === 'batchWrite' && Array.isArray(value)) {
|
|
580
610
|
value = deserializeBSON(
|
|
581
611
|
serializeToBase64({
|
|
582
|
-
_: value
|
|
583
|
-
if (Validator.OBJECT(v?.value)) {
|
|
584
|
-
v.value = transformNullRecursively(v.value);
|
|
585
|
-
} else if (Array.isArray(v?.value)) {
|
|
586
|
-
v.value = v.value.map(e =>
|
|
587
|
-
Validator.OBJECT(e) ? transformNullRecursively(e) : e
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
return v;
|
|
591
|
-
})
|
|
612
|
+
_: cleanBatchWrite(value)
|
|
592
613
|
})
|
|
593
614
|
)._;
|
|
594
615
|
}
|
|
595
616
|
|
|
596
|
-
const { projectUrl, serverE2E_PublicKey, dbUrl, dbName,
|
|
617
|
+
const { projectUrl, serverE2E_PublicKey, dbUrl, dbName, maxRetries = 1, path, find, disableCache, uglify, extraHeaders } = builder;
|
|
597
618
|
const { disableAuth, delivery = DELIVERY.DEFAULT, stepping } = config || {};
|
|
598
619
|
const writeId = `${Date.now() + ++Scoped.PendingIte}`;
|
|
599
620
|
const isBatchWrite = type === 'batchWrite';
|
|
600
621
|
const shouldCache = (delivery !== DELIVERY.DEFAULT || !disableCache) &&
|
|
601
|
-
|
|
602
|
-
delivery !== DELIVERY.NO_AWAIT_NO_CACHE &&
|
|
603
|
-
delivery !== DELIVERY.AWAIT_NO_CACHE;
|
|
622
|
+
![DELIVERY.NO_CACHE_AWAIT, DELIVERY.NO_CACHE_NO_AWAIT].includes();
|
|
604
623
|
|
|
605
624
|
await awaitStore();
|
|
606
625
|
if (shouldCache) {
|
|
@@ -648,10 +667,9 @@ const commitData = async (builder, value, type, config) => {
|
|
|
648
667
|
find: find && serializeToBase64(find)
|
|
649
668
|
}
|
|
650
669
|
}),
|
|
651
|
-
dbName,
|
|
652
|
-
dbUrl
|
|
670
|
+
...dbName ? { dbName } : undefined,
|
|
671
|
+
...dbUrl ? { dbUrl } : undefined
|
|
653
672
|
},
|
|
654
|
-
accessKey,
|
|
655
673
|
serverE2E_PublicKey,
|
|
656
674
|
authToken: disableAuth ? undefined : Scoped.AuthJWTToken[projectUrl],
|
|
657
675
|
uglify,
|
|
@@ -667,27 +685,16 @@ const commitData = async (builder, value, type, config) => {
|
|
|
667
685
|
if (e?.simpleError) {
|
|
668
686
|
console.error(`${type} error (${path}), ${e.simpleError?.message}`);
|
|
669
687
|
finalize(undefined, e?.simpleError, { removeCache: true, revertCache: true });
|
|
670
|
-
} else if (
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
DELIVERY.CACHE_NO_AWAIT,
|
|
674
|
-
DELIVERY.NO_AWAIT_NO_CACHE,
|
|
675
|
-
DELIVERY.NO_CACHE
|
|
676
|
-
].includes(delivery)
|
|
677
|
-
) {
|
|
678
|
-
finalize(
|
|
679
|
-
undefined,
|
|
680
|
-
simplifyCaughtError(e).simpleError,
|
|
681
|
-
await getReachableServer(projectUrl) ? { removeCache: true } : undefined
|
|
682
|
-
);
|
|
683
|
-
} else if (retries >= maxRetries) {
|
|
688
|
+
} else if (delivery === DELIVERY.NO_CACHE_NO_AWAIT) {
|
|
689
|
+
finalize(undefined, simplifyCaughtError(e).simpleError);
|
|
690
|
+
} else if (retries > maxRetries) {
|
|
684
691
|
finalize(
|
|
685
692
|
undefined,
|
|
686
693
|
{ error: 'retry_limit_exceeded', message: `retry exceed limit(${maxRetries})` },
|
|
687
694
|
{ removeCache: true, revertCache: true }
|
|
688
695
|
);
|
|
689
696
|
} else {
|
|
690
|
-
if (delivery === DELIVERY.
|
|
697
|
+
if (delivery === DELIVERY.NO_CACHE_AWAIT) {
|
|
691
698
|
const onlineListener = listenReachableServer(connected => {
|
|
692
699
|
if (connected) {
|
|
693
700
|
onlineListener();
|
|
@@ -703,7 +710,7 @@ const commitData = async (builder, value, type, config) => {
|
|
|
703
710
|
}
|
|
704
711
|
});
|
|
705
712
|
|
|
706
|
-
return await sendValue();
|
|
713
|
+
return (await sendValue());
|
|
707
714
|
};
|
|
708
715
|
|
|
709
716
|
export const trySendPendingWrite = (projectUrl) => {
|
|
@@ -713,20 +720,28 @@ export const trySendPendingWrite = (projectUrl) => {
|
|
|
713
720
|
const sortedWrite = Object.entries(CacheStore.PendingWrites[projectUrl] || {})
|
|
714
721
|
.filter(([k]) => !Scoped.OutgoingWrites[k])
|
|
715
722
|
.sort((a, b) => a[1].addedOn - b[1].addedOn);
|
|
723
|
+
let resolveCounts = 0;
|
|
716
724
|
|
|
717
725
|
for (const [writeId, { snapshot, builder, attempts = 1 }] of sortedWrite) {
|
|
718
726
|
try {
|
|
719
|
-
await commitData(builder, snapshot.value, snapshot.type, { ...snapshot.config, delivery: DELIVERY.
|
|
727
|
+
await commitData(builder, snapshot.value, snapshot.type, { ...snapshot.config, delivery: DELIVERY.NO_CACHE_NO_AWAIT });
|
|
720
728
|
delete CacheStore.PendingWrites[projectUrl][writeId];
|
|
729
|
+
++resolveCounts;
|
|
721
730
|
} catch (_) {
|
|
722
731
|
const { maxRetries } = builder;
|
|
723
732
|
if (!maxRetries || attempts >= maxRetries) {
|
|
724
733
|
delete CacheStore.PendingWrites[projectUrl][writeId];
|
|
734
|
+
++resolveCounts;
|
|
735
|
+
} else if (CacheStore.PendingWrites[projectUrl]?.[writeId]) {
|
|
736
|
+
CacheStore.PendingWrites[projectUrl][writeId].attempts = attempts + 1;
|
|
725
737
|
}
|
|
726
738
|
}
|
|
727
739
|
}
|
|
728
740
|
resolve();
|
|
729
741
|
Scoped.dispatchingWritesPromise = undefined;
|
|
730
|
-
if (
|
|
742
|
+
if (
|
|
743
|
+
(sortedWrite.length - resolveCounts) &&
|
|
744
|
+
await getReachableServer(projectUrl)
|
|
745
|
+
) trySendPendingWrite(projectUrl);
|
|
731
746
|
});
|
|
732
747
|
};
|