vouchington-tooling 0.0.4 → 0.0.6

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.
Files changed (52) hide show
  1. package/README.md +10 -0
  2. package/dist/cli/commands/allocate-browser-safe-ports.slot-fixtures.test-helpers.d.mts +6 -0
  3. package/dist/cli/commands/allocate-browser-safe-ports.slot-fixtures.test-helpers.mjs +103 -0
  4. package/dist/cli/commands/github-output.test-helpers.d.mts +1 -0
  5. package/dist/cli/commands/github-output.test-helpers.mjs +32 -0
  6. package/dist/cli/commands/pnpm-install.d.mts +1 -0
  7. package/dist/cli/commands/pnpm-install.mjs +27 -0
  8. package/dist/cli/commands/spawn-script.d.mts +5 -0
  9. package/dist/cli/commands/spawn-script.mjs +7 -0
  10. package/dist/cli/commands/vitest-blob-manifest.d.mts +1 -0
  11. package/dist/cli/commands/vitest-blob-manifest.mjs +11 -0
  12. package/dist/cli/index.mjs +28 -0
  13. package/dist/cli/parse.d.mts +11 -0
  14. package/dist/cli/parse.mjs +14 -0
  15. package/dist/cli/script-path.d.mts +1 -0
  16. package/dist/cli/script-path.mjs +4 -0
  17. package/dist/cli/usage.d.mts +1 -1
  18. package/dist/cli/usage.mjs +16 -1
  19. package/dist/index.d.mts +6 -0
  20. package/dist/index.mjs +3 -0
  21. package/dist/pnpm-install/exec.d.mts +8 -0
  22. package/dist/pnpm-install/exec.mjs +88 -0
  23. package/dist/pnpm-install/index.d.mts +7 -0
  24. package/dist/pnpm-install/index.mjs +6 -0
  25. package/dist/pnpm-install/metadata.d.mts +5 -0
  26. package/dist/pnpm-install/metadata.mjs +91 -0
  27. package/dist/pnpm-install/pnpm-install-fixture.test-helpers.d.mts +22 -0
  28. package/dist/pnpm-install/pnpm-install-fixture.test-helpers.mjs +174 -0
  29. package/dist/pnpm-install/process.d.mts +11 -0
  30. package/dist/pnpm-install/process.mjs +81 -0
  31. package/dist/pnpm-install/release-age.d.mts +9 -0
  32. package/dist/pnpm-install/release-age.mjs +59 -0
  33. package/dist/pnpm-install/runner.d.mts +2 -0
  34. package/dist/pnpm-install/runner.mjs +106 -0
  35. package/dist/pnpm-install/support.d.mts +30 -0
  36. package/dist/pnpm-install/support.mjs +143 -0
  37. package/dist/shared-context/fake-git.test-helpers.d.mts +11 -0
  38. package/dist/shared-context/fake-git.test-helpers.mjs +59 -0
  39. package/dist/shared-context/index.d.mts +26 -0
  40. package/dist/shared-context/index.mjs +89 -0
  41. package/dist/vitest-blob-manifest/cli.d.mts +2 -0
  42. package/dist/vitest-blob-manifest/cli.mjs +33 -0
  43. package/dist/vitest-blob-manifest/index.d.mts +37 -0
  44. package/dist/vitest-blob-manifest/index.mjs +134 -0
  45. package/package.json +16 -1
  46. package/scripts/allocate-browser-safe-ports.py +661 -0
  47. package/scripts/fetch-forbidden-ports.json +7 -0
  48. package/scripts/gha/check-needs-results.sh +19 -0
  49. package/scripts/gha/download-with-diagnostics.sh +52 -0
  50. package/scripts/gha/host-pressure-diagnostics.sh +179 -0
  51. package/scripts/gha/write-github-multiline-output.sh +60 -0
  52. package/scripts/runner-port-policy.json +7 -0
@@ -0,0 +1,59 @@
1
+ import { chmodSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ const FAKE_GIT_INSIDE = 'FAKE_GIT_INSIDE';
4
+ const FAKE_GIT_ROOT = 'FAKE_GIT_ROOT';
5
+ const FAKE_GIT_FILES = 'FAKE_GIT_FILES';
6
+ const FAKE_GIT_LS_FILES_EXIT_CODE = 'FAKE_GIT_LS_FILES_EXIT_CODE';
7
+ const FAKE_GIT_LS_FILES_STDERR = 'FAKE_GIT_LS_FILES_STDERR';
8
+ export function installFakeGit({ binDir, isInsideWorkTree = true, lsFilesExitCode = 0, lsFilesStderr = '', pathPrefix = process.env.PATH, repoRoot, trackedFiles = [], }) {
9
+ mkdirSync(binDir, { recursive: true });
10
+ writeFileSync(join(binDir, 'git'), fakeGitScript());
11
+ chmodSync(join(binDir, 'git'), 0o755);
12
+ process.env.PATH = [binDir, pathPrefix].filter(Boolean).join(':');
13
+ process.env[FAKE_GIT_INSIDE] = String(isInsideWorkTree);
14
+ process.env[FAKE_GIT_LS_FILES_EXIT_CODE] = String(lsFilesExitCode);
15
+ process.env[FAKE_GIT_LS_FILES_STDERR] = lsFilesStderr;
16
+ if (repoRoot !== undefined)
17
+ process.env[FAKE_GIT_ROOT] = repoRoot;
18
+ process.env[FAKE_GIT_FILES] = [...trackedFiles].toSorted().join('\n');
19
+ }
20
+ export function clearFakeGitEnv() {
21
+ process.env.FAKE_GIT_INSIDE = 'false';
22
+ process.env.FAKE_GIT_ROOT = '';
23
+ process.env.FAKE_GIT_FILES = '';
24
+ process.env.FAKE_GIT_LS_FILES_EXIT_CODE = '';
25
+ process.env.FAKE_GIT_LS_FILES_STDERR = '';
26
+ }
27
+ function fakeGitScript() {
28
+ return [
29
+ '#!/usr/bin/env bash',
30
+ 'set -euo pipefail',
31
+ 'if [ "${1:-}" = "-C" ]; then',
32
+ ' shift 2',
33
+ 'fi',
34
+ 'case "${1:-} ${2:-}" in',
35
+ ' "rev-parse --is-inside-work-tree")',
36
+ ' [ "${FAKE_GIT_INSIDE:-false}" = "true" ]',
37
+ ' ;;',
38
+ ' "rev-parse --show-toplevel")',
39
+ ' printf \'%s\\n\' "${FAKE_GIT_ROOT:?}"',
40
+ ' ;;',
41
+ ' "ls-files -z"|"ls-files " )',
42
+ ' if [ "${FAKE_GIT_LS_FILES_EXIT_CODE:-0}" -ne 0 ]; then',
43
+ ' printf \'%s\' "${FAKE_GIT_LS_FILES_STDERR:-}" >&2',
44
+ ' exit "${FAKE_GIT_LS_FILES_EXIT_CODE}"',
45
+ ' fi',
46
+ ' printf \'%s\\n\' "${FAKE_GIT_FILES:-}" | while IFS= read -r file; do',
47
+ ' if [ -n "$file" ]; then',
48
+ String.raw ` printf '%s\0' "$file"`,
49
+ ' fi',
50
+ ' done',
51
+ ' ;;',
52
+ ' *)',
53
+ String.raw ` printf 'unexpected fake git invocation: %s\n' "$*" >&2`,
54
+ ' exit 2',
55
+ ' ;;',
56
+ 'esac',
57
+ '',
58
+ ].join('\n');
59
+ }
@@ -0,0 +1,26 @@
1
+ export declare function gitEnv(): NodeJS.ProcessEnv;
2
+ export interface SharedContext {
3
+ repoRoot: string;
4
+ isInsideGitRepo: boolean;
5
+ trackedFiles: readonly string[];
6
+ trackedFileSet: ReadonlySet<string>;
7
+ /** Lazily reads tracked files and shares the result across policy visitors. */
8
+ readTrackedFile?: (file: string) => string | null;
9
+ }
10
+ export declare function buildContextFromTrackedFiles(repoRoot: string, trackedFiles: readonly string[]): SharedContext;
11
+ export type NamedCheck = {
12
+ name: string;
13
+ run: (ctx: SharedContext) => Promise<{
14
+ errors: string[];
15
+ fixes?: string[];
16
+ }> | {
17
+ errors: string[];
18
+ fixes?: string[];
19
+ };
20
+ };
21
+ export declare function runNamedChecks(repoRoot: string, checks: readonly NamedCheck[]): Promise<Array<{
22
+ name: string;
23
+ errors: string[];
24
+ fixes?: string[];
25
+ }>>;
26
+ export declare function buildSharedContext(inputRoot: string): Promise<SharedContext>;
@@ -0,0 +1,89 @@
1
+ import { execFile, spawn } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { promisify } from 'node:util';
5
+ const execFileAsync = promisify(execFile);
6
+ export function gitEnv() {
7
+ return Object.fromEntries(Object.entries(process.env).filter(([k]) => !k.startsWith('GIT_')));
8
+ }
9
+ async function listTrackedFiles(repoRoot) {
10
+ const lsOutput = await new Promise((resolve, reject) => {
11
+ const proc = spawn('git', ['-C', repoRoot, 'ls-files', '-z'], { env: gitEnv(), stdio: 'pipe' });
12
+ const chunks = [];
13
+ const errChunks = [];
14
+ proc.stdout.on('data', (d) => chunks.push(d));
15
+ proc.stderr.on('data', (d) => errChunks.push(d));
16
+ proc.on('error', reject);
17
+ proc.on('close', (code) => {
18
+ if (code !== 0) {
19
+ reject(new Error(`git ls-files failed (exit ${code}): ${Buffer.concat(errChunks).toString()}`));
20
+ return;
21
+ }
22
+ resolve(Buffer.concat(chunks).toString());
23
+ });
24
+ });
25
+ return lsOutput.split('\0').filter(Boolean);
26
+ }
27
+ // Builds the caches/helpers around an already-known tracked-file list, without spawning `git
28
+ // ls-files` again. Split out from buildSharedContext() so a caller that already has the list
29
+ // (e.g. a worker_threads worker whose parent already paid the spawn cost — worker_threads doesn't
30
+ // share module-level JS state across threads, so the cache above can't be shared directly) can
31
+ // reuse it instead of re-spawning `git ls-files` in its own process.
32
+ export function buildContextFromTrackedFiles(repoRoot, trackedFiles) {
33
+ const trackedFileSet = new Set(trackedFiles);
34
+ const contents = new Map();
35
+ const readTrackedFile = (file) => {
36
+ if (!trackedFileSet.has(file))
37
+ return null;
38
+ const cached = contents.get(file);
39
+ if (cached !== undefined)
40
+ return cached;
41
+ try {
42
+ const content = readFileSync(join(repoRoot, file), 'utf8');
43
+ contents.set(file, content);
44
+ return content;
45
+ }
46
+ catch {
47
+ contents.set(file, null);
48
+ return null;
49
+ }
50
+ };
51
+ return {
52
+ repoRoot,
53
+ isInsideGitRepo: true,
54
+ trackedFiles,
55
+ trackedFileSet,
56
+ readTrackedFile,
57
+ };
58
+ }
59
+ export async function runNamedChecks(repoRoot, checks) {
60
+ const ctx = await buildSharedContext(repoRoot);
61
+ return Promise.all(checks.map(async (check) => {
62
+ const result = await check.run(ctx);
63
+ return { name: check.name, ...result };
64
+ }));
65
+ }
66
+ export async function buildSharedContext(inputRoot) {
67
+ // Run rev-parse checks first
68
+ try {
69
+ await execFileAsync('git', ['-C', inputRoot, 'rev-parse', '--is-inside-work-tree'], {
70
+ env: gitEnv(),
71
+ });
72
+ }
73
+ catch {
74
+ return {
75
+ repoRoot: inputRoot,
76
+ isInsideGitRepo: false,
77
+ trackedFiles: [],
78
+ trackedFileSet: new Set(),
79
+ };
80
+ }
81
+ // Get resolved root first, then use it to list files (so paths are always relative to repo root)
82
+ const rootResult = await execFileAsync('git', ['-C', inputRoot, 'rev-parse', '--show-toplevel'], {
83
+ encoding: 'utf8',
84
+ env: gitEnv(),
85
+ });
86
+ const repoRoot = rootResult.stdout.trim();
87
+ const trackedFiles = await listTrackedFiles(repoRoot);
88
+ return buildContextFromTrackedFiles(repoRoot, trackedFiles);
89
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runVitestBlobManifestCli(args: readonly string[], env?: NodeJS.ProcessEnv, revision?: string): void;
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync } from 'node:child_process';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { writeVitestBlobManifest } from './index.mjs';
5
+ function failRepository() {
6
+ throw new Error('GITHUB_REPOSITORY is required');
7
+ }
8
+ export function runVitestBlobManifestCli(args, env = process.env, revision = execFileSync('git', ['rev-parse', 'HEAD'], {
9
+ encoding: 'utf8',
10
+ stdio: ['ignore', 'pipe', 'ignore'],
11
+ }).trim()) {
12
+ const [suite, directory = '.vitest-reports', ...extra] = args;
13
+ const runId = env.GITHUB_RUN_ID;
14
+ const rawAttempt = env.GITHUB_RUN_ATTEMPT;
15
+ if (!suite || extra.length > 0 || !runId || !rawAttempt) {
16
+ throw new Error('Usage: vouchington vitest-blob-manifest <suite> [reports-directory]');
17
+ }
18
+ const runAttempt = Number(rawAttempt);
19
+ if (!Number.isSafeInteger(runAttempt) || runAttempt < 1) {
20
+ throw new Error('GITHUB_RUN_ATTEMPT must be a positive integer');
21
+ }
22
+ writeVitestBlobManifest(directory, {
23
+ suite,
24
+ repository: env.GITHUB_REPOSITORY || failRepository(),
25
+ revision,
26
+ runId,
27
+ runAttempt,
28
+ });
29
+ }
30
+ /* v8 ignore next 3 -- exercised as an executable by the composite action contract */
31
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
32
+ runVitestBlobManifestCli(process.argv.slice(2));
33
+ }
@@ -0,0 +1,37 @@
1
+ export declare const VITEST_BLOB_MANIFEST_FILENAME = "vitest-blob-manifest.json";
2
+ export declare const VITEST_BLOB_MANIFEST_VERSION = "vitest-blob-manifest:v1";
3
+ export declare const VITEST_SUITE_PATTERN: RegExp;
4
+ export interface VitestBlobManifest {
5
+ readonly version: typeof VITEST_BLOB_MANIFEST_VERSION;
6
+ readonly suite: string;
7
+ readonly repository: string;
8
+ readonly revision: string;
9
+ readonly run: {
10
+ readonly id: string;
11
+ readonly attempt: number;
12
+ };
13
+ readonly report: {
14
+ readonly filename: string;
15
+ readonly byteLength: number;
16
+ readonly sha256: string;
17
+ };
18
+ }
19
+ export interface VitestBlobIdentity {
20
+ readonly suite: string;
21
+ readonly repository: string;
22
+ readonly revision: string;
23
+ readonly runId: string;
24
+ readonly runAttempt: number;
25
+ }
26
+ export interface InspectedVitestBlobBundle {
27
+ readonly directory: string;
28
+ readonly manifest: VitestBlobManifest;
29
+ readonly manifestBytes: Buffer;
30
+ readonly reportBytes: Buffer;
31
+ }
32
+ export declare function parseVitestBlobManifest(raw: unknown): VitestBlobManifest;
33
+ export declare function createVitestBlobManifest(identity: VitestBlobIdentity, reportBytes: Buffer): VitestBlobManifest;
34
+ export declare function serializeVitestBlobManifest(manifest: VitestBlobManifest): Buffer;
35
+ export declare function writeVitestBlobManifest(directory: string, identity: VitestBlobIdentity): string;
36
+ export declare function vitestBlobBundlePaths(directory: string, suite: string): readonly [string, string];
37
+ export declare function inspectVitestBlobBundle(directory: string): InspectedVitestBlobBundle;
@@ -0,0 +1,134 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { lstatSync, readFileSync, readdirSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
3
+ import { basename, join } from 'node:path';
4
+ export const VITEST_BLOB_MANIFEST_FILENAME = 'vitest-blob-manifest.json';
5
+ export const VITEST_BLOB_MANIFEST_VERSION = 'vitest-blob-manifest:v1';
6
+ export const VITEST_SUITE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
7
+ function isRecord(value) {
8
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
9
+ }
10
+ function hasExactKeys(value, keys) {
11
+ return Object.keys(value).toSorted().join('\0') === keys.toSorted().join('\0');
12
+ }
13
+ function isPositiveInteger(value) {
14
+ return Number.isSafeInteger(value) && Number(value) > 0;
15
+ }
16
+ function assertRegularFile(path, label) {
17
+ if (!lstatSync(path).isFile())
18
+ throw new Error(`${label} must be a regular file`);
19
+ }
20
+ function sha256(bytes) {
21
+ return createHash('sha256').update(bytes).digest('hex');
22
+ }
23
+ export function parseVitestBlobManifest(raw) {
24
+ if (!isRecord(raw) ||
25
+ !hasExactKeys(raw, ['version', 'suite', 'repository', 'revision', 'run', 'report']) ||
26
+ raw.version !== VITEST_BLOB_MANIFEST_VERSION ||
27
+ typeof raw.suite !== 'string' ||
28
+ !VITEST_SUITE_PATTERN.test(raw.suite) ||
29
+ typeof raw.repository !== 'string' ||
30
+ !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(raw.repository) ||
31
+ typeof raw.revision !== 'string' ||
32
+ !/^[0-9a-f]{40}$/.test(raw.revision) ||
33
+ !isRecord(raw.run) ||
34
+ !hasExactKeys(raw.run, ['id', 'attempt']) ||
35
+ typeof raw.run.id !== 'string' ||
36
+ !/^[1-9][0-9]*$/.test(raw.run.id) ||
37
+ !isPositiveInteger(raw.run.attempt) ||
38
+ !isRecord(raw.report) ||
39
+ !hasExactKeys(raw.report, ['filename', 'byteLength', 'sha256']) ||
40
+ raw.report.filename !== `${raw.suite}.json` ||
41
+ !Number.isSafeInteger(raw.report.byteLength) ||
42
+ Number(raw.report.byteLength) < 0 ||
43
+ typeof raw.report.sha256 !== 'string' ||
44
+ !/^[0-9a-f]{64}$/.test(raw.report.sha256)) {
45
+ throw new Error('Vitest blob manifest has an invalid schema');
46
+ }
47
+ return raw;
48
+ }
49
+ export function createVitestBlobManifest(identity, reportBytes) {
50
+ return parseVitestBlobManifest({
51
+ version: VITEST_BLOB_MANIFEST_VERSION,
52
+ suite: identity.suite,
53
+ repository: identity.repository,
54
+ revision: identity.revision,
55
+ run: { id: identity.runId, attempt: identity.runAttempt },
56
+ report: {
57
+ filename: `${identity.suite}.json`,
58
+ byteLength: reportBytes.byteLength,
59
+ sha256: sha256(reportBytes),
60
+ },
61
+ });
62
+ }
63
+ export function serializeVitestBlobManifest(manifest) {
64
+ return Buffer.from(`${JSON.stringify(parseVitestBlobManifest(manifest), null, 2)}\n`);
65
+ }
66
+ export function writeVitestBlobManifest(directory, identity) {
67
+ if (!VITEST_SUITE_PATTERN.test(identity.suite))
68
+ throw new Error('Invalid Vitest suite');
69
+ const reportEntries = readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.name.endsWith('.json') && entry.name !== VITEST_BLOB_MANIFEST_FILENAME);
70
+ const reportEntry = reportEntries[0];
71
+ if (reportEntries.length !== 1 ||
72
+ reportEntry === undefined ||
73
+ reportEntry.name !== `${identity.suite}.json` ||
74
+ !reportEntry.isFile()) {
75
+ throw new Error(`Expected exactly one ${identity.suite}.json Vitest blob report`);
76
+ }
77
+ const reportPath = join(directory, `${identity.suite}.json`);
78
+ assertRegularFile(reportPath, 'Vitest blob report');
79
+ const bytes = serializeVitestBlobManifest(createVitestBlobManifest(identity, readFileSync(reportPath)));
80
+ const manifestPath = join(directory, VITEST_BLOB_MANIFEST_FILENAME);
81
+ const temporaryPath = join(directory, `.${VITEST_BLOB_MANIFEST_FILENAME}.${randomUUID()}.tmp`);
82
+ try {
83
+ writeFileSync(temporaryPath, bytes, { flag: 'wx', mode: 0o600 });
84
+ renameSync(temporaryPath, manifestPath);
85
+ }
86
+ finally {
87
+ try {
88
+ unlinkSync(temporaryPath);
89
+ }
90
+ catch {
91
+ // Successful rename removes the temporary path.
92
+ }
93
+ }
94
+ return manifestPath;
95
+ }
96
+ export function vitestBlobBundlePaths(directory, suite) {
97
+ if (!VITEST_SUITE_PATTERN.test(suite))
98
+ throw new Error('Invalid Vitest suite');
99
+ const manifestPath = join(directory, VITEST_BLOB_MANIFEST_FILENAME);
100
+ const reportPath = join(directory, `${suite}.json`);
101
+ assertRegularFile(manifestPath, 'Vitest blob manifest');
102
+ assertRegularFile(reportPath, 'Vitest blob report');
103
+ return [manifestPath, reportPath];
104
+ }
105
+ export function inspectVitestBlobBundle(directory) {
106
+ const entries = readdirSync(directory, { withFileTypes: true });
107
+ if (entries.length !== 2 || entries.some((entry) => !entry.isFile())) {
108
+ throw new Error(`Vitest blob bundle ${basename(directory)} must contain exactly two files`);
109
+ }
110
+ const manifestPath = join(directory, VITEST_BLOB_MANIFEST_FILENAME);
111
+ assertRegularFile(manifestPath, 'Vitest blob manifest');
112
+ const manifestBytes = readFileSync(manifestPath);
113
+ let manifest;
114
+ try {
115
+ manifest = parseVitestBlobManifest(JSON.parse(manifestBytes.toString('utf8')));
116
+ }
117
+ catch (error) {
118
+ throw new Error(`Invalid Vitest blob bundle ${basename(directory)}`, { cause: error });
119
+ }
120
+ const reportPath = join(directory, manifest.report.filename);
121
+ assertRegularFile(reportPath, 'Vitest blob report');
122
+ const reportBytes = readFileSync(reportPath);
123
+ if (reportBytes.byteLength !== manifest.report.byteLength ||
124
+ sha256(reportBytes) !== manifest.report.sha256) {
125
+ throw new Error(`Vitest blob report integrity check failed for ${manifest.suite}`);
126
+ }
127
+ try {
128
+ JSON.parse(reportBytes.toString('utf8'));
129
+ }
130
+ catch (error) {
131
+ throw new Error(`Vitest blob report is not valid JSON for ${manifest.suite}`, { cause: error });
132
+ }
133
+ return { directory, manifest, manifestBytes, reportBytes };
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vouchington-tooling",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Vouchington CLI and extractable tooling libraries.",
5
5
  "homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
6
6
  "bugs": {
@@ -50,6 +50,21 @@
50
50
  "import": "./dist/gha-runtime-audit/index.mjs",
51
51
  "default": "./dist/gha-runtime-audit/index.mjs"
52
52
  },
53
+ "./vitest-blob-manifest": {
54
+ "types": "./dist/vitest-blob-manifest/index.d.mts",
55
+ "import": "./dist/vitest-blob-manifest/index.mjs",
56
+ "default": "./dist/vitest-blob-manifest/index.mjs"
57
+ },
58
+ "./pnpm-install": {
59
+ "types": "./dist/pnpm-install/index.d.mts",
60
+ "import": "./dist/pnpm-install/index.mjs",
61
+ "default": "./dist/pnpm-install/index.mjs"
62
+ },
63
+ "./shared-context": {
64
+ "types": "./dist/shared-context/index.d.mts",
65
+ "import": "./dist/shared-context/index.mjs",
66
+ "default": "./dist/shared-context/index.mjs"
67
+ },
53
68
  "./package.json": "./package.json"
54
69
  },
55
70
  "publishConfig": {