@markwharton/eh-payroll 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/client.d.ts +14 -0
- package/dist/client.js +83 -148
- package/dist/errors.d.ts +6 -6
- package/dist/errors.js +9 -9
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -131,6 +131,7 @@ const client = new EHClient({
|
|
|
131
131
|
rateLimitPerSecond: 5, // Optional: rate limit (default 5, set 0 to disable)
|
|
132
132
|
onRequest: ({ method, url, description }) => { ... }, // Optional: debug callback
|
|
133
133
|
cache: {}, // Optional: enable TTL caching (defaults below)
|
|
134
|
+
cacheInstance: cache, // Optional: custom cache backend (e.g., LayeredCache)
|
|
134
135
|
retry: { // Optional: retry on 429/503
|
|
135
136
|
maxRetries: 3,
|
|
136
137
|
initialDelayMs: 1000,
|
|
@@ -139,7 +140,7 @@ const client = new EHClient({
|
|
|
139
140
|
});
|
|
140
141
|
```
|
|
141
142
|
|
|
142
|
-
`EHConfig` extends `ClientConfig` from api-core, which provides the `baseUrl`, `onRequest`, and `
|
|
143
|
+
`EHConfig` extends `ClientConfig` from api-core, which provides the `baseUrl`, `onRequest`, `retry`, and `cacheInstance` fields. `apiKey`, `businessId`, `region`, `cache`, and `rateLimitPerSecond` are EH-specific. Pass `cacheInstance` to use a custom cache backend (e.g., `LayeredCache` with persistent stores); otherwise `cache: {}` creates an in-memory `TTLCache`. PII data (`includePii: true`) automatically skips persistent stores.
|
|
143
144
|
|
|
144
145
|
### Cache TTLs
|
|
145
146
|
|
|
@@ -154,6 +155,8 @@ const client = new EHClient({
|
|
|
154
155
|
| Kiosk staff | 1 min |
|
|
155
156
|
| Report fields | 10 min |
|
|
156
157
|
|
|
158
|
+
Failed API results (`ok: false`) are never cached — transient errors won't persist for the full TTL. See the [root README Cache System section](../../README.md#cache-system) for the full cache architecture (layered stores, PII handling, request coalescing).
|
|
159
|
+
|
|
157
160
|
### Rate Limiting
|
|
158
161
|
|
|
159
162
|
The client enforces a sliding-window rate limit of 5 requests per second (the [API limit](https://api.keypay.com.au/australia/guides/Usage.html)). All outbound requests pass through the rate limiter automatically. Set `rateLimitPerSecond: 0` in config to disable (useful for tests). The `RateLimiter` class is provided by api-core and operates per-instance (see Known Limitations in the root README).
|
package/dist/client.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export declare class EHClient {
|
|
|
35
35
|
constructor(config: EHConfig);
|
|
36
36
|
/**
|
|
37
37
|
* Route through cache if enabled, otherwise call factory directly.
|
|
38
|
+
* Failed Results (ok === false) are never cached — transient errors
|
|
39
|
+
* shouldn't persist for the full TTL.
|
|
38
40
|
*/
|
|
39
41
|
private cached;
|
|
40
42
|
/**
|
|
@@ -52,6 +54,18 @@ export declare class EHClient {
|
|
|
52
54
|
* Fetch a URL and parse the response, with standardized error handling.
|
|
53
55
|
*/
|
|
54
56
|
private fetchAndParse;
|
|
57
|
+
/**
|
|
58
|
+
* Fetch all pages of a paginated endpoint.
|
|
59
|
+
*
|
|
60
|
+
* Payroll API pagination uses either OData ($skip/$top) or PascalCase
|
|
61
|
+
* (CurrentPage/PageSize). The caller provides a buildUrl callback that
|
|
62
|
+
* receives the current skip offset and returns the full URL with
|
|
63
|
+
* pagination parameters set.
|
|
64
|
+
*
|
|
65
|
+
* Consumer always receives the complete array — pageSize controls
|
|
66
|
+
* the internal batch size (items per API call).
|
|
67
|
+
*/
|
|
68
|
+
private fetchPaginated;
|
|
55
69
|
/**
|
|
56
70
|
* Validate the API key by calling GET /user
|
|
57
71
|
*/
|
package/dist/client.js
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { AU_EMPLOYEE_OPERATIONAL_FIELDS, AU_EMPLOYEE_FIELDS, LOCATION_FIELDS, EMPLOYEE_GROUP_FIELDS, ROSTER_SHIFT_FIELDS, KIOSK_FIELDS, KIOSK_EMPLOYEE_FIELDS, } from './types.js';
|
|
10
10
|
import { buildBasicAuthHeader } from './utils.js';
|
|
11
|
-
import {
|
|
11
|
+
import { parseEHPayrollErrorResponse } from './errors.js';
|
|
12
12
|
import { EH_API_BASE, EH_REGION_URLS } from './constants.js';
|
|
13
|
-
import { TTLCache, pickFields, RateLimiter, getErrorMessage, fetchWithRetry, resolveRetryConfig, ok, err } from '@markwharton/api-core';
|
|
13
|
+
import { TTLCache, pickFields, RateLimiter, getErrorMessage, fetchWithRetry, resolveRetryConfig, ok, okVoid, err } from '@markwharton/api-core';
|
|
14
14
|
/** Default page size for paginated endpoints */
|
|
15
15
|
const DEFAULT_PAGE_SIZE = 100;
|
|
16
16
|
// ============================================================================
|
|
@@ -37,8 +37,8 @@ export class EHClient {
|
|
|
37
37
|
this.baseUrl = config.baseUrl ?? (config.region ? EH_REGION_URLS[config.region] : EH_API_BASE);
|
|
38
38
|
this.onRequest = config.onRequest;
|
|
39
39
|
// Initialize cache if configured
|
|
40
|
-
if (config.cache) {
|
|
41
|
-
this.cache = new TTLCache();
|
|
40
|
+
if (config.cache || config.cacheInstance) {
|
|
41
|
+
this.cache = config.cacheInstance ?? new TTLCache();
|
|
42
42
|
}
|
|
43
43
|
this.cacheTtl = {
|
|
44
44
|
employeesTtl: config.cache?.employeesTtl ?? 300000,
|
|
@@ -60,12 +60,16 @@ export class EHClient {
|
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Route through cache if enabled, otherwise call factory directly.
|
|
63
|
+
* Failed Results (ok === false) are never cached — transient errors
|
|
64
|
+
* shouldn't persist for the full TTL.
|
|
63
65
|
*/
|
|
64
|
-
async cached(key, ttlMs, factory) {
|
|
65
|
-
if (this.cache)
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
async cached(key, ttlMs, factory, options) {
|
|
67
|
+
if (!this.cache)
|
|
68
|
+
return factory();
|
|
69
|
+
return this.cache.get(key, ttlMs, factory, {
|
|
70
|
+
...options,
|
|
71
|
+
shouldCache: (data) => data.ok !== false,
|
|
72
|
+
});
|
|
69
73
|
}
|
|
70
74
|
/**
|
|
71
75
|
* Clear all cached API responses.
|
|
@@ -114,7 +118,7 @@ export class EHClient {
|
|
|
114
118
|
const response = await this.fetch(url, fetchOptions);
|
|
115
119
|
if (!response.ok) {
|
|
116
120
|
const errorText = await response.text();
|
|
117
|
-
const { message } =
|
|
121
|
+
const { message } = parseEHPayrollErrorResponse(errorText, response.status);
|
|
118
122
|
return err(message, response.status);
|
|
119
123
|
}
|
|
120
124
|
return ok(await parse(response));
|
|
@@ -123,6 +127,42 @@ export class EHClient {
|
|
|
123
127
|
return err(getErrorMessage(error), 0);
|
|
124
128
|
}
|
|
125
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Fetch all pages of a paginated endpoint.
|
|
132
|
+
*
|
|
133
|
+
* Payroll API pagination uses either OData ($skip/$top) or PascalCase
|
|
134
|
+
* (CurrentPage/PageSize). The caller provides a buildUrl callback that
|
|
135
|
+
* receives the current skip offset and returns the full URL with
|
|
136
|
+
* pagination parameters set.
|
|
137
|
+
*
|
|
138
|
+
* Consumer always receives the complete array — pageSize controls
|
|
139
|
+
* the internal batch size (items per API call).
|
|
140
|
+
*/
|
|
141
|
+
async fetchPaginated(buildUrl, fields, pageSize = DEFAULT_PAGE_SIZE) {
|
|
142
|
+
try {
|
|
143
|
+
const allItems = [];
|
|
144
|
+
let skip = 0;
|
|
145
|
+
while (true) {
|
|
146
|
+
const url = buildUrl(skip);
|
|
147
|
+
const response = await this.fetch(url);
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
const errorText = await response.text();
|
|
150
|
+
const { message } = parseEHPayrollErrorResponse(errorText, response.status);
|
|
151
|
+
return err(message, response.status);
|
|
152
|
+
}
|
|
153
|
+
const page = (await response.json())
|
|
154
|
+
.map(item => pickFields(item, fields));
|
|
155
|
+
allItems.push(...page);
|
|
156
|
+
if (page.length < pageSize)
|
|
157
|
+
break;
|
|
158
|
+
skip += pageSize;
|
|
159
|
+
}
|
|
160
|
+
return ok(allItems);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return err(getErrorMessage(error), 0);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
126
166
|
// ============================================================================
|
|
127
167
|
// Validation
|
|
128
168
|
// ============================================================================
|
|
@@ -134,7 +174,7 @@ export class EHClient {
|
|
|
134
174
|
try {
|
|
135
175
|
const response = await this.fetch(url);
|
|
136
176
|
if (response.ok) {
|
|
137
|
-
return
|
|
177
|
+
return okVoid();
|
|
138
178
|
}
|
|
139
179
|
if (response.status === 401 || response.status === 403) {
|
|
140
180
|
return err('Invalid or expired API key', response.status);
|
|
@@ -161,38 +201,19 @@ export class EHClient {
|
|
|
161
201
|
if (options?.includePii)
|
|
162
202
|
parts.push('pii');
|
|
163
203
|
const cacheKey = parts.join(':');
|
|
164
|
-
|
|
204
|
+
const persistOpt = options?.includePii ? { persist: false } : undefined;
|
|
205
|
+
return this.cached(cacheKey, this.cacheTtl.employeesTtl, () => {
|
|
165
206
|
const params = new URLSearchParams();
|
|
166
207
|
if (options?.payScheduleId != null)
|
|
167
208
|
params.set('filter.payScheduleId', String(options.payScheduleId));
|
|
168
209
|
if (options?.locationId != null)
|
|
169
210
|
params.set('filter.locationId', String(options.locationId));
|
|
170
211
|
params.set('$top', String(DEFAULT_PAGE_SIZE));
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const url = `${this.baseUrl}/business/${this.businessId}/employee/unstructured?${params}`;
|
|
177
|
-
const response = await this.fetch(url);
|
|
178
|
-
if (!response.ok) {
|
|
179
|
-
const errorText = await response.text();
|
|
180
|
-
const { message } = parseEHErrorResponse(errorText, response.status);
|
|
181
|
-
return err(message, response.status);
|
|
182
|
-
}
|
|
183
|
-
const page = (await response.json())
|
|
184
|
-
.map(item => pickFields(item, fields));
|
|
185
|
-
allEmployees.push(...page);
|
|
186
|
-
if (page.length < DEFAULT_PAGE_SIZE)
|
|
187
|
-
break;
|
|
188
|
-
skip += DEFAULT_PAGE_SIZE;
|
|
189
|
-
}
|
|
190
|
-
return ok(allEmployees);
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
return err(getErrorMessage(error), 0);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
212
|
+
return this.fetchPaginated((skip) => {
|
|
213
|
+
params.set('$skip', String(skip));
|
|
214
|
+
return `${this.baseUrl}/business/${this.businessId}/employee/unstructured?${params}`;
|
|
215
|
+
}, fields);
|
|
216
|
+
}, persistOpt);
|
|
196
217
|
}
|
|
197
218
|
/**
|
|
198
219
|
* Get a single employee by ID
|
|
@@ -200,12 +221,13 @@ export class EHClient {
|
|
|
200
221
|
async getEmployee(employeeId, options) {
|
|
201
222
|
const fields = options?.includePii ? AU_EMPLOYEE_FIELDS : AU_EMPLOYEE_OPERATIONAL_FIELDS;
|
|
202
223
|
const cacheKey = options?.includePii ? `employee:${employeeId}:pii` : `employee:${employeeId}`;
|
|
224
|
+
const persistOpt = options?.includePii ? { persist: false } : undefined;
|
|
203
225
|
return this.cached(cacheKey, this.cacheTtl.employeesTtl, async () => {
|
|
204
226
|
const url = `${this.baseUrl}/business/${this.businessId}/employee/unstructured/${employeeId}`;
|
|
205
227
|
return this.fetchAndParse(url, async (r) => {
|
|
206
228
|
return pickFields(await r.json(), fields);
|
|
207
229
|
});
|
|
208
|
-
});
|
|
230
|
+
}, persistOpt);
|
|
209
231
|
}
|
|
210
232
|
// ============================================================================
|
|
211
233
|
// Standard Hours
|
|
@@ -228,34 +250,12 @@ export class EHClient {
|
|
|
228
250
|
* Get all business locations
|
|
229
251
|
*/
|
|
230
252
|
async getLocations() {
|
|
231
|
-
return this.cached('locations', this.cacheTtl.locationsTtl,
|
|
232
|
-
const params = new URLSearchParams({
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
let skip = 0;
|
|
238
|
-
while (true) {
|
|
239
|
-
params.set('$skip', String(skip));
|
|
240
|
-
const url = `${this.baseUrl}/business/${this.businessId}/location?${params}`;
|
|
241
|
-
const response = await this.fetch(url);
|
|
242
|
-
if (!response.ok) {
|
|
243
|
-
const errorText = await response.text();
|
|
244
|
-
const { message } = parseEHErrorResponse(errorText, response.status);
|
|
245
|
-
return err(message, response.status);
|
|
246
|
-
}
|
|
247
|
-
const page = (await response.json())
|
|
248
|
-
.map(item => pickFields(item, LOCATION_FIELDS));
|
|
249
|
-
allLocations.push(...page);
|
|
250
|
-
if (page.length < DEFAULT_PAGE_SIZE)
|
|
251
|
-
break;
|
|
252
|
-
skip += DEFAULT_PAGE_SIZE;
|
|
253
|
-
}
|
|
254
|
-
return ok(allLocations);
|
|
255
|
-
}
|
|
256
|
-
catch (error) {
|
|
257
|
-
return err(getErrorMessage(error), 0);
|
|
258
|
-
}
|
|
253
|
+
return this.cached('locations', this.cacheTtl.locationsTtl, () => {
|
|
254
|
+
const params = new URLSearchParams({ '$top': String(DEFAULT_PAGE_SIZE) });
|
|
255
|
+
return this.fetchPaginated((skip) => {
|
|
256
|
+
params.set('$skip', String(skip));
|
|
257
|
+
return `${this.baseUrl}/business/${this.businessId}/location?${params}`;
|
|
258
|
+
}, LOCATION_FIELDS);
|
|
259
259
|
});
|
|
260
260
|
}
|
|
261
261
|
// ============================================================================
|
|
@@ -265,34 +265,12 @@ export class EHClient {
|
|
|
265
265
|
* Get all employee groups
|
|
266
266
|
*/
|
|
267
267
|
async getEmployeeGroups() {
|
|
268
|
-
return this.cached('
|
|
269
|
-
const params = new URLSearchParams({
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
let skip = 0;
|
|
275
|
-
while (true) {
|
|
276
|
-
params.set('$skip', String(skip));
|
|
277
|
-
const url = `${this.baseUrl}/business/${this.businessId}/employeegroup?${params}`;
|
|
278
|
-
const response = await this.fetch(url);
|
|
279
|
-
if (!response.ok) {
|
|
280
|
-
const errorText = await response.text();
|
|
281
|
-
const { message } = parseEHErrorResponse(errorText, response.status);
|
|
282
|
-
return err(message, response.status);
|
|
283
|
-
}
|
|
284
|
-
const page = (await response.json())
|
|
285
|
-
.map(item => pickFields(item, EMPLOYEE_GROUP_FIELDS));
|
|
286
|
-
allGroups.push(...page);
|
|
287
|
-
if (page.length < DEFAULT_PAGE_SIZE)
|
|
288
|
-
break;
|
|
289
|
-
skip += DEFAULT_PAGE_SIZE;
|
|
290
|
-
}
|
|
291
|
-
return ok(allGroups);
|
|
292
|
-
}
|
|
293
|
-
catch (error) {
|
|
294
|
-
return err(getErrorMessage(error), 0);
|
|
295
|
-
}
|
|
268
|
+
return this.cached('employeegroups', this.cacheTtl.groupsTtl, () => {
|
|
269
|
+
const params = new URLSearchParams({ '$top': String(DEFAULT_PAGE_SIZE) });
|
|
270
|
+
return this.fetchPaginated((skip) => {
|
|
271
|
+
params.set('$skip', String(skip));
|
|
272
|
+
return `${this.baseUrl}/business/${this.businessId}/employeegroup?${params}`;
|
|
273
|
+
}, EMPLOYEE_GROUP_FIELDS);
|
|
296
274
|
});
|
|
297
275
|
}
|
|
298
276
|
// ============================================================================
|
|
@@ -332,7 +310,7 @@ export class EHClient {
|
|
|
332
310
|
if (options?.includeWarnings)
|
|
333
311
|
parts.push('iw');
|
|
334
312
|
const cacheKey = parts.join(':');
|
|
335
|
-
return this.cached(cacheKey, this.cacheTtl.rosterShiftsTtl,
|
|
313
|
+
return this.cached(cacheKey, this.cacheTtl.rosterShiftsTtl, () => {
|
|
336
314
|
// Roster shift query params are PascalCase per the Swagger spec, unlike
|
|
337
315
|
// all other endpoints which use camelCase. See: https://api.keypay.com.au/swagger-au.json
|
|
338
316
|
const params = new URLSearchParams({
|
|
@@ -372,31 +350,10 @@ export class EHClient {
|
|
|
372
350
|
params.set('ExcludeShiftsOverlappingFromDate', 'true');
|
|
373
351
|
if (options?.includeWarnings)
|
|
374
352
|
params.set('IncludeWarnings', 'true');
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
while (true) {
|
|
380
|
-
params.set('CurrentPage', String(currentPage));
|
|
381
|
-
const url = `${this.baseUrl}/business/${this.businessId}/rostershift?${params}`;
|
|
382
|
-
const response = await this.fetch(url);
|
|
383
|
-
if (!response.ok) {
|
|
384
|
-
const errorText = await response.text();
|
|
385
|
-
const { message } = parseEHErrorResponse(errorText, response.status);
|
|
386
|
-
return err(message, response.status);
|
|
387
|
-
}
|
|
388
|
-
const page = (await response.json())
|
|
389
|
-
.map(item => pickFields(item, ROSTER_SHIFT_FIELDS));
|
|
390
|
-
allShifts.push(...page);
|
|
391
|
-
if (page.length < DEFAULT_PAGE_SIZE)
|
|
392
|
-
break;
|
|
393
|
-
currentPage++;
|
|
394
|
-
}
|
|
395
|
-
return ok(allShifts);
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
return err(getErrorMessage(error), 0);
|
|
399
|
-
}
|
|
353
|
+
return this.fetchPaginated((skip) => {
|
|
354
|
+
params.set('CurrentPage', String(skip / DEFAULT_PAGE_SIZE + 1));
|
|
355
|
+
return `${this.baseUrl}/business/${this.businessId}/rostershift?${params}`;
|
|
356
|
+
}, ROSTER_SHIFT_FIELDS);
|
|
400
357
|
});
|
|
401
358
|
}
|
|
402
359
|
// ============================================================================
|
|
@@ -406,34 +363,12 @@ export class EHClient {
|
|
|
406
363
|
* Get all kiosks for the business
|
|
407
364
|
*/
|
|
408
365
|
async getKiosks() {
|
|
409
|
-
return this.cached('kiosks', this.cacheTtl.kiosksTtl,
|
|
410
|
-
const params = new URLSearchParams({
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
let skip = 0;
|
|
416
|
-
while (true) {
|
|
417
|
-
params.set('$skip', String(skip));
|
|
418
|
-
const url = `${this.baseUrl}/business/${this.businessId}/kiosk?${params}`;
|
|
419
|
-
const response = await this.fetch(url);
|
|
420
|
-
if (!response.ok) {
|
|
421
|
-
const errorText = await response.text();
|
|
422
|
-
const { message } = parseEHErrorResponse(errorText, response.status);
|
|
423
|
-
return err(message, response.status);
|
|
424
|
-
}
|
|
425
|
-
const page = (await response.json())
|
|
426
|
-
.map(item => pickFields(item, KIOSK_FIELDS));
|
|
427
|
-
allKiosks.push(...page);
|
|
428
|
-
if (page.length < DEFAULT_PAGE_SIZE)
|
|
429
|
-
break;
|
|
430
|
-
skip += DEFAULT_PAGE_SIZE;
|
|
431
|
-
}
|
|
432
|
-
return ok(allKiosks);
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
return err(getErrorMessage(error), 0);
|
|
436
|
-
}
|
|
366
|
+
return this.cached('kiosks', this.cacheTtl.kiosksTtl, () => {
|
|
367
|
+
const params = new URLSearchParams({ '$top': String(DEFAULT_PAGE_SIZE) });
|
|
368
|
+
return this.fetchPaginated((skip) => {
|
|
369
|
+
params.set('$skip', String(skip));
|
|
370
|
+
return `${this.baseUrl}/business/${this.businessId}/kiosk?${params}`;
|
|
371
|
+
}, KIOSK_FIELDS);
|
|
437
372
|
});
|
|
438
373
|
}
|
|
439
374
|
/**
|
package/dist/errors.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type { ParsedError } from '@markwharton/api-core';
|
|
|
11
11
|
/**
|
|
12
12
|
* Parsed EH error response
|
|
13
13
|
*/
|
|
14
|
-
export type
|
|
14
|
+
export type EHPayrollParsedError = ParsedError;
|
|
15
15
|
/**
|
|
16
16
|
* Parse EH API error response text into a human-readable message.
|
|
17
17
|
*
|
|
@@ -19,19 +19,19 @@ export type EHParsedError = ParsedError;
|
|
|
19
19
|
* JSON error formats with no API-specific extensions.
|
|
20
20
|
*
|
|
21
21
|
* @param errorText - Raw error response text
|
|
22
|
-
* @param
|
|
22
|
+
* @param status - HTTP status code
|
|
23
23
|
* @returns Parsed error with message
|
|
24
24
|
*/
|
|
25
|
-
export declare function
|
|
25
|
+
export declare function parseEHPayrollErrorResponse(errorText: string, status: number): EHPayrollParsedError;
|
|
26
26
|
/**
|
|
27
27
|
* Custom error class for EH API errors
|
|
28
28
|
*/
|
|
29
|
-
export declare class
|
|
29
|
+
export declare class EHPayrollError extends ApiError {
|
|
30
30
|
constructor(message: string, status: number, options?: {
|
|
31
31
|
rawResponse?: string;
|
|
32
32
|
});
|
|
33
33
|
/**
|
|
34
|
-
* Create an
|
|
34
|
+
* Create an EHPayrollError from an API response
|
|
35
35
|
*/
|
|
36
|
-
static fromResponse(
|
|
36
|
+
static fromResponse(status: number, responseText: string): EHPayrollError;
|
|
37
37
|
}
|
package/dist/errors.js
CHANGED
|
@@ -14,26 +14,26 @@ import { ApiError, parseJsonErrorResponse } from '@markwharton/api-core';
|
|
|
14
14
|
* JSON error formats with no API-specific extensions.
|
|
15
15
|
*
|
|
16
16
|
* @param errorText - Raw error response text
|
|
17
|
-
* @param
|
|
17
|
+
* @param status - HTTP status code
|
|
18
18
|
* @returns Parsed error with message
|
|
19
19
|
*/
|
|
20
|
-
export function
|
|
21
|
-
return parseJsonErrorResponse(errorText,
|
|
20
|
+
export function parseEHPayrollErrorResponse(errorText, status) {
|
|
21
|
+
return parseJsonErrorResponse(errorText, status);
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Custom error class for EH API errors
|
|
25
25
|
*/
|
|
26
|
-
export class
|
|
26
|
+
export class EHPayrollError extends ApiError {
|
|
27
27
|
constructor(message, status, options) {
|
|
28
28
|
super(message, status, options);
|
|
29
|
-
this.name = '
|
|
29
|
+
this.name = 'EHPayrollError';
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
* Create an
|
|
32
|
+
* Create an EHPayrollError from an API response
|
|
33
33
|
*/
|
|
34
|
-
static fromResponse(
|
|
35
|
-
const parsed =
|
|
36
|
-
return new
|
|
34
|
+
static fromResponse(status, responseText) {
|
|
35
|
+
const parsed = parseEHPayrollErrorResponse(responseText, status);
|
|
36
|
+
return new EHPayrollError(parsed.message, status, {
|
|
37
37
|
rawResponse: responseText,
|
|
38
38
|
});
|
|
39
39
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,9 +24,9 @@ export type { EHConfig, EHCacheConfig, EHRetryConfig, EHEmployee, EHEmployeeOpti
|
|
|
24
24
|
export { AU_EMPLOYEE_OPERATIONAL_FIELDS, AU_EMPLOYEE_PII_FIELDS, AU_EMPLOYEE_FIELDS, LOCATION_FIELDS, EMPLOYEE_GROUP_FIELDS, ROSTER_SHIFT_FIELDS, KIOSK_FIELDS, KIOSK_EMPLOYEE_FIELDS, } from './types.js';
|
|
25
25
|
export type { EHAuEmployee } from './employee-types.generated.js';
|
|
26
26
|
export { buildBasicAuthHeader } from './utils.js';
|
|
27
|
-
export { ok, err, getErrorMessage, pickFields, RateLimiter } from '@markwharton/api-core';
|
|
28
|
-
export type { Result, RetryConfig, OnRequestCallback, ClientConfig } from '@markwharton/api-core';
|
|
27
|
+
export { ok, err, getErrorMessage, pickFields, RateLimiter, TTLCache, MemoryCacheStore, LayeredCache } from '@markwharton/api-core';
|
|
28
|
+
export type { Result, RetryConfig, OnRequestCallback, ClientConfig, Cache, CacheStore, CacheGetOptions } from '@markwharton/api-core';
|
|
29
29
|
export { EH_API_BASE, EH_REGION_URLS } from './constants.js';
|
|
30
30
|
export type { EHRegion } from './constants.js';
|
|
31
|
-
export {
|
|
32
|
-
export type {
|
|
31
|
+
export { EHPayrollError, parseEHPayrollErrorResponse } from './errors.js';
|
|
32
|
+
export type { EHPayrollParsedError } from './errors.js';
|
package/dist/index.js
CHANGED
|
@@ -26,8 +26,8 @@ export { AU_EMPLOYEE_OPERATIONAL_FIELDS, AU_EMPLOYEE_PII_FIELDS, AU_EMPLOYEE_FIE
|
|
|
26
26
|
// Utilities
|
|
27
27
|
export { buildBasicAuthHeader } from './utils.js';
|
|
28
28
|
// Re-exported from @markwharton/api-core
|
|
29
|
-
export { ok, err, getErrorMessage, pickFields, RateLimiter } from '@markwharton/api-core';
|
|
29
|
+
export { ok, err, getErrorMessage, pickFields, RateLimiter, TTLCache, MemoryCacheStore, LayeredCache } from '@markwharton/api-core';
|
|
30
30
|
// Constants
|
|
31
31
|
export { EH_API_BASE, EH_REGION_URLS } from './constants.js';
|
|
32
32
|
// Errors
|
|
33
|
-
export {
|
|
33
|
+
export { EHPayrollError, parseEHPayrollErrorResponse } from './errors.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markwharton/eh-payroll",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Employment Hero Payroll API client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"clean": "rm -rf dist"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@markwharton/api-core": "^1.
|
|
19
|
+
"@markwharton/api-core": "^1.3.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "^20.10.0",
|