@altopelago/aeon-cli 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/OUTPUT_CONTRACT.md +390 -0
- package/README.md +67 -0
- package/dist/main.js +63 -32
- package/dist/main.js.map +1 -1
- package/dist/runtime-bind.js +2 -2
- package/dist/runtime-bind.js.map +1 -1
- package/package.json +41 -12
package/dist/main.js
CHANGED
|
@@ -225,7 +225,7 @@ Examples:
|
|
|
225
225
|
* Exit code: 0 = valid, 1 = errors
|
|
226
226
|
*/
|
|
227
227
|
function check(args) {
|
|
228
|
-
const file =
|
|
228
|
+
const file = findFileWithValueFlags(args, ['--datatype-policy', '--max-input-bytes']);
|
|
229
229
|
if (!file) {
|
|
230
230
|
console.error('Error: No file specified');
|
|
231
231
|
console.error('Usage: aeon check <file>');
|
|
@@ -242,8 +242,7 @@ function check(args) {
|
|
|
242
242
|
console.error('Error: Invalid value for --max-input-bytes (expected a non-negative integer)');
|
|
243
243
|
process.exit(2);
|
|
244
244
|
}
|
|
245
|
-
const input =
|
|
246
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
245
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
247
246
|
const result = compile(input, {
|
|
248
247
|
...(datatypePolicy ? { datatypePolicy } : {}),
|
|
249
248
|
...(maxInputBytes !== undefined ? { maxInputBytes } : {}),
|
|
@@ -289,7 +288,7 @@ function getDefaultContractRegistryPath() {
|
|
|
289
288
|
const specsRoot = process.env.AEONITE_SPECS_ROOT
|
|
290
289
|
? path.resolve(process.env.AEONITE_SPECS_ROOT)
|
|
291
290
|
: path.resolve(repoRoot, '..', '..', 'aeonite-org', 'aeonite-specs');
|
|
292
|
-
return path.resolve(specsRoot, '
|
|
291
|
+
return path.resolve(specsRoot, 'contracts/v1/drafts/artifacts/registry.json');
|
|
293
292
|
}
|
|
294
293
|
/**
|
|
295
294
|
* aeon fmt [file] [--write]
|
|
@@ -297,7 +296,7 @@ function getDefaultContractRegistryPath() {
|
|
|
297
296
|
*/
|
|
298
297
|
function fmt(args) {
|
|
299
298
|
const writeOutput = args.includes('--write');
|
|
300
|
-
const file =
|
|
299
|
+
const file = findFileWithValueFlags(args, ['--max-input-bytes']);
|
|
301
300
|
const maxInputBytes = resolveMaxInputBytes(args);
|
|
302
301
|
if (writeOutput && !file) {
|
|
303
302
|
console.error('Error: --write requires a file path');
|
|
@@ -308,8 +307,7 @@ function fmt(args) {
|
|
|
308
307
|
console.error('Error: Invalid value for --max-input-bytes (expected a non-negative integer)');
|
|
309
308
|
process.exit(2);
|
|
310
309
|
}
|
|
311
|
-
const input = file ?
|
|
312
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
310
|
+
const input = file ? readFileWithLimit(file, maxInputBytes) : readStdin(maxInputBytes);
|
|
313
311
|
const result = canonicalize(input);
|
|
314
312
|
if (result.errors.length > 0) {
|
|
315
313
|
for (const error of result.errors) {
|
|
@@ -331,8 +329,8 @@ function fmt(args) {
|
|
|
331
329
|
* Purpose: human inspection (default) or JSON output
|
|
332
330
|
*/
|
|
333
331
|
function inspect(args) {
|
|
334
|
-
const inspectUsage = 'Usage: aeon inspect <file> [--json] [--recovery] [--annotations] [--annotations-only] [--sort-annotations] [--datatype-policy <reserved_only|allow_custom>] [--max-input-bytes <n>] [--max-attribute-depth <n>] [--max-separator-depth <n>] [--max-generic-depth <n>] [--max-nesting-depth <n>]';
|
|
335
|
-
const file = findFileWithValueFlags(args, ['--datatype-policy', '--max-input-bytes', '--max-attribute-depth', '--max-separator-depth', '--max-generic-depth', '--max-nesting-depth']);
|
|
332
|
+
const inspectUsage = 'Usage: aeon inspect <file> [--json] [--recovery] [--annotations] [--annotations-only] [--sort-annotations] [--datatype-policy <reserved_only|allow_custom>] [--max-input-bytes <n>] [--max-events <n>] [--max-attribute-depth <n>] [--max-separator-depth <n>] [--max-generic-depth <n>] [--max-nesting-depth <n>]';
|
|
333
|
+
const file = findFileWithValueFlags(args, ['--datatype-policy', '--max-input-bytes', '--max-events', '--max-attribute-depth', '--max-separator-depth', '--max-generic-depth', '--max-nesting-depth']);
|
|
336
334
|
const jsonOutput = args.includes('--json');
|
|
337
335
|
const recovery = args.includes('--recovery');
|
|
338
336
|
const annotationsOnly = args.includes('--annotations-only');
|
|
@@ -340,6 +338,7 @@ function inspect(args) {
|
|
|
340
338
|
const sortAnnotations = args.includes('--sort-annotations');
|
|
341
339
|
const datatypePolicy = resolveDatatypePolicy(args);
|
|
342
340
|
const maxInputBytes = resolveMaxInputBytes(args);
|
|
341
|
+
const maxEvents = resolveDepthOption(args, '--max-events');
|
|
343
342
|
const maxAttributeDepth = resolveDepthOption(args, '--max-attribute-depth');
|
|
344
343
|
const maxSeparatorDepth = resolveDepthOption(args, '--max-separator-depth');
|
|
345
344
|
const maxGenericDepth = resolveDepthOption(args, '--max-generic-depth');
|
|
@@ -358,6 +357,10 @@ function inspect(args) {
|
|
|
358
357
|
console.error('Error: Invalid value for --max-input-bytes (expected a non-negative integer)');
|
|
359
358
|
process.exit(2);
|
|
360
359
|
}
|
|
360
|
+
if (maxEvents === null) {
|
|
361
|
+
console.error('Error: Invalid value for --max-events (expected a non-negative integer)');
|
|
362
|
+
process.exit(2);
|
|
363
|
+
}
|
|
361
364
|
if (maxAttributeDepth === null) {
|
|
362
365
|
console.error('Error: Invalid value for --max-attribute-depth (expected a non-negative integer)');
|
|
363
366
|
process.exit(2);
|
|
@@ -374,13 +377,13 @@ function inspect(args) {
|
|
|
374
377
|
console.error('Error: Invalid value for --max-nesting-depth (expected a non-negative integer)');
|
|
375
378
|
process.exit(2);
|
|
376
379
|
}
|
|
377
|
-
const input =
|
|
378
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
380
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
379
381
|
const result = compile(input, {
|
|
380
382
|
recovery,
|
|
381
383
|
emitAnnotations: includeAnnotations || annotationsOnly,
|
|
382
384
|
...(datatypePolicy ? { datatypePolicy } : {}),
|
|
383
385
|
...(maxInputBytes !== undefined ? { maxInputBytes } : {}),
|
|
386
|
+
...(maxEvents !== undefined ? { maxEvents } : {}),
|
|
384
387
|
...(maxAttributeDepth !== undefined ? { maxAttributeDepth } : {}),
|
|
385
388
|
...(maxSeparatorDepth !== undefined ? { maxSeparatorDepth } : {}),
|
|
386
389
|
...(maxGenericDepth !== undefined ? { maxGenericDepth } : {}),
|
|
@@ -467,8 +470,7 @@ function finalize(args) {
|
|
|
467
470
|
console.error(finalizeUsage);
|
|
468
471
|
process.exit(2);
|
|
469
472
|
}
|
|
470
|
-
const input =
|
|
471
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
473
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
472
474
|
const result = compile(input, {
|
|
473
475
|
recovery,
|
|
474
476
|
...(datatypePolicy ? { datatypePolicy } : {}),
|
|
@@ -502,7 +504,7 @@ function bind(args) {
|
|
|
502
504
|
console.error('Usage: aeon bind <file> [--schema <schema.json>] [--profile <id>] [--contract-registry <registry.json>] [--trailing-separator-delimiter-policy <off|warn|error>] [--datatype-policy <reserved_only|allow_custom>] [--strict|--loose] [--projected] [--include-path <$.path>] [--annotations] [--sort-annotations]');
|
|
503
505
|
process.exit(2);
|
|
504
506
|
}
|
|
505
|
-
const file = findFileWithValueFlags(args, ['--schema', '--profile', '--contract-registry', '--trailing-separator-delimiter-policy', '--datatype-policy', '--include-path']);
|
|
507
|
+
const file = findFileWithValueFlags(args, ['--schema', '--profile', '--contract-registry', '--trailing-separator-delimiter-policy', '--datatype-policy', '--include-path', '--scope', '--max-input-bytes']);
|
|
506
508
|
if (!file) {
|
|
507
509
|
console.error('Error: No file specified');
|
|
508
510
|
console.error('Usage: aeon bind <file> [--schema <schema.json>] [--profile <id>] [--contract-registry <registry.json>] [--trailing-separator-delimiter-policy <off|warn|error>] [--datatype-policy <reserved_only|allow_custom>] [--strict|--loose] [--projected] [--include-path <$.path>] [--annotations] [--sort-annotations]');
|
|
@@ -572,8 +574,7 @@ function bind(args) {
|
|
|
572
574
|
console.error('Usage: aeon bind <file> [--schema <schema.json>] [--profile <id>] [--contract-registry <registry.json>] [--trailing-separator-delimiter-policy <off|warn|error>] [--datatype-policy <reserved_only|allow_custom>] [--strict|--loose] [--projected] [--include-path <$.path>] [--annotations] [--sort-annotations]');
|
|
573
575
|
process.exit(2);
|
|
574
576
|
}
|
|
575
|
-
const input =
|
|
576
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
577
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
577
578
|
const headerInfo = extractHeaderInfo(input);
|
|
578
579
|
const resolvedRegistryPath = contractRegistryPath
|
|
579
580
|
? path.resolve(process.cwd(), contractRegistryPath)
|
|
@@ -685,14 +686,13 @@ function integrityValidate(args) {
|
|
|
685
686
|
console.error('Error: Invalid value for --max-input-bytes (expected a non-negative integer)');
|
|
686
687
|
process.exit(2);
|
|
687
688
|
}
|
|
688
|
-
const file = findFileWithValueFlags(args, ['--public-key', '--pubkey', '--receipt']);
|
|
689
|
+
const file = findFileWithValueFlags(args, ['--public-key', '--pubkey', '--receipt', '--max-input-bytes']);
|
|
689
690
|
if (!file) {
|
|
690
691
|
console.error('Error: No file specified');
|
|
691
692
|
console.error('Usage: aeon integrity validate <file> [--strict|--loose]');
|
|
692
693
|
process.exit(2);
|
|
693
694
|
}
|
|
694
|
-
const input =
|
|
695
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
695
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
696
696
|
const compileResult = compile(input, {
|
|
697
697
|
...(maxInputBytes !== undefined ? { maxInputBytes } : {}),
|
|
698
698
|
});
|
|
@@ -740,14 +740,13 @@ function integrityVerify(args) {
|
|
|
740
740
|
console.error('Error: Invalid value for --max-input-bytes (expected a non-negative integer)');
|
|
741
741
|
process.exit(2);
|
|
742
742
|
}
|
|
743
|
-
const file = findFileWithValueFlags(args, ['--public-key', '--pubkey']);
|
|
743
|
+
const file = findFileWithValueFlags(args, ['--public-key', '--pubkey', '--receipt', '--max-input-bytes']);
|
|
744
744
|
if (!file) {
|
|
745
745
|
console.error('Error: No file specified');
|
|
746
746
|
console.error('Usage: aeon integrity verify <file> [--strict|--loose] [--public-key <path>] [--receipt <path>]');
|
|
747
747
|
process.exit(2);
|
|
748
748
|
}
|
|
749
|
-
const input =
|
|
750
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
749
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
751
750
|
const baseInput = removeEnvelope(input);
|
|
752
751
|
const compileResult = compile(input, {
|
|
753
752
|
...(maxInputBytes !== undefined ? { maxInputBytes } : {}),
|
|
@@ -1017,7 +1016,7 @@ function integrityVerify(args) {
|
|
|
1017
1016
|
}
|
|
1018
1017
|
}
|
|
1019
1018
|
function integritySign(args) {
|
|
1020
|
-
const file = findFileWithValueFlags(args, ['--private-key', '--privkey', '--receipt']);
|
|
1019
|
+
const file = findFileWithValueFlags(args, ['--private-key', '--privkey', '--receipt', '--max-input-bytes']);
|
|
1021
1020
|
const jsonOutput = args.includes('--json');
|
|
1022
1021
|
const writeOutput = args.includes('--write');
|
|
1023
1022
|
const replaceOutput = args.includes('--replace');
|
|
@@ -1039,8 +1038,7 @@ function integritySign(args) {
|
|
|
1039
1038
|
console.error('Usage: aeon integrity sign <file> --private-key <path> [--receipt <path>]');
|
|
1040
1039
|
process.exit(2);
|
|
1041
1040
|
}
|
|
1042
|
-
const input =
|
|
1043
|
-
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
1041
|
+
const input = readFileWithLimit(file, maxInputBytes);
|
|
1044
1042
|
const baseInput = removeEnvelope(input);
|
|
1045
1043
|
const envelopePresence = extractEnvelopeFields(input);
|
|
1046
1044
|
if (envelopePresence.errors.length > 0) {
|
|
@@ -1532,9 +1530,6 @@ function formatGenericErrorLine(error) {
|
|
|
1532
1530
|
const prefix = phaseLabel ? `${phaseLabel}: ` : '';
|
|
1533
1531
|
return `${prefix}${message} [${code}] path=$ span=${span}`;
|
|
1534
1532
|
}
|
|
1535
|
-
function findFile(args) {
|
|
1536
|
-
return args.find(arg => !arg.startsWith('--'));
|
|
1537
|
-
}
|
|
1538
1533
|
function findFileWithValueFlags(args, valueFlags) {
|
|
1539
1534
|
const skip = new Set();
|
|
1540
1535
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -1593,14 +1588,17 @@ function resolveDepthOption(args, flag) {
|
|
|
1593
1588
|
return null;
|
|
1594
1589
|
return Number.parseInt(value, 10);
|
|
1595
1590
|
}
|
|
1591
|
+
function failInputByteLimit(actualBytes, maxInputBytes) {
|
|
1592
|
+
console.error(`Error: Input size ${actualBytes} bytes exceeds configured limit of ${maxInputBytes} bytes`);
|
|
1593
|
+
process.exit(1);
|
|
1594
|
+
}
|
|
1596
1595
|
function enforceInputByteLimitOrExit(input, maxInputBytes) {
|
|
1597
1596
|
if (maxInputBytes === undefined)
|
|
1598
1597
|
return;
|
|
1599
1598
|
const actualBytes = Buffer.byteLength(input, 'utf8');
|
|
1600
1599
|
if (actualBytes <= maxInputBytes)
|
|
1601
1600
|
return;
|
|
1602
|
-
|
|
1603
|
-
process.exit(1);
|
|
1601
|
+
failInputByteLimit(actualBytes, maxInputBytes);
|
|
1604
1602
|
}
|
|
1605
1603
|
function readFile(file) {
|
|
1606
1604
|
try {
|
|
@@ -1611,9 +1609,42 @@ function readFile(file) {
|
|
|
1611
1609
|
process.exit(2);
|
|
1612
1610
|
}
|
|
1613
1611
|
}
|
|
1614
|
-
function
|
|
1612
|
+
function readFileWithLimit(file, maxInputBytes) {
|
|
1613
|
+
if (maxInputBytes !== undefined) {
|
|
1614
|
+
try {
|
|
1615
|
+
const stats = fs.statSync(file);
|
|
1616
|
+
if (stats.isFile() && stats.size > maxInputBytes) {
|
|
1617
|
+
failInputByteLimit(stats.size, maxInputBytes);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
catch (err) {
|
|
1621
|
+
console.error(`Error: Cannot read file: ${file}`);
|
|
1622
|
+
process.exit(2);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
const input = readFile(file);
|
|
1626
|
+
enforceInputByteLimitOrExit(input, maxInputBytes);
|
|
1627
|
+
return input;
|
|
1628
|
+
}
|
|
1629
|
+
function readStdin(maxInputBytes) {
|
|
1615
1630
|
try {
|
|
1616
|
-
|
|
1631
|
+
if (maxInputBytes === undefined) {
|
|
1632
|
+
return fs.readFileSync(0, 'utf-8');
|
|
1633
|
+
}
|
|
1634
|
+
const chunks = [];
|
|
1635
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
1636
|
+
let actualBytes = 0;
|
|
1637
|
+
while (true) {
|
|
1638
|
+
const bytesRead = fs.readSync(0, buffer, 0, buffer.length, null);
|
|
1639
|
+
if (bytesRead === 0)
|
|
1640
|
+
break;
|
|
1641
|
+
actualBytes += bytesRead;
|
|
1642
|
+
if (actualBytes > maxInputBytes) {
|
|
1643
|
+
failInputByteLimit(actualBytes, maxInputBytes);
|
|
1644
|
+
}
|
|
1645
|
+
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
1646
|
+
}
|
|
1647
|
+
return Buffer.concat(chunks).toString('utf-8');
|
|
1617
1648
|
}
|
|
1618
1649
|
catch {
|
|
1619
1650
|
console.error('Error: Cannot read stdin');
|