@axiomify/cli 5.0.0 → 6.0.0
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 +121 -52
- package/dist/chunk-YZPZCUKZ.mjs +41 -0
- package/dist/dist-SYWHGZLI.mjs +344 -0
- package/dist/index.js +2181 -293
- package/dist/index.mjs +1789 -297
- package/dist/uws_darwin_arm64_127-NGHTXN5Q.node +0 -0
- package/dist/uws_darwin_arm64_137-ESY6MPLH.node +0 -0
- package/dist/uws_darwin_arm64_147-V7BKA3SU.node +0 -0
- package/dist/uws_darwin_x64_127-WIZGG7MS.node +0 -0
- package/dist/uws_darwin_x64_137-APKZWL4Y.node +0 -0
- package/dist/uws_darwin_x64_147-W2HKFQZT.node +0 -0
- package/dist/uws_linux_arm64_127-3CO7NSFJ.node +0 -0
- package/dist/uws_linux_arm64_137-HWEDGGZV.node +0 -0
- package/dist/uws_linux_arm64_147-7UCIYMK2.node +0 -0
- package/dist/uws_linux_x64_127-KA4E76LJ.node +0 -0
- package/dist/uws_linux_x64_137-DDFLTTJR.node +0 -0
- package/dist/uws_linux_x64_147-MJSFREL3.node +0 -0
- package/dist/uws_win32_x64_127-O4US4Y4L.node +0 -0
- package/dist/uws_win32_x64_137-L5OZROQ7.node +0 -0
- package/dist/uws_win32_x64_147-D7MGKVRG.node +0 -0
- package/package.json +30 -14
package/dist/index.mjs
CHANGED
|
@@ -1,44 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { __commonJS, __require, __esm, __glob, __toESM } from './chunk-YZPZCUKZ.mjs';
|
|
2
3
|
import * as esbuild from 'esbuild';
|
|
3
|
-
import
|
|
4
|
+
import path7 from 'path';
|
|
4
5
|
import fs, { existsSync } from 'fs';
|
|
6
|
+
import pc from 'picocolors';
|
|
7
|
+
import fs5 from 'fs/promises';
|
|
5
8
|
import { spawn } from 'child_process';
|
|
9
|
+
import { createServer } from 'net';
|
|
6
10
|
import { prompt } from 'enquirer';
|
|
7
11
|
import { execa } from 'execa';
|
|
8
|
-
import fs2 from 'fs/promises';
|
|
9
|
-
import pc from 'picocolors';
|
|
10
|
-
|
|
11
|
-
var __create = Object.create;
|
|
12
|
-
var __defProp = Object.defineProperty;
|
|
13
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
16
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
17
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
18
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
19
|
-
}) : x)(function(x) {
|
|
20
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
21
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
22
|
-
});
|
|
23
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
24
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
25
|
-
};
|
|
26
|
-
var __copyProps = (to, from, except, desc) => {
|
|
27
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
28
|
-
for (let key of __getOwnPropNames(from))
|
|
29
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
30
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
31
|
-
}
|
|
32
|
-
return to;
|
|
33
|
-
};
|
|
34
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
35
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
36
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
37
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
38
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
39
|
-
__defProp(target, "default", { value: mod, enumerable: true }) ,
|
|
40
|
-
mod
|
|
41
|
-
));
|
|
42
12
|
|
|
43
13
|
// node_modules/commander/lib/error.js
|
|
44
14
|
var require_error = __commonJS({
|
|
@@ -49,7 +19,6 @@ var require_error = __commonJS({
|
|
|
49
19
|
* @param {number} exitCode suggested exit code which could be used with process.exit
|
|
50
20
|
* @param {string} code an id string representing the error
|
|
51
21
|
* @param {string} message human-readable description of the error
|
|
52
|
-
* @constructor
|
|
53
22
|
*/
|
|
54
23
|
constructor(exitCode, code, message) {
|
|
55
24
|
super(message);
|
|
@@ -64,7 +33,6 @@ var require_error = __commonJS({
|
|
|
64
33
|
/**
|
|
65
34
|
* Constructs the InvalidArgumentError class
|
|
66
35
|
* @param {string} [message] explanation of why argument is invalid
|
|
67
|
-
* @constructor
|
|
68
36
|
*/
|
|
69
37
|
constructor(message) {
|
|
70
38
|
super(1, "commander.invalidArgument", message);
|
|
@@ -125,7 +93,7 @@ var require_argument = __commonJS({
|
|
|
125
93
|
return this._name;
|
|
126
94
|
}
|
|
127
95
|
/**
|
|
128
|
-
* @package
|
|
96
|
+
* @package
|
|
129
97
|
*/
|
|
130
98
|
_concatValue(value, previous) {
|
|
131
99
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
@@ -165,7 +133,9 @@ var require_argument = __commonJS({
|
|
|
165
133
|
this.argChoices = values.slice();
|
|
166
134
|
this.parseArg = (arg, previous) => {
|
|
167
135
|
if (!this.argChoices.includes(arg)) {
|
|
168
|
-
throw new InvalidArgumentError2(
|
|
136
|
+
throw new InvalidArgumentError2(
|
|
137
|
+
`Allowed choices are ${this.argChoices.join(", ")}.`
|
|
138
|
+
);
|
|
169
139
|
}
|
|
170
140
|
if (this.variadic) {
|
|
171
141
|
return this._concatValue(arg, previous);
|
|
@@ -176,6 +146,8 @@ var require_argument = __commonJS({
|
|
|
176
146
|
}
|
|
177
147
|
/**
|
|
178
148
|
* Make argument required.
|
|
149
|
+
*
|
|
150
|
+
* @returns {Argument}
|
|
179
151
|
*/
|
|
180
152
|
argRequired() {
|
|
181
153
|
this.required = true;
|
|
@@ -183,6 +155,8 @@ var require_argument = __commonJS({
|
|
|
183
155
|
}
|
|
184
156
|
/**
|
|
185
157
|
* Make argument optional.
|
|
158
|
+
*
|
|
159
|
+
* @returns {Argument}
|
|
186
160
|
*/
|
|
187
161
|
argOptional() {
|
|
188
162
|
this.required = false;
|
|
@@ -233,7 +207,7 @@ var require_help = __commonJS({
|
|
|
233
207
|
*
|
|
234
208
|
* @param {Option} a
|
|
235
209
|
* @param {Option} b
|
|
236
|
-
* @returns number
|
|
210
|
+
* @returns {number}
|
|
237
211
|
*/
|
|
238
212
|
compareOptions(a, b) {
|
|
239
213
|
const getSortKey = (option) => {
|
|
@@ -256,9 +230,13 @@ var require_help = __commonJS({
|
|
|
256
230
|
if (!removeShort && !removeLong) {
|
|
257
231
|
visibleOptions.push(helpOption);
|
|
258
232
|
} else if (helpOption.long && !removeLong) {
|
|
259
|
-
visibleOptions.push(
|
|
233
|
+
visibleOptions.push(
|
|
234
|
+
cmd.createOption(helpOption.long, helpOption.description)
|
|
235
|
+
);
|
|
260
236
|
} else if (helpOption.short && !removeShort) {
|
|
261
|
-
visibleOptions.push(
|
|
237
|
+
visibleOptions.push(
|
|
238
|
+
cmd.createOption(helpOption.short, helpOption.description)
|
|
239
|
+
);
|
|
262
240
|
}
|
|
263
241
|
}
|
|
264
242
|
if (this.sortOptions) {
|
|
@@ -276,7 +254,9 @@ var require_help = __commonJS({
|
|
|
276
254
|
if (!this.showGlobalOptions) return [];
|
|
277
255
|
const globalOptions = [];
|
|
278
256
|
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
|
|
279
|
-
const visibleOptions = ancestorCmd.options.filter(
|
|
257
|
+
const visibleOptions = ancestorCmd.options.filter(
|
|
258
|
+
(option) => !option.hidden
|
|
259
|
+
);
|
|
280
260
|
globalOptions.push(...visibleOptions);
|
|
281
261
|
}
|
|
282
262
|
if (this.sortOptions) {
|
|
@@ -431,7 +411,9 @@ var require_help = __commonJS({
|
|
|
431
411
|
if (option.defaultValue !== void 0) {
|
|
432
412
|
const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
|
|
433
413
|
if (showDefault) {
|
|
434
|
-
extraInfo.push(
|
|
414
|
+
extraInfo.push(
|
|
415
|
+
`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`
|
|
416
|
+
);
|
|
435
417
|
}
|
|
436
418
|
}
|
|
437
419
|
if (option.presetArg !== void 0 && option.optional) {
|
|
@@ -460,7 +442,9 @@ var require_help = __commonJS({
|
|
|
460
442
|
);
|
|
461
443
|
}
|
|
462
444
|
if (argument.defaultValue !== void 0) {
|
|
463
|
-
extraInfo.push(
|
|
445
|
+
extraInfo.push(
|
|
446
|
+
`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`
|
|
447
|
+
);
|
|
464
448
|
}
|
|
465
449
|
if (extraInfo.length > 0) {
|
|
466
450
|
const extraDescripton = `(${extraInfo.join(", ")})`;
|
|
@@ -486,7 +470,11 @@ var require_help = __commonJS({
|
|
|
486
470
|
function formatItem(term, description) {
|
|
487
471
|
if (description) {
|
|
488
472
|
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
489
|
-
return helper.wrap(
|
|
473
|
+
return helper.wrap(
|
|
474
|
+
fullText,
|
|
475
|
+
helpWidth - itemIndentWidth,
|
|
476
|
+
termWidth + itemSeparatorWidth
|
|
477
|
+
);
|
|
490
478
|
}
|
|
491
479
|
return term;
|
|
492
480
|
}
|
|
@@ -496,30 +484,49 @@ var require_help = __commonJS({
|
|
|
496
484
|
let output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
|
|
497
485
|
const commandDescription = helper.commandDescription(cmd);
|
|
498
486
|
if (commandDescription.length > 0) {
|
|
499
|
-
output = output.concat([
|
|
487
|
+
output = output.concat([
|
|
488
|
+
helper.wrap(commandDescription, helpWidth, 0),
|
|
489
|
+
""
|
|
490
|
+
]);
|
|
500
491
|
}
|
|
501
492
|
const argumentList = helper.visibleArguments(cmd).map((argument) => {
|
|
502
|
-
return formatItem(
|
|
493
|
+
return formatItem(
|
|
494
|
+
helper.argumentTerm(argument),
|
|
495
|
+
helper.argumentDescription(argument)
|
|
496
|
+
);
|
|
503
497
|
});
|
|
504
498
|
if (argumentList.length > 0) {
|
|
505
499
|
output = output.concat(["Arguments:", formatList(argumentList), ""]);
|
|
506
500
|
}
|
|
507
501
|
const optionList = helper.visibleOptions(cmd).map((option) => {
|
|
508
|
-
return formatItem(
|
|
502
|
+
return formatItem(
|
|
503
|
+
helper.optionTerm(option),
|
|
504
|
+
helper.optionDescription(option)
|
|
505
|
+
);
|
|
509
506
|
});
|
|
510
507
|
if (optionList.length > 0) {
|
|
511
508
|
output = output.concat(["Options:", formatList(optionList), ""]);
|
|
512
509
|
}
|
|
513
510
|
if (this.showGlobalOptions) {
|
|
514
511
|
const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
|
|
515
|
-
return formatItem(
|
|
512
|
+
return formatItem(
|
|
513
|
+
helper.optionTerm(option),
|
|
514
|
+
helper.optionDescription(option)
|
|
515
|
+
);
|
|
516
516
|
});
|
|
517
517
|
if (globalOptionList.length > 0) {
|
|
518
|
-
output = output.concat([
|
|
518
|
+
output = output.concat([
|
|
519
|
+
"Global Options:",
|
|
520
|
+
formatList(globalOptionList),
|
|
521
|
+
""
|
|
522
|
+
]);
|
|
519
523
|
}
|
|
520
524
|
}
|
|
521
525
|
const commandList = helper.visibleCommands(cmd).map((cmd2) => {
|
|
522
|
-
return formatItem(
|
|
526
|
+
return formatItem(
|
|
527
|
+
helper.subcommandTerm(cmd2),
|
|
528
|
+
helper.subcommandDescription(cmd2)
|
|
529
|
+
);
|
|
523
530
|
});
|
|
524
531
|
if (commandList.length > 0) {
|
|
525
532
|
output = output.concat(["Commands:", formatList(commandList), ""]);
|
|
@@ -563,8 +570,11 @@ var require_help = __commonJS({
|
|
|
563
570
|
const indentString = " ".repeat(indent);
|
|
564
571
|
const zeroWidthSpace = "\u200B";
|
|
565
572
|
const breaks = `\\s${zeroWidthSpace}`;
|
|
566
|
-
const regex = new RegExp(
|
|
567
|
-
|
|
573
|
+
const regex = new RegExp(
|
|
574
|
+
`
|
|
575
|
+
|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`,
|
|
576
|
+
"g"
|
|
577
|
+
);
|
|
568
578
|
const lines = columnText.match(regex) || [];
|
|
569
579
|
return leadingStr + lines.map((line, i) => {
|
|
570
580
|
if (line === "\n") return "";
|
|
@@ -663,7 +673,7 @@ var require_option = __commonJS({
|
|
|
663
673
|
* .addOption(new Option('--log', 'write logging information to file'))
|
|
664
674
|
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
|
|
665
675
|
*
|
|
666
|
-
* @param {
|
|
676
|
+
* @param {object} impliedOptionValues
|
|
667
677
|
* @return {Option}
|
|
668
678
|
*/
|
|
669
679
|
implies(impliedOptionValues) {
|
|
@@ -718,7 +728,7 @@ var require_option = __commonJS({
|
|
|
718
728
|
return this;
|
|
719
729
|
}
|
|
720
730
|
/**
|
|
721
|
-
* @package
|
|
731
|
+
* @package
|
|
722
732
|
*/
|
|
723
733
|
_concatValue(value, previous) {
|
|
724
734
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
@@ -736,7 +746,9 @@ var require_option = __commonJS({
|
|
|
736
746
|
this.argChoices = values.slice();
|
|
737
747
|
this.parseArg = (arg, previous) => {
|
|
738
748
|
if (!this.argChoices.includes(arg)) {
|
|
739
|
-
throw new InvalidArgumentError2(
|
|
749
|
+
throw new InvalidArgumentError2(
|
|
750
|
+
`Allowed choices are ${this.argChoices.join(", ")}.`
|
|
751
|
+
);
|
|
740
752
|
}
|
|
741
753
|
if (this.variadic) {
|
|
742
754
|
return this._concatValue(arg, previous);
|
|
@@ -770,7 +782,7 @@ var require_option = __commonJS({
|
|
|
770
782
|
*
|
|
771
783
|
* @param {string} arg
|
|
772
784
|
* @return {boolean}
|
|
773
|
-
* @package
|
|
785
|
+
* @package
|
|
774
786
|
*/
|
|
775
787
|
is(arg) {
|
|
776
788
|
return this.short === arg || this.long === arg;
|
|
@@ -781,7 +793,7 @@ var require_option = __commonJS({
|
|
|
781
793
|
* Options are one of boolean, negated, required argument, or optional argument.
|
|
782
794
|
*
|
|
783
795
|
* @return {boolean}
|
|
784
|
-
* @package
|
|
796
|
+
* @package
|
|
785
797
|
*/
|
|
786
798
|
isBoolean() {
|
|
787
799
|
return !this.required && !this.optional && !this.negate;
|
|
@@ -832,7 +844,8 @@ var require_option = __commonJS({
|
|
|
832
844
|
let shortFlag;
|
|
833
845
|
let longFlag;
|
|
834
846
|
const flagParts = flags.split(/[ |,]+/);
|
|
835
|
-
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
|
|
847
|
+
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
|
|
848
|
+
shortFlag = flagParts.shift();
|
|
836
849
|
longFlag = flagParts.shift();
|
|
837
850
|
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
|
|
838
851
|
shortFlag = longFlag;
|
|
@@ -850,7 +863,8 @@ var require_suggestSimilar = __commonJS({
|
|
|
850
863
|
"node_modules/commander/lib/suggestSimilar.js"(exports) {
|
|
851
864
|
var maxDistance = 3;
|
|
852
865
|
function editDistance(a, b) {
|
|
853
|
-
if (Math.abs(a.length - b.length) > maxDistance)
|
|
866
|
+
if (Math.abs(a.length - b.length) > maxDistance)
|
|
867
|
+
return Math.max(a.length, b.length);
|
|
854
868
|
const d = [];
|
|
855
869
|
for (let i = 0; i <= a.length; i++) {
|
|
856
870
|
d[i] = [i];
|
|
@@ -929,8 +943,8 @@ var require_command = __commonJS({
|
|
|
929
943
|
"node_modules/commander/lib/command.js"(exports) {
|
|
930
944
|
var EventEmitter = __require("events").EventEmitter;
|
|
931
945
|
var childProcess = __require("child_process");
|
|
932
|
-
var
|
|
933
|
-
var
|
|
946
|
+
var path11 = __require("path");
|
|
947
|
+
var fs9 = __require("fs");
|
|
934
948
|
var process2 = __require("process");
|
|
935
949
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
936
950
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1042,8 +1056,8 @@ var require_command = __commonJS({
|
|
|
1042
1056
|
* .command('stop [service]', 'stop named service, or all if no name supplied');
|
|
1043
1057
|
*
|
|
1044
1058
|
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
|
|
1045
|
-
* @param {(
|
|
1046
|
-
* @param {
|
|
1059
|
+
* @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
|
|
1060
|
+
* @param {object} [execOpts] - configuration options (for executable)
|
|
1047
1061
|
* @return {Command} returns new command for action handler, or `this` for executable command
|
|
1048
1062
|
*/
|
|
1049
1063
|
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
|
|
@@ -1095,8 +1109,8 @@ var require_command = __commonJS({
|
|
|
1095
1109
|
* You can customise the help by overriding Help properties using configureHelp(),
|
|
1096
1110
|
* or with a subclass of Help by overriding createHelp().
|
|
1097
1111
|
*
|
|
1098
|
-
* @param {
|
|
1099
|
-
* @return {(Command|
|
|
1112
|
+
* @param {object} [configuration] - configuration options
|
|
1113
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
1100
1114
|
*/
|
|
1101
1115
|
configureHelp(configuration) {
|
|
1102
1116
|
if (configuration === void 0) return this._helpConfiguration;
|
|
@@ -1118,8 +1132,8 @@ var require_command = __commonJS({
|
|
|
1118
1132
|
* // functions based on what is being written out
|
|
1119
1133
|
* outputError(str, write) // used for displaying errors, and not used for displaying help
|
|
1120
1134
|
*
|
|
1121
|
-
* @param {
|
|
1122
|
-
* @return {(Command|
|
|
1135
|
+
* @param {object} [configuration] - configuration options
|
|
1136
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
1123
1137
|
*/
|
|
1124
1138
|
configureOutput(configuration) {
|
|
1125
1139
|
if (configuration === void 0) return this._outputConfiguration;
|
|
@@ -1153,7 +1167,7 @@ var require_command = __commonJS({
|
|
|
1153
1167
|
* See .command() for creating an attached subcommand which inherits settings from its parent.
|
|
1154
1168
|
*
|
|
1155
1169
|
* @param {Command} cmd - new subcommand
|
|
1156
|
-
* @param {
|
|
1170
|
+
* @param {object} [opts] - configuration options
|
|
1157
1171
|
* @return {Command} `this` command for chaining
|
|
1158
1172
|
*/
|
|
1159
1173
|
addCommand(cmd, opts) {
|
|
@@ -1234,10 +1248,14 @@ var require_command = __commonJS({
|
|
|
1234
1248
|
addArgument(argument) {
|
|
1235
1249
|
const previousArgument = this.registeredArguments.slice(-1)[0];
|
|
1236
1250
|
if (previousArgument && previousArgument.variadic) {
|
|
1237
|
-
throw new Error(
|
|
1251
|
+
throw new Error(
|
|
1252
|
+
`only the last argument can be variadic '${previousArgument.name()}'`
|
|
1253
|
+
);
|
|
1238
1254
|
}
|
|
1239
1255
|
if (argument.required && argument.defaultValue !== void 0 && argument.parseArg === void 0) {
|
|
1240
|
-
throw new Error(
|
|
1256
|
+
throw new Error(
|
|
1257
|
+
`a default value for a required argument is never used: '${argument.name()}'`
|
|
1258
|
+
);
|
|
1241
1259
|
}
|
|
1242
1260
|
this.registeredArguments.push(argument);
|
|
1243
1261
|
return this;
|
|
@@ -1245,6 +1263,7 @@ var require_command = __commonJS({
|
|
|
1245
1263
|
/**
|
|
1246
1264
|
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
|
|
1247
1265
|
*
|
|
1266
|
+
* @example
|
|
1248
1267
|
* program.helpCommand('help [cmd]');
|
|
1249
1268
|
* program.helpCommand('help [cmd]', 'show help');
|
|
1250
1269
|
* program.helpCommand(false); // suppress default help command
|
|
@@ -1422,7 +1441,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1422
1441
|
* Register option if no conflicts found, or throw on conflict.
|
|
1423
1442
|
*
|
|
1424
1443
|
* @param {Option} option
|
|
1425
|
-
* @
|
|
1444
|
+
* @private
|
|
1426
1445
|
*/
|
|
1427
1446
|
_registerOption(option) {
|
|
1428
1447
|
const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
|
|
@@ -1438,17 +1457,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1438
1457
|
* Register command if no conflicts found, or throw on conflict.
|
|
1439
1458
|
*
|
|
1440
1459
|
* @param {Command} command
|
|
1441
|
-
* @
|
|
1460
|
+
* @private
|
|
1442
1461
|
*/
|
|
1443
1462
|
_registerCommand(command) {
|
|
1444
1463
|
const knownBy = (cmd) => {
|
|
1445
1464
|
return [cmd.name()].concat(cmd.aliases());
|
|
1446
1465
|
};
|
|
1447
|
-
const alreadyUsed = knownBy(command).find(
|
|
1466
|
+
const alreadyUsed = knownBy(command).find(
|
|
1467
|
+
(name) => this._findCommand(name)
|
|
1468
|
+
);
|
|
1448
1469
|
if (alreadyUsed) {
|
|
1449
1470
|
const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
|
|
1450
1471
|
const newCmd = knownBy(command).join("|");
|
|
1451
|
-
throw new Error(
|
|
1472
|
+
throw new Error(
|
|
1473
|
+
`cannot add command '${newCmd}' as already have command '${existingCmd}'`
|
|
1474
|
+
);
|
|
1452
1475
|
}
|
|
1453
1476
|
this.commands.push(command);
|
|
1454
1477
|
}
|
|
@@ -1465,7 +1488,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1465
1488
|
if (option.negate) {
|
|
1466
1489
|
const positiveLongFlag = option.long.replace(/^--no-/, "--");
|
|
1467
1490
|
if (!this._findOption(positiveLongFlag)) {
|
|
1468
|
-
this.setOptionValueWithSource(
|
|
1491
|
+
this.setOptionValueWithSource(
|
|
1492
|
+
name,
|
|
1493
|
+
option.defaultValue === void 0 ? true : option.defaultValue,
|
|
1494
|
+
"default"
|
|
1495
|
+
);
|
|
1469
1496
|
}
|
|
1470
1497
|
} else if (option.defaultValue !== void 0) {
|
|
1471
1498
|
this.setOptionValueWithSource(name, option.defaultValue, "default");
|
|
@@ -1506,11 +1533,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1506
1533
|
/**
|
|
1507
1534
|
* Internal implementation shared by .option() and .requiredOption()
|
|
1508
1535
|
*
|
|
1536
|
+
* @return {Command} `this` command for chaining
|
|
1509
1537
|
* @private
|
|
1510
1538
|
*/
|
|
1511
1539
|
_optionEx(config, flags, description, fn, defaultValue) {
|
|
1512
1540
|
if (typeof flags === "object" && flags instanceof Option2) {
|
|
1513
|
-
throw new Error(
|
|
1541
|
+
throw new Error(
|
|
1542
|
+
"To add an Option object use addOption() instead of option() or requiredOption()"
|
|
1543
|
+
);
|
|
1514
1544
|
}
|
|
1515
1545
|
const option = this.createOption(flags, description);
|
|
1516
1546
|
option.makeOptionMandatory(!!config.mandatory);
|
|
@@ -1553,19 +1583,25 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1553
1583
|
return this._optionEx({}, flags, description, parseArg, defaultValue);
|
|
1554
1584
|
}
|
|
1555
1585
|
/**
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1586
|
+
* Add a required option which must have a value after parsing. This usually means
|
|
1587
|
+
* the option must be specified on the command line. (Otherwise the same as .option().)
|
|
1588
|
+
*
|
|
1589
|
+
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
|
|
1590
|
+
*
|
|
1591
|
+
* @param {string} flags
|
|
1592
|
+
* @param {string} [description]
|
|
1593
|
+
* @param {(Function|*)} [parseArg] - custom option processing function or default value
|
|
1594
|
+
* @param {*} [defaultValue]
|
|
1595
|
+
* @return {Command} `this` command for chaining
|
|
1596
|
+
*/
|
|
1567
1597
|
requiredOption(flags, description, parseArg, defaultValue) {
|
|
1568
|
-
return this._optionEx(
|
|
1598
|
+
return this._optionEx(
|
|
1599
|
+
{ mandatory: true },
|
|
1600
|
+
flags,
|
|
1601
|
+
description,
|
|
1602
|
+
parseArg,
|
|
1603
|
+
defaultValue
|
|
1604
|
+
);
|
|
1569
1605
|
}
|
|
1570
1606
|
/**
|
|
1571
1607
|
* Alter parsing of short flags with optional values.
|
|
@@ -1575,7 +1611,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1575
1611
|
* program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
|
|
1576
1612
|
* program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
|
|
1577
1613
|
*
|
|
1578
|
-
* @param {boolean} [combine
|
|
1614
|
+
* @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
|
|
1615
|
+
* @return {Command} `this` command for chaining
|
|
1579
1616
|
*/
|
|
1580
1617
|
combineFlagAndOptionalValue(combine = true) {
|
|
1581
1618
|
this._combineFlagAndOptionalValue = !!combine;
|
|
@@ -1584,8 +1621,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1584
1621
|
/**
|
|
1585
1622
|
* Allow unknown options on the command line.
|
|
1586
1623
|
*
|
|
1587
|
-
* @param {boolean} [allowUnknown
|
|
1588
|
-
* for
|
|
1624
|
+
* @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
|
|
1625
|
+
* @return {Command} `this` command for chaining
|
|
1589
1626
|
*/
|
|
1590
1627
|
allowUnknownOption(allowUnknown = true) {
|
|
1591
1628
|
this._allowUnknownOption = !!allowUnknown;
|
|
@@ -1594,8 +1631,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1594
1631
|
/**
|
|
1595
1632
|
* Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
|
|
1596
1633
|
*
|
|
1597
|
-
* @param {boolean} [allowExcess
|
|
1598
|
-
* for
|
|
1634
|
+
* @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
|
|
1635
|
+
* @return {Command} `this` command for chaining
|
|
1599
1636
|
*/
|
|
1600
1637
|
allowExcessArguments(allowExcess = true) {
|
|
1601
1638
|
this._allowExcessArguments = !!allowExcess;
|
|
@@ -1606,7 +1643,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1606
1643
|
* subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
|
|
1607
1644
|
* The default behaviour is non-positional and global options may appear anywhere on the command line.
|
|
1608
1645
|
*
|
|
1609
|
-
* @param {boolean} [positional
|
|
1646
|
+
* @param {boolean} [positional]
|
|
1647
|
+
* @return {Command} `this` command for chaining
|
|
1610
1648
|
*/
|
|
1611
1649
|
enablePositionalOptions(positional = true) {
|
|
1612
1650
|
this._enablePositionalOptions = !!positional;
|
|
@@ -1618,8 +1656,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1618
1656
|
* positional options to have been enabled on the program (parent commands).
|
|
1619
1657
|
* The default behaviour is non-positional and options may appear before or after command-arguments.
|
|
1620
1658
|
*
|
|
1621
|
-
* @param {boolean} [passThrough
|
|
1622
|
-
* for
|
|
1659
|
+
* @param {boolean} [passThrough] for unknown options.
|
|
1660
|
+
* @return {Command} `this` command for chaining
|
|
1623
1661
|
*/
|
|
1624
1662
|
passThroughOptions(passThrough = true) {
|
|
1625
1663
|
this._passThroughOptions = !!passThrough;
|
|
@@ -1631,22 +1669,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1631
1669
|
*/
|
|
1632
1670
|
_checkForBrokenPassThrough() {
|
|
1633
1671
|
if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
|
|
1634
|
-
throw new Error(
|
|
1672
|
+
throw new Error(
|
|
1673
|
+
`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`
|
|
1674
|
+
);
|
|
1635
1675
|
}
|
|
1636
1676
|
}
|
|
1637
1677
|
/**
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1678
|
+
* Whether to store option values as properties on command object,
|
|
1679
|
+
* or store separately (specify false). In both cases the option values can be accessed using .opts().
|
|
1680
|
+
*
|
|
1681
|
+
* @param {boolean} [storeAsProperties=true]
|
|
1682
|
+
* @return {Command} `this` command for chaining
|
|
1683
|
+
*/
|
|
1644
1684
|
storeOptionsAsProperties(storeAsProperties = true) {
|
|
1645
1685
|
if (this.options.length) {
|
|
1646
1686
|
throw new Error("call .storeOptionsAsProperties() before adding options");
|
|
1647
1687
|
}
|
|
1648
1688
|
if (Object.keys(this._optionValues).length) {
|
|
1649
|
-
throw new Error(
|
|
1689
|
+
throw new Error(
|
|
1690
|
+
"call .storeOptionsAsProperties() before setting option values"
|
|
1691
|
+
);
|
|
1650
1692
|
}
|
|
1651
1693
|
this._storeOptionsAsProperties = !!storeAsProperties;
|
|
1652
1694
|
return this;
|
|
@@ -1655,7 +1697,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1655
1697
|
* Retrieve option value.
|
|
1656
1698
|
*
|
|
1657
1699
|
* @param {string} key
|
|
1658
|
-
* @return {
|
|
1700
|
+
* @return {object} value
|
|
1659
1701
|
*/
|
|
1660
1702
|
getOptionValue(key) {
|
|
1661
1703
|
if (this._storeOptionsAsProperties) {
|
|
@@ -1667,20 +1709,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1667
1709
|
* Store option value.
|
|
1668
1710
|
*
|
|
1669
1711
|
* @param {string} key
|
|
1670
|
-
* @param {
|
|
1712
|
+
* @param {object} value
|
|
1671
1713
|
* @return {Command} `this` command for chaining
|
|
1672
1714
|
*/
|
|
1673
1715
|
setOptionValue(key, value) {
|
|
1674
1716
|
return this.setOptionValueWithSource(key, value, void 0);
|
|
1675
1717
|
}
|
|
1676
1718
|
/**
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1719
|
+
* Store option value and where the value came from.
|
|
1720
|
+
*
|
|
1721
|
+
* @param {string} key
|
|
1722
|
+
* @param {object} value
|
|
1723
|
+
* @param {string} source - expected values are default/config/env/cli/implied
|
|
1724
|
+
* @return {Command} `this` command for chaining
|
|
1725
|
+
*/
|
|
1684
1726
|
setOptionValueWithSource(key, value, source) {
|
|
1685
1727
|
if (this._storeOptionsAsProperties) {
|
|
1686
1728
|
this[key] = value;
|
|
@@ -1691,22 +1733,22 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1691
1733
|
return this;
|
|
1692
1734
|
}
|
|
1693
1735
|
/**
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1736
|
+
* Get source of option value.
|
|
1737
|
+
* Expected values are default | config | env | cli | implied
|
|
1738
|
+
*
|
|
1739
|
+
* @param {string} key
|
|
1740
|
+
* @return {string}
|
|
1741
|
+
*/
|
|
1700
1742
|
getOptionValueSource(key) {
|
|
1701
1743
|
return this._optionValueSources[key];
|
|
1702
1744
|
}
|
|
1703
1745
|
/**
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1746
|
+
* Get source of option value. See also .optsWithGlobals().
|
|
1747
|
+
* Expected values are default | config | env | cli | implied
|
|
1748
|
+
*
|
|
1749
|
+
* @param {string} key
|
|
1750
|
+
* @return {string}
|
|
1751
|
+
*/
|
|
1710
1752
|
getOptionValueSourceWithGlobals(key) {
|
|
1711
1753
|
let source;
|
|
1712
1754
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
@@ -1727,11 +1769,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1727
1769
|
throw new Error("first parameter to parse must be array or undefined");
|
|
1728
1770
|
}
|
|
1729
1771
|
parseOptions = parseOptions || {};
|
|
1730
|
-
if (argv === void 0) {
|
|
1731
|
-
|
|
1732
|
-
if (process2.versions && process2.versions.electron) {
|
|
1772
|
+
if (argv === void 0 && parseOptions.from === void 0) {
|
|
1773
|
+
if (process2.versions?.electron) {
|
|
1733
1774
|
parseOptions.from = "electron";
|
|
1734
1775
|
}
|
|
1776
|
+
const execArgv = process2.execArgv ?? [];
|
|
1777
|
+
if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
|
|
1778
|
+
parseOptions.from = "eval";
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
if (argv === void 0) {
|
|
1782
|
+
argv = process2.argv;
|
|
1735
1783
|
}
|
|
1736
1784
|
this.rawArgs = argv.slice();
|
|
1737
1785
|
let userArgs;
|
|
@@ -1752,26 +1800,38 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1752
1800
|
case "user":
|
|
1753
1801
|
userArgs = argv.slice(0);
|
|
1754
1802
|
break;
|
|
1803
|
+
case "eval":
|
|
1804
|
+
userArgs = argv.slice(1);
|
|
1805
|
+
break;
|
|
1755
1806
|
default:
|
|
1756
|
-
throw new Error(
|
|
1807
|
+
throw new Error(
|
|
1808
|
+
`unexpected parse option { from: '${parseOptions.from}' }`
|
|
1809
|
+
);
|
|
1757
1810
|
}
|
|
1758
|
-
if (!this._name && this._scriptPath)
|
|
1811
|
+
if (!this._name && this._scriptPath)
|
|
1812
|
+
this.nameFromFilename(this._scriptPath);
|
|
1759
1813
|
this._name = this._name || "program";
|
|
1760
1814
|
return userArgs;
|
|
1761
1815
|
}
|
|
1762
1816
|
/**
|
|
1763
1817
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
1764
1818
|
*
|
|
1765
|
-
*
|
|
1766
|
-
*
|
|
1819
|
+
* Use parseAsync instead of parse if any of your action handlers are async.
|
|
1820
|
+
*
|
|
1821
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
1822
|
+
*
|
|
1823
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1824
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1825
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1826
|
+
* - `'user'`: just user arguments
|
|
1767
1827
|
*
|
|
1768
1828
|
* @example
|
|
1769
|
-
* program.parse(process.argv
|
|
1770
|
-
* program.parse(); //
|
|
1829
|
+
* program.parse(); // parse process.argv and auto-detect electron and special node flags
|
|
1830
|
+
* program.parse(process.argv); // assume argv[0] is app and argv[1] is script
|
|
1771
1831
|
* program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
1772
1832
|
*
|
|
1773
1833
|
* @param {string[]} [argv] - optional, defaults to process.argv
|
|
1774
|
-
* @param {
|
|
1834
|
+
* @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
|
|
1775
1835
|
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
|
|
1776
1836
|
* @return {Command} `this` command for chaining
|
|
1777
1837
|
*/
|
|
@@ -1783,18 +1843,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1783
1843
|
/**
|
|
1784
1844
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
1785
1845
|
*
|
|
1786
|
-
*
|
|
1846
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
1787
1847
|
*
|
|
1788
|
-
*
|
|
1789
|
-
*
|
|
1848
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1849
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1850
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1851
|
+
* - `'user'`: just user arguments
|
|
1790
1852
|
*
|
|
1791
1853
|
* @example
|
|
1792
|
-
* await program.parseAsync(process.argv
|
|
1793
|
-
* await program.parseAsync(); //
|
|
1854
|
+
* await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
|
|
1855
|
+
* await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
|
|
1794
1856
|
* await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
1795
1857
|
*
|
|
1796
1858
|
* @param {string[]} [argv]
|
|
1797
|
-
* @param {
|
|
1859
|
+
* @param {object} [parseOptions]
|
|
1798
1860
|
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
|
|
1799
1861
|
* @return {Promise}
|
|
1800
1862
|
*/
|
|
@@ -1813,10 +1875,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1813
1875
|
let launchWithNode = false;
|
|
1814
1876
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1815
1877
|
function findFile(baseDir, baseName) {
|
|
1816
|
-
const localBin =
|
|
1817
|
-
if (
|
|
1818
|
-
if (sourceExt.includes(
|
|
1819
|
-
const foundExt = sourceExt.find(
|
|
1878
|
+
const localBin = path11.resolve(baseDir, baseName);
|
|
1879
|
+
if (fs9.existsSync(localBin)) return localBin;
|
|
1880
|
+
if (sourceExt.includes(path11.extname(baseName))) return void 0;
|
|
1881
|
+
const foundExt = sourceExt.find(
|
|
1882
|
+
(ext) => fs9.existsSync(`${localBin}${ext}`)
|
|
1883
|
+
);
|
|
1820
1884
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1821
1885
|
return void 0;
|
|
1822
1886
|
}
|
|
@@ -1827,23 +1891,32 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1827
1891
|
if (this._scriptPath) {
|
|
1828
1892
|
let resolvedScriptPath;
|
|
1829
1893
|
try {
|
|
1830
|
-
resolvedScriptPath =
|
|
1894
|
+
resolvedScriptPath = fs9.realpathSync(this._scriptPath);
|
|
1831
1895
|
} catch (err) {
|
|
1832
1896
|
resolvedScriptPath = this._scriptPath;
|
|
1833
1897
|
}
|
|
1834
|
-
executableDir =
|
|
1898
|
+
executableDir = path11.resolve(
|
|
1899
|
+
path11.dirname(resolvedScriptPath),
|
|
1900
|
+
executableDir
|
|
1901
|
+
);
|
|
1835
1902
|
}
|
|
1836
1903
|
if (executableDir) {
|
|
1837
1904
|
let localFile = findFile(executableDir, executableFile);
|
|
1838
1905
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1839
|
-
const legacyName =
|
|
1906
|
+
const legacyName = path11.basename(
|
|
1907
|
+
this._scriptPath,
|
|
1908
|
+
path11.extname(this._scriptPath)
|
|
1909
|
+
);
|
|
1840
1910
|
if (legacyName !== this._name) {
|
|
1841
|
-
localFile = findFile(
|
|
1911
|
+
localFile = findFile(
|
|
1912
|
+
executableDir,
|
|
1913
|
+
`${legacyName}-${subcommand._name}`
|
|
1914
|
+
);
|
|
1842
1915
|
}
|
|
1843
1916
|
}
|
|
1844
1917
|
executableFile = localFile || executableFile;
|
|
1845
1918
|
}
|
|
1846
|
-
launchWithNode = sourceExt.includes(
|
|
1919
|
+
launchWithNode = sourceExt.includes(path11.extname(executableFile));
|
|
1847
1920
|
let proc;
|
|
1848
1921
|
if (process2.platform !== "win32") {
|
|
1849
1922
|
if (launchWithNode) {
|
|
@@ -1869,12 +1942,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1869
1942
|
});
|
|
1870
1943
|
}
|
|
1871
1944
|
const exitCallback = this._exitCallback;
|
|
1872
|
-
proc.on("close", (code
|
|
1945
|
+
proc.on("close", (code) => {
|
|
1873
1946
|
code = code ?? 1;
|
|
1874
1947
|
if (!exitCallback) {
|
|
1875
1948
|
process2.exit(code);
|
|
1876
1949
|
} else {
|
|
1877
|
-
exitCallback(
|
|
1950
|
+
exitCallback(
|
|
1951
|
+
new CommanderError2(
|
|
1952
|
+
code,
|
|
1953
|
+
"commander.executeSubCommandAsync",
|
|
1954
|
+
"(close)"
|
|
1955
|
+
)
|
|
1956
|
+
);
|
|
1878
1957
|
}
|
|
1879
1958
|
});
|
|
1880
1959
|
proc.on("error", (err) => {
|
|
@@ -1891,7 +1970,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1891
1970
|
if (!exitCallback) {
|
|
1892
1971
|
process2.exit(1);
|
|
1893
1972
|
} else {
|
|
1894
|
-
const wrappedError = new CommanderError2(
|
|
1973
|
+
const wrappedError = new CommanderError2(
|
|
1974
|
+
1,
|
|
1975
|
+
"commander.executeSubCommandAsync",
|
|
1976
|
+
"(error)"
|
|
1977
|
+
);
|
|
1895
1978
|
wrappedError.nestedError = err;
|
|
1896
1979
|
exitCallback(wrappedError);
|
|
1897
1980
|
}
|
|
@@ -1905,7 +1988,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1905
1988
|
const subCommand = this._findCommand(commandName);
|
|
1906
1989
|
if (!subCommand) this.help({ error: true });
|
|
1907
1990
|
let promiseChain;
|
|
1908
|
-
promiseChain = this._chainOrCallSubCommandHook(
|
|
1991
|
+
promiseChain = this._chainOrCallSubCommandHook(
|
|
1992
|
+
promiseChain,
|
|
1993
|
+
subCommand,
|
|
1994
|
+
"preSubcommand"
|
|
1995
|
+
);
|
|
1909
1996
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
1910
1997
|
if (subCommand._executableHandler) {
|
|
1911
1998
|
this._executeSubCommand(subCommand, operands.concat(unknown));
|
|
@@ -1929,9 +2016,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1929
2016
|
if (subCommand && !subCommand._executableHandler) {
|
|
1930
2017
|
subCommand.help();
|
|
1931
2018
|
}
|
|
1932
|
-
return this._dispatchSubcommand(
|
|
1933
|
-
|
|
1934
|
-
|
|
2019
|
+
return this._dispatchSubcommand(
|
|
2020
|
+
subcommandName,
|
|
2021
|
+
[],
|
|
2022
|
+
[this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]
|
|
2023
|
+
);
|
|
1935
2024
|
}
|
|
1936
2025
|
/**
|
|
1937
2026
|
* Check this.args against expected this.registeredArguments.
|
|
@@ -1961,7 +2050,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1961
2050
|
let parsedValue = value;
|
|
1962
2051
|
if (value !== null && argument.parseArg) {
|
|
1963
2052
|
const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
|
|
1964
|
-
parsedValue = this._callParseArg(
|
|
2053
|
+
parsedValue = this._callParseArg(
|
|
2054
|
+
argument,
|
|
2055
|
+
value,
|
|
2056
|
+
previous,
|
|
2057
|
+
invalidValueMessage
|
|
2058
|
+
);
|
|
1965
2059
|
}
|
|
1966
2060
|
return parsedValue;
|
|
1967
2061
|
};
|
|
@@ -2069,7 +2163,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2069
2163
|
}
|
|
2070
2164
|
if (this._defaultCommandName) {
|
|
2071
2165
|
this._outputHelpIfRequested(unknown);
|
|
2072
|
-
return this._dispatchSubcommand(
|
|
2166
|
+
return this._dispatchSubcommand(
|
|
2167
|
+
this._defaultCommandName,
|
|
2168
|
+
operands,
|
|
2169
|
+
unknown
|
|
2170
|
+
);
|
|
2073
2171
|
}
|
|
2074
2172
|
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
|
|
2075
2173
|
this.help({ error: true });
|
|
@@ -2088,7 +2186,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2088
2186
|
this._processArguments();
|
|
2089
2187
|
let promiseChain;
|
|
2090
2188
|
promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
|
|
2091
|
-
promiseChain = this._chainOrCall(
|
|
2189
|
+
promiseChain = this._chainOrCall(
|
|
2190
|
+
promiseChain,
|
|
2191
|
+
() => this._actionHandler(this.processedArgs)
|
|
2192
|
+
);
|
|
2092
2193
|
if (this.parent) {
|
|
2093
2194
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
2094
2195
|
this.parent.emit(commandEvent, operands, unknown);
|
|
@@ -2125,17 +2226,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2125
2226
|
* Find matching command.
|
|
2126
2227
|
*
|
|
2127
2228
|
* @private
|
|
2229
|
+
* @return {Command | undefined}
|
|
2128
2230
|
*/
|
|
2129
2231
|
_findCommand(name) {
|
|
2130
2232
|
if (!name) return void 0;
|
|
2131
|
-
return this.commands.find(
|
|
2233
|
+
return this.commands.find(
|
|
2234
|
+
(cmd) => cmd._name === name || cmd._aliases.includes(name)
|
|
2235
|
+
);
|
|
2132
2236
|
}
|
|
2133
2237
|
/**
|
|
2134
2238
|
* Return an option matching `arg` if any.
|
|
2135
2239
|
*
|
|
2136
2240
|
* @param {string} arg
|
|
2137
2241
|
* @return {Option}
|
|
2138
|
-
* @package
|
|
2242
|
+
* @package
|
|
2139
2243
|
*/
|
|
2140
2244
|
_findOption(arg) {
|
|
2141
2245
|
return this.options.find((option) => option.is(arg));
|
|
@@ -2161,15 +2265,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2161
2265
|
* @private
|
|
2162
2266
|
*/
|
|
2163
2267
|
_checkForConflictingLocalOptions() {
|
|
2164
|
-
const definedNonDefaultOptions = this.options.filter(
|
|
2165
|
-
(
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
return false;
|
|
2169
|
-
}
|
|
2170
|
-
return this.getOptionValueSource(optionKey) !== "default";
|
|
2268
|
+
const definedNonDefaultOptions = this.options.filter((option) => {
|
|
2269
|
+
const optionKey = option.attributeName();
|
|
2270
|
+
if (this.getOptionValue(optionKey) === void 0) {
|
|
2271
|
+
return false;
|
|
2171
2272
|
}
|
|
2172
|
-
|
|
2273
|
+
return this.getOptionValueSource(optionKey) !== "default";
|
|
2274
|
+
});
|
|
2173
2275
|
const optionsWithConflicting = definedNonDefaultOptions.filter(
|
|
2174
2276
|
(option) => option.conflictsWith.length > 0
|
|
2175
2277
|
);
|
|
@@ -2299,7 +2401,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2299
2401
|
/**
|
|
2300
2402
|
* Return an object containing local option values as key-value pairs.
|
|
2301
2403
|
*
|
|
2302
|
-
* @return {
|
|
2404
|
+
* @return {object}
|
|
2303
2405
|
*/
|
|
2304
2406
|
opts() {
|
|
2305
2407
|
if (this._storeOptionsAsProperties) {
|
|
@@ -2316,7 +2418,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2316
2418
|
/**
|
|
2317
2419
|
* Return an object containing merged local and global option values as key-value pairs.
|
|
2318
2420
|
*
|
|
2319
|
-
* @return {
|
|
2421
|
+
* @return {object}
|
|
2320
2422
|
*/
|
|
2321
2423
|
optsWithGlobals() {
|
|
2322
2424
|
return this._getCommandAndAncestors().reduce(
|
|
@@ -2328,13 +2430,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2328
2430
|
* Display error message and exit (or call exitOverride).
|
|
2329
2431
|
*
|
|
2330
2432
|
* @param {string} message
|
|
2331
|
-
* @param {
|
|
2433
|
+
* @param {object} [errorOptions]
|
|
2332
2434
|
* @param {string} [errorOptions.code] - an id string representing the error
|
|
2333
2435
|
* @param {number} [errorOptions.exitCode] - used with process.exit
|
|
2334
2436
|
*/
|
|
2335
2437
|
error(message, errorOptions) {
|
|
2336
|
-
this._outputConfiguration.outputError(
|
|
2337
|
-
|
|
2438
|
+
this._outputConfiguration.outputError(
|
|
2439
|
+
`${message}
|
|
2440
|
+
`,
|
|
2441
|
+
this._outputConfiguration.writeErr
|
|
2442
|
+
);
|
|
2338
2443
|
if (typeof this._showHelpAfterError === "string") {
|
|
2339
2444
|
this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
2340
2445
|
`);
|
|
@@ -2357,7 +2462,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2357
2462
|
this.options.forEach((option) => {
|
|
2358
2463
|
if (option.envVar && option.envVar in process2.env) {
|
|
2359
2464
|
const optionKey = option.attributeName();
|
|
2360
|
-
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
2465
|
+
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
2466
|
+
this.getOptionValueSource(optionKey)
|
|
2467
|
+
)) {
|
|
2361
2468
|
if (option.required || option.optional) {
|
|
2362
2469
|
this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
|
|
2363
2470
|
} else {
|
|
@@ -2377,9 +2484,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2377
2484
|
const hasCustomOptionValue = (optionKey) => {
|
|
2378
2485
|
return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
|
|
2379
2486
|
};
|
|
2380
|
-
this.options.filter(
|
|
2487
|
+
this.options.filter(
|
|
2488
|
+
(option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
|
|
2489
|
+
this.getOptionValue(option.attributeName()),
|
|
2490
|
+
option
|
|
2491
|
+
)
|
|
2492
|
+
).forEach((option) => {
|
|
2381
2493
|
Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
|
|
2382
|
-
this.setOptionValueWithSource(
|
|
2494
|
+
this.setOptionValueWithSource(
|
|
2495
|
+
impliedKey,
|
|
2496
|
+
option.implied[impliedKey],
|
|
2497
|
+
"implied"
|
|
2498
|
+
);
|
|
2383
2499
|
});
|
|
2384
2500
|
});
|
|
2385
2501
|
}
|
|
@@ -2424,8 +2540,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2424
2540
|
const findBestOptionFromValue = (option2) => {
|
|
2425
2541
|
const optionKey = option2.attributeName();
|
|
2426
2542
|
const optionValue = this.getOptionValue(optionKey);
|
|
2427
|
-
const negativeOption = this.options.find(
|
|
2428
|
-
|
|
2543
|
+
const negativeOption = this.options.find(
|
|
2544
|
+
(target) => target.negate && optionKey === target.attributeName()
|
|
2545
|
+
);
|
|
2546
|
+
const positiveOption = this.options.find(
|
|
2547
|
+
(target) => !target.negate && optionKey === target.attributeName()
|
|
2548
|
+
);
|
|
2429
2549
|
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
|
|
2430
2550
|
return negativeOption;
|
|
2431
2551
|
}
|
|
@@ -2529,11 +2649,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2529
2649
|
* Set the description.
|
|
2530
2650
|
*
|
|
2531
2651
|
* @param {string} [str]
|
|
2532
|
-
* @param {
|
|
2652
|
+
* @param {object} [argsDescription]
|
|
2533
2653
|
* @return {(string|Command)}
|
|
2534
2654
|
*/
|
|
2535
2655
|
description(str, argsDescription) {
|
|
2536
|
-
if (str === void 0 && argsDescription === void 0)
|
|
2656
|
+
if (str === void 0 && argsDescription === void 0)
|
|
2657
|
+
return this._description;
|
|
2537
2658
|
this._description = str;
|
|
2538
2659
|
if (argsDescription) {
|
|
2539
2660
|
this._argsDescription = argsDescription;
|
|
@@ -2565,11 +2686,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2565
2686
|
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
|
|
2566
2687
|
command = this.commands[this.commands.length - 1];
|
|
2567
2688
|
}
|
|
2568
|
-
if (alias === command._name)
|
|
2689
|
+
if (alias === command._name)
|
|
2690
|
+
throw new Error("Command alias can't be the same as its name");
|
|
2569
2691
|
const matchingCommand = this.parent?._findCommand(alias);
|
|
2570
2692
|
if (matchingCommand) {
|
|
2571
2693
|
const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
|
|
2572
|
-
throw new Error(
|
|
2694
|
+
throw new Error(
|
|
2695
|
+
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
|
|
2696
|
+
);
|
|
2573
2697
|
}
|
|
2574
2698
|
command._aliases.push(alias);
|
|
2575
2699
|
return this;
|
|
@@ -2632,7 +2756,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2632
2756
|
* @return {Command}
|
|
2633
2757
|
*/
|
|
2634
2758
|
nameFromFilename(filename) {
|
|
2635
|
-
this._name =
|
|
2759
|
+
this._name = path11.basename(filename, path11.extname(filename));
|
|
2636
2760
|
return this;
|
|
2637
2761
|
}
|
|
2638
2762
|
/**
|
|
@@ -2646,9 +2770,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2646
2770
|
* @param {string} [path]
|
|
2647
2771
|
* @return {(string|null|Command)}
|
|
2648
2772
|
*/
|
|
2649
|
-
executableDir(
|
|
2650
|
-
if (
|
|
2651
|
-
this._executableDir =
|
|
2773
|
+
executableDir(path12) {
|
|
2774
|
+
if (path12 === void 0) return this._executableDir;
|
|
2775
|
+
this._executableDir = path12;
|
|
2652
2776
|
return this;
|
|
2653
2777
|
}
|
|
2654
2778
|
/**
|
|
@@ -2708,7 +2832,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2708
2832
|
this.emit(this._getHelpOption().long);
|
|
2709
2833
|
}
|
|
2710
2834
|
this.emit("afterHelp", context2);
|
|
2711
|
-
this._getCommandAndAncestors().forEach(
|
|
2835
|
+
this._getCommandAndAncestors().forEach(
|
|
2836
|
+
(command) => command.emit("afterAllHelp", context2)
|
|
2837
|
+
);
|
|
2712
2838
|
}
|
|
2713
2839
|
/**
|
|
2714
2840
|
* You can pass in flags and a description to customise the built-in help option.
|
|
@@ -2741,7 +2867,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2741
2867
|
* Returns null if has been disabled with .helpOption(false).
|
|
2742
2868
|
*
|
|
2743
2869
|
* @returns {(Option | null)} the help option
|
|
2744
|
-
* @package
|
|
2870
|
+
* @package
|
|
2745
2871
|
*/
|
|
2746
2872
|
_getHelpOption() {
|
|
2747
2873
|
if (this._helpOption === void 0) {
|
|
@@ -2876,8 +3002,206 @@ var require_commander = __commonJS({
|
|
|
2876
3002
|
}
|
|
2877
3003
|
});
|
|
2878
3004
|
|
|
3005
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_arm64_127.node
|
|
3006
|
+
var require_uws_darwin_arm64_127 = __commonJS({
|
|
3007
|
+
"../../node_modules/uWebSockets.js/uws_darwin_arm64_127.node"(exports, module) {
|
|
3008
|
+
module.exports = "./uws_darwin_arm64_127-NGHTXN5Q.node";
|
|
3009
|
+
}
|
|
3010
|
+
});
|
|
3011
|
+
|
|
3012
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_arm64_137.node
|
|
3013
|
+
var require_uws_darwin_arm64_137 = __commonJS({
|
|
3014
|
+
"../../node_modules/uWebSockets.js/uws_darwin_arm64_137.node"(exports, module) {
|
|
3015
|
+
module.exports = "./uws_darwin_arm64_137-ESY6MPLH.node";
|
|
3016
|
+
}
|
|
3017
|
+
});
|
|
3018
|
+
|
|
3019
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_arm64_147.node
|
|
3020
|
+
var require_uws_darwin_arm64_147 = __commonJS({
|
|
3021
|
+
"../../node_modules/uWebSockets.js/uws_darwin_arm64_147.node"(exports, module) {
|
|
3022
|
+
module.exports = "./uws_darwin_arm64_147-V7BKA3SU.node";
|
|
3023
|
+
}
|
|
3024
|
+
});
|
|
3025
|
+
|
|
3026
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_x64_127.node
|
|
3027
|
+
var require_uws_darwin_x64_127 = __commonJS({
|
|
3028
|
+
"../../node_modules/uWebSockets.js/uws_darwin_x64_127.node"(exports, module) {
|
|
3029
|
+
module.exports = "./uws_darwin_x64_127-WIZGG7MS.node";
|
|
3030
|
+
}
|
|
3031
|
+
});
|
|
3032
|
+
|
|
3033
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_x64_137.node
|
|
3034
|
+
var require_uws_darwin_x64_137 = __commonJS({
|
|
3035
|
+
"../../node_modules/uWebSockets.js/uws_darwin_x64_137.node"(exports, module) {
|
|
3036
|
+
module.exports = "./uws_darwin_x64_137-APKZWL4Y.node";
|
|
3037
|
+
}
|
|
3038
|
+
});
|
|
3039
|
+
|
|
3040
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_x64_147.node
|
|
3041
|
+
var require_uws_darwin_x64_147 = __commonJS({
|
|
3042
|
+
"../../node_modules/uWebSockets.js/uws_darwin_x64_147.node"(exports, module) {
|
|
3043
|
+
module.exports = "./uws_darwin_x64_147-W2HKFQZT.node";
|
|
3044
|
+
}
|
|
3045
|
+
});
|
|
3046
|
+
|
|
3047
|
+
// ../../node_modules/uWebSockets.js/uws_linux_arm64_127.node
|
|
3048
|
+
var require_uws_linux_arm64_127 = __commonJS({
|
|
3049
|
+
"../../node_modules/uWebSockets.js/uws_linux_arm64_127.node"(exports, module) {
|
|
3050
|
+
module.exports = "./uws_linux_arm64_127-3CO7NSFJ.node";
|
|
3051
|
+
}
|
|
3052
|
+
});
|
|
3053
|
+
|
|
3054
|
+
// ../../node_modules/uWebSockets.js/uws_linux_arm64_137.node
|
|
3055
|
+
var require_uws_linux_arm64_137 = __commonJS({
|
|
3056
|
+
"../../node_modules/uWebSockets.js/uws_linux_arm64_137.node"(exports, module) {
|
|
3057
|
+
module.exports = "./uws_linux_arm64_137-HWEDGGZV.node";
|
|
3058
|
+
}
|
|
3059
|
+
});
|
|
3060
|
+
|
|
3061
|
+
// ../../node_modules/uWebSockets.js/uws_linux_arm64_147.node
|
|
3062
|
+
var require_uws_linux_arm64_147 = __commonJS({
|
|
3063
|
+
"../../node_modules/uWebSockets.js/uws_linux_arm64_147.node"(exports, module) {
|
|
3064
|
+
module.exports = "./uws_linux_arm64_147-7UCIYMK2.node";
|
|
3065
|
+
}
|
|
3066
|
+
});
|
|
3067
|
+
|
|
3068
|
+
// ../../node_modules/uWebSockets.js/uws_linux_x64_127.node
|
|
3069
|
+
var require_uws_linux_x64_127 = __commonJS({
|
|
3070
|
+
"../../node_modules/uWebSockets.js/uws_linux_x64_127.node"(exports, module) {
|
|
3071
|
+
module.exports = "./uws_linux_x64_127-KA4E76LJ.node";
|
|
3072
|
+
}
|
|
3073
|
+
});
|
|
3074
|
+
|
|
3075
|
+
// ../../node_modules/uWebSockets.js/uws_linux_x64_137.node
|
|
3076
|
+
var require_uws_linux_x64_137 = __commonJS({
|
|
3077
|
+
"../../node_modules/uWebSockets.js/uws_linux_x64_137.node"(exports, module) {
|
|
3078
|
+
module.exports = "./uws_linux_x64_137-DDFLTTJR.node";
|
|
3079
|
+
}
|
|
3080
|
+
});
|
|
3081
|
+
|
|
3082
|
+
// ../../node_modules/uWebSockets.js/uws_linux_x64_147.node
|
|
3083
|
+
var require_uws_linux_x64_147 = __commonJS({
|
|
3084
|
+
"../../node_modules/uWebSockets.js/uws_linux_x64_147.node"(exports, module) {
|
|
3085
|
+
module.exports = "./uws_linux_x64_147-MJSFREL3.node";
|
|
3086
|
+
}
|
|
3087
|
+
});
|
|
3088
|
+
|
|
3089
|
+
// ../../node_modules/uWebSockets.js/uws_win32_x64_127.node
|
|
3090
|
+
var require_uws_win32_x64_127 = __commonJS({
|
|
3091
|
+
"../../node_modules/uWebSockets.js/uws_win32_x64_127.node"(exports, module) {
|
|
3092
|
+
module.exports = "./uws_win32_x64_127-O4US4Y4L.node";
|
|
3093
|
+
}
|
|
3094
|
+
});
|
|
3095
|
+
|
|
3096
|
+
// ../../node_modules/uWebSockets.js/uws_win32_x64_137.node
|
|
3097
|
+
var require_uws_win32_x64_137 = __commonJS({
|
|
3098
|
+
"../../node_modules/uWebSockets.js/uws_win32_x64_137.node"(exports, module) {
|
|
3099
|
+
module.exports = "./uws_win32_x64_137-L5OZROQ7.node";
|
|
3100
|
+
}
|
|
3101
|
+
});
|
|
3102
|
+
|
|
3103
|
+
// ../../node_modules/uWebSockets.js/uws_win32_x64_147.node
|
|
3104
|
+
var require_uws_win32_x64_147 = __commonJS({
|
|
3105
|
+
"../../node_modules/uWebSockets.js/uws_win32_x64_147.node"(exports, module) {
|
|
3106
|
+
module.exports = "./uws_win32_x64_147-D7MGKVRG.node";
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
3109
|
+
|
|
3110
|
+
// require("./uws_*_*_*.node") in ../../node_modules/uWebSockets.js/uws.js
|
|
3111
|
+
var globRequire_uws______node;
|
|
3112
|
+
var init_ = __esm({
|
|
3113
|
+
'require("./uws_*_*_*.node") in ../../node_modules/uWebSockets.js/uws.js'() {
|
|
3114
|
+
globRequire_uws______node = __glob({
|
|
3115
|
+
"./uws_darwin_arm64_127.node": () => require_uws_darwin_arm64_127(),
|
|
3116
|
+
"./uws_darwin_arm64_137.node": () => require_uws_darwin_arm64_137(),
|
|
3117
|
+
"./uws_darwin_arm64_147.node": () => require_uws_darwin_arm64_147(),
|
|
3118
|
+
"./uws_darwin_x64_127.node": () => require_uws_darwin_x64_127(),
|
|
3119
|
+
"./uws_darwin_x64_137.node": () => require_uws_darwin_x64_137(),
|
|
3120
|
+
"./uws_darwin_x64_147.node": () => require_uws_darwin_x64_147(),
|
|
3121
|
+
"./uws_linux_arm64_127.node": () => require_uws_linux_arm64_127(),
|
|
3122
|
+
"./uws_linux_arm64_137.node": () => require_uws_linux_arm64_137(),
|
|
3123
|
+
"./uws_linux_arm64_147.node": () => require_uws_linux_arm64_147(),
|
|
3124
|
+
"./uws_linux_x64_127.node": () => require_uws_linux_x64_127(),
|
|
3125
|
+
"./uws_linux_x64_137.node": () => require_uws_linux_x64_137(),
|
|
3126
|
+
"./uws_linux_x64_147.node": () => require_uws_linux_x64_147(),
|
|
3127
|
+
"./uws_win32_x64_127.node": () => require_uws_win32_x64_127(),
|
|
3128
|
+
"./uws_win32_x64_137.node": () => require_uws_win32_x64_137(),
|
|
3129
|
+
"./uws_win32_x64_147.node": () => require_uws_win32_x64_147()
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
});
|
|
3133
|
+
|
|
3134
|
+
// ../../node_modules/uWebSockets.js/uws.js
|
|
3135
|
+
var require_uws = __commonJS({
|
|
3136
|
+
"../../node_modules/uWebSockets.js/uws.js"(exports, module) {
|
|
3137
|
+
init_();
|
|
3138
|
+
module.exports = (() => {
|
|
3139
|
+
try {
|
|
3140
|
+
return globRequire_uws______node("./uws_" + process.platform + "_" + process.arch + "_" + process.versions.modules + ".node");
|
|
3141
|
+
} catch (e) {
|
|
3142
|
+
throw new Error("This version of uWS.js (v20.67.0) supports only Node.js versions 22, 24 and 26 on (glibc) Linux, macOS and Windows, on Tier 1 platforms (https://github.com/nodejs/node/blob/master/BUILDING.md#platform-list).\n\n" + e.toString());
|
|
3143
|
+
}
|
|
3144
|
+
})();
|
|
3145
|
+
var MAX_U8 = Math.pow(2, 8) - 1;
|
|
3146
|
+
var MAX_U16 = Math.pow(2, 16) - 1;
|
|
3147
|
+
var textEncoder = new TextEncoder();
|
|
3148
|
+
var toUint8Array = (value) => {
|
|
3149
|
+
if (value === void 0) return new Uint8Array(0);
|
|
3150
|
+
else if (typeof value === "string") return textEncoder.encode(value);
|
|
3151
|
+
else if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
3152
|
+
else if (value instanceof SharedArrayBuffer) return new Uint8Array(value);
|
|
3153
|
+
else return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
3154
|
+
};
|
|
3155
|
+
module.exports.DeclarativeResponse = class DeclarativeResponse {
|
|
3156
|
+
constructor() {
|
|
3157
|
+
this.instructions = [];
|
|
3158
|
+
}
|
|
3159
|
+
// Append instruction and 1-byte length values
|
|
3160
|
+
_appendInstruction(opcode, ...values) {
|
|
3161
|
+
this.instructions.push(opcode);
|
|
3162
|
+
values.forEach((value) => {
|
|
3163
|
+
const uint8Array = toUint8Array(value);
|
|
3164
|
+
if (uint8Array.byteLength > MAX_U8) throw new RangeError("Data length exceeds " + MAX_U8);
|
|
3165
|
+
this.instructions.push(uint8Array.byteLength, ...uint8Array);
|
|
3166
|
+
});
|
|
3167
|
+
}
|
|
3168
|
+
// Append instruction and 2-byte length value
|
|
3169
|
+
_appendInstructionWithLength(opcode, value) {
|
|
3170
|
+
const uint8Array = toUint8Array(value);
|
|
3171
|
+
if (uint8Array.byteLength > MAX_U16) throw new RangeError("Data length exceeds " + MAX_U16);
|
|
3172
|
+
this.instructions.push(opcode, uint8Array.byteLength & 255, uint8Array.byteLength >> 8 & 255, ...uint8Array);
|
|
3173
|
+
}
|
|
3174
|
+
writeHeader(key, value) {
|
|
3175
|
+
return this._appendInstruction(1, key, value), this;
|
|
3176
|
+
}
|
|
3177
|
+
writeBody() {
|
|
3178
|
+
return this.instructions.push(2), this;
|
|
3179
|
+
}
|
|
3180
|
+
writeQueryValue(key) {
|
|
3181
|
+
return this._appendInstruction(3, key), this;
|
|
3182
|
+
}
|
|
3183
|
+
writeHeaderValue(key) {
|
|
3184
|
+
return this._appendInstruction(4, key), this;
|
|
3185
|
+
}
|
|
3186
|
+
write(value) {
|
|
3187
|
+
return this._appendInstructionWithLength(5, value), this;
|
|
3188
|
+
}
|
|
3189
|
+
writeParameterValue(key) {
|
|
3190
|
+
return this._appendInstruction(6, key), this;
|
|
3191
|
+
}
|
|
3192
|
+
writeStatus(status) {
|
|
3193
|
+
return this._appendInstruction(7, status), this;
|
|
3194
|
+
}
|
|
3195
|
+
end(value) {
|
|
3196
|
+
this._appendInstructionWithLength(0, value);
|
|
3197
|
+
return new Uint8Array(this.instructions).buffer;
|
|
3198
|
+
}
|
|
3199
|
+
};
|
|
3200
|
+
}
|
|
3201
|
+
});
|
|
3202
|
+
|
|
2879
3203
|
// node_modules/commander/esm.mjs
|
|
2880
|
-
var import_index = __toESM(require_commander());
|
|
3204
|
+
var import_index = __toESM(require_commander(), 1);
|
|
2881
3205
|
var {
|
|
2882
3206
|
program,
|
|
2883
3207
|
createCommand,
|
|
@@ -2895,12 +3219,12 @@ var {
|
|
|
2895
3219
|
|
|
2896
3220
|
// package.json
|
|
2897
3221
|
var package_default = {
|
|
2898
|
-
version: "
|
|
3222
|
+
version: "6.0.0"};
|
|
2899
3223
|
var ALWAYS_EXTERNAL = ["uWebSockets.js"];
|
|
2900
3224
|
function getUserExternals(cwd) {
|
|
2901
3225
|
let pkgExternals = [];
|
|
2902
3226
|
try {
|
|
2903
|
-
const pkgPath =
|
|
3227
|
+
const pkgPath = path7.join(cwd, "package.json");
|
|
2904
3228
|
if (fs.existsSync(pkgPath)) {
|
|
2905
3229
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
2906
3230
|
const deps = Object.keys(pkg.dependencies || {});
|
|
@@ -2918,8 +3242,8 @@ function getUserExternals(cwd) {
|
|
|
2918
3242
|
|
|
2919
3243
|
// src/commands/build.ts
|
|
2920
3244
|
async function buildProject(entry) {
|
|
2921
|
-
const entryPath =
|
|
2922
|
-
const outPath =
|
|
3245
|
+
const entryPath = path7.resolve(process.cwd(), entry);
|
|
3246
|
+
const outPath = path7.resolve(process.cwd(), "dist/index.js");
|
|
2923
3247
|
const userExternals = getUserExternals(process.cwd());
|
|
2924
3248
|
console.log(`\u{1F528} Building production bundle from ${entry}...`);
|
|
2925
3249
|
try {
|
|
@@ -2939,9 +3263,388 @@ async function buildProject(entry) {
|
|
|
2939
3263
|
process.exit(1);
|
|
2940
3264
|
}
|
|
2941
3265
|
}
|
|
3266
|
+
function colourMethod(method) {
|
|
3267
|
+
const m = method.toUpperCase();
|
|
3268
|
+
const padded = m.padEnd(7);
|
|
3269
|
+
switch (m) {
|
|
3270
|
+
case "GET":
|
|
3271
|
+
return pc.bold(pc.green(padded));
|
|
3272
|
+
case "POST":
|
|
3273
|
+
return pc.bold(pc.blue(padded));
|
|
3274
|
+
case "PUT":
|
|
3275
|
+
return pc.bold(pc.yellow(padded));
|
|
3276
|
+
case "PATCH":
|
|
3277
|
+
return pc.bold(pc.magenta(padded));
|
|
3278
|
+
case "DELETE":
|
|
3279
|
+
return pc.bold(pc.red(padded));
|
|
3280
|
+
case "HEAD":
|
|
3281
|
+
return pc.dim(padded);
|
|
3282
|
+
case "OPTIONS":
|
|
3283
|
+
return pc.dim(padded);
|
|
3284
|
+
case "WS":
|
|
3285
|
+
return pc.bold(pc.cyan(padded));
|
|
3286
|
+
default:
|
|
3287
|
+
return padded;
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
var badge = {
|
|
3291
|
+
validation(label) {
|
|
3292
|
+
return pc.cyan(label);
|
|
3293
|
+
},
|
|
3294
|
+
deprecated() {
|
|
3295
|
+
return pc.bold(pc.red("\u2298 DEPRECATED"));
|
|
3296
|
+
},
|
|
3297
|
+
timeout(ms) {
|
|
3298
|
+
return pc.dim(`${ms}ms`);
|
|
3299
|
+
},
|
|
3300
|
+
tags(tags) {
|
|
3301
|
+
if (!tags.length) return "";
|
|
3302
|
+
return tags.map((t) => pc.dim(`#${t}`)).join(" ");
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
function visibleLength(s) {
|
|
3306
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
3307
|
+
}
|
|
3308
|
+
function pad(s, width, align) {
|
|
3309
|
+
const v = visibleLength(s);
|
|
3310
|
+
if (v >= width) return s;
|
|
3311
|
+
const filler = " ".repeat(width - v);
|
|
3312
|
+
return align === "right" ? filler + s : s + filler;
|
|
3313
|
+
}
|
|
3314
|
+
function truncate(s, max) {
|
|
3315
|
+
if (visibleLength(s) <= max) return s;
|
|
3316
|
+
const stripped = s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3317
|
+
return stripped.slice(0, max - 1) + pc.dim("\u2026");
|
|
3318
|
+
}
|
|
3319
|
+
function renderTable(columns, rows, terminalWidth = process.stdout.columns || 100) {
|
|
3320
|
+
const widths = columns.map((col, i) => {
|
|
3321
|
+
const headerW = visibleLength(col.header);
|
|
3322
|
+
const cellW = Math.max(
|
|
3323
|
+
headerW,
|
|
3324
|
+
...rows.map((r) => visibleLength(r[i] ?? ""))
|
|
3325
|
+
);
|
|
3326
|
+
let w = Math.max(headerW, cellW);
|
|
3327
|
+
if (col.minWidth) w = Math.max(w, col.minWidth);
|
|
3328
|
+
if (col.maxWidth) w = Math.min(w, col.maxWidth);
|
|
3329
|
+
return w;
|
|
3330
|
+
});
|
|
3331
|
+
const overheadPerSep = 3;
|
|
3332
|
+
const overhead = (columns.length + 1) * 2 + overheadPerSep * (columns.length - 1);
|
|
3333
|
+
let total = widths.reduce((a, b) => a + b, 0) + overhead;
|
|
3334
|
+
if (total > terminalWidth) {
|
|
3335
|
+
const flexIdx = columns.map((c, i) => ({ c, i })).filter(({ c }) => !c.minWidth).map(({ i }) => i);
|
|
3336
|
+
let excess = total - terminalWidth;
|
|
3337
|
+
for (let pass = 0; pass < 8 && excess > 0; pass++) {
|
|
3338
|
+
for (const i of flexIdx) {
|
|
3339
|
+
if (excess <= 0) break;
|
|
3340
|
+
if (widths[i] > 8) {
|
|
3341
|
+
widths[i]--;
|
|
3342
|
+
excess--;
|
|
3343
|
+
total--;
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
const bar = (l, m, r) => l + widths.map((w) => "\u2500".repeat(w + 2)).join(m) + r;
|
|
3349
|
+
const lines = [];
|
|
3350
|
+
lines.push(pc.dim(bar("\u250C", "\u252C", "\u2510")));
|
|
3351
|
+
lines.push(
|
|
3352
|
+
pc.dim("\u2502 ") + columns.map((c, i) => pc.bold(pad(c.header, widths[i], c.align ?? "left"))).join(pc.dim(" \u2502 ")) + pc.dim(" \u2502")
|
|
3353
|
+
);
|
|
3354
|
+
lines.push(pc.dim(bar("\u251C", "\u253C", "\u2524")));
|
|
3355
|
+
for (const row of rows) {
|
|
3356
|
+
lines.push(
|
|
3357
|
+
pc.dim("\u2502 ") + columns.map((c, i) => {
|
|
3358
|
+
const cell = row[i] ?? "";
|
|
3359
|
+
const truncated = c.maxWidth ? truncate(cell, widths[i]) : cell;
|
|
3360
|
+
return pad(truncated, widths[i], c.align ?? "left");
|
|
3361
|
+
}).join(pc.dim(" \u2502 ")) + pc.dim(" \u2502")
|
|
3362
|
+
);
|
|
3363
|
+
}
|
|
3364
|
+
lines.push(pc.dim(bar("\u2514", "\u2534", "\u2518")));
|
|
3365
|
+
return lines.join("\n");
|
|
3366
|
+
}
|
|
3367
|
+
function pluralise(n, singular, plural) {
|
|
3368
|
+
return n === 1 ? `${n} ${singular}` : `${n} ${plural ?? singular + "s"}`;
|
|
3369
|
+
}
|
|
3370
|
+
var symbols = {
|
|
3371
|
+
ok: pc.green("\u2713"),
|
|
3372
|
+
warn: pc.yellow("\u26A0"),
|
|
3373
|
+
fail: pc.red("\u2717"),
|
|
3374
|
+
info: pc.cyan("\u2139"),
|
|
3375
|
+
bullet: pc.dim("\u2022"),
|
|
3376
|
+
arrow: pc.dim("\u2192")
|
|
3377
|
+
};
|
|
3378
|
+
async function loadApp(entry) {
|
|
3379
|
+
const entryPath = path7.resolve(process.cwd(), entry);
|
|
3380
|
+
const tempDir = path7.resolve(process.cwd(), ".axiomify");
|
|
3381
|
+
const tempPath = path7.join(tempDir, "inspect.cjs");
|
|
3382
|
+
const userExternals = getUserExternals(process.cwd());
|
|
3383
|
+
await esbuild.build({
|
|
3384
|
+
entryPoints: [entryPath],
|
|
3385
|
+
bundle: true,
|
|
3386
|
+
platform: "node",
|
|
3387
|
+
format: "cjs",
|
|
3388
|
+
outfile: tempPath,
|
|
3389
|
+
external: [.../* @__PURE__ */ new Set([...userExternals, "node:*"])],
|
|
3390
|
+
// Silence esbuild's own progress chatter — the CLI command above is
|
|
3391
|
+
// responsible for its own user-facing output.
|
|
3392
|
+
logLevel: "error"
|
|
3393
|
+
});
|
|
3394
|
+
try {
|
|
3395
|
+
delete __require.cache[__require.resolve(tempPath)];
|
|
3396
|
+
} catch {
|
|
3397
|
+
}
|
|
3398
|
+
const hangTimer = setTimeout(() => {
|
|
3399
|
+
process.stderr.write(
|
|
3400
|
+
"\n" + pc.yellow("\u26A0 CLI inspection is taking longer than expected.") + "\n Your entry file may be starting a server unconditionally.\n Wrap the listen() call in " + pc.cyan("if (require.main === module) { ... }") + " so it only runs when executed directly.\n\n"
|
|
3401
|
+
);
|
|
3402
|
+
}, 5e3);
|
|
3403
|
+
hangTimer.unref();
|
|
3404
|
+
let mod;
|
|
3405
|
+
try {
|
|
3406
|
+
mod = __require(tempPath);
|
|
3407
|
+
} finally {
|
|
3408
|
+
clearTimeout(hangTimer);
|
|
3409
|
+
}
|
|
3410
|
+
const app = mod.app ?? mod.default;
|
|
3411
|
+
if (!app || typeof app.registeredRoutes === "undefined") {
|
|
3412
|
+
await fs5.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
3413
|
+
});
|
|
3414
|
+
throw new Error(
|
|
3415
|
+
"Could not find an exported Axiomify instance.\nEnsure your entry file exports the app:\n export const app = new Axiomify();\nor:\n export default app;"
|
|
3416
|
+
);
|
|
3417
|
+
}
|
|
3418
|
+
const cleanup = async () => {
|
|
3419
|
+
await fs5.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
3420
|
+
});
|
|
3421
|
+
};
|
|
3422
|
+
return { app, cleanup };
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
// src/commands/check.ts
|
|
3426
|
+
function add(ctx, f) {
|
|
3427
|
+
ctx.findings.push(f);
|
|
3428
|
+
}
|
|
3429
|
+
function checkRequestId(ctx) {
|
|
3430
|
+
const onRequest = ctx.app.hooks?.hooks?.onRequest ?? [];
|
|
3431
|
+
if (onRequest.length === 0) {
|
|
3432
|
+
add(ctx, {
|
|
3433
|
+
severity: "warn",
|
|
3434
|
+
area: "observability",
|
|
3435
|
+
message: "`app.enableRequestId()` has not been called",
|
|
3436
|
+
hint: "Distributed-trace correlation will be impossible without an X-Request-Id header. Add `app.enableRequestId()` after construction unless you handle this elsewhere."
|
|
3437
|
+
});
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
add(ctx, {
|
|
3441
|
+
severity: "ok",
|
|
3442
|
+
area: "observability",
|
|
3443
|
+
message: `onRequest hooks: ${onRequest.length} registered`
|
|
3444
|
+
});
|
|
3445
|
+
}
|
|
3446
|
+
function checkEnvVars(ctx) {
|
|
3447
|
+
const expectedInProd = ["JWT_SECRET", "NODE_ENV"];
|
|
3448
|
+
for (const key of expectedInProd) {
|
|
3449
|
+
if (!ctx.envKeys.has(key)) continue;
|
|
3450
|
+
if (process.env[key]) {
|
|
3451
|
+
add(ctx, { severity: "ok", area: "env", message: `${key} is set` });
|
|
3452
|
+
} else {
|
|
3453
|
+
add(ctx, {
|
|
3454
|
+
severity: "warn",
|
|
3455
|
+
area: "env",
|
|
3456
|
+
message: `${key} referenced in source but not set in environment`,
|
|
3457
|
+
hint: key === "JWT_SECRET" ? "Set this before deploying. Generate one via `node -e \"console.log(require('crypto').randomBytes(48).toString('base64'))\"`" : `Ensure ${key} is set in your deployment environment.`
|
|
3458
|
+
});
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
function checkResponseSchemas(ctx) {
|
|
3463
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3464
|
+
const missing = routes.filter(
|
|
3465
|
+
(r) => r.schema?.body && !r.schema?.response
|
|
3466
|
+
);
|
|
3467
|
+
if (missing.length > 0) {
|
|
3468
|
+
add(ctx, {
|
|
3469
|
+
severity: "warn",
|
|
3470
|
+
area: "validation",
|
|
3471
|
+
message: `${missing.length} route${missing.length === 1 ? "" : "s"} with body schema but no response schema`,
|
|
3472
|
+
hint: `Declaring \`schema.response\` pins the API contract \u2014 without it, internal model field names leak to clients and breaking changes go undetected. First offender: ${missing[0].method} ${missing[0].path}`
|
|
3473
|
+
});
|
|
3474
|
+
} else if (routes.length > 0) {
|
|
3475
|
+
add(ctx, {
|
|
3476
|
+
severity: "ok",
|
|
3477
|
+
area: "validation",
|
|
3478
|
+
message: "every route with a body schema also declares a response schema"
|
|
3479
|
+
});
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
function checkOpenApiNaming(ctx) {
|
|
3483
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3484
|
+
const usingMeta = routes.filter((r) => r.meta);
|
|
3485
|
+
if (usingMeta.length > 0) {
|
|
3486
|
+
add(ctx, {
|
|
3487
|
+
severity: "fail",
|
|
3488
|
+
area: "api",
|
|
3489
|
+
message: `${usingMeta.length} route${usingMeta.length === 1 ? "" : "s"} use the removed \`meta:\` field`,
|
|
3490
|
+
hint: `The \`meta:\` field was removed in 6.0. Move all metadata into \`schema:\` \u2014 e.g. schema: { tags: ['Users'], summary: '...' }. First offender: ${usingMeta[0].method} ${usingMeta[0].path}`
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
const usingOpenapi = routes.filter((r) => r.openapi);
|
|
3494
|
+
if (usingOpenapi.length > 0) {
|
|
3495
|
+
add(ctx, {
|
|
3496
|
+
severity: "fail",
|
|
3497
|
+
area: "api",
|
|
3498
|
+
message: `${usingOpenapi.length} route${usingOpenapi.length === 1 ? "" : "s"} use the removed top-level \`openapi:\` field`,
|
|
3499
|
+
hint: `The separate \`openapi:\` property was removed in 6.1. Move all metadata directly into \`schema:\` alongside your Zod fields. Run \`npx axiomify migrate\` to apply automatically. First offender: ${usingOpenapi[0].method} ${usingOpenapi[0].path}`
|
|
3500
|
+
});
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
function checkHealthCheck(ctx) {
|
|
3504
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3505
|
+
const hasHealth = routes.some(
|
|
3506
|
+
(r) => r.method === "GET" && ["/health", "/healthz", "/-/health", "/ping", "/live", "/ready"].some(
|
|
3507
|
+
(p) => r.path === p
|
|
3508
|
+
)
|
|
3509
|
+
);
|
|
3510
|
+
if (hasHealth) {
|
|
3511
|
+
add(ctx, { severity: "ok", area: "ops", message: "health-check route registered" });
|
|
3512
|
+
} else {
|
|
3513
|
+
add(ctx, {
|
|
3514
|
+
severity: "warn",
|
|
3515
|
+
area: "ops",
|
|
3516
|
+
message: "no health-check route detected",
|
|
3517
|
+
hint: 'Kubernetes, ECS, and load balancers expect a `/health` (or similar) endpoint. Register one via `app.healthCheck("/health")` from `@axiomify/core`.'
|
|
3518
|
+
});
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
function checkOpenApiExposure(ctx) {
|
|
3522
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3523
|
+
const docsRoute = routes.find(
|
|
3524
|
+
(r) => r.method === "GET" && (r.path === "/docs" || r.path.endsWith("/docs"))
|
|
3525
|
+
);
|
|
3526
|
+
const specRoute = routes.find(
|
|
3527
|
+
(r) => r.method === "GET" && r.path.endsWith("/openapi.json")
|
|
3528
|
+
);
|
|
3529
|
+
if (docsRoute || specRoute) {
|
|
3530
|
+
add(ctx, {
|
|
3531
|
+
severity: "warn",
|
|
3532
|
+
area: "security",
|
|
3533
|
+
message: "OpenAPI docs endpoint is registered",
|
|
3534
|
+
hint: "In production, supply `protect: (req) => ...` to `useOpenAPI()` (or set `allowPublicInProduction: true` if exposure is intentional). The runtime warning is logged on the first request."
|
|
3535
|
+
});
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
function checkRoutesLockState(ctx) {
|
|
3539
|
+
if (ctx.app._routesLocked) {
|
|
3540
|
+
add(ctx, {
|
|
3541
|
+
severity: "warn",
|
|
3542
|
+
area: "config",
|
|
3543
|
+
message: "app.lockRoutes() has already been called",
|
|
3544
|
+
hint: "The entry file appears to construct an adapter at the top level. Wrap adapter construction in `if (require.main === module) { ... }` so the CLI can introspect the app without triggering it."
|
|
3545
|
+
});
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
function checkSecurityPlugins(ctx) {
|
|
3549
|
+
const onRequest = ctx.app.hooks?.hooks?.onRequest ?? [];
|
|
3550
|
+
if (onRequest.length < 2) {
|
|
3551
|
+
add(ctx, {
|
|
3552
|
+
severity: "warn",
|
|
3553
|
+
area: "security",
|
|
3554
|
+
message: "few onRequest hooks detected \u2014 security plugins may not be registered",
|
|
3555
|
+
hint: "`@axiomify/helmet`, `@axiomify/cors`, and `@axiomify/security` each install onRequest hooks. If you are not using these, ensure equivalent defences are in place elsewhere."
|
|
3556
|
+
});
|
|
3557
|
+
} else {
|
|
3558
|
+
add(ctx, {
|
|
3559
|
+
severity: "ok",
|
|
3560
|
+
area: "security",
|
|
3561
|
+
message: `${onRequest.length} onRequest hooks registered (security plugins likely active)`
|
|
3562
|
+
});
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
function collectEnvKeysFromBundle(bundlePath) {
|
|
3566
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3567
|
+
try {
|
|
3568
|
+
const src = fs.readFileSync(bundlePath, "utf8");
|
|
3569
|
+
const re = /process\.env\.([A-Z][A-Z0-9_]*)|process\.env\[(['"])([A-Z][A-Z0-9_]*)\2\]/g;
|
|
3570
|
+
let m;
|
|
3571
|
+
while ((m = re.exec(src)) !== null) {
|
|
3572
|
+
keys.add(m[1] ?? m[3]);
|
|
3573
|
+
}
|
|
3574
|
+
} catch {
|
|
3575
|
+
}
|
|
3576
|
+
return keys;
|
|
3577
|
+
}
|
|
3578
|
+
function loadPkgJson(cwd) {
|
|
3579
|
+
try {
|
|
3580
|
+
return JSON.parse(fs.readFileSync(path7.join(cwd, "package.json"), "utf8"));
|
|
3581
|
+
} catch {
|
|
3582
|
+
return null;
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
async function runCheck(entry) {
|
|
3586
|
+
let app;
|
|
3587
|
+
let cleanup = async () => {
|
|
3588
|
+
};
|
|
3589
|
+
let bundlePath = "";
|
|
3590
|
+
try {
|
|
3591
|
+
const loaded = await loadApp(entry);
|
|
3592
|
+
app = loaded.app;
|
|
3593
|
+
cleanup = loaded.cleanup;
|
|
3594
|
+
bundlePath = path7.resolve(process.cwd(), ".axiomify/inspect.cjs");
|
|
3595
|
+
} catch (err) {
|
|
3596
|
+
console.error(pc.red("\u2717 Failed to load app:"));
|
|
3597
|
+
console.error(err.message);
|
|
3598
|
+
process.exit(1);
|
|
3599
|
+
}
|
|
3600
|
+
const ctx = {
|
|
3601
|
+
app,
|
|
3602
|
+
cwd: process.cwd(),
|
|
3603
|
+
findings: [],
|
|
3604
|
+
pkgJson: loadPkgJson(process.cwd()),
|
|
3605
|
+
envKeys: collectEnvKeysFromBundle(bundlePath)
|
|
3606
|
+
};
|
|
3607
|
+
checkEnvVars(ctx);
|
|
3608
|
+
checkRequestId(ctx);
|
|
3609
|
+
checkRoutesLockState(ctx);
|
|
3610
|
+
checkOpenApiNaming(ctx);
|
|
3611
|
+
checkSecurityPlugins(ctx);
|
|
3612
|
+
checkOpenApiExposure(ctx);
|
|
3613
|
+
checkResponseSchemas(ctx);
|
|
3614
|
+
checkHealthCheck(ctx);
|
|
3615
|
+
await cleanup();
|
|
3616
|
+
console.log();
|
|
3617
|
+
console.log(pc.bold(" \u{1F50D} Production-readiness check"));
|
|
3618
|
+
console.log();
|
|
3619
|
+
const sevOrder = { fail: 0, warn: 1, ok: 2 };
|
|
3620
|
+
ctx.findings.sort(
|
|
3621
|
+
(a, b) => sevOrder[a.severity] - sevOrder[b.severity] || a.area.localeCompare(b.area)
|
|
3622
|
+
);
|
|
3623
|
+
const sym = {
|
|
3624
|
+
ok: symbols.ok,
|
|
3625
|
+
warn: symbols.warn,
|
|
3626
|
+
fail: symbols.fail
|
|
3627
|
+
};
|
|
3628
|
+
for (const f of ctx.findings) {
|
|
3629
|
+
const tag = pc.dim(`[${f.area}]`);
|
|
3630
|
+
console.log(` ${sym[f.severity]} ${tag} ${f.message}`);
|
|
3631
|
+
if (f.hint && f.severity !== "ok") {
|
|
3632
|
+
const wrapped = f.hint.replace(/(.{1,80})(\s+|$)/g, "\n " + pc.dim("$1"));
|
|
3633
|
+
console.log(wrapped);
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
const fails = ctx.findings.filter((f) => f.severity === "fail").length;
|
|
3637
|
+
const warns = ctx.findings.filter((f) => f.severity === "warn").length;
|
|
3638
|
+
const oks = ctx.findings.filter((f) => f.severity === "ok").length;
|
|
3639
|
+
console.log();
|
|
3640
|
+
const summary = ` ${symbols.ok} ${pluralise(oks, "pass", "passes")}` + pc.dim(" \xB7 ") + (warns > 0 ? `${symbols.warn} ${pluralise(warns, "warning")}` : pc.dim("0 warnings")) + pc.dim(" \xB7 ") + (fails > 0 ? `${symbols.fail} ${pluralise(fails, "failure")}` : pc.dim("0 failures"));
|
|
3641
|
+
console.log(summary);
|
|
3642
|
+
console.log();
|
|
3643
|
+
if (fails > 0) process.exit(1);
|
|
3644
|
+
}
|
|
2942
3645
|
async function devServer(entry) {
|
|
2943
|
-
const entryPath =
|
|
2944
|
-
const outPath =
|
|
3646
|
+
const entryPath = path7.resolve(process.cwd(), entry);
|
|
3647
|
+
const outPath = path7.resolve(process.cwd(), ".axiomify/dev.js");
|
|
2945
3648
|
let child = null;
|
|
2946
3649
|
let firstBuild = true;
|
|
2947
3650
|
const startChild = () => {
|
|
@@ -3021,6 +3724,213 @@ async function devServer(entry) {
|
|
|
3021
3724
|
console.log(`\u{1F440} Axiomify Dev Engine watching for changes...`);
|
|
3022
3725
|
await ctx.watch();
|
|
3023
3726
|
}
|
|
3727
|
+
function add2(findings, f) {
|
|
3728
|
+
findings.push(f);
|
|
3729
|
+
}
|
|
3730
|
+
function probePort(port) {
|
|
3731
|
+
return new Promise((resolve) => {
|
|
3732
|
+
const server = createServer();
|
|
3733
|
+
server.once("error", (err) => {
|
|
3734
|
+
if (err.code === "EADDRINUSE") resolve("busy");
|
|
3735
|
+
else if (err.code === "EACCES") resolve("denied");
|
|
3736
|
+
else resolve("busy");
|
|
3737
|
+
});
|
|
3738
|
+
server.once("listening", () => {
|
|
3739
|
+
server.close(() => resolve("free"));
|
|
3740
|
+
});
|
|
3741
|
+
server.listen(port, "127.0.0.1");
|
|
3742
|
+
});
|
|
3743
|
+
}
|
|
3744
|
+
function checkNodeVersion(findings) {
|
|
3745
|
+
const major = parseInt(process.versions.node.split(".")[0], 10);
|
|
3746
|
+
if (major < 18) {
|
|
3747
|
+
add2(findings, {
|
|
3748
|
+
severity: "fail",
|
|
3749
|
+
area: "node",
|
|
3750
|
+
message: `Node ${process.versions.node} is below the supported minimum`,
|
|
3751
|
+
hint: "Axiomify requires Node 18 or later. Upgrade via nvm: `nvm install 22 && nvm use 22`."
|
|
3752
|
+
});
|
|
3753
|
+
} else if (major > 22) {
|
|
3754
|
+
add2(findings, {
|
|
3755
|
+
severity: "warn",
|
|
3756
|
+
area: "node",
|
|
3757
|
+
message: `Node ${process.versions.node} \u2014 uWebSockets.js has no prebuilt binary for this version`,
|
|
3758
|
+
hint: "Tests and benchmarks that need a real uWS listener will skip; the framework still builds. For a runnable production deploy, downgrade to Node 22 LTS."
|
|
3759
|
+
});
|
|
3760
|
+
} else {
|
|
3761
|
+
add2(findings, {
|
|
3762
|
+
severity: "ok",
|
|
3763
|
+
area: "node",
|
|
3764
|
+
message: `Node ${process.versions.node} (uWS prebuilt available)`
|
|
3765
|
+
});
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
function checkPlatform(findings) {
|
|
3769
|
+
if (process.platform === "linux") {
|
|
3770
|
+
add2(findings, {
|
|
3771
|
+
severity: "ok",
|
|
3772
|
+
area: "platform",
|
|
3773
|
+
message: "Linux \u2014 SO_REUSEPORT clustering supported natively"
|
|
3774
|
+
});
|
|
3775
|
+
} else {
|
|
3776
|
+
add2(findings, {
|
|
3777
|
+
severity: "warn",
|
|
3778
|
+
area: "platform",
|
|
3779
|
+
message: `${process.platform} \u2014 \`listenClustered()\` requires \`allowUserspaceProxy: true\``,
|
|
3780
|
+
hint: "Clustering on non-Linux falls back to a userspace L4 proxy that adds two event-loop hops per byte. Single-process `listen()` is the recommended path on this OS."
|
|
3781
|
+
});
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
function checkDependencyDrift(findings) {
|
|
3785
|
+
try {
|
|
3786
|
+
const pkgPath = path7.join(process.cwd(), "package.json");
|
|
3787
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
3788
|
+
const all = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
3789
|
+
const axiomifyDeps = Object.entries(all).filter(
|
|
3790
|
+
([k]) => k.startsWith("@axiomify/")
|
|
3791
|
+
);
|
|
3792
|
+
if (axiomifyDeps.length === 0) {
|
|
3793
|
+
add2(findings, {
|
|
3794
|
+
severity: "warn",
|
|
3795
|
+
area: "deps",
|
|
3796
|
+
message: "No @axiomify/* packages found in package.json",
|
|
3797
|
+
hint: "Run this from the root of a project that uses Axiomify."
|
|
3798
|
+
});
|
|
3799
|
+
return;
|
|
3800
|
+
}
|
|
3801
|
+
const versions = new Set(
|
|
3802
|
+
axiomifyDeps.map(([, v]) => v.replace(/^[\^~]/, "").replace(/^\*$/, "workspace"))
|
|
3803
|
+
);
|
|
3804
|
+
if (versions.size > 1) {
|
|
3805
|
+
add2(findings, {
|
|
3806
|
+
severity: "warn",
|
|
3807
|
+
area: "deps",
|
|
3808
|
+
message: `@axiomify/* packages are on ${versions.size} different versions`,
|
|
3809
|
+
hint: "Mixed @axiomify/* versions can cause subtle compat issues. Pin them all to the same version: " + [...versions].join(", ")
|
|
3810
|
+
});
|
|
3811
|
+
} else {
|
|
3812
|
+
add2(findings, {
|
|
3813
|
+
severity: "ok",
|
|
3814
|
+
area: "deps",
|
|
3815
|
+
message: `${axiomifyDeps.length} @axiomify/* packages aligned (${[...versions][0]})`
|
|
3816
|
+
});
|
|
3817
|
+
}
|
|
3818
|
+
} catch {
|
|
3819
|
+
add2(findings, {
|
|
3820
|
+
severity: "warn",
|
|
3821
|
+
area: "deps",
|
|
3822
|
+
message: "Could not read package.json",
|
|
3823
|
+
hint: "Run `axiomify doctor` from a project root."
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
function checkUwsLoads(findings) {
|
|
3828
|
+
try {
|
|
3829
|
+
require_uws();
|
|
3830
|
+
add2(findings, {
|
|
3831
|
+
severity: "ok",
|
|
3832
|
+
area: "uws",
|
|
3833
|
+
message: "uWebSockets.js loads successfully"
|
|
3834
|
+
});
|
|
3835
|
+
} catch (err) {
|
|
3836
|
+
const msg = String(err.message ?? err);
|
|
3837
|
+
if (msg.includes("Cannot find module")) {
|
|
3838
|
+
add2(findings, {
|
|
3839
|
+
severity: "warn",
|
|
3840
|
+
area: "uws",
|
|
3841
|
+
message: "uWebSockets.js is not installed in this project",
|
|
3842
|
+
hint: "It is a peer dependency of `@axiomify/native`. Install via `npm install --save-optional uWebSockets.js` (the package handles platform selection)."
|
|
3843
|
+
});
|
|
3844
|
+
} else {
|
|
3845
|
+
add2(findings, {
|
|
3846
|
+
severity: "fail",
|
|
3847
|
+
area: "uws",
|
|
3848
|
+
message: "uWebSockets.js native binding failed to load",
|
|
3849
|
+
hint: msg.length > 200 ? msg.slice(0, 200) + "\u2026" : msg
|
|
3850
|
+
});
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
async function checkPortAvailability(findings) {
|
|
3855
|
+
const port = parseInt(process.env.PORT ?? "3000", 10);
|
|
3856
|
+
const state = await probePort(port);
|
|
3857
|
+
if (state === "free") {
|
|
3858
|
+
add2(findings, {
|
|
3859
|
+
severity: "ok",
|
|
3860
|
+
area: "port",
|
|
3861
|
+
message: `Port ${port} is available on 127.0.0.1`
|
|
3862
|
+
});
|
|
3863
|
+
} else if (state === "busy") {
|
|
3864
|
+
add2(findings, {
|
|
3865
|
+
severity: "warn",
|
|
3866
|
+
area: "port",
|
|
3867
|
+
message: `Port ${port} is already in use`,
|
|
3868
|
+
hint: "Stop the conflicting process or set `PORT` to a different value."
|
|
3869
|
+
});
|
|
3870
|
+
} else {
|
|
3871
|
+
add2(findings, {
|
|
3872
|
+
severity: "warn",
|
|
3873
|
+
area: "port",
|
|
3874
|
+
message: `Port ${port}: bind denied (permission)`,
|
|
3875
|
+
hint: "Ports below 1024 typically require root. Use a port \u2265 1024 in development."
|
|
3876
|
+
});
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
function checkBuildArtifacts(findings) {
|
|
3880
|
+
const dist = path7.join(process.cwd(), "dist");
|
|
3881
|
+
if (fs.existsSync(dist)) {
|
|
3882
|
+
add2(findings, {
|
|
3883
|
+
severity: "ok",
|
|
3884
|
+
area: "build",
|
|
3885
|
+
message: "dist/ exists (recent `axiomify build`)"
|
|
3886
|
+
});
|
|
3887
|
+
} else {
|
|
3888
|
+
add2(findings, {
|
|
3889
|
+
severity: "warn",
|
|
3890
|
+
area: "build",
|
|
3891
|
+
message: "No dist/ directory \u2014 production build has not been run",
|
|
3892
|
+
hint: "Run `axiomify build` before deploying."
|
|
3893
|
+
});
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3896
|
+
async function runDoctor() {
|
|
3897
|
+
const findings = [];
|
|
3898
|
+
checkNodeVersion(findings);
|
|
3899
|
+
checkPlatform(findings);
|
|
3900
|
+
checkDependencyDrift(findings);
|
|
3901
|
+
checkUwsLoads(findings);
|
|
3902
|
+
checkBuildArtifacts(findings);
|
|
3903
|
+
await checkPortAvailability(findings);
|
|
3904
|
+
console.log();
|
|
3905
|
+
console.log(pc.bold(" \u{1FA7A} Axiomify doctor"));
|
|
3906
|
+
console.log();
|
|
3907
|
+
const sevOrder = { fail: 0, warn: 1, ok: 2 };
|
|
3908
|
+
findings.sort(
|
|
3909
|
+
(a, b) => sevOrder[a.severity] - sevOrder[b.severity] || a.area.localeCompare(b.area)
|
|
3910
|
+
);
|
|
3911
|
+
const sym = {
|
|
3912
|
+
ok: symbols.ok,
|
|
3913
|
+
warn: symbols.warn,
|
|
3914
|
+
fail: symbols.fail
|
|
3915
|
+
};
|
|
3916
|
+
for (const f of findings) {
|
|
3917
|
+
const tag = pc.dim(`[${f.area}]`);
|
|
3918
|
+
console.log(` ${sym[f.severity]} ${tag} ${f.message}`);
|
|
3919
|
+
if (f.hint && f.severity !== "ok") {
|
|
3920
|
+
const wrapped = f.hint.replace(/(.{1,80})(\s+|$)/g, "\n " + pc.dim("$1"));
|
|
3921
|
+
console.log(wrapped);
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
const fails = findings.filter((f) => f.severity === "fail").length;
|
|
3925
|
+
const warns = findings.filter((f) => f.severity === "warn").length;
|
|
3926
|
+
const oks = findings.filter((f) => f.severity === "ok").length;
|
|
3927
|
+
console.log();
|
|
3928
|
+
console.log(
|
|
3929
|
+
` ${symbols.ok} ${pluralise(oks, "pass", "passes")}` + pc.dim(" \xB7 ") + (warns > 0 ? `${symbols.warn} ${pluralise(warns, "warning")}` : pc.dim("0 warnings")) + pc.dim(" \xB7 ") + (fails > 0 ? `${symbols.fail} ${pluralise(fails, "failure")}` : pc.dim("0 failures"))
|
|
3930
|
+
);
|
|
3931
|
+
console.log();
|
|
3932
|
+
if (fails > 0) process.exit(1);
|
|
3933
|
+
}
|
|
3024
3934
|
var DEV_COMMAND_BY_PM = {
|
|
3025
3935
|
npm: "npm run dev",
|
|
3026
3936
|
pnpm: "pnpm dev",
|
|
@@ -3038,20 +3948,6 @@ async function initProject(targetDir, options = {}) {
|
|
|
3038
3948
|
});
|
|
3039
3949
|
}
|
|
3040
3950
|
questions.push(
|
|
3041
|
-
{
|
|
3042
|
-
type: "select",
|
|
3043
|
-
name: "adapter",
|
|
3044
|
-
message: "Which HTTP adapter do you want to use?",
|
|
3045
|
-
choices: [
|
|
3046
|
-
"Native (uWS \u2014 Fastest, 50k+ req/s)",
|
|
3047
|
-
"Fastify (High-throughput, recommended)",
|
|
3048
|
-
"Express (Max ecosystem compatibility)",
|
|
3049
|
-
"Hapi (Enterprise, plugin-first)",
|
|
3050
|
-
"Node HTTP (Zero dependency)"
|
|
3051
|
-
],
|
|
3052
|
-
initial: 0
|
|
3053
|
-
// Native is the recommended default
|
|
3054
|
-
},
|
|
3055
3951
|
{
|
|
3056
3952
|
type: "input",
|
|
3057
3953
|
name: "description",
|
|
@@ -3105,12 +4001,12 @@ async function initProject(targetDir, options = {}) {
|
|
|
3105
4001
|
);
|
|
3106
4002
|
process.exit(1);
|
|
3107
4003
|
}
|
|
3108
|
-
const dir =
|
|
4004
|
+
const dir = path7.resolve(process.cwd(), projectName);
|
|
3109
4005
|
if (existsSync(dir) && !options.force && targetDir) {
|
|
3110
4006
|
const targets = [
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
4007
|
+
path7.join(dir, "package.json"),
|
|
4008
|
+
path7.join(dir, "tsconfig.json"),
|
|
4009
|
+
path7.join(dir, "src", "index.ts")
|
|
3114
4010
|
];
|
|
3115
4011
|
const collisions = targets.filter((p) => existsSync(p));
|
|
3116
4012
|
if (collisions.length > 0) {
|
|
@@ -3122,28 +4018,11 @@ async function initProject(targetDir, options = {}) {
|
|
|
3122
4018
|
process.exit(1);
|
|
3123
4019
|
}
|
|
3124
4020
|
}
|
|
3125
|
-
await
|
|
4021
|
+
await fs5.mkdir(path7.join(dir, "src"), { recursive: true });
|
|
3126
4022
|
const AXIOMIFY_VERSION = `^${package_default.version}`;
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
if (answers.adapter.includes("Fastify")) {
|
|
3131
|
-
adapterPackage = "@axiomify/fastify";
|
|
3132
|
-
adapterImport = "import { FastifyAdapter } from '@axiomify/fastify';";
|
|
3133
|
-
adapterInit = "const server = new FastifyAdapter(app);\n await server.listen(3000);\n console.log(' Axiomify Fastify on :3000');";
|
|
3134
|
-
} else if (answers.adapter.includes("Express")) {
|
|
3135
|
-
adapterPackage = "@axiomify/express";
|
|
3136
|
-
adapterImport = "import { ExpressAdapter } from '@axiomify/express';";
|
|
3137
|
-
adapterInit = "const server = new ExpressAdapter(app);\n server.listen(3000, () => console.log(' Axiomify Express on :3000'));";
|
|
3138
|
-
} else if (answers.adapter.includes("Hapi")) {
|
|
3139
|
-
adapterPackage = "@axiomify/hapi";
|
|
3140
|
-
adapterImport = "import { HapiAdapter } from '@axiomify/hapi';";
|
|
3141
|
-
adapterInit = "const server = new HapiAdapter(app);\n await server.listen(3000);\n console.log(' Axiomify Hapi on :3000');";
|
|
3142
|
-
} else if (answers.adapter.includes("HTTP")) {
|
|
3143
|
-
adapterPackage = "@axiomify/http";
|
|
3144
|
-
adapterImport = "import { HttpAdapter } from '@axiomify/http';";
|
|
3145
|
-
adapterInit = "const server = new HttpAdapter(app);\n server.listen(3000, () => console.log(' Axiomify HTTP on :3000'));";
|
|
3146
|
-
}
|
|
4023
|
+
const adapterPackage = "@axiomify/native";
|
|
4024
|
+
const adapterImport = "import { NativeAdapter } from '@axiomify/native';";
|
|
4025
|
+
const adapterInit = "const server = new NativeAdapter(app, { port: 3000 });\n server.listen(() => console.log(' Axiomify Native on :3000'));";
|
|
3147
4026
|
const pkgJson = {
|
|
3148
4027
|
name: projectName,
|
|
3149
4028
|
version: "1.0.0",
|
|
@@ -3211,14 +4090,14 @@ async function initProject(targetDir, options = {}) {
|
|
|
3211
4090
|
"printWidth": 100,
|
|
3212
4091
|
"tabWidth": 2
|
|
3213
4092
|
}`;
|
|
3214
|
-
await
|
|
3215
|
-
await
|
|
3216
|
-
await
|
|
3217
|
-
|
|
4093
|
+
await fs5.writeFile(path7.join(dir, ".eslintrc.cjs"), eslintConfig);
|
|
4094
|
+
await fs5.writeFile(path7.join(dir, ".prettierrc"), prettierConfig);
|
|
4095
|
+
await fs5.writeFile(
|
|
4096
|
+
path7.join(dir, ".prettierignore"),
|
|
3218
4097
|
"dist\nnode_modules\ncoverage\n"
|
|
3219
4098
|
);
|
|
3220
|
-
await
|
|
3221
|
-
|
|
4099
|
+
await fs5.writeFile(
|
|
4100
|
+
path7.join(dir, ".editorconfig"),
|
|
3222
4101
|
"root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
|
|
3223
4102
|
);
|
|
3224
4103
|
}
|
|
@@ -3279,19 +4158,19 @@ async function initProject(targetDir, options = {}) {
|
|
|
3279
4158
|
"coverage",
|
|
3280
4159
|
"*.log"
|
|
3281
4160
|
].join("\n") + "\n";
|
|
3282
|
-
await
|
|
3283
|
-
|
|
4161
|
+
await fs5.writeFile(
|
|
4162
|
+
path7.join(dir, "package.json"),
|
|
3284
4163
|
JSON.stringify(pkgJson, null, 2)
|
|
3285
4164
|
);
|
|
3286
|
-
await
|
|
3287
|
-
|
|
4165
|
+
await fs5.writeFile(
|
|
4166
|
+
path7.join(dir, "tsconfig.json"),
|
|
3288
4167
|
JSON.stringify(tsConfig, null, 2)
|
|
3289
4168
|
);
|
|
3290
|
-
await
|
|
3291
|
-
await
|
|
4169
|
+
await fs5.writeFile(path7.join(dir, "src", "index.ts"), indexTs);
|
|
4170
|
+
await fs5.writeFile(path7.join(dir, ".gitignore"), gitignore);
|
|
3292
4171
|
console.log(pc.green(`
|
|
3293
4172
|
\u2705 Axiomify project initialized in ${pc.bold(dir)}`));
|
|
3294
|
-
if (answers.useGit && !existsSync(
|
|
4173
|
+
if (answers.useGit && !existsSync(path7.join(dir, ".git"))) {
|
|
3295
4174
|
try {
|
|
3296
4175
|
await execa("git", ["init"], { cwd: dir });
|
|
3297
4176
|
console.log(pc.green("\u2705 Git repository initialized"));
|
|
@@ -3325,63 +4204,644 @@ async function initProject(targetDir, options = {}) {
|
|
|
3325
4204
|
\u{1F525} Run "${devCommand}" to start your development server!`)
|
|
3326
4205
|
);
|
|
3327
4206
|
}
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
4207
|
+
var RULES = [
|
|
4208
|
+
{
|
|
4209
|
+
id: "meta-to-schema",
|
|
4210
|
+
description: "`meta:` route field removed \u2014 metadata now lives inside `schema:` alongside Zod fields",
|
|
4211
|
+
// NOTE: This rule renames `meta:` → a comment directing the dev to merge
|
|
4212
|
+
// contents into schema:. A full structural AST merge is out of scope for
|
|
4213
|
+
// the regex codemod; flag it for manual review instead (see report).
|
|
4214
|
+
match: /^(\s*)meta:(\s*\{)/gm,
|
|
4215
|
+
replace: "$1/* TODO(axiomify-migrate): merge meta fields into schema: */ openapi_REMOVE:$2"
|
|
4216
|
+
},
|
|
4217
|
+
{
|
|
4218
|
+
id: "openapi-field-to-schema",
|
|
4219
|
+
description: "`openapi:` top-level route field \u2192 contents merged into `schema:` (removed in 6.1)",
|
|
4220
|
+
// Same conservative approach: flag for manual review via TODO comment.
|
|
4221
|
+
match: /^(\s*)openapi:(\s*\{)/gm,
|
|
4222
|
+
replace: "$1/* TODO(axiomify-migrate): merge openapi fields into schema: */ openapi_REMOVE:$2"
|
|
4223
|
+
},
|
|
4224
|
+
{
|
|
4225
|
+
id: "useSwagger-import",
|
|
4226
|
+
description: "`useSwagger` import \u2192 `useOpenAPI` (the function was never named `useSwagger` in shipped code \u2014 docs were wrong)",
|
|
4227
|
+
match: /\buseSwagger\b/g,
|
|
4228
|
+
replace: "useOpenAPI"
|
|
4229
|
+
},
|
|
4230
|
+
{
|
|
4231
|
+
id: "routePrefix-option",
|
|
4232
|
+
description: "`routePrefix:` \u2192 `prefix:` on `useOpenAPI()` options",
|
|
4233
|
+
match: /(\buseOpenAPI\s*\([\s\S]*?)\brouteprefix(\s*:)/gi,
|
|
4234
|
+
// Naive: just rename the property when it appears inside a useOpenAPI() call.
|
|
4235
|
+
// The capture-group lookbehind avoids touching unrelated `routePrefix`
|
|
4236
|
+
// properties in other contexts.
|
|
4237
|
+
replace: (_match, before, suffix) => `${before}prefix${suffix}`
|
|
4238
|
+
},
|
|
4239
|
+
{
|
|
4240
|
+
id: "RouteMeta-type",
|
|
4241
|
+
description: "`RouteMeta` type \u2192 `OpenApiOperation` (alias removed in 6.0)",
|
|
4242
|
+
// Match `RouteMeta` only as a type position (after `:` or `<` or
|
|
4243
|
+
// `as`) — avoids hitting an unrelated variable named `RouteMeta`.
|
|
4244
|
+
match: /(:\s*|<\s*|\bas\s+)RouteMeta\b/g,
|
|
4245
|
+
replace: "$1OpenApiOperation"
|
|
4246
|
+
},
|
|
4247
|
+
{
|
|
4248
|
+
id: "AppPlugin-type",
|
|
4249
|
+
description: "`AppPlugin` type alias \u2192 `AppConfigurator` (removed in 5.0; runtime accepts 1-arg fns identically)",
|
|
4250
|
+
match: /(:\s*|<\s*|\bas\s+)AppPlugin\b/g,
|
|
4251
|
+
replace: "$1AppConfigurator"
|
|
4252
|
+
}
|
|
4253
|
+
];
|
|
4254
|
+
async function listSourceFiles(rootAbs) {
|
|
4255
|
+
const out = [];
|
|
4256
|
+
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".axiomify", "coverage"]);
|
|
4257
|
+
const walk = async (dir) => {
|
|
4258
|
+
let entries;
|
|
3341
4259
|
try {
|
|
3342
|
-
|
|
3343
|
-
} catch
|
|
4260
|
+
entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
4261
|
+
} catch {
|
|
4262
|
+
return;
|
|
3344
4263
|
}
|
|
3345
|
-
const
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
4264
|
+
for (const e of entries) {
|
|
4265
|
+
if (e.isDirectory()) {
|
|
4266
|
+
if (skip.has(e.name) || e.name.startsWith(".")) continue;
|
|
4267
|
+
await walk(path7.join(dir, e.name));
|
|
4268
|
+
} else if (e.isFile()) {
|
|
4269
|
+
const ext = path7.extname(e.name);
|
|
4270
|
+
if ([".ts", ".tsx", ".js", ".mjs", ".cjs"].includes(ext)) {
|
|
4271
|
+
out.push(path7.join(dir, e.name));
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
};
|
|
4276
|
+
await walk(rootAbs);
|
|
4277
|
+
return out;
|
|
4278
|
+
}
|
|
4279
|
+
function applyRules(src) {
|
|
4280
|
+
let updated = src;
|
|
4281
|
+
const counts = {};
|
|
4282
|
+
for (const rule of RULES) {
|
|
4283
|
+
const before = updated;
|
|
4284
|
+
if (typeof rule.replace === "string") {
|
|
4285
|
+
updated = updated.replace(rule.match, rule.replace);
|
|
4286
|
+
} else {
|
|
4287
|
+
updated = updated.replace(rule.match, rule.replace);
|
|
4288
|
+
}
|
|
4289
|
+
if (updated !== before) {
|
|
4290
|
+
const matches = before.match(rule.match);
|
|
4291
|
+
counts[rule.id] = matches ? matches.length : 1;
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
return { updated, counts };
|
|
4295
|
+
}
|
|
4296
|
+
function renderUnifiedDiff(file, original, updated) {
|
|
4297
|
+
if (original === updated) return "";
|
|
4298
|
+
const origLines = original.split("\n");
|
|
4299
|
+
const updatedLines = updated.split("\n");
|
|
4300
|
+
const out = [];
|
|
4301
|
+
out.push(pc.bold(`--- ${file}`));
|
|
4302
|
+
out.push(pc.bold(`+++ ${file}`));
|
|
4303
|
+
const max = Math.max(origLines.length, updatedLines.length);
|
|
4304
|
+
for (let i = 0; i < max; i++) {
|
|
4305
|
+
const a = origLines[i];
|
|
4306
|
+
const b = updatedLines[i];
|
|
4307
|
+
if (a === b) continue;
|
|
4308
|
+
if (a !== void 0) out.push(pc.red("- " + a));
|
|
4309
|
+
if (b !== void 0) out.push(pc.green("+ " + b));
|
|
4310
|
+
}
|
|
4311
|
+
return out.join("\n");
|
|
4312
|
+
}
|
|
4313
|
+
async function runMigrate(opts = {}) {
|
|
4314
|
+
const dir = opts.dir ?? "src";
|
|
4315
|
+
const rootAbs = path7.resolve(process.cwd(), dir);
|
|
4316
|
+
try {
|
|
4317
|
+
const stat = await fs5.stat(rootAbs);
|
|
4318
|
+
if (!stat.isDirectory()) throw new Error("not a directory");
|
|
4319
|
+
} catch {
|
|
4320
|
+
console.error(
|
|
4321
|
+
pc.red(`\u2717 ${dir} does not exist or is not a directory.`),
|
|
4322
|
+
`
|
|
4323
|
+
Run from a project root that contains the directory you want to migrate.`
|
|
4324
|
+
);
|
|
4325
|
+
process.exit(1);
|
|
4326
|
+
}
|
|
4327
|
+
const files = await listSourceFiles(rootAbs);
|
|
4328
|
+
if (files.length === 0) {
|
|
4329
|
+
console.log(`${symbols.info} No source files found under ${pc.cyan(dir)}.`);
|
|
4330
|
+
return;
|
|
4331
|
+
}
|
|
4332
|
+
const results = [];
|
|
4333
|
+
for (const f of files) {
|
|
4334
|
+
const original = await fs5.readFile(f, "utf8");
|
|
4335
|
+
const { updated, counts } = applyRules(original);
|
|
4336
|
+
if (Object.keys(counts).length > 0) {
|
|
4337
|
+
results.push({ file: f, counts, original, updated });
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
console.log();
|
|
4341
|
+
console.log(pc.bold(" \u{1F504} Axiomify v4 \u2192 v5 migration"));
|
|
4342
|
+
console.log(
|
|
4343
|
+
pc.dim(
|
|
4344
|
+
` Scanned ${pluralise(files.length, "file")} under ${path7.relative(process.cwd(), rootAbs) || "."}/.
|
|
4345
|
+
`
|
|
4346
|
+
)
|
|
4347
|
+
);
|
|
4348
|
+
if (results.length === 0) {
|
|
4349
|
+
console.log(` ${symbols.ok} Nothing to migrate \u2014 all patterns look up to date.`);
|
|
4350
|
+
console.log();
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4353
|
+
const totalsByRule = {};
|
|
4354
|
+
for (const r of results) {
|
|
4355
|
+
for (const [rule, n] of Object.entries(r.counts)) {
|
|
4356
|
+
totalsByRule[rule] = (totalsByRule[rule] ?? 0) + n;
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
for (const rule of RULES) {
|
|
4360
|
+
const count = totalsByRule[rule.id];
|
|
4361
|
+
if (!count) continue;
|
|
4362
|
+
console.log(
|
|
4363
|
+
` ${pc.cyan(rule.id)} ${pc.dim("\u2014")} ${rule.description}`
|
|
4364
|
+
);
|
|
4365
|
+
console.log(
|
|
4366
|
+
` ${symbols.bullet} ${pluralise(count, "change")} across ${pluralise(
|
|
4367
|
+
results.filter((r) => r.counts[rule.id]).length,
|
|
4368
|
+
"file"
|
|
4369
|
+
)}`
|
|
4370
|
+
);
|
|
4371
|
+
}
|
|
4372
|
+
console.log();
|
|
4373
|
+
if (opts.reportOnly) {
|
|
4374
|
+
console.log(pc.dim(" --report-only: no files were modified."));
|
|
4375
|
+
console.log();
|
|
4376
|
+
return;
|
|
4377
|
+
}
|
|
4378
|
+
if (opts.dryRun) {
|
|
4379
|
+
for (const r of results) {
|
|
4380
|
+
const rel = path7.relative(process.cwd(), r.file);
|
|
4381
|
+
console.log(renderUnifiedDiff(rel, r.original, r.updated));
|
|
4382
|
+
console.log();
|
|
4383
|
+
}
|
|
4384
|
+
console.log(
|
|
4385
|
+
`${symbols.info} ${pluralise(results.length, "file")} would be modified. Re-run without ${pc.cyan("--dry-run")} to apply.`
|
|
4386
|
+
);
|
|
4387
|
+
console.log();
|
|
4388
|
+
return;
|
|
4389
|
+
}
|
|
4390
|
+
for (const r of results) {
|
|
4391
|
+
await fs5.writeFile(r.file, r.updated, "utf8");
|
|
4392
|
+
console.log(` ${symbols.ok} ${pc.green("Updated")} ${path7.relative(process.cwd(), r.file)}`);
|
|
4393
|
+
}
|
|
4394
|
+
console.log();
|
|
4395
|
+
console.log(
|
|
4396
|
+
` ${symbols.ok} ${pluralise(results.length, "file")} migrated, ${pluralise(
|
|
4397
|
+
Object.values(totalsByRule).reduce((a, b) => a + b, 0),
|
|
4398
|
+
"total change"
|
|
4399
|
+
)} applied.`
|
|
4400
|
+
);
|
|
4401
|
+
console.log();
|
|
4402
|
+
console.log(pc.dim(" Manual review needed for:"));
|
|
4403
|
+
console.log(
|
|
4404
|
+
pc.dim(
|
|
4405
|
+
` ${symbols.bullet} Dangling \`AppPlugin\` / \`RouteMeta\` in import statements \u2014 the codemod renames`
|
|
4406
|
+
)
|
|
4407
|
+
);
|
|
4408
|
+
console.log(
|
|
4409
|
+
pc.dim(
|
|
4410
|
+
` type USAGES but not the import bindings themselves. TypeScript flags the unused`
|
|
4411
|
+
)
|
|
4412
|
+
);
|
|
4413
|
+
console.log(
|
|
4414
|
+
pc.dim(
|
|
4415
|
+
` import; remove it (or run \`tsc --noUnusedLocals\` once and let your editor clean up).`
|
|
4416
|
+
)
|
|
4417
|
+
);
|
|
4418
|
+
console.log(
|
|
4419
|
+
pc.dim(
|
|
4420
|
+
` ${symbols.bullet} 5-arg positional \`SerializerFn\` signatures \u2014 the function body needs by-hand updates`
|
|
4421
|
+
)
|
|
4422
|
+
);
|
|
4423
|
+
console.log(
|
|
4424
|
+
pc.dim(
|
|
4425
|
+
` ${symbols.bullet} \`new Axiomify()\` callers that relied on automatic \`X-Request-Id\` injection`
|
|
4426
|
+
)
|
|
4427
|
+
);
|
|
4428
|
+
console.log(
|
|
4429
|
+
pc.dim(
|
|
4430
|
+
` ${symbols.bullet} JWT secrets \u2014 verify they are \u2265 32 BYTES (not chars) per RFC 7518 \xA73.2`
|
|
4431
|
+
)
|
|
4432
|
+
);
|
|
4433
|
+
console.log();
|
|
4434
|
+
console.log(
|
|
4435
|
+
` See ${pc.cyan("docs/migration-v4-to-v5.md")} for the full guide and ` + pc.cyan("axiomify check") + " to verify the migrated app.\n" + pc.yellow(" Note: `openapi:` / `meta:` merges into `schema:` require manual review \u2014 check TODO comments.")
|
|
4436
|
+
);
|
|
4437
|
+
console.log();
|
|
4438
|
+
}
|
|
4439
|
+
async function jsonToYaml(obj) {
|
|
4440
|
+
const emit = (v, indent) => {
|
|
4441
|
+
const pad2 = " ".repeat(indent);
|
|
4442
|
+
if (v === null) return "null";
|
|
4443
|
+
if (typeof v === "boolean" || typeof v === "number") return String(v);
|
|
4444
|
+
if (typeof v === "string") {
|
|
4445
|
+
if (/[:#\n\r\t"'{}[\]&*!|>%@`]|^\s|\s$/.test(v) || v === "") {
|
|
4446
|
+
return JSON.stringify(v);
|
|
4447
|
+
}
|
|
4448
|
+
return v;
|
|
4449
|
+
}
|
|
4450
|
+
if (Array.isArray(v)) {
|
|
4451
|
+
if (v.length === 0) return "[]";
|
|
4452
|
+
return v.map((item) => `
|
|
4453
|
+
${pad2}- ${emit(item, indent + 1).replace(/^/gm, " ").trimStart()}`).join("");
|
|
4454
|
+
}
|
|
4455
|
+
if (typeof v === "object") {
|
|
4456
|
+
const keys = Object.keys(v);
|
|
4457
|
+
if (keys.length === 0) return "{}";
|
|
4458
|
+
return keys.map((k) => {
|
|
4459
|
+
const val = v[k];
|
|
4460
|
+
const rendered = emit(val, indent + 1);
|
|
4461
|
+
if (rendered.startsWith("\n")) return `
|
|
4462
|
+
${pad2}${k}:${rendered}`;
|
|
4463
|
+
return `
|
|
4464
|
+
${pad2}${k}: ${rendered}`;
|
|
4465
|
+
}).join("");
|
|
4466
|
+
}
|
|
4467
|
+
return JSON.stringify(v);
|
|
4468
|
+
};
|
|
4469
|
+
return emit(obj, 0).trimStart();
|
|
4470
|
+
}
|
|
4471
|
+
async function emitOpenApi(entry, opts = {}) {
|
|
4472
|
+
let app;
|
|
4473
|
+
let cleanup = async () => {
|
|
4474
|
+
};
|
|
4475
|
+
try {
|
|
4476
|
+
const loaded = await loadApp(entry);
|
|
4477
|
+
app = loaded.app;
|
|
4478
|
+
cleanup = loaded.cleanup;
|
|
4479
|
+
} catch (err) {
|
|
4480
|
+
console.error(pc.red("\u2717 Failed to load app:"));
|
|
4481
|
+
console.error(err.message);
|
|
4482
|
+
process.exit(1);
|
|
4483
|
+
}
|
|
4484
|
+
try {
|
|
4485
|
+
let OpenApiGenerator;
|
|
4486
|
+
try {
|
|
4487
|
+
({ OpenApiGenerator } = await import('./dist-SYWHGZLI.mjs'));
|
|
4488
|
+
} catch {
|
|
3355
4489
|
console.error(
|
|
3356
|
-
"
|
|
4490
|
+
pc.red("\u2717 @axiomify/openapi is not installed."),
|
|
4491
|
+
"\n Install it:",
|
|
4492
|
+
pc.cyan("npm install @axiomify/openapi")
|
|
3357
4493
|
);
|
|
3358
4494
|
process.exit(1);
|
|
3359
4495
|
}
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
app
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
const
|
|
4496
|
+
const info = {
|
|
4497
|
+
title: opts.title ?? "API",
|
|
4498
|
+
version: opts.version ?? "1.0.0"
|
|
4499
|
+
};
|
|
4500
|
+
const generator = new OpenApiGenerator(app, { info });
|
|
4501
|
+
const spec = generator.generate();
|
|
4502
|
+
if (opts.title) spec.info.title = opts.title;
|
|
4503
|
+
if (opts.version) spec.info.version = opts.version;
|
|
4504
|
+
const format = opts.format ?? "json";
|
|
4505
|
+
const serialised = format === "yaml" ? await jsonToYaml(spec) : opts.minify ? JSON.stringify(spec) : JSON.stringify(spec, null, 2);
|
|
4506
|
+
if (opts.output) {
|
|
4507
|
+
const outPath = path7.resolve(process.cwd(), opts.output);
|
|
4508
|
+
await fs5.mkdir(path7.dirname(outPath), { recursive: true });
|
|
4509
|
+
await fs5.writeFile(outPath, serialised + "\n", "utf8");
|
|
4510
|
+
const routeCount = (app.registeredRoutes ?? []).length;
|
|
3372
4511
|
console.log(
|
|
3373
|
-
`${
|
|
3374
|
-
30
|
|
3375
|
-
)} | ${validationStr}`
|
|
4512
|
+
`${pc.green("\u2713")} OpenAPI spec written to ${pc.cyan(opts.output)} ` + pc.dim(`(${routeCount} route${routeCount === 1 ? "" : "s"}, ${format})`)
|
|
3376
4513
|
);
|
|
3377
|
-
}
|
|
3378
|
-
|
|
4514
|
+
} else {
|
|
4515
|
+
process.stdout.write(serialised + "\n");
|
|
4516
|
+
}
|
|
3379
4517
|
} catch (error) {
|
|
3380
|
-
console.error("\
|
|
4518
|
+
console.error(pc.red("\u2717 Failed to generate spec:"), error);
|
|
4519
|
+
process.exit(1);
|
|
3381
4520
|
} finally {
|
|
3382
|
-
await
|
|
4521
|
+
await cleanup();
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
function normalise(raw, isWs) {
|
|
4525
|
+
const validation = [];
|
|
4526
|
+
if (raw.schema?.body) validation.push("Body");
|
|
4527
|
+
if (raw.schema?.query) validation.push("Query");
|
|
4528
|
+
if (raw.schema?.params) validation.push("Params");
|
|
4529
|
+
if (raw.schema?.response) validation.push("Response");
|
|
4530
|
+
if (raw.schema?.files) validation.push("Files");
|
|
4531
|
+
if (raw.schema?.message) validation.push("Message");
|
|
4532
|
+
const s = raw.schema ?? {};
|
|
4533
|
+
return {
|
|
4534
|
+
method: isWs ? "WS" : raw.method,
|
|
4535
|
+
path: raw.path,
|
|
4536
|
+
validation,
|
|
4537
|
+
tags: Array.isArray(s.tags) ? s.tags : [],
|
|
4538
|
+
operationId: typeof s.operationId === "string" ? s.operationId : void 0,
|
|
4539
|
+
deprecated: s.deprecated === true,
|
|
4540
|
+
timeout: typeof raw.timeout === "number" && raw.timeout > 0 ? raw.timeout : void 0,
|
|
4541
|
+
plugins: Array.isArray(raw.plugins) ? raw.plugins.length : 0,
|
|
4542
|
+
isWs
|
|
4543
|
+
};
|
|
4544
|
+
}
|
|
4545
|
+
function matchesFilter(route, opts) {
|
|
4546
|
+
if (opts.method) {
|
|
4547
|
+
const wanted = opts.method.split(",").map((m) => m.trim().toUpperCase()).filter(Boolean);
|
|
4548
|
+
if (wanted.length && !wanted.includes(route.method)) return false;
|
|
4549
|
+
}
|
|
4550
|
+
if (opts.filter) {
|
|
4551
|
+
const pat = opts.filter;
|
|
4552
|
+
if (pat.includes("*")) {
|
|
4553
|
+
const re = new RegExp(
|
|
4554
|
+
"^" + pat.split("*").map((s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*") + "$"
|
|
4555
|
+
);
|
|
4556
|
+
if (!re.test(route.path)) return false;
|
|
4557
|
+
} else if (!route.path.includes(pat)) {
|
|
4558
|
+
return false;
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
return true;
|
|
4562
|
+
}
|
|
4563
|
+
function sortRoutes(routes, by) {
|
|
4564
|
+
const methodOrder = {
|
|
4565
|
+
GET: 0,
|
|
4566
|
+
POST: 1,
|
|
4567
|
+
PUT: 2,
|
|
4568
|
+
PATCH: 3,
|
|
4569
|
+
DELETE: 4,
|
|
4570
|
+
HEAD: 5,
|
|
4571
|
+
OPTIONS: 6,
|
|
4572
|
+
WS: 7
|
|
4573
|
+
};
|
|
4574
|
+
return [...routes].sort((a, b) => {
|
|
4575
|
+
if (by === "method") {
|
|
4576
|
+
const am = methodOrder[a.method] ?? 99;
|
|
4577
|
+
const bm = methodOrder[b.method] ?? 99;
|
|
4578
|
+
if (am !== bm) return am - bm;
|
|
4579
|
+
return a.path.localeCompare(b.path);
|
|
4580
|
+
}
|
|
4581
|
+
if (a.path !== b.path) return a.path.localeCompare(b.path);
|
|
4582
|
+
return (methodOrder[a.method] ?? 99) - (methodOrder[b.method] ?? 99);
|
|
4583
|
+
});
|
|
4584
|
+
}
|
|
4585
|
+
async function inspectRoutes(entry, opts = {}) {
|
|
4586
|
+
let app;
|
|
4587
|
+
let cleanup = async () => {
|
|
4588
|
+
};
|
|
4589
|
+
try {
|
|
4590
|
+
const loaded = await loadApp(entry);
|
|
4591
|
+
app = loaded.app;
|
|
4592
|
+
cleanup = loaded.cleanup;
|
|
4593
|
+
} catch (err) {
|
|
4594
|
+
console.error(pc.red("\u2717 Failed to load app:"));
|
|
4595
|
+
console.error(err.message);
|
|
4596
|
+
process.exit(1);
|
|
4597
|
+
}
|
|
4598
|
+
try {
|
|
4599
|
+
const httpRoutes = (app.registeredRoutes ?? []).map(
|
|
4600
|
+
(r) => normalise(r, false)
|
|
4601
|
+
);
|
|
4602
|
+
const wsRoutes = (app.registeredWsRoutes ?? []).map(
|
|
4603
|
+
(r) => normalise(r, true)
|
|
4604
|
+
);
|
|
4605
|
+
const all = sortRoutes([...httpRoutes, ...wsRoutes], opts.sort ?? "path");
|
|
4606
|
+
const filtered = all.filter((r) => matchesFilter(r, opts));
|
|
4607
|
+
if (opts.json) {
|
|
4608
|
+
process.stdout.write(JSON.stringify(filtered, null, 2) + "\n");
|
|
4609
|
+
return;
|
|
4610
|
+
}
|
|
4611
|
+
if (filtered.length === 0) {
|
|
4612
|
+
console.log(
|
|
4613
|
+
"\n" + symbols.info + pc.dim(
|
|
4614
|
+
` No routes match the current filter (${all.length} total registered).
|
|
4615
|
+
`
|
|
4616
|
+
)
|
|
4617
|
+
);
|
|
4618
|
+
return;
|
|
4619
|
+
}
|
|
4620
|
+
console.log();
|
|
4621
|
+
console.log(pc.bold(" \u{1F9ED} Axiomify routes"));
|
|
4622
|
+
console.log();
|
|
4623
|
+
const columns = [
|
|
4624
|
+
{ header: "METHOD", minWidth: 7 },
|
|
4625
|
+
{ header: "PATH", minWidth: 20, maxWidth: 60 },
|
|
4626
|
+
{ header: "VALIDATION", minWidth: 10, maxWidth: 32 },
|
|
4627
|
+
{ header: "META", maxWidth: 40 }
|
|
4628
|
+
];
|
|
4629
|
+
const rows = filtered.map((r) => {
|
|
4630
|
+
const method = colourMethod(r.method);
|
|
4631
|
+
const path11 = r.deprecated ? pc.strikethrough(r.path) + " " + badge.deprecated() : r.path;
|
|
4632
|
+
const validation = r.validation.length > 0 ? r.validation.map(badge.validation).join(pc.dim(",")) : pc.dim("\u2014");
|
|
4633
|
+
const metaBits = [];
|
|
4634
|
+
if (r.operationId) metaBits.push(pc.dim(`op:`) + r.operationId);
|
|
4635
|
+
if (r.tags.length) metaBits.push(badge.tags(r.tags));
|
|
4636
|
+
if (r.timeout !== void 0) metaBits.push(badge.timeout(r.timeout));
|
|
4637
|
+
if (r.plugins > 0) metaBits.push(pc.dim(`+${r.plugins} plugin${r.plugins === 1 ? "" : "s"}`));
|
|
4638
|
+
const meta = metaBits.length ? metaBits.join(" ") : pc.dim("\u2014");
|
|
4639
|
+
return [method, path11, validation, meta];
|
|
3383
4640
|
});
|
|
4641
|
+
console.log(renderTable(columns, rows));
|
|
4642
|
+
const byMethod = filtered.reduce((acc, r) => {
|
|
4643
|
+
acc[r.method] = (acc[r.method] ?? 0) + 1;
|
|
4644
|
+
return acc;
|
|
4645
|
+
}, {});
|
|
4646
|
+
const summaryParts = Object.entries(byMethod).sort(([a], [b]) => a.localeCompare(b)).map(([m, n]) => `${colourMethod(m).trimEnd()} ${pc.bold(String(n))}`);
|
|
4647
|
+
console.log();
|
|
4648
|
+
console.log(
|
|
4649
|
+
` ${symbols.ok} ${pluralise(filtered.length, "route")}` + (filtered.length < all.length ? pc.dim(` (filtered from ${all.length})`) : "") + " " + summaryParts.join(pc.dim(" \xB7 "))
|
|
4650
|
+
);
|
|
4651
|
+
const filteredWs = filtered.filter((r) => r.isWs).length;
|
|
4652
|
+
if (filteredWs > 0) {
|
|
4653
|
+
console.log(
|
|
4654
|
+
pc.dim(` \u2514 ${pluralise(filteredWs, "WebSocket route")} included`)
|
|
4655
|
+
);
|
|
4656
|
+
}
|
|
4657
|
+
console.log();
|
|
4658
|
+
} catch (error) {
|
|
4659
|
+
console.error(pc.red("\u2717 Failed to inspect routes:"), error);
|
|
4660
|
+
process.exit(1);
|
|
4661
|
+
} finally {
|
|
4662
|
+
await cleanup();
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
var VALID_METHODS = /* @__PURE__ */ new Set([
|
|
4666
|
+
"GET",
|
|
4667
|
+
"POST",
|
|
4668
|
+
"PUT",
|
|
4669
|
+
"PATCH",
|
|
4670
|
+
"DELETE",
|
|
4671
|
+
"OPTIONS",
|
|
4672
|
+
"HEAD",
|
|
4673
|
+
"WS"
|
|
4674
|
+
]);
|
|
4675
|
+
function pathToFilename(routePath) {
|
|
4676
|
+
const cleaned = routePath.split("/").filter(Boolean).map((seg) => seg.startsWith(":") ? `by-${seg.slice(1)}` : seg).join("-");
|
|
4677
|
+
return cleaned || "root";
|
|
4678
|
+
}
|
|
4679
|
+
function generateRouteSource(method, routePath, opts) {
|
|
4680
|
+
const isWs = method === "WS";
|
|
4681
|
+
const params = routePath.match(/:[a-zA-Z_][a-zA-Z0-9_]*/g) ?? [];
|
|
4682
|
+
const paramKeys = params.map((p) => p.slice(1));
|
|
4683
|
+
const plugins = [];
|
|
4684
|
+
const extraImports = [];
|
|
4685
|
+
if (opts.auth) {
|
|
4686
|
+
plugins.push("requireAuth");
|
|
4687
|
+
extraImports.push(
|
|
4688
|
+
`import { createAuthPlugin } from '@axiomify/auth';
|
|
4689
|
+
|
|
4690
|
+
const requireAuth = createAuthPlugin({
|
|
4691
|
+
secret: process.env.JWT_SECRET!,
|
|
4692
|
+
});`
|
|
4693
|
+
);
|
|
4694
|
+
}
|
|
4695
|
+
if (opts.rateLimit) {
|
|
4696
|
+
plugins.push("limiter");
|
|
4697
|
+
extraImports.push(
|
|
4698
|
+
`import { createRateLimitPlugin, MemoryStore } from '@axiomify/rate-limit';
|
|
4699
|
+
|
|
4700
|
+
// Replace MemoryStore with RedisStore for multi-process / multi-host.
|
|
4701
|
+
const limiter = createRateLimitPlugin({
|
|
4702
|
+
windowMs: 60_000,
|
|
4703
|
+
max: 100,
|
|
4704
|
+
store: new MemoryStore(),
|
|
4705
|
+
});`
|
|
4706
|
+
);
|
|
4707
|
+
}
|
|
4708
|
+
if (isWs) {
|
|
4709
|
+
return [
|
|
4710
|
+
`import type { Axiomify } from '@axiomify/core';`,
|
|
4711
|
+
`import { z } from 'zod';`,
|
|
4712
|
+
extraImports.length ? extraImports.join("\n\n") + "\n" : "",
|
|
4713
|
+
`/**`,
|
|
4714
|
+
` * Registers WebSocket route ${routePath}.`,
|
|
4715
|
+
` * Wire this into your entry file:`,
|
|
4716
|
+
` * import { registerRoute } from './routes/${pathToFilename(routePath)}';`,
|
|
4717
|
+
` * registerRoute(app);`,
|
|
4718
|
+
` */`,
|
|
4719
|
+
`export function registerRoute(app: Axiomify): void {`,
|
|
4720
|
+
` app.ws({`,
|
|
4721
|
+
` path: '${routePath}',`,
|
|
4722
|
+
paramKeys.length > 0 ? ` schema: {
|
|
4723
|
+
params: z.object({ ${paramKeys.map((k) => `${k}: z.string()`).join(", ")} }),
|
|
4724
|
+
// Define your message shape here \u2014 runtime-validated on every incoming frame.
|
|
4725
|
+
message: z.object({
|
|
4726
|
+
text: z.string(),
|
|
4727
|
+
}),
|
|
4728
|
+
},` : ` schema: {
|
|
4729
|
+
// Define your message shape here \u2014 runtime-validated on every incoming frame.
|
|
4730
|
+
message: z.object({
|
|
4731
|
+
text: z.string(),
|
|
4732
|
+
}),
|
|
4733
|
+
},`,
|
|
4734
|
+
plugins.length > 0 ? ` plugins: [${plugins.join(", ")}],` : "",
|
|
4735
|
+
` open: (client, _req) => {`,
|
|
4736
|
+
` client.send({ type: 'welcome' });`,
|
|
4737
|
+
` },`,
|
|
4738
|
+
` message: (client, data) => {`,
|
|
4739
|
+
` // \`data\` is typed and validated from the schema above.`,
|
|
4740
|
+
` client.send({ echo: data.text });`,
|
|
4741
|
+
` },`,
|
|
4742
|
+
` close: (_client, code, reason) => {`,
|
|
4743
|
+
` console.log('connection closed', code, reason);`,
|
|
4744
|
+
` },`,
|
|
4745
|
+
` });`,
|
|
4746
|
+
`}`,
|
|
4747
|
+
``
|
|
4748
|
+
].filter(Boolean).join("\n");
|
|
3384
4749
|
}
|
|
4750
|
+
return [
|
|
4751
|
+
`import type { Axiomify } from '@axiomify/core';`,
|
|
4752
|
+
`import { z } from 'zod';`,
|
|
4753
|
+
extraImports.length ? extraImports.join("\n\n") + "\n" : "",
|
|
4754
|
+
`/**`,
|
|
4755
|
+
` * Registers ${method} ${routePath}.`,
|
|
4756
|
+
` * Wire this into your entry file:`,
|
|
4757
|
+
` * import { registerRoute } from './routes/${pathToFilename(routePath)}';`,
|
|
4758
|
+
` * registerRoute(app);`,
|
|
4759
|
+
` */`,
|
|
4760
|
+
`export function registerRoute(app: Axiomify): void {`,
|
|
4761
|
+
` app.route({`,
|
|
4762
|
+
` method: '${method}',`,
|
|
4763
|
+
` path: '${routePath}',`,
|
|
4764
|
+
` schema: {`,
|
|
4765
|
+
paramKeys.length > 0 ? ` params: z.object({ ${paramKeys.map((k) => `${k}: z.string()`).join(", ")} }),` : "",
|
|
4766
|
+
method === "POST" || method === "PUT" || method === "PATCH" ? ` body: z.object({
|
|
4767
|
+
// TODO \u2014 define request body shape
|
|
4768
|
+
}),` : "",
|
|
4769
|
+
` // response: z.object({ /* response shape */ }),`,
|
|
4770
|
+
` },`,
|
|
4771
|
+
` // OpenAPI metadata (tags, summary, operationId etc.) lives in schema: too`,
|
|
4772
|
+
` tags: ['${pathToFilename(routePath).split("-")[0] || "general"}'],`,
|
|
4773
|
+
` summary: '${method} ${routePath}',`,
|
|
4774
|
+
plugins.length > 0 ? ` plugins: [${plugins.join(", ")}],` : "",
|
|
4775
|
+
` handler: async (${paramKeys.length > 0 || method !== "GET" ? "req" : "_req"}, res) => {`,
|
|
4776
|
+
method === "POST" ? ` // TODO \u2014 handler logic
|
|
4777
|
+
res.status(201).send({ ok: true });` : method === "DELETE" ? ` // TODO \u2014 handler logic
|
|
4778
|
+
res.status(204).send(null);` : ` // TODO \u2014 handler logic
|
|
4779
|
+
res.send({ ok: true });`,
|
|
4780
|
+
` },`,
|
|
4781
|
+
` });`,
|
|
4782
|
+
`}`,
|
|
4783
|
+
``
|
|
4784
|
+
].filter(Boolean).join("\n");
|
|
4785
|
+
}
|
|
4786
|
+
async function scaffoldRoute(method, routePath, opts = {}) {
|
|
4787
|
+
const upperMethod = method.toUpperCase();
|
|
4788
|
+
if (!VALID_METHODS.has(upperMethod)) {
|
|
4789
|
+
console.error(
|
|
4790
|
+
pc.red(`\u2717 Invalid method "${method}".`),
|
|
4791
|
+
`Expected one of: ${[...VALID_METHODS].join(", ")}.`
|
|
4792
|
+
);
|
|
4793
|
+
process.exit(1);
|
|
4794
|
+
}
|
|
4795
|
+
if (!routePath.startsWith("/")) {
|
|
4796
|
+
console.error(
|
|
4797
|
+
pc.red('\u2717 Path must start with "/".'),
|
|
4798
|
+
`Got: ${routePath}`
|
|
4799
|
+
);
|
|
4800
|
+
process.exit(1);
|
|
4801
|
+
}
|
|
4802
|
+
const dir = opts.dir ?? "src/routes";
|
|
4803
|
+
const filename = pathToFilename(routePath) + ".ts";
|
|
4804
|
+
const fileAbs = path7.resolve(process.cwd(), dir, filename);
|
|
4805
|
+
const source = generateRouteSource(upperMethod, routePath, opts);
|
|
4806
|
+
if (opts.dryRun) {
|
|
4807
|
+
console.log(pc.dim(`# would write ${path7.relative(process.cwd(), fileAbs)}
|
|
4808
|
+
`));
|
|
4809
|
+
console.log(source);
|
|
4810
|
+
return;
|
|
4811
|
+
}
|
|
4812
|
+
let exists = false;
|
|
4813
|
+
try {
|
|
4814
|
+
await fs5.access(fileAbs);
|
|
4815
|
+
exists = true;
|
|
4816
|
+
} catch {
|
|
4817
|
+
}
|
|
4818
|
+
if (exists && !opts.force) {
|
|
4819
|
+
console.log(
|
|
4820
|
+
`${symbols.warn} ${pc.yellow("Already exists:")} ${path7.relative(process.cwd(), fileAbs)}
|
|
4821
|
+
Pass ${pc.cyan("--force")} to overwrite, or pick a different path.`
|
|
4822
|
+
);
|
|
4823
|
+
return;
|
|
4824
|
+
}
|
|
4825
|
+
await fs5.mkdir(path7.dirname(fileAbs), { recursive: true });
|
|
4826
|
+
await fs5.writeFile(fileAbs, source, "utf8");
|
|
4827
|
+
console.log();
|
|
4828
|
+
console.log(
|
|
4829
|
+
`${symbols.ok} ${pc.green("Created")} ${pc.cyan(path7.relative(process.cwd(), fileAbs))}`
|
|
4830
|
+
);
|
|
4831
|
+
console.log();
|
|
4832
|
+
console.log(pc.dim(" Next steps:"));
|
|
4833
|
+
console.log(
|
|
4834
|
+
` 1. Wire it into your entry file:
|
|
4835
|
+
` + pc.dim(` import { registerRoute } from './routes/${pathToFilename(routePath)}';
|
|
4836
|
+
`) + pc.dim(` registerRoute(app);`)
|
|
4837
|
+
);
|
|
4838
|
+
console.log(
|
|
4839
|
+
` 2. Fill in the TODOs in ${pc.cyan(path7.relative(process.cwd(), fileAbs))}.`
|
|
4840
|
+
);
|
|
4841
|
+
console.log(
|
|
4842
|
+
` 3. Verify with ${pc.cyan("npx axiomify routes")} and ${pc.cyan("npx axiomify check")}.`
|
|
4843
|
+
);
|
|
4844
|
+
console.log();
|
|
3385
4845
|
}
|
|
3386
4846
|
|
|
3387
4847
|
// src/index.ts
|
|
@@ -3392,5 +4852,37 @@ program2.command("init").description("Bootstrap a new Axiomify project").argumen
|
|
|
3392
4852
|
);
|
|
3393
4853
|
program2.command("dev").description("Start the development server with hot-reload").argument("[entry]", "Entry file", "src/index.ts").action(devServer);
|
|
3394
4854
|
program2.command("build").description("Compile the application for production").argument("[entry]", "Entry file", "src/index.ts").action(buildProject);
|
|
3395
|
-
program2.command("routes").description("Inspect and list all registered
|
|
4855
|
+
program2.command("routes").description("Inspect and list all registered HTTP + WebSocket routes").argument("[entry]", "Entry file", "src/index.ts").option("--json", "Emit machine-readable JSON instead of the formatted table", false).option(
|
|
4856
|
+
"-m, --method <list>",
|
|
4857
|
+
"Comma-separated list of methods to include (e.g. GET,POST,WS)"
|
|
4858
|
+
).option(
|
|
4859
|
+
"-f, --filter <pattern>",
|
|
4860
|
+
'Path filter \u2014 substring match, or glob with "*" (e.g. /api/v1/*)'
|
|
4861
|
+
).option(
|
|
4862
|
+
"-s, --sort <by>",
|
|
4863
|
+
'Sort routes by "method" or "path"',
|
|
4864
|
+
"path"
|
|
4865
|
+
).action(
|
|
4866
|
+
(entry, options) => inspectRoutes(entry, options)
|
|
4867
|
+
);
|
|
4868
|
+
program2.command("openapi").description("Generate the OpenAPI spec from the app and emit it").argument("[entry]", "Entry file", "src/index.ts").option(
|
|
4869
|
+
"-o, --output <file>",
|
|
4870
|
+
"Write the spec to this file path instead of stdout"
|
|
4871
|
+
).option("--format <fmt>", 'Output format: "json" (default) or "yaml"', "json").option("--minify", "Minified JSON (single line). Ignored for yaml.", false).option("--title <title>", "Override info.title in the generated spec").option("--spec-version <version>", "Override info.version in the generated spec").action(
|
|
4872
|
+
(entry, options) => emitOpenApi(entry, {
|
|
4873
|
+
...options,
|
|
4874
|
+
// Map the CLI flag name (`spec-version` → camel `specVersion`) onto
|
|
4875
|
+
// the internal `version` field that emitOpenApi() expects.
|
|
4876
|
+
version: options.specVersion
|
|
4877
|
+
})
|
|
4878
|
+
);
|
|
4879
|
+
program2.command("check").description("Run a static production-readiness audit against the app").argument("[entry]", "Entry file", "src/index.ts").action(runCheck);
|
|
4880
|
+
program2.command("doctor").description("Diagnose the host environment (Node, uWS, ports, dep drift)").action(runDoctor);
|
|
4881
|
+
var scaffold = program2.command("scaffold").description("Generate boilerplate (routes, modules, plugins)");
|
|
4882
|
+
scaffold.command("route <method> <path>").description("Create a new route file under src/routes/").option("--auth", "Include `requireAuth` plugin and import", false).option("--rate-limit", "Include a default rate-limit plugin", false).option("--dry-run", "Print the generated source without writing", false).option("--force", "Overwrite the file if it already exists", false).option("--dir <dir>", "Directory under cwd to create the file in", "src/routes").action(
|
|
4883
|
+
(method, routePath, options) => scaffoldRoute(method, routePath, options)
|
|
4884
|
+
);
|
|
4885
|
+
program2.command("migrate").description("v5 \u2192 v6 codemod: merge meta: fields into schema:, fix routePrefix \u2192 prefix, etc").option("--dry-run", "Show the unified diff without writing", false).option("--report-only", "Print a migration report and exit; do not write", false).option("--dir <dir>", "Directory to scan recursively", "src").action(
|
|
4886
|
+
(options) => runMigrate(options)
|
|
4887
|
+
);
|
|
3396
4888
|
program2.parse(process.argv);
|