import type { IntegrationSlug } from "@executor-js/sdk/shared";import * as Atom from "effect/unstable/reactivity/Atom";import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";import { integrationsOptimisticAtom } from "@executor-js/react/api/atoms";import { ReactivityKey } from "@executor-js/react/api/reactivity-keys";import { GraphqlClient } from "./client"; // ---------------------------------------------------------------------------// Query atoms — v2 is integration-centric. The graphql HTTP surface exposes// only the catalog integration (`getIntegration` → its stored config, which// carries the `authenticationTemplate[]`). Connections are created through the// core API (`createConnection` / `oauth.start`), not through this plugin's// surface.// --------------------------------------------------------------------------- export const graphqlIntegrationConfigAtom = (slug: IntegrationSlug) => GraphqlClient.query("graphql", "getIntegration", { params: { slug: String(slug) }, timeToLive: "15 seconds", reactivityKeys: [ReactivityKey.integrations, ReactivityKey.tools], }); // The full opaque config (including `authenticationTemplate`), used by the// configure UX to render existing auth methods and add custom ones.export const graphqlConfigAtom = (slug: IntegrationSlug) => GraphqlClient.query("graphql", "getConfig", { params: { slug: String(slug) }, timeToLive: "15 seconds", reactivityKeys: [ReactivityKey.integrations, ReactivityKey.tools], }); // ---------------------------------------------------------------------------// Mutation atoms// --------------------------------------------------------------------------- export const addGraphqlIntegration = GraphqlClient.mutation("graphql", "addIntegration"); // Merge-append custom auth methods onto an integration's `authenticationTemplate`.export const graphqlConfigure = GraphqlClient.mutation("graphql", "configure"); // Optimistically slot a pending row into the shared integration catalog so the// integrations list reflects the new GraphQL integration before the server// round-trips. The reducer mirrors the catalog `Integration` shape.export const addGraphqlIntegrationOptimistic = integrationsOptimisticAtom.pipe( Atom.optimisticFn({ reducer: ( current, arg: { readonly payload: { readonly endpoint: string; readonly slug?: string; readonly name?: string; }; }, ) => AsyncResult.map(current, (rows) => { const slug = (arg.payload.slug ?? `pending-${Math.random().toString(36).slice(2)}`) as IntegrationSlug; const integration = { slug, kind: "graphql", description: arg.payload.name ?? arg.payload.endpoint, canRemove: false, canRefresh: false, authMethods: [], }; return [integration, ...rows.filter((row) => row.slug !== slug)].sort((a, b) => a.description.localeCompare(b.description), ); }), fn: addGraphqlIntegration, }),);
import type { IntegrationSlug } from "@executor-js/sdk/shared";
import * as Atom from "effect/unstable/reactivity/Atom";
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
import { integrationsOptimisticAtom } from "@executor-js/react/api/atoms";
import { ReactivityKey } from "@executor-js/react/api/reactivity-keys";
import { GraphqlClient } from "./client";
// ---------------------------------------------------------------------------
// Query atoms — v2 is integration-centric. The graphql HTTP surface exposes
// only the catalog integration (`getIntegration` → its stored config, which
// carries the `authenticationTemplate[]`). Connections are created through the
// core API (`createConnection` / `oauth.start`), not through this plugin's
// surface.
// ---------------------------------------------------------------------------
export const graphqlIntegrationConfigAtom = (slug: IntegrationSlug) =>
GraphqlClient.query("graphql", "getIntegration", {
params: { slug: String(slug) },
timeToLive: "15 seconds",
reactivityKeys: [ReactivityKey.integrations, ReactivityKey.tools],
});
// The full opaque config (including `authenticationTemplate`), used by the
// configure UX to render existing auth methods and add custom ones.
export const graphqlConfigAtom = (slug: IntegrationSlug) =>
GraphqlClient.query("graphql", "getConfig", {
params: { slug: String(slug) },
timeToLive: "15 seconds",
reactivityKeys: [ReactivityKey.integrations, ReactivityKey.tools],
});
// ---------------------------------------------------------------------------
// Mutation atoms
// ---------------------------------------------------------------------------
export const addGraphqlIntegration = GraphqlClient.mutation("graphql", "addIntegration");
// Merge-append custom auth methods onto an integration's `authenticationTemplate`.
export const graphqlConfigure = GraphqlClient.mutation("graphql", "configure");
// Optimistically slot a pending row into the shared integration catalog so the
// integrations list reflects the new GraphQL integration before the server
// round-trips. The reducer mirrors the catalog `Integration` shape.
export const addGraphqlIntegrationOptimistic = integrationsOptimisticAtom.pipe(
Atom.optimisticFn({
reducer: (
current,
arg: {
readonly payload: {
readonly endpoint: string;
readonly slug?: string;
readonly name?: string;
};
},
) =>
AsyncResult.map(current, (rows) => {
const slug = (arg.payload.slug ??
`pending-${Math.random().toString(36).slice(2)}`) as IntegrationSlug;
const integration = {
slug,
kind: "graphql",
description: arg.payload.name ?? arg.payload.endpoint,
canRemove: false,
canRefresh: false,
authMethods: [],
};
return [integration, ...rows.filter((row) => row.slug !== slug)].sort((a, b) =>
a.description.localeCompare(b.description),
);
}),
fn: addGraphqlIntegration,
}),
);