react-native-mosquito-transport 0.0.38 → 0.0.40

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/TODO CHANGED
@@ -21,4 +21,6 @@
21
21
  - switch to events package
22
22
  - serverTimeOffset
23
23
  - avoid sending cookies ✅
24
+ - add timeout in fetchHttp
25
+ - transform undefined to void instead of null
24
26
  <!-- - error: "refreshToken retry limit exceeded" <--- no need -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mosquito-transport",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "React native javascript sdk for mosquito-transport (https://github.com/brainbehindx/mosquito-transport)",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -31,7 +31,6 @@
31
31
  "buffer": "^6.0.3",
32
32
  "entity-serializer": "^1.0.3",
33
33
  "guard-object": "^1.1.4",
34
- "lodash": "^4.17.21",
35
34
  "poke-object": "^1.0.1",
36
35
  "simplify-error": "^1.0.1",
37
36
  "socket.io-client": "^4.8.1",
@@ -0,0 +1,212 @@
1
+ import { Buffer } from "buffer";
2
+ import { Validator } from "guard-object";
3
+ import { BSONError, BSONOffsetError, BSONRegExp, BSONRuntimeError, BSONSymbol, BSONValue, BSONVersionError, Binary, Code, DBRef, Decimal128, Double, Int32, Long, MaxKey, MinKey, ObjectId, Timestamp, UUID } from '../vendor/bson';
4
+
5
+ const ErrorInstances = [
6
+ niceReturn(() => ReferenceError),
7
+ niceReturn(() => SyntaxError),
8
+ niceReturn(() => RangeError),
9
+ niceReturn(() => TypeError),
10
+ niceReturn(() => EvalError),
11
+ Error
12
+ ].filter(v => v);
13
+
14
+ /**
15
+ * @template T
16
+ * @param {T} obj
17
+ * @returns {T}
18
+ */
19
+ export function basicClone(obj) {
20
+ if ([NaN, undefined, Infinity, null].includes(obj)) {
21
+ return obj;
22
+ }
23
+
24
+ if (typeof obj === 'bigint')
25
+ return BigInt(obj);
26
+
27
+ if (
28
+ ['number', 'string', 'boolean', 'function'].includes(typeof obj) ||
29
+ obj instanceof Promise
30
+ ) return obj;
31
+
32
+ for (const e of [Date, RegExp]) {
33
+ if (isDirectInstance(obj, e))
34
+ return new e(obj);
35
+ }
36
+
37
+ if (isDirectInstance(obj, ArrayBuffer))
38
+ return obj.slice(0);
39
+
40
+ if (
41
+ typeof SharedArrayBuffer !== 'undefined' &&
42
+ isDirectInstance(obj, SharedArrayBuffer)
43
+ ) return obj.slice(0);
44
+
45
+ if (Buffer.isBuffer(obj)) return Buffer.from(obj);
46
+
47
+ for (const instance of ErrorInstances) {
48
+ if (isDirectInstance(obj, instance)) {
49
+ const n = new instance(obj.message);
50
+ n.stack = obj.stack;
51
+ // n.name = obj.name;
52
+ return n;
53
+ }
54
+ }
55
+
56
+ for (const e of [Map, Set]) {
57
+ if (isDirectInstance(obj, e))
58
+ return new e([...obj].map(basicClone));
59
+ }
60
+
61
+ for (
62
+ const e of
63
+ [
64
+ Int8Array,
65
+ Uint8Array,
66
+ Uint8ClampedArray,
67
+ Int16Array,
68
+ Uint16Array,
69
+ Int32Array,
70
+ Uint32Array,
71
+ Float32Array,
72
+ Float64Array,
73
+ BigInt64Array,
74
+ BigUint64Array
75
+ ]
76
+ ) {
77
+ if (isDirectInstance(obj, e))
78
+ return new e(Buffer.from(obj));
79
+ }
80
+
81
+ if (isDirectInstance(obj, BSONOffsetError)) {
82
+ const n = new BSONOffsetError(obj.message, obj.offset);
83
+ // n.name = obj.name;
84
+ n.stack = obj.stack;
85
+ return n;
86
+ }
87
+
88
+ for (
89
+ const instance of
90
+ [
91
+ BSONRuntimeError,
92
+ BSONVersionError,
93
+ BSONError
94
+ ]
95
+ ) {
96
+ if (isDirectInstance(obj, instance)) {
97
+ const n = new instance(obj.message);
98
+ n.stack = obj.stack;
99
+ // n.name = obj.name;
100
+ return n;
101
+ }
102
+ }
103
+
104
+ if (
105
+ typeof Response !== 'undefined' &&
106
+ isDirectInstance(obj, Response)
107
+ ) return obj.clone();
108
+
109
+ if (
110
+ typeof Headers !== 'undefined' &&
111
+ isDirectInstance(obj, Headers)
112
+ ) return new Headers(obj);
113
+
114
+ if (
115
+ typeof Blob !== 'undefined' &&
116
+ isDirectInstance(obj, Blob)
117
+ ) return obj.slice(0, obj.size, obj.type);
118
+
119
+ if (isDirectInstance(obj, BSONRegExp))
120
+ return new BSONRegExp(obj.pattern, obj.options);
121
+
122
+ if (isDirectInstance(obj, BSONSymbol))
123
+ return new BSONSymbol(obj.value);
124
+
125
+ if (isDirectInstance(obj, Binary))
126
+ return new Binary(obj.buffer, obj.sub_type);
127
+
128
+ if (isDirectInstance(obj, Code))
129
+ return new Code(obj.code, obj.scope);
130
+
131
+ if (isDirectInstance(obj, DBRef))
132
+ return new DBRef(obj.collection, obj.oid, obj.db, obj.fields);
133
+
134
+ if (isDirectInstance(obj, Decimal128))
135
+ return new Decimal128(obj.bytes);
136
+
137
+ if (isDirectInstance(obj, Double))
138
+ return new Double(obj.value);
139
+
140
+ if (isDirectInstance(obj, Int32))
141
+ return new Int32(obj.value);
142
+
143
+ if (isDirectInstance(obj, Long))
144
+ return new Long(obj.low, obj.high, obj.unsigned);
145
+
146
+ if (isDirectInstance(obj, Timestamp))
147
+ return new Timestamp({ t: obj.t, i: obj.i });
148
+
149
+ if (isDirectInstance(obj, MaxKey))
150
+ return new MaxKey();
151
+
152
+ if (isDirectInstance(obj, MinKey))
153
+ return new MinKey();
154
+
155
+ if (isDirectInstance(obj, ObjectId))
156
+ return new ObjectId(obj.id);
157
+
158
+ if (isDirectInstance(obj, UUID)) return new UUID(obj);
159
+
160
+ if (isDirectInstance(obj, BSONValue)) return obj;
161
+
162
+ if (Validator.ARRAY(obj))
163
+ return [...obj.map(basicClone)];
164
+
165
+ if (Validator.OBJECT(obj)) {
166
+ const newObj = {};
167
+
168
+ for (const key in obj) {
169
+ if (obj.hasOwnProperty(key)) {
170
+ newObj[key] = basicClone(obj[key]);
171
+ }
172
+ }
173
+
174
+ return newObj;
175
+ }
176
+
177
+ if (ArrayBuffer.isView(obj)) return Buffer.from(obj);
178
+
179
+ if (obj instanceof Error) {
180
+ // general errors
181
+ try {
182
+ const n = new obj.constructor(obj.message);
183
+ n.stack = obj.stack;
184
+ return n;
185
+ } catch (error) {
186
+ const n = new Error(obj.message);
187
+ n.stack = obj.stack;
188
+ try {
189
+ n.name = obj.name;
190
+ } catch (_) { }
191
+ return n;
192
+ }
193
+ }
194
+
195
+ throw `${obj} cannot be cloned`;
196
+ }
197
+
198
+ /**
199
+ * @template T
200
+ * @param {unknown} obj
201
+ * @param {new (...args: any[]) => T} Class
202
+ * @returns {obj is T}
203
+ */
204
+ function isDirectInstance(obj, Class) {
205
+ return typeof obj === "object" && obj !== null && obj.constructor === Class;
206
+ }
207
+
208
+ function niceReturn(func) {
209
+ try {
210
+ return func();
211
+ } catch (_) { }
212
+ }
@@ -5,15 +5,15 @@ import { DatastoreParser } from "../products/database/bson";
5
5
  import { deserialize } from "entity-serializer";
6
6
  import { breakDbMap, purgeRedundantRecords } from "./purger";
7
7
  import { FS_PATH, getSystem } from "./fs_manager";
8
- import cloneDeep from "lodash/cloneDeep";
9
8
  import { Buffer } from "buffer";
9
+ import { basicClone } from "./basic_clone";
10
10
 
11
11
  const { FILE_NAME, TABLE_NAME } = FS_PATH;
12
12
 
13
13
  const CacheKeys = Object.keys(CacheStore);
14
14
 
15
15
  const prefillDatastore = (obj, caller) => {
16
- obj = cloneDeep(obj);
16
+ obj = basicClone(obj);
17
17
  breakDbMap(obj, (_projectUrl, _dbUrl, _dbName, _path, value) => {
18
18
  Object.entries(value.instance).forEach(([access_id, obj]) => {
19
19
  value.instance[access_id] = caller(obj);
@@ -28,7 +28,7 @@ const prefillDatastore = (obj, caller) => {
28
28
  };
29
29
 
30
30
  const prefillFetcher = (store, encode) => {
31
- store = cloneDeep(store);
31
+ store = basicClone(store);
32
32
  Object.values(store).forEach(accessIdObj => {
33
33
  Object.values(accessIdObj).forEach(value => {
34
34
  value.data.buffer = encode ?
@@ -54,7 +54,7 @@ export const updateCacheStore = async (node) => {
54
54
  } = CacheStore;
55
55
 
56
56
  const minimizePendingWrite = () => {
57
- const obj = cloneDeep(PendingWrites);
57
+ const obj = basicClone(PendingWrites);
58
58
  Object.values(obj).forEach(e => {
59
59
  Object.values(e).forEach(b => {
60
60
  if ('editions' in b) delete b.editions;
@@ -187,7 +187,6 @@ export const buildFetchInterface = async ({ body, authToken, method, uglify, ser
187
187
 
188
188
  return [{
189
189
  body: uglify ? plate : body,
190
- // cache: 'no-cache',
191
190
  headers: {
192
191
  ...extraHeaders,
193
192
  'Content-type': uglify ? 'request/buffer' : 'application/json',
package/src/index.d.ts CHANGED
@@ -230,6 +230,7 @@ interface RNMTCollection {
230
230
  });
231
231
  count: (config?: CountConfig) => Promise<number>;
232
232
  get: (config?: GetConfig) => Promise<DocumentResult[]>;
233
+ // TODO: change GetConfig for this listen
233
234
  listen: (callback: (snapshot?: DocumentResult[]) => void, onError?: (error?: DocumentError) => void, config?: GetConfig) => void;
234
235
  findOne: (findOne?: DocumentFind) => ({
235
236
  get: (config?: GetConfig) => Promise<DocumentResult>;
@@ -380,6 +381,12 @@ interface GetConfig {
380
381
  * To learn and see more examples on this, Please visit https://brainbehindx.com/mosquito-transport/docs/reading_data/retrieval
381
382
  */
382
383
  disableMinimizer?: boolean;
384
+ onWaiting: (intruder: WaitingIntruder) => void | Promise<void>;
385
+ }
386
+
387
+ interface WaitingIntruder {
388
+ resolve?: undefined | ((data: any) => void);
389
+ reject?: undefined | ((err: any) => void);
383
390
  }
384
391
 
385
392
  interface GetConfigExtraction {
package/src/index.js CHANGED
@@ -12,10 +12,10 @@ import { io } from "socket.io-client";
12
12
  import { AUTH_PROVIDER_ID } from "./helpers/values";
13
13
  import EngineApi from './helpers/engine_api';
14
14
  import { Validator } from 'guard-object';
15
- import cloneDeep from 'lodash/cloneDeep';
16
15
  import { Buffer } from 'buffer';
17
16
  import MTAuth, { purgePendingToken } from './products/auth';
18
17
  import { BSON } from "./vendor/bson";
18
+ import { basicClone } from './helpers/basic_clone';
19
19
 
20
20
  const {
21
21
  _listenCollection,
@@ -58,7 +58,7 @@ class RNMT {
58
58
  throw `initializeCache must be called before creating any ${this.constructor.name} instance`;
59
59
 
60
60
  if (!Scoped.InitializedProject[projectUrl]) {
61
- Scoped.InitializedProject[projectUrl] = cloneDeep(this.config);
61
+ Scoped.InitializedProject[projectUrl] = basicClone(this.config);
62
62
  Scoped.LastTokenRefreshRef[projectUrl] = 0;
63
63
  triggerAuthToken(projectUrl);
64
64
  initTokenRefresher({ ...this.config }, true);
@@ -95,7 +95,7 @@ class RNMT {
95
95
 
96
96
  const manualCheckConnection = () => {
97
97
  const ref = ++connectionIte;
98
- fetch(_areYouOk(projectUrl), { cache: 'no-cache', credentials: 'omit' }).then(async r => {
98
+ fetch(_areYouOk(projectUrl), { credentials: 'omit' }).then(async r => {
99
99
  if ((await r.json()).status === 'yes') {
100
100
  if (ref === connectionIte) onConnect();
101
101
  } else throw null;
@@ -1,4 +1,3 @@
1
- import cloneDeep from "lodash/cloneDeep";
2
1
  import { doSignOut, revokeAuthIntance } from ".";
3
2
  import EngineApi from "../../helpers/engine_api";
4
3
  import { AuthTokenListener, TokenRefreshListener } from "../../helpers/listeners";
@@ -7,6 +6,7 @@ import { awaitStore, buildFetchInterface, buildFetchResult, getPrefferTime, upda
7
6
  import { CacheStore, Scoped } from "../../helpers/variables";
8
7
  import { simplifyError } from "simplify-error";
9
8
  import { Validator } from "guard-object";
9
+ import { basicClone } from "../../helpers/basic_clone";
10
10
 
11
11
  export const listenToken = (callback, projectUrl) =>
12
12
  AuthTokenListener.listenTo(projectUrl, (t, n) => {
@@ -40,10 +40,10 @@ export const injectEmulatedAuth = async (config, emulatedURL) => {
40
40
 
41
41
  if (emulatedURL === projectUrl) throw `auth instance for ${emulatedURL} cannot emulate itself`;
42
42
  if (depended) throw `Chain Emulation Error: this auth instance (${projectUrl}) cannot be emulated as other auth instance (${depended[0]}) is already emulating it`;
43
- const thisAuthStore = cloneDeep(CacheStore.AuthStore[projectUrl]);
43
+ const thisAuthStore = basicClone(CacheStore.AuthStore[projectUrl]);
44
44
  revokeAuthIntance(config, thisAuthStore);
45
45
 
46
- CacheStore.AuthStore[projectUrl] = cloneDeep(CacheStore.AuthStore[emulatedURL]);
46
+ CacheStore.AuthStore[projectUrl] = basicClone(CacheStore.AuthStore[emulatedURL]);
47
47
  Scoped.AuthJWTToken[projectUrl] = token;
48
48
  CacheStore.EmulatedAuth[projectUrl] = emulatedURL;
49
49
 
@@ -155,7 +155,7 @@ const refreshToken = (builder, processRef, remainRetries = 1, isForceRefresh) =>
155
155
  if (isForceRefresh) Scoped.InitiatedForcedToken[projectUrl] = true;
156
156
 
157
157
  getEmulatedLinks(projectUrl).forEach(v => {
158
- CacheStore.AuthStore[v] = cloneDeep(CacheStore.AuthStore[projectUrl]);
158
+ CacheStore.AuthStore[v] = basicClone(CacheStore.AuthStore[projectUrl]);
159
159
  Scoped.AuthJWTToken[v] = f.result.token;
160
160
 
161
161
  triggerAuthToken(v, isInit);
@@ -6,7 +6,7 @@ import { CacheStore, Scoped } from "../../helpers/variables";
6
6
  import { awaitRefreshToken, getEmulatedLinks, initTokenRefresher, injectEmulatedAuth, injectFreshToken, listenToken, parseToken, triggerAuthToken } from "./accessor";
7
7
  import { deserializeE2E, encodeBinary, serializeE2E } from "../../helpers/peripherals";
8
8
  import { simplifyCaughtError, simplifyError } from "simplify-error";
9
- import cloneDeep from "lodash/cloneDeep";
9
+ import { basicClone } from "../../helpers/basic_clone";
10
10
 
11
11
  const {
12
12
  _listenUserVerification,
@@ -171,7 +171,7 @@ const doCustomSignin = (builder, email, password) => new Promise(async (resolve,
171
171
 
172
172
  try {
173
173
  await awaitStore();
174
- const thisAuthStore = cloneDeep(CacheStore.AuthStore[projectUrl]);
174
+ const thisAuthStore = basicClone(CacheStore.AuthStore[projectUrl]);
175
175
 
176
176
  const [reqBuilder, [privateKey]] = await buildFetchInterface({
177
177
  body: { data: `${encodeBinary(email)}.${encodeBinary(password)}` },
@@ -201,7 +201,7 @@ const doCustomSignup = (builder, email, password, name, metadata) => new Promise
201
201
 
202
202
  try {
203
203
  await awaitStore();
204
- const thisAuthStore = cloneDeep(CacheStore.AuthStore[projectUrl]);
204
+ const thisAuthStore = basicClone(CacheStore.AuthStore[projectUrl]);
205
205
 
206
206
  const [reqBuilder, [privateKey]] = await buildFetchInterface({
207
207
  body: {
@@ -285,7 +285,7 @@ export const purgePendingToken = async (nodeId) => {
285
285
  try {
286
286
  let isConnected;
287
287
  try {
288
- isConnected = (await (await fetch(_areYouOk(projectUrl))).json(), { cache: 'no-cache', credentials: 'omit' }).status === 'yes';
288
+ isConnected = (await (await fetch(_areYouOk(projectUrl))).json(), { credentials: 'omit' }).status === 'yes';
289
289
  } catch (_) { }
290
290
 
291
291
  if (!isConnected)
@@ -312,7 +312,7 @@ const doGoogleSignin = (builder, token) => new Promise(async (resolve, reject) =
312
312
 
313
313
  try {
314
314
  await awaitStore();
315
- const thisAuthStore = cloneDeep(CacheStore.AuthStore[projectUrl]);
315
+ const thisAuthStore = basicClone(CacheStore.AuthStore[projectUrl]);
316
316
 
317
317
  const [reqBuilder, [privateKey]] = await buildFetchInterface({
318
318
  body: { token },
@@ -3,7 +3,6 @@ import { awaitStore, updateCacheStore } from "../../helpers/utils";
3
3
  import { CacheStore, Scoped } from "../../helpers/variables";
4
4
  import { assignExtractionFind, CompareBson, confirmFilterDoc, defaultBSON, downcastBSON, validateCollectionName, validateFilter } from "./validator";
5
5
  import { DatabaseRecordsListener } from "../../helpers/listeners";
6
- import cloneDeep from "lodash/cloneDeep";
7
6
  import { BSONRegExp, ObjectId, Timestamp } from "../../vendor/bson";
8
7
  import { niceGuard, Validator } from "guard-object";
9
8
  import { TIMESTAMP } from "./types";
@@ -11,6 +10,7 @@ import { docSize, incrementDatabaseSize } from "./counter";
11
10
  import { DatastoreParser, serializeToBase64 } from "./bson";
12
11
  import { FS_PATH, getSystem, useFS } from "../../helpers/fs_manager";
13
12
  import { grab, poke, unpoke } from "poke-object";
13
+ import { basicClone } from "../../helpers/basic_clone";
14
14
 
15
15
  const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY } = FS_PATH;
16
16
 
@@ -77,9 +77,9 @@ export const getCountQuery = async (builder, access_id) => {
77
77
  }
78
78
 
79
79
  export const insertRecord = async (builder, config, accessIdWithoutLimit, value, episode = 0) => {
80
- builder = builder && cloneDeep(builder);
81
- config = config && cloneDeep(config);
82
- value = value && cloneDeep(value);
80
+ builder = builder && basicClone(builder);
81
+ config = config && basicClone(config);
82
+ value = value && basicClone(value);
83
83
 
84
84
  await awaitStore();
85
85
  const { io } = Scoped.ReleaseCacheData;
@@ -155,7 +155,7 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
155
155
  incrementDatabaseSize(builder, path, editionSizeOffset + resultSizeOffset);
156
156
 
157
157
  poke(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', accessIdWithoutLimit], newData);
158
- if (isEpisode) poke(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, `${limit}`], cloneDeep(newResultData));
158
+ if (isEpisode) poke(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, `${limit}`], basicClone(newResultData));
159
159
  updateCacheStore(['DatabaseStore', 'DatabaseStats']);
160
160
  };
161
161
 
@@ -167,7 +167,7 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
167
167
  const isEpisode = episode === 1;
168
168
 
169
169
  const transformData = (data) => {
170
- data = cloneDeep(data);
170
+ data = basicClone(data);
171
171
  if (random) {
172
172
  data = shuffleArray(data);
173
173
  } else if (sort) {
@@ -221,7 +221,7 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
221
221
  const resultData = grab(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', accessIdWithoutLimit, `${limit}`]);
222
222
  if (resultData) {
223
223
  resultData.touched = Date.now();
224
- return [cloneDeep(resultData.data)];
224
+ return [basicClone(resultData.data)];
225
225
  }
226
226
  return null;
227
227
  }
@@ -242,8 +242,8 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
242
242
  };
243
243
 
244
244
  export const generateRecordID = (builder, config, removeLimit) => {
245
- builder = builder && cloneDeep(builder);
246
- config = config && cloneDeep(config);
245
+ builder = builder && basicClone(builder);
246
+ config = config && basicClone(config);
247
247
 
248
248
  const { command, path, countDoc } = builder;
249
249
  const { extraction, excludeFields, returnOnly } = config || {};
@@ -269,7 +269,7 @@ export const generateRecordID = (builder, config, removeLimit) => {
269
269
  };
270
270
 
271
271
  const arrangeCommands = (c, removeLimit) => {
272
- c = cloneDeep(c);
272
+ c = basicClone(c);
273
273
  const sortFind = f => {
274
274
  ['$and', '$or', '$nor'].forEach(n => {
275
275
  if (f[n]) {
@@ -375,12 +375,12 @@ const WriteValidator = {
375
375
  export const validateWriteValue = ({ type, find, value }) => WriteValidator[type]({ find, value, type });
376
376
 
377
377
  export const addPendingWrites = async (builder, writeId, result) => {
378
- builder = builder && cloneDeep(builder);
379
- result = result && cloneDeep(result);
378
+ builder = builder && basicClone(builder);
379
+ result = result && basicClone(result);
380
380
  await awaitStore();
381
381
 
382
382
  const { projectUrl } = builder;
383
- const pendingSnapshot = cloneDeep(result);
383
+ const pendingSnapshot = basicClone(result);
384
384
  const { editions, linearWrite, pathChanges } = await syncCache(builder, result);
385
385
 
386
386
  const isStaticWrite = !linearWrite.some(({ value, type }) => {
@@ -428,7 +428,7 @@ export const addPendingWrites = async (builder, writeId, result) => {
428
428
  }
429
429
 
430
430
  if (!wasShifted)
431
- poke(CacheStore.PendingWrites, [projectUrl, writeId], cloneDeep({
431
+ poke(CacheStore.PendingWrites, [projectUrl, writeId], basicClone({
432
432
  builder: pureBuilder,
433
433
  snapshot: pendingSnapshot,
434
434
  editions,
@@ -453,7 +453,7 @@ const syncCache = async (builder, result) => {
453
453
  )
454
454
  : [{ ...result, find: builder.find, path: builder.path }];
455
455
 
456
- const copiedWrite = cloneDeep(linearWrite);
456
+ const copiedWrite = basicClone(linearWrite);
457
457
 
458
458
  await Promise.all(linearWrite.map(async ({ value: writeObj, find, type, path }) => {
459
459
  WriteValidator[type]({ find, value: writeObj });
@@ -506,7 +506,7 @@ const syncCache = async (builder, result) => {
506
506
  const { extraction } = config || {};
507
507
 
508
508
  const logChanges = (d) => {
509
- editions.push(cloneDeep([entityId, d, path]));
509
+ editions.push(basicClone([entityId, d, path]));
510
510
  const [b4, af] = d;
511
511
  const offset = docSize(af) - docSize(b4);
512
512
  dataObj.size += offset;
@@ -518,7 +518,7 @@ const syncCache = async (builder, result) => {
518
518
  const accessExtraction = async obj => {
519
519
  const buildAssignedExtraction = (data) => {
520
520
  const d = (Array.isArray(extraction) ? extraction : [extraction]).map(thisExtraction => {
521
- const query = cloneDeep(thisExtraction);
521
+ const query = basicClone(thisExtraction);
522
522
 
523
523
  ['find', 'findOne'].forEach(n => {
524
524
  if (query[n])
@@ -570,7 +570,7 @@ const syncCache = async (builder, result) => {
570
570
  return findOne ? scrapDocs[0] : scrapDocs;
571
571
  }));
572
572
 
573
- return cloneDeep(Array.isArray(extraction) ? scrapedProjection : scrapedProjection[0]);
573
+ return basicClone(Array.isArray(extraction) ? scrapedProjection : scrapedProjection[0]);
574
574
  }
575
575
 
576
576
  if (['setOne', 'setMany'].includes(type)) {
@@ -582,7 +582,7 @@ const syncCache = async (builder, result) => {
582
582
 
583
583
  if (instance_data.findIndex(v => CompareBson.equal(v._id, e._id)) === -1) {
584
584
  const x = snipUpdate(obj);
585
- instance_data.push(cloneDeep(x));
585
+ instance_data.push(basicClone(x));
586
586
  logChanges([undefined, x]);
587
587
  } else if (!duplicateSets[e._id]) {
588
588
  console.warn(`document with _id=${e._id} already exist locally with ${type}() operation, skipping to online commit`);
@@ -824,7 +824,7 @@ const snipDocument = (data, find, config) => {
824
824
  if (!data || !config) return data;
825
825
  const { returnOnly, excludeFields } = config || {};
826
826
 
827
- let output = cloneDeep(data);
827
+ let output = basicClone(data);
828
828
 
829
829
  if (returnOnly) {
830
830
  output = {};
@@ -967,7 +967,7 @@ const AtomicWriter = {
967
967
  : [grab(object, destStage.slice(0, -1).join('.')), sourceStage.slice(-1)[0], destStage.slice(-1)[0]];
968
968
 
969
969
  if (tipObj && tipSource in tipObj) {
970
- tipObj[tipDest] = cloneDeep(tipObj[tipSource]);
970
+ tipObj[tipDest] = basicClone(tipObj[tipSource]);
971
971
  delete tipObj[tipSource];
972
972
  }
973
973
  },
@@ -1,6 +1,6 @@
1
- import cloneDeep from "lodash/cloneDeep";
2
1
  import { deserialize, serialize } from "../../vendor/bson";
3
2
  import { Buffer } from "buffer";
3
+ import { basicClone } from "../../helpers/basic_clone";
4
4
 
5
5
  export const deserializeBSON = (data, cast) => {
6
6
  if (typeof data === 'string')
@@ -18,7 +18,7 @@ export const serializeToBase64 = doc => Buffer.from(serialize(doc)).toString('ba
18
18
 
19
19
  export const DatastoreParser = {
20
20
  encode: (obj) => {
21
- obj = cloneDeep(obj);
21
+ obj = basicClone(obj);
22
22
  const { command, config } = obj;
23
23
 
24
24
  const serializeQuery = (e) =>
@@ -37,7 +37,7 @@ export const DatastoreParser = {
37
37
  return obj;
38
38
  },
39
39
  decode: (obj, cast = true) => {
40
- obj = cloneDeep(obj);
40
+ obj = basicClone(obj);
41
41
  const { command, config } = obj;
42
42
 
43
43
  const serializeQuery = (e) =>
@@ -11,8 +11,8 @@ import { DELIVERY, RETRIEVAL } from "../../helpers/values";
11
11
  import { ObjectId } from "../../vendor/bson";
12
12
  import { guardObject, Validator } from "guard-object";
13
13
  import { simplifyCaughtError } from "simplify-error";
14
- import cloneDeep from "lodash/cloneDeep";
15
14
  import { deserializeBSON, serializeToBase64 } from "./bson";
15
+ import { basicClone } from "../../helpers/basic_clone";
16
16
 
17
17
  export class MTCollection {
18
18
  constructor(config) {
@@ -136,6 +136,8 @@ const {
136
136
  } = EngineApi;
137
137
 
138
138
  const listenDocument = (callback, onError, builder, config) => {
139
+ builder = basicClone(builder);
140
+ config = basicClone(config);
139
141
  const { projectUrl, wsPrefix, serverE2E_PublicKey, baseUrl, dbUrl, dbName, path, disableCache, command, uglify, extraHeaders, castBSON } = builder;
140
142
  const { find, findOne, sort, direction, limit } = command;
141
143
  const { disableAuth, episode } = config || {};
@@ -160,7 +162,7 @@ const listenDocument = (callback, onError, builder, config) => {
160
162
  const thisSnapshotId = serializeToBase64({ _: s });
161
163
  if (thisSnapshotId === lastSnapshot) return;
162
164
  lastSnapshot = thisSnapshotId;
163
- callback?.(cloneDeep(transformBSON(s, castBSON)));
165
+ callback?.(basicClone(transformBSON(s, castBSON)));
164
166
  };
165
167
 
166
168
  if (shouldCache) {
@@ -255,6 +257,9 @@ const listenDocument = (callback, onError, builder, config) => {
255
257
  };
256
258
 
257
259
  const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
260
+ connectData = basicClone(connectData);
261
+ disconnectData = basicClone(disconnectData);
262
+ builder = basicClone(builder);
258
263
  const { projectUrl, wsPrefix, baseUrl, serverE2E_PublicKey, dbUrl, dbName, extraHeaders, uglify } = builder;
259
264
  const disableAuth = false;
260
265
 
@@ -344,6 +349,8 @@ const initOnDisconnectionTask = ({ builder, connectData, disconnectData }) => {
344
349
  };
345
350
 
346
351
  const countCollection = async (builder, config) => {
352
+ builder = basicClone(builder);
353
+ config = basicClone(config);
347
354
  const { projectUrl, serverE2E_PublicKey, dbUrl, dbName, maxRetries = 1, uglify, extraHeaders, path, disableCache, command = {} } = builder;
348
355
  const { find } = command;
349
356
  const { disableAuth } = config || {};
@@ -445,16 +452,20 @@ const hydrateForeignDoc = ({ data, doc_holder }) => {
445
452
 
446
453
  const transformBSON = (d, castBSON) => {
447
454
  if (castBSON) return d && deserializeBSON(serializeToBase64({ _: d }), true)._;
448
- return cloneDeep(d);
455
+ return basicClone(d);
449
456
  };
450
457
 
451
- const findObject = async (builder, config) => {
458
+ const findObject = async (builder, initConfig) => {
459
+ builder = basicClone(builder);
452
460
  const { projectUrl, serverE2E_PublicKey, dbUrl, dbName, maxRetries = 1, path, disableCache = false, uglify, extraHeaders, command, castBSON } = builder;
453
- const pureConfig = stripRequestConfig(config);
461
+
462
+ const pureConfig = stripRequestConfig(initConfig);
454
463
  validateFindObject(command);
455
- validateFindConfig(config);
464
+ validateFindConfig(initConfig);
456
465
  validateCollectionName(path);
457
466
 
467
+ let { onWaiting, ...config } = basicClone(initConfig) || {};
468
+
458
469
  const { find, findOne, sort, direction, limit, random } = command;
459
470
  const { retrieval = RETRIEVAL.DEFAULT, episode = 0, disableAuth, disableMinimizer } = config || {};
460
471
  const enableMinimizer = !disableMinimizer;
@@ -466,6 +477,7 @@ const findObject = async (builder, config) => {
466
477
 
467
478
  await awaitStore();
468
479
 
480
+ let intruder = {};
469
481
  let retries = 0, hasFinalize;
470
482
 
471
483
  const readValue = () => new Promise(async (resolve, reject) => {
@@ -473,11 +485,12 @@ const findObject = async (builder, config) => {
473
485
  instantProcess = retryProcess === 1;
474
486
 
475
487
  const finalize = (a, b) => {
476
- const res = (instantProcess && a) ? transformBSON(a[0] || undefined, castBSON) : a;
488
+ const res = (instantProcess && a) ? intruder ? transformBSON(a[0] || undefined, castBSON) : a[0] : a;
489
+ const doClone = v => intruder ? basicClone(v) : v;
477
490
 
478
491
  if (a) {
479
- resolve(instantProcess ? cloneDeep(res) : a);
480
- } else reject(instantProcess ? cloneDeep(b) : b);
492
+ resolve(instantProcess ? doClone(res) : a);
493
+ } else reject(instantProcess ? doClone(b) : b);
481
494
  if (hasFinalize || !instantProcess) return;
482
495
  hasFinalize = true;
483
496
 
@@ -488,7 +501,7 @@ const findObject = async (builder, config) => {
488
501
  delete Scoped.PendingDbReadCollective[processAccessId];
489
502
 
490
503
  resolutionList.forEach(e => {
491
- e(a ? { result: res } : undefined, b);
504
+ e(a ? { result: doClone(res) } : undefined, doClone(b));
492
505
  });
493
506
  }
494
507
  };
@@ -498,8 +511,8 @@ const findObject = async (builder, config) => {
498
511
  if (enableMinimizer) {
499
512
  if (Scoped.PendingDbReadCollective[processAccessId]) {
500
513
  Scoped.PendingDbReadCollective[processAccessId].push((a, b) => {
501
- if (a) resolve(cloneDeep(a.result));
502
- else reject(cloneDeep(b));
514
+ if (a) resolve(a.result);
515
+ else reject(b);
503
516
  });
504
517
  return;
505
518
  }
@@ -576,6 +589,8 @@ const findObject = async (builder, config) => {
576
589
  } else {
577
590
  const onlineListener = listenReachableServer(connected => {
578
591
  if (connected) {
592
+ intruder.resolve = undefined;
593
+ intruder.reject = undefined;
579
594
  onlineListener();
580
595
  readValue().then(
581
596
  e => { finalize(e); },
@@ -583,6 +598,22 @@ const findObject = async (builder, config) => {
583
598
  );
584
599
  }
585
600
  }, projectUrl);
601
+
602
+ const cleanseIntruder = () => {
603
+ onlineListener?.();
604
+ intruder = undefined;
605
+ }
606
+
607
+ intruder.resolve = (data) => {
608
+ cleanseIntruder();
609
+ finalize([data]);
610
+ };
611
+ intruder.reject = (err) => {
612
+ cleanseIntruder();
613
+ finalize(undefined, err);
614
+ };
615
+ onWaiting?.(intruder);
616
+ onWaiting = undefined;
586
617
  }
587
618
  }
588
619
  });
@@ -596,7 +627,7 @@ const transformNullRecursively = obj => Object.fromEntries(
596
627
  )
597
628
  );
598
629
 
599
- const cleanBatchWrite = (value) => cloneDeep(value).map(v => {
630
+ const cleanBatchWrite = (value) => basicClone(value).map(v => {
600
631
  if (Validator.OBJECT(v?.value)) {
601
632
  v.value = transformNullRecursively(v.value);
602
633
  } else if (Array.isArray(v?.value)) {
@@ -608,6 +639,8 @@ const cleanBatchWrite = (value) => cloneDeep(value).map(v => {
608
639
  });
609
640
 
610
641
  const commitData = async (builder, value, type, config) => {
642
+ builder = basicClone(builder);
643
+ config = basicClone(config);
611
644
  // transform undefined
612
645
  if (Validator.OBJECT(value)) {
613
646
  value = value && deserializeBSON(serializeToBase64({ _: transformNullRecursively(value) }))._;
@@ -31,7 +31,7 @@ const FindConfig = {
31
31
  ).length,
32
32
  returnOnly: ReturnAndExcludeFootprint,
33
33
  excludeFields: ReturnAndExcludeFootprint,
34
-
34
+ onWaiting: t => t === undefined || typeof t === 'function',
35
35
  episode: t => [undefined, 0, 1].includes(t),
36
36
  retrieval: t => t === undefined || Object.values(RETRIEVAL).includes(t),
37
37
  disableAuth: t => t === undefined || typeof t === 'boolean',
@@ -1,14 +1,14 @@
1
1
  import { updateCacheStore } from "../../helpers/utils";
2
2
  import { CacheStore, Scoped } from "../../helpers/variables";
3
- import cloneDeep from "lodash/cloneDeep";
4
3
  import { serialize } from "entity-serializer";
5
4
  import { incrementFetcherSize } from "./counter";
6
5
  import { FS_PATH, useFS } from "../../helpers/fs_manager";
6
+ import { basicClone } from "../../helpers/basic_clone";
7
7
 
8
8
  const { FETCH_RESOURCES } = FS_PATH;
9
9
 
10
10
  export const insertFetchResources = async (projectUrl, access_id, value) => {
11
- value = cloneDeep(value);
11
+ value = basicClone(value);
12
12
  const dataSize = serialize(value).byteLength;
13
13
 
14
14
  const { io } = Scoped.ReleaseCacheData;
@@ -41,7 +41,7 @@ export const getFetchResources = async (projectUrl, access_id) => {
41
41
  const record = CacheStore.FetchedStore[projectUrl]?.[access_id];
42
42
  if (record) record.touched = Date.now();
43
43
  updateCacheStore(['FetchedStore']);
44
- return record && cloneDeep(record?.data);
44
+ return record && basicClone(record?.data);
45
45
  }
46
46
 
47
47
  const res = await useFS(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async fs => {
@@ -6,14 +6,14 @@ import { Scoped } from "../../helpers/variables";
6
6
  import { awaitRefreshToken } from "../auth/accessor";
7
7
  import { simplifyCaughtError } from "simplify-error";
8
8
  import { guardObject, Validator } from "guard-object";
9
- import cloneDeep from "lodash/cloneDeep";
10
9
  import { serialize } from "entity-serializer";
11
10
  import { getFetchResources, insertFetchResources } from "./accessor";
11
+ import { basicClone } from "../../helpers/basic_clone";
12
12
 
13
13
  const buildFetchData = (data, extras) => {
14
14
  const { ok, type, status, statusText, redirected, url, headers, size, buffer } = data;
15
15
 
16
- const response = new Response(buffer, {
16
+ const response = new Response(Buffer.from(buffer), {
17
17
  headers: new Headers(headers),
18
18
  status,
19
19
  statusText,
@@ -86,9 +86,9 @@ export const mfetch = async (input = '', init, config) => {
86
86
  const callFetch = () => new Promise(async (resolve, reject) => {
87
87
  const retryProcess = ++retries;
88
88
 
89
- const finalize = (a, b) => {
90
- if (a) resolve(a);
91
- else reject(b);
89
+ const finalize = (a, b, extras) => {
90
+ if (a) resolve(buildFetchData(a, extras));
91
+ else reject(basicClone(b));
92
92
  if (hasFinalize || retryProcess !== 1) return;
93
93
  hasFinalize = true;
94
94
 
@@ -99,14 +99,14 @@ export const mfetch = async (input = '', init, config) => {
99
99
  delete Scoped.PendingFetchCollective[processReqId];
100
100
 
101
101
  resolutionList.forEach(e => {
102
- e(a, b);
102
+ e(a && buildFetchData(a, extras), b && basicClone(b));
103
103
  });
104
104
  }
105
105
  };
106
106
 
107
107
  await awaitStore();
108
108
  const resolveCache = (reqData) => {
109
- finalize(buildFetchData(reqData, { fromCache: true }));
109
+ finalize(reqData, undefined, { fromCache: true });
110
110
  };
111
111
 
112
112
  try {
@@ -114,8 +114,8 @@ export const mfetch = async (input = '', init, config) => {
114
114
  if (enableMinimizer) {
115
115
  if (Scoped.PendingFetchCollective[processReqId]) {
116
116
  Scoped.PendingFetchCollective[processReqId].push((a, b) => {
117
- if (a) resolve(cloneDeep(a.result));
118
- else reject(cloneDeep(b));
117
+ if (a) resolve(a);
118
+ else reject(b);
119
119
  });
120
120
  return;
121
121
  }
@@ -142,11 +142,10 @@ export const mfetch = async (input = '', init, config) => {
142
142
  const [reqBuilder, [privateKey]] = uglified ? await serializeE2E(body, mtoken, serverE2E_PublicKey) : [null, []];
143
143
 
144
144
  const f = await fetch(isLink ? input : `${projectUrl}/${normalizeRoute(input)}`, {
145
- ...(!isBaseUrl || hasBody) ? { method: 'POST' } : {},
145
+ ...hasBody ? { method: 'POST' } : {},
146
146
  credentials: 'omit',
147
147
  ...init,
148
148
  ...uglified ? { body: reqBuilder } : encodeBody ? { body: serialize(body) } : {},
149
- cache: 'no-cache',
150
149
  headers: {
151
150
  ...extraHeaders,
152
151
  ...rawHeader,
@@ -185,7 +184,7 @@ export const mfetch = async (input = '', init, config) => {
185
184
 
186
185
  if (shouldCache) insertFetchResources(projectUrl, reqId, resObj);
187
186
 
188
- finalize(buildFetchData(resObj));
187
+ finalize(resObj);
189
188
  } catch (e) {
190
189
  let thisRecord;
191
190