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.
- package/LICENSE +502 -502
- package/NOTICE +8 -8
- package/README.md +40 -11
- package/acbr.config.json +16 -16
- package/acbr.lock.json +0 -0
- package/dist/cli.js +375 -176
- package/dist/cli.js.map +4 -4
- package/dist/contract.json +0 -0
- package/dist/index.cjs +36 -11
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +36 -11
- package/dist/index.js.map +2 -2
- package/dist/runtime.cjs +36 -11
- package/dist/runtime.cjs.map +2 -2
- package/dist/runtime.js +36 -11
- package/dist/runtime.js.map +2 -2
- package/dist/types/generated/acbr/index.d.ts +1 -0
- package/dist/types/generated/acbr/models.d.ts +0 -0
- package/dist/types/src/cli.d.ts +0 -0
- package/dist/types/src/config.d.ts +0 -0
- package/dist/types/src/contract-help.d.ts +0 -0
- package/dist/types/src/diagnostics.d.ts +2 -0
- package/dist/types/src/generator.d.ts +0 -0
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/native-build.d.ts +1 -0
- package/dist/types/src/offline-check.d.ts +0 -0
- package/dist/types/src/offline-fixture.d.ts +0 -0
- package/dist/types/src/runtime.d.ts +1 -0
- package/dist/types/src/source.d.ts +0 -0
- package/dist/types/src/types.d.ts +4 -2
- package/docs/API.md +116 -90
- package/docs/ARQUITETURA.md +19 -15
- package/docs/CI.md +60 -60
- package/docs/CLI.md +1 -1
- package/docs/DEPENDENCIAS-NATIVAS.md +103 -93
- package/docs/VALIDACAO.md +67 -67
- package/docs/examples/recuperar-xml.mjs +54 -0
- package/docs/licenses/common/Apache-2.0.txt +202 -0
- package/docs/licenses/common/Artistic.txt +131 -0
- package/docs/licenses/common/GFDL-1.2.txt +397 -0
- package/docs/licenses/common/GPL-1.txt +251 -0
- package/docs/licenses/common/GPL-2.txt +339 -0
- package/docs/licenses/common/GPL-3.txt +674 -0
- package/docs/licenses/common/GPL.txt +674 -0
- package/docs/licenses/common/LGPL-2.1.txt +502 -0
- package/docs/licenses/common/LGPL-2.txt +481 -0
- package/docs/licenses/common/LGPL-3.txt +165 -0
- package/docs/licenses/common/LGPL.txt +165 -0
- package/docs/licenses/common/ORIGIN.json +208 -0
- package/docs/licenses/fpc/COPYING.FPC +25 -25
- package/docs/licenses/fpc/COPYING.GPL.txt +340 -340
- package/docs/licenses/fpc/COPYING.LGPL.txt +504 -504
- package/docs/licenses/fpc/ORIGIN.json +21 -21
- package/docs/licenses/lazarus/COPYING.LGPL.txt +481 -481
- package/docs/licenses/lazarus/COPYING.modifiedLGPL.txt +26 -26
- package/docs/licenses/lazarus/COPYING.txt +46 -46
- package/docs/licenses/lazarus/ORIGIN.json +1 -1
- package/native/NativeMotor.pas +55 -3
- package/native/NativeProtocol.pas +3 -2
- package/native/NativeRecovery.pas +274 -0
- package/native/generated/AcbrModels.pas +0 -0
- package/package.json +6 -4
- package/scripts/build-native-deps.mjs +237 -237
- package/scripts/runtime-license-inventory.d.mts +5 -0
- package/scripts/runtime-license-inventory.mjs +161 -0
- 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(
|
|
86
|
-
const configPath = resolve(
|
|
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(
|
|
102
|
-
const configPath = resolve(
|
|
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,
|
|
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) =>
|
|
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)
|
|
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
|
-
|
|
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(
|
|
213
|
+
async function fileHash(path5) {
|
|
214
214
|
const hash2 = createHash2("sha256");
|
|
215
|
-
for await (const chunk of createReadStream(
|
|
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
|
|
225
|
-
if (entry.isSymbolicLink()) throw new Error(`Fonte ACBr cont\xE9m link simb\xF3lico: ${
|
|
226
|
-
if (entry.isDirectory()) await scan(
|
|
227
|
-
else if (entry.isFile()) files[relative(directory,
|
|
228
|
-
else throw new Error(`Fonte ACBr cont\xE9m arquivo especial: ${
|
|
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 [
|
|
241
|
-
if (
|
|
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((
|
|
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
|
|
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(
|
|
584
|
+
async function exists(path5) {
|
|
416
585
|
try {
|
|
417
|
-
await access3(
|
|
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((
|
|
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
|
|
598
|
+
const path5 = join2(config.generator.outputDir, ".acbr/generated/manifest.json");
|
|
430
599
|
let value;
|
|
431
600
|
try {
|
|
432
|
-
value = JSON.parse(await
|
|
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(
|
|
447
|
-
const result = [
|
|
448
|
-
for (const entry of (await
|
|
449
|
-
if (entry.isDirectory()) result.push(...await subdirectories(join2(
|
|
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
|
|
459
|
-
if (!
|
|
460
|
-
libraries.set(name, await realpath(
|
|
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,
|
|
637
|
+
const [name, path5] = [...libraries].find(([name2]) => !inspected.has(name2));
|
|
469
638
|
inspected.add(name);
|
|
470
|
-
const dependencies = await runCommand("ldd", [
|
|
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
|
|
655
|
+
await mkdir4(licenseDir, { recursive: true });
|
|
487
656
|
const provenance = {};
|
|
488
|
-
for (const [name,
|
|
657
|
+
for (const [name, path5] of libraries) {
|
|
489
658
|
const destination = name.startsWith("ossl-modules/") ? join2(stage, name) : join2(stage, "lib", name);
|
|
490
|
-
await
|
|
491
|
-
await copyFile2(
|
|
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(
|
|
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",
|
|
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 ${
|
|
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
|
|
515
|
-
await
|
|
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
|
|
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
|
|
523
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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((
|
|
544
|
-
await
|
|
545
|
-
await
|
|
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
|
|
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
|
|
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((
|
|
581
|
-
...fontPaths.map((
|
|
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
|
|
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
|
|
759
|
+
await writeFile4(logPath, compilation.stdout + compilation.stderr);
|
|
591
760
|
} catch (error) {
|
|
592
761
|
const compilation = error;
|
|
593
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
663
|
-
for (const entry of await
|
|
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
|
|
670
|
-
for (const entry of await
|
|
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
|
|
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 [
|
|
695
|
-
if (
|
|
696
|
-
if (await fileHash(join2(directory,
|
|
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 =
|
|
736
|
-
const packagedFpc =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
792
|
-
import
|
|
793
|
-
import { fileURLToPath as
|
|
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
|
|
1090
|
-
const f =
|
|
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
|
|
1270
|
+
const digest2 = createHash4("sha256");
|
|
1097
1271
|
for (const f of files.sort()) {
|
|
1098
|
-
|
|
1099
|
-
|
|
1272
|
+
digest2.update(path3.relative(dir, f).replaceAll("\\", "/"));
|
|
1273
|
+
digest2.update(await readFile6(f));
|
|
1100
1274
|
}
|
|
1101
|
-
return
|
|
1275
|
+
return digest2.digest("hex");
|
|
1102
1276
|
}
|
|
1103
1277
|
async function generateModel(options) {
|
|
1104
|
-
const root =
|
|
1105
|
-
const models =
|
|
1106
|
-
await Promise.all([
|
|
1107
|
-
const extractor = options.extractorPath ??
|
|
1108
|
-
const executable =
|
|
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, [
|
|
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
|
|
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
|
|
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 =
|
|
1127
|
-
const files = [
|
|
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 =
|
|
1304
|
+
const metadataPath = path3.join(models, "contract.json"), metadataContent = renderContractMetadata(ir, sourceRevision, sourceHash, contractHash);
|
|
1131
1305
|
await Promise.all([
|
|
1132
|
-
...files.map((file, index) =>
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
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) =>
|
|
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
|
|
1334
|
-
import
|
|
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
|
|
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 =
|
|
1340
|
-
if (!relative3 ||
|
|
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
|
|
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
|
|
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 =
|
|
1544
|
+
root = path4.join(path4.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
|
|
1351
1545
|
} catch {
|
|
1352
|
-
throw
|
|
1546
|
+
throw fail3("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
|
|
1353
1547
|
}
|
|
1354
1548
|
}
|
|
1355
|
-
root =
|
|
1549
|
+
root = path4.resolve(root);
|
|
1356
1550
|
let m;
|
|
1357
1551
|
try {
|
|
1358
|
-
m = JSON.parse(await
|
|
1552
|
+
m = JSON.parse(await readFile7(path4.join(root, "manifest.json"), "utf8"));
|
|
1359
1553
|
} catch {
|
|
1360
|
-
throw
|
|
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
|
|
1363
|
-
if (m.
|
|
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
|
|
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
|
|
1565
|
+
data = await readFile7(file);
|
|
1371
1566
|
} catch {
|
|
1372
|
-
throw
|
|
1567
|
+
throw fail3("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
|
|
1373
1568
|
}
|
|
1374
|
-
if (
|
|
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
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
|
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 = {
|
|
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 =
|
|
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
|
|
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 (
|
|
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 ??=
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1685
|
+
env.PATH = path4.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
|
|
1490
1686
|
}
|
|
1491
|
-
const modules =
|
|
1687
|
+
const modules = path4.join(runtime.directory, "ossl-modules");
|
|
1492
1688
|
env.OPENSSL_MODULES = modules;
|
|
1493
|
-
env.OPENSSL_CONF =
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
1591
|
-
if (["assinar", "transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw
|
|
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
|
|
1795
|
+
pfx = certificate.pfx ?? await readFile7(certificate.arquivo);
|
|
1598
1796
|
} catch {
|
|
1599
|
-
throw
|
|
1797
|
+
throw fail3("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
|
|
1600
1798
|
}
|
|
1601
|
-
if (pfx.length > 2 * 1024 * 1024) throw
|
|
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(),
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1675
|
-
return request("cartaCorrecao", {
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
1970
|
-
if (
|
|
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 ??
|
|
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,
|
|
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(
|
|
2452
|
+
return realpathSync(resolve4(entry)) === realpathSync(fileURLToPath4(import.meta.url));
|
|
2254
2453
|
} catch {
|
|
2255
2454
|
return false;
|
|
2256
2455
|
}
|