@t4dhg/mcp-factorial 7.1.0 → 8.2.0

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