@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,45 @@
1
+ const writableCache = new WeakMap();
2
+ export function writableFor(kernel, memory) {
3
+ let entry = writableCache.get(kernel);
4
+ if (entry === undefined) {
5
+ const pathIndex = new Map();
6
+ entry = { writable: withMemoryWrites(kernel, memory, pathIndex), pathIndex };
7
+ writableCache.set(kernel, entry);
8
+ }
9
+ return entry;
10
+ }
11
+ /**
12
+ * Wrap a session view so `updateNode`/`createNode` route through the memory's
13
+ * optimistic write shorthands. `BoundNode.update` addresses a node by `@<id>`,
14
+ * but the memory indexes entities by tree path — so an `@<id>` ref is translated
15
+ * through `pathIndex` (populated at bind time). A ref that is NOT indexed (a node
16
+ * that was never read through a hook) falls back to the raw kernel-client floor:
17
+ * it still dispatches, just without the overlay — matching the imperative floor.
18
+ */
19
+ function withMemoryWrites(kernel, memory, pathIndex) {
20
+ const base = kernel;
21
+ const rawUpdate = base.updateNode.bind(base);
22
+ return {
23
+ ...kernel,
24
+ updateNode: (cls, ref, props) => {
25
+ const path = treePathFor(pathIndex, ref);
26
+ return path !== null ? memory.update(path, props) : rawUpdate(cls, ref, props);
27
+ },
28
+ createNode: (cls, at, props) => memory.create(cls, at, props),
29
+ // Credential rebind stays on the raw kernel-client floor (§6 note).
30
+ as: (cred) => base.as(cred),
31
+ };
32
+ }
33
+ /** The tree path an `@<id>` write ref maps to, via the bind-time index; else null. */
34
+ function treePathFor(pathIndex, ref) {
35
+ if (typeof ref !== 'string' || !ref.startsWith('@'))
36
+ return null;
37
+ return pathIndex.get(ref.slice(1)) ?? null;
38
+ }
39
+ /** Record a bound node's `id → tree path` so the write cap can address it. */
40
+ export function recordPath(pathIndex, node) {
41
+ const n = node;
42
+ if (n !== null && typeof n.id === 'string' && typeof n.path?.raw === 'string') {
43
+ pathIndex.set(n.id, n.path.raw);
44
+ }
45
+ }
@@ -0,0 +1,4 @@
1
+ export { SelectionScope } from './scope.context';
2
+ export type { Selection, SelectionScopeProps } from './scope.context';
3
+ export { useSelection } from './selection.hook';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/selection/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,4 @@
1
+ // selection — API §9. SelectionScope + useSelection: an insertion-ordered id set
2
+ // with an anchor, projected to LIVE memory nodes.
3
+ export { SelectionScope } from './scope.context';
4
+ export { useSelection } from './selection.hook';
@@ -0,0 +1,21 @@
1
+ import type { GraphMemory } from '@astrale-os/kernel-client/store';
2
+ /** A live memory node — the non-null projection of a point read. */
3
+ export type SelectionNode = NonNullable<ReturnType<GraphMemory['getSnapshot']>['node']>;
4
+ export type NodeId = SelectionNode['id'];
5
+ /**
6
+ * The in-scope graph memory, structurally narrowed. Reads the base memory the
7
+ * provider seats in `GraphContext`, defensively so selection also works under a
8
+ * bare/fake context (tests) or before one is mounted.
9
+ */
10
+ export declare function useMemory(): GraphMemory | null;
11
+ export interface LiveSnapshot {
12
+ readonly aliveIds: readonly NodeId[];
13
+ readonly nodes: readonly SelectionNode[];
14
+ }
15
+ /**
16
+ * Subscribe to each id's node shape and project the surviving nodes. The result
17
+ * keeps a stable reference across renders when membership and node identities
18
+ * are unchanged (useSyncExternalStore contract).
19
+ */
20
+ export declare function useLiveNodes(orderedIds: readonly NodeId[], memory: GraphMemory | null): LiveSnapshot;
21
+ //# sourceMappingURL=live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/selection/live.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA2B,MAAM,iCAAiC,CAAA;AAc3F,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AACvF,MAAM,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;AAyBxC;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,WAAW,GAAG,IAAI,CAO9C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;CACzC;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,YAAY,CA4Dd"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Selection liveness (API §9) — resolve the scope's ids to LIVE memory nodes, and
3
+ * the node types the selection speaks. Each id is subscribed as an independent
4
+ * point-read shape; an id drops ONLY once its shape has SETTLED to absence (the
5
+ * fixed latch) — a cold shape whose point-read has not landed is kept alive with
6
+ * no node, so a selection made from a children row is never self-cleared before
7
+ * its fetch resolves. Degrades to no nodes (ids kept) when no memory is in scope.
8
+ */
9
+ import { useCallback, useContext, useRef, useSyncExternalStore } from 'react';
10
+ import { GraphContext } from '../graph/graph.context';
11
+ const LIVE_OPTS = { live: true };
12
+ const EMPTY_NODES = [];
13
+ const NOOP = () => { };
14
+ /** Point-read shape addressing a node by its graph id. */
15
+ function nodeShape(id) {
16
+ return `@${id}`;
17
+ }
18
+ /**
19
+ * A null-node id is a CONFIRMED absence (drop it) only when the shape settled
20
+ * there: it was seen warm and is now gone (deletion), or a live subscription has
21
+ * finished fetching and found nothing (mask/never-existed). A never-warm, not-
22
+ * yet-fetched (cold/pending) shape is NOT absence — the id stays alive, no node.
23
+ */
24
+ function isConfirmedAbsent(snap, id, everWarm) {
25
+ if (everWarm.has(id))
26
+ return true;
27
+ return snap.live === true && snap.pending === false;
28
+ }
29
+ /**
30
+ * The in-scope graph memory, structurally narrowed. Reads the base memory the
31
+ * provider seats in `GraphContext`, defensively so selection also works under a
32
+ * bare/fake context (tests) or before one is mounted.
33
+ */
34
+ export function useMemory() {
35
+ const ctx = useContext(GraphContext);
36
+ return ctx !== null &&
37
+ typeof ctx.subscribe === 'function' &&
38
+ typeof ctx.getSnapshot === 'function'
39
+ ? ctx
40
+ : null;
41
+ }
42
+ function unchanged(prev, aliveIds, nodes) {
43
+ // `aliveIds` and `nodes` can differ in length (a cold id is alive with no node
44
+ // yet), so compare the two lists independently.
45
+ if (prev.aliveIds.length !== aliveIds.length || prev.nodes.length !== nodes.length)
46
+ return false;
47
+ for (let i = 0; i < aliveIds.length; i += 1)
48
+ if (prev.aliveIds[i] !== aliveIds[i])
49
+ return false;
50
+ for (let i = 0; i < nodes.length; i += 1)
51
+ if (prev.nodes[i] !== nodes[i])
52
+ return false;
53
+ return true;
54
+ }
55
+ /**
56
+ * Subscribe to each id's node shape and project the surviving nodes. The result
57
+ * keeps a stable reference across renders when membership and node identities
58
+ * are unchanged (useSyncExternalStore contract).
59
+ */
60
+ export function useLiveNodes(orderedIds, memory) {
61
+ // Stands in for `orderedIds` in the callback deps (a fresh array each render).
62
+ const idsKey = orderedIds.join(' ');
63
+ const cache = useRef(null);
64
+ // Ids whose shape has been seen warm at least once — a later null is a deletion
65
+ // (confirmed absence), whereas a never-warm null is merely cold. Monotonic, so
66
+ // re-reading getSnapshot within a render is idempotent (useSyncExternalStore-safe).
67
+ const everWarm = useRef(new Set());
68
+ const getSnapshot = useCallback(() => {
69
+ let aliveIds;
70
+ let nodes;
71
+ if (memory === null) {
72
+ // No liveness source: keep the ids, resolve no nodes.
73
+ aliveIds = orderedIds;
74
+ nodes = EMPTY_NODES;
75
+ }
76
+ else {
77
+ const seen = everWarm.current;
78
+ const a = [];
79
+ const n = [];
80
+ for (const id of orderedIds) {
81
+ const snap = memory.getSnapshot(nodeShape(id), LIVE_OPTS);
82
+ const node = snap.node;
83
+ if (node !== null) {
84
+ seen.add(id);
85
+ a.push(id);
86
+ n.push(node);
87
+ }
88
+ else if (!isConfirmedAbsent(snap, id, seen)) {
89
+ // Cold / not-yet-fetched: keep the id alive, no node yet — never a
90
+ // premature drop (the critical self-clear this guards against).
91
+ a.push(id);
92
+ }
93
+ // else: settled absence (deleted/masked) → drops from ids and nodes.
94
+ }
95
+ aliveIds = a;
96
+ nodes = n;
97
+ }
98
+ const prev = cache.current;
99
+ if (prev !== null && prev.memory === memory && unchanged(prev.snap, aliveIds, nodes)) {
100
+ return prev.snap;
101
+ }
102
+ const snap = { aliveIds, nodes };
103
+ cache.current = { memory, snap };
104
+ return snap;
105
+ }, [memory, idsKey]);
106
+ const subscribe = useCallback((onStoreChange) => {
107
+ if (memory === null || orderedIds.length === 0)
108
+ return NOOP;
109
+ const unsubs = orderedIds.map((id) => memory.subscribe(nodeShape(id), onStoreChange, LIVE_OPTS));
110
+ return () => {
111
+ for (const unsub of unsubs)
112
+ unsub();
113
+ };
114
+ }, [memory, idsKey]);
115
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
116
+ }
@@ -0,0 +1,26 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import type { NodeId, SelectionNode } from './live';
3
+ /** The value `useSelection()` returns (API §9). */
4
+ export interface Selection {
5
+ /** Selected ids, insertion-ordered. A deleted node drops out. */
6
+ readonly ids: readonly NodeId[];
7
+ /** LIVE nodes for `ids`, same order — a deleted node drops out here too. */
8
+ readonly nodes: readonly SelectionNode[];
9
+ /** Last explicit pick; null when empty or the anchor node is gone. Range math is caller-side. */
10
+ readonly anchor: NodeId | null;
11
+ has(id: NodeId): boolean;
12
+ set(ids: readonly NodeId[]): void;
13
+ add(id: NodeId): void;
14
+ toggle(id: NodeId): void;
15
+ clear(): void;
16
+ }
17
+ export interface SelectionScopeProps {
18
+ /** Seed selection (deduped); read once at mount. */
19
+ initial?: readonly NodeId[];
20
+ /** Fires when the selection changes — explicit ops AND liveness drops. Persist here. */
21
+ onChange?: (ids: readonly NodeId[]) => void;
22
+ children: ReactNode;
23
+ }
24
+ export declare const SelectionContext: import("react").Context<Selection | null>;
25
+ export declare function SelectionScope(props: SelectionScopeProps): ReactElement;
26
+ //# sourceMappingURL=scope.context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.context.d.ts","sourceRoot":"","sources":["../../src/selection/scope.context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAUpD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;AAInD,mDAAmD;AACnD,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IACxC,iGAAiG;IACjG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB,GAAG,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IACjC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAA;IAC3C,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,eAAO,MAAM,gBAAgB,2CAAwC,CAAA;AAsErE,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CA2CvE"}
@@ -0,0 +1,100 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * SelectionScope (API §9) — an insertion-ordered id set with an anchor (the last
4
+ * explicit pick), projected to LIVE memory nodes. A deleted node drops out of
5
+ * `ids`/`nodes`, and the scope re-canonicalizes its stored set to match. Range
6
+ * math stays caller-side (read `anchor`). Seats the selection context.
7
+ */
8
+ import { createContext, useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
9
+ import { useLiveNodes, useMemory } from './live';
10
+ export const SelectionContext = createContext(null);
11
+ SelectionContext.displayName = 'AstraleSelectionContext';
12
+ function dedupe(ids) {
13
+ const seen = new Set();
14
+ const out = [];
15
+ for (const id of ids) {
16
+ if (!seen.has(id)) {
17
+ seen.add(id);
18
+ out.push(id);
19
+ }
20
+ }
21
+ return out;
22
+ }
23
+ function sameIds(a, b) {
24
+ if (a.length !== b.length)
25
+ return false;
26
+ for (let i = 0; i < a.length; i += 1)
27
+ if (a[i] !== b[i])
28
+ return false;
29
+ return true;
30
+ }
31
+ function reducer(state, action) {
32
+ switch (action.t) {
33
+ case 'set': {
34
+ const ids = dedupe(action.ids);
35
+ const anchor = ids.length > 0 ? ids[ids.length - 1] : null;
36
+ if (sameIds(state.ids, ids) && state.anchor === anchor)
37
+ return state;
38
+ return { ids, anchor };
39
+ }
40
+ case 'add': {
41
+ if (state.ids.includes(action.id)) {
42
+ return state.anchor === action.id ? state : { ids: state.ids, anchor: action.id };
43
+ }
44
+ return { ids: [...state.ids, action.id], anchor: action.id };
45
+ }
46
+ case 'toggle': {
47
+ // Toggle-off keeps the anchor (the removed id is no longer a valid pivot).
48
+ if (state.ids.includes(action.id)) {
49
+ return { ids: state.ids.filter((x) => x !== action.id), anchor: state.anchor };
50
+ }
51
+ return { ids: [...state.ids, action.id], anchor: action.id };
52
+ }
53
+ case 'clear':
54
+ return state.ids.length === 0 && state.anchor === null ? state : { ids: [], anchor: null };
55
+ case 'prune': {
56
+ const anchorAlive = state.anchor === null || action.alive.includes(state.anchor);
57
+ if (sameIds(state.ids, action.alive)) {
58
+ return anchorAlive ? state : { ids: state.ids, anchor: null };
59
+ }
60
+ return { ids: action.alive, anchor: anchorAlive ? state.anchor : null };
61
+ }
62
+ }
63
+ }
64
+ function initState(initial) {
65
+ return { ids: dedupe(initial ?? []), anchor: null };
66
+ }
67
+ export function SelectionScope(props) {
68
+ const { initial, onChange, children } = props;
69
+ const [state, dispatch] = useReducer(reducer, initial, initState);
70
+ const memory = useMemory();
71
+ const { aliveIds, nodes } = useLiveNodes(state.ids, memory);
72
+ // Re-canonicalize stored state when liveness drops a node (or its anchor).
73
+ useEffect(() => {
74
+ const anchorDead = state.anchor !== null && !aliveIds.includes(state.anchor);
75
+ if (!sameIds(state.ids, aliveIds) || anchorDead)
76
+ dispatch({ t: 'prune', alive: aliveIds });
77
+ }, [aliveIds, state.ids, state.anchor]);
78
+ // Report changes (explicit ops AND liveness drops), skipping the initial mount.
79
+ const onChangeRef = useRef(onChange);
80
+ onChangeRef.current = onChange;
81
+ const mounted = useRef(false);
82
+ useEffect(() => {
83
+ if (!mounted.current) {
84
+ mounted.current = true;
85
+ return;
86
+ }
87
+ onChangeRef.current?.(aliveIds);
88
+ }, [aliveIds]);
89
+ const set = useCallback((ids) => dispatch({ t: 'set', ids }), []);
90
+ const add = useCallback((id) => dispatch({ t: 'add', id }), []);
91
+ const toggle = useCallback((id) => dispatch({ t: 'toggle', id }), []);
92
+ const clear = useCallback(() => dispatch({ t: 'clear' }), []);
93
+ const aliveSet = useMemo(() => new Set(aliveIds), [aliveIds]);
94
+ const aliveSetRef = useRef(aliveSet);
95
+ aliveSetRef.current = aliveSet;
96
+ const has = useCallback((id) => aliveSetRef.current.has(id), []);
97
+ const anchor = state.anchor !== null && aliveSet.has(state.anchor) ? state.anchor : null;
98
+ const value = useMemo(() => ({ ids: aliveIds, nodes, anchor, has, set, add, toggle, clear }), [aliveIds, nodes, anchor, has, set, add, toggle, clear]);
99
+ return _jsx(SelectionContext.Provider, { value: value, children: children });
100
+ }
@@ -0,0 +1,4 @@
1
+ import type { Selection } from './scope.context';
2
+ /** The nearest selection scope. Throws outside a `<SelectionScope>`. */
3
+ export declare function useSelection(): Selection;
4
+ //# sourceMappingURL=selection.hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.hook.d.ts","sourceRoot":"","sources":["../../src/selection/selection.hook.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAIhD,wEAAwE;AACxE,wBAAgB,YAAY,IAAI,SAAS,CAMxC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * useSelection (API §9) — the nearest selection scope's value (ids/nodes/anchor +
3
+ * has/set/add/toggle/clear). Throws outside a `<SelectionScope>`.
4
+ */
5
+ import { useContext } from 'react';
6
+ import { SelectionContext } from './scope.context';
7
+ /** The nearest selection scope. Throws outside a `<SelectionScope>`. */
8
+ export function useSelection() {
9
+ const selection = useContext(SelectionContext);
10
+ if (selection === null) {
11
+ throw new Error('useSelection must be used within a <SelectionScope>');
12
+ }
13
+ return selection;
14
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The boot machine inputs (API §2): config identity (what triggers a reboot) and
3
+ * whoami resolution (`createShell → init → whoami → OS-user preresolve`). Kept
4
+ * pure of React so the provider's boot effect composes them.
5
+ */
6
+ import type { Shell, ShellConfig } from '@astrale-os/shell';
7
+ import type { SelfNode } from '../session.context';
8
+ export declare function isShellConfig(config: ShellConfig | Shell): config is ShellConfig;
9
+ /**
10
+ * Identity of a config — primitive fields only, so re-passing an inline `fetch`,
11
+ * `adapter`, `getCredential`, or `parentWindow` each render does not reboot;
12
+ * changing the kernel/credential does. A principal switch driven by a NEW
13
+ * `getCredential` closure (rather than a new `credential` string) is therefore
14
+ * NOT observed here — remount the provider (React `key`) to rebind it.
15
+ */
16
+ export declare function configIdentity(config: ShellConfig | Shell): string;
17
+ /** Resolve whoami when the bound kernel exposes an auth surface; else null. */
18
+ export declare function resolveSelf(shell: Shell): Promise<SelfNode | null>;
19
+ //# sourceMappingURL=boot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../../src/session/boot/boot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAElD,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,GAAG,MAAM,IAAI,WAAW,CAEhF;AAeD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,GAAG,MAAM,CAYlE;AAED,+EAA+E;AAC/E,wBAAsB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAQxE"}
@@ -0,0 +1,45 @@
1
+ export function isShellConfig(config) {
2
+ return 'mode' in config;
3
+ }
4
+ let prebuiltCounter = 0;
5
+ const prebuiltIds = new WeakMap();
6
+ /** Stable id per prebuilt-Shell object reference (a new object reboots). */
7
+ function prebuiltId(shell) {
8
+ let id = prebuiltIds.get(shell);
9
+ if (id === undefined) {
10
+ prebuiltCounter += 1;
11
+ id = `prebuilt#${prebuiltCounter}`;
12
+ prebuiltIds.set(shell, id);
13
+ }
14
+ return id;
15
+ }
16
+ /**
17
+ * Identity of a config — primitive fields only, so re-passing an inline `fetch`,
18
+ * `adapter`, `getCredential`, or `parentWindow` each render does not reboot;
19
+ * changing the kernel/credential does. A principal switch driven by a NEW
20
+ * `getCredential` closure (rather than a new `credential` string) is therefore
21
+ * NOT observed here — remount the provider (React `key`) to rebind it.
22
+ */
23
+ export function configIdentity(config) {
24
+ if (!isShellConfig(config))
25
+ return prebuiltId(config);
26
+ if (config.mode === 'standalone') {
27
+ return [
28
+ 'standalone',
29
+ config.kernelUrl,
30
+ config.credential ?? '',
31
+ config.mintIdentity ?? '',
32
+ config.windowId ?? '',
33
+ ].join('|');
34
+ }
35
+ return `sandboxed|${config.initTimeoutMs ?? ''}`;
36
+ }
37
+ /** Resolve whoami when the bound kernel exposes an auth surface; else null. */
38
+ export async function resolveSelf(shell) {
39
+ const kernel = shell.kernel;
40
+ const auth = kernel.auth;
41
+ const whoami = auth?.whoami;
42
+ if (typeof whoami !== 'function')
43
+ return null;
44
+ return whoami.call(auth);
45
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * StrictMode/HMR single-ownership + deferred teardown (API §2). A booted shell's
3
+ * dispose is deferred one macrotask keyed by the SHELL object, so a synchronous
4
+ * re-mount (StrictMode/HMR, or a different provider reusing a prebuilt Shell)
5
+ * adopts the same shell by cancelling the pending dispose before it fires.
6
+ */
7
+ import type { Shell } from '@astrale-os/shell';
8
+ export interface BootRef {
9
+ key: string | null;
10
+ shell: Shell | null;
11
+ /** Bumped per boot attempt; an in-flight init/whoami whose generation is stale is ignored. */
12
+ generation: number;
13
+ }
14
+ export declare function cancelTeardown(shell: Shell): void;
15
+ /** Defer a shell's dispose one macrotask, resetting the owning ref when it fires. */
16
+ export declare function scheduleTeardown(shell: Shell, ref: BootRef): void;
17
+ export declare function disposeShell(shell: Shell): void;
18
+ //# sourceMappingURL=ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownership.d.ts","sourceRoot":"","sources":["../../../src/session/boot/ownership.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,8FAA8F;IAC9F,UAAU,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAMjD;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAUjE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAQ/C"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Pending deferred teardowns keyed by the SHELL object (not the provider): a new
3
+ * adopter of the same shell — a StrictMode/HMR re-setup, OR a different provider
4
+ * instance reusing a prebuilt Shell — cancels the pending dispose before it
5
+ * fires, so the old provider's timer can never dispose a shell the new one just
6
+ * adopted. Config-built shells are unique per boot, so they never collide here.
7
+ */
8
+ const pendingTeardowns = new WeakMap();
9
+ export function cancelTeardown(shell) {
10
+ const timer = pendingTeardowns.get(shell);
11
+ if (timer !== undefined) {
12
+ clearTimeout(timer);
13
+ pendingTeardowns.delete(shell);
14
+ }
15
+ }
16
+ /** Defer a shell's dispose one macrotask, resetting the owning ref when it fires. */
17
+ export function scheduleTeardown(shell, ref) {
18
+ cancelTeardown(shell);
19
+ const timer = setTimeout(() => {
20
+ pendingTeardowns.delete(shell);
21
+ ref.generation += 1;
22
+ disposeShell(shell);
23
+ if (ref.shell === shell)
24
+ ref.shell = null;
25
+ ref.key = null;
26
+ }, 0);
27
+ pendingTeardowns.set(shell, timer);
28
+ }
29
+ export function disposeShell(shell) {
30
+ // Best-effort: dispose never rejects meaningfully for a booted shell.
31
+ try {
32
+ const result = shell.dispose();
33
+ if (result instanceof Promise)
34
+ result.catch(() => undefined);
35
+ }
36
+ catch {
37
+ /* swallow — teardown must not throw */
38
+ }
39
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * BootStatus union + transitions (API §2). The provider's boot state machine:
3
+ * `connecting → ready` (with the resolved runtime) or `connecting → error`. The
4
+ * reducer is the single transition table children render behind.
5
+ */
6
+ import type { ShellRuntime } from '../session.context';
7
+ export type BootStatus = 'connecting' | 'ready' | 'error';
8
+ export interface BootState {
9
+ readonly status: BootStatus;
10
+ readonly error: unknown;
11
+ readonly runtime: ShellRuntime | null;
12
+ }
13
+ export type BootAction = {
14
+ readonly type: 'connecting';
15
+ } | {
16
+ readonly type: 'ready';
17
+ readonly runtime: ShellRuntime;
18
+ } | {
19
+ readonly type: 'error';
20
+ readonly error: unknown;
21
+ };
22
+ export declare const INITIAL_BOOT: BootState;
23
+ export declare function bootReducer(state: BootState, action: BootAction): BootState;
24
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/session/boot/status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,OAAO,GAAG,OAAO,CAAA;AAEzD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;CACtC;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAEvD,eAAO,MAAM,YAAY,EAAE,SAAqE,CAAA;AAEhG,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAS3E"}
@@ -0,0 +1,11 @@
1
+ export const INITIAL_BOOT = { status: 'connecting', error: undefined, runtime: null };
2
+ export function bootReducer(state, action) {
3
+ switch (action.type) {
4
+ case 'connecting':
5
+ return state.status === 'connecting' && state.runtime === null ? state : INITIAL_BOOT;
6
+ case 'ready':
7
+ return { status: 'ready', error: undefined, runtime: action.runtime };
8
+ case 'error':
9
+ return { status: 'error', error: action.error, runtime: null };
10
+ }
11
+ }
@@ -0,0 +1,3 @@
1
+ import type { ConnectionValue } from './connection.store';
2
+ export declare function useConnection(): ConnectionValue;
3
+ //# sourceMappingURL=connection.hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.hook.d.ts","sourceRoot":"","sources":["../../../src/session/connection/connection.hook.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKzD,wBAAgB,aAAa,IAAI,eAAe,CAG/C"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * useConnection (API §3) — transport status + memory journal position + retry.
3
+ * Reads the provider-owned connection store for the subtree's Shell via
4
+ * `useSyncExternalStore` (rule 3). Throws outside a `<ShellProvider>`.
5
+ */
6
+ import { useSyncExternalStore } from 'react';
7
+ import { useShell } from '../shell.hook';
8
+ import { connectionStore } from './connection.store';
9
+ export function useConnection() {
10
+ const store = connectionStore(useShell());
11
+ return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
12
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The connection store (API §3, rule 3). ONE per Shell — the provider owns it and
3
+ * registers its `retry`; `useConnection` reads it via `useSyncExternalStore` so
4
+ * connection churn re-renders only its subscribers. `status`/`seq` are a pinned
5
+ * stub ('ready'/0) until the transport-status + result-`seq` feed lands (G6).
6
+ */
7
+ import type { Shell } from '@astrale-os/shell';
8
+ export type ConnectionStatus = 'connecting' | 'ready' | 'reconnecting' | 'error';
9
+ /** Transport + memory-journal status for the subtree (API §3). */
10
+ export interface ConnectionValue {
11
+ readonly status: ConnectionStatus;
12
+ readonly error: unknown;
13
+ readonly seq: number;
14
+ retry(): void;
15
+ }
16
+ export interface ConnectionStore {
17
+ subscribe(cb: () => void): () => void;
18
+ getSnapshot(): ConnectionValue;
19
+ /** The provider registers its boot-retry here; a change re-stamps the snapshot. */
20
+ setRetry(retry: () => void): void;
21
+ }
22
+ /** The one connection store for a Shell (created on first touch). */
23
+ export declare function connectionStore(shell: Shell): ConnectionStore;
24
+ //# sourceMappingURL=connection.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.store.d.ts","sourceRoot":"","sources":["../../../src/session/connection/connection.store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,OAAO,GAAG,cAAc,GAAG,OAAO,CAAA;AAEhF,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IACrC,WAAW,IAAI,eAAe,CAAA;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CAClC;AA0BD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,eAAe,CAO7D"}
@@ -0,0 +1,31 @@
1
+ const NOOP_RETRY = () => { };
2
+ function createConnectionStore() {
3
+ const listeners = new Set();
4
+ let retry = NOOP_RETRY;
5
+ let snapshot = { status: 'ready', error: undefined, seq: 0, retry };
6
+ return {
7
+ subscribe(cb) {
8
+ listeners.add(cb);
9
+ return () => listeners.delete(cb);
10
+ },
11
+ getSnapshot: () => snapshot,
12
+ setRetry(next) {
13
+ if (next === retry)
14
+ return;
15
+ retry = next;
16
+ snapshot = { status: snapshot.status, error: snapshot.error, seq: snapshot.seq, retry };
17
+ for (const l of listeners)
18
+ l();
19
+ },
20
+ };
21
+ }
22
+ const stores = new WeakMap();
23
+ /** The one connection store for a Shell (created on first touch). */
24
+ export function connectionStore(shell) {
25
+ let s = stores.get(shell);
26
+ if (s === undefined) {
27
+ s = createConnectionStore();
28
+ stores.set(shell, s);
29
+ }
30
+ return s;
31
+ }
@@ -0,0 +1,8 @@
1
+ export { ShellProvider } from './provider';
2
+ export type { ShellError, ShellProviderProps } from './provider';
3
+ export { useShell } from './shell.hook';
4
+ export { useKernelClient } from './kernel-client.hook';
5
+ export { useKernelInstance } from './kernel-instance.hook';
6
+ export type { KernelInstance } from './kernel-instance.hook';
7
+ export { useConnection } from './connection/connection.hook';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA"}
@@ -0,0 +1,6 @@
1
+ // session — API §2 (provider) + §3 (session hooks). See SHELL_REACT_API.md.
2
+ export { ShellProvider } from './provider';
3
+ export { useShell } from './shell.hook';
4
+ export { useKernelClient } from './kernel-client.hook';
5
+ export { useKernelInstance } from './kernel-instance.hook';
6
+ export { useConnection } from './connection/connection.hook';