@chrisluyi/daas-cli 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.js +426 -65
- package/dist/test.js +1 -1
- package/package.json +9 -11
- package/skill.md +48 -1
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ MFE apps have **no build config files** — no `rsbuild.config.ts`, no `vitest.c
|
|
|
11
11
|
| Package | Version | Description |
|
|
12
12
|
|---|---|---|
|
|
13
13
|
| [`@chrisluyi/daas-cli`](https://www.npmjs.com/package/@chrisluyi/daas-cli) | 1.1.0 | CLI binary — install this as your only devDependency |
|
|
14
|
-
| [`@chrisluyi/rsbuild-config`](https://www.npmjs.com/package/@chrisluyi/rsbuild-config) | 1.1.0 | rsbuild config factory + vitest config — arrives transitively |
|
|
15
|
-
| [`@chrisluyi/template`](https://www.npmjs.com/package/@chrisluyi/template) | 1.0.0 | MFE scaffold templates (services / containers / components structure) |
|
|
14
|
+
| [`@chrisluyi/daas-rsbuild-config`](https://www.npmjs.com/package/@chrisluyi/daas-rsbuild-config) | 1.1.0 | rsbuild config factory + vitest config — arrives transitively |
|
|
15
|
+
| [`@chrisluyi/daas-template`](https://www.npmjs.com/package/@chrisluyi/daas-template) | 1.0.0 | MFE scaffold templates (services / containers / components structure) |
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
package/dist/index.js
CHANGED
|
@@ -912,6 +912,9 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
912
912
|
module.exports.createColors = createColors2;
|
|
913
913
|
});
|
|
914
914
|
|
|
915
|
+
// src/index.ts
|
|
916
|
+
import { createLogger as createLogger5, setLogger as setLogger5 } from "@chrisluyi/daas-logger";
|
|
917
|
+
|
|
915
918
|
// ../../node_modules/.bun/consola@3.4.2/node_modules/consola/dist/core.mjs
|
|
916
919
|
var LogLevels = {
|
|
917
920
|
silent: Number.NEGATIVE_INFINITY,
|
|
@@ -2312,9 +2315,18 @@ async function runMain(cmd, opts = {}) {
|
|
|
2312
2315
|
}
|
|
2313
2316
|
|
|
2314
2317
|
// src/commands/build.ts
|
|
2315
|
-
import {
|
|
2318
|
+
import { apiTransport, createLogger, setLogger } from "@chrisluyi/daas-logger";
|
|
2319
|
+
import { createConfig } from "@chrisluyi/daas-rsbuild-config";
|
|
2316
2320
|
import { createRsbuild } from "@rsbuild/core";
|
|
2317
2321
|
|
|
2322
|
+
// src/bridge.ts
|
|
2323
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
2324
|
+
import { dirname, relative, resolve as resolve2, sep as sep2 } from "path";
|
|
2325
|
+
import {
|
|
2326
|
+
BRIDGE_EXPOSE_KEY,
|
|
2327
|
+
bridgeWrapperModule
|
|
2328
|
+
} from "@chrisluyi/daas-rsbuild-config";
|
|
2329
|
+
|
|
2318
2330
|
// src/daas-config.ts
|
|
2319
2331
|
import { existsSync, readFileSync } from "fs";
|
|
2320
2332
|
import { resolve } from "path";
|
|
@@ -2332,20 +2344,64 @@ function readDaasConfig(cwd = process.cwd()) {
|
|
|
2332
2344
|
}
|
|
2333
2345
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
2334
2346
|
const daas = pkg.daas;
|
|
2335
|
-
if (!daas?.configUrl) {
|
|
2336
|
-
throw new ConfigError("No daas config found in package.json. Run daas init first.");
|
|
2337
|
-
}
|
|
2338
2347
|
return {
|
|
2339
|
-
configUrl: daas
|
|
2340
|
-
port: daas
|
|
2341
|
-
coverage: daas
|
|
2342
|
-
setupFiles: daas
|
|
2348
|
+
configUrl: daas?.configUrl,
|
|
2349
|
+
port: daas?.port ?? 3000,
|
|
2350
|
+
coverage: daas?.coverage,
|
|
2351
|
+
setupFiles: daas?.setupFiles,
|
|
2352
|
+
logUrl: daas?.logUrl,
|
|
2353
|
+
bridge: daas?.bridge ?? false
|
|
2354
|
+
};
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
// src/bridge.ts
|
|
2358
|
+
function prepareBridgeBuild(cwd, manifest) {
|
|
2359
|
+
const exposeValues = Object.values(manifest.exposes);
|
|
2360
|
+
if (exposeValues.length !== 1) {
|
|
2361
|
+
throw new ConfigError(`Bridge MFEs must expose exactly one root component (found ${exposeValues.length}). ` + "A bridge remote is a single full sub-app; expose only its root in mf.manifest.json.");
|
|
2362
|
+
}
|
|
2363
|
+
const wrapperAbsPath = resolve2(cwd, ".daas", "export-app.tsx");
|
|
2364
|
+
const rootAbs = resolve2(cwd, exposeValues[0]);
|
|
2365
|
+
let rootImport = relative(dirname(wrapperAbsPath), rootAbs).split(sep2).join("/");
|
|
2366
|
+
if (!rootImport.startsWith("."))
|
|
2367
|
+
rootImport = `./${rootImport}`;
|
|
2368
|
+
return {
|
|
2369
|
+
manifest: {
|
|
2370
|
+
name: manifest.name,
|
|
2371
|
+
exposes: { [BRIDGE_EXPOSE_KEY]: "./.daas/export-app" }
|
|
2372
|
+
},
|
|
2373
|
+
wrapperAbsPath,
|
|
2374
|
+
wrapperContent: bridgeWrapperModule(rootImport)
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
function writeBridgeWrapper(prep) {
|
|
2378
|
+
mkdirSync(dirname(prep.wrapperAbsPath), { recursive: true });
|
|
2379
|
+
writeFileSync(prep.wrapperAbsPath, prep.wrapperContent);
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
// src/logger/consolaTransport.ts
|
|
2383
|
+
function consolaTransport() {
|
|
2384
|
+
return (entry) => {
|
|
2385
|
+
switch (entry.level) {
|
|
2386
|
+
case "debug":
|
|
2387
|
+
consola.debug(entry.message, entry.context ?? "");
|
|
2388
|
+
break;
|
|
2389
|
+
case "info":
|
|
2390
|
+
consola.info(entry.message);
|
|
2391
|
+
break;
|
|
2392
|
+
case "warn":
|
|
2393
|
+
consola.warn(entry.message);
|
|
2394
|
+
break;
|
|
2395
|
+
case "error":
|
|
2396
|
+
consola.fatal(entry.message);
|
|
2397
|
+
break;
|
|
2398
|
+
}
|
|
2343
2399
|
};
|
|
2344
2400
|
}
|
|
2345
2401
|
|
|
2346
2402
|
// src/manifest.ts
|
|
2347
2403
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
2348
|
-
import { resolve as
|
|
2404
|
+
import { resolve as resolve3 } from "path";
|
|
2349
2405
|
|
|
2350
2406
|
class ManifestError extends Error {
|
|
2351
2407
|
constructor(message) {
|
|
@@ -2354,7 +2410,7 @@ class ManifestError extends Error {
|
|
|
2354
2410
|
}
|
|
2355
2411
|
}
|
|
2356
2412
|
function readManifest(cwd = process.cwd()) {
|
|
2357
|
-
const manifestPath =
|
|
2413
|
+
const manifestPath = resolve3(cwd, "mf.manifest.json");
|
|
2358
2414
|
if (existsSync2(manifestPath)) {
|
|
2359
2415
|
try {
|
|
2360
2416
|
const raw = JSON.parse(readFileSync2(manifestPath, "utf8"));
|
|
@@ -2368,7 +2424,7 @@ function readManifest(cwd = process.cwd()) {
|
|
|
2368
2424
|
return deriveFromPackageJson(cwd);
|
|
2369
2425
|
}
|
|
2370
2426
|
function deriveFromPackageJson(cwd) {
|
|
2371
|
-
const pkgPath =
|
|
2427
|
+
const pkgPath = resolve3(cwd, "package.json");
|
|
2372
2428
|
if (!existsSync2(pkgPath)) {
|
|
2373
2429
|
throw new ManifestError("No package.json found. Are you in an MFE directory?");
|
|
2374
2430
|
}
|
|
@@ -2377,14 +2433,16 @@ function deriveFromPackageJson(cwd) {
|
|
|
2377
2433
|
return { name, exposes: { "./App": "./src/App" } };
|
|
2378
2434
|
}
|
|
2379
2435
|
function normalizeManifest(raw, cwd) {
|
|
2380
|
-
const
|
|
2436
|
+
const hasName = typeof raw.name === "string";
|
|
2437
|
+
const hasExposes = raw.exposes != null;
|
|
2438
|
+
const base = hasName && hasExposes ? null : deriveFromPackageJson(cwd);
|
|
2381
2439
|
return {
|
|
2382
|
-
name:
|
|
2383
|
-
exposes:
|
|
2440
|
+
name: hasName ? raw.name.replace(/-/g, "_") : base.name,
|
|
2441
|
+
exposes: hasExposes ? raw.exposes : base.exposes
|
|
2384
2442
|
};
|
|
2385
2443
|
}
|
|
2386
2444
|
function stripScope(name) {
|
|
2387
|
-
return name.replace(/^@[^/]+\//, "");
|
|
2445
|
+
return name.replace(/^@[^/]+\//, "").replace(/-/g, "_");
|
|
2388
2446
|
}
|
|
2389
2447
|
|
|
2390
2448
|
// src/output.ts
|
|
@@ -2415,15 +2473,15 @@ function getCliVersion() {
|
|
|
2415
2473
|
}
|
|
2416
2474
|
|
|
2417
2475
|
// src/remote-config.ts
|
|
2418
|
-
import { SUPPORTED_CONFIG_VERSION } from "@chrisluyi/rsbuild-config";
|
|
2476
|
+
import { SUPPORTED_CONFIG_VERSION } from "@chrisluyi/daas-rsbuild-config";
|
|
2419
2477
|
// src/fallback-config.json
|
|
2420
2478
|
var fallback_config_default = {
|
|
2421
2479
|
version: "1.0.0",
|
|
2422
2480
|
minCliVersion: "1.0.0",
|
|
2423
2481
|
releaseNotesUrl: "https://github.com/your-org/daas-cli/releases",
|
|
2424
2482
|
shared: {
|
|
2425
|
-
react: "
|
|
2426
|
-
"react-dom": "
|
|
2483
|
+
react: "^19.0.0",
|
|
2484
|
+
"react-dom": "^19.0.0"
|
|
2427
2485
|
},
|
|
2428
2486
|
rsbuildConfigVersion: 1
|
|
2429
2487
|
};
|
|
@@ -2500,8 +2558,8 @@ function meetsMinVersion(current, min) {
|
|
|
2500
2558
|
}
|
|
2501
2559
|
|
|
2502
2560
|
// src/target.ts
|
|
2503
|
-
import { writeFileSync } from "fs";
|
|
2504
|
-
import { resolve as
|
|
2561
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
2562
|
+
import { resolve as resolve4 } from "path";
|
|
2505
2563
|
|
|
2506
2564
|
class TargetParseError extends Error {
|
|
2507
2565
|
constructor(message) {
|
|
@@ -2532,7 +2590,7 @@ function generateTsconfigDaas(cwd, target) {
|
|
|
2532
2590
|
}
|
|
2533
2591
|
}
|
|
2534
2592
|
};
|
|
2535
|
-
|
|
2593
|
+
writeFileSync2(resolve4(cwd, "tsconfig.daas.json"), `${JSON.stringify(content, null, 2)}
|
|
2536
2594
|
`);
|
|
2537
2595
|
}
|
|
2538
2596
|
|
|
@@ -2565,18 +2623,33 @@ var buildCommand = defineCommand({
|
|
|
2565
2623
|
const json = args.json;
|
|
2566
2624
|
try {
|
|
2567
2625
|
const daasConfig = readDaasConfig();
|
|
2568
|
-
|
|
2626
|
+
setLogger(createLogger([consolaTransport(), apiTransport(daasConfig.logUrl)]));
|
|
2627
|
+
let manifest = readManifest();
|
|
2628
|
+
if (daasConfig.bridge) {
|
|
2629
|
+
const prep = prepareBridgeBuild(process.cwd(), manifest);
|
|
2630
|
+
writeBridgeWrapper(prep);
|
|
2631
|
+
manifest = prep.manifest;
|
|
2632
|
+
if (!json)
|
|
2633
|
+
consola.info('Bridge mode: isolated React, exposing ./export-app (register host entry with loader: "bridge")');
|
|
2634
|
+
}
|
|
2569
2635
|
if (!json)
|
|
2570
2636
|
consola.start(`Building ${manifest.name}...`);
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2637
|
+
let remoteMeta;
|
|
2638
|
+
if (daasConfig.configUrl) {
|
|
2639
|
+
remoteMeta = await fetchRemoteConfig(daasConfig.configUrl, true);
|
|
2640
|
+
checkCliVersion(remoteMeta);
|
|
2641
|
+
checkConfigVersion(remoteMeta, true);
|
|
2642
|
+
} else {
|
|
2643
|
+
remoteMeta = loadFallback();
|
|
2644
|
+
consola.info("No configUrl \u2014 using built-in fallback config");
|
|
2645
|
+
}
|
|
2574
2646
|
const target = args.target ? parseTarget(args.target) : undefined;
|
|
2575
2647
|
if (target)
|
|
2576
2648
|
generateTsconfigDaas(process.cwd(), target);
|
|
2577
2649
|
const config = createConfig(manifest, remoteMeta, {
|
|
2578
2650
|
mode: "production",
|
|
2579
|
-
target
|
|
2651
|
+
target,
|
|
2652
|
+
bridge: daasConfig.bridge
|
|
2580
2653
|
});
|
|
2581
2654
|
const rsbuild = await createRsbuild({ rsbuildConfig: config });
|
|
2582
2655
|
await rsbuild.build();
|
|
@@ -2621,7 +2694,8 @@ var buildCommand = defineCommand({
|
|
|
2621
2694
|
});
|
|
2622
2695
|
|
|
2623
2696
|
// src/commands/dev.ts
|
|
2624
|
-
import {
|
|
2697
|
+
import { apiTransport as apiTransport2, createLogger as createLogger2, setLogger as setLogger2 } from "@chrisluyi/daas-logger";
|
|
2698
|
+
import { createConfig as createConfig2 } from "@chrisluyi/daas-rsbuild-config";
|
|
2625
2699
|
import { createRsbuild as createRsbuild2 } from "@rsbuild/core";
|
|
2626
2700
|
var devCommand = defineCommand({
|
|
2627
2701
|
meta: { name: "dev", description: "Start MFE dev server" },
|
|
@@ -2641,12 +2715,25 @@ var devCommand = defineCommand({
|
|
|
2641
2715
|
async run({ args }) {
|
|
2642
2716
|
try {
|
|
2643
2717
|
const daasConfig = readDaasConfig();
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2718
|
+
setLogger2(createLogger2([consolaTransport(), apiTransport2(daasConfig.logUrl)]));
|
|
2719
|
+
let manifest = readManifest();
|
|
2720
|
+
if (daasConfig.bridge) {
|
|
2721
|
+
const prep = prepareBridgeBuild(process.cwd(), manifest);
|
|
2722
|
+
writeBridgeWrapper(prep);
|
|
2723
|
+
manifest = prep.manifest;
|
|
2724
|
+
consola.info('Bridge mode: isolated React, exposing ./export-app (register host entry with loader: "bridge")');
|
|
2725
|
+
}
|
|
2726
|
+
let remoteMeta;
|
|
2727
|
+
if (daasConfig.configUrl) {
|
|
2728
|
+
remoteMeta = await fetchRemoteConfig(daasConfig.configUrl, false);
|
|
2729
|
+
checkCliVersion(remoteMeta);
|
|
2730
|
+
const versionOk = checkConfigVersion(remoteMeta, false);
|
|
2731
|
+
if (!versionOk) {
|
|
2732
|
+
consola.warn("Config version mismatch \u2014 update daas-cli for full compatibility");
|
|
2733
|
+
}
|
|
2734
|
+
} else {
|
|
2735
|
+
remoteMeta = loadFallback();
|
|
2736
|
+
consola.info("No configUrl \u2014 using built-in fallback config");
|
|
2650
2737
|
}
|
|
2651
2738
|
const port = args.port ? Number(args.port) : daasConfig.port;
|
|
2652
2739
|
const target = args.target ? parseTarget(args.target) : undefined;
|
|
@@ -2657,7 +2744,8 @@ var devCommand = defineCommand({
|
|
|
2657
2744
|
const config = createConfig2(manifest, remoteMeta, {
|
|
2658
2745
|
mode: "development",
|
|
2659
2746
|
port,
|
|
2660
|
-
target
|
|
2747
|
+
target,
|
|
2748
|
+
bridge: daasConfig.bridge
|
|
2661
2749
|
});
|
|
2662
2750
|
consola.start(`Starting ${manifest.name} dev server...`);
|
|
2663
2751
|
const rsbuild = await createRsbuild2({ rsbuildConfig: config });
|
|
@@ -2698,22 +2786,86 @@ function handleError(command, e2, json) {
|
|
|
2698
2786
|
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
2699
2787
|
}
|
|
2700
2788
|
|
|
2701
|
-
// src/
|
|
2789
|
+
// src/commands/host.ts
|
|
2702
2790
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
2703
|
-
import {
|
|
2791
|
+
import { resolve as resolve5 } from "path";
|
|
2792
|
+
import { createHostConfig } from "@chrisluyi/daas-rsbuild-config";
|
|
2793
|
+
import { createRsbuild as createRsbuild3 } from "@rsbuild/core";
|
|
2794
|
+
function sanitizeName(name) {
|
|
2795
|
+
return name.replace(/^@[^/]+\//, "").replace(/[^a-zA-Z0-9]/g, "_");
|
|
2796
|
+
}
|
|
2797
|
+
function readHostPackage(cwd = process.cwd()) {
|
|
2798
|
+
const pkgPath = resolve5(cwd, "package.json");
|
|
2799
|
+
if (!existsSync3(pkgPath)) {
|
|
2800
|
+
throw new Error("No package.json found. Are you in a host app directory?");
|
|
2801
|
+
}
|
|
2802
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
2803
|
+
const daas = pkg.daas ?? {};
|
|
2804
|
+
return {
|
|
2805
|
+
name: sanitizeName(pkg.name ?? "host"),
|
|
2806
|
+
port: daas.port ?? 3000
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
var hostDevCommand = defineCommand({
|
|
2810
|
+
meta: { name: "dev", description: "Start host shell dev server" },
|
|
2811
|
+
async run() {
|
|
2812
|
+
try {
|
|
2813
|
+
const { name, port } = readHostPackage();
|
|
2814
|
+
const config = createHostConfig(name, { mode: "development", port });
|
|
2815
|
+
consola.start(`Starting ${name} dev server...`);
|
|
2816
|
+
const rsbuild = await createRsbuild3({ rsbuildConfig: config });
|
|
2817
|
+
const server = await rsbuild.createDevServer();
|
|
2818
|
+
await server.listen();
|
|
2819
|
+
consola.success(`Ready on http://localhost:${port}`);
|
|
2820
|
+
} catch (e2) {
|
|
2821
|
+
consola.fatal(e2);
|
|
2822
|
+
process.exit(1);
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
});
|
|
2826
|
+
var hostBuildCommand = defineCommand({
|
|
2827
|
+
meta: { name: "build", description: "Build host shell for production" },
|
|
2828
|
+
async run() {
|
|
2829
|
+
try {
|
|
2830
|
+
const { name } = readHostPackage();
|
|
2831
|
+
const config = createHostConfig(name, { mode: "production" });
|
|
2832
|
+
consola.start(`Building ${name}...`);
|
|
2833
|
+
const rsbuild = await createRsbuild3({ rsbuildConfig: config });
|
|
2834
|
+
await rsbuild.build();
|
|
2835
|
+
consola.success("Build complete");
|
|
2836
|
+
} catch (e2) {
|
|
2837
|
+
consola.fatal(e2);
|
|
2838
|
+
process.exit(1);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
});
|
|
2842
|
+
var hostCommand = defineCommand({
|
|
2843
|
+
meta: { name: "host", description: "Commands for host shell apps" },
|
|
2844
|
+
subCommands: {
|
|
2845
|
+
dev: hostDevCommand,
|
|
2846
|
+
build: hostBuildCommand
|
|
2847
|
+
}
|
|
2848
|
+
});
|
|
2849
|
+
|
|
2850
|
+
// src/commands/info.ts
|
|
2851
|
+
import { apiTransport as apiTransport3, createLogger as createLogger3, setLogger as setLogger3 } from "@chrisluyi/daas-logger";
|
|
2852
|
+
|
|
2853
|
+
// src/init/monorepo.ts
|
|
2854
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
2855
|
+
import { dirname as dirname2, resolve as resolve6 } from "path";
|
|
2704
2856
|
function detectMonorepo(startDir) {
|
|
2705
2857
|
let dir = startDir;
|
|
2706
2858
|
for (let i2 = 0;i2 < 10; i2++) {
|
|
2707
|
-
const parent =
|
|
2859
|
+
const parent = dirname2(dir);
|
|
2708
2860
|
if (parent === dir)
|
|
2709
2861
|
break;
|
|
2710
2862
|
dir = parent;
|
|
2711
|
-
if (
|
|
2863
|
+
if (existsSync4(resolve6(dir, "bun.lockb")))
|
|
2712
2864
|
return true;
|
|
2713
|
-
const pkgPath =
|
|
2714
|
-
if (
|
|
2865
|
+
const pkgPath = resolve6(dir, "package.json");
|
|
2866
|
+
if (existsSync4(pkgPath)) {
|
|
2715
2867
|
try {
|
|
2716
|
-
const pkg = JSON.parse(
|
|
2868
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
|
|
2717
2869
|
if (pkg.workspaces)
|
|
2718
2870
|
return true;
|
|
2719
2871
|
} catch {}
|
|
@@ -2738,6 +2890,7 @@ var infoCommand = defineCommand({
|
|
|
2738
2890
|
let manifest;
|
|
2739
2891
|
try {
|
|
2740
2892
|
daasConfig = readDaasConfig();
|
|
2893
|
+
setLogger3(createLogger3([consolaTransport(), apiTransport3(daasConfig.logUrl)]));
|
|
2741
2894
|
manifest = readManifest();
|
|
2742
2895
|
} catch (e2) {
|
|
2743
2896
|
if (json)
|
|
@@ -2747,9 +2900,13 @@ var infoCommand = defineCommand({
|
|
|
2747
2900
|
}
|
|
2748
2901
|
const isMonorepo = detectMonorepo(process.cwd());
|
|
2749
2902
|
let remoteJson;
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2903
|
+
if (daasConfig.configUrl) {
|
|
2904
|
+
try {
|
|
2905
|
+
remoteJson = await fetchRemoteConfig(daasConfig.configUrl, true);
|
|
2906
|
+
} catch {
|
|
2907
|
+
remoteJson = { ...loadFallback(), offline: true };
|
|
2908
|
+
}
|
|
2909
|
+
} else {
|
|
2753
2910
|
remoteJson = { ...loadFallback(), offline: true };
|
|
2754
2911
|
}
|
|
2755
2912
|
const payload = {
|
|
@@ -2769,10 +2926,10 @@ var infoCommand = defineCommand({
|
|
|
2769
2926
|
});
|
|
2770
2927
|
|
|
2771
2928
|
// src/commands/init.ts
|
|
2772
|
-
import { existsSync as
|
|
2929
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
2773
2930
|
import { createRequire } from "module";
|
|
2774
|
-
import { resolve as
|
|
2775
|
-
import { scaffold } from "@chrisluyi/template";
|
|
2931
|
+
import { resolve as resolve8 } from "path";
|
|
2932
|
+
import { scaffold } from "@chrisluyi/daas-template";
|
|
2776
2933
|
|
|
2777
2934
|
// ../../node_modules/.bun/@clack+core@0.3.5/node_modules/@clack/core/dist/index.mjs
|
|
2778
2935
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
@@ -3265,10 +3422,10 @@ var de = () => {
|
|
|
3265
3422
|
};
|
|
3266
3423
|
|
|
3267
3424
|
// src/init/copy-template.ts
|
|
3268
|
-
import { copyFileSync, existsSync as
|
|
3269
|
-
import { dirname as
|
|
3425
|
+
import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
3426
|
+
import { dirname as dirname3, join } from "path";
|
|
3270
3427
|
import { fileURLToPath } from "url";
|
|
3271
|
-
var __dirname2 =
|
|
3428
|
+
var __dirname2 = dirname3(fileURLToPath(import.meta.url));
|
|
3272
3429
|
var TEMPLATES_DIR = join(__dirname2, "../../templates/mfe");
|
|
3273
3430
|
async function copyTemplate(destDir) {
|
|
3274
3431
|
const files = readdirSync(TEMPLATES_DIR);
|
|
@@ -3279,9 +3436,9 @@ async function copyTemplate(destDir) {
|
|
|
3279
3436
|
let dest = join(destDir, destFile);
|
|
3280
3437
|
if (destFile === "App.tsx" || destFile === "App.test.tsx") {
|
|
3281
3438
|
dest = join(destDir, "src", destFile);
|
|
3282
|
-
|
|
3439
|
+
mkdirSync2(join(destDir, "src"), { recursive: true });
|
|
3283
3440
|
}
|
|
3284
|
-
if (
|
|
3441
|
+
if (existsSync5(dest)) {
|
|
3285
3442
|
const overwrite = await se({
|
|
3286
3443
|
message: `${destFile} already exists. Overwrite?`
|
|
3287
3444
|
});
|
|
@@ -3297,11 +3454,11 @@ async function copyTemplate(destDir) {
|
|
|
3297
3454
|
}
|
|
3298
3455
|
|
|
3299
3456
|
// src/init/package-json.ts
|
|
3300
|
-
import { existsSync as
|
|
3301
|
-
import { resolve as
|
|
3457
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
3458
|
+
import { resolve as resolve7 } from "path";
|
|
3302
3459
|
function updatePackageJson(cwd, opts) {
|
|
3303
|
-
const pkgPath =
|
|
3304
|
-
const pkg =
|
|
3460
|
+
const pkgPath = resolve7(cwd, "package.json");
|
|
3461
|
+
const pkg = existsSync6(pkgPath) ? JSON.parse(readFileSync5(pkgPath, "utf8")) : {};
|
|
3305
3462
|
pkg.scripts = {
|
|
3306
3463
|
...pkg.scripts ?? {},
|
|
3307
3464
|
dev: "daas dev",
|
|
@@ -3310,9 +3467,10 @@ function updatePackageJson(cwd, opts) {
|
|
|
3310
3467
|
};
|
|
3311
3468
|
pkg.dependencies = {
|
|
3312
3469
|
...pkg.dependencies ?? {},
|
|
3470
|
+
"@module-federation/bridge-react": "*",
|
|
3313
3471
|
"@radix-ui/react-tabs": "^1.1.0",
|
|
3314
3472
|
...opts.isFullTemplate ? {
|
|
3315
|
-
"@chrisluyi/template": `^${opts.templateVersion ?? opts.cliVersion ?? "1.0.0"}`,
|
|
3473
|
+
"@chrisluyi/daas-template": `^${opts.templateVersion ?? opts.cliVersion ?? "1.0.0"}`,
|
|
3316
3474
|
"@tanstack/react-query": "^5.0.0",
|
|
3317
3475
|
zustand: "^5.0.0",
|
|
3318
3476
|
immer: "^10.0.0",
|
|
@@ -3326,7 +3484,7 @@ function updatePackageJson(cwd, opts) {
|
|
|
3326
3484
|
};
|
|
3327
3485
|
}
|
|
3328
3486
|
pkg.daas = { configUrl: opts.configUrl, port: opts.port };
|
|
3329
|
-
|
|
3487
|
+
writeFileSync3(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
3330
3488
|
`);
|
|
3331
3489
|
}
|
|
3332
3490
|
|
|
@@ -3410,7 +3568,7 @@ var initCommand = defineCommand({
|
|
|
3410
3568
|
s2.message("\u2713 Updated package.json");
|
|
3411
3569
|
if (hasExtraExposes) {
|
|
3412
3570
|
const manifest = { name: appName, exposes: { "./App": "./src/App" } };
|
|
3413
|
-
|
|
3571
|
+
writeFileSync4(resolve8(cwd, "mf.manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
3414
3572
|
`);
|
|
3415
3573
|
s2.message("\u2713 Created mf.manifest.json (add extra exposes as needed)");
|
|
3416
3574
|
}
|
|
@@ -3421,26 +3579,225 @@ var initCommand = defineCommand({
|
|
|
3421
3579
|
function getTemplateVersion() {
|
|
3422
3580
|
try {
|
|
3423
3581
|
const req = createRequire(import.meta.url);
|
|
3424
|
-
const pkg = req("@chrisluyi/template/package.json");
|
|
3582
|
+
const pkg = req("@chrisluyi/daas-template/package.json");
|
|
3425
3583
|
return pkg.version ?? "1.0.0";
|
|
3426
3584
|
} catch {
|
|
3427
3585
|
return "1.0.0";
|
|
3428
3586
|
}
|
|
3429
3587
|
}
|
|
3430
3588
|
function getPackageName(cwd) {
|
|
3431
|
-
const pkgPath =
|
|
3432
|
-
if (!
|
|
3589
|
+
const pkgPath = resolve8(cwd, "package.json");
|
|
3590
|
+
if (!existsSync7(pkgPath))
|
|
3433
3591
|
return "mfe-app";
|
|
3434
3592
|
try {
|
|
3435
|
-
const pkg = JSON.parse(
|
|
3593
|
+
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
3436
3594
|
return (pkg.name ?? "mfe-app").replace(/^@[^/]+\//, "");
|
|
3437
3595
|
} catch {
|
|
3438
3596
|
return "mfe-app";
|
|
3439
3597
|
}
|
|
3440
3598
|
}
|
|
3441
3599
|
|
|
3600
|
+
// src/region.ts
|
|
3601
|
+
import { spawnSync } from "child_process";
|
|
3602
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
3603
|
+
import { relative as relative2, resolve as resolve9 } from "path";
|
|
3604
|
+
|
|
3605
|
+
class RegionError extends Error {
|
|
3606
|
+
constructor(message) {
|
|
3607
|
+
super(message);
|
|
3608
|
+
this.name = "RegionError";
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
var DEFAULT_ALIASES = {
|
|
3612
|
+
"@region-config": "./src/config/regions/{region}/config",
|
|
3613
|
+
"@regional": "./src/config/regions/{region}/index"
|
|
3614
|
+
};
|
|
3615
|
+
function readRegionalConfig(cwd = process.cwd()) {
|
|
3616
|
+
const pkgPath = resolve9(cwd, "package.json");
|
|
3617
|
+
if (!existsSync8(pkgPath)) {
|
|
3618
|
+
throw new RegionError("No package.json found. Run from the project root (the daas.regional block lives there).");
|
|
3619
|
+
}
|
|
3620
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
3621
|
+
const r4 = pkg.daas?.regional ?? {};
|
|
3622
|
+
return {
|
|
3623
|
+
...r4,
|
|
3624
|
+
regionsDir: r4.regionsDir ?? "src/config/regions",
|
|
3625
|
+
tsconfig: r4.tsconfig ?? "tsconfig.daas.json",
|
|
3626
|
+
extends: r4.extends ?? "./tsconfig.json",
|
|
3627
|
+
bunPaths: r4.bunPaths ?? false
|
|
3628
|
+
};
|
|
3629
|
+
}
|
|
3630
|
+
function discoverRegions(cwd, cfg) {
|
|
3631
|
+
if (cfg.regions && cfg.regions.length > 0)
|
|
3632
|
+
return cfg.regions;
|
|
3633
|
+
const dir = resolve9(cwd, cfg.regionsDir ?? "src/config/regions");
|
|
3634
|
+
if (!existsSync8(dir)) {
|
|
3635
|
+
throw new RegionError(`regionsDir "${cfg.regionsDir}" does not exist \u2014 set daas.regional.regionsDir or daas.regional.regions in package.json`);
|
|
3636
|
+
}
|
|
3637
|
+
const regions = readdirSync2(dir, { withFileTypes: true }).filter((e3) => e3.isDirectory()).map((e3) => e3.name).sort();
|
|
3638
|
+
if (regions.length === 0) {
|
|
3639
|
+
throw new RegionError(`regionsDir "${cfg.regionsDir}" has no region folders`);
|
|
3640
|
+
}
|
|
3641
|
+
return regions;
|
|
3642
|
+
}
|
|
3643
|
+
function renderRegionTsconfig(cwd, cfg, region) {
|
|
3644
|
+
const regions = discoverRegions(cwd, cfg);
|
|
3645
|
+
if (!regions.includes(region)) {
|
|
3646
|
+
throw new RegionError(`Unknown region "${region}". Known: ${regions.join(", ")}`);
|
|
3647
|
+
}
|
|
3648
|
+
const aliases = cfg.aliases ?? DEFAULT_ALIASES;
|
|
3649
|
+
const paths = Object.fromEntries(Object.entries(aliases).map(([k3, v3]) => [
|
|
3650
|
+
k3,
|
|
3651
|
+
[v3.replaceAll("{region}", region)]
|
|
3652
|
+
]));
|
|
3653
|
+
const tsconfigDir = resolve9(cwd, cfg.tsconfig, "..");
|
|
3654
|
+
const regionsDirAbs = resolve9(cwd, cfg.regionsDir);
|
|
3655
|
+
const others = regions.filter((r4) => r4 !== region).map((r4) => relative2(tsconfigDir, resolve9(regionsDirAbs, r4)));
|
|
3656
|
+
const exclude = [...others, ...cfg.multiRegionFiles ?? []];
|
|
3657
|
+
const compilerOptions = {
|
|
3658
|
+
...cfg.bunPaths ? { baseUrl: ".", ignoreDeprecations: "6.0" } : {},
|
|
3659
|
+
paths
|
|
3660
|
+
};
|
|
3661
|
+
const body = JSON.stringify({ extends: cfg.extends, compilerOptions, exclude }, null, 2);
|
|
3662
|
+
return `// GENERATED by \`daas region ${region}\` \u2014 do not edit; regenerate or \`daas region --reset\`.
|
|
3663
|
+
${body}
|
|
3664
|
+
`;
|
|
3665
|
+
}
|
|
3666
|
+
function writeRegionTsconfig(cwd, cfg, region, applyTo) {
|
|
3667
|
+
const content = renderRegionTsconfig(cwd, cfg, region);
|
|
3668
|
+
const out = resolve9(cwd, cfg.tsconfig);
|
|
3669
|
+
writeFileSync5(out, content);
|
|
3670
|
+
if (applyTo) {
|
|
3671
|
+
writeFileSync5(resolve9(cwd, applyTo), content);
|
|
3672
|
+
return { generated: out, applied: resolve9(cwd, applyTo) };
|
|
3673
|
+
}
|
|
3674
|
+
return { generated: out };
|
|
3675
|
+
}
|
|
3676
|
+
function resetTsconfig(cwd, path) {
|
|
3677
|
+
const rel = relative2(cwd, resolve9(cwd, path));
|
|
3678
|
+
const show = spawnSync("git", ["show", `HEAD:${rel}`], {
|
|
3679
|
+
cwd,
|
|
3680
|
+
encoding: "utf8"
|
|
3681
|
+
});
|
|
3682
|
+
if (show.status !== 0) {
|
|
3683
|
+
throw new RegionError(`Cannot restore "${rel}" from git HEAD: ${show.stderr.trim() || "not a tracked file?"}`);
|
|
3684
|
+
}
|
|
3685
|
+
writeFileSync5(resolve9(cwd, path), show.stdout);
|
|
3686
|
+
}
|
|
3687
|
+
function runRegionCheck(cwd, cfg, runner = (p) => {
|
|
3688
|
+
const r4 = spawnSync("bunx", ["tsc", "--noEmit", "-p", p], {
|
|
3689
|
+
cwd,
|
|
3690
|
+
encoding: "utf8"
|
|
3691
|
+
});
|
|
3692
|
+
return { ok: r4.status === 0, output: `${r4.stdout ?? ""}${r4.stderr ?? ""}` };
|
|
3693
|
+
}) {
|
|
3694
|
+
const results = [];
|
|
3695
|
+
for (const region of discoverRegions(cwd, cfg)) {
|
|
3696
|
+
writeRegionTsconfig(cwd, cfg, region);
|
|
3697
|
+
const { ok, output } = runner(resolve9(cwd, cfg.tsconfig));
|
|
3698
|
+
results.push({ region, ok, output });
|
|
3699
|
+
}
|
|
3700
|
+
return results;
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
// src/commands/region.ts
|
|
3704
|
+
var regionCommand = defineCommand({
|
|
3705
|
+
meta: {
|
|
3706
|
+
name: "region",
|
|
3707
|
+
description: "Region-scoped type programs: generate a tsconfig containing ONLY the selected region (mirror of the build-time region alias swap)"
|
|
3708
|
+
},
|
|
3709
|
+
args: {
|
|
3710
|
+
region: {
|
|
3711
|
+
type: "positional",
|
|
3712
|
+
description: "Region to select (see --list)",
|
|
3713
|
+
required: false
|
|
3714
|
+
},
|
|
3715
|
+
list: { type: "boolean", default: false, description: "List regions" },
|
|
3716
|
+
check: {
|
|
3717
|
+
type: "boolean",
|
|
3718
|
+
default: false,
|
|
3719
|
+
description: "Matrix gate: generate + tsc --noEmit for EVERY region; fails if any region's program fails"
|
|
3720
|
+
},
|
|
3721
|
+
apply: {
|
|
3722
|
+
type: "string",
|
|
3723
|
+
description: "Also overwrite this tsconfig with the generated content (editor + Bun follow the selection); undo with --reset"
|
|
3724
|
+
},
|
|
3725
|
+
reset: {
|
|
3726
|
+
type: "string",
|
|
3727
|
+
description: "Restore this tsconfig from git HEAD (undo --apply)"
|
|
3728
|
+
},
|
|
3729
|
+
json: {
|
|
3730
|
+
type: "boolean",
|
|
3731
|
+
default: false,
|
|
3732
|
+
description: "Machine-readable JSON output"
|
|
3733
|
+
}
|
|
3734
|
+
},
|
|
3735
|
+
async run({ args }) {
|
|
3736
|
+
try {
|
|
3737
|
+
const cwd = process.cwd();
|
|
3738
|
+
const cfg = readRegionalConfig(cwd);
|
|
3739
|
+
if (args.reset) {
|
|
3740
|
+
resetTsconfig(cwd, args.reset);
|
|
3741
|
+
if (args.json)
|
|
3742
|
+
writeJsonSuccess("region", { reset: args.reset });
|
|
3743
|
+
else
|
|
3744
|
+
consola.success(`Restored ${args.reset} from git HEAD`);
|
|
3745
|
+
return;
|
|
3746
|
+
}
|
|
3747
|
+
if (args.list) {
|
|
3748
|
+
const regions = discoverRegions(cwd, cfg);
|
|
3749
|
+
if (args.json)
|
|
3750
|
+
writeJsonSuccess("region", { regions });
|
|
3751
|
+
else
|
|
3752
|
+
consola.info(`Regions: ${regions.join(", ")}`);
|
|
3753
|
+
return;
|
|
3754
|
+
}
|
|
3755
|
+
if (args.check) {
|
|
3756
|
+
const results = runRegionCheck(cwd, cfg);
|
|
3757
|
+
for (const r4 of results) {
|
|
3758
|
+
if (r4.ok)
|
|
3759
|
+
consola.success(`region ${r4.region}`);
|
|
3760
|
+
else {
|
|
3761
|
+
consola.error(`region ${r4.region}`);
|
|
3762
|
+
if (!args.json && r4.output.trim())
|
|
3763
|
+
consola.log(r4.output.trim());
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
const failed = results.filter((r4) => !r4.ok);
|
|
3767
|
+
if (args.json)
|
|
3768
|
+
writeJsonSuccess("region", {
|
|
3769
|
+
results: results.map(({ region, ok }) => ({ region, ok }))
|
|
3770
|
+
});
|
|
3771
|
+
if (failed.length > 0)
|
|
3772
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
3773
|
+
return;
|
|
3774
|
+
}
|
|
3775
|
+
if (!args.region) {
|
|
3776
|
+
throw new RegionError("Pass a region (see --list), or use --check / --reset");
|
|
3777
|
+
}
|
|
3778
|
+
const { generated, applied } = writeRegionTsconfig(cwd, cfg, args.region, args.apply);
|
|
3779
|
+
if (args.json)
|
|
3780
|
+
writeJsonSuccess("region", { region: args.region, generated, applied });
|
|
3781
|
+
else {
|
|
3782
|
+
consola.success(`Region-scoped tsconfig for "${args.region}" \u2192 ${generated}`);
|
|
3783
|
+
if (applied)
|
|
3784
|
+
consola.info(`Applied to ${applied} (undo: daas region --reset ${args.apply})`);
|
|
3785
|
+
}
|
|
3786
|
+
} catch (err) {
|
|
3787
|
+
if (err instanceof RegionError) {
|
|
3788
|
+
if (args.json)
|
|
3789
|
+
writeJsonError("region", EXIT_CODES.GENERAL_ERROR, err.message, "Check the daas.regional block in package.json (regionsDir/regions/aliases) and run with --list");
|
|
3790
|
+
consola.error(err.message);
|
|
3791
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
3792
|
+
}
|
|
3793
|
+
throw err;
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
});
|
|
3797
|
+
|
|
3442
3798
|
// src/commands/test.ts
|
|
3443
|
-
import {
|
|
3799
|
+
import { apiTransport as apiTransport4, createLogger as createLogger4, setLogger as setLogger4 } from "@chrisluyi/daas-logger";
|
|
3800
|
+
import { createVitestConfig } from "@chrisluyi/daas-rsbuild-config/vitest";
|
|
3444
3801
|
import { startVitest } from "vitest/node";
|
|
3445
3802
|
var testCommand = defineCommand({
|
|
3446
3803
|
meta: { name: "test", description: "Run MFE tests" },
|
|
@@ -3456,6 +3813,7 @@ var testCommand = defineCommand({
|
|
|
3456
3813
|
try {
|
|
3457
3814
|
const manifest = readManifest();
|
|
3458
3815
|
const daasConfig = readDaasConfig();
|
|
3816
|
+
setLogger4(createLogger4([consolaTransport(), apiTransport4(daasConfig.logUrl)]));
|
|
3459
3817
|
const config = createVitestConfig(manifest, {
|
|
3460
3818
|
coverage: daasConfig.coverage,
|
|
3461
3819
|
setupFiles: daasConfig.setupFiles
|
|
@@ -3479,6 +3837,7 @@ var testCommand = defineCommand({
|
|
|
3479
3837
|
});
|
|
3480
3838
|
|
|
3481
3839
|
// src/index.ts
|
|
3840
|
+
setLogger5(createLogger5([consolaTransport()]));
|
|
3482
3841
|
var main = defineCommand({
|
|
3483
3842
|
meta: {
|
|
3484
3843
|
name: "daas",
|
|
@@ -3490,7 +3849,9 @@ var main = defineCommand({
|
|
|
3490
3849
|
dev: devCommand,
|
|
3491
3850
|
build: buildCommand,
|
|
3492
3851
|
test: testCommand,
|
|
3493
|
-
info: infoCommand
|
|
3852
|
+
info: infoCommand,
|
|
3853
|
+
host: hostCommand,
|
|
3854
|
+
region: regionCommand
|
|
3494
3855
|
}
|
|
3495
3856
|
});
|
|
3496
3857
|
runMain(main);
|
package/dist/test.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrisluyi/daas-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"daas": "./dist/index.js"
|
|
@@ -16,27 +16,25 @@
|
|
|
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/daas-template --external @chrisluyi/daas-logger --external @chrisluyi/daas-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/daas-rsbuild-config",
|
|
20
20
|
"test": "bun test --ignore 'templates/**'"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@clack/prompts": "^0.7.0",
|
|
24
|
-
"@chrisluyi/
|
|
25
|
-
"@chrisluyi/
|
|
26
|
-
"@
|
|
24
|
+
"@chrisluyi/daas-logger": "workspace:*",
|
|
25
|
+
"@chrisluyi/daas-rsbuild-config": "workspace:*",
|
|
26
|
+
"@chrisluyi/daas-template": "workspace:*",
|
|
27
|
+
"@rsbuild/core": "*",
|
|
27
28
|
"citty": "^0.1.6",
|
|
28
29
|
"consola": "^3.2.3",
|
|
29
|
-
"vitest": "
|
|
30
|
+
"vitest": "*"
|
|
30
31
|
},
|
|
31
|
-
"
|
|
32
|
-
"
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20.19.0"
|
|
33
34
|
},
|
|
34
35
|
"repository": {
|
|
35
36
|
"type": "git",
|
|
36
37
|
"url": "https://github.com/Chris-LuYi/daas-cli",
|
|
37
38
|
"directory": "packages/cli"
|
|
38
|
-
},
|
|
39
|
-
"publishConfig": {
|
|
40
|
-
"access": "public"
|
|
41
39
|
}
|
|
42
40
|
}
|
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/daas-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
|