// The connect deep link: a customer sends an end user a direct link for ONE// integration ("connect your Linear") instead of pointing them at the dashboard// to hunt for it. `/connect/<integration slug>` resolves the slug against the// tenant's catalog and lands the person in the SAME connect flow the// integration detail page's own button opens.//// The slug — not a plugin id — is the stable identity here: it is what a// customer can write down and template into an email.//// Covered:// 1. Signed in, known slug → the Add connection flow is open on the right// integration, with the auth methods the spec declares// 2. Unknown slug → a clear not-found state, not a blank page or a// crash (an end user WILL mistype these, and links outlive integrations)// 3. Already connected → the deep link shows the existing connection and// still offers to add another accountimport { randomBytes, randomUUID } from "node:crypto"; import { expect } from "@effect/vitest";import { Effect } from "effect";import { AccountHttpApi } from "@executor-js/api";import { composePluginApi } from "@executor-js/api/server";import { openApiHttpPlugin } from "@executor-js/plugin-openapi/api";import { AuthTemplateSlug, ConnectionName, IntegrationSlug, ProviderItemId,} from "@executor-js/sdk/shared"; import { scenario } from "../src/scenario";import { Api, Browser, Target } from "../src/services";import { visit } from "../src/surfaces/browser"; const api = composePluginApi([openApiHttpPlugin()] as const); /** OpenAPI 3 spec with a single operation — enough to be a real catalog entry. */const greetSpec = (baseUrl: string): string => JSON.stringify({ openapi: "3.0.3", info: { title: "Deep Link API", version: "1.0.0" }, servers: [{ url: baseUrl }], paths: { "/greet": { get: { operationId: "getGreeting", summary: "Return a greeting message", responses: { "200": { description: "A greeting" } }, }, }, }, }); scenario( "Connect · /connect/<slug> lands an end user in that integration's connect flow", { timeout: 180_000 }, Effect.gen(function* () { const target = yield* Target; const browser = yield* Browser; const { client } = yield* Api; const identity = yield* target.newIdentity(); const apiClient = yield* client(api, identity); // Selfhost shares one bootstrap-admin identity, so a unique slug keeps // repeated and parallel runs out of each other's catalogs. const slug = `connect-dl-${randomBytes(4).toString("hex")}`; const specBaseUrl = "http://127.0.0.1:59999"; // never contacted here // Org-scoped hosts canonicalize console URLs onto the active org's slug, so // the deep link may legitimately arrive at either `/connect/x` or // `/<org>/connect/x`. Read the slug the shell will canonicalize onto. const accountClient = yield* client(AccountHttpApi, identity); const me = yield* accountClient.account.me(); const orgSlug = me.organization?.slug ?? null; const detailPath = orgSlug ? `/${orgSlug}/integrations/${slug}` : `/integrations/${slug}`; yield* Effect.ensuring( Effect.gen(function* () { const added = yield* apiClient.openapi.addSpec({ payload: { spec: { kind: "blob", value: greetSpec(specBaseUrl) }, slug, name: "Deep Link API", baseUrl: specBaseUrl, authenticationTemplate: [ { slug: "apiKey", type: "apiKey", headers: { "x-api-key": [{ type: "variable", name: "token" }] }, }, ], }, }); expect(added.slug, "the integration keeps the requested slug").toBe(slug); yield* browser.session(identity, async ({ page, step }) => { await step("Open the connect deep link for the seeded integration", async () => { await visit(page, `/connect/${slug}`); // It forwards into the integration's OWN detail route rather than // rendering a parallel connect UI, carrying the add-account handoff. await page.waitForURL((url) => url.pathname === detailPath, { timeout: 30_000 }); expect(new URL(page.url()).searchParams.get("addAccount")).toBe("1"); }); await step("The Add connection flow is open for that integration", async () => { await page .getByRole("heading", { name: /Add connection/ }) .waitFor({ timeout: 20_000 }); // The right integration, and the declared auth method is offered — // proof it resolved the slug rather than opening a generic dialog. await page .getByRole("dialog") .getByRole("textbox", { name: "x-api-key" }) .waitFor({ timeout: 20_000 }); }); await step("An unknown slug is a clear not-found, not a blank page", async () => { await visit(page, "/connect/zz-no-such-integration"); await page .getByText("Unknown integration: zz-no-such-integration") .waitFor({ timeout: 30_000 }); await page.getByRole("link", { name: "Back to integrations" }).waitFor(); }); }); // Already connected: the deep link must show the existing connection // and still let the person add another account. const providers = yield* apiClient.providers.list(); expect(providers.length, "a credential provider is available").toBeGreaterThan(0); yield* apiClient.connections.create({ payload: { owner: "org", name: ConnectionName.make("existing"), integration: IntegrationSlug.make(slug), template: AuthTemplateSlug.make("apiKey"), from: { provider: providers[0]!, id: ProviderItemId.make(randomUUID()) }, }, }); yield* browser.session(identity, async ({ page, step }) => { await step("The deep link surfaces the existing connection", async () => { await visit(page, `/connect/${slug}`); await page.waitForURL((url) => url.pathname === detailPath, { timeout: 30_000 }); // The connect flow still opens (this link means "connect me"), and // the already-saved account is visible behind it. await page .getByRole("heading", { name: /Add connection/ }) .waitFor({ timeout: 20_000 }); await page.keyboard.press("Escape"); await page.getByText("existing").first().waitFor({ timeout: 20_000 }); }); }); }), Effect.gen(function* () { yield* apiClient.connections .remove({ params: { owner: "org", integration: IntegrationSlug.make(slug), name: ConnectionName.make("existing"), }, }) .pipe(Effect.ignore); yield* apiClient.openapi.removeSpec({ params: { slug } }).pipe(Effect.ignore); }).pipe(Effect.ignore), ); }),);
// The connect deep link: a customer sends an end user a direct link for ONE
// integration ("connect your Linear") instead of pointing them at the dashboard
// to hunt for it. `/connect/<integration slug>` resolves the slug against the
// tenant's catalog and lands the person in the SAME connect flow the
// integration detail page's own button opens.
//
// The slug — not a plugin id — is the stable identity here: it is what a
// customer can write down and template into an email.
//
// Covered:
// 1. Signed in, known slug → the Add connection flow is open on the right
// integration, with the auth methods the spec declares
// 2. Unknown slug → a clear not-found state, not a blank page or a
// crash (an end user WILL mistype these, and links outlive integrations)
// 3. Already connected → the deep link shows the existing connection and
// still offers to add another account
import { randomBytes, randomUUID } from "node:crypto";
import { expect } from "@effect/vitest";
import { Effect } from "effect";
import { AccountHttpApi } from "@executor-js/api";
import { composePluginApi } from "@executor-js/api/server";
import { openApiHttpPlugin } from "@executor-js/plugin-openapi/api";
import {
AuthTemplateSlug,
ConnectionName,
IntegrationSlug,
ProviderItemId,
} from "@executor-js/sdk/shared";
import { scenario } from "../src/scenario";
import { Api, Browser, Target } from "../src/services";
import { visit } from "../src/surfaces/browser";
const api = composePluginApi([openApiHttpPlugin()] as const);
/** OpenAPI 3 spec with a single operation — enough to be a real catalog entry. */
const greetSpec = (baseUrl: string): string =>
JSON.stringify({
openapi: "3.0.3",
info: { title: "Deep Link API", version: "1.0.0" },
servers: [{ url: baseUrl }],
paths: {
"/greet": {
get: {
operationId: "getGreeting",
summary: "Return a greeting message",
responses: { "200": { description: "A greeting" } },
},
},
},
});
scenario(
"Connect · /connect/<slug> lands an end user in that integration's connect flow",
{ timeout: 180_000 },
Effect.gen(function* () {
const target = yield* Target;
const browser = yield* Browser;
const { client } = yield* Api;
const identity = yield* target.newIdentity();
const apiClient = yield* client(api, identity);
// Selfhost shares one bootstrap-admin identity, so a unique slug keeps
// repeated and parallel runs out of each other's catalogs.
const slug = `connect-dl-${randomBytes(4).toString("hex")}`;
const specBaseUrl = "http://127.0.0.1:59999"; // never contacted here
// Org-scoped hosts canonicalize console URLs onto the active org's slug, so
// the deep link may legitimately arrive at either `/connect/x` or
// `/<org>/connect/x`. Read the slug the shell will canonicalize onto.
const accountClient = yield* client(AccountHttpApi, identity);
const me = yield* accountClient.account.me();
const orgSlug = me.organization?.slug ?? null;
const detailPath = orgSlug ? `/${orgSlug}/integrations/${slug}` : `/integrations/${slug}`;
yield* Effect.ensuring(
Effect.gen(function* () {
const added = yield* apiClient.openapi.addSpec({
payload: {
spec: { kind: "blob", value: greetSpec(specBaseUrl) },
slug,
name: "Deep Link API",
baseUrl: specBaseUrl,
authenticationTemplate: [
{
slug: "apiKey",
type: "apiKey",
headers: { "x-api-key": [{ type: "variable", name: "token" }] },
},
],
},
});
expect(added.slug, "the integration keeps the requested slug").toBe(slug);
yield* browser.session(identity, async ({ page, step }) => {
await step("Open the connect deep link for the seeded integration", async () => {
await visit(page, `/connect/${slug}`);
// It forwards into the integration's OWN detail route rather than
// rendering a parallel connect UI, carrying the add-account handoff.
await page.waitForURL((url) => url.pathname === detailPath, { timeout: 30_000 });
expect(new URL(page.url()).searchParams.get("addAccount")).toBe("1");
});
await step("The Add connection flow is open for that integration", async () => {
await page
.getByRole("heading", { name: /Add connection/ })
.waitFor({ timeout: 20_000 });
// The right integration, and the declared auth method is offered —
// proof it resolved the slug rather than opening a generic dialog.
await page
.getByRole("dialog")
.getByRole("textbox", { name: "x-api-key" })
.waitFor({ timeout: 20_000 });
});
await step("An unknown slug is a clear not-found, not a blank page", async () => {
await visit(page, "/connect/zz-no-such-integration");
await page
.getByText("Unknown integration: zz-no-such-integration")
.waitFor({ timeout: 30_000 });
await page.getByRole("link", { name: "Back to integrations" }).waitFor();
});
});
// Already connected: the deep link must show the existing connection
// and still let the person add another account.
const providers = yield* apiClient.providers.list();
expect(providers.length, "a credential provider is available").toBeGreaterThan(0);
yield* apiClient.connections.create({
payload: {
owner: "org",
name: ConnectionName.make("existing"),
integration: IntegrationSlug.make(slug),
template: AuthTemplateSlug.make("apiKey"),
from: { provider: providers[0]!, id: ProviderItemId.make(randomUUID()) },
},
});
yield* browser.session(identity, async ({ page, step }) => {
await step("The deep link surfaces the existing connection", async () => {
await visit(page, `/connect/${slug}`);
await page.waitForURL((url) => url.pathname === detailPath, { timeout: 30_000 });
// The connect flow still opens (this link means "connect me"), and
// the already-saved account is visible behind it.
await page
.getByRole("heading", { name: /Add connection/ })
.waitFor({ timeout: 20_000 });
await page.keyboard.press("Escape");
await page.getByText("existing").first().waitFor({ timeout: 20_000 });
});
});
}),
Effect.gen(function* () {
yield* apiClient.connections
.remove({
params: {
owner: "org",
integration: IntegrationSlug.make(slug),
name: ConnectionName.make("existing"),
},
})
.pipe(Effect.ignore);
yield* apiClient.openapi.removeSpec({ params: { slug } }).pipe(Effect.ignore);
}).pipe(Effect.ignore),
);
}),
);