From 6754936a604726f82800625c4369c184d39b5db9 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Sat, 5 Sep 2026 04:52:43 +0000 Subject: [PATCH 1/2] fix(server): install pinned runtime when pnpm node lacks npm --- apps/server/src/cloud/pinnedRuntime.test.ts | 79 +++++++++++++++++++++ apps/server/src/cloud/pinnedRuntime.ts | 23 +++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/apps/server/src/cloud/pinnedRuntime.test.ts b/apps/server/src/cloud/pinnedRuntime.test.ts index f34f0f5cf4d7..a0ca9e5f0fa0 100644 --- a/apps/server/src/cloud/pinnedRuntime.test.ts +++ b/apps/server/src/cloud/pinnedRuntime.test.ts @@ -5,6 +5,7 @@ import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Fiber from "effect/Fiber"; import * as Path from "effect/Path"; +import * as PlatformError from "effect/PlatformError"; import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner"; import * as ProcessRunner from "../processRunner.ts"; @@ -38,6 +39,84 @@ const successfulRunner = (fs: FileSystem.FileSystem, path: Path.Path) => }); it.layer(NodeServices.layer)("ensurePinnedRuntimeInstalled", (it) => { + it.effect("installs through pnpm when its Node runtime has no npm executable", () => + Effect.gen(function* () { + const fs = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-pinned-pnpm-" }); + const commands: Array = []; + const install = successfulRunner(fs, path); + const paths = yield* ensurePinnedRuntimeInstalled({ + baseDir, + version: "1.2.3", + fs, + path, + runner: ProcessRunner.ProcessRunner.of({ + run: (input) => { + commands.push(input); + return input.command === "npm" + ? Effect.fail( + new ProcessRunner.ProcessSpawnError({ + command: "npm", + argumentCount: input.args.length, + cause: PlatformError.systemError({ + _tag: "NotFound", + module: "ChildProcess", + method: "spawn", + }), + }), + ) + : install.run(input); + }, + }), + validate: (staging) => + fs.exists(staging.entryPath).pipe( + Effect.flatMap((exists) => (exists ? Effect.void : Effect.die("missing runtime"))), + Effect.orDie, + ), + }); + assert.deepEqual( + commands.map((command) => command.command), + ["npm", "pnpm"], + ); + assert.deepEqual(commands[1]!.args, ["--package=npm@11", "dlx", "npm", ...commands[0]!.args]); + assert.equal(yield* fs.readFileString(paths.sentinelPath), "1.2.3\n"); + }), + ); + + it.effect("does not try a different installer for npm permission failures", () => + Effect.gen(function* () { + const fs = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-pinned-permission-" }); + const commands: string[] = []; + yield* ensurePinnedRuntimeInstalled({ + baseDir, + version: "1.2.3", + fs, + path, + runner: ProcessRunner.ProcessRunner.of({ + run: (input) => { + commands.push(input.command); + return Effect.fail( + new ProcessRunner.ProcessSpawnError({ + command: input.command, + argumentCount: input.args.length, + cause: PlatformError.systemError({ + _tag: "PermissionDenied", + module: "ChildProcess", + method: "spawn", + }), + }), + ); + }, + }), + validate: () => Effect.die("must not validate a failed install"), + }).pipe(Effect.flip); + assert.deepEqual(commands, ["npm"]); + }), + ); + it.effect("validates a staging tree before atomically publishing it", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; diff --git a/apps/server/src/cloud/pinnedRuntime.ts b/apps/server/src/cloud/pinnedRuntime.ts index 06628d5cc12f..3ae23deebc1c 100644 --- a/apps/server/src/cloud/pinnedRuntime.ts +++ b/apps/server/src/cloud/pinnedRuntime.ts @@ -2,6 +2,7 @@ import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; +import * as PlatformError from "effect/PlatformError"; import * as Schema from "effect/Schema"; import * as Option from "effect/Option"; import * as Semaphore from "effect/Semaphore"; @@ -152,14 +153,34 @@ const installPinnedRuntime = Effect.fn("cloud.pinned_runtime.ensure_installed")( return yield* Effect.gen(function* () { const installStep = "installing the pinned t3 runtime (this can take a few minutes)"; + const installArgs = [ + "install", + "--prefix", + stagingDir, + "--no-fund", + "--no-audit", + `t3@${input.version}`, + ]; yield* runner .run({ command: "npm", - args: ["install", "--prefix", stagingDir, "--no-fund", "--no-audit", `t3@${input.version}`], + args: installArgs, // Native dependencies may compile from source on slower machines. timeout: PINNED_RUNTIME_INSTALL_TIMEOUT, }) .pipe( + Effect.catchTag("ProcessSpawnError", (error) => + error.cause instanceof PlatformError.PlatformError && + error.cause.reason._tag === "NotFound" + ? // pnpm-managed Node installations do not include npm. Keep npm + // installation semantics for the pinned runtime and native builds. + runner.run({ + command: "pnpm", + args: ["--package=npm@11", "dlx", "npm", ...installArgs], + timeout: PINNED_RUNTIME_INSTALL_TIMEOUT, + }) + : Effect.fail(error), + ), Effect.mapError((cause) => new PinnedRuntimeInstallError({ step: installStep, cause })), Effect.filterOrFail( (result) => result.code === 0, From e8c08859dd41a49dbf9a8c7f7addbc05d36ec5a2 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Sat, 5 Sep 2026 05:06:22 +0000 Subject: [PATCH 2/2] refactor(server): use tagged installer error handler --- apps/server/src/cloud/pinnedRuntime.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/server/src/cloud/pinnedRuntime.ts b/apps/server/src/cloud/pinnedRuntime.ts index 3ae23deebc1c..cf8a7c3cab6b 100644 --- a/apps/server/src/cloud/pinnedRuntime.ts +++ b/apps/server/src/cloud/pinnedRuntime.ts @@ -169,18 +169,19 @@ const installPinnedRuntime = Effect.fn("cloud.pinned_runtime.ensure_installed")( timeout: PINNED_RUNTIME_INSTALL_TIMEOUT, }) .pipe( - Effect.catchTag("ProcessSpawnError", (error) => - error.cause instanceof PlatformError.PlatformError && - error.cause.reason._tag === "NotFound" - ? // pnpm-managed Node installations do not include npm. Keep npm - // installation semantics for the pinned runtime and native builds. - runner.run({ - command: "pnpm", - args: ["--package=npm@11", "dlx", "npm", ...installArgs], - timeout: PINNED_RUNTIME_INSTALL_TIMEOUT, - }) - : Effect.fail(error), - ), + Effect.catchTags({ + ProcessSpawnError: (error) => + error.cause instanceof PlatformError.PlatformError && + error.cause.reason._tag === "NotFound" + ? // pnpm-managed Node installations do not include npm. Keep npm + // installation semantics for the pinned runtime and native builds. + runner.run({ + command: "pnpm", + args: ["--package=npm@11", "dlx", "npm", ...installArgs], + timeout: PINNED_RUNTIME_INSTALL_TIMEOUT, + }) + : Effect.fail(error), + }), Effect.mapError((cause) => new PinnedRuntimeInstallError({ step: installStep, cause })), Effect.filterOrFail( (result) => result.code === 0,