cosmemilton-acbr-node 0.2.0 → 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/README.md +4 -4
- package/dist/cli.js +339 -166
- package/dist/cli.js.map +4 -4
- package/docs/DEPENDENCIAS-NATIVAS.md +10 -0
- package/docs/examples/recuperar-xml.mjs +54 -54
- 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/package.json +78 -76
- package/scripts/runtime-license-inventory.d.mts +5 -0
- package/scripts/runtime-license-inventory.mjs +161 -0
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,
|
|
@@ -651,7 +821,8 @@ Log completo: ${logPath}`, { cause: compilation });
|
|
|
651
821
|
systemDependencies,
|
|
652
822
|
...options.testOnly ? { testOnly: true } : {}
|
|
653
823
|
};
|
|
654
|
-
await
|
|
824
|
+
await auditRuntimeLicenses(stage, manifest);
|
|
825
|
+
await writeFile4(join2(stage, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
655
826
|
`);
|
|
656
827
|
await replaceRuntime(stage, target);
|
|
657
828
|
return manifest;
|
|
@@ -660,15 +831,15 @@ Log completo: ${logPath}`, { cause: compilation });
|
|
|
660
831
|
}
|
|
661
832
|
}
|
|
662
833
|
async function copyNativeSources(source, target) {
|
|
663
|
-
await
|
|
664
|
-
for (const entry of await
|
|
834
|
+
await mkdir4(target, { recursive: true });
|
|
835
|
+
for (const entry of await readdir4(source, { withFileTypes: true })) {
|
|
665
836
|
if (entry.isDirectory() && !entry.name.startsWith(".")) await copyNativeSources(join2(source, entry.name), join2(target, entry.name));
|
|
666
837
|
else if (entry.isFile() && /\.(pas|lpr|inc|lpi)$/i.test(entry.name)) await copyFile2(join2(source, entry.name), join2(target, entry.name));
|
|
667
838
|
}
|
|
668
839
|
}
|
|
669
840
|
async function copyTree(source, target) {
|
|
670
|
-
await
|
|
671
|
-
for (const entry of await
|
|
841
|
+
await mkdir4(target, { recursive: true });
|
|
842
|
+
for (const entry of await readdir4(source, { withFileTypes: true })) {
|
|
672
843
|
if (entry.isSymbolicLink()) throw new Error(`Arquivo de distribui\xE7\xE3o n\xE3o pode ser link: ${entry.name}.`);
|
|
673
844
|
if (entry.isDirectory()) await copyTree(join2(source, entry.name), join2(target, entry.name));
|
|
674
845
|
else if (entry.isFile()) await copyFile2(join2(source, entry.name), join2(target, entry.name));
|
|
@@ -690,12 +861,13 @@ async function checkBuild(config) {
|
|
|
690
861
|
const lock = await verifySource(config);
|
|
691
862
|
const generated = await generatedManifest(config);
|
|
692
863
|
const directory = runtimeDirectory(config);
|
|
693
|
-
const manifest = JSON.parse(await
|
|
864
|
+
const manifest = JSON.parse(await readFile5(join2(directory, "manifest.json"), "utf8"));
|
|
694
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.");
|
|
695
|
-
for (const [
|
|
696
|
-
if (
|
|
697
|
-
if (await fileHash(join2(directory,
|
|
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}.`);
|
|
698
869
|
}
|
|
870
|
+
await auditRuntimeLicenses(directory, manifest);
|
|
699
871
|
return manifest;
|
|
700
872
|
}
|
|
701
873
|
async function doctor(config) {
|
|
@@ -733,8 +905,8 @@ async function doctor(config) {
|
|
|
733
905
|
return items;
|
|
734
906
|
}
|
|
735
907
|
async function copyCompilerLicenses(config, stage, lazarus) {
|
|
736
|
-
const packagedLazarus =
|
|
737
|
-
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));
|
|
738
910
|
const notices = {};
|
|
739
911
|
async function copyNotice(name, candidates2) {
|
|
740
912
|
for (const source of candidates2) if (await exists(source)) {
|
|
@@ -757,11 +929,11 @@ async function copyCompilerLicenses(config, stage, lazarus) {
|
|
|
757
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"];
|
|
758
930
|
for (const directory of candidates) {
|
|
759
931
|
if (!await exists(directory)) continue;
|
|
760
|
-
for (const name of await
|
|
932
|
+
for (const name of await readdir4(directory)) {
|
|
761
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}`));
|
|
762
934
|
}
|
|
763
935
|
}
|
|
764
|
-
await
|
|
936
|
+
await writeFile4(join2(stage, "licenses/toolchain-notices.json"), `${JSON.stringify(notices, null, 2)}
|
|
765
937
|
`);
|
|
766
938
|
}
|
|
767
939
|
var REQUIRED_DYNAMIC, CORE_SYSTEM;
|
|
@@ -769,6 +941,7 @@ var init_native_build = __esm({
|
|
|
769
941
|
"src/native-build.ts"() {
|
|
770
942
|
"use strict";
|
|
771
943
|
init_source();
|
|
944
|
+
init_runtime_license_inventory();
|
|
772
945
|
REQUIRED_DYNAMIC = ["libssl.so.3", "libcrypto.so.3", "libxml2.so.2"];
|
|
773
946
|
CORE_SYSTEM = /^(?:lib(?:c|m|pthread|dl|rt|resolv|anl|util)\.so(?:\.|$)|ld-linux|linux-vdso)/;
|
|
774
947
|
}
|
|
@@ -786,12 +959,12 @@ __export(generator_exports, {
|
|
|
786
959
|
renderPascal: () => renderPascal,
|
|
787
960
|
renderTypeScript: () => renderTypeScript
|
|
788
961
|
});
|
|
789
|
-
import { createHash as
|
|
962
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
790
963
|
import { execFile } from "node:child_process";
|
|
791
964
|
import { promisify } from "node:util";
|
|
792
|
-
import { mkdir as
|
|
793
|
-
import
|
|
794
|
-
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";
|
|
795
968
|
function buildModelIR(raw) {
|
|
796
969
|
const declarations = /* @__PURE__ */ new Map();
|
|
797
970
|
for (const unit of raw.units) for (const type of unit.types) declarations.set((unit.name + "." + type.name).toLowerCase(), { unit, type });
|
|
@@ -1087,54 +1260,54 @@ function renderClientIndex() {
|
|
|
1087
1260
|
async function fingerprint(dir) {
|
|
1088
1261
|
const files = [];
|
|
1089
1262
|
async function walk(d) {
|
|
1090
|
-
for (const entry of await
|
|
1091
|
-
const f =
|
|
1263
|
+
for (const entry of await readdir5(d, { withFileTypes: true })) {
|
|
1264
|
+
const f = path3.join(d, entry.name);
|
|
1092
1265
|
if (entry.isDirectory()) await walk(f);
|
|
1093
1266
|
else if (/\.(pas|pp|inc|xsd)$/i.test(entry.name)) files.push(f);
|
|
1094
1267
|
}
|
|
1095
1268
|
}
|
|
1096
1269
|
await walk(dir);
|
|
1097
|
-
const
|
|
1270
|
+
const digest2 = createHash4("sha256");
|
|
1098
1271
|
for (const f of files.sort()) {
|
|
1099
|
-
|
|
1100
|
-
|
|
1272
|
+
digest2.update(path3.relative(dir, f).replaceAll("\\", "/"));
|
|
1273
|
+
digest2.update(await readFile6(f));
|
|
1101
1274
|
}
|
|
1102
|
-
return
|
|
1275
|
+
return digest2.digest("hex");
|
|
1103
1276
|
}
|
|
1104
1277
|
async function generateModel(options) {
|
|
1105
|
-
const root =
|
|
1106
|
-
const models =
|
|
1107
|
-
await Promise.all([
|
|
1108
|
-
const extractor = options.extractorPath ??
|
|
1109
|
-
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" : ""));
|
|
1110
1283
|
try {
|
|
1111
1284
|
await execute(options.fpcPath ?? "fpc", ["-Mobjfpc", "-Sh", "-FU" + bin, "-FE" + bin, extractor], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
|
|
1112
|
-
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 });
|
|
1113
1286
|
} catch (error) {
|
|
1114
1287
|
const e = error;
|
|
1115
1288
|
throw new Error("Extra\xE7\xE3o FCL-passrc falhou: " + (e.stderr ?? "") + (e.stdout ?? "") + e.message);
|
|
1116
1289
|
}
|
|
1117
|
-
const raw = JSON.parse(await
|
|
1290
|
+
const raw = JSON.parse(await readFile6(path3.join(cache, "raw-model.json"), "utf8"));
|
|
1118
1291
|
const ir = buildModelIR(raw), sourceRevision = Number(options.revision);
|
|
1119
1292
|
if (!Number.isSafeInteger(sourceRevision) || sourceRevision < 1) throw new Error("Revis\xE3o SVN inv\xE1lida");
|
|
1120
1293
|
const sourceHash = options.sourceHash ?? await fingerprint(options.acbrRoot), contractHash = hash(stable({ sourceRevision, sourceHash, ir }));
|
|
1121
1294
|
let previous;
|
|
1122
1295
|
try {
|
|
1123
|
-
previous = JSON.parse(await
|
|
1296
|
+
previous = JSON.parse(await readFile6(path3.join(cache, "model.ir.json"), "utf8"));
|
|
1124
1297
|
} catch (error) {
|
|
1125
1298
|
if (error.code !== "ENOENT") throw error;
|
|
1126
1299
|
}
|
|
1127
|
-
const report = compareContracts(previous, ir), reportPath =
|
|
1128
|
-
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("\\", "/"));
|
|
1129
1302
|
const content = [renderTypeScript(ir, sourceRevision, contractHash), renderClientIndex(), renderPascal(ir, sourceRevision, contractHash)];
|
|
1130
1303
|
const fileHashes = Object.fromEntries(files.map((file, index) => [file, hash(content[index])]));
|
|
1131
|
-
const metadataPath =
|
|
1304
|
+
const metadataPath = path3.join(models, "contract.json"), metadataContent = renderContractMetadata(ir, sourceRevision, sourceHash, contractHash);
|
|
1132
1305
|
await Promise.all([
|
|
1133
|
-
...files.map((file, index) =>
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
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")
|
|
1138
1311
|
]);
|
|
1139
1312
|
return { contractHash, sourceHash, models: ir.types.length, reportPath, manifestPath, metadataPath };
|
|
1140
1313
|
}
|
|
@@ -1169,7 +1342,7 @@ var init_generator = __esm({
|
|
|
1169
1342
|
ttime: { kind: "datetime" }
|
|
1170
1343
|
};
|
|
1171
1344
|
stable = (value) => JSON.stringify(value);
|
|
1172
|
-
hash = (value) =>
|
|
1345
|
+
hash = (value) => createHash4("sha256").update(value).digest("hex");
|
|
1173
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";
|
|
1174
1347
|
}
|
|
1175
1348
|
});
|
|
@@ -1351,64 +1524,64 @@ var init_types = __esm({
|
|
|
1351
1524
|
|
|
1352
1525
|
// src/runtime.ts
|
|
1353
1526
|
import { spawn as spawn2 } from "node:child_process";
|
|
1354
|
-
import { readFile as
|
|
1355
|
-
import
|
|
1527
|
+
import { readFile as readFile7, stat as stat3 } from "node:fs/promises";
|
|
1528
|
+
import path4 from "node:path";
|
|
1356
1529
|
import { createRequire } from "node:module";
|
|
1357
|
-
import { createHash as
|
|
1530
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
1358
1531
|
import { TextDecoder } from "node:util";
|
|
1359
1532
|
function confined(root, relative3) {
|
|
1360
|
-
const file =
|
|
1361
|
-
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.");
|
|
1362
1535
|
return file;
|
|
1363
1536
|
}
|
|
1364
1537
|
async function resolveRuntime(directory, contract) {
|
|
1365
|
-
if (!validContract(contract)) throw
|
|
1538
|
+
if (!validContract(contract)) throw fail3("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1366
1539
|
let root = directory;
|
|
1367
1540
|
if (!root) {
|
|
1368
|
-
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.");
|
|
1369
1542
|
try {
|
|
1370
1543
|
const require2 = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
|
|
1371
|
-
root =
|
|
1544
|
+
root = path4.join(path4.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
|
|
1372
1545
|
} catch {
|
|
1373
|
-
throw
|
|
1546
|
+
throw fail3("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
|
|
1374
1547
|
}
|
|
1375
1548
|
}
|
|
1376
|
-
root =
|
|
1549
|
+
root = path4.resolve(root);
|
|
1377
1550
|
let m;
|
|
1378
1551
|
try {
|
|
1379
|
-
m = JSON.parse(await
|
|
1552
|
+
m = JSON.parse(await readFile7(path4.join(root, "manifest.json"), "utf8"));
|
|
1380
1553
|
} catch {
|
|
1381
|
-
throw
|
|
1554
|
+
throw fail3("RUNTIME_AUSENTE", "Manifesto do runtime n\xE3o encontrado.");
|
|
1382
1555
|
}
|
|
1383
|
-
if (!validContract(m) || m.formatVersion !== 1 || !plain(m.files) || typeof m.executable !== "string" || m.platform !== process.platform || m.arch !== process.arch) throw
|
|
1384
|
-
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
|
|
1385
|
-
if (m.sourceRevision !== contract.sourceRevision || m.contractHash !== contract.contractHash) throw
|
|
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.");
|
|
1386
1559
|
for (const [name, hash2] of Object.entries(m.files)) {
|
|
1387
|
-
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.");
|
|
1388
1561
|
const file = confined(root, name);
|
|
1389
1562
|
let data;
|
|
1390
1563
|
try {
|
|
1391
1564
|
if (!(await stat3(file)).isFile()) throw Error();
|
|
1392
|
-
data = await
|
|
1565
|
+
data = await readFile7(file);
|
|
1393
1566
|
} catch {
|
|
1394
|
-
throw
|
|
1567
|
+
throw fail3("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
|
|
1395
1568
|
}
|
|
1396
|
-
if (
|
|
1569
|
+
if (createHash5("sha256").update(data).digest("hex") !== hash2) throw fail3("RUNTIME_ALTERADO", "O runtime n\xE3o corresponde ao manifesto distribu\xEDdo.");
|
|
1397
1570
|
}
|
|
1398
|
-
if (!m.files[m.executable]) throw
|
|
1571
|
+
if (!m.files[m.executable]) throw fail3("RUNTIME_INVALIDO", "O execut\xE1vel n\xE3o consta no invent\xE1rio.");
|
|
1399
1572
|
return { directory: root, executable: confined(root, m.executable), capabilities: new Set(m.capabilities ?? []) };
|
|
1400
1573
|
}
|
|
1401
1574
|
function criarEmissor(options) {
|
|
1402
|
-
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 });
|
|
1403
1576
|
if (!plain(options)) throw configFail();
|
|
1404
1577
|
if (typeof options.cnpj !== "string" || !/^\d{14}$/.test(options.cnpj)) throw configFail("cnpj");
|
|
1405
1578
|
if (typeof options.uf !== "string" || !UFS.has(options.uf)) throw configFail("uf");
|
|
1406
1579
|
if (![55, 65].includes(options.modelo)) throw configFail("modelo");
|
|
1407
1580
|
if (![1, 2].includes(options.ambiente)) throw configFail("ambiente");
|
|
1408
|
-
if (!validContract(options.contrato)) throw
|
|
1581
|
+
if (!validContract(options.contrato)) throw fail3("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1409
1582
|
const cert = options.certificado;
|
|
1410
|
-
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
|
|
1411
|
-
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" });
|
|
1412
1585
|
if (options.runtimeDirectory !== void 0 && (typeof options.runtimeDirectory !== "string" || !options.runtimeDirectory)) throw configFail("runtimeDirectory");
|
|
1413
1586
|
if (options.validaDocumento !== void 0 && typeof options.validaDocumento !== "function" || options.criaProcesso !== void 0 && typeof options.criaProcesso !== "function") throw configFail();
|
|
1414
1587
|
const cfg = { cnpj: options.cnpj, uf: options.uf, modelo: options.modelo, ambiente: options.ambiente, csc: options.csc ? { ...options.csc } : void 0 };
|
|
@@ -1422,7 +1595,7 @@ function criarEmissor(options) {
|
|
|
1422
1595
|
let runtimePromise, closed = false, teardownFailed = false, current;
|
|
1423
1596
|
const queue = [];
|
|
1424
1597
|
const closedError = () => {
|
|
1425
|
-
const error =
|
|
1598
|
+
const error = fail3("EMISSOR_FECHADO", "Emissor encerrado.");
|
|
1426
1599
|
if (teardownFailed) error.anotarFalhaLimpeza();
|
|
1427
1600
|
return error;
|
|
1428
1601
|
};
|
|
@@ -1434,10 +1607,10 @@ function criarEmissor(options) {
|
|
|
1434
1607
|
}
|
|
1435
1608
|
};
|
|
1436
1609
|
async function execute2(item) {
|
|
1437
|
-
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.");
|
|
1438
1611
|
const runtime = await (runtimePromise ??= resolveRuntime(options.runtimeDirectory, contract));
|
|
1439
|
-
if (item.req.comando === "recuperarXml" && !runtime.capabilities.has("recuperarXml")) throw
|
|
1440
|
-
if (closed || item.signal?.aborted) throw
|
|
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.");
|
|
1441
1614
|
return await new Promise((done, rejectExecution) => {
|
|
1442
1615
|
let stopError;
|
|
1443
1616
|
let child, finished = false, started = false, sending = false, total = 0, rest = Buffer.alloc(0), result;
|
|
@@ -1476,7 +1649,7 @@ function criarEmissor(options) {
|
|
|
1476
1649
|
};
|
|
1477
1650
|
const teardownFallback = () => {
|
|
1478
1651
|
if (finished) return;
|
|
1479
|
-
stopError ??=
|
|
1652
|
+
stopError ??= fail3("FALHA_MOTOR", "O motor n\xE3o foi encerrado.", item.req, uncertain());
|
|
1480
1653
|
stopError.anotarFalhaLimpeza();
|
|
1481
1654
|
teardownFailed = true;
|
|
1482
1655
|
closed = true;
|
|
@@ -1487,7 +1660,7 @@ function criarEmissor(options) {
|
|
|
1487
1660
|
};
|
|
1488
1661
|
const stop = (code, message) => {
|
|
1489
1662
|
if (finished || stopError) return;
|
|
1490
|
-
stopError =
|
|
1663
|
+
stopError = fail3(code, message, item.req, uncertain());
|
|
1491
1664
|
if (!child?.pid) {
|
|
1492
1665
|
finish(stopError);
|
|
1493
1666
|
detachOwnedChild();
|
|
@@ -1505,20 +1678,20 @@ function criarEmissor(options) {
|
|
|
1505
1678
|
current = { stop: () => stop("EMISSOR_FECHADO", "Emissor encerrado."), done: doneCurrent };
|
|
1506
1679
|
const env = {};
|
|
1507
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];
|
|
1508
|
-
if (process.platform === "linux") env.LD_LIBRARY_PATH =
|
|
1681
|
+
if (process.platform === "linux") env.LD_LIBRARY_PATH = path4.join(runtime.directory, "lib");
|
|
1509
1682
|
if (process.platform === "win32") {
|
|
1510
1683
|
const inheritedPath = env.Path ?? env.PATH ?? "";
|
|
1511
1684
|
delete env.Path;
|
|
1512
|
-
env.PATH =
|
|
1685
|
+
env.PATH = path4.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
|
|
1513
1686
|
}
|
|
1514
|
-
const modules =
|
|
1687
|
+
const modules = path4.join(runtime.directory, "ossl-modules");
|
|
1515
1688
|
env.OPENSSL_MODULES = modules;
|
|
1516
|
-
env.OPENSSL_CONF =
|
|
1689
|
+
env.OPENSSL_CONF = path4.join(runtime.directory, "openssl.cnf");
|
|
1517
1690
|
try {
|
|
1518
1691
|
child = launch(runtime.executable, ["--parent-pid", String(process.pid)], { cwd: runtime.directory, env, windowsHide: true, shell: false, stdio: ["pipe", "pipe", "pipe"] });
|
|
1519
1692
|
started = typeof child.pid === "number";
|
|
1520
1693
|
} catch {
|
|
1521
|
-
finish(
|
|
1694
|
+
finish(fail3("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.", item.req));
|
|
1522
1695
|
return;
|
|
1523
1696
|
}
|
|
1524
1697
|
item.signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -1579,7 +1752,7 @@ function criarEmissor(options) {
|
|
|
1579
1752
|
return;
|
|
1580
1753
|
}
|
|
1581
1754
|
if (code !== 0 || rest.length || !result) {
|
|
1582
|
-
finish(
|
|
1755
|
+
finish(fail3("FALHA_MOTOR", "O motor encerrou sem resposta fiscal v\xE1lida.", item.req, uncertain()));
|
|
1583
1756
|
return;
|
|
1584
1757
|
}
|
|
1585
1758
|
finish();
|
|
@@ -1608,22 +1781,22 @@ function criarEmissor(options) {
|
|
|
1608
1781
|
}
|
|
1609
1782
|
async function request(command, data, operation = {}) {
|
|
1610
1783
|
const rawOperation = operation;
|
|
1611
|
-
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" });
|
|
1612
1785
|
const signal = operation.signal;
|
|
1613
|
-
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" });
|
|
1614
1787
|
if (closed) throw closedError();
|
|
1615
|
-
if (operation.signal?.aborted) throw
|
|
1616
|
-
if (["assinar", "transmitir", "consultar", "recuperarXml", "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) });
|
|
1617
1790
|
if (command === "gerarXml") options.validaDocumento?.(data.documento);
|
|
1618
1791
|
const config = { ...cfg };
|
|
1619
1792
|
if (certificate) {
|
|
1620
1793
|
let pfx;
|
|
1621
1794
|
try {
|
|
1622
|
-
pfx = certificate.pfx ?? await
|
|
1795
|
+
pfx = certificate.pfx ?? await readFile7(certificate.arquivo);
|
|
1623
1796
|
} catch {
|
|
1624
|
-
throw
|
|
1797
|
+
throw fail3("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
|
|
1625
1798
|
}
|
|
1626
|
-
if (pfx.length > 2 * 1024 * 1024) throw
|
|
1799
|
+
if (pfx.length > 2 * 1024 * 1024) throw fail3("CERTIFICADO_EXCESSIVO", "Certificado excede o limite.");
|
|
1627
1800
|
config.certificado = { pfxBase64: pfx.toString("base64"), senha: certificate.senha };
|
|
1628
1801
|
}
|
|
1629
1802
|
let bytes, req;
|
|
@@ -1632,7 +1805,7 @@ function criarEmissor(options) {
|
|
|
1632
1805
|
if (bytes.length > bytesLimit) throw Error();
|
|
1633
1806
|
req = JSON.parse(bytes.toString("utf8"));
|
|
1634
1807
|
} catch {
|
|
1635
|
-
throw
|
|
1808
|
+
throw fail3("REQUISICAO_INVALIDA", "Dados da opera\xE7\xE3o inv\xE1lidos ou acima do limite.");
|
|
1636
1809
|
}
|
|
1637
1810
|
return new Promise((resolve5, reject) => {
|
|
1638
1811
|
if (closed) {
|
|
@@ -1642,7 +1815,7 @@ function criarEmissor(options) {
|
|
|
1642
1815
|
}
|
|
1643
1816
|
if (busy && queue.length >= capacity) {
|
|
1644
1817
|
bytes.fill(0);
|
|
1645
|
-
reject(
|
|
1818
|
+
reject(fail3("FILA_CHEIA", "A fila fiscal est\xE1 cheia."));
|
|
1646
1819
|
return;
|
|
1647
1820
|
}
|
|
1648
1821
|
const item = { req, bytes, signal: operation.signal, resolve: resolve5, reject };
|
|
@@ -1652,7 +1825,7 @@ function criarEmissor(options) {
|
|
|
1652
1825
|
queue.splice(i, 1);
|
|
1653
1826
|
bytes.fill(0);
|
|
1654
1827
|
operation.signal?.removeEventListener("abort", item.abort);
|
|
1655
|
-
reject(
|
|
1828
|
+
reject(fail3("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o."));
|
|
1656
1829
|
}
|
|
1657
1830
|
};
|
|
1658
1831
|
operation.signal?.addEventListener("abort", item.abort, { once: true });
|
|
@@ -1662,17 +1835,17 @@ function criarEmissor(options) {
|
|
|
1662
1835
|
});
|
|
1663
1836
|
}
|
|
1664
1837
|
const xmlData = (xml) => {
|
|
1665
|
-
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" });
|
|
1666
1839
|
return { xmlBase64: Buffer.from(xml, "utf8").toString("base64") };
|
|
1667
1840
|
};
|
|
1668
1841
|
const checkKey = (key) => {
|
|
1669
|
-
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" });
|
|
1670
1843
|
};
|
|
1671
1844
|
const reason = (value) => {
|
|
1672
|
-
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" });
|
|
1673
1846
|
};
|
|
1674
1847
|
const checkObject = (data, campo) => {
|
|
1675
|
-
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 });
|
|
1676
1849
|
};
|
|
1677
1850
|
return {
|
|
1678
1851
|
gerarXml: (documento, op) => request("gerarXml", { documento }, op),
|
|
@@ -1683,27 +1856,27 @@ function criarEmissor(options) {
|
|
|
1683
1856
|
consultar: (consulta, op) => {
|
|
1684
1857
|
checkObject(consulta, "consulta");
|
|
1685
1858
|
checkKey(consulta.chave);
|
|
1686
|
-
if (consulta.recibo !== void 0 && (typeof consulta.recibo !== "string" || !/^\d{15}$/.test(consulta.recibo))) throw
|
|
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" });
|
|
1687
1860
|
return request("consultar", { chave: consulta.chave, ...consulta.recibo !== void 0 ? { recibo: consulta.recibo } : {} }, op);
|
|
1688
1861
|
},
|
|
1689
1862
|
cancelar: (data, op) => {
|
|
1690
1863
|
checkObject(data, "cancelamento");
|
|
1691
1864
|
checkKey(data.chave);
|
|
1692
1865
|
reason(data.justificativa);
|
|
1693
|
-
if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw
|
|
1866
|
+
if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw fail3("PROTOCOLO_INVALIDO", "Protocolo inv\xE1lido.", void 0, false, { campo: "protocolo" });
|
|
1694
1867
|
return request("cancelar", { chave: data.chave, protocolo: data.protocolo, justificativa: data.justificativa }, op);
|
|
1695
1868
|
},
|
|
1696
1869
|
cartaCorrecao: (data, op) => {
|
|
1697
1870
|
checkObject(data, "cartaCorrecao");
|
|
1698
|
-
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.");
|
|
1699
1872
|
checkKey(data.chave);
|
|
1700
|
-
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
|
|
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" });
|
|
1701
1874
|
return request("cartaCorrecao", { chave: data.chave, correcao: data.correcao, sequenciaEvento: data.sequenciaEvento ?? 1 }, op);
|
|
1702
1875
|
},
|
|
1703
1876
|
inutilizar: (data, op) => {
|
|
1704
1877
|
checkObject(data, "inutilizacao");
|
|
1705
1878
|
reason(data.justificativa);
|
|
1706
|
-
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" });
|
|
1707
1880
|
return request("inutilizar", { inutilizacao: { ano: data.ano, serie: data.serie, numeroInicial: data.numeroInicial, numeroFinal: data.numeroFinal }, justificativa: data.justificativa }, op);
|
|
1708
1881
|
},
|
|
1709
1882
|
async fechar() {
|
|
@@ -1721,7 +1894,7 @@ function criarEmissor(options) {
|
|
|
1721
1894
|
}
|
|
1722
1895
|
};
|
|
1723
1896
|
}
|
|
1724
|
-
var STATES, UFS, MAX_BYTES, MAX_TEARDOWN_MS, plain, validContract,
|
|
1897
|
+
var STATES, UFS, MAX_BYTES, MAX_TEARDOWN_MS, plain, validContract, fail3;
|
|
1725
1898
|
var init_runtime = __esm({
|
|
1726
1899
|
"src/runtime.ts"() {
|
|
1727
1900
|
"use strict";
|
|
@@ -1735,7 +1908,7 @@ var init_runtime = __esm({
|
|
|
1735
1908
|
MAX_TEARDOWN_MS = 1e3;
|
|
1736
1909
|
plain = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
1737
1910
|
validContract = (v) => plain(v) && Number.isInteger(v.sourceRevision) && Number(v.sourceRevision) > 0 && typeof v.contractHash === "string" && /^[a-f0-9]{64}$/.test(v.contractHash);
|
|
1738
|
-
|
|
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 });
|
|
1739
1912
|
}
|
|
1740
1913
|
});
|
|
1741
1914
|
|
|
@@ -1907,7 +2080,7 @@ var init_offline_check = __esm({
|
|
|
1907
2080
|
import { realpathSync } from "node:fs";
|
|
1908
2081
|
import { access as access4 } from "node:fs/promises";
|
|
1909
2082
|
import { resolve as resolve4 } from "node:path";
|
|
1910
|
-
import { fileURLToPath as
|
|
2083
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
1911
2084
|
|
|
1912
2085
|
// src/contract-help.ts
|
|
1913
2086
|
import { createHash } from "node:crypto";
|
|
@@ -1992,8 +2165,8 @@ var fail = (message = "Os metadados do contrato s\xE3o inv\xE1lidos.") => {
|
|
|
1992
2165
|
function validateContractMetadata(value) {
|
|
1993
2166
|
const metadata = value;
|
|
1994
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();
|
|
1995
|
-
const
|
|
1996
|
-
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.");
|
|
1997
2170
|
const types = /* @__PURE__ */ new Map();
|
|
1998
2171
|
for (const node of metadata.ir.types) {
|
|
1999
2172
|
if (!node || typeof node.name !== "string" || !identifier.test(node.name) || types.has(node.name) || !["object", "list", "enum"].includes(node.kind)) fail();
|
|
@@ -2198,13 +2371,13 @@ async function main(args = process.argv.slice(2), io = process, dependencies = {
|
|
|
2198
2371
|
jsonTag = options.json;
|
|
2199
2372
|
if (options.command.length !== 3) throw new FieldHelpError("USO_INVALIDO", "Use acbr-node help TAG caminho [--json].");
|
|
2200
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.");
|
|
2201
|
-
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)));
|
|
2202
2375
|
output(description, formatFieldDescription(description));
|
|
2203
2376
|
return 0;
|
|
2204
2377
|
}
|
|
2205
2378
|
if (command === "init") {
|
|
2206
2379
|
const { initializeConfig: initializeConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2207
|
-
const config2 = await initializeConfig2(options.config, options.revision,
|
|
2380
|
+
const config2 = await initializeConfig2(options.config, options.revision, fileURLToPath4(new URL("../", import.meta.url)));
|
|
2208
2381
|
output({ configPath: config2.configPath }, `Configura\xE7\xE3o criada: ${config2.configPath}
|
|
2209
2382
|
Pr\xF3ximo passo: acbr-node source update.`);
|
|
2210
2383
|
return 0;
|
|
@@ -2276,7 +2449,7 @@ function isDirectInvocation() {
|
|
|
2276
2449
|
const entry = process.argv[1];
|
|
2277
2450
|
if (!entry) return false;
|
|
2278
2451
|
try {
|
|
2279
|
-
return realpathSync(resolve4(entry)) === realpathSync(
|
|
2452
|
+
return realpathSync(resolve4(entry)) === realpathSync(fileURLToPath4(import.meta.url));
|
|
2280
2453
|
} catch {
|
|
2281
2454
|
return false;
|
|
2282
2455
|
}
|