@jars-lt/jars-app-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.
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # @jars-lt/jars-app-sdk
2
+
3
+ Official TypeScript SDK for the [JARS Apskaita](https://app.jars.lt) accounting API — Lithuanian cloud accounting for partners, products, invoices, journal entries, and reports.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @jars-lt/jars-app-sdk
9
+ # or
10
+ npm install @jars-lt/jars-app-sdk
11
+ # or
12
+ yarn add @jars-lt/jars-app-sdk
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { JarsClient } from '@jars-lt/jars-app-sdk'
19
+
20
+ const jars = new JarsClient({ apiKey: process.env.JARS_API_KEY! })
21
+
22
+ // List partners with a search and a limit.
23
+ const partners = await jars.partners.list({ search: 'UAB', limit: 20 })
24
+
25
+ // Create a sales invoice (see the integration guide for the full line shape).
26
+ const invoice = (await jars.invoices.create({
27
+ type: 'SALES',
28
+ partnerId: partners[0]._id,
29
+ date: '2026-02-22',
30
+ lines: [/* ... */],
31
+ })) as { _id: string }
32
+
33
+ // Post it — this creates the journal entry and assigns the document number.
34
+ await jars.invoices.post(invoice._id)
35
+ ```
36
+
37
+ > The facade methods return loosely-typed payloads (`unknown` / `unknown[]`) by default. Pass a type argument — `jars.partners.list<Partner[]>()` — or cast the result to your own interface. Use `client.raw` (below) for fully-typed, schema-checked access.
38
+
39
+ ## Authentication
40
+
41
+ 1. Log in to JARS → **Settings → API Keys**.
42
+ 2. Click **Generate**, give the key a name, and copy it — it is shown only once.
43
+ 3. Provide it as `apiKey` when constructing the client.
44
+
45
+ Each API key is **bound to a single company**. All operations run in that company's context — there is no per-request tenant selection. The key is sent on every request as an `Authorization: Bearer <key>` header.
46
+
47
+ ## Configuration
48
+
49
+ ```ts
50
+ new JarsClient(config: JarsClientConfig)
51
+ ```
52
+
53
+ | Option | Type | Required | Default | Description |
54
+ | --------- | --------------- | -------- | ------------------------ | ----------------------------------------------------------------- |
55
+ | `apiKey` | `string` | yes | — | Your company-scoped API key. Throws if missing. |
56
+ | `baseUrl` | `string` | no | `https://app.jars.lt` | Override for staging/local. Trailing slashes are stripped. |
57
+ | `fetch` | `typeof fetch` | no | global `fetch` | Custom fetch implementation (e.g. a polyfill or instrumented one).|
58
+
59
+ ```ts
60
+ const jars = new JarsClient({
61
+ apiKey: process.env.JARS_API_KEY!,
62
+ baseUrl: 'http://localhost:3233', // local API
63
+ })
64
+ ```
65
+
66
+ ## Resources
67
+
68
+ Every resource is reachable as a property on the client (`jars.partners`, `jars.invoices`, …).
69
+
70
+ | Resource | Methods |
71
+ | ----------------- | ------------------------------------------------------------------------------------------------------------ |
72
+ | `jars.partners` | `list` · `get` · `create` · `update` · `remove` |
73
+ | `jars.products` | `list` · `get` · `create` · `update` · `remove` |
74
+ | `jars.invoices` | `list` · `get` · `create` · `update` · `remove` · `post` · `unpost` · `cancel` · `setExternalStatus` |
75
+ | `jars.journal` | `list` · `get` · `create` |
76
+ | `jars.reports` | `trialBalance` · `generalLedger` · `partnerBalance` · `cashBook` · `isafExport` |
77
+ | `jars.auditLogs` | `list` · `get` |
78
+ | `jars.lookups` | `accounts` · `vatCodes` · `units` · `templates` (list-only) |
79
+
80
+ ### Method signatures
81
+
82
+ ```ts
83
+ // CRUD resources (partners, products)
84
+ list<T = unknown[]>(params?: ListParams): Promise<T>
85
+ get<T = unknown>(id: string): Promise<T>
86
+ create<T = unknown>(body: Record<string, unknown>): Promise<T>
87
+ update<T = unknown>(id: string, body: Record<string, unknown>): Promise<T>
88
+ remove<T = unknown>(id: string): Promise<T>
89
+
90
+ // invoices additionally
91
+ post<T = unknown>(id: string): Promise<T>
92
+ unpost<T = unknown>(id: string): Promise<T>
93
+ cancel<T = unknown>(id: string): Promise<T>
94
+ setExternalStatus<T = unknown>(id: string, externalStatus: string | null): Promise<T>
95
+
96
+ // journal: list, get, create only
97
+ // reports: each method takes optional query params
98
+ trialBalance<T = unknown>(params?: ReportParams): Promise<T>
99
+ // lookups: list-only, e.g.
100
+ accounts<T = unknown[]>(params?: ListParams): Promise<T>
101
+ ```
102
+
103
+ ### Not in the facade yet
104
+
105
+ A few endpoints exist on the API but are not (yet) wrapped by a dedicated method:
106
+
107
+ - **Invoice PDF generation and email** (`POST /invoices/:id/pdf`, etc.)
108
+ - **Reference-data writes** — lookups expose list only; create/update/delete of accounts, VAT codes, units, and templates.
109
+
110
+ These are still reachable through the typed escape hatch below.
111
+
112
+ ## Raw escape hatch
113
+
114
+ `client.raw` is the underlying [`openapi-fetch`](https://openapi-ts.dev/openapi-fetch/) client, fully typed against the API's OpenAPI schema. Use it for endpoints the facade doesn't wrap, or when you want compile-time-checked paths and payloads:
115
+
116
+ ```ts
117
+ const { data, error } = await jars.raw.GET('/api/accounts', {
118
+ params: { query: { search: '24' } },
119
+ })
120
+ ```
121
+
122
+ The exported `paths` and `components` types describe the full schema:
123
+
124
+ ```ts
125
+ import type { paths, components } from '@jars-lt/jars-app-sdk'
126
+ ```
127
+
128
+ ## Errors
129
+
130
+ Any non-2xx response (and network/abort failures, reported as `status: 0`) throws a `JarsApiError`:
131
+
132
+ ```ts
133
+ import { JarsClient, JarsApiError } from '@jars-lt/jars-app-sdk'
134
+
135
+ try {
136
+ await jars.invoices.post(id)
137
+ } catch (e) {
138
+ if (e instanceof JarsApiError) {
139
+ console.error(e.status) // HTTP status (0 on network failure)
140
+ console.error(e.code) // stable error code, when the API provides one
141
+ console.error(e.details) // optional extra detail (e.g. validation issues)
142
+ console.error(e.message) // human-readable message
143
+ }
144
+ }
145
+ ```
146
+
147
+ ## Money convention
148
+
149
+ - **Line-level** values (`unitPrice`, `lineSubtotal`, `lineTotal`, `vatAmount`) are **EUR with up to 4 decimal places**, e.g. `unitPrice: 99.00`.
150
+ - **Document-level** values (`subtotal`, `vatTotal`, `total`, `amountDue`, and `vatSummary[]` amounts) are **integer cents**, e.g. `subtotal: 9900` for €99.00.
151
+
152
+ Localized names are objects of the form `{ lt, en?, ru? }` (`lt` required; `en`/`ru` optional).
153
+
154
+ See the [Integration Guide](https://app.jars.lt) for the full invoice/VAT calculation rules and a complete worked example.
155
+
156
+ ## Lists & filtering
157
+
158
+ Every `list(params?)` returns an **array**. The `params` object accepts the documented common keys plus arbitrary field filters that are passed straight through as query parameters:
159
+
160
+ ```ts
161
+ interface ListParams {
162
+ search?: string
163
+ sort?: string // field name; prefix with '-' for descending, e.g. '-date'
164
+ limit?: number // default 200, max 1000
165
+ [filter: string]: string | number | boolean | undefined
166
+ }
167
+ ```
168
+
169
+ ```ts
170
+ // arbitrary field filters
171
+ await jars.invoices.list({ status: 'POSTED', type: 'SALES', sort: '-date', limit: 50 })
172
+ await jars.partners.list({ externalCode: 'CRM-12345' })
173
+ ```
174
+
175
+ ## Versioning
176
+
177
+ The SDK follows [semantic versioning](https://semver.org/) **independently of the API version**:
178
+
179
+ - A new, additive API field → **minor** SDK release.
180
+ - A removed or renamed field, or a breaking method signature change → **major** SDK release.
181
+
182
+ ## Releasing
183
+
184
+ Publishing is automated by the [`Publish SDK`](../../.github/workflows/publish-sdk.yml) GitHub Actions workflow, run manually from the Actions tab:
185
+
186
+ 1. Open **Actions → Publish SDK → Run workflow**.
187
+ 2. Choose a **version bump**: `none` (publish the current `package.json` version as-is), `patch`, `minor`, or `major`.
188
+ 3. Run it.
189
+
190
+ The workflow verifies the generated types are in sync with the API, runs the SDK tests, builds the package, publishes it to npm, and — when a bump was chosen — commits the new version back to `main` (`sdk v<version>`).
191
+
192
+ Requires the `NPM_TOKEN` repository secret: an npm automation token with publish rights to the `@jars-lt` scope.
193
+
194
+ ## License
195
+
196
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,313 @@
1
+ "use strict";
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
+ AuditLogsResource: () => AuditLogsResource,
34
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
35
+ InvoicesResource: () => InvoicesResource,
36
+ JarsApiError: () => JarsApiError,
37
+ JarsClient: () => JarsClient,
38
+ JournalResource: () => JournalResource,
39
+ LookupsResource: () => LookupsResource,
40
+ PartnersResource: () => PartnersResource,
41
+ ProductsResource: () => ProductsResource,
42
+ ReportsResource: () => ReportsResource
43
+ });
44
+ module.exports = __toCommonJS(index_exports);
45
+
46
+ // src/client.ts
47
+ var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
48
+
49
+ // src/errors.ts
50
+ var JarsApiError = class _JarsApiError extends Error {
51
+ status;
52
+ code;
53
+ details;
54
+ constructor(init) {
55
+ super(init.message ?? "JARS API request failed");
56
+ this.name = "JarsApiError";
57
+ this.status = init.status;
58
+ this.code = init.code;
59
+ this.details = init.details;
60
+ Object.setPrototypeOf(this, _JarsApiError.prototype);
61
+ }
62
+ };
63
+
64
+ // src/resources/shared.ts
65
+ function toQuery(params) {
66
+ return params;
67
+ }
68
+
69
+ // src/resources/partners.ts
70
+ var PartnersResource = class {
71
+ constructor(client) {
72
+ this.client = client;
73
+ }
74
+ list(params) {
75
+ return this.client.request("get", "/api/partners", { query: toQuery(params) });
76
+ }
77
+ get(id) {
78
+ return this.client.request("get", "/api/partners/{id}", { params: { id } });
79
+ }
80
+ create(body) {
81
+ return this.client.request("post", "/api/partners", { body });
82
+ }
83
+ update(id, body) {
84
+ return this.client.request("put", "/api/partners/{id}", { params: { id }, body });
85
+ }
86
+ remove(id) {
87
+ return this.client.request("delete", "/api/partners/{id}", { params: { id } });
88
+ }
89
+ };
90
+
91
+ // src/resources/products.ts
92
+ var ProductsResource = class {
93
+ constructor(client) {
94
+ this.client = client;
95
+ }
96
+ list(params) {
97
+ return this.client.request("get", "/api/products", { query: toQuery(params) });
98
+ }
99
+ get(id) {
100
+ return this.client.request("get", "/api/products/{id}", { params: { id } });
101
+ }
102
+ create(body) {
103
+ return this.client.request("post", "/api/products", { body });
104
+ }
105
+ update(id, body) {
106
+ return this.client.request("put", "/api/products/{id}", { params: { id }, body });
107
+ }
108
+ remove(id) {
109
+ return this.client.request("delete", "/api/products/{id}", { params: { id } });
110
+ }
111
+ };
112
+
113
+ // src/resources/invoices.ts
114
+ var InvoicesResource = class {
115
+ constructor(client) {
116
+ this.client = client;
117
+ }
118
+ list(params) {
119
+ return this.client.request("get", "/api/invoices", { query: toQuery(params) });
120
+ }
121
+ get(id) {
122
+ return this.client.request("get", "/api/invoices/{id}", { params: { id } });
123
+ }
124
+ create(body) {
125
+ return this.client.request("post", "/api/invoices", { body });
126
+ }
127
+ update(id, body) {
128
+ return this.client.request("put", "/api/invoices/{id}", { params: { id }, body });
129
+ }
130
+ remove(id) {
131
+ return this.client.request("delete", "/api/invoices/{id}", { params: { id } });
132
+ }
133
+ post(id) {
134
+ return this.client.request("post", "/api/invoices/{id}/post", { params: { id } });
135
+ }
136
+ unpost(id) {
137
+ return this.client.request("post", "/api/invoices/{id}/unpost", { params: { id } });
138
+ }
139
+ cancel(id) {
140
+ return this.client.request("post", "/api/invoices/{id}/cancel", { params: { id } });
141
+ }
142
+ setExternalStatus(id, externalStatus) {
143
+ return this.client.request("patch", "/api/invoices/{id}/external-status", {
144
+ params: { id },
145
+ body: { externalStatus }
146
+ });
147
+ }
148
+ };
149
+
150
+ // src/resources/journal.ts
151
+ var JournalResource = class {
152
+ constructor(client) {
153
+ this.client = client;
154
+ }
155
+ list(params) {
156
+ return this.client.request("get", "/api/journal", { query: toQuery(params) });
157
+ }
158
+ get(id) {
159
+ return this.client.request("get", "/api/journal/{id}", { params: { id } });
160
+ }
161
+ create(body) {
162
+ return this.client.request("post", "/api/journal", { body });
163
+ }
164
+ };
165
+
166
+ // src/resources/reports.ts
167
+ var ReportsResource = class {
168
+ constructor(client) {
169
+ this.client = client;
170
+ }
171
+ trialBalance(params) {
172
+ return this.client.request("get", "/api/reports/trial-balance", { query: params });
173
+ }
174
+ generalLedger(params) {
175
+ return this.client.request("get", "/api/reports/general-ledger", { query: params });
176
+ }
177
+ partnerBalance(params) {
178
+ return this.client.request("get", "/api/reports/partner-balance", { query: params });
179
+ }
180
+ cashBook(params) {
181
+ return this.client.request("get", "/api/reports/cash-book", { query: params });
182
+ }
183
+ isafExport(params) {
184
+ return this.client.request("get", "/api/reports/isaf-export", { query: params });
185
+ }
186
+ };
187
+
188
+ // src/resources/audit-logs.ts
189
+ var AuditLogsResource = class {
190
+ constructor(client) {
191
+ this.client = client;
192
+ }
193
+ list(params) {
194
+ return this.client.request("get", "/api/audit-logs", { query: toQuery(params) });
195
+ }
196
+ get(id) {
197
+ return this.client.request("get", "/api/audit-logs/{id}", { params: { id } });
198
+ }
199
+ };
200
+
201
+ // src/resources/lookups.ts
202
+ var LookupsResource = class {
203
+ constructor(client) {
204
+ this.client = client;
205
+ }
206
+ accounts(params) {
207
+ return this.client.request("get", "/api/accounts", { query: toQuery(params) });
208
+ }
209
+ vatCodes(params) {
210
+ return this.client.request("get", "/api/vat-codes", { query: toQuery(params) });
211
+ }
212
+ units(params) {
213
+ return this.client.request("get", "/api/units", { query: toQuery(params) });
214
+ }
215
+ templates(params) {
216
+ return this.client.request("get", "/api/templates", { query: toQuery(params) });
217
+ }
218
+ };
219
+
220
+ // src/client.ts
221
+ var DEFAULT_BASE_URL = "https://app.jars.lt";
222
+ function safeJson(text) {
223
+ try {
224
+ return JSON.parse(text);
225
+ } catch {
226
+ return text;
227
+ }
228
+ }
229
+ var JarsClient = class {
230
+ /** Underlying `openapi-fetch` client for advanced, fully-typed use. */
231
+ raw;
232
+ partners;
233
+ products;
234
+ invoices;
235
+ journal;
236
+ reports;
237
+ auditLogs;
238
+ lookups;
239
+ baseUrl;
240
+ authHeader;
241
+ fetchImpl;
242
+ constructor(config) {
243
+ if (!config?.apiKey) throw new Error("JarsClient: apiKey is required");
244
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
245
+ this.authHeader = `Bearer ${config.apiKey}`;
246
+ this.fetchImpl = config.fetch ?? fetch;
247
+ this.raw = (0, import_openapi_fetch.default)({
248
+ baseUrl: this.baseUrl,
249
+ fetch: this.fetchImpl,
250
+ headers: { Authorization: this.authHeader }
251
+ });
252
+ this.partners = new PartnersResource(this);
253
+ this.products = new ProductsResource(this);
254
+ this.invoices = new InvoicesResource(this);
255
+ this.journal = new JournalResource(this);
256
+ this.reports = new ReportsResource(this);
257
+ this.auditLogs = new AuditLogsResource(this);
258
+ this.lookups = new LookupsResource(this);
259
+ }
260
+ async request(method, path, opts = {}) {
261
+ const finalPath = opts.params ? path.replace(/\{([^}]+)\}/g, (_, key) => {
262
+ const value = opts.params[key];
263
+ return encodeURIComponent(value ?? `{${key}}`);
264
+ }) : path;
265
+ const url = new URL(this.baseUrl + finalPath);
266
+ if (opts.query) {
267
+ for (const [key, value] of Object.entries(opts.query)) {
268
+ if (value !== void 0) url.searchParams.set(key, String(value));
269
+ }
270
+ }
271
+ const headers = new Headers({ Authorization: this.authHeader });
272
+ let body;
273
+ if (opts.body !== void 0) {
274
+ headers.set("content-type", "application/json");
275
+ body = JSON.stringify(opts.body);
276
+ }
277
+ let res;
278
+ try {
279
+ res = await this.fetchImpl(url, { method: method.toUpperCase(), headers, body });
280
+ } catch (cause) {
281
+ throw new JarsApiError({
282
+ status: 0,
283
+ message: cause instanceof Error ? cause.message : "Network error"
284
+ });
285
+ }
286
+ const text = await res.text();
287
+ const parsed = text === "" ? void 0 : safeJson(text);
288
+ if (!res.ok) {
289
+ const env = parsed ?? {};
290
+ throw new JarsApiError({
291
+ status: res.status,
292
+ message: env.error,
293
+ code: env.code,
294
+ details: env.details
295
+ });
296
+ }
297
+ return parsed;
298
+ }
299
+ };
300
+ // Annotate the CommonJS export names for ESM import in node:
301
+ 0 && (module.exports = {
302
+ AuditLogsResource,
303
+ DEFAULT_BASE_URL,
304
+ InvoicesResource,
305
+ JarsApiError,
306
+ JarsClient,
307
+ JournalResource,
308
+ LookupsResource,
309
+ PartnersResource,
310
+ ProductsResource,
311
+ ReportsResource
312
+ });
313
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/errors.ts","../src/resources/shared.ts","../src/resources/partners.ts","../src/resources/products.ts","../src/resources/invoices.ts","../src/resources/journal.ts","../src/resources/reports.ts","../src/resources/audit-logs.ts","../src/resources/lookups.ts"],"sourcesContent":["export { JarsClient, DEFAULT_BASE_URL } from './client'\nexport type { JarsClientConfig, RequestOptions, Method } from './client'\nexport { JarsApiError } from './errors'\nexport type { JarsApiErrorInit } from './errors'\nexport { PartnersResource } from './resources/partners'\nexport type { ListParams } from './resources/shared'\nexport { ProductsResource } from './resources/products'\nexport { InvoicesResource } from './resources/invoices'\nexport { JournalResource } from './resources/journal'\nexport { ReportsResource } from './resources/reports'\nexport type { ReportParams } from './resources/reports'\nexport { AuditLogsResource } from './resources/audit-logs'\nexport { LookupsResource } from './resources/lookups'\nexport type { paths, components } from './generated/types'\n","import createClient, { type Client } from 'openapi-fetch'\nimport type { paths } from './generated/types'\nimport { JarsApiError } from './errors'\nimport { PartnersResource } from './resources/partners'\nimport { ProductsResource } from './resources/products'\nimport { InvoicesResource } from './resources/invoices'\nimport { JournalResource } from './resources/journal'\nimport { ReportsResource } from './resources/reports'\nimport { AuditLogsResource } from './resources/audit-logs'\nimport { LookupsResource } from './resources/lookups'\n\n/** Default API host. The generated path keys already carry the `/api` prefix. */\nexport const DEFAULT_BASE_URL = 'https://app.jars.lt'\n\nexport type Method = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport interface JarsClientConfig {\n apiKey: string\n baseUrl?: string\n fetch?: typeof fetch\n}\n\nexport interface RequestOptions {\n query?: Record<string, string | number | boolean | undefined>\n body?: unknown\n params?: Record<string, string>\n}\n\ninterface ErrorEnvelope {\n error?: string\n code?: string\n details?: unknown\n}\n\n/** Parse JSON, falling back to the raw string when the body isn't valid JSON. */\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n\nexport class JarsClient {\n /** Underlying `openapi-fetch` client for advanced, fully-typed use. */\n readonly raw: Client<paths>\n\n readonly partners: PartnersResource\n readonly products: ProductsResource\n readonly invoices: InvoicesResource\n readonly journal: JournalResource\n readonly reports: ReportsResource\n readonly auditLogs: AuditLogsResource\n readonly lookups: LookupsResource\n\n private readonly baseUrl: string\n private readonly authHeader: string\n private readonly fetchImpl: typeof fetch\n\n constructor(config: JarsClientConfig) {\n if (!config?.apiKey) throw new Error('JarsClient: apiKey is required')\n\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '')\n this.authHeader = `Bearer ${config.apiKey}`\n this.fetchImpl = config.fetch ?? fetch\n\n this.raw = createClient<paths>({\n baseUrl: this.baseUrl,\n fetch: this.fetchImpl,\n headers: { Authorization: this.authHeader },\n })\n\n this.partners = new PartnersResource(this)\n this.products = new ProductsResource(this)\n this.invoices = new InvoicesResource(this)\n this.journal = new JournalResource(this)\n this.reports = new ReportsResource(this)\n this.auditLogs = new AuditLogsResource(this)\n this.lookups = new LookupsResource(this)\n }\n\n async request<T = unknown>(method: Method, path: string, opts: RequestOptions = {}): Promise<T> {\n const finalPath = opts.params\n ? path.replace(/\\{([^}]+)\\}/g, (_, key: string) => {\n const value = opts.params![key]\n return encodeURIComponent(value ?? `{${key}}`)\n })\n : path\n\n const url = new URL(this.baseUrl + finalPath)\n if (opts.query) {\n for (const [key, value] of Object.entries(opts.query)) {\n if (value !== undefined) url.searchParams.set(key, String(value))\n }\n }\n\n const headers = new Headers({ Authorization: this.authHeader })\n let body: string | undefined\n if (opts.body !== undefined) {\n headers.set('content-type', 'application/json')\n body = JSON.stringify(opts.body)\n }\n\n let res: Response\n try {\n res = await this.fetchImpl(url, { method: method.toUpperCase(), headers, body })\n } catch (cause) {\n throw new JarsApiError({\n status: 0,\n message: cause instanceof Error ? cause.message : 'Network error',\n })\n }\n\n const text = await res.text()\n const parsed = text === '' ? undefined : safeJson(text)\n\n if (!res.ok) {\n const env = (parsed ?? {}) as ErrorEnvelope\n throw new JarsApiError({\n status: res.status,\n message: env.error,\n code: env.code,\n details: env.details,\n })\n }\n\n return parsed as T\n }\n}\n","export interface JarsApiErrorInit {\n status: number\n message?: string\n code?: string\n details?: unknown\n}\n\n/** Thrown for any non-2xx API response or a network/abort failure (status 0). */\nexport class JarsApiError extends Error {\n readonly status: number\n readonly code?: string\n readonly details?: unknown\n\n constructor(init: JarsApiErrorInit) {\n super(init.message ?? 'JARS API request failed')\n this.name = 'JarsApiError'\n this.status = init.status\n this.code = init.code\n this.details = init.details\n Object.setPrototypeOf(this, JarsApiError.prototype)\n }\n}\n","import type { RequestOptions } from '../client'\n\n/**\n * List query parameters: the documented common params (search/sort/limit)\n * plus arbitrary passthrough field filters supported by the API.\n */\nexport interface ListParams {\n search?: string\n sort?: string\n limit?: number\n [filter: string]: string | number | boolean | undefined\n}\n\nexport function toQuery(params?: ListParams): RequestOptions['query'] {\n return params as RequestOptions['query']\n}\n","import type { JarsClient } from '../client'\nimport { type ListParams, toQuery } from './shared'\n\nexport type { ListParams } from './shared'\n\nexport class PartnersResource {\n constructor(private readonly client: JarsClient) {}\n\n list<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/partners', { query: toQuery(params) })\n }\n\n get<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('get', '/api/partners/{id}', { params: { id } })\n }\n\n create<T = unknown>(body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('post', '/api/partners', { body })\n }\n\n update<T = unknown>(id: string, body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('put', '/api/partners/{id}', { params: { id }, body })\n }\n\n remove<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('delete', '/api/partners/{id}', { params: { id } })\n }\n}\n","import type { JarsClient } from '../client'\nimport { type ListParams, toQuery } from './shared'\n\nexport class ProductsResource {\n constructor(private readonly client: JarsClient) {}\n\n list<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/products', { query: toQuery(params) })\n }\n\n get<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('get', '/api/products/{id}', { params: { id } })\n }\n\n create<T = unknown>(body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('post', '/api/products', { body })\n }\n\n update<T = unknown>(id: string, body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('put', '/api/products/{id}', { params: { id }, body })\n }\n\n remove<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('delete', '/api/products/{id}', { params: { id } })\n }\n}\n","import type { JarsClient } from '../client'\nimport { type ListParams, toQuery } from './shared'\n\nexport class InvoicesResource {\n constructor(private readonly client: JarsClient) {}\n\n list<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/invoices', { query: toQuery(params) })\n }\n\n get<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('get', '/api/invoices/{id}', { params: { id } })\n }\n\n create<T = unknown>(body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('post', '/api/invoices', { body })\n }\n\n update<T = unknown>(id: string, body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('put', '/api/invoices/{id}', { params: { id }, body })\n }\n\n remove<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('delete', '/api/invoices/{id}', { params: { id } })\n }\n\n post<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('post', '/api/invoices/{id}/post', { params: { id } })\n }\n\n unpost<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('post', '/api/invoices/{id}/unpost', { params: { id } })\n }\n\n cancel<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('post', '/api/invoices/{id}/cancel', { params: { id } })\n }\n\n setExternalStatus<T = unknown>(id: string, externalStatus: string | null): Promise<T> {\n return this.client.request<T>('patch', '/api/invoices/{id}/external-status', {\n params: { id },\n body: { externalStatus },\n })\n }\n}\n","import type { JarsClient } from '../client'\nimport { type ListParams, toQuery } from './shared'\n\nexport class JournalResource {\n constructor(private readonly client: JarsClient) {}\n\n list<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/journal', { query: toQuery(params) })\n }\n\n get<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('get', '/api/journal/{id}', { params: { id } })\n }\n\n create<T = unknown>(body: Record<string, unknown>): Promise<T> {\n return this.client.request<T>('post', '/api/journal', { body })\n }\n}\n","import type { JarsClient } from '../client'\n\nexport type ReportParams = Record<string, string | number | boolean | undefined>\n\nexport class ReportsResource {\n constructor(private readonly client: JarsClient) {}\n trialBalance<T = unknown>(params?: ReportParams): Promise<T> {\n return this.client.request<T>('get', '/api/reports/trial-balance', { query: params })\n }\n generalLedger<T = unknown>(params?: ReportParams): Promise<T> {\n return this.client.request<T>('get', '/api/reports/general-ledger', { query: params })\n }\n partnerBalance<T = unknown>(params?: ReportParams): Promise<T> {\n return this.client.request<T>('get', '/api/reports/partner-balance', { query: params })\n }\n cashBook<T = unknown>(params?: ReportParams): Promise<T> {\n return this.client.request<T>('get', '/api/reports/cash-book', { query: params })\n }\n isafExport<T = unknown>(params?: ReportParams): Promise<T> {\n return this.client.request<T>('get', '/api/reports/isaf-export', { query: params })\n }\n}\n","import { type ListParams, toQuery } from './shared'\nimport type { JarsClient } from '../client'\n\nexport class AuditLogsResource {\n constructor(private readonly client: JarsClient) {}\n list<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/audit-logs', { query: toQuery(params) })\n }\n get<T = unknown>(id: string): Promise<T> {\n return this.client.request<T>('get', '/api/audit-logs/{id}', { params: { id } })\n }\n}\n","import { type ListParams, toQuery } from './shared'\nimport type { JarsClient } from '../client'\n\n/**\n * Reference data (accounts, VAT codes, units, operation templates) is\n * read-mostly. For MVP the facade exposes LIST methods only; create/update/\n * delete remain available through the raw client.\n */\nexport class LookupsResource {\n constructor(private readonly client: JarsClient) {}\n\n accounts<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/accounts', { query: toQuery(params) })\n }\n\n vatCodes<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/vat-codes', { query: toQuery(params) })\n }\n\n units<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/units', { query: toQuery(params) })\n }\n\n templates<T = unknown[]>(params?: ListParams): Promise<T> {\n return this.client.request<T>('get', '/api/templates', { query: toQuery(params) })\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,2BAA0C;;;ACQnC,IAAM,eAAN,MAAM,sBAAqB,MAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAAwB;AAClC,UAAM,KAAK,WAAW,yBAAyB;AAC/C,SAAK,OAAO;AACZ,SAAK,SAAS,KAAK;AACnB,SAAK,OAAO,KAAK;AACjB,SAAK,UAAU,KAAK;AACpB,WAAO,eAAe,MAAM,cAAa,SAAS;AAAA,EACpD;AACF;;;ACRO,SAAS,QAAQ,QAA8C;AACpE,SAAO;AACT;;;ACVO,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAElD,KAAoB,QAAiC;AACnD,WAAO,KAAK,OAAO,QAAW,OAAO,iBAAiB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EAClF;AAAA,EAEA,IAAiB,IAAwB;AACvC,WAAO,KAAK,OAAO,QAAW,OAAO,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAC/E;AAAA,EAEA,OAAoB,MAA2C;AAC7D,WAAO,KAAK,OAAO,QAAW,QAAQ,iBAAiB,EAAE,KAAK,CAAC;AAAA,EACjE;AAAA,EAEA,OAAoB,IAAY,MAA2C;AACzE,WAAO,KAAK,OAAO,QAAW,OAAO,sBAAsB,EAAE,QAAQ,EAAE,GAAG,GAAG,KAAK,CAAC;AAAA,EACrF;AAAA,EAEA,OAAoB,IAAwB;AAC1C,WAAO,KAAK,OAAO,QAAW,UAAU,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAClF;AACF;;;ACxBO,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAElD,KAAoB,QAAiC;AACnD,WAAO,KAAK,OAAO,QAAW,OAAO,iBAAiB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EAClF;AAAA,EAEA,IAAiB,IAAwB;AACvC,WAAO,KAAK,OAAO,QAAW,OAAO,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAC/E;AAAA,EAEA,OAAoB,MAA2C;AAC7D,WAAO,KAAK,OAAO,QAAW,QAAQ,iBAAiB,EAAE,KAAK,CAAC;AAAA,EACjE;AAAA,EAEA,OAAoB,IAAY,MAA2C;AACzE,WAAO,KAAK,OAAO,QAAW,OAAO,sBAAsB,EAAE,QAAQ,EAAE,GAAG,GAAG,KAAK,CAAC;AAAA,EACrF;AAAA,EAEA,OAAoB,IAAwB;AAC1C,WAAO,KAAK,OAAO,QAAW,UAAU,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAClF;AACF;;;ACtBO,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAElD,KAAoB,QAAiC;AACnD,WAAO,KAAK,OAAO,QAAW,OAAO,iBAAiB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EAClF;AAAA,EAEA,IAAiB,IAAwB;AACvC,WAAO,KAAK,OAAO,QAAW,OAAO,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAC/E;AAAA,EAEA,OAAoB,MAA2C;AAC7D,WAAO,KAAK,OAAO,QAAW,QAAQ,iBAAiB,EAAE,KAAK,CAAC;AAAA,EACjE;AAAA,EAEA,OAAoB,IAAY,MAA2C;AACzE,WAAO,KAAK,OAAO,QAAW,OAAO,sBAAsB,EAAE,QAAQ,EAAE,GAAG,GAAG,KAAK,CAAC;AAAA,EACrF;AAAA,EAEA,OAAoB,IAAwB;AAC1C,WAAO,KAAK,OAAO,QAAW,UAAU,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAClF;AAAA,EAEA,KAAkB,IAAwB;AACxC,WAAO,KAAK,OAAO,QAAW,QAAQ,2BAA2B,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EACrF;AAAA,EAEA,OAAoB,IAAwB;AAC1C,WAAO,KAAK,OAAO,QAAW,QAAQ,6BAA6B,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EACvF;AAAA,EAEA,OAAoB,IAAwB;AAC1C,WAAO,KAAK,OAAO,QAAW,QAAQ,6BAA6B,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EACvF;AAAA,EAEA,kBAA+B,IAAY,gBAA2C;AACpF,WAAO,KAAK,OAAO,QAAW,SAAS,sCAAsC;AAAA,MAC3E,QAAQ,EAAE,GAAG;AAAA,MACb,MAAM,EAAE,eAAe;AAAA,IACzB,CAAC;AAAA,EACH;AACF;;;ACzCO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAElD,KAAoB,QAAiC;AACnD,WAAO,KAAK,OAAO,QAAW,OAAO,gBAAgB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EACjF;AAAA,EAEA,IAAiB,IAAwB;AACvC,WAAO,KAAK,OAAO,QAAW,OAAO,qBAAqB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EAC9E;AAAA,EAEA,OAAoB,MAA2C;AAC7D,WAAO,KAAK,OAAO,QAAW,QAAQ,gBAAgB,EAAE,KAAK,CAAC;AAAA,EAChE;AACF;;;ACbO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAClD,aAA0B,QAAmC;AAC3D,WAAO,KAAK,OAAO,QAAW,OAAO,8BAA8B,EAAE,OAAO,OAAO,CAAC;AAAA,EACtF;AAAA,EACA,cAA2B,QAAmC;AAC5D,WAAO,KAAK,OAAO,QAAW,OAAO,+BAA+B,EAAE,OAAO,OAAO,CAAC;AAAA,EACvF;AAAA,EACA,eAA4B,QAAmC;AAC7D,WAAO,KAAK,OAAO,QAAW,OAAO,gCAAgC,EAAE,OAAO,OAAO,CAAC;AAAA,EACxF;AAAA,EACA,SAAsB,QAAmC;AACvD,WAAO,KAAK,OAAO,QAAW,OAAO,0BAA0B,EAAE,OAAO,OAAO,CAAC;AAAA,EAClF;AAAA,EACA,WAAwB,QAAmC;AACzD,WAAO,KAAK,OAAO,QAAW,OAAO,4BAA4B,EAAE,OAAO,OAAO,CAAC;AAAA,EACpF;AACF;;;AClBO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAClD,KAAoB,QAAiC;AACnD,WAAO,KAAK,OAAO,QAAW,OAAO,mBAAmB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EACpF;AAAA,EACA,IAAiB,IAAwB;AACvC,WAAO,KAAK,OAAO,QAAW,OAAO,wBAAwB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAAA,EACjF;AACF;;;ACHO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAElD,SAAwB,QAAiC;AACvD,WAAO,KAAK,OAAO,QAAW,OAAO,iBAAiB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EAClF;AAAA,EAEA,SAAwB,QAAiC;AACvD,WAAO,KAAK,OAAO,QAAW,OAAO,kBAAkB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EACnF;AAAA,EAEA,MAAqB,QAAiC;AACpD,WAAO,KAAK,OAAO,QAAW,OAAO,cAAc,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EAC/E;AAAA,EAEA,UAAyB,QAAiC;AACxD,WAAO,KAAK,OAAO,QAAW,OAAO,kBAAkB,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EACnF;AACF;;;ATdO,IAAM,mBAAmB;AAuBhC,SAAS,SAAS,MAAuB;AACvC,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,aAAN,MAAiB;AAAA;AAAA,EAEb;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEQ;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAA0B;AACpC,QAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,MAAM,gCAAgC;AAErE,SAAK,WAAW,OAAO,WAAW,kBAAkB,QAAQ,QAAQ,EAAE;AACtE,SAAK,aAAa,UAAU,OAAO,MAAM;AACzC,SAAK,YAAY,OAAO,SAAS;AAEjC,SAAK,UAAM,qBAAAA,SAAoB;AAAA,MAC7B,SAAS,KAAK;AAAA,MACd,OAAO,KAAK;AAAA,MACZ,SAAS,EAAE,eAAe,KAAK,WAAW;AAAA,IAC5C,CAAC;AAED,SAAK,WAAW,IAAI,iBAAiB,IAAI;AACzC,SAAK,WAAW,IAAI,iBAAiB,IAAI;AACzC,SAAK,WAAW,IAAI,iBAAiB,IAAI;AACzC,SAAK,UAAU,IAAI,gBAAgB,IAAI;AACvC,SAAK,UAAU,IAAI,gBAAgB,IAAI;AACvC,SAAK,YAAY,IAAI,kBAAkB,IAAI;AAC3C,SAAK,UAAU,IAAI,gBAAgB,IAAI;AAAA,EACzC;AAAA,EAEA,MAAM,QAAqB,QAAgB,MAAc,OAAuB,CAAC,GAAe;AAC9F,UAAM,YAAY,KAAK,SACnB,KAAK,QAAQ,gBAAgB,CAAC,GAAG,QAAgB;AAC/C,YAAM,QAAQ,KAAK,OAAQ,GAAG;AAC9B,aAAO,mBAAmB,SAAS,IAAI,GAAG,GAAG;AAAA,IAC/C,CAAC,IACD;AAEJ,UAAM,MAAM,IAAI,IAAI,KAAK,UAAU,SAAS;AAC5C,QAAI,KAAK,OAAO;AACd,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACrD,YAAI,UAAU,OAAW,KAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,MAClE;AAAA,IACF;AAEA,UAAM,UAAU,IAAI,QAAQ,EAAE,eAAe,KAAK,WAAW,CAAC;AAC9D,QAAI;AACJ,QAAI,KAAK,SAAS,QAAW;AAC3B,cAAQ,IAAI,gBAAgB,kBAAkB;AAC9C,aAAO,KAAK,UAAU,KAAK,IAAI;AAAA,IACjC;AAEA,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,KAAK,UAAU,KAAK,EAAE,QAAQ,OAAO,YAAY,GAAG,SAAS,KAAK,CAAC;AAAA,IACjF,SAAS,OAAO;AACd,YAAM,IAAI,aAAa;AAAA,QACrB,QAAQ;AAAA,QACR,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,SAAS,SAAS,KAAK,SAAY,SAAS,IAAI;AAEtD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAO,UAAU,CAAC;AACxB,YAAM,IAAI,aAAa;AAAA,QACrB,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,MAAM,IAAI;AAAA,QACV,SAAS,IAAI;AAAA,MACf,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AACF;","names":["createClient"]}