@lovable.dev/sdk 1.7.5 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -311
- package/dist/index.d.ts +950 -929
- package/dist/index.js +5 -17
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +2695 -292
- package/dist/schemas.js +668 -194
- package/dist/schemas.js.map +1 -1
- package/package.json +2 -1
- package/src/client.ts +4 -16
- package/src/generated/paths.ts +929 -898
- package/src/generated/version.ts +1 -1
- package/src/generated/zod/zod.gen.ts +529 -189
- package/src/index.ts +1 -0
- package/src/schemas-deprecated.ts +209 -0
- package/src/schemas.ts +11 -17
- package/src/types.ts +17 -15
package/README.md
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for the Lovable API.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **Warning: experimental software.** This SDK is not covered by the public
|
|
6
|
+
> API v1 stability guarantees. Any release, including minor and patch versions,
|
|
7
|
+
> may change or remove methods, types, and behavior. Pin an exact version. For
|
|
8
|
+
> production integrations, call the public API directly.
|
|
6
9
|
|
|
7
10
|
## Installation
|
|
8
11
|
|
|
@@ -10,357 +13,205 @@ Stable for the public API v1 surface and versioned with semver.
|
|
|
10
13
|
npm install @lovable.dev/sdk
|
|
11
14
|
```
|
|
12
15
|
|
|
13
|
-
##
|
|
16
|
+
## Create an API key
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
Keys are created in the workspace settings at `https://lovable.dev/settings/api-keys`
|
|
19
|
+
(the **Access tokens** tab). You need the admin or owner role in the workspace.
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
| Setting | Effect |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| Workspace | A key belongs to one workspace and can only read or change that workspace. Resources in other workspaces return `404`. |
|
|
24
|
+
| Plan | The workspace must be on Business or higher; every public v1 call from a lower plan returns `402 payment_required`. Two operations (project PII labels, Security Center project inventory) require Enterprise. |
|
|
25
|
+
| Access | Pick Read-only or Full access per resource. Projects maps to `projects:read` / `projects:write`, Workspace maps to `workspaces:read` / `workspaces:write`. A write scope includes the matching read scope. |
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
Every key from this page carries the `public:v1` audience: it reaches the
|
|
28
|
+
advertised public v1 management operations and nothing else. The audience is
|
|
29
|
+
not shown in the settings page.
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
const project = await client.createProject(workspaces[0].id, {
|
|
27
|
-
description: "Best todo app",
|
|
28
|
-
initialMessage: "Create a todo app with authentication"
|
|
29
|
-
});
|
|
31
|
+
## Quick start
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
console.log(response.content); // AI's response text
|
|
34
|
-
console.log(response.message_id); // AI message ID
|
|
35
|
-
console.log(client.getPreviewUrl(project.id)); // Preview URL for the project
|
|
33
|
+
```typescript
|
|
34
|
+
import { LovableClient } from "@lovable.dev/sdk";
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
await client.chat(project.id, {
|
|
39
|
-
message: "Add a footer",
|
|
40
|
-
});
|
|
36
|
+
const client = new LovableClient({ apiKey: process.env.LOVABLE_API_KEY! });
|
|
41
37
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
// GET /v1/me: validates the key. A workspace-scoped key returns one workspace.
|
|
39
|
+
const me = await client.me();
|
|
40
|
+
console.log(me.email, me.workspaces?.[0]?.name);
|
|
41
|
+
|
|
42
|
+
// GET /v1/workspaces: list envelope (`data`, `pagination`) plus `workspaces`, an alias of `data`.
|
|
43
|
+
const { workspaces } = await client.listWorkspaces();
|
|
44
|
+
const workspaceId = workspaces[0].id;
|
|
49
45
|
|
|
50
|
-
//
|
|
51
|
-
await client.
|
|
52
|
-
const
|
|
53
|
-
console.log(
|
|
46
|
+
// GET /v1/projects?workspace_id=...: same envelope, plus `projects` as an alias of `data`.
|
|
47
|
+
const page = await client.listProjects(workspaceId, { limit: 20 });
|
|
48
|
+
for (const project of page.data ?? []) {
|
|
49
|
+
console.log(project.id, project.name, project.is_published ? project.url : "(not published)");
|
|
50
|
+
}
|
|
54
51
|
```
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
Every hand-written method returns the response body unchanged, apart from the
|
|
54
|
+
aliases noted above. `client.typed` is an [openapi-fetch](https://openapi-ts.dev/openapi-fetch/)
|
|
55
|
+
client over the generated route types for any advertised operation without a
|
|
56
|
+
hand-written method.
|
|
57
|
+
|
|
58
|
+
## Pagination
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
List operations take `limit` (1 to 100, default 50) and `cursor`, and return
|
|
61
|
+
`data` with `pagination.next_cursor` and `pagination.has_more`. Keep the same
|
|
62
|
+
filters across pages.
|
|
59
63
|
|
|
60
64
|
```typescript
|
|
61
|
-
|
|
65
|
+
let cursor: string | undefined;
|
|
66
|
+
do {
|
|
67
|
+
const page = await client.listProjects(workspaceId, { limit: 100, cursor });
|
|
68
|
+
for (const project of page.data ?? []) console.log(project.id);
|
|
69
|
+
cursor = page.pagination.has_more ? (page.pagination.next_cursor ?? undefined) : undefined;
|
|
70
|
+
} while (cursor);
|
|
71
|
+
```
|
|
62
72
|
|
|
63
|
-
|
|
64
|
-
"project-showcase",
|
|
65
|
-
async (ctx) => {
|
|
66
|
-
const message = await ctx.step.run("normalize", () => ctx.input.message.trim());
|
|
67
|
-
return { message, runId: await ctx.uuid("run") };
|
|
68
|
-
},
|
|
69
|
-
);
|
|
73
|
+
## Create an embed URL
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
`client.createEmbedUrl(projectId, parentOrigin)` calls
|
|
76
|
+
`POST /v1/projects/{project_id}/embed-url` with scope `projects:write`. It
|
|
77
|
+
requires Business or higher and edit permission on the project. The response
|
|
78
|
+
contains a preview URL valid for one hour and bound to one exact HTTPS parent
|
|
79
|
+
origin. Visitors can view the built preview without a Lovable login.
|
|
73
80
|
|
|
74
|
-
|
|
81
|
+
## Publish a project and poll the deployment
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
`POST /v1/projects/{project_id}/publish` (scope `projects:write`) returns `202`
|
|
84
|
+
with a `deployment_id`. Poll `GET /v1/projects/{project_id}/publish/{deployment_id}`
|
|
85
|
+
(scope `projects:read`) no more than once every 2 seconds. `completed` and
|
|
86
|
+
`error` are terminal; keep polling on `running` and on `unknown` (a degraded,
|
|
87
|
+
non-terminal state). Give up after a deadline; the example uses 10 minutes.
|
|
77
88
|
|
|
78
89
|
```typescript
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const jobId = await client.remixProject("source-project-id", {
|
|
83
|
-
workspaceId: "target-workspace-id",
|
|
84
|
-
messageId: "message-id-to-snapshot-at",
|
|
85
|
-
// remixMode: "including", // use "including" to keep the message and its AI response
|
|
86
|
-
includeHistory: true,
|
|
87
|
-
includeCustomKnowledge: true,
|
|
90
|
+
const { data: accepted } = await client.typed.POST("/v1/projects/{project_id}/publish", {
|
|
91
|
+
params: { path: { project_id: projectId } },
|
|
92
|
+
body: {}, // optional: { visibility: "workspace" }
|
|
88
93
|
});
|
|
94
|
+
if (!accepted?.deployment_id) throw new Error("publish was not accepted");
|
|
95
|
+
|
|
96
|
+
const deadline = Date.now() + 10 * 60 * 1000;
|
|
97
|
+
let deployment;
|
|
98
|
+
do {
|
|
99
|
+
if (Date.now() > deadline) throw new Error(`deployment ${accepted.deployment_id} did not finish in 10 minutes`);
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
101
|
+
({ data: deployment } = await client.typed.GET("/v1/projects/{project_id}/publish/{deployment_id}", {
|
|
102
|
+
params: { path: { project_id: projectId, deployment_id: accepted.deployment_id } },
|
|
103
|
+
}));
|
|
104
|
+
} while (deployment?.status === "running" || deployment?.status === "unknown");
|
|
105
|
+
|
|
106
|
+
if (deployment?.status === "completed") console.log(deployment.url);
|
|
107
|
+
else console.error(deployment?.error_code, deployment?.error_message);
|
|
108
|
+
```
|
|
89
109
|
|
|
90
|
-
|
|
91
|
-
const { projectId } = await client.waitForRemix("source-project-id", jobId, {
|
|
92
|
-
onProgress: (status, step) => console.log(`Remix: ${status}`, step),
|
|
93
|
-
});
|
|
110
|
+
## Errors
|
|
94
111
|
|
|
95
|
-
|
|
112
|
+
Non-2xx responses throw `ApiError`. The API returns one error envelope on
|
|
113
|
+
every operation:
|
|
96
114
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"type": "invalid_argument",
|
|
118
|
+
"title": "Invalid argument",
|
|
119
|
+
"status": 400,
|
|
120
|
+
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736",
|
|
121
|
+
"detail": "validation failed",
|
|
122
|
+
"errors": [{ "location": "query.limit", "message": "expected integer <= 100" }]
|
|
123
|
+
}
|
|
102
124
|
```
|
|
103
125
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
`type`, `title`, `status`, and `request_id` are always present. `detail`,
|
|
127
|
+
`errors[]`, and `props` are optional. Branch on `type`; `title` wording can
|
|
128
|
+
change.
|
|
107
129
|
|
|
108
|
-
|
|
|
130
|
+
| Envelope field | On `ApiError` |
|
|
109
131
|
| --- | --- |
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
132
|
+
| `status` | `status` |
|
|
133
|
+
| `type` | `type` |
|
|
134
|
+
| `title` | `message` |
|
|
135
|
+
| `detail` | `detail` |
|
|
136
|
+
| `props` | `props` |
|
|
137
|
+
| `request_id`, `errors[]` | Not exposed by the SDK. Both are in the response body when you call the API directly. |
|
|
113
138
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
HTTPie examples live in [examples/httpie.md](examples/httpie.md).
|
|
139
|
+
```typescript
|
|
140
|
+
import { ApiError } from "@lovable.dev/sdk";
|
|
117
141
|
|
|
118
|
-
|
|
142
|
+
try {
|
|
143
|
+
await client.getProject(projectId);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
if (err instanceof ApiError && err.type === "project_not_found") return null;
|
|
146
|
+
throw err;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
119
149
|
|
|
120
|
-
|
|
150
|
+
Types you will meet first:
|
|
151
|
+
|
|
152
|
+
| `status` | `type` | Cause |
|
|
153
|
+
| --- | --- | --- |
|
|
154
|
+
| 401 | `unauthorized` | Missing, revoked, or expired key |
|
|
155
|
+
| 402 | `payment_required` | Workspace plan below Business (or Enterprise where required) |
|
|
156
|
+
| 403 | `insufficient_scope` | Key lacks the operation's scope |
|
|
157
|
+
| 403 | `forbidden` | Caller lacks the workspace or project permission |
|
|
158
|
+
| 403 | `audience_forbidden` | A `public:v1` key called a route outside the public v1 contract |
|
|
159
|
+
| 404 | `project_not_found`, `workspace_not_found` | Missing resource, or a resource in another workspace |
|
|
160
|
+
| 406 | `not_acceptable` | `Accept` header excludes `application/json` |
|
|
161
|
+
| 429 | `rate_limited` | Rate limit hit; see below |
|
|
162
|
+
|
|
163
|
+
## Rate limits
|
|
164
|
+
|
|
165
|
+
Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and, when
|
|
166
|
+
known, `X-RateLimit-Reset` (Unix seconds). Limits use a sliding window: per
|
|
167
|
+
API key for key-authenticated requests, per user for session and OAuth
|
|
168
|
+
requests. Publishing is limited separately (10 per minute by default), as are
|
|
169
|
+
deployment status polling (120 per minute), analytics, security-center
|
|
170
|
+
insights, and collaborator reads (300 per minute).
|
|
171
|
+
|
|
172
|
+
On `429` the client retries the request up to three times, waiting 100 ms,
|
|
173
|
+
300 ms, then 500 ms, or longer when the `Retry-After` header asks for more.
|
|
174
|
+
After the last retry it throws `ApiError` with `status: 429` and
|
|
175
|
+
`rateLimit.retryAfterMs` parsed from `Retry-After`.
|
|
121
176
|
|
|
122
177
|
```typescript
|
|
123
|
-
|
|
178
|
+
if (err instanceof ApiError && err.status === 429) {
|
|
179
|
+
await new Promise((resolve) => setTimeout(resolve, err.rateLimit?.retryAfterMs ?? 1000));
|
|
180
|
+
}
|
|
124
181
|
```
|
|
125
182
|
|
|
126
|
-
|
|
127
|
-
- `baseUrl` (optional): Override the default API base URL
|
|
128
|
-
|
|
129
|
-
#### Methods
|
|
130
|
-
|
|
131
|
-
##### `listWorkspaces(): Promise<WorkspaceWithMembership[]>`
|
|
132
|
-
|
|
133
|
-
List all workspaces the authenticated user has access to.
|
|
134
|
-
|
|
135
|
-
##### `getWorkspace(workspaceId: string): Promise<WorkspaceWithMembership>`
|
|
136
|
-
|
|
137
|
-
Get a specific workspace by ID.
|
|
138
|
-
|
|
139
|
-
##### `listProjects(workspaceId: string, options?): Promise<ProjectResponse[]>`
|
|
140
|
-
|
|
141
|
-
List projects in a workspace.
|
|
142
|
-
|
|
143
|
-
Options:
|
|
144
|
-
|
|
145
|
-
- `limit` (optional): Maximum number of projects to return
|
|
146
|
-
- `visibility` (optional): Filter by visibility (`"all"` | `"personal"` | `"public"` | `"workspace"`)
|
|
147
|
-
|
|
148
|
-
##### `createProject(workspaceId: string, options): Promise<ProjectResponse>`
|
|
149
|
-
|
|
150
|
-
Create a new project in a workspace.
|
|
151
|
-
|
|
152
|
-
Options:
|
|
153
|
-
|
|
154
|
-
- `description` (required): Project description
|
|
155
|
-
- `techStack` (optional): Technology stack (e.g., `"react"`)
|
|
156
|
-
- `visibility` (optional): Project visibility (`"draft"` | `"private"` | `"public"`)
|
|
157
|
-
- `templateProjectId` (optional): ID of a template project to clone
|
|
158
|
-
- `initialMessage` (optional): Initial chat message to send to the AI agent
|
|
159
|
-
- `files` (optional): Array of files to attach (browser `File` objects or `FileInput` objects)
|
|
160
|
-
|
|
161
|
-
##### `getProject(projectId: string): Promise<ProjectResponse>`
|
|
162
|
-
|
|
163
|
-
Get a project by ID.
|
|
164
|
-
|
|
165
|
-
##### `updateProject(projectId: string, options): Promise<ProjectResponse>`
|
|
166
|
-
|
|
167
|
-
Update supported project fields through `PATCH /v1/projects/{project_id}`.
|
|
168
|
-
|
|
169
|
-
Options:
|
|
170
|
-
|
|
171
|
-
- `display_name` (optional): Project display name
|
|
172
|
-
- `visibility` (optional): Project visibility (`"draft"` | `"private"` | `"public"` | `"workspace_view"`)
|
|
173
|
-
|
|
174
|
-
##### `deleteProject(projectId: string): Promise<void>`
|
|
175
|
-
|
|
176
|
-
Soft-delete a project through `DELETE /v1/projects/{project_id}`.
|
|
177
|
-
|
|
178
|
-
##### `chat(projectId: string, options): Promise<SendMessageResponse>`
|
|
179
|
-
|
|
180
|
-
Send a chat message to a project's AI agent.
|
|
181
|
-
|
|
182
|
-
Options:
|
|
183
|
-
|
|
184
|
-
- `message` (required): The message to send
|
|
185
|
-
- `files` (optional): Array of files to attach (browser `File` objects or `FileInput` objects)
|
|
186
|
-
- `continuation` (optional): Override prompt cache continuation behavior (`"force"` | `"fresh_build"` | `"allow_expired_cache"`). API-key auth only. See [Continuation override](#continuation-override)
|
|
187
|
-
|
|
188
|
-
The response includes the created `message_id` and its trajectory `thread_id`. Pass both to `waitForMessageCompletion()` to wait for the matching AI reply.
|
|
189
|
-
|
|
190
|
-
##### `listMessages(projectId: string, options?): Promise<ListMessagesResponse>`
|
|
191
|
-
|
|
192
|
-
List recent project messages through `GET /v1/messages`.
|
|
193
|
-
|
|
194
|
-
##### `getMessage(projectId: string, messageId: string, options?): Promise<GetMessageResponse>`
|
|
195
|
-
|
|
196
|
-
Get a message through `GET /v1/messages/{message_id}`. Pass `waitSeconds` for server-side long polling.
|
|
197
|
-
|
|
198
|
-
##### `createVariant(projectId: string, options?): Promise<CreateVariantResponse>`
|
|
199
|
-
|
|
200
|
-
Create an independent variant from the project's current main branch, or from a specific full 40-character commit SHA.
|
|
201
|
-
|
|
202
|
-
Options:
|
|
183
|
+
## Operations outside the public v1 contract
|
|
203
184
|
|
|
204
|
-
|
|
205
|
-
|
|
185
|
+
The client also exposes builder operations: project creation and remix
|
|
186
|
+
(`createProject`, `remixProject`), messages (`chat`, `listMessages`,
|
|
187
|
+
`getMessage`, `waitForMessageCompletion`, `createVariant`), database, git and
|
|
188
|
+
file access, uploads, knowledge, skills, connectors, folders, and
|
|
189
|
+
`publish()` (which calls the deprecated `POST /v1/deployments` alias). These
|
|
190
|
+
routes are not part of the public v1 contract. A key created in the settings
|
|
191
|
+
page receives `403 audience_forbidden` from all of them. They require a key
|
|
192
|
+
without a public audience, they carry no stability guarantee, and they are not
|
|
193
|
+
documented here.
|
|
206
194
|
|
|
207
|
-
|
|
195
|
+
## Workflows subpath
|
|
208
196
|
|
|
209
|
-
-
|
|
210
|
-
|
|
211
|
-
- `branch` (string): The git branch attached to the variant
|
|
212
|
-
- `thread_id` (string): The trajectory thread driving the variant
|
|
213
|
-
|
|
214
|
-
The API returns `403 variants_not_enabled` when variants are unavailable for the authenticated user and project workspace.
|
|
215
|
-
|
|
216
|
-
##### `waitForMessageCompletion(projectId: string, messageId: string, options?): Promise<MessageCompletionResult>`
|
|
217
|
-
|
|
218
|
-
Wait for a specific message's AI response to finish. Pass the `message_id` from `chat()` or from `createProject()` with `initialMessage` (and the `thread_id` via `options.threadId` for non-main threads).
|
|
219
|
-
|
|
220
|
-
Use `getPreviewUrl(projectId)` to construct the preview URL.
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
|
|
224
|
-
- `status` (`"completed" | "awaiting_input" | "stopped" | "timeout" | "error"`): Terminal state
|
|
225
|
-
- `content` (string): The AI's full response text
|
|
226
|
-
- `message_id` (string): The AI message ID
|
|
227
|
-
- `awaiting_input` (optional): Present when `status` is `"awaiting_input"` — a non-headless turn paused by a human-in-the-loop tool. Carries the resumable `event_id`, `prev_session_id`, and optional `input_schema`
|
|
228
|
-
- `edit_id` / `commit_sha` / `summary` / `cost_credits` (optional): Result metadata
|
|
229
|
-
|
|
230
|
-
Options:
|
|
231
|
-
|
|
232
|
-
- `threadId` (optional): Trajectory thread returned by `chat()`
|
|
233
|
-
- `timeout` (optional): Maximum total time to wait in ms (default: 600000 = 10 minutes)
|
|
234
|
-
|
|
235
|
-
##### `waitForResponse(projectId: string, options?): Promise<ChatResponse>`
|
|
236
|
-
|
|
237
|
-
Deprecated compatibility helper. Prefer `waitForMessageCompletion(projectId, messageId)`.
|
|
238
|
-
|
|
239
|
-
##### `getPreviewUrl(projectId: string): string`
|
|
240
|
-
|
|
241
|
-
Get the preview URL for a project. This is a synchronous method that constructs the URL from the project ID.
|
|
242
|
-
|
|
243
|
-
##### `publish(projectId: string, options?): Promise<DeploymentResponse>`
|
|
244
|
-
|
|
245
|
-
Publish (deploy) a project to make it publicly accessible. The deployment runs asynchronously — use `waitForProjectPublished()` to wait for completion.
|
|
246
|
-
|
|
247
|
-
Options:
|
|
248
|
-
|
|
249
|
-
- `name` (optional): Custom slug for the published URL
|
|
250
|
-
|
|
251
|
-
Returns:
|
|
252
|
-
|
|
253
|
-
- `status` (string): Deployment status
|
|
254
|
-
- `deployment_id` (string): The deployment ID
|
|
255
|
-
- `url` (string): The published URL (may not be available until deployment completes)
|
|
256
|
-
|
|
257
|
-
##### `getPublishedUrl(projectId: string): Promise<string | null>`
|
|
258
|
-
|
|
259
|
-
Get the published URL for a project, or `null` if not published. Fetches the latest project details to check publication status.
|
|
260
|
-
|
|
261
|
-
##### `waitForProjectReady(projectId: string, options?): Promise<ProjectResponse>`
|
|
262
|
-
|
|
263
|
-
Wait for a project to reach "completed" status. Projects start in "in_progress" status while being created/built.
|
|
264
|
-
|
|
265
|
-
Options:
|
|
266
|
-
|
|
267
|
-
- `pollInterval` (optional): Time between polls in ms (default: 2000)
|
|
268
|
-
- `timeout` (optional): Maximum time to wait in ms (default: 300000 = 5 minutes)
|
|
269
|
-
- `onProgress` (optional): Callback for status updates
|
|
270
|
-
|
|
271
|
-
Throws an error if the project fails or timeout is reached.
|
|
272
|
-
|
|
273
|
-
##### `waitForProjectPublished(projectId: string, options?): Promise<ProjectResponse>`
|
|
274
|
-
|
|
275
|
-
Wait for a project to be published (deployed) and have a live URL.
|
|
276
|
-
|
|
277
|
-
Options:
|
|
278
|
-
|
|
279
|
-
- `pollInterval` (optional): Time between polls in ms (default: 3000)
|
|
280
|
-
- `timeout` (optional): Maximum time to wait in ms (default: 600000 = 10 minutes)
|
|
281
|
-
- `onProgress` (optional): Callback for status updates
|
|
282
|
-
|
|
283
|
-
Throws an error if timeout is reached.
|
|
284
|
-
|
|
285
|
-
##### `remixProject(sourceProjectId: string, options): Promise<string>`
|
|
286
|
-
|
|
287
|
-
Remix (fork) an existing project, optionally at a specific message point in time.
|
|
288
|
-
|
|
289
|
-
When `messageId` is provided, the remix captures the project state as it was just before that message was processed (default `remixMode: "before"`). Set `remixMode: "including"` to include the message and its AI response in the remix. Without `messageId`, the full current state is remixed.
|
|
290
|
-
|
|
291
|
-
Returns the remix job ID for polling with `waitForRemix()`.
|
|
292
|
-
|
|
293
|
-
Options:
|
|
294
|
-
|
|
295
|
-
- `workspaceId` (required): Target workspace for the new project
|
|
296
|
-
- `messageId` (optional): Message ID to snapshot at — by default the remix reflects the project state just before this message
|
|
297
|
-
- `remixMode` (optional): `"before"` (default) captures state before the message; `"including"` captures state after the message and its AI response
|
|
298
|
-
- `includeHistory` (optional, default: `false`): Copy chat history. Requires edit access to the original project. View-only access or a public remix link is not enough.
|
|
299
|
-
- `includeFiles` (optional, default: `false`): Copy project Files. Requires edit access to the original project. View-only access or a public remix link is not enough.
|
|
300
|
-
- `includeCustomKnowledge` (optional, default: `false`): Whether to copy custom instructions/knowledge
|
|
301
|
-
- `initialMessage` (optional): Initial chat message to send after remix completes
|
|
302
|
-
- `skipInitialRemixMessage` (optional, default: `false`): When true, suppresses the default "I've successfully remixed this project" message
|
|
303
|
-
- `skipIntegrations` (optional, default: `false`): When true, skips copying integrations to the remixed project
|
|
304
|
-
|
|
305
|
-
Omitting `includeFiles` or setting it to `false` skips Files for everyone. Set it to `true` to copy Files; without edit access to the original project, the request returns `403 insufficient_permissions`.
|
|
306
|
-
|
|
307
|
-
Existing callers that relied on automatic Files copying must now send `includeFiles: true`. Chat history stays independent.
|
|
308
|
-
|
|
309
|
-
This option does not control attachments in copied chat history or app code and assets.
|
|
310
|
-
|
|
311
|
-
##### `waitForRemix(sourceProjectId: string, jobId: string, options?): Promise<RemixResult>`
|
|
312
|
-
|
|
313
|
-
Wait for a remix operation to complete. Polls `GET /v1/remix-jobs/{job_id}` until the job finishes. The `sourceProjectId` argument is kept for SDK compatibility.
|
|
314
|
-
|
|
315
|
-
Returns:
|
|
316
|
-
|
|
317
|
-
- `projectId` (string): The ID of the newly created project
|
|
318
|
-
|
|
319
|
-
Options:
|
|
320
|
-
|
|
321
|
-
- `pollInterval` (optional): Time between polls in ms (default: 2000)
|
|
322
|
-
- `timeout` (optional): Maximum time to wait in ms (default: 300000 = 5 minutes)
|
|
323
|
-
- `onProgress` (optional): Callback with `(status, step?)` for progress updates
|
|
324
|
-
|
|
325
|
-
Throws an error if the remix fails or timeout is reached.
|
|
326
|
-
|
|
327
|
-
## Types
|
|
328
|
-
|
|
329
|
-
The SDK exports TypeScript types for all API responses. See `src/types.ts` for the full list.
|
|
197
|
+
`@lovable.dev/sdk/workflows` defines compute-only durable workflows for the
|
|
198
|
+
Cloudflare runtime; it does not call the Lovable API.
|
|
330
199
|
|
|
331
200
|
```typescript
|
|
332
|
-
import
|
|
333
|
-
WorkspaceWithMembership,
|
|
334
|
-
ProjectResponse,
|
|
335
|
-
CreateProjectOptions,
|
|
336
|
-
MessageCompletionResult,
|
|
337
|
-
ContinuationOverride,
|
|
338
|
-
FileInput,
|
|
339
|
-
RemixProjectOptions,
|
|
340
|
-
// ... etc
|
|
341
|
-
} from "@lovable.dev/sdk";
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### `FileInput`
|
|
201
|
+
import { defineWorkflow, toWorker } from "@lovable.dev/sdk/workflows";
|
|
345
202
|
|
|
346
|
-
|
|
203
|
+
const workflow = defineWorkflow<{ message: string }, { message: string }>("normalize", async (ctx) => ({
|
|
204
|
+
message: await ctx.step.run("normalize", () => ctx.input.message.trim()),
|
|
205
|
+
}));
|
|
347
206
|
|
|
348
|
-
|
|
349
|
-
interface FileInput {
|
|
350
|
-
name: string; // Original file name (e.g., "screenshot.png")
|
|
351
|
-
data: Blob | ArrayBuffer | Uint8Array; // File contents
|
|
352
|
-
type: string; // MIME type (e.g., "image/png")
|
|
353
|
-
}
|
|
207
|
+
export default toWorker(workflow);
|
|
354
208
|
```
|
|
355
209
|
|
|
356
|
-
|
|
210
|
+
## Reference
|
|
357
211
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
- `"force"` — skip all continuation checks (force continuation)
|
|
365
|
-
- `"fresh_build"` — force a full prompt rebuild from scratch
|
|
366
|
-
- `"allow_expired_cache"` — skip cache expiry check but respect other continuation checks
|
|
212
|
+
| Document | Content |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| [API_SPEC.md](API_SPEC.md) | Every advertised public v1 operation with its scope, parameters, and response schema |
|
|
215
|
+
| https://api.lovable.dev/v1/openapi.json | The served OpenAPI document; authoritative when the two disagree |
|
|
216
|
+
| [examples/httpie.md](examples/httpie.md) | The same calls over plain HTTP |
|
|
217
|
+
| [src/types.ts](src/types.ts) | Exported request and response types |
|