@astrale-os/shell-react 0.2.8 → 0.2.10-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/dist/application/apps/app-host.d.ts +7 -15
  2. package/dist/application/apps/app-host.d.ts.map +1 -1
  3. package/dist/application/apps/app-host.js +3 -2
  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/boundaries.d.ts +47 -0
  39. package/dist/components/boundaries.d.ts.map +1 -0
  40. package/dist/components/boundaries.js +55 -0
  41. package/dist/components/can.d.ts +11 -0
  42. package/dist/components/can.d.ts.map +1 -0
  43. package/dist/components/can.js +5 -0
  44. package/dist/components/index.d.ts +7 -0
  45. package/dist/components/index.d.ts.map +1 -0
  46. package/dist/components/index.js +4 -0
  47. package/dist/components/mount-domain-frontend.d.ts +22 -0
  48. package/dist/components/mount-domain-frontend.d.ts.map +1 -0
  49. package/dist/components/mount-domain-frontend.js +85 -0
  50. package/dist/components/view-app.d.ts +16 -0
  51. package/dist/components/view-app.d.ts.map +1 -0
  52. package/dist/components/view-app.js +16 -0
  53. package/dist/graph/call/call.hook.d.ts +8 -18
  54. package/dist/graph/call/call.hook.d.ts.map +1 -1
  55. package/dist/graph/call/call.hook.js +7 -13
  56. package/dist/graph/call/stream.hook.d.ts +12 -20
  57. package/dist/graph/call/stream.hook.d.ts.map +1 -1
  58. package/dist/graph/call/stream.hook.js +55 -111
  59. package/dist/graph/graph.context.d.ts +4 -3
  60. package/dist/graph/graph.context.d.ts.map +1 -1
  61. package/dist/graph/graph.context.js +2 -8
  62. package/dist/graph/guards.error.d.ts +7 -8
  63. package/dist/graph/guards.error.d.ts.map +1 -1
  64. package/dist/graph/guards.error.js +11 -7
  65. package/dist/graph/index.d.ts +8 -16
  66. package/dist/graph/index.d.ts.map +1 -1
  67. package/dist/graph/index.js +3 -7
  68. package/dist/graph/memory/read/envelope.d.ts +22 -54
  69. package/dist/graph/memory/read/envelope.d.ts.map +1 -1
  70. package/dist/graph/memory/read/envelope.js +26 -20
  71. package/dist/graph/memory/read/idle.d.ts +1 -15
  72. package/dist/graph/memory/read/idle.d.ts.map +1 -1
  73. package/dist/graph/memory/read/idle.js +4 -13
  74. package/dist/graph/query-definition.hook.d.ts +11 -0
  75. package/dist/graph/query-definition.hook.d.ts.map +1 -0
  76. package/dist/graph/query-definition.hook.js +205 -0
  77. package/dist/graph/resource.d.ts +34 -0
  78. package/dist/graph/resource.d.ts.map +1 -0
  79. package/dist/graph/resource.js +244 -0
  80. package/dist/graph/store.d.ts +25 -0
  81. package/dist/graph/store.d.ts.map +1 -0
  82. package/dist/graph/store.js +69 -0
  83. package/dist/host/actions.hook.d.ts +34 -0
  84. package/dist/host/actions.hook.d.ts.map +1 -0
  85. package/dist/host/actions.hook.js +125 -0
  86. package/dist/host/components.d.ts +15 -0
  87. package/dist/host/components.d.ts.map +1 -0
  88. package/dist/host/components.js +14 -0
  89. package/dist/host/index.d.ts +5 -0
  90. package/dist/host/index.d.ts.map +1 -0
  91. package/dist/host/index.js +3 -0
  92. package/dist/index.d.ts +26 -37
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +20 -31
  95. package/dist/intents/envelope.d.ts +7 -19
  96. package/dist/intents/envelope.d.ts.map +1 -1
  97. package/dist/intents/envelope.js +2 -3
  98. package/dist/intents/send-intent.hook.d.ts +5 -7
  99. package/dist/intents/send-intent.hook.d.ts.map +1 -1
  100. package/dist/intents/send-intent.hook.js +17 -75
  101. package/dist/navigation/adapters/adapter.d.ts +5 -0
  102. package/dist/navigation/adapters/adapter.d.ts.map +1 -1
  103. package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -1
  104. package/dist/navigation/adapters/memory.adapter.js +4 -0
  105. package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
  106. package/dist/navigation/adapters/url.adapter.js +57 -10
  107. package/dist/navigation/codec.d.ts +60 -0
  108. package/dist/navigation/codec.d.ts.map +1 -0
  109. package/dist/navigation/codec.js +121 -0
  110. package/dist/navigation/history.d.ts +11 -9
  111. package/dist/navigation/history.d.ts.map +1 -1
  112. package/dist/navigation/history.js +6 -8
  113. package/dist/navigation/hooks/ancestors.hook.d.ts +5 -7
  114. package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -1
  115. package/dist/navigation/hooks/ancestors.hook.js +7 -51
  116. package/dist/navigation/hooks/location.hook.d.ts.map +1 -1
  117. package/dist/navigation/hooks/location.hook.js +4 -6
  118. package/dist/navigation/hooks/scope.hook.d.ts.map +1 -1
  119. package/dist/navigation/hooks/scope.hook.js +4 -6
  120. package/dist/navigation/index.d.ts +4 -2
  121. package/dist/navigation/index.d.ts.map +1 -1
  122. package/dist/navigation/index.js +2 -1
  123. package/dist/navigation/link.d.ts +12 -0
  124. package/dist/navigation/link.d.ts.map +1 -1
  125. package/dist/navigation/link.js +13 -2
  126. package/dist/navigation/location.d.ts +13 -40
  127. package/dist/navigation/location.d.ts.map +1 -1
  128. package/dist/navigation/location.js +14 -76
  129. package/dist/navigation/scope.context.d.ts +17 -26
  130. package/dist/navigation/scope.context.d.ts.map +1 -1
  131. package/dist/navigation/scope.context.js +140 -108
  132. package/dist/navigation/snapshot.d.ts +14 -19
  133. package/dist/navigation/snapshot.d.ts.map +1 -1
  134. package/dist/navigation/snapshot.js +48 -44
  135. package/dist/schema/action.hook.d.ts +44 -0
  136. package/dist/schema/action.hook.d.ts.map +1 -0
  137. package/dist/schema/action.hook.js +72 -0
  138. package/dist/schema/domain.hook.d.ts +12 -7
  139. package/dist/schema/domain.hook.d.ts.map +1 -1
  140. package/dist/schema/domain.hook.js +101 -4
  141. package/dist/schema/index.d.ts +9 -8
  142. package/dist/schema/index.d.ts.map +1 -1
  143. package/dist/schema/index.js +5 -7
  144. package/dist/schema/kernel.hook.d.ts +4 -9
  145. package/dist/schema/kernel.hook.d.ts.map +1 -1
  146. package/dist/schema/kernel.hook.js +4 -6
  147. package/dist/schema/mutation.hook.d.ts +9 -0
  148. package/dist/schema/mutation.hook.d.ts.map +1 -0
  149. package/dist/schema/mutation.hook.js +41 -0
  150. package/dist/schema/object.hook.d.ts +16 -0
  151. package/dist/schema/object.hook.d.ts.map +1 -0
  152. package/dist/schema/object.hook.js +46 -0
  153. package/dist/schema/relation.hook.d.ts +46 -0
  154. package/dist/schema/relation.hook.d.ts.map +1 -0
  155. package/dist/schema/relation.hook.js +136 -0
  156. package/dist/selection/live.d.ts +9 -17
  157. package/dist/selection/live.d.ts.map +1 -1
  158. package/dist/selection/live.js +65 -112
  159. package/dist/selection/scope.context.js +5 -4
  160. package/dist/session/boot/boot.d.ts +1 -13
  161. package/dist/session/boot/boot.d.ts.map +1 -1
  162. package/dist/session/boot/boot.js +9 -27
  163. package/dist/session/index.d.ts +1 -0
  164. package/dist/session/index.d.ts.map +1 -1
  165. package/dist/session/kernel-instance.hook.d.ts +1 -4
  166. package/dist/session/kernel-instance.hook.d.ts.map +1 -1
  167. package/dist/session/kernel-instance.hook.js +1 -5
  168. package/dist/session/provider.d.ts +9 -23
  169. package/dist/session/provider.d.ts.map +1 -1
  170. package/dist/session/provider.js +29 -75
  171. package/dist/session/session.context.d.ts +5 -0
  172. package/dist/session/session.context.d.ts.map +1 -1
  173. package/dist/window/adopt.d.ts +0 -1
  174. package/dist/window/adopt.d.ts.map +1 -1
  175. package/dist/window/hooks/target-node.hook.d.ts +10 -6
  176. package/dist/window/hooks/target-node.hook.d.ts.map +1 -1
  177. package/dist/window/hooks/target-node.hook.js +14 -72
  178. package/dist/window/hooks/views-for.hook.d.ts +4 -3
  179. package/dist/window/hooks/views-for.hook.d.ts.map +1 -1
  180. package/dist/window/hooks/views-for.hook.js +6 -22
  181. package/dist/window/hooks/windows.hook.d.ts.map +1 -1
  182. package/dist/window/hooks/windows.hook.js +3 -4
  183. package/dist/window/host.d.ts +11 -11
  184. package/dist/window/host.d.ts.map +1 -1
  185. package/dist/window/host.js +38 -54
  186. package/dist/window/hub.d.ts +2 -0
  187. package/dist/window/hub.d.ts.map +1 -1
  188. package/dist/window/hub.js +33 -0
  189. package/dist/window/index.d.ts +3 -3
  190. package/dist/window/index.d.ts.map +1 -1
  191. package/dist/window/index.js +2 -2
  192. package/dist/window/lifecycle/mount.d.ts +5 -44
  193. package/dist/window/lifecycle/mount.d.ts.map +1 -1
  194. package/dist/window/lifecycle/mount.js +14 -120
  195. package/dist/window/lifecycle/states.d.ts +0 -5
  196. package/dist/window/lifecycle/states.d.ts.map +1 -1
  197. package/dist/window/stage.d.ts.map +1 -1
  198. package/dist/window/stage.js +1 -0
  199. package/package.json +9 -8
  200. package/src/application/apps/app-host.tsx +17 -18
  201. package/src/application/apps/apps.hook.ts +13 -6
  202. package/src/application/apps/domains.hook.ts +1 -1
  203. package/src/application/apps/open-app.hook.ts +3 -4
  204. package/src/application/index.ts +4 -6
  205. package/src/application/spaces/space.hook.ts +5 -6
  206. package/src/application/spaces/spaces.hook.ts +14 -9
  207. package/src/auth/act-as.context.tsx +37 -91
  208. package/src/auth/auth.hook.ts +2 -30
  209. package/src/auth/can.hook.ts +44 -135
  210. package/src/auth/index.ts +1 -0
  211. package/src/auth/self.hook.ts +2 -9
  212. package/src/auth/session-kernel.ts +6 -16
  213. package/src/components/boundaries.tsx +113 -0
  214. package/src/components/can.tsx +16 -0
  215. package/src/components/index.ts +14 -0
  216. package/src/components/mount-domain-frontend.tsx +158 -0
  217. package/src/components/view-app.tsx +49 -0
  218. package/src/graph/call/call.hook.ts +22 -27
  219. package/src/graph/call/stream.hook.ts +66 -143
  220. package/src/graph/graph.context.ts +6 -11
  221. package/src/graph/guards.error.ts +17 -55
  222. package/src/graph/index.ts +23 -17
  223. package/src/graph/memory/read/envelope.ts +40 -65
  224. package/src/graph/memory/read/idle.ts +5 -18
  225. package/src/graph/query-definition.hook.ts +270 -0
  226. package/src/graph/resource.ts +358 -0
  227. package/src/graph/store.ts +97 -0
  228. package/src/host/actions.hook.ts +165 -0
  229. package/src/host/components.tsx +29 -0
  230. package/src/host/index.ts +17 -0
  231. package/src/index.ts +137 -123
  232. package/src/intents/envelope.ts +7 -23
  233. package/src/intents/send-intent.hook.ts +24 -79
  234. package/src/navigation/adapters/adapter.ts +3 -0
  235. package/src/navigation/adapters/memory.adapter.ts +4 -0
  236. package/src/navigation/adapters/url.adapter.ts +48 -8
  237. package/src/navigation/codec.ts +190 -0
  238. package/src/navigation/history.ts +20 -11
  239. package/src/navigation/hooks/ancestors.hook.ts +10 -60
  240. package/src/navigation/hooks/location.hook.ts +4 -6
  241. package/src/navigation/hooks/scope.hook.ts +4 -6
  242. package/src/navigation/index.ts +18 -2
  243. package/src/navigation/link.tsx +27 -2
  244. package/src/navigation/location.ts +26 -93
  245. package/src/navigation/scope.context.tsx +151 -136
  246. package/src/navigation/snapshot.ts +69 -50
  247. package/src/schema/action.hook.ts +146 -0
  248. package/src/schema/domain.hook.ts +127 -11
  249. package/src/schema/index.ts +9 -30
  250. package/src/schema/kernel.hook.ts +6 -13
  251. package/src/schema/mutation.hook.ts +63 -0
  252. package/src/schema/object.hook.ts +85 -0
  253. package/src/schema/relation.hook.ts +253 -0
  254. package/src/selection/live.ts +75 -125
  255. package/src/selection/scope.context.tsx +4 -4
  256. package/src/session/boot/boot.ts +8 -33
  257. package/src/session/index.ts +1 -0
  258. package/src/session/kernel-instance.hook.ts +2 -11
  259. package/src/session/provider.tsx +34 -103
  260. package/src/session/session.context.ts +6 -0
  261. package/src/window/adopt.ts +0 -1
  262. package/src/window/hooks/target-node.hook.ts +20 -85
  263. package/src/window/hooks/views-for.hook.ts +12 -25
  264. package/src/window/hooks/windows.hook.ts +3 -4
  265. package/src/window/host.tsx +51 -68
  266. package/src/window/hub.ts +33 -0
  267. package/src/window/index.ts +4 -4
  268. package/src/window/lifecycle/mount.ts +15 -160
  269. package/src/window/lifecycle/states.ts +1 -5
  270. package/src/window/stage.tsx +1 -0
  271. package/dist/application/roles.hook.d.ts +0 -7
  272. package/dist/application/roles.hook.d.ts.map +0 -1
  273. package/dist/application/roles.hook.js +0 -23
  274. package/dist/graph/memory/base.d.ts +0 -21
  275. package/dist/graph/memory/base.d.ts.map +0 -1
  276. package/dist/graph/memory/base.js +0 -33
  277. package/dist/graph/memory/read/read.d.ts +0 -9
  278. package/dist/graph/memory/read/read.d.ts.map +0 -1
  279. package/dist/graph/memory/read/read.js +0 -87
  280. package/dist/graph/memory/scope.d.ts +0 -7
  281. package/dist/graph/memory/scope.d.ts.map +0 -1
  282. package/dist/graph/memory/scope.js +0 -25
  283. package/dist/graph/mutate/move.hook.d.ts +0 -7
  284. package/dist/graph/mutate/move.hook.d.ts.map +0 -1
  285. package/dist/graph/mutate/move.hook.js +0 -49
  286. package/dist/graph/mutate/mutate.hook.d.ts +0 -17
  287. package/dist/graph/mutate/mutate.hook.d.ts.map +0 -1
  288. package/dist/graph/mutate/mutate.hook.js +0 -45
  289. package/dist/graph/query/children.hook.d.ts +0 -29
  290. package/dist/graph/query/children.hook.d.ts.map +0 -1
  291. package/dist/graph/query/children.hook.js +0 -64
  292. package/dist/graph/query/graph.hook.d.ts +0 -9
  293. package/dist/graph/query/graph.hook.d.ts.map +0 -1
  294. package/dist/graph/query/graph.hook.js +0 -5
  295. package/dist/graph/query/neighbors.hook.d.ts +0 -7
  296. package/dist/graph/query/neighbors.hook.d.ts.map +0 -1
  297. package/dist/graph/query/neighbors.hook.js +0 -104
  298. package/dist/graph/query/node.hook.d.ts +0 -14
  299. package/dist/graph/query/node.hook.d.ts.map +0 -1
  300. package/dist/graph/query/node.hook.js +0 -43
  301. package/dist/graph/query/query.hook.d.ts +0 -14
  302. package/dist/graph/query/query.hook.d.ts.map +0 -1
  303. package/dist/graph/query/query.hook.js +0 -23
  304. package/dist/schema/bind-read.d.ts +0 -37
  305. package/dist/schema/bind-read.d.ts.map +0 -1
  306. package/dist/schema/bind-read.js +0 -205
  307. package/dist/schema/binding.d.ts +0 -21
  308. package/dist/schema/binding.d.ts.map +0 -1
  309. package/dist/schema/binding.js +0 -99
  310. package/dist/schema/function.hook.d.ts +0 -9
  311. package/dist/schema/function.hook.d.ts.map +0 -1
  312. package/dist/schema/function.hook.js +0 -40
  313. package/dist/schema/method.hook.d.ts +0 -14
  314. package/dist/schema/method.hook.d.ts.map +0 -1
  315. package/dist/schema/method.hook.js +0 -49
  316. package/dist/schema/tag.d.ts +0 -11
  317. package/dist/schema/tag.d.ts.map +0 -1
  318. package/dist/schema/tag.js +0 -11
  319. package/dist/schema/types.d.ts +0 -73
  320. package/dist/schema/types.d.ts.map +0 -1
  321. package/dist/schema/types.js +0 -1
  322. package/dist/schema/write.d.ts +0 -16
  323. package/dist/schema/write.d.ts.map +0 -1
  324. package/dist/schema/write.js +0 -56
  325. package/src/application/roles.hook.ts +0 -41
  326. package/src/graph/memory/base.ts +0 -50
  327. package/src/graph/memory/read/read.ts +0 -103
  328. package/src/graph/memory/scope.ts +0 -29
  329. package/src/graph/mutate/move.hook.ts +0 -70
  330. package/src/graph/mutate/mutate.hook.ts +0 -69
  331. package/src/graph/query/children.hook.ts +0 -136
  332. package/src/graph/query/graph.hook.ts +0 -13
  333. package/src/graph/query/neighbors.hook.ts +0 -159
  334. package/src/graph/query/node.hook.ts +0 -83
  335. package/src/graph/query/query.hook.ts +0 -42
  336. package/src/schema/bind-read.ts +0 -319
  337. package/src/schema/binding.ts +0 -146
  338. package/src/schema/function.hook.ts +0 -68
  339. package/src/schema/method.hook.ts +0 -103
  340. package/src/schema/tag.ts +0 -19
  341. package/src/schema/types.ts +0 -150
  342. package/src/schema/write.ts +0 -96
@@ -1,119 +1,44 @@
1
- import { rawOf } from '@astrale-os/kernel-client/graph';
1
+ import { Path } from '@astrale-os/sdk/graph/path';
2
+ import { useEffect, useState } from 'react';
3
+ import { useIdentityBinding } from './act-as.context.js';
2
4
  /**
3
- * useCan (API §4) — deduped standing-grant permission checks. `auth.check`-backed:
4
- * `undefined` while the first check is in flight (or `on` is idle), then a boolean.
5
- * Deduped per (principal, perms, nodeId) across the whole tree via the principal's
6
- * check ledger (folded in here as the dedup substrate). Standing-grant semantics:
7
- * the dispatched call remains the gatekeeper — this is a UI affordance, not the
8
- * enforcement point (SPEC §6.2). A local grant/revoke invalidates the ledger.
5
+ * Evaluate one declared Kernel policy for one exact graph object. This is a UI affordance; the
6
+ * invoked callable remains the authorization enforcement point.
9
7
  */
10
- import { useCallback, useMemo, useSyncExternalStore } from 'react';
11
- import { isIdleInput } from '../graph/memory/read/idle.js';
12
- import { useIdentityBinding } from './act-as.context.js';
13
- const NOOP_UNSUB = () => undefined;
14
- /** A node value carries the id/class/path triple (mirrors the memory's `isNodeValue`). */
15
- export function isNodeValue(x) {
16
- return typeof x === 'object' && x !== null && 'id' in x && 'class' in x && 'path' in x;
17
- }
18
- /** Normalize a `useCan` subject to a dispatchable `Ref` plus a stable dedup key. */
19
- export function toRef(on) {
20
- if (isNodeValue(on))
21
- return { ref: on.path, key: `@${on.id}` };
22
- return { ref: on, key: rawOf(on) };
23
- }
24
- // ── check ledger (the dedup substrate) ───────────────────────────────────────
25
- /** One deduped check — its last-known value plus the subscribers watching it. */
26
- class CheckCell {
27
- auth;
28
- perms;
29
- on;
30
- value = undefined;
31
- inFlight = false;
32
- listeners = new Set();
33
- constructor(auth, perms, on) {
34
- this.auth = auth;
35
- this.perms = perms;
36
- this.on = on;
37
- }
38
- subscribe = (onChange) => {
39
- this.listeners.add(onChange);
40
- this.ensure();
41
- return () => this.listeners.delete(onChange);
42
- };
43
- getSnapshot = () => this.value;
44
- /** Run the check once when the value is unknown and nothing is in flight. */
45
- ensure() {
46
- if (this.value !== undefined || this.inFlight)
47
- return;
48
- this.run();
49
- }
50
- /** Force a re-check (local grant/revoke on this principal). */
51
- invalidate() {
52
- if (this.listeners.size === 0) {
53
- this.value = undefined; // recompute lazily on the next subscribe
8
+ export function useCan(policy, object) {
9
+ const { kernel } = useIdentityBinding();
10
+ const objectId = objectIdOf(object);
11
+ const policyTarget = policyPath(policy);
12
+ const [decision, setDecision] = useState(undefined);
13
+ useEffect(() => {
14
+ if (policyTarget === null || objectId === null) {
15
+ setDecision(undefined);
54
16
  return;
55
17
  }
56
- this.run();
57
- }
58
- run() {
59
- this.inFlight = true;
60
- void this.auth
61
- .check({ on: this.on, perms: this.perms })
62
- .then((ok) => {
63
- this.value = ok;
18
+ let active = true;
19
+ setDecision(undefined);
20
+ void kernel.auth.can({ policy: policyTarget, object: objectId }).then((allowed) => {
21
+ if (active)
22
+ setDecision(allowed);
64
23
  }, () => {
65
- // A failed check leaves the value unknown (undefined) — never a false grant.
66
- this.value = undefined;
67
- })
68
- .finally(() => {
69
- this.inFlight = false;
70
- for (const l of this.listeners)
71
- l();
24
+ if (active)
25
+ setDecision(undefined);
72
26
  });
73
- }
74
- }
75
- /** Per-principal cell registry — dedup across the whole tree for one kernel handle. */
76
- export class CheckLedger {
77
- auth;
78
- cells = new Map();
79
- constructor(auth) {
80
- this.auth = auth;
81
- }
82
- cell(key, perms, on) {
83
- let cell = this.cells.get(key);
84
- if (cell === undefined) {
85
- cell = new CheckCell(this.auth, perms, on);
86
- this.cells.set(key, cell);
87
- }
88
- return cell;
89
- }
90
- /** Re-check every observed cell — conservative Tier-0 sweep after a local grant/revoke. */
91
- invalidateAll() {
92
- for (const cell of this.cells.values())
93
- cell.invalidate();
94
- }
27
+ return () => {
28
+ active = false;
29
+ };
30
+ }, [kernel, policyTarget, objectId]);
31
+ return decision;
95
32
  }
96
- // One ledger per bound kernel object → per principal. `session.as(cred)` mints a
97
- // fresh view per ActAs, so acted-as principals never share a ledger with the root.
98
- const ledgers = new WeakMap();
99
- export function ledgerFor(kernel) {
100
- let ledger = ledgers.get(kernel);
101
- if (ledger === undefined) {
102
- ledger = new CheckLedger(kernel.auth);
103
- ledgers.set(kernel, ledger);
104
- }
105
- return ledger;
33
+ function policyPath(policy) {
34
+ if (policy === null || policy === undefined)
35
+ return null;
36
+ return policy instanceof Path || typeof policy === 'string'
37
+ ? Path.from(policy).raw
38
+ : Path.project(policy).raw;
106
39
  }
107
- // ── useCan ────────────────────────────────────────────────────────────────────
108
- export function useCan(perms, on) {
109
- const binding = useIdentityBinding();
110
- const ref = isIdleInput(on) ? null : toRef(on);
111
- // The shared cell for (principal, perms, nodeId): identical to every other
112
- // useCan reading the same triple, so one check serves the whole tree.
113
- const cell = useMemo(() => ref === null ? null : ledgerFor(binding.kernel).cell(`${perms}\0${ref.key}`, perms, ref.ref),
114
- // ref is rebuilt per render; its `key` string is the stable identity.
115
- [binding.kernel, perms, ref?.key]);
116
- const subscribe = useCallback((onChange) => (cell === null ? NOOP_UNSUB : cell.subscribe(onChange)), [cell]);
117
- const getSnapshot = useCallback(() => cell?.getSnapshot(), [cell]);
118
- return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
40
+ function objectIdOf(value) {
41
+ if (value === null || value === undefined)
42
+ return null;
43
+ return typeof value === 'object' ? value.id : value;
119
44
  }
@@ -2,5 +2,6 @@ export { ActAs } from './act-as.context.js';
2
2
  export type { ActAsProps } from './act-as.context.js';
3
3
  export { useAuth } from './auth.hook.js';
4
4
  export { useCan } from './can.hook.js';
5
+ export type { PolicyObject } from './can.hook.js';
5
6
  export { useSelf } from './self.hook.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA"}
@@ -1,3 +1,3 @@
1
- import type { NodeValue } from './act-as.context.js';
2
- export declare function useSelf(): NodeValue;
1
+ import type { Identity } from '@astrale-os/kernel-client/auth';
2
+ export declare function useSelf(): Identity;
3
3
  //# sourceMappingURL=self.hook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"self.hook.d.ts","sourceRoot":"","sources":["../../src/auth/self.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAWpD,wBAAgB,OAAO,IAAI,SAAS,CAEnC"}
1
+ {"version":3,"file":"self.hook.d.ts","sourceRoot":"","sources":["../../src/auth/self.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAA;AAI9D,wBAAgB,OAAO,IAAI,QAAQ,CAElC"}
@@ -1,10 +1,3 @@
1
- /**
2
- * useSelf (API §4) — the caller's identity node, resolved at boot and read
3
- * synchronously (never suspends). An <ActAs> subtree returns the acted-as
4
- * identity. FLAG: today this is the boot-resolved whoami snapshot; it becomes a
5
- * live memory shape once the graph plane subscribes the self node — no signature
6
- * change.
7
- */
8
1
  import { useIdentityBinding } from './act-as.context.js';
9
2
  export function useSelf() {
10
3
  return useIdentityBinding().self;
@@ -1,4 +1,3 @@
1
- import type { SessionView } from './act-as.context.js';
2
- /** The EFFECTIVE dispatch kernel for this subtree. Throws outside a provider. */
3
- export declare function useSessionKernel(): SessionView;
1
+ import type { KernelClient } from '@astrale-os/shell';
2
+ export declare function useSessionKernel(): KernelClient;
4
3
  //# sourceMappingURL=session-kernel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-kernel.d.ts","sourceRoot":"","sources":["../../src/auth/session-kernel.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAKtD,iFAAiF;AACjF,wBAAgB,gBAAgB,IAAI,WAAW,CAQ9C"}
1
+ {"version":3,"file":"session-kernel.d.ts","sourceRoot":"","sources":["../../src/auth/session-kernel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAOrD,wBAAgB,gBAAgB,IAAI,YAAY,CAM/C"}
@@ -1,21 +1,12 @@
1
- /**
2
- * useSessionKernel (API §4) — the dispatch-floor resolver. Inside an `<ActAs>` it
3
- * is the acted-as principal's bound session view; otherwise the root
4
- * `shell.kernel`. Every dispatch floor (schema bindings, useCall/useStream, useMove,
5
- * typed method dispatch) routes through this so a call runs as the subtree's
6
- * principal — not the root — and its scoped memory.
7
- */
8
1
  import { useContext } from 'react';
9
2
  import { ShellContext } from '../session/session.context.js';
10
3
  import { IdentityContext } from './act-as.context.js';
11
- /** The EFFECTIVE dispatch kernel for this subtree. Throws outside a provider. */
12
4
  export function useSessionKernel() {
13
- const binding = useContext(IdentityContext);
5
+ const identity = useContext(IdentityContext);
14
6
  const runtime = useContext(ShellContext);
15
- if (binding !== null)
16
- return binding.kernel;
17
- if (runtime === null) {
7
+ if (identity !== null)
8
+ return identity.kernel;
9
+ if (runtime === null)
18
10
  throw new Error('session hooks must be used within a <ShellProvider>');
19
- }
20
11
  return runtime.shell.kernel;
21
12
  }
@@ -0,0 +1,47 @@
1
+ import type { CredentialSnapshot } from '@astrale-os/shell';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import { Component } from 'react';
4
+ import type { GraphResource } from '../graph/resource.js';
5
+ import { useConnection } from '../session/connection/connection.hook.js';
6
+ export declare function ViewBoundary<T>(props: {
7
+ readonly resource: GraphResource<T>;
8
+ readonly children: (value: T) => ReactNode;
9
+ readonly loading?: ReactNode;
10
+ readonly empty?: ReactNode;
11
+ readonly error?: (error: unknown) => ReactNode;
12
+ }): ReactElement;
13
+ export declare const GraphBoundary: typeof ViewBoundary;
14
+ export interface ViewErrorBoundaryProps {
15
+ /** A render function receives the retry generation and can recreate rejected lazy resources. */
16
+ readonly children: ReactNode | ((generation: number) => ReactNode);
17
+ readonly fallback?: (error: unknown, retry: () => void) => ReactNode;
18
+ readonly onError?: (error: unknown) => void;
19
+ }
20
+ /** Catch Shell View render/lazy failures and remount the failed subtree on explicit retry. */
21
+ export declare class ViewErrorBoundary extends Component<ViewErrorBoundaryProps, {
22
+ readonly error: unknown;
23
+ readonly generation: number;
24
+ }> {
25
+ state: {
26
+ error: unknown;
27
+ generation: number;
28
+ };
29
+ static getDerivedStateFromError(error: unknown): {
30
+ error: unknown;
31
+ };
32
+ componentDidCatch(error: unknown): void;
33
+ private readonly retry;
34
+ render(): ReactNode;
35
+ }
36
+ export declare function defaultViewLoading(): ReactElement;
37
+ export declare function defaultViewError(_error: unknown, retry: () => void): ReactElement;
38
+ export declare function ConnectionBoundary(props: {
39
+ readonly children: ReactNode;
40
+ readonly fallback?: (status: ReturnType<typeof useConnection>) => ReactNode;
41
+ }): ReactElement;
42
+ export declare function CredentialBoundary(props: {
43
+ readonly credential: CredentialSnapshot;
44
+ readonly children: ReactNode;
45
+ readonly fallback?: (credential: CredentialSnapshot) => ReactNode;
46
+ }): ReactElement;
47
+ //# sourceMappingURL=boundaries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundaries.d.ts","sourceRoot":"","sources":["../../src/components/boundaries.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,EAAE,SAAS,EAAY,MAAM,OAAO,CAAA;AAE3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAA;AAExE,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE;IACrC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,SAAS,CAAA;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,CAAA;CAC/C,GAAG,YAAY,CASf;AAED,eAAO,MAAM,aAAa,qBAAe,CAAA;AAEzC,MAAM,WAAW,sBAAsB;IACrC,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,CAAC,CAAA;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAA;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAED,8FAA8F;AAC9F,qBAAa,iBAAkB,SAAQ,SAAS,CAC9C,sBAAsB,EACtB;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CACzD;IACU,KAAK;QAAK,KAAK,EAAe,OAAO;QAAE,UAAU;MAAK;IAE/D,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO;;MAE7C;IAEQ,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/C;IAED,OAAO,CAAC,QAAQ,CAAC,KAAK,CAErB;IAEQ,MAAM,IAAI,SAAS,CAY3B;CACF;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAMjD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,YAAY,CASjF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,KAAK,SAAS,CAAA;CAC5E,GAAG,YAAY,CAOf;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,KAAK,SAAS,CAAA;CAClE,GAAG,YAAY,CAQf"}
@@ -0,0 +1,55 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Component, Fragment } from 'react';
3
+ import { useConnection } from '../session/connection/connection.hook.js';
4
+ export function ViewBoundary(props) {
5
+ const { resource } = props;
6
+ if (resource.state === 'failed') {
7
+ if (props.error !== undefined)
8
+ return _jsx(_Fragment, { children: props.error(resource.error) });
9
+ throw resource.error;
10
+ }
11
+ if (resource.data === undefined)
12
+ return _jsx(_Fragment, { children: props.loading ?? null });
13
+ if (resource.data === null)
14
+ return _jsx(_Fragment, { children: props.empty ?? null });
15
+ return _jsx(_Fragment, { children: props.children(resource.data) });
16
+ }
17
+ export const GraphBoundary = ViewBoundary;
18
+ /** Catch Shell View render/lazy failures and remount the failed subtree on explicit retry. */
19
+ export class ViewErrorBoundary extends Component {
20
+ state = { error: undefined, generation: 0 };
21
+ static getDerivedStateFromError(error) {
22
+ return { error };
23
+ }
24
+ componentDidCatch(error) {
25
+ this.props.onError?.(error);
26
+ }
27
+ retry = () => {
28
+ this.setState((state) => ({ error: undefined, generation: state.generation + 1 }));
29
+ };
30
+ render() {
31
+ if (this.state.error !== undefined) {
32
+ return (this.props.fallback?.(this.state.error, this.retry) ??
33
+ defaultViewError(this.state.error, this.retry));
34
+ }
35
+ const content = typeof this.props.children === 'function'
36
+ ? this.props.children(this.state.generation)
37
+ : this.props.children;
38
+ return _jsx(Fragment, { children: content }, this.state.generation);
39
+ }
40
+ }
41
+ export function defaultViewLoading() {
42
+ return (_jsx("div", { role: "status", "aria-live": "polite", children: "Loading view\u2026" }));
43
+ }
44
+ export function defaultViewError(_error, retry) {
45
+ return (_jsxs("section", { role: "alert", children: [_jsx("p", { children: "View could not load." }), _jsx("button", { type: "button", onClick: retry, children: "Retry" })] }));
46
+ }
47
+ export function ConnectionBoundary(props) {
48
+ const connection = useConnection();
49
+ return connection.status === 'ready' ? (_jsx(_Fragment, { children: props.children })) : (_jsx(_Fragment, { children: props.fallback?.(connection) ?? null }));
50
+ }
51
+ export function CredentialBoundary(props) {
52
+ return props.credential.state === 'valid' ||
53
+ props.credential.state === 'refreshing' ||
54
+ props.credential.state === 'degraded' ? (_jsx(_Fragment, { children: props.children })) : (_jsx(_Fragment, { children: props.fallback?.(props.credential) ?? null }));
55
+ }
@@ -0,0 +1,11 @@
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
+ import type { PolicyObject } from '../auth/can.hook.js';
5
+ export declare function Can(props: {
6
+ readonly policy: PathLike | schema.PolicyRef;
7
+ readonly object: PolicyObject;
8
+ readonly children: ReactNode;
9
+ readonly fallback?: ReactNode;
10
+ }): ReactElement;
11
+ //# sourceMappingURL=can.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"can.d.ts","sourceRoot":"","sources":["../../src/components/can.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAIvD,wBAAgB,GAAG,CAAC,KAAK,EAAE;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAA;IAC5C,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAC9B,GAAG,YAAY,CAEf"}
@@ -0,0 +1,5 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCan } from '../auth/can.hook.js';
3
+ export function Can(props) {
4
+ return _jsx(_Fragment, { children: useCan(props.policy, props.object) === true ? props.children : props.fallback });
5
+ }
@@ -0,0 +1,7 @@
1
+ export { Can } from './can.js';
2
+ export { ConnectionBoundary, CredentialBoundary, defaultViewError, defaultViewLoading, GraphBoundary, ViewErrorBoundary, ViewBoundary, } from './boundaries.js';
3
+ export type { ViewErrorBoundaryProps } from './boundaries.js';
4
+ export { ViewApp } from './view-app.js';
5
+ export { mountDomainFrontend } from './mount-domain-frontend.js';
6
+ export type { MountedDomainFrontend, MountDomainFrontendOptions } from './mount-domain-frontend.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,YAAY,GACb,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,YAAY,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { Can } from './can.js';
2
+ export { ConnectionBoundary, CredentialBoundary, defaultViewError, defaultViewLoading, GraphBoundary, ViewErrorBoundary, ViewBoundary, } from './boundaries.js';
3
+ export { ViewApp } from './view-app.js';
4
+ export { mountDomainFrontend } from './mount-domain-frontend.js';
@@ -0,0 +1,22 @@
1
+ import type { ReactRouteModule } from '@astrale-os/sdk/react';
2
+ import type { schema } from '@astrale-os/sdk/schema';
3
+ import type { Shell, ShellConfig } from '@astrale-os/shell';
4
+ import type { ReactNode } from 'react';
5
+ type ViewName<S extends schema.DomainSchema> = Extract<keyof ReactRouteModule<S>['routes'], string>;
6
+ export interface MountDomainFrontendOptions<S extends schema.DomainSchema, Name extends ViewName<S>> {
7
+ readonly root: Element | string;
8
+ readonly module: ReactRouteModule<S>;
9
+ readonly view: Name;
10
+ /** Defaults to the child-side sandbox handshake. A prebuilt Shell is the full-app escape hatch. */
11
+ readonly config?: ShellConfig | Shell;
12
+ readonly fallback?: ReactNode;
13
+ readonly errorFallback?: (error: unknown, retry: () => void) => ReactNode;
14
+ readonly onError?: (error: unknown) => void;
15
+ }
16
+ export interface MountedDomainFrontend {
17
+ unmount(): void;
18
+ }
19
+ /** Browser bootstrap used by SDK-generated route entries and custom full React apps alike. */
20
+ export declare function mountDomainFrontend<const S extends schema.DomainSchema, const Name extends ViewName<S>>(options: MountDomainFrontendOptions<S, Name>): MountedDomainFrontend;
21
+ export {};
22
+ //# sourceMappingURL=mount-domain-frontend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-domain-frontend.d.ts","sourceRoot":"","sources":["../../src/components/mount-domain-frontend.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAmC,MAAM,uBAAuB,CAAA;AAC9F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAoD,SAAS,EAAE,MAAM,OAAO,CAAA;AAWxF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,YAAY,IAAI,OAAO,CAAC,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;AAMnG,MAAM,WAAW,0BAA0B,CACzC,CAAC,SAAS,MAAM,CAAC,YAAY,EAC7B,IAAI,SAAS,QAAQ,CAAC,CAAC,CAAC;IAExB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,mGAAmG;IACnG,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,CAAA;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAA;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CACjC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,YAAY,EACnC,KAAK,CAAC,IAAI,SAAS,QAAQ,CAAC,CAAC,CAAC,EAC9B,OAAO,EAAE,0BAA0B,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,qBAAqB,CAgCrE"}
@@ -0,0 +1,85 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createElement, lazy, Suspense } from 'react';
3
+ import { createRoot } from 'react-dom/client';
4
+ import { useHistoryVersion, useOptionalNavCtx } from '../navigation/scope.context.js';
5
+ import { useDomain } from '../schema/domain.hook.js';
6
+ import { useTargetPath } from '../window/hooks/target-node.hook.js';
7
+ import { defaultViewError, defaultViewLoading, ViewErrorBoundary } from './boundaries.js';
8
+ import { ViewApp } from './view-app.js';
9
+ /** Browser bootstrap used by SDK-generated route entries and custom full React apps alike. */
10
+ export function mountDomainFrontend(options) {
11
+ const rootElement = typeof options.root === 'string' ? document.querySelector(options.root) : options.root;
12
+ if (rootElement === null)
13
+ throw new Error(`React frontend root '${options.root}' was not found.`);
14
+ const route = options.module.routes[options.view];
15
+ if (route === undefined)
16
+ throw new Error(`React View '${options.view}' is not implemented.`);
17
+ const loading = options.fallback ?? defaultViewLoading();
18
+ const errorFallback = options.errorFallback ?? defaultViewError;
19
+ const routeRuntime = createRouteRuntime();
20
+ const root = createRoot(rootElement);
21
+ root.render(_jsx(ViewApp, { config: options.config ?? { mode: 'sandboxed' }, fallback: loading, errorFallback: errorFallback, onError: ({ error }) => options.onError?.(error), children: _jsx(ViewErrorBoundary, { fallback: errorFallback, onError: options.onError, children: (generation) => (_jsx(Suspense, { fallback: loading, children: _jsx(DomainRoute, { module: options.module, name: options.view, generation: generation, runtime: routeRuntime }) })) }) }));
22
+ return Object.freeze({ unmount: () => root.unmount() });
23
+ }
24
+ function DomainRoute(props) {
25
+ const domain = useDomain(props.module.schema);
26
+ const navigation = useOptionalNavCtx();
27
+ useHistoryVersion(navigation?.history ?? null);
28
+ const view = domain[props.name];
29
+ // Domain's schema-indexed conditional retains the exact authored View type,
30
+ // while the runtime member has Core's common rich Definition shape.
31
+ const runtimeView = view;
32
+ const targetPath = useTargetPath();
33
+ const implementation = props.module.routes[props.name];
34
+ const Component = props.runtime.component(props.generation, implementation);
35
+ const declaration = runtimeView.definition;
36
+ const target = declaration.target.kind === 'domain'
37
+ ? Object.freeze({ kind: 'domain', origin: runtimeView.origin })
38
+ : targetPath === null
39
+ ? missingTarget(runtimeView.name)
40
+ : targetPath;
41
+ const current = new URL(window.location.href);
42
+ const routeParams = navigation?.history.current?.params ?? directRouteParams(current);
43
+ const route = Object.freeze({
44
+ name: props.name,
45
+ href: current.href,
46
+ params: Object.freeze({ ...routeParams }),
47
+ });
48
+ return createElement(Component, { view, target, route });
49
+ }
50
+ function directRouteParams(url) {
51
+ const params = {};
52
+ const prefix = 'astrale.param.';
53
+ for (const key of new Set(url.searchParams.keys())) {
54
+ if (!key.startsWith(prefix))
55
+ continue;
56
+ const name = key.slice(prefix.length);
57
+ if (name.length === 0 || /token|credential|authorization|secret/i.test(name)) {
58
+ throw new TypeError(`React View route param '${name}' is invalid.`);
59
+ }
60
+ const values = url.searchParams.getAll(key);
61
+ if (values.length !== 1)
62
+ throw new TypeError(`React View route param '${name}' is duplicated.`);
63
+ params[name] = values[0];
64
+ }
65
+ return Object.freeze(params);
66
+ }
67
+ function createRouteRuntime() {
68
+ const generations = new Map();
69
+ return {
70
+ component(generation, implementation) {
71
+ let Component = generations.get(generation);
72
+ if (Component === undefined) {
73
+ Component = lazy(async () => {
74
+ const loaded = await implementation.component();
75
+ return { default: loaded.default };
76
+ });
77
+ generations.set(generation, Component);
78
+ }
79
+ return Component;
80
+ },
81
+ };
82
+ }
83
+ function missingTarget(name) {
84
+ throw new Error(`React View '${name}' requires a resource target from the Shell handshake.`);
85
+ }
@@ -0,0 +1,16 @@
1
+ import type { Shell, ShellConfig } from '@astrale-os/shell';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import type { NavAdapter } from '../navigation/adapters/adapter.js';
4
+ import type { NavTarget } from '../navigation/snapshot.js';
5
+ import type { ShellProviderProps } from '../session/provider.js';
6
+ /** One generated/default root; custom React apps may compose the lower-level providers directly. */
7
+ export declare function ViewApp(props: {
8
+ readonly config: ShellConfig | Shell;
9
+ readonly navigation?: NavAdapter;
10
+ readonly initial?: NavTarget;
11
+ readonly fallback?: ReactNode;
12
+ readonly errorFallback?: ShellProviderProps['errorFallback'];
13
+ readonly onError?: ShellProviderProps['onError'];
14
+ readonly children: ReactNode;
15
+ }): ReactElement;
16
+ //# sourceMappingURL=view-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-app.d.ts","sourceRoot":"","sources":["../../src/components/view-app.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAShE,oGAAoG;AACpG,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAA;IAC5D,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAA;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,GAAG,YAAY,CAWf"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memoryAdapter } from '../navigation/adapters/memory.adapter.js';
3
+ import { urlAdapter } from '../navigation/adapters/url.adapter.js';
4
+ import { NavScope } from '../navigation/scope.context.js';
5
+ import { ShellProvider } from '../session/provider.js';
6
+ import { useShell } from '../session/shell.hook.js';
7
+ import { ViewStage } from '../window/stage.js';
8
+ /** One generated/default root; custom React apps may compose the lower-level providers directly. */
9
+ export function ViewApp(props) {
10
+ return (_jsx(ShellProvider, { config: props.config, fallback: props.fallback, errorFallback: props.errorFallback, onError: props.onError, children: _jsx(ViewAppRuntime, { ...props }) }));
11
+ }
12
+ function ViewAppRuntime(props) {
13
+ const shell = useShell();
14
+ const defaultAdapter = shell.hostCapabilities.navigation.history === 'browser' ? urlAdapter() : memoryAdapter();
15
+ return (_jsxs(NavScope, { adapter: props.navigation ?? defaultAdapter, initial: props.initial, children: [props.children, _jsx(ViewStage, {})] }));
16
+ }
@@ -1,21 +1,11 @@
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
  import type { Action } from '../action.js';
9
- export interface CallOptions {
10
- /** Per-call timeout (ms), forwarded to the kernel dispatch. */
11
- timeout?: number;
12
- /** Side-channel notified on rejection (the Action also records `.error`). */
13
- onError?(error: unknown): void;
5
+ export interface CallOptions extends SessionRequestOptions {
6
+ readonly onError?: (error: unknown) => void;
14
7
  }
15
- /**
16
- * Unary domain-function dispatch as an {@link Action}. `method` is a typed FnMap
17
- * `call` path or any string (the untyped floor); `null` yields an idle action
18
- * that rejects if invoked. Params/result are typed from the FnMap entry.
19
- */
20
- export declare function useCall<K extends CallFns<FnMap>>(method: K | null, opts?: CallOptions): Action<[FnMap[K]['params']], FnMap[K]['result']>;
8
+ export type CallResult = Value;
9
+ export declare function useCall(call: Call | null, options?: CallOptions): Action<[], CallResult>;
10
+ export declare function useCall<A extends unknown[]>(author: ((...args: A) => Call) | null, options?: CallOptions): Action<A, CallResult>;
21
11
  //# sourceMappingURL=call.hook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"call.hook.d.ts","sourceRoot":"","sources":["../../../src/graph/call/call.hook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AAE/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAK1C,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,CAAC,KAAK,CAAC,EAC9C,MAAM,EAAE,CAAC,GAAG,IAAI,EAChB,IAAI,CAAC,EAAE,WAAW,GACjB,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAalD"}
1
+ {"version":3,"file":"call.hook.d.ts","sourceRoot":"","sources":["../../../src/graph/call/call.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AAC9E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAK1C,MAAM,WAAW,WAAY,SAAQ,qBAAqB;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAA;AAG9B,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;AACzF,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EACzC,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,EACrC,OAAO,CAAC,EAAE,WAAW,GACpB,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA"}
@@ -1,22 +1,16 @@
1
1
  import { useSessionKernel } from '../../auth/session-kernel.js';
2
2
  import { useAction } from '../action.js';
3
- /**
4
- * Unary domain-function dispatch as an {@link Action}. `method` is a typed FnMap
5
- * `call` path or any string (the untyped floor); `null` yields an idle action
6
- * that rejects if invoked. Params/result are typed from the FnMap entry.
7
- */
8
- export function useCall(method, opts) {
3
+ export function useCall(author, options) {
9
4
  const kernel = useSessionKernel();
10
- // A fresh closure per render captures the current method/opts; `useAction`
11
- // keeps ONE stable callable and always dispatches this latest closure.
12
- return useAction(async (params) => {
13
- if (method === null)
14
- throw new Error('useCall: method is null (idle action invoked)');
5
+ return useAction(async (...args) => {
6
+ if (author === null)
7
+ throw new Error('useCall: idle action invoked');
8
+ const call = typeof author === 'function' ? author(...args) : author;
15
9
  try {
16
- return await kernel.call(method, params, { timeout: opts?.timeout });
10
+ return await kernel.call(call, options);
17
11
  }
18
12
  catch (error) {
19
- opts?.onError?.(error);
13
+ options?.onError?.(error);
20
14
  throw error;
21
15
  }
22
16
  });