rotacloud 1.4.2 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/interfaces/daily-revenue.interface.d.ts +3 -3
- package/dist/cjs/interfaces/sdk-config.interface.d.ts +17 -1
- package/dist/cjs/interfaces/sdk-config.interface.js +6 -0
- package/dist/cjs/rotacloud.d.ts +8 -3
- package/dist/cjs/rotacloud.js +87 -36
- package/dist/cjs/services/service.d.ts +7 -18
- package/dist/cjs/services/service.js +16 -46
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/interfaces/daily-revenue.interface.d.ts +3 -3
- package/dist/mjs/interfaces/sdk-config.interface.d.ts +17 -1
- package/dist/mjs/interfaces/sdk-config.interface.js +5 -1
- package/dist/mjs/rotacloud.d.ts +8 -3
- package/dist/mjs/rotacloud.js +82 -34
- package/dist/mjs/services/service.d.ts +7 -18
- package/dist/mjs/services/service.js +15 -42
- package/dist/mjs/version.js +1 -1
- package/package.json +1 -1
- package/src/interfaces/daily-revenue.interface.ts +3 -3
- package/src/interfaces/sdk-config.interface.ts +21 -1
- package/src/rotacloud.ts +117 -37
- package/src/services/service.ts +17 -63
- package/src/version.ts +1 -1
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { AxiosInterceptorManager, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
|
2
|
-
|
|
2
|
+
export declare enum RetryStrategy {
|
|
3
|
+
Exponential = "expo",
|
|
4
|
+
Static = "static"
|
|
5
|
+
}
|
|
6
|
+
export type RetryOptions = {
|
|
7
|
+
/** Use exponential back-off */
|
|
8
|
+
exponential?: false;
|
|
9
|
+
/** The maximum number of retries before erroring */
|
|
10
|
+
maxRetries: number;
|
|
11
|
+
/** Delay in milliseconds between retry attempts - not used in exponential back-off */
|
|
12
|
+
delay: number;
|
|
13
|
+
} | {
|
|
14
|
+
/** Use exponential back-off */
|
|
15
|
+
exponential: true;
|
|
16
|
+
/** The maximum number of retries before erroring */
|
|
17
|
+
maxRetries: number;
|
|
18
|
+
};
|
|
3
19
|
type RequestInterceptor = Parameters<AxiosInterceptorManager<InternalAxiosRequestConfig>['use']>;
|
|
4
20
|
type ResponseInterceptor = Parameters<AxiosInterceptorManager<AxiosResponse>['use']>;
|
|
5
21
|
export interface SDKBase {
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RetryStrategy = void 0;
|
|
4
|
+
var RetryStrategy;
|
|
5
|
+
(function (RetryStrategy) {
|
|
6
|
+
RetryStrategy["Exponential"] = "expo";
|
|
7
|
+
RetryStrategy["Static"] = "static";
|
|
8
|
+
})(RetryStrategy || (exports.RetryStrategy = RetryStrategy = {}));
|
package/dist/cjs/rotacloud.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AccountsService, AttendanceService, AuthService, AvailabilityService, DailyBudgetsService, DailyRevenueService, DayNotesService, DaysOffService, GroupsService, LeaveEmbargoesService, LeaveRequestService, LeaveTypesService, LeaveService, LocationsService, RolesService, SettingsService, ShiftsService, TerminalsService, TerminalsActiveService, TimeZoneService, ToilAccrualsService, ToilAllowanceService, UsersService, UsersClockInService } from './services/index.js';
|
|
2
|
-
import { SDKConfig } from './interfaces/index.js';
|
|
2
|
+
import { RetryOptions, RetryStrategy, SDKConfig } from './interfaces/index.js';
|
|
3
3
|
import { PinsService } from './services/pins.service.js';
|
|
4
4
|
export declare class RotaCloud {
|
|
5
|
-
static config: SDKConfig;
|
|
6
5
|
private client;
|
|
6
|
+
private sdkConfig;
|
|
7
7
|
defaultAPIURI: string | undefined;
|
|
8
8
|
accounts: AccountsService;
|
|
9
9
|
attendance: AttendanceService;
|
|
@@ -31,10 +31,15 @@ export declare class RotaCloud {
|
|
|
31
31
|
usersClockInService: UsersClockInService;
|
|
32
32
|
users: UsersService;
|
|
33
33
|
constructor(config: SDKConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Overrides undefined config with the default config without removing getters in the object
|
|
36
|
+
*/
|
|
37
|
+
private createConfig;
|
|
34
38
|
get config(): SDKConfig;
|
|
35
39
|
set config(configVal: SDKConfig);
|
|
40
|
+
private setupInterceptors;
|
|
36
41
|
}
|
|
37
|
-
export { RetryStrategy, RetryOptions }
|
|
42
|
+
export { RetryStrategy, RetryOptions };
|
|
38
43
|
export * from './interfaces/index.js';
|
|
39
44
|
export * from './interfaces/query-params/index.js';
|
|
40
45
|
export * from './models/index.js';
|
package/dist/cjs/rotacloud.js
CHANGED
|
@@ -28,18 +28,34 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.RetryStrategy = exports.RotaCloud = void 0;
|
|
30
30
|
const axios_1 = __importStar(require("axios"));
|
|
31
|
+
const axios_retry_1 = __importStar(require("axios-retry"));
|
|
31
32
|
const index_js_1 = require("./services/index.js");
|
|
33
|
+
const index_js_2 = require("./interfaces/index.js");
|
|
34
|
+
Object.defineProperty(exports, "RetryStrategy", { enumerable: true, get: function () { return index_js_2.RetryStrategy; } });
|
|
32
35
|
const pins_service_js_1 = require("./services/pins.service.js");
|
|
33
|
-
const
|
|
36
|
+
const index_js_3 = require("./models/index.js");
|
|
37
|
+
const DEFAULT_RETRIES = 3;
|
|
38
|
+
const DEFAULT_RETRY_DELAY = 2000;
|
|
39
|
+
const DEFAULT_RETRY_STRATEGY_OPTIONS = {
|
|
40
|
+
[index_js_2.RetryStrategy.Exponential]: {
|
|
41
|
+
exponential: true,
|
|
42
|
+
maxRetries: DEFAULT_RETRIES,
|
|
43
|
+
},
|
|
44
|
+
[index_js_2.RetryStrategy.Static]: {
|
|
45
|
+
exponential: false,
|
|
46
|
+
maxRetries: DEFAULT_RETRIES,
|
|
47
|
+
delay: DEFAULT_RETRY_DELAY,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
34
50
|
const DEFAULT_CONFIG = {
|
|
35
51
|
baseUri: 'https://api.rotacloud.com/v1',
|
|
36
|
-
retry:
|
|
52
|
+
retry: index_js_2.RetryStrategy.Exponential,
|
|
37
53
|
};
|
|
38
54
|
function parseClientError(error) {
|
|
39
55
|
var _a;
|
|
40
56
|
const axiosErrorLocation = error.response || error.request;
|
|
41
57
|
const apiErrorMessage = (_a = axiosErrorLocation.data) === null || _a === void 0 ? void 0 : _a.error;
|
|
42
|
-
return new
|
|
58
|
+
return new index_js_3.SDKError({
|
|
43
59
|
code: axiosErrorLocation.status,
|
|
44
60
|
message: apiErrorMessage || error.message,
|
|
45
61
|
data: axiosErrorLocation.data,
|
|
@@ -49,41 +65,77 @@ class RotaCloud {
|
|
|
49
65
|
constructor(config) {
|
|
50
66
|
this.client = axios_1.default.create();
|
|
51
67
|
this.defaultAPIURI = DEFAULT_CONFIG.baseUri;
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this.
|
|
74
|
-
this.
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
68
|
+
this.config = this.createConfig(config);
|
|
69
|
+
const client = this;
|
|
70
|
+
const options = {
|
|
71
|
+
get config() {
|
|
72
|
+
return client.config;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
this.accounts = new index_js_1.AccountsService(this.client, options);
|
|
76
|
+
this.attendance = new index_js_1.AttendanceService(this.client, options);
|
|
77
|
+
this.auth = new index_js_1.AuthService(this.client, options);
|
|
78
|
+
this.availability = new index_js_1.AvailabilityService(this.client, options);
|
|
79
|
+
this.dailyBudgets = new index_js_1.DailyBudgetsService(this.client, options);
|
|
80
|
+
this.dailyRevenue = new index_js_1.DailyRevenueService(this.client, options);
|
|
81
|
+
this.dayNotes = new index_js_1.DayNotesService(this.client, options);
|
|
82
|
+
this.daysOff = new index_js_1.DaysOffService(this.client, options);
|
|
83
|
+
this.group = new index_js_1.GroupsService(this.client, options);
|
|
84
|
+
this.leaveEmbargoes = new index_js_1.LeaveEmbargoesService(this.client, options);
|
|
85
|
+
this.leaveRequests = new index_js_1.LeaveRequestService(this.client, options);
|
|
86
|
+
this.leaveTypes = new index_js_1.LeaveTypesService(this.client, options);
|
|
87
|
+
this.leave = new index_js_1.LeaveService(this.client, options);
|
|
88
|
+
this.locations = new index_js_1.LocationsService(this.client, options);
|
|
89
|
+
this.pins = new pins_service_js_1.PinsService(this.client, options);
|
|
90
|
+
this.roles = new index_js_1.RolesService(this.client, options);
|
|
91
|
+
this.settings = new index_js_1.SettingsService(this.client, options);
|
|
92
|
+
this.shifts = new index_js_1.ShiftsService(this.client, options);
|
|
93
|
+
this.terminals = new index_js_1.TerminalsService(this.client, options);
|
|
94
|
+
this.terminalsActive = new index_js_1.TerminalsActiveService(this.client, options);
|
|
95
|
+
this.timeZone = new index_js_1.TimeZoneService(this.client, options);
|
|
96
|
+
this.toilAccruals = new index_js_1.ToilAccrualsService(this.client, options);
|
|
97
|
+
this.toilAllowance = new index_js_1.ToilAllowanceService(this.client, options);
|
|
98
|
+
this.usersClockInService = new index_js_1.UsersClockInService(this.client, options);
|
|
99
|
+
this.users = new index_js_1.UsersService(this.client, options);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Overrides undefined config with the default config without removing getters in the object
|
|
103
|
+
*/
|
|
104
|
+
createConfig(config) {
|
|
105
|
+
var _a;
|
|
106
|
+
const keys = Object.keys(DEFAULT_CONFIG);
|
|
107
|
+
for (const key of keys) {
|
|
108
|
+
(_a = config[key]) !== null && _a !== void 0 ? _a : (config[key] = DEFAULT_CONFIG[key]);
|
|
109
|
+
}
|
|
110
|
+
return config;
|
|
78
111
|
}
|
|
79
112
|
get config() {
|
|
80
|
-
return
|
|
113
|
+
return this.sdkConfig;
|
|
81
114
|
}
|
|
82
115
|
set config(configVal) {
|
|
83
|
-
|
|
84
|
-
|
|
116
|
+
this.sdkConfig = configVal;
|
|
117
|
+
this.setupInterceptors(configVal.retry, configVal.interceptors);
|
|
118
|
+
}
|
|
119
|
+
setupInterceptors(retry, customInterceptors) {
|
|
120
|
+
var _a, _b;
|
|
85
121
|
this.client.interceptors.request.clear();
|
|
86
122
|
this.client.interceptors.response.clear();
|
|
123
|
+
// NOTE: Retry interceptor - must be setup first
|
|
124
|
+
if (retry) {
|
|
125
|
+
const retryConfig = typeof retry === 'string' ? DEFAULT_RETRY_STRATEGY_OPTIONS[retry] : retry;
|
|
126
|
+
(0, axios_retry_1.default)(this.client, {
|
|
127
|
+
retries: retryConfig.maxRetries,
|
|
128
|
+
shouldResetTimeout: true,
|
|
129
|
+
retryCondition: (err) => { var _a; return (0, axios_retry_1.isNetworkOrIdempotentRequestError)(err) || ((_a = err.response) === null || _a === void 0 ? void 0 : _a.status) === 429; },
|
|
130
|
+
retryDelay: (retryCount) => {
|
|
131
|
+
if (retryConfig.exponential) {
|
|
132
|
+
return axios_retry_1.default.exponentialDelay(retryCount);
|
|
133
|
+
}
|
|
134
|
+
return retryConfig.delay;
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// NOTE: Error interceptor - must be setup after retry but before custom
|
|
87
139
|
this.client.interceptors.response.use((response) => response, (error) => {
|
|
88
140
|
let parsedError = error;
|
|
89
141
|
if ((0, axios_1.isAxiosError)(error)) {
|
|
@@ -91,13 +143,14 @@ class RotaCloud {
|
|
|
91
143
|
}
|
|
92
144
|
return Promise.reject(parsedError);
|
|
93
145
|
});
|
|
94
|
-
|
|
146
|
+
// NOTE: Custom interceptors - must be setup last
|
|
147
|
+
for (const requestInterceptor of (_a = customInterceptors === null || customInterceptors === void 0 ? void 0 : customInterceptors.request) !== null && _a !== void 0 ? _a : []) {
|
|
95
148
|
const callbacks = typeof requestInterceptor === 'function'
|
|
96
149
|
? [requestInterceptor]
|
|
97
150
|
: [requestInterceptor === null || requestInterceptor === void 0 ? void 0 : requestInterceptor.success, requestInterceptor === null || requestInterceptor === void 0 ? void 0 : requestInterceptor.error];
|
|
98
151
|
this.client.interceptors.request.use(...callbacks);
|
|
99
152
|
}
|
|
100
|
-
for (const responseInterceptor of (
|
|
153
|
+
for (const responseInterceptor of (_b = customInterceptors === null || customInterceptors === void 0 ? void 0 : customInterceptors.response) !== null && _b !== void 0 ? _b : []) {
|
|
101
154
|
const callbacks = typeof responseInterceptor === 'function'
|
|
102
155
|
? [responseInterceptor]
|
|
103
156
|
: [responseInterceptor === null || responseInterceptor === void 0 ? void 0 : responseInterceptor.success, responseInterceptor === null || responseInterceptor === void 0 ? void 0 : responseInterceptor.error];
|
|
@@ -106,8 +159,6 @@ class RotaCloud {
|
|
|
106
159
|
}
|
|
107
160
|
}
|
|
108
161
|
exports.RotaCloud = RotaCloud;
|
|
109
|
-
var service_js_1 = require("./services/service.js");
|
|
110
|
-
Object.defineProperty(exports, "RetryStrategy", { enumerable: true, get: function () { return service_js_1.RetryStrategy; } });
|
|
111
162
|
__exportStar(require("./interfaces/index.js"), exports);
|
|
112
163
|
__exportStar(require("./interfaces/query-params/index.js"), exports);
|
|
113
164
|
__exportStar(require("./models/index.js"), exports);
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
+
import { SDKConfig } from "../interfaces";
|
|
2
3
|
export type RequirementsOf<T, K extends keyof T> = Required<Pick<T, K>> & Partial<T>;
|
|
3
|
-
export declare enum RetryStrategy {
|
|
4
|
-
Exponential = "expo",
|
|
5
|
-
Static = "static"
|
|
6
|
-
}
|
|
7
|
-
export type RetryOptions = {
|
|
8
|
-
/** Use exponential back-off */
|
|
9
|
-
exponential?: false;
|
|
10
|
-
/** The maximum number of retries before erroring */
|
|
11
|
-
maxRetries: number;
|
|
12
|
-
/** Delay in milliseconds between retry attempts - not used in exponential back-off */
|
|
13
|
-
delay: number;
|
|
14
|
-
} | {
|
|
15
|
-
/** Use exponential back-off */
|
|
16
|
-
exponential: true;
|
|
17
|
-
/** The maximum number of retries before erroring */
|
|
18
|
-
maxRetries: number;
|
|
19
|
-
};
|
|
20
4
|
export interface Options {
|
|
21
5
|
rawResponse?: boolean;
|
|
22
6
|
limit?: number;
|
|
@@ -28,7 +12,12 @@ export type OptionsExtended<T = unknown> = Options & {
|
|
|
28
12
|
};
|
|
29
13
|
export declare abstract class Service<ApiResponse = any> {
|
|
30
14
|
protected client: AxiosInstance;
|
|
31
|
-
|
|
15
|
+
protected readonly options: {
|
|
16
|
+
config: SDKConfig;
|
|
17
|
+
};
|
|
18
|
+
constructor(client: AxiosInstance, options: {
|
|
19
|
+
config: SDKConfig;
|
|
20
|
+
});
|
|
32
21
|
private isLeaveRequest;
|
|
33
22
|
private buildQueryParams;
|
|
34
23
|
fetch<T = ApiResponse>(reqConfig: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
@@ -24,35 +24,19 @@ var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
|
|
|
24
24
|
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
|
25
25
|
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }
|
|
26
26
|
};
|
|
27
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
29
|
-
};
|
|
30
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.Service =
|
|
32
|
-
const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
33
|
-
const rotacloud_js_1 = require("../rotacloud.js");
|
|
28
|
+
exports.Service = void 0;
|
|
34
29
|
const version_js_1 = require("../version.js");
|
|
35
|
-
var RetryStrategy;
|
|
36
|
-
(function (RetryStrategy) {
|
|
37
|
-
RetryStrategy["Exponential"] = "expo";
|
|
38
|
-
RetryStrategy["Static"] = "static";
|
|
39
|
-
})(RetryStrategy || (exports.RetryStrategy = RetryStrategy = {}));
|
|
40
|
-
const DEFAULT_RETRIES = 3;
|
|
41
|
-
const DEFAULT_RETRY_DELAY = 2000;
|
|
42
|
-
const DEFAULT_RETRY_STRATEGY_OPTIONS = {
|
|
43
|
-
[RetryStrategy.Exponential]: {
|
|
44
|
-
exponential: true,
|
|
45
|
-
maxRetries: DEFAULT_RETRIES,
|
|
46
|
-
},
|
|
47
|
-
[RetryStrategy.Static]: {
|
|
48
|
-
exponential: false,
|
|
49
|
-
maxRetries: DEFAULT_RETRIES,
|
|
50
|
-
delay: DEFAULT_RETRY_DELAY,
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
30
|
class Service {
|
|
54
|
-
constructor(client
|
|
31
|
+
constructor(client,
|
|
32
|
+
// opt to use options object here, so we could
|
|
33
|
+
// define the config property as a getter
|
|
34
|
+
// in RotaCloud class. With this change config in
|
|
35
|
+
// this class will always be up-to-date with
|
|
36
|
+
// RotaCloud client config
|
|
37
|
+
options) {
|
|
55
38
|
this.client = client;
|
|
39
|
+
this.options = options;
|
|
56
40
|
}
|
|
57
41
|
isLeaveRequest(endpoint) {
|
|
58
42
|
return endpoint === '/leave_requests';
|
|
@@ -74,12 +58,12 @@ class Service {
|
|
|
74
58
|
}
|
|
75
59
|
fetch(reqConfig, options) {
|
|
76
60
|
const headers = {
|
|
77
|
-
Authorization:
|
|
78
|
-
? `Bearer ${
|
|
79
|
-
: `Basic ${
|
|
61
|
+
Authorization: this.options.config.apiKey
|
|
62
|
+
? `Bearer ${this.options.config.apiKey}`
|
|
63
|
+
: `Basic ${this.options.config.basicAuth}`,
|
|
80
64
|
'SDK-Version': version_js_1.Version.version,
|
|
81
65
|
};
|
|
82
|
-
const extraHeaders =
|
|
66
|
+
const extraHeaders = this.options.config.headers;
|
|
83
67
|
if (extraHeaders && typeof extraHeaders === 'object') {
|
|
84
68
|
for (const [key, val] of Object.entries(extraHeaders)) {
|
|
85
69
|
if (typeof key === 'string' && typeof val === 'string') {
|
|
@@ -87,28 +71,14 @@ class Service {
|
|
|
87
71
|
}
|
|
88
72
|
}
|
|
89
73
|
}
|
|
90
|
-
if (
|
|
91
|
-
headers.Account = String(
|
|
74
|
+
if (this.options.config.accountId) {
|
|
75
|
+
headers.Account = String(this.options.config.accountId);
|
|
92
76
|
}
|
|
93
77
|
else {
|
|
94
78
|
// need to convert user field in payload to a header for creating leave_requests when using an API key
|
|
95
79
|
this.isLeaveRequest(reqConfig.url) ? (headers.User = `${reqConfig.data.user}`) : undefined;
|
|
96
80
|
}
|
|
97
|
-
const finalReqConfig = Object.assign(Object.assign({}, reqConfig), { baseURL:
|
|
98
|
-
if (rotacloud_js_1.RotaCloud.config.retry) {
|
|
99
|
-
const retryConfig = typeof rotacloud_js_1.RotaCloud.config.retry === 'string'
|
|
100
|
-
? DEFAULT_RETRY_STRATEGY_OPTIONS[rotacloud_js_1.RotaCloud.config.retry]
|
|
101
|
-
: rotacloud_js_1.RotaCloud.config.retry;
|
|
102
|
-
(0, axios_retry_1.default)(this.client, {
|
|
103
|
-
retries: retryConfig.maxRetries,
|
|
104
|
-
retryDelay: (retryCount) => {
|
|
105
|
-
if (retryConfig.exponential) {
|
|
106
|
-
return axios_retry_1.default.exponentialDelay(retryCount);
|
|
107
|
-
}
|
|
108
|
-
return retryConfig.delay;
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
}
|
|
81
|
+
const finalReqConfig = Object.assign(Object.assign({}, reqConfig), { baseURL: this.options.config.baseUri, headers, params: this.buildQueryParams(options, reqConfig.params) });
|
|
112
82
|
return this.client.request(finalReqConfig);
|
|
113
83
|
}
|
|
114
84
|
fetchPages(reqConfig, options) {
|
package/dist/cjs/version.js
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { AxiosInterceptorManager, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
|
2
|
-
|
|
2
|
+
export declare enum RetryStrategy {
|
|
3
|
+
Exponential = "expo",
|
|
4
|
+
Static = "static"
|
|
5
|
+
}
|
|
6
|
+
export type RetryOptions = {
|
|
7
|
+
/** Use exponential back-off */
|
|
8
|
+
exponential?: false;
|
|
9
|
+
/** The maximum number of retries before erroring */
|
|
10
|
+
maxRetries: number;
|
|
11
|
+
/** Delay in milliseconds between retry attempts - not used in exponential back-off */
|
|
12
|
+
delay: number;
|
|
13
|
+
} | {
|
|
14
|
+
/** Use exponential back-off */
|
|
15
|
+
exponential: true;
|
|
16
|
+
/** The maximum number of retries before erroring */
|
|
17
|
+
maxRetries: number;
|
|
18
|
+
};
|
|
3
19
|
type RequestInterceptor = Parameters<AxiosInterceptorManager<InternalAxiosRequestConfig>['use']>;
|
|
4
20
|
type ResponseInterceptor = Parameters<AxiosInterceptorManager<AxiosResponse>['use']>;
|
|
5
21
|
export interface SDKBase {
|
package/dist/mjs/rotacloud.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AccountsService, AttendanceService, AuthService, AvailabilityService, DailyBudgetsService, DailyRevenueService, DayNotesService, DaysOffService, GroupsService, LeaveEmbargoesService, LeaveRequestService, LeaveTypesService, LeaveService, LocationsService, RolesService, SettingsService, ShiftsService, TerminalsService, TerminalsActiveService, TimeZoneService, ToilAccrualsService, ToilAllowanceService, UsersService, UsersClockInService } from './services/index.js';
|
|
2
|
-
import { SDKConfig } from './interfaces/index.js';
|
|
2
|
+
import { RetryOptions, RetryStrategy, SDKConfig } from './interfaces/index.js';
|
|
3
3
|
import { PinsService } from './services/pins.service.js';
|
|
4
4
|
export declare class RotaCloud {
|
|
5
|
-
static config: SDKConfig;
|
|
6
5
|
private client;
|
|
6
|
+
private sdkConfig;
|
|
7
7
|
defaultAPIURI: string | undefined;
|
|
8
8
|
accounts: AccountsService;
|
|
9
9
|
attendance: AttendanceService;
|
|
@@ -31,10 +31,15 @@ export declare class RotaCloud {
|
|
|
31
31
|
usersClockInService: UsersClockInService;
|
|
32
32
|
users: UsersService;
|
|
33
33
|
constructor(config: SDKConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Overrides undefined config with the default config without removing getters in the object
|
|
36
|
+
*/
|
|
37
|
+
private createConfig;
|
|
34
38
|
get config(): SDKConfig;
|
|
35
39
|
set config(configVal: SDKConfig);
|
|
40
|
+
private setupInterceptors;
|
|
36
41
|
}
|
|
37
|
-
export { RetryStrategy, RetryOptions }
|
|
42
|
+
export { RetryStrategy, RetryOptions };
|
|
38
43
|
export * from './interfaces/index.js';
|
|
39
44
|
export * from './interfaces/query-params/index.js';
|
|
40
45
|
export * from './models/index.js';
|
package/dist/mjs/rotacloud.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import axios, { isAxiosError } from 'axios';
|
|
2
|
-
import
|
|
2
|
+
import axiosRetry, { isNetworkOrIdempotentRequestError } from 'axios-retry';
|
|
3
|
+
import { AccountsService, AttendanceService, AuthService, AvailabilityService, DailyBudgetsService, DailyRevenueService, DayNotesService, DaysOffService, GroupsService, LeaveEmbargoesService, LeaveRequestService, LeaveTypesService, LeaveService, LocationsService, RolesService, SettingsService, ShiftsService, TerminalsService, TerminalsActiveService, TimeZoneService, ToilAccrualsService, ToilAllowanceService, UsersService, UsersClockInService, } from './services/index.js';
|
|
4
|
+
import { RetryStrategy } from './interfaces/index.js';
|
|
3
5
|
import { PinsService } from './services/pins.service.js';
|
|
4
6
|
import { SDKError } from './models/index.js';
|
|
7
|
+
const DEFAULT_RETRIES = 3;
|
|
8
|
+
const DEFAULT_RETRY_DELAY = 2000;
|
|
9
|
+
const DEFAULT_RETRY_STRATEGY_OPTIONS = {
|
|
10
|
+
[RetryStrategy.Exponential]: {
|
|
11
|
+
exponential: true,
|
|
12
|
+
maxRetries: DEFAULT_RETRIES,
|
|
13
|
+
},
|
|
14
|
+
[RetryStrategy.Static]: {
|
|
15
|
+
exponential: false,
|
|
16
|
+
maxRetries: DEFAULT_RETRIES,
|
|
17
|
+
delay: DEFAULT_RETRY_DELAY,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
5
20
|
const DEFAULT_CONFIG = {
|
|
6
21
|
baseUri: 'https://api.rotacloud.com/v1',
|
|
7
22
|
retry: RetryStrategy.Exponential,
|
|
@@ -19,43 +34,75 @@ export class RotaCloud {
|
|
|
19
34
|
constructor(config) {
|
|
20
35
|
this.client = axios.create();
|
|
21
36
|
this.defaultAPIURI = DEFAULT_CONFIG.baseUri;
|
|
22
|
-
this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.dayNotes = new DayNotesService(this.client);
|
|
29
|
-
this.daysOff = new DaysOffService(this.client);
|
|
30
|
-
this.group = new GroupsService(this.client);
|
|
31
|
-
this.leaveEmbargoes = new LeaveEmbargoesService(this.client);
|
|
32
|
-
this.leaveRequests = new LeaveRequestService(this.client);
|
|
33
|
-
this.leaveTypes = new LeaveTypesService(this.client);
|
|
34
|
-
this.leave = new LeaveService(this.client);
|
|
35
|
-
this.locations = new LocationsService(this.client);
|
|
36
|
-
this.pins = new PinsService(this.client);
|
|
37
|
-
this.roles = new RolesService(this.client);
|
|
38
|
-
this.settings = new SettingsService(this.client);
|
|
39
|
-
this.shifts = new ShiftsService(this.client);
|
|
40
|
-
this.terminals = new TerminalsService(this.client);
|
|
41
|
-
this.terminalsActive = new TerminalsActiveService(this.client);
|
|
42
|
-
this.timeZone = new TimeZoneService(this.client);
|
|
43
|
-
this.toilAccruals = new ToilAccrualsService(this.client);
|
|
44
|
-
this.toilAllowance = new ToilAllowanceService(this.client);
|
|
45
|
-
this.usersClockInService = new UsersClockInService(this.client);
|
|
46
|
-
this.users = new UsersService(this.client);
|
|
47
|
-
this.config = {
|
|
48
|
-
...DEFAULT_CONFIG,
|
|
49
|
-
...config,
|
|
37
|
+
this.config = this.createConfig(config);
|
|
38
|
+
const client = this;
|
|
39
|
+
const options = {
|
|
40
|
+
get config() {
|
|
41
|
+
return client.config;
|
|
42
|
+
}
|
|
50
43
|
};
|
|
44
|
+
this.accounts = new AccountsService(this.client, options);
|
|
45
|
+
this.attendance = new AttendanceService(this.client, options);
|
|
46
|
+
this.auth = new AuthService(this.client, options);
|
|
47
|
+
this.availability = new AvailabilityService(this.client, options);
|
|
48
|
+
this.dailyBudgets = new DailyBudgetsService(this.client, options);
|
|
49
|
+
this.dailyRevenue = new DailyRevenueService(this.client, options);
|
|
50
|
+
this.dayNotes = new DayNotesService(this.client, options);
|
|
51
|
+
this.daysOff = new DaysOffService(this.client, options);
|
|
52
|
+
this.group = new GroupsService(this.client, options);
|
|
53
|
+
this.leaveEmbargoes = new LeaveEmbargoesService(this.client, options);
|
|
54
|
+
this.leaveRequests = new LeaveRequestService(this.client, options);
|
|
55
|
+
this.leaveTypes = new LeaveTypesService(this.client, options);
|
|
56
|
+
this.leave = new LeaveService(this.client, options);
|
|
57
|
+
this.locations = new LocationsService(this.client, options);
|
|
58
|
+
this.pins = new PinsService(this.client, options);
|
|
59
|
+
this.roles = new RolesService(this.client, options);
|
|
60
|
+
this.settings = new SettingsService(this.client, options);
|
|
61
|
+
this.shifts = new ShiftsService(this.client, options);
|
|
62
|
+
this.terminals = new TerminalsService(this.client, options);
|
|
63
|
+
this.terminalsActive = new TerminalsActiveService(this.client, options);
|
|
64
|
+
this.timeZone = new TimeZoneService(this.client, options);
|
|
65
|
+
this.toilAccruals = new ToilAccrualsService(this.client, options);
|
|
66
|
+
this.toilAllowance = new ToilAllowanceService(this.client, options);
|
|
67
|
+
this.usersClockInService = new UsersClockInService(this.client, options);
|
|
68
|
+
this.users = new UsersService(this.client, options);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Overrides undefined config with the default config without removing getters in the object
|
|
72
|
+
*/
|
|
73
|
+
createConfig(config) {
|
|
74
|
+
const keys = Object.keys(DEFAULT_CONFIG);
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
config[key] ?? (config[key] = DEFAULT_CONFIG[key]);
|
|
77
|
+
}
|
|
78
|
+
return config;
|
|
51
79
|
}
|
|
52
80
|
get config() {
|
|
53
|
-
return
|
|
81
|
+
return this.sdkConfig;
|
|
54
82
|
}
|
|
55
83
|
set config(configVal) {
|
|
56
|
-
|
|
84
|
+
this.sdkConfig = configVal;
|
|
85
|
+
this.setupInterceptors(configVal.retry, configVal.interceptors);
|
|
86
|
+
}
|
|
87
|
+
setupInterceptors(retry, customInterceptors) {
|
|
57
88
|
this.client.interceptors.request.clear();
|
|
58
89
|
this.client.interceptors.response.clear();
|
|
90
|
+
// NOTE: Retry interceptor - must be setup first
|
|
91
|
+
if (retry) {
|
|
92
|
+
const retryConfig = typeof retry === 'string' ? DEFAULT_RETRY_STRATEGY_OPTIONS[retry] : retry;
|
|
93
|
+
axiosRetry(this.client, {
|
|
94
|
+
retries: retryConfig.maxRetries,
|
|
95
|
+
shouldResetTimeout: true,
|
|
96
|
+
retryCondition: (err) => isNetworkOrIdempotentRequestError(err) || err.response?.status === 429,
|
|
97
|
+
retryDelay: (retryCount) => {
|
|
98
|
+
if (retryConfig.exponential) {
|
|
99
|
+
return axiosRetry.exponentialDelay(retryCount);
|
|
100
|
+
}
|
|
101
|
+
return retryConfig.delay;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
// NOTE: Error interceptor - must be setup after retry but before custom
|
|
59
106
|
this.client.interceptors.response.use((response) => response, (error) => {
|
|
60
107
|
let parsedError = error;
|
|
61
108
|
if (isAxiosError(error)) {
|
|
@@ -63,13 +110,14 @@ export class RotaCloud {
|
|
|
63
110
|
}
|
|
64
111
|
return Promise.reject(parsedError);
|
|
65
112
|
});
|
|
66
|
-
|
|
113
|
+
// NOTE: Custom interceptors - must be setup last
|
|
114
|
+
for (const requestInterceptor of customInterceptors?.request ?? []) {
|
|
67
115
|
const callbacks = typeof requestInterceptor === 'function'
|
|
68
116
|
? [requestInterceptor]
|
|
69
117
|
: [requestInterceptor?.success, requestInterceptor?.error];
|
|
70
118
|
this.client.interceptors.request.use(...callbacks);
|
|
71
119
|
}
|
|
72
|
-
for (const responseInterceptor of
|
|
120
|
+
for (const responseInterceptor of customInterceptors?.response ?? []) {
|
|
73
121
|
const callbacks = typeof responseInterceptor === 'function'
|
|
74
122
|
? [responseInterceptor]
|
|
75
123
|
: [responseInterceptor?.success, responseInterceptor?.error];
|
|
@@ -77,7 +125,7 @@ export class RotaCloud {
|
|
|
77
125
|
}
|
|
78
126
|
}
|
|
79
127
|
}
|
|
80
|
-
export { RetryStrategy }
|
|
128
|
+
export { RetryStrategy };
|
|
81
129
|
export * from './interfaces/index.js';
|
|
82
130
|
export * from './interfaces/query-params/index.js';
|
|
83
131
|
export * from './models/index.js';
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
+
import { SDKConfig } from "../interfaces";
|
|
2
3
|
export type RequirementsOf<T, K extends keyof T> = Required<Pick<T, K>> & Partial<T>;
|
|
3
|
-
export declare enum RetryStrategy {
|
|
4
|
-
Exponential = "expo",
|
|
5
|
-
Static = "static"
|
|
6
|
-
}
|
|
7
|
-
export type RetryOptions = {
|
|
8
|
-
/** Use exponential back-off */
|
|
9
|
-
exponential?: false;
|
|
10
|
-
/** The maximum number of retries before erroring */
|
|
11
|
-
maxRetries: number;
|
|
12
|
-
/** Delay in milliseconds between retry attempts - not used in exponential back-off */
|
|
13
|
-
delay: number;
|
|
14
|
-
} | {
|
|
15
|
-
/** Use exponential back-off */
|
|
16
|
-
exponential: true;
|
|
17
|
-
/** The maximum number of retries before erroring */
|
|
18
|
-
maxRetries: number;
|
|
19
|
-
};
|
|
20
4
|
export interface Options {
|
|
21
5
|
rawResponse?: boolean;
|
|
22
6
|
limit?: number;
|
|
@@ -28,7 +12,12 @@ export type OptionsExtended<T = unknown> = Options & {
|
|
|
28
12
|
};
|
|
29
13
|
export declare abstract class Service<ApiResponse = any> {
|
|
30
14
|
protected client: AxiosInstance;
|
|
31
|
-
|
|
15
|
+
protected readonly options: {
|
|
16
|
+
config: SDKConfig;
|
|
17
|
+
};
|
|
18
|
+
constructor(client: AxiosInstance, options: {
|
|
19
|
+
config: SDKConfig;
|
|
20
|
+
});
|
|
32
21
|
private isLeaveRequest;
|
|
33
22
|
private buildQueryParams;
|
|
34
23
|
fetch<T = ApiResponse>(reqConfig: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
import axiosRetry from 'axios-retry';
|
|
2
|
-
import { RotaCloud } from '../rotacloud.js';
|
|
3
1
|
import { Version } from '../version.js';
|
|
4
|
-
export var RetryStrategy;
|
|
5
|
-
(function (RetryStrategy) {
|
|
6
|
-
RetryStrategy["Exponential"] = "expo";
|
|
7
|
-
RetryStrategy["Static"] = "static";
|
|
8
|
-
})(RetryStrategy || (RetryStrategy = {}));
|
|
9
|
-
const DEFAULT_RETRIES = 3;
|
|
10
|
-
const DEFAULT_RETRY_DELAY = 2000;
|
|
11
|
-
const DEFAULT_RETRY_STRATEGY_OPTIONS = {
|
|
12
|
-
[RetryStrategy.Exponential]: {
|
|
13
|
-
exponential: true,
|
|
14
|
-
maxRetries: DEFAULT_RETRIES,
|
|
15
|
-
},
|
|
16
|
-
[RetryStrategy.Static]: {
|
|
17
|
-
exponential: false,
|
|
18
|
-
maxRetries: DEFAULT_RETRIES,
|
|
19
|
-
delay: DEFAULT_RETRY_DELAY,
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
2
|
export class Service {
|
|
23
|
-
constructor(client
|
|
3
|
+
constructor(client,
|
|
4
|
+
// opt to use options object here, so we could
|
|
5
|
+
// define the config property as a getter
|
|
6
|
+
// in RotaCloud class. With this change config in
|
|
7
|
+
// this class will always be up-to-date with
|
|
8
|
+
// RotaCloud client config
|
|
9
|
+
options) {
|
|
24
10
|
this.client = client;
|
|
11
|
+
this.options = options;
|
|
25
12
|
}
|
|
26
13
|
isLeaveRequest(endpoint) {
|
|
27
14
|
return endpoint === '/leave_requests';
|
|
@@ -49,12 +36,12 @@ export class Service {
|
|
|
49
36
|
}
|
|
50
37
|
fetch(reqConfig, options) {
|
|
51
38
|
const headers = {
|
|
52
|
-
Authorization:
|
|
53
|
-
? `Bearer ${
|
|
54
|
-
: `Basic ${
|
|
39
|
+
Authorization: this.options.config.apiKey
|
|
40
|
+
? `Bearer ${this.options.config.apiKey}`
|
|
41
|
+
: `Basic ${this.options.config.basicAuth}`,
|
|
55
42
|
'SDK-Version': Version.version,
|
|
56
43
|
};
|
|
57
|
-
const extraHeaders =
|
|
44
|
+
const extraHeaders = this.options.config.headers;
|
|
58
45
|
if (extraHeaders && typeof extraHeaders === 'object') {
|
|
59
46
|
for (const [key, val] of Object.entries(extraHeaders)) {
|
|
60
47
|
if (typeof key === 'string' && typeof val === 'string') {
|
|
@@ -62,8 +49,8 @@ export class Service {
|
|
|
62
49
|
}
|
|
63
50
|
}
|
|
64
51
|
}
|
|
65
|
-
if (
|
|
66
|
-
headers.Account = String(
|
|
52
|
+
if (this.options.config.accountId) {
|
|
53
|
+
headers.Account = String(this.options.config.accountId);
|
|
67
54
|
}
|
|
68
55
|
else {
|
|
69
56
|
// need to convert user field in payload to a header for creating leave_requests when using an API key
|
|
@@ -71,24 +58,10 @@ export class Service {
|
|
|
71
58
|
}
|
|
72
59
|
const finalReqConfig = {
|
|
73
60
|
...reqConfig,
|
|
74
|
-
baseURL:
|
|
61
|
+
baseURL: this.options.config.baseUri,
|
|
75
62
|
headers,
|
|
76
63
|
params: this.buildQueryParams(options, reqConfig.params),
|
|
77
64
|
};
|
|
78
|
-
if (RotaCloud.config.retry) {
|
|
79
|
-
const retryConfig = typeof RotaCloud.config.retry === 'string'
|
|
80
|
-
? DEFAULT_RETRY_STRATEGY_OPTIONS[RotaCloud.config.retry]
|
|
81
|
-
: RotaCloud.config.retry;
|
|
82
|
-
axiosRetry(this.client, {
|
|
83
|
-
retries: retryConfig.maxRetries,
|
|
84
|
-
retryDelay: (retryCount) => {
|
|
85
|
-
if (retryConfig.exponential) {
|
|
86
|
-
return axiosRetry.exponentialDelay(retryCount);
|
|
87
|
-
}
|
|
88
|
-
return retryConfig.delay;
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
65
|
return this.client.request(finalReqConfig);
|
|
93
66
|
}
|
|
94
67
|
async *fetchPages(reqConfig, options) {
|
package/dist/mjs/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const Version = { version: '1.4.
|
|
1
|
+
export const Version = { version: '1.4.4' };
|
package/package.json
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { AxiosInterceptorManager, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
export enum RetryStrategy {
|
|
4
|
+
Exponential = 'expo',
|
|
5
|
+
Static = 'static',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type RetryOptions =
|
|
9
|
+
| {
|
|
10
|
+
/** Use exponential back-off */
|
|
11
|
+
exponential?: false;
|
|
12
|
+
/** The maximum number of retries before erroring */
|
|
13
|
+
maxRetries: number;
|
|
14
|
+
/** Delay in milliseconds between retry attempts - not used in exponential back-off */
|
|
15
|
+
delay: number;
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
/** Use exponential back-off */
|
|
19
|
+
exponential: true;
|
|
20
|
+
/** The maximum number of retries before erroring */
|
|
21
|
+
maxRetries: number;
|
|
22
|
+
};
|
|
3
23
|
|
|
4
24
|
type RequestInterceptor = Parameters<AxiosInterceptorManager<InternalAxiosRequestConfig>['use']>;
|
|
5
25
|
type ResponseInterceptor = Parameters<AxiosInterceptorManager<AxiosResponse>['use']>;
|
package/src/rotacloud.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import axios, { AxiosError, isAxiosError } from 'axios';
|
|
2
|
+
import axiosRetry, { isNetworkOrIdempotentRequestError } from 'axios-retry';
|
|
2
3
|
import {
|
|
3
4
|
AccountsService,
|
|
4
5
|
AttendanceService,
|
|
@@ -14,7 +15,6 @@ import {
|
|
|
14
15
|
LeaveTypesService,
|
|
15
16
|
LeaveService,
|
|
16
17
|
LocationsService,
|
|
17
|
-
RetryStrategy,
|
|
18
18
|
RolesService,
|
|
19
19
|
SettingsService,
|
|
20
20
|
ShiftsService,
|
|
@@ -26,10 +26,25 @@ import {
|
|
|
26
26
|
UsersService,
|
|
27
27
|
UsersClockInService,
|
|
28
28
|
} from './services/index.js';
|
|
29
|
-
import { SDKBase, SDKConfig } from './interfaces/index.js';
|
|
29
|
+
import { RetryOptions, RetryStrategy, SDKBase, SDKConfig } from './interfaces/index.js';
|
|
30
30
|
import { PinsService } from './services/pins.service.js';
|
|
31
31
|
import { SDKError } from './models/index.js';
|
|
32
32
|
|
|
33
|
+
const DEFAULT_RETRIES = 3;
|
|
34
|
+
const DEFAULT_RETRY_DELAY = 2000;
|
|
35
|
+
|
|
36
|
+
const DEFAULT_RETRY_STRATEGY_OPTIONS: Record<RetryStrategy, RetryOptions> = {
|
|
37
|
+
[RetryStrategy.Exponential]: {
|
|
38
|
+
exponential: true,
|
|
39
|
+
maxRetries: DEFAULT_RETRIES,
|
|
40
|
+
},
|
|
41
|
+
[RetryStrategy.Static]: {
|
|
42
|
+
exponential: false,
|
|
43
|
+
maxRetries: DEFAULT_RETRIES,
|
|
44
|
+
delay: DEFAULT_RETRY_DELAY,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
33
48
|
const DEFAULT_CONFIG: Partial<SDKBase> = {
|
|
34
49
|
baseUri: 'https://api.rotacloud.com/v1',
|
|
35
50
|
retry: RetryStrategy.Exponential,
|
|
@@ -46,51 +61,114 @@ function parseClientError(error: AxiosError): SDKError {
|
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
export class RotaCloud {
|
|
49
|
-
static config: SDKConfig;
|
|
50
64
|
private client = axios.create();
|
|
65
|
+
private sdkConfig: SDKConfig;
|
|
51
66
|
|
|
52
67
|
defaultAPIURI = DEFAULT_CONFIG.baseUri;
|
|
53
|
-
accounts
|
|
54
|
-
attendance
|
|
55
|
-
auth
|
|
56
|
-
availability
|
|
57
|
-
dailyBudgets
|
|
58
|
-
dailyRevenue
|
|
59
|
-
dayNotes
|
|
60
|
-
daysOff
|
|
61
|
-
group
|
|
62
|
-
leaveEmbargoes
|
|
63
|
-
leaveRequests
|
|
64
|
-
leaveTypes
|
|
65
|
-
leave
|
|
66
|
-
locations
|
|
67
|
-
pins
|
|
68
|
-
roles
|
|
69
|
-
settings
|
|
70
|
-
shifts
|
|
71
|
-
terminals
|
|
72
|
-
terminalsActive
|
|
73
|
-
timeZone
|
|
74
|
-
toilAccruals
|
|
75
|
-
toilAllowance
|
|
76
|
-
usersClockInService
|
|
77
|
-
users
|
|
68
|
+
accounts: AccountsService;
|
|
69
|
+
attendance: AttendanceService;
|
|
70
|
+
auth: AuthService;
|
|
71
|
+
availability: AvailabilityService;
|
|
72
|
+
dailyBudgets: DailyBudgetsService;
|
|
73
|
+
dailyRevenue: DailyRevenueService;
|
|
74
|
+
dayNotes: DayNotesService;
|
|
75
|
+
daysOff: DaysOffService;
|
|
76
|
+
group: GroupsService;
|
|
77
|
+
leaveEmbargoes: LeaveEmbargoesService;
|
|
78
|
+
leaveRequests: LeaveRequestService;
|
|
79
|
+
leaveTypes: LeaveTypesService;
|
|
80
|
+
leave: LeaveService;
|
|
81
|
+
locations: LocationsService;
|
|
82
|
+
pins: PinsService;
|
|
83
|
+
roles: RolesService;
|
|
84
|
+
settings: SettingsService;
|
|
85
|
+
shifts: ShiftsService;
|
|
86
|
+
terminals: TerminalsService;
|
|
87
|
+
terminalsActive: TerminalsActiveService;
|
|
88
|
+
timeZone: TimeZoneService;
|
|
89
|
+
toilAccruals: ToilAccrualsService;
|
|
90
|
+
toilAllowance: ToilAllowanceService;
|
|
91
|
+
usersClockInService: UsersClockInService;
|
|
92
|
+
users: UsersService;
|
|
78
93
|
|
|
79
94
|
constructor(config: SDKConfig) {
|
|
80
|
-
this.config =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
this.config = this.createConfig(config);
|
|
96
|
+
const client = this;
|
|
97
|
+
const options = {
|
|
98
|
+
get config(): SDKConfig {
|
|
99
|
+
return client.config;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.accounts = new AccountsService(this.client, options);
|
|
104
|
+
this.attendance = new AttendanceService(this.client, options);
|
|
105
|
+
this.auth = new AuthService(this.client, options);
|
|
106
|
+
this.availability = new AvailabilityService(this.client, options);
|
|
107
|
+
this.dailyBudgets = new DailyBudgetsService(this.client, options);
|
|
108
|
+
this.dailyRevenue = new DailyRevenueService(this.client, options);
|
|
109
|
+
this.dayNotes = new DayNotesService(this.client, options);
|
|
110
|
+
this.daysOff = new DaysOffService(this.client, options);
|
|
111
|
+
this.group = new GroupsService(this.client, options);
|
|
112
|
+
this.leaveEmbargoes = new LeaveEmbargoesService(this.client, options);
|
|
113
|
+
this.leaveRequests = new LeaveRequestService(this.client, options);
|
|
114
|
+
this.leaveTypes = new LeaveTypesService(this.client, options);
|
|
115
|
+
this.leave = new LeaveService(this.client, options);
|
|
116
|
+
this.locations = new LocationsService(this.client, options);
|
|
117
|
+
this.pins = new PinsService(this.client, options);
|
|
118
|
+
this.roles = new RolesService(this.client, options);
|
|
119
|
+
this.settings = new SettingsService(this.client, options);
|
|
120
|
+
this.shifts = new ShiftsService(this.client, options);
|
|
121
|
+
this.terminals = new TerminalsService(this.client, options);
|
|
122
|
+
this.terminalsActive = new TerminalsActiveService(this.client, options);
|
|
123
|
+
this.timeZone = new TimeZoneService(this.client, options);
|
|
124
|
+
this.toilAccruals = new ToilAccrualsService(this.client, options);
|
|
125
|
+
this.toilAllowance = new ToilAllowanceService(this.client, options);
|
|
126
|
+
this.usersClockInService = new UsersClockInService(this.client, options);
|
|
127
|
+
this.users = new UsersService(this.client, options);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Overrides undefined config with the default config without removing getters in the object
|
|
132
|
+
*/
|
|
133
|
+
private createConfig(config: SDKConfig): SDKConfig {
|
|
134
|
+
const keys = Object.keys(DEFAULT_CONFIG) as (keyof typeof DEFAULT_CONFIG)[];
|
|
135
|
+
for (const key of keys) {
|
|
136
|
+
config[key] ??= DEFAULT_CONFIG[key];
|
|
137
|
+
}
|
|
138
|
+
return config;
|
|
84
139
|
}
|
|
85
140
|
|
|
86
141
|
get config() {
|
|
87
|
-
return
|
|
142
|
+
return this.sdkConfig;
|
|
88
143
|
}
|
|
89
144
|
|
|
90
145
|
set config(configVal: SDKConfig) {
|
|
91
|
-
|
|
146
|
+
this.sdkConfig = configVal;
|
|
147
|
+
this.setupInterceptors(configVal.retry, configVal.interceptors);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private setupInterceptors(retry: SDKConfig['retry'], customInterceptors: SDKConfig['interceptors']) {
|
|
92
151
|
this.client.interceptors.request.clear();
|
|
93
152
|
this.client.interceptors.response.clear();
|
|
153
|
+
|
|
154
|
+
// NOTE: Retry interceptor - must be setup first
|
|
155
|
+
if (retry) {
|
|
156
|
+
const retryConfig = typeof retry === 'string' ? DEFAULT_RETRY_STRATEGY_OPTIONS[retry] : retry;
|
|
157
|
+
|
|
158
|
+
axiosRetry(this.client, {
|
|
159
|
+
retries: retryConfig.maxRetries,
|
|
160
|
+
shouldResetTimeout: true,
|
|
161
|
+
retryCondition: (err) => isNetworkOrIdempotentRequestError(err) || err.response?.status === 429,
|
|
162
|
+
retryDelay: (retryCount) => {
|
|
163
|
+
if (retryConfig.exponential) {
|
|
164
|
+
return axiosRetry.exponentialDelay(retryCount);
|
|
165
|
+
}
|
|
166
|
+
return retryConfig.delay;
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// NOTE: Error interceptor - must be setup after retry but before custom
|
|
94
172
|
this.client.interceptors.response.use(
|
|
95
173
|
(response) => response,
|
|
96
174
|
(error: unknown) => {
|
|
@@ -101,14 +179,16 @@ export class RotaCloud {
|
|
|
101
179
|
return Promise.reject(parsedError);
|
|
102
180
|
},
|
|
103
181
|
);
|
|
104
|
-
|
|
182
|
+
|
|
183
|
+
// NOTE: Custom interceptors - must be setup last
|
|
184
|
+
for (const requestInterceptor of customInterceptors?.request ?? []) {
|
|
105
185
|
const callbacks =
|
|
106
186
|
typeof requestInterceptor === 'function'
|
|
107
187
|
? ([requestInterceptor] as const)
|
|
108
188
|
: ([requestInterceptor?.success, requestInterceptor?.error] as const);
|
|
109
189
|
this.client.interceptors.request.use(...callbacks);
|
|
110
190
|
}
|
|
111
|
-
for (const responseInterceptor of
|
|
191
|
+
for (const responseInterceptor of customInterceptors?.response ?? []) {
|
|
112
192
|
const callbacks =
|
|
113
193
|
typeof responseInterceptor === 'function'
|
|
114
194
|
? ([responseInterceptor] as const)
|
|
@@ -118,7 +198,7 @@ export class RotaCloud {
|
|
|
118
198
|
}
|
|
119
199
|
}
|
|
120
200
|
|
|
121
|
-
export { RetryStrategy, RetryOptions }
|
|
201
|
+
export { RetryStrategy, RetryOptions };
|
|
122
202
|
export * from './interfaces/index.js';
|
|
123
203
|
export * from './interfaces/query-params/index.js';
|
|
124
204
|
export * from './models/index.js';
|
package/src/services/service.ts
CHANGED
|
@@ -1,31 +1,9 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
-
import axiosRetry from 'axios-retry';
|
|
3
|
-
import { RotaCloud } from '../rotacloud.js';
|
|
4
2
|
import { Version } from '../version.js';
|
|
3
|
+
import { SDKConfig } from "../interfaces";
|
|
5
4
|
|
|
6
5
|
export type RequirementsOf<T, K extends keyof T> = Required<Pick<T, K>> & Partial<T>;
|
|
7
6
|
|
|
8
|
-
export enum RetryStrategy {
|
|
9
|
-
Exponential = 'expo',
|
|
10
|
-
Static = 'static',
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type RetryOptions =
|
|
14
|
-
| {
|
|
15
|
-
/** Use exponential back-off */
|
|
16
|
-
exponential?: false;
|
|
17
|
-
/** The maximum number of retries before erroring */
|
|
18
|
-
maxRetries: number;
|
|
19
|
-
/** Delay in milliseconds between retry attempts - not used in exponential back-off */
|
|
20
|
-
delay: number;
|
|
21
|
-
}
|
|
22
|
-
| {
|
|
23
|
-
/** Use exponential back-off */
|
|
24
|
-
exponential: true;
|
|
25
|
-
/** The maximum number of retries before erroring */
|
|
26
|
-
maxRetries: number;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
7
|
export interface Options {
|
|
30
8
|
rawResponse?: boolean;
|
|
31
9
|
limit?: number;
|
|
@@ -37,26 +15,19 @@ export type OptionsExtended<T = unknown> = Options & {
|
|
|
37
15
|
fields?: (keyof T)[];
|
|
38
16
|
};
|
|
39
17
|
|
|
40
|
-
const DEFAULT_RETRIES = 3;
|
|
41
|
-
const DEFAULT_RETRY_DELAY = 2000;
|
|
42
|
-
|
|
43
|
-
const DEFAULT_RETRY_STRATEGY_OPTIONS: Record<RetryStrategy, RetryOptions> = {
|
|
44
|
-
[RetryStrategy.Exponential]: {
|
|
45
|
-
exponential: true,
|
|
46
|
-
maxRetries: DEFAULT_RETRIES,
|
|
47
|
-
},
|
|
48
|
-
[RetryStrategy.Static]: {
|
|
49
|
-
exponential: false,
|
|
50
|
-
maxRetries: DEFAULT_RETRIES,
|
|
51
|
-
delay: DEFAULT_RETRY_DELAY,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
18
|
type ParameterPrimitive = string | boolean | number | null | symbol;
|
|
56
19
|
type ParameterValue = ParameterPrimitive | ParameterPrimitive[] | undefined;
|
|
57
20
|
|
|
58
21
|
export abstract class Service<ApiResponse = any> {
|
|
59
|
-
constructor(
|
|
22
|
+
constructor(
|
|
23
|
+
protected client: AxiosInstance,
|
|
24
|
+
// opt to use options object here, so we could
|
|
25
|
+
// define the config property as a getter
|
|
26
|
+
// in RotaCloud class. With this change config in
|
|
27
|
+
// this class will always be up-to-date with
|
|
28
|
+
// RotaCloud client config
|
|
29
|
+
protected readonly options: { config: SDKConfig }
|
|
30
|
+
) {}
|
|
60
31
|
|
|
61
32
|
private isLeaveRequest(endpoint?: string): boolean {
|
|
62
33
|
return endpoint === '/leave_requests';
|
|
@@ -102,13 +73,13 @@ export abstract class Service<ApiResponse = any> {
|
|
|
102
73
|
fetch<T = ApiResponse>(reqConfig: AxiosRequestConfig, options?: Options): Promise<AxiosResponse<T | Partial<T>>>;
|
|
103
74
|
fetch<T = ApiResponse>(reqConfig: AxiosRequestConfig, options?: Options) {
|
|
104
75
|
const headers: Record<string, string> = {
|
|
105
|
-
Authorization:
|
|
106
|
-
? `Bearer ${
|
|
107
|
-
: `Basic ${
|
|
76
|
+
Authorization: this.options.config.apiKey
|
|
77
|
+
? `Bearer ${this.options.config.apiKey}`
|
|
78
|
+
: `Basic ${this.options.config.basicAuth}`,
|
|
108
79
|
'SDK-Version': Version.version,
|
|
109
80
|
};
|
|
110
81
|
|
|
111
|
-
const extraHeaders =
|
|
82
|
+
const extraHeaders = this.options.config.headers;
|
|
112
83
|
if (extraHeaders && typeof extraHeaders === 'object') {
|
|
113
84
|
for (const [key, val] of Object.entries(extraHeaders)) {
|
|
114
85
|
if (typeof key === 'string' && typeof val === 'string') {
|
|
@@ -117,8 +88,8 @@ export abstract class Service<ApiResponse = any> {
|
|
|
117
88
|
}
|
|
118
89
|
}
|
|
119
90
|
|
|
120
|
-
if (
|
|
121
|
-
headers.Account = String(
|
|
91
|
+
if (this.options.config.accountId) {
|
|
92
|
+
headers.Account = String(this.options.config.accountId);
|
|
122
93
|
} else {
|
|
123
94
|
// need to convert user field in payload to a header for creating leave_requests when using an API key
|
|
124
95
|
this.isLeaveRequest(reqConfig.url) ? (headers.User = `${reqConfig.data.user}`) : undefined;
|
|
@@ -126,28 +97,11 @@ export abstract class Service<ApiResponse = any> {
|
|
|
126
97
|
|
|
127
98
|
const finalReqConfig: AxiosRequestConfig<T> = {
|
|
128
99
|
...reqConfig,
|
|
129
|
-
baseURL:
|
|
100
|
+
baseURL: this.options.config.baseUri,
|
|
130
101
|
headers,
|
|
131
102
|
params: this.buildQueryParams(options, reqConfig.params),
|
|
132
103
|
};
|
|
133
104
|
|
|
134
|
-
if (RotaCloud.config.retry) {
|
|
135
|
-
const retryConfig =
|
|
136
|
-
typeof RotaCloud.config.retry === 'string'
|
|
137
|
-
? DEFAULT_RETRY_STRATEGY_OPTIONS[RotaCloud.config.retry]
|
|
138
|
-
: RotaCloud.config.retry;
|
|
139
|
-
|
|
140
|
-
axiosRetry(this.client, {
|
|
141
|
-
retries: retryConfig.maxRetries,
|
|
142
|
-
retryDelay: (retryCount) => {
|
|
143
|
-
if (retryConfig.exponential) {
|
|
144
|
-
return axiosRetry.exponentialDelay(retryCount);
|
|
145
|
-
}
|
|
146
|
-
return retryConfig.delay;
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
105
|
return this.client.request<T>(finalReqConfig);
|
|
152
106
|
}
|
|
153
107
|
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const Version = { version: '1.4.
|
|
1
|
+
export const Version = { version: '1.4.4' };
|