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.cjs
CHANGED
|
@@ -977,7 +977,9 @@ function isValidVatUe(value) {
|
|
|
977
977
|
return VatUe.test(value);
|
|
978
978
|
}
|
|
979
979
|
function isValidNipVatUe(value) {
|
|
980
|
-
|
|
980
|
+
if (!NipVatUe.test(value)) return false;
|
|
981
|
+
const nip = value.split("-")[0];
|
|
982
|
+
return isValidNip(nip);
|
|
981
983
|
}
|
|
982
984
|
function isValidInternalId(value) {
|
|
983
985
|
return InternalId.test(value);
|
|
@@ -2990,6 +2992,32 @@ var init_online_session = __esm({
|
|
|
2990
2992
|
}
|
|
2991
2993
|
});
|
|
2992
2994
|
|
|
2995
|
+
// src/utils/concurrency.ts
|
|
2996
|
+
async function runWithConcurrency(tasks, parallelism) {
|
|
2997
|
+
if (tasks.length === 0) return;
|
|
2998
|
+
const limit = Math.max(1, Math.min(parallelism, tasks.length));
|
|
2999
|
+
const controller = new AbortController();
|
|
3000
|
+
let index = 0;
|
|
3001
|
+
const workers = Array.from({ length: limit }, async () => {
|
|
3002
|
+
while (index < tasks.length && !controller.signal.aborted) {
|
|
3003
|
+
const current = index;
|
|
3004
|
+
index += 1;
|
|
3005
|
+
try {
|
|
3006
|
+
await tasks[current](controller.signal);
|
|
3007
|
+
} catch (err) {
|
|
3008
|
+
controller.abort();
|
|
3009
|
+
throw err;
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
});
|
|
3013
|
+
await Promise.all(workers);
|
|
3014
|
+
}
|
|
3015
|
+
var init_concurrency = __esm({
|
|
3016
|
+
"src/utils/concurrency.ts"() {
|
|
3017
|
+
"use strict";
|
|
3018
|
+
}
|
|
3019
|
+
});
|
|
3020
|
+
|
|
2993
3021
|
// src/services/batch-session.ts
|
|
2994
3022
|
var BatchSessionService;
|
|
2995
3023
|
var init_batch_session = __esm({
|
|
@@ -2998,6 +3026,7 @@ var init_batch_session = __esm({
|
|
|
2998
3026
|
init_ksef_feature();
|
|
2999
3027
|
init_rest_request();
|
|
3000
3028
|
init_routes();
|
|
3029
|
+
init_concurrency();
|
|
3001
3030
|
BatchSessionService = class {
|
|
3002
3031
|
restClient;
|
|
3003
3032
|
constructor(restClient) {
|
|
@@ -3011,12 +3040,10 @@ var init_batch_session = __esm({
|
|
|
3011
3040
|
const response = await this.restClient.execute(req);
|
|
3012
3041
|
return response.body;
|
|
3013
3042
|
}
|
|
3014
|
-
async sendParts(openResponse, parts) {
|
|
3015
|
-
const
|
|
3016
|
-
const tasks = parts.map(async (
|
|
3017
|
-
const uploadReq =
|
|
3018
|
-
(r) => r.ordinalNumber === part.ordinalNumber
|
|
3019
|
-
);
|
|
3043
|
+
async sendParts(openResponse, parts, parallelism) {
|
|
3044
|
+
const uploadMap = new Map(openResponse.partUploadRequests.map((r) => [r.ordinalNumber, r]));
|
|
3045
|
+
const tasks = parts.map((part) => async (signal) => {
|
|
3046
|
+
const uploadReq = uploadMap.get(part.ordinalNumber);
|
|
3020
3047
|
if (!uploadReq) {
|
|
3021
3048
|
throw new Error(`No upload request found for part ${part.ordinalNumber}`);
|
|
3022
3049
|
}
|
|
@@ -3024,25 +3051,38 @@ var init_batch_session = __esm({
|
|
|
3024
3051
|
for (const [k, v] of Object.entries(uploadReq.headers)) {
|
|
3025
3052
|
if (v != null) headers[k] = v;
|
|
3026
3053
|
}
|
|
3027
|
-
await fetch(uploadReq.url, {
|
|
3054
|
+
const resp = await fetch(uploadReq.url, {
|
|
3028
3055
|
method: uploadReq.method,
|
|
3029
3056
|
headers,
|
|
3030
|
-
body: part.data
|
|
3057
|
+
body: part.data,
|
|
3058
|
+
signal
|
|
3031
3059
|
});
|
|
3060
|
+
if (!resp.ok) {
|
|
3061
|
+
const body = await resp.text().catch(() => "");
|
|
3062
|
+
throw new Error(
|
|
3063
|
+
`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}${body ? ` \u2014 ${body}` : ""}`
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3032
3066
|
});
|
|
3033
|
-
|
|
3067
|
+
if (parallelism !== void 0) {
|
|
3068
|
+
await runWithConcurrency(tasks, parallelism);
|
|
3069
|
+
} else {
|
|
3070
|
+
const ac = new AbortController();
|
|
3071
|
+
await Promise.all(tasks.map((t) => t(ac.signal).catch((err) => {
|
|
3072
|
+
ac.abort();
|
|
3073
|
+
throw err;
|
|
3074
|
+
})));
|
|
3075
|
+
}
|
|
3034
3076
|
}
|
|
3035
3077
|
/**
|
|
3036
|
-
* Upload parts
|
|
3037
|
-
*
|
|
3038
|
-
*
|
|
3078
|
+
* Upload parts using streaming bodies (`duplex: 'half'`).
|
|
3079
|
+
* By default uploads sequentially to avoid backpressure issues.
|
|
3080
|
+
* Pass `parallelism` to enable bounded concurrent uploads.
|
|
3039
3081
|
*/
|
|
3040
|
-
async sendPartsWithStream(openResponse, parts) {
|
|
3041
|
-
const
|
|
3042
|
-
|
|
3043
|
-
const uploadReq =
|
|
3044
|
-
(r) => r.ordinalNumber === part.ordinalNumber
|
|
3045
|
-
);
|
|
3082
|
+
async sendPartsWithStream(openResponse, parts, parallelism) {
|
|
3083
|
+
const uploadMap = new Map(openResponse.partUploadRequests.map((r) => [r.ordinalNumber, r]));
|
|
3084
|
+
const uploadPart = async (part, signal) => {
|
|
3085
|
+
const uploadReq = uploadMap.get(part.ordinalNumber);
|
|
3046
3086
|
if (!uploadReq) {
|
|
3047
3087
|
throw new Error(`No upload request found for part ${part.ordinalNumber}`);
|
|
3048
3088
|
}
|
|
@@ -3054,11 +3094,23 @@ var init_batch_session = __esm({
|
|
|
3054
3094
|
method: uploadReq.method,
|
|
3055
3095
|
headers,
|
|
3056
3096
|
body: part.dataStream,
|
|
3097
|
+
signal,
|
|
3057
3098
|
// @ts-expect-error -- Node 18+ undici supports duplex for streaming body
|
|
3058
3099
|
duplex: "half"
|
|
3059
3100
|
});
|
|
3060
3101
|
if (!resp.ok) {
|
|
3061
|
-
|
|
3102
|
+
const body = await resp.text().catch(() => "");
|
|
3103
|
+
throw new Error(
|
|
3104
|
+
`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}${body ? ` \u2014 ${body}` : ""}`
|
|
3105
|
+
);
|
|
3106
|
+
}
|
|
3107
|
+
};
|
|
3108
|
+
if (parallelism !== void 0) {
|
|
3109
|
+
await runWithConcurrency(parts.map((p) => (signal) => uploadPart(p, signal)), parallelism);
|
|
3110
|
+
} else {
|
|
3111
|
+
const { signal } = new AbortController();
|
|
3112
|
+
for (const part of parts) {
|
|
3113
|
+
await uploadPart(part, signal);
|
|
3062
3114
|
}
|
|
3063
3115
|
}
|
|
3064
3116
|
}
|
|
@@ -3171,7 +3223,10 @@ var init_invoice_download = __esm({
|
|
|
3171
3223
|
async getInvoice(ksefNumber) {
|
|
3172
3224
|
const req = RestRequest.get(Routes.Invoices.byKsefNumber(ksefNumber));
|
|
3173
3225
|
const response = await this.restClient.executeRaw(req);
|
|
3174
|
-
return
|
|
3226
|
+
return {
|
|
3227
|
+
xml: new TextDecoder().decode(response.body),
|
|
3228
|
+
hash: response.headers.get("x-ms-meta-hash") ?? void 0
|
|
3229
|
+
};
|
|
3175
3230
|
}
|
|
3176
3231
|
async queryInvoiceMetadata(filters, pageOffset, pageSize, sortOrder) {
|
|
3177
3232
|
const req = RestRequest.post(Routes.Invoices.queryMetadata).body(filters);
|
|
@@ -4433,6 +4488,72 @@ var init_zip = __esm({
|
|
|
4433
4488
|
}
|
|
4434
4489
|
});
|
|
4435
4490
|
|
|
4491
|
+
// src/offline/holidays.ts
|
|
4492
|
+
function toDateKey(d) {
|
|
4493
|
+
return d.toISOString().slice(0, 10);
|
|
4494
|
+
}
|
|
4495
|
+
function dateKey(year, month, day) {
|
|
4496
|
+
return toDateKey(new Date(Date.UTC(year, month - 1, day)));
|
|
4497
|
+
}
|
|
4498
|
+
function addDays(d, n) {
|
|
4499
|
+
const result = new Date(d);
|
|
4500
|
+
result.setUTCDate(result.getUTCDate() + n);
|
|
4501
|
+
return result;
|
|
4502
|
+
}
|
|
4503
|
+
function computeEasterSunday(year) {
|
|
4504
|
+
const a = year % 19;
|
|
4505
|
+
const b = Math.floor(year / 100);
|
|
4506
|
+
const c = year % 100;
|
|
4507
|
+
const d = Math.floor(b / 4);
|
|
4508
|
+
const e = b % 4;
|
|
4509
|
+
const f = Math.floor((b + 8) / 25);
|
|
4510
|
+
const g = Math.floor((b - f + 1) / 3);
|
|
4511
|
+
const h = (19 * a + b - d - g + 15) % 30;
|
|
4512
|
+
const i = Math.floor(c / 4);
|
|
4513
|
+
const k = c % 4;
|
|
4514
|
+
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
|
4515
|
+
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
|
4516
|
+
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
|
4517
|
+
const day = (h + l - 7 * m + 114) % 31 + 1;
|
|
4518
|
+
return new Date(Date.UTC(year, month - 1, day));
|
|
4519
|
+
}
|
|
4520
|
+
function getPolishHolidays(year) {
|
|
4521
|
+
const cached = holidayCache.get(year);
|
|
4522
|
+
if (cached) return cached;
|
|
4523
|
+
const easter = computeEasterSunday(year);
|
|
4524
|
+
const holidays = /* @__PURE__ */ new Set([
|
|
4525
|
+
// Fixed
|
|
4526
|
+
dateKey(year, 1, 1),
|
|
4527
|
+
dateKey(year, 1, 6),
|
|
4528
|
+
dateKey(year, 5, 1),
|
|
4529
|
+
dateKey(year, 5, 3),
|
|
4530
|
+
dateKey(year, 8, 15),
|
|
4531
|
+
dateKey(year, 11, 1),
|
|
4532
|
+
dateKey(year, 11, 11),
|
|
4533
|
+
dateKey(year, 12, 25),
|
|
4534
|
+
dateKey(year, 12, 26),
|
|
4535
|
+
// Wigilia — added by Dz.U. 2024 poz. 1965, effective from 2025
|
|
4536
|
+
...year >= 2025 ? [dateKey(year, 12, 24)] : [],
|
|
4537
|
+
// Moveable
|
|
4538
|
+
toDateKey(easter),
|
|
4539
|
+
toDateKey(addDays(easter, 1)),
|
|
4540
|
+
toDateKey(addDays(easter, 49)),
|
|
4541
|
+
toDateKey(addDays(easter, 60))
|
|
4542
|
+
]);
|
|
4543
|
+
holidayCache.set(year, holidays);
|
|
4544
|
+
return holidays;
|
|
4545
|
+
}
|
|
4546
|
+
function isPolishHoliday(date) {
|
|
4547
|
+
return getPolishHolidays(date.getUTCFullYear()).has(toDateKey(date));
|
|
4548
|
+
}
|
|
4549
|
+
var holidayCache;
|
|
4550
|
+
var init_holidays = __esm({
|
|
4551
|
+
"src/offline/holidays.ts"() {
|
|
4552
|
+
"use strict";
|
|
4553
|
+
holidayCache = /* @__PURE__ */ new Map();
|
|
4554
|
+
}
|
|
4555
|
+
});
|
|
4556
|
+
|
|
4436
4557
|
// src/offline/deadline.ts
|
|
4437
4558
|
function getDefaultReason(mode) {
|
|
4438
4559
|
switch (mode) {
|
|
@@ -4449,7 +4570,7 @@ function getDefaultReason(mode) {
|
|
|
4449
4570
|
function nextBusinessDay(from) {
|
|
4450
4571
|
const d = new Date(from);
|
|
4451
4572
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
4452
|
-
while (d.getUTCDay() === 0 || d.getUTCDay() === 6) {
|
|
4573
|
+
while (d.getUTCDay() === 0 || d.getUTCDay() === 6 || isPolishHoliday(d)) {
|
|
4453
4574
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
4454
4575
|
}
|
|
4455
4576
|
return d;
|
|
@@ -4462,7 +4583,7 @@ function addBusinessDays(from, days) {
|
|
|
4462
4583
|
let remaining = days;
|
|
4463
4584
|
while (remaining > 0) {
|
|
4464
4585
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
4465
|
-
if (d.getUTCDay() !== 0 && d.getUTCDay() !== 6) {
|
|
4586
|
+
if (d.getUTCDay() !== 0 && d.getUTCDay() !== 6 && !isPolishHoliday(d)) {
|
|
4466
4587
|
remaining--;
|
|
4467
4588
|
}
|
|
4468
4589
|
}
|
|
@@ -4528,16 +4649,17 @@ var FAR_FUTURE;
|
|
|
4528
4649
|
var init_deadline = __esm({
|
|
4529
4650
|
"src/offline/deadline.ts"() {
|
|
4530
4651
|
"use strict";
|
|
4652
|
+
init_holidays();
|
|
4531
4653
|
FAR_FUTURE = /* @__PURE__ */ new Date("9999-12-31T23:59:59Z");
|
|
4532
4654
|
}
|
|
4533
4655
|
});
|
|
4534
4656
|
|
|
4535
4657
|
// src/workflows/offline-invoice-workflow.ts
|
|
4536
|
-
var
|
|
4658
|
+
var import_node_crypto3, OfflineInvoiceWorkflow;
|
|
4537
4659
|
var init_offline_invoice_workflow = __esm({
|
|
4538
4660
|
"src/workflows/offline-invoice-workflow.ts"() {
|
|
4539
4661
|
"use strict";
|
|
4540
|
-
|
|
4662
|
+
import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
4541
4663
|
init_ksef_api_error();
|
|
4542
4664
|
init_deadline();
|
|
4543
4665
|
init_document_structures();
|
|
@@ -4557,7 +4679,7 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4557
4679
|
}
|
|
4558
4680
|
const mode = options?.mode ?? "offline24";
|
|
4559
4681
|
const reason = getDefaultReason(mode);
|
|
4560
|
-
const invoiceHashBase64 =
|
|
4682
|
+
const invoiceHashBase64 = import_node_crypto3.default.createHash("sha256").update(input.invoiceXml).digest("base64");
|
|
4561
4683
|
const kod1Url = this.qrService.buildInvoiceVerificationUrl(
|
|
4562
4684
|
input.sellerNip,
|
|
4563
4685
|
input.invoiceDate,
|
|
@@ -4576,7 +4698,7 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4576
4698
|
}
|
|
4577
4699
|
const submitBy = options?.customDeadline ? typeof options.customDeadline === "string" ? options.customDeadline : options.customDeadline.toISOString() : calculateOfflineDeadline(mode, input.invoiceDate, options?.maintenanceWindow).toISOString();
|
|
4578
4700
|
const metadata = {
|
|
4579
|
-
id:
|
|
4701
|
+
id: import_node_crypto3.default.randomUUID(),
|
|
4580
4702
|
mode,
|
|
4581
4703
|
reason,
|
|
4582
4704
|
status: "GENERATED",
|
|
@@ -4732,7 +4854,7 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4732
4854
|
original.status === "CORRECTED" ? `Invoice ${rejectedInvoiceId} has already been corrected (by ${original.correctedBy})` : `Only rejected invoices can be corrected (current status: ${original.status})`
|
|
4733
4855
|
);
|
|
4734
4856
|
}
|
|
4735
|
-
const originalHash =
|
|
4857
|
+
const originalHash = import_node_crypto3.default.createHash("sha256").update(original.invoiceXml).digest("base64");
|
|
4736
4858
|
await client.crypto.init();
|
|
4737
4859
|
const encData = client.crypto.getEncryptionData();
|
|
4738
4860
|
const formCode = options.formCode ?? DEFAULT_FORM_CODE;
|
|
@@ -4745,9 +4867,9 @@ var init_offline_invoice_workflow = __esm({
|
|
|
4745
4867
|
const plainMeta = client.crypto.getFileMetadata(data);
|
|
4746
4868
|
const encrypted = client.crypto.encryptAES256(data, encData.cipherKey, encData.cipherIv);
|
|
4747
4869
|
const encMeta = client.crypto.getFileMetadata(encrypted);
|
|
4748
|
-
const correctionId =
|
|
4870
|
+
const correctionId = import_node_crypto3.default.randomUUID();
|
|
4749
4871
|
const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4750
|
-
const correctedHashBase64 =
|
|
4872
|
+
const correctedHashBase64 = import_node_crypto3.default.createHash("sha256").update(correctedInvoiceXml).digest("base64");
|
|
4751
4873
|
const kod1Url = this.qrService.buildInvoiceVerificationUrl(
|
|
4752
4874
|
original.sellerNip,
|
|
4753
4875
|
original.invoiceDate,
|
|
@@ -4902,6 +5024,7 @@ var init_client = __esm({
|
|
|
4902
5024
|
qr;
|
|
4903
5025
|
options;
|
|
4904
5026
|
authManager;
|
|
5027
|
+
_baseRestClientConfig;
|
|
4905
5028
|
_offline;
|
|
4906
5029
|
constructor(options) {
|
|
4907
5030
|
this.options = resolveOptions(options);
|
|
@@ -4913,6 +5036,8 @@ var init_client = __esm({
|
|
|
4913
5036
|
});
|
|
4914
5037
|
this.authManager = authManager;
|
|
4915
5038
|
const restClientConfig = buildRestClientConfig(options, authManager);
|
|
5039
|
+
const { authManager: _am, ...baseConfig } = restClientConfig;
|
|
5040
|
+
this._baseRestClientConfig = baseConfig;
|
|
4916
5041
|
const restClient = new RestClient(this.options, restClientConfig);
|
|
4917
5042
|
const fetcher = new CertificateFetcher(restClient);
|
|
4918
5043
|
this.crypto = new CryptographyService(fetcher);
|
|
@@ -4937,6 +5062,10 @@ var init_client = __esm({
|
|
|
4937
5062
|
}
|
|
4938
5063
|
return this._offline;
|
|
4939
5064
|
}
|
|
5065
|
+
/** @internal Create a RestClient with a different AuthManager, preserving transport/retry/rateLimit config. */
|
|
5066
|
+
createScopedRestClient(authManager) {
|
|
5067
|
+
return new RestClient(this.options, { ...this._baseRestClientConfig, authManager });
|
|
5068
|
+
}
|
|
4940
5069
|
async loginWithToken(token, nip) {
|
|
4941
5070
|
const challenge = await this.auth.getChallenge();
|
|
4942
5071
|
await this.crypto.init();
|
|
@@ -5097,9 +5226,11 @@ __export(index_exports, {
|
|
|
5097
5226
|
getDefaultReason: () => getDefaultReason,
|
|
5098
5227
|
getEffectiveStartDate: () => getEffectiveStartDate,
|
|
5099
5228
|
getFormCode: () => getFormCode,
|
|
5229
|
+
getPolishHolidays: () => getPolishHolidays,
|
|
5100
5230
|
getTimeUntilDeadline: () => getTimeUntilDeadline,
|
|
5101
5231
|
incrementalExportAndDownload: () => incrementalExportAndDownload,
|
|
5102
5232
|
isExpired: () => isExpired,
|
|
5233
|
+
isPolishHoliday: () => isPolishHoliday,
|
|
5103
5234
|
isRetryableError: () => isRetryableError,
|
|
5104
5235
|
isRetryableStatus: () => isRetryableStatus,
|
|
5105
5236
|
isValidBase64: () => isValidBase64,
|
|
@@ -5126,6 +5257,9 @@ __export(index_exports, {
|
|
|
5126
5257
|
parseUpoXml: () => parseUpoXml,
|
|
5127
5258
|
pollUntil: () => pollUntil,
|
|
5128
5259
|
resolveOptions: () => resolveOptions,
|
|
5260
|
+
resumeOnlineSession: () => resumeOnlineSession,
|
|
5261
|
+
runWithConcurrency: () => runWithConcurrency,
|
|
5262
|
+
sha256Base64: () => sha256Base642,
|
|
5129
5263
|
sleep: () => sleep,
|
|
5130
5264
|
unzip: () => unzip,
|
|
5131
5265
|
updateContinuationPoint: () => updateContinuationPoint,
|
|
@@ -5140,6 +5274,7 @@ __export(index_exports, {
|
|
|
5140
5274
|
validatePresignedUrl: () => validatePresignedUrl,
|
|
5141
5275
|
validateSchema: () => validateSchema,
|
|
5142
5276
|
validateWellFormedness: () => validateWellFormedness,
|
|
5277
|
+
verifyHash: () => verifyHash,
|
|
5143
5278
|
xmlToObject: () => xmlToObject
|
|
5144
5279
|
});
|
|
5145
5280
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -5911,6 +6046,18 @@ function parseKSeFTokenContext(token) {
|
|
|
5911
6046
|
};
|
|
5912
6047
|
}
|
|
5913
6048
|
|
|
6049
|
+
// src/utils/hash.ts
|
|
6050
|
+
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
6051
|
+
function sha256Base642(data) {
|
|
6052
|
+
return import_node_crypto2.default.createHash("sha256").update(data).digest("base64");
|
|
6053
|
+
}
|
|
6054
|
+
function verifyHash(data, expectedHash) {
|
|
6055
|
+
return sha256Base642(data) === expectedHash;
|
|
6056
|
+
}
|
|
6057
|
+
|
|
6058
|
+
// src/utils/index.ts
|
|
6059
|
+
init_concurrency();
|
|
6060
|
+
|
|
5914
6061
|
// src/workflows/polling.ts
|
|
5915
6062
|
async function pollUntil(action, condition, options) {
|
|
5916
6063
|
const intervalMs = options?.intervalMs ?? 2e3;
|
|
@@ -5929,6 +6076,10 @@ async function pollUntil(action, condition, options) {
|
|
|
5929
6076
|
}
|
|
5930
6077
|
|
|
5931
6078
|
// src/workflows/online-session-workflow.ts
|
|
6079
|
+
init_ksef_session_expired_error();
|
|
6080
|
+
init_auth_manager();
|
|
6081
|
+
init_online_session();
|
|
6082
|
+
init_session_status();
|
|
5932
6083
|
init_document_structures();
|
|
5933
6084
|
|
|
5934
6085
|
// src/xml/upo-parser.ts
|
|
@@ -6092,18 +6243,11 @@ function nonEmptyString(value) {
|
|
|
6092
6243
|
// src/workflows/online-session-workflow.ts
|
|
6093
6244
|
init_invoice_validator();
|
|
6094
6245
|
init_ksef_validation_error();
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
const encData = client.crypto.getEncryptionData();
|
|
6098
|
-
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
6099
|
-
const openResp = await client.onlineSession.openSession(
|
|
6100
|
-
{ formCode, encryption: encData.encryptionInfo },
|
|
6101
|
-
options?.upoVersion
|
|
6102
|
-
);
|
|
6103
|
-
const sessionRef = openResp.referenceNumber;
|
|
6246
|
+
function buildSessionHandle(params) {
|
|
6247
|
+
const { deps, sessionRef, validUntil, cipherKey, cipherIv, formCode, validate: validate2 } = params;
|
|
6104
6248
|
async function fetchUpo(pollOpts) {
|
|
6105
6249
|
const result = await pollUntil(
|
|
6106
|
-
() =>
|
|
6250
|
+
() => deps.sessionStatus.getSessionStatus(sessionRef),
|
|
6107
6251
|
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
6108
6252
|
{ ...pollOpts, description: `UPO for session ${sessionRef}` }
|
|
6109
6253
|
);
|
|
@@ -6119,9 +6263,9 @@ async function openOnlineSession(client, options) {
|
|
|
6119
6263
|
}
|
|
6120
6264
|
return {
|
|
6121
6265
|
sessionRef,
|
|
6122
|
-
validUntil
|
|
6266
|
+
validUntil,
|
|
6123
6267
|
async sendInvoice(invoiceXml) {
|
|
6124
|
-
if (
|
|
6268
|
+
if (validate2) {
|
|
6125
6269
|
const xmlStr = typeof invoiceXml === "string" ? invoiceXml : new TextDecoder().decode(invoiceXml);
|
|
6126
6270
|
const vResult = await validate(xmlStr);
|
|
6127
6271
|
if (!vResult.valid) {
|
|
@@ -6132,10 +6276,10 @@ async function openOnlineSession(client, options) {
|
|
|
6132
6276
|
}
|
|
6133
6277
|
}
|
|
6134
6278
|
const data = typeof invoiceXml === "string" ? new TextEncoder().encode(invoiceXml) : invoiceXml;
|
|
6135
|
-
const plainMeta =
|
|
6136
|
-
const encrypted =
|
|
6137
|
-
const encMeta =
|
|
6138
|
-
const resp = await
|
|
6279
|
+
const plainMeta = deps.crypto.getFileMetadata(data);
|
|
6280
|
+
const encrypted = deps.crypto.encryptAES256(data, cipherKey, cipherIv);
|
|
6281
|
+
const encMeta = deps.crypto.getFileMetadata(encrypted);
|
|
6282
|
+
const resp = await deps.onlineSession.sendInvoice(sessionRef, {
|
|
6139
6283
|
invoiceHash: plainMeta.hashSHA,
|
|
6140
6284
|
invoiceSize: plainMeta.fileSize,
|
|
6141
6285
|
encryptedInvoiceHash: encMeta.hashSHA,
|
|
@@ -6145,7 +6289,7 @@ async function openOnlineSession(client, options) {
|
|
|
6145
6289
|
return resp.referenceNumber;
|
|
6146
6290
|
},
|
|
6147
6291
|
async close() {
|
|
6148
|
-
await
|
|
6292
|
+
await deps.onlineSession.closeSession(sessionRef);
|
|
6149
6293
|
},
|
|
6150
6294
|
async waitForUpo(pollOpts) {
|
|
6151
6295
|
return fetchUpo(pollOpts);
|
|
@@ -6154,13 +6298,75 @@ async function openOnlineSession(client, options) {
|
|
|
6154
6298
|
const upoInfo = await fetchUpo(pollOpts);
|
|
6155
6299
|
const parsed = [];
|
|
6156
6300
|
for (const page of upoInfo.pages) {
|
|
6157
|
-
const result = await
|
|
6301
|
+
const result = await deps.sessionStatus.getSessionUpo(sessionRef, page.referenceNumber);
|
|
6158
6302
|
parsed.push(parseUpoXml(result.upo));
|
|
6159
6303
|
}
|
|
6160
6304
|
return { ...upoInfo, parsed };
|
|
6305
|
+
},
|
|
6306
|
+
getState() {
|
|
6307
|
+
const token = deps.getAccessToken();
|
|
6308
|
+
if (!token) {
|
|
6309
|
+
throw new Error("Cannot serialize session state: no access token available");
|
|
6310
|
+
}
|
|
6311
|
+
return {
|
|
6312
|
+
referenceNumber: sessionRef,
|
|
6313
|
+
aesKey: Buffer.from(cipherKey).toString("base64"),
|
|
6314
|
+
iv: Buffer.from(cipherIv).toString("base64"),
|
|
6315
|
+
accessToken: token,
|
|
6316
|
+
formCode,
|
|
6317
|
+
validUntil,
|
|
6318
|
+
...validate2 ? { validate: validate2 } : {}
|
|
6319
|
+
};
|
|
6161
6320
|
}
|
|
6162
6321
|
};
|
|
6163
6322
|
}
|
|
6323
|
+
async function openOnlineSession(client, options) {
|
|
6324
|
+
await client.crypto.init();
|
|
6325
|
+
const encData = client.crypto.getEncryptionData();
|
|
6326
|
+
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
6327
|
+
const openResp = await client.onlineSession.openSession(
|
|
6328
|
+
{ formCode, encryption: encData.encryptionInfo },
|
|
6329
|
+
options?.upoVersion
|
|
6330
|
+
);
|
|
6331
|
+
return buildSessionHandle({
|
|
6332
|
+
deps: {
|
|
6333
|
+
crypto: client.crypto,
|
|
6334
|
+
onlineSession: client.onlineSession,
|
|
6335
|
+
sessionStatus: client.sessionStatus,
|
|
6336
|
+
getAccessToken: () => client.authManager.getAccessToken()
|
|
6337
|
+
},
|
|
6338
|
+
sessionRef: openResp.referenceNumber,
|
|
6339
|
+
validUntil: openResp.validUntil,
|
|
6340
|
+
cipherKey: encData.cipherKey,
|
|
6341
|
+
cipherIv: encData.cipherIv,
|
|
6342
|
+
formCode,
|
|
6343
|
+
validate: options?.validate
|
|
6344
|
+
});
|
|
6345
|
+
}
|
|
6346
|
+
function resumeOnlineSession(client, state, options) {
|
|
6347
|
+
const expiry = new Date(state.validUntil);
|
|
6348
|
+
if (expiry.getTime() <= Date.now()) {
|
|
6349
|
+
throw new KSeFSessionExpiredError(
|
|
6350
|
+
`Cannot resume session: expired at ${state.validUntil}`
|
|
6351
|
+
);
|
|
6352
|
+
}
|
|
6353
|
+
const scopedAuth = new DefaultAuthManager(() => Promise.resolve(null), state.accessToken);
|
|
6354
|
+
const scopedRestClient = client.createScopedRestClient(scopedAuth);
|
|
6355
|
+
return buildSessionHandle({
|
|
6356
|
+
deps: {
|
|
6357
|
+
crypto: client.crypto,
|
|
6358
|
+
onlineSession: new OnlineSessionService(scopedRestClient),
|
|
6359
|
+
sessionStatus: new SessionStatusService(scopedRestClient),
|
|
6360
|
+
getAccessToken: () => scopedAuth.getAccessToken()
|
|
6361
|
+
},
|
|
6362
|
+
sessionRef: state.referenceNumber,
|
|
6363
|
+
validUntil: state.validUntil,
|
|
6364
|
+
cipherKey: new Uint8Array(Buffer.from(state.aesKey, "base64")),
|
|
6365
|
+
cipherIv: new Uint8Array(Buffer.from(state.iv, "base64")),
|
|
6366
|
+
formCode: state.formCode,
|
|
6367
|
+
validate: options?.validate ?? state.validate
|
|
6368
|
+
});
|
|
6369
|
+
}
|
|
6164
6370
|
async function openSendAndClose(client, invoices, options) {
|
|
6165
6371
|
const handle = await openOnlineSession(client, options);
|
|
6166
6372
|
for (const inv of invoices) {
|
|
@@ -6173,6 +6379,9 @@ async function openSendAndClose(client, invoices, options) {
|
|
|
6173
6379
|
// src/workflows/batch-session-workflow.ts
|
|
6174
6380
|
init_document_structures();
|
|
6175
6381
|
async function uploadBatch(client, zipData, options) {
|
|
6382
|
+
if (options?.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
|
6383
|
+
throw new Error("parallelism must be a positive integer");
|
|
6384
|
+
}
|
|
6176
6385
|
await client.crypto.init();
|
|
6177
6386
|
if (options?.validate) {
|
|
6178
6387
|
const { unzip: unzip2 } = await Promise.resolve().then(() => (init_zip(), zip_exports));
|
|
@@ -6215,7 +6424,7 @@ async function uploadBatch(client, zipData, options) {
|
|
|
6215
6424
|
},
|
|
6216
6425
|
ordinalNumber: i + 1
|
|
6217
6426
|
}));
|
|
6218
|
-
await client.batchSession.sendParts(openResp, sendingParts);
|
|
6427
|
+
await client.batchSession.sendParts(openResp, sendingParts, options?.parallelism);
|
|
6219
6428
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
6220
6429
|
const result = await pollUntil(
|
|
6221
6430
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
@@ -6236,6 +6445,9 @@ async function uploadBatch(client, zipData, options) {
|
|
|
6236
6445
|
};
|
|
6237
6446
|
}
|
|
6238
6447
|
async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
|
|
6448
|
+
if (options?.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
|
6449
|
+
throw new Error("parallelism must be a positive integer");
|
|
6450
|
+
}
|
|
6239
6451
|
await client.crypto.init();
|
|
6240
6452
|
const encData = client.crypto.getEncryptionData();
|
|
6241
6453
|
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
@@ -6257,7 +6469,7 @@ async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
|
|
|
6257
6469
|
},
|
|
6258
6470
|
options?.upoVersion
|
|
6259
6471
|
);
|
|
6260
|
-
await client.batchSession.sendPartsWithStream(openResp, streamParts);
|
|
6472
|
+
await client.batchSession.sendPartsWithStream(openResp, streamParts, options?.parallelism);
|
|
6261
6473
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
6262
6474
|
const result = await pollUntil(
|
|
6263
6475
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
@@ -6332,6 +6544,7 @@ async function doExport(client, filters, options) {
|
|
|
6332
6544
|
url: p.url,
|
|
6333
6545
|
method: p.method,
|
|
6334
6546
|
partSize: p.partSize,
|
|
6547
|
+
partHash: p.partHash,
|
|
6335
6548
|
encryptedPartSize: p.encryptedPartSize,
|
|
6336
6549
|
encryptedPartHash: p.encryptedPartHash,
|
|
6337
6550
|
expirationDate: p.expirationDate
|
|
@@ -6357,6 +6570,9 @@ async function exportAndDownload(client, filters, options) {
|
|
|
6357
6570
|
throw new Error(`Download failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
|
|
6358
6571
|
}
|
|
6359
6572
|
const encryptedData = new Uint8Array(await resp.arrayBuffer());
|
|
6573
|
+
if (options?.verifyHash !== false && !verifyHash(encryptedData, part.encryptedPartHash)) {
|
|
6574
|
+
throw new Error(`Hash mismatch for export part ${part.ordinalNumber}`);
|
|
6575
|
+
}
|
|
6360
6576
|
const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
|
|
6361
6577
|
decryptedParts.push(decrypted);
|
|
6362
6578
|
}
|
|
@@ -6429,6 +6645,9 @@ async function incrementalExportAndDownload(client, options) {
|
|
|
6429
6645
|
throw new Error(`Download failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
|
|
6430
6646
|
}
|
|
6431
6647
|
const encryptedData = new Uint8Array(await resp.arrayBuffer());
|
|
6648
|
+
if (options.verifyHash !== false && !verifyHash(encryptedData, part.encryptedPartHash)) {
|
|
6649
|
+
throw new Error(`Hash mismatch for export part ${part.ordinalNumber}`);
|
|
6650
|
+
}
|
|
6432
6651
|
const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
|
|
6433
6652
|
decryptedParts.push(decrypted);
|
|
6434
6653
|
}
|
|
@@ -6594,6 +6813,7 @@ async function authenticateWithPkcs12(client, options) {
|
|
|
6594
6813
|
|
|
6595
6814
|
// src/offline/index.ts
|
|
6596
6815
|
init_deadline();
|
|
6816
|
+
init_holidays();
|
|
6597
6817
|
|
|
6598
6818
|
// src/offline/storage.ts
|
|
6599
6819
|
function matchesFilter(invoice, filter) {
|
|
@@ -6836,9 +7056,11 @@ init_client();
|
|
|
6836
7056
|
getDefaultReason,
|
|
6837
7057
|
getEffectiveStartDate,
|
|
6838
7058
|
getFormCode,
|
|
7059
|
+
getPolishHolidays,
|
|
6839
7060
|
getTimeUntilDeadline,
|
|
6840
7061
|
incrementalExportAndDownload,
|
|
6841
7062
|
isExpired,
|
|
7063
|
+
isPolishHoliday,
|
|
6842
7064
|
isRetryableError,
|
|
6843
7065
|
isRetryableStatus,
|
|
6844
7066
|
isValidBase64,
|
|
@@ -6865,6 +7087,9 @@ init_client();
|
|
|
6865
7087
|
parseUpoXml,
|
|
6866
7088
|
pollUntil,
|
|
6867
7089
|
resolveOptions,
|
|
7090
|
+
resumeOnlineSession,
|
|
7091
|
+
runWithConcurrency,
|
|
7092
|
+
sha256Base64,
|
|
6868
7093
|
sleep,
|
|
6869
7094
|
unzip,
|
|
6870
7095
|
updateContinuationPoint,
|
|
@@ -6879,6 +7104,7 @@ init_client();
|
|
|
6879
7104
|
validatePresignedUrl,
|
|
6880
7105
|
validateSchema,
|
|
6881
7106
|
validateWellFormedness,
|
|
7107
|
+
verifyHash,
|
|
6882
7108
|
xmlToObject
|
|
6883
7109
|
});
|
|
6884
7110
|
//# sourceMappingURL=index.cjs.map
|