@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.
Files changed (115) hide show
  1. package/dist/application/apps/app-host.d.ts +5 -5
  2. package/dist/application/apps/app-host.d.ts.map +1 -1
  3. package/dist/application/apps/app-host.js +18 -39
  4. package/dist/application/apps/apps.hook.d.ts +4 -11
  5. package/dist/application/apps/apps.hook.d.ts.map +1 -1
  6. package/dist/application/apps/apps.hook.js +9 -49
  7. package/dist/application/apps/open-app.hook.d.ts +4 -7
  8. package/dist/application/apps/open-app.hook.d.ts.map +1 -1
  9. package/dist/application/apps/open-app.hook.js +2 -2
  10. package/dist/application/index.d.ts +1 -3
  11. package/dist/application/index.d.ts.map +1 -1
  12. package/dist/application/index.js +1 -2
  13. package/dist/application/spaces/space.hook.d.ts.map +1 -1
  14. package/dist/application/spaces/space.hook.js +4 -1
  15. package/dist/auth/act-as.context.d.ts +1 -1
  16. package/dist/auth/act-as.context.d.ts.map +1 -1
  17. package/dist/auth/auth.hook.d.ts +1 -1
  18. package/dist/auth/auth.hook.d.ts.map +1 -1
  19. package/dist/auth/can.hook.d.ts +2 -2
  20. package/dist/auth/can.hook.d.ts.map +1 -1
  21. package/dist/auth/self.hook.d.ts +1 -1
  22. package/dist/auth/self.hook.d.ts.map +1 -1
  23. package/dist/components/can.d.ts +2 -2
  24. package/dist/components/can.d.ts.map +1 -1
  25. package/dist/graph/call/call.hook.d.ts +2 -2
  26. package/dist/graph/call/call.hook.d.ts.map +1 -1
  27. package/dist/graph/call/stream.hook.d.ts +2 -2
  28. package/dist/graph/call/stream.hook.d.ts.map +1 -1
  29. package/dist/graph/graph.context.d.ts +1 -1
  30. package/dist/graph/graph.context.d.ts.map +1 -1
  31. package/dist/graph/guards.error.d.ts +4 -4
  32. package/dist/graph/guards.error.d.ts.map +1 -1
  33. package/dist/graph/guards.error.js +4 -4
  34. package/dist/graph/query-definition.hook.d.ts +1 -2
  35. package/dist/graph/query-definition.hook.d.ts.map +1 -1
  36. package/dist/graph/query-definition.hook.js +4 -10
  37. package/dist/graph/resource.d.ts +1 -1
  38. package/dist/graph/resource.d.ts.map +1 -1
  39. package/dist/graph/store.d.ts +2 -2
  40. package/dist/graph/store.d.ts.map +1 -1
  41. package/dist/graph/store.js +1 -1
  42. package/dist/index.d.ts +5 -5
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1 -1
  45. package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
  46. package/dist/navigation/adapters/url.adapter.js +2 -5
  47. package/dist/navigation/codec.d.ts.map +1 -1
  48. package/dist/navigation/codec.js +1 -7
  49. package/dist/navigation/link.js +1 -1
  50. package/dist/navigation/scope.context.d.ts +1 -1
  51. package/dist/navigation/scope.context.d.ts.map +1 -1
  52. package/dist/navigation/scope.context.js +3 -6
  53. package/dist/navigation/snapshot.d.ts +1 -1
  54. package/dist/navigation/snapshot.d.ts.map +1 -1
  55. package/dist/navigation/snapshot.js +2 -8
  56. package/dist/navigation/view-key.d.ts +3 -0
  57. package/dist/navigation/view-key.d.ts.map +1 -0
  58. package/dist/navigation/view-key.js +8 -0
  59. package/dist/schema/action.hook.d.ts +11 -7
  60. package/dist/schema/action.hook.d.ts.map +1 -1
  61. package/dist/schema/action.hook.js +11 -6
  62. package/dist/schema/domain.hook.js +12 -13
  63. package/dist/schema/kernel.hook.d.ts +1 -1
  64. package/dist/schema/kernel.hook.d.ts.map +1 -1
  65. package/dist/schema/kernel.hook.js +1 -1
  66. package/dist/schema/mutation.hook.d.ts +2 -2
  67. package/dist/schema/mutation.hook.d.ts.map +1 -1
  68. package/dist/schema/mutation.hook.js +6 -5
  69. package/dist/schema/object.hook.d.ts +3 -6
  70. package/dist/schema/object.hook.d.ts.map +1 -1
  71. package/dist/schema/object.hook.js +4 -5
  72. package/dist/schema/relation.hook.d.ts +29 -19
  73. package/dist/schema/relation.hook.d.ts.map +1 -1
  74. package/dist/schema/relation.hook.js +45 -63
  75. package/dist/selection/live.d.ts.map +1 -1
  76. package/dist/selection/live.js +1 -2
  77. package/dist/session/session.context.d.ts +3 -4
  78. package/dist/session/session.context.d.ts.map +1 -1
  79. package/package.json +4 -14
  80. package/src/application/apps/app-host.tsx +22 -52
  81. package/src/application/apps/apps.hook.ts +14 -64
  82. package/src/application/apps/open-app.hook.ts +5 -10
  83. package/src/application/index.ts +2 -12
  84. package/src/application/spaces/space.hook.ts +6 -1
  85. package/src/auth/act-as.context.tsx +1 -1
  86. package/src/auth/auth.hook.ts +1 -1
  87. package/src/auth/can.hook.ts +3 -3
  88. package/src/auth/self.hook.ts +1 -1
  89. package/src/components/can.tsx +2 -2
  90. package/src/graph/call/call.hook.ts +2 -2
  91. package/src/graph/call/stream.hook.ts +2 -2
  92. package/src/graph/graph.context.ts +1 -1
  93. package/src/graph/guards.error.ts +4 -4
  94. package/src/graph/query-definition.hook.ts +13 -23
  95. package/src/graph/resource.ts +1 -1
  96. package/src/graph/store.ts +3 -3
  97. package/src/index.ts +3 -7
  98. package/src/navigation/adapters/url.adapter.ts +3 -4
  99. package/src/navigation/codec.ts +1 -7
  100. package/src/navigation/link.tsx +1 -1
  101. package/src/navigation/scope.context.tsx +5 -6
  102. package/src/navigation/snapshot.ts +4 -9
  103. package/src/navigation/view-key.ts +11 -0
  104. package/src/schema/action.hook.ts +45 -28
  105. package/src/schema/domain.hook.ts +9 -10
  106. package/src/schema/kernel.hook.ts +1 -1
  107. package/src/schema/mutation.hook.ts +13 -9
  108. package/src/schema/object.hook.ts +10 -18
  109. package/src/schema/relation.hook.ts +127 -145
  110. package/src/selection/live.ts +1 -2
  111. package/src/session/session.context.ts +3 -4
  112. package/dist/application/apps/domains.hook.d.ts +0 -7
  113. package/dist/application/apps/domains.hook.d.ts.map +0 -1
  114. package/dist/application/apps/domains.hook.js +0 -18
  115. package/src/application/apps/domains.hook.ts +0 -37
@@ -1,5 +1,5 @@
1
1
  import type { PathLike } from '@astrale-os/sdk/graph/path'
2
- import type { schema } from '@astrale-os/sdk/schema'
2
+ import type { PolicyRef } from '@astrale-os/sdk/schema'
3
3
  import type { ReactElement, ReactNode } from 'react'
4
4
 
5
5
  import type { PolicyObject } from '../auth/can.hook.js'
@@ -7,7 +7,7 @@ import type { PolicyObject } from '../auth/can.hook.js'
7
7
  import { useCan } from '../auth/can.hook.js'
8
8
 
9
9
  export function Can(props: {
10
- readonly policy: PathLike | schema.PolicyRef
10
+ readonly policy: PathLike | PolicyRef
11
11
  readonly object: PolicyObject
12
12
  readonly children: ReactNode
13
13
  readonly fallback?: ReactNode
@@ -1,5 +1,5 @@
1
- import type { Call } from '@astrale-os/kernel-client'
2
- import type { SessionRequestOptions } from '@astrale-os/kernel-client/session'
1
+ import type { Call } from '@astrale-os/sdk/client'
2
+ import type { SessionRequestOptions } from '@astrale-os/sdk/client/session'
3
3
  import type { Value } from '@astrale-os/sdk/value'
4
4
 
5
5
  import type { Action } from '../action.js'
@@ -1,5 +1,5 @@
1
- import type { Call } from '@astrale-os/kernel-client'
2
- import type { SessionRequestOptions } from '@astrale-os/kernel-client/session'
1
+ import type { Call } from '@astrale-os/sdk/client'
2
+ import type { SessionRequestOptions } from '@astrale-os/sdk/client/session'
3
3
  import type { Value } from '@astrale-os/sdk/value'
4
4
  import type { KernelClient } from '@astrale-os/shell'
5
5
 
@@ -1,4 +1,4 @@
1
- import type { GraphStore } from '@astrale-os/kernel-client/store'
1
+ import type { GraphStore } from '@astrale-os/sdk/client/store'
2
2
 
3
3
  import { createContext } from 'react'
4
4
 
@@ -4,12 +4,12 @@ export {
4
4
  ResponseError,
5
5
  StaleRouteError,
6
6
  TransportError,
7
- } from '@astrale-os/kernel-client'
8
- export { NodeUnavailableError } from '@astrale-os/kernel-client/graph'
7
+ } from '@astrale-os/sdk/client'
8
+ export { NodeUnavailableError } from '@astrale-os/sdk/client'
9
9
  export { UnsupportedFeatureError } from './memory/read/envelope.js'
10
10
 
11
- import { ClientError } from '@astrale-os/kernel-client'
12
- import { NodeUnavailableError } from '@astrale-os/kernel-client/graph'
11
+ import { ClientError } from '@astrale-os/sdk/client'
12
+ import { NodeUnavailableError } from '@astrale-os/sdk/client'
13
13
 
14
14
  export function isClientError(error: unknown): error is ClientError {
15
15
  return error instanceof ClientError
@@ -1,18 +1,12 @@
1
- import type { GraphStore, StoreQueryResponse, StoreSnapshot } from '@astrale-os/kernel-client/store'
2
- import type {
3
- QueryAstExecutionOptions,
4
- QueryDefinition,
5
- QueryValueBinder,
6
- } from '@astrale-os/sdk/query'
7
- import type { QueryAST } from '@astrale-os/sdk/query'
8
- import type { DomainBinding } from '@astrale-os/shell'
1
+ import type { QueryPageRequest } from '@astrale-os/sdk/client'
2
+ import type { GraphStore, StoreQueryResponse, StoreSnapshot } from '@astrale-os/sdk/client/store'
3
+ import type { QueryAST, QueryDefinition } from '@astrale-os/sdk/query'
9
4
 
10
- import { bindQueries } from '@astrale-os/sdk/query'
5
+ import { executeQuery } from '@astrale-os/sdk/query'
11
6
  import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'
12
7
 
13
8
  import type { GraphResource, GraphResourceState } from './resource.js'
14
9
 
15
- import { useDynamicDomain } from '../schema/domain.hook.js'
16
10
  import { retainRefreshScheduler } from './resource.js'
17
11
  import { useGraphStore } from './store.js'
18
12
 
@@ -24,7 +18,7 @@ export interface QueryResourceOptions {
24
18
 
25
19
  interface TouchedShape {
26
20
  readonly ast: QueryAST
27
- readonly options: QueryAstExecutionOptions
21
+ readonly options: { readonly page: QueryPageRequest }
28
22
  }
29
23
 
30
24
  interface DefinitionSnapshot<Output> {
@@ -33,7 +27,7 @@ interface DefinitionSnapshot<Output> {
33
27
  readonly error?: unknown
34
28
  }
35
29
 
36
- class DefinitionObserver<Input, Output, Query extends QueryAST> {
30
+ class DefinitionObserver<Input, Output> {
37
31
  private readonly listeners = new Set<() => void>()
38
32
  private subscriptions: readonly (() => void)[] = Object.freeze([])
39
33
  private touched: readonly TouchedShape[] = Object.freeze([])
@@ -45,8 +39,7 @@ class DefinitionObserver<Input, Output, Query extends QueryAST> {
45
39
 
46
40
  constructor(
47
41
  private readonly store: GraphStore,
48
- private readonly binding: DomainBinding,
49
- private readonly definition: QueryDefinition<Input, Output, Query>,
42
+ private readonly definition: QueryDefinition<Input, Output>,
50
43
  private readonly input: Input,
51
44
  ) {}
52
45
 
@@ -82,14 +75,12 @@ class DefinitionObserver<Input, Output, Query extends QueryAST> {
82
75
  })
83
76
  const execute = async <Ast extends QueryAST>(
84
77
  ast: Ast,
85
- options: QueryAstExecutionOptions,
78
+ options: { readonly page: QueryPageRequest },
86
79
  ): Promise<StoreQueryResponse<Ast>> => {
87
80
  touched.push(Object.freeze({ ast, options }))
88
81
  return this.store.read(ast, { ...options, freshness })
89
82
  }
90
- const bind = this.binding.$.bind as unknown as QueryValueBinder
91
- const query = bindQueries(execute, { bind })
92
- const running = query(this.definition, this.input)
83
+ const running = executeQuery({ query: execute }, this.definition, this.input)
93
84
  .then((data) => {
94
85
  if (!this.started || generation !== this.generation) return
95
86
  this.touched = dedupeShapes(touched)
@@ -157,17 +148,16 @@ class DefinitionObserver<Input, Output, Query extends QueryAST> {
157
148
  }
158
149
 
159
150
  /** Execute one named SDK Query definition exclusively through the current GraphStore. */
160
- export function useQuery<Input, Output, Query extends QueryAST>(
161
- definition: QueryDefinition<Input, Output, Query> | null,
151
+ export function useQuery<Input, Output>(
152
+ definition: QueryDefinition<Input, Output> | null,
162
153
  input: Input,
163
154
  options: QueryResourceOptions = {},
164
155
  ): GraphResource<Output> {
165
156
  const store = useGraphStore()
166
- const binding = useDynamicDomain()
167
157
  const inputIdentity = stableIdentity(input)
168
158
  const observer = useMemo(
169
- () => (definition === null ? null : new DefinitionObserver(store, binding, definition, input)),
170
- [store, binding, definition, inputIdentity],
159
+ () => (definition === null ? null : new DefinitionObserver(store, definition, input)),
160
+ [store, definition, inputIdentity],
171
161
  )
172
162
  const idle = useMemo<DefinitionSnapshot<Output>>(() => Object.freeze({ state: 'idle' }), [])
173
163
  const subscribe = useCallback(
@@ -1,4 +1,4 @@
1
- import type { GraphStore, StoreQueryResponse, StoreSnapshot } from '@astrale-os/kernel-client/store'
1
+ import type { GraphStore, StoreQueryResponse, StoreSnapshot } from '@astrale-os/sdk/client/store'
2
2
  import type { QueryAST } from '@astrale-os/sdk/query'
3
3
 
4
4
  import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'
@@ -1,8 +1,8 @@
1
- import type { GraphApi } from '@astrale-os/kernel-client/graph'
2
- import type { GraphStore as GraphStoreValue } from '@astrale-os/kernel-client/store'
1
+ import type { GraphApi } from '@astrale-os/sdk/client'
2
+ import type { GraphStore as GraphStoreValue } from '@astrale-os/sdk/client/store'
3
3
  import type { Shell } from '@astrale-os/shell'
4
4
 
5
- import { GraphStore } from '@astrale-os/kernel-client/store'
5
+ import { GraphStore } from '@astrale-os/sdk/client/store'
6
6
  import { useContext } from 'react'
7
7
 
8
8
  import { GraphContext } from './graph.context.js'
package/src/index.ts CHANGED
@@ -178,7 +178,6 @@ export {
178
178
  AppLogo,
179
179
  useApps,
180
180
  useCurrentSpace,
181
- useInstalledDomains,
182
181
  useOpenApp,
183
182
  useSpace,
184
183
  useSpaces,
@@ -190,7 +189,6 @@ export type {
190
189
  AppLogoProps,
191
190
  AppsResult,
192
191
  CurrentSpaceResult,
193
- DomainsResult,
194
192
  SpaceResult,
195
193
  SpacesResult,
196
194
  } from './application/index.js'
@@ -200,16 +198,14 @@ export { NodeId } from '@astrale-os/sdk/graph/node'
200
198
  export { NodePath, Path } from '@astrale-os/sdk/graph/path'
201
199
  export type { Node } from '@astrale-os/sdk/graph/node'
202
200
  export type { PathLike } from '@astrale-os/sdk/graph/path'
203
- export type { AuthApi, Identity, PolicyDecisionInput } from '@astrale-os/kernel-client/auth'
204
- export type { DomainBinding, DomainInvokeOptions } from '@astrale-os/shell'
201
+ export type { AuthApi, Identity, PolicyDecisionInput } from '@astrale-os/sdk/auth'
202
+ export type { DomainBinding } from '@astrale-os/shell'
205
203
 
206
204
  // Shell contracts retained at the package root for custom full-app composition.
207
205
  export type {
208
- ApplicationNode,
209
- AppSession,
206
+ App,
210
207
  CloseResult,
211
208
  CredentialSnapshot,
212
- DomainSearchResult,
213
209
  HostCapabilities,
214
210
  IntentRegistry,
215
211
  KernelClient,
@@ -1,5 +1,4 @@
1
1
  import { NodePath } from '@astrale-os/sdk/graph/path'
2
- import { Key } from '@astrale-os/sdk/schema'
3
2
 
4
3
  /**
5
4
  * urlAdapter (API §8.1) — the History-API adapter: mirrors the location into the
@@ -9,6 +8,8 @@ import { Key } from '@astrale-os/sdk/schema'
9
8
  import type { SerializedLocation } from '../history.js'
10
9
  import type { NavAdapter } from './adapter.js'
11
10
 
11
+ import { viewKey } from '../view-key.js'
12
+
12
13
  const VIEW_KEY = 'astrale.view'
13
14
  const PARAM_PREFIX = 'astrale.param.'
14
15
 
@@ -55,9 +56,7 @@ export function urlAdapter(opts?: { param?: string }): NavAdapter {
55
56
  node = NodePath(rawNode)
56
57
  const rawView = sp.get(VIEW_KEY)
57
58
  if (rawView !== null) {
58
- const admitted = Key(rawView)
59
- if (!Key.ref(admitted).startsWith('view.')) throw new TypeError('Invalid View key.')
60
- view = admitted as Key.View
59
+ view = viewKey(rawView)
61
60
  }
62
61
  } catch {
63
62
  return null
@@ -2,7 +2,6 @@ import type { Key } from '@astrale-os/sdk/schema'
2
2
  import type { ReactElement, ReactNode } from 'react'
3
3
 
4
4
  import { Path } from '@astrale-os/sdk/graph/path'
5
- import { Key as admitKey } from '@astrale-os/sdk/schema'
6
5
  import { createElement } from 'react'
7
6
 
8
7
  import type { NavAdapter } from './adapters/adapter.js'
@@ -11,6 +10,7 @@ import type { NavSnapshot, SerializedLocation } from './history.js'
11
10
  import { NavScope } from './scope.context.js'
12
11
  import { useNavCtx } from './scope.context.js'
13
12
  import { useHistoryVersion } from './scope.context.js'
13
+ import { viewKey } from './view-key.js'
14
14
 
15
15
  export interface NavigationParam<Value> {
16
16
  encode(value: Value): string
@@ -182,9 +182,3 @@ export function useNavigation<Routes extends NavigationRoutes>(
182
182
 
183
183
  export type NavigationTarget<Definition> =
184
184
  Definition extends NavigationDefinition<infer Routes> ? RouteTarget<Routes> : never
185
-
186
- function viewKey(input: string): Key.View {
187
- const key = admitKey(input)
188
- if (!admitKey.ref(key).startsWith('view.')) throw new TypeError(`Invalid View key '${input}'.`)
189
- return key as Key.View
190
- }
@@ -50,7 +50,7 @@ export function Link(props: LinkProps): ReactElement {
50
50
  const nodeRef = target.node
51
51
 
52
52
  const preload = useCallback(() => {
53
- const query = Query.from({ kind: 'node', paths: [nodeRef] }).select({ kind: 'graph' })
53
+ const query = Query.from({ nodes: [nodeRef] }).select({ kind: 'graph' })
54
54
  void ctx.store.preload(query, { page: { size: 1 } }).catch(() => {})
55
55
  }, [ctx.store, nodeRef])
56
56
 
@@ -1,9 +1,9 @@
1
- import type { GraphStore, StoreQueryResponse } from '@astrale-os/kernel-client/store'
1
+ import type { GraphStore, StoreQueryResponse } from '@astrale-os/sdk/client/store'
2
+ import type { Key } from '@astrale-os/sdk/schema'
2
3
  import type { ReactElement, ReactNode } from 'react'
3
4
 
4
5
  import { NodePath } from '@astrale-os/sdk/graph/path'
5
6
  import { Query } from '@astrale-os/sdk/query'
6
- import { Key } from '@astrale-os/sdk/schema'
7
7
  import {
8
8
  createContext,
9
9
  startTransition,
@@ -28,6 +28,7 @@ import { memoryAdapter } from './adapters/memory.adapter.js'
28
28
  import { NavHistory, seedEntries } from './history.js'
29
29
  import { buildLocation } from './location.js'
30
30
  import { revalidateAndPrune, serializeTarget } from './snapshot.js'
31
+ import { viewKey } from './view-key.js'
31
32
 
32
33
  export interface Navigate {
33
34
  (to: NavTarget, opts?: { replace?: boolean }): void
@@ -85,7 +86,7 @@ export function useGraphPoint(target: NodePath | null): PointResult | null {
85
86
  () =>
86
87
  target === null
87
88
  ? null
88
- : Query.from({ kind: 'node', paths: [target], binding: 'navigation_target' }).select({
89
+ : Query.from({ nodes: [target], binding: 'navigation_target' }).select({
89
90
  kind: 'graph',
90
91
  }),
91
92
  [target],
@@ -253,9 +254,7 @@ function admitLocation(location: SerializedLocation): SerializedLocation {
253
254
  const node = NodePath(location.node)
254
255
  let view: Key.View | undefined
255
256
  if (location.view !== undefined) {
256
- const key = Key(location.view)
257
- if (!Key.ref(key).startsWith('view.')) throw new TypeError('Navigation View key is invalid.')
258
- view = key as Key.View
257
+ view = viewKey(location.view)
259
258
  }
260
259
  const params: Record<string, string> = {}
261
260
  if (location.params !== undefined) {
@@ -1,4 +1,4 @@
1
- import type { GraphStore } from '@astrale-os/kernel-client/store'
1
+ import type { GraphStore } from '@astrale-os/sdk/client/store'
2
2
  import type { Node } from '@astrale-os/sdk/graph/node'
3
3
  import type { NodePath, PathLike } from '@astrale-os/sdk/graph/path'
4
4
  import type { Key } from '@astrale-os/sdk/schema'
@@ -6,10 +6,11 @@ import type { Shell } from '@astrale-os/shell'
6
6
 
7
7
  import { Path } from '@astrale-os/sdk/graph/path'
8
8
  import { Query } from '@astrale-os/sdk/query'
9
- import { Key as admitKey } from '@astrale-os/sdk/schema'
10
9
 
11
10
  import type { NavHistory, SerializedLocation } from './history.js'
12
11
 
12
+ import { viewKey } from './view-key.js'
13
+
13
14
  /** Canonical navigation inputs; there is no implicit slash-tree or bare-id grammar. */
14
15
  export type NavTarget =
15
16
  | PathLike
@@ -44,12 +45,6 @@ export function serializeTarget(target: NavTarget): SerializedLocation {
44
45
  }
45
46
  }
46
47
 
47
- function viewKey(input: string): Key.View {
48
- const key = admitKey(input)
49
- if (!admitKey.ref(key).startsWith('view.')) throw new TypeError(`Invalid View key '${input}'.`)
50
- return key as Key.View
51
- }
52
-
53
48
  /** Drop restored entries that no longer resolve under the authenticated Graph capability. */
54
49
  export async function revalidateAndPrune(
55
50
  history: NavHistory,
@@ -81,7 +76,7 @@ async function resolves(
81
76
  entry: SerializedLocation,
82
77
  ): Promise<boolean> {
83
78
  try {
84
- const query = Query.from({ kind: 'node', paths: [entry.node] }).select({ kind: 'graph' })
79
+ const query = Query.from({ nodes: [entry.node] }).select({ kind: 'graph' })
85
80
  const response = await store.read(query, { page: { size: 1 } })
86
81
  if (
87
82
  response.result.kind !== 'graph' ||
@@ -0,0 +1,11 @@
1
+ import type { Key } from '@astrale-os/sdk/schema'
2
+
3
+ import { Key as admitKey } from '@astrale-os/sdk/schema'
4
+
5
+ export function viewKey(input: string): Key.View {
6
+ const key = admitKey(input)
7
+ if (!key.slice(key.indexOf(':') + 1).startsWith('view.')) {
8
+ throw new TypeError(`Invalid View key '${input}'.`)
9
+ }
10
+ return key as Key.View
11
+ }
@@ -1,25 +1,33 @@
1
- import type {
2
- InputOf,
3
- InstanceMethod,
4
- OutputOf,
5
- ReceiverOf,
6
- RemoteCallableOf,
7
- } from '@astrale-os/sdk/domain'
1
+ import type { BoundNodeFor } from '@astrale-os/sdk/client'
2
+ import type { SessionRequestOptions } from '@astrale-os/sdk/client/session'
8
3
  import type { NodeId } from '@astrale-os/sdk/graph/node'
9
4
  import type { QueryAST } from '@astrale-os/sdk/query'
10
- import type { schema } from '@astrale-os/sdk/schema'
11
- import type { DomainInvokeOptions } from '@astrale-os/shell'
12
-
5
+ import type {
6
+ CallableInputOf,
7
+ CallableResultOf,
8
+ MethodOwnerKeyOf,
9
+ MethodInheritance,
10
+ ResolvedFunction,
11
+ ResolvedMethod,
12
+ } from '@astrale-os/sdk/schema'
13
+
14
+ import { reference } from '@astrale-os/sdk/client/session'
13
15
  import { Path } from '@astrale-os/sdk/graph/path'
14
16
  import { useCallback, useMemo, useRef } from 'react'
15
17
 
16
18
  import type { Action as AsyncAction } from '../graph/action.js'
17
19
 
20
+ import { useSessionKernel } from '../auth/session-kernel.js'
18
21
  import { useAction as useAsyncAction } from '../graph/action.js'
19
22
  import { useGraphStore } from '../graph/store.js'
20
23
  import { bindingFor } from './domain.hook.js'
21
24
 
22
- type Callable = RemoteCallableOf<schema.DomainSchema> | InstanceMethod
25
+ type ExecutableInheritance = Exclude<MethodInheritance, 'abstract'>
26
+ type InstanceMethod = ResolvedMethod<unknown, unknown, false, ExecutableInheritance>
27
+ type StaticMethod = ResolvedMethod<unknown, unknown, true, ExecutableInheritance>
28
+ type Callable = ResolvedFunction | InstanceMethod | StaticMethod
29
+ type Receiver = { readonly id: NodeId }
30
+ type MethodReceiver<C extends InstanceMethod> = BoundNodeFor<MethodOwnerKeyOf<C>>
23
31
 
24
32
  const QUERY_REFRESH = Symbol('shell-react.query-refresh')
25
33
 
@@ -59,14 +67,14 @@ export type ActionRefresh =
59
67
  readonly queries: readonly QueryRefresh[]
60
68
  }
61
69
 
62
- export interface ActionOptions extends DomainInvokeOptions {
70
+ export interface ActionOptions extends SessionRequestOptions {
63
71
  readonly refresh?: ActionRefresh
64
72
  readonly onError?: (error: unknown) => void
65
73
  }
66
74
 
67
75
  type ActionArgs<C extends Callable> = C extends InstanceMethod
68
- ? [receiver: ReceiverOf<C>, input: InputOf<C>]
69
- : [input: InputOf<C>]
76
+ ? [receiver: MethodReceiver<C>, input: CallableInputOf<C>]
77
+ : [input: CallableInputOf<C>]
70
78
 
71
79
  export interface DomainAction<Args extends unknown[], Result> {
72
80
  run(...args: Args): Promise<Result>
@@ -80,8 +88,9 @@ export interface DomainAction<Args extends unknown[], Result> {
80
88
  export function useAction<C extends Callable>(
81
89
  callable: C,
82
90
  options: ActionOptions = {},
83
- ): DomainAction<ActionArgs<C>, OutputOf<C>> {
91
+ ): DomainAction<ActionArgs<C>, CallableResultOf<C>> {
84
92
  const binding = bindingFor(callable)
93
+ const kernel = useSessionKernel()
85
94
  const store = useGraphStore()
86
95
  const callableRef = useRef(callable)
87
96
  callableRef.current = callable
@@ -91,18 +100,22 @@ export function useAction<C extends Callable>(
91
100
  optionsRef.current = options
92
101
 
93
102
  const invoke = useCallback(
94
- async (...args: ActionArgs<C>): Promise<OutputOf<C>> => {
103
+ async (...args: ActionArgs<C>): Promise<CallableResultOf<C>> => {
95
104
  const current = callableRef.current
96
105
  const policy = optionsRef.current
97
106
  const { refresh: _refresh, onError: _onError, ...request } = policy
98
107
  try {
99
- const invokeExact = bindingRef.current.$.invoke as (
100
- ...values: readonly unknown[]
101
- ) => Promise<OutputOf<C>>
102
- const result =
103
- 'on' in current
104
- ? await invokeExact(current, receiverPath(args[0] as ReceiverOf<C>), args[1], request)
105
- : await invokeExact(current, args[0], request)
108
+ const result = isInstanceMethod(current)
109
+ ? await kernel.session.invoke(
110
+ reference(bindingRef.current.domain, current)(receiverPath(args[0] as Receiver)),
111
+ args[1] as never,
112
+ request,
113
+ )
114
+ : await kernel.session.invoke(
115
+ reference(bindingRef.current.domain, current),
116
+ args[0] as never,
117
+ request,
118
+ )
106
119
  const refresh = policy.refresh ?? 'all'
107
120
  if (refresh === 'all') store.invalidate()
108
121
  else if (refresh !== 'none') {
@@ -111,15 +124,15 @@ export function useAction<C extends Callable>(
111
124
  store.invalidate(target.ast, { page: target.page })
112
125
  })
113
126
  }
114
- return result
127
+ return result as CallableResultOf<C>
115
128
  } catch (error) {
116
129
  policy.onError?.(error)
117
130
  throw error
118
131
  }
119
132
  },
120
- [store],
133
+ [kernel, store],
121
134
  )
122
- const action = useAsyncAction(invoke as (...args: ActionArgs<C>) => Promise<OutputOf<C>>)
135
+ const action = useAsyncAction(invoke)
123
136
  return useMemo(() => projectAction(action), [action])
124
137
  }
125
138
 
@@ -141,6 +154,10 @@ function projectAction<Args extends unknown[], Result>(
141
154
  }
142
155
  }
143
156
 
144
- function receiverPath(receiver: { readonly id: NodeId }): string {
145
- return Path.id(receiver.id).raw
157
+ function isInstanceMethod(callable: Callable): callable is InstanceMethod {
158
+ return 'owner' in callable && callable.static === false
159
+ }
160
+
161
+ function receiverPath(receiver: Receiver): Path {
162
+ return Path.id(receiver.id)
146
163
  }
@@ -89,17 +89,16 @@ export function bindingFor(value: object): DomainBinding {
89
89
  }
90
90
 
91
91
  function registerBinding(binding: DomainBinding): void {
92
- const seen = new WeakSet<object>()
93
- const visit = (value: unknown, depth: number): void => {
94
- if (depth > 4 || value === null || typeof value !== 'object' || seen.has(value)) return
95
- seen.add(value)
96
- bindingByValue.set(value, binding)
97
- for (const [key, child] of Object.entries(value)) {
98
- if (key === 'schema' || key === 'publication' || key === 'session') continue
99
- visit(child, depth + 1)
100
- }
92
+ bindingByValue.set(binding, binding)
93
+ bindingByValue.set(binding.domain, binding)
94
+ for (const definition of Object.values(binding.domain.classes)) {
95
+ bindingByValue.set(definition, binding)
96
+ for (const method of definition.methods) bindingByValue.set(method, binding)
97
+ for (const method of definition.static.methods) bindingByValue.set(method, binding)
98
+ }
99
+ for (const callable of Object.values(binding.domain.functions)) {
100
+ bindingByValue.set(callable, binding)
101
101
  }
102
- visit(binding, 0)
103
102
  }
104
103
 
105
104
  function createResource<T>(promise: Promise<T>): Resource<T> {
@@ -1,6 +1,6 @@
1
1
  import type { DomainBinding } from '@astrale-os/shell'
2
2
 
3
- import { KernelSchema } from '@astrale-os/sdk/schema/kernel'
3
+ import { KernelSchema } from '@astrale-os/sdk/schema'
4
4
 
5
5
  import { useDomain } from './domain.hook.js'
6
6
 
@@ -1,6 +1,6 @@
1
- import type { MutationDefinition } from '@astrale-os/sdk/mutation'
1
+ import type { Mutation } from '@astrale-os/sdk/mutation'
2
2
 
3
- import { bindMutations } from '@astrale-os/sdk/mutation'
3
+ import { executeMutation } from '@astrale-os/sdk/mutation'
4
4
  import { useCallback, useMemo, useRef } from 'react'
5
5
 
6
6
  import type { Action as AsyncAction } from '../graph/action.js'
@@ -16,7 +16,7 @@ export interface MutationOptions {
16
16
 
17
17
  /** Execute one named SDK Mutation definition through GraphStore optimism/invalidation. */
18
18
  export function useMutation<Input, Output>(
19
- definition: MutationDefinition<Input, Output>,
19
+ definition: Mutation<Input, Output>,
20
20
  options: MutationOptions = {},
21
21
  ): DomainAction<[Input], Output> {
22
22
  const store = useGraphStore()
@@ -26,13 +26,17 @@ export function useMutation<Input, Output>(
26
26
  optionsRef.current = options
27
27
  const run = useCallback(
28
28
  async (input: Input): Promise<Output> => {
29
- const execute = bindMutations((ast) =>
30
- store.mutate(ast, {
31
- optimistic: optionsRef.current.optimistic ?? true,
32
- }),
33
- )
34
29
  try {
35
- return await execute(definitionRef.current, input)
30
+ return await executeMutation(
31
+ {
32
+ mutate: (ast) =>
33
+ store.mutate(ast, {
34
+ optimistic: optionsRef.current.optimistic ?? true,
35
+ }),
36
+ },
37
+ definitionRef.current,
38
+ input,
39
+ )
36
40
  } catch (error) {
37
41
  optionsRef.current.onError?.(error)
38
42
  throw error
@@ -1,7 +1,8 @@
1
- import type { StoreQueryResponse } from '@astrale-os/kernel-client/store'
2
- import type { BoundInstanceOf, Definition } from '@astrale-os/sdk/domain'
1
+ import type { BoundNode } from '@astrale-os/sdk/client'
2
+ import type { StoreQueryResponse } from '@astrale-os/sdk/client/store'
3
3
  import type { Node } from '@astrale-os/sdk/graph/node'
4
4
  import type { PathLike } from '@astrale-os/sdk/graph/path'
5
+ import type { ResolvedClass } from '@astrale-os/sdk/schema'
5
6
 
6
7
  import { Path } from '@astrale-os/sdk/graph/path'
7
8
  import { Query } from '@astrale-os/sdk/query'
@@ -16,25 +17,20 @@ export interface RichReadOptions {
16
17
  readonly pageSize?: number
17
18
  }
18
19
 
19
- type ObjectDefinition = Pick<
20
- Definition<'class' | 'interface'>,
21
- 'kind' | 'origin' | 'name' | 'key' | 'schemaRef' | 'definition'
22
- > & { readonly family: 'node' }
23
-
24
20
  /** Read and bind one exact rich object definition exclusively through GraphStore. */
25
- export function useObject<RichDefinition extends ObjectDefinition>(
26
- definition: RichDefinition,
21
+ export function useObject<Class extends ResolvedClass<'node'>>(
22
+ definition: Class,
27
23
  target: PathLike | null | undefined,
28
24
  options: RichReadOptions = {},
29
- ): GraphResource<BoundInstanceOf<RichDefinition> | null> {
25
+ ): GraphResource<BoundNode<Class> | null> {
30
26
  const binding = bindingFor(definition)
31
27
  const path = target === null || target === undefined ? null : Path.from(target)
32
28
  const query = useMemo(
33
29
  () =>
34
30
  path === null
35
31
  ? null
36
- : Query.from({ kind: 'node', paths: [path], binding: 'object' })
37
- .filter({ satisfies: definition.schemaRef })
32
+ : Query.from({ nodes: [path], binding: 'object' })
33
+ .filter({ class: definition })
38
34
  .select({ kind: 'graph' }),
39
35
  [definition, path?.raw],
40
36
  )
@@ -47,11 +43,7 @@ export function useObject<RichDefinition extends ObjectDefinition>(
47
43
  id === undefined
48
44
  ? undefined
49
45
  : result.graph.nodes.find((candidate: { readonly id: unknown }) => candidate.id === id)
50
- const bind = binding.$.bind as unknown as (
51
- expected: RichDefinition,
52
- value: Node,
53
- ) => BoundInstanceOf<RichDefinition>
54
- return node === undefined ? null : bind(definition, node)
46
+ return node === undefined ? null : binding.wrapNode(definition, node)
55
47
  },
56
48
  [binding, definition],
57
49
  )
@@ -68,7 +60,7 @@ export function useDynamicObject(
68
60
  () =>
69
61
  path === null
70
62
  ? null
71
- : Query.from({ kind: 'node', paths: [path], binding: 'dynamic_object' }).select({
63
+ : Query.from({ nodes: [path], binding: 'dynamic_object' }).select({
72
64
  kind: 'graph',
73
65
  }),
74
66
  [path?.raw],