ksef-client-ts 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +194 -40
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +276 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -7
- package/dist/index.d.ts +109 -7
- package/dist/index.js +269 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -955,7 +955,9 @@ function isValidVatUe(value) {
|
|
|
955
955
|
return VatUe.test(value);
|
|
956
956
|
}
|
|
957
957
|
function isValidNipVatUe(value) {
|
|
958
|
-
|
|
958
|
+
if (!NipVatUe.test(value)) return false;
|
|
959
|
+
const nip = value.split("-")[0];
|
|
960
|
+
return isValidNip(nip);
|
|
959
961
|
}
|
|
960
962
|
function isValidInternalId(value) {
|
|
961
963
|
return InternalId.test(value);
|
|
@@ -2967,6 +2969,32 @@ var init_online_session = __esm({
|
|
|
2967
2969
|
}
|
|
2968
2970
|
});
|
|
2969
2971
|
|
|
2972
|
+
// src/utils/concurrency.ts
|
|
2973
|
+
async function runWithConcurrency(tasks, parallelism) {
|
|
2974
|
+
if (tasks.length === 0) return;
|
|
2975
|
+
const limit = Math.max(1, Math.min(parallelism, tasks.length));
|
|
2976
|
+
const controller = new AbortController();
|
|
2977
|
+
let index = 0;
|
|
2978
|
+
const workers = Array.from({ length: limit }, async () => {
|
|
2979
|
+
while (index < tasks.length && !controller.signal.aborted) {
|
|
2980
|
+
const current = index;
|
|
2981
|
+
index += 1;
|
|
2982
|
+
try {
|
|
2983
|
+
await tasks[current](controller.signal);
|
|
2984
|
+
} catch (err) {
|
|
2985
|
+
controller.abort();
|
|
2986
|
+
throw err;
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
});
|
|
2990
|
+
await Promise.all(workers);
|
|
2991
|
+
}
|
|
2992
|
+
var init_concurrency = __esm({
|
|
2993
|
+
"src/utils/concurrency.ts"() {
|
|
2994
|
+
"use strict";
|
|
2995
|
+
}
|
|
2996
|
+
});
|
|
2997
|
+
|
|
2970
2998
|
// src/services/batch-session.ts
|
|
2971
2999
|
var BatchSessionService;
|
|
2972
3000
|
var init_batch_session = __esm({
|
|
@@ -2975,6 +3003,7 @@ var init_batch_session = __esm({
|
|
|
2975
3003
|
init_ksef_feature();
|
|
2976
3004
|
init_rest_request();
|
|
2977
3005
|
init_routes();
|
|
3006
|
+
init_concurrency();
|
|
2978
3007
|
BatchSessionService = class {
|
|
2979
3008
|
restClient;
|
|
2980
3009
|
constructor(restClient) {
|
|
@@ -2988,12 +3017,10 @@ var init_batch_session = __esm({
|
|
|
2988
3017
|
const response = await this.restClient.execute(req);
|
|
2989
3018
|
return response.body;
|
|
2990
3019
|
}
|
|
2991
|
-
async sendParts(openResponse, parts) {
|
|
2992
|
-
const
|
|
2993
|
-
const tasks = parts.map(async (
|
|
2994
|
-
const uploadReq =
|
|
2995
|
-
(r) => r.ordinalNumber === part.ordinalNumber
|
|
2996
|
-
);
|
|
3020
|
+
async sendParts(openResponse, parts, parallelism) {
|
|
3021
|
+
const uploadMap = new Map(openResponse.partUploadRequests.map((r) => [r.ordinalNumber, r]));
|
|
3022
|
+
const tasks = parts.map((part) => async (signal) => {
|
|
3023
|
+
const uploadReq = uploadMap.get(part.ordinalNumber);
|
|
2997
3024
|
if (!uploadReq) {
|
|
2998
3025
|
throw new Error(`No upload request found for part ${part.ordinalNumber}`);
|
|
2999
3026
|
}
|
|
@@ -3001,25 +3028,38 @@ var init_batch_session = __esm({
|
|
|
3001
3028
|
for (const [k, v] of Object.entries(uploadReq.headers)) {
|
|
3002
3029
|
if (v != null) headers[k] = v;
|
|
3003
3030
|
}
|
|
3004
|
-
await fetch(uploadReq.url, {
|
|
3031
|
+
const resp = await fetch(uploadReq.url, {
|
|
3005
3032
|
method: uploadReq.method,
|
|
3006
3033
|
headers,
|
|
3007
|
-
body: part.data
|
|
3034
|
+
body: part.data,
|
|
3035
|
+
signal
|
|
3008
3036
|
});
|
|
3037
|
+
if (!resp.ok) {
|
|
3038
|
+
const body = await resp.text().catch(() => "");
|
|
3039
|
+
throw new Error(
|
|
3040
|
+
`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}${body ? ` \u2014 ${body}` : ""}`
|
|
3041
|
+
);
|
|
3042
|
+
}
|
|
3009
3043
|
});
|
|
3010
|
-
|
|
3044
|
+
if (parallelism !== void 0) {
|
|
3045
|
+
await runWithConcurrency(tasks, parallelism);
|
|
3046
|
+
} else {
|
|
3047
|
+
const ac = new AbortController();
|
|
3048
|
+
await Promise.all(tasks.map((t) => t(ac.signal).catch((err) => {
|
|
3049
|
+
ac.abort();
|
|
3050
|
+
throw err;
|
|
3051
|
+
})));
|
|
3052
|
+
}
|
|
3011
3053
|
}
|
|
3012
3054
|
/**
|
|
3013
|
-
* Upload parts
|
|
3014
|
-
*
|
|
3015
|
-
*
|
|
3055
|
+
* Upload parts using streaming bodies (`duplex: 'half'`).
|
|
3056
|
+
* By default uploads sequentially to avoid backpressure issues.
|
|
3057
|
+
* Pass `parallelism` to enable bounded concurrent uploads.
|
|
3016
3058
|
*/
|
|
3017
|
-
async sendPartsWithStream(openResponse, parts) {
|
|
3018
|
-
const
|
|
3019
|
-
|
|
3020
|
-
const uploadReq =
|
|
3021
|
-
(r) => r.ordinalNumber === part.ordinalNumber
|
|
3022
|
-
);
|
|
3059
|
+
async sendPartsWithStream(openResponse, parts, parallelism) {
|
|
3060
|
+
const uploadMap = new Map(openResponse.partUploadRequests.map((r) => [r.ordinalNumber, r]));
|
|
3061
|
+
const uploadPart = async (part, signal) => {
|
|
3062
|
+
const uploadReq = uploadMap.get(part.ordinalNumber);
|
|
3023
3063
|
if (!uploadReq) {
|
|
3024
3064
|
throw new Error(`No upload request found for part ${part.ordinalNumber}`);
|
|
3025
3065
|
}
|
|
@@ -3031,11 +3071,23 @@ var init_batch_session = __esm({
|
|
|
3031
3071
|
method: uploadReq.method,
|
|
3032
3072
|
headers,
|
|
3033
3073
|
body: part.dataStream,
|
|
3074
|
+
signal,
|
|
3034
3075
|
// @ts-expect-error -- Node 18+ undici supports duplex for streaming body
|
|
3035
3076
|
duplex: "half"
|
|
3036
3077
|
});
|
|
3037
3078
|
if (!resp.ok) {
|
|
3038
|
-
|
|
3079
|
+
const body = await resp.text().catch(() => "");
|
|
3080
|
+
throw new Error(
|
|
3081
|
+
`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}${body ? ` \u2014 ${body}` : ""}`
|
|
3082
|
+
);
|
|
3083
|
+
}
|
|
3084
|
+
};
|
|
3085
|
+
if (parallelism !== void 0) {
|
|
3086
|
+
await runWithConcurrency(parts.map((p) => (signal) => uploadPart(p, signal)), parallelism);
|
|
3087
|
+
} else {
|
|
3088
|
+
const { signal } = new AbortController();
|
|
3089
|
+
for (const part of parts) {
|
|
3090
|
+
await uploadPart(part, signal);
|
|
3039
3091
|
}
|
|
3040
3092
|
}
|
|
3041
3093
|
}
|
|
@@ -3148,7 +3200,10 @@ var init_invoice_download = __esm({
|
|
|
3148
3200
|
async getInvoice(ksefNumber) {
|
|
3149
3201
|
const req = RestRequest.get(Routes.Invoices.byKsefNumber(ksefNumber));
|
|
3150
3202
|
const response = await this.restClient.executeRaw(req);
|
|
3151
|
-
return
|
|
3203
|
+
return {
|
|
3204
|
+
xml: new TextDecoder().decode(response.body),
|
|
3205
|
+
hash: response.headers.get("x-ms-meta-hash") ?? void 0
|
|
3206
|
+
};
|
|
3152
3207
|
}
|
|
3153
3208
|
async queryInvoiceMetadata(filters, pageOffset, pageSize, sortOrder) {
|
|
3154
3209
|
const req = RestRequest.post(Routes.Invoices.queryMetadata).body(filters);
|
|
@@ -4410,6 +4465,72 @@ var init_zip = __esm({
|
|
|
4410
4465
|
}
|
|
4411
4466
|
});
|
|
4412
4467
|
|
|
4468
|
+
// src/offline/holidays.ts
|
|
4469
|
+
function toDateKey(d) {
|
|
4470
|
+
return d.toISOString().slice(0, 10);
|
|
4471
|
+
}
|
|
4472
|
+
function dateKey(year, month, day) {
|
|
4473
|
+
return toDateKey(new Date(Date.UTC(year, month - 1, day)));
|
|
4474
|
+
}
|
|
4475
|
+
function addDays(d, n) {
|
|
4476
|
+
const result = new Date(d);
|
|
4477
|
+
result.setUTCDate(result.getUTCDate() + n);
|
|
4478
|
+
return result;
|
|
4479
|
+
}
|
|
4480
|
+
function computeEasterSunday(year) {
|
|
4481
|
+
const a = year % 19;
|
|
4482
|
+
const b = Math.floor(year / 100);
|
|
4483
|
+
const c = year % 100;
|
|
4484
|
+
const d = Math.floor(b / 4);
|
|
4485
|
+
const e = b % 4;
|
|
4486
|
+
const f = Math.floor((b + 8) / 25);
|
|
4487
|
+
const g = Math.floor((b - f + 1) / 3);
|
|
4488
|
+
const h = (19 * a + b - d - g + 15) % 30;
|
|
4489
|
+
const i = Math.floor(c / 4);
|
|
4490
|
+
const k = c % 4;
|
|
4491
|
+
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
|
4492
|
+
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
|
4493
|
+
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
|
4494
|
+
const day = (h + l - 7 * m + 114) % 31 + 1;
|
|
4495
|
+
return new Date(Date.UTC(year, month - 1, day));
|
|
4496
|
+
}
|
|
4497
|
+
function getPolishHolidays(year) {
|
|
4498
|
+
const cached = holidayCache.get(year);
|
|
4499
|
+
if (cached) return cached;
|
|
4500
|
+
const easter = computeEasterSunday(year);
|
|
4501
|
+
const holidays = /* @__PURE__ */ new Set([
|
|
4502
|
+
// Fixed
|
|
4503
|
+
dateKey(year, 1, 1),
|
|
4504
|
+
dateKey(year, 1, 6),
|
|
4505
|
+
dateKey(year, 5, 1),
|
|
4506
|
+
dateKey(year, 5, 3),
|
|
4507
|
+
dateKey(year, 8, 15),
|
|
4508
|
+
dateKey(year, 11, 1),
|
|
4509
|
+
dateKey(year, 11, 11),
|
|
4510
|
+
dateKey(year, 12, 25),
|
|
4511
|
+
dateKey(year, 12, 26),
|
|
4512
|
+
// Wigilia — added by Dz.U. 2024 poz. 1965, effective from 2025
|
|
4513
|
+
...year >= 2025 ? [dateKey(year, 12, 24)] : [],
|
|
4514
|
+
// Moveable
|
|
4515
|
+
toDateKey(easter),
|
|
4516
|
+
toDateKey(addDays(easter, 1)),
|
|
4517
|
+
toDateKey(addDays(easter, 49)),
|
|
4518
|
+
toDateKey(addDays(easter, 60))
|
|
4519
|
+
]);
|
|
4520
|
+
holidayCache.set(year, holidays);
|
|
4521
|
+
return holidays;
|
|
4522
|
+
}
|
|
4523
|
+
function isPolishHoliday(date) {
|
|
4524
|
+
return getPolishHolidays(date.getUTCFullYear()).has(toDateKey(date));
|
|
4525
|
+
}
|
|
4526
|
+
var holidayCache;
|
|
4527
|
+
var init_holidays = __esm({
|
|
4528
|
+
"src/offline/holidays.ts"() {
|
|
4529
|
+
"use strict";
|
|
4530
|
+
holidayCache = /* @__PURE__ */ new Map();
|
|
4531
|
+
}
|
|
4532
|
+
});
|
|
4533
|
+
|
|
4413
4534
|
// src/offline/deadline.ts
|
|
4414
4535
|
function getDefaultReason(mode) {
|
|
4415
4536
|
switch (mode) {
|
|
@@ -4426,7 +4547,7 @@ function getDefaultReason(mode) {
|
|
|
4426
4547
|
function nextBusinessDay(from) {
|
|
4427
4548
|
const d = new Date(from);
|
|
4428
4549
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
4429
|
-
while (d.getUTCDay() === 0 || d.getUTCDay() === 6) {
|
|
4550
|
+
while (d.getUTCDay() === 0 || d.getUTCDay() === 6 || isPolishHoliday(d)) {
|
|
4430
4551
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
4431
4552
|
}
|
|
4432
4553
|
return d;
|
|
@@ -4439,7 +4560,7 @@ function addBusinessDays(from, days) {
|
|
|
4439
4560
|
let remaining = days;
|
|
4440
4561
|
while (remaining > 0) {
|
|
4441
4562
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
4442
|
-
if (d.getUTCDay() !== 0 && d.getUTCDay() !== 6) {
|
|
4563
|
+
if (d.getUTCDay() !== 0 && d.getUTCDay() !== 6 && !isPolishHoliday(d)) {
|
|
4443
4564
|
remaining--;
|
|
4444
4565
|
}
|
|
4445
4566
|
}
|
|
@@ -4505,12 +4626,13 @@ var FAR_FUTURE;
|
|
|
4505
4626
|
var init_deadline = __esm({
|
|
4506
4627
|
"src/offline/deadline.ts"() {
|
|
4507
4628
|
"use strict";
|
|
4629
|
+
init_holidays();
|
|
4508
4630
|
FAR_FUTURE = /* @__PURE__ */ new Date("9999-12-31T23:59:59Z");
|
|
4509
4631
|
}
|
|
4510
4632
|
});
|
|
4511
4633
|
|
|
4512
4634
|
// src/workflows/offline-invoice-workflow.ts
|
|
4513
|
-
import
|
|
4635
|
+
import crypto7 from "crypto";
|
|
4514
4636
|
var OfflineInvoiceWorkflow;
|
|
4515
4637
|
var init_offline_invoice_workflow = __esm({
|
|
4516
4638
|
"src/workflows/offline-invoice-workflow.ts"() {
|
|
@@ -4534,7 +4656,7 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4534
4656
|
}
|
|
4535
4657
|
const mode = options?.mode ?? "offline24";
|
|
4536
4658
|
const reason = getDefaultReason(mode);
|
|
4537
|
-
const invoiceHashBase64 =
|
|
4659
|
+
const invoiceHashBase64 = crypto7.createHash("sha256").update(input.invoiceXml).digest("base64");
|
|
4538
4660
|
const kod1Url = this.qrService.buildInvoiceVerificationUrl(
|
|
4539
4661
|
input.sellerNip,
|
|
4540
4662
|
input.invoiceDate,
|
|
@@ -4553,7 +4675,7 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4553
4675
|
}
|
|
4554
4676
|
const submitBy = options?.customDeadline ? typeof options.customDeadline === "string" ? options.customDeadline : options.customDeadline.toISOString() : calculateOfflineDeadline(mode, input.invoiceDate, options?.maintenanceWindow).toISOString();
|
|
4555
4677
|
const metadata = {
|
|
4556
|
-
id:
|
|
4678
|
+
id: crypto7.randomUUID(),
|
|
4557
4679
|
mode,
|
|
4558
4680
|
reason,
|
|
4559
4681
|
status: "GENERATED",
|
|
@@ -4709,7 +4831,7 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4709
4831
|
original.status === "CORRECTED" ? `Invoice ${rejectedInvoiceId} has already been corrected (by ${original.correctedBy})` : `Only rejected invoices can be corrected (current status: ${original.status})`
|
|
4710
4832
|
);
|
|
4711
4833
|
}
|
|
4712
|
-
const originalHash =
|
|
4834
|
+
const originalHash = crypto7.createHash("sha256").update(original.invoiceXml).digest("base64");
|
|
4713
4835
|
await client.crypto.init();
|
|
4714
4836
|
const encData = client.crypto.getEncryptionData();
|
|
4715
4837
|
const formCode = options.formCode ?? DEFAULT_FORM_CODE;
|
|
@@ -4722,9 +4844,9 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4722
4844
|
const plainMeta = client.crypto.getFileMetadata(data);
|
|
4723
4845
|
const encrypted = client.crypto.encryptAES256(data, encData.cipherKey, encData.cipherIv);
|
|
4724
4846
|
const encMeta = client.crypto.getFileMetadata(encrypted);
|
|
4725
|
-
const correctionId =
|
|
4847
|
+
const correctionId = crypto7.randomUUID();
|
|
4726
4848
|
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4727
|
-
const correctedHashBase64 =
|
|
4849
|
+
const correctedHashBase64 = crypto7.createHash("sha256").update(correctedInvoiceXml).digest("base64");
|
|
4728
4850
|
const kod1Url = this.qrService.buildInvoiceVerificationUrl(
|
|
4729
4851
|
original.sellerNip,
|
|
4730
4852
|
original.invoiceDate,
|
|
@@ -4879,6 +5001,7 @@ var init_client = __esm({
|
|
|
4879
5001
|
qr;
|
|
4880
5002
|
options;
|
|
4881
5003
|
authManager;
|
|
5004
|
+
_baseRestClientConfig;
|
|
4882
5005
|
_offline;
|
|
4883
5006
|
constructor(options) {
|
|
4884
5007
|
this.options = resolveOptions(options);
|
|
@@ -4890,6 +5013,8 @@ var init_client = __esm({
|
|
|
4890
5013
|
});
|
|
4891
5014
|
this.authManager = authManager;
|
|
4892
5015
|
const restClientConfig = buildRestClientConfig(options, authManager);
|
|
5016
|
+
const { authManager: _am, ...baseConfig } = restClientConfig;
|
|
5017
|
+
this._baseRestClientConfig = baseConfig;
|
|
4893
5018
|
const restClient = new RestClient(this.options, restClientConfig);
|
|
4894
5019
|
const fetcher = new CertificateFetcher(restClient);
|
|
4895
5020
|
this.crypto = new CryptographyService(fetcher);
|
|
@@ -4914,6 +5039,10 @@ var init_client = __esm({
|
|
|
4914
5039
|
}
|
|
4915
5040
|
return this._offline;
|
|
4916
5041
|
}
|
|
5042
|
+
/** @internal Create a RestClient with a different AuthManager, preserving transport/retry/rateLimit config. */
|
|
5043
|
+
createScopedRestClient(authManager) {
|
|
5044
|
+
return new RestClient(this.options, { ...this._baseRestClientConfig, authManager });
|
|
5045
|
+
}
|
|
4917
5046
|
async loginWithToken(token, nip) {
|
|
4918
5047
|
const challenge = await this.auth.getChallenge();
|
|
4919
5048
|
await this.crypto.init();
|
|
@@ -5733,6 +5862,18 @@ function parseKSeFTokenContext(token) {
|
|
|
5733
5862
|
};
|
|
5734
5863
|
}
|
|
5735
5864
|
|
|
5865
|
+
// src/utils/hash.ts
|
|
5866
|
+
import crypto6 from "crypto";
|
|
5867
|
+
function sha256Base642(data) {
|
|
5868
|
+
return crypto6.createHash("sha256").update(data).digest("base64");
|
|
5869
|
+
}
|
|
5870
|
+
function verifyHash(data, expectedHash) {
|
|
5871
|
+
return sha256Base642(data) === expectedHash;
|
|
5872
|
+
}
|
|
5873
|
+
|
|
5874
|
+
// src/utils/index.ts
|
|
5875
|
+
init_concurrency();
|
|
5876
|
+
|
|
5736
5877
|
// src/workflows/polling.ts
|
|
5737
5878
|
async function pollUntil(action, condition, options) {
|
|
5738
5879
|
const intervalMs = options?.intervalMs ?? 2e3;
|
|
@@ -5751,6 +5892,10 @@ async function pollUntil(action, condition, options) {
|
|
|
5751
5892
|
}
|
|
5752
5893
|
|
|
5753
5894
|
// src/workflows/online-session-workflow.ts
|
|
5895
|
+
init_ksef_session_expired_error();
|
|
5896
|
+
init_auth_manager();
|
|
5897
|
+
init_online_session();
|
|
5898
|
+
init_session_status();
|
|
5754
5899
|
init_document_structures();
|
|
5755
5900
|
|
|
5756
5901
|
// src/xml/upo-parser.ts
|
|
@@ -5914,18 +6059,11 @@ function nonEmptyString(value) {
|
|
|
5914
6059
|
// src/workflows/online-session-workflow.ts
|
|
5915
6060
|
init_invoice_validator();
|
|
5916
6061
|
init_ksef_validation_error();
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
const encData = client.crypto.getEncryptionData();
|
|
5920
|
-
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
5921
|
-
const openResp = await client.onlineSession.openSession(
|
|
5922
|
-
{ formCode, encryption: encData.encryptionInfo },
|
|
5923
|
-
options?.upoVersion
|
|
5924
|
-
);
|
|
5925
|
-
const sessionRef = openResp.referenceNumber;
|
|
6062
|
+
function buildSessionHandle(params) {
|
|
6063
|
+
const { deps, sessionRef, validUntil, cipherKey, cipherIv, formCode, validate: validate2 } = params;
|
|
5926
6064
|
async function fetchUpo(pollOpts) {
|
|
5927
6065
|
const result = await pollUntil(
|
|
5928
|
-
() =>
|
|
6066
|
+
() => deps.sessionStatus.getSessionStatus(sessionRef),
|
|
5929
6067
|
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
5930
6068
|
{ ...pollOpts, description: `UPO for session ${sessionRef}` }
|
|
5931
6069
|
);
|
|
@@ -5941,9 +6079,9 @@ async function openOnlineSession(client, options) {
|
|
|
5941
6079
|
}
|
|
5942
6080
|
return {
|
|
5943
6081
|
sessionRef,
|
|
5944
|
-
validUntil
|
|
6082
|
+
validUntil,
|
|
5945
6083
|
async sendInvoice(invoiceXml) {
|
|
5946
|
-
if (
|
|
6084
|
+
if (validate2) {
|
|
5947
6085
|
const xmlStr = typeof invoiceXml === "string" ? invoiceXml : new TextDecoder().decode(invoiceXml);
|
|
5948
6086
|
const vResult = await validate(xmlStr);
|
|
5949
6087
|
if (!vResult.valid) {
|
|
@@ -5954,10 +6092,10 @@ async function openOnlineSession(client, options) {
|
|
|
5954
6092
|
}
|
|
5955
6093
|
}
|
|
5956
6094
|
const data = typeof invoiceXml === "string" ? new TextEncoder().encode(invoiceXml) : invoiceXml;
|
|
5957
|
-
const plainMeta =
|
|
5958
|
-
const encrypted =
|
|
5959
|
-
const encMeta =
|
|
5960
|
-
const resp = await
|
|
6095
|
+
const plainMeta = deps.crypto.getFileMetadata(data);
|
|
6096
|
+
const encrypted = deps.crypto.encryptAES256(data, cipherKey, cipherIv);
|
|
6097
|
+
const encMeta = deps.crypto.getFileMetadata(encrypted);
|
|
6098
|
+
const resp = await deps.onlineSession.sendInvoice(sessionRef, {
|
|
5961
6099
|
invoiceHash: plainMeta.hashSHA,
|
|
5962
6100
|
invoiceSize: plainMeta.fileSize,
|
|
5963
6101
|
encryptedInvoiceHash: encMeta.hashSHA,
|
|
@@ -5967,7 +6105,7 @@ async function openOnlineSession(client, options) {
|
|
|
5967
6105
|
return resp.referenceNumber;
|
|
5968
6106
|
},
|
|
5969
6107
|
async close() {
|
|
5970
|
-
await
|
|
6108
|
+
await deps.onlineSession.closeSession(sessionRef);
|
|
5971
6109
|
},
|
|
5972
6110
|
async waitForUpo(pollOpts) {
|
|
5973
6111
|
return fetchUpo(pollOpts);
|
|
@@ -5976,13 +6114,75 @@ async function openOnlineSession(client, options) {
|
|
|
5976
6114
|
const upoInfo = await fetchUpo(pollOpts);
|
|
5977
6115
|
const parsed = [];
|
|
5978
6116
|
for (const page of upoInfo.pages) {
|
|
5979
|
-
const result = await
|
|
6117
|
+
const result = await deps.sessionStatus.getSessionUpo(sessionRef, page.referenceNumber);
|
|
5980
6118
|
parsed.push(parseUpoXml(result.upo));
|
|
5981
6119
|
}
|
|
5982
6120
|
return { ...upoInfo, parsed };
|
|
6121
|
+
},
|
|
6122
|
+
getState() {
|
|
6123
|
+
const token = deps.getAccessToken();
|
|
6124
|
+
if (!token) {
|
|
6125
|
+
throw new Error("Cannot serialize session state: no access token available");
|
|
6126
|
+
}
|
|
6127
|
+
return {
|
|
6128
|
+
referenceNumber: sessionRef,
|
|
6129
|
+
aesKey: Buffer.from(cipherKey).toString("base64"),
|
|
6130
|
+
iv: Buffer.from(cipherIv).toString("base64"),
|
|
6131
|
+
accessToken: token,
|
|
6132
|
+
formCode,
|
|
6133
|
+
validUntil,
|
|
6134
|
+
...validate2 ? { validate: validate2 } : {}
|
|
6135
|
+
};
|
|
5983
6136
|
}
|
|
5984
6137
|
};
|
|
5985
6138
|
}
|
|
6139
|
+
async function openOnlineSession(client, options) {
|
|
6140
|
+
await client.crypto.init();
|
|
6141
|
+
const encData = client.crypto.getEncryptionData();
|
|
6142
|
+
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
6143
|
+
const openResp = await client.onlineSession.openSession(
|
|
6144
|
+
{ formCode, encryption: encData.encryptionInfo },
|
|
6145
|
+
options?.upoVersion
|
|
6146
|
+
);
|
|
6147
|
+
return buildSessionHandle({
|
|
6148
|
+
deps: {
|
|
6149
|
+
crypto: client.crypto,
|
|
6150
|
+
onlineSession: client.onlineSession,
|
|
6151
|
+
sessionStatus: client.sessionStatus,
|
|
6152
|
+
getAccessToken: () => client.authManager.getAccessToken()
|
|
6153
|
+
},
|
|
6154
|
+
sessionRef: openResp.referenceNumber,
|
|
6155
|
+
validUntil: openResp.validUntil,
|
|
6156
|
+
cipherKey: encData.cipherKey,
|
|
6157
|
+
cipherIv: encData.cipherIv,
|
|
6158
|
+
formCode,
|
|
6159
|
+
validate: options?.validate
|
|
6160
|
+
});
|
|
6161
|
+
}
|
|
6162
|
+
function resumeOnlineSession(client, state, options) {
|
|
6163
|
+
const expiry = new Date(state.validUntil);
|
|
6164
|
+
if (expiry.getTime() <= Date.now()) {
|
|
6165
|
+
throw new KSeFSessionExpiredError(
|
|
6166
|
+
`Cannot resume session: expired at ${state.validUntil}`
|
|
6167
|
+
);
|
|
6168
|
+
}
|
|
6169
|
+
const scopedAuth = new DefaultAuthManager(() => Promise.resolve(null), state.accessToken);
|
|
6170
|
+
const scopedRestClient = client.createScopedRestClient(scopedAuth);
|
|
6171
|
+
return buildSessionHandle({
|
|
6172
|
+
deps: {
|
|
6173
|
+
crypto: client.crypto,
|
|
6174
|
+
onlineSession: new OnlineSessionService(scopedRestClient),
|
|
6175
|
+
sessionStatus: new SessionStatusService(scopedRestClient),
|
|
6176
|
+
getAccessToken: () => scopedAuth.getAccessToken()
|
|
6177
|
+
},
|
|
6178
|
+
sessionRef: state.referenceNumber,
|
|
6179
|
+
validUntil: state.validUntil,
|
|
6180
|
+
cipherKey: new Uint8Array(Buffer.from(state.aesKey, "base64")),
|
|
6181
|
+
cipherIv: new Uint8Array(Buffer.from(state.iv, "base64")),
|
|
6182
|
+
formCode: state.formCode,
|
|
6183
|
+
validate: options?.validate ?? state.validate
|
|
6184
|
+
});
|
|
6185
|
+
}
|
|
5986
6186
|
async function openSendAndClose(client, invoices, options) {
|
|
5987
6187
|
const handle = await openOnlineSession(client, options);
|
|
5988
6188
|
for (const inv of invoices) {
|
|
@@ -5995,6 +6195,9 @@ async function openSendAndClose(client, invoices, options) {
|
|
|
5995
6195
|
// src/workflows/batch-session-workflow.ts
|
|
5996
6196
|
init_document_structures();
|
|
5997
6197
|
async function uploadBatch(client, zipData, options) {
|
|
6198
|
+
if (options?.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
|
6199
|
+
throw new Error("parallelism must be a positive integer");
|
|
6200
|
+
}
|
|
5998
6201
|
await client.crypto.init();
|
|
5999
6202
|
if (options?.validate) {
|
|
6000
6203
|
const { unzip: unzip2 } = await Promise.resolve().then(() => (init_zip(), zip_exports));
|
|
@@ -6037,7 +6240,7 @@ async function uploadBatch(client, zipData, options) {
|
|
|
6037
6240
|
},
|
|
6038
6241
|
ordinalNumber: i + 1
|
|
6039
6242
|
}));
|
|
6040
|
-
await client.batchSession.sendParts(openResp, sendingParts);
|
|
6243
|
+
await client.batchSession.sendParts(openResp, sendingParts, options?.parallelism);
|
|
6041
6244
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
6042
6245
|
const result = await pollUntil(
|
|
6043
6246
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
@@ -6058,6 +6261,9 @@ async function uploadBatch(client, zipData, options) {
|
|
|
6058
6261
|
};
|
|
6059
6262
|
}
|
|
6060
6263
|
async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
|
|
6264
|
+
if (options?.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
|
6265
|
+
throw new Error("parallelism must be a positive integer");
|
|
6266
|
+
}
|
|
6061
6267
|
await client.crypto.init();
|
|
6062
6268
|
const encData = client.crypto.getEncryptionData();
|
|
6063
6269
|
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
@@ -6079,7 +6285,7 @@ async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
|
|
|
6079
6285
|
},
|
|
6080
6286
|
options?.upoVersion
|
|
6081
6287
|
);
|
|
6082
|
-
await client.batchSession.sendPartsWithStream(openResp, streamParts);
|
|
6288
|
+
await client.batchSession.sendPartsWithStream(openResp, streamParts, options?.parallelism);
|
|
6083
6289
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
6084
6290
|
const result = await pollUntil(
|
|
6085
6291
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
@@ -6154,6 +6360,7 @@ async function doExport(client, filters, options) {
|
|
|
6154
6360
|
url: p.url,
|
|
6155
6361
|
method: p.method,
|
|
6156
6362
|
partSize: p.partSize,
|
|
6363
|
+
partHash: p.partHash,
|
|
6157
6364
|
encryptedPartSize: p.encryptedPartSize,
|
|
6158
6365
|
encryptedPartHash: p.encryptedPartHash,
|
|
6159
6366
|
expirationDate: p.expirationDate
|
|
@@ -6179,6 +6386,9 @@ async function exportAndDownload(client, filters, options) {
|
|
|
6179
6386
|
throw new Error(`Download failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
|
|
6180
6387
|
}
|
|
6181
6388
|
const encryptedData = new Uint8Array(await resp.arrayBuffer());
|
|
6389
|
+
if (options?.verifyHash !== false && !verifyHash(encryptedData, part.encryptedPartHash)) {
|
|
6390
|
+
throw new Error(`Hash mismatch for export part ${part.ordinalNumber}`);
|
|
6391
|
+
}
|
|
6182
6392
|
const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
|
|
6183
6393
|
decryptedParts.push(decrypted);
|
|
6184
6394
|
}
|
|
@@ -6251,6 +6461,9 @@ async function incrementalExportAndDownload(client, options) {
|
|
|
6251
6461
|
throw new Error(`Download failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
|
|
6252
6462
|
}
|
|
6253
6463
|
const encryptedData = new Uint8Array(await resp.arrayBuffer());
|
|
6464
|
+
if (options.verifyHash !== false && !verifyHash(encryptedData, part.encryptedPartHash)) {
|
|
6465
|
+
throw new Error(`Hash mismatch for export part ${part.ordinalNumber}`);
|
|
6466
|
+
}
|
|
6254
6467
|
const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
|
|
6255
6468
|
decryptedParts.push(decrypted);
|
|
6256
6469
|
}
|
|
@@ -6416,6 +6629,7 @@ async function authenticateWithPkcs12(client, options) {
|
|
|
6416
6629
|
|
|
6417
6630
|
// src/offline/index.ts
|
|
6418
6631
|
init_deadline();
|
|
6632
|
+
init_holidays();
|
|
6419
6633
|
|
|
6420
6634
|
// src/offline/storage.ts
|
|
6421
6635
|
function matchesFilter(invoice, filter) {
|
|
@@ -6657,9 +6871,11 @@ export {
|
|
|
6657
6871
|
getDefaultReason,
|
|
6658
6872
|
getEffectiveStartDate,
|
|
6659
6873
|
getFormCode,
|
|
6874
|
+
getPolishHolidays,
|
|
6660
6875
|
getTimeUntilDeadline,
|
|
6661
6876
|
incrementalExportAndDownload,
|
|
6662
6877
|
isExpired,
|
|
6878
|
+
isPolishHoliday,
|
|
6663
6879
|
isRetryableError,
|
|
6664
6880
|
isRetryableStatus,
|
|
6665
6881
|
isValidBase64,
|
|
@@ -6686,6 +6902,9 @@ export {
|
|
|
6686
6902
|
parseUpoXml,
|
|
6687
6903
|
pollUntil,
|
|
6688
6904
|
resolveOptions,
|
|
6905
|
+
resumeOnlineSession,
|
|
6906
|
+
runWithConcurrency,
|
|
6907
|
+
sha256Base642 as sha256Base64,
|
|
6689
6908
|
sleep,
|
|
6690
6909
|
unzip,
|
|
6691
6910
|
updateContinuationPoint,
|
|
@@ -6700,6 +6919,7 @@ export {
|
|
|
6700
6919
|
validatePresignedUrl,
|
|
6701
6920
|
validateSchema,
|
|
6702
6921
|
validateWellFormedness,
|
|
6922
|
+
verifyHash,
|
|
6703
6923
|
xmlToObject
|
|
6704
6924
|
};
|
|
6705
6925
|
//# sourceMappingURL=index.js.map
|