@astrale-os/shell-react 0.2.7 → 0.2.9
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 +6 -3
- package/dist/application/apps/app-host.d.ts.map +1 -1
- package/dist/application/apps/app-host.js +3 -2
- package/dist/application/apps/domains.hook.d.ts +7 -0
- package/dist/application/apps/domains.hook.d.ts.map +1 -0
- package/dist/application/apps/domains.hook.js +18 -0
- package/dist/application/index.d.ts +3 -1
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +3 -1
- package/dist/application/user/user.store.d.ts.map +1 -1
- package/dist/application/user/user.store.js +2 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/window/host.d.ts +4 -2
- package/dist/window/host.d.ts.map +1 -1
- package/dist/window/host.js +23 -3
- package/dist/window/index.d.ts +2 -2
- package/dist/window/index.d.ts.map +1 -1
- package/dist/window/lifecycle/mount.d.ts.map +1 -1
- package/dist/window/lifecycle/mount.js +32 -1
- package/dist/window/stage.d.ts.map +1 -1
- package/dist/window/stage.js +1 -0
- package/package.json +2 -2
- package/src/application/apps/app-host.tsx +8 -5
- package/src/application/apps/domains.hook.ts +37 -0
- package/src/application/index.ts +12 -2
- package/src/application/user/user.store.ts +2 -1
- package/src/index.ts +12 -1
- package/src/window/host.tsx +30 -5
- package/src/window/index.ts +2 -2
- package/src/window/lifecycle/mount.ts +31 -1
- package/src/window/stage.tsx +1 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { NodeRefInput } from '@astrale-os/kernel-client';
|
|
2
|
-
import type { ApplicationNode, AppSession, IntentRegistry
|
|
2
|
+
import type { ApplicationNode, AppSession, IntentRegistry } from '@astrale-os/shell';
|
|
3
3
|
import type { CSSProperties, ReactNode } from 'react';
|
|
4
|
-
import type { ViewHostHandle } from '../../window/host.js';
|
|
4
|
+
import type { SandboxPolicy, ViewHostHandle } from '../../window/host.js';
|
|
5
|
+
import type { ViewDescriptor } from '../../window/lifecycle/mount.js';
|
|
5
6
|
import type { WindowState } from '../../window/lifecycle/states.js';
|
|
6
7
|
/** The states `AppHost`'s fallback answers — the frame's, plus the two OS phases. */
|
|
7
8
|
export type AppHostFallbackState = WindowState | {
|
|
@@ -11,6 +12,8 @@ export type AppHostFallbackState = WindowState | {
|
|
|
11
12
|
};
|
|
12
13
|
export interface AppHostProps {
|
|
13
14
|
app: ApplicationNode | NodeRefInput;
|
|
15
|
+
/** Override the entry View while keeping the application's delegated session alive. */
|
|
16
|
+
view?: NodeRefInput | ViewDescriptor;
|
|
14
17
|
/**
|
|
15
18
|
* Default target node delivered to the app's view as `targetNodeId` (API §12.2).
|
|
16
19
|
* Container-anchored apps need one — the dock passes the current space. A deeper
|
|
@@ -21,7 +24,7 @@ export interface AppHostProps {
|
|
|
21
24
|
capabilities?: {
|
|
22
25
|
intents: readonly (keyof IntentRegistry)[];
|
|
23
26
|
};
|
|
24
|
-
sandbox?:
|
|
27
|
+
sandbox?: SandboxPolicy;
|
|
25
28
|
fallback?: (state: AppHostFallbackState) => ReactNode;
|
|
26
29
|
onSession?: (session: AppSession) => void;
|
|
27
30
|
className?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-host.d.ts","sourceRoot":"","sources":["../../../src/application/apps/app-host.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"app-host.d.ts","sourceRoot":"","sources":["../../../src/application/apps/app-host.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACpF,OAAO,KAAK,EAAE,aAAa,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAWnE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAMnE,qFAAqF;AACrF,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAC7B;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAA;AAEjC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,eAAe,GAAG,YAAY,CAAA;IACnC,uFAAuF;IACvF,IAAI,CAAC,EAAE,YAAY,GAAG,cAAc,CAAA;IACpC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,YAAY,CAAC,EAAE;QAAE,OAAO,EAAE,SAAS,CAAC,MAAM,cAAc,CAAC,EAAE,CAAA;KAAE,CAAA;IAC7D,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,SAAS,CAAA;IACrD,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAA;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB;AAED,eAAO,MAAM,OAAO,yGAqEnB,CAAA"}
|
|
@@ -53,7 +53,8 @@ export const AppHost = forwardRef(function AppHost(props, ref) {
|
|
|
53
53
|
return box(fallback?.({ phase: 'crashed', error }) ?? null);
|
|
54
54
|
if (session === null)
|
|
55
55
|
return box(fallback?.({ phase: 'opening' }) ?? null);
|
|
56
|
-
|
|
56
|
+
const view = props.view ?? session.view;
|
|
57
|
+
if (view === null)
|
|
57
58
|
return box(fallback?.({ phase: 'no-view' }) ?? null);
|
|
58
|
-
return (_jsx(ViewHost, { ref: ref, view:
|
|
59
|
+
return (_jsx(ViewHost, { ref: ref, view: view, node: props.node, credential: session.credential, capabilities: props.capabilities ?? { intents: [] }, sandbox: props.sandbox, fallback: fallback ? (s) => fallback(s) : undefined, className: className, style: style }));
|
|
59
60
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DomainSearchResult } from '@astrale-os/shell';
|
|
2
|
+
import type { ReadState } from '../../graph/memory/read/envelope.js';
|
|
3
|
+
export interface DomainsResult extends ReadState {
|
|
4
|
+
readonly domains: readonly DomainSearchResult[];
|
|
5
|
+
}
|
|
6
|
+
export declare function useDomains(): DomainsResult;
|
|
7
|
+
//# sourceMappingURL=domains.hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domains.hook.d.ts","sourceRoot":"","sources":["../../../src/application/apps/domains.hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAI3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AAQpE,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAChD;AAED,wBAAgB,UAAU,IAAI,aAAa,CAoB1C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { useAsyncResource } from '../../graph/async.js';
|
|
3
|
+
import { useShell } from '../../session/shell.hook.js';
|
|
4
|
+
import { isOsPlaneAvailable } from '../user/user.store.js';
|
|
5
|
+
const NO_DOMAINS = [];
|
|
6
|
+
export function useDomains() {
|
|
7
|
+
const shell = useShell();
|
|
8
|
+
const available = isOsPlaneAvailable(shell);
|
|
9
|
+
const result = useAsyncResource(available ? () => shell.apps.searchDomains() : null, NO_DOMAINS, [shell, available]);
|
|
10
|
+
return useMemo(() => ({
|
|
11
|
+
domains: result.data,
|
|
12
|
+
pending: result.pending,
|
|
13
|
+
error: result.error,
|
|
14
|
+
live: false,
|
|
15
|
+
seq: 0,
|
|
16
|
+
refetch: result.refetch,
|
|
17
|
+
}), [result]);
|
|
18
|
+
}
|
|
@@ -7,6 +7,8 @@ export { useSpace } from './spaces/space.hook.js';
|
|
|
7
7
|
export type { SpaceResult } from './spaces/space.hook.js';
|
|
8
8
|
export { useApps } from './apps/apps.hook.js';
|
|
9
9
|
export type { AppsResult } from './apps/apps.hook.js';
|
|
10
|
+
export { useDomains } from './apps/domains.hook.js';
|
|
11
|
+
export type { DomainsResult } from './apps/domains.hook.js';
|
|
10
12
|
export { useOpenApp } from './apps/open-app.hook.js';
|
|
11
13
|
export { AppHost } from './apps/app-host.js';
|
|
12
14
|
export type { AppHostFallbackState, AppHostProps } from './apps/app-host.js';
|
|
@@ -14,5 +16,5 @@ export { AppLogo } from './apps/app-logo.js';
|
|
|
14
16
|
export type { AppLogoProps } from './apps/app-logo.js';
|
|
15
17
|
export { useRoles } from './roles.hook.js';
|
|
16
18
|
export type { RolesResult } from './roles.hook.js';
|
|
17
|
-
export type { ApplicationNode, AppSession, RoleNode, SpaceNode, UserNode } from '@astrale-os/shell';
|
|
19
|
+
export type { ApplicationNode, AppSession, DomainSearchResult, RoleNode, SpaceNode, UserNode, } from '@astrale-os/shell';
|
|
18
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAChE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD,YAAY,EACV,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,MAAM,mBAAmB,CAAA"}
|
|
@@ -1,11 +1,13 @@
|
|
|
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, useRoles, useOpenApp,
|
|
3
|
+
// useCurrentSpace, useSpace, useApps, useDomains, useRoles, useOpenApp,
|
|
4
|
+
// AppHost, AppLogo.
|
|
4
5
|
export { useUser } from './user/user.hook.js';
|
|
5
6
|
export { useSpaces } from './spaces/spaces.hook.js';
|
|
6
7
|
export { useCurrentSpace } from './spaces/current-space.hook.js';
|
|
7
8
|
export { useSpace } from './spaces/space.hook.js';
|
|
8
9
|
export { useApps } from './apps/apps.hook.js';
|
|
10
|
+
export { useDomains } from './apps/domains.hook.js';
|
|
9
11
|
export { useOpenApp } from './apps/open-app.hook.js';
|
|
10
12
|
export { AppHost } from './apps/app-host.js';
|
|
11
13
|
export { AppLogo } from './apps/app-logo.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.store.d.ts","sourceRoot":"","sources":["../../../src/application/user/user.store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,MAAM,SAAS,GACjB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAC7C;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE;AACxC,qFAAqF;GACnF;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAE7C,eAAO,MAAM,SAAS,2BAAkC,CAAA;AAKxD,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAExD;
|
|
1
|
+
{"version":3,"file":"user.store.d.ts","sourceRoot":"","sources":["../../../src/application/user/user.store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,MAAM,SAAS,GACjB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAC7C;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE;AACxC,qFAAqF;GACnF;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAE7C,eAAO,MAAM,SAAS,2BAAkC,CAAA;AAKxD,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAExD;AAeD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB3D;AAED,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAoBhD"}
|
|
@@ -7,7 +7,8 @@ export function isOsPlaneAvailable(shell) {
|
|
|
7
7
|
}
|
|
8
8
|
function osPlaneError(cause) {
|
|
9
9
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
10
|
-
return new Error(`The OS plane is unavailable (useUser/useSpaces/useApps):
|
|
10
|
+
return new Error(`The OS plane is unavailable (useUser/useSpaces/useApps/useDomains): ` +
|
|
11
|
+
`shell.user.me() could not resolve ` +
|
|
11
12
|
`— the workspace/shell domain may not be installed for this identity. (${detail})`);
|
|
12
13
|
}
|
|
13
14
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -25,12 +25,12 @@ export type { LinkProps, MissingPolicy, NavAdapter, NavLocation, NavScopeHandle,
|
|
|
25
25
|
export { SelectionScope, useSelection } from './selection/index.js';
|
|
26
26
|
export type { Selection, SelectionScopeProps } from './selection/index.js';
|
|
27
27
|
export { useCloseGuard, useTargetNode, useViewsFor, useWindow, useWindowList, useWindows, ViewHost, ViewStage, } from './window/index.js';
|
|
28
|
-
export type { CloseGuard, CloseVerdict, ViewDescriptor, ViewHostProps, ViewSource, ViewHostHandle, ViewsForResult, WindowListEntry, WindowState, WindowView, } from './window/index.js';
|
|
28
|
+
export type { CloseGuard, CloseVerdict, ResolvedSource, SandboxPolicy, ViewDescriptor, ViewHostProps, ViewSource, ViewHostHandle, ViewsForResult, WindowListEntry, WindowState, WindowView, } from './window/index.js';
|
|
29
29
|
export { useEmitIntent, useIntent, useSendIntent } from './intents/index.js';
|
|
30
30
|
export type { EmitIntent, IntentCtx, IntentPayload, IntentReply, SendIntent, } from './intents/index.js';
|
|
31
|
-
export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useSpace, useSpaces, useUser, } from './application/index.js';
|
|
32
|
-
export type { AppHostFallbackState, AppHostProps, AppLogoProps, AppsResult, CurrentSpaceResult, RolesResult, SpaceResult, SpacesResult, } from './application/index.js';
|
|
33
|
-
export type { ApplicationNode, AppSession, RoleNode, SpaceNode, UserNode } from '@astrale-os/shell';
|
|
31
|
+
export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useDomains, useSpace, useSpaces, useUser, } from './application/index.js';
|
|
32
|
+
export type { AppHostFallbackState, AppHostProps, AppLogoProps, AppsResult, CurrentSpaceResult, RolesResult, DomainsResult, SpaceResult, SpacesResult, } from './application/index.js';
|
|
33
|
+
export type { ApplicationNode, AppSession, DomainSearchResult, RoleNode, SpaceNode, UserNode, } from '@astrale-os/shell';
|
|
34
34
|
export type { Action, ReadState, ReadOptions, Windowed } from './graph/index.js';
|
|
35
35
|
export * from './graph/guards.error.js';
|
|
36
36
|
export { DESCRIPTION_KEY, NAME_KEY, STATUS_KEY, descriptionOf, nameOf, normalizeRef, statusOf, } from '@astrale-os/kernel-client';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export { useCloseGuard, useTargetNode, useViewsFor, useWindow, useWindowList, us
|
|
|
27
27
|
// ─── intents (§11) ───────────────────────────────────────────────────────────
|
|
28
28
|
export { useEmitIntent, useIntent, useSendIntent } from './intents/index.js';
|
|
29
29
|
// ─── application — the OS plane (§12) ────────────────────────────────────────
|
|
30
|
-
export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useSpace, useSpaces, useUser, } from './application/index.js';
|
|
30
|
+
export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useDomains, useSpace, useSpaces, useUser, } from './application/index.js';
|
|
31
31
|
// ─── error taxonomy (§1.4) — guards + classes, re-exported from kernel-client ─
|
|
32
32
|
export * from './graph/guards.error.js';
|
|
33
33
|
// ─── re-exported kernel-client types (one import surface, §0 preamble) ───────
|
package/dist/window/host.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NodeRefInput } from '@astrale-os/kernel-client';
|
|
2
2
|
import type { CloseResult, IntentRegistry, MountCredential, SandboxProfile } from '@astrale-os/shell';
|
|
3
3
|
import type { CSSProperties, ReactNode } from 'react';
|
|
4
|
-
import type { ViewSource } from './lifecycle/mount.js';
|
|
4
|
+
import type { ResolvedSource, ViewSource } from './lifecycle/mount.js';
|
|
5
5
|
import type { WindowState } from './lifecycle/states.js';
|
|
6
6
|
/** Imperative handle on a mounted `ViewHost` (API §10). */
|
|
7
7
|
export interface ViewHostHandle {
|
|
@@ -13,13 +13,15 @@ export interface ViewHostHandle {
|
|
|
13
13
|
/** The one explicit remount. */
|
|
14
14
|
refresh(): void;
|
|
15
15
|
}
|
|
16
|
+
/** Static iframe sandbox flags, an explicit opt-out, or a policy over the resolved mount. */
|
|
17
|
+
export type SandboxPolicy = SandboxProfile | null | ((source: ResolvedSource) => SandboxProfile | null);
|
|
16
18
|
export type ViewHostProps = ViewSource & {
|
|
17
19
|
/** Node this view opens on — delivered as `targetNodeId`; a change retargets. */
|
|
18
20
|
node?: NodeRefInput;
|
|
19
21
|
capabilities?: {
|
|
20
22
|
intents: readonly (keyof IntentRegistry)[];
|
|
21
23
|
};
|
|
22
|
-
sandbox?:
|
|
24
|
+
sandbox?: SandboxPolicy;
|
|
23
25
|
credential?: MountCredential;
|
|
24
26
|
/** Rendered inside the anchor while the frame is not `ready`. */
|
|
25
27
|
fallback?: (state: WindowState) => ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/window/host.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,eAAe,EAEf,cAAc,EAEf,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,aAAa,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAqBnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/window/host.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,eAAe,EAEf,cAAc,EAEf,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,aAAa,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAqBnE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAcxD,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAC3E,gCAAgC;IAChC,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,6FAA6F;AAC7F,MAAM,MAAM,aAAa,GACrB,cAAc,GACd,IAAI,GACJ,CAAC,CAAC,MAAM,EAAE,cAAc,KAAK,cAAc,GAAG,IAAI,CAAC,CAAA;AAEvD,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG;IACvC,iFAAiF;IACjF,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,YAAY,CAAC,EAAE;QAAE,OAAO,EAAE,SAAS,CAAC,MAAM,cAAc,CAAC,EAAE,CAAA;KAAE,CAAA;IAC7D,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,SAAS,CAAA;IAC5C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB,CAAA;AAYD,eAAO,MAAM,QAAQ,0GA4RpB,CAAA"}
|
package/dist/window/host.js
CHANGED
|
@@ -131,6 +131,14 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
|
|
|
131
131
|
else
|
|
132
132
|
hub.stashForAdopt(mountKey, record);
|
|
133
133
|
}
|
|
134
|
+
/** A pre-ready failure must not leave an empty stage slot over the fallback UI. */
|
|
135
|
+
function crashAndRelease(error) {
|
|
136
|
+
const slot = slotRef.current;
|
|
137
|
+
slotRef.current = null;
|
|
138
|
+
lastRectRef.current = null;
|
|
139
|
+
slot?.release();
|
|
140
|
+
setStateSafe({ phase: 'crashed', windowId: windowIdRef.current ?? undefined, error });
|
|
141
|
+
}
|
|
134
142
|
// Adopt a live window a just-unmounted same-source host left behind.
|
|
135
143
|
if (!wasRefresh) {
|
|
136
144
|
const adopted = hub.takeAdopt(mountKey);
|
|
@@ -160,20 +168,32 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
|
|
|
160
168
|
catch (err) {
|
|
161
169
|
// No window yet (source resolution failed) — windowId honestly absent.
|
|
162
170
|
if (!cancelled)
|
|
163
|
-
|
|
171
|
+
crashAndRelease(err);
|
|
164
172
|
return;
|
|
165
173
|
}
|
|
166
174
|
if (cancelled)
|
|
167
175
|
return;
|
|
168
176
|
const usedHandshake = handshake === 'none' ? 'none' : resolved.handshake;
|
|
169
177
|
const deliveredTarget = refToId(p.node);
|
|
178
|
+
let sandbox;
|
|
179
|
+
try {
|
|
180
|
+
sandbox =
|
|
181
|
+
typeof p.sandbox === 'function'
|
|
182
|
+
? p.sandbox({ ...resolved, handshake: usedHandshake })
|
|
183
|
+
: p.sandbox;
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
if (!cancelled)
|
|
187
|
+
crashAndRelease(err);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
170
190
|
const params = {
|
|
171
191
|
host: slotRef.current.element,
|
|
172
192
|
url: resolved.url,
|
|
173
193
|
functionId: resolved.functionId,
|
|
174
194
|
capabilities: { intents: p.capabilities?.intents ?? [] },
|
|
175
195
|
targetNodeId: deliveredTarget,
|
|
176
|
-
sandbox
|
|
196
|
+
sandbox,
|
|
177
197
|
handshake: usedHandshake,
|
|
178
198
|
credential: p.credential,
|
|
179
199
|
};
|
|
@@ -206,7 +226,7 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
|
|
|
206
226
|
await mountWith('none', true);
|
|
207
227
|
return;
|
|
208
228
|
}
|
|
209
|
-
|
|
229
|
+
crashAndRelease(err);
|
|
210
230
|
}
|
|
211
231
|
}
|
|
212
232
|
function begin(controller) {
|
package/dist/window/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ViewStage } from './stage.js';
|
|
2
2
|
export { ViewHost } from './host.js';
|
|
3
|
-
export type { ViewHostProps, ViewHostHandle } from './host.js';
|
|
3
|
+
export type { SandboxPolicy, ViewHostProps, ViewHostHandle } from './host.js';
|
|
4
4
|
export { useWindows, useWindowList } from './hooks/windows.hook.js';
|
|
5
5
|
export type { WindowListEntry } from './hooks/windows.hook.js';
|
|
6
6
|
export { useWindow } from './hooks/window.hook.js';
|
|
@@ -10,6 +10,6 @@ export type { ViewsForResult } from './hooks/views-for.hook.js';
|
|
|
10
10
|
export { useTargetNode } from './hooks/target-node.hook.js';
|
|
11
11
|
export { useCloseGuard } from './hooks/close-guard.hook.js';
|
|
12
12
|
export type { CloseGuard, CloseVerdict } from './hooks/close-guard.hook.js';
|
|
13
|
-
export type { ViewDescriptor, ViewSource, Node } from './lifecycle/mount.js';
|
|
13
|
+
export type { ResolvedSource, ViewDescriptor, ViewSource, Node } from './lifecycle/mount.js';
|
|
14
14
|
export type { WindowState } from './lifecycle/states.js';
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/window/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/window/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACnE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC3E,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC5F,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/window/lifecycle/mount.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE5D,+EAA+E;AAC/E,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAExE,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpG,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAA;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/window/lifecycle/mount.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE5D,+EAA+E;AAC/E,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAExE,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpG,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAA;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AA2ED,4EAA4E;AAC5E,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,cAAc,CAAC,CAgBzB;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAOpD;AAED,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKzE;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGlE;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAMlF"}
|
|
@@ -24,7 +24,7 @@ async function resolveViewRef(kernel, ref, handshakeHint) {
|
|
|
24
24
|
if (node === null)
|
|
25
25
|
throw new Error(`ViewHost: view not found (${toPath(ref)})`);
|
|
26
26
|
const props = node.props ?? {};
|
|
27
|
-
const url = props
|
|
27
|
+
const url = viewUrl(props);
|
|
28
28
|
if (typeof url !== 'string' || url.length === 0) {
|
|
29
29
|
throw new Error('ViewHost: resolved view has no url');
|
|
30
30
|
}
|
|
@@ -32,6 +32,37 @@ async function resolveViewRef(kernel, ref, handshakeHint) {
|
|
|
32
32
|
const id = node.id ?? slugOfUrl(url);
|
|
33
33
|
return { url, handshake, functionId: id };
|
|
34
34
|
}
|
|
35
|
+
/** Resolve both the legacy flat url and the canonical Function binding. */
|
|
36
|
+
function viewUrl(props) {
|
|
37
|
+
if (typeof props.url === 'string' && props.url.length > 0)
|
|
38
|
+
return props.url;
|
|
39
|
+
const direct = remoteUrlOf(props.binding);
|
|
40
|
+
if (direct !== undefined)
|
|
41
|
+
return direct;
|
|
42
|
+
// Raw graph props can be keyed by the property's canonical graph key rather
|
|
43
|
+
// than its local slug. The binding value remains self-describing.
|
|
44
|
+
for (const value of Object.values(props)) {
|
|
45
|
+
const remoteUrl = remoteUrlOf(value);
|
|
46
|
+
if (remoteUrl !== undefined)
|
|
47
|
+
return remoteUrl;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
function remoteUrlOf(value) {
|
|
52
|
+
let binding = value;
|
|
53
|
+
if (typeof binding === 'string') {
|
|
54
|
+
try {
|
|
55
|
+
binding = JSON.parse(binding);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (binding === null || typeof binding !== 'object')
|
|
62
|
+
return undefined;
|
|
63
|
+
const remoteUrl = binding.remoteUrl;
|
|
64
|
+
return typeof remoteUrl === 'string' && remoteUrl.length > 0 ? remoteUrl : undefined;
|
|
65
|
+
}
|
|
35
66
|
function normalizeHandshake(value) {
|
|
36
67
|
return value === 'none' ? 'none' : 'shell';
|
|
37
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/window/stage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/window/stage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAA;AA6BxD,wBAAgB,SAAS,IAAI,YAAY,CAiBxC"}
|
package/dist/window/stage.js
CHANGED
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.9",
|
|
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": {
|
|
@@ -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.7"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@astrale-os/shell": ">=0.2.0 <1.0.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { NodeRefInput } from '@astrale-os/kernel-client'
|
|
2
|
-
import type { ApplicationNode, AppSession, IntentRegistry
|
|
2
|
+
import type { ApplicationNode, AppSession, IntentRegistry } from '@astrale-os/shell'
|
|
3
3
|
import type { CSSProperties, ReactElement, ReactNode } from 'react'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -11,7 +11,7 @@ import type { CSSProperties, ReactElement, ReactNode } from 'react'
|
|
|
11
11
|
*/
|
|
12
12
|
import { forwardRef, useEffect, useRef, useState } from 'react'
|
|
13
13
|
|
|
14
|
-
import type { ViewHostHandle } from '../../window/host.js'
|
|
14
|
+
import type { SandboxPolicy, ViewHostHandle } from '../../window/host.js'
|
|
15
15
|
import type { ViewDescriptor } from '../../window/lifecycle/mount.js'
|
|
16
16
|
import type { WindowState } from '../../window/lifecycle/states.js'
|
|
17
17
|
|
|
@@ -27,6 +27,8 @@ export type AppHostFallbackState =
|
|
|
27
27
|
|
|
28
28
|
export interface AppHostProps {
|
|
29
29
|
app: ApplicationNode | NodeRefInput
|
|
30
|
+
/** Override the entry View while keeping the application's delegated session alive. */
|
|
31
|
+
view?: NodeRefInput | ViewDescriptor
|
|
30
32
|
/**
|
|
31
33
|
* Default target node delivered to the app's view as `targetNodeId` (API §12.2).
|
|
32
34
|
* Container-anchored apps need one — the dock passes the current space. A deeper
|
|
@@ -35,7 +37,7 @@ export interface AppHostProps {
|
|
|
35
37
|
*/
|
|
36
38
|
node?: NodeRefInput
|
|
37
39
|
capabilities?: { intents: readonly (keyof IntentRegistry)[] }
|
|
38
|
-
sandbox?:
|
|
40
|
+
sandbox?: SandboxPolicy
|
|
39
41
|
fallback?: (state: AppHostFallbackState) => ReactNode
|
|
40
42
|
onSession?: (session: AppSession) => void
|
|
41
43
|
className?: string
|
|
@@ -94,12 +96,13 @@ export const AppHost = forwardRef<ViewHostHandle, AppHostProps>(
|
|
|
94
96
|
// A session-open failure has no window yet — `windowId` is honestly absent (§10).
|
|
95
97
|
if (error !== undefined) return box(fallback?.({ phase: 'crashed', error }) ?? null)
|
|
96
98
|
if (session === null) return box(fallback?.({ phase: 'opening' }) ?? null)
|
|
97
|
-
|
|
99
|
+
const view = props.view ?? session.view
|
|
100
|
+
if (view === null) return box(fallback?.({ phase: 'no-view' }) ?? null)
|
|
98
101
|
|
|
99
102
|
return (
|
|
100
103
|
<ViewHost
|
|
101
104
|
ref={ref}
|
|
102
|
-
view={
|
|
105
|
+
view={view}
|
|
103
106
|
node={props.node}
|
|
104
107
|
credential={session.credential}
|
|
105
108
|
capabilities={props.capabilities ?? { intents: [] }}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DomainSearchResult } from '@astrale-os/shell'
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
|
|
5
|
+
import type { ReadState } from '../../graph/memory/read/envelope.js'
|
|
6
|
+
|
|
7
|
+
import { useAsyncResource } from '../../graph/async.js'
|
|
8
|
+
import { useShell } from '../../session/shell.hook.js'
|
|
9
|
+
import { isOsPlaneAvailable } from '../user/user.store.js'
|
|
10
|
+
|
|
11
|
+
const NO_DOMAINS: readonly DomainSearchResult[] = []
|
|
12
|
+
|
|
13
|
+
export interface DomainsResult extends ReadState {
|
|
14
|
+
readonly domains: readonly DomainSearchResult[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function useDomains(): DomainsResult {
|
|
18
|
+
const shell = useShell()
|
|
19
|
+
const available = isOsPlaneAvailable(shell)
|
|
20
|
+
const result = useAsyncResource<readonly DomainSearchResult[]>(
|
|
21
|
+
available ? () => shell.apps.searchDomains() : null,
|
|
22
|
+
NO_DOMAINS,
|
|
23
|
+
[shell, available],
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return useMemo(
|
|
27
|
+
() => ({
|
|
28
|
+
domains: result.data,
|
|
29
|
+
pending: result.pending,
|
|
30
|
+
error: result.error,
|
|
31
|
+
live: false,
|
|
32
|
+
seq: 0,
|
|
33
|
+
refetch: result.refetch,
|
|
34
|
+
}),
|
|
35
|
+
[result],
|
|
36
|
+
)
|
|
37
|
+
}
|
package/src/application/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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, useRoles, useOpenApp,
|
|
3
|
+
// useCurrentSpace, useSpace, useApps, useDomains, useRoles, useOpenApp,
|
|
4
|
+
// AppHost, AppLogo.
|
|
4
5
|
export { useUser } from './user/user.hook.js'
|
|
5
6
|
export { useSpaces } from './spaces/spaces.hook.js'
|
|
6
7
|
export type { SpacesResult } from './spaces/spaces.hook.js'
|
|
@@ -10,6 +11,8 @@ export { useSpace } from './spaces/space.hook.js'
|
|
|
10
11
|
export type { SpaceResult } from './spaces/space.hook.js'
|
|
11
12
|
export { useApps } from './apps/apps.hook.js'
|
|
12
13
|
export type { AppsResult } from './apps/apps.hook.js'
|
|
14
|
+
export { useDomains } from './apps/domains.hook.js'
|
|
15
|
+
export type { DomainsResult } from './apps/domains.hook.js'
|
|
13
16
|
export { useOpenApp } from './apps/open-app.hook.js'
|
|
14
17
|
export { AppHost } from './apps/app-host.js'
|
|
15
18
|
export type { AppHostFallbackState, AppHostProps } from './apps/app-host.js'
|
|
@@ -19,4 +22,11 @@ export { useRoles } from './roles.hook.js'
|
|
|
19
22
|
export type { RolesResult } from './roles.hook.js'
|
|
20
23
|
|
|
21
24
|
// The OS node/session types (from the shell package, single import surface).
|
|
22
|
-
export type {
|
|
25
|
+
export type {
|
|
26
|
+
ApplicationNode,
|
|
27
|
+
AppSession,
|
|
28
|
+
DomainSearchResult,
|
|
29
|
+
RoleNode,
|
|
30
|
+
SpaceNode,
|
|
31
|
+
UserNode,
|
|
32
|
+
} from '@astrale-os/shell'
|
|
@@ -31,7 +31,8 @@ interface UserSurface {
|
|
|
31
31
|
function osPlaneError(cause: unknown): Error {
|
|
32
32
|
const detail = cause instanceof Error ? cause.message : String(cause)
|
|
33
33
|
return new Error(
|
|
34
|
-
`The OS plane is unavailable (useUser/useSpaces/useApps):
|
|
34
|
+
`The OS plane is unavailable (useUser/useSpaces/useApps/useDomains): ` +
|
|
35
|
+
`shell.user.me() could not resolve ` +
|
|
35
36
|
`— the workspace/shell domain may not be installed for this identity. (${detail})`,
|
|
36
37
|
)
|
|
37
38
|
}
|
package/src/index.ts
CHANGED
|
@@ -106,6 +106,8 @@ export {
|
|
|
106
106
|
export type {
|
|
107
107
|
CloseGuard,
|
|
108
108
|
CloseVerdict,
|
|
109
|
+
ResolvedSource,
|
|
110
|
+
SandboxPolicy,
|
|
109
111
|
ViewDescriptor,
|
|
110
112
|
ViewHostProps,
|
|
111
113
|
ViewSource,
|
|
@@ -134,6 +136,7 @@ export {
|
|
|
134
136
|
useCurrentSpace,
|
|
135
137
|
useOpenApp,
|
|
136
138
|
useRoles,
|
|
139
|
+
useDomains,
|
|
137
140
|
useSpace,
|
|
138
141
|
useSpaces,
|
|
139
142
|
useUser,
|
|
@@ -145,11 +148,19 @@ export type {
|
|
|
145
148
|
AppsResult,
|
|
146
149
|
CurrentSpaceResult,
|
|
147
150
|
RolesResult,
|
|
151
|
+
DomainsResult,
|
|
148
152
|
SpaceResult,
|
|
149
153
|
SpacesResult,
|
|
150
154
|
} from './application/index.js'
|
|
151
155
|
// OS node/session types (from the shell package, single import surface).
|
|
152
|
-
export type {
|
|
156
|
+
export type {
|
|
157
|
+
ApplicationNode,
|
|
158
|
+
AppSession,
|
|
159
|
+
DomainSearchResult,
|
|
160
|
+
RoleNode,
|
|
161
|
+
SpaceNode,
|
|
162
|
+
UserNode,
|
|
163
|
+
} from '@astrale-os/shell'
|
|
153
164
|
|
|
154
165
|
// ─── shared envelopes (§1) ───────────────────────────────────────────────────
|
|
155
166
|
export type { Action, ReadState, ReadOptions, Windowed } from './graph/index.js'
|
package/src/window/host.tsx
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from 'react'
|
|
29
29
|
|
|
30
30
|
import type { AdoptRecord } from './adopt.js'
|
|
31
|
-
import type { ViewSource } from './lifecycle/mount.js'
|
|
31
|
+
import type { ResolvedSource, ViewSource } from './lifecycle/mount.js'
|
|
32
32
|
import type { WindowState } from './lifecycle/states.js'
|
|
33
33
|
import type { SlotRect, StageController, StageSlot } from './placement.js'
|
|
34
34
|
|
|
@@ -51,11 +51,17 @@ export interface ViewHostHandle {
|
|
|
51
51
|
refresh(): void
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/** Static iframe sandbox flags, an explicit opt-out, or a policy over the resolved mount. */
|
|
55
|
+
export type SandboxPolicy =
|
|
56
|
+
| SandboxProfile
|
|
57
|
+
| null
|
|
58
|
+
| ((source: ResolvedSource) => SandboxProfile | null)
|
|
59
|
+
|
|
54
60
|
export type ViewHostProps = ViewSource & {
|
|
55
61
|
/** Node this view opens on — delivered as `targetNodeId`; a change retargets. */
|
|
56
62
|
node?: NodeRefInput
|
|
57
63
|
capabilities?: { intents: readonly (keyof IntentRegistry)[] }
|
|
58
|
-
sandbox?:
|
|
64
|
+
sandbox?: SandboxPolicy
|
|
59
65
|
credential?: MountCredential
|
|
60
66
|
/** Rendered inside the anchor while the frame is not `ready`. */
|
|
61
67
|
fallback?: (state: WindowState) => ReactNode
|
|
@@ -204,6 +210,15 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
|
|
|
204
210
|
else hub.stashForAdopt(mountKey, record)
|
|
205
211
|
}
|
|
206
212
|
|
|
213
|
+
/** A pre-ready failure must not leave an empty stage slot over the fallback UI. */
|
|
214
|
+
function crashAndRelease(error: unknown): void {
|
|
215
|
+
const slot = slotRef.current
|
|
216
|
+
slotRef.current = null
|
|
217
|
+
lastRectRef.current = null
|
|
218
|
+
slot?.release()
|
|
219
|
+
setStateSafe({ phase: 'crashed', windowId: windowIdRef.current ?? undefined, error })
|
|
220
|
+
}
|
|
221
|
+
|
|
207
222
|
// Adopt a live window a just-unmounted same-source host left behind.
|
|
208
223
|
if (!wasRefresh) {
|
|
209
224
|
const adopted = hub.takeAdopt(mountKey)
|
|
@@ -232,20 +247,30 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
|
|
|
232
247
|
resolved = await resolveSource(shell.kernel, sourceOf(p))
|
|
233
248
|
} catch (err) {
|
|
234
249
|
// No window yet (source resolution failed) — windowId honestly absent.
|
|
235
|
-
if (!cancelled)
|
|
250
|
+
if (!cancelled) crashAndRelease(err)
|
|
236
251
|
return
|
|
237
252
|
}
|
|
238
253
|
if (cancelled) return
|
|
239
254
|
|
|
240
255
|
const usedHandshake = handshake === 'none' ? 'none' : resolved.handshake
|
|
241
256
|
const deliveredTarget = refToId(p.node)
|
|
257
|
+
let sandbox: SandboxProfile | null | undefined
|
|
258
|
+
try {
|
|
259
|
+
sandbox =
|
|
260
|
+
typeof p.sandbox === 'function'
|
|
261
|
+
? p.sandbox({ ...resolved, handshake: usedHandshake })
|
|
262
|
+
: p.sandbox
|
|
263
|
+
} catch (err) {
|
|
264
|
+
if (!cancelled) crashAndRelease(err)
|
|
265
|
+
return
|
|
266
|
+
}
|
|
242
267
|
const params: MountParams = {
|
|
243
268
|
host: slotRef.current!.element,
|
|
244
269
|
url: resolved.url,
|
|
245
270
|
functionId: resolved.functionId,
|
|
246
271
|
capabilities: { intents: p.capabilities?.intents ?? [] },
|
|
247
272
|
targetNodeId: deliveredTarget,
|
|
248
|
-
sandbox
|
|
273
|
+
sandbox,
|
|
249
274
|
handshake: usedHandshake,
|
|
250
275
|
credential: p.credential,
|
|
251
276
|
}
|
|
@@ -277,7 +302,7 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
|
|
|
277
302
|
await mountWith('none', true)
|
|
278
303
|
return
|
|
279
304
|
}
|
|
280
|
-
|
|
305
|
+
crashAndRelease(err)
|
|
281
306
|
}
|
|
282
307
|
}
|
|
283
308
|
|
package/src/window/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// target-node + close-guard, and the (G5) view-resolution hook.
|
|
4
4
|
export { ViewStage } from './stage.js'
|
|
5
5
|
export { ViewHost } from './host.js'
|
|
6
|
-
export type { ViewHostProps, ViewHostHandle } from './host.js'
|
|
6
|
+
export type { SandboxPolicy, ViewHostProps, ViewHostHandle } from './host.js'
|
|
7
7
|
export { useWindows, useWindowList } from './hooks/windows.hook.js'
|
|
8
8
|
export type { WindowListEntry } from './hooks/windows.hook.js'
|
|
9
9
|
export { useWindow } from './hooks/window.hook.js'
|
|
@@ -13,5 +13,5 @@ export type { ViewsForResult } from './hooks/views-for.hook.js'
|
|
|
13
13
|
export { useTargetNode } from './hooks/target-node.hook.js'
|
|
14
14
|
export { useCloseGuard } from './hooks/close-guard.hook.js'
|
|
15
15
|
export type { CloseGuard, CloseVerdict } from './hooks/close-guard.hook.js'
|
|
16
|
-
export type { ViewDescriptor, ViewSource, Node } from './lifecycle/mount.js'
|
|
16
|
+
export type { ResolvedSource, ViewDescriptor, ViewSource, Node } from './lifecycle/mount.js'
|
|
17
17
|
export type { WindowState } from './lifecycle/states.js'
|
|
@@ -62,7 +62,7 @@ async function resolveViewRef(
|
|
|
62
62
|
const node = await kernel.get(toPath(ref))
|
|
63
63
|
if (node === null) throw new Error(`ViewHost: view not found (${toPath(ref)})`)
|
|
64
64
|
const props = (node as { id?: string; props?: Record<string, unknown> }).props ?? {}
|
|
65
|
-
const url = props
|
|
65
|
+
const url = viewUrl(props)
|
|
66
66
|
if (typeof url !== 'string' || url.length === 0) {
|
|
67
67
|
throw new Error('ViewHost: resolved view has no url')
|
|
68
68
|
}
|
|
@@ -71,6 +71,36 @@ async function resolveViewRef(
|
|
|
71
71
|
return { url, handshake, functionId: id }
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/** Resolve both the legacy flat url and the canonical Function binding. */
|
|
75
|
+
function viewUrl(props: Record<string, unknown>): string | undefined {
|
|
76
|
+
if (typeof props.url === 'string' && props.url.length > 0) return props.url
|
|
77
|
+
|
|
78
|
+
const direct = remoteUrlOf(props.binding)
|
|
79
|
+
if (direct !== undefined) return direct
|
|
80
|
+
|
|
81
|
+
// Raw graph props can be keyed by the property's canonical graph key rather
|
|
82
|
+
// than its local slug. The binding value remains self-describing.
|
|
83
|
+
for (const value of Object.values(props)) {
|
|
84
|
+
const remoteUrl = remoteUrlOf(value)
|
|
85
|
+
if (remoteUrl !== undefined) return remoteUrl
|
|
86
|
+
}
|
|
87
|
+
return undefined
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function remoteUrlOf(value: unknown): string | undefined {
|
|
91
|
+
let binding = value
|
|
92
|
+
if (typeof binding === 'string') {
|
|
93
|
+
try {
|
|
94
|
+
binding = JSON.parse(binding)
|
|
95
|
+
} catch {
|
|
96
|
+
return undefined
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (binding === null || typeof binding !== 'object') return undefined
|
|
100
|
+
const remoteUrl = (binding as { remoteUrl?: unknown }).remoteUrl
|
|
101
|
+
return typeof remoteUrl === 'string' && remoteUrl.length > 0 ? remoteUrl : undefined
|
|
102
|
+
}
|
|
103
|
+
|
|
74
104
|
function normalizeHandshake(value: unknown): 'shell' | 'none' {
|
|
75
105
|
return value === 'none' ? 'none' : 'shell'
|
|
76
106
|
}
|