Skip to content

Commit df120cc

Browse files
committed
feat: use schema-dsl runtime for model validation
1 parent 70c2869 commit df120cc

26 files changed

Lines changed: 715 additions & 207 deletions

README.md

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ The package root exports only the public package contract. Deep imports into his
189189

190190
The Model layer is optional. Use it when you want schema validation, hooks, relations, populate, custom methods, timestamps, soft delete, or optimistic locking.
191191

192-
`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.
192+
`schema-dsl` is installed automatically as a runtime dependency of monSQLize. monSQLize creates an isolated `schema-dsl/runtime` instance for each `MonSQLize` runtime, then compiles Model schema callbacks when a Model is bound to that runtime.
193193

194194
### Manual Model Registration
195195

@@ -251,6 +251,34 @@ const user = await User.insertOne({
251251
});
252252
```
253253

254+
When a service needs runtime-local custom types, messages, locale, or an already-owned schema-dsl runtime, configure `schemaDsl` on the MonSQLize instance:
255+
256+
```js
257+
const { createRuntime } = require('schema-dsl/runtime');
258+
259+
const schemaRuntime = createRuntime({
260+
types: {
261+
tenantId: { type: 'string', pattern: '^tenant_[a-z0-9]+$' }
262+
}
263+
});
264+
265+
Model.define('tenantUsers', {
266+
schema: (dsl) => dsl({
267+
tenantId: 'tenantId!',
268+
email: 'email!'
269+
})
270+
});
271+
272+
const msq = new MonSQLize({
273+
type: 'mongodb',
274+
databaseName: 'mydb',
275+
config: { uri: 'mongodb://localhost:27017' },
276+
schemaDsl: { runtime: schemaRuntime }
277+
});
278+
```
279+
280+
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.
281+
254282
### Automatic Model Loading
255283

256284
```js
@@ -573,7 +601,7 @@ Key release-readiness points:
573601
- Package exports are consolidated under `dist/cjs`, `dist/esm`, and `dist/types`.
574602
- 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`.
575603
- v1 smooth-upgrade compatibility has been validated against the target workspace consumers.
576-
- `schema-dsl` follows the npm `latest` TypeScript line `schema-dsl@2.0.11`; deprecated `2.3.x` mistake releases are intentionally excluded.
604+
- `schema-dsl` follows the npm `latest` TypeScript line `schema-dsl@2.1.1`; deprecated `2.3.x` mistake releases are intentionally excluded.
577605
- 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.
578606

579607
## Roadmap
@@ -593,9 +621,13 @@ Key release-readiness points:
593621
- Validation ledgers now match the current 56 runnable TypeScript documentation examples.
594622
- Model v1 methods factory warnings now route through the runtime logger instead of direct console output.
595623

624+
### v2.0.8
625+
626+
- Model schema validation now uses an isolated `schema-dsl/runtime` instance per MonSQLize runtime, with `schemaDsl` configuration for runtime options, extension registration, runtime injection, and validation disablement.
627+
596628
### v2.0.6
597629

598-
- Dependency alignment to `schema-dsl@2.0.11`, carrying the shared ESM/CJS custom type registry fix to downstream vext applications.
630+
- Dependency alignment carried the shared schema-dsl ESM/CJS custom type registry fix to downstream vext applications.
599631
- NodeNext declaration compatibility for ESM consumers through generated `*.d.mts` mirrors and import-side `types` conditions.
600632
- Restored v1-compatible root option type exports.
601633

changelogs/unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
## Fixed / changed
1616

1717
- Fixed aggregate direct `.toArray()` to honor cache/meta execution paths, extended `find()` ObjectId auto-conversion to comparison operators, forwarded CountQueue abort signals into MongoDB count options, and added a warning when sync idempotency falls back to in-memory storage.
18+
- Upgraded `schema-dsl` to `2.1.1` and moved Model schema compilation/validation onto a MonSQLize runtime-scoped `schema-dsl/runtime` engine. `schemaDsl` now supports runtime options, extension registration, external runtime injection, and validation disablement.
1819
- Added a short-lived read-cache dirty barrier around writes and transaction commits. Cached reads now bypass and avoid refilling query cache while a namespace is being invalidated, reducing stale-cache windows when a process exits between a database write and post-write invalidation.
1920
- Added optional Change Stream sync idempotency gates (`sync.idempotency`) with per-target keys and duplicate stats, so supervised restarts can skip targets already marked as applied before saving the shared resume token.
2021
- Added `writePathPolicy` with default `allow-both` behavior and optional `model-only` namespace enforcement across collection, db, legacy, raw, management, batch, and aggregate `$out` / `$merge` write paths.

docs/en/file-dependency-governance.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ The current root package adopts the **precise version dependency strategy**:
44

55
| Dependencies | Strategy | Reasons |
66
|------|------|------|
7-
| `cache-hub` | Exact version `2.2.4` | The npm latest release has passed compatibility verification; the root direct dependency is fixed to 2.2.4, and `schema-dsl@2.0.11` declares the same transitive dependency version |
8-
| `schema-dsl` | Exact version `2.0.11` | The release chain targets the current non-deprecated TypeScript line; monSQLize relies on schema-dsl for DSL parsing, validation and alias diagnostics, and uses 2.0.11 for type-check and Model schema verification |
7+
| `cache-hub` | Exact version `2.2.4` | The npm latest release has passed compatibility verification; the root direct dependency is fixed to 2.2.4, and `schema-dsl@2.1.1` declares the same transitive dependency version |
8+
| `schema-dsl` | Exact version `2.1.1` | The release chain targets the current non-deprecated TypeScript line; monSQLize relies on schema-dsl runtime isolation for Model schema parsing, validation, custom types, and messages, and uses 2.1.1 for type-check and Model schema verification |
99

10-
> `schema-dsl@2.0.11` is the intended latest for this release chain; the historical `2.3.x` line exists on npm but has been marked as misreleased/deprecated and must not be followed by upgrades.
10+
> `schema-dsl@2.1.1` is the intended latest for this release chain; the historical `2.3.x` line exists on npm but has been marked as misreleased/deprecated and must not be followed by upgrades.
1111
1212
## Current Risk
1313

@@ -20,8 +20,8 @@ The current root package adopts the **precise version dependency strategy**:
2020

2121
## Development status
2222

23-
- The root direct `cache-hub` dependency is fixed to `2.2.4`; `schema-dsl@2.0.11` also declares `cache-hub@2.2.4`, so no additional override is needed.
24-
- `schema-dsl` is fixed to `2.0.11`.
23+
- The root direct `cache-hub` dependency is fixed to `2.2.4`; `schema-dsl@2.1.1` also declares `cache-hub@2.2.4`, so no additional override is needed.
24+
- `schema-dsl` is fixed to `2.1.1`.
2525
- Local sibling `../schema-dsl` is only used for debugging the upstream library itself and is no longer a prerequisite for monSQLize root package installation.
2626

2727

@@ -36,21 +36,21 @@ npm run release:preflight
3636

3737
## schema-dsl 2.x upgrade verification
3838

39-
The dependency governance baseline has upgraded and fixed `schema-dsl` from the historical `^1.2.5` to `2.0.11`. The verification standard is as follows:
39+
The dependency governance baseline has upgraded and fixed `schema-dsl` from the historical `^1.2.5` to `2.1.1`. The verification standard is as follows:
4040

41-
1. The upstream released the **non-deprecated** 2.x latest version on npm: `2.0.11`.
42-
2. `npm install schema-dsl@2.0.11 --save-exact` followed by `npm run type-check`.
41+
1. The upstream released the **non-deprecated** 2.x latest version on npm: `2.1.1`.
42+
2. `npm install schema-dsl@2.1.1 --save-exact` followed by `npm run type-check`.
4343
3. All model-related unit tests/integration tests passed (covered with `npm run test:unit` and `npm run test:integration`).
4444
4. `npm run test:examples` all passed.
4545
5. `npm run release:preflight` still needs to be used as the final access control before release.
46-
6. This file, Profile, CHANGELOG, and lockfile must be synchronized to `2.0.11`.
46+
6. This file, Profile, CHANGELOG, and lockfile must be synchronized to `2.1.1`.
4747

4848
## cache-hub 2.2.4 upgrade verification
4949

5050
The dependency governance baseline has upgraded and fixed `cache-hub` from `1.0.0` to `2.2.4`. The verification standard is as follows:
5151

5252
1. The upstream npm `latest` is `2.2.4`, and the Node.js engine requirement remains `>=18`, matching the current monSQLize baseline.
53-
2. The root direct dependency resolves to `2.2.4`; `schema-dsl@2.0.11` also declares `cache-hub@2.2.4`.
53+
2. The root direct dependency resolves to `2.2.4`; `schema-dsl@2.1.1` also declares `cache-hub@2.2.4`.
5454
3. `npm run type-check`, targeted cache / function-cache tests, website build, and memory probe must pass.
5555
4. This file, Profile, CHANGELOG, package manifest, and lockfile must be synchronized with the root direct dependency `2.2.4` baseline.
5656

docs/en/model.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,50 @@ if (user.checkPassword('secret123')) {
5656

5757
---
5858

59+
## schema-dsl runtime
60+
61+
Model schema callbacks receive the `s` namespace from the MonSQLize instance's isolated `schema-dsl/runtime`. `Model.define()` stores the definition only; schema compilation and validation happen when `msq.model(name)` creates a runtime-bound Model instance.
62+
63+
For the default path, no application import from `schema-dsl` is required:
64+
65+
```javascript
66+
Model.define('users', {
67+
schema: (dsl) => dsl({
68+
email: 'email!',
69+
name: dsl.string().min(1).max(64).require()
70+
})
71+
});
72+
73+
const msq = new MonSQLize({
74+
type: 'mongodb',
75+
databaseName: 'app',
76+
config: { uri: 'mongodb://127.0.0.1:27017' }
77+
});
78+
```
79+
80+
When the application needs custom runtime-local types, messages, locale, or shared schema-dsl state, create or inject a `schema-dsl/runtime` instance through `schemaDsl`:
81+
82+
```javascript
83+
import { createRuntime } from 'schema-dsl/runtime';
84+
85+
const schemaRuntime = createRuntime({
86+
types: {
87+
tenantId: { type: 'string', pattern: '^tenant_[a-z0-9]+$' }
88+
}
89+
});
90+
91+
const msq = new MonSQLize({
92+
type: 'mongodb',
93+
databaseName: 'app',
94+
config: { uri: 'mongodb://127.0.0.1:27017' },
95+
schemaDsl: { runtime: schemaRuntime }
96+
});
97+
```
98+
99+
`schemaDsl` also accepts `{ options, extensions }` when monSQLize should own the runtime, and `schemaDsl: false` when Model schema-dsl validation must be disabled for a migration or test boundary.
100+
101+
---
102+
59103
## API Reference
60104

61105

docs/en/recipes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ const User = msq.model('users');
145145
await User.insertOne({ name: 'Ada', email: 'ada@example.com' });
146146
```
147147

148-
`schema-dsl` is installed by default with `monsqlize`. Only when the application code directly imports `schema-dsl`, it needs to be declared in the application's own dependencies.
148+
`schema-dsl` is installed by default with `monsqlize`. Model schema callbacks use the MonSQLize instance's isolated `schema-dsl/runtime`; if application code also needs the same custom types or messages, create a `schema-dsl/runtime` instance and pass it through `schemaDsl`.
149149

150150
## Troubleshoot according to error code
151151

docs/zh/file-dependency-governance.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
| 依赖 | 策略 | 原因 |
66
|------|------|------|
7-
| `cache-hub` | 精确版本 `2.2.4` | 上游 npm latest 已发布稳定版本并通过兼容验证;根包 direct dependency 固定到 2.2.4,`schema-dsl@2.0.11` 声明的传递依赖同为 2.2.4 |
8-
| `schema-dsl` | 精确版本 `2.0.11` | 本次发布链路目标为当前非 deprecated 的 TypeScript 正式线;monSQLize 依赖 schema-dsl 统一负责 DSL 解析、验证与 alias diagnostics,并以 2.0.11 执行 type-check 与 Model schema 验证 |
7+
| `cache-hub` | 精确版本 `2.2.4` | 上游 npm latest 已发布稳定版本并通过兼容验证;根包 direct dependency 固定到 2.2.4,`schema-dsl@2.1.1` 声明的传递依赖同为 2.2.4 |
8+
| `schema-dsl` | 精确版本 `2.1.1` | 本次发布链路目标为当前非 deprecated 的 TypeScript 正式线;monSQLize 依赖 schema-dsl runtime 隔离能力负责 Model schema 解析、验证、自定义类型和消息,并以 2.1.1 执行 type-check 与 Model schema 验证 |
99

10-
> `schema-dsl@2.0.11` 是本次发布链路的预期 latest;npm 上历史 `2.3.x` 已标记为误发布 / deprecated,不得跟随升级。
10+
> `schema-dsl@2.1.1` 是本次发布链路的预期 latest;npm 上历史 `2.3.x` 已标记为误发布 / deprecated,不得跟随升级。
1111
1212
## 当前风险
1313

@@ -19,8 +19,8 @@
1919

2020
### 开发态
2121

22-
- 根包 direct `cache-hub` 固定为 `2.2.4``schema-dsl@2.0.11` 声明的 `cache-hub` 版本同为 `2.2.4`,不需要额外 override。
23-
- `schema-dsl` 固定为 `2.0.11`
22+
- 根包 direct `cache-hub` 固定为 `2.2.4``schema-dsl@2.1.1` 声明的 `cache-hub` 版本同为 `2.2.4`,不需要额外 override。
23+
- `schema-dsl` 固定为 `2.1.1`
2424
- 本地 sibling `../schema-dsl` 仅用于上游库自身调试,不再作为 monSQLize 根包安装前提。
2525

2626
### 发布态
@@ -34,21 +34,21 @@ npm run release:preflight
3434

3535
## schema-dsl 2.x 升级验证
3636

37-
依赖治理基线已将 `schema-dsl` 从历史 `^1.2.5` 升级并固定到 `2.0.11`,验证标准如下:
37+
依赖治理基线已将 `schema-dsl` 从历史 `^1.2.5` 升级并固定到 `2.1.1`,验证标准如下:
3838

39-
1. 上游在 npm 发布了**非 deprecated** 的 2.x latest 版本:`2.0.11`
40-
2. `npm install schema-dsl@2.0.11 --save-exact` 后通过 `npm run type-check`
39+
1. 上游在 npm 发布了**非 deprecated** 的 2.x latest 版本:`2.1.1`
40+
2. `npm install schema-dsl@2.1.1 --save-exact` 后通过 `npm run type-check`
4141
3. model 相关单测 / 集成测试全通过(随 `npm run test:unit``npm run test:integration` 覆盖)。
4242
4. `npm run test:examples` 全通过。
4343
5. 发布前仍需以 `npm run release:preflight` 作为最终门禁。
44-
6. 本文件、Profile、CHANGELOG 与 lockfile 必须同步到 `2.0.11`
44+
6. 本文件、Profile、CHANGELOG 与 lockfile 必须同步到 `2.1.1`
4545

4646
## cache-hub 2.2.4 升级验证
4747

4848
依赖治理基线已将 `cache-hub``1.0.0` 升级并固定到 `2.2.4`,验证标准如下:
4949

5050
1. 上游 npm `latest``2.2.4`,Node.js 引擎要求仍为 `>=18`,与 monSQLize 当前基线一致。
51-
2. 根包 direct dependency 解析到 `2.2.4``schema-dsl@2.0.11` 也声明 `cache-hub@2.2.4`
51+
2. 根包 direct dependency 解析到 `2.2.4``schema-dsl@2.1.1` 也声明 `cache-hub@2.2.4`
5252
3. `npm run type-check`、缓存 / function-cache 定向测试、文档站构建与内存探针必须通过。
5353
4. 本文件、Profile、CHANGELOG、package manifest 与 lockfile 必须同步 root direct dependency 的 `2.2.4` 口径。
5454

docs/zh/model.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,50 @@ if (user.checkPassword('secret123')) {
5656

5757
---
5858

59+
## schema-dsl runtime
60+
61+
Model 的 `schema` 回调会收到当前 MonSQLize 实例隔离的 `schema-dsl/runtime``s` 命名空间。`Model.define()` 只保存定义;实际 schema 编译与验证发生在 `msq.model(name)` 创建绑定到运行时的 Model 实例时。
62+
63+
默认路径下,应用代码不需要直接导入 `schema-dsl`
64+
65+
```javascript
66+
Model.define('users', {
67+
schema: (dsl) => dsl({
68+
email: 'email!',
69+
name: dsl.string().min(1).max(64).require()
70+
})
71+
});
72+
73+
const msq = new MonSQLize({
74+
type: 'mongodb',
75+
databaseName: 'app',
76+
config: { uri: 'mongodb://127.0.0.1:27017' }
77+
});
78+
```
79+
80+
如果应用需要运行时本地的自定义类型、消息、locale,或要与 monSQLize 共享同一个 schema-dsl 状态,可以通过 `schemaDsl` 注入 `schema-dsl/runtime` 实例:
81+
82+
```javascript
83+
import { createRuntime } from 'schema-dsl/runtime';
84+
85+
const schemaRuntime = createRuntime({
86+
types: {
87+
tenantId: { type: 'string', pattern: '^tenant_[a-z0-9]+$' }
88+
}
89+
});
90+
91+
const msq = new MonSQLize({
92+
type: 'mongodb',
93+
databaseName: 'app',
94+
config: { uri: 'mongodb://127.0.0.1:27017' },
95+
schemaDsl: { runtime: schemaRuntime }
96+
});
97+
```
98+
99+
当 monSQLize 自己持有 runtime 时,`schemaDsl` 也可以传 `{ options, extensions }`;迁移或测试边界需要跳过 Model schema-dsl 验证时,可以设置 `schemaDsl: false`
100+
101+
---
102+
59103
## API 参考
60104

61105
### Model.define(collectionName, definition)

docs/zh/recipes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ const User = msq.model('users');
145145
await User.insertOne({ name: 'Ada', email: 'ada@example.com' });
146146
```
147147

148-
`schema-dsl` 已随 `monsqlize` 默认安装。只有应用代码直接导入 `schema-dsl` 时,才需要在应用自己的依赖里声明它
148+
`schema-dsl` 已随 `monsqlize` 默认安装。Model 的 schema 回调使用当前 MonSQLize 实例隔离的 `schema-dsl/runtime`;如果应用代码也需要同一组自定义类型或消息,可以创建 `schema-dsl/runtime` 实例并通过 `schemaDsl` 传入
149149

150150
## 按错误码排障
151151

examples/docs/sync-target-failure.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ async function main() {
7676
'sync manager did not record target failure in time',
7777
);
7878

79+
await runtime.startSync();
7980
await events.insertOne({ type: 'sync.recovered', payload: { step: 2 } });
8081

8182
const recoveredStats = await waitFor(

0 commit comments

Comments
 (0)