@astrale-os/shell-react 0.2.1 → 0.2.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/graph/query/neighbors.hook.js +2 -5
- package/dist/schema/binding.d.ts.map +1 -1
- package/dist/schema/binding.js +9 -9
- package/dist/schema/method.hook.js +2 -2
- package/dist/schema/write.d.ts.map +1 -1
- package/dist/schema/write.js +9 -3
- package/package.json +6 -6
- package/src/graph/query/neighbors.hook.ts +3 -11
- package/src/schema/binding.ts +17 -20
- package/src/schema/method.hook.ts +7 -7
- package/src/schema/write.ts +13 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useOut / useIn (API §6) — the public typed traversal read hooks. Resolve
|
|
3
|
-
* endpoints one-shot through `BoundNode.out/in` (`live: false`); become live with
|
|
3
|
+
* endpoints one-shot through `BoundNode.links.out/in` (`live: false`); become live with
|
|
4
4
|
* no surface change once edge-endpoint ids land. Deviations tracked in API §6/G6.
|
|
5
5
|
*/
|
|
6
6
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
@@ -17,10 +17,7 @@ function useEndpoint(node, edge, side, _opts) {
|
|
|
17
17
|
const run = useCallback(async () => {
|
|
18
18
|
if (isIdleInput(node))
|
|
19
19
|
return null;
|
|
20
|
-
|
|
21
|
-
// → createBoundNode) carries out/in. The edge name is typed by the caller.
|
|
22
|
-
const t = node;
|
|
23
|
-
const result = await (side === 'out' ? t.out(edge) : t.in(edge));
|
|
20
|
+
const result = await (side === 'out' ? node.links.out(edge) : node.links.in(edge));
|
|
24
21
|
if (schema !== undefined)
|
|
25
22
|
tagEndpoints(result, schema);
|
|
26
23
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/schema/binding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AACrF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/schema/binding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AACrF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAQ5D;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,WAAW,GAClB,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAa3B;AAyCD,YAAY,EAAE,YAAY,EAAE,CAAA"}
|
package/dist/schema/binding.js
CHANGED
|
@@ -15,22 +15,21 @@ export function bindingFor(kernel, schema, memory) {
|
|
|
15
15
|
bySchema = new WeakMap();
|
|
16
16
|
bindingCache.set(kernel, bySchema);
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
const cached = bySchema.get(schema);
|
|
19
|
+
if (cached !== undefined)
|
|
20
|
+
return cached;
|
|
21
|
+
const { writable, pathIndex } = writableFor(kernel, memory);
|
|
22
|
+
const binding = tagBinding(createSchemaBoundView(writable, schema), schema, pathIndex);
|
|
23
|
+
bySchema.set(schema, binding);
|
|
24
24
|
return binding;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Wrap a binding so `bind`/`bindAny`/`as` outputs carry a schema tag, and every
|
|
28
28
|
* bound wire node's `id → tree path` is recorded (the write cap's index); the
|
|
29
|
-
*
|
|
29
|
+
* class handles and every other member pass straight through.
|
|
30
30
|
*/
|
|
31
31
|
function tagBinding(binding, schema, pathIndex) {
|
|
32
32
|
const handler = {
|
|
33
|
-
apply: (target, _thisArg, args) => target(...args),
|
|
34
33
|
get: (target, prop, receiver) => {
|
|
35
34
|
const value = Reflect.get(target, prop, receiver);
|
|
36
35
|
if (prop === 'bind') {
|
|
@@ -46,7 +45,8 @@ function tagBinding(binding, schema, pathIndex) {
|
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
47
|
if (prop === 'as') {
|
|
49
|
-
|
|
48
|
+
const as = value;
|
|
49
|
+
return (credential) => tagBinding(as(credential), schema, pathIndex);
|
|
50
50
|
}
|
|
51
51
|
return value;
|
|
52
52
|
},
|
|
@@ -33,10 +33,10 @@ export function useMethod(schema, type, method, opts) {
|
|
|
33
33
|
return useAction(call);
|
|
34
34
|
}
|
|
35
35
|
function staticCall(binding, type, method, params) {
|
|
36
|
-
return binding
|
|
36
|
+
return binding.classes[type][method](params);
|
|
37
37
|
}
|
|
38
38
|
function instance(binding, type, ref, method, params) {
|
|
39
|
-
return binding(
|
|
39
|
+
return binding.classes[type](ref)[method](params);
|
|
40
40
|
}
|
|
41
41
|
/** Read the method's `static` flag from the schema (own + inherited). */
|
|
42
42
|
function detectStatic(schema, type, method) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/schema/write.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAE5D;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC;AAGD,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,cAAc,CAQpF;
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/schema/write.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAE5D;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC;AAGD,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,cAAc,CAQpF;AAkDD,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAK9E"}
|
package/dist/schema/write.js
CHANGED
|
@@ -19,8 +19,7 @@ export function writableFor(kernel, memory) {
|
|
|
19
19
|
function withMemoryWrites(kernel, memory, pathIndex) {
|
|
20
20
|
const base = kernel;
|
|
21
21
|
const rawUpdate = base.updateNode.bind(base);
|
|
22
|
-
return {
|
|
23
|
-
...kernel,
|
|
22
|
+
return extendCapabilities(kernel, {
|
|
24
23
|
updateNode: (cls, ref, props) => {
|
|
25
24
|
const path = treePathFor(pathIndex, ref);
|
|
26
25
|
return path !== null ? memory.update(path, props) : rawUpdate(cls, ref, props);
|
|
@@ -28,7 +27,14 @@ function withMemoryWrites(kernel, memory, pathIndex) {
|
|
|
28
27
|
createNode: (cls, at, props) => memory.create(cls, at, props),
|
|
29
28
|
// Credential rebind stays on the raw kernel-client floor (§6 note).
|
|
30
29
|
as: (cred) => base.as(cred),
|
|
31
|
-
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Clone the complete session capability object before overlaying memory writes. */
|
|
33
|
+
function extendCapabilities(base, extension) {
|
|
34
|
+
const result = Object.create(Object.getPrototypeOf(base));
|
|
35
|
+
Object.defineProperties(result, Object.getOwnPropertyDescriptors(base));
|
|
36
|
+
Object.defineProperties(result, Object.getOwnPropertyDescriptors(extension));
|
|
37
|
+
return result;
|
|
32
38
|
}
|
|
33
39
|
/** The tree path an `@<id>` write ref maps to, via the bind-time index; else null. */
|
|
34
40
|
function treePathFor(pathIndex, ref) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/shell-react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Astrale shell-react — the React face of the shell (provider, hooks, view components)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@astrale-domains/shell-schema": ">=0.3.
|
|
29
|
-
"@astrale-os/kernel-client": ">=0.4.
|
|
30
|
-
"@astrale-os/kernel-core": ">=0.7.
|
|
31
|
-
"@astrale-os/kernel-dsl": ">=0.1.
|
|
28
|
+
"@astrale-domains/shell-schema": ">=0.3.2 <1.0.0",
|
|
29
|
+
"@astrale-os/kernel-client": ">=0.4.6 <1.0.0",
|
|
30
|
+
"@astrale-os/kernel-core": ">=0.7.5 <1.0.0",
|
|
31
|
+
"@astrale-os/kernel-dsl": ">=0.1.4 <1.0.0",
|
|
32
32
|
"jose": "^6.2.3",
|
|
33
33
|
"zod": "^4.3.6"
|
|
34
34
|
},
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"react-dom": "^19.2.0",
|
|
45
45
|
"typescript": "~6.0.1-rc",
|
|
46
46
|
"vitest": "^3.2.4",
|
|
47
|
-
"@astrale-os/shell": "0.3.
|
|
47
|
+
"@astrale-os/shell": "0.3.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@astrale-os/shell": ">=0.2.0 <1.0.0",
|
|
@@ -3,7 +3,7 @@ import type { Schema } from '@astrale-os/kernel-dsl'
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* useOut / useIn (API §6) — the public typed traversal read hooks. Resolve
|
|
6
|
-
* endpoints one-shot through `BoundNode.out/in` (`live: false`); become live with
|
|
6
|
+
* endpoints one-shot through `BoundNode.links.out/in` (`live: false`); become live with
|
|
7
7
|
* no surface change once edge-endpoint ids land. Deviations tracked in API §6/G6.
|
|
8
8
|
*/
|
|
9
9
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
@@ -35,24 +35,16 @@ type EndpointEnvelope<S extends Schema> = ReadState & {
|
|
|
35
35
|
readonly nodes?: readonly AnyBoundNode<S>[]
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
interface Traversal {
|
|
39
|
-
out(edge: string): Promise<unknown>
|
|
40
|
-
in(edge: string): Promise<unknown>
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
function useEndpoint<S extends Schema>(
|
|
44
39
|
node: AnyBoundNode<S> | null | undefined,
|
|
45
|
-
edge:
|
|
40
|
+
edge: EdgeNames<S>,
|
|
46
41
|
side: 'out' | 'in',
|
|
47
42
|
_opts?: ReadOptions,
|
|
48
43
|
): EndpointEnvelope<S> {
|
|
49
44
|
const schema = isIdleInput(node) ? undefined : schemaOf(node)
|
|
50
45
|
const run = useCallback(async (): Promise<unknown> => {
|
|
51
46
|
if (isIdleInput(node)) return null
|
|
52
|
-
|
|
53
|
-
// → createBoundNode) carries out/in. The edge name is typed by the caller.
|
|
54
|
-
const t = node as unknown as Traversal
|
|
55
|
-
const result = await (side === 'out' ? t.out(edge) : t.in(edge))
|
|
47
|
+
const result = await (side === 'out' ? node.links.out(edge) : node.links.in(edge))
|
|
56
48
|
if (schema !== undefined) tagEndpoints(result, schema)
|
|
57
49
|
return result
|
|
58
50
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
package/src/schema/binding.ts
CHANGED
|
@@ -18,10 +18,8 @@ import type { SessionView } from '../auth/act-as.context.js'
|
|
|
18
18
|
import { tagSchema } from './tag.js'
|
|
19
19
|
import { recordPath, writableFor } from './write.js'
|
|
20
20
|
|
|
21
|
-
type AnyBinding = SchemaBoundView<Schema, FnMap>
|
|
22
|
-
|
|
23
21
|
/** One tagged binding per (kernel, schema) — shared across the whole tree. */
|
|
24
|
-
const bindingCache = new WeakMap<object, WeakMap<Schema,
|
|
22
|
+
const bindingCache = new WeakMap<object, WeakMap<Schema, unknown>>()
|
|
25
23
|
|
|
26
24
|
/**
|
|
27
25
|
* Resolve (and memoize) the tagged schema-bound handle for `schema` on `kernel`.
|
|
@@ -39,28 +37,26 @@ export function bindingFor<S extends Schema>(
|
|
|
39
37
|
bySchema = new WeakMap()
|
|
40
38
|
bindingCache.set(kernel, bySchema)
|
|
41
39
|
}
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return binding
|
|
40
|
+
const cached = bySchema.get(schema)
|
|
41
|
+
if (cached !== undefined) return cached as SchemaBoundView<S, FnMap>
|
|
42
|
+
|
|
43
|
+
const { writable, pathIndex } = writableFor(kernel, memory)
|
|
44
|
+
const binding = tagBinding(createSchemaBoundView(writable, schema), schema, pathIndex)
|
|
45
|
+
bySchema.set(schema, binding)
|
|
46
|
+
return binding
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
/**
|
|
52
50
|
* Wrap a binding so `bind`/`bindAny`/`as` outputs carry a schema tag, and every
|
|
53
51
|
* bound wire node's `id → tree path` is recorded (the write cap's index); the
|
|
54
|
-
*
|
|
52
|
+
* class handles and every other member pass straight through.
|
|
55
53
|
*/
|
|
56
|
-
function tagBinding(
|
|
57
|
-
binding:
|
|
58
|
-
schema:
|
|
54
|
+
function tagBinding<S extends Schema>(
|
|
55
|
+
binding: SchemaBoundView<S, FnMap>,
|
|
56
|
+
schema: S,
|
|
59
57
|
pathIndex: Map<string, string>,
|
|
60
|
-
):
|
|
61
|
-
const handler: ProxyHandler<
|
|
62
|
-
apply: (target, _thisArg, args) =>
|
|
63
|
-
(target as unknown as (...a: unknown[]) => unknown)(...(args as unknown[])),
|
|
58
|
+
): SchemaBoundView<S, FnMap> {
|
|
59
|
+
const handler: ProxyHandler<SchemaBoundView<S, FnMap>> = {
|
|
64
60
|
get: (target, prop, receiver) => {
|
|
65
61
|
const value = Reflect.get(target, prop, receiver) as unknown
|
|
66
62
|
if (prop === 'bind') {
|
|
@@ -79,8 +75,9 @@ function tagBinding(
|
|
|
79
75
|
}
|
|
80
76
|
}
|
|
81
77
|
if (prop === 'as') {
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
const as = value as SchemaBoundView<S, FnMap>['as']
|
|
79
|
+
return (credential: Parameters<typeof as>[0]) =>
|
|
80
|
+
tagBinding(as(credential), schema, pathIndex)
|
|
84
81
|
}
|
|
85
82
|
return value
|
|
86
83
|
},
|
|
@@ -45,7 +45,7 @@ export function useMethod<S extends Schema, T extends TypeNames<S>, M extends Me
|
|
|
45
45
|
method: M,
|
|
46
46
|
opts?: MethodOptions,
|
|
47
47
|
): Action<never[], unknown> {
|
|
48
|
-
const binding = useDomain(schema) as unknown as
|
|
48
|
+
const binding = useDomain(schema) as unknown as DynamicBinding
|
|
49
49
|
const on = opts?.on
|
|
50
50
|
const isStatic = useMemo(() => detectStatic(schema, type, String(method)), [schema, type, method])
|
|
51
51
|
|
|
@@ -70,26 +70,26 @@ export function useMethod<S extends Schema, T extends TypeNames<S>, M extends Me
|
|
|
70
70
|
return useAction(call)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
type
|
|
73
|
+
type DynamicClassHandle = Dispatch & ((ref: NodeRefInput) => Dispatch)
|
|
74
|
+
type DynamicBinding = { classes: Record<string, DynamicClassHandle> }
|
|
75
75
|
|
|
76
76
|
function staticCall(
|
|
77
|
-
binding:
|
|
77
|
+
binding: DynamicBinding,
|
|
78
78
|
type: string,
|
|
79
79
|
method: string,
|
|
80
80
|
params: unknown,
|
|
81
81
|
): Promise<unknown> {
|
|
82
|
-
return
|
|
82
|
+
return binding.classes[type]![method]!(params)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function instance(
|
|
86
|
-
binding:
|
|
86
|
+
binding: DynamicBinding,
|
|
87
87
|
type: string,
|
|
88
88
|
ref: NodeRefInput,
|
|
89
89
|
method: string,
|
|
90
90
|
params: unknown,
|
|
91
91
|
): Promise<unknown> {
|
|
92
|
-
return
|
|
92
|
+
return binding.classes[type]!(ref)[method]!(params)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/** Read the method's `static` flag from the schema (own + inherited). */
|
package/src/schema/write.ts
CHANGED
|
@@ -52,8 +52,7 @@ function withMemoryWrites(
|
|
|
52
52
|
as(cred: CredentialInput | (() => CredentialInput)): SessionView
|
|
53
53
|
}
|
|
54
54
|
const rawUpdate = base.updateNode.bind(base)
|
|
55
|
-
return {
|
|
56
|
-
...(kernel as object),
|
|
55
|
+
return extendCapabilities(kernel, {
|
|
57
56
|
updateNode: (cls: PathLike, ref: PathLike, props: Properties): Promise<void> => {
|
|
58
57
|
const path = treePathFor(pathIndex, ref)
|
|
59
58
|
return path !== null ? memory.update(path, props) : rawUpdate(cls, ref, props)
|
|
@@ -62,7 +61,18 @@ function withMemoryWrites(
|
|
|
62
61
|
memory.create(cls, at, props),
|
|
63
62
|
// Credential rebind stays on the raw kernel-client floor (§6 note).
|
|
64
63
|
as: (cred: CredentialInput | (() => CredentialInput)): SessionView => base.as(cred),
|
|
65
|
-
}
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Clone the complete session capability object before overlaying memory writes. */
|
|
68
|
+
function extendCapabilities<Base extends object, Extension extends object>(
|
|
69
|
+
base: Base,
|
|
70
|
+
extension: Extension,
|
|
71
|
+
): Base & Extension {
|
|
72
|
+
const result = Object.create(Object.getPrototypeOf(base)) as Base & Extension
|
|
73
|
+
Object.defineProperties(result, Object.getOwnPropertyDescriptors(base))
|
|
74
|
+
Object.defineProperties(result, Object.getOwnPropertyDescriptors(extension))
|
|
75
|
+
return result
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
/** The tree path an `@<id>` write ref maps to, via the bind-time index; else null. */
|