rastack 0.0.55 → 0.0.57
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/CHANGELOG.md +9 -0
- package/admin/AdminApp.tsx +307 -50
- package/admin/ui/DetailsModal.tsx +125 -0
- package/admin/ui/Sidebar.tsx +28 -10
- package/admin/ui/icons.tsx +41 -0
- package/admin/ui/motion.tsx +292 -0
- package/admin/ui/styles.ts +277 -0
- package/admin/useAdmin.ts +91 -0
- package/dist/admin.js +295 -18
- package/dist/compile/index.d.ts +1 -0
- package/dist/compile/index.js +8 -3
- package/dist/compile/run.d.ts +13 -0
- package/dist/compile/run.js +63 -0
- package/dist/deploy/ci.d.ts +8 -1
- package/dist/deploy/ci.js +15 -9
- package/dist/dev/harness.d.ts +44 -13
- package/dist/dev/harness.js +117 -16
- package/dist/rastack-admin.js +2 -9
- package/dist/rastack-ci.js +15 -3
- package/dist/rastack-compile.d.ts +6 -3
- package/dist/rastack-compile.js +10 -16
- package/dist/rastack-dev.d.ts +9 -5
- package/dist/rastack-dev.js +52 -32
- package/dist/rastack-update.js +11 -4
- package/dist/rastack.d.ts +4 -2
- package/dist/rastack.js +17 -6
- package/dist/wasm/rastack_wasm_bg.wasm +0 -0
- package/package.json +7 -7
- package/src/compile/index.ts +13 -4
- package/src/compile/run.ts +26 -0
- package/src/deploy/ci.ts +24 -10
- package/src/dev/harness.ts +121 -15
- package/src/rastack-admin.ts +6 -15
- package/src/rastack-ci.ts +16 -3
- package/src/rastack-compile.ts +10 -18
- package/src/rastack-dev.ts +59 -40
- package/src/rastack-update.ts +11 -4
- package/src/rastack.ts +19 -6
- package/test/deploy.spec.ts +5 -2
- package/test/dev.spec.ts +42 -1
- package/wasm/rastack_wasm_bg.wasm +0 -0
package/src/rastack-admin.ts
CHANGED
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
* falls back to a from-source cargo build.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { execFileSync
|
|
23
|
+
import { execFileSync } from "child_process";
|
|
24
24
|
import * as fs from "fs";
|
|
25
25
|
import * as http from "http";
|
|
26
26
|
import * as path from "path";
|
|
27
|
+
import { runCompile } from "./compile";
|
|
27
28
|
import {
|
|
28
29
|
WASM_ENTRY,
|
|
29
30
|
contentType,
|
|
@@ -34,18 +35,6 @@ import {
|
|
|
34
35
|
|
|
35
36
|
const HERE = __dirname; // dist/ when installed — the bundle lives beside us.
|
|
36
37
|
|
|
37
|
-
/** Compile the resources to schema.rastack.json + openapi.json in outDir. */
|
|
38
|
-
function compile(resourcesDir: string, outDir: string): boolean {
|
|
39
|
-
const compiler = path.join(HERE, "rastack-compile.js");
|
|
40
|
-
const result = spawnSync(
|
|
41
|
-
process.execPath,
|
|
42
|
-
[compiler, "compile", resourcesDir, outDir],
|
|
43
|
-
{ stdio: "inherit" },
|
|
44
|
-
);
|
|
45
|
-
if (result.status !== 0) return false;
|
|
46
|
-
return fs.existsSync(path.join(outDir, "schema.rastack.json"));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
38
|
/** Locate the prebuilt wasm bundle dir shipped in the package (no cargo fallback). */
|
|
50
39
|
function resolveWasmDir(): string | null {
|
|
51
40
|
for (const dir of wasmBundleCandidates(HERE)) {
|
|
@@ -106,9 +95,11 @@ function openBrowser(url: string): void {
|
|
|
106
95
|
function main(argv: string[]): void {
|
|
107
96
|
const args = parseAdminArgs(argv);
|
|
108
97
|
|
|
109
|
-
console.log(
|
|
98
|
+
console.log(
|
|
99
|
+
`\n rastack admin — the database console, built with React API Stack\n`,
|
|
100
|
+
);
|
|
110
101
|
console.log(`▸ Compiling ${args.resourcesDir} → ${args.outDir}`);
|
|
111
|
-
if (!
|
|
102
|
+
if (!runCompile(args.resourcesDir, args.outDir)) {
|
|
112
103
|
console.error(" ✗ compile failed — fix the resource graph and re-run.");
|
|
113
104
|
process.exit(1);
|
|
114
105
|
}
|
package/src/rastack-ci.ts
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { execSync } from "child_process";
|
|
21
|
+
import { runCompile } from "./compile";
|
|
22
|
+
import { DeployConfig } from "./deploy/config";
|
|
21
23
|
import { CiPhase, CiPlanOptions, CiStep, ciPlan } from "./deploy/ci";
|
|
22
24
|
import { loadConfig } from "./deploy/io";
|
|
23
25
|
|
|
@@ -85,13 +87,24 @@ function printPlan(phase: CiPhase, steps: CiStep[]): void {
|
|
|
85
87
|
steps.forEach((s, i) => {
|
|
86
88
|
const at = s.cwd ? ` (in ${s.cwd}/)` : "";
|
|
87
89
|
console.log(` ${i + 1}. ${s.name}${at}`);
|
|
88
|
-
|
|
90
|
+
// In-process steps have no shell command; `run` is a description.
|
|
91
|
+
console.log(` ${s.action ? "» " : "$ "}${s.run}\n`);
|
|
89
92
|
});
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
function runSteps(phase: CiPhase, steps: CiStep[]): void {
|
|
95
|
+
function runSteps(phase: CiPhase, steps: CiStep[], cfg: DeployConfig): void {
|
|
93
96
|
for (const step of steps) {
|
|
94
97
|
console.log(`\n▸ ${step.name}${step.cwd ? ` (in ${step.cwd}/)` : ""}`);
|
|
98
|
+
if (step.action === "compile") {
|
|
99
|
+
// Compilation runs in-process — it lives inside `ci` (and `dev`), not in a
|
|
100
|
+
// separately-invoked `compile` command.
|
|
101
|
+
console.log(` » ${step.run}`);
|
|
102
|
+
if (!runCompile(cfg.resourcesDir, cfg.outDir)) {
|
|
103
|
+
console.error(`\n ✗ step failed: ${step.name}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
95
108
|
console.log(` $ ${step.run}`);
|
|
96
109
|
try {
|
|
97
110
|
// Runs a CI pipeline step derived from the developer's own deploy config
|
|
@@ -123,7 +136,7 @@ function main(argv: string[]): void {
|
|
|
123
136
|
}
|
|
124
137
|
const steps = ciPlan(phase, cfg, opts);
|
|
125
138
|
if (plan) printPlan(phase, steps);
|
|
126
|
-
else runSteps(phase, steps);
|
|
139
|
+
else runSteps(phase, steps, cfg);
|
|
127
140
|
}
|
|
128
141
|
|
|
129
142
|
if (require.main === module) {
|
package/src/rastack-compile.ts
CHANGED
|
@@ -1,40 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* `rastack
|
|
5
|
-
*
|
|
4
|
+
* `rastack check | list | urls` — introspection over the TypeScript-first
|
|
5
|
+
* resource graph.
|
|
6
6
|
*
|
|
7
|
-
* rastack compile [resourcesDir] [outDir] defs → schema.rastack.json + openapi.json
|
|
8
7
|
* rastack check [resourcesDir] validate the resource graph (exit != 0 on error)
|
|
9
8
|
* rastack list [resourcesDir] print every resource + its fields/relations
|
|
10
9
|
* rastack urls [resourcesDir] print the generated /api/{app}/v1/{model}/ routes
|
|
10
|
+
*
|
|
11
|
+
* Compilation itself (defs → schema.rastack.json + openapi.json) is no longer a
|
|
12
|
+
* command here: it runs in-process inside the two modalities of use — `rastack
|
|
13
|
+
* dev`/`admin` (local) and `rastack ci` (deploy) — via the shared `runCompile`.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
import {
|
|
14
17
|
analyzeProject,
|
|
15
18
|
analyzeResources,
|
|
16
19
|
collisions,
|
|
17
|
-
compile,
|
|
18
20
|
urlsFor,
|
|
19
21
|
} from "./compile";
|
|
20
22
|
|
|
21
23
|
const DEFAULT_RESOURCES = "resources";
|
|
22
|
-
const DEFAULT_OUT = ".rastack";
|
|
23
24
|
|
|
24
25
|
function main(argv: string[]): void {
|
|
25
26
|
const [sub, ...rest] = argv;
|
|
26
27
|
|
|
27
28
|
switch (sub) {
|
|
28
|
-
case "compile": {
|
|
29
|
-
const resourcesDir = rest[0] || DEFAULT_RESOURCES;
|
|
30
|
-
const outDir = rest[1] || DEFAULT_OUT;
|
|
31
|
-
const result = compile(resourcesDir, outDir);
|
|
32
|
-
for (const d of result.diagnostics) console.warn(` ⚠ ${d.message}`);
|
|
33
|
-
console.log(
|
|
34
|
-
`✓ compiled ${result.manifest.resources.length} resource(s) → ${result.files.join(", ")}`,
|
|
35
|
-
);
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
29
|
case "check": {
|
|
39
30
|
const { resources, diagnostics } = analyzeProject(
|
|
40
31
|
rest[0] || DEFAULT_RESOURCES,
|
|
@@ -65,7 +56,9 @@ function main(argv: string[]): void {
|
|
|
65
56
|
for (const r of resources) {
|
|
66
57
|
console.log(`${r.app}.${r.model}`);
|
|
67
58
|
for (const f of r.fields) {
|
|
68
|
-
const rel = f.relation
|
|
59
|
+
const rel = f.relation
|
|
60
|
+
? ` → ${f.relation.app}.${f.relation.model}`
|
|
61
|
+
: "";
|
|
69
62
|
console.log(` ${f.name}: ${f.type}${rel}`);
|
|
70
63
|
}
|
|
71
64
|
if (r.sync) {
|
|
@@ -89,9 +82,8 @@ function main(argv: string[]): void {
|
|
|
89
82
|
}
|
|
90
83
|
default:
|
|
91
84
|
console.error(
|
|
92
|
-
`Unknown
|
|
85
|
+
`Unknown subcommand: "${sub}"\n\n` +
|
|
93
86
|
`Usage:\n` +
|
|
94
|
-
` rastack compile [resourcesDir] [outDir]\n` +
|
|
95
87
|
` rastack check [resourcesDir]\n` +
|
|
96
88
|
` rastack list [resourcesDir]\n` +
|
|
97
89
|
` rastack urls [resourcesDir]\n`,
|
package/src/rastack-dev.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* `rastack dev` — local development
|
|
4
|
+
* `rastack dev` — local development of **your app**, always over the WASM engine.
|
|
5
5
|
*
|
|
6
|
-
* rastack dev [resourcesDir] [--port <n>] [--warehouse <dir>] [--out <dir>] [--no-open]
|
|
6
|
+
* rastack dev [resourcesDir] [--port <n>] [--warehouse <dir>] [--out <dir>] [--app <dir>] [--no-open]
|
|
7
7
|
*
|
|
8
8
|
* Compiles the resources, then boots a dependency-free static server (à la
|
|
9
|
-
* `rastack design`) that hands the browser everything it needs to run the
|
|
10
|
-
*
|
|
11
|
-
* • the
|
|
9
|
+
* `rastack design`) that hands the browser everything it needs to run the
|
|
10
|
+
* developer's own app locally over WebAssembly — no native server, no cargo:
|
|
11
|
+
* • the developer's app (`index.html` from the resolved app root), or a
|
|
12
|
+
* Django-style welcome page when the project has no app yet,
|
|
12
13
|
* • the prebuilt WASM engine (`/wasm/…`) shipped in the package,
|
|
13
14
|
* • the compiled `schema.rastack.json` / `openapi.json`,
|
|
14
15
|
* • the committed Iceberg warehouse (`/data/warehouse/…`) to seed from.
|
|
15
16
|
*
|
|
17
|
+
* It does **not** serve the admin console — that is a separate command,
|
|
18
|
+
* `rastack admin`.
|
|
19
|
+
*
|
|
16
20
|
* The engine is resolved from the package's prebuilt bundle; if none is present
|
|
17
21
|
* but a Rust + wasm toolchain is, it is built from source as a fallback.
|
|
18
22
|
*/
|
|
@@ -21,39 +25,36 @@ import { execFileSync, spawnSync } from "child_process";
|
|
|
21
25
|
import * as fs from "fs";
|
|
22
26
|
import * as http from "http";
|
|
23
27
|
import * as path from "path";
|
|
28
|
+
import { runCompile } from "./compile";
|
|
24
29
|
import {
|
|
30
|
+
APP_ENTRY,
|
|
25
31
|
WASM_ENTRY,
|
|
32
|
+
appRootCandidates,
|
|
26
33
|
contentType,
|
|
27
34
|
parseDevArgs,
|
|
28
|
-
|
|
35
|
+
renderWelcome,
|
|
29
36
|
wasmBundleCandidates,
|
|
30
37
|
} from "./dev/harness";
|
|
31
38
|
|
|
32
39
|
const HERE = __dirname; // dist/ when installed
|
|
33
40
|
|
|
34
|
-
/** Compile the resources to schema.rastack.json + openapi.json in outDir. */
|
|
35
|
-
function compile(resourcesDir: string, outDir: string): boolean {
|
|
36
|
-
const compiler = path.join(HERE, "rastack-compile.js");
|
|
37
|
-
const result = spawnSync(
|
|
38
|
-
process.execPath,
|
|
39
|
-
[compiler, "compile", resourcesDir, outDir],
|
|
40
|
-
{ stdio: "inherit" },
|
|
41
|
-
);
|
|
42
|
-
if (result.status !== 0) return false;
|
|
43
|
-
return fs.existsSync(path.join(outDir, "schema.rastack.json"));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
41
|
/** True when `cargo` is on PATH (the from-source wasm fallback needs it). */
|
|
47
42
|
function cargoAvailable(): boolean {
|
|
48
43
|
try {
|
|
49
|
-
return (
|
|
50
|
-
spawnSync("cargo", ["--version"], { stdio: "ignore" }).status === 0
|
|
51
|
-
);
|
|
44
|
+
return spawnSync("cargo", ["--version"], { stdio: "ignore" }).status === 0;
|
|
52
45
|
} catch {
|
|
53
46
|
return false;
|
|
54
47
|
}
|
|
55
48
|
}
|
|
56
49
|
|
|
50
|
+
/** First app-root candidate that holds an `index.html`, or null (→ welcome). */
|
|
51
|
+
function resolveAppRoot(appDir: string): string | null {
|
|
52
|
+
for (const dir of appRootCandidates(appDir)) {
|
|
53
|
+
if (fs.existsSync(path.join(dir, APP_ENTRY))) return dir;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
57
58
|
/** Locate the prebuilt wasm bundle dir, building from source as a fallback. */
|
|
58
59
|
function resolveWasmDir(): string | null {
|
|
59
60
|
for (const dir of wasmBundleCandidates(HERE)) {
|
|
@@ -130,9 +131,9 @@ function openBrowser(url: string): void {
|
|
|
130
131
|
function main(argv: string[]): void {
|
|
131
132
|
const args = parseDevArgs(argv);
|
|
132
133
|
|
|
133
|
-
console.log(`\n rastack dev —
|
|
134
|
+
console.log(`\n rastack dev — your app, in your browser over WASM\n`);
|
|
134
135
|
console.log(`▸ Compiling ${args.resourcesDir} → ${args.outDir}`);
|
|
135
|
-
if (!
|
|
136
|
+
if (!runCompile(args.resourcesDir, args.outDir)) {
|
|
136
137
|
console.error(" ✗ compile failed — fix the resource graph and re-run.");
|
|
137
138
|
process.exit(1);
|
|
138
139
|
}
|
|
@@ -149,13 +150,8 @@ function main(argv: string[]): void {
|
|
|
149
150
|
process.exit(1);
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
console.error(
|
|
155
|
-
" ✗ admin bundle (dist/admin.js) not found — reinstall rastack.",
|
|
156
|
-
);
|
|
157
|
-
process.exit(1);
|
|
158
|
-
}
|
|
153
|
+
// Serve the developer's own app when there is one; otherwise the welcome page.
|
|
154
|
+
const appRoot = resolveAppRoot(args.appDir);
|
|
159
155
|
|
|
160
156
|
const server = http.createServer((req, res) => {
|
|
161
157
|
const url = (req.url || "/").split("?")[0];
|
|
@@ -163,13 +159,7 @@ function main(argv: string[]): void {
|
|
|
163
159
|
res.writeHead(405).end("Method not allowed");
|
|
164
160
|
return;
|
|
165
161
|
}
|
|
166
|
-
|
|
167
|
-
res
|
|
168
|
-
.writeHead(200, { "Content-Type": "text/html; charset=utf-8" })
|
|
169
|
-
.end(renderShell());
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (url === "/dev/admin.js") return serveFile(res, adminBundle);
|
|
162
|
+
// Reserved backend routes always win over the app's static files.
|
|
173
163
|
if (url.startsWith("/wasm/"))
|
|
174
164
|
return serveUnder(res, wasmDir, url.slice("/wasm/".length));
|
|
175
165
|
if (url === "/schema.rastack.json" || url === "/openapi.json")
|
|
@@ -180,14 +170,43 @@ function main(argv: string[]): void {
|
|
|
180
170
|
args.warehouseDir,
|
|
181
171
|
url.slice("/data/warehouse/".length),
|
|
182
172
|
);
|
|
183
|
-
|
|
173
|
+
|
|
174
|
+
// No app → the Django-style welcome page (root only; else 404).
|
|
175
|
+
if (!appRoot) {
|
|
176
|
+
if (url === "/" || url === "/index.html") {
|
|
177
|
+
res
|
|
178
|
+
.writeHead(200, { "Content-Type": "text/html; charset=utf-8" })
|
|
179
|
+
.end(renderWelcome());
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
res.writeHead(404).end("Not found");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Serve the app: its index.html at `/`, an existing file as-is, and any
|
|
187
|
+
// other route back to index.html (SPA client-side routing).
|
|
188
|
+
if (url === "/" || url === "/index.html")
|
|
189
|
+
return serveFile(res, path.join(appRoot, APP_ENTRY));
|
|
190
|
+
const rel = decodeURIComponent(url).replace(/^\/+/, "");
|
|
191
|
+
const target = path.resolve(appRoot, rel);
|
|
192
|
+
const safeRoot = path.resolve(appRoot);
|
|
193
|
+
const inRoot =
|
|
194
|
+
target === safeRoot || target.startsWith(safeRoot + path.sep);
|
|
195
|
+
if (inRoot && fs.existsSync(target) && fs.statSync(target).isFile())
|
|
196
|
+
return serveFile(res, target);
|
|
197
|
+
return serveFile(res, path.join(appRoot, APP_ENTRY));
|
|
184
198
|
});
|
|
185
199
|
|
|
186
200
|
server.listen(args.port, () => {
|
|
187
201
|
const url = `http://localhost:${args.port}`;
|
|
188
202
|
console.log(` ✓ WASM engine: ${path.relative(process.cwd(), wasmDir)}`);
|
|
189
|
-
|
|
190
|
-
|
|
203
|
+
if (appRoot)
|
|
204
|
+
console.log(` ✓ app: ${path.relative(process.cwd(), appRoot) || "."}`);
|
|
205
|
+
else console.log(` ○ no app found — serving the welcome page`);
|
|
206
|
+
console.log(`\n ▸ ${url}\n`);
|
|
207
|
+
console.log(
|
|
208
|
+
" Need the database console? Run `rastack admin`. Ctrl+C to stop.\n",
|
|
209
|
+
);
|
|
191
210
|
if (args.open) openBrowser(url);
|
|
192
211
|
});
|
|
193
212
|
}
|
package/src/rastack-update.ts
CHANGED
|
@@ -64,10 +64,17 @@ function runNpm(
|
|
|
64
64
|
args: string[],
|
|
65
65
|
opts: { stdio: "inherit" | ["ignore", "pipe", "pipe"]; env?: NodeJS.ProcessEnv },
|
|
66
66
|
): Buffer | null {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
if (NPM_SHELL) {
|
|
68
|
+
// Windows: launch the `npm.cmd` shim through a shell (a bare `.cmd` spawn is
|
|
69
|
+
// rejected with EINVAL since the Node CVE-2024-27980 fix). The only
|
|
70
|
+
// non-literal token — the version — is sanitized in `parseUpdateFlags`, and
|
|
71
|
+
// every other arg is a fixed literal, so nothing injectable reaches it. The
|
|
72
|
+
// nosemgrep must sit on the line directly above the `execSync` call for the
|
|
73
|
+
// engine to honour it.
|
|
74
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
75
|
+
return execSync(npmShellCommand(NPM, args), opts);
|
|
76
|
+
}
|
|
77
|
+
return execFileSync(NPM, args, opts);
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
/** Capture `npm <args>` stdout, or null when npm is absent / the call fails. */
|
package/src/rastack.ts
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* rastack — unified CLI for React API Stack
|
|
5
5
|
*
|
|
6
|
+
* Compilation is not a command of its own: it runs in-process inside the two
|
|
7
|
+
* modalities of use — `rastack dev`/`admin` (local) and `rastack ci` (deploy).
|
|
8
|
+
*
|
|
6
9
|
* Commands:
|
|
7
|
-
* rastack compile [resourcesDir] [outDir] TypeScript resources → schema.rastack.json + openapi.json
|
|
8
10
|
* rastack check [resourcesDir] Validate the resource graph
|
|
9
11
|
* rastack list [resourcesDir] Print resources, fields and relations
|
|
10
12
|
* rastack urls [resourcesDir] Print the generated /api/{app}/v1/{model}/ routes
|
|
11
13
|
* rastack generate [--schema-only] Generate typed hooks from OpenAPI
|
|
12
14
|
* rastack tokens [input] [outDir] Compile design tokens → CSS vars + typed theme
|
|
13
15
|
* rastack design [input] [--port n] Live design-system studio (showcase + edit)
|
|
14
|
-
* rastack dev [--port n] [--warehouse d] Local dev: run
|
|
16
|
+
* rastack dev [--port n] [--warehouse d] Local dev: run your app in-browser over WASM
|
|
15
17
|
* rastack admin [--warehouse dir] [--port n] Full admin console — React UI (rastack/components) over the native server
|
|
16
18
|
* rastack import <file> --resource app.model Load CSV/XLSX/PDF data and validate it (state machine)
|
|
17
19
|
* rastack scan [files...] [--fail-on-pii] Scan CSVs for PII and schema info
|
|
@@ -65,6 +67,17 @@ switch (command) {
|
|
|
65
67
|
printVersion();
|
|
66
68
|
break;
|
|
67
69
|
case "compile":
|
|
70
|
+
// Compilation is no longer a standalone command — it runs in-process as
|
|
71
|
+
// part of the two modalities of use. Point the way rather than 404.
|
|
72
|
+
console.error(
|
|
73
|
+
"`rastack compile` has been removed — compilation now runs automatically\n" +
|
|
74
|
+
"inside the two modalities of use:\n" +
|
|
75
|
+
" • rastack dev local development (compiles, then serves over WASM)\n" +
|
|
76
|
+
" • rastack ci the deploy pipeline (compiles the manifest + OpenAPI)\n\n" +
|
|
77
|
+
"Introspect the resource graph with: rastack check | list | urls\n",
|
|
78
|
+
);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
break;
|
|
68
81
|
case "check":
|
|
69
82
|
case "list":
|
|
70
83
|
case "urls":
|
|
@@ -72,8 +85,9 @@ switch (command) {
|
|
|
72
85
|
run("rastack-compile.js", [command, ...rest]);
|
|
73
86
|
break;
|
|
74
87
|
case "dev":
|
|
75
|
-
// Local development: serve
|
|
76
|
-
//
|
|
88
|
+
// Local development: serve your app in the browser over the WASM engine
|
|
89
|
+
// (no native server, no cargo). The admin console is a separate command,
|
|
90
|
+
// `rastack admin`. Replaces `serve` + `wasm`.
|
|
77
91
|
run("rastack-dev.js", rest);
|
|
78
92
|
break;
|
|
79
93
|
case "admin":
|
|
@@ -134,12 +148,11 @@ switch (command) {
|
|
|
134
148
|
console.error(
|
|
135
149
|
`Unknown command: "${command}"\n\n` +
|
|
136
150
|
`Usage:\n` +
|
|
137
|
-
` rastack compile [resourcesDir] [outDir]\n` +
|
|
138
151
|
` rastack check | list | urls [resourcesDir]\n` +
|
|
139
152
|
` rastack generate [--schema-only]\n` +
|
|
140
153
|
` rastack tokens [input] [outDir] [--prefix p] Compile design tokens → CSS vars + typed theme\n` +
|
|
141
154
|
` rastack design [input] [--port n] Live design-system studio (showcase + edit)\n` +
|
|
142
|
-
` rastack dev [--port n] [--warehouse dir] [--no-open] Run
|
|
155
|
+
` rastack dev [--port n] [--warehouse dir] [--app dir] [--no-open] Run your app in-browser over WASM (local dev)\n` +
|
|
143
156
|
` rastack admin [--warehouse dir] [--port n] [--no-open] Full admin console (React UI over the native server; needs a built rastack-server)\n` +
|
|
144
157
|
` rastack import <file.csv|.xlsx|.pdf> --resource app.model [--related app.model=<file>] [--out cleaned.json]\n` +
|
|
145
158
|
` rastack scan [files...] [--fail-on-pii]\n` +
|
package/test/deploy.spec.ts
CHANGED
|
@@ -419,12 +419,15 @@ describe("repo variables + lambda env", () => {
|
|
|
419
419
|
});
|
|
420
420
|
|
|
421
421
|
describe("ci plan — check", () => {
|
|
422
|
-
it("validates then compiles, honouring the resources dir + bin", () => {
|
|
422
|
+
it("validates then compiles in-process, honouring the resources dir + bin", () => {
|
|
423
423
|
const steps = checkSteps(base({ resourcesDir: "res" }), "npx rastack");
|
|
424
424
|
expect(steps.map((s) => s.run)).toEqual([
|
|
425
425
|
"npx rastack check res",
|
|
426
|
-
"
|
|
426
|
+
"compile res .rastack (in-process)",
|
|
427
427
|
]);
|
|
428
|
+
// The compile step runs in-process (no shell command), so the CLI can drop
|
|
429
|
+
// the standalone `compile` command entirely.
|
|
430
|
+
expect(steps[1].action).toBe("compile");
|
|
428
431
|
expect(ciPlan("check", base(), { bin: "rastack" })).toEqual(
|
|
429
432
|
checkSteps(base(), "rastack"),
|
|
430
433
|
);
|
package/test/dev.spec.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ADMIN_DEFAULTS,
|
|
3
|
+
APP_ENTRY,
|
|
3
4
|
DEV_DEFAULTS,
|
|
4
5
|
WASM_ENTRY,
|
|
6
|
+
appRootCandidates,
|
|
5
7
|
contentType,
|
|
6
8
|
parseAdminArgs,
|
|
7
9
|
parseDevArgs,
|
|
8
10
|
renderShell,
|
|
11
|
+
renderWelcome,
|
|
9
12
|
wasmBundleCandidates,
|
|
10
13
|
} from "../src/dev/harness";
|
|
11
14
|
import {
|
|
@@ -57,6 +60,7 @@ describe("rastack dev — arg parsing", () => {
|
|
|
57
60
|
resourcesDir: "app/resources",
|
|
58
61
|
outDir: "build",
|
|
59
62
|
warehouseDir: "data/wh",
|
|
63
|
+
appDir: "",
|
|
60
64
|
port: 5000,
|
|
61
65
|
open: false,
|
|
62
66
|
});
|
|
@@ -114,7 +118,7 @@ describe("rastack dev — wasm bundle resolution", () => {
|
|
|
114
118
|
});
|
|
115
119
|
});
|
|
116
120
|
|
|
117
|
-
describe("rastack
|
|
121
|
+
describe("rastack admin — HTML shell", () => {
|
|
118
122
|
it("mounts #root and loads the bundled admin", () => {
|
|
119
123
|
const html = renderShell();
|
|
120
124
|
expect(html).toContain('<div id="root">');
|
|
@@ -123,6 +127,43 @@ describe("rastack dev — HTML shell", () => {
|
|
|
123
127
|
});
|
|
124
128
|
});
|
|
125
129
|
|
|
130
|
+
describe("rastack dev — app resolution", () => {
|
|
131
|
+
it("defaults appDir to empty (probe the conventional roots)", () => {
|
|
132
|
+
expect(DEV_DEFAULTS.appDir).toBe("");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("reads --app as an explicit app root", () => {
|
|
136
|
+
expect(parseDevArgs(["--app", "site"]).appDir).toBe("site");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("probes public/www/app/root when no --app is given", () => {
|
|
140
|
+
const dirs = appRootCandidates("", "/repo");
|
|
141
|
+
expect(dirs).toEqual([
|
|
142
|
+
"/repo/public",
|
|
143
|
+
"/repo/www",
|
|
144
|
+
"/repo/app",
|
|
145
|
+
"/repo",
|
|
146
|
+
]);
|
|
147
|
+
expect(APP_ENTRY).toBe("index.html");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("uses only the explicit --app dir when set", () => {
|
|
151
|
+
expect(appRootCandidates("site", "/repo")).toEqual(["/repo/site"]);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe("rastack dev — welcome page (no app)", () => {
|
|
156
|
+
it("is a self-contained page pointing at the backend and admin", () => {
|
|
157
|
+
const html = renderWelcome();
|
|
158
|
+
expect(html.startsWith("<!doctype html>")).toBe(true);
|
|
159
|
+
// Django-style "it worked" confirmation, not the admin bundle.
|
|
160
|
+
expect(html).not.toContain("/dev/admin.js");
|
|
161
|
+
expect(html).toContain("dev server is running");
|
|
162
|
+
expect(html).toContain("/schema.rastack.json");
|
|
163
|
+
expect(html).toContain("rastack admin");
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
126
167
|
// -- admin adapters ---------------------------------------------------------
|
|
127
168
|
|
|
128
169
|
/** The in-repo airline fixtures, in manifest JSON shape. */
|
|
Binary file
|