@lovable.dev/sdk 0.1.5 → 0.1.8

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/dist/index.js CHANGED
@@ -1,13 +1,18 @@
1
+ // src/client.ts
2
+ import createClient from "openapi-fetch";
3
+
1
4
  // src/types.ts
2
5
  var ApiError = class extends Error {
3
6
  status;
4
7
  type;
5
8
  detail;
6
- constructor(status, message, type, detail) {
9
+ props;
10
+ constructor(status, message, type, detail, props) {
7
11
  super(message);
8
12
  this.status = status;
9
13
  this.type = type;
10
14
  this.detail = detail;
15
+ this.props = props;
11
16
  }
12
17
  };
13
18
 
@@ -21,10 +26,29 @@ function normalizeBaseUrl(url) {
21
26
  }
22
27
  return normalized;
23
28
  }
29
+ var errorMiddleware = {
30
+ async onResponse({ response }) {
31
+ if (response.ok) return;
32
+ let errorBody;
33
+ try {
34
+ errorBody = await response.clone().json();
35
+ } catch {
36
+ }
37
+ const message = buildErrorMessage(errorBody, response.status, response.statusText);
38
+ const type = errorBody?.type ?? errorBody?.title;
39
+ const detail = errorBody?.detail ?? errorBody?.details;
40
+ throw new ApiError(response.status, message, type, detail, errorBody?.props);
41
+ }
42
+ };
43
+ function buildErrorMessage(body, status, statusText) {
44
+ return body?.message || body?.title || (statusText ? `HTTP ${status}: ${statusText}` : `HTTP ${status}`);
45
+ }
24
46
  var LovableClient = class {
25
47
  authHeaders;
26
48
  baseUrl;
27
49
  extraHeaders;
50
+ clientSource;
51
+ typedClient;
28
52
  constructor(options) {
29
53
  const hasApiKey = !!options.apiKey;
30
54
  const hasBearerToken = !!options.bearerToken;
@@ -37,10 +61,33 @@ var LovableClient = class {
37
61
  this.authHeaders = hasApiKey ? { "Lovable-API-Key": options.apiKey } : { Authorization: `Bearer ${options.bearerToken}` };
38
62
  this.baseUrl = normalizeBaseUrl(options.baseUrl);
39
63
  this.extraHeaders = options.headers ?? {};
64
+ this.clientSource = options.clientSource ?? "sdk";
65
+ this.typedClient = createClient({
66
+ baseUrl: this.baseUrl,
67
+ headers: {
68
+ "X-Client-Source": this.clientSource,
69
+ ...this.authHeaders,
70
+ ...this.extraHeaders,
71
+ Accept: "application/json"
72
+ }
73
+ });
74
+ this.typedClient.use(errorMiddleware);
40
75
  }
41
- async rawRequest(method, path, body) {
76
+ /**
77
+ * Type-safe access to any documented API route, driven by the auto-generated
78
+ * OpenAPI schema. Path / query params and request bodies are checked at compile
79
+ * time; calling an unknown path is a type error.
80
+ *
81
+ * Non-2xx responses throw `ApiError`; on success, `data` is set on the result.
82
+ */
83
+ get typed() {
84
+ return this.typedClient;
85
+ }
86
+ async rawRequest(method, path, body, init) {
42
87
  const url = `${this.baseUrl}${path}`;
43
88
  const headers = {
89
+ "X-Client-Source": this.clientSource,
90
+ ...init?.headers,
44
91
  ...this.authHeaders,
45
92
  ...this.extraHeaders,
46
93
  Accept: "application/json"
@@ -51,7 +98,8 @@ var LovableClient = class {
51
98
  const response = await fetch(url, {
52
99
  method,
53
100
  headers,
54
- body: body !== void 0 ? JSON.stringify(body) : void 0
101
+ body: body !== void 0 ? JSON.stringify(body) : void 0,
102
+ signal: init?.signal
55
103
  });
56
104
  if (!response.ok) {
57
105
  let errorBody;
@@ -59,8 +107,10 @@ var LovableClient = class {
59
107
  errorBody = await response.json();
60
108
  } catch {
61
109
  }
62
- const message = errorBody?.message ?? errorBody?.title ?? `HTTP ${response.status}: ${response.statusText}`;
63
- throw new ApiError(response.status, message, errorBody?.title, errorBody?.detail);
110
+ const message = buildErrorMessage(errorBody, response.status, response.statusText);
111
+ const type = errorBody?.type ?? errorBody?.title;
112
+ const detail = errorBody?.detail ?? errorBody?.details;
113
+ throw new ApiError(response.status, message, type, detail, errorBody?.props);
64
114
  }
65
115
  return response;
66
116
  }
@@ -80,7 +130,8 @@ var LovableClient = class {
80
130
  * Useful for validating an API key and discovering workspace IDs.
81
131
  */
82
132
  async me() {
83
- return this.request("GET", "/v1/me");
133
+ const { data } = await this.typed.GET("/v1/me");
134
+ return { ...data, workspaces: data.workspaces ?? [] };
84
135
  }
85
136
  /**
86
137
  * List all workspaces the authenticated user has access to
@@ -130,9 +181,11 @@ var LovableClient = class {
130
181
  }
131
182
  const body = {
132
183
  description: options.description,
133
- visibility: options.visibility ?? "private",
134
184
  template_project_id: options.templateProjectId
135
185
  };
186
+ if (options.visibility) {
187
+ body.visibility = options.visibility;
188
+ }
136
189
  if (options.techStack) {
137
190
  body.tech_stack = options.techStack;
138
191
  }
@@ -271,19 +324,6 @@ var LovableClient = class {
271
324
  async queryDatabase(projectId, sql) {
272
325
  return this.request("POST", `/v1/projects/${projectId}/database/query`, { sql });
273
326
  }
274
- /**
275
- * Get database connection info for a project.
276
- *
277
- * Returns host, port, user, password, database name, and full connection string
278
- * that can be used with any PostgreSQL client (psql, pgAdmin, etc.).
279
- * The database must be enabled first (see enableDatabase).
280
- *
281
- * @param projectId - The project ID
282
- * @returns Database connection details
283
- */
284
- async getDatabaseConnectionInfo(projectId) {
285
- return this.request("GET", `/v1/projects/${projectId}/database/connection-info`);
286
- }
287
327
  // ---------------------------------------------------------------------------
288
328
  // Messages
289
329
  // ---------------------------------------------------------------------------
@@ -294,6 +334,17 @@ var LovableClient = class {
294
334
  async getMessage(projectId, messageId) {
295
335
  return this.request("GET", `/v1/projects/${projectId}/messages/${messageId}`);
296
336
  }
337
+ /**
338
+ * List recent messages in a project, newest first. Use `before` (a message ID
339
+ * from a prior page) to paginate backwards through history.
340
+ */
341
+ async listMessages(projectId, params) {
342
+ const qs = new URLSearchParams();
343
+ if (params?.limit !== void 0) qs.set("limit", String(params.limit));
344
+ if (params?.before) qs.set("before", params.before);
345
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
346
+ return this.request("GET", `/v1/projects/${projectId}/messages${suffix}`);
347
+ }
297
348
  /**
298
349
  * Poll for message completion. Waits until the AI response reaches a terminal
299
350
  * status (completed, stopped) or the timeout expires.
@@ -382,7 +433,10 @@ var LovableClient = class {
382
433
  // ---------------------------------------------------------------------------
383
434
  /** Get workspace knowledge (custom instructions for the AI agent). */
384
435
  async getWorkspaceKnowledge(workspaceId) {
385
- return this.request("GET", `/v1/workspaces/${workspaceId}/knowledge`);
436
+ const { data } = await this.typed.GET("/v1/workspaces/{workspace_id}/knowledge", {
437
+ params: { path: { workspace_id: workspaceId } }
438
+ });
439
+ return data;
386
440
  }
387
441
  /** Set workspace knowledge. Max 10,000 characters. */
388
442
  async setWorkspaceKnowledge(workspaceId, content) {
@@ -390,7 +444,10 @@ var LovableClient = class {
390
444
  }
391
445
  /** Get project knowledge (custom instructions for the AI agent). */
392
446
  async getProjectKnowledge(projectId) {
393
- return this.request("GET", `/v1/projects/${projectId}/knowledge`);
447
+ const { data } = await this.typed.GET("/v1/projects/{project_id}/knowledge", {
448
+ params: { path: { project_id: projectId } }
449
+ });
450
+ return data;
394
451
  }
395
452
  /** Set project knowledge. Max 10,000 characters. */
396
453
  async setProjectKnowledge(projectId, content) {
@@ -470,23 +527,26 @@ var LovableClient = class {
470
527
  );
471
528
  }
472
529
  // ---------------------------------------------------------------------------
473
- // MCP servers
530
+ // Connectors (MCP servers)
474
531
  // ---------------------------------------------------------------------------
475
- /** List all MCP servers connected to a workspace. */
476
- async listMCPServers(workspaceId) {
477
- return this.request("GET", `/v1/workspaces/${workspaceId}/mcp-servers`);
532
+ /** List all connectors in a workspace. */
533
+ async listConnectors(workspaceId) {
534
+ return this.request("GET", `/v1/workspaces/${workspaceId}/connectors`);
478
535
  }
479
- /** Add an MCP server to a workspace. The server URL is tested before saving. */
480
- async addMCPServer(workspaceId, body) {
481
- return this.request("POST", `/v1/workspaces/${workspaceId}/mcp-servers`, body);
536
+ /** Add a connector to a workspace. The server URL is tested before saving. */
537
+ async addConnector(workspaceId, body) {
538
+ return this.request("POST", `/v1/workspaces/${workspaceId}/connectors`, body);
482
539
  }
483
- /** Remove an MCP server from a workspace. */
484
- async removeMCPServer(workspaceId, serverId) {
485
- return this.request("DELETE", `/v1/workspaces/${workspaceId}/mcp-servers/${serverId}`);
540
+ /** Remove a connector from a workspace. */
541
+ async removeConnector(workspaceId, connectorId) {
542
+ return this.request("DELETE", `/v1/workspaces/${workspaceId}/connectors/${connectorId}`);
486
543
  }
487
- /** Browse available MCP server templates (catalog). */
488
- async listMCPCatalog(workspaceId) {
489
- return this.request("GET", `/v1/workspaces/${workspaceId}/mcp-catalog`);
544
+ /** Browse available connector templates. */
545
+ async listAvailableConnectors(workspaceId) {
546
+ return this.request(
547
+ "GET",
548
+ `/v1/workspaces/${workspaceId}/available-connectors`
549
+ );
490
550
  }
491
551
  // ---------------------------------------------------------------------------
492
552
  // Connectors
@@ -574,8 +634,7 @@ var LovableClient = class {
574
634
  include_custom_knowledge: options.includeCustomKnowledge,
575
635
  project_name: options.projectName,
576
636
  skip_initial_remix_message: options.skipInitialRemixMessage,
577
- skip_integrations: options.skipIntegrations,
578
- include_agent_state: options.includeAgentState
637
+ skip_integrations: options.skipIntegrations
579
638
  };
580
639
  if (options.messageId) {
581
640
  body.message_id = options.messageId;
@@ -589,7 +648,7 @@ var LovableClient = class {
589
648
  headless: true
590
649
  };
591
650
  }
592
- const response = await this.request("POST", `/projects/${sourceProjectId}/remix/init`, body);
651
+ const response = await this.request("POST", `/v1/projects/${sourceProjectId}/remix/init`, body);
593
652
  return response.job_id;
594
653
  }
595
654
  /**
@@ -612,7 +671,7 @@ var LovableClient = class {
612
671
  while (true) {
613
672
  const progress = await this.request(
614
673
  "GET",
615
- `/projects/${sourceProjectId}/remix/progress?job_id=${encodeURIComponent(jobId)}`
674
+ `/v1/projects/${sourceProjectId}/remix/progress?job_id=${encodeURIComponent(jobId)}`
616
675
  );
617
676
  options?.onProgress?.(progress.status, progress.step);
618
677
  if (progress.status === "completed" && progress.result) {