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.

インストールへ移動

ソース情報

リポジトリ
resonatehq/resonate-skills
ソースの最終更新活動
2026年8月21日 17:03
検出された SKILL.md の言語
英語
スター
6
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
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 ```
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る