Skip to content

Commit 03b5fa5

Browse files
committed
Relax MySQL pool constructor types
Accept the structural MySQL pool shape in MysqlKvStore and MysqlMessageQueue instead of tying the public constructors to a specific mysql2 Pool type identity. This fixes TypeScript assignment failures when applications resolve mysql2 through multiple type sources or different package versions, including the docs twoslash build path, without changing runtime behavior. Update CHANGES.md to describe the fix as a user-visible TypeScript compatibility bug fix for @fedify/mysql. Assisted-by: Codex:gpt-5.4
1 parent 195ad9b commit 03b5fa5

3 files changed

Lines changed: 56 additions & 11 deletions

File tree

CHANGES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ Version 2.1.9
88

99
To be released.
1010

11+
### @fedify/mysql
12+
13+
- Fixed a TypeScript type mismatch in `MysqlKvStore` and
14+
`MysqlMessageQueue` that could reject valid `mysql2` pools when an
15+
application resolved `mysql2` through multiple type sources or different
16+
package versions. The constructors now accept the structural pool shape
17+
they actually use, so mixed Deno/npm setups and monorepos no longer need
18+
casts or `@ts-expect-error` workarounds.
19+
1120

1221
Version 2.1.8
1322
-------------

packages/mysql/src/kv.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,28 @@ import type {
66
} from "@fedify/fedify";
77
import { isEqual } from "es-toolkit";
88
import { getLogger } from "@logtape/logtape";
9-
import type { Pool, PoolConnection, RowDataPacket } from "mysql2/promise";
9+
import type { RowDataPacket } from "mysql2/promise";
1010

1111
const logger = getLogger(["fedify", "mysql", "kv"]);
1212

13+
interface MysqlQueryable {
14+
query<TRows = unknown>(
15+
sql: string,
16+
values?: unknown,
17+
): Promise<[TRows, unknown]>;
18+
}
19+
20+
interface MysqlPoolConnection extends MysqlQueryable {
21+
beginTransaction(): Promise<void>;
22+
commit(): Promise<void>;
23+
rollback(): Promise<void>;
24+
release(): void;
25+
}
26+
27+
interface MysqlPool extends MysqlQueryable {
28+
getConnection(): Promise<MysqlPoolConnection>;
29+
}
30+
1331
/**
1432
* Options for the MySQL key-value store.
1533
*
@@ -61,7 +79,7 @@ export interface MysqlKvStoreOptions {
6179
* @since 2.1.0
6280
*/
6381
export class MysqlKvStore implements KvStore {
64-
readonly #pool: Pool;
82+
readonly #pool: MysqlPool;
6583
readonly #tableName: string;
6684
readonly #expireCleanupRate: number;
6785
#initialized: boolean;
@@ -72,7 +90,7 @@ export class MysqlKvStore implements KvStore {
7290
* @param options The options for the key-value store.
7391
* @since 2.1.0
7492
*/
75-
constructor(pool: Pool, options: MysqlKvStoreOptions = {}) {
93+
constructor(pool: MysqlPool, options: MysqlKvStoreOptions = {}) {
7694
this.#pool = pool;
7795
const tableName = options.tableName ?? "fedify_kv";
7896
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
@@ -198,7 +216,7 @@ export class MysqlKvStore implements KvStore {
198216
): Promise<boolean> {
199217
await this.initialize();
200218
const serializedKey = JSON.stringify([...key]);
201-
let conn: PoolConnection | undefined;
219+
let conn: MysqlPoolConnection | undefined;
202220
try {
203221
conn = await this.#pool.getConnection();
204222
await conn.beginTransaction();

packages/mysql/src/mq.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type {
44
MessageQueueListenOptions,
55
} from "@fedify/fedify";
66
import { getLogger } from "@logtape/logtape";
7-
import type { Pool, PoolConnection, RowDataPacket } from "mysql2/promise";
7+
import type { RowDataPacket } from "mysql2/promise";
88

99
const logger = getLogger(["fedify", "mysql", "mq"]);
1010
const INITIALIZE_MAX_ATTEMPTS = 5;
@@ -14,6 +14,24 @@ const INITIALIZE_BACKOFF_MS = 10;
1414
// the cost of a slightly larger result set from the GROUP BY query.
1515
const ORDERING_KEY_CANDIDATE_LIMIT = 10;
1616

17+
interface MysqlQueryable {
18+
query<TRows = unknown>(
19+
sql: string,
20+
values?: unknown,
21+
): Promise<[TRows, unknown]>;
22+
}
23+
24+
interface MysqlPoolConnection extends MysqlQueryable {
25+
beginTransaction(): Promise<void>;
26+
commit(): Promise<void>;
27+
rollback(): Promise<void>;
28+
release(): void;
29+
}
30+
31+
interface MysqlPool extends MysqlQueryable {
32+
getConnection(): Promise<MysqlPoolConnection>;
33+
}
34+
1735
function sleep(ms: number): Promise<void> {
1836
return new Promise((resolve) => setTimeout(resolve, ms));
1937
}
@@ -144,7 +162,7 @@ export class MysqlMessageQueue implements MessageQueue {
144162
*/
145163
readonly nativeRetrial = false;
146164

147-
readonly #pool: Pool;
165+
readonly #pool: MysqlPool;
148166
readonly #tableName: string;
149167
readonly #pollIntervalMs: number;
150168
readonly #handlerTimeoutMs: number;
@@ -157,7 +175,7 @@ export class MysqlMessageQueue implements MessageQueue {
157175
* @param options Options for the message queue.
158176
* @since 2.1.0
159177
*/
160-
constructor(pool: Pool, options: MysqlMessageQueueOptions = {}) {
178+
constructor(pool: MysqlPool, options: MysqlMessageQueueOptions = {}) {
161179
this.#pool = pool;
162180
const tableName = options.tableName ?? "fedify_mq";
163181
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
@@ -264,7 +282,7 @@ export class MysqlMessageQueue implements MessageQueue {
264282
delayMs * 1000 + index,
265283
orderingKey,
266284
]);
267-
let conn: PoolConnection | undefined;
285+
let conn: MysqlPoolConnection | undefined;
268286
try {
269287
conn = await this.#pool.getConnection();
270288
await conn.beginTransaction();
@@ -333,7 +351,7 @@ export class MysqlMessageQueue implements MessageQueue {
333351
if (signal?.aborted) break;
334352
const lockName = getMysqlLockName(this.#tableName, orderingKey);
335353

336-
let conn: PoolConnection | undefined;
354+
let conn: MysqlPoolConnection | undefined;
337355
try {
338356
conn = await this.#pool.getConnection();
339357
const [lockResult] = await conn.query<RowDataPacket[]>(
@@ -416,7 +434,7 @@ export class MysqlMessageQueue implements MessageQueue {
416434
* Returns `undefined` when no such message is available.
417435
*/
418436
async #dequeueWithoutOrderingKey(): Promise<unknown> {
419-
let conn: PoolConnection | undefined;
437+
let conn: MysqlPoolConnection | undefined;
420438
try {
421439
conn = await this.#pool.getConnection();
422440
await conn.beginTransaction();
@@ -474,7 +492,7 @@ export class MysqlMessageQueue implements MessageQueue {
474492
* Returns `undefined` when no ready message exists for the ordering key.
475493
*/
476494
async #dequeueOrderedMessage(
477-
conn: PoolConnection,
495+
conn: MysqlPoolConnection,
478496
orderingKey: string,
479497
): Promise<unknown> {
480498
await conn.beginTransaction();

0 commit comments

Comments
 (0)