vouchington-tooling 0.0.13 → 0.0.14

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 (44) hide show
  1. package/README.md +16 -2
  2. package/dist/ast-grep-rule/index.d.mts +13 -0
  3. package/dist/ast-grep-rule/index.mjs +43 -0
  4. package/dist/csv/index.d.mts +5 -0
  5. package/dist/csv/index.mjs +31 -0
  6. package/dist/gha-review-payload/diff.d.mts +30 -0
  7. package/dist/gha-review-payload/diff.mjs +121 -0
  8. package/dist/gha-review-payload/file.d.mts +7 -0
  9. package/dist/gha-review-payload/file.mjs +62 -0
  10. package/dist/gha-review-payload/index.d.mts +7 -0
  11. package/dist/gha-review-payload/index.mjs +4 -0
  12. package/dist/gha-review-payload/payload.d.mts +30 -0
  13. package/dist/gha-review-payload/payload.mjs +111 -0
  14. package/dist/gha-review-payload/remap.d.mts +13 -0
  15. package/dist/gha-review-payload/remap.mjs +89 -0
  16. package/dist/http-body/index.d.mts +18 -0
  17. package/dist/http-body/index.mjs +86 -0
  18. package/dist/http-link-pagination/index.d.mts +19 -0
  19. package/dist/http-link-pagination/index.mjs +149 -0
  20. package/dist/index.d.mts +16 -2
  21. package/dist/index.mjs +10 -1
  22. package/dist/pnpm-install/index.d.mts +2 -0
  23. package/dist/pnpm-install/index.mjs +1 -0
  24. package/dist/pnpm-install/release-age-policy-types.d.mts +34 -0
  25. package/dist/pnpm-install/release-age-policy-types.mjs +1 -0
  26. package/dist/pnpm-install/release-age-policy.d.mts +31 -0
  27. package/dist/pnpm-install/release-age-policy.mjs +136 -0
  28. package/dist/transient-retry/attempts.d.mts +5 -0
  29. package/dist/transient-retry/attempts.mjs +8 -0
  30. package/dist/transient-retry/decision-evaluator.d.mts +18 -0
  31. package/dist/transient-retry/decision-evaluator.mjs +56 -0
  32. package/dist/transient-retry/index.d.mts +4 -0
  33. package/dist/transient-retry/index.mjs +2 -0
  34. package/dist/transient-retry/types.d.mts +39 -0
  35. package/dist/transient-retry/types.mjs +1 -0
  36. package/dist/vitest-blob-manifest/constants.d.mts +1 -0
  37. package/dist/vitest-blob-manifest/constants.mjs +1 -0
  38. package/dist/vitest-blob-manifest/index.d.mts +2 -1
  39. package/dist/vitest-blob-manifest/index.mjs +3 -1
  40. package/dist/vitest-blob-manifest/report-attempt.d.mts +24 -0
  41. package/dist/vitest-blob-manifest/report-attempt.mjs +127 -0
  42. package/dist/vitest-blob-manifest/reports.d.mts +28 -0
  43. package/dist/vitest-blob-manifest/reports.mjs +160 -0
  44. package/package.json +38 -1
@@ -0,0 +1,39 @@
1
+ /** Provider-neutral context supplied to a transient-retry rule. */
2
+ export interface RetryContext {
3
+ /** The provider's current run attempt, starting at one. */
4
+ runAttempt: number;
5
+ /** A normalized attempt count shared by rules when provider attempts are sparse. */
6
+ retryAttempt?: number;
7
+ /** A normalized next-occurrence count for individual rules. */
8
+ retryAttempts?: ReadonlyMap<string, number>;
9
+ /** Targets that the provider resolved for this run. */
10
+ targetNames?: ReadonlySet<string>;
11
+ }
12
+ export type RetryDecision = 'rerun' | 'ignore' | 'fresh-plan' | 'reap-lock';
13
+ export type RetryTarget = {
14
+ targetName: string;
15
+ targetFamily?: never;
16
+ resolveTargetName?: never;
17
+ } | {
18
+ targetName?: never;
19
+ /** Static prefix shared by every dynamically named target in the family. */
20
+ targetFamily: string;
21
+ /** Resolves the exact target for this run, or null when it cannot be determined. */
22
+ resolveTargetName: (context: RetryContext) => string | null;
23
+ };
24
+ interface RetryRuleBase {
25
+ /** Stable identifier for logs and telemetry. */
26
+ id: string;
27
+ /** Maximum normalized attempts at which this rule may match. */
28
+ maxAttempts: number;
29
+ match: (context: RetryContext) => boolean | Promise<boolean>;
30
+ }
31
+ export type RetryRule = (RetryRuleBase & {
32
+ decision?: 'rerun';
33
+ /** Reruns must name a resolved target; full-provider reruns stay private. */
34
+ retryTarget: RetryTarget;
35
+ }) | (RetryRuleBase & {
36
+ decision: Exclude<RetryDecision, 'rerun'>;
37
+ retryTarget?: never;
38
+ });
39
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare const VITEST_SUITE_PATTERN: RegExp;
@@ -0,0 +1 @@
1
+ export const VITEST_SUITE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -1,6 +1,7 @@
1
+ export * from './report-attempt.mts';
2
+ export { VITEST_SUITE_PATTERN } from './constants.mts';
1
3
  export declare const VITEST_BLOB_MANIFEST_FILENAME = "vitest-blob-manifest.json";
2
4
  export declare const VITEST_BLOB_MANIFEST_VERSION = "vitest-blob-manifest:v1";
3
- export declare const VITEST_SUITE_PATTERN: RegExp;
4
5
  export interface VitestBlobManifest {
5
6
  readonly version: typeof VITEST_BLOB_MANIFEST_VERSION;
6
7
  readonly suite: string;
@@ -1,9 +1,11 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { lstatSync, readFileSync, readdirSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
3
3
  import { basename, join } from 'node:path';
4
+ import { VITEST_SUITE_PATTERN } from './constants.mjs';
5
+ export * from './report-attempt.mjs';
6
+ export { VITEST_SUITE_PATTERN } from './constants.mjs';
4
7
  export const VITEST_BLOB_MANIFEST_FILENAME = 'vitest-blob-manifest.json';
5
8
  export const VITEST_BLOB_MANIFEST_VERSION = 'vitest-blob-manifest:v1';
6
- export const VITEST_SUITE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
7
9
  function isRecord(value) {
8
10
  return typeof value === 'object' && value !== null && !Array.isArray(value);
9
11
  }
@@ -0,0 +1,24 @@
1
+ export declare const VITEST_REPORT_ATTEMPT_VERSION = "vitest-report-attempt:v1";
2
+ export declare const VITEST_REPORT_ATTEMPT_PREFIX = "vitest-report-attempt-";
3
+ export interface VitestReportAttemptIdentity {
4
+ readonly repository: string;
5
+ readonly revision: string;
6
+ readonly runId: string;
7
+ readonly attempt: number;
8
+ }
9
+ export interface VitestReportAttempt {
10
+ readonly version: typeof VITEST_REPORT_ATTEMPT_VERSION;
11
+ readonly suite: string;
12
+ readonly repository: string;
13
+ readonly revision: string;
14
+ readonly run: {
15
+ readonly id: string;
16
+ readonly attempt: number;
17
+ };
18
+ }
19
+ export declare function parseVitestReportAttempt(raw: unknown): VitestReportAttempt;
20
+ export declare function createVitestReportAttempt(suite: string, identity: VitestReportAttemptIdentity): VitestReportAttempt;
21
+ export declare function serializeVitestReportAttempt(marker: VitestReportAttempt): Buffer;
22
+ export declare function writeVitestReportAttempt(directory: string, suite: string, identity: VitestReportAttemptIdentity): string;
23
+ /** Reads only exact flattened or per-suite marker artifacts, rejecting all other layouts. */
24
+ export declare function readVitestReportAttempts(root: string, identity: VitestReportAttemptIdentity): Readonly<Record<string, number>>;
@@ -0,0 +1,127 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
3
+ import { basename, join } from 'node:path';
4
+ import { VITEST_SUITE_PATTERN } from './constants.mjs';
5
+ export const VITEST_REPORT_ATTEMPT_VERSION = 'vitest-report-attempt:v1';
6
+ export const VITEST_REPORT_ATTEMPT_PREFIX = 'vitest-report-attempt-';
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 assertIdentity(identity) {
17
+ if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(identity.repository) ||
18
+ !/^[0-9a-f]{40}$/.test(identity.revision) ||
19
+ !/^[1-9][0-9]*$/.test(identity.runId) ||
20
+ !isPositiveInteger(identity.attempt)) {
21
+ throw new Error('Vitest report attempt identity has an invalid schema');
22
+ }
23
+ }
24
+ export function parseVitestReportAttempt(raw) {
25
+ if (!isRecord(raw) ||
26
+ !hasExactKeys(raw, ['version', 'suite', 'repository', 'revision', 'run']) ||
27
+ raw.version !== VITEST_REPORT_ATTEMPT_VERSION ||
28
+ typeof raw.suite !== 'string' ||
29
+ !VITEST_SUITE_PATTERN.test(raw.suite) ||
30
+ typeof raw.repository !== 'string' ||
31
+ !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(raw.repository) ||
32
+ typeof raw.revision !== 'string' ||
33
+ !/^[0-9a-f]{40}$/.test(raw.revision) ||
34
+ !isRecord(raw.run) ||
35
+ !hasExactKeys(raw.run, ['id', 'attempt']) ||
36
+ typeof raw.run.id !== 'string' ||
37
+ !/^[1-9][0-9]*$/.test(raw.run.id) ||
38
+ !isPositiveInteger(raw.run.attempt)) {
39
+ throw new Error('Vitest report attempt marker has an invalid schema');
40
+ }
41
+ return raw;
42
+ }
43
+ export function createVitestReportAttempt(suite, identity) {
44
+ assertIdentity(identity);
45
+ return parseVitestReportAttempt({
46
+ version: VITEST_REPORT_ATTEMPT_VERSION,
47
+ suite,
48
+ repository: identity.repository,
49
+ revision: identity.revision,
50
+ run: { id: identity.runId, attempt: identity.attempt },
51
+ });
52
+ }
53
+ export function serializeVitestReportAttempt(marker) {
54
+ return Buffer.from(`${JSON.stringify(parseVitestReportAttempt(marker), null, 2)}\n`);
55
+ }
56
+ function assertDirectory(path, label) {
57
+ if (!lstatSync(path).isDirectory())
58
+ throw new Error(`${label} must be a directory`);
59
+ }
60
+ function writeAtomically(path, bytes) {
61
+ const temporary = `${path}.${randomUUID()}.tmp`;
62
+ try {
63
+ writeFileSync(temporary, bytes, { flag: 'wx', mode: 0o600 });
64
+ renameSync(temporary, path);
65
+ }
66
+ finally {
67
+ try {
68
+ unlinkSync(temporary);
69
+ }
70
+ catch {
71
+ // A successful rename consumes the temporary name.
72
+ }
73
+ }
74
+ }
75
+ export function writeVitestReportAttempt(directory, suite, identity) {
76
+ const marker = createVitestReportAttempt(suite, identity);
77
+ mkdirSync(directory, { recursive: true });
78
+ assertDirectory(directory, 'Vitest report attempt directory');
79
+ const path = join(directory, `${suite}.json`);
80
+ writeAtomically(path, serializeVitestReportAttempt(marker));
81
+ return path;
82
+ }
83
+ function readAttempt(path, suite, identity) {
84
+ const marker = parseVitestReportAttempt(JSON.parse(readFileSync(path, 'utf8')));
85
+ if (marker.suite !== suite ||
86
+ marker.repository !== identity.repository ||
87
+ marker.revision !== identity.revision ||
88
+ marker.run.id !== identity.runId ||
89
+ marker.run.attempt > identity.attempt) {
90
+ throw new Error(`Vitest report attempt identity does not match this run for ${suite}`);
91
+ }
92
+ return marker.run.attempt;
93
+ }
94
+ /** Reads only exact flattened or per-suite marker artifacts, rejecting all other layouts. */
95
+ export function readVitestReportAttempts(root, identity) {
96
+ assertIdentity(identity);
97
+ if (!existsSync(root))
98
+ return {};
99
+ assertDirectory(root, 'Vitest report attempt root');
100
+ const attempts = {};
101
+ const rootEntries = readdirSync(root, { withFileTypes: true });
102
+ const flattened = rootEntries.length === 1 && rootEntries[0].isFile();
103
+ for (const artifact of rootEntries) {
104
+ if (flattened) {
105
+ const suite = artifact.name.endsWith('.json') ? artifact.name.slice(0, -'.json'.length) : '';
106
+ if (!VITEST_SUITE_PATTERN.test(suite)) {
107
+ throw new Error('Vitest report attempt root has an unexpected entry');
108
+ }
109
+ attempts[suite] = readAttempt(join(root, artifact.name), suite, identity);
110
+ continue;
111
+ }
112
+ if (!artifact.isDirectory() || !artifact.name.startsWith(VITEST_REPORT_ATTEMPT_PREFIX)) {
113
+ throw new Error('Vitest report attempt root has an unexpected entry');
114
+ }
115
+ const suite = artifact.name.slice(VITEST_REPORT_ATTEMPT_PREFIX.length);
116
+ if (!VITEST_SUITE_PATTERN.test(suite))
117
+ throw new Error('Invalid Vitest suite attempt artifact');
118
+ const directory = join(root, artifact.name);
119
+ assertDirectory(directory, `Vitest report attempt artifact ${basename(directory)}`);
120
+ const entries = readdirSync(directory, { withFileTypes: true });
121
+ if (entries.length !== 1 || entries[0].name !== `${suite}.json` || !entries[0].isFile()) {
122
+ throw new Error(`Vitest report attempt artifact ${basename(directory)} is invalid`);
123
+ }
124
+ attempts[suite] = readAttempt(join(directory, entries[0].name), suite, identity);
125
+ }
126
+ return Object.fromEntries(Object.entries(attempts).toSorted(([left], [right]) => left.localeCompare(right)));
127
+ }
@@ -0,0 +1,28 @@
1
+ export interface PrepareVitestReportsOptions {
2
+ readonly primaryDir: string;
3
+ readonly fallbackDir: string;
4
+ readonly outputDir: string;
5
+ readonly expectedSuites: readonly VitestReportExpectation[];
6
+ readonly repository: string;
7
+ readonly revision: string;
8
+ readonly run: {
9
+ readonly id: string;
10
+ readonly currentAttempt: number;
11
+ };
12
+ }
13
+ export type VitestReportExpectation = {
14
+ readonly suite: string;
15
+ readonly minimumAttempt: number;
16
+ };
17
+ export interface SelectedVitestReport {
18
+ readonly suite: string;
19
+ readonly attempt: number;
20
+ readonly sources: readonly ('primary' | 'fallback')[];
21
+ }
22
+ /**
23
+ * Validates untrusted blob bundles and atomically publishes one newest report per expected suite.
24
+ * The caller owns artifact transport; this function deliberately has no network or CI-provider API.
25
+ */
26
+ export declare function prepareVitestReports(options: PrepareVitestReportsOptions): {
27
+ readonly selected: readonly SelectedVitestReport[];
28
+ };
@@ -0,0 +1,160 @@
1
+ /* eslint-disable max-lines -- untrusted artifact discovery and publication form one security boundary. */
2
+ import { randomUUID } from 'node:crypto';
3
+ import { existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
4
+ import { basename, dirname, join } from 'node:path';
5
+ import { inspectVitestBlobBundle, VITEST_BLOB_MANIFEST_FILENAME, VITEST_SUITE_PATTERN, } from './index.mjs';
6
+ function inspectSource(root, source) {
7
+ if (!existsSync(root))
8
+ return [];
9
+ if (!lstatSync(root).isDirectory())
10
+ throw new Error(`Vitest ${source} root must be a directory`);
11
+ const entries = readdirSync(root, { withFileTypes: true });
12
+ if (entries.length === 0)
13
+ return [];
14
+ const isFlattened = entries.some((entry) => entry.name === VITEST_BLOB_MANIFEST_FILENAME);
15
+ if (isFlattened)
16
+ return [{ ...inspectVitestBlobBundle(root), source }];
17
+ const invalid = entries.find((entry) => {
18
+ const suite = entry.name.startsWith('.invalid-') ? entry.name.slice('.invalid-'.length) : '';
19
+ return entry.isFile() && VITEST_SUITE_PATTERN.test(suite);
20
+ });
21
+ if (invalid)
22
+ throw new Error(`Vitest ${source} root contains an invalid archive marker`);
23
+ const unexpected = entries.find((entry) => !entry.isDirectory());
24
+ if (unexpected)
25
+ throw new Error(`Vitest ${source} root has an unexpected entry`);
26
+ return entries
27
+ .toSorted((left, right) => left.name.localeCompare(right.name))
28
+ .map((entry) => ({ ...inspectVitestBlobBundle(join(root, entry.name)), source }));
29
+ }
30
+ function validateOptions(options) {
31
+ if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(options.repository)) {
32
+ throw new Error('Invalid Vitest repository');
33
+ }
34
+ if (!/^[0-9a-f]{40}$/.test(options.revision))
35
+ throw new Error('Invalid Vitest revision');
36
+ if (!/^[1-9][0-9]*$/.test(options.run.id) || !Number.isSafeInteger(options.run.currentAttempt)) {
37
+ throw new Error('Invalid Vitest run');
38
+ }
39
+ if (options.run.currentAttempt < 1)
40
+ throw new Error('Invalid Vitest run');
41
+ for (const expectation of options.expectedSuites) {
42
+ if (!VITEST_SUITE_PATTERN.test(expectation.suite) ||
43
+ !Number.isSafeInteger(expectation.minimumAttempt)) {
44
+ throw new Error('Invalid expected Vitest suite');
45
+ }
46
+ if (expectation.minimumAttempt < 1 || expectation.minimumAttempt > options.run.currentAttempt) {
47
+ throw new Error('Invalid expected Vitest suite attempt');
48
+ }
49
+ }
50
+ }
51
+ function validateIdentity(candidate, options) {
52
+ const { manifest } = candidate;
53
+ if (manifest.repository !== options.repository ||
54
+ manifest.revision !== options.revision ||
55
+ manifest.run.id !== options.run.id) {
56
+ throw new Error(`Vitest blob identity does not match this run for ${manifest.suite}`);
57
+ }
58
+ if (manifest.run.attempt > options.run.currentAttempt) {
59
+ throw new Error(`Vitest blob attempt is from the future for ${manifest.suite}`);
60
+ }
61
+ }
62
+ function identical(left, right) {
63
+ return (left.manifestBytes.equals(right.manifestBytes) && left.reportBytes.equals(right.reportBytes));
64
+ }
65
+ function rejectConflictingCopies(candidates) {
66
+ const firstByIdentity = new Map();
67
+ for (const candidate of candidates) {
68
+ const key = `${candidate.manifest.suite}\0${candidate.manifest.run.attempt}`;
69
+ const first = firstByIdentity.get(key);
70
+ if (first && !identical(first, candidate)) {
71
+ throw new Error(`Conflicting Vitest blobs for ${candidate.manifest.suite} attempt ${candidate.manifest.run.attempt}`);
72
+ }
73
+ firstByIdentity.set(key, first ?? candidate);
74
+ }
75
+ }
76
+ function selectCandidates(candidates, options) {
77
+ const expected = new Map(options.expectedSuites.map((expectation) => [expectation.suite, expectation.minimumAttempt]));
78
+ if (expected.size !== options.expectedSuites.length)
79
+ throw new Error('Expected Vitest suites must be unique');
80
+ for (const candidate of candidates)
81
+ validateIdentity(candidate, options);
82
+ rejectConflictingCopies(candidates);
83
+ for (const candidate of candidates) {
84
+ if (!expected.has(candidate.manifest.suite) &&
85
+ candidate.manifest.run.attempt === options.run.currentAttempt) {
86
+ throw new Error(`Unexpected current-attempt Vitest suite: ${candidate.manifest.suite}`);
87
+ }
88
+ }
89
+ return options.expectedSuites
90
+ .toSorted((left, right) => left.suite.localeCompare(right.suite))
91
+ .map((expectation) => {
92
+ const matches = candidates.filter((candidate) => candidate.manifest.suite === expectation.suite &&
93
+ candidate.manifest.run.attempt >= expectation.minimumAttempt);
94
+ if (matches.length === 0)
95
+ throw new Error(`Missing expected Vitest suite: ${expectation.suite}`);
96
+ const latestAttempt = Math.max(...matches.map((candidate) => candidate.manifest.run.attempt));
97
+ const latest = matches.filter((candidate) => candidate.manifest.run.attempt === latestAttempt);
98
+ return {
99
+ candidate: latest[0],
100
+ sources: [...new Set(latest.map((candidate) => candidate.source))].toSorted(),
101
+ };
102
+ });
103
+ }
104
+ function replaceOutput(outputDir, selected) {
105
+ const parent = dirname(outputDir);
106
+ mkdirSync(parent, { recursive: true });
107
+ const temporary = mkdtempSync(join(parent, `.${basename(outputDir)}-`));
108
+ const backup = join(parent, `.${basename(outputDir)}-backup-${randomUUID()}`);
109
+ let backedUp = false;
110
+ try {
111
+ for (const { candidate } of selected) {
112
+ writeFileSync(join(temporary, `${candidate.manifest.suite}.json`), candidate.reportBytes, {
113
+ flag: 'wx',
114
+ mode: 0o600,
115
+ });
116
+ }
117
+ if (existsSync(outputDir)) {
118
+ if (!lstatSync(outputDir).isDirectory())
119
+ throw new Error('Vitest report output must be a directory');
120
+ renameSync(outputDir, backup);
121
+ backedUp = true;
122
+ }
123
+ try {
124
+ renameSync(temporary, outputDir);
125
+ }
126
+ catch (error) {
127
+ /* v8 ignore start -- an OS-level rename failure restores the already-tested backup path */
128
+ if (backedUp)
129
+ renameSync(backup, outputDir);
130
+ backedUp = false;
131
+ throw error;
132
+ /* v8 ignore stop */
133
+ }
134
+ }
135
+ finally {
136
+ rmSync(temporary, { recursive: true, force: true });
137
+ if (backedUp)
138
+ rmSync(backup, { recursive: true, force: true });
139
+ }
140
+ }
141
+ /**
142
+ * Validates untrusted blob bundles and atomically publishes one newest report per expected suite.
143
+ * The caller owns artifact transport; this function deliberately has no network or CI-provider API.
144
+ */
145
+ export function prepareVitestReports(options) {
146
+ validateOptions(options);
147
+ const candidates = [
148
+ ...inspectSource(options.primaryDir, 'primary'),
149
+ ...inspectSource(options.fallbackDir, 'fallback'),
150
+ ];
151
+ const selected = selectCandidates(candidates, options);
152
+ replaceOutput(options.outputDir, selected);
153
+ return {
154
+ selected: selected.map(({ candidate, sources }) => ({
155
+ suite: candidate.manifest.suite,
156
+ attempt: candidate.manifest.run.attempt,
157
+ sources,
158
+ })),
159
+ };
160
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vouchington-tooling",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
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": {
@@ -55,6 +55,11 @@
55
55
  "import": "./dist/vitest-blob-manifest/index.mjs",
56
56
  "default": "./dist/vitest-blob-manifest/index.mjs"
57
57
  },
58
+ "./vitest-reports": {
59
+ "types": "./dist/vitest-blob-manifest/reports.d.mts",
60
+ "import": "./dist/vitest-blob-manifest/reports.mjs",
61
+ "default": "./dist/vitest-blob-manifest/reports.mjs"
62
+ },
58
63
  "./pnpm-install": {
59
64
  "types": "./dist/pnpm-install/index.d.mts",
60
65
  "import": "./dist/pnpm-install/index.mjs",
@@ -95,6 +100,36 @@
95
100
  "import": "./dist/openapi-document/index.mjs",
96
101
  "default": "./dist/openapi-document/index.mjs"
97
102
  },
103
+ "./transient-retry": {
104
+ "types": "./dist/transient-retry/index.d.mts",
105
+ "import": "./dist/transient-retry/index.mjs",
106
+ "default": "./dist/transient-retry/index.mjs"
107
+ },
108
+ "./csv": {
109
+ "types": "./dist/csv/index.d.mts",
110
+ "import": "./dist/csv/index.mjs",
111
+ "default": "./dist/csv/index.mjs"
112
+ },
113
+ "./http-body": {
114
+ "types": "./dist/http-body/index.d.mts",
115
+ "import": "./dist/http-body/index.mjs",
116
+ "default": "./dist/http-body/index.mjs"
117
+ },
118
+ "./ast-grep-rule": {
119
+ "types": "./dist/ast-grep-rule/index.d.mts",
120
+ "import": "./dist/ast-grep-rule/index.mjs",
121
+ "default": "./dist/ast-grep-rule/index.mjs"
122
+ },
123
+ "./gha-review-payload": {
124
+ "types": "./dist/gha-review-payload/index.d.mts",
125
+ "import": "./dist/gha-review-payload/index.mjs",
126
+ "default": "./dist/gha-review-payload/index.mjs"
127
+ },
128
+ "./http-link-pagination": {
129
+ "types": "./dist/http-link-pagination/index.d.mts",
130
+ "import": "./dist/http-link-pagination/index.mjs",
131
+ "default": "./dist/http-link-pagination/index.mjs"
132
+ },
98
133
  "./package.json": "./package.json"
99
134
  },
100
135
  "publishConfig": {
@@ -106,6 +141,8 @@
106
141
  "typecheck": "tsc --noEmit --project tsconfig.json"
107
142
  },
108
143
  "dependencies": {
144
+ "csv-parse": "7.0.2",
145
+ "csv-stringify": "6.8.2",
109
146
  "picomatch": "4.0.5"
110
147
  },
111
148
  "devDependencies": {