From 5b7c67c1e33a5bb8dbcb3269c47b14c2a6fa6cb0 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 19 Jun 2026 18:08:33 -0700 Subject: [PATCH] refactor server cloud Effect services Co-authored-by: codex --- apps/server/src/cloud/CliTokenManager.ts | 102 ++++++++++++------ .../src/cloud/ManagedEndpointRuntime.test.ts | 98 +++++++++-------- .../src/cloud/ManagedEndpointRuntime.ts | 57 +++++----- apps/server/src/cloud/http.test.ts | 23 ++-- apps/server/src/cloud/http.ts | 40 +++---- 5 files changed, 180 insertions(+), 140 deletions(-) diff --git a/apps/server/src/cloud/CliTokenManager.ts b/apps/server/src/cloud/CliTokenManager.ts index 88a61f5df74..f2ad5e621ec 100644 --- a/apps/server/src/cloud/CliTokenManager.ts +++ b/apps/server/src/cloud/CliTokenManager.ts @@ -6,7 +6,6 @@ import * as Clock from "effect/Clock"; import * as Console from "effect/Console"; import * as Context from "effect/Context"; import * as Crypto from "effect/Crypto"; -import * as Data from "effect/Data"; import * as Deferred from "effect/Deferred"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; @@ -15,10 +14,12 @@ import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import * as Semaphore from "effect/Semaphore"; +import * as HttpClient from "effect/unstable/http/HttpClient"; +import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest"; +import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"; import * as HttpRouter from "effect/unstable/http/HttpRouter"; import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest"; import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse"; -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"; import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; import { cloudCliOAuthConfig, type CloudCliOAuthConfig } from "./publicConfig.ts"; @@ -45,35 +46,74 @@ const OAuthTokenResponse = Schema.Struct({ token_type: Schema.String, }); -export class CloudCliTokenManagerError extends Data.TaggedError("CloudCliTokenManagerError")<{ - readonly message: string; - readonly cause?: unknown; -}> {} +export class CloudCliCredentialRemovalError extends Schema.TaggedErrorClass()( + "CloudCliCredentialRemovalError", + { cause: Schema.Defect() }, +) { + override get message(): string { + return "Could not remove the stored T3 Connect CLI credential."; + } +} + +export class CloudCliCredentialRefreshError extends Schema.TaggedErrorClass()( + "CloudCliCredentialRefreshError", + { cause: Schema.Defect() }, +) { + override get message(): string { + return "Could not refresh the T3 Connect CLI credential."; + } +} + +export class CloudCliCredentialReadError extends Schema.TaggedErrorClass()( + "CloudCliCredentialReadError", + { cause: Schema.Defect() }, +) { + override get message(): string { + return "Could not read the stored T3 Connect CLI credential."; + } +} + +export class CloudCliAuthorizationError extends Schema.TaggedErrorClass()( + "CloudCliAuthorizationError", + { cause: Schema.Defect() }, +) { + override get message(): string { + return "Could not authorize the T3 Connect CLI."; + } +} -export interface CloudCliTokenManagerShape { - readonly get: Effect.Effect; - readonly getExisting: Effect.Effect, CloudCliTokenManagerError>; - readonly hasCredential: Effect.Effect; - readonly clear: Effect.Effect; +export class CloudCliAuthorizationTimeoutError extends Schema.TaggedErrorClass()( + "CloudCliAuthorizationTimeoutError", + { cause: Schema.Defect() }, +) { + override get message(): string { + return "Timed out waiting for T3 Connect authorization."; + } } +export const CloudCliTokenManagerError = Schema.Union([ + CloudCliCredentialRemovalError, + CloudCliCredentialRefreshError, + CloudCliCredentialReadError, + CloudCliAuthorizationError, + CloudCliAuthorizationTimeoutError, +]); +export type CloudCliTokenManagerError = typeof CloudCliTokenManagerError.Type; + export class CloudCliTokenManager extends Context.Service< CloudCliTokenManager, - CloudCliTokenManagerShape + { + readonly get: Effect.Effect; + readonly getExisting: Effect.Effect, CloudCliTokenManagerError>; + readonly hasCredential: Effect.Effect; + readonly clear: Effect.Effect; + } >()("t3/cloud/CliTokenManager/CloudCliTokenManager") {} const wrapError = - (message: string) => - (effect: Effect.Effect): Effect.Effect => - effect.pipe( - Effect.mapError( - (cause) => - new CloudCliTokenManagerError({ - message, - cause, - }), - ), - ); + (makeError: (cause: unknown) => WrappedError) => + (effect: Effect.Effect): Effect.Effect => + effect.pipe(Effect.mapError(makeError)); function stringToBytes(value: string): Uint8Array { return new TextEncoder().encode(value); @@ -83,7 +123,7 @@ function bytesToString(value: Uint8Array): string { return new TextDecoder().decode(value); } -const make = Effect.gen(function* () { +export const make = Effect.gen(function* () { const crypto = yield* Crypto.Crypto; const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.filterStatusOk); const secrets = yield* ServerSecretStore.ServerSecretStore; @@ -96,7 +136,7 @@ const make = Effect.gen(function* () { const clear = secrets .remove(CLOUD_CLI_OAUTH_TOKEN_SECRET) - .pipe(wrapError("Could not remove the stored T3 Connect CLI credential.")); + .pipe(wrapError((cause) => new CloudCliCredentialRemovalError({ cause }))); const read = Effect.fn("cloud.cli_token.read")(function* () { const encoded = yield* secrets.get(CLOUD_CLI_OAUTH_TOKEN_SECRET); @@ -185,10 +225,10 @@ const make = Effect.gen(function* () { yield* Console.log(`Open this URL to authorize T3 Connect:\n${authorizationUrl.toString()}\n`); const code = yield* Deferred.await(callback).pipe( Effect.timeout(CLOUD_CLI_OAUTH_CALLBACK_TIMEOUT), - Effect.catchTag("TimeoutError", () => + Effect.catchTag("TimeoutError", (cause) => Effect.fail( - new CloudCliTokenManagerError({ - message: "Timed out waiting for T3 Connect authorization.", + new CloudCliAuthorizationTimeoutError({ + cause, }), ), ), @@ -213,12 +253,12 @@ const make = Effect.gen(function* () { }); const getExisting = semaphore.withPermits(1)( - getExistingNoLock().pipe(wrapError("Could not refresh the T3 Connect CLI credential.")), + getExistingNoLock().pipe(wrapError((cause) => new CloudCliCredentialRefreshError({ cause }))), ); const hasCredential = semaphore.withPermits(1)( read().pipe( Effect.map(Option.isSome), - wrapError("Could not read the stored T3 Connect CLI credential."), + wrapError((cause) => new CloudCliCredentialReadError({ cause })), ), ); const get = semaphore.withPermits(1)( @@ -227,7 +267,7 @@ const make = Effect.gen(function* () { return Option.isSome(token) ? token.value : yield* Effect.scoped(login()).pipe(Effect.flatMap(persist)); - }).pipe(wrapError("Could not authorize the T3 Connect CLI.")), + }).pipe(wrapError((cause) => new CloudCliAuthorizationError({ cause }))), ); return CloudCliTokenManager.of({ get, getExisting, hasCredential, clear }); diff --git a/apps/server/src/cloud/ManagedEndpointRuntime.test.ts b/apps/server/src/cloud/ManagedEndpointRuntime.test.ts index 02c4b0d09ac..e0d5924fcc2 100644 --- a/apps/server/src/cloud/ManagedEndpointRuntime.test.ts +++ b/apps/server/src/cloud/ManagedEndpointRuntime.test.ts @@ -4,16 +4,15 @@ import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as Layer from "effect/Layer"; +import * as Option from "effect/Option"; import * as PlatformError from "effect/PlatformError"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; import * as RelayClient from "@t3tools/shared/relayClient"; -import { - classifyRelayClientOutput, - makeCloudManagedEndpointRuntime, -} from "./ManagedEndpointRuntime.ts"; +import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; +import * as ManagedEndpointRuntime from "./ManagedEndpointRuntime.ts"; const relayClientAvailableLayer = Layer.succeed( RelayClient.RelayClient, @@ -29,12 +28,33 @@ const relayClientAvailableLayer = Layer.succeed( }), ); -const runtimeDependencies = (spawner: ReturnType) => +const runtimeDependencies = ( + spawner: ReturnType, + relayClientLayer = relayClientAvailableLayer, +) => Layer.mergeAll( Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner), - relayClientAvailableLayer, + relayClientLayer, + Layer.mock(ServerSecretStore.ServerSecretStore)({ + get: () => Effect.succeed(Option.none()), + }), ); +const buildCloudManagedEndpointRuntime = ( + spawner: ReturnType, + relayClientLayer = relayClientAvailableLayer, +) => + Effect.gen(function* () { + const context = yield* Layer.build( + ManagedEndpointRuntime.layer.pipe( + Layer.provide(runtimeDependencies(spawner, relayClientLayer)), + ), + ); + return yield* Effect.service(ManagedEndpointRuntime.CloudManagedEndpointRuntime).pipe( + Effect.provide(context), + ); + }); + function makeHandle(input: { readonly pid: number; readonly onKill: () => void; @@ -62,16 +82,20 @@ function makeHandle(input: { describe("CloudManagedEndpointRuntime", () => { it("classifies Cloudflare connection and warning output", () => { expect( - classifyRelayClientOutput( + ManagedEndpointRuntime.classifyRelayClientOutput( "2026-06-17T02:00:00Z INF Registered tunnel connection connIndex=0", ), ).toBe("connected"); expect( - classifyRelayClientOutput("2026-06-17T02:00:00Z ERR Failed to serve tunnel connection"), + ManagedEndpointRuntime.classifyRelayClientOutput( + "2026-06-17T02:00:00Z ERR Failed to serve tunnel connection", + ), ).toBe("warning"); - expect(classifyRelayClientOutput("2026-06-17T02:00:00Z INF Starting metrics server")).toBe( - "debug", - ); + expect( + ManagedEndpointRuntime.classifyRelayClientOutput( + "2026-06-17T02:00:00Z INF Starting metrics server", + ), + ).toBe("debug"); }); it.effect("starts, deduplicates, rotates, and stops the Cloudflare connector", () => @@ -97,9 +121,7 @@ describe("CloudManagedEndpointRuntime", () => { return handle; }), ); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide(runtimeDependencies(spawner)), - ); + const runtime = yield* buildCloudManagedEndpointRuntime(spawner); yield* runtime.applyConfig({ providerKind: "cloudflare_tunnel", @@ -154,9 +176,7 @@ describe("CloudManagedEndpointRuntime", () => { return handle; }), ); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide(runtimeDependencies(spawner)), - ); + const runtime = yield* buildCloudManagedEndpointRuntime(spawner); const started = yield* runtime.applyConfig({ providerKind: "cloudflare_tunnel", @@ -193,9 +213,7 @@ describe("CloudManagedEndpointRuntime", () => { return handle; }), ); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide(runtimeDependencies(spawner)), - ); + const runtime = yield* buildCloudManagedEndpointRuntime(spawner); const config = { providerKind: "cloudflare_tunnel" as const, connectorToken: "token", @@ -240,9 +258,7 @@ describe("CloudManagedEndpointRuntime", () => { return handle; }), ); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide(runtimeDependencies(spawner)), - ); + const runtime = yield* buildCloudManagedEndpointRuntime(spawner); const started = yield* runtime.applyConfig({ providerKind: "cloudflare_tunnel", @@ -282,9 +298,7 @@ describe("CloudManagedEndpointRuntime", () => { return handle; }), ); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide(runtimeDependencies(spawner)), - ); + const runtime = yield* buildCloudManagedEndpointRuntime(spawner); const first = yield* runtime .applyConfig({ @@ -322,9 +336,7 @@ describe("CloudManagedEndpointRuntime", () => { }), ), ); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide(runtimeDependencies(spawner)), - ); + const runtime = yield* buildCloudManagedEndpointRuntime(spawner); const status = yield* runtime.applyConfig({ providerKind: "cloudflare_tunnel", @@ -344,22 +356,18 @@ describe("CloudManagedEndpointRuntime", () => { Effect.gen(function* () { const spawn = vi.fn(); const spawner = ChildProcessSpawner.make(spawn); - const runtime = yield* makeCloudManagedEndpointRuntime.pipe( - Effect.provide( - Layer.mergeAll( - Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner), - Layer.succeed( - RelayClient.RelayClient, - RelayClient.RelayClient.of({ - resolve: Effect.succeed({ - status: "missing", - version: RelayClient.CLOUDFLARED_VERSION, - }), - install: Effect.die("unused"), - installWithProgress: () => Effect.die("unused"), - }), - ), - ), + const runtime = yield* buildCloudManagedEndpointRuntime( + spawner, + Layer.succeed( + RelayClient.RelayClient, + RelayClient.RelayClient.of({ + resolve: Effect.succeed({ + status: "missing", + version: RelayClient.CLOUDFLARED_VERSION, + }), + install: Effect.die("unused"), + installWithProgress: () => Effect.die("unused"), + }), ), ); diff --git a/apps/server/src/cloud/ManagedEndpointRuntime.ts b/apps/server/src/cloud/ManagedEndpointRuntime.ts index f2eedaf0c6d..a1d7112a929 100644 --- a/apps/server/src/cloud/ManagedEndpointRuntime.ts +++ b/apps/server/src/cloud/ManagedEndpointRuntime.ts @@ -10,7 +10,8 @@ import * as Result from "effect/Result"; import * as Semaphore from "effect/Semaphore"; import * as Scope from "effect/Scope"; import * as Stream from "effect/Stream"; -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; +import * as ChildProcess from "effect/unstable/process/ChildProcess"; +import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner"; import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; import { CLOUD_ENDPOINT_RUNTIME_CONFIG, decodeRuntimeConfig } from "./config.ts"; @@ -28,17 +29,6 @@ const readRuntimeConfig = Effect.gen(function* () { return Option.getOrNull(decodeRuntimeConfig(bytesToString(bytes.value))); }); -export interface CloudManagedEndpointRuntimeShape { - readonly applyConfig: ( - config: RelayManagedEndpointRuntimeConfig | null, - ) => Effect.Effect; -} - -export class CloudManagedEndpointRuntime extends Context.Service< - CloudManagedEndpointRuntime, - CloudManagedEndpointRuntimeShape ->()("t3/cloud/ManagedEndpointRuntime/CloudManagedEndpointRuntime") {} - export type CloudManagedEndpointRuntimeStatus = | { readonly status: "disabled"; @@ -62,6 +52,15 @@ export type CloudManagedEndpointRuntimeStatus = readonly providerKind: RelayManagedEndpointRuntimeConfig["providerKind"]; }; +export class CloudManagedEndpointRuntime extends Context.Service< + CloudManagedEndpointRuntime, + { + readonly applyConfig: ( + config: RelayManagedEndpointRuntimeConfig | null, + ) => Effect.Effect; + } +>()("t3/cloud/ManagedEndpointRuntime/CloudManagedEndpointRuntime") {} + interface ActiveConnector { readonly child: ChildProcessSpawner.ChildProcessHandle; readonly scope: Scope.Closeable; @@ -97,13 +96,13 @@ const stopConnector = (connector: ActiveConnector | null) => ) : Effect.void; -export const makeCloudManagedEndpointRuntime = Effect.gen(function* () { +export const make = Effect.gen(function* () { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const relayClient = yield* RelayClient.RelayClient; const activeRef = yield* Ref.make(null); const desiredConfigRef = yield* Ref.make(null); const reconcileSemaphore = yield* Semaphore.make(1); - let reconcileConfig: CloudManagedEndpointRuntimeShape["applyConfig"]; + let reconcileConfig: CloudManagedEndpointRuntime["Service"]["applyConfig"]; const stopActive = Effect.gen(function* () { const active = yield* Ref.getAndSet(activeRef, null); @@ -301,24 +300,20 @@ export const makeCloudManagedEndpointRuntime = Effect.gen(function* () { ), ); - return CloudManagedEndpointRuntime.of({ + const runtime = CloudManagedEndpointRuntime.of({ applyConfig, }); -}); -export const layer = Layer.effect( - CloudManagedEndpointRuntime, - Effect.gen(function* () { - const runtime = yield* makeCloudManagedEndpointRuntime; - const initialConfig = yield* readRuntimeConfig.pipe( - Effect.catch((cause) => - Effect.logWarning("Failed to read managed endpoint runtime config", { cause }).pipe( - Effect.as(null), - ), + const initialConfig = yield* readRuntimeConfig.pipe( + Effect.catch((cause) => + Effect.logWarning("Failed to read managed endpoint runtime config", { cause }).pipe( + Effect.as(null), ), - ); - yield* runtime.applyConfig(initialConfig); - yield* Effect.addFinalizer(() => runtime.applyConfig(null)); - return runtime; - }), -); + ), + ); + yield* runtime.applyConfig(initialConfig); + yield* Effect.addFinalizer(() => runtime.applyConfig(null)); + return runtime; +}); + +export const layer = Layer.effect(CloudManagedEndpointRuntime, make); diff --git a/apps/server/src/cloud/http.test.ts b/apps/server/src/cloud/http.test.ts index 78285eb7dcd..3a8586f150a 100644 --- a/apps/server/src/cloud/http.test.ts +++ b/apps/server/src/cloud/http.test.ts @@ -9,13 +9,10 @@ import { HttpClient, HttpServerRequest } from "effect/unstable/http"; import { RelayClientTracer } from "@t3tools/shared/relayTracing"; import * as EnvironmentAuth from "../auth/EnvironmentAuth.ts"; import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; -import { ServerEnvironment } from "../environment/Services/ServerEnvironment.ts"; +import * as ServerEnvironment from "../environment/Services/ServerEnvironment.ts"; import * as CliTokenManager from "./CliTokenManager.ts"; import { consumeCloudReplayGuards, reconcileDesiredCloudLink } from "./http.ts"; -import { - CloudManagedEndpointRuntime, - type CloudManagedEndpointRuntimeShape, -} from "./ManagedEndpointRuntime.ts"; +import * as ManagedEndpointRuntime from "./ManagedEndpointRuntime.ts"; import { traceAuthenticatedRelayRequest, traceRelayRequest } from "./traceRelayRequest.ts"; const storeFailure = (tag: "AlreadyExists" | "PermissionDenied") => @@ -32,8 +29,8 @@ const storeFailure = (tag: "AlreadyExists" | "PermissionDenied") => const unusedSecretStoreOperation = () => Effect.die("unused secret-store operation"); function makeSecretStore( - create: ServerSecretStore.ServerSecretStoreShape["create"], -): ServerSecretStore.ServerSecretStoreShape { + create: ServerSecretStore.ServerSecretStore["Service"]["create"], +): ServerSecretStore.ServerSecretStore["Service"] { return { get: unusedSecretStoreOperation, set: unusedSecretStoreOperation, @@ -151,21 +148,21 @@ describe("reconcileDesiredCloudLink", () => { makeSecretStore(unusedSecretStoreOperation), ), Effect.provideService( - ServerEnvironment, - ServerEnvironment.of({ + ServerEnvironment.ServerEnvironment, + ServerEnvironment.ServerEnvironment.of({ getEnvironmentId: unusedSecretStoreOperation(), getDescriptor: unusedSecretStoreOperation(), }), ), Effect.provideService( - CloudManagedEndpointRuntime, - CloudManagedEndpointRuntime.of({ + ManagedEndpointRuntime.CloudManagedEndpointRuntime, + ManagedEndpointRuntime.CloudManagedEndpointRuntime.of({ applyConfig: unusedSecretStoreOperation, - } satisfies CloudManagedEndpointRuntimeShape), + } satisfies ManagedEndpointRuntime.CloudManagedEndpointRuntime["Service"]), ), Effect.provideService( EnvironmentAuth.EnvironmentAuth, - EnvironmentAuth.EnvironmentAuth.of({} as EnvironmentAuth.EnvironmentAuthShape), + EnvironmentAuth.EnvironmentAuth.of({} as EnvironmentAuth.EnvironmentAuth["Service"]), ), Effect.provideService( CliTokenManager.CloudCliTokenManager, diff --git a/apps/server/src/cloud/http.ts b/apps/server/src/cloud/http.ts index 773891124c5..86716b69a35 100644 --- a/apps/server/src/cloud/http.ts +++ b/apps/server/src/cloud/http.ts @@ -55,14 +55,8 @@ import * as HttpApiBuilder from "effect/unstable/httpapi/HttpApiBuilder"; import * as EnvironmentAuth from "../auth/EnvironmentAuth.ts"; import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; import { requireEnvironmentScope } from "../auth/http.ts"; -import { - ServerEnvironment, - type ServerEnvironmentShape, -} from "../environment/Services/ServerEnvironment.ts"; -import { - CloudManagedEndpointRuntime, - type CloudManagedEndpointRuntimeShape, -} from "./ManagedEndpointRuntime.ts"; +import * as ServerEnvironment from "../environment/Services/ServerEnvironment.ts"; +import * as ManagedEndpointRuntime from "./ManagedEndpointRuntime.ts"; import { CLOUD_ENDPOINT_RUNTIME_CONFIG, CLOUD_LINKED_USER_ID, @@ -103,6 +97,9 @@ const failEnvironmentCloudInternalError = Effect.flatMap(() => Effect.fail(new EnvironmentHttpInternalServerError({ message }))), ); +const failCloudCliTokenManagerError = (error: CliTokenManager.CloudCliTokenManagerError) => + failEnvironmentCloudInternalError(error.message)(error.cause); + const requireRelayUrl = relayUrlConfig.pipe( Effect.mapError( () => @@ -121,7 +118,7 @@ function stringToBytes(value: string): Uint8Array { } export function consumeCloudReplayGuards(input: { - readonly secrets: ServerSecretStore.ServerSecretStoreShape; + readonly secrets: ServerSecretStore.ServerSecretStore["Service"]; readonly names: ReadonlyArray; readonly value: Uint8Array; }) { @@ -208,7 +205,7 @@ function validateRelayConfigPayload( } function validateLinkedCloudUser(input: { - readonly secrets: ServerSecretStore.ServerSecretStoreShape; + readonly secrets: ServerSecretStore.ServerSecretStore["Service"]; readonly cloudUserId: string; }): Effect.Effect { return input.secrets.get(CLOUD_LINKED_USER_ID).pipe( @@ -237,7 +234,7 @@ function validateLinkedCloudUser(input: { } function readInstalledCloudUserId( - secrets: ServerSecretStore.ServerSecretStoreShape, + secrets: ServerSecretStore.ServerSecretStore["Service"], ): Effect.Effect { return secrets.get(CLOUD_LINKED_USER_ID).pipe( Effect.mapError( @@ -335,19 +332,19 @@ const decodeCloudHealthProof = Schema.decodeUnknownEffect(RelayCloudEnvironmentH const decodeCloudMintProof = Schema.decodeUnknownEffect(RelayCloudMintCredentialProofPayload); interface CloudHttpDependencies { - readonly secrets: ServerSecretStore.ServerSecretStoreShape; - readonly environment: ServerEnvironmentShape; - readonly endpointRuntime: CloudManagedEndpointRuntimeShape; - readonly environmentAuth: EnvironmentAuth.EnvironmentAuthShape; - readonly cliTokenManager: CliTokenManager.CloudCliTokenManagerShape; + readonly secrets: ServerSecretStore.ServerSecretStore["Service"]; + readonly environment: ServerEnvironment.ServerEnvironment["Service"]; + readonly endpointRuntime: ManagedEndpointRuntime.CloudManagedEndpointRuntime["Service"]; + readonly environmentAuth: EnvironmentAuth.EnvironmentAuth["Service"]; + readonly cliTokenManager: CliTokenManager.CloudCliTokenManager["Service"]; readonly httpClient: HttpClient.HttpClient; } const cloudHttpDependencies = Effect.gen(function* () { return { secrets: yield* ServerSecretStore.ServerSecretStore, - environment: yield* ServerEnvironment, - endpointRuntime: yield* CloudManagedEndpointRuntime, + environment: yield* ServerEnvironment.ServerEnvironment, + endpointRuntime: yield* ManagedEndpointRuntime.CloudManagedEndpointRuntime, environmentAuth: yield* EnvironmentAuth.EnvironmentAuth, cliTokenManager: yield* CliTokenManager.CloudCliTokenManager, httpClient: yield* HttpClient.HttpClient, @@ -595,8 +592,11 @@ const reconcileDesiredCloudLinkWith = Effect.fn("environment.cloud.reconcileDesi }); }, Effect.catchTags({ - CloudCliTokenManagerError: (error) => - failEnvironmentCloudInternalError(error.message)(error.cause), + CloudCliCredentialRemovalError: failCloudCliTokenManagerError, + CloudCliCredentialRefreshError: failCloudCliTokenManagerError, + CloudCliCredentialReadError: failCloudCliTokenManagerError, + CloudCliAuthorizationError: failCloudCliTokenManagerError, + CloudCliAuthorizationTimeoutError: failCloudCliTokenManagerError, SecretStoreError: failEnvironmentCloudInternalError( "Could not persist desired T3 Connect link state.", ),