@astrale-os/shell-react 0.3.2-beta.5 → 0.3.2-beta.8

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/CHANGELOG.md ADDED
@@ -0,0 +1,223 @@
1
+ # Changelog
2
+
3
+ ## [0.3.2-beta.8](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.7...shell-react-v0.3.2-beta.8) (2026-08-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * grant trusted Shell exchange authority ([#140](https://github.com/astrale-os/shell/issues/140)) ([349c4b5](https://github.com/astrale-os/shell/commit/349c4b593b20245a8cb836f2370807b372faf23f))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** consume Zod-coherent SDK cohort ([#145](https://github.com/astrale-os/shell/issues/145)) ([2d2027c](https://github.com/astrale-os/shell/commit/2d2027c749f83c1e35a5b4a28696761b1f8e71e1))
14
+ * **domain:** adopt function and authority requirements ([#144](https://github.com/astrale-os/shell/issues/144)) ([016e306](https://github.com/astrale-os/shell/commit/016e30603591c32a2c8cf0073fe75995c67ae004))
15
+
16
+ ## [0.3.2-beta.7](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.6...shell-react-v0.3.2-beta.7) (2026-08-29)
17
+
18
+
19
+ ### Features
20
+
21
+ * **runtime:** enforce declared iframe requirements ([#129](https://github.com/astrale-os/shell/issues/129)) ([7b8d84a](https://github.com/astrale-os/shell/commit/7b8d84a1189e95c94c2de9f1759b6510a5467813))
22
+ * **shell:** adopt flat identity authentication ([#114](https://github.com/astrale-os/shell/issues/114)) ([f267a79](https://github.com/astrale-os/shell/commit/f267a79cd8bd58c29379c4be91b481c5dd20f1cf))
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * **domain:** publish visibility-free Shell bundle ([#131](https://github.com/astrale-os/shell/issues/131)) ([61f48e5](https://github.com/astrale-os/shell/commit/61f48e56f9b18a0b83d395ce1bae648d2470140c))
28
+
29
+ ## [0.3.2-beta.6](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.5...shell-react-v0.3.2-beta.6) (2026-08-28)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * **domain:** align canonical SDK contracts ([#117](https://github.com/astrale-os/shell/issues/117)) ([78df43d](https://github.com/astrale-os/shell/commit/78df43df4b2878221c7bfc83b32944264b3835e8))
35
+ * surface Domain binding diagnostics ([#125](https://github.com/astrale-os/shell/issues/125)) ([e37b6ca](https://github.com/astrale-os/shell/commit/e37b6ca1634ea5655dafbb2386af2c7198a55fe9))
36
+
37
+ ## [0.3.2-beta.5](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.4...shell-react-v0.3.2-beta.5) (2026-08-27)
38
+
39
+
40
+ ### Bug Fixes
41
+
42
+ * **react:** publish against Shell beta.7 ([#115](https://github.com/astrale-os/shell/issues/115)) ([2e2ad9e](https://github.com/astrale-os/shell/commit/2e2ad9e471b6c39413260f76954432a53be2cb23))
43
+
44
+ ## [0.3.2-beta.4](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.3...shell-react-v0.3.2-beta.4) (2026-08-26)
45
+
46
+
47
+ ### Bug Fixes
48
+
49
+ * **react:** preserve in-flight queries through StrictMode ([#112](https://github.com/astrale-os/shell/issues/112)) ([e5b7cd7](https://github.com/astrale-os/shell/commit/e5b7cd75e001be393d94e168089eb66a1da4bfb2))
50
+ * **shell:** align the published Shell cohort ([#109](https://github.com/astrale-os/shell/issues/109)) ([6c79cb6](https://github.com/astrale-os/shell/commit/6c79cb6f0370aad84565dda27d2af1a5579c18ff))
51
+
52
+ ## [0.3.2-beta.3](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.2...shell-react-v0.3.2-beta.3) (2026-08-26)
53
+
54
+
55
+ ### Bug Fixes
56
+
57
+ * **deploy:** consume current SDK toolchain ([#96](https://github.com/astrale-os/shell/issues/96)) ([73956a0](https://github.com/astrale-os/shell/commit/73956a05a2c9e107afedfa7b1878716644074bc1))
58
+ * **deps:** consume cloudflare adapter beta.44 ([#101](https://github.com/astrale-os/shell/issues/101)) ([7e9f214](https://github.com/astrale-os/shell/commit/7e9f214fe06979d5e1a7f4ca3b00cf431ab50944))
59
+
60
+ ## [0.3.2-beta.2](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta.1...shell-react-v0.3.2-beta.2) (2026-08-25)
61
+
62
+
63
+ ### Bug Fixes
64
+
65
+ * retain sandboxed View proof boundaries ([#80](https://github.com/astrale-os/shell/issues/80)) ([7de8800](https://github.com/astrale-os/shell/commit/7de8800dc42106bd4aa0f8a6340117d17c51d195))
66
+
67
+ ## [0.3.2-beta.1](https://github.com/astrale-os/shell/compare/shell-react-v0.3.2-beta...shell-react-v0.3.2-beta.1) (2026-08-25)
68
+
69
+
70
+ ### Features
71
+
72
+ * **react:** bind projected recipes to domain context ([#72](https://github.com/astrale-os/shell/issues/72)) ([1d963dc](https://github.com/astrale-os/shell/commit/1d963dc33e98ec7c4b1cece467c9b2428e07aeea))
73
+
74
+
75
+ ### Bug Fixes
76
+
77
+ * **packages:** keep install guards private ([#71](https://github.com/astrale-os/shell/issues/71)) ([20a34ee](https://github.com/astrale-os/shell/commit/20a34eeafea868f31663b3076928c3528f4e1aec))
78
+
79
+ ## [0.3.2-beta](https://github.com/astrale-os/shell/compare/shell-react-v0.3.1...shell-react-v0.3.2-beta) (2026-08-24)
80
+
81
+
82
+ ### Bug Fixes
83
+
84
+ * **deps:** align Shell packages with SDK beta.22 ([#65](https://github.com/astrale-os/shell/issues/65)) ([18db939](https://github.com/astrale-os/shell/commit/18db93958e64678f9c000e258c12a97525fa95ef))
85
+ * **deps:** require Shell 0.4.2 beta ([#70](https://github.com/astrale-os/shell/issues/70)) ([b6ec3b3](https://github.com/astrale-os/shell/commit/b6ec3b39cd8ab571e7a3e64092e896ac8e14cd62))
86
+ * qualify the Shell release cohort ([8f837e1](https://github.com/astrale-os/shell/commit/8f837e1bf14600db18b96da6de7878f34321332c))
87
+ * qualify the Shell release cohort ([efb23d7](https://github.com/astrale-os/shell/commit/efb23d71088a407209a01cec33e5571d86ecde51))
88
+ * **release:** preserve SDK dependency ownership ([#62](https://github.com/astrale-os/shell/issues/62)) ([5199f73](https://github.com/astrale-os/shell/commit/5199f7358a64cfb1163ebb6d13c94a8b8080bcc1))
89
+
90
+ ## [0.3.1](https://github.com/astrale-os/shell/compare/shell-react-v0.3.0...shell-react-v0.3.1) (2026-08-24)
91
+
92
+
93
+ ### Bug Fixes
94
+
95
+ * **release:** qualify published sdk runtime context ([b1411a0](https://github.com/astrale-os/shell/commit/b1411a01710bab785b31c02c81ea09bc902f4e42))
96
+
97
+ ## [0.3.0](https://github.com/astrale-os/shell/compare/shell-react-v0.2.9...shell-react-v0.3.0) (2026-08-24)
98
+
99
+
100
+ ### ⚠ BREAKING CHANGES
101
+
102
+ * adopt path-only invocation
103
+
104
+ ### Features
105
+
106
+ * adopt kernel client session vocabulary ([95877b2](https://github.com/astrale-os/shell/commit/95877b25e6d672fe69f14b28ac9fa712b0649a76))
107
+ * adopt Kernel Client Session vocabulary ([ac61164](https://github.com/astrale-os/shell/commit/ac61164bba8540931ad7c0c2cf68be95fb3336c0))
108
+ * adopt Kernel V2 at the Shell client boundary ([6654ef7](https://github.com/astrale-os/shell/commit/6654ef7989691664af777824be2c97a2906b4008))
109
+ * adopt path-only invocation ([afef6f4](https://github.com/astrale-os/shell/commit/afef6f4c970b3b01bb69f758f163cc9fa2b14641))
110
+ * complete kernel v2 shell migration ([82a2d36](https://github.com/astrale-os/shell/commit/82a2d36ae804ddbfd06fa59afb6a290128c28a82))
111
+ * **domain:** deploy Shell through default adapter ([43bc418](https://github.com/astrale-os/shell/commit/43bc418952666d7aac26194134c2776b58c355e7))
112
+ * **domain:** publish @astrale-domains/shell ([905488b](https://github.com/astrale-os/shell/commit/905488b647e73793eb18ec50e5b06f763b7630e8))
113
+ * migrate shell packages to kernel beta.2 ([62ea4a2](https://github.com/astrale-os/shell/commit/62ea4a2ff5c1b149a94a3969985debd8d791e3f3))
114
+ * **runtime:** add graph-first React view runtime ([40ed99f](https://github.com/astrale-os/shell/commit/40ed99f03b2c2067f209b1be85d1667e6dc904f2))
115
+ * **runtime:** add graph-first React View runtime ([702fe44](https://github.com/astrale-os/shell/commit/702fe44a1687af992a46afac16efed87dfc6e057))
116
+ * **shell:** author graph operations with direct node targets ([a189028](https://github.com/astrale-os/shell/commit/a189028cee3d5f14678325c713b9439487c9e224))
117
+ * **shell:** author graph operations with node targets ([97f0599](https://github.com/astrale-os/shell/commit/97f05997bb34e8935349dbb6f5b9e55a2432cca3))
118
+
119
+
120
+ ### Bug Fixes
121
+
122
+ * adopt current Shell domain bindings ([121c7be](https://github.com/astrale-os/shell/commit/121c7bea57ad1bf4cedbab90ed8cba8f59955f06))
123
+ * adopt source cohort domain bindings ([bf79155](https://github.com/astrale-os/shell/commit/bf7915555d7152b2e70127b54a1e8b4fdc269b04))
124
+ * adopt the official kernel cohort ([#47](https://github.com/astrale-os/shell/issues/47)) ([c15a5b0](https://github.com/astrale-os/shell/commit/c15a5b0d8c9f4c3f6dd49bf122cfea09c4af42da))
125
+ * align shell with current kernel client ([5351dc8](https://github.com/astrale-os/shell/commit/5351dc85beafdcca8f74817e032e3aab0edf0397))
126
+ * align Shell with current Kernel cohort ([d1abeaf](https://github.com/astrale-os/shell/commit/d1abeaf2a418e7e6bf89ea85512cd0e8942d407b))
127
+ * **domain:** align deployment with current SDK ([7a5fbae](https://github.com/astrale-os/shell/commit/7a5fbae7283aac0bb9f1aebd7b7bb0a753a1ba15))
128
+ * **domain:** use the published SDK boundary ([2e494c6](https://github.com/astrale-os/shell/commit/2e494c6f8b4d3d25c71bbe51b37436fd35d6c42a))
129
+ * lock shell to current beta cohort ([8350423](https://github.com/astrale-os/shell/commit/8350423f2be37208396bd6ab37e43c102d73bb9e))
130
+
131
+ ## [0.2.9](https://github.com/astrale-os/shell/compare/shell-react-v0.2.8...shell-react-v0.2.9) (2026-07-18)
132
+
133
+
134
+ ### Features
135
+
136
+ * **windows:** support resolved iframe sandbox policies ([#30](https://github.com/astrale-os/shell/issues/30)) ([9c6c2e9](https://github.com/astrale-os/shell/commit/9c6c2e999115819227c7400bbb4f1edaf7b7b40d))
137
+
138
+
139
+ ### Bug Fixes
140
+
141
+ * **core:** keep managed iframes above workspace surfaces ([#28](https://github.com/astrale-os/shell/issues/28)) ([2ab656a](https://github.com/astrale-os/shell/commit/2ab656a46bcb342850a5703c82d82eea9bfbd958))
142
+
143
+ ## [0.2.8](https://github.com/astrale-os/shell/compare/shell-react-v0.2.7...shell-react-v0.2.8) (2026-07-15)
144
+
145
+
146
+ ### Features
147
+
148
+ * **shell:** expose domain search through useDomains ([13dbe0c](https://github.com/astrale-os/shell/commit/13dbe0c769886080fbc0da62dbe82868d27e8aaf))
149
+ * **shell:** expose domain search through useDomains ([bb3076a](https://github.com/astrale-os/shell/commit/bb3076aa1788ec8d1e6f4155014bac3ed0f93783))
150
+
151
+
152
+ ### Bug Fixes
153
+
154
+ * **react:** resolve canonical function bindings ([52be852](https://github.com/astrale-os/shell/commit/52be8529ca37aeac3878dfd198f76e3b81d37d25))
155
+ * **react:** resolve canonical function bindings ([db8f0ab](https://github.com/astrale-os/shell/commit/db8f0abbc6b3d43063a9450a1bfbb911f1d7aa1d))
156
+
157
+ ## [0.2.7](https://github.com/astrale-os/shell/compare/shell-react-v0.2.6...shell-react-v0.2.7) (2026-07-12)
158
+
159
+
160
+ ### Features
161
+
162
+ * **shell:** resolve views and reject failed intents ([0cf741e](https://github.com/astrale-os/shell/commit/0cf741ec5279ca003b97f39b4b5cbe5c71099ab3))
163
+
164
+ ## [0.2.6](https://github.com/astrale-os/shell/compare/shell-react-v0.2.5...shell-react-v0.2.6) (2026-07-12)
165
+
166
+
167
+ ### Features
168
+
169
+ * **shell-react:** add fire-and-forget intent emitter ([850e0e2](https://github.com/astrale-os/shell/commit/850e0e20f44e2475c0859c6690ea8f6f24131768))
170
+
171
+ ## [0.2.5](https://github.com/astrale-os/shell/compare/shell-react-v0.2.4...shell-react-v0.2.5) (2026-07-12)
172
+
173
+
174
+ ### Bug Fixes
175
+
176
+ * preserve virtual session capabilities ([#19](https://github.com/astrale-os/shell/issues/19)) ([792993f](https://github.com/astrale-os/shell/commit/792993f070e0f07069876068a14e324e2d446589))
177
+
178
+ ## [0.2.4](https://github.com/astrale-os/shell/compare/shell-react-v0.2.3...shell-react-v0.2.4) (2026-07-12)
179
+
180
+
181
+ ### Bug Fixes
182
+
183
+ * **react:** keep endpoint envelopes cardinality-stable ([432dd7e](https://github.com/astrale-os/shell/commit/432dd7eb3b495b305bec6acedbcb888fe96e627c))
184
+
185
+ ## [0.2.3](https://github.com/astrale-os/shell/compare/shell-react-v0.2.2...shell-react-v0.2.3) (2026-07-12)
186
+
187
+
188
+ ### Bug Fixes
189
+
190
+ * **deps:** require edge-cardinality kernel client ([83283a9](https://github.com/astrale-os/shell/commit/83283a9c794427946e527d549f5346eacc787c19))
191
+
192
+ ## [0.2.2](https://github.com/astrale-os/shell/compare/shell-react-v0.2.1...shell-react-v0.2.2) (2026-07-12)
193
+
194
+
195
+ ### Features
196
+
197
+ * **react:** adopt typed domain class handles ([c63ab05](https://github.com/astrale-os/shell/commit/c63ab053e0fa48a54e2690a58b932b54029afd8b))
198
+
199
+ ## [0.2.1](https://github.com/astrale-os/shell/compare/shell-react-v0.2.0...shell-react-v0.2.1) (2026-07-11)
200
+
201
+
202
+ ### Bug Fixes
203
+
204
+ * explicit .js specifiers + nodenext so dist loads under Node's native ESM loader ([#10](https://github.com/astrale-os/shell/issues/10)) ([2f8616f](https://github.com/astrale-os/shell/commit/2f8616ff8b5bf00e2dab9229fd6afd3dbfdce8ce))
205
+
206
+ ## [0.2.0](https://github.com/astrale-os/shell/compare/shell-react-v0.1.0...shell-react-v0.2.0) (2026-07-09)
207
+
208
+
209
+ ### ⚠ BREAKING CHANGES
210
+
211
+ * **core:** removed CreateKernelClientAdapterOpts.mintIdentity — the delegation mint is always self per the kernel invariant, so delegationMintVia covers it. createShell({ mintIdentity }) is unchanged (the facade still honors it for the identity-credential mint subject).
212
+
213
+ * **core:** legacy-ops cutover — get/mutate doors, bounded contexts, auth collapse, shell-react ([#7](https://github.com/astrale-os/shell/issues/7)) ([0119b0f](https://github.com/astrale-os/shell/commit/0119b0f64e152bd1765facce880a533401a3e65e))
214
+
215
+
216
+ ### Features
217
+
218
+ * use shell domain schema ([6ca1be8](https://github.com/astrale-os/shell/commit/6ca1be82aece4cd2925c1b4587e65b797686e804))
219
+
220
+
221
+ ### Bug Fixes
222
+
223
+ * require published shell schema entrypoints ([92aa701](https://github.com/astrale-os/shell/commit/92aa70117dbfa10bc4dc2133e1c0c322a21a571e))
@@ -1,7 +1,7 @@
1
1
  import type { Key } from '@astrale-os/sdk/schema';
2
2
  import type { App, HostCapabilities, ResolvedView } from '@astrale-os/shell';
3
3
  import type { CSSProperties, ReactNode } from 'react';
4
- import type { SandboxPolicy, ViewHostHandle } from '../../window/host.js';
4
+ import type { ViewHostHandle } from '../../window/host.js';
5
5
  import type { WindowState } from '../../window/lifecycle/states.js';
6
6
  export type AppHostFallbackState = WindowState | {
7
7
  readonly phase: 'opening';
@@ -13,7 +13,6 @@ export interface AppHostProps {
13
13
  /** Override the installed Domain entry View. */
14
14
  view?: ResolvedView;
15
15
  capabilities?: HostCapabilities;
16
- sandbox?: SandboxPolicy;
17
16
  fallback?: (state: AppHostFallbackState) => ReactNode;
18
17
  className?: string;
19
18
  style?: CSSProperties;
@@ -35,5 +35,5 @@ export const AppHost = forwardRef(function AppHost(props, ref) {
35
35
  const view = props.view ?? opened;
36
36
  if (view === null || view === undefined)
37
37
  return box(fallback?.({ phase: 'no-view' }) ?? null);
38
- return (_jsx(ViewHost, { ref: ref, view: view, capabilities: props.capabilities, sandbox: props.sandbox, fallback: fallback ? (state) => fallback(state) : undefined, className: className, style: style }));
38
+ return (_jsx(ViewHost, { ref: ref, view: view, capabilities: props.capabilities, fallback: fallback ? (state) => fallback(state) : undefined, className: className, style: style }));
39
39
  });
@@ -34,7 +34,7 @@ export declare class ViewErrorBoundary extends Component<ViewErrorBoundaryProps,
34
34
  render(): ReactNode;
35
35
  }
36
36
  export declare function defaultViewLoading(): ReactElement;
37
- export declare function defaultViewError(_error: unknown, retry: () => void): ReactElement;
37
+ export declare function defaultViewError(error: unknown, retry: () => void): ReactElement;
38
38
  export declare function ConnectionBoundary(props: {
39
39
  readonly children: ReactNode;
40
40
  readonly fallback?: (status: ReturnType<typeof useConnection>) => ReactNode;
@@ -41,8 +41,9 @@ export class ViewErrorBoundary extends Component {
41
41
  export function defaultViewLoading() {
42
42
  return (_jsx("div", { role: "status", "aria-live": "polite", children: "Loading view\u2026" }));
43
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" })] }));
44
+ export function defaultViewError(error, retry) {
45
+ const message = error instanceof Error ? error.message : String(error);
46
+ return (_jsxs("section", { role: "alert", children: [_jsx("p", { children: "View could not load." }), _jsx("p", { children: message }), _jsx("button", { type: "button", onClick: retry, children: "Retry" })] }));
46
47
  }
47
48
  export function ConnectionBoundary(props) {
48
49
  const connection = useConnection();
@@ -10,9 +10,7 @@ export async function resolveGraphStoreScope(shell, knownIdentity) {
10
10
  shell.kernel.snapshot(),
11
11
  ]);
12
12
  return Object.freeze({
13
- authority: identity === null
14
- ? 'anonymous'
15
- : `${identity.issuer}\u0000${identity.subject}\u0000${identity.id}`,
13
+ authority: identity === null ? 'anonymous' : `${identity.iss}\u0000${identity.sub}\u0000${identity.id}`,
16
14
  schemaRevision: snapshot.publication.schema.revision,
17
15
  });
18
16
  }
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export type { LinkProps, LocationDefinition, MissingPolicy, NavAdapter, NavLocat
12
12
  export { SelectionScope, useSelection } from './selection/index.js';
13
13
  export type { Selection, SelectionScopeProps } from './selection/index.js';
14
14
  export { ViewHost, ViewStage, useCloseGuard, useTargetNode, useTargetPath, useViewsFor, useWindow, useWindowList, useWindows, } from './window/index.js';
15
- export type { CloseGuard, CloseVerdict, ResolvedView, SandboxPolicy, ViewHostHandle, ViewHostProps, ViewsForResult, WindowListEntry, WindowState, WindowView, } from './window/index.js';
15
+ export type { CloseGuard, CloseVerdict, ResolvedView, ViewHostHandle, ViewHostProps, ViewsForResult, WindowListEntry, WindowState, WindowView, } from './window/index.js';
16
16
  export { HostDialog, NestedView, Notify, RequestAccess, useExternalOpen, useHostCapabilities, useHostDialog, useNotify, useOpenView, useRequestAccess, } from './host/index.js';
17
17
  export type { ExternalOpenApi, HostDialogApi, NotifyApi, OpenViewApi, RequestAccessApi, } from './host/index.js';
18
18
  export { HostCapabilityUnavailableError } from './host/index.js';
@@ -1,4 +1,4 @@
1
- import type { CloseResult, HostCapabilities, MountCredential, ResolvedView, SandboxProfile } from '@astrale-os/shell';
1
+ import type { CloseResult, HostCapabilities, MountCredential, ResolvedView } from '@astrale-os/shell';
2
2
  import type { CSSProperties, ReactNode } from 'react';
3
3
  import type { WindowState } from './lifecycle/states.js';
4
4
  /** Imperative handle on a mounted `ViewHost` (API §10). */
@@ -11,13 +11,10 @@ export interface ViewHostHandle {
11
11
  /** The one explicit remount. */
12
12
  refresh(): void;
13
13
  }
14
- /** Static iframe sandbox flags, an explicit opt-out, or a policy over the resolved mount. */
15
- export type SandboxPolicy = SandboxProfile | null | ((view: ResolvedView) => SandboxProfile | null);
16
14
  export interface ViewHostProps {
17
15
  /** One canonical target paired with one untouched View route. */
18
16
  view: ResolvedView;
19
17
  capabilities?: HostCapabilities;
20
- sandbox?: SandboxPolicy;
21
18
  credential?: MountCredential;
22
19
  handshakeTimeoutMs?: number;
23
20
  delegationTtlSeconds?: number;
@@ -32,6 +32,9 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
32
32
  const [state, setState] = useState(MOUNTING);
33
33
  const [refreshNonce, setRefreshNonce] = useState(0);
34
34
  const mountKey = viewMountKey(props.view);
35
+ const latestMountKeyRef = useRef(mountKey);
36
+ const retirementRef = useRef(null);
37
+ latestMountKeyRef.current = mountKey;
35
38
  const setStateSafe = (next) => {
36
39
  if (!aliveRef.current)
37
40
  return;
@@ -101,6 +104,20 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
101
104
  .finally(() => hub.registry.remove(id));
102
105
  slot.release();
103
106
  }
107
+ /** Authority/provenance changes retire the old generation before a replacement may mount. */
108
+ function forceRetireAndRelease(id, slot) {
109
+ slot.release();
110
+ const retirement = shell
111
+ .close(id, { force: true })
112
+ .then((result) => {
113
+ if (result.kind === 'refused') {
114
+ throw new Error('Forced View generation retirement was refused.');
115
+ }
116
+ })
117
+ .finally(() => hub.registry.remove(id));
118
+ retirementRef.current = retirement;
119
+ void retirement.catch(() => { });
120
+ }
104
121
  /** Stash the live window for adoption, or (on refresh) close it outright. */
105
122
  function cleanup() {
106
123
  cancelled = true;
@@ -123,8 +140,9 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
123
140
  state: live.state,
124
141
  dispose: () => closeAndRelease(live.windowId, slot),
125
142
  };
126
- if (refreshingRef.current)
127
- record.dispose();
143
+ if (refreshingRef.current || latestMountKeyRef.current !== mountKey) {
144
+ forceRetireAndRelease(live.windowId, slot);
145
+ }
128
146
  else
129
147
  hub.stashForAdopt(mountKey, record);
130
148
  }
@@ -155,36 +173,34 @@ export const ViewHost = forwardRef(function ViewHost(props, ref) {
155
173
  }
156
174
  }
157
175
  async function mountView() {
158
- const p = propsRef.current;
159
- let sandbox;
160
- try {
161
- sandbox = typeof p.sandbox === 'function' ? p.sandbox(p.view) : p.sandbox;
162
- }
163
- catch (err) {
164
- if (!cancelled)
165
- crashAndRelease(err);
166
- return;
167
- }
168
- const params = {
169
- host: slotRef.current.element,
170
- view: p.view,
171
- capabilities: p.capabilities ?? {
172
- version: 1,
173
- navigation: {},
174
- actions: {},
175
- browser: {},
176
- access: {},
177
- },
178
- sandbox,
179
- credential: p.credential,
180
- ...(p.handshakeTimeoutMs === undefined
181
- ? {}
182
- : { handshakeTimeoutMs: p.handshakeTimeoutMs }),
183
- ...(p.delegationTtlSeconds === undefined
184
- ? {}
185
- : { delegationTtlSeconds: p.delegationTtlSeconds }),
186
- };
187
176
  try {
177
+ const retirement = retirementRef.current;
178
+ if (retirement !== null) {
179
+ await retirement;
180
+ if (retirementRef.current === retirement)
181
+ retirementRef.current = null;
182
+ }
183
+ if (cancelled)
184
+ return;
185
+ const p = propsRef.current;
186
+ const params = {
187
+ host: slotRef.current.element,
188
+ view: p.view,
189
+ capabilities: p.capabilities ?? {
190
+ version: 1,
191
+ navigation: {},
192
+ actions: {},
193
+ browser: {},
194
+ access: {},
195
+ },
196
+ credential: p.credential,
197
+ ...(p.handshakeTimeoutMs === undefined
198
+ ? {}
199
+ : { handshakeTimeoutMs: p.handshakeTimeoutMs }),
200
+ ...(p.delegationTtlSeconds === undefined
201
+ ? {}
202
+ : { delegationTtlSeconds: p.delegationTtlSeconds }),
203
+ };
188
204
  const win = await shell.openView(params);
189
205
  // A StrictMode cleanup (or refresh) fired before mount resolved: adopt
190
206
  // then immediately close so no orphan window survives.
@@ -1,6 +1,6 @@
1
1
  export { ViewStage } from './stage.js';
2
2
  export { ViewHost } from './host.js';
3
- export type { SandboxPolicy, ViewHostProps, ViewHostHandle } from './host.js';
3
+ export type { 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';
@@ -13,5 +13,7 @@ export function viewMountKey(view) {
13
13
  route.issuer,
14
14
  route.etag,
15
15
  route.revision,
16
+ route.iframe?.sandbox?.join('\u001f') ?? '',
17
+ route.iframe?.allow?.join('\u001f') ?? '',
16
18
  ].join('\u0000');
17
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/shell-react",
3
- "version": "0.3.2-beta.5",
3
+ "version": "0.3.2-beta.8",
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": {
@@ -28,10 +28,10 @@
28
28
  "dependencies": {
29
29
  "@astrale-os/shell": ">=0.4.2-beta.7 <1.0.0",
30
30
  "jose": "^6.2.8",
31
- "zod": "^4.4.3"
31
+ "zod": "4.4.3"
32
32
  },
33
33
  "devDependencies": {
34
- "@astrale-os/sdk": "0.5.0-beta.51",
34
+ "@astrale-os/sdk": "0.5.0-beta.95",
35
35
  "@testing-library/dom": "^10.4.0",
36
36
  "@testing-library/react": "^16.3.0",
37
37
  "@types/node": "^26.2.0",
@@ -46,7 +46,7 @@
46
46
  "vitest": "4.1.10"
47
47
  },
48
48
  "peerDependencies": {
49
- "@astrale-os/sdk": ">=0.5.0-beta.51 <1.0.0",
49
+ "@astrale-os/sdk": ">=0.5.0-beta.95 <1.0.0",
50
50
  "react": ">=18",
51
51
  "react-dom": ">=18"
52
52
  },
@@ -4,7 +4,7 @@ import type { CSSProperties, ReactElement, ReactNode } from 'react'
4
4
 
5
5
  import { forwardRef, useEffect, useRef, useState } from 'react'
6
6
 
7
- import type { SandboxPolicy, ViewHostHandle } from '../../window/host.js'
7
+ import type { ViewHostHandle } from '../../window/host.js'
8
8
  import type { WindowState } from '../../window/lifecycle/states.js'
9
9
 
10
10
  import { ViewHost } from '../../window/host.js'
@@ -20,7 +20,6 @@ export interface AppHostProps {
20
20
  /** Override the installed Domain entry View. */
21
21
  view?: ResolvedView
22
22
  capabilities?: HostCapabilities
23
- sandbox?: SandboxPolicy
24
23
  fallback?: (state: AppHostFallbackState) => ReactNode
25
24
  className?: string
26
25
  style?: CSSProperties
@@ -72,7 +71,6 @@ export const AppHost = forwardRef<ViewHostHandle, AppHostProps>(
72
71
  ref={ref}
73
72
  view={view}
74
73
  capabilities={props.capabilities}
75
- sandbox={props.sandbox}
76
74
  fallback={fallback ? (state: WindowState) => fallback(state) : undefined}
77
75
  className={className}
78
76
  style={style}
@@ -75,10 +75,12 @@ export function defaultViewLoading(): ReactElement {
75
75
  )
76
76
  }
77
77
 
78
- export function defaultViewError(_error: unknown, retry: () => void): ReactElement {
78
+ export function defaultViewError(error: unknown, retry: () => void): ReactElement {
79
+ const message = error instanceof Error ? error.message : String(error)
79
80
  return (
80
81
  <section role="alert">
81
82
  <p>View could not load.</p>
83
+ <p>{message}</p>
82
84
  <button type="button" onClick={retry}>
83
85
  Retry
84
86
  </button>
@@ -39,9 +39,7 @@ export async function resolveGraphStoreScope(
39
39
  ])
40
40
  return Object.freeze({
41
41
  authority:
42
- identity === null
43
- ? 'anonymous'
44
- : `${identity.issuer}\u0000${identity.subject}\u0000${identity.id}`,
42
+ identity === null ? 'anonymous' : `${identity.iss}\u0000${identity.sub}\u0000${identity.id}`,
45
43
  schemaRevision: snapshot.publication.schema.revision,
46
44
  })
47
45
  }
package/src/index.ts CHANGED
@@ -123,7 +123,6 @@ export type {
123
123
  CloseGuard,
124
124
  CloseVerdict,
125
125
  ResolvedView,
126
- SandboxPolicy,
127
126
  ViewHostHandle,
128
127
  ViewHostProps,
129
128
  ViewsForResult,
@@ -4,7 +4,6 @@ import type {
4
4
  MountCredential,
5
5
  MountParams,
6
6
  ResolvedView,
7
- SandboxProfile,
8
7
  Window,
9
8
  } from '@astrale-os/shell'
10
9
  import type { CSSProperties, ReactElement, ReactNode } from 'react'
@@ -45,14 +44,10 @@ export interface ViewHostHandle {
45
44
  refresh(): void
46
45
  }
47
46
 
48
- /** Static iframe sandbox flags, an explicit opt-out, or a policy over the resolved mount. */
49
- export type SandboxPolicy = SandboxProfile | null | ((view: ResolvedView) => SandboxProfile | null)
50
-
51
47
  export interface ViewHostProps {
52
48
  /** One canonical target paired with one untouched View route. */
53
49
  view: ResolvedView
54
50
  capabilities?: HostCapabilities
55
- sandbox?: SandboxPolicy
56
51
  credential?: MountCredential
57
52
  handshakeTimeoutMs?: number
58
53
  delegationTtlSeconds?: number
@@ -96,6 +91,9 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
96
91
  const [refreshNonce, setRefreshNonce] = useState(0)
97
92
 
98
93
  const mountKey = viewMountKey(props.view)
94
+ const latestMountKeyRef = useRef(mountKey)
95
+ const retirementRef = useRef<Promise<void> | null>(null)
96
+ latestMountKeyRef.current = mountKey
99
97
 
100
98
  const setStateSafe = (next: WindowState) => {
101
99
  if (!aliveRef.current) return
@@ -172,6 +170,21 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
172
170
  slot.release()
173
171
  }
174
172
 
173
+ /** Authority/provenance changes retire the old generation before a replacement may mount. */
174
+ function forceRetireAndRelease(id: string, slot: StageSlot): void {
175
+ slot.release()
176
+ const retirement = shell
177
+ .close(id, { force: true })
178
+ .then((result) => {
179
+ if (result.kind === 'refused') {
180
+ throw new Error('Forced View generation retirement was refused.')
181
+ }
182
+ })
183
+ .finally(() => hub.registry.remove(id))
184
+ retirementRef.current = retirement
185
+ void retirement.catch(() => {})
186
+ }
187
+
175
188
  /** Stash the live window for adoption, or (on refresh) close it outright. */
176
189
  function cleanup(): void {
177
190
  cancelled = true
@@ -194,8 +207,9 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
194
207
  state: live.state,
195
208
  dispose: () => closeAndRelease(live.windowId, slot),
196
209
  }
197
- if (refreshingRef.current) record.dispose()
198
- else hub.stashForAdopt(mountKey, record)
210
+ if (refreshingRef.current || latestMountKeyRef.current !== mountKey) {
211
+ forceRetireAndRelease(live.windowId, slot)
212
+ } else hub.stashForAdopt(mountKey, record)
199
213
  }
200
214
 
201
215
  /** A pre-ready failure must not leave an empty stage slot over the fallback UI. */
@@ -227,35 +241,32 @@ export const ViewHost = forwardRef<ViewHostHandle, ViewHostProps>(
227
241
  }
228
242
 
229
243
  async function mountView(): Promise<void> {
230
- const p = propsRef.current
231
- let sandbox: SandboxProfile | null | undefined
232
- try {
233
- sandbox = typeof p.sandbox === 'function' ? p.sandbox(p.view) : p.sandbox
234
- } catch (err) {
235
- if (!cancelled) crashAndRelease(err)
236
- return
237
- }
238
- const params: MountParams = {
239
- host: slotRef.current!.element,
240
- view: p.view,
241
- capabilities: p.capabilities ?? {
242
- version: 1,
243
- navigation: {},
244
- actions: {},
245
- browser: {},
246
- access: {},
247
- },
248
- sandbox,
249
- credential: p.credential,
250
- ...(p.handshakeTimeoutMs === undefined
251
- ? {}
252
- : { handshakeTimeoutMs: p.handshakeTimeoutMs }),
253
- ...(p.delegationTtlSeconds === undefined
254
- ? {}
255
- : { delegationTtlSeconds: p.delegationTtlSeconds }),
256
- }
257
-
258
244
  try {
245
+ const retirement = retirementRef.current
246
+ if (retirement !== null) {
247
+ await retirement
248
+ if (retirementRef.current === retirement) retirementRef.current = null
249
+ }
250
+ if (cancelled) return
251
+ const p = propsRef.current
252
+ const params: MountParams = {
253
+ host: slotRef.current!.element,
254
+ view: p.view,
255
+ capabilities: p.capabilities ?? {
256
+ version: 1,
257
+ navigation: {},
258
+ actions: {},
259
+ browser: {},
260
+ access: {},
261
+ },
262
+ credential: p.credential,
263
+ ...(p.handshakeTimeoutMs === undefined
264
+ ? {}
265
+ : { handshakeTimeoutMs: p.handshakeTimeoutMs }),
266
+ ...(p.delegationTtlSeconds === undefined
267
+ ? {}
268
+ : { delegationTtlSeconds: p.delegationTtlSeconds }),
269
+ }
259
270
  const win = await shell.openView(params)
260
271
  // A StrictMode cleanup (or refresh) fired before mount resolved: adopt
261
272
  // then immediately close so no orphan window survives.
@@ -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 { SandboxPolicy, ViewHostProps, ViewHostHandle } from './host.js'
6
+ export type { 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'
@@ -15,5 +15,7 @@ export function viewMountKey(view: ResolvedView): string {
15
15
  route.issuer,
16
16
  route.etag,
17
17
  route.revision,
18
+ route.iframe?.sandbox?.join('\u001f') ?? '',
19
+ route.iframe?.allow?.join('\u001f') ?? '',
18
20
  ].join('\u0000')
19
21
  }