react-native-mosquito-transport 0.0.22 → 0.0.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mosquito-transport",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
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",
@@ -33,8 +33,9 @@
33
33
  "entity-serializer": "^1.0.2",
34
34
  "guard-object": "^1.1.4",
35
35
  "lodash": "^4.17.21",
36
+ "react-native-file-access": "^3.1.1",
36
37
  "react-native-get-random-values": "^1.9.0",
37
- "react-native-hash": "^3.0.3",
38
+ "react-native-sha256": "^1.4.10",
38
39
  "simplify-error": "^1.0.1",
39
40
  "socket.io-client": "^4.6.2",
40
41
  "subscription-listener": "^1.1.2",
@@ -0,0 +1,46 @@
1
+ import { Platform } from "react-native";
2
+ import { Buffer } from 'buffer';
3
+ import { deserialize, serialize } from 'entity-serializer';
4
+ import { Dirs, FileSystem } from 'react-native-file-access';
5
+
6
+ const MAX_INLINE_BLOB = 1024;
7
+
8
+ const DIR_PATH = `${Platform.OS === 'android' ? Dirs.DatabaseDir : Dirs.MainBundleDir}/MOSQUITO`;
9
+ const resolvePath = (path = '') => `${DIR_PATH}/${path.startsWith('/') ? path : '/' + path}`;
10
+
11
+ const DIR_CREATION_PROMISE = FileSystem.mkdir(DIR_PATH);
12
+
13
+ const fsWrite = async (path, data) => {
14
+ await DIR_CREATION_PROMISE;
15
+ return FileSystem.writeFile(resolvePath(path), data instanceof Buffer ? data.toString('base64') : data, 'base64');
16
+ }
17
+
18
+ const fsRead = async (path) => {
19
+ await DIR_CREATION_PROMISE;
20
+ return Buffer.from(await FileSystem.readFile(resolvePath(path), 'base64'), 'base64');
21
+ }
22
+
23
+ export const getStoreID = (db_filename, table, primary_key) => `${table}_${primary_key}_${db_filename}.blob`;
24
+
25
+ export const deleteBigData = (store_id) => FileSystem.unlink(resolvePath(store_id));
26
+
27
+ export const handleBigData = async (store_id, data) => {
28
+ const bufData = serialize(data);
29
+ if (bufData.byteLength <= MAX_INLINE_BLOB) {
30
+ return serialize([bufData]).toString('base64');
31
+ }
32
+ await fsWrite(store_id, bufData);
33
+ return serialize([undefined, store_id]).toString('base64');
34
+ };
35
+
36
+ export const parseBigData = async (result) => {
37
+ const [inline, store_id] = deserialize(Buffer.from(result, 'base64'));
38
+ if (store_id) {
39
+ try {
40
+ return deserialize(await fsRead(store_id));
41
+ } catch (error) {
42
+ throw `Referenced local file is either corrupted or deleted, Error: ${error}`;
43
+ }
44
+ }
45
+ return deserialize(inline);
46
+ };
@@ -3,7 +3,7 @@ import { ServerReachableListener } from "./listeners";
3
3
  import naclPkg from 'tweetnacl';
4
4
  import getLodash from "lodash/get";
5
5
  import { deserialize, serialize } from "entity-serializer";
6
- import { CONSTANTS, JSHash } from 'react-native-hash';
6
+ import { sha256 } from 'react-native-sha256';
7
7
 
8
8
  const { box, randomBytes } = naclPkg;
9
9
 
@@ -65,7 +65,7 @@ export function sortArrayByObjectKey(arr = [], key) {
65
65
  };
66
66
 
67
67
  export async function niceHash(str = '') {
68
- const hash = await JSHash(str, CONSTANTS.HashAlgorithms.md5);
68
+ const hash = await sha256(str);
69
69
  if (hash.length > str.length) return encodeBinary(str);
70
70
  return hash;
71
71
  };
@@ -3,6 +3,7 @@ import { Validator } from "guard-object";
3
3
  import { incrementDatabaseSizeCore } from "../products/database/counter";
4
4
  import { incrementFetcherSizeCore } from "../products/http_callable/counter";
5
5
  import unsetLodash from 'lodash/unset';
6
+ import { deleteBigData, getStoreID } from "./fs_manager";
6
7
 
7
8
  const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY, FETCH_RESOURCES } = SQLITE_PATH;
8
9
 
@@ -156,7 +157,7 @@ export const purgeRedundantRecords = async (data, builder) => {
156
157
 
157
158
  const [instanceData, resultData] = await Promise.all([
158
159
  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
+ sqlite.executeSql(`SELECT access_id_limiter, touched, size FROM ${LIMITER_RESULT(path)}`)
160
161
  ]).then(r =>
161
162
  r.map(v => v[0].rows.raw())
162
163
  );
@@ -178,19 +179,24 @@ export const purgeRedundantRecords = async (data, builder) => {
178
179
  let cuts = 0;
179
180
 
180
181
  for (let i = 0; i < redundantDbRanking.length; i++) {
181
- sizer -= redundantDbRanking[i][0].size || 0;
182
+ sizer -= (redundantDbRanking[i][0].size || 0);
182
183
  ++cuts;
183
184
  if (sizer < newSize) break;
184
185
  }
185
186
 
186
187
  console.warn(`purging ${cuts} of ${redundantDbRanking.length} db entities`);
187
188
  await Promise.all(redundantDbRanking.slice(0, cuts).map(async ([v, { builder, isCounter, path }]) => {
188
- const sqlite = await openDB(builder);
189
+ let db_filename;
190
+ const sqlite = await openDB(builder, n => db_filename = n);
189
191
  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
+ const table = (isCounter ? DB_COUNT_QUERY : 'access_id_limiter' in v ? LIMITER_RESULT : LIMITER_DATA)(path);
193
+ const id_field = 'access_id_limiter' in v ? 'access_id_limiter' : 'access_id';
194
+ const primary_key = v[id_field];
192
195
 
193
- await sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW(table, `${id_field} = ?`), [v[id_field]]);
196
+ await Promise.all([
197
+ sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW(table, `${id_field} = ?`), [primary_key]),
198
+ deleteBigData(getStoreID(db_filename, table, primary_key)).catch(() => null)
199
+ ]);
194
200
  if (!isCounter) incrementDatabaseSizeCore(data.DatabaseStats, builder, path, -v.size);
195
201
  } catch (error) {
196
202
  console.log('db redundantClearing err:', error);
@@ -223,16 +229,21 @@ export const purgeRedundantRecords = async (data, builder) => {
223
229
  let cuts = 0;
224
230
 
225
231
  for (let i = 0; i < redundantFetchRanking.length; i++) {
226
- sizer -= redundantFetchRanking[i][0].size || 0;
232
+ sizer -= (redundantFetchRanking[i][0].size || 0);
227
233
  ++cuts;
228
234
  if (sizer < newSize) break;
229
235
  }
230
236
 
231
237
  console.warn(`purging ${cuts} of ${redundantFetchRanking.length} fetcher entities`);
232
238
  await Promise.all(redundantFetchRanking.slice(0, cuts).map(async ([v, projectUrl]) => {
233
- const sqlite = await openDB(FETCH_RESOURCES(projectUrl));
239
+ let db_filename;
240
+ const sqlite = await openDB(FETCH_RESOURCES(projectUrl), n => db_filename = n);
241
+
234
242
  try {
235
- await sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW('main', 'access_id = ?'), [v.access_id]);
243
+ await Promise.all([
244
+ sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW('main', 'access_id = ?'), [v.access_id]),
245
+ deleteBigData(getStoreID(db_filename, 'main', v.access_id)).catch(() => null)
246
+ ]);
236
247
  incrementFetcherSizeCore(data.DatabaseStats, projectUrl, -v.size);
237
248
  } catch (error) {
238
249
  console.log('fetcher redundantClearing err:', error);
@@ -3,6 +3,7 @@ import { Scoped, SqliteCollective } from './variables';
3
3
  import { niceHash } from './peripherals';
4
4
 
5
5
  enablePromise(true);
6
+ let sqliteKeyHash;
6
7
 
7
8
  /**
8
9
  * 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
@@ -10,7 +11,7 @@ enablePromise(true);
10
11
  * @param {string} name
11
12
  * @returns {Promise<import('react-native-sqlite-storage').SQLiteDatabase>}
12
13
  */
13
- export const openDB = async (name) => {
14
+ export const openDB = async (name, onName) => {
14
15
 
15
16
  if (name?.projectUrl) {
16
17
  const { projectUrl, dbUrl, dbName } = name;
@@ -19,11 +20,15 @@ export const openDB = async (name) => {
19
20
 
20
21
  const { sqliteKey } = Scoped.ReleaseCacheData;
21
22
 
22
- if (sqliteKey) name = `${niceHash(sqliteKey)}__${name}`;
23
+ if (sqliteKey) {
24
+ const thisHash = await (sqliteKeyHash || (sqliteKeyHash = niceHash(sqliteKey)));
25
+ name = `${thisHash}__${name}`;
26
+ }
27
+ onName?.(name);
23
28
 
24
29
  if (!SqliteCollective.openedDb[name]) {
25
30
  SqliteCollective.openedDbProcess[name] = 0;
26
- SqliteCollective.openedDb[name] = (SqliteCollective.closeDbPromises[name] || Promise.resolve()).finally(() =>
31
+ SqliteCollective.openedDb[name] = Promise.allSettled([SqliteCollective.closeDbPromises[name] || Promise.resolve()]).then(() =>
27
32
  openDatabase({
28
33
  location: 'default',
29
34
  name,
@@ -91,13 +96,14 @@ export const openDB = async (name) => {
91
96
  * @param {any} builder
92
97
  * @param {string} access_id
93
98
  * @param {'database' | 'dbQueryCount' | 'httpFetch'} node
94
- * @returns {(task: (sqlite: import("react-native-sqlite-storage").SQLiteDatabase) => Promise<{any}> )=> Promise<{any}>}
99
+ * @returns {(task: (sqlite: import("react-native-sqlite-storage").SQLiteDatabase, db_filename: string) => Promise<{any}> )=> Promise<{any}>}
95
100
  */
96
101
  export const useSqliteLinearAccessId = (builder, access_id, node) => async (task) => {
97
102
  const { projectUrl, dbUrl, dbName } = builder;
98
103
  const nodeId = typeof builder === 'string' ? `${builder}_${access_id}` : `${projectUrl}_${dbUrl}_${dbName}_${access_id}`;
104
+ let db_filename;
99
105
 
100
- const sqlite = await openDB(builder);
106
+ const sqlite = await openDB(builder, n => db_filename = n);
101
107
 
102
108
  const thatProcess = Scoped.linearSqliteProcess[node][nodeId];
103
109
 
@@ -106,7 +112,7 @@ export const useSqliteLinearAccessId = (builder, access_id, node) => async (task
106
112
  if (thatProcess !== undefined) await thatProcess;
107
113
  } catch (_) { }
108
114
  try {
109
- resolve(await task(sqlite));
115
+ resolve(await task(sqlite, db_filename));
110
116
  } catch (error) {
111
117
  console.error('useSqliteLinearAccessId err:', error);
112
118
  reject(error);
@@ -124,10 +130,10 @@ export const useSqliteLinearAccessId = (builder, access_id, node) => async (task
124
130
  export const SQLITE_PATH = {
125
131
  FILE_NAME: 'MOSQUITO_TRANSPORT.db',
126
132
  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`
133
+ LIMITER_RESULT: path => `"${encodeURIComponent(path)}_LIMITER_RESULT"`,
134
+ LIMITER_DATA: path => `"${encodeURIComponent(path)}_LIMITER_DATA"`,
135
+ DB_COUNT_QUERY: path => `"${encodeURIComponent(path)}_DB_COUNT_QUERY"`,
136
+ FETCH_RESOURCES: projectUrl => `FETCH_RESOURCES_${encodeURIComponent(projectUrl)}.db`
131
137
  };
132
138
 
133
139
  export const SQLITE_COMMANDS = {
@@ -6,6 +6,7 @@ import { trySendPendingWrite } from "../products/database";
6
6
  import { deserialize } from "entity-serializer";
7
7
  import { openDB, SQLITE_COMMANDS, SQLITE_PATH } from "./sqlite_manager";
8
8
  import { purgeRedundantRecords } from "./purger";
9
+ import { getStoreID, handleBigData, parseBigData } from "./fs_manager";
9
10
 
10
11
  const { FILE_NAME, TABLE_NAME } = SQLITE_PATH;
11
12
 
@@ -44,14 +45,18 @@ export const updateCacheStore = (timer = 300, node) => {
44
45
 
45
46
  if (!updationKey.length) return;
46
47
  const sqlite = await openDB(FILE_NAME);
47
- await Promise.allSettled(
48
+ await Promise.all(
48
49
  updationKey
49
50
  .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();
51
+ .map(async ([ref, value]) => {
52
+ const blobData = await handleBigData(getStoreID(FILE_NAME, TABLE_NAME, ref), value);
53
+ return sqlite.executeSql(SQLITE_COMMANDS.MERGE(TABLE_NAME, ['ref', 'value']), [ref, blobData]);
54
+ })
55
+ ).catch(err => {
56
+ console.error('updateCacheStore err:', err);
57
+ }).finally(() => {
58
+ sqlite.close();
59
+ });
55
60
  }
56
61
  };
57
62
 
@@ -71,14 +76,23 @@ export const releaseCacheStore = async (builder) => {
71
76
  data = JSON.parse((await io.input()) || '{}');
72
77
  } else {
73
78
  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();
79
+ await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} ( ref TEXT PRIMARY KEY, value BLOB )`).catch(() => null);
80
+ try {
81
+ const [query] = await sqlite.executeSql(`SELECT * FROM ${TABLE_NAME}`);
82
+ data = Object.fromEntries(
83
+ await Promise.all(query.rows.raw().map(async v =>
84
+ [v.ref, await parseBigData(v.value)]
85
+ ))
86
+ );
87
+ } catch (error) {
88
+ console.error('initializeCache sqlite data release err:', error);
89
+ } finally {
90
+ sqlite.close();
91
+ }
78
92
  }
79
93
  await purgeRedundantRecords(data, builder);
80
94
  } catch (e) {
81
- console.error('releaseCacheStore data err:', e);
95
+ console.error('initializeCache data err:', e);
82
96
  }
83
97
 
84
98
  Object.entries(data).forEach(([k, v]) => {
@@ -28,7 +28,7 @@ export const Scoped = {
28
28
  httpFetch: {}
29
29
  },
30
30
  initedSqliteInstances: {
31
- httpFetch: undefined,
31
+ httpFetch: {},
32
32
  dbQueryCount: {},
33
33
  database: {}
34
34
  }
@@ -13,6 +13,7 @@ import { TIMESTAMP } from "../..";
13
13
  import { docSize, incrementDatabaseSize } from "./counter";
14
14
  import { deserializeBSON, serializeToBase64 } from "./bson";
15
15
  import { openDB, SQLITE_COMMANDS, SQLITE_PATH, useSqliteLinearAccessId } from "../../helpers/sqlite_manager";
16
+ import { getStoreID, handleBigData, parseBigData } from "../../helpers/fs_manager";
16
17
 
17
18
  const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY } = SQLITE_PATH;
18
19
 
@@ -105,20 +106,20 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
105
106
  const thisSize = docSize(value);
106
107
 
107
108
  if (!io) {
108
- await useSqliteLinearAccessId(builder, accessIdWithoutLimit, 'database')(async (sqlite) => {
109
+ await useSqliteLinearAccessId(builder, accessIdWithoutLimit, 'database')(async (sqlite, db_filename) => {
109
110
  const initNode = `${projectUrl}_${dbUrl}_${dbName}_${path}`;
110
111
 
111
112
  if (!Scoped.initedSqliteInstances.database[initNode]) {
112
113
  Scoped.initedSqliteInstances.database[initNode] = (async () => {
113
114
  await Promise.allSettled([
114
- sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_DATA(path)} ( access_id TEXT PRIMARY KEY, value TEXT, touched INTEGER, size INTEGER )`),
115
- sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_RESULT(path)} ( access_id-limit TEXT PRIMARY KEY, access_id TEXT, value TEXT, touched INTEGER, size INTEGER )`)
115
+ sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_DATA(path)} ( access_id TEXT PRIMARY KEY, value BLOB, touched INTEGER, size INTEGER )`),
116
+ sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_RESULT(path)} ( access_id_limiter TEXT PRIMARY KEY, access_id TEXT, value BLOB, touched INTEGER, size INTEGER )`)
116
117
  ]);
117
118
 
118
119
  await Promise.allSettled([
119
120
  sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_DATA(path), ['access_id'])),
120
121
  // sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_DATA(path), ['touched'])),
121
- sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_RESULT(path), ['access_id-limit'])),
122
+ sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_RESULT(path), ['access_id_limiter'])),
122
123
  // sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_RESULT(path), ['touched']))
123
124
  ]);
124
125
  })();
@@ -130,7 +131,7 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
130
131
 
131
132
  const [instanceData, resultData] = await Promise.all([
132
133
  sqlite.executeSql(`SELECT access_id, size FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [accessIdWithoutLimit]),
133
- sqlite.executeSql(`SELECT access_id-limit, size FROM ${LIMITER_RESULT(path)} WHERE access_id-limit = ?`, [resultAccessId])
134
+ sqlite.executeSql(`SELECT access_id_limiter, size FROM ${LIMITER_RESULT(path)} WHERE access_id_limiter = ?`, [resultAccessId])
134
135
  ]).then(r =>
135
136
  r.map(v => v[0].rows.item(0))
136
137
  );
@@ -150,16 +151,22 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
150
151
  data: value,
151
152
  size: thisSize
152
153
  });
154
+ const [blobData, episodeBlobData] = await Promise.all([
155
+ handleBigData(getStoreID(db_filename, LIMITER_DATA(path), accessIdWithoutLimit), newData),
156
+ isEpisode ?
157
+ handleBigData(getStoreID(db_filename, LIMITER_RESULT(path), resultAccessId), newResultData)
158
+ : Promise.resolve()
159
+ ]);
153
160
 
154
161
  await Promise.all([
155
162
  sqlite.executeSql(
156
163
  SQLITE_COMMANDS.MERGE(LIMITER_DATA(path), ['access_id', 'value', 'touched', 'size']),
157
- [accessIdWithoutLimit, newData, Date.now(), thisSize]
164
+ [accessIdWithoutLimit, blobData, Date.now(), thisSize]
158
165
  ),
159
166
  isEpisode ?
160
167
  sqlite.executeSql(
161
- SQLITE_COMMANDS.MERGE(LIMITER_RESULT(path), ['access_id-limit', 'access_id', 'value', 'touched', 'size']),
162
- [resultAccessId, accessIdWithoutLimit, newResultData, Date.now(), thisSize]
168
+ SQLITE_COMMANDS.MERGE(LIMITER_RESULT(path), ['access_id_limiter', 'access_id', 'value', 'touched', 'size']),
169
+ [resultAccessId, accessIdWithoutLimit, episodeBlobData, Date.now(), thisSize]
163
170
  ) : Promise.resolve()
164
171
  ]);
165
172
  incrementDatabaseSize(builder, path, editionSizeOffset + resultSizeOffset);
@@ -227,18 +234,16 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
227
234
  const record = await useSqliteLinearAccessId(builder, accessIdWithoutLimit, 'database')(async sqlite => {
228
235
  const resultAccessId = `${accessIdWithoutLimit}-${limit}`;
229
236
 
230
- const thisData = await (
231
- isEpisode ? sqlite.executeSql(`SELECT * FROM ${LIMITER_RESULT(path)} WHERE access_id-limit = ?`, [resultAccessId]) :
237
+ const qData = await (
238
+ isEpisode ? sqlite.executeSql(`SELECT * FROM ${LIMITER_RESULT(path)} WHERE access_id_limiter = ?`, [resultAccessId]) :
232
239
  sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [accessIdWithoutLimit])
233
- ).then(v => {
234
- const d = v[0].rows.item(0);
235
- if (d) return deserializeBSON(d.value, true);
236
- }).catch(() => null);
240
+ ).then(v => v[0].rows.item(0)).catch(() => null);
241
+ const thisData = qData && deserializeBSON(await parseBigData(qData.value), true);
237
242
 
238
243
  if (!thisData) return null;
239
244
 
240
245
  if (isEpisode) {
241
- await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS(LIMITER_RESULT(path), ['touched'], 'access_id-limit = ?'), [Date.now(), resultAccessId]);
246
+ await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS(LIMITER_RESULT(path), ['touched'], 'access_id_limiter = ?'), [Date.now(), resultAccessId]);
242
247
  return [thisData.data];
243
248
  }
244
249
 
@@ -460,20 +465,30 @@ export const addPendingWrites = async (builder, writeId, result) => {
460
465
  const pathFinder = {};
461
466
 
462
467
  await Promise.all(colListing.map(async access_id =>
463
- useSqliteLinearAccessId(builder, access_id, 'database')(async sqlite => {
464
- const data = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(v =>
465
- v[0].rows.raw().map(d => [d.access_id, deserializeBSON(d.value, true)])[0]
466
- );
468
+ useSqliteLinearAccessId(builder, access_id, 'database')(async (sqlite, db_filename) => {
469
+ const data = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(async v => {
470
+ const d = v[0].rows.item(0);
471
+ return [d.access_id, deserializeBSON(await parseBigData(d.value), true)];
472
+ });
467
473
  await MutateDataInstance(data, path =>
468
474
  pathFinder[path] || (
469
475
  pathFinder[path] = sqlite.executeSql(`SELECT value FROM ${LIMITER_DATA(path)}`).then(v =>
470
- v[0].rows.raw().map(d => deserializeBSON(d.value, true).data).flat()
476
+ Promise.all(
477
+ v[0].rows.raw().map(async d =>
478
+ deserializeBSON(await parseBigData(d.value), true).data
479
+ )
480
+ ).then(r => r.flat())
471
481
  ).catch(() => [])
472
482
  )
473
483
  );
484
+ const editedBlobData = await handleBigData(
485
+ getStoreID(db_filename, LIMITER_DATA(path), access_id),
486
+ serializeToBase64(data[1])
487
+ );
488
+
474
489
  await sqlite.executeSql(
475
490
  SQLITE_COMMANDS.MERGE(LIMITER_DATA(path), ['access_id', 'value', 'touched', 'size']),
476
- [access_id, serializeToBase64(data[1]), Date.now(), data[1].size]
491
+ [access_id, editedBlobData, Date.now(), data[1].size]
477
492
  );
478
493
  })
479
494
  ));
@@ -709,15 +724,21 @@ export const removePendingWrite = async (builder, writeId, revert) => {
709
724
  if (io) {
710
725
  RevertMutation(getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', access_id]));
711
726
  } else {
712
- await useSqliteLinearAccessId(builder, access_id, 'database')(async sqlite => {
713
- const colObj = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(v =>
714
- v[0].rows.raw().map(d => deserializeBSON(d.value))[0]
715
- ).catch(() => null);
727
+ await useSqliteLinearAccessId(builder, access_id, 'database')(async (sqlite, db_filename) => {
728
+ const colObj = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(async v => {
729
+ const d = v[0].rows.item(0);
730
+ return deserializeBSON(await parseBigData(d.value));
731
+ }).catch(() => null);
716
732
  if (!colObj) return;
717
733
  RevertMutation(colObj);
734
+ const revertedBlobData = await handleBigData(
735
+ getStoreID(db_filename, LIMITER_DATA(path), access_id),
736
+ serializeToBase64(colObj)
737
+ );
738
+
718
739
  await sqlite.executeSql(
719
740
  SQLITE_COMMANDS.MERGE(LIMITER_DATA(path), ['access_id', 'value', 'touched', 'size']),
720
- [access_id, serializeToBase64(colObj), Date.now(), colObj.size]
741
+ [access_id, revertedBlobData, Date.now(), colObj.size]
721
742
  );
722
743
  });
723
744
  }
@@ -505,8 +505,11 @@ const findObject = async (builder, config) => {
505
505
  Scoped.PendingDbReadCollective[processAccessId] = [];
506
506
  }
507
507
 
508
- const staleData = await getRecordData();
509
- if (retrieval.startsWith('sticky') && staleData) {
508
+ let staleData;
509
+ if (
510
+ retrieval.startsWith('sticky') &&
511
+ (staleData = await getRecordData())
512
+ ) {
510
513
  finalize(staleData);
511
514
  if (retrieval !== RETRIEVAL.STICKY_RELOAD) return;
512
515
  }
@@ -1,35 +1,35 @@
1
- import { Buffer } from "buffer";
2
1
  import { updateCacheStore } from "../../helpers/utils";
3
2
  import { CacheStore, Scoped } from "../../helpers/variables";
4
3
  import cloneDeep from "lodash/cloneDeep";
5
- import { deserialize, serialize } from "entity-serializer";
4
+ import { serialize } from "entity-serializer";
6
5
  import { SQLITE_COMMANDS, SQLITE_PATH, useSqliteLinearAccessId } from "../../helpers/sqlite_manager";
7
6
  import { incrementFetcherSize } from "./counter";
7
+ import { getStoreID, handleBigData, parseBigData } from "../../helpers/fs_manager";
8
8
 
9
9
  const { FETCH_RESOURCES } = SQLITE_PATH;
10
10
 
11
11
  export const insertFetchResources = async (projectUrl, access_id, value) => {
12
12
  value = cloneDeep(value);
13
- const data = serialize(value).toString('base64');
13
+ const dataSize = serialize(value).byteLength;
14
14
 
15
15
  const { io } = Scoped.ReleaseCacheData;
16
16
  if (io) {
17
17
  if (!CacheStore.FetchedStore[projectUrl])
18
18
  CacheStore.FetchedStore[projectUrl] = {};
19
19
  const b4 = CacheStore.FetchedStore[projectUrl][access_id];
20
- incrementFetcherSize(projectUrl, data.length - (b4?.size || 0));
20
+ incrementFetcherSize(projectUrl, dataSize - (b4?.size || 0));
21
21
  CacheStore.FetchedStore[projectUrl][access_id] = {
22
22
  touched: Date.now(),
23
23
  data: value,
24
- size: data.length
24
+ size: dataSize
25
25
  };
26
26
  } else {
27
27
  const initNode = projectUrl;
28
28
 
29
- await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async sqlite => {
29
+ await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async (sqlite, db_filename) => {
30
30
  if (!Scoped.initedSqliteInstances.httpFetch[initNode]) {
31
31
  Scoped.initedSqliteInstances.httpFetch[initNode] = (async () => {
32
- await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS main ( access_id TEXT PRIMARY KEY, value TEXT, touched INTEGER, size INTEGER )`).catch(() => null);
32
+ await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS main ( access_id TEXT PRIMARY KEY, value BLOB, touched INTEGER, size INTEGER )`).catch(() => null);
33
33
  await Promise.allSettled([
34
34
  sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX('main', ['access_id'])),
35
35
  sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX('main', ['touched']))
@@ -41,11 +41,13 @@ export const insertFetchResources = async (projectUrl, access_id, value) => {
41
41
  const b4Data = await sqlite.executeSql(`SELECT access_id, size FROM main WHERE access_id = ?`, [access_id]).then(r =>
42
42
  r[0].rows.item(0)
43
43
  );
44
+ const blobData = await handleBigData(getStoreID(db_filename, 'main', access_id), value);
45
+
44
46
  await sqlite.executeSql(
45
47
  SQLITE_COMMANDS.MERGE('main', ['access_id', 'value', 'touched', 'size']),
46
- [access_id, data, Date.now(), data.length]
48
+ [access_id, blobData, Date.now(), dataSize]
47
49
  );
48
- incrementFetcherSize(projectUrl, data.length - (b4Data?.size || 0));
50
+ incrementFetcherSize(projectUrl, dataSize - (b4Data?.size || 0));
49
51
  });
50
52
  }
51
53
 
@@ -61,12 +63,15 @@ export const getFetchResources = async (projectUrl, access_id) => {
61
63
  return record && cloneDeep(record?.data);
62
64
  }
63
65
 
64
- const res = await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(sqlite =>
65
- sqlite.executeSql('SELECT * FROM main WHERE access_id = ?', [access_id]).then(async r => {
66
- const data = deserialize(Buffer.from(r[0].rows.item(0).value, 'base64'));
67
- await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS('main', ['touched'], 'access_id = ?'), [Date.now(), access_id]);
68
- return data;
69
- }).catch(() => null)
70
- );
66
+ const res = await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async sqlite => {
67
+ const query = await sqlite.executeSql('SELECT * FROM main WHERE access_id = ?', [access_id]).catch(() => null);
68
+
69
+ const rawData = query && query[0].rows.item(0).value;
70
+ if (!rawData) return null;
71
+
72
+ const data = await parseBigData(rawData);
73
+ await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS('main', ['touched'], 'access_id = ?'), [Date.now(), access_id]);
74
+ return data;
75
+ });
71
76
  return res;
72
77
  }
@@ -122,8 +122,11 @@ export const mfetch = async (input = '', init, config) => {
122
122
  Scoped.PendingFetchCollective[processReqId] = [];
123
123
  }
124
124
 
125
- const reqData = await getFetchResources(projectUrl, reqId);
126
- if (retrieval.startsWith('sticky') && reqData) {
125
+ let reqData;
126
+ if (
127
+ retrieval.startsWith('sticky') &&
128
+ (reqData = await getFetchResources(projectUrl, reqId))
129
+ ) {
127
130
  resolveCache(reqData);
128
131
  if (retrieval !== RETRIEVAL.STICKY_RELOAD) return;
129
132
  }