@astrale-os/shell-react 0.2.10-beta.3 → 0.3.1
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/application/apps/app-host.d.ts +5 -5
- package/dist/application/apps/app-host.d.ts.map +1 -1
- package/dist/application/apps/app-host.js +18 -39
- package/dist/application/apps/apps.hook.d.ts +4 -11
- package/dist/application/apps/apps.hook.d.ts.map +1 -1
- package/dist/application/apps/apps.hook.js +9 -49
- package/dist/application/apps/open-app.hook.d.ts +4 -7
- package/dist/application/apps/open-app.hook.d.ts.map +1 -1
- package/dist/application/apps/open-app.hook.js +2 -2
- package/dist/application/index.d.ts +1 -3
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +1 -2
- package/dist/application/spaces/space.hook.d.ts.map +1 -1
- package/dist/application/spaces/space.hook.js +4 -1
- package/dist/auth/act-as.context.d.ts +1 -1
- package/dist/auth/act-as.context.d.ts.map +1 -1
- package/dist/auth/auth.hook.d.ts +1 -1
- package/dist/auth/auth.hook.d.ts.map +1 -1
- package/dist/auth/can.hook.d.ts +2 -2
- package/dist/auth/can.hook.d.ts.map +1 -1
- package/dist/auth/self.hook.d.ts +1 -1
- package/dist/auth/self.hook.d.ts.map +1 -1
- package/dist/components/can.d.ts +2 -2
- package/dist/components/can.d.ts.map +1 -1
- package/dist/graph/call/call.hook.d.ts +2 -2
- package/dist/graph/call/call.hook.d.ts.map +1 -1
- package/dist/graph/call/stream.hook.d.ts +2 -2
- package/dist/graph/call/stream.hook.d.ts.map +1 -1
- package/dist/graph/graph.context.d.ts +1 -1
- package/dist/graph/graph.context.d.ts.map +1 -1
- package/dist/graph/guards.error.d.ts +4 -4
- package/dist/graph/guards.error.d.ts.map +1 -1
- package/dist/graph/guards.error.js +4 -4
- package/dist/graph/query-definition.hook.d.ts +1 -2
- package/dist/graph/query-definition.hook.d.ts.map +1 -1
- package/dist/graph/query-definition.hook.js +4 -10
- package/dist/graph/resource.d.ts +1 -1
- package/dist/graph/resource.d.ts.map +1 -1
- package/dist/graph/store.d.ts +2 -2
- package/dist/graph/store.d.ts.map +1 -1
- package/dist/graph/store.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/url.adapter.js +2 -5
- package/dist/navigation/codec.d.ts.map +1 -1
- package/dist/navigation/codec.js +1 -7
- package/dist/navigation/link.js +1 -1
- package/dist/navigation/scope.context.d.ts +1 -1
- package/dist/navigation/scope.context.d.ts.map +1 -1
- package/dist/navigation/scope.context.js +3 -6
- package/dist/navigation/snapshot.d.ts +1 -1
- package/dist/navigation/snapshot.d.ts.map +1 -1
- package/dist/navigation/snapshot.js +2 -8
- package/dist/navigation/view-key.d.ts +3 -0
- package/dist/navigation/view-key.d.ts.map +1 -0
- package/dist/navigation/view-key.js +8 -0
- package/dist/schema/action.hook.d.ts +11 -7
- package/dist/schema/action.hook.d.ts.map +1 -1
- package/dist/schema/action.hook.js +11 -6
- package/dist/schema/domain.hook.js +12 -13
- package/dist/schema/kernel.hook.d.ts +1 -1
- package/dist/schema/kernel.hook.d.ts.map +1 -1
- package/dist/schema/kernel.hook.js +1 -1
- package/dist/schema/mutation.hook.d.ts +2 -2
- package/dist/schema/mutation.hook.d.ts.map +1 -1
- package/dist/schema/mutation.hook.js +6 -5
- package/dist/schema/object.hook.d.ts +3 -6
- package/dist/schema/object.hook.d.ts.map +1 -1
- package/dist/schema/object.hook.js +4 -5
- package/dist/schema/relation.hook.d.ts +29 -19
- package/dist/schema/relation.hook.d.ts.map +1 -1
- package/dist/schema/relation.hook.js +45 -63
- package/dist/selection/live.d.ts.map +1 -1
- package/dist/selection/live.js +1 -2
- package/dist/session/session.context.d.ts +3 -4
- package/dist/session/session.context.d.ts.map +1 -1
- package/package.json +4 -14
- package/src/application/apps/app-host.tsx +22 -52
- package/src/application/apps/apps.hook.ts +14 -64
- package/src/application/apps/open-app.hook.ts +5 -10
- package/src/application/index.ts +2 -12
- package/src/application/spaces/space.hook.ts +6 -1
- package/src/auth/act-as.context.tsx +1 -1
- package/src/auth/auth.hook.ts +1 -1
- package/src/auth/can.hook.ts +3 -3
- package/src/auth/self.hook.ts +1 -1
- package/src/components/can.tsx +2 -2
- package/src/graph/call/call.hook.ts +2 -2
- package/src/graph/call/stream.hook.ts +2 -2
- package/src/graph/graph.context.ts +1 -1
- package/src/graph/guards.error.ts +4 -4
- package/src/graph/query-definition.hook.ts +13 -23
- package/src/graph/resource.ts +1 -1
- package/src/graph/store.ts +3 -3
- package/src/index.ts +3 -7
- package/src/navigation/adapters/url.adapter.ts +3 -4
- package/src/navigation/codec.ts +1 -7
- package/src/navigation/link.tsx +1 -1
- package/src/navigation/scope.context.tsx +5 -6
- package/src/navigation/snapshot.ts +4 -9
- package/src/navigation/view-key.ts +11 -0
- package/src/schema/action.hook.ts +45 -28
- package/src/schema/domain.hook.ts +9 -10
- package/src/schema/kernel.hook.ts +1 -1
- package/src/schema/mutation.hook.ts +13 -9
- package/src/schema/object.hook.ts +10 -18
- package/src/schema/relation.hook.ts +127 -145
- package/src/selection/live.ts +1 -2
- package/src/session/session.context.ts +3 -4
- package/dist/application/apps/domains.hook.d.ts +0 -7
- package/dist/application/apps/domains.hook.d.ts.map +0 -1
- package/dist/application/apps/domains.hook.js +0 -18
- package/src/application/apps/domains.hook.ts +0 -37
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
EdgeEndpointAcceptedDefinitionsOf,
|
|
6
|
-
} from '@astrale-os/sdk/domain'
|
|
7
|
-
import type { LinkedCountOf } from '@astrale-os/sdk/query'
|
|
1
|
+
import type { BoundNode } from '@astrale-os/sdk/client'
|
|
2
|
+
import type { StoreQueryResponse } from '@astrale-os/sdk/client/store'
|
|
3
|
+
import type { NodeId } from '@astrale-os/sdk/graph/node'
|
|
4
|
+
import type { ClassKey as ClassKeyValue, ClassRef, ResolvedClass } from '@astrale-os/sdk/schema'
|
|
8
5
|
|
|
9
|
-
import { NodeId } from '@astrale-os/sdk/graph/node'
|
|
10
6
|
import { Path } from '@astrale-os/sdk/graph/path'
|
|
11
7
|
import { Query } from '@astrale-os/sdk/query'
|
|
8
|
+
import { ClassKey } from '@astrale-os/sdk/schema'
|
|
12
9
|
import { useCallback, useMemo } from 'react'
|
|
13
10
|
|
|
14
11
|
import type { GraphResource } from '../graph/resource.js'
|
|
@@ -16,42 +13,61 @@ import type { GraphResource } from '../graph/resource.js'
|
|
|
16
13
|
import { useStoreResource } from '../graph/resource.js'
|
|
17
14
|
import { bindingFor } from './domain.hook.js'
|
|
18
15
|
|
|
19
|
-
type DefinitionCoordinates = Pick<
|
|
20
|
-
Definition<'class' | 'interface'>,
|
|
21
|
-
'kind' | 'origin' | 'name' | 'key' | 'schemaRef' | 'definition'
|
|
22
|
-
>
|
|
23
|
-
type NodeDefinition = DefinitionCoordinates & { readonly family: 'node' }
|
|
24
|
-
type EdgeDefinition = DefinitionCoordinates & { readonly family: 'edge' }
|
|
25
16
|
type EndpointRole = 'source' | 'target'
|
|
26
17
|
type RelationCardinality = '1' | '0..1' | '0..*' | '1..*'
|
|
27
18
|
type RuntimeEndpoint = {
|
|
28
|
-
readonly accepts: readonly
|
|
29
|
-
readonly origin: string
|
|
30
|
-
readonly kind: 'class' | 'interface'
|
|
31
|
-
readonly name: string
|
|
32
|
-
}[]
|
|
19
|
+
readonly accepts: readonly ClassRef[]
|
|
33
20
|
readonly outgoing?: RelationCardinality
|
|
34
21
|
readonly incoming?: RelationCardinality
|
|
35
22
|
}
|
|
23
|
+
type DefinitionOf<Relation> =
|
|
24
|
+
Relation extends ResolvedClass<
|
|
25
|
+
'edge',
|
|
26
|
+
infer _Properties,
|
|
27
|
+
infer _Methods,
|
|
28
|
+
infer _StaticMethods,
|
|
29
|
+
infer _SelfProperties,
|
|
30
|
+
infer _SelfMethods,
|
|
31
|
+
infer _SelfStaticMethods,
|
|
32
|
+
infer Definition
|
|
33
|
+
>
|
|
34
|
+
? Definition
|
|
35
|
+
: never
|
|
36
|
+
type EndpointsOf<Relation> =
|
|
37
|
+
DefinitionOf<Relation> extends {
|
|
38
|
+
readonly orientation: 'directed'
|
|
39
|
+
readonly endpoints: infer Endpoints
|
|
40
|
+
}
|
|
41
|
+
? Endpoints
|
|
42
|
+
: never
|
|
36
43
|
type Opposite<Role extends EndpointRole> = Role extends 'source' ? 'target' : 'source'
|
|
37
|
-
type
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Relation
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
type AcceptedAt<Relation, Role extends EndpointRole> = Role extends keyof EndpointsOf<Relation>
|
|
45
|
+
? EndpointsOf<Relation>[Role] extends { readonly accepts: readonly (infer Accepted)[] }
|
|
46
|
+
? Accepted
|
|
47
|
+
: never
|
|
48
|
+
: never
|
|
49
|
+
type DeclaredCardinality<Relation, Role extends EndpointRole> = Role extends 'source'
|
|
50
|
+
? EndpointsOf<Relation> extends { readonly source: { readonly outgoing: infer Count } }
|
|
51
|
+
? Extract<Count, RelationCardinality>
|
|
52
|
+
: RelationCardinality
|
|
53
|
+
: EndpointsOf<Relation> extends { readonly target: { readonly incoming: infer Count } }
|
|
54
|
+
? Extract<Count, RelationCardinality>
|
|
55
|
+
: RelationCardinality
|
|
56
|
+
type CoversOpposite<Relation, Role extends EndpointRole, To extends ResolvedClass<'node'>> = [
|
|
57
|
+
AcceptedAt<Relation, Opposite<Role>>,
|
|
58
|
+
] extends [To['ref']]
|
|
59
|
+
? true
|
|
60
|
+
: false
|
|
61
|
+
type EffectiveCardinality<Relation, Role extends EndpointRole, To extends ResolvedClass<'node'>> =
|
|
62
|
+
DeclaredCardinality<Relation, Role> extends infer Count extends RelationCardinality
|
|
63
|
+
? CoversOpposite<Relation, Role, To> extends true
|
|
64
|
+
? Count
|
|
65
|
+
: Count extends '1'
|
|
66
|
+
? '0..1'
|
|
67
|
+
: Count extends '1..*'
|
|
68
|
+
? '0..*'
|
|
69
|
+
: Count
|
|
70
|
+
: RelationCardinality
|
|
55
71
|
|
|
56
72
|
export interface RelationUnavailable {
|
|
57
73
|
readonly kind: 'required-hidden-or-invalid'
|
|
@@ -68,59 +84,50 @@ export class RelationUnavailableError extends Error {
|
|
|
68
84
|
}
|
|
69
85
|
}
|
|
70
86
|
|
|
71
|
-
export type RelationResource<T,
|
|
87
|
+
export type RelationResource<T, Cardinality extends RelationCardinality> = Cardinality extends
|
|
88
|
+
| '1'
|
|
89
|
+
| '0..1'
|
|
72
90
|
? GraphResource<T | null> & {
|
|
73
|
-
readonly cardinality:
|
|
91
|
+
readonly cardinality: Cardinality
|
|
74
92
|
readonly unavailable?: RelationUnavailable
|
|
75
93
|
require(): T
|
|
76
94
|
}
|
|
77
95
|
: GraphResource<readonly T[]> & {
|
|
78
|
-
readonly cardinality:
|
|
96
|
+
readonly cardinality: Cardinality
|
|
79
97
|
readonly unavailable?: RelationUnavailable
|
|
80
98
|
require(): readonly T[]
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
export interface RelationOptions<Role extends EndpointRole, To> {
|
|
84
102
|
readonly from: Role
|
|
85
|
-
/** Exact rich opposite-endpoint definition used to admit and brand returned nodes. */
|
|
86
103
|
readonly to: To
|
|
87
104
|
readonly page?: { readonly size: number }
|
|
88
105
|
}
|
|
89
106
|
|
|
90
|
-
/** Traverse one
|
|
107
|
+
/** Traverse one directed resolved Edge Class and bind the selected opposite Nodes. */
|
|
91
108
|
export function useRelation<
|
|
92
|
-
|
|
109
|
+
Relation extends ResolvedClass<'edge'>,
|
|
93
110
|
Role extends EndpointRole,
|
|
94
|
-
To extends
|
|
111
|
+
To extends ResolvedClass<'node'>,
|
|
112
|
+
Source extends ResolvedClass<'node'>,
|
|
95
113
|
>(
|
|
96
|
-
|
|
97
|
-
source:
|
|
114
|
+
relation: Relation,
|
|
115
|
+
source: BoundNode<Source> | null | undefined,
|
|
98
116
|
options: RelationOptions<Role, To>,
|
|
99
|
-
): RelationResource<
|
|
100
|
-
const binding = bindingFor(
|
|
101
|
-
if (source !== null && source !== undefined)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
admitRelatedDefinition(binding, definition, options.from, options.to)
|
|
105
|
-
const path = source === null || source === undefined ? null : Path.id(NodeId(source.id))
|
|
117
|
+
): RelationResource<BoundNode<To>, EffectiveCardinality<Relation, Role, To>> {
|
|
118
|
+
const binding = bindingFor(relation)
|
|
119
|
+
if (source !== null && source !== undefined) admitSource(binding, relation, options.from, source)
|
|
120
|
+
admitRelatedDefinition(binding, relation, options.from, options.to)
|
|
121
|
+
const path = source === null || source === undefined ? null : Path.id(source.id as NodeId)
|
|
106
122
|
const query = useMemo(() => {
|
|
107
123
|
if (path === null) return null
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
const expanded = admitted.expand({
|
|
111
|
-
via: [definition.schemaRef],
|
|
124
|
+
const expanded = Query.from({ nodes: [path] }).expand({
|
|
125
|
+
via: [relation],
|
|
112
126
|
direction: options.from === 'source' ? 'outgoing' : 'incoming',
|
|
113
127
|
})
|
|
114
|
-
return expanded
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}, [definition, options.from, options.to, path?.raw, source])
|
|
118
|
-
const cardinality: RelationCardinality = effectiveCardinality(
|
|
119
|
-
binding,
|
|
120
|
-
definition,
|
|
121
|
-
options.from,
|
|
122
|
-
options.to,
|
|
123
|
-
)
|
|
128
|
+
return expanded.filter({ class: options.to }).select({ kind: 'graph', binding: expanded.node })
|
|
129
|
+
}, [relation, options.from, options.to, path?.raw])
|
|
130
|
+
const cardinality = effectiveCardinality(binding, relation, options.from, options.to)
|
|
124
131
|
const project = useCallback(
|
|
125
132
|
(response: StoreQueryResponse<NonNullable<typeof query>>) => {
|
|
126
133
|
const result = response.result
|
|
@@ -134,30 +141,21 @@ export function useRelation<
|
|
|
134
141
|
const byId = new Map(result.graph.nodes.map((node) => [node.id, node]))
|
|
135
142
|
const values = result.selection.ids.flatMap((id) => {
|
|
136
143
|
const node = byId.get(id)
|
|
137
|
-
|
|
138
|
-
const bind = binding.$.bind as unknown as (
|
|
139
|
-
expected: To,
|
|
140
|
-
value: typeof node,
|
|
141
|
-
) => BoundInstanceOf<To>
|
|
142
|
-
return [bind(options.to, node)]
|
|
144
|
+
return node === undefined ? [] : [binding.wrapNode(options.to, node)]
|
|
143
145
|
})
|
|
144
146
|
if (cardinality === '0..1') return values[0] ?? null
|
|
145
147
|
if (cardinality === '1') return values[0]
|
|
146
148
|
if (cardinality === '1..*' && values.length === 0) return undefined
|
|
147
149
|
return Object.freeze(values)
|
|
148
150
|
},
|
|
149
|
-
[binding, cardinality, options.to
|
|
151
|
+
[binding, cardinality, options.to],
|
|
150
152
|
)
|
|
151
153
|
const resource = useStoreResource(query, options.page?.size ?? 50, project)
|
|
152
154
|
const unavailable =
|
|
153
|
-
(cardinality === '1' &&
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
(cardinality === '1..*' &&
|
|
158
|
-
resource.data === undefined &&
|
|
159
|
-
resource.state !== 'idle' &&
|
|
160
|
-
resource.state !== 'loading')
|
|
155
|
+
(cardinality === '1' || cardinality === '1..*') &&
|
|
156
|
+
resource.data === undefined &&
|
|
157
|
+
resource.state !== 'idle' &&
|
|
158
|
+
resource.state !== 'loading'
|
|
161
159
|
? Object.freeze({ kind: 'required-hidden-or-invalid' as const, cardinality })
|
|
162
160
|
: undefined
|
|
163
161
|
const require = () => {
|
|
@@ -172,82 +170,66 @@ export function useRelation<
|
|
|
172
170
|
cardinality,
|
|
173
171
|
...(unavailable === undefined ? {} : { unavailable }),
|
|
174
172
|
require,
|
|
175
|
-
}) as RelationResource<
|
|
173
|
+
}) as RelationResource<BoundNode<To>, EffectiveCardinality<Relation, Role, To>>
|
|
176
174
|
}
|
|
177
175
|
|
|
178
|
-
function admitSource
|
|
176
|
+
function admitSource(
|
|
179
177
|
binding: ReturnType<typeof bindingFor>,
|
|
180
|
-
relation:
|
|
181
|
-
from:
|
|
182
|
-
source:
|
|
178
|
+
relation: ResolvedClass<'edge'>,
|
|
179
|
+
from: EndpointRole,
|
|
180
|
+
source: { readonly id: NodeId; readonly class: ClassKeyValue },
|
|
183
181
|
): void {
|
|
184
|
-
const
|
|
185
|
-
const matches =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
182
|
+
const exact = binding.domain.definition(ClassKey.ref(ClassKey(source.class)))
|
|
183
|
+
const matches =
|
|
184
|
+
exact?.ref.kind === 'class' &&
|
|
185
|
+
exact.kind === 'node' &&
|
|
186
|
+
edgeEndpoints(relation)[from].accepts.some((ref) => {
|
|
187
|
+
const accepted = binding.domain.definition(ref)
|
|
188
|
+
return accepted?.ref.kind === 'class' && accepted.kind === 'node' && exact.satisfies(accepted)
|
|
189
|
+
})
|
|
189
190
|
if (!matches) throw new TypeError('Relation source does not satisfy the selected endpoint.')
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
function
|
|
193
|
-
const endpoint = edgeEndpoints(definition)[side]
|
|
194
|
-
const cardinality = side === 'source' ? endpoint.outgoing : endpoint.incoming
|
|
195
|
-
if (cardinality === undefined) {
|
|
196
|
-
throw new TypeError(`Relation ${side} endpoint does not expose its traversal cardinality.`)
|
|
197
|
-
}
|
|
198
|
-
return cardinality
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function effectiveCardinality<
|
|
202
|
-
Relation extends EdgeDefinition,
|
|
203
|
-
Role extends EndpointRole,
|
|
204
|
-
To extends RelatedDefinition<Relation, Role>,
|
|
205
|
-
>(
|
|
193
|
+
function admitRelatedDefinition(
|
|
206
194
|
binding: ReturnType<typeof bindingFor>,
|
|
207
|
-
relation:
|
|
208
|
-
from:
|
|
209
|
-
to:
|
|
210
|
-
):
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const opposite: EndpointRole = from === 'source' ? 'target' : 'source'
|
|
216
|
-
const coversEndpoint = edgeEndpoints(relation)[opposite].accepts.every((ref) => {
|
|
217
|
-
const candidate = binding.$.inspect(ref) as Definition<'class' | 'interface'>
|
|
218
|
-
return candidate.satisfies(to)
|
|
195
|
+
relation: ResolvedClass<'edge'>,
|
|
196
|
+
from: EndpointRole,
|
|
197
|
+
to: ResolvedClass<'node'>,
|
|
198
|
+
): void {
|
|
199
|
+
const opposite = from === 'source' ? 'target' : 'source'
|
|
200
|
+
const matches = edgeEndpoints(relation)[opposite].accepts.some((ref) => {
|
|
201
|
+
const accepted = binding.domain.definition(ref)
|
|
202
|
+
return accepted?.ref.kind === 'class' && accepted.kind === 'node' && to.satisfies(accepted)
|
|
219
203
|
})
|
|
220
|
-
|
|
221
|
-
Relation
|
|
222
|
-
|
|
223
|
-
To
|
|
224
|
-
>
|
|
204
|
+
if (!matches) {
|
|
205
|
+
throw new TypeError('Relation target Class is not admitted by the opposite endpoint.')
|
|
206
|
+
}
|
|
225
207
|
}
|
|
226
208
|
|
|
227
|
-
function
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
209
|
+
function effectiveCardinality(
|
|
210
|
+
binding: ReturnType<typeof bindingFor>,
|
|
211
|
+
relation: ResolvedClass<'edge'>,
|
|
212
|
+
from: EndpointRole,
|
|
213
|
+
to: ResolvedClass<'node'>,
|
|
214
|
+
): RelationCardinality {
|
|
215
|
+
const endpoint = edgeEndpoints(relation)[from]
|
|
216
|
+
const base = from === 'source' ? endpoint.outgoing : endpoint.incoming
|
|
217
|
+
if (base === undefined) throw new TypeError(`Relation ${from} cardinality is absent.`)
|
|
218
|
+
if (base !== '1' && base !== '1..*') return base
|
|
219
|
+
const opposite = from === 'source' ? 'target' : 'source'
|
|
220
|
+
const covers = edgeEndpoints(relation)[opposite].accepts.every((ref) => {
|
|
221
|
+
const accepted = binding.domain.definition(ref)
|
|
222
|
+
return accepted?.ref.kind === 'class' && accepted.kind === 'node' && accepted.satisfies(to)
|
|
237
223
|
})
|
|
238
|
-
|
|
239
|
-
throw new TypeError('Relation target definition is not admitted by the opposite endpoint.')
|
|
224
|
+
return covers ? base : base === '1' ? '0..1' : '0..*'
|
|
240
225
|
}
|
|
241
226
|
|
|
242
|
-
function edgeEndpoints(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const target = declaration.endpoints?.target
|
|
249
|
-
if (declaration.family !== 'edge' || source === undefined || target === undefined) {
|
|
250
|
-
throw new TypeError('Relation definition does not expose admitted Edge endpoints.')
|
|
227
|
+
function edgeEndpoints(
|
|
228
|
+
relation: ResolvedClass<'edge'>,
|
|
229
|
+
): Readonly<Record<EndpointRole, RuntimeEndpoint>> {
|
|
230
|
+
const definition = relation.definition
|
|
231
|
+
if (definition.orientation !== 'directed') {
|
|
232
|
+
throw new TypeError('useRelation currently requires a directed Edge Class.')
|
|
251
233
|
}
|
|
252
|
-
return
|
|
234
|
+
return definition.endpoints
|
|
253
235
|
}
|
package/src/selection/live.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Node, NodeId } from '@astrale-os/sdk/graph/node'
|
|
2
2
|
|
|
3
|
-
import { Path } from '@astrale-os/sdk/graph/path'
|
|
4
3
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
5
4
|
|
|
6
5
|
import { useSessionKernel } from '../auth/session-kernel.js'
|
|
@@ -58,7 +57,7 @@ export function useResolvedNodes(orderedIds: readonly NodeId[]): ResolvedSelecti
|
|
|
58
57
|
}
|
|
59
58
|
setState({ key: currentKey, aliveIds: ids, nodes: [], pending: true, error: undefined })
|
|
60
59
|
try {
|
|
61
|
-
const values = await Promise.all(ids.map((nodeId) => graph.get(
|
|
60
|
+
const values = await Promise.all(ids.map((nodeId) => graph.get(nodeId)))
|
|
62
61
|
if (!alive.current || id !== generation.current) return
|
|
63
62
|
const aliveIds: NodeId[] = []
|
|
64
63
|
const nodes: Node[] = []
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphStore } from '@astrale-os/
|
|
1
|
+
import type { GraphStore } from '@astrale-os/sdk/client/store'
|
|
2
2
|
import type { KernelClient, Shell } from '@astrale-os/shell'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -11,9 +11,8 @@ import { createContext } from 'react'
|
|
|
11
11
|
import type { GraphStoreScope } from '../graph/store.js'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* whoami's node type, derived from the auth surface so
|
|
15
|
-
*
|
|
16
|
-
* kernel-client — API §14 G8). Swap for the blessed re-export when it lands.
|
|
14
|
+
* whoami's node type, derived from the SDK auth surface so this package does
|
|
15
|
+
* not duplicate the canonical Client node projection.
|
|
17
16
|
*/
|
|
18
17
|
export type SelfNode = Awaited<ReturnType<KernelClient['auth']['whoami']>>
|
|
19
18
|
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { DomainSearchResult } from '@astrale-os/shell';
|
|
2
|
-
import type { ReadState } from '../../graph/memory/read/envelope.js';
|
|
3
|
-
export interface DomainsResult extends ReadState {
|
|
4
|
-
readonly domains: readonly DomainSearchResult[];
|
|
5
|
-
}
|
|
6
|
-
export declare function useInstalledDomains(): DomainsResult;
|
|
7
|
-
//# sourceMappingURL=domains.hook.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"domains.hook.d.ts","sourceRoot":"","sources":["../../../src/application/apps/domains.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAI3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AAQpE,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAChD;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAoBnD"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { useAsyncResource } from '../../graph/async.js';
|
|
3
|
-
import { useShell } from '../../session/shell.hook.js';
|
|
4
|
-
import { isOsPlaneAvailable } from '../user/user.store.js';
|
|
5
|
-
const NO_DOMAINS = [];
|
|
6
|
-
export function useInstalledDomains() {
|
|
7
|
-
const shell = useShell();
|
|
8
|
-
const available = isOsPlaneAvailable(shell);
|
|
9
|
-
const result = useAsyncResource(available ? () => shell.apps.searchDomains() : null, NO_DOMAINS, [shell, available]);
|
|
10
|
-
return useMemo(() => ({
|
|
11
|
-
domains: result.data,
|
|
12
|
-
pending: result.pending,
|
|
13
|
-
error: result.error,
|
|
14
|
-
live: false,
|
|
15
|
-
seq: 0,
|
|
16
|
-
refetch: result.refetch,
|
|
17
|
-
}), [result]);
|
|
18
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { DomainSearchResult } from '@astrale-os/shell'
|
|
2
|
-
|
|
3
|
-
import { useMemo } from 'react'
|
|
4
|
-
|
|
5
|
-
import type { ReadState } from '../../graph/memory/read/envelope.js'
|
|
6
|
-
|
|
7
|
-
import { useAsyncResource } from '../../graph/async.js'
|
|
8
|
-
import { useShell } from '../../session/shell.hook.js'
|
|
9
|
-
import { isOsPlaneAvailable } from '../user/user.store.js'
|
|
10
|
-
|
|
11
|
-
const NO_DOMAINS: readonly DomainSearchResult[] = []
|
|
12
|
-
|
|
13
|
-
export interface DomainsResult extends ReadState {
|
|
14
|
-
readonly domains: readonly DomainSearchResult[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function useInstalledDomains(): DomainsResult {
|
|
18
|
-
const shell = useShell()
|
|
19
|
-
const available = isOsPlaneAvailable(shell)
|
|
20
|
-
const result = useAsyncResource<readonly DomainSearchResult[]>(
|
|
21
|
-
available ? () => shell.apps.searchDomains() : null,
|
|
22
|
-
NO_DOMAINS,
|
|
23
|
-
[shell, available],
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
return useMemo(
|
|
27
|
-
() => ({
|
|
28
|
-
domains: result.data,
|
|
29
|
-
pending: result.pending,
|
|
30
|
-
error: result.error,
|
|
31
|
-
live: false,
|
|
32
|
-
seq: 0,
|
|
33
|
-
refetch: result.refetch,
|
|
34
|
-
}),
|
|
35
|
-
[result],
|
|
36
|
-
)
|
|
37
|
-
}
|