@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,40 @@
1
+ import type { Shell, ShellConfig } from '@astrale-os/shell'
2
+ import type { ReactElement, ReactNode } from 'react'
3
+
4
+ import { Suspense } from 'react'
5
+
6
+ import type { ShellProviderProps } from '../session/provider.js'
7
+
8
+ import { ShellProvider } from '../session/provider.js'
9
+ import { ViewStage } from '../window/stage.js'
10
+ import { defaultViewError, defaultViewLoading, ViewErrorBoundary } from './boundaries.js'
11
+
12
+ const SANDBOXED_SHELL = Object.freeze({ mode: 'sandboxed' as const })
13
+
14
+ export interface AstraleProps {
15
+ /** Defaults to the child-side sandbox handshake; pass a Shell for an embedded host or test. */
16
+ readonly config?: ShellConfig | Shell
17
+ readonly fallback?: ReactNode
18
+ readonly errorFallback?: ShellProviderProps['errorFallback']
19
+ readonly onError?: (error: unknown) => void
20
+ readonly children: ReactNode
21
+ }
22
+
23
+ /** Complete Astrale runtime root without taking ownership of application routing. */
24
+ export function Astrale(props: AstraleProps): ReactElement {
25
+ const loading = props.fallback ?? defaultViewLoading()
26
+ const errorFallback = props.errorFallback ?? defaultViewError
27
+ return (
28
+ <ShellProvider
29
+ config={props.config ?? SANDBOXED_SHELL}
30
+ fallback={loading}
31
+ errorFallback={errorFallback}
32
+ onError={({ error }) => props.onError?.(error)}
33
+ >
34
+ <ViewErrorBoundary fallback={errorFallback} onError={props.onError}>
35
+ <Suspense fallback={loading}>{props.children}</Suspense>
36
+ </ViewErrorBoundary>
37
+ <ViewStage />
38
+ </ShellProvider>
39
+ )
40
+ }
@@ -0,0 +1,113 @@
1
+ import type { CredentialSnapshot } from '@astrale-os/shell'
2
+ import type { ReactElement, ReactNode } from 'react'
3
+
4
+ import { Component, Fragment } from 'react'
5
+
6
+ import type { GraphResource } from '../graph/resource.js'
7
+
8
+ import { useConnection } from '../session/connection/connection.hook.js'
9
+
10
+ export function ViewBoundary<T>(props: {
11
+ readonly resource: GraphResource<T>
12
+ readonly children: (value: T) => ReactNode
13
+ readonly loading?: ReactNode
14
+ readonly empty?: ReactNode
15
+ readonly error?: (error: unknown) => ReactNode
16
+ }): ReactElement {
17
+ const { resource } = props
18
+ if (resource.state === 'failed') {
19
+ if (props.error !== undefined) return <>{props.error(resource.error)}</>
20
+ throw resource.error
21
+ }
22
+ if (resource.data === undefined) return <>{props.loading ?? null}</>
23
+ if (resource.data === null) return <>{props.empty ?? null}</>
24
+ return <>{props.children(resource.data)}</>
25
+ }
26
+
27
+ export const GraphBoundary = ViewBoundary
28
+
29
+ export interface ViewErrorBoundaryProps {
30
+ /** A render function receives the retry generation and can recreate rejected lazy resources. */
31
+ readonly children: ReactNode | ((generation: number) => ReactNode)
32
+ readonly fallback?: (error: unknown, retry: () => void) => ReactNode
33
+ readonly onError?: (error: unknown) => void
34
+ }
35
+
36
+ /** Catch Shell View render/lazy failures and remount the failed subtree on explicit retry. */
37
+ export class ViewErrorBoundary extends Component<
38
+ ViewErrorBoundaryProps,
39
+ { readonly error: unknown; readonly generation: number }
40
+ > {
41
+ override state = { error: undefined as unknown, generation: 0 }
42
+
43
+ static getDerivedStateFromError(error: unknown) {
44
+ return { error }
45
+ }
46
+
47
+ override componentDidCatch(error: unknown): void {
48
+ this.props.onError?.(error)
49
+ }
50
+
51
+ private readonly retry = (): void => {
52
+ this.setState((state) => ({ error: undefined, generation: state.generation + 1 }))
53
+ }
54
+
55
+ override render(): ReactNode {
56
+ if (this.state.error !== undefined) {
57
+ return (
58
+ this.props.fallback?.(this.state.error, this.retry) ??
59
+ defaultViewError(this.state.error, this.retry)
60
+ )
61
+ }
62
+ const content =
63
+ typeof this.props.children === 'function'
64
+ ? this.props.children(this.state.generation)
65
+ : this.props.children
66
+ return <Fragment key={this.state.generation}>{content}</Fragment>
67
+ }
68
+ }
69
+
70
+ export function defaultViewLoading(): ReactElement {
71
+ return (
72
+ <div role="status" aria-live="polite">
73
+ Loading view…
74
+ </div>
75
+ )
76
+ }
77
+
78
+ export function defaultViewError(_error: unknown, retry: () => void): ReactElement {
79
+ return (
80
+ <section role="alert">
81
+ <p>View could not load.</p>
82
+ <button type="button" onClick={retry}>
83
+ Retry
84
+ </button>
85
+ </section>
86
+ )
87
+ }
88
+
89
+ export function ConnectionBoundary(props: {
90
+ readonly children: ReactNode
91
+ readonly fallback?: (status: ReturnType<typeof useConnection>) => ReactNode
92
+ }): ReactElement {
93
+ const connection = useConnection()
94
+ return connection.status === 'ready' ? (
95
+ <>{props.children}</>
96
+ ) : (
97
+ <>{props.fallback?.(connection) ?? null}</>
98
+ )
99
+ }
100
+
101
+ export function CredentialBoundary(props: {
102
+ readonly credential: CredentialSnapshot
103
+ readonly children: ReactNode
104
+ readonly fallback?: (credential: CredentialSnapshot) => ReactNode
105
+ }): ReactElement {
106
+ return props.credential.state === 'valid' ||
107
+ props.credential.state === 'refreshing' ||
108
+ props.credential.state === 'degraded' ? (
109
+ <>{props.children}</>
110
+ ) : (
111
+ <>{props.fallback?.(props.credential) ?? null}</>
112
+ )
113
+ }
@@ -0,0 +1,16 @@
1
+ import type { PathLike } from '@astrale-os/sdk/graph/path'
2
+ import type { schema } from '@astrale-os/sdk/schema'
3
+ import type { ReactElement, ReactNode } from 'react'
4
+
5
+ import type { PolicyObject } from '../auth/can.hook.js'
6
+
7
+ import { useCan } from '../auth/can.hook.js'
8
+
9
+ export function Can(props: {
10
+ readonly policy: PathLike | schema.PolicyRef
11
+ readonly object: PolicyObject
12
+ readonly children: ReactNode
13
+ readonly fallback?: ReactNode
14
+ }): ReactElement {
15
+ return <>{useCan(props.policy, props.object) === true ? props.children : props.fallback}</>
16
+ }
@@ -0,0 +1,13 @@
1
+ export { Can } from './can.js'
2
+ export {
3
+ ConnectionBoundary,
4
+ CredentialBoundary,
5
+ defaultViewError,
6
+ defaultViewLoading,
7
+ GraphBoundary,
8
+ ViewErrorBoundary,
9
+ ViewBoundary,
10
+ } from './boundaries.js'
11
+ export type { ViewErrorBoundaryProps } from './boundaries.js'
12
+ export { Astrale } from './astrale.js'
13
+ export type { AstraleProps } from './astrale.js'
@@ -1,41 +1,36 @@
1
- /**
2
- * useCall (API §7) — unary domain-function dispatch over `kernel.call`, in the
3
- * Action envelope. No result caching, no liveness — domain function reads are not
4
- * structurally invalidatable (FRONTEND §5.7); a consumer that needs freshness
5
- * owns its own refetch policy. Dispatch is a graph operation (rule 2).
6
- */
7
- import type { CallFns, FnMap } from '@astrale-os/kernel-client'
1
+ import type { Call } from '@astrale-os/kernel-client'
2
+ import type { SessionRequestOptions } from '@astrale-os/kernel-client/session'
3
+ import type { Value } from '@astrale-os/sdk/value'
8
4
 
9
5
  import type { Action } from '../action.js'
10
6
 
11
7
  import { useSessionKernel } from '../../auth/session-kernel.js'
12
8
  import { useAction } from '../action.js'
13
9
 
14
- export interface CallOptions {
15
- /** Per-call timeout (ms), forwarded to the kernel dispatch. */
16
- timeout?: number
17
- /** Side-channel notified on rejection (the Action also records `.error`). */
18
- onError?(error: unknown): void
10
+ export interface CallOptions extends SessionRequestOptions {
11
+ readonly onError?: (error: unknown) => void
19
12
  }
20
13
 
21
- /**
22
- * Unary domain-function dispatch as an {@link Action}. `method` is a typed FnMap
23
- * `call` path or any string (the untyped floor); `null` yields an idle action
24
- * that rejects if invoked. Params/result are typed from the FnMap entry.
25
- */
26
- export function useCall<K extends CallFns<FnMap>>(
27
- method: K | null,
28
- opts?: CallOptions,
29
- ): Action<[FnMap[K]['params']], FnMap[K]['result']> {
14
+ export type CallResult = Value
15
+ type CallAuthor<A extends unknown[]> = Call | ((...args: A) => Call)
16
+
17
+ export function useCall(call: Call | null, options?: CallOptions): Action<[], CallResult>
18
+ export function useCall<A extends unknown[]>(
19
+ author: ((...args: A) => Call) | null,
20
+ options?: CallOptions,
21
+ ): Action<A, CallResult>
22
+ export function useCall<A extends unknown[]>(
23
+ author: CallAuthor<A> | null,
24
+ options?: CallOptions,
25
+ ): Action<A, CallResult> {
30
26
  const kernel = useSessionKernel()
31
- // A fresh closure per render captures the current method/opts; `useAction`
32
- // keeps ONE stable callable and always dispatches this latest closure.
33
- return useAction(async (params: FnMap[K]['params']): Promise<FnMap[K]['result']> => {
34
- if (method === null) throw new Error('useCall: method is null (idle action invoked)')
27
+ return useAction(async (...args: A) => {
28
+ if (author === null) throw new Error('useCall: idle action invoked')
29
+ const call = typeof author === 'function' ? author(...args) : author
35
30
  try {
36
- return await kernel.call(method, params, { timeout: opts?.timeout })
31
+ return await kernel.call(call, options)
37
32
  } catch (error) {
38
- opts?.onError?.(error)
33
+ options?.onError?.(error)
39
34
  throw error
40
35
  }
41
36
  })
@@ -1,57 +1,44 @@
1
- import type { FnMap, StreamFns } from '@astrale-os/kernel-client'
1
+ import type { Call } from '@astrale-os/kernel-client'
2
+ import type { SessionRequestOptions } from '@astrale-os/kernel-client/session'
3
+ import type { Value } from '@astrale-os/sdk/value'
4
+ import type { KernelClient } from '@astrale-os/shell'
2
5
 
3
- /**
4
- * useStream (API §7) — streaming domain-function dispatch over `kernel.stream`,
5
- * an AsyncIterable driven by an explicit start/cancel handle. A superseding
6
- * `start` (or unmount) closes the prior run and discards its late chunks/errors;
7
- * never live. Dispatch is a graph operation (rule 2).
8
- */
9
6
  import { useCallback, useEffect, useReducer, useRef } from 'react'
10
7
 
11
8
  import { useSessionKernel } from '../../auth/session-kernel.js'
12
9
 
13
- export interface StreamOptions<T> {
14
- /** Notified per chunk as it arrives (in addition to `chunks` accumulation). */
15
- onChunk?(chunk: T): void
10
+ export type KernelStream = Awaited<ReturnType<KernelClient['stream']>>
11
+ export type StreamItem = Value
12
+ export type CallAuthor<A extends unknown[]> = Call | ((...args: A) => Call)
13
+
14
+ export interface StreamOptions<T = StreamItem> extends SessionRequestOptions {
15
+ readonly onChunk?: (chunk: T) => void
16
16
  }
17
17
 
18
- export interface StreamHandle<T> {
19
- /** Begin a run: resets chunks, then resolves when the stream ends / rejects on failure. */
20
- start(params: unknown): Promise<void>
21
- /** Chunks accumulated in the current run; reset on the next `start`. */
18
+ export interface StreamHandle<A extends unknown[] = unknown[], T = StreamItem> {
19
+ start(...args: A): Promise<void>
22
20
  readonly chunks: readonly T[]
23
- /** The most recent chunk, or null before the first. */
24
21
  readonly last: T | null
25
- /** A run is in flight. */
26
22
  readonly streaming: boolean
27
- /** Last run failure; retained until the next `start`. */
28
23
  readonly error: unknown
29
- /** Close the stream (returns the iterator); a later `start` begins fresh. */
30
24
  cancel(): void
31
25
  }
32
26
 
33
- interface StreamSnapshot<T> {
27
+ interface Snapshot<T> {
34
28
  readonly chunks: readonly T[]
35
29
  readonly last: T | null
36
30
  readonly streaming: boolean
37
31
  readonly error: unknown
38
32
  }
39
33
 
40
- const IDLE_STREAM: StreamSnapshot<unknown> = {
41
- chunks: [],
42
- last: null,
43
- streaming: false,
44
- error: undefined,
45
- }
46
-
47
- type StreamEvent<T> =
34
+ type Event<T> =
48
35
  | { readonly type: 'start' }
49
36
  | { readonly type: 'chunk'; readonly value: T }
50
37
  | { readonly type: 'end' }
51
38
  | { readonly type: 'error'; readonly error: unknown }
52
39
  | { readonly type: 'cancel' }
53
40
 
54
- function streamReducer<T>(state: StreamSnapshot<T>, event: StreamEvent<T>): StreamSnapshot<T> {
41
+ function reducer<T>(state: Snapshot<T>, event: Event<T>): Snapshot<T> {
55
42
  switch (event.type) {
56
43
  case 'start':
57
44
  return { chunks: [], last: null, streaming: true, error: undefined }
@@ -63,138 +50,74 @@ function streamReducer<T>(state: StreamSnapshot<T>, event: StreamEvent<T>): Stre
63
50
  error: undefined,
64
51
  }
65
52
  case 'end':
53
+ case 'cancel':
66
54
  return { ...state, streaming: false }
67
55
  case 'error':
68
- // Chunks accumulated before the failure are preserved.
69
56
  return { ...state, streaming: false, error: event.error }
70
- case 'cancel':
71
- return { ...state, streaming: false }
72
57
  }
73
58
  }
74
59
 
75
- /** Same shape, minus `readonly`, so the render step can re-stamp the snapshot. */
76
- interface MutableStreamHandle<T> {
77
- start(params: unknown): Promise<void>
78
- chunks: readonly T[]
79
- last: T | null
80
- streaming: boolean
81
- error: unknown
82
- cancel(): void
83
- }
84
-
85
- interface StreamRun<T> {
86
- readonly controller: AbortController
87
- iterator: AsyncIterator<T> | null
88
- }
89
-
90
- /**
91
- * Streaming domain-function dispatch. `start(params)` opens a run over
92
- * `kernel.stream`; chunks accumulate on `chunks`; `cancel()` closes the iterator
93
- * and a later `start` begins fresh. A superseding `start` (or unmount) closes the
94
- * prior run and discards its late chunks/errors — only the current run drives
95
- * state. Never live; the handle keeps one identity for the hook's lifetime.
96
- */
97
- export function useStream<K extends StreamFns<FnMap>>(
98
- method: K | null,
99
- opts?: StreamOptions<FnMap[K]['result']>,
100
- ): StreamHandle<FnMap[K]['result']> {
101
- type T = FnMap[K]['result']
60
+ export function useStream<A extends unknown[] = []>(
61
+ author: CallAuthor<A> | null,
62
+ options?: StreamOptions,
63
+ ): StreamHandle<A, StreamItem> {
102
64
  const kernel = useSessionKernel()
103
-
104
- // Latest-closure refs so the stable start/cancel dispatch the current inputs.
105
65
  const kernelRef = useRef(kernel)
106
66
  kernelRef.current = kernel
107
- const methodRef = useRef(method)
108
- methodRef.current = method
109
- const optsRef = useRef(opts)
110
- optsRef.current = opts
111
-
112
- const [snapshot, dispatch] = useReducer(streamReducer<T>, IDLE_STREAM as StreamSnapshot<T>)
113
-
114
- // `runId` supersession token; only the run whose id is still current drives state.
115
- const runIdRef = useRef(0)
116
- const currentRef = useRef<StreamRun<T> | null>(null)
117
- const alive = useRef(true)
67
+ const authorRef = useRef(author)
68
+ authorRef.current = author
69
+ const optionsRef = useRef(options)
70
+ optionsRef.current = options
71
+ const [snapshot, dispatch] = useReducer(reducer<StreamItem>, {
72
+ chunks: [],
73
+ last: null,
74
+ streaming: false,
75
+ error: undefined,
76
+ })
77
+ const runId = useRef(0)
78
+ const controller = useRef<AbortController | null>(null)
118
79
 
119
- const stop = useCallback(() => {
120
- const run = currentRef.current
121
- if (run !== null) {
122
- run.controller.abort()
123
- void run.iterator?.return?.(undefined)
124
- currentRef.current = null
125
- }
80
+ const cancel = useCallback(() => {
81
+ runId.current += 1
82
+ controller.current?.abort()
83
+ controller.current = null
84
+ dispatch({ type: 'cancel' })
126
85
  }, [])
127
86
 
128
- useEffect(() => {
129
- alive.current = true
130
- return () => {
131
- alive.current = false
132
- stop()
133
- }
134
- }, [stop])
135
-
136
- const cancel = useCallback(() => {
137
- runIdRef.current += 1
138
- stop()
139
- if (alive.current) dispatch({ type: 'cancel' })
140
- }, [stop])
87
+ useEffect(() => cancel, [cancel])
141
88
 
142
89
  const start = useCallback(
143
- (params: unknown): Promise<void> => {
144
- const method_ = methodRef.current
145
- if (method_ === null) {
146
- return Promise.reject(new Error('useStream: method is null (idle handle started)'))
147
- }
148
- runIdRef.current += 1
149
- const runId = runIdRef.current
150
- stop() // close any prior run before opening the new one
90
+ async (...args: A): Promise<void> => {
91
+ const current = authorRef.current
92
+ if (current === null) throw new Error('useStream: idle handle started')
93
+ cancel()
94
+ const id = ++runId.current
95
+ const abort = new AbortController()
96
+ controller.current = abort
151
97
  dispatch({ type: 'start' })
152
-
153
- const controller = new AbortController()
154
- const run: StreamRun<T> = { controller, iterator: null }
155
- currentRef.current = run
156
- const current = (): boolean => runIdRef.current === runId
157
-
158
- return (async () => {
159
- try {
160
- const iterable = await kernelRef.current.stream(method_, params, {
161
- signal: controller.signal,
162
- })
163
- if (!current()) return
164
- const iterator = iterable[Symbol.asyncIterator]()
165
- run.iterator = iterator
166
- for (;;) {
167
- const next = await iterator.next()
168
- if (!current()) return
169
- if (next.done === true) break
170
- if (alive.current) dispatch({ type: 'chunk', value: next.value })
171
- optsRef.current?.onChunk?.(next.value)
172
- }
173
- if (current()) {
174
- currentRef.current = null
175
- if (alive.current) dispatch({ type: 'end' })
176
- }
177
- } catch (error) {
178
- if (!current()) return // a superseded/cancelled run's failure is discarded
179
- currentRef.current = null
180
- if (alive.current) dispatch({ type: 'error', error })
181
- throw error
98
+ const call = typeof current === 'function' ? current(...args) : current
99
+ try {
100
+ const { onChunk: _onChunk, ...requestOptions } = optionsRef.current ?? {}
101
+ const stream = await kernelRef.current.stream(call, {
102
+ ...requestOptions,
103
+ signal: abort.signal,
104
+ })
105
+ for await (const chunk of stream) {
106
+ if (id !== runId.current) return
107
+ dispatch({ type: 'chunk', value: chunk })
108
+ optionsRef.current?.onChunk?.(chunk)
182
109
  }
183
- })()
110
+ if (id === runId.current) dispatch({ type: 'end' })
111
+ } catch (error) {
112
+ if (id !== runId.current) return
113
+ dispatch({ type: 'error', error })
114
+ throw error
115
+ } finally {
116
+ if (id === runId.current) controller.current = null
117
+ }
184
118
  },
185
- [stop],
119
+ [cancel],
186
120
  )
187
121
 
188
- // One render-stable handle: built once (start/cancel are stable), then its
189
- // snapshot fields re-stamped each render so reads stay current across chunks.
190
- const handleRef = useRef<MutableStreamHandle<T> | null>(null)
191
- if (handleRef.current === null) {
192
- handleRef.current = { start, cancel } as MutableStreamHandle<T>
193
- }
194
- const handle = handleRef.current
195
- handle.chunks = snapshot.chunks
196
- handle.last = snapshot.last
197
- handle.streaming = snapshot.streaming
198
- handle.error = snapshot.error
199
- return handle as StreamHandle<T>
122
+ return { start, cancel, ...snapshot }
200
123
  }
@@ -1,14 +1,9 @@
1
- import type { GraphMemory } from '@astrale-os/kernel-client/store'
1
+ import type { GraphStore } from '@astrale-os/kernel-client/store'
2
2
 
3
- /**
4
- * GraphContext (ex MemoryContext) — the root of the graph plane. Seats the base
5
- * (default-scope) memory the provider builds; the SAME handle the graph/schema/
6
- * nav hooks read through `memory/scope.ts`, and selection's liveness source.
7
- * Under `<ActAs>` the read hooks re-scope via `forScope`; selection reads the
8
- * base scope here.
9
- */
10
3
  import { createContext } from 'react'
11
4
 
12
- export type { GraphMemory }
13
- export const GraphContext = createContext<GraphMemory | null>(null)
14
- GraphContext.displayName = 'AstraleGraphContext'
5
+ /** Optional exact Client GraphStore supplied by an injected Shell adapter. */
6
+ export const GraphContext = createContext<GraphStore | null>(null)
7
+ GraphContext.displayName = 'AstraleGraphStoreContext'
8
+
9
+ export type { GraphStore }
@@ -1,58 +1,20 @@
1
- /**
2
- * Error taxonomy (API §1.4) — re-exported from kernel-client so shell-react
3
- * consumers narrow dispatch failures through the single import surface. The
4
- * dispatched kernel call stays the source of truth; these guards drive UI
5
- * affordances (retry, request-access, toast). Names match kernel-client exactly.
6
- */
7
1
  export {
8
- AuthBatchError,
9
- AuthenticationError,
10
- ClientSessionError,
11
- ConnectionError,
12
- DisconnectedError,
13
- InvalidTransportError,
14
- InvariantViolationError,
15
- KernelError,
16
- NodeUnavailableError,
17
- NotFoundError,
18
- PermissionDeniedError,
19
- TimeoutError,
20
- UnsupportedTransportError,
21
- ValidationError,
22
- WebOSError,
23
- classifyKernelError,
24
- isAuthBatchError,
25
- isAuthenticationError,
26
- isClientSessionError,
27
- isDelegationMintError,
28
- isDelegationPolicyError,
29
- isDelegationRefusedError,
30
- isHopLimitExceededError,
31
- isIdentityError,
32
- isInternalKernelError,
33
- isInvalidRequestError,
34
- isInvalidTransportError,
35
- isInvariantViolationError,
36
- isKernelError,
37
- isNodeUnavailableError,
38
- isNotFoundError,
39
- isParseError,
40
- isPermissionDeniedError,
41
- isPersistenceLoadFailedError,
42
- isPoolClosedError,
43
- isRedirectPolicyError,
44
- isRedirectRefusedError,
45
- isRegistryWriteFailedError,
46
- isSchemaOwnershipConflictError,
47
- isTransportError,
48
- isUnsupportedTransportError,
49
- isValidationError,
50
- isWebOSError,
51
- } from '@astrale-os/kernel-client'
52
- export type {
53
- AuthReason,
54
- ClientErrorDetails,
55
- IdentityError,
56
- KernelErrorKind,
2
+ ClientError,
3
+ ProtocolError,
4
+ ResponseError,
5
+ StaleRouteError,
57
6
  TransportError,
58
7
  } from '@astrale-os/kernel-client'
8
+ export { NodeUnavailableError } from '@astrale-os/kernel-client/graph'
9
+ export { UnsupportedFeatureError } from './memory/read/envelope.js'
10
+
11
+ import { ClientError } from '@astrale-os/kernel-client'
12
+ import { NodeUnavailableError } from '@astrale-os/kernel-client/graph'
13
+
14
+ export function isClientError(error: unknown): error is ClientError {
15
+ return error instanceof ClientError
16
+ }
17
+
18
+ export function isNodeUnavailableError(error: unknown): error is NodeUnavailableError {
19
+ return error instanceof NodeUnavailableError
20
+ }
@@ -1,20 +1,26 @@
1
- // graph — the graph plane (API §5 + §7). Merged read hooks, writes, dispatch.
2
- export { useNode } from './query/node.hook.js'
3
- export type { NodeResult } from './query/node.hook.js'
4
- export { useChildren } from './query/children.hook.js'
5
- export type { ChildrenOptions, ChildrenResult } from './query/children.hook.js'
6
- export { useQuery } from './query/query.hook.js'
7
- export type { QueryResult } from './query/query.hook.js'
8
- export { useGraph } from './query/graph.hook.js'
9
- export { useMutate } from './mutate/mutate.hook.js'
10
- export type { UseMutateOptions } from './mutate/mutate.hook.js'
11
- export { useMove } from './mutate/move.hook.js'
12
- export type { MoveAction } from './mutate/move.hook.js'
1
+ export { useGraphStore } from './store.js'
2
+ export { useQuery } from './query-definition.hook.js'
3
+ export type { QueryResourceOptions } from './query-definition.hook.js'
4
+ export type { GraphResource, GraphResourceState } from './resource.js'
13
5
  export { useCall } from './call/call.hook.js'
14
- export type { CallOptions } from './call/call.hook.js'
6
+ export type { CallOptions, CallResult } from './call/call.hook.js'
15
7
  export { useStream } from './call/stream.hook.js'
16
- export type { StreamHandle, StreamOptions } from './call/stream.hook.js'
8
+ export type {
9
+ CallAuthor,
10
+ KernelStream,
11
+ StreamHandle,
12
+ StreamItem,
13
+ StreamOptions,
14
+ } from './call/stream.hook.js'
17
15
  export type { Action } from './action.js'
18
- export type { ReadState, ReadOptions, Windowed, Node } from './memory/read/envelope.js'
19
- export type { GraphMemory } from './graph.context.js'
20
- export type { ShapeInput } from '@astrale-os/kernel-client/store'
16
+ export type { GraphStore } from './graph.context.js'
17
+ export {
18
+ ClientError,
19
+ NodeUnavailableError,
20
+ ProtocolError,
21
+ ResponseError,
22
+ StaleRouteError,
23
+ TransportError,
24
+ isClientError,
25
+ isNodeUnavailableError,
26
+ } from './guards.error.js'