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.
Files changed (59) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +19 -24
  3. package/admin/httpEngine.ts +5 -6
  4. package/admin/index.tsx +11 -91
  5. package/dist/admin.js +14 -22
  6. package/dist/compile/model.d.ts +1 -1
  7. package/dist/compile/run.d.ts +2 -2
  8. package/dist/compile/run.js +2 -2
  9. package/dist/define/index.d.ts +2 -3
  10. package/dist/deploy/workflows.js +1 -1
  11. package/dist/dev/harness.d.ts +19 -27
  12. package/dist/dev/harness.js +31 -40
  13. package/dist/dev/native-server.d.ts +29 -0
  14. package/dist/dev/native-server.js +174 -0
  15. package/dist/external/envelope.d.ts +1 -1
  16. package/dist/external/envelope.js +1 -1
  17. package/dist/external/service.d.ts +2 -2
  18. package/dist/external/service.js +2 -2
  19. package/dist/external/types.d.ts +1 -1
  20. package/dist/external/types.js +1 -1
  21. package/dist/rastack-admin.d.ts +6 -14
  22. package/dist/rastack-admin.js +60 -88
  23. package/dist/rastack-design.d.ts +1 -2
  24. package/dist/rastack-design.js +1 -2
  25. package/dist/rastack-dev.d.ts +7 -10
  26. package/dist/rastack-dev.js +68 -80
  27. package/dist/rastack.d.ts +1 -1
  28. package/dist/rastack.js +5 -6
  29. package/dist/validate/transitions.d.ts +1 -1
  30. package/dist/validate/transitions.js +1 -1
  31. package/hooks/query/api.ts +4 -6
  32. package/package.json +2 -2
  33. package/provider/index.ts +0 -1
  34. package/provider/provider.tsx +31 -157
  35. package/provider/types.ts +29 -77
  36. package/src/compile/model.ts +1 -1
  37. package/src/compile/run.ts +2 -2
  38. package/src/define/index.ts +2 -3
  39. package/src/deploy/workflows.ts +1 -1
  40. package/src/dev/harness.ts +30 -43
  41. package/src/dev/native-server.ts +164 -0
  42. package/src/external/envelope.ts +1 -1
  43. package/src/external/service.ts +2 -2
  44. package/src/external/types.ts +1 -1
  45. package/src/rastack-admin.ts +66 -107
  46. package/src/rastack-design.ts +1 -2
  47. package/src/rastack-dev.ts +79 -91
  48. package/src/rastack.ts +5 -6
  49. package/src/validate/transitions.ts +1 -1
  50. package/dist/rastack-wasm-build.d.ts +0 -19
  51. package/dist/rastack-wasm-build.js +0 -94
  52. package/dist/wasm/package.json +0 -4
  53. package/dist/wasm/rastack_wasm.d.ts +0 -100
  54. package/dist/wasm/rastack_wasm.js +0 -745
  55. package/dist/wasm/rastack_wasm_bg.wasm +0 -0
  56. package/dist/wasm/rastack_wasm_bg.wasm.d.ts +0 -28
  57. package/provider/wasm.ts +0 -126
  58. package/scripts/copy-wasm.js +0 -35
  59. package/src/rastack-wasm-build.ts +0 -113
@@ -1,23 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * `rastack admin` — the full, Django-admin-style console, served **in the
5
- * browser over the prebuilt WebAssembly engine** (exactly like `rastack dev`).
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
- * The console is React API Stack's own React admin (`tools/admin`, built from
10
- * `rastack/components` + `rastack/theme`). This command compiles the resources,
11
- * then boots a dependency-free static server that hands the browser everything
12
- * it needs to run the admin locally over WASM — no native server, no cargo:
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 HERE = __dirname; // dist/ when installed — the bundle lives beside us.
63
- /** Locate the prebuilt wasm bundle dir shipped in the package (no cargo fallback). */
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
- console.log(`\n rastack admin — the database console, built with React API Stack\n`);
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
- const server = http.createServer((req, res) => {
134
- const url = (req.url || "/").split("?")[0];
135
- if (req.method !== "GET") {
136
- res.writeHead(405).end("Method not allowed");
137
- return;
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
- if (url === "/" || url === "/index.html") {
140
- res
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
- if (url === "/dev/admin.js")
146
- return serveFile(res, adminBundle);
147
- if (url.startsWith("/wasm/"))
148
- return serveUnder(res, wasmDir, url.slice("/wasm/".length));
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
- server.listen(args.port, () => {
156
- const url = `http://localhost:${args.port}`;
157
- console.log(` ✓ WASM engine: ${path.relative(process.cwd(), wasmDir)}`);
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
  }
@@ -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
- * In keeping with the local-first ethos (the whole API runs in the browser via
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 {};
@@ -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
- * In keeping with the local-first ethos (the whole API runs in the browser via
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;
@@ -1,22 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * `rastack dev` — local development of **your app**, always over the WASM engine.
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, then boots a dependency-free static server (à la
8
- * `rastack design`) that hands the browser everything it needs to run the
9
- * developer's own app locally over WebAssembly — no native server, no cargo:
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
- * • the committed Iceberg warehouse (`/data/warehouse/…`) to seed from.
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 {};
@@ -1,24 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * `rastack dev` — local development of **your app**, always over the WASM engine.
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, then boots a dependency-free static server (à la
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:
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
- * • the committed Iceberg warehouse (`/data/warehouse/…`) to seed from.
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 HERE = __dirname; // dist/ when installed
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. The WASM
189
- // static-serve path remains the default for apps that ship a built index.html.
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
- /** Locate the prebuilt wasm bundle without the cargo fallback (optional here). */
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("Metro is not reachable.");
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
- // Reserved backend routes win when the engine bundle is available.
349
- if (wasmDir && url.startsWith("/wasm/"))
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
- if (wasmDir)
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, in your browser over WASM\n`);
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
- // No static build, but an Expo source tree → drive Metro live (fast refresh).
394
- if (!appRoot && isExpoProject(cwd)) {
395
- return runMetroMode(args, cwd);
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
- const wasmDir = resolveWasmDir();
398
- if (!wasmDir) {
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(` ✓ WASM engine: ${path.relative(process.cwd(), wasmDir)}`);
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: run your app in-browser over WASM
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: run your app in-browser over WASM
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 serves over WASM)\n" +
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 in the browser over the WASM engine
86
- // (no native server, no cargo). The admin console is a separate command,
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] Run your app in-browser over WASM (local dev)\n` +
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/WASM write. A write
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/WASM write. A write
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
@@ -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 for `remote` mode, or a WASM adapter for
10
- * `local`/`s3` mode) rather than swapping the instance. That is what lets the
11
- * same hooks hit a Lambda over HTTP or an in-browser WASM engine with no
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. Pass the WASM adapter to route requests into the
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.64",
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 && node scripts/copy-wasm.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"
package/provider/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./types";
2
2
  export * from "./provider";
3
- export { createWasmAdapter, createEngine, defaultEngineLoader } from "./wasm";
4
3
  export {
5
4
  WarehousePersistence,
6
5
  seedFromIceberg,