@astrale-os/shell-react 0.3.2-beta.1 → 0.3.2-beta.2
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/dist/graph/resource.d.ts +3 -1
- package/dist/graph/resource.js +7 -2
- package/dist/schema/object.hook.js +3 -1
- package/dist/schema/relation.hook.js +3 -1
- package/package.json +2 -2
- package/src/graph/resource.ts +15 -3
- package/src/schema/object.hook.ts +3 -1
- package/src/schema/relation.hook.ts +3 -1
package/dist/graph/resource.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphStore, StoreQueryResponse } from '@astrale-os/sdk/client/store';
|
|
1
|
+
import type { GraphStore, StoreQueryResponse, StoreReadOptions } from '@astrale-os/sdk/client/store';
|
|
2
2
|
import type { QueryAST } from '@astrale-os/sdk/query';
|
|
3
3
|
export type GraphResourceState = 'idle' | 'loading' | 'ready' | 'stale' | 'refreshing' | 'optimistic' | 'failed';
|
|
4
4
|
export interface GraphResource<T> {
|
|
@@ -21,6 +21,8 @@ export interface GraphResource<T> {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
export interface StoreResourceOptions<Output> {
|
|
24
|
+
/** Exact closure evidence required by typed Domain projections. */
|
|
25
|
+
readonly expected?: StoreReadOptions['expected'];
|
|
24
26
|
readonly identity?: string;
|
|
25
27
|
readonly keepPrevious?: boolean;
|
|
26
28
|
readonly window?: 'page' | 'append';
|
package/dist/graph/resource.js
CHANGED
|
@@ -4,16 +4,18 @@ class StoreObserver {
|
|
|
4
4
|
store;
|
|
5
5
|
query;
|
|
6
6
|
size;
|
|
7
|
+
expected;
|
|
7
8
|
listeners = new Set();
|
|
8
9
|
pages = Object.freeze([Object.freeze({})]);
|
|
9
10
|
unsubs = Object.freeze([]);
|
|
10
11
|
current;
|
|
11
12
|
morePromise = null;
|
|
12
13
|
started = false;
|
|
13
|
-
constructor(store, query, size) {
|
|
14
|
+
constructor(store, query, size, expected) {
|
|
14
15
|
this.store = store;
|
|
15
16
|
this.query = query;
|
|
16
17
|
this.size = size;
|
|
18
|
+
this.expected = expected;
|
|
17
19
|
}
|
|
18
20
|
subscribe = (listener) => {
|
|
19
21
|
this.listeners.add(listener);
|
|
@@ -82,6 +84,7 @@ class StoreObserver {
|
|
|
82
84
|
size: this.size,
|
|
83
85
|
...(page.after === undefined ? {} : { after: page.after }),
|
|
84
86
|
}),
|
|
87
|
+
...(this.expected === undefined ? {} : { expected: this.expected }),
|
|
85
88
|
});
|
|
86
89
|
}
|
|
87
90
|
bindPages() {
|
|
@@ -98,7 +101,9 @@ const pollers = new WeakMap();
|
|
|
98
101
|
/** Adapt exact Store pages into a tear-free React resource without a parallel entity cache. */
|
|
99
102
|
export function useStoreResource(query, pageSize, project, options = {}) {
|
|
100
103
|
const store = useGraphStore();
|
|
101
|
-
const observer = useMemo(() =>
|
|
104
|
+
const observer = useMemo(() => query === null
|
|
105
|
+
? null
|
|
106
|
+
: new StoreObserver(store, query, positivePage(pageSize), options.expected), [store, query, pageSize, options.expected]);
|
|
102
107
|
const subscribe = useCallback((listener) => (observer === null ? () => { } : observer.subscribe(listener)), [observer]);
|
|
103
108
|
const idle = useMemo(() => Object.freeze({ snapshots: Object.freeze([]), pendingMore: false }), []);
|
|
104
109
|
const getSnapshot = useCallback(() => observer?.getSnapshot() ?? idle, [observer, idle]);
|
|
@@ -22,7 +22,9 @@ export function useObject(definition, target, options = {}) {
|
|
|
22
22
|
: result.graph.nodes.find((candidate) => candidate.id === id);
|
|
23
23
|
return node === undefined ? null : binding.wrapNode(definition, node);
|
|
24
24
|
}, [binding, definition]);
|
|
25
|
-
return useStoreResource(query, options.pageSize ?? 1, project
|
|
25
|
+
return useStoreResource(query, options.pageSize ?? 1, project, {
|
|
26
|
+
expected: binding.domain.closure,
|
|
27
|
+
});
|
|
26
28
|
}
|
|
27
29
|
/** Explicitly untyped point read for inspectors; it never impersonates `useObject`. */
|
|
28
30
|
export function useDynamicObject(target, options = {}) {
|
|
@@ -52,7 +52,9 @@ export function useRelation(relation, source, options) {
|
|
|
52
52
|
return undefined;
|
|
53
53
|
return Object.freeze(values);
|
|
54
54
|
}, [binding, cardinality, options.to]);
|
|
55
|
-
const resource = useStoreResource(query, options.page?.size ?? 50, project
|
|
55
|
+
const resource = useStoreResource(query, options.page?.size ?? 50, project, {
|
|
56
|
+
expected: binding.domain.closure,
|
|
57
|
+
});
|
|
56
58
|
const unavailable = (cardinality === '1' || cardinality === '1..*') &&
|
|
57
59
|
resource.data === undefined &&
|
|
58
60
|
resource.state !== 'idle' &&
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/shell-react",
|
|
3
|
-
"version": "0.3.2-beta.
|
|
3
|
+
"version": "0.3.2-beta.2",
|
|
4
4
|
"description": "Astrale shell-react — the React face of the shell (provider, hooks, view components)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"zod": "^4.4.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@astrale-os/sdk": "0.5.0-beta.
|
|
34
|
+
"@astrale-os/sdk": "0.5.0-beta.34",
|
|
35
35
|
"@testing-library/dom": "^10.4.0",
|
|
36
36
|
"@testing-library/react": "^16.3.0",
|
|
37
37
|
"@types/node": "^26.2.0",
|
package/src/graph/resource.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
GraphStore,
|
|
3
|
+
StoreQueryResponse,
|
|
4
|
+
StoreReadOptions,
|
|
5
|
+
StoreSnapshot,
|
|
6
|
+
} from '@astrale-os/sdk/client/store'
|
|
2
7
|
import type { QueryAST } from '@astrale-os/sdk/query'
|
|
3
8
|
|
|
4
9
|
import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'
|
|
@@ -32,6 +37,8 @@ export interface GraphResource<T> {
|
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
export interface StoreResourceOptions<Output> {
|
|
40
|
+
/** Exact closure evidence required by typed Domain projections. */
|
|
41
|
+
readonly expected?: StoreReadOptions['expected']
|
|
35
42
|
readonly identity?: string
|
|
36
43
|
readonly keepPrevious?: boolean
|
|
37
44
|
readonly window?: 'page' | 'append'
|
|
@@ -61,6 +68,7 @@ class StoreObserver<Query extends QueryAST> {
|
|
|
61
68
|
private readonly store: GraphStore,
|
|
62
69
|
private readonly query: Query,
|
|
63
70
|
private readonly size: number,
|
|
71
|
+
private readonly expected: StoreReadOptions['expected'],
|
|
64
72
|
) {}
|
|
65
73
|
|
|
66
74
|
subscribe = (listener: () => void): (() => void) => {
|
|
@@ -139,6 +147,7 @@ class StoreObserver<Query extends QueryAST> {
|
|
|
139
147
|
size: this.size,
|
|
140
148
|
...(page.after === undefined ? {} : { after: page.after }),
|
|
141
149
|
}),
|
|
150
|
+
...(this.expected === undefined ? {} : { expected: this.expected }),
|
|
142
151
|
})
|
|
143
152
|
}
|
|
144
153
|
|
|
@@ -181,8 +190,11 @@ export function useStoreResource<Query extends QueryAST, Output>(
|
|
|
181
190
|
): GraphResource<Output> {
|
|
182
191
|
const store = useGraphStore()
|
|
183
192
|
const observer = useMemo(
|
|
184
|
-
() =>
|
|
185
|
-
|
|
193
|
+
() =>
|
|
194
|
+
query === null
|
|
195
|
+
? null
|
|
196
|
+
: new StoreObserver(store, query, positivePage(pageSize), options.expected),
|
|
197
|
+
[store, query, pageSize, options.expected],
|
|
186
198
|
)
|
|
187
199
|
const subscribe = useCallback(
|
|
188
200
|
(listener: () => void) => (observer === null ? () => {} : observer.subscribe(listener)),
|
|
@@ -47,7 +47,9 @@ export function useObject<Class extends ResolvedClass<'node'>>(
|
|
|
47
47
|
},
|
|
48
48
|
[binding, definition],
|
|
49
49
|
)
|
|
50
|
-
return useStoreResource(query, options.pageSize ?? 1, project
|
|
50
|
+
return useStoreResource(query, options.pageSize ?? 1, project, {
|
|
51
|
+
expected: binding.domain.closure,
|
|
52
|
+
})
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
/** Explicitly untyped point read for inspectors; it never impersonates `useObject`. */
|
|
@@ -150,7 +150,9 @@ export function useRelation<
|
|
|
150
150
|
},
|
|
151
151
|
[binding, cardinality, options.to],
|
|
152
152
|
)
|
|
153
|
-
const resource = useStoreResource(query, options.page?.size ?? 50, project
|
|
153
|
+
const resource = useStoreResource(query, options.page?.size ?? 50, project, {
|
|
154
|
+
expected: binding.domain.closure,
|
|
155
|
+
})
|
|
154
156
|
const unavailable =
|
|
155
157
|
(cardinality === '1' || cardinality === '1..*') &&
|
|
156
158
|
resource.data === undefined &&
|