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