140 lines · 4.5 KB · TypeScript
RawDownload
import {  CommandId,  EnvironmentId,  ORCHESTRATION_WS_METHODS,  ProjectId,  ThreadId,  type ClientOrchestrationCommand,} from "@t3tools/contracts";import { describe, expect, it } from "@effect/vitest";import * as Crypto from "effect/Crypto";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as SubscriptionRef from "effect/SubscriptionRef"; import {  AVAILABLE_CONNECTION_STATE,  PrimaryConnectionTarget,  type PreparedConnection,} from "../connection/model.ts";import {  EnvironmentSupervisor,  type EnvironmentSupervisorService,} from "../connection/supervisor.ts";import type { RpcSession } from "../rpc/session.ts";import type { WsRpcProtocolClient } from "../rpc/protocol.ts";import { archiveThread, createProject, stopThreadSession } from "./commands.ts"; const TEST_CRYPTO_LAYER = Layer.succeed(  Crypto.Crypto,  Crypto.make({    randomBytes: (size) => new Uint8Array(size),    digest: (_algorithm, data) => Effect.succeed(data),  }),); const TARGET = new PrimaryConnectionTarget({  environmentId: EnvironmentId.make("environment-1"),  label: "Test environment",  httpBaseUrl: "https://environment.example.test",  wsBaseUrl: "wss://environment.example.test",}); const makeSupervisor = Effect.fn("TestEnvironmentCommands.makeSupervisor")(function* (  dispatched: ClientOrchestrationCommand[],) {  const client = {    [ORCHESTRATION_WS_METHODS.dispatchCommand]: (command: ClientOrchestrationCommand) =>      Effect.sync(() => {        dispatched.push(command);        return { sequence: dispatched.length };      }),  } as unknown as WsRpcProtocolClient;  const session: RpcSession = {    client,    initialConfig: Effect.never,    ready: Effect.void,    probe: Effect.void,    closed: Effect.never,  };  return EnvironmentSupervisor.of({    target: TARGET,    state: yield* SubscriptionRef.make(AVAILABLE_CONNECTION_STATE),    session: yield* SubscriptionRef.make(Option.some(session)),    prepared: yield* SubscriptionRef.make(Option.none<PreparedConnection>()),    connect: Effect.void,    disconnect: Effect.void,    retryNow: Effect.void,  } satisfies EnvironmentSupervisorService);}); describe("environment commands", () => {  it.effect("adds generated command metadata", () =>    Effect.gen(function* () {      const dispatched: ClientOrchestrationCommand[] = [];      const supervisor = yield* makeSupervisor(dispatched);       const result = yield* createProject({        projectId: ProjectId.make("project-1"),        title: "Project",        workspaceRoot: "/workspace/project",        createdAt: "2026-06-06T00:00:00.000Z",      }).pipe(Effect.provideService(EnvironmentSupervisor, supervisor));       expect(result).toEqual({ sequence: 1 });      expect(dispatched).toEqual([        {          type: "project.create",          commandId: "00000000-0000-4000-8000-000000000000",          projectId: "project-1",          title: "Project",          workspaceRoot: "/workspace/project",          createdAt: "2026-06-06T00:00:00.000Z",        },      ]);    }).pipe(Effect.provide(TEST_CRYPTO_LAYER)),  );   it.effect("preserves caller metadata for idempotent queued commands", () =>    Effect.gen(function* () {      const dispatched: ClientOrchestrationCommand[] = [];      const supervisor = yield* makeSupervisor(dispatched);       yield* stopThreadSession({        commandId: CommandId.make("queued-command"),        threadId: ThreadId.make("thread-1"),        createdAt: "2026-06-06T00:01:00.000Z",      }).pipe(Effect.provideService(EnvironmentSupervisor, supervisor));       expect(dispatched).toEqual([        {          type: "thread.session.stop",          commandId: "queued-command",          threadId: "thread-1",          createdAt: "2026-06-06T00:01:00.000Z",        },      ]);    }).pipe(Effect.provide(TEST_CRYPTO_LAYER)),  );   it.effect("does not add timestamps to commands without createdAt", () =>    Effect.gen(function* () {      const dispatched: ClientOrchestrationCommand[] = [];      const supervisor = yield* makeSupervisor(dispatched);       yield* archiveThread({        commandId: CommandId.make("archive-command"),        threadId: ThreadId.make("thread-1"),      }).pipe(Effect.provideService(EnvironmentSupervisor, supervisor));       expect(dispatched).toEqual([        {          type: "thread.archive",          commandId: "archive-command",          threadId: "thread-1",        },      ]);    }).pipe(Effect.provide(TEST_CRYPTO_LAYER)),  );});