@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 +1 -1
- package/lib/drivers/connection-tls.d.ts +14 -10
- package/lib/drivers/connection-tls.js +168 -184
- package/lib/drivers/connection-ws.js +1 -1
- package/lib/drivers/connection.d.ts +2 -0
- package/lib/drivers/connection.js +13 -5
- package/lib/drivers/types.d.ts +2 -2
- package/lib/drivers/utilities.js +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/sqlitecloud.drivers.dev.js +4 -14
- package/lib/sqlitecloud.drivers.js +1 -1
- package/package.json +3 -3
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.
|
|
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 -
|
|
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
|
|
8
|
-
*
|
|
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
|
|
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
|
-
|
|
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 -
|
|
3
|
+
* connection-tls.ts - connection via tls socket and sqlitecloud protocol
|
|
4
4
|
*/
|
|
5
|
-
var
|
|
6
|
-
|
|
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
|
|
15
|
-
const
|
|
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
|
|
19
|
-
*
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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.
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.socket
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
/**
|
|
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 =
|
|
213
|
+
this.socket = undefined;
|
|
230
214
|
}
|
|
231
|
-
this.
|
|
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) ||
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
}
|
package/lib/drivers/types.d.ts
CHANGED
|
@@ -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.
|
|
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;
|
package/lib/drivers/utilities.js
CHANGED
|
@@ -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';
|