vona-core 5.1.45 → 5.1.47
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/dist/index.js +446 -93
- package/dist/index.js.map +1 -1
- package/dist/lib/core/testClaim.d.ts +11 -1
- package/dist/lib/core/testClaim.d.ts.map +1 -1
- package/dist/lib/core/testClaimFilesystem.d.ts +13 -0
- package/dist/lib/core/testClaimFilesystem.d.ts.map +1 -0
- package/dist/lib/core/testClaimFilesystem.test.d.ts +2 -0
- package/dist/lib/core/testClaimFilesystem.test.d.ts.map +1 -0
- package/dist/lib/core/testClaimFilesystemWindows.d.ts +19 -0
- package/dist/lib/core/testClaimFilesystemWindows.d.ts.map +1 -0
- package/dist/lib/core/testProcessWindowsNative.d.ts +59 -0
- package/dist/lib/core/testProcessWindowsNative.d.ts.map +1 -0
- package/dist/lib/framework/bootstrap.test.d.ts +2 -0
- package/dist/lib/framework/bootstrap.test.d.ts.map +1 -0
- package/dist/lib/framework/index.d.ts +1 -0
- package/dist/lib/framework/index.d.ts.map +1 -1
- package/dist/lib/framework/processWorker.d.ts +1 -0
- package/dist/lib/framework/processWorker.d.ts.map +1 -1
- package/dist/lib/framework/processWorker.test.d.ts +2 -0
- package/dist/lib/framework/processWorker.test.d.ts.map +1 -0
- package/dist/lib/framework/useApp.test.d.ts +2 -0
- package/dist/lib/framework/useApp.test.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/lib/core/testClaim.test.ts +306 -18
- package/src/lib/core/testClaim.ts +207 -99
- package/src/lib/core/testClaimFilesystem.test.ts +247 -0
- package/src/lib/core/testClaimFilesystem.ts +224 -0
- package/src/lib/core/testClaimFilesystemWindows.cs +229 -0
- package/src/lib/core/testClaimFilesystemWindows.ps1 +20 -0
- package/src/lib/core/testClaimFilesystemWindows.ts +200 -0
- package/src/lib/core/testProcessWindowsNative.cs +336 -0
- package/src/lib/core/testProcessWindowsNative.ps1 +20 -0
- package/src/lib/core/testProcessWindowsNative.ts +531 -0
- package/src/lib/framework/bootstrap.test.ts +61 -0
- package/src/lib/framework/index.ts +1 -0
- package/src/lib/framework/processWorker.test.ts +59 -0
- package/src/lib/framework/processWorker.ts +8 -5
- package/src/lib/framework/useApp.test.ts +84 -0
- package/src/lib/framework/useApp.ts +2 -2
- package/src/lib/utils/util.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -4,11 +4,11 @@ import { toLowerCaseFirstChar, splitWords } from '@cabloy/word-utils';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import fse from 'fs-extra';
|
|
6
6
|
import crypto, { createHash as createHash$1, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
7
|
-
import fs, { lstatSync, constants } from 'node:fs';
|
|
7
|
+
import fs, { lstatSync, existsSync, readFileSync, constants } from 'node:fs';
|
|
8
8
|
import { compose as compose$1 } from '@cabloy/compose';
|
|
9
9
|
import { extend } from '@cabloy/extend';
|
|
10
10
|
import { createRequire } from 'node:module';
|
|
11
|
-
import { pathToFileURL } from 'node:url';
|
|
11
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
12
12
|
import * as uuid from 'uuid';
|
|
13
13
|
import { getPlatformArch as getPlatformArch$1 } from 'vona';
|
|
14
14
|
import os from 'node:os';
|
|
@@ -26,8 +26,9 @@ import chalk from 'chalk';
|
|
|
26
26
|
import * as Winston from 'winston';
|
|
27
27
|
import DailyRotateFile from 'winston-daily-rotate-file';
|
|
28
28
|
import { MESSAGE, LEVEL } from 'triple-beam';
|
|
29
|
-
import { mkdir, open, rename, unlink } from 'node:fs/promises';
|
|
30
29
|
import { createServer } from 'node:http';
|
|
30
|
+
import { mkdir, open, rename, unlink, lstat } from 'node:fs/promises';
|
|
31
|
+
import { execFileSync, execFile } from 'node:child_process';
|
|
31
32
|
import cluster from 'node:cluster';
|
|
32
33
|
import React from 'react';
|
|
33
34
|
import { extendZodWithOpenApi } from '@cabloy/zod-to-openapi';
|
|
@@ -546,7 +547,7 @@ class AppUtil extends BeanSimple {
|
|
|
546
547
|
const globalPrefix = '/api/static';
|
|
547
548
|
if (!staticPath) staticPath = '';
|
|
548
549
|
// safe
|
|
549
|
-
staticPath = path.normalize(staticPath);
|
|
550
|
+
staticPath = path.posix.normalize(staticPath.replace(/\\/g, '/'));
|
|
550
551
|
if (staticPath.includes('..')) throw new Error(`unsafe path: ${staticPath}`);
|
|
551
552
|
// ignore globalPrefix
|
|
552
553
|
if (staticPath.startsWith('//')) return staticPath.substring(1);
|
|
@@ -811,9 +812,9 @@ async function createGeneralApp(projectPath, envRuntime) {
|
|
|
811
812
|
}
|
|
812
813
|
}
|
|
813
814
|
if (process.env.META_MODE === 'prod') {
|
|
814
|
-
const testFile = path.join(projectPath, `dist/${process.env.META_FLAVOR}/
|
|
815
|
+
const testFile = path.join(projectPath, `dist/${process.env.META_FLAVOR}/app.js`);
|
|
815
816
|
const testInstance = await import(pathToHref(testFile));
|
|
816
|
-
return await testInstance.
|
|
817
|
+
return await testInstance.createSingleApp();
|
|
817
818
|
} else {
|
|
818
819
|
const testFile = path.join(resolveVonaLocalPaths(projectPath, process.env.META_MODE).generatedRoot, 'app.ts');
|
|
819
820
|
const testInstance = await import(pathToHref(testFile));
|
|
@@ -3176,8 +3177,307 @@ function __formatLoggerFilterCheckInfo(info) {
|
|
|
3176
3177
|
return info;
|
|
3177
3178
|
}
|
|
3178
3179
|
|
|
3180
|
+
// Both source and bundled dist consumers use the checked-in, published src assets.
|
|
3181
|
+
function getWindowsTestClaimFilesystemHelper(directory = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url))) {
|
|
3182
|
+
let current = directory;
|
|
3183
|
+
while (true) {
|
|
3184
|
+
const manifest = path.join(current, 'package.json');
|
|
3185
|
+
if (existsSync(manifest)) {
|
|
3186
|
+
const value = JSON.parse(readFileSync(manifest, 'utf8'));
|
|
3187
|
+
if (value.name === 'vona-core') {
|
|
3188
|
+
const helper = path.join(current, 'src/lib/core/testClaimFilesystemWindows.ps1');
|
|
3189
|
+
if (!existsSync(helper) || !existsSync(helper.replace(/\.ps1$/, '.cs'))) throw new Error('Windows test claim filesystem helper assets are missing');
|
|
3190
|
+
return helper;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
const parent = path.dirname(current);
|
|
3194
|
+
if (parent === current) throw new Error('Cannot locate the vona-core Windows filesystem helper');
|
|
3195
|
+
current = parent;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
function invocation() {
|
|
3199
|
+
if (process.platform !== 'win32') throw new Error('Windows claim filesystem requires Windows');
|
|
3200
|
+
return ['-NoLogo', '-NoProfile', '-NonInteractive', '-File', getWindowsTestClaimFilesystemHelper()];
|
|
3201
|
+
}
|
|
3202
|
+
function decode(source) {
|
|
3203
|
+
let value;
|
|
3204
|
+
try {
|
|
3205
|
+
value = JSON.parse(source);
|
|
3206
|
+
} catch {
|
|
3207
|
+
throw new Error('Windows test claim filesystem helper returned an invalid response');
|
|
3208
|
+
}
|
|
3209
|
+
if (!value || value.ok !== true) {
|
|
3210
|
+
const error = new Error(value?.code === 'EEXIST' ? 'Test claim file already exists' : `Unsafe Windows test claim filesystem operation (${value?.code ?? 'unknown'})`);
|
|
3211
|
+
Object.assign(error, {
|
|
3212
|
+
code: value?.code ?? 'EUNSAFE'
|
|
3213
|
+
});
|
|
3214
|
+
throw error;
|
|
3215
|
+
}
|
|
3216
|
+
return value;
|
|
3217
|
+
}
|
|
3218
|
+
function windowsTestClaimFilesystemSync(request) {
|
|
3219
|
+
try {
|
|
3220
|
+
return decode(execFileSync('pwsh', invocation(), {
|
|
3221
|
+
input: JSON.stringify(request),
|
|
3222
|
+
encoding: 'utf8',
|
|
3223
|
+
windowsHide: true,
|
|
3224
|
+
timeout: 30000,
|
|
3225
|
+
maxBuffer: 8 * 1024 * 1024
|
|
3226
|
+
}));
|
|
3227
|
+
} catch (error) {
|
|
3228
|
+
if (error.code === 'ENOENT') throw new Error('Native Windows test claims require PowerShell 7 (pwsh) on PATH');
|
|
3229
|
+
throw error;
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
let bridge;
|
|
3233
|
+
function windowsTestClaimFilesystem(request) {
|
|
3234
|
+
if (!bridge) {
|
|
3235
|
+
// Explicit executable + argv, never a shell. A burst shares Add-Type startup;
|
|
3236
|
+
// the bridge owns no persistent native handles and exits when idle.
|
|
3237
|
+
const child = execFile('pwsh', invocation(), {
|
|
3238
|
+
windowsHide: true,
|
|
3239
|
+
maxBuffer: Infinity
|
|
3240
|
+
});
|
|
3241
|
+
// execFile's collection listeners are for its callback API. This bounded
|
|
3242
|
+
// line protocol consumes the streams itself, without retaining burst history.
|
|
3243
|
+
child.stdout?.removeAllListeners('data');
|
|
3244
|
+
child.stderr?.removeAllListeners('data');
|
|
3245
|
+
const state = {
|
|
3246
|
+
child,
|
|
3247
|
+
pending: [],
|
|
3248
|
+
output: '',
|
|
3249
|
+
idle: undefined
|
|
3250
|
+
};
|
|
3251
|
+
bridge = state;
|
|
3252
|
+
const fail = error => {
|
|
3253
|
+
if (bridge === state) bridge = undefined;
|
|
3254
|
+
clearTimeout(state.idle);
|
|
3255
|
+
for (const operation of state.pending.splice(0)) {
|
|
3256
|
+
clearTimeout(operation.timer);
|
|
3257
|
+
operation.reject(error);
|
|
3258
|
+
}
|
|
3259
|
+
child.stdin?.destroy();
|
|
3260
|
+
child.kill();
|
|
3261
|
+
};
|
|
3262
|
+
child.once('error', error => fail(new Error(error.code === 'ENOENT' ? 'Native Windows test claims require PowerShell 7 (pwsh) on PATH' : 'Windows test claim filesystem helper failed; operation not acknowledged')));
|
|
3263
|
+
child.once('exit', () => fail(new Error('Windows test claim filesystem helper exited; operation not acknowledged')));
|
|
3264
|
+
child.stdin?.on('error', () => fail(new Error('Windows test claim filesystem control stream failed')));
|
|
3265
|
+
child.stdout?.setEncoding('utf8');
|
|
3266
|
+
child.stderr?.resume();
|
|
3267
|
+
child.stdout?.on('data', chunk => {
|
|
3268
|
+
state.output += chunk;
|
|
3269
|
+
if (Buffer.byteLength(state.output) > 8 * 1024 * 1024) {
|
|
3270
|
+
fail(new Error('Windows test claim filesystem response exceeded limit'));
|
|
3271
|
+
return;
|
|
3272
|
+
}
|
|
3273
|
+
while (state.output.includes('\n')) {
|
|
3274
|
+
const end = state.output.indexOf('\n');
|
|
3275
|
+
const line = state.output.slice(0, end);
|
|
3276
|
+
state.output = state.output.slice(end + 1);
|
|
3277
|
+
const operation = state.pending.shift();
|
|
3278
|
+
if (!operation) {
|
|
3279
|
+
fail(new Error('Unexpected Windows test claim filesystem response'));
|
|
3280
|
+
return;
|
|
3281
|
+
}
|
|
3282
|
+
clearTimeout(operation.timer);
|
|
3283
|
+
try {
|
|
3284
|
+
operation.resolve(decode(line));
|
|
3285
|
+
} catch (error) {
|
|
3286
|
+
operation.reject(error);
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
if (!state.pending.length) {
|
|
3290
|
+
state.idle = setTimeout(() => {
|
|
3291
|
+
if (bridge === state) bridge = undefined;
|
|
3292
|
+
child.stdin?.end();
|
|
3293
|
+
}, 1000);
|
|
3294
|
+
}
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
const state = bridge;
|
|
3298
|
+
clearTimeout(state.idle);
|
|
3299
|
+
return new Promise((resolve, reject) => {
|
|
3300
|
+
const timer = setTimeout(() => {
|
|
3301
|
+
if (bridge === state) bridge = undefined;
|
|
3302
|
+
for (const operation of state.pending.splice(0)) {
|
|
3303
|
+
clearTimeout(operation.timer);
|
|
3304
|
+
operation.reject(new Error('Windows test claim filesystem operation timed out; not acknowledged'));
|
|
3305
|
+
}
|
|
3306
|
+
state.child.kill();
|
|
3307
|
+
}, 30000);
|
|
3308
|
+
state.pending.push({
|
|
3309
|
+
resolve,
|
|
3310
|
+
reject,
|
|
3311
|
+
timer
|
|
3312
|
+
});
|
|
3313
|
+
state.child.stdin?.write(`${JSON.stringify(request)}\n`);
|
|
3314
|
+
});
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3317
|
+
const TEST_CLAIM_FILE_LIMIT = 4 * 1024 * 1024;
|
|
3318
|
+
function assertTestClaimFilesystemSafePath(file, allowMissing = true) {
|
|
3319
|
+
if (process.platform === 'win32') {
|
|
3320
|
+
windowsTestClaimFilesystemSync({
|
|
3321
|
+
command: 'safe-path',
|
|
3322
|
+
path: path.resolve(file),
|
|
3323
|
+
allowMissing
|
|
3324
|
+
});
|
|
3325
|
+
return;
|
|
3326
|
+
}
|
|
3327
|
+
let current = path.resolve(file);
|
|
3328
|
+
while (true) {
|
|
3329
|
+
try {
|
|
3330
|
+
const stat = lstatSync(current);
|
|
3331
|
+
if (stat.isSymbolicLink() || current !== path.resolve(file) && !stat.isDirectory()) throw new Error('Unsafe test claim path');
|
|
3332
|
+
} catch (error) {
|
|
3333
|
+
if (!allowMissing || error.code !== 'ENOENT') throw error;
|
|
3334
|
+
}
|
|
3335
|
+
const parent = path.dirname(current);
|
|
3336
|
+
if (parent === current) break;
|
|
3337
|
+
current = parent;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
async function assertTestClaimPrivateDirectory(directory, missingAllowed = true) {
|
|
3341
|
+
if (process.platform === 'win32') {
|
|
3342
|
+
const value = await windowsTestClaimFilesystem({
|
|
3343
|
+
command: 'directory',
|
|
3344
|
+
path: path.resolve(directory),
|
|
3345
|
+
allowMissing: missingAllowed
|
|
3346
|
+
});
|
|
3347
|
+
return value.exists === true;
|
|
3348
|
+
}
|
|
3349
|
+
assertTestClaimFilesystemSafePath(directory, missingAllowed);
|
|
3350
|
+
let stat;
|
|
3351
|
+
try {
|
|
3352
|
+
stat = await lstat(directory);
|
|
3353
|
+
} catch (error) {
|
|
3354
|
+
if (missingAllowed && error.code === 'ENOENT') return false;
|
|
3355
|
+
throw error;
|
|
3356
|
+
}
|
|
3357
|
+
if (!stat.isDirectory() || (stat.mode & 0o077) !== 0 || process.getuid && stat.uid !== process.getuid()) {
|
|
3358
|
+
throw new Error('Unsafe shared test claim directory');
|
|
3359
|
+
}
|
|
3360
|
+
return true;
|
|
3361
|
+
}
|
|
3362
|
+
async function ensureTestClaimPrivateDirectory(directory) {
|
|
3363
|
+
if (process.platform === 'win32') {
|
|
3364
|
+
await windowsTestClaimFilesystem({
|
|
3365
|
+
command: 'ensure-directory',
|
|
3366
|
+
path: path.resolve(directory)
|
|
3367
|
+
});
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3370
|
+
assertTestClaimFilesystemSafePath(directory);
|
|
3371
|
+
await mkdir(directory, {
|
|
3372
|
+
mode: 0o700
|
|
3373
|
+
}).catch(error => {
|
|
3374
|
+
if (error.code !== 'EEXIST') throw error;
|
|
3375
|
+
});
|
|
3376
|
+
await assertTestClaimPrivateDirectory(directory, false);
|
|
3377
|
+
}
|
|
3378
|
+
function assertPrivateFile(file) {
|
|
3379
|
+
assertTestClaimFilesystemSafePath(file, false);
|
|
3380
|
+
const stat = lstatSync(file);
|
|
3381
|
+
if (!stat.isFile() || stat.nlink !== 1 || (stat.mode & 0o077) !== 0 || process.getuid && stat.uid !== process.getuid()) {
|
|
3382
|
+
throw new Error('Unsafe test claim file');
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
async function syncDirectory(directory) {
|
|
3386
|
+
const handle = await open(directory, constants.O_RDONLY);
|
|
3387
|
+
try {
|
|
3388
|
+
await handle.sync();
|
|
3389
|
+
} finally {
|
|
3390
|
+
await handle.close();
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
function checkContent(content) {
|
|
3394
|
+
if (Buffer.byteLength(content) > TEST_CLAIM_FILE_LIMIT) throw new Error('Invalid test claim file size');
|
|
3395
|
+
}
|
|
3396
|
+
async function readTestClaimFile(file) {
|
|
3397
|
+
if (process.platform === 'win32') {
|
|
3398
|
+
const value = await windowsTestClaimFilesystem({
|
|
3399
|
+
command: 'read',
|
|
3400
|
+
path: path.resolve(file)
|
|
3401
|
+
});
|
|
3402
|
+
if (typeof value.content !== 'string') throw new Error('Invalid test claim file response');
|
|
3403
|
+
return value.content;
|
|
3404
|
+
}
|
|
3405
|
+
assertPrivateFile(file);
|
|
3406
|
+
const handle = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
3407
|
+
try {
|
|
3408
|
+
const stat = await handle.stat();
|
|
3409
|
+
if (!stat.isFile() || stat.nlink !== 1 || stat.size > TEST_CLAIM_FILE_LIMIT || (stat.mode & 0o077) !== 0 || process.getuid && stat.uid !== process.getuid()) {
|
|
3410
|
+
throw new Error('Invalid test claim file');
|
|
3411
|
+
}
|
|
3412
|
+
// Bound the allocation and bytes read even if the file grows after fstat.
|
|
3413
|
+
const buffer = Buffer.alloc(TEST_CLAIM_FILE_LIMIT + 1);
|
|
3414
|
+
let offset = 0;
|
|
3415
|
+
while (offset < buffer.length) {
|
|
3416
|
+
const {
|
|
3417
|
+
bytesRead
|
|
3418
|
+
} = await handle.read(buffer, offset, buffer.length - offset, null);
|
|
3419
|
+
if (!bytesRead) break;
|
|
3420
|
+
offset += bytesRead;
|
|
3421
|
+
}
|
|
3422
|
+
if (offset > TEST_CLAIM_FILE_LIMIT) throw new Error('Invalid test claim file size');
|
|
3423
|
+
return buffer.subarray(0, offset).toString('utf8');
|
|
3424
|
+
} finally {
|
|
3425
|
+
await handle.close();
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
async function createTestClaimFile(file, content) {
|
|
3429
|
+
checkContent(content);
|
|
3430
|
+
if (process.platform === 'win32') {
|
|
3431
|
+
await windowsTestClaimFilesystem({
|
|
3432
|
+
command: 'create',
|
|
3433
|
+
path: path.resolve(file),
|
|
3434
|
+
content
|
|
3435
|
+
});
|
|
3436
|
+
return;
|
|
3437
|
+
}
|
|
3438
|
+
assertTestClaimFilesystemSafePath(file);
|
|
3439
|
+
const handle = await open(file, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
3440
|
+
try {
|
|
3441
|
+
await handle.writeFile(content);
|
|
3442
|
+
await handle.sync();
|
|
3443
|
+
} finally {
|
|
3444
|
+
await handle.close();
|
|
3445
|
+
}
|
|
3446
|
+
await syncDirectory(path.dirname(file));
|
|
3447
|
+
}
|
|
3448
|
+
async function replaceTestClaimFile(file, content) {
|
|
3449
|
+
checkContent(content);
|
|
3450
|
+
if (process.platform === 'win32') {
|
|
3451
|
+
await windowsTestClaimFilesystem({
|
|
3452
|
+
command: 'replace',
|
|
3453
|
+
path: path.resolve(file),
|
|
3454
|
+
content
|
|
3455
|
+
});
|
|
3456
|
+
return;
|
|
3457
|
+
}
|
|
3458
|
+
const temp = `${file}.${randomBytes(12).toString('hex')}.tmp`;
|
|
3459
|
+
const handle = await open(temp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
3460
|
+
try {
|
|
3461
|
+
try {
|
|
3462
|
+
await handle.writeFile(content);
|
|
3463
|
+
await handle.sync();
|
|
3464
|
+
} finally {
|
|
3465
|
+
await handle.close();
|
|
3466
|
+
}
|
|
3467
|
+
assertPrivateFile(file);
|
|
3468
|
+
await rename(temp, file);
|
|
3469
|
+
await syncDirectory(path.dirname(file));
|
|
3470
|
+
} finally {
|
|
3471
|
+
await unlink(temp).catch(error => {
|
|
3472
|
+
if (error.code !== 'ENOENT') throw error;
|
|
3473
|
+
});
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3179
3477
|
const TEST_CLAIM_URL_ENV = 'VONA_TEST_CLAIM_URL';
|
|
3180
3478
|
const TEST_CLAIM_TOKEN_ENV = 'VONA_TEST_CLAIM_TOKEN';
|
|
3479
|
+
/** A locator only. Containment still requires the registered guardian's live native verifier. */
|
|
3480
|
+
const TEST_CLAIM_WINDOWS_GUARDIAN_ENV = 'VONA_TEST_WINDOWS_GUARDIAN_ID';
|
|
3181
3481
|
const TEST_CLAIM_DIRECTORY = '.vona-test-claim';
|
|
3182
3482
|
function getTestClaimPaths(projectPath, runId) {
|
|
3183
3483
|
resolveTestRunId('test', runId);
|
|
@@ -3196,20 +3496,7 @@ function getTestClaimCreatedAt(runId) {
|
|
|
3196
3496
|
return `${s.slice(0, 4)}-${s.slice(4, 6)}-${s.slice(6, 8)}T${s.slice(8, 10)}:${s.slice(10, 12)}:${s.slice(12, 14)}.000Z`;
|
|
3197
3497
|
}
|
|
3198
3498
|
function assertTestClaimSafePath(file, allowMissing = true) {
|
|
3199
|
-
|
|
3200
|
-
while (true) {
|
|
3201
|
-
try {
|
|
3202
|
-
const stat = lstatSync(current);
|
|
3203
|
-
if (stat.isSymbolicLink() || current !== path.resolve(file) && !stat.isDirectory()) {
|
|
3204
|
-
throw new Error('Unsafe test claim path');
|
|
3205
|
-
}
|
|
3206
|
-
} catch (error) {
|
|
3207
|
-
if (!allowMissing || error.code !== 'ENOENT') throw error;
|
|
3208
|
-
}
|
|
3209
|
-
const parent = path.dirname(current);
|
|
3210
|
-
if (parent === current) break;
|
|
3211
|
-
current = parent;
|
|
3212
|
-
}
|
|
3499
|
+
assertTestClaimFilesystemSafePath(file, allowMissing);
|
|
3213
3500
|
}
|
|
3214
3501
|
function record(value) {
|
|
3215
3502
|
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Invalid test claim object');
|
|
@@ -3278,7 +3565,7 @@ function validateTestClaim(value, claimPath) {
|
|
|
3278
3565
|
if (!path.isAbsolute(m.projectPath) || path.resolve(m.projectPath) !== m.projectPath) throw new Error('Invalid test claim checkout');
|
|
3279
3566
|
const p = getTestClaimPaths(m.projectPath, m.runId);
|
|
3280
3567
|
if (claimPath && path.resolve(claimPath) !== p.claimPath) throw new Error('Test claim filename or checkout mismatch');
|
|
3281
|
-
oneOf(m.kind, ['unit', 'cov', 'e2e']);
|
|
3568
|
+
oneOf(m.kind, ['unit', 'cov', 'e2e', 'contract']);
|
|
3282
3569
|
keys(m.owner, ['pid', 'startTime', 'host']);
|
|
3283
3570
|
integer(m.owner.pid, 1);
|
|
3284
3571
|
text(m.owner.startTime);
|
|
@@ -3334,16 +3621,28 @@ function validateTestClaim(value, claimPath) {
|
|
|
3334
3621
|
array(m.processes);
|
|
3335
3622
|
unique(m.processes.map(item => item.id));
|
|
3336
3623
|
for (const proc of m.processes) {
|
|
3337
|
-
keys(proc, ['id', 'role', 'stage', 'pid', 'pgid', 'startTime', 'host', 'profilePath']);
|
|
3624
|
+
keys(proc, ['id', 'role', 'stage', 'pid', 'pgid', 'containment', 'jobId', 'startTime', 'host', 'profilePath']);
|
|
3338
3625
|
label(proc.id);
|
|
3339
3626
|
oneOf(proc.role, ['guardian', 'browser', 'cleanup']);
|
|
3340
3627
|
if (proc.host !== undefined) text(proc.host);
|
|
3341
3628
|
oneOf(proc.stage, ['pending', 'registered', 'drained']);
|
|
3629
|
+
if (proc.containment !== undefined) oneOf(proc.containment, ['windows-job']);
|
|
3630
|
+
if (proc.containment === 'windows-job') {
|
|
3631
|
+
if (proc.pgid !== undefined || proc.role !== 'guardian' || proc.profilePath !== undefined) throw new Error('Invalid Windows test claim containment');
|
|
3632
|
+
text(proc.jobId);
|
|
3633
|
+
if (!/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/.test(proc.jobId)) throw new Error('Invalid Windows test claim job identity');
|
|
3634
|
+
} else if (proc.jobId !== undefined) {
|
|
3635
|
+
throw new Error('Windows test claim job needs explicit containment');
|
|
3636
|
+
}
|
|
3342
3637
|
const hasIdentity = proc.pid !== undefined || proc.pgid !== undefined || proc.startTime !== undefined;
|
|
3343
3638
|
if (hasIdentity || proc.stage !== 'pending') {
|
|
3344
3639
|
integer(proc.pid, 1);
|
|
3345
|
-
integer(proc.pgid, 1);
|
|
3640
|
+
if (proc.containment !== 'windows-job') integer(proc.pgid, 1);
|
|
3346
3641
|
text(proc.startTime);
|
|
3642
|
+
if (proc.containment === 'windows-job') {
|
|
3643
|
+
if (!/^[1-9]\d{0,19}$/.test(proc.startTime)) throw new Error('Invalid Windows test claim process creation time');
|
|
3644
|
+
text(proc.host);
|
|
3645
|
+
}
|
|
3347
3646
|
}
|
|
3348
3647
|
if (proc.profilePath !== undefined) {
|
|
3349
3648
|
text(proc.profilePath);
|
|
@@ -3356,23 +3655,8 @@ function validateTestClaim(value, claimPath) {
|
|
|
3356
3655
|
for (const key of ['processes', 'databases', 'redis', 'locals']) bool(m.cleanup[key]);
|
|
3357
3656
|
return m;
|
|
3358
3657
|
}
|
|
3359
|
-
function assertPrivateFile(file) {
|
|
3360
|
-
assertTestClaimSafePath(file, false);
|
|
3361
|
-
const stat = lstatSync(file);
|
|
3362
|
-
if (!stat.isFile() || stat.nlink !== 1 || (stat.mode & 0o077) !== 0 || process.getuid && stat.uid !== process.getuid()) {
|
|
3363
|
-
throw new Error('Unsafe test claim file');
|
|
3364
|
-
}
|
|
3365
|
-
}
|
|
3366
3658
|
async function loadTestClaim(claimPath) {
|
|
3367
|
-
|
|
3368
|
-
const handle = await open(claimPath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
3369
|
-
try {
|
|
3370
|
-
const stat = await handle.stat();
|
|
3371
|
-
if (!stat.isFile() || stat.size > 4 * 1024 * 1024) throw new Error('Invalid test claim file');
|
|
3372
|
-
return validateTestClaim(parseTestClaimJson(await handle.readFile('utf8')), claimPath);
|
|
3373
|
-
} finally {
|
|
3374
|
-
await handle.close();
|
|
3375
|
-
}
|
|
3659
|
+
return validateTestClaim(parseTestClaimJson(await readTestClaimFile(claimPath)), claimPath);
|
|
3376
3660
|
}
|
|
3377
3661
|
function parseTestClaimJson(source) {
|
|
3378
3662
|
// Claim identities stay literal even when @cabloy/json5 revives ISO strings.
|
|
@@ -3380,31 +3664,13 @@ function parseTestClaimJson(source) {
|
|
|
3380
3664
|
return this[key];
|
|
3381
3665
|
});
|
|
3382
3666
|
}
|
|
3383
|
-
async function syncDirectory(directory) {
|
|
3384
|
-
const handle = await open(directory, constants.O_RDONLY);
|
|
3385
|
-
try {
|
|
3386
|
-
await handle.sync();
|
|
3387
|
-
} finally {
|
|
3388
|
-
await handle.close();
|
|
3389
|
-
}
|
|
3390
|
-
}
|
|
3391
3667
|
async function createTestClaim(projectPath, runId, kind, owner) {
|
|
3392
3668
|
const p = getTestClaimPaths(projectPath, runId);
|
|
3393
|
-
|
|
3394
|
-
await mkdir(p.claimDirectory, {
|
|
3395
|
-
mode: 0o700
|
|
3396
|
-
}).catch(error => {
|
|
3397
|
-
if (error.code !== 'EEXIST') throw error;
|
|
3398
|
-
});
|
|
3669
|
+
await ensureTestClaimPrivateDirectory(p.claimDirectory);
|
|
3399
3670
|
// The directory is shared across runs; an existing directory is valid, never an existing claim.
|
|
3400
3671
|
return createClaimFile(p, runId, kind, owner);
|
|
3401
3672
|
}
|
|
3402
3673
|
async function createClaimFile(p, runId, kind, owner) {
|
|
3403
|
-
assertTestClaimSafePath(p.claimDirectory, false);
|
|
3404
|
-
const directoryStat = lstatSync(p.claimDirectory);
|
|
3405
|
-
if (!directoryStat.isDirectory() || (directoryStat.mode & 0o077) !== 0 || process.getuid && directoryStat.uid !== process.getuid()) {
|
|
3406
|
-
throw new Error('Unsafe shared test claim directory');
|
|
3407
|
-
}
|
|
3408
3674
|
const manifest = {
|
|
3409
3675
|
version: 1,
|
|
3410
3676
|
runId,
|
|
@@ -3433,14 +3699,7 @@ async function createClaimFile(p, runId, kind, owner) {
|
|
|
3433
3699
|
}
|
|
3434
3700
|
};
|
|
3435
3701
|
validateTestClaim(manifest, p.claimPath);
|
|
3436
|
-
|
|
3437
|
-
try {
|
|
3438
|
-
await handle.writeFile(`${JSON.stringify(manifest, null, 2)}\n`);
|
|
3439
|
-
await handle.sync();
|
|
3440
|
-
} finally {
|
|
3441
|
-
await handle.close();
|
|
3442
|
-
}
|
|
3443
|
-
await syncDirectory(p.claimDirectory);
|
|
3702
|
+
await createTestClaimFile(p.claimPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
3444
3703
|
return {
|
|
3445
3704
|
claimPath: p.claimPath,
|
|
3446
3705
|
manifest
|
|
@@ -3454,23 +3713,7 @@ async function writeTestClaim(claimPath, manifest) {
|
|
|
3454
3713
|
for (const key of ['version', 'runId', 'createdAt', 'projectPath', 'kind', 'owner']) {
|
|
3455
3714
|
if (!isDeepStrictEqual(previous[key], manifest[key])) throw new Error('Test claim identity is immutable');
|
|
3456
3715
|
}
|
|
3457
|
-
|
|
3458
|
-
const handle = await open(temp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
3459
|
-
try {
|
|
3460
|
-
try {
|
|
3461
|
-
await handle.writeFile(`${JSON.stringify(manifest, null, 2)}\n`);
|
|
3462
|
-
await handle.sync();
|
|
3463
|
-
} finally {
|
|
3464
|
-
await handle.close();
|
|
3465
|
-
}
|
|
3466
|
-
assertPrivateFile(claimPath);
|
|
3467
|
-
await rename(temp, claimPath);
|
|
3468
|
-
await syncDirectory(path.dirname(claimPath));
|
|
3469
|
-
} finally {
|
|
3470
|
-
await unlink(temp).catch(error => {
|
|
3471
|
-
if (error.code !== 'ENOENT') throw error;
|
|
3472
|
-
});
|
|
3473
|
-
}
|
|
3716
|
+
await replaceTestClaimFile(claimPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
3474
3717
|
}
|
|
3475
3718
|
function applyEvent(m, event) {
|
|
3476
3719
|
record(event);
|
|
@@ -3497,7 +3740,9 @@ function applyEvent(m, event) {
|
|
|
3497
3740
|
if (event.process.stage !== 'pending') throw new Error('Process needs a write-ahead intent');
|
|
3498
3741
|
m.processes.push(event.process);
|
|
3499
3742
|
} else {
|
|
3500
|
-
if (old.role !== event.process.role
|
|
3743
|
+
if (old.role !== event.process.role || old.containment !== event.process.containment || old.jobId !== event.process.jobId) {
|
|
3744
|
+
throw new Error('Test claim process identity changed');
|
|
3745
|
+
}
|
|
3501
3746
|
if (event.process.profilePath !== undefined && old.profilePath !== event.process.profilePath) {
|
|
3502
3747
|
if (old.stage !== 'pending' || event.process.stage !== 'registered' || !old.profilePath || !event.process.profilePath.startsWith(`${old.profilePath}${path.sep}`)) {
|
|
3503
3748
|
throw new Error('Test claim process profile changed');
|
|
@@ -3578,11 +3823,79 @@ function applyEvent(m, event) {
|
|
|
3578
3823
|
}
|
|
3579
3824
|
validateTestClaim(m);
|
|
3580
3825
|
}
|
|
3826
|
+
// Native verifiers are controller-local capabilities, never HTTP registrations or journal data.
|
|
3827
|
+
const liveWindowsBrokers = new Map();
|
|
3828
|
+
function validateWindowsJobQuery(value) {
|
|
3829
|
+
keys(value, ['runId', 'guardianId', 'process']);
|
|
3830
|
+
const query = value;
|
|
3831
|
+
resolveTestRunId('test', query.runId);
|
|
3832
|
+
label(query.guardianId);
|
|
3833
|
+
keys(query.process, ['pid', 'startTime', 'host']);
|
|
3834
|
+
integer(query.process.pid, 1, 0xffffffff);
|
|
3835
|
+
text(query.process.startTime);
|
|
3836
|
+
if (!/^[1-9]\d{0,19}$/.test(query.process.startTime)) throw new Error('Invalid Windows containment creation time');
|
|
3837
|
+
text(query.process.host);
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
/** Only the controller hosting this authenticated broker can attach its sole native Job owner. */
|
|
3841
|
+
async function registerTestClaimWindowsJobVerifier(env, guardian, verify) {
|
|
3842
|
+
if (!hasTestClaimTransport(env)) throw new Error('Windows containment requires a claim broker');
|
|
3843
|
+
if (!resolveTestRunId(env.META_MODE, env.VONA_TEST_RUN_ID)) throw new Error('Windows containment requires test identity');
|
|
3844
|
+
const broker = liveWindowsBrokers.get(env[TEST_CLAIM_TOKEN_ENV]);
|
|
3845
|
+
if (!broker || broker.url !== env[TEST_CLAIM_URL_ENV]) throw new Error('Windows containment verifier must belong to the local claim broker');
|
|
3846
|
+
return await broker.register(guardian, verify);
|
|
3847
|
+
}
|
|
3581
3848
|
async function startTestClaimBroker(claimPath) {
|
|
3582
3849
|
await loadTestClaim(claimPath);
|
|
3583
3850
|
const token = randomBytes(32).toString('hex');
|
|
3584
3851
|
let queue = Promise.resolve();
|
|
3585
3852
|
let closing = false;
|
|
3853
|
+
const verifiers = new Map();
|
|
3854
|
+
let queries = 0;
|
|
3855
|
+
const containment = async query => {
|
|
3856
|
+
validateWindowsJobQuery(query);
|
|
3857
|
+
if (closing || queries >= 32) throw new Error('Windows containment verifier unavailable');
|
|
3858
|
+
queries++;
|
|
3859
|
+
try {
|
|
3860
|
+
await queue;
|
|
3861
|
+
const manifest = await loadTestClaim(claimPath);
|
|
3862
|
+
const live = verifiers.get(query.guardianId);
|
|
3863
|
+
const guardian = manifest.processes.find(item => item.id === query.guardianId);
|
|
3864
|
+
if (manifest.kind !== 'e2e' || manifest.runId !== query.runId || guardian?.stage !== 'registered' || guardian.role !== 'guardian' || guardian.containment !== 'windows-job' || guardian.host !== query.process.host || !live || !isDeepStrictEqual(live.guardian, guardian)) {
|
|
3865
|
+
throw new Error('Windows containment requires a registered live E2E guardian');
|
|
3866
|
+
}
|
|
3867
|
+
let timer;
|
|
3868
|
+
try {
|
|
3869
|
+
const verified = await Promise.race([live.verify(query.process), new Promise((_, reject) => {
|
|
3870
|
+
timer = setTimeout(() => reject(new Error('Windows containment query timed out')), 5000);
|
|
3871
|
+
})]);
|
|
3872
|
+
await queue;
|
|
3873
|
+
const current = await loadTestClaim(claimPath);
|
|
3874
|
+
if (!verified || closing || verifiers.get(query.guardianId) !== live || !isDeepStrictEqual(current.processes.find(item => item.id === query.guardianId), guardian)) {
|
|
3875
|
+
throw new Error('Windows process is not in the designated live Job');
|
|
3876
|
+
}
|
|
3877
|
+
} finally {
|
|
3878
|
+
clearTimeout(timer);
|
|
3879
|
+
}
|
|
3880
|
+
} finally {
|
|
3881
|
+
queries--;
|
|
3882
|
+
}
|
|
3883
|
+
};
|
|
3884
|
+
const register = async (guardian, verify) => {
|
|
3885
|
+
await queue;
|
|
3886
|
+
const manifest = await loadTestClaim(claimPath);
|
|
3887
|
+
if (closing || guardian.role !== 'guardian' || guardian.stage !== 'registered' || guardian.containment !== 'windows-job' || typeof verify !== 'function' || verifiers.has(guardian.id) || !isDeepStrictEqual(manifest.processes.find(item => item.id === guardian.id), guardian)) {
|
|
3888
|
+
throw new Error('Windows containment verifier needs a durable registered guardian');
|
|
3889
|
+
}
|
|
3890
|
+
const live = {
|
|
3891
|
+
guardian: structuredClone(guardian),
|
|
3892
|
+
verify
|
|
3893
|
+
};
|
|
3894
|
+
verifiers.set(guardian.id, live);
|
|
3895
|
+
return () => {
|
|
3896
|
+
if (verifiers.get(guardian.id) === live) verifiers.delete(guardian.id);
|
|
3897
|
+
};
|
|
3898
|
+
};
|
|
3586
3899
|
const update = event => {
|
|
3587
3900
|
if (closing) return Promise.reject(new Error('Test claim broker is closed'));
|
|
3588
3901
|
const result = queue.then(async () => {
|
|
@@ -3596,7 +3909,7 @@ async function startTestClaimBroker(claimPath) {
|
|
|
3596
3909
|
const server = createServer(async (req, res) => {
|
|
3597
3910
|
const auth = req.headers.authorization;
|
|
3598
3911
|
const expected = `Bearer ${token}`;
|
|
3599
|
-
if (req.method !== 'POST' ||
|
|
3912
|
+
if (req.method !== 'POST' || !['/event', '/containment'].includes(req.url) || typeof auth !== 'string' || Buffer.byteLength(auth) !== Buffer.byteLength(expected) || !timingSafeEqual(Buffer.from(auth), Buffer.from(expected))) {
|
|
3600
3913
|
res.writeHead(403).end();
|
|
3601
3914
|
req.resume();
|
|
3602
3915
|
return;
|
|
@@ -3607,7 +3920,7 @@ async function startTestClaimBroker(claimPath) {
|
|
|
3607
3920
|
body += chunk.toString('utf8');
|
|
3608
3921
|
if (Buffer.byteLength(body) > 1024 * 1024) throw new Error('Test claim event too large');
|
|
3609
3922
|
}
|
|
3610
|
-
await update(parseTestClaimJson(body));
|
|
3923
|
+
if (req.url === '/containment') await containment(parseTestClaimJson(body));else await update(parseTestClaimJson(body));
|
|
3611
3924
|
res.writeHead(204).end();
|
|
3612
3925
|
} catch {
|
|
3613
3926
|
res.writeHead(409).end('Test claim registration rejected');
|
|
@@ -3621,14 +3934,21 @@ async function startTestClaimBroker(claimPath) {
|
|
|
3621
3934
|
});
|
|
3622
3935
|
const address = server.address();
|
|
3623
3936
|
if (!address || typeof address === 'string') throw new Error('Cannot bind test claim broker');
|
|
3937
|
+
const url = `http://127.0.0.1:${address.port}/event`;
|
|
3938
|
+
liveWindowsBrokers.set(token, {
|
|
3939
|
+
url,
|
|
3940
|
+
register
|
|
3941
|
+
});
|
|
3624
3942
|
return {
|
|
3625
3943
|
env: {
|
|
3626
|
-
[TEST_CLAIM_URL_ENV]:
|
|
3944
|
+
[TEST_CLAIM_URL_ENV]: url,
|
|
3627
3945
|
[TEST_CLAIM_TOKEN_ENV]: token
|
|
3628
3946
|
},
|
|
3629
3947
|
update,
|
|
3630
3948
|
async close() {
|
|
3631
3949
|
closing = true;
|
|
3950
|
+
liveWindowsBrokers.delete(token);
|
|
3951
|
+
verifiers.clear();
|
|
3632
3952
|
await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve()));
|
|
3633
3953
|
await queue;
|
|
3634
3954
|
}
|
|
@@ -3669,6 +3989,36 @@ async function sendTestClaimEvent(env, event) {
|
|
|
3669
3989
|
throw new Error('Managed test allocation registration failed');
|
|
3670
3990
|
}
|
|
3671
3991
|
}
|
|
3992
|
+
|
|
3993
|
+
/** A transient authenticated gate: success is live exact membership, never a durable process event. */
|
|
3994
|
+
async function assertTestClaimWindowsJob(env, identity) {
|
|
3995
|
+
try {
|
|
3996
|
+
if (!hasTestClaimTransport(env)) throw new Error('Missing test claim transport');
|
|
3997
|
+
const query = {
|
|
3998
|
+
runId: env.VONA_TEST_RUN_ID,
|
|
3999
|
+
guardianId: env[TEST_CLAIM_WINDOWS_GUARDIAN_ENV],
|
|
4000
|
+
process: {
|
|
4001
|
+
pid: identity.pid,
|
|
4002
|
+
startTime: identity.startTime,
|
|
4003
|
+
host: identity.host
|
|
4004
|
+
}
|
|
4005
|
+
};
|
|
4006
|
+
validateWindowsJobQuery(query);
|
|
4007
|
+
const response = await fetch(new URL('/containment', env[TEST_CLAIM_URL_ENV]), {
|
|
4008
|
+
method: 'POST',
|
|
4009
|
+
headers: {
|
|
4010
|
+
'authorization': `Bearer ${env[TEST_CLAIM_TOKEN_ENV]}`,
|
|
4011
|
+
'content-type': 'application/json'
|
|
4012
|
+
},
|
|
4013
|
+
body: JSON.stringify(query),
|
|
4014
|
+
signal: AbortSignal.timeout(7000),
|
|
4015
|
+
redirect: 'error'
|
|
4016
|
+
});
|
|
4017
|
+
if (response.status !== 204) throw new Error('Containment rejected');
|
|
4018
|
+
} catch {
|
|
4019
|
+
throw new Error('Managed Windows browser containment verification failed');
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
3672
4022
|
function getTestClaimRedisPrefix(runId, clientName) {
|
|
3673
4023
|
const appName = getTestAppName(runId);
|
|
3674
4024
|
if (clientName === 'broadcast') return undefined;
|
|
@@ -4325,13 +4675,16 @@ async function _closeInner() {
|
|
|
4325
4675
|
clearTimeout(timeout);
|
|
4326
4676
|
process.exit(err ? 1 : 0);
|
|
4327
4677
|
}
|
|
4678
|
+
|
|
4679
|
+
// The authenticated test health endpoint uses the same guard and cleanup as signals.
|
|
4680
|
+
async function closeProcessWorker() {
|
|
4681
|
+
if (__closing) return;
|
|
4682
|
+
__closing = true;
|
|
4683
|
+
await _closeInner();
|
|
4684
|
+
}
|
|
4328
4685
|
function handleProcessWork() {
|
|
4329
4686
|
['SIGINT', 'SIGTERM', 'SIGUSR2'].forEach(signal => {
|
|
4330
|
-
process.on(signal,
|
|
4331
|
-
if (__closing) return;
|
|
4332
|
-
__closing = true;
|
|
4333
|
-
await _closeInner();
|
|
4334
|
-
});
|
|
4687
|
+
process.on(signal, closeProcessWorker);
|
|
4335
4688
|
});
|
|
4336
4689
|
process.on('uncaughtException', async err => {
|
|
4337
4690
|
const app = useApp();
|
|
@@ -4492,5 +4845,5 @@ async function retry(options, fn) {
|
|
|
4492
4845
|
|
|
4493
4846
|
zodExtendOpenApi();
|
|
4494
4847
|
|
|
4495
|
-
export { $Class, $localeScope, $makeLocaleMagic, $protocolKey, AppHmr, AppHmrDeps, AppLocale, AppLogger, AppMeta, AppMetadata, AppResource, AppUtil, BeanAopBase, BeanAopMethodBase, BeanBase, BeanBaseSimple, BeanContainer, BeanInfo, BeanScopeBase, BeanScopeContainer, BeanScopeError, BeanScopeErrorImpl, BeanScopeLocale, BeanScopeScene, BeanScopeUtil, BeanSimple, EnumAppEvent, ErrorClass, Global, LocaleModuleNameSeparator, PickClassInner, ProxyDisable, SymbolBeanContainerInstances, SymbolBeanFullName, SymbolBeanInstanceKey, SymbolBeanInstancePropsLazy, SymbolCacheAopChains, SymbolCacheAopChainsKey, SymbolDecoratorBeanFullName, SymbolDecoratorBeanInfo, SymbolDecoratorGlobal, SymbolDecoratorProxyDisable, SymbolDecoratorUse, SymbolDecoratorVirtual, SymbolHmrStateLoad, SymbolHmrStateSave, SymbolMappedClassMetadataKeys, SymbolModuleBelong, SymbolModuleName, TEST_CLAIM_DIRECTORY, TEST_CLAIM_TOKEN_ENV, TEST_CLAIM_URL_ENV, TEST_RUN_ID_ENV, TEST_RUN_OWNER_FILE, Use, Virtual, VonaApplication, __prepareInjectSelectorInfo, appHmrDeps, appMetadata, appResource, assertDisposableDatabaseName, assertIsolatedTestConfig, assertIsolatedTestDatabaseClient, assertIsolatedTestPath, assertTestAppIdentity, assertTestClaimDatabaseClient, assertTestClaimRedisClient, assertTestClaimSafePath, assertTestRunOwner, beanFullNameFromOnionName, bootstrap, buildTestClaimResourceInventory, cast, closeApp, combineConfigDefault, combineFilePathSafe, compose, copyAddon, copyMetadataOfClasses, copyProperties, copyPropertiesOfClasses, createApp, createAppMaster, createBeanDecorator, createGeneralApp, createHash, createTestClaim, deepExtend, disposeInstance, errorsInternal, filterHeaders, formatLoggerAxiosError, formatLoggerConsole, formatLoggerCtx, formatLoggerDummy, formatLoggerErrors, formatLoggerFilter, functionNoop, getDatabaseTestPrefix, getHomeVonaAppDir, getLoggerPathPhysicalRoot, getMappedClassMetadataKeys, getPlatformArch, getPublicPathPhysicalRoot, getRuntimePathPhysicalRoot, getSqlite3DatabaseNameDefault, getTestAppName, getTestClaimCreatedAt, getTestClaimPaths, getTestClaimRedisPrefix, getTestRunIdFromEnv, hasTestClaimTransport, instanceDesp, isLocaleMagic, loadJSONFile, loadTestClaim, mergeTestClaimDatabaseOptions, mergeTestClaimRedisOptions, normalizeTestClaimDatabaseEndpoint, normalizeTestClaimRedisEndpoint, onionNameFromBeanFullName, pathToHref, polyfillDispose, prepareEnv, registerMappedClassMetadataKey, registerTestClaimDatabaseCreation, registerTestClaimResourceInventory, requireAddon, requireDynamic, resolveAddon, resolveTestRunId, resolveVonaLocalPaths, resolverSharp, resolverSharpLibvips, resolverSqlite3, retry, saveJSONFile, sendTestClaimEvent, setMappedClassMetadataKeys, startTestClaimBroker, text$1 as text, useApp, usePrepareArg, usePrepareArgs, uuidv4, validateTestClaim, withIsolatedTestDatabaseDiscovery, writeTestClaim };
|
|
4848
|
+
export { $Class, $localeScope, $makeLocaleMagic, $protocolKey, AppHmr, AppHmrDeps, AppLocale, AppLogger, AppMeta, AppMetadata, AppResource, AppUtil, BeanAopBase, BeanAopMethodBase, BeanBase, BeanBaseSimple, BeanContainer, BeanInfo, BeanScopeBase, BeanScopeContainer, BeanScopeError, BeanScopeErrorImpl, BeanScopeLocale, BeanScopeScene, BeanScopeUtil, BeanSimple, EnumAppEvent, ErrorClass, Global, LocaleModuleNameSeparator, PickClassInner, ProxyDisable, SymbolBeanContainerInstances, SymbolBeanFullName, SymbolBeanInstanceKey, SymbolBeanInstancePropsLazy, SymbolCacheAopChains, SymbolCacheAopChainsKey, SymbolDecoratorBeanFullName, SymbolDecoratorBeanInfo, SymbolDecoratorGlobal, SymbolDecoratorProxyDisable, SymbolDecoratorUse, SymbolDecoratorVirtual, SymbolHmrStateLoad, SymbolHmrStateSave, SymbolMappedClassMetadataKeys, SymbolModuleBelong, SymbolModuleName, TEST_CLAIM_DIRECTORY, TEST_CLAIM_TOKEN_ENV, TEST_CLAIM_URL_ENV, TEST_CLAIM_WINDOWS_GUARDIAN_ENV, TEST_RUN_ID_ENV, TEST_RUN_OWNER_FILE, Use, Virtual, VonaApplication, __prepareInjectSelectorInfo, appHmrDeps, appMetadata, appResource, assertDisposableDatabaseName, assertIsolatedTestConfig, assertIsolatedTestDatabaseClient, assertIsolatedTestPath, assertTestAppIdentity, assertTestClaimDatabaseClient, assertTestClaimRedisClient, assertTestClaimSafePath, assertTestClaimWindowsJob, assertTestRunOwner, beanFullNameFromOnionName, bootstrap, buildTestClaimResourceInventory, cast, closeApp, closeProcessWorker, combineConfigDefault, combineFilePathSafe, compose, copyAddon, copyMetadataOfClasses, copyProperties, copyPropertiesOfClasses, createApp, createAppMaster, createBeanDecorator, createGeneralApp, createHash, createTestClaim, deepExtend, disposeInstance, errorsInternal, filterHeaders, formatLoggerAxiosError, formatLoggerConsole, formatLoggerCtx, formatLoggerDummy, formatLoggerErrors, formatLoggerFilter, functionNoop, getDatabaseTestPrefix, getHomeVonaAppDir, getLoggerPathPhysicalRoot, getMappedClassMetadataKeys, getPlatformArch, getPublicPathPhysicalRoot, getRuntimePathPhysicalRoot, getSqlite3DatabaseNameDefault, getTestAppName, getTestClaimCreatedAt, getTestClaimPaths, getTestClaimRedisPrefix, getTestRunIdFromEnv, hasTestClaimTransport, instanceDesp, isLocaleMagic, loadJSONFile, loadTestClaim, mergeTestClaimDatabaseOptions, mergeTestClaimRedisOptions, normalizeTestClaimDatabaseEndpoint, normalizeTestClaimRedisEndpoint, onionNameFromBeanFullName, pathToHref, polyfillDispose, prepareEnv, registerMappedClassMetadataKey, registerTestClaimDatabaseCreation, registerTestClaimResourceInventory, registerTestClaimWindowsJobVerifier, requireAddon, requireDynamic, resolveAddon, resolveTestRunId, resolveVonaLocalPaths, resolverSharp, resolverSharpLibvips, resolverSqlite3, retry, saveJSONFile, sendTestClaimEvent, setMappedClassMetadataKeys, startTestClaimBroker, text$1 as text, useApp, usePrepareArg, usePrepareArgs, uuidv4, validateTestClaim, withIsolatedTestDatabaseDiscovery, writeTestClaim };
|
|
4496
4849
|
//# sourceMappingURL=index.js.map
|