Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions examples/white-label-minimal/components/useBuilderSocket.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { useCallback, useEffect, useState } from "react";
import { getApp } from "../lib/chat/builder-api";
import { ApiError, getApp } from "../lib/chat/builder-api";
import { watchApp } from "../lib/chat/live-updates";
import type { App, Message } from "../lib/types";

Expand All @@ -22,11 +22,12 @@ export function useBuilderSocket(appId: string | null) {
let stopped = false;
let stop: (() => void) | undefined;
const readApp = () => getApp(appId).then((next) => { if (!stopped) setApp(next); });
const fail = () => {
const fail = (error?: unknown) => {
if (stopped) return;
stopped = true;
stop?.();
setError("Live updates paused. Reconnect to continue.");
// Our server explains configuration problems; socket errors get the generic message.
setError(error instanceof ApiError ? error.message : "Live updates paused. Reconnect to continue.");
setLoaded(key);
};

Expand Down
10 changes: 7 additions & 3 deletions examples/white-label-minimal/lib/base44/socket-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ export async function openSocketSession(appId: string) {
body: JSON.stringify({ app_ids: [appId] }),
cache: "no-store",
});
if (response.status === 401 || response.status === 403)
throw new Base44Error("Live updates need a workspace key with the apps:watch scope.", 503);
if (!response.ok) throw new Base44Error(`Base44 returned ${response.status} opening live updates.`);
if (!response.ok) {
// Base44 says why: a key without apps:watch, a workspace without white-label
// sockets, or an app the key isn't granted.
const reason = (await response.json().catch(() => null))?.error?.message;
throw new Base44Error(`Live updates unavailable: ${reason ?? `Base44 returned ${response.status}`}.`,
response.status === 401 || response.status === 403 ? 503 : 502);
}
const { socket_url, session_token } = await response.json();
return { serverUrl: new URL(socket_url).origin, sessionToken: String(session_token) };
}
4 changes: 2 additions & 2 deletions examples/white-label-minimal/tests/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ test('the live-updates session opens with the workspace key only after sign-in a
assert.equal(calls.length, 1);
});

test('a workspace key without the apps:watch scope is reported as configuration', async () => {
setup({ error: { code: 'scope_required' } }, 403);
test('Base44 rejecting the key is reported as configuration, with its reason', async () => {
setup({ error: { code: 'scope_required', message: 'The key needs the apps:watch scope' } }, 403);
const response = await request({ action: 'openBuilderSession', appId: 'app_1' });
assert.equal(response.status, 503);
assert.match((await response.json()).error, /apps:watch/);
Expand Down