@markwharton/eh-payroll 3.1.0 → 3.2.1

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 CHANGED
@@ -11,9 +11,9 @@ npm install @markwharton/eh-payroll
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { EHClient } from '@markwharton/eh-payroll';
14
+ import { PayrollClient } from '@markwharton/eh-payroll';
15
15
 
16
- const client = new EHClient({
16
+ const client = new PayrollClient({
17
17
  apiKey: 'xxx',
18
18
  businessId: 123,
19
19
  region: 'au', // 'au' | 'nz' | 'uk' | 'sg' | 'my' (default: 'au')
@@ -25,15 +25,15 @@ if (!validation.ok) throw new Error(validation.error);
25
25
 
26
26
  // Get all employees
27
27
  const empResult = await client.getEmployees();
28
- if (empResult.ok) console.log(empResult.data); // EHAuEmployee[]
28
+ if (empResult.ok) console.log(empResult.data); // PayrollAuEmployee[]
29
29
 
30
30
  // Get employees filtered by location
31
31
  const filteredResult = await client.getEmployees({ locationId: 5 });
32
- if (filteredResult.ok) console.log(filteredResult.data); // EHAuEmployee[]
32
+ if (filteredResult.ok) console.log(filteredResult.data); // PayrollAuEmployee[]
33
33
 
34
34
  // Get roster shifts for a date range (auto-paginates)
35
35
  const rosterResult = await client.getRosterShifts('2026-02-03', '2026-02-09');
36
- if (rosterResult.ok) console.log(rosterResult.data); // EHRosterShift[]
36
+ if (rosterResult.ok) console.log(rosterResult.data); // PayrollRosterShift[]
37
37
 
38
38
  // Get roster shifts with filters
39
39
  const pubResult = await client.getRosterShifts('2026-02-03', '2026-02-09', {
@@ -41,7 +41,7 @@ const pubResult = await client.getRosterShifts('2026-02-03', '2026-02-09', {
41
41
  shiftStatus: 'Published',
42
42
  selectAllRoles: true
43
43
  });
44
- if (pubResult.ok) console.log(pubResult.data); // EHRosterShift[]
44
+ if (pubResult.ok) console.log(pubResult.data); // PayrollRosterShift[]
45
45
 
46
46
  // Get leave requests for a date range (all filters server-side)
47
47
  const leaveResult = await client.getLeaveRequests({
@@ -49,27 +49,27 @@ const leaveResult = await client.getLeaveRequests({
49
49
  toDate: '2026-03-31',
50
50
  status: 'Approved',
51
51
  });
52
- if (leaveResult.ok) console.log(leaveResult.data); // EHLeaveRequest[]
52
+ if (leaveResult.ok) console.log(leaveResult.data); // PayrollLeaveRequest[]
53
53
 
54
54
  // Get business locations
55
55
  const locResult = await client.getLocations();
56
- if (locResult.ok) console.log(locResult.data); // EHLocation[]
56
+ if (locResult.ok) console.log(locResult.data); // PayrollLocation[]
57
57
 
58
58
  // List kiosks
59
59
  const kioskResult = await client.getKiosks();
60
- if (kioskResult.ok) console.log(kioskResult.data); // EHKiosk[]
60
+ if (kioskResult.ok) console.log(kioskResult.data); // PayrollKiosk[]
61
61
 
62
62
  // Get kiosk staff (time and attendance)
63
63
  const staffResult = await client.getKioskStaff(kioskId);
64
- if (staffResult.ok) console.log(staffResult.data); // EHKioskEmployee[]
64
+ if (staffResult.ok) console.log(staffResult.data); // PayrollKioskEmployee[]
65
65
 
66
66
  // Get employee groups
67
67
  const groupResult = await client.getEmployeeGroups();
68
- if (groupResult.ok) console.log(groupResult.data); // EHEmployeeGroup[]
68
+ if (groupResult.ok) console.log(groupResult.data); // PayrollEmployeeGroup[]
69
69
 
70
70
  // Get standard hours for an employee (includes FTE value)
71
71
  const hoursResult = await client.getStandardHours(employeeId);
72
- if (hoursResult.ok) console.log(hoursResult.data); // EHStandardHours
72
+ if (hoursResult.ok) console.log(hoursResult.data); // PayrollStandardHours
73
73
 
74
74
  ```
75
75
 
@@ -82,17 +82,17 @@ All methods return `Result<T>` — see [api-core Result Pattern](../../README.md
82
82
  | Method | Parameters | Returns |
83
83
  |--------|-----------|---------|
84
84
  | `validateApiKey()` | — | `Result<void>` |
85
- | `getEmployees(options?)` | `EHEmployeeOptions?` | `Result<EHAuEmployee[]>` |
86
- | `getEmployee(employeeId)` | `number` | `Result<EHAuEmployee>` |
87
- | `getEmployeeImage(employeeId)` | `number` | `Result<EHEmployeeImage>` |
88
- | `getStandardHours(employeeId)` | `number` | `Result<EHStandardHours>` |
89
- | `getLocations()` | — | `Result<EHLocation[]>` |
90
- | `getEmployeeGroups()` | — | `Result<EHEmployeeGroup[]>` |
91
- | `getRosterShifts(from, to, options?)` | `string, string, EHRosterShiftOptions?` | `Result<EHRosterShift[]>` |
92
- | `getKiosks()` | — | `Result<EHKiosk[]>` |
93
- | `getKioskStaff(kioskId, options?)` | `number, EHKioskStaffOptions?` | `Result<EHKioskEmployee[]>` |
94
- | `getLeaveRequests(options?)` | `EHLeaveRequestOptions?` | `Result<EHLeaveRequest[]>` |
95
- | `getEmployeeLeaveRequests(employeeId, options?)` | `number, EHEmployeeLeaveRequestOptions?` | `Result<EHLeaveRequest[]>` |
85
+ | `getEmployees(options?)` | `PayrollEmployeeOptions?` | `Result<PayrollAuEmployee[]>` |
86
+ | `getEmployee(employeeId)` | `number` | `Result<PayrollAuEmployee>` |
87
+ | `getEmployeeImage(employeeId)` | `number` | `Result<PayrollEmployeeImage>` |
88
+ | `getStandardHours(employeeId)` | `number` | `Result<PayrollStandardHours>` |
89
+ | `getLocations()` | — | `Result<PayrollLocation[]>` |
90
+ | `getEmployeeGroups()` | — | `Result<PayrollEmployeeGroup[]>` |
91
+ | `getRosterShifts(from, to, options?)` | `string, string, PayrollRosterShiftOptions?` | `Result<PayrollRosterShift[]>` |
92
+ | `getKiosks()` | — | `Result<PayrollKiosk[]>` |
93
+ | `getKioskStaff(kioskId, options?)` | `number, PayrollKioskStaffOptions?` | `Result<PayrollKioskEmployee[]>` |
94
+ | `getLeaveRequests(options?)` | `PayrollLeaveRequestOptions?` | `Result<PayrollLeaveRequest[]>` |
95
+ | `getEmployeeLeaveRequests(employeeId, options?)` | `number, PayrollEmployeeLeaveRequestOptions?` | `Result<PayrollLeaveRequest[]>` |
96
96
  | `clearCache()` | — | `void` |
97
97
  | `invalidateEmployeeCache()` | — | `void` |
98
98
  | `invalidateLeaveRequestCache()` | — | `void` |
@@ -106,13 +106,13 @@ Returns leave requests with all filters applied server-side. The business-level
106
106
 
107
107
  **Leave requests are time-series data** — unlike employees and locations which remain relatively stable, leave requests grow continuously. Always use `fromDate`/`toDate` filters to bound the result set.
108
108
 
109
- **`EHLeaveRequestOptions`:**
109
+ **`PayrollLeaveRequestOptions`:**
110
110
 
111
111
  | Option | Type | Description |
112
112
  |--------|------|-------------|
113
113
  | `fromDate` | `string` | Start date filter (YYYY-MM-DD) |
114
114
  | `toDate` | `string` | End date filter (YYYY-MM-DD) |
115
- | `status` | `EHLeaveRequestStatus` | `'Approved'`, `'Pending'`, `'Rejected'`, or `'Cancelled'` |
115
+ | `status` | `PayrollLeaveRequestStatus` | `'Approved'`, `'Pending'`, `'Rejected'`, or `'Cancelled'` |
116
116
  | `employeeId` | `number` | Filter by employee ID |
117
117
  | `leaveCategoryId` | `number` | Filter by leave category ID |
118
118
  | `locationId` | `number` | Filter by location ID |
@@ -123,11 +123,11 @@ Returns leave requests with all filters applied server-side. The business-level
123
123
 
124
124
  Returns leave requests for a specific employee using the per-employee endpoint with OData pagination.
125
125
 
126
- **`EHEmployeeLeaveRequestOptions`:**
126
+ **`PayrollEmployeeLeaveRequestOptions`:**
127
127
 
128
128
  | Option | Type | Description |
129
129
  |--------|------|-------------|
130
- | `status` | `EHLeaveRequestStatus` | `'Approved'`, `'Pending'`, `'Rejected'`, or `'Cancelled'` |
130
+ | `status` | `PayrollLeaveRequestStatus` | `'Approved'`, `'Pending'`, `'Rejected'`, or `'Cancelled'` |
131
131
  | `fromDate` | `string` | Start date filter (ISO 8601) |
132
132
  | `toDate` | `string` | End date filter (ISO 8601) |
133
133
 
@@ -142,7 +142,7 @@ The [KeyPay Swagger spec](https://api.keypay.com.au/swagger-au.json) uses incons
142
142
  ## Configuration
143
143
 
144
144
  ```typescript
145
- const client = new EHClient({
145
+ const client = new PayrollClient({
146
146
  apiKey: 'your-api-key', // Required: used as Basic Auth username
147
147
  businessId: 12345, // Required: business ID
148
148
  region: 'au', // Optional: au, nz, uk, sg, my (default: au)
@@ -159,7 +159,7 @@ const client = new EHClient({
159
159
  });
160
160
  ```
161
161
 
162
- `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`. Set `persistRestricted: false` to keep restricted-tier data in memory only.
162
+ `PayrollConfig` extends `ClientConfig` from api-core, which provides the `baseUrl`, `onRequest`, `retry`, and `cacheInstance` fields. `apiKey`, `businessId`, `region`, `cache`, and `rateLimitPerSecond` are payroll-specific. Pass `cacheInstance` to use a custom cache backend (e.g., `LayeredCache` with persistent stores); otherwise `cache: {}` creates an in-memory `TTLCache`. Set `persistRestricted: false` to keep restricted-tier data in memory only.
163
163
 
164
164
  ### Cache TTLs
165
165
 
package/dist/client.d.ts CHANGED
@@ -6,15 +6,15 @@
6
6
  *
7
7
  * @see https://api.keypay.com.au/
8
8
  */
9
- import type { EHConfig, EHLeaveRequest, EHLeaveRequestOptions, EHEmployeeLeaveRequestOptions, EHEmployeeOptions, EHStandardHours, EHLocation, EHEmployeeGroup, EHRosterShift, EHRosterShiftOptions, EHKiosk, EHKioskEmployee, EHKioskStaffOptions, EHEmployeeImage } from './types.js';
10
- import type { EHEmployee } from './employee-types.generated.js';
9
+ import type { PayrollConfig, PayrollLeaveRequest, PayrollLeaveRequestOptions, PayrollEmployeeLeaveRequestOptions, PayrollEmployeeOptions, PayrollStandardHours, PayrollLocation, PayrollEmployeeGroup, PayrollRosterShift, PayrollRosterShiftOptions, PayrollKiosk, PayrollKioskEmployee, PayrollKioskStaffOptions, PayrollEmployeeImage } from './types.js';
10
+ import type { PayrollEmployee } from './employee-types.generated.js';
11
11
  import type { Result } from '@markwharton/api-core';
12
12
  /**
13
13
  * Employment Hero Payroll API Client
14
14
  *
15
15
  * @example
16
16
  * ```typescript
17
- * const client = new EHClient({ apiKey: 'xxx', businessId: 123 });
17
+ * const client = new PayrollClient({ apiKey: 'xxx', businessId: 123 });
18
18
  *
19
19
  * // Validate credentials
20
20
  * await client.validateApiKey();
@@ -23,7 +23,7 @@ import type { Result } from '@markwharton/api-core';
23
23
  * const { data: employees } = await client.getEmployees();
24
24
  * ```
25
25
  */
26
- export declare class EHClient {
26
+ export declare class PayrollClient {
27
27
  private readonly apiKey;
28
28
  private readonly businessId;
29
29
  private readonly baseUrl;
@@ -33,7 +33,7 @@ export declare class EHClient {
33
33
  private readonly retryConfig?;
34
34
  private readonly rateLimiter?;
35
35
  private readonly persistRestricted;
36
- constructor(config: EHConfig);
36
+ constructor(config: PayrollConfig);
37
37
  /** Cache options for restricted-tier methods: skip persistent stores when persistRestricted is false. */
38
38
  private get restrictedPersistOpt();
39
39
  /** Route through cache if enabled, skipping failed Results. */
@@ -101,22 +101,22 @@ export declare class EHClient {
101
101
  *
102
102
  * @see https://api.keypay.com.au/australia/reference/leave-requests/au-business-hours-leave-request--list-leave-requests.html
103
103
  */
104
- getLeaveRequests(options?: EHLeaveRequestOptions): Promise<Result<EHLeaveRequest[]>>;
104
+ getLeaveRequests(options?: PayrollLeaveRequestOptions): Promise<Result<PayrollLeaveRequest[]>>;
105
105
  /**
106
106
  * Get leave requests for a specific employee
107
107
  *
108
108
  * Uses the per-employee endpoint with OData pagination.
109
109
  * Optional filters for status and date range.
110
110
  */
111
- getEmployeeLeaveRequests(employeeId: number, options?: EHEmployeeLeaveRequestOptions): Promise<Result<EHLeaveRequest[]>>;
111
+ getEmployeeLeaveRequests(employeeId: number, options?: PayrollEmployeeLeaveRequestOptions): Promise<Result<PayrollLeaveRequest[]>>;
112
112
  /**
113
113
  * Get all employees
114
114
  */
115
- getEmployees(options?: EHEmployeeOptions): Promise<Result<EHEmployee[]>>;
115
+ getEmployees(options?: PayrollEmployeeOptions): Promise<Result<PayrollEmployee[]>>;
116
116
  /**
117
117
  * Get a single employee by ID
118
118
  */
119
- getEmployee(employeeId: number): Promise<Result<EHEmployee>>;
119
+ getEmployee(employeeId: number): Promise<Result<PayrollEmployee>>;
120
120
  /**
121
121
  * Get employee profile image
122
122
  *
@@ -124,19 +124,19 @@ export declare class EHClient {
124
124
  *
125
125
  * @see https://api.keypay.com.au/australia/reference/employee/au-employee--get-employee-profile-image.html
126
126
  */
127
- getEmployeeImage(employeeId: number): Promise<Result<EHEmployeeImage>>;
127
+ getEmployeeImage(employeeId: number): Promise<Result<PayrollEmployeeImage>>;
128
128
  /**
129
129
  * Get standard hours for an employee (includes FTE value)
130
130
  */
131
- getStandardHours(employeeId: number): Promise<Result<EHStandardHours>>;
131
+ getStandardHours(employeeId: number): Promise<Result<PayrollStandardHours>>;
132
132
  /**
133
133
  * Get all business locations
134
134
  */
135
- getLocations(): Promise<Result<EHLocation[]>>;
135
+ getLocations(): Promise<Result<PayrollLocation[]>>;
136
136
  /**
137
137
  * Get all employee groups
138
138
  */
139
- getEmployeeGroups(): Promise<Result<EHEmployeeGroup[]>>;
139
+ getEmployeeGroups(): Promise<Result<PayrollEmployeeGroup[]>>;
140
140
  /**
141
141
  * Get roster shifts for a date range
142
142
  *
@@ -144,16 +144,16 @@ export declare class EHClient {
144
144
  * @param toDate - End date (YYYY-MM-DD)
145
145
  * @param options - Optional filters
146
146
  */
147
- getRosterShifts(fromDate: string, toDate: string, options?: EHRosterShiftOptions): Promise<Result<EHRosterShift[]>>;
147
+ getRosterShifts(fromDate: string, toDate: string, options?: PayrollRosterShiftOptions): Promise<Result<PayrollRosterShift[]>>;
148
148
  /**
149
149
  * Get all kiosks for the business
150
150
  */
151
- getKiosks(): Promise<Result<EHKiosk[]>>;
151
+ getKiosks(): Promise<Result<PayrollKiosk[]>>;
152
152
  /**
153
153
  * Get kiosk staff for time and attendance
154
154
  *
155
155
  * @param kioskId - Kiosk identifier
156
156
  * @param options - Optional query parameters
157
157
  */
158
- getKioskStaff(kioskId: number, options?: EHKioskStaffOptions): Promise<Result<EHKioskEmployee[]>>;
158
+ getKioskStaff(kioskId: number, options?: PayrollKioskStaffOptions): Promise<Result<PayrollKioskEmployee[]>>;
159
159
  }
package/dist/client.js CHANGED
@@ -8,8 +8,8 @@
8
8
  */
9
9
  import { ENTITIES } from './types.js';
10
10
  import { buildBasicAuthHeader } from './utils.js';
11
- import { parseEHPayrollErrorResponse } from './errors.js';
12
- import { EH_API_BASE, EH_REGION_URLS } from './constants.js';
11
+ import { parsePayrollErrorResponse } from './errors.js';
12
+ import { PAYROLL_API_BASE, PAYROLL_REGION_URLS } from './constants.js';
13
13
  import { pickFields, RateLimiter, getErrorMessage, fetchWithRetry, resolveRetryConfig, ok, okVoid, err, cachedResult, fetchAndParseResponse, resolveClientCache } from '@markwharton/api-core';
14
14
  /** Default page size for paginated endpoints */
15
15
  const DEFAULT_PAGE_SIZE = 100;
@@ -21,7 +21,7 @@ const DEFAULT_PAGE_SIZE = 100;
21
21
  *
22
22
  * @example
23
23
  * ```typescript
24
- * const client = new EHClient({ apiKey: 'xxx', businessId: 123 });
24
+ * const client = new PayrollClient({ apiKey: 'xxx', businessId: 123 });
25
25
  *
26
26
  * // Validate credentials
27
27
  * await client.validateApiKey();
@@ -30,11 +30,11 @@ const DEFAULT_PAGE_SIZE = 100;
30
30
  * const { data: employees } = await client.getEmployees();
31
31
  * ```
32
32
  */
33
- export class EHClient {
33
+ export class PayrollClient {
34
34
  constructor(config) {
35
35
  this.apiKey = config.apiKey;
36
36
  this.businessId = config.businessId;
37
- this.baseUrl = config.baseUrl ?? (config.region ? EH_REGION_URLS[config.region] : EH_API_BASE);
37
+ this.baseUrl = config.baseUrl ?? (config.region ? PAYROLL_REGION_URLS[config.region] : PAYROLL_API_BASE);
38
38
  this.onRequest = config.onRequest;
39
39
  // Initialize cache if configured
40
40
  this.cache = resolveClientCache(config);
@@ -150,7 +150,7 @@ export class EHClient {
150
150
  * Fetch a URL and parse the response, with standardized error handling.
151
151
  */
152
152
  fetchAndParse(url, parse, fetchOptions) {
153
- return fetchAndParseResponse(() => this.fetch(url, fetchOptions), parse, parseEHPayrollErrorResponse);
153
+ return fetchAndParseResponse(() => this.fetch(url, fetchOptions), parse, parsePayrollErrorResponse);
154
154
  }
155
155
  /**
156
156
  * Fetch all pages of a paginated endpoint.
@@ -172,7 +172,7 @@ export class EHClient {
172
172
  const response = await this.fetch(url);
173
173
  if (!response.ok) {
174
174
  const errorText = await response.text();
175
- const { message } = parseEHPayrollErrorResponse(errorText, response.status);
175
+ const { message } = parsePayrollErrorResponse(errorText, response.status);
176
176
  return err(message, response.status);
177
177
  }
178
178
  const page = (await response.json())
@@ -258,10 +258,10 @@ export class EHClient {
258
258
  params.set('GroupBy', options.groupBy);
259
259
  if (options?.restrictOverlappingLeave)
260
260
  params.set('RestrictOverlappingLeave', 'true');
261
- const url = this.businessUrl(ENTITIES.EHLeaveRequest.path, params);
261
+ const url = this.businessUrl(ENTITIES.PayrollLeaveRequest.path, params);
262
262
  return this.fetchAndParse(url, async (r) => {
263
263
  return (await r.json())
264
- .map(item => pickFields(item, ENTITIES.EHLeaveRequest.fields));
264
+ .map(item => pickFields(item, ENTITIES.PayrollLeaveRequest.fields));
265
265
  });
266
266
  }, this.restrictedPersistOpt);
267
267
  }
@@ -280,7 +280,7 @@ export class EHClient {
280
280
  if (options?.toDate)
281
281
  parts.push(`to:${options.toDate}`);
282
282
  const cacheKey = parts.join(':');
283
- const entityPath = ENTITIES.EHEmployeeLeaveRequest.path.replace('{employeeId}', String(employeeId));
283
+ const entityPath = ENTITIES.PayrollEmployeeLeaveRequest.path.replace('{employeeId}', String(employeeId));
284
284
  return this.cached(cacheKey, this.cacheTtl.leaveRequestsTtl, () => {
285
285
  const params = new URLSearchParams();
286
286
  params.set('$top', String(DEFAULT_PAGE_SIZE));
@@ -296,7 +296,7 @@ export class EHClient {
296
296
  return this.fetchPaginated((skip) => {
297
297
  params.set('$skip', String(skip));
298
298
  return this.businessUrl(entityPath, params);
299
- }, ENTITIES.EHEmployeeLeaveRequest.fields);
299
+ }, ENTITIES.PayrollEmployeeLeaveRequest.fields);
300
300
  }, this.restrictedPersistOpt);
301
301
  }
302
302
  // ============================================================================
@@ -321,8 +321,8 @@ export class EHClient {
321
321
  params.set('$top', String(DEFAULT_PAGE_SIZE));
322
322
  return this.fetchPaginated((skip) => {
323
323
  params.set('$skip', String(skip));
324
- return this.businessUrl(ENTITIES.EHEmployee.path, params);
325
- }, ENTITIES.EHEmployee.fields);
324
+ return this.businessUrl(ENTITIES.PayrollEmployee.path, params);
325
+ }, ENTITIES.PayrollEmployee.fields);
326
326
  }, this.restrictedPersistOpt);
327
327
  }
328
328
  /**
@@ -330,9 +330,9 @@ export class EHClient {
330
330
  */
331
331
  async getEmployee(employeeId) {
332
332
  return this.cached(`employee:${employeeId}`, this.cacheTtl.employeesTtl, async () => {
333
- const url = this.businessUrl(`${ENTITIES.EHEmployee.path}/${employeeId}`);
333
+ const url = this.businessUrl(`${ENTITIES.PayrollEmployee.path}/${employeeId}`);
334
334
  return this.fetchAndParse(url, async (r) => {
335
- return pickFields(await r.json(), ENTITIES.EHEmployee.fields);
335
+ return pickFields(await r.json(), ENTITIES.PayrollEmployee.fields);
336
336
  });
337
337
  }, this.restrictedPersistOpt);
338
338
  }
@@ -375,8 +375,8 @@ export class EHClient {
375
375
  const params = new URLSearchParams({ '$top': String(DEFAULT_PAGE_SIZE) });
376
376
  return this.fetchPaginated((skip) => {
377
377
  params.set('$skip', String(skip));
378
- return this.businessUrl(ENTITIES.EHLocation.path, params);
379
- }, ENTITIES.EHLocation.fields);
378
+ return this.businessUrl(ENTITIES.PayrollLocation.path, params);
379
+ }, ENTITIES.PayrollLocation.fields);
380
380
  });
381
381
  }
382
382
  // ============================================================================
@@ -390,8 +390,8 @@ export class EHClient {
390
390
  const params = new URLSearchParams({ '$top': String(DEFAULT_PAGE_SIZE) });
391
391
  return this.fetchPaginated((skip) => {
392
392
  params.set('$skip', String(skip));
393
- return this.businessUrl(ENTITIES.EHEmployeeGroup.path, params);
394
- }, ENTITIES.EHEmployeeGroup.fields);
393
+ return this.businessUrl(ENTITIES.PayrollEmployeeGroup.path, params);
394
+ }, ENTITIES.PayrollEmployeeGroup.fields);
395
395
  });
396
396
  }
397
397
  // ============================================================================
@@ -473,8 +473,8 @@ export class EHClient {
473
473
  params.set('IncludeWarnings', 'true');
474
474
  return this.fetchPaginated((skip) => {
475
475
  params.set('CurrentPage', String(skip / DEFAULT_PAGE_SIZE + 1));
476
- return this.businessUrl(ENTITIES.EHRosterShift.path, params);
477
- }, ENTITIES.EHRosterShift.fields);
476
+ return this.businessUrl(ENTITIES.PayrollRosterShift.path, params);
477
+ }, ENTITIES.PayrollRosterShift.fields);
478
478
  });
479
479
  }
480
480
  // ============================================================================
@@ -488,8 +488,8 @@ export class EHClient {
488
488
  const params = new URLSearchParams({ '$top': String(DEFAULT_PAGE_SIZE) });
489
489
  return this.fetchPaginated((skip) => {
490
490
  params.set('$skip', String(skip));
491
- return this.businessUrl(ENTITIES.EHKiosk.path, params);
492
- }, ENTITIES.EHKiosk.fields);
491
+ return this.businessUrl(ENTITIES.PayrollKiosk.path, params);
492
+ }, ENTITIES.PayrollKiosk.fields);
493
493
  });
494
494
  }
495
495
  /**
@@ -507,10 +507,10 @@ export class EHClient {
507
507
  if (options?.restrictCurrentShiftsToCurrentKioskLocation) {
508
508
  params.set('restrictCurrentShiftsToCurrentKioskLocation', 'true');
509
509
  }
510
- const url = this.businessUrl(ENTITIES.EHKioskEmployee.path.replace('{kioskId}', String(kioskId)), params);
510
+ const url = this.businessUrl(ENTITIES.PayrollKioskEmployee.path.replace('{kioskId}', String(kioskId)), params);
511
511
  return this.fetchAndParse(url, async (r) => {
512
512
  return (await r.json())
513
- .map(item => pickFields(item, ENTITIES.EHKioskEmployee.fields));
513
+ .map(item => pickFields(item, ENTITIES.PayrollKioskEmployee.fields));
514
514
  });
515
515
  });
516
516
  }
@@ -2,8 +2,8 @@
2
2
  * Employment Hero Payroll Constants
3
3
  */
4
4
  /** Supported API regions */
5
- export type EHRegion = 'au' | 'nz' | 'uk' | 'sg' | 'my';
5
+ export type PayrollRegion = 'au' | 'nz' | 'uk' | 'sg' | 'my';
6
6
  /** Base URLs for each region */
7
- export declare const EH_REGION_URLS: Record<EHRegion, string>;
8
- /** Default EH Payroll API base URL (AU) */
9
- export declare const EH_API_BASE: string;
7
+ export declare const PAYROLL_REGION_URLS: Record<PayrollRegion, string>;
8
+ /** Default Payroll API base URL (AU) */
9
+ export declare const PAYROLL_API_BASE: string;
package/dist/constants.js CHANGED
@@ -2,12 +2,12 @@
2
2
  * Employment Hero Payroll Constants
3
3
  */
4
4
  /** Base URLs for each region */
5
- export const EH_REGION_URLS = {
5
+ export const PAYROLL_REGION_URLS = {
6
6
  au: 'https://api.yourpayroll.com.au/api/v2',
7
7
  nz: 'https://apinz.yourpayroll.io/api/v2',
8
8
  uk: 'https://api.yourpayroll.co.uk/api/v2',
9
9
  sg: 'https://apisg.yourpayroll.io/api/v2',
10
10
  my: 'https://apimy.yourpayroll.io/api/v2',
11
11
  };
12
- /** Default EH Payroll API base URL (AU) */
13
- export const EH_API_BASE = EH_REGION_URLS.au;
12
+ /** Default Payroll API base URL (AU) */
13
+ export const PAYROLL_API_BASE = PAYROLL_REGION_URLS.au;
@@ -6,14 +6,14 @@
6
6
  *
7
7
  * Total fields: 139
8
8
  */
9
- export type EHCloselyHeldReporting = 'PerQuarter' | 'PerPayRun';
10
- export type EHEmployeeStatus = 'Active' | 'Terminated' | 'Incomplete';
11
- export type EHLeaveAccrualStartDateType = 'EmployeeStartDate' | 'SpecifiedDate' | 'CalendarYear' | 'CategorySpecificDate';
12
- export type EHMedicareLevySurchargeWithholdingTier = 'Tier1' | 'Tier2' | 'Tier3';
13
- export type EHSingleTouchPayrollCategory = 'CloselyHeld' | 'ForeignEmployment' | 'InboundAssignee' | 'LabourHire' | 'OtherSpecifiedPayments' | 'SalaryAndWages' | 'WorkingHolidayMaker' | 'SeasonalWorker';
14
- export type EHTaxCategory = 'Actor_WithTaxFreeThreshold' | 'Actor_NoTaxFreeThreshold' | 'Actor_LimitedPerformancePerWeek' | 'Actor_Promotional' | 'HorticulturalistShearer_WithTaxFreeThreshold' | 'HorticulturalistShearer_ForeignResident' | 'SeniorPensioner_Single' | 'SeniorPensioner_Married' | 'SeniorPensioner_SeparatedCoupleIllness' | 'ATODefined_DeathBeneficiary' | 'ATODefined_DownwardVariation' | 'ATODefined_NonEmployee' | 'DailyCasual';
9
+ export type PayrollCloselyHeldReporting = 'PerQuarter' | 'PerPayRun';
10
+ export type PayrollEmployeeStatus = 'Active' | 'Terminated' | 'Incomplete';
11
+ export type PayrollLeaveAccrualStartDateType = 'EmployeeStartDate' | 'SpecifiedDate' | 'CalendarYear' | 'CategorySpecificDate';
12
+ export type PayrollMedicareLevySurchargeWithholdingTier = 'Tier1' | 'Tier2' | 'Tier3';
13
+ export type PayrollSingleTouchPayrollCategory = 'CloselyHeld' | 'ForeignEmployment' | 'InboundAssignee' | 'LabourHire' | 'OtherSpecifiedPayments' | 'SalaryAndWages' | 'WorkingHolidayMaker' | 'SeasonalWorker';
14
+ export type PayrollTaxCategory = 'Actor_WithTaxFreeThreshold' | 'Actor_NoTaxFreeThreshold' | 'Actor_LimitedPerformancePerWeek' | 'Actor_Promotional' | 'HorticulturalistShearer_WithTaxFreeThreshold' | 'HorticulturalistShearer_ForeignResident' | 'SeniorPensioner_Single' | 'SeniorPensioner_Married' | 'SeniorPensioner_SeparatedCoupleIllness' | 'ATODefined_DeathBeneficiary' | 'ATODefined_DownwardVariation' | 'ATODefined_NonEmployee' | 'DailyCasual';
15
15
  /** AU employee from unstructured endpoint (139 fields) */
16
- export interface EHEmployee {
16
+ export interface PayrollEmployee {
17
17
  anniversaryDate: string | null;
18
18
  australianResident: boolean;
19
19
  automaticallyApplyPublicHolidayNotWorkedEarningsLines: boolean;
@@ -38,7 +38,7 @@ export interface EHEmployee {
38
38
  claimMedicareLevyReduction: boolean;
39
39
  claimTaxFreeThreshold: boolean;
40
40
  closelyHeldEmployee: boolean;
41
- closelyHeldReporting: EHCloselyHeldReporting | null;
41
+ closelyHeldReporting: PayrollCloselyHeldReporting | null;
42
42
  contractorABN: string | null;
43
43
  dateCreated: string | null;
44
44
  dateOfBirth: string | null;
@@ -78,7 +78,7 @@ export interface EHEmployee {
78
78
  isExemptFromPayrollTax: boolean;
79
79
  isSeasonalWorker: boolean;
80
80
  jobTitle: string | null;
81
- leaveAccrualStartDateType: EHLeaveAccrualStartDateType | null;
81
+ leaveAccrualStartDateType: PayrollLeaveAccrualStartDateType | null;
82
82
  leaveTemplate: string | null;
83
83
  leaveYearStart: string | null;
84
84
  locations: string | null;
@@ -86,7 +86,7 @@ export interface EHEmployee {
86
86
  medicareLevyExemption: string | null;
87
87
  medicareLevyReductionDependentCount: number | null;
88
88
  medicareLevyReductionSpouse: boolean;
89
- medicareLevySurchargeWithholdingTier: EHMedicareLevySurchargeWithholdingTier | null;
89
+ medicareLevySurchargeWithholdingTier: PayrollMedicareLevySurchargeWithholdingTier | null;
90
90
  middleName: string | null;
91
91
  mobilePhone: string | null;
92
92
  otherTaxOffset: boolean;
@@ -119,9 +119,9 @@ export interface EHEmployee {
119
119
  residentialSuburb: string | null;
120
120
  rosteringNotificationChoices: string | null;
121
121
  seniorsTaxOffset: boolean;
122
- singleTouchPayroll: EHSingleTouchPayrollCategory | null;
122
+ singleTouchPayroll: PayrollSingleTouchPayrollCategory | null;
123
123
  startDate: string | null;
124
- status: EHEmployeeStatus | null;
124
+ status: PayrollEmployeeStatus | null;
125
125
  stslDebt: boolean;
126
126
  superFund1_AllocatedPercentage: number | null;
127
127
  superFund1_EmployerNominatedFund: boolean;
@@ -144,7 +144,7 @@ export interface EHEmployee {
144
144
  superThresholdAmount: number | null;
145
145
  surname: string | null;
146
146
  tags: string | null;
147
- taxCategory: EHTaxCategory | null;
147
+ taxCategory: PayrollTaxCategory | null;
148
148
  taxFileNumber: string | null;
149
149
  taxVariation: number | null;
150
150
  terminationReason: string | null;
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 EHPayrollParsedError = ParsedError;
14
+ export type PayrollParsedError = ParsedError;
15
15
  /**
16
16
  * Parse EH API error response text into a human-readable message.
17
17
  *
@@ -22,16 +22,16 @@ export type EHPayrollParsedError = ParsedError;
22
22
  * @param status - HTTP status code
23
23
  * @returns Parsed error with message
24
24
  */
25
- export declare function parseEHPayrollErrorResponse(errorText: string, status: number): EHPayrollParsedError;
25
+ export declare function parsePayrollErrorResponse(errorText: string, status: number): PayrollParsedError;
26
26
  /**
27
27
  * Custom error class for EH API errors
28
28
  */
29
- export declare class EHPayrollError extends ApiError {
29
+ export declare class PayrollError extends ApiError {
30
30
  constructor(message: string, status: number, options?: {
31
31
  rawResponse?: string;
32
32
  });
33
33
  /**
34
- * Create an EHPayrollError from an API response
34
+ * Create an PayrollError from an API response
35
35
  */
36
- static fromResponse(status: number, responseText: string): EHPayrollError;
36
+ static fromResponse(status: number, responseText: string): PayrollError;
37
37
  }
package/dist/errors.js CHANGED
@@ -17,23 +17,23 @@ import { ApiError, parseJsonErrorResponse } from '@markwharton/api-core';
17
17
  * @param status - HTTP status code
18
18
  * @returns Parsed error with message
19
19
  */
20
- export function parseEHPayrollErrorResponse(errorText, status) {
20
+ export function parsePayrollErrorResponse(errorText, status) {
21
21
  return parseJsonErrorResponse(errorText, status);
22
22
  }
23
23
  /**
24
24
  * Custom error class for EH API errors
25
25
  */
26
- export class EHPayrollError extends ApiError {
26
+ export class PayrollError extends ApiError {
27
27
  constructor(message, status, options) {
28
28
  super(message, status, options);
29
- this.name = 'EHPayrollError';
29
+ this.name = 'PayrollError';
30
30
  }
31
31
  /**
32
- * Create an EHPayrollError from an API response
32
+ * Create an PayrollError from an API response
33
33
  */
34
34
  static fromResponse(status, responseText) {
35
- const parsed = parseEHPayrollErrorResponse(responseText, status);
36
- return new EHPayrollError(parsed.message, status, {
35
+ const parsed = parsePayrollErrorResponse(responseText, status);
36
+ return new PayrollError(parsed.message, status, {
37
37
  rawResponse: responseText,
38
38
  });
39
39
  }
package/dist/index.d.ts CHANGED
@@ -5,9 +5,9 @@
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * import { EHClient } from '@markwharton/eh-payroll';
8
+ * import { PayrollClient } from '@markwharton/eh-payroll';
9
9
  *
10
- * const client = new EHClient({ apiKey: 'xxx', businessId: 123 });
10
+ * const client = new PayrollClient({ apiKey: 'xxx', businessId: 123 });
11
11
  *
12
12
  * // Validate credentials
13
13
  * await client.validateApiKey();
@@ -19,15 +19,22 @@
19
19
  * const { data: rosterShifts } = await client.getRosterShifts('2026-02-03', '2026-02-09');
20
20
  * ```
21
21
  */
22
- export { EHClient } from './client.js';
23
- export type { EHConfig, EHCacheConfig, EHRetryConfig, EHLeaveRequest, EHLeaveRequestOptions, EHLeaveRequestGroupBy, EHEmployeeLeaveRequestOptions, EHLeaveRequestStatus, EHEmployee, EHEmployeeStatus, EHLeaveAccrualStartDateType, EHCloselyHeldReporting, EHMedicareLevySurchargeWithholdingTier, EHSingleTouchPayrollCategory, EHTaxCategory, EHEmployeeOptions, EHStandardHours, EHLocation, EHEmployeeGroup, EHRosterShift, EHRosterShiftOptions, EHShiftStatus, EHAttendanceStatus, EHKiosk, EHKioskEmployee, EHKioskStaffOptions, EHEmployeeImage, } from './types.js';
24
- export { EMPLOYEE_FIELDS, LEAVE_REQUEST_FIELDS, LOCATION_FIELDS, EMPLOYEE_GROUP_FIELDS, ROSTER_SHIFT_FIELDS, KIOSK_FIELDS, KIOSK_EMPLOYEE_FIELDS, ENTITIES, } from './types.js';
22
+ export { PayrollClient } from './client.js';
23
+ export type { PayrollConfig, PayrollCacheConfig, PayrollRetryConfig, PayrollLeaveRequest, PayrollLeaveRequestOptions, PayrollLeaveRequestGroupBy, PayrollEmployeeLeaveRequestOptions, PayrollLeaveRequestStatus, PayrollEmployee, PayrollEmployeeStatus, PayrollLeaveAccrualStartDateType, PayrollCloselyHeldReporting, PayrollMedicareLevySurchargeWithholdingTier, PayrollSingleTouchPayrollCategory, PayrollTaxCategory, PayrollEmployeeOptions, PayrollStandardHours, PayrollLocation, PayrollEmployeeGroup, PayrollRosterShift, PayrollRosterShiftOptions, PayrollShiftStatus, PayrollAttendanceStatus, PayrollKiosk, PayrollKioskEmployee, PayrollKioskStaffOptions, PayrollEmployeeImage, } from './types.js';
24
+ export { PAYROLL_EMPLOYEE_FIELDS, PAYROLL_LEAVE_REQUEST_FIELDS, PAYROLL_LOCATION_FIELDS, PAYROLL_EMPLOYEE_GROUP_FIELDS, PAYROLL_ROSTER_SHIFT_FIELDS, PAYROLL_KIOSK_FIELDS, PAYROLL_KIOSK_EMPLOYEE_FIELDS, ENTITIES, } from './types.js';
25
25
  export type { AccessTier } from './types.js';
26
26
  export { METHOD_TIERS } from './types.js';
27
27
  export { buildBasicAuthHeader } from './utils.js';
28
28
  export { ok, err, getErrorMessage, pickFields, normalizeEnum, RateLimiter, TTLCache, MemoryCacheStore, LayeredCache } from '@markwharton/api-core';
29
29
  export type { Result, RetryConfig, OnRequestCallback, ClientConfig, Cache, CacheStore, CacheGetOptions } from '@markwharton/api-core';
30
- export { EH_API_BASE, EH_REGION_URLS } from './constants.js';
31
- export type { EHRegion } from './constants.js';
32
- export { EHPayrollError, parseEHPayrollErrorResponse } from './errors.js';
33
- export type { EHPayrollParsedError } from './errors.js';
30
+ export { PAYROLL_API_BASE, PAYROLL_REGION_URLS } from './constants.js';
31
+ export type { PayrollRegion } from './constants.js';
32
+ export { PayrollError, parsePayrollErrorResponse } from './errors.js';
33
+ export type { PayrollParsedError } from './errors.js';
34
+ export { PayrollClient as EHClient } from './client.js';
35
+ export type { PayrollConfig as EHConfig, PayrollCacheConfig as EHCacheConfig, PayrollRetryConfig as EHRetryConfig, PayrollLeaveRequest as EHLeaveRequest, PayrollLeaveRequestOptions as EHLeaveRequestOptions, PayrollLeaveRequestGroupBy as EHLeaveRequestGroupBy, PayrollEmployeeLeaveRequestOptions as EHEmployeeLeaveRequestOptions, PayrollLeaveRequestStatus as EHLeaveRequestStatus, PayrollEmployee as EHEmployee, PayrollEmployeeStatus as EHEmployeeStatus, PayrollLeaveAccrualStartDateType as EHLeaveAccrualStartDateType, PayrollCloselyHeldReporting as EHCloselyHeldReporting, PayrollMedicareLevySurchargeWithholdingTier as EHMedicareLevySurchargeWithholdingTier, PayrollSingleTouchPayrollCategory as EHSingleTouchPayrollCategory, PayrollTaxCategory as EHTaxCategory, PayrollEmployeeOptions as EHEmployeeOptions, PayrollStandardHours as EHStandardHours, PayrollLocation as EHLocation, PayrollEmployeeGroup as EHEmployeeGroup, PayrollRosterShift as EHRosterShift, PayrollRosterShiftOptions as EHRosterShiftOptions, PayrollShiftStatus as EHShiftStatus, PayrollAttendanceStatus as EHAttendanceStatus, PayrollKiosk as EHKiosk, PayrollKioskEmployee as EHKioskEmployee, PayrollKioskStaffOptions as EHKioskStaffOptions, PayrollEmployeeImage as EHEmployeeImage, } from './types.js';
36
+ export { PAYROLL_EMPLOYEE_FIELDS as EMPLOYEE_FIELDS, PAYROLL_LEAVE_REQUEST_FIELDS as LEAVE_REQUEST_FIELDS, PAYROLL_LOCATION_FIELDS as LOCATION_FIELDS, PAYROLL_EMPLOYEE_GROUP_FIELDS as EMPLOYEE_GROUP_FIELDS, PAYROLL_ROSTER_SHIFT_FIELDS as ROSTER_SHIFT_FIELDS, PAYROLL_KIOSK_FIELDS as KIOSK_FIELDS, PAYROLL_KIOSK_EMPLOYEE_FIELDS as KIOSK_EMPLOYEE_FIELDS, } from './types.js';
37
+ export { PAYROLL_API_BASE as EH_API_BASE, PAYROLL_REGION_URLS as EH_REGION_URLS } from './constants.js';
38
+ export type { PayrollRegion as EHRegion } from './constants.js';
39
+ export { PayrollError as EHPayrollError, parsePayrollErrorResponse as parseEHPayrollErrorResponse } from './errors.js';
40
+ export type { PayrollParsedError as EHPayrollParsedError } from './errors.js';
package/dist/index.js CHANGED
@@ -5,9 +5,9 @@
5
5
  *
6
6
  * @example
7
7
  * ```typescript
8
- * import { EHClient } from '@markwharton/eh-payroll';
8
+ * import { PayrollClient } from '@markwharton/eh-payroll';
9
9
  *
10
- * const client = new EHClient({ apiKey: 'xxx', businessId: 123 });
10
+ * const client = new PayrollClient({ apiKey: 'xxx', businessId: 123 });
11
11
  *
12
12
  * // Validate credentials
13
13
  * await client.validateApiKey();
@@ -20,15 +20,26 @@
20
20
  * ```
21
21
  */
22
22
  // Main client
23
- export { EHClient } from './client.js';
23
+ export { PayrollClient } from './client.js';
24
24
  // Field definitions (for pickFields)
25
- export { EMPLOYEE_FIELDS, LEAVE_REQUEST_FIELDS, LOCATION_FIELDS, EMPLOYEE_GROUP_FIELDS, ROSTER_SHIFT_FIELDS, KIOSK_FIELDS, KIOSK_EMPLOYEE_FIELDS, ENTITIES, } from './types.js';
25
+ export { PAYROLL_EMPLOYEE_FIELDS, PAYROLL_LEAVE_REQUEST_FIELDS, PAYROLL_LOCATION_FIELDS, PAYROLL_EMPLOYEE_GROUP_FIELDS, PAYROLL_ROSTER_SHIFT_FIELDS, PAYROLL_KIOSK_FIELDS, PAYROLL_KIOSK_EMPLOYEE_FIELDS, ENTITIES, } from './types.js';
26
26
  export { METHOD_TIERS } from './types.js';
27
27
  // Utilities
28
28
  export { buildBasicAuthHeader } from './utils.js';
29
29
  // Re-exported from @markwharton/api-core
30
30
  export { ok, err, getErrorMessage, pickFields, normalizeEnum, RateLimiter, TTLCache, MemoryCacheStore, LayeredCache } from '@markwharton/api-core';
31
31
  // Constants
32
- export { EH_API_BASE, EH_REGION_URLS } from './constants.js';
32
+ export { PAYROLL_API_BASE, PAYROLL_REGION_URLS } from './constants.js';
33
33
  // Errors
34
- export { EHPayrollError, parseEHPayrollErrorResponse } from './errors.js';
34
+ export { PayrollError, parsePayrollErrorResponse } from './errors.js';
35
+ // ============================================================================
36
+ // Backward compatibility aliases (deprecated — use Payroll* names)
37
+ // ============================================================================
38
+ // Client
39
+ export { PayrollClient as EHClient } from './client.js';
40
+ // Field definitions
41
+ export { PAYROLL_EMPLOYEE_FIELDS as EMPLOYEE_FIELDS, PAYROLL_LEAVE_REQUEST_FIELDS as LEAVE_REQUEST_FIELDS, PAYROLL_LOCATION_FIELDS as LOCATION_FIELDS, PAYROLL_EMPLOYEE_GROUP_FIELDS as EMPLOYEE_GROUP_FIELDS, PAYROLL_ROSTER_SHIFT_FIELDS as ROSTER_SHIFT_FIELDS, PAYROLL_KIOSK_FIELDS as KIOSK_FIELDS, PAYROLL_KIOSK_EMPLOYEE_FIELDS as KIOSK_EMPLOYEE_FIELDS, } from './types.js';
42
+ // Constants
43
+ export { PAYROLL_API_BASE as EH_API_BASE, PAYROLL_REGION_URLS as EH_REGION_URLS } from './constants.js';
44
+ // Errors
45
+ export { PayrollError as EHPayrollError, parsePayrollErrorResponse as parseEHPayrollErrorResponse } from './errors.js';
package/dist/types.d.ts CHANGED
@@ -4,15 +4,15 @@
4
4
  * Types for the Employment Hero Payroll (KeyPay) API.
5
5
  * Based on the API reference and KeyPay .NET SDK models.
6
6
  */
7
- import type { EHRegion } from './constants.js';
7
+ import type { PayrollRegion } from './constants.js';
8
8
  import type { RetryConfig, ClientConfig } from '@markwharton/api-core';
9
9
  /**
10
- * Cache configuration for EHClient
10
+ * Cache configuration for PayrollClient
11
11
  *
12
- * When provided to EHConfig, enables in-memory TTL caching of API responses.
12
+ * When provided to PayrollConfig, enables in-memory TTL caching of API responses.
13
13
  * All TTL values are in milliseconds. Omit individual TTLs to use defaults.
14
14
  */
15
- export interface EHCacheConfig {
15
+ export interface PayrollCacheConfig {
16
16
  /** TTL for employee list (default: 300000 = 5 min) */
17
17
  employeesTtl?: number;
18
18
  /** TTL for leave requests (default: 120000 = 2 min) */
@@ -31,19 +31,19 @@ export interface EHCacheConfig {
31
31
  kioskStaffTtl?: number;
32
32
  }
33
33
  /** @deprecated Use `RetryConfig` from `@markwharton/api-core` directly. */
34
- export type EHRetryConfig = RetryConfig;
34
+ export type PayrollRetryConfig = RetryConfig;
35
35
  /**
36
36
  * Employment Hero Payroll configuration for API access
37
37
  */
38
- export interface EHConfig extends ClientConfig {
38
+ export interface PayrollConfig extends ClientConfig {
39
39
  /** API key for authentication (used as Basic Auth username) */
40
40
  apiKey: string;
41
41
  /** Business ID to operate on */
42
42
  businessId: number;
43
43
  /** API region (default: 'au'). Sets the base URL automatically. */
44
- region?: EHRegion;
44
+ region?: PayrollRegion;
45
45
  /** Enable caching with optional TTL overrides. Omit to disable caching. */
46
- cache?: EHCacheConfig;
46
+ cache?: PayrollCacheConfig;
47
47
  /** Max requests per second (default: 5 per API spec). Set 0 to disable. */
48
48
  rateLimitPerSecond?: number;
49
49
  /** Whether to persist restricted-tier data in persistent cache stores (default: true). Set false to keep restricted data in memory only. */
@@ -56,14 +56,14 @@ export interface EHConfig extends ClientConfig {
56
56
  *
57
57
  * @see employee-types.generated.ts
58
58
  */
59
- export type { EHEmployee, EHEmployeeStatus, EHLeaveAccrualStartDateType, EHCloselyHeldReporting, EHMedicareLevySurchargeWithholdingTier, EHSingleTouchPayrollCategory, EHTaxCategory, } from './employee-types.generated.js';
59
+ export type { PayrollEmployee, PayrollEmployeeStatus, PayrollLeaveAccrualStartDateType, PayrollCloselyHeldReporting, PayrollMedicareLevySurchargeWithholdingTier, PayrollSingleTouchPayrollCategory, PayrollTaxCategory, } from './employee-types.generated.js';
60
60
  /**
61
61
  * Standard hours for an employee
62
62
  *
63
63
  * From GET /business/{id}/employee/{eid}/standardhours
64
64
  * Contains the FullTimeEquivalentHours field needed for FTE calculations.
65
65
  */
66
- export interface EHStandardHours {
66
+ export interface PayrollStandardHours {
67
67
  /** Employee ID */
68
68
  employeeId: number;
69
69
  /** Standard hours per week */
@@ -78,7 +78,7 @@ export interface EHStandardHours {
78
78
  *
79
79
  * From GET /business/{id}/location
80
80
  */
81
- export interface EHLocation {
81
+ export interface PayrollLocation {
82
82
  /** Location ID */
83
83
  id: number;
84
84
  /** Parent location ID (for hierarchy) */
@@ -101,7 +101,7 @@ export interface EHLocation {
101
101
  /**
102
102
  * Employee group
103
103
  */
104
- export interface EHEmployeeGroup {
104
+ export interface PayrollEmployeeGroup {
105
105
  /** Group ID */
106
106
  id: number;
107
107
  /** Group name */
@@ -112,7 +112,7 @@ export interface EHEmployeeGroup {
112
112
  *
113
113
  * From GET /business/{id}/rostershift
114
114
  */
115
- export interface EHRosterShift {
115
+ export interface PayrollRosterShift {
116
116
  /** Shift ID */
117
117
  id: number;
118
118
  /** Employee ID (null for unassigned shifts) */
@@ -141,13 +141,13 @@ export interface EHRosterShift {
141
141
  /**
142
142
  * Time and attendance status
143
143
  */
144
- export type EHAttendanceStatus = 'NotClockedOn' | 'ClockedOn' | 'OnBreak' | 'ClockedOff';
144
+ export type PayrollAttendanceStatus = 'NotClockedOn' | 'ClockedOn' | 'OnBreak' | 'ClockedOff';
145
145
  /**
146
146
  * Kiosk employee from time and attendance
147
147
  *
148
148
  * From GET /business/{id}/kiosk/{kid}/staff
149
149
  */
150
- export interface EHKioskEmployee {
150
+ export interface PayrollKioskEmployee {
151
151
  /** Employee ID */
152
152
  employeeId: number;
153
153
  /** First name */
@@ -157,7 +157,7 @@ export interface EHKioskEmployee {
157
157
  /** Full name */
158
158
  name: string | null;
159
159
  /** Attendance status */
160
- status: EHAttendanceStatus;
160
+ status: PayrollAttendanceStatus;
161
161
  /** Clock-on time in UTC */
162
162
  clockOnTimeUtc: string | null;
163
163
  /** Break start time in UTC */
@@ -179,7 +179,7 @@ export interface EHKioskEmployee {
179
179
  * From GET /business/{id}/leaverequest
180
180
  * Fields from Swagger HourLeaveRequestResponseModel.
181
181
  */
182
- export interface EHLeaveRequest {
182
+ export interface PayrollLeaveRequest {
183
183
  /** Leave request ID */
184
184
  id: number;
185
185
  /** Employee ID */
@@ -209,28 +209,28 @@ export interface EHLeaveRequest {
209
209
  * From GET /business/{id}/employee/{eid}/image
210
210
  * Returns binary data with content type.
211
211
  */
212
- export interface EHEmployeeImage {
212
+ export interface PayrollEmployeeImage {
213
213
  /** Image data as ArrayBuffer */
214
214
  data: ArrayBuffer;
215
215
  /** Content type from response header (e.g., 'image/png') */
216
216
  contentType: string;
217
217
  }
218
218
  /** Leave request status values */
219
- export type EHLeaveRequestStatus = 'Approved' | 'Pending' | 'Rejected' | 'Cancelled';
219
+ export type PayrollLeaveRequestStatus = 'Approved' | 'Pending' | 'Rejected' | 'Cancelled';
220
220
  /** Leave request grouping options */
221
- export type EHLeaveRequestGroupBy = 'Employee' | 'LeaveType';
221
+ export type PayrollLeaveRequestGroupBy = 'Employee' | 'LeaveType';
222
222
  /**
223
223
  * Options for getLeaveRequests
224
224
  *
225
225
  * All filters are passed server-side to the API.
226
226
  */
227
- export interface EHLeaveRequestOptions {
227
+ export interface PayrollLeaveRequestOptions {
228
228
  /** Filter by start date (ISO 8601 date-time → API FromDate) */
229
229
  fromDate?: string;
230
230
  /** Filter by end date (ISO 8601 date-time → API ToDate) */
231
231
  toDate?: string;
232
232
  /** Filter by status (→ API Status) */
233
- status?: EHLeaveRequestStatus;
233
+ status?: PayrollLeaveRequestStatus;
234
234
  /** Filter by employee ID (→ API EmployeeId) */
235
235
  employeeId?: number;
236
236
  /** Filter by leave category ID (→ API LeaveCategoryId) */
@@ -238,7 +238,7 @@ export interface EHLeaveRequestOptions {
238
238
  /** Filter by location ID (→ API LocationId) */
239
239
  locationId?: number;
240
240
  /** Group results by 'Employee' or 'LeaveType' (→ API GroupBy) */
241
- groupBy?: EHLeaveRequestGroupBy;
241
+ groupBy?: PayrollLeaveRequestGroupBy;
242
242
  /** Restrict results to leave overlapping the date range (→ API RestrictOverlappingLeave) */
243
243
  restrictOverlappingLeave?: boolean;
244
244
  }
@@ -247,9 +247,9 @@ export interface EHLeaveRequestOptions {
247
247
  *
248
248
  * Filters are passed as OData $filter to the per-employee endpoint.
249
249
  */
250
- export interface EHEmployeeLeaveRequestOptions {
250
+ export interface PayrollEmployeeLeaveRequestOptions {
251
251
  /** Filter by status */
252
- status?: EHLeaveRequestStatus;
252
+ status?: PayrollLeaveRequestStatus;
253
253
  /** Filter by start date (ISO 8601 date-time) */
254
254
  fromDate?: string;
255
255
  /** Filter by end date (ISO 8601 date-time) */
@@ -258,18 +258,18 @@ export interface EHEmployeeLeaveRequestOptions {
258
258
  /**
259
259
  * Options for getEmployees
260
260
  */
261
- export interface EHEmployeeOptions {
261
+ export interface PayrollEmployeeOptions {
262
262
  /** Filter by pay schedule ID */
263
263
  payScheduleId?: number;
264
264
  /** Filter by location ID */
265
265
  locationId?: number;
266
266
  }
267
267
  /** Roster shift status filter values */
268
- export type EHShiftStatus = 'All' | 'Published' | 'Unpublished' | 'Accepted';
268
+ export type PayrollShiftStatus = 'All' | 'Published' | 'Unpublished' | 'Accepted';
269
269
  /**
270
270
  * Options for getRosterShifts
271
271
  */
272
- export interface EHRosterShiftOptions {
272
+ export interface PayrollRosterShiftOptions {
273
273
  /** Filter by employee ID */
274
274
  employeeId?: number;
275
275
  /** Filter by location ID */
@@ -279,9 +279,9 @@ export interface EHRosterShiftOptions {
279
279
  /** Include shifts with all roles (default: only unassigned roles) */
280
280
  selectAllRoles?: boolean;
281
281
  /** Filter by single shift status */
282
- shiftStatus?: EHShiftStatus;
282
+ shiftStatus?: PayrollShiftStatus;
283
283
  /** Filter by multiple shift statuses */
284
- shiftStatuses?: EHShiftStatus[];
284
+ shiftStatuses?: PayrollShiftStatus[];
285
285
  /** Filter by specific locations (multiple) */
286
286
  selectedLocations?: string[];
287
287
  /** Filter by specific employees (multiple) */
@@ -300,7 +300,7 @@ export interface EHRosterShiftOptions {
300
300
  *
301
301
  * From GET /business/{id}/kiosk
302
302
  */
303
- export interface EHKiosk {
303
+ export interface PayrollKiosk {
304
304
  /** Kiosk ID */
305
305
  id: number;
306
306
  /** External identifier */
@@ -337,12 +337,12 @@ export interface EHKiosk {
337
337
  /**
338
338
  * Options for getKioskStaff
339
339
  */
340
- export interface EHKioskStaffOptions {
340
+ export interface PayrollKioskStaffOptions {
341
341
  /** Restrict current shifts to current kiosk location (default: false) */
342
342
  restrictCurrentShiftsToCurrentKioskLocation?: boolean;
343
343
  }
344
- /** Fields for EHLeaveRequest — set false to exclude from API responses */
345
- export declare const LEAVE_REQUEST_FIELDS: {
344
+ /** Fields for PayrollLeaveRequest — set false to exclude from API responses */
345
+ export declare const PAYROLL_LEAVE_REQUEST_FIELDS: {
346
346
  readonly id: true;
347
347
  readonly employeeId: true;
348
348
  readonly leaveCategoryId: true;
@@ -355,8 +355,8 @@ export declare const LEAVE_REQUEST_FIELDS: {
355
355
  readonly notes: true;
356
356
  readonly status: true;
357
357
  };
358
- /** Fields for EHLocation — set false to exclude from API responses */
359
- export declare const LOCATION_FIELDS: {
358
+ /** Fields for PayrollLocation — set false to exclude from API responses */
359
+ export declare const PAYROLL_LOCATION_FIELDS: {
360
360
  readonly id: true;
361
361
  readonly parentId: true;
362
362
  readonly name: true;
@@ -367,8 +367,8 @@ export declare const LOCATION_FIELDS: {
367
367
  readonly state: true;
368
368
  readonly country: true;
369
369
  };
370
- /** Fields for EHKiosk — set false to exclude from API responses */
371
- export declare const KIOSK_FIELDS: {
370
+ /** Fields for PayrollKiosk — set false to exclude from API responses */
371
+ export declare const PAYROLL_KIOSK_FIELDS: {
372
372
  readonly id: true;
373
373
  readonly externalId: true;
374
374
  readonly name: true;
@@ -386,8 +386,8 @@ export declare const KIOSK_FIELDS: {
386
386
  readonly canAddEmployees: true;
387
387
  readonly paidBreaksEnabled: true;
388
388
  };
389
- /** Fields for EHKioskEmployee — set false to exclude from API responses */
390
- export declare const KIOSK_EMPLOYEE_FIELDS: {
389
+ /** Fields for PayrollKioskEmployee — set false to exclude from API responses */
390
+ export declare const PAYROLL_KIOSK_EMPLOYEE_FIELDS: {
391
391
  readonly employeeId: true;
392
392
  readonly firstName: true;
393
393
  readonly surname: true;
@@ -401,13 +401,13 @@ export declare const KIOSK_EMPLOYEE_FIELDS: {
401
401
  readonly longShift: true;
402
402
  readonly recordedTimeUtc: true;
403
403
  };
404
- /** Fields for EHEmployeeGroup — set false to exclude from API responses */
405
- export declare const EMPLOYEE_GROUP_FIELDS: {
404
+ /** Fields for PayrollEmployeeGroup — set false to exclude from API responses */
405
+ export declare const PAYROLL_EMPLOYEE_GROUP_FIELDS: {
406
406
  readonly id: true;
407
407
  readonly name: true;
408
408
  };
409
- /** Fields for EHRosterShift — set false to exclude from API responses */
410
- export declare const ROSTER_SHIFT_FIELDS: {
409
+ /** Fields for PayrollRosterShift — set false to exclude from API responses */
410
+ export declare const PAYROLL_ROSTER_SHIFT_FIELDS: {
411
411
  readonly id: true;
412
412
  readonly employeeId: true;
413
413
  readonly employeeName: true;
@@ -421,8 +421,8 @@ export declare const ROSTER_SHIFT_FIELDS: {
421
421
  readonly published: true;
422
422
  readonly accepted: true;
423
423
  };
424
- /** Fields for EHEmployee — set false to exclude from API responses */
425
- export declare const EMPLOYEE_FIELDS: {
424
+ /** Fields for PayrollEmployee — set false to exclude from API responses */
425
+ export declare const PAYROLL_EMPLOYEE_FIELDS: {
426
426
  readonly id: true;
427
427
  readonly externalId: true;
428
428
  readonly firstName: true;
package/dist/types.js CHANGED
@@ -7,42 +7,42 @@
7
7
  // ============================================================================
8
8
  // Field Definitions (for pickFields)
9
9
  // ============================================================================
10
- /** Fields for EHLeaveRequest — set false to exclude from API responses */
11
- export const LEAVE_REQUEST_FIELDS = {
10
+ /** Fields for PayrollLeaveRequest — set false to exclude from API responses */
11
+ export const PAYROLL_LEAVE_REQUEST_FIELDS = {
12
12
  id: true, employeeId: true, leaveCategoryId: true, employee: true, leaveCategory: true,
13
13
  fromDate: true, toDate: true, totalHours: true, hoursApplied: true, notes: true, status: true,
14
14
  };
15
- /** Fields for EHLocation — set false to exclude from API responses */
16
- export const LOCATION_FIELDS = {
15
+ /** Fields for PayrollLocation — set false to exclude from API responses */
16
+ export const PAYROLL_LOCATION_FIELDS = {
17
17
  id: true, parentId: true, name: true, externalId: true, source: true,
18
18
  fullyQualifiedName: true, isGlobal: true, state: true, country: true,
19
19
  };
20
- /** Fields for EHKiosk — set false to exclude from API responses */
21
- export const KIOSK_FIELDS = {
20
+ /** Fields for PayrollKiosk — set false to exclude from API responses */
21
+ export const PAYROLL_KIOSK_FIELDS = {
22
22
  id: true, externalId: true, name: true, locationId: true, timeZone: true, ianaTimeZone: true,
23
23
  allowHigherClassificationSelection: true, isLocationRequired: true, isWorkTypeRequired: true,
24
24
  restrictLocationsForEmployees: true, allowEmployeeShiftSelection: true,
25
25
  clockOnWindowMinutes: true, clockOffWindowMinutes: true,
26
26
  isPhotoRequired: true, canAddEmployees: true, paidBreaksEnabled: true,
27
27
  };
28
- /** Fields for EHKioskEmployee — set false to exclude from API responses */
29
- export const KIOSK_EMPLOYEE_FIELDS = {
28
+ /** Fields for PayrollKioskEmployee — set false to exclude from API responses */
29
+ export const PAYROLL_KIOSK_EMPLOYEE_FIELDS = {
30
30
  employeeId: true, firstName: true, surname: true, name: true, status: true,
31
31
  clockOnTimeUtc: true, breakStartTimeUtc: true, currentShiftId: true,
32
32
  employeeStartDate: true, employeeGroupIds: true, longShift: true, recordedTimeUtc: true,
33
33
  };
34
- /** Fields for EHEmployeeGroup — set false to exclude from API responses */
35
- export const EMPLOYEE_GROUP_FIELDS = {
34
+ /** Fields for PayrollEmployeeGroup — set false to exclude from API responses */
35
+ export const PAYROLL_EMPLOYEE_GROUP_FIELDS = {
36
36
  id: true, name: true,
37
37
  };
38
- /** Fields for EHRosterShift — set false to exclude from API responses */
39
- export const ROSTER_SHIFT_FIELDS = {
38
+ /** Fields for PayrollRosterShift — set false to exclude from API responses */
39
+ export const PAYROLL_ROSTER_SHIFT_FIELDS = {
40
40
  id: true, employeeId: true, employeeName: true, locationId: true, locationName: true,
41
41
  workTypeId: true, workTypeName: true, startTime: true, endTime: true,
42
42
  notes: true, published: true, accepted: true,
43
43
  };
44
- /** Fields for EHEmployee — set false to exclude from API responses */
45
- export const EMPLOYEE_FIELDS = {
44
+ /** Fields for PayrollEmployee — set false to exclude from API responses */
45
+ export const PAYROLL_EMPLOYEE_FIELDS = {
46
46
  // Identity
47
47
  id: true, externalId: true, firstName: true, surname: true, status: true,
48
48
  // Dates
@@ -111,16 +111,26 @@ export const EMPLOYEE_FIELDS = {
111
111
  };
112
112
  /** Entity registry — maps interface names to field specs and API path segments. */
113
113
  export const ENTITIES = {
114
- EHEmployee: { fields: EMPLOYEE_FIELDS, path: 'employee/unstructured', apiRef: 'employee/au-employee--get-employees', apiRefById: 'employee/au-employee--get-employee-by-id' },
115
- EHLeaveRequest: { fields: LEAVE_REQUEST_FIELDS, path: 'leaverequest', apiRef: 'leave-requests/au-business-hours-leave-request--list-leave-requests' },
116
- EHEmployeeLeaveRequest: { fields: LEAVE_REQUEST_FIELDS, path: 'employee/{employeeId}/leaverequest', apiRef: 'leave-requests/au-hours-leave-request--get-leave-requests' },
117
- EHLocation: { fields: LOCATION_FIELDS, path: 'location', apiRef: 'location/au-location--get-locations' },
118
- EHRosterShift: { fields: ROSTER_SHIFT_FIELDS, path: 'rostershift', apiRef: 'roster-shifts/au-roster-shift--get' },
119
- EHKiosk: { fields: KIOSK_FIELDS, path: 'kiosk', apiRef: 'time-and-attendance/kiosk--get-all' },
120
- EHKioskEmployee: { fields: KIOSK_EMPLOYEE_FIELDS, path: 'kiosk/{kioskId}/staff', apiRef: 'time-and-attendance/generic-time-and-attendance--get-staff' },
121
- EHEmployeeGroup: { fields: EMPLOYEE_GROUP_FIELDS, path: 'employeegroup', apiRef: 'employee-groups/au-employee-group--get-groups' },
122
- EHStandardHours: { path: 'employee/{employeeId}/standardhours', apiRef: 'employee/au-employee-standard-hours--get' },
114
+ PayrollEmployee: { fields: PAYROLL_EMPLOYEE_FIELDS, path: 'employee/unstructured', apiRef: 'employee/au-employee--get-employees', apiRefById: 'employee/au-employee--get-employee-by-id' },
115
+ PayrollLeaveRequest: { fields: PAYROLL_LEAVE_REQUEST_FIELDS, path: 'leaverequest', apiRef: 'leave-requests/au-business-hours-leave-request--list-leave-requests' },
116
+ PayrollEmployeeLeaveRequest: { fields: PAYROLL_LEAVE_REQUEST_FIELDS, path: 'employee/{employeeId}/leaverequest', apiRef: 'leave-requests/au-hours-leave-request--get-leave-requests' },
117
+ PayrollLocation: { fields: PAYROLL_LOCATION_FIELDS, path: 'location', apiRef: 'location/au-location--get-locations' },
118
+ PayrollRosterShift: { fields: PAYROLL_ROSTER_SHIFT_FIELDS, path: 'rostershift', apiRef: 'roster-shifts/au-roster-shift--get' },
119
+ PayrollKiosk: { fields: PAYROLL_KIOSK_FIELDS, path: 'kiosk', apiRef: 'time-and-attendance/kiosk--get-all' },
120
+ PayrollKioskEmployee: { fields: PAYROLL_KIOSK_EMPLOYEE_FIELDS, path: 'kiosk/{kioskId}/staff', apiRef: 'time-and-attendance/generic-time-and-attendance--get-staff' },
121
+ PayrollEmployeeGroup: { fields: PAYROLL_EMPLOYEE_GROUP_FIELDS, path: 'employeegroup', apiRef: 'employee-groups/au-employee-group--get-groups' },
122
+ PayrollStandardHours: { path: 'employee/{employeeId}/standardhours', apiRef: 'employee/au-employee-standard-hours--get' },
123
123
  };
124
+ // Backward compatibility aliases for ENTITIES keys
125
+ ENTITIES.EHEmployee = ENTITIES.PayrollEmployee;
126
+ ENTITIES.EHLeaveRequest = ENTITIES.PayrollLeaveRequest;
127
+ ENTITIES.EHEmployeeLeaveRequest = ENTITIES.PayrollEmployeeLeaveRequest;
128
+ ENTITIES.EHLocation = ENTITIES.PayrollLocation;
129
+ ENTITIES.EHRosterShift = ENTITIES.PayrollRosterShift;
130
+ ENTITIES.EHKiosk = ENTITIES.PayrollKiosk;
131
+ ENTITIES.EHKioskEmployee = ENTITIES.PayrollKioskEmployee;
132
+ ENTITIES.EHEmployeeGroup = ENTITIES.PayrollEmployeeGroup;
133
+ ENTITIES.EHStandardHours = ENTITIES.PayrollStandardHours;
124
134
  /**
125
135
  * Access tier for each data method.
126
136
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markwharton/eh-payroll",
3
- "version": "3.1.0",
3
+ "version": "3.2.1",
4
4
  "description": "Employment Hero Payroll API client",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/dist/cache.d.ts DELETED
@@ -1,38 +0,0 @@
1
- /**
2
- * Simple in-memory TTL cache with request coalescing
3
- *
4
- * Provides per-instance memoization for EHClient API responses.
5
- * In serverless environments (Azure Functions, Static Web Apps),
6
- * module-level state persists across warm invocations within the
7
- * same instance — this cache leverages that behavior.
8
- *
9
- * Request coalescing: when multiple concurrent callers request the
10
- * same expired key, only one factory call is made. All callers
11
- * receive the same resolved value (or the same rejection).
12
- *
13
- * Not a distributed cache: each instance has its own cache.
14
- * Cold starts and instance recycling naturally clear stale data.
15
- */
16
- export declare class TTLCache {
17
- private store;
18
- private inflight;
19
- /**
20
- * Get a cached value, or call the factory to populate it.
21
- *
22
- * If a factory call is already in progress for this key,
23
- * returns the existing promise instead of starting a duplicate.
24
- *
25
- * @param key - Cache key
26
- * @param ttlMs - Time-to-live in milliseconds
27
- * @param factory - Async function to produce the value on cache miss
28
- */
29
- get<T>(key: string, ttlMs: number, factory: () => Promise<T>): Promise<T>;
30
- /**
31
- * Invalidate cache entries matching a key prefix.
32
- */
33
- invalidate(prefix: string): void;
34
- /**
35
- * Clear all cached data and in-flight requests.
36
- */
37
- clear(): void;
38
- }
package/dist/cache.js DELETED
@@ -1,73 +0,0 @@
1
- /**
2
- * Simple in-memory TTL cache with request coalescing
3
- *
4
- * Provides per-instance memoization for EHClient API responses.
5
- * In serverless environments (Azure Functions, Static Web Apps),
6
- * module-level state persists across warm invocations within the
7
- * same instance — this cache leverages that behavior.
8
- *
9
- * Request coalescing: when multiple concurrent callers request the
10
- * same expired key, only one factory call is made. All callers
11
- * receive the same resolved value (or the same rejection).
12
- *
13
- * Not a distributed cache: each instance has its own cache.
14
- * Cold starts and instance recycling naturally clear stale data.
15
- */
16
- export class TTLCache {
17
- constructor() {
18
- this.store = new Map();
19
- this.inflight = new Map();
20
- }
21
- /**
22
- * Get a cached value, or call the factory to populate it.
23
- *
24
- * If a factory call is already in progress for this key,
25
- * returns the existing promise instead of starting a duplicate.
26
- *
27
- * @param key - Cache key
28
- * @param ttlMs - Time-to-live in milliseconds
29
- * @param factory - Async function to produce the value on cache miss
30
- */
31
- async get(key, ttlMs, factory) {
32
- const existing = this.store.get(key);
33
- if (existing && existing.expiresAt > Date.now()) {
34
- return existing.data;
35
- }
36
- const pending = this.inflight.get(key);
37
- if (pending) {
38
- return pending;
39
- }
40
- const promise = factory().then((data) => {
41
- this.store.set(key, { data, expiresAt: Date.now() + ttlMs });
42
- this.inflight.delete(key);
43
- return data;
44
- }, (err) => {
45
- this.inflight.delete(key);
46
- throw err;
47
- });
48
- this.inflight.set(key, promise);
49
- return promise;
50
- }
51
- /**
52
- * Invalidate cache entries matching a key prefix.
53
- */
54
- invalidate(prefix) {
55
- for (const key of this.store.keys()) {
56
- if (key.startsWith(prefix)) {
57
- this.store.delete(key);
58
- }
59
- }
60
- for (const key of this.inflight.keys()) {
61
- if (key.startsWith(prefix)) {
62
- this.inflight.delete(key);
63
- }
64
- }
65
- }
66
- /**
67
- * Clear all cached data and in-flight requests.
68
- */
69
- clear() {
70
- this.store.clear();
71
- this.inflight.clear();
72
- }
73
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Sliding window rate limiter
3
- *
4
- * Enforces a maximum number of requests per time window.
5
- * Callers that exceed the limit are queued and released when capacity opens.
6
- *
7
- * Uses a sliding window approach: tracks timestamps of recent requests and
8
- * checks that no more than `maxRequests` fall within any `windowMs` period.
9
- *
10
- * Thread-safe in single-threaded JS — no races between concurrent acquire() calls.
11
- */
12
- export declare class RateLimiter {
13
- private maxRequests;
14
- private windowMs;
15
- private timestamps;
16
- private queue;
17
- private timer;
18
- /**
19
- * @param maxRequests - Maximum requests allowed per window
20
- * @param windowMs - Window size in milliseconds (default: 1000)
21
- */
22
- constructor(maxRequests: number, windowMs?: number);
23
- /**
24
- * Acquire a rate limit token.
25
- *
26
- * Resolves immediately if under the limit, otherwise queues until capacity opens.
27
- */
28
- acquire(): Promise<void>;
29
- /** Remove timestamps outside the current window */
30
- private pruneTimestamps;
31
- /** Schedule a flush to release queued callers when the oldest timestamp expires */
32
- private scheduleFlush;
33
- }
@@ -1,63 +0,0 @@
1
- /**
2
- * Sliding window rate limiter
3
- *
4
- * Enforces a maximum number of requests per time window.
5
- * Callers that exceed the limit are queued and released when capacity opens.
6
- *
7
- * Uses a sliding window approach: tracks timestamps of recent requests and
8
- * checks that no more than `maxRequests` fall within any `windowMs` period.
9
- *
10
- * Thread-safe in single-threaded JS — no races between concurrent acquire() calls.
11
- */
12
- export class RateLimiter {
13
- /**
14
- * @param maxRequests - Maximum requests allowed per window
15
- * @param windowMs - Window size in milliseconds (default: 1000)
16
- */
17
- constructor(maxRequests, windowMs = 1000) {
18
- this.maxRequests = maxRequests;
19
- this.windowMs = windowMs;
20
- this.timestamps = [];
21
- this.queue = [];
22
- this.timer = null;
23
- }
24
- /**
25
- * Acquire a rate limit token.
26
- *
27
- * Resolves immediately if under the limit, otherwise queues until capacity opens.
28
- */
29
- acquire() {
30
- this.pruneTimestamps();
31
- if (this.timestamps.length < this.maxRequests) {
32
- this.timestamps.push(Date.now());
33
- return Promise.resolve();
34
- }
35
- return new Promise(resolve => {
36
- this.queue.push({ resolve });
37
- this.scheduleFlush();
38
- });
39
- }
40
- /** Remove timestamps outside the current window */
41
- pruneTimestamps() {
42
- const cutoff = Date.now() - this.windowMs;
43
- this.timestamps = this.timestamps.filter(t => t > cutoff);
44
- }
45
- /** Schedule a flush to release queued callers when the oldest timestamp expires */
46
- scheduleFlush() {
47
- if (this.timer || this.queue.length === 0 || this.timestamps.length === 0)
48
- return;
49
- const oldest = this.timestamps[0];
50
- const delay = Math.max(0, this.windowMs - (Date.now() - oldest) + 1);
51
- this.timer = setTimeout(() => {
52
- this.timer = null;
53
- this.pruneTimestamps();
54
- while (this.queue.length > 0 && this.timestamps.length < this.maxRequests) {
55
- this.timestamps.push(Date.now());
56
- this.queue.shift().resolve();
57
- }
58
- if (this.queue.length > 0) {
59
- this.scheduleFlush();
60
- }
61
- }, delay);
62
- }
63
- }