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/src/index.js CHANGED
@@ -2,17 +2,17 @@ import 'react-native-get-random-values';
2
2
  import { deserializeE2E, listenReachableServer, serializeE2E } from "./helpers/peripherals";
3
3
  import { awaitStore, releaseCacheStore } from "./helpers/utils";
4
4
  import { CacheStore, Scoped } from "./helpers/variables";
5
- import { MTCollection, batchWrite, trySendPendingWrite } from "./products/database";
5
+ import { MTCollection, batchWrite, onCollectionConnect, trySendPendingWrite } from "./products/database";
6
6
  import { MTStorage } from "./products/storage";
7
7
  import { ServerReachableListener, TokenRefreshListener } from "./helpers/listeners";
8
8
  import { initTokenRefresher, listenToken, listenTokenReady, triggerAuthToken } from "./products/auth/accessor";
9
- import { TIMESTAMP, DOCUMENT_EXTRACTION, FIND_GEO_JSON, GEO_JSON } from "./products/database/types";
9
+ import { TIMESTAMP, DOCUMENT_EXTRACTION, FIND_GEO_JSON, GEO_JSON, TIMESTAMP_OFFSET } from "./products/database/types";
10
10
  import { mfetch } from "./products/http_callable";
11
11
  import { io } from "socket.io-client";
12
- import { AUTH_PROVIDER_ID, CACHE_PROTOCOL } from "./helpers/values";
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';
15
+ import cloneDeep from 'lodash/cloneDeep';
16
16
  import { Buffer } from 'buffer';
17
17
  import MTAuth, { purgePendingToken } from './products/auth';
18
18
 
@@ -39,6 +39,8 @@ class RNMT {
39
39
  validateMTConfig(config, this);
40
40
  this.config = {
41
41
  ...config,
42
+ dbName: config.dbName || '',
43
+ dbUrl: config.dbUrl || '',
42
44
  serverE2E_PublicKey: config.serverE2E_PublicKey && new Uint8Array(Buffer.from(config.serverE2E_PublicKey, 'base64')),
43
45
  castBSON: config.castBSON === undefined || config.castBSON,
44
46
  maxRetries: config.maxRetries || 3,
@@ -125,16 +127,24 @@ class RNMT {
125
127
  });
126
128
  }
127
129
 
128
- getDatabase = (dbName, dbUrl) => ({
129
- collection: (path) => new MTCollection({
130
- ...this.config,
131
- path,
132
- ...dbName ? { dbName } : {},
133
- ...dbUrl ? { dbUrl } : {}
134
- })
135
- });
130
+ getDatabase = (dbName, dbUrl) => {
131
+ if (dbName) ConfigValidator.dbName(dbName);
132
+ if (dbUrl) ConfigValidator.dbUrl(dbUrl);
133
+
134
+ return {
135
+ collection: (path) => new MTCollection({
136
+ ...this.config,
137
+ path,
138
+ dbName: dbName || '',
139
+ dbUrl: dbUrl || ''
140
+ })
141
+ };
142
+ }
136
143
 
137
144
  collection = (path) => new MTCollection({ ...this.config, path });
145
+
146
+ onConnect = () => onCollectionConnect({ ...this.config });
147
+
138
148
  batchWrite = (map, configx) => batchWrite({ ...this.config }, map, configx);
139
149
  auth = () => new MTAuth({ ...this.config });
140
150
  storage = () => new MTStorage({ ...this.config });
@@ -143,7 +153,7 @@ class RNMT {
143
153
 
144
154
  getSocket = (configOpts) => {
145
155
  const { disableAuth, authHandshake } = configOpts || {};
146
- const { projectUrl, uglify, accessKey, serverE2E_PublicKey, wsPrefix, extraHeaders } = this.config;
156
+ const { projectUrl, uglify, serverE2E_PublicKey, wsPrefix, extraHeaders } = this.config;
147
157
 
148
158
  const restrictedRoute = [
149
159
  _listenCollection,
@@ -163,8 +173,11 @@ class RNMT {
163
173
  socketListenerList = [],
164
174
  socketListenerIte = 0;
165
175
 
176
+ /**
177
+ * @type {import('socket.io-client').Socket}
178
+ */
179
+ let socket;
166
180
  let hasCancelled,
167
- socket,
168
181
  tokenListener,
169
182
  clientPrivateKey;
170
183
 
@@ -250,7 +263,7 @@ class RNMT {
250
263
  const init = async () => {
251
264
  if (hasCancelled) return;
252
265
  const mtoken = disableAuth ? undefined : Scoped.AuthJWTToken[projectUrl];
253
- const [reqBuilder, [privateKey]] = uglify ? await serializeE2E({ accessKey, a_extras: authHandshake }, mtoken, serverE2E_PublicKey) : [null, []];
266
+ const [reqBuilder, [privateKey]] = uglify ? await serializeE2E({ a_extras: authHandshake }, mtoken, serverE2E_PublicKey) : [null, []];
254
267
 
255
268
  socket = io(`${wsPrefix}://${projectUrl.split('://')[1]}`, {
256
269
  transports: ['websocket', 'polling', 'flashsocket'],
@@ -260,8 +273,7 @@ class RNMT {
260
273
  e2e: reqBuilder.toString('base64')
261
274
  } : {
262
275
  ...mtoken ? { mtoken } : {},
263
- a_extras: authHandshake,
264
- accessKey
276
+ a_extras: authHandshake
265
277
  }
266
278
  });
267
279
  clientPrivateKey = privateKey;
@@ -290,7 +302,7 @@ class RNMT {
290
302
  lastTokenStatus = status || false;
291
303
  }, projectUrl);
292
304
  }
293
-
305
+ // TODO: disconnected
294
306
  return {
295
307
  timeout: (timeout) => {
296
308
  if (timeout !== undefined && !Validator.POSITIVE_INTEGER(timeout))
@@ -377,14 +389,10 @@ const discloseSocketArguments = (args = []) => {
377
389
  }
378
390
 
379
391
  const validateReleaseCacheProp = (prop) => {
380
- const cacheList = [...Object.values(CACHE_PROTOCOL)];
381
-
382
392
  Object.entries(prop).forEach(([k, v]) => {
383
- if (k === 'cachePassword') {
393
+ if (k === 'sqliteKey') {
384
394
  if (typeof v !== 'string' || v.trim().length <= 0)
385
- throw `Invalid value supplied to cachePassword, value must be a string and greater than 0 characters`;
386
- } else if (k === 'cacheProtocol') {
387
- if (!cacheList.includes(`${v}`)) throw `unknown value supplied to ${k}, expected any of ${cacheList}`;
395
+ throw `Invalid value supplied to "sqliteKey", value must be a string and greater than 0 characters`;
388
396
  } else if (k === 'io') {
389
397
  Object.entries(v).forEach(([k, v]) => {
390
398
  if (k === 'input' || k === 'output') {
@@ -392,18 +400,17 @@ const validateReleaseCacheProp = (prop) => {
392
400
  throw `Invalid value supplied to "io.${k}", expected a function but got "${v}"`;
393
401
  } else throw `Unexpected property named "io.${k}"`;
394
402
  });
403
+ if (!v?.input && !v?.output) throw '"input" and "output" are required when "io" is provided';
395
404
  } else if (k === 'promoteCache') {
396
405
  if (typeof v !== 'boolean') throw 'promoteCache should be a boolean';
397
- } else if (k === 'heapMemory') {
398
- if (typeof v !== 'number' || v <= 0)
399
- throw `Invalid value supplied to heapMemory, value must be an integer greater than zero`;
406
+ } else if (['maxLocalDatabaseSize', 'maxLocalFetchHttpSize'].includes(k)) {
407
+ if (!Validator.POSITIVE_INTEGER(v) || v <= 0)
408
+ throw `Invalid value supplied to ${k}, value must be a positive integer greater than zero`;
400
409
  } else throw `Unexpected property named ${k}`;
401
410
  });
402
-
403
- if (!prop?.io && !prop?.cacheProtocol) throw 'You need to provide either "io" or "cacheProtocol"';
404
411
  }
405
412
 
406
- const validator = {
413
+ const ConfigValidator = {
407
414
  dbName: (v) => {
408
415
  if (typeof v !== 'string' || !v.trim())
409
416
  throw `Invalid value supplied to dbName, value must be a non-empty string`;
@@ -415,15 +422,12 @@ const validator = {
415
422
  projectUrl: (v) => {
416
423
  if (typeof v !== 'string' || (!Validator.HTTPS(v) && !Validator.HTTP(v)))
417
424
  throw `Expected "projectUrl" to be valid https or http link but got "${v}"`;
425
+ if (v.endsWith('/')) throw '"projectUrl" must not end with a trailing slash "/"';
418
426
  },
419
427
  disableCache: (v) => {
420
428
  if (typeof v !== 'boolean')
421
429
  throw `Invalid value supplied to disableCache, value must be a boolean`;
422
430
  },
423
- accessKey: (v) => {
424
- if (typeof v !== 'string' || !v.trim())
425
- throw `Invalid value supplied to accessKey, value must be a non-empty string`;
426
- },
427
431
  maxRetries: (v) => {
428
432
  if (v <= 0 || !Validator.POSITIVE_INTEGER(v))
429
433
  throw `Invalid value supplied to maxRetries, value must be positive integer greater than zero`;
@@ -446,7 +450,7 @@ const validator = {
446
450
  },
447
451
  extraHeaders: v => {
448
452
  if (!Validator.OBJECT(v)) throw '"extraHeaders" must be an object';
449
- const reservedHeaders = ['mtoken', 'mosquito-token', 'init-content-type', 'content-type', 'authorization', 'uglified'];
453
+ const reservedHeaders = ['mtoken', 'mosquito-token', 'init-content-type', 'content-type', 'uglified', 'entity-encoded'];
450
454
 
451
455
  Object.entries(v).forEach(([k, v]) => {
452
456
  if (typeof v !== 'string') throw `expected a string at extraHeaders.${k} but got "${v}"`;
@@ -461,19 +465,19 @@ const validateMTConfig = (config, that) => {
461
465
  throw `${that.constructor.name} config is not an object`;
462
466
 
463
467
  for (const [k, v] of Object.entries(config)) {
464
- if (!validator[k]) throw `Unexpected property named ${k}`;
465
- validator[k](v);
468
+ if (!ConfigValidator[k]) throw `Unexpected property named ${k}`;
469
+ ConfigValidator[k](v);
466
470
  }
467
471
 
468
472
  if (config.enableE2E_Encryption && !config.serverE2E_PublicKey)
469
473
  throw '"serverE2E_PublicKey" is missing, enabling end-to-end encryption requires a public encryption key from the server';
470
474
  if (!config.projectUrl) throw `projectUrl is a required property in ${that.constructor.name}() constructor`;
471
- if (!config.accessKey) throw `accessKey is a required property in ${that.constructor.name}() constructor`;
472
475
  }
473
476
 
474
477
  export {
475
478
  DoNotEncrypt,
476
479
  TIMESTAMP,
480
+ TIMESTAMP_OFFSET,
477
481
  DOCUMENT_EXTRACTION,
478
482
  FIND_GEO_JSON,
479
483
  GEO_JSON,
@@ -1,4 +1,4 @@
1
- import cloneDeep from "lodash.clonedeep";
1
+ import cloneDeep from "lodash/cloneDeep";
2
2
  import { doSignOut, revokeAuthIntance } from ".";
3
3
  import EngineApi from "../../helpers/engine_api";
4
4
  import { AuthTokenListener, TokenRefreshListener } from "../../helpers/listeners";
@@ -20,10 +20,10 @@ export const injectFreshToken = async (config, { token, refreshToken }) => {
20
20
  await awaitStore();
21
21
  CacheStore.AuthStore[projectUrl] = { token, refreshToken };
22
22
  Scoped.AuthJWTToken[projectUrl] = token;
23
- if (projectUrl in CacheStore.EmulatedAuth)
24
- delete CacheStore.EmulatedAuth[projectUrl];
23
+ const isEmulated = projectUrl in CacheStore.EmulatedAuth;
24
+ if (isEmulated) delete CacheStore.EmulatedAuth[projectUrl];
25
25
 
26
- updateCacheStore(0);
26
+ updateCacheStore(0, ['AuthStore', isEmulated ? 'EmulatedAuth' : ''].filter(v => v));
27
27
 
28
28
  triggerAuthToken(projectUrl);
29
29
  initTokenRefresher(config);
@@ -47,7 +47,7 @@ export const injectEmulatedAuth = async (config, emulatedURL) => {
47
47
  Scoped.AuthJWTToken[projectUrl] = token;
48
48
  CacheStore.EmulatedAuth[projectUrl] = emulatedURL;
49
49
 
50
- updateCacheStore(0);
50
+ updateCacheStore(0, ['AuthStore', 'EmulatedAuth']);
51
51
  triggerAuthToken(projectUrl);
52
52
  initTokenRefresher(config);
53
53
  };
@@ -90,7 +90,7 @@ export const initTokenRefresher = async (config, forceRefresh) => {
90
90
  if (token) {
91
91
  const expireOn = (tokenInfo.exp * 1000) - 60000;
92
92
  const hasExpire = getPrefferTime() >= expireOn;
93
- const rizz = () => refreshToken(config, ++Scoped.LastTokenRefreshRef[projectUrl], maxRetries, maxRetries, forceRefresh);
93
+ const rizz = () => refreshToken(config, ++Scoped.LastTokenRefreshRef[projectUrl], maxRetries, forceRefresh);
94
94
 
95
95
  if (hasExpire || forceRefresh) {
96
96
  notifyAuthReady();
@@ -117,8 +117,8 @@ export const getEmulatedLinks = (projectUrl) => Object.entries(CacheStore.Emulat
117
117
  .filter(([_, v]) => v === projectUrl)
118
118
  .map(v => v[0]);
119
119
 
120
- const refreshToken = (builder, processRef, remainRetries = 7, initialRetries = 7, isForceRefresh) => new Promise(async (resolve, reject) => {
121
- const { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders } = builder;
120
+ const refreshToken = (builder, processRef, remainRetries = 1, isForceRefresh) => new Promise(async (resolve, reject) => {
121
+ const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
122
122
  const lostProcess = simplifyError('process_lost', 'The token refresh process has been lost and replaced with another one');
123
123
 
124
124
  try {
@@ -126,7 +126,6 @@ const refreshToken = (builder, processRef, remainRetries = 7, initialRetries = 7
126
126
 
127
127
  const [reqBuilder, [privateKey]] = await buildFetchInterface({
128
128
  body: { token, r_token },
129
- accessKey,
130
129
  uglify,
131
130
  serverE2E_PublicKey,
132
131
  extraHeaders
@@ -162,7 +161,7 @@ const refreshToken = (builder, processRef, remainRetries = 7, initialRetries = 7
162
161
  triggerAuthToken(v, isInit);
163
162
  if (isForceRefresh) Scoped.InitiatedForcedToken[v] = true;
164
163
  });
165
- updateCacheStore();
164
+ updateCacheStore(0, ['AuthStore']);
166
165
  initTokenRefresher(builder);
167
166
  } else reject(lostProcess.simpleError);
168
167
  } catch (e) {
@@ -184,7 +183,7 @@ const refreshToken = (builder, processRef, remainRetries = 7, initialRetries = 7
184
183
  l();
185
184
  } else if (c) {
186
185
  l();
187
- refreshToken(builder, processRef, remainRetries - 1, initialRetries, isForceRefresh).then(resolve, reject);
186
+ refreshToken(builder, processRef, remainRetries - 1, isForceRefresh).then(resolve, reject);
188
187
  }
189
188
  }, projectUrl);
190
189
  }
@@ -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 cloneDeep from "lodash/cloneDeep";
10
10
 
11
11
  const {
12
12
  _listenUserVerification,
@@ -48,7 +48,6 @@ export default class MTAuth {
48
48
  const { projectUrl, serverE2E_PublicKey, uglify, baseUrl, wsPrefix } = this.builder;
49
49
 
50
50
  let socket,
51
- wasDisconnected,
52
51
  hasCancelled,
53
52
  lastToken = Scoped.AuthJWTToken[projectUrl] || null,
54
53
  lastInitRef = 0;
@@ -67,14 +66,13 @@ export default class MTAuth {
67
66
 
68
67
  socket = io(`${wsPrefix}://${baseUrl}`, {
69
68
  transports: ['websocket', 'polling', 'flashsocket'],
70
- auth: uglify ? {
71
- e2e: reqBuilder.toString('base64'),
72
- _m_internal: true
73
- } : { mtoken, _m_internal: true }
69
+ auth: {
70
+ ...uglify ? { e2e: reqBuilder.toString('base64') } : { mtoken },
71
+ _m_internal: true,
72
+ _m_route: _listenUserVerification(uglify)
73
+ }
74
74
  });
75
75
 
76
- socket.emit(_listenUserVerification(uglify));
77
-
78
76
  socket.on("onVerificationChanged", async ([err, verified]) => {
79
77
  if (err) {
80
78
  onError?.(simplifyCaughtError(err).simpleError);
@@ -82,14 +80,6 @@ export default class MTAuth {
82
80
  callback?.(uglify ? await deserializeE2E(verified, serverE2E_PublicKey, privateKey) : verified);
83
81
  }
84
82
  });
85
-
86
- socket.on('connect', () => {
87
- if (wasDisconnected) socket.emit(_listenUserVerification(uglify));
88
- });
89
-
90
- socket.on('disconnect', () => {
91
- wasDisconnected = true;
92
- });
93
83
  };
94
84
 
95
85
  init();
@@ -97,7 +87,6 @@ export default class MTAuth {
97
87
  const tokenListener = listenToken(t => {
98
88
  if ((t || null) !== lastToken) {
99
89
  socket?.close?.();
100
- wasDisconnected = undefined;
101
90
  init();
102
91
  }
103
92
  lastToken = t;
@@ -178,7 +167,7 @@ export default class MTAuth {
178
167
  };
179
168
 
180
169
  const doCustomSignin = (builder, email, password) => new Promise(async (resolve, reject) => {
181
- const { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders } = builder;
170
+ const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
182
171
 
183
172
  try {
184
173
  await awaitStore();
@@ -186,7 +175,6 @@ const doCustomSignin = (builder, email, password) => new Promise(async (resolve,
186
175
 
187
176
  const [reqBuilder, [privateKey]] = await buildFetchInterface({
188
177
  body: { data: `${encodeBinary(email)}.${encodeBinary(password)}` },
189
- accessKey,
190
178
  serverE2E_PublicKey,
191
179
  uglify,
192
180
  extraHeaders
@@ -209,7 +197,7 @@ const doCustomSignin = (builder, email, password) => new Promise(async (resolve,
209
197
  });
210
198
 
211
199
  const doCustomSignup = (builder, email, password, name, metadata) => new Promise(async (resolve, reject) => {
212
- const { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders } = builder;
200
+ const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
213
201
 
214
202
  try {
215
203
  await awaitStore();
@@ -220,7 +208,6 @@ const doCustomSignup = (builder, email, password, name, metadata) => new Promise
220
208
  data: `${encodeBinary(email)}.${encodeBinary(password)}.${(encodeBinary((name || '').trim()))}`,
221
209
  metadata,
222
210
  },
223
- accessKey,
224
211
  serverE2E_PublicKey,
225
212
  uglify,
226
213
  extraHeaders
@@ -269,13 +256,13 @@ export const doSignOut = async (builder) => {
269
256
  const emulatedURL = CacheStore.EmulatedAuth[builder.projectUrl];
270
257
 
271
258
  clearCacheForSignout(builder, !emulatedURL);
272
- updateCacheStore(0);
259
+ updateCacheStore(0, ['AuthStore', 'EmulatedAuth']);
273
260
  if (emulatedURL) return;
274
261
  await revokeAuthIntance(builder);
275
262
  };
276
263
 
277
264
  export const revokeAuthIntance = async (builder, authStore) => {
278
- const { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders } = builder;
265
+ const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
279
266
  const { token, refreshToken: r_token } = { ...authStore };
280
267
 
281
268
  if (!r_token || CacheStore.EmulatedAuth[projectUrl]) return;
@@ -283,7 +270,7 @@ export const revokeAuthIntance = async (builder, authStore) => {
283
270
 
284
271
  CacheStore.PendingAuthPurge[nodeId] = {
285
272
  auth: { token, refreshToken: r_token },
286
- data: { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders }
273
+ data: { projectUrl, serverE2E_PublicKey, uglify, extraHeaders }
287
274
  };
288
275
  await purgePendingToken(nodeId);
289
276
  };
@@ -291,7 +278,7 @@ export const revokeAuthIntance = async (builder, authStore) => {
291
278
  export const purgePendingToken = async (nodeId) => {
292
279
  const {
293
280
  auth: { token, refreshToken: r_token },
294
- data: { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders }
281
+ data: { projectUrl, serverE2E_PublicKey, uglify, extraHeaders }
295
282
  } = CacheStore.PendingAuthPurge[nodeId];
296
283
 
297
284
  if (!token) return;
@@ -306,7 +293,6 @@ export const purgePendingToken = async (nodeId) => {
306
293
 
307
294
  const [reqBuilder] = await buildFetchInterface({
308
295
  body: { token, r_token },
309
- accessKey,
310
296
  uglify,
311
297
  serverE2E_PublicKey,
312
298
  extraHeaders
@@ -322,7 +308,7 @@ export const purgePendingToken = async (nodeId) => {
322
308
  };
323
309
 
324
310
  const doGoogleSignin = (builder, token) => new Promise(async (resolve, reject) => {
325
- const { projectUrl, serverE2E_PublicKey, accessKey, uglify, extraHeaders } = builder;
311
+ const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
326
312
 
327
313
  try {
328
314
  await awaitStore();
@@ -330,7 +316,6 @@ const doGoogleSignin = (builder, token) => new Promise(async (resolve, reject) =
330
316
 
331
317
  const [reqBuilder, [privateKey]] = await buildFetchInterface({
332
318
  body: { token },
333
- accessKey,
334
319
  uglify,
335
320
  serverE2E_PublicKey,
336
321
  extraHeaders