rastack 0.0.16 → 0.0.19
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 +43874 -43013
- package/dist/.prettierrc +7 -7
- package/dist/compile/analyze.js +19 -11
- package/dist/compile/index.js +26 -17
- package/dist/compile/manifest.js +2 -3
- package/dist/compile/openapi.js +5 -8
- package/dist/compile/program.js +19 -10
- package/dist/csv-schema.js +5 -6
- package/dist/define/index.js +2 -2
- package/dist/entity-generation/delete-method.js +8 -10
- package/dist/entity-generation/form.js +80 -82
- package/dist/entity-generation/get-method.js +35 -36
- package/dist/entity-generation/imports.js +24 -20
- package/dist/entity-generation/sync-method.d.ts +1 -1
- package/dist/entity-generation/sync-method.js +45 -46
- package/dist/entity-generation/update-method.js +9 -10
- package/dist/rad-wasm-build.d.ts +1 -1
- package/dist/rad-wasm-build.js +15 -6
- package/dist/rad.js +9 -2
- package/dist/schema/camel-to-pastel.js +1 -2
- package/dist/schema/capitalise-first-letter.js +1 -2
- package/dist/schema/extract-response.js +3 -4
- package/dist/schema/fetch-schema.js +4 -16
- package/dist/schema/remove-non-model-paths.js +1 -2
- package/dist/schema/to-camel-case.js +1 -2
- package/dist/schema/to-pastel-case.js +1 -2
- package/dist/schema-convert.js +22 -33
- package/dist/schema-entities.js +177 -189
- package/dist/schema-fetch.js +46 -63
- package/dist/schema-full.js +23 -36
- package/dist/schema-index.js +16 -27
- package/dist/schema-params.js +11 -22
- package/dist/seed.js +95 -97
- package/hooks/form/form.ts +207 -207
- package/hooks/form/index.ts +8 -8
- package/hooks/form/interfaces.ts +217 -217
- package/hooks/form/structure.ts +39 -39
- package/hooks/form/validate-schema.ts +49 -49
- package/hooks/index.ts +3 -3
- package/hooks/query/api.ts +42 -42
- package/hooks/query/delete.ts +45 -45
- package/hooks/query/fetch.ts +48 -48
- package/hooks/query/index.ts +21 -21
- package/hooks/query/interfaces.ts +111 -111
- package/hooks/query/list.ts +286 -286
- package/hooks/query/update.ts +88 -88
- package/hooks/query/url.ts +31 -31
- package/hooks/real-time/index.ts +1 -1
- package/hooks/real-time/pusher.ts +43 -43
- package/jest.config.cjs +6 -6
- package/package.json +57 -57
- package/provider/index.ts +13 -13
- package/provider/provider.tsx +187 -187
- package/provider/types.ts +114 -114
- package/provider/warehouse.ts +167 -167
- package/provider/wasm.ts +124 -124
- package/runtime.ts +3 -3
- package/src/.prettierrc +7 -7
- package/src/compile/analyze.ts +224 -224
- package/src/compile/index.ts +86 -86
- package/src/compile/manifest.ts +10 -10
- package/src/compile/model.ts +69 -69
- package/src/compile/openapi.ts +266 -266
- package/src/compile/program.ts +40 -40
- package/src/csv-schema.ts +187 -187
- package/src/define/index.ts +162 -162
- package/src/entity-generation/delete-method.ts +37 -37
- package/src/entity-generation/form.ts +169 -169
- package/src/entity-generation/get-method.ts +80 -80
- package/src/entity-generation/imports.ts +110 -110
- package/src/entity-generation/sync-method.ts +222 -222
- package/src/entity-generation/update-method.ts +38 -38
- package/src/index.ts +77 -77
- package/src/rad-compile.ts +88 -88
- package/src/rad-wasm-build.ts +102 -102
- package/src/rad.ts +101 -101
- package/src/scan.ts +89 -89
- package/src/schema/camel-to-pastel.ts +3 -3
- package/src/schema/capitalise-first-letter.ts +3 -3
- package/src/schema/extract-response.ts +38 -38
- package/src/schema/fetch-schema.ts +12 -12
- package/src/schema/remove-non-model-paths.ts +13 -13
- package/src/schema/to-camel-case.ts +7 -7
- package/src/schema/to-pastel-case.ts +6 -6
- package/src/schema-convert.ts +61 -61
- package/src/schema-entities.ts +401 -401
- package/src/schema-fetch.ts +82 -82
- package/src/schema-full.ts +38 -38
- package/src/schema-index.ts +29 -29
- package/src/schema-params.ts +116 -116
- package/src/seed.ts +297 -297
- package/sync/engine.ts +392 -392
- package/sync/hooks.ts +450 -450
- package/sync/index.ts +8 -8
- package/sync/persistence.ts +237 -237
- package/sync/provider.tsx +91 -91
- package/sync/registry.ts +36 -36
- package/sync/store.ts +126 -126
- package/sync/transactions.ts +300 -300
- package/sync/types.ts +94 -94
- package/test/compile.spec.ts +192 -192
- package/test/csv-schema.spec.ts +143 -143
- package/test/schema-entities.spec.ts +688 -688
- package/tsconfig.json +24 -24
- package/types.ts +18 -18
package/sync/registry.ts
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import { EntityDescriptor, EntityKey, entityKey } from "./types";
|
|
2
|
-
|
|
3
|
-
const entities = new Map<EntityKey, EntityDescriptor>();
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Registers a sync-mode entity. Called from generated entity modules at
|
|
7
|
-
* import time, so every entity a bundle uses is known before the engine
|
|
8
|
-
* starts. Idempotent per (app, model).
|
|
9
|
-
*/
|
|
10
|
-
export function defineEntity<TRow = any>(
|
|
11
|
-
descriptor: Omit<EntityDescriptor<TRow>, "__row">,
|
|
12
|
-
): EntityDescriptor<TRow> {
|
|
13
|
-
const key = entityKey(descriptor as EntityDescriptor);
|
|
14
|
-
const existing = entities.get(key);
|
|
15
|
-
if (existing) {
|
|
16
|
-
return existing as EntityDescriptor<TRow>;
|
|
17
|
-
}
|
|
18
|
-
const entity: EntityDescriptor<TRow> = {
|
|
19
|
-
idField: "id",
|
|
20
|
-
...descriptor,
|
|
21
|
-
};
|
|
22
|
-
entities.set(key, entity as EntityDescriptor);
|
|
23
|
-
return entity;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function getRegisteredEntities(): EntityDescriptor[] {
|
|
27
|
-
return Array.from(entities.values());
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getEntity(key: EntityKey): EntityDescriptor | undefined {
|
|
31
|
-
return entities.get(key);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function clearEntityRegistry(): void {
|
|
35
|
-
entities.clear();
|
|
36
|
-
}
|
|
1
|
+
import { EntityDescriptor, EntityKey, entityKey } from "./types";
|
|
2
|
+
|
|
3
|
+
const entities = new Map<EntityKey, EntityDescriptor>();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Registers a sync-mode entity. Called from generated entity modules at
|
|
7
|
+
* import time, so every entity a bundle uses is known before the engine
|
|
8
|
+
* starts. Idempotent per (app, model).
|
|
9
|
+
*/
|
|
10
|
+
export function defineEntity<TRow = any>(
|
|
11
|
+
descriptor: Omit<EntityDescriptor<TRow>, "__row">,
|
|
12
|
+
): EntityDescriptor<TRow> {
|
|
13
|
+
const key = entityKey(descriptor as EntityDescriptor);
|
|
14
|
+
const existing = entities.get(key);
|
|
15
|
+
if (existing) {
|
|
16
|
+
return existing as EntityDescriptor<TRow>;
|
|
17
|
+
}
|
|
18
|
+
const entity: EntityDescriptor<TRow> = {
|
|
19
|
+
idField: "id",
|
|
20
|
+
...descriptor,
|
|
21
|
+
};
|
|
22
|
+
entities.set(key, entity as EntityDescriptor);
|
|
23
|
+
return entity;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getRegisteredEntities(): EntityDescriptor[] {
|
|
27
|
+
return Array.from(entities.values());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getEntity(key: EntityKey): EntityDescriptor | undefined {
|
|
31
|
+
return entities.get(key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function clearEntityRegistry(): void {
|
|
35
|
+
entities.clear();
|
|
36
|
+
}
|
package/sync/store.ts
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
import { EntityKey } from "./types";
|
|
2
|
-
|
|
3
|
-
type Listener = () => void;
|
|
4
|
-
|
|
5
|
-
interface EntityCache {
|
|
6
|
-
rows: Map<string, Record<string, any>>;
|
|
7
|
-
/** Stable array reference for useSyncExternalStore; rebuilt on change. */
|
|
8
|
-
listSnapshot: Record<string, any>[] | null;
|
|
9
|
-
ready: boolean;
|
|
10
|
-
listeners: Set<Listener>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* The in-memory object pool. One cache per entity, keyed `${app}.${model}`.
|
|
15
|
-
* The store is only the live working set: durable state lives in the
|
|
16
|
-
* persistence layer and is only written from server deltas, so local disk
|
|
17
|
-
* always remains a subset of server state (Linear's invariant).
|
|
18
|
-
*/
|
|
19
|
-
export class SyncStore {
|
|
20
|
-
private caches = new Map<EntityKey, EntityCache>();
|
|
21
|
-
|
|
22
|
-
private cache(entity: EntityKey): EntityCache {
|
|
23
|
-
let cache = this.caches.get(entity);
|
|
24
|
-
if (!cache) {
|
|
25
|
-
cache = {
|
|
26
|
-
rows: new Map(),
|
|
27
|
-
listSnapshot: null,
|
|
28
|
-
ready: false,
|
|
29
|
-
listeners: new Set(),
|
|
30
|
-
};
|
|
31
|
-
this.caches.set(entity, cache);
|
|
32
|
-
}
|
|
33
|
-
return cache;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get(entity: EntityKey, id: string): Record<string, any> | undefined {
|
|
37
|
-
return this.cache(entity).rows.get(id);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getList(entity: EntityKey): Record<string, any>[] {
|
|
41
|
-
const cache = this.cache(entity);
|
|
42
|
-
if (!cache.listSnapshot) {
|
|
43
|
-
cache.listSnapshot = Array.from(cache.rows.values());
|
|
44
|
-
}
|
|
45
|
-
return cache.listSnapshot;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
isReady(entity: EntityKey): boolean {
|
|
49
|
-
return this.cache(entity).ready;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
markReady(entity: EntityKey): void {
|
|
53
|
-
const cache = this.cache(entity);
|
|
54
|
-
if (!cache.ready) {
|
|
55
|
-
cache.ready = true;
|
|
56
|
-
this.emit(cache);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
upsert(entity: EntityKey, id: string, row: Record<string, any>): void {
|
|
61
|
-
const cache = this.cache(entity);
|
|
62
|
-
cache.rows.set(id, row);
|
|
63
|
-
this.emit(cache);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
merge(
|
|
67
|
-
entity: EntityKey,
|
|
68
|
-
id: string,
|
|
69
|
-
changes: Record<string, any>,
|
|
70
|
-
): Record<string, any> {
|
|
71
|
-
const cache = this.cache(entity);
|
|
72
|
-
const next = { ...(cache.rows.get(id) || {}), ...changes };
|
|
73
|
-
cache.rows.set(id, next);
|
|
74
|
-
this.emit(cache);
|
|
75
|
-
return next;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
remove(entity: EntityKey, id: string): void {
|
|
79
|
-
const cache = this.cache(entity);
|
|
80
|
-
if (cache.rows.delete(id)) {
|
|
81
|
-
this.emit(cache);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
replaceId(entity: EntityKey, fromId: string, toId: string): void {
|
|
86
|
-
const cache = this.cache(entity);
|
|
87
|
-
const row = cache.rows.get(fromId);
|
|
88
|
-
if (row !== undefined) {
|
|
89
|
-
cache.rows.delete(fromId);
|
|
90
|
-
cache.rows.set(toId, row);
|
|
91
|
-
this.emit(cache);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
hydrate(entity: EntityKey, rows: Record<string, any>[], idField: string): void {
|
|
96
|
-
const cache = this.cache(entity);
|
|
97
|
-
rows.forEach((row) => {
|
|
98
|
-
const id = String(row[idField]);
|
|
99
|
-
cache.rows.set(id, row);
|
|
100
|
-
});
|
|
101
|
-
cache.ready = true;
|
|
102
|
-
this.emit(cache);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
subscribe(entity: EntityKey, listener: Listener): () => void {
|
|
106
|
-
const cache = this.cache(entity);
|
|
107
|
-
cache.listeners.add(listener);
|
|
108
|
-
return () => {
|
|
109
|
-
cache.listeners.delete(listener);
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
clear(): void {
|
|
114
|
-
this.caches.forEach((cache) => {
|
|
115
|
-
cache.rows.clear();
|
|
116
|
-
cache.listSnapshot = null;
|
|
117
|
-
cache.ready = false;
|
|
118
|
-
cache.listeners.forEach((listener) => listener());
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
private emit(cache: EntityCache): void {
|
|
123
|
-
cache.listSnapshot = null;
|
|
124
|
-
cache.listeners.forEach((listener) => listener());
|
|
125
|
-
}
|
|
126
|
-
}
|
|
1
|
+
import { EntityKey } from "./types";
|
|
2
|
+
|
|
3
|
+
type Listener = () => void;
|
|
4
|
+
|
|
5
|
+
interface EntityCache {
|
|
6
|
+
rows: Map<string, Record<string, any>>;
|
|
7
|
+
/** Stable array reference for useSyncExternalStore; rebuilt on change. */
|
|
8
|
+
listSnapshot: Record<string, any>[] | null;
|
|
9
|
+
ready: boolean;
|
|
10
|
+
listeners: Set<Listener>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The in-memory object pool. One cache per entity, keyed `${app}.${model}`.
|
|
15
|
+
* The store is only the live working set: durable state lives in the
|
|
16
|
+
* persistence layer and is only written from server deltas, so local disk
|
|
17
|
+
* always remains a subset of server state (Linear's invariant).
|
|
18
|
+
*/
|
|
19
|
+
export class SyncStore {
|
|
20
|
+
private caches = new Map<EntityKey, EntityCache>();
|
|
21
|
+
|
|
22
|
+
private cache(entity: EntityKey): EntityCache {
|
|
23
|
+
let cache = this.caches.get(entity);
|
|
24
|
+
if (!cache) {
|
|
25
|
+
cache = {
|
|
26
|
+
rows: new Map(),
|
|
27
|
+
listSnapshot: null,
|
|
28
|
+
ready: false,
|
|
29
|
+
listeners: new Set(),
|
|
30
|
+
};
|
|
31
|
+
this.caches.set(entity, cache);
|
|
32
|
+
}
|
|
33
|
+
return cache;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get(entity: EntityKey, id: string): Record<string, any> | undefined {
|
|
37
|
+
return this.cache(entity).rows.get(id);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getList(entity: EntityKey): Record<string, any>[] {
|
|
41
|
+
const cache = this.cache(entity);
|
|
42
|
+
if (!cache.listSnapshot) {
|
|
43
|
+
cache.listSnapshot = Array.from(cache.rows.values());
|
|
44
|
+
}
|
|
45
|
+
return cache.listSnapshot;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
isReady(entity: EntityKey): boolean {
|
|
49
|
+
return this.cache(entity).ready;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
markReady(entity: EntityKey): void {
|
|
53
|
+
const cache = this.cache(entity);
|
|
54
|
+
if (!cache.ready) {
|
|
55
|
+
cache.ready = true;
|
|
56
|
+
this.emit(cache);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
upsert(entity: EntityKey, id: string, row: Record<string, any>): void {
|
|
61
|
+
const cache = this.cache(entity);
|
|
62
|
+
cache.rows.set(id, row);
|
|
63
|
+
this.emit(cache);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
merge(
|
|
67
|
+
entity: EntityKey,
|
|
68
|
+
id: string,
|
|
69
|
+
changes: Record<string, any>,
|
|
70
|
+
): Record<string, any> {
|
|
71
|
+
const cache = this.cache(entity);
|
|
72
|
+
const next = { ...(cache.rows.get(id) || {}), ...changes };
|
|
73
|
+
cache.rows.set(id, next);
|
|
74
|
+
this.emit(cache);
|
|
75
|
+
return next;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
remove(entity: EntityKey, id: string): void {
|
|
79
|
+
const cache = this.cache(entity);
|
|
80
|
+
if (cache.rows.delete(id)) {
|
|
81
|
+
this.emit(cache);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
replaceId(entity: EntityKey, fromId: string, toId: string): void {
|
|
86
|
+
const cache = this.cache(entity);
|
|
87
|
+
const row = cache.rows.get(fromId);
|
|
88
|
+
if (row !== undefined) {
|
|
89
|
+
cache.rows.delete(fromId);
|
|
90
|
+
cache.rows.set(toId, row);
|
|
91
|
+
this.emit(cache);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
hydrate(entity: EntityKey, rows: Record<string, any>[], idField: string): void {
|
|
96
|
+
const cache = this.cache(entity);
|
|
97
|
+
rows.forEach((row) => {
|
|
98
|
+
const id = String(row[idField]);
|
|
99
|
+
cache.rows.set(id, row);
|
|
100
|
+
});
|
|
101
|
+
cache.ready = true;
|
|
102
|
+
this.emit(cache);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
subscribe(entity: EntityKey, listener: Listener): () => void {
|
|
106
|
+
const cache = this.cache(entity);
|
|
107
|
+
cache.listeners.add(listener);
|
|
108
|
+
return () => {
|
|
109
|
+
cache.listeners.delete(listener);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
clear(): void {
|
|
114
|
+
this.caches.forEach((cache) => {
|
|
115
|
+
cache.rows.clear();
|
|
116
|
+
cache.listSnapshot = null;
|
|
117
|
+
cache.ready = false;
|
|
118
|
+
cache.listeners.forEach((listener) => listener());
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private emit(cache: EntityCache): void {
|
|
123
|
+
cache.listSnapshot = null;
|
|
124
|
+
cache.listeners.forEach((listener) => listener());
|
|
125
|
+
}
|
|
126
|
+
}
|