@sqlitecloud/drivers 0.0.50 → 1.0.122
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 +3 -3
- package/lib/drivers/connection.d.ts +13 -1
- package/lib/drivers/connection.js +71 -8
- package/lib/drivers/database.js +3 -3
- package/lib/drivers/types.d.ts +25 -18
- package/lib/drivers/utilities.d.ts +10 -2
- package/lib/drivers/utilities.js +88 -29
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/sqlitecloud.drivers.dev.js +7 -17
- package/lib/sqlitecloud.drivers.js +1 -1
- package/package.json +7 -9
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
|
}
|
|
@@ -27,9 +27,9 @@ class SQLiteCloudWebsocketConnection extends connection_1.SQLiteCloudConnection
|
|
|
27
27
|
console.assert(!this.connected, 'Connection already established');
|
|
28
28
|
if (!this.socket) {
|
|
29
29
|
this.config = config;
|
|
30
|
-
const
|
|
31
|
-
const gatewayUrl = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.
|
|
32
|
-
this.socket = (0, socket_io_client_1.io)(gatewayUrl, { auth: { token:
|
|
30
|
+
const connectionstring = this.config.connectionstring;
|
|
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
|
+
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);
|
|
35
35
|
}
|
|
@@ -8,10 +8,12 @@ import { OperationsQueue } from './queue';
|
|
|
8
8
|
* Actual connection management and communication with the server in concrete classes.
|
|
9
9
|
*/
|
|
10
10
|
export declare abstract class SQLiteCloudConnection {
|
|
11
|
-
/** Parse and validate provided
|
|
11
|
+
/** Parse and validate provided connectionstring or configuration */
|
|
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 */
|
|
@@ -27,6 +29,16 @@ export declare abstract class SQLiteCloudConnection {
|
|
|
27
29
|
verbose(): void;
|
|
28
30
|
/** Will enquee a command to be executed and callback with the resulting rowset/result/error */
|
|
29
31
|
sendCommands(commands: string, callback?: ResultsCallback): this;
|
|
32
|
+
/**
|
|
33
|
+
* Sql is a promise based API for executing SQL statements. You can
|
|
34
|
+
* pass a simple string with a SQL statement or a template string
|
|
35
|
+
* using backticks and parameters in ${parameter} format. These parameters
|
|
36
|
+
* will be properly escaped and quoted like when using a prepared statement.
|
|
37
|
+
* @param sql A sql string or a template string in `backticks` format
|
|
38
|
+
* @returns An array of rows in case of selections or an object with
|
|
39
|
+
* metadata in case of insert, update, delete.
|
|
40
|
+
*/
|
|
41
|
+
sql(sql: TemplateStringsArray | string, ...values: any[]): Promise<any>;
|
|
30
42
|
/** Disconnect from server, release transport. */
|
|
31
43
|
abstract close(): this;
|
|
32
44
|
}
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* connection.ts - base abstract class for sqlitecloud server connections
|
|
4
4
|
*/
|
|
5
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
+
});
|
|
13
|
+
};
|
|
5
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
15
|
exports.SQLiteCloudConnection = void 0;
|
|
7
16
|
const types_1 = require("./types");
|
|
@@ -13,12 +22,12 @@ const utilities_2 = require("./utilities");
|
|
|
13
22
|
* Actual connection management and communication with the server in concrete classes.
|
|
14
23
|
*/
|
|
15
24
|
class SQLiteCloudConnection {
|
|
16
|
-
/** Parse and validate provided
|
|
25
|
+
/** Parse and validate provided connectionstring or configuration */
|
|
17
26
|
constructor(config, callback) {
|
|
18
27
|
/** Operations are serialized by waiting an any pending promises */
|
|
19
28
|
this.operations = new queue_1.OperationsQueue();
|
|
20
29
|
if (typeof config === 'string') {
|
|
21
|
-
this.config = (0, utilities_1.validateConfiguration)({
|
|
30
|
+
this.config = (0, utilities_1.validateConfiguration)({ connectionstring: config });
|
|
22
31
|
}
|
|
23
32
|
else {
|
|
24
33
|
this.config = (0, utilities_1.validateConfiguration)(config);
|
|
@@ -26,6 +35,10 @@ class SQLiteCloudConnection {
|
|
|
26
35
|
// connect transport layer to server
|
|
27
36
|
this.connect(callback);
|
|
28
37
|
}
|
|
38
|
+
/** Returns the connection's configuration */
|
|
39
|
+
getConfig() {
|
|
40
|
+
return Object.assign({}, this.config);
|
|
41
|
+
}
|
|
29
42
|
//
|
|
30
43
|
// internal methods (some are implemented in concrete classes using different transport layers)
|
|
31
44
|
//
|
|
@@ -37,7 +50,9 @@ class SQLiteCloudConnection {
|
|
|
37
50
|
console.error(`SQLiteCloudConnection.connect - error connecting ${this.config.host}:${this.config.port} ${error.toString()}`, error);
|
|
38
51
|
this.close();
|
|
39
52
|
}
|
|
40
|
-
|
|
53
|
+
if (callback) {
|
|
54
|
+
callback.call(this, error || null);
|
|
55
|
+
}
|
|
41
56
|
done(error);
|
|
42
57
|
});
|
|
43
58
|
});
|
|
@@ -47,7 +62,7 @@ class SQLiteCloudConnection {
|
|
|
47
62
|
log(message, ...optionalParams) {
|
|
48
63
|
if (this.config.verbose) {
|
|
49
64
|
message = (0, utilities_2.anonimizeCommand)(message);
|
|
50
|
-
console.log(`${new Date().toISOString()} ${this.config.
|
|
65
|
+
console.log(`${new Date().toISOString()} ${this.config.clientid}: ${message}`, ...optionalParams);
|
|
51
66
|
}
|
|
52
67
|
}
|
|
53
68
|
/** Enable verbose logging for debug purposes */
|
|
@@ -62,12 +77,60 @@ class SQLiteCloudConnection {
|
|
|
62
77
|
callback === null || callback === void 0 ? void 0 : callback.call(this, error);
|
|
63
78
|
done(error);
|
|
64
79
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
else {
|
|
81
|
+
this.transportCommands(commands, (error, result) => {
|
|
82
|
+
callback === null || callback === void 0 ? void 0 : callback.call(this, error, result);
|
|
83
|
+
done(error);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
69
86
|
});
|
|
70
87
|
return this;
|
|
71
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Sql is a promise based API for executing SQL statements. You can
|
|
91
|
+
* pass a simple string with a SQL statement or a template string
|
|
92
|
+
* using backticks and parameters in ${parameter} format. These parameters
|
|
93
|
+
* will be properly escaped and quoted like when using a prepared statement.
|
|
94
|
+
* @param sql A sql string or a template string in `backticks` format
|
|
95
|
+
* @returns An array of rows in case of selections or an object with
|
|
96
|
+
* metadata in case of insert, update, delete.
|
|
97
|
+
*/
|
|
98
|
+
sql(sql, ...values) {
|
|
99
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
let preparedSql = '';
|
|
101
|
+
// sql is a TemplateStringsArray, the 'raw' property is specific to TemplateStringsArray
|
|
102
|
+
if (Array.isArray(sql) && 'raw' in sql) {
|
|
103
|
+
sql.forEach((string, i) => {
|
|
104
|
+
preparedSql += string + (i < values.length ? '?' : '');
|
|
105
|
+
});
|
|
106
|
+
preparedSql = (0, utilities_1.prepareSql)(preparedSql, ...values);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
if (typeof sql === 'string') {
|
|
110
|
+
if ((values === null || values === void 0 ? void 0 : values.length) > 0) {
|
|
111
|
+
preparedSql = (0, utilities_1.prepareSql)(sql, ...values);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
preparedSql = sql;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
throw new Error('Invalid sql');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return new Promise((resolve, reject) => {
|
|
122
|
+
this.sendCommands(preparedSql, (error, results) => {
|
|
123
|
+
if (error) {
|
|
124
|
+
reject(error);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
// metadata for operations like insert, update, delete?
|
|
128
|
+
const context = (0, utilities_2.getUpdateResults)(results);
|
|
129
|
+
resolve(context ? context : results);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
72
135
|
}
|
|
73
136
|
exports.SQLiteCloudConnection = SQLiteCloudConnection;
|