cabloy 5.1.219 → 5.1.221
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/.cabloy-version +1 -1
- package/.github/workflows/agent-governance.yml +2 -2
- package/.github/workflows/create-cabloy.yml +3 -3
- package/.github/workflows/docs-pages.yml +2 -2
- package/.github/workflows/playwright-e2e.yml +4 -4
- package/.github/workflows/vona-cov-pg.yml +2 -2
- package/.github/workflows/vona-test-crud.yml +2 -2
- package/.github/workflows/vona-test-mysql.yml +2 -2
- package/.github/workflows/vona-test-pg.yml +2 -2
- package/.github/workflows/vona-test-sqlite3.yml +2 -2
- package/.github/workflows/vona-tsc.yml +2 -2
- package/.github/workflows/zova-ui.yml +2 -2
- package/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/package.json +4 -3
- package/repo-docs/frontend/openapi-sdk-guide.md +2 -0
- package/repo-docs/fullstack/quickstart.md +3 -3
- package/repo-docs/reference/repo-scripts.md +16 -0
- package/scripts/generateOpenapiIsolated.test.ts +25 -0
- package/scripts/generateOpenapiIsolated.ts +46 -12
- package/scripts/runIsolatedTest.test.ts +165 -45
- package/scripts/runIsolatedTest.ts +111 -24
- package/scripts/strictGenerationDiagnostics.test.ts +1009 -0
- package/scripts/strictGenerationDiagnostics.ts +61 -0
- package/scripts/strictGenerationStartup.test.ts +212 -0
- package/vona/package.original.json +3 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.dev.ts +14 -4
- package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/generateEntryFiles.ts +6 -1
- package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/generateVonaMeta.ts +2 -10
- package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/validateGenerationPaths.ts +27 -0
- package/vona/packages-cli/cli-set-api/test/binDevLifecycle.test.ts +1 -1
- package/vona/packages-cli/cli-set-api/test/strictGenerationPrivacy.test.ts +439 -0
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-core/src/lib/bean/beanBase.ts +4 -0
- package/vona/packages-vona/vona-core/src/lib/core/asyncLocalStorage.ts +84 -12
- package/vona/packages-vona/vona-core/src/lib/core/index.ts +14 -0
- package/vona/packages-vona/vona-core/src/lib/core/logger/appLogger.ts +19 -3
- package/vona/packages-vona/vona-core/src/lib/core/logger/diagnosticLogger.test.ts +346 -0
- package/vona/packages-vona/vona-core/src/lib/core/logger/diagnosticLogger.ts +138 -0
- package/vona/packages-vona/vona-core/src/lib/core/logger/index.ts +1 -0
- package/vona/packages-vona/vona-core/src/lib/core/logger/utils.ts +25 -5
- package/vona/packages-vona/vona-core/src/lib/core/requestBoundary.ts +89 -0
- package/vona/packages-vona/vona-core/src/lib/core/testFreshness.test.ts +379 -0
- package/vona/packages-vona/vona-core/src/lib/core/testFreshness.ts +232 -0
- package/vona/packages-vona/vona-core/src/lib/core/testStrictMode.ts +9 -0
- package/vona/packages-vona/vona-core/src/lib/framework/start.test.ts +4 -3
- package/vona/packages-vona/vona-core/src/lib/framework/start.ts +2 -0
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +691 -356
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-executor/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-executor/src/bean/bean.executor.ts +111 -60
- package/vona/src/suite-vendor/a-vona/modules/a-executor/src/service/executor.ts +6 -6
- package/vona/src/suite-vendor/a-vona/modules/a-executor/src/types/executor.ts +13 -1
- package/vona/src/suite-vendor/a-vona/modules/a-jwt/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-jwt/src/lib/jwtClientLogging.test.ts +182 -0
- package/vona/src/suite-vendor/a-vona/modules/a-jwt/src/service/jwtClient.ts +2 -8
- package/vona/src/suite-vendor/a-vona/modules/a-logger/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-logger/src/bean/aopMethod.log.ts +4 -1
- package/vona/src/suite-vendor/a-vona/modules/a-logger/src/bean/bean.logger.ts +9 -0
- package/vona/src/suite-vendor/a-vona/modules/a-logger/src/bean/middlewareSystem.httpLog.ts +27 -14
- package/vona/src/suite-vendor/a-vona/modules/a-logger/src/lib/redactHttpLog.test.ts +207 -0
- package/vona/src/suite-vendor/a-vona/modules/a-logger/src/lib/redactHttpLog.ts +30 -0
- package/vona/src/suite-vendor/a-vona/modules/a-logger/test/middlewareSystem.httpLog.test.ts +33 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/index.ts +11 -0
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/lib/protectedSqliteRegistry.ts +356 -0
- package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-startup/src/service/startup.ts +6 -0
- package/vona/src/suite-vendor/a-vona/modules/a-startup/test/devSeed.test.ts +2 -2
- package/vona/src/suite-vendor/a-vona/modules/a-telemetry/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/bean/bean.telemetry.ts +8 -1
- package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/bean/middlewareSystem.trace.ts +9 -14
- package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/lib/spanDiagnostics.ts +70 -0
- package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/service/telemetry.ts +37 -23
- package/vona/src/suite-vendor/a-vona/modules/a-version/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-version/src/service/database.ts +31 -4
- package/vona/src/suite-vendor/a-vona/package.json +2 -2
- package/zova/package.original.json +3 -2
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.bin.buildRest.ts +11 -101
- package/zova/packages-cli/cli-set-front/src/lib/common/restDependencies.ts +78 -0
- package/zova/packages-cli/cli-set-front/src/lib/common/restDependencyVersions.ts +252 -0
- package/zova/packages-cli/cli-set-front/test/restDependencies.test.ts +568 -0
- package/zova/pnpm-lock.yaml +442 -564
package/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.221
|
|
@@ -17,9 +17,9 @@ jobs:
|
|
|
17
17
|
PNPM_CONFIG_MINIMUM_RELEASE_AGE: 0
|
|
18
18
|
steps:
|
|
19
19
|
- uses: actions/checkout@v6
|
|
20
|
-
- uses: pnpm/action-setup@
|
|
20
|
+
- uses: pnpm/action-setup@v6
|
|
21
21
|
with:
|
|
22
|
-
version:
|
|
22
|
+
version: '12.14.0'
|
|
23
23
|
- uses: actions/setup-node@v6
|
|
24
24
|
with:
|
|
25
25
|
node-version: 24
|
|
@@ -35,9 +35,9 @@ jobs:
|
|
|
35
35
|
- uses: actions/setup-node@v6
|
|
36
36
|
with:
|
|
37
37
|
node-version: 24
|
|
38
|
-
- uses: pnpm/action-setup@
|
|
38
|
+
- uses: pnpm/action-setup@v6
|
|
39
39
|
with:
|
|
40
|
-
version:
|
|
40
|
+
version: '12.14.0'
|
|
41
41
|
- name: start Redis on macOS
|
|
42
42
|
if: runner.os == 'macOS'
|
|
43
43
|
shell: bash
|
|
@@ -97,7 +97,7 @@ jobs:
|
|
|
97
97
|
if (Test-Path $log) { Get-Content $log }
|
|
98
98
|
throw 'Redis did not become ready'
|
|
99
99
|
- name: create project
|
|
100
|
-
run: npm create cabloy cabloy-app
|
|
100
|
+
run: npm create cabloy@latest cabloy-app
|
|
101
101
|
- name: verify project initialization
|
|
102
102
|
working-directory: cabloy-app
|
|
103
103
|
run: >-
|
|
@@ -29,9 +29,9 @@ jobs:
|
|
|
29
29
|
PNPM_CONFIG_MINIMUM_RELEASE_AGE: 0
|
|
30
30
|
steps:
|
|
31
31
|
- uses: actions/checkout@v6
|
|
32
|
-
- uses: pnpm/action-setup@
|
|
32
|
+
- uses: pnpm/action-setup@v6
|
|
33
33
|
with:
|
|
34
|
-
version:
|
|
34
|
+
version: '12.14.0'
|
|
35
35
|
- uses: actions/setup-node@v6
|
|
36
36
|
with:
|
|
37
37
|
node-version: 24
|
|
@@ -28,9 +28,9 @@ jobs:
|
|
|
28
28
|
- uses: actions/setup-node@v6
|
|
29
29
|
with:
|
|
30
30
|
node-version: 24
|
|
31
|
-
- uses: pnpm/action-setup@
|
|
31
|
+
- uses: pnpm/action-setup@v6
|
|
32
32
|
with:
|
|
33
|
-
version:
|
|
33
|
+
version: '12.14.0'
|
|
34
34
|
- name: start Redis on macOS
|
|
35
35
|
if: runner.os == 'macOS'
|
|
36
36
|
shell: bash
|
|
@@ -136,9 +136,9 @@ jobs:
|
|
|
136
136
|
- uses: actions/setup-node@v6
|
|
137
137
|
with:
|
|
138
138
|
node-version: 24
|
|
139
|
-
- uses: pnpm/action-setup@
|
|
139
|
+
- uses: pnpm/action-setup@v6
|
|
140
140
|
with:
|
|
141
|
-
version:
|
|
141
|
+
version: '12.14.0'
|
|
142
142
|
- name: start Redis on macOS
|
|
143
143
|
if: runner.os == 'macOS'
|
|
144
144
|
shell: bash
|
|
@@ -29,9 +29,9 @@ jobs:
|
|
|
29
29
|
- uses: actions/setup-node@v6
|
|
30
30
|
with:
|
|
31
31
|
node-version: ${{ matrix.node-version }}
|
|
32
|
-
- uses: pnpm/action-setup@
|
|
32
|
+
- uses: pnpm/action-setup@v6
|
|
33
33
|
with:
|
|
34
|
-
version:
|
|
34
|
+
version: '12.14.0'
|
|
35
35
|
- name: init
|
|
36
36
|
run: npm run init
|
|
37
37
|
- name: cov
|
|
@@ -22,9 +22,9 @@ jobs:
|
|
|
22
22
|
- uses: actions/setup-node@v6
|
|
23
23
|
with:
|
|
24
24
|
node-version: ${{ matrix.node-version }}
|
|
25
|
-
- uses: pnpm/action-setup@
|
|
25
|
+
- uses: pnpm/action-setup@v6
|
|
26
26
|
with:
|
|
27
|
-
version:
|
|
27
|
+
version: '12.14.0'
|
|
28
28
|
- name: init
|
|
29
29
|
run: npm run init
|
|
30
30
|
- run: npm run vona :create:module demo-student2 -- --suite --ci
|
|
@@ -29,9 +29,9 @@ jobs:
|
|
|
29
29
|
- uses: actions/setup-node@v6
|
|
30
30
|
with:
|
|
31
31
|
node-version: ${{ matrix.node-version }}
|
|
32
|
-
- uses: pnpm/action-setup@
|
|
32
|
+
- uses: pnpm/action-setup@v6
|
|
33
33
|
with:
|
|
34
|
-
version:
|
|
34
|
+
version: '12.14.0'
|
|
35
35
|
- name: init
|
|
36
36
|
run: npm run init
|
|
37
37
|
- name: run Commerce lifecycle gate
|
|
@@ -29,9 +29,9 @@ jobs:
|
|
|
29
29
|
- uses: actions/setup-node@v6
|
|
30
30
|
with:
|
|
31
31
|
node-version: ${{ matrix.node-version }}
|
|
32
|
-
- uses: pnpm/action-setup@
|
|
32
|
+
- uses: pnpm/action-setup@v6
|
|
33
33
|
with:
|
|
34
|
-
version:
|
|
34
|
+
version: '12.14.0'
|
|
35
35
|
- name: init
|
|
36
36
|
run: npm run init
|
|
37
37
|
- name: run A-Pay focused gate
|
|
@@ -29,9 +29,9 @@ jobs:
|
|
|
29
29
|
- uses: actions/setup-node@v6
|
|
30
30
|
with:
|
|
31
31
|
node-version: ${{ matrix.node-version }}
|
|
32
|
-
- uses: pnpm/action-setup@
|
|
32
|
+
- uses: pnpm/action-setup@v6
|
|
33
33
|
with:
|
|
34
|
-
version:
|
|
34
|
+
version: '12.14.0'
|
|
35
35
|
- name: start Redis on macOS
|
|
36
36
|
if: runner.os == 'macOS'
|
|
37
37
|
shell: bash
|
|
@@ -17,9 +17,9 @@ jobs:
|
|
|
17
17
|
- uses: actions/setup-node@v6
|
|
18
18
|
with:
|
|
19
19
|
node-version: ${{ matrix.node-version }}
|
|
20
|
-
- uses: pnpm/action-setup@
|
|
20
|
+
- uses: pnpm/action-setup@v6
|
|
21
21
|
with:
|
|
22
|
-
version:
|
|
22
|
+
version: '12.14.0'
|
|
23
23
|
- name: init
|
|
24
24
|
run: npm run init
|
|
25
25
|
- name: tsc
|
|
@@ -17,9 +17,9 @@ jobs:
|
|
|
17
17
|
- uses: actions/setup-node@v6
|
|
18
18
|
with:
|
|
19
19
|
node-version: ${{ matrix.node-version }}
|
|
20
|
-
- uses: pnpm/action-setup@
|
|
20
|
+
- uses: pnpm/action-setup@v6
|
|
21
21
|
with:
|
|
22
|
-
version:
|
|
22
|
+
version: '12.14.0'
|
|
23
23
|
- name: init
|
|
24
24
|
run: npm run init
|
|
25
25
|
- name: suite
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.221
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Incorporate updates from MCP.
|
|
8
|
+
- Incorporate updates from the specification.
|
|
9
|
+
|
|
10
|
+
### Improvements
|
|
11
|
+
|
|
12
|
+
- Update pnpm.
|
|
13
|
+
|
|
14
|
+
## 5.1.220
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- Add request boundary lifecycle support and diagnostic suppression.
|
|
19
|
+
|
|
20
|
+
### Improvements
|
|
21
|
+
|
|
22
|
+
- Speed up REST declaration builds with oxc.
|
|
23
|
+
- Enhance the REST build process.
|
|
24
|
+
- Update setup documentation to use `npm create cabloy@latest`.
|
|
25
|
+
|
|
3
26
|
## 5.1.219
|
|
4
27
|
|
|
5
28
|
### Improvements
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Learn more about [Vona + Zova Integration](https://cabloy.com/fullstack/vona-zov
|
|
|
27
27
|
Create a new Cabloy Basic project:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npm create cabloy
|
|
30
|
+
npm create cabloy@latest
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
For Cabloy Start, clone the [Cabloy Start repository](https://github.com/cabloy/cabloy-start) and run `npm run init` from its root. See the [Fullstack Quickstart](https://cabloy.com/fullstack/quickstart) for prerequisites and development commands.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cabloy",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.221",
|
|
4
4
|
"gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
|
|
5
5
|
"description": "A Node.js fullstack framework",
|
|
6
6
|
"keywords": [
|
|
@@ -106,7 +106,8 @@
|
|
|
106
106
|
"typescript": "^5.9.3"
|
|
107
107
|
},
|
|
108
108
|
"engines": {
|
|
109
|
-
"node": ">=24.4.0"
|
|
109
|
+
"node": ">=24.4.0",
|
|
110
|
+
"pnpm": ">=11.5.2"
|
|
110
111
|
},
|
|
111
|
-
"packageManager": "pnpm@
|
|
112
|
+
"packageManager": "pnpm@12.14.0"
|
|
112
113
|
}
|
|
@@ -73,6 +73,8 @@ npm run contract:generate:isolated -- training-student
|
|
|
73
73
|
|
|
74
74
|
The isolated command uses the same generator and preserves module ownership validation, but manages a disposable service, claim, and test resources without starting Playwright. Generated files under `zova/src/**` are shared workspace output, not run-owned temporary files; serialize concurrent SDK generation and do not expect automatic rollback.
|
|
75
75
|
|
|
76
|
+
For an explicitly authorized run that must skip historical-claim reaping, use the standalone `--skip-expired-claim-reaping` flag. In this strict lane, generated environment source contains selected keys rather than resolved values, configuration reaches the bootstrap child in memory, service/generator stdout and stderr are discarded, and framework file logging is prevented before transport construction. Failures remain failures with categorical diagnostics and retained current-run claims/resources; there is no automatic retry or fallback to development Swagger. This is not a network or arbitrary-filesystem sandbox, and it does not authorize Provider operations or prove custom seed/logging behavior. See [Strict isolated generation](/reference/repo-scripts#test-isolation-and-development-data) for resource and diagnostic boundaries.
|
|
77
|
+
|
|
76
78
|
The project-level source resolver accepts `OPENAPI_SOURCE_URL` as a complete OpenAPI document URL. It takes precedence over `API_BASE_URL` for generation only and does not change runtime `OPENAPI_BASE_URL_*` request targets:
|
|
77
79
|
|
|
78
80
|
```bash
|
|
@@ -21,7 +21,7 @@ Before creating a new Cabloy project, make sure your environment has:
|
|
|
21
21
|
## 2. Create a new project
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npm create cabloy
|
|
24
|
+
npm create cabloy@latest
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
The generated project includes `repo-agent-governance/` plus committed adapters for Claude Code, Codex, and Cursor. This path creates a Cabloy Basic project baseline. Open it in a supported coding agent and start with the project-specific guidance; regenerate adapters from the canonical governance source rather than editing generated files directly.
|
|
@@ -52,13 +52,13 @@ npm create cabloy
|
|
|
52
52
|
#### Windows Command Prompt
|
|
53
53
|
|
|
54
54
|
```cmd
|
|
55
|
-
set pnpm_config_minimum_release_age=0 && npm create cabloy
|
|
55
|
+
set pnpm_config_minimum_release_age=0 && npm create cabloy@latest
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
#### macOS / Linux
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
pnpm_config_minimum_release_age=0 npm create cabloy
|
|
61
|
+
pnpm_config_minimum_release_age=0 npm create cabloy@latest
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
## 3. Start Vona integrated SSR
|
|
@@ -82,6 +82,22 @@ A process-list match or a free port alone is not proof of either a conflict or s
|
|
|
82
82
|
|
|
83
83
|
`npm run contract:generate:isolated -- <module-name>` starts a fresh test-mode Vona service on a run-owned loopback port, verifies its signed readiness response, fetches the Swagger document, and invokes the existing Zova OpenAPI generator without Playwright. The run owns its disposable test resources and claim-backed local roots; successful runs clean them after the service drains, while failures retain the claim and evidence for inspection. The generated SDK files under `zova/src/**` remain shared checkout output, so serialize concurrent generation for the same workspace/module and do not treat this command as an automatic rollback boundary.
|
|
84
84
|
|
|
85
|
+
For an explicitly authorized contract-generation run that must not reap historical claims, Cabloy Basic and Cabloy Start support this opt-in form:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm run contract:generate:isolated -- <module-name> --skip-expired-claim-reaping
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The wrapper consumes this standalone flag rather than forwarding it to Zova; `--skip-expired-claim-reaping=...` is rejected. Without the flag, contract generation retains normal historical-claim reaping. Unit, coverage and E2E defaults are unchanged; the runner rejects their use of this opt-out.
|
|
92
|
+
|
|
93
|
+
The opt-in lane requires strict freshness after application configuration and before module loading: run-owned public/runtime/SQLite directories must be absent or empty, shared and static-isolate database namespaces must be absent, and persistent Redis namespaces must be empty. Read-only discovery failures or preexisting resources fail closed rather than authorizing deletion. Startup requires per-application freshness proof to bypass normal test clearing; database preparation rechecks the namespace, never drops existing databases in this lane, and reuses only a database creation recorded by that application.
|
|
94
|
+
|
|
95
|
+
In the strict opt-in lane, generated `env.ts` contains a selected-key projection of the bootstrap process environment, not serialized configuration values. The CLI passes its resolved configuration to the bootstrap child in memory, preserving resolved-value precedence without exposing every inherited environment key through `app.meta.env`. Strict generation requires test mode and matching run-owned directories before configuration loading or generated-file writes. Ordinary dev/build/test and default contract generation keep their existing environment generation behavior.
|
|
96
|
+
|
|
97
|
+
Strict service and generator stdout/stderr are discarded, not captured for later redaction. Framework logger access bypasses client configuration and transport construction; direct file-transport construction fails before filesystem or rotation access. Parent failures report categorical stages instead of raw child errors, causes or response bodies. Windows output still drains through the native bridges into discard streams; this implementation policy and synthetic coverage are not native Windows runtime verification. Custom filesystem writers, external logging sinks and seed behavior remain outside this framework diagnostic boundary: it is not a universal secret sandbox or secret scanner.
|
|
98
|
+
|
|
99
|
+
This still loads environment configuration, initializes newly allocated test databases and Redis/runtime resources, and runs normal module seeds. Successful runs clean only their inventoried current-run resources after verified shutdown; failed runs retain their claim/resources, without automatic generation retry or fallback. Discarded diagnostics are not recoverable from a retained claim. Generated consumers remain shared checkout writes. Freshness is a snapshot, **not an exclusive lease**, zero-mutation mode, network sandbox, blanket log-redaction guarantee, or authorization to contact a Provider. Independently configured external resources and Provider operations retain their separate ownership and approval requirements. This shared flag does not extend Basic's separately scoped Windows verification to Start.
|
|
100
|
+
|
|
85
101
|
For Vona integrated SSR, the allocated E2E origin is supplied to Zova at runtime as server `SSR_API_BASE_URL` and browser `API_BASE_URL`. Do not edit Zova `.env` files or rebuild solely to match the test port. The current root `npm run test:e2e` consumes prebuilt frontend artifacts; refresh affected SSR/REST output and synchronize dependencies when their inputs change. See [Runtime API origins in Vona integrated SSR](/fullstack/ssr-entry-modes#runtime-api-origins-in-vona-integrated-ssr) for configuration overrides and scope.
|
|
86
102
|
|
|
87
103
|
For deliberate **dev-mode** database preparation, `npm run db:reset` is a separate, destructive command: in a single process, it clears validated application-owned Redis keys, drops and recreates managed disposable development databases, reruns migrations and instance initialization, then runs module `seed()` hooks. It requires `database.testDatabase: true` in the dev configuration and a connection outside the disposable database. Ordinary `npm run dev` and `npm run dev:one` only reuse existing managed databases; if any required target is missing, startup fails promptly with an instruction to run `npm run db:reset`. They do not create databases, perform creation-time Redis cleanup, or seed. Never run `db:reset` against development data you need to retain. Upgrades do not reset existing development data or repeat its seeds. See [Development database preparation](#development-database-preparation) and [Migration and Changes](/backend/migration-and-changes#local-development-workflow).
|
|
@@ -9,10 +9,35 @@ import type { GuardianResult, OwnedProcess } from './runIsolatedTest.ts';
|
|
|
9
9
|
import {
|
|
10
10
|
getOpenapiGeneratorCommand,
|
|
11
11
|
getOpenapiSource,
|
|
12
|
+
parseIsolatedOpenapiArgs,
|
|
12
13
|
validateOpenapiSource,
|
|
13
14
|
} from './generateOpenapiIsolated.ts';
|
|
14
15
|
import { getIsolatedVonaCommand, ROOT_DIR, withIsolatedVona } from './runIsolatedTest.ts';
|
|
15
16
|
|
|
17
|
+
test('contract reaping opt-out is explicit and removed from generator arguments', () => {
|
|
18
|
+
const original = ['training-student', '--skip-expired-claim-reaping', '--nometadata'];
|
|
19
|
+
const parsed = parseIsolatedOpenapiArgs(original);
|
|
20
|
+
assert.deepEqual(parsed, {
|
|
21
|
+
generatorArgs: ['training-student', '--nometadata'],
|
|
22
|
+
skipExpiredClaimReaping: true,
|
|
23
|
+
});
|
|
24
|
+
assert.deepEqual(original, ['training-student', '--skip-expired-claim-reaping', '--nometadata']);
|
|
25
|
+
assert.equal(
|
|
26
|
+
getOpenapiGeneratorCommand(parsed.generatorArgs).args.includes('--skip-expired-claim-reaping'),
|
|
27
|
+
false,
|
|
28
|
+
);
|
|
29
|
+
assert.deepEqual(parseIsolatedOpenapiArgs(['training-student']), {
|
|
30
|
+
generatorArgs: ['training-student'],
|
|
31
|
+
skipExpiredClaimReaping: false,
|
|
32
|
+
});
|
|
33
|
+
for (const value of ['true', 'false', '']) {
|
|
34
|
+
assert.throws(
|
|
35
|
+
() => parseIsolatedOpenapiArgs([`--skip-expired-claim-reaping=${value}`]),
|
|
36
|
+
/standalone flag/,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
16
41
|
test('builds the isolated Swagger source from the allocated port', () => {
|
|
17
42
|
assert.equal(getOpenapiSource(7123), 'http://127.0.0.1:7123/swagger/json?version=V31');
|
|
18
43
|
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
withIsolatedVona,
|
|
8
8
|
withIsolatedRun,
|
|
9
9
|
} from './runIsolatedTest.ts';
|
|
10
|
+
import { strictGenerationFailure } from './strictGenerationDiagnostics.ts';
|
|
10
11
|
|
|
11
12
|
const OPENAPI_VERSION = 'V31';
|
|
12
13
|
const SOURCE_TIMEOUT_MS = 30_000;
|
|
@@ -15,6 +16,17 @@ export function getOpenapiSource(port: number) {
|
|
|
15
16
|
return `http://127.0.0.1:${port}/swagger/json?version=${OPENAPI_VERSION}`;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
export function parseIsolatedOpenapiArgs(args: string[]) {
|
|
20
|
+
const flag = '--skip-expired-claim-reaping';
|
|
21
|
+
if (args.some(arg => arg.startsWith(`${flag}=`))) {
|
|
22
|
+
throw new Error(`${flag} is a standalone flag`);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
generatorArgs: args.filter(arg => arg !== flag),
|
|
26
|
+
skipExpiredClaimReaping: args.includes(flag),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
18
30
|
export function getOpenapiGeneratorCommand(args: string[]) {
|
|
19
31
|
if (args.some(arg => /^--projectPath(?:=|$)/.test(arg))) {
|
|
20
32
|
throw new Error(
|
|
@@ -67,25 +79,47 @@ export async function validateOpenapiSource(source: string) {
|
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
export async function generateOpenapiIsolated(args: string[]) {
|
|
70
|
-
const
|
|
82
|
+
const strict = args.some(arg => /^--skip-expired-claim-reaping(?:=|$)/.test(arg));
|
|
83
|
+
try {
|
|
84
|
+
return await generateOpenapiIsolatedInternal(args);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
throw strict ? strictGenerationFailure('run', error) : error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function generateOpenapiIsolatedInternal(args: string[]) {
|
|
91
|
+
const { generatorArgs, skipExpiredClaimReaping } = parseIsolatedOpenapiArgs(args);
|
|
92
|
+
const command = getOpenapiGeneratorCommand(generatorArgs);
|
|
71
93
|
if (process.env.E2E_BASE_URL !== undefined) {
|
|
72
94
|
throw new Error(
|
|
73
95
|
'E2E_BASE_URL is unsupported; isolated OpenAPI generation manages a local test-mode target.',
|
|
74
96
|
);
|
|
75
97
|
}
|
|
76
|
-
return await withIsolatedRun(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
await
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
return await withIsolatedRun(
|
|
99
|
+
'contract',
|
|
100
|
+
async ({ env, port }) => {
|
|
101
|
+
const source = getOpenapiSource(port);
|
|
102
|
+
await withIsolatedVona(port, env, async () => {
|
|
103
|
+
await validateOpenapiSource(source);
|
|
104
|
+
await runIsolatedProcess(command.command, command.args, command.cwd, {
|
|
105
|
+
...env,
|
|
106
|
+
OPENAPI_SOURCE_URL: source,
|
|
107
|
+
VONA_TEST_READY_KEY: undefined,
|
|
108
|
+
});
|
|
84
109
|
});
|
|
85
|
-
}
|
|
86
|
-
|
|
110
|
+
},
|
|
111
|
+
ROOT_DIR,
|
|
112
|
+
{ skipExpiredClaimReaping },
|
|
113
|
+
);
|
|
87
114
|
}
|
|
88
115
|
|
|
89
116
|
if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
|
|
90
|
-
|
|
117
|
+
const args = process.argv.slice(2);
|
|
118
|
+
try {
|
|
119
|
+
await generateOpenapiIsolated(args);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (!args.some(arg => /^--skip-expired-claim-reaping(?:=|$)/.test(arg))) throw error;
|
|
122
|
+
console.error(strictGenerationFailure('run', error).message);
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
}
|
|
91
125
|
}
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
createTestRunId,
|
|
34
34
|
getUnitTestCommands,
|
|
35
35
|
reserveTestRun,
|
|
36
|
+
reapBeforeIsolatedRun,
|
|
36
37
|
resolveNpmCli,
|
|
37
38
|
resolveCabloyEdition,
|
|
38
39
|
ROOT_DIR,
|
|
@@ -45,12 +46,104 @@ import {
|
|
|
45
46
|
waitForReady,
|
|
46
47
|
withIsolatedRun,
|
|
47
48
|
} from './runIsolatedTest.ts';
|
|
49
|
+
import { StrictGenerationError } from './strictGenerationDiagnostics.ts';
|
|
48
50
|
|
|
49
51
|
const isolationSource = resolve(
|
|
50
52
|
ROOT_DIR,
|
|
51
53
|
'vona/packages-vona/vona-core/src/lib/core/testIsolation.ts',
|
|
52
54
|
);
|
|
53
55
|
|
|
56
|
+
test('claim reaping defaults remain enabled and contract opt-out never calls the reaper', async () => {
|
|
57
|
+
const calls: string[] = [];
|
|
58
|
+
const reap = async (projectPath: string) => {
|
|
59
|
+
calls.push(projectPath);
|
|
60
|
+
return [];
|
|
61
|
+
};
|
|
62
|
+
for (const kind of ['unit', 'cov', 'e2e', 'contract'] as const) {
|
|
63
|
+
await reapBeforeIsolatedRun(kind, '/synthetic/vona', {}, reap);
|
|
64
|
+
}
|
|
65
|
+
assert.deepEqual(calls, [
|
|
66
|
+
'/synthetic/vona',
|
|
67
|
+
'/synthetic/vona',
|
|
68
|
+
'/synthetic/vona',
|
|
69
|
+
'/synthetic/vona',
|
|
70
|
+
]);
|
|
71
|
+
await reapBeforeIsolatedRun(
|
|
72
|
+
'contract',
|
|
73
|
+
'/synthetic/vona',
|
|
74
|
+
{ skipExpiredClaimReaping: true },
|
|
75
|
+
async () => {
|
|
76
|
+
throw new Error('historical reaper must not run');
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
for (const kind of ['unit', 'cov', 'e2e'] as const) {
|
|
80
|
+
await assert.rejects(
|
|
81
|
+
reapBeforeIsolatedRun(kind, '/synthetic/vona', { skipExpiredClaimReaping: true }, reap),
|
|
82
|
+
/supported only for contract generation/,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
assert.equal(calls.length, 4);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('public test entrypoints reject contract-only flags before claim reaping', () => {
|
|
89
|
+
const runnerUrl = new URL('./runIsolatedTest.ts', import.meta.url).href;
|
|
90
|
+
const source = `
|
|
91
|
+
import assert from 'node:assert/strict';
|
|
92
|
+
import { registerHooks } from 'node:module';
|
|
93
|
+
globalThis.cleanupCalls = [];
|
|
94
|
+
registerHooks({ resolve(specifier, context, nextResolve) {
|
|
95
|
+
if (context.parentURL === ${JSON.stringify(runnerUrl)} && specifier === './testClaimCleanup.ts') {
|
|
96
|
+
const source = \`
|
|
97
|
+
export function parseTestClaimTtlSeconds() { return 1; }
|
|
98
|
+
export async function reapExpiredTestClaims() {
|
|
99
|
+
globalThis.cleanupCalls.push('reap');
|
|
100
|
+
throw new Error('unexpected claim reaping');
|
|
101
|
+
}
|
|
102
|
+
export async function cleanTestClaim() {
|
|
103
|
+
globalThis.cleanupCalls.push('clean');
|
|
104
|
+
throw new Error('unexpected claim cleanup');
|
|
105
|
+
}
|
|
106
|
+
\`;
|
|
107
|
+
return { url: 'data:text/javascript,' + encodeURIComponent(source), shortCircuit: true };
|
|
108
|
+
}
|
|
109
|
+
return nextResolve(specifier, context);
|
|
110
|
+
} });
|
|
111
|
+
const { runIsolatedTest } = await import(${JSON.stringify(runnerUrl)});
|
|
112
|
+
for (const [kind, args] of [['unit', []], ['unit', ['--coverage']], ['e2e', []]]) {
|
|
113
|
+
for (const suffix of ['', '=true', '=false', '=']) {
|
|
114
|
+
await assert.rejects(
|
|
115
|
+
runIsolatedTest(kind, [...args, '--skip-expired-claim-reaping' + suffix]),
|
|
116
|
+
/--skip-expired-claim-reaping is supported only for contract generation/,
|
|
117
|
+
);
|
|
118
|
+
assert.deepEqual(globalThis.cleanupCalls, []);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
await assert.rejects(runIsolatedTest('unit', []), /unexpected claim reaping/);
|
|
122
|
+
assert.deepEqual(globalThis.cleanupCalls, ['reap']);
|
|
123
|
+
`;
|
|
124
|
+
const result = spawnSync(process.execPath, ['--input-type=module', '-e', source], {
|
|
125
|
+
cwd: ROOT_DIR,
|
|
126
|
+
env: { ...process.env, E2E_BASE_URL: undefined },
|
|
127
|
+
encoding: 'utf8',
|
|
128
|
+
timeout: 10_000,
|
|
129
|
+
});
|
|
130
|
+
assert.equal(result.error, undefined);
|
|
131
|
+
assert.equal(result.status, 0, result.stderr);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('claim reaping errors propagate without retries', async () => {
|
|
135
|
+
const error = new Error('synthetic reaper failure');
|
|
136
|
+
let calls = 0;
|
|
137
|
+
await assert.rejects(
|
|
138
|
+
reapBeforeIsolatedRun('contract', '/synthetic/vona', {}, async () => {
|
|
139
|
+
calls++;
|
|
140
|
+
throw error;
|
|
141
|
+
}),
|
|
142
|
+
value => value === error,
|
|
143
|
+
);
|
|
144
|
+
assert.equal(calls, 1);
|
|
145
|
+
});
|
|
146
|
+
|
|
54
147
|
test('public test scripts delegate to the isolated runner without recursion', () => {
|
|
55
148
|
const root = JSON.parse(readFileSync(resolve(ROOT_DIR, 'package.json'), 'utf8'));
|
|
56
149
|
const original = JSON.parse(
|
|
@@ -223,51 +316,78 @@ test('creates exclusive manifest claims and refuses stale or symlinked roots', a
|
|
|
223
316
|
}
|
|
224
317
|
});
|
|
225
318
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
319
|
+
for (const marker of ['__CABLOY_BASIC__', '__CABLOY_START__']) {
|
|
320
|
+
test(
|
|
321
|
+
`contract runs clean owned roots on success and retain failed-run evidence for ${marker}`,
|
|
322
|
+
{ concurrency: false },
|
|
323
|
+
async () => {
|
|
324
|
+
const root = mkdtempSync(join(realpathSync(tmpdir()), 'cabloy-contract-run-'));
|
|
325
|
+
mkdirSync(join(root, 'vona'));
|
|
326
|
+
writeFileSync(join(root, marker), '');
|
|
327
|
+
let claimPath = '';
|
|
328
|
+
let dataRoot = '';
|
|
329
|
+
let generatedRoot = '';
|
|
330
|
+
const previous = process.env.VONA_TEST_REQUIRE_FRESH_RESOURCES;
|
|
331
|
+
try {
|
|
332
|
+
process.env.VONA_TEST_REQUIRE_FRESH_RESOURCES = 'true';
|
|
333
|
+
await withIsolatedRun(
|
|
334
|
+
'contract',
|
|
335
|
+
async context => {
|
|
336
|
+
assert.equal(context.env.VONA_TEST_REQUIRE_FRESH_RESOURCES, undefined);
|
|
337
|
+
},
|
|
338
|
+
root,
|
|
339
|
+
);
|
|
340
|
+
assert.equal(
|
|
341
|
+
await withIsolatedRun(
|
|
342
|
+
'contract',
|
|
343
|
+
async context => {
|
|
344
|
+
({ claimPath, dataRoot, generatedRoot } = context);
|
|
345
|
+
assert.equal((await loadTestClaim(claimPath)).kind, 'contract');
|
|
346
|
+
assert.equal(context.env.META_MODE, 'test');
|
|
347
|
+
assert.equal(context.env.VONA_DB_RESET, undefined);
|
|
348
|
+
assert.equal(context.env.VONA_TEST_READY_KEY, undefined);
|
|
349
|
+
assert.equal(context.env.VONA_TEST_REQUIRE_FRESH_RESOURCES, 'true');
|
|
350
|
+
assert.ok(existsSync(join(dataRoot, '.vona-test-owner')));
|
|
351
|
+
return 'generated';
|
|
352
|
+
},
|
|
353
|
+
root,
|
|
354
|
+
{ skipExpiredClaimReaping: true },
|
|
355
|
+
),
|
|
356
|
+
'generated',
|
|
357
|
+
);
|
|
358
|
+
assert.equal(existsSync(claimPath), false);
|
|
359
|
+
assert.equal(existsSync(dataRoot), false);
|
|
360
|
+
assert.equal(existsSync(generatedRoot), false);
|
|
361
|
+
await assert.rejects(
|
|
362
|
+
withIsolatedRun(
|
|
363
|
+
'contract',
|
|
364
|
+
async context => {
|
|
365
|
+
({ claimPath, dataRoot, generatedRoot } = context);
|
|
366
|
+
throw new Error('generator failed');
|
|
367
|
+
},
|
|
368
|
+
root,
|
|
369
|
+
{ skipExpiredClaimReaping: true },
|
|
370
|
+
),
|
|
371
|
+
error => {
|
|
372
|
+
assert.ok(error instanceof StrictGenerationError);
|
|
373
|
+
assert.equal(error.stage, 'run');
|
|
374
|
+
assert.equal(error.message, 'Strict contract generation failed: run');
|
|
375
|
+
assert.doesNotMatch(error.stack ?? '', /generator failed/);
|
|
376
|
+
assert.equal(error.cause, undefined);
|
|
377
|
+
return true;
|
|
378
|
+
},
|
|
379
|
+
);
|
|
380
|
+
assert.equal((await loadTestClaim(claimPath)).status, 'failed');
|
|
381
|
+
assert.equal(existsSync(dataRoot), true);
|
|
382
|
+
assert.equal(existsSync(generatedRoot), true);
|
|
383
|
+
} finally {
|
|
384
|
+
if (previous === undefined) delete process.env.VONA_TEST_REQUIRE_FRESH_RESOURCES;
|
|
385
|
+
else process.env.VONA_TEST_REQUIRE_FRESH_RESOURCES = previous;
|
|
386
|
+
rmSync(root, { recursive: true, force: true });
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
);
|
|
390
|
+
}
|
|
271
391
|
|
|
272
392
|
test('readiness retries signed not-ready responses and rejects server exit or timeout', async () => {
|
|
273
393
|
const key = 'a'.repeat(64);
|