@sqlitecloud/drivers 0.0.40 → 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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/lib/drivers/connection-tls.d.ts +29 -0
  3. package/lib/drivers/connection-tls.js +220 -0
  4. package/lib/{transport-ws.d.ts → drivers/connection-ws.d.ts} +5 -6
  5. package/lib/{transport-ws.js → drivers/connection-ws.js} +11 -8
  6. package/lib/drivers/connection.d.ts +34 -0
  7. package/lib/drivers/connection.js +81 -0
  8. package/lib/{database.js → drivers/database.js} +68 -19
  9. package/lib/drivers/protocol.d.ts +51 -0
  10. package/lib/drivers/protocol.js +291 -0
  11. package/lib/drivers/queue.d.ts +12 -0
  12. package/lib/drivers/queue.js +42 -0
  13. package/lib/{types.d.ts → drivers/types.d.ts} +4 -2
  14. package/lib/{utilities.d.ts → drivers/utilities.d.ts} +6 -0
  15. package/lib/{utilities.js → drivers/utilities.js} +53 -3
  16. package/lib/index.d.ts +6 -8
  17. package/lib/index.js +13 -13
  18. package/lib/sqlitecloud.drivers.dev.js +619 -0
  19. package/lib/sqlitecloud.drivers.js +1 -0
  20. package/package.json +12 -3
  21. package/lib/connection.d.ts +0 -59
  22. package/lib/connection.js +0 -230
  23. package/lib/sqlitecloud.v0.0.40.dev.js +0 -597
  24. package/lib/sqlitecloud.v0.0.40.js +0 -1
  25. package/lib/transport-tls.d.ts +0 -25
  26. package/lib/transport-tls.js +0 -465
  27. /package/lib/{database.d.ts → drivers/database.d.ts} +0 -0
  28. /package/lib/{rowset.d.ts → drivers/rowset.d.ts} +0 -0
  29. /package/lib/{rowset.js → drivers/rowset.js} +0 -0
  30. /package/lib/{statement.d.ts → drivers/statement.d.ts} +0 -0
  31. /package/lib/{statement.js → drivers/statement.js} +0 -0
  32. /package/lib/{types.js → drivers/types.js} +0 -0
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
 
@@ -0,0 +1,29 @@
1
+ /**
2
+ * connection-tls.ts - connection via tls socket and sqlitecloud protocol
3
+ */
4
+ import { type SQLiteCloudConfig, type ErrorCallback, type ResultsCallback } from './types';
5
+ import { SQLiteCloudConnection } from './connection';
6
+ /**
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.
9
+ */
10
+ export declare class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
11
+ /** Currently opened bun socket used to communicated with SQLiteCloud server */
12
+ private socket?;
13
+ /** True if connection is open */
14
+ get connected(): boolean;
15
+ connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
16
+ /** Will send a command immediately (no queueing), return the rowset/result or throw an error */
17
+ transportCommands(commands: string, callback?: ResultsCallback): this;
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. */
27
+ close(): this;
28
+ }
29
+ export default SQLiteCloudTlsConnection;
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ /**
3
+ * connection-tls.ts - connection via tls socket and sqlitecloud protocol
4
+ */
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;
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.SQLiteCloudTlsConnection = void 0;
30
+ const types_1 = require("./types");
31
+ const connection_1 = require("./connection");
32
+ const utilities_1 = require("./utilities");
33
+ const protocol_1 = require("./protocol");
34
+ const tls = __importStar(require("tls"));
35
+ /**
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.
38
+ */
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
+ }
49
+ /** True if connection is open */
50
+ get connected() {
51
+ return !!this.socket;
52
+ }
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 */
55
+ connectTransport(config, callback) {
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
+ }
60
+ this.config = config;
61
+ const initializationCommands = (0, utilities_1.getInitializationCommands)(config);
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`);
81
+ }
82
+ callback === null || callback === void 0 ? void 0 : callback.call(this, error);
83
+ });
84
+ });
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' }));
100
+ });
101
+ return this;
102
+ }
103
+ /** Will send a command immediately (no queueing), return the rowset/result or throw an error */
104
+ transportCommands(commands, callback) {
105
+ var _a, _b, _c, _d, _e;
106
+ // connection needs to be established?
107
+ if (!this.socket) {
108
+ callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));
109
+ return this;
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;
116
+ // compose commands following SCPC protocol
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]);
145
+ }
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);
155
+ }
156
+ const elapsedMs = new Date().getTime() - this.startedOn.getTime();
157
+ console.debug(`<- ${bufferString} (${elapsedMs}ms)`);
158
+ }
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
+ }
174
+ }
175
+ }
176
+ }
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);
183
+ }
184
+ }
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
+ }
192
+ }
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. */
209
+ close() {
210
+ if (this.socket) {
211
+ this.socket.removeAllListeners();
212
+ this.socket.destroy();
213
+ this.socket = undefined;
214
+ }
215
+ this.operations.clear();
216
+ return this;
217
+ }
218
+ }
219
+ exports.SQLiteCloudTlsConnection = SQLiteCloudTlsConnection;
220
+ exports.default = SQLiteCloudTlsConnection;
@@ -2,23 +2,22 @@
2
2
  * transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket
3
3
  */
4
4
  import { SQLiteCloudConfig, ErrorCallback, ResultsCallback } from './types';
5
- import { ConnectionTransport } from './connection';
5
+ import { SQLiteCloudConnection } from './connection';
6
6
  /**
7
7
  * Implementation of TransportConnection that connects to the database indirectly
8
8
  * via SQLite Cloud Gateway, a socket.io based deamon that responds to sql query
9
9
  * requests by returning results and rowsets in json format. The gateway handles
10
10
  * connect, disconnect, retries, order of operations, timeouts, etc.
11
11
  */
12
- export declare class WebSocketTransport implements ConnectionTransport {
13
- /** Configuration passed to connect */
14
- private config?;
12
+ export declare class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection {
15
13
  /** Socket.io used to communicated with SQLiteCloud server */
16
14
  private socket?;
17
15
  /** True if connection is open */
18
16
  get connected(): boolean;
19
- connect(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
17
+ connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
20
18
  /** Will send a command immediately (no queueing), return the rowset/result or throw an error */
21
- processCommands(commands: string, callback?: ResultsCallback): this;
19
+ transportCommands(commands: string, callback?: ResultsCallback): this;
22
20
  /** Disconnect socket.io from server */
23
21
  close(): this;
24
22
  }
23
+ export default SQLiteCloudWebsocketConnection;
@@ -3,9 +3,10 @@
3
3
  * transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.WebSocketTransport = void 0;
6
+ exports.SQLiteCloudWebsocketConnection = void 0;
7
7
  const types_1 = require("./types");
8
8
  const rowset_1 = require("./rowset");
9
+ const connection_1 = require("./connection");
9
10
  const socket_io_client_1 = require("socket.io-client");
10
11
  /**
11
12
  * Implementation of TransportConnection that connects to the database indirectly
@@ -13,13 +14,13 @@ const socket_io_client_1 = require("socket.io-client");
13
14
  * requests by returning results and rowsets in json format. The gateway handles
14
15
  * connect, disconnect, retries, order of operations, timeouts, etc.
15
16
  */
16
- class WebSocketTransport {
17
+ class SQLiteCloudWebsocketConnection extends connection_1.SQLiteCloudConnection {
17
18
  /** True if connection is open */
18
19
  get connected() {
19
20
  return !!this.socket;
20
21
  }
21
22
  /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
22
- connect(config, callback) {
23
+ connectTransport(config, callback) {
23
24
  var _a;
24
25
  try {
25
26
  // connection established while we were waiting in line?
@@ -27,7 +28,7 @@ class WebSocketTransport {
27
28
  if (!this.socket) {
28
29
  this.config = config;
29
30
  const connectionString = this.config.connectionString;
30
- 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`;
31
32
  this.socket = (0, socket_io_client_1.io)(gatewayUrl, { auth: { token: connectionString } });
32
33
  }
33
34
  callback === null || callback === void 0 ? void 0 : callback.call(this, null);
@@ -38,7 +39,7 @@ class WebSocketTransport {
38
39
  return this;
39
40
  }
40
41
  /** Will send a command immediately (no queueing), return the rowset/result or throw an error */
41
- processCommands(commands, callback) {
42
+ transportCommands(commands, callback) {
42
43
  // connection needs to be established?
43
44
  if (!this.socket) {
44
45
  callback === null || callback === void 0 ? void 0 : callback.call(this, new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' }));
@@ -53,7 +54,7 @@ class WebSocketTransport {
53
54
  const { data, metadata } = response;
54
55
  if (data && metadata) {
55
56
  if (metadata.numberOfRows !== undefined && metadata.numberOfColumns !== undefined && metadata.columns !== undefined) {
56
- console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.processCommands - data is not an array');
57
+ console.assert(Array.isArray(data), 'SQLiteCloudWebsocketConnection.transportCommands - data is not an array');
57
58
  // we can recreate a SQLiteCloudRowset from the response which we know to be an array of arrays
58
59
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
59
60
  const rowset = new rowset_1.SQLiteCloudRowset(metadata, data.flat());
@@ -69,13 +70,15 @@ class WebSocketTransport {
69
70
  /** Disconnect socket.io from server */
70
71
  close() {
71
72
  var _a;
72
- console.assert(this.socket !== null, 'WebsocketTransport.close - connection already closed');
73
+ console.assert(this.socket !== null, 'SQLiteCloudWebsocketConnection.close - connection already closed');
73
74
  if (this.socket) {
74
75
  (_a = this.socket) === null || _a === void 0 ? void 0 : _a.close();
75
76
  this.socket = undefined;
76
77
  }
78
+ this.operations.clear();
77
79
  this.socket = undefined;
78
80
  return this;
79
81
  }
80
82
  }
81
- exports.WebSocketTransport = WebSocketTransport;
83
+ exports.SQLiteCloudWebsocketConnection = SQLiteCloudWebsocketConnection;
84
+ exports.default = SQLiteCloudWebsocketConnection;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * connection.ts - base abstract class for sqlitecloud server connections
3
+ */
4
+ import { SQLiteCloudConfig, ErrorCallback, ResultsCallback } from './types';
5
+ import { OperationsQueue } from './queue';
6
+ /**
7
+ * Base class for SQLiteCloudConnection handles basics and defines methods.
8
+ * Actual connection management and communication with the server in concrete classes.
9
+ */
10
+ export declare abstract class SQLiteCloudConnection {
11
+ /** Parse and validate provided connectionString or configuration */
12
+ constructor(config: SQLiteCloudConfig | string, callback?: ErrorCallback);
13
+ /** Configuration passed by client or extracted from connection string */
14
+ protected config: SQLiteCloudConfig;
15
+ /** Returns the connection's configuration */
16
+ getConfig(): SQLiteCloudConfig;
17
+ /** Operations are serialized by waiting an any pending promises */
18
+ protected operations: OperationsQueue;
19
+ /** Connect will establish a tls or websocket transport to the server based on configuration and environment */
20
+ protected connect(callback?: ErrorCallback): this;
21
+ protected abstract connectTransport(config: SQLiteCloudConfig, callback?: ErrorCallback): this;
22
+ /** Send a command, return the rowset/result or throw an error */
23
+ protected abstract transportCommands(commands: string, callback?: ResultsCallback): this;
24
+ /** Will log to console if verbose mode is enabled */
25
+ protected log(message: string, ...optionalParams: any[]): void;
26
+ /** Returns true if connection is open */
27
+ abstract get connected(): boolean;
28
+ /** Enable verbose logging for debug purposes */
29
+ verbose(): void;
30
+ /** Will enquee a command to be executed and callback with the resulting rowset/result/error */
31
+ sendCommands(commands: string, callback?: ResultsCallback): this;
32
+ /** Disconnect from server, release transport. */
33
+ abstract close(): this;
34
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * connection.ts - base abstract class for sqlitecloud server connections
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SQLiteCloudConnection = void 0;
7
+ const types_1 = require("./types");
8
+ const utilities_1 = require("./utilities");
9
+ const queue_1 = require("./queue");
10
+ const utilities_2 = require("./utilities");
11
+ /**
12
+ * Base class for SQLiteCloudConnection handles basics and defines methods.
13
+ * Actual connection management and communication with the server in concrete classes.
14
+ */
15
+ class SQLiteCloudConnection {
16
+ /** Parse and validate provided connectionString or configuration */
17
+ constructor(config, callback) {
18
+ /** Operations are serialized by waiting an any pending promises */
19
+ this.operations = new queue_1.OperationsQueue();
20
+ if (typeof config === 'string') {
21
+ this.config = (0, utilities_1.validateConfiguration)({ connectionString: config });
22
+ }
23
+ else {
24
+ this.config = (0, utilities_1.validateConfiguration)(config);
25
+ }
26
+ // connect transport layer to server
27
+ this.connect(callback);
28
+ }
29
+ /** Returns the connection's configuration */
30
+ getConfig() {
31
+ return Object.assign({}, this.config);
32
+ }
33
+ //
34
+ // internal methods (some are implemented in concrete classes using different transport layers)
35
+ //
36
+ /** Connect will establish a tls or websocket transport to the server based on configuration and environment */
37
+ connect(callback) {
38
+ this.operations.enqueue(done => {
39
+ this.connectTransport(this.config, error => {
40
+ if (error) {
41
+ console.error(`SQLiteCloudConnection.connect - error connecting ${this.config.host}:${this.config.port} ${error.toString()}`, error);
42
+ this.close();
43
+ }
44
+ if (callback) {
45
+ callback.call(this, error || null);
46
+ }
47
+ done(error);
48
+ });
49
+ });
50
+ return this;
51
+ }
52
+ /** Will log to console if verbose mode is enabled */
53
+ log(message, ...optionalParams) {
54
+ if (this.config.verbose) {
55
+ message = (0, utilities_2.anonimizeCommand)(message);
56
+ console.log(`${new Date().toISOString()} ${this.config.clientId}: ${message}`, ...optionalParams);
57
+ }
58
+ }
59
+ /** Enable verbose logging for debug purposes */
60
+ verbose() {
61
+ this.config.verbose = true;
62
+ }
63
+ /** Will enquee a command to be executed and callback with the resulting rowset/result/error */
64
+ sendCommands(commands, callback) {
65
+ this.operations.enqueue(done => {
66
+ if (!this.connected) {
67
+ const error = new types_1.SQLiteCloudError('Connection not established', { errorCode: 'ERR_CONNECTION_NOT_ESTABLISHED' });
68
+ callback === null || callback === void 0 ? void 0 : callback.call(this, error);
69
+ done(error);
70
+ }
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
+ }
77
+ });
78
+ return this;
79
+ }
80
+ }
81
+ exports.SQLiteCloudConnection = SQLiteCloudConnection;
@@ -2,6 +2,29 @@
2
2
  //
3
3
  // database.ts - database driver api, implements and extends sqlite3
4
4
  //
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;
27
+ };
5
28
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
29
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
30
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -16,18 +39,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
16
39
  };
17
40
  Object.defineProperty(exports, "__esModule", { value: true });
18
41
  exports.Database = void 0;
19
- // Trying as much as possible to be a drop-in replacement for SQLite3 API
20
- // https://github.com/TryGhost/node-sqlite3/wiki/API
21
- // https://github.com/TryGhost/node-sqlite3
22
- // https://github.com/TryGhost/node-sqlite3/blob/master/lib/sqlite3.d.ts
23
- /* eslint-disable @typescript-eslint/no-unused-vars */
24
- /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
25
- const connection_1 = require("./connection");
26
42
  const rowset_1 = require("./rowset");
27
43
  const types_1 = require("./types");
28
44
  const utilities_1 = require("./utilities");
29
45
  const statement_1 = require("./statement");
30
46
  const eventemitter3_1 = __importDefault(require("eventemitter3"));
47
+ const utilities_2 = require("./utilities");
31
48
  // Uses eventemitter3 instead of node events for browser compatibility
32
49
  // https://github.com/primus/eventemitter3
33
50
  /**
@@ -50,29 +67,61 @@ class Database extends eventemitter3_1.default {
50
67
  }
51
68
  // mode is ignored for now
52
69
  // opens first connection to the database automatically
53
- this.getConnection(callback);
70
+ this.getConnection((error, _connection) => {
71
+ if (callback) {
72
+ callback.call(this, error);
73
+ }
74
+ });
54
75
  }
55
76
  //
56
77
  // private methods
57
78
  //
58
79
  /** Returns first available connection from connection pool */
59
80
  getConnection(callback) {
60
- var _a;
81
+ var _a, _b, _c;
61
82
  // TODO sqlitecloud-js / implement database connection pool #10
62
83
  if (((_a = this.connections) === null || _a === void 0 ? void 0 : _a.length) > 0) {
63
84
  callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
64
85
  }
65
86
  else {
66
- this.connections.push(new connection_1.SQLiteCloudConnection(this.config, error => {
67
- if (error) {
68
- this.handleError(this.connections[0], error, callback);
69
- }
70
- else {
71
- console.assert;
72
- callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
73
- this.emitEvent('open');
74
- }
75
- }));
87
+ // connect using websocket if tls is not supported or if explicitly requested
88
+ const useWebsocket = utilities_2.isBrowser || ((_b = this.config) === null || _b === void 0 ? void 0 : _b.useWebsocket) || ((_c = this.config) === null || _c === void 0 ? void 0 : _c.gatewayUrl);
89
+ if (useWebsocket) {
90
+ // socket.io transport works in both node.js and browser environments and connects via SQLite Cloud Gateway
91
+ Promise.resolve().then(() => __importStar(require('./connection-ws'))).then(module => {
92
+ this.connections.push(new module.default(this.config, error => {
93
+ if (error) {
94
+ this.handleError(this.connections[0], error, callback);
95
+ }
96
+ else {
97
+ console.assert;
98
+ callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
99
+ this.emitEvent('open');
100
+ }
101
+ }));
102
+ })
103
+ .catch(error => {
104
+ this.handleError(null, error, callback);
105
+ });
106
+ }
107
+ else {
108
+ // tls sockets work only in node.js environments
109
+ Promise.resolve().then(() => __importStar(require('./connection-tls'))).then(module => {
110
+ this.connections.push(new module.default(this.config, error => {
111
+ if (error) {
112
+ this.handleError(this.connections[0], error, callback);
113
+ }
114
+ else {
115
+ console.assert;
116
+ callback === null || callback === void 0 ? void 0 : callback.call(this, null, this.connections[0]);
117
+ this.emitEvent('open');
118
+ }
119
+ }));
120
+ })
121
+ .catch(error => {
122
+ this.handleError(null, error, callback);
123
+ });
124
+ }
76
125
  }
77
126
  }
78
127
  /** Handles an error by closing the connection, calling the callback and/or emitting an error event */
@@ -0,0 +1,51 @@
1
+ /// <reference types="node" />
2
+ import { type SQLCloudRowsetMetadata, type SQLiteCloudDataTypes } from './types';
3
+ import { SQLiteCloudRowset } from './rowset';
4
+ export declare const CMD_STRING = "+";
5
+ export declare const CMD_ZEROSTRING = "!";
6
+ export declare const CMD_ERROR = "-";
7
+ export declare const CMD_INT = ":";
8
+ export declare const CMD_FLOAT = ",";
9
+ export declare const CMD_ROWSET = "*";
10
+ export declare const CMD_ROWSET_CHUNK = "/";
11
+ export declare const CMD_JSON = "#";
12
+ export declare const CMD_NULL = "_";
13
+ export declare const CMD_BLOB = "$";
14
+ export declare const CMD_COMPRESSED = "%";
15
+ export declare const CMD_COMMAND = "^";
16
+ export declare const CMD_ARRAY = "=";
17
+ export declare const ROWSET_CHUNKS_END = "/6 0 0 0 ";
18
+ /** Analyze first character to check if corresponding data type has LEN */
19
+ export declare function hasCommandLength(firstCharacter: string): boolean;
20
+ /** Analyze a command with explict LEN and extract it */
21
+ export declare function parseCommandLength(data: Buffer): number;
22
+ /** Receive a compressed buffer, decompress with lz4, return buffer and datatype */
23
+ export declare function decompressBuffer(buffer: Buffer): {
24
+ buffer: Buffer;
25
+ dataType: string;
26
+ };
27
+ /** Parse error message or extended error message */
28
+ export declare function parseError(buffer: Buffer, spaceIndex: number): never;
29
+ /** Parse an array of items (each of which will be parsed by type separately) */
30
+ export declare function parseArray(buffer: Buffer, spaceIndex: number): SQLiteCloudDataTypes[];
31
+ /** Parse header in a rowset or chunk of a chunked rowset */
32
+ export declare function parseRowsetHeader(buffer: Buffer): {
33
+ index: number;
34
+ metadata: SQLCloudRowsetMetadata;
35
+ fwdBuffer: Buffer;
36
+ };
37
+ export declare function bufferStartsWith(buffer: Buffer, prefix: string): boolean;
38
+ export declare function bufferEndsWith(buffer: Buffer, suffix: string): boolean;
39
+ /**
40
+ * Parse a chunk of a chunked rowset command, eg:
41
+ * *LEN 0:VERS NROWS NCOLS DATA
42
+ * @see https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk
43
+ */
44
+ export declare function parseRowsetChunks(buffers: Buffer[]): SQLiteCloudRowset;
45
+ /** Parse command, extract its data, return the data and the buffer moved to the first byte after the command */
46
+ export declare function popData(buffer: Buffer): {
47
+ data: SQLiteCloudDataTypes | SQLiteCloudRowset;
48
+ fwdBuffer: Buffer;
49
+ };
50
+ /** Format a command to be sent via SCSP protocol */
51
+ export declare function formatCommand(command: string): string;