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.
@@ -1,7 +1,7 @@
1
1
  export interface DailyRevenue {
2
2
  date: string;
3
3
  location: number;
4
- labour_percentage: number;
5
- revenue_target: number;
6
- revenue_actual: number;
4
+ labour_percentage: number | null;
5
+ revenue_target: number | null;
6
+ revenue_actual: number | null;
7
7
  }
@@ -1,5 +1,21 @@
1
1
  import { AxiosInterceptorManager, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
2
- import { RetryOptions, RetryStrategy } from '../services/service.js';
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 = {}));
@@ -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 } from './services/service.js';
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';
@@ -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 index_js_2 = require("./models/index.js");
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: index_js_1.RetryStrategy.Exponential,
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 index_js_2.SDKError({
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.accounts = new index_js_1.AccountsService(this.client);
53
- this.attendance = new index_js_1.AttendanceService(this.client);
54
- this.auth = new index_js_1.AuthService(this.client);
55
- this.availability = new index_js_1.AvailabilityService(this.client);
56
- this.dailyBudgets = new index_js_1.DailyBudgetsService(this.client);
57
- this.dailyRevenue = new index_js_1.DailyRevenueService(this.client);
58
- this.dayNotes = new index_js_1.DayNotesService(this.client);
59
- this.daysOff = new index_js_1.DaysOffService(this.client);
60
- this.group = new index_js_1.GroupsService(this.client);
61
- this.leaveEmbargoes = new index_js_1.LeaveEmbargoesService(this.client);
62
- this.leaveRequests = new index_js_1.LeaveRequestService(this.client);
63
- this.leaveTypes = new index_js_1.LeaveTypesService(this.client);
64
- this.leave = new index_js_1.LeaveService(this.client);
65
- this.locations = new index_js_1.LocationsService(this.client);
66
- this.pins = new pins_service_js_1.PinsService(this.client);
67
- this.roles = new index_js_1.RolesService(this.client);
68
- this.settings = new index_js_1.SettingsService(this.client);
69
- this.shifts = new index_js_1.ShiftsService(this.client);
70
- this.terminals = new index_js_1.TerminalsService(this.client);
71
- this.terminalsActive = new index_js_1.TerminalsActiveService(this.client);
72
- this.timeZone = new index_js_1.TimeZoneService(this.client);
73
- this.toilAccruals = new index_js_1.ToilAccrualsService(this.client);
74
- this.toilAllowance = new index_js_1.ToilAllowanceService(this.client);
75
- this.usersClockInService = new index_js_1.UsersClockInService(this.client);
76
- this.users = new index_js_1.UsersService(this.client);
77
- this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
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 RotaCloud.config;
113
+ return this.sdkConfig;
81
114
  }
82
115
  set config(configVal) {
83
- var _a, _b, _c, _d;
84
- RotaCloud.config = configVal;
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
- for (const requestInterceptor of (_b = (_a = this.config.interceptors) === null || _a === void 0 ? void 0 : _a.request) !== null && _b !== void 0 ? _b : []) {
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 (_d = (_c = this.config.interceptors) === null || _c === void 0 ? void 0 : _c.response) !== null && _d !== void 0 ? _d : []) {
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
- constructor(client: AxiosInstance);
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 = exports.RetryStrategy = void 0;
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: rotacloud_js_1.RotaCloud.config.apiKey
78
- ? `Bearer ${rotacloud_js_1.RotaCloud.config.apiKey}`
79
- : `Basic ${rotacloud_js_1.RotaCloud.config.basicAuth}`,
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 = rotacloud_js_1.RotaCloud.config.headers;
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 (rotacloud_js_1.RotaCloud.config.accountId) {
91
- headers.Account = String(rotacloud_js_1.RotaCloud.config.accountId);
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: rotacloud_js_1.RotaCloud.config.baseUri, headers, params: this.buildQueryParams(options, reqConfig.params) });
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) {
@@ -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.4.2' };
4
+ exports.Version = { version: '1.4.4' };
@@ -1,7 +1,7 @@
1
1
  export interface DailyRevenue {
2
2
  date: string;
3
3
  location: number;
4
- labour_percentage: number;
5
- revenue_target: number;
6
- revenue_actual: number;
4
+ labour_percentage: number | null;
5
+ revenue_target: number | null;
6
+ revenue_actual: number | null;
7
7
  }
@@ -1,5 +1,21 @@
1
1
  import { AxiosInterceptorManager, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
2
- import { RetryOptions, RetryStrategy } from '../services/service.js';
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 +1,5 @@
1
- export {};
1
+ export var RetryStrategy;
2
+ (function (RetryStrategy) {
3
+ RetryStrategy["Exponential"] = "expo";
4
+ RetryStrategy["Static"] = "static";
5
+ })(RetryStrategy || (RetryStrategy = {}));
@@ -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 } from './services/service.js';
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';
@@ -1,7 +1,22 @@
1
1
  import axios, { isAxiosError } from 'axios';
2
- import { AccountsService, AttendanceService, AuthService, AvailabilityService, DailyBudgetsService, DailyRevenueService, DayNotesService, DaysOffService, GroupsService, LeaveEmbargoesService, LeaveRequestService, LeaveTypesService, LeaveService, LocationsService, RetryStrategy, RolesService, SettingsService, ShiftsService, TerminalsService, TerminalsActiveService, TimeZoneService, ToilAccrualsService, ToilAllowanceService, UsersService, UsersClockInService, } from './services/index.js';
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.accounts = new AccountsService(this.client);
23
- this.attendance = new AttendanceService(this.client);
24
- this.auth = new AuthService(this.client);
25
- this.availability = new AvailabilityService(this.client);
26
- this.dailyBudgets = new DailyBudgetsService(this.client);
27
- this.dailyRevenue = new DailyRevenueService(this.client);
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 RotaCloud.config;
81
+ return this.sdkConfig;
54
82
  }
55
83
  set config(configVal) {
56
- RotaCloud.config = configVal;
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
- for (const requestInterceptor of this.config.interceptors?.request ?? []) {
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 this.config.interceptors?.response ?? []) {
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 } from './services/service.js';
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
- constructor(client: AxiosInstance);
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: RotaCloud.config.apiKey
53
- ? `Bearer ${RotaCloud.config.apiKey}`
54
- : `Basic ${RotaCloud.config.basicAuth}`,
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 = RotaCloud.config.headers;
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 (RotaCloud.config.accountId) {
66
- headers.Account = String(RotaCloud.config.accountId);
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: RotaCloud.config.baseUri,
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) {
@@ -1 +1 @@
1
- export const Version = { version: '1.4.2' };
1
+ export const Version = { version: '1.4.4' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rotacloud",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "The RotaCloud SDK for the RotaCloud API",
5
5
  "engines": {
6
6
  "node": ">=16.10.0"
@@ -1,7 +1,7 @@
1
1
  export interface DailyRevenue {
2
2
  date: string;
3
3
  location: number;
4
- labour_percentage: number;
5
- revenue_target: number;
6
- revenue_actual: number;
4
+ labour_percentage: number | null;
5
+ revenue_target: number | null;
6
+ revenue_actual: number | null;
7
7
  }
@@ -1,5 +1,25 @@
1
1
  import { AxiosInterceptorManager, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
2
- import { RetryOptions, RetryStrategy } from '../services/service.js';
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 = new AccountsService(this.client);
54
- attendance = new AttendanceService(this.client);
55
- auth = new AuthService(this.client);
56
- availability = new AvailabilityService(this.client);
57
- dailyBudgets = new DailyBudgetsService(this.client);
58
- dailyRevenue = new DailyRevenueService(this.client);
59
- dayNotes = new DayNotesService(this.client);
60
- daysOff = new DaysOffService(this.client);
61
- group = new GroupsService(this.client);
62
- leaveEmbargoes = new LeaveEmbargoesService(this.client);
63
- leaveRequests = new LeaveRequestService(this.client);
64
- leaveTypes = new LeaveTypesService(this.client);
65
- leave = new LeaveService(this.client);
66
- locations = new LocationsService(this.client);
67
- pins = new PinsService(this.client);
68
- roles = new RolesService(this.client);
69
- settings = new SettingsService(this.client);
70
- shifts = new ShiftsService(this.client);
71
- terminals = new TerminalsService(this.client);
72
- terminalsActive = new TerminalsActiveService(this.client);
73
- timeZone = new TimeZoneService(this.client);
74
- toilAccruals = new ToilAccrualsService(this.client);
75
- toilAllowance = new ToilAllowanceService(this.client);
76
- usersClockInService = new UsersClockInService(this.client);
77
- users = new UsersService(this.client);
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
- ...DEFAULT_CONFIG,
82
- ...config,
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 RotaCloud.config;
142
+ return this.sdkConfig;
88
143
  }
89
144
 
90
145
  set config(configVal: SDKConfig) {
91
- RotaCloud.config = configVal;
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
- for (const requestInterceptor of this.config.interceptors?.request ?? []) {
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 this.config.interceptors?.response ?? []) {
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 } from './services/service.js';
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';
@@ -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(protected client: AxiosInstance) {}
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: RotaCloud.config.apiKey
106
- ? `Bearer ${RotaCloud.config.apiKey}`
107
- : `Basic ${RotaCloud.config.basicAuth}`,
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 = RotaCloud.config.headers;
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 (RotaCloud.config.accountId) {
121
- headers.Account = String(RotaCloud.config.accountId);
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: RotaCloud.config.baseUri,
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.2' };
1
+ export const Version = { version: '1.4.4' };