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.
- package/CONTRIBUTING.md +37 -19
- package/MosquitoTransport.podspec +20 -0
- package/android/build.gradle +32 -42
- package/android/src/main/AndroidManifest.xml +1 -3
- package/android/src/main/java/com/mosquitotransport/MosquitoTransportModule.kt +101 -0
- package/android/src/main/java/com/mosquitotransport/MosquitoTransportPackage.kt +31 -0
- package/android/src/main/java/com/mosquitotransport/utils/FileUploader.kt +106 -0
- package/android/src/main/java/com/mosquitotransport/utils/UploadCallback.kt +7 -0
- package/ios/MosquitoTransport-Bridging-Header.h +1 -0
- package/ios/MosquitoTransport.h +6 -0
- package/ios/MosquitoTransport.mm +81 -0
- package/ios/{Mosquitodb.swift → MosquitoTransport.swift} +39 -42
- package/package.json +11 -3
- package/src/NativeMosquitoTransport.js +24 -0
- package/src/helpers/fs_manager.js +1 -1
- package/src/helpers/utils.js +2 -4
- package/src/helpers/variables.js +2 -1
- package/src/index.d.ts +55 -24
- package/src/index.js +20 -12
- package/src/products/auth/accessor.js +119 -95
- package/src/products/auth/index.js +11 -9
- package/src/products/database/index.js +1 -0
- package/src/products/http_callable/index.js +6 -5
- package/src/products/storage/index.js +65 -60
- package/.jshintignore +0 -4
- package/.jshintrc +0 -16
- package/TODO +0 -27
- package/android/gradle.properties +0 -5
- package/android/src/main/java/com/mosquitodb/MosquitodbModule.java +0 -82
- package/android/src/main/java/com/mosquitodb/MosquitodbPackage.java +0 -28
- package/android/src/main/java/com/mosquitodb/utils/FileUploader.java +0 -101
- package/android/src/main/java/com/mosquitodb/utils/UploadCallback.java +0 -7
- package/example/.bundle/config +0 -2
- package/example/.node-version +0 -1
- package/example/.watchmanconfig +0 -1
- package/example/Gemfile +0 -6
- package/example/android/app/build.gradle +0 -170
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +0 -10
- package/example/android/app/src/debug/AndroidManifest.xml +0 -13
- package/example/android/app/src/debug/java/com/mosquitodbexample/ReactNativeFlipper.java +0 -75
- package/example/android/app/src/main/AndroidManifest.xml +0 -25
- package/example/android/app/src/main/java/com/mosquitodbexample/MainActivity.java +0 -35
- package/example/android/app/src/main/java/com/mosquitodbexample/MainApplication.java +0 -62
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -36
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +0 -3
- package/example/android/app/src/main/res/values/styles.xml +0 -9
- package/example/android/app/src/release/java/com/mosquitodbexample/ReactNativeFlipper.java +0 -20
- package/example/android/build.gradle +0 -21
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -5
- package/example/android/gradle.properties +0 -44
- package/example/android/gradlew +0 -234
- package/example/android/gradlew.bat +0 -89
- package/example/android/settings.gradle +0 -4
- package/example/app.json +0 -4
- package/example/babel.config.js +0 -17
- package/example/index.js +0 -5
- package/example/ios/.xcode.env +0 -11
- package/example/ios/File.swift +0 -6
- package/example/ios/MosquitodbExample/AppDelegate.h +0 -6
- package/example/ios/MosquitodbExample/AppDelegate.mm +0 -36
- package/example/ios/MosquitodbExample/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
- package/example/ios/MosquitodbExample/Images.xcassets/Contents.json +0 -6
- package/example/ios/MosquitodbExample/Info.plist +0 -55
- package/example/ios/MosquitodbExample/LaunchScreen.storyboard +0 -47
- package/example/ios/MosquitodbExample/main.m +0 -10
- package/example/ios/MosquitodbExample-Bridging-Header.h +0 -3
- package/example/ios/MosquitodbExample.xcodeproj/project.pbxproj +0 -703
- package/example/ios/MosquitodbExample.xcodeproj/xcshareddata/xcschemes/MosquitodbExample.xcscheme +0 -88
- package/example/ios/MosquitodbExample.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/ios/MosquitodbExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/MosquitodbExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +0 -8
- package/example/ios/MosquitodbExample.xcworkspace/xcuserdata/anthony.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/MosquitodbExample.xcworkspace/xcuserdata/anthony.xcuserdatad/WorkspaceSettings.xcsettings +0 -14
- package/example/ios/MosquitodbExampleTests/Info.plist +0 -24
- package/example/ios/MosquitodbExampleTests/MosquitodbExampleTests.m +0 -66
- package/example/ios/Podfile +0 -60
- package/example/metro.config.js +0 -40
- package/example/package.json +0 -22
- package/example/react-native.config.js +0 -10
- package/example/src/App.tsx +0 -31
- package/ios/Mosquitodb-Bridging-Header.h +0 -2
- package/ios/Mosquitodb.m +0 -22
- package/ios/Mosquitodb.xcodeproj/project.pbxproj +0 -283
- package/ios/Mosquitodb.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -4
- 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,
|
|
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) =>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
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 (
|
|
111
|
+
if (await hasTokenExpire(projectUrl) || forceRefresh) {
|
|
96
112
|
notifyAuthReady();
|
|
97
113
|
return rizz();
|
|
98
114
|
} else {
|
|
99
|
-
notifyAuthReady(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
notifyAuthReady(true);
|
|
116
|
+
if (justCheck) {
|
|
117
|
+
return true;
|
|
118
|
+
} else {
|
|
119
|
+
let lastIte = 0;
|
|
103
120
|
clearInterval(Scoped.TokenRefreshTimer[projectUrl]);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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(
|
|
110
|
-
if (
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
121
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
...(
|
|
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 {
|
|
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
|
|
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 = '',
|
|
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()
|
|
48
|
+
if (typeof link !== 'string' || !Validator.LINK(link = link.trim())) {
|
|
43
49
|
onComplete?.({
|
|
44
50
|
error: 'invalid_link',
|
|
45
|
-
message: `
|
|
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
|
-
|
|
71
|
+
NativeMosquitoTransport.pauseDownload(processID);
|
|
67
72
|
isPaused = true;
|
|
68
73
|
},
|
|
69
74
|
resume: () => {
|
|
70
75
|
if (hasFinished || !isPaused || hasCancelled) return;
|
|
71
|
-
|
|
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
|
-
|
|
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 = '',
|
|
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
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
170
|
-
url: EngineApi._uploadFile(
|
|
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
|
|
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