@zerotal/orm 1.5.1 → 1.6.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/CHANGELOG.md +18 -0
- package/package.json +3 -3
- package/src/db/NPlusOneDetector.ts +3 -3
- package/src/model/State.ts +2 -1
- package/src/schema/autoMigrate.ts +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,24 @@ follows the Zerotal monorepo's unified versioning.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [1.6.0] — 2026-08-15
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Auto-`synchronize` was never hard-off in production.** The guard compared
|
|
16
|
+
`APP_ENV` against `"production"`, but `setAppEnv()` replaces that with the runtime
|
|
17
|
+
mode before the app boots — so it read `"web"` and never fired. The only thing standing
|
|
18
|
+
between a production database and boot-time schema sync was the config default in
|
|
19
|
+
`config/database.ts`. It reads `deployEnv()` now, and covers `staging` too.
|
|
20
|
+
|
|
21
|
+
- **`forceState()` did not refuse to run in production.** Its throw exists so a
|
|
22
|
+
state-machine escape hatch cannot be used on live data; the same `APP_ENV` comparison
|
|
23
|
+
meant it never triggered.
|
|
24
|
+
|
|
25
|
+
- **The N+1 detector's own environment gate never matched**, so the detector returned early
|
|
26
|
+
even in development. (The provider-level gate that installs it was fixed in 1.5.0; this is
|
|
27
|
+
the second gate inside the detector itself.)
|
|
28
|
+
|
|
11
29
|
## [1.5.0] — 2026-08-15
|
|
12
30
|
|
|
13
31
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerotal/orm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"maturity": "stable",
|
|
6
6
|
"private": false,
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"typecheck": "tsc --noEmit"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@zerotal/core": "1.
|
|
34
|
-
"@zerotal/validator": "1.
|
|
33
|
+
"@zerotal/core": "1.6.0",
|
|
34
|
+
"@zerotal/validator": "1.6.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"typescript": "^5.8.0"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ZerotalError, FrameworkEvents } from "@zerotal/core";
|
|
2
|
+
import { isProdLike, deployEnv } from "@zerotal/core";
|
|
2
3
|
import { NPlusOneDetected } from "../events.ts";
|
|
3
4
|
|
|
4
5
|
// ── N+1 Query Detector ────────────────────────────────────────────────────────
|
|
@@ -180,13 +181,12 @@ export function trackQuery(
|
|
|
180
181
|
|
|
181
182
|
// Honour explicit opt-in or auto-enable in local/development only
|
|
182
183
|
if (!_forced) {
|
|
183
|
-
const env = (
|
|
184
|
+
const env = deployEnv();
|
|
184
185
|
if (env !== "local" && env !== "development" && env !== "dev") return;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
// Production always off
|
|
188
|
-
|
|
189
|
-
if (env === "production" || env === "prod") return;
|
|
189
|
+
if (isProdLike(deployEnv())) return;
|
|
190
190
|
|
|
191
191
|
// Only watch SELECTs — the N+1 problem is purely about reads
|
|
192
192
|
if (!fingerprint.trimStart().toLowerCase().startsWith("select")) return;
|
package/src/model/State.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
// @column() status!: keyof typeof States;
|
|
20
20
|
// }
|
|
21
21
|
|
|
22
|
+
import { isProdLike, deployEnv } from "@zerotal/core";
|
|
22
23
|
import { StateError } from "../errors/index.ts";
|
|
23
24
|
import { currentOrmContext } from "./OrmContext.ts";
|
|
24
25
|
import type { Constructor } from "./mixins.ts";
|
|
@@ -278,7 +279,7 @@ export function State<TBase extends Constructor>(Base: TBase) {
|
|
|
278
279
|
* @throws {Error} when called with `APP_ENV=production`.
|
|
279
280
|
*/
|
|
280
281
|
async forceState(state: string): Promise<this> {
|
|
281
|
-
if (
|
|
282
|
+
if (isProdLike(deployEnv())) {
|
|
282
283
|
throw new Error("forceState() cannot be called in production (APP_ENV=production).");
|
|
283
284
|
}
|
|
284
285
|
const field = (this.constructor as unknown as StateModelClass).stateField;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ConcernDescriptor } from "@zerotal/core";
|
|
2
|
+
import { isProdLike, deployEnv } from "@zerotal/core";
|
|
2
3
|
import type { ConfigManager } from "@zerotal/core/config";
|
|
3
4
|
import { ModelInspector, columnDbName } from "./ModelInspector.ts";
|
|
4
5
|
import { SchemaDiffer, type DiffResult } from "./SchemaDiffer.ts";
|
|
@@ -147,9 +148,12 @@ export const autoMigrateConcern: ConcernDescriptor = {
|
|
|
147
148
|
name: "auto-migrate",
|
|
148
149
|
order: 100,
|
|
149
150
|
async run(ctx) {
|
|
150
|
-
// Hard-off
|
|
151
|
-
//
|
|
152
|
-
|
|
151
|
+
// Hard-off on any deployed environment. Both `ctx.env` AND `APP_ENV` hold the
|
|
152
|
+
// runtime mode by now — the comment that used to sit here claimed APP_ENV still
|
|
153
|
+
// carried the deployment name, which is exactly the mistake. This guard never
|
|
154
|
+
// fired under `zt serve`, so the only thing between a production database and
|
|
155
|
+
// boot-time schema sync was the config default.
|
|
156
|
+
if (isProdLike(deployEnv())) return;
|
|
153
157
|
const config = ctx.resolve<ConfigManager>("config");
|
|
154
158
|
const { enabled, disruptive } = resolveSyncOptions(config?.get("database.synchronize"));
|
|
155
159
|
if (!enabled) return;
|