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/cli.js
CHANGED
|
@@ -988,6 +988,32 @@ var init_online_session = __esm({
|
|
|
988
988
|
}
|
|
989
989
|
});
|
|
990
990
|
|
|
991
|
+
// src/utils/concurrency.ts
|
|
992
|
+
async function runWithConcurrency(tasks, parallelism) {
|
|
993
|
+
if (tasks.length === 0) return;
|
|
994
|
+
const limit = Math.max(1, Math.min(parallelism, tasks.length));
|
|
995
|
+
const controller = new AbortController();
|
|
996
|
+
let index = 0;
|
|
997
|
+
const workers = Array.from({ length: limit }, async () => {
|
|
998
|
+
while (index < tasks.length && !controller.signal.aborted) {
|
|
999
|
+
const current = index;
|
|
1000
|
+
index += 1;
|
|
1001
|
+
try {
|
|
1002
|
+
await tasks[current](controller.signal);
|
|
1003
|
+
} catch (err) {
|
|
1004
|
+
controller.abort();
|
|
1005
|
+
throw err;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
await Promise.all(workers);
|
|
1010
|
+
}
|
|
1011
|
+
var init_concurrency = __esm({
|
|
1012
|
+
"src/utils/concurrency.ts"() {
|
|
1013
|
+
"use strict";
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
|
|
991
1017
|
// src/services/batch-session.ts
|
|
992
1018
|
var BatchSessionService;
|
|
993
1019
|
var init_batch_session = __esm({
|
|
@@ -996,6 +1022,7 @@ var init_batch_session = __esm({
|
|
|
996
1022
|
init_ksef_feature();
|
|
997
1023
|
init_rest_request();
|
|
998
1024
|
init_routes();
|
|
1025
|
+
init_concurrency();
|
|
999
1026
|
BatchSessionService = class {
|
|
1000
1027
|
restClient;
|
|
1001
1028
|
constructor(restClient) {
|
|
@@ -1009,12 +1036,10 @@ var init_batch_session = __esm({
|
|
|
1009
1036
|
const response = await this.restClient.execute(req);
|
|
1010
1037
|
return response.body;
|
|
1011
1038
|
}
|
|
1012
|
-
async sendParts(openResponse, parts) {
|
|
1013
|
-
const
|
|
1014
|
-
const tasks = parts.map(async (
|
|
1015
|
-
const uploadReq =
|
|
1016
|
-
(r) => r.ordinalNumber === part.ordinalNumber
|
|
1017
|
-
);
|
|
1039
|
+
async sendParts(openResponse, parts, parallelism) {
|
|
1040
|
+
const uploadMap = new Map(openResponse.partUploadRequests.map((r) => [r.ordinalNumber, r]));
|
|
1041
|
+
const tasks = parts.map((part) => async (signal) => {
|
|
1042
|
+
const uploadReq = uploadMap.get(part.ordinalNumber);
|
|
1018
1043
|
if (!uploadReq) {
|
|
1019
1044
|
throw new Error(`No upload request found for part ${part.ordinalNumber}`);
|
|
1020
1045
|
}
|
|
@@ -1022,25 +1047,38 @@ var init_batch_session = __esm({
|
|
|
1022
1047
|
for (const [k, v] of Object.entries(uploadReq.headers)) {
|
|
1023
1048
|
if (v != null) headers[k] = v;
|
|
1024
1049
|
}
|
|
1025
|
-
await fetch(uploadReq.url, {
|
|
1050
|
+
const resp = await fetch(uploadReq.url, {
|
|
1026
1051
|
method: uploadReq.method,
|
|
1027
1052
|
headers,
|
|
1028
|
-
body: part.data
|
|
1053
|
+
body: part.data,
|
|
1054
|
+
signal
|
|
1029
1055
|
});
|
|
1056
|
+
if (!resp.ok) {
|
|
1057
|
+
const body = await resp.text().catch(() => "");
|
|
1058
|
+
throw new Error(
|
|
1059
|
+
`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}${body ? ` \u2014 ${body}` : ""}`
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1030
1062
|
});
|
|
1031
|
-
|
|
1063
|
+
if (parallelism !== void 0) {
|
|
1064
|
+
await runWithConcurrency(tasks, parallelism);
|
|
1065
|
+
} else {
|
|
1066
|
+
const ac = new AbortController();
|
|
1067
|
+
await Promise.all(tasks.map((t) => t(ac.signal).catch((err) => {
|
|
1068
|
+
ac.abort();
|
|
1069
|
+
throw err;
|
|
1070
|
+
})));
|
|
1071
|
+
}
|
|
1032
1072
|
}
|
|
1033
1073
|
/**
|
|
1034
|
-
* Upload parts
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1074
|
+
* Upload parts using streaming bodies (`duplex: 'half'`).
|
|
1075
|
+
* By default uploads sequentially to avoid backpressure issues.
|
|
1076
|
+
* Pass `parallelism` to enable bounded concurrent uploads.
|
|
1037
1077
|
*/
|
|
1038
|
-
async sendPartsWithStream(openResponse, parts) {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
const uploadReq =
|
|
1042
|
-
(r) => r.ordinalNumber === part.ordinalNumber
|
|
1043
|
-
);
|
|
1078
|
+
async sendPartsWithStream(openResponse, parts, parallelism) {
|
|
1079
|
+
const uploadMap = new Map(openResponse.partUploadRequests.map((r) => [r.ordinalNumber, r]));
|
|
1080
|
+
const uploadPart = async (part, signal) => {
|
|
1081
|
+
const uploadReq = uploadMap.get(part.ordinalNumber);
|
|
1044
1082
|
if (!uploadReq) {
|
|
1045
1083
|
throw new Error(`No upload request found for part ${part.ordinalNumber}`);
|
|
1046
1084
|
}
|
|
@@ -1052,11 +1090,23 @@ var init_batch_session = __esm({
|
|
|
1052
1090
|
method: uploadReq.method,
|
|
1053
1091
|
headers,
|
|
1054
1092
|
body: part.dataStream,
|
|
1093
|
+
signal,
|
|
1055
1094
|
// @ts-expect-error -- Node 18+ undici supports duplex for streaming body
|
|
1056
1095
|
duplex: "half"
|
|
1057
1096
|
});
|
|
1058
1097
|
if (!resp.ok) {
|
|
1059
|
-
|
|
1098
|
+
const body = await resp.text().catch(() => "");
|
|
1099
|
+
throw new Error(
|
|
1100
|
+
`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}${body ? ` \u2014 ${body}` : ""}`
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
if (parallelism !== void 0) {
|
|
1105
|
+
await runWithConcurrency(parts.map((p) => (signal) => uploadPart(p, signal)), parallelism);
|
|
1106
|
+
} else {
|
|
1107
|
+
const { signal } = new AbortController();
|
|
1108
|
+
for (const part of parts) {
|
|
1109
|
+
await uploadPart(part, signal);
|
|
1060
1110
|
}
|
|
1061
1111
|
}
|
|
1062
1112
|
}
|
|
@@ -1169,7 +1219,10 @@ var init_invoice_download = __esm({
|
|
|
1169
1219
|
async getInvoice(ksefNumber) {
|
|
1170
1220
|
const req = RestRequest.get(Routes.Invoices.byKsefNumber(ksefNumber));
|
|
1171
1221
|
const response = await this.restClient.executeRaw(req);
|
|
1172
|
-
return
|
|
1222
|
+
return {
|
|
1223
|
+
xml: new TextDecoder().decode(response.body),
|
|
1224
|
+
hash: response.headers.get("x-ms-meta-hash") ?? void 0
|
|
1225
|
+
};
|
|
1173
1226
|
}
|
|
1174
1227
|
async queryInvoiceMetadata(filters, pageOffset, pageSize, sortOrder) {
|
|
1175
1228
|
const req = RestRequest.post(Routes.Invoices.queryMetadata).body(filters);
|
|
@@ -2087,6 +2140,72 @@ var init_auth_xml_builder = __esm({
|
|
|
2087
2140
|
}
|
|
2088
2141
|
});
|
|
2089
2142
|
|
|
2143
|
+
// src/offline/holidays.ts
|
|
2144
|
+
function toDateKey(d) {
|
|
2145
|
+
return d.toISOString().slice(0, 10);
|
|
2146
|
+
}
|
|
2147
|
+
function dateKey(year, month, day) {
|
|
2148
|
+
return toDateKey(new Date(Date.UTC(year, month - 1, day)));
|
|
2149
|
+
}
|
|
2150
|
+
function addDays(d, n) {
|
|
2151
|
+
const result = new Date(d);
|
|
2152
|
+
result.setUTCDate(result.getUTCDate() + n);
|
|
2153
|
+
return result;
|
|
2154
|
+
}
|
|
2155
|
+
function computeEasterSunday(year) {
|
|
2156
|
+
const a = year % 19;
|
|
2157
|
+
const b = Math.floor(year / 100);
|
|
2158
|
+
const c = year % 100;
|
|
2159
|
+
const d = Math.floor(b / 4);
|
|
2160
|
+
const e = b % 4;
|
|
2161
|
+
const f = Math.floor((b + 8) / 25);
|
|
2162
|
+
const g = Math.floor((b - f + 1) / 3);
|
|
2163
|
+
const h = (19 * a + b - d - g + 15) % 30;
|
|
2164
|
+
const i = Math.floor(c / 4);
|
|
2165
|
+
const k = c % 4;
|
|
2166
|
+
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
|
2167
|
+
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
|
2168
|
+
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
|
2169
|
+
const day = (h + l - 7 * m + 114) % 31 + 1;
|
|
2170
|
+
return new Date(Date.UTC(year, month - 1, day));
|
|
2171
|
+
}
|
|
2172
|
+
function getPolishHolidays(year) {
|
|
2173
|
+
const cached = holidayCache.get(year);
|
|
2174
|
+
if (cached) return cached;
|
|
2175
|
+
const easter = computeEasterSunday(year);
|
|
2176
|
+
const holidays = /* @__PURE__ */ new Set([
|
|
2177
|
+
// Fixed
|
|
2178
|
+
dateKey(year, 1, 1),
|
|
2179
|
+
dateKey(year, 1, 6),
|
|
2180
|
+
dateKey(year, 5, 1),
|
|
2181
|
+
dateKey(year, 5, 3),
|
|
2182
|
+
dateKey(year, 8, 15),
|
|
2183
|
+
dateKey(year, 11, 1),
|
|
2184
|
+
dateKey(year, 11, 11),
|
|
2185
|
+
dateKey(year, 12, 25),
|
|
2186
|
+
dateKey(year, 12, 26),
|
|
2187
|
+
// Wigilia — added by Dz.U. 2024 poz. 1965, effective from 2025
|
|
2188
|
+
...year >= 2025 ? [dateKey(year, 12, 24)] : [],
|
|
2189
|
+
// Moveable
|
|
2190
|
+
toDateKey(easter),
|
|
2191
|
+
toDateKey(addDays(easter, 1)),
|
|
2192
|
+
toDateKey(addDays(easter, 49)),
|
|
2193
|
+
toDateKey(addDays(easter, 60))
|
|
2194
|
+
]);
|
|
2195
|
+
holidayCache.set(year, holidays);
|
|
2196
|
+
return holidays;
|
|
2197
|
+
}
|
|
2198
|
+
function isPolishHoliday(date) {
|
|
2199
|
+
return getPolishHolidays(date.getUTCFullYear()).has(toDateKey(date));
|
|
2200
|
+
}
|
|
2201
|
+
var holidayCache;
|
|
2202
|
+
var init_holidays = __esm({
|
|
2203
|
+
"src/offline/holidays.ts"() {
|
|
2204
|
+
"use strict";
|
|
2205
|
+
holidayCache = /* @__PURE__ */ new Map();
|
|
2206
|
+
}
|
|
2207
|
+
});
|
|
2208
|
+
|
|
2090
2209
|
// src/offline/deadline.ts
|
|
2091
2210
|
function getDefaultReason(mode) {
|
|
2092
2211
|
switch (mode) {
|
|
@@ -2103,7 +2222,7 @@ function getDefaultReason(mode) {
|
|
|
2103
2222
|
function nextBusinessDay(from) {
|
|
2104
2223
|
const d = new Date(from);
|
|
2105
2224
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
2106
|
-
while (d.getUTCDay() === 0 || d.getUTCDay() === 6) {
|
|
2225
|
+
while (d.getUTCDay() === 0 || d.getUTCDay() === 6 || isPolishHoliday(d)) {
|
|
2107
2226
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
2108
2227
|
}
|
|
2109
2228
|
return d;
|
|
@@ -2116,7 +2235,7 @@ function addBusinessDays(from, days) {
|
|
|
2116
2235
|
let remaining = days;
|
|
2117
2236
|
while (remaining > 0) {
|
|
2118
2237
|
d.setUTCDate(d.getUTCDate() + 1);
|
|
2119
|
-
if (d.getUTCDay() !== 0 && d.getUTCDay() !== 6) {
|
|
2238
|
+
if (d.getUTCDay() !== 0 && d.getUTCDay() !== 6 && !isPolishHoliday(d)) {
|
|
2120
2239
|
remaining--;
|
|
2121
2240
|
}
|
|
2122
2241
|
}
|
|
@@ -2162,6 +2281,7 @@ var FAR_FUTURE;
|
|
|
2162
2281
|
var init_deadline = __esm({
|
|
2163
2282
|
"src/offline/deadline.ts"() {
|
|
2164
2283
|
"use strict";
|
|
2284
|
+
init_holidays();
|
|
2165
2285
|
FAR_FUTURE = /* @__PURE__ */ new Date("9999-12-31T23:59:59Z");
|
|
2166
2286
|
}
|
|
2167
2287
|
});
|
|
@@ -2884,6 +3004,7 @@ var init_client = __esm({
|
|
|
2884
3004
|
qr;
|
|
2885
3005
|
options;
|
|
2886
3006
|
authManager;
|
|
3007
|
+
_baseRestClientConfig;
|
|
2887
3008
|
_offline;
|
|
2888
3009
|
constructor(options) {
|
|
2889
3010
|
this.options = resolveOptions(options);
|
|
@@ -2895,6 +3016,8 @@ var init_client = __esm({
|
|
|
2895
3016
|
});
|
|
2896
3017
|
this.authManager = authManager;
|
|
2897
3018
|
const restClientConfig = buildRestClientConfig(options, authManager);
|
|
3019
|
+
const { authManager: _am, ...baseConfig } = restClientConfig;
|
|
3020
|
+
this._baseRestClientConfig = baseConfig;
|
|
2898
3021
|
const restClient = new RestClient(this.options, restClientConfig);
|
|
2899
3022
|
const fetcher = new CertificateFetcher(restClient);
|
|
2900
3023
|
this.crypto = new CryptographyService(fetcher);
|
|
@@ -2919,6 +3042,10 @@ var init_client = __esm({
|
|
|
2919
3042
|
}
|
|
2920
3043
|
return this._offline;
|
|
2921
3044
|
}
|
|
3045
|
+
/** @internal Create a RestClient with a different AuthManager, preserving transport/retry/rateLimit config. */
|
|
3046
|
+
createScopedRestClient(authManager) {
|
|
3047
|
+
return new RestClient(this.options, { ...this._baseRestClientConfig, authManager });
|
|
3048
|
+
}
|
|
2922
3049
|
async loginWithToken(token, nip) {
|
|
2923
3050
|
const challenge2 = await this.auth.getChallenge();
|
|
2924
3051
|
await this.crypto.init();
|
|
@@ -5034,7 +5161,7 @@ var init_invoice_validator = __esm({
|
|
|
5034
5161
|
});
|
|
5035
5162
|
|
|
5036
5163
|
// src/builders/batch-file.ts
|
|
5037
|
-
import * as
|
|
5164
|
+
import * as crypto6 from "crypto";
|
|
5038
5165
|
function splitBuffer(data, maxPartSize) {
|
|
5039
5166
|
if (data.length <= maxPartSize) {
|
|
5040
5167
|
return [data];
|
|
@@ -5045,8 +5172,8 @@ function splitBuffer(data, maxPartSize) {
|
|
|
5045
5172
|
}
|
|
5046
5173
|
return parts;
|
|
5047
5174
|
}
|
|
5048
|
-
function
|
|
5049
|
-
return
|
|
5175
|
+
function sha256Base642(data) {
|
|
5176
|
+
return crypto6.createHash("sha256").update(data).digest("base64");
|
|
5050
5177
|
}
|
|
5051
5178
|
var BATCH_MAX_PART_SIZE, BATCH_MAX_TOTAL_SIZE, BATCH_MAX_PARTS, BatchFileBuilder;
|
|
5052
5179
|
var init_batch_file = __esm({
|
|
@@ -5083,7 +5210,7 @@ var init_batch_file = __esm({
|
|
|
5083
5210
|
`Data requires ${rawParts.length} parts, exceeding maximum of ${BATCH_MAX_PARTS}`
|
|
5084
5211
|
);
|
|
5085
5212
|
}
|
|
5086
|
-
const zipHash =
|
|
5213
|
+
const zipHash = sha256Base642(zipBytes);
|
|
5087
5214
|
const encryptedParts = [];
|
|
5088
5215
|
const fileParts = rawParts.map((raw, i) => {
|
|
5089
5216
|
const encrypted = encryptFn(raw);
|
|
@@ -5091,7 +5218,7 @@ var init_batch_file = __esm({
|
|
|
5091
5218
|
return {
|
|
5092
5219
|
ordinalNumber: i + 1,
|
|
5093
5220
|
fileSize: encrypted.length,
|
|
5094
|
-
fileHash:
|
|
5221
|
+
fileHash: sha256Base642(encrypted)
|
|
5095
5222
|
};
|
|
5096
5223
|
});
|
|
5097
5224
|
return {
|
|
@@ -5174,7 +5301,7 @@ var init_batch_file = __esm({
|
|
|
5174
5301
|
encryptedChunks.push(value);
|
|
5175
5302
|
}
|
|
5176
5303
|
const encryptedData = new Uint8Array(Buffer.concat(encryptedChunks));
|
|
5177
|
-
const encryptedMeta =
|
|
5304
|
+
const encryptedMeta = sha256Base642(encryptedData);
|
|
5178
5305
|
fileParts.push({
|
|
5179
5306
|
ordinalNumber: partIndex + 1,
|
|
5180
5307
|
fileSize: encryptedData.byteLength,
|
|
@@ -5218,6 +5345,9 @@ __export(batch_session_workflow_exports, {
|
|
|
5218
5345
|
uploadBatchStreamParsed: () => uploadBatchStreamParsed
|
|
5219
5346
|
});
|
|
5220
5347
|
async function uploadBatch(client, zipData, options) {
|
|
5348
|
+
if (options?.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
|
5349
|
+
throw new Error("parallelism must be a positive integer");
|
|
5350
|
+
}
|
|
5221
5351
|
await client.crypto.init();
|
|
5222
5352
|
if (options?.validate) {
|
|
5223
5353
|
const { unzip: unzip2 } = await Promise.resolve().then(() => (init_zip(), zip_exports));
|
|
@@ -5260,7 +5390,7 @@ async function uploadBatch(client, zipData, options) {
|
|
|
5260
5390
|
},
|
|
5261
5391
|
ordinalNumber: i + 1
|
|
5262
5392
|
}));
|
|
5263
|
-
await client.batchSession.sendParts(openResp, sendingParts);
|
|
5393
|
+
await client.batchSession.sendParts(openResp, sendingParts, options?.parallelism);
|
|
5264
5394
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
5265
5395
|
const result = await pollUntil(
|
|
5266
5396
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
@@ -5281,6 +5411,9 @@ async function uploadBatch(client, zipData, options) {
|
|
|
5281
5411
|
};
|
|
5282
5412
|
}
|
|
5283
5413
|
async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
|
|
5414
|
+
if (options?.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) {
|
|
5415
|
+
throw new Error("parallelism must be a positive integer");
|
|
5416
|
+
}
|
|
5284
5417
|
await client.crypto.init();
|
|
5285
5418
|
const encData = client.crypto.getEncryptionData();
|
|
5286
5419
|
const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
|
|
@@ -5302,7 +5435,7 @@ async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
|
|
|
5302
5435
|
},
|
|
5303
5436
|
options?.upoVersion
|
|
5304
5437
|
);
|
|
5305
|
-
await client.batchSession.sendPartsWithStream(openResp, streamParts);
|
|
5438
|
+
await client.batchSession.sendPartsWithStream(openResp, streamParts, options?.parallelism);
|
|
5306
5439
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
5307
5440
|
const result = await pollUntil(
|
|
5308
5441
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
@@ -6646,6 +6779,17 @@ var FileHwmStore = class {
|
|
|
6646
6779
|
// src/workflows/invoice-export-workflow.ts
|
|
6647
6780
|
init_zip();
|
|
6648
6781
|
init_polling();
|
|
6782
|
+
|
|
6783
|
+
// src/utils/hash.ts
|
|
6784
|
+
import crypto5 from "crypto";
|
|
6785
|
+
function sha256Base64(data) {
|
|
6786
|
+
return crypto5.createHash("sha256").update(data).digest("base64");
|
|
6787
|
+
}
|
|
6788
|
+
function verifyHash(data, expectedHash) {
|
|
6789
|
+
return sha256Base64(data) === expectedHash;
|
|
6790
|
+
}
|
|
6791
|
+
|
|
6792
|
+
// src/workflows/invoice-export-workflow.ts
|
|
6649
6793
|
async function doExport(client, filters, options) {
|
|
6650
6794
|
await client.crypto.init();
|
|
6651
6795
|
const encData = client.crypto.getEncryptionData();
|
|
@@ -6674,6 +6818,7 @@ async function doExport(client, filters, options) {
|
|
|
6674
6818
|
url: p.url,
|
|
6675
6819
|
method: p.method,
|
|
6676
6820
|
partSize: p.partSize,
|
|
6821
|
+
partHash: p.partHash,
|
|
6677
6822
|
encryptedPartSize: p.encryptedPartSize,
|
|
6678
6823
|
encryptedPartHash: p.encryptedPartHash,
|
|
6679
6824
|
expirationDate: p.expirationDate
|
|
@@ -6735,6 +6880,9 @@ async function incrementalExportAndDownload(client, options) {
|
|
|
6735
6880
|
throw new Error(`Download failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
|
|
6736
6881
|
}
|
|
6737
6882
|
const encryptedData = new Uint8Array(await resp.arrayBuffer());
|
|
6883
|
+
if (options.verifyHash !== false && !verifyHash(encryptedData, part.encryptedPartHash)) {
|
|
6884
|
+
throw new Error(`Hash mismatch for export part ${part.ordinalNumber}`);
|
|
6885
|
+
}
|
|
6738
6886
|
const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
|
|
6739
6887
|
decryptedParts.push(decrypted);
|
|
6740
6888
|
}
|
|
@@ -6943,6 +7091,7 @@ var send = defineCommand5({
|
|
|
6943
7091
|
stream: { type: "boolean", description: "Use stream-based batch upload (for ZIP files, reduces memory usage)" },
|
|
6944
7092
|
formCode: { type: "string", description: "Document type: FA2, FA3, PEF3, PEFKOR3, FARR1 (default: FA3)" },
|
|
6945
7093
|
validate: { type: "boolean", description: "Validate XML before sending" },
|
|
7094
|
+
parallelism: { type: "string", description: "Number of concurrent part uploads (batch mode)" },
|
|
6946
7095
|
env: { type: "string", description: "Environment (test/demo/prod)" },
|
|
6947
7096
|
json: { type: "boolean", description: "Output as JSON" },
|
|
6948
7097
|
verbose: { type: "boolean", description: "Show HTTP request/response details" },
|
|
@@ -6956,6 +7105,10 @@ var send = defineCommand5({
|
|
|
6956
7105
|
const config = loadConfig();
|
|
6957
7106
|
const nip = args.nip ?? config.nip;
|
|
6958
7107
|
const filePath = args.path;
|
|
7108
|
+
const parallelism = args.parallelism ? Number(args.parallelism) : void 0;
|
|
7109
|
+
if (parallelism !== void 0 && (!Number.isInteger(parallelism) || parallelism < 1)) {
|
|
7110
|
+
throw new Error("--parallelism must be a positive integer");
|
|
7111
|
+
}
|
|
6959
7112
|
const formCodeKey = args.formCode;
|
|
6960
7113
|
let formCode = DEFAULT_FORM_CODE;
|
|
6961
7114
|
if (formCodeKey) {
|
|
@@ -6988,7 +7141,8 @@ var send = defineCommand5({
|
|
|
6988
7141
|
if (!args.json) consola9.start(`Sending batch via stream (${(zipSize / 1e6).toFixed(1)} MB)...`);
|
|
6989
7142
|
const result = await uploadBatchStream2(client, zipStreamFactory, zipSize, {
|
|
6990
7143
|
formCode,
|
|
6991
|
-
pollOptions: { intervalMs: 3e3 }
|
|
7144
|
+
pollOptions: { intervalMs: 3e3 },
|
|
7145
|
+
parallelism
|
|
6992
7146
|
});
|
|
6993
7147
|
if (args.json) {
|
|
6994
7148
|
outputResult(result, { json: true });
|
|
@@ -7052,7 +7206,7 @@ var send = defineCommand5({
|
|
|
7052
7206
|
{ formCode, batchFile: batchFileInfo, encryption: encryptionData.encryptionInfo }
|
|
7053
7207
|
);
|
|
7054
7208
|
saveOnlineSessionRef(openResult.referenceNumber);
|
|
7055
|
-
await client.batchSession.sendParts(openResult, parts);
|
|
7209
|
+
await client.batchSession.sendParts(openResult, parts, parallelism);
|
|
7056
7210
|
await client.batchSession.closeSession(openResult.referenceNumber);
|
|
7057
7211
|
clearOnlineSessionRef();
|
|
7058
7212
|
if (args.json) {
|
|
@@ -7117,9 +7271,9 @@ var get = defineCommand5({
|
|
|
7117
7271
|
return withErrorHandler(async () => {
|
|
7118
7272
|
const globalOpts = getGlobalOpts4(args);
|
|
7119
7273
|
const { client } = await requireSession(globalOpts);
|
|
7120
|
-
const xml = await client.invoices.getInvoice(args.ksefNumber);
|
|
7274
|
+
const { xml, hash } = await client.invoices.getInvoice(args.ksefNumber);
|
|
7121
7275
|
if (args.json) {
|
|
7122
|
-
outputResult({ ksefNumber: args.ksefNumber, xml }, { json: true });
|
|
7276
|
+
outputResult({ ksefNumber: args.ksefNumber, xml, hash }, { json: true });
|
|
7123
7277
|
return;
|
|
7124
7278
|
}
|
|
7125
7279
|
if (args.o) {
|
|
@@ -8036,12 +8190,12 @@ import fs10 from "fs";
|
|
|
8036
8190
|
import path7 from "path";
|
|
8037
8191
|
|
|
8038
8192
|
// src/crypto/certificate-service.ts
|
|
8039
|
-
import * as
|
|
8193
|
+
import * as crypto7 from "crypto";
|
|
8040
8194
|
import * as x5092 from "@peculiar/x509";
|
|
8041
8195
|
var CertificateService = class {
|
|
8042
8196
|
static getSha256Fingerprint(certPem) {
|
|
8043
8197
|
const der = extractDerFromPem2(certPem);
|
|
8044
|
-
return
|
|
8198
|
+
return crypto7.createHash("sha256").update(der).digest("hex").toUpperCase();
|
|
8045
8199
|
}
|
|
8046
8200
|
static async generatePersonalCertificate(givenName, surname, serialNumber, commonName, method = "RSA") {
|
|
8047
8201
|
const nameParts = [];
|
|
@@ -8064,7 +8218,7 @@ var CertificateService = class {
|
|
|
8064
8218
|
}
|
|
8065
8219
|
};
|
|
8066
8220
|
async function generateSelfSigned(subject2, method) {
|
|
8067
|
-
x5092.cryptoProvider.set(
|
|
8221
|
+
x5092.cryptoProvider.set(crypto7.webcrypto);
|
|
8068
8222
|
let algorithm;
|
|
8069
8223
|
let signingAlgorithm;
|
|
8070
8224
|
if (method === "ECDSA") {
|
|
@@ -8079,7 +8233,7 @@ async function generateSelfSigned(subject2, method) {
|
|
|
8079
8233
|
};
|
|
8080
8234
|
signingAlgorithm = algorithm;
|
|
8081
8235
|
}
|
|
8082
|
-
const keys = await
|
|
8236
|
+
const keys = await crypto7.webcrypto.subtle.generateKey(
|
|
8083
8237
|
algorithm,
|
|
8084
8238
|
true,
|
|
8085
8239
|
["sign", "verify"]
|
|
@@ -8096,9 +8250,9 @@ async function generateSelfSigned(subject2, method) {
|
|
|
8096
8250
|
serialNumber: Date.now().toString(16)
|
|
8097
8251
|
});
|
|
8098
8252
|
const certPem = cert.toString("pem");
|
|
8099
|
-
const pkcs8 = await
|
|
8253
|
+
const pkcs8 = await crypto7.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
8100
8254
|
const privateKeyPem = pemEncode2(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
8101
|
-
const fingerprint =
|
|
8255
|
+
const fingerprint = crypto7.createHash("sha256").update(Buffer.from(cert.rawData)).digest("hex").toUpperCase();
|
|
8102
8256
|
return { certificatePem: certPem, privateKeyPem, fingerprint };
|
|
8103
8257
|
}
|
|
8104
8258
|
function extractDerFromPem2(pem) {
|