@hosty-sdk/app 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/install.d.ts +1 -1
- package/dist/react.d.ts +3 -1
- package/dist/react.js +8 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -25,6 +25,13 @@ Minimal Next.js wiring:
|
|
|
25
25
|
import { AppIdentityBridge } from "@hosty-sdk/app/react";
|
|
26
26
|
// wrap protected client content: <AppIdentityBridge>{children}</AppIdentityBridge>
|
|
27
27
|
|
|
28
|
+
// Reuse an active probe that already returns the app's session fields:
|
|
29
|
+
// <AppIdentityBridge probePath="/api/auth/session" onSession={seedSessionCache}>
|
|
30
|
+
// {children}
|
|
31
|
+
// </AppIdentityBridge>
|
|
32
|
+
// seedSessionCache receives unknown JSON; validate app-specific fields before caching.
|
|
33
|
+
// The callback runs before children mount, only for a successful active probe.
|
|
34
|
+
|
|
28
35
|
// app/api/auth/app-code/route.ts
|
|
29
36
|
import { createAppCodeRouteHandler } from "@hosty-sdk/app/server";
|
|
30
37
|
export const dynamic = "force-dynamic";
|
package/dist/install.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export interface InstallationSource {
|
|
|
83
83
|
description?: string | null;
|
|
84
84
|
};
|
|
85
85
|
};
|
|
86
|
-
/** Personal source selection requires apps.
|
|
86
|
+
/** Personal source selection requires apps.install plus apps.sources or sources.connections and Core review. */
|
|
87
87
|
sourceConnections?: {
|
|
88
88
|
manifestConnectionId?: string;
|
|
89
89
|
gitConnectionId?: string;
|
package/dist/react.d.ts
CHANGED
|
@@ -50,6 +50,8 @@ export interface AppIdentityBridgeProps {
|
|
|
50
50
|
appCodePath?: string;
|
|
51
51
|
/** Optional app-owned rendering, including loading and active content. Recovery remains SDK-owned. */
|
|
52
52
|
renderState?: (state: AppIdentityBridgeState) => ReactNode;
|
|
53
|
+
/** Receives a successful active probe before children mount, so an app can seed its session cache. */
|
|
54
|
+
onSession?: (body: unknown) => void;
|
|
53
55
|
children?: ReactNode;
|
|
54
56
|
}
|
|
55
57
|
/**
|
|
@@ -60,7 +62,7 @@ export interface AppIdentityBridgeProps {
|
|
|
60
62
|
* redirect through Core `/open` when standalone, and cards only in fallback/terminal states
|
|
61
63
|
* — never a login UI while recovery is still running.
|
|
62
64
|
*/
|
|
63
|
-
export declare function AppIdentityBridge({ probePath, appCodePath, renderState, children, }?: AppIdentityBridgeProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
|
|
65
|
+
export declare function AppIdentityBridge({ probePath, appCodePath, renderState, onSession, children, }?: AppIdentityBridgeProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
|
|
64
66
|
export interface HostThemeBridgeProps {
|
|
65
67
|
/**
|
|
66
68
|
* Whether the operating system decides the theme while no shell has spoken — `true` unless the
|
package/dist/react.js
CHANGED
|
@@ -187,7 +187,7 @@ export function useLaunchMode() {
|
|
|
187
187
|
* redirect through Core `/open` when standalone, and cards only in fallback/terminal states
|
|
188
188
|
* — never a login UI while recovery is still running.
|
|
189
189
|
*/
|
|
190
|
-
export function AppIdentityBridge({ probePath = "/api/auth/identity", appCodePath = "/api/auth/app-code", renderState, children, } = {}) {
|
|
190
|
+
export function AppIdentityBridge({ probePath = "/api/auth/identity", appCodePath = "/api/auth/app-code", renderState, onSession, children, } = {}) {
|
|
191
191
|
const [ui, setUi] = useState({ kind: "recovering" });
|
|
192
192
|
// A launch code is single-use. Strict Mode replays the effect after the URL is cleaned;
|
|
193
193
|
// keep its exchange alive and let the replacement effect await the same response.
|
|
@@ -199,6 +199,8 @@ export function AppIdentityBridge({ probePath = "/api/auth/identity", appCodePat
|
|
|
199
199
|
const upgradedAttempt = useRef(false);
|
|
200
200
|
const [activity, setActivity] = useState(null);
|
|
201
201
|
const exchangeRef = useRef(null);
|
|
202
|
+
const onSessionRef = useRef(onSession);
|
|
203
|
+
useEffect(() => { onSessionRef.current = onSession; }, [onSession]);
|
|
202
204
|
useEffect(() => {
|
|
203
205
|
let cancelled = false;
|
|
204
206
|
const controller = new AbortController();
|
|
@@ -218,6 +220,7 @@ export function AppIdentityBridge({ probePath = "/api/auth/identity", appCodePat
|
|
|
218
220
|
let protocol = null;
|
|
219
221
|
let activityMetadata = null;
|
|
220
222
|
let rejectionCode;
|
|
223
|
+
let sessionBody = null;
|
|
221
224
|
const revision = appGrantRevision();
|
|
222
225
|
try {
|
|
223
226
|
const response = await appFetch(probePath, {
|
|
@@ -227,6 +230,9 @@ export function AppIdentityBridge({ probePath = "/api/auth/identity", appCodePat
|
|
|
227
230
|
}, false);
|
|
228
231
|
const body = await response.json().catch(() => null);
|
|
229
232
|
status = readProbedSessionStatus(body);
|
|
233
|
+
if (status === "active" && !response.ok)
|
|
234
|
+
status = null;
|
|
235
|
+
sessionBody = body;
|
|
230
236
|
const identityError = body;
|
|
231
237
|
rejectionCode = identityError?.error?.code ?? identityError?.appSession?.error?.code;
|
|
232
238
|
const recovery = readRecoveryParams(body);
|
|
@@ -289,6 +295,7 @@ export function AppIdentityBridge({ probePath = "/api/auth/identity", appCodePat
|
|
|
289
295
|
});
|
|
290
296
|
switch (action.kind) {
|
|
291
297
|
case "none":
|
|
298
|
+
onSessionRef.current?.(sessionBody);
|
|
292
299
|
appSessionActive();
|
|
293
300
|
wasActive.current = true;
|
|
294
301
|
setUi({ kind: "active" });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hosty-sdk/app",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"description": "Hosty app auth: session state machine, recovery bridge, Core revalidation, and the embedder responder.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"server-only": "^0.0.1"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
|
-
"next": "^16.3.
|
|
94
|
+
"next": "^16.3.8",
|
|
95
95
|
"react": "^19.2.8"
|
|
96
96
|
},
|
|
97
97
|
"peerDependenciesMeta": {
|
|
@@ -103,14 +103,14 @@
|
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
"devDependencies": {
|
|
106
|
-
"@types/node": "^24.19.
|
|
106
|
+
"@types/node": "^24.19.1",
|
|
107
107
|
"@types/react": "^19.3.0",
|
|
108
|
-
"
|
|
109
|
-
"
|
|
108
|
+
"@types/react-dom": "^19.3.0",
|
|
109
|
+
"jsdom": "^30.1.1",
|
|
110
110
|
"react": "^19.3.0",
|
|
111
111
|
"react-dom": "^19.3.0",
|
|
112
|
-
"
|
|
113
|
-
"
|
|
112
|
+
"typescript": "^6",
|
|
113
|
+
"vitest": "^5.0.3"
|
|
114
114
|
},
|
|
115
115
|
"repository": {
|
|
116
116
|
"type": "git",
|