@ksefnik/http 0.0.1
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/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/adapter.d.ts +16 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +19 -0
- package/dist/adapter.js.map +1 -0
- package/dist/client.d.ts +48 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +107 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto.d.ts +22 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +30 -0
- package/dist/crypto.js.map +1 -0
- package/dist/endpoints.d.ts +20 -0
- package/dist/endpoints.d.ts.map +1 -0
- package/dist/endpoints.js +26 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/index.d.ts +30 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +2 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/generated/ksef-api.d.ts +10424 -0
- package/dist/generated/ksef-api.d.ts.map +1 -0
- package/dist/generated/ksef-api.js +6 -0
- package/dist/generated/ksef-api.js.map +1 -0
- package/dist/http.d.ts +24 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +120 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/invoices.d.ts +32 -0
- package/dist/invoices.d.ts.map +1 -0
- package/dist/invoices.js +130 -0
- package/dist/invoices.js.map +1 -0
- package/dist/public-key.d.ts +6 -0
- package/dist/public-key.d.ts.map +1 -0
- package/dist/public-key.js +37 -0
- package/dist/public-key.js.map +1 -0
- package/dist/retry.d.ts +19 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +59 -0
- package/dist/retry.js.map +1 -0
- package/dist/session.d.ts +29 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +109 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/xml.d.ts +12 -0
- package/dist/xml.d.ts.map +1 -0
- package/dist/xml.js +65 -0
- package/dist/xml.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CodeFormers-it
|
|
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,141 @@
|
|
|
1
|
+
# @ksefnik/http
|
|
2
|
+
|
|
3
|
+
Production HTTP client for **KSeF 2.0** (Krajowy System e-Faktur, Polish national e-invoicing system, live from 2026-02-01).
|
|
4
|
+
|
|
5
|
+
Implements the `KsefClient` interface from `@ksefnik/core` against the real `api.ksef.mf.gov.pl` endpoints. Plug it into the `Ksefnik` facade via `createHttpAdapter(...)` and you get end-to-end invoice retrieval, reconciliation, and MCP-mediated automation with zero additional code in consumers.
|
|
6
|
+
|
|
7
|
+
> **Research source of truth**: [CIRFMF/ksef-docs](https://github.com/CIRFMF/ksef-docs) — see [NOTES.md](./NOTES.md) for a summary of the auth flow, endpoint map, and rate limits used by this package.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @ksefnik/http @ksefnik/core @ksefnik/shared
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createKsefnik } from '@ksefnik/core'
|
|
19
|
+
import { createHttpAdapter } from '@ksefnik/http'
|
|
20
|
+
import { readFileSync } from 'node:fs'
|
|
21
|
+
|
|
22
|
+
const adapter = createHttpAdapter({
|
|
23
|
+
nip: '7010002137',
|
|
24
|
+
token: process.env.KSEF_TOKEN!,
|
|
25
|
+
environment: 'production',
|
|
26
|
+
publicKeyPem: readFileSync('./ksef-public-key.pem', 'utf8'),
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const ksef = createKsefnik({
|
|
30
|
+
config: { nip: '7010002137', environment: 'production', token: process.env.KSEF_TOKEN! },
|
|
31
|
+
adapter,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
await adapter.initSession?.()
|
|
35
|
+
const invoices = await ksef.invoices.fetch({ from: '2026-03-01', to: '2026-03-31' })
|
|
36
|
+
await adapter.closeSession?.()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Environments
|
|
40
|
+
|
|
41
|
+
| Environment | Base URL |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `production` | `https://api.ksef.mf.gov.pl/v2` |
|
|
44
|
+
| `demo` | `https://api-demo.ksef.mf.gov.pl/v2` |
|
|
45
|
+
| `test` | `https://api-test.ksef.mf.gov.pl/v2` |
|
|
46
|
+
|
|
47
|
+
## Authentication flow (KSeF 2.0)
|
|
48
|
+
|
|
49
|
+
1. `POST /auth/challenge` — server returns `{ challenge, timestamp }`.
|
|
50
|
+
2. Client encrypts `"{ksefToken}|{timestamp}"` with RSA-OAEP SHA-256 using the MF public key.
|
|
51
|
+
3. `POST /auth/ksef-token` — server returns `{ authenticationToken, referenceNumber }` (temporary JWT).
|
|
52
|
+
4. `POST /auth/token/redeem` (`Authorization: Bearer <authenticationToken>`) — returns `{ accessToken, refreshToken }`.
|
|
53
|
+
5. All subsequent calls use `Authorization: Bearer <accessToken>`.
|
|
54
|
+
6. Before expiry the client transparently calls `POST /auth/token/refresh` with the refresh token.
|
|
55
|
+
|
|
56
|
+
Crypto: **RSA-OAEP SHA-256 only**, implemented via `node:crypto` `webcrypto.subtle`. Zero external dependencies.
|
|
57
|
+
|
|
58
|
+
## Error handling
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { KsefApiError, KsefAuthError, KsefRateLimitError } from '@ksefnik/http'
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
await ksef.invoices.fetch(...)
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (error instanceof KsefAuthError) {
|
|
67
|
+
// 401/403 — refresh token expired, re-issue KSeF token in the portal
|
|
68
|
+
} else if (error instanceof KsefRateLimitError) {
|
|
69
|
+
// 429 — honour error.retryAfter (seconds) and retry
|
|
70
|
+
} else if (error instanceof KsefApiError) {
|
|
71
|
+
// 4xx/5xx with error.statusCode and error.detailCode
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The underlying `withRetry` from `@ksefnik/core` automatically retries `KsefRateLimitError` and `5xx` responses with exponential backoff.
|
|
77
|
+
|
|
78
|
+
## Rate limits
|
|
79
|
+
|
|
80
|
+
Per [limity-api.md](https://github.com/CIRFMF/ksef-docs/blob/main/limity/limity-api.md):
|
|
81
|
+
|
|
82
|
+
| Endpoint | req/s | req/min | req/h |
|
|
83
|
+
|---|---|---|---|
|
|
84
|
+
| `POST /invoices/query/metadata` | 8 | 16 | 20 |
|
|
85
|
+
| `GET /invoices/ksef/{ref}` | 8 | 16 | 64 |
|
|
86
|
+
| Default | 10 | 30 | 120 |
|
|
87
|
+
|
|
88
|
+
`fetchInvoices` uses `mapWithConcurrency(5)` by default to stay well within the bursting envelope.
|
|
89
|
+
|
|
90
|
+
## Not implemented in MVP
|
|
91
|
+
|
|
92
|
+
- `sendInvoice` — stub throws "not implemented".
|
|
93
|
+
- `getUpo` — stub throws "not implemented".
|
|
94
|
+
- Async export flow (`POST /invoices/exports` + polling) — v2.
|
|
95
|
+
|
|
96
|
+
## Smoke test
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
KSEF_TEST_NIP=... \
|
|
100
|
+
KSEF_TEST_TOKEN=... \
|
|
101
|
+
KSEF_TEST_PUBLIC_KEY_PATH=./ksef-test-pub.pem \
|
|
102
|
+
pnpm --filter @ksefnik/http smoke
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The smoke script talks to `api-test.ksef.mf.gov.pl` for manual end-to-end verification. It is **not** run in CI.
|
|
106
|
+
|
|
107
|
+
## Type generation from OpenAPI
|
|
108
|
+
|
|
109
|
+
Types for every KSeF 2.0 request/response in `src/session.ts`, `src/invoices.ts`, and `src/public-key.ts` are **generated** from the live production contract via [openapi-typescript](https://github.com/openapi-ts/openapi-typescript). The hand-written runtime (HTTP layer, retry, error mapping, session orchestration) is kept, but the shapes themselves are single-source-of-truth from MF.
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pnpm --filter @ksefnik/http generate
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This fetches `https://api.ksef.mf.gov.pl/docs/v2/openapi.json` and writes `src/generated/ksef-api.ts` (≈10k lines, 253 schemas, 59 paths). The generated file is committed to git so the package builds without network access, but should be refreshed whenever MF publishes a spec change.
|
|
116
|
+
|
|
117
|
+
### Workflow for contract changes
|
|
118
|
+
|
|
119
|
+
1. `pnpm --filter @ksefnik/http generate` — pulls the latest contract
|
|
120
|
+
2. `pnpm --filter @ksefnik/http build` — TypeScript flags any breaking changes at compile time (missing fields, renamed enums, nullability changes, etc.)
|
|
121
|
+
3. Fix the callsites in `session.ts`/`invoices.ts`/`public-key.ts` until the build is green
|
|
122
|
+
4. `pnpm --filter @ksefnik/http test` — unit + integration tests must stay green
|
|
123
|
+
5. `KSEF_ENV=production pnpm --filter @ksefnik/http smoke` — live verification against the real API
|
|
124
|
+
|
|
125
|
+
### What is generated vs hand-written
|
|
126
|
+
|
|
127
|
+
| Layer | Source |
|
|
128
|
+
|---|---|
|
|
129
|
+
| Request/response shapes (challenge, ksef-token, redeem, refresh, auth status, query metadata, public-key certs) | **generated** — `src/generated/ksef-api.ts` re-exported via `src/generated/index.ts` |
|
|
130
|
+
| Runtime HTTP client (`src/http.ts`) | hand-written — fetch, AbortSignal timeout, User-Agent, response parsing |
|
|
131
|
+
| Error mapping to `KsefAuthError`/`KsefRateLimitError`/`KsefApiError` | hand-written — `src/errors.ts` + `src/http.ts` |
|
|
132
|
+
| Retry with `Retry-After` honoring | hand-written — `src/retry.ts` |
|
|
133
|
+
| Auth flow orchestration (challenge → ksef-token → polling → redeem → refresh) | hand-written — `src/session.ts` |
|
|
134
|
+
| Pagination + `isTruncated` guard + concurrency | hand-written — `src/invoices.ts` |
|
|
135
|
+
| `KsefHttpClient` facade implementing `@ksefnik/core` `KsefClient` interface | hand-written — `src/client.ts` |
|
|
136
|
+
|
|
137
|
+
The generated file adds ~600KB to source control but adds **zero runtime cost** (pure `.d.ts`-style type exports — TSC erases them at build time).
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT. Part of the [ksefnik](../../README.md) monorepo.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { KsefAdapter } from '@ksefnik/shared';
|
|
2
|
+
import { type KsefHttpClientOptions } from './client.js';
|
|
3
|
+
import type { KsefEnvironment } from './endpoints.js';
|
|
4
|
+
export interface CreateHttpAdapterOpts {
|
|
5
|
+
nip: string;
|
|
6
|
+
token: string;
|
|
7
|
+
environment: KsefEnvironment;
|
|
8
|
+
/**
|
|
9
|
+
* Optional pinned MF RSA public key (PEM/SPKI). When omitted, the client
|
|
10
|
+
* fetches it from `GET /security/public-key-certificates` on first session.
|
|
11
|
+
*/
|
|
12
|
+
publicKeyPem?: string;
|
|
13
|
+
client?: Partial<Omit<KsefHttpClientOptions, 'environment' | 'publicKeyPem'>>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createHttpAdapter(opts: CreateHttpAdapterOpts): KsefAdapter;
|
|
16
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,eAAe,CAAA;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,aAAa,GAAG,cAAc,CAAC,CAAC,CAAA;CAC9E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,WAAW,CAc1E"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { KsefAdapterImpl } from '@ksefnik/core';
|
|
2
|
+
import { KsefHttpClient } from './client.js';
|
|
3
|
+
export function createHttpAdapter(opts) {
|
|
4
|
+
if (!opts.nip)
|
|
5
|
+
throw new Error('createHttpAdapter: nip is required');
|
|
6
|
+
if (!opts.token)
|
|
7
|
+
throw new Error('createHttpAdapter: token is required');
|
|
8
|
+
const client = new KsefHttpClient({
|
|
9
|
+
environment: opts.environment,
|
|
10
|
+
publicKeyPem: opts.publicKeyPem,
|
|
11
|
+
...opts.client,
|
|
12
|
+
});
|
|
13
|
+
return new KsefAdapterImpl(client, {
|
|
14
|
+
nip: opts.nip,
|
|
15
|
+
environment: opts.environment,
|
|
16
|
+
token: opts.token,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAG/C,OAAO,EAAE,cAAc,EAA8B,MAAM,aAAa,CAAA;AAexE,MAAM,UAAU,iBAAiB,CAAC,IAA2B;IAC3D,IAAI,CAAC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACpE,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;IAExE,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,GAAG,IAAI,CAAC,MAAM;KACf,CAAC,CAAA;IACF,OAAO,IAAI,eAAe,CAAC,MAAM,EAAE;QACjC,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type HttpRetryOptions } from './retry.js';
|
|
2
|
+
import type { KsefClient, KsefClientConfig, KsefSessionState, KsefRawInvoice } from '@ksefnik/core';
|
|
3
|
+
import { type KsefEnvironment } from './endpoints.js';
|
|
4
|
+
export interface KsefHttpClientOptions {
|
|
5
|
+
environment: KsefEnvironment;
|
|
6
|
+
/**
|
|
7
|
+
* MF RSA public key in PEM/SPKI format used for `/auth/ksef-token` encryption.
|
|
8
|
+
* If omitted, the client auto-fetches it from `GET /security/public-key-certificates`
|
|
9
|
+
* on first `initSession()` call and caches it for the lifetime of the client.
|
|
10
|
+
*/
|
|
11
|
+
publicKeyPem?: string;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
fetchImpl?: typeof fetch;
|
|
14
|
+
userAgent?: string;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
retry?: HttpRetryOptions;
|
|
17
|
+
}
|
|
18
|
+
export declare class KsefHttpClient implements KsefClient {
|
|
19
|
+
private readonly opts;
|
|
20
|
+
private readonly http;
|
|
21
|
+
private readonly retryOpts;
|
|
22
|
+
private cachedPublicKeyPem;
|
|
23
|
+
constructor(opts: KsefHttpClientOptions);
|
|
24
|
+
private resolvePublicKey;
|
|
25
|
+
initSession(config: KsefClientConfig): Promise<KsefSessionState>;
|
|
26
|
+
terminateSession(token: string): Promise<void>;
|
|
27
|
+
fetchInvoices(params: {
|
|
28
|
+
token: string;
|
|
29
|
+
dateFrom: string;
|
|
30
|
+
dateTo: string;
|
|
31
|
+
subjectNip?: string;
|
|
32
|
+
subjectType?: 'Subject1' | 'Subject2' | 'Subject3';
|
|
33
|
+
pageSize?: number;
|
|
34
|
+
pageOffset?: number;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
invoices: KsefRawInvoice[];
|
|
37
|
+
total: number;
|
|
38
|
+
}>;
|
|
39
|
+
sendInvoice(): Promise<{
|
|
40
|
+
ksefReferenceNumber: string;
|
|
41
|
+
timestamp: string;
|
|
42
|
+
}>;
|
|
43
|
+
getUpo(): Promise<{
|
|
44
|
+
xml: string;
|
|
45
|
+
status: 'confirmed' | 'pending' | 'rejected';
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AACjE,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACf,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAYhE,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,eAAe,CAAA;IAC5B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,gBAAgB,CAAA;CACzB;AAkCD,qBAAa,cAAe,YAAW,UAAU;IAKnC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,kBAAkB,CAAoB;gBAEjB,IAAI,EAAE,qBAAqB;YAY1C,gBAAgB;IAOxB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwBhE,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9C,aAAa,CAAC,MAAM,EAAE;QAC1B,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAA;QAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IA4BpD,WAAW,IAAI,OAAO,CAAC;QAAE,mBAAmB,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1E,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,CAAA;KAAE,CAAC;CAGvF"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { withHttpRetry } from './retry.js';
|
|
2
|
+
import { ENDPOINTS } from './endpoints.js';
|
|
3
|
+
import { HttpClient } from './http.js';
|
|
4
|
+
import { initKsefSession, refreshAccessToken, revokeCurrentSession, shouldRefresh, } from './session.js';
|
|
5
|
+
import { fetchInvoices as fetchInvoicesHttp } from './invoices.js';
|
|
6
|
+
import { fetchKsefTokenEncryptionKey } from './public-key.js';
|
|
7
|
+
/**
|
|
8
|
+
* Delimiter between fields of the encoded session token. JWTs (access and
|
|
9
|
+
* refresh tokens returned by KSeF 2.0) are base64url-encoded and cannot
|
|
10
|
+
* contain `||`, so this round-trips safely through `KsefClient.fetchInvoices`.
|
|
11
|
+
*/
|
|
12
|
+
const SESSION_TOKEN_SEPARATOR = '||';
|
|
13
|
+
function encodeSessionToken(session) {
|
|
14
|
+
return [
|
|
15
|
+
'v1',
|
|
16
|
+
session.accessToken,
|
|
17
|
+
session.refreshToken,
|
|
18
|
+
session.accessExpiresAt.toISOString(),
|
|
19
|
+
session.referenceNumber,
|
|
20
|
+
].join(SESSION_TOKEN_SEPARATOR);
|
|
21
|
+
}
|
|
22
|
+
function decodeSessionToken(token) {
|
|
23
|
+
const parts = token.split(SESSION_TOKEN_SEPARATOR);
|
|
24
|
+
if (parts.length !== 5 || parts[0] !== 'v1')
|
|
25
|
+
return null;
|
|
26
|
+
const [, accessToken, refreshToken, expiresAtIso, referenceNumber] = parts;
|
|
27
|
+
const accessExpiresAt = new Date(expiresAtIso);
|
|
28
|
+
if (Number.isNaN(accessExpiresAt.getTime()))
|
|
29
|
+
return null;
|
|
30
|
+
return { accessToken, refreshToken, accessExpiresAt, referenceNumber };
|
|
31
|
+
}
|
|
32
|
+
export class KsefHttpClient {
|
|
33
|
+
opts;
|
|
34
|
+
http;
|
|
35
|
+
retryOpts;
|
|
36
|
+
cachedPublicKeyPem;
|
|
37
|
+
constructor(opts) {
|
|
38
|
+
this.opts = opts;
|
|
39
|
+
const baseUrl = opts.baseUrl ?? ENDPOINTS[opts.environment];
|
|
40
|
+
this.http = new HttpClient({
|
|
41
|
+
baseUrl,
|
|
42
|
+
fetchImpl: opts.fetchImpl,
|
|
43
|
+
userAgent: opts.userAgent,
|
|
44
|
+
defaultTimeoutMs: opts.timeoutMs,
|
|
45
|
+
});
|
|
46
|
+
this.retryOpts = opts.retry ?? {};
|
|
47
|
+
this.cachedPublicKeyPem = opts.publicKeyPem;
|
|
48
|
+
}
|
|
49
|
+
async resolvePublicKey() {
|
|
50
|
+
if (this.cachedPublicKeyPem)
|
|
51
|
+
return this.cachedPublicKeyPem;
|
|
52
|
+
const pem = await fetchKsefTokenEncryptionKey(this.http);
|
|
53
|
+
this.cachedPublicKeyPem = pem;
|
|
54
|
+
return pem;
|
|
55
|
+
}
|
|
56
|
+
async initSession(config) {
|
|
57
|
+
if (!config.token) {
|
|
58
|
+
throw new Error('KsefHttpClient.initSession: config.token (KSeF token) is required');
|
|
59
|
+
}
|
|
60
|
+
const publicKeyPem = await this.resolvePublicKey();
|
|
61
|
+
const session = await withHttpRetry(() => initKsefSession(this.http, {
|
|
62
|
+
nip: config.nip,
|
|
63
|
+
ksefToken: config.token,
|
|
64
|
+
publicKeyPem,
|
|
65
|
+
}), this.retryOpts);
|
|
66
|
+
return {
|
|
67
|
+
token: encodeSessionToken(session),
|
|
68
|
+
nip: config.nip,
|
|
69
|
+
environment: config.environment,
|
|
70
|
+
expiresAt: session.accessExpiresAt,
|
|
71
|
+
referenceNumber: session.referenceNumber,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async terminateSession(token) {
|
|
75
|
+
const session = decodeSessionToken(token);
|
|
76
|
+
if (!session)
|
|
77
|
+
return;
|
|
78
|
+
await revokeCurrentSession(this.http, session);
|
|
79
|
+
}
|
|
80
|
+
async fetchInvoices(params) {
|
|
81
|
+
let session = decodeSessionToken(params.token);
|
|
82
|
+
if (!session) {
|
|
83
|
+
throw new Error('KsefHttpClient.fetchInvoices: invalid session token — expected the opaque ' +
|
|
84
|
+
'string returned by initSession() (format `v1||access||refresh||validUntil||ref`), ' +
|
|
85
|
+
'not a raw KSeF or JWT token');
|
|
86
|
+
}
|
|
87
|
+
if (shouldRefresh(session)) {
|
|
88
|
+
session = await withHttpRetry(() => refreshAccessToken(this.http, session), this.retryOpts);
|
|
89
|
+
}
|
|
90
|
+
const result = await withHttpRetry(() => fetchInvoicesHttp(this.http, {
|
|
91
|
+
accessToken: session.accessToken,
|
|
92
|
+
dateFrom: params.dateFrom,
|
|
93
|
+
dateTo: params.dateTo,
|
|
94
|
+
pageSize: params.pageSize,
|
|
95
|
+
pageOffset: params.pageOffset,
|
|
96
|
+
subjectType: params.subjectType ?? 'Subject2',
|
|
97
|
+
}), this.retryOpts);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
async sendInvoice() {
|
|
101
|
+
throw new Error('KsefHttpClient.sendInvoice: not implemented in HTTP client MVP — see http_plan.md §H05.5');
|
|
102
|
+
}
|
|
103
|
+
async getUpo() {
|
|
104
|
+
throw new Error('KsefHttpClient.getUpo: not implemented in HTTP client MVP');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encrypts a payload with RSA-OAEP SHA-256 using the MF public key.
|
|
3
|
+
*
|
|
4
|
+
* Accepts either:
|
|
5
|
+
* - a `-----BEGIN PUBLIC KEY-----` PEM (SubjectPublicKeyInfo), or
|
|
6
|
+
* - a `-----BEGIN CERTIFICATE-----` PEM (X.509 certificate, as returned by
|
|
7
|
+
* KSeF 2.0 `GET /security/public-key-certificates`).
|
|
8
|
+
*
|
|
9
|
+
* `node:crypto.createPublicKey` transparently handles both.
|
|
10
|
+
*/
|
|
11
|
+
export declare function rsaOaepEncrypt(plaintext: string | Uint8Array, publicKeyPemOrCert: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Builds the KSeF 2.0 encryptedToken payload for `POST /auth/ksef-token`.
|
|
14
|
+
*
|
|
15
|
+
* Format: RSA-OAEP(SHA-256) over the UTF-8 bytes of `"{ksefToken}|{timestampMs}"`,
|
|
16
|
+
* base64-encoded. `timestampMs` MUST be the integer from `timestampMs` field
|
|
17
|
+
* of the `/auth/challenge` response (Unix epoch milliseconds), passed as a
|
|
18
|
+
* decimal string. Using the sibling `timestamp` ISO string is rejected by
|
|
19
|
+
* the server (verified against `api.ksef.mf.gov.pl/v2` 2026-04-11).
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildEncryptedToken(ksefToken: string, timestampMs: string, publicKeyPemOrCert: string): string;
|
|
22
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,GAAG,UAAU,EAC9B,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAQR;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAER"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { constants, createPublicKey, publicEncrypt } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Encrypts a payload with RSA-OAEP SHA-256 using the MF public key.
|
|
4
|
+
*
|
|
5
|
+
* Accepts either:
|
|
6
|
+
* - a `-----BEGIN PUBLIC KEY-----` PEM (SubjectPublicKeyInfo), or
|
|
7
|
+
* - a `-----BEGIN CERTIFICATE-----` PEM (X.509 certificate, as returned by
|
|
8
|
+
* KSeF 2.0 `GET /security/public-key-certificates`).
|
|
9
|
+
*
|
|
10
|
+
* `node:crypto.createPublicKey` transparently handles both.
|
|
11
|
+
*/
|
|
12
|
+
export function rsaOaepEncrypt(plaintext, publicKeyPemOrCert) {
|
|
13
|
+
const key = createPublicKey(publicKeyPemOrCert);
|
|
14
|
+
const data = typeof plaintext === 'string' ? Buffer.from(plaintext, 'utf8') : Buffer.from(plaintext);
|
|
15
|
+
const encrypted = publicEncrypt({ key, padding: constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, data);
|
|
16
|
+
return encrypted.toString('base64');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Builds the KSeF 2.0 encryptedToken payload for `POST /auth/ksef-token`.
|
|
20
|
+
*
|
|
21
|
+
* Format: RSA-OAEP(SHA-256) over the UTF-8 bytes of `"{ksefToken}|{timestampMs}"`,
|
|
22
|
+
* base64-encoded. `timestampMs` MUST be the integer from `timestampMs` field
|
|
23
|
+
* of the `/auth/challenge` response (Unix epoch milliseconds), passed as a
|
|
24
|
+
* decimal string. Using the sibling `timestamp` ISO string is rejected by
|
|
25
|
+
* the server (verified against `api.ksef.mf.gov.pl/v2` 2026-04-11).
|
|
26
|
+
*/
|
|
27
|
+
export function buildEncryptedToken(ksefToken, timestampMs, publicKeyPemOrCert) {
|
|
28
|
+
return rsaOaepEncrypt(`${ksefToken}|${timestampMs}`, publicKeyPemOrCert);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEvE;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,SAA8B,EAC9B,kBAA0B;IAE1B,MAAM,GAAG,GAAG,eAAe,CAAC,kBAAkB,CAAC,CAAA;IAC/C,MAAM,IAAI,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACpG,MAAM,SAAS,GAAG,aAAa,CAC7B,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,sBAAsB,EAAE,QAAQ,EAAE,QAAQ,EAAE,EACtE,IAAI,CACL,CAAA;IACD,OAAO,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,WAAmB,EACnB,kBAA0B;IAE1B,OAAO,cAAc,CAAC,GAAG,SAAS,IAAI,WAAW,EAAE,EAAE,kBAAkB,CAAC,CAAA;AAC1E,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const ENDPOINTS: {
|
|
2
|
+
readonly production: "https://api.ksef.mf.gov.pl/v2";
|
|
3
|
+
readonly demo: "https://api-demo.ksef.mf.gov.pl/v2";
|
|
4
|
+
readonly test: "https://api-test.ksef.mf.gov.pl/v2";
|
|
5
|
+
};
|
|
6
|
+
export type KsefEnvironment = keyof typeof ENDPOINTS;
|
|
7
|
+
export declare const PATHS: {
|
|
8
|
+
readonly authChallenge: "/auth/challenge";
|
|
9
|
+
readonly authKsefToken: "/auth/ksef-token";
|
|
10
|
+
readonly authStatus: (referenceNumber: string) => string;
|
|
11
|
+
readonly authRedeem: "/auth/token/redeem";
|
|
12
|
+
readonly authRefresh: "/auth/token/refresh";
|
|
13
|
+
readonly sessionsList: "/auth/sessions";
|
|
14
|
+
readonly sessionRevokeCurrent: "/auth/sessions/current";
|
|
15
|
+
readonly sessionRevokeByRef: (referenceNumber: string) => string;
|
|
16
|
+
readonly queryMetadata: "/invoices/query/metadata";
|
|
17
|
+
readonly invoiceByKsefNumber: (ksefNumber: string) => string;
|
|
18
|
+
readonly publicKeyCertificates: "/security/public-key-certificates";
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=endpoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.d.ts","sourceRoot":"","sources":["../src/endpoints.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;CAIZ,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,SAAS,CAAA;AAapD,eAAO,MAAM,KAAK;;;2CAGc,MAAM,KAAG,MAAM;;;;;mDAMP,MAAM,KAAG,MAAM;;+CAGnB,MAAM,KAAG,MAAM;;CAGzC,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const ENDPOINTS = {
|
|
2
|
+
production: 'https://api.ksef.mf.gov.pl/v2',
|
|
3
|
+
demo: 'https://api-demo.ksef.mf.gov.pl/v2',
|
|
4
|
+
test: 'https://api-test.ksef.mf.gov.pl/v2',
|
|
5
|
+
};
|
|
6
|
+
const SAFE_REF_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
7
|
+
function assertSafeReference(value, field) {
|
|
8
|
+
if (!SAFE_REF_RE.test(value)) {
|
|
9
|
+
throw new Error(`Invalid ${field}: must match ${SAFE_REF_RE.toString()} (got: ${JSON.stringify(value)})`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
export const PATHS = {
|
|
14
|
+
authChallenge: '/auth/challenge',
|
|
15
|
+
authKsefToken: '/auth/ksef-token',
|
|
16
|
+
authStatus: (referenceNumber) => `/auth/${assertSafeReference(referenceNumber, 'referenceNumber')}`,
|
|
17
|
+
authRedeem: '/auth/token/redeem',
|
|
18
|
+
authRefresh: '/auth/token/refresh',
|
|
19
|
+
sessionsList: '/auth/sessions',
|
|
20
|
+
sessionRevokeCurrent: '/auth/sessions/current',
|
|
21
|
+
sessionRevokeByRef: (referenceNumber) => `/auth/sessions/${assertSafeReference(referenceNumber, 'referenceNumber')}`,
|
|
22
|
+
queryMetadata: '/invoices/query/metadata',
|
|
23
|
+
invoiceByKsefNumber: (ksefNumber) => `/invoices/ksef/${assertSafeReference(ksefNumber, 'ksefNumber')}`,
|
|
24
|
+
publicKeyCertificates: '/security/public-key-certificates',
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.js","sourceRoot":"","sources":["../src/endpoints.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU,EAAE,+BAA+B;IAC3C,IAAI,EAAE,oCAAoC;IAC1C,IAAI,EAAE,oCAAoC;CAClC,CAAA;AAIV,MAAM,WAAW,GAAG,wBAAwB,CAAA;AAE5C,SAAS,mBAAmB,CAAC,KAAa,EAAE,KAAa;IACvD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,WAAW,KAAK,gBAAgB,WAAW,CAAC,QAAQ,EAAE,UAAU,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CACzF,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,aAAa,EAAE,iBAAiB;IAChC,aAAa,EAAE,kBAAkB;IACjC,UAAU,EAAE,CAAC,eAAuB,EAAU,EAAE,CAC9C,SAAS,mBAAmB,CAAC,eAAe,EAAE,iBAAiB,CAAC,EAAE;IACpE,UAAU,EAAE,oBAAoB;IAChC,WAAW,EAAE,qBAAqB;IAClC,YAAY,EAAE,gBAAgB;IAC9B,oBAAoB,EAAE,wBAAwB;IAC9C,kBAAkB,EAAE,CAAC,eAAuB,EAAU,EAAE,CACtD,kBAAkB,mBAAmB,CAAC,eAAe,EAAE,iBAAiB,CAAC,EAAE;IAC7E,aAAa,EAAE,0BAA0B;IACzC,mBAAmB,EAAE,CAAC,UAAkB,EAAU,EAAE,CAClD,kBAAkB,mBAAmB,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE;IACnE,qBAAqB,EAAE,mCAAmC;CAClD,CAAA"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { KsefApiError as SharedKsefApiError } from '@ksefnik/shared';
|
|
2
|
+
export declare class KsefApiError extends SharedKsefApiError {
|
|
3
|
+
readonly requestId?: string | undefined;
|
|
4
|
+
readonly detailCode?: string | undefined;
|
|
5
|
+
constructor(message: string, statusCode?: number, requestId?: string | undefined, detailCode?: string | undefined, context?: Record<string, unknown>);
|
|
6
|
+
}
|
|
7
|
+
export declare class KsefAuthError extends KsefApiError {
|
|
8
|
+
constructor(message: string, statusCode: number, requestId?: string, detailCode?: string, context?: Record<string, unknown>);
|
|
9
|
+
}
|
|
10
|
+
export declare class KsefRateLimitError extends KsefApiError {
|
|
11
|
+
readonly retryAfter: number;
|
|
12
|
+
constructor(message: string, retryAfter: number, requestId?: string, context?: Record<string, unknown>);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpE,qBAAa,YAAa,SAAQ,kBAAkB;aAIhC,SAAS,CAAC,EAAE,MAAM;aAClB,UAAU,CAAC,EAAE,MAAM;gBAHnC,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EACH,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,UAAU,CAAC,EAAE,MAAM,YAAA,EACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED,qBAAa,aAAc,SAAQ,YAAY;gBAE3C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC;AAED,qBAAa,kBAAmB,SAAQ,YAAY;aAGhC,UAAU,EAAE,MAAM;gBADlC,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClC,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAKpC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { KsefApiError as SharedKsefApiError } from '@ksefnik/shared';
|
|
2
|
+
export class KsefApiError extends SharedKsefApiError {
|
|
3
|
+
requestId;
|
|
4
|
+
detailCode;
|
|
5
|
+
constructor(message, statusCode, requestId, detailCode, context) {
|
|
6
|
+
super(message, statusCode, context);
|
|
7
|
+
this.requestId = requestId;
|
|
8
|
+
this.detailCode = detailCode;
|
|
9
|
+
this.name = 'KsefApiError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class KsefAuthError extends KsefApiError {
|
|
13
|
+
constructor(message, statusCode, requestId, detailCode, context) {
|
|
14
|
+
super(message, statusCode, requestId, detailCode, context);
|
|
15
|
+
this.name = 'KsefAuthError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class KsefRateLimitError extends KsefApiError {
|
|
19
|
+
retryAfter;
|
|
20
|
+
constructor(message, retryAfter, requestId, context) {
|
|
21
|
+
super(message, 429, requestId, 'RATE_LIMIT', context);
|
|
22
|
+
this.retryAfter = retryAfter;
|
|
23
|
+
this.name = 'KsefRateLimitError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpE,MAAM,OAAO,YAAa,SAAQ,kBAAkB;IAIhC;IACA;IAJlB,YACE,OAAe,EACf,UAAmB,EACH,SAAkB,EAClB,UAAmB,EACnC,OAAiC;QAEjC,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;QAJnB,cAAS,GAAT,SAAS,CAAS;QAClB,eAAU,GAAV,UAAU,CAAS;QAInC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAA;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,YAAY;IAC7C,YACE,OAAe,EACf,UAAkB,EAClB,SAAkB,EAClB,UAAmB,EACnB,OAAiC;QAEjC,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;QAC1D,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAGhC;IAFlB,YACE,OAAe,EACC,UAAkB,EAClC,SAAkB,EAClB,OAAiC;QAEjC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;QAJrC,eAAU,GAAV,UAAU,CAAQ;QAKlC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports from the openapi-typescript generated file. Consumers should
|
|
3
|
+
* import named type aliases from here rather than reaching into the raw
|
|
4
|
+
* `components["schemas"][...]` tree.
|
|
5
|
+
*
|
|
6
|
+
* Regenerate with: `pnpm --filter @ksefnik/http generate`
|
|
7
|
+
* Source of truth: https://api.ksef.mf.gov.pl/docs/v2/openapi.json
|
|
8
|
+
*/
|
|
9
|
+
import type { components } from './ksef-api.js';
|
|
10
|
+
type Schemas = components['schemas'];
|
|
11
|
+
export type KsefAuthenticationChallengeResponse = Schemas['AuthenticationChallengeResponse'];
|
|
12
|
+
export type KsefInitTokenAuthenticationRequest = Schemas['InitTokenAuthenticationRequest'];
|
|
13
|
+
export type KsefAuthenticationInitResponse = Schemas['AuthenticationInitResponse'];
|
|
14
|
+
export type KsefAuthenticationOperationStatusResponse = Schemas['AuthenticationOperationStatusResponse'];
|
|
15
|
+
export type KsefAuthenticationTokensResponse = Schemas['AuthenticationTokensResponse'];
|
|
16
|
+
export type KsefAuthenticationTokenRefreshResponse = Schemas['AuthenticationTokenRefreshResponse'];
|
|
17
|
+
export type KsefTokenInfo = Schemas['TokenInfo'];
|
|
18
|
+
export type KsefAuthenticationContextIdentifier = Schemas['AuthenticationContextIdentifier'];
|
|
19
|
+
export type KsefAuthenticationContextIdentifierType = Schemas['AuthenticationContextIdentifierType'];
|
|
20
|
+
export type KsefPublicKeyCertificate = Schemas['PublicKeyCertificate'];
|
|
21
|
+
export type KsefPublicKeyCertificateUsage = Schemas['PublicKeyCertificateUsage'];
|
|
22
|
+
export type KsefInvoiceQueryFilters = Schemas['InvoiceQueryFilters'];
|
|
23
|
+
export type KsefInvoiceQuerySubjectType = Schemas['InvoiceQuerySubjectType'];
|
|
24
|
+
export type KsefInvoiceQueryDateType = Schemas['InvoiceQueryDateType'];
|
|
25
|
+
export type KsefQueryInvoicesMetadataResponse = Schemas['QueryInvoicesMetadataResponse'];
|
|
26
|
+
export type KsefInvoiceMetadata = Schemas['InvoiceMetadata'];
|
|
27
|
+
export type KsefInvoiceMetadataBuyer = Schemas['InvoiceMetadataBuyer'];
|
|
28
|
+
export type KsefInvoiceMetadataSeller = Schemas['InvoiceMetadataSeller'];
|
|
29
|
+
export type { components, paths, operations } from './ksef-api.js';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generated/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,KAAK,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;AAGpC,MAAM,MAAM,mCAAmC,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAAA;AAC5F,MAAM,MAAM,kCAAkC,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAAA;AAC1F,MAAM,MAAM,8BAA8B,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAA;AAClF,MAAM,MAAM,yCAAyC,GAAG,OAAO,CAAC,uCAAuC,CAAC,CAAA;AACxG,MAAM,MAAM,gCAAgC,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAA;AACtF,MAAM,MAAM,sCAAsC,GAAG,OAAO,CAAC,oCAAoC,CAAC,CAAA;AAClG,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;AAChD,MAAM,MAAM,mCAAmC,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAAA;AAC5F,MAAM,MAAM,uCAAuC,GAAG,OAAO,CAAC,qCAAqC,CAAC,CAAA;AAGpG,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;AACtE,MAAM,MAAM,6BAA6B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAA;AAGhF,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;AACpE,MAAM,MAAM,2BAA2B,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAA;AAC5E,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;AACtE,MAAM,MAAM,iCAAiC,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAA;AACxF,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;AAC5D,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;AACtE,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;AAGxE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generated/index.ts"],"names":[],"mappings":""}
|