Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions apps/cloud/src/mcp-session.e2e.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,19 @@ const openSession = (
return { client, clientTransport, serverTransport };
}),
({ clientTransport, serverTransport }) =>
Effect.promise(async () => {
await clientTransport.close().catch(() => undefined);
await serverTransport.close().catch(() => undefined);
}),
Effect.all(
[
Effect.tryPromise({
try: () => clientTransport.close(),
catch: (cause) => cause,
}).pipe(Effect.ignore),
Effect.tryPromise({
try: () => serverTransport.close(),
catch: (cause) => cause,
}).pipe(Effect.ignore),
],
{ discard: true },
),
).pipe(Effect.map(({ client }) => ({ client })));

const nextOrgId = (() => {
Expand Down
1 change: 1 addition & 0 deletions apps/cloud/src/observability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const sentryPayloadForCause = (
if (Cause.isCause(input)) {
const pretty = Cause.pretty(input);
const errors = Cause.prettyErrors(input);
// oxlint-disable-next-line executor/no-error-constructor -- boundary: Sentry captureException needs an Error-like primary payload for pretty Effect causes
return { primary: errors[0] ?? new Error(pretty), pretty };
}
return { primary: input, pretty: null };
Expand Down
4 changes: 2 additions & 2 deletions apps/cloud/src/org/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpApiBuilder } from "effect/unstable/httpapi";
import { Effect } from "effect";
import { Cause, Effect } from "effect";

import { UserStoreService } from "../auth/context";
import { AuthContext } from "../auth/middleware";
Expand Down Expand Up @@ -103,7 +103,7 @@ const reserveMemberSlot = Effect.gen(function* () {
Effect.catchCause((cause) =>
Effect.gen(function* () {
yield* Effect.logError("members.seats lookup failed; failing closed").pipe(
Effect.annotateLogs({ "org.id": auth.organizationId, cause: String(cause) }),
Effect.annotateLogs({ "org.id": auth.organizationId, cause: Cause.pretty(cause) }),
);
return yield* new Forbidden();
}),
Expand Down
6 changes: 5 additions & 1 deletion apps/cloud/src/routes/billing_.plans.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ function SlackContactCta() {
}
setSubmitting(true);
setError(null);
// oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: browser fetch submit path maps network failures to public UI copy
try {
const res = await fetch("/api/contact/slack", {
method: "POST",
Expand All @@ -358,7 +359,10 @@ function SlackContactCta() {
turnstileToken,
}),
});
const data = (await res.json().catch(() => ({}))) as { url?: string; error?: string };
const data = (await res.json().then(
(value) => value,
() => ({}),
)) as { url?: string; error?: string };
if (!res.ok) {
setError(data.error ?? "Something went wrong. Please try again.");
return;
Expand Down
4 changes: 2 additions & 2 deletions apps/cloud/src/secrets-isolation.e2e.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
// SDK-level change — coverage for it belongs after the fix.

import { describe, expect, it } from "@effect/vitest";
import { Effect } from "effect";
import { Effect, Result } from "effect";

import { ScopeId, SecretId } from "@executor-js/sdk";

Expand Down Expand Up @@ -237,7 +237,7 @@ describe("cloud secret isolation (HTTP, user-org scope stack)", () => {
})
.pipe(Effect.result),
);
expect(result._tag).toBe("Failure");
expect(Result.isFailure(result)).toBe(true);

// And nothing landed in the foreign org — a fresh session pointed
// at that org must not see `wrong-scope`.
Expand Down
1 change: 1 addition & 0 deletions apps/cloud/src/services/__test-harness__/api-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const TestExecutionStackMiddleware = HttpRouter.middleware<{
const request = yield* HttpServerRequest.HttpServerRequest;
const orgId = request.headers[TEST_ORG_HEADER];
if (!orgId || typeof orgId !== "string") {
// oxlint-disable-next-line executor/no-effect-escape-hatch, executor/no-error-constructor -- boundary: test HTTP harness has no request context without x-test-org-id
return yield* Effect.die(new Error("missing x-test-org-id"));
}
const userHeader = request.headers[TEST_USER_HEADER];
Expand Down
4 changes: 2 additions & 2 deletions apps/cloud/src/services/secrets-api.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// and error fidelity within a single org.

import { describe, expect, it } from "@effect/vitest";
import { Effect } from "effect";
import { Effect, Result } from "effect";

import { ScopeId, SecretId } from "@executor-js/sdk";

Expand Down Expand Up @@ -128,7 +128,7 @@ describe("secrets api (HTTP)", () => {
.remove({ params: { scopeId: ScopeId.make(org), secretId: SecretId.make(missing) } })
.pipe(Effect.result),
);
expect(result._tag).toBe("Success");
expect(Result.isSuccess(result)).toBe(true);
}),
);

Expand Down
15 changes: 8 additions & 7 deletions apps/cloud/src/services/sources-refresh.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,12 @@ const serveMutableSpec = () => {

describe("sources.refresh (HTTP)", () => {
it.effect("addSpec from URL → canRefresh:true; refresh re-fetches and updates tools", () =>
Effect.gen(function* () {
const server = yield* Effect.promise(() => serveMutableSpec());
try {
Effect.scoped(
Effect.gen(function* () {
const server = yield* Effect.acquireRelease(
Effect.promise(() => serveMutableSpec()),
(server) => Effect.promise(() => server.close()),
);
const org = `org_${crypto.randomUUID()}`;
const namespace = `ns_${crypto.randomUUID().replace(/-/g, "_")}`;

Expand Down Expand Up @@ -139,10 +142,8 @@ describe("sources.refresh (HTTP)", () => {
expect(afterTools.length).toBe(2);
expect(afterTools.some((t) => t.name.startsWith("ping"))).toBe(true);
expect(afterTools.some((t) => t.name.startsWith("pong"))).toBe(true);
} finally {
yield* Effect.promise(() => server.close());
}
}),
}),
),
);

it.effect("addSpec from raw text → canRefresh:false; refresh is a no-op", () =>
Expand Down
1 change: 1 addition & 0 deletions apps/cloud/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default defineConfig({
// the socket is closing anyway — so filter it out rather than fail
// the run with noise.
onUnhandledError(error) {
// oxlint-disable-next-line executor/no-unknown-error-message -- boundary: Vitest unhandled-error hook receives unknown host errors
if (error && (error as Error).message === "Stream was cancelled.") {
return false;
}
Expand Down
Loading