@frihet/sdk 1.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 +131 -0
- package/dist/index.cjs +542 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +458 -0
- package/dist/index.d.ts +458 -0
- package/dist/index.js +500 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @frihet/sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript SDK for the [Frihet](https://frihet.io) API. AI-native business management.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @frihet/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import Frihet from '@frihet/sdk';
|
|
15
|
+
|
|
16
|
+
const frihet = new Frihet({ apiKey: 'fri_...' });
|
|
17
|
+
|
|
18
|
+
// Create an invoice
|
|
19
|
+
const invoice = await frihet.invoices.create({
|
|
20
|
+
clientName: 'Acme Corp',
|
|
21
|
+
items: [{ description: 'Consulting', quantity: 10, unitPrice: 150 }],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// List overdue invoices
|
|
25
|
+
const overdue = await frihet.invoices.list({ status: 'overdue' });
|
|
26
|
+
|
|
27
|
+
// Mark as paid
|
|
28
|
+
await frihet.invoices.markPaid(invoice.id);
|
|
29
|
+
|
|
30
|
+
// Send by email
|
|
31
|
+
await frihet.invoices.send(invoice.id, { recipientEmail: 'billing@acme.com' });
|
|
32
|
+
|
|
33
|
+
// Download PDF
|
|
34
|
+
const pdf = await frihet.invoices.pdf(invoice.id);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Resources
|
|
38
|
+
|
|
39
|
+
| Resource | Methods |
|
|
40
|
+
|----------|---------|
|
|
41
|
+
| `frihet.invoices` | `list`, `retrieve`, `create`, `update`, `del`, `search`, `markPaid`, `send`, `pdf`, `createBatch` |
|
|
42
|
+
| `frihet.expenses` | `list`, `retrieve`, `create`, `update`, `del`, `search`, `createBatch` |
|
|
43
|
+
| `frihet.clients` | `list`, `retrieve`, `create`, `update`, `del`, `search` |
|
|
44
|
+
| `frihet.vendors` | `list`, `retrieve`, `create`, `update`, `del`, `search` |
|
|
45
|
+
| `frihet.products` | `list`, `retrieve`, `create`, `update`, `del`, `search` |
|
|
46
|
+
| `frihet.quotes` | `list`, `retrieve`, `create`, `update`, `del`, `search`, `send`, `pdf` |
|
|
47
|
+
| `frihet.webhooks` | `list`, `retrieve`, `create`, `update`, `del` |
|
|
48
|
+
| `frihet.intelligence` | `context`, `summary`, `monthly`, `quarterly` |
|
|
49
|
+
|
|
50
|
+
## Intelligence
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// Full business context (one call for AI agents)
|
|
54
|
+
const ctx = await frihet.intelligence.context();
|
|
55
|
+
|
|
56
|
+
// Monthly P&L with tax liability
|
|
57
|
+
const march = await frihet.intelligence.monthly('2026-03');
|
|
58
|
+
|
|
59
|
+
// Quarterly tax prep (Modelo 303/130)
|
|
60
|
+
const q1 = await frihet.intelligence.quarterly('2026-Q1');
|
|
61
|
+
|
|
62
|
+
// Financial summary with date range
|
|
63
|
+
const ytd = await frihet.intelligence.summary({ from: '2026-01-01', to: '2026-12-31' });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Error handling
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import Frihet, { RateLimitError, NotFoundError, ValidationError } from '@frihet/sdk';
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await frihet.invoices.retrieve('nonexistent');
|
|
73
|
+
} catch (err) {
|
|
74
|
+
if (err instanceof NotFoundError) {
|
|
75
|
+
console.log('Invoice not found');
|
|
76
|
+
} else if (err instanceof RateLimitError) {
|
|
77
|
+
console.log(`Retry after ${err.retryAfter}s`);
|
|
78
|
+
} else if (err instanceof ValidationError) {
|
|
79
|
+
console.log('Validation:', err.details);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Webhook verification
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { Webhooks } from '@frihet/sdk';
|
|
88
|
+
|
|
89
|
+
const isValid = Webhooks.verifySignature(
|
|
90
|
+
rawBody,
|
|
91
|
+
req.headers['x-frihet-signature'],
|
|
92
|
+
webhookSecret,
|
|
93
|
+
);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const frihet = new Frihet({
|
|
100
|
+
apiKey: 'fri_...',
|
|
101
|
+
baseUrl: 'https://api.frihet.io/v1', // default
|
|
102
|
+
timeout: 30000, // 30s default
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Per-request options
|
|
106
|
+
await frihet.invoices.create(data, {
|
|
107
|
+
idempotencyKey: 'unique-key-123',
|
|
108
|
+
timeout: 60000,
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Features
|
|
113
|
+
|
|
114
|
+
- Full TypeScript types with autocompletion
|
|
115
|
+
- Automatic retry on rate limits (429) and server errors (5xx)
|
|
116
|
+
- Exponential backoff with configurable retries
|
|
117
|
+
- Idempotency key support for safe retries
|
|
118
|
+
- Dual CJS/ESM output
|
|
119
|
+
- Zero runtime dependencies
|
|
120
|
+
- Request ID tracking on errors
|
|
121
|
+
- HMAC webhook signature verification
|
|
122
|
+
|
|
123
|
+
## Links
|
|
124
|
+
|
|
125
|
+
- [API Documentation](https://docs.frihet.io/desarrolladores/api-rest)
|
|
126
|
+
- [MCP Server](https://www.npmjs.com/package/@frihet/mcp-server)
|
|
127
|
+
- [CLI](https://www.npmjs.com/package/frihet)
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
APIError: () => APIError,
|
|
24
|
+
AuthenticationError: () => AuthenticationError,
|
|
25
|
+
Clients: () => Clients,
|
|
26
|
+
Expenses: () => Expenses,
|
|
27
|
+
Frihet: () => Frihet,
|
|
28
|
+
FrihetError: () => FrihetError,
|
|
29
|
+
Intelligence: () => Intelligence,
|
|
30
|
+
Invoices: () => Invoices,
|
|
31
|
+
NotFoundError: () => NotFoundError,
|
|
32
|
+
Products: () => Products,
|
|
33
|
+
Quotes: () => Quotes,
|
|
34
|
+
RateLimitError: () => RateLimitError,
|
|
35
|
+
TimeoutError: () => TimeoutError,
|
|
36
|
+
ValidationError: () => ValidationError,
|
|
37
|
+
Vendors: () => Vendors,
|
|
38
|
+
Webhooks: () => Webhooks,
|
|
39
|
+
default: () => index_default
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(index_exports);
|
|
42
|
+
|
|
43
|
+
// src/error.ts
|
|
44
|
+
var FrihetError = class extends Error {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "FrihetError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var APIError = class extends FrihetError {
|
|
51
|
+
status;
|
|
52
|
+
code;
|
|
53
|
+
requestId;
|
|
54
|
+
constructor(status, code, message, requestId) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = "APIError";
|
|
57
|
+
this.status = status;
|
|
58
|
+
this.code = code;
|
|
59
|
+
this.requestId = requestId;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var AuthenticationError = class extends APIError {
|
|
63
|
+
constructor(message = "Invalid or missing API key") {
|
|
64
|
+
super(401, "authentication_error", message);
|
|
65
|
+
this.name = "AuthenticationError";
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var NotFoundError = class extends APIError {
|
|
69
|
+
constructor(message = "Resource not found") {
|
|
70
|
+
super(404, "not_found", message);
|
|
71
|
+
this.name = "NotFoundError";
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var ValidationError = class extends APIError {
|
|
75
|
+
details;
|
|
76
|
+
constructor(message, details) {
|
|
77
|
+
super(400, "validation_error", message);
|
|
78
|
+
this.name = "ValidationError";
|
|
79
|
+
this.details = details;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var RateLimitError = class extends APIError {
|
|
83
|
+
retryAfter;
|
|
84
|
+
constructor(retryAfter) {
|
|
85
|
+
super(429, "rate_limit_exceeded", "Rate limit exceeded. Please retry later.");
|
|
86
|
+
this.name = "RateLimitError";
|
|
87
|
+
this.retryAfter = retryAfter;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var TimeoutError = class extends FrihetError {
|
|
91
|
+
constructor(timeoutMs) {
|
|
92
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
93
|
+
this.name = "TimeoutError";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/client.ts
|
|
98
|
+
var DEFAULT_BASE_URL = "https://api.frihet.io/v1";
|
|
99
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
100
|
+
var MAX_RETRIES = 3;
|
|
101
|
+
var BASE_RETRY_DELAY_MS = 1e3;
|
|
102
|
+
var SDK_VERSION = "1.0.0";
|
|
103
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
104
|
+
var HttpClient = class {
|
|
105
|
+
apiKey;
|
|
106
|
+
baseUrl;
|
|
107
|
+
timeout;
|
|
108
|
+
constructor(opts) {
|
|
109
|
+
if (!opts.apiKey) {
|
|
110
|
+
throw new Error("apiKey is required. Get one at https://app.frihet.io/settings/security");
|
|
111
|
+
}
|
|
112
|
+
this.apiKey = opts.apiKey;
|
|
113
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
114
|
+
this.timeout = opts.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
115
|
+
}
|
|
116
|
+
get defaultHeaders() {
|
|
117
|
+
return {
|
|
118
|
+
"X-API-Key": this.apiKey,
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
"Accept": "application/json",
|
|
121
|
+
"User-Agent": `@frihet/sdk/${SDK_VERSION} (node)`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async get(path, query, opts) {
|
|
125
|
+
return this.request("GET", path, void 0, query, opts);
|
|
126
|
+
}
|
|
127
|
+
async post(path, body, opts) {
|
|
128
|
+
return this.request("POST", path, body, void 0, opts);
|
|
129
|
+
}
|
|
130
|
+
async patch(path, body, opts) {
|
|
131
|
+
return this.request("PATCH", path, body, void 0, opts);
|
|
132
|
+
}
|
|
133
|
+
async del(path, opts) {
|
|
134
|
+
return this.request("DELETE", path, void 0, void 0, opts);
|
|
135
|
+
}
|
|
136
|
+
async getPage(path, query, opts) {
|
|
137
|
+
const raw = await this.requestRaw("GET", path, void 0, query, opts);
|
|
138
|
+
const body = await raw.json();
|
|
139
|
+
const page = this.extractPageFromEnvelope(body);
|
|
140
|
+
if (!page) {
|
|
141
|
+
throw new APIError(200, "invalid_response", "Expected paginated response with data array", this.extractRequestId(raw));
|
|
142
|
+
}
|
|
143
|
+
return page;
|
|
144
|
+
}
|
|
145
|
+
async getRaw(path, opts) {
|
|
146
|
+
const response = await this.requestRaw("GET", path, void 0, void 0, opts);
|
|
147
|
+
return response.arrayBuffer();
|
|
148
|
+
}
|
|
149
|
+
async request(method, path, body, query, opts) {
|
|
150
|
+
const response = await this.requestRaw(method, path, body, query, opts);
|
|
151
|
+
if (response.status === 204) {
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
const json = await response.json();
|
|
155
|
+
return this.unwrapEnvelope(json);
|
|
156
|
+
}
|
|
157
|
+
async requestRaw(method, path, body, query, opts, retryCount = 0) {
|
|
158
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
159
|
+
if (query) {
|
|
160
|
+
for (const [key, value] of Object.entries(query)) {
|
|
161
|
+
if (value !== void 0) url.searchParams.set(key, String(value));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const headers = { ...this.defaultHeaders };
|
|
165
|
+
if (opts?.idempotencyKey) {
|
|
166
|
+
headers["Idempotency-Key"] = opts.idempotencyKey;
|
|
167
|
+
}
|
|
168
|
+
const controller = new AbortController();
|
|
169
|
+
const timeoutMs = opts?.timeout ?? this.timeout;
|
|
170
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
171
|
+
let response;
|
|
172
|
+
try {
|
|
173
|
+
response = await fetch(url.toString(), {
|
|
174
|
+
method,
|
|
175
|
+
headers,
|
|
176
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
177
|
+
signal: opts?.signal ?? controller.signal
|
|
178
|
+
});
|
|
179
|
+
} catch (err) {
|
|
180
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
181
|
+
throw new TimeoutError(timeoutMs);
|
|
182
|
+
}
|
|
183
|
+
if (retryCount < MAX_RETRIES) {
|
|
184
|
+
const delayMs = BASE_RETRY_DELAY_MS * Math.pow(2, retryCount);
|
|
185
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
186
|
+
return this.requestRaw(method, path, body, query, opts, retryCount + 1);
|
|
187
|
+
}
|
|
188
|
+
throw err;
|
|
189
|
+
} finally {
|
|
190
|
+
clearTimeout(timeoutId);
|
|
191
|
+
}
|
|
192
|
+
if (RETRYABLE_STATUS_CODES.has(response.status) && retryCount < MAX_RETRIES) {
|
|
193
|
+
if (response.status === 429) {
|
|
194
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
195
|
+
const delayMs = retryAfter ? parseInt(retryAfter, 10) * 1e3 : BASE_RETRY_DELAY_MS * Math.pow(2, retryCount);
|
|
196
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
197
|
+
} else {
|
|
198
|
+
const delayMs = BASE_RETRY_DELAY_MS * Math.pow(2, retryCount);
|
|
199
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
200
|
+
}
|
|
201
|
+
return this.requestRaw(method, path, body, query, opts, retryCount + 1);
|
|
202
|
+
}
|
|
203
|
+
if (response.status === 429) {
|
|
204
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
205
|
+
throw new RateLimitError(retryAfter ? parseInt(retryAfter, 10) : void 0);
|
|
206
|
+
}
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
const requestId = this.extractRequestId(response);
|
|
209
|
+
let errorBody;
|
|
210
|
+
try {
|
|
211
|
+
const json = await response.json();
|
|
212
|
+
errorBody = json.error ? json : json.data ?? json;
|
|
213
|
+
} catch {
|
|
214
|
+
errorBody = { error: `http_${response.status}`, message: response.statusText };
|
|
215
|
+
}
|
|
216
|
+
throw this.buildError(response.status, errorBody, requestId);
|
|
217
|
+
}
|
|
218
|
+
return response;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Unwrap the API response envelope.
|
|
222
|
+
* API returns: { data: T, meta: {...} } for single resources
|
|
223
|
+
* { data: T[], total, limit, offset, meta: {...} } for lists
|
|
224
|
+
*/
|
|
225
|
+
unwrapEnvelope(json) {
|
|
226
|
+
if (json && typeof json === "object" && "data" in json) {
|
|
227
|
+
const obj = json;
|
|
228
|
+
if ("total" in obj && "limit" in obj) {
|
|
229
|
+
return json;
|
|
230
|
+
}
|
|
231
|
+
return obj.data;
|
|
232
|
+
}
|
|
233
|
+
return json;
|
|
234
|
+
}
|
|
235
|
+
extractPageFromEnvelope(json) {
|
|
236
|
+
if (!json || typeof json !== "object") return null;
|
|
237
|
+
const obj = json;
|
|
238
|
+
if (Array.isArray(obj.data) && "total" in obj) {
|
|
239
|
+
return { data: obj.data, total: obj.total, limit: obj.limit, offset: obj.offset };
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
extractRequestId(response) {
|
|
244
|
+
return response.headers.get("X-Request-Id") ?? void 0;
|
|
245
|
+
}
|
|
246
|
+
buildError(status, body, requestId) {
|
|
247
|
+
switch (status) {
|
|
248
|
+
case 401:
|
|
249
|
+
return new AuthenticationError(body.message);
|
|
250
|
+
case 404:
|
|
251
|
+
return new NotFoundError(body.message);
|
|
252
|
+
case 400:
|
|
253
|
+
case 422:
|
|
254
|
+
return new ValidationError(body.message ?? body.error, body.details);
|
|
255
|
+
case 429:
|
|
256
|
+
return new RateLimitError();
|
|
257
|
+
default:
|
|
258
|
+
return new APIError(status, body.error, body.message ?? body.error, requestId);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// src/resources/invoices.ts
|
|
264
|
+
var enc = encodeURIComponent;
|
|
265
|
+
var Invoices = class {
|
|
266
|
+
constructor(_client) {
|
|
267
|
+
this._client = _client;
|
|
268
|
+
}
|
|
269
|
+
list(params, opts) {
|
|
270
|
+
return this._client.getPage("/invoices", params, opts);
|
|
271
|
+
}
|
|
272
|
+
retrieve(id, opts) {
|
|
273
|
+
return this._client.get(`/invoices/${enc(id)}`, void 0, opts);
|
|
274
|
+
}
|
|
275
|
+
create(params, opts) {
|
|
276
|
+
return this._client.post("/invoices", params, opts);
|
|
277
|
+
}
|
|
278
|
+
update(id, params, opts) {
|
|
279
|
+
return this._client.patch(`/invoices/${enc(id)}`, params, opts);
|
|
280
|
+
}
|
|
281
|
+
del(id, opts) {
|
|
282
|
+
return this._client.del(`/invoices/${enc(id)}`, opts);
|
|
283
|
+
}
|
|
284
|
+
search(query, params, opts) {
|
|
285
|
+
return this._client.getPage("/invoices", { q: query, ...params }, opts);
|
|
286
|
+
}
|
|
287
|
+
markPaid(id, paidDate, opts) {
|
|
288
|
+
return this._client.post(`/invoices/${enc(id)}/paid`, paidDate ? { paidDate } : void 0, opts);
|
|
289
|
+
}
|
|
290
|
+
send(id, params, opts) {
|
|
291
|
+
return this._client.post(`/invoices/${enc(id)}/send`, params, opts);
|
|
292
|
+
}
|
|
293
|
+
pdf(id, opts) {
|
|
294
|
+
return this._client.getRaw(`/invoices/${enc(id)}/pdf`, opts);
|
|
295
|
+
}
|
|
296
|
+
createBatch(items, opts) {
|
|
297
|
+
return this._client.post("/invoices/batch", items, opts);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// src/resources/expenses.ts
|
|
302
|
+
var enc2 = encodeURIComponent;
|
|
303
|
+
var Expenses = class {
|
|
304
|
+
constructor(_client) {
|
|
305
|
+
this._client = _client;
|
|
306
|
+
}
|
|
307
|
+
list(params, opts) {
|
|
308
|
+
return this._client.getPage("/expenses", params, opts);
|
|
309
|
+
}
|
|
310
|
+
retrieve(id, opts) {
|
|
311
|
+
return this._client.get(`/expenses/${enc2(id)}`, void 0, opts);
|
|
312
|
+
}
|
|
313
|
+
create(params, opts) {
|
|
314
|
+
return this._client.post("/expenses", params, opts);
|
|
315
|
+
}
|
|
316
|
+
update(id, params, opts) {
|
|
317
|
+
return this._client.patch(`/expenses/${enc2(id)}`, params, opts);
|
|
318
|
+
}
|
|
319
|
+
del(id, opts) {
|
|
320
|
+
return this._client.del(`/expenses/${enc2(id)}`, opts);
|
|
321
|
+
}
|
|
322
|
+
search(query, params, opts) {
|
|
323
|
+
return this._client.getPage("/expenses", { q: query, ...params }, opts);
|
|
324
|
+
}
|
|
325
|
+
createBatch(items, opts) {
|
|
326
|
+
return this._client.post("/expenses/batch", items, opts);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// src/resources/clients.ts
|
|
331
|
+
var enc3 = encodeURIComponent;
|
|
332
|
+
var Clients = class {
|
|
333
|
+
constructor(_client) {
|
|
334
|
+
this._client = _client;
|
|
335
|
+
}
|
|
336
|
+
list(params, opts) {
|
|
337
|
+
return this._client.getPage("/clients", params, opts);
|
|
338
|
+
}
|
|
339
|
+
retrieve(id, opts) {
|
|
340
|
+
return this._client.get(`/clients/${enc3(id)}`, void 0, opts);
|
|
341
|
+
}
|
|
342
|
+
create(params, opts) {
|
|
343
|
+
return this._client.post("/clients", params, opts);
|
|
344
|
+
}
|
|
345
|
+
update(id, params, opts) {
|
|
346
|
+
return this._client.patch(`/clients/${enc3(id)}`, params, opts);
|
|
347
|
+
}
|
|
348
|
+
del(id, opts) {
|
|
349
|
+
return this._client.del(`/clients/${enc3(id)}`, opts);
|
|
350
|
+
}
|
|
351
|
+
search(query, params, opts) {
|
|
352
|
+
return this._client.getPage("/clients", { q: query, ...params }, opts);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// src/resources/products.ts
|
|
357
|
+
var enc4 = encodeURIComponent;
|
|
358
|
+
var Products = class {
|
|
359
|
+
constructor(_client) {
|
|
360
|
+
this._client = _client;
|
|
361
|
+
}
|
|
362
|
+
list(params, opts) {
|
|
363
|
+
return this._client.getPage("/products", params, opts);
|
|
364
|
+
}
|
|
365
|
+
retrieve(id, opts) {
|
|
366
|
+
return this._client.get(`/products/${enc4(id)}`, void 0, opts);
|
|
367
|
+
}
|
|
368
|
+
create(params, opts) {
|
|
369
|
+
return this._client.post("/products", params, opts);
|
|
370
|
+
}
|
|
371
|
+
update(id, params, opts) {
|
|
372
|
+
return this._client.patch(`/products/${enc4(id)}`, params, opts);
|
|
373
|
+
}
|
|
374
|
+
del(id, opts) {
|
|
375
|
+
return this._client.del(`/products/${enc4(id)}`, opts);
|
|
376
|
+
}
|
|
377
|
+
search(query, params, opts) {
|
|
378
|
+
return this._client.getPage("/products", { q: query, ...params }, opts);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// src/resources/quotes.ts
|
|
383
|
+
var enc5 = encodeURIComponent;
|
|
384
|
+
var Quotes = class {
|
|
385
|
+
constructor(_client) {
|
|
386
|
+
this._client = _client;
|
|
387
|
+
}
|
|
388
|
+
list(params, opts) {
|
|
389
|
+
return this._client.getPage("/quotes", params, opts);
|
|
390
|
+
}
|
|
391
|
+
retrieve(id, opts) {
|
|
392
|
+
return this._client.get(`/quotes/${enc5(id)}`, void 0, opts);
|
|
393
|
+
}
|
|
394
|
+
create(params, opts) {
|
|
395
|
+
return this._client.post("/quotes", params, opts);
|
|
396
|
+
}
|
|
397
|
+
update(id, params, opts) {
|
|
398
|
+
return this._client.patch(`/quotes/${enc5(id)}`, params, opts);
|
|
399
|
+
}
|
|
400
|
+
del(id, opts) {
|
|
401
|
+
return this._client.del(`/quotes/${enc5(id)}`, opts);
|
|
402
|
+
}
|
|
403
|
+
search(query, params, opts) {
|
|
404
|
+
return this._client.getPage("/quotes", { q: query, ...params }, opts);
|
|
405
|
+
}
|
|
406
|
+
pdf(id, opts) {
|
|
407
|
+
return this._client.getRaw(`/quotes/${enc5(id)}/pdf`, opts);
|
|
408
|
+
}
|
|
409
|
+
send(id, params, opts) {
|
|
410
|
+
return this._client.post(`/quotes/${enc5(id)}/send`, params, opts);
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/resources/vendors.ts
|
|
415
|
+
var enc6 = encodeURIComponent;
|
|
416
|
+
var Vendors = class {
|
|
417
|
+
constructor(_client) {
|
|
418
|
+
this._client = _client;
|
|
419
|
+
}
|
|
420
|
+
list(params, opts) {
|
|
421
|
+
return this._client.getPage("/vendors", params, opts);
|
|
422
|
+
}
|
|
423
|
+
retrieve(id, opts) {
|
|
424
|
+
return this._client.get(`/vendors/${enc6(id)}`, void 0, opts);
|
|
425
|
+
}
|
|
426
|
+
create(params, opts) {
|
|
427
|
+
return this._client.post("/vendors", params, opts);
|
|
428
|
+
}
|
|
429
|
+
update(id, params, opts) {
|
|
430
|
+
return this._client.patch(`/vendors/${enc6(id)}`, params, opts);
|
|
431
|
+
}
|
|
432
|
+
del(id, opts) {
|
|
433
|
+
return this._client.del(`/vendors/${enc6(id)}`, opts);
|
|
434
|
+
}
|
|
435
|
+
search(query, params, opts) {
|
|
436
|
+
return this._client.getPage("/vendors", { q: query, ...params }, opts);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// src/resources/webhooks.ts
|
|
441
|
+
var import_node_crypto = require("crypto");
|
|
442
|
+
var enc7 = encodeURIComponent;
|
|
443
|
+
var Webhooks = class {
|
|
444
|
+
constructor(_client) {
|
|
445
|
+
this._client = _client;
|
|
446
|
+
}
|
|
447
|
+
list(params, opts) {
|
|
448
|
+
return this._client.getPage("/webhooks", params, opts);
|
|
449
|
+
}
|
|
450
|
+
retrieve(id, opts) {
|
|
451
|
+
return this._client.get(`/webhooks/${enc7(id)}`, void 0, opts);
|
|
452
|
+
}
|
|
453
|
+
create(params, opts) {
|
|
454
|
+
return this._client.post("/webhooks", params, opts);
|
|
455
|
+
}
|
|
456
|
+
update(id, params, opts) {
|
|
457
|
+
return this._client.patch(`/webhooks/${enc7(id)}`, params, opts);
|
|
458
|
+
}
|
|
459
|
+
del(id, opts) {
|
|
460
|
+
return this._client.del(`/webhooks/${enc7(id)}`, opts);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Verify a webhook signature. Use this in your webhook handler to confirm
|
|
464
|
+
* the payload was sent by Frihet.
|
|
465
|
+
*
|
|
466
|
+
* @param payload - Raw request body (string or Buffer)
|
|
467
|
+
* @param signature - Value of the X-Frihet-Signature header
|
|
468
|
+
* @param secret - Your webhook secret
|
|
469
|
+
*/
|
|
470
|
+
static verifySignature(payload, signature, secret) {
|
|
471
|
+
const expected = `sha256=${(0, import_node_crypto.createHmac)("sha256", secret).update(payload).digest("hex")}`;
|
|
472
|
+
if (expected.length !== signature.length) return false;
|
|
473
|
+
let mismatch = 0;
|
|
474
|
+
for (let i = 0; i < expected.length; i++) {
|
|
475
|
+
mismatch |= expected.charCodeAt(i) ^ signature.charCodeAt(i);
|
|
476
|
+
}
|
|
477
|
+
return mismatch === 0;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
// src/resources/intelligence.ts
|
|
482
|
+
var Intelligence = class {
|
|
483
|
+
constructor(_client) {
|
|
484
|
+
this._client = _client;
|
|
485
|
+
}
|
|
486
|
+
context(opts) {
|
|
487
|
+
return this._client.get("/context", void 0, opts);
|
|
488
|
+
}
|
|
489
|
+
summary(params, opts) {
|
|
490
|
+
return this._client.get("/summary", params, opts);
|
|
491
|
+
}
|
|
492
|
+
monthly(month, opts) {
|
|
493
|
+
return this._client.get("/monthly", month ? { month } : void 0, opts);
|
|
494
|
+
}
|
|
495
|
+
quarterly(quarter, opts) {
|
|
496
|
+
return this._client.get("/quarterly", quarter ? { quarter } : void 0, opts);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/index.ts
|
|
501
|
+
var Frihet = class {
|
|
502
|
+
invoices;
|
|
503
|
+
expenses;
|
|
504
|
+
clients;
|
|
505
|
+
vendors;
|
|
506
|
+
products;
|
|
507
|
+
quotes;
|
|
508
|
+
webhooks;
|
|
509
|
+
intelligence;
|
|
510
|
+
constructor(opts) {
|
|
511
|
+
const client = new HttpClient(opts);
|
|
512
|
+
this.invoices = new Invoices(client);
|
|
513
|
+
this.expenses = new Expenses(client);
|
|
514
|
+
this.clients = new Clients(client);
|
|
515
|
+
this.vendors = new Vendors(client);
|
|
516
|
+
this.products = new Products(client);
|
|
517
|
+
this.quotes = new Quotes(client);
|
|
518
|
+
this.webhooks = new Webhooks(client);
|
|
519
|
+
this.intelligence = new Intelligence(client);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
var index_default = Frihet;
|
|
523
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
524
|
+
0 && (module.exports = {
|
|
525
|
+
APIError,
|
|
526
|
+
AuthenticationError,
|
|
527
|
+
Clients,
|
|
528
|
+
Expenses,
|
|
529
|
+
Frihet,
|
|
530
|
+
FrihetError,
|
|
531
|
+
Intelligence,
|
|
532
|
+
Invoices,
|
|
533
|
+
NotFoundError,
|
|
534
|
+
Products,
|
|
535
|
+
Quotes,
|
|
536
|
+
RateLimitError,
|
|
537
|
+
TimeoutError,
|
|
538
|
+
ValidationError,
|
|
539
|
+
Vendors,
|
|
540
|
+
Webhooks
|
|
541
|
+
});
|
|
542
|
+
//# sourceMappingURL=index.cjs.map
|