rastack 0.0.22 → 0.0.23

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 (60) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/cache/cache.ts +1 -1
  3. package/cache/revocation.ts +1 -1
  4. package/cache/storage.ts +1 -1
  5. package/cache/types.ts +1 -1
  6. package/define.ts +2 -0
  7. package/dist/compile/analyze.js +3 -3
  8. package/dist/compile/entities.d.ts +68 -0
  9. package/dist/compile/entities.js +496 -0
  10. package/dist/compile/index.d.ts +24 -7
  11. package/dist/compile/index.js +48 -16
  12. package/dist/compile/model.d.ts +2 -2
  13. package/dist/compile/model.js +1 -1
  14. package/dist/compile/program.d.ts +2 -1
  15. package/dist/compile/program.js +8 -3
  16. package/dist/csv-schema.js +1 -1
  17. package/dist/define/db.d.ts +73 -0
  18. package/dist/define/db.js +35 -0
  19. package/dist/define/index.d.ts +8 -8
  20. package/dist/define/index.js +10 -10
  21. package/dist/index.js +1 -1
  22. package/dist/rastack-compile.d.ts +11 -0
  23. package/dist/{rad-compile.js → rastack-compile.js} +22 -12
  24. package/dist/{rad-wasm-build.d.ts → rastack-wasm-build.d.ts} +2 -2
  25. package/dist/{rad-wasm-build.js → rastack-wasm-build.js} +6 -6
  26. package/dist/rastack.d.ts +17 -0
  27. package/dist/{rad.js → rastack.js} +24 -24
  28. package/dist/scan.d.ts +3 -3
  29. package/dist/scan.js +4 -4
  30. package/dist/seed.d.ts +2 -2
  31. package/dist/seed.js +9 -9
  32. package/hooks/real-time/pusher.ts +2 -2
  33. package/package.json +2 -3
  34. package/provider/provider.tsx +12 -12
  35. package/provider/types.ts +16 -16
  36. package/provider/warehouse.ts +1 -1
  37. package/provider/wasm.ts +10 -10
  38. package/src/compile/analyze.ts +3 -3
  39. package/src/compile/entities.ts +602 -0
  40. package/src/compile/index.ts +57 -15
  41. package/src/compile/model.ts +2 -2
  42. package/src/compile/program.ts +8 -3
  43. package/src/csv-schema.ts +1 -1
  44. package/src/define/db.ts +64 -0
  45. package/src/define/index.ts +16 -16
  46. package/src/index.ts +1 -1
  47. package/src/{rad-compile.ts → rastack-compile.ts} +30 -13
  48. package/src/{rad-wasm-build.ts → rastack-wasm-build.ts} +6 -6
  49. package/src/{rad.ts → rastack.ts} +24 -24
  50. package/src/scan.ts +4 -4
  51. package/src/seed.ts +9 -9
  52. package/sync/engine.ts +1 -1
  53. package/sync/types.ts +1 -1
  54. package/test/cache.spec.ts +1 -1
  55. package/test/compile.spec.ts +6 -6
  56. package/test/csv-schema.spec.ts +2 -2
  57. package/test/entities.spec.ts +381 -0
  58. package/types.ts +3 -0
  59. package/dist/rad-compile.d.ts +0 -11
  60. package/dist/rad.d.ts +0 -17
@@ -36,8 +36,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.buildOpenApi = exports.buildManifest = exports.analyze = void 0;
39
+ exports.buildOpenApi = exports.buildManifest = exports.detectCycles = exports.analyzeEntities = exports.analyze = void 0;
40
40
  exports.resolveResourceFiles = resolveResourceFiles;
41
+ exports.analyzeProject = analyzeProject;
41
42
  exports.analyzeResources = analyzeResources;
42
43
  exports.compile = compile;
43
44
  exports.collisions = collisions;
@@ -45,11 +46,15 @@ exports.urlsFor = urlsFor;
45
46
  const fs = __importStar(require("fs"));
46
47
  const path = __importStar(require("path"));
47
48
  const analyze_1 = require("./analyze");
49
+ const entities_1 = require("./entities");
48
50
  const manifest_1 = require("./manifest");
49
51
  const openapi_1 = require("./openapi");
50
52
  const program_1 = require("./program");
51
53
  var analyze_2 = require("./analyze");
52
54
  Object.defineProperty(exports, "analyze", { enumerable: true, get: function () { return analyze_2.analyze; } });
55
+ var entities_2 = require("./entities");
56
+ Object.defineProperty(exports, "analyzeEntities", { enumerable: true, get: function () { return entities_2.analyzeEntities; } });
57
+ Object.defineProperty(exports, "detectCycles", { enumerable: true, get: function () { return entities_2.detectCycles; } });
53
58
  var manifest_2 = require("./manifest");
54
59
  Object.defineProperty(exports, "buildManifest", { enumerable: true, get: function () { return manifest_2.buildManifest; } });
55
60
  var openapi_2 = require("./openapi");
@@ -60,18 +65,19 @@ const IGNORE_DIRS = new Set([
60
65
  "node_modules",
61
66
  ".git",
62
67
  ".expo",
63
- ".rad",
68
+ ".rad", // legacy output dir
69
+ ".rastack",
64
70
  "dist",
65
71
  "web-build",
66
72
  ]);
67
73
  /**
68
- * Every `.ts` resource file under a directory (recursively), or an explicit
69
- * file. Recursion is what lets resource definitions live **co-located with the
70
- * pages that consume them** — e.g. `app/airports/_schema.rad.ts` beside
71
- * `app/airports/index.tsx` — instead of in one top-level `resources/` folder.
72
- * `.tsx` route components and `.d.ts` files are skipped; only files with a
73
- * `resource(...)` call contribute to the manifest, so co-located helpers are
74
- * harmless.
74
+ * Every `.ts`/`.tsx` source file under a directory (recursively), or an
75
+ * explicit file. Recursion is what lets resource definitions live **co-located
76
+ * with the pages that consume them** — e.g. `app/airports/_schema.rastack.ts`
77
+ * beside `app/airports/index.tsx` — instead of in one top-level `resources/`
78
+ * folder. `.tsx` files carry no `resource(...)` definitions but are scanned
79
+ * for the typed hook calls (`useEntityList<Airport>(…)`) that root the
80
+ * interface-driven entity graph; co-located helpers are harmless.
75
81
  */
76
82
  function resolveResourceFiles(input) {
77
83
  const stat = fs.existsSync(input) ? fs.statSync(input) : undefined;
@@ -85,7 +91,7 @@ function resolveResourceFiles(input) {
85
91
  if (!IGNORE_DIRS.has(entry.name))
86
92
  walk(path.join(dir, entry.name));
87
93
  }
88
- else if (entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
94
+ else if (/\.tsx?$/.test(entry.name) && !entry.name.endsWith(".d.ts")) {
89
95
  files.push(path.resolve(dir, entry.name));
90
96
  }
91
97
  }
@@ -95,23 +101,49 @@ function resolveResourceFiles(input) {
95
101
  }
96
102
  throw new Error(`No such resources path: ${input}`);
97
103
  }
98
- /** Analyse resource definitions into the canonical model (no file output). */
99
- function analyzeResources(input) {
104
+ /**
105
+ * Analyse a project into the canonical model: explicit `resource()` DSL
106
+ * definitions plus resources inferred from hook-rooted TypeScript interfaces.
107
+ * When both surfaces define the same `app.model`, the explicit DSL definition
108
+ * wins — hook usage of a generated `IAirport` interface resolves back onto the
109
+ * authored resource instead of creating a duplicate. Cycle detection runs over
110
+ * the merged FK graph.
111
+ */
112
+ function analyzeProject(input) {
100
113
  const files = resolveResourceFiles(input);
101
114
  const program = (0, program_1.createProgram)(files);
102
- return (0, analyze_1.analyze)(program, files);
115
+ const fromDsl = (0, analyze_1.analyze)(program, files);
116
+ const fromInterfaces = (0, entities_1.analyzeEntities)(program, files);
117
+ const defined = new Set(fromDsl.map((r) => `${r.app}.${r.model}`));
118
+ const resources = [
119
+ ...fromDsl,
120
+ ...fromInterfaces.resources.filter((r) => !defined.has(`${r.app}.${r.model}`)),
121
+ ];
122
+ resources.sort((a, b) => a.app === b.app ? a.model.localeCompare(b.model) : a.app.localeCompare(b.app));
123
+ return {
124
+ resources,
125
+ diagnostics: [...fromInterfaces.diagnostics, ...(0, entities_1.detectCycles)(resources)],
126
+ };
127
+ }
128
+ /** Analyse resource definitions into the canonical model (no file output). */
129
+ function analyzeResources(input) {
130
+ return analyzeProject(input).resources;
103
131
  }
104
132
  /** Compile resource definitions to a manifest + OpenAPI, writing both to disk. */
105
133
  function compile(input, outDir) {
106
- const resources = analyzeResources(input);
134
+ const { resources, diagnostics } = analyzeProject(input);
135
+ const errors = diagnostics.filter((d) => d.severity === "error");
136
+ if (errors.length) {
137
+ throw new Error(errors.map((e) => e.message).join("\n"));
138
+ }
107
139
  const manifest = (0, manifest_1.buildManifest)(resources);
108
140
  const openapi = (0, openapi_1.buildOpenApi)(resources);
109
141
  fs.mkdirSync(outDir, { recursive: true });
110
- const manifestPath = path.join(outDir, "schema.rad.json");
142
+ const manifestPath = path.join(outDir, "schema.rastack.json");
111
143
  const openapiPath = path.join(outDir, "openapi.json");
112
144
  fs.writeFileSync(manifestPath, (0, manifest_1.manifestToJson)(manifest), { flag: "w" });
113
145
  fs.writeFileSync(openapiPath, (0, openapi_1.openApiToJson)(openapi), { flag: "w" });
114
- return { manifest, openapi, files: [manifestPath, openapiPath] };
146
+ return { manifest, openapi, files: [manifestPath, openapiPath], diagnostics };
115
147
  }
116
148
  // -- introspection (replaces `manage.py rastack check|list|urls`) -----------
117
149
  /** Detect duplicate `app.model` definitions and dangling FK targets. */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The canonical, backend-agnostic data model produced by the compiler. This is
3
- * what `schema.rad.json` serializes and what both the OpenAPI emitter and the
3
+ * what `schema.rastack.json` serializes and what both the OpenAPI emitter and the
4
4
  * Rust API consume.
5
5
  */
6
6
  export type ScalarType = "string" | "int" | "float" | "bool" | "datetime" | "uuid";
@@ -38,7 +38,7 @@ export interface AdminModel {
38
38
  listDisplay?: string[];
39
39
  }
40
40
  /**
41
- * Row-level access control, enforced by `rad-api-core` on every surface.
41
+ * Row-level access control, enforced by `rastack-api-core` on every surface.
42
42
  * `ownerField` names the field stamped with the authenticated subject;
43
43
  * `scope: "owner"` places the table under a per-identity warehouse prefix
44
44
  * (`tenants/{sub}/…`) so object-storage IAM can fence data per user.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * The canonical, backend-agnostic data model produced by the compiler. This is
4
- * what `schema.rad.json` serializes and what both the OpenAPI emitter and the
4
+ * what `schema.rastack.json` serializes and what both the OpenAPI emitter and the
5
5
  * Rust API consume.
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,7 +1,8 @@
1
1
  import * as ts from "typescript";
2
2
  /**
3
3
  * Build a `ts.Program` (and thus a `TypeChecker`) over a set of resource
4
- * definition files. The DSL package (`rad-tools/define`) is mapped to the
4
+ * definition files. The authoring subpaths (`rastack/define` for the DSL,
5
+ * `rastack/types` for the `DbConfig` column brands) are mapped to the
5
6
  * in-tree/installed sources via `paths` so both the shipped package name and
6
7
  * the local demo/tests resolve without extra linking.
7
8
  */
@@ -39,7 +39,8 @@ const path = __importStar(require("path"));
39
39
  const ts = __importStar(require("typescript"));
40
40
  /**
41
41
  * Build a `ts.Program` (and thus a `TypeChecker`) over a set of resource
42
- * definition files. The DSL package (`rad-tools/define`) is mapped to the
42
+ * definition files. The authoring subpaths (`rastack/define` for the DSL,
43
+ * `rastack/types` for the `DbConfig` column brands) are mapped to the
43
44
  * in-tree/installed sources via `paths` so both the shipped package name and
44
45
  * the local demo/tests resolve without extra linking.
45
46
  */
@@ -53,10 +54,14 @@ function createProgram(fileNames) {
53
54
  skipLibCheck: true,
54
55
  esModuleInterop: true,
55
56
  noEmit: true,
57
+ // `.tsx` app files are scanned for the typed hook calls that root the
58
+ // interface-driven entity graph.
59
+ jsx: ts.JsxEmit.ReactJSX,
56
60
  baseUrl: process.cwd(),
57
61
  paths: {
58
- "rad-tools/define": [defineDir],
59
- "rad-tools/define/*": [defineDir + "/*"],
62
+ "rastack/define": [defineDir],
63
+ "rastack/define/*": [defineDir + "/*"],
64
+ "rastack/types": [path.join(defineDir, "db")],
60
65
  },
61
66
  };
62
67
  return ts.createProgram(fileNames, options);
@@ -29,7 +29,7 @@ const DEFAULT_PII_PATTERNS = [
29
29
  "*income*",
30
30
  ];
31
31
  function loadPiiConfig(repoRoot) {
32
- const configPath = path_1.default.join(repoRoot, ".rad", "pii-patterns.yml");
32
+ const configPath = path_1.default.join(repoRoot, ".rastack", "pii-patterns.yml");
33
33
  if (!fs_1.default.existsSync(configPath)) {
34
34
  return { patterns: DEFAULT_PII_PATTERNS, luhn_check: true, require_policy: true };
35
35
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Type-level column configuration for interface-driven entities.
3
+ *
4
+ * Interface entities are plain TypeScript, so their column constraints are
5
+ * expressed *in the type system*: intersect a property type with one or more
6
+ * {@link DbConfig} brands and the compiler reads the configuration straight
7
+ * off the type — the same way it reads foreign keys.
8
+ *
9
+ * ```ts
10
+ * import { Default, Int, MaxLength, PrimaryKey, Unique, UUID } from "rastack/types";
11
+ *
12
+ * export interface Passenger {
13
+ * id: UUID & PrimaryKey;
14
+ * seat: string & MaxLength<4> & Unique;
15
+ * age: Int; // number maps to float; Int refines it
16
+ * status: string & Default<"active">;
17
+ * }
18
+ * ```
19
+ *
20
+ * Recurring configurations can extend {@link DbConfig} once and be reused:
21
+ *
22
+ * ```ts
23
+ * interface Registration extends DbConfig<{ maxLength: 10; unique: true }> {}
24
+ *
25
+ * export interface Aircraft {
26
+ * registration: string & Registration;
27
+ * }
28
+ * ```
29
+ *
30
+ * The brands are "flavors", not hard brands: the phantom `__rastackDb` property is
31
+ * optional and never exists at runtime, so a plain `"3F"` stays assignable to
32
+ * `string & MaxLength<4> & Unique` — no casts anywhere in app code.
33
+ */
34
+ /**
35
+ * The phantom carrier every constraint type extends. `C` holds the column
36
+ * configuration as literal types; the compiler recovers it from the `__rastackDb`
37
+ * property of the intersected field type.
38
+ */
39
+ export interface DbConfig<C = unknown> {
40
+ readonly __rastackDb?: C;
41
+ }
42
+ /** The column value must be unique. */
43
+ export interface Unique extends DbConfig<{
44
+ unique: true;
45
+ }> {
46
+ }
47
+ /** The column is the primary key. */
48
+ export interface PrimaryKey extends DbConfig<{
49
+ primaryKey: true;
50
+ }> {
51
+ }
52
+ /** Maximum length for string columns: `string & MaxLength<120>`. */
53
+ export interface MaxLength<N extends number> extends DbConfig<{
54
+ maxLength: N;
55
+ }> {
56
+ }
57
+ /** Server-side default value: `string & Default<"scheduled">`, `number & Default<0>`. */
58
+ export interface Default<V extends string | number | boolean> extends DbConfig<{
59
+ default: V;
60
+ }> {
61
+ }
62
+ /** An integer column — a bare `number` property maps to `float`. */
63
+ export type Int = number & DbConfig<{
64
+ int: true;
65
+ }>;
66
+ /** A UUID column, stored as a string. */
67
+ export type UUID = string & DbConfig<{
68
+ uuid: true;
69
+ }>;
70
+ /** A datetime column authored as a string (a `Date` property maps directly). */
71
+ export type DateTimeString = string & DbConfig<{
72
+ datetime: true;
73
+ }>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /**
3
+ * Type-level column configuration for interface-driven entities.
4
+ *
5
+ * Interface entities are plain TypeScript, so their column constraints are
6
+ * expressed *in the type system*: intersect a property type with one or more
7
+ * {@link DbConfig} brands and the compiler reads the configuration straight
8
+ * off the type — the same way it reads foreign keys.
9
+ *
10
+ * ```ts
11
+ * import { Default, Int, MaxLength, PrimaryKey, Unique, UUID } from "rastack/types";
12
+ *
13
+ * export interface Passenger {
14
+ * id: UUID & PrimaryKey;
15
+ * seat: string & MaxLength<4> & Unique;
16
+ * age: Int; // number maps to float; Int refines it
17
+ * status: string & Default<"active">;
18
+ * }
19
+ * ```
20
+ *
21
+ * Recurring configurations can extend {@link DbConfig} once and be reused:
22
+ *
23
+ * ```ts
24
+ * interface Registration extends DbConfig<{ maxLength: 10; unique: true }> {}
25
+ *
26
+ * export interface Aircraft {
27
+ * registration: string & Registration;
28
+ * }
29
+ * ```
30
+ *
31
+ * The brands are "flavors", not hard brands: the phantom `__rastackDb` property is
32
+ * optional and never exists at runtime, so a plain `"3F"` stays assignable to
33
+ * `string & MaxLength<4> & Unique` — no casts anywhere in app code.
34
+ */
35
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * rad-tools authoring DSL — the TypeScript-first source of truth.
2
+ * rastack authoring DSL — the TypeScript-first source of truth.
3
3
  *
4
4
  * Resources are authored as plain TypeScript. The compiler
5
5
  * (`tools/src/compile`) reads these definitions and, crucially, **infers
@@ -9,7 +9,7 @@
9
9
  * `Ref`'s string-literal type arguments.
10
10
  *
11
11
  * ```ts
12
- * import { resource, s } from "rad-tools/define";
12
+ * import { resource, s } from "rastack/define";
13
13
  *
14
14
  * export const Airport = resource("airports", "airport", {
15
15
  * code: s.string({ maxLength: 3, unique: true }),
@@ -22,16 +22,16 @@
22
22
  * });
23
23
  * ```
24
24
  */
25
- /** A scalar field. The literal `__radScalar` type is what the compiler reads. */
25
+ /** A scalar field. The literal `__rastackScalar` type is what the compiler reads. */
26
26
  export interface Scalar<T extends string> {
27
- readonly __radScalar: T;
27
+ readonly __rastackScalar: T;
28
28
  }
29
29
  /**
30
30
  * A foreign-key field. `App`/`Model` are carried as string-literal type
31
31
  * arguments so the compiler can recover the relation target purely from types.
32
32
  */
33
33
  export interface Ref<App extends string, Model extends string> {
34
- readonly __radRef: true;
34
+ readonly __rastackRef: true;
35
35
  readonly __app: App;
36
36
  readonly __model: Model;
37
37
  }
@@ -87,8 +87,8 @@ export interface SyncOptions {
87
87
  clientIds?: boolean;
88
88
  }
89
89
  /**
90
- * Row-level access control. Enforced by `rad-api-core`, so the rules are
91
- * identical on the server (Lambda / `rad serve`) and in the in-browser WASM
90
+ * Row-level access control. Enforced by `rastack-api-core`, so the rules are
91
+ * identical on the server (Lambda / `rastack serve`) and in the in-browser WASM
92
92
  * engine.
93
93
  *
94
94
  * - `ownerField` — the field that records the owning identity (the verified
@@ -126,7 +126,7 @@ export interface ResourceOptions {
126
126
  * arguments so a {@link Ref} to this resource carries a recoverable target.
127
127
  */
128
128
  export interface ResourceType<App extends string, Model extends string, F> {
129
- readonly __rad: "resource";
129
+ readonly __rastack: "resource";
130
130
  readonly __app: App;
131
131
  readonly __model: Model;
132
132
  readonly app: App;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * rad-tools authoring DSL — the TypeScript-first source of truth.
3
+ * rastack authoring DSL — the TypeScript-first source of truth.
4
4
  *
5
5
  * Resources are authored as plain TypeScript. The compiler
6
6
  * (`tools/src/compile`) reads these definitions and, crucially, **infers
@@ -10,7 +10,7 @@
10
10
  * `Ref`'s string-literal type arguments.
11
11
  *
12
12
  * ```ts
13
- * import { resource, s } from "rad-tools/define";
13
+ * import { resource, s } from "rastack/define";
14
14
  *
15
15
  * export const Airport = resource("airports", "airport", {
16
16
  * code: s.string({ maxLength: 3, unique: true }),
@@ -34,22 +34,22 @@ exports.resource = resource;
34
34
  */
35
35
  exports.s = {
36
36
  string(_opts) {
37
- return { __radScalar: "string" };
37
+ return { __rastackScalar: "string" };
38
38
  },
39
39
  int(_opts) {
40
- return { __radScalar: "int" };
40
+ return { __rastackScalar: "int" };
41
41
  },
42
42
  float(_opts) {
43
- return { __radScalar: "float" };
43
+ return { __rastackScalar: "float" };
44
44
  },
45
45
  bool(_opts) {
46
- return { __radScalar: "bool" };
46
+ return { __rastackScalar: "bool" };
47
47
  },
48
48
  datetime(_opts) {
49
- return { __radScalar: "datetime" };
49
+ return { __rastackScalar: "datetime" };
50
50
  },
51
51
  uuid(_opts) {
52
- return { __radScalar: "uuid" };
52
+ return { __rastackScalar: "uuid" };
53
53
  },
54
54
  /**
55
55
  * A foreign key. The target is `() => SomeResource`; the compiler resolves
@@ -57,13 +57,13 @@ exports.s = {
57
57
  * need to run the thunk.
58
58
  */
59
59
  ref(_thunk) {
60
- return { __radRef: true };
60
+ return { __rastackRef: true };
61
61
  },
62
62
  };
63
63
  /** Define a resource. Capture app/model as literal types for FK inference. */
64
64
  function resource(app, model, fields, options = {}) {
65
65
  return {
66
- __rad: "resource",
66
+ __rastack: "resource",
67
67
  __app: app,
68
68
  __model: model,
69
69
  app,
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ const args = process.argv.slice(2);
11
11
  const schemaOnly = args.includes("--schema-only");
12
12
  const currentDir = process.cwd(); // Get the current working directory
13
13
  const kodeDir = path_1.default.join(currentDir, ".kode");
14
- const configFile = path_1.default.join(kodeDir, "generate-rad-sdk.json");
14
+ const configFile = path_1.default.join(kodeDir, "generate-rastack-sdk.json");
15
15
  let config = {};
16
16
  // Create the .kode directory if it doesn't exist
17
17
  if (!fs_1.default.existsSync(kodeDir)) {
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `rastack compile | check | list | urls` — the TypeScript-first replacement for the
4
+ * old Django `manage.py rastack` command.
5
+ *
6
+ * rastack compile [resourcesDir] [outDir] defs → schema.rastack.json + openapi.json
7
+ * rastack check [resourcesDir] validate the resource graph (exit != 0 on error)
8
+ * rastack list [resourcesDir] print every resource + its fields/relations
9
+ * rastack urls [resourcesDir] print the generated /api/{app}/v1/{model}/ routes
10
+ */
11
+ export {};
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * `rad compile | check | list | urls` — the TypeScript-first replacement for the
4
+ * `rastack compile | check | list | urls` — the TypeScript-first replacement for the
5
5
  * old Django `manage.py rastack` command.
6
6
  *
7
- * rad compile [resourcesDir] [outDir] defs → schema.rad.json + openapi.json
8
- * rad check [resourcesDir] validate the resource graph (exit != 0 on error)
9
- * rad list [resourcesDir] print every resource + its fields/relations
10
- * rad urls [resourcesDir] print the generated /api/{app}/v1/{model}/ routes
7
+ * rastack compile [resourcesDir] [outDir] defs → schema.rastack.json + openapi.json
8
+ * rastack check [resourcesDir] validate the resource graph (exit != 0 on error)
9
+ * rastack list [resourcesDir] print every resource + its fields/relations
10
+ * rastack urls [resourcesDir] print the generated /api/{app}/v1/{model}/ routes
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  const compile_1 = require("./compile");
14
14
  const DEFAULT_RESOURCES = "resources";
15
- const DEFAULT_OUT = ".rad";
15
+ const DEFAULT_OUT = ".rastack";
16
16
  function main(argv) {
17
17
  const [sub, ...rest] = argv;
18
18
  switch (sub) {
@@ -20,12 +20,22 @@ function main(argv) {
20
20
  const resourcesDir = rest[0] || DEFAULT_RESOURCES;
21
21
  const outDir = rest[1] || DEFAULT_OUT;
22
22
  const result = (0, compile_1.compile)(resourcesDir, outDir);
23
+ for (const d of result.diagnostics)
24
+ console.warn(` ⚠ ${d.message}`);
23
25
  console.log(`✓ compiled ${result.manifest.resources.length} resource(s) → ${result.files.join(", ")}`);
24
26
  break;
25
27
  }
26
28
  case "check": {
27
- const resources = (0, compile_1.analyzeResources)(rest[0] || DEFAULT_RESOURCES);
28
- const errors = (0, compile_1.collisions)(resources);
29
+ const { resources, diagnostics } = (0, compile_1.analyzeProject)(rest[0] || DEFAULT_RESOURCES);
30
+ const errors = [
31
+ ...(0, compile_1.collisions)(resources),
32
+ ...diagnostics
33
+ .filter((d) => d.severity === "error")
34
+ .map((d) => d.message),
35
+ ];
36
+ for (const d of diagnostics.filter((d) => d.severity === "warning")) {
37
+ console.warn(` ⚠ ${d.message}`);
38
+ }
29
39
  if (errors.length) {
30
40
  for (const e of errors)
31
41
  console.error(` ✗ ${e}`);
@@ -70,10 +80,10 @@ function main(argv) {
70
80
  default:
71
81
  console.error(`Unknown compile subcommand: "${sub}"\n\n` +
72
82
  `Usage:\n` +
73
- ` rad compile [resourcesDir] [outDir]\n` +
74
- ` rad check [resourcesDir]\n` +
75
- ` rad list [resourcesDir]\n` +
76
- ` rad urls [resourcesDir]\n`);
83
+ ` rastack compile [resourcesDir] [outDir]\n` +
84
+ ` rastack check [resourcesDir]\n` +
85
+ ` rastack list [resourcesDir]\n` +
86
+ ` rastack urls [resourcesDir]\n`);
77
87
  process.exit(1);
78
88
  }
79
89
  }
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * `rad wasm` — compile the Rust API to WebAssembly for in-browser local dev.
3
+ * `rastack wasm` — compile the Rust API to WebAssembly for in-browser local dev.
4
4
  *
5
5
  * Pipeline:
6
6
  * 1. cargo build -p rad-wasm --release --target wasm32-unknown-unknown
7
- * 2. wasm-bindgen --target web → stack/wasm/rad_wasm.js + rad_wasm_bg.wasm
7
+ * 2. wasm-bindgen --target web → stack/wasm/rastack_wasm.js + rastack_wasm_bg.wasm
8
8
  * 3. wasm-opt -Oz (if available) to shrink the binary
9
9
  *
10
10
  * The generated bundle is what `<RAStackProvider mode="local">` loads. Prereqs:
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * `rad wasm` — compile the Rust API to WebAssembly for in-browser local dev.
4
+ * `rastack wasm` — compile the Rust API to WebAssembly for in-browser local dev.
5
5
  *
6
6
  * Pipeline:
7
7
  * 1. cargo build -p rad-wasm --release --target wasm32-unknown-unknown
8
- * 2. wasm-bindgen --target web → stack/wasm/rad_wasm.js + rad_wasm_bg.wasm
8
+ * 2. wasm-bindgen --target web → stack/wasm/rastack_wasm.js + rastack_wasm_bg.wasm
9
9
  * 3. wasm-opt -Oz (if available) to shrink the binary
10
10
  *
11
11
  * The generated bundle is what `<RAStackProvider mode="local">` loads. Prereqs:
@@ -22,7 +22,7 @@ const path_1 = __importDefault(require("path"));
22
22
  const repoRoot = path_1.default.resolve(__dirname, "..", "..");
23
23
  const rustDir = path_1.default.join(repoRoot, "rust");
24
24
  const outDir = path_1.default.join(repoRoot, "tools", "wasm");
25
- const wasmPath = path_1.default.join(rustDir, "target", "wasm32-unknown-unknown", "release", "rad_wasm.wasm");
25
+ const wasmPath = path_1.default.join(rustDir, "target", "wasm32-unknown-unknown", "release", "rastack_wasm.wasm");
26
26
  function run(cmd, args, cwd = repoRoot) {
27
27
  // Local build tool: `cmd`/`args` are the fixed toolchain invocations below
28
28
  // (cargo, wasm-bindgen, wasm-opt), not untrusted input — no injection surface.
@@ -65,7 +65,7 @@ run("wasm-bindgen", [
65
65
  "--out-dir",
66
66
  outDir,
67
67
  "--out-name",
68
- "rad_wasm",
68
+ "rastack_wasm",
69
69
  wasmPath,
70
70
  ]);
71
71
  // Mark the emitted bundle as ESM so Node and bundlers treat it correctly
@@ -73,11 +73,11 @@ run("wasm-bindgen", [
73
73
  fs_1.default.writeFileSync(path_1.default.join(outDir, "package.json"), JSON.stringify({ type: "module", sideEffects: false }, null, 2) + "\n");
74
74
  if (has("wasm-opt")) {
75
75
  console.log("→ wasm-opt -Oz");
76
- const bg = path_1.default.join(outDir, "rad_wasm_bg.wasm");
76
+ const bg = path_1.default.join(outDir, "rastack_wasm_bg.wasm");
77
77
  run("wasm-opt", ["-Oz", "-o", bg, bg]);
78
78
  }
79
79
  else {
80
80
  console.log("· wasm-opt not found — skipping size optimisation (optional)");
81
81
  }
82
- const size = fs_1.default.statSync(path_1.default.join(outDir, "rad_wasm_bg.wasm")).size;
82
+ const size = fs_1.default.statSync(path_1.default.join(outDir, "rastack_wasm_bg.wasm")).size;
83
83
  console.log(`✓ wasm engine built: stack/wasm/ (${(size / 1024).toFixed(0)} KB)`);
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * rastack — unified CLI for React API Stack
4
+ *
5
+ * Commands:
6
+ * rastack compile [resourcesDir] [outDir] TypeScript resources → schema.rastack.json + openapi.json
7
+ * rastack check [resourcesDir] Validate the resource graph
8
+ * rastack list [resourcesDir] Print resources, fields and relations
9
+ * rastack urls [resourcesDir] Print the generated /api/{app}/v1/{model}/ routes
10
+ * rastack generate [--schema-only] Generate typed hooks from OpenAPI
11
+ * rastack serve [--warehouse dir] Run the Rust API over an Iceberg warehouse
12
+ * rastack admin [--warehouse dir] Run the Rust admin (Django-admin-style DB browser)
13
+ * rastack wasm Compile the API to WebAssembly (in-browser local dev)
14
+ * rastack scan [files...] [--fail-on-pii] Scan CSVs for PII and schema info
15
+ * rastack seed [--env dev] [--source gs://] Load CSVs into Iceberg namespace
16
+ */
17
+ export {};