@astrale-os/shell-react 0.2.10-beta.3 → 0.3.1
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 +5 -5
- package/dist/application/apps/app-host.d.ts.map +1 -1
- package/dist/application/apps/app-host.js +18 -39
- package/dist/application/apps/apps.hook.d.ts +4 -11
- package/dist/application/apps/apps.hook.d.ts.map +1 -1
- package/dist/application/apps/apps.hook.js +9 -49
- package/dist/application/apps/open-app.hook.d.ts +4 -7
- package/dist/application/apps/open-app.hook.d.ts.map +1 -1
- package/dist/application/apps/open-app.hook.js +2 -2
- package/dist/application/index.d.ts +1 -3
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +1 -2
- package/dist/application/spaces/space.hook.d.ts.map +1 -1
- package/dist/application/spaces/space.hook.js +4 -1
- package/dist/auth/act-as.context.d.ts +1 -1
- package/dist/auth/act-as.context.d.ts.map +1 -1
- package/dist/auth/auth.hook.d.ts +1 -1
- package/dist/auth/auth.hook.d.ts.map +1 -1
- package/dist/auth/can.hook.d.ts +2 -2
- package/dist/auth/can.hook.d.ts.map +1 -1
- package/dist/auth/self.hook.d.ts +1 -1
- package/dist/auth/self.hook.d.ts.map +1 -1
- package/dist/components/can.d.ts +2 -2
- package/dist/components/can.d.ts.map +1 -1
- package/dist/graph/call/call.hook.d.ts +2 -2
- package/dist/graph/call/call.hook.d.ts.map +1 -1
- package/dist/graph/call/stream.hook.d.ts +2 -2
- package/dist/graph/call/stream.hook.d.ts.map +1 -1
- package/dist/graph/graph.context.d.ts +1 -1
- package/dist/graph/graph.context.d.ts.map +1 -1
- package/dist/graph/guards.error.d.ts +4 -4
- package/dist/graph/guards.error.d.ts.map +1 -1
- package/dist/graph/guards.error.js +4 -4
- package/dist/graph/query-definition.hook.d.ts +1 -2
- package/dist/graph/query-definition.hook.d.ts.map +1 -1
- package/dist/graph/query-definition.hook.js +4 -10
- package/dist/graph/resource.d.ts +1 -1
- package/dist/graph/resource.d.ts.map +1 -1
- package/dist/graph/store.d.ts +2 -2
- package/dist/graph/store.d.ts.map +1 -1
- package/dist/graph/store.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/navigation/adapters/url.adapter.d.ts.map +1 -1
- package/dist/navigation/adapters/url.adapter.js +2 -5
- package/dist/navigation/codec.d.ts.map +1 -1
- package/dist/navigation/codec.js +1 -7
- package/dist/navigation/link.js +1 -1
- package/dist/navigation/scope.context.d.ts +1 -1
- package/dist/navigation/scope.context.d.ts.map +1 -1
- package/dist/navigation/scope.context.js +3 -6
- package/dist/navigation/snapshot.d.ts +1 -1
- package/dist/navigation/snapshot.d.ts.map +1 -1
- package/dist/navigation/snapshot.js +2 -8
- package/dist/navigation/view-key.d.ts +3 -0
- package/dist/navigation/view-key.d.ts.map +1 -0
- package/dist/navigation/view-key.js +8 -0
- package/dist/schema/action.hook.d.ts +11 -7
- package/dist/schema/action.hook.d.ts.map +1 -1
- package/dist/schema/action.hook.js +11 -6
- package/dist/schema/domain.hook.js +12 -13
- package/dist/schema/kernel.hook.d.ts +1 -1
- package/dist/schema/kernel.hook.d.ts.map +1 -1
- package/dist/schema/kernel.hook.js +1 -1
- package/dist/schema/mutation.hook.d.ts +2 -2
- package/dist/schema/mutation.hook.d.ts.map +1 -1
- package/dist/schema/mutation.hook.js +6 -5
- package/dist/schema/object.hook.d.ts +3 -6
- package/dist/schema/object.hook.d.ts.map +1 -1
- package/dist/schema/object.hook.js +4 -5
- package/dist/schema/relation.hook.d.ts +29 -19
- package/dist/schema/relation.hook.d.ts.map +1 -1
- package/dist/schema/relation.hook.js +45 -63
- package/dist/selection/live.d.ts.map +1 -1
- package/dist/selection/live.js +1 -2
- package/dist/session/session.context.d.ts +3 -4
- package/dist/session/session.context.d.ts.map +1 -1
- package/package.json +4 -14
- package/src/application/apps/app-host.tsx +22 -52
- package/src/application/apps/apps.hook.ts +14 -64
- package/src/application/apps/open-app.hook.ts +5 -10
- package/src/application/index.ts +2 -12
- package/src/application/spaces/space.hook.ts +6 -1
- package/src/auth/act-as.context.tsx +1 -1
- package/src/auth/auth.hook.ts +1 -1
- package/src/auth/can.hook.ts +3 -3
- package/src/auth/self.hook.ts +1 -1
- package/src/components/can.tsx +2 -2
- package/src/graph/call/call.hook.ts +2 -2
- package/src/graph/call/stream.hook.ts +2 -2
- package/src/graph/graph.context.ts +1 -1
- package/src/graph/guards.error.ts +4 -4
- package/src/graph/query-definition.hook.ts +13 -23
- package/src/graph/resource.ts +1 -1
- package/src/graph/store.ts +3 -3
- package/src/index.ts +3 -7
- package/src/navigation/adapters/url.adapter.ts +3 -4
- package/src/navigation/codec.ts +1 -7
- package/src/navigation/link.tsx +1 -1
- package/src/navigation/scope.context.tsx +5 -6
- package/src/navigation/snapshot.ts +4 -9
- package/src/navigation/view-key.ts +11 -0
- package/src/schema/action.hook.ts +45 -28
- package/src/schema/domain.hook.ts +9 -10
- package/src/schema/kernel.hook.ts +1 -1
- package/src/schema/mutation.hook.ts +13 -9
- package/src/schema/object.hook.ts +10 -18
- package/src/schema/relation.hook.ts +127 -145
- package/src/selection/live.ts +1 -2
- package/src/session/session.context.ts +3 -4
- package/dist/application/apps/domains.hook.d.ts +0 -7
- package/dist/application/apps/domains.hook.d.ts.map +0 -1
- package/dist/application/apps/domains.hook.js +0 -18
- package/src/application/apps/domains.hook.ts +0 -37
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.hook.d.ts","sourceRoot":"","sources":["../../src/schema/relation.hook.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"relation.hook.d.ts","sourceRoot":"","sources":["../../src/schema/relation.hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { NodeId } from '@astrale-os/sdk/graph/node';
|
|
2
1
|
import { Path } from '@astrale-os/sdk/graph/path';
|
|
3
2
|
import { Query } from '@astrale-os/sdk/query';
|
|
3
|
+
import { ClassKey } from '@astrale-os/sdk/schema';
|
|
4
4
|
import { useCallback, useMemo } from 'react';
|
|
5
5
|
import { useStoreResource } from '../graph/resource.js';
|
|
6
6
|
import { bindingFor } from './domain.hook.js';
|
|
@@ -13,28 +13,23 @@ export class RelationUnavailableError extends Error {
|
|
|
13
13
|
this.name = 'RelationUnavailableError';
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
/** Traverse one
|
|
17
|
-
export function useRelation(
|
|
18
|
-
const binding = bindingFor(
|
|
19
|
-
if (source !== null && source !== undefined)
|
|
20
|
-
admitSource(binding,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const path = source === null || source === undefined ? null : Path.id(NodeId(source.id));
|
|
16
|
+
/** Traverse one directed resolved Edge Class and bind the selected opposite Nodes. */
|
|
17
|
+
export function useRelation(relation, source, options) {
|
|
18
|
+
const binding = bindingFor(relation);
|
|
19
|
+
if (source !== null && source !== undefined)
|
|
20
|
+
admitSource(binding, relation, options.from, source);
|
|
21
|
+
admitRelatedDefinition(binding, relation, options.from, options.to);
|
|
22
|
+
const path = source === null || source === undefined ? null : Path.id(source.id);
|
|
24
23
|
const query = useMemo(() => {
|
|
25
24
|
if (path === null)
|
|
26
25
|
return null;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const expanded = admitted.expand({
|
|
30
|
-
via: [definition.schemaRef],
|
|
26
|
+
const expanded = Query.from({ nodes: [path] }).expand({
|
|
27
|
+
via: [relation],
|
|
31
28
|
direction: options.from === 'source' ? 'outgoing' : 'incoming',
|
|
32
29
|
});
|
|
33
|
-
return expanded
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}, [definition, options.from, options.to, path?.raw, source]);
|
|
37
|
-
const cardinality = effectiveCardinality(binding, definition, options.from, options.to);
|
|
30
|
+
return expanded.filter({ class: options.to }).select({ kind: 'graph', binding: expanded.node });
|
|
31
|
+
}, [relation, options.from, options.to, path?.raw]);
|
|
32
|
+
const cardinality = effectiveCardinality(binding, relation, options.from, options.to);
|
|
38
33
|
const project = useCallback((response) => {
|
|
39
34
|
const result = response.result;
|
|
40
35
|
if (result.kind !== 'graph' || result.selection.kind !== 'node') {
|
|
@@ -47,10 +42,7 @@ export function useRelation(definition, source, options) {
|
|
|
47
42
|
const byId = new Map(result.graph.nodes.map((node) => [node.id, node]));
|
|
48
43
|
const values = result.selection.ids.flatMap((id) => {
|
|
49
44
|
const node = byId.get(id);
|
|
50
|
-
|
|
51
|
-
return [];
|
|
52
|
-
const bind = binding.$.bind;
|
|
53
|
-
return [bind(options.to, node)];
|
|
45
|
+
return node === undefined ? [] : [binding.wrapNode(options.to, node)];
|
|
54
46
|
});
|
|
55
47
|
if (cardinality === '0..1')
|
|
56
48
|
return values[0] ?? null;
|
|
@@ -59,16 +51,12 @@ export function useRelation(definition, source, options) {
|
|
|
59
51
|
if (cardinality === '1..*' && values.length === 0)
|
|
60
52
|
return undefined;
|
|
61
53
|
return Object.freeze(values);
|
|
62
|
-
}, [binding, cardinality, options.to
|
|
54
|
+
}, [binding, cardinality, options.to]);
|
|
63
55
|
const resource = useStoreResource(query, options.page?.size ?? 50, project);
|
|
64
|
-
const unavailable = (cardinality === '1' &&
|
|
56
|
+
const unavailable = (cardinality === '1' || cardinality === '1..*') &&
|
|
65
57
|
resource.data === undefined &&
|
|
66
58
|
resource.state !== 'idle' &&
|
|
67
|
-
resource.state !== 'loading'
|
|
68
|
-
(cardinality === '1..*' &&
|
|
69
|
-
resource.data === undefined &&
|
|
70
|
-
resource.state !== 'idle' &&
|
|
71
|
-
resource.state !== 'loading')
|
|
59
|
+
resource.state !== 'loading'
|
|
72
60
|
? Object.freeze({ kind: 'required-hidden-or-invalid', cardinality })
|
|
73
61
|
: undefined;
|
|
74
62
|
const require = () => {
|
|
@@ -87,50 +75,44 @@ export function useRelation(definition, source, options) {
|
|
|
87
75
|
});
|
|
88
76
|
}
|
|
89
77
|
function admitSource(binding, relation, from, source) {
|
|
90
|
-
const
|
|
91
|
-
const matches =
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
78
|
+
const exact = binding.domain.definition(ClassKey.ref(ClassKey(source.class)));
|
|
79
|
+
const matches = exact?.ref.kind === 'class' &&
|
|
80
|
+
exact.kind === 'node' &&
|
|
81
|
+
edgeEndpoints(relation)[from].accepts.some((ref) => {
|
|
82
|
+
const accepted = binding.domain.definition(ref);
|
|
83
|
+
return accepted?.ref.kind === 'class' && accepted.kind === 'node' && exact.satisfies(accepted);
|
|
84
|
+
});
|
|
95
85
|
if (!matches)
|
|
96
86
|
throw new TypeError('Relation source does not satisfy the selected endpoint.');
|
|
97
87
|
}
|
|
98
|
-
function
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
88
|
+
function admitRelatedDefinition(binding, relation, from, to) {
|
|
89
|
+
const opposite = from === 'source' ? 'target' : 'source';
|
|
90
|
+
const matches = edgeEndpoints(relation)[opposite].accepts.some((ref) => {
|
|
91
|
+
const accepted = binding.domain.definition(ref);
|
|
92
|
+
return accepted?.ref.kind === 'class' && accepted.kind === 'node' && to.satisfies(accepted);
|
|
93
|
+
});
|
|
94
|
+
if (!matches) {
|
|
95
|
+
throw new TypeError('Relation target Class is not admitted by the opposite endpoint.');
|
|
103
96
|
}
|
|
104
|
-
return cardinality;
|
|
105
97
|
}
|
|
106
98
|
function effectiveCardinality(binding, relation, from, to) {
|
|
107
|
-
const
|
|
108
|
-
|
|
99
|
+
const endpoint = edgeEndpoints(relation)[from];
|
|
100
|
+
const base = from === 'source' ? endpoint.outgoing : endpoint.incoming;
|
|
101
|
+
if (base === undefined)
|
|
102
|
+
throw new TypeError(`Relation ${from} cardinality is absent.`);
|
|
103
|
+
if (base !== '1' && base !== '1..*')
|
|
109
104
|
return base;
|
|
110
|
-
}
|
|
111
|
-
const opposite = from === 'source' ? 'target' : 'source';
|
|
112
|
-
const coversEndpoint = edgeEndpoints(relation)[opposite].accepts.every((ref) => {
|
|
113
|
-
const candidate = binding.$.inspect(ref);
|
|
114
|
-
return candidate.satisfies(to);
|
|
115
|
-
});
|
|
116
|
-
return (coversEndpoint ? base : base === '1' ? '0..1' : '0..*');
|
|
117
|
-
}
|
|
118
|
-
function admitRelatedDefinition(binding, relation, from, to) {
|
|
119
105
|
const opposite = from === 'source' ? 'target' : 'source';
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return to.satisfies(candidate);
|
|
106
|
+
const covers = edgeEndpoints(relation)[opposite].accepts.every((ref) => {
|
|
107
|
+
const accepted = binding.domain.definition(ref);
|
|
108
|
+
return accepted?.ref.kind === 'class' && accepted.kind === 'node' && accepted.satisfies(to);
|
|
124
109
|
});
|
|
125
|
-
|
|
126
|
-
throw new TypeError('Relation target definition is not admitted by the opposite endpoint.');
|
|
110
|
+
return covers ? base : base === '1' ? '0..1' : '0..*';
|
|
127
111
|
}
|
|
128
112
|
function edgeEndpoints(relation) {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (declaration.family !== 'edge' || source === undefined || target === undefined) {
|
|
133
|
-
throw new TypeError('Relation definition does not expose admitted Edge endpoints.');
|
|
113
|
+
const definition = relation.definition;
|
|
114
|
+
if (definition.orientation !== 'directed') {
|
|
115
|
+
throw new TypeError('useRelation currently requires a directed Edge Class.');
|
|
134
116
|
}
|
|
135
|
-
return
|
|
117
|
+
return definition.endpoints;
|
|
136
118
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/selection/live.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/selection/live.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AAM9D,MAAM,MAAM,aAAa,GAAG,IAAI,CAAA;AAChC,YAAY,EAAE,MAAM,EAAE,CAAA;AAEtB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAUD,iGAAiG;AACjG,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CAgEjF"}
|
package/dist/selection/live.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Path } from '@astrale-os/sdk/graph/path';
|
|
2
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
2
|
import { useSessionKernel } from '../auth/session-kernel.js';
|
|
4
3
|
/** Resolve selected identities through the authenticated GraphApi; no fake live subscription. */
|
|
@@ -34,7 +33,7 @@ export function useResolvedNodes(orderedIds) {
|
|
|
34
33
|
}
|
|
35
34
|
setState({ key: currentKey, aliveIds: ids, nodes: [], pending: true, error: undefined });
|
|
36
35
|
try {
|
|
37
|
-
const values = await Promise.all(ids.map((nodeId) => graph.get(
|
|
36
|
+
const values = await Promise.all(ids.map((nodeId) => graph.get(nodeId)));
|
|
38
37
|
if (!alive.current || id !== generation.current)
|
|
39
38
|
return;
|
|
40
39
|
const aliveIds = [];
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { GraphStore } from '@astrale-os/
|
|
1
|
+
import type { GraphStore } from '@astrale-os/sdk/client/store';
|
|
2
2
|
import type { KernelClient, Shell } from '@astrale-os/shell';
|
|
3
3
|
import type { GraphStoreScope } from '../graph/store.js';
|
|
4
4
|
/**
|
|
5
|
-
* whoami's node type, derived from the auth surface so
|
|
6
|
-
*
|
|
7
|
-
* kernel-client — API §14 G8). Swap for the blessed re-export when it lands.
|
|
5
|
+
* whoami's node type, derived from the SDK auth surface so this package does
|
|
6
|
+
* not duplicate the canonical Client node projection.
|
|
8
7
|
*/
|
|
9
8
|
export type SelfNode = Awaited<ReturnType<KernelClient['auth']['whoami']>>;
|
|
10
9
|
/** The live shell for a provider subtree (and, later, an `<ActAs>` subtree). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.context.d.ts","sourceRoot":"","sources":["../../src/session/session.context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"session.context.d.ts","sourceRoot":"","sources":["../../src/session/session.context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAS5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;AAE1E,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAA;IACpC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AACD,eAAO,MAAM,YAAY,8CAA2C,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/shell-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
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": {
|
|
@@ -29,12 +29,7 @@
|
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@astrale-os/
|
|
33
|
-
"@astrale-os/kernel-core": ">=0.9.0-beta.7 <1.0.0",
|
|
34
|
-
"@astrale-os/kernel-dsl": ">=0.2.0-beta.5 <1.0.0",
|
|
35
|
-
"@astrale-os/kernel-protocol": ">=0.5.0-beta.7 <1.0.0",
|
|
36
|
-
"@astrale-os/kernel-server": ">=0.5.0-beta.8 <1.0.0",
|
|
37
|
-
"@astrale-os/sdk": ">=0.5.0-beta.14 <1.0.0",
|
|
32
|
+
"@astrale-os/sdk": ">=0.5.0-beta.17 <1.0.0",
|
|
38
33
|
"@testing-library/dom": "^10.4.0",
|
|
39
34
|
"@testing-library/react": "^16.3.0",
|
|
40
35
|
"@types/node": "^26.0.0",
|
|
@@ -48,15 +43,10 @@
|
|
|
48
43
|
"typescript": "~6.0.1-rc",
|
|
49
44
|
"vite": "^7.3.6",
|
|
50
45
|
"vitest": "^3.2.4",
|
|
51
|
-
"@astrale-os/shell": "0.
|
|
46
|
+
"@astrale-os/shell": "0.4.1"
|
|
52
47
|
},
|
|
53
48
|
"peerDependencies": {
|
|
54
|
-
"@astrale-os/
|
|
55
|
-
"@astrale-os/kernel-core": ">=0.9.0-beta.7 <1.0.0",
|
|
56
|
-
"@astrale-os/kernel-dsl": ">=0.2.0-beta.5 <1.0.0",
|
|
57
|
-
"@astrale-os/kernel-protocol": ">=0.5.0-beta.7 <1.0.0",
|
|
58
|
-
"@astrale-os/kernel-server": ">=0.5.0-beta.8 <1.0.0",
|
|
59
|
-
"@astrale-os/sdk": ">=0.5.0-beta.14 <1.0.0",
|
|
49
|
+
"@astrale-os/sdk": ">=0.5.0-beta.17 <1.0.0",
|
|
60
50
|
"@astrale-os/shell": ">=0.3.8-beta.3 <1.0.0",
|
|
61
51
|
"react": ">=18",
|
|
62
52
|
"react-dom": ">=18"
|
|
@@ -1,87 +1,57 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
AppSession,
|
|
4
|
-
HostCapabilities,
|
|
5
|
-
NodeTarget,
|
|
6
|
-
ResolvedView,
|
|
7
|
-
} from '@astrale-os/shell'
|
|
1
|
+
import type { Key } from '@astrale-os/sdk/schema'
|
|
2
|
+
import type { App, HostCapabilities, ResolvedView } from '@astrale-os/shell'
|
|
8
3
|
import type { CSSProperties, ReactElement, ReactNode } from 'react'
|
|
9
4
|
|
|
10
|
-
/**
|
|
11
|
-
* AppHost (API §12.2) = useOpenApp + ViewHost. Opens the app's `AppSession`,
|
|
12
|
-
* mounts its entry view with the session credential, and DISPOSES the session
|
|
13
|
-
* with the window (unmount, or an app change). `opening` renders while the
|
|
14
|
-
* session opens; `no-view` when the app pins no entrypoint; every mounted-frame
|
|
15
|
-
* phase is the window module's `WindowState`.
|
|
16
|
-
*/
|
|
17
5
|
import { forwardRef, useEffect, useRef, useState } from 'react'
|
|
18
6
|
|
|
19
7
|
import type { SandboxPolicy, ViewHostHandle } from '../../window/host.js'
|
|
20
8
|
import type { WindowState } from '../../window/lifecycle/states.js'
|
|
21
9
|
|
|
22
10
|
import { ViewHost } from '../../window/host.js'
|
|
23
|
-
import { toRef } from './apps.hook.js'
|
|
24
11
|
import { useOpenApp } from './open-app.hook.js'
|
|
25
12
|
|
|
26
|
-
/** The states `AppHost`'s fallback answers — the frame's, plus the two OS phases. */
|
|
27
13
|
export type AppHostFallbackState =
|
|
28
14
|
| WindowState
|
|
29
15
|
| { readonly phase: 'opening' }
|
|
30
16
|
| { readonly phase: 'no-view' }
|
|
31
17
|
|
|
32
18
|
export interface AppHostProps {
|
|
33
|
-
app:
|
|
34
|
-
/** Override the entry View
|
|
19
|
+
app: App | Key.Origin
|
|
20
|
+
/** Override the installed Domain entry View. */
|
|
35
21
|
view?: ResolvedView
|
|
36
22
|
capabilities?: HostCapabilities
|
|
37
23
|
sandbox?: SandboxPolicy
|
|
38
24
|
fallback?: (state: AppHostFallbackState) => ReactNode
|
|
39
|
-
onSession?: (session: AppSession) => void
|
|
40
25
|
className?: string
|
|
41
26
|
style?: CSSProperties
|
|
42
27
|
}
|
|
43
28
|
|
|
29
|
+
/** Resolve and mount an installed Domain through the ordinary Shell View lifecycle. */
|
|
44
30
|
export const AppHost = forwardRef<ViewHostHandle, AppHostProps>(
|
|
45
31
|
function AppHost(props, ref): ReactElement {
|
|
46
32
|
const open = useOpenApp()
|
|
47
|
-
const [
|
|
33
|
+
const [opened, setOpened] = useState<ResolvedView | null | undefined>(undefined)
|
|
48
34
|
const [error, setError] = useState<unknown>(undefined)
|
|
49
|
-
|
|
50
|
-
const appKey = toRef(props.app)
|
|
35
|
+
const origin = typeof props.app === 'string' ? props.app : props.app.origin
|
|
51
36
|
const openRef = useRef(open)
|
|
52
37
|
openRef.current = open
|
|
53
|
-
const appRef = useRef(props.app)
|
|
54
|
-
appRef.current = props.app
|
|
55
|
-
const onSessionRef = useRef(props.onSession)
|
|
56
|
-
onSessionRef.current = props.onSession
|
|
57
38
|
|
|
58
|
-
// Open (re)opens the session per app; the cleanup disposes it — so the session
|
|
59
|
-
// is torn down with the window (unmount) and swapped on an app change.
|
|
60
39
|
useEffect(() => {
|
|
61
|
-
let
|
|
62
|
-
|
|
63
|
-
setSession(null)
|
|
40
|
+
let active = true
|
|
41
|
+
setOpened(undefined)
|
|
64
42
|
setError(undefined)
|
|
65
|
-
void openRef.current(
|
|
66
|
-
(
|
|
67
|
-
if (
|
|
68
|
-
s.dispose()
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
opened = s
|
|
72
|
-
setSession(s)
|
|
73
|
-
onSessionRef.current?.(s)
|
|
43
|
+
void openRef.current(origin).then(
|
|
44
|
+
(view) => {
|
|
45
|
+
if (active) setOpened(view)
|
|
74
46
|
},
|
|
75
|
-
(
|
|
76
|
-
if (
|
|
47
|
+
(cause: unknown) => {
|
|
48
|
+
if (active) setError(cause)
|
|
77
49
|
},
|
|
78
50
|
)
|
|
79
51
|
return () => {
|
|
80
|
-
|
|
81
|
-
opened?.dispose()
|
|
52
|
+
active = false
|
|
82
53
|
}
|
|
83
|
-
|
|
84
|
-
}, [appKey])
|
|
54
|
+
}, [origin])
|
|
85
55
|
|
|
86
56
|
const { fallback, className, style } = props
|
|
87
57
|
const box = (children: ReactNode): ReactElement => (
|
|
@@ -90,20 +60,20 @@ export const AppHost = forwardRef<ViewHostHandle, AppHostProps>(
|
|
|
90
60
|
</div>
|
|
91
61
|
)
|
|
92
62
|
|
|
93
|
-
// A session-open failure has no window yet — `windowId` is honestly absent (§10).
|
|
94
63
|
if (error !== undefined) return box(fallback?.({ phase: 'crashed', error }) ?? null)
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
64
|
+
if (opened === undefined && props.view === undefined) {
|
|
65
|
+
return box(fallback?.({ phase: 'opening' }) ?? null)
|
|
66
|
+
}
|
|
67
|
+
const view = props.view ?? opened
|
|
68
|
+
if (view === null || view === undefined) return box(fallback?.({ phase: 'no-view' }) ?? null)
|
|
98
69
|
|
|
99
70
|
return (
|
|
100
71
|
<ViewHost
|
|
101
72
|
ref={ref}
|
|
102
73
|
view={view}
|
|
103
|
-
credential={session.credential}
|
|
104
74
|
capabilities={props.capabilities}
|
|
105
75
|
sandbox={props.sandbox}
|
|
106
|
-
fallback={fallback ? (
|
|
76
|
+
fallback={fallback ? (state: WindowState) => fallback(state) : undefined}
|
|
107
77
|
className={className}
|
|
108
78
|
style={style}
|
|
109
79
|
/>
|
|
@@ -1,88 +1,38 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ApplicationNode, NodeTarget, SpaceNode } from '@astrale-os/shell'
|
|
1
|
+
import type { App } from '@astrale-os/shell'
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
/**
|
|
6
|
-
* useApps(space?) (API §12.2) — the apps installed in a space (`installed_in`
|
|
7
|
-
* in-edges). No arg targets the CURRENT space (shared store, so a switch anywhere
|
|
8
|
-
* swaps the dock) and is IDLE while none is selected (§1.3); an explicit `null`
|
|
9
|
-
* stays idle; OS plane unavailable → fully idle. Also `toRef`, the app/space
|
|
10
|
-
* subject normalizer the apps hooks share.
|
|
11
|
-
*/
|
|
12
|
-
import { useCallback, useEffect, useMemo, useSyncExternalStore } from 'react'
|
|
3
|
+
import { useMemo } from 'react'
|
|
13
4
|
|
|
14
5
|
import type { ReadState } from '../../graph/memory/read/envelope.js'
|
|
15
|
-
import type { CurrentSpaceSnapshot } from '../spaces/current-space.store.js'
|
|
16
6
|
|
|
17
7
|
import { useAsyncResource } from '../../graph/async.js'
|
|
18
8
|
import { useShell } from '../../session/shell.hook.js'
|
|
19
|
-
import { currentSpaceStore } from '../spaces/current-space.store.js'
|
|
20
9
|
import { isOsPlaneAvailable } from '../user/user.store.js'
|
|
21
10
|
|
|
22
|
-
const NO_APPS: readonly
|
|
23
|
-
const IDLE_CURRENT: CurrentSpaceSnapshot = { space: null, pending: false, error: undefined }
|
|
11
|
+
const NO_APPS: readonly App[] = []
|
|
24
12
|
|
|
25
13
|
export interface AppsResult extends ReadState {
|
|
26
|
-
readonly apps: readonly
|
|
14
|
+
readonly apps: readonly App[]
|
|
27
15
|
}
|
|
28
16
|
|
|
29
|
-
|
|
17
|
+
/** Read the installed Domain applications available to the current Shell session. */
|
|
18
|
+
export function useApps(): AppsResult {
|
|
30
19
|
const shell = useShell()
|
|
31
20
|
const available = isOsPlaneAvailable(shell)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// window swaps the dock here (§12.2). An explicit `null` stays idle; an explicit
|
|
35
|
-
// space bypasses the store entirely (no needless currentSpace fetch). OS plane
|
|
36
|
-
// unavailable (§12.2) → fully idle.
|
|
37
|
-
const useCurrent = space === undefined
|
|
38
|
-
const store = currentSpaceStore(shell)
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
if (useCurrent && available) store.ensure()
|
|
41
|
-
}, [store, useCurrent, available])
|
|
42
|
-
const subscribe = useCallback(
|
|
43
|
-
(cb: () => void) => (useCurrent && available ? store.subscribe(cb) : () => {}),
|
|
44
|
-
[store, useCurrent, available],
|
|
45
|
-
)
|
|
46
|
-
const getSnapshot = useCallback(
|
|
47
|
-
(): CurrentSpaceSnapshot => (useCurrent && available ? store.getSnapshot() : IDLE_CURRENT),
|
|
48
|
-
[store, useCurrent, available],
|
|
49
|
-
)
|
|
50
|
-
const currentSnap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
|
|
51
|
-
|
|
52
|
-
const effective = useCurrent ? currentSnap.space : (space ?? null)
|
|
53
|
-
const effRef = effective === null ? null : toRef(effective)
|
|
54
|
-
const appsRes = useAsyncResource<readonly ApplicationNode[]>(
|
|
55
|
-
!available || effRef === null ? null : () => shell.apps.in(effRef),
|
|
21
|
+
const result = useAsyncResource<readonly App[]>(
|
|
22
|
+
available ? () => shell.apps.list() : null,
|
|
56
23
|
NO_APPS,
|
|
57
|
-
[shell,
|
|
24
|
+
[shell, available],
|
|
58
25
|
)
|
|
59
26
|
|
|
60
27
|
return useMemo<AppsResult>(
|
|
61
28
|
() => ({
|
|
62
|
-
apps:
|
|
63
|
-
pending:
|
|
64
|
-
error:
|
|
29
|
+
apps: result.data,
|
|
30
|
+
pending: result.pending,
|
|
31
|
+
error: result.error,
|
|
65
32
|
live: false,
|
|
66
33
|
seq: 0,
|
|
67
|
-
refetch:
|
|
34
|
+
refetch: result.refetch,
|
|
68
35
|
}),
|
|
69
|
-
[
|
|
36
|
+
[result.data, result.pending, result.error, result.refetch],
|
|
70
37
|
)
|
|
71
38
|
}
|
|
72
|
-
|
|
73
|
-
/** A bound-node-ish subject carries a graph id. */
|
|
74
|
-
function hasId(x: unknown): x is { readonly id: string } {
|
|
75
|
-
return typeof x === 'object' && x !== null && 'id' in x
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** An `@id` ref for a bound node, else the normalized ref of a raw subject. */
|
|
79
|
-
export function toRef(x: NodeTarget | { readonly id: string }): NodeTarget {
|
|
80
|
-
return hasId(x) ? x.id : x
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Stable dependency identity for one Shell node target. */
|
|
84
|
-
export function targetKey(x: NodeTarget | { readonly id: string }): string {
|
|
85
|
-
if (hasId(x)) return `id:${x.id}`
|
|
86
|
-
if (typeof x === 'string') return `text:${x}`
|
|
87
|
-
return `path:${Path.from(x as PathLike).raw}`
|
|
88
|
-
}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* app-open protocol lives in the shell package). Resolves to the session; disposal
|
|
4
|
-
* is the caller's (AppHost disposes it with the window).
|
|
5
|
-
*/
|
|
6
|
-
import type { ApplicationNode, AppSession, NodeTarget } from '@astrale-os/shell'
|
|
1
|
+
import type { Key } from '@astrale-os/sdk/schema'
|
|
2
|
+
import type { App, ResolvedView } from '@astrale-os/shell'
|
|
7
3
|
|
|
8
4
|
import type { Action } from '../../graph/action.js'
|
|
9
5
|
|
|
10
6
|
import { useAction } from '../../graph/action.js'
|
|
11
7
|
import { useShell } from '../../session/shell.hook.js'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export function useOpenApp(): Action<[ApplicationNode | NodeTarget], AppSession> {
|
|
8
|
+
/** Resolve one installed Domain's ordinary entry View. */
|
|
9
|
+
export function useOpenApp(): Action<[App | Key.Origin], ResolvedView | null> {
|
|
15
10
|
const shell = useShell()
|
|
16
|
-
return useAction((app:
|
|
11
|
+
return useAction((app: App | Key.Origin) => shell.apps.open(app))
|
|
17
12
|
}
|
package/src/application/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// application — API §12.2. The OS-plane hooks over the shell package's
|
|
2
2
|
// `shell.user/spaces/apps` namespaces + the window module: useUser, useSpaces,
|
|
3
|
-
// useCurrentSpace, useSpace, useApps,
|
|
3
|
+
// useCurrentSpace, useSpace, useApps, useOpenApp,
|
|
4
4
|
// AppHost, AppLogo.
|
|
5
5
|
export { useUser } from './user/user.hook.js'
|
|
6
6
|
export { useSpaces } from './spaces/spaces.hook.js'
|
|
@@ -11,20 +11,10 @@ export { useSpace } from './spaces/space.hook.js'
|
|
|
11
11
|
export type { SpaceResult } from './spaces/space.hook.js'
|
|
12
12
|
export { useApps } from './apps/apps.hook.js'
|
|
13
13
|
export type { AppsResult } from './apps/apps.hook.js'
|
|
14
|
-
export { useInstalledDomains } from './apps/domains.hook.js'
|
|
15
|
-
export type { DomainsResult } from './apps/domains.hook.js'
|
|
16
14
|
export { useOpenApp } from './apps/open-app.hook.js'
|
|
17
15
|
export { AppHost } from './apps/app-host.js'
|
|
18
16
|
export type { AppHostFallbackState, AppHostProps } from './apps/app-host.js'
|
|
19
17
|
export { AppLogo } from './apps/app-logo.js'
|
|
20
18
|
export type { AppLogoProps } from './apps/app-logo.js'
|
|
21
19
|
// The OS node/session types (from the shell package, single import surface).
|
|
22
|
-
export type {
|
|
23
|
-
ApplicationNode,
|
|
24
|
-
AppSession,
|
|
25
|
-
DomainSearchResult,
|
|
26
|
-
NodeTarget,
|
|
27
|
-
ResolvedView,
|
|
28
|
-
SpaceNode,
|
|
29
|
-
UserNode,
|
|
30
|
-
} from '@astrale-os/shell'
|
|
20
|
+
export type { App, NodeTarget, ResolvedView, SpaceNode, UserNode } from '@astrale-os/shell'
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { PathLike } from '@astrale-os/sdk/graph/path'
|
|
1
2
|
import type { NodeTarget, SpaceNode } from '@astrale-os/shell'
|
|
2
3
|
|
|
4
|
+
import { Path } from '@astrale-os/sdk/graph/path'
|
|
3
5
|
/**
|
|
4
6
|
* useSpace(ref) (API §12.2) — a single space by ref; `null`/`undefined` (or an
|
|
5
7
|
* unavailable OS plane) is idle (§1.3). One-shot today (§12 flag).
|
|
@@ -11,7 +13,6 @@ import type { CurrentSpaceResult } from './current-space.hook.js'
|
|
|
11
13
|
import { useAsyncResource } from '../../graph/async.js'
|
|
12
14
|
import { isIdleInput } from '../../graph/memory/read/idle.js'
|
|
13
15
|
import { useShell } from '../../session/shell.hook.js'
|
|
14
|
-
import { targetKey } from '../apps/apps.hook.js'
|
|
15
16
|
import { isOsPlaneAvailable } from '../user/user.store.js'
|
|
16
17
|
|
|
17
18
|
export type SpaceResult = CurrentSpaceResult
|
|
@@ -38,3 +39,7 @@ export function useSpace(ref: NodeTarget | null | undefined): SpaceResult {
|
|
|
38
39
|
[idle, res],
|
|
39
40
|
)
|
|
40
41
|
}
|
|
42
|
+
|
|
43
|
+
function targetKey(input: NodeTarget): string {
|
|
44
|
+
return typeof input === 'string' ? `text:${input}` : `path:${Path.from(input as PathLike).raw}`
|
|
45
|
+
}
|
package/src/auth/auth.hook.ts
CHANGED
package/src/auth/can.hook.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NodeId } from '@astrale-os/sdk/graph/node'
|
|
2
2
|
import type { PathLike } from '@astrale-os/sdk/graph/path'
|
|
3
|
-
import type {
|
|
3
|
+
import type { PolicyRef } from '@astrale-os/sdk/schema'
|
|
4
4
|
|
|
5
5
|
import { Path } from '@astrale-os/sdk/graph/path'
|
|
6
6
|
import { useEffect, useState } from 'react'
|
|
@@ -14,7 +14,7 @@ export type PolicyObject = NodeId | { readonly id: NodeId }
|
|
|
14
14
|
* invoked callable remains the authorization enforcement point.
|
|
15
15
|
*/
|
|
16
16
|
export function useCan(
|
|
17
|
-
policy: PathLike |
|
|
17
|
+
policy: PathLike | PolicyRef | null | undefined,
|
|
18
18
|
object: PolicyObject | null | undefined,
|
|
19
19
|
): boolean | undefined {
|
|
20
20
|
const { kernel } = useIdentityBinding()
|
|
@@ -45,7 +45,7 @@ export function useCan(
|
|
|
45
45
|
return decision
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
function policyPath(policy: PathLike |
|
|
48
|
+
function policyPath(policy: PathLike | PolicyRef | null | undefined) {
|
|
49
49
|
if (policy === null || policy === undefined) return null
|
|
50
50
|
return policy instanceof Path || typeof policy === 'string'
|
|
51
51
|
? Path.from(policy).raw
|
package/src/auth/self.hook.ts
CHANGED