@beel_es/sdk 1.0.0 → 1.1.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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -76
  3. package/dist/index.d.mts +9744 -0
  4. package/dist/index.d.ts +9736 -18
  5. package/dist/index.js +801 -50
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +756 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +48 -19
  10. package/dist/client.d.ts +0 -54
  11. package/dist/client.d.ts.map +0 -1
  12. package/dist/client.js +0 -94
  13. package/dist/client.js.map +0 -1
  14. package/dist/generated/client/client.gen.d.ts +0 -3
  15. package/dist/generated/client/client.gen.d.ts.map +0 -1
  16. package/dist/generated/client/client.gen.js +0 -240
  17. package/dist/generated/client/client.gen.js.map +0 -1
  18. package/dist/generated/client/index.d.ts +0 -9
  19. package/dist/generated/client/index.d.ts.map +0 -1
  20. package/dist/generated/client/index.js +0 -18
  21. package/dist/generated/client/index.js.map +0 -1
  22. package/dist/generated/client/types.gen.d.ts +0 -118
  23. package/dist/generated/client/types.gen.d.ts.map +0 -1
  24. package/dist/generated/client/types.gen.js +0 -4
  25. package/dist/generated/client/types.gen.js.map +0 -1
  26. package/dist/generated/client/utils.gen.d.ts +0 -34
  27. package/dist/generated/client/utils.gen.d.ts.map +0 -1
  28. package/dist/generated/client/utils.gen.js +0 -242
  29. package/dist/generated/client/utils.gen.js.map +0 -1
  30. package/dist/generated/client.gen.d.ts +0 -13
  31. package/dist/generated/client.gen.d.ts.map +0 -1
  32. package/dist/generated/client.gen.js +0 -7
  33. package/dist/generated/client.gen.js.map +0 -1
  34. package/dist/generated/core/auth.gen.d.ts +0 -19
  35. package/dist/generated/core/auth.gen.d.ts.map +0 -1
  36. package/dist/generated/core/auth.gen.js +0 -19
  37. package/dist/generated/core/auth.gen.js.map +0 -1
  38. package/dist/generated/core/bodySerializer.gen.d.ts +0 -26
  39. package/dist/generated/core/bodySerializer.gen.d.ts.map +0 -1
  40. package/dist/generated/core/bodySerializer.gen.js +0 -61
  41. package/dist/generated/core/bodySerializer.gen.js.map +0 -1
  42. package/dist/generated/core/params.gen.d.ts +0 -44
  43. package/dist/generated/core/params.gen.d.ts.map +0 -1
  44. package/dist/generated/core/params.gen.js +0 -105
  45. package/dist/generated/core/params.gen.js.map +0 -1
  46. package/dist/generated/core/pathSerializer.gen.d.ts +0 -34
  47. package/dist/generated/core/pathSerializer.gen.d.ts.map +0 -1
  48. package/dist/generated/core/pathSerializer.gen.js +0 -116
  49. package/dist/generated/core/pathSerializer.gen.js.map +0 -1
  50. package/dist/generated/core/queryKeySerializer.gen.d.ts +0 -19
  51. package/dist/generated/core/queryKeySerializer.gen.d.ts.map +0 -1
  52. package/dist/generated/core/queryKeySerializer.gen.js +0 -99
  53. package/dist/generated/core/queryKeySerializer.gen.js.map +0 -1
  54. package/dist/generated/core/serverSentEvents.gen.d.ts +0 -72
  55. package/dist/generated/core/serverSentEvents.gen.d.ts.map +0 -1
  56. package/dist/generated/core/serverSentEvents.gen.js +0 -138
  57. package/dist/generated/core/serverSentEvents.gen.js.map +0 -1
  58. package/dist/generated/core/types.gen.d.ts +0 -79
  59. package/dist/generated/core/types.gen.d.ts.map +0 -1
  60. package/dist/generated/core/types.gen.js +0 -4
  61. package/dist/generated/core/types.gen.js.map +0 -1
  62. package/dist/generated/core/utils.gen.d.ts +0 -20
  63. package/dist/generated/core/utils.gen.d.ts.map +0 -1
  64. package/dist/generated/core/utils.gen.js +0 -94
  65. package/dist/generated/core/utils.gen.js.map +0 -1
  66. package/dist/generated/index.d.ts +0 -3
  67. package/dist/generated/index.d.ts.map +0 -1
  68. package/dist/generated/index.js +0 -84
  69. package/dist/generated/index.js.map +0 -1
  70. package/dist/generated/sdk.gen.d.ts +0 -966
  71. package/dist/generated/sdk.gen.d.ts.map +0 -1
  72. package/dist/generated/sdk.gen.js +0 -1490
  73. package/dist/generated/sdk.gen.js.map +0 -1
  74. package/dist/generated/types.gen.d.ts +0 -5646
  75. package/dist/generated/types.gen.d.ts.map +0 -1
  76. package/dist/generated/types.gen.js +0 -4
  77. package/dist/generated/types.gen.js.map +0 -1
  78. package/dist/index.d.ts.map +0 -1
  79. package/dist/resources/companies.d.ts +0 -75
  80. package/dist/resources/companies.d.ts.map +0 -1
  81. package/dist/resources/companies.js +0 -77
  82. package/dist/resources/companies.js.map +0 -1
  83. package/dist/resources/config.d.ts +0 -106
  84. package/dist/resources/config.d.ts.map +0 -1
  85. package/dist/resources/config.js +0 -86
  86. package/dist/resources/config.js.map +0 -1
  87. package/dist/resources/customers.d.ts +0 -172
  88. package/dist/resources/customers.d.ts.map +0 -1
  89. package/dist/resources/customers.js +0 -96
  90. package/dist/resources/customers.js.map +0 -1
  91. package/dist/resources/invoices.d.ts +0 -370
  92. package/dist/resources/invoices.d.ts.map +0 -1
  93. package/dist/resources/invoices.js +0 -174
  94. package/dist/resources/invoices.js.map +0 -1
  95. package/dist/resources/products.d.ts +0 -155
  96. package/dist/resources/products.d.ts.map +0 -1
  97. package/dist/resources/products.js +0 -96
  98. package/dist/resources/products.js.map +0 -1
  99. package/dist/resources/series.d.ts +0 -98
  100. package/dist/resources/series.d.ts.map +0 -1
  101. package/dist/resources/series.js +0 -83
  102. package/dist/resources/series.js.map +0 -1
  103. package/dist/webhooks/index.d.ts +0 -20
  104. package/dist/webhooks/index.d.ts.map +0 -1
  105. package/dist/webhooks/index.js +0 -70
  106. package/dist/webhooks/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,52 +1,803 @@
1
1
  "use strict";
2
- /**
3
- * BeeL SDK for TypeScript
4
- *
5
- * The official TypeScript SDK for the BeeL API.
6
- * Fully typed, built on top of OpenAPI-generated code.
7
- *
8
- * @example
9
- * ```typescript
10
- * import { BeeL } from '@beel/sdk';
11
- *
12
- * const client = new BeeL('your-api-key');
13
- * const invoice = await client.invoices.get('inv_123');
14
- * ```
15
- */
16
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- var desc = Object.getOwnPropertyDescriptor(m, k);
19
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
- desc = { enumerable: true, get: function() { return m[k]; } };
21
- }
22
- Object.defineProperty(o, k2, desc);
23
- }) : (function(o, m, k, k2) {
24
- if (k2 === undefined) k2 = k;
25
- o[k2] = m[k];
26
- }));
27
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
28
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
29
- };
30
- Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.WebhookVerificationError = exports.WebhookVerifier = exports.Config = exports.Companies = exports.Series = exports.Products = exports.Customers = exports.Invoices = exports.BeeLError = exports.BeeL = void 0;
32
- var client_1 = require("./client");
33
- Object.defineProperty(exports, "BeeL", { enumerable: true, get: function () { return client_1.BeeL; } });
34
- Object.defineProperty(exports, "BeeLError", { enumerable: true, get: function () { return client_1.BeeLError; } });
35
- var invoices_1 = require("./resources/invoices");
36
- Object.defineProperty(exports, "Invoices", { enumerable: true, get: function () { return invoices_1.Invoices; } });
37
- var customers_1 = require("./resources/customers");
38
- Object.defineProperty(exports, "Customers", { enumerable: true, get: function () { return customers_1.Customers; } });
39
- var products_1 = require("./resources/products");
40
- Object.defineProperty(exports, "Products", { enumerable: true, get: function () { return products_1.Products; } });
41
- var series_1 = require("./resources/series");
42
- Object.defineProperty(exports, "Series", { enumerable: true, get: function () { return series_1.Series; } });
43
- var companies_1 = require("./resources/companies");
44
- Object.defineProperty(exports, "Companies", { enumerable: true, get: function () { return companies_1.Companies; } });
45
- var config_1 = require("./resources/config");
46
- Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } });
47
- // Re-export all generated types
48
- __exportStar(require("./generated/types.gen"), exports);
49
- var webhooks_1 = require("./webhooks");
50
- Object.defineProperty(exports, "WebhookVerifier", { enumerable: true, get: function () { return webhooks_1.WebhookVerifier; } });
51
- Object.defineProperty(exports, "WebhookVerificationError", { enumerable: true, get: function () { return webhooks_1.WebhookVerificationError; } });
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BeeL: () => BeeL,
34
+ BeeLApiError: () => BeeLApiError,
35
+ BeeLAuthError: () => BeeLAuthError,
36
+ BeeLConflictError: () => BeeLConflictError,
37
+ BeeLNotFoundError: () => BeeLNotFoundError,
38
+ BeeLRateLimitError: () => BeeLRateLimitError,
39
+ BeeLValidationError: () => BeeLValidationError,
40
+ CustomerBuilder: () => CustomerBuilder,
41
+ InvoiceBuilder: () => InvoiceBuilder,
42
+ WebhookVerificationError: () => WebhookVerificationError,
43
+ WebhookVerifier: () => WebhookVerifier
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/http/client.ts
48
+ var import_openapi_fetch = __toESM(require("openapi-fetch"));
49
+
50
+ // src/http/middleware.ts
51
+ var import_crypto = require("crypto");
52
+
53
+ // src/core/errors.ts
54
+ var BeeLApiError = class extends Error {
55
+ constructor(message, statusCode, code, details, requestId) {
56
+ super(message);
57
+ this.name = "BeeLApiError";
58
+ this.statusCode = statusCode;
59
+ this.code = code;
60
+ this.details = details;
61
+ this.requestId = requestId;
62
+ }
63
+ };
64
+ var BeeLRateLimitError = class extends BeeLApiError {
65
+ constructor(message, retryAfterSeconds, requestId) {
66
+ super(message, 429, "RATE_LIMIT_EXCEEDED", void 0, requestId);
67
+ this.name = "BeeLRateLimitError";
68
+ this.retryAfterSeconds = retryAfterSeconds;
69
+ }
70
+ };
71
+ var BeeLValidationError = class extends BeeLApiError {
72
+ constructor(message, details, requestId) {
73
+ super(message, 422, "UNPROCESSABLE_ENTITY", details, requestId);
74
+ this.name = "BeeLValidationError";
75
+ }
76
+ };
77
+ var BeeLAuthError = class extends BeeLApiError {
78
+ constructor(message, statusCode, requestId) {
79
+ super(
80
+ message,
81
+ statusCode,
82
+ statusCode === 401 ? "UNAUTHORIZED" : "FORBIDDEN",
83
+ void 0,
84
+ requestId
85
+ );
86
+ this.name = "BeeLAuthError";
87
+ }
88
+ };
89
+ var BeeLNotFoundError = class extends BeeLApiError {
90
+ constructor(message, requestId) {
91
+ super(message, 404, "NOT_FOUND", void 0, requestId);
92
+ this.name = "BeeLNotFoundError";
93
+ }
94
+ };
95
+ var BeeLConflictError = class extends BeeLApiError {
96
+ constructor(message, requestId) {
97
+ super(message, 409, "CONFLICT", void 0, requestId);
98
+ this.name = "BeeLConflictError";
99
+ }
100
+ };
101
+ function throwApiError(status, body) {
102
+ const parsed = body;
103
+ const errorData = parsed?.error ?? parsed;
104
+ const message = errorData?.message ?? `API error ${status}`;
105
+ const code = errorData?.code ?? "UNKNOWN";
106
+ const details = errorData?.details;
107
+ const requestId = parsed?.meta?.request_id;
108
+ switch (status) {
109
+ case 401:
110
+ case 403:
111
+ throw new BeeLAuthError(message, status, requestId);
112
+ case 404:
113
+ throw new BeeLNotFoundError(message, requestId);
114
+ case 409:
115
+ throw new BeeLConflictError(message, requestId);
116
+ case 422:
117
+ throw new BeeLValidationError(message, details, requestId);
118
+ case 429: {
119
+ const retryAfter = errorData?.retry_after ?? 60;
120
+ throw new BeeLRateLimitError(message, retryAfter, requestId);
121
+ }
122
+ default:
123
+ throw new BeeLApiError(message, status, code, details, requestId);
124
+ }
125
+ }
126
+
127
+ // src/http/middleware.ts
128
+ var requestMiddleware = {
129
+ async onRequest({ request }) {
130
+ const method = request.method;
131
+ if (["POST", "PUT", "PATCH"].includes(method)) {
132
+ const hasBody = request.headers.get("content-type")?.includes("application/json");
133
+ if (!hasBody) {
134
+ const clone = new Request(request, {
135
+ body: request.body ?? "{}",
136
+ headers: new Headers(request.headers)
137
+ });
138
+ clone.headers.set("Content-Type", "application/json");
139
+ if (method === "POST" && !clone.headers.has("Idempotency-Key")) {
140
+ clone.headers.set("Idempotency-Key", (0, import_crypto.randomUUID)());
141
+ }
142
+ return clone;
143
+ }
144
+ }
145
+ if (method === "POST" && !request.headers.has("Idempotency-Key")) {
146
+ request.headers.set("Idempotency-Key", (0, import_crypto.randomUUID)());
147
+ }
148
+ return request;
149
+ }
150
+ };
151
+ var errorMiddleware = {
152
+ async onResponse({ response }) {
153
+ if (!response.ok) {
154
+ const body = await response.json().catch(() => null);
155
+ throwApiError(response.status, body);
156
+ }
157
+ return response;
158
+ }
159
+ };
160
+ function createRetryMiddleware(options) {
161
+ return {
162
+ async onError({ error, request }) {
163
+ if (!(error instanceof BeeLApiError)) return;
164
+ if (!(error instanceof BeeLRateLimitError) && error.statusCode < 500) return;
165
+ for (let attempt = 0; attempt < options.maxRetries; attempt++) {
166
+ const delay = error instanceof BeeLRateLimitError ? error.retryAfterSeconds * 1e3 : Math.min(
167
+ options.initialDelayMs * Math.pow(2, attempt) + Math.random() * options.initialDelayMs,
168
+ options.maxDelayMs
169
+ );
170
+ await new Promise((r) => setTimeout(r, delay));
171
+ try {
172
+ if (request.method === "POST") {
173
+ request.headers.set("Idempotency-Key", (0, import_crypto.randomUUID)());
174
+ }
175
+ const response = await fetch(request.clone());
176
+ if (response.ok) return response;
177
+ const body = await response.json().catch(() => null);
178
+ throwApiError(response.status, body);
179
+ } catch (retryError) {
180
+ if (!(retryError instanceof BeeLApiError)) throw retryError;
181
+ if (!(retryError instanceof BeeLRateLimitError) && retryError.statusCode < 500) throw retryError;
182
+ if (attempt === options.maxRetries - 1) throw retryError;
183
+ }
184
+ }
185
+ }
186
+ };
187
+ }
188
+
189
+ // src/http/client.ts
190
+ function createBeeLClient(config) {
191
+ const client = (0, import_openapi_fetch.default)({
192
+ baseUrl: config.baseUrl ?? "https://app.beel.es/api",
193
+ headers: {
194
+ Authorization: `Bearer ${config.apiKey}`
195
+ }
196
+ });
197
+ client.use(requestMiddleware);
198
+ client.use(errorMiddleware);
199
+ client.use(
200
+ createRetryMiddleware({
201
+ maxRetries: config.maxRetries ?? 3,
202
+ initialDelayMs: config.retryDelayMs ?? 500,
203
+ maxDelayMs: config.maxRetryDelayMs ?? 3e4
204
+ })
205
+ );
206
+ return client;
207
+ }
208
+
209
+ // src/resources/invoices.ts
210
+ var InvoicesResource = class {
211
+ constructor(client) {
212
+ this.client = client;
213
+ }
214
+ /**
215
+ * List invoices with optional filters and pagination.
216
+ *
217
+ * @example
218
+ * const { invoices, pagination } = await beel.invoices.list({ status: 'ISSUED', limit: 20 });
219
+ */
220
+ async list(params) {
221
+ const { data } = await this.client.GET("/v1/invoices", { params: { query: params } });
222
+ return data.data;
223
+ }
224
+ /**
225
+ * Create a new invoice. An idempotency key is automatically added.
226
+ *
227
+ * @example
228
+ * const invoice = await beel.invoices.create({
229
+ * type: 'STANDARD',
230
+ * recipient: { customer_id: 'uuid' },
231
+ * lines: [{ description: 'Service', quantity: 1, unit_price: 100, discount_percentage: 0 }],
232
+ * });
233
+ */
234
+ async create(body) {
235
+ const { data } = await this.client.POST("/v1/invoices", { body });
236
+ return data.data;
237
+ }
238
+ /** Get an invoice by ID. */
239
+ async get(id) {
240
+ const { data } = await this.client.GET("/v1/invoices/{invoice_id}", { params: { path: { invoice_id: id } } });
241
+ return data.data;
242
+ }
243
+ /** Update a draft invoice. Only draft invoices can be updated. */
244
+ async update(id, body) {
245
+ const { data } = await this.client.PUT("/v1/invoices/{invoice_id}", { params: { path: { invoice_id: id } }, body });
246
+ return data.data;
247
+ }
248
+ /** Delete a draft invoice. Only draft invoices can be deleted. */
249
+ async delete(id) {
250
+ await this.client.DELETE("/v1/invoices/{invoice_id}", { params: { path: { invoice_id: id } } });
251
+ }
252
+ /** Duplicate an invoice, optionally into a different series. */
253
+ async duplicate(id, options) {
254
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/duplicate", { params: { path: { invoice_id: id } }, body: options });
255
+ return data.data;
256
+ }
257
+ /**
258
+ * Issue a draft invoice. Assigns an invoice number and triggers VeriFactu submission.
259
+ * @param options.wait_for_pdf - If true, waits for PDF generation before returning.
260
+ */
261
+ async issue(id, options) {
262
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/issue", { params: { path: { invoice_id: id }, query: options } });
263
+ return data.data;
264
+ }
265
+ /**
266
+ * Mark an invoice as paid.
267
+ * @param options.payment_date - Payment date (defaults to today).
268
+ * @param options.payment_method - Payment method details.
269
+ */
270
+ async markPaid(id, options) {
271
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/mark-paid", { params: { path: { invoice_id: id } }, body: options });
272
+ return data.data;
273
+ }
274
+ /** Mark an invoice as sent (e.g. delivered by other means). */
275
+ async markSent(id, options) {
276
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/mark-sent", { params: { path: { invoice_id: id } }, body: options });
277
+ return data.data;
278
+ }
279
+ /** Revert a paid/sent invoice back to issued status. */
280
+ async revertToIssued(id) {
281
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/revert-to-issued", { params: { path: { invoice_id: id } } });
282
+ return data.data;
283
+ }
284
+ /**
285
+ * Void an issued invoice. Requires a reason (min 10 chars).
286
+ *
287
+ * @example
288
+ * await beel.invoices.void('id', { reason: 'Duplicate invoice sent in error' });
289
+ */
290
+ async void(id, params) {
291
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/void", { params: { path: { invoice_id: id } }, body: params });
292
+ return data.data;
293
+ }
294
+ /** Create a corrective invoice that references the original. */
295
+ async createCorrective(id, body) {
296
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/corrective", { params: { path: { invoice_id: id } }, body });
297
+ return data.data;
298
+ }
299
+ /** Schedule a draft invoice to be issued on a future date. */
300
+ async schedule(id, params) {
301
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/schedule", { params: { path: { invoice_id: id } }, body: params });
302
+ return data.data;
303
+ }
304
+ /** Cancel a scheduled invoice, returning it to draft. */
305
+ async unschedule(id) {
306
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/unschedule", { params: { path: { invoice_id: id } } });
307
+ return data.data;
308
+ }
309
+ /** Change the scheduled date of a scheduled invoice. */
310
+ async reschedule(id, params) {
311
+ const { data } = await this.client.PATCH("/v1/invoices/{invoice_id}/reschedule", { params: { path: { invoice_id: id } }, body: params });
312
+ return data.data;
313
+ }
314
+ /**
315
+ * Get a pre-signed URL to download the invoice PDF.
316
+ * The URL expires in 5 minutes. Use `beel.downloadPdf(id)` for a simpler Buffer download.
317
+ */
318
+ async getPdf(id) {
319
+ const { data } = await this.client.GET("/v1/invoices/{invoice_id}/pdf", { params: { path: { invoice_id: id } } });
320
+ return data.data;
321
+ }
322
+ /** Send an invoice by email. Uses the customer's email by default. */
323
+ async sendEmail(id, options) {
324
+ const { data } = await this.client.POST("/v1/invoices/{invoice_id}/send", { params: { path: { invoice_id: id } }, body: options });
325
+ return data.data;
326
+ }
327
+ };
328
+
329
+ // src/resources/customers.ts
330
+ var CustomersResource = class {
331
+ constructor(client) {
332
+ this.client = client;
333
+ }
334
+ /**
335
+ * List customers with optional filters and pagination.
336
+ *
337
+ * @example
338
+ * const { customers, pagination } = await beel.customers.list({ search: 'Acme', limit: 10 });
339
+ */
340
+ async list(params) {
341
+ const { data } = await this.client.GET("/v1/customers", { params: { query: params } });
342
+ return data.data;
343
+ }
344
+ /**
345
+ * Create a new customer.
346
+ *
347
+ * @example
348
+ * const customer = await beel.customers.create({
349
+ * legal_name: 'Acme SL',
350
+ * nif: 'B12345678',
351
+ * address: { street: 'Calle Mayor', number: '1', postal_code: '28001', city: 'Madrid', province: 'Madrid', country: 'Spain', country_code: 'ES' },
352
+ * });
353
+ */
354
+ async create(body) {
355
+ const { data } = await this.client.POST("/v1/customers", { body });
356
+ return data.data;
357
+ }
358
+ /** Get a customer by ID. */
359
+ async get(id) {
360
+ const { data } = await this.client.GET("/v1/customers/{customer_id}", { params: { path: { customer_id: id } } });
361
+ return data.data;
362
+ }
363
+ /** Update a customer. Only provided fields are changed. */
364
+ async update(id, body) {
365
+ const { data } = await this.client.PUT("/v1/customers/{customer_id}", { params: { path: { customer_id: id } }, body });
366
+ return data.data;
367
+ }
368
+ /** Deactivate (soft-delete) a customer. */
369
+ async deactivate(id) {
370
+ await this.client.DELETE("/v1/customers/{customer_id}", { params: { path: { customer_id: id } } });
371
+ }
372
+ };
373
+
374
+ // src/resources/products.ts
375
+ var ProductsResource = class {
376
+ constructor(client) {
377
+ this.client = client;
378
+ }
379
+ /**
380
+ * List products with optional filters and pagination.
381
+ *
382
+ * @example
383
+ * const { products, pagination } = await beel.products.list({ category: 'SERVICE' });
384
+ */
385
+ async list(params) {
386
+ const { data } = await this.client.GET("/v1/products", { params: { query: params } });
387
+ return data.data;
388
+ }
389
+ /**
390
+ * Create a new product or service.
391
+ *
392
+ * @example
393
+ * const product = await beel.products.create({
394
+ * name: 'Consulting',
395
+ * code: 'CONS-001',
396
+ * category: 'SERVICE',
397
+ * default_price: 100,
398
+ * main_tax: { type: 'IVA', percentage: 21 },
399
+ * });
400
+ */
401
+ async create(body) {
402
+ const { data } = await this.client.POST("/v1/products", { body });
403
+ return data.data;
404
+ }
405
+ /** Get a product by ID. */
406
+ async get(id) {
407
+ const { data } = await this.client.GET("/v1/products/{product_id}", { params: { path: { product_id: id } } });
408
+ return data.data;
409
+ }
410
+ /** Update a product. Only provided fields are changed. */
411
+ async update(id, body) {
412
+ const { data } = await this.client.PUT("/v1/products/{product_id}", { params: { path: { product_id: id } }, body });
413
+ return data.data;
414
+ }
415
+ /** Delete a product permanently. */
416
+ async delete(id) {
417
+ await this.client.DELETE("/v1/products/{product_id}", { params: { path: { product_id: id } } });
418
+ }
419
+ /**
420
+ * Search products by name or code. Returns up to `limit` results.
421
+ *
422
+ * @example
423
+ * const results = await beel.products.search('consulting', 5);
424
+ */
425
+ async search(q, limit) {
426
+ const { data } = await this.client.GET("/v1/products/search", { params: { query: { q, limit } } });
427
+ return data.data;
428
+ }
429
+ };
430
+
431
+ // src/resources/configuration.ts
432
+ var ConfigurationResource = class {
433
+ constructor(client) {
434
+ this.client = client;
435
+ }
436
+ /** Get the current tax configuration (default VAT, IRPF, etc.). */
437
+ async getTaxConfig() {
438
+ const { data } = await this.client.GET("/v1/configuration/taxes");
439
+ return data.data;
440
+ }
441
+ /** Update tax configuration. */
442
+ async updateTaxConfig(body) {
443
+ const { data } = await this.client.PUT("/v1/configuration/taxes", { body });
444
+ return data.data;
445
+ }
446
+ /** Get available tax types (IVA/IGIC rates, IRPF types, equivalence surcharges). */
447
+ async getTaxTypes() {
448
+ const { data } = await this.client.GET("/v1/configuration/tax-types");
449
+ return data.data;
450
+ }
451
+ /** Get invoice customization options (logo, colors, footer text, etc.). */
452
+ async getInvoiceCustomizationOptions() {
453
+ const { data } = await this.client.GET("/v1/configuration/invoice-customization-options");
454
+ return data.data;
455
+ }
456
+ /** Update the user's preferred language (es, en, ca). */
457
+ async updateLanguage(language) {
458
+ const { data } = await this.client.PUT("/v1/configuration/language", { body: { language } });
459
+ return data.data;
460
+ }
461
+ /** Get VeriFactu configuration (enabled, certificate status, etc.). */
462
+ async getVerifactu() {
463
+ const { data } = await this.client.GET("/v1/configuration/verifactu");
464
+ return data.data;
465
+ }
466
+ /** Update VeriFactu configuration. */
467
+ async updateVerifactu(body) {
468
+ const { data } = await this.client.PUT("/v1/configuration/verifactu", { body });
469
+ return data.data;
470
+ }
471
+ };
472
+
473
+ // src/resources/series.ts
474
+ var SeriesResource = class {
475
+ constructor(client) {
476
+ this.client = client;
477
+ }
478
+ /**
479
+ * List all invoice series. Optionally filter by active status.
480
+ *
481
+ * @example
482
+ * const series = await beel.series.list();
483
+ * const activeSeries = await beel.series.list(true);
484
+ */
485
+ async list(active) {
486
+ const { data } = await this.client.GET("/v1/configuration/series", {
487
+ params: { query: active !== void 0 ? { active } : void 0 }
488
+ });
489
+ return data.data;
490
+ }
491
+ /** Create a new invoice series (e.g. "A-2026", "RECT"). */
492
+ async create(body) {
493
+ const { data } = await this.client.POST("/v1/configuration/series", { body });
494
+ return data.data;
495
+ }
496
+ /** Update a series (name, description, etc.). */
497
+ async update(id, body) {
498
+ const { data } = await this.client.PUT("/v1/configuration/series/{series_id}", {
499
+ params: { path: { series_id: id } },
500
+ body
501
+ });
502
+ return data.data;
503
+ }
504
+ /** Delete an invoice series. Only empty series can be deleted. */
505
+ async delete(id) {
506
+ await this.client.DELETE("/v1/configuration/series/{series_id}", {
507
+ params: { path: { series_id: id } }
508
+ });
509
+ }
510
+ /** Set a series as the default for new invoices. */
511
+ async setDefault(id) {
512
+ const { data } = await this.client.POST("/v1/configuration/series/{series_id}/default", {
513
+ params: { path: { series_id: id } }
514
+ });
515
+ return data.data;
516
+ }
517
+ };
518
+
519
+ // src/resources/nif.ts
520
+ var NifResource = class {
521
+ constructor(client) {
522
+ this.client = client;
523
+ }
524
+ /**
525
+ * Validate a Spanish NIF/CIF against the AEAT tax registry.
526
+ *
527
+ * @example
528
+ * const result = await beel.nif.validate('B12345678');
529
+ * console.log(result.valid, result.name);
530
+ */
531
+ async validate(nif) {
532
+ const { data } = await this.client.POST("/v1/nif/validate", { body: { nif } });
533
+ return data.data;
534
+ }
535
+ };
536
+
537
+ // src/client.ts
538
+ var BeeL = class {
539
+ constructor(config) {
540
+ const client = createBeeLClient(config);
541
+ this.invoices = new InvoicesResource(client);
542
+ this.customers = new CustomersResource(client);
543
+ this.products = new ProductsResource(client);
544
+ this.configuration = new ConfigurationResource(client);
545
+ this.series = new SeriesResource(client);
546
+ this.nif = new NifResource(client);
547
+ }
548
+ /**
549
+ * Download an invoice PDF as a Buffer.
550
+ *
551
+ * @example
552
+ * ```typescript
553
+ * const { buffer, fileName } = await beel.downloadPdf('invoice-uuid');
554
+ * fs.writeFileSync(fileName, buffer);
555
+ * ```
556
+ */
557
+ async downloadPdf(invoiceId) {
558
+ const pdf = await this.invoices.getPdf(invoiceId);
559
+ const response = await fetch(pdf.download_url);
560
+ if (!response.ok) throw new Error(`Failed to download PDF: ${response.status}`);
561
+ const arrayBuffer = await response.arrayBuffer();
562
+ return { buffer: Buffer.from(arrayBuffer), fileName: pdf.file_name };
563
+ }
564
+ };
565
+
566
+ // src/webhooks/verifier.ts
567
+ var import_crypto2 = require("crypto");
568
+ var WebhookVerifier = class {
569
+ /**
570
+ * Creates a new WebhookVerifier
571
+ *
572
+ * @param secret - Your webhook secret from BeeL dashboard
573
+ * @param toleranceSeconds - Maximum age of webhook events (default: 300 = 5 minutes)
574
+ */
575
+ constructor(secret, toleranceSeconds = 300) {
576
+ if (!secret || secret.trim().length === 0) {
577
+ throw new Error("Webhook secret is required");
578
+ }
579
+ this.secret = secret;
580
+ this.toleranceSeconds = toleranceSeconds;
581
+ }
582
+ /**
583
+ * Verify a webhook signature and return the parsed event
584
+ *
585
+ * @param rawBody - Raw request body (string or Buffer, before JSON parsing)
586
+ * @param signatureHeader - Value of the `BeeL-Signature` header
587
+ * @returns Parsed webhook event
588
+ * @throws {WebhookVerificationError} If signature is invalid or event is too old
589
+ *
590
+ * @example Basic usage
591
+ * ```typescript
592
+ * const verifier = new WebhookVerifier('your_secret');
593
+ * const event = verifier.verify(rawBody, signature);
594
+ *
595
+ * if (event.type === 'verifactu.status.updated') {
596
+ * console.log('Invoice:', event.data.invoice_number);
597
+ * console.log('Status:', event.data.new_status);
598
+ * }
599
+ * ```
600
+ */
601
+ verify(rawBody, signatureHeader) {
602
+ if (!signatureHeader) {
603
+ throw new WebhookVerificationError("Missing BeeL-Signature header");
604
+ }
605
+ const { timestamp, signature } = this.parseSignatureHeader(signatureHeader);
606
+ const now = Math.floor(Date.now() / 1e3);
607
+ const age = Math.abs(now - timestamp);
608
+ if (age > this.toleranceSeconds) {
609
+ throw new WebhookVerificationError(
610
+ `Webhook timestamp too old (${age}s ago, max ${this.toleranceSeconds}s allowed)`
611
+ );
612
+ }
613
+ const bodyString = Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : rawBody;
614
+ const expectedSignature = this.computeSignature(timestamp, bodyString);
615
+ if (!this.secureCompare(signature, expectedSignature)) {
616
+ throw new WebhookVerificationError("Invalid webhook signature");
617
+ }
618
+ try {
619
+ return JSON.parse(bodyString);
620
+ } catch (error) {
621
+ throw new WebhookVerificationError("Invalid JSON in webhook body");
622
+ }
623
+ }
624
+ /**
625
+ * Parse the BeeL-Signature header
626
+ *
627
+ * Format: `t=1741362026,v1=3c4f7a2e...`
628
+ */
629
+ parseSignatureHeader(header) {
630
+ const parts = header.split(",");
631
+ let timestamp;
632
+ let signature;
633
+ for (const part of parts) {
634
+ const [key, value] = part.split("=", 2);
635
+ if (key === "t") {
636
+ timestamp = parseInt(value, 10);
637
+ } else if (key === "v1") {
638
+ signature = value;
639
+ }
640
+ }
641
+ if (!timestamp || !signature) {
642
+ throw new WebhookVerificationError(
643
+ "Invalid signature header format (expected: t=timestamp,v1=signature)"
644
+ );
645
+ }
646
+ if (isNaN(timestamp)) {
647
+ throw new WebhookVerificationError("Invalid timestamp in signature header");
648
+ }
649
+ return { timestamp, signature };
650
+ }
651
+ /**
652
+ * Compute HMAC-SHA256 signature
653
+ *
654
+ * Algorithm:
655
+ * 1. Build signed payload: `{timestamp}.{raw_body}`
656
+ * 2. Compute: HMAC-SHA256(secret, signed_payload)
657
+ * 3. Return hex digest
658
+ */
659
+ computeSignature(timestamp, body) {
660
+ const signedPayload = `${timestamp}.${body}`;
661
+ return (0, import_crypto2.createHmac)("sha256", this.secret).update(signedPayload, "utf8").digest("hex");
662
+ }
663
+ /**
664
+ * Constant-time string comparison to prevent timing attacks
665
+ */
666
+ secureCompare(a, b) {
667
+ if (a.length !== b.length) {
668
+ return false;
669
+ }
670
+ const bufferA = Buffer.from(a, "utf8");
671
+ const bufferB = Buffer.from(b, "utf8");
672
+ return (0, import_crypto2.timingSafeEqual)(bufferA, bufferB);
673
+ }
674
+ };
675
+ var WebhookVerificationError = class extends Error {
676
+ constructor(message) {
677
+ super(message);
678
+ this.name = "WebhookVerificationError";
679
+ }
680
+ };
681
+
682
+ // src/builders/customer-builder.ts
683
+ var CustomerBuilder = class _CustomerBuilder {
684
+ constructor() {
685
+ }
686
+ static create() {
687
+ return new _CustomerBuilder();
688
+ }
689
+ name(name) {
690
+ this._name = name;
691
+ return this;
692
+ }
693
+ nif(nif) {
694
+ this._nif = nif;
695
+ return this;
696
+ }
697
+ email(email) {
698
+ this._email = email;
699
+ return this;
700
+ }
701
+ phone(phone) {
702
+ this._phone = phone;
703
+ return this;
704
+ }
705
+ address(street, number, postalCode, city, province, country, countryCode = "ES") {
706
+ this._address = { street, number, postal_code: postalCode, city, province, country, country_code: countryCode };
707
+ return this;
708
+ }
709
+ notes(notes) {
710
+ this._notes = notes;
711
+ return this;
712
+ }
713
+ build() {
714
+ if (!this._name || this._name.trim().length === 0) throw new Error("Legal name is required");
715
+ if (!this._nif || this._nif.trim().length === 0) throw new Error("NIF/CIF is required");
716
+ if (!this._address) throw new Error("Address is required");
717
+ return {
718
+ legal_name: this._name,
719
+ nif: this._nif,
720
+ email: this._email,
721
+ phone: this._phone,
722
+ address: this._address,
723
+ notes: this._notes
724
+ };
725
+ }
726
+ };
727
+
728
+ // src/builders/invoice-builder.ts
729
+ var InvoiceBuilder = class _InvoiceBuilder {
730
+ constructor() {
731
+ this._type = "STANDARD";
732
+ this._lines = [];
733
+ }
734
+ static create() {
735
+ return new _InvoiceBuilder();
736
+ }
737
+ type(type) {
738
+ this._type = type;
739
+ return this;
740
+ }
741
+ forCustomer(customerId) {
742
+ this._customerId = customerId;
743
+ return this;
744
+ }
745
+ operationDate(date) {
746
+ this._operationDate = date instanceof Date ? date.toISOString().split("T")[0] : date;
747
+ return this;
748
+ }
749
+ dueDate(date) {
750
+ this._dueDate = date instanceof Date ? date.toISOString().split("T")[0] : date;
751
+ return this;
752
+ }
753
+ addLine(description, quantity, unitPrice, discountPercentage = 0) {
754
+ this._lines.push({ description, quantity, unit_price: unitPrice, discount_percentage: discountPercentage });
755
+ return this;
756
+ }
757
+ addLineObject(line) {
758
+ this._lines.push(line);
759
+ return this;
760
+ }
761
+ notes(notes) {
762
+ this._notes = notes;
763
+ return this;
764
+ }
765
+ series(id) {
766
+ this._seriesId = id;
767
+ return this;
768
+ }
769
+ metadata(data) {
770
+ this._metadata = data;
771
+ return this;
772
+ }
773
+ build() {
774
+ if (!this._customerId) throw new Error("Customer ID is required");
775
+ if (this._lines.length === 0) throw new Error("At least one invoice line is required");
776
+ const recipient = { customer_id: this._customerId };
777
+ return {
778
+ type: this._type,
779
+ operation_date: this._operationDate,
780
+ due_date: this._dueDate,
781
+ recipient,
782
+ lines: this._lines,
783
+ notes: this._notes,
784
+ series_id: this._seriesId,
785
+ metadata: this._metadata
786
+ };
787
+ }
788
+ };
789
+ // Annotate the CommonJS export names for ESM import in node:
790
+ 0 && (module.exports = {
791
+ BeeL,
792
+ BeeLApiError,
793
+ BeeLAuthError,
794
+ BeeLConflictError,
795
+ BeeLNotFoundError,
796
+ BeeLRateLimitError,
797
+ BeeLValidationError,
798
+ CustomerBuilder,
799
+ InvoiceBuilder,
800
+ WebhookVerificationError,
801
+ WebhookVerifier
802
+ });
52
803
  //# sourceMappingURL=index.js.map