@bensandee/tooling 0.14.0 → 0.14.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @bensandee/tooling
2
2
 
3
+ ## 0.14.1
4
+
5
+ ### Patch Changes
6
+
7
+ - caeebd8: Add d.ts declaration file output and types export conditions
8
+ - caeebd8: Bump tsdown from 0.21.0 to 0.21.2
9
+ - Updated dependencies [caeebd8]
10
+ - Updated dependencies [caeebd8]
11
+ - @bensandee/common@0.1.2
12
+
3
13
  ## 0.14.0
4
14
 
5
15
  ### Minor Changes
package/dist/bin.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/bin.mjs CHANGED
@@ -595,8 +595,8 @@ function addReleaseDeps(deps, config) {
595
595
  function getAddedDevDepNames(config) {
596
596
  const deps = { ...ROOT_DEV_DEPS };
597
597
  if (config.structure !== "monorepo") Object.assign(deps, PER_PACKAGE_DEV_DEPS);
598
- deps["@bensandee/config"] = "0.8.0";
599
- deps["@bensandee/tooling"] = "0.14.0";
598
+ deps["@bensandee/config"] = "0.8.1";
599
+ deps["@bensandee/tooling"] = "0.14.1";
600
600
  if (config.formatter === "oxfmt") deps["oxfmt"] = "0.35.0";
601
601
  if (config.formatter === "prettier") deps["prettier"] = "3.8.1";
602
602
  addReleaseDeps(deps, config);
@@ -616,9 +616,9 @@ async function generatePackageJson(ctx) {
616
616
  if (ctx.config.releaseStrategy !== "none" && ctx.config.releaseStrategy !== "changesets") allScripts["trigger-release"] = "pnpm exec tooling release:trigger";
617
617
  const devDeps = { ...ROOT_DEV_DEPS };
618
618
  if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
619
- devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.8.0";
620
- devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.14.0";
621
- if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.9.1";
619
+ devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.8.1";
620
+ devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.14.1";
621
+ if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.9.2";
622
622
  if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = "0.35.0";
623
623
  if (ctx.config.formatter === "prettier") devDeps["prettier"] = "3.8.1";
624
624
  addReleaseDeps(devDeps, ctx.config);
@@ -3690,7 +3690,7 @@ const runChecksCommand = defineCommand({
3690
3690
  const main = defineCommand({
3691
3691
  meta: {
3692
3692
  name: "tooling",
3693
- version: "0.14.0",
3693
+ version: "0.14.1",
3694
3694
  description: "Bootstrap and maintain standardized TypeScript project tooling"
3695
3695
  },
3696
3696
  subCommands: {
@@ -3705,7 +3705,7 @@ const main = defineCommand({
3705
3705
  "release:simple": releaseSimpleCommand
3706
3706
  }
3707
3707
  });
3708
- console.log(`@bensandee/tooling v0.14.0`);
3708
+ console.log(`@bensandee/tooling v0.14.1`);
3709
3709
  runMain(main);
3710
3710
  //#endregion
3711
3711
  export {};
@@ -0,0 +1,117 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/release/types.d.ts
4
+ /** Result of executing a shell command. */
5
+ interface ExecResult {
6
+ stdout: string;
7
+ stderr: string;
8
+ exitCode: number;
9
+ }
10
+ /** Options for executing a shell command. */
11
+ interface ExecOptions {
12
+ cwd?: string;
13
+ env?: Record<string, string>;
14
+ }
15
+ //#endregion
16
+ //#region src/docker-verify/types.d.ts
17
+ /** Abstraction over side effects for testability. */
18
+ interface DockerVerifyExecutor {
19
+ /** Run a shell command and return the result (stdout/stderr captured). */
20
+ exec(command: string, options?: ExecOptions): ExecResult;
21
+ /** Run a shell command, streaming stdout/stderr to the console. */
22
+ execInherit(command: string, options?: ExecOptions): void;
23
+ /** Perform an HTTP request. */
24
+ fetch(url: string, init?: RequestInit): Promise<Response>;
25
+ /** Get current time in ms (mockable clock). */
26
+ now(): number;
27
+ /** Sleep for the given duration (mockable delay). */
28
+ sleep(ms: number): Promise<void>;
29
+ /** Register a process signal handler. Returns a dispose function. */
30
+ onSignal(signal: NodeJS.Signals, handler: () => void): () => void;
31
+ /** Log a message to the console. */
32
+ log(message: string): void;
33
+ /** Log an error to the console. */
34
+ logError(message: string): void;
35
+ }
36
+ /** A single HTTP health check definition. */
37
+ interface HttpHealthCheck {
38
+ /** Human-readable name for logging (e.g. "API", "Frontend"). */
39
+ name: string;
40
+ /** URL to fetch. */
41
+ url: string;
42
+ /** Validate the response. Return true if healthy. */
43
+ validate: (response: Response) => Promise<boolean>;
44
+ }
45
+ /** Docker compose configuration. */
46
+ interface ComposeConfig {
47
+ /** Working directory for docker compose commands. */
48
+ cwd: string;
49
+ /** Compose files to use (e.g. ["docker-compose.yaml", "docker-compose.verify.yaml"]). */
50
+ composeFiles: string[];
51
+ /** Optional env file for compose. */
52
+ envFile?: string;
53
+ /** Service names to monitor for container-level health. */
54
+ services: string[];
55
+ }
56
+ /** Full verification configuration. */
57
+ interface VerifyConfig {
58
+ /** Docker compose settings. */
59
+ compose: ComposeConfig;
60
+ /** Optional build command to run before starting compose (e.g. "pnpm image:build"). */
61
+ buildCommand?: string;
62
+ /** Working directory for the build command (defaults to compose.cwd). */
63
+ buildCwd?: string;
64
+ /** HTTP health checks to poll. All must pass for success. */
65
+ healthChecks: HttpHealthCheck[];
66
+ /** Maximum time to wait for all checks to pass, in ms. Default: 120000. */
67
+ timeoutMs?: number;
68
+ /** Interval between polling attempts, in ms. Default: 5000. */
69
+ pollIntervalMs?: number;
70
+ }
71
+ /** Result of the verification run. */
72
+ type VerifyResult = {
73
+ success: true;
74
+ elapsedMs: number;
75
+ } | {
76
+ success: false;
77
+ reason: "timeout" | "unhealthy-container" | "error";
78
+ message: string;
79
+ elapsedMs: number;
80
+ };
81
+ //#endregion
82
+ //#region src/docker-verify/executor.d.ts
83
+ /** Create an executor that runs real commands, fetches, and manages process signals. */
84
+ declare function createRealExecutor(): DockerVerifyExecutor;
85
+ //#endregion
86
+ //#region src/docker-verify/verify.d.ts
87
+ /** Run the full Docker image verification lifecycle. */
88
+ declare function runVerification(executor: DockerVerifyExecutor, config: VerifyConfig): Promise<VerifyResult>;
89
+ //#endregion
90
+ //#region src/docker-verify/compose.d.ts
91
+ /** Zod schema for a single container entry from `docker compose ps --format json`. */
92
+ declare const ContainerInfoSchema: z.ZodObject<{
93
+ Service: z.ZodString;
94
+ Health: z.ZodString;
95
+ }, z.core.$strip>;
96
+ type ContainerInfo = z.infer<typeof ContainerInfoSchema>;
97
+ /** Build the `docker compose` base command string from config. */
98
+ declare function composeCommand(config: ComposeConfig): string;
99
+ /** Start the compose stack in detached mode. */
100
+ declare function composeUp(executor: DockerVerifyExecutor, config: ComposeConfig): void;
101
+ /** Tear down the compose stack, removing volumes and orphans. Swallows errors. */
102
+ declare function composeDown(executor: DockerVerifyExecutor, config: ComposeConfig): void;
103
+ /** Show logs for a specific service (or all services if not specified). Swallows errors. */
104
+ declare function composeLogs(executor: DockerVerifyExecutor, config: ComposeConfig, service?: string): void;
105
+ /**
106
+ * Query container status via `docker compose ps --format json`.
107
+ * Handles both JSON array and newline-delimited JSON (varies by docker compose version).
108
+ */
109
+ declare function composePs(executor: DockerVerifyExecutor, config: ComposeConfig): ContainerInfo[];
110
+ //#endregion
111
+ //#region src/docker-verify/health.d.ts
112
+ /** Look up the health status of a specific service from container info. */
113
+ declare function getContainerHealth(containers: ContainerInfo[], serviceName: string): string;
114
+ /** Run a single HTTP health check, returning true if the validator passes. */
115
+ declare function checkHttpHealth(executor: DockerVerifyExecutor, check: HttpHealthCheck): Promise<boolean>;
116
+ //#endregion
117
+ export { type ComposeConfig, type ContainerInfo, type DockerVerifyExecutor, type HttpHealthCheck, type VerifyConfig, type VerifyResult, checkHttpHealth, composeCommand, composeDown, composeLogs, composePs, composeUp, createRealExecutor, getContainerHealth, runVerification };
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/utils/json.d.ts
4
+ declare const PackageJsonSchema: z.ZodObject<{
5
+ name: z.ZodOptional<z.ZodString>;
6
+ version: z.ZodOptional<z.ZodString>;
7
+ private: z.ZodOptional<z.ZodBoolean>;
8
+ type: z.ZodOptional<z.ZodString>;
9
+ scripts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
10
+ dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
11
+ devDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
12
+ bin: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
13
+ exports: z.ZodOptional<z.ZodUnknown>;
14
+ main: z.ZodOptional<z.ZodString>;
15
+ types: z.ZodOptional<z.ZodString>;
16
+ typings: z.ZodOptional<z.ZodString>;
17
+ engines: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
18
+ }, z.core.$loose>;
19
+ type PackageJson = z.infer<typeof PackageJsonSchema>;
20
+ //#endregion
21
+ //#region src/types.d.ts
22
+ type CiPlatform = "github" | "forgejo" | "none";
23
+ type ReleaseStrategy = "release-it" | "simple" | "changesets" | "none";
24
+ /** User's answers from the interactive prompt or CLI flags. */
25
+ interface ProjectConfig {
26
+ /** Project name (from package.json name or user input) */
27
+ name: string;
28
+ /** Whether this is a new project or existing */
29
+ isNew: boolean;
30
+ /** Project structure */
31
+ structure: "single" | "monorepo";
32
+ /** Include @bensandee/eslint-plugin oxlint plugin */
33
+ useEslintPlugin: boolean;
34
+ /** Formatter choice */
35
+ formatter: "oxfmt" | "prettier";
36
+ /** Set up vitest with a starter test */
37
+ setupVitest: boolean;
38
+ /** CI platform choice */
39
+ ci: CiPlatform;
40
+ /** Set up Renovate for automated dependency updates */
41
+ setupRenovate: boolean;
42
+ /** Release management strategy */
43
+ releaseStrategy: ReleaseStrategy;
44
+ /** Project type determines tsconfig base configuration */
45
+ projectType: "default" | "node" | "react" | "library";
46
+ /** Auto-detect and configure tsconfig bases for monorepo packages */
47
+ detectPackageTypes: boolean;
48
+ /** Target directory (default: cwd) */
49
+ targetDir: string;
50
+ }
51
+ /** Result from a single generator: what file was written and how. */
52
+ interface GeneratorResult {
53
+ filePath: string;
54
+ action: "created" | "updated" | "skipped" | "archived";
55
+ /** Human-readable description of what changed */
56
+ description: string;
57
+ }
58
+ /** Context passed to each generator function. */
59
+ interface GeneratorContext {
60
+ config: ProjectConfig;
61
+ /** Absolute path to target directory */
62
+ targetDir: string;
63
+ /** Pre-parsed package.json from the target directory, or undefined if missing/invalid */
64
+ packageJson: PackageJson | undefined;
65
+ /** Check whether a file exists in the target directory */
66
+ exists: (relativePath: string) => boolean;
67
+ /** Read an existing file from the target directory, returns undefined if not found */
68
+ read: (relativePath: string) => string | undefined;
69
+ /** Write a file to the target directory (creating directories as needed) */
70
+ write: (relativePath: string, content: string) => void;
71
+ /** Remove a file from the target directory (no-op if not found) */
72
+ remove: (relativePath: string) => void;
73
+ /** Prompt user for conflict resolution on non-mergeable files */
74
+ confirmOverwrite: (relativePath: string) => Promise<"overwrite" | "skip">;
75
+ }
76
+ /** Generator function signature. */
77
+ type Generator = (ctx: GeneratorContext) => Promise<GeneratorResult>;
78
+ /** State detected from an existing project directory. */
79
+ interface DetectedProjectState {
80
+ hasPackageJson: boolean;
81
+ hasTsconfig: boolean;
82
+ hasOxlintConfig: boolean;
83
+ /** Legacy .oxlintrc.json found (should be migrated to oxlint.config.ts) */
84
+ hasLegacyOxlintJson: boolean;
85
+ hasGitignore: boolean;
86
+ hasVitestConfig: boolean;
87
+ hasTsdownConfig: boolean;
88
+ hasPnpmWorkspace: boolean;
89
+ hasKnipConfig: boolean;
90
+ hasRenovateConfig: boolean;
91
+ hasReleaseItConfig: boolean;
92
+ hasSimpleReleaseConfig: boolean;
93
+ hasChangesetsConfig: boolean;
94
+ /** Legacy tooling configs found */
95
+ legacyConfigs: LegacyConfig[];
96
+ }
97
+ declare const LEGACY_TOOLS: readonly ["eslint", "prettier", "jest", "webpack", "rollup"];
98
+ type LegacyTool = (typeof LEGACY_TOOLS)[number];
99
+ interface LegacyConfig {
100
+ tool: LegacyTool;
101
+ files: string[];
102
+ }
103
+ //#endregion
104
+ export { type DetectedProjectState, type Generator, type GeneratorContext, type GeneratorResult, type LegacyConfig, type ProjectConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bensandee/tooling",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
5
5
  "bin": {
6
6
  "tooling": "./dist/bin.mjs"
@@ -14,9 +14,15 @@
14
14
  "#src/*.ts": "./src/*.ts"
15
15
  },
16
16
  "exports": {
17
- ".": "./dist/index.mjs",
17
+ ".": {
18
+ "types": "./dist/index.d.mts",
19
+ "default": "./dist/index.mjs"
20
+ },
18
21
  "./bin": "./dist/bin.mjs",
19
- "./docker-verify": "./dist/docker-verify/index.mjs",
22
+ "./docker-verify": {
23
+ "types": "./dist/docker-verify/index.d.mts",
24
+ "default": "./dist/docker-verify/index.mjs"
25
+ },
20
26
  "./package.json": "./package.json"
21
27
  },
22
28
  "publishConfig": {
@@ -29,14 +35,14 @@
29
35
  "jsonc-parser": "^3.3.1",
30
36
  "yaml": "^2.8.2",
31
37
  "zod": "^4.3.6",
32
- "@bensandee/common": "0.1.1"
38
+ "@bensandee/common": "0.1.2"
33
39
  },
34
40
  "devDependencies": {
35
41
  "@types/node": "24.12.0",
36
- "tsdown": "0.21.0",
42
+ "tsdown": "0.21.2",
37
43
  "typescript": "5.9.3",
38
44
  "vitest": "4.0.18",
39
- "@bensandee/config": "0.8.0"
45
+ "@bensandee/config": "0.8.1"
40
46
  },
41
47
  "optionalDependencies": {
42
48
  "@changesets/cli": "^2.29.4",