@astrale-os/shell-react 0.1.0

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 (378) hide show
  1. package/LICENSE +202 -0
  2. package/dist/application/apps/app-host.d.ts +31 -0
  3. package/dist/application/apps/app-host.d.ts.map +1 -0
  4. package/dist/application/apps/app-host.js +59 -0
  5. package/dist/application/apps/app-logo.d.ts +19 -0
  6. package/dist/application/apps/app-logo.d.ts.map +1 -0
  7. package/dist/application/apps/app-logo.js +31 -0
  8. package/dist/application/apps/apps.hook.d.ts +12 -0
  9. package/dist/application/apps/apps.hook.d.ts.map +1 -0
  10. package/dist/application/apps/apps.hook.js +51 -0
  11. package/dist/application/apps/open-app.hook.d.ts +10 -0
  12. package/dist/application/apps/open-app.hook.d.ts.map +1 -0
  13. package/dist/application/apps/open-app.hook.js +7 -0
  14. package/dist/application/index.d.ts +18 -0
  15. package/dist/application/index.d.ts.map +1 -0
  16. package/dist/application/index.js +12 -0
  17. package/dist/application/roles.hook.d.ts +7 -0
  18. package/dist/application/roles.hook.d.ts.map +1 -0
  19. package/dist/application/roles.hook.js +23 -0
  20. package/dist/application/spaces/current-space.hook.d.ts +7 -0
  21. package/dist/application/spaces/current-space.hook.d.ts.map +1 -0
  22. package/dist/application/spaces/current-space.hook.js +27 -0
  23. package/dist/application/spaces/current-space.store.d.ts +32 -0
  24. package/dist/application/spaces/current-space.store.d.ts.map +1 -0
  25. package/dist/application/spaces/current-space.store.js +79 -0
  26. package/dist/application/spaces/space.hook.d.ts +5 -0
  27. package/dist/application/spaces/space.hook.d.ts.map +1 -0
  28. package/dist/application/spaces/space.hook.js +25 -0
  29. package/dist/application/spaces/spaces.hook.d.ts +14 -0
  30. package/dist/application/spaces/spaces.hook.d.ts.map +1 -0
  31. package/dist/application/spaces/spaces.hook.js +82 -0
  32. package/dist/application/user/user.hook.d.ts +10 -0
  33. package/dist/application/user/user.hook.d.ts.map +1 -0
  34. package/dist/application/user/user.hook.js +19 -0
  35. package/dist/application/user/user.store.d.ts +35 -0
  36. package/dist/application/user/user.store.d.ts.map +1 -0
  37. package/dist/application/user/user.store.js +51 -0
  38. package/dist/auth/act-as.context.d.ts +40 -0
  39. package/dist/auth/act-as.context.d.ts.map +1 -0
  40. package/dist/auth/act-as.context.js +84 -0
  41. package/dist/auth/auth.hook.d.ts +3 -0
  42. package/dist/auth/auth.hook.d.ts.map +1 -0
  43. package/dist/auth/auth.hook.js +25 -0
  44. package/dist/auth/can.hook.d.ts +40 -0
  45. package/dist/auth/can.hook.d.ts.map +1 -0
  46. package/dist/auth/can.hook.js +119 -0
  47. package/dist/auth/index.d.ts +6 -0
  48. package/dist/auth/index.d.ts.map +1 -0
  49. package/dist/auth/index.js +5 -0
  50. package/dist/auth/self.hook.d.ts +3 -0
  51. package/dist/auth/self.hook.d.ts.map +1 -0
  52. package/dist/auth/self.hook.js +11 -0
  53. package/dist/auth/session-kernel.d.ts +4 -0
  54. package/dist/auth/session-kernel.d.ts.map +1 -0
  55. package/dist/auth/session-kernel.js +21 -0
  56. package/dist/graph/action.d.ts +22 -0
  57. package/dist/graph/action.d.ts.map +1 -0
  58. package/dist/graph/action.js +85 -0
  59. package/dist/graph/async.d.ts +11 -0
  60. package/dist/graph/async.d.ts.map +1 -0
  61. package/dist/graph/async.js +60 -0
  62. package/dist/graph/call/call.hook.d.ts +21 -0
  63. package/dist/graph/call/call.hook.d.ts.map +1 -0
  64. package/dist/graph/call/call.hook.js +23 -0
  65. package/dist/graph/call/stream.hook.d.ts +28 -0
  66. package/dist/graph/call/stream.hook.d.ts.map +1 -0
  67. package/dist/graph/call/stream.hook.js +137 -0
  68. package/dist/graph/graph.context.d.ts +4 -0
  69. package/dist/graph/graph.context.d.ts.map +1 -0
  70. package/dist/graph/graph.context.js +10 -0
  71. package/dist/graph/guards.error.d.ts +9 -0
  72. package/dist/graph/guards.error.d.ts.map +1 -0
  73. package/dist/graph/guards.error.js +7 -0
  74. package/dist/graph/index.d.ts +20 -0
  75. package/dist/graph/index.d.ts.map +1 -0
  76. package/dist/graph/index.js +9 -0
  77. package/dist/graph/memory/base.d.ts +21 -0
  78. package/dist/graph/memory/base.d.ts.map +1 -0
  79. package/dist/graph/memory/base.js +33 -0
  80. package/dist/graph/memory/read/envelope.d.ts +71 -0
  81. package/dist/graph/memory/read/envelope.d.ts.map +1 -0
  82. package/dist/graph/memory/read/envelope.js +29 -0
  83. package/dist/graph/memory/read/idle.d.ts +18 -0
  84. package/dist/graph/memory/read/idle.d.ts.map +1 -0
  85. package/dist/graph/memory/read/idle.js +16 -0
  86. package/dist/graph/memory/read/read.d.ts +9 -0
  87. package/dist/graph/memory/read/read.d.ts.map +1 -0
  88. package/dist/graph/memory/read/read.js +87 -0
  89. package/dist/graph/memory/scope.d.ts +7 -0
  90. package/dist/graph/memory/scope.d.ts.map +1 -0
  91. package/dist/graph/memory/scope.js +25 -0
  92. package/dist/graph/mutate/move.hook.d.ts +7 -0
  93. package/dist/graph/mutate/move.hook.d.ts.map +1 -0
  94. package/dist/graph/mutate/move.hook.js +49 -0
  95. package/dist/graph/mutate/mutate.hook.d.ts +17 -0
  96. package/dist/graph/mutate/mutate.hook.d.ts.map +1 -0
  97. package/dist/graph/mutate/mutate.hook.js +45 -0
  98. package/dist/graph/query/children.hook.d.ts +29 -0
  99. package/dist/graph/query/children.hook.d.ts.map +1 -0
  100. package/dist/graph/query/children.hook.js +64 -0
  101. package/dist/graph/query/graph.hook.d.ts +9 -0
  102. package/dist/graph/query/graph.hook.d.ts.map +1 -0
  103. package/dist/graph/query/graph.hook.js +5 -0
  104. package/dist/graph/query/neighbors.hook.d.ts +7 -0
  105. package/dist/graph/query/neighbors.hook.d.ts.map +1 -0
  106. package/dist/graph/query/neighbors.hook.js +79 -0
  107. package/dist/graph/query/node.hook.d.ts +14 -0
  108. package/dist/graph/query/node.hook.d.ts.map +1 -0
  109. package/dist/graph/query/node.hook.js +43 -0
  110. package/dist/graph/query/query.hook.d.ts +14 -0
  111. package/dist/graph/query/query.hook.d.ts.map +1 -0
  112. package/dist/graph/query/query.hook.js +23 -0
  113. package/dist/index.d.ts +43 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +34 -0
  116. package/dist/intents/envelope.d.ts +33 -0
  117. package/dist/intents/envelope.d.ts.map +1 -0
  118. package/dist/intents/envelope.js +19 -0
  119. package/dist/intents/index.d.ts +6 -0
  120. package/dist/intents/index.d.ts.map +1 -0
  121. package/dist/intents/index.js +3 -0
  122. package/dist/intents/listen-intent.hook.d.ts +16 -0
  123. package/dist/intents/listen-intent.hook.d.ts.map +1 -0
  124. package/dist/intents/listen-intent.hook.js +75 -0
  125. package/dist/intents/reply.d.ts +9 -0
  126. package/dist/intents/reply.d.ts.map +1 -0
  127. package/dist/intents/reply.js +14 -0
  128. package/dist/intents/send-intent.hook.d.ts +12 -0
  129. package/dist/intents/send-intent.hook.d.ts.map +1 -0
  130. package/dist/intents/send-intent.hook.js +86 -0
  131. package/dist/navigation/adapters/adapter.d.ts +15 -0
  132. package/dist/navigation/adapters/adapter.d.ts.map +1 -0
  133. package/dist/navigation/adapters/adapter.js +1 -0
  134. package/dist/navigation/adapters/memory.adapter.d.ts +9 -0
  135. package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -0
  136. package/dist/navigation/adapters/memory.adapter.js +15 -0
  137. package/dist/navigation/adapters/url.adapter.d.ts +6 -0
  138. package/dist/navigation/adapters/url.adapter.d.ts.map +1 -0
  139. package/dist/navigation/adapters/url.adapter.js +59 -0
  140. package/dist/navigation/history.d.ts +63 -0
  141. package/dist/navigation/history.d.ts.map +1 -0
  142. package/dist/navigation/history.js +144 -0
  143. package/dist/navigation/hooks/ancestors.hook.d.ts +13 -0
  144. package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -0
  145. package/dist/navigation/hooks/ancestors.hook.js +56 -0
  146. package/dist/navigation/hooks/location.hook.d.ts +4 -0
  147. package/dist/navigation/hooks/location.hook.d.ts.map +1 -0
  148. package/dist/navigation/hooks/location.hook.js +17 -0
  149. package/dist/navigation/hooks/navigate.hook.d.ts +12 -0
  150. package/dist/navigation/hooks/navigate.hook.d.ts.map +1 -0
  151. package/dist/navigation/hooks/navigate.hook.js +33 -0
  152. package/dist/navigation/hooks/scope.hook.d.ts +12 -0
  153. package/dist/navigation/hooks/scope.hook.d.ts.map +1 -0
  154. package/dist/navigation/hooks/scope.hook.js +21 -0
  155. package/dist/navigation/index.d.ts +16 -0
  156. package/dist/navigation/index.d.ts.map +1 -0
  157. package/dist/navigation/index.js +10 -0
  158. package/dist/navigation/link.d.ts +11 -0
  159. package/dist/navigation/link.d.ts.map +1 -0
  160. package/dist/navigation/link.js +62 -0
  161. package/dist/navigation/location.d.ts +48 -0
  162. package/dist/navigation/location.d.ts.map +1 -0
  163. package/dist/navigation/location.js +88 -0
  164. package/dist/navigation/scope.context.d.ts +64 -0
  165. package/dist/navigation/scope.context.d.ts.map +1 -0
  166. package/dist/navigation/scope.context.js +178 -0
  167. package/dist/navigation/snapshot.d.ts +22 -0
  168. package/dist/navigation/snapshot.d.ts.map +1 -0
  169. package/dist/navigation/snapshot.js +65 -0
  170. package/dist/schema/bind-read.d.ts +37 -0
  171. package/dist/schema/bind-read.d.ts.map +1 -0
  172. package/dist/schema/bind-read.js +205 -0
  173. package/dist/schema/binding.d.ts +21 -0
  174. package/dist/schema/binding.d.ts.map +1 -0
  175. package/dist/schema/binding.js +55 -0
  176. package/dist/schema/domain.hook.d.ts +10 -0
  177. package/dist/schema/domain.hook.d.ts.map +1 -0
  178. package/dist/schema/domain.hook.js +7 -0
  179. package/dist/schema/function.hook.d.ts +9 -0
  180. package/dist/schema/function.hook.d.ts.map +1 -0
  181. package/dist/schema/function.hook.js +40 -0
  182. package/dist/schema/index.d.ts +10 -0
  183. package/dist/schema/index.d.ts.map +1 -0
  184. package/dist/schema/index.js +8 -0
  185. package/dist/schema/kernel.hook.d.ts +10 -0
  186. package/dist/schema/kernel.hook.d.ts.map +1 -0
  187. package/dist/schema/kernel.hook.js +8 -0
  188. package/dist/schema/method.hook.d.ts +14 -0
  189. package/dist/schema/method.hook.d.ts.map +1 -0
  190. package/dist/schema/method.hook.js +49 -0
  191. package/dist/schema/tag.d.ts +11 -0
  192. package/dist/schema/tag.d.ts.map +1 -0
  193. package/dist/schema/tag.js +11 -0
  194. package/dist/schema/types.d.ts +73 -0
  195. package/dist/schema/types.d.ts.map +1 -0
  196. package/dist/schema/types.js +1 -0
  197. package/dist/schema/write.d.ts +15 -0
  198. package/dist/schema/write.d.ts.map +1 -0
  199. package/dist/schema/write.js +45 -0
  200. package/dist/selection/index.d.ts +4 -0
  201. package/dist/selection/index.d.ts.map +1 -0
  202. package/dist/selection/index.js +4 -0
  203. package/dist/selection/live.d.ts +21 -0
  204. package/dist/selection/live.d.ts.map +1 -0
  205. package/dist/selection/live.js +116 -0
  206. package/dist/selection/scope.context.d.ts +26 -0
  207. package/dist/selection/scope.context.d.ts.map +1 -0
  208. package/dist/selection/scope.context.js +100 -0
  209. package/dist/selection/selection.hook.d.ts +4 -0
  210. package/dist/selection/selection.hook.d.ts.map +1 -0
  211. package/dist/selection/selection.hook.js +14 -0
  212. package/dist/session/boot/boot.d.ts +19 -0
  213. package/dist/session/boot/boot.d.ts.map +1 -0
  214. package/dist/session/boot/boot.js +45 -0
  215. package/dist/session/boot/ownership.d.ts +18 -0
  216. package/dist/session/boot/ownership.d.ts.map +1 -0
  217. package/dist/session/boot/ownership.js +39 -0
  218. package/dist/session/boot/status.d.ts +24 -0
  219. package/dist/session/boot/status.d.ts.map +1 -0
  220. package/dist/session/boot/status.js +11 -0
  221. package/dist/session/connection/connection.hook.d.ts +3 -0
  222. package/dist/session/connection/connection.hook.d.ts.map +1 -0
  223. package/dist/session/connection/connection.hook.js +12 -0
  224. package/dist/session/connection/connection.store.d.ts +24 -0
  225. package/dist/session/connection/connection.store.d.ts.map +1 -0
  226. package/dist/session/connection/connection.store.js +31 -0
  227. package/dist/session/index.d.ts +8 -0
  228. package/dist/session/index.d.ts.map +1 -0
  229. package/dist/session/index.js +6 -0
  230. package/dist/session/kernel-client.hook.d.ts +9 -0
  231. package/dist/session/kernel-client.hook.d.ts.map +1 -0
  232. package/dist/session/kernel-client.hook.js +5 -0
  233. package/dist/session/kernel-instance.hook.d.ts +9 -0
  234. package/dist/session/kernel-instance.hook.d.ts.map +1 -0
  235. package/dist/session/kernel-instance.hook.js +10 -0
  236. package/dist/session/provider.d.ts +31 -0
  237. package/dist/session/provider.d.ts.map +1 -0
  238. package/dist/session/provider.js +165 -0
  239. package/dist/session/session.context.d.ts +18 -0
  240. package/dist/session/session.context.d.ts.map +1 -0
  241. package/dist/session/session.context.js +8 -0
  242. package/dist/session/shell.hook.d.ts +4 -0
  243. package/dist/session/shell.hook.d.ts.map +1 -0
  244. package/dist/session/shell.hook.js +15 -0
  245. package/dist/window/adopt.d.ts +27 -0
  246. package/dist/window/adopt.d.ts.map +1 -0
  247. package/dist/window/adopt.js +27 -0
  248. package/dist/window/hooks/close-guard.hook.d.ts +6 -0
  249. package/dist/window/hooks/close-guard.hook.d.ts.map +1 -0
  250. package/dist/window/hooks/close-guard.hook.js +90 -0
  251. package/dist/window/hooks/target-node.hook.d.ts +7 -0
  252. package/dist/window/hooks/target-node.hook.d.ts.map +1 -0
  253. package/dist/window/hooks/target-node.hook.js +77 -0
  254. package/dist/window/hooks/views-for.hook.d.ts +8 -0
  255. package/dist/window/hooks/views-for.hook.d.ts.map +1 -0
  256. package/dist/window/hooks/views-for.hook.js +51 -0
  257. package/dist/window/hooks/window.hook.d.ts +4 -0
  258. package/dist/window/hooks/window.hook.d.ts.map +1 -0
  259. package/dist/window/hooks/window.hook.js +14 -0
  260. package/dist/window/hooks/windows.hook.d.ts +15 -0
  261. package/dist/window/hooks/windows.hook.d.ts.map +1 -0
  262. package/dist/window/hooks/windows.hook.js +25 -0
  263. package/dist/window/host.d.ts +31 -0
  264. package/dist/window/host.d.ts.map +1 -0
  265. package/dist/window/host.js +270 -0
  266. package/dist/window/hub.d.ts +41 -0
  267. package/dist/window/hub.d.ts.map +1 -0
  268. package/dist/window/hub.js +100 -0
  269. package/dist/window/index.d.ts +15 -0
  270. package/dist/window/index.d.ts.map +1 -0
  271. package/dist/window/index.js +10 -0
  272. package/dist/window/lifecycle/mount.d.ts +47 -0
  273. package/dist/window/lifecycle/mount.d.ts.map +1 -0
  274. package/dist/window/lifecycle/mount.js +92 -0
  275. package/dist/window/lifecycle/states.d.ts +33 -0
  276. package/dist/window/lifecycle/states.d.ts.map +1 -0
  277. package/dist/window/lifecycle/states.js +7 -0
  278. package/dist/window/placement.d.ts +33 -0
  279. package/dist/window/placement.d.ts.map +1 -0
  280. package/dist/window/placement.js +57 -0
  281. package/dist/window/stage.d.ts +3 -0
  282. package/dist/window/stage.d.ts.map +1 -0
  283. package/dist/window/stage.js +41 -0
  284. package/package.json +59 -0
  285. package/src/application/apps/app-host.tsx +113 -0
  286. package/src/application/apps/app-logo.tsx +56 -0
  287. package/src/application/apps/apps.hook.ts +81 -0
  288. package/src/application/apps/open-app.hook.ts +18 -0
  289. package/src/application/index.ts +22 -0
  290. package/src/application/roles.hook.ts +41 -0
  291. package/src/application/spaces/current-space.hook.ts +43 -0
  292. package/src/application/spaces/current-space.store.ts +110 -0
  293. package/src/application/spaces/space.hook.ts +41 -0
  294. package/src/application/spaces/spaces.hook.ts +113 -0
  295. package/src/application/user/user.hook.ts +27 -0
  296. package/src/application/user/user.store.ts +85 -0
  297. package/src/auth/act-as.context.tsx +124 -0
  298. package/src/auth/auth.hook.ts +36 -0
  299. package/src/auth/can.hook.ts +149 -0
  300. package/src/auth/index.ts +6 -0
  301. package/src/auth/self.hook.ts +14 -0
  302. package/src/auth/session-kernel.ts +24 -0
  303. package/src/graph/action.ts +127 -0
  304. package/src/graph/async.ts +87 -0
  305. package/src/graph/call/call.hook.ts +42 -0
  306. package/src/graph/call/stream.hook.ts +200 -0
  307. package/src/graph/graph.context.ts +14 -0
  308. package/src/graph/guards.error.ts +58 -0
  309. package/src/graph/index.ts +20 -0
  310. package/src/graph/memory/base.ts +50 -0
  311. package/src/graph/memory/read/envelope.ts +98 -0
  312. package/src/graph/memory/read/idle.ts +24 -0
  313. package/src/graph/memory/read/read.ts +103 -0
  314. package/src/graph/memory/scope.ts +29 -0
  315. package/src/graph/mutate/move.hook.ts +70 -0
  316. package/src/graph/mutate/mutate.hook.ts +69 -0
  317. package/src/graph/query/children.hook.ts +136 -0
  318. package/src/graph/query/graph.hook.ts +13 -0
  319. package/src/graph/query/neighbors.hook.ts +124 -0
  320. package/src/graph/query/node.hook.ts +83 -0
  321. package/src/graph/query/query.hook.ts +42 -0
  322. package/src/index.ts +202 -0
  323. package/src/intents/envelope.ts +52 -0
  324. package/src/intents/index.ts +6 -0
  325. package/src/intents/listen-intent.hook.ts +92 -0
  326. package/src/intents/reply.ts +24 -0
  327. package/src/intents/send-intent.hook.ts +111 -0
  328. package/src/navigation/adapters/adapter.ts +13 -0
  329. package/src/navigation/adapters/memory.adapter.ts +22 -0
  330. package/src/navigation/adapters/url.adapter.ts +61 -0
  331. package/src/navigation/history.ts +170 -0
  332. package/src/navigation/hooks/ancestors.hook.ts +71 -0
  333. package/src/navigation/hooks/location.hook.ts +21 -0
  334. package/src/navigation/hooks/navigate.hook.ts +43 -0
  335. package/src/navigation/hooks/scope.hook.ts +34 -0
  336. package/src/navigation/index.ts +17 -0
  337. package/src/navigation/link.tsx +110 -0
  338. package/src/navigation/location.ts +122 -0
  339. package/src/navigation/scope.context.tsx +267 -0
  340. package/src/navigation/snapshot.ts +79 -0
  341. package/src/schema/bind-read.ts +319 -0
  342. package/src/schema/binding.ts +91 -0
  343. package/src/schema/domain.hook.ts +16 -0
  344. package/src/schema/function.hook.ts +68 -0
  345. package/src/schema/index.ts +25 -0
  346. package/src/schema/kernel.hook.ts +17 -0
  347. package/src/schema/method.hook.ts +103 -0
  348. package/src/schema/tag.ts +19 -0
  349. package/src/schema/types.ts +150 -0
  350. package/src/schema/write.ts +80 -0
  351. package/src/selection/index.ts +5 -0
  352. package/src/selection/live.ts +142 -0
  353. package/src/selection/scope.context.tsx +151 -0
  354. package/src/selection/selection.hook.ts +18 -0
  355. package/src/session/boot/boot.ts +57 -0
  356. package/src/session/boot/ownership.ts +54 -0
  357. package/src/session/boot/status.ts +32 -0
  358. package/src/session/connection/connection.hook.ts +16 -0
  359. package/src/session/connection/connection.store.ts +58 -0
  360. package/src/session/index.ts +8 -0
  361. package/src/session/kernel-client.hook.ts +13 -0
  362. package/src/session/kernel-instance.hook.ts +22 -0
  363. package/src/session/provider.tsx +205 -0
  364. package/src/session/session.context.ts +27 -0
  365. package/src/session/shell.hook.ts +19 -0
  366. package/src/window/adopt.ts +57 -0
  367. package/src/window/hooks/close-guard.hook.ts +100 -0
  368. package/src/window/hooks/target-node.hook.ts +94 -0
  369. package/src/window/hooks/views-for.hook.ts +82 -0
  370. package/src/window/hooks/window.hook.ts +18 -0
  371. package/src/window/hooks/windows.hook.ts +40 -0
  372. package/src/window/host.tsx +347 -0
  373. package/src/window/hub.ts +156 -0
  374. package/src/window/index.ts +17 -0
  375. package/src/window/lifecycle/mount.ts +134 -0
  376. package/src/window/lifecycle/states.ts +23 -0
  377. package/src/window/placement.ts +84 -0
  378. package/src/window/stage.tsx +46 -0
@@ -0,0 +1,48 @@
1
+ import type { LiveResult } from '@astrale-os/kernel-client/store';
2
+ import type { SerializedLocation } from './history';
3
+ /**
4
+ * The rich graph `Node`, derived from the memory's read envelope — kernel-client
5
+ * does not re-export `Node` at its root yet (API §14 G8), so shell-react reads it
6
+ * off `LiveResult` rather than taking a direct kernel-core dependency.
7
+ */
8
+ export type Node = NonNullable<LiveResult['node']>;
9
+ export type NodeId = Node['id'];
10
+ /** The live, id-anchored location a scope currently points at (API §8.1). */
11
+ export interface NavLocation {
12
+ /** The anchor — survives rename/move. */
13
+ readonly id: NodeId;
14
+ /** LIVE projection of the node's current path (empty until first resolve). */
15
+ readonly path: string;
16
+ /** Live memory node — null while cold, or after the anchor stops resolving. */
17
+ readonly node: Node | null;
18
+ /** View function ref rendering it, when one is open. */
19
+ readonly view?: string;
20
+ readonly params: Readonly<Record<string, string>>;
21
+ /** The anchor no longer resolves (deleted / masked). */
22
+ readonly missing: boolean;
23
+ }
24
+ /** The idle location a scope with no current entry projects (inert / boot). */
25
+ export declare const IDLE_LOCATION: NavLocation;
26
+ /** Project a serialized entry + its live read into the public {@link NavLocation}. */
27
+ export declare function buildLocation(entry: SerializedLocation | null, result: LiveResult | null, settled: boolean): NavLocation;
28
+ /**
29
+ * Whether a read has definitively settled — data present, a hard error, or a
30
+ * completed empty fetch. Guards `missing` (and the missing policy) against the
31
+ * one-render false-empty before a cold shape's first fetch is even in flight.
32
+ */
33
+ export declare function useSettled(result: LiveResult | null, key: string | null): boolean;
34
+ /** The raw path of a live node (empty when cold). */
35
+ export declare function pathOf(node: Node | null): string;
36
+ /** Best-effort anchor id from a stored ref (`@<id>` → id, else the raw ref). */
37
+ export declare function idHint(ref: string): string;
38
+ /** Best-effort path from a stored ref (a `/…` ref is already a path). */
39
+ export declare function pathHint(ref: string): string;
40
+ /** The parent absolute path, or null at (or above) root. */
41
+ export declare function parentPath(raw: string): string | null;
42
+ /**
43
+ * The inclusive, root-first path chain for an absolute path — the ancestry the
44
+ * kernel tree encodes in the slug path (`/a/b/c` → `/`, `/a`, `/a/b`, `/a/b/c`).
45
+ * The node itself is the last element, so breadcrumbs map the chain directly.
46
+ */
47
+ export declare function chainPaths(raw: string): string[];
48
+ //# sourceMappingURL=location.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../src/navigation/location.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAWjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAEnD;;;;GAIG;AACH,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;AAClD,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAA;AAE/B,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjD,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAID,+EAA+E;AAC/E,eAAO,MAAM,aAAa,EAAE,WAM3B,CAAA;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,kBAAkB,GAAG,IAAI,EAChC,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,OAAO,EAAE,OAAO,GACf,WAAW,CAWb;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CASjF;AAID,qDAAqD;AACrD,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAEhD;AAED,gFAAgF;AAChF,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAUhD"}
@@ -0,0 +1,88 @@
1
+ import { rawOf } from '@astrale-os/kernel-client/graph';
2
+ /**
3
+ * NavLocation projection (API §8.1) — the live, id-anchored location a scope
4
+ * points at (live path, missing flag), its `buildLocation` assembly, the
5
+ * `useSettled` guard against a one-render false-empty, and the framework-free
6
+ * path math (parent/chain) the scope and hooks share.
7
+ */
8
+ import { useEffect, useRef } from 'react';
9
+ const EMPTY_PARAMS = Object.freeze({});
10
+ /** The idle location a scope with no current entry projects (inert / boot). */
11
+ export const IDLE_LOCATION = {
12
+ id: '',
13
+ path: '',
14
+ node: null,
15
+ params: EMPTY_PARAMS,
16
+ missing: false,
17
+ };
18
+ /** Project a serialized entry + its live read into the public {@link NavLocation}. */
19
+ export function buildLocation(entry, result, settled) {
20
+ if (entry === null)
21
+ return IDLE_LOCATION;
22
+ const node = result?.node ?? null;
23
+ return {
24
+ id: (node?.id ?? idHint(entry.node)),
25
+ path: node ? pathOf(node) : pathHint(entry.node),
26
+ node,
27
+ ...(entry.view !== undefined ? { view: entry.view } : {}),
28
+ params: entry.params ?? IDLE_LOCATION.params,
29
+ missing: settled && node === null,
30
+ };
31
+ }
32
+ /**
33
+ * Whether a read has definitively settled — data present, a hard error, or a
34
+ * completed empty fetch. Guards `missing` (and the missing policy) against the
35
+ * one-render false-empty before a cold shape's first fetch is even in flight.
36
+ */
37
+ export function useSettled(result, key) {
38
+ const sawPending = useRef(new Map());
39
+ useEffect(() => {
40
+ if (key !== null && result?.pending === true)
41
+ sawPending.current.set(key, true);
42
+ }, [key, result?.pending]);
43
+ if (key === null || result === null)
44
+ return false;
45
+ if (result.node !== null)
46
+ return true;
47
+ if (result.error !== undefined)
48
+ return true;
49
+ return !result.pending && sawPending.current.get(key) === true;
50
+ }
51
+ // ── path math ──────────────────────────────────────────────────────────────
52
+ /** The raw path of a live node (empty when cold). */
53
+ export function pathOf(node) {
54
+ return node ? rawOf(node.path) : '';
55
+ }
56
+ /** Best-effort anchor id from a stored ref (`@<id>` → id, else the raw ref). */
57
+ export function idHint(ref) {
58
+ return ref.startsWith('@') ? ref.slice(1) : ref;
59
+ }
60
+ /** Best-effort path from a stored ref (a `/…` ref is already a path). */
61
+ export function pathHint(ref) {
62
+ return ref.startsWith('/') ? ref : '';
63
+ }
64
+ /** The parent absolute path, or null at (or above) root. */
65
+ export function parentPath(raw) {
66
+ const norm = raw.replace(/\/+$/, '');
67
+ if (norm === '' || norm === '/')
68
+ return null;
69
+ const idx = norm.lastIndexOf('/');
70
+ return idx <= 0 ? '/' : norm.slice(0, idx);
71
+ }
72
+ /**
73
+ * The inclusive, root-first path chain for an absolute path — the ancestry the
74
+ * kernel tree encodes in the slug path (`/a/b/c` → `/`, `/a`, `/a/b`, `/a/b/c`).
75
+ * The node itself is the last element, so breadcrumbs map the chain directly.
76
+ */
77
+ export function chainPaths(raw) {
78
+ const norm = raw.replace(/\/+$/, '');
79
+ if (norm === '' || norm === '/')
80
+ return ['/'];
81
+ const out = ['/'];
82
+ let acc = '';
83
+ for (const seg of norm.split('/').filter(Boolean)) {
84
+ acc += `/${seg}`;
85
+ out.push(acc);
86
+ }
87
+ return out;
88
+ }
@@ -0,0 +1,64 @@
1
+ import type { GraphMemory, LiveResult, ShapeInput } from '@astrale-os/kernel-client/store';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import type { NavAdapter } from './adapters/adapter';
4
+ import type { NavSnapshot } from './history';
5
+ import type { NavLocation } from './location';
6
+ import type { NavTarget } from './snapshot';
7
+ import { NavHistory } from './history';
8
+ /** The imperative navigation surface (API §8.2). */
9
+ export interface Navigate {
10
+ (to: NavTarget, opts?: {
11
+ replace?: boolean;
12
+ }): void;
13
+ back(): void;
14
+ forward(): void;
15
+ /** To the parent via `has_parent`; no-op at root or while the node is cold. */
16
+ up(): void;
17
+ readonly canBack: boolean;
18
+ readonly canForward: boolean;
19
+ }
20
+ /** A mutable `Navigate` — the scope stamps `canBack`/`canForward` onto it live. */
21
+ export interface MutableNavigate {
22
+ (to: Parameters<Navigate>[0], opts?: Parameters<Navigate>[1]): void;
23
+ back(): void;
24
+ forward(): void;
25
+ up(): void;
26
+ canBack: boolean;
27
+ canForward: boolean;
28
+ }
29
+ /** The nearest scope's shared handle (stable for the scope's lifetime). */
30
+ export interface NavCtx {
31
+ readonly history: NavHistory;
32
+ readonly memory: GraphMemory;
33
+ readonly adapter: NavAdapter;
34
+ readonly navigate: MutableNavigate;
35
+ }
36
+ export declare const NavContext: import("react").Context<NavCtx | null>;
37
+ /** The nearest scope, or throw — the door every public nav hook goes through. */
38
+ export declare function useNavCtx(): NavCtx;
39
+ /** The nearest scope or null (for `useAncestors`, usable outside a scope). */
40
+ export declare function useOptionalNavCtx(): NavCtx | null;
41
+ /** Re-render on any history change (no-op subscription when there is no scope). */
42
+ export declare function useHistoryVersion(history: NavHistory | null): number;
43
+ /**
44
+ * Subscribe to one memory shape, tear-free. `shape` must be stable per read
45
+ * (a string ref, or a builder memoized upstream); a null shape is idle (no I/O).
46
+ */
47
+ export declare function useMemoryShape(memory: GraphMemory, shape: ShapeInput | null): LiveResult | null;
48
+ /** The missing-anchor policy — a fallback strategy or a caller-supplied resolver. */
49
+ export type MissingPolicy = 'ancestor' | 'hold' | ((loc: NavLocation) => NavTarget | null);
50
+ export interface NavScopeProps {
51
+ /** Persistence seam. Default: a fresh {@link memoryAdapter} (captured once). */
52
+ adapter?: NavAdapter;
53
+ /** A saved snapshot — revalidated against the memory; dead entries dropped. */
54
+ restore?: NavSnapshot;
55
+ /** Seed target when neither `adapter.read()` nor `restore` yields one. */
56
+ initial?: NavTarget;
57
+ /** Fires per navigation with the new location + snapshot — persist here. */
58
+ onChange?: (loc: NavLocation, snapshot: NavSnapshot) => void;
59
+ /** What to do when the current anchor stops resolving. Default `'ancestor'`. */
60
+ missing?: MissingPolicy;
61
+ children: ReactNode;
62
+ }
63
+ export declare function NavScope(props: NavScopeProps): ReactElement;
64
+ //# sourceMappingURL=scope.context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.context.d.ts","sourceRoot":"","sources":["../../src/navigation/scope.context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAqBpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAI3C,OAAO,EAAE,UAAU,EAAe,MAAM,WAAW,CAAA;AAInD,oDAAoD;AACpD,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;IACnD,IAAI,IAAI,IAAI,CAAA;IACZ,OAAO,IAAI,IAAI,CAAA;IACf,+EAA+E;IAC/E,EAAE,IAAI,IAAI,CAAA;IACV,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAC7B;AAED,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IACnE,IAAI,IAAI,IAAI,CAAA;IACZ,OAAO,IAAI,IAAI,CAAA;IACf,EAAE,IAAI,IAAI,CAAA;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;CACnC;AAED,eAAO,MAAM,UAAU,wCAAqC,CAAA;AAG5D,iFAAiF;AACjF,wBAAgB,SAAS,IAAI,MAAM,CAIlC;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjD;AAID,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,GAAG,MAAM,CAOpE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,UAAU,GAAG,IAAI,CAU/F;AAED,qFAAqF;AACrF,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,WAAW,KAAK,SAAS,GAAG,IAAI,CAAC,CAAA;AAE1F,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAA;IAC5D,gFAAgF;IAChF,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CA2H3D"}
@@ -0,0 +1,178 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * NavScope (API §8.2) — owns one history stack, wires it to an adapter, and seats
4
+ * the scope context. Seeds from restore/adapter/initial, revalidates a restored
5
+ * stack against the memory, mirrors navigations to/from the adapter, and runs the
6
+ * `missing` policy when the current anchor stops resolving. Also the scope's shared
7
+ * glue (`NavContext`, the `useSyncExternalStore` reads) and the imperative
8
+ * `Navigate` surface. Scopes nest.
9
+ */
10
+ import { createContext, startTransition, useCallback, useContext, useEffect, useMemo, useRef, useSyncExternalStore, } from 'react';
11
+ import { useMemory } from '../graph/memory/scope';
12
+ import { memoryAdapter } from './adapters/memory.adapter';
13
+ import { NavHistory, seedEntries } from './history';
14
+ import { buildLocation, parentPath, pathHint, pathOf, useSettled } from './location';
15
+ import { revalidateAndPrune, serializeTarget } from './snapshot';
16
+ export const NavContext = createContext(null);
17
+ NavContext.displayName = 'AstraleNavContext';
18
+ /** The nearest scope, or throw — the door every public nav hook goes through. */
19
+ export function useNavCtx() {
20
+ const ctx = useContext(NavContext);
21
+ if (ctx === null)
22
+ throw new Error('nav hooks must be used within a <NavScope>');
23
+ return ctx;
24
+ }
25
+ /** The nearest scope or null (for `useAncestors`, usable outside a scope). */
26
+ export function useOptionalNavCtx() {
27
+ return useContext(NavContext);
28
+ }
29
+ const NOOP_UNSUB = () => undefined;
30
+ /** Re-render on any history change (no-op subscription when there is no scope). */
31
+ export function useHistoryVersion(history) {
32
+ const subscribe = useCallback((cb) => (history !== null ? history.subscribe(cb) : NOOP_UNSUB), [history]);
33
+ const getSnapshot = useCallback(() => (history !== null ? history.getVersion() : 0), [history]);
34
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
35
+ }
36
+ /**
37
+ * Subscribe to one memory shape, tear-free. `shape` must be stable per read
38
+ * (a string ref, or a builder memoized upstream); a null shape is idle (no I/O).
39
+ */
40
+ export function useMemoryShape(memory, shape) {
41
+ const subscribe = useCallback((cb) => (shape !== null ? memory.subscribe(shape, cb) : NOOP_UNSUB), [memory, shape]);
42
+ const getSnapshot = useCallback(() => (shape !== null ? memory.getSnapshot(shape) : null), [memory, shape]);
43
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
44
+ }
45
+ export function NavScope(props) {
46
+ const memory = useMemory();
47
+ // Adapter + history are captured ONCE — an inline `adapter={memoryAdapter()}`
48
+ // (or a re-passed `initial`) must never rebuild the scope's state.
49
+ const adapterRef = useRef(null);
50
+ if (adapterRef.current === null)
51
+ adapterRef.current = props.adapter ?? memoryAdapter();
52
+ const adapter = adapterRef.current;
53
+ const historyRef = useRef(null);
54
+ if (historyRef.current === null) {
55
+ const seed = seedEntries(adapter.read(), props.restore, props.initial !== undefined ? serializeTarget(props.initial) : null);
56
+ historyRef.current = new NavHistory(seed.entries, seed.cursor);
57
+ }
58
+ const history = historyRef.current;
59
+ // Latest-value refs so the stable navigate + effects read current inputs.
60
+ const memoryRef = useRef(memory);
61
+ memoryRef.current = memory;
62
+ const onChangeRef = useRef(props.onChange);
63
+ onChangeRef.current = props.onChange;
64
+ const missingRef = useRef(props.missing);
65
+ missingRef.current = props.missing;
66
+ const fireOnChange = useCallback(() => {
67
+ const cb = onChangeRef.current;
68
+ if (cb === undefined)
69
+ return;
70
+ const entry = history.current;
71
+ const live = entry !== null ? memoryRef.current.peek(entry.node) : null;
72
+ cb(buildLocation(entry, live, (live?.node ?? null) !== null), history.snapshot());
73
+ }, [history]);
74
+ // The one stable navigate object; hooks re-stamp canBack/canForward onto it.
75
+ const navigate = useMemo(() => {
76
+ const commit = (changed, replace) => {
77
+ if (!changed)
78
+ return;
79
+ const loc = history.current;
80
+ if (loc !== null)
81
+ adapter.write(loc, { replace });
82
+ fireOnChange();
83
+ };
84
+ const nav = ((to, opts) => {
85
+ const loc = serializeTarget(to);
86
+ const replace = opts?.replace ?? false;
87
+ startTransition(() => commit(history.push(loc, replace), replace));
88
+ });
89
+ nav.back = () => startTransition(() => commit(history.back(), false));
90
+ nav.forward = () => startTransition(() => commit(history.forward(), false));
91
+ nav.up = () => {
92
+ const entry = history.current;
93
+ if (entry === null)
94
+ return;
95
+ const live = memoryRef.current.peek(entry.node);
96
+ const raw = live?.node ? pathOf(live.node) : pathHint(entry.node);
97
+ const parent = raw !== '' ? parentPath(raw) : null;
98
+ if (parent !== null)
99
+ nav(parent);
100
+ };
101
+ nav.canBack = history.canBack;
102
+ nav.canForward = history.canForward;
103
+ return nav;
104
+ }, [history, adapter, fireOnChange]);
105
+ // Re-render the scope on every navigation so the missing watcher tracks the
106
+ // current entry (consumers re-render through their own version subscription).
107
+ const historyVersion = useHistoryVersion(history);
108
+ // Mount: canonicalize a non-adapter seed into the adapter, then relay external
109
+ // (browser/URL) changes back into the history.
110
+ useEffect(() => {
111
+ const seedLoc = history.current;
112
+ if (seedLoc !== null && adapter.read() === null)
113
+ adapter.write(seedLoc, { replace: true });
114
+ return adapter.subscribe(() => {
115
+ const loc = adapter.read();
116
+ if (loc === null)
117
+ return;
118
+ startTransition(() => {
119
+ if (history.syncExternal(loc))
120
+ fireOnChange();
121
+ });
122
+ });
123
+ }, [history, adapter, fireOnChange]);
124
+ // Restore revalidation — once, against the shared memory.
125
+ const revalidatedRef = useRef(false);
126
+ useEffect(() => {
127
+ if (revalidatedRef.current || props.restore === undefined)
128
+ return;
129
+ revalidatedRef.current = true;
130
+ void revalidateAndPrune(history, memory);
131
+ }, [memory, props.restore, history]);
132
+ // Missing-anchor watcher: the current entry's live read drives the policy.
133
+ const currentShape = history.current?.node ?? null;
134
+ const currentResult = useMemoryShape(memory, currentShape);
135
+ const settled = useSettled(currentResult, currentShape);
136
+ const lastPathRef = useRef(null);
137
+ const handledRef = useRef(null);
138
+ useEffect(() => {
139
+ const resolved = currentResult?.node ?? null;
140
+ if (resolved !== null)
141
+ lastPathRef.current = pathOf(resolved);
142
+ }, [currentResult?.node]);
143
+ useEffect(() => {
144
+ const entry = history.current;
145
+ if (entry === null)
146
+ return;
147
+ if ((currentResult?.node ?? null) !== null) {
148
+ handledRef.current = null;
149
+ return;
150
+ }
151
+ if (!settled || handledRef.current === entry.node)
152
+ return;
153
+ handledRef.current = entry.node;
154
+ applyMissingPolicy(entry, missingRef.current ?? 'ancestor', {
155
+ lastPath: lastPathRef.current,
156
+ result: currentResult,
157
+ navigate,
158
+ });
159
+ // historyVersion re-runs this when the current entry changes.
160
+ }, [settled, currentResult, history, navigate, historyVersion]);
161
+ const ctx = useMemo(() => ({ history, memory, adapter, navigate }), [history, memory, adapter, navigate]);
162
+ return _jsx(NavContext.Provider, { value: ctx, children: props.children });
163
+ }
164
+ function applyMissingPolicy(entry, policy, deps) {
165
+ if (policy === 'hold')
166
+ return;
167
+ if (typeof policy === 'function') {
168
+ const target = policy(buildLocation(entry, deps.result, true));
169
+ if (target !== null)
170
+ deps.navigate(target, { replace: true });
171
+ return;
172
+ }
173
+ // 'ancestor': climb one level toward a resolvable ancestor (repeats per settle).
174
+ const raw = deps.lastPath ?? pathHint(entry.node);
175
+ const parent = raw !== '' ? parentPath(raw) : null;
176
+ if (parent !== null)
177
+ deps.navigate(parent, { replace: true });
178
+ }
@@ -0,0 +1,22 @@
1
+ import type { AnyBoundNode, NodeRefInput } from '@astrale-os/kernel-client';
2
+ import type { PathLike } from '@astrale-os/kernel-client/graph';
3
+ import type { GraphMemory } from '@astrale-os/kernel-client/store';
4
+ import type { NavHistory } from './history';
5
+ import type { SerializedLocation } from './history';
6
+ import type { Node, NodeId } from './location';
7
+ /** Everything `navigate()` / `Link` / `initial` accept (API §8.1). */
8
+ export type NavTarget = NodeId | PathLike | Node | AnyBoundNode | {
9
+ node: NodeId | PathLike;
10
+ view?: NodeRefInput;
11
+ params?: Record<string, string>;
12
+ };
13
+ /** Normalize any {@link NavTarget} to its stored, id-anchored serialization. */
14
+ export declare function serializeTarget(target: NavTarget): SerializedLocation;
15
+ /**
16
+ * Revalidate a restored stack against the memory and drop dead entries (API §8.2).
17
+ * Each entry is point-read one-shot; a null/failed read is a dead anchor. The
18
+ * cursor re-lands on the surviving current entry, else the nearest survivor
19
+ * before it.
20
+ */
21
+ export declare function revalidateAndPrune(history: NavHistory, memory: GraphMemory): Promise<void>;
22
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/navigation/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AASlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE9C,sEAAsE;AACtE,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,QAAQ,GACR,IAAI,GACJ,YAAY,GACZ;IAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,YAAY,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAA;AAMrF,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,kBAAkB,CAgBrE;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhG"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * NavSnapshot serialize/restore (API §8.1/§8.2) — the `NavTarget` input space, the
3
+ * `serializeTarget` normalization into the id-anchored stored form, and the
4
+ * restore-time `revalidateAndPrune` that drops dead entries against the memory.
5
+ */
6
+ import { normalizeRef } from '@astrale-os/kernel-client';
7
+ function isRecord(x) {
8
+ return typeof x === 'object' && x !== null;
9
+ }
10
+ /** Normalize any {@link NavTarget} to its stored, id-anchored serialization. */
11
+ export function serializeTarget(target) {
12
+ if (typeof target === 'string')
13
+ return { node: normalizeRef(target) };
14
+ if (isRecord(target) && 'node' in target) {
15
+ const t = target;
16
+ return {
17
+ node: normalizeRef(t.node),
18
+ ...(t.view !== undefined ? { view: normalizeRef(t.view) } : {}),
19
+ ...(t.params !== undefined ? { params: { ...t.params } } : {}),
20
+ };
21
+ }
22
+ // A Node / BoundNode carries `id` (id-anchored, so rename/move survive) and `path`;
23
+ // anything else is a typed `Path` value → its raw address.
24
+ if (isRecord(target) && 'id' in target && 'path' in target) {
25
+ return { node: normalizeRef(target.id) };
26
+ }
27
+ return { node: normalizeRef(target) };
28
+ }
29
+ /**
30
+ * Revalidate a restored stack against the memory and drop dead entries (API §8.2).
31
+ * Each entry is point-read one-shot; a null/failed read is a dead anchor. The
32
+ * cursor re-lands on the surviving current entry, else the nearest survivor
33
+ * before it.
34
+ */
35
+ export async function revalidateAndPrune(history, memory) {
36
+ const { entries, cursor } = history.snapshot();
37
+ const alive = await Promise.all(entries.map((e) => resolves(memory, e.node)));
38
+ if (alive.every(Boolean))
39
+ return;
40
+ const survivors = [];
41
+ let newCursor = -1;
42
+ let fallback = -1;
43
+ entries.forEach((entry, i) => {
44
+ if (!alive[i])
45
+ return;
46
+ survivors.push(entry);
47
+ const idx = survivors.length - 1;
48
+ if (i === cursor)
49
+ newCursor = idx;
50
+ else if (i < cursor)
51
+ fallback = idx;
52
+ });
53
+ if (newCursor === -1)
54
+ newCursor = fallback !== -1 ? fallback : survivors.length > 0 ? 0 : -1;
55
+ history.reset(survivors, newCursor);
56
+ }
57
+ async function resolves(memory, ref) {
58
+ try {
59
+ const result = await memory.query(ref, { live: false });
60
+ return result.node !== null;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
@@ -0,0 +1,37 @@
1
+ import type { OrderInput } from '@astrale-os/kernel-client/graph';
2
+ import type { LiveResult, ShapeInput } from '@astrale-os/kernel-client/store';
3
+ import type { Node } from '@astrale-os/kernel-core';
4
+ import type { Schema } from '@astrale-os/kernel-dsl';
5
+ import { type AnyBoundNode, type BoundNode, type DefOf, type NodeRefInput, type SchemaBoundView, type TypeNames } from '@astrale-os/kernel-client';
6
+ import type { ReadOptions } from '../graph/memory/read/envelope';
7
+ import type { TypedChildrenResult, TypedNodeResult } from './types';
8
+ /** Bind one wire node as `type`; stable while the wire node, binding, and type hold. */
9
+ export declare function useBoundNode<S extends Schema, T extends TypeNames<S>>(binding: SchemaBoundView<S>, type: T, wire: Node | null | undefined): BoundNode<DefOf<S, T>, S> | null;
10
+ /**
11
+ * Bind many wire nodes as `type`; per-node identity + a stable array on no
12
+ * change. `skipMismatch` drops nodes whose class is not `type` (a mixed-class
13
+ * child set) instead of throwing.
14
+ */
15
+ export declare function useBoundNodes<S extends Schema, T extends TypeNames<S>>(binding: SchemaBoundView<S>, type: T, wires: readonly Node[], skipMismatch?: boolean): readonly BoundNode<DefOf<S, T>, S>[];
16
+ /** Bind many wire nodes classlessly (traversal endpoints); per-node + stable array. */
17
+ export declare function useBoundEndpoints<S extends Schema>(binding: SchemaBoundView<S>, wires: readonly Node[]): readonly AnyBoundNode<S>[];
18
+ /** Base read options plus the window growth mode (a `useChildren`-specific extra). */
19
+ export type ShapeOptions = ReadOptions & {
20
+ window?: 'append' | 'paged';
21
+ };
22
+ /**
23
+ * Subscribe to a memory shape. `null` shape → idle (`null`, no I/O). A cold
24
+ * shape suspends unless `suspend: false`. The returned `LiveResult` is the
25
+ * unified read envelope — callers project `node`/`children`/`nodes`.
26
+ */
27
+ export declare function useShape(shape: ShapeInput | null | undefined, opts?: ShapeOptions): LiveResult | null;
28
+ export declare function useNode<S extends Schema, T extends TypeNames<S>>(schema: S, type: T, ref: NodeRefInput | null | undefined, opts?: ReadOptions): TypedNodeResult<S, T>;
29
+ export declare function useChildren<S extends Schema, T extends TypeNames<S>>(parent: AnyBoundNode<S> | null | undefined, opts: ReadOptions & {
30
+ type: T;
31
+ order?: OrderInput;
32
+ limit?: number;
33
+ window?: 'append' | 'paged';
34
+ }): TypedChildrenResult<S, T>;
35
+ /** Recover the schema a BoundNode was bound under; a clear error if it is untagged. */
36
+ export declare function requireSchema(node: object): Schema;
37
+ //# sourceMappingURL=bind-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind-read.d.ts","sourceRoot":"","sources":["../../src/schema/bind-read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,UAAU,EAAe,MAAM,iCAAiC,CAAA;AAC7F,OAAO,KAAK,EACV,UAAU,EAEV,UAAU,EACX,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAEpD,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,SAAS,EACf,MAAM,2BAA2B,CAAA;AAalC,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAiBnE,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,EACnE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAC3B,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAC5B,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAclC;AASD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,EACpE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAC3B,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,YAAY,UAAQ,GACnB,SAAS,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAuBtC;AAQD,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAChD,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAC3B,KAAK,EAAE,SAAS,IAAI,EAAE,GACrB,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,CAiB5B;AAQD,sFAAsF;AACtF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,CAAA;AAkBxE;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACpC,IAAI,CAAC,EAAE,YAAY,GAClB,UAAU,GAAG,IAAI,CA6BnB;AAID,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,EAC9D,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,CAAC,EACP,GAAG,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EACpC,IAAI,CAAC,EAAE,WAAW,GACjB,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAYvB;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,EAClE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EAC1C,IAAI,EAAE,WAAW,GAAG;IAClB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;CAC5B,GACA,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAkC3B;AAwBD,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASlD"}