@astrale-os/shell-react 0.2.9 → 0.2.10-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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 +7 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +4 -0
- package/dist/components/mount-domain-frontend.d.ts +22 -0
- package/dist/components/mount-domain-frontend.d.ts.map +1 -0
- package/dist/components/mount-domain-frontend.js +85 -0
- package/dist/components/view-app.d.ts +16 -0
- package/dist/components/view-app.d.ts.map +1 -0
- package/dist/components/view-app.js +16 -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 +9 -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/boundaries.tsx +113 -0
- package/src/components/can.tsx +16 -0
- package/src/components/index.ts +14 -0
- package/src/components/mount-domain-frontend.tsx +158 -0
- package/src/components/view-app.tsx +49 -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 +136 -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/dist/auth/can.hook.js
CHANGED
|
@@ -1,119 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Path } from '@astrale-os/sdk/graph/path';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useIdentityBinding } from './act-as.context.js';
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Deduped per (principal, perms, nodeId) across the whole tree via the principal's
|
|
6
|
-
* check ledger (folded in here as the dedup substrate). Standing-grant semantics:
|
|
7
|
-
* the dispatched call remains the gatekeeper — this is a UI affordance, not the
|
|
8
|
-
* enforcement point (SPEC §6.2). A local grant/revoke invalidates the ledger.
|
|
5
|
+
* Evaluate one declared Kernel policy for one exact graph object. This is a UI affordance; the
|
|
6
|
+
* invoked callable remains the authorization enforcement point.
|
|
9
7
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/** Normalize a `useCan` subject to a dispatchable `Ref` plus a stable dedup key. */
|
|
19
|
-
export function toRef(on) {
|
|
20
|
-
if (isNodeValue(on))
|
|
21
|
-
return { ref: on.path, key: `@${on.id}` };
|
|
22
|
-
return { ref: on, key: rawOf(on) };
|
|
23
|
-
}
|
|
24
|
-
// ── check ledger (the dedup substrate) ───────────────────────────────────────
|
|
25
|
-
/** One deduped check — its last-known value plus the subscribers watching it. */
|
|
26
|
-
class CheckCell {
|
|
27
|
-
auth;
|
|
28
|
-
perms;
|
|
29
|
-
on;
|
|
30
|
-
value = undefined;
|
|
31
|
-
inFlight = false;
|
|
32
|
-
listeners = new Set();
|
|
33
|
-
constructor(auth, perms, on) {
|
|
34
|
-
this.auth = auth;
|
|
35
|
-
this.perms = perms;
|
|
36
|
-
this.on = on;
|
|
37
|
-
}
|
|
38
|
-
subscribe = (onChange) => {
|
|
39
|
-
this.listeners.add(onChange);
|
|
40
|
-
this.ensure();
|
|
41
|
-
return () => this.listeners.delete(onChange);
|
|
42
|
-
};
|
|
43
|
-
getSnapshot = () => this.value;
|
|
44
|
-
/** Run the check once when the value is unknown and nothing is in flight. */
|
|
45
|
-
ensure() {
|
|
46
|
-
if (this.value !== undefined || this.inFlight)
|
|
47
|
-
return;
|
|
48
|
-
this.run();
|
|
49
|
-
}
|
|
50
|
-
/** Force a re-check (local grant/revoke on this principal). */
|
|
51
|
-
invalidate() {
|
|
52
|
-
if (this.listeners.size === 0) {
|
|
53
|
-
this.value = undefined; // recompute lazily on the next subscribe
|
|
8
|
+
export function useCan(policy, object) {
|
|
9
|
+
const { kernel } = useIdentityBinding();
|
|
10
|
+
const objectId = objectIdOf(object);
|
|
11
|
+
const policyTarget = policyPath(policy);
|
|
12
|
+
const [decision, setDecision] = useState(undefined);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (policyTarget === null || objectId === null) {
|
|
15
|
+
setDecision(undefined);
|
|
54
16
|
return;
|
|
55
17
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
.check({ on: this.on, perms: this.perms })
|
|
62
|
-
.then((ok) => {
|
|
63
|
-
this.value = ok;
|
|
18
|
+
let active = true;
|
|
19
|
+
setDecision(undefined);
|
|
20
|
+
void kernel.auth.can({ policy: policyTarget, object: objectId }).then((allowed) => {
|
|
21
|
+
if (active)
|
|
22
|
+
setDecision(allowed);
|
|
64
23
|
}, () => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
})
|
|
68
|
-
.finally(() => {
|
|
69
|
-
this.inFlight = false;
|
|
70
|
-
for (const l of this.listeners)
|
|
71
|
-
l();
|
|
24
|
+
if (active)
|
|
25
|
+
setDecision(undefined);
|
|
72
26
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
cells = new Map();
|
|
79
|
-
constructor(auth) {
|
|
80
|
-
this.auth = auth;
|
|
81
|
-
}
|
|
82
|
-
cell(key, perms, on) {
|
|
83
|
-
let cell = this.cells.get(key);
|
|
84
|
-
if (cell === undefined) {
|
|
85
|
-
cell = new CheckCell(this.auth, perms, on);
|
|
86
|
-
this.cells.set(key, cell);
|
|
87
|
-
}
|
|
88
|
-
return cell;
|
|
89
|
-
}
|
|
90
|
-
/** Re-check every observed cell — conservative Tier-0 sweep after a local grant/revoke. */
|
|
91
|
-
invalidateAll() {
|
|
92
|
-
for (const cell of this.cells.values())
|
|
93
|
-
cell.invalidate();
|
|
94
|
-
}
|
|
27
|
+
return () => {
|
|
28
|
+
active = false;
|
|
29
|
+
};
|
|
30
|
+
}, [kernel, policyTarget, objectId]);
|
|
31
|
+
return decision;
|
|
95
32
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
ledger = new CheckLedger(kernel.auth);
|
|
103
|
-
ledgers.set(kernel, ledger);
|
|
104
|
-
}
|
|
105
|
-
return ledger;
|
|
33
|
+
function policyPath(policy) {
|
|
34
|
+
if (policy === null || policy === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
return policy instanceof Path || typeof policy === 'string'
|
|
37
|
+
? Path.from(policy).raw
|
|
38
|
+
: Path.project(policy).raw;
|
|
106
39
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// The shared cell for (principal, perms, nodeId): identical to every other
|
|
112
|
-
// useCan reading the same triple, so one check serves the whole tree.
|
|
113
|
-
const cell = useMemo(() => ref === null ? null : ledgerFor(binding.kernel).cell(`${perms}\0${ref.key}`, perms, ref.ref),
|
|
114
|
-
// ref is rebuilt per render; its `key` string is the stable identity.
|
|
115
|
-
[binding.kernel, perms, ref?.key]);
|
|
116
|
-
const subscribe = useCallback((onChange) => (cell === null ? NOOP_UNSUB : cell.subscribe(onChange)), [cell]);
|
|
117
|
-
const getSnapshot = useCallback(() => cell?.getSnapshot(), [cell]);
|
|
118
|
-
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
40
|
+
function objectIdOf(value) {
|
|
41
|
+
if (value === null || value === undefined)
|
|
42
|
+
return null;
|
|
43
|
+
return typeof value === 'object' ? value.id : value;
|
|
119
44
|
}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { ActAs } from './act-as.context.js';
|
|
|
2
2
|
export type { ActAsProps } from './act-as.context.js';
|
|
3
3
|
export { useAuth } from './auth.hook.js';
|
|
4
4
|
export { useCan } from './can.hook.js';
|
|
5
|
+
export type { PolicyObject } from './can.hook.js';
|
|
5
6
|
export { useSelf } from './self.hook.js';
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA"}
|
package/dist/auth/self.hook.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function useSelf():
|
|
1
|
+
import type { Identity } from '@astrale-os/kernel-client/auth';
|
|
2
|
+
export declare function useSelf(): Identity;
|
|
3
3
|
//# sourceMappingURL=self.hook.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self.hook.d.ts","sourceRoot":"","sources":["../../src/auth/self.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"self.hook.d.ts","sourceRoot":"","sources":["../../src/auth/self.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAA;AAI9D,wBAAgB,OAAO,IAAI,QAAQ,CAElC"}
|
package/dist/auth/self.hook.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useSelf (API §4) — the caller's identity node, resolved at boot and read
|
|
3
|
-
* synchronously (never suspends). An <ActAs> subtree returns the acted-as
|
|
4
|
-
* identity. FLAG: today this is the boot-resolved whoami snapshot; it becomes a
|
|
5
|
-
* live memory shape once the graph plane subscribes the self node — no signature
|
|
6
|
-
* change.
|
|
7
|
-
*/
|
|
8
1
|
import { useIdentityBinding } from './act-as.context.js';
|
|
9
2
|
export function useSelf() {
|
|
10
3
|
return useIdentityBinding().self;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export declare function useSessionKernel(): SessionView;
|
|
1
|
+
import type { KernelClient } from '@astrale-os/shell';
|
|
2
|
+
export declare function useSessionKernel(): KernelClient;
|
|
4
3
|
//# sourceMappingURL=session-kernel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-kernel.d.ts","sourceRoot":"","sources":["../../src/auth/session-kernel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-kernel.d.ts","sourceRoot":"","sources":["../../src/auth/session-kernel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAOrD,wBAAgB,gBAAgB,IAAI,YAAY,CAM/C"}
|
|
@@ -1,21 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useSessionKernel (API §4) — the dispatch-floor resolver. Inside an `<ActAs>` it
|
|
3
|
-
* is the acted-as principal's bound session view; otherwise the root
|
|
4
|
-
* `shell.kernel`. Every dispatch floor (schema bindings, useCall/useStream, useMove,
|
|
5
|
-
* typed method dispatch) routes through this so a call runs as the subtree's
|
|
6
|
-
* principal — not the root — and its scoped memory.
|
|
7
|
-
*/
|
|
8
1
|
import { useContext } from 'react';
|
|
9
2
|
import { ShellContext } from '../session/session.context.js';
|
|
10
3
|
import { IdentityContext } from './act-as.context.js';
|
|
11
|
-
/** The EFFECTIVE dispatch kernel for this subtree. Throws outside a provider. */
|
|
12
4
|
export function useSessionKernel() {
|
|
13
|
-
const
|
|
5
|
+
const identity = useContext(IdentityContext);
|
|
14
6
|
const runtime = useContext(ShellContext);
|
|
15
|
-
if (
|
|
16
|
-
return
|
|
17
|
-
if (runtime === null)
|
|
7
|
+
if (identity !== null)
|
|
8
|
+
return identity.kernel;
|
|
9
|
+
if (runtime === null)
|
|
18
10
|
throw new Error('session hooks must be used within a <ShellProvider>');
|
|
19
|
-
}
|
|
20
11
|
return runtime.shell.kernel;
|
|
21
12
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CredentialSnapshot } from '@astrale-os/shell';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { Component } from 'react';
|
|
4
|
+
import type { GraphResource } from '../graph/resource.js';
|
|
5
|
+
import { useConnection } from '../session/connection/connection.hook.js';
|
|
6
|
+
export declare function ViewBoundary<T>(props: {
|
|
7
|
+
readonly resource: GraphResource<T>;
|
|
8
|
+
readonly children: (value: T) => ReactNode;
|
|
9
|
+
readonly loading?: ReactNode;
|
|
10
|
+
readonly empty?: ReactNode;
|
|
11
|
+
readonly error?: (error: unknown) => ReactNode;
|
|
12
|
+
}): ReactElement;
|
|
13
|
+
export declare const GraphBoundary: typeof ViewBoundary;
|
|
14
|
+
export interface ViewErrorBoundaryProps {
|
|
15
|
+
/** A render function receives the retry generation and can recreate rejected lazy resources. */
|
|
16
|
+
readonly children: ReactNode | ((generation: number) => ReactNode);
|
|
17
|
+
readonly fallback?: (error: unknown, retry: () => void) => ReactNode;
|
|
18
|
+
readonly onError?: (error: unknown) => void;
|
|
19
|
+
}
|
|
20
|
+
/** Catch Shell View render/lazy failures and remount the failed subtree on explicit retry. */
|
|
21
|
+
export declare class ViewErrorBoundary extends Component<ViewErrorBoundaryProps, {
|
|
22
|
+
readonly error: unknown;
|
|
23
|
+
readonly generation: number;
|
|
24
|
+
}> {
|
|
25
|
+
state: {
|
|
26
|
+
error: unknown;
|
|
27
|
+
generation: number;
|
|
28
|
+
};
|
|
29
|
+
static getDerivedStateFromError(error: unknown): {
|
|
30
|
+
error: unknown;
|
|
31
|
+
};
|
|
32
|
+
componentDidCatch(error: unknown): void;
|
|
33
|
+
private readonly retry;
|
|
34
|
+
render(): ReactNode;
|
|
35
|
+
}
|
|
36
|
+
export declare function defaultViewLoading(): ReactElement;
|
|
37
|
+
export declare function defaultViewError(_error: unknown, retry: () => void): ReactElement;
|
|
38
|
+
export declare function ConnectionBoundary(props: {
|
|
39
|
+
readonly children: ReactNode;
|
|
40
|
+
readonly fallback?: (status: ReturnType<typeof useConnection>) => ReactNode;
|
|
41
|
+
}): ReactElement;
|
|
42
|
+
export declare function CredentialBoundary(props: {
|
|
43
|
+
readonly credential: CredentialSnapshot;
|
|
44
|
+
readonly children: ReactNode;
|
|
45
|
+
readonly fallback?: (credential: CredentialSnapshot) => ReactNode;
|
|
46
|
+
}): ReactElement;
|
|
47
|
+
//# sourceMappingURL=boundaries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.d.ts","sourceRoot":"","sources":["../../src/components/boundaries.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,EAAE,SAAS,EAAY,MAAM,OAAO,CAAA;AAE3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAA;AAExE,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE;IACrC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,SAAS,CAAA;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,CAAA;CAC/C,GAAG,YAAY,CASf;AAED,eAAO,MAAM,aAAa,qBAAe,CAAA;AAEzC,MAAM,WAAW,sBAAsB;IACrC,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,CAAC,CAAA;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAA;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAED,8FAA8F;AAC9F,qBAAa,iBAAkB,SAAQ,SAAS,CAC9C,sBAAsB,EACtB;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CACzD;IACU,KAAK;QAAK,KAAK,EAAe,OAAO;QAAE,UAAU;MAAK;IAE/D,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO;;MAE7C;IAEQ,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/C;IAED,OAAO,CAAC,QAAQ,CAAC,KAAK,CAErB;IAEQ,MAAM,IAAI,SAAS,CAY3B;CACF;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAMjD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,YAAY,CASjF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,KAAK,SAAS,CAAA;CAC5E,GAAG,YAAY,CAOf;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,KAAK,SAAS,CAAA;CAClE,GAAG,YAAY,CAQf"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component, Fragment } from 'react';
|
|
3
|
+
import { useConnection } from '../session/connection/connection.hook.js';
|
|
4
|
+
export function ViewBoundary(props) {
|
|
5
|
+
const { resource } = props;
|
|
6
|
+
if (resource.state === 'failed') {
|
|
7
|
+
if (props.error !== undefined)
|
|
8
|
+
return _jsx(_Fragment, { children: props.error(resource.error) });
|
|
9
|
+
throw resource.error;
|
|
10
|
+
}
|
|
11
|
+
if (resource.data === undefined)
|
|
12
|
+
return _jsx(_Fragment, { children: props.loading ?? null });
|
|
13
|
+
if (resource.data === null)
|
|
14
|
+
return _jsx(_Fragment, { children: props.empty ?? null });
|
|
15
|
+
return _jsx(_Fragment, { children: props.children(resource.data) });
|
|
16
|
+
}
|
|
17
|
+
export const GraphBoundary = ViewBoundary;
|
|
18
|
+
/** Catch Shell View render/lazy failures and remount the failed subtree on explicit retry. */
|
|
19
|
+
export class ViewErrorBoundary extends Component {
|
|
20
|
+
state = { error: undefined, generation: 0 };
|
|
21
|
+
static getDerivedStateFromError(error) {
|
|
22
|
+
return { error };
|
|
23
|
+
}
|
|
24
|
+
componentDidCatch(error) {
|
|
25
|
+
this.props.onError?.(error);
|
|
26
|
+
}
|
|
27
|
+
retry = () => {
|
|
28
|
+
this.setState((state) => ({ error: undefined, generation: state.generation + 1 }));
|
|
29
|
+
};
|
|
30
|
+
render() {
|
|
31
|
+
if (this.state.error !== undefined) {
|
|
32
|
+
return (this.props.fallback?.(this.state.error, this.retry) ??
|
|
33
|
+
defaultViewError(this.state.error, this.retry));
|
|
34
|
+
}
|
|
35
|
+
const content = typeof this.props.children === 'function'
|
|
36
|
+
? this.props.children(this.state.generation)
|
|
37
|
+
: this.props.children;
|
|
38
|
+
return _jsx(Fragment, { children: content }, this.state.generation);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function defaultViewLoading() {
|
|
42
|
+
return (_jsx("div", { role: "status", "aria-live": "polite", children: "Loading view\u2026" }));
|
|
43
|
+
}
|
|
44
|
+
export function defaultViewError(_error, retry) {
|
|
45
|
+
return (_jsxs("section", { role: "alert", children: [_jsx("p", { children: "View could not load." }), _jsx("button", { type: "button", onClick: retry, children: "Retry" })] }));
|
|
46
|
+
}
|
|
47
|
+
export function ConnectionBoundary(props) {
|
|
48
|
+
const connection = useConnection();
|
|
49
|
+
return connection.status === 'ready' ? (_jsx(_Fragment, { children: props.children })) : (_jsx(_Fragment, { children: props.fallback?.(connection) ?? null }));
|
|
50
|
+
}
|
|
51
|
+
export function CredentialBoundary(props) {
|
|
52
|
+
return props.credential.state === 'valid' ||
|
|
53
|
+
props.credential.state === 'refreshing' ||
|
|
54
|
+
props.credential.state === 'degraded' ? (_jsx(_Fragment, { children: props.children })) : (_jsx(_Fragment, { children: props.fallback?.(props.credential) ?? null }));
|
|
55
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PathLike } from '@astrale-os/sdk/graph/path';
|
|
2
|
+
import type { schema } from '@astrale-os/sdk/schema';
|
|
3
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
4
|
+
import type { PolicyObject } from '../auth/can.hook.js';
|
|
5
|
+
export declare function Can(props: {
|
|
6
|
+
readonly policy: PathLike | schema.PolicyRef;
|
|
7
|
+
readonly object: PolicyObject;
|
|
8
|
+
readonly children: ReactNode;
|
|
9
|
+
readonly fallback?: ReactNode;
|
|
10
|
+
}): ReactElement;
|
|
11
|
+
//# sourceMappingURL=can.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"can.d.ts","sourceRoot":"","sources":["../../src/components/can.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAIvD,wBAAgB,GAAG,CAAC,KAAK,EAAE;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAA;IAC5C,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAC9B,GAAG,YAAY,CAEf"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCan } from '../auth/can.hook.js';
|
|
3
|
+
export function Can(props) {
|
|
4
|
+
return _jsx(_Fragment, { children: useCan(props.policy, props.object) === true ? props.children : props.fallback });
|
|
5
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Can } from './can.js';
|
|
2
|
+
export { ConnectionBoundary, CredentialBoundary, defaultViewError, defaultViewLoading, GraphBoundary, ViewErrorBoundary, ViewBoundary, } from './boundaries.js';
|
|
3
|
+
export type { ViewErrorBoundaryProps } from './boundaries.js';
|
|
4
|
+
export { ViewApp } from './view-app.js';
|
|
5
|
+
export { mountDomainFrontend } from './mount-domain-frontend.js';
|
|
6
|
+
export type { MountedDomainFrontend, MountDomainFrontendOptions } from './mount-domain-frontend.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,YAAY,GACb,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,YAAY,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { Can } from './can.js';
|
|
2
|
+
export { ConnectionBoundary, CredentialBoundary, defaultViewError, defaultViewLoading, GraphBoundary, ViewErrorBoundary, ViewBoundary, } from './boundaries.js';
|
|
3
|
+
export { ViewApp } from './view-app.js';
|
|
4
|
+
export { mountDomainFrontend } from './mount-domain-frontend.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReactRouteModule } from '@astrale-os/sdk/react';
|
|
2
|
+
import type { schema } from '@astrale-os/sdk/schema';
|
|
3
|
+
import type { Shell, ShellConfig } from '@astrale-os/shell';
|
|
4
|
+
import type { ReactNode } from 'react';
|
|
5
|
+
type ViewName<S extends schema.DomainSchema> = Extract<keyof ReactRouteModule<S>['routes'], string>;
|
|
6
|
+
export interface MountDomainFrontendOptions<S extends schema.DomainSchema, Name extends ViewName<S>> {
|
|
7
|
+
readonly root: Element | string;
|
|
8
|
+
readonly module: ReactRouteModule<S>;
|
|
9
|
+
readonly view: Name;
|
|
10
|
+
/** Defaults to the child-side sandbox handshake. A prebuilt Shell is the full-app escape hatch. */
|
|
11
|
+
readonly config?: ShellConfig | Shell;
|
|
12
|
+
readonly fallback?: ReactNode;
|
|
13
|
+
readonly errorFallback?: (error: unknown, retry: () => void) => ReactNode;
|
|
14
|
+
readonly onError?: (error: unknown) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface MountedDomainFrontend {
|
|
17
|
+
unmount(): void;
|
|
18
|
+
}
|
|
19
|
+
/** Browser bootstrap used by SDK-generated route entries and custom full React apps alike. */
|
|
20
|
+
export declare function mountDomainFrontend<const S extends schema.DomainSchema, const Name extends ViewName<S>>(options: MountDomainFrontendOptions<S, Name>): MountedDomainFrontend;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=mount-domain-frontend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount-domain-frontend.d.ts","sourceRoot":"","sources":["../../src/components/mount-domain-frontend.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAmC,MAAM,uBAAuB,CAAA;AAC9F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAoD,SAAS,EAAE,MAAM,OAAO,CAAA;AAWxF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,YAAY,IAAI,OAAO,CAAC,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;AAMnG,MAAM,WAAW,0BAA0B,CACzC,CAAC,SAAS,MAAM,CAAC,YAAY,EAC7B,IAAI,SAAS,QAAQ,CAAC,CAAC,CAAC;IAExB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,mGAAmG;IACnG,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,CAAA;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAA;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CACjC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,YAAY,EACnC,KAAK,CAAC,IAAI,SAAS,QAAQ,CAAC,CAAC,CAAC,EAC9B,OAAO,EAAE,0BAA0B,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,qBAAqB,CAgCrE"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createElement, lazy, Suspense } from 'react';
|
|
3
|
+
import { createRoot } from 'react-dom/client';
|
|
4
|
+
import { useHistoryVersion, useOptionalNavCtx } from '../navigation/scope.context.js';
|
|
5
|
+
import { useDomain } from '../schema/domain.hook.js';
|
|
6
|
+
import { useTargetPath } from '../window/hooks/target-node.hook.js';
|
|
7
|
+
import { defaultViewError, defaultViewLoading, ViewErrorBoundary } from './boundaries.js';
|
|
8
|
+
import { ViewApp } from './view-app.js';
|
|
9
|
+
/** Browser bootstrap used by SDK-generated route entries and custom full React apps alike. */
|
|
10
|
+
export function mountDomainFrontend(options) {
|
|
11
|
+
const rootElement = typeof options.root === 'string' ? document.querySelector(options.root) : options.root;
|
|
12
|
+
if (rootElement === null)
|
|
13
|
+
throw new Error(`React frontend root '${options.root}' was not found.`);
|
|
14
|
+
const route = options.module.routes[options.view];
|
|
15
|
+
if (route === undefined)
|
|
16
|
+
throw new Error(`React View '${options.view}' is not implemented.`);
|
|
17
|
+
const loading = options.fallback ?? defaultViewLoading();
|
|
18
|
+
const errorFallback = options.errorFallback ?? defaultViewError;
|
|
19
|
+
const routeRuntime = createRouteRuntime();
|
|
20
|
+
const root = createRoot(rootElement);
|
|
21
|
+
root.render(_jsx(ViewApp, { config: options.config ?? { mode: 'sandboxed' }, fallback: loading, errorFallback: errorFallback, onError: ({ error }) => options.onError?.(error), children: _jsx(ViewErrorBoundary, { fallback: errorFallback, onError: options.onError, children: (generation) => (_jsx(Suspense, { fallback: loading, children: _jsx(DomainRoute, { module: options.module, name: options.view, generation: generation, runtime: routeRuntime }) })) }) }));
|
|
22
|
+
return Object.freeze({ unmount: () => root.unmount() });
|
|
23
|
+
}
|
|
24
|
+
function DomainRoute(props) {
|
|
25
|
+
const domain = useDomain(props.module.schema);
|
|
26
|
+
const navigation = useOptionalNavCtx();
|
|
27
|
+
useHistoryVersion(navigation?.history ?? null);
|
|
28
|
+
const view = domain[props.name];
|
|
29
|
+
// Domain's schema-indexed conditional retains the exact authored View type,
|
|
30
|
+
// while the runtime member has Core's common rich Definition shape.
|
|
31
|
+
const runtimeView = view;
|
|
32
|
+
const targetPath = useTargetPath();
|
|
33
|
+
const implementation = props.module.routes[props.name];
|
|
34
|
+
const Component = props.runtime.component(props.generation, implementation);
|
|
35
|
+
const declaration = runtimeView.definition;
|
|
36
|
+
const target = declaration.target.kind === 'domain'
|
|
37
|
+
? Object.freeze({ kind: 'domain', origin: runtimeView.origin })
|
|
38
|
+
: targetPath === null
|
|
39
|
+
? missingTarget(runtimeView.name)
|
|
40
|
+
: targetPath;
|
|
41
|
+
const current = new URL(window.location.href);
|
|
42
|
+
const routeParams = navigation?.history.current?.params ?? directRouteParams(current);
|
|
43
|
+
const route = Object.freeze({
|
|
44
|
+
name: props.name,
|
|
45
|
+
href: current.href,
|
|
46
|
+
params: Object.freeze({ ...routeParams }),
|
|
47
|
+
});
|
|
48
|
+
return createElement(Component, { view, target, route });
|
|
49
|
+
}
|
|
50
|
+
function directRouteParams(url) {
|
|
51
|
+
const params = {};
|
|
52
|
+
const prefix = 'astrale.param.';
|
|
53
|
+
for (const key of new Set(url.searchParams.keys())) {
|
|
54
|
+
if (!key.startsWith(prefix))
|
|
55
|
+
continue;
|
|
56
|
+
const name = key.slice(prefix.length);
|
|
57
|
+
if (name.length === 0 || /token|credential|authorization|secret/i.test(name)) {
|
|
58
|
+
throw new TypeError(`React View route param '${name}' is invalid.`);
|
|
59
|
+
}
|
|
60
|
+
const values = url.searchParams.getAll(key);
|
|
61
|
+
if (values.length !== 1)
|
|
62
|
+
throw new TypeError(`React View route param '${name}' is duplicated.`);
|
|
63
|
+
params[name] = values[0];
|
|
64
|
+
}
|
|
65
|
+
return Object.freeze(params);
|
|
66
|
+
}
|
|
67
|
+
function createRouteRuntime() {
|
|
68
|
+
const generations = new Map();
|
|
69
|
+
return {
|
|
70
|
+
component(generation, implementation) {
|
|
71
|
+
let Component = generations.get(generation);
|
|
72
|
+
if (Component === undefined) {
|
|
73
|
+
Component = lazy(async () => {
|
|
74
|
+
const loaded = await implementation.component();
|
|
75
|
+
return { default: loaded.default };
|
|
76
|
+
});
|
|
77
|
+
generations.set(generation, Component);
|
|
78
|
+
}
|
|
79
|
+
return Component;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function missingTarget(name) {
|
|
84
|
+
throw new Error(`React View '${name}' requires a resource target from the Shell handshake.`);
|
|
85
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Shell, ShellConfig } from '@astrale-os/shell';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import type { NavAdapter } from '../navigation/adapters/adapter.js';
|
|
4
|
+
import type { NavTarget } from '../navigation/snapshot.js';
|
|
5
|
+
import type { ShellProviderProps } from '../session/provider.js';
|
|
6
|
+
/** One generated/default root; custom React apps may compose the lower-level providers directly. */
|
|
7
|
+
export declare function ViewApp(props: {
|
|
8
|
+
readonly config: ShellConfig | Shell;
|
|
9
|
+
readonly navigation?: NavAdapter;
|
|
10
|
+
readonly initial?: NavTarget;
|
|
11
|
+
readonly fallback?: ReactNode;
|
|
12
|
+
readonly errorFallback?: ShellProviderProps['errorFallback'];
|
|
13
|
+
readonly onError?: ShellProviderProps['onError'];
|
|
14
|
+
readonly children: ReactNode;
|
|
15
|
+
}): ReactElement;
|
|
16
|
+
//# sourceMappingURL=view-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-app.d.ts","sourceRoot":"","sources":["../../src/components/view-app.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAShE,oGAAoG;AACpG,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAA;IAC5D,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAA;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,GAAG,YAAY,CAWf"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { memoryAdapter } from '../navigation/adapters/memory.adapter.js';
|
|
3
|
+
import { urlAdapter } from '../navigation/adapters/url.adapter.js';
|
|
4
|
+
import { NavScope } from '../navigation/scope.context.js';
|
|
5
|
+
import { ShellProvider } from '../session/provider.js';
|
|
6
|
+
import { useShell } from '../session/shell.hook.js';
|
|
7
|
+
import { ViewStage } from '../window/stage.js';
|
|
8
|
+
/** One generated/default root; custom React apps may compose the lower-level providers directly. */
|
|
9
|
+
export function ViewApp(props) {
|
|
10
|
+
return (_jsx(ShellProvider, { config: props.config, fallback: props.fallback, errorFallback: props.errorFallback, onError: props.onError, children: _jsx(ViewAppRuntime, { ...props }) }));
|
|
11
|
+
}
|
|
12
|
+
function ViewAppRuntime(props) {
|
|
13
|
+
const shell = useShell();
|
|
14
|
+
const defaultAdapter = shell.hostCapabilities.navigation.history === 'browser' ? urlAdapter() : memoryAdapter();
|
|
15
|
+
return (_jsxs(NavScope, { adapter: props.navigation ?? defaultAdapter, initial: props.initial, children: [props.children, _jsx(ViewStage, {})] }));
|
|
16
|
+
}
|
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* structurally invalidatable (FRONTEND §5.7); a consumer that needs freshness
|
|
5
|
-
* owns its own refetch policy. Dispatch is a graph operation (rule 2).
|
|
6
|
-
*/
|
|
7
|
-
import type { CallFns, FnMap } from '@astrale-os/kernel-client';
|
|
1
|
+
import type { Call } from '@astrale-os/kernel-client';
|
|
2
|
+
import type { SessionRequestOptions } from '@astrale-os/kernel-client/session';
|
|
3
|
+
import type { Value } from '@astrale-os/sdk/value';
|
|
8
4
|
import type { Action } from '../action.js';
|
|
9
|
-
export interface CallOptions {
|
|
10
|
-
|
|
11
|
-
timeout?: number;
|
|
12
|
-
/** Side-channel notified on rejection (the Action also records `.error`). */
|
|
13
|
-
onError?(error: unknown): void;
|
|
5
|
+
export interface CallOptions extends SessionRequestOptions {
|
|
6
|
+
readonly onError?: (error: unknown) => void;
|
|
14
7
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* that rejects if invoked. Params/result are typed from the FnMap entry.
|
|
19
|
-
*/
|
|
20
|
-
export declare function useCall<K extends CallFns<FnMap>>(method: K | null, opts?: CallOptions): Action<[FnMap[K]['params']], FnMap[K]['result']>;
|
|
8
|
+
export type CallResult = Value;
|
|
9
|
+
export declare function useCall(call: Call | null, options?: CallOptions): Action<[], CallResult>;
|
|
10
|
+
export declare function useCall<A extends unknown[]>(author: ((...args: A) => Call) | null, options?: CallOptions): Action<A, CallResult>;
|
|
21
11
|
//# sourceMappingURL=call.hook.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call.hook.d.ts","sourceRoot":"","sources":["../../../src/graph/call/call.hook.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"call.hook.d.ts","sourceRoot":"","sources":["../../../src/graph/call/call.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AAC9E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAK1C,MAAM,WAAW,WAAY,SAAQ,qBAAqB;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAA;AAG9B,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;AACzF,wBAAgB,OAAO,CAAC,CAAC,SAAS,OAAO,EAAE,EACzC,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,EACrC,OAAO,CAAC,EAAE,WAAW,GACpB,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA"}
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { useSessionKernel } from '../../auth/session-kernel.js';
|
|
2
2
|
import { useAction } from '../action.js';
|
|
3
|
-
|
|
4
|
-
* Unary domain-function dispatch as an {@link Action}. `method` is a typed FnMap
|
|
5
|
-
* `call` path or any string (the untyped floor); `null` yields an idle action
|
|
6
|
-
* that rejects if invoked. Params/result are typed from the FnMap entry.
|
|
7
|
-
*/
|
|
8
|
-
export function useCall(method, opts) {
|
|
3
|
+
export function useCall(author, options) {
|
|
9
4
|
const kernel = useSessionKernel();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
throw new Error('useCall: method is null (idle action invoked)');
|
|
5
|
+
return useAction(async (...args) => {
|
|
6
|
+
if (author === null)
|
|
7
|
+
throw new Error('useCall: idle action invoked');
|
|
8
|
+
const call = typeof author === 'function' ? author(...args) : author;
|
|
15
9
|
try {
|
|
16
|
-
return await kernel.call(
|
|
10
|
+
return await kernel.call(call, options);
|
|
17
11
|
}
|
|
18
12
|
catch (error) {
|
|
19
|
-
|
|
13
|
+
options?.onError?.(error);
|
|
20
14
|
throw error;
|
|
21
15
|
}
|
|
22
16
|
});
|