rastack 0.0.58 → 0.0.59

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 (83) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +190 -0
  3. package/dist/deploy/ci.js +2 -2
  4. package/dist/deploy/io.js +2 -2
  5. package/dist/dev/harness.d.ts +1 -1
  6. package/dist/dev/harness.js +1 -2
  7. package/dist/external/cache.d.ts +28 -0
  8. package/dist/external/cache.js +35 -0
  9. package/dist/external/envelope.d.ts +35 -0
  10. package/dist/external/envelope.js +48 -0
  11. package/dist/external/graphql.d.ts +25 -0
  12. package/dist/external/graphql.js +78 -0
  13. package/dist/external/handler.d.ts +52 -0
  14. package/dist/external/handler.js +139 -0
  15. package/dist/external/index.d.ts +19 -0
  16. package/dist/external/index.js +38 -0
  17. package/dist/external/lambda.d.ts +49 -0
  18. package/dist/external/lambda.js +86 -0
  19. package/dist/external/rest.d.ts +17 -0
  20. package/dist/external/rest.js +46 -0
  21. package/dist/external/route.d.ts +12 -0
  22. package/dist/external/route.js +33 -0
  23. package/dist/external/service.d.ts +50 -0
  24. package/dist/external/service.js +59 -0
  25. package/dist/external/types.d.ts +107 -0
  26. package/dist/external/types.js +22 -0
  27. package/dist/external/util.d.ts +16 -0
  28. package/dist/external/util.js +58 -0
  29. package/dist/rastack-dev.js +10 -0
  30. package/dist/rastack-wasm-build.d.ts +1 -1
  31. package/dist/rastack-wasm-build.js +6 -6
  32. package/dist/wasm/rastack_wasm_bg.wasm +0 -0
  33. package/external.ts +10 -0
  34. package/hooks/query/delete.ts +12 -11
  35. package/hooks/query/fetch.ts +6 -8
  36. package/hooks/query/interfaces.ts +1 -4
  37. package/hooks/query/list.ts +16 -9
  38. package/hooks/query/update.ts +8 -6
  39. package/package.json +24 -2
  40. package/scripts/copy-templates.js +1 -1
  41. package/scripts/copy-wasm.js +1 -1
  42. package/scripts/dev-install.mjs +63 -0
  43. package/src/deploy/ci.ts +2 -2
  44. package/src/deploy/io.ts +2 -2
  45. package/src/dev/harness.ts +1 -2
  46. package/src/external/cache.ts +53 -0
  47. package/src/external/envelope.ts +78 -0
  48. package/src/external/graphql.ts +98 -0
  49. package/src/external/handler.ts +207 -0
  50. package/src/external/index.ts +25 -0
  51. package/src/external/lambda.ts +108 -0
  52. package/src/external/rest.ts +60 -0
  53. package/src/external/route.ts +33 -0
  54. package/src/external/service.ts +86 -0
  55. package/src/external/types.ts +121 -0
  56. package/src/external/util.ts +57 -0
  57. package/src/rastack-dev.ts +11 -0
  58. package/src/rastack-wasm-build.ts +6 -6
  59. package/jest.config.cjs +0 -12
  60. package/test/auth.spec.ts +0 -207
  61. package/test/cache.spec.ts +0 -263
  62. package/test/cognito.spec.ts +0 -281
  63. package/test/compile.spec.ts +0 -240
  64. package/test/components.spec.ts +0 -524
  65. package/test/csv-schema.spec.ts +0 -143
  66. package/test/deploy.spec.ts +0 -571
  67. package/test/dev.spec.ts +0 -414
  68. package/test/entities.spec.ts +0 -597
  69. package/test/import.spec.ts +0 -241
  70. package/test/plugin.spec.ts +0 -315
  71. package/test/runtime-manifest.spec.ts +0 -309
  72. package/test/schema-entities.spec.ts +0 -688
  73. package/test/tokens.spec.ts +0 -302
  74. package/test/transitions.spec.ts +0 -372
  75. package/test/typed-hooks.spec.ts +0 -412
  76. package/test/update.spec.ts +0 -152
  77. package/test/validate.spec.ts +0 -319
  78. package/tsconfig.json +0 -27
  79. package/wasm/package.json +0 -4
  80. package/wasm/rastack_wasm.d.ts +0 -100
  81. package/wasm/rastack_wasm.js +0 -745
  82. package/wasm/rastack_wasm_bg.wasm +0 -0
  83. package/wasm/rastack_wasm_bg.wasm.d.ts +0 -28
@@ -1,240 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
2
- import { join } from "path";
3
- import {
4
- analyzeResources,
5
- buildOpenApi,
6
- collisions,
7
- compile,
8
- ResourceModel,
9
- } from "../src/compile";
10
- import { generateFiles, generateFolders } from "../src/schema-entities";
11
- import { removeNonModelPaths } from "../src/schema/remove-non-model-paths";
12
-
13
- /**
14
- * The compiler's fixtures are real `.ts` files that import the DSL by its
15
- * package name (`rastack/define`); `createProgram` maps that to the in-tree
16
- * source, so the type checker resolves the `Ref`/`Resource` brands exactly as it
17
- * would in a consumer project.
18
- */
19
- const workRoot = join(__dirname, "compile-fixtures");
20
- const resourcesDir = join(workRoot, "resources");
21
- const outDir = join(workRoot, "out");
22
-
23
- const AIRPORTS_TS = `
24
- import { resource, s } from "rastack/define";
25
-
26
- export const Airport = resource("airports", "airport", {
27
- code: s.string({ maxLength: 3, unique: true }),
28
- name: s.string({ maxLength: 120 }),
29
- }, { search: ["code", "name"], admin: { listDisplay: ["code", "name"] } });
30
-
31
- export const Terminal = resource("airports", "terminal", {
32
- airport: s.ref(() => Airport),
33
- label: s.string({ maxLength: 20 }),
34
- });
35
-
36
- export const Flight = resource("airports", "flight", {
37
- number: s.string({ maxLength: 8 }),
38
- status: s.string({ maxLength: 20, default: "scheduled" }),
39
- }, { sync: { mode: "local", scope: "owner_id={user.id}", confirmed: ["update"] } });
40
-
41
- export const Gate = resource("airports", "gate", {
42
- number: s.string({ maxLength: 5 }),
43
- }, { sync: { mode: "local", load: "lazy" } });
44
-
45
- export const Booking = resource("airports", "booking", {
46
- reference: s.string({ maxLength: 12 }),
47
- }, { sync: { mode: "local", clientIds: true } });
48
-
49
- export const Itinerary = resource("airports", "itinerary", {
50
- owner: s.string({ maxLength: 64 }),
51
- notes: s.string({ maxLength: 500 }),
52
- }, {
53
- permission: "authenticated",
54
- access: { ownerField: "owner", scope: "owner", adminGroups: ["staff"] },
55
- });
56
- `;
57
-
58
- function findResource(
59
- resources: ResourceModel[],
60
- app: string,
61
- model: string,
62
- ): ResourceModel {
63
- const found = resources.find((r) => r.app === app && r.model === model);
64
- if (!found) throw new Error(`missing ${app}.${model}`);
65
- return found;
66
- }
67
-
68
- describe("rastack compile — resource analysis & FK inference", () => {
69
- beforeAll(() => {
70
- mkdirSync(resourcesDir, { recursive: true });
71
- writeFileSync(join(resourcesDir, "airports.ts"), AIRPORTS_TS);
72
- });
73
-
74
- afterAll(() => {
75
- rmSync(workRoot, { recursive: true, force: true });
76
- });
77
-
78
- it("infers a foreign key from the field type", () => {
79
- const resources = analyzeResources(resourcesDir);
80
- const terminal = findResource(resources, "airports", "terminal");
81
-
82
- const airportField = terminal.fields.find((f) => f.name === "airport");
83
- expect(airportField?.type).toBe("fk");
84
- expect(airportField?.relation).toEqual({
85
- app: "airports",
86
- model: "airport",
87
- });
88
-
89
- expect(terminal.relations).toEqual([
90
- { field: "airport", target: "airports.airport", kind: "fk" },
91
- ]);
92
- });
93
-
94
- it("maps scalar fields and their constraints", () => {
95
- const resources = analyzeResources(resourcesDir);
96
- const airport = findResource(resources, "airports", "airport");
97
-
98
- const code = airport.fields.find((f) => f.name === "code");
99
- expect(code).toMatchObject({ type: "string", maxLength: 3, unique: true });
100
-
101
- const name = airport.fields.find((f) => f.name === "name");
102
- expect(name).toMatchObject({ type: "string", maxLength: 120 });
103
-
104
- expect(airport.search).toEqual(["code", "name"]);
105
- expect(airport.admin).toEqual({ listDisplay: ["code", "name"] });
106
- });
107
-
108
- it("captures sync config (local / lazy / client-ids / confirmed)", () => {
109
- const resources = analyzeResources(resourcesDir);
110
-
111
- expect(findResource(resources, "airports", "flight").sync).toMatchObject({
112
- mode: "local",
113
- scope: "owner_id={user.id}",
114
- confirmed: ["update"],
115
- });
116
- expect(findResource(resources, "airports", "gate").sync).toMatchObject({
117
- mode: "local",
118
- load: "lazy",
119
- });
120
- expect(findResource(resources, "airports", "booking").sync).toMatchObject({
121
- mode: "local",
122
- clientIds: true,
123
- });
124
- });
125
-
126
- it("captures row-level access config (ownerField / scope / adminGroups)", () => {
127
- const resources = analyzeResources(resourcesDir);
128
- const itinerary = findResource(resources, "airports", "itinerary");
129
-
130
- expect(itinerary.permission).toBe("authenticated");
131
- expect(itinerary.access).toEqual({
132
- ownerField: "owner",
133
- scope: "owner",
134
- adminGroups: ["staff"],
135
- });
136
-
137
- // Resources without an access block stay unstamped.
138
- expect(
139
- findResource(resources, "airports", "airport").access,
140
- ).toBeUndefined();
141
- });
142
-
143
- it("reports no collisions for a valid graph", () => {
144
- const resources = analyzeResources(resourcesDir);
145
- expect(collisions(resources)).toEqual([]);
146
- });
147
- });
148
-
149
- describe("rastack compile — OpenAPI emission", () => {
150
- beforeAll(() => {
151
- mkdirSync(resourcesDir, { recursive: true });
152
- writeFileSync(join(resourcesDir, "airports.ts"), AIRPORTS_TS);
153
- });
154
-
155
- afterAll(() => {
156
- rmSync(workRoot, { recursive: true, force: true });
157
- });
158
-
159
- it("writes schema.rastack.json and openapi.json", () => {
160
- const result = compile(resourcesDir, outDir);
161
- expect(existsSync(join(outDir, "schema.rastack.json"))).toBe(true);
162
- expect(existsSync(join(outDir, "openapi.json"))).toBe(true);
163
- expect(result.manifest.resources.length).toBe(6);
164
- });
165
-
166
- it("emits the /api/{app}/v1/{model}/ contract with FK + sync extensions", () => {
167
- const resources = analyzeResources(resourcesDir);
168
- const doc = buildOpenApi(resources);
169
-
170
- // URL-segment contract the codegen keys off.
171
- expect(doc.paths["/api/airports/v1/terminal/"]).toBeDefined();
172
- expect(doc.paths["/api/airports/v1/terminal/{id}/"]).toBeDefined();
173
-
174
- // FK field carries the new relation extension.
175
- const terminalSchema = doc.components.schemas.Terminal;
176
- expect(terminalSchema.properties.airport["x-rastack-relation"]).toEqual({
177
- app: "airports",
178
- model: "airport",
179
- });
180
-
181
- // Local-mode sync extensions, confirmed on update.
182
- const flightList = doc.paths["/api/airports/v1/flight/"];
183
- expect(flightList.get["x-rastack-sync"]).toBe("local");
184
- expect(
185
- doc.paths["/api/airports/v1/flight/{id}/"].put["x-rastack-sync"],
186
- ).toBe("confirmed");
187
- expect(doc.paths["/api/airports/v1/gate/"].get["x-rastack-sync-load"]).toBe(
188
- "lazy",
189
- );
190
- expect(
191
- doc.paths["/api/airports/v1/booking/"].post["x-rastack-sync-client-ids"],
192
- ).toBe(true);
193
-
194
- // Access-controlled resource carries the full policy on every op — the
195
- // permission gate plus the access block `rastack/auth` mirrors in the UI.
196
- const itineraryList = doc.paths["/api/airports/v1/itinerary/"];
197
- expect(itineraryList.get["x-rastack-permission"]).toBe("authenticated");
198
- expect(itineraryList.get["x-rastack-access"]).toEqual({
199
- ownerField: "owner",
200
- scope: "owner",
201
- adminGroups: ["staff"],
202
- });
203
- expect(
204
- doc.paths["/api/airports/v1/itinerary/{id}/"].delete["x-rastack-access"],
205
- ).toEqual({ ownerField: "owner", scope: "owner", adminGroups: ["staff"] });
206
- // Unscoped resources stay unstamped.
207
- expect(
208
- doc.paths["/api/airports/v1/airport/"].get["x-rastack-access"],
209
- ).toBeUndefined();
210
- expect(
211
- doc.paths["/api/airports/v1/airport/"].get["x-rastack-permission"],
212
- ).toBeUndefined();
213
- });
214
-
215
- it("round-trips through the existing hooks codegen", async () => {
216
- const resources = analyzeResources(resourcesDir);
217
- const doc = buildOpenApi(resources);
218
- const paths = removeNonModelPaths(doc.paths);
219
-
220
- const entitiesPath = join(workRoot, "entities");
221
- mkdirSync(entitiesPath, { recursive: true });
222
- await generateFolders(entitiesPath, paths);
223
- await generateFiles(entitiesPath, paths);
224
-
225
- // Non-sync entity → plain async hook.
226
- const airportApi = readFileSync(
227
- join(entitiesPath, "airports", "airport", "api.ts"),
228
- "utf-8",
229
- );
230
- expect(airportApi).toContain("export function useListAirport(");
231
-
232
- // Sync entity → store-backed hooks + a defineEntity descriptor.
233
- const flightApi = readFileSync(
234
- join(entitiesPath, "airports", "flight", "api.ts"),
235
- "utf-8",
236
- );
237
- expect(flightApi).toContain("defineEntity<IFlight>({");
238
- expect(flightApi).toContain("from 'rastack/sync'");
239
- });
240
- });