@nanoforge-dev/cli 1.1.1 → 1.3.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/nf.js CHANGED
@@ -36,11 +36,11 @@ var __decorateClass = (decorators, target, key, kind) => {
36
36
 
37
37
  // package.json
38
38
  var require_package = __commonJS({
39
- "package.json"(exports, module2) {
40
- module2.exports = {
39
+ "package.json"(exports, module) {
40
+ module.exports = {
41
41
  $schema: "https://json.schemastore.org/package.json",
42
42
  name: "@nanoforge-dev/cli",
43
- version: "1.1.1",
43
+ version: "1.3.0",
44
44
  description: "NanoForge CLI",
45
45
  keywords: [
46
46
  "nanoforge",
@@ -73,6 +73,7 @@ var require_package = __commonJS({
73
73
  funding: "",
74
74
  scripts: {
75
75
  build: "tsc --noEmit && tsup",
76
+ "build:dev": "tsc --noEmit && NODE_ENV=development tsup",
76
77
  start: "node dist/nf.js",
77
78
  lint: "prettier --check . && eslint --format=pretty src",
78
79
  format: "prettier --write . && eslint --fix --format=pretty src",
@@ -100,8 +101,10 @@ var require_package = __commonJS({
100
101
  "class-transformer": "catalog:libs",
101
102
  "class-validator": "catalog:libs",
102
103
  commander: "catalog:cli",
104
+ dotenv: "catalog:libs",
103
105
  "node-emoji": "catalog:cli",
104
106
  ora: "catalog:cli",
107
+ rc9: "catalog:libs",
105
108
  "reflect-metadata": "catalog:libs"
106
109
  },
107
110
  devDependencies: {
@@ -159,7 +162,7 @@ var loadLocalBinCommandLoader = /* @__PURE__ */ __name(async () => {
159
162
  }, "loadLocalBinCommandLoader");
160
163
 
161
164
  // src/command/command.loader.ts
162
- import { red as red8 } from "ansis";
165
+ import { red as red6 } from "ansis";
163
166
 
164
167
  // src/lib/ui/messages.ts
165
168
  import { green } from "ansis";
@@ -187,48 +190,83 @@ var Emojis = {
187
190
  };
188
191
 
189
192
  // src/lib/ui/messages.ts
193
+ var success = /* @__PURE__ */ __name((text) => `${Emojis.ROCKET} ${text}`, "success");
194
+ var failure = /* @__PURE__ */ __name((text) => `${Emojis.SCREAM} ${text}`, "failure");
190
195
  var Messages = {
196
+ // --- Build ---
191
197
  BUILD_START: "NanoForge Build",
192
- BUILD_WATCH_START: "Start watching mode",
198
+ BUILD_SUCCESS: success("Build succeeded!"),
199
+ BUILD_FAILED: failure("Build failed!"),
200
+ BUILD_WATCH_START: "Watching for changes...",
193
201
  BUILD_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Building ${part}`, "BUILD_PART_IN_PROGRESS"),
194
- BUILD_PART_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((part) => `${part} updated. Rebuilding`, "BUILD_PART_WATCH_IN_PROGRESS"),
195
- BUILD_NOTHING: "Nothing to build, terminated.",
196
- BUILD_SUCCESS: `${Emojis.ROCKET} Build succeeded !`,
197
- BUILD_PART_FAILED: /* @__PURE__ */ __name((part, commandToRunManually) => `${Emojis.SCREAM} Build of ${part} failed !
198
- In case you don't see any errors above, consider manually running the failed command ${commandToRunManually} to see more details on why it errored out.`, "BUILD_PART_FAILED"),
199
- BUILD_FAILED: `${Emojis.SCREAM} Build failed !`,
202
+ BUILD_PART_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((part) => `${part} updated, rebuilding`, "BUILD_PART_WATCH_IN_PROGRESS"),
203
+ BUILD_PART_FAILED: /* @__PURE__ */ __name((part, command) => failure(`Build of ${part} failed!
204
+ Try running manually: ${command}`), "BUILD_PART_FAILED"),
205
+ // --- Install ---
200
206
  INSTALL_START: "NanoForge Installation",
201
- INSTALL_NAMES_QUESTION: "Witch libraries do you want to install ?",
207
+ INSTALL_SUCCESS: success("Installation completed!"),
208
+ INSTALL_FAILED: failure("Installation failed!"),
209
+ INSTALL_NAMES_QUESTION: "Which libraries do you want to install?",
210
+ INSTALL_PACKAGES_IN_PROGRESS: "Install Nanoforge Packages",
211
+ // --- Login ---
212
+ LOGIN_START: "NanoForge Login",
213
+ LOGIN_SUCCESS: success("Login completed!"),
214
+ LOGIN_FAILED: failure("Login failed!"),
215
+ LOGIN_API_KEY_QUESTION: "What is your registry api key?",
216
+ // --- Logout ---
217
+ LOGOUT_START: "NanoForge Logout",
218
+ LOGOUT_SUCCESS: success("Logout completed!"),
219
+ LOGOUT_FAILED: failure("Logout failed!"),
220
+ // --- New Project ---
202
221
  NEW_START: "NanoForge Project Creation",
203
- NEW_SUCCESS: `${Emojis.ROCKET} Project successfully created !`,
204
- NEW_FAILED: `${Emojis.SCREAM} Project creation failed !`,
205
- NEW_NAME_QUESTION: "What is the name of your project ?",
206
- NEW_PACKAGE_MANAGER_QUESTION: "Which package manager do you want to use ?",
207
- NEW_LANGUAGE_QUESTION: "Which language do you want to use ?",
208
- NEW_STRICT_QUESTION: "Do you want to use types strict mode ?",
209
- NEW_SERVER_QUESTION: "Do you want generate a server to create a multiplayer game ?",
210
- NEW_SKIP_INSTALL_QUESTION: "Do you want to skip installation ?",
222
+ NEW_SUCCESS: success("Project successfully created!"),
223
+ NEW_FAILED: failure("Project creation failed!"),
224
+ NEW_NAME_QUESTION: "What is the name of your project?",
225
+ NEW_PACKAGE_MANAGER_QUESTION: "Which package manager do you want to use?",
226
+ NEW_LANGUAGE_QUESTION: "Which language do you want to use?",
227
+ NEW_STRICT_QUESTION: "Do you want to use strict type checking?",
228
+ NEW_SERVER_QUESTION: "Do you want to generate a server for multiplayer?",
229
+ NEW_SKIP_INSTALL_QUESTION: "Do you want to skip dependency installation?",
230
+ NEW_DOCKER_QUESTION: "Do you want to add a Dockerfile for containerization?",
231
+ // --- Generate ---
211
232
  GENERATE_START: "NanoForge Generate",
212
- GENERATE_WATCH_START: "Start watching mode",
213
- GENERATE_SUCCESS: `${Emojis.ROCKET} Generate succeeded !`,
214
- GENERATE_FAILED: `${Emojis.SCREAM} Generate failed !`,
215
- DEV_START: "NanoForge Dev mode",
233
+ GENERATE_SUCCESS: success("Generation succeeded!"),
234
+ GENERATE_FAILED: failure("Generation failed!"),
235
+ GENERATE_WATCH_START: "Watching for changes...",
236
+ // --- Dev ---
237
+ DEV_START: "NanoForge Dev Mode",
216
238
  DEV_SUCCESS: "Dev mode ended",
217
- DEV_FAILED: `${Emojis.SCREAM} Dev failed !`,
218
- SCHEMATICS_START: "Schematics execution",
219
- SCHEMATIC_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Executing schematic ${name}...`, "SCHEMATIC_IN_PROGRESS"),
220
- SCHEMATIC_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Update watched. Executing schematic ${name}...`, "SCHEMATIC_WATCH_IN_PROGRESS"),
221
- SCHEMATIC_SUCCESS: /* @__PURE__ */ __name((name) => `${Emojis.ROCKET} Schematic ${name} executed successfully !`, "SCHEMATIC_SUCCESS"),
222
- SCHEMATIC_FAILED: /* @__PURE__ */ __name((name) => `${Emojis.SCREAM} Schematic ${name} execution failed. See error below for more details.`, "SCHEMATIC_FAILED"),
223
- PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS: `Installation in progress... ${Emojis.COFFEE}`,
224
- PACKAGE_MANAGER_INSTALLATION_NOTHING: "Nothing to install, terminated.",
225
- PACKAGE_MANAGER_INSTALLATION_SUCCEED: /* @__PURE__ */ __name((names) => names ? `${Emojis.ROCKET} Packages successfully installed : ${names.map((name) => green(name)).join(", ")} !` : `${Emojis.ROCKET} Packages successfully installed !`, "PACKAGE_MANAGER_INSTALLATION_SUCCEED"),
226
- PACKAGE_MANAGER_INSTALLATION_FAILED: /* @__PURE__ */ __name((commandToRunManually) => `${Emojis.SCREAM} Packages installation failed !
227
- In case you don't see any errors above, consider manually running the failed command ${commandToRunManually} to see more details on why it errored out.`, "PACKAGE_MANAGER_INSTALLATION_FAILED"),
228
- RUN_START: "NanoForge Run",
229
- RUN_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Running ${part}...`, "RUN_PART_IN_PROGRESS"),
230
- RUN_PART_SUCCESS: /* @__PURE__ */ __name((part) => `${Emojis.ROCKET} Run of ${part} terminated.`, "RUN_PART_SUCCESS"),
231
- RUN_PART_FAILED: /* @__PURE__ */ __name((part) => `${Emojis.SCREAM} Run of ${part} failed !`, "RUN_PART_FAILED"),
239
+ DEV_FAILED: failure("Dev mode failed!"),
240
+ // --- Start ---
241
+ START_START: "NanoForge Start",
242
+ START_SUCCESS: success("Start completed!"),
243
+ START_FAILED: failure("Start failed!"),
244
+ START_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Starting ${part}...`, "START_PART_IN_PROGRESS"),
245
+ START_PART_SUCCESS: /* @__PURE__ */ __name((part) => success(`${part} terminated.`), "START_PART_SUCCESS"),
246
+ START_PART_FAILED: /* @__PURE__ */ __name((part) => failure(`${part} failed!`), "START_PART_FAILED"),
247
+ // --- Publish ---
248
+ PUBLISH_START: "NanoForge Publish",
249
+ PUBLISH_SUCCESS: success("Publish completed!"),
250
+ PUBLISH_FAILED: failure("Publish failed!"),
251
+ PUBLISH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Publishing ${name}...`, "PUBLISH_IN_PROGRESS"),
252
+ // --- Unpublish ---
253
+ UNPUBLISH_START: "NanoForge Unpublish",
254
+ UNPUBLISH_SUCCESS: success("Unpublish completed!"),
255
+ UNPUBLISH_FAILED: failure("Unpublish failed!"),
256
+ UNPUBLISH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Unpublishing ${name}...`, "UNPUBLISH_IN_PROGRESS"),
257
+ // --- Schematics ---
258
+ SCHEMATICS_START: "Running schematics",
259
+ SCHEMATIC_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Generating ${name}...`, "SCHEMATIC_IN_PROGRESS"),
260
+ SCHEMATIC_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Change detected, regenerating ${name}...`, "SCHEMATIC_WATCH_IN_PROGRESS"),
261
+ SCHEMATIC_SUCCESS: /* @__PURE__ */ __name((name) => success(`${name} generated successfully!`), "SCHEMATIC_SUCCESS"),
262
+ SCHEMATIC_FAILED: /* @__PURE__ */ __name((name) => failure(`${name} generation failed.`), "SCHEMATIC_FAILED"),
263
+ // --- Package Manager ---
264
+ PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS: `Installing dependencies... ${Emojis.COFFEE}`,
265
+ PACKAGE_MANAGER_INSTALLATION_NOTHING: "Nothing to install.",
266
+ PACKAGE_MANAGER_INSTALLATION_SUCCEED: /* @__PURE__ */ __name((names) => names ? success(`Packages installed: ${names.map((n) => green(n)).join(", ")}`) : success("Packages installed!"), "PACKAGE_MANAGER_INSTALLATION_SUCCEED"),
267
+ PACKAGE_MANAGER_INSTALLATION_FAILED: /* @__PURE__ */ __name((command) => failure(`Package installation failed!
268
+ Try running manually: ${command}`), "PACKAGE_MANAGER_INSTALLATION_FAILED"),
269
+ // --- Runner ---
232
270
  RUNNER_EXECUTION_ERROR: /* @__PURE__ */ __name((command) => `
233
271
  Failed to execute command: ${command}`, "RUNNER_EXECUTION_ERROR")
234
272
  };
@@ -240,10 +278,12 @@ var Prefixes = {
240
278
  ERROR: bgRgb(210, 0, 75).bold.rgb(0, 0, 0)(" Error ")
241
279
  };
242
280
 
281
+ // src/lib/ui/spinner.ts
282
+ import ora from "ora";
283
+ var getSpinner = /* @__PURE__ */ __name((message) => ora({ text: message }), "getSpinner");
284
+
243
285
  // src/action/actions/build.action.ts
244
- import * as ansis from "ansis";
245
286
  import { watch } from "chokidar";
246
- import * as console2 from "console";
247
287
  import { dirname, join as join4 } from "path";
248
288
 
249
289
  // src/lib/input/base-inputs.ts
@@ -303,16 +343,40 @@ var getDevGenerateInput = /* @__PURE__ */ __name((inputs) => {
303
343
  return getBooleanInputWithDefault(inputs, "generate", false);
304
344
  }, "getDevGenerateInput");
305
345
 
346
+ // src/lib/input/inputs/install/lib.input.ts
347
+ function getInstallLibInput(inputs) {
348
+ return getBooleanInputWithDefault(inputs, "lib", false);
349
+ }
350
+ __name(getInstallLibInput, "getInstallLibInput");
351
+
306
352
  // src/lib/question/questions/confirm.question.ts
307
353
  import { confirm } from "@inquirer/prompts";
308
354
 
309
355
  // src/lib/utils/errors.ts
356
+ import { red } from "ansis";
357
+ var getErrorMessage = /* @__PURE__ */ __name((error) => {
358
+ if (error instanceof Error) return getErrorString(error);
359
+ if (typeof error === "string") return error;
360
+ return void 0;
361
+ }, "getErrorMessage");
362
+ var getErrorString = /* @__PURE__ */ __name((error) => {
363
+ const stack = error.stack ? error.stack : error.message;
364
+ const cause = error.cause && typeof error.cause === "object" ? JSON.stringify(error.cause, null, 2) : error.cause;
365
+ return `${stack}${cause ? `
366
+ ${cause}` : ""}`;
367
+ }, "getErrorString");
368
+ var handleActionError = /* @__PURE__ */ __name((context, error) => {
369
+ console.error();
370
+ console.error(red(context));
371
+ const msg = getErrorMessage(error);
372
+ if (msg) console.error(msg);
373
+ process.exit(1);
374
+ }, "handleActionError");
310
375
  var promptError = /* @__PURE__ */ __name((err) => {
311
376
  if (err.name === "ExitPromptError") {
312
377
  process.exit(1);
313
- } else {
314
- throw err;
315
378
  }
379
+ throw err;
316
380
  }, "promptError");
317
381
 
318
382
  // src/lib/question/questions/confirm.question.ts
@@ -384,79 +448,155 @@ var getInstallNamesInputOrAsk = /* @__PURE__ */ __name((inputs) => {
384
448
  );
385
449
  }, "getInstallNamesInputOrAsk");
386
450
 
387
- // src/lib/package-manager/package-manager.factory.ts
388
- import fs2 from "fs";
389
- import { resolve as resolve2 } from "path";
451
+ // src/lib/input/inputs/install/server.input.ts
452
+ function getInstallServerInput(inputs) {
453
+ return getBooleanInputWithDefault(inputs, "server", false);
454
+ }
455
+ __name(getInstallServerInput, "getInstallServerInput");
390
456
 
391
- // src/lib/runner/runner.factory.ts
392
- import { yellow } from "ansis";
457
+ // src/lib/input/inputs/login-out/api-key.input.ts
458
+ var getApiKeyInput = /* @__PURE__ */ __name((inputs) => {
459
+ return getStringInput(inputs, "apiKey");
460
+ }, "getApiKeyInput");
461
+ var getLoginApiKeyInputOrAsk = /* @__PURE__ */ __name((inputs) => {
462
+ return getInputOrAsk(
463
+ getApiKeyInput(inputs),
464
+ () => askInput(Messages.LOGIN_API_KEY_QUESTION, {
465
+ required: true
466
+ })
467
+ );
468
+ }, "getLoginApiKeyInputOrAsk");
393
469
 
394
- // src/lib/runner/abstract.runner.ts
395
- import { red } from "ansis";
396
- import { spawn } from "child_process";
397
- import * as process2 from "process";
398
- var AbstractRunner = class {
399
- constructor(binary, args = []) {
400
- this.binary = binary;
401
- this.args = args;
402
- }
403
- static {
404
- __name(this, "AbstractRunner");
405
- }
406
- async run(args, collect = false, cwd2 = process2.cwd(), env2, listeners, failSpinner) {
407
- const options = {
408
- cwd: cwd2,
409
- stdio: collect ? "pipe" : "inherit",
410
- shell: true,
411
- env: { ...process2.env, ...env2 }
412
- };
413
- return new Promise((resolve3, reject) => {
414
- const child = spawn(
415
- `${this.binary} ${[...this.args, ...args].join(" ")}`,
416
- options
417
- );
418
- const res = [];
419
- child.stdout?.on(
420
- "data",
421
- listeners?.onStdout ?? ((data) => res.push(data.toString().replace(/\r\n|\n/, "")))
422
- );
423
- child.stderr?.on(
424
- "data",
425
- listeners?.onStderr ?? ((data) => res.push(data.toString().replace(/\r\n|\n/, "")))
426
- );
427
- child.on("close", (code) => {
428
- if (code === 0) {
429
- resolve3(collect && res.length ? res.join("\n") : null);
430
- } else {
431
- if (failSpinner) failSpinner();
432
- console.error(
433
- red(Messages.RUNNER_EXECUTION_ERROR([this.binary, ...this.args, ...args].join(" ")))
434
- );
435
- if (res.length) {
436
- console.error();
437
- console.error(res.join("\n"));
438
- console.error();
439
- }
440
- reject();
441
- }
442
- });
443
- });
444
- }
445
- rawFullCommand(args) {
446
- const commandArgs = [...this.args, ...args];
447
- return `${this.binary} ${commandArgs.join(" ")}`;
448
- }
449
- };
470
+ // src/lib/input/inputs/login-out/local.input.ts
471
+ function getLocalInput(inputs) {
472
+ return getBooleanInputWithDefault(inputs, "local", false);
473
+ }
474
+ __name(getLocalInput, "getLocalInput");
450
475
 
451
- // src/lib/runner/runners/bun.runner.ts
452
- var BunRunner = class extends AbstractRunner {
453
- static {
454
- __name(this, "BunRunner");
476
+ // src/lib/input/inputs/new/docker.input.ts
477
+ var getNewDockerInput = /* @__PURE__ */ __name((inputs) => {
478
+ return getBooleanInput(inputs, "docker");
479
+ }, "getNewDockerInput");
480
+ var getNewDockerOrAsk = /* @__PURE__ */ __name((inputs) => {
481
+ return getInputOrAsk(
482
+ getNewDockerInput(inputs),
483
+ () => askConfirm(Messages.NEW_DOCKER_QUESTION, { default: true })
484
+ );
485
+ }, "getNewDockerOrAsk");
486
+
487
+ // src/lib/input/inputs/new/init-functions.input.ts
488
+ var getNewInitFunctionsWithDefault = /* @__PURE__ */ __name((inputs) => {
489
+ return getBooleanInputWithDefault(inputs, "initFunctions", false);
490
+ }, "getNewInitFunctionsWithDefault");
491
+
492
+ // src/lib/input/inputs/new/language.input.ts
493
+ var getLanguageInput = /* @__PURE__ */ __name((inputs) => {
494
+ return getStringInput(inputs, "language");
495
+ }, "getLanguageInput");
496
+ var getNewLanguageInputOrAsk = /* @__PURE__ */ __name((inputs) => {
497
+ return getInputOrAsk(
498
+ getLanguageInput(inputs),
499
+ () => askSelect(Messages.NEW_LANGUAGE_QUESTION, [{ value: "ts" }, { value: "js" }], {
500
+ default: "ts"
501
+ })
502
+ );
503
+ }, "getNewLanguageInputOrAsk");
504
+
505
+ // src/lib/input/inputs/new/lint.input.ts
506
+ var getNewLintInput = /* @__PURE__ */ __name((inputs) => {
507
+ return getBooleanInputWithDefault(inputs, "lint", true);
508
+ }, "getNewLintInput");
509
+
510
+ // src/lib/input/inputs/new/name.input.ts
511
+ var getNameInput = /* @__PURE__ */ __name((inputs) => {
512
+ return getStringInput(inputs, "name");
513
+ }, "getNameInput");
514
+ var getNewNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
515
+ return getInputOrAsk(
516
+ getNameInput(inputs),
517
+ () => askInput(Messages.NEW_NAME_QUESTION, {
518
+ required: true,
519
+ default: "nanoforge-app"
520
+ })
521
+ );
522
+ }, "getNewNameInputOrAsk");
523
+
524
+ // src/lib/input/inputs/new/package-manager.input.ts
525
+ var getPackageManagerInput = /* @__PURE__ */ __name((inputs) => {
526
+ return getStringInput(inputs, "packageManager");
527
+ }, "getPackageManagerInput");
528
+ var getNewPackageManagerInputOrAsk = /* @__PURE__ */ __name((inputs) => {
529
+ return getInputOrAsk(
530
+ getPackageManagerInput(inputs),
531
+ () => askSelect(
532
+ Messages.NEW_PACKAGE_MANAGER_QUESTION,
533
+ [{ value: "npm" }, { value: "yarn" }, { value: "pnpm" }, { value: "bun" }],
534
+ {
535
+ default: "npm"
536
+ }
537
+ )
538
+ );
539
+ }, "getNewPackageManagerInputOrAsk");
540
+
541
+ // src/lib/input/inputs/new/path.input.ts
542
+ var getNewPathInput = /* @__PURE__ */ __name((inputs) => {
543
+ return getStringInput(inputs, "path");
544
+ }, "getNewPathInput");
545
+
546
+ // src/lib/input/inputs/new/server.input.ts
547
+ var getNewServerInput = /* @__PURE__ */ __name((inputs) => {
548
+ return getBooleanInput(inputs, "server");
549
+ }, "getNewServerInput");
550
+ var getNewServerOrAsk = /* @__PURE__ */ __name((inputs) => {
551
+ return getInputOrAsk(
552
+ getNewServerInput(inputs),
553
+ () => askConfirm(Messages.NEW_SERVER_QUESTION, { default: false })
554
+ );
555
+ }, "getNewServerOrAsk");
556
+
557
+ // src/lib/input/inputs/new/skip-install.input.ts
558
+ var getNewSkipInstallInput = /* @__PURE__ */ __name((inputs) => {
559
+ return getBooleanInput(inputs, "skipInstall");
560
+ }, "getNewSkipInstallInput");
561
+ var getNewSkipInstallOrAsk = /* @__PURE__ */ __name((inputs) => {
562
+ return getInputOrAsk(
563
+ getNewSkipInstallInput(inputs),
564
+ () => askConfirm(Messages.NEW_SKIP_INSTALL_QUESTION, { default: false })
565
+ );
566
+ }, "getNewSkipInstallOrAsk");
567
+
568
+ // src/lib/input/inputs/new/strict.input.ts
569
+ var getNewStrictInput = /* @__PURE__ */ __name((inputs) => {
570
+ return getBooleanInput(inputs, "strict");
571
+ }, "getNewStrictInput");
572
+ var getNewStrictOrAsk = /* @__PURE__ */ __name((inputs) => {
573
+ return getInputOrAsk(
574
+ getNewStrictInput(inputs),
575
+ () => askConfirm(Messages.NEW_STRICT_QUESTION, { default: true })
576
+ );
577
+ }, "getNewStrictOrAsk");
578
+
579
+ // src/lib/package-manager/package-manager.ts
580
+ import { bold, red as red3 } from "ansis";
581
+
582
+ // src/lib/runner/process-logger.ts
583
+ import { green as green2, red as red2, yellow } from "ansis";
584
+ var formatLines = /* @__PURE__ */ __name((chunk) => {
585
+ return chunk.toString().replace(/\r\n|\n/g, "\n").replace(/^\n+|\n+$/g, "").split("\n");
586
+ }, "formatLines");
587
+ var timestamp = /* @__PURE__ */ __name(() => yellow(`[${(/* @__PURE__ */ new Date()).toISOString()}]`), "timestamp");
588
+ var createStdoutLogger = /* @__PURE__ */ __name((name) => (chunk) => {
589
+ const prefix = green2(`(${name}) INFO -`);
590
+ for (const line of formatLines(chunk)) {
591
+ console.info(`${timestamp()} ${prefix} ${line}`);
455
592
  }
456
- constructor() {
457
- super("bun");
593
+ }, "createStdoutLogger");
594
+ var createStderrLogger = /* @__PURE__ */ __name((name) => (chunk) => {
595
+ const prefix = red2(`(${name}) ERROR -`);
596
+ for (const line of formatLines(chunk)) {
597
+ console.error(`${timestamp()} ${prefix} ${line}`);
458
598
  }
459
- };
599
+ }, "createStderrLogger");
460
600
 
461
601
  // src/lib/utils/path.ts
462
602
  import fs from "fs";
@@ -483,268 +623,262 @@ var resolveCLINodeBinaryPath = /* @__PURE__ */ __name((name) => {
483
623
  throw new Error("Could not find module path");
484
624
  }, "resolveCLINodeBinaryPath");
485
625
 
486
- // src/lib/runner/runners/local-bun.runner.ts
487
- var LocalBunRunner = class extends AbstractRunner {
488
- static {
489
- __name(this, "LocalBunRunner");
490
- }
491
- constructor() {
492
- super(resolveCLINodeBinaryPath("bun"));
493
- }
494
- };
495
-
496
- // src/lib/runner/runners/npm.runner.ts
497
- var NpmRunner = class extends AbstractRunner {
498
- static {
499
- __name(this, "NpmRunner");
500
- }
501
- constructor() {
502
- super("npm");
503
- }
504
- };
505
-
506
- // src/lib/runner/runners/pnpm.runner.ts
507
- var PnpmRunner = class extends AbstractRunner {
508
- static {
509
- __name(this, "PnpmRunner");
510
- }
511
- constructor() {
512
- super("pnpm");
513
- }
514
- };
515
-
516
- // src/lib/runner/runners/schematic.runner.ts
517
- var SchematicRunner = class _SchematicRunner extends AbstractRunner {
518
- static {
519
- __name(this, "SchematicRunner");
520
- }
521
- static getModulePaths() {
522
- return module.paths;
523
- }
524
- static findClosestSchematicsBinary() {
525
- try {
526
- return getModulePath("@angular-devkit/schematics-cli/bin/schematics.js");
527
- } catch (e) {
528
- console.error(e);
529
- throw new Error("'schematics' binary path could not be found!");
530
- }
531
- }
532
- constructor() {
533
- super(`node`, [`"${_SchematicRunner.findClosestSchematicsBinary()}"`]);
534
- }
535
- };
536
-
537
- // src/lib/runner/runners/yarn.runner.ts
538
- var YarnRunner = class extends AbstractRunner {
539
- static {
540
- __name(this, "YarnRunner");
541
- }
542
- constructor() {
543
- super("yarn");
544
- }
545
- };
546
-
547
- // src/lib/runner/runner.factory.ts
548
- var RunnerFactory = class {
549
- static {
550
- __name(this, "RunnerFactory");
551
- }
552
- static create(runner) {
553
- switch (runner) {
554
- case 0 /* BUN */:
555
- return new BunRunner();
556
- case 1 /* LOCAL_BUN */:
557
- return new LocalBunRunner();
558
- case 2 /* NPM */:
559
- return new NpmRunner();
560
- case 3 /* PNPM */:
561
- return new PnpmRunner();
562
- case 4 /* SCHEMATIC */:
563
- return new SchematicRunner();
564
- case 5 /* YARN */:
565
- return new YarnRunner();
566
- default:
567
- console.info(yellow`[WARN] Unsupported runner: ${runner}`);
568
- throw Error(`Unsupported runner: ${runner}`);
569
- }
570
- }
571
- };
572
-
573
- // src/lib/package-manager/abstract.package-manager.ts
574
- import { bold, green as green2, red as red2, yellow as yellow2 } from "ansis";
575
- import ora from "ora";
576
- var SPINNER = /* @__PURE__ */ __name((message) => ora({
577
- text: message
578
- }), "SPINNER");
579
- var FAIL_SPINNER = /* @__PURE__ */ __name((spinner) => () => spinner.fail(), "FAIL_SPINNER");
580
- var AbstractPackageManager = class {
581
- constructor(runner) {
626
+ // src/lib/utils/spinner.ts
627
+ var withSpinner = /* @__PURE__ */ __name(async (message, task, onError) => {
628
+ const spinner = getSpinner(message);
629
+ spinner.start();
630
+ try {
631
+ const value = await task(spinner);
632
+ spinner.succeed();
633
+ return { success: true, value };
634
+ } catch (error) {
635
+ spinner.fail();
636
+ if (onError) onError();
637
+ return { success: false, error };
638
+ }
639
+ }, "withSpinner");
640
+
641
+ // src/lib/package-manager/package-manager.ts
642
+ var PackageManager = class {
643
+ constructor(name, commands, runner) {
644
+ this.name = name;
645
+ this.commands = commands;
582
646
  this.runner = runner;
583
647
  }
584
648
  static {
585
- __name(this, "AbstractPackageManager");
649
+ __name(this, "PackageManager");
586
650
  }
587
651
  async install(directory) {
588
- const spinner = SPINNER(Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS);
589
- spinner.start();
590
- try {
591
- const commandArgs = [this.cli.install, this.cli.silentFlag];
592
- const collect = true;
593
- await this.runner.run(
594
- commandArgs,
595
- collect,
596
- getCwd(directory),
597
- void 0,
598
- void 0,
599
- () => spinner.fail()
600
- );
601
- spinner.succeed();
602
- this.printInstallSuccess();
603
- } catch {
604
- const commandArgs = [this.cli.install];
605
- const commandToRun = this.runner.rawFullCommand(commandArgs);
606
- this.printInstallFailure(commandToRun);
607
- }
608
- }
609
- version() {
610
- const commandArguments = ["--version"];
611
- const collect = true;
612
- return this.runner.run(commandArguments, collect);
613
- }
614
- addProduction(directory, dependencies) {
615
- const command = [this.cli.add, this.cli.saveFlag];
616
- return this.add(command, directory, dependencies);
617
- }
618
- addDevelopment(directory, dependencies) {
619
- const command = [this.cli.add, this.cli.saveDevFlag];
620
- return this.add(command, directory, dependencies);
621
- }
622
- async build(name, directory, entry, output, flags, watch3) {
623
- if (!this.cli.build) throw new Error(`Package manager ${this.name} does not support building`);
624
- const spinner = SPINNER(
625
- (watch3 ? Messages.BUILD_PART_WATCH_IN_PROGRESS : Messages.BUILD_PART_IN_PROGRESS)(name)
652
+ const args = [this.commands.install, this.commands.silentFlag];
653
+ const result = await withSpinner(
654
+ Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS,
655
+ async (spinner) => {
656
+ await this.exec(args, directory, { onFail: /* @__PURE__ */ __name(() => spinner.fail(), "onFail") });
657
+ this.logSuccess(Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED());
658
+ },
659
+ () => this.logFailure(this.formatFailCommand([this.commands.install]))
626
660
  );
627
- spinner.start();
628
- try {
629
- const commandArgs = [
630
- this.cli.build,
631
- this.cli.silentFlag,
632
- entry,
633
- "--outdir",
634
- output,
635
- ...flags ?? []
636
- ];
637
- const collect = true;
638
- await this.runner.run(
639
- commandArgs,
640
- collect,
641
- getCwd(directory),
642
- void 0,
643
- void 0,
644
- FAIL_SPINNER(spinner)
645
- );
646
- spinner.succeed();
647
- return true;
648
- } catch {
649
- const commandArgs = [this.cli.install];
650
- const commandToRun = this.runner.rawFullCommand(commandArgs);
651
- console.error(red2(Messages.BUILD_PART_FAILED(name, bold(commandToRun))));
652
- return false;
653
- }
661
+ return result.success;
662
+ }
663
+ async addProduction(directory, dependencies) {
664
+ return this.addDependencies(this.commands.saveFlag, directory, dependencies);
665
+ }
666
+ async addDevelopment(directory, dependencies) {
667
+ return this.addDependencies(this.commands.saveDevFlag, directory, dependencies);
668
+ }
669
+ async build(name, directory, entry, output, flags = [], watch3 = false) {
670
+ this.assertSupports("build");
671
+ const message = watch3 ? Messages.BUILD_PART_WATCH_IN_PROGRESS(name) : Messages.BUILD_PART_IN_PROGRESS(name);
672
+ const args = [
673
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
674
+ this.commands.build,
675
+ this.commands.silentFlag,
676
+ entry,
677
+ "--outdir",
678
+ output,
679
+ ...flags
680
+ ];
681
+ const result = await withSpinner(
682
+ message,
683
+ async (spinner) => {
684
+ await this.exec(args, directory, { onFail: /* @__PURE__ */ __name(() => spinner.fail(), "onFail") });
685
+ },
686
+ () => this.logBuildFailure(name)
687
+ );
688
+ return result.success;
654
689
  }
655
- async run(name, directory, file, env2 = {}, flags = [], silent = false) {
690
+ async run(name, directory, script, params, env2 = {}, flags = [], silent = false) {
691
+ console.info(Messages.START_PART_IN_PROGRESS(name));
656
692
  try {
657
- console.info(Messages.RUN_PART_IN_PROGRESS(name));
658
- const commandArgs = [...flags, this.cli.run];
659
- if (silent) commandArgs.push(this.cli.silentFlag);
660
- commandArgs.push(file);
661
- await this.runner.run(commandArgs, true, getCwd(directory), env2, {
662
- onStdout: this.onRunStdout(name),
663
- onStderr: this.onRunStderr(name)
693
+ const args = this.buildRunArgs(script, params, flags, silent);
694
+ await this.exec(args, directory, {
695
+ env: env2,
696
+ listeners: {
697
+ onStdout: createStdoutLogger(name),
698
+ onStderr: createStderrLogger(name)
699
+ }
664
700
  });
665
- console.info(Messages.RUN_PART_SUCCESS(name));
701
+ console.info(Messages.START_PART_SUCCESS(name));
666
702
  return true;
667
703
  } catch {
668
- console.error(red2(Messages.RUN_PART_FAILED(name)));
704
+ console.error(red3(Messages.START_PART_FAILED(name)));
669
705
  return false;
670
706
  }
671
707
  }
672
708
  async runDev(directory, command, env2 = {}, flags = [], collect = true) {
673
709
  try {
674
- const commandArgs = [this.cli.exec, command, ...flags];
675
- await this.runner.run(commandArgs, collect, getCwd(directory), env2);
710
+ const base = [this.commands.exec, command];
711
+ if (this.commands.runArgsFlag) base.push(this.commands.runArgsFlag);
712
+ await this.exec([...base, ...flags], directory, { collect, env: env2 });
676
713
  return true;
677
714
  } catch {
678
715
  return false;
679
716
  }
680
717
  }
681
- async add(args, directory, dependencies) {
718
+ async addDependencies(saveFlag, directory, dependencies) {
682
719
  if (!dependencies.length) {
683
- console.info();
684
- console.info(Messages.PACKAGE_MANAGER_INSTALLATION_NOTHING);
685
- console.info();
720
+ this.logEmpty(Messages.PACKAGE_MANAGER_INSTALLATION_NOTHING);
686
721
  return true;
687
722
  }
688
- const commandArguments = [...args, ...dependencies];
689
- const spinner = SPINNER(Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS);
690
- spinner.start();
691
- try {
692
- const collect = true;
693
- await this.runner.run(
694
- commandArguments,
695
- collect,
696
- getCwd(directory),
697
- void 0,
698
- void 0,
699
- FAIL_SPINNER(spinner)
700
- );
701
- spinner.succeed();
702
- this.printInstallSuccess(dependencies);
703
- return true;
704
- } catch {
705
- spinner.fail();
706
- const commandToRun = this.runner.rawFullCommand(commandArguments);
707
- this.printInstallFailure(commandToRun);
708
- return false;
723
+ const args = [this.commands.add, saveFlag, ...dependencies];
724
+ const result = await withSpinner(
725
+ Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS,
726
+ async (spinner) => {
727
+ await this.exec(args, directory, { onFail: /* @__PURE__ */ __name(() => spinner.fail(), "onFail") });
728
+ this.logSuccess(Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(dependencies));
729
+ },
730
+ () => this.logFailure(this.formatFailCommand(args))
731
+ );
732
+ return result.success;
733
+ }
734
+ assertSupports(feature) {
735
+ if (!this.commands[feature]) {
736
+ throw new Error(`Package manager "${this.name}" does not support "${feature}"`);
709
737
  }
710
738
  }
711
- printInstallSuccess(dependencies) {
739
+ buildRunArgs(script, params, flags, silent) {
740
+ const args = [...flags, this.commands.run];
741
+ if (silent) args.push(this.commands.silentFlag);
742
+ args.push(script);
743
+ if (params.length === 0) return args;
744
+ if (this.commands.runArgsFlag) args.push(this.commands.runArgsFlag);
745
+ return args.concat(params);
746
+ }
747
+ exec(args, directory, options = {}) {
748
+ return this.runner.run(args, {
749
+ collect: options.collect ?? true,
750
+ cwd: getCwd(directory),
751
+ env: options.env,
752
+ listeners: options.listeners,
753
+ onFail: options.onFail
754
+ });
755
+ }
756
+ formatFailCommand(args) {
757
+ return this.runner.fullCommand(args);
758
+ }
759
+ logSuccess(message) {
712
760
  console.info();
713
- console.info(Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(dependencies));
761
+ console.info(message);
714
762
  console.info();
715
763
  }
716
- printInstallFailure(command) {
717
- console.error(red2(Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(bold(command))));
764
+ logFailure(command) {
765
+ console.error(red3(Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(bold(command))));
718
766
  }
719
- onRunStdout = /* @__PURE__ */ __name((name) => (chunk) => {
720
- chunk.toString().replace(/\r\n|\n/g, "\n").replace(/^\n+|\n+$/g, "").split("\n").forEach((line) => {
721
- const date = yellow2(`[${(/* @__PURE__ */ new Date()).toISOString()}]`);
722
- const prompt = green2(`(${name}) INFO -`);
723
- console.info(`${date} ${prompt} ${line}`);
724
- });
725
- }, "onRunStdout");
726
- onRunStderr = /* @__PURE__ */ __name((name) => (chunk) => {
727
- chunk.toString().replace(/\r\n|\n/g, "\n").replace(/^\n+|\n+$/g, "").split("\n").forEach((line) => {
728
- const date = yellow2(`[${(/* @__PURE__ */ new Date()).toISOString()}]`);
729
- const prompt = red2(`(${name}) ERROR -`);
730
- console.error(`${date} ${prompt} ${line}`);
767
+ logBuildFailure(name) {
768
+ const command = this.formatFailCommand([this.commands.install]);
769
+ console.error(red3(Messages.BUILD_PART_FAILED(name, bold(command))));
770
+ }
771
+ logEmpty(message) {
772
+ console.info();
773
+ console.info(message);
774
+ console.info();
775
+ }
776
+ };
777
+
778
+ // src/lib/package-manager/package-manager.factory.ts
779
+ import fs2 from "fs";
780
+ import { resolve as resolve2 } from "path";
781
+
782
+ // src/lib/runner/runner.ts
783
+ import { red as red4 } from "ansis";
784
+ import { spawn } from "child_process";
785
+ import * as process2 from "process";
786
+ var Runner = class {
787
+ constructor(binary, baseArgs = []) {
788
+ this.binary = binary;
789
+ this.baseArgs = baseArgs;
790
+ }
791
+ static {
792
+ __name(this, "Runner");
793
+ }
794
+ async run(args, options = {}) {
795
+ const { collect = false, cwd: cwd2 = process2.cwd(), env: env2, listeners, onFail } = options;
796
+ const spawnOpts = this.buildSpawnOptions(collect, cwd2, env2);
797
+ const fullArgs = [...this.baseArgs, ...args];
798
+ return new Promise((resolve4, reject) => {
799
+ const child = spawn(`${this.binary} ${fullArgs.join(" ")}`, spawnOpts);
800
+ const output = this.attachOutputHandlers(child, listeners);
801
+ child.on("close", (code) => {
802
+ if (code === 0) {
803
+ resolve4(this.formatOutput(output, collect));
804
+ } else {
805
+ this.handleFailure(output, fullArgs, onFail);
806
+ reject(this.createError(fullArgs, code));
807
+ }
808
+ });
731
809
  });
732
- }, "onRunStderr");
810
+ }
811
+ fullCommand(args) {
812
+ return [this.binary, ...this.baseArgs, ...args].join(" ");
813
+ }
814
+ buildSpawnOptions(collect, cwd2, env2) {
815
+ return {
816
+ cwd: cwd2,
817
+ stdio: collect ? "pipe" : "inherit",
818
+ shell: true,
819
+ env: { ...process2.env, ...env2 }
820
+ };
821
+ }
822
+ attachOutputHandlers(child, listeners) {
823
+ const output = [];
824
+ const defaultHandler = /* @__PURE__ */ __name((data) => output.push(data.toString().replace(/\r\n|\n/, "")), "defaultHandler");
825
+ child.stdout?.on("data", listeners?.onStdout ?? defaultHandler);
826
+ child.stderr?.on("data", listeners?.onStderr ?? defaultHandler);
827
+ return output;
828
+ }
829
+ formatOutput(output, collect) {
830
+ return collect && output.length ? output.join("\n") : null;
831
+ }
832
+ handleFailure(output, args, onFail) {
833
+ if (onFail) onFail();
834
+ this.logFailedCommand(args);
835
+ this.logCapturedOutput(output);
836
+ }
837
+ logFailedCommand(args) {
838
+ console.error(red4(`
839
+ Failed to execute command: ${this.binary} ${args.join(" ")}`));
840
+ }
841
+ logCapturedOutput(output) {
842
+ if (output.length) {
843
+ console.error();
844
+ console.error(output.join("\n"));
845
+ console.error();
846
+ }
847
+ }
848
+ createError(args, code) {
849
+ return new Error(`Command "${this.binary} ${args.join(" ")}" exited with code ${code}`);
850
+ }
733
851
  };
734
852
 
735
- // src/lib/package-manager/package-managers/bun.package-manager.ts
736
- var BunPackageManager = class extends AbstractPackageManager {
853
+ // src/lib/runner/runner.factory.ts
854
+ var RunnerFactory = class {
737
855
  static {
738
- __name(this, "BunPackageManager");
856
+ __name(this, "RunnerFactory");
739
857
  }
740
- constructor() {
741
- super(RunnerFactory.create(0 /* BUN */));
858
+ static create(binary, args) {
859
+ return new Runner(binary, args);
742
860
  }
743
- get name() {
744
- return "bun" /* BUN */.toUpperCase();
861
+ static createLocal(binary, args) {
862
+ return new Runner(resolveCLINodeBinaryPath(binary), args);
745
863
  }
746
- get cli() {
747
- return {
864
+ static createSchematic() {
865
+ const binaryPath = this.resolveSchematicBinary();
866
+ return new Runner("node", [`"${binaryPath}"`]);
867
+ }
868
+ static resolveSchematicBinary() {
869
+ try {
870
+ return getModulePath("@angular-devkit/schematics-cli/bin/schematics.js");
871
+ } catch {
872
+ throw new Error("'schematics' binary path could not be found!");
873
+ }
874
+ }
875
+ };
876
+
877
+ // src/lib/package-manager/package-manager-configs.ts
878
+ var PM_CONFIGS = {
879
+ ["bun" /* BUN */]: {
880
+ binary: "bun",
881
+ commands: {
748
882
  install: "install",
749
883
  add: "add",
750
884
  update: "update",
@@ -754,23 +888,11 @@ var BunPackageManager = class extends AbstractPackageManager {
754
888
  saveFlag: "--save",
755
889
  saveDevFlag: "--dev",
756
890
  silentFlag: "--silent"
757
- };
758
- }
759
- };
760
-
761
- // src/lib/package-manager/package-managers/local-bun.package-manager.ts
762
- var LocalBunPackageManager = class extends AbstractPackageManager {
763
- static {
764
- __name(this, "LocalBunPackageManager");
765
- }
766
- constructor() {
767
- super(RunnerFactory.create(1 /* LOCAL_BUN */));
768
- }
769
- get name() {
770
- return "local_bun" /* LOCAL_BUN */.toUpperCase();
771
- }
772
- get cli() {
773
- return {
891
+ }
892
+ },
893
+ ["local_bun" /* LOCAL_BUN */]: {
894
+ binary: "bun",
895
+ commands: {
774
896
  install: "install",
775
897
  add: "add",
776
898
  update: "update",
@@ -782,49 +904,26 @@ var LocalBunPackageManager = class extends AbstractPackageManager {
782
904
  saveFlag: "--save",
783
905
  saveDevFlag: "--dev",
784
906
  silentFlag: "--silent"
785
- };
786
- }
787
- };
788
-
789
- // src/lib/package-manager/package-managers/npm.package-manager.ts
790
- var NpmPackageManager = class extends AbstractPackageManager {
791
- static {
792
- __name(this, "NpmPackageManager");
793
- }
794
- constructor() {
795
- super(RunnerFactory.create(2 /* NPM */));
796
- }
797
- get name() {
798
- return "npm" /* NPM */.toUpperCase();
799
- }
800
- get cli() {
801
- return {
907
+ }
908
+ },
909
+ ["npm" /* NPM */]: {
910
+ binary: "npm",
911
+ commands: {
802
912
  install: "install",
803
913
  add: "install",
804
914
  update: "update",
805
915
  remove: "uninstall",
806
916
  exec: "exec",
807
917
  run: "run",
918
+ runArgsFlag: "--",
808
919
  saveFlag: "--save",
809
920
  saveDevFlag: "--save-dev",
810
921
  silentFlag: "--silent"
811
- };
812
- }
813
- };
814
-
815
- // src/lib/package-manager/package-managers/pnpm.package-manager.ts
816
- var PnpmPackageManager = class extends AbstractPackageManager {
817
- static {
818
- __name(this, "PnpmPackageManager");
819
- }
820
- constructor() {
821
- super(RunnerFactory.create(3 /* PNPM */));
822
- }
823
- get name() {
824
- return "pnpm" /* PNPM */.toUpperCase();
825
- }
826
- get cli() {
827
- return {
922
+ }
923
+ },
924
+ ["pnpm" /* PNPM */]: {
925
+ binary: "pnpm",
926
+ commands: {
828
927
  install: "install",
829
928
  add: "add",
830
929
  update: "update",
@@ -834,23 +933,11 @@ var PnpmPackageManager = class extends AbstractPackageManager {
834
933
  saveFlag: "-P",
835
934
  saveDevFlag: "-D",
836
935
  silentFlag: "--silent"
837
- };
838
- }
839
- };
840
-
841
- // src/lib/package-manager/package-managers/yarn.package-manager.ts
842
- var YarnPackageManager = class extends AbstractPackageManager {
843
- static {
844
- __name(this, "YarnPackageManager");
845
- }
846
- constructor() {
847
- super(RunnerFactory.create(5 /* YARN */));
848
- }
849
- get name() {
850
- return "yarn" /* YARN */.toUpperCase();
851
- }
852
- get cli() {
853
- return {
936
+ }
937
+ },
938
+ ["yarn" /* YARN */]: {
939
+ binary: "yarn",
940
+ commands: {
854
941
  install: "install",
855
942
  add: "add",
856
943
  update: "update",
@@ -860,54 +947,63 @@ var YarnPackageManager = class extends AbstractPackageManager {
860
947
  saveFlag: "",
861
948
  saveDevFlag: "-D",
862
949
  silentFlag: "--silent"
863
- };
950
+ }
864
951
  }
865
952
  };
866
953
 
867
954
  // src/lib/package-manager/package-manager.factory.ts
955
+ var LOCK_FILE_MAP = {
956
+ "bun.lock": "bun" /* BUN */,
957
+ "package-lock.json": "npm" /* NPM */,
958
+ "pnpm-lock.yaml": "pnpm" /* PNPM */,
959
+ "yarn.lock": "yarn" /* YARN */
960
+ };
868
961
  var PackageManagerFactory = class {
869
962
  static {
870
963
  __name(this, "PackageManagerFactory");
871
964
  }
872
965
  static create(name) {
873
- switch (name) {
874
- case "bun" /* BUN */:
875
- return new BunPackageManager();
876
- case "local_bun" /* LOCAL_BUN */:
877
- return new LocalBunPackageManager();
878
- case "npm" /* NPM */:
879
- return new NpmPackageManager();
880
- case "pnpm" /* PNPM */:
881
- return new PnpmPackageManager();
882
- case "yarn" /* YARN */:
883
- return new YarnPackageManager();
884
- default:
885
- throw new Error(`Package manager ${name} is not managed.`);
966
+ const config2 = PM_CONFIGS[name];
967
+ if (!config2) {
968
+ throw new Error(`Package manager ${name} is not managed.`);
886
969
  }
970
+ const runner = this.createRunner(name, config2.binary);
971
+ return new PackageManager(name, config2.commands, runner);
887
972
  }
888
973
  static async find(directory = ".") {
889
- const DEFAULT_PACKAGE_MANAGER = "npm" /* NPM */;
974
+ const detected = await this.detectFromLockFile(directory);
975
+ return this.create(detected);
976
+ }
977
+ static createRunner(name, binary) {
978
+ if (name === "local_bun" /* LOCAL_BUN */) {
979
+ return RunnerFactory.createLocal("bun");
980
+ }
981
+ return RunnerFactory.create(binary);
982
+ }
983
+ static async detectFromLockFile(directory) {
890
984
  try {
891
985
  const files = await fs2.promises.readdir(resolve2(directory));
892
- if (files.includes("bun.lock")) {
893
- return this.create("bun" /* BUN */);
986
+ for (const [lockFile, pmName] of Object.entries(LOCK_FILE_MAP)) {
987
+ if (files.includes(lockFile)) return pmName;
894
988
  }
895
- if (files.includes("package-lock.json")) {
896
- return this.create("npm" /* NPM */);
897
- }
898
- if (files.includes("pnpm-lock.yaml")) {
899
- return this.create("pnpm" /* PNPM */);
900
- }
901
- if (files.includes("yarn.lock")) {
902
- return this.create("yarn" /* YARN */);
903
- }
904
- return this.create(DEFAULT_PACKAGE_MANAGER);
905
989
  } catch {
906
- return this.create(DEFAULT_PACKAGE_MANAGER);
907
990
  }
991
+ return "npm" /* NPM */;
908
992
  }
909
993
  };
910
994
 
995
+ // src/lib/utils/run-safe.ts
996
+ import { red as red5 } from "ansis";
997
+ var runSafe = /* @__PURE__ */ __name(async (fn, fallback) => {
998
+ try {
999
+ return await fn();
1000
+ } catch (error) {
1001
+ const msg = getErrorMessage(error);
1002
+ if (msg) console.error(red5(msg));
1003
+ return fallback;
1004
+ }
1005
+ }, "runSafe");
1006
+
911
1007
  // src/lib/config/config.type.ts
912
1008
  import { Expose, Type } from "class-transformer";
913
1009
  import { IsBoolean, IsEnum, IsNotEmpty, IsPort, IsString, ValidateNested } from "class-validator";
@@ -944,7 +1040,6 @@ var ClientConfig = class {
944
1040
  __name(this, "ClientConfig");
945
1041
  }
946
1042
  port;
947
- gameExposurePort;
948
1043
  build;
949
1044
  runtime;
950
1045
  };
@@ -952,10 +1047,6 @@ __decorateClass([
952
1047
  Expose(),
953
1048
  IsPort()
954
1049
  ], ClientConfig.prototype, "port", 2);
955
- __decorateClass([
956
- Expose(),
957
- IsPort()
958
- ], ClientConfig.prototype, "gameExposurePort", 2);
959
1050
  __decorateClass([
960
1051
  Expose(),
961
1052
  Type(() => BuildConfig),
@@ -971,7 +1062,6 @@ var ServerConfig = class {
971
1062
  __name(this, "ServerConfig");
972
1063
  }
973
1064
  enable;
974
- port;
975
1065
  build;
976
1066
  runtime;
977
1067
  };
@@ -979,10 +1069,6 @@ __decorateClass([
979
1069
  Expose(),
980
1070
  IsBoolean()
981
1071
  ], ServerConfig.prototype, "enable", 2);
982
- __decorateClass([
983
- Expose(),
984
- IsPort()
985
- ], ServerConfig.prototype, "port", 2);
986
1072
  __decorateClass([
987
1073
  Expose(),
988
1074
  Type(() => BuildConfig),
@@ -1033,6 +1119,13 @@ import { validate } from "class-validator";
1033
1119
  import { existsSync as existsSync2, readFileSync } from "fs";
1034
1120
  import { join as join3 } from "path";
1035
1121
 
1122
+ // src/lib/constants.ts
1123
+ var CONFIG_FILE_NAME = "nanoforge.config.json";
1124
+ var MANIFEST_FILE_NAME = "nanoforge.manifest.json";
1125
+ var GLOBAL_CONFIG_FILE_NAME = ".nanoforgerc";
1126
+ var NANOFORGE_DIR = ".nanoforge";
1127
+ var REGISTRY_URL = "https://api.nanoforge.dev";
1128
+
1036
1129
  // src/lib/utils/object.ts
1037
1130
  var isObject = /* @__PURE__ */ __name((item) => {
1038
1131
  return item && typeof item === "object" && !Array.isArray(item);
@@ -1052,6 +1145,7 @@ var deepMerge = /* @__PURE__ */ __name((target, ...sources) => {
1052
1145
  }
1053
1146
  return deepMerge(target, ...sources);
1054
1147
  }, "deepMerge");
1148
+ var isEmpty = /* @__PURE__ */ __name((target) => Object.keys(target).length === 0, "isEmpty");
1055
1149
 
1056
1150
  // src/lib/config/config-defaults.ts
1057
1151
  var CONFIG_DEFAULTS = {
@@ -1060,7 +1154,6 @@ var CONFIG_DEFAULTS = {
1060
1154
  initFunctions: true,
1061
1155
  client: {
1062
1156
  port: "3000",
1063
- gameExposurePort: "3001",
1064
1157
  build: {
1065
1158
  entryFile: "client/main.ts",
1066
1159
  outDir: ".nanoforge/client"
@@ -1071,7 +1164,6 @@ var CONFIG_DEFAULTS = {
1071
1164
  },
1072
1165
  server: {
1073
1166
  enable: false,
1074
- port: "3002",
1075
1167
  build: {
1076
1168
  entryFile: "server/main.ts",
1077
1169
  outDir: ".nanoforge/server"
@@ -1088,18 +1180,17 @@ var getConfigPath = /* @__PURE__ */ __name((directory, name) => {
1088
1180
  if (name) {
1089
1181
  return join3(directory, name);
1090
1182
  } else {
1091
- for (const n of ["nanoforge.config.json"]) {
1183
+ for (const n of [CONFIG_FILE_NAME]) {
1092
1184
  const path = join3(directory, n);
1093
1185
  if (existsSync2(path)) return path;
1094
1186
  }
1095
- throw new Error(`Unsupported config: ${name}`);
1187
+ throw new Error(`No config file found in directory: ${directory}`);
1096
1188
  }
1097
1189
  }, "getConfigPath");
1098
1190
  var loadConfig = /* @__PURE__ */ __name(async (directory, name) => {
1099
1191
  if (config) return config;
1100
1192
  let rawData;
1101
1193
  const path = getConfigPath(directory, name);
1102
- if (!path) throw new Error("No config file found");
1103
1194
  try {
1104
1195
  rawData = deepMerge(CONFIG_DEFAULTS, JSON.parse(readFileSync(path, "utf-8")));
1105
1196
  } catch {
@@ -1127,6 +1218,32 @@ var AbstractAction = class {
1127
1218
  static {
1128
1219
  __name(this, "AbstractAction");
1129
1220
  }
1221
+ async run(args, options, extraFlags) {
1222
+ this.logStart();
1223
+ try {
1224
+ const result = await this.handle(args, options, extraFlags);
1225
+ this.resolveResult(result);
1226
+ } catch (error) {
1227
+ handleActionError(this.failureMessage, error);
1228
+ }
1229
+ }
1230
+ logStart() {
1231
+ console.info();
1232
+ console.info(`${Prefixes.INFO} ${this.startMessage}`);
1233
+ console.info();
1234
+ }
1235
+ resolveResult(result) {
1236
+ const success2 = result?.success !== false;
1237
+ const keepAlive = result?.keepAlive === true;
1238
+ if (keepAlive) return;
1239
+ console.info();
1240
+ if (!success2) {
1241
+ handleActionError(this.failureMessage, result.error);
1242
+ process.exit(1);
1243
+ }
1244
+ if (this.successMessage) console.info(this.successMessage);
1245
+ process.exit(0);
1246
+ }
1130
1247
  };
1131
1248
 
1132
1249
  // src/action/actions/build.action.ts
@@ -1134,121 +1251,121 @@ var BuildAction = class extends AbstractAction {
1134
1251
  static {
1135
1252
  __name(this, "BuildAction");
1136
1253
  }
1254
+ startMessage = Messages.BUILD_START;
1255
+ successMessage = Messages.BUILD_SUCCESS;
1256
+ failureMessage = Messages.BUILD_FAILED;
1137
1257
  async handle(_args, options) {
1138
- console2.info(Messages.BUILD_START);
1139
- console2.info();
1140
- try {
1141
- const directory = getDirectoryInput(options);
1142
- const config2 = await getConfig(options, directory);
1143
- const watch3 = getWatchInput(options);
1144
- const client = getPart(
1258
+ const directory = getDirectoryInput(options);
1259
+ const config2 = await getConfig(options, directory);
1260
+ const isWatch = getWatchInput(options);
1261
+ const targets = this.resolveTargets(config2, options);
1262
+ const results = await this.buildAll(targets, directory, isWatch);
1263
+ if (isWatch) {
1264
+ return this.enterWatchMode();
1265
+ }
1266
+ return { success: results.every(Boolean) };
1267
+ }
1268
+ resolveTargets(config2, options) {
1269
+ const targets = [
1270
+ this.createTarget(
1271
+ "Client",
1145
1272
  config2.client.build,
1146
- options.get("clientDirectory")?.value,
1147
- "client"
1148
- );
1149
- let res = await buildPart("Client", client, directory, { watch: watch3 });
1150
- if (config2.server.enable) {
1151
- const server = getPart(
1273
+ "browser",
1274
+ getStringInput(options, "clientDirectory")
1275
+ )
1276
+ ];
1277
+ if (config2.server.enable) {
1278
+ targets.push(
1279
+ this.createTarget(
1280
+ "Server",
1152
1281
  config2.server.build,
1153
- options.get("serverDirectory")?.value,
1154
- "server"
1155
- );
1156
- res = await buildPart("Server", server, directory, { watch: watch3 }) ? res : false;
1157
- }
1158
- console2.info();
1159
- if (watch3) {
1160
- console2.info(Messages.BUILD_WATCH_START);
1161
- console2.info();
1162
- return;
1163
- }
1164
- if (!res) {
1165
- console2.info(Messages.BUILD_FAILED);
1166
- process.exit(1);
1167
- }
1168
- console2.info(Messages.BUILD_SUCCESS);
1169
- process.exit(0);
1170
- } catch (e) {
1171
- console2.error(e);
1172
- process.exit(1);
1282
+ "node",
1283
+ getStringInput(options, "serverDirectory")
1284
+ )
1285
+ );
1173
1286
  }
1287
+ return targets;
1174
1288
  }
1175
- };
1176
- var getPart = /* @__PURE__ */ __name((config2, directoryOption, target) => {
1177
- return {
1178
- entry: config2.entryFile,
1179
- output: directoryOption || config2.outDir,
1180
- target
1181
- };
1182
- }, "getPart");
1183
- var buildPart = /* @__PURE__ */ __name(async (name, part, directory, options) => {
1184
- const packageManagerName = "local_bun" /* LOCAL_BUN */;
1185
- const packageManager = PackageManagerFactory.create(packageManagerName);
1186
- const build = /* @__PURE__ */ __name(async (watch3 = false) => {
1187
- try {
1188
- return await packageManager.build(
1189
- name,
1289
+ createTarget(name, config2, platform, outDirOverride) {
1290
+ return {
1291
+ name,
1292
+ entry: config2.entryFile,
1293
+ output: outDirOverride || config2.outDir,
1294
+ platform
1295
+ };
1296
+ }
1297
+ async buildAll(targets, directory, isWatch) {
1298
+ const results = [];
1299
+ for (const target of targets) {
1300
+ const result = await this.buildTarget(target, directory, isWatch);
1301
+ results.push(result);
1302
+ }
1303
+ return results;
1304
+ }
1305
+ async buildTarget(target, directory, isWatch) {
1306
+ const packageManager = PackageManagerFactory.create("local_bun" /* LOCAL_BUN */);
1307
+ const executeBuild = /* @__PURE__ */ __name((rebuild = false) => runSafe(
1308
+ () => packageManager.build(
1309
+ target.name,
1190
1310
  directory,
1191
- part.entry,
1192
- part.output,
1193
- [
1194
- "--asset-naming",
1195
- "[name].[ext]",
1196
- "--target",
1197
- part.target === "client" ? "browser" : "node"
1198
- ],
1199
- watch3
1200
- );
1201
- } catch (error4) {
1202
- if (error4 && error4.message) {
1203
- console2.error(ansis.red(error4.message));
1204
- }
1205
- return false;
1311
+ target.entry,
1312
+ target.output,
1313
+ ["--asset-naming", "[name].[ext]", "--target", target.platform],
1314
+ rebuild
1315
+ ),
1316
+ false
1317
+ ), "executeBuild");
1318
+ if (isWatch) {
1319
+ this.watchDirectory(directory, target.entry, () => executeBuild(true));
1206
1320
  }
1207
- }, "build");
1208
- if (options?.watch)
1209
- watch(dirname(join4(getCwd(directory), part.entry))).on("change", () => build(true));
1210
- return await build();
1211
- }, "buildPart");
1321
+ const result = await executeBuild();
1322
+ return result !== false;
1323
+ }
1324
+ watchDirectory(directory, entry, onChange) {
1325
+ const watchPath = dirname(join4(getCwd(directory), entry));
1326
+ watch(watchPath).on("change", onChange);
1327
+ }
1328
+ enterWatchMode() {
1329
+ console.info();
1330
+ console.info(Messages.BUILD_WATCH_START);
1331
+ console.info();
1332
+ return { keepAlive: true };
1333
+ }
1334
+ };
1212
1335
 
1213
1336
  // src/action/actions/dev.action.ts
1214
- import * as ansis2 from "ansis";
1215
1337
  var DevAction = class extends AbstractAction {
1216
1338
  static {
1217
1339
  __name(this, "DevAction");
1218
1340
  }
1341
+ startMessage = Messages.DEV_START;
1342
+ successMessage = Messages.DEV_SUCCESS;
1343
+ failureMessage = Messages.DEV_FAILED;
1219
1344
  async handle(_args, options) {
1220
- console.info(Messages.DEV_START);
1221
- console.info();
1222
- try {
1223
- const directory = getDirectoryInput(options);
1224
- const generate = getDevGenerateInput(options);
1225
- await Promise.all([
1226
- generate ? runAction("generate", [], directory, false) : void 0,
1227
- runAction("build", [], directory, false),
1228
- runAction("start", [], directory, true)
1229
- ]);
1230
- console.info(Messages.DEV_SUCCESS);
1231
- process.exit(0);
1232
- } catch (e) {
1233
- console.error(Messages.DEV_FAILED);
1234
- console.error(e);
1235
- process.exit(1);
1345
+ const directory = getDirectoryInput(options);
1346
+ const generate = getDevGenerateInput(options);
1347
+ const tasks = this.buildTaskList(directory, generate);
1348
+ await Promise.all(tasks);
1349
+ return { keepAlive: true };
1350
+ }
1351
+ buildTaskList(directory, generate) {
1352
+ const tasks = [];
1353
+ if (generate) {
1354
+ tasks.push(this.runSubCommand("generate", directory, { silent: true }));
1236
1355
  }
1356
+ tasks.push(this.runSubCommand("build", directory, { silent: true }));
1357
+ tasks.push(this.runSubCommand("start", directory, { silent: false }));
1358
+ return tasks;
1359
+ }
1360
+ async runSubCommand(command, directory, options) {
1361
+ await runSafe(async () => {
1362
+ const packageManager = await PackageManagerFactory.find(directory);
1363
+ await packageManager.runDev(directory, "nf", {}, [command, "--watch"], options.silent);
1364
+ });
1237
1365
  }
1238
1366
  };
1239
- var runAction = /* @__PURE__ */ __name(async (command, params, directory, stdout = false) => {
1240
- try {
1241
- const packageManager = await PackageManagerFactory.find(directory);
1242
- await packageManager.runDev(directory, "nf", {}, [command, ...params, "--watch"], !stdout);
1243
- } catch (error4) {
1244
- if (error4 && error4.message) {
1245
- console.error(ansis2.red(error4.message));
1246
- }
1247
- }
1248
- }, "runAction");
1249
1367
 
1250
1368
  // src/action/actions/generate.action.ts
1251
- import * as console3 from "console";
1252
1369
  import { join as join5 } from "path";
1253
1370
 
1254
1371
  // src/lib/schematics/abstract.collection.ts
@@ -1261,25 +1378,19 @@ var AbstractCollection = class {
1261
1378
  static {
1262
1379
  __name(this, "AbstractCollection");
1263
1380
  }
1264
- async execute(name, options, flags, failSpinner) {
1381
+ async execute(name, options, flags, onFail) {
1265
1382
  const command = this.buildCommandLine(name, options, flags);
1266
- await this.runner.run(
1267
- command,
1268
- true,
1269
- this.cwd ? getCwd(this.cwd) : void 0,
1270
- void 0,
1271
- void 0,
1272
- failSpinner
1273
- );
1383
+ await this.runner.run(command, {
1384
+ collect: true,
1385
+ cwd: this.cwd ? getCwd(this.cwd) : void 0,
1386
+ onFail
1387
+ });
1274
1388
  }
1275
1389
  buildCommandLine(name, options, flags = []) {
1276
- return [`${this.collection}:${name}`, ...flags, ...this.buildOptions(options)];
1390
+ return [`${this.collection}:${name}`, ...flags, ...this.serializeOptions(options)];
1277
1391
  }
1278
- buildOptions(options) {
1279
- return options.reduce(
1280
- (old, option) => [...old, ...option.toCommandString()],
1281
- []
1282
- );
1392
+ serializeOptions(options) {
1393
+ return options.flatMap((option) => option.toCommandString());
1283
1394
  }
1284
1395
  };
1285
1396
 
@@ -1308,6 +1419,11 @@ var NanoforgeCollection = class _NanoforgeCollection extends AbstractCollection
1308
1419
  name: "part-main",
1309
1420
  alias: "main",
1310
1421
  description: "Generate a NanoForge Part Main file"
1422
+ },
1423
+ {
1424
+ name: "docker",
1425
+ alias: "docker",
1426
+ description: "Generate a Dockerfile for the application"
1311
1427
  }
1312
1428
  ];
1313
1429
  constructor(runner, cwd2) {
@@ -1339,12 +1455,11 @@ var CollectionFactory = class {
1339
1455
  __name(this, "CollectionFactory");
1340
1456
  }
1341
1457
  static create(collection, directory) {
1342
- const schematicRunner = RunnerFactory.create(4 /* SCHEMATIC */);
1458
+ const schematicRunner = RunnerFactory.createSchematic();
1343
1459
  if (collection === "@nanoforge-dev/schematics" /* NANOFORGE */) {
1344
1460
  return new NanoforgeCollection(schematicRunner, directory);
1345
- } else {
1346
- return new NanoforgeCollection(schematicRunner, directory);
1347
1461
  }
1462
+ throw new Error(`Unknown collection: ${collection}`);
1348
1463
  }
1349
1464
  };
1350
1465
 
@@ -1402,19 +1517,10 @@ var SchematicOption = class {
1402
1517
 
1403
1518
  // src/action/common/schematics.ts
1404
1519
  import { watch as watch2 } from "chokidar";
1405
-
1406
- // src/action/common/spinner.ts
1407
- import ora2 from "ora";
1408
- var getSpinner = /* @__PURE__ */ __name((message) => ora2({
1409
- text: message
1410
- }), "getSpinner");
1411
-
1412
- // src/action/common/schematics.ts
1413
1520
  var executeSchematic = /* @__PURE__ */ __name(async (name, collection, schematicName, options, fileToWatch) => {
1414
- const execute = /* @__PURE__ */ __name(async (watch3 = false) => {
1415
- const spinner = getSpinner(
1416
- (watch3 ? Messages.SCHEMATIC_WATCH_IN_PROGRESS : Messages.SCHEMATIC_IN_PROGRESS)(name)
1417
- );
1521
+ const execute = /* @__PURE__ */ __name(async (isRebuild = false) => {
1522
+ const message = isRebuild ? Messages.SCHEMATIC_WATCH_IN_PROGRESS(name) : Messages.SCHEMATIC_IN_PROGRESS(name);
1523
+ const spinner = getSpinner(message);
1418
1524
  spinner.start();
1419
1525
  await collection.execute(
1420
1526
  schematicName,
@@ -1424,16 +1530,17 @@ var executeSchematic = /* @__PURE__ */ __name(async (name, collection, schematic
1424
1530
  );
1425
1531
  spinner.succeed(Messages.SCHEMATIC_SUCCESS(name));
1426
1532
  }, "execute");
1427
- if (fileToWatch) watch2(fileToWatch).on("change", () => execute(true));
1428
- return await execute();
1533
+ if (fileToWatch) {
1534
+ watch2(fileToWatch).on("change", () => execute(true));
1535
+ }
1536
+ await execute();
1429
1537
  }, "executeSchematic");
1430
1538
  var mapSchematicOptions = /* @__PURE__ */ __name((inputs) => {
1431
- return Object.entries(inputs).reduce((old, [key, value]) => {
1432
- if (value === void 0) return old;
1433
- return [
1434
- ...old,
1435
- new SchematicOption(key, typeof value === "object" ? mapSchematicOptions(value) : value)
1436
- ];
1539
+ return Object.entries(inputs).reduce((acc, [key, value]) => {
1540
+ if (value === void 0) return acc;
1541
+ const mapped = typeof value === "object" ? new SchematicOption(key, mapSchematicOptions(value)) : new SchematicOption(key, value);
1542
+ acc.push(mapped);
1543
+ return acc;
1437
1544
  }, []);
1438
1545
  }, "mapSchematicOptions");
1439
1546
 
@@ -1442,370 +1549,816 @@ var GenerateAction = class extends AbstractAction {
1442
1549
  static {
1443
1550
  __name(this, "GenerateAction");
1444
1551
  }
1552
+ startMessage = Messages.GENERATE_START;
1553
+ successMessage = Messages.GENERATE_SUCCESS;
1554
+ failureMessage = Messages.GENERATE_FAILED;
1445
1555
  async handle(_args, options) {
1446
- console3.info(Messages.GENERATE_START);
1447
- console3.info();
1448
- try {
1449
- const directory = getDirectoryInput(options);
1450
- const config2 = await getConfig(options, directory);
1451
- const watch3 = getWatchInput(options);
1452
- const values = await getSchemaValues(config2);
1453
- await generateFiles(values, directory, watch3);
1454
- console3.info();
1455
- if (watch3) {
1456
- console3.info(Messages.GENERATE_WATCH_START);
1457
- console3.info();
1458
- return;
1459
- }
1460
- console3.info(Messages.GENERATE_SUCCESS);
1461
- process.exit(0);
1462
- } catch (e) {
1463
- console3.error(Messages.GENERATE_FAILED);
1464
- console3.error(e);
1465
- process.exit(1);
1556
+ const directory = getDirectoryInput(options);
1557
+ const config2 = await getConfig(options, directory);
1558
+ const isWatch = getWatchInput(options);
1559
+ const values = this.extractValues(config2);
1560
+ await this.generateParts(values, directory, isWatch);
1561
+ if (isWatch) {
1562
+ return this.enterWatchMode();
1466
1563
  }
1564
+ return {};
1467
1565
  }
1468
- };
1469
- var getSchemaValues = /* @__PURE__ */ __name(async (config2) => {
1470
- return {
1471
- name: config2.name,
1472
- directory: ".",
1473
- language: config2.language,
1474
- server: config2.server.enable,
1475
- initFunctions: config2.initFunctions
1476
- };
1477
- }, "getSchemaValues");
1478
- var generateFiles = /* @__PURE__ */ __name(async (values, directory, watch3) => {
1479
- const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1480
- console3.info(Messages.SCHEMATICS_START);
1481
- console3.info();
1482
- await executeSchematic(
1483
- "Client main file",
1484
- collection,
1485
- "part-main",
1486
- {
1487
- name: values.name,
1488
- part: "client",
1489
- directory: values.directory,
1490
- language: values.language,
1491
- initFunctions: values.initFunctions
1492
- },
1493
- watch3 ? join5(getCwd(directory), values.directory, ".nanoforge", "client.save.json") : void 0
1494
- );
1495
- if (values.server) {
1566
+ extractValues(config2) {
1567
+ return {
1568
+ name: config2.name,
1569
+ directory: ".",
1570
+ language: config2.language,
1571
+ server: config2.server.enable,
1572
+ initFunctions: config2.initFunctions
1573
+ };
1574
+ }
1575
+ async generateParts(values, directory, watch3) {
1576
+ const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1577
+ const baseOptions = this.baseSchematicOptions(values);
1496
1578
  await executeSchematic(
1497
- "Server main file",
1579
+ "Client main file",
1498
1580
  collection,
1499
1581
  "part-main",
1500
- {
1501
- name: values.name,
1502
- part: "server",
1503
- directory: values.directory,
1504
- language: values.language,
1505
- initFunctions: values.initFunctions
1506
- },
1507
- join5(getCwd(directory), values.directory, ".nanoforge", "server.save.json")
1582
+ { ...baseOptions, part: "client" },
1583
+ watch3 ? this.watchPath(directory, values.directory, "client") : void 0
1508
1584
  );
1585
+ if (values.server) {
1586
+ await executeSchematic(
1587
+ "Server main file",
1588
+ collection,
1589
+ "part-main",
1590
+ { ...baseOptions, part: "server" },
1591
+ this.watchPath(directory, values.directory, "server")
1592
+ );
1593
+ }
1509
1594
  }
1510
- }, "generateFiles");
1595
+ baseSchematicOptions(values) {
1596
+ return {
1597
+ name: values.name,
1598
+ directory: values.directory,
1599
+ language: values.language,
1600
+ initFunctions: values.initFunctions
1601
+ };
1602
+ }
1603
+ watchPath(directory, subDir, part) {
1604
+ return join5(getCwd(directory), subDir, NANOFORGE_DIR, `${part}.save.json`);
1605
+ }
1606
+ enterWatchMode() {
1607
+ console.info();
1608
+ console.info(Messages.GENERATE_WATCH_START);
1609
+ console.info();
1610
+ return { keepAlive: true };
1611
+ }
1612
+ };
1511
1613
 
1512
1614
  // src/action/actions/install.action.ts
1513
- import * as ansis3 from "ansis";
1514
- import * as process3 from "process";
1515
- var InstallAction = class extends AbstractAction {
1615
+ import { join as join7 } from "path";
1616
+
1617
+ // src/lib/global-config/global-config-handler.ts
1618
+ import { read, readUser, write, writeUser } from "rc9";
1619
+
1620
+ // src/lib/global-config/global-config-defaults.ts
1621
+ var GLOBAL_CONFIG_DEFAULTS = {};
1622
+
1623
+ // src/lib/global-config/global-config-handler.ts
1624
+ var GlobalConfigHandler = class {
1516
1625
  static {
1517
- __name(this, "InstallAction");
1626
+ __name(this, "GlobalConfigHandler");
1518
1627
  }
1519
- async handle(args, options) {
1520
- console.info(Messages.INSTALL_START);
1521
- console.info();
1522
- try {
1523
- const names = await getInstallNamesInputOrAsk(args);
1524
- const directory = getDirectoryInput(options);
1525
- await installPackages(names, directory);
1526
- process3.exit(0);
1527
- } catch (e) {
1528
- console.error(e);
1529
- process3.exit(1);
1530
- }
1628
+ static read(dir) {
1629
+ const localConfig = this._readConfig(read, false, dir);
1630
+ if (localConfig) return localConfig;
1631
+ return this._readConfig(readUser, true);
1531
1632
  }
1532
- };
1533
- var installPackages = /* @__PURE__ */ __name(async (names, directory) => {
1534
- try {
1535
- const packageManager = await PackageManagerFactory.find(directory);
1536
- const res = await packageManager.addProduction(directory, names);
1537
- if (!res) process3.exit(1);
1538
- } catch (error4) {
1539
- if (error4 && error4.message) {
1540
- console.error(ansis3.red(error4.message));
1633
+ static write(config2, local = false, dir) {
1634
+ const options = {
1635
+ name: GLOBAL_CONFIG_FILE_NAME,
1636
+ dir
1637
+ };
1638
+ if (local) write(config2, options);
1639
+ else writeUser(config2, options);
1640
+ }
1641
+ static _readConfig(func, force, dir) {
1642
+ const res = func({
1643
+ name: GLOBAL_CONFIG_FILE_NAME,
1644
+ dir
1645
+ });
1646
+ if (!force) {
1647
+ if (isEmpty(res)) return null;
1541
1648
  }
1542
- process3.exit(1);
1649
+ return deepMerge(GLOBAL_CONFIG_DEFAULTS, res);
1543
1650
  }
1544
- }, "installPackages");
1545
-
1546
- // src/action/actions/new.action.ts
1547
- import * as ansis4 from "ansis";
1548
- import console4 from "console";
1549
- import * as process4 from "process";
1651
+ };
1550
1652
 
1551
- // src/lib/input/inputs/new/init-functions.input.ts
1552
- var getNewInitFunctionsWithDefault = /* @__PURE__ */ __name((inputs) => {
1553
- return getBooleanInputWithDefault(inputs, "initFunctions", false);
1554
- }, "getNewInitFunctionsWithDefault");
1653
+ // src/lib/http/http-client.ts
1654
+ var HttpClient = class {
1655
+ static {
1656
+ __name(this, "HttpClient");
1657
+ }
1658
+ _baseUrl;
1659
+ _baseOptions;
1660
+ _middlewares;
1661
+ constructor(baseUrl, options) {
1662
+ this._baseUrl = baseUrl;
1663
+ this._baseOptions = options ?? {
1664
+ headers: {
1665
+ "Content-Type": "application/json"
1666
+ }
1667
+ };
1668
+ this._middlewares = [];
1669
+ }
1670
+ get(path, options) {
1671
+ return this._applyMiddlewares(path, options, (newPath, newOptions) => {
1672
+ return this._request(newPath, {
1673
+ ...newOptions,
1674
+ method: "GET"
1675
+ });
1676
+ });
1677
+ }
1678
+ post(path, body, options) {
1679
+ return this._applyMiddlewares(path, options, (newPath, newOptions) => {
1680
+ return this._request(newPath, {
1681
+ ...newOptions,
1682
+ method: "POST",
1683
+ body
1684
+ });
1685
+ });
1686
+ }
1687
+ put(path, body, options) {
1688
+ return this._applyMiddlewares(path, options, (newPath, newOptions) => {
1689
+ return this._request(newPath, {
1690
+ ...newOptions,
1691
+ method: "PUT",
1692
+ body
1693
+ });
1694
+ });
1695
+ }
1696
+ patch(path, body, options) {
1697
+ return this._applyMiddlewares(path, options, async (newPath, newOptions) => {
1698
+ return this._request(newPath, {
1699
+ ...newOptions,
1700
+ method: "PATCH",
1701
+ body
1702
+ });
1703
+ });
1704
+ }
1705
+ delete(path, options) {
1706
+ return this._applyMiddlewares(path, options, (newPath, newOptions) => {
1707
+ return this._request(newPath, {
1708
+ ...newOptions,
1709
+ method: "DELETE",
1710
+ body: "{}"
1711
+ });
1712
+ });
1713
+ }
1714
+ useMiddlewares(...middlewares) {
1715
+ for (const middleware of middlewares) this._middlewares.push(middleware);
1716
+ return this;
1717
+ }
1718
+ async _request(path, request) {
1719
+ const res = await fetch(path, request);
1720
+ res.content = null;
1721
+ return res;
1722
+ }
1723
+ _applyMiddlewares(path, options, callback) {
1724
+ const baseParams = {
1725
+ path,
1726
+ fullPath: this._getUrl(path),
1727
+ options: {
1728
+ ...this._baseOptions,
1729
+ ...options,
1730
+ headers: {
1731
+ ...this._baseOptions.headers,
1732
+ ...options?.headers
1733
+ }
1734
+ }
1735
+ };
1736
+ const middlewares = this._middlewares.slice();
1737
+ let response;
1738
+ const execution = /* @__PURE__ */ __name(async (params) => {
1739
+ if (!params) params = baseParams;
1740
+ const middleware = middlewares.shift();
1741
+ if (!middleware) response = await callback(params.fullPath, params.options);
1742
+ else response = await middleware(params, execution) ?? response;
1743
+ return response;
1744
+ }, "execution");
1745
+ return execution(baseParams);
1746
+ }
1747
+ _getUrl(path) {
1748
+ return `${this._baseUrl}${path}`;
1749
+ }
1750
+ };
1555
1751
 
1556
- // src/lib/input/inputs/new/language.input.ts
1557
- var getLanguageInput = /* @__PURE__ */ __name((inputs) => {
1558
- return getStringInput(inputs, "language");
1559
- }, "getLanguageInput");
1560
- var getNewLanguageInputOrAsk = /* @__PURE__ */ __name((inputs) => {
1561
- return getInputOrAsk(
1562
- getLanguageInput(inputs),
1563
- () => askSelect(Messages.NEW_LANGUAGE_QUESTION, [{ value: "ts" }, { value: "js" }], {
1564
- default: "ts"
1565
- })
1566
- );
1567
- }, "getNewLanguageInputOrAsk");
1752
+ // src/lib/http/repository.ts
1753
+ var Repository = class {
1754
+ static {
1755
+ __name(this, "Repository");
1756
+ }
1757
+ _client;
1758
+ constructor(client2) {
1759
+ this._client = client2;
1760
+ }
1761
+ get(path, options) {
1762
+ return this.runRequest("get", path, options);
1763
+ }
1764
+ getFile(path, options) {
1765
+ return this.runFileRequest("get", path, options);
1766
+ }
1767
+ post(path, body, options) {
1768
+ return this.runRequestBody("post", path, body ?? {}, options);
1769
+ }
1770
+ put(path, body, options) {
1771
+ return this.runRequestBody("put", path, body ?? {}, options);
1772
+ }
1773
+ patch(path, body, options) {
1774
+ return this.runRequestBody("patch", path, body ?? {}, options);
1775
+ }
1776
+ delete(path, options) {
1777
+ return this.runRequest("delete", path, options);
1778
+ }
1779
+ async runRequest(request, path, options) {
1780
+ const res = await this._client[request](path, options);
1781
+ const data = await res.json();
1782
+ if (!res.ok)
1783
+ throw new Error(`Request failed with status code ${res.status}`, {
1784
+ cause: data["error"]
1785
+ });
1786
+ return data;
1787
+ }
1788
+ async runFileRequest(request, path, options) {
1789
+ const res = await this._client[request](path, options);
1790
+ if (!res.ok)
1791
+ throw new Error(`Request failed with status code ${res.status}`, {
1792
+ cause: (await res.json())["error"]
1793
+ });
1794
+ return await res.blob();
1795
+ }
1796
+ async runRequestBody(request, path, body, options) {
1797
+ const res = await this._client[request](
1798
+ path,
1799
+ body === void 0 ? void 0 : body instanceof FormData ? body : JSON.stringify(body),
1800
+ options
1801
+ );
1802
+ const data = await res.json();
1803
+ if (!res.ok)
1804
+ throw new Error(`Request failed with status code ${res.status}`, {
1805
+ cause: data["error"]
1806
+ });
1807
+ return data;
1808
+ }
1809
+ };
1568
1810
 
1569
- // src/lib/input/inputs/new/name.input.ts
1570
- var getNameInput = /* @__PURE__ */ __name((inputs) => {
1571
- return getStringInput(inputs, "name");
1572
- }, "getNameInput");
1573
- var getNewNameInputOrAsk = /* @__PURE__ */ __name((inputs) => {
1574
- return getInputOrAsk(
1575
- getNameInput(inputs),
1576
- () => askInput(Messages.NEW_NAME_QUESTION, {
1577
- required: true,
1578
- default: "nanoforge-app"
1811
+ // src/lib/http/client.ts
1812
+ var client = new HttpClient(REGISTRY_URL ?? "");
1813
+ var api = new Repository(client);
1814
+ var withAuth = /* @__PURE__ */ __name((apiKey, force = false, headers = {
1815
+ "Content-Type": "application/json"
1816
+ }) => {
1817
+ if (!apiKey && force) {
1818
+ console.error("No registry key found. Please use `nf login` to login");
1819
+ throw new Error("No apikey found. Please use `nf login` to login");
1820
+ }
1821
+ return new Repository(
1822
+ new HttpClient(REGISTRY_URL ?? "", {
1823
+ headers: {
1824
+ Authorization: apiKey,
1825
+ ...headers
1826
+ }
1579
1827
  })
1580
1828
  );
1581
- }, "getNewNameInputOrAsk");
1582
-
1583
- // src/lib/input/inputs/new/package-manager.input.ts
1584
- var getPackageManagerInput = /* @__PURE__ */ __name((inputs) => {
1585
- return getStringInput(inputs, "packageManager");
1586
- }, "getPackageManagerInput");
1587
- var getNewPackageManagerInputOrAsk = /* @__PURE__ */ __name((inputs) => {
1588
- return getInputOrAsk(
1589
- getPackageManagerInput(inputs),
1590
- () => askSelect(
1591
- Messages.NEW_PACKAGE_MANAGER_QUESTION,
1592
- [{ value: "npm" }, { value: "yarn" }, { value: "pnpm" }, { value: "bun" }],
1593
- {
1594
- default: "npm"
1595
- }
1596
- )
1829
+ }, "withAuth");
1830
+
1831
+ // src/lib/manifest/manifest-resolver.ts
1832
+ var resolveManifestDependencies = /* @__PURE__ */ __name(async (names, dir) => {
1833
+ const client2 = withAuth(GlobalConfigHandler.read(dir).apiKey, false);
1834
+ return concatDeps(await Promise.all(names.map(async (d) => resolveDeps(d, client2))));
1835
+ }, "resolveManifestDependencies");
1836
+ var resolveManifest = /* @__PURE__ */ __name(async (name, client2) => {
1837
+ return await client2.get(`/registry/${name}`);
1838
+ }, "resolveManifest");
1839
+ var resolveDeps = /* @__PURE__ */ __name(async (name, client2) => {
1840
+ const manifest = await resolveManifest(name, client2);
1841
+ const baseDeps = manifest.dependencies ?? [];
1842
+ const deps = await Promise.all(baseDeps.map(async (d) => resolveDeps(d, client2)));
1843
+ return concatDeps(
1844
+ [{ nf: { [manifest.name]: manifest }, npm: getNpmDeps(manifest) }].concat(deps)
1597
1845
  );
1598
- }, "getNewPackageManagerInputOrAsk");
1846
+ }, "resolveDeps");
1847
+ var getNpmDeps = /* @__PURE__ */ __name((manifest) => {
1848
+ return Object.entries(manifest.npmDependencies ?? {});
1849
+ }, "getNpmDeps");
1850
+ var concatDeps = /* @__PURE__ */ __name((deps) => {
1851
+ return {
1852
+ npm: deps.map(({ npm }) => npm).flat(),
1853
+ nf: Object.fromEntries(deps.map(({ nf }) => Object.entries(nf)).flat())
1854
+ };
1855
+ }, "concatDeps");
1599
1856
 
1600
- // src/lib/input/inputs/new/path.input.ts
1601
- var getNewPathInput = /* @__PURE__ */ __name((inputs) => {
1602
- return getStringInput(inputs, "path");
1603
- }, "getNewPathInput");
1857
+ // src/lib/registry/registry.ts
1858
+ import fs3 from "fs";
1859
+ import { join as join6 } from "path";
1860
+ var Registry = class {
1861
+ static {
1862
+ __name(this, "Registry");
1863
+ }
1864
+ static async publish(manifest, dir) {
1865
+ const client2 = this._getClient(dir, true, false);
1866
+ const filename = manifest.publish?.paths?.package ?? "index.ts";
1867
+ const file = await this._getPackageFile(filename, dir);
1868
+ const data = new FormData();
1869
+ for (const key of Object.keys(manifest)) {
1870
+ const value = manifest[key];
1871
+ if (!value) continue;
1872
+ data.append(key, typeof value === "string" ? value : JSON.stringify(value));
1873
+ }
1874
+ data.append("_packageFile", file, filename);
1875
+ await client2.put(`/registry/${manifest.name}`, data);
1876
+ }
1877
+ static async unpublish(manifest, dir) {
1878
+ const client2 = this._getClient(dir, true);
1879
+ await client2.delete(`/registry/${manifest.name}`);
1880
+ }
1881
+ static async install(manifests, dir) {
1882
+ const cwd2 = getCwd(dir);
1883
+ const client2 = this._getClient(dir, false);
1884
+ for (const manifest of manifests) {
1885
+ await this.installPackage(client2, manifest, cwd2);
1886
+ }
1887
+ }
1888
+ static async installPackage(client2, manifest, dir) {
1889
+ const file = await client2.getFile(`/registry/${manifest.name}/-/${manifest._file}`);
1890
+ const path = join6(dir, this.getTypeSubFolder(manifest.type));
1891
+ fs3.mkdirSync(path, { recursive: true });
1892
+ fs3.writeFileSync(join6(path, manifest._file), await file.bytes());
1893
+ }
1894
+ static getTypeSubFolder(type) {
1895
+ if (type === "component") return "components";
1896
+ if (type === "system") return "systems";
1897
+ return ".";
1898
+ }
1899
+ static _getClient(dir, force, headers = true) {
1900
+ const config2 = GlobalConfigHandler.read(dir);
1901
+ return withAuth(config2.apiKey, force, !headers ? {} : void 0);
1902
+ }
1903
+ static _getPackageFile(filename, dir) {
1904
+ const path = join6(getCwd(dir ?? "."), filename);
1905
+ if (!fs3.existsSync(path))
1906
+ throw new Error(
1907
+ "Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.components`!"
1908
+ );
1909
+ try {
1910
+ fs3.accessSync(path, fs3.constants.R_OK);
1911
+ return fs3.openAsBlob(path);
1912
+ } catch {
1913
+ throw new Error("Cannot read package file, please verify your file permissions!");
1914
+ }
1915
+ }
1916
+ };
1604
1917
 
1605
- // src/lib/input/inputs/new/server.input.ts
1606
- var getNewServerInput = /* @__PURE__ */ __name((inputs) => {
1607
- return getBooleanInput(inputs, "server");
1608
- }, "getNewServerInput");
1609
- var getNewServerOrAsk = /* @__PURE__ */ __name((inputs) => {
1610
- return getInputOrAsk(
1611
- getNewServerInput(inputs),
1612
- () => askConfirm(Messages.NEW_SERVER_QUESTION, { default: false })
1613
- );
1614
- }, "getNewServerOrAsk");
1918
+ // src/action/actions/install.action.ts
1919
+ var InstallAction = class extends AbstractAction {
1920
+ static {
1921
+ __name(this, "InstallAction");
1922
+ }
1923
+ startMessage = Messages.INSTALL_START;
1924
+ successMessage = Messages.INSTALL_SUCCESS;
1925
+ failureMessage = Messages.INSTALL_FAILED;
1926
+ async handle(args, options) {
1927
+ const names = await getInstallNamesInputOrAsk(args);
1928
+ const directory = getDirectoryInput(options);
1929
+ const isLib = getInstallLibInput(options);
1930
+ const isServer = getInstallServerInput(options);
1931
+ return isLib ? this._installLibs(directory, names) : this._installNfPackages(directory, names, isServer);
1932
+ }
1933
+ async _installLibs(directory, names) {
1934
+ const packageManager = await PackageManagerFactory.find(directory);
1935
+ return { success: await packageManager.addDevelopment(directory, names) };
1936
+ }
1937
+ async _installNfPackages(directory, names, isServer) {
1938
+ const deps = await resolveManifestDependencies(names, directory);
1939
+ const libSuccess = await this._installLibs(
1940
+ directory,
1941
+ deps.npm.map(([name, version]) => `${name}@${version}`)
1942
+ );
1943
+ if (!libSuccess) return { success: false };
1944
+ return withSpinner(Messages.INSTALL_PACKAGES_IN_PROGRESS, async () => {
1945
+ await Registry.install(
1946
+ Object.values(deps.nf),
1947
+ join7(directory, isServer ? "server" : "client")
1948
+ );
1949
+ });
1950
+ }
1951
+ };
1615
1952
 
1616
- // src/lib/input/inputs/new/skip-install.input.ts
1617
- var getNewSkipInstallInput = /* @__PURE__ */ __name((inputs) => {
1618
- return getBooleanInput(inputs, "skipInstall");
1619
- }, "getNewSkipInstallInput");
1620
- var getNewSkipInstallOrAsk = /* @__PURE__ */ __name((inputs) => {
1621
- return getInputOrAsk(
1622
- getNewSkipInstallInput(inputs),
1623
- () => askConfirm(Messages.NEW_SKIP_INSTALL_QUESTION, { default: false })
1624
- );
1625
- }, "getNewSkipInstallOrAsk");
1953
+ // src/action/actions/login.action.ts
1954
+ var LoginAction = class extends AbstractAction {
1955
+ static {
1956
+ __name(this, "LoginAction");
1957
+ }
1958
+ startMessage = Messages.LOGIN_START;
1959
+ successMessage = Messages.LOGIN_SUCCESS;
1960
+ failureMessage = Messages.LOGIN_FAILED;
1961
+ async handle(_args, options) {
1962
+ const directory = getDirectoryInput(options);
1963
+ const isLocal = getLocalInput(options);
1964
+ const apiKey = await getLoginApiKeyInputOrAsk(options);
1965
+ await withAuth(apiKey, true).post("/registry-key/verify");
1966
+ GlobalConfigHandler.write(
1967
+ {
1968
+ apiKey
1969
+ },
1970
+ isLocal,
1971
+ directory
1972
+ );
1973
+ return { success: true };
1974
+ }
1975
+ };
1626
1976
 
1627
- // src/lib/input/inputs/new/strict.input.ts
1628
- var getNewStrictInput = /* @__PURE__ */ __name((inputs) => {
1629
- return getBooleanInput(inputs, "strict");
1630
- }, "getNewStrictInput");
1631
- var getNewStrictOrAsk = /* @__PURE__ */ __name((inputs) => {
1632
- return getInputOrAsk(
1633
- getNewStrictInput(inputs),
1634
- () => askConfirm(Messages.NEW_STRICT_QUESTION, { default: true })
1635
- );
1636
- }, "getNewStrictOrAsk");
1977
+ // src/action/actions/logout.action.ts
1978
+ var LogoutAction = class extends AbstractAction {
1979
+ static {
1980
+ __name(this, "LogoutAction");
1981
+ }
1982
+ startMessage = Messages.LOGOUT_START;
1983
+ successMessage = Messages.LOGOUT_SUCCESS;
1984
+ failureMessage = Messages.LOGOUT_FAILED;
1985
+ async handle(_args, options) {
1986
+ const directory = getDirectoryInput(options);
1987
+ const isLocal = getLocalInput(options);
1988
+ GlobalConfigHandler.write(
1989
+ {
1990
+ apiKey: void 0
1991
+ },
1992
+ isLocal,
1993
+ directory
1994
+ );
1995
+ return { success: true };
1996
+ }
1997
+ };
1637
1998
 
1638
1999
  // src/action/actions/new.action.ts
2000
+ import { join as join8 } from "path";
1639
2001
  var NewAction = class extends AbstractAction {
1640
2002
  static {
1641
2003
  __name(this, "NewAction");
1642
2004
  }
2005
+ startMessage = Messages.NEW_START;
2006
+ successMessage = Messages.NEW_SUCCESS;
2007
+ failureMessage = Messages.NEW_FAILED;
1643
2008
  async handle(_args, options) {
1644
- console4.info(Messages.NEW_START);
1645
- try {
1646
- const directory = getDirectoryInput(options);
1647
- const values = await getSchemaValues2(options);
1648
- await generateApplicationFiles(values, directory);
1649
- if (!values.skipInstall) await runInstall(directory, values.packageManager);
1650
- console4.info();
1651
- console4.info(Messages.NEW_SUCCESS);
1652
- process4.exit(0);
1653
- } catch {
1654
- console4.error(Messages.NEW_FAILED);
1655
- process4.exit(1);
2009
+ const cwdDirectory = getDirectoryInput(options);
2010
+ const values = await this.collectValues(options);
2011
+ await this.scaffold(values, cwdDirectory);
2012
+ let res = true;
2013
+ if (!values.skipInstall) {
2014
+ res = await this.installDependencies(
2015
+ values.packageManager,
2016
+ join8(cwdDirectory, values.directory ?? values.name)
2017
+ );
1656
2018
  }
2019
+ return { success: res };
1657
2020
  }
1658
- };
1659
- var getSchemaValues2 = /* @__PURE__ */ __name(async (inputs) => {
1660
- return {
1661
- name: await getNewNameInputOrAsk(inputs),
1662
- directory: getNewPathInput(inputs),
1663
- packageManager: await getNewPackageManagerInputOrAsk(inputs),
1664
- language: await getNewLanguageInputOrAsk(inputs),
1665
- strict: await getNewStrictOrAsk(inputs),
1666
- server: await getNewServerOrAsk(inputs),
1667
- initFunctions: getNewInitFunctionsWithDefault(inputs),
1668
- skipInstall: await getNewSkipInstallOrAsk(inputs)
1669
- };
1670
- }, "getSchemaValues");
1671
- var generateApplicationFiles = /* @__PURE__ */ __name(async (values, directory) => {
1672
- console4.info();
1673
- const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1674
- console4.info();
1675
- console4.info(Messages.SCHEMATICS_START);
1676
- console4.info();
1677
- await executeSchematic("Application", collection, "application", {
1678
- name: values.name,
1679
- directory: values.directory,
1680
- packageManager: values.packageManager,
1681
- language: values.language,
1682
- strict: values.strict,
1683
- server: values.server
1684
- });
1685
- await executeSchematic("Configuration", collection, "configuration", {
1686
- name: values.name,
1687
- directory: values.directory,
1688
- server: values.server
1689
- });
1690
- await executeSchematic("Base Client", collection, "part-base", {
1691
- name: values.name,
1692
- part: "client",
1693
- directory: values.directory,
1694
- language: values.language,
1695
- initFunctions: values.initFunctions
1696
- });
1697
- await executeSchematic("Client main file", collection, "part-main", {
1698
- name: values.name,
1699
- part: "client",
1700
- directory: values.directory,
1701
- language: values.language,
1702
- initFunctions: values.initFunctions
1703
- });
1704
- if (values.server) {
1705
- await executeSchematic("Base server", collection, "part-base", {
2021
+ async collectValues(inputs) {
2022
+ return {
2023
+ name: await getNewNameInputOrAsk(inputs),
2024
+ directory: getNewPathInput(inputs),
2025
+ packageManager: await getNewPackageManagerInputOrAsk(inputs),
2026
+ language: await getNewLanguageInputOrAsk(inputs),
2027
+ strict: await getNewStrictOrAsk(inputs),
2028
+ server: await getNewServerOrAsk(inputs),
2029
+ initFunctions: getNewInitFunctionsWithDefault(inputs),
2030
+ skipInstall: await getNewSkipInstallOrAsk(inputs),
2031
+ docker: await getNewDockerOrAsk(inputs),
2032
+ lint: getNewLintInput(inputs)
2033
+ };
2034
+ }
2035
+ async scaffold(values, directory) {
2036
+ const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
2037
+ console.info(Messages.SCHEMATICS_START);
2038
+ console.info();
2039
+ await this.generateApplication(collection, values);
2040
+ await this.generateConfiguration(collection, values);
2041
+ await this.generateClientParts(collection, values);
2042
+ await this.generateDocker(collection, values);
2043
+ if (values.server) {
2044
+ await this.generateServerParts(collection, values);
2045
+ }
2046
+ }
2047
+ generateApplication(collection, values) {
2048
+ return executeSchematic("Application", collection, "application", {
1706
2049
  name: values.name,
1707
- part: "server",
1708
2050
  directory: values.directory,
2051
+ packageManager: values.packageManager,
1709
2052
  language: values.language,
1710
- initFunctions: values.initFunctions
2053
+ strict: values.strict,
2054
+ server: values.server,
2055
+ lint: values.lint
1711
2056
  });
1712
- await executeSchematic("Server main file", collection, "part-main", {
2057
+ }
2058
+ generateConfiguration(collection, values) {
2059
+ return executeSchematic("Configuration", collection, "configuration", {
1713
2060
  name: values.name,
1714
- part: "server",
2061
+ directory: values.directory,
2062
+ server: values.server
2063
+ });
2064
+ }
2065
+ async generateClientParts(collection, values) {
2066
+ const partOptions = this.partOptions(values, "client");
2067
+ await executeSchematic("Client base", collection, "part-base", {
2068
+ ...partOptions,
2069
+ server: values.server
2070
+ });
2071
+ await executeSchematic("Client main file", collection, "part-main", partOptions);
2072
+ }
2073
+ async generateServerParts(collection, values) {
2074
+ const partOptions = this.partOptions(values, "server");
2075
+ await executeSchematic("Server base", collection, "part-base", {
2076
+ ...partOptions,
2077
+ server: values.server
2078
+ });
2079
+ await executeSchematic("Server main file", collection, "part-main", partOptions);
2080
+ }
2081
+ async generateDocker(collection, values) {
2082
+ await executeSchematic("Docker", collection, "docker", {
2083
+ name: values.name,
2084
+ directory: values.directory,
2085
+ packageManager: values.packageManager
2086
+ });
2087
+ }
2088
+ partOptions(values, part) {
2089
+ return {
2090
+ name: values.name,
2091
+ part,
1715
2092
  directory: values.directory,
1716
2093
  language: values.language,
1717
2094
  initFunctions: values.initFunctions
1718
- });
2095
+ };
2096
+ }
2097
+ async installDependencies(packageManagerName, directory) {
2098
+ const packageManager = PackageManagerFactory.create(packageManagerName);
2099
+ return await packageManager.install(directory);
1719
2100
  }
1720
- }, "generateApplicationFiles");
1721
- var runInstall = /* @__PURE__ */ __name(async (directory, pkgManagerName) => {
2101
+ };
2102
+
2103
+ // src/lib/manifest/manifest.type.ts
2104
+ import { Expose as Expose2, Type as Type2 } from "class-transformer";
2105
+ import {
2106
+ IsEnum as IsEnum2,
2107
+ IsNotEmpty as IsNotEmpty2,
2108
+ IsObject,
2109
+ IsOptional,
2110
+ IsString as IsString2,
2111
+ Matches,
2112
+ ValidateNested as ValidateNested2
2113
+ } from "class-validator";
2114
+ var ManifestPackageTypeEnum = /* @__PURE__ */ ((ManifestPackageTypeEnum2) => {
2115
+ ManifestPackageTypeEnum2["COMPONENT"] = "component";
2116
+ ManifestPackageTypeEnum2["SYSTEM"] = "system";
2117
+ return ManifestPackageTypeEnum2;
2118
+ })(ManifestPackageTypeEnum || {});
2119
+ var PathsPublishManifest = class {
2120
+ static {
2121
+ __name(this, "PathsPublishManifest");
2122
+ }
2123
+ package;
2124
+ };
2125
+ __decorateClass([
2126
+ Expose2(),
2127
+ IsString2(),
2128
+ IsNotEmpty2(),
2129
+ IsOptional()
2130
+ ], PathsPublishManifest.prototype, "package", 2);
2131
+ var PublishManifest = class {
2132
+ static {
2133
+ __name(this, "PublishManifest");
2134
+ }
2135
+ paths;
2136
+ };
2137
+ __decorateClass([
2138
+ Expose2(),
2139
+ IsOptional(),
2140
+ ValidateNested2(),
2141
+ Type2(() => PathsPublishManifest)
2142
+ ], PublishManifest.prototype, "paths", 2);
2143
+ var Manifest = class {
2144
+ static {
2145
+ __name(this, "Manifest");
2146
+ }
2147
+ name;
2148
+ type;
2149
+ description;
2150
+ dependencies;
2151
+ publish;
2152
+ npmDependencies;
2153
+ };
2154
+ __decorateClass([
2155
+ Expose2(),
2156
+ IsString2(),
2157
+ Matches(/^[A-Za-z0-9-]+\/[A-Za-z0-9-]+$/),
2158
+ IsNotEmpty2()
2159
+ ], Manifest.prototype, "name", 2);
2160
+ __decorateClass([
2161
+ Expose2(),
2162
+ IsString2(),
2163
+ IsEnum2(ManifestPackageTypeEnum),
2164
+ IsNotEmpty2()
2165
+ ], Manifest.prototype, "type", 2);
2166
+ __decorateClass([
2167
+ Expose2(),
2168
+ IsString2(),
2169
+ IsOptional()
2170
+ ], Manifest.prototype, "description", 2);
2171
+ __decorateClass([
2172
+ Expose2(),
2173
+ IsString2({ each: true }),
2174
+ IsNotEmpty2({ each: true }),
2175
+ IsOptional()
2176
+ ], Manifest.prototype, "dependencies", 2);
2177
+ __decorateClass([
2178
+ Expose2(),
2179
+ IsOptional(),
2180
+ ValidateNested2(),
2181
+ Type2(() => PublishManifest)
2182
+ ], Manifest.prototype, "publish", 2);
2183
+ __decorateClass([
2184
+ Expose2(),
2185
+ IsObject(),
2186
+ IsOptional()
2187
+ ], Manifest.prototype, "npmDependencies", 2);
2188
+
2189
+ // src/lib/manifest/manifest-loader.ts
2190
+ import { plainToInstance as plainToInstance2 } from "class-transformer";
2191
+ import { validate as validate2 } from "class-validator";
2192
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
2193
+ import { join as join9 } from "path";
2194
+ var getManifestPath = /* @__PURE__ */ __name((directory) => {
2195
+ for (const n of [MANIFEST_FILE_NAME]) {
2196
+ const path = join9(directory, n);
2197
+ if (existsSync3(path)) return path;
2198
+ }
2199
+ throw new Error(`No manifest file found in directory: ${directory}`);
2200
+ }, "getManifestPath");
2201
+ var loadManifest = /* @__PURE__ */ __name(async (directory) => {
2202
+ let rawData;
2203
+ const path = getManifestPath(directory);
1722
2204
  try {
1723
- const packageManager = PackageManagerFactory.create(pkgManagerName);
1724
- await packageManager.install(directory);
1725
- } catch (error4) {
1726
- if (error4 && error4.message) {
1727
- console4.error(ansis4.red(error4.message));
1728
- }
1729
- process4.exit(1);
2205
+ rawData = deepMerge({}, JSON.parse(readFileSync2(path, "utf-8")));
2206
+ } catch {
2207
+ rawData = null;
2208
+ }
2209
+ if (!rawData) throw new Error(`Not able to read manifest file : ${path}`);
2210
+ const data = plainToInstance2(Manifest, rawData, {
2211
+ excludeExtraneousValues: true
2212
+ });
2213
+ const errors = await validate2(data);
2214
+ if (errors.length > 0)
2215
+ throw new Error(`Invalid manifest
2216
+ ${errors.toString().replace(/,/g, "\n")}`);
2217
+ return data;
2218
+ }, "loadManifest");
2219
+
2220
+ // src/action/actions/publish.action.ts
2221
+ var PublishAction = class extends AbstractAction {
2222
+ static {
2223
+ __name(this, "PublishAction");
2224
+ }
2225
+ startMessage = Messages.PUBLISH_START;
2226
+ successMessage = Messages.PUBLISH_SUCCESS;
2227
+ failureMessage = Messages.PUBLISH_FAILED;
2228
+ async handle(_args, options) {
2229
+ const directory = getDirectoryInput(options);
2230
+ const manifest = await loadManifest(directory);
2231
+ return withSpinner(Messages.PUBLISH_IN_PROGRESS(manifest.name), async () => {
2232
+ await Registry.publish(manifest, directory);
2233
+ });
1730
2234
  }
1731
- }, "runInstall");
2235
+ };
1732
2236
 
1733
2237
  // src/action/actions/start.action.ts
1734
- import * as ansis5 from "ansis";
1735
- import * as console5 from "console";
1736
- import * as process5 from "process";
1737
- import { join as join6 } from "path";
2238
+ import dotenv from "dotenv";
2239
+ import { join as join10, resolve as resolve3 } from "path";
1738
2240
  var StartAction = class extends AbstractAction {
1739
2241
  static {
1740
2242
  __name(this, "StartAction");
1741
2243
  }
2244
+ startMessage = Messages.START_START;
2245
+ successMessage = Messages.START_SUCCESS;
2246
+ failureMessage = Messages.START_FAILED;
1742
2247
  async handle(_args, options) {
1743
- console5.info(Messages.RUN_START);
1744
- console5.info();
1745
- try {
1746
- const directory = getDirectoryInput(options);
1747
- const config2 = await getConfig(options, directory);
1748
- const clientDir = config2.client.runtime.dir;
1749
- const serverDir = config2.server.runtime.dir;
1750
- const clientPort = getStringInputWithDefault(options, "clientPort", config2.client.port);
1751
- const cert = getStringInput(options, "cert");
1752
- const key = getStringInput(options, "key");
1753
- const watch3 = getWatchInput(options);
1754
- await Promise.all([
1755
- config2.server.enable ? this.startServer(directory, serverDir, watch3) : void 0,
1756
- this.startClient(
1757
- clientPort,
1758
- directory,
1759
- clientDir,
1760
- {
1761
- watch: watch3,
1762
- serverGameDir: config2.server.enable ? serverDir : void 0
1763
- },
1764
- cert,
1765
- key
1766
- )
1767
- ]);
1768
- process5.exit(0);
1769
- } catch (e) {
1770
- console5.error(e);
1771
- process5.exit(1);
2248
+ const directory = getDirectoryInput(options);
2249
+ const config2 = await getConfig(options, directory);
2250
+ const watch3 = getWatchInput(options);
2251
+ const port = getStringInputWithDefault(options, "port", config2.client.port);
2252
+ const ssl = this.resolveSSL(options);
2253
+ const tasks = this.buildStartTasks(config2, directory, watch3, port, ssl);
2254
+ await Promise.all(tasks);
2255
+ return { keepAlive: true };
2256
+ }
2257
+ resolveSSL(options) {
2258
+ const cert = getStringInput(options, "cert");
2259
+ const key = getStringInput(options, "key");
2260
+ if (!cert && !key) return void 0;
2261
+ if (!cert) throw new Error("No cert entered for SSL. Please enter a key with --cert.");
2262
+ if (!key) throw new Error("No key entered for SSL. Please enter a key with --key.");
2263
+ return {
2264
+ cert,
2265
+ key
2266
+ };
2267
+ }
2268
+ buildStartTasks(config2, directory, watch3, port, ssl) {
2269
+ const env2 = this.parseEnv(directory);
2270
+ const tasks = [];
2271
+ if (config2.server.enable) {
2272
+ tasks.push(this.startServer(directory, config2, { watch: watch3 }, env2));
1772
2273
  }
2274
+ tasks.push(this.startClient(directory, config2, { watch: watch3, port, ssl }, env2));
2275
+ return tasks;
2276
+ }
2277
+ async startClient(directory, config2, options, env2) {
2278
+ const loaderPath = getModulePath("@nanoforge-dev/loader-client/package.json", true);
2279
+ const params = this.buildClientParams(directory, config2, options);
2280
+ await this.runLoader("Client", loaderPath, params, env2.client);
1773
2281
  }
1774
- async startClient(port, directory, gameDir, options, cert, key) {
1775
- const path = getModulePath("@nanoforge-dev/loader-client/package.json", true);
2282
+ async startServer(directory, config2, options, env2) {
2283
+ const loaderPath = getModulePath("@nanoforge-dev/loader-server/package.json", true);
2284
+ const params = this.buildServerParams(directory, config2, options);
2285
+ await this.runLoader("Server", loaderPath, params, env2.server);
2286
+ }
2287
+ buildClientParams(directory, config2, options) {
1776
2288
  const params = {
1777
- PORT: port,
1778
- GAME_DIR: getCwd(join6(directory, gameDir)),
1779
- CERT: cert ? join6(getCwd(directory), cert) : void 0,
1780
- KEY: key ? join6(getCwd(directory), key) : void 0
2289
+ "-d": getCwd(join10(directory, config2.client.runtime.dir)),
2290
+ "-p": options.port
1781
2291
  };
1782
- if (options?.watch) {
1783
- params["WATCH"] = "true";
1784
- if (options?.serverGameDir) {
1785
- params["WATCH_SERVER_GAME_DIR"] = getCwd(join6(directory, options.serverGameDir));
2292
+ if (options.watch) params["--watch"] = true;
2293
+ if (options.watch) {
2294
+ params["--watch"] = true;
2295
+ if (config2.server.enable) {
2296
+ params["--watch-server-dir"] = getCwd(join10(directory, config2.server.runtime.dir));
1786
2297
  }
1787
2298
  }
1788
- return runPart("Client", path, params);
2299
+ if (options.ssl) {
2300
+ params["--cert"] = options.ssl.cert;
2301
+ params["--key"] = options.ssl.key;
2302
+ }
2303
+ return this.buildParams(params);
1789
2304
  }
1790
- startServer(directory, gameDir, watch3) {
1791
- const path = getModulePath("@nanoforge-dev/loader-server/package.json", true);
2305
+ buildServerParams(directory, config2, options) {
1792
2306
  const params = {
1793
- GAME_DIR: getCwd(join6(directory, gameDir))
2307
+ "-d": getCwd(join10(directory, config2.server.runtime.dir))
2308
+ };
2309
+ if (options.watch) params["--watch"] = true;
2310
+ return this.buildParams(params);
2311
+ }
2312
+ buildParams(params) {
2313
+ return Object.entries(params).map(([key, value]) => typeof value === "string" ? [key, value] : [key]).flat();
2314
+ }
2315
+ parseEnv(dir) {
2316
+ const prefix = "NANOFORGE_";
2317
+ const clientPrefix = `${prefix}CLIENT_`;
2318
+ const serverPrefix = `${prefix}SERVER_`;
2319
+ const rawEnv = {
2320
+ ...process.env
1794
2321
  };
1795
- if (watch3) params["WATCH"] = "true";
1796
- return runPart("Server", path, params);
2322
+ dotenv.config({
2323
+ path: resolve3(getCwd(join10(dir, ".env"))),
2324
+ processEnv: rawEnv
2325
+ });
2326
+ const baseEnv = Object.entries(rawEnv).filter(
2327
+ ([key, value]) => key.startsWith(prefix) && !!value
2328
+ );
2329
+ return {
2330
+ client: Object.fromEntries(
2331
+ baseEnv.filter(([key]) => !key.startsWith(serverPrefix)).map(([key, value]) => [key.replace(clientPrefix, prefix), value])
2332
+ ),
2333
+ server: Object.fromEntries(
2334
+ baseEnv.filter(([key]) => !key.startsWith(clientPrefix)).map(([key, value]) => [key.replace(serverPrefix, prefix), value])
2335
+ )
2336
+ };
2337
+ }
2338
+ async runLoader(name, directory, params, env2) {
2339
+ await runSafe(async () => {
2340
+ const packageManager = await PackageManagerFactory.find(directory);
2341
+ await packageManager.run(name, directory, "start", params, env2, [], true);
2342
+ });
1797
2343
  }
1798
2344
  };
1799
- var runPart = /* @__PURE__ */ __name(async (part, directory, env2, flags) => {
1800
- try {
1801
- const packageManager = await PackageManagerFactory.find(directory);
1802
- await packageManager.run(part, directory, "start", env2, flags, true);
1803
- } catch (error4) {
1804
- if (error4 && error4.message) {
1805
- console5.error(ansis5.red(error4.message));
1806
- }
2345
+
2346
+ // src/action/actions/unpublish.action.ts
2347
+ var UnpublishAction = class extends AbstractAction {
2348
+ static {
2349
+ __name(this, "UnpublishAction");
1807
2350
  }
1808
- }, "runPart");
2351
+ startMessage = Messages.UNPUBLISH_START;
2352
+ successMessage = Messages.UNPUBLISH_SUCCESS;
2353
+ failureMessage = Messages.UNPUBLISH_FAILED;
2354
+ async handle(_args, options) {
2355
+ const directory = getDirectoryInput(options);
2356
+ const manifest = await loadManifest(directory);
2357
+ return withSpinner(Messages.UNPUBLISH_IN_PROGRESS(manifest.name), async () => {
2358
+ await Registry.unpublish(manifest, directory);
2359
+ });
2360
+ }
2361
+ };
1809
2362
 
1810
2363
  // src/command/abstract.command.ts
1811
2364
  var AbstractCommand = class {
@@ -1815,6 +2368,13 @@ var AbstractCommand = class {
1815
2368
  static {
1816
2369
  __name(this, "AbstractCommand");
1817
2370
  }
2371
+ static mapToInput(mapping) {
2372
+ const input2 = /* @__PURE__ */ new Map();
2373
+ for (const [key, value] of Object.entries(mapping)) {
2374
+ input2.set(key, { value });
2375
+ }
2376
+ return input2;
2377
+ }
1818
2378
  };
1819
2379
 
1820
2380
  // src/command/commands/build.command.ts
@@ -1823,15 +2383,15 @@ var BuildCommand = class extends AbstractCommand {
1823
2383
  __name(this, "BuildCommand");
1824
2384
  }
1825
2385
  load(program2) {
1826
- program2.command("build").description("build your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--client-outDir [clientDirectory]", "specify the output directory of the client").option("--server-outDir [serverDirectory]", "specify the output directory of the server").option("--watch", "build app in watching mode", false).action(async (rawOptions) => {
1827
- const options = /* @__PURE__ */ new Map();
1828
- options.set("directory", { value: rawOptions.directory });
1829
- options.set("config", { value: rawOptions.config });
1830
- options.set("clientDirectory", { value: rawOptions.clientOutDir });
1831
- options.set("serverDirectory", { value: rawOptions.serverOutDir });
1832
- options.set("watch", { value: rawOptions.watch });
1833
- const args = /* @__PURE__ */ new Map();
1834
- await this.action.handle(args, options);
2386
+ program2.command("build").description("build your game").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).option("--client-outDir [clientDirectory]", "specify the output directory of the client").option("--server-outDir [serverDirectory]", "specify the output directory of the server").option("--watch", "build app in watching mode", false).action(async (rawOptions) => {
2387
+ const options = AbstractCommand.mapToInput({
2388
+ directory: rawOptions.directory,
2389
+ config: rawOptions.config,
2390
+ clientDirectory: rawOptions.clientOutDir,
2391
+ serverDirectory: rawOptions.serverOutDir,
2392
+ watch: rawOptions.watch
2393
+ });
2394
+ await this.action.run(/* @__PURE__ */ new Map(), options);
1835
2395
  });
1836
2396
  }
1837
2397
  };
@@ -1842,13 +2402,13 @@ var DevCommand = class extends AbstractCommand {
1842
2402
  __name(this, "DevCommand");
1843
2403
  }
1844
2404
  load(program2) {
1845
- program2.command("dev").description("run your game in dev mode").option("-d, --directory [directory]", "specify the directory of your project").option("--generate", "generate app from config", false).action(async (rawOptions) => {
1846
- const options = /* @__PURE__ */ new Map();
1847
- options.set("directory", { value: rawOptions.directory });
1848
- options.set("config", { value: rawOptions.config });
1849
- options.set("generate", { value: rawOptions.generate });
1850
- const args = /* @__PURE__ */ new Map();
1851
- await this.action.handle(args, options);
2405
+ program2.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) => {
2406
+ const options = AbstractCommand.mapToInput({
2407
+ directory: rawOptions.directory,
2408
+ config: rawOptions.config,
2409
+ generate: rawOptions.generate
2410
+ });
2411
+ await this.action.run(/* @__PURE__ */ new Map(), options);
1852
2412
  });
1853
2413
  }
1854
2414
  };
@@ -1859,13 +2419,13 @@ var GenerateCommand = class extends AbstractCommand {
1859
2419
  __name(this, "GenerateCommand");
1860
2420
  }
1861
2421
  load(program2) {
1862
- program2.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--watch", "generate app in watching mode", false).action(async (rawOptions) => {
1863
- const options = /* @__PURE__ */ new Map();
1864
- options.set("directory", { value: rawOptions.directory });
1865
- options.set("config", { value: rawOptions.config });
1866
- options.set("watch", { value: rawOptions.watch });
1867
- const args = /* @__PURE__ */ new Map();
1868
- await this.action.handle(args, options);
2422
+ program2.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).option("--watch", "generate app in watching mode", false).action(async (rawOptions) => {
2423
+ const options = AbstractCommand.mapToInput({
2424
+ directory: rawOptions.directory,
2425
+ config: rawOptions.config,
2426
+ watch: rawOptions.watch
2427
+ });
2428
+ await this.action.run(/* @__PURE__ */ new Map(), options);
1869
2429
  });
1870
2430
  }
1871
2431
  };
@@ -1876,12 +2436,53 @@ var InstallCommand = class extends AbstractCommand {
1876
2436
  __name(this, "InstallCommand");
1877
2437
  }
1878
2438
  load(program2) {
1879
- program2.command("install [names...]").alias("add").description("add NanoForge library to your project").option("-d, --directory [directory]", "specify the directory of your project").action(async (names, rawOptions) => {
1880
- const options = /* @__PURE__ */ new Map();
1881
- options.set("directory", { value: rawOptions.directory });
1882
- const args = /* @__PURE__ */ new Map();
1883
- args.set("names", { value: names.length ? names : void 0 });
1884
- await this.action.handle(args, options);
2439
+ program2.command("install [names...]").alias("add").description("add Nanoforge components and systems to your project").option("-d, --directory [directory]", "specify the working directory of the command").option("-l, --lib", "install library instead of component/system", false).option(
2440
+ "-s, --server",
2441
+ "install components/systems on server (default install on client)",
2442
+ false
2443
+ ).action(async (names, rawOptions) => {
2444
+ const options = AbstractCommand.mapToInput({
2445
+ directory: rawOptions.directory,
2446
+ lib: rawOptions.lib,
2447
+ server: rawOptions.server
2448
+ });
2449
+ const args = AbstractCommand.mapToInput({
2450
+ names: names.length ? names : void 0
2451
+ });
2452
+ await this.action.run(args, options);
2453
+ });
2454
+ }
2455
+ };
2456
+
2457
+ // src/command/commands/login.command.ts
2458
+ var LoginCommand = class extends AbstractCommand {
2459
+ static {
2460
+ __name(this, "LoginCommand");
2461
+ }
2462
+ load(program2) {
2463
+ program2.command("login").description("login to Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").option("-l, --local", "login only for the project", false).option("-k, --api-key <key>", "api key for Nanoforge registry").action(async (rawOptions) => {
2464
+ const options = AbstractCommand.mapToInput({
2465
+ directory: rawOptions.directory,
2466
+ local: rawOptions.local,
2467
+ apiKey: rawOptions.apiKey
2468
+ });
2469
+ await this.action.run(/* @__PURE__ */ new Map(), options);
2470
+ });
2471
+ }
2472
+ };
2473
+
2474
+ // src/command/commands/logout.command.ts
2475
+ var LogoutCommand = class extends AbstractCommand {
2476
+ static {
2477
+ __name(this, "LogoutCommand");
2478
+ }
2479
+ load(program2) {
2480
+ program2.command("logout").description("logout from Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").option("-l, --local", "logout only for the project").action(async (rawOptions) => {
2481
+ const options = AbstractCommand.mapToInput({
2482
+ directory: rawOptions.directory,
2483
+ local: rawOptions.local
2484
+ });
2485
+ await this.action.run(/* @__PURE__ */ new Map(), options);
1885
2486
  });
1886
2487
  }
1887
2488
  };
@@ -1892,19 +2493,39 @@ var NewCommand = class extends AbstractCommand {
1892
2493
  __name(this, "NewCommand");
1893
2494
  }
1894
2495
  load(program2) {
1895
- program2.command("new").description("create a new nanoforge project").option("-d, --directory [directory]", "specify the directory of your project").option("--name [name]", "specify the name of your project").option("--path [path]", "specify the path of your project").option("--package-manager [packageManager]", "specify the package manager of your project").option("--language [language]", "specify the language of your project").option("--strict", "use strict mode").option("--no-strict", "do not use strict mode").option("--server", "create a server").option("--no-server", "do not create a server").option("--init-functions", "initialize functions").option("--no-init-functions", "do not initialize functions").option("--skip-install", "skip installing dependencies").option("--no-skip-install", "do not skip installing dependencies").action(async (rawOptions) => {
1896
- const options = /* @__PURE__ */ new Map();
1897
- options.set("directory", { value: rawOptions.directory });
1898
- options.set("name", { value: rawOptions.name });
1899
- options.set("path", { value: rawOptions.path });
1900
- options.set("packageManager", { value: rawOptions.packageManager });
1901
- options.set("language", { value: rawOptions.language });
1902
- options.set("strict", { value: rawOptions.strict });
1903
- options.set("server", { value: rawOptions.server });
1904
- options.set("initFunctions", { value: rawOptions.initFunctions });
1905
- options.set("skipInstall", { value: rawOptions.skipInstall });
1906
- const args = /* @__PURE__ */ new Map();
1907
- await this.action.handle(args, options);
2496
+ program2.command("new").description("create a new nanoforge project").option("-d, --directory [directory]", "specify the working directory of the command").option("--name [name]", "specify the name of your project").option(
2497
+ "--path [path]",
2498
+ "specify the relative path where your project will be created (default: name of the project)"
2499
+ ).option("--package-manager [packageManager]", "specify the package manager of your project").option("--language [language]", "specify the language of your project").option("--strict", "use strict mode").option("--no-strict", "do not use strict mode").option("--server", "create a server").option("--no-server", "do not create a server").option("--init-functions", "initialize functions").option("--no-init-functions", "do not initialize functions").option("--skip-install", "skip installing dependencies").option("--no-skip-install", "do not skip installing dependencies").option("--docker", "generate docker files").option("--no-docker", "do not generate docker files").option("--no-lint", "do not generate lint files").action(async (rawOptions) => {
2500
+ const options = AbstractCommand.mapToInput({
2501
+ directory: rawOptions.directory,
2502
+ name: rawOptions.name,
2503
+ path: rawOptions.path,
2504
+ packageManager: rawOptions.packageManager,
2505
+ language: rawOptions.language,
2506
+ strict: rawOptions.strict,
2507
+ server: rawOptions.server,
2508
+ initFunctions: rawOptions.initFunctions,
2509
+ skipInstall: rawOptions.skipInstall,
2510
+ docker: rawOptions.docker,
2511
+ lint: rawOptions.lint
2512
+ });
2513
+ await this.action.run(/* @__PURE__ */ new Map(), options);
2514
+ });
2515
+ }
2516
+ };
2517
+
2518
+ // src/command/commands/publish.command.ts
2519
+ var PublishCommand = class extends AbstractCommand {
2520
+ static {
2521
+ __name(this, "PublishCommand");
2522
+ }
2523
+ load(program2) {
2524
+ program2.command("publish").description("publish package to Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").action(async (rawOptions) => {
2525
+ const options = AbstractCommand.mapToInput({
2526
+ directory: rawOptions.directory
2527
+ });
2528
+ await this.action.run(/* @__PURE__ */ new Map(), options);
1908
2529
  });
1909
2530
  }
1910
2531
  };
@@ -1915,23 +2536,31 @@ var StartCommand = class extends AbstractCommand {
1915
2536
  __name(this, "StartCommand");
1916
2537
  }
1917
2538
  load(program2) {
1918
- program2.command("start").description("start your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option(
1919
- "-p, --client-port [clientPort]",
1920
- "specify the port of the loader (the website to load the game)"
1921
- ).option("--game-exposure-port [gameExposurePort]", "specify the port of the game exposure").option("--server-port [serverPort]", "specify the port of the server").option("--watch", "run app in watching mode", false).option("--cert [cert]", "path to the SSL certificate for HTTPS").option("--key [key]", "path to the SSL key for HTTPS").action(async (rawOptions) => {
1922
- const options = /* @__PURE__ */ new Map();
1923
- options.set("directory", { value: rawOptions.directory });
1924
- options.set("config", { value: rawOptions.config });
1925
- options.set("clientPort", { value: rawOptions.clientPort });
1926
- options.set("gameExposurePort", {
1927
- value: rawOptions.gameExposurePort
2539
+ program2.command("start").description("start your game").option("-d, --directory [directory]", "specify the working directory of the command").option("-c, --config [config]", "path to the config file", CONFIG_FILE_NAME).option("-p, --port [port]", "specify the port of the loader (the website to load the game)").option("--watch", "run app in watching mode", false).option("--cert [cert]", "path to the SSL certificate for HTTPS").option("--key [key]", "path to the SSL key for HTTPS").action(async (rawOptions) => {
2540
+ const options = AbstractCommand.mapToInput({
2541
+ directory: rawOptions.directory,
2542
+ config: rawOptions.config,
2543
+ port: rawOptions.port,
2544
+ watch: rawOptions.watch,
2545
+ cert: rawOptions.cert,
2546
+ key: rawOptions.key
1928
2547
  });
1929
- options.set("serverPort", { value: rawOptions.serverPort });
1930
- options.set("watch", { value: rawOptions.watch });
1931
- options.set("cert", { value: rawOptions.cert });
1932
- options.set("key", { value: rawOptions.key });
1933
- const args = /* @__PURE__ */ new Map();
1934
- await this.action.handle(args, options);
2548
+ await this.action.run(/* @__PURE__ */ new Map(), options);
2549
+ });
2550
+ }
2551
+ };
2552
+
2553
+ // src/command/commands/unpublish.command.ts
2554
+ var UnpublishCommand = class extends AbstractCommand {
2555
+ static {
2556
+ __name(this, "UnpublishCommand");
2557
+ }
2558
+ load(program2) {
2559
+ program2.command("unpublish").description("unpublish package to Nanoforge registry").option("-d, --directory [directory]", "specify the working directory of the command").action(async (rawOptions) => {
2560
+ const options = AbstractCommand.mapToInput({
2561
+ directory: rawOptions.directory
2562
+ });
2563
+ await this.action.run(/* @__PURE__ */ new Map(), options);
1935
2564
  });
1936
2565
  }
1937
2566
  };
@@ -1942,19 +2571,23 @@ var CommandLoader = class {
1942
2571
  __name(this, "CommandLoader");
1943
2572
  }
1944
2573
  static async load(program2) {
2574
+ new NewCommand(new NewAction()).load(program2);
2575
+ new InstallCommand(new InstallAction()).load(program2);
1945
2576
  new BuildCommand(new BuildAction()).load(program2);
2577
+ new StartCommand(new StartAction()).load(program2);
1946
2578
  new DevCommand(new DevAction()).load(program2);
1947
2579
  new GenerateCommand(new GenerateAction()).load(program2);
1948
- new InstallCommand(new InstallAction()).load(program2);
1949
- new NewCommand(new NewAction()).load(program2);
1950
- new StartCommand(new StartAction()).load(program2);
2580
+ new LoginCommand(new LoginAction()).load(program2);
2581
+ new LogoutCommand(new LogoutAction()).load(program2);
2582
+ new PublishCommand(new PublishAction()).load(program2);
2583
+ new UnpublishCommand(new UnpublishAction()).load(program2);
1951
2584
  this.handleInvalidCommand(program2);
1952
2585
  }
1953
2586
  static handleInvalidCommand(program2) {
1954
2587
  program2.on("command:*", () => {
1955
2588
  console.error(`
1956
- ${Prefixes.ERROR} Invalid command: ${red8`%s`}`, program2.args.join(" "));
1957
- console.log(`See ${red8`--help`} for a list of available commands.
2589
+ ${Prefixes.ERROR} Invalid command: ${red6`%s`}`, program2.args.join(" "));
2590
+ console.log(`See ${red6`--help`} for a list of available commands.
1958
2591
  `);
1959
2592
  process.exit(1);
1960
2593
  });