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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/dist/application/apps/app-host.d.ts +4 -15
  2. package/dist/application/apps/app-host.d.ts.map +1 -1
  3. package/dist/application/apps/app-host.js +1 -1
  4. package/dist/application/apps/apps.hook.d.ts +7 -4
  5. package/dist/application/apps/apps.hook.d.ts.map +1 -1
  6. package/dist/application/apps/apps.hook.js +10 -2
  7. package/dist/application/apps/domains.hook.d.ts +1 -1
  8. package/dist/application/apps/domains.hook.d.ts.map +1 -1
  9. package/dist/application/apps/domains.hook.js +1 -1
  10. package/dist/application/apps/open-app.hook.d.ts +2 -3
  11. package/dist/application/apps/open-app.hook.d.ts.map +1 -1
  12. package/dist/application/index.d.ts +2 -4
  13. package/dist/application/index.d.ts.map +1 -1
  14. package/dist/application/index.js +2 -3
  15. package/dist/application/spaces/space.hook.d.ts +2 -2
  16. package/dist/application/spaces/space.hook.d.ts.map +1 -1
  17. package/dist/application/spaces/space.hook.js +2 -2
  18. package/dist/application/spaces/spaces.hook.d.ts +2 -3
  19. package/dist/application/spaces/spaces.hook.d.ts.map +1 -1
  20. package/dist/application/spaces/spaces.hook.js +10 -3
  21. package/dist/auth/act-as.context.d.ts +15 -32
  22. package/dist/auth/act-as.context.d.ts.map +1 -1
  23. package/dist/auth/act-as.context.js +22 -66
  24. package/dist/auth/auth.hook.d.ts +1 -0
  25. package/dist/auth/auth.hook.d.ts.map +1 -1
  26. package/dist/auth/auth.hook.js +2 -22
  27. package/dist/auth/can.hook.d.ts +10 -38
  28. package/dist/auth/can.hook.d.ts.map +1 -1
  29. package/dist/auth/can.hook.js +35 -110
  30. package/dist/auth/index.d.ts +1 -0
  31. package/dist/auth/index.d.ts.map +1 -1
  32. package/dist/auth/self.hook.d.ts +2 -2
  33. package/dist/auth/self.hook.d.ts.map +1 -1
  34. package/dist/auth/self.hook.js +0 -7
  35. package/dist/auth/session-kernel.d.ts +2 -3
  36. package/dist/auth/session-kernel.d.ts.map +1 -1
  37. package/dist/auth/session-kernel.js +4 -13
  38. package/dist/components/boundaries.d.ts +47 -0
  39. package/dist/components/boundaries.d.ts.map +1 -0
  40. package/dist/components/boundaries.js +55 -0
  41. package/dist/components/can.d.ts +11 -0
  42. package/dist/components/can.d.ts.map +1 -0
  43. package/dist/components/can.js +5 -0
  44. package/dist/components/index.d.ts +7 -0
  45. package/dist/components/index.d.ts.map +1 -0
  46. package/dist/components/index.js +4 -0
  47. package/dist/components/mount-domain-frontend.d.ts +22 -0
  48. package/dist/components/mount-domain-frontend.d.ts.map +1 -0
  49. package/dist/components/mount-domain-frontend.js +85 -0
  50. package/dist/components/view-app.d.ts +16 -0
  51. package/dist/components/view-app.d.ts.map +1 -0
  52. package/dist/components/view-app.js +16 -0
  53. package/dist/graph/call/call.hook.d.ts +8 -18
  54. package/dist/graph/call/call.hook.d.ts.map +1 -1
  55. package/dist/graph/call/call.hook.js +7 -13
  56. package/dist/graph/call/stream.hook.d.ts +12 -20
  57. package/dist/graph/call/stream.hook.d.ts.map +1 -1
  58. package/dist/graph/call/stream.hook.js +55 -111
  59. package/dist/graph/graph.context.d.ts +4 -3
  60. package/dist/graph/graph.context.d.ts.map +1 -1
  61. package/dist/graph/graph.context.js +2 -8
  62. package/dist/graph/guards.error.d.ts +7 -8
  63. package/dist/graph/guards.error.d.ts.map +1 -1
  64. package/dist/graph/guards.error.js +11 -7
  65. package/dist/graph/index.d.ts +8 -16
  66. package/dist/graph/index.d.ts.map +1 -1
  67. package/dist/graph/index.js +3 -7
  68. package/dist/graph/memory/read/envelope.d.ts +22 -54
  69. package/dist/graph/memory/read/envelope.d.ts.map +1 -1
  70. package/dist/graph/memory/read/envelope.js +26 -20
  71. package/dist/graph/memory/read/idle.d.ts +1 -15
  72. package/dist/graph/memory/read/idle.d.ts.map +1 -1
  73. package/dist/graph/memory/read/idle.js +4 -13
  74. package/dist/graph/query-definition.hook.d.ts +11 -0
  75. package/dist/graph/query-definition.hook.d.ts.map +1 -0
  76. package/dist/graph/query-definition.hook.js +205 -0
  77. package/dist/graph/resource.d.ts +34 -0
  78. package/dist/graph/resource.d.ts.map +1 -0
  79. package/dist/graph/resource.js +244 -0
  80. package/dist/graph/store.d.ts +25 -0
  81. package/dist/graph/store.d.ts.map +1 -0
  82. package/dist/graph/store.js +69 -0
  83. package/dist/host/actions.hook.d.ts +34 -0
  84. package/dist/host/actions.hook.d.ts.map +1 -0
  85. package/dist/host/actions.hook.js +125 -0
  86. package/dist/host/components.d.ts +15 -0
  87. package/dist/host/components.d.ts.map +1 -0
  88. package/dist/host/components.js +14 -0
  89. package/dist/host/index.d.ts +5 -0
  90. package/dist/host/index.d.ts.map +1 -0
  91. package/dist/host/index.js +3 -0
  92. package/dist/index.d.ts +26 -37
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +20 -31
  95. package/dist/intents/envelope.d.ts +7 -19
  96. package/dist/intents/envelope.d.ts.map +1 -1
  97. package/dist/intents/envelope.js +2 -3
  98. package/dist/intents/send-intent.hook.d.ts +5 -7
  99. package/dist/intents/send-intent.hook.d.ts.map +1 -1
  100. package/dist/intents/send-intent.hook.js +17 -75
  101. package/dist/navigation/adapters/adapter.d.ts +5 -0
  102. package/dist/navigation/adapters/adapter.d.ts.map +1 -1
  103. package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -1
  104. package/dist/navigation/adapters/memory.adapter.js +4 -0
  105. package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
  106. package/dist/navigation/adapters/url.adapter.js +57 -10
  107. package/dist/navigation/codec.d.ts +60 -0
  108. package/dist/navigation/codec.d.ts.map +1 -0
  109. package/dist/navigation/codec.js +121 -0
  110. package/dist/navigation/history.d.ts +11 -9
  111. package/dist/navigation/history.d.ts.map +1 -1
  112. package/dist/navigation/history.js +6 -8
  113. package/dist/navigation/hooks/ancestors.hook.d.ts +5 -7
  114. package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -1
  115. package/dist/navigation/hooks/ancestors.hook.js +7 -51
  116. package/dist/navigation/hooks/location.hook.d.ts.map +1 -1
  117. package/dist/navigation/hooks/location.hook.js +4 -6
  118. package/dist/navigation/hooks/scope.hook.d.ts.map +1 -1
  119. package/dist/navigation/hooks/scope.hook.js +4 -6
  120. package/dist/navigation/index.d.ts +4 -2
  121. package/dist/navigation/index.d.ts.map +1 -1
  122. package/dist/navigation/index.js +2 -1
  123. package/dist/navigation/link.d.ts +12 -0
  124. package/dist/navigation/link.d.ts.map +1 -1
  125. package/dist/navigation/link.js +13 -2
  126. package/dist/navigation/location.d.ts +13 -40
  127. package/dist/navigation/location.d.ts.map +1 -1
  128. package/dist/navigation/location.js +14 -76
  129. package/dist/navigation/scope.context.d.ts +17 -26
  130. package/dist/navigation/scope.context.d.ts.map +1 -1
  131. package/dist/navigation/scope.context.js +140 -108
  132. package/dist/navigation/snapshot.d.ts +14 -19
  133. package/dist/navigation/snapshot.d.ts.map +1 -1
  134. package/dist/navigation/snapshot.js +48 -44
  135. package/dist/schema/action.hook.d.ts +44 -0
  136. package/dist/schema/action.hook.d.ts.map +1 -0
  137. package/dist/schema/action.hook.js +72 -0
  138. package/dist/schema/domain.hook.d.ts +12 -7
  139. package/dist/schema/domain.hook.d.ts.map +1 -1
  140. package/dist/schema/domain.hook.js +101 -4
  141. package/dist/schema/index.d.ts +9 -8
  142. package/dist/schema/index.d.ts.map +1 -1
  143. package/dist/schema/index.js +5 -7
  144. package/dist/schema/kernel.hook.d.ts +4 -9
  145. package/dist/schema/kernel.hook.d.ts.map +1 -1
  146. package/dist/schema/kernel.hook.js +4 -6
  147. package/dist/schema/mutation.hook.d.ts +9 -0
  148. package/dist/schema/mutation.hook.d.ts.map +1 -0
  149. package/dist/schema/mutation.hook.js +41 -0
  150. package/dist/schema/object.hook.d.ts +16 -0
  151. package/dist/schema/object.hook.d.ts.map +1 -0
  152. package/dist/schema/object.hook.js +46 -0
  153. package/dist/schema/relation.hook.d.ts +46 -0
  154. package/dist/schema/relation.hook.d.ts.map +1 -0
  155. package/dist/schema/relation.hook.js +136 -0
  156. package/dist/selection/live.d.ts +9 -17
  157. package/dist/selection/live.d.ts.map +1 -1
  158. package/dist/selection/live.js +65 -112
  159. package/dist/selection/scope.context.js +5 -4
  160. package/dist/session/boot/boot.d.ts +1 -13
  161. package/dist/session/boot/boot.d.ts.map +1 -1
  162. package/dist/session/boot/boot.js +9 -27
  163. package/dist/session/index.d.ts +1 -0
  164. package/dist/session/index.d.ts.map +1 -1
  165. package/dist/session/kernel-instance.hook.d.ts +1 -4
  166. package/dist/session/kernel-instance.hook.d.ts.map +1 -1
  167. package/dist/session/kernel-instance.hook.js +1 -5
  168. package/dist/session/provider.d.ts +9 -23
  169. package/dist/session/provider.d.ts.map +1 -1
  170. package/dist/session/provider.js +29 -75
  171. package/dist/session/session.context.d.ts +5 -0
  172. package/dist/session/session.context.d.ts.map +1 -1
  173. package/dist/window/adopt.d.ts +0 -1
  174. package/dist/window/adopt.d.ts.map +1 -1
  175. package/dist/window/hooks/target-node.hook.d.ts +10 -6
  176. package/dist/window/hooks/target-node.hook.d.ts.map +1 -1
  177. package/dist/window/hooks/target-node.hook.js +14 -72
  178. package/dist/window/hooks/views-for.hook.d.ts +4 -3
  179. package/dist/window/hooks/views-for.hook.d.ts.map +1 -1
  180. package/dist/window/hooks/views-for.hook.js +6 -22
  181. package/dist/window/hooks/windows.hook.d.ts.map +1 -1
  182. package/dist/window/hooks/windows.hook.js +3 -4
  183. package/dist/window/host.d.ts +9 -11
  184. package/dist/window/host.d.ts.map +1 -1
  185. package/dist/window/host.js +26 -62
  186. package/dist/window/hub.d.ts +2 -0
  187. package/dist/window/hub.d.ts.map +1 -1
  188. package/dist/window/hub.js +33 -0
  189. package/dist/window/index.d.ts +2 -2
  190. package/dist/window/index.d.ts.map +1 -1
  191. package/dist/window/index.js +2 -2
  192. package/dist/window/lifecycle/mount.d.ts +5 -44
  193. package/dist/window/lifecycle/mount.d.ts.map +1 -1
  194. package/dist/window/lifecycle/mount.js +14 -120
  195. package/dist/window/lifecycle/states.d.ts +0 -5
  196. package/dist/window/lifecycle/states.d.ts.map +1 -1
  197. package/package.json +9 -8
  198. package/src/application/apps/app-host.tsx +11 -15
  199. package/src/application/apps/apps.hook.ts +13 -6
  200. package/src/application/apps/domains.hook.ts +1 -1
  201. package/src/application/apps/open-app.hook.ts +3 -4
  202. package/src/application/index.ts +4 -6
  203. package/src/application/spaces/space.hook.ts +5 -6
  204. package/src/application/spaces/spaces.hook.ts +14 -9
  205. package/src/auth/act-as.context.tsx +37 -91
  206. package/src/auth/auth.hook.ts +2 -30
  207. package/src/auth/can.hook.ts +44 -135
  208. package/src/auth/index.ts +1 -0
  209. package/src/auth/self.hook.ts +2 -9
  210. package/src/auth/session-kernel.ts +6 -16
  211. package/src/components/boundaries.tsx +113 -0
  212. package/src/components/can.tsx +16 -0
  213. package/src/components/index.ts +14 -0
  214. package/src/components/mount-domain-frontend.tsx +158 -0
  215. package/src/components/view-app.tsx +49 -0
  216. package/src/graph/call/call.hook.ts +22 -27
  217. package/src/graph/call/stream.hook.ts +66 -143
  218. package/src/graph/graph.context.ts +6 -11
  219. package/src/graph/guards.error.ts +17 -55
  220. package/src/graph/index.ts +23 -17
  221. package/src/graph/memory/read/envelope.ts +40 -65
  222. package/src/graph/memory/read/idle.ts +5 -18
  223. package/src/graph/query-definition.hook.ts +270 -0
  224. package/src/graph/resource.ts +358 -0
  225. package/src/graph/store.ts +97 -0
  226. package/src/host/actions.hook.ts +165 -0
  227. package/src/host/components.tsx +29 -0
  228. package/src/host/index.ts +17 -0
  229. package/src/index.ts +136 -124
  230. package/src/intents/envelope.ts +7 -23
  231. package/src/intents/send-intent.hook.ts +24 -79
  232. package/src/navigation/adapters/adapter.ts +3 -0
  233. package/src/navigation/adapters/memory.adapter.ts +4 -0
  234. package/src/navigation/adapters/url.adapter.ts +48 -8
  235. package/src/navigation/codec.ts +190 -0
  236. package/src/navigation/history.ts +20 -11
  237. package/src/navigation/hooks/ancestors.hook.ts +10 -60
  238. package/src/navigation/hooks/location.hook.ts +4 -6
  239. package/src/navigation/hooks/scope.hook.ts +4 -6
  240. package/src/navigation/index.ts +18 -2
  241. package/src/navigation/link.tsx +27 -2
  242. package/src/navigation/location.ts +26 -93
  243. package/src/navigation/scope.context.tsx +151 -136
  244. package/src/navigation/snapshot.ts +69 -50
  245. package/src/schema/action.hook.ts +146 -0
  246. package/src/schema/domain.hook.ts +127 -11
  247. package/src/schema/index.ts +9 -30
  248. package/src/schema/kernel.hook.ts +6 -13
  249. package/src/schema/mutation.hook.ts +63 -0
  250. package/src/schema/object.hook.ts +85 -0
  251. package/src/schema/relation.hook.ts +253 -0
  252. package/src/selection/live.ts +75 -125
  253. package/src/selection/scope.context.tsx +4 -4
  254. package/src/session/boot/boot.ts +8 -33
  255. package/src/session/index.ts +1 -0
  256. package/src/session/kernel-instance.hook.ts +2 -11
  257. package/src/session/provider.tsx +34 -103
  258. package/src/session/session.context.ts +6 -0
  259. package/src/window/adopt.ts +0 -1
  260. package/src/window/hooks/target-node.hook.ts +20 -85
  261. package/src/window/hooks/views-for.hook.ts +12 -25
  262. package/src/window/hooks/windows.hook.ts +3 -4
  263. package/src/window/host.tsx +35 -77
  264. package/src/window/hub.ts +33 -0
  265. package/src/window/index.ts +3 -3
  266. package/src/window/lifecycle/mount.ts +15 -160
  267. package/src/window/lifecycle/states.ts +1 -5
  268. package/dist/application/roles.hook.d.ts +0 -7
  269. package/dist/application/roles.hook.d.ts.map +0 -1
  270. package/dist/application/roles.hook.js +0 -23
  271. package/dist/graph/memory/base.d.ts +0 -21
  272. package/dist/graph/memory/base.d.ts.map +0 -1
  273. package/dist/graph/memory/base.js +0 -33
  274. package/dist/graph/memory/read/read.d.ts +0 -9
  275. package/dist/graph/memory/read/read.d.ts.map +0 -1
  276. package/dist/graph/memory/read/read.js +0 -87
  277. package/dist/graph/memory/scope.d.ts +0 -7
  278. package/dist/graph/memory/scope.d.ts.map +0 -1
  279. package/dist/graph/memory/scope.js +0 -25
  280. package/dist/graph/mutate/move.hook.d.ts +0 -7
  281. package/dist/graph/mutate/move.hook.d.ts.map +0 -1
  282. package/dist/graph/mutate/move.hook.js +0 -49
  283. package/dist/graph/mutate/mutate.hook.d.ts +0 -17
  284. package/dist/graph/mutate/mutate.hook.d.ts.map +0 -1
  285. package/dist/graph/mutate/mutate.hook.js +0 -45
  286. package/dist/graph/query/children.hook.d.ts +0 -29
  287. package/dist/graph/query/children.hook.d.ts.map +0 -1
  288. package/dist/graph/query/children.hook.js +0 -64
  289. package/dist/graph/query/graph.hook.d.ts +0 -9
  290. package/dist/graph/query/graph.hook.d.ts.map +0 -1
  291. package/dist/graph/query/graph.hook.js +0 -5
  292. package/dist/graph/query/neighbors.hook.d.ts +0 -7
  293. package/dist/graph/query/neighbors.hook.d.ts.map +0 -1
  294. package/dist/graph/query/neighbors.hook.js +0 -104
  295. package/dist/graph/query/node.hook.d.ts +0 -14
  296. package/dist/graph/query/node.hook.d.ts.map +0 -1
  297. package/dist/graph/query/node.hook.js +0 -43
  298. package/dist/graph/query/query.hook.d.ts +0 -14
  299. package/dist/graph/query/query.hook.d.ts.map +0 -1
  300. package/dist/graph/query/query.hook.js +0 -23
  301. package/dist/schema/bind-read.d.ts +0 -37
  302. package/dist/schema/bind-read.d.ts.map +0 -1
  303. package/dist/schema/bind-read.js +0 -205
  304. package/dist/schema/binding.d.ts +0 -21
  305. package/dist/schema/binding.d.ts.map +0 -1
  306. package/dist/schema/binding.js +0 -99
  307. package/dist/schema/function.hook.d.ts +0 -9
  308. package/dist/schema/function.hook.d.ts.map +0 -1
  309. package/dist/schema/function.hook.js +0 -40
  310. package/dist/schema/method.hook.d.ts +0 -14
  311. package/dist/schema/method.hook.d.ts.map +0 -1
  312. package/dist/schema/method.hook.js +0 -49
  313. package/dist/schema/tag.d.ts +0 -11
  314. package/dist/schema/tag.d.ts.map +0 -1
  315. package/dist/schema/tag.js +0 -11
  316. package/dist/schema/types.d.ts +0 -73
  317. package/dist/schema/types.d.ts.map +0 -1
  318. package/dist/schema/types.js +0 -1
  319. package/dist/schema/write.d.ts +0 -16
  320. package/dist/schema/write.d.ts.map +0 -1
  321. package/dist/schema/write.js +0 -56
  322. package/src/application/roles.hook.ts +0 -41
  323. package/src/graph/memory/base.ts +0 -50
  324. package/src/graph/memory/read/read.ts +0 -103
  325. package/src/graph/memory/scope.ts +0 -29
  326. package/src/graph/mutate/move.hook.ts +0 -70
  327. package/src/graph/mutate/mutate.hook.ts +0 -69
  328. package/src/graph/query/children.hook.ts +0 -136
  329. package/src/graph/query/graph.hook.ts +0 -13
  330. package/src/graph/query/neighbors.hook.ts +0 -159
  331. package/src/graph/query/node.hook.ts +0 -83
  332. package/src/graph/query/query.hook.ts +0 -42
  333. package/src/schema/bind-read.ts +0 -319
  334. package/src/schema/binding.ts +0 -146
  335. package/src/schema/function.hook.ts +0 -68
  336. package/src/schema/method.hook.ts +0 -103
  337. package/src/schema/tag.ts +0 -19
  338. package/src/schema/types.ts +0 -150
  339. package/src/schema/write.ts +0 -96
@@ -0,0 +1,205 @@
1
+ import { bindQueries } from '@astrale-os/sdk/query';
2
+ import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
3
+ import { useDynamicDomain } from '../schema/domain.hook.js';
4
+ import { retainRefreshScheduler } from './resource.js';
5
+ import { useGraphStore } from './store.js';
6
+ class DefinitionObserver {
7
+ store;
8
+ binding;
9
+ definition;
10
+ input;
11
+ listeners = new Set();
12
+ subscriptions = Object.freeze([]);
13
+ touched = Object.freeze([]);
14
+ current = Object.freeze({ state: 'loading' });
15
+ generation = 0;
16
+ pending = null;
17
+ started = false;
18
+ rerunQueued = false;
19
+ constructor(store, binding, definition, input) {
20
+ this.store = store;
21
+ this.binding = binding;
22
+ this.definition = definition;
23
+ this.input = input;
24
+ }
25
+ subscribe = (listener) => {
26
+ this.listeners.add(listener);
27
+ return () => this.listeners.delete(listener);
28
+ };
29
+ getSnapshot = () => this.current;
30
+ start() {
31
+ this.started = true;
32
+ void this.run('cached');
33
+ return () => {
34
+ this.started = false;
35
+ this.generation += 1;
36
+ this.subscriptions.forEach((unsubscribe) => unsubscribe());
37
+ this.subscriptions = Object.freeze([]);
38
+ };
39
+ }
40
+ refresh = async () => {
41
+ await this.run('refresh');
42
+ };
43
+ run(freshness) {
44
+ if (this.pending !== null && freshness === 'cached')
45
+ return this.pending;
46
+ const generation = ++this.generation;
47
+ const touched = [];
48
+ this.update({
49
+ state: this.current.data === undefined ? 'loading' : 'refreshing',
50
+ ...(this.current.data === undefined ? {} : { data: this.current.data }),
51
+ });
52
+ const execute = async (ast, options) => {
53
+ touched.push(Object.freeze({ ast, options }));
54
+ return this.store.read(ast, { ...options, freshness });
55
+ };
56
+ const bind = this.binding.$.bind;
57
+ const query = bindQueries(execute, { bind });
58
+ const running = query(this.definition, this.input)
59
+ .then((data) => {
60
+ if (!this.started || generation !== this.generation)
61
+ return;
62
+ this.touched = dedupeShapes(touched);
63
+ this.bindShapes();
64
+ this.update({ state: this.storeState(), data });
65
+ })
66
+ .catch((error) => {
67
+ if (!this.started || generation !== this.generation)
68
+ return;
69
+ this.touched = dedupeShapes(touched);
70
+ this.bindShapes();
71
+ this.update({
72
+ state: 'failed',
73
+ ...(this.current.data === undefined ? {} : { data: this.current.data }),
74
+ error,
75
+ });
76
+ })
77
+ .finally(() => {
78
+ if (this.pending === running)
79
+ this.pending = null;
80
+ });
81
+ this.pending = running;
82
+ return running;
83
+ }
84
+ bindShapes() {
85
+ this.subscriptions.forEach((unsubscribe) => unsubscribe());
86
+ this.subscriptions = Object.freeze(this.touched.map(({ ast, options }) => this.store.subscribe(ast, this.onStoreChange, options)));
87
+ }
88
+ onStoreChange = () => {
89
+ const state = this.storeState();
90
+ this.update({
91
+ state,
92
+ ...(this.current.data === undefined ? {} : { data: this.current.data }),
93
+ ...(this.current.error === undefined ? {} : { error: this.current.error }),
94
+ });
95
+ if ((state === 'ready' || state === 'optimistic') && !this.rerunQueued) {
96
+ this.rerunQueued = true;
97
+ queueMicrotask(() => {
98
+ this.rerunQueued = false;
99
+ if (this.started)
100
+ void this.run('cached');
101
+ });
102
+ }
103
+ };
104
+ storeState() {
105
+ const snapshots = this.touched.map(({ ast, options }) => this.store.getSnapshot(ast, options));
106
+ if (snapshots.length === 0)
107
+ return this.current.state;
108
+ return combine(snapshots);
109
+ }
110
+ update(next) {
111
+ if (next.state === this.current.state &&
112
+ next.data === this.current.data &&
113
+ next.error === this.current.error)
114
+ return;
115
+ this.current = Object.freeze(next);
116
+ this.listeners.forEach((listener) => listener());
117
+ }
118
+ }
119
+ /** Execute one named SDK Query definition exclusively through the current GraphStore. */
120
+ export function useQuery(definition, input, options = {}) {
121
+ const store = useGraphStore();
122
+ const binding = useDynamicDomain();
123
+ const inputIdentity = stableIdentity(input);
124
+ const observer = useMemo(() => (definition === null ? null : new DefinitionObserver(store, binding, definition, input)), [store, binding, definition, inputIdentity]);
125
+ const idle = useMemo(() => Object.freeze({ state: 'idle' }), []);
126
+ const subscribe = useCallback((listener) => observer?.subscribe(listener) ?? (() => { }), [observer]);
127
+ const snapshot = useCallback(() => observer?.getSnapshot() ?? idle, [observer, idle]);
128
+ const current = useSyncExternalStore(subscribe, snapshot, snapshot);
129
+ useEffect(() => observer?.start(), [observer]);
130
+ const identity = definition === null ? 'idle' : `${definition.id}\u0000${inputIdentity}`;
131
+ useEffect(() => {
132
+ if (observer === null || options.refreshInterval === undefined)
133
+ return;
134
+ return retainRefreshScheduler(store, identity, observer.refresh, options.refreshInterval, options.refreshWhen ?? 'visible');
135
+ }, [store, observer, identity, options.refreshInterval, options.refreshWhen]);
136
+ const previousRef = useRef(undefined);
137
+ const previous = options.keepPrevious && previousRef.current?.identity !== identity
138
+ ? previousRef.current
139
+ : undefined;
140
+ useEffect(() => {
141
+ if (current.data !== undefined) {
142
+ previousRef.current = Object.freeze({ identity, data: current.data });
143
+ }
144
+ }, [identity, current.data]);
145
+ return useMemo(() => Object.freeze({
146
+ state: current.state,
147
+ data: current.data,
148
+ error: current.error,
149
+ ...(previous === undefined ? {} : { previous }),
150
+ transitioning: current.state === 'loading' || current.state === 'refreshing',
151
+ live: false,
152
+ sequence: 0,
153
+ refresh: observer?.refresh ?? (() => Promise.resolve()),
154
+ more: Object.freeze({ has: false, pending: false, load: () => Promise.resolve() }),
155
+ }), [current, previous, observer]);
156
+ }
157
+ function dedupeShapes(input) {
158
+ const seen = new Set();
159
+ return Object.freeze(input.filter(({ ast, options }) => {
160
+ const key = `${JSON.stringify(ast)}\u0000${JSON.stringify(options.page)}`;
161
+ if (seen.has(key))
162
+ return false;
163
+ seen.add(key);
164
+ return true;
165
+ }));
166
+ }
167
+ function combine(snapshots) {
168
+ if (snapshots.some((snapshot) => snapshot.state === 'cold'))
169
+ return 'loading';
170
+ for (const state of ['failed', 'loading', 'refreshing', 'optimistic', 'stale']) {
171
+ if (snapshots.some((snapshot) => snapshot.state === state))
172
+ return state;
173
+ }
174
+ return 'ready';
175
+ }
176
+ function stableIdentity(value) {
177
+ const seen = new WeakSet();
178
+ const encode = (input) => {
179
+ if (input === null)
180
+ return ['null'];
181
+ if (typeof input !== 'object') {
182
+ if (typeof input === 'function' || typeof input === 'symbol' || typeof input === 'bigint') {
183
+ throw new TypeError('Query input must be portable and serializable.');
184
+ }
185
+ if (input === undefined)
186
+ return ['undefined'];
187
+ if (typeof input === 'number' && !Number.isFinite(input)) {
188
+ throw new TypeError('Query input numbers must be finite.');
189
+ }
190
+ return [typeof input, input];
191
+ }
192
+ if (seen.has(input))
193
+ throw new TypeError('Query input cannot contain cycles.');
194
+ seen.add(input);
195
+ if (Array.isArray(input))
196
+ return ['array', input.map(encode)];
197
+ return [
198
+ 'object',
199
+ Object.fromEntries(Object.keys(input)
200
+ .sort()
201
+ .map((key) => [key, encode(input[key])])),
202
+ ];
203
+ };
204
+ return JSON.stringify(encode(value));
205
+ }
@@ -0,0 +1,34 @@
1
+ import type { GraphStore, StoreQueryResponse } from '@astrale-os/kernel-client/store';
2
+ import type { QueryAST } from '@astrale-os/sdk/query';
3
+ export type GraphResourceState = 'idle' | 'loading' | 'ready' | 'stale' | 'refreshing' | 'optimistic' | 'failed';
4
+ export interface GraphResource<T> {
5
+ readonly state: GraphResourceState;
6
+ /** Current-scope data only. Previous-scope data is never substituted here. */
7
+ readonly data: T | undefined;
8
+ readonly error: unknown;
9
+ readonly previous?: {
10
+ readonly identity: string;
11
+ readonly data: T;
12
+ };
13
+ readonly transitioning: boolean;
14
+ readonly live: false;
15
+ readonly sequence: 0;
16
+ refresh(): Promise<void>;
17
+ readonly more: {
18
+ readonly has: boolean;
19
+ readonly pending: boolean;
20
+ load(): Promise<void>;
21
+ };
22
+ }
23
+ export interface StoreResourceOptions<Output> {
24
+ readonly identity?: string;
25
+ readonly keepPrevious?: boolean;
26
+ readonly window?: 'page' | 'append';
27
+ readonly merge?: (pages: readonly Output[]) => Output;
28
+ readonly refreshInterval?: number;
29
+ readonly refreshWhen?: 'always' | 'visible';
30
+ }
31
+ /** Adapt exact Store pages into a tear-free React resource without a parallel entity cache. */
32
+ export declare function useStoreResource<Query extends QueryAST, Output>(query: Query | null, pageSize: number, project: (response: StoreQueryResponse<Query>) => Output, options?: StoreResourceOptions<Output>): GraphResource<Output>;
33
+ export declare function retainRefreshScheduler(store: GraphStore, identity: string, refresh: () => Promise<void>, interval: number, when: 'always' | 'visible'): () => void;
34
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/graph/resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAiB,MAAM,iCAAiC,CAAA;AACpG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAMrD,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,GACP,YAAY,GACZ,YAAY,GACZ,QAAQ,CAAA;AAEZ,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;IAClC,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;KAAE,CAAA;IACnE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;IACpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;QACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;QACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KACtB,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB,CAAC,MAAM;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAA;IACrD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAC5C;AAsID,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,QAAQ,EAAE,MAAM,EAC7D,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,MAAM,EACxD,OAAO,GAAE,oBAAoB,CAAC,MAAM,CAAM,GACzC,aAAa,CAAC,MAAM,CAAC,CA2EvB;AAoCD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,GAAG,SAAS,GACzB,MAAM,IAAI,CAkCZ"}
@@ -0,0 +1,244 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
2
+ import { useGraphStore } from './store.js';
3
+ class StoreObserver {
4
+ store;
5
+ query;
6
+ size;
7
+ listeners = new Set();
8
+ pages = Object.freeze([Object.freeze({})]);
9
+ unsubs = Object.freeze([]);
10
+ current;
11
+ morePromise = null;
12
+ started = false;
13
+ constructor(store, query, size) {
14
+ this.store = store;
15
+ this.query = query;
16
+ this.size = size;
17
+ }
18
+ subscribe = (listener) => {
19
+ this.listeners.add(listener);
20
+ return () => this.listeners.delete(listener);
21
+ };
22
+ getSnapshot = () => {
23
+ if (this.current !== undefined)
24
+ return this.current;
25
+ this.current = Object.freeze({
26
+ snapshots: Object.freeze(this.pages.map((page) => this.store.getSnapshot(this.query, this.pageOptions(page)))),
27
+ pendingMore: this.morePromise !== null,
28
+ });
29
+ return this.current;
30
+ };
31
+ start() {
32
+ if (!this.started) {
33
+ this.started = true;
34
+ this.bindPages();
35
+ void this.store
36
+ .read(this.query, {
37
+ ...this.pageOptions(this.pages[0]),
38
+ freshness: 'cached',
39
+ })
40
+ .catch(() => { });
41
+ }
42
+ return () => {
43
+ this.started = false;
44
+ this.unsubs.forEach((unsubscribe) => unsubscribe());
45
+ this.unsubs = Object.freeze([]);
46
+ };
47
+ }
48
+ async refresh() {
49
+ await Promise.all(this.pages.map((page) => this.store.read(this.query, { ...this.pageOptions(page), freshness: 'refresh' })));
50
+ }
51
+ hasMore() {
52
+ const snapshots = this.getSnapshot().snapshots;
53
+ const last = snapshots[snapshots.length - 1];
54
+ const response = last === undefined ? undefined : responseOf(last);
55
+ return response?.page.next !== undefined;
56
+ }
57
+ loadMore() {
58
+ if (this.morePromise !== null)
59
+ return this.morePromise;
60
+ const snapshots = this.getSnapshot().snapshots;
61
+ const last = snapshots[snapshots.length - 1];
62
+ const after = last === undefined ? undefined : responseOf(last)?.page.next;
63
+ if (after === undefined)
64
+ return Promise.resolve();
65
+ if (this.pages.some((page) => page.after === after))
66
+ return Promise.resolve();
67
+ this.pages = Object.freeze([...this.pages, Object.freeze({ after })]);
68
+ this.bindPages();
69
+ this.morePromise = this.store
70
+ .read(this.query, { ...this.pageOptions({ after }), freshness: 'cached' })
71
+ .then(() => { })
72
+ .finally(() => {
73
+ this.morePromise = null;
74
+ this.publish();
75
+ });
76
+ this.publish();
77
+ return this.morePromise;
78
+ }
79
+ pageOptions(page) {
80
+ return Object.freeze({
81
+ page: Object.freeze({
82
+ size: this.size,
83
+ ...(page.after === undefined ? {} : { after: page.after }),
84
+ }),
85
+ });
86
+ }
87
+ bindPages() {
88
+ this.unsubs.forEach((unsubscribe) => unsubscribe());
89
+ this.unsubs = Object.freeze(this.pages.map((page) => this.store.subscribe(this.query, this.publish, this.pageOptions(page))));
90
+ this.publish();
91
+ }
92
+ publish = () => {
93
+ this.current = undefined;
94
+ this.listeners.forEach((listener) => listener());
95
+ };
96
+ }
97
+ const pollers = new WeakMap();
98
+ /** Adapt exact Store pages into a tear-free React resource without a parallel entity cache. */
99
+ export function useStoreResource(query, pageSize, project, options = {}) {
100
+ const store = useGraphStore();
101
+ const observer = useMemo(() => (query === null ? null : new StoreObserver(store, query, positivePage(pageSize))), [store, query, pageSize]);
102
+ const subscribe = useCallback((listener) => (observer === null ? () => { } : observer.subscribe(listener)), [observer]);
103
+ const idle = useMemo(() => Object.freeze({ snapshots: Object.freeze([]), pendingMore: false }), []);
104
+ const getSnapshot = useCallback(() => observer?.getSnapshot() ?? idle, [observer, idle]);
105
+ const current = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
106
+ useEffect(() => observer?.start(), [observer]);
107
+ const pollIdentity = query === null ? null : `${options.identity ?? JSON.stringify(query)}\u0000${pageSize}`;
108
+ useEffect(() => {
109
+ if (query === null || observer === null || options.refreshInterval === undefined)
110
+ return;
111
+ return retainRefreshScheduler(store, pollIdentity, () => observer.refresh(), options.refreshInterval, options.refreshWhen ?? 'visible');
112
+ }, [store, query, observer, pollIdentity, options.refreshInterval, options.refreshWhen]);
113
+ const refresh = useCallback(async () => observer?.refresh(), [observer]);
114
+ const loadMore = useCallback(async () => observer?.loadMore(), [observer]);
115
+ const identity = options.identity ?? pollIdentity ?? 'idle';
116
+ const projected = useMemo(() => {
117
+ const responses = current.snapshots.flatMap((snapshot) => {
118
+ const response = responseOf(snapshot);
119
+ return response === undefined ? [] : [response];
120
+ });
121
+ if (responses.length === 0)
122
+ return undefined;
123
+ const pages = responses.map(project);
124
+ if ((options.window ?? 'page') === 'page')
125
+ return pages[0];
126
+ return options.merge?.(pages) ?? mergeAppendPages(pages);
127
+ }, [current, project, options.window, options.merge]);
128
+ const previousRef = useRef(undefined);
129
+ const prior = previousRef.current;
130
+ const previous = options.keepPrevious && prior !== undefined && prior.identity !== identity ? prior : undefined;
131
+ useEffect(() => {
132
+ if (projected !== undefined)
133
+ previousRef.current = Object.freeze({ identity, data: projected });
134
+ }, [identity, projected]);
135
+ return useMemo(() => {
136
+ const snapshots = current.snapshots;
137
+ const state = query === null ? 'idle' : combinedState(snapshots);
138
+ const failed = snapshots.find((snapshot) => snapshot.state === 'failed');
139
+ return Object.freeze({
140
+ state,
141
+ data: projected,
142
+ ...(failed?.state === 'failed' ? { error: failed.error } : { error: undefined }),
143
+ ...(previous === undefined ? {} : { previous }),
144
+ transitioning: state === 'loading' || state === 'refreshing',
145
+ live: false,
146
+ sequence: 0,
147
+ refresh,
148
+ more: Object.freeze({
149
+ has: observer?.hasMore() ?? false,
150
+ pending: current.pendingMore,
151
+ load: loadMore,
152
+ }),
153
+ });
154
+ }, [current, query, projected, previous, refresh, observer, loadMore]);
155
+ }
156
+ function combinedState(snapshots) {
157
+ if (snapshots.length === 0 || snapshots.some((snapshot) => snapshot.state === 'cold'))
158
+ return 'loading';
159
+ for (const state of ['failed', 'loading', 'refreshing', 'optimistic', 'stale']) {
160
+ if (snapshots.some((snapshot) => snapshot.state === state))
161
+ return state;
162
+ }
163
+ return 'ready';
164
+ }
165
+ function responseOf(snapshot) {
166
+ return 'response' in snapshot ? snapshot.response : undefined;
167
+ }
168
+ function mergeAppendPages(pages) {
169
+ const first = pages[0];
170
+ if (!Array.isArray(first))
171
+ return pages[pages.length - 1];
172
+ const seen = new Set();
173
+ const merged = [];
174
+ for (const page of pages) {
175
+ for (const value of page) {
176
+ const identity = value !== null && typeof value === 'object' && 'id' in value
177
+ ? value.id
178
+ : value;
179
+ if (seen.has(identity))
180
+ continue;
181
+ seen.add(identity);
182
+ merged.push(value);
183
+ }
184
+ }
185
+ return Object.freeze(merged);
186
+ }
187
+ export function retainRefreshScheduler(store, identity, refresh, interval, when) {
188
+ if (!Number.isSafeInteger(interval) || interval < 250) {
189
+ throw new TypeError('refreshInterval must be an integer of at least 250ms.');
190
+ }
191
+ let byIdentity = pollers.get(store);
192
+ if (byIdentity === undefined) {
193
+ byIdentity = new Map();
194
+ pollers.set(store, byIdentity);
195
+ }
196
+ let scheduler = byIdentity.get(identity);
197
+ if (scheduler === undefined) {
198
+ scheduler = { subscribers: new Map(), timer: undefined };
199
+ byIdentity.set(identity, scheduler);
200
+ }
201
+ const token = Symbol(identity);
202
+ scheduler.subscribers.set(token, { interval, when, refresh });
203
+ schedulePoll(scheduler);
204
+ if (typeof document !== 'undefined' && scheduler.onVisibility === undefined) {
205
+ scheduler.onVisibility = () => schedulePoll(scheduler, true);
206
+ document.addEventListener('visibilitychange', scheduler.onVisibility);
207
+ }
208
+ return () => {
209
+ scheduler.subscribers.delete(token);
210
+ if (scheduler.subscribers.size !== 0) {
211
+ schedulePoll(scheduler);
212
+ return;
213
+ }
214
+ if (scheduler.timer !== undefined)
215
+ clearTimeout(scheduler.timer);
216
+ if (typeof document !== 'undefined' && scheduler.onVisibility !== undefined) {
217
+ document.removeEventListener('visibilitychange', scheduler.onVisibility);
218
+ }
219
+ byIdentity.delete(identity);
220
+ if (byIdentity.size === 0)
221
+ pollers.delete(store);
222
+ };
223
+ }
224
+ function schedulePoll(scheduler, immediate = false) {
225
+ if (scheduler.timer !== undefined)
226
+ clearTimeout(scheduler.timer);
227
+ const subscribers = [...scheduler.subscribers.values()];
228
+ if (subscribers.length === 0)
229
+ return;
230
+ const interval = Math.min(...subscribers.map((subscriber) => subscriber.interval));
231
+ scheduler.timer = setTimeout(() => {
232
+ scheduler.timer = undefined;
233
+ const visible = typeof document === 'undefined' || document.visibilityState !== 'hidden';
234
+ const eligible = [...scheduler.subscribers.values()].filter((subscriber) => subscriber.when === 'always' || visible);
235
+ eligible.forEach((subscriber) => void subscriber.refresh().catch(() => { }));
236
+ schedulePoll(scheduler);
237
+ }, immediate ? 0 : interval);
238
+ }
239
+ function positivePage(input) {
240
+ if (!Number.isSafeInteger(input) || input < 1) {
241
+ throw new TypeError('Graph resource page size must be a positive safe integer.');
242
+ }
243
+ return input;
244
+ }
@@ -0,0 +1,25 @@
1
+ import type { GraphApi } from '@astrale-os/kernel-client/graph';
2
+ import type { GraphStore as GraphStoreValue } from '@astrale-os/kernel-client/store';
3
+ import type { Shell } from '@astrale-os/shell';
4
+ interface StoreEntry {
5
+ readonly shell: Shell;
6
+ readonly graph: GraphApi;
7
+ readonly scope: string;
8
+ readonly store: GraphStoreValue;
9
+ readonly owned: boolean;
10
+ retained: number;
11
+ generation: number;
12
+ }
13
+ /** Authority/schema identity. Session ids and Publication ETags are deliberately absent. */
14
+ export interface GraphStoreScope {
15
+ readonly authority: string;
16
+ readonly schemaRevision: string;
17
+ }
18
+ type StoreIdentity = Awaited<ReturnType<Shell['kernel']['auth']['whoami']>>;
19
+ export declare function resolveGraphStoreScope(shell: Shell, knownIdentity?: StoreIdentity | null): Promise<GraphStoreScope>;
20
+ export declare function storeFor(shell: Shell, scope: GraphStoreScope): StoreEntry;
21
+ export declare function retainStore(entry: StoreEntry): () => void;
22
+ /** The exact caller/schema-scoped GraphStore for the current View subtree. */
23
+ export declare function useGraphStore(): GraphStoreValue;
24
+ export {};
25
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/graph/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACpF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAO9C,UAAU,UAAU;IAClB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAID,4FAA4F;AAC5F,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC;AAED,KAAK,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;AAE3E,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,KAAK,EACZ,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,GACnC,OAAO,CAAC,eAAe,CAAC,CAc1B;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,GAAG,UAAU,CAwBzE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,IAAI,CAezD;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,eAAe,CAI/C"}
@@ -0,0 +1,69 @@
1
+ import { GraphStore } from '@astrale-os/kernel-client/store';
2
+ import { useContext } from 'react';
3
+ import { GraphContext } from './graph.context.js';
4
+ const entries = new WeakMap();
5
+ export async function resolveGraphStoreScope(shell, knownIdentity) {
6
+ const [identity, snapshot] = await Promise.all([
7
+ knownIdentity === undefined
8
+ ? shell.kernel.auth.whoami().catch(() => null)
9
+ : Promise.resolve(knownIdentity),
10
+ shell.kernel.snapshot(),
11
+ ]);
12
+ return Object.freeze({
13
+ authority: identity === null
14
+ ? 'anonymous'
15
+ : `${identity.issuer}\u0000${identity.subject}\u0000${identity.id}`,
16
+ schemaRevision: snapshot.publication.schema.revision,
17
+ });
18
+ }
19
+ export function storeFor(shell, scope) {
20
+ const current = entries.get(shell);
21
+ const scopeKey = `${scope.authority}\u0000${scope.schemaRevision}`;
22
+ if (current !== undefined && current.graph === shell.kernel.graph && current.scope === scopeKey) {
23
+ return current;
24
+ }
25
+ const supplied = shell.kernel.store;
26
+ const created = {
27
+ shell,
28
+ graph: shell.kernel.graph,
29
+ scope: scopeKey,
30
+ // A supplied Store is trusted only for the KernelClient's first declared scope. A later
31
+ // authority/revision/GraphApi replacement gets a new Store and cannot inherit old memory.
32
+ store: current === undefined && supplied !== undefined
33
+ ? supplied
34
+ : new GraphStore({ graph: shell.kernel.graph }),
35
+ owned: current !== undefined || supplied === undefined,
36
+ retained: 0,
37
+ generation: 0,
38
+ };
39
+ entries.set(shell, created);
40
+ if (current !== undefined && current.retained === 0 && current.owned)
41
+ current.store.close();
42
+ return created;
43
+ }
44
+ export function retainStore(entry) {
45
+ entry.generation += 1;
46
+ entry.retained += 1;
47
+ let released = false;
48
+ return () => {
49
+ if (released)
50
+ return;
51
+ released = true;
52
+ entry.retained -= 1;
53
+ const generation = ++entry.generation;
54
+ queueMicrotask(() => {
55
+ if (entry.retained !== 0 || entry.generation !== generation || !entry.owned)
56
+ return;
57
+ if (entries.get(entry.shell) === entry)
58
+ entries.delete(entry.shell);
59
+ entry.store.close();
60
+ });
61
+ };
62
+ }
63
+ /** The exact caller/schema-scoped GraphStore for the current View subtree. */
64
+ export function useGraphStore() {
65
+ const store = useContext(GraphContext);
66
+ if (store === null)
67
+ throw new Error('useGraphStore must be used within a <ShellProvider>');
68
+ return store;
69
+ }
@@ -0,0 +1,34 @@
1
+ import type { AccessRequest, AccessResult, ExternalOpenRequest, ExternalOpenResult, HostCapabilities, ModalRequest, ModalResult, NotificationRequest, NotificationResult, OpenViewRequest, OpenViewResult } from '@astrale-os/shell';
2
+ export declare function useHostCapabilities(): HostCapabilities;
3
+ export declare class HostCapabilityUnavailableError extends Error {
4
+ readonly capability: string;
5
+ readonly code: 'SHELL_REACT_HOST_CAPABILITY_UNAVAILABLE';
6
+ constructor(capability: string);
7
+ }
8
+ export interface HostDialogApi {
9
+ readonly supported: boolean;
10
+ open(request: ModalRequest): Promise<ModalResult>;
11
+ confirm(request: Omit<ModalRequest, 'nested'>): Promise<boolean>;
12
+ }
13
+ export declare function useHostDialog(): HostDialogApi;
14
+ export interface NotifyApi {
15
+ (request: NotificationRequest): Promise<NotificationResult>;
16
+ readonly supported: boolean;
17
+ }
18
+ export declare function useNotify(): NotifyApi;
19
+ export interface OpenViewApi {
20
+ (request: OpenViewRequest): Promise<OpenViewResult>;
21
+ readonly supported: boolean;
22
+ }
23
+ export declare function useOpenView(): OpenViewApi;
24
+ export interface ExternalOpenApi {
25
+ (request: ExternalOpenRequest): Promise<ExternalOpenResult>;
26
+ readonly supported: boolean;
27
+ }
28
+ export declare function useExternalOpen(): ExternalOpenApi;
29
+ export interface RequestAccessApi {
30
+ (request: AccessRequest): Promise<AccessResult>;
31
+ readonly supported: boolean;
32
+ }
33
+ export declare function useRequestAccess(): RequestAccessApi;
34
+ //# sourceMappingURL=actions.hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.hook.d.ts","sourceRoot":"","sources":["../../src/host/actions.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACf,MAAM,mBAAmB,CAAA;AAO1B,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD;AAED,qBAAa,8BAA+B,SAAQ,KAAK;IAE3C,QAAQ,CAAC,UAAU,EAAE,MAAM;IADvC,QAAQ,CAAC,IAAI,EAAG,yCAAyC,CAAS;IAClE,YAAqB,UAAU,EAAE,MAAM,EAGtC;CACF;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IACjD,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACjE;AAED,wBAAgB,aAAa,IAAI,aAAa,CAmB7C;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC3D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,SAAS,IAAI,SAAS,CAerC;AAED,MAAM,WAAW,WAAW;IAC1B,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,WAAW,IAAI,WAAW,CAezC;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC3D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,eAAe,IAAI,eAAe,CAejD;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAC/C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,gBAAgB,IAAI,gBAAgB,CAenD"}