rotacloud 1.0.33 → 1.0.34

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.
@@ -8,7 +8,6 @@ export interface UsersQueryParams {
8
8
  search?: string;
9
9
  order?: string;
10
10
  period?: string;
11
- location?: number;
12
11
  start_time?: number;
13
12
  end_time?: number;
14
13
  start_date?: string;
@@ -27,11 +27,11 @@ export declare abstract class Service<ApiResponse = any> {
27
27
  protected client: AxiosInstance;
28
28
  isLeaveRequest(endpoint?: string): boolean;
29
29
  private buildQueryStr;
30
- private getPagingObject;
30
+ private parsePageLinkHeader;
31
31
  fetch<T = ApiResponse>(httpOptions: AxiosRequestConfig, options?: Options): Promise<AxiosResponse<T>>;
32
32
  private listFetch;
33
33
  private listResponses;
34
- iterator<T = ApiResponse>(reqObject: any, options?: Options): {
34
+ iterator<T = ApiResponse>(reqObject: AxiosRequestConfig<T[]>, options?: Options): {
35
35
  [Symbol.asyncIterator](): {
36
36
  next(): Promise<IteratorResult<T, void>>;
37
37
  };
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
12
3
  var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
13
4
  if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
@@ -67,6 +58,8 @@ class Service {
67
58
  return endpoint === '/leave_requests';
68
59
  }
69
60
  buildQueryStr(queryParams) {
61
+ if (!queryParams)
62
+ return '';
70
63
  const reducedParams = Object.entries(queryParams).reduce((params, [key, val]) => {
71
64
  if (val !== undefined && val !== '') {
72
65
  if (Array.isArray(val))
@@ -78,70 +71,63 @@ class Service {
78
71
  }, []);
79
72
  return new URLSearchParams(reducedParams).toString();
80
73
  }
81
- getPagingObject(res) {
82
- const links = res.headers.link.split(',');
83
- const keyVal = {};
84
- links.forEach((link) => {
85
- const exp = link.split(';');
86
- const key = exp[1].replace(' rel="', '').replace('"', '').trim();
87
- const value = exp[0].replace('<', '').replace('>', '').trim();
88
- keyVal[key] = value;
89
- });
90
- return keyVal;
74
+ parsePageLinkHeader(linkHeader) {
75
+ var _a, _b;
76
+ const pageData = {};
77
+ for (const link of linkHeader.split(',')) {
78
+ const { rel, url } = (_b = (_a = link.match(/<(?<url>.*)>; rel="(?<rel>\w*)"/)) === null || _a === void 0 ? void 0 : _a.groups) !== null && _b !== void 0 ? _b : {};
79
+ pageData[rel] = url;
80
+ }
81
+ return pageData;
91
82
  }
92
83
  fetch(httpOptions, options) {
93
- return __awaiter(this, void 0, void 0, function* () {
94
- const headers = {
95
- Authorization: `Bearer ${rotacloud_js_1.RotaCloud.config.apiKey}`,
96
- 'SDK-Version': version_js_1.Version.version,
97
- };
98
- if (rotacloud_js_1.RotaCloud.config.accountId) {
99
- headers.Account = String(rotacloud_js_1.RotaCloud.config.accountId);
100
- }
101
- else {
102
- // need to convert user field in payload to a header for creating leave_requests when using an API key
103
- this.isLeaveRequest(httpOptions.url) ? (headers.User = `${httpOptions.data.user}`) : undefined;
104
- }
105
- const reqObject = Object.assign(Object.assign({}, httpOptions), { baseURL: rotacloud_js_1.RotaCloud.config.baseUri, headers, params: Object.assign({ expand: options === null || options === void 0 ? void 0 : options.expand, fields: options === null || options === void 0 ? void 0 : options.fields, limit: options === null || options === void 0 ? void 0 : options.limit }, httpOptions === null || httpOptions === void 0 ? void 0 : httpOptions.params), paramsSerializer: (params) => {
106
- return params ? this.buildQueryStr(params) : '';
107
- } });
108
- if (rotacloud_js_1.RotaCloud.config.retry) {
109
- const retryConfig = typeof rotacloud_js_1.RotaCloud.config.retry === 'string'
110
- ? DEFAULT_RETRY_STRATEGY_OPTIONS[rotacloud_js_1.RotaCloud.config.retry]
111
- : rotacloud_js_1.RotaCloud.config.retry;
112
- (0, axios_retry_1.default)(this.client, {
113
- retries: retryConfig.maxRetries,
114
- retryDelay: (retryCount) => {
115
- if (retryConfig.exponential) {
116
- return axios_retry_1.default.exponentialDelay(retryCount);
117
- }
118
- return retryConfig.delay;
119
- },
120
- });
121
- }
122
- const response = yield this.client.request(reqObject);
123
- return response;
124
- });
84
+ const headers = {
85
+ Authorization: `Bearer ${rotacloud_js_1.RotaCloud.config.apiKey}`,
86
+ 'SDK-Version': version_js_1.Version.version,
87
+ };
88
+ if (rotacloud_js_1.RotaCloud.config.accountId) {
89
+ headers.Account = String(rotacloud_js_1.RotaCloud.config.accountId);
90
+ }
91
+ else {
92
+ // need to convert user field in payload to a header for creating leave_requests when using an API key
93
+ this.isLeaveRequest(httpOptions.url) ? (headers.User = `${httpOptions.data.user}`) : undefined;
94
+ }
95
+ const reqObject = Object.assign(Object.assign({}, httpOptions), { baseURL: rotacloud_js_1.RotaCloud.config.baseUri, headers, params: Object.assign({ expand: options === null || options === void 0 ? void 0 : options.expand, fields: options === null || options === void 0 ? void 0 : options.fields, limit: options === null || options === void 0 ? void 0 : options.limit }, httpOptions === null || httpOptions === void 0 ? void 0 : httpOptions.params), paramsSerializer: this.buildQueryStr });
96
+ if (rotacloud_js_1.RotaCloud.config.retry) {
97
+ const retryConfig = typeof rotacloud_js_1.RotaCloud.config.retry === 'string'
98
+ ? DEFAULT_RETRY_STRATEGY_OPTIONS[rotacloud_js_1.RotaCloud.config.retry]
99
+ : rotacloud_js_1.RotaCloud.config.retry;
100
+ (0, axios_retry_1.default)(this.client, {
101
+ retries: retryConfig.maxRetries,
102
+ retryDelay: (retryCount) => {
103
+ if (retryConfig.exponential) {
104
+ return axios_retry_1.default.exponentialDelay(retryCount);
105
+ }
106
+ return retryConfig.delay;
107
+ },
108
+ });
109
+ }
110
+ return this.client.request(reqObject);
125
111
  }
126
112
  listFetch(reqObject, options) {
113
+ var _a;
127
114
  return __asyncGenerator(this, arguments, function* listFetch_1() {
128
- let running = true;
129
- do {
130
- const res = yield __await(this.fetch(reqObject, options));
131
- if (res.headers.link) {
132
- const pagingObject = this.getPagingObject(res);
133
- if (pagingObject.last) {
134
- reqObject.url = pagingObject.next;
135
- }
136
- else {
137
- running = false;
138
- }
139
- }
140
- else {
141
- running = false;
142
- }
115
+ let pageRequestObject = reqObject;
116
+ let currentPageUrl = pageRequestObject.url;
117
+ let pageRemaining = true;
118
+ while (pageRemaining) {
119
+ const res = yield __await(this.fetch(pageRequestObject, options));
120
+ const pageLinkMap = this.parsePageLinkHeader((_a = res.headers.link) !== null && _a !== void 0 ? _a : '');
121
+ pageRemaining = Boolean(pageLinkMap.next);
122
+ // NOTE: query params including paging options are included in the "next" link
123
+ pageRequestObject = { url: pageLinkMap.next };
143
124
  yield yield __await(res);
144
- } while (running);
125
+ // Failsafe incase the page does not change
126
+ if (currentPageUrl === pageRequestObject.url) {
127
+ throw new Error('Next page link did not change');
128
+ }
129
+ currentPageUrl = pageRequestObject.url;
130
+ }
145
131
  });
146
132
  }
147
133
  listResponses(reqObject, options) {
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Version = void 0;
4
- exports.Version = { version: '1.0.33' };
4
+ exports.Version = { version: '1.0.34' };
@@ -8,7 +8,6 @@ export interface UsersQueryParams {
8
8
  search?: string;
9
9
  order?: string;
10
10
  period?: string;
11
- location?: number;
12
11
  start_time?: number;
13
12
  end_time?: number;
14
13
  start_date?: string;
@@ -27,11 +27,11 @@ export declare abstract class Service<ApiResponse = any> {
27
27
  protected client: AxiosInstance;
28
28
  isLeaveRequest(endpoint?: string): boolean;
29
29
  private buildQueryStr;
30
- private getPagingObject;
30
+ private parsePageLinkHeader;
31
31
  fetch<T = ApiResponse>(httpOptions: AxiosRequestConfig, options?: Options): Promise<AxiosResponse<T>>;
32
32
  private listFetch;
33
33
  private listResponses;
34
- iterator<T = ApiResponse>(reqObject: any, options?: Options): {
34
+ iterator<T = ApiResponse>(reqObject: AxiosRequestConfig<T[]>, options?: Options): {
35
35
  [Symbol.asyncIterator](): {
36
36
  next(): Promise<IteratorResult<T, void>>;
37
37
  };
@@ -28,6 +28,8 @@ export class Service {
28
28
  return endpoint === '/leave_requests';
29
29
  }
30
30
  buildQueryStr(queryParams) {
31
+ if (!queryParams)
32
+ return '';
31
33
  const reducedParams = Object.entries(queryParams).reduce((params, [key, val]) => {
32
34
  if (val !== undefined && val !== '') {
33
35
  if (Array.isArray(val))
@@ -39,18 +41,15 @@ export class Service {
39
41
  }, []);
40
42
  return new URLSearchParams(reducedParams).toString();
41
43
  }
42
- getPagingObject(res) {
43
- const links = res.headers.link.split(',');
44
- const keyVal = {};
45
- links.forEach((link) => {
46
- const exp = link.split(';');
47
- const key = exp[1].replace(' rel="', '').replace('"', '').trim();
48
- const value = exp[0].replace('<', '').replace('>', '').trim();
49
- keyVal[key] = value;
50
- });
51
- return keyVal;
44
+ parsePageLinkHeader(linkHeader) {
45
+ const pageData = {};
46
+ for (const link of linkHeader.split(',')) {
47
+ const { rel, url } = link.match(/<(?<url>.*)>; rel="(?<rel>\w*)"/)?.groups ?? {};
48
+ pageData[rel] = url;
49
+ }
50
+ return pageData;
52
51
  }
53
- async fetch(httpOptions, options) {
52
+ fetch(httpOptions, options) {
54
53
  const headers = {
55
54
  Authorization: `Bearer ${RotaCloud.config.apiKey}`,
56
55
  'SDK-Version': Version.version,
@@ -72,9 +71,7 @@ export class Service {
72
71
  limit: options?.limit,
73
72
  ...httpOptions?.params,
74
73
  },
75
- paramsSerializer: (params) => {
76
- return params ? this.buildQueryStr(params) : '';
77
- },
74
+ paramsSerializer: this.buildQueryStr,
78
75
  };
79
76
  if (RotaCloud.config.retry) {
80
77
  const retryConfig = typeof RotaCloud.config.retry === 'string'
@@ -90,27 +87,25 @@ export class Service {
90
87
  },
91
88
  });
92
89
  }
93
- const response = await this.client.request(reqObject);
94
- return response;
90
+ return this.client.request(reqObject);
95
91
  }
96
92
  async *listFetch(reqObject, options) {
97
- let running = true;
98
- do {
99
- const res = await this.fetch(reqObject, options);
100
- if (res.headers.link) {
101
- const pagingObject = this.getPagingObject(res);
102
- if (pagingObject.last) {
103
- reqObject.url = pagingObject.next;
104
- }
105
- else {
106
- running = false;
107
- }
108
- }
109
- else {
110
- running = false;
111
- }
93
+ let pageRequestObject = reqObject;
94
+ let currentPageUrl = pageRequestObject.url;
95
+ let pageRemaining = true;
96
+ while (pageRemaining) {
97
+ const res = await this.fetch(pageRequestObject, options);
98
+ const pageLinkMap = this.parsePageLinkHeader(res.headers.link ?? '');
99
+ pageRemaining = Boolean(pageLinkMap.next);
100
+ // NOTE: query params including paging options are included in the "next" link
101
+ pageRequestObject = { url: pageLinkMap.next };
112
102
  yield res;
113
- } while (running);
103
+ // Failsafe incase the page does not change
104
+ if (currentPageUrl === pageRequestObject.url) {
105
+ throw new Error('Next page link did not change');
106
+ }
107
+ currentPageUrl = pageRequestObject.url;
108
+ }
114
109
  }
115
110
  async *listResponses(reqObject, options) {
116
111
  for await (const res of this.listFetch(reqObject, options)) {
@@ -1 +1 @@
1
- export const Version = { version: '1.0.33' };
1
+ export const Version = { version: '1.0.34' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rotacloud",
3
- "version": "1.0.33",
3
+ "version": "1.0.34",
4
4
  "description": "The RotaCloud SDK for the RotaCloud API",
5
5
  "engines": {
6
6
  "node": ">=14.17.0"
@@ -8,7 +8,6 @@ export interface UsersQueryParams {
8
8
  search?: string;
9
9
  order?: string;
10
10
  period?: string;
11
- location?: number;
12
11
  start_time?: number;
13
12
  end_time?: number;
14
13
  start_date?: string;
@@ -65,7 +65,8 @@ export abstract class Service<ApiResponse = any> {
65
65
  return endpoint === '/leave_requests';
66
66
  }
67
67
 
68
- private buildQueryStr(queryParams: Record<string, ParameterValue>) {
68
+ private buildQueryStr(queryParams: Record<string, ParameterValue> | undefined) {
69
+ if (!queryParams) return '';
69
70
  const reducedParams = Object.entries(queryParams).reduce((params, [key, val]) => {
70
71
  if (val !== undefined && val !== '') {
71
72
  if (Array.isArray(val)) params.push(...val.map((item) => [`${key}[]`, String(item)]));
@@ -77,20 +78,17 @@ export abstract class Service<ApiResponse = any> {
77
78
  return new URLSearchParams(reducedParams).toString();
78
79
  }
79
80
 
80
- private getPagingObject(res): Partial<PagingObject> {
81
- const links = res.headers.link.split(',');
82
- const keyVal = {};
83
-
84
- links.forEach((link) => {
85
- const exp = link.split(';');
86
- const key = exp[1].replace(' rel="', '').replace('"', '').trim();
87
- const value = exp[0].replace('<', '').replace('>', '').trim();
88
- keyVal[key] = value;
89
- });
90
- return keyVal;
81
+ private parsePageLinkHeader(linkHeader: string): Partial<PagingObject> {
82
+ const pageData = {};
83
+ for (const link of linkHeader.split(',')) {
84
+ const { rel, url } = link.match(/<(?<url>.*)>; rel="(?<rel>\w*)"/)?.groups ?? {};
85
+ pageData[rel] = url;
86
+ }
87
+
88
+ return pageData;
91
89
  }
92
90
 
93
- public async fetch<T = ApiResponse>(httpOptions: AxiosRequestConfig, options?: Options): Promise<AxiosResponse<T>> {
91
+ public fetch<T = ApiResponse>(httpOptions: AxiosRequestConfig, options?: Options): Promise<AxiosResponse<T>> {
94
92
  const headers: AxiosRequestHeaders = {
95
93
  Authorization: `Bearer ${RotaCloud.config.apiKey}`,
96
94
  'SDK-Version': Version.version,
@@ -112,9 +110,7 @@ export abstract class Service<ApiResponse = any> {
112
110
  limit: options?.limit,
113
111
  ...httpOptions?.params,
114
112
  },
115
- paramsSerializer: (params) => {
116
- return params ? this.buildQueryStr(params) : '';
117
- },
113
+ paramsSerializer: this.buildQueryStr,
118
114
  };
119
115
 
120
116
  if (RotaCloud.config.retry) {
@@ -134,38 +130,40 @@ export abstract class Service<ApiResponse = any> {
134
130
  });
135
131
  }
136
132
 
137
- const response = await this.client.request<T>(reqObject);
138
- return response;
133
+ return this.client.request<T>(reqObject);
139
134
  }
140
135
 
141
136
  private async *listFetch<T = ApiResponse>(
142
137
  reqObject: AxiosRequestConfig<T[]>,
143
138
  options?: Options
144
139
  ): AsyncGenerator<AxiosResponse<T[], any>> {
145
- let running = true;
146
- do {
147
- const res = await this.fetch<T[]>(reqObject, options);
148
- if (res.headers.link) {
149
- const pagingObject = this.getPagingObject(res);
150
- if (pagingObject.last) {
151
- reqObject.url = pagingObject.next;
152
- } else {
153
- running = false;
154
- }
155
- } else {
156
- running = false;
157
- }
140
+ let pageRequestObject = reqObject;
141
+ let currentPageUrl = pageRequestObject.url;
142
+
143
+ let pageRemaining = true;
144
+ while (pageRemaining) {
145
+ const res = await this.fetch<T[]>(pageRequestObject, options);
146
+ const pageLinkMap = this.parsePageLinkHeader(res.headers.link ?? '');
147
+ pageRemaining = Boolean(pageLinkMap.next);
148
+ // NOTE: query params including paging options are included in the "next" link
149
+ pageRequestObject = { url: pageLinkMap.next };
158
150
  yield res;
159
- } while (running);
151
+
152
+ // Failsafe incase the page does not change
153
+ if (currentPageUrl === pageRequestObject.url) {
154
+ throw new Error('Next page link did not change');
155
+ }
156
+ currentPageUrl = pageRequestObject.url;
157
+ }
160
158
  }
161
159
 
162
- private async *listResponses<T = ApiResponse>(reqObject, options?: Options) {
160
+ private async *listResponses<T = ApiResponse>(reqObject: AxiosRequestConfig<T[]>, options?: Options) {
163
161
  for await (const res of this.listFetch<T>(reqObject, options)) {
164
162
  yield* res.data;
165
163
  }
166
164
  }
167
165
 
168
- public iterator<T = ApiResponse>(reqObject, options?: Options) {
166
+ public iterator<T = ApiResponse>(reqObject: AxiosRequestConfig<T[]>, options?: Options) {
169
167
  const iterator = this.listResponses<T>(reqObject, options);
170
168
  return {
171
169
  [Symbol.asyncIterator]() {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const Version = { version: '1.0.33' };
1
+ export const Version = { version: '1.0.34' };