@voyantjs/plugin-smartbill 0.78.0 → 0.80.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 CHANGED
@@ -199,6 +199,43 @@ finance records.
199
199
  | `./workflows` | Proforma conversion polling and drift reconciliation factories |
200
200
  | `./types` | SmartBill adapter and bundle types |
201
201
 
202
+ ## Rate limits
203
+
204
+ SmartBill can block an account after bursty traffic. `createSmartbillClient`
205
+ throws `SmartbillRateLimitError` when a response carries SmartBill's
206
+ rate-limit shape, with `retryAfterMs`, `retryAfterAt`, and `blockedAt` when the
207
+ response text contains enough timing data.
208
+
209
+ For cron or batch pollers, enable the process-local circuit breaker so repeated
210
+ calls do not keep hitting SmartBill while the account is blocked:
211
+
212
+ ```typescript
213
+ import {
214
+ createSmartbillClient,
215
+ SmartbillRateLimitCircuitOpenError,
216
+ SmartbillRateLimitError,
217
+ } from "@voyantjs/plugin-smartbill/client"
218
+
219
+ const client = createSmartbillClient({
220
+ username,
221
+ apiToken,
222
+ rateLimit: {
223
+ circuitBreaker: true,
224
+ },
225
+ })
226
+
227
+ try {
228
+ await client.listEstimateInvoices(companyVatCode, seriesName, number)
229
+ } catch (err) {
230
+ if (
231
+ err instanceof SmartbillRateLimitError ||
232
+ err instanceof SmartbillRateLimitCircuitOpenError
233
+ ) {
234
+ // Stop the batch and retry after `err.retryAfterMs`.
235
+ }
236
+ }
237
+ ```
238
+
202
239
  ## Local SmartBill Mock
203
240
 
204
241
  SmartBill does not provide a practical sandbox, and invoice/proforma calls can
package/dist/client.d.ts CHANGED
@@ -13,6 +13,16 @@ export interface SmartbillClientOptions {
13
13
  apiUrl?: string;
14
14
  /** Override `fetch` (e.g. in tests). Defaults to global `fetch`. */
15
15
  fetch?: SmartbillFetch;
16
+ /** Optional process-local protection for SmartBill account rate limits. */
17
+ rateLimit?: {
18
+ /**
19
+ * When enabled, the client opens a process-local circuit after the first
20
+ * SmartBill rate-limit response and skips network calls until retry time.
21
+ */
22
+ circuitBreaker?: boolean;
23
+ /** Test hook for deterministic time. */
24
+ now?: () => Date;
25
+ };
16
26
  }
17
27
  export interface SmartbillClientApi {
18
28
  /** Create an invoice. Returns the live envelope: series + number + URL + status/message. */
@@ -45,5 +55,32 @@ export interface SmartbillClientApi {
45
55
  /** List invoices created from a proforma (conversion lookup). */
46
56
  listEstimateInvoices(companyVatCode: string, seriesName: string, number: string): Promise<SmartbillEstimateInvoicesResponse>;
47
57
  }
58
+ export interface SmartbillApiErrorOptions {
59
+ operation: string;
60
+ status?: number;
61
+ body?: string;
62
+ response?: unknown;
63
+ }
64
+ export declare class SmartbillApiError extends Error {
65
+ readonly operation: string;
66
+ readonly status?: number;
67
+ readonly body?: string;
68
+ readonly response?: unknown;
69
+ constructor(message: string, options: SmartbillApiErrorOptions);
70
+ }
71
+ export interface SmartbillRateLimitErrorOptions extends SmartbillApiErrorOptions {
72
+ retryAfterMs?: number;
73
+ retryAfterAt?: Date;
74
+ blockedAt?: Date;
75
+ }
76
+ export declare class SmartbillRateLimitError extends SmartbillApiError {
77
+ readonly retryAfterMs?: number;
78
+ readonly retryAfterAt?: Date;
79
+ readonly blockedAt?: Date;
80
+ constructor(message: string, options: SmartbillRateLimitErrorOptions);
81
+ }
82
+ export declare class SmartbillRateLimitCircuitOpenError extends SmartbillRateLimitError {
83
+ constructor(options: SmartbillRateLimitErrorOptions);
84
+ }
48
85
  export declare function createSmartbillClient(options: SmartbillClientOptions): SmartbillClientApi;
49
86
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,YAAY,CAAA;AAEnB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,4FAA4F;IAC5F,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC5E,iCAAiC;IACjC,cAAc,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC7E,uEAAuE;IACvE,aAAa,CACX,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC7B,8CAA8C;IAC9C,cAAc,CACZ,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC7B,4CAA4C;IAC5C,aAAa,CACX,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC7B,wEAAwE;IACxE,cAAc,CACZ,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC,CAAA;IACpC,kCAAkC;IAClC,cAAc,CACZ,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAChC;;;OAGG;IACH,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAClG,mCAAmC;IACnC,eAAe,CACb,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAChC,yCAAyC;IACzC,gBAAgB,CACd,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACnC,sDAAsD;IACtD,SAAS,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAA;IAC5C,gEAAgE;IAChE,UAAU,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAA;IAC9C,iEAAiE;IACjE,oBAAoB,CAClB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iCAAiC,CAAC,CAAA;CAC9C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,kBAAkB,CAqMzF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,6 +1,87 @@
1
+ export class SmartbillApiError extends Error {
2
+ operation;
3
+ status;
4
+ body;
5
+ response;
6
+ constructor(message, options) {
7
+ super(message);
8
+ this.name = "SmartbillApiError";
9
+ this.operation = options.operation;
10
+ this.status = options.status;
11
+ this.body = options.body;
12
+ this.response = options.response;
13
+ }
14
+ }
15
+ export class SmartbillRateLimitError extends SmartbillApiError {
16
+ retryAfterMs;
17
+ retryAfterAt;
18
+ blockedAt;
19
+ constructor(message, options) {
20
+ super(message, options);
21
+ this.name = "SmartbillRateLimitError";
22
+ this.retryAfterMs = options.retryAfterMs;
23
+ this.retryAfterAt = options.retryAfterAt;
24
+ this.blockedAt = options.blockedAt;
25
+ }
26
+ }
27
+ export class SmartbillRateLimitCircuitOpenError extends SmartbillRateLimitError {
28
+ constructor(options) {
29
+ super(`SmartBill rate-limit circuit is open${options.retryAfterMs !== undefined ? `; retry after ${options.retryAfterMs}ms` : ""}`, options);
30
+ this.name = "SmartbillRateLimitCircuitOpenError";
31
+ }
32
+ }
33
+ const RATE_LIMIT_TEXT_PATTERN = /limita\s+maxima\s+de\s+requesturi|vei\s+putea\s+executa\s+alte\s+requesturi/i;
34
+ const RATE_LIMIT_MINUTES_PATTERN = /dupa\s+(\d+)\s*min/i;
35
+ const RATE_LIMIT_DATE_PATTERN = /(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{2}):(\d{2})|(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{2}):(\d{2})/;
36
+ function isRecord(value) {
37
+ return typeof value === "object" && value !== null;
38
+ }
39
+ function parseSmartbillDate(value) {
40
+ const match = RATE_LIMIT_DATE_PATTERN.exec(value);
41
+ if (!match)
42
+ return undefined;
43
+ if (match[1]) {
44
+ const [, day, month, year, hour, minute, second] = match;
45
+ return new Date(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second));
46
+ }
47
+ const [, , , , , , , year, month, day, hour, minute, second] = match;
48
+ return new Date(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second));
49
+ }
50
+ function parseSmartbillRateLimit(status, parsed, now) {
51
+ if (!isRecord(parsed))
52
+ return null;
53
+ const errorText = typeof parsed.errorText === "string"
54
+ ? parsed.errorText
55
+ : typeof parsed.message === "string"
56
+ ? parsed.message
57
+ : "";
58
+ if (status !== 403 && !RATE_LIMIT_TEXT_PATTERN.test(errorText))
59
+ return null;
60
+ if (!RATE_LIMIT_TEXT_PATTERN.test(errorText))
61
+ return null;
62
+ const minutesMatch = RATE_LIMIT_MINUTES_PATTERN.exec(errorText);
63
+ const blockedAt = parseSmartbillDate(errorText);
64
+ const minutes = minutesMatch?.[1] ? Number(minutesMatch[1]) : undefined;
65
+ const retryAfterAt = blockedAt && minutes !== undefined
66
+ ? new Date(blockedAt.getTime() + minutes * 60_000)
67
+ : typeof parsed.cooldown === "number" && parsed.cooldown > 0
68
+ ? new Date(now.getTime() + parsed.cooldown * 1000)
69
+ : undefined;
70
+ const retryAfterMs = retryAfterAt
71
+ ? Math.max(0, retryAfterAt.getTime() - now.getTime())
72
+ : undefined;
73
+ return {
74
+ errorText,
75
+ retryAfterMs,
76
+ retryAfterAt,
77
+ blockedAt,
78
+ };
79
+ }
1
80
  export function createSmartbillClient(options) {
2
81
  const apiUrl = (options.apiUrl ?? "https://ws.smartbill.ro/SBORO/api").replace(/\/$/, "");
3
- const fetchImpl = options.fetch ?? globalThis.fetch;
82
+ const fetchImpl = options.fetch ?? createGlobalSmartbillFetch();
83
+ const now = options.rateLimit?.now ?? (() => new Date());
84
+ let rateLimitCircuitOpenUntil;
4
85
  function authHeader() {
5
86
  return `Basic ${btoa(`${options.username}:${options.apiToken}`)}`;
6
87
  }
@@ -15,6 +96,7 @@ export function createSmartbillClient(options) {
15
96
  if (!fetchImpl) {
16
97
  throw new Error("SmartBill client requires a fetch implementation");
17
98
  }
99
+ assertRateLimitCircuitClosed(operation);
18
100
  const init = {
19
101
  method,
20
102
  headers: headers(),
@@ -32,11 +114,11 @@ export function createSmartbillClient(options) {
32
114
  // leave parsed as null, surface text
33
115
  }
34
116
  if (!response.ok) {
35
- throw new Error(`SmartBill ${operation} failed (${response.status}): ${text}`);
117
+ throw buildApiError(operation, response.status, text, parsed);
36
118
  }
37
119
  const envelope = (parsed ?? {});
38
120
  if (envelope.status === "Error" || envelope.errorText) {
39
- throw new Error(`SmartBill ${operation} failed: ${envelope.errorText ?? envelope.message ?? "Error"}`);
121
+ throw buildApiError(operation, response.status, text, parsed);
40
122
  }
41
123
  return envelope;
42
124
  }
@@ -44,13 +126,14 @@ export function createSmartbillClient(options) {
44
126
  if (!fetchImpl) {
45
127
  throw new Error("SmartBill client requires a fetch implementation");
46
128
  }
129
+ assertRateLimitCircuitClosed(operation);
47
130
  const response = await fetchImpl(`${apiUrl}${path}`, {
48
131
  method: "GET",
49
132
  headers: { ...headers(), Accept: "application/octet-stream" },
50
133
  });
51
134
  if (!response.ok) {
52
135
  const text = await response.text().catch(() => "");
53
- throw new Error(`SmartBill ${operation} failed (${response.status}): ${text}`);
136
+ throw buildApiError(operation, response.status, text, parseJson(text));
54
137
  }
55
138
  const buffer = await response.arrayBuffer();
56
139
  const contentType = response.headers?.get("content-type") ?? "application/pdf";
@@ -59,6 +142,55 @@ export function createSmartbillClient(options) {
59
142
  function pdfQuery(companyVatCode, seriesName, number) {
60
143
  return `cif=${encodeURIComponent(companyVatCode)}&seriesname=${encodeURIComponent(seriesName)}&number=${encodeURIComponent(number)}`;
61
144
  }
145
+ function assertRateLimitCircuitClosed(operation) {
146
+ if (!options.rateLimit?.circuitBreaker || !rateLimitCircuitOpenUntil)
147
+ return;
148
+ const currentTime = now();
149
+ if (currentTime.getTime() >= rateLimitCircuitOpenUntil.getTime()) {
150
+ rateLimitCircuitOpenUntil = undefined;
151
+ return;
152
+ }
153
+ throw new SmartbillRateLimitCircuitOpenError({
154
+ operation,
155
+ retryAfterAt: rateLimitCircuitOpenUntil,
156
+ retryAfterMs: rateLimitCircuitOpenUntil.getTime() - currentTime.getTime(),
157
+ });
158
+ }
159
+ function buildApiError(operation, status, text, parsed) {
160
+ const rateLimit = parseSmartbillRateLimit(status, parsed, now());
161
+ if (rateLimit) {
162
+ if (options.rateLimit?.circuitBreaker && rateLimit.retryAfterAt) {
163
+ rateLimitCircuitOpenUntil = rateLimit.retryAfterAt;
164
+ }
165
+ return new SmartbillRateLimitError(`SmartBill ${operation} rate-limited: ${rateLimit.errorText}`, {
166
+ operation,
167
+ status,
168
+ body: text,
169
+ response: parsed,
170
+ retryAfterMs: rateLimit.retryAfterMs,
171
+ retryAfterAt: rateLimit.retryAfterAt,
172
+ blockedAt: rateLimit.blockedAt,
173
+ });
174
+ }
175
+ const envelope = isRecord(parsed) ? parsed : null;
176
+ const message = envelope?.errorText || envelope?.message
177
+ ? `SmartBill ${operation} failed: ${envelope.errorText ?? envelope.message ?? "Error"}`
178
+ : `SmartBill ${operation} failed (${status}): ${text}`;
179
+ return new SmartbillApiError(message, {
180
+ operation,
181
+ status,
182
+ body: text,
183
+ response: parsed,
184
+ });
185
+ }
186
+ function parseJson(text) {
187
+ try {
188
+ return text ? JSON.parse(text) : null;
189
+ }
190
+ catch {
191
+ return null;
192
+ }
193
+ }
62
194
  async function createInvoice(body) {
63
195
  return request("createInvoice", "POST", "/invoice", body);
64
196
  }
@@ -123,3 +255,8 @@ export function createSmartbillClient(options) {
123
255
  listEstimateInvoices,
124
256
  };
125
257
  }
258
+ function createGlobalSmartbillFetch() {
259
+ if (typeof globalThis.fetch !== "function")
260
+ return undefined;
261
+ return (input, init) => globalThis.fetch(input, init);
262
+ }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export type { RetrySmartbillInvoiceArtifactInput, SmartbillArtifactPersistenceOptions, SmartbillArtifactPersistenceResult, SmartbillArtifactPersistenceRuntime, SmartbillArtifactStorageContext, SmartbillDbResolver, SmartbillDocumentStorageResolver, SmartbillDocumentType, SmartbillExternalRef, SmartbillStorageKeyPrefixResolver, } from "./artifacts.js";
2
2
  export { retrySmartbillInvoiceArtifact } from "./artifacts.js";
3
- export type { SmartbillClientApi, SmartbillClientOptions } from "./client.js";
4
- export { createSmartbillClient } from "./client.js";
3
+ export type { SmartbillApiErrorOptions, SmartbillClientApi, SmartbillClientOptions, } from "./client.js";
4
+ export { createSmartbillClient, SmartbillApiError, SmartbillRateLimitCircuitOpenError, SmartbillRateLimitError, } from "./client.js";
5
5
  export type { SmartbillAdminModuleOptions, SmartbillAdminRouteRuntime, SmartbillPluginOptionsResolver, } from "./hono.js";
6
6
  export { buildSmartbillAdminRouteRuntime, createSmartbillAdminModule, createSmartbillAdminRoutes, SMARTBILL_ADMIN_RUNTIME_CONTAINER_KEY, } from "./hono.js";
7
7
  export type { SmartbillEventValue, SmartbillMappingOptions, SmartbillMaybePromise, } from "./mapping.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kCAAkC,EAClC,mCAAmC,EACnC,kCAAkC,EAClC,mCAAmC,EACnC,+BAA+B,EAC/B,mBAAmB,EACnB,gCAAgC,EAChC,qBAAqB,EACrB,oBAAoB,EACpB,iCAAiC,GAClC,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA;AAC9D,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,8BAA8B,GAC/B,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,EAC1B,0BAA0B,EAC1B,qCAAqC,GACtC,MAAM,WAAW,CAAA;AAClB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrD,YAAY,EACV,qBAAqB,EACrB,2BAA2B,EAC3B,wCAAwC,EACxC,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EAAE,+BAA+B,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EACV,gCAAgC,EAChC,uCAAuC,EACvC,8BAA8B,EAC9B,0BAA0B,EAC1B,gCAAgC,EAChC,+BAA+B,EAC/B,gCAAgC,GACjC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,sCAAsC,EAAE,MAAM,iBAAiB,CAAA;AACxE,YAAY,EACV,8BAA8B,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAC3E,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,EAC9B,2BAA2B,EAC3B,iCAAiC,EACjC,wCAAwC,EACxC,uCAAuC,EACvC,uBAAuB,EACvB,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,sBAAsB,EACtB,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,8BAA8B,EAC9B,uCAAuC,GACxC,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kCAAkC,EAClC,mCAAmC,EACnC,kCAAkC,EAClC,mCAAmC,EACnC,+BAA+B,EAC/B,mBAAmB,EACnB,gCAAgC,EAChC,qBAAqB,EACrB,oBAAoB,EACpB,iCAAiC,GAClC,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA;AAC9D,YAAY,EACV,wBAAwB,EACxB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,kCAAkC,EAClC,uBAAuB,GACxB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,8BAA8B,GAC/B,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,EAC1B,0BAA0B,EAC1B,qCAAqC,GACtC,MAAM,WAAW,CAAA;AAClB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrD,YAAY,EACV,qBAAqB,EACrB,2BAA2B,EAC3B,wCAAwC,EACxC,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EAAE,+BAA+B,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EACV,gCAAgC,EAChC,uCAAuC,EACvC,8BAA8B,EAC9B,0BAA0B,EAC1B,gCAAgC,EAChC,+BAA+B,EAC/B,gCAAgC,GACjC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,sCAAsC,EAAE,MAAM,iBAAiB,CAAA;AACxE,YAAY,EACV,8BAA8B,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAC3E,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,EAC9B,2BAA2B,EAC3B,iCAAiC,EACjC,wCAAwC,EACxC,uCAAuC,EACvC,uBAAuB,EACvB,uBAAuB,EACvB,6BAA6B,EAC7B,6BAA6B,EAC7B,sBAAsB,EACtB,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,8BAA8B,EAC9B,uCAAuC,GACxC,MAAM,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { retrySmartbillInvoiceArtifact } from "./artifacts.js";
2
- export { createSmartbillClient } from "./client.js";
2
+ export { createSmartbillClient, SmartbillApiError, SmartbillRateLimitCircuitOpenError, SmartbillRateLimitError, } from "./client.js";
3
3
  export { buildSmartbillAdminRouteRuntime, createSmartbillAdminModule, createSmartbillAdminRoutes, SMARTBILL_ADMIN_RUNTIME_CONTAINER_KEY, } from "./hono.js";
4
4
  export { mapClient, mapLineItems, mapVoyantInvoiceToSmartbill, mapVoyantInvoiceToSmartbillAsync, } from "./mapping.js";
5
5
  export { createSmartbillMockServer } from "./mock.js";
@@ -9,6 +9,13 @@ export declare const smartbillPluginOptionsSchema: z.ZodObject<{
9
9
  seriesName: z.ZodCustom<import("./mapping.js").SmartbillEventValue<string>, import("./mapping.js").SmartbillEventValue<string>>;
10
10
  apiUrl: z.ZodOptional<z.ZodString>;
11
11
  fetch: z.ZodOptional<z.ZodCustom<SmartbillFetch | undefined, SmartbillFetch | undefined>>;
12
+ rateLimit: z.ZodOptional<z.ZodCustom<{
13
+ circuitBreaker?: boolean;
14
+ now?: () => Date;
15
+ } | undefined, {
16
+ circuitBreaker?: boolean;
17
+ now?: () => Date;
18
+ } | undefined>>;
12
19
  language: z.ZodOptional<z.ZodString>;
13
20
  isTaxIncluded: z.ZodOptional<z.ZodBoolean>;
14
21
  measuringUnitName: z.ZodOptional<z.ZodCustom<import("./mapping.js").SmartbillEventValue<string | null | undefined>, import("./mapping.js").SmartbillEventValue<string | null | undefined>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,CAAC,EAAE,MAAM,KAAK,CAAA;AACjC,OAAO,KAAK,EACV,mCAAmC,EACnC,mBAAmB,EACnB,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,gBAAgB,CAAA;AAEvB,OAAO,KAAK,EACV,qBAAqB,EACrB,2BAA2B,EAC3B,wCAAwC,EACxC,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAgHhD,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;iBAwBK,CAAA;AAE9C,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,sBAAsB,GAC9B,sBAAsB,CAexB"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,CAAC,EAAE,MAAM,KAAK,CAAA;AACjC,OAAO,KAAK,EACV,mCAAmC,EACnC,mBAAmB,EACnB,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,gBAAgB,CAAA;AAGvB,OAAO,KAAK,EACV,qBAAqB,EACrB,2BAA2B,EAC3B,wCAAwC,EACxC,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AA0HhD,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyBK,CAAA;AAE9C,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,sBAAsB,GAC9B,sBAAsB,CAexB"}
@@ -6,6 +6,15 @@ const optionalEventText = z.custom((value) => value === undefined ||
6
6
  (typeof value === "string" && value.trim().length > 0) ||
7
7
  typeof value === "function", "Expected a non-empty string or event resolver function");
8
8
  const optionalFetch = z.custom((value) => value === undefined || typeof value === "function", "Expected a fetch implementation function");
9
+ const optionalRateLimit = z.custom((value) => {
10
+ if (value === undefined)
11
+ return true;
12
+ if (typeof value !== "object" || value === null)
13
+ return false;
14
+ const options = value;
15
+ return ((options.circuitBreaker === undefined || typeof options.circuitBreaker === "boolean") &&
16
+ (options.now === undefined || typeof options.now === "function"));
17
+ }, "Expected valid SmartBill rate-limit options");
9
18
  const optionalLogger = z.custom((value) => value === undefined ||
10
19
  (typeof value === "object" &&
11
20
  value !== null &&
@@ -65,6 +74,7 @@ export const smartbillPluginOptionsSchema = z.object({
65
74
  seriesName: requiredEventString,
66
75
  apiUrl: optionalUrl,
67
76
  fetch: optionalFetch.optional(),
77
+ rateLimit: optionalRateLimit.optional(),
68
78
  language: optionalString,
69
79
  isTaxIncluded: z.boolean().optional(),
70
80
  measuringUnitName: optionalEventText.optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/plugin-smartbill",
3
- "version": "0.78.0",
3
+ "version": "0.80.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -59,18 +59,18 @@
59
59
  "drizzle-orm": "^0.45.2",
60
60
  "hono": "^4.12.10",
61
61
  "zod": "^4.3.6",
62
- "@voyantjs/core": "0.78.0",
63
- "@voyantjs/finance": "0.78.0",
64
- "@voyantjs/hono": "0.78.0",
65
- "@voyantjs/storage": "0.78.0"
62
+ "@voyantjs/core": "0.80.0",
63
+ "@voyantjs/finance": "0.80.0",
64
+ "@voyantjs/hono": "0.80.0",
65
+ "@voyantjs/storage": "0.80.0"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@tanstack/react-query": "^5.0.0",
69
69
  "lucide-react": "^0.475.0",
70
70
  "react": "^19.0.0",
71
71
  "react-dom": "^19.0.0",
72
- "@voyantjs/finance-react": "0.78.0",
73
- "@voyantjs/ui": "0.78.0"
72
+ "@voyantjs/finance-react": "0.80.0",
73
+ "@voyantjs/ui": "0.80.0"
74
74
  },
75
75
  "peerDependenciesMeta": {
76
76
  "@tanstack/react-query": {
@@ -101,8 +101,8 @@
101
101
  "react-dom": "^19.2.4",
102
102
  "typescript": "^6.0.2",
103
103
  "vitest": "^4.1.2",
104
- "@voyantjs/finance-react": "0.78.0",
105
- "@voyantjs/ui": "0.78.0",
104
+ "@voyantjs/finance-react": "0.80.0",
105
+ "@voyantjs/ui": "0.80.0",
106
106
  "@voyantjs/voyant-typescript-config": "0.1.0"
107
107
  },
108
108
  "files": [