@sqlitecloud/drivers 1.0.193 → 1.0.245

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.
@@ -19,6 +19,7 @@ export declare class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
19
19
  private startedOn;
20
20
  private executingCommands?;
21
21
  private processCallback?;
22
+ private pendingChunks;
22
23
  /** Handles data received in response to an outbound command sent by processCommands */
23
24
  private processCommandsData;
24
25
  /** Completes a transaction initiated by processCommands */
@@ -45,6 +45,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
45
45
  // buffer to accumulate incoming data until an whole command is received and can be parsed
46
46
  this.buffer = Buffer.alloc(0);
47
47
  this.startedOn = new Date();
48
+ this.pendingChunks = [];
48
49
  }
49
50
  /** True if connection is open */
50
51
  get connected() {
@@ -137,10 +138,11 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
137
138
  }
138
139
  /** Handles data received in response to an outbound command sent by processCommands */
139
140
  processCommandsData(data) {
140
- var _a, _b, _c, _d, _e, _f;
141
+ var _a, _b, _c, _d, _e, _f, _g;
141
142
  try {
142
143
  // append data to buffer as it arrives
143
144
  if (data.length && data.length > 0) {
145
+ // console.debug(`processCommandsData - received ${data.length} bytes`)
144
146
  this.buffer = Buffer.concat([this.buffer, data]);
145
147
  }
146
148
  let dataType = (_a = this.buffer) === null || _a === void 0 ? void 0 : _a.subarray(0, 1).toString();
@@ -154,22 +156,33 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
154
156
  bufferString = bufferString.substring(0, 100) + '...' + bufferString.substring(bufferString.length - 40);
155
157
  }
156
158
  const elapsedMs = new Date().getTime() - this.startedOn.getTime();
157
- console.debug(`<- ${bufferString} (${elapsedMs}ms)`);
159
+ console.debug(`<- ${bufferString} (${bufferString.length} bytes, ${elapsedMs}ms)`);
158
160
  }
159
161
  // need to decompress this buffer before decoding?
160
162
  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);
163
+ const decompressResults = (0, protocol_1.decompressBuffer)(this.buffer);
164
+ if (decompressResults.dataType === protocol_1.CMD_ROWSET_CHUNK) {
165
+ this.pendingChunks.push(decompressResults.buffer);
166
+ this.buffer = decompressResults.remainingBuffer;
167
+ this.processCommandsData(Buffer.alloc(0));
168
+ return;
169
+ }
170
+ else {
171
+ const { data } = (0, protocol_1.popData)(decompressResults.buffer);
172
+ (_c = this.processCommandsFinish) === null || _c === void 0 ? void 0 : _c.call(this, null, data);
173
+ }
167
174
  }
168
175
  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);
176
+ if (dataType !== protocol_1.CMD_ROWSET_CHUNK) {
177
+ const { data } = (0, protocol_1.popData)(this.buffer);
178
+ (_d = this.processCommandsFinish) === null || _d === void 0 ? void 0 : _d.call(this, null, data);
179
+ }
180
+ else {
181
+ const completeChunk = (0, protocol_1.bufferEndsWith)(this.buffer, protocol_1.ROWSET_CHUNKS_END);
182
+ if (completeChunk) {
183
+ const parsedData = (0, protocol_1.parseRowsetChunks)([...this.pendingChunks, this.buffer]);
184
+ (_e = this.processCommandsFinish) === null || _e === void 0 ? void 0 : _e.call(this, null, parsedData);
185
+ }
173
186
  }
174
187
  }
175
188
  }
@@ -179,14 +192,15 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
179
192
  const lastChar = this.buffer.subarray(this.buffer.length - 1, this.buffer.length).toString('utf8');
180
193
  if (lastChar == ' ') {
181
194
  const { data } = (0, protocol_1.popData)(this.buffer);
182
- (_e = this.processCommandsFinish) === null || _e === void 0 ? void 0 : _e.call(this, null, data);
195
+ (_f = this.processCommandsFinish) === null || _f === void 0 ? void 0 : _f.call(this, null, data);
183
196
  }
184
197
  }
185
198
  }
186
199
  catch (error) {
187
- console.assert(error instanceof Error);
200
+ console.error(`processCommandsData - error: ${error}`);
201
+ console.assert(error instanceof Error, 'An error occoured while processing data');
188
202
  if (error instanceof Error) {
189
- (_f = this.processCommandsFinish) === null || _f === void 0 ? void 0 : _f.call(this, error);
203
+ (_g = this.processCommandsFinish) === null || _g === void 0 ? void 0 : _g.call(this, error);
190
204
  }
191
205
  }
192
206
  }
@@ -204,6 +218,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
204
218
  this.processCallback(error, result);
205
219
  }
206
220
  this.buffer = Buffer.alloc(0);
221
+ this.pendingChunks = [];
207
222
  }
208
223
  /** Disconnect immediately, release connection, no events. */
209
224
  close() {
@@ -24,6 +24,7 @@ export declare function parseCommandLength(data: Buffer): number;
24
24
  export declare function decompressBuffer(buffer: Buffer): {
25
25
  buffer: Buffer;
26
26
  dataType: string;
27
+ remainingBuffer: Buffer;
27
28
  };
28
29
  /** Parse error message or extended error message */
29
30
  export declare function parseError(buffer: Buffer, spaceIndex: number): never;
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.formatCommand = exports.popData = exports.parseRowsetChunks = exports.bufferEndsWith = exports.bufferStartsWith = exports.parseRowsetHeader = exports.parseArray = exports.parseError = exports.decompressBuffer = exports.parseCommandLength = exports.hasCommandLength = exports.ROWSET_CHUNKS_END = exports.CMD_PUBSUB = exports.CMD_ARRAY = exports.CMD_COMMAND = exports.CMD_COMPRESSED = exports.CMD_BLOB = exports.CMD_NULL = exports.CMD_JSON = exports.CMD_ROWSET_CHUNK = exports.CMD_ROWSET = exports.CMD_FLOAT = exports.CMD_INT = exports.CMD_ERROR = exports.CMD_ZEROSTRING = exports.CMD_STRING = void 0;
7
7
  const types_1 = require("./types");
8
8
  const rowset_1 = require("./rowset");
9
+ // https://www.npmjs.com/package/lz4js
9
10
  const lz4 = require('lz4js');
10
11
  // The server communicates with clients via commands defined in
11
12
  // SQLiteCloud Server Protocol (SCSP), see more at:
@@ -44,26 +45,31 @@ function parseCommandLength(data) {
44
45
  exports.parseCommandLength = parseCommandLength;
45
46
  /** Receive a compressed buffer, decompress with lz4, return buffer and datatype */
46
47
  function decompressBuffer(buffer) {
48
+ // https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-compression
49
+ // jest test/database.test.ts -t "select large result set"
50
+ // starts with %<commandLength> <compressed> <uncompressed>
47
51
  const spaceIndex = buffer.indexOf(' ');
48
- buffer = buffer.subarray(spaceIndex + 1);
49
- // extract compressed size
50
- const compressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8'));
51
- buffer = buffer.subarray(buffer.indexOf(' ') + 1);
52
- // extract decompressed size
53
- const decompressedSize = parseInt(buffer.subarray(0, buffer.indexOf(' ') + 1).toString('utf8'));
54
- buffer = buffer.subarray(buffer.indexOf(' ') + 1);
52
+ const commandLength = parseInt(buffer.subarray(1, spaceIndex).toString('utf8'));
53
+ let commandBuffer = buffer.subarray(spaceIndex + 1, spaceIndex + 1 + commandLength);
54
+ const remainingBuffer = buffer.subarray(spaceIndex + 1 + commandLength);
55
+ // extract compressed + decompressed size
56
+ const compressedSize = parseInt(commandBuffer.subarray(0, commandBuffer.indexOf(' ') + 1).toString('utf8'));
57
+ commandBuffer = commandBuffer.subarray(commandBuffer.indexOf(' ') + 1);
58
+ const decompressedSize = parseInt(commandBuffer.subarray(0, commandBuffer.indexOf(' ') + 1).toString('utf8'));
59
+ commandBuffer = commandBuffer.subarray(commandBuffer.indexOf(' ') + 1);
55
60
  // extract compressed dataType
56
- const dataType = buffer.subarray(0, 1).toString('utf8');
57
- const decompressedBuffer = Buffer.alloc(decompressedSize);
58
- const compressedBuffer = buffer.subarray(buffer.length - compressedSize);
61
+ const dataType = commandBuffer.subarray(0, 1).toString('utf8');
62
+ let decompressedBuffer = Buffer.alloc(decompressedSize);
63
+ const compressedBuffer = commandBuffer.subarray(commandBuffer.length - compressedSize);
59
64
  // lz4js library is javascript and doesn't have types so we silence the type check
60
65
  // eslint-disable-next-line
61
66
  const decompressionResult = lz4.decompressBlock(compressedBuffer, decompressedBuffer, 0, compressedSize, 0);
62
- buffer = Buffer.concat([buffer.subarray(0, buffer.length - compressedSize), decompressedBuffer]);
67
+ // the entire command is composed of the header (which is not compressed) + the decompressed block
68
+ decompressedBuffer = Buffer.concat([commandBuffer.subarray(0, commandBuffer.length - compressedSize), decompressedBuffer]);
63
69
  if (decompressionResult <= 0 || decompressionResult !== decompressedSize) {
64
70
  throw new Error(`lz4 decompression error at offset ${decompressionResult}`);
65
71
  }
66
- return { buffer, dataType };
72
+ return { buffer: decompressedBuffer, dataType, remainingBuffer };
67
73
  }
68
74
  exports.decompressBuffer = decompressBuffer;
69
75
  /** Parse error message or extended error message */
@@ -117,7 +123,7 @@ function parseRowsetHeader(buffer) {
117
123
  buffer = buffer.subarray(buffer.indexOf(':') + 1);
118
124
  // extract rowset header
119
125
  const { data, fwdBuffer } = popIntegers(buffer, 3);
120
- return {
126
+ const result = {
121
127
  index,
122
128
  metadata: {
123
129
  version: data[0],
@@ -127,6 +133,8 @@ function parseRowsetHeader(buffer) {
127
133
  },
128
134
  fwdBuffer
129
135
  };
136
+ // console.debug(`parseRowsetHeader`, result)
137
+ return result;
130
138
  }
131
139
  exports.parseRowsetHeader = parseRowsetHeader;
132
140
  /** Extract column names and, optionally, more metadata out of a rowset's header */
@@ -195,7 +203,8 @@ function parseRowsetChunks(buffers) {
195
203
  const data = [];
196
204
  // validate and skip data type
197
205
  const dataType = buffer.subarray(0, 1).toString();
198
- console.assert(dataType === exports.CMD_ROWSET_CHUNK);
206
+ if (dataType !== exports.CMD_ROWSET_CHUNK)
207
+ throw new Error(`parseRowsetChunks - dataType: ${dataType} should be CMD_ROWSET_CHUNK`);
199
208
  buffer = buffer.subarray(buffer.indexOf(' ') + 1);
200
209
  while (buffer.length > 0 && !bufferStartsWith(buffer, exports.ROWSET_CHUNKS_END)) {
201
210
  // chunk header, eg: 0:VERS NROWS NCOLS
@@ -240,21 +249,24 @@ function popData(buffer) {
240
249
  }
241
250
  // first character is the data type
242
251
  console.assert(buffer && buffer instanceof Buffer);
243
- const dataType = buffer.subarray(0, 1).toString('utf8');
244
- console.assert(dataType !== exports.CMD_COMPRESSED, "Compressed data shouldn't be decompressed before parsing");
245
- console.assert(dataType !== exports.CMD_ROWSET_CHUNK, 'Chunked data should be parsed by parseRowsetChunks');
252
+ let dataType = buffer.subarray(0, 1).toString('utf8');
253
+ if (dataType == exports.CMD_COMPRESSED)
254
+ throw new Error('Compressed data should be decompressed before parsing');
255
+ if (dataType == exports.CMD_ROWSET_CHUNK)
256
+ throw new Error('Chunked data should be parsed by parseRowsetChunks');
246
257
  let spaceIndex = buffer.indexOf(' ');
247
258
  if (spaceIndex === -1) {
248
259
  spaceIndex = buffer.length - 1;
249
260
  }
250
- let commandEnd = -1;
261
+ let commandEnd = -1, commandLength = -1;
251
262
  if (dataType === exports.CMD_INT || dataType === exports.CMD_FLOAT || dataType === exports.CMD_NULL) {
252
263
  commandEnd = spaceIndex + 1;
253
264
  }
254
265
  else {
255
- const commandLength = parseInt(buffer.subarray(1, spaceIndex).toString());
266
+ commandLength = parseInt(buffer.subarray(1, spaceIndex).toString());
256
267
  commandEnd = spaceIndex + 1 + commandLength;
257
268
  }
269
+ // console.debug(`popData - dataType: ${dataType}, spaceIndex: ${spaceIndex}, commandLength: ${commandLength}, commandEnd: ${commandEnd}`)
258
270
  switch (dataType) {
259
271
  case exports.CMD_INT:
260
272
  return popResults(parseInt(buffer.subarray(1, spaceIndex).toString()));
@@ -282,7 +294,9 @@ function popData(buffer) {
282
294
  parseError(buffer, spaceIndex); // throws custom error
283
295
  break;
284
296
  }
285
- throw new TypeError(`Data type: ${dataType} is not defined in SCSP`);
297
+ const msg = `popData - Data type: ${Number(dataType)} '${dataType}' is not defined in SCSP, spaceIndex: ${spaceIndex}, commandLength: ${commandLength}, commandEnd: ${commandEnd}`;
298
+ console.error(msg);
299
+ throw new TypeError(msg);
286
300
  }
287
301
  exports.popData = popData;
288
302
  /** Format a command to be sent via SCSP protocol */
@@ -7,7 +7,7 @@ import tls from 'tls';
7
7
  /** Default timeout value for queries */
8
8
  export declare const DEFAULT_TIMEOUT: number;
9
9
  /** Default tls connection port */
10
- export declare const DEFAULT_PORT = 9960;
10
+ export declare const DEFAULT_PORT = 8860;
11
11
  /**
12
12
  * Configuration for SQLite cloud connection
13
13
  * @note Options are all lowecase so they 1:1 compatible with C SDK
@@ -7,7 +7,7 @@ exports.SQLiteCloudArrayType = exports.SQLiteCloudError = exports.DEFAULT_PORT =
7
7
  /** Default timeout value for queries */
8
8
  exports.DEFAULT_TIMEOUT = 300 * 1000;
9
9
  /** Default tls connection port */
10
- exports.DEFAULT_PORT = 9960;
10
+ exports.DEFAULT_PORT = 8860;
11
11
  /** Custom error reported by SQLiteCloud drivers */
12
12
  class SQLiteCloudError extends Error {
13
13
  constructor(message, args) {
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.parseBooleanToZeroOne = exports.parseBoolean = exports.parseconnectionstring = exports.validateConfiguration = exports.popCallback = exports.getUpdateResults = exports.prepareSql = exports.escapeSqlParameter = exports.getInitializationCommands = exports.anonimizeError = exports.anonimizeCommand = exports.isNode = exports.isBrowser = void 0;
7
7
  const types_1 = require("./types");
8
8
  const types_2 = require("./types");
9
+ const whatwg_url_1 = require("whatwg-url");
9
10
  //
10
11
  // determining running environment, thanks to browser-or-node
11
12
  // https://www.npmjs.com/package/browser-or-node
@@ -200,7 +201,7 @@ function validateConfiguration(config) {
200
201
  config.clientid || (config.clientid = 'SQLiteCloud');
201
202
  config.verbose = parseBoolean(config.verbose);
202
203
  config.noblob = parseBoolean(config.noblob);
203
- config.compression = parseBoolean(config.compression);
204
+ config.compression = config.compression != undefined && config.compression != null ? parseBoolean(config.compression) : true; // default: true
204
205
  config.create = parseBoolean(config.create);
205
206
  config.non_linearizable = parseBoolean(config.non_linearizable);
206
207
  config.insecure = parseBoolean(config.insecure);
@@ -235,7 +236,7 @@ function parseconnectionstring(connectionstring) {
235
236
  // the sqlitecloud: protocol is not recognized by the URL constructor in browsers
236
237
  // so we need to replace it with https: to make it work
237
238
  const knownProtocolUrl = connectionstring.replace('sqlitecloud:', 'https:');
238
- const url = new URL(knownProtocolUrl);
239
+ const url = new whatwg_url_1.URL(knownProtocolUrl);
239
240
  // all lowecase options
240
241
  const options = {};
241
242
  url.searchParams.forEach((value, key) => {