react-native-mosquito-transport 0.0.19 → 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.
@@ -0,0 +1,264 @@
1
+ import { openDB, SQLITE_COMMANDS, SQLITE_PATH } from "./sqlite_manager";
2
+ import { Validator } from "guard-object";
3
+ import { incrementDatabaseSizeCore } from "../products/database/counter";
4
+ import { incrementFetcherSizeCore } from "../products/http_callable/counter";
5
+ import unsetLodash from 'lodash/unset';
6
+
7
+ const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY, FETCH_RESOURCES } = SQLITE_PATH;
8
+
9
+ export const purgeRedundantRecords = async (data, builder) => {
10
+ const { io, maxLocalDatabaseSize = 10485760, maxLocalFetchHttpSize = 10485760 } = builder;
11
+
12
+ /**
13
+ * @type {import('./variables')['CacheStore']['DatabaseStats']}
14
+ */
15
+ const { _db_size, _fetcher_size, counters, database, fetchers } = data.DatabaseStats || {};
16
+
17
+ if (io) {
18
+ const purgeDatabase = () => {
19
+ if (!Validator.POSITIVE_NUMBER(_db_size) || !maxLocalDatabaseSize || _db_size < maxLocalDatabaseSize) return;
20
+ const DbListing = [];
21
+
22
+ breakDbMap(data.DatabaseStore, (projectUrl, dbUrl, dbName, path, value) => {
23
+ Object.entries(value.instance).forEach(([access_id, obj]) => {
24
+ DbListing.push({
25
+ builder: { projectUrl, dbUrl, dbName },
26
+ path,
27
+ access_id,
28
+ value: obj
29
+ });
30
+ });
31
+ Object.entries(value.episode).forEach(([access_id, limitObj]) => {
32
+ Object.entries(limitObj).forEach(([limit, obj]) => {
33
+ DbListing.push({
34
+ builder: { projectUrl, dbUrl, dbName },
35
+ path,
36
+ access_id,
37
+ limit,
38
+ value: obj,
39
+ isEpisode: true
40
+ });
41
+ });
42
+ });
43
+ });
44
+
45
+ breakDbMap(data.DatabaseCountResult, (projectUrl, dbUrl, dbName, path, value) => {
46
+ Object.entries(value).forEach(([access_id, obj]) => {
47
+ DbListing.push({
48
+ builder: { projectUrl, dbUrl, dbName },
49
+ path,
50
+ access_id,
51
+ value: obj,
52
+ isCount: true
53
+ });
54
+ });
55
+ });
56
+
57
+ const redundantDbRanking = DbListing.sort((a, b) =>
58
+ a.value.touched - b.value.touched
59
+ );
60
+
61
+ const newSize = maxLocalDatabaseSize / 2;
62
+ let sizer = _db_size;
63
+ let cuts = 0;
64
+
65
+ for (let i = 0; i < redundantDbRanking.length; i++) {
66
+ sizer -= redundantDbRanking[i].value.size || 0;
67
+ ++cuts;
68
+ if (sizer < newSize) break;
69
+ }
70
+
71
+ console.warn(`purging ${cuts} of ${redundantDbRanking.length} db entities`);
72
+ redundantDbRanking.slice(0, cuts).forEach(({
73
+ builder,
74
+ path,
75
+ access_id,
76
+ isCount,
77
+ isEpisode,
78
+ limit,
79
+ value: { size }
80
+ }) => {
81
+ const { projectUrl, dbUrl, dbName } = builder;
82
+ if (isCount) {
83
+ unsetLodash(data.DatabaseCountResult, [projectUrl, dbUrl, dbName, path, access_id]);
84
+ } else {
85
+ incrementDatabaseSizeCore(data.DatabaseStats, builder, path, -size);
86
+ if (isEpisode) {
87
+ unsetLodash(data.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'episode', access_id, limit]);
88
+ } else {
89
+ unsetLodash(data.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', access_id]);
90
+ }
91
+ }
92
+ });
93
+ }
94
+ const purgeFetcher = () => {
95
+ if (!Validator.POSITIVE_NUMBER(_fetcher_size) || !maxLocalFetchHttpSize || _fetcher_size < maxLocalFetchHttpSize) return;
96
+ const redundantFetchRanking = Object.entries(data.FetchedStore).map(([projectUrl, access_id_Obj]) =>
97
+ Object.entries(access_id_Obj).map(([access_id, data]) => ({
98
+ access_id,
99
+ projectUrl,
100
+ data
101
+ }))
102
+ ).flat().sort(([a], [b]) =>
103
+ a.data.touched - b.data.touched
104
+ );
105
+
106
+ const newSize = maxLocalFetchHttpSize / 2;
107
+ let sizer = _fetcher_size;
108
+ let cuts = 0;
109
+
110
+ for (let i = 0; i < redundantFetchRanking.length; i++) {
111
+ sizer -= redundantFetchRanking[i].data.size || 0;
112
+ ++cuts;
113
+ if (sizer < newSize) break;
114
+ }
115
+
116
+ console.warn(`purging ${cuts} of ${redundantFetchRanking.length} fetcher entities`);
117
+ redundantFetchRanking.slice(0, cuts).forEach(({ access_id, data: { size }, projectUrl }) => {
118
+ incrementFetcherSizeCore(data.DatabaseStats, projectUrl, -size);
119
+ unsetLodash(data.FetchedStore, [projectUrl, access_id]);
120
+ });
121
+ console.log('fetcher purging complete');
122
+ }
123
+ purgeDatabase();
124
+ purgeFetcher();
125
+ } else {
126
+ // purge redundant data
127
+ await Promise.allSettled([
128
+ (async () => {
129
+ try {
130
+ if (!Validator.POSITIVE_NUMBER(_db_size) || !maxLocalDatabaseSize || _db_size < maxLocalDatabaseSize) return;
131
+ const instances = [];
132
+
133
+ [database, counters].forEach((map, i) => {
134
+ breakDbMap(map, (projectUrl, dbUrl, dbName, path) => {
135
+ instances.push({
136
+ builder: { projectUrl, dbUrl, dbName },
137
+ isCounter: !!i,
138
+ path
139
+ });
140
+ });
141
+ });
142
+
143
+ const redundantDbRanking = await Promise.all(
144
+ instances.map(async obj => {
145
+ const { builder, isCounter, path } = obj;
146
+
147
+ const sqlite = await openDB(builder);
148
+
149
+ try {
150
+ if (isCounter) {
151
+ const data = await sqlite.executeSql(`SELECT * FROM ${DB_COUNT_QUERY(path)}`).then(r =>
152
+ r[0].rows.raw()
153
+ );
154
+ return data.map(v => [v, obj]);
155
+ }
156
+
157
+ const [instanceData, resultData] = await Promise.all([
158
+ sqlite.executeSql(`SELECT access_id, touched, size FROM ${LIMITER_DATA(path)}`),
159
+ sqlite.executeSql(`SELECT access_id-limit, touched, size FROM ${LIMITER_RESULT(path)}`)
160
+ ]).then(r =>
161
+ r.map(v => v[0].rows.raw())
162
+ );
163
+ return [...instanceData, ...resultData].map(v => [v, obj]);
164
+ } catch (error) {
165
+ console.error('redundantDbRanking err:', error);
166
+ return [];
167
+ } finally {
168
+ sqlite.close();
169
+ }
170
+ })
171
+ ).then(r =>
172
+ r.flat().sort(([a], [b]) =>
173
+ a.touched - b.touched
174
+ )
175
+ );
176
+ const newSize = maxLocalDatabaseSize / 2;
177
+ let sizer = _db_size;
178
+ let cuts = 0;
179
+
180
+ for (let i = 0; i < redundantDbRanking.length; i++) {
181
+ sizer -= redundantDbRanking[i][0].size || 0;
182
+ ++cuts;
183
+ if (sizer < newSize) break;
184
+ }
185
+
186
+ console.warn(`purging ${cuts} of ${redundantDbRanking.length} db entities`);
187
+ await Promise.all(redundantDbRanking.slice(0, cuts).map(async ([v, { builder, isCounter, path }]) => {
188
+ const sqlite = await openDB(builder);
189
+ try {
190
+ const table = (isCounter ? DB_COUNT_QUERY : 'access_id-limit' in v ? LIMITER_RESULT : LIMITER_DATA)(path);
191
+ const id_field = 'access_id-limit' in v ? 'access_id-limit' : 'access_id';
192
+
193
+ await sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW(table, `${id_field} = ?`), [v[id_field]]);
194
+ if (!isCounter) incrementDatabaseSizeCore(data.DatabaseStats, builder, path, -v.size);
195
+ } catch (error) {
196
+ console.log('db redundantClearing err:', error);
197
+ }
198
+ sqlite.close();
199
+ }));
200
+ console.log('database purging complete');
201
+ } catch (error) {
202
+ console.error('database purging err:', error);
203
+ }
204
+ })(),
205
+ (async () => {
206
+ try {
207
+ if (!Validator.POSITIVE_NUMBER(_fetcher_size) || !maxLocalFetchHttpSize || _fetcher_size < maxLocalFetchHttpSize) return;
208
+
209
+ const redundantFetchRanking = await Promise.all(Object.entries(fetchers).map(async ([projectUrl]) => {
210
+ const sqlite = await openDB(FETCH_RESOURCES(projectUrl));
211
+ const data = await sqlite.executeSql('SELECT access_id, touched, size FROM main').then(r =>
212
+ r[0].rows.raw()
213
+ );
214
+ return data.map(v => [v, projectUrl]);
215
+ })).then(r =>
216
+ r.flat().sort(([a], [b]) =>
217
+ a.touched - b.touched
218
+ )
219
+ );
220
+
221
+ const newSize = maxLocalFetchHttpSize / 2;
222
+ let sizer = _fetcher_size;
223
+ let cuts = 0;
224
+
225
+ for (let i = 0; i < redundantFetchRanking.length; i++) {
226
+ sizer -= redundantFetchRanking[i][0].size || 0;
227
+ ++cuts;
228
+ if (sizer < newSize) break;
229
+ }
230
+
231
+ console.warn(`purging ${cuts} of ${redundantFetchRanking.length} fetcher entities`);
232
+ await Promise.all(redundantFetchRanking.slice(0, cuts).map(async ([v, projectUrl]) => {
233
+ const sqlite = await openDB(FETCH_RESOURCES(projectUrl));
234
+ try {
235
+ await sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW('main', 'access_id = ?'), [v.access_id]);
236
+ incrementFetcherSizeCore(data.DatabaseStats, projectUrl, -v.size);
237
+ } catch (error) {
238
+ console.log('fetcher redundantClearing err:', error);
239
+ }
240
+ sqlite.close();
241
+ }));
242
+ console.log('fetcher purging complete');
243
+ } catch (error) {
244
+ console.error('fetcher purging err:', error);
245
+ }
246
+ })()
247
+ ]);
248
+ }
249
+ }
250
+
251
+ const breakDbMap = (obj, callback) =>
252
+ Object.entries(obj).forEach(([projectUrl, dbUrlObj]) => {
253
+ Object.entries(dbUrlObj).forEach(([dbUrl, dbNameObj]) => {
254
+ Object.entries(dbNameObj).forEach(([dbName, pathObj]) => {
255
+ Object.entries(pathObj).forEach(([path, value]) => {
256
+ callback(projectUrl, dbUrl, dbName, path, value);
257
+ });
258
+ });
259
+ });
260
+ });
261
+
262
+ export const purgeInstance = (projectUrl) => {
263
+ // TODO: purge when signed-out
264
+ }
@@ -0,0 +1,138 @@
1
+ import { enablePromise, openDatabase } from 'react-native-sqlite-storage';
2
+ import { Scoped, SqliteCollective } from './variables';
3
+ import { niceHash } from './peripherals';
4
+
5
+ enablePromise(true);
6
+
7
+ /**
8
+ * this method implement a centralize approach for opening and closing of sqlite database to ensure consistency across multiple task opening and closing the database in diferent order
9
+ *
10
+ * @param {string} name
11
+ * @returns {Promise<import('react-native-sqlite-storage').SQLiteDatabase>}
12
+ */
13
+ export const openDB = async (name) => {
14
+
15
+ if (name?.projectUrl) {
16
+ const { projectUrl, dbUrl, dbName } = name;
17
+ name = encodeURIComponent(`${projectUrl}_${dbUrl}_${dbName}`) + '.db';
18
+ }
19
+
20
+ const { sqliteKey } = Scoped.ReleaseCacheData;
21
+
22
+ if (sqliteKey) name = `${niceHash(sqliteKey)}__${name}`;
23
+
24
+ if (!SqliteCollective.openedDb[name]) {
25
+ SqliteCollective.openedDbProcess[name] = 0;
26
+ SqliteCollective.openedDb[name] = (SqliteCollective.closeDbPromises[name] || Promise.resolve()).finally(() =>
27
+ openDatabase({
28
+ location: 'default',
29
+ name,
30
+ key: sqliteKey
31
+ }).then(db => {
32
+ const prevClose = db.close.bind(db);
33
+
34
+ db.close = () => new Promise((resolve, reject) => {
35
+ if (--SqliteCollective.openedDbProcess[name] === 0) {
36
+ let willClose;
37
+ const timer = setTimeout(async () => {
38
+ willClose = true;
39
+ delete SqliteCollective.openedDb[name];
40
+ delete SqliteCollective.openedDbProcess[name];
41
+ SqliteCollective.closeDbPromises[name] = prevClose().then(() => {
42
+ resolve('active');
43
+ }).catch(e => {
44
+ reject(new Error(`${e}`));
45
+ }).finally(() => {
46
+ delete SqliteCollective.closeDbPromises[name];
47
+ });
48
+ delete SqliteCollective.openedDbReducerTimer[name];
49
+ }, 7);
50
+
51
+ SqliteCollective.openedDbReducerTimer[name] = () => {
52
+ clearTimeout(timer);
53
+ if (!willClose) resolve('passive');
54
+ delete SqliteCollective.openedDbReducerTimer[name];
55
+ }
56
+ } else resolve('passive');
57
+ });
58
+ return db;
59
+ })
60
+ );
61
+ }
62
+
63
+ SqliteCollective.openedDbReducerTimer[name]?.();
64
+ ++SqliteCollective.openedDbProcess[name];
65
+ const thisDb = await SqliteCollective.openedDb[name];
66
+ let hasClosed;
67
+
68
+ const thisClose = async () => {
69
+ if (hasClosed) return;
70
+ hasClosed = true;
71
+ return (await thisDb.close());
72
+ }
73
+
74
+ return new Proxy({}, {
75
+ get: (_, n) => {
76
+ if (n === 'close') {
77
+ return thisClose;
78
+ } else if (typeof thisDb[n] === 'function')
79
+ return thisDb[n].bind(thisDb);
80
+ return thisDb[n];
81
+ },
82
+ set: (_, n, v) => {
83
+ thisDb[n] = v;
84
+ }
85
+ });
86
+ };
87
+
88
+ /**
89
+ * this method linearize read/write on sqlite ensuring consistency across concurrent operations
90
+ *
91
+ * @param {any} builder
92
+ * @param {string} access_id
93
+ * @param {'database' | 'dbQueryCount' | 'httpFetch'} node
94
+ * @returns {(task: (sqlite: import("react-native-sqlite-storage").SQLiteDatabase) => Promise<{any}> )=> Promise<{any}>}
95
+ */
96
+ export const useSqliteLinearAccessId = (builder, access_id, node) => async (task) => {
97
+ const { projectUrl, dbUrl, dbName } = builder;
98
+ const nodeId = typeof builder === 'string' ? `${builder}_${access_id}` : `${projectUrl}_${dbUrl}_${dbName}_${access_id}`;
99
+
100
+ const sqlite = await openDB(builder);
101
+
102
+ const thatProcess = Scoped.linearSqliteProcess[node][nodeId];
103
+
104
+ const thisPromise = new Promise(async (resolve, reject) => {
105
+ try {
106
+ if (thatProcess !== undefined) await thatProcess;
107
+ } catch (_) { }
108
+ try {
109
+ resolve(await task(sqlite));
110
+ } catch (error) {
111
+ console.error('useSqliteLinearAccessId err:', error);
112
+ reject(error);
113
+ } finally {
114
+ if (Scoped.linearSqliteProcess[node][nodeId] === thisPromise)
115
+ delete Scoped.linearSqliteProcess[node][nodeId];
116
+ sqlite.close();
117
+ }
118
+ });
119
+
120
+ Scoped.linearSqliteProcess[node][nodeId] = thisPromise;
121
+ return (await thisPromise);
122
+ };
123
+
124
+ export const SQLITE_PATH = {
125
+ FILE_NAME: 'MOSQUITO_TRANSPORT.db',
126
+ TABLE_NAME: 'MT_MAIN',
127
+ LIMITER_RESULT: path => `"${encodeURIComponent(path)}-LIMITER_RESULT"`,
128
+ LIMITER_DATA: path => `"${encodeURIComponent(path)}-LIMITER_DATA"`,
129
+ DB_COUNT_QUERY: path => `"${encodeURIComponent(path)}-DB_COUNT_QUERY"`,
130
+ FETCH_RESOURCES: projectUrl => `FETCH_RESOURCES-${encodeURIComponent(projectUrl)}.db`
131
+ };
132
+
133
+ export const SQLITE_COMMANDS = {
134
+ MERGE: (table, columns = []) => `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${columns.map(() => '?').join(', ')}) ON CONFLICT(${columns[0]}) DO UPDATE SET ${columns.slice(1).map(v => `${v} = excluded.${v}`).join(', ')}`,
135
+ UPDATE_COLUMNS: (table, columns = [], query = '') => `UPDATE ${table} SET ${columns.map(v => `${v} = ?`).join(', ')} WHERE ${query}`,
136
+ CREATE_INDEX: (table, columns) => `CREATE INDEX idx_${columns.join('_')} ON ${table}(${columns.join(', ')})`,
137
+ DELETE_ROW: (table, query) => `DELETE FROM ${table} WHERE ${query}`
138
+ }
@@ -1,57 +1,103 @@
1
- import AsyncStorage from "@react-native-async-storage/async-storage";
2
1
  import { ServerReachableListener, StoreReadyListener } from "./listeners";
3
- import { CACHE_PROTOCOL, CACHE_STORAGE_PATH, DEFAULT_CACHE_PASSWORD, LOCAL_STORAGE_PATH } from "./values";
4
2
  import { CacheStore, Scoped } from "./variables";
5
- import { decryptString, encryptString, niceTry, serializeE2E } from "./peripherals";
3
+ import { serializeE2E } from "./peripherals";
4
+ import { deserializeBSON, serializeToBase64 } from "../products/database/bson";
5
+ import { trySendPendingWrite } from "../products/database";
6
+ import { deserialize } from "entity-serializer";
7
+ import { openDB, SQLITE_COMMANDS, SQLITE_PATH } from "./sqlite_manager";
8
+ import { purgeRedundantRecords } from "./purger";
6
9
 
7
- export const updateCacheStore = () => {
8
- const { cachePassword = DEFAULT_CACHE_PASSWORD, cacheProtocol = CACHE_PROTOCOL.ASYNC_STORAGE, io } = Scoped.ReleaseCacheData;
10
+ const { FILE_NAME, TABLE_NAME } = SQLITE_PATH;
9
11
 
10
- clearTimeout(Scoped.cacheStorageReducer);
11
- Scoped.cacheStorageReducer = setTimeout(() => {
12
- const txt = encryptString(
13
- JSON.stringify({ ...CacheStore }),
14
- cachePassword,
15
- cachePassword
16
- );
12
+ const CacheKeys = Object.keys(CacheStore);
13
+
14
+ export const updateCacheStore = (timer = 300, node) => {
15
+ const { io, promoteCache } = Scoped.ReleaseCacheData;
16
+
17
+ const doUpdate = async () => {
18
+ const {
19
+ AuthStore,
20
+ EmulatedAuth,
21
+ PendingAuthPurge,
22
+ DatabaseStore,
23
+ PendingWrites,
24
+ ...restStore
25
+ } = CacheStore;
17
26
 
18
27
  if (io) {
19
- io.output(txt);
20
- } else if (cacheProtocol === CACHE_PROTOCOL.ASYNC_STORAGE) {
21
- AsyncStorage.setItem(CACHE_STORAGE_PATH, txt);
28
+ const txt = JSON.stringify({
29
+ AuthStore,
30
+ EmulatedAuth,
31
+ PendingAuthPurge,
32
+ ...promoteCache ? {
33
+ DatabaseStore: serializeToBase64(DatabaseStore),
34
+ PendingWrites: serializeToBase64(PendingWrites)
35
+ } : {},
36
+ ...promoteCache ? restStore : {}
37
+ });
38
+
39
+ io.output(txt, node);
22
40
  } else {
23
- const fs = require('react-native-fs');
24
- fs.writeFile(LOCAL_STORAGE_PATH(), txt, 'utf8');
41
+ // use sqlite
42
+ const exclusion = ['DatabaseStore', 'DatabaseCountResult', 'FetchedStore'];
43
+ const updationKey = (node ? Array.isArray(node) ? node : [node] : CacheKeys).filter(v => !exclusion.includes(v));
44
+
45
+ if (!updationKey.length) return;
46
+ const sqlite = await openDB(FILE_NAME);
47
+ await Promise.allSettled(
48
+ updationKey
49
+ .map(v => [v, v === 'PendingWrites' ? serializeToBase64(CacheStore[v]) : CacheStore[v]])
50
+ .map(([ref, value]) =>
51
+ sqlite.executeSql(SQLITE_COMMANDS.MERGE(TABLE_NAME, ['ref', 'value']), [ref, JSON.stringify(value)])
52
+ )
53
+ );
54
+ sqlite.close();
25
55
  }
26
- }, 500);
27
- }
56
+ };
57
+
58
+ clearTimeout(Scoped.cacheStorageReducer);
59
+ if (timer) {
60
+ Scoped.cacheStorageReducer = setTimeout(doUpdate, timer);
61
+ } else doUpdate();
62
+ };
28
63
 
29
64
  export const releaseCacheStore = async (builder) => {
30
- const { cachePassword = DEFAULT_CACHE_PASSWORD, cacheProtocol = CACHE_PROTOCOL.ASYNC_STORAGE, io } = builder;
65
+ const { io } = builder;
31
66
 
32
- let txt;
67
+ let data = {};
33
68
 
34
- if (io) {
35
- txt = await io.input();
36
- } else if (cacheProtocol === CACHE_PROTOCOL.ASYNC_STORAGE) {
37
- txt = await niceTry(() => AsyncStorage.getItem(CACHE_STORAGE_PATH));
38
- } else {
39
- const fs = require('react-native-fs');
40
- txt = await niceTry(() => fs.readFile(LOCAL_STORAGE_PATH(), 'utf8'));
69
+ try {
70
+ if (io) {
71
+ data = JSON.parse((await io.input()) || '{}');
72
+ } else {
73
+ const sqlite = await openDB(FILE_NAME);
74
+ await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} ( ref TEXT PRIMARY KEY, value TEXT )`).catch(() => null);
75
+ const [query] = await sqlite.executeSql(`SELECT * FROM ${TABLE_NAME}`);
76
+ data = Object.fromEntries(query.rows.raw().map(v => [v.ref, JSON.parse(v.value)]));
77
+ sqlite.close();
78
+ }
79
+ await purgeRedundantRecords(data, builder);
80
+ } catch (e) {
81
+ console.error('releaseCacheStore data err:', e);
41
82
  }
42
83
 
43
- const j = JSON.parse(decryptString(txt || '', cachePassword, cachePassword) || '{}');
44
-
45
- Object.entries(j).forEach(([k, v]) => {
46
- CacheStore[k] = v;
84
+ Object.entries(data).forEach(([k, v]) => {
85
+ if (['DatabaseStore', 'PendingWrites'].includes(k)) {
86
+ CacheStore[k] = deserializeBSON(v);
87
+ } else CacheStore[k] = v;
47
88
  });
48
89
  Object.entries(CacheStore.AuthStore).forEach(([key, value]) => {
49
90
  Scoped.AuthJWTToken[key] = value?.token;
50
91
  });
92
+ Object.keys(CacheStore.PendingWrites).forEach(projectUrl => {
93
+ if (Scoped.IS_CONNECTED[projectUrl])
94
+ trySendPendingWrite(projectUrl);
95
+ });
51
96
  Scoped.IsStoreReady = true;
52
97
  StoreReadyListener.dispatch('_', 'ready');
53
- // TODO: commit pending write
54
- }
98
+ };
99
+
100
+ export const getPrefferTime = () => Date.now() + (Scoped.serverTimeOffset || 0);
55
101
 
56
102
  export const awaitStore = () => new Promise(resolve => {
57
103
  if (Scoped.IsStoreReady) {
@@ -92,26 +138,29 @@ export const getReachableServer = (projectUrl) => new Promise(resolve => {
92
138
  }, true);
93
139
  });
94
140
 
95
- export const buildFetchInterface = ({ body, accessKey, authToken, method, uglify, serverE2E_PublicKey }) => {
141
+ export const buildFetchInterface = async ({ body, authToken, method, uglify, serverE2E_PublicKey, extraHeaders }) => {
96
142
  if (!uglify) body = JSON.stringify({ ...body });
97
- const [plate, keyPair] = uglify ? serializeE2E(body, authToken, serverE2E_PublicKey) : [undefined, []];
143
+ const [plate, keyPair] = uglify ? await serializeE2E(body, authToken, serverE2E_PublicKey) : [undefined, []];
98
144
 
99
145
  return [{
100
146
  body: uglify ? plate : body,
101
- cache: 'no-cache',
147
+ // cache: 'no-cache',
102
148
  headers: {
103
- 'Content-type': uglify ? 'text/plain' : 'application/json',
104
- 'Authorization': accessKey,
105
- ...((authToken && !uglify) ? { 'Mosquito-Token': authToken } : {})
149
+ ...extraHeaders,
150
+ 'Content-type': uglify ? 'request/buffer' : 'application/json',
151
+ ...(authToken && !uglify) ? { 'Mosquito-Token': authToken } : {}
106
152
  },
107
153
  method: method || 'POST'
108
154
  }, keyPair];
109
155
  };
110
156
 
111
- export const simplifyError = (error, message) => ({
112
- simpleError: { error, message }
113
- });
114
-
115
- export const validateRequestMethod = (method) => {
116
- // TODO:
117
- }
157
+ export const buildFetchResult = async (fetchRef, ugly) => {
158
+ if (ugly) {
159
+ const [data, simpleError] = deserialize(await fetchRef.arrayBuffer());
160
+ if (simpleError) throw simpleError;
161
+ return data;
162
+ }
163
+ const json = await fetchRef.json();
164
+ if (json.simpleError) throw json;
165
+ return json;
166
+ };
@@ -1,82 +1,28 @@
1
- import { Platform } from 'react-native';
2
- import { encodeBinary } from './peripherals';
3
-
4
- export const CACHE_STORAGE_PATH = encodeBinary('MOSQUITO_TRANSPORT_FREEZER'),
5
- DEFAULT_CACHE_PASSWORD = encodeBinary('MOSQUITO_TRANSPORT_CACHE_PASSWORD'),
6
- LOCAL_STORAGE_PATH = () => {
7
- const fs = require('react-native-fs');
8
- return `${Platform.OS === 'android' ? fs.ExternalCachesDirectoryPath : fs.CachesDirectoryPath}/${encodeBinary('MOSQUITO_TRANSPORT_STORAGE')}`;
9
- },
10
- DEFAULT_DB_NAME = 'DEFAULT_DB',
11
- DEFAULT_DB_URL = 'mongodb://127.0.0.1:27017',
12
- DEFAULT_ENCRYPT_IV = '****';
13
-
14
- export const CACHE_PROTOCOL = {
15
- ASYNC_STORAGE: 'async-storage',
16
- REACT_NATIVE_FS: 'reat-native-fs',
17
- SQLITE: 'sqlite' // TODO:
18
- };
19
1
 
20
2
  export const RETRIEVAL = {
21
3
  STICKY: 'sticky',
22
4
  STICKY_NO_AWAIT: 'sticky-no-await',
23
5
  STICKY_RELOAD: 'sticky-reload',
24
6
  DEFAULT: 'default',
7
+ CACHE_AWAIT: 'cache-await',
25
8
  CACHE_NO_AWAIT: 'cache-no-await',
26
- NO_CACHE_NO_AWAIT: 'no-cache-no-await'
9
+ NO_CACHE_NO_AWAIT: 'no-cache-no-await',
10
+ NO_CACHE_AWAIT: 'no-cache-await'
27
11
  };
28
12
 
29
13
  export const DELIVERY = {
30
14
  DEFAULT: 'default',
31
- NO_CACHE: 'no-cache',
32
- NO_AWAIT: 'no-await',
33
- NO_AWAIT_NO_CACHE: 'no-await-no-cache',
34
- AWAIT_NO_CACHE: 'await-no-cache',
35
- CACHE_NO_AWAIT: 'cache-no-await'
36
- };
37
-
38
- export const WRITE_OPS = {
39
- $SET: '$set',
40
- $PUSH: '$push',
41
- $PULL: '$pull',
42
- $UNSET: '$unset',
43
- $INC: '$inc',
44
- $MAX: '$max',
45
- $MIN: '$min',
46
- $MUL: '$mul',
47
- $RENAME: '$rename',
48
- $SET_ON_INSERT: '$setOnInsert'
49
- };
50
- export const WRITE_OPS_LIST = Object.values(WRITE_OPS);
51
-
52
- export const READ_OPS = {
53
- $IN: '$in',
54
- $ALL: '$all',
55
- $NIN: '$nin',
56
- $GT: '$gt',
57
- $GTE: '$gte',
58
- $LT: '$lt',
59
- $LTE: '$lte',
60
- $TEXT: '$text',
61
- // $EQ: '$eq',
62
- // $REGEX: '$regex',
63
- // $EXISTS: '$exists',
64
- $NEAR: '$near',
65
- $TYPE: '$type',
66
- $SIZE: '$size',
67
- // $NE: '$ne'
68
- };
69
- export const READ_OPS_LIST = Object.values(READ_OPS);
70
-
71
- export const Regexs = {
72
- LINK: () => /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
15
+ CACHE_AWAIT: 'cache-await',
16
+ CACHE_NO_AWAIT: 'cache-no-await',
17
+ NO_CACHE_NO_AWAIT: 'no-cache-no-await',
18
+ NO_CACHE_AWAIT: 'no-cache-await'
73
19
  };
74
20
 
75
21
  export const AUTH_PROVIDER_ID = {
76
- GOOGLE: 'google.com',
77
- FACEBOOK: 'facebook.com',
22
+ GOOGLE: 'google',
23
+ FACEBOOK: 'facebook',
78
24
  PASSWORD: 'password',
79
- TWITTER: 'x.com',
80
- GITHUB: 'github.com',
81
- APPLE: 'apple.com'
25
+ TWITTER: 'x',
26
+ GITHUB: 'github',
27
+ APPLE: 'apple'
82
28
  };