@kolbo/app-sdk
Advanced tools
+1
-1
| { | ||
| "name": "@kolbo/app-sdk", | ||
| "version": "2.1.0", | ||
| "version": "2.1.1", | ||
| "description": "Kolbo App Builder SDK — auth, data, storage and AI for generated apps", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -507,2 +507,26 @@ // Kolbo-native adapter. | ||
| // Pre-flight guard. If the sandbox booted without the API key env var | ||
| // (race between .env write and Vite startup — most common when the | ||
| // session was created before ensureKolboApiKey was wired), every | ||
| // AI call would 401 with an opaque "401" string. Surface a specific | ||
| // error the user can actually act on. | ||
| const assertKey = () => { | ||
| if (!apiKey || apiKey.length < 10) { | ||
| throw new Error( | ||
| 'Kolbo AI key missing — this preview was built before the API key was injected. ' + | ||
| 'Click "Reload preview" in the top bar (or regenerate) to rebuild with the key.' | ||
| ); | ||
| } | ||
| }; | ||
| // Translate 401 into the same actionable message, in case the key was | ||
| // revoked / rotated between sandbox boot and this call. | ||
| const assertAuthed = (res) => { | ||
| if (res.status === 401) { | ||
| throw new Error( | ||
| 'Kolbo AI rejected this preview\'s API key (401). The key may have been revoked ' + | ||
| 'or the sandbox env is stale. Reload the preview or regenerate.' | ||
| ); | ||
| } | ||
| }; | ||
| async function poll(pollUrl, timeoutMs = 300_000) { | ||
@@ -529,5 +553,7 @@ const deadline = Date.now() + timeoutMs; | ||
| async chat({ message, messages, session_id, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const text = message ?? (messages ? messages[messages.length - 1]?.content : '') ?? ''; | ||
| const body = { message: text, session_id, ...(model ? { model } : {}), ...rest }; | ||
| const r = await fetch(`${apiBase}/v1/chat`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(r); | ||
| if (r.status === 402) throw new Error('Out of Kolbo AI credits — top up at kolbo.ai/pricing'); | ||
@@ -540,3 +566,5 @@ if (!r.ok) throw new Error(`Chat failed: ${r.status}`); | ||
| const body = { prompt, aspect_ratio, ...(model ? { model } : {}), ...(visual_dna_id ? { visual_dna_id } : {}), ...(reference_image ? { reference_image } : {}), ...rest }; | ||
| assertKey(); | ||
| const init = await fetch(`${apiBase}/v1/generate/image`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (init.status === 402) throw new Error('Out of Kolbo AI credits'); | ||
@@ -549,4 +577,6 @@ if (!init.ok) throw new Error(`Image init failed: ${init.status}`); | ||
| async generateImageEdit({ prompt, image, mask, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { prompt, image, ...(mask ? { mask } : {}), ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/image-edit`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Image edit failed: ${init.status}`); | ||
@@ -558,4 +588,6 @@ const { pollUrl } = await init.json(); | ||
| async generateVideo({ prompt, duration = 5, aspect_ratio = '16:9', model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { prompt, duration, aspect_ratio, ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/video`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Video init failed: ${init.status}`); | ||
@@ -567,4 +599,6 @@ const { pollUrl } = await init.json(); | ||
| async generateVideoFromImage({ prompt, image, duration = 5, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { prompt, image, duration, ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/video/from-image`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Video-from-image init failed: ${init.status}`); | ||
@@ -576,4 +610,6 @@ const { pollUrl } = await init.json(); | ||
| async generateLipsync({ image, video, audio, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { audio, ...(image ? { image } : {}), ...(video ? { video } : {}), ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/lipsync`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Lipsync init failed: ${init.status}`); | ||
@@ -585,4 +621,6 @@ const { pollUrl } = await init.json(); | ||
| async generateMusic({ prompt, duration, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { prompt, ...(duration ? { duration } : {}), ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/music`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Music init failed: ${init.status}`); | ||
@@ -594,4 +632,6 @@ const { pollUrl } = await init.json(); | ||
| async generateSpeech({ text, voice, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { text, ...(voice ? { voice } : {}), ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/speech`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Speech init failed: ${init.status}`); | ||
@@ -603,4 +643,6 @@ const { pollUrl } = await init.json(); | ||
| async generateSound({ prompt, duration, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { prompt, ...(duration ? { duration } : {}), ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/generate/sound`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Sound init failed: ${init.status}`); | ||
@@ -612,4 +654,6 @@ const { pollUrl } = await init.json(); | ||
| async transcribe({ audio, model, ...rest } = {}) { | ||
| assertKey(); | ||
| const body = { audio, ...(model ? { model } : {}), ...rest }; | ||
| const init = await fetch(`${apiBase}/v1/transcribe`, { method: 'POST', headers: h(), body: JSON.stringify(body) }); | ||
| assertAuthed(init); | ||
| if (!init.ok) throw new Error(`Transcribe init failed: ${init.status}`); | ||
@@ -616,0 +660,0 @@ const { pollUrl } = await init.json(); |
74448
2.14%1313
3.39%