@fast-white-cat/integration-ksef-direct 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.
Files changed (140) hide show
  1. package/README.md +36 -0
  2. package/dist/index.js +2 -0
  3. package/dist/index.js.map +7 -0
  4. package/dist/modules/integration_ksef_direct/acl.js +13 -0
  5. package/dist/modules/integration_ksef_direct/acl.js.map +7 -0
  6. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents/[id].js +92 -0
  7. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents/[id].js.map +7 -0
  8. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents.js +105 -0
  9. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents.js.map +7 -0
  10. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/health.js +158 -0
  11. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/health.js.map +7 -0
  12. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents/[id].js +86 -0
  13. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents/[id].js.map +7 -0
  14. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents.js +112 -0
  15. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents.js.map +7 -0
  16. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/seller-info.js +54 -0
  17. package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/seller-info.js.map +7 -0
  18. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents/[id]/send.js +64 -0
  19. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents/[id]/send.js.map +7 -0
  20. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents.js +104 -0
  21. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents.js.map +7 -0
  22. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/invoice-numbers.js +41 -0
  23. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/invoice-numbers.js.map +7 -0
  24. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/fetch.js +172 -0
  25. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/fetch.js.map +7 -0
  26. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/sync.js +80 -0
  27. package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/sync.js.map +7 -0
  28. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.js +441 -0
  29. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.js.map +7 -0
  30. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.meta.js +8 -0
  31. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.meta.js.map +7 -0
  32. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/page.js +193 -0
  33. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/page.js.map +7 -0
  34. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/received-documents/page.js +314 -0
  35. package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/received-documents/page.js.map +7 -0
  36. package/dist/modules/integration_ksef_direct/backend/page.js +154 -0
  37. package/dist/modules/integration_ksef_direct/backend/page.js.map +7 -0
  38. package/dist/modules/integration_ksef_direct/commands/create-ksef-direct-document.js +80 -0
  39. package/dist/modules/integration_ksef_direct/commands/create-ksef-direct-document.js.map +7 -0
  40. package/dist/modules/integration_ksef_direct/commands/enqueue-ksef-direct-document.js +43 -0
  41. package/dist/modules/integration_ksef_direct/commands/enqueue-ksef-direct-document.js.map +7 -0
  42. package/dist/modules/integration_ksef_direct/data/entities.js +224 -0
  43. package/dist/modules/integration_ksef_direct/data/entities.js.map +7 -0
  44. package/dist/modules/integration_ksef_direct/data/validators.js +103 -0
  45. package/dist/modules/integration_ksef_direct/data/validators.js.map +7 -0
  46. package/dist/modules/integration_ksef_direct/di.js +11 -0
  47. package/dist/modules/integration_ksef_direct/di.js.map +7 -0
  48. package/dist/modules/integration_ksef_direct/events.js +21 -0
  49. package/dist/modules/integration_ksef_direct/events.js.map +7 -0
  50. package/dist/modules/integration_ksef_direct/index.js +10 -0
  51. package/dist/modules/integration_ksef_direct/index.js.map +7 -0
  52. package/dist/modules/integration_ksef_direct/integration.js +56 -0
  53. package/dist/modules/integration_ksef_direct/integration.js.map +7 -0
  54. package/dist/modules/integration_ksef_direct/lib/health.js +32 -0
  55. package/dist/modules/integration_ksef_direct/lib/health.js.map +7 -0
  56. package/dist/modules/integration_ksef_direct/lib/invoiceNumberFormat.js +23 -0
  57. package/dist/modules/integration_ksef_direct/lib/invoiceNumberFormat.js.map +7 -0
  58. package/dist/modules/integration_ksef_direct/lib/ksefClient.js +523 -0
  59. package/dist/modules/integration_ksef_direct/lib/ksefClient.js.map +7 -0
  60. package/dist/modules/integration_ksef_direct/lib/ksefCrypto.js +103 -0
  61. package/dist/modules/integration_ksef_direct/lib/ksefCrypto.js.map +7 -0
  62. package/dist/modules/integration_ksef_direct/lib/ksefFa2Xml.js +123 -0
  63. package/dist/modules/integration_ksef_direct/lib/ksefFa2Xml.js.map +7 -0
  64. package/dist/modules/integration_ksef_direct/lib/ksefXmlParser.js +76 -0
  65. package/dist/modules/integration_ksef_direct/lib/ksefXmlParser.js.map +7 -0
  66. package/dist/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.js +15 -0
  67. package/dist/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.js.map +7 -0
  68. package/dist/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.js +17 -0
  69. package/dist/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.js.map +7 -0
  70. package/dist/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.js +15 -0
  71. package/dist/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.js.map +7 -0
  72. package/dist/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.js +17 -0
  73. package/dist/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.js.map +7 -0
  74. package/dist/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.js +16 -0
  75. package/dist/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.js.map +7 -0
  76. package/dist/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.js +15 -0
  77. package/dist/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.js.map +7 -0
  78. package/dist/modules/integration_ksef_direct/setup.js +11 -0
  79. package/dist/modules/integration_ksef_direct/setup.js.map +7 -0
  80. package/dist/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.js +19 -0
  81. package/dist/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.js.map +7 -0
  82. package/dist/modules/integration_ksef_direct/workers/check-ksef-document-status.js +103 -0
  83. package/dist/modules/integration_ksef_direct/workers/check-ksef-document-status.js.map +7 -0
  84. package/dist/modules/integration_ksef_direct/workers/send-ksef-document.js +104 -0
  85. package/dist/modules/integration_ksef_direct/workers/send-ksef-document.js.map +7 -0
  86. package/dist/modules/integration_ksef_direct/workers/sync-received-documents.js +137 -0
  87. package/dist/modules/integration_ksef_direct/workers/sync-received-documents.js.map +7 -0
  88. package/dist/types/declarations.d.js +1 -0
  89. package/dist/types/declarations.d.js.map +7 -0
  90. package/package.json +98 -0
  91. package/src/index.ts +1 -0
  92. package/src/modules/integration_ksef_direct/__tests__/invoiceNumberFormat.test.ts +42 -0
  93. package/src/modules/integration_ksef_direct/__tests__/ksefFa2Xml.test.ts +407 -0
  94. package/src/modules/integration_ksef_direct/__tests__/ksefXmlParser.test.ts +230 -0
  95. package/src/modules/integration_ksef_direct/acl.ts +9 -0
  96. package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents/[id].ts +94 -0
  97. package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents.ts +111 -0
  98. package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/health.ts +194 -0
  99. package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents/[id].ts +88 -0
  100. package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents.ts +119 -0
  101. package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/seller-info.ts +62 -0
  102. package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents/[id]/send.ts +64 -0
  103. package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents.ts +109 -0
  104. package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/invoice-numbers.ts +40 -0
  105. package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/fetch.ts +185 -0
  106. package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/sync.ts +86 -0
  107. package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.meta.ts +4 -0
  108. package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.tsx +470 -0
  109. package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/page.tsx +233 -0
  110. package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/received-documents/page.tsx +415 -0
  111. package/src/modules/integration_ksef_direct/backend/page.tsx +183 -0
  112. package/src/modules/integration_ksef_direct/commands/create-ksef-direct-document.ts +93 -0
  113. package/src/modules/integration_ksef_direct/commands/enqueue-ksef-direct-document.ts +57 -0
  114. package/src/modules/integration_ksef_direct/data/entities.ts +195 -0
  115. package/src/modules/integration_ksef_direct/data/validators.ts +115 -0
  116. package/src/modules/integration_ksef_direct/di.ts +9 -0
  117. package/src/modules/integration_ksef_direct/events.ts +18 -0
  118. package/src/modules/integration_ksef_direct/i18n/en.json +115 -0
  119. package/src/modules/integration_ksef_direct/i18n/pl.json +115 -0
  120. package/src/modules/integration_ksef_direct/index.ts +6 -0
  121. package/src/modules/integration_ksef_direct/integration.ts +54 -0
  122. package/src/modules/integration_ksef_direct/lib/health.ts +43 -0
  123. package/src/modules/integration_ksef_direct/lib/invoiceNumberFormat.ts +23 -0
  124. package/src/modules/integration_ksef_direct/lib/ksefClient.ts +668 -0
  125. package/src/modules/integration_ksef_direct/lib/ksefCrypto.ts +138 -0
  126. package/src/modules/integration_ksef_direct/lib/ksefFa2Xml.ts +147 -0
  127. package/src/modules/integration_ksef_direct/lib/ksefXmlParser.ts +97 -0
  128. package/src/modules/integration_ksef_direct/migrations/.snapshot-open-mercato.json +1028 -0
  129. package/src/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.ts +15 -0
  130. package/src/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.ts +17 -0
  131. package/src/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.ts +15 -0
  132. package/src/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.ts +17 -0
  133. package/src/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.ts +16 -0
  134. package/src/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.ts +15 -0
  135. package/src/modules/integration_ksef_direct/setup.ts +9 -0
  136. package/src/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.ts +21 -0
  137. package/src/modules/integration_ksef_direct/workers/check-ksef-document-status.ts +129 -0
  138. package/src/modules/integration_ksef_direct/workers/send-ksef-document.ts +137 -0
  139. package/src/modules/integration_ksef_direct/workers/sync-received-documents.ts +171 -0
  140. package/src/types/declarations.d.ts +1 -0
@@ -0,0 +1,523 @@
1
+ import { z } from "zod";
2
+ import { fetchPublicKey, clearPublicKeyCache, encryptKsefToken } from "./ksefCrypto.js";
3
+ const BASE_URLS = {
4
+ test: "https://api-test.ksef.mf.gov.pl/v2",
5
+ production: "https://api.ksef.mf.gov.pl/v2"
6
+ };
7
+ const TOKEN_CACHE = /* @__PURE__ */ new Map();
8
+ const ChallengeResponseSchema = z.object({
9
+ challenge: z.string(),
10
+ timestampMs: z.number().optional()
11
+ });
12
+ const KsefTokenResponseSchema = z.object({
13
+ referenceNumber: z.string(),
14
+ authenticationToken: z.object({
15
+ token: z.string(),
16
+ validUntil: z.string().optional()
17
+ })
18
+ });
19
+ const AuthStatusSchema = z.object({
20
+ status: z.object({
21
+ code: z.number(),
22
+ description: z.string().optional()
23
+ })
24
+ });
25
+ const RedeemResponseSchema = z.object({
26
+ sessionToken: z.object({
27
+ token: z.string(),
28
+ generatedAt: z.string().optional(),
29
+ validUntil: z.string().optional()
30
+ }).optional(),
31
+ accessToken: z.object({
32
+ token: z.string(),
33
+ validUntil: z.string().optional()
34
+ }).optional(),
35
+ refreshToken: z.object({
36
+ token: z.string(),
37
+ validUntil: z.string().optional()
38
+ }).optional()
39
+ }).passthrough();
40
+ const RateLimitsSchema = z.object({
41
+ otherPerSecond: z.number().optional(),
42
+ otherPerMinute: z.number().optional()
43
+ });
44
+ function cacheKey(credentials) {
45
+ return `${credentials.environment}:${credentials.tenantId ?? ""}:${credentials.nip}`;
46
+ }
47
+ async function ksefFetch(url, options) {
48
+ const response = await fetch(url, {
49
+ ...options,
50
+ signal: AbortSignal.timeout(15e3)
51
+ });
52
+ if (response.status === 429) {
53
+ const retryAfter = response.headers.get("Retry-After");
54
+ const waitMs = Math.min(retryAfter ? parseInt(retryAfter, 10) * 1e3 : 2e3, 1e4);
55
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
56
+ return fetch(url, { ...options, signal: AbortSignal.timeout(15e3) });
57
+ }
58
+ return response;
59
+ }
60
+ async function getValidAccessToken(credentials) {
61
+ const key = cacheKey(credentials);
62
+ const cached = TOKEN_CACHE.get(key);
63
+ const now = /* @__PURE__ */ new Date();
64
+ if (cached) {
65
+ const refreshThreshold = new Date(cached.accessTokenExp.getTime() - 2 * 60 * 1e3);
66
+ if (now < refreshThreshold) {
67
+ return cached.accessToken;
68
+ }
69
+ if (now < cached.refreshTokenExp) {
70
+ const newAccessToken = await refreshAccessToken(cached.refreshToken, credentials.environment);
71
+ TOKEN_CACHE.set(key, {
72
+ ...cached,
73
+ accessToken: newAccessToken,
74
+ accessTokenExp: new Date(Date.now() + 14 * 60 * 1e3)
75
+ });
76
+ return newAccessToken;
77
+ }
78
+ }
79
+ return authenticate(credentials);
80
+ }
81
+ async function authenticate(credentials) {
82
+ const baseUrl = BASE_URLS[credentials.environment];
83
+ const publicKeyPem = await fetchPublicKey(credentials.environment);
84
+ const challengeRes = await ksefFetch(`${baseUrl}/auth/challenge`, {
85
+ method: "POST",
86
+ headers: { "Content-Type": "application/json" },
87
+ body: JSON.stringify({})
88
+ });
89
+ if (!challengeRes.ok) {
90
+ throw new KsefAuthError(`Challenge request failed: HTTP ${challengeRes.status}`, "AUTH_CHALLENGE_FAILED");
91
+ }
92
+ const challengeData = ChallengeResponseSchema.parse(await challengeRes.json());
93
+ const timestampMs = challengeData.timestampMs ?? Date.now();
94
+ let encryptedToken;
95
+ try {
96
+ encryptedToken = encryptKsefToken(credentials.ksefToken, timestampMs, publicKeyPem);
97
+ } catch {
98
+ clearPublicKeyCache(credentials.environment);
99
+ const freshKey = await fetchPublicKey(credentials.environment);
100
+ encryptedToken = encryptKsefToken(credentials.ksefToken, timestampMs, freshKey);
101
+ }
102
+ const ksefTokenRes = await ksefFetch(`${baseUrl}/auth/ksef-token`, {
103
+ method: "POST",
104
+ headers: { "Content-Type": "application/json" },
105
+ body: JSON.stringify({
106
+ challenge: challengeData.challenge,
107
+ contextIdentifier: { type: "nip", value: credentials.nip },
108
+ encryptedToken
109
+ })
110
+ });
111
+ if (!ksefTokenRes.ok) {
112
+ const body = await ksefTokenRes.text().catch(() => "");
113
+ throw new KsefAuthError(
114
+ `KSeF token submission failed: HTTP ${ksefTokenRes.status}${body ? ` \u2014 ${body}` : ""}`,
115
+ ksefTokenRes.status === 401 ? "AUTH_FAILED" : "AUTH_KSEF_TOKEN_FAILED"
116
+ );
117
+ }
118
+ const tokenData = KsefTokenResponseSchema.parse(await ksefTokenRes.json());
119
+ const authToken = tokenData.authenticationToken.token;
120
+ const authStatusData = await pollAuthStatus(baseUrl, tokenData.referenceNumber, authToken);
121
+ if (!authStatusData) {
122
+ throw new KsefAuthError("Authentication timed out waiting for KSeF status", "AUTH_TIMEOUT");
123
+ }
124
+ const redeemRes = await ksefFetch(`${baseUrl}/auth/token/redeem`, {
125
+ method: "POST",
126
+ headers: {
127
+ "Content-Type": "application/json",
128
+ "Authorization": `Bearer ${authToken}`
129
+ },
130
+ body: JSON.stringify({})
131
+ });
132
+ if (!redeemRes.ok) {
133
+ const body = await redeemRes.text().catch(() => "");
134
+ throw new KsefAuthError(`Token redeem failed: HTTP ${redeemRes.status}${body ? ` \u2014 ${body}` : ""}`, "AUTH_REDEEM_FAILED");
135
+ }
136
+ const redeemRaw = await redeemRes.json();
137
+ const redeemData = RedeemResponseSchema.parse(redeemRaw);
138
+ const sessionTokenObj = redeemData.sessionToken ?? redeemData.accessToken;
139
+ if (!sessionTokenObj) {
140
+ throw new KsefAuthError(
141
+ `Unexpected redeem response shape: ${JSON.stringify(redeemRaw)}`,
142
+ "AUTH_REDEEM_FAILED"
143
+ );
144
+ }
145
+ const accessToken = sessionTokenObj.token;
146
+ const refreshTokenValue = redeemData.refreshToken?.token ?? accessToken;
147
+ const refreshTokenExp = redeemData.refreshToken?.validUntil ? new Date(redeemData.refreshToken.validUntil) : new Date(Date.now() + 60 * 60 * 1e3);
148
+ const accessTokenExp = sessionTokenObj.validUntil ? new Date(sessionTokenObj.validUntil) : new Date(Date.now() + 14 * 60 * 1e3);
149
+ TOKEN_CACHE.set(cacheKey(credentials), {
150
+ accessToken,
151
+ accessTokenExp,
152
+ refreshToken: refreshTokenValue,
153
+ refreshTokenExp
154
+ });
155
+ return accessToken;
156
+ }
157
+ async function pollAuthStatus(baseUrl, referenceNumber, authToken) {
158
+ const deadline = Date.now() + 3e4;
159
+ let delay = 1e3;
160
+ while (Date.now() < deadline) {
161
+ await new Promise((resolve) => setTimeout(resolve, delay));
162
+ delay = Math.min(delay * 1.5, 5e3);
163
+ const res = await ksefFetch(`${baseUrl}/auth/${referenceNumber}`, {
164
+ method: "GET",
165
+ headers: {
166
+ "Accept": "application/json",
167
+ "Authorization": `Bearer ${authToken}`
168
+ }
169
+ });
170
+ if (res.ok) {
171
+ const data = AuthStatusSchema.safeParse(await res.json());
172
+ if (data.success) {
173
+ const code = data.data.status.code;
174
+ if (code === 200) return true;
175
+ if (code >= 400) {
176
+ throw new KsefAuthError(
177
+ `KSeF authentication failed: ${data.data.status.description ?? `status ${code}`}`,
178
+ "AUTH_FAILED"
179
+ );
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return false;
185
+ }
186
+ async function refreshAccessToken(refreshToken, environment) {
187
+ const baseUrl = BASE_URLS[environment];
188
+ const res = await ksefFetch(`${baseUrl}/auth/token/refresh`, {
189
+ method: "POST",
190
+ headers: {
191
+ "Content-Type": "application/json",
192
+ "Authorization": `Bearer ${refreshToken}`
193
+ },
194
+ body: JSON.stringify({})
195
+ });
196
+ if (!res.ok) {
197
+ throw new KsefAuthError(`Token refresh failed: HTTP ${res.status}`, "AUTH_REFRESH_FAILED");
198
+ }
199
+ const raw = await res.json();
200
+ const data = RedeemResponseSchema.parse(raw);
201
+ const token = data.sessionToken?.token ?? data.accessToken?.token;
202
+ if (!token) throw new KsefAuthError("Unexpected refresh response shape", "AUTH_REFRESH_FAILED");
203
+ return token;
204
+ }
205
+ async function verifyAccess(credentials) {
206
+ const baseUrl = BASE_URLS[credentials.environment];
207
+ const key = cacheKey(credentials);
208
+ let accessToken;
209
+ try {
210
+ accessToken = await getValidAccessToken(credentials);
211
+ } catch (err) {
212
+ TOKEN_CACHE.delete(key);
213
+ throw err;
214
+ }
215
+ const res = await ksefFetch(`${baseUrl}/rate-limits`, {
216
+ method: "GET",
217
+ headers: {
218
+ "Accept": "application/json",
219
+ "Authorization": `Bearer ${accessToken}`
220
+ }
221
+ });
222
+ if (res.status === 401) {
223
+ TOKEN_CACHE.delete(key);
224
+ const freshToken = await authenticate(credentials);
225
+ const retryRes = await ksefFetch(`${baseUrl}/rate-limits`, {
226
+ method: "GET",
227
+ headers: {
228
+ "Accept": "application/json",
229
+ "Authorization": `Bearer ${freshToken}`
230
+ }
231
+ });
232
+ if (!retryRes.ok) {
233
+ throw new KsefNetworkError(`Rate limits check failed after re-auth: HTTP ${retryRes.status}`);
234
+ }
235
+ const parsed2 = RateLimitsSchema.safeParse(await retryRes.json());
236
+ return parsed2.success ? parsed2.data : {};
237
+ }
238
+ if (!res.ok) {
239
+ throw new KsefNetworkError(`Rate limits check failed: HTTP ${res.status}`);
240
+ }
241
+ const parsed = RateLimitsSchema.safeParse(await res.json());
242
+ return parsed.success ? parsed.data : {};
243
+ }
244
+ function clearTokenCache(tenantKey) {
245
+ if (tenantKey) {
246
+ TOKEN_CACHE.delete(tenantKey);
247
+ } else {
248
+ TOKEN_CACHE.clear();
249
+ }
250
+ }
251
+ class KsefAuthError extends Error {
252
+ constructor(message, errorCode) {
253
+ super(message);
254
+ this.name = "KsefAuthError";
255
+ this.errorCode = errorCode;
256
+ }
257
+ }
258
+ class KsefNetworkError extends Error {
259
+ constructor(message) {
260
+ super(message);
261
+ this.errorCode = "NETWORK_ERROR";
262
+ this.name = "KsefNetworkError";
263
+ }
264
+ }
265
+ const OpenSessionResponseSchema = z.object({
266
+ referenceNumber: z.string(),
267
+ validUntil: z.string()
268
+ });
269
+ const SendInvoiceToSessionResponseSchema = z.object({
270
+ referenceNumber: z.string()
271
+ });
272
+ const SessionStatusResponseSchema = z.object({
273
+ status: z.object({
274
+ code: z.number(),
275
+ description: z.string(),
276
+ details: z.array(z.string()).optional().nullable()
277
+ }),
278
+ successfulInvoiceCount: z.number().optional().nullable(),
279
+ failedInvoiceCount: z.number().optional().nullable()
280
+ }).passthrough();
281
+ async function sendInvoice(credentials, payload) {
282
+ const baseUrl = BASE_URLS[credentials.environment];
283
+ const accessToken = await getValidAccessToken(credentials);
284
+ const openRes = await ksefFetch(`${baseUrl}/sessions/online`, {
285
+ method: "POST",
286
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${accessToken}` },
287
+ body: JSON.stringify({
288
+ formCode: { systemCode: "FA (2)", schemaVersion: "1-0E", value: "FA" },
289
+ encryption: {
290
+ encryptedSymmetricKey: payload.encryptedSymmetricKey,
291
+ initializationVector: payload.initializationVector,
292
+ ...payload.publicKeyId ? { publicKeyId: payload.publicKeyId } : {}
293
+ }
294
+ })
295
+ });
296
+ if (!openRes.ok) {
297
+ const body = await openRes.text().catch(() => "");
298
+ throw new KsefNetworkError(`Session open failed: HTTP ${openRes.status}${body ? ` \u2014 ${body}` : ""}`);
299
+ }
300
+ const openData = OpenSessionResponseSchema.parse(await openRes.json());
301
+ const sessionReferenceNumber = openData.referenceNumber;
302
+ let invoiceReferenceNumber;
303
+ try {
304
+ const sendRes = await ksefFetch(
305
+ `${baseUrl}/sessions/online/${encodeURIComponent(sessionReferenceNumber)}/invoices`,
306
+ {
307
+ method: "POST",
308
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${accessToken}` },
309
+ body: JSON.stringify({
310
+ invoiceHash: payload.invoiceHash,
311
+ invoiceSize: payload.invoiceSize,
312
+ encryptedInvoiceHash: payload.encryptedInvoiceHash,
313
+ encryptedInvoiceSize: payload.encryptedInvoiceSize,
314
+ encryptedInvoiceContent: payload.encryptedInvoiceContent
315
+ })
316
+ }
317
+ );
318
+ if (!sendRes.ok) {
319
+ const body = await sendRes.text().catch(() => "");
320
+ throw new KsefNetworkError(`Invoice send failed: HTTP ${sendRes.status}${body ? ` \u2014 ${body}` : ""}`);
321
+ }
322
+ const sendData = SendInvoiceToSessionResponseSchema.parse(await sendRes.json());
323
+ invoiceReferenceNumber = sendData.referenceNumber;
324
+ } catch (err) {
325
+ await ksefFetch(
326
+ `${baseUrl}/sessions/online/${encodeURIComponent(sessionReferenceNumber)}/close`,
327
+ { method: "POST", headers: { "Authorization": `Bearer ${accessToken}` } }
328
+ ).catch(() => {
329
+ });
330
+ throw err;
331
+ }
332
+ const closeRes = await ksefFetch(
333
+ `${baseUrl}/sessions/online/${encodeURIComponent(sessionReferenceNumber)}/close`,
334
+ { method: "POST", headers: { "Authorization": `Bearer ${accessToken}` } }
335
+ );
336
+ return { sessionReferenceNumber, invoiceReferenceNumber };
337
+ }
338
+ const SessionListResponseSchema = z.object({
339
+ sessions: z.array(z.object({
340
+ referenceNumber: z.string()
341
+ }).passthrough()).default([]),
342
+ continuationToken: z.string().nullable().optional()
343
+ }).passthrough();
344
+ const SessionInvoiceItemSchema = z.object({
345
+ referenceNumber: z.string().optional(),
346
+ ksefNumber: z.string().optional(),
347
+ ksefReferenceNumber: z.string().optional(),
348
+ issueDate: z.string().nullable().optional(),
349
+ subjectBy: z.object({
350
+ identifier: z.object({
351
+ type: z.string().optional(),
352
+ identifier: z.string().optional()
353
+ }).optional(),
354
+ name: z.string().optional()
355
+ }).passthrough().optional(),
356
+ grossAmount: z.union([z.string(), z.number()]).nullable().optional(),
357
+ netAmount: z.union([z.string(), z.number()]).nullable().optional(),
358
+ vatAmount: z.union([z.string(), z.number()]).nullable().optional(),
359
+ currency: z.string().nullable().optional(),
360
+ invoiceNumber: z.string().nullable().optional(),
361
+ upoDownloadUrl: z.string().nullable().optional(),
362
+ invoiceDownloadUrl: z.string().nullable().optional()
363
+ }).passthrough();
364
+ const SessionInvoiceListResponseSchema = z.object({
365
+ invoices: z.array(SessionInvoiceItemSchema).default([]),
366
+ continuationToken: z.string().nullable().optional()
367
+ }).passthrough();
368
+ async function fetchAllSessionInvoices(baseUrl, accessToken, sessionRef) {
369
+ const results = [];
370
+ let continuationToken = void 0;
371
+ let isFirst = true;
372
+ while (isFirst || continuationToken) {
373
+ isFirst = false;
374
+ const url = new URL(`${baseUrl}/sessions/${encodeURIComponent(sessionRef)}/invoices`);
375
+ if (continuationToken) url.searchParams.set("continuationToken", continuationToken);
376
+ const res = await ksefFetch(url.toString(), {
377
+ method: "GET",
378
+ headers: { "Accept": "application/json", "Authorization": `Bearer ${accessToken}` }
379
+ });
380
+ if (!res.ok) break;
381
+ const data = SessionInvoiceListResponseSchema.parse(await res.json());
382
+ continuationToken = data.continuationToken ?? null;
383
+ for (const inv of data.invoices) {
384
+ const ksefRef = inv.ksefNumber ?? inv.ksefReferenceNumber;
385
+ if (!ksefRef) continue;
386
+ const grossRaw = inv.grossAmount;
387
+ const netRaw = inv.netAmount;
388
+ const vatRaw = inv.vatAmount;
389
+ results.push({
390
+ ksefReferenceNumber: ksefRef,
391
+ sessionReferenceNumber: sessionRef,
392
+ issueDate: inv.issueDate ?? null,
393
+ sellerNip: inv.subjectBy?.identifier?.identifier ?? null,
394
+ sellerName: inv.subjectBy?.name ?? null,
395
+ grossAmount: grossRaw != null ? String(grossRaw) : null,
396
+ netAmount: netRaw != null ? String(netRaw) : null,
397
+ vatAmount: vatRaw != null ? String(vatRaw) : null,
398
+ currency: inv.currency ?? null,
399
+ invoiceNumber: inv.invoiceNumber ?? null,
400
+ upoDownloadUrl: inv.upoDownloadUrl ?? null,
401
+ invoiceDownloadUrl: inv.invoiceDownloadUrl ?? null
402
+ });
403
+ }
404
+ if (!continuationToken) break;
405
+ }
406
+ return results;
407
+ }
408
+ async function queryReceivedInvoices(credentials, params) {
409
+ const baseUrl = BASE_URLS[credentials.environment];
410
+ const accessToken = await getValidAccessToken(credentials);
411
+ const allItems = [];
412
+ let continuationToken = void 0;
413
+ let isFirst = true;
414
+ while (isFirst || continuationToken) {
415
+ isFirst = false;
416
+ const sessionUrl = new URL(`${baseUrl}/sessions`);
417
+ sessionUrl.searchParams.set("sessionType", "online");
418
+ sessionUrl.searchParams.set("direction", "received");
419
+ sessionUrl.searchParams.set("dateFrom", params.dateFrom);
420
+ sessionUrl.searchParams.set("dateTo", params.dateTo);
421
+ if (continuationToken) sessionUrl.searchParams.set("continuationToken", continuationToken);
422
+ const res = await ksefFetch(sessionUrl.toString(), {
423
+ method: "GET",
424
+ headers: { "Accept": "application/json", "Authorization": `Bearer ${accessToken}` }
425
+ });
426
+ if (!res.ok) {
427
+ const body = await res.text().catch(() => "");
428
+ throw new KsefNetworkError(`Query received sessions failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
429
+ }
430
+ const sessionData = SessionListResponseSchema.parse(await res.json());
431
+ continuationToken = sessionData.continuationToken ?? null;
432
+ for (const session of sessionData.sessions) {
433
+ const invoices = await fetchAllSessionInvoices(baseUrl, accessToken, session.referenceNumber);
434
+ allItems.push(...invoices);
435
+ }
436
+ if (!continuationToken) break;
437
+ }
438
+ return { items: allItems, totalCount: allItems.length };
439
+ }
440
+ async function downloadFromUrl(url) {
441
+ const res = await fetch(url, {
442
+ method: "GET",
443
+ signal: AbortSignal.timeout(3e4)
444
+ });
445
+ if (!res.ok) {
446
+ const body = await res.text().catch(() => "");
447
+ throw new KsefNetworkError(`Invoice download failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
448
+ }
449
+ return res.text();
450
+ }
451
+ async function downloadInvoiceFromUrl(url) {
452
+ return downloadFromUrl(url);
453
+ }
454
+ async function downloadInvoice(credentials, ksefReferenceNumber) {
455
+ const baseUrl = BASE_URLS[credentials.environment];
456
+ const accessToken = await getValidAccessToken(credentials);
457
+ const res = await ksefFetch(`${baseUrl}/invoices/ksef/${encodeURIComponent(ksefReferenceNumber)}`, {
458
+ method: "GET",
459
+ headers: { "Accept": "application/octet-stream", "Authorization": `Bearer ${accessToken}` }
460
+ });
461
+ if (!res.ok) {
462
+ const body = await res.text().catch(() => "");
463
+ throw new KsefNetworkError(`Invoice fetch failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
464
+ }
465
+ const contentType = res.headers.get("content-type") ?? "";
466
+ let rawContent;
467
+ if (contentType.includes("application/json")) {
468
+ const data = await res.json();
469
+ const downloadUrl = data["invoiceDownloadUrl"] ?? data["downloadUrl"] ?? data["url"];
470
+ if (downloadUrl) {
471
+ rawContent = await downloadFromUrl(downloadUrl);
472
+ } else if (typeof data["content"] === "string") {
473
+ rawContent = data["content"];
474
+ } else {
475
+ throw new KsefNetworkError(`Unexpected JSON response from /invoices/ksef \u2014 keys: ${Object.keys(data).join(", ")}`);
476
+ }
477
+ return {
478
+ rawContent,
479
+ upoDownloadUrl: data["upoDownloadUrl"] ?? null,
480
+ invoiceDownloadUrl: data["invoiceDownloadUrl"] ?? null
481
+ };
482
+ }
483
+ rawContent = await res.text();
484
+ return { rawContent, upoDownloadUrl: null, invoiceDownloadUrl: null };
485
+ }
486
+ async function checkInvoiceStatus(credentials, referenceNumber) {
487
+ const baseUrl = BASE_URLS[credentials.environment];
488
+ const accessToken = await getValidAccessToken(credentials);
489
+ const res = await ksefFetch(`${baseUrl}/sessions/${encodeURIComponent(referenceNumber)}`, {
490
+ method: "GET",
491
+ headers: { "Accept": "application/json", "Authorization": `Bearer ${accessToken}` }
492
+ });
493
+ if (!res.ok) {
494
+ const body = await res.text().catch(() => "");
495
+ throw new KsefNetworkError(`Session status check failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ""}`);
496
+ }
497
+ const data = SessionStatusResponseSchema.parse(await res.json());
498
+ const code = data.status.code;
499
+ if (code === 200) {
500
+ if ((data.failedInvoiceCount ?? 0) > 0) {
501
+ const details = data.status.details?.join("; ") ?? "";
502
+ return { processingCode: 400, errorDescription: `KSeF rejected ${data.failedInvoiceCount} invoice(s): ${data.status.description}${details ? ` \u2014 ${details}` : ""}` };
503
+ }
504
+ return { processingCode: 200 };
505
+ }
506
+ if (code >= 400) {
507
+ const details = data.status.details?.join("; ") ?? "";
508
+ return { processingCode: code, errorDescription: `${data.status.description}${details ? ` \u2014 ${details}` : ""}` };
509
+ }
510
+ return { processingCode: 100 };
511
+ }
512
+ export {
513
+ KsefAuthError,
514
+ KsefNetworkError,
515
+ checkInvoiceStatus,
516
+ clearTokenCache,
517
+ downloadInvoice,
518
+ downloadInvoiceFromUrl,
519
+ queryReceivedInvoices,
520
+ sendInvoice,
521
+ verifyAccess
522
+ };
523
+ //# sourceMappingURL=ksefClient.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/integration_ksef_direct/lib/ksefClient.ts"],
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { fetchPublicKey, clearPublicKeyCache, encryptKsefToken } from './ksefCrypto'\n\ntype KsefEnvironment = 'test' | 'production'\n\nconst BASE_URLS: Record<KsefEnvironment, string> = {\n test: 'https://api-test.ksef.mf.gov.pl/v2',\n production: 'https://api.ksef.mf.gov.pl/v2',\n}\n\nexport interface KsefCredentials {\n ksefToken: string\n nip: string\n environment: KsefEnvironment\n tenantId?: string\n}\n\ninterface KsefTokenCache {\n accessToken: string\n accessTokenExp: Date\n refreshToken: string\n refreshTokenExp: Date\n}\n\nconst TOKEN_CACHE = new Map<string, KsefTokenCache>()\n\nconst ChallengeResponseSchema = z.object({\n challenge: z.string(),\n timestampMs: z.number().optional(),\n})\n\nconst KsefTokenResponseSchema = z.object({\n referenceNumber: z.string(),\n authenticationToken: z.object({\n token: z.string(),\n validUntil: z.string().optional(),\n }),\n})\n\nconst AuthStatusSchema = z.object({\n status: z.object({\n code: z.number(),\n description: z.string().optional(),\n }),\n})\n\nconst RedeemResponseSchema = z.object({\n sessionToken: z.object({\n token: z.string(),\n generatedAt: z.string().optional(),\n validUntil: z.string().optional(),\n }).optional(),\n accessToken: z.object({\n token: z.string(),\n validUntil: z.string().optional(),\n }).optional(),\n refreshToken: z.object({\n token: z.string(),\n validUntil: z.string().optional(),\n }).optional(),\n}).passthrough()\n\nconst RateLimitsSchema = z.object({\n otherPerSecond: z.number().optional(),\n otherPerMinute: z.number().optional(),\n})\n\nexport type KsefRateLimits = z.infer<typeof RateLimitsSchema>\n\nfunction cacheKey(credentials: KsefCredentials): string {\n return `${credentials.environment}:${credentials.tenantId ?? ''}:${credentials.nip}`\n}\n\nasync function ksefFetch(url: string, options: RequestInit): Promise<Response> {\n const response = await fetch(url, {\n ...options,\n signal: AbortSignal.timeout(15_000),\n })\n\n if (response.status === 429) {\n const retryAfter = response.headers.get('Retry-After')\n const waitMs = Math.min(retryAfter ? parseInt(retryAfter, 10) * 1000 : 2000, 10_000)\n await new Promise((resolve) => setTimeout(resolve, waitMs))\n return fetch(url, { ...options, signal: AbortSignal.timeout(15_000) })\n }\n\n return response\n}\n\nasync function getValidAccessToken(credentials: KsefCredentials): Promise<string> {\n const key = cacheKey(credentials)\n const cached = TOKEN_CACHE.get(key)\n const now = new Date()\n\n if (cached) {\n const refreshThreshold = new Date(cached.accessTokenExp.getTime() - 2 * 60 * 1000)\n if (now < refreshThreshold) {\n return cached.accessToken\n }\n\n if (now < cached.refreshTokenExp) {\n const newAccessToken = await refreshAccessToken(cached.refreshToken, credentials.environment)\n TOKEN_CACHE.set(key, {\n ...cached,\n accessToken: newAccessToken,\n accessTokenExp: new Date(Date.now() + 14 * 60 * 1000),\n })\n return newAccessToken\n }\n }\n\n return authenticate(credentials)\n}\n\nasync function authenticate(credentials: KsefCredentials): Promise<string> {\n const baseUrl = BASE_URLS[credentials.environment]\n\n const publicKeyPem = await fetchPublicKey(credentials.environment)\n\n const challengeRes = await ksefFetch(`${baseUrl}/auth/challenge`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n if (!challengeRes.ok) {\n throw new KsefAuthError(`Challenge request failed: HTTP ${challengeRes.status}`, 'AUTH_CHALLENGE_FAILED')\n }\n const challengeData = ChallengeResponseSchema.parse(await challengeRes.json())\n\n const timestampMs = challengeData.timestampMs ?? Date.now()\n let encryptedToken: string\n try {\n encryptedToken = encryptKsefToken(credentials.ksefToken, timestampMs, publicKeyPem)\n } catch {\n clearPublicKeyCache(credentials.environment)\n const freshKey = await fetchPublicKey(credentials.environment)\n encryptedToken = encryptKsefToken(credentials.ksefToken, timestampMs, freshKey)\n }\n\n const ksefTokenRes = await ksefFetch(`${baseUrl}/auth/ksef-token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n challenge: challengeData.challenge,\n contextIdentifier: { type: 'nip', value: credentials.nip },\n encryptedToken,\n }),\n })\n if (!ksefTokenRes.ok) {\n const body = await ksefTokenRes.text().catch(() => '')\n throw new KsefAuthError(\n `KSeF token submission failed: HTTP ${ksefTokenRes.status}${body ? ` \u2014 ${body}` : ''}`,\n ksefTokenRes.status === 401 ? 'AUTH_FAILED' : 'AUTH_KSEF_TOKEN_FAILED',\n )\n }\n const tokenData = KsefTokenResponseSchema.parse(await ksefTokenRes.json())\n const authToken = tokenData.authenticationToken.token\n\n const authStatusData = await pollAuthStatus(baseUrl, tokenData.referenceNumber, authToken)\n if (!authStatusData) {\n throw new KsefAuthError('Authentication timed out waiting for KSeF status', 'AUTH_TIMEOUT')\n }\n\n const redeemRes = await ksefFetch(`${baseUrl}/auth/token/redeem`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${authToken}`,\n },\n body: JSON.stringify({}),\n })\n if (!redeemRes.ok) {\n const body = await redeemRes.text().catch(() => '')\n throw new KsefAuthError(`Token redeem failed: HTTP ${redeemRes.status}${body ? ` \u2014 ${body}` : ''}`, 'AUTH_REDEEM_FAILED')\n }\n\n const redeemRaw = await redeemRes.json() as Record<string, unknown>\n const redeemData = RedeemResponseSchema.parse(redeemRaw)\n const sessionTokenObj = redeemData.sessionToken ?? redeemData.accessToken\n if (!sessionTokenObj) {\n throw new KsefAuthError(\n `Unexpected redeem response shape: ${JSON.stringify(redeemRaw)}`,\n 'AUTH_REDEEM_FAILED',\n )\n }\n const accessToken = sessionTokenObj.token\n const refreshTokenValue = redeemData.refreshToken?.token ?? accessToken\n const refreshTokenExp = redeemData.refreshToken?.validUntil\n ? new Date(redeemData.refreshToken.validUntil)\n : new Date(Date.now() + 60 * 60 * 1000)\n const accessTokenExp = sessionTokenObj.validUntil\n ? new Date(sessionTokenObj.validUntil)\n : new Date(Date.now() + 14 * 60 * 1000)\n\n TOKEN_CACHE.set(cacheKey(credentials), {\n accessToken,\n accessTokenExp,\n refreshToken: refreshTokenValue,\n refreshTokenExp,\n })\n\n return accessToken\n}\n\nasync function pollAuthStatus(baseUrl: string, referenceNumber: string, authToken: string): Promise<boolean> {\n const deadline = Date.now() + 30_000\n let delay = 1000\n\n while (Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, delay))\n delay = Math.min(delay * 1.5, 5000)\n\n const res = await ksefFetch(`${baseUrl}/auth/${referenceNumber}`, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authToken}`,\n },\n })\n\n if (res.ok) {\n const data = AuthStatusSchema.safeParse(await res.json())\n if (data.success) {\n const code = data.data.status.code\n if (code === 200) return true\n if (code >= 400) {\n throw new KsefAuthError(\n `KSeF authentication failed: ${data.data.status.description ?? `status ${code}`}`,\n 'AUTH_FAILED',\n )\n }\n }\n }\n }\n\n return false\n}\n\nasync function refreshAccessToken(refreshToken: string, environment: KsefEnvironment): Promise<string> {\n const baseUrl = BASE_URLS[environment]\n const res = await ksefFetch(`${baseUrl}/auth/token/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${refreshToken}`,\n },\n body: JSON.stringify({}),\n })\n\n if (!res.ok) {\n throw new KsefAuthError(`Token refresh failed: HTTP ${res.status}`, 'AUTH_REFRESH_FAILED')\n }\n\n const raw = await res.json() as Record<string, unknown>\n const data = RedeemResponseSchema.parse(raw)\n const token = data.sessionToken?.token ?? data.accessToken?.token\n if (!token) throw new KsefAuthError('Unexpected refresh response shape', 'AUTH_REFRESH_FAILED')\n return token\n}\n\nexport async function verifyAccess(credentials: KsefCredentials): Promise<KsefRateLimits> {\n const baseUrl = BASE_URLS[credentials.environment]\n const key = cacheKey(credentials)\n\n let accessToken: string\n try {\n accessToken = await getValidAccessToken(credentials)\n } catch (err) {\n TOKEN_CACHE.delete(key)\n throw err\n }\n\n const res = await ksefFetch(`${baseUrl}/rate-limits`, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${accessToken}`,\n },\n })\n\n if (res.status === 401) {\n TOKEN_CACHE.delete(key)\n const freshToken = await authenticate(credentials)\n const retryRes = await ksefFetch(`${baseUrl}/rate-limits`, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${freshToken}`,\n },\n })\n if (!retryRes.ok) {\n throw new KsefNetworkError(`Rate limits check failed after re-auth: HTTP ${retryRes.status}`)\n }\n const parsed = RateLimitsSchema.safeParse(await retryRes.json())\n return parsed.success ? parsed.data : {}\n }\n\n if (!res.ok) {\n throw new KsefNetworkError(`Rate limits check failed: HTTP ${res.status}`)\n }\n\n const parsed = RateLimitsSchema.safeParse(await res.json())\n return parsed.success ? parsed.data : {}\n}\n\nexport function clearTokenCache(tenantKey?: string): void {\n if (tenantKey) {\n TOKEN_CACHE.delete(tenantKey)\n } else {\n TOKEN_CACHE.clear()\n }\n}\n\nexport class KsefAuthError extends Error {\n readonly errorCode: string\n constructor(message: string, errorCode: string) {\n super(message)\n this.name = 'KsefAuthError'\n this.errorCode = errorCode\n }\n}\n\nexport class KsefNetworkError extends Error {\n readonly errorCode = 'NETWORK_ERROR'\n constructor(message: string) {\n super(message)\n this.name = 'KsefNetworkError'\n }\n}\n\nconst OpenSessionResponseSchema = z.object({\n referenceNumber: z.string(),\n validUntil: z.string(),\n})\n\nconst SendInvoiceToSessionResponseSchema = z.object({\n referenceNumber: z.string(),\n})\n\nconst SessionStatusResponseSchema = z.object({\n status: z.object({\n code: z.number(),\n description: z.string(),\n details: z.array(z.string()).optional().nullable(),\n }),\n successfulInvoiceCount: z.number().optional().nullable(),\n failedInvoiceCount: z.number().optional().nullable(),\n}).passthrough()\n\nexport async function sendInvoice(\n credentials: KsefCredentials,\n payload: {\n encryptedSymmetricKey: string\n initializationVector: string\n encryptedInvoiceContent: string\n invoiceHash: string\n invoiceSize: number\n encryptedInvoiceHash: string\n encryptedInvoiceSize: number\n publicKeyId?: string\n },\n): Promise<{ sessionReferenceNumber: string; invoiceReferenceNumber: string }> {\n const baseUrl = BASE_URLS[credentials.environment]\n const accessToken = await getValidAccessToken(credentials)\n\n const openRes = await ksefFetch(`${baseUrl}/sessions/online`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` },\n body: JSON.stringify({\n formCode: { systemCode: 'FA (2)', schemaVersion: '1-0E', value: 'FA' },\n encryption: {\n encryptedSymmetricKey: payload.encryptedSymmetricKey,\n initializationVector: payload.initializationVector,\n ...(payload.publicKeyId ? { publicKeyId: payload.publicKeyId } : {}),\n },\n }),\n })\n\n if (!openRes.ok) {\n const body = await openRes.text().catch(() => '')\n throw new KsefNetworkError(`Session open failed: HTTP ${openRes.status}${body ? ` \u2014 ${body}` : ''}`)\n }\n\n const openData = OpenSessionResponseSchema.parse(await openRes.json())\n const sessionReferenceNumber = openData.referenceNumber\n\n let invoiceReferenceNumber: string\n try {\n const sendRes = await ksefFetch(\n `${baseUrl}/sessions/online/${encodeURIComponent(sessionReferenceNumber)}/invoices`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` },\n body: JSON.stringify({\n invoiceHash: payload.invoiceHash,\n invoiceSize: payload.invoiceSize,\n encryptedInvoiceHash: payload.encryptedInvoiceHash,\n encryptedInvoiceSize: payload.encryptedInvoiceSize,\n encryptedInvoiceContent: payload.encryptedInvoiceContent,\n }),\n },\n )\n\n if (!sendRes.ok) {\n const body = await sendRes.text().catch(() => '')\n throw new KsefNetworkError(`Invoice send failed: HTTP ${sendRes.status}${body ? ` \u2014 ${body}` : ''}`)\n }\n\n const sendData = SendInvoiceToSessionResponseSchema.parse(await sendRes.json())\n invoiceReferenceNumber = sendData.referenceNumber\n } catch (err) {\n await ksefFetch(\n `${baseUrl}/sessions/online/${encodeURIComponent(sessionReferenceNumber)}/close`,\n { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}` } },\n ).catch(() => {})\n throw err\n }\n\n const closeRes = await ksefFetch(\n `${baseUrl}/sessions/online/${encodeURIComponent(sessionReferenceNumber)}/close`,\n { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}` } },\n )\n\n\n return { sessionReferenceNumber, invoiceReferenceNumber }\n}\n\nexport interface KsefReceivedInvoiceSummary {\n ksefReferenceNumber: string\n sessionReferenceNumber: string\n issueDate: string | null\n sellerNip: string | null\n sellerName: string | null\n grossAmount: string | null\n netAmount: string | null\n vatAmount: string | null\n currency: string | null\n invoiceNumber: string | null\n upoDownloadUrl: string | null\n invoiceDownloadUrl: string | null\n}\n\nconst SessionListResponseSchema = z.object({\n sessions: z.array(z.object({\n referenceNumber: z.string(),\n }).passthrough()).default([]),\n continuationToken: z.string().nullable().optional(),\n}).passthrough()\n\nconst SessionInvoiceItemSchema = z.object({\n referenceNumber: z.string().optional(),\n ksefNumber: z.string().optional(),\n ksefReferenceNumber: z.string().optional(),\n issueDate: z.string().nullable().optional(),\n subjectBy: z.object({\n identifier: z.object({\n type: z.string().optional(),\n identifier: z.string().optional(),\n }).optional(),\n name: z.string().optional(),\n }).passthrough().optional(),\n grossAmount: z.union([z.string(), z.number()]).nullable().optional(),\n netAmount: z.union([z.string(), z.number()]).nullable().optional(),\n vatAmount: z.union([z.string(), z.number()]).nullable().optional(),\n currency: z.string().nullable().optional(),\n invoiceNumber: z.string().nullable().optional(),\n upoDownloadUrl: z.string().nullable().optional(),\n invoiceDownloadUrl: z.string().nullable().optional(),\n}).passthrough()\n\nconst SessionInvoiceListResponseSchema = z.object({\n invoices: z.array(SessionInvoiceItemSchema).default([]),\n continuationToken: z.string().nullable().optional(),\n}).passthrough()\n\nasync function fetchAllSessionInvoices(\n baseUrl: string,\n accessToken: string,\n sessionRef: string,\n): Promise<KsefReceivedInvoiceSummary[]> {\n const results: KsefReceivedInvoiceSummary[] = []\n let continuationToken: string | null | undefined = undefined\n let isFirst = true\n\n while (isFirst || continuationToken) {\n isFirst = false\n const url = new URL(`${baseUrl}/sessions/${encodeURIComponent(sessionRef)}/invoices`)\n if (continuationToken) url.searchParams.set('continuationToken', continuationToken)\n\n const res = await ksefFetch(url.toString(), {\n method: 'GET',\n headers: { 'Accept': 'application/json', 'Authorization': `Bearer ${accessToken}` },\n })\n\n if (!res.ok) break\n\n const data = SessionInvoiceListResponseSchema.parse(await res.json())\n continuationToken = data.continuationToken ?? null\n\n for (const inv of data.invoices) {\n const ksefRef = inv.ksefNumber ?? inv.ksefReferenceNumber\n if (!ksefRef) continue\n const grossRaw = inv.grossAmount\n const netRaw = inv.netAmount\n const vatRaw = inv.vatAmount\n results.push({\n ksefReferenceNumber: ksefRef,\n sessionReferenceNumber: sessionRef,\n issueDate: inv.issueDate ?? null,\n sellerNip: inv.subjectBy?.identifier?.identifier ?? null,\n sellerName: inv.subjectBy?.name ?? null,\n grossAmount: grossRaw != null ? String(grossRaw) : null,\n netAmount: netRaw != null ? String(netRaw) : null,\n vatAmount: vatRaw != null ? String(vatRaw) : null,\n currency: inv.currency ?? null,\n invoiceNumber: inv.invoiceNumber ?? null,\n upoDownloadUrl: inv.upoDownloadUrl ?? null,\n invoiceDownloadUrl: inv.invoiceDownloadUrl ?? null,\n })\n }\n\n if (!continuationToken) break\n }\n\n return results\n}\n\nexport async function queryReceivedInvoices(\n credentials: KsefCredentials,\n params: {\n dateFrom: string\n dateTo: string\n },\n): Promise<{ items: KsefReceivedInvoiceSummary[]; totalCount: number }> {\n const baseUrl = BASE_URLS[credentials.environment]\n const accessToken = await getValidAccessToken(credentials)\n const allItems: KsefReceivedInvoiceSummary[] = []\n\n let continuationToken: string | null | undefined = undefined\n let isFirst = true\n\n while (isFirst || continuationToken) {\n isFirst = false\n const sessionUrl = new URL(`${baseUrl}/sessions`)\n sessionUrl.searchParams.set('sessionType', 'online')\n sessionUrl.searchParams.set('direction', 'received')\n sessionUrl.searchParams.set('dateFrom', params.dateFrom)\n sessionUrl.searchParams.set('dateTo', params.dateTo)\n if (continuationToken) sessionUrl.searchParams.set('continuationToken', continuationToken)\n\n const res = await ksefFetch(sessionUrl.toString(), {\n method: 'GET',\n headers: { 'Accept': 'application/json', 'Authorization': `Bearer ${accessToken}` },\n })\n\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new KsefNetworkError(`Query received sessions failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ''}`)\n }\n\n const sessionData = SessionListResponseSchema.parse(await res.json())\n continuationToken = sessionData.continuationToken ?? null\n\n for (const session of sessionData.sessions) {\n const invoices = await fetchAllSessionInvoices(baseUrl, accessToken, session.referenceNumber)\n allItems.push(...invoices)\n }\n\n if (!continuationToken) break\n }\n\n return { items: allItems, totalCount: allItems.length }\n}\n\nasync function downloadFromUrl(url: string): Promise<string> {\n const res = await fetch(url, {\n method: 'GET',\n signal: AbortSignal.timeout(30_000),\n })\n\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new KsefNetworkError(`Invoice download failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ''}`)\n }\n\n return res.text()\n}\n\nexport async function downloadInvoiceFromUrl(url: string): Promise<string> {\n return downloadFromUrl(url)\n}\n\nexport async function downloadInvoice(\n credentials: KsefCredentials,\n ksefReferenceNumber: string,\n): Promise<{ rawContent: string; upoDownloadUrl: string | null; invoiceDownloadUrl: string | null }> {\n const baseUrl = BASE_URLS[credentials.environment]\n const accessToken = await getValidAccessToken(credentials)\n\n const res = await ksefFetch(`${baseUrl}/invoices/ksef/${encodeURIComponent(ksefReferenceNumber)}`, {\n method: 'GET',\n headers: { 'Accept': 'application/octet-stream', 'Authorization': `Bearer ${accessToken}` },\n })\n\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new KsefNetworkError(`Invoice fetch failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ''}`)\n }\n\n const contentType = res.headers.get('content-type') ?? ''\n let rawContent: string\n\n if (contentType.includes('application/json')) {\n const data = await res.json() as Record<string, unknown>\n const downloadUrl = (data['invoiceDownloadUrl'] ?? data['downloadUrl'] ?? data['url']) as string | undefined\n if (downloadUrl) {\n rawContent = await downloadFromUrl(downloadUrl)\n } else if (typeof data['content'] === 'string') {\n rawContent = data['content'] as string\n } else {\n throw new KsefNetworkError(`Unexpected JSON response from /invoices/ksef \u2014 keys: ${Object.keys(data).join(', ')}`)\n }\n return {\n rawContent,\n upoDownloadUrl: (data['upoDownloadUrl'] as string | undefined) ?? null,\n invoiceDownloadUrl: (data['invoiceDownloadUrl'] as string | undefined) ?? null,\n }\n }\n\n rawContent = await res.text()\n return { rawContent, upoDownloadUrl: null, invoiceDownloadUrl: null }\n}\n\nexport async function checkInvoiceStatus(\n credentials: KsefCredentials,\n referenceNumber: string,\n): Promise<{ processingCode: number; ksefReferenceNumber?: string; errorDescription?: string }> {\n const baseUrl = BASE_URLS[credentials.environment]\n const accessToken = await getValidAccessToken(credentials)\n\n const res = await ksefFetch(`${baseUrl}/sessions/${encodeURIComponent(referenceNumber)}`, {\n method: 'GET',\n headers: { 'Accept': 'application/json', 'Authorization': `Bearer ${accessToken}` },\n })\n\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new KsefNetworkError(`Session status check failed: HTTP ${res.status}${body ? ` \u2014 ${body}` : ''}`)\n }\n\n const data = SessionStatusResponseSchema.parse(await res.json())\n const code = data.status.code\n\n if (code === 200) {\n if ((data.failedInvoiceCount ?? 0) > 0) {\n const details = data.status.details?.join('; ') ?? ''\n return { processingCode: 400, errorDescription: `KSeF rejected ${data.failedInvoiceCount} invoice(s): ${data.status.description}${details ? ` \u2014 ${details}` : ''}` }\n }\n return { processingCode: 200 }\n }\n\n if (code >= 400) {\n const details = data.status.details?.join('; ') ?? ''\n return { processingCode: code, errorDescription: `${data.status.description}${details ? ` \u2014 ${details}` : ''}` }\n }\n\n return { processingCode: 100 }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["parsed"]
7
+ }