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.
- package/CHANGELOG.md +32 -0
- package/README.md +19 -24
- package/admin/AdminApp.tsx +56 -3
- package/admin/httpEngine.ts +5 -6
- package/admin/index.tsx +11 -85
- package/admin/ui/icons.tsx +9 -0
- package/admin/ui/styles.ts +3 -0
- package/admin/useAdmin.ts +41 -4
- package/dist/admin.js +17 -22
- package/dist/compile/analyze.js +11 -1
- 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 +10 -4
- package/dist/define/index.js +2 -2
- package/dist/define/manifest.js +7 -1
- package/dist/deploy/io.d.ts +50 -0
- package/dist/deploy/io.js +124 -0
- 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-bootstrap.js +18 -47
- 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-init.d.ts +6 -3
- package/dist/rastack-init.js +43 -30
- 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 -134
- package/provider/types.ts +30 -69
- package/src/compile/analyze.ts +11 -1
- package/src/compile/model.ts +1 -1
- package/src/compile/run.ts +2 -2
- package/src/define/index.ts +7 -4
- package/src/define/manifest.ts +7 -1
- package/src/deploy/io.ts +162 -1
- 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-bootstrap.ts +24 -69
- package/src/rastack-design.ts +1 -2
- package/src/rastack-dev.ts +79 -91
- package/src/rastack-init.ts +50 -41
- 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-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-init.d.ts
CHANGED
|
@@ -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.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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.
|
package/dist/rastack-init.js
CHANGED
|
@@ -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.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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`).
|
|
248
|
-
*
|
|
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(` ──
|
|
260
|
-
console.log(
|
|
261
|
-
console.log(" ──
|
|
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:
|
|
280
|
-
*
|
|
281
|
-
*
|
|
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
|
-
//
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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.
|
|
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
|
|
320
|
-
" (`npm i -g rastack`)
|
|
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? (
|
|
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:
|
|
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"
|