Skip to content

feat: use esm only#951

Merged
SamTV12345 merged 9 commits into
mainfrom
feauture/sped-improvement
May 10, 2026
Merged

feat: use esm only#951
SamTV12345 merged 9 commits into
mainfrom
feauture/sped-improvement

Conversation

@SamTV12345
Copy link
Copy Markdown
Member

No description provided.

@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Modernize to ES modules with enhanced TypeScript type safety and async/await API

✨ Enhancement

Grey Divider

Walkthroughs

Description
• **Modernize codebase to ES modules**: Converted from CommonJS to ESM with proper module
  configuration in package.json, tsconfig.json, and rolldown.config.mjs
• **Remove callback-based API**: Eliminated deprecated callback support and callbackify utilities
  across all database methods in favor of pure async/await
• **Enhance TypeScript type safety**: Added comprehensive type definitions throughout the codebase,
  removed @ts-nocheck directives, and enforced type-only imports using verbatimModuleSyntax
• **Refactor all database drivers**: Updated 18 database driver files to use type-only imports for
  better ESM compatibility and cleaner output
• **Improve cache layer**: Modernized CacheAndBufferLayer.ts with proper generic typing, enhanced
  LRU cache implementation, and improved error handling
• **Define Logger interface**: Created new Logger type definition with standardized logging
  methods and level-checking functions
• **Reorganize dependencies**: Moved database drivers to devDependencies and updated version
  constraints for better flexibility
• **Update CI/CD**: Bumped pnpm version from 10 to 11 in GitHub Actions workflow
Diagram
flowchart LR
  CommonJS["CommonJS<br/>Callbacks<br/>Loose Types"]
  ESM["ES Modules<br/>Async/Await<br/>Strong Types"]
  Config["Config Updates<br/>package.json<br/>tsconfig.json<br/>rolldown.config.mjs"]
  Drivers["18 Database<br/>Drivers<br/>Type-only Imports"]
  Cache["Cache Layer<br/>Generics<br/>Type Safety"]
  Logger["Logger<br/>Interface<br/>Type Definitions"]
  
  CommonJS -- "Modernize" --> ESM
  ESM -- "Configure" --> Config
  ESM -- "Refactor" --> Drivers
  ESM -- "Enhance" --> Cache
  ESM -- "Define" --> Logger
Loading

Grey Divider

File Changes

1. lib/CacheAndBufferLayer.ts ✨ Enhancement +237/-322

TypeScript type safety and modernization of cache layer

• Removed @ts-nocheck directive and added comprehensive TypeScript type definitions for all
 classes and functions
• Converted class from CommonJS export to ES6 export class syntax with full type annotations
• Added new type definitions: BulkOp, CacheEntry, CacheSettings, InternalDB,
 LegacyWrappedDB, and Metrics
• Refactored SelfContainedPromise class with proper generic typing and improved done callback
 implementation
• Enhanced LRU cache class with TypeScript generics and proper method signatures
• Improved error handling and type safety throughout database operations

lib/CacheAndBufferLayer.ts


2. index.ts ✨ Enhancement +104/-222

Modernize API to async/await and remove callback support

• Removed 'use strict' directive and CommonJS callback-based API in favor of pure async/await
• Removed deprecated callback support and callbackify utilities for all database methods
• Added type exports for Metrics, CacheSettings, Logger, and Settings
• Converted Database class to use modern async methods with proper TypeScript typing
• Simplified method signatures by removing optional callback parameters
• Improved initDB() method with better type casting and error messages

index.ts


3. lib/AbstractDatabase.ts ✨ Enhancement +26/-29

Enhance AbstractDatabase with strict TypeScript typing

• Added Logger type import and improved type definitions for Settings
• Enhanced simpleGlobToRegExp function with proper formatting
• Improved constructor validation and method type checking
• Added return type annotations to all methods including createFindRegex() and doBulk()
• Removed unnecessary @ts-ignore comments with proper type handling

lib/AbstractDatabase.ts


View more (23)
4. databases/surrealdb_db.ts ✨ Enhancement +8/-6

Improve type imports and method signatures in SurrealDB driver

• Changed import from default to type import for Settings
• Changed import from default to type import for BulkObject
• Added type casting and eslint disable comments for clientOptions handling
• Updated doBulk() method return type to Promise<void> and removed unnecessary null return

databases/surrealdb_db.ts


5. lib/logging.ts ✨ Enhancement +29/-23

Define Logger interface and improve logging type safety

• Added new Logger type definition with all required logging methods and level-checking functions
• Updated ConsoleLogger class to implement the Logger interface
• Refactored normalizeLogger() function with improved type safety and proper return type
• Improved variable naming and type annotations throughout the module

lib/logging.ts


6. databases/cassandra_db.ts ✨ Enhancement +10/-6

Refactor imports to use type-only syntax in Cassandra driver

• Changed imports to use type imports for Settings, ArrayOrObject, ValueCallback, and
 ResultSet
• Added eslint disable comments for type assertions on clientOptions
• Improved logger callback handling with proper type casting

databases/cassandra_db.ts


7. databases/redis_db.ts ✨ Enhancement +6/-5

Update Redis driver with type-only imports and proper return types

• Changed imports to use type-only syntax for Settings, RedisClientOptions, and BulkObject
• Updated doBulk() method return type to Promise<void> and removed unnecessary null return

databases/redis_db.ts


8. databases/mysql_db.ts ✨ Enhancement +5/-4

Modernize MySQL driver imports with type-only syntax

• Changed imports to use type-only syntax for Settings, BulkObject, ConnectionConfig, Pool,
 and QueryError
• Removed unnecessary logger assignment comment
• Improved import organization and formatting

databases/mysql_db.ts


9. databases/elasticsearch_db.ts ✨ Enhancement +4/-4

Update Elasticsearch driver with type-only imports

• Changed imports to use type-only syntax for Settings and BulkObject
• Separated assert and equal imports for clarity
• Improved import organization

databases/elasticsearch_db.ts


10. databases/mongodb_db.ts ✨ Enhancement +4/-4

Refactor MongoDB driver with type-only imports

• Changed imports to use type-only syntax for Settings, BulkObject, Collection, and Db
• Improved import organization and formatting

databases/mongodb_db.ts


11. databases/couch_db.ts ✨ Enhancement +4/-3

Update CouchDB driver with type-only imports

• Changed imports to use type-only syntax for Settings, Agent, and BulkObject
• Improved import organization and formatting

databases/couch_db.ts


12. databases/postgres_db.ts ✨ Enhancement +3/-3

Modernize PostgreSQL driver with type-only imports

• Changed imports to use type-only syntax for Settings and BulkObject
• Improved import formatting and spacing

databases/postgres_db.ts


13. databases/rethink_db.ts ✨ Enhancement +2/-2

Update RethinkDB driver with type-only imports

• Changed imports to use type-only syntax for Settings and BulkObject

databases/rethink_db.ts


14. databases/mssql_db.ts ✨ Enhancement +4/-3

Refactor MSSQL driver with type-only imports

• Changed imports to use type-only syntax for Settings, ConnectionPool, and BulkObject
• Improved import organization and formatting

databases/mssql_db.ts


15. databases/dirty_db.ts ✨ Enhancement +1/-1

Update Dirty driver with type-only import

• Changed import to use type-only syntax for Settings

databases/dirty_db.ts


16. databases/sqlite_db.ts ✨ Enhancement +2/-3

Modernize SQLite driver with type-only imports

• Removed 'use strict' directive
• Changed imports to use type-only syntax for BulkObject and Settings
• Improved import path formatting

databases/sqlite_db.ts


17. databases/postgrespool_db.ts ✨ Enhancement +1/-1

Update PostgreSQL pool driver with type-only import

• Changed import to use type-only syntax for Settings

databases/postgrespool_db.ts


18. databases/dirty_git_db.ts ✨ Enhancement +1/-1

Update Dirty Git driver with type-only import

• Changed import to use type-only syntax for Settings

databases/dirty_git_db.ts


19. databases/memory_db.ts ✨ Enhancement +1/-1

Update Memory driver with type-only import

• Changed import to use type-only syntax for Settings

databases/memory_db.ts


20. databases/mock_db.ts ✨ Enhancement +1/-1

Update Mock driver with type-only import

• Changed import to use type-only syntax for Settings

databases/mock_db.ts


21. package.json ⚙️ Configuration changes +49/-27

Convert to ES modules and update package configuration

• Changed module type from commonjs to esm for ES6 module support
• Added version field 6.0.0
• Converted dependencies to peerDependencies with optional metadata
• Added exports field with proper import/types configuration
• Added main and files fields for package distribution
• Reorganized devDependencies alphabetically

package.json


22. tsconfig.json ⚙️ Configuration changes +1/-0

Enable verbatimModuleSyntax for ESM compatibility

• Added verbatimModuleSyntax compiler option set to true to enforce type-only imports for
 correct ESM output

tsconfig.json


23. .github/workflows/npmpublish.yml ⚙️ Configuration changes +1/-1

Update pnpm version in CI workflow

• Updated pnpm version from 10 to 11 in the GitHub Actions workflow

.github/workflows/npmpublish.yml


24. rolldown.config.mjs ⚙️ Configuration changes +1/-2

Switch build output format to ES modules

• Changed output format from cjs (CommonJS) to esm (ES modules)
• Removed explanatory comment about external modules

rolldown.config.mjs


25. pnpm-workspace.yaml ⚙️ Configuration changes +5/-0

Add build configuration for optional dependencies

• Added allowBuilds configuration section with build flags for optional native dependencies

pnpm-workspace.yaml


26. pnpm-lock.yaml Dependencies +81/-309

Reorganize dependencies and optimize build configuration

• Reorganized dependencies by moving database drivers and related packages from dependencies to
 devDependencies
• Updated version specifiers for async, dirty-ts, rusty-store-kv, and simple-git to more
 permissive ranges
• Removed optional dependencies like apache-arrow from @elastic/elasticsearch and build tools
 (jiti, terser) from vite
• Added libc platform specifications to multiple native bindings for @oxfmt, @oxlint,
 @rolldown, and @rollup packages
• Cleaned up unused transitive dependencies and type definitions

pnpm-lock.yaml


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 10, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0)

Grey Divider


Action required

1. doBulk missing drops writes 🐞 Bug ≡ Correctness
Description
CacheAndBufferLayer._write() treats a missing doBulk() as success due to optional chaining, then
marks entries clean without writing anything to the underlying DB. This can silently lose buffered
writes for wrapped DB implementations that do not provide doBulk().
Code

lib/CacheAndBufferLayer.ts[R539-551]

      let success = false;
      try {
-        await this.wrappedDB.doBulk(ops);
+        await this.wrappedDB!.doBulk?.(ops);
        success = true;
      } catch (err) {
        this.logger.error(
-            `Bulk write of ${ops.length} ops failed, retrying individually: ${err.stack || err}`);
+          `Bulk write of ${ops.length} ops failed, retrying individually: ${(err as Error).stack ?? String(err)}`,
+        );
        this.metrics.writesToDbRetried += ops.length;
-        await Promise.all(ops.map(async (op, i) => await writeOneOp(op, entries[i])));
+        await Promise.all(ops.map(async (op, i) => writeOneOp(op, entries[i])));
      }
      if (success) entries.forEach((entry) => markDone(entry, null));
    }
-    // This call to this.buffer.evictOld() can be safely removed (if we haven't run out of memory by
-    // this point then it is probably safe to continue using the memory until the next call to
-    // this.buffer.set() evicts the old entries), except removing it would cause some reads to be
-    // satisfied from the cache even when this.settings.cache = 0. That would contradict the
-    // documented behavior for cache = 0.
Evidence
InternalDB explicitly defines doBulk as optional, but _write() uses optional chaining and still sets
success=true, so the success path can run even if doBulk was never invoked.

lib/CacheAndBufferLayer.ts[40-50]
lib/CacheAndBufferLayer.ts[536-551]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`lib/CacheAndBufferLayer.ts` treats an absent `doBulk()` as a successful bulk write due to optional chaining (`doBulk?.(...)`), then marks all entries as written.

## Issue Context
`InternalDB` explicitly models `doBulk` as optional, so the cache layer must handle drivers that don't implement it by doing per-op writes.

## Fix Focus Areas
- lib/CacheAndBufferLayer.ts[40-50]
- lib/CacheAndBufferLayer.ts[536-551]

## Implementation notes
- Replace the optional-chained call with an explicit branch:
 - If `this.wrappedDB!.doBulk` is a function: call it.
 - Else: write individually (same logic as the retry path) and treat that as success.
- Ensure entries are only `markDone(..., null)` after at least one actual write path ran.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Default sqlite may crash 🐞 Bug ☼ Reliability
Description
The package now relies on optional peerDependencies for DB drivers, but Database still defaults to
sqlite, whose driver imports rusty-store-kv. If the peer dependency is not installed, init() will
throw a runtime module-not-found error without a clear, actionable message.
Code

package.json[R25-70]

+  "exports": {
+    ".": {
+      "import": "./dist/index.js",
+      "types": "./dist/index.d.ts"
+    }
+  },
+  "main": "./dist/index.js",
+  "types": "./dist/index.d.ts",
+  "files": [
+    "dist/*.js",
+    "dist/*.d.ts",
+    "dist/databases",
+    "dist/lib"
+  ],
+  "peerDependencies": {
+    "@elastic/elasticsearch": "^9.0.0",
+    "async": "^3.0.0",
+    "cassandra-driver": "^4.0.0",
+    "dirty-ts": "^1.0.0",
+    "mongodb": "^7.0.0",
+    "mssql": "^12.0.0",
+    "mysql2": "^3.0.0",
+    "nano": "^11.0.0",
+    "pg": "^8.0.0",
+    "redis": "^5.0.0",
+    "rethinkdb": "^2.0.0",
+    "rusty-store-kv": "^1.0.0",
+    "simple-git": "^3.0.0",
+    "surrealdb": "^2.0.0"
+  },
+  "peerDependenciesMeta": {
+    "@elastic/elasticsearch": {"optional": true},
+    "async": {"optional": true},
+    "cassandra-driver": {"optional": true},
+    "dirty-ts": {"optional": true},
+    "mongodb": {"optional": true},
+    "mssql": {"optional": true},
+    "mysql2": {"optional": true},
+    "nano": {"optional": true},
+    "pg": {"optional": true},
+    "redis": {"optional": true},
+    "rethinkdb": {"optional": true},
+    "rusty-store-kv": {"optional": true},
+    "simple-git": {"optional": true},
+    "surrealdb": {"optional": true}
  },
Evidence
Database defaults to sqlite, sqlite_db imports an external dependency, and the bundler configuration
externalizes non-relative imports (so rusty-store-kv must be installed at runtime). The dependency
is no longer in dependencies, only optional peerDependencies.

index.ts[68-72]
databases/sqlite_db.ts[2-4]
rolldown.config.mjs[4-11]
package.json[39-70]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
With all drivers moved to optional `peerDependencies`, the package no longer guarantees the default backend (sqlite) can be loaded. A user who doesn't have `rusty-store-kv` installed will get a runtime import error when `init()` loads `sqlite_db`.

## Issue Context
- `Database` defaults to `sqlite` when `type` is undefined.
- `sqlite_db` imports `rusty-store-kv`.
- Bundling config externalizes non-relative imports, so the module must exist in the consumer's install.

## Fix Focus Areas
- index.ts[68-72]
- databases/sqlite_db.ts[2-4]
- package.json[39-70]
- rolldown.config.mjs[4-11]

## Implementation notes
Choose one:
1) Keep the default backend installable:
  - Move `rusty-store-kv` back to `dependencies` (not optional peer), OR
2) Keep all backends optional, but make default safe and explicit:
  - Change the default type from `sqlite` to `memory`, OR
  - If default remains `sqlite`, catch `ERR_MODULE_NOT_FOUND` in `initDB()` when importing the driver and throw a new error that clearly instructs: `npm i rusty-store-kv`.
Also consider documenting required installs per backend.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. setSub null deletes property 🐞 Bug ≡ Correctness
Description
CacheAndBufferLayer.setSub() deletes a subproperty when the provided value is null because it uses a
loose null check (value == null). This makes it impossible to store null as a meaningful subproperty
value.
Code

lib/CacheAndBufferLayer.ts[R423-427]

          if (value == null) {
-              delete ptr.obj[ptr.prop];
+            delete ptr.obj[ptr.prop];
          } else {
-              ptr.obj[ptr.prop] = value;
+            ptr.obj[ptr.prop] = value;
          }
Evidence
setSub() uses value == null which treats null and undefined the same, and the test suite
demonstrates deletion via undefined (not null), implying null may be intended as a storable value
rather than a delete marker for subproperties.

lib/CacheAndBufferLayer.ts[388-427]
test/lib/test_lib.ts[234-246]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`setSub()` currently deletes the target property when `value` is `null` or `undefined` due to `value == null`. This prevents storing `null` values inside stored objects.

## Issue Context
The test suite exercises deletion using `undefined`, not `null`, so conflating the two is a behavioral change that can surprise callers.

## Fix Focus Areas
- lib/CacheAndBufferLayer.ts[388-427]
- test/lib/test_lib.ts[234-246]

## Implementation notes
- Change the deletion condition from `value == null` to `value === undefined` if the intended delete marker is `undefined`.
- If `null` should also delete, document it explicitly and add a test case covering `null` deletion.
- Consider using a dedicated sentinel for deletion to avoid ambiguous semantics.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Cassandra logger type mismatch 🐞 Bug ⚙ Maintainability
Description
Settings.logger is typed as a Logger object, but cassandra_db documents and uses it as a callable
function for cassandra-driver log events. This forces unsafe casts and breaks TypeScript consumers
configuring Cassandra driver logging.
Code

lib/AbstractDatabase.ts[R38-42]

  cache?: number;
  writeInterval?: number;
-  logger?: any;
-  columnFamily?: any;
-  clientOptions?: any;
+  logger?: Logger;
+  columnFamily?: unknown;
+  clientOptions?: unknown;
Evidence
Abstract Settings declares logger as Logger (object with methods), while cassandra_db stores
settings.logger and invokes it as a function in the cassandra-driver 'log' handler.

lib/AbstractDatabase.ts[38-42]
databases/cassandra_db.ts[41-56]
databases/cassandra_db.ts[71-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Settings.logger` is typed as `Logger`, but Cassandra driver integration expects a callable function and the code invokes it as such. This is a type contract mismatch that currently relies on `as any`.

## Issue Context
`settings.logger` in cassandra_db is not the same concept as ueberdb's normalized logger object; it's a cassandra-driver log callback.

## Fix Focus Areas
- lib/AbstractDatabase.ts[38-42]
- databases/cassandra_db.ts[41-56]
- databases/cassandra_db.ts[71-75]

## Implementation notes
Options:
- Change `Settings.logger` to a union that matches reality, e.g. `Logger | ((...args: unknown[]) => void)`.
- Or introduce a separate setting name for cassandra driver logging (e.g. `cassandraLogListener`) and keep `logger` reserved for ueberdb logging.
- Remove `as any` casts once the type reflects intended usage.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines 539 to 551
let success = false;
try {
await this.wrappedDB.doBulk(ops);
await this.wrappedDB!.doBulk?.(ops);
success = true;
} catch (err) {
this.logger.error(
`Bulk write of ${ops.length} ops failed, retrying individually: ${err.stack || err}`);
`Bulk write of ${ops.length} ops failed, retrying individually: ${(err as Error).stack ?? String(err)}`,
);
this.metrics.writesToDbRetried += ops.length;
await Promise.all(ops.map(async (op, i) => await writeOneOp(op, entries[i])));
await Promise.all(ops.map(async (op, i) => writeOneOp(op, entries[i])));
}
if (success) entries.forEach((entry) => markDone(entry, null));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Dobulk missing drops writes 🐞 Bug ≡ Correctness

CacheAndBufferLayer._write() treats a missing doBulk() as success due to optional chaining, then
marks entries clean without writing anything to the underlying DB. This can silently lose buffered
writes for wrapped DB implementations that do not provide doBulk().
Agent Prompt
## Issue description
`lib/CacheAndBufferLayer.ts` treats an absent `doBulk()` as a successful bulk write due to optional chaining (`doBulk?.(...)`), then marks all entries as written.

## Issue Context
`InternalDB` explicitly models `doBulk` as optional, so the cache layer must handle drivers that don't implement it by doing per-op writes.

## Fix Focus Areas
- lib/CacheAndBufferLayer.ts[40-50]
- lib/CacheAndBufferLayer.ts[536-551]

## Implementation notes
- Replace the optional-chained call with an explicit branch:
  - If `this.wrappedDB!.doBulk` is a function: call it.
  - Else: write individually (same logic as the retry path) and treat that as success.
- Ensure entries are only `markDone(..., null)` after at least one actual write path ran.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@SamTV12345 SamTV12345 changed the title Feauture/sped improvement feat: use esm only May 10, 2026
@SamTV12345 SamTV12345 merged commit b852144 into main May 10, 2026
13 checks passed
@SamTV12345 SamTV12345 deleted the feauture/sped-improvement branch May 10, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant