rastack 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/cache/cache.ts +1 -1
- package/cache/revocation.ts +1 -1
- package/cache/storage.ts +1 -1
- package/cache/types.ts +1 -1
- package/define.ts +2 -0
- package/dist/compile/analyze.js +3 -3
- package/dist/compile/entities.d.ts +68 -0
- package/dist/compile/entities.js +496 -0
- package/dist/compile/index.d.ts +24 -7
- package/dist/compile/index.js +48 -16
- package/dist/compile/model.d.ts +2 -2
- package/dist/compile/model.js +1 -1
- package/dist/compile/program.d.ts +2 -1
- package/dist/compile/program.js +8 -3
- package/dist/csv-schema.js +1 -1
- package/dist/define/db.d.ts +73 -0
- package/dist/define/db.js +35 -0
- package/dist/define/index.d.ts +8 -8
- package/dist/define/index.js +10 -10
- package/dist/index.js +1 -1
- package/dist/rastack-compile.d.ts +11 -0
- package/dist/{rad-compile.js → rastack-compile.js} +22 -12
- package/dist/{rad-wasm-build.d.ts → rastack-wasm-build.d.ts} +2 -2
- package/dist/{rad-wasm-build.js → rastack-wasm-build.js} +6 -6
- package/dist/rastack.d.ts +17 -0
- package/dist/{rad.js → rastack.js} +24 -24
- package/dist/scan.d.ts +3 -3
- package/dist/scan.js +4 -4
- package/dist/seed.d.ts +2 -2
- package/dist/seed.js +9 -9
- package/hooks/real-time/pusher.ts +2 -2
- package/package.json +2 -3
- package/provider/provider.tsx +12 -12
- package/provider/types.ts +16 -16
- package/provider/warehouse.ts +1 -1
- package/provider/wasm.ts +10 -10
- package/src/compile/analyze.ts +3 -3
- package/src/compile/entities.ts +602 -0
- package/src/compile/index.ts +57 -15
- package/src/compile/model.ts +2 -2
- package/src/compile/program.ts +8 -3
- package/src/csv-schema.ts +1 -1
- package/src/define/db.ts +64 -0
- package/src/define/index.ts +16 -16
- package/src/index.ts +1 -1
- package/src/{rad-compile.ts → rastack-compile.ts} +30 -13
- package/src/{rad-wasm-build.ts → rastack-wasm-build.ts} +6 -6
- package/src/{rad.ts → rastack.ts} +24 -24
- package/src/scan.ts +4 -4
- package/src/seed.ts +9 -9
- package/sync/engine.ts +1 -1
- package/sync/types.ts +1 -1
- package/test/cache.spec.ts +1 -1
- package/test/compile.spec.ts +6 -6
- package/test/csv-schema.spec.ts +2 -2
- package/test/entities.spec.ts +381 -0
- package/types.ts +3 -0
- package/dist/rad-compile.d.ts +0 -11
- package/dist/rad.d.ts +0 -17
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* rastack — unified CLI for React API Stack
|
|
5
5
|
*
|
|
6
6
|
* Commands:
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
7
|
+
* rastack compile [resourcesDir] [outDir] TypeScript resources → schema.rastack.json + openapi.json
|
|
8
|
+
* rastack check [resourcesDir] Validate the resource graph
|
|
9
|
+
* rastack list [resourcesDir] Print resources, fields and relations
|
|
10
|
+
* rastack urls [resourcesDir] Print the generated /api/{app}/v1/{model}/ routes
|
|
11
|
+
* rastack generate [--schema-only] Generate typed hooks from OpenAPI
|
|
12
|
+
* rastack serve [--warehouse dir] Run the Rust API over an Iceberg warehouse
|
|
13
|
+
* rastack admin [--warehouse dir] Run the Rust admin (Django-admin-style DB browser)
|
|
14
|
+
* rastack wasm Compile the API to WebAssembly (in-browser local dev)
|
|
15
|
+
* rastack scan [files...] [--fail-on-pii] Scan CSVs for PII and schema info
|
|
16
|
+
* rastack seed [--env dev] [--source gs://] Load CSVs into Iceberg namespace
|
|
17
17
|
*/
|
|
18
18
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
19
19
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -23,7 +23,7 @@ const child_process_1 = require("child_process");
|
|
|
23
23
|
const path_1 = __importDefault(require("path"));
|
|
24
24
|
const [command, ...rest] = process.argv.slice(2);
|
|
25
25
|
function run(script, args = rest) {
|
|
26
|
-
// `
|
|
26
|
+
// `rastack` is a local developer CLI: `script` is a fixed internal dist filename
|
|
27
27
|
// and `args` come from the developer's own shell (process.argv), not from an
|
|
28
28
|
// untrusted network request — there is no command-injection surface here.
|
|
29
29
|
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
@@ -35,8 +35,8 @@ function run(script, args = rest) {
|
|
|
35
35
|
/** Invoke the compiled Rust server binary (built by `cargo build` in rust/). */
|
|
36
36
|
function runRust(subcommand) {
|
|
37
37
|
const repoRoot = path_1.default.resolve(__dirname, "..", "..");
|
|
38
|
-
const binary = process.env.
|
|
39
|
-
path_1.default.join(repoRoot, "rust", "target", "release", "
|
|
38
|
+
const binary = process.env.RASTACK_SERVER_BIN ||
|
|
39
|
+
path_1.default.join(repoRoot, "rust", "target", "release", "rastack-server");
|
|
40
40
|
// Runs the locally-built Rust server binary with a fixed internal subcommand
|
|
41
41
|
// ("serve"/"admin"); `rest` is the developer's own CLI args, not untrusted
|
|
42
42
|
// input — no command-injection surface.
|
|
@@ -57,8 +57,8 @@ switch (command) {
|
|
|
57
57
|
case "check":
|
|
58
58
|
case "list":
|
|
59
59
|
case "urls":
|
|
60
|
-
//
|
|
61
|
-
run("
|
|
60
|
+
// rastack-compile dispatches on its own first argument, so pass the command.
|
|
61
|
+
run("rastack-compile.js", [command, ...rest]);
|
|
62
62
|
break;
|
|
63
63
|
case "serve":
|
|
64
64
|
runRust("serve");
|
|
@@ -68,7 +68,7 @@ switch (command) {
|
|
|
68
68
|
break;
|
|
69
69
|
case "wasm":
|
|
70
70
|
// Compile the API to WebAssembly for in-browser local dev.
|
|
71
|
-
run("
|
|
71
|
+
run("rastack-wasm-build.js", rest);
|
|
72
72
|
break;
|
|
73
73
|
case "scan":
|
|
74
74
|
run("scan.js");
|
|
@@ -84,12 +84,12 @@ switch (command) {
|
|
|
84
84
|
default:
|
|
85
85
|
console.error(`Unknown command: "${command}"\n\n` +
|
|
86
86
|
`Usage:\n` +
|
|
87
|
-
`
|
|
88
|
-
`
|
|
89
|
-
`
|
|
90
|
-
`
|
|
91
|
-
`
|
|
92
|
-
`
|
|
93
|
-
`
|
|
87
|
+
` rastack compile [resourcesDir] [outDir]\n` +
|
|
88
|
+
` rastack check | list | urls [resourcesDir]\n` +
|
|
89
|
+
` rastack generate [--schema-only]\n` +
|
|
90
|
+
` rastack serve | admin [--warehouse dir]\n` +
|
|
91
|
+
` rastack wasm Compile the API to WebAssembly (browser local dev)\n` +
|
|
92
|
+
` rastack scan [files...] [--fail-on-pii]\n` +
|
|
93
|
+
` rastack seed [--env dev|staging] [--source gs://bucket/ | ./myapp-dev/]\n`);
|
|
94
94
|
process.exit(1);
|
|
95
95
|
}
|
package/dist/scan.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* rastack scan
|
|
4
4
|
*
|
|
5
5
|
* Scans CSV files in myapp-dev/ for PII column patterns and schema issues.
|
|
6
6
|
* Exits non-zero if violations are found and --fail-on-pii is passed.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* rastack scan [files...] [--fail-on-pii]
|
|
10
|
+
* rastack scan myapp-dev/passengers.csv myapp-dev/flights.csv --fail-on-pii
|
|
11
11
|
*/
|
|
12
12
|
export {};
|
package/dist/scan.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* rastack scan
|
|
5
5
|
*
|
|
6
6
|
* Scans CSV files in myapp-dev/ for PII column patterns and schema issues.
|
|
7
7
|
* Exits non-zero if violations are found and --fail-on-pii is passed.
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* rastack scan [files...] [--fail-on-pii]
|
|
11
|
+
* rastack scan myapp-dev/passengers.csv myapp-dev/flights.csv --fail-on-pii
|
|
12
12
|
*/
|
|
13
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -70,7 +70,7 @@ if (hasErrors) {
|
|
|
70
70
|
if (totalViolations > 0) {
|
|
71
71
|
console.warn(`Scan found ${totalViolations} PII violation(s) across ${files.length} file(s).`);
|
|
72
72
|
if (failOnPii) {
|
|
73
|
-
console.error("Failing because --fail-on-pii is set. Remove PII data or add access policies in .
|
|
73
|
+
console.error("Failing because --fail-on-pii is set. Remove PII data or add access policies in .rastack/policies/.");
|
|
74
74
|
process.exit(1);
|
|
75
75
|
}
|
|
76
76
|
}
|
package/dist/seed.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* rastack seed
|
|
4
4
|
*
|
|
5
5
|
* Loads CSV files from a local directory or GCS bucket into the target
|
|
6
6
|
* Iceberg namespace. Performs schema inference, PII check, and idempotent
|
|
7
7
|
* table creation before writing rows.
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
|
-
*
|
|
10
|
+
* rastack seed [--env dev|staging] [--source gs://bucket/ | --source ./myapp-dev/]
|
|
11
11
|
*
|
|
12
12
|
* Environment variables (set via CI secrets or .env):
|
|
13
13
|
* GCP_PROJECT GCP project ID
|
package/dist/seed.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* rastack seed
|
|
5
5
|
*
|
|
6
6
|
* Loads CSV files from a local directory or GCS bucket into the target
|
|
7
7
|
* Iceberg namespace. Performs schema inference, PII check, and idempotent
|
|
8
8
|
* table creation before writing rows.
|
|
9
9
|
*
|
|
10
10
|
* Usage:
|
|
11
|
-
*
|
|
11
|
+
* rastack seed [--env dev|staging] [--source gs://bucket/ | --source ./myapp-dev/]
|
|
12
12
|
*
|
|
13
13
|
* Environment variables (set via CI secrets or .env):
|
|
14
14
|
* GCP_PROJECT GCP project ID
|
|
@@ -44,10 +44,10 @@ function resolveFiles() {
|
|
|
44
44
|
return (0, csv_schema_1.discoverCsvFiles)(source);
|
|
45
45
|
}
|
|
46
46
|
function downloadFromGcs(gcsUri) {
|
|
47
|
-
const tmpDir = path_1.default.join(repoRoot, ".
|
|
47
|
+
const tmpDir = path_1.default.join(repoRoot, ".rastack", "tmp", "seed");
|
|
48
48
|
fs_1.default.mkdirSync(tmpDir, { recursive: true });
|
|
49
49
|
console.log(`Downloading CSVs from ${gcsUri} ...`);
|
|
50
|
-
// `
|
|
50
|
+
// `rastack seed` is a local/CI developer tool; `gcsUri` is an operator-supplied
|
|
51
51
|
// --source argument (a gs:// bucket the operator controls), not untrusted
|
|
52
52
|
// network input, so there is no command-injection surface here.
|
|
53
53
|
try {
|
|
@@ -75,7 +75,7 @@ function validateSchema(csvPath) {
|
|
|
75
75
|
.map((v) => ` ${v.column}: ${v.reason}`)
|
|
76
76
|
.join("\n");
|
|
77
77
|
throw new Error(`PII detected in ${path_1.default.basename(csvPath)}:\n${list}\n` +
|
|
78
|
-
`Remove PII data before seeding. Run "
|
|
78
|
+
`Remove PII data before seeding. Run "rastack scan" to review.`);
|
|
79
79
|
}
|
|
80
80
|
return schema;
|
|
81
81
|
}
|
|
@@ -118,7 +118,7 @@ function buildCreateTableSql(schema, namespace) {
|
|
|
118
118
|
// Step 4: write schema fingerprints to registry
|
|
119
119
|
// ---------------------------------------------------------------------------
|
|
120
120
|
function writeFingerprint(schema) {
|
|
121
|
-
const registryDir = path_1.default.join(repoRoot, ".
|
|
121
|
+
const registryDir = path_1.default.join(repoRoot, ".rastack", "registry");
|
|
122
122
|
fs_1.default.mkdirSync(registryDir, { recursive: true });
|
|
123
123
|
const registryPath = path_1.default.join(registryDir, `${schema.tableName}.json`);
|
|
124
124
|
let existing = {};
|
|
@@ -216,16 +216,16 @@ async function main() {
|
|
|
216
216
|
writeFingerprint(schema);
|
|
217
217
|
}
|
|
218
218
|
// Emit DDL summary
|
|
219
|
-
const ddlDir = path_1.default.join(repoRoot, ".
|
|
219
|
+
const ddlDir = path_1.default.join(repoRoot, ".rastack", "ddl");
|
|
220
220
|
fs_1.default.mkdirSync(ddlDir, { recursive: true });
|
|
221
221
|
for (const schema of schemas) {
|
|
222
222
|
const ddl = buildCreateTableSql(schema, env);
|
|
223
223
|
fs_1.default.writeFileSync(path_1.default.join(ddlDir, `${schema.tableName}.sql`), ddl + "\n");
|
|
224
224
|
}
|
|
225
|
-
console.log(`\nDDL written to .
|
|
225
|
+
console.log(`\nDDL written to .rastack/ddl/`);
|
|
226
226
|
// Run Python seed via pyiceberg if available
|
|
227
227
|
const seedScript = buildPythonSeedScript(schemas, files);
|
|
228
|
-
const scriptPath = path_1.default.join(repoRoot, ".
|
|
228
|
+
const scriptPath = path_1.default.join(repoRoot, ".rastack", "tmp", "seed.py");
|
|
229
229
|
fs_1.default.mkdirSync(path_1.default.dirname(scriptPath), { recursive: true });
|
|
230
230
|
fs_1.default.writeFileSync(scriptPath, seedScript);
|
|
231
231
|
const pythonBin = process.env.PYTHON ?? "python";
|
|
@@ -2,7 +2,7 @@ import { useEffect } from "react";
|
|
|
2
2
|
import { useSyncEngineOptional } from "../../sync/provider";
|
|
3
3
|
|
|
4
4
|
export interface PusherWakeOptions {
|
|
5
|
-
/** Channel to subscribe to. Defaults to "
|
|
5
|
+
/** Channel to subscribe to. Defaults to "rastack-sync". */
|
|
6
6
|
channel?: string;
|
|
7
7
|
/** Event name carrying sync notifications. Defaults to "sync". */
|
|
8
8
|
event?: string;
|
|
@@ -20,7 +20,7 @@ export interface PusherWakeOptions {
|
|
|
20
20
|
*/
|
|
21
21
|
export function usePusher(options?: PusherWakeOptions) {
|
|
22
22
|
const engine = useSyncEngineOptional();
|
|
23
|
-
const channelName = options?.channel || "
|
|
23
|
+
const channelName = options?.channel || "rastack-sync";
|
|
24
24
|
const eventName = options?.event || "sync";
|
|
25
25
|
const client =
|
|
26
26
|
options?.client ??
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rastack",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "runtime.ts",
|
|
6
6
|
"types": "runtime.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"rastack": "dist/
|
|
9
|
-
"rad": "dist/rad.js"
|
|
8
|
+
"rastack": "dist/rastack.js"
|
|
10
9
|
},
|
|
11
10
|
"publishConfig": {
|
|
12
11
|
"access": "public"
|
package/provider/provider.tsx
CHANGED
|
@@ -9,8 +9,8 @@ import React, {
|
|
|
9
9
|
} from "react";
|
|
10
10
|
import { API, configureApi, resetApi } from "../hooks/query/api";
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
RastackClient,
|
|
13
|
+
RastackEngine,
|
|
14
14
|
RAStackProviderConfig,
|
|
15
15
|
RadStatus,
|
|
16
16
|
WarehouseSource,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
purgeIdentityCache,
|
|
34
34
|
} from "../cache";
|
|
35
35
|
|
|
36
|
-
const
|
|
36
|
+
const RastackContext = createContext<RastackClient | null>(null);
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* The one place a React app configures *where the API runs* — over HTTP
|
|
@@ -52,7 +52,7 @@ export function RAStackProvider({
|
|
|
52
52
|
...config
|
|
53
53
|
}: RAStackProviderConfig & { children: ReactNode }): JSX.Element {
|
|
54
54
|
const [status, setStatus] = useState<RadStatus>("idle");
|
|
55
|
-
const engineRef = useRef<
|
|
55
|
+
const engineRef = useRef<RastackEngine | null>(null);
|
|
56
56
|
const persistRef = useRef<(() => void) & { flush: () => void }>();
|
|
57
57
|
const cacheStorageRef = useRef<CacheStorage | null>(null);
|
|
58
58
|
|
|
@@ -64,7 +64,7 @@ export function RAStackProvider({
|
|
|
64
64
|
// Locally persisted state is namespaced per identity, so two accounts on
|
|
65
65
|
// one device never share bytes.
|
|
66
66
|
const warehouseDb = withIdentity(
|
|
67
|
-
config.databaseName || "
|
|
67
|
+
config.databaseName || "rastack-warehouse",
|
|
68
68
|
config.identity,
|
|
69
69
|
);
|
|
70
70
|
|
|
@@ -76,7 +76,7 @@ export function RAStackProvider({
|
|
|
76
76
|
await deleteIndexedDb(warehouseDb);
|
|
77
77
|
// Replicated rows in the sync engine's store are derived from the same
|
|
78
78
|
// access — they go too.
|
|
79
|
-
await deleteIndexedDb(config.syncDatabaseName || "
|
|
79
|
+
await deleteIndexedDb(config.syncDatabaseName || "rastack-sync");
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
/** Revocation entry point shared by automatic detection and app signals. */
|
|
@@ -196,7 +196,7 @@ export function RAStackProvider({
|
|
|
196
196
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
197
197
|
}, [config.mode, config.baseURL, config.warehouseBaseUrl, config.identity]);
|
|
198
198
|
|
|
199
|
-
const client = useMemo<
|
|
199
|
+
const client = useMemo<RastackClient>(
|
|
200
200
|
() => ({
|
|
201
201
|
mode: config.mode,
|
|
202
202
|
status,
|
|
@@ -227,7 +227,7 @@ export function RAStackProvider({
|
|
|
227
227
|
[config.mode, status, config.identity],
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
-
return <
|
|
230
|
+
return <RastackContext.Provider value={client}>{children}</RastackContext.Provider>;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
function pickPersistence(
|
|
@@ -255,15 +255,15 @@ function withIdentity(name: string, identity?: string): string {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
/** Access the imperative Rad client (engine, status, warehouse helpers). */
|
|
258
|
-
export function
|
|
259
|
-
const client = useContext(
|
|
258
|
+
export function useRastackClient(): RastackClient {
|
|
259
|
+
const client = useContext(RastackContext);
|
|
260
260
|
if (!client) {
|
|
261
|
-
throw new Error("
|
|
261
|
+
throw new Error("useRastackClient must be used within a <RAStackProvider>.");
|
|
262
262
|
}
|
|
263
263
|
return client;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
/** Just the current status — handy for a loading gate while WASM boots. */
|
|
267
267
|
export function useRadStatus(): RadStatus {
|
|
268
|
-
return
|
|
268
|
+
return useRastackClient().status;
|
|
269
269
|
}
|
package/provider/types.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Configuration for `<RAStackProvider>` — the single place a React app chooses
|
|
3
3
|
* *where the API runs*:
|
|
4
4
|
*
|
|
5
|
-
* - `remote` — talk to the Rust API over HTTP (Lambda in prod, `
|
|
5
|
+
* - `remote` — talk to the Rust API over HTTP (Lambda in prod, `rastack serve`
|
|
6
6
|
* locally). The classic client/server split.
|
|
7
7
|
* - `local` — compile-free local development: the entire API runs in the
|
|
8
8
|
* browser via WebAssembly over an in-memory Iceberg warehouse, seeded from a
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export type RadMode = "remote" | "local" | "s3";
|
|
16
16
|
|
|
17
|
-
/** The subset of the WASM `
|
|
18
|
-
export interface
|
|
17
|
+
/** The subset of the WASM `RastackApi` class the provider uses. */
|
|
18
|
+
export interface RastackEngine {
|
|
19
19
|
handle(
|
|
20
20
|
method: string,
|
|
21
21
|
path: string,
|
|
@@ -34,21 +34,21 @@ export interface RadEngine {
|
|
|
34
34
|
setAuth?(subject: string | undefined, groups?: string[]): void;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/** Constructor of the generated `
|
|
38
|
-
export interface
|
|
39
|
-
new (manifestJson: string, openapiJson?: string):
|
|
37
|
+
/** Constructor of the generated `RastackApi` class. */
|
|
38
|
+
export interface RastackEngineCtor {
|
|
39
|
+
new (manifestJson: string, openapiJson?: string): RastackEngine;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/** What a WASM bundle loader must resolve to. */
|
|
43
|
-
export interface
|
|
43
|
+
export interface RastackWasmModule {
|
|
44
44
|
/** wasm-pack `web` target exposes an init fn that fetches the `.wasm`. */
|
|
45
45
|
default?: (input?: any) => Promise<any>;
|
|
46
46
|
init?: (input?: any) => Promise<any>;
|
|
47
|
-
|
|
47
|
+
RastackApi: RastackEngineCtor;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/** Load and initialise the compiled WASM engine module. */
|
|
51
|
-
export type
|
|
51
|
+
export type RastackEngineLoader = () => Promise<RastackWasmModule>;
|
|
52
52
|
|
|
53
53
|
/** Where to read/write the warehouse blob in `s3` mode (or any custom sink). */
|
|
54
54
|
export interface WarehouseSource {
|
|
@@ -84,7 +84,7 @@ export interface RAStackProviderConfig {
|
|
|
84
84
|
*/
|
|
85
85
|
onAccessRevoked?: () => void;
|
|
86
86
|
/**
|
|
87
|
-
* The sync engine's IndexedDB database (`
|
|
87
|
+
* The sync engine's IndexedDB database (`rastack-sync` by default) so
|
|
88
88
|
* revocation and `purgeLocal()` erase replicated rows too. Set to the same
|
|
89
89
|
* `databaseName` you pass the sync engine if you changed it.
|
|
90
90
|
*/
|
|
@@ -97,7 +97,7 @@ export interface RAStackProviderConfig {
|
|
|
97
97
|
maxOfflineMs?: number;
|
|
98
98
|
|
|
99
99
|
// -- local / s3 mode --
|
|
100
|
-
/** `schema.
|
|
100
|
+
/** `schema.rastack.json` — object or JSON string. Required for WASM modes. */
|
|
101
101
|
manifest?: object | string;
|
|
102
102
|
/** `openapi.json` — object or JSON string. Optional (`/api/schema/`). */
|
|
103
103
|
openapi?: object | string;
|
|
@@ -133,9 +133,9 @@ export interface RAStackProviderConfig {
|
|
|
133
133
|
/**
|
|
134
134
|
* Override how the WASM module is loaded. Supply this from app code (where
|
|
135
135
|
* your bundler can resolve the generated bundle) if the default loader can't
|
|
136
|
-
* find it. Defaults to importing `rastack/wasm/
|
|
136
|
+
* find it. Defaults to importing `rastack/wasm/rastack_wasm.js`.
|
|
137
137
|
*/
|
|
138
|
-
loadEngine?:
|
|
138
|
+
loadEngine?: RastackEngineLoader;
|
|
139
139
|
|
|
140
140
|
// -- lifecycle --
|
|
141
141
|
onStatusChange?: (status: RadStatus) => void;
|
|
@@ -150,12 +150,12 @@ export type RadStatus =
|
|
|
150
150
|
| "revoked" // access revoked — local data has been deleted
|
|
151
151
|
| "error";
|
|
152
152
|
|
|
153
|
-
/** Imperative handle exposed via `
|
|
154
|
-
export interface
|
|
153
|
+
/** Imperative handle exposed via `useRastackClient()`. */
|
|
154
|
+
export interface RastackClient {
|
|
155
155
|
mode: RadMode;
|
|
156
156
|
status: RadStatus;
|
|
157
157
|
/** The live WASM engine (null in `remote` mode). */
|
|
158
|
-
engine:
|
|
158
|
+
engine: RastackEngine | null;
|
|
159
159
|
/** Snapshot the local warehouse to a portable blob (WASM modes only). */
|
|
160
160
|
exportWarehouse(): Promise<Uint8Array>;
|
|
161
161
|
/** Download that snapshot as a file — a portable backup of local edits. */
|
package/provider/warehouse.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Persistence for the in-browser warehouse blob produced by
|
|
3
|
-
* `
|
|
3
|
+
* `RastackApi.exportWarehouse()`. A single blob (the whole Iceberg warehouse)
|
|
4
4
|
* lives in a one-row IndexedDB store so `local` mode survives reloads; `s3`
|
|
5
5
|
* mode swaps this for a {@link WarehouseSource} over object storage.
|
|
6
6
|
*/
|
package/provider/wasm.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AxiosAdapter, AxiosError, AxiosResponse } from "axios";
|
|
2
|
-
import {
|
|
2
|
+
import { RastackEngine, RastackEngineLoader, RastackWasmModule } from "./types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Default WASM loader: import the bundle `
|
|
6
|
-
* (`rastack/wasm/
|
|
5
|
+
* Default WASM loader: import the bundle `rastack wasm` generates
|
|
6
|
+
* (`rastack/wasm/rastack_wasm.js`) and run its init. The indirection through
|
|
7
7
|
* `new Function` keeps a genuine dynamic `import()` at runtime even when the
|
|
8
8
|
* package is transpiled to CommonJS, so the consumer's bundler resolves and
|
|
9
9
|
* code-splits the `.wasm`.
|
|
@@ -12,8 +12,8 @@ const runtimeImport: (specifier: string) => Promise<any> =
|
|
|
12
12
|
// eslint-disable-next-line no-new-func
|
|
13
13
|
new Function("s", "return import(s)") as any;
|
|
14
14
|
|
|
15
|
-
export const defaultEngineLoader:
|
|
16
|
-
const mod:
|
|
15
|
+
export const defaultEngineLoader: RastackEngineLoader = async () => {
|
|
16
|
+
const mod: RastackWasmModule = await runtimeImport("rastack/wasm/rastack_wasm.js");
|
|
17
17
|
const init = mod.default || mod.init;
|
|
18
18
|
if (typeof init === "function") {
|
|
19
19
|
await init();
|
|
@@ -23,14 +23,14 @@ export const defaultEngineLoader: RadEngineLoader = async () => {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Instantiate the engine from a loaded module and the compiled schema. The
|
|
26
|
-
* manifest/openapi are passed as JSON strings — the same `schema.
|
|
26
|
+
* manifest/openapi are passed as JSON strings — the same `schema.rastack.json` /
|
|
27
27
|
* `openapi.json` the Rust server reads.
|
|
28
28
|
*/
|
|
29
29
|
export function createEngine(
|
|
30
|
-
mod:
|
|
30
|
+
mod: RastackWasmModule,
|
|
31
31
|
manifest: object | string,
|
|
32
32
|
openapi?: object | string,
|
|
33
|
-
):
|
|
33
|
+
): RastackEngine {
|
|
34
34
|
const manifestJson =
|
|
35
35
|
typeof manifest === "string" ? manifest : JSON.stringify(manifest);
|
|
36
36
|
const openapiJson =
|
|
@@ -39,7 +39,7 @@ export function createEngine(
|
|
|
39
39
|
: typeof openapi === "string"
|
|
40
40
|
? openapi
|
|
41
41
|
: JSON.stringify(openapi);
|
|
42
|
-
return new mod.
|
|
42
|
+
return new mod.RastackApi(manifestJson, openapiJson);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
const MUTATING = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
@@ -55,7 +55,7 @@ const MUTATING = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
|
55
55
|
* persist of the warehouse.
|
|
56
56
|
*/
|
|
57
57
|
export function createWasmAdapter(
|
|
58
|
-
engine:
|
|
58
|
+
engine: RastackEngine,
|
|
59
59
|
onWrite?: () => void,
|
|
60
60
|
): AxiosAdapter {
|
|
61
61
|
return async (config: any): Promise<AxiosResponse> => {
|
package/src/compile/analyze.ts
CHANGED
|
@@ -111,7 +111,7 @@ function analyzeField(
|
|
|
111
111
|
|
|
112
112
|
// Foreign key: the field type is Ref<App, Model>. Recover the target from
|
|
113
113
|
// the string-literal type arguments — this is the "infer FK from types" step.
|
|
114
|
-
if (fieldType.getProperty("
|
|
114
|
+
if (fieldType.getProperty("__rastackRef")) {
|
|
115
115
|
const app = literalTypeProp(fieldType, "__app", checker, initializer);
|
|
116
116
|
const model = literalTypeProp(fieldType, "__model", checker, initializer);
|
|
117
117
|
if (app && model) {
|
|
@@ -120,8 +120,8 @@ function analyzeField(
|
|
|
120
120
|
return undefined;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// Scalar: the field type carries a `
|
|
124
|
-
const scalar = literalTypeProp(fieldType, "
|
|
123
|
+
// Scalar: the field type carries a `__rastackScalar` string-literal discriminant.
|
|
124
|
+
const scalar = literalTypeProp(fieldType, "__rastackScalar", checker, initializer);
|
|
125
125
|
if (!scalar) return undefined;
|
|
126
126
|
|
|
127
127
|
const field: FieldModel = { name, type: scalar as ScalarType };
|