@de./sdk-rn 1.0.26 → 1.0.27
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/dist/backend/Auth.d.ts +26 -1
- package/dist/backend/Auth.d.ts.map +1 -1
- package/dist/backend/Auth.js +95 -14
- package/dist/backend/Auth.js.map +1 -1
- package/dist/types/auth.d.ts +1 -0
- package/package.json +1 -1
- package/src/backend/Auth.ts +106 -19
- package/src/types/auth.d.ts +1 -0
package/dist/backend/Auth.d.ts
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
import type { AuthCredentials, AuthOptions } from '../types/auth';
|
|
2
2
|
export default class Auth {
|
|
3
3
|
private version;
|
|
4
|
+
private options;
|
|
4
5
|
protected creds: AuthCredentials;
|
|
5
|
-
private
|
|
6
|
+
private refreshTimer?;
|
|
6
7
|
private autorefresh?;
|
|
8
|
+
private onNewToken?;
|
|
7
9
|
private baseURL;
|
|
10
|
+
private isRotating;
|
|
8
11
|
accessToken?: string;
|
|
9
12
|
constructor(creds: AuthCredentials, options?: AuthOptions);
|
|
10
13
|
private request;
|
|
14
|
+
private debug;
|
|
15
|
+
private error;
|
|
16
|
+
/**
|
|
17
|
+
* Schedule next token rotation
|
|
18
|
+
*/
|
|
19
|
+
private scheduleRotation;
|
|
20
|
+
/**
|
|
21
|
+
* Clear rotation timer
|
|
22
|
+
*/
|
|
23
|
+
private clearRotation;
|
|
11
24
|
getToken(): Promise<string>;
|
|
12
25
|
rotateToken(): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Stop auto-refresh and clean up resources
|
|
28
|
+
*/
|
|
29
|
+
stopAutoRefresh(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Start auto-refresh
|
|
32
|
+
*/
|
|
33
|
+
startAutoRefresh(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Clean up all resources
|
|
36
|
+
*/
|
|
37
|
+
destroy(): void;
|
|
13
38
|
}
|
|
14
39
|
//# sourceMappingURL=Auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Auth.d.ts","sourceRoot":"","sources":["../../src/backend/Auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAsB,MAAM,eAAe,CAAA;AAWrF,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,OAAO,CAAC,OAAO,CAAQ;IACvB,SAAS,CAAC,KAAK,EAAE,eAAe,CAAA;IAChC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"Auth.d.ts","sourceRoot":"","sources":["../../src/backend/Auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAsB,MAAM,eAAe,CAAA;AAWrF,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAa;IAC5B,SAAS,CAAC,KAAK,EAAE,eAAe,CAAA;IAChC,OAAO,CAAC,YAAY,CAAC,CAAQ;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAyB;IAC5C,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,UAAU,CAAiB;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;gBAEd,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,WAAW;YAqB5C,OAAO;IA+BrB,OAAO,CAAC,KAAK;IAGb,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOf,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAgB3B,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IA0DpC;;OAEG;IACH,eAAe;IAOf;;OAEG;IACH,gBAAgB;IAOhB;;OAEG;IACH,OAAO;CAOR"}
|
package/dist/backend/Auth.js
CHANGED
|
@@ -13,6 +13,7 @@ import { Platform } from 'react-native';
|
|
|
13
13
|
const ACCESS_TOKEN_EXPIRY = 3.75; // in 3 minutes 45 seconds
|
|
14
14
|
export default class Auth {
|
|
15
15
|
constructor(creds, options) {
|
|
16
|
+
this.isRotating = false;
|
|
16
17
|
if (!creds)
|
|
17
18
|
throw new Error('Undefined Credentials. Check https://doc.dedot.io/sdk/auth');
|
|
18
19
|
if (!creds.workspace)
|
|
@@ -24,6 +25,7 @@ export default class Auth {
|
|
|
24
25
|
if (!creds.secret)
|
|
25
26
|
throw new Error('Undefined Connector Secret. Check https://doc.dedot.io/sdk/auth');
|
|
26
27
|
this.creds = creds;
|
|
28
|
+
this.options = options || {};
|
|
27
29
|
this.version = (options === null || options === void 0 ? void 0 : options.version) || 1;
|
|
28
30
|
this.baseURL = (options === null || options === void 0 ? void 0 : options.env) !== 'dev'
|
|
29
31
|
? 'https://api.dedot.io'
|
|
@@ -33,6 +35,7 @@ export default class Auth {
|
|
|
33
35
|
default: 'http://api.dedot.io:24800'
|
|
34
36
|
});
|
|
35
37
|
this.autorefresh = (options === null || options === void 0 ? void 0 : options.autorefresh) || false;
|
|
38
|
+
this.onNewToken = options === null || options === void 0 ? void 0 : options.onNewToken;
|
|
36
39
|
}
|
|
37
40
|
async request(_a) {
|
|
38
41
|
var { url } = _a, options = __rest(_a, ["url"]);
|
|
@@ -56,29 +59,56 @@ export default class Auth {
|
|
|
56
59
|
options.body = JSON.stringify(options.body);
|
|
57
60
|
}
|
|
58
61
|
options = Object.assign(Object.assign({}, rawOptions), options);
|
|
59
|
-
|
|
62
|
+
this.debug('Auth request', `${this.baseURL}/v${this.version}/${url.replace(/^\//, '')}`, options);
|
|
60
63
|
const response = await fetch(`${this.baseURL}/v${this.version}/${url.replace(/^\//, '')}`, options);
|
|
61
64
|
return await response.json();
|
|
62
65
|
}
|
|
66
|
+
debug(...args) {
|
|
67
|
+
var _a;
|
|
68
|
+
((_a = this.options) === null || _a === void 0 ? void 0 : _a.env) === 'dev' && console.debug('[Auth]', ...args);
|
|
69
|
+
}
|
|
70
|
+
error(...args) {
|
|
71
|
+
console.error('[Auth]', ...args);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Schedule next token rotation
|
|
75
|
+
*/
|
|
76
|
+
scheduleRotation() {
|
|
77
|
+
if (!this.autorefresh)
|
|
78
|
+
return;
|
|
79
|
+
this.clearRotation();
|
|
80
|
+
this.refreshTimer = setTimeout(() => this.rotateToken(), ACCESS_TOKEN_EXPIRY * 60 * 1000);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clear rotation timer
|
|
84
|
+
*/
|
|
85
|
+
clearRotation() {
|
|
86
|
+
if (!this.refreshTimer)
|
|
87
|
+
return;
|
|
88
|
+
clearTimeout(this.refreshTimer);
|
|
89
|
+
this.refreshTimer = undefined;
|
|
90
|
+
}
|
|
63
91
|
async getToken() {
|
|
64
|
-
const
|
|
92
|
+
const options = {
|
|
65
93
|
url: '/access/token',
|
|
66
94
|
method: 'POST',
|
|
67
95
|
body: this.creds
|
|
68
96
|
}, { error, message, token } = await this.request(options);
|
|
69
97
|
if (error)
|
|
70
98
|
throw new Error(message);
|
|
71
|
-
// Set auto-refresh token every 4 mins
|
|
72
|
-
if (this.autorefresh) {
|
|
73
|
-
clearTimeout(this.expiryTime);
|
|
74
|
-
this.expiryTime = setTimeout(() => this.rotateToken(), ACCESS_TOKEN_EXPIRY * 60 * 1000);
|
|
75
|
-
}
|
|
76
99
|
this.accessToken = token;
|
|
100
|
+
this.scheduleRotation(); // Schedule auto-refresh
|
|
77
101
|
return token;
|
|
78
102
|
}
|
|
79
103
|
async rotateToken() {
|
|
104
|
+
// Prevent concurrent rotation attempts
|
|
105
|
+
if (this.isRotating) {
|
|
106
|
+
this.debug('Token rotation already in progress, skipping');
|
|
107
|
+
return this.accessToken;
|
|
108
|
+
}
|
|
80
109
|
if (!this.accessToken)
|
|
81
110
|
throw new Error('No access token found');
|
|
111
|
+
this.isRotating = true;
|
|
82
112
|
try {
|
|
83
113
|
const options = {
|
|
84
114
|
url: '/access/token/rotate',
|
|
@@ -87,18 +117,69 @@ export default class Auth {
|
|
|
87
117
|
}, { error, message, token } = await this.request(options);
|
|
88
118
|
if (error)
|
|
89
119
|
throw new Error(message);
|
|
90
|
-
// Set auto-refresh token every 4 mins
|
|
91
|
-
if (this.autorefresh) {
|
|
92
|
-
clearTimeout(this.expiryTime);
|
|
93
|
-
this.expiryTime = setTimeout(() => this.rotateToken(), ACCESS_TOKEN_EXPIRY * 60 * 1000);
|
|
94
|
-
}
|
|
95
120
|
this.accessToken = token;
|
|
121
|
+
// Notify callback listener
|
|
122
|
+
if (typeof this.onNewToken === 'function')
|
|
123
|
+
try {
|
|
124
|
+
this.onNewToken(token);
|
|
125
|
+
}
|
|
126
|
+
catch (callbackError) {
|
|
127
|
+
this.error('[Auth] Error in onNewToken callback:', callbackError);
|
|
128
|
+
}
|
|
129
|
+
// Schedule next rotation
|
|
130
|
+
this.scheduleRotation();
|
|
131
|
+
this.debug('Token rotated successfully');
|
|
96
132
|
return token;
|
|
97
133
|
}
|
|
98
134
|
catch (error) {
|
|
99
|
-
|
|
100
|
-
|
|
135
|
+
this.debug('Refresh access token failed:', error.message);
|
|
136
|
+
try {
|
|
137
|
+
// Fallback: Get new token instead
|
|
138
|
+
const newToken = await this.getToken();
|
|
139
|
+
this.debug('Fallback to new token successful');
|
|
140
|
+
// Notify callback listener about new token
|
|
141
|
+
if (this.onNewToken)
|
|
142
|
+
try {
|
|
143
|
+
this.onNewToken(newToken);
|
|
144
|
+
}
|
|
145
|
+
catch (callbackError) {
|
|
146
|
+
this.error('Error in onNewToken callback:', callbackError);
|
|
147
|
+
}
|
|
148
|
+
return newToken;
|
|
149
|
+
}
|
|
150
|
+
catch (fallbackError) {
|
|
151
|
+
this.error('Fallback to new token also failed:', fallbackError.message);
|
|
152
|
+
throw fallbackError;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
this.isRotating = false;
|
|
101
157
|
}
|
|
102
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Stop auto-refresh and clean up resources
|
|
161
|
+
*/
|
|
162
|
+
stopAutoRefresh() {
|
|
163
|
+
this.debug('Stopping auto-refresh');
|
|
164
|
+
this.clearRotation();
|
|
165
|
+
this.autorefresh = false;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Start auto-refresh
|
|
169
|
+
*/
|
|
170
|
+
startAutoRefresh() {
|
|
171
|
+
this.debug('Starting auto-refresh');
|
|
172
|
+
this.autorefresh = true;
|
|
173
|
+
this.scheduleRotation();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Clean up all resources
|
|
177
|
+
*/
|
|
178
|
+
destroy() {
|
|
179
|
+
this.debug('Destroying Auth instance');
|
|
180
|
+
this.stopAutoRefresh();
|
|
181
|
+
this.accessToken = undefined;
|
|
182
|
+
this.onNewToken = undefined;
|
|
183
|
+
}
|
|
103
184
|
}
|
|
104
185
|
//# sourceMappingURL=Auth.js.map
|
package/dist/backend/Auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Auth.js","sourceRoot":"","sources":["../../src/backend/Auth.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,MAAM,mBAAmB,GAAG,IAAI,CAAA,CAAC,0BAA0B;AAQ3D,MAAM,CAAC,OAAO,OAAO,IAAI;
|
|
1
|
+
{"version":3,"file":"Auth.js","sourceRoot":"","sources":["../../src/backend/Auth.ts"],"names":[],"mappings":"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"}
|
package/dist/types/auth.d.ts
CHANGED
package/package.json
CHANGED
package/src/backend/Auth.ts
CHANGED
|
@@ -11,10 +11,13 @@ type AuthResponse = {
|
|
|
11
11
|
|
|
12
12
|
export default class Auth {
|
|
13
13
|
private version: number
|
|
14
|
+
private options: AuthOptions
|
|
14
15
|
protected creds: AuthCredentials
|
|
15
|
-
private
|
|
16
|
+
private refreshTimer?: number
|
|
16
17
|
private autorefresh?: boolean
|
|
18
|
+
private onNewToken?: (token: string) => void
|
|
17
19
|
private baseURL: string
|
|
20
|
+
private isRotating: boolean = false
|
|
18
21
|
public accessToken?: string
|
|
19
22
|
|
|
20
23
|
constructor( creds: AuthCredentials, options?: AuthOptions ){
|
|
@@ -25,6 +28,7 @@ export default class Auth {
|
|
|
25
28
|
if( !creds.secret ) throw new Error('Undefined Connector Secret. Check https://doc.dedot.io/sdk/auth')
|
|
26
29
|
|
|
27
30
|
this.creds = creds
|
|
31
|
+
this.options = options || {}
|
|
28
32
|
this.version = options?.version || 1
|
|
29
33
|
this.baseURL = options?.env !== 'dev'
|
|
30
34
|
? 'https://api.dedot.io'
|
|
@@ -34,9 +38,10 @@ export default class Auth {
|
|
|
34
38
|
default: 'http://api.dedot.io:24800'
|
|
35
39
|
})
|
|
36
40
|
this.autorefresh = options?.autorefresh || false
|
|
41
|
+
this.onNewToken = options?.onNewToken
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
private async request<T>({ url, ...options }: AuthRequestOptions ): Promise<T>{
|
|
44
|
+
private async request<T>({ url, ...options }: AuthRequestOptions ): Promise<T> {
|
|
40
45
|
const rawOptions: any = {
|
|
41
46
|
method: 'GET',
|
|
42
47
|
headers: {
|
|
@@ -61,15 +66,41 @@ export default class Auth {
|
|
|
61
66
|
|
|
62
67
|
options = { ...rawOptions, ...options }
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
this.debug('Auth request', `${this.baseURL}/v${this.version}/${url.replace(/^\//, '')}`, options )
|
|
65
70
|
const response = await fetch(`${this.baseURL}/v${this.version}/${url.replace(/^\//, '')}`, options )
|
|
66
71
|
|
|
67
72
|
return await response.json() as T
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
private debug( ...args: any[] ){
|
|
76
|
+
this.options?.env === 'dev' && console.debug('[Auth]', ...args )
|
|
77
|
+
}
|
|
78
|
+
private error( ...args: any[] ){
|
|
79
|
+
console.error('[Auth]', ...args )
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Schedule next token rotation
|
|
84
|
+
*/
|
|
85
|
+
private scheduleRotation(){
|
|
86
|
+
if( !this.autorefresh ) return
|
|
87
|
+
|
|
88
|
+
this.clearRotation()
|
|
89
|
+
this.refreshTimer = setTimeout( () => this.rotateToken(), ACCESS_TOKEN_EXPIRY * 60 * 1000 )
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Clear rotation timer
|
|
94
|
+
*/
|
|
95
|
+
private clearRotation(){
|
|
96
|
+
if( !this.refreshTimer ) return
|
|
97
|
+
|
|
98
|
+
clearTimeout( this.refreshTimer )
|
|
99
|
+
this.refreshTimer = undefined
|
|
100
|
+
}
|
|
101
|
+
|
|
70
102
|
async getToken(): Promise<string>{
|
|
71
103
|
const
|
|
72
|
-
{ workspace, cid, secret } = this.creds,
|
|
73
104
|
options: AuthRequestOptions = {
|
|
74
105
|
url: '/access/token',
|
|
75
106
|
method: 'POST',
|
|
@@ -78,20 +109,24 @@ export default class Auth {
|
|
|
78
109
|
{ error, message, token } = await this.request<AuthResponse>( options )
|
|
79
110
|
if( error ) throw new Error( message )
|
|
80
111
|
|
|
81
|
-
// Set auto-refresh token every 4 mins
|
|
82
|
-
if( this.autorefresh ){
|
|
83
|
-
clearTimeout( this.expiryTime )
|
|
84
|
-
this.expiryTime = setTimeout( () => this.rotateToken(), ACCESS_TOKEN_EXPIRY * 60 * 1000 )
|
|
85
|
-
}
|
|
86
|
-
|
|
87
112
|
this.accessToken = token
|
|
113
|
+
this.scheduleRotation() // Schedule auto-refresh
|
|
114
|
+
|
|
88
115
|
return token
|
|
89
116
|
}
|
|
90
117
|
|
|
91
|
-
async rotateToken(){
|
|
118
|
+
async rotateToken(): Promise<string> {
|
|
119
|
+
// Prevent concurrent rotation attempts
|
|
120
|
+
if( this.isRotating ){
|
|
121
|
+
this.debug('Token rotation already in progress, skipping')
|
|
122
|
+
return this.accessToken!
|
|
123
|
+
}
|
|
124
|
+
|
|
92
125
|
if( !this.accessToken )
|
|
93
126
|
throw new Error('No access token found')
|
|
94
127
|
|
|
128
|
+
this.isRotating = true
|
|
129
|
+
|
|
95
130
|
try {
|
|
96
131
|
const
|
|
97
132
|
options: AuthRequestOptions = {
|
|
@@ -102,18 +137,70 @@ export default class Auth {
|
|
|
102
137
|
{ error, message, token } = await this.request<AuthResponse>( options )
|
|
103
138
|
if( error ) throw new Error( message )
|
|
104
139
|
|
|
105
|
-
// Set auto-refresh token every 4 mins
|
|
106
|
-
if( this.autorefresh ){
|
|
107
|
-
clearTimeout( this.expiryTime )
|
|
108
|
-
this.expiryTime = setTimeout( () => this.rotateToken(), ACCESS_TOKEN_EXPIRY * 60 * 1000 )
|
|
109
|
-
}
|
|
110
|
-
|
|
111
140
|
this.accessToken = token
|
|
141
|
+
|
|
142
|
+
// Notify callback listener
|
|
143
|
+
if( typeof this.onNewToken === 'function' )
|
|
144
|
+
try { this.onNewToken( token ) }
|
|
145
|
+
catch( callbackError ){ this.error('[Auth] Error in onNewToken callback:', callbackError) }
|
|
146
|
+
|
|
147
|
+
// Schedule next rotation
|
|
148
|
+
this.scheduleRotation()
|
|
149
|
+
|
|
150
|
+
this.debug('Token rotated successfully')
|
|
112
151
|
return token
|
|
113
152
|
}
|
|
114
153
|
catch( error: any ){
|
|
115
|
-
|
|
116
|
-
|
|
154
|
+
this.debug('Refresh access token failed:', error.message)
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
// Fallback: Get new token instead
|
|
158
|
+
const newToken = await this.getToken()
|
|
159
|
+
this.debug('Fallback to new token successful')
|
|
160
|
+
|
|
161
|
+
// Notify callback listener about new token
|
|
162
|
+
if( this.onNewToken )
|
|
163
|
+
try { this.onNewToken( newToken ) }
|
|
164
|
+
catch( callbackError ){ this.error('Error in onNewToken callback:', callbackError) }
|
|
165
|
+
|
|
166
|
+
return newToken
|
|
167
|
+
}
|
|
168
|
+
catch( fallbackError: any ){
|
|
169
|
+
this.error('Fallback to new token also failed:', fallbackError.message)
|
|
170
|
+
throw fallbackError
|
|
171
|
+
}
|
|
117
172
|
}
|
|
173
|
+
finally { this.isRotating = false }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Stop auto-refresh and clean up resources
|
|
178
|
+
*/
|
|
179
|
+
stopAutoRefresh(){
|
|
180
|
+
this.debug('Stopping auto-refresh')
|
|
181
|
+
|
|
182
|
+
this.clearRotation()
|
|
183
|
+
this.autorefresh = false
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Start auto-refresh
|
|
188
|
+
*/
|
|
189
|
+
startAutoRefresh(){
|
|
190
|
+
this.debug('Starting auto-refresh')
|
|
191
|
+
|
|
192
|
+
this.autorefresh = true
|
|
193
|
+
this.scheduleRotation()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Clean up all resources
|
|
198
|
+
*/
|
|
199
|
+
destroy(){
|
|
200
|
+
this.debug('Destroying Auth instance')
|
|
201
|
+
this.stopAutoRefresh()
|
|
202
|
+
|
|
203
|
+
this.accessToken = undefined
|
|
204
|
+
this.onNewToken = undefined
|
|
118
205
|
}
|
|
119
206
|
}
|