@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.
- package/LICENSE +202 -0
- package/dist/application/apps/app-host.d.ts +31 -0
- package/dist/application/apps/app-host.d.ts.map +1 -0
- package/dist/application/apps/app-host.js +59 -0
- package/dist/application/apps/app-logo.d.ts +19 -0
- package/dist/application/apps/app-logo.d.ts.map +1 -0
- package/dist/application/apps/app-logo.js +31 -0
- package/dist/application/apps/apps.hook.d.ts +12 -0
- package/dist/application/apps/apps.hook.d.ts.map +1 -0
- package/dist/application/apps/apps.hook.js +51 -0
- package/dist/application/apps/open-app.hook.d.ts +10 -0
- package/dist/application/apps/open-app.hook.d.ts.map +1 -0
- package/dist/application/apps/open-app.hook.js +7 -0
- package/dist/application/index.d.ts +18 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/index.js +12 -0
- package/dist/application/roles.hook.d.ts +7 -0
- package/dist/application/roles.hook.d.ts.map +1 -0
- package/dist/application/roles.hook.js +23 -0
- package/dist/application/spaces/current-space.hook.d.ts +7 -0
- package/dist/application/spaces/current-space.hook.d.ts.map +1 -0
- package/dist/application/spaces/current-space.hook.js +27 -0
- package/dist/application/spaces/current-space.store.d.ts +32 -0
- package/dist/application/spaces/current-space.store.d.ts.map +1 -0
- package/dist/application/spaces/current-space.store.js +79 -0
- package/dist/application/spaces/space.hook.d.ts +5 -0
- package/dist/application/spaces/space.hook.d.ts.map +1 -0
- package/dist/application/spaces/space.hook.js +25 -0
- package/dist/application/spaces/spaces.hook.d.ts +14 -0
- package/dist/application/spaces/spaces.hook.d.ts.map +1 -0
- package/dist/application/spaces/spaces.hook.js +82 -0
- package/dist/application/user/user.hook.d.ts +10 -0
- package/dist/application/user/user.hook.d.ts.map +1 -0
- package/dist/application/user/user.hook.js +19 -0
- package/dist/application/user/user.store.d.ts +35 -0
- package/dist/application/user/user.store.d.ts.map +1 -0
- package/dist/application/user/user.store.js +51 -0
- package/dist/auth/act-as.context.d.ts +40 -0
- package/dist/auth/act-as.context.d.ts.map +1 -0
- package/dist/auth/act-as.context.js +84 -0
- package/dist/auth/auth.hook.d.ts +3 -0
- package/dist/auth/auth.hook.d.ts.map +1 -0
- package/dist/auth/auth.hook.js +25 -0
- package/dist/auth/can.hook.d.ts +40 -0
- package/dist/auth/can.hook.d.ts.map +1 -0
- package/dist/auth/can.hook.js +119 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/self.hook.d.ts +3 -0
- package/dist/auth/self.hook.d.ts.map +1 -0
- package/dist/auth/self.hook.js +11 -0
- package/dist/auth/session-kernel.d.ts +4 -0
- package/dist/auth/session-kernel.d.ts.map +1 -0
- package/dist/auth/session-kernel.js +21 -0
- package/dist/graph/action.d.ts +22 -0
- package/dist/graph/action.d.ts.map +1 -0
- package/dist/graph/action.js +85 -0
- package/dist/graph/async.d.ts +11 -0
- package/dist/graph/async.d.ts.map +1 -0
- package/dist/graph/async.js +60 -0
- package/dist/graph/call/call.hook.d.ts +21 -0
- package/dist/graph/call/call.hook.d.ts.map +1 -0
- package/dist/graph/call/call.hook.js +23 -0
- package/dist/graph/call/stream.hook.d.ts +28 -0
- package/dist/graph/call/stream.hook.d.ts.map +1 -0
- package/dist/graph/call/stream.hook.js +137 -0
- package/dist/graph/graph.context.d.ts +4 -0
- package/dist/graph/graph.context.d.ts.map +1 -0
- package/dist/graph/graph.context.js +10 -0
- package/dist/graph/guards.error.d.ts +9 -0
- package/dist/graph/guards.error.d.ts.map +1 -0
- package/dist/graph/guards.error.js +7 -0
- package/dist/graph/index.d.ts +20 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +9 -0
- package/dist/graph/memory/base.d.ts +21 -0
- package/dist/graph/memory/base.d.ts.map +1 -0
- package/dist/graph/memory/base.js +33 -0
- package/dist/graph/memory/read/envelope.d.ts +71 -0
- package/dist/graph/memory/read/envelope.d.ts.map +1 -0
- package/dist/graph/memory/read/envelope.js +29 -0
- package/dist/graph/memory/read/idle.d.ts +18 -0
- package/dist/graph/memory/read/idle.d.ts.map +1 -0
- package/dist/graph/memory/read/idle.js +16 -0
- package/dist/graph/memory/read/read.d.ts +9 -0
- package/dist/graph/memory/read/read.d.ts.map +1 -0
- package/dist/graph/memory/read/read.js +87 -0
- package/dist/graph/memory/scope.d.ts +7 -0
- package/dist/graph/memory/scope.d.ts.map +1 -0
- package/dist/graph/memory/scope.js +25 -0
- package/dist/graph/mutate/move.hook.d.ts +7 -0
- package/dist/graph/mutate/move.hook.d.ts.map +1 -0
- package/dist/graph/mutate/move.hook.js +49 -0
- package/dist/graph/mutate/mutate.hook.d.ts +17 -0
- package/dist/graph/mutate/mutate.hook.d.ts.map +1 -0
- package/dist/graph/mutate/mutate.hook.js +45 -0
- package/dist/graph/query/children.hook.d.ts +29 -0
- package/dist/graph/query/children.hook.d.ts.map +1 -0
- package/dist/graph/query/children.hook.js +64 -0
- package/dist/graph/query/graph.hook.d.ts +9 -0
- package/dist/graph/query/graph.hook.d.ts.map +1 -0
- package/dist/graph/query/graph.hook.js +5 -0
- package/dist/graph/query/neighbors.hook.d.ts +7 -0
- package/dist/graph/query/neighbors.hook.d.ts.map +1 -0
- package/dist/graph/query/neighbors.hook.js +79 -0
- package/dist/graph/query/node.hook.d.ts +14 -0
- package/dist/graph/query/node.hook.d.ts.map +1 -0
- package/dist/graph/query/node.hook.js +43 -0
- package/dist/graph/query/query.hook.d.ts +14 -0
- package/dist/graph/query/query.hook.d.ts.map +1 -0
- package/dist/graph/query/query.hook.js +23 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/intents/envelope.d.ts +33 -0
- package/dist/intents/envelope.d.ts.map +1 -0
- package/dist/intents/envelope.js +19 -0
- package/dist/intents/index.d.ts +6 -0
- package/dist/intents/index.d.ts.map +1 -0
- package/dist/intents/index.js +3 -0
- package/dist/intents/listen-intent.hook.d.ts +16 -0
- package/dist/intents/listen-intent.hook.d.ts.map +1 -0
- package/dist/intents/listen-intent.hook.js +75 -0
- package/dist/intents/reply.d.ts +9 -0
- package/dist/intents/reply.d.ts.map +1 -0
- package/dist/intents/reply.js +14 -0
- package/dist/intents/send-intent.hook.d.ts +12 -0
- package/dist/intents/send-intent.hook.d.ts.map +1 -0
- package/dist/intents/send-intent.hook.js +86 -0
- package/dist/navigation/adapters/adapter.d.ts +15 -0
- package/dist/navigation/adapters/adapter.d.ts.map +1 -0
- package/dist/navigation/adapters/adapter.js +1 -0
- package/dist/navigation/adapters/memory.adapter.d.ts +9 -0
- package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -0
- package/dist/navigation/adapters/memory.adapter.js +15 -0
- package/dist/navigation/adapters/url.adapter.d.ts +6 -0
- package/dist/navigation/adapters/url.adapter.d.ts.map +1 -0
- package/dist/navigation/adapters/url.adapter.js +59 -0
- package/dist/navigation/history.d.ts +63 -0
- package/dist/navigation/history.d.ts.map +1 -0
- package/dist/navigation/history.js +144 -0
- package/dist/navigation/hooks/ancestors.hook.d.ts +13 -0
- package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -0
- package/dist/navigation/hooks/ancestors.hook.js +56 -0
- package/dist/navigation/hooks/location.hook.d.ts +4 -0
- package/dist/navigation/hooks/location.hook.d.ts.map +1 -0
- package/dist/navigation/hooks/location.hook.js +17 -0
- package/dist/navigation/hooks/navigate.hook.d.ts +12 -0
- package/dist/navigation/hooks/navigate.hook.d.ts.map +1 -0
- package/dist/navigation/hooks/navigate.hook.js +33 -0
- package/dist/navigation/hooks/scope.hook.d.ts +12 -0
- package/dist/navigation/hooks/scope.hook.d.ts.map +1 -0
- package/dist/navigation/hooks/scope.hook.js +21 -0
- package/dist/navigation/index.d.ts +16 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +10 -0
- package/dist/navigation/link.d.ts +11 -0
- package/dist/navigation/link.d.ts.map +1 -0
- package/dist/navigation/link.js +62 -0
- package/dist/navigation/location.d.ts +48 -0
- package/dist/navigation/location.d.ts.map +1 -0
- package/dist/navigation/location.js +88 -0
- package/dist/navigation/scope.context.d.ts +64 -0
- package/dist/navigation/scope.context.d.ts.map +1 -0
- package/dist/navigation/scope.context.js +178 -0
- package/dist/navigation/snapshot.d.ts +22 -0
- package/dist/navigation/snapshot.d.ts.map +1 -0
- package/dist/navigation/snapshot.js +65 -0
- package/dist/schema/bind-read.d.ts +37 -0
- package/dist/schema/bind-read.d.ts.map +1 -0
- package/dist/schema/bind-read.js +205 -0
- package/dist/schema/binding.d.ts +21 -0
- package/dist/schema/binding.d.ts.map +1 -0
- package/dist/schema/binding.js +55 -0
- package/dist/schema/domain.hook.d.ts +10 -0
- package/dist/schema/domain.hook.d.ts.map +1 -0
- package/dist/schema/domain.hook.js +7 -0
- package/dist/schema/function.hook.d.ts +9 -0
- package/dist/schema/function.hook.d.ts.map +1 -0
- package/dist/schema/function.hook.js +40 -0
- package/dist/schema/index.d.ts +10 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +8 -0
- package/dist/schema/kernel.hook.d.ts +10 -0
- package/dist/schema/kernel.hook.d.ts.map +1 -0
- package/dist/schema/kernel.hook.js +8 -0
- package/dist/schema/method.hook.d.ts +14 -0
- package/dist/schema/method.hook.d.ts.map +1 -0
- package/dist/schema/method.hook.js +49 -0
- package/dist/schema/tag.d.ts +11 -0
- package/dist/schema/tag.d.ts.map +1 -0
- package/dist/schema/tag.js +11 -0
- package/dist/schema/types.d.ts +73 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +1 -0
- package/dist/schema/write.d.ts +15 -0
- package/dist/schema/write.d.ts.map +1 -0
- package/dist/schema/write.js +45 -0
- package/dist/selection/index.d.ts +4 -0
- package/dist/selection/index.d.ts.map +1 -0
- package/dist/selection/index.js +4 -0
- package/dist/selection/live.d.ts +21 -0
- package/dist/selection/live.d.ts.map +1 -0
- package/dist/selection/live.js +116 -0
- package/dist/selection/scope.context.d.ts +26 -0
- package/dist/selection/scope.context.d.ts.map +1 -0
- package/dist/selection/scope.context.js +100 -0
- package/dist/selection/selection.hook.d.ts +4 -0
- package/dist/selection/selection.hook.d.ts.map +1 -0
- package/dist/selection/selection.hook.js +14 -0
- package/dist/session/boot/boot.d.ts +19 -0
- package/dist/session/boot/boot.d.ts.map +1 -0
- package/dist/session/boot/boot.js +45 -0
- package/dist/session/boot/ownership.d.ts +18 -0
- package/dist/session/boot/ownership.d.ts.map +1 -0
- package/dist/session/boot/ownership.js +39 -0
- package/dist/session/boot/status.d.ts +24 -0
- package/dist/session/boot/status.d.ts.map +1 -0
- package/dist/session/boot/status.js +11 -0
- package/dist/session/connection/connection.hook.d.ts +3 -0
- package/dist/session/connection/connection.hook.d.ts.map +1 -0
- package/dist/session/connection/connection.hook.js +12 -0
- package/dist/session/connection/connection.store.d.ts +24 -0
- package/dist/session/connection/connection.store.d.ts.map +1 -0
- package/dist/session/connection/connection.store.js +31 -0
- package/dist/session/index.d.ts +8 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +6 -0
- package/dist/session/kernel-client.hook.d.ts +9 -0
- package/dist/session/kernel-client.hook.d.ts.map +1 -0
- package/dist/session/kernel-client.hook.js +5 -0
- package/dist/session/kernel-instance.hook.d.ts +9 -0
- package/dist/session/kernel-instance.hook.d.ts.map +1 -0
- package/dist/session/kernel-instance.hook.js +10 -0
- package/dist/session/provider.d.ts +31 -0
- package/dist/session/provider.d.ts.map +1 -0
- package/dist/session/provider.js +165 -0
- package/dist/session/session.context.d.ts +18 -0
- package/dist/session/session.context.d.ts.map +1 -0
- package/dist/session/session.context.js +8 -0
- package/dist/session/shell.hook.d.ts +4 -0
- package/dist/session/shell.hook.d.ts.map +1 -0
- package/dist/session/shell.hook.js +15 -0
- package/dist/window/adopt.d.ts +27 -0
- package/dist/window/adopt.d.ts.map +1 -0
- package/dist/window/adopt.js +27 -0
- package/dist/window/hooks/close-guard.hook.d.ts +6 -0
- package/dist/window/hooks/close-guard.hook.d.ts.map +1 -0
- package/dist/window/hooks/close-guard.hook.js +90 -0
- package/dist/window/hooks/target-node.hook.d.ts +7 -0
- package/dist/window/hooks/target-node.hook.d.ts.map +1 -0
- package/dist/window/hooks/target-node.hook.js +77 -0
- package/dist/window/hooks/views-for.hook.d.ts +8 -0
- package/dist/window/hooks/views-for.hook.d.ts.map +1 -0
- package/dist/window/hooks/views-for.hook.js +51 -0
- package/dist/window/hooks/window.hook.d.ts +4 -0
- package/dist/window/hooks/window.hook.d.ts.map +1 -0
- package/dist/window/hooks/window.hook.js +14 -0
- package/dist/window/hooks/windows.hook.d.ts +15 -0
- package/dist/window/hooks/windows.hook.d.ts.map +1 -0
- package/dist/window/hooks/windows.hook.js +25 -0
- package/dist/window/host.d.ts +31 -0
- package/dist/window/host.d.ts.map +1 -0
- package/dist/window/host.js +270 -0
- package/dist/window/hub.d.ts +41 -0
- package/dist/window/hub.d.ts.map +1 -0
- package/dist/window/hub.js +100 -0
- package/dist/window/index.d.ts +15 -0
- package/dist/window/index.d.ts.map +1 -0
- package/dist/window/index.js +10 -0
- package/dist/window/lifecycle/mount.d.ts +47 -0
- package/dist/window/lifecycle/mount.d.ts.map +1 -0
- package/dist/window/lifecycle/mount.js +92 -0
- package/dist/window/lifecycle/states.d.ts +33 -0
- package/dist/window/lifecycle/states.d.ts.map +1 -0
- package/dist/window/lifecycle/states.js +7 -0
- package/dist/window/placement.d.ts +33 -0
- package/dist/window/placement.d.ts.map +1 -0
- package/dist/window/placement.js +57 -0
- package/dist/window/stage.d.ts +3 -0
- package/dist/window/stage.d.ts.map +1 -0
- package/dist/window/stage.js +41 -0
- package/package.json +59 -0
- package/src/application/apps/app-host.tsx +113 -0
- package/src/application/apps/app-logo.tsx +56 -0
- package/src/application/apps/apps.hook.ts +81 -0
- package/src/application/apps/open-app.hook.ts +18 -0
- package/src/application/index.ts +22 -0
- package/src/application/roles.hook.ts +41 -0
- package/src/application/spaces/current-space.hook.ts +43 -0
- package/src/application/spaces/current-space.store.ts +110 -0
- package/src/application/spaces/space.hook.ts +41 -0
- package/src/application/spaces/spaces.hook.ts +113 -0
- package/src/application/user/user.hook.ts +27 -0
- package/src/application/user/user.store.ts +85 -0
- package/src/auth/act-as.context.tsx +124 -0
- package/src/auth/auth.hook.ts +36 -0
- package/src/auth/can.hook.ts +149 -0
- package/src/auth/index.ts +6 -0
- package/src/auth/self.hook.ts +14 -0
- package/src/auth/session-kernel.ts +24 -0
- package/src/graph/action.ts +127 -0
- package/src/graph/async.ts +87 -0
- package/src/graph/call/call.hook.ts +42 -0
- package/src/graph/call/stream.hook.ts +200 -0
- package/src/graph/graph.context.ts +14 -0
- package/src/graph/guards.error.ts +58 -0
- package/src/graph/index.ts +20 -0
- package/src/graph/memory/base.ts +50 -0
- package/src/graph/memory/read/envelope.ts +98 -0
- package/src/graph/memory/read/idle.ts +24 -0
- package/src/graph/memory/read/read.ts +103 -0
- package/src/graph/memory/scope.ts +29 -0
- package/src/graph/mutate/move.hook.ts +70 -0
- package/src/graph/mutate/mutate.hook.ts +69 -0
- package/src/graph/query/children.hook.ts +136 -0
- package/src/graph/query/graph.hook.ts +13 -0
- package/src/graph/query/neighbors.hook.ts +124 -0
- package/src/graph/query/node.hook.ts +83 -0
- package/src/graph/query/query.hook.ts +42 -0
- package/src/index.ts +202 -0
- package/src/intents/envelope.ts +52 -0
- package/src/intents/index.ts +6 -0
- package/src/intents/listen-intent.hook.ts +92 -0
- package/src/intents/reply.ts +24 -0
- package/src/intents/send-intent.hook.ts +111 -0
- package/src/navigation/adapters/adapter.ts +13 -0
- package/src/navigation/adapters/memory.adapter.ts +22 -0
- package/src/navigation/adapters/url.adapter.ts +61 -0
- package/src/navigation/history.ts +170 -0
- package/src/navigation/hooks/ancestors.hook.ts +71 -0
- package/src/navigation/hooks/location.hook.ts +21 -0
- package/src/navigation/hooks/navigate.hook.ts +43 -0
- package/src/navigation/hooks/scope.hook.ts +34 -0
- package/src/navigation/index.ts +17 -0
- package/src/navigation/link.tsx +110 -0
- package/src/navigation/location.ts +122 -0
- package/src/navigation/scope.context.tsx +267 -0
- package/src/navigation/snapshot.ts +79 -0
- package/src/schema/bind-read.ts +319 -0
- package/src/schema/binding.ts +91 -0
- package/src/schema/domain.hook.ts +16 -0
- package/src/schema/function.hook.ts +68 -0
- package/src/schema/index.ts +25 -0
- package/src/schema/kernel.hook.ts +17 -0
- package/src/schema/method.hook.ts +103 -0
- package/src/schema/tag.ts +19 -0
- package/src/schema/types.ts +150 -0
- package/src/schema/write.ts +80 -0
- package/src/selection/index.ts +5 -0
- package/src/selection/live.ts +142 -0
- package/src/selection/scope.context.tsx +151 -0
- package/src/selection/selection.hook.ts +18 -0
- package/src/session/boot/boot.ts +57 -0
- package/src/session/boot/ownership.ts +54 -0
- package/src/session/boot/status.ts +32 -0
- package/src/session/connection/connection.hook.ts +16 -0
- package/src/session/connection/connection.store.ts +58 -0
- package/src/session/index.ts +8 -0
- package/src/session/kernel-client.hook.ts +13 -0
- package/src/session/kernel-instance.hook.ts +22 -0
- package/src/session/provider.tsx +205 -0
- package/src/session/session.context.ts +27 -0
- package/src/session/shell.hook.ts +19 -0
- package/src/window/adopt.ts +57 -0
- package/src/window/hooks/close-guard.hook.ts +100 -0
- package/src/window/hooks/target-node.hook.ts +94 -0
- package/src/window/hooks/views-for.hook.ts +82 -0
- package/src/window/hooks/window.hook.ts +18 -0
- package/src/window/hooks/windows.hook.ts +40 -0
- package/src/window/host.tsx +347 -0
- package/src/window/hub.ts +156 -0
- package/src/window/index.ts +17 -0
- package/src/window/lifecycle/mount.ts +134 -0
- package/src/window/lifecycle/states.ts +23 -0
- package/src/window/placement.ts +84 -0
- package/src/window/stage.tsx +46 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { LiveResult } from '@astrale-os/kernel-client/store'
|
|
2
|
+
|
|
3
|
+
import { rawOf } from '@astrale-os/kernel-client/graph'
|
|
4
|
+
/**
|
|
5
|
+
* NavLocation projection (API §8.1) — the live, id-anchored location a scope
|
|
6
|
+
* points at (live path, missing flag), its `buildLocation` assembly, the
|
|
7
|
+
* `useSettled` guard against a one-render false-empty, and the framework-free
|
|
8
|
+
* path math (parent/chain) the scope and hooks share.
|
|
9
|
+
*/
|
|
10
|
+
import { useEffect, useRef } from 'react'
|
|
11
|
+
|
|
12
|
+
import type { SerializedLocation } from './history'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The rich graph `Node`, derived from the memory's read envelope — kernel-client
|
|
16
|
+
* does not re-export `Node` at its root yet (API §14 G8), so shell-react reads it
|
|
17
|
+
* off `LiveResult` rather than taking a direct kernel-core dependency.
|
|
18
|
+
*/
|
|
19
|
+
export type Node = NonNullable<LiveResult['node']>
|
|
20
|
+
export type NodeId = Node['id']
|
|
21
|
+
|
|
22
|
+
/** The live, id-anchored location a scope currently points at (API §8.1). */
|
|
23
|
+
export interface NavLocation {
|
|
24
|
+
/** The anchor — survives rename/move. */
|
|
25
|
+
readonly id: NodeId
|
|
26
|
+
/** LIVE projection of the node's current path (empty until first resolve). */
|
|
27
|
+
readonly path: string
|
|
28
|
+
/** Live memory node — null while cold, or after the anchor stops resolving. */
|
|
29
|
+
readonly node: Node | null
|
|
30
|
+
/** View function ref rendering it, when one is open. */
|
|
31
|
+
readonly view?: string
|
|
32
|
+
readonly params: Readonly<Record<string, string>>
|
|
33
|
+
/** The anchor no longer resolves (deleted / masked). */
|
|
34
|
+
readonly missing: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const EMPTY_PARAMS: Readonly<Record<string, string>> = Object.freeze({})
|
|
38
|
+
|
|
39
|
+
/** The idle location a scope with no current entry projects (inert / boot). */
|
|
40
|
+
export const IDLE_LOCATION: NavLocation = {
|
|
41
|
+
id: '' as NodeId,
|
|
42
|
+
path: '',
|
|
43
|
+
node: null,
|
|
44
|
+
params: EMPTY_PARAMS,
|
|
45
|
+
missing: false,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Project a serialized entry + its live read into the public {@link NavLocation}. */
|
|
49
|
+
export function buildLocation(
|
|
50
|
+
entry: SerializedLocation | null,
|
|
51
|
+
result: LiveResult | null,
|
|
52
|
+
settled: boolean,
|
|
53
|
+
): NavLocation {
|
|
54
|
+
if (entry === null) return IDLE_LOCATION
|
|
55
|
+
const node = result?.node ?? null
|
|
56
|
+
return {
|
|
57
|
+
id: (node?.id ?? idHint(entry.node)) as NodeId,
|
|
58
|
+
path: node ? pathOf(node) : pathHint(entry.node),
|
|
59
|
+
node,
|
|
60
|
+
...(entry.view !== undefined ? { view: entry.view } : {}),
|
|
61
|
+
params: entry.params ?? IDLE_LOCATION.params,
|
|
62
|
+
missing: settled && node === null,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether a read has definitively settled — data present, a hard error, or a
|
|
68
|
+
* completed empty fetch. Guards `missing` (and the missing policy) against the
|
|
69
|
+
* one-render false-empty before a cold shape's first fetch is even in flight.
|
|
70
|
+
*/
|
|
71
|
+
export function useSettled(result: LiveResult | null, key: string | null): boolean {
|
|
72
|
+
const sawPending = useRef(new Map<string, boolean>())
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (key !== null && result?.pending === true) sawPending.current.set(key, true)
|
|
75
|
+
}, [key, result?.pending])
|
|
76
|
+
if (key === null || result === null) return false
|
|
77
|
+
if (result.node !== null) return true
|
|
78
|
+
if (result.error !== undefined) return true
|
|
79
|
+
return !result.pending && sawPending.current.get(key) === true
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ── path math ──────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
/** The raw path of a live node (empty when cold). */
|
|
85
|
+
export function pathOf(node: Node | null): string {
|
|
86
|
+
return node ? rawOf(node.path) : ''
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Best-effort anchor id from a stored ref (`@<id>` → id, else the raw ref). */
|
|
90
|
+
export function idHint(ref: string): string {
|
|
91
|
+
return ref.startsWith('@') ? ref.slice(1) : ref
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Best-effort path from a stored ref (a `/…` ref is already a path). */
|
|
95
|
+
export function pathHint(ref: string): string {
|
|
96
|
+
return ref.startsWith('/') ? ref : ''
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The parent absolute path, or null at (or above) root. */
|
|
100
|
+
export function parentPath(raw: string): string | null {
|
|
101
|
+
const norm = raw.replace(/\/+$/, '')
|
|
102
|
+
if (norm === '' || norm === '/') return null
|
|
103
|
+
const idx = norm.lastIndexOf('/')
|
|
104
|
+
return idx <= 0 ? '/' : norm.slice(0, idx)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The inclusive, root-first path chain for an absolute path — the ancestry the
|
|
109
|
+
* kernel tree encodes in the slug path (`/a/b/c` → `/`, `/a`, `/a/b`, `/a/b/c`).
|
|
110
|
+
* The node itself is the last element, so breadcrumbs map the chain directly.
|
|
111
|
+
*/
|
|
112
|
+
export function chainPaths(raw: string): string[] {
|
|
113
|
+
const norm = raw.replace(/\/+$/, '')
|
|
114
|
+
if (norm === '' || norm === '/') return ['/']
|
|
115
|
+
const out = ['/']
|
|
116
|
+
let acc = ''
|
|
117
|
+
for (const seg of norm.split('/').filter(Boolean)) {
|
|
118
|
+
acc += `/${seg}`
|
|
119
|
+
out.push(acc)
|
|
120
|
+
}
|
|
121
|
+
return out
|
|
122
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import type { GraphMemory, LiveResult, ShapeInput } from '@astrale-os/kernel-client/store'
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* NavScope (API §8.2) — owns one history stack, wires it to an adapter, and seats
|
|
6
|
+
* the scope context. Seeds from restore/adapter/initial, revalidates a restored
|
|
7
|
+
* stack against the memory, mirrors navigations to/from the adapter, and runs the
|
|
8
|
+
* `missing` policy when the current anchor stops resolving. Also the scope's shared
|
|
9
|
+
* glue (`NavContext`, the `useSyncExternalStore` reads) and the imperative
|
|
10
|
+
* `Navigate` surface. Scopes nest.
|
|
11
|
+
*/
|
|
12
|
+
import {
|
|
13
|
+
createContext,
|
|
14
|
+
startTransition,
|
|
15
|
+
useCallback,
|
|
16
|
+
useContext,
|
|
17
|
+
useEffect,
|
|
18
|
+
useMemo,
|
|
19
|
+
useRef,
|
|
20
|
+
useSyncExternalStore,
|
|
21
|
+
} from 'react'
|
|
22
|
+
|
|
23
|
+
import type { NavAdapter } from './adapters/adapter'
|
|
24
|
+
import type { NavSnapshot, SerializedLocation } from './history'
|
|
25
|
+
import type { NavLocation } from './location'
|
|
26
|
+
import type { NavTarget } from './snapshot'
|
|
27
|
+
|
|
28
|
+
import { useMemory } from '../graph/memory/scope'
|
|
29
|
+
import { memoryAdapter } from './adapters/memory.adapter'
|
|
30
|
+
import { NavHistory, seedEntries } from './history'
|
|
31
|
+
import { buildLocation, parentPath, pathHint, pathOf, useSettled } from './location'
|
|
32
|
+
import { revalidateAndPrune, serializeTarget } from './snapshot'
|
|
33
|
+
|
|
34
|
+
/** The imperative navigation surface (API §8.2). */
|
|
35
|
+
export interface Navigate {
|
|
36
|
+
(to: NavTarget, opts?: { replace?: boolean }): void
|
|
37
|
+
back(): void
|
|
38
|
+
forward(): void
|
|
39
|
+
/** To the parent via `has_parent`; no-op at root or while the node is cold. */
|
|
40
|
+
up(): void
|
|
41
|
+
readonly canBack: boolean
|
|
42
|
+
readonly canForward: boolean
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A mutable `Navigate` — the scope stamps `canBack`/`canForward` onto it live. */
|
|
46
|
+
export interface MutableNavigate {
|
|
47
|
+
(to: Parameters<Navigate>[0], opts?: Parameters<Navigate>[1]): void
|
|
48
|
+
back(): void
|
|
49
|
+
forward(): void
|
|
50
|
+
up(): void
|
|
51
|
+
canBack: boolean
|
|
52
|
+
canForward: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The nearest scope's shared handle (stable for the scope's lifetime). */
|
|
56
|
+
export interface NavCtx {
|
|
57
|
+
readonly history: NavHistory
|
|
58
|
+
readonly memory: GraphMemory
|
|
59
|
+
readonly adapter: NavAdapter
|
|
60
|
+
readonly navigate: MutableNavigate
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const NavContext = createContext<NavCtx | null>(null)
|
|
64
|
+
NavContext.displayName = 'AstraleNavContext'
|
|
65
|
+
|
|
66
|
+
/** The nearest scope, or throw — the door every public nav hook goes through. */
|
|
67
|
+
export function useNavCtx(): NavCtx {
|
|
68
|
+
const ctx = useContext(NavContext)
|
|
69
|
+
if (ctx === null) throw new Error('nav hooks must be used within a <NavScope>')
|
|
70
|
+
return ctx
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The nearest scope or null (for `useAncestors`, usable outside a scope). */
|
|
74
|
+
export function useOptionalNavCtx(): NavCtx | null {
|
|
75
|
+
return useContext(NavContext)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const NOOP_UNSUB = (): void => undefined
|
|
79
|
+
|
|
80
|
+
/** Re-render on any history change (no-op subscription when there is no scope). */
|
|
81
|
+
export function useHistoryVersion(history: NavHistory | null): number {
|
|
82
|
+
const subscribe = useCallback(
|
|
83
|
+
(cb: () => void) => (history !== null ? history.subscribe(cb) : NOOP_UNSUB),
|
|
84
|
+
[history],
|
|
85
|
+
)
|
|
86
|
+
const getSnapshot = useCallback(() => (history !== null ? history.getVersion() : 0), [history])
|
|
87
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Subscribe to one memory shape, tear-free. `shape` must be stable per read
|
|
92
|
+
* (a string ref, or a builder memoized upstream); a null shape is idle (no I/O).
|
|
93
|
+
*/
|
|
94
|
+
export function useMemoryShape(memory: GraphMemory, shape: ShapeInput | null): LiveResult | null {
|
|
95
|
+
const subscribe = useCallback(
|
|
96
|
+
(cb: () => void) => (shape !== null ? memory.subscribe(shape, cb) : NOOP_UNSUB),
|
|
97
|
+
[memory, shape],
|
|
98
|
+
)
|
|
99
|
+
const getSnapshot = useCallback(
|
|
100
|
+
() => (shape !== null ? memory.getSnapshot(shape) : null),
|
|
101
|
+
[memory, shape],
|
|
102
|
+
)
|
|
103
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The missing-anchor policy — a fallback strategy or a caller-supplied resolver. */
|
|
107
|
+
export type MissingPolicy = 'ancestor' | 'hold' | ((loc: NavLocation) => NavTarget | null)
|
|
108
|
+
|
|
109
|
+
export interface NavScopeProps {
|
|
110
|
+
/** Persistence seam. Default: a fresh {@link memoryAdapter} (captured once). */
|
|
111
|
+
adapter?: NavAdapter
|
|
112
|
+
/** A saved snapshot — revalidated against the memory; dead entries dropped. */
|
|
113
|
+
restore?: NavSnapshot
|
|
114
|
+
/** Seed target when neither `adapter.read()` nor `restore` yields one. */
|
|
115
|
+
initial?: NavTarget
|
|
116
|
+
/** Fires per navigation with the new location + snapshot — persist here. */
|
|
117
|
+
onChange?: (loc: NavLocation, snapshot: NavSnapshot) => void
|
|
118
|
+
/** What to do when the current anchor stops resolving. Default `'ancestor'`. */
|
|
119
|
+
missing?: MissingPolicy
|
|
120
|
+
children: ReactNode
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function NavScope(props: NavScopeProps): ReactElement {
|
|
124
|
+
const memory = useMemory()
|
|
125
|
+
|
|
126
|
+
// Adapter + history are captured ONCE — an inline `adapter={memoryAdapter()}`
|
|
127
|
+
// (or a re-passed `initial`) must never rebuild the scope's state.
|
|
128
|
+
const adapterRef = useRef<NavAdapter | null>(null)
|
|
129
|
+
if (adapterRef.current === null) adapterRef.current = props.adapter ?? memoryAdapter()
|
|
130
|
+
const adapter = adapterRef.current
|
|
131
|
+
|
|
132
|
+
const historyRef = useRef<NavHistory | null>(null)
|
|
133
|
+
if (historyRef.current === null) {
|
|
134
|
+
const seed = seedEntries(
|
|
135
|
+
adapter.read(),
|
|
136
|
+
props.restore,
|
|
137
|
+
props.initial !== undefined ? serializeTarget(props.initial) : null,
|
|
138
|
+
)
|
|
139
|
+
historyRef.current = new NavHistory(seed.entries, seed.cursor)
|
|
140
|
+
}
|
|
141
|
+
const history = historyRef.current
|
|
142
|
+
|
|
143
|
+
// Latest-value refs so the stable navigate + effects read current inputs.
|
|
144
|
+
const memoryRef = useRef(memory)
|
|
145
|
+
memoryRef.current = memory
|
|
146
|
+
const onChangeRef = useRef(props.onChange)
|
|
147
|
+
onChangeRef.current = props.onChange
|
|
148
|
+
const missingRef = useRef(props.missing)
|
|
149
|
+
missingRef.current = props.missing
|
|
150
|
+
|
|
151
|
+
const fireOnChange = useCallback((): void => {
|
|
152
|
+
const cb = onChangeRef.current
|
|
153
|
+
if (cb === undefined) return
|
|
154
|
+
const entry = history.current
|
|
155
|
+
const live = entry !== null ? memoryRef.current.peek(entry.node) : null
|
|
156
|
+
cb(buildLocation(entry, live, (live?.node ?? null) !== null), history.snapshot())
|
|
157
|
+
}, [history])
|
|
158
|
+
|
|
159
|
+
// The one stable navigate object; hooks re-stamp canBack/canForward onto it.
|
|
160
|
+
const navigate = useMemo<MutableNavigate>(() => {
|
|
161
|
+
const commit = (changed: boolean, replace: boolean): void => {
|
|
162
|
+
if (!changed) return
|
|
163
|
+
const loc = history.current
|
|
164
|
+
if (loc !== null) adapter.write(loc, { replace })
|
|
165
|
+
fireOnChange()
|
|
166
|
+
}
|
|
167
|
+
const nav = ((to: NavTarget, opts?: { replace?: boolean }) => {
|
|
168
|
+
const loc = serializeTarget(to)
|
|
169
|
+
const replace = opts?.replace ?? false
|
|
170
|
+
startTransition(() => commit(history.push(loc, replace), replace))
|
|
171
|
+
}) as MutableNavigate
|
|
172
|
+
nav.back = () => startTransition(() => commit(history.back(), false))
|
|
173
|
+
nav.forward = () => startTransition(() => commit(history.forward(), false))
|
|
174
|
+
nav.up = () => {
|
|
175
|
+
const entry = history.current
|
|
176
|
+
if (entry === null) return
|
|
177
|
+
const live = memoryRef.current.peek(entry.node)
|
|
178
|
+
const raw = live?.node ? pathOf(live.node) : pathHint(entry.node)
|
|
179
|
+
const parent = raw !== '' ? parentPath(raw) : null
|
|
180
|
+
if (parent !== null) nav(parent)
|
|
181
|
+
}
|
|
182
|
+
nav.canBack = history.canBack
|
|
183
|
+
nav.canForward = history.canForward
|
|
184
|
+
return nav
|
|
185
|
+
}, [history, adapter, fireOnChange])
|
|
186
|
+
|
|
187
|
+
// Re-render the scope on every navigation so the missing watcher tracks the
|
|
188
|
+
// current entry (consumers re-render through their own version subscription).
|
|
189
|
+
const historyVersion = useHistoryVersion(history)
|
|
190
|
+
|
|
191
|
+
// Mount: canonicalize a non-adapter seed into the adapter, then relay external
|
|
192
|
+
// (browser/URL) changes back into the history.
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
const seedLoc = history.current
|
|
195
|
+
if (seedLoc !== null && adapter.read() === null) adapter.write(seedLoc, { replace: true })
|
|
196
|
+
return adapter.subscribe(() => {
|
|
197
|
+
const loc = adapter.read()
|
|
198
|
+
if (loc === null) return
|
|
199
|
+
startTransition(() => {
|
|
200
|
+
if (history.syncExternal(loc)) fireOnChange()
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
}, [history, adapter, fireOnChange])
|
|
204
|
+
|
|
205
|
+
// Restore revalidation — once, against the shared memory.
|
|
206
|
+
const revalidatedRef = useRef(false)
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
if (revalidatedRef.current || props.restore === undefined) return
|
|
209
|
+
revalidatedRef.current = true
|
|
210
|
+
void revalidateAndPrune(history, memory)
|
|
211
|
+
}, [memory, props.restore, history])
|
|
212
|
+
|
|
213
|
+
// Missing-anchor watcher: the current entry's live read drives the policy.
|
|
214
|
+
const currentShape = history.current?.node ?? null
|
|
215
|
+
const currentResult = useMemoryShape(memory, currentShape)
|
|
216
|
+
const settled = useSettled(currentResult, currentShape)
|
|
217
|
+
const lastPathRef = useRef<string | null>(null)
|
|
218
|
+
const handledRef = useRef<string | null>(null)
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
const resolved = currentResult?.node ?? null
|
|
221
|
+
if (resolved !== null) lastPathRef.current = pathOf(resolved)
|
|
222
|
+
}, [currentResult?.node])
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
const entry = history.current
|
|
225
|
+
if (entry === null) return
|
|
226
|
+
if ((currentResult?.node ?? null) !== null) {
|
|
227
|
+
handledRef.current = null
|
|
228
|
+
return
|
|
229
|
+
}
|
|
230
|
+
if (!settled || handledRef.current === entry.node) return
|
|
231
|
+
handledRef.current = entry.node
|
|
232
|
+
applyMissingPolicy(entry, missingRef.current ?? 'ancestor', {
|
|
233
|
+
lastPath: lastPathRef.current,
|
|
234
|
+
result: currentResult,
|
|
235
|
+
navigate,
|
|
236
|
+
})
|
|
237
|
+
// historyVersion re-runs this when the current entry changes.
|
|
238
|
+
}, [settled, currentResult, history, navigate, historyVersion])
|
|
239
|
+
|
|
240
|
+
const ctx = useMemo<NavCtx>(
|
|
241
|
+
() => ({ history, memory, adapter, navigate }),
|
|
242
|
+
[history, memory, adapter, navigate],
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
return <NavContext.Provider value={ctx}>{props.children}</NavContext.Provider>
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function applyMissingPolicy(
|
|
249
|
+
entry: SerializedLocation,
|
|
250
|
+
policy: MissingPolicy,
|
|
251
|
+
deps: {
|
|
252
|
+
lastPath: string | null
|
|
253
|
+
result: LiveResult | null
|
|
254
|
+
navigate: MutableNavigate
|
|
255
|
+
},
|
|
256
|
+
): void {
|
|
257
|
+
if (policy === 'hold') return
|
|
258
|
+
if (typeof policy === 'function') {
|
|
259
|
+
const target = policy(buildLocation(entry, deps.result, true))
|
|
260
|
+
if (target !== null) deps.navigate(target, { replace: true })
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
// 'ancestor': climb one level toward a resolvable ancestor (repeats per settle).
|
|
264
|
+
const raw = deps.lastPath ?? pathHint(entry.node)
|
|
265
|
+
const parent = raw !== '' ? parentPath(raw) : null
|
|
266
|
+
if (parent !== null) deps.navigate(parent, { replace: true })
|
|
267
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AnyBoundNode, NodeRefInput } from '@astrale-os/kernel-client'
|
|
2
|
+
import type { PathLike } from '@astrale-os/kernel-client/graph'
|
|
3
|
+
import type { GraphMemory } from '@astrale-os/kernel-client/store'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* NavSnapshot serialize/restore (API §8.1/§8.2) — the `NavTarget` input space, the
|
|
7
|
+
* `serializeTarget` normalization into the id-anchored stored form, and the
|
|
8
|
+
* restore-time `revalidateAndPrune` that drops dead entries against the memory.
|
|
9
|
+
*/
|
|
10
|
+
import { normalizeRef } from '@astrale-os/kernel-client'
|
|
11
|
+
|
|
12
|
+
import type { NavHistory } from './history'
|
|
13
|
+
import type { SerializedLocation } from './history'
|
|
14
|
+
import type { Node, NodeId } from './location'
|
|
15
|
+
|
|
16
|
+
/** Everything `navigate()` / `Link` / `initial` accept (API §8.1). */
|
|
17
|
+
export type NavTarget =
|
|
18
|
+
| NodeId
|
|
19
|
+
| PathLike
|
|
20
|
+
| Node
|
|
21
|
+
| AnyBoundNode
|
|
22
|
+
| { node: NodeId | PathLike; view?: NodeRefInput; params?: Record<string, string> }
|
|
23
|
+
|
|
24
|
+
function isRecord(x: unknown): x is Record<string, unknown> {
|
|
25
|
+
return typeof x === 'object' && x !== null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Normalize any {@link NavTarget} to its stored, id-anchored serialization. */
|
|
29
|
+
export function serializeTarget(target: NavTarget): SerializedLocation {
|
|
30
|
+
if (typeof target === 'string') return { node: normalizeRef(target) }
|
|
31
|
+
if (isRecord(target) && 'node' in target) {
|
|
32
|
+
const t = target as { node: NodeRefInput; view?: NodeRefInput; params?: Record<string, string> }
|
|
33
|
+
return {
|
|
34
|
+
node: normalizeRef(t.node),
|
|
35
|
+
...(t.view !== undefined ? { view: normalizeRef(t.view) } : {}),
|
|
36
|
+
...(t.params !== undefined ? { params: { ...t.params } } : {}),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// A Node / BoundNode carries `id` (id-anchored, so rename/move survive) and `path`;
|
|
40
|
+
// anything else is a typed `Path` value → its raw address.
|
|
41
|
+
if (isRecord(target) && 'id' in target && 'path' in target) {
|
|
42
|
+
return { node: normalizeRef((target as { id: NodeRefInput }).id) }
|
|
43
|
+
}
|
|
44
|
+
return { node: normalizeRef(target as NodeRefInput) }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Revalidate a restored stack against the memory and drop dead entries (API §8.2).
|
|
49
|
+
* Each entry is point-read one-shot; a null/failed read is a dead anchor. The
|
|
50
|
+
* cursor re-lands on the surviving current entry, else the nearest survivor
|
|
51
|
+
* before it.
|
|
52
|
+
*/
|
|
53
|
+
export async function revalidateAndPrune(history: NavHistory, memory: GraphMemory): Promise<void> {
|
|
54
|
+
const { entries, cursor } = history.snapshot()
|
|
55
|
+
const alive = await Promise.all(entries.map((e) => resolves(memory, e.node)))
|
|
56
|
+
if (alive.every(Boolean)) return
|
|
57
|
+
|
|
58
|
+
const survivors: SerializedLocation[] = []
|
|
59
|
+
let newCursor = -1
|
|
60
|
+
let fallback = -1
|
|
61
|
+
entries.forEach((entry, i) => {
|
|
62
|
+
if (!alive[i]) return
|
|
63
|
+
survivors.push(entry)
|
|
64
|
+
const idx = survivors.length - 1
|
|
65
|
+
if (i === cursor) newCursor = idx
|
|
66
|
+
else if (i < cursor) fallback = idx
|
|
67
|
+
})
|
|
68
|
+
if (newCursor === -1) newCursor = fallback !== -1 ? fallback : survivors.length > 0 ? 0 : -1
|
|
69
|
+
history.reset(survivors, newCursor)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function resolves(memory: GraphMemory, ref: string): Promise<boolean> {
|
|
73
|
+
try {
|
|
74
|
+
const result = await memory.query(ref, { live: false })
|
|
75
|
+
return result.node !== null
|
|
76
|
+
} catch {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|