cosmemilton-acbr-node 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSE +502 -502
  2. package/NOTICE +8 -8
  3. package/README.md +40 -11
  4. package/acbr.config.json +16 -16
  5. package/acbr.lock.json +0 -0
  6. package/dist/cli.js +375 -176
  7. package/dist/cli.js.map +4 -4
  8. package/dist/contract.json +0 -0
  9. package/dist/index.cjs +36 -11
  10. package/dist/index.cjs.map +2 -2
  11. package/dist/index.js +36 -11
  12. package/dist/index.js.map +2 -2
  13. package/dist/runtime.cjs +36 -11
  14. package/dist/runtime.cjs.map +2 -2
  15. package/dist/runtime.js +36 -11
  16. package/dist/runtime.js.map +2 -2
  17. package/dist/types/generated/acbr/index.d.ts +1 -0
  18. package/dist/types/generated/acbr/models.d.ts +0 -0
  19. package/dist/types/src/cli.d.ts +0 -0
  20. package/dist/types/src/config.d.ts +0 -0
  21. package/dist/types/src/contract-help.d.ts +0 -0
  22. package/dist/types/src/diagnostics.d.ts +2 -0
  23. package/dist/types/src/generator.d.ts +0 -0
  24. package/dist/types/src/index.d.ts +1 -0
  25. package/dist/types/src/native-build.d.ts +1 -0
  26. package/dist/types/src/offline-check.d.ts +0 -0
  27. package/dist/types/src/offline-fixture.d.ts +0 -0
  28. package/dist/types/src/runtime.d.ts +1 -0
  29. package/dist/types/src/source.d.ts +0 -0
  30. package/dist/types/src/types.d.ts +4 -2
  31. package/docs/API.md +116 -90
  32. package/docs/ARQUITETURA.md +19 -15
  33. package/docs/CI.md +60 -60
  34. package/docs/CLI.md +1 -1
  35. package/docs/DEPENDENCIAS-NATIVAS.md +103 -93
  36. package/docs/VALIDACAO.md +67 -67
  37. package/docs/examples/recuperar-xml.mjs +54 -0
  38. package/docs/licenses/common/Apache-2.0.txt +202 -0
  39. package/docs/licenses/common/Artistic.txt +131 -0
  40. package/docs/licenses/common/GFDL-1.2.txt +397 -0
  41. package/docs/licenses/common/GPL-1.txt +251 -0
  42. package/docs/licenses/common/GPL-2.txt +339 -0
  43. package/docs/licenses/common/GPL-3.txt +674 -0
  44. package/docs/licenses/common/GPL.txt +674 -0
  45. package/docs/licenses/common/LGPL-2.1.txt +502 -0
  46. package/docs/licenses/common/LGPL-2.txt +481 -0
  47. package/docs/licenses/common/LGPL-3.txt +165 -0
  48. package/docs/licenses/common/LGPL.txt +165 -0
  49. package/docs/licenses/common/ORIGIN.json +208 -0
  50. package/docs/licenses/fpc/COPYING.FPC +25 -25
  51. package/docs/licenses/fpc/COPYING.GPL.txt +340 -340
  52. package/docs/licenses/fpc/COPYING.LGPL.txt +504 -504
  53. package/docs/licenses/fpc/ORIGIN.json +21 -21
  54. package/docs/licenses/lazarus/COPYING.LGPL.txt +481 -481
  55. package/docs/licenses/lazarus/COPYING.modifiedLGPL.txt +26 -26
  56. package/docs/licenses/lazarus/COPYING.txt +46 -46
  57. package/docs/licenses/lazarus/ORIGIN.json +1 -1
  58. package/native/NativeMotor.pas +55 -3
  59. package/native/NativeProtocol.pas +3 -2
  60. package/native/NativeRecovery.pas +274 -0
  61. package/native/generated/AcbrModels.pas +0 -0
  62. package/package.json +6 -4
  63. package/scripts/build-native-deps.mjs +237 -237
  64. package/scripts/runtime-license-inventory.d.mts +5 -0
  65. package/scripts/runtime-license-inventory.mjs +161 -0
  66. package/tools/extract-model.lpr +119 -119
@@ -1,237 +1,237 @@
1
- #!/usr/bin/env node
2
- // Build only freely available Windows x64 dependencies. Run on Linux/WSL.
3
- import { spawn } from 'node:child_process';
4
- import { createHash } from 'node:crypto';
5
- import { createReadStream, createWriteStream } from 'node:fs';
6
- import { access, copyFile, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
7
- import { availableParallelism } from 'node:os';
8
- import { dirname, join, relative, resolve } from 'node:path';
9
- import { fileURLToPath } from 'node:url';
10
-
11
- const sources = [
12
- {
13
- name: 'openssl', version: '3.5.9', file: 'openssl-3.5.9.tar.gz',
14
- url: 'https://github.com/openssl/openssl/releases/download/openssl-3.5.9/openssl-3.5.9.tar.gz',
15
- checksumUrl: 'https://github.com/openssl/openssl/releases/download/openssl-3.5.9/openssl-3.5.9.tar.gz.sha256',
16
- sha256: '603f5602e2eef00d77fbd429d34dcd5822bb301757a1bc9cdb24c670f1eb859a',
17
- license: 'Apache-2.0',
18
- },
19
- {
20
- name: 'libxml2', version: '2.15.4', file: 'libxml2-2.15.4.tar.xz',
21
- url: 'https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.4.tar.xz',
22
- checksumUrl: 'https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.4.sha256sum',
23
- sha256: '98087fd181d9070724f3fbc65c7377db03038eb92bd882374daff44940138821',
24
- license: 'MIT',
25
- },
26
- ];
27
- const argumentsMap = new Map();
28
- for (let index = 2; index < process.argv.length; index++) {
29
- const key = process.argv[index];
30
- if (key === '--resume') { argumentsMap.set(key, 'true'); continue; }
31
- if (key === '--help') {
32
- console.log('node scripts/build-native-deps.mjs [--project DIR] [--jobs N] [--resume] [--openssl-archive FILE] [--libxml2-archive FILE]\nRun on Ubuntu/WSL with gcc/g++-mingw-w64-x86-64, binutils-mingw-w64-x86-64, cmake, ninja-build, make, perl, curl, tar, xz-utils.');
33
- process.exit(0);
34
- }
35
- if (!['--project', '--jobs', '--openssl-archive', '--libxml2-archive'].includes(key) || !process.argv[index + 1])
36
- throw new Error('Unknown or incomplete option: ' + key);
37
- argumentsMap.set(key, process.argv[++index]);
38
- }
39
- if (process.platform !== 'linux') throw new Error('Run this cross compilation script on Linux/WSL.');
40
- const projectRoot = resolve(argumentsMap.get('--project') ?? join(dirname(fileURLToPath(import.meta.url)), '..'));
41
- const jobs = Number(argumentsMap.get('--jobs') ?? Math.min(availableParallelism(), 12));
42
- if (!Number.isInteger(jobs) || jobs < 1 || jobs > 64) throw new Error('--jobs must be an integer from 1 to 64.');
43
- const depsRoot = join(projectRoot, '.acbr/deps');
44
- const buildRoot = join(depsRoot, 'build/windows');
45
- const sourceRoot = join(buildRoot, 'source');
46
- const installRoot = join(buildRoot, 'install');
47
- const downloads = join(depsRoot, 'downloads');
48
- const output = join(depsRoot, 'win32-x64');
49
- const staging = join(buildRoot, 'staging');
50
- const logs = join(buildRoot, 'logs');
51
- await Promise.all([buildRoot, sourceRoot, installRoot, downloads, staging, logs].map(path => mkdir(path, { recursive: true })));
52
- const commands = [];
53
- const baseEnv = { ...process.env, SOURCE_DATE_EPOCH: '0', LC_ALL: 'C', TZ: 'UTC' };
54
- let commandNumber = 0;
55
- async function run(command, args, { cwd = buildRoot, env = {}, quiet = true, record = true, captureAll = false } = {}) {
56
- const logfile = join(logs, String(++commandNumber).padStart(2, '0') + '-' + command.replaceAll(/[^a-zA-Z0-9_-]/g, '_') + '.log');
57
- if (record) commands.push({ command, args, cwd: relative(projectRoot, cwd), env });
58
- if (!quiet) console.log('> ' + command + ' ' + args.join(' '));
59
- return await new Promise((fulfill, reject) => {
60
- const sink = createWriteStream(logfile);
61
- const child = spawn(command, args, { cwd, env: { ...baseEnv, ...env }, stdio: ['ignore', 'pipe', 'pipe'] });
62
- let tail = '';
63
- const append = data => {
64
- sink.write(data);
65
- tail = captureAll ? tail + data.toString() : (tail + data.toString()).slice(-24_000);
66
- };
67
- child.stdout.on('data', append);
68
- child.stderr.on('data', append);
69
- child.on('error', error => { sink.end(); reject(error); });
70
- child.on('close', code => {
71
- sink.end();
72
- if (code === 0) fulfill(tail);
73
- else reject(new Error(command + ' exited ' + code + '. Log: ' + logfile + '\n' + tail));
74
- });
75
- });
76
- }
77
- async function exists(path) { try { await access(path); return true; } catch { return false; } }
78
- async function hash(path) {
79
- const digest = createHash('sha256');
80
- for await (const chunk of createReadStream(path)) digest.update(chunk);
81
- return digest.digest('hex');
82
- }
83
- async function verifyArchive(path, source) {
84
- if (await hash(path) !== source.sha256) throw new Error('SHA-256 mismatch: ' + path);
85
- }
86
- async function archive(source) {
87
- const path = join(downloads, source.file);
88
- const provided = argumentsMap.get('--' + source.name + '-archive');
89
- if (provided) {
90
- await verifyArchive(resolve(provided), source);
91
- if (resolve(provided) !== path) await copyFile(resolve(provided), path);
92
- } else if (!(await exists(path))) {
93
- console.log('Downloading ' + source.file + ' from the official source.');
94
- const partial = path + '.partial';
95
- await run('curl', ['--fail', '--silent', '--show-error', '--location', '--retry', '3', '--connect-timeout', '30', '--output', partial, source.url]);
96
- await verifyArchive(partial, source);
97
- await rename(partial, path);
98
- }
99
- await verifyArchive(path, source);
100
- return path;
101
- }
102
- const compiler = 'x86_64-w64-mingw32-gcc-win32';
103
- const cxx = 'x86_64-w64-mingw32-g++-win32';
104
- const toolNames = [compiler, cxx, 'x86_64-w64-mingw32-objdump', 'x86_64-w64-mingw32-ar', 'x86_64-w64-mingw32-windres', 'cmake', 'ninja', 'make', 'perl', 'curl', 'tar'];
105
- const tools = {};
106
- for (const name of toolNames) {
107
- const text = await run(name, ['--version'], { record: false });
108
- tools[name] = text.trim().split('\n')[0];
109
- }
110
- tools.compilerVersion = (await run(compiler, ['-dumpfullversion'], { record: false })).trim();
111
- tools.packages = (await run('dpkg-query', ['-W', '-f=' + String.fromCharCode(36) + '{binary:Package}=' + String.fromCharCode(36) + '{Version}' + String.fromCharCode(10), 'gcc-mingw-w64-x86-64-win32', 'mingw-w64-common'], { record: false })).trim().split(String.fromCharCode(10));
112
- const archives = await Promise.all(sources.map(archive));
113
- for (let index = 0; index < sources.length; index++) {
114
- const source = sources[index];
115
- // Only exact, checksum-verified upstream archives are extracted.
116
- await run('tar', ['-xf', archives[index], '-C', sourceRoot]);
117
- console.log(source.name + ' ' + source.version + ': source SHA-256 verified.');
118
- }
119
- const opensslDir = join(sourceRoot, 'openssl-3.5.9');
120
- const opensslInstall = join(installRoot, 'openssl');
121
- console.log('Building OpenSSL shared DLLs and the legacy provider (MinGW x64)...');
122
- const opensslEnv = { CC: 'gcc-win32', CXX: 'g++-win32' };
123
- const configureArgs = [
124
- 'Configure', 'mingw64', 'shared', 'no-tests',
125
- '--cross-compile-prefix=x86_64-w64-mingw32-',
126
- '--prefix=' + opensslInstall,
127
- '--openssldir=C:/acbr-node/openssl',
128
- '--libdir=lib', '-static-libgcc', '-Wl,--no-insert-timestamp',
129
- ];
130
- if (argumentsMap.has('--resume')) {
131
- const dump = JSON.parse(await run('perl', ['-I.', '-Mconfigdata', '-MJSON::PP', '-e', 'print JSON::PP::encode_json({args=>$configdata::config{perlargv},env=>$configdata::config{perlenv},version=>$configdata::config{full_version}})'], { cwd: opensslDir, record: false, captureAll: true }));
132
- const currentEnv = { ...baseEnv, ...opensslEnv };
133
- if (dump.version !== sources[0].version || JSON.stringify(dump.args) !== JSON.stringify(configureArgs.slice(1)) ||
134
- Object.entries(dump.env).some(([key,value]) => (currentEnv[key] ?? null) !== value))
135
- throw new Error('--resume requires the same pinned source, Configure arguments and environment as the previous build.');
136
- commands.push({ command: 'perl', args: configureArgs, cwd: relative(projectRoot, opensslDir), env: opensslEnv, reusedConfiguration: true });
137
- console.log('Resuming the matching OpenSSL configuration with the existing toolchain.');
138
- } else {
139
- await run('perl', configureArgs, { cwd: opensslDir, env: opensslEnv });
140
- }
141
- await run('make', ['-j' + jobs, 'build_sw'], { cwd: opensslDir, env: opensslEnv });
142
- await run('make', ['install_sw'], { cwd: opensslDir, env: opensslEnv });
143
- console.log('Building libxml2 shared DLL with XML Schema and C14N support...');
144
- const xmlBuild = join(buildRoot, 'libxml2');
145
- const xmlInstall = join(installRoot, 'libxml2');
146
- const toolchain = join(buildRoot, 'mingw-x64.cmake');
147
- await writeFile(toolchain, [
148
- 'set(CMAKE_SYSTEM_NAME Windows)',
149
- 'set(CMAKE_SYSTEM_PROCESSOR x86_64)',
150
- 'set(CMAKE_C_COMPILER ' + compiler + ')',
151
- 'set(CMAKE_CXX_COMPILER ' + cxx + ')',
152
- 'set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)',
153
- 'set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)',
154
- 'set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)',
155
- 'set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)',
156
- 'set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)',
157
- 'set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)',
158
- '',
159
- ].join('\n'));
160
- await run('cmake', [
161
- '-S', join(sourceRoot, 'libxml2-2.15.4'), '-B', xmlBuild, '-G', 'Ninja',
162
- '-DCMAKE_TOOLCHAIN_FILE=' + toolchain,
163
- '-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_INSTALL_PREFIX=' + xmlInstall,
164
- '-DCMAKE_C_FLAGS=-static-libgcc',
165
- '-DCMAKE_SHARED_LINKER_FLAGS=-static-libgcc -static-libstdc++ -Wl,--no-insert-timestamp',
166
- '-DBUILD_SHARED_LIBS=ON',
167
- '-DLIBXML2_WITH_ICONV=OFF', '-DLIBXML2_WITH_ICU=OFF', '-DLIBXML2_WITH_ZLIB=OFF',
168
- '-DLIBXML2_WITH_PYTHON=OFF', '-DLIBXML2_WITH_PROGRAMS=OFF', '-DLIBXML2_WITH_TESTS=OFF',
169
- '-DLIBXML2_WITH_SCHEMAS=ON', '-DLIBXML2_WITH_C14N=ON', '-DLIBXML2_WITH_THREADS=ON',
170
- '-DLIBXML2_WITH_LEGACY=OFF', '-DLIBXML2_WITH_HTTP=OFF',
171
- ]);
172
- await run('cmake', ['--build', xmlBuild, '--parallel', String(jobs)]);
173
- await run('cmake', ['--install', xmlBuild]);
174
- const dlls = [
175
- { name: 'libcrypto-3-x64.dll', path: join(opensslInstall, 'bin/libcrypto-3-x64.dll'), source: 'openssl' },
176
- { name: 'libssl-3-x64.dll', path: join(opensslInstall, 'bin/libssl-3-x64.dll'), source: 'openssl' },
177
- { name: 'legacy.dll', path: join(opensslInstall, 'lib/ossl-modules/legacy.dll'), source: 'openssl' },
178
- { name: 'libxml2.dll', path: join(xmlInstall, 'bin/libxml2.dll'), source: 'libxml2' },
179
- ];
180
- const systemDlls = new Set([
181
- 'advapi32.dll', 'bcrypt.dll', 'crypt32.dll', 'gdi32.dll', 'kernel32.dll', 'msvcrt.dll',
182
- 'ntdll.dll', 'ole32.dll', 'secur32.dll', 'shell32.dll', 'user32.dll', 'version.dll', 'ws2_32.dll',
183
- ]);
184
- const bundledDlls = new Set(dlls.map(dll => dll.name.toLowerCase()));
185
- const artifacts = [];
186
- for (const dll of dlls) {
187
- const table = await run('x86_64-w64-mingw32-objdump', ['-p', dll.path], { record: false, captureAll: true });
188
- if (!table.includes('pei-x86-64')) throw new Error('Expected a PE x64 DLL: ' + dll.path);
189
- const imports = [...table.matchAll(/DLL Name:\s*(\S+)/g)].map(match => match[1]).sort();
190
- for (const imported of imports)
191
- if (!systemDlls.has(imported.toLowerCase()) && !bundledDlls.has(imported.toLowerCase()))
192
- throw new Error(dll.name + ' imports an unbundled/non-system library: ' + imported);
193
- if (dll.source === 'libxml2')
194
- for (const symbol of ['xmlReadMemory', 'xmlFreeDoc', 'xmlC14NDocDumpMemory', 'xmlSchemaNewParserCtxt', 'xmlSchemaParse', 'xmlSchemaValidateDoc'])
195
- if (!new RegExp('\\]\\s+' + symbol + '(?:\\s|$)').test(table))
196
- throw new Error('Required XML function is missing: ' + symbol);
197
- await copyFile(dll.path, join(staging, dll.name));
198
- const license = dll.source === 'openssl' ? join(opensslDir, 'LICENSE.txt') : join(sourceRoot, 'libxml2-2.15.4/Copyright');
199
- await copyFile(license, join(staging, dll.name + '.LICENSE'));
200
- artifacts.push({ name: dll.name, source: dll.source, sha256: await hash(dll.path), imports });
201
- console.log(dll.name + ': ' + imports.join(', '));
202
- }
203
- // Static GCC/MinGW runtime code still requires its applicable license notices.
204
- // Ubuntu packages contain the full GCC runtime exception and MinGW notices.
205
- await copyFile('/usr/share/doc/gcc-13/copyright', join(staging, 'GCC-Runtime.LICENSE'));
206
- await copyFile('/usr/share/common-licenses/GPL-3', join(staging, 'GCC-GPL-3.LICENSE'));
207
- await copyFile('/usr/share/doc/mingw-w64-common/copyright', join(staging, 'MinGW-w64.LICENSE'));
208
- const manifest = {
209
- format: 1,
210
- platform: 'win32', arch: 'x64',
211
- buildHost: 'Linux/WSL', sharedLibraries: true, vcRedistributable: false,
212
- sourceDateEpoch: 0,
213
- sources,
214
- tools,
215
- buildCommands: commands,
216
- artifacts,
217
- runtimeNotices: ['GCC-Runtime.LICENSE', 'GCC-GPL-3.LICENSE', 'MinGW-w64.LICENSE'],
218
- validation: {
219
- crossCompiled: true, peImportAudit: true,
220
- requiredLibxml2Exports: true,
221
- upstreamTestsRun: false,
222
- reason: 'Windows target executables cannot run natively on the Linux build host. Run offline worker smoke tests on Windows.',
223
- },
224
- };
225
- await writeFile(join(staging, 'SOURCE.json'), JSON.stringify(manifest, null, 2) + '\n');
226
- // Update only the task's fixed dependency directory after all builds and audits pass.
227
- await mkdir(output, { recursive: true });
228
- const files = [
229
- ...dlls.flatMap(dll => [dll.name, dll.name + '.LICENSE']),
230
- 'GCC-Runtime.LICENSE', 'GCC-GPL-3.LICENSE', 'MinGW-w64.LICENSE', 'SOURCE.json',
231
- ];
232
- for (const name of files) await copyFile(join(staging, name), join(output, name));
233
- // Remove only known artifacts from the earlier MSVC-based dependency staging.
234
- for (const name of ['vcruntime140.dll', 'vcruntime140.dll.LICENSE', 'upstream-manifest.json'])
235
- await rm(join(output, name), { force: true });
236
- console.log('Windows x64 dependencies ready: ' + output);
237
- console.log('Provenance, command line and DLL hashes: ' + join(output, 'SOURCE.json'));
1
+ #!/usr/bin/env node
2
+ // Build only freely available Windows x64 dependencies. Run on Linux/WSL.
3
+ import { spawn } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
5
+ import { createReadStream, createWriteStream } from 'node:fs';
6
+ import { access, copyFile, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
7
+ import { availableParallelism } from 'node:os';
8
+ import { dirname, join, relative, resolve } from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+
11
+ const sources = [
12
+ {
13
+ name: 'openssl', version: '3.5.9', file: 'openssl-3.5.9.tar.gz',
14
+ url: 'https://github.com/openssl/openssl/releases/download/openssl-3.5.9/openssl-3.5.9.tar.gz',
15
+ checksumUrl: 'https://github.com/openssl/openssl/releases/download/openssl-3.5.9/openssl-3.5.9.tar.gz.sha256',
16
+ sha256: '603f5602e2eef00d77fbd429d34dcd5822bb301757a1bc9cdb24c670f1eb859a',
17
+ license: 'Apache-2.0',
18
+ },
19
+ {
20
+ name: 'libxml2', version: '2.15.4', file: 'libxml2-2.15.4.tar.xz',
21
+ url: 'https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.4.tar.xz',
22
+ checksumUrl: 'https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.4.sha256sum',
23
+ sha256: '98087fd181d9070724f3fbc65c7377db03038eb92bd882374daff44940138821',
24
+ license: 'MIT',
25
+ },
26
+ ];
27
+ const argumentsMap = new Map();
28
+ for (let index = 2; index < process.argv.length; index++) {
29
+ const key = process.argv[index];
30
+ if (key === '--resume') { argumentsMap.set(key, 'true'); continue; }
31
+ if (key === '--help') {
32
+ console.log('node scripts/build-native-deps.mjs [--project DIR] [--jobs N] [--resume] [--openssl-archive FILE] [--libxml2-archive FILE]\nRun on Ubuntu/WSL with gcc/g++-mingw-w64-x86-64, binutils-mingw-w64-x86-64, cmake, ninja-build, make, perl, curl, tar, xz-utils.');
33
+ process.exit(0);
34
+ }
35
+ if (!['--project', '--jobs', '--openssl-archive', '--libxml2-archive'].includes(key) || !process.argv[index + 1])
36
+ throw new Error('Unknown or incomplete option: ' + key);
37
+ argumentsMap.set(key, process.argv[++index]);
38
+ }
39
+ if (process.platform !== 'linux') throw new Error('Run this cross compilation script on Linux/WSL.');
40
+ const projectRoot = resolve(argumentsMap.get('--project') ?? join(dirname(fileURLToPath(import.meta.url)), '..'));
41
+ const jobs = Number(argumentsMap.get('--jobs') ?? Math.min(availableParallelism(), 12));
42
+ if (!Number.isInteger(jobs) || jobs < 1 || jobs > 64) throw new Error('--jobs must be an integer from 1 to 64.');
43
+ const depsRoot = join(projectRoot, '.acbr/deps');
44
+ const buildRoot = join(depsRoot, 'build/windows');
45
+ const sourceRoot = join(buildRoot, 'source');
46
+ const installRoot = join(buildRoot, 'install');
47
+ const downloads = join(depsRoot, 'downloads');
48
+ const output = join(depsRoot, 'win32-x64');
49
+ const staging = join(buildRoot, 'staging');
50
+ const logs = join(buildRoot, 'logs');
51
+ await Promise.all([buildRoot, sourceRoot, installRoot, downloads, staging, logs].map(path => mkdir(path, { recursive: true })));
52
+ const commands = [];
53
+ const baseEnv = { ...process.env, SOURCE_DATE_EPOCH: '0', LC_ALL: 'C', TZ: 'UTC' };
54
+ let commandNumber = 0;
55
+ async function run(command, args, { cwd = buildRoot, env = {}, quiet = true, record = true, captureAll = false } = {}) {
56
+ const logfile = join(logs, String(++commandNumber).padStart(2, '0') + '-' + command.replaceAll(/[^a-zA-Z0-9_-]/g, '_') + '.log');
57
+ if (record) commands.push({ command, args, cwd: relative(projectRoot, cwd), env });
58
+ if (!quiet) console.log('> ' + command + ' ' + args.join(' '));
59
+ return await new Promise((fulfill, reject) => {
60
+ const sink = createWriteStream(logfile);
61
+ const child = spawn(command, args, { cwd, env: { ...baseEnv, ...env }, stdio: ['ignore', 'pipe', 'pipe'] });
62
+ let tail = '';
63
+ const append = data => {
64
+ sink.write(data);
65
+ tail = captureAll ? tail + data.toString() : (tail + data.toString()).slice(-24_000);
66
+ };
67
+ child.stdout.on('data', append);
68
+ child.stderr.on('data', append);
69
+ child.on('error', error => { sink.end(); reject(error); });
70
+ child.on('close', code => {
71
+ sink.end();
72
+ if (code === 0) fulfill(tail);
73
+ else reject(new Error(command + ' exited ' + code + '. Log: ' + logfile + '\n' + tail));
74
+ });
75
+ });
76
+ }
77
+ async function exists(path) { try { await access(path); return true; } catch { return false; } }
78
+ async function hash(path) {
79
+ const digest = createHash('sha256');
80
+ for await (const chunk of createReadStream(path)) digest.update(chunk);
81
+ return digest.digest('hex');
82
+ }
83
+ async function verifyArchive(path, source) {
84
+ if (await hash(path) !== source.sha256) throw new Error('SHA-256 mismatch: ' + path);
85
+ }
86
+ async function archive(source) {
87
+ const path = join(downloads, source.file);
88
+ const provided = argumentsMap.get('--' + source.name + '-archive');
89
+ if (provided) {
90
+ await verifyArchive(resolve(provided), source);
91
+ if (resolve(provided) !== path) await copyFile(resolve(provided), path);
92
+ } else if (!(await exists(path))) {
93
+ console.log('Downloading ' + source.file + ' from the official source.');
94
+ const partial = path + '.partial';
95
+ await run('curl', ['--fail', '--silent', '--show-error', '--location', '--retry', '3', '--connect-timeout', '30', '--output', partial, source.url]);
96
+ await verifyArchive(partial, source);
97
+ await rename(partial, path);
98
+ }
99
+ await verifyArchive(path, source);
100
+ return path;
101
+ }
102
+ const compiler = 'x86_64-w64-mingw32-gcc-win32';
103
+ const cxx = 'x86_64-w64-mingw32-g++-win32';
104
+ const toolNames = [compiler, cxx, 'x86_64-w64-mingw32-objdump', 'x86_64-w64-mingw32-ar', 'x86_64-w64-mingw32-windres', 'cmake', 'ninja', 'make', 'perl', 'curl', 'tar'];
105
+ const tools = {};
106
+ for (const name of toolNames) {
107
+ const text = await run(name, ['--version'], { record: false });
108
+ tools[name] = text.trim().split('\n')[0];
109
+ }
110
+ tools.compilerVersion = (await run(compiler, ['-dumpfullversion'], { record: false })).trim();
111
+ tools.packages = (await run('dpkg-query', ['-W', '-f=' + String.fromCharCode(36) + '{binary:Package}=' + String.fromCharCode(36) + '{Version}' + String.fromCharCode(10), 'gcc-mingw-w64-x86-64-win32', 'mingw-w64-common'], { record: false })).trim().split(String.fromCharCode(10));
112
+ const archives = await Promise.all(sources.map(archive));
113
+ for (let index = 0; index < sources.length; index++) {
114
+ const source = sources[index];
115
+ // Only exact, checksum-verified upstream archives are extracted.
116
+ await run('tar', ['-xf', archives[index], '-C', sourceRoot]);
117
+ console.log(source.name + ' ' + source.version + ': source SHA-256 verified.');
118
+ }
119
+ const opensslDir = join(sourceRoot, 'openssl-3.5.9');
120
+ const opensslInstall = join(installRoot, 'openssl');
121
+ console.log('Building OpenSSL shared DLLs and the legacy provider (MinGW x64)...');
122
+ const opensslEnv = { CC: 'gcc-win32', CXX: 'g++-win32' };
123
+ const configureArgs = [
124
+ 'Configure', 'mingw64', 'shared', 'no-tests',
125
+ '--cross-compile-prefix=x86_64-w64-mingw32-',
126
+ '--prefix=' + opensslInstall,
127
+ '--openssldir=C:/acbr-node/openssl',
128
+ '--libdir=lib', '-static-libgcc', '-Wl,--no-insert-timestamp',
129
+ ];
130
+ if (argumentsMap.has('--resume')) {
131
+ const dump = JSON.parse(await run('perl', ['-I.', '-Mconfigdata', '-MJSON::PP', '-e', 'print JSON::PP::encode_json({args=>$configdata::config{perlargv},env=>$configdata::config{perlenv},version=>$configdata::config{full_version}})'], { cwd: opensslDir, record: false, captureAll: true }));
132
+ const currentEnv = { ...baseEnv, ...opensslEnv };
133
+ if (dump.version !== sources[0].version || JSON.stringify(dump.args) !== JSON.stringify(configureArgs.slice(1)) ||
134
+ Object.entries(dump.env).some(([key,value]) => (currentEnv[key] ?? null) !== value))
135
+ throw new Error('--resume requires the same pinned source, Configure arguments and environment as the previous build.');
136
+ commands.push({ command: 'perl', args: configureArgs, cwd: relative(projectRoot, opensslDir), env: opensslEnv, reusedConfiguration: true });
137
+ console.log('Resuming the matching OpenSSL configuration with the existing toolchain.');
138
+ } else {
139
+ await run('perl', configureArgs, { cwd: opensslDir, env: opensslEnv });
140
+ }
141
+ await run('make', ['-j' + jobs, 'build_sw'], { cwd: opensslDir, env: opensslEnv });
142
+ await run('make', ['install_sw'], { cwd: opensslDir, env: opensslEnv });
143
+ console.log('Building libxml2 shared DLL with XML Schema and C14N support...');
144
+ const xmlBuild = join(buildRoot, 'libxml2');
145
+ const xmlInstall = join(installRoot, 'libxml2');
146
+ const toolchain = join(buildRoot, 'mingw-x64.cmake');
147
+ await writeFile(toolchain, [
148
+ 'set(CMAKE_SYSTEM_NAME Windows)',
149
+ 'set(CMAKE_SYSTEM_PROCESSOR x86_64)',
150
+ 'set(CMAKE_C_COMPILER ' + compiler + ')',
151
+ 'set(CMAKE_CXX_COMPILER ' + cxx + ')',
152
+ 'set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)',
153
+ 'set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)',
154
+ 'set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)',
155
+ 'set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)',
156
+ 'set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)',
157
+ 'set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)',
158
+ '',
159
+ ].join('\n'));
160
+ await run('cmake', [
161
+ '-S', join(sourceRoot, 'libxml2-2.15.4'), '-B', xmlBuild, '-G', 'Ninja',
162
+ '-DCMAKE_TOOLCHAIN_FILE=' + toolchain,
163
+ '-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_INSTALL_PREFIX=' + xmlInstall,
164
+ '-DCMAKE_C_FLAGS=-static-libgcc',
165
+ '-DCMAKE_SHARED_LINKER_FLAGS=-static-libgcc -static-libstdc++ -Wl,--no-insert-timestamp',
166
+ '-DBUILD_SHARED_LIBS=ON',
167
+ '-DLIBXML2_WITH_ICONV=OFF', '-DLIBXML2_WITH_ICU=OFF', '-DLIBXML2_WITH_ZLIB=OFF',
168
+ '-DLIBXML2_WITH_PYTHON=OFF', '-DLIBXML2_WITH_PROGRAMS=OFF', '-DLIBXML2_WITH_TESTS=OFF',
169
+ '-DLIBXML2_WITH_SCHEMAS=ON', '-DLIBXML2_WITH_C14N=ON', '-DLIBXML2_WITH_THREADS=ON',
170
+ '-DLIBXML2_WITH_LEGACY=OFF', '-DLIBXML2_WITH_HTTP=OFF',
171
+ ]);
172
+ await run('cmake', ['--build', xmlBuild, '--parallel', String(jobs)]);
173
+ await run('cmake', ['--install', xmlBuild]);
174
+ const dlls = [
175
+ { name: 'libcrypto-3-x64.dll', path: join(opensslInstall, 'bin/libcrypto-3-x64.dll'), source: 'openssl' },
176
+ { name: 'libssl-3-x64.dll', path: join(opensslInstall, 'bin/libssl-3-x64.dll'), source: 'openssl' },
177
+ { name: 'legacy.dll', path: join(opensslInstall, 'lib/ossl-modules/legacy.dll'), source: 'openssl' },
178
+ { name: 'libxml2.dll', path: join(xmlInstall, 'bin/libxml2.dll'), source: 'libxml2' },
179
+ ];
180
+ const systemDlls = new Set([
181
+ 'advapi32.dll', 'bcrypt.dll', 'crypt32.dll', 'gdi32.dll', 'kernel32.dll', 'msvcrt.dll',
182
+ 'ntdll.dll', 'ole32.dll', 'secur32.dll', 'shell32.dll', 'user32.dll', 'version.dll', 'ws2_32.dll',
183
+ ]);
184
+ const bundledDlls = new Set(dlls.map(dll => dll.name.toLowerCase()));
185
+ const artifacts = [];
186
+ for (const dll of dlls) {
187
+ const table = await run('x86_64-w64-mingw32-objdump', ['-p', dll.path], { record: false, captureAll: true });
188
+ if (!table.includes('pei-x86-64')) throw new Error('Expected a PE x64 DLL: ' + dll.path);
189
+ const imports = [...table.matchAll(/DLL Name:\s*(\S+)/g)].map(match => match[1]).sort();
190
+ for (const imported of imports)
191
+ if (!systemDlls.has(imported.toLowerCase()) && !bundledDlls.has(imported.toLowerCase()))
192
+ throw new Error(dll.name + ' imports an unbundled/non-system library: ' + imported);
193
+ if (dll.source === 'libxml2')
194
+ for (const symbol of ['xmlReadMemory', 'xmlFreeDoc', 'xmlC14NDocDumpMemory', 'xmlSchemaNewParserCtxt', 'xmlSchemaParse', 'xmlSchemaValidateDoc'])
195
+ if (!new RegExp('\\]\\s+' + symbol + '(?:\\s|$)').test(table))
196
+ throw new Error('Required XML function is missing: ' + symbol);
197
+ await copyFile(dll.path, join(staging, dll.name));
198
+ const license = dll.source === 'openssl' ? join(opensslDir, 'LICENSE.txt') : join(sourceRoot, 'libxml2-2.15.4/Copyright');
199
+ await copyFile(license, join(staging, dll.name + '.LICENSE'));
200
+ artifacts.push({ name: dll.name, source: dll.source, sha256: await hash(dll.path), imports });
201
+ console.log(dll.name + ': ' + imports.join(', '));
202
+ }
203
+ // Static GCC/MinGW runtime code still requires its applicable license notices.
204
+ // Ubuntu packages contain the full GCC runtime exception and MinGW notices.
205
+ await copyFile('/usr/share/doc/gcc-13/copyright', join(staging, 'GCC-Runtime.LICENSE'));
206
+ await copyFile('/usr/share/common-licenses/GPL-3', join(staging, 'GCC-GPL-3.LICENSE'));
207
+ await copyFile('/usr/share/doc/mingw-w64-common/copyright', join(staging, 'MinGW-w64.LICENSE'));
208
+ const manifest = {
209
+ format: 1,
210
+ platform: 'win32', arch: 'x64',
211
+ buildHost: 'Linux/WSL', sharedLibraries: true, vcRedistributable: false,
212
+ sourceDateEpoch: 0,
213
+ sources,
214
+ tools,
215
+ buildCommands: commands,
216
+ artifacts,
217
+ runtimeNotices: ['GCC-Runtime.LICENSE', 'GCC-GPL-3.LICENSE', 'MinGW-w64.LICENSE'],
218
+ validation: {
219
+ crossCompiled: true, peImportAudit: true,
220
+ requiredLibxml2Exports: true,
221
+ upstreamTestsRun: false,
222
+ reason: 'Windows target executables cannot run natively on the Linux build host. Run offline worker smoke tests on Windows.',
223
+ },
224
+ };
225
+ await writeFile(join(staging, 'SOURCE.json'), JSON.stringify(manifest, null, 2) + '\n');
226
+ // Update only the task's fixed dependency directory after all builds and audits pass.
227
+ await mkdir(output, { recursive: true });
228
+ const files = [
229
+ ...dlls.flatMap(dll => [dll.name, dll.name + '.LICENSE']),
230
+ 'GCC-Runtime.LICENSE', 'GCC-GPL-3.LICENSE', 'MinGW-w64.LICENSE', 'SOURCE.json',
231
+ ];
232
+ for (const name of files) await copyFile(join(staging, name), join(output, name));
233
+ // Remove only known artifacts from the earlier MSVC-based dependency staging.
234
+ for (const name of ['vcruntime140.dll', 'vcruntime140.dll.LICENSE', 'upstream-manifest.json'])
235
+ await rm(join(output, name), { force: true });
236
+ console.log('Windows x64 dependencies ready: ' + output);
237
+ console.log('Provenance, command line and DLL hashes: ' + join(output, 'SOURCE.json'));
@@ -0,0 +1,5 @@
1
+ export interface RuntimeLicenseOptions { policyDirectory?: string; }
2
+ export interface RuntimeLicenseInventory { formatVersion: number; policySha256: string; files: Record<string, unknown>; }
3
+ export function auditLicensePolicy(directory: string, options?: RuntimeLicenseOptions): Promise<string>;
4
+ export function completeRuntimeLicenses(runtime: string, options?: RuntimeLicenseOptions): Promise<RuntimeLicenseInventory>;
5
+ export function auditRuntimeLicenses(runtime: string, manifest: { files: Record<string, string>; platform?: string }, options?: RuntimeLicenseOptions): Promise<RuntimeLicenseInventory>;