monsqlize 2.0.6 → 3.1.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
@@ -1,52 +1,73 @@
1
1
  # monSQLize
2
2
 
3
- TypeScript-native MongoDB ODM and enhancement layer with v1-compatible APIs, multi-level caching, distributed locks, transactions, Saga orchestration, model validation, connection pools, Change Stream sync, slow-query logging, and CommonJS / ESM / TypeScript declaration outputs.
3
+ Database-native production data runtime layer for TypeScript services. monSQLize keeps database semantics explicit while adding shared runtime capabilities for caching, transactions, connection pools, models, synchronization, observability, and CommonJS / ESM / TypeScript declaration outputs.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/monsqlize.svg)](https://www.npmjs.com/package/monsqlize)
6
6
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
7
- [![MongoDB](https://img.shields.io/badge/MongoDB-6.x%20%2F%207.x-green.svg)](https://www.mongodb.com/)
7
+ [![MongoDB](https://img.shields.io/badge/MongoDB-7.x%20%2F%208.x-green.svg)](https://www.mongodb.com/)
8
8
  [![Node.js](https://img.shields.io/badge/Node.js-18%2B-brightgreen)](https://nodejs.org/)
9
9
 
10
10
  Documentation: [English](https://vextjs.github.io/monSQLize/) · [简体中文](https://vextjs.github.io/monSQLize/zh/)
11
+ Quick path: [Installation](https://vextjs.github.io/monSQLize/getting-started) · [Basic Usage](https://vextjs.github.io/monSQLize/basic-operations)
12
+ Configuration reference: [English](https://vextjs.github.io/monSQLize/configuration) · [简体中文](https://vextjs.github.io/monSQLize/zh/configuration)
13
+ Upgrade and security: [Migration Guide](./MIGRATION.md) · [Private Vulnerability Reporting](./SECURITY.md)
14
+
15
+ The npm `latest` dist-tag and GitHub Pages are the stable channel; `main` may contain the next release. Pages deployment accepts only a versioned Git tag whose package version is already present on npm, so unpublished APIs are not promoted as stable documentation.
16
+
17
+ This source tree contains the stable `3.1.0` release candidate, pinned to verified registry `schema-dsl@3.0.0`. The v3 package remains subject to the full release gate before its immutable tag and npm publication.
11
18
 
12
19
  ```bash
13
20
  npm install monsqlize
14
21
  ```
15
22
 
16
- monSQLize is currently a MongoDB-focused package. The long-term product direction is to keep the MongoDB-style query experience while gradually extending the same high-level API shape to additional database backends.
17
-
18
- ## Table of Contents
19
-
20
- - [Why monSQLize](#why-monsqlize)
21
- - [When to Use It](#when-to-use-it)
22
- - [Installation](#installation)
23
- - [Quick Start](#quick-start)
24
- - [Model Layer](#model-layer)
25
- - [Caching and Performance](#caching-and-performance)
26
- - [Advanced Capabilities](#advanced-capabilities)
27
- - [Migration from the MongoDB Driver](#migration-from-the-mongodb-driver)
28
- - [Compatibility](#compatibility)
29
- - [Documentation](#documentation)
30
- - [Development](#development)
31
- - [Release Status](#release-status)
32
- - [Roadmap](#roadmap)
33
- - [License](#license)
34
- - [Support](#support)
23
+ MongoDB is the first complete adapter. MySQL and PostgreSQL adapters are planned as database-native runtime adapters, not as a transparent promise that every database already accepts the same query syntax.
35
24
 
36
25
  ## Why monSQLize
37
26
 
38
- monSQLize keeps the MongoDB driver mental model while adding the production features most teams end up building around it:
27
+ monSQLize is not an ORM and it is not just a CRUD wrapper. It is a production data runtime layer: the database driver remains visible, while the operational features teams usually build around the driver are provided in one runtime.
39
28
 
40
- - Drop-in collection helpers that preserve MongoDB-style CRUD, aggregation, indexes, transactions, and Change Streams.
41
- - Smart caching through `cache-hub`, including local memory caching, optional Redis-backed L2 caching, automatic invalidation, and function-level caching.
29
+ - Database-native adapter APIs: the current stable adapter preserves MongoDB-style CRUD, aggregation, indexes, transactions, and Change Streams.
30
+ - Smart database caching through `cache-hub`, including local memory caching, optional Redis-backed L2 caching, and automatic invalidation.
42
31
  - A lightweight Model layer with `schema-dsl` validation, hooks, relations, populate, custom methods, timestamps, soft delete, optimistic locking, and production-safe index preflight.
43
32
  - Multi-connection-pool support, pool health checks, pool-scoped collections/models, and fallback strategies.
44
- - Business locks and distributed locks for multi-instance deployments.
45
- - Saga orchestration for multi-step business workflows.
46
33
  - Change Stream sync helpers with resume token storage.
47
34
  - Slow-query logging and query diagnostics.
48
35
  - CommonJS, ESM, and TypeScript declaration outputs from `dist/**`.
49
36
 
37
+ ## Adapter Status
38
+
39
+ | Adapter | Current status | Public entry |
40
+ |---|---|---|
41
+ | MongoDB | Stable and fully implemented | `type: 'mongodb'`, `collection()`, `db()`, `use()`, `pool()` |
42
+ | MySQL | Planned / in development | Not part of the current npm runtime yet |
43
+ | PostgreSQL | Planned / in development | Not part of the current npm runtime yet |
44
+
45
+ The shared runtime direction is cache consistency, connection lifecycle, transaction helpers, model constraints, synchronization, and observability across adapters. Adapter-native query, transaction, and connection semantics will stay explicit.
46
+
47
+ ## Runtime Consistency Contract
48
+
49
+ monSQLize coordinates cache, transactions, sync, and queues inside the runtime, but it does not provide a global strict-consistency kernel. MongoDB transactions keep MongoDB session ACID semantics. Query caching is opt-in, and write-side cache invalidation is explicit: use `cache.invalidate` for precise entries or `autoInvalidate` / `cache.autoInvalidate` for broad invalidation. Cache invalidation runs after successful writes or transaction commit and is best-effort; Redis/L2 cache and Pub/Sub invalidation provide eventual cross-instance coherence rather than atomic cache/DB commits. Change Stream sync is at-least-once; custom targets should be idempotent by change event `_id`, and `sync.idempotency` can record per-target replay markers when a durable store is provided. Transaction cache locks are process-local in the current v3 runtime; use explicit business coordination, idempotency/fencing, or cache bypassing for cross-instance strict flows.
50
+
51
+ ## Write Path Policy
52
+
53
+ By default, both `collection()` and `model()` may write. Applications that want all writes for selected namespaces to pass through Model defaults, hooks, timestamps, versioning, and soft-delete rules can enable `writePathPolicy`.
54
+
55
+ ```ts
56
+ const msq = new MonSQLize({
57
+ type: 'mongodb',
58
+ databaseName: 'app',
59
+ config: { uri: 'mongodb://localhost:27017' },
60
+ writePathPolicy: {
61
+ default: 'model-only',
62
+ namespaces: {
63
+ 'app.audit_logs': 'allow-both'
64
+ }
65
+ }
66
+ });
67
+ ```
68
+
69
+ `model-only` blocks direct collection/db/legacy write surfaces by default, including raw access and `$out` / `$merge` aggregate writes, while Model write and Model management methods remain available. See [Write Path Policy](./docs/en/write-path-policy.md).
70
+
50
71
  ## When to Use It
51
72
 
52
73
  monSQLize is a good fit when you need:
@@ -54,8 +75,9 @@ monSQLize is a good fit when you need:
54
75
  | Scenario | Benefit |
55
76
  |---|---|
56
77
  | High-concurrency reads | Cache hot data and reduce repeated database work. |
57
- | MongoDB API compatibility | Keep familiar query syntax while adding higher-level helpers. |
58
- | Multi-instance services | Use Redis invalidation and distributed locks to keep instances coordinated. |
78
+ | MongoDB API compatibility today | Keep familiar MongoDB syntax while adding higher-level runtime helpers. |
79
+ | A future multi-database runtime boundary | Prepare for MySQL/PostgreSQL adapters without turning SQL into fake MongoDB syntax. |
80
+ | Multi-instance services | Use Redis invalidation and pool health checks to keep instances coordinated. |
59
81
  | Transaction-heavy flows | Use `withTransaction()` and transaction-aware helpers instead of hand-rolled lifecycle code. |
60
82
  | Model-level ergonomics | Add schema validation, hooks, populate, and custom methods only where needed. |
61
83
  | Smooth upgrade from v1 | Keep legacy application source stable while adopting the TypeScript rewrite. |
@@ -68,37 +90,32 @@ monSQLize is usually not the best first choice for pure write-heavy workloads, e
68
90
  npm install monsqlize
69
91
  ```
70
92
 
71
- Runtime dependencies installed with the package:
72
-
73
- - `mongodb` - official MongoDB driver.
74
- - `schema-dsl` - model schema validation runtime dependency.
75
- - `cache-hub` - cache and function-cache foundation.
76
- - `async-lock` - local concurrency lock support.
77
- - `ioredis` - Redis-backed L2 cache, distributed invalidation, and distributed lock support.
78
- - `ssh2` - SSH tunnel support for restricted/private network deployment.
93
+ Use Node.js 18 or newer and provide a MongoDB connection URI. Optional Redis, SSH tunnel, cache, Model, and sync features are configured only when your application enables them.
79
94
 
80
95
  ## Quick Start
81
96
 
97
+ The current stable quick start uses the MongoDB adapter.
98
+
82
99
  ### CommonJS
83
100
 
84
101
  ```js
85
102
  const MonSQLize = require('monsqlize');
86
103
 
87
- const db = new MonSQLize({
104
+ const msq = new MonSQLize({
88
105
  type: 'mongodb',
89
106
  databaseName: 'mydb',
90
107
  config: {
91
108
  uri: 'mongodb://localhost:27017'
92
109
  },
93
110
  cache: {
94
- enabled: true,
95
- ttl: 60_000
111
+ maxEntries: 10000,
112
+ defaultTtl: 60_000
96
113
  }
97
114
  });
98
115
 
99
- await db.connect();
116
+ await msq.connect();
100
117
 
101
- const users = db.collection('users');
118
+ const users = msq.collection('users');
102
119
 
103
120
  await users.insertOne({
104
121
  username: 'john',
@@ -107,23 +124,25 @@ await users.insertOne({
107
124
  });
108
125
 
109
126
  const user = await users.findOne({ email: 'john@example.com' });
110
- const userById = await users.findOneById('507f1f77bcf86cd799439011');
127
+ const sameUser = await users.findOne({ _id: '507f1f77bcf86cd799439011' });
111
128
 
112
129
  await users.updateOne(
113
130
  { email: 'john@example.com' },
114
131
  { $set: { lastLoginAt: new Date() } }
115
132
  );
116
133
 
117
- await db.close();
134
+ await msq.close();
118
135
  ```
119
136
 
137
+ Next, use the [Basic Usage guide](https://vextjs.github.io/monSQLize/basic-operations) for common CRUD, pagination, read cache, and Model entry-point examples.
138
+
120
139
  ### ESM and TypeScript
121
140
 
122
141
  ```ts
123
142
  import MonSQLize from 'monsqlize';
124
143
  import type { Collection } from 'monsqlize';
125
144
 
126
- const db = new MonSQLize({
145
+ const msq = new MonSQLize({
127
146
  type: 'mongodb',
128
147
  databaseName: 'mydb',
129
148
  config: {
@@ -131,12 +150,12 @@ const db = new MonSQLize({
131
150
  }
132
151
  });
133
152
 
134
- await db.connect();
153
+ await msq.connect();
135
154
 
136
- const users: Collection = db.collection('users');
155
+ const users: Collection = msq.collection('users');
137
156
  const activeUsers = await users.find({ status: 'active' }).toArray();
138
157
 
139
- await db.close();
158
+ await msq.close();
140
159
  ```
141
160
 
142
161
  Published entry points:
@@ -147,13 +166,13 @@ Published entry points:
147
166
  | ESM | `dist/esm/index.mjs` |
148
167
  | Types | `dist/types/index.d.ts` |
149
168
 
150
- The package root exports only the public package contract. Deep imports into historical `lib/**` files are not part of the v2 publishing surface.
169
+ The package root exports only the public package contract. Deep imports into historical `lib/**` files are not part of the v3 publishing surface.
151
170
 
152
171
  ## Model Layer
153
172
 
154
173
  The Model layer is optional. Use it when you want schema validation, hooks, relations, populate, custom methods, timestamps, soft delete, or optimistic locking.
155
174
 
156
- `schema-dsl` is installed automatically as a runtime dependency of monSQLize. You only need to declare `schema-dsl` in your own app if your application imports it directly.
175
+ Models use the current `schema-dsl/runtime` path through monSQLize. monSQLize creates an isolated schema runtime for each `MonSQLize` instance, then compiles Model schema callbacks when a Model is bound to that runtime.
157
176
 
158
177
  ### Manual Model Registration
159
178
 
@@ -162,7 +181,7 @@ const MonSQLize = require('monsqlize');
162
181
  const { Model } = MonSQLize;
163
182
 
164
183
  Model.define('users', {
165
- schema: (dsl) => dsl({
184
+ schema: (s) => s({
166
185
  username: 'string:3-32!',
167
186
  email: 'email!',
168
187
  password: 'string:6-!',
@@ -198,15 +217,15 @@ Model.define('users', {
198
217
  })
199
218
  });
200
219
 
201
- const db = new MonSQLize({
220
+ const msq = new MonSQLize({
202
221
  type: 'mongodb',
203
222
  databaseName: 'mydb',
204
223
  config: { uri: 'mongodb://localhost:27017' }
205
224
  });
206
225
 
207
- await db.connect();
226
+ await msq.connect();
208
227
 
209
- const User = db.model('users');
228
+ const User = msq.model('users');
210
229
  const user = await User.insertOne({
211
230
  username: 'john',
212
231
  email: 'john@example.com',
@@ -215,29 +234,60 @@ const user = await User.insertOne({
215
234
  });
216
235
  ```
217
236
 
237
+ When a service needs runtime-local custom types, messages, locale, or an already-owned schema-dsl runtime, configure `schemaDsl` on the MonSQLize instance:
238
+
239
+ ```js
240
+ const { createRuntime } = require('schema-dsl/runtime');
241
+
242
+ const schemaRuntime = createRuntime({
243
+ types: {
244
+ tenantId: { type: 'string', pattern: '^tenant_[a-z0-9]+$' }
245
+ }
246
+ });
247
+
248
+ Model.define('tenantUsers', {
249
+ schema: (s) => s({
250
+ tenantId: 'tenantId!',
251
+ email: 'email!'
252
+ })
253
+ });
254
+
255
+ const msq = new MonSQLize({
256
+ type: 'mongodb',
257
+ databaseName: 'mydb',
258
+ config: { uri: 'mongodb://localhost:27017' },
259
+ schemaDsl: { runtime: schemaRuntime }
260
+ });
261
+ ```
262
+
263
+ For monSQLize-only Model validation, no direct application import from `schema-dsl` is required. Direct application imports should use `schema-dsl/runtime` when they need to share the same isolated runtime state with monSQLize.
264
+ Use `schemaDsl: { extensions }` when monSQLize should own the runtime and register extension definitions. When the application owns the schema-dsl lifecycle, configure that runtime directly, including `runtime.registerExtensions([...])`, and inject it with `schemaDsl: { runtime }`. If the default `schema-dsl/runtime` entry cannot be resolved or does not expose the required runtime APIs, monSQLize throws `INVALID_CONFIG`; validation is disabled only when `schemaDsl: false` or `schemaDsl: { enabled: false }` is set explicitly.
265
+
266
+ For `insertOne`, `insertMany`, `insertBatch`, `replaceOne`, `findOneAndReplace`, and hydrated document `save()`, successful schema validation now forwards schema-dsl's normalized `data` into the actual write. Public errors remain `{ field, message }`, mapped from canonical upstream `path/message`. Update operators and pipelines are intentionally outside this complete-document normalization contract.
267
+
218
268
  ### Automatic Model Loading
219
269
 
220
270
  ```js
221
271
  const path = require('path');
222
272
  const MonSQLize = require('monsqlize');
223
273
 
224
- const db = new MonSQLize({
274
+ const msq = new MonSQLize({
225
275
  type: 'mongodb',
226
276
  databaseName: 'mydb',
227
277
  config: { uri: 'mongodb://localhost:27017' },
228
278
  models: path.join(__dirname, 'models')
229
279
  });
230
280
 
231
- await db.connect();
281
+ await msq.connect();
232
282
 
233
- const User = db.model('users');
283
+ const User = msq.model('users');
234
284
  ```
235
285
 
236
286
  ```js
237
287
  // models/user.model.js
238
288
  module.exports = {
239
289
  name: 'users',
240
- schema: (dsl) => dsl({
290
+ schema: (s) => s({
241
291
  username: 'string:3-32!',
242
292
  email: 'email!'
243
293
  }),
@@ -258,27 +308,56 @@ Relative model paths are resolved from `process.cwd()`. In production services,
258
308
  Model-declared indexes are still created automatically by default for backward compatibility. Production services can turn off automatic indexing and run an explicit preflight before creating missing indexes:
259
309
 
260
310
  ```js
261
- const db = new MonSQLize({
311
+ const msq = new MonSQLize({
262
312
  type: 'mongodb',
263
313
  databaseName: 'mydb',
264
314
  config: { uri: 'mongodb://localhost:27017' },
265
315
  autoIndex: false
266
316
  });
267
317
 
268
- const plan = await db.ensureModelIndexes({ models: ['users'], dryRun: true });
318
+ const plan = await msq.ensureModelIndexes({ models: ['users'], dryRun: true });
269
319
 
270
320
  if (plan.totals.conflicts === 0) {
271
- await db.ensureModelIndexes({ models: ['users'], throwOnError: true });
321
+ await msq.ensureModelIndexes({ models: ['users'], throwOnError: true });
272
322
  }
273
323
  ```
274
324
 
275
325
  `ensureModelIndexes()` creates only missing indexes. It does not drop, rename, or rebuild conflicting indexes.
276
326
 
327
+ ### Versioned Writes
328
+
329
+ Models with `options.version` use single-document optimistic concurrency control. When the filter contains a direct `_id`, monSQLize reads the current version automatically. You can still pass an explicit version in the filter or as `expectedVersion` when you want to control the expected version yourself:
330
+
331
+ ```js
332
+ await User.updateOne(
333
+ { _id: userId },
334
+ { $set: { status: 'active' } }
335
+ );
336
+
337
+ await User.replaceOne(
338
+ { _id: userId },
339
+ nextUser,
340
+ { expectedVersion: user.version }
341
+ );
342
+ ```
343
+
344
+ Successful `save()`, `updateOne()`, `replaceOne()`, `findOneAndUpdate()`, and `findOneAndReplace()` advance the version. Stale writes throw a `WRITE_CONFLICT` error.
345
+
346
+ For `updateMany()` and `updateBatch()`, choose the batch version behavior explicitly when needed:
347
+
348
+ ```js
349
+ await User.updateMany({ status: 'pending' }, { $set: { status: 'active' } }, {
350
+ versionMode: 'strict' // 'counter' | 'strict' | 'off'
351
+ });
352
+ ```
353
+
354
+ `counter` is the default and only increments the version counter; it is not optimistic locking. `strict` pre-reads matching document IDs and versions, conditionally updates each document, and returns `conflictCount` / `conflictedIds` on the result object.
355
+
277
356
  ### Populate
278
357
 
279
358
  ```js
280
359
  Model.define('posts', {
281
- schema: (dsl) => dsl({
360
+ schema: (s) => s({
282
361
  title: 'string:1-200!',
283
362
  content: 'string!',
284
363
  userId: 'objectId!'
@@ -296,12 +375,20 @@ const userWithPosts = await User.findOne({ username: 'john' })
296
375
 
297
376
  Populate is supported by `find()`, `findOne()`, `findByIds()`, `findOneById()`, `findAndCount()`, and `findPage()`.
298
377
 
378
+ For has-many relations, `skip` and `limit` are applied per parent document after related records are grouped. Nested populate has a default `maxDepth` of `5`; set `maxDepth` on a populate branch when a self-referencing relation needs a different cap.
379
+
380
+ ### Soft Delete Visibility
381
+
382
+ When `softDelete` is enabled, standard model read paths hide deleted documents by default: `find()`, `findOne()`, `findOneById()`, `findByIds()`, `findPage()`, `findAndCount()`, `count()`, `distinct()`, `aggregate()`, `stream()`, and `explain()`. Pass `withDeleted: true` to include deleted documents or `onlyDeleted: true` to query only deleted documents.
383
+
384
+ For aggregation, monSQLize prepends a soft-delete `$match` stage before the user pipeline, or after `$geoNear` when that stage is first. Soft-delete filtering inside user-authored `$lookup` pipelines remains the application's responsibility.
385
+
299
386
  ## Caching and Performance
300
387
 
301
- monSQLize can cache collection queries and arbitrary async functions.
388
+ monSQLize can cache collection queries and coordinate local/Redis-backed invalidation for database runtime usage.
302
389
 
303
390
  ```js
304
- const users = db.collection('users');
391
+ const users = msq.collection('users');
305
392
 
306
393
  const hotUser = await users.findOne(
307
394
  { email: 'john@example.com' },
@@ -309,51 +396,36 @@ const hotUser = await users.findOne(
309
396
  );
310
397
  ```
311
398
 
312
- ```js
313
- const { withCache } = require('monsqlize');
314
-
315
- async function getUserProfile(userId) {
316
- const user = await db.collection('users').findOneById(userId);
317
- const orders = await db.collection('orders').find({ userId }).toArray();
318
- return { user, orders };
319
- }
320
-
321
- const cachedGetUserProfile = withCache(getUserProfile, {
322
- ttl: 300_000,
323
- cache: db.getCache()
324
- });
325
-
326
- await cachedGetUserProfile('user-1');
327
- ```
328
-
329
399
  Cache capabilities include:
330
400
 
331
401
  - In-memory L1 cache.
332
402
  - Optional Redis-backed L2 cache.
333
403
  - Automatic invalidation after writes.
334
- - Function-level caching through `withCache()`.
335
- - In-flight request deduplication.
336
- - Namespaces, TTLs, statistics, and conditional caching.
404
+ - Cache namespace, TTL, and distributed invalidation controls.
337
405
 
338
406
  ## Advanced Capabilities
339
407
 
340
408
  ### Transactions
341
409
 
342
410
  ```js
343
- await db.withTransaction(async (session) => {
344
- await db.collection('orders').insertOne({ userId, status: 'pending' }, { session });
345
- await db.collection('users').updateOne(
411
+ await msq.withTransaction(async (tx) => {
412
+ await msq.collection('orders').insertOne({ userId, status: 'pending' }, { session: tx.session });
413
+ await msq.collection('users').updateOne(
346
414
  { _id: userId },
347
415
  { $inc: { orderCount: 1 } },
348
- { session }
416
+ { session: tx.session }
349
417
  );
350
418
  });
351
419
  ```
352
420
 
421
+ Read options such as `session`, `readConcern`, `readPreference`, `collation`, `hint`, `maxTimeMS`, and `allowDiskUse` are forwarded to the MongoDB driver. Query caches are bypassed while a `session` is present, so transaction reads use the driver snapshot instead of a shared cache entry.
422
+
423
+ Transaction cache invalidations are recorded during the transaction and flushed only after a successful commit. If the transaction aborts, pending invalidations are discarded.
424
+
353
425
  ### Connection Pools
354
426
 
355
427
  ```js
356
- const db = new MonSQLize({
428
+ const msq = new MonSQLize({
357
429
  type: 'mongodb',
358
430
  databaseName: 'main',
359
431
  config: { uri: 'mongodb://primary:27017' },
@@ -362,24 +434,13 @@ const db = new MonSQLize({
362
434
  ]
363
435
  });
364
436
 
365
- const reports = db.pool('analytics').collection('reports');
366
- ```
367
-
368
- ### Distributed Locks
369
-
370
- ```js
371
- await db.withLock('inventory:sku-1', async () => {
372
- await db.collection('inventory').updateOne(
373
- { sku: 'sku-1' },
374
- { $inc: { stock: -1 } }
375
- );
376
- });
437
+ const reports = msq.pool('analytics').collection('reports');
377
438
  ```
378
439
 
379
440
  ### Change Streams
380
441
 
381
442
  ```js
382
- const watcher = db.collection('orders').watch([
443
+ const watcher = msq.collection('orders').watch([
383
444
  { $match: { 'fullDocument.status': 'pending' } }
384
445
  ]);
385
446
 
@@ -388,25 +449,6 @@ watcher.on('change', (change) => {
388
449
  });
389
450
  ```
390
451
 
391
- ### Saga Orchestration
392
-
393
- ```js
394
- db.defineSaga('checkout', [
395
- {
396
- name: 'reserveInventory',
397
- execute: async (ctx) => reserveInventory(ctx),
398
- compensate: async (ctx) => releaseInventory(ctx)
399
- },
400
- {
401
- name: 'chargePayment',
402
- execute: async (ctx) => chargePayment(ctx),
403
- compensate: async (ctx) => refundPayment(ctx)
404
- }
405
- ]);
406
-
407
- await db.executeSaga('checkout', { orderId });
408
- ```
409
-
410
452
  ## Migration from the MongoDB Driver
411
453
 
412
454
  The smallest migration is usually to replace only initialization:
@@ -421,15 +463,15 @@ const nativeUsers = nativeClient.db('mydb').collection('users');
421
463
  ```js
422
464
  const MonSQLize = require('monsqlize');
423
465
 
424
- const db = new MonSQLize({
466
+ const msq = new MonSQLize({
425
467
  type: 'mongodb',
426
468
  databaseName: 'mydb',
427
469
  config: { uri: 'mongodb://localhost:27017' },
428
470
  cache: { enabled: true }
429
471
  });
430
472
 
431
- await db.connect();
432
- const users = db.collection('users');
473
+ await msq.connect();
474
+ const users = msq.collection('users');
433
475
  ```
434
476
 
435
477
  MongoDB-style collection calls can remain unchanged in most cases:
@@ -439,15 +481,15 @@ const user = await users.findOne({ email });
439
481
  const list = await users.find({ status: 'active' }).toArray();
440
482
  ```
441
483
 
442
- The v2 line has been validated against the workspace consumers `chat`, `payment`, `user`, `admin`, `search`, `vext`, and `permission-core` without requiring business-source changes in those projects.
484
+ The v3 line has been validated against the workspace consumers `chat`, `payment`, `user`, `admin`, `search`, `vext`, and `permission-core` without requiring business-source changes in those projects.
443
485
 
444
486
  ## Compatibility
445
487
 
446
488
  | Surface | Current Support |
447
489
  |---|---|
448
490
  | Node.js | `>=18.0.0`; CI covers Node 18 / 20 / 22. |
449
- | MongoDB driver | `mongodb@6.21.0` runtime baseline; driver 7.2.0 has additional compatibility coverage. |
450
- | MongoDB server | Memory-server based 6.x / 7.x validation is covered by the project test matrix. |
491
+ | MongoDB driver | `mongodb@6.21.0` runtime baseline; driver 7.5.0 has additional compatibility coverage. |
492
+ | MongoDB server | Memory-server based 7.x / 8.x validation is covered by the strict project test matrix. |
451
493
  | Module systems | CommonJS and ESM are both validated. |
452
494
  | TypeScript | Public declarations are published from `dist/types/index.d.ts`. |
453
495
  | Package license | Apache-2.0. |
@@ -456,25 +498,27 @@ See the current support and verification documents:
456
498
 
457
499
  - [English documentation](https://github.com/vextjs/monSQLize/blob/main/docs/en/README.md)
458
500
  - [Chinese documentation](https://github.com/vextjs/monSQLize/blob/main/docs/zh/README.md)
459
- - [English recipes](https://github.com/vextjs/monSQLize/blob/main/docs/en/recipes.md)
501
+ - [English common scenarios](https://github.com/vextjs/monSQLize/blob/main/docs/en/recipes.md)
460
502
  - [Support matrix](https://github.com/vextjs/monSQLize/blob/main/docs/en/support-matrix.md)
461
- - [Verification entry points](https://github.com/vextjs/monSQLize/blob/main/docs/en/verification-entrypoints.md)
462
503
  - [test/compatibility/README.md](https://github.com/vextjs/monSQLize/blob/main/test/compatibility/README.md)
463
504
  - [test/validation/VERIFICATION-PROGRESS.md](https://github.com/vextjs/monSQLize/blob/main/test/validation/VERIFICATION-PROGRESS.md)
464
505
 
465
506
  ## Documentation
466
507
 
467
- Current TypeScript documentation and examples are the source of truth for the v2 package:
508
+ Current TypeScript documentation and examples are the source of truth for the v3 package:
468
509
 
469
510
  - Complete docs: [English](https://vextjs.github.io/monSQLize/) · [简体中文](https://vextjs.github.io/monSQLize/zh/)
470
- - `docs/en/**` - default English documentation.
471
- - `docs/zh/**` - Simplified Chinese documentation.
472
- - `docs/en/recipes.md` / `docs/zh/recipes.md` - shortest copy-ready paths for common setup scenarios.
473
- - `examples/**` - TypeScript examples.
474
- - `test/compatibility/**` - package exports and compatibility guards.
475
- - `test/validation/**` - verification ledgers and mapping notes.
476
-
477
- Historical v1 assets are useful for tracing old behavior, but they are not the current publishing surface for v2.
511
+ - Constructor configuration: [English](https://vextjs.github.io/monSQLize/configuration) · [简体中文](https://vextjs.github.io/monSQLize/zh/configuration)
512
+ - Production rollout: [English](https://vextjs.github.io/monSQLize/production-rollout) · [简体中文](https://vextjs.github.io/monSQLize/zh/production-rollout)
513
+ - Production data migration: [English](https://vextjs.github.io/monSQLize/production-data-migration) · [简体中文](https://vextjs.github.io/monSQLize/zh/production-data-migration)
514
+ - Data tasks API: [English](https://vextjs.github.io/monSQLize/data-tasks) · [简体中文](https://vextjs.github.io/monSQLize/zh/data-tasks)
515
+ - Common scenarios: [English](https://vextjs.github.io/monSQLize/recipes) · [简体中文](https://vextjs.github.io/monSQLize/zh/recipes)
516
+ - Example source: [examples index](https://github.com/vextjs/monSQLize/blob/main/examples/README.md)
517
+ - Documentation source: [docs/en](https://github.com/vextjs/monSQLize/tree/main/docs/en) · [docs/zh](https://github.com/vextjs/monSQLize/tree/main/docs/zh)
518
+ - Compatibility checks: [test/compatibility](https://github.com/vextjs/monSQLize/tree/main/test/compatibility)
519
+ - Verification mapping: [test/validation](https://github.com/vextjs/monSQLize/tree/main/test/validation)
520
+
521
+ Historical v1 and v2 assets are useful for tracing old behavior, but they are not the current publishing surface for v3.
478
522
 
479
523
  ## Development
480
524
 
@@ -495,9 +539,9 @@ npm run verify:full
495
539
  npm run release:preflight
496
540
  ```
497
541
 
498
- Release preflight runs linting, type checks, size guards, runtime checks, compatibility checks, refactor guards, production dependency audit, the default test suite, and `npm pack --dry-run`.
542
+ The package self-check command runs linting, documentation/type/size/runtime/compatibility/refactor guards, the default test suite, 90% source coverage, all runnable examples, the MongoDB server matrix, real dataTasks and CLI integration, production dependency audit, a temporary package-install smoke, and a final `npm pack --dry-run`.
499
543
 
500
- `npm run release:publish` runs the preflight gate once and then calls `npm publish --ignore-scripts` so the final publish step does not repeat the full lifecycle gate. Raw `npm publish` is still guarded by `prepublishOnly`.
544
+ `npm run release:publish` runs the package self-check once and then calls `npm publish --ignore-scripts` so the final publish step does not repeat the full lifecycle check. Raw `npm publish` is still guarded by `prepublishOnly`.
501
545
 
502
546
  Optional commands:
503
547
 
@@ -507,82 +551,30 @@ npm run test:examples
507
551
  npm run test:coverage
508
552
  npm run test:audit
509
553
  npm run test:server-matrix
554
+ npm run test:data-tasks:integration
555
+ npm run test:data-task-cli
556
+ npm run test:pack-install
510
557
  npm run test:real-env:private
511
558
  ```
512
559
 
513
- `check:docs-examples` verifies the 97/97 bilingual documentation matrix, runnable-example runner parity, shared-example targets, doc-check targets, and user-facing path text.
514
-
515
- `test:examples`, `test:server-matrix`, and `config.useMemoryServer` use a fixed `mongodb-memory-server` policy: MongoDB `7.0.14` by default, binaries cached under `.cache/mongodb-memory-server/binaries`, and temporary data paths created under `.cache/mongodb-memory-server/db` with forced cleanup for project-managed paths. Stale managed data paths whose owner PID is no longer alive are pruned before new memory-server launches. Override with `MONSQLIZE_MEMORY_MONGO_BINARY_VERSION`, `MONSQLIZE_REPLSET_BINARY_VERSION`, `MONGOMS_DOWNLOAD_DIR`, or `MONSQLIZE_MEMORY_SERVER_DB_DIR` when needed.
560
+ `check:docs-examples` verifies the bilingual documentation matrix, runnable-example runner parity, shared-example targets, doc-check targets, and user-facing path text.
516
561
 
517
- `test:coverage` is the independent 90% coverage governance gate for the published CJS runtime artifact. `test:audit` checks production dependencies against the npm registry. `test:real-env:private` is intentionally opt-in and expects private environment variables. Coverage and private real-environment checks are not part of the default CI or release gate.
562
+ `test:examples`, `test:server-matrix`, and `config.useMemoryServer` use a fixed `mongodb-memory-server` policy: MongoDB `7.0.37` by default, binaries cached under `.cache/mongodb-memory-server/binaries`, and temporary data paths created under `.cache/mongodb-memory-server/db` with forced cleanup for project-managed paths. The release matrix strictly requires MongoDB `7.0.37` and `8.0.26`; a missing binary, failed probe, or failed combination exits nonzero. Stale managed data paths whose owner PID is no longer alive are pruned before new memory-server launches. Override with `MONSQLIZE_MEMORY_MONGO_BINARY_VERSION`, `MONSQLIZE_REPLSET_BINARY_VERSION`, `MONGOMS_DOWNLOAD_DIR`, or `MONSQLIZE_MEMORY_SERVER_DB_DIR` when needed.
518
563
 
519
- ## Release Status
520
-
521
- The current release train targets `v2.0.6`.
522
-
523
- Key release-readiness points:
524
-
525
- - TypeScript rewrite completed for the current runtime and test entry points.
526
- - Package exports are consolidated under `dist/cjs`, `dist/esm`, and `dist/types`.
527
- - npm packages include the runtime bundles and declaration files only; source maps are disabled by default and can be generated locally with `MONSQLIZE_BUILD_SOURCEMAPS=1 npm run build`.
528
- - v1 smooth-upgrade compatibility has been validated against the target workspace consumers.
529
- - `schema-dsl` follows the npm `latest` TypeScript line `schema-dsl@2.0.11`; deprecated `2.3.x` mistake releases are intentionally excluded.
530
- - GitHub Actions publishes to npm from `v*` tags after running `npm run release:preflight`; the publish step skips duplicate lifecycle scripts because the gate already ran in the same job.
564
+ `test:coverage` remains an independently runnable 90% governance command for the published CJS runtime plus source-level gap coverage resolved through sourcemaps, and the single-source release preflight requires it. Public CI runs that same preflight in its release-gate job. `test:audit` checks production dependencies against the npm registry. Only `test:real-env:private` remains opt-in because it expects private environment variables.
531
565
 
532
566
  ## Roadmap
533
567
 
534
- ### v2.0.6
535
-
536
- - Dependency alignment to `schema-dsl@2.0.11`, carrying the shared ESM/CJS custom type registry fix to downstream vext applications.
537
- - NodeNext declaration compatibility for ESM consumers through generated `*.d.mts` mirrors and import-side `types` conditions.
538
- - Restored v1-compatible root option type exports.
539
-
540
- ### v2.0.4
541
-
542
- - Production-safe Model index rollout controls with `autoIndex`, dry-run preflight, conflict reporting, and explicit `ensureIndexes()` / `ensureModelIndexes()` APIs.
543
- - `schema-dsl` updated to `2.0.9`, with transitive `cache-hub` aligned to `2.2.4`.
544
- - User-facing capability and verification documentation wording cleaned up, plus documentation home experience refinements.
545
-
546
- ### v2.0.3
547
-
548
- - v1 compatibility patch for documented `findPage({ cache })` behavior.
549
- - Public transaction and distributed cache invalidator statistics APIs.
550
- - Standalone documentation-site link safety and bilingual docs consistency fixes.
551
- - Release preflight alignment for bilingual docs paths and production dependency audit.
552
-
553
- ### v2.0.2
554
-
555
- - Deterministic dependency metadata patch.
556
- - `ioredis` and `ssh2` are installed with monSQLize by default, so Redis-backed cache/locks and SSH tunnels no longer require a separate dependency install step.
557
-
558
- ### v2.0.1
559
-
560
- - v1 smooth-upgrade compatibility patch for Model actual collection names, scoped pools/databases, automatic-index dedupe, and cache/pool option aliases.
561
- - Documentation and public types aligned with the current runtime behavior.
562
-
563
- ### v2.0.0
564
-
565
- - TypeScript-native runtime and declarations.
566
- - v1 smooth-upgrade compatibility bridge.
567
- - Multi-level cache and function-cache support through `cache-hub`.
568
- - Transactions, business locks, distributed locks, Saga orchestration, connection pools, Change Stream sync, and slow-query logging.
569
- - Model layer with `schema-dsl` validation, relations, populate, hooks, and custom methods.
570
-
571
- ### v2.x
572
-
568
+ - MongoDB remains the stable adapter and the current production runtime.
569
+ - MySQL and PostgreSQL adapters will be introduced as database-native adapters under the same production runtime contract.
570
+ - Adapter status will move from planned to alpha/stable only after runtime support, public types, examples, and verification coverage are present.
571
+ - The project does not currently promise production-ready "one query syntax automatically adapts to every database" behavior.
573
572
  - Query analyzer improvements.
574
573
  - Automatic index suggestions.
575
- - Migration tooling.
574
+ - Additional data-task observability and large-scope operational probes.
576
575
  - GraphQL integration experiments.
577
576
  - More real-environment validation coverage.
578
577
 
579
- ### v3.0+
580
-
581
- - Unified API experiments for MySQL.
582
- - Unified API experiments for PostgreSQL.
583
- - Broader ORM capabilities.
584
- - Cross-database sync middleware.
585
-
586
578
  ## License
587
579
 
588
580
  monSQLize is released under the [Apache License 2.0](./LICENSE).