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/cli.js CHANGED
@@ -43,6 +43,9 @@ var init_ksef_api_error = __esm({
43
43
  const message = details?.length ? details.map((d) => d.exceptionDescription ?? "").filter(Boolean).join("; ") || `KSeF API error: HTTP ${statusCode}` : `KSeF API error: HTTP ${statusCode}`;
44
44
  return new _KSeFApiError(message, statusCode, body);
45
45
  }
46
+ toProblemFields() {
47
+ return { detail: this.message };
48
+ }
46
49
  };
47
50
  }
48
51
  });
@@ -54,17 +57,20 @@ var init_ksef_rate_limit_error = __esm({
54
57
  "use strict";
55
58
  init_ksef_api_error();
56
59
  KSeFRateLimitError = class _KSeFRateLimitError extends KSeFApiError {
60
+ statusCode = 429;
57
61
  retryAfterSeconds;
58
62
  retryAfterDate;
59
63
  recommendedDelay;
60
- constructor(message, statusCode, errorResponse, retryAfterSeconds, retryAfterDate) {
64
+ problem;
65
+ constructor(message, statusCode, errorResponse, retryAfterSeconds, retryAfterDate, problem) {
61
66
  super(message, statusCode, errorResponse);
62
67
  this.name = "KSeFRateLimitError";
63
68
  this.retryAfterSeconds = retryAfterSeconds;
64
69
  this.retryAfterDate = retryAfterDate;
65
70
  this.recommendedDelay = retryAfterSeconds ?? 60;
71
+ this.problem = problem;
66
72
  }
67
- static fromRetryAfterHeader(statusCode, retryAfterHeader, body) {
73
+ static fromRetryAfterHeader(statusCode, retryAfterHeader, body, problem) {
68
74
  let retryAfterSeconds;
69
75
  let retryAfterDate;
70
76
  if (retryAfterHeader) {
@@ -79,8 +85,16 @@ var init_ksef_rate_limit_error = __esm({
79
85
  }
80
86
  }
81
87
  }
82
- const message = retryAfterSeconds != null ? `Rate limited. Retry after ${retryAfterSeconds}s` : "Rate limited by KSeF API";
83
- return new _KSeFRateLimitError(message, statusCode, body, retryAfterSeconds, retryAfterDate);
88
+ const message = retryAfterSeconds != null ? `Rate limited. Retry after ${retryAfterSeconds}s` : problem?.detail ?? "Rate limited by KSeF API";
89
+ return new _KSeFRateLimitError(message, statusCode, body, retryAfterSeconds, retryAfterDate, problem);
90
+ }
91
+ toProblemFields() {
92
+ return {
93
+ detail: this.problem?.detail,
94
+ traceId: this.problem?.traceId,
95
+ instance: this.problem?.instance,
96
+ timestamp: this.problem?.timestamp
97
+ };
84
98
  }
85
99
  };
86
100
  }
@@ -91,18 +105,28 @@ var KSeFUnauthorizedError;
91
105
  var init_ksef_unauthorized_error = __esm({
92
106
  "src/errors/ksef-unauthorized-error.ts"() {
93
107
  "use strict";
94
- init_ksef_error();
95
- KSeFUnauthorizedError = class extends KSeFError {
108
+ init_ksef_api_error();
109
+ KSeFUnauthorizedError = class extends KSeFApiError {
96
110
  statusCode = 401;
97
111
  detail;
98
112
  traceId;
99
113
  instance;
114
+ timestamp;
100
115
  constructor(problemDetails) {
101
- super(problemDetails.detail || "Unauthorized");
116
+ super(problemDetails.detail || "Unauthorized", 401);
102
117
  this.name = "KSeFUnauthorizedError";
103
118
  this.detail = problemDetails.detail;
104
119
  this.traceId = problemDetails.traceId;
105
120
  this.instance = problemDetails.instance;
121
+ this.timestamp = problemDetails.timestamp;
122
+ }
123
+ toProblemFields() {
124
+ return {
125
+ detail: this.detail,
126
+ traceId: this.traceId,
127
+ instance: this.instance,
128
+ timestamp: this.timestamp
129
+ };
106
130
  }
107
131
  };
108
132
  }
@@ -113,27 +137,122 @@ var KSeFForbiddenError;
113
137
  var init_ksef_forbidden_error = __esm({
114
138
  "src/errors/ksef-forbidden-error.ts"() {
115
139
  "use strict";
116
- init_ksef_error();
117
- KSeFForbiddenError = class extends KSeFError {
140
+ init_ksef_api_error();
141
+ KSeFForbiddenError = class extends KSeFApiError {
118
142
  statusCode = 403;
119
143
  detail;
120
144
  reasonCode;
121
145
  instance;
122
146
  security;
123
147
  traceId;
148
+ timestamp;
124
149
  constructor(problemDetails) {
125
- super(problemDetails.detail || "Forbidden");
150
+ super(problemDetails.detail || "Forbidden", 403);
126
151
  this.name = "KSeFForbiddenError";
127
152
  this.detail = problemDetails.detail;
128
153
  this.reasonCode = problemDetails.reasonCode;
129
154
  this.instance = problemDetails.instance;
130
155
  this.security = problemDetails.security;
131
156
  this.traceId = problemDetails.traceId;
157
+ this.timestamp = problemDetails.timestamp;
158
+ }
159
+ toProblemFields() {
160
+ return {
161
+ detail: this.detail,
162
+ reasonCode: this.reasonCode,
163
+ security: this.security,
164
+ traceId: this.traceId,
165
+ instance: this.instance,
166
+ timestamp: this.timestamp
167
+ };
168
+ }
169
+ };
170
+ }
171
+ });
172
+
173
+ // src/errors/ksef-gone-error.ts
174
+ var KSeFGoneError;
175
+ var init_ksef_gone_error = __esm({
176
+ "src/errors/ksef-gone-error.ts"() {
177
+ "use strict";
178
+ init_ksef_api_error();
179
+ KSeFGoneError = class extends KSeFApiError {
180
+ statusCode = 410;
181
+ detail;
182
+ instance;
183
+ traceId;
184
+ timestamp;
185
+ constructor(problemDetails) {
186
+ super(problemDetails.detail || "Operation status no longer available (retention expired)", 410);
187
+ this.name = "KSeFGoneError";
188
+ this.detail = problemDetails.detail;
189
+ this.instance = problemDetails.instance;
190
+ this.traceId = problemDetails.traceId;
191
+ this.timestamp = problemDetails.timestamp;
192
+ }
193
+ toProblemFields() {
194
+ return {
195
+ detail: this.detail,
196
+ traceId: this.traceId,
197
+ instance: this.instance,
198
+ timestamp: this.timestamp
199
+ };
132
200
  }
133
201
  };
134
202
  }
135
203
  });
136
204
 
205
+ // src/errors/ksef-bad-request-error.ts
206
+ var KSeFBadRequestError;
207
+ var init_ksef_bad_request_error = __esm({
208
+ "src/errors/ksef-bad-request-error.ts"() {
209
+ "use strict";
210
+ init_ksef_api_error();
211
+ KSeFBadRequestError = class extends KSeFApiError {
212
+ statusCode = 400;
213
+ detail;
214
+ instance;
215
+ errors;
216
+ traceId;
217
+ timestamp;
218
+ constructor(problemDetails) {
219
+ super(problemDetails.detail || problemDetails.title || "Bad Request", 400);
220
+ this.name = "KSeFBadRequestError";
221
+ this.detail = problemDetails.detail;
222
+ this.instance = problemDetails.instance;
223
+ this.errors = problemDetails.errors ?? [];
224
+ this.traceId = problemDetails.traceId;
225
+ this.timestamp = problemDetails.timestamp;
226
+ }
227
+ toProblemFields() {
228
+ return {
229
+ detail: this.detail,
230
+ errors: this.errors.length ? this.errors : void 0,
231
+ traceId: this.traceId,
232
+ instance: this.instance,
233
+ timestamp: this.timestamp
234
+ };
235
+ }
236
+ };
237
+ }
238
+ });
239
+
240
+ // src/errors/ksef-auth-status-error.ts
241
+ var init_ksef_auth_status_error = __esm({
242
+ "src/errors/ksef-auth-status-error.ts"() {
243
+ "use strict";
244
+ init_ksef_error();
245
+ }
246
+ });
247
+
248
+ // src/errors/ksef-session-expired-error.ts
249
+ var init_ksef_session_expired_error = __esm({
250
+ "src/errors/ksef-session-expired-error.ts"() {
251
+ "use strict";
252
+ init_ksef_error();
253
+ }
254
+ });
255
+
137
256
  // src/errors/ksef-validation-error.ts
138
257
  var ksef_validation_error_exports = {};
139
258
  __export(ksef_validation_error_exports, {
@@ -162,6 +281,72 @@ var init_ksef_validation_error = __esm({
162
281
  }
163
282
  });
164
283
 
284
+ // src/errors/error-codes.ts
285
+ function hasErrorCode(body, code) {
286
+ return !!body?.exception?.exceptionDetailList?.some((d) => d.exceptionCode === code);
287
+ }
288
+ var KSeFErrorCode;
289
+ var init_error_codes = __esm({
290
+ "src/errors/error-codes.ts"() {
291
+ "use strict";
292
+ KSeFErrorCode = {
293
+ BatchTimeout: 21208,
294
+ DuplicateInvoice: 440
295
+ };
296
+ }
297
+ });
298
+
299
+ // src/errors/ksef-batch-timeout-error.ts
300
+ var KSeFBatchTimeoutError;
301
+ var init_ksef_batch_timeout_error = __esm({
302
+ "src/errors/ksef-batch-timeout-error.ts"() {
303
+ "use strict";
304
+ init_ksef_api_error();
305
+ init_error_codes();
306
+ KSeFBatchTimeoutError = class _KSeFBatchTimeoutError extends KSeFApiError {
307
+ errorCode = KSeFErrorCode.BatchTimeout;
308
+ constructor(message, statusCode, errorResponse) {
309
+ super(message, statusCode, errorResponse);
310
+ this.name = "KSeFBatchTimeoutError";
311
+ }
312
+ static fromResponse(statusCode, body) {
313
+ const detail = body?.exception?.exceptionDetailList?.find(
314
+ (d) => d.exceptionCode === KSeFErrorCode.BatchTimeout
315
+ );
316
+ const message = detail?.exceptionDescription?.trim() || "Batch session timed out before the server completed processing (KSeF 21208).";
317
+ return new _KSeFBatchTimeoutError(message, statusCode, body);
318
+ }
319
+ };
320
+ }
321
+ });
322
+
323
+ // src/errors/assert-never.ts
324
+ var init_assert_never = __esm({
325
+ "src/errors/assert-never.ts"() {
326
+ "use strict";
327
+ }
328
+ });
329
+
330
+ // src/errors/index.ts
331
+ var init_errors = __esm({
332
+ "src/errors/index.ts"() {
333
+ "use strict";
334
+ init_ksef_error();
335
+ init_ksef_api_error();
336
+ init_ksef_rate_limit_error();
337
+ init_ksef_unauthorized_error();
338
+ init_ksef_forbidden_error();
339
+ init_ksef_gone_error();
340
+ init_ksef_bad_request_error();
341
+ init_ksef_auth_status_error();
342
+ init_ksef_session_expired_error();
343
+ init_ksef_validation_error();
344
+ init_ksef_batch_timeout_error();
345
+ init_error_codes();
346
+ init_assert_never();
347
+ }
348
+ });
349
+
165
350
  // src/config/environments.ts
166
351
  var Environment;
167
352
  var init_environments = __esm({
@@ -197,7 +382,8 @@ function resolveOptions(options = {}) {
197
382
  apiVersion: options.apiVersion ?? DEFAULT_API_VERSION,
198
383
  timeout: options.timeout ?? DEFAULT_TIMEOUT,
199
384
  customHeaders: options.customHeaders ?? {},
200
- environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST")
385
+ environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST"),
386
+ errorFormat: options.errorFormat ?? "problem-details"
201
387
  };
202
388
  }
203
389
  var DEFAULT_API_VERSION, DEFAULT_TIMEOUT;
@@ -388,6 +574,27 @@ var init_presigned_url_policy = __esm({
388
574
 
389
575
  // src/http/rest-client.ts
390
576
  import { consola as consola3 } from "consola";
577
+ function isBadRequestProblem(value) {
578
+ if (typeof value !== "object" || value === null) return false;
579
+ const v = value;
580
+ if (typeof v.title !== "string") return false;
581
+ if (v.status !== void 0 && typeof v.status !== "number") return false;
582
+ if (v.errors !== void 0) {
583
+ if (!Array.isArray(v.errors)) return false;
584
+ for (const item of v.errors) {
585
+ if (typeof item !== "object" || item === null) return false;
586
+ const detail = item;
587
+ if (typeof detail.code !== "number") return false;
588
+ if (typeof detail.description !== "string") return false;
589
+ }
590
+ }
591
+ return true;
592
+ }
593
+ function isTooManyRequestsProblem(value) {
594
+ if (typeof value !== "object" || value === null) return false;
595
+ const v = value;
596
+ 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");
597
+ }
391
598
  var RestClient;
392
599
  var init_rest_client = __esm({
393
600
  "src/http/rest-client.ts"() {
@@ -396,6 +603,10 @@ var init_rest_client = __esm({
396
603
  init_ksef_rate_limit_error();
397
604
  init_ksef_unauthorized_error();
398
605
  init_ksef_forbidden_error();
606
+ init_ksef_gone_error();
607
+ init_ksef_bad_request_error();
608
+ init_ksef_batch_timeout_error();
609
+ init_error_codes();
399
610
  init_route_builder();
400
611
  init_transport();
401
612
  init_retry_policy();
@@ -482,6 +693,10 @@ var init_rest_client = __esm({
482
693
  ...this.options.customHeaders,
483
694
  ...request.getHeaders()
484
695
  };
696
+ const hasHeader = (name) => Object.keys(headers).some((header) => header.toLowerCase() === name.toLowerCase());
697
+ if (this.options.errorFormat !== "legacy" && !hasHeader("x-error-format")) {
698
+ headers["X-Error-Format"] = "problem-details";
699
+ }
485
700
  if (!headers["Authorization"] && this.authManager) {
486
701
  const token = overrideToken ?? this.authManager.getAccessToken();
487
702
  if (token) {
@@ -520,34 +735,70 @@ var init_rest_client = __esm({
520
735
  async ensureSuccess(response) {
521
736
  if (response.ok) return;
522
737
  const text = await response.text().catch(() => "");
738
+ let jsonCache = null;
523
739
  const parseJson = () => {
524
- try {
525
- return JSON.parse(text);
526
- } catch {
527
- return void 0;
740
+ if (jsonCache === null) {
741
+ try {
742
+ jsonCache = { value: JSON.parse(text) };
743
+ } catch {
744
+ jsonCache = { value: void 0 };
745
+ }
528
746
  }
747
+ return jsonCache.value;
529
748
  };
530
- if (response.status === 429) {
749
+ const tryParseProblem = (guard) => {
531
750
  const parsed = parseJson();
751
+ return parsed !== void 0 && guard(parsed) ? parsed : void 0;
752
+ };
753
+ if (response.status === 400) {
754
+ const problem = tryParseProblem(isBadRequestProblem);
755
+ if (problem) {
756
+ throw new KSeFBadRequestError(problem);
757
+ }
758
+ const legacy = parseJson();
759
+ if (hasErrorCode(legacy, KSeFErrorCode.BatchTimeout)) {
760
+ throw KSeFBatchTimeoutError.fromResponse(400, legacy);
761
+ }
762
+ throw KSeFApiError.fromResponse(400, legacy);
763
+ }
764
+ if (response.status === 429) {
765
+ const problem = tryParseProblem(isTooManyRequestsProblem);
766
+ const legacy = problem ? void 0 : parseJson();
532
767
  throw KSeFRateLimitError.fromRetryAfterHeader(
533
768
  response.status,
534
769
  response.headers.get("Retry-After"),
535
- parsed
770
+ legacy,
771
+ problem
536
772
  );
537
773
  }
538
774
  if (response.status === 401) {
539
- const body = parseJson();
540
- if (body?.detail) {
541
- throw new KSeFUnauthorizedError(body);
775
+ const body2 = parseJson();
776
+ if (body2?.detail) {
777
+ throw new KSeFUnauthorizedError(body2);
542
778
  }
543
779
  }
544
780
  if (response.status === 403) {
545
- const body = parseJson();
546
- if (body?.reasonCode) {
547
- throw new KSeFForbiddenError(body);
781
+ const body2 = parseJson();
782
+ if (body2?.reasonCode) {
783
+ throw new KSeFForbiddenError(body2);
548
784
  }
549
785
  }
550
- throw KSeFApiError.fromResponse(response.status, parseJson());
786
+ if (response.status === 410) {
787
+ const body2 = parseJson();
788
+ throw new KSeFGoneError({
789
+ title: body2?.title || "Gone",
790
+ status: body2?.status || 410,
791
+ detail: body2?.detail || "Operation status no longer available (retention expired)",
792
+ instance: body2?.instance,
793
+ traceId: body2?.traceId,
794
+ timestamp: body2?.timestamp
795
+ });
796
+ }
797
+ const body = parseJson();
798
+ if (hasErrorCode(body, KSeFErrorCode.BatchTimeout)) {
799
+ throw KSeFBatchTimeoutError.fromResponse(response.status, body);
800
+ }
801
+ throw KSeFApiError.fromResponse(response.status, body);
551
802
  }
552
803
  };
553
804
  }
@@ -1251,9 +1502,10 @@ var PermissionsService;
1251
1502
  var init_permissions = __esm({
1252
1503
  "src/services/permissions.ts"() {
1253
1504
  "use strict";
1505
+ init_ksef_validation_error();
1254
1506
  init_rest_request();
1255
1507
  init_routes();
1256
- PermissionsService = class {
1508
+ PermissionsService = class _PermissionsService {
1257
1509
  restClient;
1258
1510
  constructor(restClient) {
1259
1511
  this.restClient = restClient;
@@ -1311,6 +1563,7 @@ var init_permissions = __esm({
1311
1563
  }
1312
1564
  // Search methods
1313
1565
  async queryPersonalGrants(options, pageOffset, pageSize) {
1566
+ _PermissionsService.validateContextIdentifier(options?.contextIdentifier);
1314
1567
  const req = RestRequest.post(Routes.Permissions.Query.personalGrants).body(options ?? {});
1315
1568
  if (pageOffset !== void 0) req.query("pageOffset", String(pageOffset));
1316
1569
  if (pageSize !== void 0) req.query("pageSize", String(pageSize));
@@ -1339,6 +1592,7 @@ var init_permissions = __esm({
1339
1592
  return response.body;
1340
1593
  }
1341
1594
  async queryEntitiesGrants(options, pageOffset, pageSize) {
1595
+ _PermissionsService.validateContextIdentifier(options?.contextIdentifier);
1342
1596
  const req = RestRequest.post(Routes.Permissions.Query.entitiesGrants).body(options ?? {});
1343
1597
  if (pageOffset !== void 0) req.query("pageOffset", String(pageOffset));
1344
1598
  if (pageSize !== void 0) req.query("pageSize", String(pageSize));
@@ -1377,17 +1631,90 @@ var init_permissions = __esm({
1377
1631
  const response = await this.restClient.execute(req);
1378
1632
  return response.body;
1379
1633
  }
1634
+ static validateContextIdentifier(ctx) {
1635
+ if (!ctx) return;
1636
+ if (ctx.type === "InternalId") {
1637
+ const len = ctx.value.length;
1638
+ if (len < 10 || len > 16) {
1639
+ throw KSeFValidationError.fromField(
1640
+ "contextIdentifier.value",
1641
+ `InternalId must be 10-16 characters, got ${len}`
1642
+ );
1643
+ }
1644
+ }
1645
+ }
1380
1646
  };
1381
1647
  }
1382
1648
  });
1383
1649
 
1650
+ // src/utils/jwt.ts
1651
+ function decodeJwtPayload(token) {
1652
+ const parts = token.split(".");
1653
+ if (parts.length !== 3) return null;
1654
+ try {
1655
+ const payload = parts[1];
1656
+ const json = Buffer.from(payload, "base64url").toString("utf-8");
1657
+ return JSON.parse(json);
1658
+ } catch {
1659
+ return null;
1660
+ }
1661
+ }
1662
+ function tryParseJson(value) {
1663
+ if (typeof value !== "string") return void 0;
1664
+ try {
1665
+ return JSON.parse(value);
1666
+ } catch {
1667
+ return void 0;
1668
+ }
1669
+ }
1670
+ function tryParseJsonArray(value) {
1671
+ if (typeof value !== "string") return void 0;
1672
+ try {
1673
+ const parsed = JSON.parse(value);
1674
+ return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
1675
+ } catch {
1676
+ return void 0;
1677
+ }
1678
+ }
1679
+ function parseKSeFTokenContext(token) {
1680
+ const raw = decodeJwtPayload(token);
1681
+ if (!raw) return null;
1682
+ return {
1683
+ type: typeof raw["typ"] === "string" ? raw["typ"] : void 0,
1684
+ contextIdentifierType: typeof raw["cit"] === "string" ? raw["cit"] : void 0,
1685
+ contextIdentifierValue: typeof raw["civ"] === "string" ? raw["civ"] : void 0,
1686
+ authMethod: typeof raw["aum"] === "string" ? raw["aum"] : void 0,
1687
+ permissions: tryParseJsonArray(raw["per"]),
1688
+ subjectDetails: tryParseJson(raw["sud"]),
1689
+ authorSubjectIdentifier: tryParseJson(raw["asi"]),
1690
+ issuedAt: typeof raw["iat"] === "number" ? raw["iat"] : void 0,
1691
+ expiresAt: typeof raw["exp"] === "number" ? raw["exp"] : void 0
1692
+ };
1693
+ }
1694
+ var init_jwt = __esm({
1695
+ "src/utils/jwt.ts"() {
1696
+ "use strict";
1697
+ }
1698
+ });
1699
+
1384
1700
  // src/services/tokens.ts
1385
- var TokenService;
1701
+ function toTokenAuthorIdentifierType(value) {
1702
+ return TOKEN_AUTHOR_IDENTIFIER_TYPES.has(value) ? value : void 0;
1703
+ }
1704
+ var TOKEN_AUTHOR_IDENTIFIER_TYPES, TokenService;
1386
1705
  var init_tokens = __esm({
1387
1706
  "src/services/tokens.ts"() {
1388
1707
  "use strict";
1389
1708
  init_rest_request();
1390
1709
  init_routes();
1710
+ init_jwt();
1711
+ init_ksef_api_error();
1712
+ init_ksef_error();
1713
+ TOKEN_AUTHOR_IDENTIFIER_TYPES = /* @__PURE__ */ new Set([
1714
+ "Nip",
1715
+ "Pesel",
1716
+ "Fingerprint"
1717
+ ]);
1391
1718
  TokenService = class {
1392
1719
  restClient;
1393
1720
  constructor(restClient) {
@@ -1422,6 +1749,73 @@ var init_tokens = __esm({
1422
1749
  const req = RestRequest.delete(Routes.Tokens.byReference(ref));
1423
1750
  await this.restClient.executeVoid(req);
1424
1751
  }
1752
+ /**
1753
+ * Resolves the reference number of the token currently in use for authentication.
1754
+ * The only JWT payload field treated as authoritative is the KSeF-specific `trn`
1755
+ * (token reference number). Standard RFC 7519 claims such as `jti` are NOT a safe
1756
+ * fallback — a `jti` that differs from the KSeF reference would cause a DELETE to
1757
+ * hit a non-existent path, which `revokeSelf` treats as already-revoked, falsely
1758
+ * reporting success while leaving the token active on the server. When `trn` is
1759
+ * absent, we fall back to `GET /tokens` filtered by author and context; requires
1760
+ * exactly one active match and returns undefined when ambiguous.
1761
+ */
1762
+ async findSelfReferenceNumber(accessToken) {
1763
+ if (!accessToken) return void 0;
1764
+ const payload = decodeJwtPayload(accessToken);
1765
+ if (payload && typeof payload["trn"] === "string" && payload["trn"].length > 0) {
1766
+ return payload["trn"];
1767
+ }
1768
+ const ctx = parseKSeFTokenContext(accessToken);
1769
+ const author = ctx?.authorSubjectIdentifier;
1770
+ if (!author?.type || !author.value) return void 0;
1771
+ if (!ctx?.contextIdentifierType || !ctx?.contextIdentifierValue) return void 0;
1772
+ const authorType = toTokenAuthorIdentifierType(author.type);
1773
+ if (!authorType) return void 0;
1774
+ let continuationToken;
1775
+ let match;
1776
+ do {
1777
+ const list5 = await this.queryTokens({
1778
+ status: ["Active"],
1779
+ authorIdentifier: author.value,
1780
+ authorIdentifierType: authorType,
1781
+ pageSize: 50,
1782
+ continuationToken
1783
+ });
1784
+ for (const t of list5.tokens) {
1785
+ if (t.status === "Active" && t.contextIdentifier?.value === ctx.contextIdentifierValue && t.contextIdentifier?.type === ctx.contextIdentifierType) {
1786
+ if (match) return void 0;
1787
+ match = t.referenceNumber;
1788
+ }
1789
+ }
1790
+ continuationToken = list5.continuationToken ?? void 0;
1791
+ } while (continuationToken);
1792
+ return match;
1793
+ }
1794
+ /**
1795
+ * Revokes the token currently used for authentication.
1796
+ * Treats 404/409/410 on DELETE as "already revoked" and returns successfully with
1797
+ * `alreadyRevoked: true` so callers can still clear local state.
1798
+ */
1799
+ async revokeSelf(opts = {}) {
1800
+ let ref = opts.referenceNumber;
1801
+ if (!ref && opts.accessToken) {
1802
+ ref = await this.findSelfReferenceNumber(opts.accessToken);
1803
+ }
1804
+ if (!ref) {
1805
+ throw new KSeFError(
1806
+ "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."
1807
+ );
1808
+ }
1809
+ try {
1810
+ await this.revokeToken(ref);
1811
+ return { referenceNumber: ref, alreadyRevoked: false };
1812
+ } catch (err) {
1813
+ if (err instanceof KSeFApiError && (err.statusCode === 404 || err.statusCode === 409 || err.statusCode === 410)) {
1814
+ return { referenceNumber: ref, alreadyRevoked: true };
1815
+ }
1816
+ throw err;
1817
+ }
1818
+ }
1425
1819
  };
1426
1820
  }
1427
1821
  });
@@ -1478,37 +1872,6 @@ var init_certificates = __esm({
1478
1872
  }
1479
1873
  });
1480
1874
 
1481
- // src/errors/ksef-auth-status-error.ts
1482
- var init_ksef_auth_status_error = __esm({
1483
- "src/errors/ksef-auth-status-error.ts"() {
1484
- "use strict";
1485
- init_ksef_error();
1486
- }
1487
- });
1488
-
1489
- // src/errors/ksef-session-expired-error.ts
1490
- var init_ksef_session_expired_error = __esm({
1491
- "src/errors/ksef-session-expired-error.ts"() {
1492
- "use strict";
1493
- init_ksef_error();
1494
- }
1495
- });
1496
-
1497
- // src/errors/index.ts
1498
- var init_errors = __esm({
1499
- "src/errors/index.ts"() {
1500
- "use strict";
1501
- init_ksef_error();
1502
- init_ksef_api_error();
1503
- init_ksef_rate_limit_error();
1504
- init_ksef_unauthorized_error();
1505
- init_ksef_forbidden_error();
1506
- init_ksef_auth_status_error();
1507
- init_ksef_session_expired_error();
1508
- init_ksef_validation_error();
1509
- }
1510
- });
1511
-
1512
1875
  // src/services/lighthouse.ts
1513
1876
  var LighthouseService;
1514
1877
  var init_lighthouse = __esm({
@@ -2673,8 +3036,8 @@ function computeRootDigest(doc) {
2673
3036
  return crypto4.createHash("sha256").update(canonical, "utf-8").digest("base64");
2674
3037
  }
2675
3038
  function computeSignedPropertiesDigest(qualifyingPropertiesXml) {
2676
- const parser = new DOMParser();
2677
- const qpDoc = parser.parseFromString(qualifyingPropertiesXml, "text/xml");
3039
+ const parser2 = new DOMParser();
3040
+ const qpDoc = parser2.parseFromString(qualifyingPropertiesXml, "text/xml");
2678
3041
  const signedProps = findElementByLocalName(qpDoc.documentElement, "SignedProperties");
2679
3042
  if (!signedProps) {
2680
3043
  throw new Error("SignedProperties element not found in QualifyingProperties");
@@ -2826,8 +3189,8 @@ var init_signature_service = __esm({
2826
3189
  const isEc = privateKey.asymmetricKeyType === "ec";
2827
3190
  const signatureAlgorithm = isEc ? ECDSA_SHA256_SIGNATURE : RSA_SHA256_SIGNATURE;
2828
3191
  const signingTime = new Date(Date.now() + CLOCK_SKEW_BUFFER_MS).toISOString();
2829
- const parser = new DOMParser();
2830
- const doc = parser.parseFromString(xml, "text/xml");
3192
+ const parser2 = new DOMParser();
3193
+ const doc = parser2.parseFromString(xml, "text/xml");
2831
3194
  const root = doc.documentElement;
2832
3195
  if (!root) {
2833
3196
  throw new Error("XML document has no root element");
@@ -2847,7 +3210,7 @@ var init_signature_service = __esm({
2847
3210
  rootDigest,
2848
3211
  signedPropertiesDigest
2849
3212
  );
2850
- const signedInfoDoc = parser.parseFromString(signedInfoXml, "text/xml");
3213
+ const signedInfoDoc = parser2.parseFromString(signedInfoXml, "text/xml");
2851
3214
  const canonicalSignedInfo = canonicalize(signedInfoDoc.documentElement);
2852
3215
  const signatureValue = computeSignatureValue(
2853
3216
  canonicalSignedInfo,
@@ -2860,7 +3223,7 @@ var init_signature_service = __esm({
2860
3223
  certBase64,
2861
3224
  qualifyingPropertiesXml
2862
3225
  );
2863
- const signatureDoc = parser.parseFromString(signatureXml, "text/xml");
3226
+ const signatureDoc = parser2.parseFromString(signatureXml, "text/xml");
2864
3227
  const importedNode = doc.importNode(signatureDoc.documentElement, true);
2865
3228
  root.appendChild(importedNode);
2866
3229
  return new XMLSerializer().serializeToString(doc);
@@ -3060,6 +3423,7 @@ var init_client = __esm({
3060
3423
  const tokens = await this.auth.getAccessToken(authToken);
3061
3424
  this.authManager.setAccessToken(tokens.accessToken.token);
3062
3425
  this.authManager.setRefreshToken(tokens.refreshToken.token);
3426
+ return { clientIp: challenge2.clientIp };
3063
3427
  }
3064
3428
  async loginWithCertificate(certPem, keyPem, nip, keyPassword) {
3065
3429
  const challenge2 = await this.auth.getChallenge();
@@ -3072,11 +3436,12 @@ var init_client = __esm({
3072
3436
  const tokens = await this.auth.getAccessToken(authToken);
3073
3437
  this.authManager.setAccessToken(tokens.accessToken.token);
3074
3438
  this.authManager.setRefreshToken(tokens.refreshToken.token);
3439
+ return { clientIp: challenge2.clientIp };
3075
3440
  }
3076
3441
  async loginWithPkcs12(p12, password, nip) {
3077
3442
  const { Pkcs12Loader: Pkcs12Loader2 } = await Promise.resolve().then(() => (init_pkcs12_loader(), pkcs12_loader_exports));
3078
3443
  const { certificatePem, privateKeyPem } = Pkcs12Loader2.load(p12, password);
3079
- await this.loginWithCertificate(certificatePem, privateKeyPem, nip);
3444
+ return this.loginWithCertificate(certificatePem, privateKeyPem, nip);
3080
3445
  }
3081
3446
  async awaitAuthReady(referenceNumber, authToken) {
3082
3447
  for (let i = 0; i < 30; i++) {
@@ -3288,12 +3653,84 @@ var init_invoice_field_extractor = __esm({
3288
3653
  }
3289
3654
  });
3290
3655
 
3656
+ // src/xml/xml-engine.ts
3657
+ import { XMLBuilder, XMLParser as XMLParser3 } from "fast-xml-parser";
3658
+ var parser, builder;
3659
+ var init_xml_engine = __esm({
3660
+ "src/xml/xml-engine.ts"() {
3661
+ "use strict";
3662
+ parser = new XMLParser3({
3663
+ ignoreAttributes: false,
3664
+ preserveOrder: true,
3665
+ attributeNamePrefix: "@_",
3666
+ textNodeName: "#text",
3667
+ allowBooleanAttributes: true,
3668
+ // Preserve leading zeros and keep everything as strings — KSeF fields like
3669
+ // KRS (`\d{10}`) and NIP (`\d{10}`) would otherwise be lossy through parse.
3670
+ parseTagValue: false,
3671
+ parseAttributeValue: false,
3672
+ trimValues: false
3673
+ });
3674
+ builder = new XMLBuilder({
3675
+ ignoreAttributes: false,
3676
+ preserveOrder: true,
3677
+ attributeNamePrefix: "@_",
3678
+ textNodeName: "#text",
3679
+ format: false,
3680
+ suppressBooleanAttributes: false,
3681
+ suppressEmptyNode: false,
3682
+ processEntities: true
3683
+ });
3684
+ }
3685
+ });
3686
+
3687
+ // src/xml/order-map.ts
3688
+ var init_order_map = __esm({
3689
+ "src/xml/order-map.ts"() {
3690
+ "use strict";
3691
+ }
3692
+ });
3693
+
3694
+ // src/xml/faktura-builder.ts
3695
+ var init_faktura_builder = __esm({
3696
+ "src/xml/faktura-builder.ts"() {
3697
+ "use strict";
3698
+ init_xml_engine();
3699
+ init_order_map();
3700
+ }
3701
+ });
3702
+
3703
+ // src/xml/pef-builder.ts
3704
+ var init_pef_builder = __esm({
3705
+ "src/xml/pef-builder.ts"() {
3706
+ "use strict";
3707
+ init_ksef_validation_error();
3708
+ init_xml_engine();
3709
+ }
3710
+ });
3711
+
3712
+ // src/xml/invoice-serializer.ts
3713
+ var init_invoice_serializer = __esm({
3714
+ "src/xml/invoice-serializer.ts"() {
3715
+ "use strict";
3716
+ init_ksef_validation_error();
3717
+ init_faktura_builder();
3718
+ init_pef_builder();
3719
+ init_xml_engine();
3720
+ }
3721
+ });
3722
+
3291
3723
  // src/xml/index.ts
3292
3724
  var init_xml = __esm({
3293
3725
  "src/xml/index.ts"() {
3294
3726
  "use strict";
3295
3727
  init_upo_parser();
3296
3728
  init_invoice_field_extractor();
3729
+ init_xml_engine();
3730
+ init_order_map();
3731
+ init_faktura_builder();
3732
+ init_pef_builder();
3733
+ init_invoice_serializer();
3297
3734
  }
3298
3735
  });
3299
3736
 
@@ -4944,6 +5381,115 @@ var init_schema_registry = __esm({
4944
5381
  }
4945
5382
  });
4946
5383
 
5384
+ // src/validation/char-validity.ts
5385
+ function validateCharValidity(xml) {
5386
+ return [...findProcessingInstructions(xml), ...findDiscouragedUnicode(xml)];
5387
+ }
5388
+ function findProcessingInstructionTokens(xml) {
5389
+ const tokens = [];
5390
+ for (let i = 0; i < xml.length; ) {
5391
+ if (xml.startsWith("<!--", i)) {
5392
+ const end = xml.indexOf("-->", i + 4);
5393
+ i = end === -1 ? xml.length : end + 3;
5394
+ continue;
5395
+ }
5396
+ if (xml.startsWith("<![CDATA[", i)) {
5397
+ const end = xml.indexOf("]]>", i + 9);
5398
+ i = end === -1 ? xml.length : end + 3;
5399
+ continue;
5400
+ }
5401
+ if (xml.startsWith("<?", i)) {
5402
+ const end = xml.indexOf("?>", i + 2);
5403
+ if (end === -1) break;
5404
+ tokens.push({ token: xml.slice(i, end + 2), index: i });
5405
+ i = end + 2;
5406
+ continue;
5407
+ }
5408
+ i += 1;
5409
+ }
5410
+ return tokens;
5411
+ }
5412
+ function findProcessingInstructions(xml) {
5413
+ const errors = [];
5414
+ const matches = findProcessingInstructionTokens(xml);
5415
+ if (matches.length === 0) return errors;
5416
+ const firstMatch = matches[0];
5417
+ const firstTarget = firstMatch.token.match(PI_TARGET_RE)?.[1];
5418
+ const hasBom = xml.charCodeAt(0) === 65279;
5419
+ const prologPosition = hasBom ? 1 : 0;
5420
+ const firstIsProlog = firstMatch.index === prologPosition && firstTarget === "xml";
5421
+ for (let i = 0; i < matches.length; i++) {
5422
+ if (i === 0 && firstIsProlog) continue;
5423
+ const m = matches[i];
5424
+ const target = m.token.match(PI_TARGET_RE)?.[1] ?? "?";
5425
+ errors.push({
5426
+ code: "XML_PROCESSING_INSTRUCTION",
5427
+ message: `Processing instruction <?${target}?> at offset ${m.index} is not allowed (only <?xml ... ?> prolog is permitted)`,
5428
+ path: `offset:${m.index}`
5429
+ });
5430
+ }
5431
+ return errors;
5432
+ }
5433
+ function findDiscouragedUnicode(xml) {
5434
+ const errors = [];
5435
+ const seenRanges = /* @__PURE__ */ new Set();
5436
+ let utf16Offset = 0;
5437
+ for (const ch of xml) {
5438
+ const cp = ch.codePointAt(0);
5439
+ const idx = rangeIndex(cp);
5440
+ if (idx >= 0 && !seenRanges.has(idx)) {
5441
+ seenRanges.add(idx);
5442
+ errors.push({
5443
+ code: "XML_DISCOURAGED_UNICODE",
5444
+ 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)`,
5445
+ path: `offset:${utf16Offset}`
5446
+ });
5447
+ }
5448
+ utf16Offset += ch.length;
5449
+ }
5450
+ return errors;
5451
+ }
5452
+ function rangeIndex(cp) {
5453
+ let lo = 0;
5454
+ let hi = DISCOURAGED_UNICODE_RANGES.length - 1;
5455
+ while (lo <= hi) {
5456
+ const mid = lo + hi >> 1;
5457
+ const [start, end] = DISCOURAGED_UNICODE_RANGES[mid];
5458
+ if (cp < start) hi = mid - 1;
5459
+ else if (cp > end) lo = mid + 1;
5460
+ else return mid;
5461
+ }
5462
+ return -1;
5463
+ }
5464
+ var DISCOURAGED_UNICODE_RANGES, PI_TARGET_RE;
5465
+ var init_char_validity = __esm({
5466
+ "src/validation/char-validity.ts"() {
5467
+ "use strict";
5468
+ DISCOURAGED_UNICODE_RANGES = [
5469
+ [127, 132],
5470
+ [134, 159],
5471
+ [64976, 65007],
5472
+ [131070, 131071],
5473
+ [196606, 196607],
5474
+ [262142, 262143],
5475
+ [327678, 327679],
5476
+ [393214, 393215],
5477
+ [458750, 458751],
5478
+ [524286, 524287],
5479
+ [589822, 589823],
5480
+ [655358, 655359],
5481
+ [720894, 720895],
5482
+ [786430, 786431],
5483
+ [851966, 851967],
5484
+ [917502, 917503],
5485
+ [983038, 983039],
5486
+ [1048574, 1048575],
5487
+ [1114110, 1114111]
5488
+ ];
5489
+ PI_TARGET_RE = /^<\?(\S+)/;
5490
+ }
5491
+ });
5492
+
4947
5493
  // src/validation/patterns.ts
4948
5494
  function isValidNip(value) {
4949
5495
  if (!Nip.test(value)) return false;
@@ -5130,6 +5676,12 @@ function collectDateErrors(obj, rootElement, errors) {
5130
5676
  }
5131
5677
  }
5132
5678
  async function validate(xml, options) {
5679
+ if (!options?.skipCharValidity) {
5680
+ const l1aErrors = validateCharValidity(xml);
5681
+ if (l1aErrors.length > 0) {
5682
+ return { valid: false, schemaType: null, errors: l1aErrors };
5683
+ }
5684
+ }
5133
5685
  const parsed = xml && xml.trim() ? xmlToObject(xml) : void 0;
5134
5686
  const l1 = validateWellFormedness(xml, parsed);
5135
5687
  if (!l1.valid) return l1;
@@ -5156,6 +5708,7 @@ var init_invoice_validator = __esm({
5156
5708
  "use strict";
5157
5709
  init_xml_to_object();
5158
5710
  init_schema_registry();
5711
+ init_char_validity();
5159
5712
  init_patterns();
5160
5713
  }
5161
5714
  });
@@ -5640,67 +6193,119 @@ function clearOnlineSessionRef() {
5640
6193
  }
5641
6194
  }
5642
6195
 
5643
- // src/cli/error-handler.ts
5644
- init_ksef_rate_limit_error();
5645
- init_ksef_unauthorized_error();
5646
- init_ksef_forbidden_error();
5647
- init_ksef_api_error();
5648
- init_ksef_validation_error();
6196
+ // src/cli/error-renderer.ts
6197
+ init_errors();
5649
6198
  import { consola as consola2 } from "consola";
5650
- async function withErrorHandler(fn) {
5651
- try {
5652
- await fn();
5653
- } catch (error) {
6199
+ function renderCliError(error, opts) {
6200
+ if (opts?.json) {
6201
+ const payload = error instanceof Error ? serializeError(error) : { name: "UnknownError", value: safeValue(error) };
6202
+ process.stdout.write(JSON.stringify({ error: payload }, null, 2) + "\n");
6203
+ return;
6204
+ }
6205
+ if (error instanceof KSeFApiError) {
5654
6206
  if (error instanceof KSeFRateLimitError) {
5655
6207
  consola2.error("Rate limited by KSeF API.");
5656
- consola2.info(`Hint: Retry after ${error.recommendedDelay}s.`);
5657
- process.exit(1);
5658
- }
5659
- if (error instanceof KSeFUnauthorizedError) {
5660
- consola2.error(`KSeF API error (HTTP 401): ${error.detail}`);
5661
- if (error.traceId) consola2.error(` Trace ID: ${error.traceId}`);
5662
- consola2.info("Hint: Your session may have expired. Run `ksef auth login` to re-authenticate.");
5663
- process.exit(1);
5664
- }
5665
- if (error instanceof KSeFForbiddenError) {
5666
- consola2.error(`KSeF API error (HTTP 403): ${error.detail}`);
5667
- consola2.error(` Reason: ${error.reasonCode}`);
5668
- if (error.traceId) consola2.error(` Trace ID: ${error.traceId}`);
5669
- consola2.info("Hint: Check your permissions for this operation.");
5670
- process.exit(1);
6208
+ } else {
6209
+ consola2.error(`KSeF API error (HTTP ${error.statusCode}): ${error.message}`);
5671
6210
  }
5672
- if (error instanceof KSeFValidationError) {
5673
- consola2.error(error.message);
5674
- for (const detail of error.details) {
5675
- consola2.error(` ${detail.field ? `[${detail.field}] ` : ""}${detail.message}`);
6211
+ renderProblemDetails(error.toProblemFields());
6212
+ const legacyDetails = error.errorResponse?.exception?.exceptionDetailList;
6213
+ if (legacyDetails?.length) {
6214
+ for (const d of legacyDetails) {
6215
+ consola2.error(` \u2514 [${d.exceptionCode}] ${d.exceptionDescription ?? ""}`);
5676
6216
  }
5677
- process.exit(1);
5678
6217
  }
5679
- if (error instanceof KSeFApiError) {
5680
- consola2.error(`KSeF API error (HTTP ${error.statusCode}): ${error.message}`);
5681
- if (error.errorResponse?.exception?.exceptionDetailList) {
5682
- for (const detail of error.errorResponse.exception.exceptionDetailList) {
5683
- consola2.error(` - [${detail.exceptionCode}] ${detail.exceptionDescription}`);
5684
- }
5685
- }
5686
- if (error.statusCode === 401 || error.statusCode === 403) {
5687
- consola2.info("Hint: Run `ksef auth login` to authenticate.");
5688
- } else if (error.statusCode === 404) {
5689
- consola2.info("Hint: Check if the resource reference is correct.");
5690
- }
5691
- process.exit(1);
6218
+ const hint = hintForStatus(error);
6219
+ if (hint) consola2.info(hint);
6220
+ return;
6221
+ }
6222
+ if (error instanceof KSeFValidationError) {
6223
+ consola2.error(error.message);
6224
+ for (const d of error.details) {
6225
+ consola2.error(` \u2514 ${d.field ? `[${d.field}] ` : ""}${d.message}`);
5692
6226
  }
5693
- if (error instanceof Error) {
5694
- const msg = error.message;
5695
- if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("ETIMEDOUT") || msg.includes("ENOTFOUND")) {
5696
- consola2.error("Cannot reach KSeF API. Check your network connection and environment.");
5697
- consola2.info("Hint: Run `ksef doctor` to diagnose connectivity issues.");
5698
- process.exit(1);
5699
- }
6227
+ return;
6228
+ }
6229
+ if (error instanceof Error) {
6230
+ const msg = error.message;
6231
+ if (/fetch failed|ECONNREFUSED|ETIMEDOUT|ENOTFOUND/.test(msg)) {
6232
+ consola2.error("Cannot reach KSeF API. Check your network connection and environment.");
6233
+ consola2.info("Hint: Run `ksef doctor` to diagnose connectivity issues.");
6234
+ } else {
5700
6235
  consola2.error(msg);
5701
- process.exit(1);
5702
6236
  }
5703
- consola2.error("Unknown error", error);
6237
+ return;
6238
+ }
6239
+ consola2.error("Unknown error", error);
6240
+ }
6241
+ function renderProblemDetails(fields) {
6242
+ if (fields.detail) consola2.error(` \u2514 Detail: ${fields.detail}`);
6243
+ if (fields.reasonCode) consola2.error(` \u2514 Reason: ${fields.reasonCode}`);
6244
+ const required = fields.security?.requiredAnyOfPermissions;
6245
+ if (required?.length) {
6246
+ consola2.error(` \u2514 Required (any of): ${required.join(", ")}`);
6247
+ }
6248
+ const present = fields.security?.presentPermissions;
6249
+ if (present?.length) {
6250
+ consola2.error(` \u2514 Present: ${present.join(", ")}`);
6251
+ }
6252
+ if (fields.errors?.length) {
6253
+ consola2.error(` \u2514 Errors:`);
6254
+ for (const err of fields.errors) {
6255
+ consola2.error(` \u2022 [${err.code}] ${err.description}`);
6256
+ for (const d of err.details ?? []) {
6257
+ consola2.error(` \u2514 ${d}`);
6258
+ }
6259
+ }
6260
+ }
6261
+ if (fields.traceId) consola2.error(` \u2514 Trace ID: ${fields.traceId}`);
6262
+ if (fields.instance) consola2.error(` \u2514 Instance: ${fields.instance}`);
6263
+ if (fields.timestamp) consola2.error(` \u2514 Timestamp: ${fields.timestamp}`);
6264
+ }
6265
+ function safeValue(value) {
6266
+ try {
6267
+ return JSON.parse(JSON.stringify(value));
6268
+ } catch {
6269
+ return String(value);
6270
+ }
6271
+ }
6272
+ function serializeError(error) {
6273
+ if (error instanceof KSeFApiError) {
6274
+ return {
6275
+ ...error.toProblemFields(),
6276
+ name: error.name,
6277
+ statusCode: error.statusCode,
6278
+ message: error.message
6279
+ };
6280
+ }
6281
+ if (error instanceof KSeFValidationError) {
6282
+ return {
6283
+ name: error.name,
6284
+ message: error.message,
6285
+ details: error.details
6286
+ };
6287
+ }
6288
+ return {
6289
+ name: error.name,
6290
+ message: error.message
6291
+ };
6292
+ }
6293
+ function hintForStatus(error) {
6294
+ if (error instanceof KSeFRateLimitError) return `Hint: Retry after ${error.recommendedDelay}s.`;
6295
+ if (error instanceof KSeFUnauthorizedError) return "Hint: Your session may have expired. Run `ksef auth login` to re-authenticate.";
6296
+ if (error instanceof KSeFForbiddenError) return "Hint: Check your permissions for this operation.";
6297
+ if (error instanceof KSeFBadRequestError) return "Hint: Review the error list above; fix the flagged fields and retry.";
6298
+ if (error instanceof KSeFGoneError) return "Hint: The operation has aged out. Re-submit the request if still relevant.";
6299
+ if (error.statusCode === 404) return "Hint: Check if the resource reference is correct.";
6300
+ return void 0;
6301
+ }
6302
+
6303
+ // src/cli/error-handler.ts
6304
+ async function withErrorHandler(fn, opts) {
6305
+ try {
6306
+ await fn();
6307
+ } catch (error) {
6308
+ renderCliError(error, opts);
5704
6309
  process.exit(1);
5705
6310
  }
5706
6311
  }
@@ -5745,7 +6350,7 @@ var set = defineCommand({
5745
6350
  }
5746
6351
  saveConfig(config);
5747
6352
  outputSuccess("Configuration updated.");
5748
- });
6353
+ }, { json: Boolean(args.json) });
5749
6354
  }
5750
6355
  });
5751
6356
  var show = defineCommand({
@@ -5757,7 +6362,7 @@ var show = defineCommand({
5757
6362
  return withErrorHandler(async () => {
5758
6363
  const config = loadConfig();
5759
6364
  outputKeyValue(config, { json: args.json });
5760
- });
6365
+ }, { json: Boolean(args.json) });
5761
6366
  }
5762
6367
  });
5763
6368
  var reset = defineCommand({
@@ -5813,6 +6418,12 @@ function saveCredentials(creds) {
5813
6418
  mode: 384
5814
6419
  });
5815
6420
  }
6421
+ function clearCredentials() {
6422
+ try {
6423
+ fs3.unlinkSync(CREDENTIALS_FILE);
6424
+ } catch {
6425
+ }
6426
+ }
5816
6427
 
5817
6428
  // src/workflows/auth-workflow.ts
5818
6429
  init_polling();
@@ -5948,53 +6559,7 @@ function clearPendingChallenge() {
5948
6559
 
5949
6560
  // src/cli/commands/auth.ts
5950
6561
  init_polling();
5951
-
5952
- // src/utils/jwt.ts
5953
- function decodeJwtPayload(token) {
5954
- const parts = token.split(".");
5955
- if (parts.length !== 3) return null;
5956
- try {
5957
- const payload = parts[1];
5958
- const json = Buffer.from(payload, "base64url").toString("utf-8");
5959
- return JSON.parse(json);
5960
- } catch {
5961
- return null;
5962
- }
5963
- }
5964
- function tryParseJson(value) {
5965
- if (typeof value !== "string") return void 0;
5966
- try {
5967
- return JSON.parse(value);
5968
- } catch {
5969
- return void 0;
5970
- }
5971
- }
5972
- function tryParseJsonArray(value) {
5973
- if (typeof value !== "string") return void 0;
5974
- try {
5975
- const parsed = JSON.parse(value);
5976
- return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : void 0;
5977
- } catch {
5978
- return void 0;
5979
- }
5980
- }
5981
- function parseKSeFTokenContext(token) {
5982
- const raw = decodeJwtPayload(token);
5983
- if (!raw) return null;
5984
- return {
5985
- type: typeof raw["typ"] === "string" ? raw["typ"] : void 0,
5986
- contextIdentifierType: typeof raw["cit"] === "string" ? raw["cit"] : void 0,
5987
- contextIdentifierValue: typeof raw["civ"] === "string" ? raw["civ"] : void 0,
5988
- authMethod: typeof raw["aum"] === "string" ? raw["aum"] : void 0,
5989
- permissions: tryParseJsonArray(raw["per"]),
5990
- subjectDetails: tryParseJson(raw["sud"]),
5991
- authorSubjectIdentifier: tryParseJson(raw["asi"]),
5992
- issuedAt: typeof raw["iat"] === "number" ? raw["iat"] : void 0,
5993
- expiresAt: typeof raw["exp"] === "number" ? raw["exp"] : void 0
5994
- };
5995
- }
5996
-
5997
- // src/cli/commands/auth.ts
6562
+ init_jwt();
5998
6563
  async function readStdin(stream = process.stdin) {
5999
6564
  const chunks = [];
6000
6565
  for await (const chunk of stream) {
@@ -6025,7 +6590,7 @@ var challenge = defineCommand2({
6025
6590
  const client = createClient(globalOpts);
6026
6591
  const result = await client.auth.getChallenge();
6027
6592
  outputResult(result, { json: args.json });
6028
- });
6593
+ }, { json: Boolean(args.json) });
6029
6594
  }
6030
6595
  });
6031
6596
  var login = defineCommand2({
@@ -6056,17 +6621,18 @@ var login = defineCommand2({
6056
6621
  throw new Error("NIP is required. Provide --nip or set it via `ksef config set --nip <nip>`.");
6057
6622
  }
6058
6623
  const token = args.token ?? loadCredentials()?.token;
6624
+ let loginResult;
6059
6625
  if (token) {
6060
- await client.loginWithToken(token, nip);
6626
+ loginResult = await client.loginWithToken(token, nip);
6061
6627
  } else if (args.p12) {
6062
6628
  const fs15 = await import("fs");
6063
6629
  const p12Buffer = fs15.readFileSync(args.p12);
6064
- await client.loginWithPkcs12(p12Buffer, args["p12-password"] ?? "", nip);
6630
+ loginResult = await client.loginWithPkcs12(p12Buffer, args["p12-password"] ?? "", nip);
6065
6631
  } else if (args.cert && args.key) {
6066
6632
  const fs15 = await import("fs");
6067
6633
  const certPem = fs15.readFileSync(args.cert, "utf-8");
6068
6634
  const keyPem = fs15.readFileSync(args.key, "utf-8");
6069
- await client.loginWithCertificate(certPem, keyPem, nip, args["key-password"]);
6635
+ loginResult = await client.loginWithCertificate(certPem, keyPem, nip, args["key-password"]);
6070
6636
  } else {
6071
6637
  throw new Error("Provide --token, --p12, or both --cert and --key for authentication.");
6072
6638
  }
@@ -6081,8 +6647,27 @@ var login = defineCommand2({
6081
6647
  if (args.env && args.env !== config.environment) {
6082
6648
  saveConfig({ ...config, environment: session.environment });
6083
6649
  }
6084
- outputSuccess("Logged in successfully.");
6085
- });
6650
+ if (args.token) {
6651
+ const prev = { ...loadCredentials() ?? {} };
6652
+ delete prev.tokenReferenceNumber;
6653
+ let ref;
6654
+ try {
6655
+ ref = await client.tokens.findSelfReferenceNumber(session.accessToken);
6656
+ } catch {
6657
+ }
6658
+ saveCredentials({
6659
+ ...prev,
6660
+ token: args.token,
6661
+ ...ref ? { tokenReferenceNumber: ref } : {}
6662
+ });
6663
+ }
6664
+ if (args.json) {
6665
+ console.log(JSON.stringify({ status: "ok", clientIp: loginResult.clientIp }, null, 2));
6666
+ } else {
6667
+ consola6.info(`Seen client IP: ${loginResult.clientIp}`);
6668
+ outputSuccess("Logged in successfully.");
6669
+ }
6670
+ }, { json: Boolean(args.json) });
6086
6671
  }
6087
6672
  });
6088
6673
  var status = defineCommand2({
@@ -6100,7 +6685,7 @@ var status = defineCommand2({
6100
6685
  const { client, session } = await requireSession(globalOpts);
6101
6686
  const result = await client.auth.getAuthStatus(args.ref, session.accessToken);
6102
6687
  outputResult(result, { json: args.json });
6103
- });
6688
+ }, { json: Boolean(args.json) });
6104
6689
  }
6105
6690
  });
6106
6691
  var logout = defineCommand2({
@@ -6112,6 +6697,102 @@ var logout = defineCommand2({
6112
6697
  });
6113
6698
  }
6114
6699
  });
6700
+ var revokeSelfToken = defineCommand2({
6701
+ meta: {
6702
+ name: "revoke-self-token",
6703
+ description: "Revoke the token currently used for authentication. Reference number is resolved via discovery first (JWT payload, then a filtered active-token list), falling back to local cache only if discovery fails; revocation is idempotent (404/409/410 treated as already-revoked)."
6704
+ },
6705
+ args: {
6706
+ "keep-local": { type: "boolean", description: "Revoke server-side but keep local session" },
6707
+ "dry-run": { type: "boolean", description: "Print what would happen without revoking the token (discovery may still query the API)" },
6708
+ env: { type: "string", description: "Environment (test/demo/prod)" },
6709
+ json: { type: "boolean", description: "Output as JSON" },
6710
+ verbose: { type: "boolean", description: "Show HTTP request/response details" },
6711
+ timeout: { type: "string", description: "Request timeout (ms)" }
6712
+ },
6713
+ run({ args }) {
6714
+ return withErrorHandler(async () => {
6715
+ const globalOpts = getGlobalOpts(args);
6716
+ const { client, session } = await requireSession(globalOpts);
6717
+ if (args.env && args.env !== session.environment) {
6718
+ throw new Error(
6719
+ `Current session is '${session.environment}', but --env='${args.env}'. Refusing to revoke a token from a different environment.`
6720
+ );
6721
+ }
6722
+ let discoveredRef;
6723
+ try {
6724
+ discoveredRef = await client.tokens.findSelfReferenceNumber(session.accessToken);
6725
+ } catch {
6726
+ discoveredRef = void 0;
6727
+ }
6728
+ const cachedRef = discoveredRef ? void 0 : loadCredentials()?.tokenReferenceNumber;
6729
+ const ref = discoveredRef ?? cachedRef;
6730
+ const source = discoveredRef ? "discovery" : cachedRef ? "cache-fallback" : "none";
6731
+ if (args["dry-run"]) {
6732
+ if (args.json) {
6733
+ outputResult(
6734
+ {
6735
+ status: "dry-run",
6736
+ referenceNumber: ref ?? null,
6737
+ source,
6738
+ wouldClearLocal: !args["keep-local"]
6739
+ },
6740
+ { json: true }
6741
+ );
6742
+ return;
6743
+ }
6744
+ if (source === "cache-fallback") {
6745
+ outputWarning(
6746
+ "Using cached reference (discovery failed). Verify this is the token you intend to revoke."
6747
+ );
6748
+ }
6749
+ outputKeyValue(
6750
+ {
6751
+ "Would revoke": ref ?? "(unknown \u2014 discovery failed)",
6752
+ Source: source,
6753
+ "Would clear local": args["keep-local"] ? "no" : "yes"
6754
+ },
6755
+ { json: false }
6756
+ );
6757
+ return;
6758
+ }
6759
+ if (source === "cache-fallback" && !args.json) {
6760
+ outputWarning(
6761
+ "Using cached reference (discovery failed). Verify this is the token you intend to revoke."
6762
+ );
6763
+ }
6764
+ const { referenceNumber, alreadyRevoked } = await client.tokens.revokeSelf({
6765
+ referenceNumber: ref,
6766
+ accessToken: session.accessToken
6767
+ });
6768
+ const localCleared = !args["keep-local"];
6769
+ if (localCleared) {
6770
+ clearSession();
6771
+ clearCredentials();
6772
+ }
6773
+ if (args.json) {
6774
+ outputResult(
6775
+ {
6776
+ status: alreadyRevoked ? "already-revoked" : "revoked",
6777
+ referenceNumber,
6778
+ source,
6779
+ localCleared
6780
+ },
6781
+ { json: true }
6782
+ );
6783
+ } else {
6784
+ if (alreadyRevoked) {
6785
+ outputWarning(`Token ${referenceNumber} was already revoked on the server.`);
6786
+ } else {
6787
+ outputSuccess(`Token ${referenceNumber} revoked.`);
6788
+ }
6789
+ if (localCleared) {
6790
+ outputSuccess("Local session and credentials cleared.");
6791
+ }
6792
+ }
6793
+ }, { json: Boolean(args.json) });
6794
+ }
6795
+ });
6115
6796
  var refresh = defineCommand2({
6116
6797
  meta: { name: "refresh", description: "Refresh the access token" },
6117
6798
  args: {
@@ -6136,7 +6817,7 @@ var refresh = defineCommand2({
6136
6817
  session.expiresAt = result.accessToken.validUntil;
6137
6818
  saveSession(session);
6138
6819
  outputSuccess("Token refreshed successfully.");
6139
- });
6820
+ }, { json: Boolean(args.json) });
6140
6821
  }
6141
6822
  });
6142
6823
  var whoami = defineCommand2({
@@ -6187,7 +6868,7 @@ var whoami = defineCommand2({
6187
6868
  info.context = context2;
6188
6869
  }
6189
6870
  outputKeyValue(info, { json: args.json });
6190
- });
6871
+ }, { json: Boolean(args.json) });
6191
6872
  }
6192
6873
  });
6193
6874
  var loginExternal = defineCommand2({
@@ -6244,6 +6925,8 @@ var loginExternal = defineCommand2({
6244
6925
  process.stderr.write(`Challenge: ${challengeResult.challenge}
6245
6926
  `);
6246
6927
  process.stderr.write(`Timestamp: ${challengeResult.timestamp}
6928
+ `);
6929
+ process.stderr.write(`Seen client IP: ${challengeResult.clientIp}
6247
6930
  `);
6248
6931
  process.stderr.write(`Note: Sign this XML and submit with --submit before the challenge expires.
6249
6932
  `);
@@ -6279,12 +6962,21 @@ var loginExternal = defineCommand2({
6279
6962
  clearPendingChallenge();
6280
6963
  outputSuccess("Logged in successfully via external signature.");
6281
6964
  }
6282
- });
6965
+ }, { json: Boolean(args.json) });
6283
6966
  }
6284
6967
  });
6285
6968
  var authCommand = defineCommand2({
6286
6969
  meta: { name: "auth", description: "Authentication commands" },
6287
- subCommands: { challenge, login, "login-external": loginExternal, status, logout, refresh, whoami }
6970
+ subCommands: {
6971
+ challenge,
6972
+ login,
6973
+ "login-external": loginExternal,
6974
+ status,
6975
+ logout,
6976
+ "revoke-self-token": revokeSelfToken,
6977
+ refresh,
6978
+ whoami
6979
+ }
6288
6980
  });
6289
6981
 
6290
6982
  // src/cli/commands/session.ts
@@ -6353,7 +7045,7 @@ var open = defineCommand3({
6353
7045
  "Valid Until": result.validUntil
6354
7046
  }, { json: false });
6355
7047
  }
6356
- });
7048
+ }, { json: Boolean(args.json) });
6357
7049
  }
6358
7050
  });
6359
7051
  var close = defineCommand3({
@@ -6377,7 +7069,7 @@ var close = defineCommand3({
6377
7069
  await client.onlineSession.closeSession(ref);
6378
7070
  clearOnlineSessionRef();
6379
7071
  outputSuccess(`Session ${ref} closed.`);
6380
- });
7072
+ }, { json: Boolean(args.json) });
6381
7073
  }
6382
7074
  });
6383
7075
  var status2 = defineCommand3({
@@ -6411,7 +7103,7 @@ var status2 = defineCommand3({
6411
7103
  "Failed": result.failedInvoiceCount ?? 0
6412
7104
  }, { json: false });
6413
7105
  }
6414
- });
7106
+ }, { json: Boolean(args.json) });
6415
7107
  }
6416
7108
  });
6417
7109
  var list = defineCommand3({
@@ -6444,6 +7136,7 @@ var list = defineCommand3({
6444
7136
  reference: s.referenceNumber,
6445
7137
  status: `${s.status.code} \u2014 ${s.status.description}`,
6446
7138
  created: s.dateCreated,
7139
+ updated: s.dateUpdated,
6447
7140
  total: s.totalInvoiceCount,
6448
7141
  success: s.successfulInvoiceCount,
6449
7142
  failed: s.failedInvoiceCount
@@ -6452,6 +7145,7 @@ var list = defineCommand3({
6452
7145
  { key: "reference", label: "Reference" },
6453
7146
  { key: "status", label: "Status" },
6454
7147
  { key: "created", label: "Created" },
7148
+ { key: "updated", label: "Updated" },
6455
7149
  { key: "total", label: "Total" },
6456
7150
  { key: "success", label: "Success" },
6457
7151
  { key: "failed", label: "Failed" }
@@ -6461,7 +7155,7 @@ var list = defineCommand3({
6461
7155
  if (result.continuationToken) {
6462
7156
  consola7.info(`More results available. Continuation token: ${result.continuationToken}`);
6463
7157
  }
6464
- });
7158
+ }, { json: Boolean(args.json) });
6465
7159
  }
6466
7160
  });
6467
7161
  var invoices = defineCommand3({
@@ -6512,7 +7206,7 @@ var invoices = defineCommand3({
6512
7206
  if (result.continuationToken) {
6513
7207
  consola7.info(`More results available. Continuation token: ${result.continuationToken}`);
6514
7208
  }
6515
- });
7209
+ }, { json: Boolean(args.json) });
6516
7210
  }
6517
7211
  });
6518
7212
  var failed = defineCommand3({
@@ -6563,7 +7257,7 @@ var failed = defineCommand3({
6563
7257
  if (result.continuationToken) {
6564
7258
  consola7.info(`More results available. Continuation token: ${result.continuationToken}`);
6565
7259
  }
6566
- });
7260
+ }, { json: Boolean(args.json) });
6567
7261
  }
6568
7262
  });
6569
7263
  var upo = defineCommand3({
@@ -6616,7 +7310,7 @@ var upo = defineCommand3({
6616
7310
  } else {
6617
7311
  console.log(result.upo);
6618
7312
  }
6619
- });
7313
+ }, { json: Boolean(args.json) });
6620
7314
  }
6621
7315
  });
6622
7316
  var active = defineCommand3({
@@ -6662,7 +7356,7 @@ var active = defineCommand3({
6662
7356
  if (result.continuationToken) {
6663
7357
  consola7.info(`More results available. Continuation token: ${result.continuationToken}`);
6664
7358
  }
6665
- });
7359
+ }, { json: Boolean(args.json) });
6666
7360
  }
6667
7361
  });
6668
7362
  var revoke = defineCommand3({
@@ -6696,7 +7390,7 @@ var revoke = defineCommand3({
6696
7390
  } else {
6697
7391
  throw new Error("Provide a session reference or use --current to revoke the current session.");
6698
7392
  }
6699
- });
7393
+ }, { json: Boolean(args.json) });
6700
7394
  }
6701
7395
  });
6702
7396
  var invoice = defineCommand3({
@@ -6732,7 +7426,7 @@ var invoice = defineCommand3({
6732
7426
  "Invoicing Mode": result.invoicingMode ?? "N/A"
6733
7427
  }, { json: false });
6734
7428
  }
6735
- });
7429
+ }, { json: Boolean(args.json) });
6736
7430
  }
6737
7431
  });
6738
7432
  var sessionCommand = defineCommand3({
@@ -7022,7 +7716,7 @@ var exportIncremental = defineCommand4({
7022
7716
  consola8.info(`Final HWM: ${continuationPoints[subjectType] ?? "complete"}`);
7023
7717
  consola8.info(`Output: ${outputDir}`);
7024
7718
  }
7025
- });
7719
+ }, { json: Boolean(args.json) });
7026
7720
  }
7027
7721
  });
7028
7722
 
@@ -7078,8 +7772,8 @@ var QUERY_FILTER_ARGS = {
7078
7772
  dateType: { type: "string", description: "Date type: Issue|Invoicing|PermanentStorage (default: Invoicing)" },
7079
7773
  sellerNip: { type: "string", description: "Filter by seller NIP" },
7080
7774
  buyerNip: { type: "string", description: "Filter by buyer NIP" },
7081
- amountFrom: { type: "string", description: "Minimum amount" },
7082
- amountTo: { type: "string", description: "Maximum amount" },
7775
+ amountFrom: { type: "string", description: "Minimum amount (negative values allowed)" },
7776
+ amountTo: { type: "string", description: "Maximum amount (negative values allowed)" },
7083
7777
  amountType: { type: "string", description: "Amount type: Brutto|Netto|Vat (default: Brutto)" },
7084
7778
  currency: { type: "string", description: "Currency code (e.g. PLN, EUR)" }
7085
7779
  };
@@ -7254,7 +7948,7 @@ var send = defineCommand5({
7254
7948
  outputSuccess(`Invoice sent. Ref: ${result.referenceNumber}`);
7255
7949
  }
7256
7950
  }
7257
- });
7951
+ }, { json: Boolean(args.json) });
7258
7952
  }
7259
7953
  });
7260
7954
  var get = defineCommand5({
@@ -7282,7 +7976,7 @@ var get = defineCommand5({
7282
7976
  } else {
7283
7977
  console.log(xml);
7284
7978
  }
7285
- });
7979
+ }, { json: Boolean(args.json) });
7286
7980
  }
7287
7981
  });
7288
7982
  var query = defineCommand5({
@@ -7339,7 +8033,7 @@ var query = defineCommand5({
7339
8033
  if (result.hasMore) {
7340
8034
  consola9.info("More results available. Use --page to fetch the next page.");
7341
8035
  }
7342
- });
8036
+ }, { json: Boolean(args.json) });
7343
8037
  }
7344
8038
  });
7345
8039
  var exportCmd = defineCommand5({
@@ -7370,7 +8064,7 @@ var exportCmd = defineCommand5({
7370
8064
  outputSuccess(`Export started. Ref: ${result.referenceNumber}`);
7371
8065
  consola9.info("Check status with: ksef invoice export-status " + result.referenceNumber);
7372
8066
  }
7373
- });
8067
+ }, { json: Boolean(args.json) });
7374
8068
  }
7375
8069
  });
7376
8070
  var exportStatus = defineCommand5({
@@ -7420,7 +8114,7 @@ var exportStatus = defineCommand5({
7420
8114
  );
7421
8115
  }
7422
8116
  }
7423
- });
8117
+ }, { json: Boolean(args.json) });
7424
8118
  }
7425
8119
  });
7426
8120
  var VALID_SCHEMA_TYPES = SCHEMA_TYPES;
@@ -7490,7 +8184,7 @@ var validateCmd = defineCommand5({
7490
8184
  if (invalidCount > 0) {
7491
8185
  process.exitCode = 1;
7492
8186
  }
7493
- });
8187
+ }, { json: Boolean(args.json) });
7494
8188
  }
7495
8189
  });
7496
8190
  var invoiceCommand = defineCommand5({
@@ -7500,6 +8194,7 @@ var invoiceCommand = defineCommand5({
7500
8194
 
7501
8195
  // src/cli/commands/permission.ts
7502
8196
  import { defineCommand as defineCommand6 } from "citty";
8197
+ init_ksef_validation_error();
7503
8198
  function getGlobalOpts5(args) {
7504
8199
  return {
7505
8200
  env: args.env,
@@ -7688,7 +8383,7 @@ var grant = defineCommand6({
7688
8383
  } else {
7689
8384
  outputSuccess(`Permission granted. Ref: ${result.referenceNumber}`);
7690
8385
  }
7691
- });
8386
+ }, { json: Boolean(args.json) });
7692
8387
  }
7693
8388
  });
7694
8389
  var revoke2 = defineCommand6({
@@ -7717,7 +8412,7 @@ var revoke2 = defineCommand6({
7717
8412
  } else {
7718
8413
  outputSuccess(`Permission grant ${args.grantId} revoked. Ref: ${result.referenceNumber}`);
7719
8414
  }
7720
- });
8415
+ }, { json: Boolean(args.json) });
7721
8416
  }
7722
8417
  });
7723
8418
  var search = defineCommand6({
@@ -7727,6 +8422,8 @@ var search = defineCommand6({
7727
8422
  identifier: { type: "string", description: "Subject identifier value" },
7728
8423
  identifierType: { type: "string", description: "Subject identifier type" },
7729
8424
  queryType: { type: "string", description: "Query type (e.g. PermissionsInCurrentContext, Granted)" },
8425
+ contextType: { type: "string", description: "Context identifier type: Nip | InternalId (for --type personal and --type entities-grants)" },
8426
+ contextValue: { type: "string", description: "Context identifier value (NIP or 10-16 char InternalId)" },
7730
8427
  page: { type: "string", description: "Page offset (default: 0)" },
7731
8428
  pageSize: { type: "string", description: "Page size" },
7732
8429
  env: { type: "string", description: "Environment (test/demo/prod)" },
@@ -7741,9 +8438,33 @@ var search = defineCommand6({
7741
8438
  const { client } = await requireSession(globalOpts);
7742
8439
  const page = args.page ? parseInt(args.page, 10) : void 0;
7743
8440
  const pageSize = args.pageSize ? parseInt(args.pageSize, 10) : void 0;
8441
+ const resolveContextBody = () => {
8442
+ const hasType = Boolean(args.contextType);
8443
+ const hasValue = Boolean(args.contextValue);
8444
+ if (hasType !== hasValue) {
8445
+ throw KSeFValidationError.fromField(
8446
+ hasType ? "--context-value" : "--context-type",
8447
+ "--context-type and --context-value must be provided together."
8448
+ );
8449
+ }
8450
+ if (!hasType) return {};
8451
+ if (args.contextType !== "Nip" && args.contextType !== "InternalId") {
8452
+ throw KSeFValidationError.fromField(
8453
+ "--context-type",
8454
+ `--context-type must be "Nip" or "InternalId", got "${args.contextType}".`
8455
+ );
8456
+ }
8457
+ return {
8458
+ contextIdentifier: {
8459
+ type: args.contextType,
8460
+ value: args.contextValue
8461
+ }
8462
+ };
8463
+ };
7744
8464
  switch (args.type) {
7745
8465
  case "personal": {
7746
- const response = await client.permissions.queryPersonalGrants({}, page, pageSize);
8466
+ const body = resolveContextBody();
8467
+ const response = await client.permissions.queryPersonalGrants(body, page, pageSize);
7747
8468
  if (args.json) {
7748
8469
  outputResult(response, { json: true });
7749
8470
  return;
@@ -7849,7 +8570,8 @@ var search = defineCommand6({
7849
8570
  break;
7850
8571
  }
7851
8572
  case "entities-grants": {
7852
- const response = await client.permissions.queryEntitiesGrants({}, page, pageSize);
8573
+ const body = resolveContextBody();
8574
+ const response = await client.permissions.queryEntitiesGrants(body, page, pageSize);
7853
8575
  if (args.json) {
7854
8576
  outputResult(response, { json: true });
7855
8577
  return;
@@ -7956,7 +8678,7 @@ var search = defineCommand6({
7956
8678
  default:
7957
8679
  throw new Error(`Unknown search type: ${args.type}. Use: personal, persons, subunits, entities, entities-grants, subordinate-entities, authorizations, eu-entities`);
7958
8680
  }
7959
- });
8681
+ }, { json: Boolean(args.json) });
7960
8682
  }
7961
8683
  });
7962
8684
  var status3 = defineCommand6({
@@ -7982,7 +8704,7 @@ var status3 = defineCommand6({
7982
8704
  "Status Description": result.status.description
7983
8705
  }, { json: false });
7984
8706
  }
7985
- });
8707
+ }, { json: Boolean(args.json) });
7986
8708
  }
7987
8709
  });
7988
8710
  var attachmentStatus = defineCommand6({
@@ -8006,7 +8728,7 @@ var attachmentStatus = defineCommand6({
8006
8728
  "Attachments": result.isAttachmentAllowed ? "Allowed" : "Not Allowed"
8007
8729
  }, { json: false });
8008
8730
  }
8009
- });
8731
+ }, { json: Boolean(args.json) });
8010
8732
  }
8011
8733
  });
8012
8734
  var permissionCommand = defineCommand6({
@@ -8059,7 +8781,7 @@ var generate = defineCommand7({
8059
8781
  "Token": result.token
8060
8782
  }, { json: false });
8061
8783
  }
8062
- });
8784
+ }, { json: Boolean(args.json) });
8063
8785
  }
8064
8786
  });
8065
8787
  var list2 = defineCommand7({
@@ -8118,7 +8840,7 @@ var list2 = defineCommand7({
8118
8840
  if (result.continuationToken) {
8119
8841
  consola10.info(`More results available. Continuation token: ${result.continuationToken}`);
8120
8842
  }
8121
- });
8843
+ }, { json: Boolean(args.json) });
8122
8844
  }
8123
8845
  });
8124
8846
  var get2 = defineCommand7({
@@ -8151,7 +8873,7 @@ var get2 = defineCommand7({
8151
8873
  "Last Used": result.lastUseDate ?? "Never"
8152
8874
  }, { json: false });
8153
8875
  }
8154
- });
8876
+ }, { json: Boolean(args.json) });
8155
8877
  }
8156
8878
  });
8157
8879
  var revoke3 = defineCommand7({
@@ -8175,7 +8897,7 @@ var revoke3 = defineCommand7({
8175
8897
  } else {
8176
8898
  outputSuccess(`Token ${ref} revoked.`);
8177
8899
  }
8178
- });
8900
+ }, { json: Boolean(args.json) });
8179
8901
  }
8180
8902
  });
8181
8903
  var tokenCommand = defineCommand7({
@@ -8358,7 +9080,7 @@ var generate2 = defineCommand8({
8358
9080
  "Private Key": keyPath
8359
9081
  }, { json: false });
8360
9082
  }
8361
- });
9083
+ }, { json: Boolean(args.json) });
8362
9084
  }
8363
9085
  });
8364
9086
  var enroll = defineCommand8({
@@ -8396,7 +9118,7 @@ var enroll = defineCommand8({
8396
9118
  "Timestamp": result.timestamp
8397
9119
  }, { json: false });
8398
9120
  }
8399
- });
9121
+ }, { json: Boolean(args.json) });
8400
9122
  }
8401
9123
  });
8402
9124
  var status4 = defineCommand8({
@@ -8428,7 +9150,7 @@ var status4 = defineCommand8({
8428
9150
  }
8429
9151
  outputKeyValue(kv, { json: false });
8430
9152
  }
8431
- });
9153
+ }, { json: Boolean(args.json) });
8432
9154
  }
8433
9155
  });
8434
9156
  var list3 = defineCommand8({
@@ -8491,7 +9213,7 @@ var list3 = defineCommand8({
8491
9213
  if (result.hasMore) {
8492
9214
  consola11.info("More results available. Use --page to paginate.");
8493
9215
  }
8494
- });
9216
+ }, { json: Boolean(args.json) });
8495
9217
  }
8496
9218
  });
8497
9219
  var revoke4 = defineCommand8({
@@ -8518,7 +9240,7 @@ var revoke4 = defineCommand8({
8518
9240
  } else {
8519
9241
  outputSuccess(`Certificate ${serial} revoked.`);
8520
9242
  }
8521
- });
9243
+ }, { json: Boolean(args.json) });
8522
9244
  }
8523
9245
  });
8524
9246
  var limits = defineCommand8({
@@ -8546,7 +9268,7 @@ var limits = defineCommand8({
8546
9268
  "Certificate Remaining": result.certificate.remaining
8547
9269
  }, { json: false });
8548
9270
  }
8549
- });
9271
+ }, { json: Boolean(args.json) });
8550
9272
  }
8551
9273
  });
8552
9274
  var enrollmentData = defineCommand8({
@@ -8577,7 +9299,7 @@ var enrollmentData = defineCommand8({
8577
9299
  if (result.organizationIdentifier) kv["Organization ID"] = result.organizationIdentifier;
8578
9300
  outputKeyValue(kv, { json: false });
8579
9301
  }
8580
- });
9302
+ }, { json: Boolean(args.json) });
8581
9303
  }
8582
9304
  });
8583
9305
  var retrieve = defineCommand8({
@@ -8620,7 +9342,7 @@ var retrieve = defineCommand8({
8620
9342
  ],
8621
9343
  { json: false }
8622
9344
  );
8623
- });
9345
+ }, { json: Boolean(args.json) });
8624
9346
  }
8625
9347
  });
8626
9348
  var certCommand = defineCommand8({
@@ -8749,7 +9471,7 @@ URL: ${url2}`);
8749
9471
  console.log(buffer.toString("base64"));
8750
9472
  }
8751
9473
  }
8752
- });
9474
+ }, { json: Boolean(args.json) });
8753
9475
  }
8754
9476
  });
8755
9477
  var certificate = defineCommand9({
@@ -8810,7 +9532,7 @@ URL: ${url2}`);
8810
9532
  console.log(buffer.toString("base64"));
8811
9533
  }
8812
9534
  }
8813
- });
9535
+ }, { json: Boolean(args.json) });
8814
9536
  }
8815
9537
  });
8816
9538
  var url = defineCommand9({
@@ -8834,7 +9556,7 @@ var url = defineCommand9({
8834
9556
  } else {
8835
9557
  console.log(verificationUrl);
8836
9558
  }
8837
- });
9559
+ }, { json: Boolean(args.json) });
8838
9560
  }
8839
9561
  });
8840
9562
  var qrCommand = defineCommand9({
@@ -8878,7 +9600,7 @@ var status5 = defineCommand10({
8878
9600
  "Timestamp": result.timestamp
8879
9601
  }, { json: false });
8880
9602
  }
8881
- });
9603
+ }, { json: Boolean(args.json) });
8882
9604
  }
8883
9605
  });
8884
9606
  var messages = defineCommand10({
@@ -8920,7 +9642,7 @@ var messages = defineCommand10({
8920
9642
  ],
8921
9643
  { json: false }
8922
9644
  );
8923
- });
9645
+ }, { json: Boolean(args.json) });
8924
9646
  }
8925
9647
  });
8926
9648
  var lighthouseCommand = defineCommand10({
@@ -8976,7 +9698,7 @@ var createSubject = defineCommand11({
8976
9698
  };
8977
9699
  await createClient(globalOpts).testData.createSubject(request);
8978
9700
  outputDone(args.json);
8979
- });
9701
+ }, { json: Boolean(args.json) });
8980
9702
  }
8981
9703
  });
8982
9704
  var removeSubject = defineCommand11({
@@ -8995,7 +9717,7 @@ var removeSubject = defineCommand11({
8995
9717
  const request = { subjectNip: args.nip };
8996
9718
  await createClient(globalOpts).testData.removeSubject(request);
8997
9719
  outputDone(args.json);
8998
- });
9720
+ }, { json: Boolean(args.json) });
8999
9721
  }
9000
9722
  });
9001
9723
  var createPerson = defineCommand11({
@@ -9026,7 +9748,7 @@ var createPerson = defineCommand11({
9026
9748
  };
9027
9749
  await createClient(globalOpts).testData.createPerson(request);
9028
9750
  outputDone(args.json);
9029
- });
9751
+ }, { json: Boolean(args.json) });
9030
9752
  }
9031
9753
  });
9032
9754
  var removePerson = defineCommand11({
@@ -9045,7 +9767,7 @@ var removePerson = defineCommand11({
9045
9767
  const request = { nip: args.nip };
9046
9768
  await createClient(globalOpts).testData.removePerson(request);
9047
9769
  outputDone(args.json);
9048
- });
9770
+ }, { json: Boolean(args.json) });
9049
9771
  }
9050
9772
  });
9051
9773
  var grantPermissions = defineCommand11({
@@ -9076,7 +9798,7 @@ var grantPermissions = defineCommand11({
9076
9798
  };
9077
9799
  await createClient(globalOpts).testData.grantPermissions(request);
9078
9800
  outputDone(args.json);
9079
- });
9801
+ }, { json: Boolean(args.json) });
9080
9802
  }
9081
9803
  });
9082
9804
  var revokePermissions = defineCommand11({
@@ -9104,7 +9826,7 @@ var revokePermissions = defineCommand11({
9104
9826
  };
9105
9827
  await createClient(globalOpts).testData.revokePermissions(request);
9106
9828
  outputDone(args.json);
9107
- });
9829
+ }, { json: Boolean(args.json) });
9108
9830
  }
9109
9831
  });
9110
9832
  var enableAttachment = defineCommand11({
@@ -9123,7 +9845,7 @@ var enableAttachment = defineCommand11({
9123
9845
  const request = { nip: args.nip };
9124
9846
  await createClient(globalOpts).testData.enableAttachment(request);
9125
9847
  outputDone(args.json);
9126
- });
9848
+ }, { json: Boolean(args.json) });
9127
9849
  }
9128
9850
  });
9129
9851
  var disableAttachment = defineCommand11({
@@ -9146,7 +9868,7 @@ var disableAttachment = defineCommand11({
9146
9868
  };
9147
9869
  await createClient(globalOpts).testData.disableAttachment(request);
9148
9870
  outputDone(args.json);
9149
- });
9871
+ }, { json: Boolean(args.json) });
9150
9872
  }
9151
9873
  });
9152
9874
  var changeSessionLimits = defineCommand11({
@@ -9183,7 +9905,7 @@ var changeSessionLimits = defineCommand11({
9183
9905
  };
9184
9906
  await client.testData.changeSessionLimits(request);
9185
9907
  outputDone(args.json);
9186
- });
9908
+ }, { json: Boolean(args.json) });
9187
9909
  }
9188
9910
  });
9189
9911
  var restoreSessionLimits = defineCommand11({
@@ -9202,7 +9924,7 @@ var restoreSessionLimits = defineCommand11({
9202
9924
  const { client } = await requireSession(globalOpts);
9203
9925
  await client.testData.restoreDefaultSessionLimits();
9204
9926
  outputDone(args.json);
9205
- });
9927
+ }, { json: Boolean(args.json) });
9206
9928
  }
9207
9929
  });
9208
9930
  var changeCertLimits = defineCommand11({
@@ -9229,7 +9951,7 @@ var changeCertLimits = defineCommand11({
9229
9951
  };
9230
9952
  await client.testData.changeCertificatesLimit(request);
9231
9953
  outputDone(args.json);
9232
- });
9954
+ }, { json: Boolean(args.json) });
9233
9955
  }
9234
9956
  });
9235
9957
  var restoreCertLimits = defineCommand11({
@@ -9248,7 +9970,7 @@ var restoreCertLimits = defineCommand11({
9248
9970
  const { client } = await requireSession(globalOpts);
9249
9971
  await client.testData.restoreDefaultCertificatesLimit();
9250
9972
  outputDone(args.json);
9251
- });
9973
+ }, { json: Boolean(args.json) });
9252
9974
  }
9253
9975
  });
9254
9976
  var setRateLimits = defineCommand11({
@@ -9271,7 +9993,7 @@ var setRateLimits = defineCommand11({
9271
9993
  };
9272
9994
  await client.testData.setRateLimits(request);
9273
9995
  outputDone(args.json);
9274
- });
9996
+ }, { json: Boolean(args.json) });
9275
9997
  }
9276
9998
  });
9277
9999
  var restoreRateLimits = defineCommand11({
@@ -9290,7 +10012,7 @@ var restoreRateLimits = defineCommand11({
9290
10012
  const { client } = await requireSession(globalOpts);
9291
10013
  await client.testData.restoreDefaultRateLimits();
9292
10014
  outputDone(args.json);
9293
- });
10015
+ }, { json: Boolean(args.json) });
9294
10016
  }
9295
10017
  });
9296
10018
  var setProductionRateLimits = defineCommand11({
@@ -9309,7 +10031,7 @@ var setProductionRateLimits = defineCommand11({
9309
10031
  const { client } = await requireSession(globalOpts);
9310
10032
  await client.testData.setProductionRateLimits();
9311
10033
  outputDone(args.json);
9312
- });
10034
+ }, { json: Boolean(args.json) });
9313
10035
  }
9314
10036
  });
9315
10037
  var blockContext = defineCommand11({
@@ -9336,7 +10058,7 @@ var blockContext = defineCommand11({
9336
10058
  };
9337
10059
  await client.testData.blockContext(request);
9338
10060
  outputDone(args.json);
9339
- });
10061
+ }, { json: Boolean(args.json) });
9340
10062
  }
9341
10063
  });
9342
10064
  var unblockContext = defineCommand11({
@@ -9363,7 +10085,7 @@ var unblockContext = defineCommand11({
9363
10085
  };
9364
10086
  await client.testData.unblockContext(request);
9365
10087
  outputDone(args.json);
9366
- });
10088
+ }, { json: Boolean(args.json) });
9367
10089
  }
9368
10090
  });
9369
10091
  var testDataCommand = defineCommand11({
@@ -9425,7 +10147,7 @@ var context = defineCommand12({
9425
10147
  "Batch \u2014 Max Invoices": result.batchSession.maxInvoices
9426
10148
  }, { json: false });
9427
10149
  }
9428
- });
10150
+ }, { json: Boolean(args.json) });
9429
10151
  }
9430
10152
  });
9431
10153
  var subject = defineCommand12({
@@ -9449,7 +10171,7 @@ var subject = defineCommand12({
9449
10171
  "Max Certificates": result.certificate?.maxCertificates ?? "Unlimited"
9450
10172
  }, { json: false });
9451
10173
  }
9452
- });
10174
+ }, { json: Boolean(args.json) });
9453
10175
  }
9454
10176
  });
9455
10177
  var rate = defineCommand12({
@@ -9485,7 +10207,7 @@ var rate = defineCommand12({
9485
10207
  ],
9486
10208
  { json: false }
9487
10209
  );
9488
- });
10210
+ }, { json: Boolean(args.json) });
9489
10211
  }
9490
10212
  });
9491
10213
  var limitsCommand = defineCommand12({
@@ -9546,7 +10268,7 @@ var providers = defineCommand13({
9546
10268
  if (result.hasMore) {
9547
10269
  consola12.info("More results available. Use --page to paginate.");
9548
10270
  }
9549
- });
10271
+ }, { json: Boolean(args.json) });
9550
10272
  }
9551
10273
  });
9552
10274
  var peppolCommand = defineCommand13({
@@ -9657,7 +10379,7 @@ ${passed}/${total} checks passed.`);
9657
10379
  consola13.warn(`
9658
10380
  ${passed}/${total} checks passed.`);
9659
10381
  }
9660
- });
10382
+ }, { json: Boolean(args.json) });
9661
10383
  }
9662
10384
  });
9663
10385
 
@@ -10042,7 +10764,7 @@ var setupCommand = defineCommand16({
10042
10764
  " ksef session open \u2014 Open an online session",
10043
10765
  " ksef auth whoami \u2014 Check current session"
10044
10766
  ].join("\n"));
10045
- });
10767
+ }, { json: Boolean(args.json) });
10046
10768
  }
10047
10769
  });
10048
10770
 
@@ -10280,7 +11002,7 @@ var generate3 = defineCommand17({
10280
11002
  "KOD II": metadata.kod2Url ?? "(not generated)"
10281
11003
  }, { json: false });
10282
11004
  }
10283
- });
11005
+ }, { json: Boolean(args.json) });
10284
11006
  }
10285
11007
  });
10286
11008
  var list4 = defineCommand17({
@@ -10329,7 +11051,7 @@ var list4 = defineCommand17({
10329
11051
  ],
10330
11052
  { json: args.json }
10331
11053
  );
10332
- });
11054
+ }, { json: Boolean(args.json) });
10333
11055
  }
10334
11056
  });
10335
11057
  var status6 = defineCommand17({
@@ -10365,7 +11087,7 @@ var status6 = defineCommand17({
10365
11087
  Error: invoice3.error ? `${invoice3.error.code}: ${invoice3.error.message}` : "-"
10366
11088
  }, { json: false });
10367
11089
  }
10368
- });
11090
+ }, { json: Boolean(args.json) });
10369
11091
  }
10370
11092
  });
10371
11093
  var submit = defineCommand17({
@@ -10421,7 +11143,7 @@ var submit = defineCommand17({
10421
11143
  );
10422
11144
  }
10423
11145
  }
10424
- });
11146
+ }, { json: Boolean(args.json) });
10425
11147
  }
10426
11148
  });
10427
11149
  var correct = defineCommand17({
@@ -10451,7 +11173,7 @@ var correct = defineCommand17({
10451
11173
  } else {
10452
11174
  outputSuccess(`Correction submitted. KSeF ref: ${result.ksefReferenceNumber ?? "pending"}`);
10453
11175
  }
10454
- });
11176
+ }, { json: Boolean(args.json) });
10455
11177
  }
10456
11178
  });
10457
11179
  var del = defineCommand17({
@@ -10501,7 +11223,7 @@ var del = defineCommand17({
10501
11223
  }
10502
11224
  await storage.delete(args.id);
10503
11225
  outputSuccess(`Deleted offline invoice ${args.id}`);
10504
- });
11226
+ }, { json: Boolean(args.json) });
10505
11227
  }
10506
11228
  });
10507
11229
  var offlineCommand = defineCommand17({