@lovable.dev/sdk 0.1.5 → 0.1.7
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 +0 -23
- package/dist/index.d.ts +17 -18
- package/dist/index.js +25 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,28 +79,6 @@ await client.chat(projectId, { message: "Add dark mode" });
|
|
|
79
79
|
const response = await client.waitForResponse(projectId);
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
### Remixing with agent state
|
|
83
|
-
|
|
84
|
-
Enable `includeAgentState` to carry over the agent's continuation state to the remixed project, allowing prompt cache reuse on the first follow-up message.
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
const jobId = await client.remixProject("source-project-id", {
|
|
88
|
-
workspaceId: "target-workspace-id",
|
|
89
|
-
messageId: "message-id-to-snapshot-at",
|
|
90
|
-
includeHistory: true,
|
|
91
|
-
includeCustomKnowledge: true,
|
|
92
|
-
includeAgentState: true,
|
|
93
|
-
});
|
|
94
|
-
const { projectId } = await client.waitForRemix("source-project-id", jobId);
|
|
95
|
-
|
|
96
|
-
await client.chat(projectId, {
|
|
97
|
-
message: "Add dark mode",
|
|
98
|
-
continuation: "allow_expired_cache",
|
|
99
|
-
});
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Requires `includeHistory`, `includeCustomKnowledge`, and API-key auth.
|
|
103
|
-
|
|
104
82
|
### Continuation override
|
|
105
83
|
|
|
106
84
|
The `continuation` option on `chat()` overrides prompt cache reuse behavior. API-key auth only.
|
|
@@ -310,7 +288,6 @@ Options:
|
|
|
310
288
|
- `remixMode` (optional): `"before"` (default) captures state before the message; `"including"` captures state after the message and its AI response
|
|
311
289
|
- `includeHistory` (optional, default: `false`): Whether to preserve chat history
|
|
312
290
|
- `includeCustomKnowledge` (optional, default: `false`): Whether to copy custom instructions/knowledge
|
|
313
|
-
- `includeAgentState` (optional, default: `false`): Copy agent continuation state so the prompt cache can be reused after remix. Requires `includeHistory: true`, `includeCustomKnowledge: true`, and API-key auth. See [Remixing with agent state](#remixing-with-agent-state-prompt-cache-continuation)
|
|
314
291
|
- `initialMessage` (optional): Initial chat message to send after remix completes
|
|
315
292
|
- `skipInitialRemixMessage` (optional, default: `false`): When true, suppresses the default "I've successfully remixed this project" message
|
|
316
293
|
- `skipIntegrations` (optional, default: `false`): When true, skips copying integrations to the remixed project
|
package/dist/index.d.ts
CHANGED
|
@@ -356,7 +356,7 @@ interface ReplayReviewsResponse {
|
|
|
356
356
|
results: BatchReplayReviewsOutcome;
|
|
357
357
|
}
|
|
358
358
|
type RemixJobStatus = "unknown" | "preparing" | "running" | "completed" | "error";
|
|
359
|
-
type RemixJobStep = "starting" | "creating_new_project" | "remixing_integration" | "finalizing" | "completed";
|
|
359
|
+
type RemixJobStep = "starting" | "creating_new_project" | "restoring_supabase" | "copying_history" | "preparing_repository" | "remixing_integration" | "pushing_repository" | "finalizing" | "completed";
|
|
360
360
|
interface RemixJobStepInfo {
|
|
361
361
|
step: RemixJobStep;
|
|
362
362
|
integration_name?: string;
|
|
@@ -373,8 +373,6 @@ interface RemixProjectOptions {
|
|
|
373
373
|
projectName?: string;
|
|
374
374
|
skipInitialRemixMessage?: boolean;
|
|
375
375
|
skipIntegrations?: boolean;
|
|
376
|
-
/** Copy agent continuation state so prompt cache can be reused after remix. Requires includeHistory. API-key auth only. */
|
|
377
|
-
includeAgentState?: boolean;
|
|
378
376
|
}
|
|
379
377
|
interface RemixResult {
|
|
380
378
|
projectId: string;
|
|
@@ -408,7 +406,8 @@ declare class ApiError extends Error {
|
|
|
408
406
|
readonly status: number;
|
|
409
407
|
readonly type?: string;
|
|
410
408
|
readonly detail?: string;
|
|
411
|
-
|
|
409
|
+
readonly props?: Record<string, unknown>;
|
|
410
|
+
constructor(status: number, message: string, type?: string, detail?: string, props?: Record<string, unknown>);
|
|
412
411
|
}
|
|
413
412
|
interface SendMessageResponse {
|
|
414
413
|
message_id: string;
|
|
@@ -546,7 +545,7 @@ interface TemplateProjectResponse {
|
|
|
546
545
|
description: string;
|
|
547
546
|
updated_at: string;
|
|
548
547
|
}
|
|
549
|
-
interface
|
|
548
|
+
interface ConnectorResponse {
|
|
550
549
|
id: string;
|
|
551
550
|
name: string;
|
|
552
551
|
url?: string;
|
|
@@ -554,7 +553,7 @@ interface MCPServerResponse {
|
|
|
554
553
|
connector_id?: string;
|
|
555
554
|
is_connected: boolean;
|
|
556
555
|
}
|
|
557
|
-
interface
|
|
556
|
+
interface AvailableConnectorEntry {
|
|
558
557
|
id: string;
|
|
559
558
|
display_name: string;
|
|
560
559
|
summary: string;
|
|
@@ -562,7 +561,7 @@ interface MCPCatalogEntry {
|
|
|
562
561
|
requires_custom_url?: boolean;
|
|
563
562
|
documentation_url?: string;
|
|
564
563
|
}
|
|
565
|
-
interface
|
|
564
|
+
interface AddConnectorBody {
|
|
566
565
|
name: string;
|
|
567
566
|
url: string;
|
|
568
567
|
auth_type: "none" | "bearer_token";
|
|
@@ -823,19 +822,19 @@ declare class LovableClient {
|
|
|
823
822
|
listTemplateProjects(workspaceId: string): Promise<{
|
|
824
823
|
templates: TemplateProjectResponse[];
|
|
825
824
|
}>;
|
|
826
|
-
/** List all
|
|
827
|
-
|
|
828
|
-
|
|
825
|
+
/** List all connectors in a workspace. */
|
|
826
|
+
listConnectors(workspaceId: string): Promise<{
|
|
827
|
+
connectors: ConnectorResponse[];
|
|
829
828
|
}>;
|
|
830
|
-
/** Add
|
|
831
|
-
|
|
832
|
-
/** Remove
|
|
833
|
-
|
|
829
|
+
/** Add a connector to a workspace. The server URL is tested before saving. */
|
|
830
|
+
addConnector(workspaceId: string, body: AddConnectorBody): Promise<ConnectorResponse>;
|
|
831
|
+
/** Remove a connector from a workspace. */
|
|
832
|
+
removeConnector(workspaceId: string, connectorId: string): Promise<{
|
|
834
833
|
success: boolean;
|
|
835
834
|
}>;
|
|
836
|
-
/** Browse available
|
|
837
|
-
|
|
838
|
-
catalog:
|
|
835
|
+
/** Browse available connector templates. */
|
|
836
|
+
listAvailableConnectors(workspaceId: string): Promise<{
|
|
837
|
+
catalog: AvailableConnectorEntry[];
|
|
839
838
|
}>;
|
|
840
839
|
/** List standard (OAuth-based) connectors in a workspace. */
|
|
841
840
|
listStandardConnectors(workspaceId: string): Promise<{
|
|
@@ -999,4 +998,4 @@ declare class LovableClient {
|
|
|
999
998
|
waitForProjectPublished(projectId: string, options?: WaitOptions): Promise<ProjectResponse>;
|
|
1000
999
|
}
|
|
1001
1000
|
|
|
1002
|
-
export { type
|
|
1001
|
+
export { type AddConnectorBody, type AddUserToWorkspaceInputBody, ApiError, type AvailableConnectorEntry, type BatchItemOutcome, type BatchReplayReviewsOutcome, type BatchTracesResult, type ChatMessageOptions, type ChatRequest, type ChatResponse, type ChatResponseOptions, type ConnectionItem, type ConnectorResponse, type ContinuationOverride, type CreateProjectBody, type CreateProjectOptions, type CustomModelConfig, type DatabaseConnectionInfo, type DatabaseQueryResult, type DatabaseStatus, type DeploymentResponse, type DiffEntry, type DiffHunk, type DiffLine, type EditSummary, type EditsResponse, type EnableDatabaseResult, type FileInput, type FileUploadUrlResponse, type GetMessageResponse, type GetMessageTracesOptions, type GitDiffResponse, type GitFileEntry, type GitFilesResponse, type InviteCollaboratorOptions, type KnowledgeResponse, type LibraryProjectResponse, type ListData, type ListDataPoint, type ListProjectItem, type ListProjectsOptions, type ListProjectsResponse, LovableClient, type LovableClientOptions, type LovableError, type MCPConnectorItem, type MeResponse, type MeWorkspace, type MemberRole, type MessageCompletionOptions, type MessageCompletionResult, type MessageTracesResponse, type ProjectAnalyticsResponse, type ProjectAnalyticsTrendResponse, type ProjectResponse, type ProjectStatus, type ProjectVisibility, type RemixJobStatus, type RemixJobStep, type RemixJobStepInfo, type RemixMode, type RemixProjectOptions, type RemixResult, type RemixWaitOptions, type ReplayOutcome, type ReplayReviewsItemInput, type ReplayReviewsRequestBody, type ReplayReviewsResponse, type ReviewerRunResult, type SeamlessConnectorItem, type SendMessageResponse, type StandardConnectorItem, type TemplateProjectResponse, type TimeSeriesData, type TimeSeriesDataPoint, type TracePurpose, type TraceQuery, type TraceSpan, type TrendDataPoint, type UnscopedFile, type WaitOptions, type WorkspaceMembership, type WorkspaceMembershipResponse, type WorkspaceWithMembership };
|
package/dist/index.js
CHANGED
|
@@ -3,11 +3,13 @@ var ApiError = class extends Error {
|
|
|
3
3
|
status;
|
|
4
4
|
type;
|
|
5
5
|
detail;
|
|
6
|
-
|
|
6
|
+
props;
|
|
7
|
+
constructor(status, message, type, detail, props) {
|
|
7
8
|
super(message);
|
|
8
9
|
this.status = status;
|
|
9
10
|
this.type = type;
|
|
10
11
|
this.detail = detail;
|
|
12
|
+
this.props = props;
|
|
11
13
|
}
|
|
12
14
|
};
|
|
13
15
|
|
|
@@ -60,7 +62,9 @@ var LovableClient = class {
|
|
|
60
62
|
} catch {
|
|
61
63
|
}
|
|
62
64
|
const message = errorBody?.message ?? errorBody?.title ?? `HTTP ${response.status}: ${response.statusText}`;
|
|
63
|
-
|
|
65
|
+
const type = errorBody?.type ?? errorBody?.title;
|
|
66
|
+
const detail = errorBody?.detail ?? errorBody?.details;
|
|
67
|
+
throw new ApiError(response.status, message, type, detail, errorBody?.props);
|
|
64
68
|
}
|
|
65
69
|
return response;
|
|
66
70
|
}
|
|
@@ -470,23 +474,26 @@ var LovableClient = class {
|
|
|
470
474
|
);
|
|
471
475
|
}
|
|
472
476
|
// ---------------------------------------------------------------------------
|
|
473
|
-
// MCP servers
|
|
477
|
+
// Connectors (MCP servers)
|
|
474
478
|
// ---------------------------------------------------------------------------
|
|
475
|
-
/** List all
|
|
476
|
-
async
|
|
477
|
-
return this.request("GET", `/v1/workspaces/${workspaceId}/
|
|
479
|
+
/** List all connectors in a workspace. */
|
|
480
|
+
async listConnectors(workspaceId) {
|
|
481
|
+
return this.request("GET", `/v1/workspaces/${workspaceId}/connectors`);
|
|
478
482
|
}
|
|
479
|
-
/** Add
|
|
480
|
-
async
|
|
481
|
-
return this.request("POST", `/v1/workspaces/${workspaceId}/
|
|
483
|
+
/** Add a connector to a workspace. The server URL is tested before saving. */
|
|
484
|
+
async addConnector(workspaceId, body) {
|
|
485
|
+
return this.request("POST", `/v1/workspaces/${workspaceId}/connectors`, body);
|
|
482
486
|
}
|
|
483
|
-
/** Remove
|
|
484
|
-
async
|
|
485
|
-
return this.request("DELETE", `/v1/workspaces/${workspaceId}/
|
|
487
|
+
/** Remove a connector from a workspace. */
|
|
488
|
+
async removeConnector(workspaceId, connectorId) {
|
|
489
|
+
return this.request("DELETE", `/v1/workspaces/${workspaceId}/connectors/${connectorId}`);
|
|
486
490
|
}
|
|
487
|
-
/** Browse available
|
|
488
|
-
async
|
|
489
|
-
return this.request(
|
|
491
|
+
/** Browse available connector templates. */
|
|
492
|
+
async listAvailableConnectors(workspaceId) {
|
|
493
|
+
return this.request(
|
|
494
|
+
"GET",
|
|
495
|
+
`/v1/workspaces/${workspaceId}/available-connectors`
|
|
496
|
+
);
|
|
490
497
|
}
|
|
491
498
|
// ---------------------------------------------------------------------------
|
|
492
499
|
// Connectors
|
|
@@ -574,8 +581,7 @@ var LovableClient = class {
|
|
|
574
581
|
include_custom_knowledge: options.includeCustomKnowledge,
|
|
575
582
|
project_name: options.projectName,
|
|
576
583
|
skip_initial_remix_message: options.skipInitialRemixMessage,
|
|
577
|
-
skip_integrations: options.skipIntegrations
|
|
578
|
-
include_agent_state: options.includeAgentState
|
|
584
|
+
skip_integrations: options.skipIntegrations
|
|
579
585
|
};
|
|
580
586
|
if (options.messageId) {
|
|
581
587
|
body.message_id = options.messageId;
|
|
@@ -589,7 +595,7 @@ var LovableClient = class {
|
|
|
589
595
|
headless: true
|
|
590
596
|
};
|
|
591
597
|
}
|
|
592
|
-
const response = await this.request("POST", `/projects/${sourceProjectId}/remix/init`, body);
|
|
598
|
+
const response = await this.request("POST", `/v1/projects/${sourceProjectId}/remix/init`, body);
|
|
593
599
|
return response.job_id;
|
|
594
600
|
}
|
|
595
601
|
/**
|
|
@@ -612,7 +618,7 @@ var LovableClient = class {
|
|
|
612
618
|
while (true) {
|
|
613
619
|
const progress = await this.request(
|
|
614
620
|
"GET",
|
|
615
|
-
`/projects/${sourceProjectId}/remix/progress?job_id=${encodeURIComponent(jobId)}`
|
|
621
|
+
`/v1/projects/${sourceProjectId}/remix/progress?job_id=${encodeURIComponent(jobId)}`
|
|
616
622
|
);
|
|
617
623
|
options?.onProgress?.(progress.status, progress.step);
|
|
618
624
|
if (progress.status === "completed" && progress.result) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"sourcesContent":["// Type definitions for the Lovable SDK\n// These are self-contained and don't require external dependencies\n\nexport type ProjectVisibility = \"draft\" | \"private\" | \"public\";\nexport type MemberRole = \"admin\" | \"collaborator\" | \"invited\" | \"member\" | \"none\" | \"owner\" | \"viewer\";\nexport type ProjectStatus = \"completed\" | \"in_progress\" | \"failed\";\n\nexport interface MeWorkspace {\n id: string;\n name: string;\n role: string;\n}\n\nexport interface MeResponse {\n id: string;\n email: string;\n name: string;\n workspaces: MeWorkspace[];\n}\n\nexport interface WorkspaceMembership {\n email: string;\n invited_at?: string;\n joined_at?: string;\n monthly_credit_limit: number | null;\n project_access?: Record<string, { access_level?: string }>;\n role: MemberRole;\n user_id: string;\n workspace_id: string;\n}\n\nexport interface WorkspaceWithMembership {\n id: string;\n name: string;\n description?: string;\n image_url?: string;\n owner_id?: string;\n is_personal?: boolean;\n plan?: string;\n plan_type?: string;\n num_projects: number;\n num_seats?: number;\n membership: WorkspaceMembership;\n created_at: string;\n updated_at: string;\n deleted_at?: string;\n credits_granted: number;\n credits_used: number;\n daily_credits_limit: number;\n daily_credits_used: number;\n billing_period_credits_limit: number;\n billing_period_credits_used: number;\n billing_period_start_date?: string;\n billing_period_end_date?: string;\n rollover_credits_limit: number;\n rollover_credits_used: number;\n topup_credits_limit: number;\n topup_credits_used: number;\n total_credits_used: number;\n subscription_status?:\n | \"active\"\n | \"canceled\"\n | \"incomplete_expired\"\n | \"incomplete\"\n | \"past_due\"\n | \"paused\"\n | \"trialing\"\n | \"unpaid\";\n referral_code?: string;\n short_referral_code?: string;\n referral_count: number;\n followers_count: number;\n default_project_visibility?: ProjectVisibility;\n default_project_publish_visibility?: \"private\" | \"public\";\n mcp_enabled?: boolean;\n}\n\nexport interface WorkspaceMembershipResponse {\n user_id: string;\n username: string;\n display_name?: string;\n email?: string;\n role: MemberRole;\n invited_at?: string;\n joined_at?: string;\n monthly_credit_limit?: number;\n total_credits_used?: number;\n total_credits_used_in_billing_period?: number;\n project_access?: Record<string, { access_level?: string }>;\n}\n\n/**\n * Project response from the API.\n *\n * The v1 endpoints (getProject, createProject) return a lean subset:\n * id, workspace_id, name, display_name, description, status, visibility,\n * is_published, url. Other fields are available from list endpoints.\n */\nexport interface ProjectResponse {\n id: string;\n name?: string;\n display_name?: string;\n description?: string;\n tech_stack?: string;\n status?: string;\n visibility?: ProjectVisibility;\n publish_visibility?: \"private\" | \"public\";\n is_published?: boolean;\n /** Present in create project response when initial_message was provided */\n message_id?: string;\n is_starred?: boolean;\n is_template?: boolean;\n is_github?: boolean;\n is_supabase_enabled?: boolean;\n url?: string;\n og_image_url?: string;\n latest_screenshot_url?: string;\n user_id?: string;\n user_display_name?: string;\n user_photo_url?: string;\n created_at?: string;\n created_by?: string;\n updated_at?: string;\n deleted_at?: string;\n last_edited_at?: string;\n last_viewed_at?: string;\n published_at?: string;\n workspace_id?: string;\n folder_id?: string;\n category?: string;\n edit_count?: number;\n gen_count?: number;\n user_message_count?: number;\n remix_count?: number;\n remixed_from_project_id?: string;\n template_project_id?: string;\n credit_total?: number;\n custom_instructions?: string;\n main_branch?: string;\n latest_commit_sha?: string;\n github_repo_name?: string;\n github_repo_id?: number;\n deployment_target?: string;\n active_deployment_job_id?: string;\n environments_enabled?: boolean;\n hide_badge?: boolean | null;\n featured?: boolean;\n featured_at?: string;\n feature_rank?: number;\n feature_source?: string;\n}\n\nexport interface UnscopedFile {\n file_id: string;\n type: \"user_upload\";\n file_name?: string;\n mime_type?: string;\n}\n\nexport interface FileInput {\n name: string;\n data: Blob | ArrayBuffer | Uint8Array;\n type: string;\n}\n\n/**\n * Configuration to use a custom OpenAI-compatible model as the main agent.\n */\nexport interface CustomModelConfig {\n /** Base URL of the OpenAI-compatible API (e.g. \"https://my-vllm.example.com/v1\") */\n endpoint: string;\n /** API key for the custom endpoint */\n apiKey: string;\n /** Model identifier sent in the request (e.g. \"my-org/my-model-id\") */\n modelName: string;\n}\n\nexport interface ChatRequest {\n id: string;\n message: string;\n chat_only: boolean;\n headless: boolean;\n ai_message_id?: string;\n intent?: string;\n model?: string;\n temperature?: number;\n current_page?: string;\n view?: string;\n view_description?: string;\n prev_session_id?: string;\n is_creation?: boolean;\n files?: UnscopedFile[];\n custom_model_endpoint?: string;\n custom_model_api_key?: string;\n custom_model_name?: string;\n custom_model_disable_race?: boolean;\n}\n\nexport interface CreateProjectBody {\n description: string;\n tech_stack?: string;\n visibility?: ProjectVisibility;\n template_project_id?: string;\n initial_message?: string;\n files?: UnscopedFile[];\n selected_libraries?: { project_id: string }[];\n category?: string;\n project_type?: string;\n prompt_name?: string;\n selected_theme?: string;\n env_vars?: Record<string, string>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AddUserToWorkspaceInputBody {\n email: string;\n role?: MemberRole;\n}\n\nexport interface GetWorkspacesResponse {\n workspaces: WorkspaceWithMembership[] | null;\n}\n\nexport interface GetWorkspaceProjectsResponse {\n projects: ProjectResponse[] | null;\n}\n\nexport interface CreateProjectOptions {\n description: string;\n techStack?: string;\n visibility?: ProjectVisibility;\n templateProjectId?: string;\n initialMessage?: string;\n /** Files to upload and attach to the initial message. The SDK handles uploading. */\n files?: (File | FileInput)[];\n /** Pre-uploaded file references to attach to the initial message. Skips upload. */\n uploadedFiles?: UnscopedFile[];\n /** Design system library projects to connect to the new project. */\n selectedLibraries?: { project_id: string }[];\n}\n\nexport interface InviteCollaboratorOptions {\n email: string;\n role?: MemberRole;\n}\n\n/**\n * Controls prompt cache continuation behavior for a message.\n *\n * - `\"force\"` — skip cache TTL and token/criteria checks (force continuation)\n * - `\"fresh_build\"` — force a full prompt rebuild from scratch\n * - `\"allow_expired_cache\"` — skip cache TTL check but respect token/criteria limits\n *\n * Omit for default behavior (5-min TTL, token and criteria checks apply).\n */\nexport type ContinuationOverride = \"force\" | \"fresh_build\" | \"allow_expired_cache\";\n\nexport interface ChatMessageOptions {\n message: string;\n /** Files to upload and attach. The SDK handles uploading them first. */\n files?: (File | FileInput)[];\n /** Pre-uploaded file references (already uploaded via getFileUploadUrl). Skips upload. */\n uploadedFiles?: UnscopedFile[];\n /** Enable plan mode: the agent discusses and plans without editing code. */\n planMode?: boolean;\n customModel?: CustomModelConfig;\n /**\n * When true, the server may skip staggered inference racing for that request if your\n * custom model endpoint supports it; otherwise the request fails with a validation error.\n * API key authentication only. Sent as `custom_model_disable_race` in the JSON body.\n */\n customModelDisableRace?: boolean;\n /**\n * Override continuation behavior for this message.\n * Controls whether the agent reuses the prompt cache or rebuilds from scratch.\n */\n continuation?: ContinuationOverride;\n}\n\nexport interface LovableClientOptions {\n /** API key for authentication (mutually exclusive with bearerToken) */\n apiKey?: string;\n /** Bearer token for OAuth authentication (mutually exclusive with apiKey) */\n bearerToken?: string;\n baseUrl?: string;\n /** Additional headers to include on every request */\n headers?: Record<string, string>;\n}\n\nexport interface LovableError extends Error {\n status: number;\n type?: string;\n detail?: string;\n}\n\nexport interface WaitOptions {\n pollInterval?: number;\n timeout?: number;\n onProgress?: (project: ProjectResponse) => void;\n}\n\nexport interface DeploymentResponse {\n status: string;\n deployment_id?: string;\n url?: string;\n}\n\nexport interface ChatResponse {\n content: string;\n previewUrl: string;\n messageId: string;\n}\n\nexport interface ChatResponseOptions {\n timeout?: number;\n}\n\n// --- Trace types ---\n\nexport type TracePurpose = \"main_agent\" | \"codebase_rag\" | \"knowledge_rag\" | \"review\";\n\nexport interface TraceSpan {\n span_id: string;\n root_span_id?: string;\n span_parents?: unknown;\n span_name?: string;\n span_type?: string;\n purpose?: string;\n subpurpose?: string;\n created?: string;\n input?: unknown;\n output?: unknown;\n error?: unknown;\n metadata?: unknown;\n metrics?: unknown;\n scores?: unknown;\n tags?: unknown;\n}\n\nexport interface MessageTracesResponse {\n message_id: string;\n braintrust_span_id: string;\n root_span_id: string;\n response_message_id?: string;\n spans: TraceSpan[];\n}\n\nexport interface GetMessageTracesOptions {\n purposes?: TracePurpose[];\n}\n\nexport interface TraceQuery {\n projectId: string;\n messageId: string;\n}\n\nexport interface BatchTracesResult {\n traces: Map<string, MessageTracesResponse>;\n errors: Map<string, Error>;\n}\n\n// --- On-demand review replay (`/v1/_dev/.../reviews/replay`) — typed in SDK only ---\n\nexport interface ReplayReviewsItemInput {\n /** Assistant (AI) message id for the turn to score */\n response_message_id: string;\n /** Optional per-item reviewer types */\n reviewer_types?: string[] | null;\n}\n\nexport interface ReplayReviewsRequestBody {\n items: ReplayReviewsItemInput[];\n /** Defaults to project_success_v3 and user_sentiment when omitted */\n reviewer_types?: string[] | null;\n /** Parallel items (default 4, max 16) */\n concurrency?: number;\n}\n\nexport interface ReviewerRunResult {\n reviewer_type: string;\n score?: number;\n message?: string;\n model?: string;\n published_rubric_rows: number;\n error?: string;\n}\n\nexport interface ReplayOutcome {\n response_message_id: string;\n user_message_id: string;\n results: ReviewerRunResult[] | null;\n}\n\nexport interface BatchItemOutcome {\n response_message_id: string;\n ok: boolean;\n error?: string;\n replay?: ReplayOutcome;\n}\n\nexport interface BatchReplayReviewsOutcome {\n items: BatchItemOutcome[];\n}\n\nexport interface ReplayReviewsResponse {\n results: BatchReplayReviewsOutcome;\n}\n\n// --- Remix types ---\n\nexport type RemixJobStatus = \"unknown\" | \"preparing\" | \"running\" | \"completed\" | \"error\";\n\nexport type RemixJobStep = \"starting\" | \"creating_new_project\" | \"remixing_integration\" | \"finalizing\" | \"completed\";\n\nexport interface RemixJobStepInfo {\n step: RemixJobStep;\n integration_name?: string;\n status?: string;\n}\n\nexport type RemixMode = \"before\" | \"including\";\n\nexport interface RemixProjectOptions {\n workspaceId: string;\n messageId?: string;\n remixMode?: RemixMode;\n includeHistory?: boolean;\n includeCustomKnowledge?: boolean;\n initialMessage?: string;\n projectName?: string;\n skipInitialRemixMessage?: boolean;\n skipIntegrations?: boolean;\n /** Copy agent continuation state so prompt cache can be reused after remix. Requires includeHistory. API-key auth only. */\n includeAgentState?: boolean;\n}\n\nexport interface RemixInitBody {\n workspace_id: string;\n message_id?: string;\n remix_mode?: RemixMode;\n include_history?: boolean;\n include_custom_knowledge?: boolean;\n initial_message?: ChatRequest;\n project_name?: string;\n skip_initial_remix_message?: boolean;\n skip_integrations?: boolean;\n include_agent_state?: boolean;\n}\n\nexport interface RemixInitResponse {\n job_id: string;\n}\n\nexport interface RemixProgressResult {\n project_id: string;\n}\n\nexport interface RemixProgressResponse {\n status: RemixJobStatus;\n step?: RemixJobStepInfo;\n error_message?: string;\n result?: RemixProgressResult;\n}\n\nexport interface RemixResult {\n projectId: string;\n}\n\nexport interface RemixWaitOptions {\n pollInterval?: number;\n timeout?: number;\n onProgress?: (status: RemixJobStatus, step?: RemixJobStepInfo) => void;\n}\n\n// --- Database types ---\n\nexport interface DatabaseStatus {\n enabled: boolean;\n stack?: string;\n}\n\nexport interface EnableDatabaseResult {\n enabled: boolean;\n stack: string;\n}\n\nexport interface DatabaseQueryResult {\n rows: Record<string, unknown>[] | null;\n}\n\nexport interface DatabaseConnectionInfo {\n host: string;\n port: string;\n user: string;\n password: string;\n database: string;\n connection_string: string;\n api_url: string;\n}\n\n// --- API Error ---\n\nexport class ApiError extends Error {\n readonly status: number;\n readonly type?: string;\n readonly detail?: string;\n\n constructor(status: number, message: string, type?: string, detail?: string) {\n super(message);\n this.status = status;\n this.type = type;\n this.detail = detail;\n }\n}\n\n// --- Send message response ---\n\nexport interface SendMessageResponse {\n message_id: string;\n status: string;\n}\n\n// --- Get message response ---\n\nexport interface GetMessageResponse {\n message_id: string;\n role: string;\n content: string;\n status: string;\n created_at: string;\n edit_id?: string;\n commit_sha?: string;\n summary?: string;\n cost_credits?: number;\n response?: {\n message_id: string;\n status: string;\n content: string;\n edit_id?: string;\n commit_sha?: string;\n summary?: string;\n cost_credits?: number;\n };\n queue_position?: number;\n queue_paused?: boolean;\n queue_pause_reason?: string;\n}\n\nexport interface MessageCompletionResult {\n status: \"completed\" | \"timeout\" | \"error\";\n message_id: string;\n content: string;\n edit_id?: string;\n commit_sha?: string;\n summary?: string;\n cost_credits?: number;\n error?: string;\n}\n\nexport interface MessageCompletionOptions {\n /** Time between polls in ms (default: 3000) */\n pollInterval?: number;\n /** Maximum time to wait in ms (default: 600000 = 10 minutes) */\n timeout?: number;\n}\n\n// --- Knowledge ---\n\nexport interface KnowledgeResponse {\n content: string;\n}\n\n// --- File upload ---\n\nexport interface FileUploadUrlResponse {\n url: string;\n file_id: string;\n}\n\n// --- Git types ---\n\nexport interface DiffLine {\n type: string;\n content: string;\n}\n\nexport interface DiffHunk {\n oldStart: number;\n oldCount: number;\n newStart: number;\n newCount: number;\n lines: DiffLine[];\n}\n\nexport interface DiffEntry {\n action: string;\n file_path: string;\n original_file_path?: string;\n file_type?: string;\n is_image: boolean;\n is_incomplete?: boolean;\n hunks?: DiffHunk[];\n}\n\nexport interface GitDiffResponse {\n diffs: DiffEntry[];\n error?: string;\n}\n\nexport interface GitFileEntry {\n path: string;\n size: number;\n binary: boolean;\n}\n\nexport interface GitFilesResponse {\n files: GitFileEntry[];\n ref: string;\n}\n\n// --- Edits ---\n\nexport interface EditSummary {\n id: string;\n type: string;\n commit_sha?: string;\n commit_message?: string;\n status: string;\n created_at: string;\n}\n\nexport interface EditsResponse {\n edits: EditSummary[];\n has_more: boolean;\n}\n\n// --- List projects (expanded) ---\n\nexport interface ListProjectItem extends ProjectResponse {\n user_id?: string;\n is_template?: boolean;\n is_starred?: boolean;\n created_at?: string;\n updated_at?: string;\n last_edited_at?: string;\n last_viewed_at?: string;\n edit_count?: number;\n remix_count?: number;\n}\n\nexport interface ListProjectsResponse {\n projects: ListProjectItem[];\n total: number;\n has_more: boolean;\n}\n\nexport interface ListProjectsOptions {\n query?: string;\n visibility?: string;\n publish_status?: string;\n folder_id?: string;\n user_id?: string;\n sort_by?: string;\n sort_order?: string;\n viewed_by_me?: boolean;\n limit?: number;\n offset?: number;\n cursor?: string;\n}\n\n// --- Library & template projects ---\n\nexport interface LibraryProjectResponse {\n id: string;\n name: string | null;\n description: string;\n updated_at: string;\n}\n\nexport interface TemplateProjectResponse {\n id: string;\n name: string | null;\n description: string;\n updated_at: string;\n}\n\n// --- MCP servers ---\n\nexport interface MCPServerResponse {\n id: string;\n name: string;\n url?: string;\n auth_type: string;\n connector_id?: string;\n is_connected: boolean;\n}\n\nexport interface MCPCatalogEntry {\n id: string;\n display_name: string;\n summary: string;\n category: string;\n requires_custom_url?: boolean;\n documentation_url?: string;\n}\n\nexport interface AddMCPServerBody {\n name: string;\n url: string;\n auth_type: \"none\" | \"bearer_token\";\n connector_id?: string;\n token?: string;\n}\n\n// --- Connectors ---\n\nexport interface StandardConnectorItem {\n id: string;\n display_name: string;\n short_description: string;\n categories: string[];\n is_enabled_for_workspace: boolean;\n auth_type: string;\n logo_id?: string;\n documentation_url?: string;\n connection_scope?: string;\n}\n\nexport interface SeamlessConnectorItem {\n id: string;\n display_name: string;\n short_description: string;\n categories: string[];\n is_enabled_for_workspace: boolean;\n logo_id?: string;\n documentation_url?: string;\n}\n\nexport interface MCPConnectorItem {\n id: string;\n display_name: string;\n summary: string;\n status: string;\n is_enabled_for_workspace: boolean;\n is_connected: boolean;\n connector_id?: string;\n documentation_url?: string;\n}\n\nexport interface ConnectionItem {\n id: string;\n connector_id: string;\n display_name: string;\n is_managed: boolean;\n status: string;\n created_at: string;\n updated_at: string;\n}\n\n// --- Analytics ---\n\nexport interface TimeSeriesDataPoint {\n date: string;\n value: number;\n}\n\nexport interface TimeSeriesData {\n total: number;\n label: string;\n data: TimeSeriesDataPoint[];\n}\n\nexport interface ListDataPoint {\n label: string;\n value: number;\n}\n\nexport interface ListData {\n label: string;\n data: ListDataPoint[];\n}\n\nexport interface ProjectAnalyticsResponse {\n timeSeries: {\n visitors: TimeSeriesData;\n pageviews: TimeSeriesData;\n pageviewsPerVisit: TimeSeriesData;\n sessionDuration: TimeSeriesData;\n bounceRate: TimeSeriesData;\n };\n lists: {\n page: ListData;\n source: ListData;\n device: ListData;\n country: ListData;\n };\n}\n\nexport interface TrendDataPoint {\n time: string;\n visits: number;\n}\n\nexport interface ProjectAnalyticsTrendResponse {\n data: TrendDataPoint[];\n currentVisitors: number;\n}\n","import type {\n LovableClientOptions,\n CreateProjectOptions,\n InviteCollaboratorOptions,\n ChatMessageOptions,\n WaitOptions,\n WorkspaceWithMembership,\n ProjectResponse,\n WorkspaceMembershipResponse,\n CreateProjectBody,\n AddUserToWorkspaceInputBody,\n GetWorkspacesResponse,\n DeploymentResponse,\n ChatResponse,\n ChatResponseOptions,\n UnscopedFile,\n FileInput,\n RemixProjectOptions,\n RemixInitBody,\n RemixInitResponse,\n RemixProgressResponse,\n RemixResult,\n RemixWaitOptions,\n MessageTracesResponse,\n GetMessageTracesOptions,\n TraceQuery,\n BatchTracesResult,\n ReplayReviewsRequestBody,\n ReplayReviewsResponse,\n MeResponse,\n DatabaseStatus,\n EnableDatabaseResult,\n DatabaseQueryResult,\n DatabaseConnectionInfo,\n SendMessageResponse,\n GetMessageResponse,\n MessageCompletionResult,\n MessageCompletionOptions,\n KnowledgeResponse,\n FileUploadUrlResponse,\n GitDiffResponse,\n GitFilesResponse,\n EditsResponse,\n ListProjectsResponse,\n ListProjectsOptions,\n MCPServerResponse,\n MCPCatalogEntry,\n AddMCPServerBody,\n StandardConnectorItem,\n SeamlessConnectorItem,\n MCPConnectorItem,\n ConnectionItem,\n ProjectAnalyticsResponse,\n ProjectAnalyticsTrendResponse,\n LibraryProjectResponse,\n TemplateProjectResponse,\n} from \"./types.js\";\n\nimport { ApiError } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.lovable.dev\";\n\nfunction normalizeBaseUrl(url: string | undefined): string {\n if (!url) return DEFAULT_BASE_URL;\n\n const normalized = url.replace(/\\/$/, \"\");\n\n if (!normalized.startsWith(\"http://\") && !normalized.startsWith(\"https://\")) {\n throw new Error(`baseUrl must include a protocol (http:// or https://). Got: \"${url}\"`);\n }\n\n return normalized;\n}\n\nexport class LovableClient {\n private readonly authHeaders: Record<string, string>;\n private readonly baseUrl: string;\n private readonly extraHeaders: Record<string, string>;\n\n constructor(options: LovableClientOptions) {\n const hasApiKey = !!options.apiKey;\n const hasBearerToken = !!options.bearerToken;\n\n if (!hasApiKey && !hasBearerToken) {\n throw new Error(\"Either apiKey or bearerToken is required\");\n }\n if (hasApiKey && hasBearerToken) {\n throw new Error(\"Provide either apiKey or bearerToken, not both\");\n }\n\n this.authHeaders = hasApiKey\n ? { \"Lovable-API-Key\": options.apiKey! }\n : { Authorization: `Bearer ${options.bearerToken}` };\n\n this.baseUrl = normalizeBaseUrl(options.baseUrl);\n this.extraHeaders = options.headers ?? {};\n }\n\n private async rawRequest(method: string, path: string, body?: unknown): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n ...this.authHeaders,\n ...this.extraHeaders,\n Accept: \"application/json\",\n };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n let errorBody: { title?: string; message?: string; detail?: string } | undefined;\n try {\n errorBody = (await response.json()) as { title?: string; message?: string; detail?: string };\n } catch {\n // Ignore JSON parse errors\n }\n\n const message = errorBody?.message ?? errorBody?.title ?? `HTTP ${response.status}: ${response.statusText}`;\n throw new ApiError(response.status, message, errorBody?.title, errorBody?.detail);\n }\n\n return response;\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const response = await this.rawRequest(method, path, body);\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n private async requestText(method: string, path: string): Promise<string> {\n const response = await this.rawRequest(method, path);\n return response.text();\n }\n\n /**\n * Get the current authenticated user and their workspaces.\n * Useful for validating an API key and discovering workspace IDs.\n */\n async me(): Promise<MeResponse> {\n return this.request<MeResponse>(\"GET\", \"/v1/me\");\n }\n\n /**\n * List all workspaces the authenticated user has access to\n */\n async listWorkspaces(): Promise<WorkspaceWithMembership[]> {\n const response = await this.request<GetWorkspacesResponse>(\"GET\", \"/v1/workspaces\");\n return response.workspaces ?? [];\n }\n\n /**\n * Get a specific workspace by ID\n */\n async getWorkspace(workspaceId: string): Promise<WorkspaceWithMembership> {\n const response = await this.request<{ workspace: WorkspaceWithMembership }>(\"GET\", `/v1/workspaces/${workspaceId}`);\n return response.workspace;\n }\n\n /**\n * List projects in a workspace.\n * Supports full-text search, filtering by visibility/publish status/folder/creator,\n * and pagination via offset or cursor.\n */\n async listProjects(workspaceId: string, options?: ListProjectsOptions): Promise<ListProjectsResponse> {\n const params = new URLSearchParams();\n if (options?.query) params.set(\"q\", options.query);\n if (options?.visibility) params.set(\"visibility\", options.visibility);\n if (options?.publish_status) params.set(\"publish_status\", options.publish_status);\n if (options?.folder_id) params.set(\"folder_id\", options.folder_id);\n if (options?.user_id) params.set(\"user_id\", options.user_id);\n if (options?.sort_by) params.set(\"sort_by\", options.sort_by);\n if (options?.sort_order) params.set(\"sort_order\", options.sort_order);\n if (options?.viewed_by_me) params.set(\"viewed_by_me\", \"true\");\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined) params.set(\"offset\", String(options.offset));\n if (options?.cursor) params.set(\"cursor\", options.cursor);\n\n const query = params.toString();\n const path = `/v1/workspaces/${workspaceId}/projects${query ? `?${query}` : \"\"}`;\n\n return this.request<ListProjectsResponse>(\"GET\", path);\n }\n\n /**\n * Create a new project in a workspace\n */\n async createProject(workspaceId: string, options: CreateProjectOptions): Promise<ProjectResponse> {\n let fileRefs: UnscopedFile[] | undefined;\n if (options.uploadedFiles?.length) {\n fileRefs = options.uploadedFiles;\n } else if (options.files?.length) {\n fileRefs = await this.uploadFiles(options.files);\n }\n\n const body: CreateProjectBody = {\n description: options.description,\n visibility: options.visibility ?? \"private\",\n template_project_id: options.templateProjectId,\n };\n if (options.techStack) {\n body.tech_stack = options.techStack;\n }\n if (options.selectedLibraries?.length) {\n body.selected_libraries = options.selectedLibraries;\n }\n\n if (options.initialMessage) {\n body.initial_message = options.initialMessage;\n }\n if (fileRefs?.length) {\n body.files = fileRefs;\n }\n\n const project = await this.request<ProjectResponse>(\"POST\", `/v1/workspaces/${workspaceId}/projects`, body);\n\n return project;\n }\n\n /**\n * Send a chat message to a project.\n *\n * The API accepts the message and processes it in the background.\n * Returns the message ID and status. Use `waitForMessageCompletion()`\n * to poll for the AI response, or `waitForResponse()` for SSE streaming.\n */\n async chat(projectId: string, options: ChatMessageOptions): Promise<SendMessageResponse> {\n let fileRefs: UnscopedFile[] | undefined;\n if (options.uploadedFiles?.length) {\n fileRefs = options.uploadedFiles;\n } else if (options.files?.length) {\n fileRefs = await this.uploadFiles(options.files);\n }\n\n const body: {\n message: string;\n files?: UnscopedFile[];\n plan_mode?: boolean;\n custom_model_endpoint?: string;\n custom_model_api_key?: string;\n custom_model_name?: string;\n custom_model_disable_race?: boolean;\n continuation?: string;\n } = {\n message: options.message,\n };\n if (fileRefs) {\n body.files = fileRefs;\n }\n if (options.planMode) {\n body.plan_mode = true;\n }\n if (options.customModel) {\n body.custom_model_endpoint = options.customModel.endpoint;\n body.custom_model_api_key = options.customModel.apiKey;\n body.custom_model_name = options.customModel.modelName;\n }\n if (options.customModelDisableRace) {\n body.custom_model_disable_race = true;\n }\n if (options.continuation) {\n body.continuation = options.continuation;\n }\n\n return this.request<SendMessageResponse>(\"POST\", `/v1/projects/${projectId}/messages`, body);\n }\n\n /**\n * Invite a user to a workspace as a collaborator\n */\n async inviteCollaborator(\n workspaceId: string,\n options: InviteCollaboratorOptions,\n ): Promise<WorkspaceMembershipResponse> {\n const body: AddUserToWorkspaceInputBody = {\n email: options.email,\n role: options.role ?? \"member\",\n };\n\n return this.request<WorkspaceMembershipResponse>(\"POST\", `/workspaces/${workspaceId}/memberships`, body);\n }\n\n /**\n * List members of a workspace\n */\n async listWorkspaceMembers(workspaceId: string): Promise<WorkspaceMembershipResponse[]> {\n const response = await this.request<{\n memberships: WorkspaceMembershipResponse[] | null;\n }>(\"GET\", `/workspaces/${workspaceId}/memberships`);\n return response.memberships ?? [];\n }\n\n /**\n * Remove a member from a workspace\n */\n async removeWorkspaceMember(workspaceId: string, userId: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/workspaces/${workspaceId}/memberships/${userId}`);\n }\n\n /**\n * Get project details by ID\n */\n async getProject(projectId: string): Promise<ProjectResponse> {\n return this.request<ProjectResponse>(\"GET\", `/v1/projects/${projectId}`);\n }\n\n /**\n * Get the preview URL for a project.\n *\n * The preview URL is available once the project reaches \"completed\" status.\n * This URL allows viewing the project in development mode.\n *\n * @param projectId - The project ID\n * @returns The preview URL\n */\n getPreviewUrl(projectId: string): string {\n return `https://id-preview--${projectId}.lovable.app`;\n }\n\n /**\n * Get the published URL for a project (if published).\n *\n * Returns the public URL if the project has been published, or null if not.\n *\n * @param projectId - The project ID\n * @returns The published URL or null if not published\n */\n async getPublishedUrl(projectId: string): Promise<string | null> {\n const project = await this.getProject(projectId);\n return project.is_published && project.url ? project.url : null;\n }\n\n /**\n * Get the cloud database status for a project.\n *\n * @param projectId - The project ID\n * @returns Whether the database is enabled and which stack is used\n */\n async getDatabaseStatus(projectId: string): Promise<DatabaseStatus> {\n return this.request<DatabaseStatus>(\"GET\", `/v1/projects/${projectId}/database`);\n }\n\n /**\n * Enable (provision) a cloud database for a project.\n *\n * This triggers database provisioning which takes 30-60 seconds.\n * The call blocks until provisioning completes.\n *\n * @param projectId - The project ID\n * @returns The database status after enablement\n */\n async enableDatabase(projectId: string): Promise<EnableDatabaseResult> {\n return this.request<EnableDatabaseResult>(\"POST\", `/v1/projects/${projectId}/database/enable`);\n }\n\n /**\n * Execute a SQL query against the project's cloud database.\n *\n * Supports SELECT, INSERT, UPDATE, DELETE, and DDL statements.\n * The database must be enabled first (see enableDatabase).\n *\n * @param projectId - The project ID\n * @param sql - SQL query to execute\n * @returns Query result rows as JSON objects\n */\n async queryDatabase(projectId: string, sql: string): Promise<DatabaseQueryResult> {\n return this.request<DatabaseQueryResult>(\"POST\", `/v1/projects/${projectId}/database/query`, { sql });\n }\n\n /**\n * Get database connection info for a project.\n *\n * Returns host, port, user, password, database name, and full connection string\n * that can be used with any PostgreSQL client (psql, pgAdmin, etc.).\n * The database must be enabled first (see enableDatabase).\n *\n * @param projectId - The project ID\n * @returns Database connection details\n */\n async getDatabaseConnectionInfo(projectId: string): Promise<DatabaseConnectionInfo> {\n return this.request<DatabaseConnectionInfo>(\"GET\", `/v1/projects/${projectId}/database/connection-info`);\n }\n\n // ---------------------------------------------------------------------------\n // Messages\n // ---------------------------------------------------------------------------\n\n /**\n * Get a message by ID. Returns the message content, status, and (for user messages)\n * the AI response if available. Use to poll for completion after `chat()`.\n */\n async getMessage(projectId: string, messageId: string): Promise<GetMessageResponse> {\n return this.request<GetMessageResponse>(\"GET\", `/v1/projects/${projectId}/messages/${messageId}`);\n }\n\n /**\n * Poll for message completion. Waits until the AI response reaches a terminal\n * status (completed, stopped) or the timeout expires.\n *\n * Handles edge cases: 404 grace period for race conditions between queue\n * dequeue and event creation, and queue pause detection.\n */\n async waitForMessageCompletion(\n projectId: string,\n messageId: string,\n options?: MessageCompletionOptions,\n ): Promise<MessageCompletionResult> {\n const pollInterval = options?.pollInterval ?? 3000;\n const timeout = options?.timeout ?? 600_000;\n const deadline = Date.now() + timeout;\n let notFoundSince: number | null = null;\n const notFoundGraceMs = 15_000;\n\n while (Date.now() < deadline) {\n try {\n const msg = await this.getMessage(projectId, messageId);\n notFoundSince = null;\n\n if (msg.status === \"queued\") {\n if (msg.queue_paused && msg.queue_pause_reason !== \"hitl_tool\") {\n return {\n status: \"error\",\n message_id: messageId,\n content: \"\",\n error:\n `Message is queued (position ${msg.queue_position ?? \"unknown\"}) but the queue is paused` +\n (msg.queue_pause_reason ? ` (reason: ${msg.queue_pause_reason})` : \"\") +\n `. Unpause the queue in the Lovable editor, or use wait=false to return immediately.`,\n };\n }\n await sleep(pollInterval);\n continue;\n }\n\n const ai = msg.response;\n if (ai) {\n if (ai.status === \"completed\" || ai.status === \"stopped\") {\n return {\n status: ai.status === \"completed\" ? \"completed\" : \"error\",\n message_id: ai.message_id,\n content: ai.content,\n edit_id: ai.edit_id,\n commit_sha: ai.commit_sha,\n summary: ai.summary,\n cost_credits: ai.cost_credits,\n };\n }\n }\n\n if (msg.role === \"assistant\") {\n if (msg.status === \"completed\" || msg.status === \"stopped\") {\n return {\n status: msg.status === \"completed\" ? \"completed\" : \"error\",\n message_id: msg.message_id,\n content: msg.content,\n edit_id: msg.edit_id,\n commit_sha: msg.commit_sha,\n summary: msg.summary,\n cost_credits: msg.cost_credits,\n };\n }\n }\n\n await sleep(pollInterval);\n } catch (err) {\n if (err instanceof ApiError && err.status === 404) {\n if (notFoundSince === null) {\n notFoundSince = Date.now();\n }\n if (Date.now() - notFoundSince < notFoundGraceMs) {\n await sleep(pollInterval);\n continue;\n }\n return {\n status: \"error\",\n message_id: messageId,\n content: \"\",\n error: \"Message not found. It may have been deleted from the queue.\",\n };\n }\n await sleep(pollInterval);\n }\n }\n\n return {\n status: \"timeout\",\n message_id: messageId,\n content: \"\",\n error: `Agent did not finish within ${timeout / 1000}s`,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Knowledge\n // ---------------------------------------------------------------------------\n\n /** Get workspace knowledge (custom instructions for the AI agent). */\n async getWorkspaceKnowledge(workspaceId: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"GET\", `/v1/workspaces/${workspaceId}/knowledge`);\n }\n\n /** Set workspace knowledge. Max 10,000 characters. */\n async setWorkspaceKnowledge(workspaceId: string, content: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"PUT\", `/v1/workspaces/${workspaceId}/knowledge`, { content });\n }\n\n /** Get project knowledge (custom instructions for the AI agent). */\n async getProjectKnowledge(projectId: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"GET\", `/v1/projects/${projectId}/knowledge`);\n }\n\n /** Set project knowledge. Max 10,000 characters. */\n async setProjectKnowledge(projectId: string, content: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"PUT\", `/v1/projects/${projectId}/knowledge`, { content });\n }\n\n // ---------------------------------------------------------------------------\n // Git operations\n // ---------------------------------------------------------------------------\n\n /**\n * Get the structured diff for a message or commit.\n * Pass `messageId` to get the diff for a specific AI message,\n * or `sha` for a specific commit.\n */\n async getDiff(\n projectId: string,\n params: { messageId?: string; sha?: string; baseSha?: string },\n ): Promise<GitDiffResponse> {\n const qs = new URLSearchParams();\n if (params.messageId) qs.set(\"message_id\", params.messageId);\n if (params.sha) qs.set(\"sha\", params.sha);\n if (params.baseSha) qs.set(\"base_sha\", params.baseSha);\n return this.request<GitDiffResponse>(\"GET\", `/v1/projects/${projectId}/git/diff?${qs.toString()}`);\n }\n\n /** List all files in a project at a specific git ref. */\n async listFiles(projectId: string, ref: string): Promise<GitFilesResponse> {\n const qs = new URLSearchParams({ ref });\n return this.request<GitFilesResponse>(\"GET\", `/v1/projects/${projectId}/git/files?${qs.toString()}`);\n }\n\n /** Read the raw content of a single file at a specific git ref. Returns text. */\n async readFile(projectId: string, path: string, ref: string): Promise<string> {\n const qs = new URLSearchParams({ path, ref });\n return this.requestText(\"GET\", `/v1/projects/${projectId}/git/file?${qs.toString()}`);\n }\n\n // ---------------------------------------------------------------------------\n // Edits\n // ---------------------------------------------------------------------------\n\n /** List the edit history of a project. */\n async listEdits(projectId: string, params?: { limit?: number; before?: string }): Promise<EditsResponse> {\n const qs = new URLSearchParams();\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n if (params?.before) qs.set(\"before\", params.before);\n const suffix = qs.toString() ? `?${qs.toString()}` : \"\";\n return this.request<EditsResponse>(\"GET\", `/v1/projects/${projectId}/edits${suffix}`);\n }\n\n // ---------------------------------------------------------------------------\n // File upload\n // ---------------------------------------------------------------------------\n\n /** Get a presigned URL for uploading a file. Returns the upload URL and file ID. */\n async getFileUploadUrl(params: { file_name: string; content_type?: string }): Promise<FileUploadUrlResponse> {\n return this.request<FileUploadUrlResponse>(\"POST\", \"/v1/files/upload-url\", params);\n }\n\n // ---------------------------------------------------------------------------\n // Visibility\n // ---------------------------------------------------------------------------\n\n /** Set a project's visibility (draft, private, or public). */\n async setProjectVisibility(projectId: string, visibility: string): Promise<{ visibility: string }> {\n return this.request<{ visibility: string }>(\"PUT\", `/v1/projects/${projectId}/visibility`, { visibility });\n }\n\n /** Set a folder's visibility (personal or workspace). */\n async setFolderVisibility(\n workspaceId: string,\n folderId: string,\n visibility: string,\n ): Promise<{ visibility: string }> {\n return this.request<{ visibility: string }>(\"PUT\", `/v1/workspaces/${workspaceId}/folders/${folderId}/visibility`, {\n visibility,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Library & template projects\n // ---------------------------------------------------------------------------\n\n /** List available design system library projects in a workspace. */\n async listLibraryProjects(workspaceId: string): Promise<{ libraries: LibraryProjectResponse[] }> {\n return this.request<{ libraries: LibraryProjectResponse[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/available-library-projects`,\n );\n }\n\n /** List available template projects in a workspace. */\n async listTemplateProjects(workspaceId: string): Promise<{ templates: TemplateProjectResponse[] }> {\n return this.request<{ templates: TemplateProjectResponse[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/available-template-projects`,\n );\n }\n\n // ---------------------------------------------------------------------------\n // MCP servers\n // ---------------------------------------------------------------------------\n\n /** List all MCP servers connected to a workspace. */\n async listMCPServers(workspaceId: string): Promise<{ servers: MCPServerResponse[] }> {\n return this.request<{ servers: MCPServerResponse[] }>(\"GET\", `/v1/workspaces/${workspaceId}/mcp-servers`);\n }\n\n /** Add an MCP server to a workspace. The server URL is tested before saving. */\n async addMCPServer(workspaceId: string, body: AddMCPServerBody): Promise<MCPServerResponse> {\n return this.request<MCPServerResponse>(\"POST\", `/v1/workspaces/${workspaceId}/mcp-servers`, body);\n }\n\n /** Remove an MCP server from a workspace. */\n async removeMCPServer(workspaceId: string, serverId: string): Promise<{ success: boolean }> {\n return this.request<{ success: boolean }>(\"DELETE\", `/v1/workspaces/${workspaceId}/mcp-servers/${serverId}`);\n }\n\n /** Browse available MCP server templates (catalog). */\n async listMCPCatalog(workspaceId: string): Promise<{ catalog: MCPCatalogEntry[] }> {\n return this.request<{ catalog: MCPCatalogEntry[] }>(\"GET\", `/v1/workspaces/${workspaceId}/mcp-catalog`);\n }\n\n // ---------------------------------------------------------------------------\n // Connectors\n // ---------------------------------------------------------------------------\n\n /** List standard (OAuth-based) connectors in a workspace. */\n async listStandardConnectors(workspaceId: string): Promise<{ connectors: StandardConnectorItem[] }> {\n return this.request<{ connectors: StandardConnectorItem[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/connectors/standard`,\n );\n }\n\n /** List seamless (zero-config) connectors in a workspace. */\n async listSeamlessConnectors(workspaceId: string): Promise<{ connectors: SeamlessConnectorItem[] }> {\n return this.request<{ connectors: SeamlessConnectorItem[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/connectors/seamless`,\n );\n }\n\n /** List MCP connectors in a workspace. */\n async listMCPConnectors(workspaceId: string): Promise<{ connectors: MCPConnectorItem[]; custom_enabled: boolean }> {\n return this.request<{ connectors: MCPConnectorItem[]; custom_enabled: boolean }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/connectors/mcp`,\n );\n }\n\n /** List authenticated connections (accounts) in a workspace. */\n async listConnections(\n workspaceId: string,\n params?: { connector_id?: string },\n ): Promise<{ connections: ConnectionItem[] }> {\n const qs = new URLSearchParams();\n if (params?.connector_id) qs.set(\"connector_id\", params.connector_id);\n const suffix = qs.toString() ? `?${qs.toString()}` : \"\";\n return this.request<{ connections: ConnectionItem[] }>(\"GET\", `/v1/workspaces/${workspaceId}/connections${suffix}`);\n }\n\n // ---------------------------------------------------------------------------\n // Analytics\n // ---------------------------------------------------------------------------\n\n /** Get historical analytics for a published project. */\n async getProjectAnalytics(\n projectId: string,\n params: { startDate: string; endDate: string; granularity?: string },\n ): Promise<ProjectAnalyticsResponse> {\n const qs = new URLSearchParams({\n startDate: params.startDate,\n endDate: params.endDate,\n });\n if (params.granularity) qs.set(\"granularity\", params.granularity);\n return this.request<ProjectAnalyticsResponse>(\"GET\", `/v1/projects/${projectId}/analytics?${qs.toString()}`);\n }\n\n /** Get real-time visitor trend for a published project. */\n async getProjectAnalyticsTrend(projectId: string): Promise<ProjectAnalyticsTrendResponse> {\n return this.request<ProjectAnalyticsTrendResponse>(\"GET\", `/v1/projects/${projectId}/analytics/trend`);\n }\n\n /**\n * Publish a project.\n *\n * This triggers a deployment which makes the project publicly accessible.\n * The deployment runs asynchronously - use waitForProjectPublished() to wait for completion.\n *\n * @param projectId - The project ID to publish\n * @param options.name - Optional custom slug for the published URL\n * @returns Deployment info including deployment ID\n */\n async publish(projectId: string, options?: { name?: string }): Promise<DeploymentResponse> {\n return this.request<DeploymentResponse>(\"POST\", `/v1/projects/${projectId}/deployments`, {\n name: options?.name,\n });\n }\n\n /**\n * Remix (fork) an existing project, optionally at a specific message point in time.\n *\n * When `messageId` is provided, the remix captures the project state as it was\n * just before that message was processed (default). Set `remixMode: \"including\"`\n * to include the message and its AI response in the remix.\n * Without `messageId`, the full current state is remixed.\n *\n * @param sourceProjectId - The project to remix from\n * @param options.workspaceId - Target workspace for the new project\n * @param options.messageId - Optional message ID to snapshot at\n * @param options.remixMode - \"before\" (default): state before the message; \"including\": state after the message and its AI response\n * @param options.includeHistory - Whether to preserve chat history (default: false)\n * @param options.includeCustomKnowledge - Whether to copy custom instructions (default: false)\n * @param options.initialMessage - Optional initial message to send after remix\n * @returns The remix job ID for polling progress\n */\n async remixProject(sourceProjectId: string, options: RemixProjectOptions): Promise<string> {\n const body: RemixInitBody = {\n workspace_id: options.workspaceId,\n include_history: options.includeHistory,\n include_custom_knowledge: options.includeCustomKnowledge,\n project_name: options.projectName,\n skip_initial_remix_message: options.skipInitialRemixMessage,\n skip_integrations: options.skipIntegrations,\n include_agent_state: options.includeAgentState,\n };\n\n if (options.messageId) {\n body.message_id = options.messageId;\n body.remix_mode = options.remixMode ?? \"before\";\n }\n\n if (options.initialMessage) {\n body.initial_message = {\n id: crypto.randomUUID(),\n message: options.initialMessage,\n chat_only: false,\n headless: true,\n };\n }\n\n const response = await this.request<RemixInitResponse>(\"POST\", `/projects/${sourceProjectId}/remix/init`, body);\n return response.job_id;\n }\n\n /**\n * Wait for a remix operation to complete.\n *\n * Polls the remix progress endpoint until the job reaches \"completed\" or \"error\" status.\n *\n * @param sourceProjectId - The source project ID (used for the progress endpoint)\n * @param jobId - The job ID returned by `remixProject()`\n * @param options.pollInterval - Time between polls in ms (default: 2000)\n * @param options.timeout - Maximum time to wait in ms (default: 300000 = 5 minutes)\n * @param options.onProgress - Optional callback for status/step updates\n * @returns The new project ID\n * @throws Error if the remix fails or timeout is reached\n */\n async waitForRemix(sourceProjectId: string, jobId: string, options?: RemixWaitOptions): Promise<RemixResult> {\n const pollInterval = options?.pollInterval ?? 2000;\n const timeout = options?.timeout ?? 300000;\n const startTime = Date.now();\n\n while (true) {\n const progress = await this.request<RemixProgressResponse>(\n \"GET\",\n `/projects/${sourceProjectId}/remix/progress?job_id=${encodeURIComponent(jobId)}`,\n );\n\n options?.onProgress?.(progress.status, progress.step);\n\n if (progress.status === \"completed\" && progress.result) {\n return { projectId: progress.result.project_id };\n }\n\n if (progress.status === \"error\") {\n throw new Error(progress.error_message ?? \"Remix failed\");\n }\n\n if (Date.now() - startTime > timeout) {\n throw new Error(`Timeout waiting for remix of project ${sourceProjectId}`);\n }\n\n await sleep(pollInterval);\n }\n }\n\n /**\n * Wait for a project to reach \"completed\" status.\n *\n * Projects start in \"in_progress\" status while being created/built.\n * This method polls until the status becomes \"completed\" or \"failed\".\n * A successful completion means the project's preview is ready to view.\n *\n * @param projectId - The project ID to wait for\n * @param options.pollInterval - Time between polls in ms (default: 2000)\n * @param options.timeout - Maximum time to wait in ms (default: 300000 = 5 minutes)\n * @param options.onProgress - Optional callback for status updates\n * @returns The completed project\n * @throws Error if project fails or timeout is reached\n */\n async waitForProjectReady(projectId: string, options?: WaitOptions): Promise<ProjectResponse> {\n const pollInterval = options?.pollInterval ?? 2000;\n const timeout = options?.timeout ?? 300000;\n const startTime = Date.now();\n\n while (true) {\n const project = await this.getProject(projectId);\n options?.onProgress?.(project);\n\n if (project.status === \"completed\") {\n return project;\n }\n\n if (project.status === \"failed\") {\n throw new Error(`Project ${projectId} failed to build`);\n }\n\n if (Date.now() - startTime > timeout) {\n throw new Error(`Timeout waiting for project ${projectId} to be ready`);\n }\n\n await sleep(pollInterval);\n }\n }\n\n /**\n * Wait for the AI response to a chat message.\n *\n * Connects to the project's message stream (SSE) and accumulates the\n * response content until the message is complete. Returns the full\n * response text along with the project's preview URL.\n *\n * Use this after `chat()` or after `createProject()` with `initialMessage`.\n *\n * @param projectId - The project ID to listen for\n * @param options.timeout - Maximum time to wait in ms (default: 300000 = 5 minutes)\n * @returns The AI response content and preview URL\n * @throws Error if the stream fails or timeout is reached\n */\n async waitForResponse(projectId: string, options?: ChatResponseOptions): Promise<ChatResponse> {\n const timeout = options?.timeout ?? 300000;\n const url = `${this.baseUrl}/v1/projects/${projectId}/messages/stream`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n headers: {\n ...this.authHeaders,\n ...this.extraHeaders,\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new ApiError(response.status, `Failed to connect to message stream: HTTP ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error(\"Response body is not readable\");\n }\n\n const result = await this.consumeSSEStream(response.body);\n return {\n content: result.content,\n messageId: result.messageId,\n previewUrl: this.getPreviewUrl(projectId),\n };\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw new Error(`Timeout waiting for response on project ${projectId}`);\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Developer/experimental APIs. These are not part of the stable v1 surface\n * and may change without notice.\n */\n get _dev() {\n return {\n /**\n * Fetch Braintrust traces for a specific chat message.\n *\n * Returns the trace spans associated with the AI response message.\n * The messageId is available from the ChatResponse returned by waitForResponse().\n *\n * Use the `purposes` option to filter which span types are returned.\n * When a purpose has multiple spans (e.g. main_agent across turns),\n * only the last span is returned — it contains the full accumulated context.\n *\n * @param projectId - The project ID\n * @param messageId - The AI message ID (from ChatResponse.messageId)\n * @param options.purposes - Filter spans by purpose (e.g. [\"main_agent\", \"knowledge_rag\"])\n * @returns The trace data including filtered spans\n */\n getMessageTraces: async (\n projectId: string,\n messageId: string,\n options?: GetMessageTracesOptions,\n ): Promise<MessageTracesResponse> => {\n const params = new URLSearchParams();\n if (options?.purposes?.length) {\n params.set(\"purposes\", options.purposes.join(\",\"));\n }\n const query = params.toString();\n const path = `/v1/_dev/projects/${projectId}/messages/${messageId}/traces${query ? `?${query}` : \"\"}`;\n return this.request<MessageTracesResponse>(\"GET\", path);\n },\n\n /**\n * Fetch traces for multiple messages across projects in parallel.\n *\n * Fires concurrent requests (up to `concurrency` at a time) and collects\n * results. Failed requests are captured in `errors` instead of throwing.\n *\n * @param queries - Array of { projectId, messageId } to fetch\n * @param options.purposes - Filter spans by purpose (applied to all queries)\n * @param options.concurrency - Max parallel requests (default: 5)\n * @returns Object with `traces` map (keyed by messageId) and `errors` map\n */\n getMessageTracesBatch: async (\n queries: TraceQuery[],\n options?: GetMessageTracesOptions & { concurrency?: number },\n ): Promise<BatchTracesResult> => {\n const concurrency = options?.concurrency ?? 5;\n const traces = new Map<string, MessageTracesResponse>();\n const errors = new Map<string, Error>();\n const purposeOpts = options?.purposes ? { purposes: options.purposes } : undefined;\n\n const pending = [...queries];\n const executing = new Set<Promise<void>>();\n\n for (const query of pending) {\n const task = this._dev\n .getMessageTraces(query.projectId, query.messageId, purposeOpts)\n .then((result) => {\n traces.set(query.messageId, result);\n })\n .catch((err) => {\n errors.set(query.messageId, err instanceof Error ? err : new Error(String(err)));\n })\n .finally(() => {\n executing.delete(task);\n });\n\n executing.add(task);\n\n if (executing.size >= concurrency) {\n await Promise.race(executing);\n }\n }\n\n await Promise.all(executing);\n\n return { traces, errors };\n },\n\n /**\n * Re-run project reviewers (e.g. project_success_v3, user_sentiment) for past assistant\n * messages. Requires an API key with project write access.\n */\n replayReviews: async (projectId: string, body: ReplayReviewsRequestBody): Promise<ReplayReviewsResponse> => {\n return this.request<ReplayReviewsResponse>(\"POST\", `/v1/_dev/projects/${projectId}/reviews/replay`, body);\n },\n };\n }\n\n private isFileInput(file: File | FileInput): file is FileInput {\n return \"data\" in file;\n }\n\n private async uploadFile(file: File | FileInput): Promise<UnscopedFile> {\n const fileName = this.isFileInput(file) ? file.name : file.name;\n const mimeType = this.isFileInput(file) ? file.type : file.type;\n const body = this.isFileInput(file) ? file.data : file;\n\n const { url, file_id: objectPath } = await this.request<{ url: string; file_id: string }>(\n \"POST\",\n \"/v1/files/upload-url\",\n {\n file_name: fileName,\n content_type: mimeType,\n },\n );\n\n const uploadResponse = await fetch(url, {\n method: \"PUT\",\n body,\n headers: { \"Content-Type\": mimeType },\n });\n if (!uploadResponse.ok) {\n throw new Error(`File upload failed for \"${fileName}\": HTTP ${uploadResponse.status}`);\n }\n\n return { file_id: objectPath, type: \"user_upload\", file_name: fileName, mime_type: mimeType };\n }\n\n private async uploadFiles(files: (File | FileInput)[]): Promise<UnscopedFile[]> {\n return Promise.all(files.map((file) => this.uploadFile(file)));\n }\n\n private async consumeSSEStream(body: ReadableStream<Uint8Array>): Promise<{ content: string; messageId: string }> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let content = \"\";\n let messageId = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop() ?? \"\";\n\n for (const part of parts) {\n if (!part.trim()) continue;\n\n const lines = part.split(\"\\n\");\n let eventType = \"\";\n let eventData = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event: \")) {\n eventType = line.slice(7);\n } else if (line.startsWith(\"data: \")) {\n eventData = line.slice(6);\n }\n }\n\n if (eventType === \"message\" && eventData) {\n try {\n const data = JSON.parse(eventData);\n if (typeof data.content === \"string\") {\n content += data.content;\n }\n if (typeof data.message_id === \"string\" && data.message_id) {\n messageId = data.message_id;\n }\n if (data.is_final) {\n return { content, messageId };\n }\n } catch {\n // Skip non-JSON data lines\n }\n }\n\n if (eventType === \"error\") {\n let detail = \"Stream error from server\";\n try {\n const data = JSON.parse(eventData);\n if (data.message) detail = data.message;\n } catch {\n // use default message\n }\n throw new Error(detail);\n }\n }\n }\n } finally {\n void reader.cancel();\n }\n\n return { content, messageId };\n }\n\n /**\n * Wait for a project to be published (deployed).\n *\n * This method polls until the project has `is_published: true` and a `url`.\n *\n * @param projectId - The project ID to wait for\n * @param options.pollInterval - Time between polls in ms (default: 3000)\n * @param options.timeout - Maximum time to wait in ms (default: 600000 = 10 minutes)\n * @param options.onProgress - Optional callback for status updates\n * @returns The published project with URL\n * @throws Error if timeout is reached\n */\n async waitForProjectPublished(projectId: string, options?: WaitOptions): Promise<ProjectResponse> {\n const pollInterval = options?.pollInterval ?? 3000;\n const timeout = options?.timeout ?? 600000;\n const startTime = Date.now();\n\n while (true) {\n const project = await this.getProject(projectId);\n options?.onProgress?.(project);\n\n if (project.is_published && project.url) {\n return project;\n }\n\n if (project.status === \"failed\") {\n throw new Error(`Project ${projectId} failed to build`);\n }\n\n if (Date.now() - startTime > timeout) {\n throw new Error(`Timeout waiting for project ${projectId} to be published`);\n }\n\n await sleep(pollInterval);\n }\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"sourcesContent":["// Type definitions for the Lovable SDK\n// These are self-contained and don't require external dependencies\n\nexport type ProjectVisibility = \"draft\" | \"private\" | \"public\";\nexport type MemberRole = \"admin\" | \"collaborator\" | \"invited\" | \"member\" | \"none\" | \"owner\" | \"viewer\";\nexport type ProjectStatus = \"completed\" | \"in_progress\" | \"failed\";\n\nexport interface MeWorkspace {\n id: string;\n name: string;\n role: string;\n}\n\nexport interface MeResponse {\n id: string;\n email: string;\n name: string;\n workspaces: MeWorkspace[];\n}\n\nexport interface WorkspaceMembership {\n email: string;\n invited_at?: string;\n joined_at?: string;\n monthly_credit_limit: number | null;\n project_access?: Record<string, { access_level?: string }>;\n role: MemberRole;\n user_id: string;\n workspace_id: string;\n}\n\nexport interface WorkspaceWithMembership {\n id: string;\n name: string;\n description?: string;\n image_url?: string;\n owner_id?: string;\n is_personal?: boolean;\n plan?: string;\n plan_type?: string;\n num_projects: number;\n num_seats?: number;\n membership: WorkspaceMembership;\n created_at: string;\n updated_at: string;\n deleted_at?: string;\n credits_granted: number;\n credits_used: number;\n daily_credits_limit: number;\n daily_credits_used: number;\n billing_period_credits_limit: number;\n billing_period_credits_used: number;\n billing_period_start_date?: string;\n billing_period_end_date?: string;\n rollover_credits_limit: number;\n rollover_credits_used: number;\n topup_credits_limit: number;\n topup_credits_used: number;\n total_credits_used: number;\n subscription_status?:\n | \"active\"\n | \"canceled\"\n | \"incomplete_expired\"\n | \"incomplete\"\n | \"past_due\"\n | \"paused\"\n | \"trialing\"\n | \"unpaid\";\n referral_code?: string;\n short_referral_code?: string;\n referral_count: number;\n followers_count: number;\n default_project_visibility?: ProjectVisibility;\n default_project_publish_visibility?: \"private\" | \"public\";\n mcp_enabled?: boolean;\n}\n\nexport interface WorkspaceMembershipResponse {\n user_id: string;\n username: string;\n display_name?: string;\n email?: string;\n role: MemberRole;\n invited_at?: string;\n joined_at?: string;\n monthly_credit_limit?: number;\n total_credits_used?: number;\n total_credits_used_in_billing_period?: number;\n project_access?: Record<string, { access_level?: string }>;\n}\n\n/**\n * Project response from the API.\n *\n * The v1 endpoints (getProject, createProject) return a lean subset:\n * id, workspace_id, name, display_name, description, status, visibility,\n * is_published, url. Other fields are available from list endpoints.\n */\nexport interface ProjectResponse {\n id: string;\n name?: string;\n display_name?: string;\n description?: string;\n tech_stack?: string;\n status?: string;\n visibility?: ProjectVisibility;\n publish_visibility?: \"private\" | \"public\";\n is_published?: boolean;\n /** Present in create project response when initial_message was provided */\n message_id?: string;\n is_starred?: boolean;\n is_template?: boolean;\n is_github?: boolean;\n is_supabase_enabled?: boolean;\n url?: string;\n og_image_url?: string;\n latest_screenshot_url?: string;\n user_id?: string;\n user_display_name?: string;\n user_photo_url?: string;\n created_at?: string;\n created_by?: string;\n updated_at?: string;\n deleted_at?: string;\n last_edited_at?: string;\n last_viewed_at?: string;\n published_at?: string;\n workspace_id?: string;\n folder_id?: string;\n category?: string;\n edit_count?: number;\n gen_count?: number;\n user_message_count?: number;\n remix_count?: number;\n remixed_from_project_id?: string;\n template_project_id?: string;\n credit_total?: number;\n custom_instructions?: string;\n main_branch?: string;\n latest_commit_sha?: string;\n github_repo_name?: string;\n github_repo_id?: number;\n deployment_target?: string;\n active_deployment_job_id?: string;\n environments_enabled?: boolean;\n hide_badge?: boolean | null;\n featured?: boolean;\n featured_at?: string;\n feature_rank?: number;\n feature_source?: string;\n}\n\nexport interface UnscopedFile {\n file_id: string;\n type: \"user_upload\";\n file_name?: string;\n mime_type?: string;\n}\n\nexport interface FileInput {\n name: string;\n data: Blob | ArrayBuffer | Uint8Array;\n type: string;\n}\n\n/**\n * Configuration to use a custom OpenAI-compatible model as the main agent.\n */\nexport interface CustomModelConfig {\n /** Base URL of the OpenAI-compatible API (e.g. \"https://my-vllm.example.com/v1\") */\n endpoint: string;\n /** API key for the custom endpoint */\n apiKey: string;\n /** Model identifier sent in the request (e.g. \"my-org/my-model-id\") */\n modelName: string;\n}\n\nexport interface ChatRequest {\n id: string;\n message: string;\n chat_only: boolean;\n headless: boolean;\n ai_message_id?: string;\n intent?: string;\n model?: string;\n temperature?: number;\n current_page?: string;\n view?: string;\n view_description?: string;\n prev_session_id?: string;\n is_creation?: boolean;\n files?: UnscopedFile[];\n custom_model_endpoint?: string;\n custom_model_api_key?: string;\n custom_model_name?: string;\n custom_model_disable_race?: boolean;\n}\n\nexport interface CreateProjectBody {\n description: string;\n tech_stack?: string;\n visibility?: ProjectVisibility;\n template_project_id?: string;\n initial_message?: string;\n files?: UnscopedFile[];\n selected_libraries?: { project_id: string }[];\n category?: string;\n project_type?: string;\n prompt_name?: string;\n selected_theme?: string;\n env_vars?: Record<string, string>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AddUserToWorkspaceInputBody {\n email: string;\n role?: MemberRole;\n}\n\nexport interface GetWorkspacesResponse {\n workspaces: WorkspaceWithMembership[] | null;\n}\n\nexport interface GetWorkspaceProjectsResponse {\n projects: ProjectResponse[] | null;\n}\n\nexport interface CreateProjectOptions {\n description: string;\n techStack?: string;\n visibility?: ProjectVisibility;\n templateProjectId?: string;\n initialMessage?: string;\n /** Files to upload and attach to the initial message. The SDK handles uploading. */\n files?: (File | FileInput)[];\n /** Pre-uploaded file references to attach to the initial message. Skips upload. */\n uploadedFiles?: UnscopedFile[];\n /** Design system library projects to connect to the new project. */\n selectedLibraries?: { project_id: string }[];\n}\n\nexport interface InviteCollaboratorOptions {\n email: string;\n role?: MemberRole;\n}\n\n/**\n * Controls prompt cache continuation behavior for a message.\n *\n * - `\"force\"` — skip cache TTL and token/criteria checks (force continuation)\n * - `\"fresh_build\"` — force a full prompt rebuild from scratch\n * - `\"allow_expired_cache\"` — skip cache TTL check but respect token/criteria limits\n *\n * Omit for default behavior (5-min TTL, token and criteria checks apply).\n */\nexport type ContinuationOverride = \"force\" | \"fresh_build\" | \"allow_expired_cache\";\n\nexport interface ChatMessageOptions {\n message: string;\n /** Files to upload and attach. The SDK handles uploading them first. */\n files?: (File | FileInput)[];\n /** Pre-uploaded file references (already uploaded via getFileUploadUrl). Skips upload. */\n uploadedFiles?: UnscopedFile[];\n /** Enable plan mode: the agent discusses and plans without editing code. */\n planMode?: boolean;\n customModel?: CustomModelConfig;\n /**\n * When true, the server may skip staggered inference racing for that request if your\n * custom model endpoint supports it; otherwise the request fails with a validation error.\n * API key authentication only. Sent as `custom_model_disable_race` in the JSON body.\n */\n customModelDisableRace?: boolean;\n /**\n * Override continuation behavior for this message.\n * Controls whether the agent reuses the prompt cache or rebuilds from scratch.\n */\n continuation?: ContinuationOverride;\n}\n\nexport interface LovableClientOptions {\n /** API key for authentication (mutually exclusive with bearerToken) */\n apiKey?: string;\n /** Bearer token for OAuth authentication (mutually exclusive with apiKey) */\n bearerToken?: string;\n baseUrl?: string;\n /** Additional headers to include on every request */\n headers?: Record<string, string>;\n}\n\nexport interface LovableError extends Error {\n status: number;\n type?: string;\n detail?: string;\n}\n\nexport interface WaitOptions {\n pollInterval?: number;\n timeout?: number;\n onProgress?: (project: ProjectResponse) => void;\n}\n\nexport interface DeploymentResponse {\n status: string;\n deployment_id?: string;\n url?: string;\n}\n\nexport interface ChatResponse {\n content: string;\n previewUrl: string;\n messageId: string;\n}\n\nexport interface ChatResponseOptions {\n timeout?: number;\n}\n\n// --- Trace types ---\n\nexport type TracePurpose = \"main_agent\" | \"codebase_rag\" | \"knowledge_rag\" | \"review\";\n\nexport interface TraceSpan {\n span_id: string;\n root_span_id?: string;\n span_parents?: unknown;\n span_name?: string;\n span_type?: string;\n purpose?: string;\n subpurpose?: string;\n created?: string;\n input?: unknown;\n output?: unknown;\n error?: unknown;\n metadata?: unknown;\n metrics?: unknown;\n scores?: unknown;\n tags?: unknown;\n}\n\nexport interface MessageTracesResponse {\n message_id: string;\n braintrust_span_id: string;\n root_span_id: string;\n response_message_id?: string;\n spans: TraceSpan[];\n}\n\nexport interface GetMessageTracesOptions {\n purposes?: TracePurpose[];\n}\n\nexport interface TraceQuery {\n projectId: string;\n messageId: string;\n}\n\nexport interface BatchTracesResult {\n traces: Map<string, MessageTracesResponse>;\n errors: Map<string, Error>;\n}\n\n// --- On-demand review replay (`/v1/_dev/.../reviews/replay`) — typed in SDK only ---\n\nexport interface ReplayReviewsItemInput {\n /** Assistant (AI) message id for the turn to score */\n response_message_id: string;\n /** Optional per-item reviewer types */\n reviewer_types?: string[] | null;\n}\n\nexport interface ReplayReviewsRequestBody {\n items: ReplayReviewsItemInput[];\n /** Defaults to project_success_v3 and user_sentiment when omitted */\n reviewer_types?: string[] | null;\n /** Parallel items (default 4, max 16) */\n concurrency?: number;\n}\n\nexport interface ReviewerRunResult {\n reviewer_type: string;\n score?: number;\n message?: string;\n model?: string;\n published_rubric_rows: number;\n error?: string;\n}\n\nexport interface ReplayOutcome {\n response_message_id: string;\n user_message_id: string;\n results: ReviewerRunResult[] | null;\n}\n\nexport interface BatchItemOutcome {\n response_message_id: string;\n ok: boolean;\n error?: string;\n replay?: ReplayOutcome;\n}\n\nexport interface BatchReplayReviewsOutcome {\n items: BatchItemOutcome[];\n}\n\nexport interface ReplayReviewsResponse {\n results: BatchReplayReviewsOutcome;\n}\n\n// --- Remix types ---\n\nexport type RemixJobStatus = \"unknown\" | \"preparing\" | \"running\" | \"completed\" | \"error\";\n\nexport type RemixJobStep =\n | \"starting\"\n | \"creating_new_project\"\n | \"restoring_supabase\"\n | \"copying_history\"\n | \"preparing_repository\"\n | \"remixing_integration\"\n | \"pushing_repository\"\n | \"finalizing\"\n | \"completed\";\n\nexport interface RemixJobStepInfo {\n step: RemixJobStep;\n integration_name?: string;\n status?: string;\n}\n\nexport type RemixMode = \"before\" | \"including\";\n\nexport interface RemixProjectOptions {\n workspaceId: string;\n messageId?: string;\n remixMode?: RemixMode;\n includeHistory?: boolean;\n includeCustomKnowledge?: boolean;\n initialMessage?: string;\n projectName?: string;\n skipInitialRemixMessage?: boolean;\n skipIntegrations?: boolean;\n}\n\nexport interface RemixInitBody {\n workspace_id: string;\n message_id?: string;\n remix_mode?: RemixMode;\n include_history?: boolean;\n include_custom_knowledge?: boolean;\n initial_message?: ChatRequest;\n project_name?: string;\n skip_initial_remix_message?: boolean;\n skip_integrations?: boolean;\n}\n\nexport interface RemixInitResponse {\n job_id: string;\n}\n\nexport interface RemixProgressResult {\n project_id: string;\n}\n\nexport interface RemixProgressResponse {\n status: RemixJobStatus;\n step?: RemixJobStepInfo;\n error_message?: string;\n result?: RemixProgressResult;\n}\n\nexport interface RemixResult {\n projectId: string;\n}\n\nexport interface RemixWaitOptions {\n pollInterval?: number;\n timeout?: number;\n onProgress?: (status: RemixJobStatus, step?: RemixJobStepInfo) => void;\n}\n\n// --- Database types ---\n\nexport interface DatabaseStatus {\n enabled: boolean;\n stack?: string;\n}\n\nexport interface EnableDatabaseResult {\n enabled: boolean;\n stack: string;\n}\n\nexport interface DatabaseQueryResult {\n rows: Record<string, unknown>[] | null;\n}\n\nexport interface DatabaseConnectionInfo {\n host: string;\n port: string;\n user: string;\n password: string;\n database: string;\n connection_string: string;\n api_url: string;\n}\n\n// --- API Error ---\n\nexport class ApiError extends Error {\n readonly status: number;\n readonly type?: string;\n readonly detail?: string;\n readonly props?: Record<string, unknown>;\n\n constructor(status: number, message: string, type?: string, detail?: string, props?: Record<string, unknown>) {\n super(message);\n this.status = status;\n this.type = type;\n this.detail = detail;\n this.props = props;\n }\n}\n\n// --- Send message response ---\n\nexport interface SendMessageResponse {\n message_id: string;\n status: string;\n}\n\n// --- Get message response ---\n\nexport interface GetMessageResponse {\n message_id: string;\n role: string;\n content: string;\n status: string;\n created_at: string;\n edit_id?: string;\n commit_sha?: string;\n summary?: string;\n cost_credits?: number;\n response?: {\n message_id: string;\n status: string;\n content: string;\n edit_id?: string;\n commit_sha?: string;\n summary?: string;\n cost_credits?: number;\n };\n queue_position?: number;\n queue_paused?: boolean;\n queue_pause_reason?: string;\n}\n\nexport interface MessageCompletionResult {\n status: \"completed\" | \"timeout\" | \"error\";\n message_id: string;\n content: string;\n edit_id?: string;\n commit_sha?: string;\n summary?: string;\n cost_credits?: number;\n error?: string;\n}\n\nexport interface MessageCompletionOptions {\n /** Time between polls in ms (default: 3000) */\n pollInterval?: number;\n /** Maximum time to wait in ms (default: 600000 = 10 minutes) */\n timeout?: number;\n}\n\n// --- Knowledge ---\n\nexport interface KnowledgeResponse {\n content: string;\n}\n\n// --- File upload ---\n\nexport interface FileUploadUrlResponse {\n url: string;\n file_id: string;\n}\n\n// --- Git types ---\n\nexport interface DiffLine {\n type: string;\n content: string;\n}\n\nexport interface DiffHunk {\n oldStart: number;\n oldCount: number;\n newStart: number;\n newCount: number;\n lines: DiffLine[];\n}\n\nexport interface DiffEntry {\n action: string;\n file_path: string;\n original_file_path?: string;\n file_type?: string;\n is_image: boolean;\n is_incomplete?: boolean;\n hunks?: DiffHunk[];\n}\n\nexport interface GitDiffResponse {\n diffs: DiffEntry[];\n error?: string;\n}\n\nexport interface GitFileEntry {\n path: string;\n size: number;\n binary: boolean;\n}\n\nexport interface GitFilesResponse {\n files: GitFileEntry[];\n ref: string;\n}\n\n// --- Edits ---\n\nexport interface EditSummary {\n id: string;\n type: string;\n commit_sha?: string;\n commit_message?: string;\n status: string;\n created_at: string;\n}\n\nexport interface EditsResponse {\n edits: EditSummary[];\n has_more: boolean;\n}\n\n// --- List projects (expanded) ---\n\nexport interface ListProjectItem extends ProjectResponse {\n user_id?: string;\n is_template?: boolean;\n is_starred?: boolean;\n created_at?: string;\n updated_at?: string;\n last_edited_at?: string;\n last_viewed_at?: string;\n edit_count?: number;\n remix_count?: number;\n}\n\nexport interface ListProjectsResponse {\n projects: ListProjectItem[];\n total: number;\n has_more: boolean;\n}\n\nexport interface ListProjectsOptions {\n query?: string;\n visibility?: string;\n publish_status?: string;\n folder_id?: string;\n user_id?: string;\n sort_by?: string;\n sort_order?: string;\n viewed_by_me?: boolean;\n limit?: number;\n offset?: number;\n cursor?: string;\n}\n\n// --- Library & template projects ---\n\nexport interface LibraryProjectResponse {\n id: string;\n name: string | null;\n description: string;\n updated_at: string;\n}\n\nexport interface TemplateProjectResponse {\n id: string;\n name: string | null;\n description: string;\n updated_at: string;\n}\n\n// --- MCP servers ---\n\nexport interface ConnectorResponse {\n id: string;\n name: string;\n url?: string;\n auth_type: string;\n connector_id?: string;\n is_connected: boolean;\n}\n\nexport interface AvailableConnectorEntry {\n id: string;\n display_name: string;\n summary: string;\n category: string;\n requires_custom_url?: boolean;\n documentation_url?: string;\n}\n\nexport interface AddConnectorBody {\n name: string;\n url: string;\n auth_type: \"none\" | \"bearer_token\";\n connector_id?: string;\n token?: string;\n}\n\n// --- Connectors ---\n\nexport interface StandardConnectorItem {\n id: string;\n display_name: string;\n short_description: string;\n categories: string[];\n is_enabled_for_workspace: boolean;\n auth_type: string;\n logo_id?: string;\n documentation_url?: string;\n connection_scope?: string;\n}\n\nexport interface SeamlessConnectorItem {\n id: string;\n display_name: string;\n short_description: string;\n categories: string[];\n is_enabled_for_workspace: boolean;\n logo_id?: string;\n documentation_url?: string;\n}\n\nexport interface MCPConnectorItem {\n id: string;\n display_name: string;\n summary: string;\n status: string;\n is_enabled_for_workspace: boolean;\n is_connected: boolean;\n connector_id?: string;\n documentation_url?: string;\n}\n\nexport interface ConnectionItem {\n id: string;\n connector_id: string;\n display_name: string;\n is_managed: boolean;\n status: string;\n created_at: string;\n updated_at: string;\n}\n\n// --- Analytics ---\n\nexport interface TimeSeriesDataPoint {\n date: string;\n value: number;\n}\n\nexport interface TimeSeriesData {\n total: number;\n label: string;\n data: TimeSeriesDataPoint[];\n}\n\nexport interface ListDataPoint {\n label: string;\n value: number;\n}\n\nexport interface ListData {\n label: string;\n data: ListDataPoint[];\n}\n\nexport interface ProjectAnalyticsResponse {\n timeSeries: {\n visitors: TimeSeriesData;\n pageviews: TimeSeriesData;\n pageviewsPerVisit: TimeSeriesData;\n sessionDuration: TimeSeriesData;\n bounceRate: TimeSeriesData;\n };\n lists: {\n page: ListData;\n source: ListData;\n device: ListData;\n country: ListData;\n };\n}\n\nexport interface TrendDataPoint {\n time: string;\n visits: number;\n}\n\nexport interface ProjectAnalyticsTrendResponse {\n data: TrendDataPoint[];\n currentVisitors: number;\n}\n","import type {\n LovableClientOptions,\n CreateProjectOptions,\n InviteCollaboratorOptions,\n ChatMessageOptions,\n WaitOptions,\n WorkspaceWithMembership,\n ProjectResponse,\n WorkspaceMembershipResponse,\n CreateProjectBody,\n AddUserToWorkspaceInputBody,\n GetWorkspacesResponse,\n DeploymentResponse,\n ChatResponse,\n ChatResponseOptions,\n UnscopedFile,\n FileInput,\n RemixProjectOptions,\n RemixInitBody,\n RemixInitResponse,\n RemixProgressResponse,\n RemixResult,\n RemixWaitOptions,\n MessageTracesResponse,\n GetMessageTracesOptions,\n TraceQuery,\n BatchTracesResult,\n ReplayReviewsRequestBody,\n ReplayReviewsResponse,\n MeResponse,\n DatabaseStatus,\n EnableDatabaseResult,\n DatabaseQueryResult,\n DatabaseConnectionInfo,\n SendMessageResponse,\n GetMessageResponse,\n MessageCompletionResult,\n MessageCompletionOptions,\n KnowledgeResponse,\n FileUploadUrlResponse,\n GitDiffResponse,\n GitFilesResponse,\n EditsResponse,\n ListProjectsResponse,\n ListProjectsOptions,\n ConnectorResponse,\n AvailableConnectorEntry,\n AddConnectorBody,\n StandardConnectorItem,\n SeamlessConnectorItem,\n MCPConnectorItem,\n ConnectionItem,\n ProjectAnalyticsResponse,\n ProjectAnalyticsTrendResponse,\n LibraryProjectResponse,\n TemplateProjectResponse,\n} from \"./types.js\";\n\nimport { ApiError } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.lovable.dev\";\n\nfunction normalizeBaseUrl(url: string | undefined): string {\n if (!url) return DEFAULT_BASE_URL;\n\n const normalized = url.replace(/\\/$/, \"\");\n\n if (!normalized.startsWith(\"http://\") && !normalized.startsWith(\"https://\")) {\n throw new Error(`baseUrl must include a protocol (http:// or https://). Got: \"${url}\"`);\n }\n\n return normalized;\n}\n\nexport class LovableClient {\n private readonly authHeaders: Record<string, string>;\n private readonly baseUrl: string;\n private readonly extraHeaders: Record<string, string>;\n\n constructor(options: LovableClientOptions) {\n const hasApiKey = !!options.apiKey;\n const hasBearerToken = !!options.bearerToken;\n\n if (!hasApiKey && !hasBearerToken) {\n throw new Error(\"Either apiKey or bearerToken is required\");\n }\n if (hasApiKey && hasBearerToken) {\n throw new Error(\"Provide either apiKey or bearerToken, not both\");\n }\n\n this.authHeaders = hasApiKey\n ? { \"Lovable-API-Key\": options.apiKey! }\n : { Authorization: `Bearer ${options.bearerToken}` };\n\n this.baseUrl = normalizeBaseUrl(options.baseUrl);\n this.extraHeaders = options.headers ?? {};\n }\n\n private async rawRequest(method: string, path: string, body?: unknown): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n ...this.authHeaders,\n ...this.extraHeaders,\n Accept: \"application/json\",\n };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n let errorBody:\n | {\n type?: string;\n title?: string;\n message?: string;\n detail?: string;\n details?: string;\n props?: Record<string, unknown>;\n }\n | undefined;\n try {\n errorBody = (await response.json()) as typeof errorBody;\n } catch {\n // Ignore JSON parse errors\n }\n\n const message = errorBody?.message ?? errorBody?.title ?? `HTTP ${response.status}: ${response.statusText}`;\n const type = errorBody?.type ?? errorBody?.title;\n const detail = errorBody?.detail ?? errorBody?.details;\n throw new ApiError(response.status, message, type, detail, errorBody?.props);\n }\n\n return response;\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const response = await this.rawRequest(method, path, body);\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n private async requestText(method: string, path: string): Promise<string> {\n const response = await this.rawRequest(method, path);\n return response.text();\n }\n\n /**\n * Get the current authenticated user and their workspaces.\n * Useful for validating an API key and discovering workspace IDs.\n */\n async me(): Promise<MeResponse> {\n return this.request<MeResponse>(\"GET\", \"/v1/me\");\n }\n\n /**\n * List all workspaces the authenticated user has access to\n */\n async listWorkspaces(): Promise<WorkspaceWithMembership[]> {\n const response = await this.request<GetWorkspacesResponse>(\"GET\", \"/v1/workspaces\");\n return response.workspaces ?? [];\n }\n\n /**\n * Get a specific workspace by ID\n */\n async getWorkspace(workspaceId: string): Promise<WorkspaceWithMembership> {\n const response = await this.request<{ workspace: WorkspaceWithMembership }>(\"GET\", `/v1/workspaces/${workspaceId}`);\n return response.workspace;\n }\n\n /**\n * List projects in a workspace.\n * Supports full-text search, filtering by visibility/publish status/folder/creator,\n * and pagination via offset or cursor.\n */\n async listProjects(workspaceId: string, options?: ListProjectsOptions): Promise<ListProjectsResponse> {\n const params = new URLSearchParams();\n if (options?.query) params.set(\"q\", options.query);\n if (options?.visibility) params.set(\"visibility\", options.visibility);\n if (options?.publish_status) params.set(\"publish_status\", options.publish_status);\n if (options?.folder_id) params.set(\"folder_id\", options.folder_id);\n if (options?.user_id) params.set(\"user_id\", options.user_id);\n if (options?.sort_by) params.set(\"sort_by\", options.sort_by);\n if (options?.sort_order) params.set(\"sort_order\", options.sort_order);\n if (options?.viewed_by_me) params.set(\"viewed_by_me\", \"true\");\n if (options?.limit !== undefined) params.set(\"limit\", String(options.limit));\n if (options?.offset !== undefined) params.set(\"offset\", String(options.offset));\n if (options?.cursor) params.set(\"cursor\", options.cursor);\n\n const query = params.toString();\n const path = `/v1/workspaces/${workspaceId}/projects${query ? `?${query}` : \"\"}`;\n\n return this.request<ListProjectsResponse>(\"GET\", path);\n }\n\n /**\n * Create a new project in a workspace\n */\n async createProject(workspaceId: string, options: CreateProjectOptions): Promise<ProjectResponse> {\n let fileRefs: UnscopedFile[] | undefined;\n if (options.uploadedFiles?.length) {\n fileRefs = options.uploadedFiles;\n } else if (options.files?.length) {\n fileRefs = await this.uploadFiles(options.files);\n }\n\n const body: CreateProjectBody = {\n description: options.description,\n visibility: options.visibility ?? \"private\",\n template_project_id: options.templateProjectId,\n };\n if (options.techStack) {\n body.tech_stack = options.techStack;\n }\n if (options.selectedLibraries?.length) {\n body.selected_libraries = options.selectedLibraries;\n }\n\n if (options.initialMessage) {\n body.initial_message = options.initialMessage;\n }\n if (fileRefs?.length) {\n body.files = fileRefs;\n }\n\n const project = await this.request<ProjectResponse>(\"POST\", `/v1/workspaces/${workspaceId}/projects`, body);\n\n return project;\n }\n\n /**\n * Send a chat message to a project.\n *\n * The API accepts the message and processes it in the background.\n * Returns the message ID and status. Use `waitForMessageCompletion()`\n * to poll for the AI response, or `waitForResponse()` for SSE streaming.\n */\n async chat(projectId: string, options: ChatMessageOptions): Promise<SendMessageResponse> {\n let fileRefs: UnscopedFile[] | undefined;\n if (options.uploadedFiles?.length) {\n fileRefs = options.uploadedFiles;\n } else if (options.files?.length) {\n fileRefs = await this.uploadFiles(options.files);\n }\n\n const body: {\n message: string;\n files?: UnscopedFile[];\n plan_mode?: boolean;\n custom_model_endpoint?: string;\n custom_model_api_key?: string;\n custom_model_name?: string;\n custom_model_disable_race?: boolean;\n continuation?: string;\n } = {\n message: options.message,\n };\n if (fileRefs) {\n body.files = fileRefs;\n }\n if (options.planMode) {\n body.plan_mode = true;\n }\n if (options.customModel) {\n body.custom_model_endpoint = options.customModel.endpoint;\n body.custom_model_api_key = options.customModel.apiKey;\n body.custom_model_name = options.customModel.modelName;\n }\n if (options.customModelDisableRace) {\n body.custom_model_disable_race = true;\n }\n if (options.continuation) {\n body.continuation = options.continuation;\n }\n\n return this.request<SendMessageResponse>(\"POST\", `/v1/projects/${projectId}/messages`, body);\n }\n\n /**\n * Invite a user to a workspace as a collaborator\n */\n async inviteCollaborator(\n workspaceId: string,\n options: InviteCollaboratorOptions,\n ): Promise<WorkspaceMembershipResponse> {\n const body: AddUserToWorkspaceInputBody = {\n email: options.email,\n role: options.role ?? \"member\",\n };\n\n return this.request<WorkspaceMembershipResponse>(\"POST\", `/workspaces/${workspaceId}/memberships`, body);\n }\n\n /**\n * List members of a workspace\n */\n async listWorkspaceMembers(workspaceId: string): Promise<WorkspaceMembershipResponse[]> {\n const response = await this.request<{\n memberships: WorkspaceMembershipResponse[] | null;\n }>(\"GET\", `/workspaces/${workspaceId}/memberships`);\n return response.memberships ?? [];\n }\n\n /**\n * Remove a member from a workspace\n */\n async removeWorkspaceMember(workspaceId: string, userId: string): Promise<void> {\n await this.request<void>(\"DELETE\", `/workspaces/${workspaceId}/memberships/${userId}`);\n }\n\n /**\n * Get project details by ID\n */\n async getProject(projectId: string): Promise<ProjectResponse> {\n return this.request<ProjectResponse>(\"GET\", `/v1/projects/${projectId}`);\n }\n\n /**\n * Get the preview URL for a project.\n *\n * The preview URL is available once the project reaches \"completed\" status.\n * This URL allows viewing the project in development mode.\n *\n * @param projectId - The project ID\n * @returns The preview URL\n */\n getPreviewUrl(projectId: string): string {\n return `https://id-preview--${projectId}.lovable.app`;\n }\n\n /**\n * Get the published URL for a project (if published).\n *\n * Returns the public URL if the project has been published, or null if not.\n *\n * @param projectId - The project ID\n * @returns The published URL or null if not published\n */\n async getPublishedUrl(projectId: string): Promise<string | null> {\n const project = await this.getProject(projectId);\n return project.is_published && project.url ? project.url : null;\n }\n\n /**\n * Get the cloud database status for a project.\n *\n * @param projectId - The project ID\n * @returns Whether the database is enabled and which stack is used\n */\n async getDatabaseStatus(projectId: string): Promise<DatabaseStatus> {\n return this.request<DatabaseStatus>(\"GET\", `/v1/projects/${projectId}/database`);\n }\n\n /**\n * Enable (provision) a cloud database for a project.\n *\n * This triggers database provisioning which takes 30-60 seconds.\n * The call blocks until provisioning completes.\n *\n * @param projectId - The project ID\n * @returns The database status after enablement\n */\n async enableDatabase(projectId: string): Promise<EnableDatabaseResult> {\n return this.request<EnableDatabaseResult>(\"POST\", `/v1/projects/${projectId}/database/enable`);\n }\n\n /**\n * Execute a SQL query against the project's cloud database.\n *\n * Supports SELECT, INSERT, UPDATE, DELETE, and DDL statements.\n * The database must be enabled first (see enableDatabase).\n *\n * @param projectId - The project ID\n * @param sql - SQL query to execute\n * @returns Query result rows as JSON objects\n */\n async queryDatabase(projectId: string, sql: string): Promise<DatabaseQueryResult> {\n return this.request<DatabaseQueryResult>(\"POST\", `/v1/projects/${projectId}/database/query`, { sql });\n }\n\n /**\n * Get database connection info for a project.\n *\n * Returns host, port, user, password, database name, and full connection string\n * that can be used with any PostgreSQL client (psql, pgAdmin, etc.).\n * The database must be enabled first (see enableDatabase).\n *\n * @param projectId - The project ID\n * @returns Database connection details\n */\n async getDatabaseConnectionInfo(projectId: string): Promise<DatabaseConnectionInfo> {\n return this.request<DatabaseConnectionInfo>(\"GET\", `/v1/projects/${projectId}/database/connection-info`);\n }\n\n // ---------------------------------------------------------------------------\n // Messages\n // ---------------------------------------------------------------------------\n\n /**\n * Get a message by ID. Returns the message content, status, and (for user messages)\n * the AI response if available. Use to poll for completion after `chat()`.\n */\n async getMessage(projectId: string, messageId: string): Promise<GetMessageResponse> {\n return this.request<GetMessageResponse>(\"GET\", `/v1/projects/${projectId}/messages/${messageId}`);\n }\n\n /**\n * Poll for message completion. Waits until the AI response reaches a terminal\n * status (completed, stopped) or the timeout expires.\n *\n * Handles edge cases: 404 grace period for race conditions between queue\n * dequeue and event creation, and queue pause detection.\n */\n async waitForMessageCompletion(\n projectId: string,\n messageId: string,\n options?: MessageCompletionOptions,\n ): Promise<MessageCompletionResult> {\n const pollInterval = options?.pollInterval ?? 3000;\n const timeout = options?.timeout ?? 600_000;\n const deadline = Date.now() + timeout;\n let notFoundSince: number | null = null;\n const notFoundGraceMs = 15_000;\n\n while (Date.now() < deadline) {\n try {\n const msg = await this.getMessage(projectId, messageId);\n notFoundSince = null;\n\n if (msg.status === \"queued\") {\n if (msg.queue_paused && msg.queue_pause_reason !== \"hitl_tool\") {\n return {\n status: \"error\",\n message_id: messageId,\n content: \"\",\n error:\n `Message is queued (position ${msg.queue_position ?? \"unknown\"}) but the queue is paused` +\n (msg.queue_pause_reason ? ` (reason: ${msg.queue_pause_reason})` : \"\") +\n `. Unpause the queue in the Lovable editor, or use wait=false to return immediately.`,\n };\n }\n await sleep(pollInterval);\n continue;\n }\n\n const ai = msg.response;\n if (ai) {\n if (ai.status === \"completed\" || ai.status === \"stopped\") {\n return {\n status: ai.status === \"completed\" ? \"completed\" : \"error\",\n message_id: ai.message_id,\n content: ai.content,\n edit_id: ai.edit_id,\n commit_sha: ai.commit_sha,\n summary: ai.summary,\n cost_credits: ai.cost_credits,\n };\n }\n }\n\n if (msg.role === \"assistant\") {\n if (msg.status === \"completed\" || msg.status === \"stopped\") {\n return {\n status: msg.status === \"completed\" ? \"completed\" : \"error\",\n message_id: msg.message_id,\n content: msg.content,\n edit_id: msg.edit_id,\n commit_sha: msg.commit_sha,\n summary: msg.summary,\n cost_credits: msg.cost_credits,\n };\n }\n }\n\n await sleep(pollInterval);\n } catch (err) {\n if (err instanceof ApiError && err.status === 404) {\n if (notFoundSince === null) {\n notFoundSince = Date.now();\n }\n if (Date.now() - notFoundSince < notFoundGraceMs) {\n await sleep(pollInterval);\n continue;\n }\n return {\n status: \"error\",\n message_id: messageId,\n content: \"\",\n error: \"Message not found. It may have been deleted from the queue.\",\n };\n }\n await sleep(pollInterval);\n }\n }\n\n return {\n status: \"timeout\",\n message_id: messageId,\n content: \"\",\n error: `Agent did not finish within ${timeout / 1000}s`,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Knowledge\n // ---------------------------------------------------------------------------\n\n /** Get workspace knowledge (custom instructions for the AI agent). */\n async getWorkspaceKnowledge(workspaceId: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"GET\", `/v1/workspaces/${workspaceId}/knowledge`);\n }\n\n /** Set workspace knowledge. Max 10,000 characters. */\n async setWorkspaceKnowledge(workspaceId: string, content: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"PUT\", `/v1/workspaces/${workspaceId}/knowledge`, { content });\n }\n\n /** Get project knowledge (custom instructions for the AI agent). */\n async getProjectKnowledge(projectId: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"GET\", `/v1/projects/${projectId}/knowledge`);\n }\n\n /** Set project knowledge. Max 10,000 characters. */\n async setProjectKnowledge(projectId: string, content: string): Promise<KnowledgeResponse> {\n return this.request<KnowledgeResponse>(\"PUT\", `/v1/projects/${projectId}/knowledge`, { content });\n }\n\n // ---------------------------------------------------------------------------\n // Git operations\n // ---------------------------------------------------------------------------\n\n /**\n * Get the structured diff for a message or commit.\n * Pass `messageId` to get the diff for a specific AI message,\n * or `sha` for a specific commit.\n */\n async getDiff(\n projectId: string,\n params: { messageId?: string; sha?: string; baseSha?: string },\n ): Promise<GitDiffResponse> {\n const qs = new URLSearchParams();\n if (params.messageId) qs.set(\"message_id\", params.messageId);\n if (params.sha) qs.set(\"sha\", params.sha);\n if (params.baseSha) qs.set(\"base_sha\", params.baseSha);\n return this.request<GitDiffResponse>(\"GET\", `/v1/projects/${projectId}/git/diff?${qs.toString()}`);\n }\n\n /** List all files in a project at a specific git ref. */\n async listFiles(projectId: string, ref: string): Promise<GitFilesResponse> {\n const qs = new URLSearchParams({ ref });\n return this.request<GitFilesResponse>(\"GET\", `/v1/projects/${projectId}/git/files?${qs.toString()}`);\n }\n\n /** Read the raw content of a single file at a specific git ref. Returns text. */\n async readFile(projectId: string, path: string, ref: string): Promise<string> {\n const qs = new URLSearchParams({ path, ref });\n return this.requestText(\"GET\", `/v1/projects/${projectId}/git/file?${qs.toString()}`);\n }\n\n // ---------------------------------------------------------------------------\n // Edits\n // ---------------------------------------------------------------------------\n\n /** List the edit history of a project. */\n async listEdits(projectId: string, params?: { limit?: number; before?: string }): Promise<EditsResponse> {\n const qs = new URLSearchParams();\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n if (params?.before) qs.set(\"before\", params.before);\n const suffix = qs.toString() ? `?${qs.toString()}` : \"\";\n return this.request<EditsResponse>(\"GET\", `/v1/projects/${projectId}/edits${suffix}`);\n }\n\n // ---------------------------------------------------------------------------\n // File upload\n // ---------------------------------------------------------------------------\n\n /** Get a presigned URL for uploading a file. Returns the upload URL and file ID. */\n async getFileUploadUrl(params: { file_name: string; content_type?: string }): Promise<FileUploadUrlResponse> {\n return this.request<FileUploadUrlResponse>(\"POST\", \"/v1/files/upload-url\", params);\n }\n\n // ---------------------------------------------------------------------------\n // Visibility\n // ---------------------------------------------------------------------------\n\n /** Set a project's visibility (draft, private, or public). */\n async setProjectVisibility(projectId: string, visibility: string): Promise<{ visibility: string }> {\n return this.request<{ visibility: string }>(\"PUT\", `/v1/projects/${projectId}/visibility`, { visibility });\n }\n\n /** Set a folder's visibility (personal or workspace). */\n async setFolderVisibility(\n workspaceId: string,\n folderId: string,\n visibility: string,\n ): Promise<{ visibility: string }> {\n return this.request<{ visibility: string }>(\"PUT\", `/v1/workspaces/${workspaceId}/folders/${folderId}/visibility`, {\n visibility,\n });\n }\n\n // ---------------------------------------------------------------------------\n // Library & template projects\n // ---------------------------------------------------------------------------\n\n /** List available design system library projects in a workspace. */\n async listLibraryProjects(workspaceId: string): Promise<{ libraries: LibraryProjectResponse[] }> {\n return this.request<{ libraries: LibraryProjectResponse[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/available-library-projects`,\n );\n }\n\n /** List available template projects in a workspace. */\n async listTemplateProjects(workspaceId: string): Promise<{ templates: TemplateProjectResponse[] }> {\n return this.request<{ templates: TemplateProjectResponse[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/available-template-projects`,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Connectors (MCP servers)\n // ---------------------------------------------------------------------------\n\n /** List all connectors in a workspace. */\n async listConnectors(workspaceId: string): Promise<{ connectors: ConnectorResponse[] }> {\n return this.request<{ connectors: ConnectorResponse[] }>(\"GET\", `/v1/workspaces/${workspaceId}/connectors`);\n }\n\n /** Add a connector to a workspace. The server URL is tested before saving. */\n async addConnector(workspaceId: string, body: AddConnectorBody): Promise<ConnectorResponse> {\n return this.request<ConnectorResponse>(\"POST\", `/v1/workspaces/${workspaceId}/connectors`, body);\n }\n\n /** Remove a connector from a workspace. */\n async removeConnector(workspaceId: string, connectorId: string): Promise<{ success: boolean }> {\n return this.request<{ success: boolean }>(\"DELETE\", `/v1/workspaces/${workspaceId}/connectors/${connectorId}`);\n }\n\n /** Browse available connector templates. */\n async listAvailableConnectors(workspaceId: string): Promise<{ catalog: AvailableConnectorEntry[] }> {\n return this.request<{ catalog: AvailableConnectorEntry[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/available-connectors`,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Connectors\n // ---------------------------------------------------------------------------\n\n /** List standard (OAuth-based) connectors in a workspace. */\n async listStandardConnectors(workspaceId: string): Promise<{ connectors: StandardConnectorItem[] }> {\n return this.request<{ connectors: StandardConnectorItem[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/connectors/standard`,\n );\n }\n\n /** List seamless (zero-config) connectors in a workspace. */\n async listSeamlessConnectors(workspaceId: string): Promise<{ connectors: SeamlessConnectorItem[] }> {\n return this.request<{ connectors: SeamlessConnectorItem[] }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/connectors/seamless`,\n );\n }\n\n /** List MCP connectors in a workspace. */\n async listMCPConnectors(workspaceId: string): Promise<{ connectors: MCPConnectorItem[]; custom_enabled: boolean }> {\n return this.request<{ connectors: MCPConnectorItem[]; custom_enabled: boolean }>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/connectors/mcp`,\n );\n }\n\n /** List authenticated connections (accounts) in a workspace. */\n async listConnections(\n workspaceId: string,\n params?: { connector_id?: string },\n ): Promise<{ connections: ConnectionItem[] }> {\n const qs = new URLSearchParams();\n if (params?.connector_id) qs.set(\"connector_id\", params.connector_id);\n const suffix = qs.toString() ? `?${qs.toString()}` : \"\";\n return this.request<{ connections: ConnectionItem[] }>(\"GET\", `/v1/workspaces/${workspaceId}/connections${suffix}`);\n }\n\n // ---------------------------------------------------------------------------\n // Analytics\n // ---------------------------------------------------------------------------\n\n /** Get historical analytics for a published project. */\n async getProjectAnalytics(\n projectId: string,\n params: { startDate: string; endDate: string; granularity?: string },\n ): Promise<ProjectAnalyticsResponse> {\n const qs = new URLSearchParams({\n startDate: params.startDate,\n endDate: params.endDate,\n });\n if (params.granularity) qs.set(\"granularity\", params.granularity);\n return this.request<ProjectAnalyticsResponse>(\"GET\", `/v1/projects/${projectId}/analytics?${qs.toString()}`);\n }\n\n /** Get real-time visitor trend for a published project. */\n async getProjectAnalyticsTrend(projectId: string): Promise<ProjectAnalyticsTrendResponse> {\n return this.request<ProjectAnalyticsTrendResponse>(\"GET\", `/v1/projects/${projectId}/analytics/trend`);\n }\n\n /**\n * Publish a project.\n *\n * This triggers a deployment which makes the project publicly accessible.\n * The deployment runs asynchronously - use waitForProjectPublished() to wait for completion.\n *\n * @param projectId - The project ID to publish\n * @param options.name - Optional custom slug for the published URL\n * @returns Deployment info including deployment ID\n */\n async publish(projectId: string, options?: { name?: string }): Promise<DeploymentResponse> {\n return this.request<DeploymentResponse>(\"POST\", `/v1/projects/${projectId}/deployments`, {\n name: options?.name,\n });\n }\n\n /**\n * Remix (fork) an existing project, optionally at a specific message point in time.\n *\n * When `messageId` is provided, the remix captures the project state as it was\n * just before that message was processed (default). Set `remixMode: \"including\"`\n * to include the message and its AI response in the remix.\n * Without `messageId`, the full current state is remixed.\n *\n * @param sourceProjectId - The project to remix from\n * @param options.workspaceId - Target workspace for the new project\n * @param options.messageId - Optional message ID to snapshot at\n * @param options.remixMode - \"before\" (default): state before the message; \"including\": state after the message and its AI response\n * @param options.includeHistory - Whether to preserve chat history (default: false)\n * @param options.includeCustomKnowledge - Whether to copy custom instructions (default: false)\n * @param options.initialMessage - Optional initial message to send after remix\n * @returns The remix job ID for polling progress\n */\n async remixProject(sourceProjectId: string, options: RemixProjectOptions): Promise<string> {\n const body: RemixInitBody = {\n workspace_id: options.workspaceId,\n include_history: options.includeHistory,\n include_custom_knowledge: options.includeCustomKnowledge,\n project_name: options.projectName,\n skip_initial_remix_message: options.skipInitialRemixMessage,\n skip_integrations: options.skipIntegrations,\n };\n\n if (options.messageId) {\n body.message_id = options.messageId;\n body.remix_mode = options.remixMode ?? \"before\";\n }\n\n if (options.initialMessage) {\n body.initial_message = {\n id: crypto.randomUUID(),\n message: options.initialMessage,\n chat_only: false,\n headless: true,\n };\n }\n\n const response = await this.request<RemixInitResponse>(\"POST\", `/v1/projects/${sourceProjectId}/remix/init`, body);\n return response.job_id;\n }\n\n /**\n * Wait for a remix operation to complete.\n *\n * Polls the remix progress endpoint until the job reaches \"completed\" or \"error\" status.\n *\n * @param sourceProjectId - The source project ID (used for the progress endpoint)\n * @param jobId - The job ID returned by `remixProject()`\n * @param options.pollInterval - Time between polls in ms (default: 2000)\n * @param options.timeout - Maximum time to wait in ms (default: 300000 = 5 minutes)\n * @param options.onProgress - Optional callback for status/step updates\n * @returns The new project ID\n * @throws Error if the remix fails or timeout is reached\n */\n async waitForRemix(sourceProjectId: string, jobId: string, options?: RemixWaitOptions): Promise<RemixResult> {\n const pollInterval = options?.pollInterval ?? 2000;\n const timeout = options?.timeout ?? 300000;\n const startTime = Date.now();\n\n while (true) {\n const progress = await this.request<RemixProgressResponse>(\n \"GET\",\n `/v1/projects/${sourceProjectId}/remix/progress?job_id=${encodeURIComponent(jobId)}`,\n );\n\n options?.onProgress?.(progress.status, progress.step);\n\n if (progress.status === \"completed\" && progress.result) {\n return { projectId: progress.result.project_id };\n }\n\n if (progress.status === \"error\") {\n throw new Error(progress.error_message ?? \"Remix failed\");\n }\n\n if (Date.now() - startTime > timeout) {\n throw new Error(`Timeout waiting for remix of project ${sourceProjectId}`);\n }\n\n await sleep(pollInterval);\n }\n }\n\n /**\n * Wait for a project to reach \"completed\" status.\n *\n * Projects start in \"in_progress\" status while being created/built.\n * This method polls until the status becomes \"completed\" or \"failed\".\n * A successful completion means the project's preview is ready to view.\n *\n * @param projectId - The project ID to wait for\n * @param options.pollInterval - Time between polls in ms (default: 2000)\n * @param options.timeout - Maximum time to wait in ms (default: 300000 = 5 minutes)\n * @param options.onProgress - Optional callback for status updates\n * @returns The completed project\n * @throws Error if project fails or timeout is reached\n */\n async waitForProjectReady(projectId: string, options?: WaitOptions): Promise<ProjectResponse> {\n const pollInterval = options?.pollInterval ?? 2000;\n const timeout = options?.timeout ?? 300000;\n const startTime = Date.now();\n\n while (true) {\n const project = await this.getProject(projectId);\n options?.onProgress?.(project);\n\n if (project.status === \"completed\") {\n return project;\n }\n\n if (project.status === \"failed\") {\n throw new Error(`Project ${projectId} failed to build`);\n }\n\n if (Date.now() - startTime > timeout) {\n throw new Error(`Timeout waiting for project ${projectId} to be ready`);\n }\n\n await sleep(pollInterval);\n }\n }\n\n /**\n * Wait for the AI response to a chat message.\n *\n * Connects to the project's message stream (SSE) and accumulates the\n * response content until the message is complete. Returns the full\n * response text along with the project's preview URL.\n *\n * Use this after `chat()` or after `createProject()` with `initialMessage`.\n *\n * @param projectId - The project ID to listen for\n * @param options.timeout - Maximum time to wait in ms (default: 300000 = 5 minutes)\n * @returns The AI response content and preview URL\n * @throws Error if the stream fails or timeout is reached\n */\n async waitForResponse(projectId: string, options?: ChatResponseOptions): Promise<ChatResponse> {\n const timeout = options?.timeout ?? 300000;\n const url = `${this.baseUrl}/v1/projects/${projectId}/messages/stream`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n headers: {\n ...this.authHeaders,\n ...this.extraHeaders,\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new ApiError(response.status, `Failed to connect to message stream: HTTP ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error(\"Response body is not readable\");\n }\n\n const result = await this.consumeSSEStream(response.body);\n return {\n content: result.content,\n messageId: result.messageId,\n previewUrl: this.getPreviewUrl(projectId),\n };\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw new Error(`Timeout waiting for response on project ${projectId}`);\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Developer/experimental APIs. These are not part of the stable v1 surface\n * and may change without notice.\n */\n get _dev() {\n return {\n /**\n * Fetch Braintrust traces for a specific chat message.\n *\n * Returns the trace spans associated with the AI response message.\n * The messageId is available from the ChatResponse returned by waitForResponse().\n *\n * Use the `purposes` option to filter which span types are returned.\n * When a purpose has multiple spans (e.g. main_agent across turns),\n * only the last span is returned — it contains the full accumulated context.\n *\n * @param projectId - The project ID\n * @param messageId - The AI message ID (from ChatResponse.messageId)\n * @param options.purposes - Filter spans by purpose (e.g. [\"main_agent\", \"knowledge_rag\"])\n * @returns The trace data including filtered spans\n */\n getMessageTraces: async (\n projectId: string,\n messageId: string,\n options?: GetMessageTracesOptions,\n ): Promise<MessageTracesResponse> => {\n const params = new URLSearchParams();\n if (options?.purposes?.length) {\n params.set(\"purposes\", options.purposes.join(\",\"));\n }\n const query = params.toString();\n const path = `/v1/_dev/projects/${projectId}/messages/${messageId}/traces${query ? `?${query}` : \"\"}`;\n return this.request<MessageTracesResponse>(\"GET\", path);\n },\n\n /**\n * Fetch traces for multiple messages across projects in parallel.\n *\n * Fires concurrent requests (up to `concurrency` at a time) and collects\n * results. Failed requests are captured in `errors` instead of throwing.\n *\n * @param queries - Array of { projectId, messageId } to fetch\n * @param options.purposes - Filter spans by purpose (applied to all queries)\n * @param options.concurrency - Max parallel requests (default: 5)\n * @returns Object with `traces` map (keyed by messageId) and `errors` map\n */\n getMessageTracesBatch: async (\n queries: TraceQuery[],\n options?: GetMessageTracesOptions & { concurrency?: number },\n ): Promise<BatchTracesResult> => {\n const concurrency = options?.concurrency ?? 5;\n const traces = new Map<string, MessageTracesResponse>();\n const errors = new Map<string, Error>();\n const purposeOpts = options?.purposes ? { purposes: options.purposes } : undefined;\n\n const pending = [...queries];\n const executing = new Set<Promise<void>>();\n\n for (const query of pending) {\n const task = this._dev\n .getMessageTraces(query.projectId, query.messageId, purposeOpts)\n .then((result) => {\n traces.set(query.messageId, result);\n })\n .catch((err) => {\n errors.set(query.messageId, err instanceof Error ? err : new Error(String(err)));\n })\n .finally(() => {\n executing.delete(task);\n });\n\n executing.add(task);\n\n if (executing.size >= concurrency) {\n await Promise.race(executing);\n }\n }\n\n await Promise.all(executing);\n\n return { traces, errors };\n },\n\n /**\n * Re-run project reviewers (e.g. project_success_v3, user_sentiment) for past assistant\n * messages. Requires an API key with project write access.\n */\n replayReviews: async (projectId: string, body: ReplayReviewsRequestBody): Promise<ReplayReviewsResponse> => {\n return this.request<ReplayReviewsResponse>(\"POST\", `/v1/_dev/projects/${projectId}/reviews/replay`, body);\n },\n };\n }\n\n private isFileInput(file: File | FileInput): file is FileInput {\n return \"data\" in file;\n }\n\n private async uploadFile(file: File | FileInput): Promise<UnscopedFile> {\n const fileName = this.isFileInput(file) ? file.name : file.name;\n const mimeType = this.isFileInput(file) ? file.type : file.type;\n const body = this.isFileInput(file) ? file.data : file;\n\n const { url, file_id: objectPath } = await this.request<{ url: string; file_id: string }>(\n \"POST\",\n \"/v1/files/upload-url\",\n {\n file_name: fileName,\n content_type: mimeType,\n },\n );\n\n const uploadResponse = await fetch(url, {\n method: \"PUT\",\n body,\n headers: { \"Content-Type\": mimeType },\n });\n if (!uploadResponse.ok) {\n throw new Error(`File upload failed for \"${fileName}\": HTTP ${uploadResponse.status}`);\n }\n\n return { file_id: objectPath, type: \"user_upload\", file_name: fileName, mime_type: mimeType };\n }\n\n private async uploadFiles(files: (File | FileInput)[]): Promise<UnscopedFile[]> {\n return Promise.all(files.map((file) => this.uploadFile(file)));\n }\n\n private async consumeSSEStream(body: ReadableStream<Uint8Array>): Promise<{ content: string; messageId: string }> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let content = \"\";\n let messageId = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop() ?? \"\";\n\n for (const part of parts) {\n if (!part.trim()) continue;\n\n const lines = part.split(\"\\n\");\n let eventType = \"\";\n let eventData = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event: \")) {\n eventType = line.slice(7);\n } else if (line.startsWith(\"data: \")) {\n eventData = line.slice(6);\n }\n }\n\n if (eventType === \"message\" && eventData) {\n try {\n const data = JSON.parse(eventData);\n if (typeof data.content === \"string\") {\n content += data.content;\n }\n if (typeof data.message_id === \"string\" && data.message_id) {\n messageId = data.message_id;\n }\n if (data.is_final) {\n return { content, messageId };\n }\n } catch {\n // Skip non-JSON data lines\n }\n }\n\n if (eventType === \"error\") {\n let detail = \"Stream error from server\";\n try {\n const data = JSON.parse(eventData);\n if (data.message) detail = data.message;\n } catch {\n // use default message\n }\n throw new Error(detail);\n }\n }\n }\n } finally {\n void reader.cancel();\n }\n\n return { content, messageId };\n }\n\n /**\n * Wait for a project to be published (deployed).\n *\n * This method polls until the project has `is_published: true` and a `url`.\n *\n * @param projectId - The project ID to wait for\n * @param options.pollInterval - Time between polls in ms (default: 3000)\n * @param options.timeout - Maximum time to wait in ms (default: 600000 = 10 minutes)\n * @param options.onProgress - Optional callback for status updates\n * @returns The published project with URL\n * @throws Error if timeout is reached\n */\n async waitForProjectPublished(projectId: string, options?: WaitOptions): Promise<ProjectResponse> {\n const pollInterval = options?.pollInterval ?? 3000;\n const timeout = options?.timeout ?? 600000;\n const startTime = Date.now();\n\n while (true) {\n const project = await this.getProject(projectId);\n options?.onProgress?.(project);\n\n if (project.is_published && project.url) {\n return project;\n }\n\n if (project.status === \"failed\") {\n throw new Error(`Project ${projectId} failed to build`);\n }\n\n if (Date.now() - startTime > timeout) {\n throw new Error(`Timeout waiting for project ${projectId} to be published`);\n }\n\n await sleep(pollInterval);\n }\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"mappings":"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","names":[]}
|