rastack 0.0.64 → 0.0.69
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 +25 -0
- package/README.md +19 -24
- package/admin/httpEngine.ts +5 -6
- package/admin/index.tsx +11 -91
- package/dist/admin.js +14 -22
- package/dist/compile/model.d.ts +1 -1
- package/dist/compile/run.d.ts +2 -2
- package/dist/compile/run.js +2 -2
- package/dist/define/index.d.ts +2 -3
- package/dist/deploy/workflows.js +1 -1
- package/dist/dev/harness.d.ts +19 -27
- package/dist/dev/harness.js +31 -40
- package/dist/dev/native-server.d.ts +29 -0
- package/dist/dev/native-server.js +174 -0
- package/dist/external/envelope.d.ts +1 -1
- package/dist/external/envelope.js +1 -1
- package/dist/external/service.d.ts +2 -2
- package/dist/external/service.js +2 -2
- package/dist/external/types.d.ts +1 -1
- package/dist/external/types.js +1 -1
- package/dist/rastack-admin.d.ts +6 -14
- package/dist/rastack-admin.js +60 -88
- package/dist/rastack-design.d.ts +1 -2
- package/dist/rastack-design.js +1 -2
- package/dist/rastack-dev.d.ts +7 -10
- package/dist/rastack-dev.js +68 -80
- package/dist/rastack.d.ts +1 -1
- package/dist/rastack.js +5 -6
- package/dist/validate/transitions.d.ts +1 -1
- package/dist/validate/transitions.js +1 -1
- package/hooks/query/api.ts +4 -6
- package/package.json +2 -2
- package/provider/index.ts +0 -1
- package/provider/provider.tsx +31 -157
- package/provider/types.ts +29 -77
- package/src/compile/model.ts +1 -1
- package/src/compile/run.ts +2 -2
- package/src/define/index.ts +2 -3
- package/src/deploy/workflows.ts +1 -1
- package/src/dev/harness.ts +30 -43
- package/src/dev/native-server.ts +164 -0
- package/src/external/envelope.ts +1 -1
- package/src/external/service.ts +2 -2
- package/src/external/types.ts +1 -1
- package/src/rastack-admin.ts +66 -107
- package/src/rastack-design.ts +1 -2
- package/src/rastack-dev.ts +79 -91
- package/src/rastack.ts +5 -6
- package/src/validate/transitions.ts +1 -1
- package/dist/rastack-wasm-build.d.ts +0 -19
- package/dist/rastack-wasm-build.js +0 -94
- package/dist/wasm/package.json +0 -4
- package/dist/wasm/rastack_wasm.d.ts +0 -100
- package/dist/wasm/rastack_wasm.js +0 -745
- package/dist/wasm/rastack_wasm_bg.wasm +0 -0
- package/dist/wasm/rastack_wasm_bg.wasm.d.ts +0 -28
- package/provider/wasm.ts +0 -126
- package/scripts/copy-wasm.js +0 -35
- package/src/rastack-wasm-build.ts +0 -113
package/dist/rastack-admin.js
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
* `rastack admin` — the
|
|
5
|
-
*
|
|
4
|
+
* `rastack admin` — the Django-admin-style console, served by the native
|
|
5
|
+
* `rastack-server` process.
|
|
6
6
|
*
|
|
7
7
|
* rastack admin [resourcesDir] [--warehouse <dir>] [--port <n>] [--out <dir>] [--no-open]
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* • the bundled React admin (`/dev/admin.js`), which defaults to `mode:"local"`,
|
|
14
|
-
* • the prebuilt WASM engine (`/wasm/…`) shipped in the package,
|
|
15
|
-
* • the compiled `schema.rastack.json` / `openapi.json`,
|
|
16
|
-
* • the committed Iceberg warehouse (`/data/warehouse/…`) to seed from.
|
|
17
|
-
*
|
|
18
|
-
* The engine is the single prebuilt `.wasm` bundle shipped in the npm package;
|
|
19
|
-
* if it is missing the command errors and points at `rastack update` — it never
|
|
20
|
-
* falls back to a from-source cargo build.
|
|
9
|
+
* Compiles the resources, then starts `rastack-server admin`. That process is
|
|
10
|
+
* the API (`rastack-api-core`) and it serves the React bundle at `/admin/`.
|
|
11
|
+
* The browser renders the console and calls `/api` on that same origin.
|
|
12
|
+
* The engine does not run in the browser.
|
|
21
13
|
*/
|
|
22
14
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
15
|
if (k2 === undefined) k2 = k;
|
|
@@ -55,47 +47,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
55
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
48
|
const child_process_1 = require("child_process");
|
|
57
49
|
const fs = __importStar(require("fs"));
|
|
58
|
-
const http = __importStar(require("http"));
|
|
59
50
|
const path = __importStar(require("path"));
|
|
60
51
|
const compile_1 = require("./compile");
|
|
61
52
|
const harness_1 = require("./dev/harness");
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
function resolveWasmDir() {
|
|
65
|
-
for (const dir of (0, harness_1.wasmBundleCandidates)(HERE)) {
|
|
66
|
-
if (fs.existsSync(path.join(dir, harness_1.WASM_ENTRY)))
|
|
67
|
-
return dir;
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
/** Serve one file if it exists and stays within `root`; else 404/403. */
|
|
72
|
-
function serveUnder(res, root, relPath) {
|
|
73
|
-
const safeRoot = path.resolve(root);
|
|
74
|
-
const rel = decodeURIComponent(relPath).replace(/^\/+/, "");
|
|
75
|
-
const target = path.resolve(safeRoot, rel);
|
|
76
|
-
// Path-traversal guard: the resolved target must stay inside the root.
|
|
77
|
-
if (target !== safeRoot && !target.startsWith(safeRoot + path.sep)) {
|
|
78
|
-
res.writeHead(403).end("Forbidden");
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
fs.readFile(target, (err, data) => {
|
|
82
|
-
if (err) {
|
|
83
|
-
res.writeHead(404).end("Not found");
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
res.writeHead(200, { "Content-Type": (0, harness_1.contentType)(target) }).end(data);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
/** Serve an exact file (no traversal concern — a fixed internal artifact). */
|
|
90
|
-
function serveFile(res, file) {
|
|
91
|
-
fs.readFile(file, (err, data) => {
|
|
92
|
-
if (err) {
|
|
93
|
-
res.writeHead(404).end("Not found");
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
res.writeHead(200, { "Content-Type": (0, harness_1.contentType)(file) }).end(data);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
53
|
+
const native_server_1 = require("./dev/native-server");
|
|
54
|
+
const HERE = __dirname; // dist/ when installed — admin.js lives beside us.
|
|
99
55
|
/** Best-effort open the default browser at `url`. */
|
|
100
56
|
function openBrowser(url) {
|
|
101
57
|
const cmd = process.platform === "darwin"
|
|
@@ -110,57 +66,73 @@ function openBrowser(url) {
|
|
|
110
66
|
/* non-fatal — the URL is printed anyway */
|
|
111
67
|
}
|
|
112
68
|
}
|
|
113
|
-
function main(argv) {
|
|
69
|
+
async function main(argv) {
|
|
114
70
|
const args = (0, harness_1.parseAdminArgs)(argv);
|
|
115
|
-
|
|
71
|
+
const cwd = process.cwd();
|
|
72
|
+
console.log(`\n rastack admin — the database console, on the native Rust server\n`);
|
|
116
73
|
console.log(`▸ Compiling ${args.resourcesDir} → ${args.outDir}`);
|
|
117
74
|
if (!(0, compile_1.runCompile)(args.resourcesDir, args.outDir)) {
|
|
118
75
|
console.error(" ✗ compile failed — fix the resource graph and re-run.");
|
|
119
76
|
process.exit(1);
|
|
120
77
|
}
|
|
121
|
-
const wasmDir = resolveWasmDir();
|
|
122
|
-
if (!wasmDir) {
|
|
123
|
-
console.error("\n ✗ No prebuilt WASM engine found in this rastack install.\n" +
|
|
124
|
-
" Update rastack to pull the prebuilt bundle:\n" +
|
|
125
|
-
" rastack update\n");
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
78
|
const adminBundle = path.join(HERE, "admin.js");
|
|
129
79
|
if (!fs.existsSync(adminBundle)) {
|
|
130
80
|
console.error(" ✗ admin bundle (dist/admin.js) not found — reinstall rastack.");
|
|
131
81
|
process.exit(1);
|
|
132
82
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
83
|
+
let bin;
|
|
84
|
+
try {
|
|
85
|
+
bin = (0, native_server_1.ensureServerBinary)(cwd);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
console.error(`\n${err.message}\n`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const manifest = path.resolve(cwd, args.outDir, "schema.rastack.json");
|
|
92
|
+
const warehouse = path.resolve(cwd, args.warehouseDir);
|
|
93
|
+
const child = (0, native_server_1.startNativeServer)({
|
|
94
|
+
bin,
|
|
95
|
+
command: "admin",
|
|
96
|
+
manifest,
|
|
97
|
+
warehouse,
|
|
98
|
+
addr: `127.0.0.1:${args.port}`,
|
|
99
|
+
adminAssets: HERE,
|
|
100
|
+
});
|
|
101
|
+
const stop = () => {
|
|
102
|
+
try {
|
|
103
|
+
child.kill("SIGTERM");
|
|
138
104
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
.writeHead(200, { "Content-Type": "text/html; charset=utf-8" })
|
|
142
|
-
.end((0, harness_1.renderShell)("React API Stack — admin"));
|
|
143
|
-
return;
|
|
105
|
+
catch {
|
|
106
|
+
/* already gone */
|
|
144
107
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (url === "/schema.rastack.json" || url === "/openapi.json")
|
|
150
|
-
return serveUnder(res, args.outDir, path.basename(url));
|
|
151
|
-
if (url.startsWith("/data/warehouse/"))
|
|
152
|
-
return serveUnder(res, args.warehouseDir, url.slice("/data/warehouse/".length));
|
|
153
|
-
res.writeHead(404).end("Not found");
|
|
108
|
+
};
|
|
109
|
+
process.on("SIGINT", () => {
|
|
110
|
+
stop();
|
|
111
|
+
process.exit(0);
|
|
154
112
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
console.log(`\n ▸ ${url}\n`);
|
|
159
|
-
console.log(" Press Ctrl+C to stop.\n");
|
|
160
|
-
if (args.open)
|
|
161
|
-
openBrowser(url);
|
|
113
|
+
process.on("SIGTERM", () => {
|
|
114
|
+
stop();
|
|
115
|
+
process.exit(0);
|
|
162
116
|
});
|
|
117
|
+
try {
|
|
118
|
+
await (0, native_server_1.waitForTcp)(args.port, child);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.error(`\n${err.message}\n`);
|
|
122
|
+
stop();
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
const url = `http://127.0.0.1:${args.port}/admin/`;
|
|
126
|
+
console.log(` ✓ native engine: ${bin}`);
|
|
127
|
+
console.log(`\n ▸ ${url}\n`);
|
|
128
|
+
console.log(" Press Ctrl+C to stop.\n");
|
|
129
|
+
if (args.open)
|
|
130
|
+
openBrowser(url);
|
|
131
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
163
132
|
}
|
|
164
133
|
if (require.main === module) {
|
|
165
|
-
main(process.argv.slice(2))
|
|
134
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
135
|
+
console.error(err);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
});
|
|
166
138
|
}
|
package/dist/rastack-design.d.ts
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
* source and hitting **Save** writes it back and recompiles `tokens.css` /
|
|
12
12
|
* `tokens.ts`, so the rest of the app picks the change up on reload.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* WASM), the studio needs no build step and no external dependencies.
|
|
14
|
+
* The studio needs no build step and no external dependencies.
|
|
16
15
|
*/
|
|
17
16
|
export {};
|
package/dist/rastack-design.js
CHANGED
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
* source and hitting **Save** writes it back and recompiles `tokens.css` /
|
|
13
13
|
* `tokens.ts`, so the rest of the app picks the change up on reload.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* WASM), the studio needs no build step and no external dependencies.
|
|
15
|
+
* The studio needs no build step and no external dependencies.
|
|
17
16
|
*/
|
|
18
17
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
18
|
if (k2 === undefined) k2 = k;
|
package/dist/rastack-dev.d.ts
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* `rastack dev` — local development of **your app
|
|
3
|
+
* `rastack dev` — local development of **your app** against the native engine.
|
|
4
4
|
*
|
|
5
5
|
* rastack dev [resourcesDir] [--port <n>] [--warehouse <dir>] [--out <dir>] [--app <dir>] [--no-open]
|
|
6
6
|
*
|
|
7
|
-
* Compiles the resources,
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Compiles the resources, starts a native `rastack-server` (`rastack-api-core`
|
|
8
|
+
* over the on-disk Iceberg warehouse), and serves the developer's app. The
|
|
9
|
+
* browser is the UI. `/api` on this origin is proxied to that process.
|
|
10
10
|
* • the developer's app (`index.html` from the resolved app root), or a
|
|
11
11
|
* Django-style welcome page when the project has no app yet,
|
|
12
|
-
* • the prebuilt WASM engine (`/wasm/…`) shipped in the package,
|
|
13
12
|
* • the compiled `schema.rastack.json` / `openapi.json`,
|
|
14
|
-
* •
|
|
13
|
+
* • `/api/…` forwarded to the native server.
|
|
15
14
|
*
|
|
16
15
|
* It does **not** serve the admin console — that is a separate command,
|
|
17
|
-
* `rastack admin`.
|
|
18
|
-
*
|
|
19
|
-
* The engine is resolved from the package's prebuilt bundle; if none is present
|
|
20
|
-
* but a Rust + wasm toolchain is, it is built from source as a fallback.
|
|
16
|
+
* `rastack admin`. The browser does not execute the engine. There is no
|
|
17
|
+
* in-browser fallback.
|
|
21
18
|
*/
|
|
22
19
|
export {};
|
package/dist/rastack-dev.js
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
* `rastack dev` — local development of **your app
|
|
4
|
+
* `rastack dev` — local development of **your app** against the native engine.
|
|
5
5
|
*
|
|
6
6
|
* rastack dev [resourcesDir] [--port <n>] [--warehouse <dir>] [--out <dir>] [--app <dir>] [--no-open]
|
|
7
7
|
*
|
|
8
|
-
* Compiles the resources,
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Compiles the resources, starts a native `rastack-server` (`rastack-api-core`
|
|
9
|
+
* over the on-disk Iceberg warehouse), and serves the developer's app. The
|
|
10
|
+
* browser is the UI. `/api` on this origin is proxied to that process.
|
|
11
11
|
* • the developer's app (`index.html` from the resolved app root), or a
|
|
12
12
|
* Django-style welcome page when the project has no app yet,
|
|
13
|
-
* • the prebuilt WASM engine (`/wasm/…`) shipped in the package,
|
|
14
13
|
* • the compiled `schema.rastack.json` / `openapi.json`,
|
|
15
|
-
* •
|
|
14
|
+
* • `/api/…` forwarded to the native server.
|
|
16
15
|
*
|
|
17
16
|
* It does **not** serve the admin console — that is a separate command,
|
|
18
|
-
* `rastack admin`.
|
|
19
|
-
*
|
|
20
|
-
* The engine is resolved from the package's prebuilt bundle; if none is present
|
|
21
|
-
* but a Rust + wasm toolchain is, it is built from source as a fallback.
|
|
17
|
+
* `rastack admin`. The browser does not execute the engine. There is no
|
|
18
|
+
* in-browser fallback.
|
|
22
19
|
*/
|
|
23
20
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
24
21
|
if (k2 === undefined) k2 = k;
|
|
@@ -63,16 +60,7 @@ const compile_1 = require("./compile");
|
|
|
63
60
|
const config_1 = require("./deploy/config");
|
|
64
61
|
const io_1 = require("./deploy/io");
|
|
65
62
|
const harness_1 = require("./dev/harness");
|
|
66
|
-
const
|
|
67
|
-
/** True when `cargo` is on PATH (the from-source wasm fallback needs it). */
|
|
68
|
-
function cargoAvailable() {
|
|
69
|
-
try {
|
|
70
|
-
return (0, child_process_1.spawnSync)("cargo", ["--version"], { stdio: "ignore" }).status === 0;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
63
|
+
const native_server_1 = require("./dev/native-server");
|
|
76
64
|
/** First app-root candidate that holds an `index.html`, or null (→ welcome). */
|
|
77
65
|
function resolveAppRoot(appDir) {
|
|
78
66
|
for (const dir of (0, harness_1.appRootCandidates)(appDir)) {
|
|
@@ -81,30 +69,6 @@ function resolveAppRoot(appDir) {
|
|
|
81
69
|
}
|
|
82
70
|
return null;
|
|
83
71
|
}
|
|
84
|
-
/** Locate the prebuilt wasm bundle dir, building from source as a fallback. */
|
|
85
|
-
function resolveWasmDir() {
|
|
86
|
-
for (const dir of (0, harness_1.wasmBundleCandidates)(HERE)) {
|
|
87
|
-
if (fs.existsSync(path.join(dir, harness_1.WASM_ENTRY)))
|
|
88
|
-
return dir;
|
|
89
|
-
}
|
|
90
|
-
if (cargoAvailable()) {
|
|
91
|
-
console.log("\n▸ No prebuilt WASM engine found — building it from source (cargo)…\n");
|
|
92
|
-
try {
|
|
93
|
-
// Lazy require so a normal `dev` with a prebuilt bundle never loads it.
|
|
94
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
95
|
-
require("./rastack-wasm-build").buildWasm();
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
console.error(` ✗ wasm build failed: ${err.message}`);
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
for (const dir of (0, harness_1.wasmBundleCandidates)(HERE)) {
|
|
102
|
-
if (fs.existsSync(path.join(dir, harness_1.WASM_ENTRY)))
|
|
103
|
-
return dir;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
72
|
/** Serve one file if it exists and stays within `root`; else 404/403. */
|
|
109
73
|
function serveUnder(res, root, relPath) {
|
|
110
74
|
const safeRoot = path.resolve(root);
|
|
@@ -185,8 +149,9 @@ function openBrowser(url) {
|
|
|
185
149
|
// A React Native (Expo) app has no static `index.html`: its web build is a
|
|
186
150
|
// Metro bundle. Rather than make the developer run a second tool, `dev` starts
|
|
187
151
|
// Expo's Metro dev server itself and reverse-proxies to it, so `rastack dev`
|
|
188
|
-
// stays the single command *and* keeps Metro's fast-refresh.
|
|
189
|
-
//
|
|
152
|
+
// stays the single command *and* keeps Metro's fast-refresh. Apps that ship
|
|
153
|
+
// a built index.html use the static server below. Both proxy /api to the
|
|
154
|
+
// native server.
|
|
190
155
|
// ---------------------------------------------------------------------------
|
|
191
156
|
/** True when the project is an Expo app (so `dev` should drive Metro). */
|
|
192
157
|
function isExpoProject(cwd) {
|
|
@@ -208,15 +173,7 @@ function isExpoProject(cwd) {
|
|
|
208
173
|
}
|
|
209
174
|
return false;
|
|
210
175
|
}
|
|
211
|
-
/**
|
|
212
|
-
function findWasmDir() {
|
|
213
|
-
for (const dir of (0, harness_1.wasmBundleCandidates)(HERE)) {
|
|
214
|
-
if (fs.existsSync(path.join(dir, harness_1.WASM_ENTRY)))
|
|
215
|
-
return dir;
|
|
216
|
-
}
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
/** Grab an ephemeral free TCP port for Metro (avoids a fixed-port clash). */
|
|
176
|
+
/** Grab an ephemeral free TCP port (Metro, or the native API beside this server). */
|
|
220
177
|
function getFreePort() {
|
|
221
178
|
return new Promise((resolve, reject) => {
|
|
222
179
|
const srv = net.createServer();
|
|
@@ -287,7 +244,7 @@ function proxyToMetro(req, res, port) {
|
|
|
287
244
|
proxyReq.on("error", () => {
|
|
288
245
|
if (!res.headersSent)
|
|
289
246
|
res.writeHead(502);
|
|
290
|
-
res.end("
|
|
247
|
+
res.end("Upstream is not reachable.");
|
|
291
248
|
});
|
|
292
249
|
req.pipe(proxyReq);
|
|
293
250
|
}
|
|
@@ -311,10 +268,7 @@ function proxyUpgrade(req, clientSocket, head, port) {
|
|
|
311
268
|
clientSocket.on("error", () => upstream.destroy());
|
|
312
269
|
}
|
|
313
270
|
/** `rastack dev` for an Expo app: start Metro and reverse-proxy to it. */
|
|
314
|
-
async function runMetroMode(args, cwd) {
|
|
315
|
-
// The wasm engine is optional here — an Expo/RN-web app runs its own engine —
|
|
316
|
-
// so a missing bundle is fine. When present, the reserved backend routes work.
|
|
317
|
-
const wasmDir = findWasmDir();
|
|
271
|
+
async function runMetroMode(args, cwd, apiPort, stopEngine) {
|
|
318
272
|
const metroPort = await getFreePort();
|
|
319
273
|
console.log(`▸ Starting Metro bundler (Expo) on :${metroPort} …`);
|
|
320
274
|
const metro = startMetro(cwd, metroPort);
|
|
@@ -323,6 +277,7 @@ async function runMetroMode(args, cwd) {
|
|
|
323
277
|
if (shuttingDown)
|
|
324
278
|
return;
|
|
325
279
|
shuttingDown = true;
|
|
280
|
+
stopEngine();
|
|
326
281
|
try {
|
|
327
282
|
metro.kill();
|
|
328
283
|
}
|
|
@@ -345,9 +300,8 @@ async function runMetroMode(args, cwd) {
|
|
|
345
300
|
}
|
|
346
301
|
const server = http.createServer((req, res) => {
|
|
347
302
|
const url = (req.url || "/").split("?")[0];
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return serveUnder(res, wasmDir, url.slice("/wasm/".length));
|
|
303
|
+
if (url.startsWith("/api/") || url === "/api")
|
|
304
|
+
return proxyToMetro(req, res, apiPort);
|
|
351
305
|
if (url === "/schema.rastack.json" || url === "/openapi.json")
|
|
352
306
|
return serveUnder(res, args.outDir, path.basename(url));
|
|
353
307
|
if (url === "/__rastack/cognito.json")
|
|
@@ -371,8 +325,7 @@ async function runMetroMode(args, cwd) {
|
|
|
371
325
|
server.listen(args.port, () => {
|
|
372
326
|
const url = `http://localhost:${args.port}`;
|
|
373
327
|
console.log(` ✓ Metro live on :${metroPort} — fast refresh on`);
|
|
374
|
-
|
|
375
|
-
console.log(` ✓ WASM engine: ${path.relative(cwd, wasmDir)}`);
|
|
328
|
+
console.log(` ✓ native engine: 127.0.0.1:${apiPort} (proxied at /api)`);
|
|
376
329
|
console.log(`\n ▸ ${url}\n`);
|
|
377
330
|
console.log(" Edits reload live. Need the database console? Run `rastack admin`. Ctrl+C to stop.\n");
|
|
378
331
|
if (args.open)
|
|
@@ -382,7 +335,7 @@ async function runMetroMode(args, cwd) {
|
|
|
382
335
|
async function main(argv) {
|
|
383
336
|
const args = (0, harness_1.parseDevArgs)(argv);
|
|
384
337
|
const cwd = process.cwd();
|
|
385
|
-
console.log(`\n rastack dev — your app
|
|
338
|
+
console.log(`\n rastack dev — your app in the browser, the API in native Rust\n`);
|
|
386
339
|
console.log(`▸ Compiling ${args.resourcesDir} → ${args.outDir}`);
|
|
387
340
|
if (!(0, compile_1.runCompile)(args.resourcesDir, args.outDir)) {
|
|
388
341
|
console.error(" ✗ compile failed — fix the resource graph and re-run.");
|
|
@@ -390,28 +343,63 @@ async function main(argv) {
|
|
|
390
343
|
}
|
|
391
344
|
// Serve the developer's own app when there is one; otherwise the welcome page.
|
|
392
345
|
const appRoot = resolveAppRoot(args.appDir);
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
346
|
+
let engine;
|
|
347
|
+
let apiPort;
|
|
348
|
+
let stopping = false;
|
|
349
|
+
try {
|
|
350
|
+
const bin = (0, native_server_1.ensureServerBinary)(cwd);
|
|
351
|
+
apiPort = await getFreePort();
|
|
352
|
+
const manifest = path.resolve(cwd, args.outDir, "schema.rastack.json");
|
|
353
|
+
const warehouse = path.resolve(cwd, args.warehouseDir);
|
|
354
|
+
engine = (0, native_server_1.startNativeServer)({
|
|
355
|
+
bin,
|
|
356
|
+
command: "serve",
|
|
357
|
+
manifest,
|
|
358
|
+
warehouse,
|
|
359
|
+
addr: `127.0.0.1:${apiPort}`,
|
|
360
|
+
});
|
|
361
|
+
await (0, native_server_1.waitForTcp)(apiPort, engine);
|
|
396
362
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
console.error("\n ✗ No WASM engine available.\n" +
|
|
400
|
-
" Upgrade rastack for the prebuilt bundle (`rastack update`), or install\n" +
|
|
401
|
-
" the Rust toolchain to build it from source:\n" +
|
|
402
|
-
" rustup target add wasm32-unknown-unknown\n" +
|
|
403
|
-
" cargo install wasm-bindgen-cli\n");
|
|
363
|
+
catch (err) {
|
|
364
|
+
console.error(`\n${err.message}\n`);
|
|
404
365
|
process.exit(1);
|
|
405
366
|
}
|
|
367
|
+
const stopEngine = () => {
|
|
368
|
+
stopping = true;
|
|
369
|
+
try {
|
|
370
|
+
engine.kill("SIGTERM");
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
/* already gone */
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
engine.on("exit", (code) => {
|
|
377
|
+
if (stopping)
|
|
378
|
+
return;
|
|
379
|
+
console.error(`\n ✗ native engine exited (code ${code ?? "?"}).`);
|
|
380
|
+
process.exit(code ?? 1);
|
|
381
|
+
});
|
|
382
|
+
// No static build, but an Expo source tree → drive Metro live (fast refresh).
|
|
383
|
+
// Metro mode owns the shutdown signals so it can stop both processes.
|
|
384
|
+
if (!appRoot && isExpoProject(cwd)) {
|
|
385
|
+
return runMetroMode(args, cwd, apiPort, stopEngine);
|
|
386
|
+
}
|
|
387
|
+
process.on("SIGINT", () => {
|
|
388
|
+
stopEngine();
|
|
389
|
+
process.exit(0);
|
|
390
|
+
});
|
|
391
|
+
process.on("SIGTERM", () => {
|
|
392
|
+
stopEngine();
|
|
393
|
+
process.exit(0);
|
|
394
|
+
});
|
|
406
395
|
const server = http.createServer((req, res) => {
|
|
407
396
|
const url = (req.url || "/").split("?")[0];
|
|
397
|
+
if (url.startsWith("/api/") || url === "/api")
|
|
398
|
+
return proxyToMetro(req, res, apiPort);
|
|
408
399
|
if (req.method !== "GET") {
|
|
409
400
|
res.writeHead(405).end("Method not allowed");
|
|
410
401
|
return;
|
|
411
402
|
}
|
|
412
|
-
// Reserved backend routes always win over the app's static files.
|
|
413
|
-
if (url.startsWith("/wasm/"))
|
|
414
|
-
return serveUnder(res, wasmDir, url.slice("/wasm/".length));
|
|
415
403
|
if (url === "/schema.rastack.json" || url === "/openapi.json")
|
|
416
404
|
return serveUnder(res, args.outDir, path.basename(url));
|
|
417
405
|
if (url === "/__rastack/cognito.json")
|
|
@@ -443,7 +431,7 @@ async function main(argv) {
|
|
|
443
431
|
});
|
|
444
432
|
server.listen(args.port, () => {
|
|
445
433
|
const url = `http://localhost:${args.port}`;
|
|
446
|
-
console.log(` ✓
|
|
434
|
+
console.log(` ✓ native engine: 127.0.0.1:${apiPort} (proxied at /api)`);
|
|
447
435
|
if (appRoot)
|
|
448
436
|
console.log(` ✓ app: ${path.relative(process.cwd(), appRoot) || "."}`);
|
|
449
437
|
else
|
package/dist/rastack.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* rastack generate [--schema-only] Generate typed hooks from OpenAPI
|
|
13
13
|
* rastack tokens [input] [outDir] Compile design tokens → CSS vars + typed theme
|
|
14
14
|
* rastack design [input] [--port n] Live design-system studio (showcase + edit)
|
|
15
|
-
* rastack dev [--port n] [--warehouse d] Local dev:
|
|
15
|
+
* rastack dev [--port n] [--warehouse d] Local dev: your app in the browser, the API in native Rust
|
|
16
16
|
* rastack admin [--warehouse dir] [--port n] Full admin console — React UI (rastack/components) over the native server
|
|
17
17
|
* rastack import <file> --resource app.model Load CSV/XLSX/PDF data and validate it (state machine)
|
|
18
18
|
* rastack scan [files...] [--fail-on-pii] (LEGACY, pre-Rust) Scan CSVs for PII and schema info
|
package/dist/rastack.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* rastack generate [--schema-only] Generate typed hooks from OpenAPI
|
|
14
14
|
* rastack tokens [input] [outDir] Compile design tokens → CSS vars + typed theme
|
|
15
15
|
* rastack design [input] [--port n] Live design-system studio (showcase + edit)
|
|
16
|
-
* rastack dev [--port n] [--warehouse d] Local dev:
|
|
16
|
+
* rastack dev [--port n] [--warehouse d] Local dev: your app in the browser, the API in native Rust
|
|
17
17
|
* rastack admin [--warehouse dir] [--port n] Full admin console — React UI (rastack/components) over the native server
|
|
18
18
|
* rastack import <file> --resource app.model Load CSV/XLSX/PDF data and validate it (state machine)
|
|
19
19
|
* rastack scan [files...] [--fail-on-pii] (LEGACY, pre-Rust) Scan CSVs for PII and schema info
|
|
@@ -70,7 +70,7 @@ switch (command) {
|
|
|
70
70
|
// part of the two modalities of use. Point the way rather than 404.
|
|
71
71
|
console.error("`rastack compile` has been removed — compilation now runs automatically\n" +
|
|
72
72
|
"inside the two modalities of use:\n" +
|
|
73
|
-
" • rastack dev local development (compiles, then
|
|
73
|
+
" • rastack dev local development (compiles, then proxies /api to native rastack-server)\n" +
|
|
74
74
|
" • rastack ci the deploy pipeline (compiles the manifest + OpenAPI)\n\n" +
|
|
75
75
|
"Introspect the resource graph with: rastack check | list | urls\n");
|
|
76
76
|
process.exit(1);
|
|
@@ -82,9 +82,8 @@ switch (command) {
|
|
|
82
82
|
run("rastack-compile.js", [command, ...rest]);
|
|
83
83
|
break;
|
|
84
84
|
case "dev":
|
|
85
|
-
// Local development: serve your app
|
|
86
|
-
//
|
|
87
|
-
// `rastack admin`. Replaces `serve` + `wasm`.
|
|
85
|
+
// Local development: serve your app and proxy /api to native rastack-server.
|
|
86
|
+
// The admin console is a separate command, `rastack admin`.
|
|
88
87
|
run("rastack-dev.js", rest);
|
|
89
88
|
break;
|
|
90
89
|
case "admin":
|
|
@@ -154,7 +153,7 @@ switch (command) {
|
|
|
154
153
|
` rastack generate [--schema-only]\n` +
|
|
155
154
|
` rastack tokens [input] [outDir] [--prefix p] Compile design tokens → CSS vars + typed theme\n` +
|
|
156
155
|
` rastack design [input] [--port n] Live design-system studio (showcase + edit)\n` +
|
|
157
|
-
` rastack dev [--port n] [--warehouse dir] [--app dir] [--no-open]
|
|
156
|
+
` rastack dev [--port n] [--warehouse dir] [--app dir] [--no-open] App in the browser, API in native rastack-server\n` +
|
|
158
157
|
` rastack admin [--warehouse dir] [--port n] [--no-open] Full admin console (React UI over the native server; needs a built rastack-server)\n` +
|
|
159
158
|
` rastack import <file.csv|.xlsx|.pdf> --resource app.model [--related app.model=<file>] [--out cleaned.json]\n` +
|
|
160
159
|
` rastack scan [files...] [--fail-on-pii] (legacy, pre-Rust)\n` +
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* list), and this module is the *shared executable form* of it: the same pure
|
|
24
24
|
* functions guard a form submit (`useForm(...).transition("board")`), the
|
|
25
25
|
* record machine (`runRecordMachine` with a `previous` row in context), and —
|
|
26
|
-
* re-implemented 1:1 in `rastack-api-core` — every server
|
|
26
|
+
* re-implemented 1:1 in `rastack-api-core` — every native-server write. A write
|
|
27
27
|
* that jumps between states without a declared edge is rejected on every
|
|
28
28
|
* surface, which is what makes a transition "a backend function that is
|
|
29
29
|
* state-machine safe": the only way to move a record between states is a
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* list), and this module is the *shared executable form* of it: the same pure
|
|
25
25
|
* functions guard a form submit (`useForm(...).transition("board")`), the
|
|
26
26
|
* record machine (`runRecordMachine` with a `previous` row in context), and —
|
|
27
|
-
* re-implemented 1:1 in `rastack-api-core` — every server
|
|
27
|
+
* re-implemented 1:1 in `rastack-api-core` — every native-server write. A write
|
|
28
28
|
* that jumps between states without a declared edge is rejected on every
|
|
29
29
|
* surface, which is what makes a transition "a backend function that is
|
|
30
30
|
* state-machine safe": the only way to move a record between states is a
|
package/hooks/query/api.ts
CHANGED
|
@@ -6,10 +6,9 @@ const defaultBaseURL = process.env.NEXT_PUBLIC_BASE_URL || "http://127.0.0.1:800
|
|
|
6
6
|
/**
|
|
7
7
|
* The shared axios client every generated hook talks through. It is a stable
|
|
8
8
|
* singleton — imported directly all over the codegen — so `<RAStackProvider>`
|
|
9
|
-
* reconfigures it *in place* (base URL
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* codegen changes.
|
|
9
|
+
* reconfigures it *in place* (base URL) rather than swapping the instance.
|
|
10
|
+
* Every mode talks HTTP to the native server. The browser does not run the
|
|
11
|
+
* engine.
|
|
13
12
|
*/
|
|
14
13
|
export const API: AxiosInstance = axios.create({
|
|
15
14
|
baseURL: defaultBaseURL,
|
|
@@ -19,8 +18,7 @@ export interface ApiConfig {
|
|
|
19
18
|
/** Base URL for HTTP (`remote`) mode. */
|
|
20
19
|
baseURL?: string;
|
|
21
20
|
/**
|
|
22
|
-
* Axios adapter override.
|
|
23
|
-
* in-browser engine; pass `null` to restore axios's default HTTP transport.
|
|
21
|
+
* Axios adapter override. `null` keeps axios's default HTTP transport.
|
|
24
22
|
*/
|
|
25
23
|
adapter?: AxiosAdapter | null;
|
|
26
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rastack",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "runtime.ts",
|
|
6
6
|
"types": "runtime.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
37
|
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
|
|
38
|
-
"build": "tsc && cp src/.prettierrc dist/.prettierrc && node scripts/copy-templates.js && node scripts/build-admin.js
|
|
38
|
+
"build": "tsc && cp src/.prettierrc dist/.prettierrc && node scripts/copy-templates.js && node scripts/build-admin.js",
|
|
39
39
|
"dev:install": "node scripts/dev-install.mjs",
|
|
40
40
|
"start": "node dist/index.js",
|
|
41
41
|
"test": "jest"
|