@factorialco/api-client 3.0.0-beta.2026100139 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -28
- package/dist/cjs/errors.d.ts +96 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +155 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/generated/sdk.gen.d.ts +27 -1
- package/dist/cjs/generated/sdk.gen.d.ts.map +1 -1
- package/dist/cjs/generated/sdk.gen.js +27 -1
- package/dist/cjs/generated/sdk.gen.js.map +1 -1
- package/dist/cjs/generated/types.gen.d.ts +3 -3
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +6 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/pagination.d.ts +5 -3
- package/dist/cjs/pagination.d.ts.map +1 -1
- package/dist/cjs/pagination.js +5 -6
- package/dist/cjs/pagination.js.map +1 -1
- package/dist/cjs/sdk.d.ts +976 -956
- package/dist/cjs/sdk.d.ts.map +1 -1
- package/dist/cjs/sdk.js +871 -347
- package/dist/cjs/sdk.js.map +1 -1
- package/dist/esm/errors.d.ts +96 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +149 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/generated/sdk.gen.d.ts +27 -1
- package/dist/esm/generated/sdk.gen.d.ts.map +1 -1
- package/dist/esm/generated/sdk.gen.js +27 -1
- package/dist/esm/generated/sdk.gen.js.map +1 -1
- package/dist/esm/generated/types.gen.d.ts +3 -3
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pagination.d.ts +5 -3
- package/dist/esm/pagination.d.ts.map +1 -1
- package/dist/esm/pagination.js +5 -6
- package/dist/esm/pagination.js.map +1 -1
- package/dist/esm/sdk.d.ts +976 -956
- package/dist/esm/sdk.d.ts.map +1 -1
- package/dist/esm/sdk.js +864 -342
- package/dist/esm/sdk.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -10,15 +10,18 @@ The SDK uses standard semver (`MAJOR.MINOR.PATCH`), independent of the Factorial
|
|
|
10
10
|
|-------------|----------------------|
|
|
11
11
|
| `1.x.y` | `2026-04-01` |
|
|
12
12
|
| `2.x.y` | `2026-07-01` |
|
|
13
|
+
| `3.x.y` | `2026-10-01` |
|
|
13
14
|
|
|
14
|
-
Factorial releases new API versions quarterly (Jan/Apr/Jul/Oct).
|
|
15
|
+
Factorial releases new API versions quarterly (Jan/Apr/Jul/Oct). A new major is
|
|
16
|
+
usually cut for a new API version, but can also be cut for a breaking change to
|
|
17
|
+
the SDK itself — which is why `2.x` and `3.x` target the same API version.
|
|
15
18
|
|
|
16
19
|
See the [Factorial API versioning docs](https://apidoc.factorialhr.com/docs/api-versioning) for details.
|
|
17
20
|
|
|
18
21
|
## Installation
|
|
19
22
|
|
|
20
23
|
```sh
|
|
21
|
-
npm install @factorialco/api-client@2026-
|
|
24
|
+
npm install @factorialco/api-client@2026-10-01
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
## Quick start
|
|
@@ -30,8 +33,10 @@ const client = new FactorialClient({
|
|
|
30
33
|
apiKey: process.env.FACTORIAL_API_KEY,
|
|
31
34
|
});
|
|
32
35
|
|
|
33
|
-
const { data:
|
|
34
|
-
|
|
36
|
+
const { data: page } = await client.employees.employees.list({
|
|
37
|
+
query: { only_active: true, only_managers: false },
|
|
38
|
+
});
|
|
39
|
+
console.log(`${page.meta?.total} employees total`);
|
|
35
40
|
```
|
|
36
41
|
|
|
37
42
|
## Authentication
|
|
@@ -90,8 +95,8 @@ Every resource exposes the standard methods available in the API:
|
|
|
90
95
|
|
|
91
96
|
```ts
|
|
92
97
|
// List (single page, up to 100 items)
|
|
93
|
-
const { data:
|
|
94
|
-
query: { only_active: true },
|
|
98
|
+
const { data: page } = await client.employees.employees.list({
|
|
99
|
+
query: { only_active: true, only_managers: false },
|
|
95
100
|
});
|
|
96
101
|
|
|
97
102
|
// Get by ID
|
|
@@ -115,40 +120,53 @@ await client.timeoff.leaves.delete({ path: { id: 99 } });
|
|
|
115
120
|
|
|
116
121
|
// Named actions
|
|
117
122
|
await client.timeoff.leaves.approve({ body: { id: 99 } });
|
|
118
|
-
await client.attendance.shifts.clockIn({
|
|
123
|
+
await client.attendance.shifts.clockIn({
|
|
124
|
+
body: { employee_id: 1, now: new Date().toISOString().slice(0, 19) },
|
|
125
|
+
});
|
|
119
126
|
```
|
|
120
127
|
|
|
121
128
|
## Pagination
|
|
122
129
|
|
|
123
|
-
The Factorial API uses **cursor-based pagination**.
|
|
124
|
-
`{ data: { data, meta }
|
|
130
|
+
The Factorial API uses **cursor-based pagination**. Every list endpoint resolves
|
|
131
|
+
to `{ data: { data, meta }, request, response }`, where `meta` carries
|
|
132
|
+
`has_next_page`, `end_cursor`, and `total`. The spec marks `data` and `meta`
|
|
133
|
+
optional, so access them with `?.`. A non-2xx response throws — see
|
|
134
|
+
[Error handling](#error-handling).
|
|
125
135
|
|
|
126
136
|
### Single page
|
|
127
137
|
|
|
128
138
|
```ts
|
|
129
|
-
const { data:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const page2 = await client.employees.employees.list({
|
|
134
|
-
query: { limit: 50, after_id: meta.end_cursor },
|
|
135
|
-
});
|
|
136
|
-
}
|
|
139
|
+
const { data: page } = await client.employees.employees.list({
|
|
140
|
+
query: { only_active: true, only_managers: false },
|
|
141
|
+
});
|
|
142
|
+
console.log(page.data?.length, page.meta?.has_next_page);
|
|
137
143
|
```
|
|
138
144
|
|
|
145
|
+
`limit` and `after_id` work at runtime but are absent from the OpenAPI spec, so
|
|
146
|
+
they are not part of the typed `query`. Prefer `paginate({ limit })` below; to
|
|
147
|
+
cursor by hand, cast the query.
|
|
148
|
+
|
|
139
149
|
### Stream all pages (async iterator)
|
|
140
150
|
|
|
141
151
|
```ts
|
|
142
|
-
for await (const employee of client.employees.employees.paginate(
|
|
152
|
+
for await (const employee of client.employees.employees.paginate({
|
|
153
|
+
query: { only_active: true, only_managers: false },
|
|
154
|
+
})) {
|
|
143
155
|
console.log(employee.full_name);
|
|
144
156
|
}
|
|
145
157
|
```
|
|
146
158
|
|
|
159
|
+
`paginate()` and `all()` accept `limit` (items per request, max 100) and
|
|
160
|
+
`maxItems` (a cap on the total fetched) alongside the endpoint's own options.
|
|
161
|
+
|
|
147
162
|
### Collect all into array
|
|
148
163
|
|
|
149
164
|
```ts
|
|
150
165
|
// Optional safety cap via maxItems
|
|
151
|
-
const all = await client.employees.employees.all({
|
|
166
|
+
const all = await client.employees.employees.all({
|
|
167
|
+
query: { only_active: true, only_managers: false },
|
|
168
|
+
maxItems: 500,
|
|
169
|
+
});
|
|
152
170
|
```
|
|
153
171
|
|
|
154
172
|
Both `paginate()` and `all()` are available on every list endpoint.
|
|
@@ -172,23 +190,47 @@ There is no server-side aggregation endpoint; compute totals client-side.
|
|
|
172
190
|
|
|
173
191
|
## Error handling
|
|
174
192
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
Any non-2xx response (bad/expired token, wrong base URL, `4xx`/`5xx`) **throws a
|
|
194
|
+
`FactorialApiError`** rather than resolving to empty data. Results carry no
|
|
195
|
+
`error` field — wrap calls in `try`/`catch`:
|
|
178
196
|
|
|
179
197
|
```ts
|
|
198
|
+
import { FactorialApiError, FactorialClient } from "@factorialco/api-client";
|
|
199
|
+
|
|
180
200
|
try {
|
|
181
|
-
const { data } = await client.employees.employees.
|
|
201
|
+
const { data } = await client.employees.employees.get({ path: { id: "42" } });
|
|
182
202
|
console.log(data);
|
|
183
203
|
} catch (err) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
204
|
+
if (err instanceof FactorialApiError) {
|
|
205
|
+
console.error(err.status); // 404
|
|
206
|
+
console.error(err.method); // "GET"
|
|
207
|
+
console.error(err.url); // full request URL
|
|
208
|
+
console.error(err.body); // parsed error body from the API
|
|
209
|
+
console.error(err.message); // "Factorial API 404 Not Found: GET https://… — {…}"
|
|
210
|
+
} else {
|
|
211
|
+
// Transport failure (DNS, connection reset, abort) — not an HTTP response.
|
|
212
|
+
throw err;
|
|
213
|
+
}
|
|
187
214
|
}
|
|
188
215
|
```
|
|
189
216
|
|
|
190
|
-
|
|
191
|
-
|
|
217
|
+
`FactorialApiError` fields:
|
|
218
|
+
|
|
219
|
+
| Field | Type | Notes |
|
|
220
|
+
|-------|------|-------|
|
|
221
|
+
| `status` | `number` | HTTP status code |
|
|
222
|
+
| `statusText` | `string` | Reason phrase; empty over HTTP/2 |
|
|
223
|
+
| `method` | `string` | Request method |
|
|
224
|
+
| `url` | `string` | Full request URL, including the query string |
|
|
225
|
+
| `body` | `unknown` | Parsed JSON, the raw string for non-JSON, `undefined` when empty |
|
|
226
|
+
| `headers` | `Headers` | Response headers; non-enumerable |
|
|
227
|
+
| `response` | `Response` | Raw response; non-enumerable, body already consumed |
|
|
228
|
+
|
|
229
|
+
`headers` and `response` are non-enumerable so `console.error(err)` stays
|
|
230
|
+
readable — they are still accessible directly.
|
|
231
|
+
|
|
232
|
+
Across package copies (the ESM + CJS dual-package hazard) `instanceof` can fail;
|
|
233
|
+
`isFactorialApiError(err)` is a name-based fallback for that case.
|
|
192
234
|
|
|
193
235
|
## Webhooks
|
|
194
236
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types for the Factorial API client.
|
|
3
|
+
*
|
|
4
|
+
* Every non-2xx HTTP response is thrown as a {@link FactorialApiError} carrying
|
|
5
|
+
* the status, method, URL and parsed body. Transport failures (DNS, connection
|
|
6
|
+
* reset, aborted request) are *not* wrapped — they surface as the underlying
|
|
7
|
+
* error, typically a `TypeError` from `fetch`.
|
|
8
|
+
*/
|
|
9
|
+
/** Constructor payload for {@link FactorialApiError}. */
|
|
10
|
+
export interface FactorialApiErrorInit {
|
|
11
|
+
/** HTTP status code, e.g. `401`. */
|
|
12
|
+
status: number;
|
|
13
|
+
/** HTTP reason phrase, e.g. `"Unauthorized"`. Empty over HTTP/2. */
|
|
14
|
+
statusText: string;
|
|
15
|
+
/** HTTP method of the failed request, e.g. `"GET"`. */
|
|
16
|
+
method: string;
|
|
17
|
+
/** Full request URL, including the query string. */
|
|
18
|
+
url: string;
|
|
19
|
+
/**
|
|
20
|
+
* Response body: the parsed JSON when the body was valid JSON, the raw string
|
|
21
|
+
* for non-JSON bodies, `undefined` when the body was empty.
|
|
22
|
+
*/
|
|
23
|
+
body: unknown;
|
|
24
|
+
/** Response headers. Rate-limit and request-id headers live here. */
|
|
25
|
+
headers?: Headers;
|
|
26
|
+
/** The raw `Response`, when one was produced. */
|
|
27
|
+
response?: Response;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown for every non-2xx response from the Factorial API.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* try {
|
|
35
|
+
* await client.employees.employees.get({ path: { id: "1" } });
|
|
36
|
+
* } catch (err) {
|
|
37
|
+
* if (err instanceof FactorialApiError) {
|
|
38
|
+
* console.error(err.status, err.method, err.url, err.body);
|
|
39
|
+
* } else {
|
|
40
|
+
* throw err; // transport failure (e.g. a fetch TypeError)
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare class FactorialApiError extends Error {
|
|
46
|
+
/** HTTP status code, e.g. `401`. */
|
|
47
|
+
readonly status: number;
|
|
48
|
+
/** HTTP reason phrase, e.g. `"Unauthorized"`. Empty over HTTP/2. */
|
|
49
|
+
readonly statusText: string;
|
|
50
|
+
/** HTTP method of the failed request, e.g. `"GET"`. */
|
|
51
|
+
readonly method: string;
|
|
52
|
+
/** Full request URL, including the query string. */
|
|
53
|
+
readonly url: string;
|
|
54
|
+
/**
|
|
55
|
+
* Response body: the parsed JSON when the body was valid JSON, the raw string
|
|
56
|
+
* for non-JSON bodies, `undefined` when the body was empty.
|
|
57
|
+
*/
|
|
58
|
+
readonly body: unknown;
|
|
59
|
+
/**
|
|
60
|
+
* Response headers. Rate-limit and request-id headers live here.
|
|
61
|
+
*
|
|
62
|
+
* Non-enumerable, so logging the error stays readable.
|
|
63
|
+
*/
|
|
64
|
+
readonly headers: Headers;
|
|
65
|
+
/**
|
|
66
|
+
* The raw `Response`. Its body stream has already been consumed to populate
|
|
67
|
+
* {@link FactorialApiError.body} — read that instead.
|
|
68
|
+
*
|
|
69
|
+
* Non-enumerable, so logging the error stays readable.
|
|
70
|
+
*/
|
|
71
|
+
readonly response?: Response;
|
|
72
|
+
constructor(init: FactorialApiErrorInit);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* `instanceof`-safe check for {@link FactorialApiError}.
|
|
76
|
+
*
|
|
77
|
+
* Prefer `err instanceof FactorialApiError`. Use this helper when two copies of
|
|
78
|
+
* the package may be loaded at once (the ESM + CJS dual-package hazard), where
|
|
79
|
+
* `instanceof` can fail across realm boundaries.
|
|
80
|
+
*/
|
|
81
|
+
export declare function isFactorialApiError(error: unknown): error is FactorialApiError;
|
|
82
|
+
/**
|
|
83
|
+
* Converts the raw value thrown by the underlying fetch client for a non-2xx
|
|
84
|
+
* response (the parsed JSON body, the raw text, or `""`) into a
|
|
85
|
+
* {@link FactorialApiError}.
|
|
86
|
+
*
|
|
87
|
+
* Registered as the client's error interceptor by `FactorialClient`. Values
|
|
88
|
+
* that do not describe an HTTP error response are returned untouched:
|
|
89
|
+
*
|
|
90
|
+
* - no `Response` — a transport failure such as a `fetch` `TypeError`
|
|
91
|
+
* - an ok `Response` — a failure while parsing a 2xx body
|
|
92
|
+
* - an `Error` instance — already a usable error, e.g. thrown by a user
|
|
93
|
+
* interceptor
|
|
94
|
+
*/
|
|
95
|
+
export declare function toFactorialApiError(error: unknown, response: Response | undefined, request: Request | undefined): unknown;
|
|
96
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,yDAAyD;AACzD,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAG,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;gBAEjB,IAAI,EAAE,qBAAqB;CAwBxC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAO9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAC9B,OAAO,EAAE,OAAO,GAAG,SAAS,GAC3B,OAAO,CAaT"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error types for the Factorial API client.
|
|
4
|
+
*
|
|
5
|
+
* Every non-2xx HTTP response is thrown as a {@link FactorialApiError} carrying
|
|
6
|
+
* the status, method, URL and parsed body. Transport failures (DNS, connection
|
|
7
|
+
* reset, aborted request) are *not* wrapped — they surface as the underlying
|
|
8
|
+
* error, typically a `TypeError` from `fetch`.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.FactorialApiError = void 0;
|
|
12
|
+
exports.isFactorialApiError = isFactorialApiError;
|
|
13
|
+
exports.toFactorialApiError = toFactorialApiError;
|
|
14
|
+
/**
|
|
15
|
+
* Thrown for every non-2xx response from the Factorial API.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* try {
|
|
20
|
+
* await client.employees.employees.get({ path: { id: "1" } });
|
|
21
|
+
* } catch (err) {
|
|
22
|
+
* if (err instanceof FactorialApiError) {
|
|
23
|
+
* console.error(err.status, err.method, err.url, err.body);
|
|
24
|
+
* } else {
|
|
25
|
+
* throw err; // transport failure (e.g. a fetch TypeError)
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class FactorialApiError extends Error {
|
|
31
|
+
/** HTTP status code, e.g. `401`. */
|
|
32
|
+
status;
|
|
33
|
+
/** HTTP reason phrase, e.g. `"Unauthorized"`. Empty over HTTP/2. */
|
|
34
|
+
statusText;
|
|
35
|
+
/** HTTP method of the failed request, e.g. `"GET"`. */
|
|
36
|
+
method;
|
|
37
|
+
/** Full request URL, including the query string. */
|
|
38
|
+
url;
|
|
39
|
+
/**
|
|
40
|
+
* Response body: the parsed JSON when the body was valid JSON, the raw string
|
|
41
|
+
* for non-JSON bodies, `undefined` when the body was empty.
|
|
42
|
+
*/
|
|
43
|
+
body;
|
|
44
|
+
/**
|
|
45
|
+
* Response headers. Rate-limit and request-id headers live here.
|
|
46
|
+
*
|
|
47
|
+
* Non-enumerable, so logging the error stays readable.
|
|
48
|
+
*/
|
|
49
|
+
headers;
|
|
50
|
+
/**
|
|
51
|
+
* The raw `Response`. Its body stream has already been consumed to populate
|
|
52
|
+
* {@link FactorialApiError.body} — read that instead.
|
|
53
|
+
*
|
|
54
|
+
* Non-enumerable, so logging the error stays readable.
|
|
55
|
+
*/
|
|
56
|
+
response;
|
|
57
|
+
constructor(init) {
|
|
58
|
+
super(formatMessage(init));
|
|
59
|
+
this.name = "FactorialApiError";
|
|
60
|
+
this.status = init.status;
|
|
61
|
+
this.statusText = init.statusText;
|
|
62
|
+
this.method = init.method;
|
|
63
|
+
this.url = init.url;
|
|
64
|
+
this.body = init.body;
|
|
65
|
+
// `headers` and `response` are hidden from enumeration: console.error(err)
|
|
66
|
+
// and JSON.stringify(err) would otherwise dump the whole Response object,
|
|
67
|
+
// burying the fields that identify the failure.
|
|
68
|
+
Object.defineProperty(this, "headers", {
|
|
69
|
+
value: init.headers ?? new Headers(),
|
|
70
|
+
enumerable: false,
|
|
71
|
+
writable: false,
|
|
72
|
+
configurable: true,
|
|
73
|
+
});
|
|
74
|
+
Object.defineProperty(this, "response", {
|
|
75
|
+
value: init.response,
|
|
76
|
+
enumerable: false,
|
|
77
|
+
writable: false,
|
|
78
|
+
configurable: true,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.FactorialApiError = FactorialApiError;
|
|
83
|
+
/**
|
|
84
|
+
* `instanceof`-safe check for {@link FactorialApiError}.
|
|
85
|
+
*
|
|
86
|
+
* Prefer `err instanceof FactorialApiError`. Use this helper when two copies of
|
|
87
|
+
* the package may be loaded at once (the ESM + CJS dual-package hazard), where
|
|
88
|
+
* `instanceof` can fail across realm boundaries.
|
|
89
|
+
*/
|
|
90
|
+
function isFactorialApiError(error) {
|
|
91
|
+
return (error instanceof FactorialApiError ||
|
|
92
|
+
(typeof error === "object" &&
|
|
93
|
+
error !== null &&
|
|
94
|
+
error.name === "FactorialApiError"));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Converts the raw value thrown by the underlying fetch client for a non-2xx
|
|
98
|
+
* response (the parsed JSON body, the raw text, or `""`) into a
|
|
99
|
+
* {@link FactorialApiError}.
|
|
100
|
+
*
|
|
101
|
+
* Registered as the client's error interceptor by `FactorialClient`. Values
|
|
102
|
+
* that do not describe an HTTP error response are returned untouched:
|
|
103
|
+
*
|
|
104
|
+
* - no `Response` — a transport failure such as a `fetch` `TypeError`
|
|
105
|
+
* - an ok `Response` — a failure while parsing a 2xx body
|
|
106
|
+
* - an `Error` instance — already a usable error, e.g. thrown by a user
|
|
107
|
+
* interceptor
|
|
108
|
+
*/
|
|
109
|
+
function toFactorialApiError(error, response, request) {
|
|
110
|
+
if (response === undefined || response.ok)
|
|
111
|
+
return error;
|
|
112
|
+
if (error instanceof Error)
|
|
113
|
+
return error;
|
|
114
|
+
return new FactorialApiError({
|
|
115
|
+
status: response.status,
|
|
116
|
+
statusText: response.statusText,
|
|
117
|
+
method: request?.method ?? "UNKNOWN",
|
|
118
|
+
url: request?.url ?? response.url,
|
|
119
|
+
// An empty body reaches us as "" because JSON.parse("") throws upstream.
|
|
120
|
+
body: error === "" ? undefined : error,
|
|
121
|
+
headers: response.headers,
|
|
122
|
+
response,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/** Longest body excerpt appended to the error message. */
|
|
126
|
+
const EXCERPT_MAX_LENGTH = 200;
|
|
127
|
+
function formatMessage({ status, statusText, method, url, body, }) {
|
|
128
|
+
const head = `Factorial API ${status}${statusText ? ` ${statusText}` : ""}: ${method} ${url}`;
|
|
129
|
+
const excerpt = bodyExcerpt(body);
|
|
130
|
+
return excerpt ? `${head} — ${excerpt}` : head;
|
|
131
|
+
}
|
|
132
|
+
function bodyExcerpt(body) {
|
|
133
|
+
if (body === undefined || body === null || body === "")
|
|
134
|
+
return undefined;
|
|
135
|
+
let text;
|
|
136
|
+
if (typeof body === "string") {
|
|
137
|
+
text = body;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
try {
|
|
141
|
+
text = JSON.stringify(body) ?? String(body);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Circular structures and BigInt values make JSON.stringify throw.
|
|
145
|
+
text = String(body);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const oneLine = text.replace(/\s+/g, " ").trim();
|
|
149
|
+
if (!oneLine)
|
|
150
|
+
return undefined;
|
|
151
|
+
return oneLine.length > EXCERPT_MAX_LENGTH
|
|
152
|
+
? `${oneLine.slice(0, EXCERPT_MAX_LENGTH)}…`
|
|
153
|
+
: oneLine;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -728,7 +728,33 @@ export declare const getApi20261001ResourcesCompensationsPayrollResultsById: <Th
|
|
|
728
728
|
/**
|
|
729
729
|
* Bulk creates a Payroll result
|
|
730
730
|
*
|
|
731
|
-
* Imports payroll result amounts for employees of
|
|
731
|
+
* Imports payroll result amounts for employees of an existing payroll run, for example the
|
|
732
|
+
* figures returned by an external payroll provider. Only Factorial ids are accepted.
|
|
733
|
+
*
|
|
734
|
+
* The import is atomic: the whole request is validated before anything is written, and any
|
|
735
|
+
* error rejects it entirely. A 4xx or 5xx response means nothing was written, so a failed
|
|
736
|
+
* request can be retried as is.
|
|
737
|
+
*
|
|
738
|
+
* The request is rejected when:
|
|
739
|
+
* - it has no results, an employee entry has no items, it carries more than 1,000 amounts,
|
|
740
|
+
* or it repeats an employee or a concept for the same employee
|
|
741
|
+
* - the payroll run, an employee or a payroll concept does not exist in the company
|
|
742
|
+
* - an employee is not part of the payroll run, that is, is not one of the employees
|
|
743
|
+
* Factorial lists in that run. On regular runs the employee's contract must cover the run
|
|
744
|
+
* period, they must not have been terminated more than 60 days before the run starts and,
|
|
745
|
+
* when the run's cycle is limited to a people group, they must belong to it. Off-cycle
|
|
746
|
+
* runs only apply the people group and a 365-day termination window. The error lists
|
|
747
|
+
* these employees in `errors.employee_ids`, so they can be removed and the rest resent.
|
|
748
|
+
* - a concept is a base salary concept or is disabled
|
|
749
|
+
* - an employee entry does not include the company's net_pay concept (find its id with
|
|
750
|
+
* compensations/concepts)
|
|
751
|
+
* - an amount is outside the signed 32-bit integer range
|
|
752
|
+
*
|
|
753
|
+
* Re-posting an (employee, concept) pair replaces its amount and keeps the row id. Pairs not
|
|
754
|
+
* included in the request are left untouched; there is no delete. Split larger payrolls into
|
|
755
|
+
* requests of up to 1,000 amounts, keeping all of an employee's items in the same request.
|
|
756
|
+
* Requires the "Import payroll results" permission.
|
|
757
|
+
*
|
|
732
758
|
*/
|
|
733
759
|
export declare const postApi20261001ResourcesCompensationsPayrollResultsBulkCreate: <ThrowOnError extends boolean = false>(options?: Options<PostApi20261001ResourcesCompensationsPayrollResultsBulkCreateData, ThrowOnError>) => RequestResult<PostApi20261001ResourcesCompensationsPayrollResultsBulkCreateResponses, unknown, ThrowOnError>;
|
|
734
760
|
/**
|