attlaz-client 1.16.7 → 1.17.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.
@@ -12,7 +12,7 @@ export declare class HttpClient {
12
12
  static HTTP_UNAVAILABLE: number;
13
13
  static HTTP_TIMEOUT: number;
14
14
  static request(request: HttpClientRequest): Promise<HttpClientResponse>;
15
- private static popsicleRequest;
15
+ private static axiosRequest;
16
16
  private static isJson;
17
17
  static formatContentType(input: string): {
18
18
  type: string;
@@ -1,4 +1,5 @@
1
- import { fetch } from 'popsicle';
1
+ // import {fetch} from 'popsicle';
2
+ import axios from 'axios';
2
3
  import { HttpClientResponse } from './HttpClientResponse.js';
3
4
  import { ClientError } from './ClientError.js';
4
5
  export class HttpClient {
@@ -13,7 +14,7 @@ export class HttpClient {
13
14
  static HTTP_UNAVAILABLE = 503;
14
15
  static HTTP_TIMEOUT = 504;
15
16
  static async request(request) {
16
- const response = await HttpClient.popsicleRequest(request);
17
+ const response = await HttpClient.axiosRequest(request);
17
18
  // const response: HttpClientResponse = await HttpClient.superAgentRequest(request);
18
19
  const error = ClientError.byStatus(response.status, response.statusText);
19
20
  if (error !== null && error !== undefined) {
@@ -24,39 +25,74 @@ export class HttpClient {
24
25
  }
25
26
  return response;
26
27
  }
27
- static async popsicleRequest(request) {
28
- const rawRequest = {
28
+ static async axiosRequest(request) {
29
+ const requestConfig = {
29
30
  url: request.getFullUrl(),
30
31
  method: request.method,
31
32
  headers: request.headers,
32
- omitDefaultHeaders: true,
33
- body: request.body,
33
+ data: request.body,
34
34
  };
35
- const rawResponse = await fetch(request.getFullUrl(), rawRequest);
35
+ // TODO: should we share this instance between requests?
36
+ const axiosInstance = axios.create();
37
+ const rawResponse = await axiosInstance.request(requestConfig);
36
38
  const httpResponse = new HttpClientResponse(rawResponse.status, rawResponse.statusText);
37
- for (const header of rawResponse.headers.keys()) {
38
- const headerValue = rawResponse.headers.get(header);
39
+ Object.keys(rawResponse.headers).forEach((header) => {
40
+ const headerValue = rawResponse.headers[header];
39
41
  httpResponse.headers[header] = headerValue === null ? '' : headerValue;
40
- }
41
- httpResponse.body = await rawResponse.text();
42
- if (HttpClient.isJson(httpResponse)) {
43
- let jsonData = null;
44
- if (httpResponse.body !== '') {
45
- try {
46
- jsonData = JSON.parse(httpResponse.body);
47
- }
48
- catch (e) {
49
- // console.error(, {statusText: httpResponse.statusText, error: e});
50
- throw new Error('Unable to parse response data to JSON');
51
- }
52
- }
53
- httpResponse.body = jsonData;
54
- }
55
- else {
56
- // response.body = rawData;
57
- }
42
+ });
43
+ // console.log('Raw', rawResponse.data);
44
+ // console.log('Is json', HttpClient.isJson(httpResponse));
45
+ httpResponse.body = await rawResponse.data;
46
+ // if (HttpClient.isJson(httpResponse)) {
47
+ // let jsonData: object | null = null;
48
+ // if (httpResponse.body !== '') {
49
+ // try {
50
+ // jsonData = JSON.parse(httpResponse.body);
51
+ // } catch (e) {
52
+ // // console.error(, {statusText: httpResponse.statusText, error: e});
53
+ // throw new Error('Unable to parse response data to JSON');
54
+ // }
55
+ // }
56
+ // httpResponse.body = jsonData;
57
+ // } else {
58
+ // // response.body = rawData;
59
+ // }
58
60
  return httpResponse;
59
61
  }
62
+ // private static async popsicleRequest(request: HttpClientRequest): Promise<HttpClientResponse> {
63
+ // const rawRequest: CommonRequestOptions<any> = {
64
+ // url: request.getFullUrl(),
65
+ // method: request.method,
66
+ // headers: request.headers,
67
+ // omitDefaultHeaders: true,
68
+ // body: request.body,
69
+ // } as CommonRequestOptions<any>;
70
+ // const rawResponse: PopsicleResponse = await fetch(request.getFullUrl(), rawRequest);
71
+ // const httpResponse: HttpClientResponse = new HttpClientResponse(rawResponse.status, rawResponse.statusText);
72
+ // for (const header of rawResponse.headers.keys()) {
73
+ // const headerValue: string | null = rawResponse.headers.get(header);
74
+ // httpResponse.headers[header] = headerValue === null ? '' : headerValue;
75
+ // }
76
+ //
77
+ // httpResponse.body = await rawResponse.text();
78
+ // if (HttpClient.isJson(httpResponse)) {
79
+ // let jsonData: object | null = null;
80
+ // if (httpResponse.body !== '') {
81
+ // try {
82
+ // jsonData = JSON.parse(httpResponse.body);
83
+ // } catch (e) {
84
+ // // console.error(, {statusText: httpResponse.statusText, error: e});
85
+ // throw new Error('Unable to parse response data to JSON');
86
+ // }
87
+ // }
88
+ // httpResponse.body = jsonData;
89
+ // } else {
90
+ // // response.body = rawData;
91
+ // }
92
+ //
93
+ //
94
+ // return httpResponse;
95
+ // }
60
96
  // private static async superAgentRequest(request: HttpClientRequest): Promise<HttpClientResponse> {
61
97
  //
62
98
  //
@@ -5,14 +5,14 @@ import { Headers } from './Data/Headers.js';
5
5
  export declare class OAuthClient {
6
6
  private readonly options;
7
7
  private debug;
8
- private oauthClient;
9
- private oauthToken;
8
+ private axiosInstance;
10
9
  private oathClientToken;
11
10
  private refreshTokenPromise;
12
11
  constructor(options: OAuthClientOptions);
13
12
  authenticate(username: string, password: string): Promise<boolean>;
14
13
  authenticate(): Promise<boolean>;
15
14
  refreshToken(): Promise<void>;
15
+ private getAxiosInstance;
16
16
  isTokenExpires(): boolean;
17
17
  request(action: string, parameters?: Parameters, method?: string, signWithOauthToken?: boolean): Promise<any>;
18
18
  isAuthenticated(): boolean;
@@ -22,11 +22,6 @@ export declare class OAuthClient {
22
22
  enableDebug(): void;
23
23
  disableDebug(): void;
24
24
  isDebugEnabled(): boolean;
25
- getTokenFlowUrl(options?: {
26
- query?: {
27
- [key: string]: string | string[];
28
- };
29
- } | null): string;
30
25
  getDefaultHeaders(): Headers;
31
26
  private isNodeEnvironment;
32
27
  private tokenToOauthClientToken;
@@ -1,4 +1,6 @@
1
- import ClientOAuth2 from 'client-oauth2';
1
+ // import ClientOAuth2, {Token} from 'client-oauth2';
2
+ import { clientCredentials, ownerCredentials, refreshToken } from 'axios-oauth-client';
3
+ import axios from 'axios';
2
4
  import { ClientError } from './ClientError.js';
3
5
  import { HttpClient } from './HttpClient.js';
4
6
  import { HttpClientRequest } from './HttpClientRequest.js';
@@ -8,38 +10,44 @@ import { VERSION } from '../version.js';
8
10
  export class OAuthClient {
9
11
  options;
10
12
  debug = false;
11
- oauthClient;
12
- oauthToken = null;
13
+ axiosInstance = null;
14
+ // private oauthClient: ClientOAuth2;
15
+ // private oauthToken: Token | null = null;
13
16
  oathClientToken = null;
14
17
  refreshTokenPromise = null;
15
18
  constructor(options) {
16
19
  this.options = options;
17
- this.oauthClient = new ClientOAuth2({
18
- clientId: options.clientId === null ? undefined : options.clientId,
19
- clientSecret: options.clientSecret === null ? undefined : options.clientSecret,
20
- accessTokenUri: this.getUri(options.accessTokenUri),
21
- authorizationUri: this.getUri(options.authorizationUri),
22
- redirectUri: options.redirectUri,
23
- scopes: options.scopes,
24
- state: options.state,
25
- headers: this.getDefaultHeaders(),
26
- });
20
+ // this.oauthClient = new ClientOAuth2({
21
+ // clientId: options.clientId === null ? undefined : options.clientId,
22
+ // clientSecret: options.clientSecret === null ? undefined : options.clientSecret,
23
+ // accessTokenUri: this.getUri(options.accessTokenUri),
24
+ // authorizationUri: this.getUri(options.authorizationUri),
25
+ // redirectUri: options.redirectUri,
26
+ // scopes: options.scopes,
27
+ // state: options.state,
28
+ // headers: this.getDefaultHeaders(),
29
+ // });
27
30
  }
28
31
  async authenticate(username = null, password = null) {
29
32
  // TODO: should we encrypt the password in the client (or is https save enough)?
30
33
  try {
31
- let accessToken;
32
34
  if (username !== null && username !== undefined && password !== null && password !== undefined) {
33
- // Password flow
34
- accessToken = await this.oauthClient.owner.getToken(username, password);
35
+ // Password flow / Owner Credentials grant
36
+ const getOwnerCredentials = ownerCredentials(this.getAxiosInstance(), this.getUri(this.options.accessTokenUri), this.options.clientId === null ? undefined : this.options.clientId, this.options.clientSecret === null ? undefined : this.options.clientSecret);
37
+ const rawAuthToken = await getOwnerCredentials(username, password, 'OPTIONAL_SCOPES');
38
+ this.oathClientToken = this.tokenToOauthClientToken(rawAuthToken);
39
+ // accessToken = await this.oauthClient.owner.getToken(username, password);
40
+ return true;
35
41
  }
36
- else {
37
- // Client credentials flow
38
- accessToken = await this.oauthClient.credentials.getToken();
39
- }
40
- this.oauthToken = accessToken;
41
- this.oathClientToken = this.tokenToOauthClientToken(this.oauthToken);
42
+ // Client credentials flow
43
+ const getClientCredentials = clientCredentials(this.getAxiosInstance(), this.getUri(this.options.accessTokenUri), this.options.clientId === null ? undefined : this.options.clientId, this.options.clientSecret === null ? undefined : this.options.clientSecret);
44
+ const rawAuthToken = await getClientCredentials('OPTIONAL_SCOPES');
45
+ this.oathClientToken = this.tokenToOauthClientToken(rawAuthToken);
46
+ // accessToken = await this.oauthClient.credentials.getToken();
42
47
  return true;
48
+ // this.oauthToken = accessToken;
49
+ // this.oathClientToken = this.tokenToOauthClientToken(rawAuthToken);
50
+ // return true;
43
51
  }
44
52
  catch (e) {
45
53
  if (this.debug) {
@@ -52,25 +60,37 @@ export class OAuthClient {
52
60
  if (this.debug) {
53
61
  console.debug('[OAuthClient] refresh token');
54
62
  }
55
- if (this.oauthToken === null) {
63
+ if (this.oathClientToken === null) {
56
64
  throw new Error('unable to refresh token, auth token not set');
57
65
  }
58
- if (this.oauthToken.refreshToken === undefined || this.oauthToken.refreshToken === null || this.oauthToken.refreshToken === '') {
66
+ if (this.oathClientToken.refresh_token === undefined || this.oathClientToken.refresh_token === null || this.oathClientToken.refresh_token === '') {
59
67
  throw new Error('unable to refresh token, refresh token not set');
60
68
  }
61
69
  try {
62
- this.oauthToken = await this.oauthToken.refresh();
63
- this.oathClientToken = this.tokenToOauthClientToken(this.oauthToken);
70
+ const getRefreshToken = refreshToken(this.getAxiosInstance(), this.getUri(this.options.accessTokenUri), this.options.clientId === null ? undefined : this.options.clientId, this.options.clientSecret === null ? undefined : this.options.clientSecret);
71
+ const auth = await getRefreshToken(this.oathClientToken.refresh_token, 'OPTIONAL_SCOPES');
72
+ // this.oauthToken = await this.oauthToken.refresh();
73
+ this.oathClientToken = this.tokenToOauthClientToken(auth);
64
74
  }
65
75
  catch (e) {
66
76
  throw ClientError.fromError(e);
67
77
  }
68
78
  }
79
+ getAxiosInstance() {
80
+ if (this.axiosInstance === null) {
81
+ this.axiosInstance = axios.create({
82
+ // httpsAgent: new https.Agent({
83
+ // rejectUnauthorized: false,
84
+ // }),
85
+ });
86
+ }
87
+ return this.axiosInstance;
88
+ }
69
89
  isTokenExpires() {
70
- if (this.oauthToken === null) {
90
+ if (this.oathClientToken === null) {
71
91
  throw new Error('No token defined');
72
92
  }
73
- return this.oauthToken.expired();
93
+ return OAuthClientToken.isExpired(this.oathClientToken);
74
94
  }
75
95
  async request(action, parameters = null, method = 'GET', signWithOauthToken = true) {
76
96
  if (signWithOauthToken && !this.isAuthenticated()) {
@@ -78,10 +98,10 @@ export class OAuthClient {
78
98
  }
79
99
  else {
80
100
  if (signWithOauthToken) {
81
- if (this.oauthToken === null) {
101
+ if (this.oathClientToken === null) {
82
102
  throw new ClientError('Unable to perform request, access token not provided');
83
103
  }
84
- if (signWithOauthToken && this.oauthToken.expired()) {
104
+ if (signWithOauthToken && OAuthClientToken.isExpired(this.oathClientToken)) {
85
105
  if (this.refreshTokenPromise === null) {
86
106
  this.refreshTokenPromise = this.refreshToken();
87
107
  await this.refreshTokenPromise;
@@ -120,30 +140,25 @@ export class OAuthClient {
120
140
  return this.oathClientToken !== null && this.oathClientToken !== undefined;
121
141
  }
122
142
  getToken() {
123
- if (this.oauthToken === null) {
124
- return null;
125
- }
126
- if (this.oathClientToken === null) {
127
- this.oathClientToken = this.tokenToOauthClientToken(this.oauthToken);
128
- }
129
143
  return this.oathClientToken;
130
144
  }
131
145
  setToken(token) {
132
- const data = {
133
- access_token: token.access_token,
134
- token_type: token.token_type,
135
- refresh_token: token.refresh_token,
136
- scope: token.scope,
137
- };
138
- const oauthToken = this.oauthClient.createToken(data);
139
- if (token.expires !== null && token.expires !== undefined) {
140
- oauthToken.expiresIn(token.expires);
141
- }
142
- this.oauthToken = oauthToken;
146
+ // const data: {} = {
147
+ // access_token: token.access_token,
148
+ // token_type: token.token_type,
149
+ // refresh_token: token.refresh_token,
150
+ // scope: token.scope,
151
+ //
152
+ // };
153
+ // const oauthToken: Token = this.oauthClient.createToken(data);
154
+ // if (token.expires !== null && token.expires !== undefined) {
155
+ // oauthToken.expiresIn(token.expires);
156
+ // }
157
+ // this.oauthToken = oauthToken;
143
158
  this.oathClientToken = token;
144
159
  }
145
160
  unsetToken() {
146
- this.oauthToken = null;
161
+ // this.oauthToken = null;
147
162
  this.oathClientToken = null;
148
163
  }
149
164
  enableDebug() {
@@ -155,9 +170,9 @@ export class OAuthClient {
155
170
  isDebugEnabled() {
156
171
  return this.debug;
157
172
  }
158
- getTokenFlowUrl(options = null) {
159
- return this.oauthClient.token.getUri(options === null ? undefined : options);
160
- }
173
+ // public getTokenFlowUrl(options: { query?: { [key: string]: string | string[] } } | null = null): string {
174
+ // return this.oauthClient.token.getUri(options === null ? undefined : options);
175
+ // }
161
176
  getDefaultHeaders() {
162
177
  const userAgentInfo = {
163
178
  version: VERSION,
@@ -175,18 +190,18 @@ export class OAuthClient {
175
190
  return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
176
191
  }
177
192
  tokenToOauthClientToken(oauthToken) {
178
- let scopes = '';
179
- if (Object.prototype.hasOwnProperty.call(oauthToken.data, 'scopes')) {
180
- scopes = oauthToken.data.scopes;
181
- }
182
- else if (Object.prototype.hasOwnProperty.call(oauthToken.data, 'scope')) {
183
- scopes = oauthToken.data.scope;
184
- }
185
- const token = new OAuthClientToken(oauthToken.accessToken, oauthToken.tokenType, oauthToken.refreshToken, scopes);
186
- const rawTokenExpires = oauthToken.expires;
187
- if (rawTokenExpires !== null && rawTokenExpires !== undefined) {
188
- token.expires = rawTokenExpires;
189
- }
193
+ // console.log('Auth token', oauthToken);
194
+ // let scopes: string = '';
195
+ // if (Object.prototype.hasOwnProperty.call(oauthToken.data, 'scopes')) {
196
+ // scopes = oauthToken.data.scopes;
197
+ // } else if (Object.prototype.hasOwnProperty.call(oauthToken.data, 'scope')) {
198
+ // scopes = oauthToken.data.scope;
199
+ // }
200
+ const refreshToken = oauthToken.refresh_token === undefined || oauthToken.refresh_token === null ? null : oauthToken.refresh_token;
201
+ const token = new OAuthClientToken(oauthToken.access_token, oauthToken.token_type, refreshToken, oauthToken.scope);
202
+ const t = new Date();
203
+ t.setSeconds(t.getSeconds() + oauthToken.expires_in);
204
+ token.expires = t;
190
205
  return token;
191
206
  }
192
207
  getUri(uri) {
@@ -219,22 +234,23 @@ export class OAuthClient {
219
234
  });
220
235
  }
221
236
  if (signWithOauthToken) {
222
- if (this.oauthToken === null) {
237
+ if (this.oathClientToken === null) {
223
238
  throw new ClientError('Unable to perform request, access token not provided');
224
239
  }
225
- if (this.oauthToken.expired()) {
240
+ if (OAuthClientToken.isExpired(this.oathClientToken)) {
226
241
  throw new Error('Unable to sign request, token is expired');
227
242
  }
228
243
  requestData = this.signRequest(requestData);
229
244
  }
230
- else {
231
- }
232
245
  return requestData;
233
246
  }
234
247
  signRequest(requestObject) {
235
248
  if (this.oathClientToken === null) {
236
249
  throw new ClientError('Unable to sign request, access token not provided');
237
250
  }
251
+ if (OAuthClientToken.isExpired(this.oathClientToken)) {
252
+ throw new Error('Unable to sign request, token is expired');
253
+ }
238
254
  const tokenType = this.oathClientToken.token_type;
239
255
  const accessToken = this.oathClientToken.access_token;
240
256
  if (tokenType !== undefined && tokenType.toLowerCase() === 'bearer') {
@@ -4,7 +4,7 @@ export declare class OAuthClientToken {
4
4
  refresh_token: string | null;
5
5
  expires: Date | null;
6
6
  scope: string;
7
- constructor(access_token: string, token_type: string, refresh_token: string, scope: string);
7
+ constructor(access_token: string, token_type: string, refresh_token: string | null, scope: string);
8
8
  static isExpired(token: OAuthClientToken): boolean;
9
9
  static serialize(token: OAuthClientToken): string;
10
10
  static deserialize(serializedToken: string): OAuthClientToken;
@@ -1,7 +1,8 @@
1
1
  import { Endpoint } from './Endpoint.js';
2
2
  import { CollectionResult } from '../Model/Result/CollectionResult.js';
3
3
  import { InboxMessage } from '../Model/Inbox/InboxMessage.js';
4
+ import { CursorPagination } from '../Model/Pagination/CursorPagination.js';
4
5
  export declare class InboxEndpoint extends Endpoint {
5
- getAll(unacknowledgedOnly?: boolean): Promise<CollectionResult<InboxMessage>>;
6
+ getAll(pagination?: CursorPagination | null, unacknowledgedOnly?: boolean): Promise<CollectionResult<InboxMessage>>;
6
7
  save(message: InboxMessage): Promise<InboxMessage>;
7
8
  }
@@ -1,8 +1,12 @@
1
1
  import { Endpoint } from './Endpoint.js';
2
2
  import { InboxMessage } from '../Model/Inbox/InboxMessage.js';
3
+ import { QueryString } from '../Http/Data/QueryString.js';
3
4
  export class InboxEndpoint extends Endpoint {
4
- async getAll(unacknowledgedOnly = false) {
5
- const result = await this.requestCollection('/inbox_messages?unacknowledgedOnly=' + unacknowledgedOnly, InboxMessage.parse);
5
+ async getAll(pagination = null, unacknowledgedOnly = false) {
6
+ const queryString = new QueryString('inbox_messages');
7
+ queryString.set('unacknowledgedOnly', unacknowledgedOnly);
8
+ queryString.addPagination(pagination);
9
+ const result = await this.requestCollection(queryString, InboxMessage.parse);
6
10
  return result;
7
11
  }
8
12
  async save(message) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "attlaz-client",
3
- "version": "1.16.7",
3
+ "version": "1.17.0",
4
4
  "description": "Javascript Client to access Attlaz API",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",
@@ -41,19 +41,19 @@
41
41
  "registry": "https://registry.npmjs.org"
42
42
  },
43
43
  "dependencies": {
44
- "client-oauth2": "^4.3.3",
45
- "popsicle": "^12.1.0"
44
+ "axios": "^1.7.7",
45
+ "axios-oauth-client": "^2.2.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/jest": "^29.5.2",
49
49
  "@types/node": "^22.1.0",
50
- "@typescript-eslint/eslint-plugin": "^7.1.0",
51
- "@typescript-eslint/parser": "^7.1.0",
50
+ "@typescript-eslint/eslint-plugin": "^8.12.2",
51
+ "@typescript-eslint/parser": "^8.12.2",
52
52
  "dotenv": "^16.3.1",
53
53
  "eslint": "^8.42.0",
54
54
  "eslint-config-airbnb-base": "^15.0.0",
55
55
  "eslint-plugin-import": "^2.27.5",
56
- "eslint-plugin-jsdoc": "^48.2.0",
56
+ "eslint-plugin-jsdoc": "^50.4.3",
57
57
  "eslint-plugin-prefer-arrow": "^1.2.3",
58
58
  "eslint-plugin-promise": "^7.0.0",
59
59
  "jest": "^29.5.0",
@@ -62,7 +62,7 @@
62
62
  "rollup-plugin-node-resolve": "^5.2.0",
63
63
  "rollup-plugin-typescript": "^1.0.1",
64
64
  "ts-jest": "^29.1.0",
65
- "typescript": "^5.1.3"
65
+ "typescript": "^5.5.4"
66
66
  },
67
67
  "directories": {
68
68
  "test": "test"