cosmemilton-acbr-node 0.1.2 → 0.2.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.
Files changed (66) hide show
  1. package/LICENSE +502 -502
  2. package/NOTICE +8 -8
  3. package/README.md +40 -11
  4. package/acbr.config.json +16 -16
  5. package/acbr.lock.json +0 -0
  6. package/dist/cli.js +375 -176
  7. package/dist/cli.js.map +4 -4
  8. package/dist/contract.json +0 -0
  9. package/dist/index.cjs +36 -11
  10. package/dist/index.cjs.map +2 -2
  11. package/dist/index.js +36 -11
  12. package/dist/index.js.map +2 -2
  13. package/dist/runtime.cjs +36 -11
  14. package/dist/runtime.cjs.map +2 -2
  15. package/dist/runtime.js +36 -11
  16. package/dist/runtime.js.map +2 -2
  17. package/dist/types/generated/acbr/index.d.ts +1 -0
  18. package/dist/types/generated/acbr/models.d.ts +0 -0
  19. package/dist/types/src/cli.d.ts +0 -0
  20. package/dist/types/src/config.d.ts +0 -0
  21. package/dist/types/src/contract-help.d.ts +0 -0
  22. package/dist/types/src/diagnostics.d.ts +2 -0
  23. package/dist/types/src/generator.d.ts +0 -0
  24. package/dist/types/src/index.d.ts +1 -0
  25. package/dist/types/src/native-build.d.ts +1 -0
  26. package/dist/types/src/offline-check.d.ts +0 -0
  27. package/dist/types/src/offline-fixture.d.ts +0 -0
  28. package/dist/types/src/runtime.d.ts +1 -0
  29. package/dist/types/src/source.d.ts +0 -0
  30. package/dist/types/src/types.d.ts +4 -2
  31. package/docs/API.md +116 -90
  32. package/docs/ARQUITETURA.md +19 -15
  33. package/docs/CI.md +60 -60
  34. package/docs/CLI.md +1 -1
  35. package/docs/DEPENDENCIAS-NATIVAS.md +103 -93
  36. package/docs/VALIDACAO.md +67 -67
  37. package/docs/examples/recuperar-xml.mjs +54 -0
  38. package/docs/licenses/common/Apache-2.0.txt +202 -0
  39. package/docs/licenses/common/Artistic.txt +131 -0
  40. package/docs/licenses/common/GFDL-1.2.txt +397 -0
  41. package/docs/licenses/common/GPL-1.txt +251 -0
  42. package/docs/licenses/common/GPL-2.txt +339 -0
  43. package/docs/licenses/common/GPL-3.txt +674 -0
  44. package/docs/licenses/common/GPL.txt +674 -0
  45. package/docs/licenses/common/LGPL-2.1.txt +502 -0
  46. package/docs/licenses/common/LGPL-2.txt +481 -0
  47. package/docs/licenses/common/LGPL-3.txt +165 -0
  48. package/docs/licenses/common/LGPL.txt +165 -0
  49. package/docs/licenses/common/ORIGIN.json +208 -0
  50. package/docs/licenses/fpc/COPYING.FPC +25 -25
  51. package/docs/licenses/fpc/COPYING.GPL.txt +340 -340
  52. package/docs/licenses/fpc/COPYING.LGPL.txt +504 -504
  53. package/docs/licenses/fpc/ORIGIN.json +21 -21
  54. package/docs/licenses/lazarus/COPYING.LGPL.txt +481 -481
  55. package/docs/licenses/lazarus/COPYING.modifiedLGPL.txt +26 -26
  56. package/docs/licenses/lazarus/COPYING.txt +46 -46
  57. package/docs/licenses/lazarus/ORIGIN.json +1 -1
  58. package/native/NativeMotor.pas +55 -3
  59. package/native/NativeProtocol.pas +3 -2
  60. package/native/NativeRecovery.pas +274 -0
  61. package/native/generated/AcbrModels.pas +0 -0
  62. package/package.json +6 -4
  63. package/scripts/build-native-deps.mjs +237 -237
  64. package/scripts/runtime-license-inventory.d.mts +5 -0
  65. package/scripts/runtime-license-inventory.mjs +161 -0
  66. package/tools/extract-model.lpr +119 -119
package/dist/cli.js CHANGED
@@ -82,8 +82,8 @@ function parseConfig(input, configPath) {
82
82
  }
83
83
  };
84
84
  }
85
- async function loadConfig(path4 = "acbr.config.json") {
86
- const configPath = resolve(path4);
85
+ async function loadConfig(path5 = "acbr.config.json") {
86
+ const configPath = resolve(path5);
87
87
  let contents;
88
88
  try {
89
89
  contents = await readFile2(configPath, "utf8");
@@ -98,8 +98,8 @@ async function loadConfig(path4 = "acbr.config.json") {
98
98
  }
99
99
  return parseConfig(value, configPath);
100
100
  }
101
- async function initializeConfig(path4 = "acbr.config.json", revision2 = "HEAD", assetRoot) {
102
- const configPath = resolve(path4);
101
+ async function initializeConfig(path5 = "acbr.config.json", revision2 = "HEAD", assetRoot) {
102
+ const configPath = resolve(path5);
103
103
  const config = defaultConfig();
104
104
  config.source.revision = revision2;
105
105
  parseConfig(config, configPath);
@@ -182,7 +182,7 @@ import { createReadStream } from "node:fs";
182
182
  import { access as access2, mkdir as mkdir2, readdir as readdir2, readFile as readFile3, rename, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
183
183
  import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "node:path";
184
184
  async function runCommand(command, args, options = {}) {
185
- return new Promise((done, fail3) => {
185
+ return new Promise((done, fail4) => {
186
186
  const child = spawn(command, args, { cwd: options.cwd, env: options.env ?? process.env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, shell: false });
187
187
  let stdout = "";
188
188
  let stderr = "";
@@ -199,20 +199,20 @@ async function runCommand(command, args, options = {}) {
199
199
  };
200
200
  child.stdout.on("data", (data) => append("stdout", data));
201
201
  child.stderr.on("data", (data) => append("stderr", data));
202
- child.on("error", (error) => fail3(new Error(`N\xE3o foi poss\xEDvel executar ${command}: ${error.message}`, { cause: error })));
202
+ child.on("error", (error) => fail4(new Error(`N\xE3o foi poss\xEDvel executar ${command}: ${error.message}`, { cause: error })));
203
203
  child.on("close", (code) => {
204
- if (overflow) fail3(new Error(`Sa\xEDda de ${command} excedeu o limite de ${maximum} bytes.`));
204
+ if (overflow) fail4(new Error(`Sa\xEDda de ${command} excedeu o limite de ${maximum} bytes.`));
205
205
  else if (code !== 0) {
206
206
  const diagnostic = (stderr || stdout).split("\n").slice(-80).join("\n").slice(-16e3);
207
- fail3(Object.assign(new Error(`${command} terminou com c\xF3digo ${code}:
207
+ fail4(Object.assign(new Error(`${command} terminou com c\xF3digo ${code}:
208
208
  ${diagnostic}`), { stdout, stderr }));
209
209
  } else done({ stdout, stderr });
210
210
  });
211
211
  });
212
212
  }
213
- async function fileHash(path4) {
213
+ async function fileHash(path5) {
214
214
  const hash2 = createHash2("sha256");
215
- for await (const chunk of createReadStream(path4)) hash2.update(chunk);
215
+ for await (const chunk of createReadStream(path5)) hash2.update(chunk);
216
216
  return hash2.digest("hex");
217
217
  }
218
218
  async function snapshotSource(directory) {
@@ -221,11 +221,11 @@ async function snapshotSource(directory) {
221
221
  const entries = (await readdir2(current, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name, "en"));
222
222
  for (const entry of entries) {
223
223
  if (entry.name === ".svn") continue;
224
- const path4 = join(current, entry.name);
225
- if (entry.isSymbolicLink()) throw new Error(`Fonte ACBr cont\xE9m link simb\xF3lico: ${path4}.`);
226
- if (entry.isDirectory()) await scan(path4);
227
- else if (entry.isFile()) files[relative(directory, path4).split(sep).join("/")] = await fileHash(path4);
228
- else throw new Error(`Fonte ACBr cont\xE9m arquivo especial: ${path4}.`);
224
+ const path5 = join(current, entry.name);
225
+ if (entry.isSymbolicLink()) throw new Error(`Fonte ACBr cont\xE9m link simb\xF3lico: ${path5}.`);
226
+ if (entry.isDirectory()) await scan(path5);
227
+ else if (entry.isFile()) files[relative(directory, path5).split(sep).join("/")] = await fileHash(path5);
228
+ else throw new Error(`Fonte ACBr cont\xE9m arquivo especial: ${path5}.`);
229
229
  }
230
230
  }
231
231
  await scan(resolve2(directory));
@@ -237,8 +237,8 @@ function validateLock(value) {
237
237
  if (!value || typeof value !== "object") throw new Error("Lock ACBr inv\xE1lido.");
238
238
  const lock = value;
239
239
  if (lock.formatVersion !== 1 || !lock.source || !Number.isSafeInteger(lock.source.revision) || lock.source.revision < 1 || !Array.isArray(lock.source.parts) || !lock.source.files || typeof lock.source.files !== "object" || Array.isArray(lock.source.files) || !/^[a-f0-9]{64}$/.test(lock.source.treeHash)) throw new Error("Formato inv\xE1lido em acbr.lock.json.");
240
- for (const [path4, hash2] of Object.entries(lock.source.files)) {
241
- if (path4.startsWith("/") || path4.includes("\\") || path4.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(hash2)) throw new Error("Caminho ou hash inv\xE1lido no lock ACBr.");
240
+ for (const [path5, hash2] of Object.entries(lock.source.files)) {
241
+ if (path5.startsWith("/") || path5.includes("\\") || path5.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(hash2)) throw new Error("Caminho ou hash inv\xE1lido no lock ACBr.");
242
242
  }
243
243
  if (lock.source.parts.join("\n") !== SOURCE_PARTS.join("\n")) throw new Error("Partes ACBr divergentes no lock.");
244
244
  return lock;
@@ -268,7 +268,7 @@ async function verifySourceContents(config) {
268
268
  const snapshot = await snapshotSource(config.source.directory);
269
269
  if (snapshot.treeHash !== lock.source.treeHash) {
270
270
  const names = /* @__PURE__ */ new Set([...Object.keys(snapshot.files), ...Object.keys(lock.source.files)]);
271
- const changed = [...names].filter((path4) => snapshot.files[path4] !== lock.source.files[path4]);
271
+ const changed = [...names].filter((path5) => snapshot.files[path5] !== lock.source.files[path5]);
272
272
  throw new Error(`Fontes ACBr divergem do lock (${changed.length} arquivo(s)): ${changed.slice(0, 10).join(", ")}. Preserve as altera\xE7\xF5es antes de atualizar.`);
273
273
  }
274
274
  return lock;
@@ -396,6 +396,175 @@ var init_source = __esm({
396
396
  }
397
397
  });
398
398
 
399
+ // scripts/runtime-license-inventory.mjs
400
+ import { createHash as createHash3 } from "node:crypto";
401
+ import { lstat, mkdir as mkdir3, readFile as readFile4, readdir as readdir3, writeFile as writeFile3 } from "node:fs/promises";
402
+ import path2 from "node:path";
403
+ import { fileURLToPath } from "node:url";
404
+ async function regularFile(root, name) {
405
+ if (!name || path2.posix.isAbsolute(name) || name.includes("\\") || name.split("/").some((p) => !p || p === "." || p === "..")) fail2("caminho inv\xE1lido.");
406
+ const parts = name.split("/");
407
+ let file = root;
408
+ for (let i = 0; i < parts.length; i++) {
409
+ file = path2.join(file, parts[i]);
410
+ const info = await lstat(file);
411
+ if (info.isSymbolicLink() || (i < parts.length - 1 ? !info.isDirectory() : !info.isFile())) fail2("arquivo n\xE3o regular: " + name);
412
+ if (i === parts.length - 1 && info.size > MAX_TEXT_BYTES) fail2("texto excede o limite: " + name);
413
+ }
414
+ return readFile4(file);
415
+ }
416
+ function references(bytes, notice) {
417
+ const names = /* @__PURE__ */ new Set();
418
+ for (const match of bytes.toString("utf8").matchAll(/\/usr\/share\/common-licenses\/([^\s"'<>`\u2018\u2019\u201c\u201d]+)/g)) {
419
+ const name = match[1].replace(/[.,;:)\]}]+$/, "");
420
+ if (!NAME.test(name)) fail2("refer\xEAncia common-licenses inv\xE1lida em " + notice);
421
+ names.add(name);
422
+ }
423
+ return [...names].sort();
424
+ }
425
+ async function policyAt(directory) {
426
+ const raw = await regularFile(directory, "ORIGIN.json");
427
+ let policy;
428
+ try {
429
+ policy = JSON.parse(raw.toString("utf8"));
430
+ } catch {
431
+ fail2("ORIGIN.json inv\xE1lido.");
432
+ }
433
+ if (policy.formatVersion !== 1 || !object(policy.files) || !Object.hasOwn(policy.files, "Apache-2.0")) fail2("pol\xEDtica can\xF4nica incompleta.");
434
+ const files = /* @__PURE__ */ new Map();
435
+ for (const name of Object.keys(policy.files).sort()) {
436
+ const entry = policy.files[name];
437
+ if (!NAME.test(name) || !object(entry) || entry.file !== name + ".txt" || !HASH.test(entry.sha256) || !Number.isSafeInteger(entry.bytes) || entry.bytes <= 0 || entry.bytes > MAX_TEXT_BYTES) fail2("registro can\xF4nico inv\xE1lido: " + name);
438
+ const bytes = await regularFile(directory, entry.file);
439
+ if (bytes.length !== entry.bytes || digest(bytes) !== entry.sha256) fail2("texto can\xF4nico diverge da origem aprovada: " + name);
440
+ files.set(name, { entry, bytes });
441
+ }
442
+ return { sha256: digest(raw), files };
443
+ }
444
+ async function noticesAt(runtime) {
445
+ const notices = [];
446
+ async function visit(prefix) {
447
+ for (const entry of (await readdir3(path2.join(runtime, prefix), { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
448
+ const name = prefix + "/" + entry.name;
449
+ if (entry.isSymbolicLink()) fail2("link em avisos: " + name);
450
+ if (entry.isDirectory()) {
451
+ if (name !== "licenses/common") await visit(name);
452
+ } else if (entry.isFile()) notices.push({ name, bytes: await regularFile(runtime, name) });
453
+ else fail2("aviso n\xE3o regular: " + name);
454
+ }
455
+ }
456
+ await visit("licenses");
457
+ return notices;
458
+ }
459
+ async function expectedInventory(runtime, policyDirectory) {
460
+ const policy = await policyAt(policyDirectory);
461
+ const notices = await noticesAt(runtime);
462
+ const required = /* @__PURE__ */ new Map([["Apache-2.0", /* @__PURE__ */ new Set(["policy:OpenSSL"])]]);
463
+ const add = (name, source) => {
464
+ if (!policy.files.has(name)) fail2("refer\xEAncia common-licenses n\xE3o aprovada: " + name);
465
+ if (!required.has(name)) required.set(name, /* @__PURE__ */ new Set());
466
+ required.get(name).add(source);
467
+ };
468
+ for (const notice of notices) for (const name of references(notice.bytes, notice.name)) add(name, notice.name);
469
+ const scanned = /* @__PURE__ */ new Set();
470
+ while (scanned.size < required.size) {
471
+ const name = [...required.keys()].find((name2) => !scanned.has(name2));
472
+ scanned.add(name);
473
+ const aliasOf = policy.files.get(name).entry.aliasOf;
474
+ if (aliasOf !== void 0) {
475
+ if (typeof aliasOf !== "string") fail2("alias can\xF4nico inv\xE1lido: " + name);
476
+ add(aliasOf, COMMON + name + ".txt");
477
+ if (policy.files.get(aliasOf).entry.sha256 !== policy.files.get(name).entry.sha256) fail2("alias diverge do texto can\xF4nico: " + name);
478
+ }
479
+ for (const referenced of references(policy.files.get(name).bytes, COMMON + name + ".txt")) add(referenced, COMMON + name + ".txt");
480
+ }
481
+ const files = {};
482
+ for (const name of [...required.keys()].sort()) {
483
+ const { entry } = policy.files.get(name);
484
+ files[name] = { file: COMMON + entry.file, sha256: entry.sha256, bytes: entry.bytes, requiredBy: [...required.get(name)].sort(), origin: entry };
485
+ }
486
+ return { inventory: { formatVersion: 1, policySha256: policy.sha256, files }, policy, notices };
487
+ }
488
+ async function writeExact(file, bytes) {
489
+ try {
490
+ await writeFile3(file, bytes, { flag: "wx" });
491
+ } catch (error) {
492
+ if (error.code !== "EEXIST") throw error;
493
+ const info = await lstat(file);
494
+ if (!info.isFile() || info.isSymbolicLink() || !(await readFile4(file)).equals(bytes)) fail2("recusa substituir material existente divergente.");
495
+ }
496
+ }
497
+ async function completeRuntimeLicenses(runtime, { policyDirectory = defaultPolicy } = {}) {
498
+ const { inventory, policy } = await expectedInventory(runtime, policyDirectory);
499
+ const directory = path2.join(runtime, "licenses/common");
500
+ try {
501
+ if (!(await lstat(directory)).isDirectory() || (await lstat(directory)).isSymbolicLink()) fail2("diret\xF3rio common n\xE3o regular.");
502
+ } catch (error) {
503
+ if (error.code !== "ENOENT") throw error;
504
+ await mkdir3(directory);
505
+ }
506
+ for (const [name, entry] of Object.entries(inventory.files)) await writeExact(path2.join(runtime, entry.file), policy.files.get(name).bytes);
507
+ await writeExact(path2.join(runtime, INVENTORY), Buffer.from(JSON.stringify(inventory, null, 2) + "\n"));
508
+ return inventory;
509
+ }
510
+ async function auditRuntimeLicenses(runtime, manifest, { policyDirectory = defaultPolicy } = {}) {
511
+ const { inventory, notices } = await expectedInventory(runtime, policyDirectory);
512
+ if (!object(manifest?.files)) fail2("manifesto sem invent\xE1rio.");
513
+ const dependencyFiles = [];
514
+ if (manifest.platform === "linux") {
515
+ const source = "sources/native-dependencies.json";
516
+ let dependencies;
517
+ try {
518
+ dependencies = JSON.parse((await regularFile(runtime, source)).toString("utf8"));
519
+ } catch {
520
+ fail2("proveni\xEAncia Linux ausente ou inv\xE1lida.");
521
+ }
522
+ if (!object(dependencies) || Object.keys(dependencies).length === 0) fail2("proveni\xEAncia Linux sem depend\xEAncias.");
523
+ dependencyFiles.push(source);
524
+ for (const dependency of Object.values(dependencies)) {
525
+ const name = dependency?.copyright;
526
+ if (typeof name !== "string" || !name.startsWith("licenses/") || name.startsWith(COMMON)) fail2("aviso de depend\xEAncia Linux ausente da proveni\xEAncia.");
527
+ dependencyFiles.push(name);
528
+ }
529
+ }
530
+ let actual;
531
+ try {
532
+ actual = JSON.parse((await regularFile(runtime, INVENTORY)).toString("utf8"));
533
+ } catch {
534
+ fail2("invent\xE1rio common-licenses ausente ou inv\xE1lido.");
535
+ }
536
+ if (JSON.stringify(actual) !== JSON.stringify(inventory)) fail2("invent\xE1rio common-licenses diverge da pol\xEDtica e dos avisos.");
537
+ const expectedFiles = [INVENTORY, ...Object.values(inventory.files).map((entry) => entry.file)].sort();
538
+ const commonFiles = (await readdir3(path2.join(runtime, "licenses/common"))).map((name) => COMMON + name).sort();
539
+ if (JSON.stringify(commonFiles) !== JSON.stringify(expectedFiles)) fail2("invent\xE1rio common-licenses incompleto ou com arquivos extras.");
540
+ for (const name of [...notices.map((notice) => notice.name), ...dependencyFiles, ...expectedFiles]) {
541
+ const bytes = await regularFile(runtime, name);
542
+ if (!Object.hasOwn(manifest.files, name) || manifest.files[name] !== digest(bytes)) fail2("material de licen\xE7a ausente do manifesto ou hash divergente: " + name);
543
+ }
544
+ for (const entry of Object.values(inventory.files)) {
545
+ const bytes = await regularFile(runtime, entry.file);
546
+ if (bytes.length !== entry.bytes || digest(bytes) !== entry.sha256) fail2("texto integral diverge da origem aprovada: " + entry.file);
547
+ }
548
+ return inventory;
549
+ }
550
+ var HASH, NAME, MAX_TEXT_BYTES, COMMON, INVENTORY, defaultPolicy, digest, fail2, object;
551
+ var init_runtime_license_inventory = __esm({
552
+ "scripts/runtime-license-inventory.mjs"() {
553
+ "use strict";
554
+ HASH = /^[a-f0-9]{64}$/;
555
+ NAME = /^[A-Za-z0-9][A-Za-z0-9.+_-]*$/;
556
+ MAX_TEXT_BYTES = 4 * 1024 * 1024;
557
+ COMMON = "licenses/common/";
558
+ INVENTORY = COMMON + "INVENTORY.json";
559
+ defaultPolicy = fileURLToPath(new URL("../docs/licenses/common/", import.meta.url));
560
+ digest = (bytes) => createHash3("sha256").update(bytes).digest("hex");
561
+ fail2 = (message) => {
562
+ throw Error("Licen\xE7as do runtime: " + message);
563
+ };
564
+ object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
565
+ }
566
+ });
567
+
399
568
  // src/native-build.ts
400
569
  var native_build_exports = {};
401
570
  __export(native_build_exports, {
@@ -405,31 +574,31 @@ __export(native_build_exports, {
405
574
  findLazarus: () => findLazarus,
406
575
  runtimeDirectory: () => runtimeDirectory
407
576
  });
408
- import { copyFile as copyFile2, mkdir as mkdir3, readdir as readdir3, readFile as readFile4, rename as rename2, rm as rm2, stat as stat2, chmod, realpath, access as access3, writeFile as writeFile3 } from "node:fs/promises";
577
+ import { copyFile as copyFile2, mkdir as mkdir4, readdir as readdir4, readFile as readFile5, rename as rename2, rm as rm2, stat as stat2, chmod, realpath, access as access3, writeFile as writeFile4 } from "node:fs/promises";
409
578
  import { basename, dirname as dirname3, join as join2, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
410
579
  import { randomUUID as randomUUID2 } from "node:crypto";
411
- import { fileURLToPath } from "node:url";
580
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
412
581
  function runtimeDirectory(config) {
413
582
  return join2(config.native.outputDir, `${process.platform}-${process.arch}`);
414
583
  }
415
- async function exists(path4) {
584
+ async function exists(path5) {
416
585
  try {
417
- await access3(path4);
586
+ await access3(path5);
418
587
  return true;
419
588
  } catch {
420
589
  return false;
421
590
  }
422
591
  }
423
592
  async function findLazarus(config) {
424
- const candidates = config.native.lazarusRoot ? [config.native.lazarusRoot] : [process.env.LAZARUS_ROOT, "/usr/lib/lazarus/default", "/usr/lib/lazarus/3.0", "C:\\lazarus"].filter((path4) => Boolean(path4));
593
+ const candidates = config.native.lazarusRoot ? [config.native.lazarusRoot] : [process.env.LAZARUS_ROOT, "/usr/lib/lazarus/default", "/usr/lib/lazarus/3.0", "C:\\lazarus"].filter((path5) => Boolean(path5));
425
594
  for (const candidate of candidates) if (await exists(join2(candidate, "components/lazutils"))) return realpath(candidate);
426
595
  throw new Error("Lazarus n\xE3o encontrado. Defina native.lazarusRoot em acbr.config.json ou LAZARUS_ROOT.");
427
596
  }
428
597
  async function generatedManifest(config) {
429
- const path4 = join2(config.generator.outputDir, ".acbr/generated/manifest.json");
598
+ const path5 = join2(config.generator.outputDir, ".acbr/generated/manifest.json");
430
599
  let value;
431
600
  try {
432
- value = JSON.parse(await readFile4(path4, "utf8"));
601
+ value = JSON.parse(await readFile5(path5, "utf8"));
433
602
  } catch (error) {
434
603
  throw new Error("Contrato gerado ausente ou inv\xE1lido. Execute acbr-node generate.", { cause: error });
435
604
  }
@@ -443,10 +612,10 @@ async function generatedManifest(config) {
443
612
  }
444
613
  return value;
445
614
  }
446
- async function subdirectories(path4) {
447
- const result = [path4];
448
- for (const entry of (await readdir3(path4, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
449
- if (entry.isDirectory()) result.push(...await subdirectories(join2(path4, entry.name)));
615
+ async function subdirectories(path5) {
616
+ const result = [path5];
617
+ for (const entry of (await readdir4(path5, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
618
+ if (entry.isDirectory()) result.push(...await subdirectories(join2(path5, entry.name)));
450
619
  }
451
620
  return result;
452
621
  }
@@ -455,9 +624,9 @@ async function copyLinuxLibraries(stage) {
455
624
  const libraries = /* @__PURE__ */ new Map();
456
625
  for (const name of REQUIRED_DYNAMIC) {
457
626
  const line = stdout.split("\n").find((value) => value.trim().startsWith(`${name} `) && value.includes("x86-64"));
458
- const path4 = line?.split("=>")[1]?.trim();
459
- if (!path4) throw new Error(`Depend\xEAncia din\xE2mica ausente: ${name}. Instale OpenSSL 3 e libxml2 compat\xEDveis.`);
460
- libraries.set(name, await realpath(path4));
627
+ const path5 = line?.split("=>")[1]?.trim();
628
+ if (!path5) throw new Error(`Depend\xEAncia din\xE2mica ausente: ${name}. Instale OpenSSL 3 e libxml2 compat\xEDveis.`);
629
+ libraries.set(name, await realpath(path5));
461
630
  }
462
631
  const modules = "/usr/lib/x86_64-linux-gnu/ossl-modules";
463
632
  if (!await exists(join2(modules, "legacy.so"))) throw new Error("Provider legacy OpenSSL 3 ausente. Instale o pacote libssl3/libssl3t64 completo.");
@@ -465,9 +634,9 @@ async function copyLinuxLibraries(stage) {
465
634
  const systemDependencies = /* @__PURE__ */ new Set();
466
635
  const inspected = /* @__PURE__ */ new Set();
467
636
  while (inspected.size < libraries.size) {
468
- const [name, path4] = [...libraries].find(([name2]) => !inspected.has(name2));
637
+ const [name, path5] = [...libraries].find(([name2]) => !inspected.has(name2));
469
638
  inspected.add(name);
470
- const dependencies = await runCommand("ldd", [path4]);
639
+ const dependencies = await runCommand("ldd", [path5]);
471
640
  for (const line of dependencies.stdout.split("\n")) {
472
641
  if (line.includes("not found")) throw new Error(`Depend\xEAncia transitiva ausente: ${line.trim()}.`);
473
642
  const match = /^\s*(\S+)\s+=>\s+(\S+)/.exec(line);
@@ -483,19 +652,19 @@ async function copyLinuxLibraries(stage) {
483
652
  }
484
653
  }
485
654
  const licenseDir = join2(stage, "licenses");
486
- await mkdir3(licenseDir, { recursive: true });
655
+ await mkdir4(licenseDir, { recursive: true });
487
656
  const provenance = {};
488
- for (const [name, path4] of libraries) {
657
+ for (const [name, path5] of libraries) {
489
658
  const destination = name.startsWith("ossl-modules/") ? join2(stage, name) : join2(stage, "lib", name);
490
- await mkdir3(dirname3(destination), { recursive: true });
491
- await copyFile2(path4, destination);
659
+ await mkdir4(dirname3(destination), { recursive: true });
660
+ await copyFile2(path5, destination);
492
661
  const aliases = name === "libssl.so.3" ? ["libssl.so"] : name === "libcrypto.so.3" ? ["libcrypto.so"] : name === "libxml2.so.2" ? ["libxml2.so"] : [];
493
- for (const alias of aliases) await copyFile2(path4, join2(stage, "lib", alias));
662
+ for (const alias of aliases) await copyFile2(path5, join2(stage, "lib", alias));
494
663
  let owner;
495
664
  try {
496
- owner = (await runCommand("dpkg-query", ["-S", path4])).stdout.split("\n")[0].split(": ")[0];
665
+ owner = (await runCommand("dpkg-query", ["-S", path5])).stdout.split("\n")[0].split(": ")[0];
497
666
  } catch (error) {
498
- throw new Error(`N\xE3o foi poss\xEDvel identificar pacote/licen\xE7a de ${path4}. Build requer Debian/Ubuntu com depend\xEAncias registradas pelo dpkg.`, { cause: error });
667
+ throw new Error(`N\xE3o foi poss\xEDvel identificar pacote/licen\xE7a de ${path5}. Build requer Debian/Ubuntu com depend\xEAncias registradas pelo dpkg.`, { cause: error });
499
668
  }
500
669
  const pkg = owner.split(":")[0];
501
670
  const copyright = `/usr/share/doc/${pkg}/copyright`;
@@ -511,40 +680,40 @@ async function copyLinuxLibraries(stage) {
511
680
  copyright: `licenses/${name.replaceAll("/", "-")}.txt`
512
681
  };
513
682
  }
514
- await mkdir3(join2(stage, "sources"), { recursive: true });
515
- await writeFile3(join2(stage, "sources/native-dependencies.json"), `${JSON.stringify(provenance, null, 2)}
683
+ await mkdir4(join2(stage, "sources"), { recursive: true });
684
+ await writeFile4(join2(stage, "sources/native-dependencies.json"), `${JSON.stringify(provenance, null, 2)}
516
685
  `);
517
- await writeFile3(join2(stage, "openssl.cnf"), "openssl_conf = openssl_init\n[openssl_init]\nproviders = provider_sect\n[provider_sect]\ndefault = default_sect\nlegacy = legacy_sect\n[default_sect]\nactivate = 1\n[legacy_sect]\nactivate = 1\n");
686
+ await writeFile4(join2(stage, "openssl.cnf"), "openssl_conf = openssl_init\n[openssl_init]\nproviders = provider_sect\n[provider_sect]\ndefault = default_sect\nlegacy = legacy_sect\n[default_sect]\nactivate = 1\n[legacy_sect]\nactivate = 1\n");
518
687
  return [...systemDependencies].sort();
519
688
  }
520
689
  async function copyExplicitLibraries(config, stage) {
521
690
  if (!config.native.libraryFiles?.length) throw new Error("Windows exige native.libraryFiles com DLLs OpenSSL 3/libxml2 e arquivos .LICENSE adjacentes.");
522
- await mkdir3(join2(stage, "lib"), { recursive: true });
523
- await mkdir3(join2(stage, "licenses"), { recursive: true });
691
+ await mkdir4(join2(stage, "lib"), { recursive: true });
692
+ await mkdir4(join2(stage, "licenses"), { recursive: true });
524
693
  const sources = {};
525
694
  const dependencyDirectories = new Set([...config.native.libraryFiles ?? [], ...config.native.providerFiles ?? []].map(dirname3));
526
695
  for (const directory of dependencyDirectories) {
527
- for (const entry of await readdir3(directory)) {
696
+ for (const entry of await readdir4(directory)) {
528
697
  if (entry.endsWith(".LICENSE")) await copyFile2(join2(directory, entry), join2(stage, "licenses", entry));
529
698
  else if (entry === "SOURCE.json") {
530
- await mkdir3(join2(stage, "sources"), { recursive: true });
699
+ await mkdir4(join2(stage, "sources"), { recursive: true });
531
700
  await copyFile2(join2(directory, entry), join2(stage, "sources", `${basename(directory)}-SOURCE.json`));
532
701
  }
533
702
  }
534
703
  }
535
704
  for (const [directory, files] of [["lib", config.native.libraryFiles], ["ossl-modules", config.native.providerFiles ?? []]]) {
536
- await mkdir3(join2(stage, directory), { recursive: true });
705
+ await mkdir4(join2(stage, directory), { recursive: true });
537
706
  for (const source of files) {
538
707
  await copyFile2(source, join2(stage, directory, basename(source)));
539
708
  await copyFile2(`${source}.LICENSE`, join2(stage, "licenses", `${basename(source)}.txt`));
540
- if (await exists(`${source}.SOURCE.json`)) sources[`${directory}/${basename(source)}`] = JSON.parse(await readFile4(`${source}.SOURCE.json`, "utf8"));
709
+ if (await exists(`${source}.SOURCE.json`)) sources[`${directory}/${basename(source)}`] = JSON.parse(await readFile5(`${source}.SOURCE.json`, "utf8"));
541
710
  }
542
711
  }
543
- if (!config.native.providerFiles?.some((path4) => basename(path4).toLowerCase() === "legacy.dll")) throw new Error("Windows requer native.providerFiles com o provider legacy.dll de OpenSSL 3 e licen\xE7a adjacente.");
544
- await mkdir3(join2(stage, "sources"), { recursive: true });
545
- await writeFile3(join2(stage, "sources/native-dependencies.json"), `${JSON.stringify(sources, null, 2)}
712
+ if (!config.native.providerFiles?.some((path5) => basename(path5).toLowerCase() === "legacy.dll")) throw new Error("Windows requer native.providerFiles com o provider legacy.dll de OpenSSL 3 e licen\xE7a adjacente.");
713
+ await mkdir4(join2(stage, "sources"), { recursive: true });
714
+ await writeFile4(join2(stage, "sources/native-dependencies.json"), `${JSON.stringify(sources, null, 2)}
546
715
  `);
547
- await writeFile3(join2(stage, "openssl.cnf"), "openssl_conf = openssl_init\n[openssl_init]\nproviders = provider_sect\n[provider_sect]\ndefault = default_sect\nlegacy = legacy_sect\n[default_sect]\nactivate = 1\n[legacy_sect]\nactivate = 1\n");
716
+ await writeFile4(join2(stage, "openssl.cnf"), "openssl_conf = openssl_init\n[openssl_init]\nproviders = provider_sect\n[provider_sect]\ndefault = default_sect\nlegacy = legacy_sect\n[default_sect]\nactivate = 1\n[legacy_sect]\nactivate = 1\n");
548
717
  }
549
718
  async function buildNative(config, options = {}) {
550
719
  if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw new Error("Build inicial suporta Linux x64 e Windows x64.");
@@ -556,7 +725,7 @@ async function buildNative(config, options = {}) {
556
725
  const target = options.testOnly ? join2(config.projectRoot, ".acbr/test-runtime", `${process.platform}-${process.arch}`) : runtimeDirectory(config);
557
726
  const stage = join2(dirname3(target), `.runtime-stage-${randomUUID2()}`);
558
727
  const units = join2(stage, ".units");
559
- await mkdir3(units, { recursive: true });
728
+ await mkdir4(units, { recursive: true });
560
729
  const executable = process.platform === "win32" ? "acbr-worker.exe" : "acbr-worker";
561
730
  try {
562
731
  const cpu = (await runCommand(config.native.fpc, ["-iTP"])).stdout.trim();
@@ -577,20 +746,20 @@ async function buildNative(config, options = {}) {
577
746
  `-FU${units}`,
578
747
  `-FE${stage}`,
579
748
  `-o${executable}`,
580
- ...searchPaths.map((path4) => `-Fu${path4}`),
581
- ...fontPaths.map((path4) => `-Fi${path4}`),
749
+ ...searchPaths.map((path5) => `-Fu${path5}`),
750
+ ...fontPaths.map((path5) => `-Fi${path5}`),
582
751
  config.native.project
583
752
  ];
584
753
  const responseFile = join2(stage, ".compiler.rsp");
585
754
  if (args.some((arg) => /[\"\r\n]/.test(arg))) throw new Error("Caminhos do build n\xE3o podem conter aspas ou quebras de linha.");
586
- await writeFile3(responseFile, args.slice(0, -1).join("\n") + "\n");
755
+ await writeFile4(responseFile, args.slice(0, -1).join("\n") + "\n");
587
756
  const logPath = join2(config.projectRoot, ".acbr/build.log");
588
757
  try {
589
758
  const compilation = await runCommand(config.native.fpc, [`@${responseFile}`, config.native.project], { cwd: config.projectRoot, maxOutputBytes: 32 * 1024 * 1024 });
590
- await writeFile3(logPath, compilation.stdout + compilation.stderr);
759
+ await writeFile4(logPath, compilation.stdout + compilation.stderr);
591
760
  } catch (error) {
592
761
  const compilation = error;
593
- await writeFile3(logPath, (compilation.stdout ?? "") + (compilation.stderr ?? compilation.message));
762
+ await writeFile4(logPath, (compilation.stdout ?? "") + (compilation.stderr ?? compilation.message));
594
763
  throw new Error(`${compilation.message}
595
764
  Log completo: ${logPath}`, { cause: compilation });
596
765
  }
@@ -599,9 +768,9 @@ Log completo: ${logPath}`, { cause: compilation });
599
768
  await copyTree(schemas, join2(stage, "schemas"));
600
769
  const services = join2(source, "Fontes/ACBrDFe/ACBrNFe/ACBrNFeServicos.ini");
601
770
  await copyFile2(services, join2(stage, "ACBrNFeServicos.ini"));
602
- await mkdir3(join2(stage, "licenses"), { recursive: true });
771
+ await mkdir4(join2(stage, "licenses"), { recursive: true });
603
772
  await copyFile2(join2(source, "Doctos/LICENSE.TXT"), join2(stage, "licenses/ACBr-LICENSE.TXT"));
604
- await mkdir3(join2(stage, "sources/native"), { recursive: true });
773
+ await mkdir4(join2(stage, "sources/native"), { recursive: true });
605
774
  await copyNativeSources(dirname3(config.native.project), join2(stage, "sources/native"));
606
775
  await copyFile2(join2(config.generator.outputDir, "native/generated/AcbrModels.pas"), join2(stage, "sources/native/AcbrModels.pas"));
607
776
  for (const name of ["fp-compiler-3.2.2", "fp-units-rtl-3.2.2", "fpc"]) {
@@ -615,7 +784,7 @@ Log completo: ${logPath}`, { cause: compilation });
615
784
  const archive = join2(stage, "sources/acbr-source.tar.gz");
616
785
  const tarArgs = process.platform === "linux" ? ["--sort=name", "--mtime=@0", "--owner=0", "--group=0", "--numeric-owner", "-I", "gzip -n"] : [];
617
786
  await runCommand("tar", [...tarArgs, process.platform === "linux" ? "-cf" : "-czf", archive, "-C", source, "Fontes", "Exemplos/ACBrDFe/Schemas/NFe", "Doctos/LICENSE.TXT"]);
618
- await writeFile3(join2(stage, "sources/build.json"), `${JSON.stringify({
787
+ await writeFile4(join2(stage, "sources/build.json"), `${JSON.stringify({
619
788
  sourceRevision: lock.source.revision,
620
789
  sourceUrl: lock.source.url,
621
790
  sourceTreeHash: lock.source.treeHash,
@@ -637,6 +806,7 @@ Log completo: ${logPath}`, { cause: compilation });
637
806
  if (currentGenerated.contractHash !== contract.contractHash || currentGenerated.sourceHash !== contract.sourceHash || Object.entries(contract.fileHashes).some(([name, hash2]) => currentGenerated.fileHashes[name] !== hash2)) throw new Error("Arquivos gerados mudaram durante a compila\xE7\xE3o. Execute build novamente.");
638
807
  const currentSource = await verifySource(config);
639
808
  if (currentSource.source.revision !== lock.source.revision || currentSource.source.treeHash !== lock.source.treeHash) throw new Error("Fontes ACBr foram atualizadas durante a compila\xE7\xE3o. Execute generate e build novamente.");
809
+ await completeRuntimeLicenses(stage);
640
810
  const files = (await snapshotSource(stage)).files;
641
811
  const manifest = {
642
812
  formatVersion: 1,
@@ -647,10 +817,12 @@ Log completo: ${logPath}`, { cause: compilation });
647
817
  executable,
648
818
  files,
649
819
  generatedFileHashes: contract.fileHashes,
820
+ capabilities: ["recuperarXml"],
650
821
  systemDependencies,
651
822
  ...options.testOnly ? { testOnly: true } : {}
652
823
  };
653
- await writeFile3(join2(stage, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
824
+ await auditRuntimeLicenses(stage, manifest);
825
+ await writeFile4(join2(stage, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
654
826
  `);
655
827
  await replaceRuntime(stage, target);
656
828
  return manifest;
@@ -659,15 +831,15 @@ Log completo: ${logPath}`, { cause: compilation });
659
831
  }
660
832
  }
661
833
  async function copyNativeSources(source, target) {
662
- await mkdir3(target, { recursive: true });
663
- for (const entry of await readdir3(source, { withFileTypes: true })) {
834
+ await mkdir4(target, { recursive: true });
835
+ for (const entry of await readdir4(source, { withFileTypes: true })) {
664
836
  if (entry.isDirectory() && !entry.name.startsWith(".")) await copyNativeSources(join2(source, entry.name), join2(target, entry.name));
665
837
  else if (entry.isFile() && /\.(pas|lpr|inc|lpi)$/i.test(entry.name)) await copyFile2(join2(source, entry.name), join2(target, entry.name));
666
838
  }
667
839
  }
668
840
  async function copyTree(source, target) {
669
- await mkdir3(target, { recursive: true });
670
- for (const entry of await readdir3(source, { withFileTypes: true })) {
841
+ await mkdir4(target, { recursive: true });
842
+ for (const entry of await readdir4(source, { withFileTypes: true })) {
671
843
  if (entry.isSymbolicLink()) throw new Error(`Arquivo de distribui\xE7\xE3o n\xE3o pode ser link: ${entry.name}.`);
672
844
  if (entry.isDirectory()) await copyTree(join2(source, entry.name), join2(target, entry.name));
673
845
  else if (entry.isFile()) await copyFile2(join2(source, entry.name), join2(target, entry.name));
@@ -689,12 +861,13 @@ async function checkBuild(config) {
689
861
  const lock = await verifySource(config);
690
862
  const generated = await generatedManifest(config);
691
863
  const directory = runtimeDirectory(config);
692
- const manifest = JSON.parse(await readFile4(join2(directory, "manifest.json"), "utf8"));
693
- if (manifest.formatVersion !== 1 || manifest.platform !== process.platform || manifest.arch !== process.arch || manifest.sourceRevision !== lock.source.revision || generated.sourceHash !== lock.source.treeHash || manifest.contractHash !== generated.contractHash || !manifest.generatedFileHashes || Object.entries(generated.fileHashes).some(([name, hash2]) => manifest.generatedFileHashes[name] !== hash2) || typeof manifest.executable !== "string" || !manifest.files || !Object.hasOwn(manifest.files, manifest.executable)) throw new Error("Runtime diverge das fontes ou contrato. Execute build.");
694
- for (const [path4, expected] of Object.entries(manifest.files)) {
695
- if (path4.startsWith("/") || path4.includes("\\") || path4.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(expected)) throw new Error(`Caminho/hash inv\xE1lido no runtime: ${path4}.`);
696
- if (await fileHash(join2(directory, path4)) !== expected) throw new Error(`Hash inv\xE1lido no runtime: ${path4}.`);
864
+ const manifest = JSON.parse(await readFile5(join2(directory, "manifest.json"), "utf8"));
865
+ if (manifest.formatVersion !== 1 || manifest.platform !== process.platform || manifest.arch !== process.arch || manifest.sourceRevision !== lock.source.revision || generated.sourceHash !== lock.source.treeHash || manifest.contractHash !== generated.contractHash || !manifest.generatedFileHashes || Object.entries(generated.fileHashes).some(([name, hash2]) => manifest.generatedFileHashes[name] !== hash2) || !Array.isArray(manifest.capabilities) || !manifest.capabilities.includes("recuperarXml") || typeof manifest.executable !== "string" || !manifest.files || !Object.hasOwn(manifest.files, manifest.executable)) throw new Error("Runtime diverge das fontes ou contrato. Execute build.");
866
+ for (const [path5, expected] of Object.entries(manifest.files)) {
867
+ if (path5.startsWith("/") || path5.includes("\\") || path5.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(expected)) throw new Error(`Caminho/hash inv\xE1lido no runtime: ${path5}.`);
868
+ if (await fileHash(join2(directory, path5)) !== expected) throw new Error(`Hash inv\xE1lido no runtime: ${path5}.`);
697
869
  }
870
+ await auditRuntimeLicenses(directory, manifest);
698
871
  return manifest;
699
872
  }
700
873
  async function doctor(config) {
@@ -732,8 +905,8 @@ async function doctor(config) {
732
905
  return items;
733
906
  }
734
907
  async function copyCompilerLicenses(config, stage, lazarus) {
735
- const packagedLazarus = fileURLToPath(new URL("../docs/licenses/lazarus/", import.meta.url));
736
- const packagedFpc = fileURLToPath(new URL("../docs/licenses/fpc/", import.meta.url));
908
+ const packagedLazarus = fileURLToPath2(new URL("../docs/licenses/lazarus/", import.meta.url));
909
+ const packagedFpc = fileURLToPath2(new URL("../docs/licenses/fpc/", import.meta.url));
737
910
  const notices = {};
738
911
  async function copyNotice(name, candidates2) {
739
912
  for (const source of candidates2) if (await exists(source)) {
@@ -756,11 +929,11 @@ async function copyCompilerLicenses(config, stage, lazarus) {
756
929
  const candidates = [join2(fpcRoot, "doc"), fpcRoot, join2(lazarus, "fpc"), "/usr/share/doc/fp-compiler-3.2.2", "/usr/share/doc/fp-units-rtl-3.2.2"];
757
930
  for (const directory of candidates) {
758
931
  if (!await exists(directory)) continue;
759
- for (const name of await readdir3(directory)) {
932
+ for (const name of await readdir4(directory)) {
760
933
  if (/^(?:copying|license|copyright)/i.test(name) && (await stat2(join2(directory, name))).isFile()) await copyFile2(join2(directory, name), join2(stage, "licenses", `FPC-${basename(directory)}-${name}`));
761
934
  }
762
935
  }
763
- await writeFile3(join2(stage, "licenses/toolchain-notices.json"), `${JSON.stringify(notices, null, 2)}
936
+ await writeFile4(join2(stage, "licenses/toolchain-notices.json"), `${JSON.stringify(notices, null, 2)}
764
937
  `);
765
938
  }
766
939
  var REQUIRED_DYNAMIC, CORE_SYSTEM;
@@ -768,6 +941,7 @@ var init_native_build = __esm({
768
941
  "src/native-build.ts"() {
769
942
  "use strict";
770
943
  init_source();
944
+ init_runtime_license_inventory();
771
945
  REQUIRED_DYNAMIC = ["libssl.so.3", "libcrypto.so.3", "libxml2.so.2"];
772
946
  CORE_SYSTEM = /^(?:lib(?:c|m|pthread|dl|rt|resolv|anl|util)\.so(?:\.|$)|ld-linux|linux-vdso)/;
773
947
  }
@@ -785,12 +959,12 @@ __export(generator_exports, {
785
959
  renderPascal: () => renderPascal,
786
960
  renderTypeScript: () => renderTypeScript
787
961
  });
788
- import { createHash as createHash3 } from "node:crypto";
962
+ import { createHash as createHash4 } from "node:crypto";
789
963
  import { execFile } from "node:child_process";
790
964
  import { promisify } from "node:util";
791
- import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4, readdir as readdir4 } from "node:fs/promises";
792
- import path2 from "node:path";
793
- import { fileURLToPath as fileURLToPath2 } from "node:url";
965
+ import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5, readdir as readdir5 } from "node:fs/promises";
966
+ import path3 from "node:path";
967
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
794
968
  function buildModelIR(raw) {
795
969
  const declarations = /* @__PURE__ */ new Map();
796
970
  for (const unit of raw.units) for (const type of unit.types) declarations.set((unit.name + "." + type.name).toLowerCase(), { unit, type });
@@ -1086,54 +1260,54 @@ function renderClientIndex() {
1086
1260
  async function fingerprint(dir) {
1087
1261
  const files = [];
1088
1262
  async function walk(d) {
1089
- for (const entry of await readdir4(d, { withFileTypes: true })) {
1090
- const f = path2.join(d, entry.name);
1263
+ for (const entry of await readdir5(d, { withFileTypes: true })) {
1264
+ const f = path3.join(d, entry.name);
1091
1265
  if (entry.isDirectory()) await walk(f);
1092
1266
  else if (/\.(pas|pp|inc|xsd)$/i.test(entry.name)) files.push(f);
1093
1267
  }
1094
1268
  }
1095
1269
  await walk(dir);
1096
- const digest = createHash3("sha256");
1270
+ const digest2 = createHash4("sha256");
1097
1271
  for (const f of files.sort()) {
1098
- digest.update(path2.relative(dir, f).replaceAll("\\", "/"));
1099
- digest.update(await readFile5(f));
1272
+ digest2.update(path3.relative(dir, f).replaceAll("\\", "/"));
1273
+ digest2.update(await readFile6(f));
1100
1274
  }
1101
- return digest.digest("hex");
1275
+ return digest2.digest("hex");
1102
1276
  }
1103
1277
  async function generateModel(options) {
1104
- const root = path2.resolve(options.outputDir), cache = path2.join(root, ".acbr/generated"), bin = path2.join(root, ".acbr/bin");
1105
- const models = path2.resolve(root, options.modelOutputDir ?? "generated/acbr"), native = path2.resolve(root, options.nativeOutputDir ?? "native/generated");
1106
- await Promise.all([mkdir4(cache, { recursive: true }), mkdir4(bin, { recursive: true }), mkdir4(models, { recursive: true }), mkdir4(native, { recursive: true })]);
1107
- const extractor = options.extractorPath ?? fileURLToPath2(new URL("../tools/extract-model.lpr", import.meta.url));
1108
- const executable = path2.join(bin, "extract-model" + (process.platform === "win32" ? ".exe" : ""));
1278
+ const root = path3.resolve(options.outputDir), cache = path3.join(root, ".acbr/generated"), bin = path3.join(root, ".acbr/bin");
1279
+ const models = path3.resolve(root, options.modelOutputDir ?? "generated/acbr"), native = path3.resolve(root, options.nativeOutputDir ?? "native/generated");
1280
+ await Promise.all([mkdir5(cache, { recursive: true }), mkdir5(bin, { recursive: true }), mkdir5(models, { recursive: true }), mkdir5(native, { recursive: true })]);
1281
+ const extractor = options.extractorPath ?? fileURLToPath3(new URL("../tools/extract-model.lpr", import.meta.url));
1282
+ const executable = path3.join(bin, "extract-model" + (process.platform === "win32" ? ".exe" : ""));
1109
1283
  try {
1110
1284
  await execute(options.fpcPath ?? "fpc", ["-Mobjfpc", "-Sh", "-FU" + bin, "-FE" + bin, extractor], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
1111
- await execute(executable, [path2.resolve(options.acbrRoot), path2.join(cache, "raw-model.json"), process.platform === "win32" ? "win64" : "linux"], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
1285
+ await execute(executable, [path3.resolve(options.acbrRoot), path3.join(cache, "raw-model.json"), process.platform === "win32" ? "win64" : "linux"], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
1112
1286
  } catch (error) {
1113
1287
  const e = error;
1114
1288
  throw new Error("Extra\xE7\xE3o FCL-passrc falhou: " + (e.stderr ?? "") + (e.stdout ?? "") + e.message);
1115
1289
  }
1116
- const raw = JSON.parse(await readFile5(path2.join(cache, "raw-model.json"), "utf8"));
1290
+ const raw = JSON.parse(await readFile6(path3.join(cache, "raw-model.json"), "utf8"));
1117
1291
  const ir = buildModelIR(raw), sourceRevision = Number(options.revision);
1118
1292
  if (!Number.isSafeInteger(sourceRevision) || sourceRevision < 1) throw new Error("Revis\xE3o SVN inv\xE1lida");
1119
1293
  const sourceHash = options.sourceHash ?? await fingerprint(options.acbrRoot), contractHash = hash(stable({ sourceRevision, sourceHash, ir }));
1120
1294
  let previous;
1121
1295
  try {
1122
- previous = JSON.parse(await readFile5(path2.join(cache, "model.ir.json"), "utf8"));
1296
+ previous = JSON.parse(await readFile6(path3.join(cache, "model.ir.json"), "utf8"));
1123
1297
  } catch (error) {
1124
1298
  if (error.code !== "ENOENT") throw error;
1125
1299
  }
1126
- const report = compareContracts(previous, ir), reportPath = path2.join(cache, "changes.json"), manifestPath = path2.join(cache, "manifest.json");
1127
- const files = [path2.relative(root, path2.join(models, "models.ts")), path2.relative(root, path2.join(models, "index.ts")), path2.relative(root, path2.join(native, "AcbrModels.pas"))].map((f) => f.replaceAll("\\", "/"));
1300
+ const report = compareContracts(previous, ir), reportPath = path3.join(cache, "changes.json"), manifestPath = path3.join(cache, "manifest.json");
1301
+ const files = [path3.relative(root, path3.join(models, "models.ts")), path3.relative(root, path3.join(models, "index.ts")), path3.relative(root, path3.join(native, "AcbrModels.pas"))].map((f) => f.replaceAll("\\", "/"));
1128
1302
  const content = [renderTypeScript(ir, sourceRevision, contractHash), renderClientIndex(), renderPascal(ir, sourceRevision, contractHash)];
1129
1303
  const fileHashes = Object.fromEntries(files.map((file, index) => [file, hash(content[index])]));
1130
- const metadataPath = path2.join(models, "contract.json"), metadataContent = renderContractMetadata(ir, sourceRevision, sourceHash, contractHash);
1304
+ const metadataPath = path3.join(models, "contract.json"), metadataContent = renderContractMetadata(ir, sourceRevision, sourceHash, contractHash);
1131
1305
  await Promise.all([
1132
- ...files.map((file, index) => writeFile4(path2.resolve(root, file), content[index], "utf8")),
1133
- writeFile4(path2.join(cache, "model.ir.json"), JSON.stringify(ir, null, 2) + "\n", "utf8"),
1134
- writeFile4(metadataPath, metadataContent, "utf8"),
1135
- writeFile4(reportPath, JSON.stringify(report, null, 2) + "\n", "utf8"),
1136
- writeFile4(manifestPath, JSON.stringify({ schemaVersion: 1, sourceRevision, sourceHash, contractHash, root: ir.root, models: ir.types.length, files, fileHashes, metadata: { file: path2.relative(root, metadataPath).replaceAll("\\", "/"), sha256: hash(metadataContent) } }, null, 2) + "\n", "utf8")
1306
+ ...files.map((file, index) => writeFile5(path3.resolve(root, file), content[index], "utf8")),
1307
+ writeFile5(path3.join(cache, "model.ir.json"), JSON.stringify(ir, null, 2) + "\n", "utf8"),
1308
+ writeFile5(metadataPath, metadataContent, "utf8"),
1309
+ writeFile5(reportPath, JSON.stringify(report, null, 2) + "\n", "utf8"),
1310
+ writeFile5(manifestPath, JSON.stringify({ schemaVersion: 1, sourceRevision, sourceHash, contractHash, root: ir.root, models: ir.types.length, files, fileHashes, metadata: { file: path3.relative(root, metadataPath).replaceAll("\\", "/"), sha256: hash(metadataContent) } }, null, 2) + "\n", "utf8")
1137
1311
  ]);
1138
1312
  return { contractHash, sourceHash, models: ir.types.length, reportPath, manifestPath, metadataPath };
1139
1313
  }
@@ -1168,14 +1342,19 @@ var init_generator = __esm({
1168
1342
  ttime: { kind: "datetime" }
1169
1343
  };
1170
1344
  stable = (value) => JSON.stringify(value);
1171
- hash = (value) => createHash3("sha256").update(value).digest("hex");
1345
+ hash = (value) => createHash4("sha256").update(value).digest("hex");
1172
1346
  tsType = (p) => p.kind === "object" ? p.ref + "Input" : p.kind === "list" ? p.ref + "Input" : p.kind === "enum" ? p.ref : p.kind === "integer" ? "number" : p.kind === "boolean" ? "boolean" : "string";
1173
1347
  }
1174
1348
  });
1175
1349
 
1176
1350
  // src/diagnostics.ts
1351
+ function base64XmlRecuperadoValido(value) {
1352
+ if (typeof value !== "string" || value.length === 0 || value.length > Math.ceil(MAX_RECOVERED_XML_BYTES / 3) * 4) return false;
1353
+ const bytes = Buffer.from(value, "base64");
1354
+ return bytes.length > 0 && bytes.length <= MAX_RECOVERED_XML_BYTES && bytes.toString("base64") === value;
1355
+ }
1177
1356
  function etapaDaOperacao(comando) {
1178
- return { gerarXml: "geracao", validar: "validacao", assinar: "assinatura", transmitir: "transmissao", consultar: "consulta", cancelar: "cancelamento", cartaCorrecao: "carta_correcao", inutilizar: "inutilizacao" }[comando] ?? "operacao";
1357
+ return { gerarXml: "geracao", validar: "validacao", assinar: "assinatura", transmitir: "transmissao", consultar: "consulta", recuperarXml: "consulta", cancelar: "cancelamento", cartaCorrecao: "carta_correcao", inutilizar: "inutilizacao" }[comando] ?? "operacao";
1179
1358
  }
1180
1359
  function criarDiagnosticoErro(codigo, desconhecido = false, detalhes = {}) {
1181
1360
  const safeCode = Object.hasOwn(CATALOGO, codigo) ? codigo : "FALHA_LOCAL";
@@ -1212,18 +1391,30 @@ function diagnosticarResultado(resultado, comando) {
1212
1391
  const protocolo = typeof resultado.protocolo === "string" && /^\d{15}$/.test(resultado.protocolo);
1213
1392
  const chave = typeof resultado.chave === "string" && /^\d{44}$/.test(resultado.chave);
1214
1393
  const autorizacao = (comando === "transmitir" || comando === "consultar") && resultado.estado === "AUTORIZADO" && [100, 150].includes(resultado.cStat) && protocolo && chave && (comando === "consultar" || resultado.envioIniciado !== false);
1394
+ const xmlRecuperado = comando === "recuperarXml" && base64XmlRecuperadoValido(resultado.xmlBase64);
1395
+ const recuperacao = comando === "recuperarXml" && resultado.estado === "XML_RECUPERADO" && resultado.cStat === 100 && protocolo && chave && semEvento && xmlRecuperado;
1215
1396
  const evento = comando === "cancelar" && resultado.estado === "CANCELADO" && [135, 136].includes(resultado.cStat) && chave || comando === "cartaCorrecao" && resultado.estado === "EVENTO_REGISTRADO" && resultado.cStat === 135 && chave || comando === "inutilizar" && resultado.estado === "INUTILIZADO" && resultado.cStat === 102;
1216
1397
  if (local && resultado.sucesso === true && semEvento) {
1217
1398
  statusEnvio = "nao_enviado";
1218
1399
  codigo = "ETAPA_LOCAL_CONCLUIDA";
1219
1400
  mensagem = "A etapa local foi conclu\xEDda; esta opera\xE7\xE3o n\xE3o transmitiu a nota.";
1220
1401
  acao = "Confira o resultado antes de seguir para a pr\xF3xima etapa.";
1402
+ } else if (resultado.sucesso === true && recuperacao) {
1403
+ statusEnvio = "autorizado";
1404
+ codigo = "XML_RECUPERADO";
1405
+ mensagem = "O XML autorizado foi recuperado por consulta; esta opera\xE7\xE3o n\xE3o transmitiu a nota.";
1406
+ acao = "Guarde o XML recuperado com o protocolo de autoriza\xE7\xE3o.";
1407
+ } else if (comando === "recuperarXml" && resultado.sucesso === false && resultado.codigo === "RECUPERACAO_NAO_COMPROVADA" && ["CONSULTADO", "ERRO"].includes(resultado.estado) && semEvento) {
1408
+ statusEnvio = "nao_enviado";
1409
+ codigo = "RECUPERACAO_NAO_COMPROVADA";
1410
+ mensagem = CATALOGO.RECUPERACAO_NAO_COMPROVADA[1];
1411
+ acao = CATALOGO.RECUPERACAO_NAO_COMPROVADA[2];
1221
1412
  } else if (resultado.sucesso === true && (autorizacao || evento && protocolo && resultado.envioIniciado !== false)) {
1222
1413
  statusEnvio = "autorizado";
1223
1414
  codigo = "OPERACAO_CONFIRMADA";
1224
1415
  mensagem = { AUTORIZADO: "A nota foi autorizada.", CANCELADO: "O cancelamento foi confirmado.", EVENTO_REGISTRADO: "O evento foi registrado.", INUTILIZADO: "A faixa foi inutilizada." }[resultado.estado];
1225
1416
  acao = "Guarde o resultado fiscal. N\xE3o repita esta opera\xE7\xE3o.";
1226
- } else if (resultado.sucesso === false && (comando === "consultar" || resultado.envioIniciado !== false) && ["transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(comando) && Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 && (resultado.estado === "DENEGADO" && [110, 301, 302].includes(resultado.cStat) || resultado.estado === "REJEITADO" && ![100, 150, 110, 301, 302, 101, 151, 155, 103, 104, 105, 108, 109, 204, 539, 573, 135, 136, 102, 217].includes(resultado.cStat))) {
1417
+ } else if (resultado.sucesso === false && (comando === "consultar" || comando === "recuperarXml" || resultado.envioIniciado !== false) && ["transmitir", "consultar", "recuperarXml", "cancelar", "cartaCorrecao", "inutilizar"].includes(comando) && Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 && (resultado.estado === "DENEGADO" && [110, 301, 302].includes(resultado.cStat) || resultado.estado === "REJEITADO" && ![100, 150, 110, 301, 302, 101, 151, 155, 103, 104, 105, 108, 109, 204, 539, 573, 135, 136, 102, 217].includes(resultado.cStat))) {
1227
1418
  statusEnvio = "rejeitado";
1228
1419
  codigo = resultado.estado === "DENEGADO" ? "NOTA_DENEGADA" : "OPERACAO_REJEITADA";
1229
1420
  mensagem = resultado.estado === "DENEGADO" ? "A nota foi denegada." : "A opera\xE7\xE3o foi rejeitada.";
@@ -1238,13 +1429,14 @@ function diagnosticarResultado(resultado, comando) {
1238
1429
  const cStat = Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 ? resultado.cStat : void 0;
1239
1430
  return Object.freeze({ codigo, etapa, mensagem, acao, statusEnvio, ...cStat !== void 0 ? { cStat } : {} });
1240
1431
  }
1241
- var ETAPAS, CAMPOS, CATALOGO;
1432
+ var ETAPAS, CAMPOS, MAX_RECOVERED_XML_BYTES, CATALOGO;
1242
1433
  var init_diagnostics = __esm({
1243
1434
  "src/diagnostics.ts"() {
1244
1435
  "use strict";
1245
1436
  init_types();
1246
1437
  ETAPAS = /* @__PURE__ */ new Set(["configuracao", "documento", "runtime", "geracao", "validacao", "assinatura", "transmissao", "consulta", "cancelamento", "carta_correcao", "inutilizacao", "operacao", "limpeza"]);
1247
1438
  CAMPOS = /* @__PURE__ */ new Set(["cnpj", "uf", "modelo", "ambiente", "contrato", "certificado", "certificado.senha", "certificado.pfx", "certificado.arquivo", "csc", "csc.id", "csc.valor", "timeoutMs", "limiteFila", "limiteBytes", "runtimeDirectory", "documento", "xml", "consulta", "chave", "recibo", "cancelamento", "protocolo", "justificativa", "cartaCorrecao", "correcao", "sequenciaEvento", "inutilizacao", "ano", "serie", "numeroInicial", "numeroFinal", "operacao", "signal"]);
1439
+ MAX_RECOVERED_XML_BYTES = 4 * 1024 * 1024;
1248
1440
  CATALOGO = {
1249
1441
  CONFIGURACAO_INVALIDA: ["configuracao", "A configura\xE7\xE3o cont\xE9m um campo inv\xE1lido.", "Confira o campo indicado e seu tipo antes de continuar."],
1250
1442
  CONTRATO_INVALIDO: ["configuracao", "O contrato do cliente \xE9 inv\xE1lido.", "Use o contrato gerado junto com o cliente."],
@@ -1260,6 +1452,7 @@ var init_diagnostics = __esm({
1260
1452
  XML_NAO_ASSINADO: ["assinatura", "A opera\xE7\xE3o exige XML previamente assinado.", "Conclua a assinatura e a valida\xE7\xE3o antes de transmitir."],
1261
1453
  XML_ALTERADO: ["assinatura", "O XML assinado foi alterado.", "Use exatamente o XML assinado e persistido; n\xE3o edite seu conte\xFAdo."],
1262
1454
  RETORNO_INVALIDO: ["transmissao", "A identidade ou o protocolo do retorno fiscal \xE9 inv\xE1lido.", "Consulte a situa\xE7\xE3o fiscal antes de decidir repetir a opera\xE7\xE3o."],
1455
+ RECUPERACAO_NAO_COMPROVADA: ["consulta", "A consulta n\xE3o comprovou a recupera\xE7\xE3o do XML autorizado.", "Preserve o XML assinado original e confira a situa\xE7\xE3o fiscal. N\xE3o transmita a nota para tentar recuperar o protocolo."],
1263
1456
  OPERACAO_FISCAL_FALHOU: ["operacao", "O motor n\xE3o conseguiu concluir a etapa fiscal.", "Confira a configura\xE7\xE3o da etapa, os dados do XML e as depend\xEAncias do runtime."],
1264
1457
  TLS_SERVIDOR_INVALIDO: ["transmissao", "A verifica\xE7\xE3o TLS do servi\xE7o fiscal falhou.", "Confira o servi\xE7o e a cadeia de confian\xE7a; mantenha a verifica\xE7\xE3o TLS habilitada."],
1265
1458
  CSC_INVALIDO: ["configuracao", "A configura\xE7\xE3o do CSC \xE9 inv\xE1lida.", "Confira id e valor do CSC sem registrar seu conte\xFAdo."],
@@ -1268,6 +1461,7 @@ var init_diagnostics = __esm({
1268
1461
  RUNTIME_INVALIDO: ["runtime", "O runtime fiscal \xE9 inv\xE1lido.", "Use um runtime distribu\xEDdo e compat\xEDvel com a plataforma."],
1269
1462
  RUNTIME_INCOMPLETO: ["runtime", "Falta um arquivo do runtime fiscal.", "Reinstale o runtime da plataforma."],
1270
1463
  RUNTIME_ALTERADO: ["runtime", "A integridade do runtime fiscal n\xE3o foi confirmada.", "Reinstale o runtime; n\xE3o desative a verifica\xE7\xE3o dos hashes."],
1464
+ RUNTIME_SEM_CAPACIDADE: ["runtime", "O runtime instalado n\xE3o oferece esta opera\xE7\xE3o.", "Atualize o pacote principal e o runtime da plataforma para vers\xF5es compat\xEDveis com a opera\xE7\xE3o solicitada."],
1271
1465
  CONTRATO_DIVERGENTE: ["runtime", "Cliente e motor usam contratos diferentes.", "Use vers\xF5es compat\xEDveis ou regenere e recompile ambos."],
1272
1466
  DOCUMENTO_INVALIDO: ["documento", "O documento cont\xE9m dados incompat\xEDveis com o modelo.", "Valide os campos e tipos do documento antes de gerar o XML."],
1273
1467
  OPERACAO_INVALIDA: ["operacao", "Os par\xE2metros da opera\xE7\xE3o s\xE3o inv\xE1lidos.", "Informe um objeto com os campos exigidos pela opera\xE7\xE3o."],
@@ -1330,68 +1524,69 @@ var init_types = __esm({
1330
1524
 
1331
1525
  // src/runtime.ts
1332
1526
  import { spawn as spawn2 } from "node:child_process";
1333
- import { readFile as readFile6, stat as stat3 } from "node:fs/promises";
1334
- import path3 from "node:path";
1527
+ import { readFile as readFile7, stat as stat3 } from "node:fs/promises";
1528
+ import path4 from "node:path";
1335
1529
  import { createRequire } from "node:module";
1336
- import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
1530
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
1337
1531
  import { TextDecoder } from "node:util";
1338
1532
  function confined(root, relative3) {
1339
- const file = path3.resolve(root, relative3), part = path3.relative(root, file);
1340
- if (!relative3 || path3.isAbsolute(relative3) || part === ".." || part.startsWith(".." + path3.sep)) throw fail2("RUNTIME_INVALIDO", "Caminho inv\xE1lido no runtime.");
1533
+ const file = path4.resolve(root, relative3), part = path4.relative(root, file);
1534
+ if (!relative3 || path4.isAbsolute(relative3) || part === ".." || part.startsWith(".." + path4.sep)) throw fail3("RUNTIME_INVALIDO", "Caminho inv\xE1lido no runtime.");
1341
1535
  return file;
1342
1536
  }
1343
1537
  async function resolveRuntime(directory, contract) {
1344
- if (!validContract(contract)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
1538
+ if (!validContract(contract)) throw fail3("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
1345
1539
  let root = directory;
1346
1540
  if (!root) {
1347
- if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw fail2("PLATAFORMA_NAO_SUPORTADA", "Esta vers\xE3o exige Linux ou Windows x64.");
1541
+ if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw fail3("PLATAFORMA_NAO_SUPORTADA", "Esta vers\xE3o exige Linux ou Windows x64.");
1348
1542
  try {
1349
1543
  const require2 = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
1350
- root = path3.join(path3.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
1544
+ root = path4.join(path4.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
1351
1545
  } catch {
1352
- throw fail2("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
1546
+ throw fail3("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
1353
1547
  }
1354
1548
  }
1355
- root = path3.resolve(root);
1549
+ root = path4.resolve(root);
1356
1550
  let m;
1357
1551
  try {
1358
- m = JSON.parse(await readFile6(path3.join(root, "manifest.json"), "utf8"));
1552
+ m = JSON.parse(await readFile7(path4.join(root, "manifest.json"), "utf8"));
1359
1553
  } catch {
1360
- throw fail2("RUNTIME_AUSENTE", "Manifesto do runtime n\xE3o encontrado.");
1554
+ throw fail3("RUNTIME_AUSENTE", "Manifesto do runtime n\xE3o encontrado.");
1361
1555
  }
1362
- if (!validContract(m) || m.formatVersion !== 1 || !plain(m.files) || typeof m.executable !== "string" || m.platform !== process.platform || m.arch !== process.arch) throw fail2("RUNTIME_INVALIDO", "Manifesto ou plataforma do runtime inv\xE1lidos.");
1363
- if (m.sourceRevision !== contract.sourceRevision || m.contractHash !== contract.contractHash) throw fail2("CONTRATO_DIVERGENTE", "Cliente e motor foram gerados de contratos diferentes; regenere e recompile.");
1556
+ if (!validContract(m) || m.formatVersion !== 1 || !plain(m.files) || typeof m.executable !== "string" || m.platform !== process.platform || m.arch !== process.arch) throw fail3("RUNTIME_INVALIDO", "Manifesto ou plataforma do runtime inv\xE1lidos.");
1557
+ if (m.capabilities !== void 0 && (!Array.isArray(m.capabilities) || !m.capabilities.every((value) => typeof value === "string" && /^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(value)))) throw fail3("RUNTIME_INVALIDO", "Capacidades do runtime inv\xE1lidas.");
1558
+ if (m.sourceRevision !== contract.sourceRevision || m.contractHash !== contract.contractHash) throw fail3("CONTRATO_DIVERGENTE", "Cliente e motor foram gerados de contratos diferentes; regenere e recompile.");
1364
1559
  for (const [name, hash2] of Object.entries(m.files)) {
1365
- if (typeof hash2 !== "string" || !/^[a-f0-9]{64}$/.test(hash2)) throw fail2("RUNTIME_INVALIDO", "Hash inv\xE1lido no runtime.");
1560
+ if (typeof hash2 !== "string" || !/^[a-f0-9]{64}$/.test(hash2)) throw fail3("RUNTIME_INVALIDO", "Hash inv\xE1lido no runtime.");
1366
1561
  const file = confined(root, name);
1367
1562
  let data;
1368
1563
  try {
1369
1564
  if (!(await stat3(file)).isFile()) throw Error();
1370
- data = await readFile6(file);
1565
+ data = await readFile7(file);
1371
1566
  } catch {
1372
- throw fail2("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
1567
+ throw fail3("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
1373
1568
  }
1374
- if (createHash4("sha256").update(data).digest("hex") !== hash2) throw fail2("RUNTIME_ALTERADO", "O runtime n\xE3o corresponde ao manifesto distribu\xEDdo.");
1569
+ if (createHash5("sha256").update(data).digest("hex") !== hash2) throw fail3("RUNTIME_ALTERADO", "O runtime n\xE3o corresponde ao manifesto distribu\xEDdo.");
1375
1570
  }
1376
- if (!m.files[m.executable]) throw fail2("RUNTIME_INVALIDO", "O execut\xE1vel n\xE3o consta no invent\xE1rio.");
1377
- return { directory: root, executable: confined(root, m.executable) };
1571
+ if (!m.files[m.executable]) throw fail3("RUNTIME_INVALIDO", "O execut\xE1vel n\xE3o consta no invent\xE1rio.");
1572
+ return { directory: root, executable: confined(root, m.executable), capabilities: new Set(m.capabilities ?? []) };
1378
1573
  }
1379
1574
  function criarEmissor(options) {
1380
- const configFail = (campo) => fail2("CONFIGURACAO_INVALIDA", "Informe campos e tipos v\xE1lidos na configura\xE7\xE3o.", void 0, false, { etapa: "configuracao", campo });
1575
+ const configFail = (campo) => fail3("CONFIGURACAO_INVALIDA", "Informe campos e tipos v\xE1lidos na configura\xE7\xE3o.", void 0, false, { etapa: "configuracao", campo });
1381
1576
  if (!plain(options)) throw configFail();
1382
1577
  if (typeof options.cnpj !== "string" || !/^\d{14}$/.test(options.cnpj)) throw configFail("cnpj");
1383
1578
  if (typeof options.uf !== "string" || !UFS.has(options.uf)) throw configFail("uf");
1384
1579
  if (![55, 65].includes(options.modelo)) throw configFail("modelo");
1385
1580
  if (![1, 2].includes(options.ambiente)) throw configFail("ambiente");
1386
- if (!validContract(options.contrato)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
1581
+ if (!validContract(options.contrato)) throw fail3("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
1387
1582
  const cert = options.certificado;
1388
- if (cert !== void 0 && (!plain(cert) || typeof cert.senha !== "string" || !!cert.pfx === !!cert.arquivo || cert.pfx !== void 0 && !(cert.pfx instanceof Uint8Array) || cert.arquivo !== void 0 && (typeof cert.arquivo !== "string" || !cert.arquivo))) throw fail2("CERTIFICADO_INVALIDO", "Informe A1 em pfx ou arquivo e sua senha.", void 0, false, { campo: "certificado" });
1389
- if (options.csc !== void 0 && (!plain(options.csc) || typeof options.csc.id !== "string" || !/^\d{1,6}$/.test(options.csc.id) || typeof options.csc.valor !== "string" || !options.csc.valor || options.csc.valor.length > 256)) throw fail2("CSC_INVALIDO", "CSC inv\xE1lido.", void 0, false, { campo: "csc" });
1583
+ if (cert !== void 0 && (!plain(cert) || typeof cert.senha !== "string" || !!cert.pfx === !!cert.arquivo || cert.pfx !== void 0 && !(cert.pfx instanceof Uint8Array) || cert.arquivo !== void 0 && (typeof cert.arquivo !== "string" || !cert.arquivo))) throw fail3("CERTIFICADO_INVALIDO", "Informe A1 em pfx ou arquivo e sua senha.", void 0, false, { campo: "certificado" });
1584
+ if (options.csc !== void 0 && (!plain(options.csc) || typeof options.csc.id !== "string" || !/^\d{1,6}$/.test(options.csc.id) || typeof options.csc.valor !== "string" || !options.csc.valor || options.csc.valor.length > 256)) throw fail3("CSC_INVALIDO", "CSC inv\xE1lido.", void 0, false, { campo: "csc" });
1390
1585
  if (options.runtimeDirectory !== void 0 && (typeof options.runtimeDirectory !== "string" || !options.runtimeDirectory)) throw configFail("runtimeDirectory");
1391
1586
  if (options.validaDocumento !== void 0 && typeof options.validaDocumento !== "function" || options.criaProcesso !== void 0 && typeof options.criaProcesso !== "function") throw configFail();
1392
1587
  const cfg = { cnpj: options.cnpj, uf: options.uf, modelo: options.modelo, ambiente: options.ambiente, csc: options.csc ? { ...options.csc } : void 0 };
1393
1588
  const certificate = cert ? { ...cert, pfx: cert.pfx ? Buffer.from(cert.pfx) : void 0 } : void 0;
1394
- const contract = { ...options.contrato };
1589
+ const contract = { sourceRevision: options.contrato.sourceRevision, contractHash: options.contrato.contractHash };
1395
1590
  const timeout = options.timeoutMs ?? 12e4, capacity = options.limiteFila ?? 32, bytesLimit = options.limiteBytes ?? MAX_BYTES;
1396
1591
  if (!Number.isInteger(timeout) || timeout < 1 || timeout > 12e4) throw configFail("timeoutMs");
1397
1592
  if (!Number.isInteger(capacity) || capacity < 0 || capacity > 1e3) throw configFail("limiteFila");
@@ -1400,7 +1595,7 @@ function criarEmissor(options) {
1400
1595
  let runtimePromise, closed = false, teardownFailed = false, current;
1401
1596
  const queue = [];
1402
1597
  const closedError = () => {
1403
- const error = fail2("EMISSOR_FECHADO", "Emissor encerrado.");
1598
+ const error = fail3("EMISSOR_FECHADO", "Emissor encerrado.");
1404
1599
  if (teardownFailed) error.anotarFalhaLimpeza();
1405
1600
  return error;
1406
1601
  };
@@ -1412,9 +1607,10 @@ function criarEmissor(options) {
1412
1607
  }
1413
1608
  };
1414
1609
  async function execute2(item) {
1415
- if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
1610
+ if (closed || item.signal?.aborted) throw fail3("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
1416
1611
  const runtime = await (runtimePromise ??= resolveRuntime(options.runtimeDirectory, contract));
1417
- if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
1612
+ if (item.req.comando === "recuperarXml" && !runtime.capabilities.has("recuperarXml")) throw fail3("RUNTIME_SEM_CAPACIDADE", "O runtime n\xE3o oferece recupera\xE7\xE3o de XML; atualize o pacote e o runtime compat\xEDvel.", item.req, false, { etapa: "runtime" });
1613
+ if (closed || item.signal?.aborted) throw fail3("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
1418
1614
  return await new Promise((done, rejectExecution) => {
1419
1615
  let stopError;
1420
1616
  let child, finished = false, started = false, sending = false, total = 0, rest = Buffer.alloc(0), result;
@@ -1453,7 +1649,7 @@ function criarEmissor(options) {
1453
1649
  };
1454
1650
  const teardownFallback = () => {
1455
1651
  if (finished) return;
1456
- stopError ??= fail2("FALHA_MOTOR", "O motor n\xE3o foi encerrado.", item.req, uncertain());
1652
+ stopError ??= fail3("FALHA_MOTOR", "O motor n\xE3o foi encerrado.", item.req, uncertain());
1457
1653
  stopError.anotarFalhaLimpeza();
1458
1654
  teardownFailed = true;
1459
1655
  closed = true;
@@ -1464,7 +1660,7 @@ function criarEmissor(options) {
1464
1660
  };
1465
1661
  const stop = (code, message) => {
1466
1662
  if (finished || stopError) return;
1467
- stopError = fail2(code, message, item.req, uncertain());
1663
+ stopError = fail3(code, message, item.req, uncertain());
1468
1664
  if (!child?.pid) {
1469
1665
  finish(stopError);
1470
1666
  detachOwnedChild();
@@ -1482,20 +1678,20 @@ function criarEmissor(options) {
1482
1678
  current = { stop: () => stop("EMISSOR_FECHADO", "Emissor encerrado."), done: doneCurrent };
1483
1679
  const env = {};
1484
1680
  for (const key of ["PATH", "Path", "SystemRoot", "WINDIR", "TEMP", "TMP", "HOME", "LANG", "LC_ALL"]) if (process.env[key] !== void 0) env[key] = process.env[key];
1485
- if (process.platform === "linux") env.LD_LIBRARY_PATH = path3.join(runtime.directory, "lib");
1681
+ if (process.platform === "linux") env.LD_LIBRARY_PATH = path4.join(runtime.directory, "lib");
1486
1682
  if (process.platform === "win32") {
1487
1683
  const inheritedPath = env.Path ?? env.PATH ?? "";
1488
1684
  delete env.Path;
1489
- env.PATH = path3.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
1685
+ env.PATH = path4.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
1490
1686
  }
1491
- const modules = path3.join(runtime.directory, "ossl-modules");
1687
+ const modules = path4.join(runtime.directory, "ossl-modules");
1492
1688
  env.OPENSSL_MODULES = modules;
1493
- env.OPENSSL_CONF = path3.join(runtime.directory, "openssl.cnf");
1689
+ env.OPENSSL_CONF = path4.join(runtime.directory, "openssl.cnf");
1494
1690
  try {
1495
1691
  child = launch(runtime.executable, ["--parent-pid", String(process.pid)], { cwd: runtime.directory, env, windowsHide: true, shell: false, stdio: ["pipe", "pipe", "pipe"] });
1496
1692
  started = typeof child.pid === "number";
1497
1693
  } catch {
1498
- finish(fail2("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.", item.req));
1694
+ finish(fail3("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.", item.req));
1499
1695
  return;
1500
1696
  }
1501
1697
  item.signal?.addEventListener("abort", abort, { once: true });
@@ -1536,9 +1732,11 @@ function criarEmissor(options) {
1536
1732
  continue;
1537
1733
  }
1538
1734
  if (result || frame.versao !== 1 || frame.sourceRevision !== contract.sourceRevision || frame.contractHash !== contract.contractHash || typeof frame.sucesso !== "boolean" || !STATES.has(String(frame.estado))) throw Error();
1539
- if (frame.xmlBase64 !== void 0 && (typeof frame.xmlBase64 !== "string" || !frame.xmlBase64.length || Buffer.from(frame.xmlBase64, "base64").toString("base64") !== frame.xmlBase64)) throw Error();
1735
+ if (frame.xmlBase64 !== void 0 && (item.req.comando === "recuperarXml" ? !base64XmlRecuperadoValido(frame.xmlBase64) : typeof frame.xmlBase64 !== "string" || !frame.xmlBase64.length || Buffer.from(frame.xmlBase64, "base64").toString("base64") !== frame.xmlBase64)) throw Error();
1540
1736
  if (frame.cStat !== void 0 && (!Number.isInteger(frame.cStat) || Number(frame.cStat) < 1 || Number(frame.cStat) > 9999)) throw Error();
1541
1737
  if (frame.envioIniciado !== void 0 && typeof frame.envioIniciado !== "boolean" || sending && frame.envioIniciado === false) throw Error();
1738
+ if (frame.estado === "XML_RECUPERADO" && item.req.comando !== "recuperarXml") throw Error();
1739
+ if (item.req.comando === "recuperarXml" && (frame.sucesso === true || frame.estado === "XML_RECUPERADO") && (frame.sucesso !== true || frame.estado !== "XML_RECUPERADO" || frame.cStat !== 100 || typeof frame.chave !== "string" || !/^\d{44}$/.test(frame.chave) || typeof frame.protocolo !== "string" || !/^\d{15}$/.test(frame.protocolo) || typeof frame.xmlBase64 !== "string" || frame.envioIniciado === true || sending)) throw Error();
1542
1740
  const fiscal = frame;
1543
1741
  result = { ...fiscal, diagnostico: diagnosticarResultado(sending ? { ...fiscal, envioIniciado: true } : fiscal, item.req.comando) };
1544
1742
  } catch {
@@ -1554,7 +1752,7 @@ function criarEmissor(options) {
1554
1752
  return;
1555
1753
  }
1556
1754
  if (code !== 0 || rest.length || !result) {
1557
- finish(fail2("FALHA_MOTOR", "O motor encerrou sem resposta fiscal v\xE1lida.", item.req, uncertain()));
1755
+ finish(fail3("FALHA_MOTOR", "O motor encerrou sem resposta fiscal v\xE1lida.", item.req, uncertain()));
1558
1756
  return;
1559
1757
  }
1560
1758
  finish();
@@ -1583,31 +1781,31 @@ function criarEmissor(options) {
1583
1781
  }
1584
1782
  async function request(command, data, operation = {}) {
1585
1783
  const rawOperation = operation;
1586
- if (!plain(rawOperation)) throw fail2("OPERACAO_INVALIDA", "Informe op\xE7\xF5es v\xE1lidas para a opera\xE7\xE3o.", void 0, false, { etapa: etapaDaOperacao(command), campo: "operacao" });
1784
+ if (!plain(rawOperation)) throw fail3("OPERACAO_INVALIDA", "Informe op\xE7\xF5es v\xE1lidas para a opera\xE7\xE3o.", void 0, false, { etapa: etapaDaOperacao(command), campo: "operacao" });
1587
1785
  const signal = operation.signal;
1588
- if (signal !== void 0 && (!plain(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) throw fail2("OPERACAO_INVALIDA", "Informe op\xE7\xF5es v\xE1lidas para a opera\xE7\xE3o.", void 0, false, { etapa: etapaDaOperacao(command), campo: "signal" });
1786
+ if (signal !== void 0 && (!plain(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) throw fail3("OPERACAO_INVALIDA", "Informe op\xE7\xF5es v\xE1lidas para a opera\xE7\xE3o.", void 0, false, { etapa: etapaDaOperacao(command), campo: "signal" });
1589
1787
  if (closed) throw closedError();
1590
- if (operation.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
1591
- if (["assinar", "transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw fail2("CERTIFICADO_AUSENTE", "A opera\xE7\xE3o exige um certificado A1.");
1788
+ if (operation.signal?.aborted) throw fail3("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
1789
+ if (["assinar", "transmitir", "consultar", "recuperarXml", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw fail3("CERTIFICADO_AUSENTE", "A opera\xE7\xE3o exige um certificado A1.", void 0, false, { etapa: etapaDaOperacao(command) });
1592
1790
  if (command === "gerarXml") options.validaDocumento?.(data.documento);
1593
1791
  const config = { ...cfg };
1594
1792
  if (certificate) {
1595
1793
  let pfx;
1596
1794
  try {
1597
- pfx = certificate.pfx ?? await readFile6(certificate.arquivo);
1795
+ pfx = certificate.pfx ?? await readFile7(certificate.arquivo);
1598
1796
  } catch {
1599
- throw fail2("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
1797
+ throw fail3("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
1600
1798
  }
1601
- if (pfx.length > 2 * 1024 * 1024) throw fail2("CERTIFICADO_EXCESSIVO", "Certificado excede o limite.");
1799
+ if (pfx.length > 2 * 1024 * 1024) throw fail3("CERTIFICADO_EXCESSIVO", "Certificado excede o limite.");
1602
1800
  config.certificado = { pfxBase64: pfx.toString("base64"), senha: certificate.senha };
1603
1801
  }
1604
1802
  let bytes, req;
1605
1803
  try {
1606
- bytes = Buffer.from(JSON.stringify({ versao: 1, id: randomUUID3(), ...contract, comando: command, config, ...data }) + "\n", "utf8");
1804
+ bytes = Buffer.from(JSON.stringify({ ...data, ...contract, versao: 1, id: randomUUID3(), comando: command, config }) + "\n", "utf8");
1607
1805
  if (bytes.length > bytesLimit) throw Error();
1608
1806
  req = JSON.parse(bytes.toString("utf8"));
1609
1807
  } catch {
1610
- throw fail2("REQUISICAO_INVALIDA", "Dados da opera\xE7\xE3o inv\xE1lidos ou acima do limite.");
1808
+ throw fail3("REQUISICAO_INVALIDA", "Dados da opera\xE7\xE3o inv\xE1lidos ou acima do limite.");
1611
1809
  }
1612
1810
  return new Promise((resolve5, reject) => {
1613
1811
  if (closed) {
@@ -1617,7 +1815,7 @@ function criarEmissor(options) {
1617
1815
  }
1618
1816
  if (busy && queue.length >= capacity) {
1619
1817
  bytes.fill(0);
1620
- reject(fail2("FILA_CHEIA", "A fila fiscal est\xE1 cheia."));
1818
+ reject(fail3("FILA_CHEIA", "A fila fiscal est\xE1 cheia."));
1621
1819
  return;
1622
1820
  }
1623
1821
  const item = { req, bytes, signal: operation.signal, resolve: resolve5, reject };
@@ -1627,7 +1825,7 @@ function criarEmissor(options) {
1627
1825
  queue.splice(i, 1);
1628
1826
  bytes.fill(0);
1629
1827
  operation.signal?.removeEventListener("abort", item.abort);
1630
- reject(fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o."));
1828
+ reject(fail3("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o."));
1631
1829
  }
1632
1830
  };
1633
1831
  operation.signal?.addEventListener("abort", item.abort, { once: true });
@@ -1637,47 +1835,48 @@ function criarEmissor(options) {
1637
1835
  });
1638
1836
  }
1639
1837
  const xmlData = (xml) => {
1640
- if (typeof xml !== "string" || !xml.trim() || Buffer.byteLength(xml, "utf8") > 2 * 1024 * 1024) throw fail2("XML_INVALIDO", "XML vazio ou acima do limite.", void 0, false, { campo: "xml" });
1838
+ if (typeof xml !== "string" || !xml.trim() || Buffer.byteLength(xml, "utf8") > 2 * 1024 * 1024) throw fail3("XML_INVALIDO", "XML vazio ou acima do limite.", void 0, false, { campo: "xml" });
1641
1839
  return { xmlBase64: Buffer.from(xml, "utf8").toString("base64") };
1642
1840
  };
1643
1841
  const checkKey = (key) => {
1644
- if (typeof key !== "string" || !/^\d{44}$/.test(key)) throw fail2("CHAVE_INVALIDA", "Chave fiscal inv\xE1lida.", void 0, false, { campo: "chave" });
1842
+ if (typeof key !== "string" || !/^\d{44}$/.test(key)) throw fail3("CHAVE_INVALIDA", "Chave fiscal inv\xE1lida.", void 0, false, { campo: "chave" });
1645
1843
  };
1646
1844
  const reason = (value) => {
1647
- if (typeof value !== "string" || value.length < 15 || value.length > 255) throw fail2("JUSTIFICATIVA_INVALIDA", "Justificativa deve ter de 15 a 255 caracteres.", void 0, false, { campo: "justificativa" });
1845
+ if (typeof value !== "string" || value.length < 15 || value.length > 255) throw fail3("JUSTIFICATIVA_INVALIDA", "Justificativa deve ter de 15 a 255 caracteres.", void 0, false, { campo: "justificativa" });
1648
1846
  };
1649
1847
  const checkObject = (data, campo) => {
1650
- if (!plain(data)) throw fail2("OPERACAO_INVALIDA", "Informe os par\xE2metros da opera\xE7\xE3o como objeto.", void 0, false, { campo });
1848
+ if (!plain(data)) throw fail3("OPERACAO_INVALIDA", "Informe os par\xE2metros da opera\xE7\xE3o como objeto.", void 0, false, { campo });
1651
1849
  };
1652
1850
  return {
1653
1851
  gerarXml: (documento, op) => request("gerarXml", { documento }, op),
1654
1852
  validar: (xml, op) => request("validar", xmlData(xml), op),
1655
1853
  assinar: (xml, op) => request("assinar", xmlData(xml), op),
1656
1854
  transmitir: (xml, op) => request("transmitir", xmlData(xml), op),
1855
+ recuperarXml: (xmlAssinado, opcoes) => request("recuperarXml", xmlData(xmlAssinado), opcoes),
1657
1856
  consultar: (consulta, op) => {
1658
1857
  checkObject(consulta, "consulta");
1659
1858
  checkKey(consulta.chave);
1660
- if (consulta.recibo !== void 0 && (typeof consulta.recibo !== "string" || !/^\d{15}$/.test(consulta.recibo))) throw fail2("RECIBO_INVALIDO", "Recibo inv\xE1lido.", void 0, false, { campo: "recibo" });
1661
- return request("consultar", consulta, op);
1859
+ if (consulta.recibo !== void 0 && (typeof consulta.recibo !== "string" || !/^\d{15}$/.test(consulta.recibo))) throw fail3("RECIBO_INVALIDO", "Recibo inv\xE1lido.", void 0, false, { campo: "recibo" });
1860
+ return request("consultar", { chave: consulta.chave, ...consulta.recibo !== void 0 ? { recibo: consulta.recibo } : {} }, op);
1662
1861
  },
1663
1862
  cancelar: (data, op) => {
1664
1863
  checkObject(data, "cancelamento");
1665
1864
  checkKey(data.chave);
1666
1865
  reason(data.justificativa);
1667
- if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw fail2("PROTOCOLO_INVALIDO", "Protocolo inv\xE1lido.", void 0, false, { campo: "protocolo" });
1668
- return request("cancelar", data, op);
1866
+ if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw fail3("PROTOCOLO_INVALIDO", "Protocolo inv\xE1lido.", void 0, false, { campo: "protocolo" });
1867
+ return request("cancelar", { chave: data.chave, protocolo: data.protocolo, justificativa: data.justificativa }, op);
1669
1868
  },
1670
1869
  cartaCorrecao: (data, op) => {
1671
1870
  checkObject(data, "cartaCorrecao");
1672
- if (cfg.modelo !== 55) throw fail2("OPERACAO_NAO_SUPORTADA", "Carta de corre\xE7\xE3o exige NF-e modelo 55.");
1871
+ if (cfg.modelo !== 55) throw fail3("OPERACAO_NAO_SUPORTADA", "Carta de corre\xE7\xE3o exige NF-e modelo 55.");
1673
1872
  checkKey(data.chave);
1674
- if (typeof data.correcao !== "string" || data.correcao.length < 15 || data.correcao.length > 1e3 || !Number.isInteger(data.sequenciaEvento ?? 1) || (data.sequenciaEvento ?? 1) < 1 || (data.sequenciaEvento ?? 1) > 20) throw fail2("CORRECAO_INVALIDA", "Dados da carta de corre\xE7\xE3o inv\xE1lidos.", void 0, false, { campo: "cartaCorrecao" });
1675
- return request("cartaCorrecao", { ...data, sequenciaEvento: data.sequenciaEvento ?? 1 }, op);
1873
+ if (typeof data.correcao !== "string" || data.correcao.length < 15 || data.correcao.length > 1e3 || !Number.isInteger(data.sequenciaEvento ?? 1) || (data.sequenciaEvento ?? 1) < 1 || (data.sequenciaEvento ?? 1) > 20) throw fail3("CORRECAO_INVALIDA", "Dados da carta de corre\xE7\xE3o inv\xE1lidos.", void 0, false, { campo: "cartaCorrecao" });
1874
+ return request("cartaCorrecao", { chave: data.chave, correcao: data.correcao, sequenciaEvento: data.sequenciaEvento ?? 1 }, op);
1676
1875
  },
1677
1876
  inutilizar: (data, op) => {
1678
1877
  checkObject(data, "inutilizacao");
1679
1878
  reason(data.justificativa);
1680
- if (!Number.isInteger(data.ano) || data.ano < 0 || data.ano > 99 || !Number.isInteger(data.serie) || data.serie < 0 || data.serie > 999 || !Number.isInteger(data.numeroInicial) || data.numeroInicial < 1 || !Number.isInteger(data.numeroFinal) || data.numeroFinal < data.numeroInicial || data.numeroFinal > 999999999) throw fail2("INUTILIZACAO_INVALIDA", "Faixa de inutiliza\xE7\xE3o inv\xE1lida.", void 0, false, { campo: "inutilizacao" });
1879
+ if (!Number.isInteger(data.ano) || data.ano < 0 || data.ano > 99 || !Number.isInteger(data.serie) || data.serie < 0 || data.serie > 999 || !Number.isInteger(data.numeroInicial) || data.numeroInicial < 1 || !Number.isInteger(data.numeroFinal) || data.numeroFinal < data.numeroInicial || data.numeroFinal > 999999999) throw fail3("INUTILIZACAO_INVALIDA", "Faixa de inutiliza\xE7\xE3o inv\xE1lida.", void 0, false, { campo: "inutilizacao" });
1681
1880
  return request("inutilizar", { inutilizacao: { ano: data.ano, serie: data.serie, numeroInicial: data.numeroInicial, numeroFinal: data.numeroFinal }, justificativa: data.justificativa }, op);
1682
1881
  },
1683
1882
  async fechar() {
@@ -1695,7 +1894,7 @@ function criarEmissor(options) {
1695
1894
  }
1696
1895
  };
1697
1896
  }
1698
- var STATES, UFS, MAX_BYTES, MAX_TEARDOWN_MS, plain, validContract, fail2;
1897
+ var STATES, UFS, MAX_BYTES, MAX_TEARDOWN_MS, plain, validContract, fail3;
1699
1898
  var init_runtime = __esm({
1700
1899
  "src/runtime.ts"() {
1701
1900
  "use strict";
@@ -1703,13 +1902,13 @@ var init_runtime = __esm({
1703
1902
  init_diagnostics();
1704
1903
  init_types();
1705
1904
  init_diagnostics();
1706
- STATES = /* @__PURE__ */ new Set(["DENEGADO", "XML_GERADO", "VALIDADO", "ASSINADO", "AUTORIZADO", "REJEITADO", "PENDENTE", "INDETERMINADO", "CONSULTADO", "CANCELADO", "EVENTO_REGISTRADO", "INUTILIZADO", "ERRO"]);
1905
+ STATES = /* @__PURE__ */ new Set(["DENEGADO", "XML_GERADO", "VALIDADO", "ASSINADO", "XML_RECUPERADO", "AUTORIZADO", "REJEITADO", "PENDENTE", "INDETERMINADO", "CONSULTADO", "CANCELADO", "EVENTO_REGISTRADO", "INUTILIZADO", "ERRO"]);
1707
1906
  UFS = new Set("AC AL AP AM BA CE DF ES GO MA MT MS MG PA PB PR PE PI RJ RN RS RO RR SC SP SE TO".split(" "));
1708
1907
  MAX_BYTES = 8 * 1024 * 1024;
1709
1908
  MAX_TEARDOWN_MS = 1e3;
1710
1909
  plain = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
1711
1910
  validContract = (v) => plain(v) && Number.isInteger(v.sourceRevision) && Number(v.sourceRevision) > 0 && typeof v.contractHash === "string" && /^[a-f0-9]{64}$/.test(v.contractHash);
1712
- fail2 = (code, message, req, unknown = false, detalhes) => new ErroAcbrNode(code, message, unknown, req?.comando === "transmitir" ? req.xmlBase64 : void 0, { ...req ? { etapa: etapaDaOperacao(req.comando) } : {}, ...detalhes });
1911
+ fail3 = (code, message, req, unknown = false, detalhes) => new ErroAcbrNode(code, message, unknown, req?.comando === "transmitir" ? req.xmlBase64 : void 0, { ...req ? { etapa: etapaDaOperacao(req.comando) } : {}, ...detalhes });
1713
1912
  }
1714
1913
  });
1715
1914
 
@@ -1881,7 +2080,7 @@ var init_offline_check = __esm({
1881
2080
  import { realpathSync } from "node:fs";
1882
2081
  import { access as access4 } from "node:fs/promises";
1883
2082
  import { resolve as resolve4 } from "node:path";
1884
- import { fileURLToPath as fileURLToPath3 } from "node:url";
2083
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
1885
2084
 
1886
2085
  // src/contract-help.ts
1887
2086
  import { createHash } from "node:crypto";
@@ -1966,8 +2165,8 @@ var fail = (message = "Os metadados do contrato s\xE3o inv\xE1lidos.") => {
1966
2165
  function validateContractMetadata(value) {
1967
2166
  const metadata = value;
1968
2167
  if (!metadata || metadata.formatVersion !== 1 || !Number.isSafeInteger(metadata.sourceRevision) || metadata.sourceRevision < 1 || !sha256.test(metadata.sourceHash ?? "") || !sha256.test(metadata.contractHash ?? "") || metadata.ir?.schemaVersion !== 1 || !identifier.test(metadata.ir.root ?? "") || !Array.isArray(metadata.ir.types) || metadata.ir.types.length === 0) fail();
1969
- const digest = createHash("sha256").update(JSON.stringify({ sourceRevision: metadata.sourceRevision, sourceHash: metadata.sourceHash, ir: metadata.ir })).digest("hex");
1970
- if (digest !== metadata.contractHash) fail("O hash dos metadados diverge do contrato gerado.");
2168
+ const digest2 = createHash("sha256").update(JSON.stringify({ sourceRevision: metadata.sourceRevision, sourceHash: metadata.sourceHash, ir: metadata.ir })).digest("hex");
2169
+ if (digest2 !== metadata.contractHash) fail("O hash dos metadados diverge do contrato gerado.");
1971
2170
  const types = /* @__PURE__ */ new Map();
1972
2171
  for (const node of metadata.ir.types) {
1973
2172
  if (!node || typeof node.name !== "string" || !identifier.test(node.name) || types.has(node.name) || !["object", "list", "enum"].includes(node.kind)) fail();
@@ -2172,13 +2371,13 @@ async function main(args = process.argv.slice(2), io = process, dependencies = {
2172
2371
  jsonTag = options.json;
2173
2372
  if (options.command.length !== 3) throw new FieldHelpError("USO_INVALIDO", "Use acbr-node help TAG caminho [--json].");
2174
2373
  if (options.revision !== void 0 || args.includes("--config")) throw new FieldHelpError("USO_INVALIDO", "help TAG usa o contrato instalado e n\xE3o aceita --config ou --revision.");
2175
- const description = await describeInstalledField(options.command[2], dependencies.contractRoot ?? fileURLToPath3(new URL("../", import.meta.url)));
2374
+ const description = await describeInstalledField(options.command[2], dependencies.contractRoot ?? fileURLToPath4(new URL("../", import.meta.url)));
2176
2375
  output(description, formatFieldDescription(description));
2177
2376
  return 0;
2178
2377
  }
2179
2378
  if (command === "init") {
2180
2379
  const { initializeConfig: initializeConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
2181
- const config2 = await initializeConfig2(options.config, options.revision, fileURLToPath3(new URL("../", import.meta.url)));
2380
+ const config2 = await initializeConfig2(options.config, options.revision, fileURLToPath4(new URL("../", import.meta.url)));
2182
2381
  output({ configPath: config2.configPath }, `Configura\xE7\xE3o criada: ${config2.configPath}
2183
2382
  Pr\xF3ximo passo: acbr-node source update.`);
2184
2383
  return 0;
@@ -2250,7 +2449,7 @@ function isDirectInvocation() {
2250
2449
  const entry = process.argv[1];
2251
2450
  if (!entry) return false;
2252
2451
  try {
2253
- return realpathSync(resolve4(entry)) === realpathSync(fileURLToPath3(import.meta.url));
2452
+ return realpathSync(resolve4(entry)) === realpathSync(fileURLToPath4(import.meta.url));
2254
2453
  } catch {
2255
2454
  return false;
2256
2455
  }