@sqlitecloud/drivers 1.0.715 → 1.0.738-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,18 +8,25 @@
8
8
 
9
9
  ## Install
10
10
 
11
+ ### Web / Node.js / Next.js
12
+
11
13
  ```bash
12
14
  npm install @sqlitecloud/drivers
13
15
  ```
14
16
 
15
- ## React Native / Expo Install
17
+ No additional dependencies required - the package works out of the box.
18
+
19
+ ### React Native / Expo
16
20
 
17
- You also have to install Peer Dependencies
21
+ When using this package in React Native or Expo projects, you must install the required peer dependencies. These dependencies are optional and not installed automatically to avoid polluting web and Node.js projects with unnecessary packages.
18
22
 
19
23
  ```bash
20
- npm install @sqlitecloud/drivers react-native-tcp-socket react-native-quick-base64
24
+ npm install @sqlitecloud/drivers
25
+ npm install react-native-tcp-socket react-native-quick-base64 @craftzdog/react-native-buffer react-native-url-polyfill
21
26
  ```
22
27
 
28
+ If you forget to install these dependencies, the package will throw clear error messages indicating which dependency is missing and how to install it.
29
+
23
30
  React Native run iOS
24
31
 
25
32
  ```bash
@@ -2,48 +2,21 @@
2
2
  /**
3
3
  * connection-tls.ts - connection via tls socket and sqlitecloud protocol
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 () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
5
  Object.defineProperty(exports, "__esModule", { value: true });
39
6
  exports.SQLiteCloudTlsConnection = void 0;
40
7
  const connection_1 = require("./connection");
41
8
  const protocol_1 = require("./protocol");
42
9
  const types_1 = require("./types");
43
10
  const utilities_1 = require("./utilities");
11
+ const safe_imports_1 = require("./safe-imports");
44
12
  // explicitly importing buffer library to allow cross-platform support by replacing it
45
- const buffer_1 = require("buffer");
46
- const tls = __importStar(require("tls"));
13
+ // In React Native: Metro resolves 'buffer' to '@craftzdog/react-native-buffer' via package.json react-native field
14
+ // In Web/Node: Uses standard buffer package
15
+ const Buffer = (0, safe_imports_1.getSafeBuffer)();
16
+ // In React Native: Metro resolves 'tls' to 'react-native-tcp-socket' via package.json react-native field
17
+ // In Node: Uses native tls module
18
+ // In Browser: Returns null (browser field sets tls to false)
19
+ const tls = (0, safe_imports_1.getSafeTLS)();
47
20
  /**
48
21
  * Implementation of SQLiteCloudConnection that connects to the database using specific tls APIs
49
22
  * that connect to native sockets or tls sockets and communicates via raw, binary protocol.
@@ -55,7 +28,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
55
28
  // onData is called when data is received, it will process the data until all data is retrieved for a response
56
29
  // when response is complete or there's an error, finish is called to call the results callback set by processCommands...
57
30
  // buffer to accumulate incoming data until an whole command is received and can be parsed
58
- this.buffer = buffer_1.Buffer.alloc(0);
31
+ this.buffer = Buffer.alloc(0);
59
32
  this.startedOn = new Date();
60
33
  this.pendingChunks = [];
61
34
  }
@@ -66,6 +39,15 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
66
39
  /* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
67
40
  connectTransport(config, callback) {
68
41
  console.assert(!this.connected, 'SQLiteCloudTlsConnection.connect - connection already established');
42
+ // Check if tls is available (it's null in browser contexts)
43
+ if (!tls) {
44
+ const error = new types_1.SQLiteCloudError('TLS connections are not available in this environment. Use WebSocket connections instead by setting usewebsocket: true in your configuration.', { errorCode: 'ERR_TLS_NOT_AVAILABLE' });
45
+ if (callback) {
46
+ callback.call(this, error);
47
+ return this;
48
+ }
49
+ throw error;
50
+ }
69
51
  if (this.config.verbose) {
70
52
  console.debug(`-> connecting ${config === null || config === void 0 ? void 0 : config.host}:${config === null || config === void 0 ? void 0 : config.port}`);
71
53
  }
@@ -106,10 +88,10 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
106
88
  // disable Nagle algorithm because we want our writes to be sent ASAP
107
89
  // https://brooker.co.za/blog/2024/05/09/nagle.html
108
90
  this.socket.setNoDelay(true);
109
- this.socket.on('data', data => {
91
+ this.socket.on('data', (data) => {
110
92
  this.processCommandsData(data);
111
93
  });
112
- this.socket.on('error', error => {
94
+ this.socket.on('error', (error) => {
113
95
  this.close();
114
96
  this.processCommandsFinish(new types_1.SQLiteCloudError('Connection error', { errorCode: 'ERR_CONNECTION_ERROR', cause: error }));
115
97
  });
@@ -140,7 +122,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
140
122
  commands = { query: commands };
141
123
  }
142
124
  // reset buffer and rowset chunks, define response callback
143
- this.buffer = buffer_1.Buffer.alloc(0);
125
+ this.buffer = Buffer.alloc(0);
144
126
  this.startedOn = new Date();
145
127
  this.processCallback = callback;
146
128
  this.executingCommands = commands;
@@ -173,7 +155,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
173
155
  // append data to buffer as it arrives
174
156
  if (data.length && data.length > 0) {
175
157
  // console.debug(`processCommandsData - received ${data.length} bytes`)
176
- this.buffer = buffer_1.Buffer.concat([this.buffer, data]);
158
+ this.buffer = Buffer.concat([this.buffer, data]);
177
159
  }
178
160
  let dataType = (_a = this.buffer) === null || _a === void 0 ? void 0 : _a.subarray(0, 1).toString();
179
161
  if ((0, protocol_1.hasCommandLength)(dataType)) {
@@ -194,7 +176,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
194
176
  if (decompressResults.dataType === protocol_1.CMD_ROWSET_CHUNK) {
195
177
  this.pendingChunks.push(decompressResults.buffer);
196
178
  this.buffer = decompressResults.remainingBuffer;
197
- this.processCommandsData(buffer_1.Buffer.alloc(0));
179
+ this.processCommandsData(Buffer.alloc(0));
198
180
  return;
199
181
  }
200
182
  else {
@@ -247,7 +229,7 @@ class SQLiteCloudTlsConnection extends connection_1.SQLiteCloudConnection {
247
229
  if (this.processCallback) {
248
230
  this.processCallback(error, result);
249
231
  }
250
- this.buffer = buffer_1.Buffer.alloc(0);
232
+ this.buffer = Buffer.alloc(0);
251
233
  this.pendingChunks = [];
252
234
  }
253
235
  /** Disconnect immediately, release connection, no events. */
@@ -1,6 +1,5 @@
1
1
  import { SQLiteCloudRowset } from './rowset';
2
2
  import { SQLiteCloudCommand, type SQLCloudRowsetMetadata, type SQLiteCloudDataTypes } from './types';
3
- import { Buffer } from 'buffer';
4
3
  export declare const CMD_STRING = "+";
5
4
  export declare const CMD_ZEROSTRING = "!";
6
5
  export declare const CMD_ERROR = "-";
@@ -17,8 +17,11 @@ exports.popData = popData;
17
17
  exports.formatCommand = formatCommand;
18
18
  const rowset_1 = require("./rowset");
19
19
  const types_1 = require("./types");
20
+ const safe_imports_1 = require("./safe-imports");
20
21
  // explicitly importing buffer library to allow cross-platform support by replacing it
21
- const buffer_1 = require("buffer");
22
+ // In React Native: Metro resolves 'buffer' to '@craftzdog/react-native-buffer' via package.json react-native field
23
+ // In Web/Node: Uses standard buffer package
24
+ const Buffer = (0, safe_imports_1.getSafeBuffer)();
22
25
  // https://www.npmjs.com/package/lz4js
23
26
  const lz4 = require('lz4js');
24
27
  // The server communicates with clients via commands defined in
@@ -70,12 +73,12 @@ function decompressBuffer(buffer) {
70
73
  commandBuffer = commandBuffer.subarray(commandBuffer.indexOf(' ') + 1);
71
74
  // extract compressed dataType
72
75
  const dataType = commandBuffer.subarray(0, 1).toString('utf8');
73
- let decompressedBuffer = buffer_1.Buffer.alloc(decompressedSize);
76
+ let decompressedBuffer = Buffer.alloc(decompressedSize);
74
77
  const compressedBuffer = commandBuffer.subarray(commandBuffer.length - compressedSize);
75
78
  // lz4js library is javascript and doesn't have types so we silence the type check
76
79
  const decompressionResult = lz4.decompressBlock(compressedBuffer, decompressedBuffer, 0, compressedSize, 0);
77
80
  // the entire command is composed of the header (which is not compressed) + the decompressed block
78
- decompressedBuffer = buffer_1.Buffer.concat([commandBuffer.subarray(0, commandBuffer.length - compressedSize), decompressedBuffer]);
81
+ decompressedBuffer = Buffer.concat([commandBuffer.subarray(0, commandBuffer.length - compressedSize), decompressedBuffer]);
79
82
  if (decompressionResult <= 0 || decompressionResult !== decompressedSize) {
80
83
  throw new Error(`lz4 decompression error at offset ${decompressionResult}`);
81
84
  }
@@ -199,7 +202,7 @@ function bufferEndsWith(buffer, suffix) {
199
202
  * @see https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md#scsp-rowset-chunk
200
203
  */
201
204
  function parseRowsetChunks(buffers) {
202
- let buffer = buffer_1.Buffer.concat(buffers);
205
+ let buffer = Buffer.concat(buffers);
203
206
  if (!bufferStartsWith(buffer, exports.CMD_ROWSET_CHUNK) || !bufferEndsWith(buffer, exports.ROWSET_CHUNKS_END)) {
204
207
  throw new Error('SQLiteCloudConnection.parseRowsetChunks - invalid chunks buffer');
205
208
  }
@@ -251,7 +254,7 @@ function popData(buffer) {
251
254
  return { data, fwdBuffer };
252
255
  }
253
256
  // first character is the data type
254
- console.assert(buffer && buffer instanceof buffer_1.Buffer);
257
+ console.assert(buffer && buffer instanceof Buffer);
255
258
  let dataType = buffer.subarray(0, 1).toString('utf8');
256
259
  if (dataType == exports.CMD_COMPRESSED)
257
260
  throw new Error('Compressed data should be decompressed before parsing');
@@ -324,15 +327,15 @@ function formatCommand(command) {
324
327
  }
325
328
  function serializeCommand(data, zeroString = false) {
326
329
  const n = data.length;
327
- let serializedData = buffer_1.Buffer.from(`${n} `);
330
+ let serializedData = Buffer.from(`${n} `);
328
331
  for (let i = 0; i < n; i++) {
329
332
  // the first string is the sql and it must be zero-terminated
330
333
  const zs = i == 0 || zeroString;
331
- serializedData = buffer_1.Buffer.concat([serializedData, serializeData(data[i], zs)]);
334
+ serializedData = Buffer.concat([serializedData, serializeData(data[i], zs)]);
332
335
  }
333
336
  const bytesTotal = serializedData.byteLength;
334
- const header = buffer_1.Buffer.from(`${exports.CMD_ARRAY}${bytesTotal} `);
335
- return buffer_1.Buffer.concat([header, serializedData]);
337
+ const header = Buffer.from(`${exports.CMD_ARRAY}${bytesTotal} `);
338
+ return Buffer.concat([header, serializedData]);
336
339
  }
337
340
  function serializeData(data, zeroString = false) {
338
341
  if (typeof data === 'string') {
@@ -341,26 +344,26 @@ function serializeData(data, zeroString = false) {
341
344
  cmd = exports.CMD_ZEROSTRING;
342
345
  data += '\0';
343
346
  }
344
- const header = `${cmd}${buffer_1.Buffer.byteLength(data, 'utf-8')} `;
345
- return buffer_1.Buffer.from(header + data);
347
+ const header = `${cmd}${Buffer.byteLength(data, 'utf-8')} `;
348
+ return Buffer.from(header + data);
346
349
  }
347
350
  if (typeof data === 'number') {
348
351
  if (Number.isInteger(data)) {
349
- return buffer_1.Buffer.from(`${exports.CMD_INT}${data} `);
352
+ return Buffer.from(`${exports.CMD_INT}${data} `);
350
353
  }
351
354
  else {
352
- return buffer_1.Buffer.from(`${exports.CMD_FLOAT}${data} `);
355
+ return Buffer.from(`${exports.CMD_FLOAT}${data} `);
353
356
  }
354
357
  }
355
358
  if (typeof data === 'bigint') {
356
- return buffer_1.Buffer.from(`${exports.CMD_INT}${data} `);
359
+ return Buffer.from(`${exports.CMD_INT}${data} `);
357
360
  }
358
- if (buffer_1.Buffer.isBuffer(data)) {
361
+ if (Buffer.isBuffer(data)) {
359
362
  const header = `${exports.CMD_BLOB}${data.byteLength} `;
360
- return buffer_1.Buffer.concat([buffer_1.Buffer.from(header), data]);
363
+ return Buffer.concat([Buffer.from(header), data]);
361
364
  }
362
365
  if (data === null || data === undefined) {
363
- return buffer_1.Buffer.from(`${exports.CMD_NULL} `);
366
+ return Buffer.from(`${exports.CMD_NULL} `);
364
367
  }
365
368
  if (Array.isArray(data)) {
366
369
  return serializeCommand(data, zeroString);
@@ -0,0 +1,31 @@
1
+ /**
2
+ * safe-imports.ts - Safe imports for optional React Native dependencies
3
+ *
4
+ * This module provides safe imports for dependencies that are optional peer dependencies.
5
+ * When these dependencies are not installed (e.g., using the package in a web/Next.js context),
6
+ * the imports will still work. However, in React Native contexts where these dependencies are
7
+ * required but not installed, clear error messages will be thrown.
8
+ */
9
+ /**
10
+ * Detects if we're running in React Native environment
11
+ */
12
+ export declare function isReactNative(): boolean;
13
+ /**
14
+ * Safely imports the URL class from whatwg-url or react-native-url-polyfill
15
+ * In React Native: Uses react-native-url-polyfill (via react-native field mapping)
16
+ * In Web/Node: Uses whatwg-url
17
+ */
18
+ export declare function getSafeURL(): typeof import('whatwg-url').URL;
19
+ /**
20
+ * Safely imports the Buffer class from buffer or @craftzdog/react-native-buffer
21
+ * In React Native: Uses @craftzdog/react-native-buffer (via react-native field mapping)
22
+ * In Web/Node: Uses buffer package
23
+ */
24
+ export declare function getSafeBuffer(): typeof import('buffer').Buffer;
25
+ /**
26
+ * Safely imports the tls module or react-native-tcp-socket
27
+ * In React Native: Uses react-native-tcp-socket (via react-native field mapping)
28
+ * In Node: Uses native tls module
29
+ * In Browser: Will return null (browser field sets tls to false)
30
+ */
31
+ export declare function getSafeTLS(): typeof import('tls') | null;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * safe-imports.ts - Safe imports for optional React Native dependencies
4
+ *
5
+ * This module provides safe imports for dependencies that are optional peer dependencies.
6
+ * When these dependencies are not installed (e.g., using the package in a web/Next.js context),
7
+ * the imports will still work. However, in React Native contexts where these dependencies are
8
+ * required but not installed, clear error messages will be thrown.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.isReactNative = isReactNative;
12
+ exports.getSafeURL = getSafeURL;
13
+ exports.getSafeBuffer = getSafeBuffer;
14
+ exports.getSafeTLS = getSafeTLS;
15
+ const types_1 = require("./types");
16
+ /**
17
+ * Detects if we're running in React Native environment
18
+ */
19
+ function isReactNative() {
20
+ return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
21
+ }
22
+ /**
23
+ * Safely imports the URL class from whatwg-url or react-native-url-polyfill
24
+ * In React Native: Uses react-native-url-polyfill (via react-native field mapping)
25
+ * In Web/Node: Uses whatwg-url
26
+ */
27
+ function getSafeURL() {
28
+ try {
29
+ // In React Native, Metro bundler will resolve this to react-native-url-polyfill
30
+ // In Web/Node, this will resolve to whatwg-url
31
+ const { URL } = require('whatwg-url');
32
+ return URL;
33
+ }
34
+ catch (error) {
35
+ if (isReactNative()) {
36
+ throw new types_1.SQLiteCloudError('Missing required React Native dependency: react-native-url-polyfill. ' +
37
+ 'Please install it using: npm install react-native-url-polyfill', { errorCode: 'ERR_MISSING_DEPENDENCY', cause: error });
38
+ }
39
+ throw new types_1.SQLiteCloudError('Failed to load URL parser. Please ensure whatwg-url is installed.', { errorCode: 'ERR_MISSING_DEPENDENCY', cause: error });
40
+ }
41
+ }
42
+ /**
43
+ * Safely imports the Buffer class from buffer or @craftzdog/react-native-buffer
44
+ * In React Native: Uses @craftzdog/react-native-buffer (via react-native field mapping)
45
+ * In Web/Node: Uses buffer package
46
+ */
47
+ function getSafeBuffer() {
48
+ try {
49
+ // In React Native, Metro bundler will resolve this to @craftzdog/react-native-buffer
50
+ // In Web/Node, this will resolve to buffer package
51
+ const { Buffer } = require('buffer');
52
+ return Buffer;
53
+ }
54
+ catch (error) {
55
+ if (isReactNative()) {
56
+ throw new types_1.SQLiteCloudError('Missing required React Native dependency: @craftzdog/react-native-buffer. ' +
57
+ 'Please install it using: npm install @craftzdog/react-native-buffer', { errorCode: 'ERR_MISSING_DEPENDENCY', cause: error });
58
+ }
59
+ throw new types_1.SQLiteCloudError('Failed to load Buffer library. Please ensure buffer package is installed.', { errorCode: 'ERR_MISSING_DEPENDENCY', cause: error });
60
+ }
61
+ }
62
+ /**
63
+ * Safely imports the tls module or react-native-tcp-socket
64
+ * In React Native: Uses react-native-tcp-socket (via react-native field mapping)
65
+ * In Node: Uses native tls module
66
+ * In Browser: Will return null (browser field sets tls to false)
67
+ */
68
+ function getSafeTLS() {
69
+ try {
70
+ // In React Native, Metro bundler will resolve this to react-native-tcp-socket
71
+ // In Node, this will resolve to native tls module
72
+ // In Browser, the browser field in package.json sets tls to false
73
+ const tls = require('tls');
74
+ if (tls === false || !tls) {
75
+ return null;
76
+ }
77
+ return tls;
78
+ }
79
+ catch (error) {
80
+ if (isReactNative()) {
81
+ throw new types_1.SQLiteCloudError('Missing required React Native dependency: react-native-tcp-socket. ' +
82
+ 'Please install it using: npm install react-native-tcp-socket', { errorCode: 'ERR_MISSING_DEPENDENCY', cause: error });
83
+ }
84
+ // In browser context, tls is not available (WebSocket should be used instead)
85
+ return null;
86
+ }
87
+ }
@@ -15,8 +15,11 @@ exports.parseconnectionstring = parseconnectionstring;
15
15
  exports.parseBoolean = parseBoolean;
16
16
  exports.parseBooleanToZeroOne = parseBooleanToZeroOne;
17
17
  const types_1 = require("./types");
18
+ const safe_imports_1 = require("./safe-imports");
18
19
  // explicitly importing these libraries to allow cross-platform support by replacing them
19
- const whatwg_url_1 = require("whatwg-url");
20
+ // In React Native: Metro resolves 'whatwg-url' to 'react-native-url-polyfill' via package.json react-native field
21
+ // In Web/Node: Uses standard whatwg-url package
22
+ const URL = (0, safe_imports_1.getSafeURL)();
20
23
  //
21
24
  // determining running environment, thanks to browser-or-node
22
25
  // https://www.npmjs.com/package/browser-or-node
@@ -193,7 +196,7 @@ function parseconnectionstring(connectionstring) {
193
196
  // the sqlitecloud: protocol is not recognized by the URL constructor in browsers
194
197
  // so we need to replace it with https: to make it work
195
198
  const knownProtocolUrl = connectionstring.replace('sqlitecloud:', 'https:');
196
- const url = new whatwg_url_1.URL(knownProtocolUrl);
199
+ const url = new URL(knownProtocolUrl);
197
200
  // all lowecase options
198
201
  const options = {};
199
202
  url.searchParams.forEach((value, key) => {