@arkstack/console 0.13.2 → 0.14.1

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.
Files changed (2) hide show
  1. package/dist/index.js +159 -3
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as ArkstackConsoleApp } from "./app-DnaQWE9q.js";
3
3
  import { n as BaseTCConfig, r as TSConfig, t as BuildInterfaces } from "./BuildInterfaces-CsZ3Uerb.js";
4
- import { abort, abortIf, assertFound, config, discoverCommands, env, importFile, initializeGlobalContext, loadPrototypes, outputDir, rebuildOutput } from "@arkstack/common";
5
- import { existsSync, realpathSync } from "node:fs";
4
+ import { Publisher, abort, abortIf, assertFound, config, discoverCommands, env, importFile, initializeGlobalContext, loadPrototypes, outputDir, rebuildOutput } from "@arkstack/common";
5
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
- import path, { join } from "node:path";
7
+ import path, { dirname, join } from "node:path";
8
8
  import { Arkstack } from "@arkstack/contract";
9
9
  import { MakeResource, applyRuntimeConfig, getDefaultConfig } from "resora";
10
10
  import { Command, Kernel } from "@h3ravel/musket";
11
11
  import { spawn } from "node:child_process";
12
+ import { randomBytes } from "node:crypto";
12
13
  import { resolve } from "path";
13
14
  import { writeFile } from "fs/promises";
14
15
  import { CliApp as CliApp$1 } from "arkormx";
@@ -76,6 +77,47 @@ var DevCommand = class extends Command {
76
77
  }
77
78
  };
78
79
 
80
+ //#endregion
81
+ //#region dist/commands/KeyGenerateCommand.js
82
+ /**
83
+ * Generate and set the application key (APP_KEY).
84
+ *
85
+ * APP_KEY is the unified secret used for signing JWTs and encrypting values
86
+ * across the framework (exposed as `config('app.key')`).
87
+ */
88
+ var KeyGenerateCommand = class extends Command {
89
+ signature = `key:generate
90
+ {--show : Display the generated key instead of writing it to the .env file.}
91
+ {--force : Overwrite the existing APP_KEY without confirmation.}
92
+ `;
93
+ description = "Set the application key (APP_KEY).";
94
+ async handle() {
95
+ const key = this.generateKey();
96
+ if (this.option("show")) {
97
+ this.line(key);
98
+ return;
99
+ }
100
+ const envPath = join(Arkstack.rootDir(), ".env");
101
+ if (!existsSync(envPath)) {
102
+ this.error("No .env file found. Copy .env.example to .env before running key:generate.");
103
+ return;
104
+ }
105
+ const contents = readFileSync(envPath, "utf-8");
106
+ const existing = contents.match(/^APP_KEY=(.*)$/m);
107
+ if (existing?.[1]?.trim() && !this.option("force")) {
108
+ if (!await this.confirm("An application key already exists. Overwrite it?", false)) {
109
+ this.info("Application key generation aborted.");
110
+ return;
111
+ }
112
+ }
113
+ writeFileSync(envPath, existing ? contents.replace(/^APP_KEY=.*$/m, `APP_KEY=${key}`) : `${contents.replace(/\s*$/, "")}\nAPP_KEY=${key}\n`);
114
+ this.success("Application key set successfully.");
115
+ }
116
+ generateKey() {
117
+ return randomBytes(32).toString("base64url");
118
+ }
119
+ };
120
+
79
121
  //#endregion
80
122
  //#region dist/commands/MakeCommand.js
81
123
  var MakeCommand = class extends Command {
@@ -198,6 +240,118 @@ var MakeResource$1 = class extends MakeResource {
198
240
  }
199
241
  };
200
242
 
243
+ //#endregion
244
+ //#region dist/commands/PublishCommand.js
245
+ /** Suffix that marks a file as a publishable stub; stripped on publish. */
246
+ const STUB_SUFFIX = ".stub";
247
+ /**
248
+ * Strip a trailing `.stub` suffix from a path.
249
+ *
250
+ * Stubs are shipped as `<name>.<ext>.stub` so they are ignored by linting,
251
+ * type-checking and test discovery in the source repo, then restored to their
252
+ * real extension when published into an application.
253
+ *
254
+ * @param path
255
+ */
256
+ const stripStubSuffix = (path) => path.endsWith(STUB_SUFFIX) ? path.slice(0, -5) : path;
257
+ /**
258
+ * Publish artifacts (migrations, stubs, assets, …) that installed packages
259
+ * register via `publishes()` into the consuming application.
260
+ */
261
+ var PublishCommand = class extends Command {
262
+ signature = `publish
263
+ {--package= : Only publish artifacts registered by this package (e.g. @arkstack/cache).}
264
+ {--tag= : Only publish artifacts registered under this tag.}
265
+ {--force : Overwrite files that already exist at the destination.}
266
+ {--list : List the publishable artifacts without copying anything.}
267
+ `;
268
+ description = "Publish package artifacts into your application.";
269
+ async handle() {
270
+ await this.loadPackageSetups();
271
+ const filter = {
272
+ package: this.option("package"),
273
+ tag: this.option("tag")
274
+ };
275
+ const groups = Publisher.publishables(filter);
276
+ if (groups.length < 1) {
277
+ this.warn(`No publishable artifacts found${this.describeFilter(filter)}.`);
278
+ return;
279
+ }
280
+ if (this.option("list")) {
281
+ this.listGroups(groups);
282
+ return;
283
+ }
284
+ let published = 0;
285
+ let skipped = 0;
286
+ for (const group of groups) for (const entry of group.entries) {
287
+ if (!existsSync(entry.from)) {
288
+ this.warn(`[${group.package}] Source not found, skipping: ${entry.from}`);
289
+ continue;
290
+ }
291
+ const to = stripStubSuffix(entry.to);
292
+ const dest = join(Arkstack.rootDir(), to);
293
+ if (existsSync(dest) && !this.option("force")) {
294
+ this.warn(`Exists, skipped (use --force): ${to}`);
295
+ skipped++;
296
+ continue;
297
+ }
298
+ mkdirSync(dirname(dest), { recursive: true });
299
+ cpSync(entry.from, dest, { recursive: true });
300
+ if (statSync(dest).isDirectory()) this.stripStubsInTree(dest);
301
+ this.success(`Published [${group.package}] -> ${to}`);
302
+ published++;
303
+ }
304
+ this.info(`Done. ${published} published, ${skipped} skipped.`);
305
+ }
306
+ /**
307
+ * Recursively rename `*.stub` files within a published directory to their
308
+ * real extension.
309
+ *
310
+ * @param dir
311
+ */
312
+ stripStubsInTree(dir) {
313
+ for (const item of readdirSync(dir, {
314
+ recursive: true,
315
+ withFileTypes: true
316
+ })) if (item.isFile() && item.name.endsWith(STUB_SUFFIX)) {
317
+ const current = join(item.parentPath, item.name);
318
+ renameSync(current, stripStubSuffix(current));
319
+ }
320
+ }
321
+ /**
322
+ * Print the publishable artifacts grouped by package without copying.
323
+ *
324
+ * @param groups
325
+ */
326
+ listGroups(groups) {
327
+ this.info("Publishable artifacts:");
328
+ for (const group of groups) {
329
+ this.line(` ${group.package}${group.tag ? ` (tag: ${group.tag})` : ""}`);
330
+ for (const entry of group.entries) this.line(` - ${stripStubSuffix(entry.to)}`);
331
+ }
332
+ }
333
+ /**
334
+ * Import the `setup` module of every installed `@arkstack/*` package so its
335
+ * `publishes()` registrations run. Errors (missing build, side effects) are
336
+ * ignored so one bad package cannot break publishing.
337
+ */
338
+ async loadPackageSetups() {
339
+ const scope = join(Arkstack.rootDir(), "node_modules", "@arkstack");
340
+ if (!existsSync(scope)) return;
341
+ for (const pkg of readdirSync(scope)) {
342
+ const setup = join(scope, pkg, "dist", "setup.js");
343
+ if (!existsSync(setup)) continue;
344
+ try {
345
+ await import(pathToFileURL(setup).href);
346
+ } catch {}
347
+ }
348
+ }
349
+ describeFilter(filter) {
350
+ const parts = [filter.package ? `package "${filter.package}"` : "", filter.tag ? `tag "${filter.tag}"` : ""].filter(Boolean);
351
+ return parts.length ? ` for ${parts.join(" and ")}` : "";
352
+ }
353
+ };
354
+
201
355
  //#endregion
202
356
  //#region dist/commands/RouteList.js
203
357
  var RouteList = class extends Command {
@@ -332,6 +486,8 @@ const runConsoleKernel = async (options = {}) => {
332
486
  DevCommand,
333
487
  BuildCommand,
334
488
  MakeCommand,
489
+ KeyGenerateCommand,
490
+ PublishCommand,
335
491
  ...userCommands
336
492
  ],
337
493
  discoveryPaths: [join(Arkstack.rootDir(), "node_modules", "@arkstack/*", "dist", "commands", "*.js")],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/console",
3
- "version": "0.13.2",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "description": "Console module for Arkstack, providing the command-line runtime and console integration layer.",
6
6
  "homepage": "https://arkstack.toneflix.net/guide/cli",
@@ -42,7 +42,7 @@
42
42
  }
43
43
  },
44
44
  "peerDependencies": {
45
- "arkormx": "^2.9.2",
45
+ "arkormx": "^2.9.3",
46
46
  "clear-router": "^2.8.8"
47
47
  },
48
48
  "dependencies": {
@@ -51,8 +51,8 @@
51
51
  "chalk": "^5.6.2",
52
52
  "resora": "^1.3.26",
53
53
  "ts-morph": "^28.0.0",
54
- "@arkstack/common": "^0.13.2",
55
- "@arkstack/contract": "^0.13.2"
54
+ "@arkstack/contract": "^0.14.1",
55
+ "@arkstack/common": "^0.14.1"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsdown",