@t4dhg/mcp-factorial 8.2.0 → 10.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.
Files changed (126) hide show
  1. package/README.md +77 -15
  2. package/dist/api/attendance.d.ts +37 -13
  3. package/dist/api/attendance.d.ts.map +1 -1
  4. package/dist/api/attendance.js +161 -31
  5. package/dist/api/attendance.js.map +1 -1
  6. package/dist/api/contracts.js +4 -4
  7. package/dist/api/contracts.js.map +1 -1
  8. package/dist/api/documents.d.ts +6 -5
  9. package/dist/api/documents.d.ts.map +1 -1
  10. package/dist/api/documents.js +17 -12
  11. package/dist/api/documents.js.map +1 -1
  12. package/dist/api/employees.d.ts +5 -3
  13. package/dist/api/employees.d.ts.map +1 -1
  14. package/dist/api/employees.js +7 -5
  15. package/dist/api/employees.js.map +1 -1
  16. package/dist/api/index.d.ts +1 -1
  17. package/dist/api/index.d.ts.map +1 -1
  18. package/dist/api/index.js +1 -1
  19. package/dist/api/index.js.map +1 -1
  20. package/dist/api/time-off.d.ts +6 -1
  21. package/dist/api/time-off.d.ts.map +1 -1
  22. package/dist/api/time-off.js +20 -16
  23. package/dist/api/time-off.js.map +1 -1
  24. package/dist/attendance/backfill.d.ts +36 -0
  25. package/dist/attendance/backfill.d.ts.map +1 -0
  26. package/dist/attendance/backfill.js +104 -0
  27. package/dist/attendance/backfill.js.map +1 -0
  28. package/dist/attendance/gate.d.ts +40 -0
  29. package/dist/attendance/gate.d.ts.map +1 -0
  30. package/dist/attendance/gate.js +63 -0
  31. package/dist/attendance/gate.js.map +1 -0
  32. package/dist/attendance/identity.d.ts +27 -0
  33. package/dist/attendance/identity.d.ts.map +1 -0
  34. package/dist/attendance/identity.js +73 -0
  35. package/dist/attendance/identity.js.map +1 -0
  36. package/dist/attendance/planner.d.ts +147 -0
  37. package/dist/attendance/planner.d.ts.map +1 -0
  38. package/dist/attendance/planner.js +316 -0
  39. package/dist/attendance/planner.js.map +1 -0
  40. package/dist/config.d.ts +1 -1
  41. package/dist/config.d.ts.map +1 -1
  42. package/dist/config.js +4 -1
  43. package/dist/config.js.map +1 -1
  44. package/dist/endpoints.d.ts +5 -0
  45. package/dist/endpoints.d.ts.map +1 -1
  46. package/dist/endpoints.js +5 -0
  47. package/dist/endpoints.js.map +1 -1
  48. package/dist/http-client.d.ts +26 -1
  49. package/dist/http-client.d.ts.map +1 -1
  50. package/dist/http-client.js +68 -8
  51. package/dist/http-client.js.map +1 -1
  52. package/dist/schemas/ats.d.ts +204 -127
  53. package/dist/schemas/ats.d.ts.map +1 -1
  54. package/dist/schemas/ats.js +77 -39
  55. package/dist/schemas/ats.js.map +1 -1
  56. package/dist/schemas/attendance.d.ts +367 -0
  57. package/dist/schemas/attendance.d.ts.map +1 -0
  58. package/dist/schemas/attendance.js +159 -0
  59. package/dist/schemas/attendance.js.map +1 -0
  60. package/dist/schemas/documents.d.ts +75 -45
  61. package/dist/schemas/documents.d.ts.map +1 -1
  62. package/dist/schemas/documents.js +44 -15
  63. package/dist/schemas/documents.js.map +1 -1
  64. package/dist/schemas/employees.d.ts +135 -77
  65. package/dist/schemas/employees.d.ts.map +1 -1
  66. package/dist/schemas/employees.js +65 -30
  67. package/dist/schemas/employees.js.map +1 -1
  68. package/dist/schemas/index.d.ts +3 -2
  69. package/dist/schemas/index.d.ts.map +1 -1
  70. package/dist/schemas/index.js +4 -2
  71. package/dist/schemas/index.js.map +1 -1
  72. package/dist/schemas/job-catalog.d.ts +39 -27
  73. package/dist/schemas/job-catalog.d.ts.map +1 -1
  74. package/dist/schemas/job-catalog.js +16 -9
  75. package/dist/schemas/job-catalog.js.map +1 -1
  76. package/dist/schemas/payroll.d.ts +89 -70
  77. package/dist/schemas/payroll.d.ts.map +1 -1
  78. package/dist/schemas/payroll.js +49 -24
  79. package/dist/schemas/payroll.js.map +1 -1
  80. package/dist/schemas/projects.d.ts +123 -97
  81. package/dist/schemas/projects.d.ts.map +1 -1
  82. package/dist/schemas/projects.js +51 -32
  83. package/dist/schemas/projects.js.map +1 -1
  84. package/dist/schemas/shared.d.ts +13 -0
  85. package/dist/schemas/shared.d.ts.map +1 -1
  86. package/dist/schemas/shared.js +13 -0
  87. package/dist/schemas/shared.js.map +1 -1
  88. package/dist/schemas/time-off.d.ts +244 -187
  89. package/dist/schemas/time-off.d.ts.map +1 -1
  90. package/dist/schemas/time-off.js +96 -63
  91. package/dist/schemas/time-off.js.map +1 -1
  92. package/dist/schemas/training.d.ts +180 -76
  93. package/dist/schemas/training.d.ts.map +1 -1
  94. package/dist/schemas/training.js +75 -25
  95. package/dist/schemas/training.js.map +1 -1
  96. package/dist/schemas/work-areas.d.ts +14 -21
  97. package/dist/schemas/work-areas.d.ts.map +1 -1
  98. package/dist/schemas/work-areas.js +9 -7
  99. package/dist/schemas/work-areas.js.map +1 -1
  100. package/dist/tools/ats.js +3 -3
  101. package/dist/tools/ats.js.map +1 -1
  102. package/dist/tools/attendance.d.ts +9 -1
  103. package/dist/tools/attendance.d.ts.map +1 -1
  104. package/dist/tools/attendance.js +314 -24
  105. package/dist/tools/attendance.js.map +1 -1
  106. package/dist/tools/documents.js +6 -6
  107. package/dist/tools/documents.js.map +1 -1
  108. package/dist/tools/index.js +2 -2
  109. package/dist/tools/index.js.map +1 -1
  110. package/dist/tools/shared.d.ts +2 -2
  111. package/dist/tools/shared.d.ts.map +1 -1
  112. package/dist/tools/shared.js +14 -2
  113. package/dist/tools/shared.js.map +1 -1
  114. package/dist/tools/time-off.d.ts.map +1 -1
  115. package/dist/tools/time-off.js +15 -6
  116. package/dist/tools/time-off.js.map +1 -1
  117. package/dist/tools/work-areas.js +2 -2
  118. package/dist/tools/work-areas.js.map +1 -1
  119. package/dist/types.d.ts +29 -14
  120. package/dist/types.d.ts.map +1 -1
  121. package/dist/write-safety.d.ts +18 -0
  122. package/dist/write-safety.d.ts.map +1 -1
  123. package/dist/write-safety.js +19 -0
  124. package/dist/write-safety.js.map +1 -1
  125. package/llms.txt +6 -4
  126. package/package.json +1 -1
package/README.md CHANGED
@@ -29,7 +29,7 @@ A comprehensive Model Context Protocol (MCP) server that provides AI assistants
29
29
 
30
30
  ### Hierarchical Tool Discovery (v8.0.0+)
31
31
 
32
- The MCP server uses a hierarchical tool structure for optimal context usage. Instead of 117 individual tools, you get 14 category-based tools with an `action` parameter.
32
+ The MCP server uses a hierarchical tool structure for optimal context usage. Instead of 123 individual tools, you get 14 category-based tools with an `action` parameter.
33
33
 
34
34
  | Tool | Description | Actions |
35
35
  | ----------------------- | ----------------------------- | -------------------------------------------------- |
@@ -39,7 +39,7 @@ The MCP server uses a hierarchical tool structure for optimal context usage. Ins
39
39
  | `factorial_locations` | Location management | list, get, create, update, delete |
40
40
  | `factorial_contracts` | Contract/salary data | list, get_with_employee, by_job_role, by_job_level |
41
41
  | `factorial_time_off` | Leave management | 10 actions |
42
- | `factorial_attendance` | Shift management | list, get, create, update, delete |
42
+ | `factorial_attendance` | Shifts and registro horario | 11 actions incl. clock_in, gaps, log_range |
43
43
  | `factorial_documents` | Document management | 8 actions (downloads require OAuth2 - see below) |
44
44
  | `factorial_job_catalog` | Job roles/levels | list_roles, get_role, list_levels |
45
45
  | `factorial_projects` | Project management | 16 actions for projects, tasks, workers, time |
@@ -73,7 +73,7 @@ factorial_time_off({
73
73
  factorial_discover({ category: 'employees' });
74
74
  ```
75
75
 
76
- ### 117 Operations Across 14 Categories
76
+ ### 123 Operations Across 14 Categories
77
77
 
78
78
  | Category | Operations |
79
79
  | --------------- | ------------------------------------------------------------------------------------------------------ |
@@ -81,7 +81,7 @@ factorial_discover({ category: 'employees' });
81
81
  | **Teams** | list, get, create, update, delete |
82
82
  | **Locations** | list, get, create, update, delete |
83
83
  | **Time Off** | list_leaves, get_leave, list_types, get_type, list_allowances, create, update, cancel, approve, reject |
84
- | **Attendance** | list, get, create, update, delete |
84
+ | **Attendance** | list, get, create, update, delete, clock_in, clock_out, status, gaps, log_range, log_days |
85
85
  | **Projects** | 16 operations for projects, tasks, workers, time records |
86
86
  | **Training** | 12 operations for trainings, sessions, enrollments |
87
87
  | **Work Areas** | list, get, create, update, archive, unarchive |
@@ -91,6 +91,45 @@ factorial_discover({ category: 'employees' });
91
91
  | **Job Catalog** | list_roles, get_role, list_levels (read-only) |
92
92
  | **Contracts** | list, get_with_employee, by_job_role, by_job_level (read-only) |
93
93
 
94
+ ### Attendance and Registro Horario
95
+
96
+ Factorial asks employees to record their working hours day by day. `factorial_attendance` lets Claude do that, for one day or for a whole month, and for any employee the API key can see.
97
+
98
+ Times are `HH:MM` in the company's local time, exactly as Factorial shows them. Records written by this server carry `source: "api"`, so they are distinguishable from live clocks in Factorial's own activity log.
99
+
100
+ | Action | What it does |
101
+ | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
102
+ | `status` | Whether the employee is clocked in and since when. Always prints the configured identity. |
103
+ | `clock_in`, `clock_out` | Live clocking at the current time. |
104
+ | `gaps` | Workdays in a date range where the contract expects more hours than were tracked. Weekends, bank holidays and full-day leave are excluded. |
105
+ | `log_range` | Apply a daily pattern (`segments`) to every workable day in a range. Skips weekends, bank holidays, days the contract expects 0 minutes, approved leave, future dates, and any segment overlapping an existing shift. |
106
+ | `log_days` | Write an explicit list of days with their segments, for migrating from another platform. Only refuses future dates, approved leave and overlaps, so a Saturday someone worked can be written. |
107
+ | `list`, `get`, `create`, `update`, `delete` | Individual shift records. `list` needs `start_on` and `end_on` (or `ids`, or `updated_at`); Factorial ignores paging on this endpoint, so paging is client-side. |
108
+
109
+ ```typescript
110
+ // Find the missing days first
111
+ factorial_attendance({ action: 'gaps', start_on: '2026-03-01', end_on: '2026-03-31' });
112
+
113
+ // Preview a month of split days; nothing is written yet
114
+ factorial_attendance({
115
+ action: 'log_range',
116
+ start_on: '2026-03-01',
117
+ end_on: '2026-03-31',
118
+ segments: [
119
+ { clock_in: '09:00', clock_out: '14:00' },
120
+ { clock_in: '15:00', clock_out: '18:00' },
121
+ ],
122
+ });
123
+ // -> "Plan for <name> (<id>) ... 20 days to write, 40 shift records, 160h ... confirmation_token: <token>"
124
+
125
+ // Same call plus the token writes it
126
+ factorial_attendance({ action: 'log_range', /* same arguments */ confirmation_token: '<token>' });
127
+ ```
128
+
129
+ "Today" for the future-date rule is the date in the zone of the machine running the server, so run it in the company's zone or accept that the boundary day may be off by one. Bank holidays come from the company's own calendar in Factorial (`worked_times.day_type`), so no holiday list is needed. Approved leave is read from `timeoff/leaves`; pass `skip_leave: false` when the source system is right and Factorial's leave record is stale. Half-day leave days are left out of `log_range` and named in the preview; write the worked half with `log_days`.
130
+
131
+ Set `FACTORIAL_EMPLOYEE_ID` to your own employee id so that `employee_id` can be omitted. Writes aimed at anyone else, and every bulk write, require a confirmation token; see [Safety & Security](#safety--security).
132
+
94
133
  ### 5 MCP Resources
95
134
 
96
135
  | Resource URI | Description |
@@ -292,16 +331,17 @@ FACTORIAL_OAUTH_REFRESH_TOKEN=your-refresh-token
292
331
 
293
332
  ## Configuration Options
294
333
 
295
- | Environment Variable | Description | Default |
296
- | ------------------------------- | ------------------------------------ | ------------ |
297
- | `FACTORIAL_API_KEY` | Your FactorialHR API key | Required |
298
- | `FACTORIAL_API_VERSION` | API version | `2025-10-01` |
299
- | `FACTORIAL_TIMEOUT_MS` | Request timeout (ms) | `30000` |
300
- | `FACTORIAL_MAX_RETRIES` | Max retry attempts | `3` |
301
- | `DEBUG` | Enable debug logging | `false` |
302
- | `FACTORIAL_OAUTH_CLIENT_ID` | OAuth2 client ID (for downloads) | - |
303
- | `FACTORIAL_OAUTH_CLIENT_SECRET` | OAuth2 client secret (for downloads) | - |
304
- | `FACTORIAL_OAUTH_REFRESH_TOKEN` | OAuth2 refresh token (for downloads) | - |
334
+ | Environment Variable | Description | Default |
335
+ | ------------------------------- | -------------------------------------------------------------------- | ------------ |
336
+ | `FACTORIAL_API_KEY` | Your FactorialHR API key | Required |
337
+ | `FACTORIAL_API_VERSION` | API version | `2026-07-01` |
338
+ | `FACTORIAL_EMPLOYEE_ID` | Your employee id: default target and ungated identity for attendance | - |
339
+ | `FACTORIAL_TIMEOUT_MS` | Request timeout (ms) | `30000` |
340
+ | `FACTORIAL_MAX_RETRIES` | Max retry attempts | `3` |
341
+ | `DEBUG` | Enable debug logging | `false` |
342
+ | `FACTORIAL_OAUTH_CLIENT_ID` | OAuth2 client ID (for downloads) | - |
343
+ | `FACTORIAL_OAUTH_CLIENT_SECRET` | OAuth2 client secret (for downloads) | - |
344
+ | `FACTORIAL_OAUTH_REFRESH_TOKEN` | OAuth2 refresh token (for downloads) | - |
305
345
 
306
346
  ## Safety & Security
307
347
 
@@ -326,6 +366,25 @@ The following operations require explicit confirmation (`confirm: true`). Called
326
366
  - `factorial_ats({ action: 'delete_candidate' })` - Permanently deletes a candidate
327
367
  - `factorial_ats({ action: 'delete_application' })` - Permanently deletes an application
328
368
 
369
+ ### Operations Gated by a Confirmation Token
370
+
371
+ Attendance writes are gated by **who they target and how many records they touch**, which a per-operation policy cannot express. A first call writes nothing and returns a preview that names the person, the dates and the totals, plus a `confirmation_token` valid for five minutes and bound to exactly that plan. Repeating the call with the token executes it; if the plan changed in between (someone wrote a shift), the token is refused and a new preview is issued. `confirm: true` cannot bypass this gate, because there is no token to pass on a first call.
372
+
373
+ Gated whenever the target is not the configured `FACTORIAL_EMPLOYEE_ID`, and always when that variable is unset:
374
+
375
+ - `factorial_attendance({ action: 'create' })` - Creates a shift for another person
376
+ - `factorial_attendance({ action: 'update' })` - Updates another person's shift (the shift is fetched first to learn whose it is)
377
+ - `factorial_attendance({ action: 'delete' })` - Deletes another person's shift, in addition to `confirm: true`
378
+ - `factorial_attendance({ action: 'clock_in' })` - Clocks another person in
379
+ - `factorial_attendance({ action: 'clock_out' })` - Clocks another person out
380
+
381
+ Always gated, whatever the target, because volume is its own hazard:
382
+
383
+ - `factorial_attendance({ action: 'log_range' })` - Writes one or more shift records per workable day in a range
384
+ - `factorial_attendance({ action: 'log_days' })` - Writes an explicit list of days
385
+
386
+ Re-running a bulk call after a partial failure is safe against its own earlier writes: the planner re-reads existing shifts and skips whatever overlaps. It does not protect against another writer between the read and the writes.
387
+
329
388
  ### Document Downloads
330
389
 
331
390
  Document names come from Factorial metadata rather than from the caller, so downloads treat them as untrusted:
@@ -505,7 +564,10 @@ A: Yes! Full CRUD operations are available for employees, teams, locations, time
505
564
  A: Data is cached in-memory with TTLs: employees (5 min), teams (10 min), locations (15 min), contracts (3 min).
506
565
 
507
566
  **Q: What FactorialHR API version is used?**
508
- A: Version `2025-10-01` by default. Override with `FACTORIAL_API_VERSION` environment variable.
567
+ A: Version `2026-07-01` by default. Override with `FACTORIAL_API_VERSION` environment variable. Since that version every Factorial identifier (`id` and `*_id` fields) is a string, not a number; treat them as opaque strings.
568
+
569
+ **Q: Can Claude fill in my registro horario?**
570
+ A: Yes. Set `FACTORIAL_EMPLOYEE_ID`, run `gaps` to see the missing days, then `log_range` with your daily segments. The first call returns a preview and a token; the second call writes. See [Attendance and Registro Horario](#attendance-and-registro-horario).
509
571
 
510
572
  **Q: Are write operations logged?**
511
573
  A: Yes, every write is recorded by the audit module with a timestamp, entity, changes, and outcome. The log lives in memory in the running process (last 1000 entries) and is not retrievable through the MCP interface, so treat it as a debugging aid rather than a compliance record. See [Audit Logging](#audit-logging).
@@ -1,27 +1,51 @@
1
1
  /**
2
- * Attendance API endpoints: Shifts
2
+ * Attendance API endpoints: shifts, open shifts, per-day summaries, clocking
3
+ *
4
+ * Verified against the live API on version 2026-07-01 (read-only, 2026-09-06):
5
+ * - /attendance/shifts honours employee_ids[], start_on, end_on, ids[],
6
+ * updated_at, workable and half_day. It ignores employee_id (singular),
7
+ * clock_in_gte, clock_in_lte, page and limit, and returns every matching
8
+ * record with `paginateable: false`. Pagination is therefore client-side.
9
+ * - Single-record GETs and every write return the record at the top level.
10
+ * - estimated_times and worked_times require employee_ids[] and start_on.
3
11
  */
4
12
  import { type PaginatedResponse } from '../pagination.js';
5
- import type { Shift, CreateShiftInput, UpdateShiftInput } from '../schemas.js';
6
- import type { ListShiftsOptions } from '../types.js';
13
+ import { type Shift, type OpenShift, type EstimatedTime, type WorkedTime, type CreateShiftInput, type UpdateShiftInput, type ClockInput } from '../schemas.js';
14
+ import type { ListShiftsOptions, DailyTimesOptions } from '../types.js';
7
15
  /**
8
- * List shifts with optional filtering
16
+ * Format a Date as ISO 8601 with the offset of the machine running the server,
17
+ * which is what the clock_in and clock_out endpoints expect in `now`.
9
18
  */
10
- export declare function listShifts(options?: ListShiftsOptions): Promise<PaginatedResponse<Shift>>;
19
+ export declare function formatLocalIso(date: Date): string;
20
+ /** Today's date, YYYY-MM-DD, in the zone of the machine running the server */
21
+ export declare function localToday(now?: Date): string;
11
22
  /**
12
- * Get a specific shift by ID
23
+ * List shifts. Refuses an unbounded query: with no date range, no ids and no
24
+ * updated_at the endpoint returns every shift in the company (tens of
25
+ * thousands of records on a real tenant).
13
26
  */
27
+ export declare function listShifts(options?: ListShiftsOptions): Promise<PaginatedResponse<Shift>>;
28
+ /** All shifts for some employees in a date range, unpaginated and validated */
29
+ export declare function listShiftsInRange(employeeIds: number[], startOn: string, endOn: string): Promise<Shift[]>;
30
+ /** Get a specific shift by ID */
14
31
  export declare function getShift(id: number): Promise<Shift>;
15
32
  /**
16
- * Create a new shift
33
+ * Create a shift. `source` is always sent as `api`, so the record is
34
+ * distinguishable from a live clock in Factorial's own activity log.
17
35
  */
18
36
  export declare function createShift(input: CreateShiftInput): Promise<Shift>;
19
- /**
20
- * Update a shift
21
- */
37
+ /** Update a shift */
22
38
  export declare function updateShift(id: number, input: UpdateShiftInput): Promise<Shift>;
23
- /**
24
- * Delete a shift
25
- */
39
+ /** Delete a shift */
26
40
  export declare function deleteShift(id: number): Promise<void>;
41
+ /** Currently open shifts, optionally for one employee */
42
+ export declare function listOpenShifts(employeeId?: number): Promise<OpenShift[]>;
43
+ /** Expected minutes per day from the weekly contract pattern */
44
+ export declare function listEstimatedTimes(options: DailyTimesOptions): Promise<EstimatedTime[]>;
45
+ /** Tracked minutes and day type per day; the holiday calendar surfaces here */
46
+ export declare function listWorkedTimes(options: DailyTimesOptions): Promise<WorkedTime[]>;
47
+ /** Clock an employee in now */
48
+ export declare function clockIn(input: ClockInput, now?: Date): Promise<Shift>;
49
+ /** Clock an employee out now */
50
+ export declare function clockOut(input: ClockInput, now?: Date): Promise<Shift>;
27
51
  //# sourceMappingURL=attendance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attendance.d.ts","sourceRoot":"","sources":["../../src/api/attendance.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAA2C,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACnG,OAAO,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAI/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAe/F;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAIzD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAKzE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAOrF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3D"}
1
+ {"version":3,"file":"attendance.d.ts","sourceRoot":"","sources":["../../src/api/attendance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAQL,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAExE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAUjD;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,GAAG,GAAE,IAAiB,GAAG,MAAM,CAEzD;AA+BD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CA4BnC;AAED,+EAA+E;AAC/E,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,KAAK,EAAE,CAAC,CAKlB;AAED,iCAAiC;AACjC,wBAAsB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAIzD;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAWzE;AAED,qBAAqB;AACrB,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAQrF;AAED,qBAAqB;AACrB,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3D;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAM9E;AAED,gEAAgE;AAChE,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAS7F;AAED,+EAA+E;AAC/E,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CASvF;AAuBD,+BAA+B;AAC/B,wBAAsB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,CAEvF;AAED,gCAAgC;AAChC,wBAAsB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,CAExF"}
@@ -1,62 +1,192 @@
1
1
  /**
2
- * Attendance API endpoints: Shifts
2
+ * Attendance API endpoints: shifts, open shifts, per-day summaries, clocking
3
+ *
4
+ * Verified against the live API on version 2026-07-01 (read-only, 2026-09-06):
5
+ * - /attendance/shifts honours employee_ids[], start_on, end_on, ids[],
6
+ * updated_at, workable and half_day. It ignores employee_id (singular),
7
+ * clock_in_gte, clock_in_lte, page and limit, and returns every matching
8
+ * record with `paginateable: false`. Pagination is therefore client-side.
9
+ * - Single-record GETs and every write return the record at the top level.
10
+ * - estimated_times and worked_times require employee_ids[] and start_on.
3
11
  */
4
- import { fetchList, fetchOne, postOne, patchOne, deleteOne } from '../http-client.js';
5
- import { buildPaginationParams, paginateResponse } from '../pagination.js';
12
+ import { fetchList, fetchOne, postOne, patchOne, deleteOne, factorialRequest, } from '../http-client.js';
13
+ import { cache } from '../cache.js';
14
+ import { buildPaginationParams, sliceForPagination, } from '../pagination.js';
15
+ import { ShiftSchema, OpenShiftSchema, EstimatedTimeSchema, WorkedTimeSchema, CreateShiftInputSchema, UpdateShiftInputSchema, ClockInputSchema, } from '../schemas.js';
16
+ import { parseData, parseArray } from '../schemas/shared.js';
6
17
  import { AuditAction, auditedOperation } from '../audit.js';
7
18
  import { validateId } from '../utils.js';
8
19
  import { ENDPOINTS, endpointWithId } from '../endpoints.js';
20
+ import { NotFoundError, UnprocessableEntityError, ValidationError } from '../errors.js';
9
21
  /**
10
- * List shifts with optional filtering
22
+ * Format a Date as ISO 8601 with the offset of the machine running the server,
23
+ * which is what the clock_in and clock_out endpoints expect in `now`.
11
24
  */
12
- export async function listShifts(options) {
13
- const params = buildPaginationParams(options);
14
- const queryParams = {
15
- page: params.page,
16
- limit: params.limit,
17
- };
18
- if (options?.employee_id)
19
- queryParams.employee_id = options.employee_id;
20
- if (options?.clock_in_gte)
21
- queryParams.clock_in_gte = options.clock_in_gte;
22
- if (options?.clock_in_lte)
23
- queryParams.clock_in_lte = options.clock_in_lte;
24
- const shifts = await fetchList(ENDPOINTS.shifts, { params: queryParams });
25
- return paginateResponse(shifts, params.page, params.limit);
25
+ export function formatLocalIso(date) {
26
+ const pad = (n) => String(n).padStart(2, '0');
27
+ const offsetMinutes = -date.getTimezoneOffset();
28
+ const sign = offsetMinutes >= 0 ? '+' : '-';
29
+ const abs = Math.abs(offsetMinutes);
30
+ return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` +
31
+ `T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}` +
32
+ `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`);
33
+ }
34
+ /** Today's date, YYYY-MM-DD, in the zone of the machine running the server */
35
+ export function localToday(now = new Date()) {
36
+ return formatLocalIso(now).slice(0, 10);
37
+ }
38
+ /**
39
+ * Factorial answers a shift write for a missing or invisible employee with
40
+ * `404 El recurso no existe`, which points at the wrong thing entirely.
41
+ */
42
+ function rewriteShiftWriteError(error, employeeId) {
43
+ if (error instanceof NotFoundError) {
44
+ throw new Error(`Factorial answered 404 to the shift write. For this endpoint that means the employee ` +
45
+ `(${employeeId ?? 'not provided'}) does not exist or is not visible to this API key, ` +
46
+ 'not that the shift endpoint is missing.');
47
+ }
48
+ if (error instanceof UnprocessableEntityError || error instanceof ValidationError) {
49
+ const message = error.message.toLowerCase();
50
+ if (message.includes('approv') ||
51
+ message.includes('edit_timesheet') ||
52
+ message.includes('permi')) {
53
+ throw new Error(`${error.message}\n\nThis tenant appears to require approval for attendance edits. ` +
54
+ 'Factorial offers an edit-timesheet-request flow (POST /attendance/edit_timesheet_requests) ' +
55
+ 'that a manager approves; this server does not implement it yet.');
56
+ }
57
+ }
58
+ throw error;
26
59
  }
27
60
  /**
28
- * Get a specific shift by ID
61
+ * List shifts. Refuses an unbounded query: with no date range, no ids and no
62
+ * updated_at the endpoint returns every shift in the company (tens of
63
+ * thousands of records on a real tenant).
29
64
  */
65
+ export async function listShifts(options = {}) {
66
+ const bounded = (options.start_on && options.end_on) ||
67
+ (options.ids && options.ids.length > 0) ||
68
+ options.updated_at;
69
+ if (!bounded) {
70
+ throw new Error('Refusing to list shifts without bounds: pass start_on and end_on (YYYY-MM-DD), or ids, ' +
71
+ 'or updated_at. Factorial ignores page and limit on this endpoint and returns every ' +
72
+ 'shift in the company otherwise.');
73
+ }
74
+ const params = buildPaginationParams(options);
75
+ const shifts = await fetchList(ENDPOINTS.shifts, {
76
+ params: {
77
+ employee_ids: options.employee_ids,
78
+ start_on: options.start_on,
79
+ end_on: options.end_on,
80
+ ids: options.ids,
81
+ updated_at: options.updated_at,
82
+ workable: options.workable,
83
+ half_day: options.half_day,
84
+ },
85
+ });
86
+ const parsed = parseArray('Shift', ShiftSchema, shifts);
87
+ return sliceForPagination(parsed, params);
88
+ }
89
+ /** All shifts for some employees in a date range, unpaginated and validated */
90
+ export async function listShiftsInRange(employeeIds, startOn, endOn) {
91
+ const shifts = await fetchList(ENDPOINTS.shifts, {
92
+ params: { employee_ids: employeeIds, start_on: startOn, end_on: endOn },
93
+ });
94
+ return parseArray('Shift', ShiftSchema, shifts);
95
+ }
96
+ /** Get a specific shift by ID */
30
97
  export async function getShift(id) {
31
98
  validateId(id, 'shift');
32
- return fetchOne(endpointWithId(ENDPOINTS.shifts, id));
99
+ const shift = await fetchOne(endpointWithId(ENDPOINTS.shifts, id));
100
+ return parseData('Shift', ShiftSchema, shift);
33
101
  }
34
102
  /**
35
- * Create a new shift
103
+ * Create a shift. `source` is always sent as `api`, so the record is
104
+ * distinguishable from a live clock in Factorial's own activity log.
36
105
  */
37
106
  export async function createShift(input) {
107
+ const body = CreateShiftInputSchema.parse(input);
38
108
  return auditedOperation(AuditAction.CREATE, 'shift', undefined, async () => {
39
- const shift = await postOne(ENDPOINTS.shifts, input);
40
- return shift;
109
+ try {
110
+ const shift = await postOne(ENDPOINTS.shifts, { ...body, source: 'api' });
111
+ cache.invalidatePrefix('shifts');
112
+ return parseData('Shift', ShiftSchema, shift);
113
+ }
114
+ catch (error) {
115
+ rewriteShiftWriteError(error, body.employee_id);
116
+ }
41
117
  });
42
118
  }
43
- /**
44
- * Update a shift
45
- */
119
+ /** Update a shift */
46
120
  export async function updateShift(id, input) {
47
121
  validateId(id, 'shift');
122
+ const body = UpdateShiftInputSchema.parse(input);
48
123
  return auditedOperation(AuditAction.UPDATE, 'shift', id, async () => {
49
- const shift = await patchOne(endpointWithId(ENDPOINTS.shifts, id), input);
50
- return shift;
124
+ const shift = await patchOne(endpointWithId(ENDPOINTS.shifts, id), body);
125
+ cache.invalidatePrefix('shifts');
126
+ return parseData('Shift', ShiftSchema, shift);
51
127
  });
52
128
  }
53
- /**
54
- * Delete a shift
55
- */
129
+ /** Delete a shift */
56
130
  export async function deleteShift(id) {
57
131
  validateId(id, 'shift');
58
132
  return auditedOperation(AuditAction.DELETE, 'shift', id, async () => {
59
133
  await deleteOne(endpointWithId(ENDPOINTS.shifts, id));
134
+ cache.invalidatePrefix('shifts');
135
+ });
136
+ }
137
+ /** Currently open shifts, optionally for one employee */
138
+ export async function listOpenShifts(employeeId) {
139
+ const data = await fetchList(ENDPOINTS.openShifts, {
140
+ params: { employee_ids: employeeId ? [employeeId] : undefined },
141
+ });
142
+ const parsed = parseArray('OpenShift', OpenShiftSchema, data);
143
+ return employeeId ? parsed.filter(s => s.employee_id === String(employeeId)) : parsed;
144
+ }
145
+ /** Expected minutes per day from the weekly contract pattern */
146
+ export async function listEstimatedTimes(options) {
147
+ const data = await fetchList(ENDPOINTS.estimatedTimes, {
148
+ params: {
149
+ employee_ids: options.employee_ids,
150
+ start_on: options.start_on,
151
+ end_on: options.end_on,
152
+ },
60
153
  });
154
+ return parseArray('EstimatedTime', EstimatedTimeSchema, data);
155
+ }
156
+ /** Tracked minutes and day type per day; the holiday calendar surfaces here */
157
+ export async function listWorkedTimes(options) {
158
+ const data = await fetchList(ENDPOINTS.workedTimes, {
159
+ params: {
160
+ employee_ids: options.employee_ids,
161
+ start_on: options.start_on,
162
+ end_on: options.end_on,
163
+ },
164
+ });
165
+ return parseArray('WorkedTime', WorkedTimeSchema, data);
166
+ }
167
+ async function clockAction(action, input, now) {
168
+ const body = ClockInputSchema.parse(input);
169
+ const endpoint = action === 'clock_in' ? ENDPOINTS.clockIn : ENDPOINTS.clockOut;
170
+ return auditedOperation(AuditAction.CREATE, `shift_${action}`, undefined, async () => {
171
+ try {
172
+ const shift = await factorialRequest(endpoint, {
173
+ method: 'POST',
174
+ body: { ...body, now: formatLocalIso(now) },
175
+ });
176
+ cache.invalidatePrefix('shifts');
177
+ return parseData('Shift', ShiftSchema, shift);
178
+ }
179
+ catch (error) {
180
+ rewriteShiftWriteError(error, body.employee_id);
181
+ }
182
+ });
183
+ }
184
+ /** Clock an employee in now */
185
+ export async function clockIn(input, now = new Date()) {
186
+ return clockAction('clock_in', input, now);
187
+ }
188
+ /** Clock an employee out now */
189
+ export async function clockOut(input, now = new Date()) {
190
+ return clockAction('clock_out', input, now);
61
191
  }
62
192
  //# sourceMappingURL=attendance.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attendance.js","sourceRoot":"","sources":["../../src/api/attendance.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAA0B,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG5D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAA2B;IAC1D,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE9C,MAAM,WAAW,GAAgD;QAC/D,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC;IAEF,IAAI,OAAO,EAAE,WAAW;QAAE,WAAW,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACxE,IAAI,OAAO,EAAE,YAAY;QAAE,WAAW,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3E,IAAI,OAAO,EAAE,YAAY;QAAE,WAAW,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAE3E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAQ,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAEjF,OAAO,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAAU;IACvC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAExB,OAAO,QAAQ,CAAQ,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAuB;IACvD,OAAO,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAQ,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC5D,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAU,EAAE,KAAuB;IACnE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAExB,OAAO,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAQ,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACjF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAU;IAC1C,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAExB,OAAO,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,SAAS,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"attendance.js","sourceRoot":"","sources":["../../src/api/attendance.ts"],"names":[],"mappings":"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"}
@@ -19,7 +19,7 @@ export async function listContracts(employeeId, options) {
19
19
  // so we fetch all contracts and filter client-side
20
20
  const allContracts = await cached('contracts:all', () => fetchList(ENDPOINTS.contracts), CACHE_TTL.contracts);
21
21
  const filtered = employeeId !== undefined
22
- ? allContracts.filter(c => c.employee_id === employeeId)
22
+ ? allContracts.filter(c => c.employee_id === String(employeeId))
23
23
  : allContracts;
24
24
  return sliceForPagination(filtered, params);
25
25
  }
@@ -30,7 +30,7 @@ export async function listContracts(employeeId, options) {
30
30
  export async function getLatestContract(employeeId) {
31
31
  validateId(employeeId, 'employee');
32
32
  const allContracts = await cached('contracts:all', () => fetchList(ENDPOINTS.contracts), CACHE_TTL.contracts);
33
- const employeeContracts = allContracts.filter(c => c.employee_id === employeeId);
33
+ const employeeContracts = allContracts.filter(c => c.employee_id === String(employeeId));
34
34
  if (employeeContracts.length === 0) {
35
35
  return null;
36
36
  }
@@ -70,7 +70,7 @@ export async function listEmployeesByJobRole(jobRoleId, options) {
70
70
  // Find contracts with this job role, grouped by employee (latest contract per employee)
71
71
  const latestContractsByEmployee = new Map();
72
72
  for (const contract of allContracts) {
73
- if (contract.job_catalog_role_id === jobRoleId) {
73
+ if (contract.job_catalog_role_id === String(jobRoleId)) {
74
74
  const existing = latestContractsByEmployee.get(contract.employee_id);
75
75
  if (!existing) {
76
76
  latestContractsByEmployee.set(contract.employee_id, contract);
@@ -113,7 +113,7 @@ export async function listEmployeesByJobLevel(jobLevelId, options) {
113
113
  // Find contracts with this job level, grouped by employee (latest contract per employee)
114
114
  const latestContractsByEmployee = new Map();
115
115
  for (const contract of allContracts) {
116
- if (contract.job_catalog_level_id === jobLevelId) {
116
+ if (contract.job_catalog_level_id === String(jobLevelId)) {
117
117
  const existing = latestContractsByEmployee.get(contract.employee_id);
118
118
  if (!existing) {
119
119
  latestContractsByEmployee.set(contract.employee_id, contract);
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/api/contracts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/api/contracts.ts"],"names":[],"mappings":"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"}
@@ -19,9 +19,10 @@ export declare function listDocuments(options?: ListDocumentsOptions): Promise<P
19
19
  /**
20
20
  * Get a specific document by ID
21
21
  *
22
- * Note: The Factorial API's individual document endpoint (/documents/documents/{id})
23
- * can be unreliable, similar to the employee endpoint. This function implements a fallback
24
- * to listing all documents and filtering if the direct endpoint fails or returns no data.
22
+ * The direct endpoint is tried first; if it answers 404 the function falls back
23
+ * to listing all documents and filtering. (Until 10.0.0 the direct endpoint always
24
+ * appeared to return nothing, because the client unwrapped a `data` envelope the
25
+ * API does not send for single records; the fallback was masking that bug.)
25
26
  *
26
27
  * IMPORTANT: Due to Factorial API limitations, this function may not find employee-specific
27
28
  * documents that were returned by listDocuments({ employee_ids: [...] }). This is because
@@ -37,7 +38,7 @@ export declare function getDocument(id: number): Promise<Document>;
37
38
  * Response from the download-urls/bulk-create endpoint
38
39
  */
39
40
  interface DownloadUrlResponse {
40
- document_id: number;
41
+ document_id: number | string;
41
42
  url: string;
42
43
  }
43
44
  /**
@@ -50,7 +51,7 @@ interface DownloadUrlResponse {
50
51
  * @returns Array of document IDs with their signed download URLs
51
52
  * @throws Error if OAuth2 is not configured or authentication fails
52
53
  */
53
- export declare function getDocumentDownloadUrls(documentIds: number[]): Promise<DownloadUrlResponse[]>;
54
+ export declare function getDocumentDownloadUrls(documentIds: string[]): Promise<DownloadUrlResponse[]>;
54
55
  /**
55
56
  * Download a document by getting its signed URL and fetching the content
56
57
  * @param idOrDocument - The document ID or a Document object (to avoid re-fetching metadata)
@@ -1 +1 @@
1
- {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/api/documents.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAA2C,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACnG,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAItD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAErD;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI3D;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAqCtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoC/D;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAoEhC;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,GAAG,QAAQ,EAC/B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CA6C/C;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC,CAmDhC;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAE/C"}
1
+ {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/api/documents.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAA2C,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACnG,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAItD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAErD;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI3D;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAqCtC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoC/D;AAED;;GAEG;AACH,UAAU,mBAAmB;IAG3B,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAwEhC;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,GAAG,QAAQ,EAC/B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAiD/C;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC,CAmDhC;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAE/C"}