@astrale-os/shell-react 0.2.8 → 0.2.10-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/application/apps/app-host.d.ts +7 -15
- package/dist/application/apps/app-host.d.ts.map +1 -1
- package/dist/application/apps/app-host.js +3 -2
- package/dist/application/apps/apps.hook.d.ts +7 -4
- package/dist/application/apps/apps.hook.d.ts.map +1 -1
- package/dist/application/apps/apps.hook.js +10 -2
- package/dist/application/apps/domains.hook.d.ts +1 -1
- package/dist/application/apps/domains.hook.d.ts.map +1 -1
- package/dist/application/apps/domains.hook.js +1 -1
- package/dist/application/apps/open-app.hook.d.ts +2 -3
- package/dist/application/apps/open-app.hook.d.ts.map +1 -1
- package/dist/application/index.d.ts +2 -4
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +2 -3
- package/dist/application/spaces/space.hook.d.ts +2 -2
- package/dist/application/spaces/space.hook.d.ts.map +1 -1
- package/dist/application/spaces/space.hook.js +2 -2
- package/dist/application/spaces/spaces.hook.d.ts +2 -3
- package/dist/application/spaces/spaces.hook.d.ts.map +1 -1
- package/dist/application/spaces/spaces.hook.js +10 -3
- package/dist/auth/act-as.context.d.ts +15 -32
- package/dist/auth/act-as.context.d.ts.map +1 -1
- package/dist/auth/act-as.context.js +22 -66
- package/dist/auth/auth.hook.d.ts +1 -0
- package/dist/auth/auth.hook.d.ts.map +1 -1
- package/dist/auth/auth.hook.js +2 -22
- package/dist/auth/can.hook.d.ts +10 -38
- package/dist/auth/can.hook.d.ts.map +1 -1
- package/dist/auth/can.hook.js +35 -110
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/self.hook.d.ts +2 -2
- package/dist/auth/self.hook.d.ts.map +1 -1
- package/dist/auth/self.hook.js +0 -7
- package/dist/auth/session-kernel.d.ts +2 -3
- package/dist/auth/session-kernel.d.ts.map +1 -1
- package/dist/auth/session-kernel.js +4 -13
- package/dist/components/boundaries.d.ts +47 -0
- package/dist/components/boundaries.d.ts.map +1 -0
- package/dist/components/boundaries.js +55 -0
- package/dist/components/can.d.ts +11 -0
- package/dist/components/can.d.ts.map +1 -0
- package/dist/components/can.js +5 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +4 -0
- package/dist/components/mount-domain-frontend.d.ts +22 -0
- package/dist/components/mount-domain-frontend.d.ts.map +1 -0
- package/dist/components/mount-domain-frontend.js +85 -0
- package/dist/components/view-app.d.ts +16 -0
- package/dist/components/view-app.d.ts.map +1 -0
- package/dist/components/view-app.js +16 -0
- package/dist/graph/call/call.hook.d.ts +8 -18
- package/dist/graph/call/call.hook.d.ts.map +1 -1
- package/dist/graph/call/call.hook.js +7 -13
- package/dist/graph/call/stream.hook.d.ts +12 -20
- package/dist/graph/call/stream.hook.d.ts.map +1 -1
- package/dist/graph/call/stream.hook.js +55 -111
- package/dist/graph/graph.context.d.ts +4 -3
- package/dist/graph/graph.context.d.ts.map +1 -1
- package/dist/graph/graph.context.js +2 -8
- package/dist/graph/guards.error.d.ts +7 -8
- package/dist/graph/guards.error.d.ts.map +1 -1
- package/dist/graph/guards.error.js +11 -7
- package/dist/graph/index.d.ts +8 -16
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +3 -7
- package/dist/graph/memory/read/envelope.d.ts +22 -54
- package/dist/graph/memory/read/envelope.d.ts.map +1 -1
- package/dist/graph/memory/read/envelope.js +26 -20
- package/dist/graph/memory/read/idle.d.ts +1 -15
- package/dist/graph/memory/read/idle.d.ts.map +1 -1
- package/dist/graph/memory/read/idle.js +4 -13
- package/dist/graph/query-definition.hook.d.ts +11 -0
- package/dist/graph/query-definition.hook.d.ts.map +1 -0
- package/dist/graph/query-definition.hook.js +205 -0
- package/dist/graph/resource.d.ts +34 -0
- package/dist/graph/resource.d.ts.map +1 -0
- package/dist/graph/resource.js +244 -0
- package/dist/graph/store.d.ts +25 -0
- package/dist/graph/store.d.ts.map +1 -0
- package/dist/graph/store.js +69 -0
- package/dist/host/actions.hook.d.ts +34 -0
- package/dist/host/actions.hook.d.ts.map +1 -0
- package/dist/host/actions.hook.js +125 -0
- package/dist/host/components.d.ts +15 -0
- package/dist/host/components.d.ts.map +1 -0
- package/dist/host/components.js +14 -0
- package/dist/host/index.d.ts +5 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +3 -0
- package/dist/index.d.ts +26 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -31
- package/dist/intents/envelope.d.ts +7 -19
- package/dist/intents/envelope.d.ts.map +1 -1
- package/dist/intents/envelope.js +2 -3
- package/dist/intents/send-intent.hook.d.ts +5 -7
- package/dist/intents/send-intent.hook.d.ts.map +1 -1
- package/dist/intents/send-intent.hook.js +17 -75
- package/dist/navigation/adapters/adapter.d.ts +5 -0
- package/dist/navigation/adapters/adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/memory.adapter.js +4 -0
- package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/url.adapter.js +57 -10
- package/dist/navigation/codec.d.ts +60 -0
- package/dist/navigation/codec.d.ts.map +1 -0
- package/dist/navigation/codec.js +121 -0
- package/dist/navigation/history.d.ts +11 -9
- package/dist/navigation/history.d.ts.map +1 -1
- package/dist/navigation/history.js +6 -8
- package/dist/navigation/hooks/ancestors.hook.d.ts +5 -7
- package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -1
- package/dist/navigation/hooks/ancestors.hook.js +7 -51
- package/dist/navigation/hooks/location.hook.d.ts.map +1 -1
- package/dist/navigation/hooks/location.hook.js +4 -6
- package/dist/navigation/hooks/scope.hook.d.ts.map +1 -1
- package/dist/navigation/hooks/scope.hook.js +4 -6
- package/dist/navigation/index.d.ts +4 -2
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +2 -1
- package/dist/navigation/link.d.ts +12 -0
- package/dist/navigation/link.d.ts.map +1 -1
- package/dist/navigation/link.js +13 -2
- package/dist/navigation/location.d.ts +13 -40
- package/dist/navigation/location.d.ts.map +1 -1
- package/dist/navigation/location.js +14 -76
- package/dist/navigation/scope.context.d.ts +17 -26
- package/dist/navigation/scope.context.d.ts.map +1 -1
- package/dist/navigation/scope.context.js +140 -108
- package/dist/navigation/snapshot.d.ts +14 -19
- package/dist/navigation/snapshot.d.ts.map +1 -1
- package/dist/navigation/snapshot.js +48 -44
- package/dist/schema/action.hook.d.ts +44 -0
- package/dist/schema/action.hook.d.ts.map +1 -0
- package/dist/schema/action.hook.js +72 -0
- package/dist/schema/domain.hook.d.ts +12 -7
- package/dist/schema/domain.hook.d.ts.map +1 -1
- package/dist/schema/domain.hook.js +101 -4
- package/dist/schema/index.d.ts +9 -8
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +5 -7
- package/dist/schema/kernel.hook.d.ts +4 -9
- package/dist/schema/kernel.hook.d.ts.map +1 -1
- package/dist/schema/kernel.hook.js +4 -6
- package/dist/schema/mutation.hook.d.ts +9 -0
- package/dist/schema/mutation.hook.d.ts.map +1 -0
- package/dist/schema/mutation.hook.js +41 -0
- package/dist/schema/object.hook.d.ts +16 -0
- package/dist/schema/object.hook.d.ts.map +1 -0
- package/dist/schema/object.hook.js +46 -0
- package/dist/schema/relation.hook.d.ts +46 -0
- package/dist/schema/relation.hook.d.ts.map +1 -0
- package/dist/schema/relation.hook.js +136 -0
- package/dist/selection/live.d.ts +9 -17
- package/dist/selection/live.d.ts.map +1 -1
- package/dist/selection/live.js +65 -112
- package/dist/selection/scope.context.js +5 -4
- package/dist/session/boot/boot.d.ts +1 -13
- package/dist/session/boot/boot.d.ts.map +1 -1
- package/dist/session/boot/boot.js +9 -27
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/kernel-instance.hook.d.ts +1 -4
- package/dist/session/kernel-instance.hook.d.ts.map +1 -1
- package/dist/session/kernel-instance.hook.js +1 -5
- package/dist/session/provider.d.ts +9 -23
- package/dist/session/provider.d.ts.map +1 -1
- package/dist/session/provider.js +29 -75
- package/dist/session/session.context.d.ts +5 -0
- package/dist/session/session.context.d.ts.map +1 -1
- package/dist/window/adopt.d.ts +0 -1
- package/dist/window/adopt.d.ts.map +1 -1
- package/dist/window/hooks/target-node.hook.d.ts +10 -6
- package/dist/window/hooks/target-node.hook.d.ts.map +1 -1
- package/dist/window/hooks/target-node.hook.js +14 -72
- package/dist/window/hooks/views-for.hook.d.ts +4 -3
- package/dist/window/hooks/views-for.hook.d.ts.map +1 -1
- package/dist/window/hooks/views-for.hook.js +6 -22
- package/dist/window/hooks/windows.hook.d.ts.map +1 -1
- package/dist/window/hooks/windows.hook.js +3 -4
- package/dist/window/host.d.ts +11 -11
- package/dist/window/host.d.ts.map +1 -1
- package/dist/window/host.js +38 -54
- package/dist/window/hub.d.ts +2 -0
- package/dist/window/hub.d.ts.map +1 -1
- package/dist/window/hub.js +33 -0
- package/dist/window/index.d.ts +3 -3
- package/dist/window/index.d.ts.map +1 -1
- package/dist/window/index.js +2 -2
- package/dist/window/lifecycle/mount.d.ts +5 -44
- package/dist/window/lifecycle/mount.d.ts.map +1 -1
- package/dist/window/lifecycle/mount.js +14 -120
- package/dist/window/lifecycle/states.d.ts +0 -5
- package/dist/window/lifecycle/states.d.ts.map +1 -1
- package/dist/window/stage.d.ts.map +1 -1
- package/dist/window/stage.js +1 -0
- package/package.json +9 -8
- package/src/application/apps/app-host.tsx +17 -18
- package/src/application/apps/apps.hook.ts +13 -6
- package/src/application/apps/domains.hook.ts +1 -1
- package/src/application/apps/open-app.hook.ts +3 -4
- package/src/application/index.ts +4 -6
- package/src/application/spaces/space.hook.ts +5 -6
- package/src/application/spaces/spaces.hook.ts +14 -9
- package/src/auth/act-as.context.tsx +37 -91
- package/src/auth/auth.hook.ts +2 -30
- package/src/auth/can.hook.ts +44 -135
- package/src/auth/index.ts +1 -0
- package/src/auth/self.hook.ts +2 -9
- package/src/auth/session-kernel.ts +6 -16
- package/src/components/boundaries.tsx +113 -0
- package/src/components/can.tsx +16 -0
- package/src/components/index.ts +14 -0
- package/src/components/mount-domain-frontend.tsx +158 -0
- package/src/components/view-app.tsx +49 -0
- package/src/graph/call/call.hook.ts +22 -27
- package/src/graph/call/stream.hook.ts +66 -143
- package/src/graph/graph.context.ts +6 -11
- package/src/graph/guards.error.ts +17 -55
- package/src/graph/index.ts +23 -17
- package/src/graph/memory/read/envelope.ts +40 -65
- package/src/graph/memory/read/idle.ts +5 -18
- package/src/graph/query-definition.hook.ts +270 -0
- package/src/graph/resource.ts +358 -0
- package/src/graph/store.ts +97 -0
- package/src/host/actions.hook.ts +165 -0
- package/src/host/components.tsx +29 -0
- package/src/host/index.ts +17 -0
- package/src/index.ts +137 -123
- package/src/intents/envelope.ts +7 -23
- package/src/intents/send-intent.hook.ts +24 -79
- package/src/navigation/adapters/adapter.ts +3 -0
- package/src/navigation/adapters/memory.adapter.ts +4 -0
- package/src/navigation/adapters/url.adapter.ts +48 -8
- package/src/navigation/codec.ts +190 -0
- package/src/navigation/history.ts +20 -11
- package/src/navigation/hooks/ancestors.hook.ts +10 -60
- package/src/navigation/hooks/location.hook.ts +4 -6
- package/src/navigation/hooks/scope.hook.ts +4 -6
- package/src/navigation/index.ts +18 -2
- package/src/navigation/link.tsx +27 -2
- package/src/navigation/location.ts +26 -93
- package/src/navigation/scope.context.tsx +151 -136
- package/src/navigation/snapshot.ts +69 -50
- package/src/schema/action.hook.ts +146 -0
- package/src/schema/domain.hook.ts +127 -11
- package/src/schema/index.ts +9 -30
- package/src/schema/kernel.hook.ts +6 -13
- package/src/schema/mutation.hook.ts +63 -0
- package/src/schema/object.hook.ts +85 -0
- package/src/schema/relation.hook.ts +253 -0
- package/src/selection/live.ts +75 -125
- package/src/selection/scope.context.tsx +4 -4
- package/src/session/boot/boot.ts +8 -33
- package/src/session/index.ts +1 -0
- package/src/session/kernel-instance.hook.ts +2 -11
- package/src/session/provider.tsx +34 -103
- package/src/session/session.context.ts +6 -0
- package/src/window/adopt.ts +0 -1
- package/src/window/hooks/target-node.hook.ts +20 -85
- package/src/window/hooks/views-for.hook.ts +12 -25
- package/src/window/hooks/windows.hook.ts +3 -4
- package/src/window/host.tsx +51 -68
- package/src/window/hub.ts +33 -0
- package/src/window/index.ts +4 -4
- package/src/window/lifecycle/mount.ts +15 -160
- package/src/window/lifecycle/states.ts +1 -5
- package/src/window/stage.tsx +1 -0
- package/dist/application/roles.hook.d.ts +0 -7
- package/dist/application/roles.hook.d.ts.map +0 -1
- package/dist/application/roles.hook.js +0 -23
- package/dist/graph/memory/base.d.ts +0 -21
- package/dist/graph/memory/base.d.ts.map +0 -1
- package/dist/graph/memory/base.js +0 -33
- package/dist/graph/memory/read/read.d.ts +0 -9
- package/dist/graph/memory/read/read.d.ts.map +0 -1
- package/dist/graph/memory/read/read.js +0 -87
- package/dist/graph/memory/scope.d.ts +0 -7
- package/dist/graph/memory/scope.d.ts.map +0 -1
- package/dist/graph/memory/scope.js +0 -25
- package/dist/graph/mutate/move.hook.d.ts +0 -7
- package/dist/graph/mutate/move.hook.d.ts.map +0 -1
- package/dist/graph/mutate/move.hook.js +0 -49
- package/dist/graph/mutate/mutate.hook.d.ts +0 -17
- package/dist/graph/mutate/mutate.hook.d.ts.map +0 -1
- package/dist/graph/mutate/mutate.hook.js +0 -45
- package/dist/graph/query/children.hook.d.ts +0 -29
- package/dist/graph/query/children.hook.d.ts.map +0 -1
- package/dist/graph/query/children.hook.js +0 -64
- package/dist/graph/query/graph.hook.d.ts +0 -9
- package/dist/graph/query/graph.hook.d.ts.map +0 -1
- package/dist/graph/query/graph.hook.js +0 -5
- package/dist/graph/query/neighbors.hook.d.ts +0 -7
- package/dist/graph/query/neighbors.hook.d.ts.map +0 -1
- package/dist/graph/query/neighbors.hook.js +0 -104
- package/dist/graph/query/node.hook.d.ts +0 -14
- package/dist/graph/query/node.hook.d.ts.map +0 -1
- package/dist/graph/query/node.hook.js +0 -43
- package/dist/graph/query/query.hook.d.ts +0 -14
- package/dist/graph/query/query.hook.d.ts.map +0 -1
- package/dist/graph/query/query.hook.js +0 -23
- package/dist/schema/bind-read.d.ts +0 -37
- package/dist/schema/bind-read.d.ts.map +0 -1
- package/dist/schema/bind-read.js +0 -205
- package/dist/schema/binding.d.ts +0 -21
- package/dist/schema/binding.d.ts.map +0 -1
- package/dist/schema/binding.js +0 -99
- package/dist/schema/function.hook.d.ts +0 -9
- package/dist/schema/function.hook.d.ts.map +0 -1
- package/dist/schema/function.hook.js +0 -40
- package/dist/schema/method.hook.d.ts +0 -14
- package/dist/schema/method.hook.d.ts.map +0 -1
- package/dist/schema/method.hook.js +0 -49
- package/dist/schema/tag.d.ts +0 -11
- package/dist/schema/tag.d.ts.map +0 -1
- package/dist/schema/tag.js +0 -11
- package/dist/schema/types.d.ts +0 -73
- package/dist/schema/types.d.ts.map +0 -1
- package/dist/schema/types.js +0 -1
- package/dist/schema/write.d.ts +0 -16
- package/dist/schema/write.d.ts.map +0 -1
- package/dist/schema/write.js +0 -56
- package/src/application/roles.hook.ts +0 -41
- package/src/graph/memory/base.ts +0 -50
- package/src/graph/memory/read/read.ts +0 -103
- package/src/graph/memory/scope.ts +0 -29
- package/src/graph/mutate/move.hook.ts +0 -70
- package/src/graph/mutate/mutate.hook.ts +0 -69
- package/src/graph/query/children.hook.ts +0 -136
- package/src/graph/query/graph.hook.ts +0 -13
- package/src/graph/query/neighbors.hook.ts +0 -159
- package/src/graph/query/node.hook.ts +0 -83
- package/src/graph/query/query.hook.ts +0 -42
- package/src/schema/bind-read.ts +0 -319
- package/src/schema/binding.ts +0 -146
- package/src/schema/function.hook.ts +0 -68
- package/src/schema/method.hook.ts +0 -103
- package/src/schema/tag.ts +0 -19
- package/src/schema/types.ts +0 -150
- package/src/schema/write.ts +0 -96
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import type { AnyBoundNode, EdgeNames } from '@astrale-os/kernel-client'
|
|
2
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* useOut / useIn (API §6) — the public typed traversal read hooks. Resolve
|
|
6
|
-
* endpoints one-shot through `BoundNode.links.out/in` (`live: false`); become live with
|
|
7
|
-
* no surface change once edge-endpoint ids land. Deviations tracked in API §6/G6.
|
|
8
|
-
*/
|
|
9
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
10
|
-
|
|
11
|
-
import type { EndpointResult } from '../../schema/types.js'
|
|
12
|
-
import type { ReadState, ReadOptions } from '../memory/read/envelope.js'
|
|
13
|
-
|
|
14
|
-
import { schemaOf, tagSchema } from '../../schema/tag.js'
|
|
15
|
-
import { isIdleInput } from '../memory/read/idle.js'
|
|
16
|
-
|
|
17
|
-
export function useOut<S extends Schema, E extends EdgeNames<S>>(
|
|
18
|
-
node: AnyBoundNode<S> | null | undefined,
|
|
19
|
-
edge: E,
|
|
20
|
-
opts?: ReadOptions,
|
|
21
|
-
): EndpointResult<S, E, 'to'> {
|
|
22
|
-
return useEndpoint(node, edge, 'out', opts) as unknown as EndpointResult<S, E, 'to'>
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function useIn<S extends Schema, E extends EdgeNames<S>>(
|
|
26
|
-
node: AnyBoundNode<S> | null | undefined,
|
|
27
|
-
edge: E,
|
|
28
|
-
opts?: ReadOptions,
|
|
29
|
-
): EndpointResult<S, E, 'from'> {
|
|
30
|
-
return useEndpoint(node, edge, 'in', opts) as unknown as EndpointResult<S, E, 'from'>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
type EndpointEnvelope<S extends Schema> = ReadState & {
|
|
34
|
-
readonly node?: AnyBoundNode<S> | null
|
|
35
|
-
readonly nodes?: readonly AnyBoundNode<S>[]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function useEndpoint<S extends Schema>(
|
|
39
|
-
node: AnyBoundNode<S> | null | undefined,
|
|
40
|
-
edge: EdgeNames<S>,
|
|
41
|
-
side: 'out' | 'in',
|
|
42
|
-
opts?: ReadOptions,
|
|
43
|
-
): EndpointEnvelope<S> {
|
|
44
|
-
const schema = isIdleInput(node) ? undefined : schemaOf(node)
|
|
45
|
-
const single = schema !== undefined && isSingleEndpoint(schema, edge, side)
|
|
46
|
-
const key = `${node?.id ?? ''}\u0000${edge}\u0000${side}`
|
|
47
|
-
const run = useCallback(async (): Promise<unknown> => {
|
|
48
|
-
if (isIdleInput(node)) return null
|
|
49
|
-
const result = await (side === 'out' ? node.links.out(edge) : node.links.in(edge))
|
|
50
|
-
if (schema !== undefined) tagEndpoints(result, schema)
|
|
51
|
-
return result
|
|
52
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
-
}, [node?.id, edge, side])
|
|
54
|
-
|
|
55
|
-
const { data, pending, error, refetch } = useAsyncRead(
|
|
56
|
-
isIdleInput(node) ? null : run,
|
|
57
|
-
key,
|
|
58
|
-
opts?.keepPrevious === true,
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
return useMemo<EndpointEnvelope<S>>(() => {
|
|
62
|
-
const live: ReadState = { pending, error, live: false, seq: 0, refetch }
|
|
63
|
-
if (isIdleInput(node)) return { ...live, node: null, nodes: EMPTY }
|
|
64
|
-
if (single) {
|
|
65
|
-
const value = Array.isArray(data) ? data[0] : data
|
|
66
|
-
return { ...live, node: (value ?? null) as AnyBoundNode<S> | null }
|
|
67
|
-
}
|
|
68
|
-
const values = Array.isArray(data) ? data : data === null || data === undefined ? EMPTY : [data]
|
|
69
|
-
return { ...live, nodes: values as readonly AnyBoundNode<S>[] }
|
|
70
|
-
}, [node, data, pending, error, refetch, single])
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
const EMPTY: readonly never[] = Object.freeze([])
|
|
76
|
-
|
|
77
|
-
function isSingleEndpoint(schema: Schema, edge: string, side: 'out' | 'in'): boolean {
|
|
78
|
-
const definition = schema.classes[edge] as
|
|
79
|
-
| {
|
|
80
|
-
readonly from?: { readonly cardinality?: string }
|
|
81
|
-
readonly to?: { readonly cardinality?: string }
|
|
82
|
-
}
|
|
83
|
-
| undefined
|
|
84
|
-
const cardinality = (side === 'out' ? definition?.to : definition?.from)?.cardinality
|
|
85
|
-
return cardinality === '1' || cardinality === '0..1'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function tagEndpoints(result: unknown, schema: Schema): void {
|
|
89
|
-
if (Array.isArray(result)) for (const r of result) tagSchema(r, schema)
|
|
90
|
-
else if (result !== null && result !== undefined) tagSchema(result, schema)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
interface AsyncState<T> {
|
|
94
|
-
data?: T
|
|
95
|
-
pending: boolean
|
|
96
|
-
error: unknown
|
|
97
|
-
key: string | null
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** One-shot async read with pending/error/refetch and stale-response guarding. */
|
|
101
|
-
function useAsyncRead<T>(
|
|
102
|
-
run: (() => Promise<T>) | null,
|
|
103
|
-
key: string,
|
|
104
|
-
keepPrevious: boolean,
|
|
105
|
-
): AsyncState<T> & { refetch(): Promise<void> } {
|
|
106
|
-
const [state, setState] = useState<AsyncState<T>>({
|
|
107
|
-
pending: run !== null,
|
|
108
|
-
error: undefined,
|
|
109
|
-
key: run === null ? null : key,
|
|
110
|
-
})
|
|
111
|
-
const runRef = useRef(run)
|
|
112
|
-
runRef.current = run
|
|
113
|
-
const keyRef = useRef(key)
|
|
114
|
-
keyRef.current = key
|
|
115
|
-
const keepPreviousRef = useRef(keepPrevious)
|
|
116
|
-
keepPreviousRef.current = keepPrevious
|
|
117
|
-
const seq = useRef(0)
|
|
118
|
-
|
|
119
|
-
const refetch = useCallback((): Promise<void> => {
|
|
120
|
-
const current = runRef.current
|
|
121
|
-
const currentKey = keyRef.current
|
|
122
|
-
if (current === null) {
|
|
123
|
-
setState({ pending: false, error: undefined, data: undefined, key: null })
|
|
124
|
-
return Promise.resolve()
|
|
125
|
-
}
|
|
126
|
-
const my = ++seq.current
|
|
127
|
-
setState((s) => ({
|
|
128
|
-
data: s.key === currentKey || keepPreviousRef.current === true ? s.data : undefined,
|
|
129
|
-
pending: true,
|
|
130
|
-
error: undefined,
|
|
131
|
-
key: currentKey,
|
|
132
|
-
}))
|
|
133
|
-
return current().then(
|
|
134
|
-
(data) => {
|
|
135
|
-
if (my === seq.current) {
|
|
136
|
-
setState({ data, pending: false, error: undefined, key: currentKey })
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
(error: unknown) => {
|
|
140
|
-
if (my === seq.current) {
|
|
141
|
-
setState((s) => ({ data: s.data, pending: false, error, key: currentKey }))
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
)
|
|
145
|
-
}, [])
|
|
146
|
-
|
|
147
|
-
useEffect(() => {
|
|
148
|
-
void refetch()
|
|
149
|
-
}, [key, refetch])
|
|
150
|
-
|
|
151
|
-
const current = state.key === key
|
|
152
|
-
return {
|
|
153
|
-
data: current || keepPrevious ? state.data : undefined,
|
|
154
|
-
pending: run !== null && (!current || state.pending),
|
|
155
|
-
error: current ? state.error : undefined,
|
|
156
|
-
key: current ? state.key : null,
|
|
157
|
-
refetch,
|
|
158
|
-
}
|
|
159
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { NodeRefInput, TypeNames } from '@astrale-os/kernel-client'
|
|
2
|
-
import type { PathLike } from '@astrale-os/kernel-client/graph'
|
|
3
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* useNode (API §5 + §6) — ONE public symbol, overloaded: pass a `Schema` (+ type)
|
|
7
|
-
* for the typed `BoundNode` result, or a bare ref for the untyped `Node` result.
|
|
8
|
-
* Both forms ride the SAME memory shape — a typed read and its untyped twin are
|
|
9
|
-
* one cache entry, one liveness, one overlay. The runtime dispatches on the first
|
|
10
|
-
* argument; a given call site is always one form, so hook order is stable.
|
|
11
|
-
*/
|
|
12
|
-
import { useMemo } from 'react'
|
|
13
|
-
|
|
14
|
-
import type { TypedNodeResult } from '../../schema/types.js'
|
|
15
|
-
import type { ReadState, Node, ReadOptions } from '../memory/read/envelope.js'
|
|
16
|
-
|
|
17
|
-
import { useNode as useNodeTyped } from '../../schema/bind-read.js'
|
|
18
|
-
import { useRead } from '../memory/read/read.js'
|
|
19
|
-
|
|
20
|
-
export interface NodeResult extends ReadState {
|
|
21
|
-
/** The node, or `null` when missing ≡ masked (never throws NOT_FOUND). */
|
|
22
|
-
readonly node: Node | null
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* A `Schema` (from `defineSchema`) — its shape (`domain`/`classes`/`interfaces`)
|
|
27
|
-
* is disjoint from a `PathLike` (`string | Path`), so this cleanly routes the
|
|
28
|
-
* typed vs untyped overload at runtime.
|
|
29
|
-
*/
|
|
30
|
-
function isSchema(value: unknown): value is Schema {
|
|
31
|
-
return (
|
|
32
|
-
typeof value === 'object' &&
|
|
33
|
-
value !== null &&
|
|
34
|
-
'domain' in value &&
|
|
35
|
-
'classes' in value &&
|
|
36
|
-
'interfaces' in value
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** One node by path — live, suspense-first; `null` ref is idle (§1.3). */
|
|
41
|
-
function useNodeUntyped(ref: PathLike | null | undefined, opts?: ReadOptions): NodeResult {
|
|
42
|
-
const r = useRead(ref, opts)
|
|
43
|
-
return useMemo(
|
|
44
|
-
() => ({
|
|
45
|
-
pending: r.pending,
|
|
46
|
-
error: r.error,
|
|
47
|
-
live: r.live,
|
|
48
|
-
seq: r.seq,
|
|
49
|
-
refetch: r.refetch,
|
|
50
|
-
node: r.first,
|
|
51
|
-
}),
|
|
52
|
-
[r],
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Typed: one node bound under `schema` as `type`. */
|
|
57
|
-
export function useNode<S extends Schema, T extends TypeNames<S>>(
|
|
58
|
-
schema: S,
|
|
59
|
-
type: T,
|
|
60
|
-
ref: NodeRefInput | null | undefined,
|
|
61
|
-
opts?: ReadOptions,
|
|
62
|
-
): TypedNodeResult<S, T>
|
|
63
|
-
/** Untyped: one node by ref — `null` ref is idle (§1.3). */
|
|
64
|
-
export function useNode(ref: PathLike | null | undefined, opts?: ReadOptions): NodeResult
|
|
65
|
-
// The implementation signature returns an erased supertype of both result
|
|
66
|
-
// shapes — every overload above is assignable to it regardless of `BoundNode`
|
|
67
|
-
// variance; callers only ever see the precise overload return types.
|
|
68
|
-
export function useNode(
|
|
69
|
-
a: unknown,
|
|
70
|
-
b?: unknown,
|
|
71
|
-
c?: unknown,
|
|
72
|
-
d?: unknown,
|
|
73
|
-
): ReadState & { readonly node: unknown } {
|
|
74
|
-
if (isSchema(a)) {
|
|
75
|
-
return useNodeTyped(
|
|
76
|
-
a,
|
|
77
|
-
b as string,
|
|
78
|
-
c as NodeRefInput | null | undefined,
|
|
79
|
-
d as ReadOptions | undefined,
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
return useNodeUntyped(a as PathLike | null | undefined, b as ReadOptions | undefined)
|
|
83
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { GatherBuilder, QueryASTInput, QuerySource } from '@astrale-os/kernel-client/graph'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* useQuery (API §5) — a structured read: a builder callback or an AST value;
|
|
5
|
-
* `null` is idle (§1.3). Rides the §1 envelope over the shared memory, projecting
|
|
6
|
-
* roots/first/nodes and the gathered-alias arms.
|
|
7
|
-
*/
|
|
8
|
-
import { useMemo } from 'react'
|
|
9
|
-
|
|
10
|
-
import type { ReadState, Node, ReadOptions, Windowed } from '../memory/read/envelope.js'
|
|
11
|
-
|
|
12
|
-
import { useRead } from '../memory/read/read.js'
|
|
13
|
-
|
|
14
|
-
export interface QueryResult extends ReadState, Windowed {
|
|
15
|
-
readonly nodes: readonly Node[]
|
|
16
|
-
readonly roots: readonly Node[]
|
|
17
|
-
readonly first: Node | null
|
|
18
|
-
gathered(alias: string): { readonly nodes: readonly Node[]; readonly first: Node | null }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** A structured read — builder callback or AST value; `null` is idle (§1.3). */
|
|
22
|
-
export function useQuery(
|
|
23
|
-
build: ((q: QuerySource) => GatherBuilder) | QueryASTInput | null | undefined,
|
|
24
|
-
opts?: ReadOptions,
|
|
25
|
-
): QueryResult {
|
|
26
|
-
const r = useRead(build ?? null, opts)
|
|
27
|
-
return useMemo(
|
|
28
|
-
() => ({
|
|
29
|
-
pending: r.pending,
|
|
30
|
-
error: r.error,
|
|
31
|
-
live: r.live,
|
|
32
|
-
seq: r.seq,
|
|
33
|
-
refetch: r.refetch,
|
|
34
|
-
nodes: r.nodes,
|
|
35
|
-
roots: r.roots,
|
|
36
|
-
first: r.first,
|
|
37
|
-
gathered: r.gathered,
|
|
38
|
-
more: r.more,
|
|
39
|
-
}),
|
|
40
|
-
[r],
|
|
41
|
-
)
|
|
42
|
-
}
|
package/src/schema/bind-read.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import type { GatherBuilder, OrderInput, QuerySource } from '@astrale-os/kernel-client/graph'
|
|
2
|
-
import type {
|
|
3
|
-
LiveResult,
|
|
4
|
-
ReadOptions as StoreReadOptions,
|
|
5
|
-
ShapeInput,
|
|
6
|
-
} from '@astrale-os/kernel-client/store'
|
|
7
|
-
import type { Node } from '@astrale-os/kernel-core'
|
|
8
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
BindTypeMismatchError,
|
|
12
|
-
normalizeRef,
|
|
13
|
-
type AnyBoundNode,
|
|
14
|
-
type BoundNode,
|
|
15
|
-
type DefOf,
|
|
16
|
-
type NodeRefInput,
|
|
17
|
-
type SchemaBoundView,
|
|
18
|
-
type TypeNames,
|
|
19
|
-
} from '@astrale-os/kernel-client'
|
|
20
|
-
import { shapeInputToAST, stableStringify, stripCursors } from '@astrale-os/kernel-client/store'
|
|
21
|
-
import { compileDomain } from '@astrale-os/kernel-core/domain'
|
|
22
|
-
/**
|
|
23
|
-
* Binder-over-memory composition (API §6, §1.7) — consumed by the `graph/query/`
|
|
24
|
-
* overloads. Binds wire `Node`s from the shared memory to stable `BoundNode`s
|
|
25
|
-
* (an unchanged wire node re-binds to the SAME instance), and composes those
|
|
26
|
-
* binders with a `useSyncExternalStore` read substrate (`useShape`) into the typed
|
|
27
|
-
* `useNode`/`useChildren` reads. A typed read and its untyped twin ride the SAME
|
|
28
|
-
* memory shape, so they are one cache entry, one liveness, one overlay.
|
|
29
|
-
*/
|
|
30
|
-
import { useCallback, useMemo, useRef, useSyncExternalStore } from 'react'
|
|
31
|
-
|
|
32
|
-
import type { ReadState, ReadOptions } from '../graph/memory/read/envelope.js'
|
|
33
|
-
import type { TypedChildrenResult, TypedNodeResult } from './types.js'
|
|
34
|
-
|
|
35
|
-
import { useSessionKernel } from '../auth/session-kernel.js'
|
|
36
|
-
import { idleReadState, isIdleInput } from '../graph/memory/read/idle.js'
|
|
37
|
-
import { useMemory } from '../graph/memory/scope.js'
|
|
38
|
-
import { bindingFor } from './binding.js'
|
|
39
|
-
import { schemaOf, tagSchema } from './tag.js'
|
|
40
|
-
|
|
41
|
-
// ── binder hooks ────────────────────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
interface OneCache<S extends Schema> {
|
|
44
|
-
wire: Node | null
|
|
45
|
-
binding: SchemaBoundView<S>
|
|
46
|
-
type: string
|
|
47
|
-
bound: BoundNode<unknown, S> | null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Bind one wire node as `type`; stable while the wire node, binding, and type hold. */
|
|
51
|
-
export function useBoundNode<S extends Schema, T extends TypeNames<S>>(
|
|
52
|
-
binding: SchemaBoundView<S>,
|
|
53
|
-
type: T,
|
|
54
|
-
wire: Node | null | undefined,
|
|
55
|
-
): BoundNode<DefOf<S, T>, S> | null {
|
|
56
|
-
const ref = useRef<OneCache<S> | null>(null)
|
|
57
|
-
const node = wire ?? null
|
|
58
|
-
let entry = ref.current
|
|
59
|
-
if (entry === null || entry.wire !== node || entry.binding !== binding || entry.type !== type) {
|
|
60
|
-
entry = {
|
|
61
|
-
wire: node,
|
|
62
|
-
binding,
|
|
63
|
-
type,
|
|
64
|
-
bound: node === null ? null : (binding.bind(type, node) as BoundNode<unknown, S>),
|
|
65
|
-
}
|
|
66
|
-
ref.current = entry
|
|
67
|
-
}
|
|
68
|
-
return entry.bound as BoundNode<DefOf<S, T>, S> | null
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
interface ManyCache<S extends Schema> {
|
|
72
|
-
binding: SchemaBoundView<S>
|
|
73
|
-
type: string
|
|
74
|
-
perNode: WeakMap<Node, BoundNode<unknown, S>>
|
|
75
|
-
last: readonly BoundNode<unknown, S>[]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Bind many wire nodes as `type`; per-node identity + a stable array on no
|
|
80
|
-
* change. `skipMismatch` drops nodes whose class is not `type` (a mixed-class
|
|
81
|
-
* child set) instead of throwing.
|
|
82
|
-
*/
|
|
83
|
-
export function useBoundNodes<S extends Schema, T extends TypeNames<S>>(
|
|
84
|
-
binding: SchemaBoundView<S>,
|
|
85
|
-
type: T,
|
|
86
|
-
wires: readonly Node[],
|
|
87
|
-
skipMismatch = false,
|
|
88
|
-
): readonly BoundNode<DefOf<S, T>, S>[] {
|
|
89
|
-
const ref = useRef<ManyCache<S> | null>(null)
|
|
90
|
-
if (ref.current === null || ref.current.binding !== binding || ref.current.type !== type) {
|
|
91
|
-
ref.current = { binding, type, perNode: new WeakMap(), last: [] }
|
|
92
|
-
}
|
|
93
|
-
const cache = ref.current
|
|
94
|
-
const next: BoundNode<unknown, S>[] = []
|
|
95
|
-
for (const w of wires) {
|
|
96
|
-
let b = cache.perNode.get(w)
|
|
97
|
-
if (b === undefined) {
|
|
98
|
-
try {
|
|
99
|
-
b = binding.bind(type, w) as BoundNode<unknown, S>
|
|
100
|
-
} catch (error) {
|
|
101
|
-
if (skipMismatch && error instanceof BindTypeMismatchError) continue
|
|
102
|
-
throw error
|
|
103
|
-
}
|
|
104
|
-
cache.perNode.set(w, b)
|
|
105
|
-
}
|
|
106
|
-
next.push(b)
|
|
107
|
-
}
|
|
108
|
-
if (sameArray(cache.last, next)) return cache.last as readonly BoundNode<DefOf<S, T>, S>[]
|
|
109
|
-
cache.last = next
|
|
110
|
-
return next as readonly BoundNode<DefOf<S, T>, S>[]
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
interface EndpointCache<S extends Schema> {
|
|
114
|
-
binding: SchemaBoundView<S>
|
|
115
|
-
perNode: WeakMap<Node, AnyBoundNode<S>>
|
|
116
|
-
last: readonly AnyBoundNode<S>[]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Bind many wire nodes classlessly (traversal endpoints); per-node + stable array. */
|
|
120
|
-
export function useBoundEndpoints<S extends Schema>(
|
|
121
|
-
binding: SchemaBoundView<S>,
|
|
122
|
-
wires: readonly Node[],
|
|
123
|
-
): readonly AnyBoundNode<S>[] {
|
|
124
|
-
const ref = useRef<EndpointCache<S> | null>(null)
|
|
125
|
-
if (ref.current === null || ref.current.binding !== binding) {
|
|
126
|
-
ref.current = { binding, perNode: new WeakMap(), last: [] }
|
|
127
|
-
}
|
|
128
|
-
const cache = ref.current
|
|
129
|
-
const next = wires.map((w) => {
|
|
130
|
-
let b = cache.perNode.get(w)
|
|
131
|
-
if (b === undefined) {
|
|
132
|
-
b = binding.bindAny(w)
|
|
133
|
-
cache.perNode.set(w, b)
|
|
134
|
-
}
|
|
135
|
-
return b
|
|
136
|
-
})
|
|
137
|
-
if (sameArray(cache.last, next)) return cache.last
|
|
138
|
-
cache.last = next
|
|
139
|
-
return next
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function sameArray<A>(a: readonly A[], b: readonly A[]): boolean {
|
|
143
|
-
return a.length === b.length && a.every((x, i) => x === b[i])
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ── read substrate ────────────────────────────────────────────────────────────
|
|
147
|
-
|
|
148
|
-
/** Base read options plus the window growth mode (a `useChildren`-specific extra). */
|
|
149
|
-
export type ShapeOptions = ReadOptions & { window?: 'append' | 'paged' }
|
|
150
|
-
|
|
151
|
-
/** Store-facing options — render-time concerns (`suspend`/`keepPrevious`) stay here. */
|
|
152
|
-
function toStoreOptions(opts?: ShapeOptions): StoreReadOptions | undefined {
|
|
153
|
-
if (opts === undefined) return undefined
|
|
154
|
-
const out: StoreReadOptions = {}
|
|
155
|
-
if (opts.live !== undefined) out.live = opts.live
|
|
156
|
-
if (opts.window !== undefined) out.window = opts.window
|
|
157
|
-
if (opts.with !== undefined) out.with = opts.with as unknown as StoreReadOptions['with']
|
|
158
|
-
return out
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/** A stable string identity for a (shape, options) pair — the subscription key. */
|
|
162
|
-
function keyOf(shape: ShapeInput, opts?: ShapeOptions): string {
|
|
163
|
-
const ast = stripCursors(shapeInputToAST(shape))
|
|
164
|
-
return `${stableStringify(ast)}|${opts?.live === false ? '0' : '1'}|${opts?.window ?? ''}|${opts?.with ?? ''}`
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Subscribe to a memory shape. `null` shape → idle (`null`, no I/O). A cold
|
|
169
|
-
* shape suspends unless `suspend: false`. The returned `LiveResult` is the
|
|
170
|
-
* unified read envelope — callers project `node`/`children`/`nodes`.
|
|
171
|
-
*/
|
|
172
|
-
export function useShape(
|
|
173
|
-
shape: ShapeInput | null | undefined,
|
|
174
|
-
opts?: ShapeOptions,
|
|
175
|
-
): LiveResult | null {
|
|
176
|
-
const memory = useMemory()
|
|
177
|
-
const storeOpts = toStoreOptions(opts)
|
|
178
|
-
const key = isIdleInput(shape) ? null : keyOf(shape, opts)
|
|
179
|
-
|
|
180
|
-
const subscribe = useCallback(
|
|
181
|
-
(onChange: () => void): (() => void) => {
|
|
182
|
-
if (isIdleInput(shape)) return () => {}
|
|
183
|
-
return memory.subscribe(shape, onChange, storeOpts)
|
|
184
|
-
},
|
|
185
|
-
// The shape's canonical identity is `key`; the captured `shape` is equivalent.
|
|
186
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
187
|
-
[memory, key],
|
|
188
|
-
)
|
|
189
|
-
const getSnapshot = useCallback(
|
|
190
|
-
(): LiveResult | null => (isIdleInput(shape) ? null : memory.getSnapshot(shape, storeOpts)),
|
|
191
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
192
|
-
[memory, key],
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
|
|
196
|
-
|
|
197
|
-
if (!isIdleInput(shape) && opts?.suspend !== false && memory.peek(shape, storeOpts) === null) {
|
|
198
|
-
// Cold FAILURE (§1.4): a rejected fetch with no data throws to the boundary;
|
|
199
|
-
// re-throwing the promise would re-arm a fetch each retry (infinite loop).
|
|
200
|
-
if (snapshot !== null && snapshot.error !== undefined) throw snapshot.error
|
|
201
|
-
throw memory.promise(shape, storeOpts)
|
|
202
|
-
}
|
|
203
|
-
return snapshot
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// ── typed reads (schema-first useNode, BoundNode-first useChildren) ──────────────
|
|
207
|
-
|
|
208
|
-
export function useNode<S extends Schema, T extends TypeNames<S>>(
|
|
209
|
-
schema: S,
|
|
210
|
-
type: T,
|
|
211
|
-
ref: NodeRefInput | null | undefined,
|
|
212
|
-
opts?: ReadOptions,
|
|
213
|
-
): TypedNodeResult<S, T> {
|
|
214
|
-
const binding = bindingFor(useSessionKernel(), schema, useMemory())
|
|
215
|
-
const shape = isIdleInput(ref) ? null : normalizeRef(ref)
|
|
216
|
-
const snap = useShape(shape, opts)
|
|
217
|
-
const wire = snap?.node ?? null
|
|
218
|
-
const bound = useBoundNode(binding, type, wire)
|
|
219
|
-
if (bound !== null) tagSchema(bound, schema)
|
|
220
|
-
const live = snap === null ? idleReadState() : readStateOf(snap)
|
|
221
|
-
return useMemo(
|
|
222
|
-
() => ({ ...live, node: bound }),
|
|
223
|
-
[bound, live.pending, live.error, live.live, live.seq],
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function useChildren<S extends Schema, T extends TypeNames<S>>(
|
|
228
|
-
parent: AnyBoundNode<S> | null | undefined,
|
|
229
|
-
opts: ReadOptions & {
|
|
230
|
-
type: T
|
|
231
|
-
order?: OrderInput
|
|
232
|
-
limit?: number
|
|
233
|
-
window?: 'append' | 'paged'
|
|
234
|
-
},
|
|
235
|
-
): TypedChildrenResult<S, T> {
|
|
236
|
-
const kernel = useSessionKernel()
|
|
237
|
-
const memory = useMemory()
|
|
238
|
-
const schema = isIdleInput(parent) ? null : requireSchema(parent)
|
|
239
|
-
const binding = schema === null ? null : bindingFor(kernel, schema, memory)
|
|
240
|
-
|
|
241
|
-
const parentRef = isIdleInput(parent) ? null : `@${parent.id}`
|
|
242
|
-
const classRef = schema === null ? undefined : classRefFor(schema, opts.type)
|
|
243
|
-
const shape =
|
|
244
|
-
parentRef === null
|
|
245
|
-
? null
|
|
246
|
-
: (q: QuerySource): GatherBuilder =>
|
|
247
|
-
q.from(parentRef).children({
|
|
248
|
-
...(classRef !== undefined ? { classes: [classRef] } : {}),
|
|
249
|
-
...(opts.order !== undefined ? { order: opts.order } : {}),
|
|
250
|
-
...(opts.limit !== undefined ? { limit: opts.limit } : {}),
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
const snap = useShape(shape, opts)
|
|
254
|
-
const wires = snap?.children ?? EMPTY
|
|
255
|
-
const bound = useBoundNodes(
|
|
256
|
-
(binding ?? UNBOUND) as unknown as SchemaBoundView<S>,
|
|
257
|
-
opts.type,
|
|
258
|
-
binding === null ? EMPTY : wires,
|
|
259
|
-
true,
|
|
260
|
-
)
|
|
261
|
-
if (schema !== null) for (const b of bound) tagSchema(b, schema)
|
|
262
|
-
|
|
263
|
-
const live = snap === null ? idleReadState() : readStateOf(snap)
|
|
264
|
-
const more = snap?.more ?? IDLE_MORE
|
|
265
|
-
return useMemo(
|
|
266
|
-
() => ({ ...live, more, children: bound }),
|
|
267
|
-
[bound, more, live.pending, live.error, live.live, live.seq],
|
|
268
|
-
)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
272
|
-
|
|
273
|
-
const EMPTY: readonly never[] = Object.freeze([])
|
|
274
|
-
const IDLE_MORE = { has: false, load: () => Promise.resolve(), pending: false } as const
|
|
275
|
-
const UNBOUND = {} as never
|
|
276
|
-
|
|
277
|
-
function readStateOf(snap: {
|
|
278
|
-
pending: boolean
|
|
279
|
-
error: unknown
|
|
280
|
-
live: boolean
|
|
281
|
-
seq: number
|
|
282
|
-
refetch(): Promise<void>
|
|
283
|
-
}): ReadState {
|
|
284
|
-
return {
|
|
285
|
-
pending: snap.pending,
|
|
286
|
-
error: snap.error,
|
|
287
|
-
live: snap.live,
|
|
288
|
-
seq: snap.seq,
|
|
289
|
-
refetch: snap.refetch,
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/** Recover the schema a BoundNode was bound under; a clear error if it is untagged. */
|
|
294
|
-
export function requireSchema(node: object): Schema {
|
|
295
|
-
const schema = schemaOf(node)
|
|
296
|
-
if (schema === undefined) {
|
|
297
|
-
throw new Error(
|
|
298
|
-
'useChildren: the parent was not produced by a shell-react typed binding — ' +
|
|
299
|
-
'obtain it from useNode / useDomain(schema).bind() so its schema is known.',
|
|
300
|
-
)
|
|
301
|
-
}
|
|
302
|
-
return schema
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const compiledCache = new WeakMap<Schema, ReturnType<typeof compileDomain>>()
|
|
306
|
-
|
|
307
|
-
/** The descent class ref for a type name (class or interface), or undefined. */
|
|
308
|
-
function classRefFor(schema: Schema, type: string): string | undefined {
|
|
309
|
-
let compiled = compiledCache.get(schema)
|
|
310
|
-
if (compiled === undefined) {
|
|
311
|
-
compiled = compileDomain(schema)
|
|
312
|
-
compiledCache.set(schema, compiled)
|
|
313
|
-
}
|
|
314
|
-
const accessor = compiled.$ as unknown as {
|
|
315
|
-
c(name: string): { path?: { class?: { raw: string } } } | undefined
|
|
316
|
-
i(name: string): { path?: { class?: { raw: string } } } | undefined
|
|
317
|
-
}
|
|
318
|
-
return accessor.c(type)?.path?.class?.raw ?? accessor.i(type)?.path?.class?.raw
|
|
319
|
-
}
|