import { createServer } from "node:http";import { readFileSync } from "node:fs";import { join } from "node:path"; import { FileSystem } from "@effect/platform";import { NodeFileSystem } from "@effect/platform-node";import { describe, expect, it } from "@effect/vitest";import { assertTrue } from "@effect/vitest/utils";import * as Effect from "effect/Effect";import * as Fiber from "effect/Fiber";import * as Option from "effect/Option"; import type { AccountId } from "#schema";import { ExecutionIdSchema, ExecutionInteractionIdSchema, type ExecutionInteraction, ProviderAuthGrantIdSchema, SecretMaterialIdSchema, SourceAuthSessionIdSchema, SourceIdSchema, WorkspaceOauthClientIdSchema,} from "#schema";import type { ToolPath } from "@executor/codemode-core"; import { type ControlPlaneRuntime, createControlPlaneRuntime, LiveExecutionManagerService, provideControlPlaneRuntime,} from "./index";import { createSourceFromPayload } from "./source-definitions";import { decodeSourceCredentialSelectionContent } from "./source-credential-interactions";import { persistSource } from "./source-store";import { withControlPlaneClient } from "./test-http-client"; const makeRuntime = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const workspaceRoot = yield* fs.makeTempDirectoryScoped({ prefix: "executor-control-plane-runtime-", }); const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); return yield* Effect.acquireRelease( createControlPlaneRuntime({ workspaceRoot, homeConfigPath, homeStateDirectory, }), (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), );}).pipe(Effect.provide(NodeFileSystem.layer)); type OpenApiSpecServer = { baseUrl: string; specUrl: string; close: () => Promise<void>;}; type GoogleWorkspaceTestServer = { baseUrl: string; tokenEndpoint: string; discoveryUrl: (input: { service: string; version: string; scope: string; }) => string; queueTokenResponse: (response: { access_token: string; refresh_token?: string; expires_in?: number; scope?: string; }) => void; tokenRequests: URLSearchParams[]; discoveryAuthorizations: string[]; close: () => Promise<void>;}; const makeOpenApiSpecServer = Effect.acquireRelease( Effect.promise<OpenApiSpecServer>( () => new Promise<OpenApiSpecServer>((resolve, reject) => { const openApiDocument = JSON.stringify({ openapi: "3.0.3", info: { title: "GitHub Test API", version: "1.0.0", }, paths: { "/repos/{owner}/{repo}": { get: { operationId: "repos/get-repo", tags: ["repos"], summary: "Get a repository", responses: { 200: { description: "ok", }, }, }, }, }, }); const server = createServer((request, response) => { if (request.url !== "/openapi.json") { response.statusCode = 404; response.end(); return; } response.statusCode = 200; response.setHeader("content-type", "application/json"); response.end(openApiDocument); }); server.once("error", reject); server.listen(0, "127.0.0.1", () => { const address = server.address(); if (!address || typeof address === "string") { reject(new Error("Failed to bind OpenAPI runtime test server")); return; } const baseUrl = `http://127.0.0.1:${address.port}`; resolve({ baseUrl, specUrl: `${baseUrl}/openapi.json`, close: () => new Promise<void>((closeResolve, closeReject) => { server.close((error) => { if (error) { closeReject(error); return; } closeResolve(); }); }), }); }); }), ), (server) => Effect.promise(() => server.close()).pipe(Effect.orDie),); const makeGoogleWorkspaceTestServer = Effect.acquireRelease( Effect.promise<GoogleWorkspaceTestServer>( () => new Promise<GoogleWorkspaceTestServer>((resolve, reject) => { const discoveryScopes = new Map<string, string>(); const tokenResponses: Array<{ access_token: string; refresh_token?: string; expires_in?: number; scope?: string; }> = []; const tokenRequests: URLSearchParams[] = []; const discoveryAuthorizations: string[] = []; let baseUrl = ""; let currentAccessToken: string | null = null; const server = createServer(async (request, response) => { const requestUrl = new URL( request.url ?? "/", `http://${request.headers.host ?? "127.0.0.1"}`, ); if (request.method === "POST" && requestUrl.pathname === "/oauth/token") { const chunks: Buffer[] = []; for await (const chunk of request) { chunks.push(Buffer.from(chunk)); } const params = new URLSearchParams(Buffer.concat(chunks).toString("utf8")); tokenRequests.push(params); const nextResponse = tokenResponses.shift(); if (!nextResponse) { response.statusCode = 500; response.setHeader("content-type", "application/json"); response.end(JSON.stringify({ error: "missing_token_response", })); return; } currentAccessToken = nextResponse.access_token; response.statusCode = 200; response.setHeader("content-type", "application/json"); response.end(JSON.stringify({ token_type: "Bearer", expires_in: 3600, ...nextResponse, })); return; } const discoveryMatch = /^\/([^/]+)\/\$discovery\/rest$/.exec(requestUrl.pathname); if (request.method === "GET" && discoveryMatch) { const service = discoveryMatch[1]!; const version = requestUrl.searchParams.get("version") ?? "v1"; const authorizationHeader = typeof request.headers.authorization === "string" ? request.headers.authorization : Array.isArray(request.headers.authorization) ? (request.headers.authorization[0] ?? "") : ""; discoveryAuthorizations.push(authorizationHeader); if (authorizationHeader !== `Bearer ${currentAccessToken ?? ""}`) { response.statusCode = 401; response.end("Unauthorized"); return; } const scope = discoveryScopes.get(`${service}:${version}`) ?? `https://example.test/auth/${service}`; response.statusCode = 200; response.setHeader("content-type", "application/json"); response.end(JSON.stringify({ name: service, version, title: `${service} API`, description: `Test ${service} API`, rootUrl: `${baseUrl}/`, servicePath: `${service}/${version}/`, auth: { oauth2: { scopes: { [scope]: { description: `${service} scope`, }, }, }, }, methods: { list: { id: `${service}.list`, path: "items", httpMethod: "GET", response: { $ref: "ListResponse", }, }, }, schemas: { ListResponse: { id: "ListResponse", type: "object", properties: { items: { type: "array", items: { type: "string", }, }, }, }, }, })); return; } response.statusCode = 404; response.end(); }); server.once("error", reject); server.listen(0, "127.0.0.1", () => { const address = server.address(); if (!address || typeof address === "string") { reject(new Error("Failed to bind Google workspace test server")); return; } baseUrl = `http://127.0.0.1:${address.port}`; resolve({ baseUrl, tokenEndpoint: `${baseUrl}/oauth/token`, discoveryUrl: ({ service, version, scope }) => { discoveryScopes.set(`${service}:${version}`, scope); return `${baseUrl}/${service}/$discovery/rest?version=${encodeURIComponent(version)}`; }, queueTokenResponse: (tokenResponse) => { tokenResponses.push(tokenResponse); }, tokenRequests, discoveryAuthorizations, close: () => new Promise<void>((closeResolve, closeReject) => { server.close((error) => { if (error) { closeReject(error); return; } closeResolve(); }); }), }); }); }), ), (server) => Effect.promise(() => server.close()).pipe(Effect.orDie),); const upsertLocalSecret = (runtime: ControlPlaneRuntime, input: { id: string; name: string; purpose: "oauth_refresh_token" | "oauth_client_info" | "oauth_access_token"; value: string;}) => runtime.persistence.rows.secretMaterials.upsert({ id: SecretMaterialIdSchema.make(input.id), providerId: "local", handle: input.id, name: input.name, purpose: input.purpose, value: input.value, createdAt: Date.now(), updatedAt: Date.now(), }); const createPersistedGoogleSource = (input: { runtime: ControlPlaneRuntime; name: string; namespace: string; service: string; version: string; discoveryUrl: string; scopes: ReadonlyArray<string>; auth: { kind: "none"; } | { kind: "provider_grant_ref"; grantId: ReturnType<typeof ProviderAuthGrantIdSchema.make>; providerKey: string; requiredScopes: ReadonlyArray<string>; headerName: string; prefix: string; };}) => Effect.gen(function* () { const installation = input.runtime.localInstallation; const source = yield* createSourceFromPayload({ workspaceId: installation.workspaceId, sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), payload: { name: input.name, kind: "google_discovery", endpoint: input.discoveryUrl, namespace: input.namespace, binding: { service: input.service, version: input.version, discoveryUrl: input.discoveryUrl, scopes: [...input.scopes], }, importAuthPolicy: "reuse_runtime", importAuth: { kind: "none" }, auth: input.auth as any, status: "connected", enabled: true, }, now: Date.now(), }); return yield* persistSource(input.runtime.persistence.rows, source, { actorAccountId: installation.accountId, }).pipe((effect) => provideControlPlaneRuntime(effect, input.runtime)); }); const expectLeft = <A, E>(effect: Effect.Effect<A, E, never>) => Effect.either(effect).pipe( Effect.flatMap((result) => result._tag === "Left" ? Effect.succeed(result.left) : Effect.fail(new Error("Expected effect to fail")), ), ); describe("control-plane-runtime", () => { it.scoped("writes local source changes through executor.jsonc", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const workspaceRoot = yield* fs.makeTempDirectoryScoped({ prefix: "executor-local-config-runtime-", }); const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); const runtime = yield* Effect.acquireRelease( createControlPlaneRuntime({ workspaceRoot, homeConfigPath, homeStateDirectory, }), (createdRuntime) => Effect.promise(() => createdRuntime.close()).pipe(Effect.orDie), ); const openApiServer = yield* makeOpenApiSpecServer; const installation = runtime.localInstallation; const createdSource = yield* withControlPlaneClient( { runtime, accountId: installation.accountId }, (client) => client.sources.create({ path: { workspaceId: installation.workspaceId }, payload: { name: "GitHub", kind: "openapi", endpoint: openApiServer.baseUrl, namespace: "github", binding: { specUrl: openApiServer.specUrl, defaultHeaders: null, }, auth: { kind: "none" }, }, }), ); const configPath = join(workspaceRoot, ".executor", "executor.jsonc"); const createdConfig = JSON.parse(readFileSync(configPath, "utf8")) as { sources?: Record<string, { kind: string; connection: { endpoint: string } }>; }; expect(createdConfig.sources?.github?.kind).toBe("openapi"); expect(createdConfig.sources?.github?.connection.endpoint).toBe(openApiServer.baseUrl); const removed = yield* withControlPlaneClient( { runtime, accountId: installation.accountId }, (client) => client.sources.remove({ path: { workspaceId: installation.workspaceId, sourceId: createdSource.id, }, }), ); expect(removed.removed).toBe(true); const removedConfig = JSON.parse(readFileSync(configPath, "utf8")) as { sources?: Record<string, unknown>; }; expect(removedConfig.sources?.github).toBeUndefined(); }).pipe(Effect.provide(NodeFileSystem.layer)), 60_000, ); it.scoped("manages local secrets through provider-backed metadata rows", () => Effect.gen(function* () { const runtime = yield* makeRuntime; const created = yield* withControlPlaneClient( { runtime }, (client) => client.local.createSecret({ payload: { name: "GitHub PAT", value: "ghp_test_token", providerId: "local", }, }), ); expect(created.providerId).toBe("local"); const listed = yield* withControlPlaneClient( { runtime }, (client) => client.local.listSecrets({}), ); expect(listed).toEqual([ expect.objectContaining({ id: created.id, providerId: "local", name: "GitHub PAT", }), ]); const updated = yield* withControlPlaneClient( { runtime }, (client) => client.local.updateSecret({ path: { secretId: created.id }, payload: { name: "GitHub PAT Updated", value: "ghp_test_token_v2", }, }), ); expect(updated.providerId).toBe("local"); expect(updated.name).toBe("GitHub PAT Updated"); const storedSecret = yield* runtime.persistence.rows.secretMaterials.getById( SecretMaterialIdSchema.make(created.id), ); assertTrue(Option.isSome(storedSecret)); expect(storedSecret.value.providerId).toBe("local"); expect(storedSecret.value.value).toBe("ghp_test_token_v2"); const removed = yield* withControlPlaneClient(Lines 1–500 of 1528. Load more
import { createServer } from "node:http"; import { readFileSync } from "node:fs"; import { join } from "node:path"; import { FileSystem } from "@effect/platform"; import { NodeFileSystem } from "@effect/platform-node"; import { describe, expect, it } from "@effect/vitest"; import { assertTrue } from "@effect/vitest/utils"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as Option from "effect/Option"; import type { AccountId } from "#schema"; import { ExecutionIdSchema, ExecutionInteractionIdSchema, type ExecutionInteraction, ProviderAuthGrantIdSchema, SecretMaterialIdSchema, SourceAuthSessionIdSchema, SourceIdSchema, WorkspaceOauthClientIdSchema, } from "#schema"; import type { ToolPath } from "@executor/codemode-core"; import { type ControlPlaneRuntime, createControlPlaneRuntime, LiveExecutionManagerService, provideControlPlaneRuntime, } from "./index"; import { createSourceFromPayload } from "./source-definitions"; import { decodeSourceCredentialSelectionContent } from "./source-credential-interactions"; import { persistSource } from "./source-store"; import { withControlPlaneClient } from "./test-http-client"; const makeRuntime = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const workspaceRoot = yield* fs.makeTempDirectoryScoped({ prefix: "executor-control-plane-runtime-", }); const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); return yield* Effect.acquireRelease( createControlPlaneRuntime({ workspaceRoot, homeConfigPath, homeStateDirectory, }), (runtime) => Effect.promise(() => runtime.close()).pipe(Effect.orDie), ); }).pipe(Effect.provide(NodeFileSystem.layer)); type OpenApiSpecServer = { baseUrl: string; specUrl: string; close: () => Promise<void>; }; type GoogleWorkspaceTestServer = { baseUrl: string; tokenEndpoint: string; discoveryUrl: (input: { service: string; version: string; scope: string; }) => string; queueTokenResponse: (response: { access_token: string; refresh_token?: string; expires_in?: number; scope?: string; }) => void; tokenRequests: URLSearchParams[]; discoveryAuthorizations: string[]; close: () => Promise<void>; }; const makeOpenApiSpecServer = Effect.acquireRelease( Effect.promise<OpenApiSpecServer>( () => new Promise<OpenApiSpecServer>((resolve, reject) => { const openApiDocument = JSON.stringify({ openapi: "3.0.3", info: { title: "GitHub Test API", version: "1.0.0", }, paths: { "/repos/{owner}/{repo}": { get: { operationId: "repos/get-repo", tags: ["repos"], summary: "Get a repository", responses: { 200: { description: "ok", }, }, }, }, }, }); const server = createServer((request, response) => { if (request.url !== "/openapi.json") { response.statusCode = 404; response.end(); return; } response.statusCode = 200; response.setHeader("content-type", "application/json"); response.end(openApiDocument); }); server.once("error", reject); server.listen(0, "127.0.0.1", () => { const address = server.address(); if (!address || typeof address === "string") { reject(new Error("Failed to bind OpenAPI runtime test server")); return; } const baseUrl = `http://127.0.0.1:${address.port}`; resolve({ baseUrl, specUrl: `${baseUrl}/openapi.json`, close: () => new Promise<void>((closeResolve, closeReject) => { server.close((error) => { if (error) { closeReject(error); return; } closeResolve(); }); }), }); }); }), ), (server) => Effect.promise(() => server.close()).pipe(Effect.orDie), ); const makeGoogleWorkspaceTestServer = Effect.acquireRelease( Effect.promise<GoogleWorkspaceTestServer>( () => new Promise<GoogleWorkspaceTestServer>((resolve, reject) => { const discoveryScopes = new Map<string, string>(); const tokenResponses: Array<{ access_token: string; refresh_token?: string; expires_in?: number; scope?: string; }> = []; const tokenRequests: URLSearchParams[] = []; const discoveryAuthorizations: string[] = []; let baseUrl = ""; let currentAccessToken: string | null = null; const server = createServer(async (request, response) => { const requestUrl = new URL( request.url ?? "/", `http://${request.headers.host ?? "127.0.0.1"}`, ); if (request.method === "POST" && requestUrl.pathname === "/oauth/token") { const chunks: Buffer[] = []; for await (const chunk of request) { chunks.push(Buffer.from(chunk)); } const params = new URLSearchParams(Buffer.concat(chunks).toString("utf8")); tokenRequests.push(params); const nextResponse = tokenResponses.shift(); if (!nextResponse) { response.statusCode = 500; response.setHeader("content-type", "application/json"); response.end(JSON.stringify({ error: "missing_token_response", })); return; } currentAccessToken = nextResponse.access_token; response.statusCode = 200; response.setHeader("content-type", "application/json"); response.end(JSON.stringify({ token_type: "Bearer", expires_in: 3600, ...nextResponse, })); return; } const discoveryMatch = /^\/([^/]+)\/\$discovery\/rest$/.exec(requestUrl.pathname); if (request.method === "GET" && discoveryMatch) { const service = discoveryMatch[1]!; const version = requestUrl.searchParams.get("version") ?? "v1"; const authorizationHeader = typeof request.headers.authorization === "string" ? request.headers.authorization : Array.isArray(request.headers.authorization) ? (request.headers.authorization[0] ?? "") : ""; discoveryAuthorizations.push(authorizationHeader); if (authorizationHeader !== `Bearer ${currentAccessToken ?? ""}`) { response.statusCode = 401; response.end("Unauthorized"); return; } const scope = discoveryScopes.get(`${service}:${version}`) ?? `https://example.test/auth/${service}`; response.statusCode = 200; response.setHeader("content-type", "application/json"); response.end(JSON.stringify({ name: service, version, title: `${service} API`, description: `Test ${service} API`, rootUrl: `${baseUrl}/`, servicePath: `${service}/${version}/`, auth: { oauth2: { scopes: { [scope]: { description: `${service} scope`, }, }, }, }, methods: { list: { id: `${service}.list`, path: "items", httpMethod: "GET", response: { $ref: "ListResponse", }, }, }, schemas: { ListResponse: { id: "ListResponse", type: "object", properties: { items: { type: "array", items: { type: "string", }, }, }, }, }, })); return; } response.statusCode = 404; response.end(); }); server.once("error", reject); server.listen(0, "127.0.0.1", () => { const address = server.address(); if (!address || typeof address === "string") { reject(new Error("Failed to bind Google workspace test server")); return; } baseUrl = `http://127.0.0.1:${address.port}`; resolve({ baseUrl, tokenEndpoint: `${baseUrl}/oauth/token`, discoveryUrl: ({ service, version, scope }) => { discoveryScopes.set(`${service}:${version}`, scope); return `${baseUrl}/${service}/$discovery/rest?version=${encodeURIComponent(version)}`; }, queueTokenResponse: (tokenResponse) => { tokenResponses.push(tokenResponse); }, tokenRequests, discoveryAuthorizations, close: () => new Promise<void>((closeResolve, closeReject) => { server.close((error) => { if (error) { closeReject(error); return; } closeResolve(); }); }), }); }); }), ), (server) => Effect.promise(() => server.close()).pipe(Effect.orDie), ); const upsertLocalSecret = (runtime: ControlPlaneRuntime, input: { id: string; name: string; purpose: "oauth_refresh_token" | "oauth_client_info" | "oauth_access_token"; value: string; }) => runtime.persistence.rows.secretMaterials.upsert({ id: SecretMaterialIdSchema.make(input.id), providerId: "local", handle: input.id, name: input.name, purpose: input.purpose, value: input.value, createdAt: Date.now(), updatedAt: Date.now(), }); const createPersistedGoogleSource = (input: { runtime: ControlPlaneRuntime; name: string; namespace: string; service: string; version: string; discoveryUrl: string; scopes: ReadonlyArray<string>; auth: { kind: "none"; } | { kind: "provider_grant_ref"; grantId: ReturnType<typeof ProviderAuthGrantIdSchema.make>; providerKey: string; requiredScopes: ReadonlyArray<string>; headerName: string; prefix: string; }; }) => Effect.gen(function* () { const installation = input.runtime.localInstallation; const source = yield* createSourceFromPayload({ workspaceId: installation.workspaceId, sourceId: SourceIdSchema.make(`src_${crypto.randomUUID()}`), payload: { name: input.name, kind: "google_discovery", endpoint: input.discoveryUrl, namespace: input.namespace, binding: { service: input.service, version: input.version, discoveryUrl: input.discoveryUrl, scopes: [...input.scopes], }, importAuthPolicy: "reuse_runtime", importAuth: { kind: "none" }, auth: input.auth as any, status: "connected", enabled: true, }, now: Date.now(), }); return yield* persistSource(input.runtime.persistence.rows, source, { actorAccountId: installation.accountId, }).pipe((effect) => provideControlPlaneRuntime(effect, input.runtime)); }); const expectLeft = <A, E>(effect: Effect.Effect<A, E, never>) => Effect.either(effect).pipe( Effect.flatMap((result) => result._tag === "Left" ? Effect.succeed(result.left) : Effect.fail(new Error("Expected effect to fail")), ), ); describe("control-plane-runtime", () => { it.scoped("writes local source changes through executor.jsonc", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const workspaceRoot = yield* fs.makeTempDirectoryScoped({ prefix: "executor-local-config-runtime-", }); const homeConfigPath = join(workspaceRoot, ".executor-home.jsonc"); const homeStateDirectory = join(workspaceRoot, ".executor-home-state"); const runtime = yield* Effect.acquireRelease( createControlPlaneRuntime({ workspaceRoot, homeConfigPath, homeStateDirectory, }), (createdRuntime) => Effect.promise(() => createdRuntime.close()).pipe(Effect.orDie), ); const openApiServer = yield* makeOpenApiSpecServer; const installation = runtime.localInstallation; const createdSource = yield* withControlPlaneClient( { runtime, accountId: installation.accountId }, (client) => client.sources.create({ path: { workspaceId: installation.workspaceId }, payload: { name: "GitHub", kind: "openapi", endpoint: openApiServer.baseUrl, namespace: "github", binding: { specUrl: openApiServer.specUrl, defaultHeaders: null, }, auth: { kind: "none" }, }, }), ); const configPath = join(workspaceRoot, ".executor", "executor.jsonc"); const createdConfig = JSON.parse(readFileSync(configPath, "utf8")) as { sources?: Record<string, { kind: string; connection: { endpoint: string } }>; }; expect(createdConfig.sources?.github?.kind).toBe("openapi"); expect(createdConfig.sources?.github?.connection.endpoint).toBe(openApiServer.baseUrl); const removed = yield* withControlPlaneClient( { runtime, accountId: installation.accountId }, (client) => client.sources.remove({ path: { workspaceId: installation.workspaceId, sourceId: createdSource.id, }, }), ); expect(removed.removed).toBe(true); const removedConfig = JSON.parse(readFileSync(configPath, "utf8")) as { sources?: Record<string, unknown>; }; expect(removedConfig.sources?.github).toBeUndefined(); }).pipe(Effect.provide(NodeFileSystem.layer)), 60_000, ); it.scoped("manages local secrets through provider-backed metadata rows", () => Effect.gen(function* () { const runtime = yield* makeRuntime; const created = yield* withControlPlaneClient( { runtime }, (client) => client.local.createSecret({ payload: { name: "GitHub PAT", value: "ghp_test_token", providerId: "local", }, }), ); expect(created.providerId).toBe("local"); const listed = yield* withControlPlaneClient( { runtime }, (client) => client.local.listSecrets({}), ); expect(listed).toEqual([ expect.objectContaining({ id: created.id, providerId: "local", name: "GitHub PAT", }), ]); const updated = yield* withControlPlaneClient( { runtime }, (client) => client.local.updateSecret({ path: { secretId: created.id }, payload: { name: "GitHub PAT Updated", value: "ghp_test_token_v2", }, }), ); expect(updated.providerId).toBe("local"); expect(updated.name).toBe("GitHub PAT Updated"); const storedSecret = yield* runtime.persistence.rows.secretMaterials.getById( SecretMaterialIdSchema.make(created.id), ); assertTrue(Option.isSome(storedSecret)); expect(storedSecret.value.providerId).toBe("local"); expect(storedSecret.value.value).toBe("ghp_test_token_v2"); const removed = yield* withControlPlaneClient(