@orvello/sdk 0.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.
@@ -0,0 +1 @@
1
+ 4efd4e4b669168c9cab5419fa04dd4e26a2029de2d4b10a59918e366189e1072
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Niccas Williams
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # `@orvello/sdk`
2
+
3
+ Typed, zero-dependency SDK for integrating Node and Next.js applications with **orvello** — the
4
+ accounting, invoicing, bookkeeping, customer-company and payments platform.
5
+
6
+ ## Features
7
+
8
+ - **End-to-End Typed**: Autogenerated DTOs, request bodies, and responses directly from the
9
+ orvello service contract.
10
+ - **Contract Verification**: Built-in runtime diagnostic (`diagnoseOrvello`) to verify that the
11
+ orvello service you point at speaks the exact contract compiled into the SDK.
12
+ - **Robust HTTP Engine**:
13
+ - Automatic unwrapping of `ApiEnvelope<T>` returning data directly.
14
+ - Automatic retry with exponential backoff on retriable errors (5xx, 429, network failures).
15
+ - Native PDF and binary blob streaming (`Blob`).
16
+ - `Idempotency-Key` support for safe webhooks and financial mutations.
17
+ - **Zero Runtime Dependencies**: Uses native Fetch and WebCrypto.
18
+ - **Flexible Auth**: Supports static API Keys, Bearer tokens, async token getters, and OAuth2
19
+ Client Credentials with automatic token caching.
20
+ - **Ergonomic Accounting Helpers**: Bank account caching (`getDefaultBankAccount`), base64 receipt
21
+ attachments (`buildBase64Receipt`), VAT calculations (`calculateVat`), and Kleinunternehmer
22
+ detection (`isKleinunternehmer`).
23
+
24
+ > **No baked-in endpoint.** This SDK deliberately ships without a fixed target URL. Every
25
+ > `OrvelloClient` — and every `diagnoseOrvello` call — must be pointed at an orvello platform URL
26
+ > explicitly (see below). Nothing quietly aims at a hidden default host.
27
+
28
+ ---
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pnpm add @orvello/sdk
34
+ # or
35
+ npm install @orvello/sdk
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Quick Start
41
+
42
+ ```typescript
43
+ import { createOrvelloClient, type BaseUrlProvider } from "@orvello/sdk";
44
+
45
+ // Point the client at your orvello deployment explicitly.
46
+ // baseUrl can be a plain string, a function returning a string/Promise, or come from ORVELLO_URL.
47
+ const orvello = createOrvelloClient({
48
+ baseUrl: process.env.ORVELLO_URL!, // e.g. "https://your-org.orvello.example"
49
+ auth: {
50
+ clientId: process.env.ORVELLO_CLIENT_ID!,
51
+ clientSecret: process.env.ORVELLO_CLIENT_SECRET!,
52
+ },
53
+ });
54
+
55
+ // API Key / Bearer token alternative:
56
+ // const orvello = createOrvelloClient({
57
+ // baseUrl: process.env.ORVELLO_URL!,
58
+ // auth: { apiKey: process.env.ORVELLO_API_KEY! },
59
+ // });
60
+ ```
61
+
62
+ ### Environment-driven configuration
63
+
64
+ `OrvelloClient` also auto-discovers its target and credentials from `ORVELLO_*` variables when no
65
+ explicit `baseUrl`/`auth` is given:
66
+
67
+ ```bash
68
+ ORVELLO_URL=https://your-org.orvello.example
69
+ ORVELLO_OAUTH_CLIENT_ID=...
70
+ ORVELLO_OAUTH_CLIENT_SECRET=...
71
+ # optional
72
+ ORVELLO_OAUTH_SCOPE=...
73
+ # or instead of OAuth:
74
+ ORVELLO_API_KEY=...
75
+ ```
76
+
77
+ ```typescript
78
+ // No config object at all — resolves ORVELLO_URL + any ORVELLO_* credentials.
79
+ const orvello = createOrvelloClient();
80
+ ```
81
+
82
+ If neither a `baseUrl` nor `ORVELLO_URL` is present, construction throws a clear error instead of
83
+ silently pointing at a fixed host.
84
+
85
+ ---
86
+
87
+ ## Usage Examples
88
+
89
+ ### 1. Invoices
90
+
91
+ #### Create an Invoice
92
+ ```typescript
93
+ const result = await orvello.invoices.create({
94
+ invoiceDate: "2026-09-05",
95
+ dueDate: "2026-09-19",
96
+ currency: "EUR",
97
+ customerName: "Acme Corp",
98
+ customerEmail: "accounting@acme.com",
99
+ issueImmediately: true,
100
+ generatePdf: true,
101
+ lineItems: [
102
+ { title: "Web Development Services", quantity: 1, unitPriceNet: "1500.00", taxRate: 19 },
103
+ ],
104
+ });
105
+
106
+ console.log("Created invoice:", result.invoice.invoiceNumber);
107
+ console.log("PDF URL:", result.pdfUrl);
108
+ ```
109
+
110
+ #### Download Invoice PDF
111
+ ```typescript
112
+ // As a binary Blob
113
+ const pdfBlob = await orvello.invoices.downloadPdf(result.invoice.id);
114
+
115
+ // Or from a relative/direct URL
116
+ const pdfFromUrl = await orvello.invoices.downloadPdfFromUrl(result.pdfUrl!);
117
+ ```
118
+
119
+ #### Settle an Invoice (Mark as Paid & Reconcile)
120
+ ```typescript
121
+ await orvello.invoices.updateStatus(result.invoice.id, {
122
+ status: "paid",
123
+ paymentReference: "STRIPE-PI-998877",
124
+ });
125
+
126
+ // Or use One-Shot Settlement with payment account and fee deduction:
127
+ const settlement = await orvello.bookkeeping.payments.settleInvoice({
128
+ invoiceId: result.invoice.id,
129
+ paymentAccountId: 1, // e.g. Stripe Account
130
+ payoutAmount: "1735.00", // net received after Stripe fee
131
+ paymentDate: "2026-09-05",
132
+ externalRef: "stripe-charge-ch_12345",
133
+ });
134
+ ```
135
+
136
+ #### Issue a Credit Note / Cancellation
137
+ ```typescript
138
+ // Preview first (GoBD compliant)
139
+ const preview = await orvello.invoices.previewCreditNote(result.invoice.id, {
140
+ mode: "full",
141
+ reason: "Customer cancellation within 14 days",
142
+ });
143
+
144
+ // Issue the credit note
145
+ const creditNote = await orvello.invoices.issueCreditNote(result.invoice.id, {
146
+ mode: "full",
147
+ reason: "Customer cancellation within 14 days",
148
+ });
149
+ console.log("Credit note issued:", creditNote.invoice.invoiceNumber);
150
+ ```
151
+
152
+ ---
153
+
154
+ ### 2. Bookkeeping & Expenses with Receipt Upload
155
+
156
+ ```typescript
157
+ import { buildBase64Receipt } from "@orvello/sdk";
158
+ import fs from "node:fs/promises";
159
+
160
+ const fileBuffer = await fs.readFile("./receipt.pdf");
161
+ const receipt = buildBase64Receipt(fileBuffer, "server-hosting.pdf", "application/pdf");
162
+
163
+ const expense = await orvello.bookkeeping.expenses.create(
164
+ {
165
+ managingCompanyId: 1,
166
+ expenseDate: "2026-09-01",
167
+ grossAmount: "119.00",
168
+ netAmount: "100.00",
169
+ taxAmount: "19.00",
170
+ taxRate: "19.00",
171
+ paymentMethod: "bank",
172
+ description: "Hetzner Dedicated Server",
173
+ externalRef: "hetzner-inv-2026-09",
174
+ },
175
+ { receipt }
176
+ );
177
+ ```
178
+
179
+ ---
180
+
181
+ ### 3. Payment Accounts & Default Bank Account
182
+
183
+ ```typescript
184
+ // Retrieve the default bank account (cached for 5 minutes)
185
+ const bank = await orvello.bookkeeping.getDefaultBankAccount();
186
+ console.log(`IBAN: ${bank.iban}, BIC: ${bank.bic}, Bank: ${bank.bank}`);
187
+ ```
188
+
189
+ ---
190
+
191
+ ### 4. Managing Company Context & Kleinunternehmer Detection
192
+
193
+ ```typescript
194
+ import { isKleinunternehmer } from "@orvello/sdk";
195
+
196
+ const context = await orvello.managingCompanies.getCurrent();
197
+ if (isKleinunternehmer(context)) {
198
+ console.log("Managing company is Kleinunternehmer (§ 19 UStG) - no VAT shown.");
199
+ } else {
200
+ console.log("Standard taxation (19% VAT).");
201
+ }
202
+ ```
203
+
204
+ ---
205
+
206
+ ### 5. Dunning / Mahnwesen
207
+
208
+ ```typescript
209
+ // Get overdue invoices ready for dunning
210
+ const suggestions = await orvello.dunning.suggestions({ limit: 10 });
211
+
212
+ // Issue dunning notice
213
+ for (const item of suggestions.items) {
214
+ if (item.suggestedLevel) {
215
+ const notice = await orvello.dunning.issue(item.invoiceId, { level: item.suggestedLevel });
216
+ }
217
+ }
218
+ ```
219
+
220
+ ---
221
+
222
+ ### 6. Contract Integrity & Health Diagnostic
223
+
224
+ ```typescript
225
+ import { diagnoseOrvello } from "@orvello/sdk";
226
+
227
+ // Pointed at the same platform (client carries a baseUrl) — no baked-in target here either.
228
+ const health = await diagnoseOrvello({ client: orvello });
229
+ if (!health.ok) {
230
+ console.warn("orvello service problem or contract drift:", health.problems);
231
+ } else {
232
+ console.log("orvello service is healthy and contract matches the SDK!");
233
+ }
234
+ ```
235
+
236
+ ---
237
+
238
+ ## Contract Types Re-Export
239
+
240
+ All generated DTOs, request types, and response types are re-exported under `@orvello/sdk/contract`:
241
+
242
+ ```typescript
243
+ import type {
244
+ InvoicesCreateExternalBody,
245
+ InvoicesGetByIdExternalResponseData,
246
+ CustomerCompany,
247
+ Invoice,
248
+ PaymentAccount,
249
+ } from "@orvello/sdk/contract";
250
+ ```
251
+
252
+ > **A note on generated names.** The contract subpath re-exports the raw platform contract, which is
253
+ > produced by the accounting backend itself. Some DTOs there carry the backend's internal prefixes
254
+ > (e.g. `NodeBillUser`, `NodeBillAppPermissions`). Those are the unchanged, authoritative types of
255
+ > the backend schema — the SDK only mirrors them. If the backend ever renames them it will flow
256
+ > through automatically via `api:generate`/`sync:contract`; do not hand-edit them here.
257
+
258
+ ---
259
+
260
+ ## License
261
+
262
+ MIT