Skip to main content

resonate-lovable-usage-prompt-typescript

Specialized guidance for building Resonate applications within Lovable.dev, which is Node.js/React/TypeScript. Use when working with Lovable's AI-assisted development environment to scaffold, iterate, and deploy Resonate workflows in the TypeScript SDK.

Quellinformationen

Repository
resonatehq/resonate-skills
Letzte Quellaktivität
21. August 2026 um 17:03
Erkannte Sprache von SKILL.md
Englisch
Sterne
6
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
resonate-lovable-usage-prompt-typescript
description
Specialized guidance for building Resonate applications within Lovable.dev, which is Node.js/React/TypeScript. Use when working with Lovable's AI-assisted development environment to scaffold, iterate, and deploy Resonate workflows in the TypeScript SDK.
license
Apache-2.0
# Resonate Lovable Usage Prompt — TypeScript > **SDK version:** This skill reflects `@resonatehq/sdk` v0.11.4 (current on npm). ## Overview This skill provides specialized guidance for building Resonate durable execution applications within [Lovable.dev](https://lovable.dev), an AI-assisted full-stack development environment. Lovable enables rapid prototyping and deployment of React + Node.js applications with built-in hosting. ## Core Philosophy: Resonate IS the Database **Critical insight:** For workflow state, Resonate is your single source of truth. You don't need a separate database to track workflow status, pending approvals, or execution state. ``` Traditional approach (unnecessary complexity): Create workflow → Store in DB → Poll DB for status → Sync with Resonate Resonate approach (simple): Create workflow → Query Resonate directly → Done ``` **Why this matters:** - Query promises by ID prefix to list pending items - Resolve promises to complete workflows - No DB sync logic, no stale state, no race conditions **When you DO need a database:** - Business data that outlives workflows (user profiles, orders, products) - Analytics and reporting - Data that needs relational queries **When you DON'T need a database:** - Workflow status (use Resonate promises) - Pending approvals (query by prefix) - Execution state (Resonate tracks this) ## Lovable Environment Constraints ### What Lovable Provides - React frontend (Vite + TypeScript) - Node.js backend (Express + TypeScript) - PostgreSQL database (Supabase) - Built-in deployment pipeline - AI-assisted code generation - Git integration ### Lovable Limitations for Resonate **Lovable does NOT provide:** - Long-running backend processes - WebSocket servers - Background workers - Cron jobs or schedulers **Implication:** You cannot run a persistent Resonate worker inside Lovable's backend. ## Recommended Architecture for Lovable + Resonate ### Architecture A: External Resonate Server (Recommended) **Lovable backend acts as HTTP client to external Resonate:** ``` Lovable Frontend (React) ↓ Lovable Backend (Express) [HTTP Client Only] ↓ External Resonate Server (Cloud Run, Fly.io, Railway) ↓ Resonate Workers (separate deployment) ``` **Lovable backend code:** ```typescript // server/routes/workflows.ts import { Resonate } from "@resonatehq/sdk"; import express from "express"; const router = express.Router(); // Connect to external Resonate server const resonate = new Resonate({ url: process.env.RESONATE_URL, // e.g., https://resonate.example.com token: process.env.RESONATE_TOKEN, // JWT token for auth (if server requires it) group: "lovable-client" }); // Start a workflow (non-blocking) router.post("/api/workflows/start", async (req, res) => { const { workflowType, input } = req.body; const workflowId = `workflow-${Date.now()}`; await resonate.beginRpc( workflowId, workflowType, input, resonate.options({ target: "poll://any@workers" // Routes to external workers }) ); res.json({ workflowId, status: "started", pollUrl: `/api/workflows/${workflowId}/status` }); }); // Check workflow status router.get("/api/workflows/:id/status", async (req, res) => { try { const handle = await resonate.get(req.params.id); const result = await handle.result(); res.json({ workflowId: req.params.id, status: "completed", result }); } catch (error) { res.json({ workflowId: req.params.id, status: "pending" }); } }); export default router; ``` **External workers (deployed separately):** ```typescript // workers/index.ts (deployed to Cloud Run/Fly.io) import { Resonate, type Context } from "@resonatehq/sdk"; const resonate = new Resonate({ url: process.env.RESONATE_URL, token: process.env.RESONATE_TOKEN, // JWT token for auth group: "workers" }); function* processOrder(ctx: Context, input: any) { // Durable workflow logic const validated = yield* ctx.run(validateOrder, input); const payment = yield* ctx.run(processPayment, validated); const shipment = yield* ctx.run(createShipment, payment); return { status: "success", shipment }; } resonate.register("processOrder", processOrder); // Keep worker alive process.on("SIGTERM", () => process.exit(0)); ``` ### Architecture B: Supabase Edge Functions (Alternative) If using Lovable with Supabase Edge Functions, see the **resonate-supabase-deployments-typescript** skill for complete Deno-specific patterns including: - `@resonatehq/supabase` shim usage - `start/` and `probe/` endpoint patterns - Deno.serve() request handling **Limitation:** Supabase Edge Functions have 30-second timeout, so workflows must complete quickly or use async patterns. ## HTTP API vs SDK: When to Use Which This is the most important decision when building with Lovable + Resonate. ### Use the SDK (Programming Model) When: | Action | SDK Method | Example | |--------|------------|---------| | Start a workflow | `resonate.run()`, `resonate.rpc()`, `beginRun()`, `beginRpc()` | Starting an order processing workflow | | Execute durable code | Generator functions with `ctx.run()`, `ctx.sleep()` | The workflow logic itself | | Register workflow handlers | `resonate.register()` | Setting up workers | **Key insight:** The SDK is for **executing workflows**. You need a process that can run the workflow code. ### Use the HTTP API Directly When: | Action | HTTP Method | Example | |--------|-------------|---------| | List promises by prefix | `GET /promises?id=prefix-*` | Showing all pending approvals in UI | | Get promise state | `GET /promises/{id}` | Checking if a workflow completed | | Resolve a HITL promise | `PATCH /promises/{id}` | User clicking "Approve" button | | Create a standalone promise | `POST /promises` | External system creating a promise to be resolved later | **Key insight:** The HTTP API is for **managing promise state** without running workflow code. ### Decision Flowchart ``` Do you need to RUN workflow code (generators, ctx.run, ctx.sleep)? │ ├─ YES → Use SDK: resonate.run(), resonate.rpc(), etc. │ (Requires a worker process that can execute the code) │ └─ NO → Are you querying or resolving existing promises? │ ├─ YES → Use HTTP API: GET/PATCH /promises │ (Can be done from any HTTP client) │ └─ NO → You probably need the SDK ``` ### Lovable-Specific Guidance Since Lovable **cannot run persistent workers**, your Lovable backend should: 1. **Use SDK** to START workflows on external workers: `resonate.beginRpc()` with `target: "poll://any@workers"` 2. **Use HTTP API** to QUERY workflow state: `GET /promises?id=...` 3. **Use HTTP API or SDK** to RESOLVE promises: `PATCH /promises/{id}` or `resonate.promises.resolve(id, { data })` The actual workflow EXECUTION happens on your external workers (Cloud Run, Fly.io, etc.), not in Lovable. ## Lovable-Specific Patterns ### Pattern 1: Async Workflow with Polling **Frontend (React):** ```tsx // src/components/WorkflowRunner.tsx import { useState } from "react"; import { useToast } from "@/components/ui/use-toast"; export function WorkflowRunner() { const [workflowId, setWorkflowId] = useState<string | null>(null); const [status, setStatus] = useState<"idle" | "running" | "completed">("idle"); const { toast } = useToast(); const startWorkflow = async () => { setStatus("running"); const response = await fetch("/api/workflows/start", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ workflowType: "processOrder", input: { orderId: "123", items: [...] } }) }); const { workflowId } = await response.json(); setWorkflowId(workflowId); // Poll for completion const pollInterval = setInterval(async () => { const statusRes = await fetch(`/api/workflows/${workflowId}/status`); const data = await statusRes.json(); if (data.status === "completed") { clearInterval(pollInterval); setStatus("completed"); toast({ title: "Workflow completed!", description: JSON.stringify(data.result) }); } }, 2000); }; return ( <div> <button onClick={startWorkflow} disabled={status === "running"}> Start Workflow </button> {status === "running" && <p>Workflow running... (ID: {workflowId})</p>} {status === "completed" && <p>Workflow completed!</p>} </div> ); } ``` ### Pattern 2: Store Workflow State in Supabase **Track workflow progress in Lovable's built-in PostgreSQL:** ```typescript // server/routes/workflows.ts router.post("/api/workflows/start", async (req, res) => { const { workflowType, input } = req.body; const workflowId = `workflow-${Date.now()}`; // Store in database await supabase.from("workflows").insert({ id: workflowId, type: workflowType, input, status: "pending", created_at: new Date().toISOString() }); // Start Resonate workflow await resonate.beginRpc(workflowId, workflowType, input, resonate.options({ target: "poll://any@workers" })); res.json({ workflowId }); }); // Webhook for completion (called by external worker) router.post("/api/workflows/:id/complete", async (req, res) => { const { id } = req.params; const { result } = req.body; await supabase.from("workflows").update({ status: "completed", result, completed_at: new Date().toISOString() }).eq("id", id); res.json({ success: true }); }); ``` ### Pattern 3: Human-in-the-Loop with Lovable UI **Workflow creates approval request, Lovable UI resolves it:** ```typescript // External worker function* approvalWorkflow(ctx: Context, orderId: string) { const promise = yield* ctx.promise({ timeout: 24 * 60 * 60 * 1000 }); // Notify Lovable backend yield* ctx.run(async () => { await fetch(`${lovableBackendUrl}/api/approvals/create`, { method: "POST", body: JSON.stringify({ orderId, promiseId: promise.id }) }); }); const decision = yield* promise; return decision; } // Lovable backend router.post("/api/approvals/resolve/:promiseId", async (req, res) => { const { promiseId } = req.params; const { approved } = req.body; const data = Buffer.from(JSON.stringify({ approved })).toString('base64'); await resonate.promises.resolve(promiseId, { data }); res.json({ success: true }); }); // Lovable frontend function ApprovalButton({ promiseId }: { promiseId: string }) { const handleApprove = async () => { await fetch(`/api/approvals/resolve/${promiseId}`, { method: "POST", body: JSON.stringify({ approved: true }) }); }; return <button onClick={handleApprove}>Approve</button>; } ``` ## Deployment Strategy ### Step 1: Deploy Resonate Server **Options:** - Google Cloud Run (recommended for Lovable users) - Fly.io - Railway - Render **Example (Cloud Run):** ```bash # Deploy Resonate server docker pull resonatehq/resonate:latest gcloud run deploy resonate-server \ --image resonatehq/resonate:latest \ --platform managed \ --region us-central1 \ --allow-unauthenticated ``` ### Step 2: Deploy Resonate Workers **Same platforms, separate service:** ```bash # Build and deploy worker docker build -t workers . gcloud run deploy resonate-workers \ --image gcr.io/PROJECT/workers \ --platform managed \ --set-env-vars RESONATE_URL=https://resonate-server-xxx.run.app ```
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen