react-native-mosquito-transport 0.0.48 → 0.0.50
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 +10 -2
- 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 +1 -1
- package/src/index.js +15 -10
- package/src/products/auth/accessor.js +97 -76
- package/src/products/auth/index.js +7 -6
- package/src/products/database/index.js +1 -0
- package/src/products/storage/index.js +9 -23
- package/.jshintignore +0 -4
- package/.jshintrc +0 -16
- package/TODO +0 -35
- 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,52 +1,34 @@
|
|
|
1
1
|
import React
|
|
2
2
|
|
|
3
|
-
@objc
|
|
4
|
-
|
|
3
|
+
@objc
|
|
4
|
+
public protocol NativeMosquitoTransportImplDelegate {
|
|
5
|
+
func sendEvent(name: String, body: Any)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@objc(NativeMosquitoTransportImpl)
|
|
9
|
+
public class NativeMosquitoTransportImpl: NSObject, URLSessionDataDelegate {
|
|
10
|
+
// Add property for the Objective-C bridge
|
|
11
|
+
@objc public weak var delegate: NativeMosquitoTransportImplDelegate? = nil
|
|
5
12
|
|
|
6
13
|
public override init() {
|
|
7
14
|
super.init()
|
|
8
15
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
@objc(supportedEvents)
|
|
15
|
-
override public func supportedEvents() -> [String] {
|
|
16
|
-
return [
|
|
17
|
-
"mt-uploading-progress",
|
|
18
|
-
"mt-uploading-status",
|
|
19
|
-
"mt-download-progress",
|
|
20
|
-
"mt-download-status"
|
|
21
|
-
]
|
|
16
|
+
|
|
17
|
+
private func emitNewEvent(name: String, body: Any? = nil) {
|
|
18
|
+
delegate?.sendEvent(name: name, body: body ?? [])
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
var uploadTask: [String:
|
|
25
|
-
var downloadTask: [String: MosquitodbDownloadTask] = [:]
|
|
26
|
-
|
|
27
|
-
@objc(downloadFile:)
|
|
28
|
-
func downloadFile(options: [String: Any]) -> Void {
|
|
29
|
-
let processID = options["processID"] as! String
|
|
30
|
-
downloadTask[processID] = MosquitodbDownloadTask()
|
|
31
|
-
downloadTask[processID]?.downloadFile(options: options, completion: { res in
|
|
32
|
-
let status = res![0] as? String
|
|
33
|
-
|
|
34
|
-
self.sendEvent(withName: status, body: res![1])
|
|
35
|
-
if status == "mt-download-status" {
|
|
36
|
-
self.downloadTask.removeValue(forKey: processID)
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
}
|
|
21
|
+
var uploadTask: [String: MosquitoTransportUploadTask] = [:]
|
|
40
22
|
|
|
41
23
|
@objc(uploadFile:)
|
|
42
|
-
func uploadFile(options: [String: Any]) -> Void {
|
|
24
|
+
public func uploadFile(options: [String: Any]) -> Void {
|
|
43
25
|
let processID = options["processID"] as! String
|
|
44
26
|
|
|
45
|
-
uploadTask[processID] =
|
|
27
|
+
uploadTask[processID] = MosquitoTransportUploadTask()
|
|
46
28
|
uploadTask[processID]?.uploadFile(options: options, completion: { res in
|
|
47
29
|
let status = res![0] as? String
|
|
48
30
|
|
|
49
|
-
self.
|
|
31
|
+
self.emitNewEvent(name: status!, body: res![1])
|
|
50
32
|
if status == "mt-uploading-status" {
|
|
51
33
|
self.uploadTask.removeValue(forKey: processID)
|
|
52
34
|
}
|
|
@@ -54,28 +36,43 @@ class Mosquitodb: RCTEventEmitter, URLSessionDataDelegate {
|
|
|
54
36
|
}
|
|
55
37
|
|
|
56
38
|
@objc(cancelUpload:)
|
|
57
|
-
func cancelUpload (processID: String)-> Void {
|
|
39
|
+
public func cancelUpload (processID: String)-> Void {
|
|
58
40
|
uploadTask[processID]?.cancelUpload()
|
|
59
41
|
}
|
|
60
42
|
|
|
43
|
+
var downloadTask: [String: MosquitoTransportDownloadTask] = [:]
|
|
44
|
+
|
|
45
|
+
@objc(downloadFile:)
|
|
46
|
+
public func downloadFile(options: [String: Any]) -> Void {
|
|
47
|
+
let processID = options["processID"] as! String
|
|
48
|
+
downloadTask[processID] = MosquitoTransportDownloadTask()
|
|
49
|
+
downloadTask[processID]?.downloadFile(options: options, completion: { res in
|
|
50
|
+
let status = res![0] as? String
|
|
51
|
+
|
|
52
|
+
self.emitNewEvent(name: status!, body: res![1])
|
|
53
|
+
if status == "mt-download-status" {
|
|
54
|
+
self.downloadTask.removeValue(forKey: processID)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
61
59
|
@objc(cancelDownload:)
|
|
62
|
-
func cancelDownload (processID: String)-> Void {
|
|
60
|
+
public func cancelDownload (processID: String)-> Void {
|
|
63
61
|
downloadTask[processID]?.cancelDownload()
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
@objc(pauseDownload:)
|
|
67
|
-
func pauseDownload (processID: String)-> Void {
|
|
65
|
+
public func pauseDownload (processID: String)-> Void {
|
|
68
66
|
downloadTask[processID]?.pauseDownload()
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
@objc(resumeDownload:)
|
|
72
|
-
func resumeDownload (processID: String)-> Void {
|
|
70
|
+
public func resumeDownload (processID: String)-> Void {
|
|
73
71
|
downloadTask[processID]?.resumeDownload()
|
|
74
72
|
}
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
class MosquitodbUploadTask: NSObject, URLSessionDataDelegate {
|
|
75
|
+
class MosquitoTransportUploadTask: NSObject, URLSessionDataDelegate {
|
|
79
76
|
|
|
80
77
|
var mainProcessID: String = ""
|
|
81
78
|
var mainTask : URLSessionUploadTask? = nil
|
|
@@ -177,7 +174,7 @@ class MosquitodbUploadTask: NSObject, URLSessionDataDelegate {
|
|
|
177
174
|
}
|
|
178
175
|
|
|
179
176
|
|
|
180
|
-
class
|
|
177
|
+
class MosquitoTransportDownloadTask: NSObject, URLSessionDownloadDelegate {
|
|
181
178
|
|
|
182
179
|
var mainProcessID: String = ""
|
|
183
180
|
var mainTask : URLSessionDownloadTask? = nil
|
|
@@ -208,7 +205,7 @@ class MosquitodbDownloadTask: NSObject, URLSessionDownloadDelegate {
|
|
|
208
205
|
mainOptions = options
|
|
209
206
|
trigger = completion
|
|
210
207
|
task.resume()
|
|
211
|
-
print("
|
|
208
|
+
print("MosquitoTransportDownloadTask started:\(mainProcessID)")
|
|
212
209
|
}
|
|
213
210
|
|
|
214
211
|
func cancelDownload ()-> Void {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mosquito-transport",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.50",
|
|
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",
|
|
@@ -26,6 +26,14 @@
|
|
|
26
26
|
"url": "https://github.com/brainbehindx/react-native-mosquito-transport/issues"
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/brainbehindx/react-native-mosquito-transport#readme",
|
|
29
|
+
"codegenConfig": {
|
|
30
|
+
"name": "MosquitoTransportSpec",
|
|
31
|
+
"type": "modules",
|
|
32
|
+
"jsSrcsDir": "src",
|
|
33
|
+
"android": {
|
|
34
|
+
"javaPackageName": "com.mosquitotransport"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
29
37
|
"dependencies": {
|
|
30
38
|
"@turf/turf": "^7.2.0",
|
|
31
39
|
"buffer": "^6.0.3",
|
|
@@ -43,4 +51,4 @@
|
|
|
43
51
|
"react-native-get-random-values": "*",
|
|
44
52
|
"react-native-sha256": "*"
|
|
45
53
|
}
|
|
46
|
-
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type { TurboModule } from 'react-native';
|
|
3
|
+
import { type UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
|
|
4
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export interface Spec extends TurboModule {
|
|
7
|
+
// storage
|
|
8
|
+
uploadFile(option: UnsafeObject): void;
|
|
9
|
+
cancelUpload(process_id: string): void;
|
|
10
|
+
downloadFile(option: UnsafeObject): void;
|
|
11
|
+
cancelDownload(process_id: string): void;
|
|
12
|
+
pauseDownload(process_id: string): void;
|
|
13
|
+
resumeDownload(process_id: string): void;
|
|
14
|
+
|
|
15
|
+
// utils
|
|
16
|
+
getSystemUptime(): Promise<number>;
|
|
17
|
+
|
|
18
|
+
// event listeners
|
|
19
|
+
// readonly onMessage?: EventEmitter<{ message: string }>;
|
|
20
|
+
addListener(eventName: string): void;
|
|
21
|
+
removeListeners(count: number): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('MosquitoTransport');
|
|
@@ -4,7 +4,7 @@ import { Platform } from "react-native";
|
|
|
4
4
|
import { Dirs, FileSystem } from "react-native-file-access";
|
|
5
5
|
import { Buffer } from "buffer";
|
|
6
6
|
|
|
7
|
-
const PARENT_FOLDER = `${Platform.OS === 'android' ? Dirs.DocumentDir.split('/').slice(0, -1).join('/') : Dirs.
|
|
7
|
+
const PARENT_FOLDER = `${Platform.OS === 'android' ? Dirs.DocumentDir.split('/').slice(0, -1).join('/') : Dirs.LibraryDir}/mosquito_base`;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* this method linearize read/write for individual access_id on the file system ensuring consistency across concurrent operations
|
package/src/helpers/utils.js
CHANGED
|
@@ -134,21 +134,19 @@ export const releaseCacheStore = async (builder) => {
|
|
|
134
134
|
Scoped.AuthJWTToken[key] = value?.token;
|
|
135
135
|
});
|
|
136
136
|
Scoped.IsStoreReady = true;
|
|
137
|
-
StoreReadyListener.dispatchPersist('_',
|
|
137
|
+
StoreReadyListener.dispatchPersist('_', true);
|
|
138
138
|
setTimeout(() => {
|
|
139
139
|
if (tobePurged.length) updateCacheStore(tobePurged);
|
|
140
140
|
}, 0);
|
|
141
141
|
};
|
|
142
142
|
|
|
143
|
-
export const getPrefferTime = () => Date.now() + (Scoped.serverTimeOffset || 0);
|
|
144
|
-
|
|
145
143
|
export const awaitStore = () => new Promise(resolve => {
|
|
146
144
|
if (Scoped.IsStoreReady) {
|
|
147
145
|
resolve();
|
|
148
146
|
return;
|
|
149
147
|
}
|
|
150
148
|
const l = StoreReadyListener.listenToPersist('_', t => {
|
|
151
|
-
if (t
|
|
149
|
+
if (t) {
|
|
152
150
|
resolve();
|
|
153
151
|
l();
|
|
154
152
|
}
|
package/src/helpers/variables.js
CHANGED
|
@@ -10,7 +10,8 @@ export const Scoped = {
|
|
|
10
10
|
AuthJWTToken: {},
|
|
11
11
|
IsStoreReady: false,
|
|
12
12
|
TokenRefreshTimer: {},
|
|
13
|
-
|
|
13
|
+
TokenRefreshProcess: {},
|
|
14
|
+
TokenTimestamping: {},
|
|
14
15
|
StorageProcessID: 0,
|
|
15
16
|
InitiatedForcedToken: {},
|
|
16
17
|
PendingFetchCollective: {},
|
package/src/index.d.ts
CHANGED
|
@@ -347,7 +347,7 @@ interface GetConfig {
|
|
|
347
347
|
retrieval?: Retrieval;
|
|
348
348
|
/**
|
|
349
349
|
* - 0: returns data that may have been internally updated locally with updateOne, updateMany, mergeOne, deleteOne, deleteMany, putOne, replaceOne
|
|
350
|
-
* - 1: returns exact data which was cached in the last query process
|
|
350
|
+
* - 1: returns exact remote data which was cached in the last query process
|
|
351
351
|
*
|
|
352
352
|
* @defaults - 0
|
|
353
353
|
*
|
package/src/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { Buffer } from 'buffer';
|
|
|
16
16
|
import MTAuth, { purgePendingToken } from './products/auth';
|
|
17
17
|
import { BSON } from "./vendor/bson";
|
|
18
18
|
import { basicClone } from './helpers/basic_clone';
|
|
19
|
+
import { AppState } from "react-native";
|
|
19
20
|
|
|
20
21
|
const {
|
|
21
22
|
_listenCollection,
|
|
@@ -59,11 +60,10 @@ class RNMT {
|
|
|
59
60
|
|
|
60
61
|
if (!Scoped.InitializedProject[projectUrl]) {
|
|
61
62
|
Scoped.InitializedProject[projectUrl] = basicClone(this.config);
|
|
62
|
-
Scoped.LastTokenRefreshRef[projectUrl] = 0;
|
|
63
63
|
triggerAuthToken(projectUrl);
|
|
64
|
-
initTokenRefresher({
|
|
64
|
+
initTokenRefresher({ config: this.config, forceRefresh: true });
|
|
65
65
|
|
|
66
|
-
let isConnected, recentToken;
|
|
66
|
+
let isConnected, recentToken, isVirtualMachineFocused = true;
|
|
67
67
|
|
|
68
68
|
const socket = io(`${this.config.wsPrefix}://${this.config.baseUrl}`, {
|
|
69
69
|
transports: ['websocket', 'polling', 'flashsocket'],
|
|
@@ -86,9 +86,9 @@ class RNMT {
|
|
|
86
86
|
};
|
|
87
87
|
const onDisconnect = () => {
|
|
88
88
|
++connectionIte;
|
|
89
|
-
isConnected = false;
|
|
90
|
-
Scoped.IS_CONNECTED[projectUrl] =
|
|
91
|
-
ServerReachableListener.dispatchPersist(projectUrl,
|
|
89
|
+
isConnected = isVirtualMachineFocused ? false : null;
|
|
90
|
+
Scoped.IS_CONNECTED[projectUrl] = isConnected;
|
|
91
|
+
ServerReachableListener.dispatchPersist(projectUrl, isConnected);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
const manualCheckConnection = () => {
|
|
@@ -112,6 +112,11 @@ class RNMT {
|
|
|
112
112
|
manualCheckConnection();
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
+
AppState.addEventListener('change', (s) => {
|
|
116
|
+
isVirtualMachineFocused = s === 'active';
|
|
117
|
+
manualCheckConnection();
|
|
118
|
+
});
|
|
119
|
+
|
|
115
120
|
const updateMountedToken = () => {
|
|
116
121
|
socket.emit('_update_mounted_user', recentToken || null);
|
|
117
122
|
};
|
|
@@ -308,7 +313,7 @@ class RNMT {
|
|
|
308
313
|
tokenListener = listenTokenReady(status => {
|
|
309
314
|
if (lastTokenStatus === (status || false)) return;
|
|
310
315
|
|
|
311
|
-
if (status
|
|
316
|
+
if (status) {
|
|
312
317
|
init();
|
|
313
318
|
} else {
|
|
314
319
|
socket?.close?.();
|
|
@@ -448,7 +453,7 @@ const ConfigValidator = {
|
|
|
448
453
|
if (v.endsWith('/')) throw '"projectUrl" must not end with a trailing slash "/"';
|
|
449
454
|
},
|
|
450
455
|
disableCache: (v) => {
|
|
451
|
-
if (typeof v !== 'boolean')
|
|
456
|
+
if (typeof v !== 'boolean' && v !== undefined)
|
|
452
457
|
throw `Invalid value supplied to disableCache, value must be a boolean`;
|
|
453
458
|
},
|
|
454
459
|
maxRetries: (v) => {
|
|
@@ -456,7 +461,7 @@ const ConfigValidator = {
|
|
|
456
461
|
throw `Invalid value supplied to maxRetries, value must be positive integer greater than zero`;
|
|
457
462
|
},
|
|
458
463
|
enableE2E_Encryption: (v) => {
|
|
459
|
-
if (typeof v !== 'boolean')
|
|
464
|
+
if (typeof v !== 'boolean' && v !== undefined)
|
|
460
465
|
throw `Invalid value supplied to enableE2E_Encryption, value must be a boolean`;
|
|
461
466
|
},
|
|
462
467
|
castBSON: v => {
|
|
@@ -468,7 +473,7 @@ const ConfigValidator = {
|
|
|
468
473
|
throw `Expected "borrowToken" to be valid https or http link but got "${v}"`;
|
|
469
474
|
},
|
|
470
475
|
serverE2E_PublicKey: (v) => {
|
|
471
|
-
if (typeof v !== 'string' || !v.trim())
|
|
476
|
+
if (v !== undefined && (typeof v !== 'string' || !v.trim()))
|
|
472
477
|
throw `Invalid value supplied to serverETE_PublicKey, value must be a non-empty string`;
|
|
473
478
|
},
|
|
474
479
|
extraHeaders: v => {
|
|
@@ -2,11 +2,12 @@ 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,65 +96,84 @@ 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
|
+
}, 9000);
|
|
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
|
|
|
136
|
+
const hasTokenExpire = async (projectUrl) => {
|
|
137
|
+
const timestamp = Scoped.TokenTimestamping[projectUrl];
|
|
138
|
+
if (!timestamp) return true;
|
|
139
|
+
const uptime = await NativeMosquitoTransport.getSystemUptime();
|
|
140
|
+
|
|
141
|
+
return timestamp.ttl <= (uptime - timestamp.uptime);
|
|
142
|
+
}
|
|
143
|
+
|
|
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
|
+
}
|
|
151
|
+
|
|
116
152
|
export const getEmulatedLinks = (projectUrl) => Object.entries(CacheStore.EmulatedAuth)
|
|
117
153
|
.filter(([_, v]) => v === projectUrl)
|
|
118
154
|
.map(v => v[0]);
|
|
119
155
|
|
|
120
|
-
const refreshToken = (builder,
|
|
121
|
-
|
|
122
|
-
|
|
156
|
+
const refreshToken = (builder, remainRetries = 1, isForceRefresh) =>
|
|
157
|
+
new Promise(async (resolve, reject) => {
|
|
158
|
+
const { projectUrl, serverE2E_PublicKey, uglify, extraHeaders } = builder;
|
|
123
159
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const [reqBuilder, [privateKey]] = await buildFetchInterface({
|
|
128
|
-
body: { token, r_token },
|
|
129
|
-
uglify,
|
|
130
|
-
serverE2E_PublicKey,
|
|
131
|
-
extraHeaders
|
|
132
|
-
});
|
|
160
|
+
try {
|
|
161
|
+
const { token, refreshToken: r_token } = CacheStore.AuthStore[projectUrl];
|
|
133
162
|
|
|
134
|
-
|
|
163
|
+
const [reqBuilder, [privateKey]] = await buildFetchInterface({
|
|
164
|
+
body: { token, r_token },
|
|
165
|
+
uglify,
|
|
166
|
+
serverE2E_PublicKey,
|
|
167
|
+
extraHeaders
|
|
168
|
+
});
|
|
135
169
|
|
|
136
|
-
|
|
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
|
-
}
|
|
170
|
+
const data = await buildFetchResult(await fetch(EngineApi._refreshAuthToken(projectUrl, uglify), reqBuilder), uglify);
|
|
144
171
|
|
|
145
|
-
|
|
172
|
+
const f = uglify ? await deserializeE2E(data, serverE2E_PublicKey, privateKey) : data;
|
|
146
173
|
|
|
147
|
-
if (CacheStore.AuthStore[projectUrl]) {
|
|
148
174
|
CacheStore.AuthStore[projectUrl].token = f.result.token;
|
|
149
175
|
Scoped.AuthJWTToken[projectUrl] = f.result.token;
|
|
176
|
+
await updateTokenTimestamp(projectUrl, f.result.token);
|
|
150
177
|
|
|
151
178
|
resolve(f.result.token);
|
|
152
179
|
const isInit = !Scoped.InitiatedForcedToken[projectUrl] && isForceRefresh;
|
|
@@ -162,30 +189,24 @@ const refreshToken = (builder, processRef, remainRetries = 1, isForceRefresh) =>
|
|
|
162
189
|
if (isForceRefresh) Scoped.InitiatedForcedToken[v] = true;
|
|
163
190
|
});
|
|
164
191
|
updateCacheStore(['AuthStore']);
|
|
165
|
-
initTokenRefresher(builder);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
reject(
|
|
174
|
-
processRef === Scoped.LastTokenRefreshRef[projectUrl] ?
|
|
175
|
-
lostProcess.simpleError :
|
|
192
|
+
initTokenRefresher({ config: builder });
|
|
193
|
+
} catch (e) {
|
|
194
|
+
if (e.simpleError) {
|
|
195
|
+
console.error(`refreshToken error: ${e.simpleError?.message}`);
|
|
196
|
+
doSignOut({ ...builder });
|
|
197
|
+
reject(e.simpleError);
|
|
198
|
+
} else if (remainRetries <= 0) {
|
|
199
|
+
reject(
|
|
176
200
|
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);
|
|
201
|
+
);
|
|
202
|
+
console.error(`refreshToken retry limit exceeded err:`, e);
|
|
203
|
+
} else {
|
|
204
|
+
const l = listenReachableServer(c => {
|
|
205
|
+
if (c) {
|
|
206
|
+
l();
|
|
207
|
+
refreshToken(builder, remainRetries - 1, isForceRefresh).then(resolve, reject);
|
|
208
|
+
}
|
|
209
|
+
}, projectUrl);
|
|
210
|
+
}
|
|
189
211
|
}
|
|
190
|
-
}
|
|
191
|
-
});
|
|
212
|
+
});
|
|
@@ -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,7 +249,7 @@ 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) => {
|
|
@@ -335,8 +336,8 @@ const doProviderSignin = (builder, token, metadata, endpointer) => new Promise(a
|
|
|
335
336
|
refreshToken: f.result.refreshToken,
|
|
336
337
|
isNewUser: f.result.isNewUser
|
|
337
338
|
});
|
|
338
|
-
await injectFreshToken(builder, f.result);
|
|
339
339
|
revokeAuthIntance(builder, thisAuthStore);
|
|
340
|
+
await injectFreshToken(builder, f.result);
|
|
340
341
|
} catch (e) {
|
|
341
342
|
reject(simplifyCaughtError(e).simpleError);
|
|
342
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,
|