diff --git a/packages/turso-serverless/src/compat.ts b/packages/turso-serverless/src/compat.ts index c5f954389..44523d942 100644 --- a/packages/turso-serverless/src/compat.ts +++ b/packages/turso-serverless/src/compat.ts @@ -307,6 +307,11 @@ class LibSQLClient implements Client { close(): void { this._closed = true; + // Note: The libSQL client interface expects synchronous close, + // but our underlying session needs async close. We'll fire and forget. + this.session.close().catch(error => { + console.error('Error closing session:', error); + }); } } diff --git a/packages/turso-serverless/src/connection.ts b/packages/turso-serverless/src/connection.ts index a7846e8dc..3f73a08bc 100644 --- a/packages/turso-serverless/src/connection.ts +++ b/packages/turso-serverless/src/connection.ts @@ -90,6 +90,15 @@ export class Connection { const sql = `PRAGMA ${pragma}`; return this.session.execute(sql); } + + /** + * Close the connection. + * + * This sends a close request to the server to properly clean up the stream. + */ + async close(): Promise { + await this.session.close(); + } } /** diff --git a/packages/turso-serverless/src/protocol.ts b/packages/turso-serverless/src/protocol.ts index 07a94e96c..aac5c7117 100644 --- a/packages/turso-serverless/src/protocol.ts +++ b/packages/turso-serverless/src/protocol.ts @@ -52,9 +52,13 @@ export interface SequenceRequest { sql: string; } +export interface CloseRequest { + type: 'close'; +} + export interface PipelineRequest { baton: string | null; - requests: (ExecuteRequest | BatchRequest | SequenceRequest)[]; + requests: (ExecuteRequest | BatchRequest | SequenceRequest | CloseRequest)[]; } export interface PipelineResponse { @@ -63,7 +67,7 @@ export interface PipelineResponse { results: Array<{ type: 'ok' | 'error'; response?: { - type: 'execute' | 'batch' | 'sequence'; + type: 'execute' | 'batch' | 'sequence' | 'close'; result?: ExecuteResult; }; error?: { diff --git a/packages/turso-serverless/src/session.ts b/packages/turso-serverless/src/session.ts index eb401fd03..3adf37a40 100644 --- a/packages/turso-serverless/src/session.ts +++ b/packages/turso-serverless/src/session.ts @@ -7,7 +7,8 @@ import { type CursorResponse, type CursorEntry, type PipelineRequest, - type SequenceRequest + type SequenceRequest, + type CloseRequest } from './protocol.js'; import { DatabaseError } from './error.js'; @@ -248,4 +249,33 @@ export class Session { } } } + + /** + * Close the session. + * + * This sends a close request to the server to properly clean up the stream + * before resetting the local state. + */ + async close(): Promise { + // Only send close request if we have an active baton + if (this.baton) { + try { + const request: PipelineRequest = { + baton: this.baton, + requests: [{ + type: "close" + } as CloseRequest] + }; + + await executePipeline(this.baseUrl, this.config.authToken, request); + } catch (error) { + // Ignore errors during close, as the connection might already be closed + console.error('Error closing session:', error); + } + } + + // Reset local state + this.baton = null; + this.baseUrl = ''; + } } \ No newline at end of file