rastack 0.0.44 → 0.0.46
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 +311 -158
- package/admin/adapters.ts +99 -0
- package/admin/httpEngine.ts +56 -0
- package/admin/index.tsx +91 -39
- package/admin/ui/FilterBar.tsx +231 -0
- package/admin/ui/Popover.tsx +54 -0
- package/admin/ui/Sidebar.tsx +86 -0
- package/admin/ui/icons.tsx +146 -0
- package/admin/ui/styles.ts +398 -0
- package/admin/useAdmin.ts +149 -14
- package/dist/admin.js +395 -17
- package/dist/dev/harness.d.ts +17 -0
- package/dist/dev/harness.js +39 -1
- package/dist/rastack-admin.d.ts +14 -0
- package/dist/rastack-admin.js +128 -0
- package/dist/rastack.d.ts +1 -1
- package/dist/rastack.js +7 -23
- package/dist/wasm/rastack_wasm.js +1 -1
- package/dist/wasm/rastack_wasm_bg.wasm +0 -0
- package/package.json +1 -1
- package/src/dev/harness.ts +44 -0
- package/src/rastack-admin.ts +112 -0
- package/src/rastack.ts +8 -28
- package/test/dev.spec.ts +96 -0
- package/wasm/rastack_wasm.js +1 -1
- package/wasm/rastack_wasm_bg.wasm +0 -0
package/dist/dev/harness.d.ts
CHANGED
|
@@ -30,6 +30,23 @@ export declare const DEV_DEFAULTS: DevArgs;
|
|
|
30
30
|
* single positional resources dir. Unknown flags are ignored (forgiving CLI).
|
|
31
31
|
*/
|
|
32
32
|
export declare function parseDevArgs(argv: string[]): DevArgs;
|
|
33
|
+
/** Args for `rastack admin` — like `DevArgs`, but bound to a real server port. */
|
|
34
|
+
export interface AdminArgs {
|
|
35
|
+
resourcesDir: string;
|
|
36
|
+
outDir: string;
|
|
37
|
+
warehouseDir: string;
|
|
38
|
+
/** TCP port the native `rastack-server` binds (the admin lives at `/admin/`). */
|
|
39
|
+
port: number;
|
|
40
|
+
open: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare const ADMIN_DEFAULTS: AdminArgs;
|
|
43
|
+
/**
|
|
44
|
+
* Parse `rastack admin` args: `--port`, `--warehouse`, `--out`, `--no-open`, and
|
|
45
|
+
* a single positional resources dir. Mirrors `parseDevArgs` but defaults to the
|
|
46
|
+
* server's port 8000 (the React admin is served by the native server, not a
|
|
47
|
+
* node static server).
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseAdminArgs(argv: string[]): AdminArgs;
|
|
33
50
|
/** MIME type for a served path, defaulting to octet-stream (Iceberg data files). */
|
|
34
51
|
export declare function contentType(filePath: string): string;
|
|
35
52
|
/**
|
package/dist/dev/harness.js
CHANGED
|
@@ -47,8 +47,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
47
47
|
};
|
|
48
48
|
})();
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.WASM_ENTRY = exports.DEV_DEFAULTS = void 0;
|
|
50
|
+
exports.WASM_ENTRY = exports.ADMIN_DEFAULTS = exports.DEV_DEFAULTS = void 0;
|
|
51
51
|
exports.parseDevArgs = parseDevArgs;
|
|
52
|
+
exports.parseAdminArgs = parseAdminArgs;
|
|
52
53
|
exports.contentType = contentType;
|
|
53
54
|
exports.wasmBundleCandidates = wasmBundleCandidates;
|
|
54
55
|
exports.renderShell = renderShell;
|
|
@@ -88,6 +89,43 @@ function parseDevArgs(argv) {
|
|
|
88
89
|
open,
|
|
89
90
|
};
|
|
90
91
|
}
|
|
92
|
+
exports.ADMIN_DEFAULTS = {
|
|
93
|
+
resourcesDir: "resources",
|
|
94
|
+
outDir: ".rastack",
|
|
95
|
+
warehouseDir: "data/warehouse",
|
|
96
|
+
port: 8000,
|
|
97
|
+
open: true,
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Parse `rastack admin` args: `--port`, `--warehouse`, `--out`, `--no-open`, and
|
|
101
|
+
* a single positional resources dir. Mirrors `parseDevArgs` but defaults to the
|
|
102
|
+
* server's port 8000 (the React admin is served by the native server, not a
|
|
103
|
+
* node static server).
|
|
104
|
+
*/
|
|
105
|
+
function parseAdminArgs(argv) {
|
|
106
|
+
const positional = [];
|
|
107
|
+
let { resourcesDir, outDir, warehouseDir, port, open } = exports.ADMIN_DEFAULTS;
|
|
108
|
+
for (let i = 0; i < argv.length; i++) {
|
|
109
|
+
const a = argv[i];
|
|
110
|
+
if (a === "--port")
|
|
111
|
+
port = Number(argv[++i]) || port;
|
|
112
|
+
else if (a === "--warehouse")
|
|
113
|
+
warehouseDir = argv[++i] ?? warehouseDir;
|
|
114
|
+
else if (a === "--out")
|
|
115
|
+
outDir = argv[++i] ?? outDir;
|
|
116
|
+
else if (a === "--no-open")
|
|
117
|
+
open = false;
|
|
118
|
+
else if (!a.startsWith("-"))
|
|
119
|
+
positional.push(a);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
resourcesDir: positional[0] || resourcesDir,
|
|
123
|
+
outDir,
|
|
124
|
+
warehouseDir,
|
|
125
|
+
port,
|
|
126
|
+
open,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
91
129
|
const MIME = {
|
|
92
130
|
".html": "text/html; charset=utf-8",
|
|
93
131
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `rastack admin` — the full, Django-admin-style console, served by the native
|
|
4
|
+
* `rastack-server` against the real Iceberg warehouse.
|
|
5
|
+
*
|
|
6
|
+
* rastack admin [resourcesDir] [--warehouse <dir>] [--port <n>] [--out <dir>] [--no-open]
|
|
7
|
+
*
|
|
8
|
+
* Unlike the old server-rendered `/admin`, the console is React API Stack's own
|
|
9
|
+
* React admin (`tools/admin`, built from `rastack/components` + `rastack/theme`)
|
|
10
|
+
* — this command compiles the resources, points the server at the prebuilt
|
|
11
|
+
* bundle (`RASTACK_ADMIN_ASSETS`), and boots it. The bundle talks back to the
|
|
12
|
+
* same server's `/api` over HTTP, so edits persist to the real warehouse.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* `rastack admin` — the full, Django-admin-style console, served by the native
|
|
5
|
+
* `rastack-server` against the real Iceberg warehouse.
|
|
6
|
+
*
|
|
7
|
+
* rastack admin [resourcesDir] [--warehouse <dir>] [--port <n>] [--out <dir>] [--no-open]
|
|
8
|
+
*
|
|
9
|
+
* Unlike the old server-rendered `/admin`, the console is React API Stack's own
|
|
10
|
+
* React admin (`tools/admin`, built from `rastack/components` + `rastack/theme`)
|
|
11
|
+
* — this command compiles the resources, points the server at the prebuilt
|
|
12
|
+
* bundle (`RASTACK_ADMIN_ASSETS`), and boots it. The bundle talks back to the
|
|
13
|
+
* same server's `/api` over HTTP, so edits persist to the real warehouse.
|
|
14
|
+
*/
|
|
15
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(o, k2, desc);
|
|
22
|
+
}) : (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
}));
|
|
26
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
27
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
28
|
+
}) : function(o, v) {
|
|
29
|
+
o["default"] = v;
|
|
30
|
+
});
|
|
31
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
32
|
+
var ownKeys = function(o) {
|
|
33
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
34
|
+
var ar = [];
|
|
35
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
36
|
+
return ar;
|
|
37
|
+
};
|
|
38
|
+
return ownKeys(o);
|
|
39
|
+
};
|
|
40
|
+
return function (mod) {
|
|
41
|
+
if (mod && mod.__esModule) return mod;
|
|
42
|
+
var result = {};
|
|
43
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
44
|
+
__setModuleDefault(result, mod);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
})();
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
const child_process_1 = require("child_process");
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const harness_1 = require("./dev/harness");
|
|
53
|
+
const HERE = __dirname; // dist/ when installed — the bundle lives beside us.
|
|
54
|
+
/** Compile the resources to schema.rastack.json + openapi.json in outDir. */
|
|
55
|
+
function compile(resourcesDir, outDir) {
|
|
56
|
+
const compiler = path.join(HERE, "rastack-compile.js");
|
|
57
|
+
const result = (0, child_process_1.spawnSync)(process.execPath, [compiler, "compile", resourcesDir, outDir], { stdio: "inherit" });
|
|
58
|
+
if (result.status !== 0)
|
|
59
|
+
return false;
|
|
60
|
+
return fs.existsSync(path.join(outDir, "schema.rastack.json"));
|
|
61
|
+
}
|
|
62
|
+
/** Best-effort open the default browser at `url`. */
|
|
63
|
+
function openBrowser(url) {
|
|
64
|
+
const cmd = process.platform === "darwin"
|
|
65
|
+
? "open"
|
|
66
|
+
: process.platform === "win32"
|
|
67
|
+
? "start"
|
|
68
|
+
: "xdg-open";
|
|
69
|
+
try {
|
|
70
|
+
(0, child_process_1.execFileSync)(cmd, [url], { stdio: "ignore" });
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
/* non-fatal — the URL is printed anyway */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function main(argv) {
|
|
77
|
+
const args = (0, harness_1.parseAdminArgs)(argv);
|
|
78
|
+
console.log(`\n rastack admin — the database console, built with React API Stack\n`);
|
|
79
|
+
console.log(`▸ Compiling ${args.resourcesDir} → ${args.outDir}`);
|
|
80
|
+
if (!compile(args.resourcesDir, args.outDir)) {
|
|
81
|
+
console.error(" ✗ compile failed — fix the resource graph and re-run.");
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
const bundle = path.join(HERE, "admin.js");
|
|
85
|
+
if (!fs.existsSync(bundle)) {
|
|
86
|
+
console.error(" ✗ admin bundle (dist/admin.js) not found — reinstall rastack.");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const repoRoot = path.resolve(HERE, "..", "..");
|
|
90
|
+
const binary = process.env.RASTACK_SERVER_BIN ||
|
|
91
|
+
path.join(repoRoot, "rust", "target", "release", "rastack-server");
|
|
92
|
+
const manifest = path.join(args.outDir, "schema.rastack.json");
|
|
93
|
+
const serverArgs = [
|
|
94
|
+
"admin",
|
|
95
|
+
"--manifest",
|
|
96
|
+
manifest,
|
|
97
|
+
"--warehouse",
|
|
98
|
+
args.warehouseDir,
|
|
99
|
+
"--addr",
|
|
100
|
+
`127.0.0.1:${args.port}`,
|
|
101
|
+
// Local dev context: the admin runs unauthenticated, exactly like the old
|
|
102
|
+
// native admin. Production admins run the server with --jwks/--admin-group.
|
|
103
|
+
"--insecure-dev-auth",
|
|
104
|
+
];
|
|
105
|
+
const url = `http://127.0.0.1:${args.port}/admin/`;
|
|
106
|
+
// The server serves the React bundle from here; hand the path via env so the
|
|
107
|
+
// Rust side stays free of JS-toolchain knowledge.
|
|
108
|
+
const child = (0, child_process_1.spawn)(binary, serverArgs, {
|
|
109
|
+
stdio: "inherit",
|
|
110
|
+
env: { ...process.env, RASTACK_ADMIN_ASSETS: HERE },
|
|
111
|
+
});
|
|
112
|
+
child.on("error", () => {
|
|
113
|
+
console.error(` ✗ Could not run the Rust server (${binary}). Build it first:\n` +
|
|
114
|
+
` cd rust && cargo build --release\n`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
117
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
118
|
+
// Give the server a moment to bind, then print + open.
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
console.log(`\n ▸ ${url}\n`);
|
|
121
|
+
console.log(" Press Ctrl+C to stop.\n");
|
|
122
|
+
if (args.open)
|
|
123
|
+
openBrowser(url);
|
|
124
|
+
}, 700);
|
|
125
|
+
}
|
|
126
|
+
if (require.main === module) {
|
|
127
|
+
main(process.argv.slice(2));
|
|
128
|
+
}
|
package/dist/rastack.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* rastack tokens [input] [outDir] Compile design tokens → CSS vars + typed theme
|
|
12
12
|
* rastack design [input] [--port n] Live design-system studio (showcase + edit)
|
|
13
13
|
* rastack dev [--port n] [--warehouse d] Local dev: run the app + admin in-browser over WASM
|
|
14
|
-
* rastack admin [--warehouse dir]
|
|
14
|
+
* rastack admin [--warehouse dir] [--port n] Full admin console — React UI (rastack/components) over the native server
|
|
15
15
|
* rastack scan [files...] [--fail-on-pii] Scan CSVs for PII and schema info
|
|
16
16
|
* rastack seed [--env dev] [--source gs://] Load CSVs into Iceberg namespace
|
|
17
17
|
* rastack bootstrap [--owner o] [--repo r] Stand the tier-0 AWS account stack up (once per account+region)
|
package/dist/rastack.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* rastack tokens [input] [outDir] Compile design tokens → CSS vars + typed theme
|
|
13
13
|
* rastack design [input] [--port n] Live design-system studio (showcase + edit)
|
|
14
14
|
* rastack dev [--port n] [--warehouse d] Local dev: run the app + admin in-browser over WASM
|
|
15
|
-
* rastack admin [--warehouse dir]
|
|
15
|
+
* rastack admin [--warehouse dir] [--port n] Full admin console — React UI (rastack/components) over the native server
|
|
16
16
|
* rastack scan [files...] [--fail-on-pii] Scan CSVs for PII and schema info
|
|
17
17
|
* rastack seed [--env dev] [--source gs://] Load CSVs into Iceberg namespace
|
|
18
18
|
* rastack bootstrap [--owner o] [--repo r] Stand the tier-0 AWS account stack up (once per account+region)
|
|
@@ -56,26 +56,6 @@ function run(script, args = rest) {
|
|
|
56
56
|
process.exit(err.status ?? 1);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
/** Invoke the compiled Rust server binary (built by `cargo build` in rust/). */
|
|
60
|
-
function runRust(subcommand) {
|
|
61
|
-
const repoRoot = path_1.default.resolve(__dirname, "..", "..");
|
|
62
|
-
const binary = process.env.RASTACK_SERVER_BIN ||
|
|
63
|
-
path_1.default.join(repoRoot, "rust", "target", "release", "rastack-server");
|
|
64
|
-
// Runs the locally-built Rust server binary with a fixed internal subcommand
|
|
65
|
-
// ("serve"/"admin"); `rest` is the developer's own CLI args, not untrusted
|
|
66
|
-
// input — no command-injection surface.
|
|
67
|
-
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
68
|
-
const result = (0, child_process_1.spawnSync)(binary, [subcommand, ...rest], {
|
|
69
|
-
stdio: "inherit",
|
|
70
|
-
env: process.env,
|
|
71
|
-
});
|
|
72
|
-
if (result.error) {
|
|
73
|
-
console.error(`Could not run the Rust server (${binary}). Build it first:\n` +
|
|
74
|
-
` cd rust && cargo build --release\n`);
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
77
|
-
process.exit(result.status ?? 0);
|
|
78
|
-
}
|
|
79
59
|
switch (command) {
|
|
80
60
|
case "--version":
|
|
81
61
|
case "-v":
|
|
@@ -95,7 +75,11 @@ switch (command) {
|
|
|
95
75
|
run("rastack-dev.js", rest);
|
|
96
76
|
break;
|
|
97
77
|
case "admin":
|
|
98
|
-
|
|
78
|
+
// Full Django-admin-style console: the native Rust server serves React API
|
|
79
|
+
// Stack's own React admin (built from `rastack/components` + `rastack/theme`)
|
|
80
|
+
// over the real Iceberg warehouse. `rastack-admin.js` compiles, wires the
|
|
81
|
+
// bundle in, and boots the server.
|
|
82
|
+
run("rastack-admin.js", rest);
|
|
99
83
|
break;
|
|
100
84
|
case "tokens":
|
|
101
85
|
// Design tokens → CSS custom properties + typed theme.
|
|
@@ -148,7 +132,7 @@ switch (command) {
|
|
|
148
132
|
` rastack tokens [input] [outDir] [--prefix p] Compile design tokens → CSS vars + typed theme\n` +
|
|
149
133
|
` rastack design [input] [--port n] Live design-system studio (showcase + edit)\n` +
|
|
150
134
|
` rastack dev [--port n] [--warehouse dir] [--no-open] Run the app + admin in-browser over WASM (local dev)\n` +
|
|
151
|
-
` rastack admin [--warehouse dir]
|
|
135
|
+
` rastack admin [--warehouse dir] [--port n] [--no-open] Full admin console (React UI over the native server; needs a built rastack-server)\n` +
|
|
152
136
|
` rastack scan [files...] [--fail-on-pii]\n` +
|
|
153
137
|
` rastack seed [--env dev|staging] [--source gs://bucket/ | ./myapp-dev/]\n` +
|
|
154
138
|
` rastack bootstrap [--owner o] [--repo r] [--region r] [--prefix p] [--reuse-oidc] [--print] Stand the AWS account stack up\n` +
|
|
@@ -375,7 +375,7 @@ function __wbg_get_imports() {
|
|
|
375
375
|
return ret;
|
|
376
376
|
},
|
|
377
377
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
378
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
378
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 80, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
379
379
|
const ret = makeMutClosure(arg0, arg1, wasm_bindgen_1a7aa9db5392c486___convert__closures_____invoke___wasm_bindgen_1a7aa9db5392c486___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_1a7aa9db5392c486___JsError___true_);
|
|
380
380
|
return ret;
|
|
381
381
|
},
|
|
Binary file
|
package/package.json
CHANGED
package/src/dev/harness.ts
CHANGED
|
@@ -60,6 +60,50 @@ export function parseDevArgs(argv: string[]): DevArgs {
|
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/** Args for `rastack admin` — like `DevArgs`, but bound to a real server port. */
|
|
64
|
+
export interface AdminArgs {
|
|
65
|
+
resourcesDir: string;
|
|
66
|
+
outDir: string;
|
|
67
|
+
warehouseDir: string;
|
|
68
|
+
/** TCP port the native `rastack-server` binds (the admin lives at `/admin/`). */
|
|
69
|
+
port: number;
|
|
70
|
+
open: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const ADMIN_DEFAULTS: AdminArgs = {
|
|
74
|
+
resourcesDir: "resources",
|
|
75
|
+
outDir: ".rastack",
|
|
76
|
+
warehouseDir: "data/warehouse",
|
|
77
|
+
port: 8000,
|
|
78
|
+
open: true,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Parse `rastack admin` args: `--port`, `--warehouse`, `--out`, `--no-open`, and
|
|
83
|
+
* a single positional resources dir. Mirrors `parseDevArgs` but defaults to the
|
|
84
|
+
* server's port 8000 (the React admin is served by the native server, not a
|
|
85
|
+
* node static server).
|
|
86
|
+
*/
|
|
87
|
+
export function parseAdminArgs(argv: string[]): AdminArgs {
|
|
88
|
+
const positional: string[] = [];
|
|
89
|
+
let { resourcesDir, outDir, warehouseDir, port, open } = ADMIN_DEFAULTS;
|
|
90
|
+
for (let i = 0; i < argv.length; i++) {
|
|
91
|
+
const a = argv[i];
|
|
92
|
+
if (a === "--port") port = Number(argv[++i]) || port;
|
|
93
|
+
else if (a === "--warehouse") warehouseDir = argv[++i] ?? warehouseDir;
|
|
94
|
+
else if (a === "--out") outDir = argv[++i] ?? outDir;
|
|
95
|
+
else if (a === "--no-open") open = false;
|
|
96
|
+
else if (!a.startsWith("-")) positional.push(a);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
resourcesDir: positional[0] || resourcesDir,
|
|
100
|
+
outDir,
|
|
101
|
+
warehouseDir,
|
|
102
|
+
port,
|
|
103
|
+
open,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
63
107
|
const MIME: Record<string, string> = {
|
|
64
108
|
".html": "text/html; charset=utf-8",
|
|
65
109
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `rastack admin` — the full, Django-admin-style console, served by the native
|
|
5
|
+
* `rastack-server` against the real Iceberg warehouse.
|
|
6
|
+
*
|
|
7
|
+
* rastack admin [resourcesDir] [--warehouse <dir>] [--port <n>] [--out <dir>] [--no-open]
|
|
8
|
+
*
|
|
9
|
+
* Unlike the old server-rendered `/admin`, the console is React API Stack's own
|
|
10
|
+
* React admin (`tools/admin`, built from `rastack/components` + `rastack/theme`)
|
|
11
|
+
* — this command compiles the resources, points the server at the prebuilt
|
|
12
|
+
* bundle (`RASTACK_ADMIN_ASSETS`), and boots it. The bundle talks back to the
|
|
13
|
+
* same server's `/api` over HTTP, so edits persist to the real warehouse.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { execFileSync, spawn, spawnSync } from "child_process";
|
|
17
|
+
import * as fs from "fs";
|
|
18
|
+
import * as path from "path";
|
|
19
|
+
import { parseAdminArgs } from "./dev/harness";
|
|
20
|
+
|
|
21
|
+
const HERE = __dirname; // dist/ when installed — the bundle lives beside us.
|
|
22
|
+
|
|
23
|
+
/** Compile the resources to schema.rastack.json + openapi.json in outDir. */
|
|
24
|
+
function compile(resourcesDir: string, outDir: string): boolean {
|
|
25
|
+
const compiler = path.join(HERE, "rastack-compile.js");
|
|
26
|
+
const result = spawnSync(
|
|
27
|
+
process.execPath,
|
|
28
|
+
[compiler, "compile", resourcesDir, outDir],
|
|
29
|
+
{ stdio: "inherit" },
|
|
30
|
+
);
|
|
31
|
+
if (result.status !== 0) return false;
|
|
32
|
+
return fs.existsSync(path.join(outDir, "schema.rastack.json"));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Best-effort open the default browser at `url`. */
|
|
36
|
+
function openBrowser(url: string): void {
|
|
37
|
+
const cmd =
|
|
38
|
+
process.platform === "darwin"
|
|
39
|
+
? "open"
|
|
40
|
+
: process.platform === "win32"
|
|
41
|
+
? "start"
|
|
42
|
+
: "xdg-open";
|
|
43
|
+
try {
|
|
44
|
+
execFileSync(cmd, [url], { stdio: "ignore" });
|
|
45
|
+
} catch {
|
|
46
|
+
/* non-fatal — the URL is printed anyway */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function main(argv: string[]): void {
|
|
51
|
+
const args = parseAdminArgs(argv);
|
|
52
|
+
|
|
53
|
+
console.log(`\n rastack admin — the database console, built with React API Stack\n`);
|
|
54
|
+
console.log(`▸ Compiling ${args.resourcesDir} → ${args.outDir}`);
|
|
55
|
+
if (!compile(args.resourcesDir, args.outDir)) {
|
|
56
|
+
console.error(" ✗ compile failed — fix the resource graph and re-run.");
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const bundle = path.join(HERE, "admin.js");
|
|
61
|
+
if (!fs.existsSync(bundle)) {
|
|
62
|
+
console.error(" ✗ admin bundle (dist/admin.js) not found — reinstall rastack.");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const repoRoot = path.resolve(HERE, "..", "..");
|
|
67
|
+
const binary =
|
|
68
|
+
process.env.RASTACK_SERVER_BIN ||
|
|
69
|
+
path.join(repoRoot, "rust", "target", "release", "rastack-server");
|
|
70
|
+
|
|
71
|
+
const manifest = path.join(args.outDir, "schema.rastack.json");
|
|
72
|
+
const serverArgs = [
|
|
73
|
+
"admin",
|
|
74
|
+
"--manifest",
|
|
75
|
+
manifest,
|
|
76
|
+
"--warehouse",
|
|
77
|
+
args.warehouseDir,
|
|
78
|
+
"--addr",
|
|
79
|
+
`127.0.0.1:${args.port}`,
|
|
80
|
+
// Local dev context: the admin runs unauthenticated, exactly like the old
|
|
81
|
+
// native admin. Production admins run the server with --jwks/--admin-group.
|
|
82
|
+
"--insecure-dev-auth",
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const url = `http://127.0.0.1:${args.port}/admin/`;
|
|
86
|
+
// The server serves the React bundle from here; hand the path via env so the
|
|
87
|
+
// Rust side stays free of JS-toolchain knowledge.
|
|
88
|
+
const child = spawn(binary, serverArgs, {
|
|
89
|
+
stdio: "inherit",
|
|
90
|
+
env: { ...process.env, RASTACK_ADMIN_ASSETS: HERE },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
child.on("error", () => {
|
|
94
|
+
console.error(
|
|
95
|
+
` ✗ Could not run the Rust server (${binary}). Build it first:\n` +
|
|
96
|
+
` cd rust && cargo build --release\n`,
|
|
97
|
+
);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
100
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
101
|
+
|
|
102
|
+
// Give the server a moment to bind, then print + open.
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
console.log(`\n ▸ ${url}\n`);
|
|
105
|
+
console.log(" Press Ctrl+C to stop.\n");
|
|
106
|
+
if (args.open) openBrowser(url);
|
|
107
|
+
}, 700);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (require.main === module) {
|
|
111
|
+
main(process.argv.slice(2));
|
|
112
|
+
}
|
package/src/rastack.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* rastack tokens [input] [outDir] Compile design tokens → CSS vars + typed theme
|
|
13
13
|
* rastack design [input] [--port n] Live design-system studio (showcase + edit)
|
|
14
14
|
* rastack dev [--port n] [--warehouse d] Local dev: run the app + admin in-browser over WASM
|
|
15
|
-
* rastack admin [--warehouse dir]
|
|
15
|
+
* rastack admin [--warehouse dir] [--port n] Full admin console — React UI (rastack/components) over the native server
|
|
16
16
|
* rastack scan [files...] [--fail-on-pii] Scan CSVs for PII and schema info
|
|
17
17
|
* rastack seed [--env dev] [--source gs://] Load CSVs into Iceberg namespace
|
|
18
18
|
* rastack bootstrap [--owner o] [--repo r] Stand the tier-0 AWS account stack up (once per account+region)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* rastack update [<version>] [--check] Update the CLI in place (self-update)
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import { execSync
|
|
25
|
+
import { execSync } from "child_process";
|
|
26
26
|
import { readFileSync } from "fs";
|
|
27
27
|
import path from "path";
|
|
28
28
|
|
|
@@ -57,30 +57,6 @@ function run(script: string, args: string[] = rest) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
/** Invoke the compiled Rust server binary (built by `cargo build` in rust/). */
|
|
61
|
-
function runRust(subcommand: string) {
|
|
62
|
-
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
63
|
-
const binary =
|
|
64
|
-
process.env.RASTACK_SERVER_BIN ||
|
|
65
|
-
path.join(repoRoot, "rust", "target", "release", "rastack-server");
|
|
66
|
-
// Runs the locally-built Rust server binary with a fixed internal subcommand
|
|
67
|
-
// ("serve"/"admin"); `rest` is the developer's own CLI args, not untrusted
|
|
68
|
-
// input — no command-injection surface.
|
|
69
|
-
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
70
|
-
const result = spawnSync(binary, [subcommand, ...rest], {
|
|
71
|
-
stdio: "inherit",
|
|
72
|
-
env: process.env,
|
|
73
|
-
});
|
|
74
|
-
if (result.error) {
|
|
75
|
-
console.error(
|
|
76
|
-
`Could not run the Rust server (${binary}). Build it first:\n` +
|
|
77
|
-
` cd rust && cargo build --release\n`,
|
|
78
|
-
);
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
process.exit(result.status ?? 0);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
60
|
switch (command) {
|
|
85
61
|
case "--version":
|
|
86
62
|
case "-v":
|
|
@@ -100,7 +76,11 @@ switch (command) {
|
|
|
100
76
|
run("rastack-dev.js", rest);
|
|
101
77
|
break;
|
|
102
78
|
case "admin":
|
|
103
|
-
|
|
79
|
+
// Full Django-admin-style console: the native Rust server serves React API
|
|
80
|
+
// Stack's own React admin (built from `rastack/components` + `rastack/theme`)
|
|
81
|
+
// over the real Iceberg warehouse. `rastack-admin.js` compiles, wires the
|
|
82
|
+
// bundle in, and boots the server.
|
|
83
|
+
run("rastack-admin.js", rest);
|
|
104
84
|
break;
|
|
105
85
|
case "tokens":
|
|
106
86
|
// Design tokens → CSS custom properties + typed theme.
|
|
@@ -154,7 +134,7 @@ switch (command) {
|
|
|
154
134
|
` rastack tokens [input] [outDir] [--prefix p] Compile design tokens → CSS vars + typed theme\n` +
|
|
155
135
|
` rastack design [input] [--port n] Live design-system studio (showcase + edit)\n` +
|
|
156
136
|
` rastack dev [--port n] [--warehouse dir] [--no-open] Run the app + admin in-browser over WASM (local dev)\n` +
|
|
157
|
-
` rastack admin [--warehouse dir]
|
|
137
|
+
` rastack admin [--warehouse dir] [--port n] [--no-open] Full admin console (React UI over the native server; needs a built rastack-server)\n` +
|
|
158
138
|
` rastack scan [files...] [--fail-on-pii]\n` +
|
|
159
139
|
` rastack seed [--env dev|staging] [--source gs://bucket/ | ./myapp-dev/]\n` +
|
|
160
140
|
` rastack bootstrap [--owner o] [--repo r] [--region r] [--prefix p] [--reuse-oidc] [--print] Stand the AWS account stack up\n` +
|