@chrisluyi/daas-cli 1.2.1 → 1.4.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.
Files changed (3) hide show
  1. package/dist/index.js +242 -133
  2. package/package.json +8 -2
  3. package/skill.md +48 -1
package/dist/index.js CHANGED
@@ -2311,12 +2311,36 @@ async function runMain(cmd, opts = {}) {
2311
2311
  }
2312
2312
  }
2313
2313
 
2314
- // src/commands/dev.ts
2315
- import { createRsbuild } from "@rsbuild/core";
2314
+ // src/index.ts
2315
+ import { createLogger as createLogger5, setLogger as setLogger5 } from "@chrisluyi/logger";
2316
+
2317
+ // src/logger/consolaTransport.ts
2318
+ function consolaTransport() {
2319
+ return (entry) => {
2320
+ switch (entry.level) {
2321
+ case "debug":
2322
+ consola.debug(entry.message, entry.context ?? "");
2323
+ break;
2324
+ case "info":
2325
+ consola.info(entry.message);
2326
+ break;
2327
+ case "warn":
2328
+ consola.warn(entry.message);
2329
+ break;
2330
+ case "error":
2331
+ consola.fatal(entry.message);
2332
+ break;
2333
+ }
2334
+ };
2335
+ }
2336
+
2337
+ // src/commands/build.ts
2316
2338
  import { createConfig } from "@chrisluyi/rsbuild-config";
2339
+ import { createLogger, setLogger, apiTransport } from "@chrisluyi/logger";
2340
+ import { createRsbuild } from "@rsbuild/core";
2317
2341
 
2318
2342
  // src/daas-config.ts
2319
- import { readFileSync, existsSync } from "fs";
2343
+ import { existsSync, readFileSync } from "fs";
2320
2344
  import { resolve } from "path";
2321
2345
 
2322
2346
  class ConfigError extends Error {
@@ -2339,12 +2363,13 @@ function readDaasConfig(cwd = process.cwd()) {
2339
2363
  configUrl: daas.configUrl,
2340
2364
  port: daas.port ?? 3000,
2341
2365
  coverage: daas.coverage,
2342
- setupFiles: daas.setupFiles
2366
+ setupFiles: daas.setupFiles,
2367
+ logUrl: daas.logUrl
2343
2368
  };
2344
2369
  }
2345
2370
 
2346
2371
  // src/manifest.ts
2347
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
2372
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
2348
2373
  import { resolve as resolve2 } from "path";
2349
2374
 
2350
2375
  class ManifestError extends Error {
@@ -2387,6 +2412,33 @@ function stripScope(name) {
2387
2412
  return name.replace(/^@[^/]+\//, "");
2388
2413
  }
2389
2414
 
2415
+ // src/output.ts
2416
+ function formatSuccess(command, data) {
2417
+ return { ok: true, command, cliVersion: getCliVersion(), ...data };
2418
+ }
2419
+ function formatError(command, exitCode, error, suggestion) {
2420
+ return {
2421
+ ok: false,
2422
+ command,
2423
+ exitCode,
2424
+ error,
2425
+ suggestion,
2426
+ cliVersion: getCliVersion()
2427
+ };
2428
+ }
2429
+ function writeJsonSuccess(command, data) {
2430
+ process.stdout.write(`${JSON.stringify(formatSuccess(command, data))}
2431
+ `);
2432
+ }
2433
+ function writeJsonError(command, exitCode, error, suggestion) {
2434
+ process.stdout.write(`${JSON.stringify(formatError(command, exitCode, error, suggestion))}
2435
+ `);
2436
+ process.exit(exitCode);
2437
+ }
2438
+ function getCliVersion() {
2439
+ return process.env.DAAS_CLI_VERSION ?? "0.0.0";
2440
+ }
2441
+
2390
2442
  // src/remote-config.ts
2391
2443
  import { SUPPORTED_CONFIG_VERSION } from "@chrisluyi/rsbuild-config";
2392
2444
  // src/fallback-config.json
@@ -2498,36 +2550,17 @@ function generateTsconfigDaas(cwd, target) {
2498
2550
  extends: "./tsconfig.json",
2499
2551
  compilerOptions: {
2500
2552
  paths: {
2501
- "@region-config": [`./src/config/regions/${target.region}`],
2553
+ "@region-config": [`./src/config/regions/${target.region}/config`],
2502
2554
  "@platform-config": [`./src/config/platforms/${target.platform}`],
2503
- "@product-config": [`./src/config/products/${target.product}`]
2555
+ "@product-config": [`./src/config/products/${target.product}`],
2556
+ "@regional": [`./src/config/regions/${target.region}/index`]
2504
2557
  }
2505
2558
  }
2506
2559
  };
2507
- writeFileSync(resolve3(cwd, "tsconfig.daas.json"), JSON.stringify(content, null, 2) + `
2560
+ writeFileSync(resolve3(cwd, "tsconfig.daas.json"), `${JSON.stringify(content, null, 2)}
2508
2561
  `);
2509
2562
  }
2510
2563
 
2511
- // src/output.ts
2512
- function formatSuccess(command, data) {
2513
- return { ok: true, command, cliVersion: getCliVersion(), ...data };
2514
- }
2515
- function formatError(command, exitCode, error, suggestion) {
2516
- return { ok: false, command, exitCode, error, suggestion, cliVersion: getCliVersion() };
2517
- }
2518
- function writeJsonSuccess(command, data) {
2519
- process.stdout.write(JSON.stringify(formatSuccess(command, data)) + `
2520
- `);
2521
- }
2522
- function writeJsonError(command, exitCode, error, suggestion) {
2523
- process.stdout.write(JSON.stringify(formatError(command, exitCode, error, suggestion)) + `
2524
- `);
2525
- process.exit(exitCode);
2526
- }
2527
- function getCliVersion() {
2528
- return process.env.DAAS_CLI_VERSION ?? "0.0.0";
2529
- }
2530
-
2531
2564
  // src/types.ts
2532
2565
  var EXIT_CODES = {
2533
2566
  SUCCESS: 0,
@@ -2538,83 +2571,26 @@ var EXIT_CODES = {
2538
2571
  CONFIG_VERSION_MISMATCH: 5
2539
2572
  };
2540
2573
 
2541
- // src/commands/dev.ts
2542
- var devCommand = defineCommand({
2543
- meta: { name: "dev", description: "Start MFE dev server" },
2544
- args: {
2545
- target: { type: "positional", description: "Build target (e.g. sg-foo-mb-dev)", required: false },
2546
- port: { type: "string", description: "Override dev server port" },
2547
- json: { type: "boolean", default: false, description: "Machine-readable JSON output" }
2548
- },
2549
- async run({ args }) {
2550
- try {
2551
- const daasConfig = readDaasConfig();
2552
- const manifest = readManifest();
2553
- const remoteMeta = await fetchRemoteConfig(daasConfig.configUrl, false);
2554
- checkCliVersion(remoteMeta);
2555
- const versionOk = checkConfigVersion(remoteMeta, false);
2556
- if (!versionOk) {
2557
- consola.warn("Config version mismatch \u2014 update daas-cli for full compatibility");
2558
- }
2559
- const port = args.port ? Number(args.port) : daasConfig.port;
2560
- const target = args.target ? parseTarget(args.target) : undefined;
2561
- if (target) {
2562
- generateTsconfigDaas(process.cwd(), target);
2563
- consola.info(`Target: ${args.target} (region=${target.region}, product=${target.product}, platform=${target.platform}, env=${target.environment})`);
2564
- }
2565
- const config = createConfig(manifest, remoteMeta, { mode: "development", port, target });
2566
- consola.start(`Starting ${manifest.name} dev server...`);
2567
- const rsbuild = await createRsbuild({ rsbuildConfig: config });
2568
- const server = await rsbuild.createDevServer();
2569
- await server.listen();
2570
- consola.success(`Ready on http://localhost:${port}`);
2571
- } catch (e2) {
2572
- handleError("dev", e2, args.json);
2573
- }
2574
- }
2575
- });
2576
- function handleError(command, e2, json) {
2577
- if (e2 instanceof CliVersionError) {
2578
- if (json)
2579
- writeJsonError(command, EXIT_CODES.CLI_TOO_OLD, e2.message, "Update daas-cli to the required version.");
2580
- consola.fatal(e2.message);
2581
- process.exit(EXIT_CODES.CLI_TOO_OLD);
2582
- }
2583
- if (e2 instanceof FetchError) {
2584
- if (json)
2585
- writeJsonError(command, EXIT_CODES.REMOTE_FETCH_FAILED, e2.message, "Check network or VPN.");
2586
- consola.warn(`Remote config unavailable \u2014 using fallback. ${e2.message}`);
2587
- process.exit(EXIT_CODES.REMOTE_FETCH_FAILED);
2588
- }
2589
- if (e2 instanceof TargetParseError) {
2590
- if (json)
2591
- writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Check target format: {region}-{product}-{platform}-{environment}");
2592
- consola.fatal(e2.message);
2593
- process.exit(EXIT_CODES.CONFIG_ERROR);
2594
- }
2595
- if (e2 instanceof ConfigError || e2 instanceof ManifestError) {
2596
- if (json)
2597
- writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Run daas init first.");
2598
- consola.fatal(e2.message);
2599
- process.exit(EXIT_CODES.CONFIG_ERROR);
2600
- }
2601
- consola.fatal(e2);
2602
- process.exit(EXIT_CODES.GENERAL_ERROR);
2603
- }
2604
-
2605
2574
  // src/commands/build.ts
2606
- import { createRsbuild as createRsbuild2 } from "@rsbuild/core";
2607
- import { createConfig as createConfig2 } from "@chrisluyi/rsbuild-config";
2608
2575
  var buildCommand = defineCommand({
2609
2576
  meta: { name: "build", description: "Build MFE for production" },
2610
2577
  args: {
2611
- target: { type: "positional", description: "Build target (e.g. sg-foo-mb-prod)", required: false },
2612
- json: { type: "boolean", default: false, description: "Machine-readable JSON output" }
2578
+ target: {
2579
+ type: "positional",
2580
+ description: "Build target (e.g. sg-foo-mb-prod)",
2581
+ required: false
2582
+ },
2583
+ json: {
2584
+ type: "boolean",
2585
+ default: false,
2586
+ description: "Machine-readable JSON output"
2587
+ }
2613
2588
  },
2614
2589
  async run({ args }) {
2615
2590
  const json = args.json;
2616
2591
  try {
2617
2592
  const daasConfig = readDaasConfig();
2593
+ setLogger(createLogger([consolaTransport(), apiTransport(daasConfig.logUrl)]));
2618
2594
  const manifest = readManifest();
2619
2595
  if (!json)
2620
2596
  consola.start(`Building ${manifest.name}...`);
@@ -2624,8 +2600,11 @@ var buildCommand = defineCommand({
2624
2600
  const target = args.target ? parseTarget(args.target) : undefined;
2625
2601
  if (target)
2626
2602
  generateTsconfigDaas(process.cwd(), target);
2627
- const config = createConfig2(manifest, remoteMeta, { mode: "production", target });
2628
- const rsbuild = await createRsbuild2({ rsbuildConfig: config });
2603
+ const config = createConfig(manifest, remoteMeta, {
2604
+ mode: "production",
2605
+ target
2606
+ });
2607
+ const rsbuild = await createRsbuild({ rsbuildConfig: config });
2629
2608
  await rsbuild.build();
2630
2609
  if (json)
2631
2610
  writeJsonSuccess("build", { appName: manifest.name, output: "./dist" });
@@ -2667,41 +2646,92 @@ var buildCommand = defineCommand({
2667
2646
  }
2668
2647
  });
2669
2648
 
2670
- // src/commands/test.ts
2671
- import { startVitest } from "vitest/node";
2672
- import { createVitestConfig } from "@chrisluyi/rsbuild-config/vitest";
2673
- var testCommand = defineCommand({
2674
- meta: { name: "test", description: "Run MFE tests" },
2649
+ // src/commands/dev.ts
2650
+ import { createConfig as createConfig2 } from "@chrisluyi/rsbuild-config";
2651
+ import { createLogger as createLogger2, setLogger as setLogger2, apiTransport as apiTransport2 } from "@chrisluyi/logger";
2652
+ import { createRsbuild as createRsbuild2 } from "@rsbuild/core";
2653
+ var devCommand = defineCommand({
2654
+ meta: { name: "dev", description: "Start MFE dev server" },
2675
2655
  args: {
2676
- json: { type: "boolean", default: false, description: "Machine-readable JSON output" }
2656
+ target: {
2657
+ type: "positional",
2658
+ description: "Build target (e.g. sg-foo-mb-dev)",
2659
+ required: false
2660
+ },
2661
+ port: { type: "string", description: "Override dev server port" },
2662
+ json: {
2663
+ type: "boolean",
2664
+ default: false,
2665
+ description: "Machine-readable JSON output"
2666
+ }
2677
2667
  },
2678
2668
  async run({ args }) {
2679
- const json = args.json;
2680
2669
  try {
2681
- const manifest = readManifest();
2682
2670
  const daasConfig = readDaasConfig();
2683
- const config = createVitestConfig(manifest, { coverage: daasConfig.coverage, setupFiles: daasConfig.setupFiles });
2684
- const vitest = await startVitest("test", [], config);
2685
- const failed = vitest?.state.getFiles().some((f3) => f3.result?.state === "fail") ?? false;
2686
- if (json) {
2687
- if (failed)
2688
- writeJsonError("test", EXIT_CODES.GENERAL_ERROR, "Tests failed", "Check test output above");
2689
- writeJsonSuccess("test", { appName: manifest.name, passed: !failed });
2671
+ setLogger2(createLogger2([consolaTransport(), apiTransport2(daasConfig.logUrl)]));
2672
+ const manifest = readManifest();
2673
+ const remoteMeta = await fetchRemoteConfig(daasConfig.configUrl, false);
2674
+ checkCliVersion(remoteMeta);
2675
+ const versionOk = checkConfigVersion(remoteMeta, false);
2676
+ if (!versionOk) {
2677
+ consola.warn("Config version mismatch \u2014 update daas-cli for full compatibility");
2690
2678
  }
2691
- if (failed)
2692
- process.exit(EXIT_CODES.GENERAL_ERROR);
2679
+ const port = args.port ? Number(args.port) : daasConfig.port;
2680
+ const target = args.target ? parseTarget(args.target) : undefined;
2681
+ if (target) {
2682
+ generateTsconfigDaas(process.cwd(), target);
2683
+ consola.info(`Target: ${args.target} (region=${target.region}, product=${target.product}, platform=${target.platform}, env=${target.environment})`);
2684
+ }
2685
+ const config = createConfig2(manifest, remoteMeta, {
2686
+ mode: "development",
2687
+ port,
2688
+ target
2689
+ });
2690
+ consola.start(`Starting ${manifest.name} dev server...`);
2691
+ const rsbuild = await createRsbuild2({ rsbuildConfig: config });
2692
+ const server = await rsbuild.createDevServer();
2693
+ await server.listen();
2694
+ consola.success(`Ready on http://localhost:${port}`);
2693
2695
  } catch (e2) {
2694
- if (json)
2695
- writeJsonError("test", EXIT_CODES.GENERAL_ERROR, e2.message, "Check test configuration");
2696
- consola.fatal(e2);
2697
- process.exit(EXIT_CODES.GENERAL_ERROR);
2696
+ handleError("dev", e2, args.json);
2698
2697
  }
2699
2698
  }
2700
2699
  });
2700
+ function handleError(command, e2, json) {
2701
+ if (e2 instanceof CliVersionError) {
2702
+ if (json)
2703
+ writeJsonError(command, EXIT_CODES.CLI_TOO_OLD, e2.message, "Update daas-cli to the required version.");
2704
+ consola.fatal(e2.message);
2705
+ process.exit(EXIT_CODES.CLI_TOO_OLD);
2706
+ }
2707
+ if (e2 instanceof FetchError) {
2708
+ if (json)
2709
+ writeJsonError(command, EXIT_CODES.REMOTE_FETCH_FAILED, e2.message, "Check network or VPN.");
2710
+ consola.warn(`Remote config unavailable \u2014 using fallback. ${e2.message}`);
2711
+ process.exit(EXIT_CODES.REMOTE_FETCH_FAILED);
2712
+ }
2713
+ if (e2 instanceof TargetParseError) {
2714
+ if (json)
2715
+ writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Check target format: {region}-{product}-{platform}-{environment}");
2716
+ consola.fatal(e2.message);
2717
+ process.exit(EXIT_CODES.CONFIG_ERROR);
2718
+ }
2719
+ if (e2 instanceof ConfigError || e2 instanceof ManifestError) {
2720
+ if (json)
2721
+ writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Run daas init first.");
2722
+ consola.fatal(e2.message);
2723
+ process.exit(EXIT_CODES.CONFIG_ERROR);
2724
+ }
2725
+ consola.fatal(e2);
2726
+ process.exit(EXIT_CODES.GENERAL_ERROR);
2727
+ }
2728
+
2729
+ // src/commands/info.ts
2730
+ import { createLogger as createLogger3, setLogger as setLogger3, apiTransport as apiTransport3 } from "@chrisluyi/logger";
2701
2731
 
2702
2732
  // src/init/monorepo.ts
2703
2733
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
2704
- import { resolve as resolve4, dirname } from "path";
2734
+ import { dirname, resolve as resolve4 } from "path";
2705
2735
  function detectMonorepo(startDir) {
2706
2736
  let dir = startDir;
2707
2737
  for (let i2 = 0;i2 < 10; i2++) {
@@ -2727,7 +2757,11 @@ function detectMonorepo(startDir) {
2727
2757
  var infoCommand = defineCommand({
2728
2758
  meta: { name: "info", description: "Show resolved MFE project state" },
2729
2759
  args: {
2730
- json: { type: "boolean", default: false, description: "Machine-readable JSON output" }
2760
+ json: {
2761
+ type: "boolean",
2762
+ default: false,
2763
+ description: "Machine-readable JSON output"
2764
+ }
2731
2765
  },
2732
2766
  async run({ args }) {
2733
2767
  const json = args.json;
@@ -2735,6 +2769,7 @@ var infoCommand = defineCommand({
2735
2769
  let manifest;
2736
2770
  try {
2737
2771
  daasConfig = readDaasConfig();
2772
+ setLogger3(createLogger3([consolaTransport(), apiTransport3(daasConfig.logUrl)]));
2738
2773
  manifest = readManifest();
2739
2774
  } catch (e2) {
2740
2775
  if (json)
@@ -2766,6 +2801,9 @@ var infoCommand = defineCommand({
2766
2801
  });
2767
2802
 
2768
2803
  // src/commands/init.ts
2804
+ import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
2805
+ import { createRequire } from "module";
2806
+ import { resolve as resolve6 } from "path";
2769
2807
  import { scaffold } from "@chrisluyi/template";
2770
2808
 
2771
2809
  // ../../node_modules/.bun/@clack+core@0.3.5/node_modules/@clack/core/dist/index.mjs
@@ -3258,12 +3296,8 @@ var de = () => {
3258
3296
  return process.on("uncaughtExceptionMonitor", () => $2(2)), process.on("unhandledRejection", () => $2(2)), process.on("SIGINT", () => $2(1)), process.on("SIGTERM", () => $2(1)), process.on("exit", $2), { start: l3, stop: u3, message: m3 };
3259
3297
  };
3260
3298
 
3261
- // src/commands/init.ts
3262
- import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
3263
- import { resolve as resolve6 } from "path";
3264
-
3265
3299
  // src/init/copy-template.ts
3266
- import { existsSync as existsSync4, copyFileSync, mkdirSync, readdirSync } from "fs";
3300
+ import { copyFileSync, existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
3267
3301
  import { dirname as dirname2, join } from "path";
3268
3302
  import { fileURLToPath } from "url";
3269
3303
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
@@ -3280,7 +3314,9 @@ async function copyTemplate(destDir) {
3280
3314
  mkdirSync(join(destDir, "src"), { recursive: true });
3281
3315
  }
3282
3316
  if (existsSync4(dest)) {
3283
- const overwrite = await se({ message: `${destFile} already exists. Overwrite?` });
3317
+ const overwrite = await se({
3318
+ message: `${destFile} already exists. Overwrite?`
3319
+ });
3284
3320
  if (!overwrite) {
3285
3321
  result.skipped.push(destFile);
3286
3322
  continue;
@@ -3293,7 +3329,7 @@ async function copyTemplate(destDir) {
3293
3329
  }
3294
3330
 
3295
3331
  // src/init/package-json.ts
3296
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5 } from "fs";
3332
+ import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
3297
3333
  import { resolve as resolve5 } from "path";
3298
3334
  function updatePackageJson(cwd, opts) {
3299
3335
  const pkgPath = resolve5(cwd, "package.json");
@@ -3304,6 +3340,17 @@ function updatePackageJson(cwd, opts) {
3304
3340
  build: "daas build",
3305
3341
  test: "daas test"
3306
3342
  };
3343
+ pkg.dependencies = {
3344
+ ...pkg.dependencies ?? {},
3345
+ "@radix-ui/react-tabs": "^1.1.0",
3346
+ ...opts.isFullTemplate ? {
3347
+ "@chrisluyi/template": `^${opts.templateVersion ?? opts.cliVersion ?? "1.0.0"}`,
3348
+ "@tanstack/react-query": "^5.0.0",
3349
+ zustand: "^5.0.0",
3350
+ immer: "^10.0.0",
3351
+ zod: "^3.23.0"
3352
+ } : {}
3353
+ };
3307
3354
  if (!opts.isMonorepo) {
3308
3355
  pkg.devDependencies = {
3309
3356
  ...pkg.devDependencies ?? {},
@@ -3311,7 +3358,7 @@ function updatePackageJson(cwd, opts) {
3311
3358
  };
3312
3359
  }
3313
3360
  pkg.daas = { configUrl: opts.configUrl, port: opts.port };
3314
- writeFileSync2(pkgPath, JSON.stringify(pkg, null, 2) + `
3361
+ writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
3315
3362
  `);
3316
3363
  }
3317
3364
 
@@ -3320,7 +3367,10 @@ var KNOWN_TEMPLATES = ["default"];
3320
3367
  var initCommand = defineCommand({
3321
3368
  meta: { name: "init", description: "Scaffold a new MFE app" },
3322
3369
  args: {
3323
- template: { type: "string", description: "Template name. Use 'default' for the full services/containers/components structure." }
3370
+ template: {
3371
+ type: "string",
3372
+ description: "Template name. Use 'default' for the full services/containers/components structure."
3373
+ }
3324
3374
  },
3325
3375
  async run({ args }) {
3326
3376
  if (!process.stdin.isTTY) {
@@ -3364,7 +3414,9 @@ var initCommand = defineCommand({
3364
3414
  appName,
3365
3415
  onConflict: async (relPath) => {
3366
3416
  s2.stop("");
3367
- const overwrite = await se({ message: `${relPath} already exists. Overwrite?` });
3417
+ const overwrite = await se({
3418
+ message: `${relPath} already exists. Overwrite?`
3419
+ });
3368
3420
  s2.start(`Scaffolding ${appName}...`);
3369
3421
  return overwrite;
3370
3422
  }
@@ -3380,11 +3432,17 @@ var initCommand = defineCommand({
3380
3432
  s2.message(`\u2713 Created ${f4}`);
3381
3433
  for (const f4 of skipped)
3382
3434
  s2.message(`\u2014 Skipped ${f4} (kept existing)`);
3383
- updatePackageJson(cwd, { configUrl, port, isMonorepo });
3435
+ updatePackageJson(cwd, {
3436
+ configUrl,
3437
+ port,
3438
+ isMonorepo,
3439
+ isFullTemplate: useFullTemplate,
3440
+ templateVersion: getTemplateVersion()
3441
+ });
3384
3442
  s2.message("\u2713 Updated package.json");
3385
3443
  if (hasExtraExposes) {
3386
3444
  const manifest = { name: appName, exposes: { "./App": "./src/App" } };
3387
- writeFileSync3(resolve6(cwd, "mf.manifest.json"), JSON.stringify(manifest, null, 2) + `
3445
+ writeFileSync3(resolve6(cwd, "mf.manifest.json"), `${JSON.stringify(manifest, null, 2)}
3388
3446
  `);
3389
3447
  s2.message("\u2713 Created mf.manifest.json (add extra exposes as needed)");
3390
3448
  }
@@ -3392,6 +3450,15 @@ var initCommand = defineCommand({
3392
3450
  $e(isMonorepo ? "Run: daas dev" : "Run: bun install && daas dev");
3393
3451
  }
3394
3452
  });
3453
+ function getTemplateVersion() {
3454
+ try {
3455
+ const req = createRequire(import.meta.url);
3456
+ const pkg = req("@chrisluyi/template/package.json");
3457
+ return pkg.version ?? "1.0.0";
3458
+ } catch {
3459
+ return "1.0.0";
3460
+ }
3461
+ }
3395
3462
  function getPackageName(cwd) {
3396
3463
  const pkgPath = resolve6(cwd, "package.json");
3397
3464
  if (!existsSync6(pkgPath))
@@ -3404,7 +3471,49 @@ function getPackageName(cwd) {
3404
3471
  }
3405
3472
  }
3406
3473
 
3474
+ // src/commands/test.ts
3475
+ import { createVitestConfig } from "@chrisluyi/rsbuild-config/vitest";
3476
+ import { createLogger as createLogger4, setLogger as setLogger4, apiTransport as apiTransport4 } from "@chrisluyi/logger";
3477
+ import { startVitest } from "vitest/node";
3478
+ var testCommand = defineCommand({
3479
+ meta: { name: "test", description: "Run MFE tests" },
3480
+ args: {
3481
+ json: {
3482
+ type: "boolean",
3483
+ default: false,
3484
+ description: "Machine-readable JSON output"
3485
+ }
3486
+ },
3487
+ async run({ args }) {
3488
+ const json = args.json;
3489
+ try {
3490
+ const manifest = readManifest();
3491
+ const daasConfig = readDaasConfig();
3492
+ setLogger4(createLogger4([consolaTransport(), apiTransport4(daasConfig.logUrl)]));
3493
+ const config = createVitestConfig(manifest, {
3494
+ coverage: daasConfig.coverage,
3495
+ setupFiles: daasConfig.setupFiles
3496
+ });
3497
+ const vitest = await startVitest("test", [], config);
3498
+ const failed = vitest?.state.getFiles().some((f4) => f4.result?.state === "fail") ?? false;
3499
+ if (json) {
3500
+ if (failed)
3501
+ writeJsonError("test", EXIT_CODES.GENERAL_ERROR, "Tests failed", "Check test output above");
3502
+ writeJsonSuccess("test", { appName: manifest.name, passed: !failed });
3503
+ }
3504
+ if (failed)
3505
+ process.exit(EXIT_CODES.GENERAL_ERROR);
3506
+ } catch (e3) {
3507
+ if (json)
3508
+ writeJsonError("test", EXIT_CODES.GENERAL_ERROR, e3.message, "Check test configuration");
3509
+ consola.fatal(e3);
3510
+ process.exit(EXIT_CODES.GENERAL_ERROR);
3511
+ }
3512
+ }
3513
+ });
3514
+
3407
3515
  // src/index.ts
3516
+ setLogger5(createLogger5([consolaTransport()]));
3408
3517
  var main = defineCommand({
3409
3518
  meta: {
3410
3519
  name: "daas",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrisluyi/daas-cli",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "daas": "./dist/index.js"
@@ -16,11 +16,12 @@
16
16
  "skill.md"
17
17
  ],
18
18
  "scripts": {
19
- "build": "bun build src/index.ts --outfile dist/index.js.tmp --target bun --external @rspack/core --external @rspack/lite-tapable --external @rsbuild/core --external @rsbuild/plugin-react --external @module-federation/rsbuild-plugin --external vitest --external @vitest/browser --external @vitest/ui --external tapable --external react-router-dom --external lightningcss --external @chrisluyi/template --external @chrisluyi/rsbuild-config && printf '%s\\n' '#!/usr/bin/env bun' | cat - dist/index.js.tmp > dist/index.js && rm dist/index.js.tmp && chmod +x dist/index.js && bun build src/test.ts --outfile dist/test.js --target bun --external vitest --external @testing-library/react --external @testing-library/user-event --external @chrisluyi/rsbuild-config",
19
+ "build": "bun build src/index.ts --outfile dist/index.js.tmp --target bun --external @rspack/core --external @rspack/lite-tapable --external @rsbuild/core --external @rsbuild/plugin-react --external @module-federation/rsbuild-plugin --external vitest --external @vitest/browser --external @vitest/ui --external tapable --external react-router-dom --external lightningcss --external @chrisluyi/template --external @chrisluyi/logger --external @chrisluyi/rsbuild-config && printf '%s\\n' '#!/usr/bin/env bun' | cat - dist/index.js.tmp > dist/index.js && rm dist/index.js.tmp && chmod +x dist/index.js && bun build src/test.ts --outfile dist/test.js --target bun --external vitest --external @testing-library/react --external @testing-library/user-event --external @chrisluyi/rsbuild-config",
20
20
  "test": "bun test --ignore 'templates/**'"
21
21
  },
22
22
  "dependencies": {
23
23
  "@clack/prompts": "^0.7.0",
24
+ "@chrisluyi/logger": "workspace:*",
24
25
  "@chrisluyi/rsbuild-config": "workspace:*",
25
26
  "@chrisluyi/template": "workspace:*",
26
27
  "@rsbuild/core": "^1.0.0",
@@ -31,6 +32,11 @@
31
32
  "devDependencies": {
32
33
  "typescript": "^5.5.0"
33
34
  },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/Chris-LuYi/daas-cli",
38
+ "directory": "packages/cli"
39
+ },
34
40
  "publishConfig": {
35
41
  "access": "public"
36
42
  }
package/skill.md CHANGED
@@ -96,13 +96,60 @@ src/
96
96
  components/App.tsx ← presentational component
97
97
  containers/AppContainer.tsx ← data/business logic wrapper
98
98
  services/index.ts ← data fetching / API calls
99
+ flows/ ← multi-step flows (optional — add when needed)
100
+ <name>/
101
+ types.ts ← TData interface
102
+ index.ts ← createFlow<TData>(...)
103
+ steps/ ← step components (useFlowData / useFlowActions)
99
104
  config/
100
105
  regions/default.ts ← region config layer
101
106
  platforms/default.ts ← platform config layer
102
107
  products/default.ts ← product config layer
103
108
  ```
104
109
 
110
+ ## Template Runtime (`@chrisluyi/template/runtime`)
111
+
112
+ Key utilities available in MFE components:
113
+
114
+ | Export | Purpose |
115
+ |---|---|
116
+ | `createApiClient` | Region-aware HTTP client (auto-injects X-Region-Id, X-Locale headers) |
117
+ | `createService` | React Query data fetching with Zod validation |
118
+ | `createStore` | Zustand UI state (per-module singleton) |
119
+ | `createForm` | Zod-validated form with regional widget injection |
120
+ | `createFlow` | Router-agnostic multi-step flow engine |
121
+ | `FlowEngine` | Component wrapper — renders current step automatically |
122
+ | `useFlow` | Hook — use when you need a custom layout (progress bar etc.) |
123
+ | `useFlowData` | Step hook — read/write the shared typed data bag |
124
+ | `useFlowActions` | Step hook — `next()`, `back()`, `isFirst`, `isLast` |
125
+ | `useRegional` | Access the full `RegionalRegistry` from any component |
126
+
127
+ ### Flow SDK quick reference
128
+
129
+ ```ts
130
+ // Define
131
+ const myFlow = createFlow<MyData>({
132
+ id: "MyFlow",
133
+ steps: [{ id: "step1", component: Step1 }, { id: "step2", component: Step2 }],
134
+ initialData: {},
135
+ })
136
+
137
+ // Mount
138
+ const registry = useRegional()
139
+ return <FlowEngine flow={myFlow} registry={registry} />
140
+
141
+ // Inside a step — no props needed
142
+ const { data, setData } = useFlowData<MyData>()
143
+ const { next, back, isLast } = useFlowActions()
144
+ ```
145
+
146
+ Regional step injection via `RegionalRegistry.flows?`:
147
+ ```ts
148
+ createRegistry(defaultRegistry, {
149
+ flows: { MyFlow: { extraSteps: [{ after: "step1", id: "extra", component: ExtraStep }] } }
150
+ })
151
+ ```
152
+
105
153
  ## Roadmap (do not suggest these — not yet implemented)
106
154
 
107
- - v1.5: `daas dev sg-foo-mb-dev` target strings for multi-region builds
108
155
  - v2+: `daas lint` — validates project structure against template conventions