@astrale-os/shell-react 0.2.9 → 0.2.10-beta.3
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/dist/application/apps/app-host.d.ts +4 -15
- package/dist/application/apps/app-host.d.ts.map +1 -1
- package/dist/application/apps/app-host.js +1 -1
- package/dist/application/apps/apps.hook.d.ts +7 -4
- package/dist/application/apps/apps.hook.d.ts.map +1 -1
- package/dist/application/apps/apps.hook.js +10 -2
- package/dist/application/apps/domains.hook.d.ts +1 -1
- package/dist/application/apps/domains.hook.d.ts.map +1 -1
- package/dist/application/apps/domains.hook.js +1 -1
- package/dist/application/apps/open-app.hook.d.ts +2 -3
- package/dist/application/apps/open-app.hook.d.ts.map +1 -1
- package/dist/application/index.d.ts +2 -4
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +2 -3
- package/dist/application/spaces/space.hook.d.ts +2 -2
- package/dist/application/spaces/space.hook.d.ts.map +1 -1
- package/dist/application/spaces/space.hook.js +2 -2
- package/dist/application/spaces/spaces.hook.d.ts +2 -3
- package/dist/application/spaces/spaces.hook.d.ts.map +1 -1
- package/dist/application/spaces/spaces.hook.js +10 -3
- package/dist/auth/act-as.context.d.ts +15 -32
- package/dist/auth/act-as.context.d.ts.map +1 -1
- package/dist/auth/act-as.context.js +22 -66
- package/dist/auth/auth.hook.d.ts +1 -0
- package/dist/auth/auth.hook.d.ts.map +1 -1
- package/dist/auth/auth.hook.js +2 -22
- package/dist/auth/can.hook.d.ts +10 -38
- package/dist/auth/can.hook.d.ts.map +1 -1
- package/dist/auth/can.hook.js +35 -110
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/self.hook.d.ts +2 -2
- package/dist/auth/self.hook.d.ts.map +1 -1
- package/dist/auth/self.hook.js +0 -7
- package/dist/auth/session-kernel.d.ts +2 -3
- package/dist/auth/session-kernel.d.ts.map +1 -1
- package/dist/auth/session-kernel.js +4 -13
- package/dist/components/astrale.d.ts +14 -0
- package/dist/components/astrale.d.ts.map +1 -0
- package/dist/components/astrale.js +12 -0
- package/dist/components/boundaries.d.ts +47 -0
- package/dist/components/boundaries.d.ts.map +1 -0
- package/dist/components/boundaries.js +55 -0
- package/dist/components/can.d.ts +11 -0
- package/dist/components/can.d.ts.map +1 -0
- package/dist/components/can.js +5 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +3 -0
- package/dist/graph/call/call.hook.d.ts +8 -18
- package/dist/graph/call/call.hook.d.ts.map +1 -1
- package/dist/graph/call/call.hook.js +7 -13
- package/dist/graph/call/stream.hook.d.ts +12 -20
- package/dist/graph/call/stream.hook.d.ts.map +1 -1
- package/dist/graph/call/stream.hook.js +55 -111
- package/dist/graph/graph.context.d.ts +4 -3
- package/dist/graph/graph.context.d.ts.map +1 -1
- package/dist/graph/graph.context.js +2 -8
- package/dist/graph/guards.error.d.ts +7 -8
- package/dist/graph/guards.error.d.ts.map +1 -1
- package/dist/graph/guards.error.js +11 -7
- package/dist/graph/index.d.ts +8 -16
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +3 -7
- package/dist/graph/memory/read/envelope.d.ts +22 -54
- package/dist/graph/memory/read/envelope.d.ts.map +1 -1
- package/dist/graph/memory/read/envelope.js +26 -20
- package/dist/graph/memory/read/idle.d.ts +1 -15
- package/dist/graph/memory/read/idle.d.ts.map +1 -1
- package/dist/graph/memory/read/idle.js +4 -13
- package/dist/graph/query-definition.hook.d.ts +11 -0
- package/dist/graph/query-definition.hook.d.ts.map +1 -0
- package/dist/graph/query-definition.hook.js +205 -0
- package/dist/graph/resource.d.ts +34 -0
- package/dist/graph/resource.d.ts.map +1 -0
- package/dist/graph/resource.js +244 -0
- package/dist/graph/store.d.ts +25 -0
- package/dist/graph/store.d.ts.map +1 -0
- package/dist/graph/store.js +69 -0
- package/dist/host/actions.hook.d.ts +34 -0
- package/dist/host/actions.hook.d.ts.map +1 -0
- package/dist/host/actions.hook.js +125 -0
- package/dist/host/components.d.ts +15 -0
- package/dist/host/components.d.ts.map +1 -0
- package/dist/host/components.js +14 -0
- package/dist/host/index.d.ts +5 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +3 -0
- package/dist/index.d.ts +26 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -31
- package/dist/intents/envelope.d.ts +7 -19
- package/dist/intents/envelope.d.ts.map +1 -1
- package/dist/intents/envelope.js +2 -3
- package/dist/intents/send-intent.hook.d.ts +5 -7
- package/dist/intents/send-intent.hook.d.ts.map +1 -1
- package/dist/intents/send-intent.hook.js +17 -75
- package/dist/navigation/adapters/adapter.d.ts +5 -0
- package/dist/navigation/adapters/adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/memory.adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/memory.adapter.js +4 -0
- package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/url.adapter.js +57 -10
- package/dist/navigation/codec.d.ts +60 -0
- package/dist/navigation/codec.d.ts.map +1 -0
- package/dist/navigation/codec.js +121 -0
- package/dist/navigation/history.d.ts +11 -9
- package/dist/navigation/history.d.ts.map +1 -1
- package/dist/navigation/history.js +6 -8
- package/dist/navigation/hooks/ancestors.hook.d.ts +5 -7
- package/dist/navigation/hooks/ancestors.hook.d.ts.map +1 -1
- package/dist/navigation/hooks/ancestors.hook.js +7 -51
- package/dist/navigation/hooks/location.hook.d.ts.map +1 -1
- package/dist/navigation/hooks/location.hook.js +4 -6
- package/dist/navigation/hooks/scope.hook.d.ts.map +1 -1
- package/dist/navigation/hooks/scope.hook.js +4 -6
- package/dist/navigation/index.d.ts +4 -2
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +2 -1
- package/dist/navigation/link.d.ts +12 -0
- package/dist/navigation/link.d.ts.map +1 -1
- package/dist/navigation/link.js +13 -2
- package/dist/navigation/location.d.ts +13 -40
- package/dist/navigation/location.d.ts.map +1 -1
- package/dist/navigation/location.js +14 -76
- package/dist/navigation/scope.context.d.ts +17 -26
- package/dist/navigation/scope.context.d.ts.map +1 -1
- package/dist/navigation/scope.context.js +140 -108
- package/dist/navigation/snapshot.d.ts +14 -19
- package/dist/navigation/snapshot.d.ts.map +1 -1
- package/dist/navigation/snapshot.js +48 -44
- package/dist/schema/action.hook.d.ts +44 -0
- package/dist/schema/action.hook.d.ts.map +1 -0
- package/dist/schema/action.hook.js +72 -0
- package/dist/schema/domain.hook.d.ts +12 -7
- package/dist/schema/domain.hook.d.ts.map +1 -1
- package/dist/schema/domain.hook.js +101 -4
- package/dist/schema/index.d.ts +9 -8
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +5 -7
- package/dist/schema/kernel.hook.d.ts +4 -9
- package/dist/schema/kernel.hook.d.ts.map +1 -1
- package/dist/schema/kernel.hook.js +4 -6
- package/dist/schema/mutation.hook.d.ts +9 -0
- package/dist/schema/mutation.hook.d.ts.map +1 -0
- package/dist/schema/mutation.hook.js +41 -0
- package/dist/schema/object.hook.d.ts +16 -0
- package/dist/schema/object.hook.d.ts.map +1 -0
- package/dist/schema/object.hook.js +46 -0
- package/dist/schema/relation.hook.d.ts +46 -0
- package/dist/schema/relation.hook.d.ts.map +1 -0
- package/dist/schema/relation.hook.js +136 -0
- package/dist/selection/live.d.ts +9 -17
- package/dist/selection/live.d.ts.map +1 -1
- package/dist/selection/live.js +65 -112
- package/dist/selection/scope.context.js +5 -4
- package/dist/session/boot/boot.d.ts +1 -13
- package/dist/session/boot/boot.d.ts.map +1 -1
- package/dist/session/boot/boot.js +9 -27
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/kernel-instance.hook.d.ts +1 -4
- package/dist/session/kernel-instance.hook.d.ts.map +1 -1
- package/dist/session/kernel-instance.hook.js +1 -5
- package/dist/session/provider.d.ts +9 -23
- package/dist/session/provider.d.ts.map +1 -1
- package/dist/session/provider.js +29 -75
- package/dist/session/session.context.d.ts +5 -0
- package/dist/session/session.context.d.ts.map +1 -1
- package/dist/window/adopt.d.ts +0 -1
- package/dist/window/adopt.d.ts.map +1 -1
- package/dist/window/hooks/target-node.hook.d.ts +10 -6
- package/dist/window/hooks/target-node.hook.d.ts.map +1 -1
- package/dist/window/hooks/target-node.hook.js +14 -72
- package/dist/window/hooks/views-for.hook.d.ts +4 -3
- package/dist/window/hooks/views-for.hook.d.ts.map +1 -1
- package/dist/window/hooks/views-for.hook.js +6 -22
- package/dist/window/hooks/windows.hook.d.ts.map +1 -1
- package/dist/window/hooks/windows.hook.js +3 -4
- package/dist/window/host.d.ts +9 -11
- package/dist/window/host.d.ts.map +1 -1
- package/dist/window/host.js +26 -62
- package/dist/window/hub.d.ts +2 -0
- package/dist/window/hub.d.ts.map +1 -1
- package/dist/window/hub.js +33 -0
- package/dist/window/index.d.ts +2 -2
- package/dist/window/index.d.ts.map +1 -1
- package/dist/window/index.js +2 -2
- package/dist/window/lifecycle/mount.d.ts +5 -44
- package/dist/window/lifecycle/mount.d.ts.map +1 -1
- package/dist/window/lifecycle/mount.js +14 -120
- package/dist/window/lifecycle/states.d.ts +0 -5
- package/dist/window/lifecycle/states.d.ts.map +1 -1
- package/package.json +20 -8
- package/src/application/apps/app-host.tsx +11 -15
- package/src/application/apps/apps.hook.ts +13 -6
- package/src/application/apps/domains.hook.ts +1 -1
- package/src/application/apps/open-app.hook.ts +3 -4
- package/src/application/index.ts +4 -6
- package/src/application/spaces/space.hook.ts +5 -6
- package/src/application/spaces/spaces.hook.ts +14 -9
- package/src/auth/act-as.context.tsx +37 -91
- package/src/auth/auth.hook.ts +2 -30
- package/src/auth/can.hook.ts +44 -135
- package/src/auth/index.ts +1 -0
- package/src/auth/self.hook.ts +2 -9
- package/src/auth/session-kernel.ts +6 -16
- package/src/components/astrale.tsx +40 -0
- package/src/components/boundaries.tsx +113 -0
- package/src/components/can.tsx +16 -0
- package/src/components/index.ts +13 -0
- package/src/graph/call/call.hook.ts +22 -27
- package/src/graph/call/stream.hook.ts +66 -143
- package/src/graph/graph.context.ts +6 -11
- package/src/graph/guards.error.ts +17 -55
- package/src/graph/index.ts +23 -17
- package/src/graph/memory/read/envelope.ts +40 -65
- package/src/graph/memory/read/idle.ts +5 -18
- package/src/graph/query-definition.hook.ts +270 -0
- package/src/graph/resource.ts +358 -0
- package/src/graph/store.ts +97 -0
- package/src/host/actions.hook.ts +165 -0
- package/src/host/components.tsx +29 -0
- package/src/host/index.ts +17 -0
- package/src/index.ts +131 -124
- package/src/intents/envelope.ts +7 -23
- package/src/intents/send-intent.hook.ts +24 -79
- package/src/navigation/adapters/adapter.ts +3 -0
- package/src/navigation/adapters/memory.adapter.ts +4 -0
- package/src/navigation/adapters/url.adapter.ts +48 -8
- package/src/navigation/codec.ts +190 -0
- package/src/navigation/history.ts +20 -11
- package/src/navigation/hooks/ancestors.hook.ts +10 -60
- package/src/navigation/hooks/location.hook.ts +4 -6
- package/src/navigation/hooks/scope.hook.ts +4 -6
- package/src/navigation/index.ts +18 -2
- package/src/navigation/link.tsx +27 -2
- package/src/navigation/location.ts +26 -93
- package/src/navigation/scope.context.tsx +151 -136
- package/src/navigation/snapshot.ts +69 -50
- package/src/schema/action.hook.ts +146 -0
- package/src/schema/domain.hook.ts +127 -11
- package/src/schema/index.ts +9 -30
- package/src/schema/kernel.hook.ts +6 -13
- package/src/schema/mutation.hook.ts +63 -0
- package/src/schema/object.hook.ts +85 -0
- package/src/schema/relation.hook.ts +253 -0
- package/src/selection/live.ts +75 -125
- package/src/selection/scope.context.tsx +4 -4
- package/src/session/boot/boot.ts +8 -33
- package/src/session/index.ts +1 -0
- package/src/session/kernel-instance.hook.ts +2 -11
- package/src/session/provider.tsx +34 -103
- package/src/session/session.context.ts +6 -0
- package/src/window/adopt.ts +0 -1
- package/src/window/hooks/target-node.hook.ts +20 -85
- package/src/window/hooks/views-for.hook.ts +12 -25
- package/src/window/hooks/windows.hook.ts +3 -4
- package/src/window/host.tsx +35 -77
- package/src/window/hub.ts +33 -0
- package/src/window/index.ts +3 -3
- package/src/window/lifecycle/mount.ts +15 -160
- package/src/window/lifecycle/states.ts +1 -5
- package/dist/application/roles.hook.d.ts +0 -7
- package/dist/application/roles.hook.d.ts.map +0 -1
- package/dist/application/roles.hook.js +0 -23
- package/dist/graph/memory/base.d.ts +0 -21
- package/dist/graph/memory/base.d.ts.map +0 -1
- package/dist/graph/memory/base.js +0 -33
- package/dist/graph/memory/read/read.d.ts +0 -9
- package/dist/graph/memory/read/read.d.ts.map +0 -1
- package/dist/graph/memory/read/read.js +0 -87
- package/dist/graph/memory/scope.d.ts +0 -7
- package/dist/graph/memory/scope.d.ts.map +0 -1
- package/dist/graph/memory/scope.js +0 -25
- package/dist/graph/mutate/move.hook.d.ts +0 -7
- package/dist/graph/mutate/move.hook.d.ts.map +0 -1
- package/dist/graph/mutate/move.hook.js +0 -49
- package/dist/graph/mutate/mutate.hook.d.ts +0 -17
- package/dist/graph/mutate/mutate.hook.d.ts.map +0 -1
- package/dist/graph/mutate/mutate.hook.js +0 -45
- package/dist/graph/query/children.hook.d.ts +0 -29
- package/dist/graph/query/children.hook.d.ts.map +0 -1
- package/dist/graph/query/children.hook.js +0 -64
- package/dist/graph/query/graph.hook.d.ts +0 -9
- package/dist/graph/query/graph.hook.d.ts.map +0 -1
- package/dist/graph/query/graph.hook.js +0 -5
- package/dist/graph/query/neighbors.hook.d.ts +0 -7
- package/dist/graph/query/neighbors.hook.d.ts.map +0 -1
- package/dist/graph/query/neighbors.hook.js +0 -104
- package/dist/graph/query/node.hook.d.ts +0 -14
- package/dist/graph/query/node.hook.d.ts.map +0 -1
- package/dist/graph/query/node.hook.js +0 -43
- package/dist/graph/query/query.hook.d.ts +0 -14
- package/dist/graph/query/query.hook.d.ts.map +0 -1
- package/dist/graph/query/query.hook.js +0 -23
- package/dist/schema/bind-read.d.ts +0 -37
- package/dist/schema/bind-read.d.ts.map +0 -1
- package/dist/schema/bind-read.js +0 -205
- package/dist/schema/binding.d.ts +0 -21
- package/dist/schema/binding.d.ts.map +0 -1
- package/dist/schema/binding.js +0 -99
- package/dist/schema/function.hook.d.ts +0 -9
- package/dist/schema/function.hook.d.ts.map +0 -1
- package/dist/schema/function.hook.js +0 -40
- package/dist/schema/method.hook.d.ts +0 -14
- package/dist/schema/method.hook.d.ts.map +0 -1
- package/dist/schema/method.hook.js +0 -49
- package/dist/schema/tag.d.ts +0 -11
- package/dist/schema/tag.d.ts.map +0 -1
- package/dist/schema/tag.js +0 -11
- package/dist/schema/types.d.ts +0 -73
- package/dist/schema/types.d.ts.map +0 -1
- package/dist/schema/types.js +0 -1
- package/dist/schema/write.d.ts +0 -16
- package/dist/schema/write.d.ts.map +0 -1
- package/dist/schema/write.js +0 -56
- package/src/application/roles.hook.ts +0 -41
- package/src/graph/memory/base.ts +0 -50
- package/src/graph/memory/read/read.ts +0 -103
- package/src/graph/memory/scope.ts +0 -29
- package/src/graph/mutate/move.hook.ts +0 -70
- package/src/graph/mutate/mutate.hook.ts +0 -69
- package/src/graph/query/children.hook.ts +0 -136
- package/src/graph/query/graph.hook.ts +0 -13
- package/src/graph/query/neighbors.hook.ts +0 -159
- package/src/graph/query/node.hook.ts +0 -83
- package/src/graph/query/query.hook.ts +0 -42
- package/src/schema/bind-read.ts +0 -319
- package/src/schema/binding.ts +0 -146
- package/src/schema/function.hook.ts +0 -68
- package/src/schema/method.hook.ts +0 -103
- package/src/schema/tag.ts +0 -19
- package/src/schema/types.ts +0 -150
- package/src/schema/write.ts +0 -96
package/src/schema/binding.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bindingFor(kernel, schema) — memoized `withSchema` handles (API §6). The
|
|
3
|
-
* `withSchema` handle is a *binding*, never a "view". Memoizes
|
|
4
|
-
* `createSchemaBoundView` per (session, schema) so a binding — and the BoundNodes
|
|
5
|
-
* it mints — keep referential identity across renders. Each binding is wrapped so
|
|
6
|
-
* every BoundNode it hands back is schema-tagged (the traversal hooks read it
|
|
7
|
-
* back) and its raw node recorded (the write capability's index).
|
|
8
|
-
*/
|
|
9
|
-
import type { FnMap, NodeRefInput, SchemaBoundView } from '@astrale-os/kernel-client'
|
|
10
|
-
import type { GraphMemory } from '@astrale-os/kernel-client/store'
|
|
11
|
-
import type { Node } from '@astrale-os/kernel-core'
|
|
12
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
13
|
-
|
|
14
|
-
import { createSchemaBoundView } from '@astrale-os/kernel-client'
|
|
15
|
-
|
|
16
|
-
import type { SessionView } from '../auth/act-as.context.js'
|
|
17
|
-
|
|
18
|
-
import { tagSchema } from './tag.js'
|
|
19
|
-
import { recordNode, writableFor } from './write.js'
|
|
20
|
-
|
|
21
|
-
/** One tagged binding per (kernel, schema) — shared across the whole tree. */
|
|
22
|
-
const bindingCache = new WeakMap<object, WeakMap<Schema, unknown>>()
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Resolve (and memoize) the tagged schema-bound handle for `schema` on `kernel`.
|
|
26
|
-
* `kernel` is the EFFECTIVE dispatch kernel (root or `<ActAs>` — §4); the cache is
|
|
27
|
-
* keyed on it, so an acted-as subtree gets its own memoized bindings for free.
|
|
28
|
-
* `memory` is the SAME scoped memory the read hooks use (1:1 with `kernel`).
|
|
29
|
-
*/
|
|
30
|
-
export function bindingFor<S extends Schema>(
|
|
31
|
-
kernel: SessionView,
|
|
32
|
-
schema: S,
|
|
33
|
-
memory: GraphMemory,
|
|
34
|
-
): SchemaBoundView<S, FnMap> {
|
|
35
|
-
let bySchema = bindingCache.get(kernel)
|
|
36
|
-
if (bySchema === undefined) {
|
|
37
|
-
bySchema = new WeakMap()
|
|
38
|
-
bindingCache.set(kernel, bySchema)
|
|
39
|
-
}
|
|
40
|
-
const cached = bySchema.get(schema)
|
|
41
|
-
if (cached !== undefined) return cached as SchemaBoundView<S, FnMap>
|
|
42
|
-
|
|
43
|
-
const { writable, nodeIndex } = writableFor(kernel, memory)
|
|
44
|
-
const binding = tagBinding(createSchemaBoundView(writable, schema), schema, nodeIndex)
|
|
45
|
-
bySchema.set(schema, binding)
|
|
46
|
-
return binding
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Wrap a binding so `bind`/`bindAny`/`as` outputs carry a schema tag, and every
|
|
51
|
-
* bound wire node is recorded with its class and path (the write cap's index); the
|
|
52
|
-
* class handles and every other member pass straight through.
|
|
53
|
-
*/
|
|
54
|
-
function tagBinding<S extends Schema>(
|
|
55
|
-
binding: SchemaBoundView<S, FnMap>,
|
|
56
|
-
schema: S,
|
|
57
|
-
nodeIndex: Map<string, Node>,
|
|
58
|
-
): SchemaBoundView<S, FnMap> {
|
|
59
|
-
let taggedClasses: unknown
|
|
60
|
-
const handler: ProxyHandler<SchemaBoundView<S, FnMap>> = {
|
|
61
|
-
get: (target, prop, receiver) => {
|
|
62
|
-
const value = Reflect.get(target, prop, receiver) as unknown
|
|
63
|
-
if (prop === 'node' || prop === 'create') {
|
|
64
|
-
return async (...args: unknown[]) =>
|
|
65
|
-
tagBoundResult(
|
|
66
|
-
await (value as (...callArgs: unknown[]) => Promise<unknown>)(...args),
|
|
67
|
-
schema,
|
|
68
|
-
nodeIndex,
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
if (prop === 'bind') {
|
|
72
|
-
return (type: string, node: Node, opts?: unknown) => {
|
|
73
|
-
recordNode(nodeIndex, node)
|
|
74
|
-
return tagSchema(
|
|
75
|
-
(value as (t: string, n: Node, o?: unknown) => unknown)(type, node, opts),
|
|
76
|
-
schema,
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (prop === 'bindAny') {
|
|
81
|
-
return (node: Node) => {
|
|
82
|
-
recordNode(nodeIndex, node)
|
|
83
|
-
return tagSchema((value as (n: Node) => unknown)(node), schema)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (prop === 'classes') {
|
|
87
|
-
taggedClasses ??= tagClassHandles(value as object, schema, nodeIndex)
|
|
88
|
-
return taggedClasses
|
|
89
|
-
}
|
|
90
|
-
if (prop === 'as') {
|
|
91
|
-
const as = value as SchemaBoundView<S, FnMap>['as']
|
|
92
|
-
return (credential: Parameters<typeof as>[0]) =>
|
|
93
|
-
tagBinding(as(credential), schema, nodeIndex)
|
|
94
|
-
}
|
|
95
|
-
if (prop === 'withSchema') {
|
|
96
|
-
return <S2 extends Schema>(next: S2) =>
|
|
97
|
-
tagBinding((value as SchemaBoundView<S, FnMap>['withSchema'])(next), next, nodeIndex)
|
|
98
|
-
}
|
|
99
|
-
return value
|
|
100
|
-
},
|
|
101
|
-
}
|
|
102
|
-
return new Proxy(binding, handler)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function tagClassHandles<S extends Schema>(
|
|
106
|
-
classes: object,
|
|
107
|
-
schema: S,
|
|
108
|
-
nodeIndex: Map<string, Node>,
|
|
109
|
-
): object {
|
|
110
|
-
const handles = new Map<PropertyKey, unknown>()
|
|
111
|
-
return new Proxy(classes, {
|
|
112
|
-
get(target, prop, receiver) {
|
|
113
|
-
const cached = handles.get(prop)
|
|
114
|
-
if (cached !== undefined) return cached
|
|
115
|
-
const handle = Reflect.get(target, prop, receiver) as unknown
|
|
116
|
-
if (typeof handle !== 'function') return handle
|
|
117
|
-
const tagged = new Proxy(handle, {
|
|
118
|
-
get(handleTarget, member, handleReceiver) {
|
|
119
|
-
const value = Reflect.get(handleTarget, member, handleReceiver) as unknown
|
|
120
|
-
if (member !== 'get') return value
|
|
121
|
-
return async (...args: unknown[]) =>
|
|
122
|
-
tagBoundResult(
|
|
123
|
-
await (value as (...callArgs: unknown[]) => Promise<unknown>)(...args),
|
|
124
|
-
schema,
|
|
125
|
-
nodeIndex,
|
|
126
|
-
)
|
|
127
|
-
},
|
|
128
|
-
})
|
|
129
|
-
handles.set(prop, tagged)
|
|
130
|
-
return tagged
|
|
131
|
-
},
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function tagBoundResult<R>(result: R, schema: Schema, nodeIndex: Map<string, Node>): R {
|
|
136
|
-
const nodes = Array.isArray(result) ? result : [result]
|
|
137
|
-
for (const node of nodes) {
|
|
138
|
-
if (node !== null && typeof node === 'object') {
|
|
139
|
-
recordNode(nodeIndex, node)
|
|
140
|
-
tagSchema(node, schema)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return result
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export type { NodeRefInput }
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
2
|
-
|
|
3
|
-
import { compileDomain } from '@astrale-os/kernel-core/domain'
|
|
4
|
-
/**
|
|
5
|
-
* `useFunction` (API §6) — `useMethod`'s sibling for a domain's top-level
|
|
6
|
-
* standalone functions (the `functions` map of `defineSchema`). Dispatched by the
|
|
7
|
-
* compiled FunctionPath from the compiled-domain accessor, never string-built.
|
|
8
|
-
* Dispatch is correct but not compile-time typed (see the note in schema/types.ts).
|
|
9
|
-
*/
|
|
10
|
-
import { useCallback, useMemo, useRef } from 'react'
|
|
11
|
-
|
|
12
|
-
import type { Action } from '../graph/action.js'
|
|
13
|
-
import type { FunctionNames, FunctionParams, FunctionResult } from './types.js'
|
|
14
|
-
|
|
15
|
-
import { useAction } from '../graph/action.js'
|
|
16
|
-
import { useDomain } from './domain.hook.js'
|
|
17
|
-
|
|
18
|
-
export interface FunctionOptions {
|
|
19
|
-
/** Extra failure channel; the action still rejects and records `.error`. */
|
|
20
|
-
onError?: (error: unknown) => void
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const compiledCache = new WeakMap<Schema, ReturnType<typeof compileDomain>>()
|
|
24
|
-
|
|
25
|
-
/** The dispatch path for a standalone function, from the compiled accessor. */
|
|
26
|
-
function functionPathOf(schema: Schema, name: string): string {
|
|
27
|
-
let compiled = compiledCache.get(schema)
|
|
28
|
-
if (compiled === undefined) {
|
|
29
|
-
compiled = compileDomain(schema)
|
|
30
|
-
compiledCache.set(schema, compiled)
|
|
31
|
-
}
|
|
32
|
-
const entry = compiled.$.f(name)
|
|
33
|
-
if (entry === undefined) {
|
|
34
|
-
throw new Error(`Unknown function '${name}' in schema '${schema.domain}'`)
|
|
35
|
-
}
|
|
36
|
-
return entry.path.domain.raw
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
type RawCall = (method: string, params: unknown, opts?: unknown) => Promise<unknown>
|
|
40
|
-
|
|
41
|
-
export function useFunction<S extends Schema, F extends FunctionNames<S>>(
|
|
42
|
-
schema: S,
|
|
43
|
-
fn: F,
|
|
44
|
-
opts?: FunctionOptions,
|
|
45
|
-
): Action<[FunctionParams<S, F>], FunctionResult<S, F>> {
|
|
46
|
-
const binding = useDomain(schema)
|
|
47
|
-
const path = useMemo(() => functionPathOf(schema, String(fn)), [schema, fn])
|
|
48
|
-
|
|
49
|
-
const onErrorRef = useRef(opts?.onError)
|
|
50
|
-
onErrorRef.current = opts?.onError
|
|
51
|
-
|
|
52
|
-
const call = useCallback(
|
|
53
|
-
async (params: FunctionParams<S, F>): Promise<FunctionResult<S, F>> => {
|
|
54
|
-
try {
|
|
55
|
-
return (await (binding.raw.call as unknown as RawCall)(path, params)) as FunctionResult<
|
|
56
|
-
S,
|
|
57
|
-
F
|
|
58
|
-
>
|
|
59
|
-
} catch (error) {
|
|
60
|
-
onErrorRef.current?.(error)
|
|
61
|
-
throw error
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
[binding, path],
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
return useAction(call)
|
|
68
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import type { NodeRefInput, TypeNames } from '@astrale-os/kernel-client'
|
|
2
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
3
|
-
|
|
4
|
-
import { resolveAllMethods } from '@astrale-os/kernel-dsl'
|
|
5
|
-
/**
|
|
6
|
-
* `useMethod` (API §6) — typed method dispatch with call state. Three forms,
|
|
7
|
-
* selected by the method's static-ness and whether `on` is given:
|
|
8
|
-
* static → action(params)
|
|
9
|
-
* instance + on → action(params) (bound to that node)
|
|
10
|
-
* instance, no on → action(ref, params)
|
|
11
|
-
* Params/result come from the method's Zod contracts.
|
|
12
|
-
*/
|
|
13
|
-
import { useCallback, useMemo, useRef } from 'react'
|
|
14
|
-
|
|
15
|
-
import type { Action } from '../graph/action.js'
|
|
16
|
-
import type { AutoMethodAction, BoundMethodAction, MethodNames } from './types.js'
|
|
17
|
-
|
|
18
|
-
import { useAction } from '../graph/action.js'
|
|
19
|
-
import { useDomain } from './domain.hook.js'
|
|
20
|
-
|
|
21
|
-
export interface MethodOptions {
|
|
22
|
-
/** Bind the action to this node — dispatch as `action(params)`. */
|
|
23
|
-
on?: NodeRefInput
|
|
24
|
-
/** Extra failure channel; the action still rejects and records `.error`. */
|
|
25
|
-
onError?: (error: unknown) => void
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type Dispatch = Record<string, (params: unknown) => Promise<unknown>>
|
|
29
|
-
|
|
30
|
-
export function useMethod<S extends Schema, T extends TypeNames<S>, M extends MethodNames<S, T>>(
|
|
31
|
-
schema: S,
|
|
32
|
-
type: T,
|
|
33
|
-
method: M,
|
|
34
|
-
opts: MethodOptions & { on: NodeRefInput },
|
|
35
|
-
): BoundMethodAction<S, T, M>
|
|
36
|
-
export function useMethod<S extends Schema, T extends TypeNames<S>, M extends MethodNames<S, T>>(
|
|
37
|
-
schema: S,
|
|
38
|
-
type: T,
|
|
39
|
-
method: M,
|
|
40
|
-
opts?: MethodOptions,
|
|
41
|
-
): AutoMethodAction<S, T, M>
|
|
42
|
-
export function useMethod<S extends Schema, T extends TypeNames<S>, M extends MethodNames<S, T>>(
|
|
43
|
-
schema: S,
|
|
44
|
-
type: T,
|
|
45
|
-
method: M,
|
|
46
|
-
opts?: MethodOptions,
|
|
47
|
-
): Action<never[], unknown> {
|
|
48
|
-
const binding = useDomain(schema) as unknown as DynamicBinding
|
|
49
|
-
const on = opts?.on
|
|
50
|
-
const isStatic = useMemo(() => detectStatic(schema, type, String(method)), [schema, type, method])
|
|
51
|
-
|
|
52
|
-
const onErrorRef = useRef(opts?.onError)
|
|
53
|
-
onErrorRef.current = opts?.onError
|
|
54
|
-
|
|
55
|
-
const call = useCallback(
|
|
56
|
-
async (...args: unknown[]): Promise<unknown> => {
|
|
57
|
-
const name = String(method)
|
|
58
|
-
try {
|
|
59
|
-
if (on !== undefined) return await instance(binding, type as string, on, name, args[0])
|
|
60
|
-
if (isStatic) return await staticCall(binding, type as string, name, args[0])
|
|
61
|
-
return await instance(binding, type as string, args[0] as NodeRefInput, name, args[1])
|
|
62
|
-
} catch (error) {
|
|
63
|
-
onErrorRef.current?.(error)
|
|
64
|
-
throw error
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
[binding, type, method, on, isStatic],
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
return useAction(call)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
type DynamicClassHandle = Dispatch & ((ref: NodeRefInput) => Dispatch)
|
|
74
|
-
type DynamicBinding = { classes: Record<string, DynamicClassHandle> }
|
|
75
|
-
|
|
76
|
-
function staticCall(
|
|
77
|
-
binding: DynamicBinding,
|
|
78
|
-
type: string,
|
|
79
|
-
method: string,
|
|
80
|
-
params: unknown,
|
|
81
|
-
): Promise<unknown> {
|
|
82
|
-
return binding.classes[type]![method]!(params)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function instance(
|
|
86
|
-
binding: DynamicBinding,
|
|
87
|
-
type: string,
|
|
88
|
-
ref: NodeRefInput,
|
|
89
|
-
method: string,
|
|
90
|
-
params: unknown,
|
|
91
|
-
): Promise<unknown> {
|
|
92
|
-
return binding.classes[type]!(ref)[method]!(params)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** Read the method's `static` flag from the schema (own + inherited). */
|
|
96
|
-
function detectStatic(schema: Schema, type: string, method: string): boolean {
|
|
97
|
-
const def =
|
|
98
|
-
(schema.classes as Record<string, unknown>)[type] ??
|
|
99
|
-
(schema.interfaces as Record<string, unknown>)[type]
|
|
100
|
-
if (def === undefined) return false
|
|
101
|
-
const methods = resolveAllMethods(def as Parameters<typeof resolveAllMethods>[0])
|
|
102
|
-
return methods[method]?.config.static === true
|
|
103
|
-
}
|
package/src/schema/tag.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema-tagging of raw nodes (API §6, the bindAny bridge). A module-level tag
|
|
3
|
-
* records the schema each BoundNode was bound under, so the traversal hooks can
|
|
4
|
-
* recover it from the node alone (`useChildren`/`useOut`/`useIn` re-bind endpoints).
|
|
5
|
-
*/
|
|
6
|
-
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
7
|
-
|
|
8
|
-
const schemaOfNode = new WeakMap<object, Schema>()
|
|
9
|
-
|
|
10
|
-
/** Record the schema a BoundNode was bound under; returns the node unchanged. */
|
|
11
|
-
export function tagSchema<N>(node: N, schema: Schema): N {
|
|
12
|
-
if (node !== null && typeof node === 'object') schemaOfNode.set(node, schema)
|
|
13
|
-
return node
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** The schema a BoundNode was bound under, if it came from a shell-react binding. */
|
|
17
|
-
export function schemaOf(node: object): Schema | undefined {
|
|
18
|
-
return schemaOfNode.get(node)
|
|
19
|
-
}
|
package/src/schema/types.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-level surface for the schema module (API §6): the read envelopes
|
|
3
|
-
* (`TypedNodeResult`/`TypedChildrenResult`/`EndpointResult`) and the method /
|
|
4
|
-
* function contract projections. Param inference mirrors the client's proxy
|
|
5
|
-
* types (Zod optionality preserved), re-derived here because it is not exported.
|
|
6
|
-
*/
|
|
7
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
8
|
-
import type {
|
|
9
|
-
AnyBoundNode,
|
|
10
|
-
BoundNode,
|
|
11
|
-
DefOf,
|
|
12
|
-
EdgeNames,
|
|
13
|
-
EndpointsOf,
|
|
14
|
-
NodeRefInput,
|
|
15
|
-
TypeNames,
|
|
16
|
-
} from '@astrale-os/kernel-client'
|
|
17
|
-
import type { z } from '@astrale-os/kernel-core'
|
|
18
|
-
import type {
|
|
19
|
-
AllMethods,
|
|
20
|
-
ExtractMethodNames,
|
|
21
|
-
ExtractMethodParams,
|
|
22
|
-
ExtractMethodReturnValue,
|
|
23
|
-
Schema,
|
|
24
|
-
} from '@astrale-os/kernel-dsl'
|
|
25
|
-
|
|
26
|
-
import type { Action } from '../graph/action.js'
|
|
27
|
-
import type { ReadState, Windowed } from '../graph/memory/read/envelope.js'
|
|
28
|
-
|
|
29
|
-
// ── Read envelopes ──────────────────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
export interface TypedNodeResult<S extends Schema, T extends TypeNames<S>> extends ReadState {
|
|
32
|
-
readonly node: BoundNode<DefOf<S, T>, S> | null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface TypedChildrenResult<S extends Schema, T extends TypeNames<S>>
|
|
36
|
-
extends ReadState, Windowed {
|
|
37
|
-
readonly children: readonly BoundNode<DefOf<S, T>, S>[]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Cardinality decides the envelope key: single|null for `1`/`0..1`, array otherwise. */
|
|
41
|
-
export type EndpointResult<S extends Schema, E extends EdgeNames<S>, Side extends 'from' | 'to'> =
|
|
42
|
-
EndpointsOf<S, E, Side> extends readonly unknown[]
|
|
43
|
-
? ReadState & { readonly nodes: EndpointsOf<S, E, Side> }
|
|
44
|
-
: ReadState & { readonly node: EndpointsOf<S, E, Side> }
|
|
45
|
-
|
|
46
|
-
/** Untyped traversal fallback — mirrors the raw `neighbors` shorthand. */
|
|
47
|
-
export interface UntypedEndpointResult<S extends Schema> extends ReadState, Windowed {
|
|
48
|
-
readonly nodes: readonly AnyBoundNode<S>[]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ── Method contracts ──────────────────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
/** Dispatchable method names on `type` (own + inherited). */
|
|
54
|
-
export type MethodNames<S extends Schema, T extends TypeNames<S>> = ExtractMethodNames<DefOf<S, T>>
|
|
55
|
-
|
|
56
|
-
type OptionalKeys<P> = {
|
|
57
|
-
[K in keyof P]: P[K] extends z.ZodOptional<any> | z.ZodDefault<any> ? K : never
|
|
58
|
-
}[keyof P]
|
|
59
|
-
type RequiredKeys<P> = Exclude<keyof P, OptionalKeys<P>>
|
|
60
|
-
type InferParams<P> = {
|
|
61
|
-
[K in RequiredKeys<P>]: P[K] extends z.ZodType<infer T> ? T : never
|
|
62
|
-
} & {
|
|
63
|
-
[K in OptionalKeys<P>]?: P[K] extends z.ZodType<infer T> ? T : never
|
|
64
|
-
}
|
|
65
|
-
type Simplify<T> = { [K in keyof T]: T[K] }
|
|
66
|
-
|
|
67
|
-
/** Runtime params object for method `M` on `type`. */
|
|
68
|
-
export type MethodParams<
|
|
69
|
-
S extends Schema,
|
|
70
|
-
T extends TypeNames<S>,
|
|
71
|
-
M extends MethodNames<S, T>,
|
|
72
|
-
> = Simplify<InferParams<ExtractMethodParams<DefOf<S, T>, M & string>>>
|
|
73
|
-
|
|
74
|
-
/** Resolved return value of method `M` on `type`. */
|
|
75
|
-
export type MethodResult<
|
|
76
|
-
S extends Schema,
|
|
77
|
-
T extends TypeNames<S>,
|
|
78
|
-
M extends MethodNames<S, T>,
|
|
79
|
-
> = ExtractMethodReturnValue<DefOf<S, T>, M & string>
|
|
80
|
-
|
|
81
|
-
/** True when method `M` on `type` is static. */
|
|
82
|
-
export type MethodIsStatic<
|
|
83
|
-
S extends Schema,
|
|
84
|
-
T extends TypeNames<S>,
|
|
85
|
-
M extends MethodNames<S, T>,
|
|
86
|
-
> = M extends keyof AllMethods<DefOf<S, T>>
|
|
87
|
-
? AllMethods<DefOf<S, T>>[M] extends { config: { static: true } }
|
|
88
|
-
? true
|
|
89
|
-
: false
|
|
90
|
-
: false
|
|
91
|
-
|
|
92
|
-
/** Action for a `on`-bound or static method: `action(params)`. */
|
|
93
|
-
export type BoundMethodAction<
|
|
94
|
-
S extends Schema,
|
|
95
|
-
T extends TypeNames<S>,
|
|
96
|
-
M extends MethodNames<S, T>,
|
|
97
|
-
> = Action<[MethodParams<S, T, M>], MethodResult<S, T, M>>
|
|
98
|
-
|
|
99
|
-
/** Action for an unbound instance method: `action(ref, params)`. */
|
|
100
|
-
export type TargetedMethodAction<
|
|
101
|
-
S extends Schema,
|
|
102
|
-
T extends TypeNames<S>,
|
|
103
|
-
M extends MethodNames<S, T>,
|
|
104
|
-
> = Action<[ref: NodeRefInput, params: MethodParams<S, T, M>], MethodResult<S, T, M>>
|
|
105
|
-
|
|
106
|
-
/** Static → `action(params)`; instance → `action(ref, params)` (no `on`). */
|
|
107
|
-
export type AutoMethodAction<
|
|
108
|
-
S extends Schema,
|
|
109
|
-
T extends TypeNames<S>,
|
|
110
|
-
M extends MethodNames<S, T>,
|
|
111
|
-
> =
|
|
112
|
-
MethodIsStatic<S, T, M> extends true ? BoundMethodAction<S, T, M> : TargetedMethodAction<S, T, M>
|
|
113
|
-
|
|
114
|
-
// ── Function contracts ──────────────────────────────────────────────────────────────
|
|
115
|
-
//
|
|
116
|
-
// DEGRADATION (§6 deviation — tracked to kernel-dsl): `defineSchema`
|
|
117
|
-
// (kernel/dsl/src/schema/define.ts) does NOT make the `functions` record generic
|
|
118
|
-
// — `Schema.functions` is the widened `Record<string, FuncDef>`, and `FuncDef`'s
|
|
119
|
-
// input/output default to `z.ZodType`. So for a real domain schema `S['functions']
|
|
120
|
-
// [F]` is a bare `FuncDef`: `FunctionNames<S>` widens to `string` (ANY name
|
|
121
|
-
// compiles), and `FunctionParams`/`FunctionResult` resolve to `unknown`. These
|
|
122
|
-
// projections are correct in shape; the phantom type-safety is upstream. The fix
|
|
123
|
-
// belongs in kernel-dsl (make `defineSchema` generic over the functions record →
|
|
124
|
-
// `Schema<I, C, F>`) and is deferred here: it is a cross-ecosystem change (a third
|
|
125
|
-
// `Schema` type param threads through every domain's declared type) carrying the
|
|
126
|
-
// declaration-emit size hazard `imports` was widened to avoid (schema.ts). Until
|
|
127
|
-
// then, treat `useFunction` names/params/results as UNCHECKED at real call sites.
|
|
128
|
-
|
|
129
|
-
/** Standalone top-level function names of the schema (widens to `string` today — see above). */
|
|
130
|
-
export type FunctionNames<S extends Schema> = keyof S['functions'] & string
|
|
131
|
-
|
|
132
|
-
/** Input value of standalone function `F` (`unknown` for a widened `FuncDef` — see above). */
|
|
133
|
-
export type FunctionParams<
|
|
134
|
-
S extends Schema,
|
|
135
|
-
F extends FunctionNames<S>,
|
|
136
|
-
> = S['functions'][F] extends { config: { input: infer I } }
|
|
137
|
-
? I extends z.ZodType
|
|
138
|
-
? z.infer<I>
|
|
139
|
-
: never
|
|
140
|
-
: never
|
|
141
|
-
|
|
142
|
-
/** Output value of standalone function `F` (`unknown` for a widened `FuncDef` — see above). */
|
|
143
|
-
export type FunctionResult<
|
|
144
|
-
S extends Schema,
|
|
145
|
-
F extends FunctionNames<S>,
|
|
146
|
-
> = S['functions'][F] extends { config: { output: infer O } }
|
|
147
|
-
? O extends z.ZodType
|
|
148
|
-
? z.infer<O>
|
|
149
|
-
: never
|
|
150
|
-
: never
|
package/src/schema/write.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory-routed writes (API §6). Wraps a session view so `updateNode`/`createNode`
|
|
3
|
-
* route through the shared `GraphMemory`'s optimistic write shorthands — so
|
|
4
|
-
* `BoundNode.update` / `SchemaBoundView.create` from hook-returned nodes are
|
|
5
|
-
* optimistic (SAFE-MODE prop regime) and revalidate affected shapes, instead of
|
|
6
|
-
* the raw kernel-client floor that bypasses the overlay. Keeps the bind-time
|
|
7
|
-
* `id → tree-path` index the write capability addresses nodes through.
|
|
8
|
-
*/
|
|
9
|
-
import type { CredentialInput } from '@astrale-os/kernel-client'
|
|
10
|
-
import type { PathLike, Properties } from '@astrale-os/kernel-client/graph'
|
|
11
|
-
import type { GraphMemory } from '@astrale-os/kernel-client/store'
|
|
12
|
-
import type { Node } from '@astrale-os/kernel-core'
|
|
13
|
-
|
|
14
|
-
import type { SessionView } from '../auth/act-as.context.js'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* One memory-backed writable kernel per (effective) session view, plus the
|
|
18
|
-
* bind-time `id → tree-path` index it consults. Shared across every schema binding
|
|
19
|
-
* over the same session so a node bound under any schema resolves for a write.
|
|
20
|
-
*/
|
|
21
|
-
export interface WritableKernel {
|
|
22
|
-
readonly writable: SessionView
|
|
23
|
-
readonly nodeIndex: Map<string, Node>
|
|
24
|
-
}
|
|
25
|
-
const writableCache = new WeakMap<object, WritableKernel>()
|
|
26
|
-
|
|
27
|
-
export function writableFor(kernel: SessionView, memory: GraphMemory): WritableKernel {
|
|
28
|
-
let entry = writableCache.get(kernel)
|
|
29
|
-
if (entry === undefined) {
|
|
30
|
-
const nodeIndex = new Map<string, Node>()
|
|
31
|
-
entry = { writable: withMemoryWrites(kernel, memory, nodeIndex), nodeIndex }
|
|
32
|
-
writableCache.set(kernel, entry)
|
|
33
|
-
}
|
|
34
|
-
return entry
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Wrap a session view so `updateNode`/`createNode` route through the memory's
|
|
39
|
-
* optimistic write shorthands. `BoundNode.update` addresses a node by `@<id>`,
|
|
40
|
-
* but the memory needs the node's class and tree path — so an `@<id>` ref is translated
|
|
41
|
-
* through `nodeIndex` (populated at bind time). A ref that is NOT indexed (a node
|
|
42
|
-
* that was never bound) falls back to the raw kernel-client floor:
|
|
43
|
-
* it still dispatches, just without the overlay — matching the imperative floor.
|
|
44
|
-
*/
|
|
45
|
-
function withMemoryWrites(
|
|
46
|
-
kernel: SessionView,
|
|
47
|
-
memory: GraphMemory,
|
|
48
|
-
nodeIndex: Map<string, Node>,
|
|
49
|
-
): SessionView {
|
|
50
|
-
const base = kernel as unknown as {
|
|
51
|
-
updateNode(cls: PathLike, ref: PathLike, props: Properties): Promise<void>
|
|
52
|
-
createNode(cls: PathLike, at: PathLike, props?: Properties): Promise<string>
|
|
53
|
-
as(cred: CredentialInput | (() => CredentialInput)): SessionView
|
|
54
|
-
}
|
|
55
|
-
const rawUpdate = base.updateNode.bind(base)
|
|
56
|
-
return extendCapabilities(kernel, {
|
|
57
|
-
updateNode: (cls: PathLike, ref: PathLike, props: Properties): Promise<void> => {
|
|
58
|
-
const node = indexedNode(nodeIndex, ref)
|
|
59
|
-
return node !== null ? memory.update(node, props) : rawUpdate(cls, ref, props)
|
|
60
|
-
},
|
|
61
|
-
createNode: (cls: PathLike, at: PathLike, props?: Properties): Promise<string> =>
|
|
62
|
-
memory.create(cls, at, props),
|
|
63
|
-
// Credential rebind stays on the raw kernel-client floor (§6 note).
|
|
64
|
-
as: (cred: CredentialInput | (() => CredentialInput)): SessionView => base.as(cred),
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Overlay memory writes without materializing a possibly virtual session surface. */
|
|
69
|
-
function extendCapabilities<Base extends object, Extension extends object>(
|
|
70
|
-
base: Base,
|
|
71
|
-
extension: Extension,
|
|
72
|
-
): Base & Extension {
|
|
73
|
-
return new Proxy(base as Base & Extension, {
|
|
74
|
-
get(target, prop, receiver) {
|
|
75
|
-
return Object.prototype.hasOwnProperty.call(extension, prop)
|
|
76
|
-
? Reflect.get(extension, prop, extension)
|
|
77
|
-
: Reflect.get(target, prop, receiver)
|
|
78
|
-
},
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** The tree path an `@<id>` write ref maps to, via the bind-time index; else null. */
|
|
83
|
-
function indexedNode(nodeIndex: Map<string, Node>, ref: PathLike): Node | null {
|
|
84
|
-
if (typeof ref !== 'string' || !ref.startsWith('@')) return null
|
|
85
|
-
return nodeIndex.get(ref.slice(1)) ?? null
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Record a bound node's raw value so the write cap retains its class and tree path. */
|
|
89
|
-
export function recordNode(nodeIndex: Map<string, Node>, node: unknown): void {
|
|
90
|
-
const wrapped = node as { raw?: unknown } | null
|
|
91
|
-
const candidate = wrapped?.raw !== null && typeof wrapped?.raw === 'object' ? wrapped.raw : node
|
|
92
|
-
const n = candidate as { id?: unknown; path?: { raw?: unknown } } | null
|
|
93
|
-
if (n !== null && typeof n.id === 'string' && typeof n.path?.raw === 'string') {
|
|
94
|
-
nodeIndex.set(n.id, candidate as Node)
|
|
95
|
-
}
|
|
96
|
-
}
|