@astrale-os/shell-react 0.2.8 → 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.
@@ -1,7 +1,8 @@
1
1
  import type { NodeRefInput } from '@astrale-os/kernel-client';
2
- import type { ApplicationNode, AppSession, IntentRegistry, SandboxProfile } from '@astrale-os/shell';
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?: SandboxProfile | null;
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,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACpG,OAAO,KAAK,EAAE,aAAa,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAA;AAWnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,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;;;;;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,cAAc,GAAG,IAAI,CAAA;IAC/B,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,yGAoEnB,CAAA"}
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
- if (session.view === null)
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: session.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
+ 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
  });
package/dist/index.d.ts CHANGED
@@ -25,7 +25,7 @@ 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
31
  export { AppHost, AppLogo, useApps, useCurrentSpace, useOpenApp, useRoles, useDomains, useSpace, useSpaces, useUser, } from './application/index.js';
@@ -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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"}
@@ -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?: SandboxProfile | null;
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;AACtD,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,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,cAAc,GAAG,IAAI,CAAA;IAC/B,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,0GAyQpB,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"}
@@ -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
- setStateSafe({ phase: 'crashed', error: err });
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: p.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
- setStateSafe({ phase: 'crashed', windowId: windowIdRef.current ?? undefined, error: err });
229
+ crashAndRelease(err);
210
230
  }
211
231
  }
212
232
  function begin(controller) {
@@ -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;AAC9D,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,UAAU,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC5E,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,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":"stage.d.ts","sourceRoot":"","sources":["../../src/window/stage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAA;AA4BxD,wBAAgB,SAAS,IAAI,YAAY,CAiBxC"}
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"}
@@ -20,6 +20,7 @@ const STAGE_STYLE = {
20
20
  left: 0,
21
21
  right: 0,
22
22
  bottom: 0,
23
+ zIndex: 20,
23
24
  pointerEvents: 'none',
24
25
  };
25
26
  export function ViewStage() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/shell-react",
3
- "version": "0.2.8",
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.6"
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, SandboxProfile } from '@astrale-os/shell'
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?: SandboxProfile | null
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
- if (session.view === null) return box(fallback?.({ phase: 'no-view' }) ?? null)
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={session.view as ViewDescriptor}
105
+ view={view}
103
106
  node={props.node}
104
107
  credential={session.credential}
105
108
  capabilities={props.capabilities ?? { intents: [] }}
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,
@@ -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?: SandboxProfile | null
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) setStateSafe({ phase: 'crashed', error: err })
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: p.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
- setStateSafe({ phase: 'crashed', windowId: windowIdRef.current ?? undefined, error: err })
305
+ crashAndRelease(err)
281
306
  }
282
307
  }
283
308
 
@@ -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'
@@ -23,6 +23,7 @@ const STAGE_STYLE: CSSProperties = {
23
23
  left: 0,
24
24
  right: 0,
25
25
  bottom: 0,
26
+ zIndex: 20,
26
27
  pointerEvents: 'none',
27
28
  }
28
29