ksef-client-ts 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -43,7 +43,8 @@ function resolveOptions(options = {}) {
43
43
  apiVersion: options.apiVersion ?? DEFAULT_API_VERSION,
44
44
  timeout: options.timeout ?? DEFAULT_TIMEOUT,
45
45
  customHeaders: options.customHeaders ?? {},
46
- environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST")
46
+ environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST"),
47
+ errorFormat: options.errorFormat ?? "problem-details"
47
48
  };
48
49
  }
49
50
  var DEFAULT_API_VERSION, DEFAULT_TIMEOUT;
@@ -99,6 +100,9 @@ var init_ksef_api_error = __esm({
99
100
  const message = details?.length ? details.map((d) => d.exceptionDescription ?? "").filter(Boolean).join("; ") || `KSeF API error: HTTP ${statusCode}` : `KSeF API error: HTTP ${statusCode}`;
100
101
  return new _KSeFApiError(message, statusCode, body);
101
102
  }
103
+ toProblemFields() {
104
+ return { detail: this.message };
105
+ }
102
106
  };
103
107
  }
104
108
  });
@@ -110,17 +114,20 @@ var init_ksef_rate_limit_error = __esm({
110
114
  "use strict";
111
115
  init_ksef_api_error();
112
116
  KSeFRateLimitError = class _KSeFRateLimitError extends KSeFApiError {
117
+ statusCode = 429;
113
118
  retryAfterSeconds;
114
119
  retryAfterDate;
115
120
  recommendedDelay;
116
- constructor(message, statusCode, errorResponse, retryAfterSeconds, retryAfterDate) {
121
+ problem;
122
+ constructor(message, statusCode, errorResponse, retryAfterSeconds, retryAfterDate, problem) {
117
123
  super(message, statusCode, errorResponse);
118
124
  this.name = "KSeFRateLimitError";
119
125
  this.retryAfterSeconds = retryAfterSeconds;
120
126
  this.retryAfterDate = retryAfterDate;
121
127
  this.recommendedDelay = retryAfterSeconds ?? 60;
128
+ this.problem = problem;
122
129
  }
123
- static fromRetryAfterHeader(statusCode, retryAfterHeader, body) {
130
+ static fromRetryAfterHeader(statusCode, retryAfterHeader, body, problem) {
124
131
  let retryAfterSeconds;
125
132
  let retryAfterDate;
126
133
  if (retryAfterHeader) {
@@ -135,8 +142,16 @@ var init_ksef_rate_limit_error = __esm({
135
142
  }
136
143
  }
137
144
  }
138
- const message = retryAfterSeconds != null ? `Rate limited. Retry after ${retryAfterSeconds}s` : "Rate limited by KSeF API";
139
- return new _KSeFRateLimitError(message, statusCode, body, retryAfterSeconds, retryAfterDate);
145
+ const message = retryAfterSeconds != null ? `Rate limited. Retry after ${retryAfterSeconds}s` : problem?.detail ?? "Rate limited by KSeF API";
146
+ return new _KSeFRateLimitError(message, statusCode, body, retryAfterSeconds, retryAfterDate, problem);
147
+ }
148
+ toProblemFields() {
149
+ return {
150
+ detail: this.problem?.detail,
151
+ traceId: this.problem?.traceId,
152
+ instance: this.problem?.instance,
153
+ timestamp: this.problem?.timestamp
154
+ };
140
155
  }
141
156
  };
142
157
  }
@@ -147,18 +162,28 @@ var KSeFUnauthorizedError;
147
162
  var init_ksef_unauthorized_error = __esm({
148
163
  "src/errors/ksef-unauthorized-error.ts"() {
149
164
  "use strict";
150
- init_ksef_error();
151
- KSeFUnauthorizedError = class extends KSeFError {
165
+ init_ksef_api_error();
166
+ KSeFUnauthorizedError = class extends KSeFApiError {
152
167
  statusCode = 401;
153
168
  detail;
154
169
  traceId;
155
170
  instance;
171
+ timestamp;
156
172
  constructor(problemDetails) {
157
- super(problemDetails.detail || "Unauthorized");
173
+ super(problemDetails.detail || "Unauthorized", 401);
158
174
  this.name = "KSeFUnauthorizedError";
159
175
  this.detail = problemDetails.detail;
160
176
  this.traceId = problemDetails.traceId;
161
177
  this.instance = problemDetails.instance;
178
+ this.timestamp = problemDetails.timestamp;
179
+ }
180
+ toProblemFields() {
181
+ return {
182
+ detail: this.detail,
183
+ traceId: this.traceId,
184
+ instance: this.instance,
185
+ timestamp: this.timestamp
186
+ };
162
187
  }
163
188
  };
164
189
  }
@@ -169,22 +194,101 @@ var KSeFForbiddenError;
169
194
  var init_ksef_forbidden_error = __esm({
170
195
  "src/errors/ksef-forbidden-error.ts"() {
171
196
  "use strict";
172
- init_ksef_error();
173
- KSeFForbiddenError = class extends KSeFError {
197
+ init_ksef_api_error();
198
+ KSeFForbiddenError = class extends KSeFApiError {
174
199
  statusCode = 403;
175
200
  detail;
176
201
  reasonCode;
177
202
  instance;
178
203
  security;
179
204
  traceId;
205
+ timestamp;
180
206
  constructor(problemDetails) {
181
- super(problemDetails.detail || "Forbidden");
207
+ super(problemDetails.detail || "Forbidden", 403);
182
208
  this.name = "KSeFForbiddenError";
183
209
  this.detail = problemDetails.detail;
184
210
  this.reasonCode = problemDetails.reasonCode;
185
211
  this.instance = problemDetails.instance;
186
212
  this.security = problemDetails.security;
187
213
  this.traceId = problemDetails.traceId;
214
+ this.timestamp = problemDetails.timestamp;
215
+ }
216
+ toProblemFields() {
217
+ return {
218
+ detail: this.detail,
219
+ reasonCode: this.reasonCode,
220
+ security: this.security,
221
+ traceId: this.traceId,
222
+ instance: this.instance,
223
+ timestamp: this.timestamp
224
+ };
225
+ }
226
+ };
227
+ }
228
+ });
229
+
230
+ // src/errors/ksef-gone-error.ts
231
+ var KSeFGoneError;
232
+ var init_ksef_gone_error = __esm({
233
+ "src/errors/ksef-gone-error.ts"() {
234
+ "use strict";
235
+ init_ksef_api_error();
236
+ KSeFGoneError = class extends KSeFApiError {
237
+ statusCode = 410;
238
+ detail;
239
+ instance;
240
+ traceId;
241
+ timestamp;
242
+ constructor(problemDetails) {
243
+ super(problemDetails.detail || "Operation status no longer available (retention expired)", 410);
244
+ this.name = "KSeFGoneError";
245
+ this.detail = problemDetails.detail;
246
+ this.instance = problemDetails.instance;
247
+ this.traceId = problemDetails.traceId;
248
+ this.timestamp = problemDetails.timestamp;
249
+ }
250
+ toProblemFields() {
251
+ return {
252
+ detail: this.detail,
253
+ traceId: this.traceId,
254
+ instance: this.instance,
255
+ timestamp: this.timestamp
256
+ };
257
+ }
258
+ };
259
+ }
260
+ });
261
+
262
+ // src/errors/ksef-bad-request-error.ts
263
+ var KSeFBadRequestError;
264
+ var init_ksef_bad_request_error = __esm({
265
+ "src/errors/ksef-bad-request-error.ts"() {
266
+ "use strict";
267
+ init_ksef_api_error();
268
+ KSeFBadRequestError = class extends KSeFApiError {
269
+ statusCode = 400;
270
+ detail;
271
+ instance;
272
+ errors;
273
+ traceId;
274
+ timestamp;
275
+ constructor(problemDetails) {
276
+ super(problemDetails.detail || problemDetails.title || "Bad Request", 400);
277
+ this.name = "KSeFBadRequestError";
278
+ this.detail = problemDetails.detail;
279
+ this.instance = problemDetails.instance;
280
+ this.errors = problemDetails.errors ?? [];
281
+ this.traceId = problemDetails.traceId;
282
+ this.timestamp = problemDetails.timestamp;
283
+ }
284
+ toProblemFields() {
285
+ return {
286
+ detail: this.detail,
287
+ errors: this.errors.length ? this.errors : void 0,
288
+ traceId: this.traceId,
289
+ instance: this.instance,
290
+ timestamp: this.timestamp
291
+ };
188
292
  }
189
293
  };
190
294
  }
@@ -252,6 +356,55 @@ var init_ksef_validation_error = __esm({
252
356
  }
253
357
  });
254
358
 
359
+ // src/errors/error-codes.ts
360
+ function hasErrorCode(body, code) {
361
+ return !!body?.exception?.exceptionDetailList?.some((d) => d.exceptionCode === code);
362
+ }
363
+ var KSeFErrorCode;
364
+ var init_error_codes = __esm({
365
+ "src/errors/error-codes.ts"() {
366
+ "use strict";
367
+ KSeFErrorCode = {
368
+ BatchTimeout: 21208,
369
+ DuplicateInvoice: 440
370
+ };
371
+ }
372
+ });
373
+
374
+ // src/errors/ksef-batch-timeout-error.ts
375
+ var KSeFBatchTimeoutError;
376
+ var init_ksef_batch_timeout_error = __esm({
377
+ "src/errors/ksef-batch-timeout-error.ts"() {
378
+ "use strict";
379
+ init_ksef_api_error();
380
+ init_error_codes();
381
+ KSeFBatchTimeoutError = class _KSeFBatchTimeoutError extends KSeFApiError {
382
+ errorCode = KSeFErrorCode.BatchTimeout;
383
+ constructor(message, statusCode, errorResponse) {
384
+ super(message, statusCode, errorResponse);
385
+ this.name = "KSeFBatchTimeoutError";
386
+ }
387
+ static fromResponse(statusCode, body) {
388
+ const detail = body?.exception?.exceptionDetailList?.find(
389
+ (d) => d.exceptionCode === KSeFErrorCode.BatchTimeout
390
+ );
391
+ const message = detail?.exceptionDescription?.trim() || "Batch session timed out before the server completed processing (KSeF 21208).";
392
+ return new _KSeFBatchTimeoutError(message, statusCode, body);
393
+ }
394
+ };
395
+ }
396
+ });
397
+
398
+ // src/errors/assert-never.ts
399
+ function assertNever(value) {
400
+ throw new Error(`Unexpected value: ${String(value)}`);
401
+ }
402
+ var init_assert_never = __esm({
403
+ "src/errors/assert-never.ts"() {
404
+ "use strict";
405
+ }
406
+ });
407
+
255
408
  // src/errors/index.ts
256
409
  var init_errors = __esm({
257
410
  "src/errors/index.ts"() {
@@ -261,9 +414,14 @@ var init_errors = __esm({
261
414
  init_ksef_rate_limit_error();
262
415
  init_ksef_unauthorized_error();
263
416
  init_ksef_forbidden_error();
417
+ init_ksef_gone_error();
418
+ init_ksef_bad_request_error();
264
419
  init_ksef_auth_status_error();
265
420
  init_ksef_session_expired_error();
266
421
  init_ksef_validation_error();
422
+ init_ksef_batch_timeout_error();
423
+ init_error_codes();
424
+ init_assert_never();
267
425
  }
268
426
  });
269
427
 
@@ -512,6 +670,27 @@ var init_presigned_url_policy = __esm({
512
670
 
513
671
  // src/http/rest-client.ts
514
672
  import { consola } from "consola";
673
+ function isBadRequestProblem(value) {
674
+ if (typeof value !== "object" || value === null) return false;
675
+ const v = value;
676
+ if (typeof v.title !== "string") return false;
677
+ if (v.status !== void 0 && typeof v.status !== "number") return false;
678
+ if (v.errors !== void 0) {
679
+ if (!Array.isArray(v.errors)) return false;
680
+ for (const item of v.errors) {
681
+ if (typeof item !== "object" || item === null) return false;
682
+ const detail = item;
683
+ if (typeof detail.code !== "number") return false;
684
+ if (typeof detail.description !== "string") return false;
685
+ }
686
+ }
687
+ return true;
688
+ }
689
+ function isTooManyRequestsProblem(value) {
690
+ if (typeof value !== "object" || value === null) return false;
691
+ const v = value;
692
+ return typeof v.title === "string" && (v.status === void 0 || typeof v.status === "number") && (v.detail === void 0 || typeof v.detail === "string") && (v.instance === void 0 || typeof v.instance === "string") && (v.traceId === void 0 || typeof v.traceId === "string") && (v.timestamp === void 0 || typeof v.timestamp === "string");
693
+ }
515
694
  var RestClient;
516
695
  var init_rest_client = __esm({
517
696
  "src/http/rest-client.ts"() {
@@ -520,6 +699,10 @@ var init_rest_client = __esm({
520
699
  init_ksef_rate_limit_error();
521
700
  init_ksef_unauthorized_error();
522
701
  init_ksef_forbidden_error();
702
+ init_ksef_gone_error();
703
+ init_ksef_bad_request_error();
704
+ init_ksef_batch_timeout_error();
705
+ init_error_codes();
523
706
  init_route_builder();
524
707
  init_transport();
525
708
  init_retry_policy();
@@ -606,6 +789,10 @@ var init_rest_client = __esm({
606
789
  ...this.options.customHeaders,
607
790
  ...request.getHeaders()
608
791
  };
792
+ const hasHeader = (name) => Object.keys(headers).some((header) => header.toLowerCase() === name.toLowerCase());
793
+ if (this.options.errorFormat !== "legacy" && !hasHeader("x-error-format")) {
794
+ headers["X-Error-Format"] = "problem-details";
795
+ }
609
796
  if (!headers["Authorization"] && this.authManager) {
610
797
  const token = overrideToken ?? this.authManager.getAccessToken();
611
798
  if (token) {
@@ -644,34 +831,70 @@ var init_rest_client = __esm({
644
831
  async ensureSuccess(response) {
645
832
  if (response.ok) return;
646
833
  const text = await response.text().catch(() => "");
834
+ let jsonCache = null;
647
835
  const parseJson = () => {
648
- try {
649
- return JSON.parse(text);
650
- } catch {
651
- return void 0;
836
+ if (jsonCache === null) {
837
+ try {
838
+ jsonCache = { value: JSON.parse(text) };
839
+ } catch {
840
+ jsonCache = { value: void 0 };
841
+ }
652
842
  }
843
+ return jsonCache.value;
653
844
  };
654
- if (response.status === 429) {
845
+ const tryParseProblem = (guard) => {
655
846
  const parsed = parseJson();
847
+ return parsed !== void 0 && guard(parsed) ? parsed : void 0;
848
+ };
849
+ if (response.status === 400) {
850
+ const problem = tryParseProblem(isBadRequestProblem);
851
+ if (problem) {
852
+ throw new KSeFBadRequestError(problem);
853
+ }
854
+ const legacy = parseJson();
855
+ if (hasErrorCode(legacy, KSeFErrorCode.BatchTimeout)) {
856
+ throw KSeFBatchTimeoutError.fromResponse(400, legacy);
857
+ }
858
+ throw KSeFApiError.fromResponse(400, legacy);
859
+ }
860
+ if (response.status === 429) {
861
+ const problem = tryParseProblem(isTooManyRequestsProblem);
862
+ const legacy = problem ? void 0 : parseJson();
656
863
  throw KSeFRateLimitError.fromRetryAfterHeader(
657
864
  response.status,
658
865
  response.headers.get("Retry-After"),
659
- parsed
866
+ legacy,
867
+ problem
660
868
  );
661
869
  }
662
870
  if (response.status === 401) {
663
- const body = parseJson();
664
- if (body?.detail) {
665
- throw new KSeFUnauthorizedError(body);
871
+ const body2 = parseJson();
872
+ if (body2?.detail) {
873
+ throw new KSeFUnauthorizedError(body2);
666
874
  }
667
875
  }
668
876
  if (response.status === 403) {
669
- const body = parseJson();
670
- if (body?.reasonCode) {
671
- throw new KSeFForbiddenError(body);
877
+ const body2 = parseJson();
878
+ if (body2?.reasonCode) {
879
+ throw new KSeFForbiddenError(body2);
672
880
  }
673
881
  }
674
- throw KSeFApiError.fromResponse(response.status, parseJson());
882
+ if (response.status === 410) {
883
+ const body2 = parseJson();
884
+ throw new KSeFGoneError({
885
+ title: body2?.title || "Gone",
886
+ status: body2?.status || 410,
887
+ detail: body2?.detail || "Operation status no longer available (retention expired)",
888
+ instance: body2?.instance,
889
+ traceId: body2?.traceId,
890
+ timestamp: body2?.timestamp
891
+ });
892
+ }
893
+ const body = parseJson();
894
+ if (hasErrorCode(body, KSeFErrorCode.BatchTimeout)) {
895
+ throw KSeFBatchTimeoutError.fromResponse(response.status, body);
896
+ }
897
+ throw KSeFApiError.fromResponse(response.status, body);
675
898
  }
676
899
  };
677
900
  }
@@ -2590,6 +2813,115 @@ var init_schema_registry = __esm({
2590
2813
  }
2591
2814
  });
2592
2815
 
2816
+ // src/validation/char-validity.ts
2817
+ function validateCharValidity(xml) {
2818
+ return [...findProcessingInstructions(xml), ...findDiscouragedUnicode(xml)];
2819
+ }
2820
+ function findProcessingInstructionTokens(xml) {
2821
+ const tokens = [];
2822
+ for (let i = 0; i < xml.length; ) {
2823
+ if (xml.startsWith("<!--", i)) {
2824
+ const end = xml.indexOf("-->", i + 4);
2825
+ i = end === -1 ? xml.length : end + 3;
2826
+ continue;
2827
+ }
2828
+ if (xml.startsWith("<![CDATA[", i)) {
2829
+ const end = xml.indexOf("]]>", i + 9);
2830
+ i = end === -1 ? xml.length : end + 3;
2831
+ continue;
2832
+ }
2833
+ if (xml.startsWith("<?", i)) {
2834
+ const end = xml.indexOf("?>", i + 2);
2835
+ if (end === -1) break;
2836
+ tokens.push({ token: xml.slice(i, end + 2), index: i });
2837
+ i = end + 2;
2838
+ continue;
2839
+ }
2840
+ i += 1;
2841
+ }
2842
+ return tokens;
2843
+ }
2844
+ function findProcessingInstructions(xml) {
2845
+ const errors = [];
2846
+ const matches = findProcessingInstructionTokens(xml);
2847
+ if (matches.length === 0) return errors;
2848
+ const firstMatch = matches[0];
2849
+ const firstTarget = firstMatch.token.match(PI_TARGET_RE)?.[1];
2850
+ const hasBom = xml.charCodeAt(0) === 65279;
2851
+ const prologPosition = hasBom ? 1 : 0;
2852
+ const firstIsProlog = firstMatch.index === prologPosition && firstTarget === "xml";
2853
+ for (let i = 0; i < matches.length; i++) {
2854
+ if (i === 0 && firstIsProlog) continue;
2855
+ const m = matches[i];
2856
+ const target = m.token.match(PI_TARGET_RE)?.[1] ?? "?";
2857
+ errors.push({
2858
+ code: "XML_PROCESSING_INSTRUCTION",
2859
+ message: `Processing instruction <?${target}?> at offset ${m.index} is not allowed (only <?xml ... ?> prolog is permitted)`,
2860
+ path: `offset:${m.index}`
2861
+ });
2862
+ }
2863
+ return errors;
2864
+ }
2865
+ function findDiscouragedUnicode(xml) {
2866
+ const errors = [];
2867
+ const seenRanges = /* @__PURE__ */ new Set();
2868
+ let utf16Offset = 0;
2869
+ for (const ch of xml) {
2870
+ const cp = ch.codePointAt(0);
2871
+ const idx = rangeIndex(cp);
2872
+ if (idx >= 0 && !seenRanges.has(idx)) {
2873
+ seenRanges.add(idx);
2874
+ errors.push({
2875
+ code: "XML_DISCOURAGED_UNICODE",
2876
+ message: `Discouraged Unicode character U+${cp.toString(16).toUpperCase().padStart(4, "0")} found at offset ${utf16Offset} (W3C XML 1.0 \xA72.2 rejects this range)`,
2877
+ path: `offset:${utf16Offset}`
2878
+ });
2879
+ }
2880
+ utf16Offset += ch.length;
2881
+ }
2882
+ return errors;
2883
+ }
2884
+ function rangeIndex(cp) {
2885
+ let lo = 0;
2886
+ let hi = DISCOURAGED_UNICODE_RANGES.length - 1;
2887
+ while (lo <= hi) {
2888
+ const mid = lo + hi >> 1;
2889
+ const [start, end] = DISCOURAGED_UNICODE_RANGES[mid];
2890
+ if (cp < start) hi = mid - 1;
2891
+ else if (cp > end) lo = mid + 1;
2892
+ else return mid;
2893
+ }
2894
+ return -1;
2895
+ }
2896
+ var DISCOURAGED_UNICODE_RANGES, PI_TARGET_RE;
2897
+ var init_char_validity = __esm({
2898
+ "src/validation/char-validity.ts"() {
2899
+ "use strict";
2900
+ DISCOURAGED_UNICODE_RANGES = [
2901
+ [127, 132],
2902
+ [134, 159],
2903
+ [64976, 65007],
2904
+ [131070, 131071],
2905
+ [196606, 196607],
2906
+ [262142, 262143],
2907
+ [327678, 327679],
2908
+ [393214, 393215],
2909
+ [458750, 458751],
2910
+ [524286, 524287],
2911
+ [589822, 589823],
2912
+ [655358, 655359],
2913
+ [720894, 720895],
2914
+ [786430, 786431],
2915
+ [851966, 851967],
2916
+ [917502, 917503],
2917
+ [983038, 983039],
2918
+ [1048574, 1048575],
2919
+ [1114110, 1114111]
2920
+ ];
2921
+ PI_TARGET_RE = /^<\?(\S+)/;
2922
+ }
2923
+ });
2924
+
2593
2925
  // src/validation/invoice-validator.ts
2594
2926
  var invoice_validator_exports = {};
2595
2927
  __export(invoice_validator_exports, {
@@ -2742,6 +3074,12 @@ function collectDateErrors(obj, rootElement, errors) {
2742
3074
  }
2743
3075
  }
2744
3076
  async function validate(xml, options) {
3077
+ if (!options?.skipCharValidity) {
3078
+ const l1aErrors = validateCharValidity(xml);
3079
+ if (l1aErrors.length > 0) {
3080
+ return { valid: false, schemaType: null, errors: l1aErrors };
3081
+ }
3082
+ }
2745
3083
  const parsed = xml && xml.trim() ? xmlToObject(xml) : void 0;
2746
3084
  const l1 = validateWellFormedness(xml, parsed);
2747
3085
  if (!l1.valid) return l1;
@@ -2768,6 +3106,7 @@ var init_invoice_validator = __esm({
2768
3106
  "use strict";
2769
3107
  init_xml_to_object();
2770
3108
  init_schema_registry();
3109
+ init_char_validity();
2771
3110
  init_patterns();
2772
3111
  }
2773
3112
  });
@@ -3232,9 +3571,10 @@ var PermissionsService;
3232
3571
  var init_permissions = __esm({
3233
3572
  "src/services/permissions.ts"() {
3234
3573
  "use strict";
3574
+ init_ksef_validation_error();
3235
3575
  init_rest_request();
3236
3576
  init_routes();
3237
- PermissionsService = class {
3577
+ PermissionsService = class _PermissionsService {
3238
3578
  restClient;
3239
3579
  constructor(restClient) {
3240
3580
  this.restClient = restClient;
@@ -3292,6 +3632,7 @@ var init_permissions = __esm({
3292
3632
  }
3293
3633
  // Search methods
3294
3634
  async queryPersonalGrants(options, pageOffset, pageSize) {
3635
+ _PermissionsService.validateContextIdentifier(options?.contextIdentifier);
3295
3636
  const req = RestRequest.post(Routes.Permissions.Query.personalGrants).body(options ?? {});
3296
3637
  if (pageOffset !== void 0) req.query("pageOffset", String(pageOffset));
3297
3638
  if (pageSize !== void 0) req.query("pageSize", String(pageSize));
@@ -3320,6 +3661,7 @@ var init_permissions = __esm({
3320
3661
  return response.body;
3321
3662
  }
3322
3663
  async queryEntitiesGrants(options, pageOffset, pageSize) {
3664
+ _PermissionsService.validateContextIdentifier(options?.contextIdentifier);
3323
3665
  const req = RestRequest.post(Routes.Permissions.Query.entitiesGrants).body(options ?? {});
3324
3666
  if (pageOffset !== void 0) req.query("pageOffset", String(pageOffset));
3325
3667
  if (pageSize !== void 0) req.query("pageSize", String(pageSize));
@@ -3358,17 +3700,90 @@ var init_permissions = __esm({
3358
3700
  const response = await this.restClient.execute(req);
3359
3701
  return response.body;
3360
3702
  }
3703
+ static validateContextIdentifier(ctx) {
3704
+ if (!ctx) return;
3705
+ if (ctx.type === "InternalId") {
3706
+ const len = ctx.value.length;
3707
+ if (len < 10 || len > 16) {
3708
+ throw KSeFValidationError.fromField(
3709
+ "contextIdentifier.value",
3710
+ `InternalId must be 10-16 characters, got ${len}`
3711
+ );
3712
+ }
3713
+ }
3714
+ }
3361
3715
  };
3362
3716
  }
3363
3717
  });
3364
3718
 
3719
+ // src/utils/jwt.ts
3720
+ function decodeJwtPayload(token) {
3721
+ const parts = token.split(".");
3722
+ if (parts.length !== 3) return null;
3723
+ try {
3724
+ const payload = parts[1];
3725
+ const json = Buffer.from(payload, "base64url").toString("utf-8");
3726
+ return JSON.parse(json);
3727
+ } catch {
3728
+ return null;
3729
+ }
3730
+ }
3731
+ function tryParseJson(value) {
3732
+ if (typeof value !== "string") return void 0;
3733
+ try {
3734
+ return JSON.parse(value);
3735
+ } catch {
3736
+ return void 0;
3737
+ }
3738
+ }
3739
+ function tryParseJsonArray(value) {
3740
+ if (typeof value !== "string") return void 0;
3741
+ try {
3742
+ const parsed = JSON.parse(value);
3743
+ return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
3744
+ } catch {
3745
+ return void 0;
3746
+ }
3747
+ }
3748
+ function parseKSeFTokenContext(token) {
3749
+ const raw = decodeJwtPayload(token);
3750
+ if (!raw) return null;
3751
+ return {
3752
+ type: typeof raw["typ"] === "string" ? raw["typ"] : void 0,
3753
+ contextIdentifierType: typeof raw["cit"] === "string" ? raw["cit"] : void 0,
3754
+ contextIdentifierValue: typeof raw["civ"] === "string" ? raw["civ"] : void 0,
3755
+ authMethod: typeof raw["aum"] === "string" ? raw["aum"] : void 0,
3756
+ permissions: tryParseJsonArray(raw["per"]),
3757
+ subjectDetails: tryParseJson(raw["sud"]),
3758
+ authorSubjectIdentifier: tryParseJson(raw["asi"]),
3759
+ issuedAt: typeof raw["iat"] === "number" ? raw["iat"] : void 0,
3760
+ expiresAt: typeof raw["exp"] === "number" ? raw["exp"] : void 0
3761
+ };
3762
+ }
3763
+ var init_jwt = __esm({
3764
+ "src/utils/jwt.ts"() {
3765
+ "use strict";
3766
+ }
3767
+ });
3768
+
3365
3769
  // src/services/tokens.ts
3366
- var TokenService;
3770
+ function toTokenAuthorIdentifierType(value) {
3771
+ return TOKEN_AUTHOR_IDENTIFIER_TYPES.has(value) ? value : void 0;
3772
+ }
3773
+ var TOKEN_AUTHOR_IDENTIFIER_TYPES, TokenService;
3367
3774
  var init_tokens = __esm({
3368
3775
  "src/services/tokens.ts"() {
3369
3776
  "use strict";
3370
3777
  init_rest_request();
3371
3778
  init_routes();
3779
+ init_jwt();
3780
+ init_ksef_api_error();
3781
+ init_ksef_error();
3782
+ TOKEN_AUTHOR_IDENTIFIER_TYPES = /* @__PURE__ */ new Set([
3783
+ "Nip",
3784
+ "Pesel",
3785
+ "Fingerprint"
3786
+ ]);
3372
3787
  TokenService = class {
3373
3788
  restClient;
3374
3789
  constructor(restClient) {
@@ -3403,6 +3818,73 @@ var init_tokens = __esm({
3403
3818
  const req = RestRequest.delete(Routes.Tokens.byReference(ref));
3404
3819
  await this.restClient.executeVoid(req);
3405
3820
  }
3821
+ /**
3822
+ * Resolves the reference number of the token currently in use for authentication.
3823
+ * The only JWT payload field treated as authoritative is the KSeF-specific `trn`
3824
+ * (token reference number). Standard RFC 7519 claims such as `jti` are NOT a safe
3825
+ * fallback — a `jti` that differs from the KSeF reference would cause a DELETE to
3826
+ * hit a non-existent path, which `revokeSelf` treats as already-revoked, falsely
3827
+ * reporting success while leaving the token active on the server. When `trn` is
3828
+ * absent, we fall back to `GET /tokens` filtered by author and context; requires
3829
+ * exactly one active match and returns undefined when ambiguous.
3830
+ */
3831
+ async findSelfReferenceNumber(accessToken) {
3832
+ if (!accessToken) return void 0;
3833
+ const payload = decodeJwtPayload(accessToken);
3834
+ if (payload && typeof payload["trn"] === "string" && payload["trn"].length > 0) {
3835
+ return payload["trn"];
3836
+ }
3837
+ const ctx = parseKSeFTokenContext(accessToken);
3838
+ const author = ctx?.authorSubjectIdentifier;
3839
+ if (!author?.type || !author.value) return void 0;
3840
+ if (!ctx?.contextIdentifierType || !ctx?.contextIdentifierValue) return void 0;
3841
+ const authorType = toTokenAuthorIdentifierType(author.type);
3842
+ if (!authorType) return void 0;
3843
+ let continuationToken;
3844
+ let match;
3845
+ do {
3846
+ const list = await this.queryTokens({
3847
+ status: ["Active"],
3848
+ authorIdentifier: author.value,
3849
+ authorIdentifierType: authorType,
3850
+ pageSize: 50,
3851
+ continuationToken
3852
+ });
3853
+ for (const t of list.tokens) {
3854
+ if (t.status === "Active" && t.contextIdentifier?.value === ctx.contextIdentifierValue && t.contextIdentifier?.type === ctx.contextIdentifierType) {
3855
+ if (match) return void 0;
3856
+ match = t.referenceNumber;
3857
+ }
3858
+ }
3859
+ continuationToken = list.continuationToken ?? void 0;
3860
+ } while (continuationToken);
3861
+ return match;
3862
+ }
3863
+ /**
3864
+ * Revokes the token currently used for authentication.
3865
+ * Treats 404/409/410 on DELETE as "already revoked" and returns successfully with
3866
+ * `alreadyRevoked: true` so callers can still clear local state.
3867
+ */
3868
+ async revokeSelf(opts = {}) {
3869
+ let ref = opts.referenceNumber;
3870
+ if (!ref && opts.accessToken) {
3871
+ ref = await this.findSelfReferenceNumber(opts.accessToken);
3872
+ }
3873
+ if (!ref) {
3874
+ throw new KSeFError(
3875
+ "Could not determine the current token reference number: no cache, JWT lacks the field, and the active-token list had 0 or 2+ matches in the current context."
3876
+ );
3877
+ }
3878
+ try {
3879
+ await this.revokeToken(ref);
3880
+ return { referenceNumber: ref, alreadyRevoked: false };
3881
+ } catch (err) {
3882
+ if (err instanceof KSeFApiError && (err.statusCode === 404 || err.statusCode === 409 || err.statusCode === 410)) {
3883
+ return { referenceNumber: ref, alreadyRevoked: true };
3884
+ }
3885
+ throw err;
3886
+ }
3887
+ }
3406
3888
  };
3407
3889
  }
3408
3890
  });
@@ -4031,8 +4513,8 @@ function computeRootDigest(doc) {
4031
4513
  return crypto3.createHash("sha256").update(canonical, "utf-8").digest("base64");
4032
4514
  }
4033
4515
  function computeSignedPropertiesDigest(qualifyingPropertiesXml) {
4034
- const parser = new DOMParser2();
4035
- const qpDoc = parser.parseFromString(qualifyingPropertiesXml, "text/xml");
4516
+ const parser2 = new DOMParser2();
4517
+ const qpDoc = parser2.parseFromString(qualifyingPropertiesXml, "text/xml");
4036
4518
  const signedProps = findElementByLocalName(qpDoc.documentElement, "SignedProperties");
4037
4519
  if (!signedProps) {
4038
4520
  throw new Error("SignedProperties element not found in QualifyingProperties");
@@ -4184,8 +4666,8 @@ var init_signature_service = __esm({
4184
4666
  const isEc = privateKey.asymmetricKeyType === "ec";
4185
4667
  const signatureAlgorithm = isEc ? ECDSA_SHA256_SIGNATURE : RSA_SHA256_SIGNATURE;
4186
4668
  const signingTime = new Date(Date.now() + CLOCK_SKEW_BUFFER_MS).toISOString();
4187
- const parser = new DOMParser2();
4188
- const doc = parser.parseFromString(xml, "text/xml");
4669
+ const parser2 = new DOMParser2();
4670
+ const doc = parser2.parseFromString(xml, "text/xml");
4189
4671
  const root = doc.documentElement;
4190
4672
  if (!root) {
4191
4673
  throw new Error("XML document has no root element");
@@ -4205,7 +4687,7 @@ var init_signature_service = __esm({
4205
4687
  rootDigest,
4206
4688
  signedPropertiesDigest
4207
4689
  );
4208
- const signedInfoDoc = parser.parseFromString(signedInfoXml, "text/xml");
4690
+ const signedInfoDoc = parser2.parseFromString(signedInfoXml, "text/xml");
4209
4691
  const canonicalSignedInfo = canonicalize(signedInfoDoc.documentElement);
4210
4692
  const signatureValue = computeSignatureValue(
4211
4693
  canonicalSignedInfo,
@@ -4218,7 +4700,7 @@ var init_signature_service = __esm({
4218
4700
  certBase64,
4219
4701
  qualifyingPropertiesXml
4220
4702
  );
4221
- const signatureDoc = parser.parseFromString(signatureXml, "text/xml");
4703
+ const signatureDoc = parser2.parseFromString(signatureXml, "text/xml");
4222
4704
  const importedNode = doc.importNode(signatureDoc.documentElement, true);
4223
4705
  root.appendChild(importedNode);
4224
4706
  return new XMLSerializer().serializeToString(doc);
@@ -5057,6 +5539,7 @@ var init_client = __esm({
5057
5539
  const tokens = await this.auth.getAccessToken(authToken);
5058
5540
  this.authManager.setAccessToken(tokens.accessToken.token);
5059
5541
  this.authManager.setRefreshToken(tokens.refreshToken.token);
5542
+ return { clientIp: challenge.clientIp };
5060
5543
  }
5061
5544
  async loginWithCertificate(certPem, keyPem, nip, keyPassword) {
5062
5545
  const challenge = await this.auth.getChallenge();
@@ -5069,11 +5552,12 @@ var init_client = __esm({
5069
5552
  const tokens = await this.auth.getAccessToken(authToken);
5070
5553
  this.authManager.setAccessToken(tokens.accessToken.token);
5071
5554
  this.authManager.setRefreshToken(tokens.refreshToken.token);
5555
+ return { clientIp: challenge.clientIp };
5072
5556
  }
5073
5557
  async loginWithPkcs12(p12, password, nip) {
5074
5558
  const { Pkcs12Loader: Pkcs12Loader2 } = await Promise.resolve().then(() => (init_pkcs12_loader(), pkcs12_loader_exports));
5075
5559
  const { certificatePem, privateKeyPem } = Pkcs12Loader2.load(p12, password);
5076
- await this.loginWithCertificate(certificatePem, privateKeyPem, nip);
5560
+ return this.loginWithCertificate(certificatePem, privateKeyPem, nip);
5077
5561
  }
5078
5562
  async awaitAuthReady(referenceNumber, authToken) {
5079
5563
  for (let i = 0; i < 30; i++) {
@@ -5125,6 +5609,7 @@ var PERMISSION_DESCRIPTION_MAX_LENGTH = 256;
5125
5609
  init_xml_to_object();
5126
5610
  init_schema_registry();
5127
5611
  init_invoice_validator();
5612
+ init_char_validity();
5128
5613
 
5129
5614
  // src/models/index.ts
5130
5615
  init_document_structures();
@@ -5816,51 +6301,7 @@ function escapeXml2(str) {
5816
6301
 
5817
6302
  // src/utils/index.ts
5818
6303
  init_zip();
5819
-
5820
- // src/utils/jwt.ts
5821
- function decodeJwtPayload(token) {
5822
- const parts = token.split(".");
5823
- if (parts.length !== 3) return null;
5824
- try {
5825
- const payload = parts[1];
5826
- const json = Buffer.from(payload, "base64url").toString("utf-8");
5827
- return JSON.parse(json);
5828
- } catch {
5829
- return null;
5830
- }
5831
- }
5832
- function tryParseJson(value) {
5833
- if (typeof value !== "string") return void 0;
5834
- try {
5835
- return JSON.parse(value);
5836
- } catch {
5837
- return void 0;
5838
- }
5839
- }
5840
- function tryParseJsonArray(value) {
5841
- if (typeof value !== "string") return void 0;
5842
- try {
5843
- const parsed = JSON.parse(value);
5844
- return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
5845
- } catch {
5846
- return void 0;
5847
- }
5848
- }
5849
- function parseKSeFTokenContext(token) {
5850
- const raw = decodeJwtPayload(token);
5851
- if (!raw) return null;
5852
- return {
5853
- type: typeof raw["typ"] === "string" ? raw["typ"] : void 0,
5854
- contextIdentifierType: typeof raw["cit"] === "string" ? raw["cit"] : void 0,
5855
- contextIdentifierValue: typeof raw["civ"] === "string" ? raw["civ"] : void 0,
5856
- authMethod: typeof raw["aum"] === "string" ? raw["aum"] : void 0,
5857
- permissions: tryParseJsonArray(raw["per"]),
5858
- subjectDetails: tryParseJson(raw["sud"]),
5859
- authorSubjectIdentifier: tryParseJson(raw["asi"]),
5860
- issuedAt: typeof raw["iat"] === "number" ? raw["iat"] : void 0,
5861
- expiresAt: typeof raw["exp"] === "number" ? raw["exp"] : void 0
5862
- };
5863
- }
6304
+ init_jwt();
5864
6305
 
5865
6306
  // src/utils/hash.ts
5866
6307
  import crypto6 from "crypto";
@@ -6056,6 +6497,524 @@ function nonEmptyString(value) {
6056
6497
  return typeof value === "string" && value.length > 0 ? value : void 0;
6057
6498
  }
6058
6499
 
6500
+ // src/xml/xml-engine.ts
6501
+ import { XMLBuilder, XMLParser as XMLParser3 } from "fast-xml-parser";
6502
+ var XML_DECLARATION = '<?xml version="1.0" encoding="UTF-8"?>\n';
6503
+ var parser = new XMLParser3({
6504
+ ignoreAttributes: false,
6505
+ preserveOrder: true,
6506
+ attributeNamePrefix: "@_",
6507
+ textNodeName: "#text",
6508
+ allowBooleanAttributes: true,
6509
+ // Preserve leading zeros and keep everything as strings — KSeF fields like
6510
+ // KRS (`\d{10}`) and NIP (`\d{10}`) would otherwise be lossy through parse.
6511
+ parseTagValue: false,
6512
+ parseAttributeValue: false,
6513
+ trimValues: false
6514
+ });
6515
+ var builder = new XMLBuilder({
6516
+ ignoreAttributes: false,
6517
+ preserveOrder: true,
6518
+ attributeNamePrefix: "@_",
6519
+ textNodeName: "#text",
6520
+ format: false,
6521
+ suppressBooleanAttributes: false,
6522
+ suppressEmptyNode: false,
6523
+ processEntities: true
6524
+ });
6525
+ function createObjectBuilder(pretty = false) {
6526
+ return new XMLBuilder({
6527
+ ignoreAttributes: false,
6528
+ preserveOrder: false,
6529
+ attributeNamePrefix: "@_",
6530
+ textNodeName: "#text",
6531
+ format: pretty,
6532
+ suppressBooleanAttributes: false,
6533
+ suppressEmptyNode: false,
6534
+ processEntities: true
6535
+ });
6536
+ }
6537
+ function prependDeclaration(xml) {
6538
+ return xml.startsWith("<?xml") ? xml : `${XML_DECLARATION}${xml}`;
6539
+ }
6540
+ function parseXml(xml) {
6541
+ return parser.parse(xml);
6542
+ }
6543
+ function buildXml(document) {
6544
+ return prependDeclaration(builder.build(document));
6545
+ }
6546
+ function buildXmlFromObject(document, options) {
6547
+ return prependDeclaration(createObjectBuilder(options?.pretty).build(document));
6548
+ }
6549
+ function stripBom(input) {
6550
+ return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
6551
+ }
6552
+
6553
+ // src/xml/order-map.ts
6554
+ var ORDER_MAP = {
6555
+ Faktura: ["Naglowek", "Podmiot1", "Podmiot2", "Podmiot3", "Fa", "Stopka"],
6556
+ Naglowek: ["KodFormularza", "WariantFormularza", "DataWytworzeniaFa", "SystemInfo"],
6557
+ Podmiot1: [
6558
+ "PrefiksPodatnika",
6559
+ "NrEORI",
6560
+ "DaneIdentyfikacyjne",
6561
+ "Adres",
6562
+ "AdresKoresp",
6563
+ "DaneKontaktowe",
6564
+ "StatusInfoPodatnika"
6565
+ ],
6566
+ Podmiot2: [
6567
+ "NrEORI",
6568
+ "DaneIdentyfikacyjne",
6569
+ "Adres",
6570
+ "AdresKoresp",
6571
+ "DaneKontaktowe",
6572
+ "NrKlienta",
6573
+ "IDNabywcy",
6574
+ "JST",
6575
+ "GV"
6576
+ ],
6577
+ Podmiot3: [
6578
+ "IDNabywcy",
6579
+ "NrEORI",
6580
+ "DaneIdentyfikacyjne",
6581
+ "Adres",
6582
+ "AdresKoresp",
6583
+ "DaneKontaktowe",
6584
+ "Rola",
6585
+ "Udzial"
6586
+ ],
6587
+ DaneIdentyfikacyjne: [
6588
+ "NIP",
6589
+ "IDWew",
6590
+ "KodUE",
6591
+ "NrVatUE",
6592
+ "KodKraju",
6593
+ "NrID",
6594
+ "BrakID",
6595
+ "Nazwa",
6596
+ "Identyfikator",
6597
+ "KRS"
6598
+ ],
6599
+ Adres: ["KodKraju", "AdresL1", "AdresL2", "AdresL3"],
6600
+ DaneKontaktowe: ["Email", "Telefon"],
6601
+ Fa: [
6602
+ "KodWaluty",
6603
+ "P_1",
6604
+ "P_1M",
6605
+ "P_2",
6606
+ "WZ",
6607
+ "P_6",
6608
+ "OkresFa",
6609
+ // Multi-rate interleave per VAT group — DO NOT flatten into P_13_* block then P_14_* block.
6610
+ // See smekcio TS d1ec8fe and the "multi-rate interleave" regression test.
6611
+ "P_13_1",
6612
+ "P_14_1",
6613
+ "P_14_1W",
6614
+ "P_13_2",
6615
+ "P_14_2",
6616
+ "P_14_2W",
6617
+ "P_13_3",
6618
+ "P_14_3",
6619
+ "P_14_3W",
6620
+ "P_13_4",
6621
+ "P_14_4",
6622
+ "P_14_4W",
6623
+ "P_13_5",
6624
+ "P_14_5",
6625
+ "P_13_6_1",
6626
+ "P_13_6_2",
6627
+ "P_13_6_3",
6628
+ "P_13_7",
6629
+ "P_13_8",
6630
+ "P_13_9",
6631
+ "P_13_10",
6632
+ "P_13_11",
6633
+ "P_15",
6634
+ "KursWalutyZ",
6635
+ "Adnotacje",
6636
+ "RodzajFaktury",
6637
+ "PrzyczynaKorekty",
6638
+ "TypKorekty",
6639
+ "DaneFaKorygowanej",
6640
+ "OkresFaKorygowanej",
6641
+ "NrFaKorygowany",
6642
+ "Podmiot1K",
6643
+ "Podmiot2K",
6644
+ "Podmiot3K",
6645
+ "ZaliczkaCzesciowa",
6646
+ "FP",
6647
+ "TP",
6648
+ "DodatkowyOpis",
6649
+ "FakturaZaliczkowa",
6650
+ "ZwrotAkcyzy",
6651
+ "FaWiersz",
6652
+ "FaWiersze",
6653
+ "Rozliczenie",
6654
+ "Platnosc"
6655
+ ],
6656
+ Adnotacje: ["P_16", "P_17", "P_18", "P_18A", "Zwolnienie", "NoweSrodkiTransportu", "P_23", "PMarzy"],
6657
+ OkresFa: ["P_6_Od", "P_6_Do"],
6658
+ FaWiersz: [
6659
+ "NrWierszaFa",
6660
+ "UU_ID",
6661
+ "P_6A",
6662
+ "P_7",
6663
+ "Indeks",
6664
+ "GTIN",
6665
+ "PKWiU",
6666
+ "CN",
6667
+ "PKOB",
6668
+ "P_8A",
6669
+ "P_8B",
6670
+ "P_9A",
6671
+ "P_9B",
6672
+ "P_10",
6673
+ "P_11",
6674
+ "P_11A",
6675
+ "P_11Vat",
6676
+ "P_12",
6677
+ "P_12_XII",
6678
+ "P_12_Zal_15",
6679
+ "KwotaAkcyzy",
6680
+ "GTU",
6681
+ "Procedura",
6682
+ "KursWaluty",
6683
+ "StanPrzed"
6684
+ ]
6685
+ };
6686
+ function comparePKey(a, b) {
6687
+ const normalize = (value) => value.replace(/^P_/, "").split("_").map((part) => Number.isNaN(Number(part)) ? part : Number(part));
6688
+ const aParts = normalize(a);
6689
+ const bParts = normalize(b);
6690
+ const max = Math.max(aParts.length, bParts.length);
6691
+ for (let i = 0; i < max; i += 1) {
6692
+ const left = aParts[i];
6693
+ const right = bParts[i];
6694
+ if (left === void 0) return -1;
6695
+ if (right === void 0) return 1;
6696
+ if (typeof left === "number" && typeof right === "number") {
6697
+ if (left !== right) return left - right;
6698
+ continue;
6699
+ }
6700
+ const leftStr = String(left);
6701
+ const rightStr = String(right);
6702
+ if (leftStr !== rightStr) return leftStr < rightStr ? -1 : 1;
6703
+ }
6704
+ return 0;
6705
+ }
6706
+ function isObject(value) {
6707
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6708
+ }
6709
+ function normalizeValueForKey(key, value) {
6710
+ if (Array.isArray(value)) {
6711
+ return value.map(
6712
+ (item) => isObject(item) ? orderXmlObject(item, key) : normalizeValue(item)
6713
+ );
6714
+ }
6715
+ if (isObject(value)) return orderXmlObject(value, key);
6716
+ return value;
6717
+ }
6718
+ function normalizeValue(value) {
6719
+ if (Array.isArray(value)) return value.map((item) => normalizeValue(item));
6720
+ if (isObject(value)) return orderXmlObject(value);
6721
+ return value;
6722
+ }
6723
+ function orderXmlObject(value, contextKey) {
6724
+ const order = contextKey ? ORDER_MAP[contextKey] : void 0;
6725
+ const keys = Object.keys(value);
6726
+ const used = /* @__PURE__ */ new Set();
6727
+ const ordered = {};
6728
+ if (order) {
6729
+ for (const key of order) {
6730
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
6731
+ const item = value[key];
6732
+ if (item !== void 0) ordered[key] = normalizeValueForKey(key, item);
6733
+ used.add(key);
6734
+ }
6735
+ }
6736
+ }
6737
+ const pKeys = keys.filter((key) => !used.has(key) && key.startsWith("P_")).sort(comparePKey);
6738
+ for (const key of pKeys) {
6739
+ const item = value[key];
6740
+ if (item !== void 0) ordered[key] = normalizeValueForKey(key, item);
6741
+ used.add(key);
6742
+ }
6743
+ for (const key of keys) {
6744
+ if (used.has(key)) continue;
6745
+ const item = value[key];
6746
+ if (item !== void 0) ordered[key] = normalizeValueForKey(key, item);
6747
+ }
6748
+ return ordered;
6749
+ }
6750
+
6751
+ // src/xml/faktura-builder.ts
6752
+ var FAKTURA_NAMESPACE = {
6753
+ FA2: "http://crd.gov.pl/wzor/2023/06/29/12648/",
6754
+ FA3: "http://crd.gov.pl/wzor/2025/06/25/13775/"
6755
+ };
6756
+ var ETD_NAMESPACE = {
6757
+ FA2: "http://crd.gov.pl/xml/schematy/2020/10/08/eDokumenty",
6758
+ FA3: "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2022/01/05/eD/DefinicjeTypy/"
6759
+ };
6760
+ function toKodFormularza(formCode) {
6761
+ return {
6762
+ "@_kodSystemowy": formCode.systemCode,
6763
+ "@_wersjaSchemy": formCode.schemaVersion,
6764
+ "#text": formCode.value
6765
+ };
6766
+ }
6767
+ function isFormCodeShape(value) {
6768
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
6769
+ const candidate = value;
6770
+ return typeof candidate.systemCode === "string" && typeof candidate.schemaVersion === "string" && typeof candidate.value === "string";
6771
+ }
6772
+ function isObject2(value) {
6773
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6774
+ }
6775
+ function normalizeTopLevelChild(key, value) {
6776
+ if (key === "Naglowek" && isObject2(value)) {
6777
+ return normalizeNaglowek(value);
6778
+ }
6779
+ if (Array.isArray(value)) {
6780
+ return value.map((item) => isObject2(item) ? orderXmlObject(item, key) : item);
6781
+ }
6782
+ if (isObject2(value)) return orderXmlObject(value, key);
6783
+ return value;
6784
+ }
6785
+ function normalizeNaglowek(value) {
6786
+ const result = {};
6787
+ for (const [key, item] of Object.entries(value)) {
6788
+ if (item === void 0) continue;
6789
+ if (key === "KodFormularza" && isFormCodeShape(item)) {
6790
+ result[key] = toKodFormularza(item);
6791
+ continue;
6792
+ }
6793
+ if (Array.isArray(item)) {
6794
+ result[key] = item.map(
6795
+ (entry) => isObject2(entry) ? orderXmlObject(entry, key) : entry
6796
+ );
6797
+ continue;
6798
+ }
6799
+ if (isObject2(item)) {
6800
+ result[key] = orderXmlObject(item, key);
6801
+ continue;
6802
+ }
6803
+ result[key] = item;
6804
+ }
6805
+ return result;
6806
+ }
6807
+ function normalizeTopLevel(input) {
6808
+ const result = {};
6809
+ for (const [key, value] of Object.entries(input)) {
6810
+ if (value === void 0) continue;
6811
+ result[key] = normalizeTopLevelChild(key, value);
6812
+ }
6813
+ return result;
6814
+ }
6815
+ function buildFakturaXml(faktura, options = {}) {
6816
+ const schema = options.schema ?? "FA3";
6817
+ const fakturaNamespace = options.fakturaNamespace ?? FAKTURA_NAMESPACE[schema];
6818
+ const etdNamespace = options.etdNamespace ?? ETD_NAMESPACE[schema];
6819
+ const normalized = normalizeTopLevel(faktura);
6820
+ const ordered = orderXmlObject(normalized, "Faktura");
6821
+ const document = {
6822
+ Faktura: {
6823
+ ...ordered,
6824
+ "@_xmlns": fakturaNamespace,
6825
+ "@_xmlns:etd": etdNamespace
6826
+ }
6827
+ };
6828
+ return buildXmlFromObject(document, { pretty: options.pretty });
6829
+ }
6830
+ function isFakturaInput(input) {
6831
+ if (!isObject2(input)) return false;
6832
+ const candidate = input;
6833
+ if (!Object.prototype.hasOwnProperty.call(candidate, "Naglowek")) return false;
6834
+ if (!Object.prototype.hasOwnProperty.call(candidate, "Fa")) return false;
6835
+ return isObject2(candidate.Naglowek) && isObject2(candidate.Fa);
6836
+ }
6837
+
6838
+ // src/xml/pef-builder.ts
6839
+ init_ksef_validation_error();
6840
+ var PEF_NAMESPACE = {
6841
+ PEF: "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
6842
+ PEF_KOR: "urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"
6843
+ };
6844
+ var UBL_EXT_NS = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2";
6845
+ var UBL_CBC_NS = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
6846
+ var UBL_CAC_NS = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2";
6847
+ var UBL_CBC_PL_NS = "urn:pl:extended:CommonBasicComponents-2";
6848
+ var UBL_CAC_PL_NS = "urn:pl:extended:CommonAggregateComponents-2";
6849
+ function isPefUblDocumentInput(input) {
6850
+ if (typeof input !== "object" || input === null || Array.isArray(input)) return false;
6851
+ const obj = input;
6852
+ const invoice = obj.Invoice;
6853
+ const creditNote = obj.CreditNote;
6854
+ const hasInvoice = typeof invoice === "object" && invoice !== null && !Array.isArray(invoice);
6855
+ const hasCreditNote = typeof creditNote === "object" && creditNote !== null && !Array.isArray(creditNote);
6856
+ return hasInvoice !== hasCreditNote;
6857
+ }
6858
+ function inferSchema(input) {
6859
+ return "Invoice" in input ? "PEF" : "PEF_KOR";
6860
+ }
6861
+ function isNonArrayObject(value) {
6862
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6863
+ }
6864
+ function assertPefShape(input) {
6865
+ if (!isNonArrayObject(input)) {
6866
+ throw new KSeFValidationError("PEF input must be a non-array object.");
6867
+ }
6868
+ const hasInvoiceKey = "Invoice" in input;
6869
+ const hasCreditNoteKey = "CreditNote" in input;
6870
+ if (hasInvoiceKey && hasCreditNoteKey) {
6871
+ throw new KSeFValidationError(
6872
+ "PEF input must contain exactly one of `Invoice` or `CreditNote`, not both."
6873
+ );
6874
+ }
6875
+ if (!hasInvoiceKey && !hasCreditNoteKey) {
6876
+ throw new KSeFValidationError(
6877
+ "PEF input must contain either an `Invoice` or a `CreditNote` root element."
6878
+ );
6879
+ }
6880
+ const rootKey = hasInvoiceKey ? "Invoice" : "CreditNote";
6881
+ if (!isNonArrayObject(input[rootKey])) {
6882
+ throw new KSeFValidationError(
6883
+ `PEF \`${rootKey}\` value must be a non-array object.`
6884
+ );
6885
+ }
6886
+ }
6887
+ function buildPefXml(input, options = {}) {
6888
+ assertPefShape(input);
6889
+ const inferred = inferSchema(input);
6890
+ const schema = options.schema ?? input.schema ?? inferred;
6891
+ if (schema !== inferred) {
6892
+ throw new KSeFValidationError(
6893
+ `PEF schema mismatch: expected ${inferred} based on root element, got ${schema}.`
6894
+ );
6895
+ }
6896
+ const commonNamespaces = {
6897
+ "@_xmlns:ext": UBL_EXT_NS,
6898
+ "@_xmlns:cbc": UBL_CBC_NS,
6899
+ "@_xmlns:cac": UBL_CAC_NS,
6900
+ "@_xmlns:cbc-pl": UBL_CBC_PL_NS,
6901
+ "@_xmlns:cac-pl": UBL_CAC_PL_NS
6902
+ };
6903
+ const document = "Invoice" in input ? {
6904
+ Invoice: {
6905
+ ...input.Invoice,
6906
+ "@_xmlns": PEF_NAMESPACE.PEF,
6907
+ ...commonNamespaces
6908
+ }
6909
+ } : {
6910
+ CreditNote: {
6911
+ ...input.CreditNote,
6912
+ "@_xmlns": PEF_NAMESPACE.PEF_KOR,
6913
+ ...commonNamespaces
6914
+ }
6915
+ };
6916
+ return buildXmlFromObject(document, { pretty: options.pretty });
6917
+ }
6918
+
6919
+ // src/xml/invoice-serializer.ts
6920
+ init_ksef_validation_error();
6921
+ var FAKTURA_SCHEMAS = /* @__PURE__ */ new Set(["FA2", "FA3"]);
6922
+ var PEF_SCHEMAS = /* @__PURE__ */ new Set(["PEF", "PEF_KOR"]);
6923
+ function isNonArrayObject2(value) {
6924
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6925
+ }
6926
+ function classifyUnknownObject(input) {
6927
+ const looksLikeFaktura = "Naglowek" in input || "Fa" in input || "Podmiot1" in input || "Podmiot2" in input;
6928
+ const hasInvoice = "Invoice" in input;
6929
+ const hasCreditNote = "CreditNote" in input;
6930
+ if (hasInvoice && hasCreditNote) {
6931
+ return new KSeFValidationError(
6932
+ "Input must contain exactly one of `Invoice` or `CreditNote`, not both."
6933
+ );
6934
+ }
6935
+ if (hasInvoice !== hasCreditNote) {
6936
+ const rootKey = hasInvoice ? "Invoice" : "CreditNote";
6937
+ if (!isNonArrayObject2(input[rootKey])) {
6938
+ return KSeFValidationError.fromField(
6939
+ rootKey,
6940
+ `PEF \`${rootKey}\` value must be a non-array object.`
6941
+ );
6942
+ }
6943
+ }
6944
+ if (looksLikeFaktura) {
6945
+ const missing = [];
6946
+ if (!("Naglowek" in input)) missing.push("Naglowek");
6947
+ if (!("Fa" in input)) missing.push("Fa");
6948
+ if (missing.length > 0) {
6949
+ return KSeFValidationError.fromField(
6950
+ missing[0],
6951
+ `Faktura input is missing required top-level key(s): ${missing.join(", ")}.`
6952
+ );
6953
+ }
6954
+ for (const key of ["Naglowek", "Fa"]) {
6955
+ if (!isNonArrayObject2(input[key])) {
6956
+ return KSeFValidationError.fromField(
6957
+ key,
6958
+ `Faktura \`${key}\` value must be a non-null, non-array object.`
6959
+ );
6960
+ }
6961
+ }
6962
+ return new KSeFValidationError(
6963
+ "Faktura-like input failed shape validation: `Naglowek` and `Fa` must be own enumerable properties on the input object."
6964
+ );
6965
+ }
6966
+ return new KSeFValidationError(
6967
+ "Unsupported invoice input shape: expected `FakturaInput` (with `Naglowek` + `Fa`) or `PefUblDocumentInput` (with `Invoice` or `CreditNote`)."
6968
+ );
6969
+ }
6970
+ function serializeInvoiceXml(input, options) {
6971
+ if (Buffer.isBuffer(input)) return input;
6972
+ if (typeof input === "string") {
6973
+ return Buffer.from(stripBom(input), "utf8");
6974
+ }
6975
+ if (Array.isArray(input)) {
6976
+ return Buffer.from(stripBom(buildXml(input)), "utf8");
6977
+ }
6978
+ if (input && typeof input === "object") {
6979
+ const schema = options?.schema;
6980
+ if (isPefUblDocumentInput(input)) {
6981
+ if (schema && !PEF_SCHEMAS.has(schema)) {
6982
+ throw new KSeFValidationError(
6983
+ `schema option ${schema} is not compatible with a PEF / PEF_KOR input.`
6984
+ );
6985
+ }
6986
+ const pefSchema = schema === "PEF" || schema === "PEF_KOR" ? schema : void 0;
6987
+ const xml = buildPefXml(input, {
6988
+ schema: pefSchema,
6989
+ pretty: options?.pretty
6990
+ });
6991
+ return Buffer.from(stripBom(xml), "utf8");
6992
+ }
6993
+ if (isFakturaInput(input)) {
6994
+ if (schema && !FAKTURA_SCHEMAS.has(schema)) {
6995
+ throw new KSeFValidationError(
6996
+ `schema option ${schema} is not compatible with a Faktura input.`
6997
+ );
6998
+ }
6999
+ const fakturaSchema = schema === "FA2" || schema === "FA3" ? schema : void 0;
7000
+ const xml = buildFakturaXml(input, {
7001
+ schema: fakturaSchema,
7002
+ fakturaNamespace: options?.fakturaNamespace,
7003
+ etdNamespace: options?.etdNamespace,
7004
+ pretty: options?.pretty
7005
+ });
7006
+ return Buffer.from(stripBom(xml), "utf8");
7007
+ }
7008
+ throw classifyUnknownObject(input);
7009
+ }
7010
+ throw new KSeFValidationError(
7011
+ "Unsupported invoice input type: expected Buffer, string, XmlDocument, FakturaInput, or PefUblDocumentInput."
7012
+ );
7013
+ }
7014
+ function buildRawXmlString(document, options) {
7015
+ return buildXmlFromObject(document, options);
7016
+ }
7017
+
6059
7018
  // src/workflows/online-session-workflow.ts
6060
7019
  init_invoice_validator();
6061
7020
  init_ksef_validation_error();
@@ -6784,10 +7743,13 @@ export {
6784
7743
  CertificateService,
6785
7744
  CryptographyService,
6786
7745
  DEFAULT_FORM_CODE,
7746
+ DISCOURAGED_UNICODE_RANGES,
6787
7747
  DefaultAuthManager,
6788
7748
  ENFORCE_XADES_COMPLIANCE,
7749
+ ETD_NAMESPACE,
6789
7750
  EntityPermissionGrantBuilder,
6790
7751
  Environment,
7752
+ FAKTURA_NAMESPACE,
6791
7753
  FORM_CODES,
6792
7754
  FORM_CODE_KEYS,
6793
7755
  FileHwmStore,
@@ -6804,9 +7766,13 @@ export {
6804
7766
  KSEF_FEATURE_HEADER,
6805
7767
  KSeFApiError,
6806
7768
  KSeFAuthStatusError,
7769
+ KSeFBadRequestError,
7770
+ KSeFBatchTimeoutError,
6807
7771
  KSeFClient,
6808
7772
  KSeFError,
7773
+ KSeFErrorCode,
6809
7774
  KSeFForbiddenError,
7775
+ KSeFGoneError,
6810
7776
  KSeFRateLimitError,
6811
7777
  KSeFSessionExpiredError,
6812
7778
  KSeFUnauthorizedError,
@@ -6818,8 +7784,10 @@ export {
6818
7784
  LimitsService,
6819
7785
  Nip,
6820
7786
  NipVatUe,
7787
+ ORDER_MAP,
6821
7788
  OfflineInvoiceWorkflow,
6822
7789
  OnlineSessionService,
7790
+ PEF_NAMESPACE,
6823
7791
  PERMISSION_DESCRIPTION_MAX_LENGTH,
6824
7792
  PERMISSION_DESCRIPTION_MIN_LENGTH,
6825
7793
  PeppolId,
@@ -6849,14 +7817,21 @@ export {
6849
7817
  VatUe,
6850
7818
  VerificationLinkService,
6851
7819
  addBusinessDays,
7820
+ assertNever,
6852
7821
  authenticateWithCertificate,
6853
7822
  authenticateWithExternalSignature,
6854
7823
  authenticateWithPkcs12,
6855
7824
  authenticateWithToken,
6856
7825
  batchValidationDetails,
7826
+ buildFakturaXml,
7827
+ buildPefXml,
7828
+ buildRawXmlString,
6857
7829
  buildUnsignedAuthTokenRequestXml,
7830
+ buildXml,
7831
+ buildXmlFromObject,
6858
7832
  calculateBackoff,
6859
7833
  calculateOfflineDeadline,
7834
+ comparePKey,
6860
7835
  createZip,
6861
7836
  decodeJwtPayload,
6862
7837
  deduplicateByKsefNumber,
@@ -6875,6 +7850,9 @@ export {
6875
7850
  getTimeUntilDeadline,
6876
7851
  incrementalExportAndDownload,
6877
7852
  isExpired,
7853
+ isFakturaInput,
7854
+ isFormCodeShape,
7855
+ isPefUblDocumentInput,
6878
7856
  isPolishHoliday,
6879
7857
  isRetryableError,
6880
7858
  isRetryableStatus,
@@ -6896,16 +7874,21 @@ export {
6896
7874
  nextBusinessDay,
6897
7875
  openOnlineSession,
6898
7876
  openSendAndClose,
7877
+ orderXmlObject,
6899
7878
  parseFormCode,
6900
7879
  parseKSeFTokenContext,
6901
7880
  parseRetryAfter,
6902
7881
  parseUpoXml,
7882
+ parseXml,
6903
7883
  pollUntil,
6904
7884
  resolveOptions,
6905
7885
  resumeOnlineSession,
6906
7886
  runWithConcurrency,
7887
+ serializeInvoiceXml,
6907
7888
  sha256Base642 as sha256Base64,
6908
7889
  sleep,
7890
+ stripBom,
7891
+ toKodFormularza,
6909
7892
  unzip,
6910
7893
  updateContinuationPoint,
6911
7894
  uploadBatch,
@@ -6915,6 +7898,7 @@ export {
6915
7898
  validate,
6916
7899
  validateBatch,
6917
7900
  validateBusinessRules,
7901
+ validateCharValidity,
6918
7902
  validateFormCodeForSession,
6919
7903
  validatePresignedUrl,
6920
7904
  validateSchema,