@untestutils/core 0.5.0

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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/dist/artifact-store.d.mts +19 -0
  3. package/dist/artifact-store.d.ts +20 -0
  4. package/dist/artifact-store.d.ts.map +1 -0
  5. package/dist/artifact-store.mjs +52 -0
  6. package/dist/debug.d.mts +5 -0
  7. package/dist/debug.d.ts +6 -0
  8. package/dist/debug.d.ts.map +1 -0
  9. package/dist/debug.mjs +22 -0
  10. package/dist/drivers/cli-framework.d.mts +57 -0
  11. package/dist/drivers/cli-framework.d.ts +64 -0
  12. package/dist/drivers/cli-framework.d.ts.map +1 -0
  13. package/dist/drivers/cli-framework.mjs +138 -0
  14. package/dist/drivers/command.d.mts +15 -0
  15. package/dist/drivers/command.d.ts +16 -0
  16. package/dist/drivers/command.d.ts.map +1 -0
  17. package/dist/drivers/command.mjs +70 -0
  18. package/dist/drivers/define-driver.d.mts +4 -0
  19. package/dist/drivers/define-driver.d.ts +5 -0
  20. package/dist/drivers/define-driver.d.ts.map +1 -0
  21. package/dist/drivers/define-driver.mjs +3 -0
  22. package/dist/drivers/host.d.mts +18 -0
  23. package/dist/drivers/host.d.ts +19 -0
  24. package/dist/drivers/host.d.ts.map +1 -0
  25. package/dist/drivers/host.mjs +31 -0
  26. package/dist/drivers/index.d.mts +12 -0
  27. package/dist/drivers/index.d.ts +13 -0
  28. package/dist/drivers/index.d.ts.map +1 -0
  29. package/dist/drivers/index.mjs +6 -0
  30. package/dist/drivers/node-entry.d.mts +13 -0
  31. package/dist/drivers/node-entry.d.ts +14 -0
  32. package/dist/drivers/node-entry.d.ts.map +1 -0
  33. package/dist/drivers/node-entry.mjs +55 -0
  34. package/dist/drivers/static-dir.d.mts +9 -0
  35. package/dist/drivers/static-dir.d.ts +10 -0
  36. package/dist/drivers/static-dir.d.ts.map +1 -0
  37. package/dist/drivers/static-dir.mjs +90 -0
  38. package/dist/harness.d.mts +4 -0
  39. package/dist/harness.d.ts +5 -0
  40. package/dist/harness.d.ts.map +1 -0
  41. package/dist/harness.mjs +18 -0
  42. package/dist/hash.d.mts +6 -0
  43. package/dist/hash.d.ts +7 -0
  44. package/dist/hash.d.ts.map +1 -0
  45. package/dist/hash.mjs +76 -0
  46. package/dist/identity.d.mts +9 -0
  47. package/dist/identity.d.ts +10 -0
  48. package/dist/identity.d.ts.map +1 -0
  49. package/dist/identity.mjs +44 -0
  50. package/dist/index.d.mts +29 -0
  51. package/dist/index.d.ts +30 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.mjs +22 -0
  54. package/dist/lock.d.mts +26 -0
  55. package/dist/lock.d.ts +27 -0
  56. package/dist/lock.d.ts.map +1 -0
  57. package/dist/lock.mjs +145 -0
  58. package/dist/orchestrator.d.mts +19 -0
  59. package/dist/orchestrator.d.ts +22 -0
  60. package/dist/orchestrator.d.ts.map +1 -0
  61. package/dist/orchestrator.mjs +343 -0
  62. package/dist/paths.d.mts +20 -0
  63. package/dist/paths.d.ts +21 -0
  64. package/dist/paths.d.ts.map +1 -0
  65. package/dist/paths.mjs +124 -0
  66. package/dist/ports.d.mts +2 -0
  67. package/dist/ports.d.ts +8 -0
  68. package/dist/ports.d.ts.map +1 -0
  69. package/dist/ports.mjs +38 -0
  70. package/dist/process.d.mts +31 -0
  71. package/dist/process.d.ts +36 -0
  72. package/dist/process.d.ts.map +1 -0
  73. package/dist/process.mjs +191 -0
  74. package/dist/progress.d.mts +45 -0
  75. package/dist/progress.d.ts +66 -0
  76. package/dist/progress.d.ts.map +1 -0
  77. package/dist/progress.mjs +205 -0
  78. package/dist/ready.d.mts +11 -0
  79. package/dist/ready.d.ts +12 -0
  80. package/dist/ready.d.ts.map +1 -0
  81. package/dist/ready.mjs +142 -0
  82. package/dist/recipes.d.mts +23 -0
  83. package/dist/recipes.d.ts +24 -0
  84. package/dist/recipes.d.ts.map +1 -0
  85. package/dist/recipes.mjs +94 -0
  86. package/dist/run-helper.d.mts +6 -0
  87. package/dist/run-helper.d.ts +7 -0
  88. package/dist/run-helper.d.ts.map +1 -0
  89. package/dist/run-helper.mjs +79 -0
  90. package/dist/target-registry.d.mts +27 -0
  91. package/dist/target-registry.d.ts +28 -0
  92. package/dist/target-registry.d.ts.map +1 -0
  93. package/dist/target-registry.mjs +103 -0
  94. package/dist/types.d.mts +92 -0
  95. package/dist/types.d.ts +93 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.mjs +1 -0
  98. package/package.json +54 -0
@@ -0,0 +1,103 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "pathe";
4
+ import { atomicWriteJson, FileLock } from "./lock.mjs";
5
+ import { normalizeBaseUrl } from "./paths.mjs";
6
+ import { debug } from "./debug.mjs";
7
+ export class TargetRegistry {
8
+ artifactsRoot;
9
+ constructor(artifactsRoot) {
10
+ this.artifactsRoot = artifactsRoot;
11
+ }
12
+ get filePath() {
13
+ return join(this.artifactsRoot, "targets.json");
14
+ }
15
+ lockPath() {
16
+ return join(this.artifactsRoot, "locks", "targets.lock");
17
+ }
18
+ async withLock(fn) {
19
+ const lock = new FileLock(this.lockPath(), "targets");
20
+ await lock.acquire();
21
+ try {
22
+ return await fn();
23
+ } finally {
24
+ await lock.release();
25
+ }
26
+ }
27
+ async read() {
28
+ if (!existsSync(this.filePath)) return {};
29
+ try {
30
+ return JSON.parse(await readFile(this.filePath, "utf8"));
31
+ } catch {
32
+ return {};
33
+ }
34
+ }
35
+ async write(map) {
36
+ await atomicWriteJson(this.filePath, map);
37
+ debug("registry", `wrote ${Object.keys(map).length} targets`);
38
+ }
39
+ async set(entry) {
40
+ let previous;
41
+ await this.withLock(async () => {
42
+ const map = await this.read();
43
+ previous = map[entry.id];
44
+ const normalized = {
45
+ ...entry,
46
+ url: entry.url ? normalizeBaseUrl(entry.url) : undefined
47
+ };
48
+ map[entry.id] = normalized;
49
+ await this.write(map);
50
+ this.applyEnv(normalized);
51
+ });
52
+ return previous;
53
+ }
54
+ async get(id) {
55
+ const map = await this.read();
56
+ const fromFile = map[id];
57
+ const fromEnv = process.env[envKey(id)];
58
+ if (fromFile) {
59
+ return {
60
+ ...fromFile,
61
+
62
+ url: fromEnv ? normalizeBaseUrl(fromEnv) : fromFile.url
63
+ };
64
+ }
65
+ if (fromEnv) {
66
+ return {
67
+ id,
68
+ url: normalizeBaseUrl(fromEnv),
69
+ identity: id
70
+ };
71
+ }
72
+ return undefined;
73
+ }
74
+ applyAllToEnv(map) {
75
+ for (const entry of Object.values(map)) this.applyEnv(entry);
76
+ }
77
+ applyEnv(entry) {
78
+ if (entry.url) process.env[envKey(entry.id)] = entry.url;
79
+ if (entry.dir) process.env[envDirKey(entry.id)] = entry.dir;
80
+ }
81
+ async clear() {
82
+ await this.withLock(async () => {
83
+ await atomicWriteJson(this.filePath, {});
84
+ });
85
+ }
86
+
87
+ async drain() {
88
+ return this.withLock(async () => {
89
+ const map = await this.read();
90
+ await atomicWriteJson(this.filePath, {});
91
+ return map;
92
+ });
93
+ }
94
+ }
95
+ export function envKey(id) {
96
+ return `UNTESTUTILS_HOST_${sanitizeId(id)}`;
97
+ }
98
+ export function envDirKey(id) {
99
+ return `UNTESTUTILS_DIR_${sanitizeId(id)}`;
100
+ }
101
+ function sanitizeId(id) {
102
+ return id.replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase();
103
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Core recipe types — framework-free.
3
+ */
4
+ export type RunningKind = "url" | "dir" | "url+dir";
5
+ export interface RunningBase {
6
+ stop?: () => Promise<void>;
7
+ /** OS pid of the managed server (for cross-worker teardown via registry). */
8
+ pid?: number;
9
+ }
10
+ export interface RunningUrl extends RunningBase {
11
+ kind: "url";
12
+ url: string;
13
+ }
14
+ export interface RunningDir extends RunningBase {
15
+ kind: "dir";
16
+ dir: string;
17
+ }
18
+ export interface RunningBoth extends RunningBase {
19
+ kind: "url+dir";
20
+ url: string;
21
+ dir: string;
22
+ }
23
+ export type Running = RunningUrl | RunningDir | RunningBoth;
24
+ export type SharePolicy = "always" | "never" | "prepare-only";
25
+ export interface HashCtx {
26
+ root?: string;
27
+ outDir: string;
28
+ artifactsRoot: string;
29
+ }
30
+ export interface PrepareCtx {
31
+ root?: string;
32
+ outDir: string;
33
+ artifactsRoot: string;
34
+ env: NodeJS.ProcessEnv;
35
+ run: RunHelper;
36
+ }
37
+ export interface StartCtx {
38
+ root?: string;
39
+ outDir: string;
40
+ artifactsRoot: string;
41
+ port: number;
42
+ host: string;
43
+ env: NodeJS.ProcessEnv;
44
+ run: RunHelper;
45
+ }
46
+ export interface RunResult {
47
+ exitCode: number;
48
+ stdout: string;
49
+ stderr: string;
50
+ }
51
+ export interface DetachedProcess {
52
+ pid?: number;
53
+ stop: () => Promise<void>;
54
+ logs: () => string;
55
+ }
56
+ export interface RunHelper {
57
+ (strings: TemplateStringsArray, ...values: unknown[]): Promise<RunResult>;
58
+ detached: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<DetachedProcess>;
59
+ command: (cmd: string, opts?: {
60
+ cwd?: string;
61
+ env?: NodeJS.ProcessEnv;
62
+ }) => Promise<RunResult>;
63
+ }
64
+ export interface Recipe {
65
+ id?: string;
66
+ hashInputs?: (ctx: HashCtx) => string[] | Promise<string[]>;
67
+ prepare?: (ctx: PrepareCtx) => Promise<void>;
68
+ start: (ctx: StartCtx) => Promise<Running>;
69
+ ready?: (running: Running) => Promise<void>;
70
+ verifyArtifact?: (outDir: string) => Promise<void>;
71
+ share?: SharePolicy;
72
+ }
73
+ export type RecipeFactory<Opts = unknown> = (opts: Opts) => Recipe;
74
+ export interface RecipeRegistry {
75
+ readonly [id: string]: Recipe;
76
+ }
77
+ export interface HarnessHandle {
78
+ id: string;
79
+ url?: string;
80
+ dir?: string;
81
+ $fetch: typeof import("ofetch").$fetch;
82
+ files: {
83
+ read: (rel: string) => Promise<string>;
84
+ exists: (rel: string) => Promise<boolean>;
85
+ list: (rel?: string) => Promise<string[]>;
86
+ };
87
+ dispose?: () => Promise<void>;
88
+ }
89
+ export interface UseHarnessOptions {
90
+ browser?: boolean;
91
+ }
92
+ export declare const SCHEMA_VERSION: 1;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Core recipe types — framework-free.
3
+ */
4
+ export type RunningKind = 'url' | 'dir' | 'url+dir';
5
+ export interface RunningBase {
6
+ stop?: () => Promise<void>;
7
+ /** OS pid of the managed server (for cross-worker teardown via registry). */
8
+ pid?: number;
9
+ }
10
+ export interface RunningUrl extends RunningBase {
11
+ kind: 'url';
12
+ url: string;
13
+ }
14
+ export interface RunningDir extends RunningBase {
15
+ kind: 'dir';
16
+ dir: string;
17
+ }
18
+ export interface RunningBoth extends RunningBase {
19
+ kind: 'url+dir';
20
+ url: string;
21
+ dir: string;
22
+ }
23
+ export type Running = RunningUrl | RunningDir | RunningBoth;
24
+ export type SharePolicy = 'always' | 'never' | 'prepare-only';
25
+ export interface HashCtx {
26
+ root?: string;
27
+ outDir: string;
28
+ artifactsRoot: string;
29
+ }
30
+ export interface PrepareCtx {
31
+ root?: string;
32
+ outDir: string;
33
+ artifactsRoot: string;
34
+ env: NodeJS.ProcessEnv;
35
+ run: RunHelper;
36
+ }
37
+ export interface StartCtx {
38
+ root?: string;
39
+ outDir: string;
40
+ artifactsRoot: string;
41
+ port: number;
42
+ host: string;
43
+ env: NodeJS.ProcessEnv;
44
+ run: RunHelper;
45
+ }
46
+ export interface RunResult {
47
+ exitCode: number;
48
+ stdout: string;
49
+ stderr: string;
50
+ }
51
+ export interface DetachedProcess {
52
+ pid?: number;
53
+ stop: () => Promise<void>;
54
+ logs: () => string;
55
+ }
56
+ export interface RunHelper {
57
+ (strings: TemplateStringsArray, ...values: unknown[]): Promise<RunResult>;
58
+ detached: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<DetachedProcess>;
59
+ command: (cmd: string, opts?: {
60
+ cwd?: string;
61
+ env?: NodeJS.ProcessEnv;
62
+ }) => Promise<RunResult>;
63
+ }
64
+ export interface Recipe {
65
+ id?: string;
66
+ hashInputs?: (ctx: HashCtx) => string[] | Promise<string[]>;
67
+ prepare?: (ctx: PrepareCtx) => Promise<void>;
68
+ start: (ctx: StartCtx) => Promise<Running>;
69
+ ready?: (running: Running) => Promise<void>;
70
+ verifyArtifact?: (outDir: string) => Promise<void>;
71
+ share?: SharePolicy;
72
+ }
73
+ export type RecipeFactory<Opts = unknown> = (opts: Opts) => Recipe;
74
+ export interface RecipeRegistry {
75
+ readonly [id: string]: Recipe;
76
+ }
77
+ export interface HarnessHandle {
78
+ id: string;
79
+ url?: string;
80
+ dir?: string;
81
+ $fetch: typeof import('ofetch').$fetch;
82
+ files: {
83
+ read: (rel: string) => Promise<string>;
84
+ exists: (rel: string) => Promise<boolean>;
85
+ list: (rel?: string) => Promise<string[]>;
86
+ };
87
+ dispose?: () => Promise<void>;
88
+ }
89
+ export interface UseHarnessOptions {
90
+ browser?: boolean;
91
+ }
92
+ export declare const SCHEMA_VERSION: 1;
93
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.mjs ADDED
@@ -0,0 +1 @@
1
+ export const SCHEMA_VERSION = 1;
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@untestutils/core",
3
+ "version": "0.5.0",
4
+ "description": "Recipe harness core — locks, registry, orchestrator, drivers",
5
+ "license": "MIT",
6
+ "homepage": "https://s00d.github.io/untestutils/",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/s00d/untestutils.git",
10
+ "directory": "packages/core"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "main": "./dist/index.mjs",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.mjs",
23
+ "default": "./dist/index.mjs"
24
+ },
25
+ "./drivers": {
26
+ "types": "./dist/drivers/index.d.ts",
27
+ "import": "./dist/drivers/index.mjs",
28
+ "default": "./dist/drivers/index.mjs"
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "dependencies": {
36
+ "consola": "^3.4.2",
37
+ "ofetch": "^1.5.1",
38
+ "pathe": "^2.0.3"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^26.6.1",
42
+ "obuild": "^0.4.40",
43
+ "publint": "^0.3.24",
44
+ "typescript": "^6.0.3"
45
+ },
46
+ "engines": {
47
+ "node": ">=20"
48
+ },
49
+ "scripts": {
50
+ "typecheck": "tsc --noEmit -p tsconfig.json",
51
+ "build": "obuild && tsc -p tsconfig.build.json",
52
+ "publint": "publint --strict"
53
+ }
54
+ }