@benjosivo/mysql 1.0.3 → 1.2.2

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
@@ -4,46 +4,10 @@ Shared MySQL client (pooling, automatic retry on deadlock/lock-timeout, transact
4
4
 
5
5
  ## Install
6
6
 
7
- This package is published to **GitHub Packages**, not the public npm registry, so every machine needs a one-time setup before `npm install` will work — even though the repo and package are public. GitHub Packages never allows anonymous installs; a valid GitHub token is always required.
8
-
9
- ### One-time setup (per machine)
10
-
11
- 1. **Create a GitHub Personal Access Token.**
12
- GitHub → click your avatar → **Settings** → **Developer settings** → **Personal access tokens** → **Tokens (classic)** → **Generate new token (classic)**.
13
- Scope needed: **`read:packages`**. Copy the token — GitHub only shows it once.
14
-
15
- 2. **Add two lines to your global npm config.**
16
- Find the file path:
17
- ```
18
- npm config get globalconfig
19
- ```
20
- It's typically `C:\Users\<you>\AppData\Roaming\npm\etc\npmrc` on Windows. Open that file in a text editor and add:
21
- ```
22
- @benjosivo:registry=https://npm.pkg.github.com
23
- //npm.pkg.github.com/:_authToken=YOUR_TOKEN_HERE
24
- ```
25
- Editing the file directly is more reliable than `npm config set` — on some npm versions, `npm config set @benjosivo:registry=... --global` fails with a cryptic `` `` is not a valid npm option `` error. If you'd rather use the CLI, use the space-separated form instead of `=`:
26
- ```
27
- npm config set @benjosivo:registry https://npm.pkg.github.com --global
28
- ```
29
-
30
- 3. **Verify both lines took effect:**
31
- ```
32
- npm config list
33
- ```
34
- You should see both `@benjosivo:registry = "https://npm.pkg.github.com"` and `//npm.pkg.github.com/:_authToken = (protected)` in the output.
35
-
36
- ### Install
37
-
38
7
  ```
39
8
  npm install @benjosivo/mysql
40
9
  ```
41
10
 
42
- ### Troubleshooting
43
-
44
- - **`404 Not Found - GET https://registry.npmjs.org/@benjosivo%2fmysql`** — npm is checking the default npm registry instead of GitHub Packages. This means the `@benjosivo:registry` line from step 2 above isn't set (check with `npm config get @benjosivo:registry`). Add it and retry.
45
- - **401/403 or `ENEEDAUTH`** — the auth token is missing, expired, or lacks `read:packages` scope. Regenerate a token and re-add it.
46
-
47
11
  ## Usage
48
12
 
49
13
  ```ts
@@ -87,6 +51,34 @@ executeMySQLQuery(query, values?, returnFieldTypes?, connKey?)
87
51
 
88
52
  Returns the rows directly on success. On failure it returns `{ error, values, connKey }` instead of throwing (matches `mysql2`'s row-result shape so existing call sites don't need try/catch).
89
53
 
54
+ ### Statements prepared statements can't run
55
+
56
+ `executeMySQLQuery` uses `execute()` (MySQL's prepared-statement protocol), and MySQL rejects a
57
+ number of statements there with *"This command is not supported in the prepared statement protocol
58
+ yet"* — `SET GLOBAL ...`, `USE ...`, `LOCK TABLES`, several `SHOW` variants, and so on. For those,
59
+ use `runMySQLQuery`, which goes through `query()` (text protocol) instead:
60
+
61
+ ```ts
62
+ import { runMySQLQuery } from '@benjosivo/mysql';
63
+
64
+ await runMySQLQuery("SET GLOBAL general_log = 'OFF'");
65
+
66
+ // placeholders still work — mysql2 escapes and interpolates them client-side
67
+ await runMySQLQuery('SET GLOBAL general_log = ?', ['OFF']);
68
+
69
+ // optionally run inside an existing transaction
70
+ await runMySQLQuery('SELECT * FROM users WHERE id = ?', [userId], connKey);
71
+ ```
72
+
73
+ ```ts
74
+ runMySQLQuery(query, values?, connKey?)
75
+ ```
76
+
77
+ Same result shape as `executeMySQLQuery`: rows on success, `{ error, values, connKey }` on failure.
78
+ It's deliberately simple — no deadlock/lock-timeout retry — so prefer `executeMySQLQuery` for
79
+ regular application queries and keep this one for statements the prepared-statement protocol
80
+ refuses.
81
+
90
82
  ### Transactions
91
83
 
92
84
  ```ts
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import mysql from 'mysql2/promise';
1
2
  export interface MySQLClientConfig {
2
3
  host: string;
3
4
  user: string;
@@ -24,6 +25,27 @@ export declare function executeMySQLQuery2(opt: {
24
25
  returnFieldTypes?: boolean;
25
26
  returnListTables?: boolean | string;
26
27
  }): Promise<any>;
28
+ /**
29
+ * Runs a statement through mysql2's `query()` (text protocol) instead of `execute()`
30
+ * (prepared-statement protocol).
31
+ *
32
+ * MySQL refuses a number of statements in the prepared-statement protocol
33
+ * ("This command is not supported in the prepared statement protocol yet") —
34
+ * `SET GLOBAL ...`, `USE ...`, `LOCK TABLES`, several `SHOW` variants, etc.
35
+ * Use this for those; keep using `executeMySQLQuery` for everything else, since
36
+ * that one adds deadlock/lock-timeout retries and prepared statements.
37
+ *
38
+ * Values are escaped and interpolated client-side by mysql2 (`?` placeholders),
39
+ * so parameters are still safe to pass.
40
+ *
41
+ * Returns the rows on success, or `{ error, values, connKey }` on failure —
42
+ * same shape as `executeMySQLQuery`.
43
+ */
44
+ export declare function runMySQLQuery(query: string, values?: any[], connKey?: string): Promise<mysql.RowDataPacket[][] | mysql.OkPacket[] | mysql.ResultSetHeader[] | mysql.RowDataPacket[] | mysql.OkPacket | mysql.ResultSetHeader | {
45
+ error: any;
46
+ values: any[];
47
+ connKey: string | null;
48
+ } | [mysql.RowDataPacket[], mysql.ResultSetHeader]>;
27
49
  export declare function connectionCommit(keyConn: string): Promise<{
28
50
  error?: unknown;
29
51
  }>;
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ exports.loopKillOpenTRX = loopKillOpenTRX;
42
42
  exports.stopLoopKillOpenTRX = stopLoopKillOpenTRX;
43
43
  exports.executeMySQLQuery = executeMySQLQuery;
44
44
  exports.executeMySQLQuery2 = executeMySQLQuery2;
45
+ exports.runMySQLQuery = runMySQLQuery;
45
46
  exports.connectionCommit = connectionCommit;
46
47
  exports.connectionRollback = connectionRollback;
47
48
  const crypto_1 = require("crypto");
@@ -369,6 +370,49 @@ async function executeMySQLQuery2(opt) {
369
370
  return { error: error?.message ?? error, values, connKey: connKey ?? null };
370
371
  }
371
372
  }
373
+ /**
374
+ * Runs a statement through mysql2's `query()` (text protocol) instead of `execute()`
375
+ * (prepared-statement protocol).
376
+ *
377
+ * MySQL refuses a number of statements in the prepared-statement protocol
378
+ * ("This command is not supported in the prepared statement protocol yet") —
379
+ * `SET GLOBAL ...`, `USE ...`, `LOCK TABLES`, several `SHOW` variants, etc.
380
+ * Use this for those; keep using `executeMySQLQuery` for everything else, since
381
+ * that one adds deadlock/lock-timeout retries and prepared statements.
382
+ *
383
+ * Values are escaped and interpolated client-side by mysql2 (`?` placeholders),
384
+ * so parameters are still safe to pass.
385
+ *
386
+ * Returns the rows on success, or `{ error, values, connKey }` on failure —
387
+ * same shape as `executeMySQLQuery`.
388
+ */
389
+ async function runMySQLQuery(query, values = [], connKey) {
390
+ requireConfig();
391
+ let conn;
392
+ try {
393
+ if (connKey) {
394
+ const tr = listTransaction.get(connKey);
395
+ if (!tr) {
396
+ const msg = `Transaction key not found: ${connKey}`;
397
+ handleError(msg, 'MySQL: runMySQLQuery');
398
+ return { error: msg, values, connKey };
399
+ }
400
+ tr.lastUpdate = Date.now();
401
+ conn = tr.conn;
402
+ }
403
+ else if (lastConnectionCheck + 5 * 60000 <= Date.now()) {
404
+ await ensurePool();
405
+ }
406
+ const [rows] = await (conn ?? requirePool()).query(query, values);
407
+ return rows;
408
+ }
409
+ catch (error) {
410
+ const errorMsg = String(error?.message ?? error);
411
+ const queryStr = query.length > 200 ? `${query.substring(0, 200)}...` : query;
412
+ handleError(error, `MySQL${error?.code ? ` [${error.code}]` : ''}${connKey ? ' (using connection)' : ''}\n${errorMsg}\n\nparams: ${values}\n\nquery: ${queryStr}`);
413
+ return { error: error?.message ?? error, values, connKey: connKey ?? null };
414
+ }
415
+ }
372
416
  async function createTransaction() {
373
417
  const keyConn = (0, crypto_1.randomUUID)();
374
418
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benjosivo/mysql",
3
- "version": "1.0.3",
3
+ "version": "1.2.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -18,5 +18,9 @@
18
18
  "@types/node": "^26.1.2",
19
19
  "typescript": "^7.0.2"
20
20
  },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/benjosivo/mysql.git"
24
+ },
21
25
  "license": "MIT"
22
26
  }