@arkstack/console-slim 0.5.2 → 0.5.3

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.
@@ -1,6 +1,8 @@
1
+ import { existsSync } from "node:fs";
1
2
  import path, { isAbsolute, join } from "node:path";
3
+ import { Arkstack } from "@arkstack/contract";
2
4
  import { CliApp } from "resora";
3
- import { existsSync } from "node:fs";
5
+
4
6
  //#region dist/config.js
5
7
  const defaultConfig = (app) => {
6
8
  return {
@@ -16,15 +18,16 @@ const defaultConfig = (app) => {
16
18
  }
17
19
  };
18
20
  };
21
+
19
22
  //#endregion
20
23
  //#region dist/app.js
21
24
  const resolveStubsDir = (config, options, core) => {
22
25
  const configuredDir = config?.localStubsDir;
23
- if (configuredDir) return isAbsolute(configuredDir) ? configuredDir : join(process.cwd(), configuredDir);
26
+ if (configuredDir) return isAbsolute(configuredDir) ? configuredDir : join(Arkstack.rootDir(), configuredDir);
24
27
  if (!options?.stubsDir) {
25
28
  const driver = core?.getDriver().name ?? "h3";
26
- let stubsDir = path.resolve(process.cwd(), `node_modules/@arkstack/driver-${driver}/stubs`);
27
- if (!existsSync(stubsDir)) stubsDir = path.resolve(process.cwd(), "stubs");
29
+ let stubsDir = path.resolve(Arkstack.rootDir(), `node_modules/@arkstack/driver-${driver}/stubs`);
30
+ if (!existsSync(stubsDir)) stubsDir = path.resolve(Arkstack.rootDir(), "stubs");
28
31
  return stubsDir;
29
32
  }
30
33
  return options?.stubsDir;
@@ -42,7 +45,7 @@ var ArkstackConsoleApp = class extends CliApp {
42
45
  this.mergeConfig();
43
46
  const normalized = name.endsWith("Controller") ? name.replace(/controller/i, "") : name;
44
47
  let controllerName = normalized.endsWith("Controller") ? normalized : `${normalized}Controller`;
45
- const outputPath = join(path.resolve(process.cwd(), "src", "app/http/controllers"), `${controllerName}.${opts?.ext ?? "ts"}`);
48
+ const outputPath = join(path.resolve(Arkstack.rootDir(), "src", "app/http/controllers"), `${controllerName}.${opts?.ext ?? "ts"}`);
46
49
  const stubsDir = resolveStubsDir(this.config, this.options, this.core);
47
50
  if (!stubsDir) {
48
51
  console.error("Error: stubsDir is not configured. Set stubsDir in resora.config.js.");
@@ -69,7 +72,7 @@ var ArkstackConsoleApp = class extends CliApp {
69
72
  * @returns
70
73
  */
71
74
  normalizePath = (p) => {
72
- return p.replace(process.cwd(), "");
75
+ return p.replace(Arkstack.rootDir(), "");
73
76
  };
74
77
  /**
75
78
  * Recursively merge defaultConfig with config from resora.config.js, giving
@@ -86,7 +89,6 @@ var ArkstackConsoleApp = class extends CliApp {
86
89
  };
87
90
  };
88
91
  };
89
- //#endregion
90
- export { resolveStubsDir as n, ArkstackConsoleApp as t };
91
92
 
92
- //# sourceMappingURL=app-CCSjImjr.js.map
93
+ //#endregion
94
+ export { resolveStubsDir as n, ArkstackConsoleApp as t };
package/dist/app.d.ts CHANGED
@@ -19,9 +19,18 @@ declare class ArkstackConsoleApp<TCore extends Core> extends CliApp {
19
19
  private readonly options;
20
20
  constructor(core: TCore, options: ConsoleAppOptions);
21
21
  makeController: (name: string, opts: any) => string;
22
+ /**
23
+ * Normalize a file path by removing the current working directory from it.
24
+ *
25
+ * @param p
26
+ * @returns
27
+ */
22
28
  normalizePath: (p: string) => string;
29
+ /**
30
+ * Recursively merge defaultConfig with config from resora.config.js, giving
31
+ * precedence to resora.
32
+ */
23
33
  mergeConfig: () => void;
24
34
  }
25
35
  //#endregion
26
- export { ArkstackConsoleApp, ConsoleAppOptions, resolveStubsDir };
27
- //# sourceMappingURL=app.d.ts.map
36
+ export { ArkstackConsoleApp, ConsoleAppOptions, resolveStubsDir };
package/dist/app.js CHANGED
@@ -1,2 +1,3 @@
1
- import { n as resolveStubsDir, t as ArkstackConsoleApp } from "./app-CCSjImjr.js";
2
- export { ArkstackConsoleApp, resolveStubsDir };
1
+ import { n as resolveStubsDir, t as ArkstackConsoleApp } from "./app-6GsnmZ2-.js";
2
+
3
+ export { ArkstackConsoleApp, resolveStubsDir };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,11 @@
2
2
  interface RunConsoleOptions {
3
3
  logo?: string;
4
4
  }
5
+ /**
6
+ * Runs the console kernel, initializing the application and registering commands.
7
+ *
8
+ * @param options
9
+ */
5
10
  declare const runConsoleKernel: (options?: RunConsoleOptions) => Promise<void>;
6
11
  //#endregion
7
- export { RunConsoleOptions, runConsoleKernel };
8
- //# sourceMappingURL=index.d.ts.map
12
+ export { RunConsoleOptions, runConsoleKernel };
package/dist/index.js CHANGED
@@ -1,15 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { t as ArkstackConsoleApp } from "./app-CCSjImjr.js";
3
- import { config, env, importFile, loadPrototypes, outputDir } from "@arkstack/common";
2
+ import { t as ArkstackConsoleApp } from "./app-6GsnmZ2-.js";
3
+ import { config, discoverCommands, env, importFile, loadPrototypes, outputDir, rebuildOutput } from "@arkstack/common";
4
+ import { existsSync, realpathSync } from "node:fs";
4
5
  import { fileURLToPath, pathToFileURL } from "node:url";
5
6
  import path, { join } from "node:path";
7
+ import { Arkstack } from "@arkstack/contract";
6
8
  import { MakeResource } from "resora";
7
- import { realpathSync } from "node:fs";
8
9
  import { Command, Kernel } from "@h3ravel/musket";
9
10
  import { spawn } from "node:child_process";
10
11
  import { resolve } from "path";
11
12
  import { writeFile } from "fs/promises";
12
13
  import chalk from "chalk";
14
+
13
15
  //#region dist/commands/BuildCommand.js
14
16
  var BuildCommand = class extends Command {
15
17
  signature = "build";
@@ -17,7 +19,7 @@ var BuildCommand = class extends Command {
17
19
  async handle() {
18
20
  await new Promise((resolve, reject) => {
19
21
  const child = spawn(process.platform === "win32" ? "pnpm.cmd" : "pnpm", ["exec", "tsdown"], {
20
- cwd: process.cwd(),
22
+ cwd: Arkstack.rootDir(),
21
23
  stdio: "inherit",
22
24
  env: Object.assign({}, process.env, { NODE_ENV: "production" })
23
25
  });
@@ -34,12 +36,16 @@ var BuildCommand = class extends Command {
34
36
  });
35
37
  }
36
38
  };
39
+
37
40
  //#endregion
38
41
  //#region dist/commands/DevCommand.js
39
42
  var DevCommand = class extends Command {
40
- signature = "dev";
43
+ signature = `dev
44
+ {--t|tunnel : tunnel the dev server through Ngrok}
45
+ `;
41
46
  description = "Run the development server";
42
47
  async handle() {
48
+ const tunnel = this.option?.("tunnel");
43
49
  await new Promise((resolve, reject) => {
44
50
  const child = spawn(process.platform === "win32" ? "pnpm.cmd" : "pnpm", [
45
51
  "exec",
@@ -47,8 +53,12 @@ var DevCommand = class extends Command {
47
53
  "--log-level",
48
54
  "silent"
49
55
  ], {
50
- cwd: process.cwd(),
51
- stdio: "inherit"
56
+ cwd: Arkstack.rootDir(),
57
+ stdio: "inherit",
58
+ env: Object.assign(process.env, {
59
+ NODE_ENV: "development",
60
+ TUNNEL: tunnel ? "true" : void 0
61
+ })
52
62
  });
53
63
  child.on("error", (error) => {
54
64
  reject(error);
@@ -63,6 +73,7 @@ var DevCommand = class extends Command {
63
73
  });
64
74
  }
65
75
  };
76
+
66
77
  //#endregion
67
78
  //#region dist/commands/MakeCommand.js
68
79
  var MakeCommand = class extends Command {
@@ -74,7 +85,7 @@ var MakeCommand = class extends Command {
74
85
  const name = String(this.argument("name")).replace(/\s+/g, "").replace(/\.js$/, "").trim();
75
86
  if (!name) return void this.error("Command name is required");
76
87
  const stubContent = this.stub(name);
77
- const filePath = resolve(process.cwd(), "src", `app/console/commands/${name}.js`);
88
+ const filePath = resolve(Arkstack.rootDir(), "src", `app/console/commands/${name}.js`);
78
89
  await writeFile(filePath, stubContent, { flag: "wx" });
79
90
  this.success(`Command ${name} created successfully at ${filePath}`);
80
91
  }
@@ -98,6 +109,7 @@ var MakeCommand = class extends Command {
98
109
  ].join("\n");
99
110
  }
100
111
  };
112
+
101
113
  //#endregion
102
114
  //#region dist/commands/MakeController.js
103
115
  var MakeController = class extends Command {
@@ -115,6 +127,7 @@ var MakeController = class extends Command {
115
127
  this.success(`Controller: ${this.app.normalizePath(name)} created successfully!`);
116
128
  }
117
129
  };
130
+
118
131
  //#endregion
119
132
  //#region dist/commands/MakeFullResource.js
120
133
  var MakeFullResource = class extends Command {
@@ -141,9 +154,11 @@ var MakeFullResource = class extends Command {
141
154
  this.success(`Created full resource set: ${this.app.normalizePath(res1.name)}, ${this.app.normalizePath(res2.name)}, ${this.app.normalizePath(name3)} successfully!`);
142
155
  }
143
156
  };
157
+
144
158
  //#endregion
145
159
  //#region dist/commands/MakeResource.js
146
160
  var MakeResource$1 = class extends MakeResource {};
161
+
147
162
  //#endregion
148
163
  //#region dist/commands/RouteList.js
149
164
  var RouteList = class extends Command {
@@ -174,6 +189,7 @@ var RouteList = class extends Command {
174
189
  ].join("\n");
175
190
  }
176
191
  };
192
+
177
193
  //#endregion
178
194
  //#region dist/logo.js
179
195
  var logo_default = String.raw`
@@ -184,16 +200,40 @@ var logo_default = String.raw`
184
200
  | | | | | | (__\__ \ || (_| | (__| <
185
201
  \_| |_/_| \___|___/\__\__,_|\___|_|\_\
186
202
  `;
203
+
187
204
  //#endregion
188
205
  //#region dist/index.js
189
- /**
190
- * Loads the core application instance by importing the bootstrap file.
206
+ /**
207
+ * A missing-module error from importing a stale/incomplete build artifact.
191
208
  *
209
+ * @param error
192
210
  * @returns
193
211
  */
212
+ const isMissingModuleError = (error) => {
213
+ const code = error?.code;
214
+ return code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND";
215
+ };
216
+ /**
217
+ * Loads the core application instance by importing the built bootstrap file.
218
+ *
219
+ * The kernel boots this for every command — including `build` — before the build
220
+ * can run, so a stale or incomplete build artifact (source changed since the last
221
+ * build: a module moved, renamed, or added) would otherwise wedge startup with
222
+ * `Cannot find module '<outDir>/...'`. When that happens and source is present,
223
+ * regenerate the output once and retry.
224
+ *
225
+ * @returns
226
+ */
194
227
  const loadCoreApp = async () => {
195
- const dist = path.relative(process.cwd(), outputDir());
196
- return (await importFile(join(process.cwd(), `${dist}/core/bootstrap.js`))).app;
228
+ const dist = path.relative(Arkstack.rootDir(), outputDir());
229
+ const bootstrapPath = join(Arkstack.rootDir(), `${dist}/core/bootstrap.js`);
230
+ try {
231
+ return (await importFile(bootstrapPath)).app;
232
+ } catch (error) {
233
+ if (!isMissingModuleError(error) || !existsSync(join(Arkstack.rootDir(), "src"))) throw error;
234
+ await rebuildOutput();
235
+ return (await importFile(bootstrapPath)).app;
236
+ }
197
237
  };
198
238
  /**
199
239
  * Runs the console kernel, initializing the application and registering commands.
@@ -203,12 +243,12 @@ const loadCoreApp = async () => {
203
243
  const runConsoleKernel = async (options = {}) => {
204
244
  loadPrototypes();
205
245
  const app = await loadCoreApp();
206
- const dist = path.relative(process.cwd(), outputDir());
207
246
  const stubsDir = process.env.ARKSTACK_STUBS_DIR;
208
247
  globalThis.app = () => app;
209
248
  globalThis.env = env;
210
249
  globalThis.config = config;
211
250
  globalThis.arkctx = { runtime: "CLI" };
251
+ const userCommands = await discoverCommands();
212
252
  await Kernel.init(await new ArkstackConsoleApp(app, { stubsDir }).loadConfig(), {
213
253
  logo: options.logo ?? logo_default,
214
254
  name: "Cmd",
@@ -219,16 +259,10 @@ const runConsoleKernel = async (options = {}) => {
219
259
  MakeFullResource,
220
260
  DevCommand,
221
261
  BuildCommand,
222
- MakeCommand
223
- ],
224
- discoveryPaths: [
225
- join(process.cwd(), "src", "app", "console", "commands/*.js"),
226
- join(process.cwd(), "src", "app/console/commands/*.js"),
227
- join(process.cwd(), "src", "app/console/commands/*.mjs"),
228
- join(process.cwd(), dist, "app/console/commands/*.js"),
229
- join(process.cwd(), dist, "app/console/commands/*.mjs"),
230
- join(process.cwd(), "node_modules", "@arkstack/*", "dist", "commands", "*.js")
262
+ MakeCommand,
263
+ ...userCommands
231
264
  ],
265
+ discoveryPaths: [join(Arkstack.rootDir(), "node_modules", "@arkstack/*", "dist", "commands", "*.js")],
232
266
  exceptionHandler(exception) {
233
267
  throw exception;
234
268
  }
@@ -250,7 +284,6 @@ const isEntrypointExecution = () => {
250
284
  }
251
285
  };
252
286
  if (isEntrypointExecution()) await runConsoleKernel();
253
- //#endregion
254
- export { runConsoleKernel };
255
287
 
256
- //# sourceMappingURL=index.js.map
288
+ //#endregion
289
+ export { runConsoleKernel };
package/dist/prepare.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { Arkstack } from "@arkstack/contract";
1
2
  import { spawn } from "node:child_process";
2
3
  import chalk from "chalk";
4
+
3
5
  //#region dist/prepare.js
4
6
  const NODE_ENV = process.env.NODE_ENV || "development";
5
7
  const child = spawn(process.platform === "win32" ? "pnpm.cmd" : "pnpm", [
@@ -7,7 +9,7 @@ const child = spawn(process.platform === "win32" ? "pnpm.cmd" : "pnpm", [
7
9
  "tsdown",
8
10
  "--log-level=silent"
9
11
  ], {
10
- cwd: process.cwd(),
12
+ cwd: Arkstack.rootDir(),
11
13
  stdio: "inherit",
12
14
  env: Object.assign({}, process.env, {
13
15
  NODE_ENV,
@@ -24,7 +26,6 @@ child.on("exit", (code) => {
24
26
  }
25
27
  throw new Error(`tsdown exited with code ${code}`);
26
28
  });
27
- //#endregion
28
- export {};
29
29
 
30
- //# sourceMappingURL=prepare.js.map
30
+ //#endregion
31
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/console-slim",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "type": "module",
5
5
  "description": "Slim console module for Arkstack, providing the command-line runtime and console integration layer.",
6
6
  "homepage": "https://arkstack.toneflix.net",
@@ -42,14 +42,14 @@
42
42
  }
43
43
  },
44
44
  "peerDependencies": {
45
- "clear-router": "^2.6.4"
45
+ "clear-router": "^2.9.0"
46
46
  },
47
47
  "dependencies": {
48
- "@h3ravel/musket": "^0.10.1",
48
+ "@h3ravel/musket": "^2.2.1",
49
49
  "chalk": "^5.6.2",
50
- "resora": "^1.2.4",
51
- "@arkstack/common": "^0.5.2",
52
- "@arkstack/contract": "^0.5.2"
50
+ "resora": "^1.3.27",
51
+ "@arkstack/common": "^0.5.3",
52
+ "@arkstack/contract": "^0.5.3"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsdown",
@@ -1 +0,0 @@
1
- {"version":3,"file":"app-CCSjImjr.js","names":[],"sources":["../src/config.ts","../src/app.ts"],"sourcesContent":["import { Core } from './types'\n\nexport const defaultConfig = (app: Core) => {\n const driver = app.getDriver().name ?? 'h3'\n\n return {\n resourcesDir: 'src/app/http/resources',\n localStubsDir: `node_modules/@arkstack/driver-${driver}/stubs`,\n stubs: {\n resource: 'resource.stub',\n collection: 'resource.collection.stub',\n controller: 'controller.stub',\n api: 'controller.api.stub',\n model: 'controller.model.stub',\n apiResource: 'controller.api.resource.stub',\n }\n }\n}","// oxlint-disable typescript/no-explicit-any\nimport path, { isAbsolute, join } from 'node:path'\n\nimport { CliApp } from 'resora'\nimport { defaultConfig } from './config'\nimport { existsSync } from 'node:fs'\n\ninterface Core {\n [k: string]: any\n getDriver: () => {\n [k: string]: any\n name: string\n }\n}\n\nexport interface ConsoleAppOptions {\n stubsDir?: string;\n}\n\nexport const resolveStubsDir = (\n config: { localStubsDir?: string } | undefined,\n options?: ConsoleAppOptions,\n core?: Core\n\n) => {\n const configuredDir = config?.localStubsDir\n\n if (configuredDir) {\n return isAbsolute(configuredDir)\n ? configuredDir\n : join(process.cwd(), configuredDir)\n }\n\n if (!options?.stubsDir) {\n const driver = core?.getDriver().name ?? 'h3'\n let stubsDir = path.resolve(process.cwd(), `node_modules/@arkstack/driver-${driver}/stubs`)\n if (!existsSync(stubsDir)) {\n stubsDir = path.resolve(process.cwd(), 'stubs')\n }\n\n return stubsDir\n }\n\n return options?.stubsDir\n}\n\nexport class ArkstackConsoleApp<TCore extends Core> extends CliApp {\n core: TCore\n private readonly options: ConsoleAppOptions\n\n constructor(\n core: TCore,\n options: ConsoleAppOptions,\n ) {\n super()\n this.core = core\n this.options = options\n this.mergeConfig()\n }\n\n makeController = (name: string, opts: any) => {\n this.mergeConfig()\n const normalized = (name.endsWith('Controller') ? name.replace(/controller/i, '') : name)\n\n let controllerName = normalized.endsWith('Controller') ? normalized : `${normalized}Controller`\n const controllersDir = path.resolve(process.cwd(), 'src', 'app/http/controllers')\n const fileName = `${controllerName}.${opts?.ext ?? 'ts'}`\n const outputPath = join(controllersDir, fileName)\n const stubsDir = resolveStubsDir(this.config as any, this.options, this.core)\n if (!stubsDir) {\n console.error('Error: stubsDir is not configured. Set stubsDir in resora.config.js.')\n process.exit(1)\n }\n\n const stubPath = join(\n stubsDir,\n opts.model\n ? (this.config.stubs as any).model\n : opts.api\n ? (this.config.stubs as any).api\n : (this.config.stubs as any).controller,\n )\n\n if (!existsSync(stubPath)) {\n console.error(`Error: Stub file ${stubPath} not found.`)\n process.exit(1)\n }\n\n controllerName = controllerName.split('/').pop() as string\n\n this.generateFile(\n stubPath,\n outputPath,\n {\n // If class name contains / or ., take only the last part for the class name\n ControllerName: controllerName,\n Model: opts.model?.pascalCase(),\n ModelName: opts.model?.camelCase(),\n Name: controllerName.replace(/controller/i, ''),\n },\n opts,\n )\n\n return outputPath\n }\n\n /**\n * Normalize a file path by removing the current working directory from it. \n * \n * @param p \n * @returns \n */\n normalizePath = (p: string) => {\n return p.replace(process.cwd(), '')\n }\n\n /**\n * Recursively merge defaultConfig with config from resora.config.js, giving \n * precedence to resora.\n */\n mergeConfig = () => {\n this.config = {\n ...defaultConfig(this.core),\n ...this.config,\n stubs: {\n ...defaultConfig(this.core).stubs,\n ...this.config?.stubs,\n },\n }\n }\n}\n"],"mappings":";;;;AAEA,MAAa,iBAAiB,QAAc;CAGxC,OAAO;EACH,cAAc;EACd,eAAe,iCAJJ,IAAI,WAAW,CAAC,QAAQ,KAIoB;EACvD,OAAO;GACH,UAAU;GACV,YAAY;GACZ,YAAY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GAChB;EACJ;;;;ACGL,MAAa,mBACT,QACA,SACA,SAEC;CACD,MAAM,gBAAgB,QAAQ;CAE9B,IAAI,eACA,OAAO,WAAW,cAAc,GAC1B,gBACA,KAAK,QAAQ,KAAK,EAAE,cAAc;CAG5C,IAAI,CAAC,SAAS,UAAU;EACpB,MAAM,SAAS,MAAM,WAAW,CAAC,QAAQ;EACzC,IAAI,WAAW,KAAK,QAAQ,QAAQ,KAAK,EAAE,iCAAiC,OAAO,QAAQ;EAC3F,IAAI,CAAC,WAAW,SAAS,EACrB,WAAW,KAAK,QAAQ,QAAQ,KAAK,EAAE,QAAQ;EAGnD,OAAO;;CAGX,OAAO,SAAS;;AAGpB,IAAa,qBAAb,cAA4D,OAAO;CAC/D;CACA;CAEA,YACI,MACA,SACF;EACE,OAAO;EACP,KAAK,OAAO;EACZ,KAAK,UAAU;EACf,KAAK,aAAa;;CAGtB,kBAAkB,MAAc,SAAc;EAC1C,KAAK,aAAa;EAClB,MAAM,aAAc,KAAK,SAAS,aAAa,GAAG,KAAK,QAAQ,eAAe,GAAG,GAAG;EAEpF,IAAI,iBAAiB,WAAW,SAAS,aAAa,GAAG,aAAa,GAAG,WAAW;EAGpF,MAAM,aAAa,KAFI,KAAK,QAAQ,QAAQ,KAAK,EAAE,OAAO,uBAEpB,EAAE,GADpB,eAAe,GAAG,MAAM,OAAO,OACF;EACjD,MAAM,WAAW,gBAAgB,KAAK,QAAe,KAAK,SAAS,KAAK,KAAK;EAC7E,IAAI,CAAC,UAAU;GACX,QAAQ,MAAM,uEAAuE;GACrF,QAAQ,KAAK,EAAE;;EAGnB,MAAM,WAAW,KACb,UACA,KAAK,QACE,KAAK,OAAO,MAAc,QAC3B,KAAK,MACA,KAAK,OAAO,MAAc,MAC1B,KAAK,OAAO,MAAc,WACxC;EAED,IAAI,CAAC,WAAW,SAAS,EAAE;GACvB,QAAQ,MAAM,oBAAoB,SAAS,aAAa;GACxD,QAAQ,KAAK,EAAE;;EAGnB,iBAAiB,eAAe,MAAM,IAAI,CAAC,KAAK;EAEhD,KAAK,aACD,UACA,YACA;GAEI,gBAAgB;GAChB,OAAO,KAAK,OAAO,YAAY;GAC/B,WAAW,KAAK,OAAO,WAAW;GAClC,MAAM,eAAe,QAAQ,eAAe,GAAG;GAClD,EACD,KACH;EAED,OAAO;;;;;;;;CASX,iBAAiB,MAAc;EAC3B,OAAO,EAAE,QAAQ,QAAQ,KAAK,EAAE,GAAG;;;;;;CAOvC,oBAAoB;EAChB,KAAK,SAAS;GACV,GAAG,cAAc,KAAK,KAAK;GAC3B,GAAG,KAAK;GACR,OAAO;IACH,GAAG,cAAc,KAAK,KAAK,CAAC;IAC5B,GAAG,KAAK,QAAQ;IACnB;GACJ"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["MakeResource","MakeResourceBase","logo","MakeResource"],"sources":["../src/commands/BuildCommand.ts","../src/commands/DevCommand.ts","../src/commands/MakeCommand.ts","../src/commands/MakeController.ts","../src/commands/MakeFullResource.ts","../src/commands/MakeResource.ts","../src/commands/RouteList.ts","../src/logo.ts","../src/index.ts"],"sourcesContent":["import { Command } from '@h3ravel/musket'\nimport { spawn } from 'node:child_process'\n\nexport class BuildCommand extends Command {\n protected signature = 'build'\n\n protected description = 'Build the application for production'\n\n async handle () {\n await new Promise<void>((resolve, reject) => {\n const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'\n const child = spawn(command, ['exec', 'tsdown'], {\n cwd: process.cwd(),\n stdio: 'inherit',\n env: Object.assign({}, process.env, {\n NODE_ENV: 'production',\n }),\n })\n\n child.on('error', (error) => {\n reject(error)\n })\n\n child.on('exit', (code) => {\n if (code === 0 || code === null) {\n resolve()\n \nreturn\n }\n\n reject(new Error(`tsdown exited with code ${code}`))\n })\n })\n }\n}\n","import { Command } from '@h3ravel/musket'\nimport { spawn } from 'node:child_process'\n\nexport class DevCommand extends Command {\n protected signature = 'dev'\n\n protected description = 'Run the development server'\n\n async handle () {\n await new Promise<void>((resolve, reject) => {\n const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'\n const child = spawn(command, ['exec', 'tsdown', '--log-level', 'silent'], {\n cwd: process.cwd(),\n stdio: 'inherit',\n })\n\n child.on('error', (error) => {\n reject(error)\n })\n\n child.on('exit', (code) => {\n if (code === 0 || code === null) {\n resolve()\n \nreturn\n }\n\n reject(new Error(`tsdown exited with code ${code}`))\n })\n })\n }\n}\n","import { Command } from '@h3ravel/musket'\nimport { resolve } from 'path'\nimport { writeFile } from 'fs/promises'\n\nexport class MakeCommand extends Command {\n protected signature = `make:command \n {name : name of the command to create}\n `\n\n protected description = 'Creates a new console command class.'\n\n async handle () {\n const name = String(this.argument('name'))\n .replace(/\\s+/g, '')\n .replace(/\\.ts$/, '').trim()\n\n if (!name) return void this.error('Command name is required')\n\n const stubContent = this.stub(name)\n const filePath = resolve(process.cwd(), 'src', `app/console/commands/${name}.ts`)\n\n await writeFile(filePath, stubContent, { flag: 'wx' })\n this.success(`Command ${name} created successfully at ${filePath}`)\n }\n\n stub (name: string) {\n name = name.endsWith('Command') ? name : `${name}Command`\n name = name.split('/').pop()!.split('.').shift()!\n const signature = `app:${name.toLowerCase()}`\n const description = `Description for ${signature} command`\n\n const stub = [\n 'import { Command } from \\'@h3ravel/musket\\'',\n '',\n `export class ${name} extends Command {`,\n ` signature = '${signature}'`,\n '',\n ` description = '${description}'`,\n '',\n ' async handle () {',\n ' // Command logic goes here',\n ' }',\n '}',\n ]\n\n return stub.join('\\n')\n }\n}\n","import { ArkstackConsoleApp } from '../app'\nimport { Command } from '@h3ravel/musket'\n\n// oxlint-disable-next-line typescript/no-explicit-any\nexport class MakeController extends Command<ArkstackConsoleApp<any>> {\n protected signature = `make:controller\n {name : name of the controller to create}\n {--api : make an API controller}\n {--m|model? : name of model to attach to controller}\n {--force : force overwrite if controller already exists}\n `\n\n protected description = 'Create a new controller file'\n\n async handle () {\n this.app.command = this\n\n if (!this.argument('name')) return void this.error('Error: Controller name is required.')\n\n const name = this.app.makeController(this.argument('name'), this.options())\n\n this.success(`Controller: ${this.app.normalizePath(name)} created successfully!`)\n }\n}\n","import { ArkstackConsoleApp } from '../app'\nimport { Command } from '@h3ravel/musket'\n\n// oxlint-disable-next-line typescript/no-explicit-any\nexport class MakeFullResource extends Command<ArkstackConsoleApp<any>> {\n protected signature = `make:full-resource\n {prefix : prefix of the resources to create, \"Admin\" will create AdminResource, AdminCollection and AdminController}\n {--m|model? : name of model to attach to the generated controller}\n {--f|factory : Create and link a factory}\n {--s|seeder : Create a seeder file for the model (only if --model is specified)}\n {--x|migration : Create a migration file for the model (only if --model is specified)}\n {--force : force overwrite if resources already exist}\n `\n\n protected description =\n 'Create a full new set of API resources (Controller, Resource, Collection)'\n\n async handle () {\n this.app.command = this\n\n const res1 = this.app.makeResource(this.argument('prefix'), {\n force: this.option('force')\n })\n const res2 = this.app.makeResource(this.argument('prefix') + 'Collection', {\n collection: true,\n force: this.option('force'),\n })\n const name3 = this.app.makeController(\n this.argument('prefix'),\n Object.assign({}, this.options(), { api: true, force: this.option('force') }),\n )\n\n this.success(`Created full resource set: ${this.app.normalizePath(res1.name)}, ${this.app.normalizePath(res2.name)}, ${this.app.normalizePath(name3)} successfully!`)\n }\n}\n","import { MakeResource as MakeResourceBase } from 'resora'\n\nexport class MakeResource extends MakeResourceBase {\n}\n","import { ArkstackConsoleApp } from '../app'\nimport type { ArkstackRouterAwareCore } from '@arkstack/contract'\nimport { Command } from '@h3ravel/musket'\nimport type { Route } from 'clear-router'\nimport chalk from 'chalk'\n\ntype App = ArkstackConsoleApp<ArkstackRouterAwareCore<unknown, Route[]>>;\n\nexport class RouteList extends Command<App> {\n protected signature = `route:list\n {--p|path? : Path to filter routes by}\n `\n\n protected description = 'List all registered routes'\n\n async handle () {\n const routes = await this.app.core.getRouter().list(this.options(), this.app.core.getAppInstance())\n\n console.log(this.formatRoutes(routes.reverse()))\n this.newLine()\n this.info(`Total routes: ${routes.length}`)\n }\n\n private formatRoutes (routes: Route[]) {\n if (routes.length === 0) {\n return 'No routes registered.'\n }\n\n const rows = routes.map((route) => ({\n method: route.methods.join('|').toUpperCase(),\n path: route.path,\n handler: route.controllerName ? `${route.controllerName} → ${route.actionName}` : route.actionName ?? 'N/A',\n }))\n\n const methodWidth = Math.max('METHOD'.length, ...rows.map((row) => row.method.length))\n const pathWidth = Math.max('PATH'.length, ...rows.map((row) => row.path.length))\n const handlerWidth = Math.max('HANDLER'.length, ...rows.map((row) => row.handler.length))\n\n const header = `${'METHOD'.padEnd(methodWidth)} ${'PATH'.padEnd(pathWidth)} ${'HANDLER'.padEnd(handlerWidth)}`\n const divider = `${'-'.repeat(methodWidth)} ${'-'.repeat(pathWidth)} ${'-'.repeat(handlerWidth)}`\n const body = rows.map(\n (row) => `${chalk.green(row.method.padEnd(methodWidth))} ${chalk.blue(row.path.padEnd(pathWidth))} ${chalk.yellow(row.handler.padEnd(handlerWidth))}`\n )\n\n return [header, divider, ...body].join('\\n')\n }\n}\n","export default String.raw`\n ___ _ _ \n / _ \\ | | | | \n/ /_\\ \\_ __ ___ ___| |_ __ _ ___| | __\n| _ | '__/ __/ __| __/ _' |/ __| |/ /\n| | | | | | (__\\__ \\ || (_| | (__| < \n\\_| |_/_| \\___|___/\\__\\__,_|\\___|_|\\_\\ \n`","#!/usr/bin/env node\n\nimport { config, env, importFile, loadPrototypes, outputDir } from '@arkstack/common'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport path, { join } from 'node:path'\n\nimport { ArkstackConsoleApp } from './app'\nimport { BuildCommand } from './commands/BuildCommand'\nimport { DevCommand } from './commands/DevCommand'\nimport { Kernel } from '@h3ravel/musket'\nimport { MakeCommand } from './commands/MakeCommand'\nimport { MakeController } from './commands/MakeController'\nimport { MakeFullResource } from './commands/MakeFullResource'\nimport { MakeResource } from './commands/MakeResource'\nimport { RouteList } from './commands/RouteList'\nimport logo from './logo'\nimport { realpathSync } from 'node:fs'\n\nexport interface RunConsoleOptions {\n logo?: string;\n}\n\n/**\n * Loads the core application instance by importing the bootstrap file.\n * \n * @returns \n */\nconst loadCoreApp = async () => {\n const dist = path.relative(process.cwd(), outputDir())\n\n const bootstrapPath = join(process.cwd(), `${dist}/core/bootstrap.js`)\n\n\n const module = await importFile<{ app: any }>(bootstrapPath)\n\n return module.app\n}\n\n/**\n * Runs the console kernel, initializing the application and registering commands.\n * \n * @param options \n */\nexport const runConsoleKernel = async (options: RunConsoleOptions = {}) => {\n loadPrototypes()\n\n const app = await loadCoreApp()\n const dist = path.relative(process.cwd(), outputDir())\n const stubsDir = process.env.ARKSTACK_STUBS_DIR\n globalThis.app = () => app as never\n globalThis.env = env\n globalThis.config = config\n globalThis.arkctx = {\n runtime: 'CLI',\n }\n\n await Kernel.init(await new ArkstackConsoleApp(app, { stubsDir }).loadConfig(), {\n logo: options.logo ?? logo,\n name: 'Cmd',\n baseCommands: [\n RouteList,\n MakeResource,\n MakeController,\n MakeFullResource,\n DevCommand,\n BuildCommand,\n MakeCommand,\n ],\n discoveryPaths: [\n join(process.cwd(), 'src', 'app', 'console', 'commands/*.ts'),\n join(process.cwd(), 'src', 'app/console/commands/*.js'),\n join(process.cwd(), 'src', 'app/console/commands/*.mjs'),\n join(process.cwd(), dist, 'app/console/commands/*.js'),\n join(process.cwd(), dist, 'app/console/commands/*.mjs'),\n join(process.cwd(), 'node_modules', '@arkstack/*', 'dist', 'commands', '*.js'),\n ],\n exceptionHandler (exception) {\n throw exception\n },\n })\n}\n\n/**\n * Determines if the current module is being executed as the entry \n * point of the application.\n * \n * @returns \n */\nconst isEntrypointExecution = () => {\n const argvEntry = process.argv[1]\n\n if (!argvEntry) {\n return false\n }\n\n try {\n const currentModulePath = realpathSync(fileURLToPath(import.meta.url))\n const entryPath = realpathSync(argvEntry)\n\n return currentModulePath === entryPath\n } catch {\n return import.meta.url === pathToFileURL(argvEntry).href\n }\n}\n\nif (isEntrypointExecution()) {\n await runConsoleKernel()\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"prepare.js","names":[],"sources":["../src/prepare.ts"],"sourcesContent":["import chalk from 'chalk'\nimport { spawn } from 'node:child_process'\n\nconst NODE_ENV = process.env.NODE_ENV || 'development'\nconst command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'\nconst child = spawn(command, ['exec', 'tsdown', '--log-level=silent'], {\n cwd: process.cwd(),\n stdio: 'inherit',\n env: Object.assign({}, process.env, {\n NODE_ENV,\n CLI_BUILD: 'true',\n }),\n})\n\nchild.on('error', (error) => {\n throw error\n})\n\nchild.on('exit', (code) => {\n if (code === 0 || code === null) {\n console.log(chalk.green(`Arkstak is ready for ${NODE_ENV === 'production' ? 'deployment' : NODE_ENV}!`))\n\n return\n }\n\n throw new Error(`tsdown exited with code ${code}`)\n\n})"],"mappings":";;;AAGA,MAAM,WAAW,QAAQ,IAAI,YAAY;AAEzC,MAAM,QAAQ,MADE,QAAQ,aAAa,UAAU,aAAa,QAC/B;CAAC;CAAQ;CAAU;CAAqB,EAAE;CACnE,KAAK,QAAQ,KAAK;CAClB,OAAO;CACP,KAAK,OAAO,OAAO,EAAE,EAAE,QAAQ,KAAK;EAChC;EACA,WAAW;EACd,CAAC;CACL,CAAC;AAEF,MAAM,GAAG,UAAU,UAAU;CACzB,MAAM;EACR;AAEF,MAAM,GAAG,SAAS,SAAS;CACvB,IAAI,SAAS,KAAK,SAAS,MAAM;EAC7B,QAAQ,IAAI,MAAM,MAAM,wBAAwB,aAAa,eAAe,eAAe,SAAS,GAAG,CAAC;EAExG;;CAGJ,MAAM,IAAI,MAAM,2BAA2B,OAAO"}