ksef-client-ts 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -67,7 +67,8 @@ function resolveOptions(options = {}) {
67
67
  lighthouseUrl: options.lighthouseUrl ?? env.lighthouseUrl,
68
68
  apiVersion: options.apiVersion ?? DEFAULT_API_VERSION,
69
69
  timeout: options.timeout ?? DEFAULT_TIMEOUT,
70
- customHeaders: options.customHeaders ?? {}
70
+ customHeaders: options.customHeaders ?? {},
71
+ environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST")
71
72
  };
72
73
  }
73
74
  var DEFAULT_API_VERSION, DEFAULT_TIMEOUT;
@@ -1107,6 +1108,36 @@ var init_batch_session = __esm({
1107
1108
  });
1108
1109
  await Promise.all(tasks);
1109
1110
  }
1111
+ /**
1112
+ * Upload parts sequentially (not in parallel) because each part uses a
1113
+ * streaming body (`duplex: 'half'`). Parallel streaming uploads can cause
1114
+ * backpressure issues and exceed memory limits for large payloads.
1115
+ */
1116
+ async sendPartsWithStream(openResponse, parts) {
1117
+ const uploadRequests = openResponse.partUploadRequests;
1118
+ for (const part of parts) {
1119
+ const uploadReq = uploadRequests.find(
1120
+ (r) => r.ordinalNumber === part.ordinalNumber
1121
+ );
1122
+ if (!uploadReq) {
1123
+ throw new Error(`No upload request found for part ${part.ordinalNumber}`);
1124
+ }
1125
+ const headers = {};
1126
+ for (const [k, v] of Object.entries(uploadReq.headers)) {
1127
+ if (v != null) headers[k] = v;
1128
+ }
1129
+ const resp = await fetch(uploadReq.url, {
1130
+ method: uploadReq.method,
1131
+ headers,
1132
+ body: part.dataStream,
1133
+ // @ts-expect-error -- Node 18+ undici supports duplex for streaming body
1134
+ duplex: "half"
1135
+ });
1136
+ if (!resp.ok) {
1137
+ throw new Error(`Upload failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
1138
+ }
1139
+ }
1140
+ }
1110
1141
  async closeSession(batchRef) {
1111
1142
  const req = RestRequest.post(Routes.Sessions.Batch.close(batchRef));
1112
1143
  await this.restClient.executeVoid(req);
@@ -1575,84 +1606,111 @@ var init_test_data = __esm({
1575
1606
  "use strict";
1576
1607
  init_rest_request();
1577
1608
  init_routes();
1609
+ init_ksef_error();
1578
1610
  TestDataService = class {
1579
1611
  restClient;
1580
- constructor(restClient) {
1612
+ environmentName;
1613
+ constructor(restClient, environmentName) {
1581
1614
  this.restClient = restClient;
1615
+ this.environmentName = environmentName;
1616
+ }
1617
+ ensureTestEnvironment() {
1618
+ if (this.environmentName && this.environmentName !== "TEST") {
1619
+ throw new KSeFError(
1620
+ `Test data APIs are only available on the TEST environment (current: ${this.environmentName})`
1621
+ );
1622
+ }
1582
1623
  }
1583
1624
  // Subject management
1584
1625
  async createSubject(request) {
1626
+ this.ensureTestEnvironment();
1585
1627
  const req = RestRequest.post(Routes.TestData.createSubject).body(request);
1586
1628
  await this.restClient.executeVoid(req);
1587
1629
  }
1588
1630
  async removeSubject(request) {
1631
+ this.ensureTestEnvironment();
1589
1632
  const req = RestRequest.post(Routes.TestData.removeSubject).body(request);
1590
1633
  await this.restClient.executeVoid(req);
1591
1634
  }
1592
1635
  // Person management
1593
1636
  async createPerson(request) {
1637
+ this.ensureTestEnvironment();
1594
1638
  const req = RestRequest.post(Routes.TestData.createPerson).body(request);
1595
1639
  await this.restClient.executeVoid(req);
1596
1640
  }
1597
1641
  async removePerson(request) {
1642
+ this.ensureTestEnvironment();
1598
1643
  const req = RestRequest.post(Routes.TestData.removePerson).body(request);
1599
1644
  await this.restClient.executeVoid(req);
1600
1645
  }
1601
1646
  // Permissions
1602
1647
  async grantPermissions(request) {
1648
+ this.ensureTestEnvironment();
1603
1649
  const req = RestRequest.post(Routes.TestData.grantPerms).body(request);
1604
1650
  await this.restClient.executeVoid(req);
1605
1651
  }
1606
1652
  async revokePermissions(request) {
1653
+ this.ensureTestEnvironment();
1607
1654
  const req = RestRequest.post(Routes.TestData.revokePerms).body(request);
1608
1655
  await this.restClient.executeVoid(req);
1609
1656
  }
1610
1657
  // Attachment permissions
1611
1658
  async enableAttachment(request) {
1659
+ this.ensureTestEnvironment();
1612
1660
  const req = RestRequest.post(Routes.TestData.enableAttach).body(request);
1613
1661
  await this.restClient.executeVoid(req);
1614
1662
  }
1615
1663
  async disableAttachment(request) {
1664
+ this.ensureTestEnvironment();
1616
1665
  const req = RestRequest.post(Routes.TestData.disableAttach).body(request);
1617
1666
  await this.restClient.executeVoid(req);
1618
1667
  }
1619
1668
  // Session limits
1620
1669
  async changeSessionLimits(request) {
1670
+ this.ensureTestEnvironment();
1621
1671
  const req = RestRequest.post(Routes.TestData.changeSessionLimitsInCurrentContext).body(request);
1622
1672
  await this.restClient.executeVoid(req);
1623
1673
  }
1624
1674
  async restoreDefaultSessionLimits() {
1675
+ this.ensureTestEnvironment();
1625
1676
  const req = RestRequest.delete(Routes.TestData.restoreDefaultSessionLimitsInCurrentContext);
1626
1677
  await this.restClient.executeVoid(req);
1627
1678
  }
1628
1679
  // Certificate limits
1629
1680
  async changeCertificatesLimit(request) {
1681
+ this.ensureTestEnvironment();
1630
1682
  const req = RestRequest.post(Routes.TestData.changeCertificatesLimitInCurrentSubject).body(request);
1631
1683
  await this.restClient.executeVoid(req);
1632
1684
  }
1633
1685
  async restoreDefaultCertificatesLimit() {
1686
+ this.ensureTestEnvironment();
1634
1687
  const req = RestRequest.delete(Routes.TestData.restoreDefaultCertificatesLimitInCurrentSubject);
1635
1688
  await this.restClient.executeVoid(req);
1636
1689
  }
1637
1690
  // Rate limits
1638
1691
  async setRateLimits(request) {
1692
+ this.ensureTestEnvironment();
1639
1693
  const req = RestRequest.post(Routes.TestData.rateLimits).body(request);
1640
1694
  await this.restClient.executeVoid(req);
1641
1695
  }
1642
1696
  async restoreDefaultRateLimits() {
1697
+ this.ensureTestEnvironment();
1643
1698
  const req = RestRequest.delete(Routes.TestData.rateLimits);
1644
1699
  await this.restClient.executeVoid(req);
1645
1700
  }
1646
1701
  async setProductionRateLimits() {
1702
+ this.ensureTestEnvironment();
1647
1703
  const req = RestRequest.post(Routes.TestData.productionRateLimits);
1648
1704
  await this.restClient.executeVoid(req);
1649
1705
  }
1650
1706
  // Context blocking
1651
1707
  async blockContext(request) {
1708
+ this.ensureTestEnvironment();
1652
1709
  const req = RestRequest.post(Routes.TestData.blockContext).body(request);
1653
1710
  await this.restClient.executeVoid(req);
1654
1711
  }
1655
1712
  async unblockContext(request) {
1713
+ this.ensureTestEnvironment();
1656
1714
  const req = RestRequest.post(Routes.TestData.unblockContext).body(request);
1657
1715
  await this.restClient.executeVoid(req);
1658
1716
  }
@@ -1730,7 +1788,7 @@ ${lines.join("\n")}
1730
1788
 
1731
1789
  // src/crypto/cryptography-service.ts
1732
1790
  function setCryptoProvider() {
1733
- x509.cryptoProvider.set(crypto.webcrypto);
1791
+ x509.cryptoProvider.set(crypto2.webcrypto);
1734
1792
  }
1735
1793
  function buildX500Name(fields) {
1736
1794
  const parts = [];
@@ -1754,11 +1812,11 @@ function pemEncode(der, label) {
1754
1812
  ${lines.join("\n")}
1755
1813
  -----END ${label}-----`;
1756
1814
  }
1757
- var crypto, x509, CryptographyService;
1815
+ var crypto2, x509, CryptographyService;
1758
1816
  var init_cryptography_service = __esm({
1759
1817
  "src/crypto/cryptography-service.ts"() {
1760
1818
  "use strict";
1761
- crypto = __toESM(require("crypto"), 1);
1819
+ crypto2 = __toESM(require("crypto"), 1);
1762
1820
  x509 = __toESM(require("@peculiar/x509"), 1);
1763
1821
  CryptographyService = class {
1764
1822
  fetcher;
@@ -1774,12 +1832,34 @@ var init_cryptography_service = __esm({
1774
1832
  // ---------------------------------------------------------------------------
1775
1833
  /** Encrypt with AES-256-CBC (PKCS7 padding is automatic in Node). */
1776
1834
  encryptAES256(content, key, iv) {
1777
- const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
1835
+ const cipher = crypto2.createCipheriv("aes-256-cbc", key, iv);
1778
1836
  return new Uint8Array(Buffer.concat([cipher.update(content), cipher.final()]));
1779
1837
  }
1838
+ /**
1839
+ * Encrypt with AES-256-CBC as a streaming transform.
1840
+ * Returns a ReadableStream that yields encrypted chunks as the input is read.
1841
+ */
1842
+ encryptAES256Stream(input, key, iv) {
1843
+ const cipher = crypto2.createCipheriv("aes-256-cbc", key, iv);
1844
+ const transform = new TransformStream({
1845
+ transform(chunk, controller) {
1846
+ const encrypted = cipher.update(chunk);
1847
+ if (encrypted.length > 0) {
1848
+ controller.enqueue(new Uint8Array(encrypted));
1849
+ }
1850
+ },
1851
+ flush(controller) {
1852
+ const final = cipher.final();
1853
+ if (final.length > 0) {
1854
+ controller.enqueue(new Uint8Array(final));
1855
+ }
1856
+ }
1857
+ });
1858
+ return input.pipeThrough(transform);
1859
+ }
1780
1860
  /** Decrypt with AES-256-CBC. */
1781
1861
  decryptAES256(content, key, iv) {
1782
- const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
1862
+ const decipher = crypto2.createDecipheriv("aes-256-cbc", key, iv);
1783
1863
  return new Uint8Array(Buffer.concat([decipher.update(content), decipher.final()]));
1784
1864
  }
1785
1865
  // ---------------------------------------------------------------------------
@@ -1790,14 +1870,14 @@ var init_cryptography_service = __esm({
1790
1870
  * SymmetricKeyEncryption certificate's RSA public key (RSA-OAEP SHA-256).
1791
1871
  */
1792
1872
  getEncryptionData() {
1793
- const key = crypto.randomBytes(32);
1794
- const iv = crypto.randomBytes(16);
1873
+ const key = crypto2.randomBytes(32);
1874
+ const iv = crypto2.randomBytes(16);
1795
1875
  const certPem = this.fetcher.getSymmetricKeyEncryptionPem();
1796
- const encryptedKey = crypto.publicEncrypt(
1876
+ const encryptedKey = crypto2.publicEncrypt(
1797
1877
  {
1798
1878
  key: certPem,
1799
1879
  oaepHash: "sha256",
1800
- padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
1880
+ padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING
1801
1881
  },
1802
1882
  key
1803
1883
  );
@@ -1831,7 +1911,7 @@ var init_cryptography_service = __esm({
1831
1911
  const timestampMs = new Date(challengeTimestamp).getTime();
1832
1912
  const plaintext = Buffer.from(`${token}|${timestampMs}`, "utf-8");
1833
1913
  const certPem = this.fetcher.getKsefTokenEncryptionPem();
1834
- const cert = new crypto.X509Certificate(certPem);
1914
+ const cert = new crypto2.X509Certificate(certPem);
1835
1915
  const publicKey = cert.publicKey;
1836
1916
  if (publicKey.asymmetricKeyType === "rsa") {
1837
1917
  return this.encryptRsaOaep(certPem, plaintext);
@@ -1846,9 +1926,26 @@ var init_cryptography_service = __esm({
1846
1926
  // ---------------------------------------------------------------------------
1847
1927
  /** Compute SHA-256 hash (base64) and byte length. */
1848
1928
  getFileMetadata(file) {
1849
- const hash = crypto.createHash("sha256").update(file).digest("base64");
1929
+ const hash = crypto2.createHash("sha256").update(file).digest("base64");
1850
1930
  return { hashSHA: hash, fileSize: file.length };
1851
1931
  }
1932
+ /** Compute SHA-256 hash (base64) and byte length from a ReadableStream. */
1933
+ async getFileMetadataFromStream(stream) {
1934
+ const hash = crypto2.createHash("sha256");
1935
+ let fileSize = 0;
1936
+ const reader = stream.getReader();
1937
+ try {
1938
+ for (; ; ) {
1939
+ const { done, value } = await reader.read();
1940
+ if (done) break;
1941
+ hash.update(value);
1942
+ fileSize += value.byteLength;
1943
+ }
1944
+ } finally {
1945
+ reader.releaseLock();
1946
+ }
1947
+ return { hashSHA: hash.digest("base64"), fileSize };
1948
+ }
1852
1949
  // ---------------------------------------------------------------------------
1853
1950
  // CSR generation
1854
1951
  // ---------------------------------------------------------------------------
@@ -1861,7 +1958,7 @@ var init_cryptography_service = __esm({
1861
1958
  publicExponent: new Uint8Array([1, 0, 1]),
1862
1959
  modulusLength: 2048
1863
1960
  };
1864
- const keys = await crypto.webcrypto.subtle.generateKey(
1961
+ const keys = await crypto2.webcrypto.subtle.generateKey(
1865
1962
  algorithm,
1866
1963
  true,
1867
1964
  ["sign", "verify"]
@@ -1872,7 +1969,7 @@ var init_cryptography_service = __esm({
1872
1969
  signingAlgorithm: algorithm
1873
1970
  });
1874
1971
  const csrDer = new Uint8Array(csr.rawData);
1875
- const pkcs8 = await crypto.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
1972
+ const pkcs8 = await crypto2.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
1876
1973
  const privateKeyPem = pemEncode(new Uint8Array(pkcs8), "PRIVATE KEY");
1877
1974
  return { csrDer, privateKeyPem };
1878
1975
  }
@@ -1883,7 +1980,7 @@ var init_cryptography_service = __esm({
1883
1980
  name: "ECDSA",
1884
1981
  namedCurve: "P-256"
1885
1982
  };
1886
- const keys = await crypto.webcrypto.subtle.generateKey(
1983
+ const keys = await crypto2.webcrypto.subtle.generateKey(
1887
1984
  algorithm,
1888
1985
  true,
1889
1986
  ["sign", "verify"]
@@ -1894,7 +1991,7 @@ var init_cryptography_service = __esm({
1894
1991
  signingAlgorithm: { name: "ECDSA", hash: "SHA-256" }
1895
1992
  });
1896
1993
  const csrDer = new Uint8Array(csr.rawData);
1897
- const pkcs8 = await crypto.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
1994
+ const pkcs8 = await crypto2.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
1898
1995
  const privateKeyPem = pemEncode(new Uint8Array(pkcs8), "PRIVATE KEY");
1899
1996
  return { csrDer, privateKeyPem };
1900
1997
  }
@@ -1903,7 +2000,7 @@ var init_cryptography_service = __esm({
1903
2000
  // ---------------------------------------------------------------------------
1904
2001
  /** Parse a PEM-encoded private key into a Node.js KeyObject. */
1905
2002
  parsePrivateKey(pem) {
1906
- return crypto.createPrivateKey(pem);
2003
+ return crypto2.createPrivateKey(pem);
1907
2004
  }
1908
2005
  // ---------------------------------------------------------------------------
1909
2006
  // Private helpers
@@ -1911,11 +2008,11 @@ var init_cryptography_service = __esm({
1911
2008
  /** RSA-OAEP SHA-256 encryption. */
1912
2009
  encryptRsaOaep(certPem, plaintext) {
1913
2010
  return new Uint8Array(
1914
- crypto.publicEncrypt(
2011
+ crypto2.publicEncrypt(
1915
2012
  {
1916
2013
  key: certPem,
1917
2014
  oaepHash: "sha256",
1918
- padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
2015
+ padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING
1919
2016
  },
1920
2017
  plaintext
1921
2018
  )
@@ -1932,15 +2029,15 @@ var init_cryptography_service = __esm({
1932
2029
  * (Java-compatible — GCM appends the 16-byte tag to the ciphertext).
1933
2030
  */
1934
2031
  encryptEcdhAesGcm(receiverPublicKey, plaintext) {
1935
- const { privateKey: ephPrivKey, publicKey: ephPubKey } = crypto.generateKeyPairSync("ec", {
2032
+ const { privateKey: ephPrivKey, publicKey: ephPubKey } = crypto2.generateKeyPairSync("ec", {
1936
2033
  namedCurve: "prime256v1"
1937
2034
  });
1938
- const sharedSecret = crypto.diffieHellman({
2035
+ const sharedSecret = crypto2.diffieHellman({
1939
2036
  privateKey: ephPrivKey,
1940
2037
  publicKey: receiverPublicKey
1941
2038
  });
1942
- const nonce = crypto.randomBytes(12);
1943
- const cipher = crypto.createCipheriv("aes-256-gcm", sharedSecret, nonce);
2039
+ const nonce = crypto2.randomBytes(12);
2040
+ const cipher = crypto2.createCipheriv("aes-256-gcm", sharedSecret, nonce);
1944
2041
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1945
2042
  const tag = cipher.getAuthTag();
1946
2043
  const ephemeralSpki = ephPubKey.export({ type: "spki", format: "der" });
@@ -6508,7 +6605,7 @@ function canonicalize(elem) {
6508
6605
  function computeRootDigest(doc) {
6509
6606
  const root = doc.documentElement;
6510
6607
  const canonical = canonicalize(root);
6511
- return crypto2.createHash("sha256").update(canonical, "utf-8").digest("base64");
6608
+ return crypto3.createHash("sha256").update(canonical, "utf-8").digest("base64");
6512
6609
  }
6513
6610
  function computeSignedPropertiesDigest(qualifyingPropertiesXml) {
6514
6611
  const parser = new import_xmldom.DOMParser();
@@ -6518,7 +6615,7 @@ function computeSignedPropertiesDigest(qualifyingPropertiesXml) {
6518
6615
  throw new Error("SignedProperties element not found in QualifyingProperties");
6519
6616
  }
6520
6617
  const canonical = canonicalize(signedProps);
6521
- return crypto2.createHash("sha256").update(canonical, "utf-8").digest("base64");
6618
+ return crypto3.createHash("sha256").update(canonical, "utf-8").digest("base64");
6522
6619
  }
6523
6620
  function buildSignedInfo(signatureAlgorithm, rootDigest, signedPropertiesDigest) {
6524
6621
  return [
@@ -6549,12 +6646,12 @@ function computeSignatureValue(canonicalSignedInfo, privateKeyPem, isEc) {
6549
6646
  const data = Buffer.from(canonicalSignedInfo, "utf-8");
6550
6647
  let signature;
6551
6648
  if (isEc) {
6552
- signature = crypto2.sign("sha256", data, {
6649
+ signature = crypto3.sign("sha256", data, {
6553
6650
  key: privateKeyPem,
6554
6651
  dsaEncoding: "ieee-p1363"
6555
6652
  });
6556
6653
  } else {
6557
- signature = crypto2.sign("sha256", data, privateKeyPem);
6654
+ signature = crypto3.sign("sha256", data, privateKeyPem);
6558
6655
  }
6559
6656
  return signature.toString("base64");
6560
6657
  }
@@ -6623,11 +6720,11 @@ function wrapBase64(base64) {
6623
6720
  }
6624
6721
  return lines.join("\n");
6625
6722
  }
6626
- var crypto2, import_xml_crypto, import_xmldom, XADES_NS, DS_NS, SIGNED_PROPERTIES_TYPE, SHA256_DIGEST_METHOD, EXC_C14N_ALGORITHM, ENVELOPED_SIGNATURE_TRANSFORM, RSA_SHA256_SIGNATURE, ECDSA_SHA256_SIGNATURE, CLOCK_SKEW_BUFFER_MS, SIGNATURE_ID, SIGNED_PROPERTIES_ID, SignatureService;
6723
+ var crypto3, import_xml_crypto, import_xmldom, XADES_NS, DS_NS, SIGNED_PROPERTIES_TYPE, SHA256_DIGEST_METHOD, EXC_C14N_ALGORITHM, ENVELOPED_SIGNATURE_TRANSFORM, RSA_SHA256_SIGNATURE, ECDSA_SHA256_SIGNATURE, CLOCK_SKEW_BUFFER_MS, SIGNATURE_ID, SIGNED_PROPERTIES_ID, SignatureService;
6627
6724
  var init_signature_service = __esm({
6628
6725
  "src/crypto/signature-service.ts"() {
6629
6726
  "use strict";
6630
- crypto2 = __toESM(require("crypto"), 1);
6727
+ crypto3 = __toESM(require("crypto"), 1);
6631
6728
  import_xml_crypto = require("xml-crypto");
6632
6729
  import_xmldom = __toESM(require_lib(), 1);
6633
6730
  XADES_NS = "http://uri.etsi.org/01903/v1.3.2#";
@@ -6656,11 +6753,11 @@ var init_signature_service = __esm({
6656
6753
  }
6657
6754
  const certDer = extractDerFromPem(certPem);
6658
6755
  const certBase64 = certDer.toString("base64");
6659
- const certDigest = crypto2.createHash("sha256").update(certDer).digest("base64");
6660
- const x5093 = new crypto2.X509Certificate(certPem);
6756
+ const certDigest = crypto3.createHash("sha256").update(certDer).digest("base64");
6757
+ const x5093 = new crypto3.X509Certificate(certPem);
6661
6758
  const issuerName = normalizeIssuerDn(x5093.issuer);
6662
6759
  const serialNumber = hexSerialToDecimal(x5093.serialNumber);
6663
- const privateKey = crypto2.createPrivateKey(privateKeyPem);
6760
+ const privateKey = crypto3.createPrivateKey(privateKeyPem);
6664
6761
  const isEc = privateKey.asymmetricKeyType === "ec";
6665
6762
  const signatureAlgorithm = isEc ? ECDSA_SHA256_SIGNATURE : RSA_SHA256_SIGNATURE;
6666
6763
  const signingTime = new Date(Date.now() + CLOCK_SKEW_BUFFER_MS).toISOString();
@@ -6763,6 +6860,32 @@ var init_pkcs12_loader = __esm({
6763
6860
  }
6764
6861
  });
6765
6862
 
6863
+ // src/crypto/auth-xml-builder.ts
6864
+ function buildUnsignedAuthTokenRequestXml(options) {
6865
+ const { challenge, contextIdentifier, subjectIdentifierType = "certificateSubject" } = options;
6866
+ const identifierElement = `<${contextIdentifier.type}>${xmlEscape(contextIdentifier.value)}</${contextIdentifier.type}>`;
6867
+ return [
6868
+ '<?xml version="1.0" encoding="utf-8"?>',
6869
+ `<AuthTokenRequest xmlns="${AUTH_TOKEN_REQUEST_NS}">`,
6870
+ `<Challenge>${xmlEscape(challenge)}</Challenge>`,
6871
+ `<ContextIdentifier>`,
6872
+ identifierElement,
6873
+ `</ContextIdentifier>`,
6874
+ `<SubjectIdentifierType>${xmlEscape(subjectIdentifierType)}</SubjectIdentifierType>`,
6875
+ `</AuthTokenRequest>`
6876
+ ].join("");
6877
+ }
6878
+ function xmlEscape(str) {
6879
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
6880
+ }
6881
+ var AUTH_TOKEN_REQUEST_NS;
6882
+ var init_auth_xml_builder = __esm({
6883
+ "src/crypto/auth-xml-builder.ts"() {
6884
+ "use strict";
6885
+ AUTH_TOKEN_REQUEST_NS = "http://ksef.mf.gov.pl/auth/token/2.0";
6886
+ }
6887
+ });
6888
+
6766
6889
  // src/qr/verification-link-service.ts
6767
6890
  var import_node_crypto, VerificationLinkService;
6768
6891
  var init_verification_link_service = __esm({
@@ -6827,19 +6950,11 @@ __export(client_exports, {
6827
6950
  buildAuthTokenRequestXml: () => buildAuthTokenRequestXml
6828
6951
  });
6829
6952
  function buildAuthTokenRequestXml(challenge, nip, subjectIdentifierType = "certificateSubject") {
6830
- return [
6831
- '<?xml version="1.0" encoding="utf-8"?>',
6832
- `<AuthTokenRequest xmlns="${AUTH_TOKEN_REQUEST_NS}">`,
6833
- `<Challenge>${xmlEscape(challenge)}</Challenge>`,
6834
- `<ContextIdentifier>`,
6835
- `<Nip>${xmlEscape(nip)}</Nip>`,
6836
- `</ContextIdentifier>`,
6837
- `<SubjectIdentifierType>${xmlEscape(subjectIdentifierType)}</SubjectIdentifierType>`,
6838
- `</AuthTokenRequest>`
6839
- ].join("");
6840
- }
6841
- function xmlEscape(str) {
6842
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
6953
+ return buildUnsignedAuthTokenRequestXml({
6954
+ challenge,
6955
+ contextIdentifier: { type: "Nip", value: nip },
6956
+ subjectIdentifierType
6957
+ });
6843
6958
  }
6844
6959
  function buildRestClientConfig(options, authManager) {
6845
6960
  const config = { authManager };
@@ -6866,7 +6981,7 @@ function buildRestClientConfig(options, authManager) {
6866
6981
  }
6867
6982
  return config;
6868
6983
  }
6869
- var KSeFClient, AUTH_TOKEN_REQUEST_NS;
6984
+ var KSeFClient;
6870
6985
  var init_client = __esm({
6871
6986
  "src/client.ts"() {
6872
6987
  "use strict";
@@ -6892,6 +7007,7 @@ var init_client = __esm({
6892
7007
  init_certificate_fetcher();
6893
7008
  init_cryptography_service();
6894
7009
  init_verification_link_service();
7010
+ init_auth_xml_builder();
6895
7011
  KSeFClient = class {
6896
7012
  auth;
6897
7013
  activeSessions;
@@ -6935,7 +7051,7 @@ var init_client = __esm({
6935
7051
  this.lighthouse = new LighthouseService(this.options);
6936
7052
  this.limits = new LimitsService(restClient);
6937
7053
  this.peppol = new PeppolService(restClient);
6938
- this.testData = new TestDataService(restClient);
7054
+ this.testData = new TestDataService(restClient, this.options.environmentName);
6939
7055
  this.qr = new VerificationLinkService(this.options.baseQrUrl);
6940
7056
  }
6941
7057
  async loginWithToken(token, nip) {
@@ -6985,7 +7101,6 @@ var init_client = __esm({
6985
7101
  this.authManager.setRefreshToken(void 0);
6986
7102
  }
6987
7103
  };
6988
- AUTH_TOKEN_REQUEST_NS = "http://ksef.mf.gov.pl/auth/token/2.0";
6989
7104
  }
6990
7105
  });
6991
7106
 
@@ -6997,7 +7112,11 @@ __export(index_exports, {
6997
7112
  AuthService: () => AuthService,
6998
7113
  AuthTokenRequestBuilder: () => AuthTokenRequestBuilder,
6999
7114
  AuthorizationPermissionGrantBuilder: () => AuthorizationPermissionGrantBuilder,
7115
+ BATCH_MAX_PARTS: () => BATCH_MAX_PARTS,
7116
+ BATCH_MAX_PART_SIZE: () => BATCH_MAX_PART_SIZE,
7117
+ BATCH_MAX_TOTAL_SIZE: () => BATCH_MAX_TOTAL_SIZE,
7000
7118
  Base64String: () => Base64String,
7119
+ BatchFileBuilder: () => BatchFileBuilder,
7001
7120
  BatchSessionService: () => BatchSessionService,
7002
7121
  CERTIFICATE_NAME_MAX_LENGTH: () => CERTIFICATE_NAME_MAX_LENGTH,
7003
7122
  CERTIFICATE_NAME_MIN_LENGTH: () => CERTIFICATE_NAME_MIN_LENGTH,
@@ -7011,6 +7130,11 @@ __export(index_exports, {
7011
7130
  ENFORCE_XADES_COMPLIANCE: () => ENFORCE_XADES_COMPLIANCE,
7012
7131
  EntityPermissionGrantBuilder: () => EntityPermissionGrantBuilder,
7013
7132
  Environment: () => Environment,
7133
+ FORM_CODES: () => FORM_CODES,
7134
+ FORM_CODE_KEYS: () => FORM_CODE_KEYS,
7135
+ FileHwmStore: () => FileHwmStore,
7136
+ INVOICE_TYPES_BY_SYSTEM_CODE: () => INVOICE_TYPES_BY_SYSTEM_CODE,
7137
+ InMemoryHwmStore: () => InMemoryHwmStore,
7014
7138
  InternalId: () => InternalId,
7015
7139
  InvoiceDownloadService: () => InvoiceDownloadService,
7016
7140
  InvoiceQueryFilterBuilder: () => InvoiceQueryFilterBuilder,
@@ -7056,21 +7180,29 @@ __export(index_exports, {
7056
7180
  SessionStatusService: () => SessionStatusService,
7057
7181
  Sha256Base64: () => Sha256Base64,
7058
7182
  SignatureService: () => SignatureService,
7183
+ SystemCode: () => SystemCode,
7059
7184
  TestDataService: () => TestDataService,
7060
7185
  TokenService: () => TokenService,
7061
7186
  UpoVersion: () => UpoVersion,
7062
7187
  VatUe: () => VatUe,
7063
7188
  VerificationLinkService: () => VerificationLinkService,
7064
7189
  authenticateWithCertificate: () => authenticateWithCertificate,
7190
+ authenticateWithExternalSignature: () => authenticateWithExternalSignature,
7065
7191
  authenticateWithPkcs12: () => authenticateWithPkcs12,
7066
7192
  authenticateWithToken: () => authenticateWithToken,
7193
+ buildUnsignedAuthTokenRequestXml: () => buildUnsignedAuthTokenRequestXml,
7067
7194
  calculateBackoff: () => calculateBackoff,
7195
+ createZip: () => createZip,
7196
+ deduplicateByKsefNumber: () => deduplicateByKsefNumber,
7068
7197
  defaultPresignedUrlPolicy: () => defaultPresignedUrlPolicy,
7069
7198
  defaultRateLimitPolicy: () => defaultRateLimitPolicy,
7070
7199
  defaultRetryPolicy: () => defaultRetryPolicy,
7071
7200
  defaultTransport: () => defaultTransport,
7072
7201
  exportAndDownload: () => exportAndDownload,
7073
7202
  exportInvoices: () => exportInvoices,
7203
+ getEffectiveStartDate: () => getEffectiveStartDate,
7204
+ getFormCode: () => getFormCode,
7205
+ incrementalExportAndDownload: () => incrementalExportAndDownload,
7074
7206
  isRetryableError: () => isRetryableError,
7075
7207
  isRetryableStatus: () => isRetryableStatus,
7076
7208
  isValidBase64: () => isValidBase64,
@@ -7090,11 +7222,19 @@ __export(index_exports, {
7090
7222
  isValidVatUe: () => isValidVatUe,
7091
7223
  openOnlineSession: () => openOnlineSession,
7092
7224
  openSendAndClose: () => openSendAndClose,
7225
+ parseFormCode: () => parseFormCode,
7093
7226
  parseRetryAfter: () => parseRetryAfter,
7227
+ parseUpoXml: () => parseUpoXml,
7094
7228
  pollUntil: () => pollUntil,
7095
7229
  resolveOptions: () => resolveOptions,
7096
7230
  sleep: () => sleep,
7231
+ unzip: () => unzip,
7232
+ updateContinuationPoint: () => updateContinuationPoint,
7097
7233
  uploadBatch: () => uploadBatch,
7234
+ uploadBatchParsed: () => uploadBatchParsed,
7235
+ uploadBatchStream: () => uploadBatchStream,
7236
+ uploadBatchStreamParsed: () => uploadBatchStreamParsed,
7237
+ validateFormCodeForSession: () => validateFormCodeForSession,
7098
7238
  validatePresignedUrl: () => validatePresignedUrl
7099
7239
  });
7100
7240
  module.exports = __toCommonJS(index_exports);
@@ -7227,6 +7367,65 @@ var SUBUNIT_NAME_MAX_LENGTH = 256;
7227
7367
  var PERMISSION_DESCRIPTION_MIN_LENGTH = 5;
7228
7368
  var PERMISSION_DESCRIPTION_MAX_LENGTH = 256;
7229
7369
 
7370
+ // src/models/document-structures/types.ts
7371
+ var SystemCode = {
7372
+ FA_2: "FA (2)",
7373
+ FA_3: "FA (3)",
7374
+ PEF_3: "PEF (3)",
7375
+ PEF_KOR_3: "PEF_KOR (3)",
7376
+ FA_RR_1: "FA_RR (1)"
7377
+ };
7378
+ var FORM_CODES = {
7379
+ FA_2: { systemCode: "FA (2)", schemaVersion: "1-0E", value: "FA" },
7380
+ FA_3: { systemCode: "FA (3)", schemaVersion: "1-0E", value: "FA" },
7381
+ PEF_3: { systemCode: "PEF (3)", schemaVersion: "2-1", value: "PEF" },
7382
+ PEF_KOR_3: { systemCode: "PEF_KOR (3)", schemaVersion: "2-1", value: "PEF" },
7383
+ FA_RR_1_LEGACY: { systemCode: "FA_RR (1)", schemaVersion: "1-0E", value: "RR" },
7384
+ FA_RR_1_TRANSITION: { systemCode: "FA_RR (1)", schemaVersion: "1-1E", value: "RR" },
7385
+ FA_RR_1: { systemCode: "FA_RR (1)", schemaVersion: "1-1E", value: "FA_RR" }
7386
+ };
7387
+ var INVOICE_TYPES_BY_SYSTEM_CODE = {
7388
+ [SystemCode.FA_2]: ["Vat", "Zal", "Kor", "Roz", "Upr", "KorZal", "KorRoz"],
7389
+ [SystemCode.FA_3]: ["Vat", "Zal", "Kor", "Roz", "Upr", "KorZal", "KorRoz"],
7390
+ [SystemCode.PEF_3]: ["VatPef", "VatPefSp", "KorPef"],
7391
+ [SystemCode.PEF_KOR_3]: ["KorPef"],
7392
+ [SystemCode.FA_RR_1]: ["VatRr", "KorVatRr"]
7393
+ };
7394
+ var FORM_CODE_KEYS = {
7395
+ FA2: FORM_CODES.FA_2,
7396
+ FA3: FORM_CODES.FA_3,
7397
+ PEF3: FORM_CODES.PEF_3,
7398
+ PEFKOR3: FORM_CODES.PEF_KOR_3,
7399
+ FARR1: FORM_CODES.FA_RR_1
7400
+ };
7401
+
7402
+ // src/models/document-structures/helpers.ts
7403
+ var SYSTEM_CODE_TO_FORM_CODE = {
7404
+ [SystemCode.FA_2]: FORM_CODES.FA_2,
7405
+ [SystemCode.FA_3]: FORM_CODES.FA_3,
7406
+ [SystemCode.PEF_3]: FORM_CODES.PEF_3,
7407
+ [SystemCode.PEF_KOR_3]: FORM_CODES.PEF_KOR_3,
7408
+ [SystemCode.FA_RR_1]: FORM_CODES.FA_RR_1
7409
+ };
7410
+ var ALL_FORM_CODES = Object.values(FORM_CODES);
7411
+ var BATCH_DISALLOWED_SYSTEM_CODES = /* @__PURE__ */ new Set([
7412
+ SystemCode.PEF_3,
7413
+ SystemCode.PEF_KOR_3
7414
+ ]);
7415
+ function getFormCode(systemCode) {
7416
+ return SYSTEM_CODE_TO_FORM_CODE[systemCode];
7417
+ }
7418
+ function parseFormCode(raw) {
7419
+ const match = ALL_FORM_CODES.find(
7420
+ (fc) => fc.systemCode === raw.systemCode && fc.schemaVersion === raw.schemaVersion && fc.value === raw.value
7421
+ );
7422
+ return match ?? raw;
7423
+ }
7424
+ function validateFormCodeForSession(formCode, sessionType) {
7425
+ if (sessionType === "online") return true;
7426
+ return !BATCH_DISALLOWED_SYSTEM_CODES.has(formCode.systemCode);
7427
+ }
7428
+
7230
7429
  // src/services/index.ts
7231
7430
  init_auth();
7232
7431
  init_active_sessions();
@@ -7590,18 +7789,188 @@ var AuthorizationPermissionGrantBuilder = class {
7590
7789
  }
7591
7790
  };
7592
7791
 
7792
+ // src/builders/batch-file.ts
7793
+ var crypto = __toESM(require("crypto"), 1);
7794
+ init_ksef_validation_error();
7795
+ var BATCH_MAX_PART_SIZE = 1e8;
7796
+ var BATCH_MAX_TOTAL_SIZE = 5e9;
7797
+ var BATCH_MAX_PARTS = 50;
7798
+ var BatchFileBuilder = class {
7799
+ /**
7800
+ * Build batch file metadata and encrypted parts from a raw ZIP.
7801
+ *
7802
+ * @param zipBytes - Unencrypted ZIP data
7803
+ * @param encryptFn - AES-256-CBC encryption function (called per part)
7804
+ * @param options - Optional configuration
7805
+ */
7806
+ static build(zipBytes, encryptFn, options) {
7807
+ const maxPartSize = options?.maxPartSize ?? BATCH_MAX_PART_SIZE;
7808
+ if (maxPartSize <= 0) {
7809
+ throw new KSeFValidationError("maxPartSize must be a positive number");
7810
+ }
7811
+ if (zipBytes.length === 0) {
7812
+ throw new KSeFValidationError("ZIP data must not be empty");
7813
+ }
7814
+ if (zipBytes.length > BATCH_MAX_TOTAL_SIZE) {
7815
+ throw new KSeFValidationError(
7816
+ `ZIP size ${zipBytes.length} exceeds maximum of ${BATCH_MAX_TOTAL_SIZE} bytes (5 GB)`
7817
+ );
7818
+ }
7819
+ const rawParts = splitBuffer(zipBytes, maxPartSize);
7820
+ if (rawParts.length > BATCH_MAX_PARTS) {
7821
+ throw new KSeFValidationError(
7822
+ `Data requires ${rawParts.length} parts, exceeding maximum of ${BATCH_MAX_PARTS}`
7823
+ );
7824
+ }
7825
+ const zipHash = sha256Base64(zipBytes);
7826
+ const encryptedParts = [];
7827
+ const fileParts = rawParts.map((raw, i) => {
7828
+ const encrypted = encryptFn(raw);
7829
+ encryptedParts.push(encrypted);
7830
+ return {
7831
+ ordinalNumber: i + 1,
7832
+ fileSize: encrypted.length,
7833
+ fileHash: sha256Base64(encrypted)
7834
+ };
7835
+ });
7836
+ return {
7837
+ batchFile: {
7838
+ fileSize: zipBytes.length,
7839
+ fileHash: zipHash,
7840
+ fileParts
7841
+ },
7842
+ encryptedParts
7843
+ };
7844
+ }
7845
+ /**
7846
+ * Stream-based variant: two-pass build from a stream factory.
7847
+ *
7848
+ * Pass 1: consume stream to compute ZIP hash.
7849
+ * Pass 2: re-create stream, split into parts, encrypt each, compute per-part metadata.
7850
+ *
7851
+ * @param zipStreamFactory - Factory that creates a fresh ReadableStream of the ZIP data
7852
+ * @param zipSize - Total ZIP byte size (from fs.stat or known in advance)
7853
+ * @param encryptStreamFn - Stream-to-stream AES-256-CBC encryption function
7854
+ * @param hashStreamFn - Stream-to-FileMetadata hashing function
7855
+ * @param options - Optional configuration
7856
+ */
7857
+ static async buildFromStream(zipStreamFactory, zipSize, encryptStreamFn, hashStreamFn, options) {
7858
+ const maxPartSize = options?.maxPartSize ?? BATCH_MAX_PART_SIZE;
7859
+ if (maxPartSize <= 0) {
7860
+ throw new KSeFValidationError("maxPartSize must be a positive number");
7861
+ }
7862
+ if (zipSize === 0) {
7863
+ throw new KSeFValidationError("ZIP data must not be empty");
7864
+ }
7865
+ if (zipSize > BATCH_MAX_TOTAL_SIZE) {
7866
+ throw new KSeFValidationError(
7867
+ `ZIP size ${zipSize} exceeds maximum of ${BATCH_MAX_TOTAL_SIZE} bytes (5 GB)`
7868
+ );
7869
+ }
7870
+ const partCount = Math.ceil(zipSize / maxPartSize);
7871
+ if (partCount > BATCH_MAX_PARTS) {
7872
+ throw new KSeFValidationError(
7873
+ `Data requires ${partCount} parts, exceeding maximum of ${BATCH_MAX_PARTS}`
7874
+ );
7875
+ }
7876
+ const zipMeta = await hashStreamFn(zipStreamFactory());
7877
+ const fileParts = [];
7878
+ const streamParts = [];
7879
+ const reader = zipStreamFactory().getReader();
7880
+ let pending = [];
7881
+ let pendingSize = 0;
7882
+ for (let partIndex = 0; partIndex < partCount; partIndex++) {
7883
+ const isLastPart = partIndex === partCount - 1;
7884
+ const targetSize = isLastPart ? zipSize - partIndex * maxPartSize : maxPartSize;
7885
+ while (pendingSize < targetSize) {
7886
+ const { done, value } = await reader.read();
7887
+ if (done) break;
7888
+ pending.push(value);
7889
+ pendingSize += value.byteLength;
7890
+ }
7891
+ const buffer = new Uint8Array(Buffer.concat(pending));
7892
+ const partData = buffer.subarray(0, targetSize);
7893
+ if (buffer.byteLength > targetSize) {
7894
+ const remainder = buffer.subarray(targetSize);
7895
+ pending = [remainder];
7896
+ pendingSize = remainder.byteLength;
7897
+ } else {
7898
+ pending = [];
7899
+ pendingSize = 0;
7900
+ }
7901
+ const partStream = new ReadableStream({
7902
+ start(controller) {
7903
+ controller.enqueue(partData);
7904
+ controller.close();
7905
+ }
7906
+ });
7907
+ const encryptedStream = encryptStreamFn(partStream);
7908
+ const encryptedChunks = [];
7909
+ const encReader = encryptedStream.getReader();
7910
+ for (; ; ) {
7911
+ const { done, value } = await encReader.read();
7912
+ if (done) break;
7913
+ encryptedChunks.push(value);
7914
+ }
7915
+ const encryptedData = new Uint8Array(Buffer.concat(encryptedChunks));
7916
+ const encryptedMeta = sha256Base64(encryptedData);
7917
+ fileParts.push({
7918
+ ordinalNumber: partIndex + 1,
7919
+ fileSize: encryptedData.byteLength,
7920
+ fileHash: encryptedMeta
7921
+ });
7922
+ const uploadStream = new ReadableStream({
7923
+ start(controller) {
7924
+ controller.enqueue(encryptedData);
7925
+ controller.close();
7926
+ }
7927
+ });
7928
+ streamParts.push({
7929
+ dataStream: uploadStream,
7930
+ metadata: {
7931
+ hashSHA: encryptedMeta,
7932
+ fileSize: encryptedData.byteLength
7933
+ },
7934
+ ordinalNumber: partIndex + 1
7935
+ });
7936
+ }
7937
+ reader.releaseLock();
7938
+ return {
7939
+ batchFile: {
7940
+ fileSize: zipSize,
7941
+ fileHash: zipMeta.hashSHA,
7942
+ fileParts
7943
+ },
7944
+ streamParts
7945
+ };
7946
+ }
7947
+ };
7948
+ function splitBuffer(data, maxPartSize) {
7949
+ if (data.length <= maxPartSize) {
7950
+ return [data];
7951
+ }
7952
+ const parts = [];
7953
+ for (let offset = 0; offset < data.length; offset += maxPartSize) {
7954
+ parts.push(data.subarray(offset, Math.min(offset + maxPartSize, data.length)));
7955
+ }
7956
+ return parts;
7957
+ }
7958
+ function sha256Base64(data) {
7959
+ return crypto.createHash("sha256").update(data).digest("base64");
7960
+ }
7961
+
7593
7962
  // src/crypto/index.ts
7594
7963
  init_certificate_fetcher();
7595
7964
  init_cryptography_service();
7596
7965
  init_signature_service();
7597
7966
 
7598
7967
  // src/crypto/certificate-service.ts
7599
- var crypto3 = __toESM(require("crypto"), 1);
7968
+ var crypto4 = __toESM(require("crypto"), 1);
7600
7969
  var x5092 = __toESM(require("@peculiar/x509"), 1);
7601
7970
  var CertificateService = class {
7602
7971
  static getSha256Fingerprint(certPem) {
7603
7972
  const der = extractDerFromPem2(certPem);
7604
- return crypto3.createHash("sha256").update(der).digest("hex").toUpperCase();
7973
+ return crypto4.createHash("sha256").update(der).digest("hex").toUpperCase();
7605
7974
  }
7606
7975
  static async generatePersonalCertificate(givenName, surname, serialNumber, commonName, method = "RSA") {
7607
7976
  const nameParts = [];
@@ -7624,7 +7993,7 @@ var CertificateService = class {
7624
7993
  }
7625
7994
  };
7626
7995
  async function generateSelfSigned(subject, method) {
7627
- x5092.cryptoProvider.set(crypto3.webcrypto);
7996
+ x5092.cryptoProvider.set(crypto4.webcrypto);
7628
7997
  let algorithm;
7629
7998
  let signingAlgorithm;
7630
7999
  if (method === "ECDSA") {
@@ -7639,7 +8008,7 @@ async function generateSelfSigned(subject, method) {
7639
8008
  };
7640
8009
  signingAlgorithm = algorithm;
7641
8010
  }
7642
- const keys = await crypto3.webcrypto.subtle.generateKey(
8011
+ const keys = await crypto4.webcrypto.subtle.generateKey(
7643
8012
  algorithm,
7644
8013
  true,
7645
8014
  ["sign", "verify"]
@@ -7656,9 +8025,9 @@ async function generateSelfSigned(subject, method) {
7656
8025
  serialNumber: Date.now().toString(16)
7657
8026
  });
7658
8027
  const certPem = cert.toString("pem");
7659
- const pkcs8 = await crypto3.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
8028
+ const pkcs8 = await crypto4.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
7660
8029
  const privateKeyPem = pemEncode2(new Uint8Array(pkcs8), "PRIVATE KEY");
7661
- const fingerprint = crypto3.createHash("sha256").update(Buffer.from(cert.rawData)).digest("hex").toUpperCase();
8030
+ const fingerprint = crypto4.createHash("sha256").update(Buffer.from(cert.rawData)).digest("hex").toUpperCase();
7662
8031
  return { certificatePem: certPem, privateKeyPem, fingerprint };
7663
8032
  }
7664
8033
  function extractDerFromPem2(pem) {
@@ -7678,6 +8047,7 @@ ${lines.join("\n")}
7678
8047
 
7679
8048
  // src/crypto/index.ts
7680
8049
  init_pkcs12_loader();
8050
+ init_auth_xml_builder();
7681
8051
 
7682
8052
  // src/qr/index.ts
7683
8053
  init_verification_link_service();
@@ -7741,6 +8111,94 @@ function escapeXml2(str) {
7741
8111
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
7742
8112
  }
7743
8113
 
8114
+ // src/utils/zip.ts
8115
+ var import_yazl = require("yazl");
8116
+ var import_yauzl = require("yauzl");
8117
+ var DEFAULT_UNZIP_OPTIONS = {
8118
+ maxFiles: 1e4,
8119
+ maxTotalUncompressedSize: 2e9,
8120
+ maxFileUncompressedSize: 5e8,
8121
+ maxCompressionRatio: 200
8122
+ };
8123
+ async function createZip(entries) {
8124
+ return new Promise((resolve, reject) => {
8125
+ const zipfile = new import_yazl.ZipFile();
8126
+ for (const entry of entries) {
8127
+ zipfile.addBuffer(Buffer.from(entry.content), entry.fileName);
8128
+ }
8129
+ const chunks = [];
8130
+ zipfile.outputStream.on("data", (chunk) => chunks.push(chunk));
8131
+ zipfile.outputStream.on("error", (err) => reject(err));
8132
+ zipfile.outputStream.on("end", () => resolve(Buffer.concat(chunks)));
8133
+ zipfile.end();
8134
+ });
8135
+ }
8136
+ async function unzip(buffer, options = {}) {
8137
+ const limits = { ...DEFAULT_UNZIP_OPTIONS, ...options };
8138
+ return new Promise((resolve, reject) => {
8139
+ (0, import_yauzl.fromBuffer)(buffer, { lazyEntries: true }, (err, zipfile) => {
8140
+ if (err || !zipfile) {
8141
+ reject(err ?? new Error("Failed to open zip buffer"));
8142
+ return;
8143
+ }
8144
+ const files = /* @__PURE__ */ new Map();
8145
+ let totalUncompressed = 0;
8146
+ zipfile.readEntry();
8147
+ zipfile.on("entry", (entry) => {
8148
+ if (entry.fileName.endsWith("/")) {
8149
+ zipfile.readEntry();
8150
+ return;
8151
+ }
8152
+ if (limits.maxFiles > 0 && files.size >= limits.maxFiles) {
8153
+ reject(new Error("zip contains too many files"));
8154
+ return;
8155
+ }
8156
+ const uncompressedSize = entry.uncompressedSize ?? 0;
8157
+ const compressedSize = entry.compressedSize ?? 0;
8158
+ if (limits.maxFileUncompressedSize > 0 && uncompressedSize > limits.maxFileUncompressedSize) {
8159
+ reject(new Error("zip entry exceeds max_file_uncompressed_size"));
8160
+ return;
8161
+ }
8162
+ if (limits.maxTotalUncompressedSize > 0) {
8163
+ totalUncompressed += uncompressedSize;
8164
+ if (totalUncompressed > limits.maxTotalUncompressedSize) {
8165
+ reject(new Error("zip exceeds max_total_uncompressed_size"));
8166
+ return;
8167
+ }
8168
+ }
8169
+ if (limits.maxCompressionRatio !== null) {
8170
+ if (compressedSize === 0 && uncompressedSize > 0) {
8171
+ reject(new Error("zip entry has suspicious compression metadata"));
8172
+ return;
8173
+ }
8174
+ if (compressedSize > 0 && uncompressedSize > 0) {
8175
+ const ratio = uncompressedSize / compressedSize;
8176
+ if (ratio > limits.maxCompressionRatio) {
8177
+ reject(new Error("zip entry exceeds max_compression_ratio"));
8178
+ return;
8179
+ }
8180
+ }
8181
+ }
8182
+ zipfile.openReadStream(entry, (streamErr, stream) => {
8183
+ if (streamErr || !stream) {
8184
+ reject(streamErr ?? new Error("Failed to read zip entry"));
8185
+ return;
8186
+ }
8187
+ const chunks = [];
8188
+ stream.on("data", (chunk) => chunks.push(chunk));
8189
+ stream.on("error", (streamError) => reject(streamError));
8190
+ stream.on("end", () => {
8191
+ files.set(entry.fileName, Buffer.concat(chunks));
8192
+ zipfile.readEntry();
8193
+ });
8194
+ });
8195
+ });
8196
+ zipfile.on("end", () => resolve(files));
8197
+ zipfile.on("error", (zipErr) => reject(zipErr));
8198
+ });
8199
+ });
8200
+ }
8201
+
7744
8202
  // src/workflows/polling.ts
7745
8203
  async function pollUntil(action, condition, options) {
7746
8204
  const intervalMs = options?.intervalMs ?? 2e3;
@@ -7758,17 +8216,150 @@ async function pollUntil(action, condition, options) {
7758
8216
  );
7759
8217
  }
7760
8218
 
8219
+ // src/xml/upo-parser.ts
8220
+ var import_fast_xml_parser = require("fast-xml-parser");
8221
+ init_ksef_validation_error();
8222
+ function isRecord(value) {
8223
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8224
+ }
8225
+ function requireRecord(value, at) {
8226
+ if (!isRecord(value)) {
8227
+ throw KSeFValidationError.fromField(at, `Expected object at ${at}`);
8228
+ }
8229
+ return value;
8230
+ }
8231
+ function requireString(value, at) {
8232
+ if (typeof value !== "string" || value.length === 0) {
8233
+ throw KSeFValidationError.fromField(at, `Expected non-empty string at ${at}`);
8234
+ }
8235
+ return value;
8236
+ }
8237
+ function optionalRecord(value) {
8238
+ return isRecord(value) ? value : void 0;
8239
+ }
8240
+ function optionalString(value) {
8241
+ return typeof value === "string" && value.length > 0 ? value : void 0;
8242
+ }
8243
+ function requireNumberFromString(value, at) {
8244
+ const raw = requireString(value, at);
8245
+ const parsed = Number.parseInt(raw, 10);
8246
+ if (!Number.isFinite(parsed)) {
8247
+ throw KSeFValidationError.fromField(at, `Expected integer at ${at}, got "${raw}"`);
8248
+ }
8249
+ return parsed;
8250
+ }
8251
+ function ensureArray(value) {
8252
+ if (value == null) return [];
8253
+ return Array.isArray(value) ? value : [value];
8254
+ }
8255
+ function parseIdKontekstu(obj) {
8256
+ const nip = optionalString(obj.Nip);
8257
+ if (nip) return { kind: "Nip", nip };
8258
+ const idWewnetrzny = optionalString(obj.IdWewnetrzny);
8259
+ if (idWewnetrzny) return { kind: "IdWewnetrzny", idWewnetrzny };
8260
+ const idZlozonyVatUE = optionalString(obj.IdZlozonyVatUE);
8261
+ if (idZlozonyVatUE) return { kind: "IdZlozonyVatUE", idZlozonyVatUE };
8262
+ const idDostawcyUslugPeppol = optionalString(obj.IdDostawcyUslugPeppol);
8263
+ if (idDostawcyUslugPeppol) return { kind: "IdDostawcyUslugPeppol", idDostawcyUslugPeppol };
8264
+ throw KSeFValidationError.fromField(
8265
+ "Uwierzytelnienie.IdKontekstu",
8266
+ "Unsupported context identifier. Expected Nip | IdWewnetrzny | IdZlozonyVatUE | IdDostawcyUslugPeppol"
8267
+ );
8268
+ }
8269
+ function parseProof(obj) {
8270
+ const tokenRef = optionalString(obj.NumerReferencyjnyTokenaKSeF);
8271
+ if (tokenRef) return { kind: "NumerReferencyjnyTokenaKSeF", numerReferencyjnyTokenaKSeF: tokenRef };
8272
+ const docHash = optionalString(obj.SkrotDokumentuUwierzytelniajacego);
8273
+ if (docHash) return { kind: "SkrotDokumentuUwierzytelniajacego", skrotDokumentuUwierzytelniajacego: docHash };
8274
+ throw KSeFValidationError.fromField(
8275
+ "Uwierzytelnienie",
8276
+ "Unsupported auth proof. Expected NumerReferencyjnyTokenaKSeF | SkrotDokumentuUwierzytelniajacego"
8277
+ );
8278
+ }
8279
+ function parseUwierzytelnienie(obj) {
8280
+ const idKontekstu = parseIdKontekstu(
8281
+ requireRecord(obj.IdKontekstu, "Uwierzytelnienie.IdKontekstu")
8282
+ );
8283
+ const proof = parseProof(obj);
8284
+ return { idKontekstu, proof };
8285
+ }
8286
+ function parseOpisPotwierdzenia(obj) {
8287
+ return {
8288
+ strona: requireNumberFromString(obj.Strona, "OpisPotwierdzenia.Strona"),
8289
+ liczbaStron: requireNumberFromString(obj.LiczbaStron, "OpisPotwierdzenia.LiczbaStron"),
8290
+ zakresDokumentowOd: requireNumberFromString(obj.ZakresDokumentowOd, "OpisPotwierdzenia.ZakresDokumentowOd"),
8291
+ zakresDokumentowDo: requireNumberFromString(obj.ZakresDokumentowDo, "OpisPotwierdzenia.ZakresDokumentowDo"),
8292
+ calkowitaLiczbaDokumentow: requireNumberFromString(obj.CalkowitaLiczbaDokumentow, "OpisPotwierdzenia.CalkowitaLiczbaDokumentow")
8293
+ };
8294
+ }
8295
+ function parseDokument(obj) {
8296
+ return {
8297
+ nipSprzedawcy: requireString(obj.NipSprzedawcy, "Dokument.NipSprzedawcy"),
8298
+ numerKSeFDokumentu: requireString(obj.NumerKSeFDokumentu, "Dokument.NumerKSeFDokumentu"),
8299
+ numerFaktury: requireString(obj.NumerFaktury, "Dokument.NumerFaktury"),
8300
+ dataWystawieniaFaktury: requireString(obj.DataWystawieniaFaktury, "Dokument.DataWystawieniaFaktury"),
8301
+ dataPrzeslaniaDokumentu: requireString(obj.DataPrzeslaniaDokumentu, "Dokument.DataPrzeslaniaDokumentu"),
8302
+ dataNadaniaNumeruKSeF: requireString(obj.DataNadaniaNumeruKSeF, "Dokument.DataNadaniaNumeruKSeF"),
8303
+ skrotDokumentu: requireString(obj.SkrotDokumentu, "Dokument.SkrotDokumentu"),
8304
+ trybWysylki: requireString(obj.TrybWysylki, "Dokument.TrybWysylki")
8305
+ };
8306
+ }
8307
+ var upoParser = new import_fast_xml_parser.XMLParser({
8308
+ ignoreAttributes: false,
8309
+ attributeNamePrefix: "@_",
8310
+ parseTagValue: false,
8311
+ parseAttributeValue: false,
8312
+ removeNSPrefix: true,
8313
+ trimValues: false
8314
+ });
8315
+ function parseUpoXml(xml) {
8316
+ const text = Buffer.isBuffer(xml) ? xml.toString("utf8") : xml;
8317
+ const parsed = upoParser.parse(text);
8318
+ const potwierdzenie = requireRecord(parsed?.Potwierdzenie, "Potwierdzenie");
8319
+ const opisPotwierdzenia = optionalRecord(potwierdzenie.OpisPotwierdzenia);
8320
+ const dokumenty = ensureArray(potwierdzenie.Dokument).map(
8321
+ (doc, i) => parseDokument(requireRecord(doc, `Dokument[${i}]`))
8322
+ );
8323
+ if (dokumenty.length === 0) {
8324
+ throw KSeFValidationError.fromField("Dokument", "Expected at least one Dokument in UPO");
8325
+ }
8326
+ return {
8327
+ nazwaPodmiotuPrzyjmujacego: requireString(potwierdzenie.NazwaPodmiotuPrzyjmujacego, "NazwaPodmiotuPrzyjmujacego"),
8328
+ numerReferencyjnySesji: requireString(potwierdzenie.NumerReferencyjnySesji, "NumerReferencyjnySesji"),
8329
+ uwierzytelnienie: parseUwierzytelnienie(requireRecord(potwierdzenie.Uwierzytelnienie, "Uwierzytelnienie")),
8330
+ ...opisPotwierdzenia && { opisPotwierdzenia: parseOpisPotwierdzenia(opisPotwierdzenia) },
8331
+ nazwaStrukturyLogicznej: requireString(potwierdzenie.NazwaStrukturyLogicznej, "NazwaStrukturyLogicznej"),
8332
+ kodFormularza: requireString(potwierdzenie.KodFormularza, "KodFormularza"),
8333
+ dokumenty
8334
+ };
8335
+ }
8336
+
7761
8337
  // src/workflows/online-session-workflow.ts
7762
- var DEFAULT_FORM_CODE = { systemCode: "FA", schemaVersion: "3", value: "FA (3)" };
7763
8338
  async function openOnlineSession(client, options) {
7764
8339
  await client.crypto.init();
7765
8340
  const encData = client.crypto.getEncryptionData();
7766
- const formCode = options?.formCode ?? DEFAULT_FORM_CODE;
8341
+ const formCode = options?.formCode ?? FORM_CODES.FA_2;
7767
8342
  const openResp = await client.onlineSession.openSession(
7768
8343
  { formCode, encryption: encData.encryptionInfo },
7769
8344
  options?.upoVersion
7770
8345
  );
7771
8346
  const sessionRef = openResp.referenceNumber;
8347
+ async function fetchUpo(pollOpts) {
8348
+ const result = await pollUntil(
8349
+ () => client.sessionStatus.getSessionStatus(sessionRef),
8350
+ (s) => s.status.code === 200 || s.status.code >= 400,
8351
+ { ...pollOpts, description: `UPO for session ${sessionRef}` }
8352
+ );
8353
+ if (result.status.code !== 200) {
8354
+ throw new Error(`Session failed: ${result.status.code} \u2014 ${result.status.description}`);
8355
+ }
8356
+ return {
8357
+ pages: result.upo?.pages ?? [],
8358
+ invoiceCount: result.invoiceCount,
8359
+ successfulInvoiceCount: result.successfulInvoiceCount,
8360
+ failedInvoiceCount: result.failedInvoiceCount
8361
+ };
8362
+ }
7772
8363
  return {
7773
8364
  sessionRef,
7774
8365
  validUntil: openResp.validUntil,
@@ -7790,20 +8381,16 @@ async function openOnlineSession(client, options) {
7790
8381
  await client.onlineSession.closeSession(sessionRef);
7791
8382
  },
7792
8383
  async waitForUpo(pollOpts) {
7793
- const result = await pollUntil(
7794
- () => client.sessionStatus.getSessionStatus(sessionRef),
7795
- (s) => s.status.code !== 100,
7796
- { ...pollOpts, description: `UPO for session ${sessionRef}` }
7797
- );
7798
- if (result.status.code !== 200) {
7799
- throw new Error(`Session failed: ${result.status.code} \u2014 ${result.status.description}`);
7800
- }
7801
- return {
7802
- pages: result.upo?.pages ?? [],
7803
- invoiceCount: result.invoiceCount,
7804
- successfulInvoiceCount: result.successfulInvoiceCount,
7805
- failedInvoiceCount: result.failedInvoiceCount
7806
- };
8384
+ return fetchUpo(pollOpts);
8385
+ },
8386
+ async waitForUpoParsed(pollOpts) {
8387
+ const upoInfo = await fetchUpo(pollOpts);
8388
+ const parsed = [];
8389
+ for (const page of upoInfo.pages) {
8390
+ const result = await client.sessionStatus.getSessionUpo(sessionRef, page.referenceNumber);
8391
+ parsed.push(parseUpoXml(result.upo));
8392
+ }
8393
+ return { ...upoInfo, parsed };
7807
8394
  }
7808
8395
  };
7809
8396
  }
@@ -7817,32 +8404,78 @@ async function openSendAndClose(client, invoices, options) {
7817
8404
  }
7818
8405
 
7819
8406
  // src/workflows/batch-session-workflow.ts
7820
- var DEFAULT_FORM_CODE2 = { systemCode: "FA", schemaVersion: "3", value: "FA (3)" };
7821
- async function uploadBatch(client, zipParts, totalFileSize, totalFileHash, options) {
8407
+ async function uploadBatch(client, zipData, options) {
7822
8408
  await client.crypto.init();
7823
8409
  const encData = client.crypto.getEncryptionData();
7824
- const formCode = options?.formCode ?? DEFAULT_FORM_CODE2;
7825
- const fileParts = zipParts.map((part, i) => {
7826
- const meta = client.crypto.getFileMetadata(new Uint8Array(part.data));
7827
- return { ordinalNumber: i + 1, fileSize: meta.fileSize, fileHash: meta.hashSHA };
8410
+ const formCode = options?.formCode ?? FORM_CODES.FA_2;
8411
+ const encryptFn = (part) => client.crypto.encryptAES256(part, encData.cipherKey, encData.cipherIv);
8412
+ const { batchFile, encryptedParts } = BatchFileBuilder.build(zipData, encryptFn, {
8413
+ maxPartSize: options?.maxPartSize
7828
8414
  });
7829
8415
  const openResp = await client.batchSession.openSession(
7830
8416
  {
7831
8417
  formCode,
7832
8418
  encryption: encData.encryptionInfo,
7833
- batchFile: { fileSize: totalFileSize, fileHash: totalFileHash, fileParts }
8419
+ batchFile,
8420
+ offlineMode: options?.offlineMode
7834
8421
  },
7835
8422
  options?.upoVersion
7836
8423
  );
7837
- const sendingParts = zipParts.map((part, i) => {
7838
- const meta = client.crypto.getFileMetadata(new Uint8Array(part.data));
7839
- return { data: part.data, metadata: meta, ordinalNumber: i + 1 };
7840
- });
8424
+ const sendingParts = encryptedParts.map((part, i) => ({
8425
+ data: part.buffer.slice(part.byteOffset, part.byteOffset + part.byteLength),
8426
+ metadata: {
8427
+ hashSHA: batchFile.fileParts[i].fileHash,
8428
+ fileSize: batchFile.fileParts[i].fileSize
8429
+ },
8430
+ ordinalNumber: i + 1
8431
+ }));
7841
8432
  await client.batchSession.sendParts(openResp, sendingParts);
7842
8433
  await client.batchSession.closeSession(openResp.referenceNumber);
7843
8434
  const result = await pollUntil(
7844
8435
  () => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
7845
- (s) => s.status.code !== 100,
8436
+ (s) => s.status.code === 200 || s.status.code >= 400,
8437
+ { ...options?.pollOptions, description: `UPO for batch ${openResp.referenceNumber}` }
8438
+ );
8439
+ if (result.status.code !== 200) {
8440
+ throw new Error(`Batch session failed: ${result.status.code} \u2014 ${result.status.description}`);
8441
+ }
8442
+ return {
8443
+ sessionRef: openResp.referenceNumber,
8444
+ upo: {
8445
+ pages: result.upo?.pages ?? [],
8446
+ invoiceCount: result.invoiceCount,
8447
+ successfulInvoiceCount: result.successfulInvoiceCount,
8448
+ failedInvoiceCount: result.failedInvoiceCount
8449
+ }
8450
+ };
8451
+ }
8452
+ async function uploadBatchStream(client, zipStreamFactory, zipSize, options) {
8453
+ await client.crypto.init();
8454
+ const encData = client.crypto.getEncryptionData();
8455
+ const formCode = options?.formCode ?? FORM_CODES.FA_2;
8456
+ const encryptStreamFn = (stream) => client.crypto.encryptAES256Stream(stream, encData.cipherKey, encData.cipherIv);
8457
+ const hashStreamFn = (stream) => client.crypto.getFileMetadataFromStream(stream);
8458
+ const { batchFile, streamParts } = await BatchFileBuilder.buildFromStream(
8459
+ zipStreamFactory,
8460
+ zipSize,
8461
+ encryptStreamFn,
8462
+ hashStreamFn,
8463
+ { maxPartSize: options?.maxPartSize }
8464
+ );
8465
+ const openResp = await client.batchSession.openSession(
8466
+ {
8467
+ formCode,
8468
+ encryption: encData.encryptionInfo,
8469
+ batchFile,
8470
+ offlineMode: options?.offlineMode
8471
+ },
8472
+ options?.upoVersion
8473
+ );
8474
+ await client.batchSession.sendPartsWithStream(openResp, streamParts);
8475
+ await client.batchSession.closeSession(openResp.referenceNumber);
8476
+ const result = await pollUntil(
8477
+ () => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
8478
+ (s) => s.status.code === 200 || s.status.code >= 400,
7846
8479
  { ...options?.pollOptions, description: `UPO for batch ${openResp.referenceNumber}` }
7847
8480
  );
7848
8481
  if (result.status.code !== 200) {
@@ -7858,9 +8491,33 @@ async function uploadBatch(client, zipParts, totalFileSize, totalFileHash, optio
7858
8491
  }
7859
8492
  };
7860
8493
  }
8494
+ async function uploadBatchStreamParsed(client, zipStreamFactory, zipSize, options) {
8495
+ const result = await uploadBatchStream(client, zipStreamFactory, zipSize, options);
8496
+ const parsed = [];
8497
+ for (const page of result.upo.pages) {
8498
+ const upoResult = await client.sessionStatus.getSessionUpo(result.sessionRef, page.referenceNumber);
8499
+ parsed.push(parseUpoXml(upoResult.upo));
8500
+ }
8501
+ return {
8502
+ sessionRef: result.sessionRef,
8503
+ upo: { ...result.upo, parsed }
8504
+ };
8505
+ }
8506
+ async function uploadBatchParsed(client, zipData, options) {
8507
+ const result = await uploadBatch(client, zipData, options);
8508
+ const parsed = [];
8509
+ for (const page of result.upo.pages) {
8510
+ const upoResult = await client.sessionStatus.getSessionUpo(result.sessionRef, page.referenceNumber);
8511
+ parsed.push(parseUpoXml(upoResult.upo));
8512
+ }
8513
+ return {
8514
+ sessionRef: result.sessionRef,
8515
+ upo: { ...result.upo, parsed }
8516
+ };
8517
+ }
7861
8518
 
7862
8519
  // src/workflows/invoice-export-workflow.ts
7863
- async function exportInvoices(client, filters, options) {
8520
+ async function doExport(client, filters, options) {
7864
8521
  await client.crypto.init();
7865
8522
  const encData = client.crypto.getEncryptionData();
7866
8523
  const opResp = await client.invoices.exportInvoices({
@@ -7870,7 +8527,7 @@ async function exportInvoices(client, filters, options) {
7870
8527
  });
7871
8528
  const result = await pollUntil(
7872
8529
  () => client.invoices.getInvoiceExportStatus(opResp.referenceNumber),
7873
- (s) => s.status.code !== 100,
8530
+ (s) => s.status.code === 200 || s.status.code >= 400,
7874
8531
  { ...options?.pollOptions, description: `export ${opResp.referenceNumber}` }
7875
8532
  );
7876
8533
  if (result.status.code !== 200) {
@@ -7880,23 +8537,31 @@ async function exportInvoices(client, filters, options) {
7880
8537
  throw new Error("Export completed but no package available");
7881
8538
  }
7882
8539
  return {
7883
- parts: result.package.parts.map((p) => ({
7884
- ordinalNumber: p.ordinalNumber,
7885
- url: p.url,
7886
- method: p.method,
7887
- partSize: p.partSize,
7888
- encryptedPartSize: p.encryptedPartSize,
7889
- encryptedPartHash: p.encryptedPartHash,
7890
- expirationDate: p.expirationDate
7891
- })),
7892
- invoiceCount: result.package.invoiceCount,
7893
- isTruncated: result.package.isTruncated,
7894
- permanentStorageHwmDate: result.package.permanentStorageHwmDate
8540
+ encData,
8541
+ referenceNumber: opResp.referenceNumber,
8542
+ result: {
8543
+ parts: result.package.parts.map((p) => ({
8544
+ ordinalNumber: p.ordinalNumber,
8545
+ url: p.url,
8546
+ method: p.method,
8547
+ partSize: p.partSize,
8548
+ encryptedPartSize: p.encryptedPartSize,
8549
+ encryptedPartHash: p.encryptedPartHash,
8550
+ expirationDate: p.expirationDate
8551
+ })),
8552
+ invoiceCount: result.package.invoiceCount,
8553
+ isTruncated: result.package.isTruncated,
8554
+ permanentStorageHwmDate: result.package.permanentStorageHwmDate,
8555
+ lastPermanentStorageDate: result.package.lastPermanentStorageDate
8556
+ }
7895
8557
  };
7896
8558
  }
8559
+ async function exportInvoices(client, filters, options) {
8560
+ const { result } = await doExport(client, filters, options);
8561
+ return result;
8562
+ }
7897
8563
  async function exportAndDownload(client, filters, options) {
7898
- const encData = client.crypto.getEncryptionData();
7899
- const exportResult = await exportInvoices(client, filters, options);
8564
+ const { result: exportResult, encData } = await doExport(client, filters, options);
7900
8565
  const download = options?.transport ?? fetch;
7901
8566
  const decryptedParts = [];
7902
8567
  for (const part of exportResult.parts) {
@@ -7908,13 +8573,144 @@ async function exportAndDownload(client, filters, options) {
7908
8573
  const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
7909
8574
  decryptedParts.push(decrypted);
7910
8575
  }
8576
+ if (options?.extract) {
8577
+ const zipBuffer = Buffer.concat(decryptedParts);
8578
+ const files = await unzip(zipBuffer, options.unzipOptions);
8579
+ return { ...exportResult, files };
8580
+ }
7911
8581
  return {
7912
8582
  ...exportResult,
7913
8583
  decryptedParts
7914
8584
  };
7915
8585
  }
7916
8586
 
8587
+ // src/workflows/hwm-coordinator.ts
8588
+ function updateContinuationPoint(points, subjectType, pkg) {
8589
+ if (pkg.isTruncated && pkg.lastPermanentStorageDate) {
8590
+ points[subjectType] = pkg.lastPermanentStorageDate;
8591
+ } else if (pkg.permanentStorageHwmDate) {
8592
+ points[subjectType] = pkg.permanentStorageHwmDate;
8593
+ } else {
8594
+ delete points[subjectType];
8595
+ }
8596
+ }
8597
+ function getEffectiveStartDate(points, subjectType, windowFrom) {
8598
+ return points[subjectType] ?? windowFrom;
8599
+ }
8600
+ function deduplicateByKsefNumber(entries) {
8601
+ const seen = /* @__PURE__ */ new Set();
8602
+ return entries.filter((entry) => {
8603
+ const key = entry.ksefNumber.toLowerCase();
8604
+ if (seen.has(key)) return false;
8605
+ seen.add(key);
8606
+ return true;
8607
+ });
8608
+ }
8609
+
8610
+ // src/workflows/incremental-export-workflow.ts
8611
+ async function incrementalExportAndDownload(client, options) {
8612
+ const maxIterations = options.maxIterations ?? 20;
8613
+ const points = options.continuationPoints;
8614
+ if (options.store) {
8615
+ const loaded = await options.store.load();
8616
+ for (const [key, value] of Object.entries(loaded)) {
8617
+ if (value !== void 0 && points[key] === void 0) {
8618
+ points[key] = value;
8619
+ }
8620
+ }
8621
+ }
8622
+ const referenceNumbers = [];
8623
+ const decryptedParts = [];
8624
+ let previousFrom;
8625
+ let iteration = 0;
8626
+ for (; iteration < maxIterations; iteration++) {
8627
+ const effectiveFrom = getEffectiveStartDate(points, options.subjectType, options.windowFrom);
8628
+ if (previousFrom !== void 0 && effectiveFrom === previousFrom) {
8629
+ break;
8630
+ }
8631
+ previousFrom = effectiveFrom;
8632
+ const filters = options.filtersFactory ? options.filtersFactory(effectiveFrom, options.windowTo) : buildDefaultFilters(options.subjectType, effectiveFrom, options.windowTo);
8633
+ const { result, encData, referenceNumber } = await doExport(client, filters, {
8634
+ onlyMetadata: options.onlyMetadata,
8635
+ pollOptions: options.pollOptions
8636
+ });
8637
+ referenceNumbers.push(referenceNumber);
8638
+ const download = options.transport ?? fetch;
8639
+ for (const part of result.parts) {
8640
+ const resp = await download(part.url, { method: part.method });
8641
+ if (!resp.ok) {
8642
+ throw new Error(`Download failed for part ${part.ordinalNumber}: HTTP ${resp.status}`);
8643
+ }
8644
+ const encryptedData = new Uint8Array(await resp.arrayBuffer());
8645
+ const decrypted = client.crypto.decryptAES256(encryptedData, encData.cipherKey, encData.cipherIv);
8646
+ decryptedParts.push(decrypted);
8647
+ }
8648
+ updateContinuationPoint(points, options.subjectType, {
8649
+ isTruncated: result.isTruncated,
8650
+ lastPermanentStorageDate: result.lastPermanentStorageDate,
8651
+ permanentStorageHwmDate: result.permanentStorageHwmDate
8652
+ });
8653
+ if (options.store) {
8654
+ await options.store.save(points);
8655
+ }
8656
+ options.onIterationComplete?.(iteration, result);
8657
+ if (!result.isTruncated) {
8658
+ iteration++;
8659
+ break;
8660
+ }
8661
+ }
8662
+ return {
8663
+ referenceNumbers,
8664
+ invoices: [],
8665
+ decryptedParts,
8666
+ continuationPoints: points,
8667
+ iterationCount: iteration
8668
+ };
8669
+ }
8670
+ function buildDefaultFilters(subjectType, from, to) {
8671
+ return {
8672
+ subjectType,
8673
+ dateRange: {
8674
+ dateType: "PermanentStorage",
8675
+ from,
8676
+ to
8677
+ }
8678
+ };
8679
+ }
8680
+
8681
+ // src/workflows/hwm-storage.ts
8682
+ var fs = __toESM(require("fs/promises"), 1);
8683
+ var InMemoryHwmStore = class {
8684
+ points = {};
8685
+ async load() {
8686
+ return { ...this.points };
8687
+ }
8688
+ async save(points) {
8689
+ this.points = { ...points };
8690
+ }
8691
+ };
8692
+ var FileHwmStore = class {
8693
+ constructor(filePath) {
8694
+ this.filePath = filePath;
8695
+ }
8696
+ async load() {
8697
+ try {
8698
+ const data = await fs.readFile(this.filePath, "utf-8");
8699
+ return JSON.parse(data);
8700
+ } catch (err) {
8701
+ if (err.code === "ENOENT") {
8702
+ return {};
8703
+ }
8704
+ throw err;
8705
+ }
8706
+ }
8707
+ async save(points) {
8708
+ await fs.writeFile(this.filePath, JSON.stringify(points, null, 2), "utf-8");
8709
+ }
8710
+ };
8711
+
7917
8712
  // src/workflows/auth-workflow.ts
8713
+ init_auth_xml_builder();
7918
8714
  async function authenticateWithToken(client, options) {
7919
8715
  const challenge = await client.auth.getChallenge();
7920
8716
  await client.crypto.init();
@@ -7968,6 +8764,34 @@ async function authenticateWithCertificate(client, options) {
7968
8764
  refreshTokenValidUntil: tokens.refreshToken.validUntil
7969
8765
  };
7970
8766
  }
8767
+ async function authenticateWithExternalSignature(client, options) {
8768
+ const challenge = await client.auth.getChallenge();
8769
+ const unsignedXml = buildUnsignedAuthTokenRequestXml({
8770
+ challenge: challenge.challenge,
8771
+ contextIdentifier: options.contextIdentifier
8772
+ });
8773
+ const signedXml = await options.signXml(unsignedXml);
8774
+ const submitResult = await client.auth.submitXadesAuthRequest(
8775
+ signedXml,
8776
+ options.verifyCertificateChain ?? false,
8777
+ options.enforceXadesCompliance ?? false
8778
+ );
8779
+ const authToken = submitResult.authenticationToken.token;
8780
+ await pollUntil(
8781
+ () => client.auth.getAuthStatus(submitResult.referenceNumber, authToken),
8782
+ (s) => s.status.code !== 100,
8783
+ { ...options.pollOptions, description: `auth ${submitResult.referenceNumber}` }
8784
+ );
8785
+ const tokens = await client.auth.getAccessToken(authToken);
8786
+ client.authManager.setAccessToken(tokens.accessToken.token);
8787
+ client.authManager.setRefreshToken(tokens.refreshToken.token);
8788
+ return {
8789
+ accessToken: tokens.accessToken.token,
8790
+ accessTokenValidUntil: tokens.accessToken.validUntil,
8791
+ refreshToken: tokens.refreshToken.token,
8792
+ refreshTokenValidUntil: tokens.refreshToken.validUntil
8793
+ };
8794
+ }
7971
8795
  async function authenticateWithPkcs12(client, options) {
7972
8796
  const { Pkcs12Loader: Pkcs12Loader2 } = await Promise.resolve().then(() => (init_pkcs12_loader(), pkcs12_loader_exports));
7973
8797
  const { certificatePem, privateKeyPem } = Pkcs12Loader2.load(options.p12, options.password);
@@ -7990,7 +8814,11 @@ init_client();
7990
8814
  AuthService,
7991
8815
  AuthTokenRequestBuilder,
7992
8816
  AuthorizationPermissionGrantBuilder,
8817
+ BATCH_MAX_PARTS,
8818
+ BATCH_MAX_PART_SIZE,
8819
+ BATCH_MAX_TOTAL_SIZE,
7993
8820
  Base64String,
8821
+ BatchFileBuilder,
7994
8822
  BatchSessionService,
7995
8823
  CERTIFICATE_NAME_MAX_LENGTH,
7996
8824
  CERTIFICATE_NAME_MIN_LENGTH,
@@ -8004,6 +8832,11 @@ init_client();
8004
8832
  ENFORCE_XADES_COMPLIANCE,
8005
8833
  EntityPermissionGrantBuilder,
8006
8834
  Environment,
8835
+ FORM_CODES,
8836
+ FORM_CODE_KEYS,
8837
+ FileHwmStore,
8838
+ INVOICE_TYPES_BY_SYSTEM_CODE,
8839
+ InMemoryHwmStore,
8007
8840
  InternalId,
8008
8841
  InvoiceDownloadService,
8009
8842
  InvoiceQueryFilterBuilder,
@@ -8049,21 +8882,29 @@ init_client();
8049
8882
  SessionStatusService,
8050
8883
  Sha256Base64,
8051
8884
  SignatureService,
8885
+ SystemCode,
8052
8886
  TestDataService,
8053
8887
  TokenService,
8054
8888
  UpoVersion,
8055
8889
  VatUe,
8056
8890
  VerificationLinkService,
8057
8891
  authenticateWithCertificate,
8892
+ authenticateWithExternalSignature,
8058
8893
  authenticateWithPkcs12,
8059
8894
  authenticateWithToken,
8895
+ buildUnsignedAuthTokenRequestXml,
8060
8896
  calculateBackoff,
8897
+ createZip,
8898
+ deduplicateByKsefNumber,
8061
8899
  defaultPresignedUrlPolicy,
8062
8900
  defaultRateLimitPolicy,
8063
8901
  defaultRetryPolicy,
8064
8902
  defaultTransport,
8065
8903
  exportAndDownload,
8066
8904
  exportInvoices,
8905
+ getEffectiveStartDate,
8906
+ getFormCode,
8907
+ incrementalExportAndDownload,
8067
8908
  isRetryableError,
8068
8909
  isRetryableStatus,
8069
8910
  isValidBase64,
@@ -8083,11 +8924,19 @@ init_client();
8083
8924
  isValidVatUe,
8084
8925
  openOnlineSession,
8085
8926
  openSendAndClose,
8927
+ parseFormCode,
8086
8928
  parseRetryAfter,
8929
+ parseUpoXml,
8087
8930
  pollUntil,
8088
8931
  resolveOptions,
8089
8932
  sleep,
8933
+ unzip,
8934
+ updateContinuationPoint,
8090
8935
  uploadBatch,
8936
+ uploadBatchParsed,
8937
+ uploadBatchStream,
8938
+ uploadBatchStreamParsed,
8939
+ validateFormCodeForSession,
8091
8940
  validatePresignedUrl
8092
8941
  });
8093
8942
  //# sourceMappingURL=index.cjs.map