@nanoforge-dev/cli 1.5.3-beta.8113568 → 1.5.4-beta.2af80f5

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/nf.js CHANGED
@@ -4,7 +4,7 @@ import "reflect-metadata";
4
4
  import { execSync, spawn } from "node:child_process";
5
5
  import fs, { existsSync } from "fs";
6
6
  import { join, posix, resolve } from "path";
7
- import { bgRgb, bold, green, red, yellow } from "ansis";
7
+ import { bgRgb, bold, cyan, green, red, yellow } from "ansis";
8
8
  import { get } from "node-emoji";
9
9
  import ora from "ora";
10
10
  import { watch } from "chokidar";
@@ -232,12 +232,79 @@ const Prefixes = {
232
232
  //#region src/lib/ui/spinner.ts
233
233
  const getSpinner = (message) => ora({ text: message });
234
234
  //#endregion
235
+ //#region src/lib/utils/errors.ts
236
+ var CLIError = class extends Error {
237
+ suggestion;
238
+ constructor(message, suggestion) {
239
+ super(message);
240
+ this.name = this.constructor.name;
241
+ this.suggestion = suggestion;
242
+ Object.setPrototypeOf(this, new.target.prototype);
243
+ }
244
+ };
245
+ var ConfigNotFoundError = class extends CLIError {
246
+ constructor(configPath) {
247
+ super(`Configuration file not found at path: ${configPath}.`, "Please run 'nf new' or provide a valid --config path.");
248
+ }
249
+ };
250
+ var InvalidCommandArgumentError = class extends CLIError {
251
+ constructor(argName, expected) {
252
+ super(`Invalid argument '${argName}'. Expected: ${expected}.`, "Verify the command syntax using the --help flag.");
253
+ }
254
+ };
255
+ var RegistryAuthenticationError = class extends CLIError {
256
+ constructor() {
257
+ super("You must be logged in to perform this action.", "Run 'nf login' to authenticate.");
258
+ }
259
+ };
260
+ var ManifestError = class extends CLIError {
261
+ constructor(detail) {
262
+ super(`Manifest Error: ${detail}`, "Check your nanoforge.manifest.json file for syntax or formatting errors.");
263
+ }
264
+ };
265
+ var FileSystemError = class extends CLIError {
266
+ constructor(action, targetPath) {
267
+ super(`File System Error [${action}]: ${targetPath}`, "Verify your file permissions and ensure the path exists.");
268
+ }
269
+ };
270
+ var ApiRequestError = class extends CLIError {
271
+ constructor(status, cause) {
272
+ const causeStr = cause && typeof cause === "object" ? JSON.stringify(cause, null, 2) : cause;
273
+ super(`API Request failed (Status ${status})${causeStr ? `\nDetails: ${causeStr}` : ""}`, "Check your network connection, API key, or the registry status.");
274
+ }
275
+ };
276
+ const getErrorString = (error) => {
277
+ const stack = error.stack ? error.stack : error.message;
278
+ const cause = error.cause && typeof error.cause === "object" ? JSON.stringify(error.cause, null, 2) : error.cause;
279
+ return `${stack}${cause ? `\n${cause}` : ""}`;
280
+ };
281
+ const getErrorMessage = (error) => {
282
+ if (error instanceof Error) return getErrorString(error);
283
+ if (typeof error === "string") return error;
284
+ };
285
+ const handleActionError = (context, error) => {
286
+ console.error();
287
+ console.error(red(context));
288
+ if (error instanceof CLIError) {
289
+ console.error(error.message);
290
+ if (error.suggestion) console.info(cyan(`\nšŸ’” Suggestion: ${error.suggestion}`));
291
+ process.exit(1);
292
+ }
293
+ const msg = getErrorMessage(error);
294
+ if (msg) console.error(msg);
295
+ process.exit(1);
296
+ };
297
+ const promptError = (err) => {
298
+ if (err.name === "ExitPromptError") process.exit(1);
299
+ throw err;
300
+ };
301
+ //#endregion
235
302
  //#region src/lib/input/base-inputs.ts
236
303
  const getStringInput = (input, field) => {
237
304
  const value = input.get(field)?.value;
238
305
  if (value === void 0) return void 0;
239
306
  if (typeof value === "string") return value;
240
- throw new Error(`Invalid type for ${field}`);
307
+ throw new InvalidCommandArgumentError(field, "string");
241
308
  };
242
309
  const getStringInputWithDefault = (input, field, defaultValue) => {
243
310
  return getStringInput(input, field) ?? defaultValue;
@@ -246,7 +313,7 @@ const getBooleanInput = (input, field) => {
246
313
  const value = input.get(field)?.value;
247
314
  if (value === void 0) return void 0;
248
315
  if (typeof value === "boolean") return value;
249
- throw new Error(`Invalid type for ${field}`);
316
+ throw new InvalidCommandArgumentError(field, "boolean");
250
317
  };
251
318
  const getBooleanInputWithDefault = (input, field, defaultValue) => {
252
319
  return getBooleanInput(input, field) ?? defaultValue;
@@ -255,7 +322,7 @@ const getArrayInput = (input, field) => {
255
322
  const value = input.get(field)?.value;
256
323
  if (value === void 0) return void 0;
257
324
  if (typeof value === "object" && Array.isArray(value)) return value;
258
- throw new Error(`Invalid type for ${field}`);
325
+ throw new InvalidCommandArgumentError(field, "array");
259
326
  };
260
327
  //#endregion
261
328
  //#region src/lib/input/ask-inputs.ts
@@ -264,7 +331,7 @@ const getInputOrAsk = async (baseInput, askCb, defaultValue) => {
264
331
  const res = await askCb();
265
332
  if (res !== void 0) return res;
266
333
  if (defaultValue !== void 0) return defaultValue;
267
- throw new Error("No input provided");
334
+ throw new CLIError("No input provided. Please provide a valid value.");
268
335
  };
269
336
  //#endregion
270
337
  //#region src/lib/input/inputs/directory.input.ts
@@ -283,28 +350,6 @@ const getEditorInput = (inputs) => {
283
350
  return getBooleanInputWithDefault(inputs, "editor", false);
284
351
  };
285
352
  //#endregion
286
- //#region src/lib/utils/errors.ts
287
- const getErrorMessage = (error) => {
288
- if (error instanceof Error) return getErrorString(error);
289
- if (typeof error === "string") return error;
290
- };
291
- const getErrorString = (error) => {
292
- const stack = error.stack ? error.stack : error.message;
293
- const cause = error.cause && typeof error.cause === "object" ? JSON.stringify(error.cause, null, 2) : error.cause;
294
- return `${stack}${cause ? `\n${cause}` : ""}`;
295
- };
296
- const handleActionError = (context, error) => {
297
- console.error();
298
- console.error(red(context));
299
- const msg = getErrorMessage(error);
300
- if (msg) console.error(msg);
301
- process.exit(1);
302
- };
303
- const promptError = (err) => {
304
- if (err.name === "ExitPromptError") process.exit(1);
305
- throw err;
306
- };
307
- //#endregion
308
353
  //#region src/lib/question/questions/confirm.question.ts
309
354
  const askConfirm = async (question, baseOptions) => {
310
355
  return await confirm({
@@ -396,7 +441,7 @@ const getWatchInput = (inputs) => {
396
441
  const getCreateTypeInput = (inputs) => {
397
442
  const res = getStringInput(inputs, "type");
398
443
  if (res && ["component", "system"].includes(res)) return res;
399
- throw new Error("Invalid type. Please enter 'component' or 'system'.");
444
+ throw new InvalidCommandArgumentError("type", "'component' or 'system'");
400
445
  };
401
446
  //#endregion
402
447
  //#region src/lib/input/inputs/dev/generate.input.ts
@@ -532,7 +577,7 @@ const resolveCLINodeBinaryPath = (name) => {
532
577
  base = join(base, "..");
533
578
  }
534
579
  }
535
- throw new Error("Could not find module path");
580
+ throw new FileSystemError("resolve binary", name);
536
581
  };
537
582
  //#endregion
538
583
  //#region src/lib/utils/spinner.ts
@@ -651,7 +696,7 @@ var PackageManager = class {
651
696
  return (await withSpinner(() => this.exec(args, directory), Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS, Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(), Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(this.formatFailCommand(args)))).success;
652
697
  }
653
698
  assertSupports(feature) {
654
- if (!this.commands[feature]) throw new Error(`Package manager "${this.name}" does not support "${feature}"`);
699
+ if (!this.commands[feature]) throw new CLIError(`Package manager "${this.name}" does not support "${feature}"`);
655
700
  }
656
701
  buildRunArgs(script, params, flags, silent) {
657
702
  const args = [...flags, this.commands.run];
@@ -662,7 +707,7 @@ var PackageManager = class {
662
707
  return args.concat(params);
663
708
  }
664
709
  buildRunFileArgs(script, params, flags, silent) {
665
- if (!this.commands.runFile) throw new Error("Package manager does not support runFile");
710
+ if (!this.commands.runFile) throw new CLIError("Package manager does not support runFile");
666
711
  const args = [...flags, this.commands.runFile];
667
712
  if (silent) args.push(this.commands.silentFlag);
668
713
  args.push(script);
@@ -776,7 +821,7 @@ var RunnerFactory = class {
776
821
  try {
777
822
  return getModulePath("@angular-devkit/schematics-cli/bin/schematics.js");
778
823
  } catch {
779
- throw new Error("'schematics' binary path could not be found!");
824
+ throw new CLIError("'schematics' binary path could not be found!");
780
825
  }
781
826
  }
782
827
  };
@@ -868,7 +913,7 @@ const LOCK_FILE_MAP = {
868
913
  var PackageManagerFactory = class {
869
914
  static create(name) {
870
915
  const config = PM_CONFIGS[name];
871
- if (!config) throw new Error(`Package manager ${name} is not managed.`);
916
+ if (!config) throw new CLIError(`Package manager '${name}' is not managed/supported.`);
872
917
  const runner = this.createRunner(name, config.binary);
873
918
  return new PackageManager(name, config.commands, runner);
874
919
  }
@@ -892,7 +937,7 @@ var PackageManagerFactory = class {
892
937
  //#region src/lib/utils/files.ts
893
938
  const copyFiles = (from, to) => {
894
939
  if (!fs.existsSync(from)) return;
895
- if (!fs.existsSync(to)) throw new Error(`Directory ${to} does not exist`);
940
+ if (!fs.existsSync(to)) throw new FileSystemError("directory not found", to);
896
941
  fs.readdirSync(from, { recursive: true }).forEach((file) => {
897
942
  fs.copyFileSync(join(from, file.toString()), join(to, file.toString()));
898
943
  });
@@ -1119,7 +1164,7 @@ const getConfigPath = (directory, name) => {
1119
1164
  const path = join$1(directory, n);
1120
1165
  if (existsSync$1(path)) return path;
1121
1166
  }
1122
- throw new Error(`No config file found in directory: ${directory}`);
1167
+ throw new ConfigNotFoundError(join$1(directory, CONFIG_FILE_NAME));
1123
1168
  }
1124
1169
  };
1125
1170
  const loadConfig = async (directory, name, noThrow = false) => {
@@ -1131,10 +1176,10 @@ const loadConfig = async (directory, name, noThrow = false) => {
1131
1176
  } catch {
1132
1177
  rawData = noThrow ? CONFIG_DEFAULTS : null;
1133
1178
  }
1134
- if (!rawData) throw new Error(`Not able to read config file : ${path}`);
1179
+ if (!rawData) throw new FileSystemError("read config file", path);
1135
1180
  const data = plainToInstance(Config, rawData, { excludeExtraneousValues: true });
1136
1181
  const errors = await validate(data);
1137
- if (errors.length > 0) throw new Error(`Invalid config :\n${errors.toString().replace(/,/g, "\n")}`);
1182
+ if (errors.length > 0) throw new CLIError(`Invalid config:\n${errors.toString().replace(/,/g, "\n")}`);
1138
1183
  config = data;
1139
1184
  return config;
1140
1185
  };
@@ -1324,7 +1369,7 @@ var NanoforgeCollection = class NanoforgeCollection extends AbstractCollection {
1324
1369
  }
1325
1370
  validate(name) {
1326
1371
  const schematic = NanoforgeCollection.schematics.find((s) => s.name === name || s.alias === name);
1327
- if (schematic === void 0 || schematic === null) throw new Error(`Invalid schematic "${name}". Please, ensure that "${name}" exists in this collection.`);
1372
+ if (schematic === void 0 || schematic === null) throw new CLIError(`Invalid schematic "${name}". Please, ensure that "${name}" exists in this collection.`);
1328
1373
  return schematic.name;
1329
1374
  }
1330
1375
  };
@@ -1334,7 +1379,7 @@ var CollectionFactory = class {
1334
1379
  static create(collection, directory) {
1335
1380
  const schematicRunner = RunnerFactory.createSchematic();
1336
1381
  if (collection === "@nanoforge-dev/schematics") return new NanoforgeCollection(schematicRunner, directory);
1337
- throw new Error(`Unknown collection: ${collection}`);
1382
+ throw new CLIError(`Unknown collection: ${collection}`);
1338
1383
  }
1339
1384
  };
1340
1385
  //#endregion
@@ -1428,20 +1473,34 @@ var DevAction = class extends AbstractAction {
1428
1473
  async handle(_args, options) {
1429
1474
  const directory = getDirectoryInput(options);
1430
1475
  const generate = getDevGenerateInput(options);
1431
- const tasks = this.buildTaskList(directory, generate);
1476
+ const editor = getEditorInput(options);
1477
+ const tasks = this.buildTaskList(directory, generate, editor);
1432
1478
  await Promise.all(tasks);
1433
1479
  return { keepAlive: true };
1434
1480
  }
1435
- buildTaskList(directory, generate) {
1481
+ buildTaskList(directory, generate, editor) {
1436
1482
  const tasks = [];
1437
- if (generate) tasks.push(this.runSubCommand("generate", directory, { silent: true }));
1438
- tasks.push(this.runSubCommand("build", directory, { silent: true }));
1483
+ const extraFlags = editor ? ["--editor"] : [];
1484
+ if (generate) tasks.push(this.runSubCommand("generate", directory, {
1485
+ silent: true,
1486
+ extraFlags
1487
+ }));
1488
+ tasks.push(this.runSubCommand("build", directory, {
1489
+ silent: true,
1490
+ extraFlags
1491
+ }));
1439
1492
  tasks.push(this.runSubCommand("start", directory, { silent: false }));
1440
1493
  return tasks;
1441
1494
  }
1442
1495
  async runSubCommand(command, directory, options) {
1443
1496
  await runSafe(async () => {
1444
- await (await PackageManagerFactory.find(directory)).runDev(directory, "nf", {}, [command, "--watch"], options.silent);
1497
+ const packageManager = await PackageManagerFactory.find(directory);
1498
+ const args = [
1499
+ command,
1500
+ "--watch",
1501
+ ...options.extraFlags ?? []
1502
+ ];
1503
+ await packageManager.runDev(directory, "nf", {}, args, options.silent);
1445
1504
  });
1446
1505
  }
1447
1506
  };
@@ -1669,27 +1728,24 @@ var Repository = class {
1669
1728
  async runRequest(request, path, options) {
1670
1729
  const res = await this._client[request](path, options);
1671
1730
  const data = await res.json();
1672
- if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { cause: data["error"] });
1731
+ if (!res.ok) throw new ApiRequestError(res.status, data["error"]);
1673
1732
  return data;
1674
1733
  }
1675
1734
  async runFileRequest(request, path, options) {
1676
1735
  const res = await this._client[request](path, options);
1677
- if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { cause: (await res.json())["error"] });
1736
+ if (!res.ok) throw new ApiRequestError(res.status, (await res.json())["error"]);
1678
1737
  return await res.blob();
1679
1738
  }
1680
1739
  async runRequestBody(request, path, body, options) {
1681
1740
  const res = await this._client[request](path, body === void 0 ? void 0 : body instanceof FormData ? body : JSON.stringify(body), options);
1682
1741
  const data = await res.json();
1683
- if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { cause: data["error"] });
1742
+ if (!res.ok) throw new ApiRequestError(res.status, data["error"]);
1684
1743
  return data;
1685
1744
  }
1686
1745
  };
1687
1746
  new Repository(new HttpClient("https://api.nanoforge.eu"));
1688
1747
  const withAuth = (apiKey, force = false, headers = { "Content-Type": "application/json" }) => {
1689
- if (!apiKey && force) {
1690
- console.error("No registry key found. Please use `nf login` to login");
1691
- throw new Error("No apikey found. Please use `nf login` to login");
1692
- }
1748
+ if (!apiKey && force) throw new RegistryAuthenticationError();
1693
1749
  return new Repository(new HttpClient("https://api.nanoforge.eu", { headers: {
1694
1750
  Authorization: apiKey,
1695
1751
  ...headers
@@ -1765,12 +1821,12 @@ var Registry = class {
1765
1821
  }
1766
1822
  static _getPackageFile(filename, dir) {
1767
1823
  const path = join(getCwd(dir ?? "."), filename);
1768
- if (!fs.existsSync(path)) throw new Error("Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.package`!");
1824
+ if (!fs.existsSync(path)) throw new CLIError("Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.package`!");
1769
1825
  try {
1770
1826
  fs.accessSync(path, fs.constants.R_OK);
1771
1827
  return fs.openAsBlob(path);
1772
1828
  } catch {
1773
- throw new Error("Cannot read package file, please verify your file permissions!");
1829
+ throw new CLIError("Cannot read package file, please verify your file permissions!");
1774
1830
  }
1775
1831
  }
1776
1832
  };
@@ -2077,7 +2133,7 @@ const getManifestPath = (directory) => {
2077
2133
  const path = join$1(directory, n);
2078
2134
  if (existsSync$1(path)) return path;
2079
2135
  }
2080
- throw new Error(`No manifest file found in directory: ${directory}`);
2136
+ throw new ManifestError(`No manifest file found in directory: ${directory}`);
2081
2137
  };
2082
2138
  const loadManifest = async (directory) => {
2083
2139
  let rawData;
@@ -2087,10 +2143,10 @@ const loadManifest = async (directory) => {
2087
2143
  } catch {
2088
2144
  rawData = null;
2089
2145
  }
2090
- if (!rawData) throw new Error(`Not able to read manifest file : ${path}`);
2146
+ if (!rawData) throw new ManifestError(`Unable to read or parse file at ${path}`);
2091
2147
  const data = plainToInstance(Manifest, rawData, { excludeExtraneousValues: true });
2092
2148
  const errors = await validate(data);
2093
- if (errors.length > 0) throw new Error(`Invalid manifest\n${errors.toString().replace(/,/g, "\n")}`);
2149
+ if (errors.length > 0) throw new ManifestError(`Validation failed\n${errors.toString()}`);
2094
2150
  return data;
2095
2151
  };
2096
2152
  //#endregion
@@ -2133,8 +2189,8 @@ var StartAction = class extends AbstractAction {
2133
2189
  const cert = getStringInput(options, "cert");
2134
2190
  const key = getStringInput(options, "key");
2135
2191
  if (!cert && !key) return void 0;
2136
- if (!cert) throw new Error("No cert entered for SSL. Please enter a key with --cert.");
2137
- if (!key) throw new Error("No key entered for SSL. Please enter a key with --key.");
2192
+ if (!cert) throw new CLIError("No cert entered for SSL. Please enter a cert with --cert.");
2193
+ if (!key) throw new CLIError("No key entered for SSL. Please enter a key with --key.");
2138
2194
  return {
2139
2195
  cert,
2140
2196
  key
@@ -2279,11 +2335,12 @@ var CreateCommand = class extends AbstractCommand {
2279
2335
  //#region src/command/commands/dev.command.ts
2280
2336
  var DevCommand = class extends AbstractCommand {
2281
2337
  load(program) {
2282
- program.command("dev").description("run your game in dev mode").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--generate", "generate app from config", false).action(async (rawOptions) => {
2338
+ program.command("dev").description("run your game in dev mode").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--generate", "generate app from config", false).option("-e, --editor", "run the editor", false).action(async (rawOptions) => {
2283
2339
  const options = AbstractCommand.mapToInput({
2284
2340
  directory: rawOptions.directory,
2285
2341
  config: rawOptions.config,
2286
- generate: rawOptions.generate
2342
+ generate: rawOptions.generate,
2343
+ editor: rawOptions.editor
2287
2344
  });
2288
2345
  await this.action.run(/* @__PURE__ */ new Map(), options);
2289
2346
  });
@@ -2453,7 +2510,7 @@ var CommandLoader = class {
2453
2510
  };
2454
2511
  //#endregion
2455
2512
  //#region package.json
2456
- var version = "1.5.3-beta.8113568";
2513
+ var version = "1.5.4-beta.2af80f5";
2457
2514
  //#endregion
2458
2515
  //#region src/bin/nf.ts
2459
2516
  const bootstrap = async () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@nanoforge-dev/cli",
4
- "version": "1.5.3-beta.8113568",
4
+ "version": "1.5.4-beta.2af80f5",
5
5
  "description": "NanoForge CLI",
6
6
  "keywords": [
7
7
  "nanoforge",
@@ -56,7 +56,7 @@
56
56
  "@commitlint/cli": "^21.0.2",
57
57
  "@commitlint/config-conventional": "^21.0.2",
58
58
  "@favware/cliff-jumper": "^6.1.0",
59
- "@nanoforge-dev/actions": "^2.1.1",
59
+ "@nanoforge-dev/actions": "^2.1.2",
60
60
  "@nanoforge-dev/utils-eslint-config": "^1.0.2",
61
61
  "@nanoforge-dev/utils-prettier-config": "^1.0.2",
62
62
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",