@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.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var esbuild = require('esbuild');
|
|
5
|
-
var
|
|
5
|
+
var path7 = require('path');
|
|
6
6
|
var fs = require('fs');
|
|
7
|
+
var pc = require('picocolors');
|
|
8
|
+
var fs5 = require('fs/promises');
|
|
7
9
|
var child_process = require('child_process');
|
|
10
|
+
var net = require('net');
|
|
8
11
|
var enquirer = require('enquirer');
|
|
9
12
|
var execa = require('execa');
|
|
10
|
-
var fs2 = require('fs/promises');
|
|
11
|
-
var pc = require('picocolors');
|
|
12
13
|
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
|
|
@@ -31,10 +32,10 @@ function _interopNamespace(e) {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
var esbuild__namespace = /*#__PURE__*/_interopNamespace(esbuild);
|
|
34
|
-
var
|
|
35
|
+
var path7__default = /*#__PURE__*/_interopDefault(path7);
|
|
35
36
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
36
|
-
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
37
37
|
var pc__default = /*#__PURE__*/_interopDefault(pc);
|
|
38
|
+
var fs5__default = /*#__PURE__*/_interopDefault(fs5);
|
|
38
39
|
|
|
39
40
|
var __create = Object.create;
|
|
40
41
|
var __defProp = Object.defineProperty;
|
|
@@ -48,9 +49,21 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
48
49
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
49
50
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
50
51
|
});
|
|
51
|
-
var
|
|
52
|
+
var __glob = (map) => (path11) => {
|
|
53
|
+
var fn = map[path11];
|
|
54
|
+
if (fn) return fn();
|
|
55
|
+
throw new Error("Module not found in bundle: " + path11);
|
|
56
|
+
};
|
|
57
|
+
var __esm = (fn, res) => function __init() {
|
|
58
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
59
|
+
};
|
|
60
|
+
var __commonJS = (cb, mod) => function __require3() {
|
|
52
61
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
53
62
|
};
|
|
63
|
+
var __export = (target, all) => {
|
|
64
|
+
for (var name in all)
|
|
65
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
66
|
+
};
|
|
54
67
|
var __copyProps = (to, from, except, desc) => {
|
|
55
68
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
56
69
|
for (let key of __getOwnPropNames(from))
|
|
@@ -77,7 +90,6 @@ var require_error = __commonJS({
|
|
|
77
90
|
* @param {number} exitCode suggested exit code which could be used with process.exit
|
|
78
91
|
* @param {string} code an id string representing the error
|
|
79
92
|
* @param {string} message human-readable description of the error
|
|
80
|
-
* @constructor
|
|
81
93
|
*/
|
|
82
94
|
constructor(exitCode, code, message) {
|
|
83
95
|
super(message);
|
|
@@ -92,7 +104,6 @@ var require_error = __commonJS({
|
|
|
92
104
|
/**
|
|
93
105
|
* Constructs the InvalidArgumentError class
|
|
94
106
|
* @param {string} [message] explanation of why argument is invalid
|
|
95
|
-
* @constructor
|
|
96
107
|
*/
|
|
97
108
|
constructor(message) {
|
|
98
109
|
super(1, "commander.invalidArgument", message);
|
|
@@ -153,7 +164,7 @@ var require_argument = __commonJS({
|
|
|
153
164
|
return this._name;
|
|
154
165
|
}
|
|
155
166
|
/**
|
|
156
|
-
* @package
|
|
167
|
+
* @package
|
|
157
168
|
*/
|
|
158
169
|
_concatValue(value, previous) {
|
|
159
170
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
@@ -193,7 +204,9 @@ var require_argument = __commonJS({
|
|
|
193
204
|
this.argChoices = values.slice();
|
|
194
205
|
this.parseArg = (arg, previous) => {
|
|
195
206
|
if (!this.argChoices.includes(arg)) {
|
|
196
|
-
throw new InvalidArgumentError2(
|
|
207
|
+
throw new InvalidArgumentError2(
|
|
208
|
+
`Allowed choices are ${this.argChoices.join(", ")}.`
|
|
209
|
+
);
|
|
197
210
|
}
|
|
198
211
|
if (this.variadic) {
|
|
199
212
|
return this._concatValue(arg, previous);
|
|
@@ -204,6 +217,8 @@ var require_argument = __commonJS({
|
|
|
204
217
|
}
|
|
205
218
|
/**
|
|
206
219
|
* Make argument required.
|
|
220
|
+
*
|
|
221
|
+
* @returns {Argument}
|
|
207
222
|
*/
|
|
208
223
|
argRequired() {
|
|
209
224
|
this.required = true;
|
|
@@ -211,6 +226,8 @@ var require_argument = __commonJS({
|
|
|
211
226
|
}
|
|
212
227
|
/**
|
|
213
228
|
* Make argument optional.
|
|
229
|
+
*
|
|
230
|
+
* @returns {Argument}
|
|
214
231
|
*/
|
|
215
232
|
argOptional() {
|
|
216
233
|
this.required = false;
|
|
@@ -261,7 +278,7 @@ var require_help = __commonJS({
|
|
|
261
278
|
*
|
|
262
279
|
* @param {Option} a
|
|
263
280
|
* @param {Option} b
|
|
264
|
-
* @returns number
|
|
281
|
+
* @returns {number}
|
|
265
282
|
*/
|
|
266
283
|
compareOptions(a, b) {
|
|
267
284
|
const getSortKey = (option) => {
|
|
@@ -284,9 +301,13 @@ var require_help = __commonJS({
|
|
|
284
301
|
if (!removeShort && !removeLong) {
|
|
285
302
|
visibleOptions.push(helpOption);
|
|
286
303
|
} else if (helpOption.long && !removeLong) {
|
|
287
|
-
visibleOptions.push(
|
|
304
|
+
visibleOptions.push(
|
|
305
|
+
cmd.createOption(helpOption.long, helpOption.description)
|
|
306
|
+
);
|
|
288
307
|
} else if (helpOption.short && !removeShort) {
|
|
289
|
-
visibleOptions.push(
|
|
308
|
+
visibleOptions.push(
|
|
309
|
+
cmd.createOption(helpOption.short, helpOption.description)
|
|
310
|
+
);
|
|
290
311
|
}
|
|
291
312
|
}
|
|
292
313
|
if (this.sortOptions) {
|
|
@@ -304,7 +325,9 @@ var require_help = __commonJS({
|
|
|
304
325
|
if (!this.showGlobalOptions) return [];
|
|
305
326
|
const globalOptions = [];
|
|
306
327
|
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
|
|
307
|
-
const visibleOptions = ancestorCmd.options.filter(
|
|
328
|
+
const visibleOptions = ancestorCmd.options.filter(
|
|
329
|
+
(option) => !option.hidden
|
|
330
|
+
);
|
|
308
331
|
globalOptions.push(...visibleOptions);
|
|
309
332
|
}
|
|
310
333
|
if (this.sortOptions) {
|
|
@@ -459,7 +482,9 @@ var require_help = __commonJS({
|
|
|
459
482
|
if (option.defaultValue !== void 0) {
|
|
460
483
|
const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
|
|
461
484
|
if (showDefault) {
|
|
462
|
-
extraInfo.push(
|
|
485
|
+
extraInfo.push(
|
|
486
|
+
`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`
|
|
487
|
+
);
|
|
463
488
|
}
|
|
464
489
|
}
|
|
465
490
|
if (option.presetArg !== void 0 && option.optional) {
|
|
@@ -488,7 +513,9 @@ var require_help = __commonJS({
|
|
|
488
513
|
);
|
|
489
514
|
}
|
|
490
515
|
if (argument.defaultValue !== void 0) {
|
|
491
|
-
extraInfo.push(
|
|
516
|
+
extraInfo.push(
|
|
517
|
+
`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`
|
|
518
|
+
);
|
|
492
519
|
}
|
|
493
520
|
if (extraInfo.length > 0) {
|
|
494
521
|
const extraDescripton = `(${extraInfo.join(", ")})`;
|
|
@@ -514,7 +541,11 @@ var require_help = __commonJS({
|
|
|
514
541
|
function formatItem(term, description) {
|
|
515
542
|
if (description) {
|
|
516
543
|
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
517
|
-
return helper.wrap(
|
|
544
|
+
return helper.wrap(
|
|
545
|
+
fullText,
|
|
546
|
+
helpWidth - itemIndentWidth,
|
|
547
|
+
termWidth + itemSeparatorWidth
|
|
548
|
+
);
|
|
518
549
|
}
|
|
519
550
|
return term;
|
|
520
551
|
}
|
|
@@ -524,30 +555,49 @@ var require_help = __commonJS({
|
|
|
524
555
|
let output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
|
|
525
556
|
const commandDescription = helper.commandDescription(cmd);
|
|
526
557
|
if (commandDescription.length > 0) {
|
|
527
|
-
output = output.concat([
|
|
558
|
+
output = output.concat([
|
|
559
|
+
helper.wrap(commandDescription, helpWidth, 0),
|
|
560
|
+
""
|
|
561
|
+
]);
|
|
528
562
|
}
|
|
529
563
|
const argumentList = helper.visibleArguments(cmd).map((argument) => {
|
|
530
|
-
return formatItem(
|
|
564
|
+
return formatItem(
|
|
565
|
+
helper.argumentTerm(argument),
|
|
566
|
+
helper.argumentDescription(argument)
|
|
567
|
+
);
|
|
531
568
|
});
|
|
532
569
|
if (argumentList.length > 0) {
|
|
533
570
|
output = output.concat(["Arguments:", formatList(argumentList), ""]);
|
|
534
571
|
}
|
|
535
572
|
const optionList = helper.visibleOptions(cmd).map((option) => {
|
|
536
|
-
return formatItem(
|
|
573
|
+
return formatItem(
|
|
574
|
+
helper.optionTerm(option),
|
|
575
|
+
helper.optionDescription(option)
|
|
576
|
+
);
|
|
537
577
|
});
|
|
538
578
|
if (optionList.length > 0) {
|
|
539
579
|
output = output.concat(["Options:", formatList(optionList), ""]);
|
|
540
580
|
}
|
|
541
581
|
if (this.showGlobalOptions) {
|
|
542
582
|
const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
|
|
543
|
-
return formatItem(
|
|
583
|
+
return formatItem(
|
|
584
|
+
helper.optionTerm(option),
|
|
585
|
+
helper.optionDescription(option)
|
|
586
|
+
);
|
|
544
587
|
});
|
|
545
588
|
if (globalOptionList.length > 0) {
|
|
546
|
-
output = output.concat([
|
|
589
|
+
output = output.concat([
|
|
590
|
+
"Global Options:",
|
|
591
|
+
formatList(globalOptionList),
|
|
592
|
+
""
|
|
593
|
+
]);
|
|
547
594
|
}
|
|
548
595
|
}
|
|
549
596
|
const commandList = helper.visibleCommands(cmd).map((cmd2) => {
|
|
550
|
-
return formatItem(
|
|
597
|
+
return formatItem(
|
|
598
|
+
helper.subcommandTerm(cmd2),
|
|
599
|
+
helper.subcommandDescription(cmd2)
|
|
600
|
+
);
|
|
551
601
|
});
|
|
552
602
|
if (commandList.length > 0) {
|
|
553
603
|
output = output.concat(["Commands:", formatList(commandList), ""]);
|
|
@@ -591,8 +641,11 @@ var require_help = __commonJS({
|
|
|
591
641
|
const indentString = " ".repeat(indent);
|
|
592
642
|
const zeroWidthSpace = "\u200B";
|
|
593
643
|
const breaks = `\\s${zeroWidthSpace}`;
|
|
594
|
-
const regex = new RegExp(
|
|
595
|
-
|
|
644
|
+
const regex = new RegExp(
|
|
645
|
+
`
|
|
646
|
+
|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`,
|
|
647
|
+
"g"
|
|
648
|
+
);
|
|
596
649
|
const lines = columnText.match(regex) || [];
|
|
597
650
|
return leadingStr + lines.map((line, i) => {
|
|
598
651
|
if (line === "\n") return "";
|
|
@@ -691,7 +744,7 @@ var require_option = __commonJS({
|
|
|
691
744
|
* .addOption(new Option('--log', 'write logging information to file'))
|
|
692
745
|
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
|
|
693
746
|
*
|
|
694
|
-
* @param {
|
|
747
|
+
* @param {object} impliedOptionValues
|
|
695
748
|
* @return {Option}
|
|
696
749
|
*/
|
|
697
750
|
implies(impliedOptionValues) {
|
|
@@ -746,7 +799,7 @@ var require_option = __commonJS({
|
|
|
746
799
|
return this;
|
|
747
800
|
}
|
|
748
801
|
/**
|
|
749
|
-
* @package
|
|
802
|
+
* @package
|
|
750
803
|
*/
|
|
751
804
|
_concatValue(value, previous) {
|
|
752
805
|
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
|
@@ -764,7 +817,9 @@ var require_option = __commonJS({
|
|
|
764
817
|
this.argChoices = values.slice();
|
|
765
818
|
this.parseArg = (arg, previous) => {
|
|
766
819
|
if (!this.argChoices.includes(arg)) {
|
|
767
|
-
throw new InvalidArgumentError2(
|
|
820
|
+
throw new InvalidArgumentError2(
|
|
821
|
+
`Allowed choices are ${this.argChoices.join(", ")}.`
|
|
822
|
+
);
|
|
768
823
|
}
|
|
769
824
|
if (this.variadic) {
|
|
770
825
|
return this._concatValue(arg, previous);
|
|
@@ -798,7 +853,7 @@ var require_option = __commonJS({
|
|
|
798
853
|
*
|
|
799
854
|
* @param {string} arg
|
|
800
855
|
* @return {boolean}
|
|
801
|
-
* @package
|
|
856
|
+
* @package
|
|
802
857
|
*/
|
|
803
858
|
is(arg) {
|
|
804
859
|
return this.short === arg || this.long === arg;
|
|
@@ -809,7 +864,7 @@ var require_option = __commonJS({
|
|
|
809
864
|
* Options are one of boolean, negated, required argument, or optional argument.
|
|
810
865
|
*
|
|
811
866
|
* @return {boolean}
|
|
812
|
-
* @package
|
|
867
|
+
* @package
|
|
813
868
|
*/
|
|
814
869
|
isBoolean() {
|
|
815
870
|
return !this.required && !this.optional && !this.negate;
|
|
@@ -860,7 +915,8 @@ var require_option = __commonJS({
|
|
|
860
915
|
let shortFlag;
|
|
861
916
|
let longFlag;
|
|
862
917
|
const flagParts = flags.split(/[ |,]+/);
|
|
863
|
-
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
|
|
918
|
+
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
|
|
919
|
+
shortFlag = flagParts.shift();
|
|
864
920
|
longFlag = flagParts.shift();
|
|
865
921
|
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
|
|
866
922
|
shortFlag = longFlag;
|
|
@@ -878,7 +934,8 @@ var require_suggestSimilar = __commonJS({
|
|
|
878
934
|
"node_modules/commander/lib/suggestSimilar.js"(exports) {
|
|
879
935
|
var maxDistance = 3;
|
|
880
936
|
function editDistance(a, b) {
|
|
881
|
-
if (Math.abs(a.length - b.length) > maxDistance)
|
|
937
|
+
if (Math.abs(a.length - b.length) > maxDistance)
|
|
938
|
+
return Math.max(a.length, b.length);
|
|
882
939
|
const d = [];
|
|
883
940
|
for (let i = 0; i <= a.length; i++) {
|
|
884
941
|
d[i] = [i];
|
|
@@ -957,8 +1014,8 @@ var require_command = __commonJS({
|
|
|
957
1014
|
"node_modules/commander/lib/command.js"(exports) {
|
|
958
1015
|
var EventEmitter = __require("events").EventEmitter;
|
|
959
1016
|
var childProcess = __require("child_process");
|
|
960
|
-
var
|
|
961
|
-
var
|
|
1017
|
+
var path11 = __require("path");
|
|
1018
|
+
var fs9 = __require("fs");
|
|
962
1019
|
var process2 = __require("process");
|
|
963
1020
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
964
1021
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1070,8 +1127,8 @@ var require_command = __commonJS({
|
|
|
1070
1127
|
* .command('stop [service]', 'stop named service, or all if no name supplied');
|
|
1071
1128
|
*
|
|
1072
1129
|
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
|
|
1073
|
-
* @param {(
|
|
1074
|
-
* @param {
|
|
1130
|
+
* @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
|
|
1131
|
+
* @param {object} [execOpts] - configuration options (for executable)
|
|
1075
1132
|
* @return {Command} returns new command for action handler, or `this` for executable command
|
|
1076
1133
|
*/
|
|
1077
1134
|
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
|
|
@@ -1123,8 +1180,8 @@ var require_command = __commonJS({
|
|
|
1123
1180
|
* You can customise the help by overriding Help properties using configureHelp(),
|
|
1124
1181
|
* or with a subclass of Help by overriding createHelp().
|
|
1125
1182
|
*
|
|
1126
|
-
* @param {
|
|
1127
|
-
* @return {(Command|
|
|
1183
|
+
* @param {object} [configuration] - configuration options
|
|
1184
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
1128
1185
|
*/
|
|
1129
1186
|
configureHelp(configuration) {
|
|
1130
1187
|
if (configuration === void 0) return this._helpConfiguration;
|
|
@@ -1146,8 +1203,8 @@ var require_command = __commonJS({
|
|
|
1146
1203
|
* // functions based on what is being written out
|
|
1147
1204
|
* outputError(str, write) // used for displaying errors, and not used for displaying help
|
|
1148
1205
|
*
|
|
1149
|
-
* @param {
|
|
1150
|
-
* @return {(Command|
|
|
1206
|
+
* @param {object} [configuration] - configuration options
|
|
1207
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
1151
1208
|
*/
|
|
1152
1209
|
configureOutput(configuration) {
|
|
1153
1210
|
if (configuration === void 0) return this._outputConfiguration;
|
|
@@ -1181,7 +1238,7 @@ var require_command = __commonJS({
|
|
|
1181
1238
|
* See .command() for creating an attached subcommand which inherits settings from its parent.
|
|
1182
1239
|
*
|
|
1183
1240
|
* @param {Command} cmd - new subcommand
|
|
1184
|
-
* @param {
|
|
1241
|
+
* @param {object} [opts] - configuration options
|
|
1185
1242
|
* @return {Command} `this` command for chaining
|
|
1186
1243
|
*/
|
|
1187
1244
|
addCommand(cmd, opts) {
|
|
@@ -1262,10 +1319,14 @@ var require_command = __commonJS({
|
|
|
1262
1319
|
addArgument(argument) {
|
|
1263
1320
|
const previousArgument = this.registeredArguments.slice(-1)[0];
|
|
1264
1321
|
if (previousArgument && previousArgument.variadic) {
|
|
1265
|
-
throw new Error(
|
|
1322
|
+
throw new Error(
|
|
1323
|
+
`only the last argument can be variadic '${previousArgument.name()}'`
|
|
1324
|
+
);
|
|
1266
1325
|
}
|
|
1267
1326
|
if (argument.required && argument.defaultValue !== void 0 && argument.parseArg === void 0) {
|
|
1268
|
-
throw new Error(
|
|
1327
|
+
throw new Error(
|
|
1328
|
+
`a default value for a required argument is never used: '${argument.name()}'`
|
|
1329
|
+
);
|
|
1269
1330
|
}
|
|
1270
1331
|
this.registeredArguments.push(argument);
|
|
1271
1332
|
return this;
|
|
@@ -1273,6 +1334,7 @@ var require_command = __commonJS({
|
|
|
1273
1334
|
/**
|
|
1274
1335
|
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
|
|
1275
1336
|
*
|
|
1337
|
+
* @example
|
|
1276
1338
|
* program.helpCommand('help [cmd]');
|
|
1277
1339
|
* program.helpCommand('help [cmd]', 'show help');
|
|
1278
1340
|
* program.helpCommand(false); // suppress default help command
|
|
@@ -1450,7 +1512,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1450
1512
|
* Register option if no conflicts found, or throw on conflict.
|
|
1451
1513
|
*
|
|
1452
1514
|
* @param {Option} option
|
|
1453
|
-
* @
|
|
1515
|
+
* @private
|
|
1454
1516
|
*/
|
|
1455
1517
|
_registerOption(option) {
|
|
1456
1518
|
const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
|
|
@@ -1466,17 +1528,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1466
1528
|
* Register command if no conflicts found, or throw on conflict.
|
|
1467
1529
|
*
|
|
1468
1530
|
* @param {Command} command
|
|
1469
|
-
* @
|
|
1531
|
+
* @private
|
|
1470
1532
|
*/
|
|
1471
1533
|
_registerCommand(command) {
|
|
1472
1534
|
const knownBy = (cmd) => {
|
|
1473
1535
|
return [cmd.name()].concat(cmd.aliases());
|
|
1474
1536
|
};
|
|
1475
|
-
const alreadyUsed = knownBy(command).find(
|
|
1537
|
+
const alreadyUsed = knownBy(command).find(
|
|
1538
|
+
(name) => this._findCommand(name)
|
|
1539
|
+
);
|
|
1476
1540
|
if (alreadyUsed) {
|
|
1477
1541
|
const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
|
|
1478
1542
|
const newCmd = knownBy(command).join("|");
|
|
1479
|
-
throw new Error(
|
|
1543
|
+
throw new Error(
|
|
1544
|
+
`cannot add command '${newCmd}' as already have command '${existingCmd}'`
|
|
1545
|
+
);
|
|
1480
1546
|
}
|
|
1481
1547
|
this.commands.push(command);
|
|
1482
1548
|
}
|
|
@@ -1493,7 +1559,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1493
1559
|
if (option.negate) {
|
|
1494
1560
|
const positiveLongFlag = option.long.replace(/^--no-/, "--");
|
|
1495
1561
|
if (!this._findOption(positiveLongFlag)) {
|
|
1496
|
-
this.setOptionValueWithSource(
|
|
1562
|
+
this.setOptionValueWithSource(
|
|
1563
|
+
name,
|
|
1564
|
+
option.defaultValue === void 0 ? true : option.defaultValue,
|
|
1565
|
+
"default"
|
|
1566
|
+
);
|
|
1497
1567
|
}
|
|
1498
1568
|
} else if (option.defaultValue !== void 0) {
|
|
1499
1569
|
this.setOptionValueWithSource(name, option.defaultValue, "default");
|
|
@@ -1534,11 +1604,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1534
1604
|
/**
|
|
1535
1605
|
* Internal implementation shared by .option() and .requiredOption()
|
|
1536
1606
|
*
|
|
1607
|
+
* @return {Command} `this` command for chaining
|
|
1537
1608
|
* @private
|
|
1538
1609
|
*/
|
|
1539
1610
|
_optionEx(config, flags, description, fn, defaultValue) {
|
|
1540
1611
|
if (typeof flags === "object" && flags instanceof Option2) {
|
|
1541
|
-
throw new Error(
|
|
1612
|
+
throw new Error(
|
|
1613
|
+
"To add an Option object use addOption() instead of option() or requiredOption()"
|
|
1614
|
+
);
|
|
1542
1615
|
}
|
|
1543
1616
|
const option = this.createOption(flags, description);
|
|
1544
1617
|
option.makeOptionMandatory(!!config.mandatory);
|
|
@@ -1581,19 +1654,25 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1581
1654
|
return this._optionEx({}, flags, description, parseArg, defaultValue);
|
|
1582
1655
|
}
|
|
1583
1656
|
/**
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1657
|
+
* Add a required option which must have a value after parsing. This usually means
|
|
1658
|
+
* the option must be specified on the command line. (Otherwise the same as .option().)
|
|
1659
|
+
*
|
|
1660
|
+
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
|
|
1661
|
+
*
|
|
1662
|
+
* @param {string} flags
|
|
1663
|
+
* @param {string} [description]
|
|
1664
|
+
* @param {(Function|*)} [parseArg] - custom option processing function or default value
|
|
1665
|
+
* @param {*} [defaultValue]
|
|
1666
|
+
* @return {Command} `this` command for chaining
|
|
1667
|
+
*/
|
|
1595
1668
|
requiredOption(flags, description, parseArg, defaultValue) {
|
|
1596
|
-
return this._optionEx(
|
|
1669
|
+
return this._optionEx(
|
|
1670
|
+
{ mandatory: true },
|
|
1671
|
+
flags,
|
|
1672
|
+
description,
|
|
1673
|
+
parseArg,
|
|
1674
|
+
defaultValue
|
|
1675
|
+
);
|
|
1597
1676
|
}
|
|
1598
1677
|
/**
|
|
1599
1678
|
* Alter parsing of short flags with optional values.
|
|
@@ -1603,7 +1682,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1603
1682
|
* program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
|
|
1604
1683
|
* program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
|
|
1605
1684
|
*
|
|
1606
|
-
* @param {boolean} [combine
|
|
1685
|
+
* @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
|
|
1686
|
+
* @return {Command} `this` command for chaining
|
|
1607
1687
|
*/
|
|
1608
1688
|
combineFlagAndOptionalValue(combine = true) {
|
|
1609
1689
|
this._combineFlagAndOptionalValue = !!combine;
|
|
@@ -1612,8 +1692,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1612
1692
|
/**
|
|
1613
1693
|
* Allow unknown options on the command line.
|
|
1614
1694
|
*
|
|
1615
|
-
* @param {boolean} [allowUnknown
|
|
1616
|
-
* for
|
|
1695
|
+
* @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
|
|
1696
|
+
* @return {Command} `this` command for chaining
|
|
1617
1697
|
*/
|
|
1618
1698
|
allowUnknownOption(allowUnknown = true) {
|
|
1619
1699
|
this._allowUnknownOption = !!allowUnknown;
|
|
@@ -1622,8 +1702,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1622
1702
|
/**
|
|
1623
1703
|
* Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
|
|
1624
1704
|
*
|
|
1625
|
-
* @param {boolean} [allowExcess
|
|
1626
|
-
* for
|
|
1705
|
+
* @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
|
|
1706
|
+
* @return {Command} `this` command for chaining
|
|
1627
1707
|
*/
|
|
1628
1708
|
allowExcessArguments(allowExcess = true) {
|
|
1629
1709
|
this._allowExcessArguments = !!allowExcess;
|
|
@@ -1634,7 +1714,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1634
1714
|
* subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
|
|
1635
1715
|
* The default behaviour is non-positional and global options may appear anywhere on the command line.
|
|
1636
1716
|
*
|
|
1637
|
-
* @param {boolean} [positional
|
|
1717
|
+
* @param {boolean} [positional]
|
|
1718
|
+
* @return {Command} `this` command for chaining
|
|
1638
1719
|
*/
|
|
1639
1720
|
enablePositionalOptions(positional = true) {
|
|
1640
1721
|
this._enablePositionalOptions = !!positional;
|
|
@@ -1646,8 +1727,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1646
1727
|
* positional options to have been enabled on the program (parent commands).
|
|
1647
1728
|
* The default behaviour is non-positional and options may appear before or after command-arguments.
|
|
1648
1729
|
*
|
|
1649
|
-
* @param {boolean} [passThrough
|
|
1650
|
-
* for
|
|
1730
|
+
* @param {boolean} [passThrough] for unknown options.
|
|
1731
|
+
* @return {Command} `this` command for chaining
|
|
1651
1732
|
*/
|
|
1652
1733
|
passThroughOptions(passThrough = true) {
|
|
1653
1734
|
this._passThroughOptions = !!passThrough;
|
|
@@ -1659,22 +1740,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1659
1740
|
*/
|
|
1660
1741
|
_checkForBrokenPassThrough() {
|
|
1661
1742
|
if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
|
|
1662
|
-
throw new Error(
|
|
1743
|
+
throw new Error(
|
|
1744
|
+
`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`
|
|
1745
|
+
);
|
|
1663
1746
|
}
|
|
1664
1747
|
}
|
|
1665
1748
|
/**
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1749
|
+
* Whether to store option values as properties on command object,
|
|
1750
|
+
* or store separately (specify false). In both cases the option values can be accessed using .opts().
|
|
1751
|
+
*
|
|
1752
|
+
* @param {boolean} [storeAsProperties=true]
|
|
1753
|
+
* @return {Command} `this` command for chaining
|
|
1754
|
+
*/
|
|
1672
1755
|
storeOptionsAsProperties(storeAsProperties = true) {
|
|
1673
1756
|
if (this.options.length) {
|
|
1674
1757
|
throw new Error("call .storeOptionsAsProperties() before adding options");
|
|
1675
1758
|
}
|
|
1676
1759
|
if (Object.keys(this._optionValues).length) {
|
|
1677
|
-
throw new Error(
|
|
1760
|
+
throw new Error(
|
|
1761
|
+
"call .storeOptionsAsProperties() before setting option values"
|
|
1762
|
+
);
|
|
1678
1763
|
}
|
|
1679
1764
|
this._storeOptionsAsProperties = !!storeAsProperties;
|
|
1680
1765
|
return this;
|
|
@@ -1683,7 +1768,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1683
1768
|
* Retrieve option value.
|
|
1684
1769
|
*
|
|
1685
1770
|
* @param {string} key
|
|
1686
|
-
* @return {
|
|
1771
|
+
* @return {object} value
|
|
1687
1772
|
*/
|
|
1688
1773
|
getOptionValue(key) {
|
|
1689
1774
|
if (this._storeOptionsAsProperties) {
|
|
@@ -1695,20 +1780,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1695
1780
|
* Store option value.
|
|
1696
1781
|
*
|
|
1697
1782
|
* @param {string} key
|
|
1698
|
-
* @param {
|
|
1783
|
+
* @param {object} value
|
|
1699
1784
|
* @return {Command} `this` command for chaining
|
|
1700
1785
|
*/
|
|
1701
1786
|
setOptionValue(key, value) {
|
|
1702
1787
|
return this.setOptionValueWithSource(key, value, void 0);
|
|
1703
1788
|
}
|
|
1704
1789
|
/**
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1790
|
+
* Store option value and where the value came from.
|
|
1791
|
+
*
|
|
1792
|
+
* @param {string} key
|
|
1793
|
+
* @param {object} value
|
|
1794
|
+
* @param {string} source - expected values are default/config/env/cli/implied
|
|
1795
|
+
* @return {Command} `this` command for chaining
|
|
1796
|
+
*/
|
|
1712
1797
|
setOptionValueWithSource(key, value, source) {
|
|
1713
1798
|
if (this._storeOptionsAsProperties) {
|
|
1714
1799
|
this[key] = value;
|
|
@@ -1719,22 +1804,22 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1719
1804
|
return this;
|
|
1720
1805
|
}
|
|
1721
1806
|
/**
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1807
|
+
* Get source of option value.
|
|
1808
|
+
* Expected values are default | config | env | cli | implied
|
|
1809
|
+
*
|
|
1810
|
+
* @param {string} key
|
|
1811
|
+
* @return {string}
|
|
1812
|
+
*/
|
|
1728
1813
|
getOptionValueSource(key) {
|
|
1729
1814
|
return this._optionValueSources[key];
|
|
1730
1815
|
}
|
|
1731
1816
|
/**
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1817
|
+
* Get source of option value. See also .optsWithGlobals().
|
|
1818
|
+
* Expected values are default | config | env | cli | implied
|
|
1819
|
+
*
|
|
1820
|
+
* @param {string} key
|
|
1821
|
+
* @return {string}
|
|
1822
|
+
*/
|
|
1738
1823
|
getOptionValueSourceWithGlobals(key) {
|
|
1739
1824
|
let source;
|
|
1740
1825
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
@@ -1755,11 +1840,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1755
1840
|
throw new Error("first parameter to parse must be array or undefined");
|
|
1756
1841
|
}
|
|
1757
1842
|
parseOptions = parseOptions || {};
|
|
1758
|
-
if (argv === void 0) {
|
|
1759
|
-
|
|
1760
|
-
if (process2.versions && process2.versions.electron) {
|
|
1843
|
+
if (argv === void 0 && parseOptions.from === void 0) {
|
|
1844
|
+
if (process2.versions?.electron) {
|
|
1761
1845
|
parseOptions.from = "electron";
|
|
1762
1846
|
}
|
|
1847
|
+
const execArgv = process2.execArgv ?? [];
|
|
1848
|
+
if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
|
|
1849
|
+
parseOptions.from = "eval";
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
if (argv === void 0) {
|
|
1853
|
+
argv = process2.argv;
|
|
1763
1854
|
}
|
|
1764
1855
|
this.rawArgs = argv.slice();
|
|
1765
1856
|
let userArgs;
|
|
@@ -1780,26 +1871,38 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1780
1871
|
case "user":
|
|
1781
1872
|
userArgs = argv.slice(0);
|
|
1782
1873
|
break;
|
|
1874
|
+
case "eval":
|
|
1875
|
+
userArgs = argv.slice(1);
|
|
1876
|
+
break;
|
|
1783
1877
|
default:
|
|
1784
|
-
throw new Error(
|
|
1878
|
+
throw new Error(
|
|
1879
|
+
`unexpected parse option { from: '${parseOptions.from}' }`
|
|
1880
|
+
);
|
|
1785
1881
|
}
|
|
1786
|
-
if (!this._name && this._scriptPath)
|
|
1882
|
+
if (!this._name && this._scriptPath)
|
|
1883
|
+
this.nameFromFilename(this._scriptPath);
|
|
1787
1884
|
this._name = this._name || "program";
|
|
1788
1885
|
return userArgs;
|
|
1789
1886
|
}
|
|
1790
1887
|
/**
|
|
1791
1888
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
1792
1889
|
*
|
|
1793
|
-
*
|
|
1794
|
-
*
|
|
1890
|
+
* Use parseAsync instead of parse if any of your action handlers are async.
|
|
1891
|
+
*
|
|
1892
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
1893
|
+
*
|
|
1894
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1895
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1896
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1897
|
+
* - `'user'`: just user arguments
|
|
1795
1898
|
*
|
|
1796
1899
|
* @example
|
|
1797
|
-
* program.parse(process.argv
|
|
1798
|
-
* program.parse(); //
|
|
1900
|
+
* program.parse(); // parse process.argv and auto-detect electron and special node flags
|
|
1901
|
+
* program.parse(process.argv); // assume argv[0] is app and argv[1] is script
|
|
1799
1902
|
* program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
1800
1903
|
*
|
|
1801
1904
|
* @param {string[]} [argv] - optional, defaults to process.argv
|
|
1802
|
-
* @param {
|
|
1905
|
+
* @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
|
|
1803
1906
|
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
|
|
1804
1907
|
* @return {Command} `this` command for chaining
|
|
1805
1908
|
*/
|
|
@@ -1811,18 +1914,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1811
1914
|
/**
|
|
1812
1915
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
1813
1916
|
*
|
|
1814
|
-
*
|
|
1917
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
1815
1918
|
*
|
|
1816
|
-
*
|
|
1817
|
-
*
|
|
1919
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1920
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1921
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1922
|
+
* - `'user'`: just user arguments
|
|
1818
1923
|
*
|
|
1819
1924
|
* @example
|
|
1820
|
-
* await program.parseAsync(process.argv
|
|
1821
|
-
* await program.parseAsync(); //
|
|
1925
|
+
* await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
|
|
1926
|
+
* await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
|
|
1822
1927
|
* await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
1823
1928
|
*
|
|
1824
1929
|
* @param {string[]} [argv]
|
|
1825
|
-
* @param {
|
|
1930
|
+
* @param {object} [parseOptions]
|
|
1826
1931
|
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
|
|
1827
1932
|
* @return {Promise}
|
|
1828
1933
|
*/
|
|
@@ -1841,10 +1946,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1841
1946
|
let launchWithNode = false;
|
|
1842
1947
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1843
1948
|
function findFile(baseDir, baseName) {
|
|
1844
|
-
const localBin =
|
|
1845
|
-
if (
|
|
1846
|
-
if (sourceExt.includes(
|
|
1847
|
-
const foundExt = sourceExt.find(
|
|
1949
|
+
const localBin = path11.resolve(baseDir, baseName);
|
|
1950
|
+
if (fs9.existsSync(localBin)) return localBin;
|
|
1951
|
+
if (sourceExt.includes(path11.extname(baseName))) return void 0;
|
|
1952
|
+
const foundExt = sourceExt.find(
|
|
1953
|
+
(ext) => fs9.existsSync(`${localBin}${ext}`)
|
|
1954
|
+
);
|
|
1848
1955
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1849
1956
|
return void 0;
|
|
1850
1957
|
}
|
|
@@ -1855,23 +1962,32 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1855
1962
|
if (this._scriptPath) {
|
|
1856
1963
|
let resolvedScriptPath;
|
|
1857
1964
|
try {
|
|
1858
|
-
resolvedScriptPath =
|
|
1965
|
+
resolvedScriptPath = fs9.realpathSync(this._scriptPath);
|
|
1859
1966
|
} catch (err) {
|
|
1860
1967
|
resolvedScriptPath = this._scriptPath;
|
|
1861
1968
|
}
|
|
1862
|
-
executableDir =
|
|
1969
|
+
executableDir = path11.resolve(
|
|
1970
|
+
path11.dirname(resolvedScriptPath),
|
|
1971
|
+
executableDir
|
|
1972
|
+
);
|
|
1863
1973
|
}
|
|
1864
1974
|
if (executableDir) {
|
|
1865
1975
|
let localFile = findFile(executableDir, executableFile);
|
|
1866
1976
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1867
|
-
const legacyName =
|
|
1977
|
+
const legacyName = path11.basename(
|
|
1978
|
+
this._scriptPath,
|
|
1979
|
+
path11.extname(this._scriptPath)
|
|
1980
|
+
);
|
|
1868
1981
|
if (legacyName !== this._name) {
|
|
1869
|
-
localFile = findFile(
|
|
1982
|
+
localFile = findFile(
|
|
1983
|
+
executableDir,
|
|
1984
|
+
`${legacyName}-${subcommand._name}`
|
|
1985
|
+
);
|
|
1870
1986
|
}
|
|
1871
1987
|
}
|
|
1872
1988
|
executableFile = localFile || executableFile;
|
|
1873
1989
|
}
|
|
1874
|
-
launchWithNode = sourceExt.includes(
|
|
1990
|
+
launchWithNode = sourceExt.includes(path11.extname(executableFile));
|
|
1875
1991
|
let proc;
|
|
1876
1992
|
if (process2.platform !== "win32") {
|
|
1877
1993
|
if (launchWithNode) {
|
|
@@ -1897,12 +2013,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1897
2013
|
});
|
|
1898
2014
|
}
|
|
1899
2015
|
const exitCallback = this._exitCallback;
|
|
1900
|
-
proc.on("close", (code
|
|
2016
|
+
proc.on("close", (code) => {
|
|
1901
2017
|
code = code ?? 1;
|
|
1902
2018
|
if (!exitCallback) {
|
|
1903
2019
|
process2.exit(code);
|
|
1904
2020
|
} else {
|
|
1905
|
-
exitCallback(
|
|
2021
|
+
exitCallback(
|
|
2022
|
+
new CommanderError2(
|
|
2023
|
+
code,
|
|
2024
|
+
"commander.executeSubCommandAsync",
|
|
2025
|
+
"(close)"
|
|
2026
|
+
)
|
|
2027
|
+
);
|
|
1906
2028
|
}
|
|
1907
2029
|
});
|
|
1908
2030
|
proc.on("error", (err) => {
|
|
@@ -1919,7 +2041,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1919
2041
|
if (!exitCallback) {
|
|
1920
2042
|
process2.exit(1);
|
|
1921
2043
|
} else {
|
|
1922
|
-
const wrappedError = new CommanderError2(
|
|
2044
|
+
const wrappedError = new CommanderError2(
|
|
2045
|
+
1,
|
|
2046
|
+
"commander.executeSubCommandAsync",
|
|
2047
|
+
"(error)"
|
|
2048
|
+
);
|
|
1923
2049
|
wrappedError.nestedError = err;
|
|
1924
2050
|
exitCallback(wrappedError);
|
|
1925
2051
|
}
|
|
@@ -1933,7 +2059,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1933
2059
|
const subCommand = this._findCommand(commandName);
|
|
1934
2060
|
if (!subCommand) this.help({ error: true });
|
|
1935
2061
|
let promiseChain;
|
|
1936
|
-
promiseChain = this._chainOrCallSubCommandHook(
|
|
2062
|
+
promiseChain = this._chainOrCallSubCommandHook(
|
|
2063
|
+
promiseChain,
|
|
2064
|
+
subCommand,
|
|
2065
|
+
"preSubcommand"
|
|
2066
|
+
);
|
|
1937
2067
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
1938
2068
|
if (subCommand._executableHandler) {
|
|
1939
2069
|
this._executeSubCommand(subCommand, operands.concat(unknown));
|
|
@@ -1957,9 +2087,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1957
2087
|
if (subCommand && !subCommand._executableHandler) {
|
|
1958
2088
|
subCommand.help();
|
|
1959
2089
|
}
|
|
1960
|
-
return this._dispatchSubcommand(
|
|
1961
|
-
|
|
1962
|
-
|
|
2090
|
+
return this._dispatchSubcommand(
|
|
2091
|
+
subcommandName,
|
|
2092
|
+
[],
|
|
2093
|
+
[this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]
|
|
2094
|
+
);
|
|
1963
2095
|
}
|
|
1964
2096
|
/**
|
|
1965
2097
|
* Check this.args against expected this.registeredArguments.
|
|
@@ -1989,7 +2121,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1989
2121
|
let parsedValue = value;
|
|
1990
2122
|
if (value !== null && argument.parseArg) {
|
|
1991
2123
|
const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
|
|
1992
|
-
parsedValue = this._callParseArg(
|
|
2124
|
+
parsedValue = this._callParseArg(
|
|
2125
|
+
argument,
|
|
2126
|
+
value,
|
|
2127
|
+
previous,
|
|
2128
|
+
invalidValueMessage
|
|
2129
|
+
);
|
|
1993
2130
|
}
|
|
1994
2131
|
return parsedValue;
|
|
1995
2132
|
};
|
|
@@ -2097,7 +2234,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2097
2234
|
}
|
|
2098
2235
|
if (this._defaultCommandName) {
|
|
2099
2236
|
this._outputHelpIfRequested(unknown);
|
|
2100
|
-
return this._dispatchSubcommand(
|
|
2237
|
+
return this._dispatchSubcommand(
|
|
2238
|
+
this._defaultCommandName,
|
|
2239
|
+
operands,
|
|
2240
|
+
unknown
|
|
2241
|
+
);
|
|
2101
2242
|
}
|
|
2102
2243
|
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
|
|
2103
2244
|
this.help({ error: true });
|
|
@@ -2116,7 +2257,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2116
2257
|
this._processArguments();
|
|
2117
2258
|
let promiseChain;
|
|
2118
2259
|
promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
|
|
2119
|
-
promiseChain = this._chainOrCall(
|
|
2260
|
+
promiseChain = this._chainOrCall(
|
|
2261
|
+
promiseChain,
|
|
2262
|
+
() => this._actionHandler(this.processedArgs)
|
|
2263
|
+
);
|
|
2120
2264
|
if (this.parent) {
|
|
2121
2265
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
2122
2266
|
this.parent.emit(commandEvent, operands, unknown);
|
|
@@ -2153,17 +2297,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2153
2297
|
* Find matching command.
|
|
2154
2298
|
*
|
|
2155
2299
|
* @private
|
|
2300
|
+
* @return {Command | undefined}
|
|
2156
2301
|
*/
|
|
2157
2302
|
_findCommand(name) {
|
|
2158
2303
|
if (!name) return void 0;
|
|
2159
|
-
return this.commands.find(
|
|
2304
|
+
return this.commands.find(
|
|
2305
|
+
(cmd) => cmd._name === name || cmd._aliases.includes(name)
|
|
2306
|
+
);
|
|
2160
2307
|
}
|
|
2161
2308
|
/**
|
|
2162
2309
|
* Return an option matching `arg` if any.
|
|
2163
2310
|
*
|
|
2164
2311
|
* @param {string} arg
|
|
2165
2312
|
* @return {Option}
|
|
2166
|
-
* @package
|
|
2313
|
+
* @package
|
|
2167
2314
|
*/
|
|
2168
2315
|
_findOption(arg) {
|
|
2169
2316
|
return this.options.find((option) => option.is(arg));
|
|
@@ -2189,15 +2336,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2189
2336
|
* @private
|
|
2190
2337
|
*/
|
|
2191
2338
|
_checkForConflictingLocalOptions() {
|
|
2192
|
-
const definedNonDefaultOptions = this.options.filter(
|
|
2193
|
-
(
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
return false;
|
|
2197
|
-
}
|
|
2198
|
-
return this.getOptionValueSource(optionKey) !== "default";
|
|
2339
|
+
const definedNonDefaultOptions = this.options.filter((option) => {
|
|
2340
|
+
const optionKey = option.attributeName();
|
|
2341
|
+
if (this.getOptionValue(optionKey) === void 0) {
|
|
2342
|
+
return false;
|
|
2199
2343
|
}
|
|
2200
|
-
|
|
2344
|
+
return this.getOptionValueSource(optionKey) !== "default";
|
|
2345
|
+
});
|
|
2201
2346
|
const optionsWithConflicting = definedNonDefaultOptions.filter(
|
|
2202
2347
|
(option) => option.conflictsWith.length > 0
|
|
2203
2348
|
);
|
|
@@ -2327,7 +2472,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2327
2472
|
/**
|
|
2328
2473
|
* Return an object containing local option values as key-value pairs.
|
|
2329
2474
|
*
|
|
2330
|
-
* @return {
|
|
2475
|
+
* @return {object}
|
|
2331
2476
|
*/
|
|
2332
2477
|
opts() {
|
|
2333
2478
|
if (this._storeOptionsAsProperties) {
|
|
@@ -2344,7 +2489,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2344
2489
|
/**
|
|
2345
2490
|
* Return an object containing merged local and global option values as key-value pairs.
|
|
2346
2491
|
*
|
|
2347
|
-
* @return {
|
|
2492
|
+
* @return {object}
|
|
2348
2493
|
*/
|
|
2349
2494
|
optsWithGlobals() {
|
|
2350
2495
|
return this._getCommandAndAncestors().reduce(
|
|
@@ -2356,13 +2501,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2356
2501
|
* Display error message and exit (or call exitOverride).
|
|
2357
2502
|
*
|
|
2358
2503
|
* @param {string} message
|
|
2359
|
-
* @param {
|
|
2504
|
+
* @param {object} [errorOptions]
|
|
2360
2505
|
* @param {string} [errorOptions.code] - an id string representing the error
|
|
2361
2506
|
* @param {number} [errorOptions.exitCode] - used with process.exit
|
|
2362
2507
|
*/
|
|
2363
2508
|
error(message, errorOptions) {
|
|
2364
|
-
this._outputConfiguration.outputError(
|
|
2365
|
-
|
|
2509
|
+
this._outputConfiguration.outputError(
|
|
2510
|
+
`${message}
|
|
2511
|
+
`,
|
|
2512
|
+
this._outputConfiguration.writeErr
|
|
2513
|
+
);
|
|
2366
2514
|
if (typeof this._showHelpAfterError === "string") {
|
|
2367
2515
|
this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
2368
2516
|
`);
|
|
@@ -2385,7 +2533,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2385
2533
|
this.options.forEach((option) => {
|
|
2386
2534
|
if (option.envVar && option.envVar in process2.env) {
|
|
2387
2535
|
const optionKey = option.attributeName();
|
|
2388
|
-
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
2536
|
+
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
2537
|
+
this.getOptionValueSource(optionKey)
|
|
2538
|
+
)) {
|
|
2389
2539
|
if (option.required || option.optional) {
|
|
2390
2540
|
this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
|
|
2391
2541
|
} else {
|
|
@@ -2405,9 +2555,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2405
2555
|
const hasCustomOptionValue = (optionKey) => {
|
|
2406
2556
|
return this.getOptionValue(optionKey) !== void 0 && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
|
|
2407
2557
|
};
|
|
2408
|
-
this.options.filter(
|
|
2558
|
+
this.options.filter(
|
|
2559
|
+
(option) => option.implied !== void 0 && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(
|
|
2560
|
+
this.getOptionValue(option.attributeName()),
|
|
2561
|
+
option
|
|
2562
|
+
)
|
|
2563
|
+
).forEach((option) => {
|
|
2409
2564
|
Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
|
|
2410
|
-
this.setOptionValueWithSource(
|
|
2565
|
+
this.setOptionValueWithSource(
|
|
2566
|
+
impliedKey,
|
|
2567
|
+
option.implied[impliedKey],
|
|
2568
|
+
"implied"
|
|
2569
|
+
);
|
|
2411
2570
|
});
|
|
2412
2571
|
});
|
|
2413
2572
|
}
|
|
@@ -2452,8 +2611,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2452
2611
|
const findBestOptionFromValue = (option2) => {
|
|
2453
2612
|
const optionKey = option2.attributeName();
|
|
2454
2613
|
const optionValue = this.getOptionValue(optionKey);
|
|
2455
|
-
const negativeOption = this.options.find(
|
|
2456
|
-
|
|
2614
|
+
const negativeOption = this.options.find(
|
|
2615
|
+
(target) => target.negate && optionKey === target.attributeName()
|
|
2616
|
+
);
|
|
2617
|
+
const positiveOption = this.options.find(
|
|
2618
|
+
(target) => !target.negate && optionKey === target.attributeName()
|
|
2619
|
+
);
|
|
2457
2620
|
if (negativeOption && (negativeOption.presetArg === void 0 && optionValue === false || negativeOption.presetArg !== void 0 && optionValue === negativeOption.presetArg)) {
|
|
2458
2621
|
return negativeOption;
|
|
2459
2622
|
}
|
|
@@ -2557,11 +2720,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2557
2720
|
* Set the description.
|
|
2558
2721
|
*
|
|
2559
2722
|
* @param {string} [str]
|
|
2560
|
-
* @param {
|
|
2723
|
+
* @param {object} [argsDescription]
|
|
2561
2724
|
* @return {(string|Command)}
|
|
2562
2725
|
*/
|
|
2563
2726
|
description(str, argsDescription) {
|
|
2564
|
-
if (str === void 0 && argsDescription === void 0)
|
|
2727
|
+
if (str === void 0 && argsDescription === void 0)
|
|
2728
|
+
return this._description;
|
|
2565
2729
|
this._description = str;
|
|
2566
2730
|
if (argsDescription) {
|
|
2567
2731
|
this._argsDescription = argsDescription;
|
|
@@ -2593,11 +2757,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2593
2757
|
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
|
|
2594
2758
|
command = this.commands[this.commands.length - 1];
|
|
2595
2759
|
}
|
|
2596
|
-
if (alias === command._name)
|
|
2760
|
+
if (alias === command._name)
|
|
2761
|
+
throw new Error("Command alias can't be the same as its name");
|
|
2597
2762
|
const matchingCommand = this.parent?._findCommand(alias);
|
|
2598
2763
|
if (matchingCommand) {
|
|
2599
2764
|
const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
|
|
2600
|
-
throw new Error(
|
|
2765
|
+
throw new Error(
|
|
2766
|
+
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`
|
|
2767
|
+
);
|
|
2601
2768
|
}
|
|
2602
2769
|
command._aliases.push(alias);
|
|
2603
2770
|
return this;
|
|
@@ -2660,7 +2827,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2660
2827
|
* @return {Command}
|
|
2661
2828
|
*/
|
|
2662
2829
|
nameFromFilename(filename) {
|
|
2663
|
-
this._name =
|
|
2830
|
+
this._name = path11.basename(filename, path11.extname(filename));
|
|
2664
2831
|
return this;
|
|
2665
2832
|
}
|
|
2666
2833
|
/**
|
|
@@ -2674,9 +2841,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2674
2841
|
* @param {string} [path]
|
|
2675
2842
|
* @return {(string|null|Command)}
|
|
2676
2843
|
*/
|
|
2677
|
-
executableDir(
|
|
2678
|
-
if (
|
|
2679
|
-
this._executableDir =
|
|
2844
|
+
executableDir(path12) {
|
|
2845
|
+
if (path12 === void 0) return this._executableDir;
|
|
2846
|
+
this._executableDir = path12;
|
|
2680
2847
|
return this;
|
|
2681
2848
|
}
|
|
2682
2849
|
/**
|
|
@@ -2736,7 +2903,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2736
2903
|
this.emit(this._getHelpOption().long);
|
|
2737
2904
|
}
|
|
2738
2905
|
this.emit("afterHelp", context2);
|
|
2739
|
-
this._getCommandAndAncestors().forEach(
|
|
2906
|
+
this._getCommandAndAncestors().forEach(
|
|
2907
|
+
(command) => command.emit("afterAllHelp", context2)
|
|
2908
|
+
);
|
|
2740
2909
|
}
|
|
2741
2910
|
/**
|
|
2742
2911
|
* You can pass in flags and a description to customise the built-in help option.
|
|
@@ -2769,7 +2938,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2769
2938
|
* Returns null if has been disabled with .helpOption(false).
|
|
2770
2939
|
*
|
|
2771
2940
|
* @returns {(Option | null)} the help option
|
|
2772
|
-
* @package
|
|
2941
|
+
* @package
|
|
2773
2942
|
*/
|
|
2774
2943
|
_getHelpOption() {
|
|
2775
2944
|
if (this._helpOption === void 0) {
|
|
@@ -2904,6 +3073,557 @@ var require_commander = __commonJS({
|
|
|
2904
3073
|
}
|
|
2905
3074
|
});
|
|
2906
3075
|
|
|
3076
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_arm64_127.node
|
|
3077
|
+
var require_uws_darwin_arm64_127 = __commonJS({
|
|
3078
|
+
"../../node_modules/uWebSockets.js/uws_darwin_arm64_127.node"(exports, module) {
|
|
3079
|
+
module.exports = "./uws_darwin_arm64_127-NGHTXN5Q.node";
|
|
3080
|
+
}
|
|
3081
|
+
});
|
|
3082
|
+
|
|
3083
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_arm64_137.node
|
|
3084
|
+
var require_uws_darwin_arm64_137 = __commonJS({
|
|
3085
|
+
"../../node_modules/uWebSockets.js/uws_darwin_arm64_137.node"(exports, module) {
|
|
3086
|
+
module.exports = "./uws_darwin_arm64_137-ESY6MPLH.node";
|
|
3087
|
+
}
|
|
3088
|
+
});
|
|
3089
|
+
|
|
3090
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_arm64_147.node
|
|
3091
|
+
var require_uws_darwin_arm64_147 = __commonJS({
|
|
3092
|
+
"../../node_modules/uWebSockets.js/uws_darwin_arm64_147.node"(exports, module) {
|
|
3093
|
+
module.exports = "./uws_darwin_arm64_147-V7BKA3SU.node";
|
|
3094
|
+
}
|
|
3095
|
+
});
|
|
3096
|
+
|
|
3097
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_x64_127.node
|
|
3098
|
+
var require_uws_darwin_x64_127 = __commonJS({
|
|
3099
|
+
"../../node_modules/uWebSockets.js/uws_darwin_x64_127.node"(exports, module) {
|
|
3100
|
+
module.exports = "./uws_darwin_x64_127-WIZGG7MS.node";
|
|
3101
|
+
}
|
|
3102
|
+
});
|
|
3103
|
+
|
|
3104
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_x64_137.node
|
|
3105
|
+
var require_uws_darwin_x64_137 = __commonJS({
|
|
3106
|
+
"../../node_modules/uWebSockets.js/uws_darwin_x64_137.node"(exports, module) {
|
|
3107
|
+
module.exports = "./uws_darwin_x64_137-APKZWL4Y.node";
|
|
3108
|
+
}
|
|
3109
|
+
});
|
|
3110
|
+
|
|
3111
|
+
// ../../node_modules/uWebSockets.js/uws_darwin_x64_147.node
|
|
3112
|
+
var require_uws_darwin_x64_147 = __commonJS({
|
|
3113
|
+
"../../node_modules/uWebSockets.js/uws_darwin_x64_147.node"(exports, module) {
|
|
3114
|
+
module.exports = "./uws_darwin_x64_147-W2HKFQZT.node";
|
|
3115
|
+
}
|
|
3116
|
+
});
|
|
3117
|
+
|
|
3118
|
+
// ../../node_modules/uWebSockets.js/uws_linux_arm64_127.node
|
|
3119
|
+
var require_uws_linux_arm64_127 = __commonJS({
|
|
3120
|
+
"../../node_modules/uWebSockets.js/uws_linux_arm64_127.node"(exports, module) {
|
|
3121
|
+
module.exports = "./uws_linux_arm64_127-3CO7NSFJ.node";
|
|
3122
|
+
}
|
|
3123
|
+
});
|
|
3124
|
+
|
|
3125
|
+
// ../../node_modules/uWebSockets.js/uws_linux_arm64_137.node
|
|
3126
|
+
var require_uws_linux_arm64_137 = __commonJS({
|
|
3127
|
+
"../../node_modules/uWebSockets.js/uws_linux_arm64_137.node"(exports, module) {
|
|
3128
|
+
module.exports = "./uws_linux_arm64_137-HWEDGGZV.node";
|
|
3129
|
+
}
|
|
3130
|
+
});
|
|
3131
|
+
|
|
3132
|
+
// ../../node_modules/uWebSockets.js/uws_linux_arm64_147.node
|
|
3133
|
+
var require_uws_linux_arm64_147 = __commonJS({
|
|
3134
|
+
"../../node_modules/uWebSockets.js/uws_linux_arm64_147.node"(exports, module) {
|
|
3135
|
+
module.exports = "./uws_linux_arm64_147-7UCIYMK2.node";
|
|
3136
|
+
}
|
|
3137
|
+
});
|
|
3138
|
+
|
|
3139
|
+
// ../../node_modules/uWebSockets.js/uws_linux_x64_127.node
|
|
3140
|
+
var require_uws_linux_x64_127 = __commonJS({
|
|
3141
|
+
"../../node_modules/uWebSockets.js/uws_linux_x64_127.node"(exports, module) {
|
|
3142
|
+
module.exports = "./uws_linux_x64_127-KA4E76LJ.node";
|
|
3143
|
+
}
|
|
3144
|
+
});
|
|
3145
|
+
|
|
3146
|
+
// ../../node_modules/uWebSockets.js/uws_linux_x64_137.node
|
|
3147
|
+
var require_uws_linux_x64_137 = __commonJS({
|
|
3148
|
+
"../../node_modules/uWebSockets.js/uws_linux_x64_137.node"(exports, module) {
|
|
3149
|
+
module.exports = "./uws_linux_x64_137-DDFLTTJR.node";
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
|
|
3153
|
+
// ../../node_modules/uWebSockets.js/uws_linux_x64_147.node
|
|
3154
|
+
var require_uws_linux_x64_147 = __commonJS({
|
|
3155
|
+
"../../node_modules/uWebSockets.js/uws_linux_x64_147.node"(exports, module) {
|
|
3156
|
+
module.exports = "./uws_linux_x64_147-MJSFREL3.node";
|
|
3157
|
+
}
|
|
3158
|
+
});
|
|
3159
|
+
|
|
3160
|
+
// ../../node_modules/uWebSockets.js/uws_win32_x64_127.node
|
|
3161
|
+
var require_uws_win32_x64_127 = __commonJS({
|
|
3162
|
+
"../../node_modules/uWebSockets.js/uws_win32_x64_127.node"(exports, module) {
|
|
3163
|
+
module.exports = "./uws_win32_x64_127-O4US4Y4L.node";
|
|
3164
|
+
}
|
|
3165
|
+
});
|
|
3166
|
+
|
|
3167
|
+
// ../../node_modules/uWebSockets.js/uws_win32_x64_137.node
|
|
3168
|
+
var require_uws_win32_x64_137 = __commonJS({
|
|
3169
|
+
"../../node_modules/uWebSockets.js/uws_win32_x64_137.node"(exports, module) {
|
|
3170
|
+
module.exports = "./uws_win32_x64_137-L5OZROQ7.node";
|
|
3171
|
+
}
|
|
3172
|
+
});
|
|
3173
|
+
|
|
3174
|
+
// ../../node_modules/uWebSockets.js/uws_win32_x64_147.node
|
|
3175
|
+
var require_uws_win32_x64_147 = __commonJS({
|
|
3176
|
+
"../../node_modules/uWebSockets.js/uws_win32_x64_147.node"(exports, module) {
|
|
3177
|
+
module.exports = "./uws_win32_x64_147-D7MGKVRG.node";
|
|
3178
|
+
}
|
|
3179
|
+
});
|
|
3180
|
+
|
|
3181
|
+
// require("./uws_*_*_*.node") in ../../node_modules/uWebSockets.js/uws.js
|
|
3182
|
+
var globRequire_uws______node;
|
|
3183
|
+
var init_ = __esm({
|
|
3184
|
+
'require("./uws_*_*_*.node") in ../../node_modules/uWebSockets.js/uws.js'() {
|
|
3185
|
+
globRequire_uws______node = __glob({
|
|
3186
|
+
"./uws_darwin_arm64_127.node": () => require_uws_darwin_arm64_127(),
|
|
3187
|
+
"./uws_darwin_arm64_137.node": () => require_uws_darwin_arm64_137(),
|
|
3188
|
+
"./uws_darwin_arm64_147.node": () => require_uws_darwin_arm64_147(),
|
|
3189
|
+
"./uws_darwin_x64_127.node": () => require_uws_darwin_x64_127(),
|
|
3190
|
+
"./uws_darwin_x64_137.node": () => require_uws_darwin_x64_137(),
|
|
3191
|
+
"./uws_darwin_x64_147.node": () => require_uws_darwin_x64_147(),
|
|
3192
|
+
"./uws_linux_arm64_127.node": () => require_uws_linux_arm64_127(),
|
|
3193
|
+
"./uws_linux_arm64_137.node": () => require_uws_linux_arm64_137(),
|
|
3194
|
+
"./uws_linux_arm64_147.node": () => require_uws_linux_arm64_147(),
|
|
3195
|
+
"./uws_linux_x64_127.node": () => require_uws_linux_x64_127(),
|
|
3196
|
+
"./uws_linux_x64_137.node": () => require_uws_linux_x64_137(),
|
|
3197
|
+
"./uws_linux_x64_147.node": () => require_uws_linux_x64_147(),
|
|
3198
|
+
"./uws_win32_x64_127.node": () => require_uws_win32_x64_127(),
|
|
3199
|
+
"./uws_win32_x64_137.node": () => require_uws_win32_x64_137(),
|
|
3200
|
+
"./uws_win32_x64_147.node": () => require_uws_win32_x64_147()
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
});
|
|
3204
|
+
|
|
3205
|
+
// ../../node_modules/uWebSockets.js/uws.js
|
|
3206
|
+
var require_uws = __commonJS({
|
|
3207
|
+
"../../node_modules/uWebSockets.js/uws.js"(exports, module) {
|
|
3208
|
+
init_();
|
|
3209
|
+
module.exports = (() => {
|
|
3210
|
+
try {
|
|
3211
|
+
return globRequire_uws______node("./uws_" + process.platform + "_" + process.arch + "_" + process.versions.modules + ".node");
|
|
3212
|
+
} catch (e) {
|
|
3213
|
+
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());
|
|
3214
|
+
}
|
|
3215
|
+
})();
|
|
3216
|
+
var MAX_U8 = Math.pow(2, 8) - 1;
|
|
3217
|
+
var MAX_U16 = Math.pow(2, 16) - 1;
|
|
3218
|
+
var textEncoder = new TextEncoder();
|
|
3219
|
+
var toUint8Array = (value) => {
|
|
3220
|
+
if (value === void 0) return new Uint8Array(0);
|
|
3221
|
+
else if (typeof value === "string") return textEncoder.encode(value);
|
|
3222
|
+
else if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
3223
|
+
else if (value instanceof SharedArrayBuffer) return new Uint8Array(value);
|
|
3224
|
+
else return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
3225
|
+
};
|
|
3226
|
+
module.exports.DeclarativeResponse = class DeclarativeResponse {
|
|
3227
|
+
constructor() {
|
|
3228
|
+
this.instructions = [];
|
|
3229
|
+
}
|
|
3230
|
+
// Append instruction and 1-byte length values
|
|
3231
|
+
_appendInstruction(opcode, ...values) {
|
|
3232
|
+
this.instructions.push(opcode);
|
|
3233
|
+
values.forEach((value) => {
|
|
3234
|
+
const uint8Array = toUint8Array(value);
|
|
3235
|
+
if (uint8Array.byteLength > MAX_U8) throw new RangeError("Data length exceeds " + MAX_U8);
|
|
3236
|
+
this.instructions.push(uint8Array.byteLength, ...uint8Array);
|
|
3237
|
+
});
|
|
3238
|
+
}
|
|
3239
|
+
// Append instruction and 2-byte length value
|
|
3240
|
+
_appendInstructionWithLength(opcode, value) {
|
|
3241
|
+
const uint8Array = toUint8Array(value);
|
|
3242
|
+
if (uint8Array.byteLength > MAX_U16) throw new RangeError("Data length exceeds " + MAX_U16);
|
|
3243
|
+
this.instructions.push(opcode, uint8Array.byteLength & 255, uint8Array.byteLength >> 8 & 255, ...uint8Array);
|
|
3244
|
+
}
|
|
3245
|
+
writeHeader(key, value) {
|
|
3246
|
+
return this._appendInstruction(1, key, value), this;
|
|
3247
|
+
}
|
|
3248
|
+
writeBody() {
|
|
3249
|
+
return this.instructions.push(2), this;
|
|
3250
|
+
}
|
|
3251
|
+
writeQueryValue(key) {
|
|
3252
|
+
return this._appendInstruction(3, key), this;
|
|
3253
|
+
}
|
|
3254
|
+
writeHeaderValue(key) {
|
|
3255
|
+
return this._appendInstruction(4, key), this;
|
|
3256
|
+
}
|
|
3257
|
+
write(value) {
|
|
3258
|
+
return this._appendInstructionWithLength(5, value), this;
|
|
3259
|
+
}
|
|
3260
|
+
writeParameterValue(key) {
|
|
3261
|
+
return this._appendInstruction(6, key), this;
|
|
3262
|
+
}
|
|
3263
|
+
writeStatus(status) {
|
|
3264
|
+
return this._appendInstruction(7, status), this;
|
|
3265
|
+
}
|
|
3266
|
+
end(value) {
|
|
3267
|
+
this._appendInstructionWithLength(0, value);
|
|
3268
|
+
return new Uint8Array(this.instructions).buffer;
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
}
|
|
3272
|
+
});
|
|
3273
|
+
|
|
3274
|
+
// ../openapi/dist/index.mjs
|
|
3275
|
+
var dist_exports = {};
|
|
3276
|
+
__export(dist_exports, {
|
|
3277
|
+
OpenApiGenerator: () => OpenApiGenerator,
|
|
3278
|
+
Security: () => Security,
|
|
3279
|
+
defineSecuritySchemes: () => defineSecuritySchemes,
|
|
3280
|
+
useOpenAPI: () => useOpenAPI
|
|
3281
|
+
});
|
|
3282
|
+
function zodSchemaToOpenApi(schema) {
|
|
3283
|
+
const s = schema;
|
|
3284
|
+
if (typeof s.toJSONSchema === "function") {
|
|
3285
|
+
const full = s.toJSONSchema({ target: "openApi3_1" });
|
|
3286
|
+
const { $schema: _dropped, ...rest } = full;
|
|
3287
|
+
return rest;
|
|
3288
|
+
}
|
|
3289
|
+
try {
|
|
3290
|
+
const { zodToJsonSchema } = __require2("zod-to-json-schema");
|
|
3291
|
+
return zodToJsonSchema(schema, { target: "openApi3" });
|
|
3292
|
+
} catch {
|
|
3293
|
+
return { type: "object" };
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
function isZodSchema(value) {
|
|
3297
|
+
return typeof value === "object" && value !== null && typeof value.safeParse === "function";
|
|
3298
|
+
}
|
|
3299
|
+
function escapeHtml(s) {
|
|
3300
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3301
|
+
}
|
|
3302
|
+
function escapeJsString(s) {
|
|
3303
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
3304
|
+
}
|
|
3305
|
+
function defineSecuritySchemes(schemes) {
|
|
3306
|
+
return {
|
|
3307
|
+
schemes,
|
|
3308
|
+
require: (name, scopes = []) => [{ [name]: scopes }],
|
|
3309
|
+
requireMultiple: (requirements) => {
|
|
3310
|
+
const combined = {};
|
|
3311
|
+
requirements.forEach((req) => {
|
|
3312
|
+
combined[req] = [];
|
|
3313
|
+
});
|
|
3314
|
+
return [combined];
|
|
3315
|
+
}
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
function inferSchemaFromPayload(data, depth = 0) {
|
|
3319
|
+
if (depth > 32) return { type: "object" };
|
|
3320
|
+
if (data === null) return { type: "null" };
|
|
3321
|
+
if (Array.isArray(data)) {
|
|
3322
|
+
return {
|
|
3323
|
+
type: "array",
|
|
3324
|
+
items: data.length > 0 ? inferSchemaFromPayload(data[0], depth + 1) : { type: "object" }
|
|
3325
|
+
};
|
|
3326
|
+
}
|
|
3327
|
+
if (typeof data === "object") {
|
|
3328
|
+
const properties = {};
|
|
3329
|
+
for (const [key, value] of Object.entries(data)) {
|
|
3330
|
+
properties[key] = inferSchemaFromPayload(value, depth + 1);
|
|
3331
|
+
}
|
|
3332
|
+
return { type: "object", properties };
|
|
3333
|
+
}
|
|
3334
|
+
return { type: typeof data };
|
|
3335
|
+
}
|
|
3336
|
+
function useOpenAPI(app, options) {
|
|
3337
|
+
const rawPrefix = options.prefix ?? "/docs";
|
|
3338
|
+
const normalizedPrefix = rawPrefix.startsWith("/") ? rawPrefix : `/${rawPrefix}`;
|
|
3339
|
+
const prefix = normalizedPrefix === "/" ? "/" : normalizedPrefix.endsWith("/") ? normalizedPrefix.slice(0, -1) : normalizedPrefix;
|
|
3340
|
+
const docsPaths = prefix === "/" ? ["/"] : [prefix, `${prefix}/`];
|
|
3341
|
+
const docsPathSet = new Set(docsPaths);
|
|
3342
|
+
const specPath = prefix === "/" ? "/openapi.json" : `${prefix}/openapi.json`;
|
|
3343
|
+
const generator = new OpenApiGenerator(app, options);
|
|
3344
|
+
let cachedSpec = null;
|
|
3345
|
+
let cachedSpecJson = null;
|
|
3346
|
+
let emittedPublicDocsWarning = false;
|
|
3347
|
+
if (options.autoInferResponses) {
|
|
3348
|
+
app.addHook("onPostHandler", (req, res, match) => {
|
|
3349
|
+
if (!match?.route) return;
|
|
3350
|
+
if (req.path === specPath || docsPathSet.has(req.path)) {
|
|
3351
|
+
return;
|
|
3352
|
+
}
|
|
3353
|
+
const payload = res.payload;
|
|
3354
|
+
if (payload === void 0) return;
|
|
3355
|
+
if (!cachedSpec) cachedSpec = generator.generate();
|
|
3356
|
+
const path11 = generator.formatPath(match.route.path);
|
|
3357
|
+
const method = match.route.method.toLowerCase();
|
|
3358
|
+
const statusCode = String(res.statusCode);
|
|
3359
|
+
const existingResponse = cachedSpec.paths[path11]?.[method]?.responses?.[statusCode];
|
|
3360
|
+
const isDefault = existingResponse?.description === "Successful response" && existingResponse?.content?.["application/json"]?.schema?.type === "object";
|
|
3361
|
+
if (existingResponse && !isDefault) return;
|
|
3362
|
+
let parsedData = payload;
|
|
3363
|
+
if (typeof payload === "string") {
|
|
3364
|
+
try {
|
|
3365
|
+
parsedData = JSON.parse(payload);
|
|
3366
|
+
} catch {
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
if (cachedSpec.paths[path11]?.[method]) {
|
|
3370
|
+
cachedSpec.paths[path11][method].responses[statusCode] = {
|
|
3371
|
+
description: "Auto-inferred response",
|
|
3372
|
+
content: {
|
|
3373
|
+
"application/json": { schema: inferSchemaFromPayload(parsedData) }
|
|
3374
|
+
}
|
|
3375
|
+
};
|
|
3376
|
+
cachedSpecJson = null;
|
|
3377
|
+
}
|
|
3378
|
+
});
|
|
3379
|
+
}
|
|
3380
|
+
const guard = async (req) => {
|
|
3381
|
+
if (!options.protect) {
|
|
3382
|
+
if (process.env.NODE_ENV === "production") {
|
|
3383
|
+
if (!emittedPublicDocsWarning) {
|
|
3384
|
+
emittedPublicDocsWarning = true;
|
|
3385
|
+
console.warn(
|
|
3386
|
+
"[axiomify/openapi] OpenAPI endpoints are not protected. Production access is denied by default. Provide a `protect` function or set `allowPublicInProduction: true` explicitly."
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
return options.allowPublicInProduction === true;
|
|
3390
|
+
}
|
|
3391
|
+
return true;
|
|
3392
|
+
}
|
|
3393
|
+
return Boolean(await options.protect(req));
|
|
3394
|
+
};
|
|
3395
|
+
app.route({
|
|
3396
|
+
method: "GET",
|
|
3397
|
+
path: specPath,
|
|
3398
|
+
handler: async (req, res) => {
|
|
3399
|
+
if (!await guard(req)) return res.status(403).send(null, "Forbidden");
|
|
3400
|
+
if (!cachedSpec) cachedSpec = generator.generate();
|
|
3401
|
+
if (!cachedSpecJson) cachedSpecJson = JSON.stringify(cachedSpec);
|
|
3402
|
+
res.status(200).sendRaw(cachedSpecJson, "application/json");
|
|
3403
|
+
}
|
|
3404
|
+
});
|
|
3405
|
+
const docsHandler = async (req, res) => {
|
|
3406
|
+
if (!await guard(req)) return res.status(403).send(null, "Forbidden");
|
|
3407
|
+
if (typeof res.setHeader === "function") {
|
|
3408
|
+
res.setHeader("Content-Security-Policy", DOCS_CSP);
|
|
3409
|
+
} else if (typeof res.header === "function") {
|
|
3410
|
+
res.header("Content-Security-Policy", DOCS_CSP);
|
|
3411
|
+
}
|
|
3412
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
3413
|
+
const specUrl = isDev ? `${specPath}?t=${Date.now()}` : specPath;
|
|
3414
|
+
const html = `<!DOCTYPE html>
|
|
3415
|
+
<html lang="en">
|
|
3416
|
+
<head>
|
|
3417
|
+
<meta charset="utf-8" />
|
|
3418
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
3419
|
+
<title>${escapeHtml(options.info.title)} - API Docs</title>
|
|
3420
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.11.0/swagger-ui.min.css" integrity="sha384-bIuUyBV7i6P7z/kPAs1oeBIf8PMIqVkPVDzzaOL+QH7kWmvCT9HDTWwGVs0L4/9Q" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
3421
|
+
</head>
|
|
3422
|
+
<body style="margin: 0; padding: 0;">
|
|
3423
|
+
<div id="swagger-ui"></div>
|
|
3424
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.11.0/swagger-ui-bundle.min.js" integrity="sha384-XHDYRdiHvBq7oL4CtkiJKfdVVA5PydxYtssHVtRrvPlha1m+zz8kboiyx/MAsyl3" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
3425
|
+
<script>
|
|
3426
|
+
window.onload = () => {
|
|
3427
|
+
window.ui = SwaggerUIBundle({
|
|
3428
|
+
url: '${escapeJsString(specUrl)}',
|
|
3429
|
+
dom_id: '#swagger-ui',
|
|
3430
|
+
});
|
|
3431
|
+
};
|
|
3432
|
+
</script>
|
|
3433
|
+
</body>
|
|
3434
|
+
</html>`;
|
|
3435
|
+
res.status(200).sendRaw(html, "text/html");
|
|
3436
|
+
};
|
|
3437
|
+
app.route({
|
|
3438
|
+
method: "GET",
|
|
3439
|
+
path: prefix,
|
|
3440
|
+
handler: docsHandler
|
|
3441
|
+
});
|
|
3442
|
+
}
|
|
3443
|
+
var __require2, OpenApiGenerator, DOCS_CSP, Security;
|
|
3444
|
+
var init_dist = __esm({
|
|
3445
|
+
"../openapi/dist/index.mjs"() {
|
|
3446
|
+
__require2 = /* @__PURE__ */ ((x) => typeof __require !== "undefined" ? __require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3447
|
+
get: (a, b) => (typeof __require !== "undefined" ? __require : a)[b]
|
|
3448
|
+
}) : x)(function(x) {
|
|
3449
|
+
if (typeof __require !== "undefined") return __require.apply(this, arguments);
|
|
3450
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
3451
|
+
});
|
|
3452
|
+
OpenApiGenerator = class {
|
|
3453
|
+
constructor(app, options) {
|
|
3454
|
+
this.app = app;
|
|
3455
|
+
this.options = options;
|
|
3456
|
+
}
|
|
3457
|
+
app;
|
|
3458
|
+
options;
|
|
3459
|
+
generate() {
|
|
3460
|
+
const spec = {
|
|
3461
|
+
openapi: "3.1.0",
|
|
3462
|
+
info: this.options.info,
|
|
3463
|
+
paths: {}
|
|
3464
|
+
};
|
|
3465
|
+
if (this.options.components) spec.components = this.options.components;
|
|
3466
|
+
if (this.options.security) spec.security = this.options.security;
|
|
3467
|
+
for (const route of this.app.registeredRoutes) {
|
|
3468
|
+
const openApiPath = this.formatPath(route.path);
|
|
3469
|
+
const method = route.method.toLowerCase();
|
|
3470
|
+
const paths = spec.paths;
|
|
3471
|
+
if (!paths[openApiPath]) paths[openApiPath] = {};
|
|
3472
|
+
const s = route.schema ?? {};
|
|
3473
|
+
const operation = {
|
|
3474
|
+
// OAS §4.8.10.2 — summary. Defaults to `${method} ${path}`.
|
|
3475
|
+
summary: s.summary ?? `${route.method} ${route.path}`,
|
|
3476
|
+
// OAS §4.8.10.5 — operationId for client codegen tools.
|
|
3477
|
+
// Auto-synthesised from method+path when omitted:
|
|
3478
|
+
// GET /users/:id → "getUsersById" POST /users → "postUsers"
|
|
3479
|
+
operationId: s.operationId ?? this.synthesiseOperationId(route.method, route.path),
|
|
3480
|
+
parameters: this.extractParameters(route),
|
|
3481
|
+
responses: this.extractResponses(route)
|
|
3482
|
+
};
|
|
3483
|
+
if (s.description) operation.description = s.description;
|
|
3484
|
+
if (s.tags) operation.tags = s.tags;
|
|
3485
|
+
if (s.security !== void 0) operation.security = s.security;
|
|
3486
|
+
if (s.deprecated) operation.deprecated = true;
|
|
3487
|
+
if (s.externalDocs) operation.externalDocs = s.externalDocs;
|
|
3488
|
+
if (s.servers) operation.servers = s.servers;
|
|
3489
|
+
if (s.callbacks) operation.callbacks = s.callbacks;
|
|
3490
|
+
const body = this.extractBody(route);
|
|
3491
|
+
if (body) {
|
|
3492
|
+
if (s.requestBodyDescription) body.description = s.requestBodyDescription;
|
|
3493
|
+
operation.requestBody = body;
|
|
3494
|
+
}
|
|
3495
|
+
paths[openApiPath][method] = operation;
|
|
3496
|
+
}
|
|
3497
|
+
return spec;
|
|
3498
|
+
}
|
|
3499
|
+
/** Translates Axiomify path syntax to OpenAPI: `/users/:id` → `/users/{id}` */
|
|
3500
|
+
formatPath(path11) {
|
|
3501
|
+
return path11.replace(/:([a-zA-Z0-9_]+)/g, "{$1}");
|
|
3502
|
+
}
|
|
3503
|
+
extractParameters(route) {
|
|
3504
|
+
const parameters = [];
|
|
3505
|
+
if (route.schema?.params) {
|
|
3506
|
+
const paramSchema = zodSchemaToOpenApi(route.schema.params);
|
|
3507
|
+
const properties = paramSchema.properties ?? {};
|
|
3508
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
3509
|
+
parameters.push({ name: key, in: "path", required: true, schema: prop });
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
if (route.schema?.query) {
|
|
3513
|
+
const querySchema = zodSchemaToOpenApi(route.schema.query);
|
|
3514
|
+
const properties = querySchema.properties ?? {};
|
|
3515
|
+
const required = querySchema.required ?? [];
|
|
3516
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
3517
|
+
parameters.push({
|
|
3518
|
+
name: key,
|
|
3519
|
+
in: "query",
|
|
3520
|
+
required: required.includes(key),
|
|
3521
|
+
schema: prop
|
|
3522
|
+
});
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
return parameters;
|
|
3526
|
+
}
|
|
3527
|
+
/**
|
|
3528
|
+
* Synthesise a stable, codegen-friendly operationId from method+path
|
|
3529
|
+
* when the route definition doesn't supply one. Example outputs:
|
|
3530
|
+
* GET /users/:id → getUsersById
|
|
3531
|
+
* POST /users → postUsers
|
|
3532
|
+
* GET /users/:id/posts/:pid → getUsersByIdPostsByPid
|
|
3533
|
+
*
|
|
3534
|
+
* Determinism matters here — client codegen produces the same function
|
|
3535
|
+
* names on every run as long as method+path are stable.
|
|
3536
|
+
*/
|
|
3537
|
+
synthesiseOperationId(method, path11) {
|
|
3538
|
+
const verb = method.toLowerCase();
|
|
3539
|
+
const parts = [];
|
|
3540
|
+
for (const seg of path11.split("/")) {
|
|
3541
|
+
if (!seg) continue;
|
|
3542
|
+
if (seg.startsWith(":")) {
|
|
3543
|
+
const name = seg.slice(1);
|
|
3544
|
+
parts.push("By", name.charAt(0).toUpperCase() + name.slice(1));
|
|
3545
|
+
} else if (seg === "*") {
|
|
3546
|
+
parts.push("All");
|
|
3547
|
+
} else {
|
|
3548
|
+
parts.push(seg.charAt(0).toUpperCase() + seg.slice(1));
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
return verb + parts.join("");
|
|
3552
|
+
}
|
|
3553
|
+
extractBody(route) {
|
|
3554
|
+
if (!route.schema?.body && !route.schema?.files) return void 0;
|
|
3555
|
+
const hasFiles = !!route.schema.files;
|
|
3556
|
+
const contentType = hasFiles ? "multipart/form-data" : "application/json";
|
|
3557
|
+
let finalSchema = { type: "object", properties: {} };
|
|
3558
|
+
if (route.schema.body) {
|
|
3559
|
+
const bodySchema = zodSchemaToOpenApi(route.schema.body);
|
|
3560
|
+
if (bodySchema.type === "object") {
|
|
3561
|
+
finalSchema.properties = { ...bodySchema.properties };
|
|
3562
|
+
if (bodySchema.required) finalSchema.required = bodySchema.required;
|
|
3563
|
+
if (bodySchema.additionalProperties !== void 0) {
|
|
3564
|
+
finalSchema.additionalProperties = bodySchema.additionalProperties;
|
|
3565
|
+
}
|
|
3566
|
+
} else {
|
|
3567
|
+
finalSchema = hasFiles ? { type: "object", properties: { payload: bodySchema } } : bodySchema;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
if (hasFiles) {
|
|
3571
|
+
const files = route.schema.files;
|
|
3572
|
+
const props = finalSchema.properties ?? {};
|
|
3573
|
+
for (const [fieldName, config] of Object.entries(files)) {
|
|
3574
|
+
props[fieldName] = {
|
|
3575
|
+
type: "string",
|
|
3576
|
+
format: "binary",
|
|
3577
|
+
...config.description ? { description: config.description } : {},
|
|
3578
|
+
...config.maxSize ? { description: `Max size: ${config.maxSize} bytes` } : {}
|
|
3579
|
+
};
|
|
3580
|
+
}
|
|
3581
|
+
finalSchema.properties = props;
|
|
3582
|
+
}
|
|
3583
|
+
return { required: true, content: { [contentType]: { schema: finalSchema } } };
|
|
3584
|
+
}
|
|
3585
|
+
extractResponses(route) {
|
|
3586
|
+
const descriptions = route.schema?.responseDescriptions ?? {};
|
|
3587
|
+
const defaultResponse = {
|
|
3588
|
+
"200": {
|
|
3589
|
+
description: descriptions["200"] ?? "Successful response",
|
|
3590
|
+
content: { "application/json": { schema: { type: "object" } } }
|
|
3591
|
+
}
|
|
3592
|
+
};
|
|
3593
|
+
if (!route.schema?.response) return defaultResponse;
|
|
3594
|
+
const responseSchema = route.schema.response;
|
|
3595
|
+
const responses = {};
|
|
3596
|
+
if (isZodSchema(responseSchema)) {
|
|
3597
|
+
responses["200"] = {
|
|
3598
|
+
description: descriptions["200"] ?? "Successful response",
|
|
3599
|
+
content: {
|
|
3600
|
+
"application/json": { schema: zodSchemaToOpenApi(responseSchema) }
|
|
3601
|
+
}
|
|
3602
|
+
};
|
|
3603
|
+
} else if (typeof responseSchema === "object" && responseSchema !== null) {
|
|
3604
|
+
for (const [code, schema] of Object.entries(
|
|
3605
|
+
responseSchema
|
|
3606
|
+
)) {
|
|
3607
|
+
responses[code] = {
|
|
3608
|
+
description: descriptions[code] ?? `Response ${code}`,
|
|
3609
|
+
content: {
|
|
3610
|
+
"application/json": { schema: zodSchemaToOpenApi(schema) }
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
return Object.keys(responses).length > 0 ? responses : defaultResponse;
|
|
3616
|
+
}
|
|
3617
|
+
};
|
|
3618
|
+
DOCS_CSP = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://unpkg.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: https://validator.swagger.io; worker-src 'self' blob:;";
|
|
3619
|
+
Security = defineSecuritySchemes({
|
|
3620
|
+
bearerAuth: { type: "http", scheme: "bearer" },
|
|
3621
|
+
apiKey: { type: "apiKey", in: "header", name: "X-API-KEY" },
|
|
3622
|
+
basicAuth: { type: "http", scheme: "basic" }
|
|
3623
|
+
});
|
|
3624
|
+
}
|
|
3625
|
+
});
|
|
3626
|
+
|
|
2907
3627
|
// node_modules/commander/esm.mjs
|
|
2908
3628
|
var import_index = __toESM(require_commander());
|
|
2909
3629
|
var {
|
|
@@ -2923,12 +3643,12 @@ var {
|
|
|
2923
3643
|
|
|
2924
3644
|
// package.json
|
|
2925
3645
|
var package_default = {
|
|
2926
|
-
version: "
|
|
3646
|
+
version: "6.0.0"};
|
|
2927
3647
|
var ALWAYS_EXTERNAL = ["uWebSockets.js"];
|
|
2928
3648
|
function getUserExternals(cwd) {
|
|
2929
3649
|
let pkgExternals = [];
|
|
2930
3650
|
try {
|
|
2931
|
-
const pkgPath =
|
|
3651
|
+
const pkgPath = path7__default.default.join(cwd, "package.json");
|
|
2932
3652
|
if (fs__default.default.existsSync(pkgPath)) {
|
|
2933
3653
|
const pkg = JSON.parse(fs__default.default.readFileSync(pkgPath, "utf8"));
|
|
2934
3654
|
const deps = Object.keys(pkg.dependencies || {});
|
|
@@ -2946,8 +3666,8 @@ function getUserExternals(cwd) {
|
|
|
2946
3666
|
|
|
2947
3667
|
// src/commands/build.ts
|
|
2948
3668
|
async function buildProject(entry) {
|
|
2949
|
-
const entryPath =
|
|
2950
|
-
const outPath =
|
|
3669
|
+
const entryPath = path7__default.default.resolve(process.cwd(), entry);
|
|
3670
|
+
const outPath = path7__default.default.resolve(process.cwd(), "dist/index.js");
|
|
2951
3671
|
const userExternals = getUserExternals(process.cwd());
|
|
2952
3672
|
console.log(`\u{1F528} Building production bundle from ${entry}...`);
|
|
2953
3673
|
try {
|
|
@@ -2967,36 +3687,415 @@ async function buildProject(entry) {
|
|
|
2967
3687
|
process.exit(1);
|
|
2968
3688
|
}
|
|
2969
3689
|
}
|
|
2970
|
-
|
|
2971
|
-
const
|
|
2972
|
-
const
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
3690
|
+
function colourMethod(method) {
|
|
3691
|
+
const m = method.toUpperCase();
|
|
3692
|
+
const padded = m.padEnd(7);
|
|
3693
|
+
switch (m) {
|
|
3694
|
+
case "GET":
|
|
3695
|
+
return pc__default.default.bold(pc__default.default.green(padded));
|
|
3696
|
+
case "POST":
|
|
3697
|
+
return pc__default.default.bold(pc__default.default.blue(padded));
|
|
3698
|
+
case "PUT":
|
|
3699
|
+
return pc__default.default.bold(pc__default.default.yellow(padded));
|
|
3700
|
+
case "PATCH":
|
|
3701
|
+
return pc__default.default.bold(pc__default.default.magenta(padded));
|
|
3702
|
+
case "DELETE":
|
|
3703
|
+
return pc__default.default.bold(pc__default.default.red(padded));
|
|
3704
|
+
case "HEAD":
|
|
3705
|
+
return pc__default.default.dim(padded);
|
|
3706
|
+
case "OPTIONS":
|
|
3707
|
+
return pc__default.default.dim(padded);
|
|
3708
|
+
case "WS":
|
|
3709
|
+
return pc__default.default.bold(pc__default.default.cyan(padded));
|
|
3710
|
+
default:
|
|
3711
|
+
return padded;
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
var badge = {
|
|
3715
|
+
validation(label) {
|
|
3716
|
+
return pc__default.default.cyan(label);
|
|
3717
|
+
},
|
|
3718
|
+
deprecated() {
|
|
3719
|
+
return pc__default.default.bold(pc__default.default.red("\u2298 DEPRECATED"));
|
|
3720
|
+
},
|
|
3721
|
+
timeout(ms) {
|
|
3722
|
+
return pc__default.default.dim(`${ms}ms`);
|
|
3723
|
+
},
|
|
3724
|
+
tags(tags) {
|
|
3725
|
+
if (!tags.length) return "";
|
|
3726
|
+
return tags.map((t) => pc__default.default.dim(`#${t}`)).join(" ");
|
|
3727
|
+
}
|
|
3728
|
+
};
|
|
3729
|
+
function visibleLength(s) {
|
|
3730
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
3731
|
+
}
|
|
3732
|
+
function pad(s, width, align) {
|
|
3733
|
+
const v = visibleLength(s);
|
|
3734
|
+
if (v >= width) return s;
|
|
3735
|
+
const filler = " ".repeat(width - v);
|
|
3736
|
+
return align === "right" ? filler + s : s + filler;
|
|
3737
|
+
}
|
|
3738
|
+
function truncate(s, max) {
|
|
3739
|
+
if (visibleLength(s) <= max) return s;
|
|
3740
|
+
const stripped = s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3741
|
+
return stripped.slice(0, max - 1) + pc__default.default.dim("\u2026");
|
|
3742
|
+
}
|
|
3743
|
+
function renderTable(columns, rows, terminalWidth = process.stdout.columns || 100) {
|
|
3744
|
+
const widths = columns.map((col, i) => {
|
|
3745
|
+
const headerW = visibleLength(col.header);
|
|
3746
|
+
const cellW = Math.max(
|
|
3747
|
+
headerW,
|
|
3748
|
+
...rows.map((r) => visibleLength(r[i] ?? ""))
|
|
3749
|
+
);
|
|
3750
|
+
let w = Math.max(headerW, cellW);
|
|
3751
|
+
if (col.minWidth) w = Math.max(w, col.minWidth);
|
|
3752
|
+
if (col.maxWidth) w = Math.min(w, col.maxWidth);
|
|
3753
|
+
return w;
|
|
3754
|
+
});
|
|
3755
|
+
const overheadPerSep = 3;
|
|
3756
|
+
const overhead = (columns.length + 1) * 2 + overheadPerSep * (columns.length - 1);
|
|
3757
|
+
let total = widths.reduce((a, b) => a + b, 0) + overhead;
|
|
3758
|
+
if (total > terminalWidth) {
|
|
3759
|
+
const flexIdx = columns.map((c, i) => ({ c, i })).filter(({ c }) => !c.minWidth).map(({ i }) => i);
|
|
3760
|
+
let excess = total - terminalWidth;
|
|
3761
|
+
for (let pass = 0; pass < 8 && excess > 0; pass++) {
|
|
3762
|
+
for (const i of flexIdx) {
|
|
3763
|
+
if (excess <= 0) break;
|
|
3764
|
+
if (widths[i] > 8) {
|
|
3765
|
+
widths[i]--;
|
|
3766
|
+
excess--;
|
|
3767
|
+
total--;
|
|
2993
3768
|
}
|
|
2994
|
-
}
|
|
2995
|
-
forceKill.unref();
|
|
2996
|
-
} else {
|
|
2997
|
-
startChild();
|
|
3769
|
+
}
|
|
2998
3770
|
}
|
|
2999
|
-
}
|
|
3771
|
+
}
|
|
3772
|
+
const bar = (l, m, r) => l + widths.map((w) => "\u2500".repeat(w + 2)).join(m) + r;
|
|
3773
|
+
const lines = [];
|
|
3774
|
+
lines.push(pc__default.default.dim(bar("\u250C", "\u252C", "\u2510")));
|
|
3775
|
+
lines.push(
|
|
3776
|
+
pc__default.default.dim("\u2502 ") + columns.map((c, i) => pc__default.default.bold(pad(c.header, widths[i], c.align ?? "left"))).join(pc__default.default.dim(" \u2502 ")) + pc__default.default.dim(" \u2502")
|
|
3777
|
+
);
|
|
3778
|
+
lines.push(pc__default.default.dim(bar("\u251C", "\u253C", "\u2524")));
|
|
3779
|
+
for (const row of rows) {
|
|
3780
|
+
lines.push(
|
|
3781
|
+
pc__default.default.dim("\u2502 ") + columns.map((c, i) => {
|
|
3782
|
+
const cell = row[i] ?? "";
|
|
3783
|
+
const truncated = c.maxWidth ? truncate(cell, widths[i]) : cell;
|
|
3784
|
+
return pad(truncated, widths[i], c.align ?? "left");
|
|
3785
|
+
}).join(pc__default.default.dim(" \u2502 ")) + pc__default.default.dim(" \u2502")
|
|
3786
|
+
);
|
|
3787
|
+
}
|
|
3788
|
+
lines.push(pc__default.default.dim(bar("\u2514", "\u2534", "\u2518")));
|
|
3789
|
+
return lines.join("\n");
|
|
3790
|
+
}
|
|
3791
|
+
function pluralise(n, singular, plural) {
|
|
3792
|
+
return n === 1 ? `${n} ${singular}` : `${n} ${plural ?? singular + "s"}`;
|
|
3793
|
+
}
|
|
3794
|
+
var symbols = {
|
|
3795
|
+
ok: pc__default.default.green("\u2713"),
|
|
3796
|
+
warn: pc__default.default.yellow("\u26A0"),
|
|
3797
|
+
fail: pc__default.default.red("\u2717"),
|
|
3798
|
+
info: pc__default.default.cyan("\u2139"),
|
|
3799
|
+
bullet: pc__default.default.dim("\u2022"),
|
|
3800
|
+
arrow: pc__default.default.dim("\u2192")
|
|
3801
|
+
};
|
|
3802
|
+
async function loadApp(entry) {
|
|
3803
|
+
const entryPath = path7__default.default.resolve(process.cwd(), entry);
|
|
3804
|
+
const tempDir = path7__default.default.resolve(process.cwd(), ".axiomify");
|
|
3805
|
+
const tempPath = path7__default.default.join(tempDir, "inspect.cjs");
|
|
3806
|
+
const userExternals = getUserExternals(process.cwd());
|
|
3807
|
+
await esbuild__namespace.build({
|
|
3808
|
+
entryPoints: [entryPath],
|
|
3809
|
+
bundle: true,
|
|
3810
|
+
platform: "node",
|
|
3811
|
+
format: "cjs",
|
|
3812
|
+
outfile: tempPath,
|
|
3813
|
+
external: [.../* @__PURE__ */ new Set([...userExternals, "node:*"])],
|
|
3814
|
+
// Silence esbuild's own progress chatter — the CLI command above is
|
|
3815
|
+
// responsible for its own user-facing output.
|
|
3816
|
+
logLevel: "error"
|
|
3817
|
+
});
|
|
3818
|
+
try {
|
|
3819
|
+
delete __require.cache[__require.resolve(tempPath)];
|
|
3820
|
+
} catch {
|
|
3821
|
+
}
|
|
3822
|
+
const hangTimer = setTimeout(() => {
|
|
3823
|
+
process.stderr.write(
|
|
3824
|
+
"\n" + pc__default.default.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__default.default.cyan("if (require.main === module) { ... }") + " so it only runs when executed directly.\n\n"
|
|
3825
|
+
);
|
|
3826
|
+
}, 5e3);
|
|
3827
|
+
hangTimer.unref();
|
|
3828
|
+
let mod;
|
|
3829
|
+
try {
|
|
3830
|
+
mod = __require(tempPath);
|
|
3831
|
+
} finally {
|
|
3832
|
+
clearTimeout(hangTimer);
|
|
3833
|
+
}
|
|
3834
|
+
const app = mod.app ?? mod.default;
|
|
3835
|
+
if (!app || typeof app.registeredRoutes === "undefined") {
|
|
3836
|
+
await fs5__default.default.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
3837
|
+
});
|
|
3838
|
+
throw new Error(
|
|
3839
|
+
"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;"
|
|
3840
|
+
);
|
|
3841
|
+
}
|
|
3842
|
+
const cleanup = async () => {
|
|
3843
|
+
await fs5__default.default.rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
3844
|
+
});
|
|
3845
|
+
};
|
|
3846
|
+
return { app, cleanup };
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3849
|
+
// src/commands/check.ts
|
|
3850
|
+
function add(ctx, f) {
|
|
3851
|
+
ctx.findings.push(f);
|
|
3852
|
+
}
|
|
3853
|
+
function checkRequestId(ctx) {
|
|
3854
|
+
const onRequest = ctx.app.hooks?.hooks?.onRequest ?? [];
|
|
3855
|
+
if (onRequest.length === 0) {
|
|
3856
|
+
add(ctx, {
|
|
3857
|
+
severity: "warn",
|
|
3858
|
+
area: "observability",
|
|
3859
|
+
message: "`app.enableRequestId()` has not been called",
|
|
3860
|
+
hint: "Distributed-trace correlation will be impossible without an X-Request-Id header. Add `app.enableRequestId()` after construction unless you handle this elsewhere."
|
|
3861
|
+
});
|
|
3862
|
+
return;
|
|
3863
|
+
}
|
|
3864
|
+
add(ctx, {
|
|
3865
|
+
severity: "ok",
|
|
3866
|
+
area: "observability",
|
|
3867
|
+
message: `onRequest hooks: ${onRequest.length} registered`
|
|
3868
|
+
});
|
|
3869
|
+
}
|
|
3870
|
+
function checkEnvVars(ctx) {
|
|
3871
|
+
const expectedInProd = ["JWT_SECRET", "NODE_ENV"];
|
|
3872
|
+
for (const key of expectedInProd) {
|
|
3873
|
+
if (!ctx.envKeys.has(key)) continue;
|
|
3874
|
+
if (process.env[key]) {
|
|
3875
|
+
add(ctx, { severity: "ok", area: "env", message: `${key} is set` });
|
|
3876
|
+
} else {
|
|
3877
|
+
add(ctx, {
|
|
3878
|
+
severity: "warn",
|
|
3879
|
+
area: "env",
|
|
3880
|
+
message: `${key} referenced in source but not set in environment`,
|
|
3881
|
+
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.`
|
|
3882
|
+
});
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
function checkResponseSchemas(ctx) {
|
|
3887
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3888
|
+
const missing = routes.filter(
|
|
3889
|
+
(r) => r.schema?.body && !r.schema?.response
|
|
3890
|
+
);
|
|
3891
|
+
if (missing.length > 0) {
|
|
3892
|
+
add(ctx, {
|
|
3893
|
+
severity: "warn",
|
|
3894
|
+
area: "validation",
|
|
3895
|
+
message: `${missing.length} route${missing.length === 1 ? "" : "s"} with body schema but no response schema`,
|
|
3896
|
+
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}`
|
|
3897
|
+
});
|
|
3898
|
+
} else if (routes.length > 0) {
|
|
3899
|
+
add(ctx, {
|
|
3900
|
+
severity: "ok",
|
|
3901
|
+
area: "validation",
|
|
3902
|
+
message: "every route with a body schema also declares a response schema"
|
|
3903
|
+
});
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
function checkOpenApiNaming(ctx) {
|
|
3907
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3908
|
+
const usingMeta = routes.filter((r) => r.meta);
|
|
3909
|
+
if (usingMeta.length > 0) {
|
|
3910
|
+
add(ctx, {
|
|
3911
|
+
severity: "fail",
|
|
3912
|
+
area: "api",
|
|
3913
|
+
message: `${usingMeta.length} route${usingMeta.length === 1 ? "" : "s"} use the removed \`meta:\` field`,
|
|
3914
|
+
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}`
|
|
3915
|
+
});
|
|
3916
|
+
}
|
|
3917
|
+
const usingOpenapi = routes.filter((r) => r.openapi);
|
|
3918
|
+
if (usingOpenapi.length > 0) {
|
|
3919
|
+
add(ctx, {
|
|
3920
|
+
severity: "fail",
|
|
3921
|
+
area: "api",
|
|
3922
|
+
message: `${usingOpenapi.length} route${usingOpenapi.length === 1 ? "" : "s"} use the removed top-level \`openapi:\` field`,
|
|
3923
|
+
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}`
|
|
3924
|
+
});
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
function checkHealthCheck(ctx) {
|
|
3928
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3929
|
+
const hasHealth = routes.some(
|
|
3930
|
+
(r) => r.method === "GET" && ["/health", "/healthz", "/-/health", "/ping", "/live", "/ready"].some(
|
|
3931
|
+
(p) => r.path === p
|
|
3932
|
+
)
|
|
3933
|
+
);
|
|
3934
|
+
if (hasHealth) {
|
|
3935
|
+
add(ctx, { severity: "ok", area: "ops", message: "health-check route registered" });
|
|
3936
|
+
} else {
|
|
3937
|
+
add(ctx, {
|
|
3938
|
+
severity: "warn",
|
|
3939
|
+
area: "ops",
|
|
3940
|
+
message: "no health-check route detected",
|
|
3941
|
+
hint: 'Kubernetes, ECS, and load balancers expect a `/health` (or similar) endpoint. Register one via `app.healthCheck("/health")` from `@axiomify/core`.'
|
|
3942
|
+
});
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
function checkOpenApiExposure(ctx) {
|
|
3946
|
+
const routes = ctx.app.registeredRoutes ?? [];
|
|
3947
|
+
const docsRoute = routes.find(
|
|
3948
|
+
(r) => r.method === "GET" && (r.path === "/docs" || r.path.endsWith("/docs"))
|
|
3949
|
+
);
|
|
3950
|
+
const specRoute = routes.find(
|
|
3951
|
+
(r) => r.method === "GET" && r.path.endsWith("/openapi.json")
|
|
3952
|
+
);
|
|
3953
|
+
if (docsRoute || specRoute) {
|
|
3954
|
+
add(ctx, {
|
|
3955
|
+
severity: "warn",
|
|
3956
|
+
area: "security",
|
|
3957
|
+
message: "OpenAPI docs endpoint is registered",
|
|
3958
|
+
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."
|
|
3959
|
+
});
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
function checkRoutesLockState(ctx) {
|
|
3963
|
+
if (ctx.app._routesLocked) {
|
|
3964
|
+
add(ctx, {
|
|
3965
|
+
severity: "warn",
|
|
3966
|
+
area: "config",
|
|
3967
|
+
message: "app.lockRoutes() has already been called",
|
|
3968
|
+
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."
|
|
3969
|
+
});
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
function checkSecurityPlugins(ctx) {
|
|
3973
|
+
const onRequest = ctx.app.hooks?.hooks?.onRequest ?? [];
|
|
3974
|
+
if (onRequest.length < 2) {
|
|
3975
|
+
add(ctx, {
|
|
3976
|
+
severity: "warn",
|
|
3977
|
+
area: "security",
|
|
3978
|
+
message: "few onRequest hooks detected \u2014 security plugins may not be registered",
|
|
3979
|
+
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."
|
|
3980
|
+
});
|
|
3981
|
+
} else {
|
|
3982
|
+
add(ctx, {
|
|
3983
|
+
severity: "ok",
|
|
3984
|
+
area: "security",
|
|
3985
|
+
message: `${onRequest.length} onRequest hooks registered (security plugins likely active)`
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3989
|
+
function collectEnvKeysFromBundle(bundlePath) {
|
|
3990
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3991
|
+
try {
|
|
3992
|
+
const src = fs__default.default.readFileSync(bundlePath, "utf8");
|
|
3993
|
+
const re = /process\.env\.([A-Z][A-Z0-9_]*)|process\.env\[(['"])([A-Z][A-Z0-9_]*)\2\]/g;
|
|
3994
|
+
let m;
|
|
3995
|
+
while ((m = re.exec(src)) !== null) {
|
|
3996
|
+
keys.add(m[1] ?? m[3]);
|
|
3997
|
+
}
|
|
3998
|
+
} catch {
|
|
3999
|
+
}
|
|
4000
|
+
return keys;
|
|
4001
|
+
}
|
|
4002
|
+
function loadPkgJson(cwd) {
|
|
4003
|
+
try {
|
|
4004
|
+
return JSON.parse(fs__default.default.readFileSync(path7__default.default.join(cwd, "package.json"), "utf8"));
|
|
4005
|
+
} catch {
|
|
4006
|
+
return null;
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
async function runCheck(entry) {
|
|
4010
|
+
let app;
|
|
4011
|
+
let cleanup = async () => {
|
|
4012
|
+
};
|
|
4013
|
+
let bundlePath = "";
|
|
4014
|
+
try {
|
|
4015
|
+
const loaded = await loadApp(entry);
|
|
4016
|
+
app = loaded.app;
|
|
4017
|
+
cleanup = loaded.cleanup;
|
|
4018
|
+
bundlePath = path7__default.default.resolve(process.cwd(), ".axiomify/inspect.cjs");
|
|
4019
|
+
} catch (err) {
|
|
4020
|
+
console.error(pc__default.default.red("\u2717 Failed to load app:"));
|
|
4021
|
+
console.error(err.message);
|
|
4022
|
+
process.exit(1);
|
|
4023
|
+
}
|
|
4024
|
+
const ctx = {
|
|
4025
|
+
app,
|
|
4026
|
+
cwd: process.cwd(),
|
|
4027
|
+
findings: [],
|
|
4028
|
+
pkgJson: loadPkgJson(process.cwd()),
|
|
4029
|
+
envKeys: collectEnvKeysFromBundle(bundlePath)
|
|
4030
|
+
};
|
|
4031
|
+
checkEnvVars(ctx);
|
|
4032
|
+
checkRequestId(ctx);
|
|
4033
|
+
checkRoutesLockState(ctx);
|
|
4034
|
+
checkOpenApiNaming(ctx);
|
|
4035
|
+
checkSecurityPlugins(ctx);
|
|
4036
|
+
checkOpenApiExposure(ctx);
|
|
4037
|
+
checkResponseSchemas(ctx);
|
|
4038
|
+
checkHealthCheck(ctx);
|
|
4039
|
+
await cleanup();
|
|
4040
|
+
console.log();
|
|
4041
|
+
console.log(pc__default.default.bold(" \u{1F50D} Production-readiness check"));
|
|
4042
|
+
console.log();
|
|
4043
|
+
const sevOrder = { fail: 0, warn: 1, ok: 2 };
|
|
4044
|
+
ctx.findings.sort(
|
|
4045
|
+
(a, b) => sevOrder[a.severity] - sevOrder[b.severity] || a.area.localeCompare(b.area)
|
|
4046
|
+
);
|
|
4047
|
+
const sym = {
|
|
4048
|
+
ok: symbols.ok,
|
|
4049
|
+
warn: symbols.warn,
|
|
4050
|
+
fail: symbols.fail
|
|
4051
|
+
};
|
|
4052
|
+
for (const f of ctx.findings) {
|
|
4053
|
+
const tag = pc__default.default.dim(`[${f.area}]`);
|
|
4054
|
+
console.log(` ${sym[f.severity]} ${tag} ${f.message}`);
|
|
4055
|
+
if (f.hint && f.severity !== "ok") {
|
|
4056
|
+
const wrapped = f.hint.replace(/(.{1,80})(\s+|$)/g, "\n " + pc__default.default.dim("$1"));
|
|
4057
|
+
console.log(wrapped);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
const fails = ctx.findings.filter((f) => f.severity === "fail").length;
|
|
4061
|
+
const warns = ctx.findings.filter((f) => f.severity === "warn").length;
|
|
4062
|
+
const oks = ctx.findings.filter((f) => f.severity === "ok").length;
|
|
4063
|
+
console.log();
|
|
4064
|
+
const summary = ` ${symbols.ok} ${pluralise(oks, "pass", "passes")}` + pc__default.default.dim(" \xB7 ") + (warns > 0 ? `${symbols.warn} ${pluralise(warns, "warning")}` : pc__default.default.dim("0 warnings")) + pc__default.default.dim(" \xB7 ") + (fails > 0 ? `${symbols.fail} ${pluralise(fails, "failure")}` : pc__default.default.dim("0 failures"));
|
|
4065
|
+
console.log(summary);
|
|
4066
|
+
console.log();
|
|
4067
|
+
if (fails > 0) process.exit(1);
|
|
4068
|
+
}
|
|
4069
|
+
async function devServer(entry) {
|
|
4070
|
+
const entryPath = path7__default.default.resolve(process.cwd(), entry);
|
|
4071
|
+
const outPath = path7__default.default.resolve(process.cwd(), ".axiomify/dev.js");
|
|
4072
|
+
let child = null;
|
|
4073
|
+
let firstBuild = true;
|
|
4074
|
+
const startChild = () => {
|
|
4075
|
+
child = child_process.spawn("node", [outPath], { stdio: "inherit" });
|
|
4076
|
+
child.on("error", (err) => {
|
|
4077
|
+
console.error("\u274C Failed to start process:", err);
|
|
4078
|
+
});
|
|
4079
|
+
};
|
|
4080
|
+
const GRACEFUL_KILL_MS = 3e3;
|
|
4081
|
+
const restartServer = () => {
|
|
4082
|
+
if (child && child.exitCode === null && child.signalCode === null) {
|
|
4083
|
+
child.removeAllListeners("exit");
|
|
4084
|
+
const oldChild = child;
|
|
4085
|
+
oldChild.once("exit", () => {
|
|
4086
|
+
startChild();
|
|
4087
|
+
});
|
|
4088
|
+
oldChild.kill("SIGTERM");
|
|
4089
|
+
const forceKill = setTimeout(() => {
|
|
4090
|
+
if (oldChild.exitCode === null && oldChild.signalCode === null) {
|
|
4091
|
+
oldChild.kill("SIGKILL");
|
|
4092
|
+
}
|
|
4093
|
+
}, GRACEFUL_KILL_MS);
|
|
4094
|
+
forceKill.unref();
|
|
4095
|
+
} else {
|
|
4096
|
+
startChild();
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
3000
4099
|
const watchPlugin = {
|
|
3001
4100
|
name: "watch-plugin",
|
|
3002
4101
|
setup(build3) {
|
|
@@ -3049,6 +4148,213 @@ async function devServer(entry) {
|
|
|
3049
4148
|
console.log(`\u{1F440} Axiomify Dev Engine watching for changes...`);
|
|
3050
4149
|
await ctx.watch();
|
|
3051
4150
|
}
|
|
4151
|
+
function add2(findings, f) {
|
|
4152
|
+
findings.push(f);
|
|
4153
|
+
}
|
|
4154
|
+
function probePort(port) {
|
|
4155
|
+
return new Promise((resolve) => {
|
|
4156
|
+
const server = net.createServer();
|
|
4157
|
+
server.once("error", (err) => {
|
|
4158
|
+
if (err.code === "EADDRINUSE") resolve("busy");
|
|
4159
|
+
else if (err.code === "EACCES") resolve("denied");
|
|
4160
|
+
else resolve("busy");
|
|
4161
|
+
});
|
|
4162
|
+
server.once("listening", () => {
|
|
4163
|
+
server.close(() => resolve("free"));
|
|
4164
|
+
});
|
|
4165
|
+
server.listen(port, "127.0.0.1");
|
|
4166
|
+
});
|
|
4167
|
+
}
|
|
4168
|
+
function checkNodeVersion(findings) {
|
|
4169
|
+
const major = parseInt(process.versions.node.split(".")[0], 10);
|
|
4170
|
+
if (major < 18) {
|
|
4171
|
+
add2(findings, {
|
|
4172
|
+
severity: "fail",
|
|
4173
|
+
area: "node",
|
|
4174
|
+
message: `Node ${process.versions.node} is below the supported minimum`,
|
|
4175
|
+
hint: "Axiomify requires Node 18 or later. Upgrade via nvm: `nvm install 22 && nvm use 22`."
|
|
4176
|
+
});
|
|
4177
|
+
} else if (major > 22) {
|
|
4178
|
+
add2(findings, {
|
|
4179
|
+
severity: "warn",
|
|
4180
|
+
area: "node",
|
|
4181
|
+
message: `Node ${process.versions.node} \u2014 uWebSockets.js has no prebuilt binary for this version`,
|
|
4182
|
+
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."
|
|
4183
|
+
});
|
|
4184
|
+
} else {
|
|
4185
|
+
add2(findings, {
|
|
4186
|
+
severity: "ok",
|
|
4187
|
+
area: "node",
|
|
4188
|
+
message: `Node ${process.versions.node} (uWS prebuilt available)`
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
function checkPlatform(findings) {
|
|
4193
|
+
if (process.platform === "linux") {
|
|
4194
|
+
add2(findings, {
|
|
4195
|
+
severity: "ok",
|
|
4196
|
+
area: "platform",
|
|
4197
|
+
message: "Linux \u2014 SO_REUSEPORT clustering supported natively"
|
|
4198
|
+
});
|
|
4199
|
+
} else {
|
|
4200
|
+
add2(findings, {
|
|
4201
|
+
severity: "warn",
|
|
4202
|
+
area: "platform",
|
|
4203
|
+
message: `${process.platform} \u2014 \`listenClustered()\` requires \`allowUserspaceProxy: true\``,
|
|
4204
|
+
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."
|
|
4205
|
+
});
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
function checkDependencyDrift(findings) {
|
|
4209
|
+
try {
|
|
4210
|
+
const pkgPath = path7__default.default.join(process.cwd(), "package.json");
|
|
4211
|
+
const pkg = JSON.parse(fs__default.default.readFileSync(pkgPath, "utf8"));
|
|
4212
|
+
const all = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
4213
|
+
const axiomifyDeps = Object.entries(all).filter(
|
|
4214
|
+
([k]) => k.startsWith("@axiomify/")
|
|
4215
|
+
);
|
|
4216
|
+
if (axiomifyDeps.length === 0) {
|
|
4217
|
+
add2(findings, {
|
|
4218
|
+
severity: "warn",
|
|
4219
|
+
area: "deps",
|
|
4220
|
+
message: "No @axiomify/* packages found in package.json",
|
|
4221
|
+
hint: "Run this from the root of a project that uses Axiomify."
|
|
4222
|
+
});
|
|
4223
|
+
return;
|
|
4224
|
+
}
|
|
4225
|
+
const versions = new Set(
|
|
4226
|
+
axiomifyDeps.map(([, v]) => v.replace(/^[\^~]/, "").replace(/^\*$/, "workspace"))
|
|
4227
|
+
);
|
|
4228
|
+
if (versions.size > 1) {
|
|
4229
|
+
add2(findings, {
|
|
4230
|
+
severity: "warn",
|
|
4231
|
+
area: "deps",
|
|
4232
|
+
message: `@axiomify/* packages are on ${versions.size} different versions`,
|
|
4233
|
+
hint: "Mixed @axiomify/* versions can cause subtle compat issues. Pin them all to the same version: " + [...versions].join(", ")
|
|
4234
|
+
});
|
|
4235
|
+
} else {
|
|
4236
|
+
add2(findings, {
|
|
4237
|
+
severity: "ok",
|
|
4238
|
+
area: "deps",
|
|
4239
|
+
message: `${axiomifyDeps.length} @axiomify/* packages aligned (${[...versions][0]})`
|
|
4240
|
+
});
|
|
4241
|
+
}
|
|
4242
|
+
} catch {
|
|
4243
|
+
add2(findings, {
|
|
4244
|
+
severity: "warn",
|
|
4245
|
+
area: "deps",
|
|
4246
|
+
message: "Could not read package.json",
|
|
4247
|
+
hint: "Run `axiomify doctor` from a project root."
|
|
4248
|
+
});
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
function checkUwsLoads(findings) {
|
|
4252
|
+
try {
|
|
4253
|
+
require_uws();
|
|
4254
|
+
add2(findings, {
|
|
4255
|
+
severity: "ok",
|
|
4256
|
+
area: "uws",
|
|
4257
|
+
message: "uWebSockets.js loads successfully"
|
|
4258
|
+
});
|
|
4259
|
+
} catch (err) {
|
|
4260
|
+
const msg = String(err.message ?? err);
|
|
4261
|
+
if (msg.includes("Cannot find module")) {
|
|
4262
|
+
add2(findings, {
|
|
4263
|
+
severity: "warn",
|
|
4264
|
+
area: "uws",
|
|
4265
|
+
message: "uWebSockets.js is not installed in this project",
|
|
4266
|
+
hint: "It is a peer dependency of `@axiomify/native`. Install via `npm install --save-optional uWebSockets.js` (the package handles platform selection)."
|
|
4267
|
+
});
|
|
4268
|
+
} else {
|
|
4269
|
+
add2(findings, {
|
|
4270
|
+
severity: "fail",
|
|
4271
|
+
area: "uws",
|
|
4272
|
+
message: "uWebSockets.js native binding failed to load",
|
|
4273
|
+
hint: msg.length > 200 ? msg.slice(0, 200) + "\u2026" : msg
|
|
4274
|
+
});
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
async function checkPortAvailability(findings) {
|
|
4279
|
+
const port = parseInt(process.env.PORT ?? "3000", 10);
|
|
4280
|
+
const state = await probePort(port);
|
|
4281
|
+
if (state === "free") {
|
|
4282
|
+
add2(findings, {
|
|
4283
|
+
severity: "ok",
|
|
4284
|
+
area: "port",
|
|
4285
|
+
message: `Port ${port} is available on 127.0.0.1`
|
|
4286
|
+
});
|
|
4287
|
+
} else if (state === "busy") {
|
|
4288
|
+
add2(findings, {
|
|
4289
|
+
severity: "warn",
|
|
4290
|
+
area: "port",
|
|
4291
|
+
message: `Port ${port} is already in use`,
|
|
4292
|
+
hint: "Stop the conflicting process or set `PORT` to a different value."
|
|
4293
|
+
});
|
|
4294
|
+
} else {
|
|
4295
|
+
add2(findings, {
|
|
4296
|
+
severity: "warn",
|
|
4297
|
+
area: "port",
|
|
4298
|
+
message: `Port ${port}: bind denied (permission)`,
|
|
4299
|
+
hint: "Ports below 1024 typically require root. Use a port \u2265 1024 in development."
|
|
4300
|
+
});
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
function checkBuildArtifacts(findings) {
|
|
4304
|
+
const dist = path7__default.default.join(process.cwd(), "dist");
|
|
4305
|
+
if (fs__default.default.existsSync(dist)) {
|
|
4306
|
+
add2(findings, {
|
|
4307
|
+
severity: "ok",
|
|
4308
|
+
area: "build",
|
|
4309
|
+
message: "dist/ exists (recent `axiomify build`)"
|
|
4310
|
+
});
|
|
4311
|
+
} else {
|
|
4312
|
+
add2(findings, {
|
|
4313
|
+
severity: "warn",
|
|
4314
|
+
area: "build",
|
|
4315
|
+
message: "No dist/ directory \u2014 production build has not been run",
|
|
4316
|
+
hint: "Run `axiomify build` before deploying."
|
|
4317
|
+
});
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
async function runDoctor() {
|
|
4321
|
+
const findings = [];
|
|
4322
|
+
checkNodeVersion(findings);
|
|
4323
|
+
checkPlatform(findings);
|
|
4324
|
+
checkDependencyDrift(findings);
|
|
4325
|
+
checkUwsLoads(findings);
|
|
4326
|
+
checkBuildArtifacts(findings);
|
|
4327
|
+
await checkPortAvailability(findings);
|
|
4328
|
+
console.log();
|
|
4329
|
+
console.log(pc__default.default.bold(" \u{1FA7A} Axiomify doctor"));
|
|
4330
|
+
console.log();
|
|
4331
|
+
const sevOrder = { fail: 0, warn: 1, ok: 2 };
|
|
4332
|
+
findings.sort(
|
|
4333
|
+
(a, b) => sevOrder[a.severity] - sevOrder[b.severity] || a.area.localeCompare(b.area)
|
|
4334
|
+
);
|
|
4335
|
+
const sym = {
|
|
4336
|
+
ok: symbols.ok,
|
|
4337
|
+
warn: symbols.warn,
|
|
4338
|
+
fail: symbols.fail
|
|
4339
|
+
};
|
|
4340
|
+
for (const f of findings) {
|
|
4341
|
+
const tag = pc__default.default.dim(`[${f.area}]`);
|
|
4342
|
+
console.log(` ${sym[f.severity]} ${tag} ${f.message}`);
|
|
4343
|
+
if (f.hint && f.severity !== "ok") {
|
|
4344
|
+
const wrapped = f.hint.replace(/(.{1,80})(\s+|$)/g, "\n " + pc__default.default.dim("$1"));
|
|
4345
|
+
console.log(wrapped);
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
const fails = findings.filter((f) => f.severity === "fail").length;
|
|
4349
|
+
const warns = findings.filter((f) => f.severity === "warn").length;
|
|
4350
|
+
const oks = findings.filter((f) => f.severity === "ok").length;
|
|
4351
|
+
console.log();
|
|
4352
|
+
console.log(
|
|
4353
|
+
` ${symbols.ok} ${pluralise(oks, "pass", "passes")}` + pc__default.default.dim(" \xB7 ") + (warns > 0 ? `${symbols.warn} ${pluralise(warns, "warning")}` : pc__default.default.dim("0 warnings")) + pc__default.default.dim(" \xB7 ") + (fails > 0 ? `${symbols.fail} ${pluralise(fails, "failure")}` : pc__default.default.dim("0 failures"))
|
|
4354
|
+
);
|
|
4355
|
+
console.log();
|
|
4356
|
+
if (fails > 0) process.exit(1);
|
|
4357
|
+
}
|
|
3052
4358
|
var DEV_COMMAND_BY_PM = {
|
|
3053
4359
|
npm: "npm run dev",
|
|
3054
4360
|
pnpm: "pnpm dev",
|
|
@@ -3066,20 +4372,6 @@ async function initProject(targetDir, options = {}) {
|
|
|
3066
4372
|
});
|
|
3067
4373
|
}
|
|
3068
4374
|
questions.push(
|
|
3069
|
-
{
|
|
3070
|
-
type: "select",
|
|
3071
|
-
name: "adapter",
|
|
3072
|
-
message: "Which HTTP adapter do you want to use?",
|
|
3073
|
-
choices: [
|
|
3074
|
-
"Native (uWS \u2014 Fastest, 50k+ req/s)",
|
|
3075
|
-
"Fastify (High-throughput, recommended)",
|
|
3076
|
-
"Express (Max ecosystem compatibility)",
|
|
3077
|
-
"Hapi (Enterprise, plugin-first)",
|
|
3078
|
-
"Node HTTP (Zero dependency)"
|
|
3079
|
-
],
|
|
3080
|
-
initial: 0
|
|
3081
|
-
// Native is the recommended default
|
|
3082
|
-
},
|
|
3083
4375
|
{
|
|
3084
4376
|
type: "input",
|
|
3085
4377
|
name: "description",
|
|
@@ -3133,12 +4425,12 @@ async function initProject(targetDir, options = {}) {
|
|
|
3133
4425
|
);
|
|
3134
4426
|
process.exit(1);
|
|
3135
4427
|
}
|
|
3136
|
-
const dir =
|
|
4428
|
+
const dir = path7__default.default.resolve(process.cwd(), projectName);
|
|
3137
4429
|
if (fs.existsSync(dir) && !options.force && targetDir) {
|
|
3138
4430
|
const targets = [
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
4431
|
+
path7__default.default.join(dir, "package.json"),
|
|
4432
|
+
path7__default.default.join(dir, "tsconfig.json"),
|
|
4433
|
+
path7__default.default.join(dir, "src", "index.ts")
|
|
3142
4434
|
];
|
|
3143
4435
|
const collisions = targets.filter((p) => fs.existsSync(p));
|
|
3144
4436
|
if (collisions.length > 0) {
|
|
@@ -3150,28 +4442,11 @@ async function initProject(targetDir, options = {}) {
|
|
|
3150
4442
|
process.exit(1);
|
|
3151
4443
|
}
|
|
3152
4444
|
}
|
|
3153
|
-
await
|
|
4445
|
+
await fs5__default.default.mkdir(path7__default.default.join(dir, "src"), { recursive: true });
|
|
3154
4446
|
const AXIOMIFY_VERSION = `^${package_default.version}`;
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
if (answers.adapter.includes("Fastify")) {
|
|
3159
|
-
adapterPackage = "@axiomify/fastify";
|
|
3160
|
-
adapterImport = "import { FastifyAdapter } from '@axiomify/fastify';";
|
|
3161
|
-
adapterInit = "const server = new FastifyAdapter(app);\n await server.listen(3000);\n console.log(' Axiomify Fastify on :3000');";
|
|
3162
|
-
} else if (answers.adapter.includes("Express")) {
|
|
3163
|
-
adapterPackage = "@axiomify/express";
|
|
3164
|
-
adapterImport = "import { ExpressAdapter } from '@axiomify/express';";
|
|
3165
|
-
adapterInit = "const server = new ExpressAdapter(app);\n server.listen(3000, () => console.log(' Axiomify Express on :3000'));";
|
|
3166
|
-
} else if (answers.adapter.includes("Hapi")) {
|
|
3167
|
-
adapterPackage = "@axiomify/hapi";
|
|
3168
|
-
adapterImport = "import { HapiAdapter } from '@axiomify/hapi';";
|
|
3169
|
-
adapterInit = "const server = new HapiAdapter(app);\n await server.listen(3000);\n console.log(' Axiomify Hapi on :3000');";
|
|
3170
|
-
} else if (answers.adapter.includes("HTTP")) {
|
|
3171
|
-
adapterPackage = "@axiomify/http";
|
|
3172
|
-
adapterImport = "import { HttpAdapter } from '@axiomify/http';";
|
|
3173
|
-
adapterInit = "const server = new HttpAdapter(app);\n server.listen(3000, () => console.log(' Axiomify HTTP on :3000'));";
|
|
3174
|
-
}
|
|
4447
|
+
const adapterPackage = "@axiomify/native";
|
|
4448
|
+
const adapterImport = "import { NativeAdapter } from '@axiomify/native';";
|
|
4449
|
+
const adapterInit = "const server = new NativeAdapter(app, { port: 3000 });\n server.listen(() => console.log(' Axiomify Native on :3000'));";
|
|
3175
4450
|
const pkgJson = {
|
|
3176
4451
|
name: projectName,
|
|
3177
4452
|
version: "1.0.0",
|
|
@@ -3239,14 +4514,14 @@ async function initProject(targetDir, options = {}) {
|
|
|
3239
4514
|
"printWidth": 100,
|
|
3240
4515
|
"tabWidth": 2
|
|
3241
4516
|
}`;
|
|
3242
|
-
await
|
|
3243
|
-
await
|
|
3244
|
-
await
|
|
3245
|
-
|
|
4517
|
+
await fs5__default.default.writeFile(path7__default.default.join(dir, ".eslintrc.cjs"), eslintConfig);
|
|
4518
|
+
await fs5__default.default.writeFile(path7__default.default.join(dir, ".prettierrc"), prettierConfig);
|
|
4519
|
+
await fs5__default.default.writeFile(
|
|
4520
|
+
path7__default.default.join(dir, ".prettierignore"),
|
|
3246
4521
|
"dist\nnode_modules\ncoverage\n"
|
|
3247
4522
|
);
|
|
3248
|
-
await
|
|
3249
|
-
|
|
4523
|
+
await fs5__default.default.writeFile(
|
|
4524
|
+
path7__default.default.join(dir, ".editorconfig"),
|
|
3250
4525
|
"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"
|
|
3251
4526
|
);
|
|
3252
4527
|
}
|
|
@@ -3307,19 +4582,19 @@ async function initProject(targetDir, options = {}) {
|
|
|
3307
4582
|
"coverage",
|
|
3308
4583
|
"*.log"
|
|
3309
4584
|
].join("\n") + "\n";
|
|
3310
|
-
await
|
|
3311
|
-
|
|
4585
|
+
await fs5__default.default.writeFile(
|
|
4586
|
+
path7__default.default.join(dir, "package.json"),
|
|
3312
4587
|
JSON.stringify(pkgJson, null, 2)
|
|
3313
4588
|
);
|
|
3314
|
-
await
|
|
3315
|
-
|
|
4589
|
+
await fs5__default.default.writeFile(
|
|
4590
|
+
path7__default.default.join(dir, "tsconfig.json"),
|
|
3316
4591
|
JSON.stringify(tsConfig, null, 2)
|
|
3317
4592
|
);
|
|
3318
|
-
await
|
|
3319
|
-
await
|
|
4593
|
+
await fs5__default.default.writeFile(path7__default.default.join(dir, "src", "index.ts"), indexTs);
|
|
4594
|
+
await fs5__default.default.writeFile(path7__default.default.join(dir, ".gitignore"), gitignore);
|
|
3320
4595
|
console.log(pc__default.default.green(`
|
|
3321
4596
|
\u2705 Axiomify project initialized in ${pc__default.default.bold(dir)}`));
|
|
3322
|
-
if (answers.useGit && !fs.existsSync(
|
|
4597
|
+
if (answers.useGit && !fs.existsSync(path7__default.default.join(dir, ".git"))) {
|
|
3323
4598
|
try {
|
|
3324
4599
|
await execa.execa("git", ["init"], { cwd: dir });
|
|
3325
4600
|
console.log(pc__default.default.green("\u2705 Git repository initialized"));
|
|
@@ -3353,63 +4628,644 @@ async function initProject(targetDir, options = {}) {
|
|
|
3353
4628
|
\u{1F525} Run "${devCommand}" to start your development server!`)
|
|
3354
4629
|
);
|
|
3355
4630
|
}
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
4631
|
+
var RULES = [
|
|
4632
|
+
{
|
|
4633
|
+
id: "meta-to-schema",
|
|
4634
|
+
description: "`meta:` route field removed \u2014 metadata now lives inside `schema:` alongside Zod fields",
|
|
4635
|
+
// NOTE: This rule renames `meta:` → a comment directing the dev to merge
|
|
4636
|
+
// contents into schema:. A full structural AST merge is out of scope for
|
|
4637
|
+
// the regex codemod; flag it for manual review instead (see report).
|
|
4638
|
+
match: /^(\s*)meta:(\s*\{)/gm,
|
|
4639
|
+
replace: "$1/* TODO(axiomify-migrate): merge meta fields into schema: */ openapi_REMOVE:$2"
|
|
4640
|
+
},
|
|
4641
|
+
{
|
|
4642
|
+
id: "openapi-field-to-schema",
|
|
4643
|
+
description: "`openapi:` top-level route field \u2192 contents merged into `schema:` (removed in 6.1)",
|
|
4644
|
+
// Same conservative approach: flag for manual review via TODO comment.
|
|
4645
|
+
match: /^(\s*)openapi:(\s*\{)/gm,
|
|
4646
|
+
replace: "$1/* TODO(axiomify-migrate): merge openapi fields into schema: */ openapi_REMOVE:$2"
|
|
4647
|
+
},
|
|
4648
|
+
{
|
|
4649
|
+
id: "useSwagger-import",
|
|
4650
|
+
description: "`useSwagger` import \u2192 `useOpenAPI` (the function was never named `useSwagger` in shipped code \u2014 docs were wrong)",
|
|
4651
|
+
match: /\buseSwagger\b/g,
|
|
4652
|
+
replace: "useOpenAPI"
|
|
4653
|
+
},
|
|
4654
|
+
{
|
|
4655
|
+
id: "routePrefix-option",
|
|
4656
|
+
description: "`routePrefix:` \u2192 `prefix:` on `useOpenAPI()` options",
|
|
4657
|
+
match: /(\buseOpenAPI\s*\([\s\S]*?)\brouteprefix(\s*:)/gi,
|
|
4658
|
+
// Naive: just rename the property when it appears inside a useOpenAPI() call.
|
|
4659
|
+
// The capture-group lookbehind avoids touching unrelated `routePrefix`
|
|
4660
|
+
// properties in other contexts.
|
|
4661
|
+
replace: (_match, before, suffix) => `${before}prefix${suffix}`
|
|
4662
|
+
},
|
|
4663
|
+
{
|
|
4664
|
+
id: "RouteMeta-type",
|
|
4665
|
+
description: "`RouteMeta` type \u2192 `OpenApiOperation` (alias removed in 6.0)",
|
|
4666
|
+
// Match `RouteMeta` only as a type position (after `:` or `<` or
|
|
4667
|
+
// `as`) — avoids hitting an unrelated variable named `RouteMeta`.
|
|
4668
|
+
match: /(:\s*|<\s*|\bas\s+)RouteMeta\b/g,
|
|
4669
|
+
replace: "$1OpenApiOperation"
|
|
4670
|
+
},
|
|
4671
|
+
{
|
|
4672
|
+
id: "AppPlugin-type",
|
|
4673
|
+
description: "`AppPlugin` type alias \u2192 `AppConfigurator` (removed in 5.0; runtime accepts 1-arg fns identically)",
|
|
4674
|
+
match: /(:\s*|<\s*|\bas\s+)AppPlugin\b/g,
|
|
4675
|
+
replace: "$1AppConfigurator"
|
|
4676
|
+
}
|
|
4677
|
+
];
|
|
4678
|
+
async function listSourceFiles(rootAbs) {
|
|
4679
|
+
const out = [];
|
|
4680
|
+
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".axiomify", "coverage"]);
|
|
4681
|
+
const walk = async (dir) => {
|
|
4682
|
+
let entries;
|
|
3369
4683
|
try {
|
|
3370
|
-
|
|
3371
|
-
} catch
|
|
4684
|
+
entries = await fs5__default.default.readdir(dir, { withFileTypes: true });
|
|
4685
|
+
} catch {
|
|
4686
|
+
return;
|
|
3372
4687
|
}
|
|
3373
|
-
const
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
4688
|
+
for (const e of entries) {
|
|
4689
|
+
if (e.isDirectory()) {
|
|
4690
|
+
if (skip.has(e.name) || e.name.startsWith(".")) continue;
|
|
4691
|
+
await walk(path7__default.default.join(dir, e.name));
|
|
4692
|
+
} else if (e.isFile()) {
|
|
4693
|
+
const ext = path7__default.default.extname(e.name);
|
|
4694
|
+
if ([".ts", ".tsx", ".js", ".mjs", ".cjs"].includes(ext)) {
|
|
4695
|
+
out.push(path7__default.default.join(dir, e.name));
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
};
|
|
4700
|
+
await walk(rootAbs);
|
|
4701
|
+
return out;
|
|
4702
|
+
}
|
|
4703
|
+
function applyRules(src) {
|
|
4704
|
+
let updated = src;
|
|
4705
|
+
const counts = {};
|
|
4706
|
+
for (const rule of RULES) {
|
|
4707
|
+
const before = updated;
|
|
4708
|
+
if (typeof rule.replace === "string") {
|
|
4709
|
+
updated = updated.replace(rule.match, rule.replace);
|
|
4710
|
+
} else {
|
|
4711
|
+
updated = updated.replace(rule.match, rule.replace);
|
|
4712
|
+
}
|
|
4713
|
+
if (updated !== before) {
|
|
4714
|
+
const matches = before.match(rule.match);
|
|
4715
|
+
counts[rule.id] = matches ? matches.length : 1;
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
return { updated, counts };
|
|
4719
|
+
}
|
|
4720
|
+
function renderUnifiedDiff(file, original, updated) {
|
|
4721
|
+
if (original === updated) return "";
|
|
4722
|
+
const origLines = original.split("\n");
|
|
4723
|
+
const updatedLines = updated.split("\n");
|
|
4724
|
+
const out = [];
|
|
4725
|
+
out.push(pc__default.default.bold(`--- ${file}`));
|
|
4726
|
+
out.push(pc__default.default.bold(`+++ ${file}`));
|
|
4727
|
+
const max = Math.max(origLines.length, updatedLines.length);
|
|
4728
|
+
for (let i = 0; i < max; i++) {
|
|
4729
|
+
const a = origLines[i];
|
|
4730
|
+
const b = updatedLines[i];
|
|
4731
|
+
if (a === b) continue;
|
|
4732
|
+
if (a !== void 0) out.push(pc__default.default.red("- " + a));
|
|
4733
|
+
if (b !== void 0) out.push(pc__default.default.green("+ " + b));
|
|
4734
|
+
}
|
|
4735
|
+
return out.join("\n");
|
|
4736
|
+
}
|
|
4737
|
+
async function runMigrate(opts = {}) {
|
|
4738
|
+
const dir = opts.dir ?? "src";
|
|
4739
|
+
const rootAbs = path7__default.default.resolve(process.cwd(), dir);
|
|
4740
|
+
try {
|
|
4741
|
+
const stat = await fs5__default.default.stat(rootAbs);
|
|
4742
|
+
if (!stat.isDirectory()) throw new Error("not a directory");
|
|
4743
|
+
} catch {
|
|
4744
|
+
console.error(
|
|
4745
|
+
pc__default.default.red(`\u2717 ${dir} does not exist or is not a directory.`),
|
|
4746
|
+
`
|
|
4747
|
+
Run from a project root that contains the directory you want to migrate.`
|
|
4748
|
+
);
|
|
4749
|
+
process.exit(1);
|
|
4750
|
+
}
|
|
4751
|
+
const files = await listSourceFiles(rootAbs);
|
|
4752
|
+
if (files.length === 0) {
|
|
4753
|
+
console.log(`${symbols.info} No source files found under ${pc__default.default.cyan(dir)}.`);
|
|
4754
|
+
return;
|
|
4755
|
+
}
|
|
4756
|
+
const results = [];
|
|
4757
|
+
for (const f of files) {
|
|
4758
|
+
const original = await fs5__default.default.readFile(f, "utf8");
|
|
4759
|
+
const { updated, counts } = applyRules(original);
|
|
4760
|
+
if (Object.keys(counts).length > 0) {
|
|
4761
|
+
results.push({ file: f, counts, original, updated });
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
console.log();
|
|
4765
|
+
console.log(pc__default.default.bold(" \u{1F504} Axiomify v4 \u2192 v5 migration"));
|
|
4766
|
+
console.log(
|
|
4767
|
+
pc__default.default.dim(
|
|
4768
|
+
` Scanned ${pluralise(files.length, "file")} under ${path7__default.default.relative(process.cwd(), rootAbs) || "."}/.
|
|
4769
|
+
`
|
|
4770
|
+
)
|
|
4771
|
+
);
|
|
4772
|
+
if (results.length === 0) {
|
|
4773
|
+
console.log(` ${symbols.ok} Nothing to migrate \u2014 all patterns look up to date.`);
|
|
4774
|
+
console.log();
|
|
4775
|
+
return;
|
|
4776
|
+
}
|
|
4777
|
+
const totalsByRule = {};
|
|
4778
|
+
for (const r of results) {
|
|
4779
|
+
for (const [rule, n] of Object.entries(r.counts)) {
|
|
4780
|
+
totalsByRule[rule] = (totalsByRule[rule] ?? 0) + n;
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
for (const rule of RULES) {
|
|
4784
|
+
const count = totalsByRule[rule.id];
|
|
4785
|
+
if (!count) continue;
|
|
4786
|
+
console.log(
|
|
4787
|
+
` ${pc__default.default.cyan(rule.id)} ${pc__default.default.dim("\u2014")} ${rule.description}`
|
|
4788
|
+
);
|
|
4789
|
+
console.log(
|
|
4790
|
+
` ${symbols.bullet} ${pluralise(count, "change")} across ${pluralise(
|
|
4791
|
+
results.filter((r) => r.counts[rule.id]).length,
|
|
4792
|
+
"file"
|
|
4793
|
+
)}`
|
|
4794
|
+
);
|
|
4795
|
+
}
|
|
4796
|
+
console.log();
|
|
4797
|
+
if (opts.reportOnly) {
|
|
4798
|
+
console.log(pc__default.default.dim(" --report-only: no files were modified."));
|
|
4799
|
+
console.log();
|
|
4800
|
+
return;
|
|
4801
|
+
}
|
|
4802
|
+
if (opts.dryRun) {
|
|
4803
|
+
for (const r of results) {
|
|
4804
|
+
const rel = path7__default.default.relative(process.cwd(), r.file);
|
|
4805
|
+
console.log(renderUnifiedDiff(rel, r.original, r.updated));
|
|
4806
|
+
console.log();
|
|
4807
|
+
}
|
|
4808
|
+
console.log(
|
|
4809
|
+
`${symbols.info} ${pluralise(results.length, "file")} would be modified. Re-run without ${pc__default.default.cyan("--dry-run")} to apply.`
|
|
4810
|
+
);
|
|
4811
|
+
console.log();
|
|
4812
|
+
return;
|
|
4813
|
+
}
|
|
4814
|
+
for (const r of results) {
|
|
4815
|
+
await fs5__default.default.writeFile(r.file, r.updated, "utf8");
|
|
4816
|
+
console.log(` ${symbols.ok} ${pc__default.default.green("Updated")} ${path7__default.default.relative(process.cwd(), r.file)}`);
|
|
4817
|
+
}
|
|
4818
|
+
console.log();
|
|
4819
|
+
console.log(
|
|
4820
|
+
` ${symbols.ok} ${pluralise(results.length, "file")} migrated, ${pluralise(
|
|
4821
|
+
Object.values(totalsByRule).reduce((a, b) => a + b, 0),
|
|
4822
|
+
"total change"
|
|
4823
|
+
)} applied.`
|
|
4824
|
+
);
|
|
4825
|
+
console.log();
|
|
4826
|
+
console.log(pc__default.default.dim(" Manual review needed for:"));
|
|
4827
|
+
console.log(
|
|
4828
|
+
pc__default.default.dim(
|
|
4829
|
+
` ${symbols.bullet} Dangling \`AppPlugin\` / \`RouteMeta\` in import statements \u2014 the codemod renames`
|
|
4830
|
+
)
|
|
4831
|
+
);
|
|
4832
|
+
console.log(
|
|
4833
|
+
pc__default.default.dim(
|
|
4834
|
+
` type USAGES but not the import bindings themselves. TypeScript flags the unused`
|
|
4835
|
+
)
|
|
4836
|
+
);
|
|
4837
|
+
console.log(
|
|
4838
|
+
pc__default.default.dim(
|
|
4839
|
+
` import; remove it (or run \`tsc --noUnusedLocals\` once and let your editor clean up).`
|
|
4840
|
+
)
|
|
4841
|
+
);
|
|
4842
|
+
console.log(
|
|
4843
|
+
pc__default.default.dim(
|
|
4844
|
+
` ${symbols.bullet} 5-arg positional \`SerializerFn\` signatures \u2014 the function body needs by-hand updates`
|
|
4845
|
+
)
|
|
4846
|
+
);
|
|
4847
|
+
console.log(
|
|
4848
|
+
pc__default.default.dim(
|
|
4849
|
+
` ${symbols.bullet} \`new Axiomify()\` callers that relied on automatic \`X-Request-Id\` injection`
|
|
4850
|
+
)
|
|
4851
|
+
);
|
|
4852
|
+
console.log(
|
|
4853
|
+
pc__default.default.dim(
|
|
4854
|
+
` ${symbols.bullet} JWT secrets \u2014 verify they are \u2265 32 BYTES (not chars) per RFC 7518 \xA73.2`
|
|
4855
|
+
)
|
|
4856
|
+
);
|
|
4857
|
+
console.log();
|
|
4858
|
+
console.log(
|
|
4859
|
+
` See ${pc__default.default.cyan("docs/migration-v4-to-v5.md")} for the full guide and ` + pc__default.default.cyan("axiomify check") + " to verify the migrated app.\n" + pc__default.default.yellow(" Note: `openapi:` / `meta:` merges into `schema:` require manual review \u2014 check TODO comments.")
|
|
4860
|
+
);
|
|
4861
|
+
console.log();
|
|
4862
|
+
}
|
|
4863
|
+
async function jsonToYaml(obj) {
|
|
4864
|
+
const emit = (v, indent) => {
|
|
4865
|
+
const pad2 = " ".repeat(indent);
|
|
4866
|
+
if (v === null) return "null";
|
|
4867
|
+
if (typeof v === "boolean" || typeof v === "number") return String(v);
|
|
4868
|
+
if (typeof v === "string") {
|
|
4869
|
+
if (/[:#\n\r\t"'{}[\]&*!|>%@`]|^\s|\s$/.test(v) || v === "") {
|
|
4870
|
+
return JSON.stringify(v);
|
|
4871
|
+
}
|
|
4872
|
+
return v;
|
|
4873
|
+
}
|
|
4874
|
+
if (Array.isArray(v)) {
|
|
4875
|
+
if (v.length === 0) return "[]";
|
|
4876
|
+
return v.map((item) => `
|
|
4877
|
+
${pad2}- ${emit(item, indent + 1).replace(/^/gm, " ").trimStart()}`).join("");
|
|
4878
|
+
}
|
|
4879
|
+
if (typeof v === "object") {
|
|
4880
|
+
const keys = Object.keys(v);
|
|
4881
|
+
if (keys.length === 0) return "{}";
|
|
4882
|
+
return keys.map((k) => {
|
|
4883
|
+
const val = v[k];
|
|
4884
|
+
const rendered = emit(val, indent + 1);
|
|
4885
|
+
if (rendered.startsWith("\n")) return `
|
|
4886
|
+
${pad2}${k}:${rendered}`;
|
|
4887
|
+
return `
|
|
4888
|
+
${pad2}${k}: ${rendered}`;
|
|
4889
|
+
}).join("");
|
|
4890
|
+
}
|
|
4891
|
+
return JSON.stringify(v);
|
|
4892
|
+
};
|
|
4893
|
+
return emit(obj, 0).trimStart();
|
|
4894
|
+
}
|
|
4895
|
+
async function emitOpenApi(entry, opts = {}) {
|
|
4896
|
+
let app;
|
|
4897
|
+
let cleanup = async () => {
|
|
4898
|
+
};
|
|
4899
|
+
try {
|
|
4900
|
+
const loaded = await loadApp(entry);
|
|
4901
|
+
app = loaded.app;
|
|
4902
|
+
cleanup = loaded.cleanup;
|
|
4903
|
+
} catch (err) {
|
|
4904
|
+
console.error(pc__default.default.red("\u2717 Failed to load app:"));
|
|
4905
|
+
console.error(err.message);
|
|
4906
|
+
process.exit(1);
|
|
4907
|
+
}
|
|
4908
|
+
try {
|
|
4909
|
+
let OpenApiGenerator2;
|
|
4910
|
+
try {
|
|
4911
|
+
({ OpenApiGenerator: OpenApiGenerator2 } = await Promise.resolve().then(() => (init_dist(), dist_exports)));
|
|
4912
|
+
} catch {
|
|
3383
4913
|
console.error(
|
|
3384
|
-
"
|
|
4914
|
+
pc__default.default.red("\u2717 @axiomify/openapi is not installed."),
|
|
4915
|
+
"\n Install it:",
|
|
4916
|
+
pc__default.default.cyan("npm install @axiomify/openapi")
|
|
3385
4917
|
);
|
|
3386
4918
|
process.exit(1);
|
|
3387
4919
|
}
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
app
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
const
|
|
4920
|
+
const info = {
|
|
4921
|
+
title: opts.title ?? "API",
|
|
4922
|
+
version: opts.version ?? "1.0.0"
|
|
4923
|
+
};
|
|
4924
|
+
const generator = new OpenApiGenerator2(app, { info });
|
|
4925
|
+
const spec = generator.generate();
|
|
4926
|
+
if (opts.title) spec.info.title = opts.title;
|
|
4927
|
+
if (opts.version) spec.info.version = opts.version;
|
|
4928
|
+
const format = opts.format ?? "json";
|
|
4929
|
+
const serialised = format === "yaml" ? await jsonToYaml(spec) : opts.minify ? JSON.stringify(spec) : JSON.stringify(spec, null, 2);
|
|
4930
|
+
if (opts.output) {
|
|
4931
|
+
const outPath = path7__default.default.resolve(process.cwd(), opts.output);
|
|
4932
|
+
await fs5__default.default.mkdir(path7__default.default.dirname(outPath), { recursive: true });
|
|
4933
|
+
await fs5__default.default.writeFile(outPath, serialised + "\n", "utf8");
|
|
4934
|
+
const routeCount = (app.registeredRoutes ?? []).length;
|
|
3400
4935
|
console.log(
|
|
3401
|
-
`${
|
|
3402
|
-
30
|
|
3403
|
-
)} | ${validationStr}`
|
|
4936
|
+
`${pc__default.default.green("\u2713")} OpenAPI spec written to ${pc__default.default.cyan(opts.output)} ` + pc__default.default.dim(`(${routeCount} route${routeCount === 1 ? "" : "s"}, ${format})`)
|
|
3404
4937
|
);
|
|
3405
|
-
}
|
|
3406
|
-
|
|
4938
|
+
} else {
|
|
4939
|
+
process.stdout.write(serialised + "\n");
|
|
4940
|
+
}
|
|
3407
4941
|
} catch (error) {
|
|
3408
|
-
console.error("\
|
|
4942
|
+
console.error(pc__default.default.red("\u2717 Failed to generate spec:"), error);
|
|
4943
|
+
process.exit(1);
|
|
3409
4944
|
} finally {
|
|
3410
|
-
await
|
|
4945
|
+
await cleanup();
|
|
4946
|
+
}
|
|
4947
|
+
}
|
|
4948
|
+
function normalise(raw, isWs) {
|
|
4949
|
+
const validation = [];
|
|
4950
|
+
if (raw.schema?.body) validation.push("Body");
|
|
4951
|
+
if (raw.schema?.query) validation.push("Query");
|
|
4952
|
+
if (raw.schema?.params) validation.push("Params");
|
|
4953
|
+
if (raw.schema?.response) validation.push("Response");
|
|
4954
|
+
if (raw.schema?.files) validation.push("Files");
|
|
4955
|
+
if (raw.schema?.message) validation.push("Message");
|
|
4956
|
+
const s = raw.schema ?? {};
|
|
4957
|
+
return {
|
|
4958
|
+
method: isWs ? "WS" : raw.method,
|
|
4959
|
+
path: raw.path,
|
|
4960
|
+
validation,
|
|
4961
|
+
tags: Array.isArray(s.tags) ? s.tags : [],
|
|
4962
|
+
operationId: typeof s.operationId === "string" ? s.operationId : void 0,
|
|
4963
|
+
deprecated: s.deprecated === true,
|
|
4964
|
+
timeout: typeof raw.timeout === "number" && raw.timeout > 0 ? raw.timeout : void 0,
|
|
4965
|
+
plugins: Array.isArray(raw.plugins) ? raw.plugins.length : 0,
|
|
4966
|
+
isWs
|
|
4967
|
+
};
|
|
4968
|
+
}
|
|
4969
|
+
function matchesFilter(route, opts) {
|
|
4970
|
+
if (opts.method) {
|
|
4971
|
+
const wanted = opts.method.split(",").map((m) => m.trim().toUpperCase()).filter(Boolean);
|
|
4972
|
+
if (wanted.length && !wanted.includes(route.method)) return false;
|
|
4973
|
+
}
|
|
4974
|
+
if (opts.filter) {
|
|
4975
|
+
const pat = opts.filter;
|
|
4976
|
+
if (pat.includes("*")) {
|
|
4977
|
+
const re = new RegExp(
|
|
4978
|
+
"^" + pat.split("*").map((s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*") + "$"
|
|
4979
|
+
);
|
|
4980
|
+
if (!re.test(route.path)) return false;
|
|
4981
|
+
} else if (!route.path.includes(pat)) {
|
|
4982
|
+
return false;
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
return true;
|
|
4986
|
+
}
|
|
4987
|
+
function sortRoutes(routes, by) {
|
|
4988
|
+
const methodOrder = {
|
|
4989
|
+
GET: 0,
|
|
4990
|
+
POST: 1,
|
|
4991
|
+
PUT: 2,
|
|
4992
|
+
PATCH: 3,
|
|
4993
|
+
DELETE: 4,
|
|
4994
|
+
HEAD: 5,
|
|
4995
|
+
OPTIONS: 6,
|
|
4996
|
+
WS: 7
|
|
4997
|
+
};
|
|
4998
|
+
return [...routes].sort((a, b) => {
|
|
4999
|
+
if (by === "method") {
|
|
5000
|
+
const am = methodOrder[a.method] ?? 99;
|
|
5001
|
+
const bm = methodOrder[b.method] ?? 99;
|
|
5002
|
+
if (am !== bm) return am - bm;
|
|
5003
|
+
return a.path.localeCompare(b.path);
|
|
5004
|
+
}
|
|
5005
|
+
if (a.path !== b.path) return a.path.localeCompare(b.path);
|
|
5006
|
+
return (methodOrder[a.method] ?? 99) - (methodOrder[b.method] ?? 99);
|
|
5007
|
+
});
|
|
5008
|
+
}
|
|
5009
|
+
async function inspectRoutes(entry, opts = {}) {
|
|
5010
|
+
let app;
|
|
5011
|
+
let cleanup = async () => {
|
|
5012
|
+
};
|
|
5013
|
+
try {
|
|
5014
|
+
const loaded = await loadApp(entry);
|
|
5015
|
+
app = loaded.app;
|
|
5016
|
+
cleanup = loaded.cleanup;
|
|
5017
|
+
} catch (err) {
|
|
5018
|
+
console.error(pc__default.default.red("\u2717 Failed to load app:"));
|
|
5019
|
+
console.error(err.message);
|
|
5020
|
+
process.exit(1);
|
|
5021
|
+
}
|
|
5022
|
+
try {
|
|
5023
|
+
const httpRoutes = (app.registeredRoutes ?? []).map(
|
|
5024
|
+
(r) => normalise(r, false)
|
|
5025
|
+
);
|
|
5026
|
+
const wsRoutes = (app.registeredWsRoutes ?? []).map(
|
|
5027
|
+
(r) => normalise(r, true)
|
|
5028
|
+
);
|
|
5029
|
+
const all = sortRoutes([...httpRoutes, ...wsRoutes], opts.sort ?? "path");
|
|
5030
|
+
const filtered = all.filter((r) => matchesFilter(r, opts));
|
|
5031
|
+
if (opts.json) {
|
|
5032
|
+
process.stdout.write(JSON.stringify(filtered, null, 2) + "\n");
|
|
5033
|
+
return;
|
|
5034
|
+
}
|
|
5035
|
+
if (filtered.length === 0) {
|
|
5036
|
+
console.log(
|
|
5037
|
+
"\n" + symbols.info + pc__default.default.dim(
|
|
5038
|
+
` No routes match the current filter (${all.length} total registered).
|
|
5039
|
+
`
|
|
5040
|
+
)
|
|
5041
|
+
);
|
|
5042
|
+
return;
|
|
5043
|
+
}
|
|
5044
|
+
console.log();
|
|
5045
|
+
console.log(pc__default.default.bold(" \u{1F9ED} Axiomify routes"));
|
|
5046
|
+
console.log();
|
|
5047
|
+
const columns = [
|
|
5048
|
+
{ header: "METHOD", minWidth: 7 },
|
|
5049
|
+
{ header: "PATH", minWidth: 20, maxWidth: 60 },
|
|
5050
|
+
{ header: "VALIDATION", minWidth: 10, maxWidth: 32 },
|
|
5051
|
+
{ header: "META", maxWidth: 40 }
|
|
5052
|
+
];
|
|
5053
|
+
const rows = filtered.map((r) => {
|
|
5054
|
+
const method = colourMethod(r.method);
|
|
5055
|
+
const path11 = r.deprecated ? pc__default.default.strikethrough(r.path) + " " + badge.deprecated() : r.path;
|
|
5056
|
+
const validation = r.validation.length > 0 ? r.validation.map(badge.validation).join(pc__default.default.dim(",")) : pc__default.default.dim("\u2014");
|
|
5057
|
+
const metaBits = [];
|
|
5058
|
+
if (r.operationId) metaBits.push(pc__default.default.dim(`op:`) + r.operationId);
|
|
5059
|
+
if (r.tags.length) metaBits.push(badge.tags(r.tags));
|
|
5060
|
+
if (r.timeout !== void 0) metaBits.push(badge.timeout(r.timeout));
|
|
5061
|
+
if (r.plugins > 0) metaBits.push(pc__default.default.dim(`+${r.plugins} plugin${r.plugins === 1 ? "" : "s"}`));
|
|
5062
|
+
const meta = metaBits.length ? metaBits.join(" ") : pc__default.default.dim("\u2014");
|
|
5063
|
+
return [method, path11, validation, meta];
|
|
3411
5064
|
});
|
|
5065
|
+
console.log(renderTable(columns, rows));
|
|
5066
|
+
const byMethod = filtered.reduce((acc, r) => {
|
|
5067
|
+
acc[r.method] = (acc[r.method] ?? 0) + 1;
|
|
5068
|
+
return acc;
|
|
5069
|
+
}, {});
|
|
5070
|
+
const summaryParts = Object.entries(byMethod).sort(([a], [b]) => a.localeCompare(b)).map(([m, n]) => `${colourMethod(m).trimEnd()} ${pc__default.default.bold(String(n))}`);
|
|
5071
|
+
console.log();
|
|
5072
|
+
console.log(
|
|
5073
|
+
` ${symbols.ok} ${pluralise(filtered.length, "route")}` + (filtered.length < all.length ? pc__default.default.dim(` (filtered from ${all.length})`) : "") + " " + summaryParts.join(pc__default.default.dim(" \xB7 "))
|
|
5074
|
+
);
|
|
5075
|
+
const filteredWs = filtered.filter((r) => r.isWs).length;
|
|
5076
|
+
if (filteredWs > 0) {
|
|
5077
|
+
console.log(
|
|
5078
|
+
pc__default.default.dim(` \u2514 ${pluralise(filteredWs, "WebSocket route")} included`)
|
|
5079
|
+
);
|
|
5080
|
+
}
|
|
5081
|
+
console.log();
|
|
5082
|
+
} catch (error) {
|
|
5083
|
+
console.error(pc__default.default.red("\u2717 Failed to inspect routes:"), error);
|
|
5084
|
+
process.exit(1);
|
|
5085
|
+
} finally {
|
|
5086
|
+
await cleanup();
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5089
|
+
var VALID_METHODS = /* @__PURE__ */ new Set([
|
|
5090
|
+
"GET",
|
|
5091
|
+
"POST",
|
|
5092
|
+
"PUT",
|
|
5093
|
+
"PATCH",
|
|
5094
|
+
"DELETE",
|
|
5095
|
+
"OPTIONS",
|
|
5096
|
+
"HEAD",
|
|
5097
|
+
"WS"
|
|
5098
|
+
]);
|
|
5099
|
+
function pathToFilename(routePath) {
|
|
5100
|
+
const cleaned = routePath.split("/").filter(Boolean).map((seg) => seg.startsWith(":") ? `by-${seg.slice(1)}` : seg).join("-");
|
|
5101
|
+
return cleaned || "root";
|
|
5102
|
+
}
|
|
5103
|
+
function generateRouteSource(method, routePath, opts) {
|
|
5104
|
+
const isWs = method === "WS";
|
|
5105
|
+
const params = routePath.match(/:[a-zA-Z_][a-zA-Z0-9_]*/g) ?? [];
|
|
5106
|
+
const paramKeys = params.map((p) => p.slice(1));
|
|
5107
|
+
const plugins = [];
|
|
5108
|
+
const extraImports = [];
|
|
5109
|
+
if (opts.auth) {
|
|
5110
|
+
plugins.push("requireAuth");
|
|
5111
|
+
extraImports.push(
|
|
5112
|
+
`import { createAuthPlugin } from '@axiomify/auth';
|
|
5113
|
+
|
|
5114
|
+
const requireAuth = createAuthPlugin({
|
|
5115
|
+
secret: process.env.JWT_SECRET!,
|
|
5116
|
+
});`
|
|
5117
|
+
);
|
|
5118
|
+
}
|
|
5119
|
+
if (opts.rateLimit) {
|
|
5120
|
+
plugins.push("limiter");
|
|
5121
|
+
extraImports.push(
|
|
5122
|
+
`import { createRateLimitPlugin, MemoryStore } from '@axiomify/rate-limit';
|
|
5123
|
+
|
|
5124
|
+
// Replace MemoryStore with RedisStore for multi-process / multi-host.
|
|
5125
|
+
const limiter = createRateLimitPlugin({
|
|
5126
|
+
windowMs: 60_000,
|
|
5127
|
+
max: 100,
|
|
5128
|
+
store: new MemoryStore(),
|
|
5129
|
+
});`
|
|
5130
|
+
);
|
|
5131
|
+
}
|
|
5132
|
+
if (isWs) {
|
|
5133
|
+
return [
|
|
5134
|
+
`import type { Axiomify } from '@axiomify/core';`,
|
|
5135
|
+
`import { z } from 'zod';`,
|
|
5136
|
+
extraImports.length ? extraImports.join("\n\n") + "\n" : "",
|
|
5137
|
+
`/**`,
|
|
5138
|
+
` * Registers WebSocket route ${routePath}.`,
|
|
5139
|
+
` * Wire this into your entry file:`,
|
|
5140
|
+
` * import { registerRoute } from './routes/${pathToFilename(routePath)}';`,
|
|
5141
|
+
` * registerRoute(app);`,
|
|
5142
|
+
` */`,
|
|
5143
|
+
`export function registerRoute(app: Axiomify): void {`,
|
|
5144
|
+
` app.ws({`,
|
|
5145
|
+
` path: '${routePath}',`,
|
|
5146
|
+
paramKeys.length > 0 ? ` schema: {
|
|
5147
|
+
params: z.object({ ${paramKeys.map((k) => `${k}: z.string()`).join(", ")} }),
|
|
5148
|
+
// Define your message shape here \u2014 runtime-validated on every incoming frame.
|
|
5149
|
+
message: z.object({
|
|
5150
|
+
text: z.string(),
|
|
5151
|
+
}),
|
|
5152
|
+
},` : ` schema: {
|
|
5153
|
+
// Define your message shape here \u2014 runtime-validated on every incoming frame.
|
|
5154
|
+
message: z.object({
|
|
5155
|
+
text: z.string(),
|
|
5156
|
+
}),
|
|
5157
|
+
},`,
|
|
5158
|
+
plugins.length > 0 ? ` plugins: [${plugins.join(", ")}],` : "",
|
|
5159
|
+
` open: (client, _req) => {`,
|
|
5160
|
+
` client.send({ type: 'welcome' });`,
|
|
5161
|
+
` },`,
|
|
5162
|
+
` message: (client, data) => {`,
|
|
5163
|
+
` // \`data\` is typed and validated from the schema above.`,
|
|
5164
|
+
` client.send({ echo: data.text });`,
|
|
5165
|
+
` },`,
|
|
5166
|
+
` close: (_client, code, reason) => {`,
|
|
5167
|
+
` console.log('connection closed', code, reason);`,
|
|
5168
|
+
` },`,
|
|
5169
|
+
` });`,
|
|
5170
|
+
`}`,
|
|
5171
|
+
``
|
|
5172
|
+
].filter(Boolean).join("\n");
|
|
5173
|
+
}
|
|
5174
|
+
return [
|
|
5175
|
+
`import type { Axiomify } from '@axiomify/core';`,
|
|
5176
|
+
`import { z } from 'zod';`,
|
|
5177
|
+
extraImports.length ? extraImports.join("\n\n") + "\n" : "",
|
|
5178
|
+
`/**`,
|
|
5179
|
+
` * Registers ${method} ${routePath}.`,
|
|
5180
|
+
` * Wire this into your entry file:`,
|
|
5181
|
+
` * import { registerRoute } from './routes/${pathToFilename(routePath)}';`,
|
|
5182
|
+
` * registerRoute(app);`,
|
|
5183
|
+
` */`,
|
|
5184
|
+
`export function registerRoute(app: Axiomify): void {`,
|
|
5185
|
+
` app.route({`,
|
|
5186
|
+
` method: '${method}',`,
|
|
5187
|
+
` path: '${routePath}',`,
|
|
5188
|
+
` schema: {`,
|
|
5189
|
+
paramKeys.length > 0 ? ` params: z.object({ ${paramKeys.map((k) => `${k}: z.string()`).join(", ")} }),` : "",
|
|
5190
|
+
method === "POST" || method === "PUT" || method === "PATCH" ? ` body: z.object({
|
|
5191
|
+
// TODO \u2014 define request body shape
|
|
5192
|
+
}),` : "",
|
|
5193
|
+
` // response: z.object({ /* response shape */ }),`,
|
|
5194
|
+
` },`,
|
|
5195
|
+
` // OpenAPI metadata (tags, summary, operationId etc.) lives in schema: too`,
|
|
5196
|
+
` tags: ['${pathToFilename(routePath).split("-")[0] || "general"}'],`,
|
|
5197
|
+
` summary: '${method} ${routePath}',`,
|
|
5198
|
+
plugins.length > 0 ? ` plugins: [${plugins.join(", ")}],` : "",
|
|
5199
|
+
` handler: async (${paramKeys.length > 0 || method !== "GET" ? "req" : "_req"}, res) => {`,
|
|
5200
|
+
method === "POST" ? ` // TODO \u2014 handler logic
|
|
5201
|
+
res.status(201).send({ ok: true });` : method === "DELETE" ? ` // TODO \u2014 handler logic
|
|
5202
|
+
res.status(204).send(null);` : ` // TODO \u2014 handler logic
|
|
5203
|
+
res.send({ ok: true });`,
|
|
5204
|
+
` },`,
|
|
5205
|
+
` });`,
|
|
5206
|
+
`}`,
|
|
5207
|
+
``
|
|
5208
|
+
].filter(Boolean).join("\n");
|
|
5209
|
+
}
|
|
5210
|
+
async function scaffoldRoute(method, routePath, opts = {}) {
|
|
5211
|
+
const upperMethod = method.toUpperCase();
|
|
5212
|
+
if (!VALID_METHODS.has(upperMethod)) {
|
|
5213
|
+
console.error(
|
|
5214
|
+
pc__default.default.red(`\u2717 Invalid method "${method}".`),
|
|
5215
|
+
`Expected one of: ${[...VALID_METHODS].join(", ")}.`
|
|
5216
|
+
);
|
|
5217
|
+
process.exit(1);
|
|
5218
|
+
}
|
|
5219
|
+
if (!routePath.startsWith("/")) {
|
|
5220
|
+
console.error(
|
|
5221
|
+
pc__default.default.red('\u2717 Path must start with "/".'),
|
|
5222
|
+
`Got: ${routePath}`
|
|
5223
|
+
);
|
|
5224
|
+
process.exit(1);
|
|
5225
|
+
}
|
|
5226
|
+
const dir = opts.dir ?? "src/routes";
|
|
5227
|
+
const filename = pathToFilename(routePath) + ".ts";
|
|
5228
|
+
const fileAbs = path7__default.default.resolve(process.cwd(), dir, filename);
|
|
5229
|
+
const source = generateRouteSource(upperMethod, routePath, opts);
|
|
5230
|
+
if (opts.dryRun) {
|
|
5231
|
+
console.log(pc__default.default.dim(`# would write ${path7__default.default.relative(process.cwd(), fileAbs)}
|
|
5232
|
+
`));
|
|
5233
|
+
console.log(source);
|
|
5234
|
+
return;
|
|
5235
|
+
}
|
|
5236
|
+
let exists = false;
|
|
5237
|
+
try {
|
|
5238
|
+
await fs5__default.default.access(fileAbs);
|
|
5239
|
+
exists = true;
|
|
5240
|
+
} catch {
|
|
3412
5241
|
}
|
|
5242
|
+
if (exists && !opts.force) {
|
|
5243
|
+
console.log(
|
|
5244
|
+
`${symbols.warn} ${pc__default.default.yellow("Already exists:")} ${path7__default.default.relative(process.cwd(), fileAbs)}
|
|
5245
|
+
Pass ${pc__default.default.cyan("--force")} to overwrite, or pick a different path.`
|
|
5246
|
+
);
|
|
5247
|
+
return;
|
|
5248
|
+
}
|
|
5249
|
+
await fs5__default.default.mkdir(path7__default.default.dirname(fileAbs), { recursive: true });
|
|
5250
|
+
await fs5__default.default.writeFile(fileAbs, source, "utf8");
|
|
5251
|
+
console.log();
|
|
5252
|
+
console.log(
|
|
5253
|
+
`${symbols.ok} ${pc__default.default.green("Created")} ${pc__default.default.cyan(path7__default.default.relative(process.cwd(), fileAbs))}`
|
|
5254
|
+
);
|
|
5255
|
+
console.log();
|
|
5256
|
+
console.log(pc__default.default.dim(" Next steps:"));
|
|
5257
|
+
console.log(
|
|
5258
|
+
` 1. Wire it into your entry file:
|
|
5259
|
+
` + pc__default.default.dim(` import { registerRoute } from './routes/${pathToFilename(routePath)}';
|
|
5260
|
+
`) + pc__default.default.dim(` registerRoute(app);`)
|
|
5261
|
+
);
|
|
5262
|
+
console.log(
|
|
5263
|
+
` 2. Fill in the TODOs in ${pc__default.default.cyan(path7__default.default.relative(process.cwd(), fileAbs))}.`
|
|
5264
|
+
);
|
|
5265
|
+
console.log(
|
|
5266
|
+
` 3. Verify with ${pc__default.default.cyan("npx axiomify routes")} and ${pc__default.default.cyan("npx axiomify check")}.`
|
|
5267
|
+
);
|
|
5268
|
+
console.log();
|
|
3413
5269
|
}
|
|
3414
5270
|
|
|
3415
5271
|
// src/index.ts
|
|
@@ -3420,5 +5276,37 @@ program2.command("init").description("Bootstrap a new Axiomify project").argumen
|
|
|
3420
5276
|
);
|
|
3421
5277
|
program2.command("dev").description("Start the development server with hot-reload").argument("[entry]", "Entry file", "src/index.ts").action(devServer);
|
|
3422
5278
|
program2.command("build").description("Compile the application for production").argument("[entry]", "Entry file", "src/index.ts").action(buildProject);
|
|
3423
|
-
program2.command("routes").description("Inspect and list all registered
|
|
5279
|
+
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(
|
|
5280
|
+
"-m, --method <list>",
|
|
5281
|
+
"Comma-separated list of methods to include (e.g. GET,POST,WS)"
|
|
5282
|
+
).option(
|
|
5283
|
+
"-f, --filter <pattern>",
|
|
5284
|
+
'Path filter \u2014 substring match, or glob with "*" (e.g. /api/v1/*)'
|
|
5285
|
+
).option(
|
|
5286
|
+
"-s, --sort <by>",
|
|
5287
|
+
'Sort routes by "method" or "path"',
|
|
5288
|
+
"path"
|
|
5289
|
+
).action(
|
|
5290
|
+
(entry, options) => inspectRoutes(entry, options)
|
|
5291
|
+
);
|
|
5292
|
+
program2.command("openapi").description("Generate the OpenAPI spec from the app and emit it").argument("[entry]", "Entry file", "src/index.ts").option(
|
|
5293
|
+
"-o, --output <file>",
|
|
5294
|
+
"Write the spec to this file path instead of stdout"
|
|
5295
|
+
).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(
|
|
5296
|
+
(entry, options) => emitOpenApi(entry, {
|
|
5297
|
+
...options,
|
|
5298
|
+
// Map the CLI flag name (`spec-version` → camel `specVersion`) onto
|
|
5299
|
+
// the internal `version` field that emitOpenApi() expects.
|
|
5300
|
+
version: options.specVersion
|
|
5301
|
+
})
|
|
5302
|
+
);
|
|
5303
|
+
program2.command("check").description("Run a static production-readiness audit against the app").argument("[entry]", "Entry file", "src/index.ts").action(runCheck);
|
|
5304
|
+
program2.command("doctor").description("Diagnose the host environment (Node, uWS, ports, dep drift)").action(runDoctor);
|
|
5305
|
+
var scaffold = program2.command("scaffold").description("Generate boilerplate (routes, modules, plugins)");
|
|
5306
|
+
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(
|
|
5307
|
+
(method, routePath, options) => scaffoldRoute(method, routePath, options)
|
|
5308
|
+
);
|
|
5309
|
+
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(
|
|
5310
|
+
(options) => runMigrate(options)
|
|
5311
|
+
);
|
|
3424
5312
|
program2.parse(process.argv);
|