@astrale-os/shell-react 0.2.9 → 0.2.10-beta.3

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 (335) hide show
  1. package/dist/application/apps/app-host.d.ts +4 -15
  2. package/dist/application/apps/app-host.d.ts.map +1 -1
  3. package/dist/application/apps/app-host.js +1 -1
  4. package/dist/application/apps/apps.hook.d.ts +7 -4
  5. package/dist/application/apps/apps.hook.d.ts.map +1 -1
  6. package/dist/application/apps/apps.hook.js +10 -2
  7. package/dist/application/apps/domains.hook.d.ts +1 -1
  8. package/dist/application/apps/domains.hook.d.ts.map +1 -1
  9. package/dist/application/apps/domains.hook.js +1 -1
  10. package/dist/application/apps/open-app.hook.d.ts +2 -3
  11. package/dist/application/apps/open-app.hook.d.ts.map +1 -1
  12. package/dist/application/index.d.ts +2 -4
  13. package/dist/application/index.d.ts.map +1 -1
  14. package/dist/application/index.js +2 -3
  15. package/dist/application/spaces/space.hook.d.ts +2 -2
  16. package/dist/application/spaces/space.hook.d.ts.map +1 -1
  17. package/dist/application/spaces/space.hook.js +2 -2
  18. package/dist/application/spaces/spaces.hook.d.ts +2 -3
  19. package/dist/application/spaces/spaces.hook.d.ts.map +1 -1
  20. package/dist/application/spaces/spaces.hook.js +10 -3
  21. package/dist/auth/act-as.context.d.ts +15 -32
  22. package/dist/auth/act-as.context.d.ts.map +1 -1
  23. package/dist/auth/act-as.context.js +22 -66
  24. package/dist/auth/auth.hook.d.ts +1 -0
  25. package/dist/auth/auth.hook.d.ts.map +1 -1
  26. package/dist/auth/auth.hook.js +2 -22
  27. package/dist/auth/can.hook.d.ts +10 -38
  28. package/dist/auth/can.hook.d.ts.map +1 -1
  29. package/dist/auth/can.hook.js +35 -110
  30. package/dist/auth/index.d.ts +1 -0
  31. package/dist/auth/index.d.ts.map +1 -1
  32. package/dist/auth/self.hook.d.ts +2 -2
  33. package/dist/auth/self.hook.d.ts.map +1 -1
  34. package/dist/auth/self.hook.js +0 -7
  35. package/dist/auth/session-kernel.d.ts +2 -3
  36. package/dist/auth/session-kernel.d.ts.map +1 -1
  37. package/dist/auth/session-kernel.js +4 -13
  38. package/dist/components/astrale.d.ts +14 -0
  39. package/dist/components/astrale.d.ts.map +1 -0
  40. package/dist/components/astrale.js +12 -0
  41. package/dist/components/boundaries.d.ts +47 -0
  42. package/dist/components/boundaries.d.ts.map +1 -0
  43. package/dist/components/boundaries.js +55 -0
  44. package/dist/components/can.d.ts +11 -0
  45. package/dist/components/can.d.ts.map +1 -0
  46. package/dist/components/can.js +5 -0
  47. package/dist/components/index.d.ts +6 -0
  48. package/dist/components/index.d.ts.map +1 -0
  49. package/dist/components/index.js +3 -0
  50. package/dist/graph/call/call.hook.d.ts +8 -18
  51. package/dist/graph/call/call.hook.d.ts.map +1 -1
  52. package/dist/graph/call/call.hook.js +7 -13
  53. package/dist/graph/call/stream.hook.d.ts +12 -20
  54. package/dist/graph/call/stream.hook.d.ts.map +1 -1
  55. package/dist/graph/call/stream.hook.js +55 -111
  56. package/dist/graph/graph.context.d.ts +4 -3
  57. package/dist/graph/graph.context.d.ts.map +1 -1
  58. package/dist/graph/graph.context.js +2 -8
  59. package/dist/graph/guards.error.d.ts +7 -8
  60. package/dist/graph/guards.error.d.ts.map +1 -1
  61. package/dist/graph/guards.error.js +11 -7
  62. package/dist/graph/index.d.ts +8 -16
  63. package/dist/graph/index.d.ts.map +1 -1
  64. package/dist/graph/index.js +3 -7
  65. package/dist/graph/memory/read/envelope.d.ts +22 -54
  66. package/dist/graph/memory/read/envelope.d.ts.map +1 -1
  67. package/dist/graph/memory/read/envelope.js +26 -20
  68. package/dist/graph/memory/read/idle.d.ts +1 -15
  69. package/dist/graph/memory/read/idle.d.ts.map +1 -1
  70. package/dist/graph/memory/read/idle.js +4 -13
  71. package/dist/graph/query-definition.hook.d.ts +11 -0
  72. package/dist/graph/query-definition.hook.d.ts.map +1 -0
  73. package/dist/graph/query-definition.hook.js +205 -0
  74. package/dist/graph/resource.d.ts +34 -0
  75. package/dist/graph/resource.d.ts.map +1 -0
  76. package/dist/graph/resource.js +244 -0
  77. package/dist/graph/store.d.ts +25 -0
  78. package/dist/graph/store.d.ts.map +1 -0
  79. package/dist/graph/store.js +69 -0
  80. package/dist/host/actions.hook.d.ts +34 -0
  81. package/dist/host/actions.hook.d.ts.map +1 -0
  82. package/dist/host/actions.hook.js +125 -0
  83. package/dist/host/components.d.ts +15 -0
  84. package/dist/host/components.d.ts.map +1 -0
  85. package/dist/host/components.js +14 -0
  86. package/dist/host/index.d.ts +5 -0
  87. package/dist/host/index.d.ts.map +1 -0
  88. package/dist/host/index.js +3 -0
  89. package/dist/index.d.ts +26 -37
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +20 -31
  92. package/dist/intents/envelope.d.ts +7 -19
  93. package/dist/intents/envelope.d.ts.map +1 -1
  94. package/dist/intents/envelope.js +2 -3
  95. package/dist/intents/send-intent.hook.d.ts +5 -7
  96. package/dist/intents/send-intent.hook.d.ts.map +1 -1
  97. package/dist/intents/send-intent.hook.js +17 -75
  98. package/dist/navigation/adapters/adapter.d.ts +5 -0
  99. package/dist/navigation/adapters/adapter.d.ts.map +1 -1
  100. package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -1
  101. package/dist/navigation/adapters/memory.adapter.js +4 -0
  102. package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
  103. package/dist/navigation/adapters/url.adapter.js +57 -10
  104. package/dist/navigation/codec.d.ts +60 -0
  105. package/dist/navigation/codec.d.ts.map +1 -0
  106. package/dist/navigation/codec.js +121 -0
  107. package/dist/navigation/history.d.ts +11 -9
  108. package/dist/navigation/history.d.ts.map +1 -1
  109. package/dist/navigation/history.js +6 -8
  110. package/dist/navigation/hooks/ancestors.hook.d.ts +5 -7
  111. package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -1
  112. package/dist/navigation/hooks/ancestors.hook.js +7 -51
  113. package/dist/navigation/hooks/location.hook.d.ts.map +1 -1
  114. package/dist/navigation/hooks/location.hook.js +4 -6
  115. package/dist/navigation/hooks/scope.hook.d.ts.map +1 -1
  116. package/dist/navigation/hooks/scope.hook.js +4 -6
  117. package/dist/navigation/index.d.ts +4 -2
  118. package/dist/navigation/index.d.ts.map +1 -1
  119. package/dist/navigation/index.js +2 -1
  120. package/dist/navigation/link.d.ts +12 -0
  121. package/dist/navigation/link.d.ts.map +1 -1
  122. package/dist/navigation/link.js +13 -2
  123. package/dist/navigation/location.d.ts +13 -40
  124. package/dist/navigation/location.d.ts.map +1 -1
  125. package/dist/navigation/location.js +14 -76
  126. package/dist/navigation/scope.context.d.ts +17 -26
  127. package/dist/navigation/scope.context.d.ts.map +1 -1
  128. package/dist/navigation/scope.context.js +140 -108
  129. package/dist/navigation/snapshot.d.ts +14 -19
  130. package/dist/navigation/snapshot.d.ts.map +1 -1
  131. package/dist/navigation/snapshot.js +48 -44
  132. package/dist/schema/action.hook.d.ts +44 -0
  133. package/dist/schema/action.hook.d.ts.map +1 -0
  134. package/dist/schema/action.hook.js +72 -0
  135. package/dist/schema/domain.hook.d.ts +12 -7
  136. package/dist/schema/domain.hook.d.ts.map +1 -1
  137. package/dist/schema/domain.hook.js +101 -4
  138. package/dist/schema/index.d.ts +9 -8
  139. package/dist/schema/index.d.ts.map +1 -1
  140. package/dist/schema/index.js +5 -7
  141. package/dist/schema/kernel.hook.d.ts +4 -9
  142. package/dist/schema/kernel.hook.d.ts.map +1 -1
  143. package/dist/schema/kernel.hook.js +4 -6
  144. package/dist/schema/mutation.hook.d.ts +9 -0
  145. package/dist/schema/mutation.hook.d.ts.map +1 -0
  146. package/dist/schema/mutation.hook.js +41 -0
  147. package/dist/schema/object.hook.d.ts +16 -0
  148. package/dist/schema/object.hook.d.ts.map +1 -0
  149. package/dist/schema/object.hook.js +46 -0
  150. package/dist/schema/relation.hook.d.ts +46 -0
  151. package/dist/schema/relation.hook.d.ts.map +1 -0
  152. package/dist/schema/relation.hook.js +136 -0
  153. package/dist/selection/live.d.ts +9 -17
  154. package/dist/selection/live.d.ts.map +1 -1
  155. package/dist/selection/live.js +65 -112
  156. package/dist/selection/scope.context.js +5 -4
  157. package/dist/session/boot/boot.d.ts +1 -13
  158. package/dist/session/boot/boot.d.ts.map +1 -1
  159. package/dist/session/boot/boot.js +9 -27
  160. package/dist/session/index.d.ts +1 -0
  161. package/dist/session/index.d.ts.map +1 -1
  162. package/dist/session/kernel-instance.hook.d.ts +1 -4
  163. package/dist/session/kernel-instance.hook.d.ts.map +1 -1
  164. package/dist/session/kernel-instance.hook.js +1 -5
  165. package/dist/session/provider.d.ts +9 -23
  166. package/dist/session/provider.d.ts.map +1 -1
  167. package/dist/session/provider.js +29 -75
  168. package/dist/session/session.context.d.ts +5 -0
  169. package/dist/session/session.context.d.ts.map +1 -1
  170. package/dist/window/adopt.d.ts +0 -1
  171. package/dist/window/adopt.d.ts.map +1 -1
  172. package/dist/window/hooks/target-node.hook.d.ts +10 -6
  173. package/dist/window/hooks/target-node.hook.d.ts.map +1 -1
  174. package/dist/window/hooks/target-node.hook.js +14 -72
  175. package/dist/window/hooks/views-for.hook.d.ts +4 -3
  176. package/dist/window/hooks/views-for.hook.d.ts.map +1 -1
  177. package/dist/window/hooks/views-for.hook.js +6 -22
  178. package/dist/window/hooks/windows.hook.d.ts.map +1 -1
  179. package/dist/window/hooks/windows.hook.js +3 -4
  180. package/dist/window/host.d.ts +9 -11
  181. package/dist/window/host.d.ts.map +1 -1
  182. package/dist/window/host.js +26 -62
  183. package/dist/window/hub.d.ts +2 -0
  184. package/dist/window/hub.d.ts.map +1 -1
  185. package/dist/window/hub.js +33 -0
  186. package/dist/window/index.d.ts +2 -2
  187. package/dist/window/index.d.ts.map +1 -1
  188. package/dist/window/index.js +2 -2
  189. package/dist/window/lifecycle/mount.d.ts +5 -44
  190. package/dist/window/lifecycle/mount.d.ts.map +1 -1
  191. package/dist/window/lifecycle/mount.js +14 -120
  192. package/dist/window/lifecycle/states.d.ts +0 -5
  193. package/dist/window/lifecycle/states.d.ts.map +1 -1
  194. package/package.json +20 -8
  195. package/src/application/apps/app-host.tsx +11 -15
  196. package/src/application/apps/apps.hook.ts +13 -6
  197. package/src/application/apps/domains.hook.ts +1 -1
  198. package/src/application/apps/open-app.hook.ts +3 -4
  199. package/src/application/index.ts +4 -6
  200. package/src/application/spaces/space.hook.ts +5 -6
  201. package/src/application/spaces/spaces.hook.ts +14 -9
  202. package/src/auth/act-as.context.tsx +37 -91
  203. package/src/auth/auth.hook.ts +2 -30
  204. package/src/auth/can.hook.ts +44 -135
  205. package/src/auth/index.ts +1 -0
  206. package/src/auth/self.hook.ts +2 -9
  207. package/src/auth/session-kernel.ts +6 -16
  208. package/src/components/astrale.tsx +40 -0
  209. package/src/components/boundaries.tsx +113 -0
  210. package/src/components/can.tsx +16 -0
  211. package/src/components/index.ts +13 -0
  212. package/src/graph/call/call.hook.ts +22 -27
  213. package/src/graph/call/stream.hook.ts +66 -143
  214. package/src/graph/graph.context.ts +6 -11
  215. package/src/graph/guards.error.ts +17 -55
  216. package/src/graph/index.ts +23 -17
  217. package/src/graph/memory/read/envelope.ts +40 -65
  218. package/src/graph/memory/read/idle.ts +5 -18
  219. package/src/graph/query-definition.hook.ts +270 -0
  220. package/src/graph/resource.ts +358 -0
  221. package/src/graph/store.ts +97 -0
  222. package/src/host/actions.hook.ts +165 -0
  223. package/src/host/components.tsx +29 -0
  224. package/src/host/index.ts +17 -0
  225. package/src/index.ts +131 -124
  226. package/src/intents/envelope.ts +7 -23
  227. package/src/intents/send-intent.hook.ts +24 -79
  228. package/src/navigation/adapters/adapter.ts +3 -0
  229. package/src/navigation/adapters/memory.adapter.ts +4 -0
  230. package/src/navigation/adapters/url.adapter.ts +48 -8
  231. package/src/navigation/codec.ts +190 -0
  232. package/src/navigation/history.ts +20 -11
  233. package/src/navigation/hooks/ancestors.hook.ts +10 -60
  234. package/src/navigation/hooks/location.hook.ts +4 -6
  235. package/src/navigation/hooks/scope.hook.ts +4 -6
  236. package/src/navigation/index.ts +18 -2
  237. package/src/navigation/link.tsx +27 -2
  238. package/src/navigation/location.ts +26 -93
  239. package/src/navigation/scope.context.tsx +151 -136
  240. package/src/navigation/snapshot.ts +69 -50
  241. package/src/schema/action.hook.ts +146 -0
  242. package/src/schema/domain.hook.ts +127 -11
  243. package/src/schema/index.ts +9 -30
  244. package/src/schema/kernel.hook.ts +6 -13
  245. package/src/schema/mutation.hook.ts +63 -0
  246. package/src/schema/object.hook.ts +85 -0
  247. package/src/schema/relation.hook.ts +253 -0
  248. package/src/selection/live.ts +75 -125
  249. package/src/selection/scope.context.tsx +4 -4
  250. package/src/session/boot/boot.ts +8 -33
  251. package/src/session/index.ts +1 -0
  252. package/src/session/kernel-instance.hook.ts +2 -11
  253. package/src/session/provider.tsx +34 -103
  254. package/src/session/session.context.ts +6 -0
  255. package/src/window/adopt.ts +0 -1
  256. package/src/window/hooks/target-node.hook.ts +20 -85
  257. package/src/window/hooks/views-for.hook.ts +12 -25
  258. package/src/window/hooks/windows.hook.ts +3 -4
  259. package/src/window/host.tsx +35 -77
  260. package/src/window/hub.ts +33 -0
  261. package/src/window/index.ts +3 -3
  262. package/src/window/lifecycle/mount.ts +15 -160
  263. package/src/window/lifecycle/states.ts +1 -5
  264. package/dist/application/roles.hook.d.ts +0 -7
  265. package/dist/application/roles.hook.d.ts.map +0 -1
  266. package/dist/application/roles.hook.js +0 -23
  267. package/dist/graph/memory/base.d.ts +0 -21
  268. package/dist/graph/memory/base.d.ts.map +0 -1
  269. package/dist/graph/memory/base.js +0 -33
  270. package/dist/graph/memory/read/read.d.ts +0 -9
  271. package/dist/graph/memory/read/read.d.ts.map +0 -1
  272. package/dist/graph/memory/read/read.js +0 -87
  273. package/dist/graph/memory/scope.d.ts +0 -7
  274. package/dist/graph/memory/scope.d.ts.map +0 -1
  275. package/dist/graph/memory/scope.js +0 -25
  276. package/dist/graph/mutate/move.hook.d.ts +0 -7
  277. package/dist/graph/mutate/move.hook.d.ts.map +0 -1
  278. package/dist/graph/mutate/move.hook.js +0 -49
  279. package/dist/graph/mutate/mutate.hook.d.ts +0 -17
  280. package/dist/graph/mutate/mutate.hook.d.ts.map +0 -1
  281. package/dist/graph/mutate/mutate.hook.js +0 -45
  282. package/dist/graph/query/children.hook.d.ts +0 -29
  283. package/dist/graph/query/children.hook.d.ts.map +0 -1
  284. package/dist/graph/query/children.hook.js +0 -64
  285. package/dist/graph/query/graph.hook.d.ts +0 -9
  286. package/dist/graph/query/graph.hook.d.ts.map +0 -1
  287. package/dist/graph/query/graph.hook.js +0 -5
  288. package/dist/graph/query/neighbors.hook.d.ts +0 -7
  289. package/dist/graph/query/neighbors.hook.d.ts.map +0 -1
  290. package/dist/graph/query/neighbors.hook.js +0 -104
  291. package/dist/graph/query/node.hook.d.ts +0 -14
  292. package/dist/graph/query/node.hook.d.ts.map +0 -1
  293. package/dist/graph/query/node.hook.js +0 -43
  294. package/dist/graph/query/query.hook.d.ts +0 -14
  295. package/dist/graph/query/query.hook.d.ts.map +0 -1
  296. package/dist/graph/query/query.hook.js +0 -23
  297. package/dist/schema/bind-read.d.ts +0 -37
  298. package/dist/schema/bind-read.d.ts.map +0 -1
  299. package/dist/schema/bind-read.js +0 -205
  300. package/dist/schema/binding.d.ts +0 -21
  301. package/dist/schema/binding.d.ts.map +0 -1
  302. package/dist/schema/binding.js +0 -99
  303. package/dist/schema/function.hook.d.ts +0 -9
  304. package/dist/schema/function.hook.d.ts.map +0 -1
  305. package/dist/schema/function.hook.js +0 -40
  306. package/dist/schema/method.hook.d.ts +0 -14
  307. package/dist/schema/method.hook.d.ts.map +0 -1
  308. package/dist/schema/method.hook.js +0 -49
  309. package/dist/schema/tag.d.ts +0 -11
  310. package/dist/schema/tag.d.ts.map +0 -1
  311. package/dist/schema/tag.js +0 -11
  312. package/dist/schema/types.d.ts +0 -73
  313. package/dist/schema/types.d.ts.map +0 -1
  314. package/dist/schema/types.js +0 -1
  315. package/dist/schema/write.d.ts +0 -16
  316. package/dist/schema/write.d.ts.map +0 -1
  317. package/dist/schema/write.js +0 -56
  318. package/src/application/roles.hook.ts +0 -41
  319. package/src/graph/memory/base.ts +0 -50
  320. package/src/graph/memory/read/read.ts +0 -103
  321. package/src/graph/memory/scope.ts +0 -29
  322. package/src/graph/mutate/move.hook.ts +0 -70
  323. package/src/graph/mutate/mutate.hook.ts +0 -69
  324. package/src/graph/query/children.hook.ts +0 -136
  325. package/src/graph/query/graph.hook.ts +0 -13
  326. package/src/graph/query/neighbors.hook.ts +0 -159
  327. package/src/graph/query/node.hook.ts +0 -83
  328. package/src/graph/query/query.hook.ts +0 -42
  329. package/src/schema/bind-read.ts +0 -319
  330. package/src/schema/binding.ts +0 -146
  331. package/src/schema/function.hook.ts +0 -68
  332. package/src/schema/method.hook.ts +0 -103
  333. package/src/schema/tag.ts +0 -19
  334. package/src/schema/types.ts +0 -150
  335. package/src/schema/write.ts +0 -96
@@ -0,0 +1,146 @@
1
+ import type {
2
+ InputOf,
3
+ InstanceMethod,
4
+ OutputOf,
5
+ ReceiverOf,
6
+ RemoteCallableOf,
7
+ } from '@astrale-os/sdk/domain'
8
+ import type { NodeId } from '@astrale-os/sdk/graph/node'
9
+ 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
+
13
+ import { Path } from '@astrale-os/sdk/graph/path'
14
+ import { useCallback, useMemo, useRef } from 'react'
15
+
16
+ import type { Action as AsyncAction } from '../graph/action.js'
17
+
18
+ import { useAction as useAsyncAction } from '../graph/action.js'
19
+ import { useGraphStore } from '../graph/store.js'
20
+ import { bindingFor } from './domain.hook.js'
21
+
22
+ type Callable = RemoteCallableOf<schema.DomainSchema> | InstanceMethod
23
+
24
+ const QUERY_REFRESH = Symbol('shell-react.query-refresh')
25
+
26
+ export interface QueryRefresh {
27
+ readonly id: string
28
+ readonly [QUERY_REFRESH]: () => {
29
+ readonly ast: QueryAST
30
+ readonly page: Readonly<{ readonly size: number }>
31
+ }
32
+ }
33
+
34
+ type RefreshableQuery<Input, Query extends QueryAST> = {
35
+ readonly id: string
36
+ readonly page: Readonly<{ readonly size: number }>
37
+ prepare?(input: Input): Input
38
+ build(input: Input): Query
39
+ }
40
+
41
+ /** Pair one exact named Query definition with its admitted input for targeted invalidation. */
42
+ export function queryRefresh<Input, Query extends QueryAST>(
43
+ definition: RefreshableQuery<Input, Query>,
44
+ input: Input,
45
+ ): QueryRefresh {
46
+ return Object.freeze({
47
+ id: definition.id,
48
+ [QUERY_REFRESH]: () => {
49
+ const prepared = definition.prepare?.(input) ?? input
50
+ return Object.freeze({ ast: definition.build(prepared), page: definition.page })
51
+ },
52
+ })
53
+ }
54
+
55
+ export type ActionRefresh =
56
+ | 'all'
57
+ | 'none'
58
+ | {
59
+ readonly queries: readonly QueryRefresh[]
60
+ }
61
+
62
+ export interface ActionOptions extends DomainInvokeOptions {
63
+ readonly refresh?: ActionRefresh
64
+ readonly onError?: (error: unknown) => void
65
+ }
66
+
67
+ type ActionArgs<C extends Callable> = C extends InstanceMethod
68
+ ? [receiver: ReceiverOf<C>, input: InputOf<C>]
69
+ : [input: InputOf<C>]
70
+
71
+ export interface DomainAction<Args extends unknown[], Result> {
72
+ run(...args: Args): Promise<Result>
73
+ readonly pending: boolean
74
+ readonly error: unknown
75
+ readonly result: Result | undefined
76
+ reset(): void
77
+ }
78
+
79
+ /** Invoke one schema-declared Function or Method and invalidate Store by explicit policy. */
80
+ export function useAction<C extends Callable>(
81
+ callable: C,
82
+ options: ActionOptions = {},
83
+ ): DomainAction<ActionArgs<C>, OutputOf<C>> {
84
+ const binding = bindingFor(callable)
85
+ const store = useGraphStore()
86
+ const callableRef = useRef(callable)
87
+ callableRef.current = callable
88
+ const bindingRef = useRef(binding)
89
+ bindingRef.current = binding
90
+ const optionsRef = useRef(options)
91
+ optionsRef.current = options
92
+
93
+ const invoke = useCallback(
94
+ async (...args: ActionArgs<C>): Promise<OutputOf<C>> => {
95
+ const current = callableRef.current
96
+ const policy = optionsRef.current
97
+ const { refresh: _refresh, onError: _onError, ...request } = policy
98
+ 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)
106
+ const refresh = policy.refresh ?? 'all'
107
+ if (refresh === 'all') store.invalidate()
108
+ else if (refresh !== 'none') {
109
+ refresh.queries.forEach((query) => {
110
+ const target = query[QUERY_REFRESH]()
111
+ store.invalidate(target.ast, { page: target.page })
112
+ })
113
+ }
114
+ return result
115
+ } catch (error) {
116
+ policy.onError?.(error)
117
+ throw error
118
+ }
119
+ },
120
+ [store],
121
+ )
122
+ const action = useAsyncAction(invoke as (...args: ActionArgs<C>) => Promise<OutputOf<C>>)
123
+ return useMemo(() => projectAction(action), [action])
124
+ }
125
+
126
+ function projectAction<Args extends unknown[], Result>(
127
+ action: AsyncAction<Args, Result>,
128
+ ): DomainAction<Args, Result> {
129
+ return {
130
+ run: (...args) => action(...args),
131
+ get pending() {
132
+ return action.pending
133
+ },
134
+ get error() {
135
+ return action.error
136
+ },
137
+ get result() {
138
+ return action.result
139
+ },
140
+ reset: action.reset,
141
+ }
142
+ }
143
+
144
+ function receiverPath(receiver: { readonly id: NodeId }): string {
145
+ return Path.id(receiver.id).raw
146
+ }
@@ -1,16 +1,132 @@
1
+ import type { DomainBinding, KernelClient } from '@astrale-os/shell'
2
+
3
+ import { schema } from '@astrale-os/sdk/schema'
4
+
5
+ import { useSessionKernel } from '../auth/session-kernel.js'
6
+
7
+ type Resource<T> =
8
+ | { readonly status: 'pending'; readonly promise: Promise<void> }
9
+ | { readonly status: 'ready'; readonly value: T }
10
+ | { readonly status: 'failed'; readonly error: unknown }
11
+
12
+ const typed = new WeakMap<KernelClient, WeakMap<object, Resource<DomainBinding>>>()
13
+ const dynamic = new WeakMap<KernelClient, Resource<DomainBinding>>()
14
+ const aggregates = new WeakMap<
15
+ KernelClient,
16
+ Map<string, Resource<Readonly<Record<string, DomainBinding>>>>
17
+ >()
18
+ const bindingByValue = new WeakMap<object, DomainBinding>()
19
+
1
20
  /**
2
- * useDomain(schema) (API §6) — the typed domain binding, `kernel.withSchema(schema)`,
3
- * memoized per (effective session, schema). The BoundNodes it mints ride the
4
- * shared scoped memory, so typed writes are optimistic and revalidate (§6).
21
+ * Resolve an exact verified DomainBinding. The first render suspends while Session snapshot and schema
22
+ * revision checks complete; later renders return the retained binding synchronously.
5
23
  */
6
- import type { FnMap, SchemaBoundView } from '@astrale-os/kernel-client'
7
- import type { Schema } from '@astrale-os/kernel-dsl'
24
+ export function useDomain<const S extends schema.DomainSchema>(schema: S): DomainBinding<S> {
25
+ const kernel = useSessionKernel()
26
+ let bySchema = typed.get(kernel)
27
+ if (bySchema === undefined) {
28
+ bySchema = new WeakMap()
29
+ typed.set(kernel, bySchema)
30
+ }
31
+ let resource = bySchema.get(schema)
32
+ if (resource === undefined) {
33
+ resource = createResource(kernel.domain(schema)) as Resource<DomainBinding>
34
+ bySchema.set(schema, resource)
35
+ }
36
+ const binding = read(resource) as unknown as DomainBinding<S>
37
+ registerBinding(binding as unknown as DomainBinding)
38
+ return binding
39
+ }
8
40
 
9
- import { useSessionKernel } from '../auth/session-kernel.js'
10
- import { useMemory } from '../graph/memory/scope.js'
11
- import { bindingFor } from './binding.js'
41
+ /** Dynamic verified root binding used by tools that intentionally do not carry a schema witness. */
42
+ export function useDynamicDomain(): DomainBinding {
43
+ const kernel = useSessionKernel()
44
+ let resource = dynamic.get(kernel)
45
+ if (resource === undefined) {
46
+ resource = createResource(kernel.domain())
47
+ dynamic.set(kernel, resource)
48
+ }
49
+ const binding = read(resource)
50
+ registerBinding(binding)
51
+ return binding
52
+ }
53
+
54
+ /** Bind several exact installed schemas behind one Suspense boundary and stable named result. */
55
+ export function useDomains<const Schemas extends Readonly<Record<string, schema.DomainSchema>>>(
56
+ schemas: Schemas,
57
+ ): { readonly [Name in keyof Schemas]: DomainBinding<Schemas[Name]> } {
58
+ const kernel = useSessionKernel()
59
+ const names = Object.keys(schemas).sort()
60
+ if (names.length === 0) return Object.freeze({}) as never
61
+ const key = names
62
+ .map((name) => `${name}\u0000${schemas[name]!.origin}\u0000${schema.revision(schemas[name]!)}`)
63
+ .join('\u0001')
64
+ let bySet = aggregates.get(kernel)
65
+ if (bySet === undefined) {
66
+ bySet = new Map()
67
+ aggregates.set(kernel, bySet)
68
+ }
69
+ let resource = bySet.get(key)
70
+ if (resource === undefined) {
71
+ resource = createResource(
72
+ Promise.all(
73
+ names.map(async (name) => [name, await kernel.domain(schemas[name]!)] as const),
74
+ ).then((entries) => Object.freeze(Object.fromEntries(entries))),
75
+ )
76
+ bySet.set(key, resource)
77
+ }
78
+ const values = read(resource)
79
+ Object.values(values).forEach(registerBinding)
80
+ return values as { readonly [Name in keyof Schemas]: DomainBinding<Schemas[Name]> }
81
+ }
82
+
83
+ export function bindingFor(value: object): DomainBinding {
84
+ const binding = bindingByValue.get(value)
85
+ if (binding === undefined) {
86
+ throw new Error('The definition is not owned by a Domain bound in this React runtime.')
87
+ }
88
+ return binding
89
+ }
90
+
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
+ }
101
+ }
102
+ visit(binding, 0)
103
+ }
104
+
105
+ function createResource<T>(promise: Promise<T>): Resource<T> {
106
+ const cell: {
107
+ status: 'pending' | 'ready' | 'failed'
108
+ promise: Promise<void>
109
+ value?: T
110
+ error?: unknown
111
+ } = {
112
+ status: 'pending',
113
+ promise: Promise.resolve(),
114
+ }
115
+ cell.promise = promise.then(
116
+ (value) => {
117
+ cell.status = 'ready'
118
+ cell.value = value
119
+ },
120
+ (error: unknown) => {
121
+ cell.status = 'failed'
122
+ cell.error = error
123
+ },
124
+ )
125
+ return cell as Resource<T>
126
+ }
12
127
 
13
- /** The typed domain binding — `kernel.withSchema(schema)`, memoized per (session, schema). */
14
- export function useDomain<S extends Schema>(schema: S): SchemaBoundView<S, FnMap> {
15
- return bindingFor(useSessionKernel(), schema, useMemory())
128
+ function read<T>(resource: Resource<T>): T {
129
+ if (resource.status === 'pending') throw resource.promise
130
+ if (resource.status === 'failed') throw resource.error
131
+ return resource.value
16
132
  }
@@ -1,31 +1,10 @@
1
- // schema — the typing substrate (API §6). Typed kernel/domain bindings, typed
2
- // reads, method/function dispatch. See SHELL_REACT_API.md.
3
1
  export { useKernel } from './kernel.hook.js'
4
- export { useDomain } from './domain.hook.js'
5
- export {
6
- useNode,
7
- useChildren,
8
- useBoundNode,
9
- useBoundNodes,
10
- useBoundEndpoints,
11
- } from './bind-read.js'
12
- export { useOut, useIn } from '../graph/query/neighbors.hook.js'
13
- export { useMethod } from './method.hook.js'
14
- export type { MethodOptions } from './method.hook.js'
15
- export { useFunction } from './function.hook.js'
16
- export type { FunctionOptions } from './function.hook.js'
17
- export type {
18
- AutoMethodAction,
19
- BoundMethodAction,
20
- EndpointResult,
21
- FunctionNames,
22
- FunctionParams,
23
- FunctionResult,
24
- MethodIsStatic,
25
- MethodNames,
26
- MethodParams,
27
- MethodResult,
28
- TargetedMethodAction,
29
- TypedChildrenResult,
30
- TypedNodeResult,
31
- } from './types.js'
2
+ export { useDomain, useDomains, useDynamicDomain } from './domain.hook.js'
3
+ export { queryRefresh, useAction } from './action.hook.js'
4
+ export type { ActionOptions, ActionRefresh, DomainAction, QueryRefresh } from './action.hook.js'
5
+ export { useMutation } from './mutation.hook.js'
6
+ export type { MutationOptions } from './mutation.hook.js'
7
+ export { useDynamicObject, useObject } from './object.hook.js'
8
+ export type { RichReadOptions } from './object.hook.js'
9
+ export { RelationUnavailableError, useRelation } from './relation.hook.js'
10
+ export type { RelationOptions, RelationResource, RelationUnavailable } from './relation.hook.js'
@@ -1,17 +1,10 @@
1
- /**
2
- * useKernel (API §6) — the typed kernel, `kernel.withSchema(KernelSchema)`,
3
- * memoized per (effective) session. The kernel's own schema baked in; dispatch
4
- * and reads run as the subtree's principal over its scoped memory (§4).
5
- */
6
- import type { FnMap, SchemaBoundView } from '@astrale-os/kernel-client'
1
+ import type { DomainBinding } from '@astrale-os/shell'
7
2
 
8
- import { KernelSchema } from '@astrale-os/kernel-core'
3
+ import { KernelSchema } from '@astrale-os/sdk/schema/kernel'
9
4
 
10
- import { useSessionKernel } from '../auth/session-kernel.js'
11
- import { useMemory } from '../graph/memory/scope.js'
12
- import { bindingFor } from './binding.js'
5
+ import { useDomain } from './domain.hook.js'
13
6
 
14
- /** The typed kernel — `kernel.withSchema(KernelSchema)`, memoized (§4-scoped). */
15
- export function useKernel(): SchemaBoundView<typeof KernelSchema, FnMap> {
16
- return bindingFor(useSessionKernel(), KernelSchema, useMemory())
7
+ /** The verified, exactly typed Kernel Domain binding. */
8
+ export function useKernel(): DomainBinding<typeof KernelSchema> {
9
+ return useDomain(KernelSchema)
17
10
  }
@@ -0,0 +1,63 @@
1
+ import type { MutationDefinition } from '@astrale-os/sdk/mutation'
2
+
3
+ import { bindMutations } from '@astrale-os/sdk/mutation'
4
+ import { useCallback, useMemo, useRef } from 'react'
5
+
6
+ import type { Action as AsyncAction } from '../graph/action.js'
7
+ import type { DomainAction } from './action.hook.js'
8
+
9
+ import { useAction as useAsyncAction } from '../graph/action.js'
10
+ import { useGraphStore } from '../graph/store.js'
11
+
12
+ export interface MutationOptions {
13
+ readonly optimistic?: boolean
14
+ readonly onError?: (error: unknown) => void
15
+ }
16
+
17
+ /** Execute one named SDK Mutation definition through GraphStore optimism/invalidation. */
18
+ export function useMutation<Input, Output>(
19
+ definition: MutationDefinition<Input, Output>,
20
+ options: MutationOptions = {},
21
+ ): DomainAction<[Input], Output> {
22
+ const store = useGraphStore()
23
+ const definitionRef = useRef(definition)
24
+ definitionRef.current = definition
25
+ const optionsRef = useRef(options)
26
+ optionsRef.current = options
27
+ const run = useCallback(
28
+ async (input: Input): Promise<Output> => {
29
+ const execute = bindMutations((ast) =>
30
+ store.mutate(ast, {
31
+ optimistic: optionsRef.current.optimistic ?? true,
32
+ }),
33
+ )
34
+ try {
35
+ return await execute(definitionRef.current, input)
36
+ } catch (error) {
37
+ optionsRef.current.onError?.(error)
38
+ throw error
39
+ }
40
+ },
41
+ [store],
42
+ )
43
+ const action = useAsyncAction(run)
44
+ return useMemo(() => project(action), [action])
45
+ }
46
+
47
+ function project<Input, Output>(
48
+ action: AsyncAction<[Input], Output>,
49
+ ): DomainAction<[Input], Output> {
50
+ return {
51
+ run: (input) => action(input),
52
+ get pending() {
53
+ return action.pending
54
+ },
55
+ get error() {
56
+ return action.error
57
+ },
58
+ get result() {
59
+ return action.result
60
+ },
61
+ reset: action.reset,
62
+ }
63
+ }
@@ -0,0 +1,85 @@
1
+ import type { StoreQueryResponse } from '@astrale-os/kernel-client/store'
2
+ import type { BoundInstanceOf, Definition } from '@astrale-os/sdk/domain'
3
+ import type { Node } from '@astrale-os/sdk/graph/node'
4
+ import type { PathLike } from '@astrale-os/sdk/graph/path'
5
+
6
+ import { Path } from '@astrale-os/sdk/graph/path'
7
+ import { Query } from '@astrale-os/sdk/query'
8
+ import { useCallback, useMemo } from 'react'
9
+
10
+ import type { GraphResource } from '../graph/resource.js'
11
+
12
+ import { useStoreResource } from '../graph/resource.js'
13
+ import { bindingFor } from './domain.hook.js'
14
+
15
+ export interface RichReadOptions {
16
+ readonly pageSize?: number
17
+ }
18
+
19
+ type ObjectDefinition = Pick<
20
+ Definition<'class' | 'interface'>,
21
+ 'kind' | 'origin' | 'name' | 'key' | 'schemaRef' | 'definition'
22
+ > & { readonly family: 'node' }
23
+
24
+ /** Read and bind one exact rich object definition exclusively through GraphStore. */
25
+ export function useObject<RichDefinition extends ObjectDefinition>(
26
+ definition: RichDefinition,
27
+ target: PathLike | null | undefined,
28
+ options: RichReadOptions = {},
29
+ ): GraphResource<BoundInstanceOf<RichDefinition> | null> {
30
+ const binding = bindingFor(definition)
31
+ const path = target === null || target === undefined ? null : Path.from(target)
32
+ const query = useMemo(
33
+ () =>
34
+ path === null
35
+ ? null
36
+ : Query.from({ kind: 'node', paths: [path], binding: 'object' })
37
+ .filter({ satisfies: definition.schemaRef })
38
+ .select({ kind: 'graph' }),
39
+ [definition, path?.raw],
40
+ )
41
+ const project = useCallback(
42
+ (response: StoreQueryResponse<NonNullable<typeof query>>) => {
43
+ const result = response.result
44
+ if (result.kind !== 'graph' || result.selection.kind !== 'node') return null
45
+ const id = result.selection.ids[0]
46
+ const node =
47
+ id === undefined
48
+ ? undefined
49
+ : 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)
55
+ },
56
+ [binding, definition],
57
+ )
58
+ return useStoreResource(query, options.pageSize ?? 1, project)
59
+ }
60
+
61
+ /** Explicitly untyped point read for inspectors; it never impersonates `useObject`. */
62
+ export function useDynamicObject(
63
+ target: PathLike | null | undefined,
64
+ options: RichReadOptions = {},
65
+ ): GraphResource<Node | null> {
66
+ const path = target === null || target === undefined ? null : Path.from(target)
67
+ const query = useMemo(
68
+ () =>
69
+ path === null
70
+ ? null
71
+ : Query.from({ kind: 'node', paths: [path], binding: 'dynamic_object' }).select({
72
+ kind: 'graph',
73
+ }),
74
+ [path?.raw],
75
+ )
76
+ const project = useCallback((response: StoreQueryResponse<NonNullable<typeof query>>) => {
77
+ const result = response.result
78
+ if (result.kind !== 'graph' || result.selection.kind !== 'node') return null
79
+ const id = result.selection.ids[0]
80
+ return id === undefined
81
+ ? null
82
+ : (result.graph.nodes.find((candidate) => candidate.id === id) ?? null)
83
+ }, [])
84
+ return useStoreResource(query, options.pageSize ?? 1, project)
85
+ }