@sqlitecloud/drivers 0.0.50 → 0.0.56

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 CHANGED
@@ -17,7 +17,7 @@ npm install @sqlitecloud/drivers
17
17
  ```ts
18
18
  import { Database } from '@sqlitecloud/drivers'
19
19
 
20
- let database = new Database('sqlitecloud://user:password@xxx.sqlite.cloud:8860/chinook.db')
20
+ let database = new Database('sqlitecloud://user:password@xxx.sqlite.cloud:8860/chinook.sqlite')
21
21
 
22
22
  let name = 'Breaking The Rules'
23
23
 
@@ -1,25 +1,29 @@
1
1
  /**
2
- * connection-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol
2
+ * connection-tls.ts - connection via tls socket and sqlitecloud protocol
3
3
  */
4
- import { SQLiteCloudConfig, ErrorCallback, ResultsCallback } from './types';
4
+ import { type SQLiteCloudConfig, type ErrorCallback, type ResultsCallback } from './types';
5
5
  import { SQLiteCloudConnection } from './connection';
6
6
  /**
7
- * Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol.
8
- * Connects with plain socket with no encryption is the ?insecure=1 parameter is specified.
9
- * SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc.
10
- * A connection socket is established when the connection is created and closed when the connection is closed.
11
- * All operations are serialized by waiting for any pending operations to complete. Once a connection is closed,
12
- * it cannot be reopened and you must create a new connection.
7
+ * Implementation of SQLiteCloudConnection that connects to the database using specific Bun APIs
8
+ * that connect to native sockets or tls sockets and communicates via raw, binary protocol.
13
9
  */
14
10
  export declare class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
15
- /** Currently opened tls socket used to communicated with SQLiteCloud server */
11
+ /** Currently opened bun socket used to communicated with SQLiteCloud server */
16
12
  private socket?;
17
13
  /** True if connection is open */
18
14
  get connected(): boolean;
19
15
  connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
20
16
  /** Will send a command immediately (no queueing), return the rowset/result or throw an error */
21
17
  transportCommands(commands: string, callback?: ResultsCallback): this;
22
- /** Disconnect from server, release connection. */
18
+ private buffer;
19
+ private startedOn;
20
+ private executingCommands?;
21
+ private processCallback?;
22
+ /** Handles data received in response to an outbound command sent by processCommands */
23
+ private processCommandsData;
24
+ /** Completes a transaction initiated by processCommands */
25
+ private processCommandsFinish;
26
+ /** Disconnect immediately, release connection, no events. */
23
27
  close(): this;
24
28
  }
25
29
  export default SQLiteCloudTlsConnection;
@@ -1,234 +1,218 @@
1
1
  "use strict";
2
2
  /**
3
- * connection-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol
3
+ * connection-tls.ts - connection via tls socket and sqlitecloud protocol
4
4
  */
5
- var __importDefault = (this && this.__importDefault) || function (mod) {
6
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || function (mod) {
22
+ if (mod && mod.__esModule) return mod;
23
+ var result = {};
24
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
25
+ __setModuleDefault(result, mod);
26
+ return result;
7
27
  };
8
28
  Object.defineProperty(exports, "__esModule", { value: true });
9
29
  exports.SQLiteCloudTlsConnection = void 0;
10
30
  const types_1 = require("./types");
11
31
  const connection_1 = require("./connection");
12
- const protocol_1 = require("./protocol");
13
32
  const utilities_1 = require("./utilities");
14
- const protocol_2 = require("./protocol");
15
- const net_1 = __importDefault(require("net"));
16
- const tls_1 = __importDefault(require("tls"));
33
+ const protocol_1 = require("./protocol");
34
+ const tls = __importStar(require("tls"));
17
35
  /**
18
- * Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol.
19
- * Connects with plain socket with no encryption is the ?insecure=1 parameter is specified.
20
- * SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc.
21
- * A connection socket is established when the connection is created and closed when the connection is closed.
22
- * All operations are serialized by waiting for any pending operations to complete. Once a connection is closed,
23
- * it cannot be reopened and you must create a new connection.
36
+ * Implementation of SQLiteCloudConnection that connects to the database using specific Bun APIs
37
+ * that connect to native sockets or tls sockets and communicates via raw, binary protocol.
24
38
  */
25
39
  class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
40
+ constructor() {
41
+ super(...arguments);
42
+ // processCommands sets up empty buffers, results callback then send the command to the server via socket.write
43
+ // onData is called when data is received, it will process the data until all data is retrieved for a response
44
+ // when response is complete or there's an error, finish is called to call the results callback set by processCommands...
45
+ // buffer to accumulate incoming data until an whole command is received and can be parsed
46
+ this.buffer = Buffer.alloc(0);
47
+ this.startedOn = new Date();
48
+ }
26
49
  /** True if connection is open */
27
50
  get connected() {
28
51
  return !!this.socket;
29
52
  }
30
53
  /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
54
+ /* eslint-disable @typescript-eslint/no-unused-vars */
31
55
  connectTransport(config, callback) {
32
- // connection established while we were waiting in line?
33
- console.assert(!this.connected, 'Connection already established');
34
- // clear all listeners and call done in the operations queue
35
- const finish = error => {
36
- if (this.socket) {
37
- this.socket.removeAllListeners('data');
38
- this.socket.removeAllListeners('error');
39
- this.socket.removeAllListeners('close');
40
- if (error) {
41
- this.close();
42
- }
43
- }
44
- callback === null || callback === void 0 ? void 0 : callback.call(this, error);
45
- };
56
+ console.assert(!this.connected, 'SQLiteCloudTlsConnection.connect - connection already established');
57
+ if (this.config.verbose) {
58
+ console.debug(`-> connecting ${config === null || config === void 0 ? void 0 : config.host}:${config === null || config === void 0 ? void 0 : config.port}`);
59
+ }
46
60
  this.config = config;
47
61
  const initializationCommands = (0, utilities_1.getInitializationCommands)(config);
48
- if (config.insecure) {
49
- // connect to plain socket, without encryption, only if insecure parameter specified
50
- // this option is mainly for testing purposes and is not available on production nodes
51
- // which would need to connect using tls and proper certificates as per code below
52
- const connectionOptions = {
53
- host: config.host,
54
- port: config.port
55
- };
56
- this.socket = net_1.default.connect(connectionOptions, () => {
57
- console.warn(`TlsConnection.connectTransport - connected to ${config.host}:${config.port} using insecure protocol`);
58
- // send initialization commands
59
- console.assert(this.socket, 'Connection already closed');
60
- this.transportCommands(initializationCommands, error => {
61
- if (error && this.socket) {
62
- this.close();
63
- }
64
- if (callback) {
65
- callback === null || callback === void 0 ? void 0 : callback.call(this, error);
66
- callback = undefined;
67
- }
68
- finish(error);
69
- });
70
- });
71
- }
72
- else {
73
- // connect to tls socket, initialize connection, setup event handlers
74
- this.socket = tls_1.default.connect(this.config.port, this.config.host, this.config.tlsOptions, () => {
75
- const tlsSocket = this.socket;
76
- if (!(tlsSocket === null || tlsSocket === void 0 ? void 0 : tlsSocket.authorized)) {
77
- const anonimizedError = (0, utilities_1.anonimizeError)(tlsSocket.authorizationError);
78
- console.error('Connection was not authorized', anonimizedError);
79
- this.close();
80
- finish(new types_1.SQLiteCloudError('Connection was not authorized', { cause: anonimizedError }));
81
- }
82
- else {
83
- // the connection was closed before it was even opened,
84
- // eg. client closed the connection before the server accepted it
85
- if (this.socket === null) {
86
- finish(new types_1.SQLiteCloudError('Connection was closed before it was done opening'));
87
- return;
88
- }
89
- // send initialization commands
90
- console.assert(this.socket, 'Connection already closed');
91
- this.transportCommands(initializationCommands, error => {
92
- if (error && this.socket) {
93
- this.close();
94
- }
95
- if (callback) {
96
- callback === null || callback === void 0 ? void 0 : callback.call(this, error);
97
- callback = undefined;
98
- }
99
- finish(error);
100
- });
62
+ // connect to plain socket, without encryption, only if insecure parameter specified
63
+ // this option is mainly for testing purposes and is not available on production nodes
64
+ // which would need to connect using tls and proper certificates as per code below
65
+ const connectionOptions = {
66
+ host: config.host,
67
+ port: config.port,
68
+ rejectUnauthorized: false,
69
+ // Server name for the SNI (Server Name Indication) TLS extension.
70
+ // https://r2.nodejs.org/docs/v6.11.4/api/tls.html#tls_class_tls_tlssocket
71
+ servername: config.host
72
+ };
73
+ this.socket = tls.connect(connectionOptions, () => {
74
+ var _a;
75
+ if (this.config.verbose) {
76
+ console.debug(`SQLiteCloudTlsConnection - connected to ${this.config.host}, authorized: ${(_a = this.socket) === null || _a === void 0 ? void 0 : _a.authorized}`);
77
+ }
78
+ this.transportCommands(initializationCommands, error => {
79
+ if (this.config.verbose) {
80
+ console.debug(`SQLiteCloudTlsConnection - initialized connection`);
101
81
  }
82
+ callback === null || callback === void 0 ? void 0 : callback.call(this, error);
102
83
  });
103
- }
104
- this.socket.on('close', () => {
105
- this.socket = null;
106
- finish(new types_1.SQLiteCloudError('Connection was closed'));
107
84
  });
108
- this.socket.once('error', (error) => {
109
- console.error('Connection error', error);
110
- finish(new types_1.SQLiteCloudError('Connection error', { cause: error }));
85
+ this.socket.on('data', data => {
86
+ this.processCommandsData(data);
87
+ });
88
+ this.socket.on('error', error => {
89
+ this.close();
90
+ this.processCommandsFinish(new types_1.SQLiteCloudError('Connection error', { errorCode: 'ERR_CONNECTION_ERROR', cause: error }));
91
+ });
92
+ this.socket.on('end', () => {
93
+ this.close();
94
+ if (this.processCallback)
95
+ this.processCommandsFinish(new types_1.SQLiteCloudError('Server ended the connection', { errorCode: 'ERR_CONNECTION_ENDED' }));
96
+ });
97
+ this.socket.on('close', () => {
98
+ this.close();
99
+ this.processCommandsFinish(new types_1.SQLiteCloudError('Connection closed', { errorCode: 'ERR_CONNECTION_CLOSED' }));
111
100
  });
112
101
  return this;
113
102
  }
114
103
  /** Will send a command immediately (no queueing), return the rowset/result or throw an error */
115
104
  transportCommands(commands, callback) {
116
- var _a, _b, _c;
105
+ var _a, _b, _c, _d, _e;
117
106
  // connection needs to be established?
118
107
  if (!this.socket) {
119
108
  callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));
120
109
  return this;
121
110
  }
111
+ // reset buffer and rowset chunks, define response callback
112
+ this.buffer = Buffer.alloc(0);
113
+ this.startedOn = new Date();
114
+ this.processCallback = callback;
115
+ this.executingCommands = commands;
122
116
  // compose commands following SCPC protocol
123
- commands = (0, protocol_1.formatCommand)(commands);
124
- let buffer = Buffer.alloc(0);
125
- const rowsetChunks = [];
126
- // const startedOn = new Date()
127
- // define what to do if an answer does not arrive within the set timeout
128
- let socketTimeout;
129
- // clear all listeners and call done in the operations queue
130
- const finish = (error, result) => {
131
- clearTimeout(socketTimeout);
132
- if (this.socket) {
133
- this.socket.removeAllListeners('data');
134
- this.socket.removeAllListeners('error');
135
- this.socket.removeAllListeners('close');
136
- }
137
- if (callback) {
138
- callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);
139
- callback = undefined;
117
+ const formattedCommands = (0, protocol_1.formatCommand)(commands);
118
+ if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.verbose) {
119
+ console.debug(`-> ${formattedCommands}`);
120
+ }
121
+ const timeoutMs = (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : 0;
122
+ if (timeoutMs > 0) {
123
+ const timeout = setTimeout(() => {
124
+ var _a;
125
+ callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection timeout out', { errorCode: 'ERR_CONNECTION_TIMEOUT' }));
126
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.destroy();
127
+ this.socket = undefined;
128
+ }, timeoutMs);
129
+ (_d = this.socket) === null || _d === void 0 ? void 0 : _d.write(formattedCommands, 'utf-8', () => {
130
+ clearTimeout(timeout); // Clear the timeout on successful write
131
+ });
132
+ }
133
+ else {
134
+ (_e = this.socket) === null || _e === void 0 ? void 0 : _e.write(formattedCommands, 'utf-8');
135
+ }
136
+ return this;
137
+ }
138
+ /** Handles data received in response to an outbound command sent by processCommands */
139
+ processCommandsData(data) {
140
+ var _a, _b, _c, _d, _e, _f;
141
+ try {
142
+ // append data to buffer as it arrives
143
+ if (data.length && data.length > 0) {
144
+ this.buffer = Buffer.concat([this.buffer, data]);
140
145
  }
141
- };
142
- // define the Promise that waits for the server response
143
- const readData = (data) => {
144
- var _a, _b;
145
- try {
146
- // on first ondata event, dataType is read from data, on subsequent ondata event, is read from buffer that is the concatanations of data received on each ondata event
147
- let dataType = buffer.length === 0 ? data.subarray(0, 1).toString() : buffer.subarray(0, 1).toString('utf8');
148
- buffer = Buffer.concat([buffer, data]);
149
- const commandLength = (0, protocol_1.hasCommandLength)(dataType);
150
- if (commandLength) {
151
- const commandLength = (0, protocol_1.parseCommandLength)(buffer);
152
- const hasReceivedEntireCommand = buffer.length - buffer.indexOf(' ') - 1 >= commandLength ? true : false;
153
- if (hasReceivedEntireCommand) {
154
- if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.verbose) {
155
- let bufferString = buffer.toString('utf8');
156
- if (bufferString.length > 1000) {
157
- bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40);
158
- }
159
- // const elapsedMs = new Date().getTime() - startedOn.getTime()
160
- // console.debug(`Receive: ${bufferString} - ${elapsedMs}ms`)
161
- }
162
- // need to decompress this buffer before decoding?
163
- if (dataType === protocol_1.CMD_COMPRESSED) {
164
- ;
165
- ({ buffer, dataType } = (0, protocol_1.decompressBuffer)(buffer));
166
- }
167
- if (dataType !== protocol_1.CMD_ROWSET_CHUNK) {
168
- (_b = this.socket) === null || _b === void 0 ? void 0 : _b.off('data', readData);
169
- const { data } = (0, protocol_1.popData)(buffer);
170
- finish(null, data);
171
- }
172
- else {
173
- // check if rowset received the ending chunk
174
- if ((0, protocol_1.bufferEndsWith)(buffer, protocol_1.ROWSET_CHUNKS_END)) {
175
- rowsetChunks.push(buffer);
176
- const parsedData = (0, protocol_2.parseRowsetChunks)(rowsetChunks);
177
- finish === null || finish === void 0 ? void 0 : finish.call(this, null, parsedData);
178
- }
179
- else {
180
- // no ending string? ask server for another chunk
181
- rowsetChunks.push(buffer);
182
- buffer = Buffer.alloc(0);
183
- }
146
+ let dataType = (_a = this.buffer) === null || _a === void 0 ? void 0 : _a.subarray(0, 1).toString();
147
+ if ((0, protocol_1.hasCommandLength)(dataType)) {
148
+ const commandLength = (0, protocol_1.parseCommandLength)(this.buffer);
149
+ const hasReceivedEntireCommand = this.buffer.length - this.buffer.indexOf(' ') - 1 >= commandLength ? true : false;
150
+ if (hasReceivedEntireCommand) {
151
+ if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.verbose) {
152
+ let bufferString = this.buffer.toString('utf8');
153
+ if (bufferString.length > 1000) {
154
+ bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40);
184
155
  }
156
+ const elapsedMs = new Date().getTime() - this.startedOn.getTime();
157
+ console.debug(`<- ${bufferString} (${elapsedMs}ms)`);
185
158
  }
186
- }
187
- else {
188
- // command with no explicit len so make sure that the final character is a space
189
- const lastChar = buffer.subarray(buffer.length - 1, buffer.length).toString('utf8');
190
- if (lastChar == ' ') {
191
- const { data } = (0, protocol_1.popData)(buffer);
192
- finish(null, data);
159
+ // need to decompress this buffer before decoding?
160
+ if (dataType === protocol_1.CMD_COMPRESSED) {
161
+ ;
162
+ ({ buffer: this.buffer, dataType } = (0, protocol_1.decompressBuffer)(this.buffer));
163
+ }
164
+ if (dataType !== protocol_1.CMD_ROWSET_CHUNK) {
165
+ const { data } = (0, protocol_1.popData)(this.buffer);
166
+ (_c = this.processCommandsFinish) === null || _c === void 0 ? void 0 : _c.call(this, null, data);
167
+ }
168
+ else {
169
+ // check if rowset received the ending chunk in which case it can be unpacked
170
+ if ((0, protocol_1.bufferEndsWith)(this.buffer, protocol_1.ROWSET_CHUNKS_END)) {
171
+ const parsedData = (0, protocol_1.parseRowsetChunks)([this.buffer]);
172
+ (_d = this.processCommandsFinish) === null || _d === void 0 ? void 0 : _d.call(this, null, parsedData);
173
+ }
193
174
  }
194
175
  }
195
176
  }
196
- catch (error) {
197
- console.assert(error instanceof Error);
198
- if (error instanceof Error) {
199
- finish(error);
177
+ else {
178
+ // command with no explicit len so make sure that the final character is a space
179
+ const lastChar = this.buffer.subarray(this.buffer.length - 1, this.buffer.length).toString('utf8');
180
+ if (lastChar == ' ') {
181
+ const { data } = (0, protocol_1.popData)(this.buffer);
182
+ (_e = this.processCommandsFinish) === null || _e === void 0 ? void 0 : _e.call(this, null, data);
200
183
  }
201
184
  }
202
- };
203
- (_a = this.socket) === null || _a === void 0 ? void 0 : _a.once('close', () => {
204
- finish(new types_1.SQLiteCloudError('Connection was closed', { cause: (0, utilities_1.anonimizeCommand)(commands) }));
205
- });
206
- (_b = this.socket) === null || _b === void 0 ? void 0 : _b.write(commands, 'utf8', () => {
207
- var _a, _b;
208
- // @ts-ignore
209
- socketTimeout = setTimeout(() => {
210
- const timeoutError = new types_1.SQLiteCloudError('Request timed out', { cause: (0, utilities_1.anonimizeCommand)(commands) });
211
- // console.debug(`Request timed out, config.timeout is ${this.config?.timeout as number}ms`, timeoutError)
212
- finish(timeoutError);
213
- }, (_a = this.config) === null || _a === void 0 ? void 0 : _a.timeout);
214
- (_b = this.socket) === null || _b === void 0 ? void 0 : _b.on('data', readData);
215
- });
216
- (_c = this.socket) === null || _c === void 0 ? void 0 : _c.once('error', (error) => {
217
- console.error('Socket error', error);
218
- this.close();
219
- finish(new types_1.SQLiteCloudError('Socket error', { cause: (0, utilities_1.anonimizeError)(error) }));
220
- });
221
- return this;
185
+ }
186
+ catch (error) {
187
+ console.assert(error instanceof Error);
188
+ if (error instanceof Error) {
189
+ (_f = this.processCommandsFinish) === null || _f === void 0 ? void 0 : _f.call(this, error);
190
+ }
191
+ }
222
192
  }
223
- /** Disconnect from server, release connection. */
193
+ /** Completes a transaction initiated by processCommands */
194
+ processCommandsFinish(error, result) {
195
+ if (error) {
196
+ if (this.processCallback) {
197
+ console.error('processCommandsFinish - error', error);
198
+ }
199
+ else {
200
+ console.warn('processCommandsFinish - error with no registered callback', error);
201
+ }
202
+ }
203
+ if (this.processCallback) {
204
+ this.processCallback(error, result);
205
+ // this.processCallback = undefined
206
+ }
207
+ }
208
+ /** Disconnect immediately, release connection, no events. */
224
209
  close() {
225
- console.assert(this.socket !== null, 'TlsConnection.close - connection already closed');
226
- this.operations.clear();
227
210
  if (this.socket) {
211
+ this.socket.removeAllListeners();
228
212
  this.socket.destroy();
229
- this.socket = null;
213
+ this.socket = undefined;
230
214
  }
231
- this.socket = undefined;
215
+ this.operations.clear();
232
216
  return this;
233
217
  }
234
218
  }
@@ -28,7 +28,7 @@ class SQLiteCloudWebsocketConnection extends connection_1.SQLiteCloudConnection
28
28
  if (!this.socket) {
29
29
  this.config = config;
30
30
  const connectionString = this.config.connectionString;
31
- const gatewayUrl = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.gatewayUrl) || `ws://${this.config.host}:4000`;
31
+ const gatewayUrl = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.gatewayUrl) || `${this.config.host === 'localhost' ? 'ws' : 'wss'}://${this.config.host}:4000`;
32
32
  this.socket = (0, socket_io_client_1.io)(gatewayUrl, { auth: { token: connectionString } });
33
33
  }
34
34
  callback === null || callback === void 0 ? void 0 : callback.call(this, null);
@@ -12,6 +12,8 @@ export declare abstract class SQLiteCloudConnection {
12
12
  constructor(config: SQLiteCloudConfig | string, callback?: ErrorCallback);
13
13
  /** Configuration passed by client or extracted from connection string */
14
14
  protected config: SQLiteCloudConfig;
15
+ /** Returns the connection's configuration */
16
+ getConfig(): SQLiteCloudConfig;
15
17
  /** Operations are serialized by waiting an any pending promises */
16
18
  protected operations: OperationsQueue;
17
19
  /** Connect will establish a tls or websocket transport to the server based on configuration and environment */
@@ -26,6 +26,10 @@ class SQLiteCloudConnection {
26
26
  // connect transport layer to server
27
27
  this.connect(callback);
28
28
  }
29
+ /** Returns the connection's configuration */
30
+ getConfig() {
31
+ return Object.assign({}, this.config);
32
+ }
29
33
  //
30
34
  // internal methods (some are implemented in concrete classes using different transport layers)
31
35
  //
@@ -37,7 +41,9 @@ class SQLiteCloudConnection {
37
41
  console.error(`SQLiteCloudConnection.connect - error connecting ${this.config.host}:${this.config.port} ${error.toString()}`, error);
38
42
  this.close();
39
43
  }
40
- callback === null || callback === void 0 ? void 0 : callback.call(this, error || null);
44
+ if (callback) {
45
+ callback.call(this, error || null);
46
+ }
41
47
  done(error);
42
48
  });
43
49
  });
@@ -62,10 +68,12 @@ class SQLiteCloudConnection {
62
68
  callback === null || callback === void 0 ? void 0 : callback.call(this, error);
63
69
  done(error);
64
70
  }
65
- this.transportCommands(commands, (error, result) => {
66
- callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);
67
- done(error);
68
- });
71
+ else {
72
+ this.transportCommands(commands, (error, result) => {
73
+ callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);
74
+ done(error);
75
+ });
76
+ }
69
77
  });
70
78
  return this;
71
79
  }
@@ -18,7 +18,7 @@ export interface SQLiteCloudConfig {
18
18
  password?: string;
19
19
  /** True if password is hashed, default is false */
20
20
  passwordHashed?: boolean;
21
- /** Host name is required unless connectionString is provided */
21
+ /** Host name is required unless connectionString is provided, eg: xxx.sqlitecloud.io */
22
22
  host?: string;
23
23
  /** Port number for tls socket */
24
24
  port?: number;
@@ -47,7 +47,7 @@ export interface SQLiteCloudConfig {
47
47
  tlsOptions?: tls.ConnectionOptions;
48
48
  /** True if we should force use of SQLite Cloud Gateway and websocket connections, default: true in browsers, false in node.js */
49
49
  useWebsocket?: boolean;
50
- /** Url where we can connect to a SQLite Cloud Gateway that has a socket.io deamon waiting to connect, eg. ws://host:4000 */
50
+ /** Url where we can connect to a SQLite Cloud Gateway that has a socket.io deamon waiting to connect, eg. wss://host:4000 */
51
51
  gatewayUrl?: string;
52
52
  /** Optional identifier used for verbose logging */
53
53
  clientId?: string;
@@ -175,7 +175,7 @@ function validateConfiguration(config) {
175
175
  if (!config.connectionString) {
176
176
  // build connection string from configuration, values are already validated
177
177
  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
178
- config.connectionString = `sqlitecloud://${config.username}:${config.password}@${config.host}:${config.port}/${config.database}`;
178
+ config.connectionString = `sqlitecloud://${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}@${config.host}:${config.port}/${config.database}`;
179
179
  }
180
180
  return config;
181
181
  }
@@ -194,7 +194,7 @@ function parseConnectionString(connectionString) {
194
194
  url.searchParams.forEach((value, key) => {
195
195
  options[key] = value;
196
196
  });
197
- const config = Object.assign({ username: url.username, password: url.password, host: url.hostname, port: url.port ? parseInt(url.port) : undefined }, options);
197
+ const config = Object.assign({ username: decodeURIComponent(url.username), password: decodeURIComponent(url.password), host: url.hostname, port: url.port ? parseInt(url.port) : undefined }, options);
198
198
  const database = url.pathname.replace('/', ''); // pathname is database name, remove the leading slash
199
199
  if (database) {
200
200
  config.database = database;
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Database } from './drivers/database';
2
2
  export { Statement } from './drivers/statement';
3
3
  export { SQLiteCloudConnection } from './drivers/connection';
4
- export { type SQLiteCloudConfig, type SQLCloudRowsetMetadata, SQLiteCloudError, type ErrorCallback } from './drivers/types';
4
+ export { type SQLiteCloudConfig, type SQLCloudRowsetMetadata, SQLiteCloudError, type ResultsCallback, type ErrorCallback } from './drivers/types';
5
5
  export { SQLiteCloudRowset, SQLiteCloudRow } from './drivers/rowset';
6
6
  export { escapeSqlParameter, prepareSql, parseConnectionString, validateConfiguration } from './drivers/utilities';