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