@sasjs/adapter 3.1.0 → 3.2.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.
Files changed (47) hide show
  1. package/SASViyaApiClient.d.ts +2 -8
  2. package/SASjs.d.ts +16 -10
  3. package/SASjsApiClient.d.ts +22 -0
  4. package/auth/AuthManager.d.ts +12 -4
  5. package/auth/getAccessTokenForSasjs.d.ts +11 -0
  6. package/auth/{getAccessToken.d.ts → getAccessTokenForViya.d.ts} +1 -1
  7. package/auth/getAuthCodeForSasjs.d.ts +9 -0
  8. package/auth/getTokens.d.ts +3 -2
  9. package/auth/refreshTokensForSasjs.d.ts +10 -0
  10. package/auth/{refreshTokens.d.ts → refreshTokensForViya.d.ts} +2 -2
  11. package/auth/spec/{getAccessToken.spec.d.ts → getAccessTokenForSasjs.spec.d.ts} +0 -0
  12. package/auth/spec/{refreshTokens.spec.d.ts → getAccessTokenForViya.spec.d.ts} +0 -0
  13. package/auth/spec/mockResponses.d.ts +4 -0
  14. package/auth/spec/refreshTokensForSasjs.spec.d.ts +1 -0
  15. package/auth/spec/refreshTokensForViya.spec.d.ts +1 -0
  16. package/index.js +2 -2
  17. package/node/SASViyaApiClient.d.ts +2 -8
  18. package/node/SASjs.d.ts +15 -9
  19. package/node/SASjsApiClient.d.ts +22 -0
  20. package/node/auth/AuthManager.d.ts +11 -3
  21. package/node/auth/getAccessTokenForSasjs.d.ts +11 -0
  22. package/node/auth/{getAccessToken.d.ts → getAccessTokenForViya.d.ts} +1 -1
  23. package/node/auth/getAuthCodeForSasjs.d.ts +9 -0
  24. package/node/auth/getTokens.d.ts +3 -2
  25. package/node/auth/refreshTokensForSasjs.d.ts +10 -0
  26. package/node/auth/{refreshTokens.d.ts → refreshTokensForViya.d.ts} +2 -2
  27. package/node/index.js +2 -2
  28. package/node/request/RequestClient.d.ts +4 -0
  29. package/node/request/SasjsRequestClient.d.ts +8 -0
  30. package/package.json +1 -1
  31. package/request/RequestClient.d.ts +4 -0
  32. package/request/SasjsRequestClient.d.ts +8 -0
  33. package/src/SASViyaApiClient.ts +10 -5
  34. package/src/SASjs.ts +83 -47
  35. package/src/SASjsApiClient.ts +43 -0
  36. package/src/auth/AuthManager.ts +65 -10
  37. package/src/auth/getAccessTokenForSasjs.ts +36 -0
  38. package/src/auth/{getAccessToken.ts → getAccessTokenForViya.ts} +1 -1
  39. package/src/auth/getAuthCodeForSasjs.ts +31 -0
  40. package/src/auth/getTokens.ts +16 -9
  41. package/src/auth/refreshTokensForSasjs.ts +35 -0
  42. package/src/auth/{refreshTokens.ts → refreshTokensForViya.ts} +2 -2
  43. package/src/auth/spec/mockResponses.ts +5 -0
  44. package/src/job-execution/WebJobExecutor.ts +0 -1
  45. package/src/request/RequestClient.ts +11 -0
  46. package/src/request/Sas9RequestClient.ts +1 -1
  47. package/src/request/SasjsRequestClient.ts +23 -0
@@ -27,7 +27,9 @@ export interface HttpClient {
27
27
  etag: string;
28
28
  }>;
29
29
  getCsrfToken(type: 'general' | 'file'): CsrfToken | undefined;
30
+ saveLocalStorageToken(accessToken: string, refreshToken: string): void;
30
31
  clearCsrfTokens(): void;
32
+ clearLocalStorageTokens(): void;
31
33
  getBaseUrl(): string;
32
34
  }
33
35
  export declare class RequestClient implements HttpClient {
@@ -38,8 +40,10 @@ export declare class RequestClient implements HttpClient {
38
40
  protected httpClient: AxiosInstance;
39
41
  constructor(baseUrl: string, httpsAgentOptions?: https.AgentOptions);
40
42
  setConfig(baseUrl: string, httpsAgentOptions?: https.AgentOptions): void;
43
+ saveLocalStorageToken(accessToken: string, refreshToken: string): void;
41
44
  getCsrfToken(type?: 'general' | 'file'): CsrfToken | undefined;
42
45
  clearCsrfTokens(): void;
46
+ clearLocalStorageTokens(): void;
43
47
  getBaseUrl(): string;
44
48
  /**
45
49
  * this method returns all requests, an array of SASjsRequest type
@@ -0,0 +1,8 @@
1
+ import { RequestClient } from './RequestClient';
2
+ /**
3
+ * Specific request client for SASJS.
4
+ * Append tokens in headers.
5
+ */
6
+ export declare class SasjsRequestClient extends RequestClient {
7
+ getHeaders: (accessToken: string | undefined, contentType: string) => any;
8
+ }
package/package.json CHANGED
@@ -80,5 +80,5 @@
80
80
  "https": "^1.0.0",
81
81
  "tough-cookie": "^4.0.0"
82
82
  },
83
- "version": "3.1.0"
83
+ "version": "3.2.0"
84
84
  }
@@ -27,7 +27,9 @@ export interface HttpClient {
27
27
  etag: string;
28
28
  }>;
29
29
  getCsrfToken(type: 'general' | 'file'): CsrfToken | undefined;
30
+ saveLocalStorageToken(accessToken: string, refreshToken: string): void;
30
31
  clearCsrfTokens(): void;
32
+ clearLocalStorageTokens(): void;
31
33
  getBaseUrl(): string;
32
34
  }
33
35
  export declare class RequestClient implements HttpClient {
@@ -38,8 +40,10 @@ export declare class RequestClient implements HttpClient {
38
40
  protected httpClient: AxiosInstance;
39
41
  constructor(baseUrl: string, httpsAgentOptions?: https.AgentOptions);
40
42
  setConfig(baseUrl: string, httpsAgentOptions?: https.AgentOptions): void;
43
+ saveLocalStorageToken(accessToken: string, refreshToken: string): void;
41
44
  getCsrfToken(type?: 'general' | 'file'): CsrfToken | undefined;
42
45
  clearCsrfTokens(): void;
46
+ clearLocalStorageTokens(): void;
43
47
  getBaseUrl(): string;
44
48
  /**
45
49
  * this method returns all requests, an array of SASjsRequest type
@@ -0,0 +1,8 @@
1
+ import { RequestClient } from './RequestClient';
2
+ /**
3
+ * Specific request client for SASJS.
4
+ * Append tokens in headers.
5
+ */
6
+ export declare class SasjsRequestClient extends RequestClient {
7
+ getHeaders: (accessToken: string | undefined, contentType: string) => any;
8
+ }
@@ -22,8 +22,8 @@ import { pollJobState } from './api/viya/pollJobState'
22
22
  import { getTokens } from './auth/getTokens'
23
23
  import { uploadTables } from './api/viya/uploadTables'
24
24
  import { executeScript } from './api/viya/executeScript'
25
- import { getAccessToken } from './auth/getAccessToken'
26
- import { refreshTokens } from './auth/refreshTokens'
25
+ import { getAccessTokenForViya } from './auth/getAccessTokenForViya'
26
+ import { refreshTokensForViya } from './auth/refreshTokensForViya'
27
27
 
28
28
  /**
29
29
  * A client for interfacing with the SAS Viya REST API.
@@ -534,21 +534,26 @@ export class SASViyaApiClient {
534
534
  clientSecret: string,
535
535
  authCode: string
536
536
  ): Promise<SasAuthResponse> {
537
- return getAccessToken(this.requestClient, clientId, clientSecret, authCode)
537
+ return getAccessTokenForViya(
538
+ this.requestClient,
539
+ clientId,
540
+ clientSecret,
541
+ authCode
542
+ )
538
543
  }
539
544
 
540
545
  /**
541
546
  * Exchanges the refresh token for an access token for the given client.
542
547
  * @param clientId - the client ID to authenticate with.
543
548
  * @param clientSecret - the client secret to authenticate with.
544
- * @param authCode - the refresh token received from the server.
549
+ * @param refreshToken - the refresh token received from the server.
545
550
  */
546
551
  public async refreshTokens(
547
552
  clientId: string,
548
553
  clientSecret: string,
549
554
  refreshToken: string
550
555
  ) {
551
- return refreshTokens(
556
+ return refreshTokensForViya(
552
557
  this.requestClient,
553
558
  clientId,
554
559
  clientSecret,
package/src/SASjs.ts CHANGED
@@ -11,15 +11,17 @@ import {
11
11
  } from './types'
12
12
  import { SASViyaApiClient } from './SASViyaApiClient'
13
13
  import { SAS9ApiClient } from './SAS9ApiClient'
14
- import { SASjsApiClient } from './SASjsApiClient'
14
+ import { SASjsApiClient, SASjsAuthResponse } from './SASjsApiClient'
15
15
  import { AuthManager } from './auth'
16
16
  import {
17
17
  ServerType,
18
18
  MacroVar,
19
19
  AuthConfig,
20
- ExtraResponseAttributes
20
+ ExtraResponseAttributes,
21
+ SasAuthResponse
21
22
  } from '@sasjs/utils/types'
22
23
  import { RequestClient } from './request/RequestClient'
24
+ import { SasjsRequestClient } from './request/SasjsRequestClient'
23
25
  import {
24
26
  JobExecutor,
25
27
  WebJobExecutor,
@@ -53,7 +55,7 @@ export default class SASjs {
53
55
  private jobsPath: string = ''
54
56
  private sasViyaApiClient: SASViyaApiClient | null = null
55
57
  private sas9ApiClient: SAS9ApiClient | null = null
56
- private SASjsApiClient: SASjsApiClient | null = null
58
+ private sasJSApiClient: SASjsApiClient | null = null
57
59
  private fileUploader: FileUploader | null = null
58
60
  private authManager: AuthManager | null = null
59
61
  private requestClient: RequestClient | null = null
@@ -80,7 +82,7 @@ export default class SASjs {
80
82
  userName: string,
81
83
  password: string
82
84
  ) {
83
- this.isMethodSupported('executeScriptSAS9', ServerType.Sas9)
85
+ this.isMethodSupported('executeScriptSAS9', [ServerType.Sas9])
84
86
 
85
87
  return await this.sas9ApiClient?.executeScript(
86
88
  linesOfCode,
@@ -94,7 +96,7 @@ export default class SASjs {
94
96
  * @param accessToken - an access token for an authorized user.
95
97
  */
96
98
  public async getComputeContexts(accessToken: string) {
97
- this.isMethodSupported('getComputeContexts', ServerType.SasViya)
99
+ this.isMethodSupported('getComputeContexts', [ServerType.SasViya])
98
100
 
99
101
  return await this.sasViyaApiClient!.getComputeContexts(accessToken)
100
102
  }
@@ -104,7 +106,7 @@ export default class SASjs {
104
106
  * @param accessToken - an access token for an authorized user.
105
107
  */
106
108
  public async getLauncherContexts(accessToken: string) {
107
- this.isMethodSupported('getLauncherContexts', ServerType.SasViya)
109
+ this.isMethodSupported('getLauncherContexts', [ServerType.SasViya])
108
110
 
109
111
  return await this.sasViyaApiClient!.getLauncherContexts(accessToken)
110
112
  }
@@ -113,7 +115,7 @@ export default class SASjs {
113
115
  * Gets default(system) launcher contexts.
114
116
  */
115
117
  public getDefaultComputeContexts() {
116
- this.isMethodSupported('getDefaultComputeContexts', ServerType.SasViya)
118
+ this.isMethodSupported('getDefaultComputeContexts', [ServerType.SasViya])
117
119
 
118
120
  return this.sasViyaApiClient!.getDefaultComputeContexts()
119
121
  }
@@ -123,7 +125,7 @@ export default class SASjs {
123
125
  * @param authConfig - an access token, refresh token, client and secret for an authorized user.
124
126
  */
125
127
  public async getExecutableContexts(authConfig: AuthConfig) {
126
- this.isMethodSupported('getExecutableContexts', ServerType.SasViya)
128
+ this.isMethodSupported('getExecutableContexts', [ServerType.SasViya])
127
129
 
128
130
  return await this.sasViyaApiClient!.getExecutableContexts(authConfig)
129
131
  }
@@ -145,7 +147,7 @@ export default class SASjs {
145
147
  accessToken: string,
146
148
  authorizedUsers?: string[]
147
149
  ) {
148
- this.isMethodSupported('createComputeContext', ServerType.SasViya)
150
+ this.isMethodSupported('createComputeContext', [ServerType.SasViya])
149
151
 
150
152
  return await this.sasViyaApiClient!.createComputeContext(
151
153
  contextName,
@@ -170,7 +172,7 @@ export default class SASjs {
170
172
  launchType: string,
171
173
  accessToken: string
172
174
  ) {
173
- this.isMethodSupported('createLauncherContext', ServerType.SasViya)
175
+ this.isMethodSupported('createLauncherContext', [ServerType.SasViya])
174
176
 
175
177
  return await this.sasViyaApiClient!.createLauncherContext(
176
178
  contextName,
@@ -191,7 +193,7 @@ export default class SASjs {
191
193
  editedContext: EditContextInput,
192
194
  accessToken?: string
193
195
  ) {
194
- this.isMethodSupported('editComputeContext', ServerType.SasViya)
196
+ this.isMethodSupported('editComputeContext', [ServerType.SasViya])
195
197
 
196
198
  return await this.sasViyaApiClient!.editComputeContext(
197
199
  contextName,
@@ -206,7 +208,7 @@ export default class SASjs {
206
208
  * @param accessToken - an access token for an authorized user.
207
209
  */
208
210
  public async deleteComputeContext(contextName: string, accessToken?: string) {
209
- this.isMethodSupported('deleteComputeContext', ServerType.SasViya)
211
+ this.isMethodSupported('deleteComputeContext', [ServerType.SasViya])
210
212
 
211
213
  return await this.sasViyaApiClient!.deleteComputeContext(
212
214
  contextName,
@@ -224,7 +226,7 @@ export default class SASjs {
224
226
  contextName: string,
225
227
  accessToken?: string
226
228
  ) {
227
- this.isMethodSupported('getComputeContextByName', ServerType.SasViya)
229
+ this.isMethodSupported('getComputeContextByName', [ServerType.SasViya])
228
230
 
229
231
  return await this.sasViyaApiClient!.getComputeContextByName(
230
232
  contextName,
@@ -238,7 +240,7 @@ export default class SASjs {
238
240
  * @param accessToken - an access token for an authorized user.
239
241
  */
240
242
  public async getComputeContextById(contextId: string, accessToken?: string) {
241
- this.isMethodSupported('getComputeContextById', ServerType.SasViya)
243
+ this.isMethodSupported('getComputeContextById', [ServerType.SasViya])
242
244
 
243
245
  return await this.sasViyaApiClient!.getComputeContextById(
244
246
  contextId,
@@ -247,7 +249,7 @@ export default class SASjs {
247
249
  }
248
250
 
249
251
  public async createSession(contextName: string, accessToken: string) {
250
- this.isMethodSupported('createSession', ServerType.SasViya)
252
+ this.isMethodSupported('createSession', [ServerType.SasViya])
251
253
 
252
254
  return await this.sasViyaApiClient!.createSession(contextName, accessToken)
253
255
  }
@@ -267,7 +269,7 @@ export default class SASjs {
267
269
  authConfig?: AuthConfig,
268
270
  debug?: boolean
269
271
  ) {
270
- this.isMethodSupported('executeScriptSASViya', ServerType.SasViya)
272
+ this.isMethodSupported('executeScriptSASViya', [ServerType.SasViya])
271
273
  if (!contextName) {
272
274
  throw new Error(
273
275
  'Context name is undefined. Please set a `contextName` in your SASjs or override config.'
@@ -357,7 +359,7 @@ export default class SASjs {
357
359
  * @param accessToken - the access token to authorize the request.
358
360
  */
359
361
  public async getFolder(folderPath: string, accessToken?: string) {
360
- this.isMethodSupported('getFolder', ServerType.SasViya)
362
+ this.isMethodSupported('getFolder', [ServerType.SasViya])
361
363
  return await this.sasViyaApiClient!.getFolder(folderPath, accessToken)
362
364
  }
363
365
 
@@ -367,7 +369,7 @@ export default class SASjs {
367
369
  * @param accessToken - an access token for authorizing the request.
368
370
  */
369
371
  public async deleteFolder(folderPath: string, accessToken: string) {
370
- this.isMethodSupported('deleteFolder', ServerType.SasViya)
372
+ this.isMethodSupported('deleteFolder', [ServerType.SasViya])
371
373
 
372
374
  return await this.sasViyaApiClient?.deleteFolder(folderPath, accessToken)
373
375
  }
@@ -382,7 +384,7 @@ export default class SASjs {
382
384
  accessToken?: string,
383
385
  limit?: number
384
386
  ) {
385
- this.isMethodSupported('listFolder', ServerType.SasViya)
387
+ this.isMethodSupported('listFolder', [ServerType.SasViya])
386
388
 
387
389
  return await this.sasViyaApiClient?.listFolder(
388
390
  sourceFolder,
@@ -404,7 +406,7 @@ export default class SASjs {
404
406
  targetFolderName: string,
405
407
  accessToken: string
406
408
  ) {
407
- this.isMethodSupported('moveFolder', ServerType.SasViya)
409
+ this.isMethodSupported('moveFolder', [ServerType.SasViya])
408
410
 
409
411
  return await this.sasViyaApiClient?.moveFolder(
410
412
  sourceFolder,
@@ -422,7 +424,7 @@ export default class SASjs {
422
424
  accessToken?: string,
423
425
  sasApiClient?: SASViyaApiClient
424
426
  ) {
425
- this.isMethodSupported('createJobDefinition', ServerType.SasViya)
427
+ this.isMethodSupported('createJobDefinition', [ServerType.SasViya])
426
428
 
427
429
  if (sasApiClient)
428
430
  return await sasApiClient!.createJobDefinition(
@@ -442,7 +444,7 @@ export default class SASjs {
442
444
  }
443
445
 
444
446
  public async getAuthCode(clientId: string) {
445
- this.isMethodSupported('getAuthCode', ServerType.SasViya)
447
+ this.isMethodSupported('getAuthCode', [ServerType.SasViya])
446
448
 
447
449
  return await this.sasViyaApiClient!.getAuthCode(clientId)
448
450
  }
@@ -457,8 +459,14 @@ export default class SASjs {
457
459
  clientId: string,
458
460
  clientSecret: string,
459
461
  authCode: string
460
- ) {
461
- this.isMethodSupported('getAccessToken', ServerType.SasViya)
462
+ ): Promise<SasAuthResponse | SASjsAuthResponse> {
463
+ this.isMethodSupported('getAccessToken', [
464
+ ServerType.SasViya,
465
+ ServerType.Sasjs
466
+ ])
467
+
468
+ if (this.sasjsConfig.serverType === ServerType.Sasjs)
469
+ return await this.sasJSApiClient!.getAccessToken(clientId, authCode)
462
470
 
463
471
  return await this.sasViyaApiClient!.getAccessToken(
464
472
  clientId,
@@ -467,12 +475,24 @@ export default class SASjs {
467
475
  )
468
476
  }
469
477
 
478
+ /**
479
+ * Exchanges the refresh token for an access token for the given client.
480
+ * @param clientId - the client ID to authenticate with.
481
+ * @param clientSecret - the client secret to authenticate with.
482
+ * @param refreshToken - the refresh token received from the server.
483
+ */
470
484
  public async refreshTokens(
471
485
  clientId: string,
472
486
  clientSecret: string,
473
487
  refreshToken: string
474
- ) {
475
- this.isMethodSupported('refreshTokens', ServerType.SasViya)
488
+ ): Promise<SasAuthResponse | SASjsAuthResponse> {
489
+ this.isMethodSupported('refreshTokens', [
490
+ ServerType.SasViya,
491
+ ServerType.Sasjs
492
+ ])
493
+
494
+ if (this.sasjsConfig.serverType === ServerType.Sasjs)
495
+ return await this.sasJSApiClient!.refreshTokens(refreshToken)
476
496
 
477
497
  return await this.sasViyaApiClient!.refreshTokens(
478
498
  clientId,
@@ -482,7 +502,7 @@ export default class SASjs {
482
502
  }
483
503
 
484
504
  public async deleteClient(clientId: string, accessToken: string) {
485
- this.isMethodSupported('deleteClient', ServerType.SasViya)
505
+ this.isMethodSupported('deleteClient', [ServerType.SasViya])
486
506
 
487
507
  return await this.sasViyaApiClient!.deleteClient(clientId, accessToken)
488
508
  }
@@ -528,29 +548,39 @@ export default class SASjs {
528
548
 
529
549
  /**
530
550
  * Checks whether a session is active, or login is required.
531
- * @param accessToken - an optional access token is required for SASjs server type.
532
551
  * @returns - a promise which resolves with an object containing two values - a boolean `isLoggedIn`, and a string `userName`.
533
552
  */
534
- public async checkSession(accessToken?: string) {
535
- return this.authManager!.checkSession(accessToken)
553
+ public async checkSession() {
554
+ return this.authManager!.checkSession()
536
555
  }
537
556
 
538
557
  /**
539
558
  * Logs into the SAS server with the supplied credentials.
540
559
  * @param username - a string representing the username.
541
560
  * @param password - a string representing the password.
561
+ * @param clientId - a string representing the client ID.
542
562
  */
543
563
  public async logIn(
544
564
  username?: string,
545
565
  password?: string,
566
+ clientId?: string,
546
567
  options: LoginOptions = {}
547
568
  ): Promise<LoginResult> {
548
569
  if (this.sasjsConfig.loginMechanism === LoginMechanism.Default) {
549
- if (!username || !password) {
570
+ if (!username || !password)
550
571
  throw new Error(
551
572
  'A username and password are required when using the default login mechanism.'
552
573
  )
574
+
575
+ if (this.sasjsConfig.serverType === ServerType.Sasjs) {
576
+ if (!clientId)
577
+ throw new Error(
578
+ 'A username, password and clientId are required when using the default login mechanism with server type SASJS.'
579
+ )
580
+
581
+ return this.authManager!.logInSasjs(username, password, clientId)
553
582
  }
583
+
554
584
  return this.authManager!.logIn(username, password)
555
585
  }
556
586
 
@@ -565,10 +595,9 @@ export default class SASjs {
565
595
 
566
596
  /**
567
597
  * Logs out of the configured SAS server.
568
- * @param accessToken - an optional access token is required for SASjs server type.
569
598
  */
570
- public logOut(accessToken?: string) {
571
- return this.authManager!.logOut(accessToken)
599
+ public logOut() {
600
+ return this.authManager!.logOut()
572
601
  }
573
602
 
574
603
  /**
@@ -777,7 +806,7 @@ export default class SASjs {
777
806
  accessToken?: string,
778
807
  isForced = false
779
808
  ) {
780
- this.isMethodSupported('deployServicePack', ServerType.SasViya)
809
+ this.isMethodSupported('deployServicePack', [ServerType.SasViya])
781
810
 
782
811
  let sasApiClient: any = null
783
812
  if (serverUrl || appLoc) {
@@ -832,11 +861,11 @@ export default class SASjs {
832
861
  }
833
862
 
834
863
  public async deployToSASjs(members: [FolderMember, ServiceMember]) {
835
- return await this.SASjsApiClient?.deploy(members, this.sasjsConfig.appLoc)
864
+ return await this.sasJSApiClient?.deploy(members, this.sasjsConfig.appLoc)
836
865
  }
837
866
 
838
867
  public async executeJobSASjs(query: ExecutionQuery) {
839
- return await this.SASjsApiClient?.executeJob(query)
868
+ return await this.sasJSApiClient?.executeJob(query)
840
869
  }
841
870
 
842
871
  /**
@@ -872,7 +901,7 @@ export default class SASjs {
872
901
  ...config
873
902
  }
874
903
 
875
- this.isMethodSupported('startComputeJob', ServerType.SasViya)
904
+ this.isMethodSupported('startComputeJob', [ServerType.SasViya])
876
905
  if (!config.contextName) {
877
906
  throw new Error(
878
907
  'Context name is undefined. Please set a `contextName` in your SASjs or override config.'
@@ -964,7 +993,11 @@ export default class SASjs {
964
993
  }
965
994
 
966
995
  if (!this.requestClient) {
967
- this.requestClient = new RequestClient(
996
+ const RequestClientClass =
997
+ this.sasjsConfig.serverType === ServerType.Sasjs
998
+ ? SasjsRequestClient
999
+ : RequestClient
1000
+ this.requestClient = new RequestClientClass(
968
1001
  this.sasjsConfig.serverUrl,
969
1002
  this.sasjsConfig.httpsAgentOptions
970
1003
  )
@@ -1020,10 +1053,10 @@ export default class SASjs {
1020
1053
  }
1021
1054
 
1022
1055
  if (this.sasjsConfig.serverType === ServerType.Sasjs) {
1023
- if (this.SASjsApiClient) {
1024
- this.SASjsApiClient.setConfig(this.sasjsConfig.serverUrl)
1056
+ if (this.sasJSApiClient) {
1057
+ this.sasJSApiClient.setConfig(this.sasjsConfig.serverUrl)
1025
1058
  } else {
1026
- this.SASjsApiClient = new SASjsApiClient(
1059
+ this.sasJSApiClient = new SASjsApiClient(
1027
1060
  this.sasjsConfig.serverUrl,
1028
1061
  this.requestClient
1029
1062
  )
@@ -1117,12 +1150,15 @@ export default class SASjs {
1117
1150
  })
1118
1151
  }
1119
1152
 
1120
- private isMethodSupported(method: string, serverType: string) {
1121
- if (this.sasjsConfig.serverType !== serverType) {
1153
+ private isMethodSupported(method: string, serverTypes: ServerType[]) {
1154
+ if (
1155
+ !this.sasjsConfig.serverType ||
1156
+ !serverTypes.includes(this.sasjsConfig.serverType)
1157
+ ) {
1122
1158
  throw new Error(
1123
- `Method '${method}' is only supported on ${
1124
- serverType === ServerType.Sas9 ? 'SAS9' : 'SAS Viya'
1125
- } servers.`
1159
+ `Method '${method}' is only supported on ${serverTypes.join(
1160
+ ', '
1161
+ )} servers.`
1126
1162
  )
1127
1163
  }
1128
1164
  }
@@ -1,5 +1,8 @@
1
1
  import { FolderMember, ServiceMember, ExecutionQuery } from './types'
2
2
  import { RequestClient } from './request/RequestClient'
3
+ import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs'
4
+ import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs'
5
+ import { getAuthCodeForSasjs } from './auth/getAuthCodeForSasjs'
3
6
 
4
7
  export class SASjsApiClient {
5
8
  constructor(
@@ -36,4 +39,44 @@ export class SASjsApiClient {
36
39
 
37
40
  return Promise.resolve(result)
38
41
  }
42
+
43
+ /**
44
+ * Exchanges the auth code for an access token for the given client.
45
+ * @param clientId - the client ID to authenticate with.
46
+ * @param authCode - the auth code received from the server.
47
+ */
48
+ public async getAccessToken(
49
+ clientId: string,
50
+ authCode: string
51
+ ): Promise<SASjsAuthResponse> {
52
+ return getAccessTokenForSasjs(this.requestClient, clientId, authCode)
53
+ }
54
+
55
+ /**
56
+ * Exchanges the refresh token for an access token.
57
+ * @param refreshToken - the refresh token received from the server.
58
+ */
59
+ public async refreshTokens(refreshToken: string): Promise<SASjsAuthResponse> {
60
+ return refreshTokensForSasjs(this.requestClient, refreshToken)
61
+ }
62
+
63
+ /**
64
+ * Performs a login authenticate and returns an auth code for the given client.
65
+ * @param username - a string representing the username.
66
+ * @param password - a string representing the password.
67
+ * @param clientId - the client ID to authenticate with.
68
+ */
69
+ public async getAuthCode(
70
+ username: string,
71
+ password: string,
72
+ clientId: string
73
+ ) {
74
+ return getAuthCodeForSasjs(this.requestClient, username, password, clientId)
75
+ }
76
+ }
77
+
78
+ // todo move to sasjs/utils
79
+ export interface SASjsAuthResponse {
80
+ access_token: string
81
+ refresh_token: string
39
82
  }
@@ -2,6 +2,8 @@ import { ServerType } from '@sasjs/utils/types'
2
2
  import { RequestClient } from '../request/RequestClient'
3
3
  import { LoginOptions, LoginResult } from '../types/Login'
4
4
  import { serialize } from '../utils'
5
+ import { getAccessTokenForSasjs } from './getAccessTokenForSasjs'
6
+ import { getAuthCodeForSasjs } from './getAuthCodeForSasjs'
5
7
  import { openWebPage } from './openWebPage'
6
8
  import { verifySas9Login } from './verifySas9Login'
7
9
  import { verifySasViyaLogin } from './verifySasViyaLogin'
@@ -81,6 +83,39 @@ export class AuthManager {
81
83
  return { isLoggedIn: false, userName: '' }
82
84
  }
83
85
 
86
+ /**
87
+ * Logs into the SAS server with the supplied credentials.
88
+ * @param userName - a string representing the username.
89
+ * @param password - a string representing the password.
90
+ * @param clientId - a string representing the client ID.
91
+ * @returns - a boolean `isLoggedin` and a string `username`
92
+ */
93
+ public async logInSasjs(
94
+ username: string,
95
+ password: string,
96
+ clientId: string
97
+ ): Promise<LoginResult> {
98
+ const isLoggedIn = await this.sendLoginRequestSasjs(
99
+ username,
100
+ password,
101
+ clientId
102
+ )
103
+ .then((res) => {
104
+ this.userName = username
105
+ this.requestClient.saveLocalStorageToken(
106
+ res.access_token,
107
+ res.refresh_token
108
+ )
109
+ return true
110
+ })
111
+ .catch(() => false)
112
+
113
+ return {
114
+ isLoggedIn,
115
+ userName: this.userName
116
+ }
117
+ }
118
+
84
119
  /**
85
120
  * Logs into the SAS server with the supplied credentials.
86
121
  * @param username - a string representing the username.
@@ -180,28 +215,41 @@ export class AuthManager {
180
215
  return loginResponse
181
216
  }
182
217
 
218
+ private async sendLoginRequestSasjs(
219
+ username: string,
220
+ password: string,
221
+ clientId: string
222
+ ) {
223
+ const authCode = await getAuthCodeForSasjs(
224
+ this.requestClient,
225
+ username,
226
+ password,
227
+ clientId
228
+ )
229
+ return getAccessTokenForSasjs(this.requestClient, clientId, authCode)
230
+ }
183
231
  /**
184
232
  * Checks whether a session is active, or login is required.
185
- * @param accessToken - an optional access token is required for SASjs server type.
186
233
  * @returns - a promise which resolves with an object containing three values
187
234
  * - a boolean `isLoggedIn`
188
235
  * - a string `userName` and
189
236
  * - a form `loginForm` if not loggedin.
190
237
  */
191
- public async checkSession(accessToken?: string): Promise<{
238
+ public async checkSession(): Promise<{
192
239
  isLoggedIn: boolean
193
240
  userName: string
194
241
  loginForm?: any
195
242
  }> {
196
- const { isLoggedIn, userName } = await this.fetchUserName(accessToken)
243
+ const { isLoggedIn, userName } = await this.fetchUserName()
197
244
  let loginForm = null
198
245
 
199
- if (!isLoggedIn && this.serverType !== ServerType.Sasjs) {
246
+ if (!isLoggedIn) {
200
247
  //We will logout to make sure cookies are removed and login form is presented
201
248
  //Residue can happen in case of session expiration
202
249
  await this.logOut()
203
250
 
204
- loginForm = await this.getNewLoginForm()
251
+ if (this.serverType !== ServerType.Sasjs)
252
+ loginForm = await this.getNewLoginForm()
205
253
  }
206
254
 
207
255
  return Promise.resolve({
@@ -221,7 +269,7 @@ export class AuthManager {
221
269
  return await this.getLoginForm(formResponse)
222
270
  }
223
271
 
224
- private async fetchUserName(accessToken?: string): Promise<{
272
+ private async fetchUserName(): Promise<{
225
273
  isLoggedIn: boolean
226
274
  userName: string
227
275
  }> {
@@ -232,9 +280,8 @@ export class AuthManager {
232
280
  ? `${this.serverUrl}/SASStoredProcess`
233
281
  : `${this.serverUrl}/SASjsApi/session`
234
282
 
235
- // Access token is required for server type `SASjs`
236
283
  const { result: loginResponse } = await this.requestClient
237
- .get<string>(url, accessToken, 'text/plain')
284
+ .get<string>(url, undefined, 'text/plain')
238
285
  .catch((err: any) => {
239
286
  return { result: 'authErr' }
240
287
  })
@@ -315,11 +362,19 @@ export class AuthManager {
315
362
  * Logs out of the configured SAS server.
316
363
  * @param accessToken - an optional access token is required for SASjs server type.
317
364
  */
318
- public logOut(accessToken?: string) {
365
+ public async logOut() {
319
366
  if (this.serverType === ServerType.Sasjs) {
320
- return this.requestClient.post(this.logoutUrl, undefined, accessToken)
367
+ return this.requestClient
368
+ .delete(this.logoutUrl)
369
+ .catch(() => true)
370
+ .finally(() => {
371
+ this.requestClient.clearLocalStorageTokens()
372
+ return true
373
+ })
321
374
  }
375
+
322
376
  this.requestClient.clearCsrfTokens()
377
+
323
378
  return this.requestClient.get(this.logoutUrl, undefined).then(() => true)
324
379
  }
325
380
  }