@emilgroup/migration-sdk 0.10.1-beta.4 → 0.11.1-beta.0
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/README.md +2 -2
- package/api/migration-api.ts +68 -34
- package/base.ts +167 -34
- package/common.ts +3 -2
- package/configuration.ts +20 -0
- package/dist/api/health-api.d.ts +1 -1
- package/dist/api/migration-api.d.ts +17 -17
- package/dist/api/migration-api.js +104 -63
- package/dist/base.d.ts +22 -0
- package/dist/base.js +170 -46
- package/dist/common.d.ts +1 -1
- package/dist/common.js +1 -0
- package/dist/configuration.d.ts +17 -0
- package/dist/configuration.js +2 -0
- package/dist/models/create-ingest-run-async-request-dto.d.ts +2 -0
- package/dist/models/create-ingest-run-async-request-dto.js +3 -1
- package/dist/models/create-ingest-run-sync-request-dto.d.ts +2 -0
- package/dist/models/create-ingest-run-sync-request-dto.js +3 -1
- package/dist/models/flush-ingested-data-request-dto.d.ts +2 -0
- package/dist/models/flush-ingested-data-request-dto.js +3 -1
- package/models/create-ingest-run-async-request-dto.ts +3 -1
- package/models/create-ingest-run-sync-request-dto.ts +3 -1
- package/models/flush-ingested-data-request-dto.ts +3 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,11 +17,11 @@ Although this package can be used in both TypeScript and JavaScript, it is inten
|
|
|
17
17
|
Navigate to the folder of your consuming project and run one of the following commands:
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
npm install @emilgroup/migration-sdk@0.
|
|
20
|
+
npm install @emilgroup/migration-sdk@0.11.1-beta.0 --save
|
|
21
21
|
```
|
|
22
22
|
or
|
|
23
23
|
```
|
|
24
|
-
yarn add @emilgroup/migration-sdk@0.
|
|
24
|
+
yarn add @emilgroup/migration-sdk@0.11.1-beta.0
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
And then you can import ``.
|
package/api/migration-api.ts
CHANGED
|
@@ -101,8 +101,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
101
101
|
// http bearer authentication required
|
|
102
102
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
105
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
106
|
+
if (authorizationValue) {
|
|
107
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
|
|
@@ -152,8 +154,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
152
154
|
// http bearer authentication required
|
|
153
155
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
154
156
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
158
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
159
|
+
if (authorizationValue) {
|
|
160
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
|
|
@@ -199,8 +203,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
199
203
|
// http bearer authentication required
|
|
200
204
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
201
205
|
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
207
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
208
|
+
if (authorizationValue) {
|
|
209
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
|
|
@@ -246,8 +252,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
246
252
|
// http bearer authentication required
|
|
247
253
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
248
254
|
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
256
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
257
|
+
if (authorizationValue) {
|
|
258
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
|
|
@@ -293,8 +301,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
293
301
|
// http bearer authentication required
|
|
294
302
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
295
303
|
|
|
296
|
-
|
|
297
|
-
|
|
304
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
305
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
306
|
+
if (authorizationValue) {
|
|
307
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
298
308
|
}
|
|
299
309
|
|
|
300
310
|
|
|
@@ -340,8 +350,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
340
350
|
// http bearer authentication required
|
|
341
351
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
342
352
|
|
|
343
|
-
|
|
344
|
-
|
|
353
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
354
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
355
|
+
if (authorizationValue) {
|
|
356
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
345
357
|
}
|
|
346
358
|
|
|
347
359
|
|
|
@@ -388,8 +400,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
388
400
|
// http bearer authentication required
|
|
389
401
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
390
402
|
|
|
391
|
-
|
|
392
|
-
|
|
403
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
404
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
405
|
+
if (authorizationValue) {
|
|
406
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
393
407
|
}
|
|
394
408
|
|
|
395
409
|
|
|
@@ -433,8 +447,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
433
447
|
// http bearer authentication required
|
|
434
448
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
435
449
|
|
|
436
|
-
|
|
437
|
-
|
|
450
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
451
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
452
|
+
if (authorizationValue) {
|
|
453
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
438
454
|
}
|
|
439
455
|
|
|
440
456
|
|
|
@@ -478,8 +494,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
478
494
|
// http bearer authentication required
|
|
479
495
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
480
496
|
|
|
481
|
-
|
|
482
|
-
|
|
497
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
498
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
499
|
+
if (authorizationValue) {
|
|
500
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
483
501
|
}
|
|
484
502
|
|
|
485
503
|
|
|
@@ -554,8 +572,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
554
572
|
localVarQueryParameter['filters'] = filters;
|
|
555
573
|
}
|
|
556
574
|
|
|
557
|
-
|
|
558
|
-
|
|
575
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
576
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
577
|
+
if (authorizationValue) {
|
|
578
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
559
579
|
}
|
|
560
580
|
|
|
561
581
|
|
|
@@ -630,8 +650,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
630
650
|
localVarQueryParameter['filters'] = filters;
|
|
631
651
|
}
|
|
632
652
|
|
|
633
|
-
|
|
634
|
-
|
|
653
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
654
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
655
|
+
if (authorizationValue) {
|
|
656
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
635
657
|
}
|
|
636
658
|
|
|
637
659
|
|
|
@@ -710,8 +732,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
710
732
|
localVarQueryParameter['filters'] = filters;
|
|
711
733
|
}
|
|
712
734
|
|
|
713
|
-
|
|
714
|
-
|
|
735
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
736
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
737
|
+
if (authorizationValue) {
|
|
738
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
715
739
|
}
|
|
716
740
|
|
|
717
741
|
|
|
@@ -790,8 +814,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
790
814
|
localVarQueryParameter['filters'] = filters;
|
|
791
815
|
}
|
|
792
816
|
|
|
793
|
-
|
|
794
|
-
|
|
817
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
818
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
819
|
+
if (authorizationValue) {
|
|
820
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
795
821
|
}
|
|
796
822
|
|
|
797
823
|
|
|
@@ -866,8 +892,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
866
892
|
localVarQueryParameter['filters'] = filters;
|
|
867
893
|
}
|
|
868
894
|
|
|
869
|
-
|
|
870
|
-
|
|
895
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
896
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
897
|
+
if (authorizationValue) {
|
|
898
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
871
899
|
}
|
|
872
900
|
|
|
873
901
|
|
|
@@ -914,8 +942,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
914
942
|
// http bearer authentication required
|
|
915
943
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
916
944
|
|
|
917
|
-
|
|
918
|
-
|
|
945
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
946
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
947
|
+
if (authorizationValue) {
|
|
948
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
919
949
|
}
|
|
920
950
|
|
|
921
951
|
|
|
@@ -965,8 +995,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
965
995
|
// http bearer authentication required
|
|
966
996
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
967
997
|
|
|
968
|
-
|
|
969
|
-
|
|
998
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
999
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
1000
|
+
if (authorizationValue) {
|
|
1001
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
970
1002
|
}
|
|
971
1003
|
|
|
972
1004
|
|
|
@@ -1016,8 +1048,10 @@ export const MigrationApiAxiosParamCreator = function (configuration?: Configura
|
|
|
1016
1048
|
// http bearer authentication required
|
|
1017
1049
|
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
|
1018
1050
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1051
|
+
// Only Authorization falls back to the configured token; an empty value is never sent.
|
|
1052
|
+
const authorizationValue = 'Authorization'.toLowerCase() === 'authorization' ? (authorization || baseAccessToken) : authorization;
|
|
1053
|
+
if (authorizationValue) {
|
|
1054
|
+
localVarHeaderParameter['Authorization'] = String(authorizationValue);
|
|
1021
1055
|
}
|
|
1022
1056
|
|
|
1023
1057
|
|
package/base.ts
CHANGED
|
@@ -32,9 +32,20 @@ export const COLLECTION_FORMATS = {
|
|
|
32
32
|
pipes: "|",
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
export interface SessionClass {
|
|
36
|
+
sub: string;
|
|
37
|
+
username?: string;
|
|
38
|
+
email?: string;
|
|
39
|
+
tenantSlug?: string;
|
|
40
|
+
permissions?: string;
|
|
41
|
+
expiresAt?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
export interface LoginClass {
|
|
36
45
|
accessToken: string;
|
|
37
46
|
permissions: string;
|
|
47
|
+
authMode?: string;
|
|
48
|
+
session?: SessionClass;
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
|
|
@@ -68,10 +79,19 @@ interface TokenData {
|
|
|
68
79
|
accessToken?: string;
|
|
69
80
|
username?: string;
|
|
70
81
|
permissions?: string;
|
|
82
|
+
// 'both' or 'session' when authservice keeps the tokens in a server session.
|
|
83
|
+
authMode?: string;
|
|
84
|
+
sub?: string;
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
const NETWORK_ERROR_MESSAGE = "Network Error";
|
|
74
88
|
const TOKEN_DATA = 'APP_TOKEN';
|
|
89
|
+
// Sent only to authservice, to ask for a server session.
|
|
90
|
+
const AUTH_MODE_HEADER = 'X-Emil-Auth-Mode';
|
|
91
|
+
// Names the account on every call; one browser session can hold several.
|
|
92
|
+
const ACCOUNT_HEADER = 'X-Emil-Account';
|
|
93
|
+
const SESSION_MODES = ['both', 'session'];
|
|
94
|
+
const RESEND_SAFE_METHODS = ['get', 'head', 'options'];
|
|
75
95
|
|
|
76
96
|
/**
|
|
77
97
|
*
|
|
@@ -93,10 +113,18 @@ export class BaseAPI {
|
|
|
93
113
|
this.configuration = configuration;
|
|
94
114
|
this.basePath = configuration.basePath || this.basePath;
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
if (configuration.cookieAuth) {
|
|
117
|
+
this.configuration.username = this.configuration.username || this.tokenData.username;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.usesSession()) {
|
|
121
|
+
this.useSessionAuth();
|
|
122
|
+
} else {
|
|
123
|
+
// Use config token if provided, otherwise use tokenData token
|
|
124
|
+
const configToken = this.configuration.accessToken;
|
|
125
|
+
const storedToken = accessToken ? `Bearer ${accessToken}` : '';
|
|
126
|
+
this.configuration.accessToken = configToken || storedToken;
|
|
127
|
+
}
|
|
100
128
|
} else {
|
|
101
129
|
const { accessToken, username } = this.tokenData;
|
|
102
130
|
|
|
@@ -110,6 +138,107 @@ export class BaseAPI {
|
|
|
110
138
|
this.attachInterceptor(axios);
|
|
111
139
|
}
|
|
112
140
|
|
|
141
|
+
// The app's own account wins over APP_TOKEN, which holds whichever tab wrote last.
|
|
142
|
+
private sessionAccount(): string | undefined {
|
|
143
|
+
return this.configuration.account || this.tokenData.sub;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Apps may pass the address as the second argument only; authservice is on the same host.
|
|
147
|
+
private authBasePath(): string {
|
|
148
|
+
return this.configuration.basePath || this.basePath;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private usesSession(): boolean {
|
|
152
|
+
return !!this.configuration.cookieAuth && SESSION_MODES.indexOf(this.tokenData.authMode) !== -1 && !!this.sessionAccount();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private useSessionAuth() {
|
|
156
|
+
const { headers, ...baseOptions } = this.configuration.baseOptions || {};
|
|
157
|
+
this.configuration.accessToken = '';
|
|
158
|
+
this.configuration.baseOptions = {
|
|
159
|
+
...baseOptions,
|
|
160
|
+
withCredentials: true,
|
|
161
|
+
headers: { ...headers, [ACCOUNT_HEADER]: this.sessionAccount() },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private useHeaderAuth(accessToken: string) {
|
|
166
|
+
this.configuration.accessToken = accessToken ? `Bearer ${accessToken}` : '';
|
|
167
|
+
this.tokenData.accessToken = accessToken;
|
|
168
|
+
delete this.tokenData.authMode;
|
|
169
|
+
delete this.tokenData.sub;
|
|
170
|
+
if (this.configuration.cookieAuth) {
|
|
171
|
+
const { withCredentials, headers, ...baseOptions } = this.configuration.baseOptions || {};
|
|
172
|
+
const { [ACCOUNT_HEADER]: account, ...otherHeaders } = headers || {};
|
|
173
|
+
this.configuration.baseOptions = { ...baseOptions, headers: otherHeaders };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private applyTokenReply({ accessToken, authMode, session }: LoginClass) {
|
|
178
|
+
if (this.configuration.cookieAuth && SESSION_MODES.indexOf(authMode) !== -1 && session?.sub) {
|
|
179
|
+
this.tokenData.authMode = authMode;
|
|
180
|
+
this.tokenData.sub = session.sub;
|
|
181
|
+
if (this.configuration.account) {
|
|
182
|
+
// A workspace switch moves the app to another account.
|
|
183
|
+
this.configuration.account = session.sub;
|
|
184
|
+
}
|
|
185
|
+
// Both keeps the token for apps not moved yet; session mode keeps no token at all.
|
|
186
|
+
if (authMode === 'both' && accessToken) {
|
|
187
|
+
this.tokenData.accessToken = accessToken;
|
|
188
|
+
} else {
|
|
189
|
+
delete this.tokenData.accessToken;
|
|
190
|
+
}
|
|
191
|
+
this.useSessionAuth();
|
|
192
|
+
} else {
|
|
193
|
+
this.useHeaderAuth(accessToken);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private sessionHeaders(): Record<string, string> {
|
|
198
|
+
if (!this.configuration.cookieAuth) {
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
[AUTH_MODE_HEADER]: 'session',
|
|
203
|
+
...(this.usesSession() && { [ACCOUNT_HEADER]: this.sessionAccount() }),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private withCurrentAuth(config: AxiosRequestConfig): AxiosRequestConfig {
|
|
208
|
+
delete config.headers['Authorization'];
|
|
209
|
+
delete config.headers[ACCOUNT_HEADER];
|
|
210
|
+
if (this.usesSession()) {
|
|
211
|
+
config.headers[ACCOUNT_HEADER] = this.sessionAccount();
|
|
212
|
+
config.withCredentials = true;
|
|
213
|
+
} else if (this.configuration.accessToken) {
|
|
214
|
+
config.headers['Authorization'] = this.configuration.accessToken;
|
|
215
|
+
}
|
|
216
|
+
return config;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Both keeps the token, so a session call the browser could not complete can be sent again with it.
|
|
220
|
+
private canRetryWithToken(config: AxiosRequestConfig): boolean {
|
|
221
|
+
return !!config.withCredentials && !!config.headers?.[ACCOUNT_HEADER]
|
|
222
|
+
&& !!this.tokenData.accessToken && this.tokenData.authMode !== 'session';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// A network error can come after the server ran the call, so only a call that is safe to repeat is sent again.
|
|
226
|
+
private canResend(config: AxiosRequestConfig): boolean {
|
|
227
|
+
return RESEND_SAFE_METHODS.indexOf((config.method || 'get').toLowerCase()) !== -1
|
|
228
|
+
|| Object.keys(config.headers || {}).some((name) => name.toLowerCase() === 'idempotency-key');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private switchToToken() {
|
|
232
|
+
this.useHeaderAuth(this.tokenData.accessToken);
|
|
233
|
+
this.storeTokenData(this.tokenData);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private retryWithToken(axios: AxiosInstance, config: AxiosRequestConfig) {
|
|
237
|
+
this.switchToToken();
|
|
238
|
+
config.withCredentials = false;
|
|
239
|
+
return axios(this.withCurrentAuth(config));
|
|
240
|
+
}
|
|
241
|
+
|
|
113
242
|
selectEnvironment(env: Environment) {
|
|
114
243
|
this.selectBasePath(env);
|
|
115
244
|
}
|
|
@@ -129,8 +258,8 @@ export class BaseAPI {
|
|
|
129
258
|
async authorize(username: string, password: string, targetWorkspace?: string): Promise<void> {
|
|
130
259
|
const options: AxiosRequestConfig = {
|
|
131
260
|
method: 'POST',
|
|
132
|
-
url: `${this.
|
|
133
|
-
headers: { 'Content-Type': 'application/json' },
|
|
261
|
+
url: `${this.authBasePath()}/authservice/v1/login`,
|
|
262
|
+
headers: { 'Content-Type': 'application/json', ...(this.configuration.cookieAuth && { [AUTH_MODE_HEADER]: 'session' }) },
|
|
134
263
|
data: {
|
|
135
264
|
username,
|
|
136
265
|
password,
|
|
@@ -140,13 +269,10 @@ export class BaseAPI {
|
|
|
140
269
|
|
|
141
270
|
const response = await globalAxios.request<LoginClass>(options);
|
|
142
271
|
|
|
143
|
-
const { data: { accessToken, permissions } } = response;
|
|
144
|
-
|
|
145
272
|
this.configuration.username = username;
|
|
146
|
-
this.configuration.accessToken = `Bearer ${accessToken}`;
|
|
147
273
|
this.tokenData.username = username;
|
|
148
|
-
this.tokenData.
|
|
149
|
-
this.
|
|
274
|
+
this.tokenData.permissions = response.data.permissions;
|
|
275
|
+
this.applyTokenReply(response.data);
|
|
150
276
|
|
|
151
277
|
}
|
|
152
278
|
|
|
@@ -170,9 +296,10 @@ export class BaseAPI {
|
|
|
170
296
|
|
|
171
297
|
const options: AxiosRequestConfig = {
|
|
172
298
|
method: 'POST',
|
|
173
|
-
url: `${this.
|
|
299
|
+
url: `${this.authBasePath()}/authservice/v1/refresh-token`,
|
|
174
300
|
headers: {
|
|
175
301
|
'Content-Type': 'application/json',
|
|
302
|
+
...this.sessionHeaders(),
|
|
176
303
|
},
|
|
177
304
|
data: { username: username },
|
|
178
305
|
withCredentials: true,
|
|
@@ -213,20 +340,22 @@ export class BaseAPI {
|
|
|
213
340
|
&& !originalConfig._retry) {
|
|
214
341
|
originalConfig._retry = true;
|
|
215
342
|
try {
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
this.
|
|
219
|
-
|
|
220
|
-
delete originalConfig.headers['Authorization']
|
|
221
|
-
|
|
222
|
-
originalConfig.headers['Authorization'] = accessToken;
|
|
223
|
-
|
|
224
|
-
this.configuration.accessToken = accessToken;
|
|
225
|
-
this.tokenData.accessToken = tokenString;
|
|
226
|
-
|
|
343
|
+
const reply = await this.refreshTokenInternal();
|
|
344
|
+
this.tokenData.permissions = reply.permissions;
|
|
345
|
+
this.applyTokenReply(reply);
|
|
227
346
|
this.storeTokenData(this.tokenData);
|
|
228
347
|
|
|
229
|
-
|
|
348
|
+
if (!this.usesSession()) {
|
|
349
|
+
return axios(this.withCurrentAuth(originalConfig));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Both mode: if the browser does not send the session cookie (another site), use the token.
|
|
353
|
+
return axios(this.withCurrentAuth(originalConfig)).catch((retryError) => {
|
|
354
|
+
if (retryError?.response?.status !== 401 || !this.tokenData.accessToken) {
|
|
355
|
+
return Promise.reject(retryError);
|
|
356
|
+
}
|
|
357
|
+
return this.retryWithToken(axios, originalConfig);
|
|
358
|
+
});
|
|
230
359
|
} catch (_error) {
|
|
231
360
|
if (_error.response && _error.response.data) {
|
|
232
361
|
return Promise.reject(_error.response.data);
|
|
@@ -234,26 +363,30 @@ export class BaseAPI {
|
|
|
234
363
|
return Promise.reject(_error);
|
|
235
364
|
}
|
|
236
365
|
}
|
|
366
|
+
} else if (err.message === NETWORK_ERROR_MESSAGE && this.canRetryWithToken(originalConfig)) {
|
|
367
|
+
// Both mode: the browser blocked the session call or hid its reply; later calls use the token.
|
|
368
|
+
if (!this.canResend(originalConfig)) {
|
|
369
|
+
this.switchToToken();
|
|
370
|
+
return Promise.reject(err);
|
|
371
|
+
}
|
|
372
|
+
return this.retryWithToken(axios, originalConfig);
|
|
237
373
|
} else if (err.message === NETWORK_ERROR_MESSAGE
|
|
238
|
-
&& originalConfig.headers.hasOwnProperty('Authorization')
|
|
374
|
+
&& (originalConfig.headers.hasOwnProperty('Authorization')
|
|
375
|
+
|| (this.configuration.cookieAuth && originalConfig.withCredentials && this.canResend(originalConfig)))
|
|
239
376
|
&& _retry_count < 4
|
|
240
377
|
) {
|
|
241
378
|
_retry_count++;
|
|
242
379
|
try {
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
this.tokenData.permissions = permissions;
|
|
380
|
+
// In session mode an unreadable 401 (no CORS headers on the error reply) also lands here.
|
|
381
|
+
const reply = await this.refreshTokenInternal();
|
|
382
|
+
this.tokenData.permissions = reply.permissions;
|
|
246
383
|
|
|
247
384
|
_retry = true;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this.configuration.accessToken = accessToken;
|
|
251
|
-
this.tokenData.accessToken = tokenString;
|
|
252
|
-
|
|
385
|
+
this.applyTokenReply(reply);
|
|
253
386
|
this.storeTokenData(this.tokenData);
|
|
254
387
|
|
|
255
388
|
return axios.request({
|
|
256
|
-
...originalConfig,
|
|
389
|
+
...this.withCurrentAuth(originalConfig),
|
|
257
390
|
});
|
|
258
391
|
} catch (_error) {
|
|
259
392
|
if (_error.response && _error.response.data) {
|
package/common.ts
CHANGED
|
@@ -130,9 +130,10 @@ export const toPathString = function (url: URL) {
|
|
|
130
130
|
* @export
|
|
131
131
|
*/
|
|
132
132
|
export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) {
|
|
133
|
-
|
|
133
|
+
// Typed by hand: since axios 1.20, request() returns an internal axios type that SDK declarations cannot name.
|
|
134
|
+
return <T = unknown, R = AxiosResponse<T>>(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH): Promise<R> => {
|
|
134
135
|
const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url};
|
|
135
|
-
return axios.request<T, R>(axiosRequestArgs)
|
|
136
|
+
return axios.request<T, R>(axiosRequestArgs) as Promise<R>;
|
|
136
137
|
};
|
|
137
138
|
}
|
|
138
139
|
|
package/configuration.ts
CHANGED
|
@@ -21,6 +21,8 @@ export interface ConfigurationParameters {
|
|
|
21
21
|
basePath?: string;
|
|
22
22
|
baseOptions?: any;
|
|
23
23
|
formDataCtor?: new () => any;
|
|
24
|
+
cookieAuth?: boolean;
|
|
25
|
+
account?: string;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export class Configuration {
|
|
@@ -74,6 +76,22 @@ export class Configuration {
|
|
|
74
76
|
*/
|
|
75
77
|
formDataCtor?: new () => any;
|
|
76
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Use a server session when authservice makes one; otherwise the token, as without this option.
|
|
81
|
+
* Set `account` too, so each SDK object keeps its own account.
|
|
82
|
+
*
|
|
83
|
+
* @type {boolean}
|
|
84
|
+
* @memberof Configuration
|
|
85
|
+
*/
|
|
86
|
+
cookieAuth?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* The session account (Cognito sub) this app shows, so the SDK never takes another tab's account.
|
|
89
|
+
*
|
|
90
|
+
* @type {string}
|
|
91
|
+
* @memberof Configuration
|
|
92
|
+
*/
|
|
93
|
+
account?: string;
|
|
94
|
+
|
|
77
95
|
constructor(param: ConfigurationParameters = {}) {
|
|
78
96
|
this.apiKey = param.apiKey;
|
|
79
97
|
this.username = param.username;
|
|
@@ -82,6 +100,8 @@ export class Configuration {
|
|
|
82
100
|
this.basePath = param.basePath;
|
|
83
101
|
this.baseOptions = param.baseOptions;
|
|
84
102
|
this.formDataCtor = param.formDataCtor;
|
|
103
|
+
this.cookieAuth = param.cookieAuth;
|
|
104
|
+
this.account = param.account;
|
|
85
105
|
}
|
|
86
106
|
|
|
87
107
|
/**
|
package/dist/api/health-api.d.ts
CHANGED
|
@@ -66,5 +66,5 @@ export declare class HealthApi extends BaseAPI {
|
|
|
66
66
|
* @throws {RequiredError}
|
|
67
67
|
* @memberof HealthApi
|
|
68
68
|
*/
|
|
69
|
-
check(options?: AxiosRequestConfig): Promise<import("axios").AxiosResponse<InlineResponse200, any, {}>>;
|
|
69
|
+
check(options?: AxiosRequestConfig): Promise<import("axios").AxiosResponse<InlineResponse200, any, {}, any>>;
|
|
70
70
|
}
|