@t4dhg/mcp-factorial 4.0.0 → 5.0.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/dist/api.js CHANGED
@@ -7,6 +7,9 @@ import { fetchList, fetchOne, postOne, patchOne, deleteOne, postAction } from '.
7
7
  import { cache, cached, CACHE_TTL, CacheManager } from './cache.js';
8
8
  import { buildPaginationParams, paginateResponse, sliceForPagination, } from './pagination.js';
9
9
  import { AuditAction, auditedOperation } from './audit.js';
10
+ import { validateId } from './utils.js';
11
+ import { ENDPOINTS, endpointWithId, endpointWithAction } from './endpoints.js';
12
+ import { NotFoundError } from './errors.js';
10
13
  // ============================================================================
11
14
  // Employee endpoints
12
15
  // ============================================================================
@@ -19,7 +22,7 @@ export async function listEmployees(options) {
19
22
  // For filtered requests, we need to fetch all and filter client-side
20
23
  // because the API doesn't reliably filter
21
24
  if (options?.team_id || options?.location_id) {
22
- const allEmployees = await cached('employees:all', () => fetchList('/employees/employees'), CACHE_TTL.employees);
25
+ const allEmployees = await cached('employees:all', () => fetchList(ENDPOINTS.employees), CACHE_TTL.employees);
23
26
  let filtered = allEmployees;
24
27
  if (options.team_id) {
25
28
  filtered = filtered.filter(e => e.team_ids?.includes(options.team_id));
@@ -30,7 +33,7 @@ export async function listEmployees(options) {
30
33
  return sliceForPagination(filtered, params);
31
34
  }
32
35
  // Without filters, use pagination directly
33
- const employees = await cached(cacheKey, () => fetchList('/employees/employees', { params }), CACHE_TTL.employees);
36
+ const employees = await cached(cacheKey, () => fetchList(ENDPOINTS.employees, { params }), CACHE_TTL.employees);
34
37
  return paginateResponse(employees, params.page, params.limit);
35
38
  }
36
39
  /**
@@ -41,12 +44,10 @@ export async function listEmployees(options) {
41
44
  * if the direct endpoint fails or returns no data.
42
45
  */
43
46
  export async function getEmployee(id) {
44
- if (!id || id <= 0) {
45
- throw new Error('Invalid employee ID. Please provide a positive number.');
46
- }
47
+ validateId(id, 'employee');
47
48
  // Try the direct endpoint first
48
49
  try {
49
- const employee = await cached(`employee:${id}`, () => fetchOne(`/employees/employees/${id}`), CACHE_TTL.employees);
50
+ const employee = await cached(`employee:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.employees, id)), CACHE_TTL.employees);
50
51
  // If we got a valid employee, return it
51
52
  if (employee) {
52
53
  return employee;
@@ -55,13 +56,13 @@ export async function getEmployee(id) {
55
56
  catch (error) {
56
57
  // If direct fetch fails with NotFoundError, try fallback
57
58
  // (other errors will be re-thrown below)
58
- if (!(error instanceof Error && error.message.includes('not found'))) {
59
+ if (!(error instanceof NotFoundError)) {
59
60
  throw error;
60
61
  }
61
62
  }
62
63
  // Fallback: Fetch all employees and filter (same approach as searchEmployees)
63
64
  // This works around Factorial API limitations with the individual employee endpoint
64
- const allEmployees = await cached('employees:all', () => fetchList('/employees/employees'), CACHE_TTL.employees);
65
+ const allEmployees = await cached('employees:all', () => fetchList(ENDPOINTS.employees), CACHE_TTL.employees);
65
66
  const employee = allEmployees.find(emp => emp.id === id);
66
67
  if (!employee) {
67
68
  throw new Error(`Employee with ID ${id} not found.`);
@@ -75,7 +76,7 @@ export async function searchEmployees(query) {
75
76
  if (!query || query.trim().length < 2) {
76
77
  throw new Error('Search query must be at least 2 characters long.');
77
78
  }
78
- const allEmployees = await cached('employees:all', () => fetchList('/employees/employees'), CACHE_TTL.employees);
79
+ const allEmployees = await cached('employees:all', () => fetchList(ENDPOINTS.employees), CACHE_TTL.employees);
79
80
  const lowerQuery = query.toLowerCase().trim();
80
81
  return allEmployees.filter(emp => emp.full_name?.toLowerCase().includes(lowerQuery) ||
81
82
  emp.email?.toLowerCase().includes(lowerQuery) ||
@@ -91,17 +92,15 @@ export async function searchEmployees(query) {
91
92
  export async function listTeams(options) {
92
93
  const params = buildPaginationParams(options);
93
94
  const cacheKey = CacheManager.key('teams', options);
94
- const teams = await cached(cacheKey, () => fetchList('/teams/teams'), CACHE_TTL.teams);
95
+ const teams = await cached(cacheKey, () => fetchList(ENDPOINTS.teams), CACHE_TTL.teams);
95
96
  return sliceForPagination(teams, params);
96
97
  }
97
98
  /**
98
99
  * Get a specific team by ID
99
100
  */
100
101
  export async function getTeam(id) {
101
- if (!id || id <= 0) {
102
- throw new Error('Invalid team ID. Please provide a positive number.');
103
- }
104
- return cached(`team:${id}`, () => fetchOne(`/teams/teams/${id}`), CACHE_TTL.teams);
102
+ validateId(id, 'team');
103
+ return cached(`team:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.teams, id)), CACHE_TTL.teams);
105
104
  }
106
105
  // ============================================================================
107
106
  // Location endpoints
@@ -112,17 +111,15 @@ export async function getTeam(id) {
112
111
  export async function listLocations(options) {
113
112
  const params = buildPaginationParams(options);
114
113
  const cacheKey = CacheManager.key('locations', options);
115
- const locations = await cached(cacheKey, () => fetchList('/locations/locations'), CACHE_TTL.locations);
114
+ const locations = await cached(cacheKey, () => fetchList(ENDPOINTS.locations), CACHE_TTL.locations);
116
115
  return sliceForPagination(locations, params);
117
116
  }
118
117
  /**
119
118
  * Get a specific location by ID
120
119
  */
121
120
  export async function getLocation(id) {
122
- if (!id || id <= 0) {
123
- throw new Error('Invalid location ID. Please provide a positive number.');
124
- }
125
- return cached(`location:${id}`, () => fetchOne(`/locations/locations/${id}`), CACHE_TTL.locations);
121
+ validateId(id, 'location');
122
+ return cached(`location:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.locations, id)), CACHE_TTL.locations);
126
123
  }
127
124
  // ============================================================================
128
125
  // Contract endpoints
@@ -131,13 +128,13 @@ export async function getLocation(id) {
131
128
  * List contracts, optionally filtered by employee ID
132
129
  */
133
130
  export async function listContracts(employeeId, options) {
134
- if (employeeId !== undefined && employeeId <= 0) {
135
- throw new Error('Invalid employee ID. Please provide a positive number.');
131
+ if (employeeId !== undefined) {
132
+ validateId(employeeId, 'employee');
136
133
  }
137
134
  const params = buildPaginationParams(options);
138
135
  // Note: The API doesn't reliably filter by employee_id query param,
139
136
  // so we fetch all contracts and filter client-side
140
- const allContracts = await cached('contracts:all', () => fetchList('/contracts/contract-versions'), CACHE_TTL.contracts);
137
+ const allContracts = await cached('contracts:all', () => fetchList(ENDPOINTS.contracts), CACHE_TTL.contracts);
141
138
  const filtered = employeeId !== undefined
142
139
  ? allContracts.filter(c => c.employee_id === employeeId)
143
140
  : allContracts;
@@ -163,32 +160,28 @@ export async function listLeaves(options) {
163
160
  queryParams.start_on_gte = options.start_on_gte;
164
161
  if (options?.start_on_lte)
165
162
  queryParams.start_on_lte = options.start_on_lte;
166
- const leaves = await fetchList('/timeoff/leaves', { params: queryParams });
163
+ const leaves = await fetchList(ENDPOINTS.leaves, { params: queryParams });
167
164
  return paginateResponse(leaves, params.page, params.limit);
168
165
  }
169
166
  /**
170
167
  * Get a specific leave by ID
171
168
  */
172
169
  export async function getLeave(id) {
173
- if (!id || id <= 0) {
174
- throw new Error('Invalid leave ID. Please provide a positive number.');
175
- }
176
- return fetchOne(`/timeoff/leaves/${id}`);
170
+ validateId(id, 'leave');
171
+ return fetchOne(endpointWithId(ENDPOINTS.leaves, id));
177
172
  }
178
173
  /**
179
174
  * List all leave types
180
175
  */
181
176
  export async function listLeaveTypes() {
182
- return cached('leave-types:all', () => fetchList('/timeoff/leave-types'), CACHE_TTL.leaves);
177
+ return cached('leave-types:all', () => fetchList(ENDPOINTS.leaveTypes), CACHE_TTL.leaves);
183
178
  }
184
179
  /**
185
180
  * Get a specific leave type by ID
186
181
  */
187
182
  export async function getLeaveType(id) {
188
- if (!id || id <= 0) {
189
- throw new Error('Invalid leave type ID. Please provide a positive number.');
190
- }
191
- return fetchOne(`/timeoff/leave-types/${id}`);
183
+ validateId(id, 'leave type');
184
+ return fetchOne(endpointWithId(ENDPOINTS.leaveTypes, id));
192
185
  }
193
186
  /**
194
187
  * List allowances with optional filtering by employee
@@ -201,7 +194,7 @@ export async function listAllowances(options) {
201
194
  };
202
195
  if (options?.employee_id)
203
196
  queryParams.employee_id = options.employee_id;
204
- const allowances = await fetchList('/timeoff/allowances', { params: queryParams });
197
+ const allowances = await fetchList(ENDPOINTS.allowances, { params: queryParams });
205
198
  return paginateResponse(allowances, params.page, params.limit);
206
199
  }
207
200
  // ============================================================================
@@ -222,17 +215,15 @@ export async function listShifts(options) {
222
215
  queryParams.clock_in_gte = options.clock_in_gte;
223
216
  if (options?.clock_in_lte)
224
217
  queryParams.clock_in_lte = options.clock_in_lte;
225
- const shifts = await fetchList('/attendance/shifts', { params: queryParams });
218
+ const shifts = await fetchList(ENDPOINTS.shifts, { params: queryParams });
226
219
  return paginateResponse(shifts, params.page, params.limit);
227
220
  }
228
221
  /**
229
222
  * Get a specific shift by ID
230
223
  */
231
224
  export async function getShift(id) {
232
- if (!id || id <= 0) {
233
- throw new Error('Invalid shift ID. Please provide a positive number.');
234
- }
235
- return fetchOne(`/attendance/shifts/${id}`);
225
+ validateId(id, 'shift');
226
+ return fetchOne(endpointWithId(ENDPOINTS.shifts, id));
236
227
  }
237
228
  // ============================================================================
238
229
  // Document endpoints (Read-only)
@@ -241,16 +232,14 @@ export async function getShift(id) {
241
232
  * List all folders
242
233
  */
243
234
  export async function listFolders() {
244
- return cached('folders:all', () => fetchList('/documents/folders'), CACHE_TTL.default);
235
+ return cached('folders:all', () => fetchList(ENDPOINTS.folders), CACHE_TTL.default);
245
236
  }
246
237
  /**
247
238
  * Get a specific folder by ID
248
239
  */
249
240
  export async function getFolder(id) {
250
- if (!id || id <= 0) {
251
- throw new Error('Invalid folder ID. Please provide a positive number.');
252
- }
253
- return fetchOne(`/documents/folders/${id}`);
241
+ validateId(id, 'folder');
242
+ return fetchOne(endpointWithId(ENDPOINTS.folders, id));
254
243
  }
255
244
  /**
256
245
  * List documents with optional filtering by folder
@@ -271,20 +260,18 @@ export async function listDocuments(options) {
271
260
  const baseParams = new URLSearchParams(queryParams).toString();
272
261
  const fullParams = baseParams ? `${baseParams}&${employeeIdsParam}` : employeeIdsParam;
273
262
  // Make request with custom query string
274
- const documents = await fetchList(`/documents/documents?${fullParams}`);
263
+ const documents = await fetchList(`${ENDPOINTS.documents}?${fullParams}`);
275
264
  return paginateResponse(documents, params.page, params.limit);
276
265
  }
277
- const documents = await fetchList('/documents/documents', { params: queryParams });
266
+ const documents = await fetchList(ENDPOINTS.documents, { params: queryParams });
278
267
  return paginateResponse(documents, params.page, params.limit);
279
268
  }
280
269
  /**
281
270
  * Get a specific document by ID
282
271
  */
283
272
  export async function getDocument(id) {
284
- if (!id || id <= 0) {
285
- throw new Error('Invalid document ID. Please provide a positive number.');
286
- }
287
- return fetchOne(`/documents/documents/${id}`);
273
+ validateId(id, 'document');
274
+ return fetchOne(endpointWithId(ENDPOINTS.documents, id));
288
275
  }
289
276
  // ============================================================================
290
277
  // Job Catalog endpoints
@@ -293,31 +280,27 @@ export async function getDocument(id) {
293
280
  * List all job roles
294
281
  */
295
282
  export async function listJobRoles() {
296
- return cached('job-roles:all', () => fetchList('/job_catalog/roles'), CACHE_TTL.default);
283
+ return cached('job-roles:all', () => fetchList(ENDPOINTS.jobRoles), CACHE_TTL.default);
297
284
  }
298
285
  /**
299
286
  * Get a specific job role by ID
300
287
  */
301
288
  export async function getJobRole(id) {
302
- if (!id || id <= 0) {
303
- throw new Error('Invalid job role ID. Please provide a positive number.');
304
- }
305
- return fetchOne(`/job_catalog/roles/${id}`);
289
+ validateId(id, 'job role');
290
+ return fetchOne(endpointWithId(ENDPOINTS.jobRoles, id));
306
291
  }
307
292
  /**
308
293
  * List all job levels
309
294
  */
310
295
  export async function listJobLevels() {
311
- return cached('job-levels:all', () => fetchList('/job_catalog/levels'), CACHE_TTL.default);
296
+ return cached('job-levels:all', () => fetchList(ENDPOINTS.jobLevels), CACHE_TTL.default);
312
297
  }
313
298
  /**
314
299
  * Get a specific job level by ID
315
300
  */
316
301
  export async function getJobLevel(id) {
317
- if (!id || id <= 0) {
318
- throw new Error('Invalid job level ID. Please provide a positive number.');
319
- }
320
- return fetchOne(`/job_catalog/levels/${id}`);
302
+ validateId(id, 'job level');
303
+ return fetchOne(endpointWithId(ENDPOINTS.jobLevels, id));
321
304
  }
322
305
  // ============================================================================
323
306
  // Cache utilities
@@ -342,7 +325,7 @@ export function invalidateCache(resourceType) {
342
325
  */
343
326
  export async function createEmployee(input) {
344
327
  return auditedOperation(AuditAction.CREATE, 'employee', undefined, async () => {
345
- const employee = await postOne('/employees/employees', input);
328
+ const employee = await postOne(ENDPOINTS.employees, input);
346
329
  cache.invalidatePrefix('employees');
347
330
  return employee;
348
331
  }, Object.fromEntries(Object.entries(input).map(([k, v]) => [k, { to: v }])));
@@ -351,11 +334,9 @@ export async function createEmployee(input) {
351
334
  * Update an existing employee
352
335
  */
353
336
  export async function updateEmployee(id, input) {
354
- if (!id || id <= 0) {
355
- throw new Error('Invalid employee ID. Please provide a positive number.');
356
- }
337
+ validateId(id, 'employee');
357
338
  return auditedOperation(AuditAction.UPDATE, 'employee', id, async () => {
358
- const employee = await patchOne(`/employees/employees/${id}`, input);
339
+ const employee = await patchOne(endpointWithId(ENDPOINTS.employees, id), input);
359
340
  cache.invalidate(`employee:${id}`);
360
341
  cache.invalidatePrefix('employees');
361
342
  return employee;
@@ -365,11 +346,9 @@ export async function updateEmployee(id, input) {
365
346
  * Terminate an employee (soft delete)
366
347
  */
367
348
  export async function terminateEmployee(id, terminatedOn, reason) {
368
- if (!id || id <= 0) {
369
- throw new Error('Invalid employee ID. Please provide a positive number.');
370
- }
349
+ validateId(id, 'employee');
371
350
  return auditedOperation(AuditAction.TERMINATE, 'employee', id, async () => {
372
- const employee = await patchOne(`/employees/employees/${id}`, {
351
+ const employee = await patchOne(endpointWithId(ENDPOINTS.employees, id), {
373
352
  terminated_on: terminatedOn,
374
353
  });
375
354
  cache.invalidate(`employee:${id}`);
@@ -385,7 +364,7 @@ export async function terminateEmployee(id, terminatedOn, reason) {
385
364
  */
386
365
  export async function createTeam(input) {
387
366
  return auditedOperation(AuditAction.CREATE, 'team', undefined, async () => {
388
- const team = await postOne('/teams/teams', input);
367
+ const team = await postOne(ENDPOINTS.teams, input);
389
368
  cache.invalidatePrefix('teams');
390
369
  return team;
391
370
  });
@@ -394,11 +373,9 @@ export async function createTeam(input) {
394
373
  * Update an existing team
395
374
  */
396
375
  export async function updateTeam(id, input) {
397
- if (!id || id <= 0) {
398
- throw new Error('Invalid team ID. Please provide a positive number.');
399
- }
376
+ validateId(id, 'team');
400
377
  return auditedOperation(AuditAction.UPDATE, 'team', id, async () => {
401
- const team = await patchOne(`/teams/teams/${id}`, input);
378
+ const team = await patchOne(endpointWithId(ENDPOINTS.teams, id), input);
402
379
  cache.invalidate(`team:${id}`);
403
380
  cache.invalidatePrefix('teams');
404
381
  return team;
@@ -408,11 +385,9 @@ export async function updateTeam(id, input) {
408
385
  * Delete a team
409
386
  */
410
387
  export async function deleteTeam(id) {
411
- if (!id || id <= 0) {
412
- throw new Error('Invalid team ID. Please provide a positive number.');
413
- }
388
+ validateId(id, 'team');
414
389
  return auditedOperation(AuditAction.DELETE, 'team', id, async () => {
415
- await deleteOne(`/teams/teams/${id}`);
390
+ await deleteOne(endpointWithId(ENDPOINTS.teams, id));
416
391
  cache.invalidate(`team:${id}`);
417
392
  cache.invalidatePrefix('teams');
418
393
  });
@@ -425,7 +400,7 @@ export async function deleteTeam(id) {
425
400
  */
426
401
  export async function createLocation(input) {
427
402
  return auditedOperation(AuditAction.CREATE, 'location', undefined, async () => {
428
- const location = await postOne('/locations/locations', input);
403
+ const location = await postOne(ENDPOINTS.locations, input);
429
404
  cache.invalidatePrefix('locations');
430
405
  return location;
431
406
  });
@@ -434,11 +409,9 @@ export async function createLocation(input) {
434
409
  * Update an existing location
435
410
  */
436
411
  export async function updateLocation(id, input) {
437
- if (!id || id <= 0) {
438
- throw new Error('Invalid location ID. Please provide a positive number.');
439
- }
412
+ validateId(id, 'location');
440
413
  return auditedOperation(AuditAction.UPDATE, 'location', id, async () => {
441
- const location = await patchOne(`/locations/locations/${id}`, input);
414
+ const location = await patchOne(endpointWithId(ENDPOINTS.locations, id), input);
442
415
  cache.invalidate(`location:${id}`);
443
416
  cache.invalidatePrefix('locations');
444
417
  return location;
@@ -448,11 +421,9 @@ export async function updateLocation(id, input) {
448
421
  * Delete a location
449
422
  */
450
423
  export async function deleteLocation(id) {
451
- if (!id || id <= 0) {
452
- throw new Error('Invalid location ID. Please provide a positive number.');
453
- }
424
+ validateId(id, 'location');
454
425
  return auditedOperation(AuditAction.DELETE, 'location', id, async () => {
455
- await deleteOne(`/locations/locations/${id}`);
426
+ await deleteOne(endpointWithId(ENDPOINTS.locations, id));
456
427
  cache.invalidate(`location:${id}`);
457
428
  cache.invalidatePrefix('locations');
458
429
  });
@@ -465,7 +436,7 @@ export async function deleteLocation(id) {
465
436
  */
466
437
  export async function createLeave(input) {
467
438
  return auditedOperation(AuditAction.CREATE, 'leave', undefined, async () => {
468
- const leave = await postOne('/timeoff/leaves', input);
439
+ const leave = await postOne(ENDPOINTS.leaves, input);
469
440
  return leave;
470
441
  });
471
442
  }
@@ -473,11 +444,9 @@ export async function createLeave(input) {
473
444
  * Update a leave request
474
445
  */
475
446
  export async function updateLeave(id, input) {
476
- if (!id || id <= 0) {
477
- throw new Error('Invalid leave ID. Please provide a positive number.');
478
- }
447
+ validateId(id, 'leave');
479
448
  return auditedOperation(AuditAction.UPDATE, 'leave', id, async () => {
480
- const leave = await patchOne(`/timeoff/leaves/${id}`, input);
449
+ const leave = await patchOne(endpointWithId(ENDPOINTS.leaves, id), input);
481
450
  return leave;
482
451
  });
483
452
  }
@@ -485,22 +454,18 @@ export async function updateLeave(id, input) {
485
454
  * Cancel a leave request
486
455
  */
487
456
  export async function cancelLeave(id) {
488
- if (!id || id <= 0) {
489
- throw new Error('Invalid leave ID. Please provide a positive number.');
490
- }
457
+ validateId(id, 'leave');
491
458
  return auditedOperation(AuditAction.DELETE, 'leave', id, async () => {
492
- await deleteOne(`/timeoff/leaves/${id}`);
459
+ await deleteOne(endpointWithId(ENDPOINTS.leaves, id));
493
460
  });
494
461
  }
495
462
  /**
496
463
  * Approve a leave request
497
464
  */
498
465
  export async function approveLeave(id, input) {
499
- if (!id || id <= 0) {
500
- throw new Error('Invalid leave ID. Please provide a positive number.');
501
- }
466
+ validateId(id, 'leave');
502
467
  return auditedOperation(AuditAction.APPROVE, 'leave', id, async () => {
503
- const leave = await postAction(`/timeoff/leaves/${id}/approve`, input || {});
468
+ const leave = await postAction(endpointWithAction(ENDPOINTS.leaves, id, 'approve'), input || {});
504
469
  return leave;
505
470
  });
506
471
  }
@@ -508,11 +473,9 @@ export async function approveLeave(id, input) {
508
473
  * Reject a leave request
509
474
  */
510
475
  export async function rejectLeave(id, input) {
511
- if (!id || id <= 0) {
512
- throw new Error('Invalid leave ID. Please provide a positive number.');
513
- }
476
+ validateId(id, 'leave');
514
477
  return auditedOperation(AuditAction.REJECT, 'leave', id, async () => {
515
- const leave = await postAction(`/timeoff/leaves/${id}/reject`, input || {});
478
+ const leave = await postAction(endpointWithAction(ENDPOINTS.leaves, id, 'reject'), input || {});
516
479
  return leave;
517
480
  });
518
481
  }
@@ -524,7 +487,7 @@ export async function rejectLeave(id, input) {
524
487
  */
525
488
  export async function createShift(input) {
526
489
  return auditedOperation(AuditAction.CREATE, 'shift', undefined, async () => {
527
- const shift = await postOne('/attendance/shifts', input);
490
+ const shift = await postOne(ENDPOINTS.shifts, input);
528
491
  return shift;
529
492
  });
530
493
  }
@@ -532,11 +495,9 @@ export async function createShift(input) {
532
495
  * Update a shift
533
496
  */
534
497
  export async function updateShift(id, input) {
535
- if (!id || id <= 0) {
536
- throw new Error('Invalid shift ID. Please provide a positive number.');
537
- }
498
+ validateId(id, 'shift');
538
499
  return auditedOperation(AuditAction.UPDATE, 'shift', id, async () => {
539
- const shift = await patchOne(`/attendance/shifts/${id}`, input);
500
+ const shift = await patchOne(endpointWithId(ENDPOINTS.shifts, id), input);
540
501
  return shift;
541
502
  });
542
503
  }
@@ -544,11 +505,9 @@ export async function updateShift(id, input) {
544
505
  * Delete a shift
545
506
  */
546
507
  export async function deleteShift(id) {
547
- if (!id || id <= 0) {
548
- throw new Error('Invalid shift ID. Please provide a positive number.');
549
- }
508
+ validateId(id, 'shift');
550
509
  return auditedOperation(AuditAction.DELETE, 'shift', id, async () => {
551
- await deleteOne(`/attendance/shifts/${id}`);
510
+ await deleteOne(endpointWithId(ENDPOINTS.shifts, id));
552
511
  });
553
512
  }
554
513
  // ============================================================================
@@ -559,17 +518,15 @@ export async function deleteShift(id) {
559
518
  */
560
519
  export async function listProjects(options) {
561
520
  const params = buildPaginationParams(options);
562
- const projects = await cached(CacheManager.key('projects', options), () => fetchList('/project_management/projects'), CACHE_TTL.default);
521
+ const projects = await cached(CacheManager.key('projects', options), () => fetchList(ENDPOINTS.projects), CACHE_TTL.default);
563
522
  return sliceForPagination(projects, params);
564
523
  }
565
524
  /**
566
525
  * Get a specific project by ID
567
526
  */
568
527
  export async function getProject(id) {
569
- if (!id || id <= 0) {
570
- throw new Error('Invalid project ID. Please provide a positive number.');
571
- }
572
- return cached(`project:${id}`, () => fetchOne(`/project_management/projects/${id}`), CACHE_TTL.default);
528
+ validateId(id, 'project');
529
+ return cached(`project:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.projects, id)), CACHE_TTL.default);
573
530
  }
574
531
  /**
575
532
  * List project tasks
@@ -579,7 +536,7 @@ export async function listProjectTasks(projectId, options) {
579
536
  const queryParams = {};
580
537
  if (projectId)
581
538
  queryParams.project_ids = projectId;
582
- const tasks = await fetchList('/project_management/project_tasks', {
539
+ const tasks = await fetchList(ENDPOINTS.projectTasks, {
583
540
  params: queryParams,
584
541
  });
585
542
  return sliceForPagination(tasks, params);
@@ -588,10 +545,8 @@ export async function listProjectTasks(projectId, options) {
588
545
  * Get a specific project task by ID
589
546
  */
590
547
  export async function getProjectTask(id) {
591
- if (!id || id <= 0) {
592
- throw new Error('Invalid task ID. Please provide a positive number.');
593
- }
594
- return fetchOne(`/project_management/project_tasks/${id}`);
548
+ validateId(id, 'task');
549
+ return fetchOne(endpointWithId(ENDPOINTS.projectTasks, id));
595
550
  }
596
551
  /**
597
552
  * List project workers
@@ -601,7 +556,7 @@ export async function listProjectWorkers(projectId, options) {
601
556
  const queryParams = {};
602
557
  if (projectId)
603
558
  queryParams.project_ids = projectId;
604
- const workers = await fetchList('/project_management/project_workers', {
559
+ const workers = await fetchList(ENDPOINTS.projectWorkers, {
605
560
  params: queryParams,
606
561
  });
607
562
  return sliceForPagination(workers, params);
@@ -610,10 +565,8 @@ export async function listProjectWorkers(projectId, options) {
610
565
  * Get a specific project worker by ID
611
566
  */
612
567
  export async function getProjectWorker(id) {
613
- if (!id || id <= 0) {
614
- throw new Error('Invalid project worker ID. Please provide a positive number.');
615
- }
616
- return fetchOne(`/project_management/project_workers/${id}`);
568
+ validateId(id, 'project worker');
569
+ return fetchOne(endpointWithId(ENDPOINTS.projectWorkers, id));
617
570
  }
618
571
  /**
619
572
  * List time records
@@ -623,7 +576,7 @@ export async function listTimeRecords(projectWorkerId, options) {
623
576
  const queryParams = {};
624
577
  if (projectWorkerId)
625
578
  queryParams.project_workers_ids = projectWorkerId;
626
- const records = await fetchList('/project_management/time_records', {
579
+ const records = await fetchList(ENDPOINTS.timeRecords, {
627
580
  params: queryParams,
628
581
  });
629
582
  return sliceForPagination(records, params);
@@ -632,10 +585,8 @@ export async function listTimeRecords(projectWorkerId, options) {
632
585
  * Get a specific time record by ID
633
586
  */
634
587
  export async function getTimeRecord(id) {
635
- if (!id || id <= 0) {
636
- throw new Error('Invalid time record ID. Please provide a positive number.');
637
- }
638
- return fetchOne(`/project_management/time_records/${id}`);
588
+ validateId(id, 'time record');
589
+ return fetchOne(endpointWithId(ENDPOINTS.timeRecords, id));
639
590
  }
640
591
  // ============================================================================
641
592
  // Projects & Time Tracking - WRITE endpoints
@@ -645,7 +596,7 @@ export async function getTimeRecord(id) {
645
596
  */
646
597
  export async function createProject(input) {
647
598
  return auditedOperation(AuditAction.CREATE, 'project', undefined, async () => {
648
- const project = await postOne('/project_management/projects', input);
599
+ const project = await postOne(ENDPOINTS.projects, input);
649
600
  cache.invalidatePrefix('projects');
650
601
  return project;
651
602
  });
@@ -654,11 +605,9 @@ export async function createProject(input) {
654
605
  * Update a project
655
606
  */
656
607
  export async function updateProject(id, input) {
657
- if (!id || id <= 0) {
658
- throw new Error('Invalid project ID. Please provide a positive number.');
659
- }
608
+ validateId(id, 'project');
660
609
  return auditedOperation(AuditAction.UPDATE, 'project', id, async () => {
661
- const project = await patchOne(`/project_management/projects/${id}`, input);
610
+ const project = await patchOne(endpointWithId(ENDPOINTS.projects, id), input);
662
611
  cache.invalidate(`project:${id}`);
663
612
  cache.invalidatePrefix('projects');
664
613
  return project;
@@ -668,11 +617,9 @@ export async function updateProject(id, input) {
668
617
  * Delete a project
669
618
  */
670
619
  export async function deleteProject(id) {
671
- if (!id || id <= 0) {
672
- throw new Error('Invalid project ID. Please provide a positive number.');
673
- }
620
+ validateId(id, 'project');
674
621
  return auditedOperation(AuditAction.DELETE, 'project', id, async () => {
675
- await deleteOne(`/project_management/projects/${id}`);
622
+ await deleteOne(endpointWithId(ENDPOINTS.projects, id));
676
623
  cache.invalidate(`project:${id}`);
677
624
  cache.invalidatePrefix('projects');
678
625
  });
@@ -682,29 +629,25 @@ export async function deleteProject(id) {
682
629
  */
683
630
  export async function createProjectTask(input) {
684
631
  return auditedOperation(AuditAction.CREATE, 'project_task', undefined, async () => {
685
- return postOne('/project_management/project_tasks', input);
632
+ return postOne(ENDPOINTS.projectTasks, input);
686
633
  });
687
634
  }
688
635
  /**
689
636
  * Update a project task
690
637
  */
691
638
  export async function updateProjectTask(id, input) {
692
- if (!id || id <= 0) {
693
- throw new Error('Invalid task ID. Please provide a positive number.');
694
- }
639
+ validateId(id, 'task');
695
640
  return auditedOperation(AuditAction.UPDATE, 'project_task', id, async () => {
696
- return patchOne(`/project_management/project_tasks/${id}`, input);
641
+ return patchOne(endpointWithId(ENDPOINTS.projectTasks, id), input);
697
642
  });
698
643
  }
699
644
  /**
700
645
  * Delete a project task
701
646
  */
702
647
  export async function deleteProjectTask(id) {
703
- if (!id || id <= 0) {
704
- throw new Error('Invalid task ID. Please provide a positive number.');
705
- }
648
+ validateId(id, 'task');
706
649
  return auditedOperation(AuditAction.DELETE, 'project_task', id, async () => {
707
- await deleteOne(`/project_management/project_tasks/${id}`);
650
+ await deleteOne(endpointWithId(ENDPOINTS.projectTasks, id));
708
651
  });
709
652
  }
710
653
  /**
@@ -712,18 +655,16 @@ export async function deleteProjectTask(id) {
712
655
  */
713
656
  export async function assignProjectWorker(input) {
714
657
  return auditedOperation(AuditAction.ASSIGN, 'project_worker', undefined, async () => {
715
- return postOne('/project_management/project_workers', input);
658
+ return postOne(ENDPOINTS.projectWorkers, input);
716
659
  });
717
660
  }
718
661
  /**
719
662
  * Remove a worker from a project
720
663
  */
721
664
  export async function removeProjectWorker(id) {
722
- if (!id || id <= 0) {
723
- throw new Error('Invalid project worker ID. Please provide a positive number.');
724
- }
665
+ validateId(id, 'project worker');
725
666
  return auditedOperation(AuditAction.UNASSIGN, 'project_worker', id, async () => {
726
- await deleteOne(`/project_management/project_workers/${id}`);
667
+ await deleteOne(endpointWithId(ENDPOINTS.projectWorkers, id));
727
668
  });
728
669
  }
729
670
  /**
@@ -731,29 +672,25 @@ export async function removeProjectWorker(id) {
731
672
  */
732
673
  export async function createTimeRecord(input) {
733
674
  return auditedOperation(AuditAction.CREATE, 'time_record', undefined, async () => {
734
- return postOne('/project_management/time_records', input);
675
+ return postOne(ENDPOINTS.timeRecords, input);
735
676
  });
736
677
  }
737
678
  /**
738
679
  * Update a time record
739
680
  */
740
681
  export async function updateTimeRecord(id, input) {
741
- if (!id || id <= 0) {
742
- throw new Error('Invalid time record ID. Please provide a positive number.');
743
- }
682
+ validateId(id, 'time record');
744
683
  return auditedOperation(AuditAction.UPDATE, 'time_record', id, async () => {
745
- return patchOne(`/project_management/time_records/${id}`, input);
684
+ return patchOne(endpointWithId(ENDPOINTS.timeRecords, id), input);
746
685
  });
747
686
  }
748
687
  /**
749
688
  * Delete a time record
750
689
  */
751
690
  export async function deleteTimeRecord(id) {
752
- if (!id || id <= 0) {
753
- throw new Error('Invalid time record ID. Please provide a positive number.');
754
- }
691
+ validateId(id, 'time record');
755
692
  return auditedOperation(AuditAction.DELETE, 'time_record', id, async () => {
756
- await deleteOne(`/project_management/time_records/${id}`);
693
+ await deleteOne(endpointWithId(ENDPOINTS.timeRecords, id));
757
694
  });
758
695
  }
759
696
  // ============================================================================
@@ -764,17 +701,15 @@ export async function deleteTimeRecord(id) {
764
701
  */
765
702
  export async function listTrainings(options) {
766
703
  const params = buildPaginationParams(options);
767
- const trainings = await cached(CacheManager.key('trainings', options), () => fetchList('/trainings/trainings'), CACHE_TTL.default);
704
+ const trainings = await cached(CacheManager.key('trainings', options), () => fetchList(ENDPOINTS.trainings), CACHE_TTL.default);
768
705
  return sliceForPagination(trainings, params);
769
706
  }
770
707
  /**
771
708
  * Get a specific training by ID
772
709
  */
773
710
  export async function getTraining(id) {
774
- if (!id || id <= 0) {
775
- throw new Error('Invalid training ID. Please provide a positive number.');
776
- }
777
- return cached(`training:${id}`, () => fetchOne(`/trainings/trainings/${id}`), CACHE_TTL.default);
711
+ validateId(id, 'training');
712
+ return cached(`training:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.trainings, id)), CACHE_TTL.default);
778
713
  }
779
714
  /**
780
715
  * List training sessions
@@ -784,17 +719,17 @@ export async function listTrainingSessions(trainingId, options) {
784
719
  const queryParams = {};
785
720
  if (trainingId)
786
721
  queryParams.training_id = trainingId;
787
- const sessions = await fetchList('/trainings/sessions', { params: queryParams });
722
+ const sessions = await fetchList(ENDPOINTS.trainingSessions, {
723
+ params: queryParams,
724
+ });
788
725
  return sliceForPagination(sessions, params);
789
726
  }
790
727
  /**
791
728
  * Get a specific training session by ID
792
729
  */
793
730
  export async function getTrainingSession(id) {
794
- if (!id || id <= 0) {
795
- throw new Error('Invalid session ID. Please provide a positive number.');
796
- }
797
- return fetchOne(`/trainings/sessions/${id}`);
731
+ validateId(id, 'session');
732
+ return fetchOne(endpointWithId(ENDPOINTS.trainingSessions, id));
798
733
  }
799
734
  /**
800
735
  * List training enrollments
@@ -804,7 +739,7 @@ export async function listTrainingEnrollments(trainingId, options) {
804
739
  const queryParams = {};
805
740
  if (trainingId)
806
741
  queryParams.training_id = trainingId;
807
- const enrollments = await fetchList('/trainings/memberships', {
742
+ const enrollments = await fetchList(ENDPOINTS.trainingMemberships, {
808
743
  params: queryParams,
809
744
  });
810
745
  return sliceForPagination(enrollments, params);
@@ -813,10 +748,8 @@ export async function listTrainingEnrollments(trainingId, options) {
813
748
  * Get a specific training enrollment by ID
814
749
  */
815
750
  export async function getTrainingEnrollment(id) {
816
- if (!id || id <= 0) {
817
- throw new Error('Invalid enrollment ID. Please provide a positive number.');
818
- }
819
- return fetchOne(`/trainings/memberships/${id}`);
751
+ validateId(id, 'enrollment');
752
+ return fetchOne(endpointWithId(ENDPOINTS.trainingMemberships, id));
820
753
  }
821
754
  // ============================================================================
822
755
  // Training & Development - WRITE endpoints
@@ -826,7 +759,7 @@ export async function getTrainingEnrollment(id) {
826
759
  */
827
760
  export async function createTraining(input) {
828
761
  return auditedOperation(AuditAction.CREATE, 'training', undefined, async () => {
829
- const training = await postOne('/trainings/trainings', input);
762
+ const training = await postOne(ENDPOINTS.trainings, input);
830
763
  cache.invalidatePrefix('trainings');
831
764
  return training;
832
765
  });
@@ -835,11 +768,9 @@ export async function createTraining(input) {
835
768
  * Update a training program
836
769
  */
837
770
  export async function updateTraining(id, input) {
838
- if (!id || id <= 0) {
839
- throw new Error('Invalid training ID. Please provide a positive number.');
840
- }
771
+ validateId(id, 'training');
841
772
  return auditedOperation(AuditAction.UPDATE, 'training', id, async () => {
842
- const training = await patchOne(`/trainings/trainings/${id}`, input);
773
+ const training = await patchOne(endpointWithId(ENDPOINTS.trainings, id), input);
843
774
  cache.invalidate(`training:${id}`);
844
775
  cache.invalidatePrefix('trainings');
845
776
  return training;
@@ -849,11 +780,9 @@ export async function updateTraining(id, input) {
849
780
  * Delete a training program
850
781
  */
851
782
  export async function deleteTraining(id) {
852
- if (!id || id <= 0) {
853
- throw new Error('Invalid training ID. Please provide a positive number.');
854
- }
783
+ validateId(id, 'training');
855
784
  return auditedOperation(AuditAction.DELETE, 'training', id, async () => {
856
- await deleteOne(`/trainings/trainings/${id}`);
785
+ await deleteOne(endpointWithId(ENDPOINTS.trainings, id));
857
786
  cache.invalidate(`training:${id}`);
858
787
  cache.invalidatePrefix('trainings');
859
788
  });
@@ -863,29 +792,25 @@ export async function deleteTraining(id) {
863
792
  */
864
793
  export async function createTrainingSession(input) {
865
794
  return auditedOperation(AuditAction.CREATE, 'training_session', undefined, async () => {
866
- return postOne('/trainings/sessions', input);
795
+ return postOne(ENDPOINTS.trainingSessions, input);
867
796
  });
868
797
  }
869
798
  /**
870
799
  * Update a training session
871
800
  */
872
801
  export async function updateTrainingSession(id, input) {
873
- if (!id || id <= 0) {
874
- throw new Error('Invalid session ID. Please provide a positive number.');
875
- }
802
+ validateId(id, 'session');
876
803
  return auditedOperation(AuditAction.UPDATE, 'training_session', id, async () => {
877
- return patchOne(`/trainings/sessions/${id}`, input);
804
+ return patchOne(endpointWithId(ENDPOINTS.trainingSessions, id), input);
878
805
  });
879
806
  }
880
807
  /**
881
808
  * Delete a training session
882
809
  */
883
810
  export async function deleteTrainingSession(id) {
884
- if (!id || id <= 0) {
885
- throw new Error('Invalid session ID. Please provide a positive number.');
886
- }
811
+ validateId(id, 'session');
887
812
  return auditedOperation(AuditAction.DELETE, 'training_session', id, async () => {
888
- await deleteOne(`/trainings/sessions/${id}`);
813
+ await deleteOne(endpointWithId(ENDPOINTS.trainingSessions, id));
889
814
  });
890
815
  }
891
816
  /**
@@ -893,18 +818,16 @@ export async function deleteTrainingSession(id) {
893
818
  */
894
819
  export async function enrollInTraining(input) {
895
820
  return auditedOperation(AuditAction.ASSIGN, 'training_enrollment', undefined, async () => {
896
- return postOne('/trainings/memberships', input);
821
+ return postOne(ENDPOINTS.trainingMemberships, input);
897
822
  });
898
823
  }
899
824
  /**
900
825
  * Remove enrollment from a training
901
826
  */
902
827
  export async function unenrollFromTraining(id) {
903
- if (!id || id <= 0) {
904
- throw new Error('Invalid enrollment ID. Please provide a positive number.');
905
- }
828
+ validateId(id, 'enrollment');
906
829
  return auditedOperation(AuditAction.UNASSIGN, 'training_enrollment', id, async () => {
907
- await deleteOne(`/trainings/memberships/${id}`);
830
+ await deleteOne(endpointWithId(ENDPOINTS.trainingMemberships, id));
908
831
  });
909
832
  }
910
833
  // ============================================================================
@@ -915,24 +838,22 @@ export async function unenrollFromTraining(id) {
915
838
  */
916
839
  export async function listWorkAreas(options) {
917
840
  const params = buildPaginationParams(options);
918
- const workAreas = await cached(CacheManager.key('work_areas', options), () => fetchList('/locations/work_areas'), CACHE_TTL.locations);
841
+ const workAreas = await cached(CacheManager.key('work_areas', options), () => fetchList(ENDPOINTS.workAreas), CACHE_TTL.locations);
919
842
  return sliceForPagination(workAreas, params);
920
843
  }
921
844
  /**
922
845
  * Get a specific work area by ID
923
846
  */
924
847
  export async function getWorkArea(id) {
925
- if (!id || id <= 0) {
926
- throw new Error('Invalid work area ID. Please provide a positive number.');
927
- }
928
- return cached(`work_area:${id}`, () => fetchOne(`/locations/work_areas/${id}`), CACHE_TTL.locations);
848
+ validateId(id, 'work area');
849
+ return cached(`work_area:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.workAreas, id)), CACHE_TTL.locations);
929
850
  }
930
851
  /**
931
852
  * Create a work area
932
853
  */
933
854
  export async function createWorkArea(input) {
934
855
  return auditedOperation(AuditAction.CREATE, 'work_area', undefined, async () => {
935
- const workArea = await postOne('/locations/work_areas', input);
856
+ const workArea = await postOne(ENDPOINTS.workAreas, input);
936
857
  cache.invalidatePrefix('work_areas');
937
858
  return workArea;
938
859
  });
@@ -941,11 +862,9 @@ export async function createWorkArea(input) {
941
862
  * Update a work area
942
863
  */
943
864
  export async function updateWorkArea(id, input) {
944
- if (!id || id <= 0) {
945
- throw new Error('Invalid work area ID. Please provide a positive number.');
946
- }
865
+ validateId(id, 'work area');
947
866
  return auditedOperation(AuditAction.UPDATE, 'work_area', id, async () => {
948
- const workArea = await patchOne(`/locations/work_areas/${id}`, input);
867
+ const workArea = await patchOne(endpointWithId(ENDPOINTS.workAreas, id), input);
949
868
  cache.invalidate(`work_area:${id}`);
950
869
  cache.invalidatePrefix('work_areas');
951
870
  return workArea;
@@ -955,11 +874,9 @@ export async function updateWorkArea(id, input) {
955
874
  * Archive a work area
956
875
  */
957
876
  export async function archiveWorkArea(id) {
958
- if (!id || id <= 0) {
959
- throw new Error('Invalid work area ID. Please provide a positive number.');
960
- }
877
+ validateId(id, 'work area');
961
878
  return auditedOperation(AuditAction.ARCHIVE, 'work_area', id, async () => {
962
- const workArea = await postAction(`/locations/work_areas/${id}/archive`);
879
+ const workArea = await postAction(endpointWithAction(ENDPOINTS.workAreas, id, 'archive'));
963
880
  cache.invalidate(`work_area:${id}`);
964
881
  cache.invalidatePrefix('work_areas');
965
882
  return workArea;
@@ -969,11 +886,9 @@ export async function archiveWorkArea(id) {
969
886
  * Unarchive a work area
970
887
  */
971
888
  export async function unarchiveWorkArea(id) {
972
- if (!id || id <= 0) {
973
- throw new Error('Invalid work area ID. Please provide a positive number.');
974
- }
889
+ validateId(id, 'work area');
975
890
  return auditedOperation(AuditAction.UNARCHIVE, 'work_area', id, async () => {
976
- const workArea = await postAction(`/locations/work_areas/${id}/unarchive`);
891
+ const workArea = await postAction(endpointWithAction(ENDPOINTS.workAreas, id, 'unarchive'));
977
892
  cache.invalidate(`work_area:${id}`);
978
893
  cache.invalidatePrefix('work_areas');
979
894
  return workArea;
@@ -987,34 +902,30 @@ export async function unarchiveWorkArea(id) {
987
902
  */
988
903
  export async function listJobPostings(options) {
989
904
  const params = buildPaginationParams(options);
990
- const postings = await cached(CacheManager.key('job_postings', options), () => fetchList('/ats/job_postings'), CACHE_TTL.default);
905
+ const postings = await cached(CacheManager.key('job_postings', options), () => fetchList(ENDPOINTS.jobPostings), CACHE_TTL.default);
991
906
  return sliceForPagination(postings, params);
992
907
  }
993
908
  /**
994
909
  * Get a specific job posting by ID
995
910
  */
996
911
  export async function getJobPosting(id) {
997
- if (!id || id <= 0) {
998
- throw new Error('Invalid job posting ID. Please provide a positive number.');
999
- }
1000
- return cached(`job_posting:${id}`, () => fetchOne(`/ats/job_postings/${id}`), CACHE_TTL.default);
912
+ validateId(id, 'job posting');
913
+ return cached(`job_posting:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.jobPostings, id)), CACHE_TTL.default);
1001
914
  }
1002
915
  /**
1003
916
  * List all candidates
1004
917
  */
1005
918
  export async function listCandidates(options) {
1006
919
  const params = buildPaginationParams(options);
1007
- const candidates = await fetchList('/ats/candidates');
920
+ const candidates = await fetchList(ENDPOINTS.candidates);
1008
921
  return sliceForPagination(candidates, params);
1009
922
  }
1010
923
  /**
1011
924
  * Get a specific candidate by ID
1012
925
  */
1013
926
  export async function getCandidate(id) {
1014
- if (!id || id <= 0) {
1015
- throw new Error('Invalid candidate ID. Please provide a positive number.');
1016
- }
1017
- return fetchOne(`/ats/candidates/${id}`);
927
+ validateId(id, 'candidate');
928
+ return fetchOne(endpointWithId(ENDPOINTS.candidates, id));
1018
929
  }
1019
930
  /**
1020
931
  * List all applications
@@ -1024,32 +935,30 @@ export async function listApplications(jobPostingId, options) {
1024
935
  const queryParams = {};
1025
936
  if (jobPostingId)
1026
937
  queryParams.job_posting_id = jobPostingId;
1027
- const applications = await fetchList('/ats/applications', { params: queryParams });
938
+ const applications = await fetchList(ENDPOINTS.applications, {
939
+ params: queryParams,
940
+ });
1028
941
  return sliceForPagination(applications, params);
1029
942
  }
1030
943
  /**
1031
944
  * Get a specific application by ID
1032
945
  */
1033
946
  export async function getApplication(id) {
1034
- if (!id || id <= 0) {
1035
- throw new Error('Invalid application ID. Please provide a positive number.');
1036
- }
1037
- return fetchOne(`/ats/applications/${id}`);
947
+ validateId(id, 'application');
948
+ return fetchOne(endpointWithId(ENDPOINTS.applications, id));
1038
949
  }
1039
950
  /**
1040
951
  * List all hiring stages
1041
952
  */
1042
953
  export async function listHiringStages() {
1043
- return cached('hiring_stages:all', () => fetchList('/ats/hiring_stages'), CACHE_TTL.default);
954
+ return cached('hiring_stages:all', () => fetchList(ENDPOINTS.hiringStages), CACHE_TTL.default);
1044
955
  }
1045
956
  /**
1046
957
  * Get a specific hiring stage by ID
1047
958
  */
1048
959
  export async function getHiringStage(id) {
1049
- if (!id || id <= 0) {
1050
- throw new Error('Invalid hiring stage ID. Please provide a positive number.');
1051
- }
1052
- return fetchOne(`/ats/hiring_stages/${id}`);
960
+ validateId(id, 'hiring stage');
961
+ return fetchOne(endpointWithId(ENDPOINTS.hiringStages, id));
1053
962
  }
1054
963
  // ============================================================================
1055
964
  // ATS (Recruiting) - WRITE endpoints
@@ -1059,7 +968,7 @@ export async function getHiringStage(id) {
1059
968
  */
1060
969
  export async function createJobPosting(input) {
1061
970
  return auditedOperation(AuditAction.CREATE, 'job_posting', undefined, async () => {
1062
- const posting = await postOne('/ats/job_postings', input);
971
+ const posting = await postOne(ENDPOINTS.jobPostings, input);
1063
972
  cache.invalidatePrefix('job_postings');
1064
973
  return posting;
1065
974
  });
@@ -1068,11 +977,9 @@ export async function createJobPosting(input) {
1068
977
  * Update a job posting
1069
978
  */
1070
979
  export async function updateJobPosting(id, input) {
1071
- if (!id || id <= 0) {
1072
- throw new Error('Invalid job posting ID. Please provide a positive number.');
1073
- }
980
+ validateId(id, 'job posting');
1074
981
  return auditedOperation(AuditAction.UPDATE, 'job_posting', id, async () => {
1075
- const posting = await patchOne(`/ats/job_postings/${id}`, input);
982
+ const posting = await patchOne(endpointWithId(ENDPOINTS.jobPostings, id), input);
1076
983
  cache.invalidate(`job_posting:${id}`);
1077
984
  cache.invalidatePrefix('job_postings');
1078
985
  return posting;
@@ -1082,11 +989,9 @@ export async function updateJobPosting(id, input) {
1082
989
  * Delete a job posting
1083
990
  */
1084
991
  export async function deleteJobPosting(id) {
1085
- if (!id || id <= 0) {
1086
- throw new Error('Invalid job posting ID. Please provide a positive number.');
1087
- }
992
+ validateId(id, 'job posting');
1088
993
  return auditedOperation(AuditAction.DELETE, 'job_posting', id, async () => {
1089
- await deleteOne(`/ats/job_postings/${id}`);
994
+ await deleteOne(endpointWithId(ENDPOINTS.jobPostings, id));
1090
995
  cache.invalidate(`job_posting:${id}`);
1091
996
  cache.invalidatePrefix('job_postings');
1092
997
  });
@@ -1096,29 +1001,25 @@ export async function deleteJobPosting(id) {
1096
1001
  */
1097
1002
  export async function createCandidate(input) {
1098
1003
  return auditedOperation(AuditAction.CREATE, 'candidate', undefined, async () => {
1099
- return postOne('/ats/candidates', input);
1004
+ return postOne(ENDPOINTS.candidates, input);
1100
1005
  });
1101
1006
  }
1102
1007
  /**
1103
1008
  * Update a candidate
1104
1009
  */
1105
1010
  export async function updateCandidate(id, input) {
1106
- if (!id || id <= 0) {
1107
- throw new Error('Invalid candidate ID. Please provide a positive number.');
1108
- }
1011
+ validateId(id, 'candidate');
1109
1012
  return auditedOperation(AuditAction.UPDATE, 'candidate', id, async () => {
1110
- return patchOne(`/ats/candidates/${id}`, input);
1013
+ return patchOne(endpointWithId(ENDPOINTS.candidates, id), input);
1111
1014
  });
1112
1015
  }
1113
1016
  /**
1114
1017
  * Delete a candidate
1115
1018
  */
1116
1019
  export async function deleteCandidate(id) {
1117
- if (!id || id <= 0) {
1118
- throw new Error('Invalid candidate ID. Please provide a positive number.');
1119
- }
1020
+ validateId(id, 'candidate');
1120
1021
  return auditedOperation(AuditAction.DELETE, 'candidate', id, async () => {
1121
- await deleteOne(`/ats/candidates/${id}`);
1022
+ await deleteOne(endpointWithId(ENDPOINTS.candidates, id));
1122
1023
  });
1123
1024
  }
1124
1025
  /**
@@ -1126,40 +1027,34 @@ export async function deleteCandidate(id) {
1126
1027
  */
1127
1028
  export async function createApplication(input) {
1128
1029
  return auditedOperation(AuditAction.CREATE, 'application', undefined, async () => {
1129
- return postOne('/ats/applications', input);
1030
+ return postOne(ENDPOINTS.applications, input);
1130
1031
  });
1131
1032
  }
1132
1033
  /**
1133
1034
  * Update an application
1134
1035
  */
1135
1036
  export async function updateApplication(id, input) {
1136
- if (!id || id <= 0) {
1137
- throw new Error('Invalid application ID. Please provide a positive number.');
1138
- }
1037
+ validateId(id, 'application');
1139
1038
  return auditedOperation(AuditAction.UPDATE, 'application', id, async () => {
1140
- return patchOne(`/ats/applications/${id}`, input);
1039
+ return patchOne(endpointWithId(ENDPOINTS.applications, id), input);
1141
1040
  });
1142
1041
  }
1143
1042
  /**
1144
1043
  * Delete an application
1145
1044
  */
1146
1045
  export async function deleteApplication(id) {
1147
- if (!id || id <= 0) {
1148
- throw new Error('Invalid application ID. Please provide a positive number.');
1149
- }
1046
+ validateId(id, 'application');
1150
1047
  return auditedOperation(AuditAction.DELETE, 'application', id, async () => {
1151
- await deleteOne(`/ats/applications/${id}`);
1048
+ await deleteOne(endpointWithId(ENDPOINTS.applications, id));
1152
1049
  });
1153
1050
  }
1154
1051
  /**
1155
1052
  * Advance an application to the next stage
1156
1053
  */
1157
1054
  export async function advanceApplication(id) {
1158
- if (!id || id <= 0) {
1159
- throw new Error('Invalid application ID. Please provide a positive number.');
1160
- }
1055
+ validateId(id, 'application');
1161
1056
  return auditedOperation(AuditAction.UPDATE, 'application', id, async () => {
1162
- return postAction(`/ats/applications/${id}/apply`);
1057
+ return postAction(endpointWithAction(ENDPOINTS.applications, id, 'apply'));
1163
1058
  });
1164
1059
  }
1165
1060
  // ============================================================================
@@ -1173,7 +1068,7 @@ export async function listPayrollSupplements(employeeId, options) {
1173
1068
  const queryParams = {};
1174
1069
  if (employeeId)
1175
1070
  queryParams.employee_id = employeeId;
1176
- const supplements = await fetchList('/payroll/supplements', {
1071
+ const supplements = await fetchList(ENDPOINTS.payrollSupplements, {
1177
1072
  params: queryParams,
1178
1073
  });
1179
1074
  return sliceForPagination(supplements, params);
@@ -1182,10 +1077,8 @@ export async function listPayrollSupplements(employeeId, options) {
1182
1077
  * Get a specific payroll supplement by ID
1183
1078
  */
1184
1079
  export async function getPayrollSupplement(id) {
1185
- if (!id || id <= 0) {
1186
- throw new Error('Invalid supplement ID. Please provide a positive number.');
1187
- }
1188
- return fetchOne(`/payroll/supplements/${id}`);
1080
+ validateId(id, 'supplement');
1081
+ return fetchOne(endpointWithId(ENDPOINTS.payrollSupplements, id));
1189
1082
  }
1190
1083
  /**
1191
1084
  * List tax identifiers
@@ -1195,7 +1088,7 @@ export async function listTaxIdentifiers(employeeId, options) {
1195
1088
  const queryParams = {};
1196
1089
  if (employeeId)
1197
1090
  queryParams.employee_id = employeeId;
1198
- const identifiers = await fetchList('/payroll_employees/identifiers', {
1091
+ const identifiers = await fetchList(ENDPOINTS.taxIdentifiers, {
1199
1092
  params: queryParams,
1200
1093
  });
1201
1094
  return sliceForPagination(identifiers, params);
@@ -1204,10 +1097,8 @@ export async function listTaxIdentifiers(employeeId, options) {
1204
1097
  * Get a specific tax identifier by ID
1205
1098
  */
1206
1099
  export async function getTaxIdentifier(id) {
1207
- if (!id || id <= 0) {
1208
- throw new Error('Invalid tax identifier ID. Please provide a positive number.');
1209
- }
1210
- return fetchOne(`/payroll_employees/identifiers/${id}`);
1100
+ validateId(id, 'tax identifier');
1101
+ return fetchOne(endpointWithId(ENDPOINTS.taxIdentifiers, id));
1211
1102
  }
1212
1103
  /**
1213
1104
  * List family situations
@@ -1217,7 +1108,7 @@ export async function listFamilySituations(employeeId, options) {
1217
1108
  const queryParams = {};
1218
1109
  if (employeeId)
1219
1110
  queryParams.employee_id = employeeId;
1220
- const situations = await fetchList('/payroll/family_situations', {
1111
+ const situations = await fetchList(ENDPOINTS.familySituations, {
1221
1112
  params: queryParams,
1222
1113
  });
1223
1114
  return sliceForPagination(situations, params);
@@ -1226,9 +1117,7 @@ export async function listFamilySituations(employeeId, options) {
1226
1117
  * Get a specific family situation by ID
1227
1118
  */
1228
1119
  export async function getFamilySituation(id) {
1229
- if (!id || id <= 0) {
1230
- throw new Error('Invalid family situation ID. Please provide a positive number.');
1231
- }
1232
- return fetchOne(`/payroll/family_situations/${id}`);
1120
+ validateId(id, 'family situation');
1121
+ return fetchOne(endpointWithId(ENDPOINTS.familySituations, id));
1233
1122
  }
1234
1123
  //# sourceMappingURL=api.js.map