mysql-memory-server 1.3.0 → 1.4.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
@@ -11,7 +11,7 @@ Download with your package manager of choice. The package name is `mysql-memory-
11
11
  #### Requirements
12
12
 
13
13
  - Node.js 16.6.0 and newer
14
- - macOS 13+, Windows, or Linux (Only Ubuntu has been tested. Other Linux distributions may or may not work at this time.)
14
+ - macOS 13+, Windows, or Linux (This package is only tested on Ubuntu 20.04, 22.04, 24.04, and Fedora 40. Other Linux distributions may or may not work at this time.)
15
15
 
16
16
  Windows only requirements:
17
17
  - `Microsoft Visual C++ 2019 Redistributable Package` needs to be installed
@@ -143,6 +143,22 @@ Default: root
143
143
 
144
144
  Description: The username of the user that is used to login to the database.
145
145
 
146
+ - `port: number`
147
+
148
+ Required: No
149
+
150
+ Default: 0
151
+
152
+ Description: The port that the database will listen on. If set to 0, a randomly generated port is used.
153
+
154
+ - `xPort: number`
155
+
156
+ Required: No
157
+
158
+ Default: 0
159
+
160
+ Description: The port that the MySQL X Plugin will listen on. If set to 0, a randomly generated port is used.
161
+
146
162
  - `ignoreUnsupportedSystemVersion: boolean`
147
163
 
148
164
  Required: No
package/dist/src/index.js CHANGED
@@ -53,7 +53,9 @@ async function createDB(opts) {
53
53
  deleteDBAfterStopped: true,
54
54
  //mysqlmsn = MySQL Memory Server Node.js
55
55
  dbPath: (0, path_1.normalize)(`${os.tmpdir()}/mysqlmsn/dbs/${(0, crypto_1.randomUUID)().replace(/-/g, '')}`),
56
- ignoreUnsupportedSystemVersion: false
56
+ ignoreUnsupportedSystemVersion: false,
57
+ port: 0,
58
+ xPort: 0
57
59
  };
58
60
  const options = { ...defaultOptions, ...opts };
59
61
  const logger = new Logger_1.default(options.logLevel);
@@ -88,7 +90,7 @@ async function createDB(opts) {
88
90
  binaryFilepath = await (0, Downloader_1.downloadBinary)(binaryInfo, options, logger);
89
91
  }
90
92
  catch (error) {
91
- logger.error('Failed to download binary');
93
+ logger.error('Failed to download binary:', error);
92
94
  throw `Failed to download binary. The error was: "${error}"`;
93
95
  }
94
96
  logger.log('Running downloaded binary');
@@ -170,13 +170,15 @@ function downloadBinary(binaryInfo, options, logger) {
170
170
  const extractedPath = `${dirpath}/${version}`;
171
171
  await fsPromises.mkdir(extractedPath, { recursive: true });
172
172
  const binaryPath = (0, path_1.normalize)(`${extractedPath}/mysql/bin/mysqld${process.platform === 'win32' ? '.exe' : ''}`);
173
+ const archivePath = `${dirpath}/${version}.${fileExtension}`;
173
174
  const binaryExists = fs.existsSync(binaryPath);
174
175
  if (binaryExists) {
175
176
  return resolve(binaryPath);
176
177
  }
178
+ let lockedByUs = false;
177
179
  try {
178
180
  (0, proper_lockfile_1.lockSync)(extractedPath);
179
- const archivePath = `${dirpath}/${version}.${fileExtension}`;
181
+ lockedByUs = true;
180
182
  await downloadFromCDN(url, archivePath, logger);
181
183
  await extractBinary(url, archivePath, extractedPath);
182
184
  try {
@@ -188,12 +190,28 @@ function downloadBinary(binaryInfo, options, logger) {
188
190
  return resolve(binaryPath);
189
191
  }
190
192
  catch (e) {
191
- if (String(e) === 'Error: Lock file is already being held') {
193
+ if (String(e).includes('Lock file is already being held')) {
192
194
  logger.log('Waiting for lock for MySQL version', version);
193
195
  await (0, FileLock_1.waitForLock)(extractedPath, options);
194
196
  logger.log('Lock is gone for version', version);
195
197
  return resolve(binaryPath);
196
198
  }
199
+ if (lockedByUs) {
200
+ try {
201
+ await Promise.all([
202
+ fsPromises.rm(extractedPath, { force: true, recursive: true }),
203
+ fsPromises.rm(archivePath, { force: true, recursive: true })
204
+ ]);
205
+ }
206
+ finally {
207
+ try {
208
+ (0, proper_lockfile_1.unlockSync)(extractedPath, { realpath: false });
209
+ }
210
+ catch (e) {
211
+ logger.error('An error occurred while unlocking path:', e);
212
+ }
213
+ }
214
+ }
197
215
  return reject(e);
198
216
  }
199
217
  }
@@ -135,8 +135,8 @@ class Executor {
135
135
  do {
136
136
  await __classPrivateFieldGet(this, _Executor_instances, "m", _Executor_setupDataDirectories).call(this, options, binaryFilepath, datadir, true);
137
137
  this.logger.log('Setting up directories was successful');
138
- const port = (0, Port_1.GenerateRandomPort)();
139
- const mySQLXPort = (0, Port_1.GenerateRandomPort)();
138
+ const port = options.port || (0, Port_1.GenerateRandomPort)();
139
+ const mySQLXPort = options.xPort || (0, Port_1.GenerateRandomPort)();
140
140
  this.logger.log('Using port:', port, 'and MySQLX port:', mySQLXPort, 'on retry:', retries);
141
141
  try {
142
142
  this.logger.log('Starting MySQL process');
@@ -194,7 +194,7 @@ _Executor_instances = new WeakSet(), _Executor_execute = function _Executor_exec
194
194
  const errorLogFile = `${datadir}/errorlog.err`;
195
195
  return new Promise(async (resolve, reject) => {
196
196
  await fsPromises.rm(logFile, { force: true });
197
- const process = (0, child_process_1.spawn)(binaryFilepath, ['--no-defaults', `--port=${port}`, `--datadir=${datadir}`, `--mysqlx-port=${mySQLXPort}`, `--mysqlx-socket=${dbPath}/x.sock`, `--socket=${dbPath}/m.sock`, `--general-log-file=${logFile}`, '--general-log=1', `--init-file=${dbPath}/init.sql`, '--bind-address=127.0.0.1', '--innodb-doublewrite=OFF', '--mysqlx=FORCE', `--log-error=${errorLogFile}`], { signal: AbortSignal_1.default.signal, killSignal: 'SIGKILL' });
197
+ const process = (0, child_process_1.spawn)(binaryFilepath, ['--no-defaults', `--port=${port}`, `--datadir=${datadir}`, `--mysqlx-port=${mySQLXPort}`, `--mysqlx-socket=${dbPath}/x.sock`, `--socket=${dbPath}/m.sock`, `--general-log-file=${logFile}`, '--general-log=1', `--init-file=${dbPath}/init.sql`, '--bind-address=127.0.0.1', '--innodb-doublewrite=OFF', '--mysqlx=FORCE', `--log-error=${errorLogFile}`, `--user=${os.userInfo().username}`], { signal: AbortSignal_1.default.signal, killSignal: 'SIGKILL' });
198
198
  //resolveFunction is the function that will be called to resolve the promise that stops the database.
199
199
  //If resolveFunction is not undefined, the database has received a kill signal and data cleanup procedures should run.
200
200
  //Once ran, resolveFunction will be called.
@@ -12,6 +12,8 @@ export type ServerOptions = {
12
12
  deleteDBAfterStopped?: boolean;
13
13
  dbPath?: string;
14
14
  ignoreUnsupportedSystemVersion?: boolean;
15
+ port?: number;
16
+ xPort?: number;
15
17
  };
16
18
  export type InternalServerOptions = {
17
19
  version?: string;
@@ -25,6 +27,8 @@ export type InternalServerOptions = {
25
27
  deleteDBAfterStopped: boolean;
26
28
  dbPath: string;
27
29
  ignoreUnsupportedSystemVersion: boolean;
30
+ port: number;
31
+ xPort: number;
28
32
  };
29
33
  export type ExecutorOptions = {
30
34
  logLevel: LOG_LEVEL;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mysql-memory-server",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Spin up an ephemeral MySQL database from your JavaScript code",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",