mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-21 08:02:18 +00:00
Move Foundry HTTP APIs out of /api/rivet
This commit is contained in:
parent
436eb4a3a3
commit
58b19c2253
6 changed files with 46 additions and 34 deletions
|
|
@ -36,9 +36,9 @@ That recipe sets `NODE_ENV=development`, which enables the dotenv loader.
|
||||||
These values can be safely defaulted for local development:
|
These values can be safely defaulted for local development:
|
||||||
|
|
||||||
- `APP_URL=http://localhost:4173`
|
- `APP_URL=http://localhost:4173`
|
||||||
- `BETTER_AUTH_URL=http://localhost:4173`
|
- `BETTER_AUTH_URL=http://localhost:7741`
|
||||||
- `BETTER_AUTH_SECRET=sandbox-agent-foundry-development-only-change-me`
|
- `BETTER_AUTH_SECRET=sandbox-agent-foundry-development-only-change-me`
|
||||||
- `GITHUB_REDIRECT_URI=http://localhost:4173/api/rivet/app/auth/github/callback`
|
- `GITHUB_REDIRECT_URI=http://localhost:7741/api/auth/github/callback`
|
||||||
|
|
||||||
These should be treated as development-only values.
|
These should be treated as development-only values.
|
||||||
|
|
||||||
|
|
@ -90,7 +90,7 @@ Recommended GitHub App permissions:
|
||||||
- Repository `Checks: Read`
|
- Repository `Checks: Read`
|
||||||
- Repository `Commit statuses: Read`
|
- Repository `Commit statuses: Read`
|
||||||
|
|
||||||
Set the webhook URL to `https://<your-backend-host>/api/rivet/app/webhooks/github` and generate a webhook secret. Store the secret as `GITHUB_WEBHOOK_SECRET`.
|
Set the webhook URL to `https://<your-backend-host>/api/webhooks/github` and generate a webhook secret. Store the secret as `GITHUB_WEBHOOK_SECRET`.
|
||||||
|
|
||||||
Recommended webhook subscriptions:
|
Recommended webhook subscriptions:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -832,7 +832,7 @@ export const workspaceAppActions = {
|
||||||
customerId,
|
customerId,
|
||||||
customerEmail: session.currentUserEmail,
|
customerEmail: session.currentUserEmail,
|
||||||
planId: input.planId,
|
planId: input.planId,
|
||||||
successUrl: `${appShell.appUrl}/api/rivet/app/billing/checkout/complete?organizationId=${encodeURIComponent(
|
successUrl: `${appShell.apiUrl}/api/billing/checkout/complete?organizationId=${encodeURIComponent(
|
||||||
input.organizationId,
|
input.organizationId,
|
||||||
)}&foundrySession=${encodeURIComponent(input.sessionId)}&session_id={CHECKOUT_SESSION_ID}`,
|
)}&foundrySession=${encodeURIComponent(input.sessionId)}&session_id={CHECKOUT_SESSION_ID}`,
|
||||||
cancelUrl: `${appShell.appUrl}/organizations/${input.organizationId}/billing?foundrySession=${encodeURIComponent(input.sessionId)}`,
|
cancelUrl: `${appShell.appUrl}/organizations/${input.organizationId}/billing?foundrySession=${encodeURIComponent(input.sessionId)}`,
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
endpoint: `http://127.0.0.1:${config.backend.port}/api/rivet`,
|
endpoint: `http://127.0.0.1:${config.backend.port}/api/rivet`,
|
||||||
}) as any;
|
}) as any;
|
||||||
|
|
||||||
// Wrap RivetKit and app routes in a single Hono app mounted at /api/rivet.
|
// Serve custom Foundry HTTP APIs alongside the RivetKit registry.
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
const allowHeaders = [
|
const allowHeaders = [
|
||||||
"Content-Type",
|
"Content-Type",
|
||||||
|
|
@ -93,7 +93,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
];
|
];
|
||||||
const exposeHeaders = ["Content-Type", "x-foundry-session", "x-rivet-ray-id"];
|
const exposeHeaders = ["Content-Type", "x-foundry-session", "x-rivet-ray-id"];
|
||||||
app.use(
|
app.use(
|
||||||
"/api/rivet/*",
|
"/api/*",
|
||||||
cors({
|
cors({
|
||||||
origin: (origin) => origin ?? "*",
|
origin: (origin) => origin ?? "*",
|
||||||
credentials: true,
|
credentials: true,
|
||||||
|
|
@ -103,7 +103,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
"/api/rivet",
|
"/api",
|
||||||
cors({
|
cors({
|
||||||
origin: (origin) => origin ?? "*",
|
origin: (origin) => origin ?? "*",
|
||||||
credentials: true,
|
credentials: true,
|
||||||
|
|
@ -132,12 +132,12 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
return sessionId;
|
return sessionId;
|
||||||
};
|
};
|
||||||
|
|
||||||
app.get("/api/rivet/app/snapshot", async (c) => {
|
app.get("/api/app/snapshot", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(await appWorkspaceAction(async (workspace) => await workspace.getAppSnapshot({ sessionId })));
|
return c.json(await appWorkspaceAction(async (workspace) => await workspace.getAppSnapshot({ sessionId })));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/rivet/app/auth/github/start", async (c) => {
|
app.get("/api/auth/github/start", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
const result = await appWorkspaceAction(async (workspace) => await workspace.startAppGithubAuth({ sessionId }));
|
const result = await appWorkspaceAction(async (workspace) => await workspace.startAppGithubAuth({ sessionId }));
|
||||||
return Response.redirect(result.url, 302);
|
return Response.redirect(result.url, 302);
|
||||||
|
|
@ -154,20 +154,20 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
return Response.redirect(result.redirectTo, 302);
|
return Response.redirect(result.redirectTo, 302);
|
||||||
};
|
};
|
||||||
|
|
||||||
app.get("/api/rivet/app/auth/github/callback", handleGithubAuthCallback);
|
app.get("/api/auth/github/callback", handleGithubAuthCallback);
|
||||||
app.get("/api/auth/callback/github", handleGithubAuthCallback);
|
app.get("/api/auth/callback/github", handleGithubAuthCallback);
|
||||||
|
|
||||||
app.post("/api/rivet/app/sign-out", async (c) => {
|
app.post("/api/app/sign-out", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(await appWorkspaceAction(async (workspace) => await workspace.signOutApp({ sessionId })));
|
return c.json(await appWorkspaceAction(async (workspace) => await workspace.signOutApp({ sessionId })));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/onboarding/starter-repo/skip", async (c) => {
|
app.post("/api/app/onboarding/starter-repo/skip", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(await appWorkspaceAction(async (workspace) => await workspace.skipAppStarterRepo({ sessionId })));
|
return c.json(await appWorkspaceAction(async (workspace) => await workspace.skipAppStarterRepo({ sessionId })));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/starter-repo/star", async (c) => {
|
app.post("/api/app/organizations/:organizationId/starter-repo/star", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await appWorkspaceAction(
|
await appWorkspaceAction(
|
||||||
|
|
@ -180,7 +180,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/select", async (c) => {
|
app.post("/api/app/organizations/:organizationId/select", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await appWorkspaceAction(
|
await appWorkspaceAction(
|
||||||
|
|
@ -193,7 +193,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.patch("/api/rivet/app/organizations/:organizationId/profile", async (c) => {
|
app.patch("/api/app/organizations/:organizationId/profile", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
const body = await c.req.json();
|
const body = await c.req.json();
|
||||||
return c.json(
|
return c.json(
|
||||||
|
|
@ -210,7 +210,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/import", async (c) => {
|
app.post("/api/app/organizations/:organizationId/import", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await appWorkspaceAction(
|
await appWorkspaceAction(
|
||||||
|
|
@ -223,7 +223,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/reconnect", async (c) => {
|
app.post("/api/app/organizations/:organizationId/reconnect", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await appWorkspaceAction(
|
await appWorkspaceAction(
|
||||||
|
|
@ -236,7 +236,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/billing/checkout", async (c) => {
|
app.post("/api/app/organizations/:organizationId/billing/checkout", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
const body = await c.req.json().catch(() => ({}));
|
const body = await c.req.json().catch(() => ({}));
|
||||||
const planId = body?.planId === "free" || body?.planId === "team" ? (body.planId as FoundryBillingPlanId) : "team";
|
const planId = body?.planId === "free" || body?.planId === "team" ? (body.planId as FoundryBillingPlanId) : "team";
|
||||||
|
|
@ -249,7 +249,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/rivet/app/billing/checkout/complete", async (c) => {
|
app.get("/api/billing/checkout/complete", async (c) => {
|
||||||
const organizationId = c.req.query("organizationId");
|
const organizationId = c.req.query("organizationId");
|
||||||
const sessionId = c.req.query("foundrySession");
|
const sessionId = c.req.query("foundrySession");
|
||||||
const checkoutSessionId = c.req.query("session_id");
|
const checkoutSessionId = c.req.query("session_id");
|
||||||
|
|
@ -264,7 +264,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
return Response.redirect(result.redirectTo, 302);
|
return Response.redirect(result.redirectTo, 302);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/billing/portal", async (c) => {
|
app.post("/api/app/organizations/:organizationId/billing/portal", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await (await appWorkspace()).createAppBillingPortalSession({
|
await (await appWorkspace()).createAppBillingPortalSession({
|
||||||
|
|
@ -274,7 +274,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/billing/cancel", async (c) => {
|
app.post("/api/app/organizations/:organizationId/billing/cancel", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await (await appWorkspace()).cancelAppScheduledRenewal({
|
await (await appWorkspace()).cancelAppScheduledRenewal({
|
||||||
|
|
@ -284,7 +284,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/organizations/:organizationId/billing/resume", async (c) => {
|
app.post("/api/app/organizations/:organizationId/billing/resume", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await (await appWorkspace()).resumeAppSubscription({
|
await (await appWorkspace()).resumeAppSubscription({
|
||||||
|
|
@ -294,7 +294,7 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/api/rivet/app/workspaces/:workspaceId/seat-usage", async (c) => {
|
app.post("/api/app/workspaces/:workspaceId/seat-usage", async (c) => {
|
||||||
const sessionId = await resolveSessionId(c);
|
const sessionId = await resolveSessionId(c);
|
||||||
return c.json(
|
return c.json(
|
||||||
await (await appWorkspace()).recordAppSeatUsage({
|
await (await appWorkspace()).recordAppSeatUsage({
|
||||||
|
|
@ -313,10 +313,9 @@ export async function startBackend(options: BackendStartOptions = {}): Promise<v
|
||||||
return c.json({ ok: true });
|
return c.json({ ok: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
app.post("/api/rivet/app/webhooks/stripe", handleStripeWebhook);
|
app.post("/api/webhooks/stripe", handleStripeWebhook);
|
||||||
app.post("/api/rivet/app/stripe/webhook", handleStripeWebhook);
|
|
||||||
|
|
||||||
app.post("/api/rivet/app/webhooks/github", async (c) => {
|
app.post("/api/webhooks/github", async (c) => {
|
||||||
const payload = await c.req.text();
|
const payload = await c.req.text();
|
||||||
await (await appWorkspace()).handleAppGithubWebhook({
|
await (await appWorkspace()).handleAppGithubWebhook({
|
||||||
payload,
|
payload,
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,14 @@ export type AppShellStripeClient = Pick<
|
||||||
|
|
||||||
export interface AppShellServices {
|
export interface AppShellServices {
|
||||||
appUrl: string;
|
appUrl: string;
|
||||||
|
apiUrl: string;
|
||||||
github: AppShellGithubClient;
|
github: AppShellGithubClient;
|
||||||
stripe: AppShellStripeClient;
|
stripe: AppShellStripeClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateAppShellServicesOptions {
|
export interface CreateAppShellServicesOptions {
|
||||||
appUrl?: string;
|
appUrl?: string;
|
||||||
|
apiUrl?: string;
|
||||||
github?: AppShellGithubClient;
|
github?: AppShellGithubClient;
|
||||||
stripe?: AppShellStripeClient;
|
stripe?: AppShellStripeClient;
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +62,7 @@ export interface CreateAppShellServicesOptions {
|
||||||
export function createDefaultAppShellServices(options: CreateAppShellServicesOptions = {}): AppShellServices {
|
export function createDefaultAppShellServices(options: CreateAppShellServicesOptions = {}): AppShellServices {
|
||||||
return {
|
return {
|
||||||
appUrl: (options.appUrl ?? process.env.APP_URL ?? "http://localhost:4173").replace(/\/$/, ""),
|
appUrl: (options.appUrl ?? process.env.APP_URL ?? "http://localhost:4173").replace(/\/$/, ""),
|
||||||
|
apiUrl: (options.apiUrl ?? process.env.BETTER_AUTH_URL ?? process.env.APP_URL ?? "http://localhost:7741").replace(/\/$/, ""),
|
||||||
github: options.github ?? new GitHubAppClient(),
|
github: options.github ?? new GitHubAppClient(),
|
||||||
stripe: options.stripe ?? new StripeAppClient(),
|
stripe: options.stripe ?? new StripeAppClient(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,14 @@ export function createBackendClientFromConfig(config: AppConfig): BackendClient
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripTrailingSlash(value: string): string {
|
||||||
|
return value.replace(/\/$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveAppApiEndpoint(endpoint: string): string {
|
||||||
|
return stripTrailingSlash(endpoint).replace(/\/api\/rivet$/, "/api");
|
||||||
|
}
|
||||||
|
|
||||||
function isLoopbackHost(hostname: string): boolean {
|
function isLoopbackHost(hostname: string): boolean {
|
||||||
const h = hostname.toLowerCase();
|
const h = hostname.toLowerCase();
|
||||||
return h === "127.0.0.1" || h === "localhost" || h === "0.0.0.0" || h === "::1";
|
return h === "127.0.0.1" || h === "localhost" || h === "0.0.0.0" || h === "::1";
|
||||||
|
|
@ -386,6 +394,8 @@ export function createBackendClient(options: BackendClientOptions): BackendClien
|
||||||
return createMockBackendClient(options.defaultWorkspaceId);
|
return createMockBackendClient(options.defaultWorkspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rivetApiEndpoint = stripTrailingSlash(options.endpoint);
|
||||||
|
const appApiEndpoint = deriveAppApiEndpoint(options.endpoint);
|
||||||
let clientPromise: Promise<RivetClient> | null = null;
|
let clientPromise: Promise<RivetClient> | null = null;
|
||||||
let appSessionId = typeof window !== "undefined" ? window.localStorage.getItem("sandbox-agent-foundry:remote-app-session") : null;
|
let appSessionId = typeof window !== "undefined" ? window.localStorage.getItem("sandbox-agent-foundry:remote-app-session") : null;
|
||||||
const workbenchSubscriptions = new Map<
|
const workbenchSubscriptions = new Map<
|
||||||
|
|
@ -434,7 +444,7 @@ export function createBackendClient(options: BackendClientOptions): BackendClien
|
||||||
headers.set("Content-Type", "application/json");
|
headers.set("Content-Type", "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch(`${options.endpoint.replace(/\/$/, "")}${path}`, {
|
const res = await fetch(`${appApiEndpoint}${path}`, {
|
||||||
...init,
|
...init,
|
||||||
headers,
|
headers,
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
|
|
@ -465,22 +475,22 @@ export function createBackendClient(options: BackendClientOptions): BackendClien
|
||||||
// Use the serverless /metadata endpoint to discover the manager endpoint.
|
// Use the serverless /metadata endpoint to discover the manager endpoint.
|
||||||
// If the server reports a loopback clientEndpoint (127.0.0.1), rewrite to the same host
|
// If the server reports a loopback clientEndpoint (127.0.0.1), rewrite to the same host
|
||||||
// as the configured endpoint so remote browsers/clients can connect.
|
// as the configured endpoint so remote browsers/clients can connect.
|
||||||
const configured = new URL(options.endpoint);
|
const configured = new URL(rivetApiEndpoint);
|
||||||
const configuredOrigin = `${configured.protocol}//${configured.host}`;
|
const configuredOrigin = `${configured.protocol}//${configured.host}`;
|
||||||
|
|
||||||
const initialNamespace = undefined;
|
const initialNamespace = undefined;
|
||||||
const metadata = await fetchMetadataWithRetry(options.endpoint, initialNamespace, {
|
const metadata = await fetchMetadataWithRetry(rivetApiEndpoint, initialNamespace, {
|
||||||
timeoutMs: 30_000,
|
timeoutMs: 30_000,
|
||||||
requestTimeoutMs: 8_000,
|
requestTimeoutMs: 8_000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Candidate endpoint: manager endpoint if provided, otherwise stick to the configured endpoint.
|
// Candidate endpoint: manager endpoint if provided, otherwise stick to the configured endpoint.
|
||||||
const candidateEndpoint = metadata.clientEndpoint ? rewriteLoopbackClientEndpoint(metadata.clientEndpoint, configuredOrigin) : options.endpoint;
|
const candidateEndpoint = metadata.clientEndpoint ? rewriteLoopbackClientEndpoint(metadata.clientEndpoint, configuredOrigin) : rivetApiEndpoint;
|
||||||
|
|
||||||
// If the manager port isn't reachable from this client (common behind reverse proxies),
|
// If the manager port isn't reachable from this client (common behind reverse proxies),
|
||||||
// fall back to the configured serverless endpoint to avoid hanging requests.
|
// fall back to the configured serverless endpoint to avoid hanging requests.
|
||||||
const shouldUseCandidate = metadata.clientEndpoint ? await probeMetadataEndpoint(candidateEndpoint, metadata.clientNamespace, 1_500) : true;
|
const shouldUseCandidate = metadata.clientEndpoint ? await probeMetadataEndpoint(candidateEndpoint, metadata.clientNamespace, 1_500) : true;
|
||||||
const resolvedEndpoint = shouldUseCandidate ? candidateEndpoint : options.endpoint;
|
const resolvedEndpoint = shouldUseCandidate ? candidateEndpoint : rivetApiEndpoint;
|
||||||
|
|
||||||
return createClient({
|
return createClient({
|
||||||
endpoint: resolvedEndpoint,
|
endpoint: resolvedEndpoint,
|
||||||
|
|
@ -676,10 +686,10 @@ export function createBackendClient(options: BackendClientOptions): BackendClien
|
||||||
|
|
||||||
async signInWithGithub(): Promise<void> {
|
async signInWithGithub(): Promise<void> {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
window.location.assign(`${options.endpoint.replace(/\/$/, "")}/app/auth/github/start`);
|
window.location.assign(`${appApiEndpoint}/auth/github/start`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await redirectTo("/app/auth/github/start");
|
await redirectTo("/auth/github/start");
|
||||||
},
|
},
|
||||||
|
|
||||||
async signOutApp(): Promise<FoundryAppSnapshot> {
|
async signOutApp(): Promise<FoundryAppSnapshot> {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
port: 4173,
|
port: 4173,
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api/rivet": {
|
"/api": {
|
||||||
target: backendProxyTarget,
|
target: backendProxyTarget,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue