Skip to content

Commit 61bb53c

Browse files
committed
docs: bundler target and skipLibCheck troubleshooting notes
1 parent 45972cc commit 61bb53c

5 files changed

Lines changed: 160 additions & 0 deletions

File tree

.changeset/lazy-peers-typings.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'zaileys': patch
3+
---
4+
5+
Remove `pg`/`redis` type imports from published typings — consumers without the optional peer deps no longer fail typecheck (TS2307). Declarations are now emitted by TypeScript 7 directly instead of bundled, and the packaging guard fails the build if any optional peer ever leaks into `dist` typings again.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ Zaileys ships dual ESM/CJS entry points with type declarations for both module s
235235

236236
Package managers: **npm**, **pnpm**, **yarn**, and **bun** are all supported.
237237

238+
### Bundling & typecheck troubleshooting
239+
240+
- **`bun build` fails with "Browser build cannot import Node.js builtin"** — Zaileys (and baileys underneath) is a Node-only library; bun's bundler defaults to a browser target. Pass the target explicitly: `bun build index.ts --target bun` (or `--target node`).
241+
- **`tsc` reports errors inside `node_modules` (`ws`, `thread-stream`, `whatsapp-rust-bridge`)** — upstream declaration issues, not yours. Set `"skipLibCheck": true` in your `tsconfig.json`.
242+
238243
## Documentation
239244

240245
- 🌐 [**zeative.github.io/zaileys**](https://zeative.github.io/zaileys/) — full documentation site: guides, API reference, recipes

SPEC.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# SPEC — Fix consumer build/typecheck breakage (optional peer deps leak into dist typings)
2+
3+
## 1. Objective
4+
5+
Consumers of `zaileys` who do NOT install optional peers (`pg`, `redis`) get hard TypeScript errors:
6+
7+
```
8+
node_modules/zaileys/dist/index.d.ts:4:22 - TS2307: Cannot find module 'pg'
9+
node_modules/zaileys/dist/index.d.ts:5:33 - TS2307: Cannot find module 'redis'
10+
```
11+
12+
Cause: `src/auth/adapters/{postgres,redis}.ts` and `src/store/adapters/{postgres,redis}.ts` use `import type { Pool, PoolClient } from 'pg'` / `import type { RedisClientType } from 'redis'`. tsup's dts rollup hoists these into top-level imports in `dist/index.d.ts`, so the published typings *require* optional packages to resolve.
13+
14+
Fix: remove all `pg`/`redis` type imports from source. Replace with local minimal structural interfaces (only the members zaileys actually calls). Result: `dist/index.d.ts` has zero references to optional peer packages; consumers without them typecheck clean.
15+
16+
Non-goals (upstream / consumer-side, documented only):
17+
18+
- `bun build index.ts` browser-target errors (`async_hooks`, `stream/promises`, `child_process` from baileys/detect-libc): zaileys is a Node-only library; consumer must build with `--target node` or `--target bun`. Add a README/docs troubleshooting note.
19+
- Type errors inside `baileys` (`ws` missing @types), `thread-stream`, `whatsapp-rust-bridge`: upstream packages; consumer mitigates with `skipLibCheck: true`. Document in same troubleshooting note.
20+
21+
Target users: any TS consumer of zaileys using sqlite (default) or convex auth/store, without pg/redis installed.
22+
23+
## 2. Acceptance criteria
24+
25+
1. `grep "from 'pg'\|from 'redis'" dist/index.d.ts dist/index.d.cts` → no matches after build.
26+
2. Structural types keep real-client compatibility: passing an actual `pg.Pool` / redis client to the adapters still typechecks (structural subtyping — verify with existing devDeps `pg`/`redis` in a type test).
27+
3. Runtime behavior unchanged — adapters still dynamic-import the real packages; existing tests pass.
28+
4. Fresh consumer simulation: a scratch project with only `zaileys` installed (no pg/redis) runs `tsc --noEmit` over `import { Client } from 'zaileys'` with zero TS2307 from zaileys dist.
29+
5. Docs: troubleshooting section covering bun target + skipLibCheck for upstream lib errors.
30+
31+
## 3. Commands
32+
33+
```bash
34+
pnpm build # tsup → dist (esm+cjs+dts)
35+
pnpm typecheck # tsgo --noEmit
36+
pnpm test # vitest run
37+
pnpm size # size-limit
38+
```
39+
40+
Verification for this fix: `pnpm build && grep -c "'pg'\|'redis'" dist/index.d.ts` (expect 0) + scratch consumer tsc check.
41+
42+
## 4. Project structure (touched files)
43+
44+
```
45+
src/auth/adapters/postgres.ts # drop pg import → local PgPoolLike/PgClientLike types
46+
src/auth/adapters/redis.ts # drop redis import → local RedisClientLike type
47+
src/store/adapters/postgres.ts # same
48+
src/store/adapters/redis.ts # same
49+
src/types/… # (optional) shared minimal client types if adapters can share one def
50+
docs/… # troubleshooting note (bun target, skipLibCheck)
51+
.changeset/*.md # patch bump
52+
```
53+
54+
Prefer one shared definition (e.g. `src/shared/optional-clients.ts`) over 4 duplicated copies if both auth+store use identical shapes.
55+
56+
## 5. Code style
57+
58+
- Existing repo conventions: strict TS, no `any` (audit:any script), lean one-liner comments only for non-obvious intent.
59+
- Structural interfaces named `*Like` (e.g. `PgPoolLike`) to signal duck-typing; include only methods actually invoked (`query`, `connect`, `release`, redis `get/set/del/connect/quit/…` — derive from adapter usage, not from full upstream API).
60+
- Keep `import type`/dynamic `await import('pg')` pattern at runtime; cast dynamic import result to the Like types.
61+
62+
## 6. Testing strategy
63+
64+
- Existing vitest suite must pass unchanged (adapters covered by pg-mem / mocks).
65+
- Add one type-level regression test: assert real `pg.Pool` and `redis` client (from devDeps) are assignable to the Like types (compile-time `satisfies`/assignment in a `.test-d`-style file or plain test file).
66+
- Post-build assertion (script or CI step): grep dist d.ts for `'pg'`/`'redis'` — fail if found. Prevents regression when tsup/dts rollup changes.
67+
68+
## 7. Boundaries
69+
70+
- **Always**: keep pg/redis/better-sqlite3/convex optional at runtime AND type level; patch-level semver (no public API change — parameter types widen structurally).
71+
- **Ask first**: publishing to npm; changing peerDependencies; renaming exported types that consumers may reference (e.g. if `Pool` was re-exported).
72+
- **Never**: add pg/redis to `dependencies`; ship breaking API changes for this fix; touch baileys/upstream workarounds via patch-package.

tasks/plan.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Plan — decouple dist typings from optional peers (pg, redis)
2+
3+
Spec: ../SPEC.md
4+
5+
## Dependency graph
6+
7+
```
8+
T1 shared Like types (pg) ──▶ T2 migrate pg adapters (auth+store)
9+
T3 shared Like types (redis) ─▶ T4 migrate redis adapters (auth+store)
10+
T2 + T4 ──▶ CHECKPOINT A (build + dist grep + consumer sim)
11+
CHECKPOINT A ──▶ T5 regression guards (type test + post-build grep)
12+
T5 ──▶ T6 docs + changeset ──▶ CHECKPOINT B (final verify)
13+
```
14+
15+
pg and redis slices are independent — can land in either order. Each slice is vertical: types → both adapters → build → verify.
16+
17+
## Key facts (from code read)
18+
19+
- Leak source: exported option interfaces (`PostgresAuthStoreOptions.pool?: Pool`, `RedisAuthStoreOptions.client?: RedisClientType`, store equivalents) AND private class members typed `Pool`/`RedisClientType` — rollup-plugin-dts emits both into `dist/index.d.ts:4-5` as hard imports.
20+
- `type PgModule = typeof import('pg')` is un-exported and used only in impl → verify post-build it doesn't leak; if it does, cast dynamic import to a minimal ctor shape instead.
21+
- Every internal usage must be typed against Like interfaces (any reference to `pg`/`redis` types anywhere in an emitted declaration resolves the module).
22+
23+
### pg surface actually used
24+
`Pool`: `query(sql, params?) → {rows}` (generic row), `connect() → PoolClient`, `end()`; `PoolClient`: `query`, `release()`. Plus `new Pool({connectionString, max})` via dynamic import.
25+
26+
### redis surface actually used
27+
Client: `get set del(k|k[]) mGet hGet hSet hmGet hGetAll sAdd sRem sMembers sIsMember zAdd zRangeByScore scan multi connect quit isOpen`. Multi builder: `set del sAdd sRem hSet zAdd` (chainable, return this) + `exec()`. `scan(cursor, {MATCH, COUNT}) → {cursor, keys}`. `createClient({url})` via dynamic import.
28+
29+
Design: loose param types (e.g. `unknown[]` for query params), precise-enough returns for internal code. Real `pg.Pool` / redis client must remain structurally assignable (acceptance #2). Name them `PgPoolLike`, `PgPoolClientLike`, `RedisClientLike`, `RedisMultiLike` in one shared file `src/types/optional-clients.ts` (both auth+store import it).
30+
31+
---
32+
33+
## Tasks
34+
35+
### T1 — pg Like types
36+
Create `src/types/optional-clients.ts` with `PgQueryResultLike<R>`, `PgPoolClientLike`, `PgPoolLike`.
37+
- AC: `pnpm typecheck` passes with file compiled (temporarily imported or included).
38+
- Verify: tsgo --noEmit.
39+
40+
### T2 — migrate pg adapters (vertical slice)
41+
`src/auth/adapters/postgres.ts` + `src/store/adapters/postgres.ts`: drop `import type {...} from 'pg'`, type options/fields/locals with Like types; keep dynamic `import('pg')`, cast ctor result.
42+
- AC: `pnpm typecheck && pnpm test` green; `pnpm build && grep "'pg'" dist/index.d.ts` → no match; external-pool option still accepts real `pg.Pool` (devDep) without cast.
43+
- Verify: run commands above.
44+
45+
### T3 — redis Like types
46+
Add `RedisClientLike` + `RedisMultiLike` to same shared file (chainable multi, exec, scan shape).
47+
- AC: typecheck passes.
48+
49+
### T4 — migrate redis adapters (vertical slice)
50+
`src/auth/adapters/redis.ts` + `src/store/adapters/redis.ts`: same treatment; `createClient(...)` cast to `RedisClientLike`.
51+
- AC: typecheck + tests green; `grep "'redis'" dist/index.d.ts` → no match; real redis client (devDep) assignable to `client?:` option.
52+
53+
### CHECKPOINT A — consumer simulation
54+
Scratch dir (outside repo, use session scratchpad): `npm init -y && npm i <packed tgz via pnpm pack>` WITHOUT pg/redis, minimal `index.ts` importing `{ Client }` (+ types), `tsc --noEmit --skipLibCheck false`… realistic: `skipLibCheck: true` (upstream baileys/ws errors are out of scope) but zero errors pointing at `node_modules/zaileys/dist/*`.
55+
- Gate: no TS2307 'pg'/'redis' from zaileys dist. STOP and reassess if rollup still emits imports (fallback: post-process d.ts in tsup onSuccess).
56+
57+
### T5 — regression guards
58+
1. Type test (e.g. `tests/types/optional-clients.test-d.ts` or plain vitest file with compile-time assignments): real `pg.Pool`, real redis client assignable to Like types.
59+
2. Guard: extend tsup `onSuccess` (or `pnpm build` postscript) — fail build if `dist/index.d.ts|d.cts` matches `from '(pg|redis|better-sqlite3|convex)'`.
60+
- AC: guard demonstrably fails when a leak is reintroduced (test once by temporary revert), passes on clean build.
61+
62+
### T6 — docs + changeset
63+
- Docs troubleshooting: (1) bun bundling needs `--target node|bun` (zaileys Node-only, baileys uses node builtins); (2) upstream d.ts errors (`ws`, thread-stream, whatsapp-rust-bridge) → `skipLibCheck: true`.
64+
- Changeset: patch, "fix: remove pg/redis type imports from published typings; consumers without optional peers no longer fail typecheck".
65+
- AC: docs build ok; changeset lints.
66+
67+
### CHECKPOINT B — final
68+
`pnpm typecheck && pnpm test && pnpm build && pnpm size` all green; consumer sim re-run; review diff for API changes (must be none semantically).

tasks/todo.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Todo — optional peer typings fix
2+
3+
- [ ] T1: `src/types/optional-clients.ts` — PgPoolLike/PgPoolClientLike/PgQueryResultLike
4+
- [ ] T2: migrate auth+store postgres adapters; build; grep dist for 'pg' = 0
5+
- [ ] T3: add RedisClientLike/RedisMultiLike to shared file
6+
- [ ] T4: migrate auth+store redis adapters; build; grep dist for 'redis' = 0
7+
- [ ] CHECKPOINT A: pnpm pack → scratch consumer without pg/redis → tsc clean re zaileys dist
8+
- [ ] T5: type-assignability regression test + post-build leak guard (pg|redis|better-sqlite3|convex)
9+
- [ ] T6: docs troubleshooting (bun target, skipLibCheck) + patch changeset
10+
- [ ] CHECKPOINT B: typecheck + test + build + size green; re-run consumer sim

0 commit comments

Comments
 (0)