@unoverse-platform/studio 0.1.42 → 0.1.44
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/package.json +1 -1
- package/screens/TemplatesView.tsx +28 -13
- package/src/host.ts +18 -0
package/package.json
CHANGED
|
@@ -26,7 +26,7 @@ import { ComponentStore } from "@unoverse/sdk";
|
|
|
26
26
|
import { StreamedUnoverseTemplate, useUnoverseConnection, computeAppWidth, resolveActiveLayout, visible, type ResolvedTheme, type UseVoiceServiceConfig } from "@unoverse/sdk";
|
|
27
27
|
import { NativeAppHost } from "./NativeAppHost";
|
|
28
28
|
import { inArrangement, viewOfSlice } from "./states";
|
|
29
|
-
import { client, authedFetch, hasAuth, UNOVERSE_BASE } from "studio-host";
|
|
29
|
+
import { client, authedFetch, hasAuth, UNOVERSE_BASE, liveUniverseUrl } from "studio-host";
|
|
30
30
|
|
|
31
31
|
// Per-APP test conversation: each app chats in its own conversation id, so testing
|
|
32
32
|
// one client's app never inherits another's agent history/memory (the "BPP answers
|
|
@@ -45,15 +45,23 @@ const chatIdFor = (app: string) => `demo-${app.toLowerCase()}-${SESSION_NONCE}`;
|
|
|
45
45
|
// :4105 — since the workbench retired, uWS binds the public port DIRECTLY in dev, same
|
|
46
46
|
// as prod (the retired workbench was :4205, the retired gateway :4100). Prod uses the
|
|
47
47
|
// page origin.
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// THE LIVE SERVER IS NOT CONFIGURED HERE. The universe Studio is signed into (the
|
|
49
|
+
// header connection, via studio-host's liveUniverseUrl) IS the live environment, so
|
|
50
|
+
// being signed into one universe while previewing against another is impossible by
|
|
51
|
+
// construction. Only with NO universe connected does the preview fall back to the
|
|
52
|
+
// local dev platform. The old hardcoded default (`localhost:4105` + a sample
|
|
53
|
+
// workflow id, persisted under "unoverse.workbench.conn") is retired: it kept green
|
|
54
|
+
// "Connected" sessions against stale localhost stacks while the header showed a
|
|
55
|
+
// production universe. Workflow + trigger come from the app's manifest binding; the
|
|
56
|
+
// only thing persisted now is a hand-pasted JWT for auth-off dev servers.
|
|
57
|
+
const LOCAL_DEV_SERVER = "localhost:4105";
|
|
58
|
+
const CONN_DEFAULTS = { token: "" };
|
|
59
|
+
const CONN_KEY = "unoverse.workbench.conn.v2";
|
|
50
60
|
|
|
51
61
|
function loadConn(): typeof CONN_DEFAULTS {
|
|
52
62
|
try {
|
|
53
63
|
const saved = JSON.parse(localStorage.getItem(CONN_KEY) ?? "{}");
|
|
54
|
-
|
|
55
|
-
if (saved.server === "localhost:4100" || saved.server === "localhost:4205") delete saved.server;
|
|
56
|
-
return { ...CONN_DEFAULTS, ...saved };
|
|
64
|
+
return { token: typeof saved.token === "string" ? saved.token : "" };
|
|
57
65
|
} catch {
|
|
58
66
|
return { ...CONN_DEFAULTS };
|
|
59
67
|
}
|
|
@@ -238,23 +246,30 @@ export function TemplatesView({
|
|
|
238
246
|
const authToken = auth?.user?.access_token;
|
|
239
247
|
const token = authToken || connCfg.token;
|
|
240
248
|
|
|
249
|
+
// The live server: the signed-in universe, else the local dev platform (see the
|
|
250
|
+
// CONN_DEFAULTS note). A universe URL is already an https origin; the bare local
|
|
251
|
+
// fallback gets http.
|
|
252
|
+
const universeUrl = liveUniverseUrl();
|
|
253
|
+
const liveServer = universeUrl ?? LOCAL_DEV_SERVER;
|
|
254
|
+
const liveBase = liveServer.includes("://") ? liveServer : `http://${liveServer}`;
|
|
255
|
+
|
|
241
256
|
const config = useMemo(
|
|
242
257
|
() => ({
|
|
243
|
-
apiUrl:
|
|
258
|
+
apiUrl: liveBase,
|
|
244
259
|
// Component stream rides the Unoverse `/stream` MCP endpoint (§5b). In the canvas
|
|
245
260
|
// the path that reaches Unoverse is UNOVERSE_BASE (/unoverse-mcp proxy in dev, the
|
|
246
261
|
// explicit gated URL in prod) — always absolute there. In local Studio UNOVERSE_BASE
|
|
247
262
|
// is "" (a folder, not a universe; its origin serves no /stream), so the stream goes
|
|
248
263
|
// to the CONNECTED universe — same base the apiUrl above uses. An empty string here
|
|
249
264
|
// threw `Invalid URL` inside the SDK and killed the stream silently.
|
|
250
|
-
streamUrl: UNOVERSE_BASE ||
|
|
265
|
+
streamUrl: UNOVERSE_BASE || liveBase,
|
|
251
266
|
// A real JWT makes the workbench a proper authenticated channel: it rides the
|
|
252
267
|
// MCP stream's `Authorization` header and the REST `Authorization` header, so the
|
|
253
268
|
// workflow gets full user context (incl. the email claim → CRM join). See
|
|
254
269
|
// docs/AUTH_TOKEN_FLOW.md. Blank → no token (server must run with DISABLE_AUTH=true).
|
|
255
270
|
getAccessToken: token ? async () => token : undefined,
|
|
256
271
|
}),
|
|
257
|
-
[
|
|
272
|
+
[liveBase, token],
|
|
258
273
|
);
|
|
259
274
|
// The APP decides which workflow runs: the selected template's manifest binding
|
|
260
275
|
// (workflow + trigger) drives the connection. No manual entry — MCP decides.
|
|
@@ -395,7 +410,7 @@ export function TemplatesView({
|
|
|
395
410
|
// START_CALL REST triggers the workflow on the gateway. The audio WS lane is
|
|
396
411
|
// derived by the SDK from the client's server origin (see the renderer) — the
|
|
397
412
|
// host passes NO wsUrl, so every host (incl. srcdoc iframes) is identical.
|
|
398
|
-
apiUrl:
|
|
413
|
+
apiUrl: liveBase,
|
|
399
414
|
getAccessToken: token ? async () => token : undefined,
|
|
400
415
|
session: {
|
|
401
416
|
userId: session.userId,
|
|
@@ -409,7 +424,7 @@ export function TemplatesView({
|
|
|
409
424
|
store,
|
|
410
425
|
}
|
|
411
426
|
: undefined,
|
|
412
|
-
[isVoice,
|
|
427
|
+
[isVoice, liveBase, token, session, store],
|
|
413
428
|
);
|
|
414
429
|
|
|
415
430
|
// "Load the app → it calls its workflow" — but ONLY for apps with autoTrigger (Mode B).
|
|
@@ -808,7 +823,7 @@ export function TemplatesView({
|
|
|
808
823
|
come from the selected app's manifest binding (no manual entry). */}
|
|
809
824
|
{(
|
|
810
825
|
[
|
|
811
|
-
{ label: "Server", value:
|
|
826
|
+
{ label: "Server", value: liveServer, note: universeUrl ? "signed-in universe" : "local dev (no universe connected)" },
|
|
812
827
|
{ label: "Workflow", value: binding?.workflow ?? "— no app binding", note: "from app" },
|
|
813
828
|
{ label: "Trigger node", value: binding?.trigger ?? "—", note: "from app" },
|
|
814
829
|
]
|
|
@@ -1017,7 +1032,7 @@ export function TemplatesView({
|
|
|
1017
1032
|
/* NATIVE: the universe serves the app; Studio just hosts it. Same
|
|
1018
1033
|
ui:// shell ChatGPT loads, same boot contract, its own connections. */
|
|
1019
1034
|
<NativeAppHost
|
|
1020
|
-
server={UNOVERSE_BASE ||
|
|
1035
|
+
server={UNOVERSE_BASE || liveBase}
|
|
1021
1036
|
token={token}
|
|
1022
1037
|
templateId={`${selectedDef?.org ? `${selectedDef.org}/` : ""}${selected ?? ""}`}
|
|
1023
1038
|
userId={session.userId}
|
package/src/host.ts
CHANGED
|
@@ -21,6 +21,24 @@ export const UNOVERSE_BASE = "";
|
|
|
21
21
|
/** No login offline. Kept so the shared screens can ask without branching on host. */
|
|
22
22
|
export const hasAuth = false;
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The universe Studio is signed into (the header connection), or null when offline.
|
|
26
|
+
* THE LIVE PREVIEW'S SERVER. One source of truth: the same selection App.tsx keeps
|
|
27
|
+
* (`studio:universe` is its usePersistentState pointer into the saved universe list),
|
|
28
|
+
* so it is impossible to be signed into one universe and silently previewing against
|
|
29
|
+
* another. The shared screens fall back to the local dev platform only when no
|
|
30
|
+
* universe is connected.
|
|
31
|
+
*/
|
|
32
|
+
export function liveUniverseUrl(): string | null {
|
|
33
|
+
try {
|
|
34
|
+
const raw = localStorage.getItem("studio:universe");
|
|
35
|
+
const url = raw === null ? null : (JSON.parse(raw) as string | null);
|
|
36
|
+
return url || null;
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
24
42
|
/**
|
|
25
43
|
* SOURCE ACCESS: this host serves the files behind a definition, so the screens may show
|
|
26
44
|
* the source view. Local Studio reads the developer's own folder, so it can.
|