@unifetch/fortnox 2.1.1 → 2.3.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 (65) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +231 -183
  3. package/dist/create-fortnox-mini-COurqL1e.d.mts +24524 -0
  4. package/dist/create-fortnox-mini-COurqL1e.d.mts.map +1 -0
  5. package/dist/create-fortnox-mini-DfNjIlYm.d.cts +24524 -0
  6. package/dist/create-fortnox-mini-DfNjIlYm.d.cts.map +1 -0
  7. package/dist/{index-BWHJmubR.d.cts → index-IeYuLkvO.d.mts} +15 -4
  8. package/dist/index-IeYuLkvO.d.mts.map +1 -0
  9. package/dist/{index-CqOhNC_h.d.mts → index-hOzXwnXm.d.cts} +15 -4
  10. package/dist/index-hOzXwnXm.d.cts.map +1 -0
  11. package/dist/index.cjs +1660 -2
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.d.cts +1676 -2
  14. package/dist/index.d.cts.map +1 -0
  15. package/dist/index.d.mts +1676 -2
  16. package/dist/index.d.mts.map +1 -0
  17. package/dist/index.mjs +1660 -2
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/mini.cjs +27 -0
  20. package/dist/mini.cjs.map +1 -0
  21. package/dist/mini.d.cts +16 -0
  22. package/dist/mini.d.cts.map +1 -0
  23. package/dist/mini.d.mts +16 -0
  24. package/dist/mini.d.mts.map +1 -0
  25. package/dist/mini.mjs +26 -0
  26. package/dist/mini.mjs.map +1 -0
  27. package/dist/request-DyylPAyE.mjs +66 -0
  28. package/dist/request-DyylPAyE.mjs.map +1 -0
  29. package/dist/request-QlzK3EWz.cjs +78 -0
  30. package/dist/request-QlzK3EWz.cjs.map +1 -0
  31. package/dist/types/custom/index.d.cts +1 -1
  32. package/dist/types/custom/index.d.mts +1 -1
  33. package/package.json +4 -9
  34. package/dist/create-fortnox-BB_0mFBL.mjs +0 -1717
  35. package/dist/create-fortnox-BB_0mFBL.mjs.map +0 -1
  36. package/dist/create-fortnox-BQgaBk5m.d.cts +0 -1697
  37. package/dist/create-fortnox-BQgaBk5m.d.cts.map +0 -1
  38. package/dist/create-fortnox-DGjVOKfm.cjs +0 -1723
  39. package/dist/create-fortnox-DGjVOKfm.cjs.map +0 -1
  40. package/dist/create-fortnox-DiGzUeVa.d.mts +0 -1697
  41. package/dist/create-fortnox-DiGzUeVa.d.mts.map +0 -1
  42. package/dist/index-BWHJmubR.d.cts.map +0 -1
  43. package/dist/index-CqOhNC_h.d.mts.map +0 -1
  44. package/dist/official-BFBd-NeQ.d.cts +0 -12259
  45. package/dist/official-BFBd-NeQ.d.cts.map +0 -1
  46. package/dist/official-DeZGQsNS.d.mts +0 -12259
  47. package/dist/official-DeZGQsNS.d.mts.map +0 -1
  48. package/dist/official.cjs +0 -9
  49. package/dist/official.cjs.map +0 -1
  50. package/dist/official.d.cts +0 -2
  51. package/dist/official.d.mts +0 -2
  52. package/dist/official.mjs +0 -8
  53. package/dist/official.mjs.map +0 -1
  54. package/dist/patched.cjs +0 -9
  55. package/dist/patched.cjs.map +0 -1
  56. package/dist/patched.d.cts +0 -12256
  57. package/dist/patched.d.cts.map +0 -1
  58. package/dist/patched.d.mts +0 -12256
  59. package/dist/patched.d.mts.map +0 -1
  60. package/dist/patched.mjs +0 -8
  61. package/dist/patched.mjs.map +0 -1
  62. package/dist/utility-types-CXs8tUw_.d.mts +0 -15
  63. package/dist/utility-types-CXs8tUw_.d.mts.map +0 -1
  64. package/dist/utility-types-DLzshE5r.d.cts +0 -15
  65. package/dist/utility-types-DLzshE5r.d.cts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @unifetch/fortnox
2
2
 
3
+ ## 2.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Export the full client and mini client from sperate paths for better tree-shaking. Create official/patched client by providing a genering to the init function.
8
+
9
+ ## 2.2.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Add new initializer - createFortnoxMini() which only exposes the .path() method. It still has full type safety but results in very small bundle size compared to initFortnox()
14
+
3
15
  ## 2.1.1
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -1,183 +1,231 @@
1
- # @unifetch/fortnox
2
-
3
- TypeScript SDK for the [Fortnox API](https://api.fortnox.se/apidocs), fully typed from the official OpenAPI specification — with corrections applied where the spec has incorrect or overly permissive types.
4
-
5
- Zero dependencies. Fully compatible with edge runtimes such as [Cloudflare Workers](https://workers.cloudflare.com/) and Vercel Edge Functions.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install @unifetch/fortnox
11
- # or
12
- pnpm add @unifetch/fortnox
13
- ```
14
-
15
- ## Initialization
16
-
17
- There are two ways to initialize the client.
18
-
19
- ### 1. Access token
20
-
21
- Use this if you manage your own oAuth flow and already have a Fortnox access token.
22
-
23
- ```ts
24
- import { initFortnox } from "@unifetch/fortnox";
25
-
26
- const fortnox = initFortnox({
27
- accessToken: "your-access-token",
28
- });
29
- ```
30
-
31
- ### 2. Proxy via unifetch.dev
32
-
33
- [unifetch.dev](https://unifetch.dev) acts as a proxy layer that internally handles OAuth and token rotation, removing the need to manage credentials yourself.
34
-
35
- ```ts
36
- import { initFortnox } from "@unifetch/fortnox";
37
-
38
- const fortnox = initFortnox({
39
- proxy: {
40
- baseUrl: "https://proxy.unifetch.dev/fortnox",
41
- apiKey: "your-api-key", // You generate it on unifetch.dev dashboard
42
- tenantId: "your-tenant-id", // Your company's unique fortnox id. You can see it on unifetch.dev dashboard.
43
- },
44
- });
45
- ```
46
-
47
- ## Usage
48
-
49
- Every response is a discriminated union of `{ error: null; data: T }` or `{ error: ErrorResponse; data: null }`. Once you handle (or narrow) the error branch, TypeScript automatically infers that `data` is non-null.
50
-
51
- There are two ways to call the API.
52
-
53
- ### Resource-based API (recommended)
54
-
55
- Access resources by name and call operations by their ID. Both the resource name and operation ID are autocompleted by TypeScript.
56
-
57
- > **Note:** The operation names (e.g. `getList`, `create`, `bookkeep`) are **manually curated** and are not derived from the official Fortnox OpenAPI specification. The official spec uses operation ids that are inconsistent and ambiguous across endpoints. The names used here follow a consistent, human-readable convention defined in [`overrides/operation-ids.json`](overrides/operation-ids.json).
58
-
59
- ```ts
60
- const { data, error } = await fortnox.invoices.getList();
61
-
62
- if (error) {
63
- console.error(error.ErrorInformation.message);
64
- } else {
65
- // data is non-null here — TypeScript knows this after the error check
66
- console.log(data.Invoices);
67
- }
68
- ```
69
-
70
- #### With query parameters
71
-
72
- ```ts
73
- const { data, error } = await fortnox.invoices.getList({
74
- query: { fromdate: "2024-01-01", todate: "2024-12-31" },
75
- });
76
-
77
- if (error) throw error;
78
-
79
- for (const invoice of data.Invoices) {
80
- console.log(invoice.DocumentNumber, invoice.Total);
81
- }
82
- ```
83
-
84
- #### Creating a resource
85
-
86
- ```ts
87
- const { data, error } = await fortnox.invoices.create({
88
- body: {
89
- Invoice: {
90
- CustomerNumber: "1",
91
- InvoiceRows: [
92
- { ArticleNumber: "A1", DeliveredQuantity: 2 },
93
- ],
94
- },
95
- },
96
- });
97
-
98
- if (error) throw error;
99
-
100
- console.log(data.Invoice.DocumentNumber);
101
- ```
102
-
103
- #### Fetching a single resource by ID
104
-
105
- ```ts
106
- const { data, error } = await fortnox.invoices.get({
107
- params: { DocumentNumber: "100" },
108
- });
109
-
110
- if (error) throw error;
111
-
112
- console.log(data.Invoice.CustomerName);
113
- ```
114
-
115
- #### Calling an action on a resource
116
-
117
- ```ts
118
- const { data, error } = await fortnox.invoices.bookkeep({
119
- params: { DocumentNumber: "100" },
120
- });
121
- ```
122
-
123
- ### Path-based API
124
-
125
- If you want to access an endpoint directly by its raw path, use `fortnox.path()`. This is equivalent to the resource-based API under the hood. The path and all the parameters are fully typed.
126
-
127
- ```ts
128
- const { data, error } = await fortnox.path("/3/invoices").get();
129
-
130
- if (error) throw error;
131
-
132
- console.log(data.Invoices);
133
- ```
134
-
135
- ```ts
136
- const { data, error } = await fortnox.path("/3/invoices/{DocumentNumber}").get({
137
- params: { DocumentNumber: "100" },
138
- });
139
- ```
140
-
141
- ## Type definitions
142
-
143
- ### `@unifetch/fortnox` (default) patched types
144
-
145
- The default import uses **patched type definitions**. Fortnox's official OpenAPI spec has a number of incorrect or missing type constraints (e.g. response wrapper properties marked as optional when they are always present). This package fixes those issues so the types accurately reflect real API behavior. But some of the "patched" types can still be incorrect since we do not have clear documentation.
146
-
147
- ```ts
148
- import { initFortnox } from "@unifetch/fortnox";
149
- // or equivalently:
150
- import { initFortnox } from "@unifetch/fortnox/patched";
151
- ```
152
-
153
- ### `@unifetch/fortnox/official` — unmodified types
154
-
155
- If you need the raw types exactly as they appear in Fortnox's official OpenAPI specification, import from the `/official` subpath.
156
-
157
- ```ts
158
- import { initFortnox } from "@unifetch/fortnox/official";
159
- ```
160
-
161
- > **Note:** The official types may include inaccuracies inherited from the upstream spec. Prefer the default (patched) import unless you have a specific reason to use the unmodified types.
162
-
163
- ## Error handling
164
-
165
- The error object has the following shape:
166
-
167
- ```ts
168
- type ErrorResponse = {
169
- ErrorSource: "fortnox" | "unknown";
170
- ErrorInformation: {
171
- error: number;
172
- message: string;
173
- code: number;
174
- };
175
- };
176
- ```
177
-
178
- - `ErrorSource: "fortnox"` — the Fortnox API returned a non-2xx response.
179
- - `ErrorSource: "unknown"` — a network or unexpected error occurred.
180
-
181
- ## License
182
-
183
- ISC
1
+ # @unifetch/fortnox
2
+
3
+ TypeScript SDK for the [Fortnox API](https://api.fortnox.se/apidocs), fully typed from the official OpenAPI specification — with corrections applied where the spec has incorrect or overly permissive types.
4
+
5
+ Zero dependencies. Fully compatible with edge runtimes such as [Cloudflare Workers](https://workers.cloudflare.com/) and Vercel Edge Functions.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @unifetch/fortnox
11
+ # or
12
+ pnpm add @unifetch/fortnox
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Clients
18
+
19
+ There are two clients to choose from.
20
+
21
+ ### `initFortnox` full client
22
+
23
+ Includes both the resource-based API (`fortnox.invoices.getList()`) and the path-based API (`fortnox.path()`). This is the right choice for most server-side applications where bundle size is not a concern.
24
+
25
+ ```ts
26
+ import { initFortnox } from "@unifetch/fortnox";
27
+ ```
28
+
29
+ ### `initFortnoxMini` — minimal client
30
+
31
+ Includes **only** the path-based API (`fortnox.path()`). The entire resource-based layer — including the map of all routes and operation IDs — is absent from this client, which means a bundler can **tree-shake it away entirely**. Use this when bundle size is a hard constraint, such as in [Cloudflare Workers](https://workers.cloudflare.com/) or Vercel Edge Functions.
32
+
33
+ ```ts
34
+ import { initFortnoxMini } from "@unifetch/fortnox/mini";
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Route variant
40
+
41
+ Both clients accept an optional `"official" | "patched"` generic that controls which type definitions are used. It defaults to `"patched"`.
42
+
43
+ | Variant | Description |
44
+ |---|---|
45
+ | `"patched"` *(default)* | Corrected types — fixes inaccuracies in Fortnox's official spec (e.g. response wrapper properties incorrectly marked as optional). Recommended for most projects. |
46
+ | `"official"` | Raw, unmodified types exactly as they appear in Fortnox's official OpenAPI specification. |
47
+
48
+ ```ts
49
+ // "patched" is the default no generic needed
50
+ const fortnox = initFortnox({ accessToken: "..." });
51
+
52
+ // Explicitly patched
53
+ const fortnox = initFortnox<"patched">({ accessToken: "..." });
54
+
55
+ // Official, unmodified Fortnox types
56
+ const fortnox = initFortnox<"official">({ accessToken: "..." });
57
+ ```
58
+
59
+ The same generic is available on `initFortnoxMini`:
60
+
61
+ ```ts
62
+ import { initFortnoxMini } from "@unifetch/fortnox/mini";
63
+
64
+ const fortnox = initFortnoxMini<"official">({ accessToken: "..." });
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Initialization
70
+
71
+ Both clients support two authentication options.
72
+
73
+ ### Option 1 Access token
74
+
75
+ Use this if you manage your own OAuth flow and already have a Fortnox access token.
76
+
77
+ ```ts
78
+ import { initFortnox } from "@unifetch/fortnox";
79
+
80
+ const fortnox = initFortnox({ accessToken: "your-access-token" });
81
+ ```
82
+
83
+ ### Option 2 — Proxy via unifetch.dev
84
+
85
+ [unifetch.dev](https://unifetch.dev) acts as a proxy layer that internally handles OAuth and token rotation, removing the complecity of managing credentials yourself.
86
+
87
+ ```ts
88
+ import { initFortnox } from "@unifetch/fortnox";
89
+
90
+ const fortnox = initFortnox({
91
+ proxy: {
92
+ baseUrl: "https://proxy.unifetch.dev/fortnox",
93
+ apiKey: "your-api-key", // Generate on the unifetch.dev dashboard
94
+ tenantId: "your-tenant-id", // Your company's unique Fortnox ID, visible on the unifetch.dev dashboard
95
+ },
96
+ });
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Usage
102
+
103
+ Every response is a discriminated union of `{ error: null; data: T }` or `{ error: ErrorResponse; data: null }`. Once you handle (or narrow) the error branch, TypeScript automatically infers that `data` is non-null.
104
+
105
+ `initFortnox` supports both APIs below. `initFortnoxMini` supports only the path-based API.
106
+
107
+ ### Resource-based API (recommended)
108
+
109
+ Access resources by name and call operations by their ID. Both the resource name and the operation ID are autocompleted by TypeScript.
110
+
111
+ > **Note:** Operation names (e.g. `getList`, `create`, `bookkeep`) are **manually curated** and are not derived from the official Fortnox OpenAPI spec. The official spec uses operation IDs that are inconsistent and ambiguous across endpoints. The names used here follow a consistent, human-readable convention defined in [`overrides/operation-ids.json`](overrides/operation-ids.json).
112
+
113
+ #### Fetching a list
114
+
115
+ ```ts
116
+ const { data, error } = await fortnox.invoices.getList();
117
+
118
+ if (error) {
119
+ console.error(error.ErrorInformation.message);
120
+ } else {
121
+ // data is non-null here — TypeScript knows this after the error check
122
+ console.log(data.Invoices);
123
+ }
124
+ ```
125
+
126
+ #### With query parameters
127
+
128
+ ```ts
129
+ const { data, error } = await fortnox.invoices.getList({
130
+ query: { fromdate: "2024-01-01", todate: "2024-12-31" },
131
+ });
132
+
133
+ if (error) throw error;
134
+
135
+ for (const invoice of data.Invoices) {
136
+ console.log(invoice.DocumentNumber, invoice.Total);
137
+ }
138
+ ```
139
+
140
+ #### Fetching a single resource
141
+
142
+ ```ts
143
+ const { data, error } = await fortnox.invoices.get({
144
+ params: { DocumentNumber: "100" },
145
+ });
146
+
147
+ if (error) throw error;
148
+
149
+ console.log(data.Invoice.CustomerName);
150
+ ```
151
+
152
+ #### Creating a resource
153
+
154
+ ```ts
155
+ const { data, error } = await fortnox.invoices.create({
156
+ body: {
157
+ Invoice: {
158
+ CustomerNumber: "1",
159
+ InvoiceRows: [
160
+ { ArticleNumber: "A1", DeliveredQuantity: 2 },
161
+ ],
162
+ },
163
+ },
164
+ });
165
+
166
+ if (error) throw error;
167
+
168
+ console.log(data.Invoice.DocumentNumber);
169
+ ```
170
+
171
+ #### Calling an action on a resource
172
+
173
+ ```ts
174
+ const { data, error } = await fortnox.invoices.bookkeep({
175
+ params: { DocumentNumber: "100" },
176
+ });
177
+ ```
178
+
179
+ ### Path-based API
180
+
181
+ Call any endpoint directly by its raw path. The path, parameters, and response are fully typed.
182
+
183
+ ```ts
184
+ const { data, error } = await fortnox.path("/3/invoices").get();
185
+
186
+ if (error) throw error;
187
+
188
+ console.log(data.Invoices);
189
+ ```
190
+
191
+ ```ts
192
+ const { data, error } = await fortnox.path("/3/invoices/{DocumentNumber}").get({
193
+ params: { DocumentNumber: "100" },
194
+ });
195
+ ```
196
+
197
+ This is the only API available on `initFortnoxMini`:
198
+
199
+ ```ts
200
+ import { initFortnoxMini } from "@unifetch/fortnox/mini";
201
+
202
+ const fortnox = initFortnoxMini({ accessToken: "your-access-token" });
203
+
204
+ const { data, error } = await fortnox.path("/3/invoices").get();
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Error handling
210
+
211
+ The error object has the following shape:
212
+
213
+ ```ts
214
+ type ErrorResponse = {
215
+ ErrorSource: "fortnox" | "unknown";
216
+ ErrorInformation: {
217
+ error: number;
218
+ message: string;
219
+ code: number;
220
+ };
221
+ };
222
+ ```
223
+
224
+ - `ErrorSource: "fortnox"` — the Fortnox API returned a non-2xx response.
225
+ - `ErrorSource: "unknown"` — a network or unexpected error occurred.
226
+
227
+ ---
228
+
229
+ ## License
230
+
231
+ ISC