react-native-mosquito-transport 0.0.47 → 0.0.49

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.
Files changed (97) hide show
  1. package/CONTRIBUTING.md +37 -19
  2. package/MosquitoTransport.podspec +20 -0
  3. package/android/build.gradle +32 -42
  4. package/android/src/main/AndroidManifest.xml +1 -3
  5. package/android/src/main/java/com/mosquitotransport/MosquitoTransportModule.kt +101 -0
  6. package/android/src/main/java/com/mosquitotransport/MosquitoTransportPackage.kt +31 -0
  7. package/android/src/main/java/com/mosquitotransport/utils/FileUploader.kt +106 -0
  8. package/android/src/main/java/com/mosquitotransport/utils/UploadCallback.kt +7 -0
  9. package/ios/MosquitoTransport-Bridging-Header.h +1 -0
  10. package/ios/MosquitoTransport.h +6 -0
  11. package/ios/MosquitoTransport.mm +81 -0
  12. package/ios/{Mosquitodb.swift → MosquitoTransport.swift} +39 -42
  13. package/package.json +11 -3
  14. package/src/NativeMosquitoTransport.js +24 -0
  15. package/src/helpers/fs_manager.js +1 -1
  16. package/src/helpers/utils.js +2 -4
  17. package/src/helpers/variables.js +2 -1
  18. package/src/index.d.ts +55 -24
  19. package/src/index.js +20 -12
  20. package/src/products/auth/accessor.js +119 -95
  21. package/src/products/auth/index.js +11 -9
  22. package/src/products/database/index.js +1 -0
  23. package/src/products/http_callable/index.js +6 -5
  24. package/src/products/storage/index.js +65 -60
  25. package/.jshintignore +0 -4
  26. package/.jshintrc +0 -16
  27. package/TODO +0 -27
  28. package/android/gradle.properties +0 -5
  29. package/android/src/main/java/com/mosquitodb/MosquitodbModule.java +0 -82
  30. package/android/src/main/java/com/mosquitodb/MosquitodbPackage.java +0 -28
  31. package/android/src/main/java/com/mosquitodb/utils/FileUploader.java +0 -101
  32. package/android/src/main/java/com/mosquitodb/utils/UploadCallback.java +0 -7
  33. package/example/.bundle/config +0 -2
  34. package/example/.node-version +0 -1
  35. package/example/.watchmanconfig +0 -1
  36. package/example/Gemfile +0 -6
  37. package/example/android/app/build.gradle +0 -170
  38. package/example/android/app/debug.keystore +0 -0
  39. package/example/android/app/proguard-rules.pro +0 -10
  40. package/example/android/app/src/debug/AndroidManifest.xml +0 -13
  41. package/example/android/app/src/debug/java/com/mosquitodbexample/ReactNativeFlipper.java +0 -75
  42. package/example/android/app/src/main/AndroidManifest.xml +0 -25
  43. package/example/android/app/src/main/java/com/mosquitodbexample/MainActivity.java +0 -35
  44. package/example/android/app/src/main/java/com/mosquitodbexample/MainApplication.java +0 -62
  45. package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -36
  46. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  47. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  48. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  49. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  50. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  51. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  52. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  53. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  54. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  55. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  56. package/example/android/app/src/main/res/values/strings.xml +0 -3
  57. package/example/android/app/src/main/res/values/styles.xml +0 -9
  58. package/example/android/app/src/release/java/com/mosquitodbexample/ReactNativeFlipper.java +0 -20
  59. package/example/android/build.gradle +0 -21
  60. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  61. package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -5
  62. package/example/android/gradle.properties +0 -44
  63. package/example/android/gradlew +0 -234
  64. package/example/android/gradlew.bat +0 -89
  65. package/example/android/settings.gradle +0 -4
  66. package/example/app.json +0 -4
  67. package/example/babel.config.js +0 -17
  68. package/example/index.js +0 -5
  69. package/example/ios/.xcode.env +0 -11
  70. package/example/ios/File.swift +0 -6
  71. package/example/ios/MosquitodbExample/AppDelegate.h +0 -6
  72. package/example/ios/MosquitodbExample/AppDelegate.mm +0 -36
  73. package/example/ios/MosquitodbExample/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
  74. package/example/ios/MosquitodbExample/Images.xcassets/Contents.json +0 -6
  75. package/example/ios/MosquitodbExample/Info.plist +0 -55
  76. package/example/ios/MosquitodbExample/LaunchScreen.storyboard +0 -47
  77. package/example/ios/MosquitodbExample/main.m +0 -10
  78. package/example/ios/MosquitodbExample-Bridging-Header.h +0 -3
  79. package/example/ios/MosquitodbExample.xcodeproj/project.pbxproj +0 -703
  80. package/example/ios/MosquitodbExample.xcodeproj/xcshareddata/xcschemes/MosquitodbExample.xcscheme +0 -88
  81. package/example/ios/MosquitodbExample.xcworkspace/contents.xcworkspacedata +0 -10
  82. package/example/ios/MosquitodbExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  83. package/example/ios/MosquitodbExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +0 -8
  84. package/example/ios/MosquitodbExample.xcworkspace/xcuserdata/anthony.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  85. package/example/ios/MosquitodbExample.xcworkspace/xcuserdata/anthony.xcuserdatad/WorkspaceSettings.xcsettings +0 -14
  86. package/example/ios/MosquitodbExampleTests/Info.plist +0 -24
  87. package/example/ios/MosquitodbExampleTests/MosquitodbExampleTests.m +0 -66
  88. package/example/ios/Podfile +0 -60
  89. package/example/metro.config.js +0 -40
  90. package/example/package.json +0 -22
  91. package/example/react-native.config.js +0 -10
  92. package/example/src/App.tsx +0 -31
  93. package/ios/Mosquitodb-Bridging-Header.h +0 -2
  94. package/ios/Mosquitodb.m +0 -22
  95. package/ios/Mosquitodb.xcodeproj/project.pbxproj +0 -283
  96. package/ios/Mosquitodb.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -4
  97. package/react-native-mosquitodb.podspec +0 -35
@@ -1,12 +1,13 @@
1
- import { doSignOut, revokeAuthIntance } from ".";
1
+ import { doSignOut, revokeAuthIntance } from "./index.js";
2
2
  import EngineApi from "../../helpers/engine_api";
3
3
  import { AuthTokenListener, TokenRefreshListener } from "../../helpers/listeners";
4
4
  import { decodeBinary, deserializeE2E, listenReachableServer } from "../../helpers/peripherals";
5
- import { awaitStore, buildFetchInterface, buildFetchResult, getPrefferTime, updateCacheStore } from "../../helpers/utils";
5
+ import { awaitStore, buildFetchInterface, buildFetchResult, updateCacheStore } from "../../helpers/utils";
6
6
  import { CacheStore, Scoped } from "../../helpers/variables";
7
7
  import { simplifyError } from "simplify-error";
8
8
  import { Validator } from "guard-object";
9
9
  import { basicClone } from "../../helpers/basic_clone";
10
+ import NativeMosquitoTransport from "../../NativeMosquitoTransport.js";
10
11
 
11
12
  export const listenToken = (callback, projectUrl) =>
12
13
  AuthTokenListener.listenToPersist(projectUrl, (t, n) => {
@@ -17,16 +18,16 @@ export const listenToken = (callback, projectUrl) =>
17
18
  export const injectFreshToken = async (config, { token, refreshToken }) => {
18
19
  const { projectUrl } = config;
19
20
 
20
- await awaitStore();
21
21
  CacheStore.AuthStore[projectUrl] = { token, refreshToken };
22
22
  Scoped.AuthJWTToken[projectUrl] = token;
23
23
  const isEmulated = projectUrl in CacheStore.EmulatedAuth;
24
24
  if (isEmulated) delete CacheStore.EmulatedAuth[projectUrl];
25
+ await updateTokenTimestamp(projectUrl, token);
25
26
 
26
27
  updateCacheStore(['AuthStore', isEmulated ? 'EmulatedAuth' : ''].filter(v => v));
27
28
 
28
29
  triggerAuthToken(projectUrl);
29
- initTokenRefresher(config);
30
+ initTokenRefresher({ config });
30
31
  };
31
32
 
32
33
  export const injectEmulatedAuth = async (config, emulatedURL) => {
@@ -49,7 +50,7 @@ export const injectEmulatedAuth = async (config, emulatedURL) => {
49
50
 
50
51
  updateCacheStore(['AuthStore', 'EmulatedAuth']);
51
52
  triggerAuthToken(projectUrl);
52
- initTokenRefresher(config);
53
+ initTokenRefresher({ config });
53
54
  };
54
55
 
55
56
  export const parseToken = (token) => JSON.parse(decodeBinary(token.split('.')[1]));
@@ -59,28 +60,35 @@ export const triggerAuthToken = async (projectUrl, isInit) => {
59
60
  AuthTokenListener.dispatchPersist(projectUrl, CacheStore.AuthStore[projectUrl]?.token || null, isInit);
60
61
  };
61
62
 
62
- export const awaitRefreshToken = (projectUrl) => new Promise(resolve => {
63
- const l = TokenRefreshListener.listenToPersist(projectUrl, v => {
64
- if (v === 'ready') {
65
- l();
66
- resolve();
63
+ export const awaitRefreshToken = (projectUrl) =>
64
+ new Promise(async resolve => {
65
+ try {
66
+ if (await initTokenRefresher({ justCheck: true, config: Scoped.InitializedProject[projectUrl] })) {
67
+ resolve();
68
+ } else throw null;
69
+ } catch (_) {
70
+ const l = TokenRefreshListener.listenToPersist(projectUrl, v => {
71
+ if (v) {
72
+ l();
73
+ resolve();
74
+ }
75
+ });
67
76
  }
68
77
  });
69
- });
70
78
 
71
79
  export const listenTokenReady = (callback, projectUrl) => TokenRefreshListener.listenToPersist(projectUrl, callback);
72
80
 
73
- export const initTokenRefresher = async (config, forceRefresh) => {
81
+ export const initTokenRefresher = async ({ config, forceRefresh, justCheck }) => {
74
82
  const { projectUrl, maxRetries } = config;
75
83
  if (!Scoped.IsStoreReady) await awaitStore();
76
84
  const { token } = CacheStore.AuthStore[projectUrl] || {};
77
85
  const emulatedURL = CacheStore.EmulatedAuth[projectUrl];
78
- const tokenInfo = token && parseToken(token);
79
86
 
80
- clearInterval(Scoped.TokenRefreshTimer[projectUrl]);
87
+ if (!justCheck) clearInterval(Scoped.TokenRefreshTimer[projectUrl]);
81
88
  if (emulatedURL) return;
82
89
 
83
90
  const notifyAuthReady = (value) => {
91
+ if (justCheck) return;
84
92
  TokenRefreshListener.dispatchPersist(projectUrl, value);
85
93
  getEmulatedLinks(projectUrl).forEach(v => {
86
94
  TokenRefreshListener.dispatchPersist(v, value);
@@ -88,104 +96,120 @@ export const initTokenRefresher = async (config, forceRefresh) => {
88
96
  }
89
97
 
90
98
  if (token) {
91
- const expireOn = (tokenInfo.exp * 1000) - 60000;
92
- const hasExpire = getPrefferTime() >= expireOn;
93
- const rizz = () => refreshToken(config, ++Scoped.LastTokenRefreshRef[projectUrl], maxRetries, forceRefresh);
99
+ const rizz = () => {
100
+ const runningProcess = Scoped.TokenRefreshProcess[projectUrl];
101
+ if (runningProcess) return runningProcess;
102
+
103
+ Scoped.TokenRefreshProcess[projectUrl] =
104
+ refreshToken(config, maxRetries, forceRefresh);
105
+
106
+ Scoped.TokenRefreshProcess[projectUrl].finally(() => {
107
+ delete Scoped.TokenRefreshProcess[projectUrl];
108
+ });
109
+ }
94
110
 
95
- if (hasExpire || forceRefresh) {
111
+ if (await hasTokenExpire(projectUrl) || forceRefresh) {
96
112
  notifyAuthReady();
97
113
  return rizz();
98
114
  } else {
99
- notifyAuthReady('ready');
100
- Scoped.TokenRefreshTimer[projectUrl] = setInterval(() => {
101
- const countdown = expireOn - getPrefferTime();
102
- if (countdown > 3000) return;
115
+ notifyAuthReady(true);
116
+ if (justCheck) {
117
+ return true;
118
+ } else {
119
+ let lastIte = 0;
103
120
  clearInterval(Scoped.TokenRefreshTimer[projectUrl]);
104
- notifyAuthReady();
105
- rizz();
106
- }, 3000);
121
+ Scoped.TokenRefreshTimer[projectUrl] = setInterval(async () => {
122
+ const iteRef = ++lastIte;
123
+ if (iteRef !== lastIte || !(await hasTokenExpire(projectUrl))) return;
124
+ clearInterval(Scoped.TokenRefreshTimer[projectUrl]);
125
+ notifyAuthReady();
126
+ rizz();
127
+ }, 7000);
128
+ }
107
129
  }
108
130
  } else {
109
- notifyAuthReady('ready');
110
- if (forceRefresh) {
111
- return simplifyError('no_token_yet', 'No token is available to initiate a refresh').simpleError;
112
- }
131
+ notifyAuthReady(true);
132
+ if (justCheck) return true;
113
133
  }
114
134
  };
115
135
 
116
- export const getEmulatedLinks = (projectUrl) => Object.entries(CacheStore.EmulatedAuth)
117
- .filter(([_, v]) => v === projectUrl)
118
- .map(v => v[0]);
136
+ const hasTokenExpire = async (projectUrl) => {
137
+ const timestamp = Scoped.TokenTimestamping[projectUrl];
138
+ if (!timestamp) return true;
139
+ const uptime = await NativeMosquitoTransport.getSystemUptime();
119
140
 
120
- const refreshToken = (builder, processRef, remainRetries = 1, isForceRefresh) => new Promise(async (resolve, reject) => {
121
- const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
122
- const lostProcess = simplifyError('process_lost', 'The token refresh process has been lost and replaced with another one');
141
+ return timestamp.ttl <= (uptime - timestamp.uptime);
142
+ }
123
143
 
124
- try {
125
- const { token, refreshToken: r_token } = CacheStore.AuthStore[projectUrl];
144
+ const updateTokenTimestamp = async (projectUrl, token) => {
145
+ const { exp, iat } = parseToken(token);
146
+ Scoped.TokenTimestamping[projectUrl] = {
147
+ ttl: ((exp * 1000) - (iat * 1000)) - 60_000,
148
+ uptime: await NativeMosquitoTransport.getSystemUptime()
149
+ };
150
+ }
126
151
 
127
- const [reqBuilder, [privateKey]] = await buildFetchInterface({
128
- body: { token, r_token },
129
- uglify,
130
- serverE2E_PublicKey,
131
- extraHeaders
132
- });
152
+ export const getEmulatedLinks = (projectUrl) => Object.entries(CacheStore.EmulatedAuth)
153
+ .filter(([_, v]) => v === projectUrl)
154
+ .map(v => v[0]);
133
155
 
134
- let data;
156
+ const refreshToken = (builder, remainRetries = 1, isForceRefresh) =>
157
+ new Promise(async (resolve, reject) => {
158
+ const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
159
+ const lostProcess = simplifyError('process_lost', 'The token refresh process has been lost and replaced with another one');
135
160
 
136
161
  try {
137
- data = await buildFetchResult(await fetch(EngineApi._refreshAuthToken(projectUrl, uglify), reqBuilder), uglify);
138
- } finally {
139
- if (processRef !== Scoped.LastTokenRefreshRef[projectUrl]) {
140
- reject(lostProcess.simpleError);
141
- return;
142
- }
143
- }
144
-
145
- const f = uglify ? await deserializeE2E(data, serverE2E_PublicKey, privateKey) : data;
146
-
147
- if (CacheStore.AuthStore[projectUrl]) {
148
- CacheStore.AuthStore[projectUrl].token = f.result.token;
149
- Scoped.AuthJWTToken[projectUrl] = f.result.token;
150
-
151
- resolve(f.result.token);
152
- const isInit = !Scoped.InitiatedForcedToken[projectUrl] && isForceRefresh;
153
-
154
- triggerAuthToken(projectUrl, isInit);
155
- if (isForceRefresh) Scoped.InitiatedForcedToken[projectUrl] = true;
162
+ const { token, refreshToken: r_token } = CacheStore.AuthStore[projectUrl];
156
163
 
157
- getEmulatedLinks(projectUrl).forEach(v => {
158
- CacheStore.AuthStore[v] = basicClone(CacheStore.AuthStore[projectUrl]);
159
- Scoped.AuthJWTToken[v] = f.result.token;
160
-
161
- triggerAuthToken(v, isInit);
162
- if (isForceRefresh) Scoped.InitiatedForcedToken[v] = true;
164
+ const [reqBuilder, [privateKey]] = await buildFetchInterface({
165
+ body: { token, r_token },
166
+ uglify,
167
+ serverE2E_PublicKey,
168
+ extraHeaders
163
169
  });
164
- updateCacheStore(['AuthStore']);
165
- initTokenRefresher(builder);
166
- } else reject(lostProcess.simpleError);
167
- } catch (e) {
168
- if (e.simpleError) {
169
- console.error(`refreshToken error: ${e.simpleError?.message}`);
170
- doSignOut({ ...builder });
171
- reject(e.simpleError);
172
- } else if (remainRetries <= 0) {
173
- reject(
174
- processRef === Scoped.LastTokenRefreshRef[projectUrl] ?
175
- lostProcess.simpleError :
170
+
171
+ const data = await buildFetchResult(await fetch(EngineApi._refreshAuthToken(projectUrl, uglify), reqBuilder), uglify);
172
+
173
+ const f = uglify ? await deserializeE2E(data, serverE2E_PublicKey, privateKey) : data;
174
+
175
+ if (CacheStore.AuthStore[projectUrl]) {
176
+ CacheStore.AuthStore[projectUrl].token = f.result.token;
177
+ Scoped.AuthJWTToken[projectUrl] = f.result.token;
178
+ await updateTokenTimestamp(projectUrl, f.result.token);
179
+
180
+ resolve(f.result.token);
181
+ const isInit = !Scoped.InitiatedForcedToken[projectUrl] && isForceRefresh;
182
+
183
+ triggerAuthToken(projectUrl, isInit);
184
+ if (isForceRefresh) Scoped.InitiatedForcedToken[projectUrl] = true;
185
+
186
+ getEmulatedLinks(projectUrl).forEach(v => {
187
+ CacheStore.AuthStore[v] = basicClone(CacheStore.AuthStore[projectUrl]);
188
+ Scoped.AuthJWTToken[v] = f.result.token;
189
+
190
+ triggerAuthToken(v, isInit);
191
+ if (isForceRefresh) Scoped.InitiatedForcedToken[v] = true;
192
+ });
193
+ updateCacheStore(['AuthStore']);
194
+ initTokenRefresher({ config: builder });
195
+ } else reject(lostProcess.simpleError);
196
+ } catch (e) {
197
+ if (e.simpleError) {
198
+ console.error(`refreshToken error: ${e.simpleError?.message}`);
199
+ doSignOut({ ...builder });
200
+ reject(e.simpleError);
201
+ } else if (remainRetries <= 0) {
202
+ reject(
176
203
  simplifyError('retry_limit_reached', 'The retry limit has been reach and execution prematurely stopped').simpleError
177
- );
178
- console.error(`refreshToken retry limit exceeded`);
179
- } else {
180
- const l = listenReachableServer(c => {
181
- if (processRef !== Scoped.LastTokenRefreshRef[projectUrl]) {
182
- reject(lostProcess.simpleError);
183
- l();
184
- } else if (c) {
185
- l();
186
- refreshToken(builder, processRef, remainRetries - 1, isForceRefresh).then(resolve, reject);
187
- }
188
- }, projectUrl);
204
+ );
205
+ console.error(`refreshToken retry limit exceeded`);
206
+ } else {
207
+ const l = listenReachableServer(c => {
208
+ if (c) {
209
+ l();
210
+ refreshToken(builder, remainRetries - 1, isForceRefresh).then(resolve, reject);
211
+ }
212
+ }, projectUrl);
213
+ }
189
214
  }
190
- }
191
- });
215
+ });
@@ -59,10 +59,11 @@ export default class MTAuth {
59
59
  onError?.(simplifyError('user_login_required', 'You must be signed-in to use this method').simpleError);
60
60
  return;
61
61
  }
62
- if (processID !== lastInitRef) return;
62
+ if (processID !== lastInitRef || hasCancelled) return;
63
63
  const mtoken = Scoped.AuthJWTToken[projectUrl],
64
64
  [reqBuilder, [privateKey]] = uglify ? await serializeE2E({ mtoken }, undefined, serverE2E_PublicKey) : [null, []];
65
65
 
66
+ if (processID !== lastInitRef || hasCancelled) return;
66
67
  socket = io(`${wsPrefix}://${baseUrl}`, {
67
68
  transports: ['websocket', 'polling', 'flashsocket'],
68
69
  auth: {
@@ -159,7 +160,7 @@ export default class MTAuth {
159
160
 
160
161
  signOut = () => doSignOut(this.builder);
161
162
 
162
- forceRefreshToken = () => initTokenRefresher(this.builder, true);
163
+ forceRefreshToken = () => initTokenRefresher({ config: this.builder, forceRefresh: true });
163
164
 
164
165
  emulate = async (projectUrl) => {
165
166
  await injectEmulatedAuth(this.builder, projectUrl);
@@ -189,8 +190,8 @@ const doCustomSignin = (builder, email, password) => new Promise(async (resolve,
189
190
  token: r.result.token,
190
191
  refreshToken: r.result.refreshToken
191
192
  });
192
- await injectFreshToken(builder, r.result);
193
193
  revokeAuthIntance(builder, thisAuthStore);
194
+ await injectFreshToken(builder, r.result);
194
195
  } catch (e) {
195
196
  reject(simplifyCaughtError(e).simpleError);
196
197
  }
@@ -223,8 +224,8 @@ const doCustomSignup = (builder, email, password, name, metadata) => new Promise
223
224
  refreshToken: r.result.refreshToken,
224
225
  isNewUser: !!r.result.isNewUser
225
226
  });
226
- await injectFreshToken(builder, r.result);
227
227
  revokeAuthIntance(builder, thisAuthStore);
228
+ await injectFreshToken(builder, r.result);
228
229
  } catch (e) {
229
230
  reject(simplifyCaughtError(e).simpleError);
230
231
  }
@@ -248,17 +249,19 @@ const clearCacheForSignout = (builder, disposeEmulated) => {
248
249
 
249
250
  purgeCache(projectUrl, true);
250
251
  if (disposeEmulated) getEmulatedLinks(projectUrl).forEach(e => purgeCache(e));
251
- initTokenRefresher(builder);
252
+ initTokenRefresher({ config: builder });
252
253
  };
253
254
 
254
255
  export const doSignOut = async (builder) => {
255
256
  if (!Scoped.IsStoreReady) await awaitStore();
256
257
  const emulatedURL = CacheStore.EmulatedAuth[builder.projectUrl];
258
+ const thisAuthStore = emulatedURL ? undefined : basicClone(CacheStore.AuthStore[builder.projectUrl]);
257
259
 
258
260
  clearCacheForSignout(builder, !emulatedURL);
259
261
  updateCacheStore(['AuthStore', 'EmulatedAuth']);
260
262
  if (emulatedURL) return;
261
- await revokeAuthIntance(builder);
263
+
264
+ await revokeAuthIntance(builder, thisAuthStore);
262
265
  };
263
266
 
264
267
  export const revokeAuthIntance = async (builder, authStore) => {
@@ -288,8 +291,7 @@ export const purgePendingToken = async (nodeId) => {
288
291
  isConnected = (await (await fetch(_areYouOk(projectUrl), { credentials: 'omit' })).json()).status === 'yes';
289
292
  } catch (_) { }
290
293
 
291
- if (!isConnected)
292
- await awaitReachableServer(projectUrl);
294
+ if (!isConnected) await awaitReachableServer(projectUrl);
293
295
 
294
296
  const [reqBuilder] = await buildFetchInterface({
295
297
  body: { token, r_token },
@@ -334,8 +336,8 @@ const doProviderSignin = (builder, token, metadata, endpointer) => new Promise(a
334
336
  refreshToken: f.result.refreshToken,
335
337
  isNewUser: f.result.isNewUser
336
338
  });
337
- await injectFreshToken(builder, f.result);
338
339
  revokeAuthIntance(builder, thisAuthStore);
340
+ await injectFreshToken(builder, f.result);
339
341
  } catch (e) {
340
342
  reject(simplifyCaughtError(e).simpleError);
341
343
  }
@@ -206,6 +206,7 @@ const listenDocument = (callback, onError, builder, config) => {
206
206
 
207
207
  const [encPlate, [privateKey]] = uglify ? await serializeE2E({ _body: authObj }, mtoken, serverE2E_PublicKey) : ['', []];
208
208
 
209
+ if (hasCancelled || processID !== lastInitRef) return;
209
210
  socket = io(`${wsPrefix}://${baseUrl}`, {
210
211
  transports: ['websocket', 'polling', 'flashsocket'],
211
212
  extraHeaders,
@@ -3,7 +3,7 @@ import { deserializeE2E, listenReachableServer, niceHash, normalizeRoute, serial
3
3
  import { awaitStore, getReachableServer } from "../../helpers/utils";
4
4
  import { RETRIEVAL } from "../../helpers/values";
5
5
  import { Scoped } from "../../helpers/variables";
6
- import { awaitRefreshToken } from "../auth/accessor";
6
+ import { awaitRefreshToken, parseToken } from "../auth/accessor";
7
7
  import { simplifyCaughtError } from "simplify-error";
8
8
  import { guardObject, Validator } from "guard-object";
9
9
  import { serialize } from "entity-serializer";
@@ -71,17 +71,18 @@ export const mfetch = async (input = '', init, config) => {
71
71
  ) throw `"body" must be any of string, buffer, object`;
72
72
  }
73
73
  await awaitStore();
74
+ const thisToken = disableAuth ? '' : (Scoped.AuthJWTToken[projectUrl] || '');
74
75
 
75
76
  const reqId = await niceHash(
76
77
  serialize([
77
78
  rawHeader,
78
79
  body,
79
- !!disableAuth,
80
+ // !!disableAuth,
80
81
  input,
81
- disableAuth ? '' : (Scoped.AuthJWTToken[projectUrl] || '')
82
+ thisToken && await parseToken(thisToken).uid
82
83
  ]).toString('base64')
83
84
  );
84
- const processReqId = `${reqId}_${disableCache}_${retrieval}`;
85
+ const processReqId = `${reqId}_${thisToken}_${disableCache}_${retrieval}`;
85
86
 
86
87
  let retries = 0, hasFinalize;
87
88
 
@@ -143,7 +144,7 @@ export const mfetch = async (input = '', init, config) => {
143
144
  const [reqBuilder, [privateKey]] = uglified ? await serializeE2E(body, mtoken, serverE2E_PublicKey) : [null, []];
144
145
 
145
146
  const f = await fetch(isLink ? input : `${projectUrl}/${normalizeRoute(input)}`, {
146
- ...(encodeBody || uglified) ? { method: 'POST' } : {},
147
+ ...(hasBody || uglified) ? { method: 'POST' } : {},
147
148
  credentials: 'omit',
148
149
  ...init,
149
150
  ...uglified ? { body: reqBuilder } : encodeBody ? { body: serialize(body) } : {},
@@ -1,52 +1,57 @@
1
1
  import EngineApi from "../../helpers/engine_api";
2
2
  import { deserializeE2E, prefixStoragePath } from "../../helpers/peripherals";
3
3
  import { Scoped } from "../../helpers/variables";
4
- import { DeviceEventEmitter, NativeEventEmitter, NativeModules, Platform } from 'react-native';
4
+ import { NativeEventEmitter } from 'react-native';
5
+ import NativeMosquitoTransport from '../../NativeMosquitoTransport';
5
6
  import { awaitReachableServer, buildFetchInterface, buildFetchResult } from "../../helpers/utils";
6
7
  import { awaitRefreshToken } from "../auth/accessor";
7
8
  import { simplifyError } from "simplify-error";
9
+ import { Validator } from "guard-object";
8
10
 
9
- const LINKING_ERROR =
10
- `The package 'react-native-mosquito-transport' doesn't seem to be linked. Make sure: \n\n` +
11
- Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
12
- '- You rebuilt the app after installing the package\n' +
13
- '- You are not using Expo Go\n';
14
-
15
- const RNMTModule = NativeModules.Mosquitodb || (
16
- new Proxy({}, {
17
- get() {
18
- throw new Error(LINKING_ERROR);
19
- },
20
- })
21
- );
22
- const emitter = Platform.OS === 'android' ?
23
- DeviceEventEmitter : new NativeEventEmitter(RNMTModule);
11
+ const emitter = new NativeEventEmitter(NativeMosquitoTransport);
24
12
 
25
13
  export class MTStorage {
26
14
  constructor(config) {
27
15
  this.builder = { ...config };
28
16
  }
29
17
 
30
- downloadFile(link = '', onComplete, destination, onProgress, options) {
31
- const { awaitServer } = options || {};
18
+ downloadFile = (link = '', destination, options) => {
19
+ const { awaitServer, onProgress } = options || {};
32
20
  let hasFinished, isPaused, hasCancelled;
33
21
 
34
22
  const { projectUrl, extraHeaders } = this.builder;
23
+ let onComplete;
24
+
25
+ const promise = new Promise((resolve, reject) => {
26
+ onComplete = (err, path) => {
27
+ if (hasFinished) return;
28
+ hasFinished = true;
29
+ if (path) {
30
+ resolve(path);
31
+ } else reject(err);
32
+ }
33
+ });
34
+
35
+ promise.abort = () => {
36
+ if (hasFinished || hasCancelled) return;
37
+ NativeMosquitoTransport.cancelDownload(processID);
38
+ hasCancelled = true;
39
+ onComplete?.({ error: 'download_aborted', message: 'The download process was aborted' });
40
+ }
35
41
 
36
42
  if (destination && (typeof destination !== 'string' || !destination.trim())) {
37
43
  onComplete?.({ error: 'destination_invalid', message: 'destination must be a non-empty string' });
38
- return () => { };
44
+ return promise;
39
45
  }
40
46
  if (destination) destination = prefixStoragePath(destination?.trim());
41
47
 
42
- if (typeof link !== 'string' || !link.trim().startsWith(`${EngineApi.staticStorage(projectUrl)}/`)) {
48
+ if (typeof link !== 'string' || !Validator.LINK(link = link.trim())) {
43
49
  onComplete?.({
44
50
  error: 'invalid_link',
45
- message: `link has an invalid value, expected a string that starts with "${EngineApi.staticStorage(projectUrl)}/"`
51
+ message: `downloadFile first argument has an invalid value, expected a valid link string but got '${link}' instead`
46
52
  });
47
- return () => { };
53
+ return promise;
48
54
  }
49
- link = link.trim();
50
55
 
51
56
  const processID = `${++Scoped.StorageProcessID}`;
52
57
  const init = async () => {
@@ -63,12 +68,12 @@ export class MTStorage {
63
68
  isPaused: !!isPaused,
64
69
  pause: () => {
65
70
  if (hasFinished || isPaused || hasCancelled) return;
66
- RNMTModule.pauseDownload(processID);
71
+ NativeMosquitoTransport.pauseDownload(processID);
67
72
  isPaused = true;
68
73
  },
69
74
  resume: () => {
70
75
  if (hasFinished || !isPaused || hasCancelled) return;
71
- RNMTModule.resumeDownload(processID);
76
+ NativeMosquitoTransport.resumeDownload(processID);
72
77
  isPaused = false;
73
78
  }
74
79
  });
@@ -86,10 +91,9 @@ export class MTStorage {
86
91
  onComplete?.(path ? undefined : (result?.simpleError || { error, message: errorDes }), path);
87
92
  resultListener.remove();
88
93
  progressListener.remove();
89
- hasFinished = true;
90
94
  });
91
95
 
92
- RNMTModule.downloadFile({
96
+ NativeMosquitoTransport.downloadFile({
93
97
  url: link,
94
98
  authToken: Scoped.AuthJWTToken[projectUrl],
95
99
  ...destination ? {
@@ -103,30 +107,36 @@ export class MTStorage {
103
107
  }
104
108
 
105
109
  init();
106
-
107
- return () => {
108
- if (hasFinished || hasCancelled) return;
109
- RNMTModule.cancelDownload(processID);
110
- hasCancelled = true;
111
- setTimeout(() => {
112
- onComplete?.({ error: 'download_aborted', message: 'The download process was aborted' });
113
- }, 1);
114
- }
110
+ return promise;
115
111
  }
116
112
 
117
- uploadFile(file = '', destination = '', onComplete, onProgress, options) {
118
- const { createHash, awaitServer } = options || {};
113
+ uploadFile = (file = '', destination = '', options) => {
114
+ const { createHash, awaitServer, onProgress } = options || {};
119
115
  let hasFinished, hasCancelled;
116
+ let thisComplete;
120
117
 
121
- const thisComplete = (...args) => {
122
- if (hasFinished) return;
123
- hasFinished = true;
124
- onComplete?.(...args);
125
- }
118
+ const promise = new Promise((resolve, reject) => {
119
+ thisComplete = (err, url) => {
120
+ if (hasFinished) return;
121
+ hasFinished = true;
122
+ if (url) {
123
+ resolve(url);
124
+ } else reject(err);
125
+ }
126
+ });
127
+
128
+ promise.abort = () => {
129
+ if (hasFinished || hasCancelled) return;
130
+ hasCancelled = true;
131
+ setTimeout(() => {
132
+ thisComplete?.({ error: 'upload_aborted', message: 'The upload process was aborted' });
133
+ }, 0);
134
+ NativeMosquitoTransport.cancelUpload(processID);
135
+ };
126
136
 
127
137
  if (typeof file !== 'string' || !file.trim()) {
128
138
  thisComplete?.({ error: 'file_path_invalid', message: 'file must be a non-empty string in uploadFile()' });
129
- return () => { };
139
+ return promise;
130
140
  }
131
141
  destination = destination?.trim?.();
132
142
 
@@ -134,7 +144,7 @@ export class MTStorage {
134
144
  validateDestination(destination);
135
145
  } catch (error) {
136
146
  thisComplete?.({ error: 'destination_invalid', message: error });
137
- return () => { };
147
+ return promise;
138
148
  }
139
149
 
140
150
  const isAsset = file.startsWith('ph://') || file.startsWith('content://');
@@ -142,6 +152,7 @@ export class MTStorage {
142
152
 
143
153
  const { projectUrl, uglify, extraHeaders } = this.builder;
144
154
  const processID = `${++Scoped.StorageProcessID}`;
155
+ const thisProjectUrl = options?.projectUrl || projectUrl;
145
156
 
146
157
  const init = async () => {
147
158
  if (awaitServer) await awaitReachableServer(projectUrl);
@@ -166,8 +177,8 @@ export class MTStorage {
166
177
  });
167
178
  const authToken = Scoped.AuthJWTToken[projectUrl];
168
179
 
169
- RNMTModule.uploadFile({
170
- url: EngineApi._uploadFile(projectUrl, uglify),
180
+ NativeMosquitoTransport.uploadFile({
181
+ url: EngineApi._uploadFile(thisProjectUrl, uglify),
171
182
  file: isAsset ? file : file.substring('file://'.length),
172
183
  ...authToken ? { authToken } : {},
173
184
  createHash: createHash ? 'yes' : 'no',
@@ -178,24 +189,16 @@ export class MTStorage {
178
189
  }
179
190
 
180
191
  init();
181
-
182
- return () => {
183
- if (hasFinished || hasCancelled) return;
184
- hasCancelled = true;
185
- setTimeout(() => {
186
- thisComplete?.({ error: 'upload_aborted', message: 'The upload process was aborted' });
187
- }, 0);
188
- RNMTModule.cancelUpload(processID);
189
- }
192
+ return promise;
190
193
  }
191
194
 
192
- deleteFile = (path) => deleteContent(this.builder, path);
193
- deleteFolder = (path) => deleteContent(this.builder, path, true);
195
+ deleteFile = (path, options) => deleteContent(this.builder, path, options);
196
+ deleteFolder = (path, options) => deleteContent(this.builder, path, options, true);
194
197
  }
195
198
 
196
199
  const { _deleteFile, _deleteFolder } = EngineApi;
197
200
 
198
- const deleteContent = async (builder, path, isFolder) => {
201
+ const deleteContent = async (builder, path, options, isFolder) => {
199
202
  const { projectUrl, uglify, extraHeaders, serverE2E_PublicKey } = builder;
200
203
 
201
204
  try {
@@ -207,8 +210,10 @@ const deleteContent = async (builder, path, isFolder) => {
207
210
  serverE2E_PublicKey,
208
211
  uglify
209
212
  });
213
+ const thisProjectUrl = options?.projectUrl || projectUrl;
210
214
 
211
- const data = await buildFetchResult(await fetch((isFolder ? _deleteFolder : _deleteFile)(projectUrl, uglify), reqBuilder), uglify);
215
+ const res = await fetch((isFolder ? _deleteFolder : _deleteFile)(thisProjectUrl, uglify), reqBuilder);
216
+ const data = await buildFetchResult(res, uglify);
212
217
  const result = uglify ? await deserializeE2E(data, serverE2E_PublicKey, privateKey) : data;
213
218
 
214
219
  if (result.status !== 'success') throw 'operation not successful';
package/.jshintignore DELETED
@@ -1,4 +0,0 @@
1
- node_modules/
2
- android/
3
- example/
4
- ios/