@unispechq/unispec-platform 0.2.0 → 0.2.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.
- package/README.md +21 -41
- package/dist/cli.js +2 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/index.d.ts +1 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -2
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/portal.d.ts +3 -0
- package/dist/commands/portal.d.ts.map +1 -0
- package/dist/commands/portal.js +90 -0
- package/dist/commands/portal.js.map +1 -0
- package/package.json +1 -1
- package/dist/commands/dev.d.ts +0 -3
- package/dist/commands/dev.d.ts.map +0 -1
- package/dist/commands/dev.js +0 -211
- package/dist/commands/dev.js.map +0 -1
- package/dist/commands/start.d.ts +0 -3
- package/dist/commands/start.d.ts.map +0 -1
- package/dist/commands/start.js +0 -125
- package/dist/commands/start.js.map +0 -1
- package/dist/dev/aggregate.d.ts +0 -15
- package/dist/dev/aggregate.d.ts.map +0 -1
- package/dist/dev/aggregate.js +0 -56
- package/dist/dev/aggregate.js.map +0 -1
- package/dist/dev/index.d.ts +0 -3
- package/dist/dev/index.d.ts.map +0 -1
- package/dist/dev/index.js +0 -3
- package/dist/dev/index.js.map +0 -1
- package/dist/dev/server.d.ts +0 -17
- package/dist/dev/server.d.ts.map +0 -1
- package/dist/dev/server.js +0 -503
- package/dist/dev/server.js.map +0 -1
- package/dist/dev/ui.d.ts +0 -3
- package/dist/dev/ui.d.ts.map +0 -1
- package/dist/dev/ui.js +0 -93
- package/dist/dev/ui.js.map +0 -1
- package/dist/workspace/storage.d.ts +0 -7
- package/dist/workspace/storage.d.ts.map +0 -1
- package/dist/workspace/storage.js +0 -60
- package/dist/workspace/storage.js.map +0 -1
- package/dist/workspace/types.d.ts +0 -64
- package/dist/workspace/types.d.ts.map +0 -1
- package/dist/workspace/types.js +0 -2
- package/dist/workspace/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -89,59 +89,39 @@ Options:
|
|
|
89
89
|
- `--format <format>` — `json|yaml` (for JSON-like targets)
|
|
90
90
|
- `--output <file>` — write output to file (use `-` for stdout)
|
|
91
91
|
|
|
92
|
-
### `unispec dev
|
|
93
|
-
|
|
92
|
+
### `unispec portal <dev|start>`
|
|
93
|
+
Launch UniSpec Portal (Next.js orchestrator).
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
In the current architecture, `unispec-platform` provides CLI utilities (validate/normalize/diff/convert) and a launcher for `@unispechq/unispec-portal`.
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
- `POST /tests/run` — run workspace tests (suite/flow)
|
|
97
|
+
Examples:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
unispec portal dev --config ./unispec.config.json
|
|
101
|
+
unispec portal start --config ./unispec.config.json
|
|
102
|
+
```
|
|
104
103
|
|
|
105
104
|
Options:
|
|
106
105
|
|
|
107
|
-
- `--config <path>` — path to config file
|
|
108
|
-
- `--host <host>` — bind host (
|
|
109
|
-
- `--port <port>` — bind port (
|
|
110
|
-
- `--
|
|
111
|
-
- `--
|
|
112
|
-
- `--
|
|
113
|
-
- `--
|
|
114
|
-
- `--
|
|
106
|
+
- `--config <path>` — path to config file
|
|
107
|
+
- `--host <host>` — bind host (forwarded to portal)
|
|
108
|
+
- `--port <port>` — bind port (forwarded to portal)
|
|
109
|
+
- `--storage <type>` — `json|sqlite` (forwarded to portal)
|
|
110
|
+
- `--data-dir <path>` — data directory (forwarded to portal)
|
|
111
|
+
- `--open` — open browser (forwarded to portal)
|
|
112
|
+
- `--verbose` — verbose output (forwarded to portal)
|
|
113
|
+
- `--json-errors` — output errors as JSON (forwarded to portal)
|
|
115
114
|
- `--portal-package <name>` — portal package name (default: `@unispechq/unispec-portal`)
|
|
116
115
|
|
|
117
|
-
Planned responsibilities:
|
|
118
|
-
|
|
119
|
-
- Watch local specs and/or connected services
|
|
120
|
-
- Aggregate multiple UniSpec documents (microservices mode)
|
|
121
|
-
- Serve a local dashboard and endpoints (e.g. `/unispec.json` for aggregated view)
|
|
122
|
-
- Provide a single workflow to validate/normalize/diff before publishing to Registry
|
|
123
|
-
|
|
124
116
|
---
|
|
125
117
|
|
|
126
|
-
##
|
|
127
|
-
|
|
128
|
-
`unispec dev` starts a local HTTP API that aggregates multiple UniSpec documents.
|
|
118
|
+
## Notes
|
|
129
119
|
|
|
130
|
-
|
|
120
|
+
All orchestration responsibilities (HTTP API, watch mode, workspace storage, and test runner) live in the Portal package.
|
|
131
121
|
|
|
132
|
-
|
|
133
|
-
- Port: `4141`
|
|
134
|
-
|
|
135
|
-
Endpoints:
|
|
136
|
-
|
|
137
|
-
- `GET /health` -> `OK`
|
|
138
|
-
- `GET /unispec.json` -> aggregated JSON
|
|
139
|
-
- `GET /workspace.json` -> workspace info (paths + API URLs)
|
|
140
|
-
- `GET /workspace/state` -> workspace state
|
|
141
|
-
- `PUT /workspace/state` -> save workspace state
|
|
142
|
-
- `POST /tests/run` -> run tests (suite flow)
|
|
122
|
+
---
|
|
143
123
|
|
|
144
|
-
Aggregation format (A)
|
|
124
|
+
## Aggregation format (A)
|
|
145
125
|
|
|
146
126
|
```json
|
|
147
127
|
{
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import { registerConvertCommand,
|
|
3
|
+
import { registerConvertCommand, registerDiffCommand, registerNormalizeCommand, registerPortalCommand, registerValidateCommand, } from "./commands/index.js";
|
|
4
4
|
function errorToJson(err, includeStack) {
|
|
5
5
|
const message = err instanceof Error ? err.message : String(err);
|
|
6
6
|
const code = err instanceof Error && "code" in err ? String(err.code) : undefined;
|
|
@@ -41,8 +41,7 @@ registerValidateCommand(program);
|
|
|
41
41
|
registerNormalizeCommand(program);
|
|
42
42
|
registerDiffCommand(program);
|
|
43
43
|
registerConvertCommand(program);
|
|
44
|
-
|
|
45
|
-
registerStartCommand(program);
|
|
44
|
+
registerPortalCommand(program);
|
|
46
45
|
program.parseAsync(normalizeGlobalOptionsArgv(process.argv)).catch((err) => {
|
|
47
46
|
const opts = program.opts();
|
|
48
47
|
const verbose = opts.verbose ?? false;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,sBAAsB,EACtB,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
package/dist/commands/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/commands/portal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoE5D"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
async function resolvePortalBin(portalPackage) {
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const pkgJsonPath = require.resolve(`${portalPackage}/package.json`);
|
|
8
|
+
const pkgDir = dirname(pkgJsonPath);
|
|
9
|
+
const pkgRaw = await readFile(pkgJsonPath, "utf8");
|
|
10
|
+
const pkg = JSON.parse(pkgRaw);
|
|
11
|
+
if (!pkg.bin) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
if (typeof pkg.bin === "string") {
|
|
15
|
+
return { binPath: join(pkgDir, pkg.bin), binName: portalPackage };
|
|
16
|
+
}
|
|
17
|
+
const entries = Object.entries(pkg.bin);
|
|
18
|
+
if (entries.length === 0) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const preferred = entries.find(([name]) => name === "unispec-portal") ?? entries[0];
|
|
22
|
+
return { binPath: join(pkgDir, preferred[1]), binName: preferred[0] };
|
|
23
|
+
}
|
|
24
|
+
function pickArg(options, camel, kebab) {
|
|
25
|
+
const v = options[camel] ?? options[kebab];
|
|
26
|
+
if (v === undefined || v === null)
|
|
27
|
+
return undefined;
|
|
28
|
+
return String(v);
|
|
29
|
+
}
|
|
30
|
+
export function registerPortalCommand(program) {
|
|
31
|
+
const cmd = program
|
|
32
|
+
.command("portal")
|
|
33
|
+
.description("Launch UniSpec Portal (Next.js orchestrator)")
|
|
34
|
+
.option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal");
|
|
35
|
+
const addSharedOptions = (c) => c
|
|
36
|
+
.requiredOption("--config <path>", "Path to unispec config file")
|
|
37
|
+
.option("--host <host>", "Bind host")
|
|
38
|
+
.option("--port <port>", "Bind port")
|
|
39
|
+
.option("--storage <type>", "Storage backend (json|sqlite)")
|
|
40
|
+
.option("--data-dir <path>", "Data directory (default: <configDir>/.unispec)")
|
|
41
|
+
.option("--open", "Open browser")
|
|
42
|
+
.option("--verbose", "Verbose portal output")
|
|
43
|
+
.option("--json-errors", "Output portal errors as JSON");
|
|
44
|
+
for (const mode of ["dev", "start"]) {
|
|
45
|
+
addSharedOptions(cmd
|
|
46
|
+
.command(mode)
|
|
47
|
+
.description(`Run portal in ${mode} mode`)
|
|
48
|
+
.action(async function (options) {
|
|
49
|
+
const parentOpts = this.parent?.opts?.();
|
|
50
|
+
const portalPackage = String(parentOpts?.portalPackage ?? "@unispechq/unispec-portal");
|
|
51
|
+
let resolved = null;
|
|
52
|
+
try {
|
|
53
|
+
resolved = await resolvePortalBin(portalPackage);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
57
|
+
throw new Error(`Failed to resolve portal package '${portalPackage}': ${message}`);
|
|
58
|
+
}
|
|
59
|
+
if (!resolved) {
|
|
60
|
+
throw new Error(`Portal package '${portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
|
|
61
|
+
}
|
|
62
|
+
const args = [resolved.binPath, mode, "--config", String(options.config)];
|
|
63
|
+
const host = pickArg(options, "host", "host");
|
|
64
|
+
if (host)
|
|
65
|
+
args.push("--host", host);
|
|
66
|
+
const port = pickArg(options, "port", "port");
|
|
67
|
+
if (port)
|
|
68
|
+
args.push("--port", port);
|
|
69
|
+
const storage = pickArg(options, "storage", "storage");
|
|
70
|
+
if (storage)
|
|
71
|
+
args.push("--storage", storage);
|
|
72
|
+
const dataDir = pickArg(options, "dataDir", "data-dir");
|
|
73
|
+
if (dataDir)
|
|
74
|
+
args.push("--data-dir", dataDir);
|
|
75
|
+
if (options.open)
|
|
76
|
+
args.push("--open");
|
|
77
|
+
if (options.verbose)
|
|
78
|
+
args.push("--verbose");
|
|
79
|
+
if (options["jsonErrors"] ?? options["json-errors"])
|
|
80
|
+
args.push("--json-errors");
|
|
81
|
+
const child = spawn(process.execPath, args, {
|
|
82
|
+
stdio: "inherit",
|
|
83
|
+
env: { ...process.env },
|
|
84
|
+
});
|
|
85
|
+
const code = await new Promise((resolve) => child.once("exit", (c) => resolve(c ?? 0)));
|
|
86
|
+
process.exitCode = code;
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=portal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.js","sourceRoot":"","sources":["../../src/commands/portal.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/commands/dev.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiFzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgLzD"}
|
package/dist/commands/dev.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { watch } from "node:fs";
|
|
3
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { readFile } from "node:fs/promises";
|
|
6
|
-
import { loadConfig } from "../config/loadConfig.js";
|
|
7
|
-
import { findConfigPath } from "../config/loadConfig.js";
|
|
8
|
-
import { aggregateFromConfig } from "../dev/aggregate.js";
|
|
9
|
-
import { startDevServer } from "../dev/server.js";
|
|
10
|
-
function resolveConfigSpecPaths(config, baseDir) {
|
|
11
|
-
if (!baseDir)
|
|
12
|
-
return config;
|
|
13
|
-
const services = Array.isArray(config.services) ? config.services : [];
|
|
14
|
-
return {
|
|
15
|
-
...config,
|
|
16
|
-
services: services.map((s) => {
|
|
17
|
-
const spec = String(s?.spec ?? "");
|
|
18
|
-
const resolvedSpec = spec && !isAbsolute(spec) ? resolve(baseDir, spec) : spec;
|
|
19
|
-
return {
|
|
20
|
-
...s,
|
|
21
|
-
spec: resolvedSpec,
|
|
22
|
-
};
|
|
23
|
-
}),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
async function resolvePortalBin(portalPackage) {
|
|
27
|
-
const require = createRequire(import.meta.url);
|
|
28
|
-
const pkgJsonPath = require.resolve(`${portalPackage}/package.json`);
|
|
29
|
-
const pkgDir = dirname(pkgJsonPath);
|
|
30
|
-
const pkgRaw = await readFile(pkgJsonPath, "utf8");
|
|
31
|
-
const pkg = JSON.parse(pkgRaw);
|
|
32
|
-
if (!pkg.bin) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
if (typeof pkg.bin === "string") {
|
|
36
|
-
return { binPath: join(pkgDir, pkg.bin), binName: portalPackage };
|
|
37
|
-
}
|
|
38
|
-
const entries = Object.entries(pkg.bin);
|
|
39
|
-
if (entries.length === 0) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
const preferred = entries.find(([name]) => name.includes("dev")) ?? entries[0];
|
|
43
|
-
return { binPath: join(pkgDir, preferred[1]), binName: preferred[0] };
|
|
44
|
-
}
|
|
45
|
-
async function spawnPortalDevServer(options) {
|
|
46
|
-
const resolved = await resolvePortalBin(options.portalPackage);
|
|
47
|
-
if (!resolved) {
|
|
48
|
-
throw new Error(`Portal package '${options.portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
|
|
49
|
-
}
|
|
50
|
-
const args = [resolved.binPath, "--port", String(options.port)];
|
|
51
|
-
const child = spawn(process.execPath, args, {
|
|
52
|
-
stdio: options.verbose ? "inherit" : "ignore",
|
|
53
|
-
env: { ...process.env, PORT: String(options.port) },
|
|
54
|
-
});
|
|
55
|
-
child.once("exit", (code) => {
|
|
56
|
-
if (options.verbose) {
|
|
57
|
-
process.stderr.write(`Portal dev server exited with code ${code ?? "null"}\n`);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
return child;
|
|
61
|
-
}
|
|
62
|
-
export function registerDevCommand(program) {
|
|
63
|
-
program
|
|
64
|
-
.command("dev")
|
|
65
|
-
.description("Local orchestrator mode: aggregate specs and serve a local API")
|
|
66
|
-
.option("--config <path>", "Path to unispec config file")
|
|
67
|
-
.option("--host <host>", "Host to bind", "127.0.0.1")
|
|
68
|
-
.option("--port <port>", "Port to bind", "4141")
|
|
69
|
-
.option("--watch", "Watch config/spec files and refresh aggregated snapshot")
|
|
70
|
-
.option("--ui", "Serve embedded UI at /", true)
|
|
71
|
-
.option("--no-ui", "Disable embedded UI")
|
|
72
|
-
.option("--ui-dev <url>", "Proxy UI requests to an external dev server (e.g. Next.js)")
|
|
73
|
-
.option("--portal", "Spawn portal server and proxy UI to it")
|
|
74
|
-
.option("--portal-port <port>", "Port for portal server", "3000")
|
|
75
|
-
.option("--portal-dev", "Spawn portal dev server from an installed dependency and proxy UI to it")
|
|
76
|
-
.option("--portal-dev-port <port>", "Port for portal dev server")
|
|
77
|
-
.option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal")
|
|
78
|
-
.action(async function (options) {
|
|
79
|
-
const parentOpts = this.parent?.opts?.();
|
|
80
|
-
const verbose = parentOpts?.verbose ?? false;
|
|
81
|
-
const host = String(options.host ?? "127.0.0.1");
|
|
82
|
-
const port = Number(options.port ?? 4141);
|
|
83
|
-
let snapshot;
|
|
84
|
-
let snapshotError;
|
|
85
|
-
const configPath = await findConfigPath({ explicitPath: options.config });
|
|
86
|
-
const configDir = configPath ? dirname(configPath) : undefined;
|
|
87
|
-
const workspaceDir = configDir ? join(configDir, ".unispec") : undefined;
|
|
88
|
-
const loadAndAggregate = async () => {
|
|
89
|
-
const config = await loadConfig({ explicitPath: options.config });
|
|
90
|
-
const cfg = resolveConfigSpecPaths(config ?? { version: 1, services: [] }, configDir);
|
|
91
|
-
return aggregateFromConfig(cfg);
|
|
92
|
-
};
|
|
93
|
-
const refreshSnapshot = async () => {
|
|
94
|
-
try {
|
|
95
|
-
snapshot = await loadAndAggregate();
|
|
96
|
-
snapshotError = undefined;
|
|
97
|
-
if (verbose) {
|
|
98
|
-
process.stderr.write("Refreshed aggregated snapshot\n");
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
catch (err) {
|
|
102
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
103
|
-
snapshotError = { message };
|
|
104
|
-
if (verbose) {
|
|
105
|
-
process.stderr.write(`Failed to refresh snapshot: ${message}\n`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
await refreshSnapshot();
|
|
110
|
-
const getConfig = async () => {
|
|
111
|
-
const config = await loadConfig({ explicitPath: options.config });
|
|
112
|
-
return resolveConfigSpecPaths(config ?? { version: 1, services: [] }, configDir);
|
|
113
|
-
};
|
|
114
|
-
const getAggregated = async () => {
|
|
115
|
-
if (snapshot) {
|
|
116
|
-
return snapshot;
|
|
117
|
-
}
|
|
118
|
-
if (snapshotError) {
|
|
119
|
-
return {
|
|
120
|
-
version: 1,
|
|
121
|
-
generatedAt: new Date().toISOString(),
|
|
122
|
-
services: [
|
|
123
|
-
{
|
|
124
|
-
name: "orchestrator",
|
|
125
|
-
specPath: "config",
|
|
126
|
-
valid: false,
|
|
127
|
-
errors: [snapshotError],
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
return loadAndAggregate();
|
|
133
|
-
};
|
|
134
|
-
let portalChild;
|
|
135
|
-
let uiDevUrl = options.uiDev;
|
|
136
|
-
const portalEnabled = options.portalDev || options.portal;
|
|
137
|
-
const portalPortRaw = options.portalDevPort ?? options.portalPort;
|
|
138
|
-
if (portalEnabled) {
|
|
139
|
-
if (uiDevUrl) {
|
|
140
|
-
throw new Error("--portal cannot be used together with --ui-dev");
|
|
141
|
-
}
|
|
142
|
-
const portalPort = Number(portalPortRaw ?? 3000);
|
|
143
|
-
const portalPackage = String(options.portalPackage ?? "@unispechq/unispec-portal");
|
|
144
|
-
uiDevUrl = `http://127.0.0.1:${portalPort}`;
|
|
145
|
-
try {
|
|
146
|
-
portalChild = await spawnPortalDevServer({ portalPackage, port: portalPort, verbose });
|
|
147
|
-
const stop = () => {
|
|
148
|
-
try {
|
|
149
|
-
portalChild?.kill("SIGINT");
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// ignore
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
process.once("SIGINT", stop);
|
|
156
|
-
process.once("SIGTERM", stop);
|
|
157
|
-
process.once("exit", stop);
|
|
158
|
-
if (verbose) {
|
|
159
|
-
process.stderr.write(`Spawned portal server (${portalPackage}) at ${uiDevUrl}\n`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
164
|
-
throw new Error(`Failed to start portal dev server: ${message}`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (options.watch) {
|
|
168
|
-
const cfg = await getConfig();
|
|
169
|
-
const serviceSpecs = Array.isArray(cfg.services) ? cfg.services.map((s) => String(s.spec ?? "")) : [];
|
|
170
|
-
const watchTargets = [
|
|
171
|
-
...(configPath ? [configPath] : []),
|
|
172
|
-
...serviceSpecs.filter(Boolean).map((p) => (isAbsolute(p) ? p : resolve(process.cwd(), p))),
|
|
173
|
-
];
|
|
174
|
-
let timer;
|
|
175
|
-
const scheduleRefresh = () => {
|
|
176
|
-
if (timer)
|
|
177
|
-
clearTimeout(timer);
|
|
178
|
-
timer = setTimeout(() => {
|
|
179
|
-
void refreshSnapshot();
|
|
180
|
-
}, 200);
|
|
181
|
-
};
|
|
182
|
-
for (const target of watchTargets) {
|
|
183
|
-
try {
|
|
184
|
-
watch(target, { persistent: true }, () => scheduleRefresh());
|
|
185
|
-
if (verbose) {
|
|
186
|
-
process.stderr.write(`Watching ${target}\n`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
catch (err) {
|
|
190
|
-
if (verbose) {
|
|
191
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
192
|
-
process.stderr.write(`Failed to watch ${target}: ${message}\n`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
await startDevServer({
|
|
198
|
-
host,
|
|
199
|
-
port,
|
|
200
|
-
getConfig,
|
|
201
|
-
getAggregated,
|
|
202
|
-
verbose,
|
|
203
|
-
mode: "dev",
|
|
204
|
-
configPath,
|
|
205
|
-
workspaceDir,
|
|
206
|
-
ui: options.ui,
|
|
207
|
-
uiDevUrl,
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
//# sourceMappingURL=dev.js.map
|
package/dist/commands/dev.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/start.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0EzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwF3D"}
|
package/dist/commands/start.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
-
import { loadConfig, findConfigPath } from "../config/loadConfig.js";
|
|
6
|
-
import { startDevServer } from "../dev/server.js";
|
|
7
|
-
function resolveConfigSpecPaths(config, baseDir) {
|
|
8
|
-
if (!baseDir)
|
|
9
|
-
return config;
|
|
10
|
-
const services = Array.isArray(config.services) ? config.services : [];
|
|
11
|
-
return {
|
|
12
|
-
...config,
|
|
13
|
-
services: services.map((s) => {
|
|
14
|
-
const spec = String(s?.spec ?? "");
|
|
15
|
-
const resolvedSpec = spec && !isAbsolute(spec) ? resolve(baseDir, spec) : spec;
|
|
16
|
-
return {
|
|
17
|
-
...s,
|
|
18
|
-
spec: resolvedSpec,
|
|
19
|
-
};
|
|
20
|
-
}),
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
async function resolvePortalBin(portalPackage, kind) {
|
|
24
|
-
const require = createRequire(import.meta.url);
|
|
25
|
-
const pkgJsonPath = require.resolve(`${portalPackage}/package.json`);
|
|
26
|
-
const pkgDir = dirname(pkgJsonPath);
|
|
27
|
-
const pkgRaw = await readFile(pkgJsonPath, "utf8");
|
|
28
|
-
const pkg = JSON.parse(pkgRaw);
|
|
29
|
-
if (!pkg.bin)
|
|
30
|
-
return null;
|
|
31
|
-
if (typeof pkg.bin === "string") {
|
|
32
|
-
return join(pkgDir, pkg.bin);
|
|
33
|
-
}
|
|
34
|
-
const entries = Object.entries(pkg.bin);
|
|
35
|
-
if (entries.length === 0)
|
|
36
|
-
return null;
|
|
37
|
-
const preferred = entries.find(([name]) => name.includes(kind)) ?? entries[0];
|
|
38
|
-
return join(pkgDir, preferred[1]);
|
|
39
|
-
}
|
|
40
|
-
async function spawnPortalServer(options) {
|
|
41
|
-
const binPath = await resolvePortalBin(options.portalPackage, options.mode);
|
|
42
|
-
if (!binPath) {
|
|
43
|
-
throw new Error(`Portal package '${options.portalPackage}' does not expose a runnable bin. Expected a package.json "bin" entry.`);
|
|
44
|
-
}
|
|
45
|
-
const args = [binPath, "--port", String(options.port), "--mode", options.mode];
|
|
46
|
-
const child = spawn(process.execPath, args, {
|
|
47
|
-
stdio: options.verbose ? "inherit" : "ignore",
|
|
48
|
-
env: { ...process.env, PORT: String(options.port) },
|
|
49
|
-
});
|
|
50
|
-
child.once("exit", (code) => {
|
|
51
|
-
if (options.verbose) {
|
|
52
|
-
process.stderr.write(`Portal server exited with code ${code ?? "null"}\n`);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
return child;
|
|
56
|
-
}
|
|
57
|
-
export function registerStartCommand(program) {
|
|
58
|
-
program
|
|
59
|
-
.command("start")
|
|
60
|
-
.description("Start a local server (UI + /unispec.json)")
|
|
61
|
-
.option("--config <path>", "Path to unispec config file")
|
|
62
|
-
.option("--host <host>", "Host to bind", "127.0.0.1")
|
|
63
|
-
.option("--port <port>", "Port to bind", "4141")
|
|
64
|
-
.option("--ui", "Serve embedded UI at /", true)
|
|
65
|
-
.option("--no-ui", "Disable embedded UI")
|
|
66
|
-
.option("--ui-url <url>", "Proxy UI requests to an external UI server")
|
|
67
|
-
.option("--portal", "Spawn portal server (SSR) from an installed dependency and proxy UI to it")
|
|
68
|
-
.option("--portal-port <port>", "Port for portal server", "3000")
|
|
69
|
-
.option("--portal-package <name>", "Portal package name", "@unispechq/unispec-portal")
|
|
70
|
-
.action(async function (options) {
|
|
71
|
-
const parentOpts = this.parent?.opts?.();
|
|
72
|
-
const verbose = parentOpts?.verbose ?? false;
|
|
73
|
-
const host = String(options.host ?? "127.0.0.1");
|
|
74
|
-
const port = Number(options.port ?? 4141);
|
|
75
|
-
const configPath = await findConfigPath({ explicitPath: options.config });
|
|
76
|
-
const configDir = configPath ? dirname(configPath) : undefined;
|
|
77
|
-
const workspaceDir = configDir ? join(configDir, ".unispec") : undefined;
|
|
78
|
-
const getConfig = async () => {
|
|
79
|
-
const config = await loadConfig({ explicitPath: options.config });
|
|
80
|
-
return resolveConfigSpecPaths(config ?? { version: 1, services: [] }, configDir);
|
|
81
|
-
};
|
|
82
|
-
let portalChild;
|
|
83
|
-
let uiDevUrl = options.uiUrl;
|
|
84
|
-
if (options.portal) {
|
|
85
|
-
if (uiDevUrl) {
|
|
86
|
-
throw new Error("--portal cannot be used together with --ui-url");
|
|
87
|
-
}
|
|
88
|
-
const portalPort = Number(options.portalPort ?? 3000);
|
|
89
|
-
const portalPackage = String(options.portalPackage ?? "@unispechq/unispec-portal");
|
|
90
|
-
uiDevUrl = `http://127.0.0.1:${portalPort}`;
|
|
91
|
-
portalChild = await spawnPortalServer({
|
|
92
|
-
portalPackage,
|
|
93
|
-
port: portalPort,
|
|
94
|
-
mode: "start",
|
|
95
|
-
verbose,
|
|
96
|
-
});
|
|
97
|
-
const stop = () => {
|
|
98
|
-
try {
|
|
99
|
-
portalChild?.kill("SIGINT");
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
// ignore
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
process.once("SIGINT", stop);
|
|
106
|
-
process.once("SIGTERM", stop);
|
|
107
|
-
process.once("exit", stop);
|
|
108
|
-
if (verbose) {
|
|
109
|
-
process.stderr.write(`Spawned portal server (${portalPackage}) at ${uiDevUrl}\n`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
await startDevServer({
|
|
113
|
-
host,
|
|
114
|
-
port,
|
|
115
|
-
getConfig,
|
|
116
|
-
verbose,
|
|
117
|
-
mode: "start",
|
|
118
|
-
configPath,
|
|
119
|
-
workspaceDir,
|
|
120
|
-
ui: options.ui,
|
|
121
|
-
uiDevUrl: uiDevUrl,
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
//# sourceMappingURL=start.js.map
|