| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | import * as NodeServices from "@effect/platform-node/NodeServices"; | 1 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 2 | import { describe, expect, it } from "@effect/vitest"; | 2 | import { describe, expect, it } from "@effect/vitest"; |
| 3 | import * as Effect from "effect/Effect"; | 3 | import * as Effect from "effect/Effect"; |
| 4 | import * as FileSystem from "effect/FileSystem"; | 4 | import * as Layer from "effect/Layer"; |
| 5 | import * as Option from "effect/Option"; | 5 | import * as Option from "effect/Option"; |
| 6 | import * as Path from "effect/Path"; | 6 | import * as Path from "effect/Path"; |
| 7 | import * as PlatformError from "effect/PlatformError"; | 7 | import * as PlatformError from "effect/PlatformError"; |
| ... | @@ -18,6 +18,12 @@ import { RelayClientTracer } from "@t3tools/shared/relayTracing"; | ... | @@ -18,6 +18,12 @@ import { RelayClientTracer } from "@t3tools/shared/relayTracing"; |
| 18 | import * as EnvironmentAuth from "../auth/EnvironmentAuth.ts"; | 18 | import * as EnvironmentAuth from "../auth/EnvironmentAuth.ts"; |
| 19 | import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; | 19 | import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; |
| 20 | import * as ServerConfigModule from "../config.ts"; | 20 | import * as ServerConfigModule from "../config.ts"; |
| | 21 | import { writeServiceState } from "../serviceLauncher.ts"; |
| | 22 | import { |
| | 23 | SERVICE_LAUNCHER_PROTOCOL, |
| | 24 | SERVICE_STATE_FILE, |
| | 25 | type ServiceUpdateRecord, |
| | 26 | } from "./serviceProtocol.ts"; |
| 21 | import * as ServerEnvironment from "../environment/ServerEnvironment.ts"; | 27 | import * as ServerEnvironment from "../environment/ServerEnvironment.ts"; |
| 22 | import { CLOUD_CLI_DESIRED_LINK_SECRET } from "./CliState.ts"; | 28 | import { CLOUD_CLI_DESIRED_LINK_SECRET } from "./CliState.ts"; |
| 23 | import * as CliTokenManager from "./CliTokenManager.ts"; | 29 | import * as CliTokenManager from "./CliTokenManager.ts"; |
| ... | @@ -259,18 +265,20 @@ describe("releaseManagedTunnelOnShutdown", () => { | ... | @@ -259,18 +265,20 @@ describe("releaseManagedTunnelOnShutdown", () => { |
| 259 | readonly respond?: () => Response; | 265 | readonly respond?: () => Response; |
| 260 | } | 266 | } |
| 261 | | 267 | |
| 262 | // Writes the launcher's durable state file into this test's baseDir; the | 268 | // Writes the launcher's durable state file into this test's baseDir with |
| 263 | // release reads it to detect an in-flight update handoff. | 269 | // the launcher's own writer; the release reads it to detect an in-flight |
| 264 | const writeServiceState = (update: Record<string, unknown>) => | 270 | // update handoff. |
| | 271 | const writeLauncherState = (update: ServiceUpdateRecord) => |
| 265 | Effect.gen(function* () { | 272 | Effect.gen(function* () { |
| 266 | const fs = yield* FileSystem.FileSystem; | | |
| 267 | const path = yield* Path.Path; | 273 | const path = yield* Path.Path; |
| 268 | const config = yield* ServerConfigModule.ServerConfig; | 274 | const config = yield* ServerConfigModule.ServerConfig; |
| 269 | const statePath = path.join(config.baseDir, "runtime", "service-state.json"); | 275 | const statePath = path.join(config.baseDir, "runtime", SERVICE_STATE_FILE); |
| 270 | yield* fs.makeDirectory(path.dirname(statePath), { recursive: true }); | 276 | yield* Effect.promise(() => |
| 271 | yield* fs.writeFileString( | 277 | writeServiceState(statePath, { |
| 272 | statePath, | 278 | protocol: SERVICE_LAUNCHER_PROTOCOL, |
| 273 | JSON.stringify({ version: 1, activeVersion: "0.0.30", update }), | 279 | activeVersion: "0.0.30", |
| | 280 | update, |
| | 281 | }), |
| 274 | ); | 282 | ); |
| 275 | }); | 283 | }); |
| 276 | | 284 | |
| ... | @@ -326,8 +334,11 @@ describe("releaseManagedTunnelOnShutdown", () => { | ... | @@ -326,8 +334,11 @@ describe("releaseManagedTunnelOnShutdown", () => { |
| 326 | ), | 334 | ), |
| 327 | // The release consults the launcher state file under the configured | 335 | // The release consults the launcher state file under the configured |
| 328 | // baseDir, so every harness run gets a scoped temp baseDir. | 336 | // baseDir, so every harness run gets a scoped temp baseDir. |
| 329 | Effect.provide(ServerConfigModule.layerTest("/", { prefix: "t3-http-release-test-" })), | 337 | Effect.provide( |
| 330 | Effect.provide(NodeServices.layer), | 338 | ServerConfigModule.layerTest("/", { prefix: "t3-http-release-test-" }).pipe( |
| | 339 | Layer.provideMerge(NodeServices.layer), |
| | 340 | ), |
| | 341 | ), |
| 331 | Effect.scoped, | 342 | Effect.scoped, |
| 332 | ); | 343 | ); |
| 333 | | 344 | |
| ... | @@ -419,7 +430,7 @@ describe("releaseManagedTunnelOnShutdown", () => { | ... | @@ -419,7 +430,7 @@ describe("releaseManagedTunnelOnShutdown", () => { |
| 419 | const requests: Array<HttpClientRequest.HttpClientRequest> = []; | 430 | const requests: Array<HttpClientRequest.HttpClientRequest> = []; |
| 420 | | 431 | |
| 421 | return Effect.gen(function* () { | 432 | return Effect.gen(function* () { |
| 422 | yield* writeServiceState({ | 433 | yield* writeLauncherState({ |
| 423 | id: "update-1", | 434 | id: "update-1", |
| 424 | fromVersion: "0.0.30", | 435 | fromVersion: "0.0.30", |
| 425 | targetVersion: "0.0.31", | 436 | targetVersion: "0.0.31", |
| ... | @@ -446,7 +457,7 @@ describe("releaseManagedTunnelOnShutdown", () => { | ... | @@ -446,7 +457,7 @@ describe("releaseManagedTunnelOnShutdown", () => { |
| 446 | const requests: Array<HttpClientRequest.HttpClientRequest> = []; | 457 | const requests: Array<HttpClientRequest.HttpClientRequest> = []; |
| 447 | | 458 | |
| 448 | return Effect.gen(function* () { | 459 | return Effect.gen(function* () { |
| 449 | yield* writeServiceState({ | 460 | yield* writeLauncherState({ |
| 450 | id: "update-1", | 461 | id: "update-1", |
| 451 | fromVersion: "0.0.30", | 462 | fromVersion: "0.0.30", |
| 452 | targetVersion: "0.0.31", | 463 | targetVersion: "0.0.31", |