cabloy 5.1.220 → 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 +2 -2
- 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 +11 -0
- package/package.json +4 -3
- package/repo-docs/frontend/openapi-sdk-guide.md +2 -0
- package/repo-docs/reference/repo-scripts.md +5 -1
- package/scripts/generateOpenapiIsolated.ts +18 -1
- package/scripts/runIsolatedTest.test.ts +9 -1
- package/scripts/runIsolatedTest.ts +81 -18
- package/scripts/strictGenerationDiagnostics.test.ts +1009 -0
- package/scripts/strictGenerationDiagnostics.ts +61 -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/core/logger/appLogger.ts +10 -2
- package/vona/packages-vona/vona-core/src/lib/core/logger/diagnosticLogger.test.ts +268 -68
- package/vona/packages-vona/vona-core/src/lib/core/testFreshness.ts +3 -9
- package/vona/packages-vona/vona-core/src/lib/core/testStrictMode.ts +9 -0
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +542 -236
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -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/package.json +1 -1
- 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/common/restDependencyVersions.ts +22 -1
- package/zova/packages-cli/cli-set-front/test/restDependencies.test.ts +137 -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
|
|
@@ -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
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
|
|
@@ -92,7 +92,11 @@ The wrapper consumes this standalone flag rather than forwarding it to Zova; `--
|
|
|
92
92
|
|
|
93
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
94
|
|
|
95
|
-
|
|
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.
|
|
96
100
|
|
|
97
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.
|
|
98
102
|
|
|
@@ -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;
|
|
@@ -78,6 +79,15 @@ export async function validateOpenapiSource(source: string) {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
export async function generateOpenapiIsolated(args: string[]) {
|
|
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[]) {
|
|
81
91
|
const { generatorArgs, skipExpiredClaimReaping } = parseIsolatedOpenapiArgs(args);
|
|
82
92
|
const command = getOpenapiGeneratorCommand(generatorArgs);
|
|
83
93
|
if (process.env.E2E_BASE_URL !== undefined) {
|
|
@@ -104,5 +114,12 @@ export async function generateOpenapiIsolated(args: string[]) {
|
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
|
|
107
|
-
|
|
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
|
+
}
|
|
108
125
|
}
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
waitForReady,
|
|
47
47
|
withIsolatedRun,
|
|
48
48
|
} from './runIsolatedTest.ts';
|
|
49
|
+
import { StrictGenerationError } from './strictGenerationDiagnostics.ts';
|
|
49
50
|
|
|
50
51
|
const isolationSource = resolve(
|
|
51
52
|
ROOT_DIR,
|
|
@@ -367,7 +368,14 @@ for (const marker of ['__CABLOY_BASIC__', '__CABLOY_START__']) {
|
|
|
367
368
|
root,
|
|
368
369
|
{ skipExpiredClaimReaping: true },
|
|
369
370
|
),
|
|
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
|
+
},
|
|
371
379
|
);
|
|
372
380
|
assert.equal((await loadTestClaim(claimPath)).status, 'failed');
|
|
373
381
|
assert.equal(existsSync(dataRoot), true);
|
|
@@ -14,6 +14,13 @@ import {
|
|
|
14
14
|
sendTestClaimEvent,
|
|
15
15
|
startTestClaimBroker,
|
|
16
16
|
} from '../vona/packages-vona/vona-core/src/lib/core/testClaim.ts';
|
|
17
|
+
import {
|
|
18
|
+
discardNativeOutput,
|
|
19
|
+
guardianStdio,
|
|
20
|
+
reportIsolatedDiagnostic,
|
|
21
|
+
strictGenerationFailure,
|
|
22
|
+
usesStrictGeneration,
|
|
23
|
+
} from './strictGenerationDiagnostics.ts';
|
|
17
24
|
import {
|
|
18
25
|
cleanTestClaim,
|
|
19
26
|
parseTestClaimTtlSeconds,
|
|
@@ -94,7 +101,16 @@ export async function startOwnedProcess(
|
|
|
94
101
|
cwd: string,
|
|
95
102
|
env: NodeJS.ProcessEnv,
|
|
96
103
|
): Promise<OwnedProcess> {
|
|
97
|
-
|
|
104
|
+
const strict = usesStrictGeneration(env);
|
|
105
|
+
if (process.platform === 'win32') {
|
|
106
|
+
return startWindowsOwnedProcess(
|
|
107
|
+
command,
|
|
108
|
+
args,
|
|
109
|
+
cwd,
|
|
110
|
+
env,
|
|
111
|
+
strict ? discardNativeOutput() : undefined,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
98
114
|
const processId = randomUUID();
|
|
99
115
|
const managed = hasTestClaimTransport(env);
|
|
100
116
|
const registration = { id: processId, role: 'guardian', stage: 'pending' as const };
|
|
@@ -102,7 +118,7 @@ export async function startOwnedProcess(
|
|
|
102
118
|
const guardian: ChildProcess = spawn(process.execPath, [GUARDIAN_FILE], {
|
|
103
119
|
cwd: ROOT_DIR,
|
|
104
120
|
env,
|
|
105
|
-
stdio:
|
|
121
|
+
stdio: guardianStdio(strict),
|
|
106
122
|
detached: true,
|
|
107
123
|
});
|
|
108
124
|
let drained: GuardianResult | undefined;
|
|
@@ -335,9 +351,15 @@ export async function withIsolatedVona<T>(
|
|
|
335
351
|
callback: () => Promise<T>,
|
|
336
352
|
dependencies: IsolatedVonaDependencies = { start: startOwnedProcess, ready: waitForReady },
|
|
337
353
|
): Promise<T> {
|
|
354
|
+
const strict = usesStrictGeneration(env);
|
|
338
355
|
const readyKey = randomBytes(32).toString('hex');
|
|
339
356
|
const command = getIsolatedVonaCommand(port, env, readyKey);
|
|
340
|
-
|
|
357
|
+
let server: OwnedProcess;
|
|
358
|
+
try {
|
|
359
|
+
server = await dependencies.start(command.command, command.args, command.cwd, command.env);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
throw strict ? strictGenerationFailure('startup') : error;
|
|
362
|
+
}
|
|
341
363
|
let stopping = false;
|
|
342
364
|
let exitedEarly = false;
|
|
343
365
|
void server.wait().then(
|
|
@@ -351,7 +373,9 @@ export async function withIsolatedVona<T>(
|
|
|
351
373
|
let interrupted = false;
|
|
352
374
|
const onInterrupt = () => {
|
|
353
375
|
interrupted = true;
|
|
354
|
-
void server
|
|
376
|
+
void server
|
|
377
|
+
.stop()
|
|
378
|
+
.catch(error => reportIsolatedDiagnostic(strict, 'interrupt-stop-failed', error));
|
|
355
379
|
};
|
|
356
380
|
process.on('SIGINT', onInterrupt);
|
|
357
381
|
process.on('SIGTERM', onInterrupt);
|
|
@@ -398,19 +422,22 @@ export async function withIsolatedVona<T>(
|
|
|
398
422
|
if (interrupted) throw new Error('Isolated Vona run interrupted');
|
|
399
423
|
result = await callback();
|
|
400
424
|
} catch (error) {
|
|
401
|
-
operationError =
|
|
425
|
+
operationError = strict
|
|
426
|
+
? strictGenerationFailure(ready ? 'operation' : 'startup', error)
|
|
427
|
+
: toError(error);
|
|
402
428
|
} finally {
|
|
403
429
|
stopping = true;
|
|
404
430
|
try {
|
|
405
431
|
await shutdown();
|
|
406
432
|
} catch (error) {
|
|
407
|
-
shutdownError = toError(error);
|
|
433
|
+
shutdownError = strict ? strictGenerationFailure('shutdown') : toError(error);
|
|
408
434
|
} finally {
|
|
409
435
|
process.off('SIGINT', onInterrupt);
|
|
410
436
|
process.off('SIGTERM', onInterrupt);
|
|
411
437
|
}
|
|
412
438
|
}
|
|
413
439
|
if (operationError && shutdownError) {
|
|
440
|
+
if (strict) throw strictGenerationFailure('operation-and-shutdown');
|
|
414
441
|
throw new AggregateError(
|
|
415
442
|
[operationError, shutdownError],
|
|
416
443
|
'Isolated Vona operation and shutdown failed',
|
|
@@ -427,11 +454,19 @@ export async function runIsolatedProcess(
|
|
|
427
454
|
cwd: string,
|
|
428
455
|
env: NodeJS.ProcessEnv,
|
|
429
456
|
) {
|
|
430
|
-
const
|
|
457
|
+
const strict = usesStrictGeneration(env);
|
|
458
|
+
let child: OwnedProcess;
|
|
459
|
+
try {
|
|
460
|
+
child = await startOwnedProcess(command, args, cwd, env);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
throw strict ? strictGenerationFailure('generator') : error;
|
|
463
|
+
}
|
|
431
464
|
let interrupted = false;
|
|
432
465
|
const onInterrupt = () => {
|
|
433
466
|
interrupted = true;
|
|
434
|
-
void child
|
|
467
|
+
void child
|
|
468
|
+
.stop()
|
|
469
|
+
.catch(error => reportIsolatedDiagnostic(strict, 'interrupt-stop-failed', error));
|
|
435
470
|
};
|
|
436
471
|
process.on('SIGINT', onInterrupt);
|
|
437
472
|
process.on('SIGTERM', onInterrupt);
|
|
@@ -440,6 +475,8 @@ export async function runIsolatedProcess(
|
|
|
440
475
|
if (result.failed || interrupted || result.result?.code !== 0) {
|
|
441
476
|
throw new Error(`Isolated test exited: ${result.result?.signal ?? result.result?.code}`);
|
|
442
477
|
}
|
|
478
|
+
} catch (error) {
|
|
479
|
+
throw strict ? strictGenerationFailure('generator') : error;
|
|
443
480
|
} finally {
|
|
444
481
|
process.off('SIGINT', onInterrupt);
|
|
445
482
|
process.off('SIGTERM', onInterrupt);
|
|
@@ -576,6 +613,20 @@ export async function withIsolatedRun<T>(
|
|
|
576
613
|
rootDir = ROOT_DIR,
|
|
577
614
|
options: IsolatedRunOptions = {},
|
|
578
615
|
): Promise<T> {
|
|
616
|
+
try {
|
|
617
|
+
return await withIsolatedRunInternal(kind, callback, rootDir, options);
|
|
618
|
+
} catch (error) {
|
|
619
|
+
throw options.skipExpiredClaimReaping ? strictGenerationFailure('preparation', error) : error;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
async function withIsolatedRunInternal<T>(
|
|
624
|
+
kind: 'unit' | 'cov' | 'e2e' | 'contract',
|
|
625
|
+
callback: (context: IsolatedRunContext) => Promise<T>,
|
|
626
|
+
rootDir: string,
|
|
627
|
+
options: IsolatedRunOptions,
|
|
628
|
+
): Promise<T> {
|
|
629
|
+
const strict = options.skipExpiredClaimReaping === true;
|
|
579
630
|
resolveCabloyEdition(rootDir);
|
|
580
631
|
const vonaDir = resolve(rootDir, 'vona');
|
|
581
632
|
await reapBeforeIsolatedRun(kind, vonaDir, options);
|
|
@@ -632,21 +683,33 @@ export async function withIsolatedRun<T>(
|
|
|
632
683
|
await broker?.update({ type: 'status', status: 'failed' }).catch(() => {
|
|
633
684
|
console.error('Could not record failed test status; claim retained');
|
|
634
685
|
});
|
|
635
|
-
throw error;
|
|
686
|
+
throw strict ? strictGenerationFailure('run', error) : error;
|
|
636
687
|
} finally {
|
|
637
688
|
if (!completed) {
|
|
638
|
-
|
|
689
|
+
reportIsolatedDiagnostic(
|
|
690
|
+
strict,
|
|
691
|
+
'failed-resources-retained',
|
|
692
|
+
`Isolated test claim and resources retained for inspection: ${claimPath}`,
|
|
693
|
+
);
|
|
639
694
|
}
|
|
640
695
|
await broker?.close();
|
|
641
696
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
697
|
+
try {
|
|
698
|
+
const cleanup = await cleanTestClaim(claimPath, {
|
|
699
|
+
projectPath: vonaDir,
|
|
700
|
+
isInactive: claim => isTestClaimInactive(claim, true),
|
|
701
|
+
warn: message => reportIsolatedDiagnostic(strict, 'cleanup-warning', message),
|
|
702
|
+
});
|
|
703
|
+
if (cleanup.status !== 'cleaned') {
|
|
704
|
+
reportIsolatedDiagnostic(
|
|
705
|
+
strict,
|
|
706
|
+
'cleanup-incomplete-claim-retained',
|
|
707
|
+
`Isolated test claim retained for inspection: ${claimPath}`,
|
|
708
|
+
);
|
|
709
|
+
throw new Error('Isolated test succeeded but resource cleanup did not complete');
|
|
710
|
+
}
|
|
711
|
+
} catch (error) {
|
|
712
|
+
throw strict ? strictGenerationFailure('cleanup') : error;
|
|
650
713
|
}
|
|
651
714
|
return result as T;
|
|
652
715
|
}
|