mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 04:07:44 +02:00
[eric] publish: outputs publish fields + publishApi (preflight/publish/unpublish)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
// Fetch helpers for the app-publishing endpoints. The global interceptor in
|
||||
// shared/config.ts attaches the bearer, so we never set it here. The /publish
|
||||
// endpoints return a result object (ok / blocked / error) rather than HTTP errors
|
||||
// for the normal flow, so callers inspect the body.
|
||||
import { API_BASE } from '@/shared/config';
|
||||
|
||||
import { ReviewSummary } from './shareTypes';
|
||||
|
||||
const OUTPUTS_API = `${API_BASE}/outputs`;
|
||||
|
||||
export interface PublishResult {
|
||||
ok: boolean;
|
||||
published_slug?: string | null;
|
||||
published_url?: string | null;
|
||||
/** True when the AST safety net blocked a non-force publish; review carries why. */
|
||||
blocked?: boolean;
|
||||
review?: ReviewSummary | null;
|
||||
error?: string | null;
|
||||
}
|
||||
|
||||
export async function publishPreflight(outputId: string): Promise<ReviewSummary> {
|
||||
const res = await fetch(`${OUTPUTS_API}/publish/preflight`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ output_id: outputId }),
|
||||
});
|
||||
if (!res.ok) throw new Error("We couldn't check this app.");
|
||||
const data = await res.json();
|
||||
return data.review as ReviewSummary;
|
||||
}
|
||||
|
||||
export async function publishApp(
|
||||
outputId: string,
|
||||
opts: { slug?: string; force?: boolean } = {},
|
||||
): Promise<PublishResult> {
|
||||
const res = await fetch(`${OUTPUTS_API}/publish`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ output_id: outputId, slug: opts.slug, force: !!opts.force }),
|
||||
});
|
||||
if (!res.ok) throw new Error('Publishing failed. Please try again.');
|
||||
return (await res.json()) as PublishResult;
|
||||
}
|
||||
|
||||
export async function unpublishApp(outputId: string): Promise<void> {
|
||||
const res = await fetch(`${OUTPUTS_API}/unpublish`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ output_id: outputId }),
|
||||
});
|
||||
if (!res.ok) throw new Error("We couldn't unpublish this app.");
|
||||
}
|
||||
@@ -21,6 +21,17 @@ export interface Output {
|
||||
workspace_id?: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
/** App publishing to {slug}.openswarm.dev. Server-managed; mirrored here after a publish/unpublish. */
|
||||
published_slug?: string | null;
|
||||
published_url?: string | null;
|
||||
publish_status?: 'publishing' | 'published' | 'error' | null;
|
||||
}
|
||||
|
||||
export interface PublishStatePatch {
|
||||
id: string;
|
||||
published_slug?: string | null;
|
||||
published_url?: string | null;
|
||||
publish_status?: Output['publish_status'];
|
||||
}
|
||||
|
||||
export function getFrontendCode(output: Output): string {
|
||||
@@ -133,6 +144,14 @@ const outputsSlice = createSlice({
|
||||
const existing = state.items[incoming.id];
|
||||
state.items[incoming.id] = existing ? { ...existing, ...incoming } : incoming;
|
||||
},
|
||||
/** Reflect a publish/unpublish result onto an existing Output without a refetch. */
|
||||
setOutputPublishState(state, action: { payload: PublishStatePatch; type: string }) {
|
||||
const o = state.items[action.payload.id];
|
||||
if (!o) return;
|
||||
if ('published_slug' in action.payload) o.published_slug = action.payload.published_slug ?? null;
|
||||
if ('published_url' in action.payload) o.published_url = action.payload.published_url ?? null;
|
||||
if ('publish_status' in action.payload) o.publish_status = action.payload.publish_status ?? null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
@@ -150,5 +169,5 @@ const outputsSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { upsertOutput } = outputsSlice.actions;
|
||||
export const { upsertOutput, setOutputPublishState } = outputsSlice.actions;
|
||||
export default outputsSlice.reducer;
|
||||
|
||||
Reference in New Issue
Block a user