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.

Informations de source

Dépôt
resonatehq/resonate-skills
Dernière activité de la source
21 août 2026 à 17:03
Langue détectée de SKILL.md
anglais
Étoiles
6
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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 ```
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub