@voyantjs/plugin-smartbill 0.78.0 → 0.79.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 +37 -0
- package/dist/client.d.ts +37 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +141 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/validation.d.ts +7 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +10 -0
- package/package.json +9 -9
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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;
|
|
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 ??
|
|
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
|
|
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
|
|
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
|
|
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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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";
|
package/dist/validation.d.ts
CHANGED
|
@@ -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>>>;
|
package/dist/validation.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/validation.js
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.79.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.
|
|
63
|
-
"@voyantjs/finance": "0.
|
|
64
|
-
"@voyantjs/hono": "0.
|
|
65
|
-
"@voyantjs/storage": "0.
|
|
62
|
+
"@voyantjs/core": "0.79.0",
|
|
63
|
+
"@voyantjs/finance": "0.79.0",
|
|
64
|
+
"@voyantjs/hono": "0.79.0",
|
|
65
|
+
"@voyantjs/storage": "0.79.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.
|
|
73
|
-
"@voyantjs/ui": "0.
|
|
72
|
+
"@voyantjs/finance-react": "0.79.0",
|
|
73
|
+
"@voyantjs/ui": "0.79.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.
|
|
105
|
-
"@voyantjs/ui": "0.
|
|
104
|
+
"@voyantjs/finance-react": "0.79.0",
|
|
105
|
+
"@voyantjs/ui": "0.79.0",
|
|
106
106
|
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
107
107
|
},
|
|
108
108
|
"files": [
|