rastack 0.0.63 → 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 (76) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +19 -24
  3. package/admin/AdminApp.tsx +56 -3
  4. package/admin/httpEngine.ts +5 -6
  5. package/admin/index.tsx +11 -85
  6. package/admin/ui/icons.tsx +9 -0
  7. package/admin/ui/styles.ts +3 -0
  8. package/admin/useAdmin.ts +41 -4
  9. package/dist/admin.js +17 -22
  10. package/dist/compile/analyze.js +11 -1
  11. package/dist/compile/model.d.ts +1 -1
  12. package/dist/compile/run.d.ts +2 -2
  13. package/dist/compile/run.js +2 -2
  14. package/dist/define/index.d.ts +10 -4
  15. package/dist/define/index.js +2 -2
  16. package/dist/define/manifest.js +7 -1
  17. package/dist/deploy/io.d.ts +50 -0
  18. package/dist/deploy/io.js +124 -0
  19. package/dist/deploy/workflows.js +1 -1
  20. package/dist/dev/harness.d.ts +19 -27
  21. package/dist/dev/harness.js +31 -40
  22. package/dist/dev/native-server.d.ts +29 -0
  23. package/dist/dev/native-server.js +174 -0
  24. package/dist/external/envelope.d.ts +1 -1
  25. package/dist/external/envelope.js +1 -1
  26. package/dist/external/service.d.ts +2 -2
  27. package/dist/external/service.js +2 -2
  28. package/dist/external/types.d.ts +1 -1
  29. package/dist/external/types.js +1 -1
  30. package/dist/rastack-admin.d.ts +6 -14
  31. package/dist/rastack-admin.js +60 -88
  32. package/dist/rastack-bootstrap.js +18 -47
  33. package/dist/rastack-design.d.ts +1 -2
  34. package/dist/rastack-design.js +1 -2
  35. package/dist/rastack-dev.d.ts +7 -10
  36. package/dist/rastack-dev.js +68 -80
  37. package/dist/rastack-init.d.ts +6 -3
  38. package/dist/rastack-init.js +43 -30
  39. package/dist/rastack.d.ts +1 -1
  40. package/dist/rastack.js +5 -6
  41. package/dist/validate/transitions.d.ts +1 -1
  42. package/dist/validate/transitions.js +1 -1
  43. package/hooks/query/api.ts +4 -6
  44. package/package.json +2 -2
  45. package/provider/index.ts +0 -1
  46. package/provider/provider.tsx +31 -134
  47. package/provider/types.ts +30 -69
  48. package/src/compile/analyze.ts +11 -1
  49. package/src/compile/model.ts +1 -1
  50. package/src/compile/run.ts +2 -2
  51. package/src/define/index.ts +7 -4
  52. package/src/define/manifest.ts +7 -1
  53. package/src/deploy/io.ts +162 -1
  54. package/src/deploy/workflows.ts +1 -1
  55. package/src/dev/harness.ts +30 -43
  56. package/src/dev/native-server.ts +164 -0
  57. package/src/external/envelope.ts +1 -1
  58. package/src/external/service.ts +2 -2
  59. package/src/external/types.ts +1 -1
  60. package/src/rastack-admin.ts +66 -107
  61. package/src/rastack-bootstrap.ts +24 -69
  62. package/src/rastack-design.ts +1 -2
  63. package/src/rastack-dev.ts +79 -91
  64. package/src/rastack-init.ts +50 -41
  65. package/src/rastack.ts +5 -6
  66. package/src/validate/transitions.ts +1 -1
  67. package/dist/rastack-wasm-build.d.ts +0 -19
  68. package/dist/rastack-wasm-build.js +0 -94
  69. package/dist/wasm/package.json +0 -4
  70. package/dist/wasm/rastack_wasm.d.ts +0 -100
  71. package/dist/wasm/rastack_wasm.js +0 -745
  72. package/dist/wasm/rastack_wasm_bg.wasm +0 -0
  73. package/dist/wasm/rastack_wasm_bg.wasm.d.ts +0 -28
  74. package/provider/wasm.ts +0 -126
  75. package/scripts/copy-wasm.js +0 -35
  76. package/src/rastack-wasm-build.ts +0 -113
@@ -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
@@ -11,14 +11,17 @@
11
11
  * 1. writes `.rastack/deploy.json` + `.github/workflows/{ci,deploy-backend}.yml`
12
12
  * (GitHub coordinates default from the `origin` remote; missing fields are
13
13
  * prompted for on a TTY);
14
- * 2. resolves the tier-0 bootstrap stack's artifacts bucket — erroring with a
15
- * pointer to `rastack bootstrap` when that account+region stack is missing
16
- * (init is per-app and never creates account-level infrastructure);
14
+ * 2. verifies the AWS CLI is logged in, then ensures the tier-0 bootstrap stack
15
+ * exists — creating it (the S3 template/placeholder buckets + GitHub OIDC
16
+ * provider) when missing, reconciling it when it already does;
17
17
  * 3. uploads the Lambda placeholder bundle to that bucket;
18
18
  * 4. deploys the per-app backend (app.yaml) with the resolved ArtifactsBucket;
19
19
  * 5. reads the stack Outputs back into the config and prints the two GitHub repo
20
20
  * Variables CI needs.
21
21
  *
22
+ * The CloudFormation templates ship inside the `rastack` package; a partial
23
+ * install falls back to downloading them from reactapistack.com.
24
+ *
22
25
  * Thereafter the recurring code deploy is CI's job — `rastack ci deploy`, which
23
26
  * `rastack deploy` also runs. `--no-deploy` scaffolds only; `--print` shows the
24
27
  * exact single-line `aws cloudformation deploy` commands without running them.
@@ -12,14 +12,17 @@
12
12
  * 1. writes `.rastack/deploy.json` + `.github/workflows/{ci,deploy-backend}.yml`
13
13
  * (GitHub coordinates default from the `origin` remote; missing fields are
14
14
  * prompted for on a TTY);
15
- * 2. resolves the tier-0 bootstrap stack's artifacts bucket — erroring with a
16
- * pointer to `rastack bootstrap` when that account+region stack is missing
17
- * (init is per-app and never creates account-level infrastructure);
15
+ * 2. verifies the AWS CLI is logged in, then ensures the tier-0 bootstrap stack
16
+ * exists — creating it (the S3 template/placeholder buckets + GitHub OIDC
17
+ * provider) when missing, reconciling it when it already does;
18
18
  * 3. uploads the Lambda placeholder bundle to that bucket;
19
19
  * 4. deploys the per-app backend (app.yaml) with the resolved ArtifactsBucket;
20
20
  * 5. reads the stack Outputs back into the config and prints the two GitHub repo
21
21
  * Variables CI needs.
22
22
  *
23
+ * The CloudFormation templates ship inside the `rastack` package; a partial
24
+ * install falls back to downloading them from reactapistack.com.
25
+ *
23
26
  * Thereafter the recurring code deploy is CI's job — `rastack ci deploy`, which
24
27
  * `rastack deploy` also runs. `--no-deploy` scaffolds only; `--print` shows the
25
28
  * exact single-line `aws cloudformation deploy` commands without running them.
@@ -244,8 +247,10 @@ function envLabel(cfg, env) {
244
247
  }
245
248
  /**
246
249
  * Print the exact commands `init` would run, without touching the cloud
247
- * (`--print`). The artifacts bucket is read from the bootstrap stack when the
248
- * AWS CLI is available, else shown as a placeholder.
250
+ * (`--print`). init stands up *both* stacks, so both `aws cloudformation deploy`
251
+ * commands are shown: the tier-0 bootstrap stack (created only when missing) and
252
+ * the per-app backend. The artifacts bucket is read from an existing bootstrap
253
+ * stack when the AWS CLI is available, else shown as a placeholder.
249
254
  */
250
255
  function printPlan(cfg, envs) {
251
256
  const bucket = (0, io_1.awsAvailable)()
@@ -254,11 +259,12 @@ function printPlan(cfg, envs) {
254
259
  const withBucket = (0, config_1.mergeConfig)(cfg, {
255
260
  artifactsBucket: bucket ?? "<ArtifactsBucketName from bootstrap stack>",
256
261
  });
262
+ const bootstrapTemplate = (0, io_1.resolveDeployAsset)("bootstrap.yaml") ?? undefined;
257
263
  const appTemplate = (0, io_1.resolveDeployAsset)("app.yaml") ?? undefined;
258
264
  console.log(`\n Deployment plan (${envs.join(" + ")} @ ${cfg.region})\n`);
259
- console.log(` ── Prerequisite: the tier-0 bootstrap stack (${(0, config_1.bootstrapStackName)(cfg)}) must exist ──`);
260
- console.log(` Create it once per account+region (init does not): rastack bootstrap --region ${cfg.region}\n`);
261
- console.log(" ── 1. Per-app backend (app.yaml) — one stack per environment ──");
265
+ console.log(` ── 1. Tier-0 bootstrap stack (${(0, config_1.bootstrapStackName)(cfg)}) — created only when missing ──`);
266
+ console.log("\n " + (0, config_1.bootstrapStackCommand)(cfg, false, bootstrapTemplate) + "\n");
267
+ console.log(" ── 2. Per-app backend (app.yaml) — one stack per environment ──");
262
268
  for (const env of envs) {
263
269
  const e = (0, config_1.resolveEnvironment)(withBucket, env);
264
270
  console.log(`\n # ${envLabel(withBucket, env)} — stack ${e.stackName}`);
@@ -276,9 +282,12 @@ function printPlan(cfg, envs) {
276
282
  console.log("");
277
283
  }
278
284
  /**
279
- * Stand the infrastructure up: ensure the bootstrap stack + artifacts bucket,
280
- * upload the Lambda placeholder, deploy app.yaml, and read the Outputs back into
281
- * the config. Returns the config enriched with the resolved buckets + outputs.
285
+ * Stand the infrastructure up: verify the AWS CLI is logged in, ensure the
286
+ * tier-0 bootstrap stack (creating it when missing), upload the Lambda
287
+ * placeholder, deploy app.yaml, and read the Outputs back into the config.
288
+ * `init` is the single command that stands up *everything* — there is no
289
+ * separate manual bootstrap step. Returns the config enriched with the resolved
290
+ * buckets + outputs.
282
291
  */
283
292
  async function standUp(cfg, envs, interactive) {
284
293
  if (!(0, io_1.awsAvailable)()) {
@@ -286,23 +295,27 @@ async function standUp(cfg, envs, interactive) {
286
295
  " or re-run with --print to see the commands, or --no-deploy to skip.");
287
296
  process.exit(1);
288
297
  }
289
- // 1. Resolve the artifacts bucket from the tier-0 bootstrap stack. That stack
290
- // is an account+region once-off — the S3 buckets that host the templates +
291
- // Lambda placeholder, and the GitHub OIDC provider. `init` is a per-app
292
- // command and deliberately does NOT create it: standing up account-level
293
- // infrastructure is `rastack bootstrap`'s job (run once by an account admin),
294
- // so a missing bootstrap stack is a clear, actionable error, not an implicit
295
- // account mutation buried inside an app deploy.
296
- const artifactsBucket = (0, io_1.stackOutput)((0, config_1.bootstrapStackName)(cfg), config_1.BOOTSTRAP_ARTIFACTS_OUTPUT, cfg.region);
297
- const templatesBucket = (0, io_1.stackOutput)((0, config_1.bootstrapStackName)(cfg), config_1.BOOTSTRAP_TEMPLATES_OUTPUT, cfg.region);
298
- if (!artifactsBucket) {
299
- console.error(`\n ✗ Bootstrap stack ${(0, config_1.bootstrapStackName)(cfg)} not found in ${cfg.region}.\n` +
300
- " It is the once-per-account+region step that hosts the CloudFormation\n" +
301
- " templates and the Lambda placeholder every app deploy reads. Create it\n" +
302
- " first (an account admin does this once), then re-run `rastack init`:\n\n" +
303
- ` rastack bootstrap --region ${cfg.region}\n`);
298
+ // Verify the AWS CLI is actually logged in before creating any stacks, so a
299
+ // missing/expired credential fails fast with an actionable message rather than
300
+ // a cryptic `cloudformation deploy` error partway through.
301
+ const account = (0, io_1.awsIdentity)(cfg.region);
302
+ if (!account) {
303
+ console.error(" ✗ the AWS CLI has no usable credentials — it is not logged in.\n" +
304
+ " Configure credentials, then re-run `rastack init`:\n" +
305
+ " aws configure # static access key / secret\n" +
306
+ " aws sso login # or an existing SSO session\n" +
307
+ " Or re-run with --print to see the commands, or --no-deploy to skip.");
304
308
  process.exit(1);
305
309
  }
310
+ console.log(` ✓ AWS account ${account} (${cfg.region})`);
311
+ // 1. Ensure the tier-0 bootstrap stack exists — the S3 buckets that host the
312
+ // templates + Lambda placeholder and the GitHub OIDC provider. init creates
313
+ // it when missing (idempotent for an existing one), so a single command
314
+ // takes an account+repo from nothing to a deployed backend.
315
+ const { artifactsBucket, templatesBucket } = await (0, io_1.ensureBootstrapStack)(cfg).catch((err) => {
316
+ console.error(`\n ✗ ${err.message}`);
317
+ process.exit(1);
318
+ });
306
319
  console.log(` ✓ artifacts bucket: ${artifactsBucket}`);
307
320
  // 2. Upload the placeholder the function is created from (shared by all envs).
308
321
  console.log("\n▸ Uploading the Lambda placeholder bundle");
@@ -314,10 +327,10 @@ async function standUp(cfg, envs, interactive) {
314
327
  artifactsBucket,
315
328
  templatesBucket: templatesBucket ?? undefined,
316
329
  });
317
- const appTemplate = (0, io_1.resolveDeployAsset)("app.yaml");
330
+ const appTemplate = await (0, io_1.resolveTemplateFile)("app.yaml");
318
331
  if (!appTemplate) {
319
- console.error(" ✗ app.yaml template not found in the rastack package. Reinstall rastack\n" +
320
- " (`npm i -g rastack`) or run from the framework repo.");
332
+ console.error(" ✗ app.yaml template not found in the rastack package and could not be\n" +
333
+ " downloaded from reactapistack.com. Reinstall rastack (`npm i -g rastack`).");
321
334
  process.exit(1);
322
335
  }
323
336
  // 3. Deploy one stack per environment — each with its own Cognito pool,
@@ -501,7 +514,7 @@ async function main(argv) {
501
514
  const stacks = flags.envs
502
515
  .map((env) => (0, config_1.resolveEnvironment)(cfg, env).stackName)
503
516
  .join(" + ");
504
- const ok = await confirm(`Deploy ${stacks} to AWS ${cfg.region} now? (requires the bootstrap stack to exist) [y/N]`);
517
+ const ok = await confirm(`Deploy ${stacks} to AWS ${cfg.region} now? (creates the bootstrap stack if missing) [y/N]`);
505
518
  if (!ok) {
506
519
  console.log("\n Skipped the deploy. Re-run to deploy, or `rastack init --print` for the commands.\n");
507
520
  return;
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.63",
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,