// ---------------------------------------------------------------------------// examples/all-plugins//// Wires every ported plugin into a single Executor and walks the common v2// flows: credential providers, integration registration, connection creation// (a connection IS the credential), per-connection tool production, execution,// filtered listing, and shutdown.//// This is what an app/local or app/cloud bootstrap file looks like under the// v2 SDK shape — minus the HTTP API layer, runtime lifecycle, and owner/tenant// persistence that real apps add on top.//// Runs against the SDK's ephemeral in-memory FumaDB backend so you can// `bun run src/main.ts` and watch the whole surface exercise itself. Plugins// that need external infra (keychain prompts, 1Password unlock, MCP transport,// WorkOS Vault, Google OAuth) are wired so their credential providers and// extensions exist, but the flows that hit their backends are skipped by// default.// --------------------------------------------------------------------------- import { Cause, Effect, Redacted, Result } from "effect"; import { AuthTemplateSlug, ConnectionName, createExecutor, credentialValueToWrite, IntegrationSlug, ProviderItemId, ProviderKey, Tenant, ToolAddress, type CredentialProvider,} from "@executor-js/sdk"; import { fileSecretsPlugin } from "@executor-js/plugin-file-secrets";import { googleCatalog, googleDiscoveryAdapter,} from "@executor-js/plugin-openapi/providers/google";import { graphqlPlugin } from "@executor-js/plugin-graphql";import { keychainPlugin } from "@executor-js/plugin-keychain";import { mcpPlugin } from "@executor-js/plugin-mcp";import { onepasswordPlugin } from "@executor-js/plugin-onepassword";import { openApiPlugin, variable } from "@executor-js/plugin-openapi";import { microsoftCatalog, microsoftGraphAdapter,} from "@executor-js/plugin-openapi/providers/microsoft";import { workosVaultPlugin } from "@executor-js/plugin-workos-vault"; // ---------------------------------------------------------------------------// 1. Build the ExecutorConfig.//// Three pieces: tenant, plugins, and credential providers. The executor// auto-registers every `plugin.credentialProviders`; `config.providers` adds// inline ones (registered first, so they win as the default writable store).// Compare to v1, where you'd pass pre-built ToolRegistry, SourceRegistry,// SecretStore, and PolicyEngine service instances plus a scope stack.// --------------------------------------------------------------------------- // A connection's value lives in a writable credential provider. This tiny// in-memory store is enough for a script; the keychain / file-secrets /// 1Password plugins below contribute durable ones. Providers are Effect-native,// so `get`/`set` return `Effect`s, and `get` hands back a `Redacted` so a// credential cannot land in a log by accident.const memory = new Map<string, string>();const memoryProvider: CredentialProvider = { key: ProviderKey.make("memory"), writable: true, get: (id: ProviderItemId) => Effect.sync(() => { const value = memory.get(String(id)); return value === undefined ? null : Redacted.make(value); }), set: (id: ProviderItemId, value: string | Redacted.Redacted<string>) => Effect.sync(() => { memory.set(String(id), credentialValueToWrite(value)); }),}; const plugins = [ // Credential providers — three of them contributed by three plugins. The // executor auto-registers each one at startup via `plugin.credentialProviders` // (the v2 successor to v1's `secretProviders`). A connection routes its value // through one of these. keychainPlugin(), fileSecretsPlugin(), onepasswordPlugin(), // Integration plugins — these declare their own schemas (tables), register // integrations via their extension methods (`addSpec` / `addServer` / // `addIntegration`), and produce tools per connection. graphqlPlugin(), mcpPlugin({ dangerouslyAllowStdioMCP: false }), openApiPlugin({ presets: [...googleCatalog, ...microsoftCatalog], specFormats: [googleDiscoveryAdapter, microsoftGraphAdapter], }), // workos-vault is a cloud-hosted credential provider. It would contribute a // "workos-vault" provider if credentials were available. We skip it here // because it needs a real WorkOS API key; uncomment and supply credentials to // wire it in. // // workosVaultPlugin({ // credentials: { // apiKey: process.env.WORKOS_API_KEY!, // clientId: process.env.WORKOS_CLIENT_ID!, // }, // }),] as const; // Silence the unused-import warning for workos-vault (kept in scope as// documentation; uncomment the plugin entry above to use it).void workosVaultPlugin; // ---------------------------------------------------------------------------// 2. A tiny OpenAPI spec we'll use to demonstrate integration + connection// registration. Four operations, all deterministic.// --------------------------------------------------------------------------- const exampleOpenApiSpec = JSON.stringify({ openapi: "3.0.0", info: { title: "Example API", version: "1.0.0" }, servers: [{ url: "https://example.com/api" }], paths: { "/items": { get: { operationId: "items.list", tags: ["items"], summary: "List items", responses: { "200": { description: "ok", content: { "application/json": { schema: { type: "array", items: { $ref: "#/components/schemas/Item" }, }, }, }, }, }, }, post: { operationId: "items.create", tags: ["items"], summary: "Create an item", requestBody: { content: { "application/json": { schema: { $ref: "#/components/schemas/Item" }, }, }, }, responses: { "201": { description: "created" } }, }, }, "/items/{id}": { get: { operationId: "items.get", tags: ["items"], parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }], responses: { "200": { description: "ok" } }, }, delete: { operationId: "items.delete", tags: ["items"], parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }], responses: { "204": { description: "deleted" } }, }, }, }, components: { schemas: { Item: { type: "object", properties: { id: { type: "string" }, name: { type: "string" }, }, required: ["id", "name"], }, }, },}); // ---------------------------------------------------------------------------// 3. Main program — builds the executor and walks every surface.// --------------------------------------------------------------------------- const program = Effect.gen(function* () { console.log("=".repeat(72)); console.log("Building executor with every ported plugin"); console.log("=".repeat(72)); const executor = yield* createExecutor({ tenant: Tenant.make("example-tenant"), plugins, providers: [memoryProvider], onElicitation: "accept-all" as const, // `redirectUri` is intentionally omitted: this example never runs an // interactive OAuth flow. A host that serves OAuth must pass // `${webBaseUrl}/oauth/callback` here (there is no localhost default). }); // Every plugin's extension is accessible as `executor[pluginId]`. // TypeScript knows about each one — hovering over `executor` in your // editor shows the full merged surface. console.log("\nExecutor built. Plugin extensions:"); console.log(" executor.keychain ", typeof executor.keychain); console.log(" executor.fileSecrets ", typeof executor.fileSecrets); console.log(" executor.onepassword ", typeof executor.onepassword); console.log(" executor.graphql ", typeof executor.graphql); console.log(" executor.mcp ", typeof executor.mcp); console.log(" executor.openapi ", typeof executor.openapi); // ------------------------------------------------------------------------- // Credential providers — the inline `memory` store plus whichever plugin // providers were reachable (keychain/file/1Password register at startup). // A connection routes its value through one of these; there is no separate // secret store in v2 (a connection IS the saved credential). // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Credential providers"); console.log("-".repeat(72)); const providerKeys = yield* executor.providers.list(); console.log( "Registered providers:", providerKeys.map((k) => String(k)), ); // ------------------------------------------------------------------------- // Integration: OpenAPI — register a tiny spec as an integration. The // `authenticationTemplate` declares WHERE a connection's value renders on // each request (here an `X-API-Key` header); `variable("token")` is the slot // the resolved credential fills. // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Integration: OpenAPI"); console.log("-".repeat(72)); const addSpecResult = yield* executor.openapi.addSpec({ spec: { kind: "blob", value: exampleOpenApiSpec }, slug: "example-api", description: "Example API", baseUrl: "https://example.com/api", authenticationTemplate: [ { slug: "apiKey", type: "apiKey", headers: { "X-API-Key": [variable("token")] }, }, ], }); console.log("Registered OpenAPI integration:", { slug: String(addSpecResult.slug), toolCount: addSpecResult.toolCount, }); // A connection is the credential. Creating one with an inline `value` writes // it to the default writable provider (`memory`) and produces the // integration's per-connection tools, addressed // `tools.example-api.org.default.<tool>`. const openApiConnection = yield* executor.connections.create({ owner: "org", name: ConnectionName.make("default"), integration: IntegrationSlug.make("example-api"), template: AuthTemplateSlug.make("apiKey"), value: "sk-example-redacted", }); console.log("Created connection:", { address: String(openApiConnection.address), provider: String(openApiConnection.provider), }); const exampleTools = yield* executor.tools.list({ integration: IntegrationSlug.make("example-api"), }); console.log( "Tools under 'example-api':", exampleTools.map((t) => String(t.address)), ); // Annotations are derived at read time via plugin.resolveAnnotations. // GET tools are auto-approved, POST/DELETE require approval: console.log( "Annotations on example-api tools:", exampleTools.map((t) => ({ name: String(t.name), requiresApproval: t.annotations?.requiresApproval ?? false, })), ); // `tools.schema` walks the read path: reads the tool row, attaches matching // $defs (the `Item` schema) for $ref resolution. const getItemTool = exampleTools.find((t) => String(t.name).startsWith("items__get")); if (getItemTool) { const getItemSchema = yield* executor.tools.schema(getItemTool.address); console.log( "Schema for items.get has $defs?", getItemSchema?.inputSchema && typeof getItemSchema.inputSchema === "object" && "$defs" in getItemSchema.inputSchema, ); } // ------------------------------------------------------------------------- // Integration: GraphQL — introspect via a canned JSON doc so we don't need a // real server running, then connect (this endpoint needs no credential, so // the connection carries an empty value through a "none" template). // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Integration: GraphQL"); console.log("-".repeat(72)); const introspectionJson = JSON.stringify({ data: { __schema: { queryType: { name: "Query" }, mutationType: { name: "Mutation" }, types: [ { kind: "OBJECT", name: "Query", description: null, fields: [ { name: "hello", description: "Greet someone", args: [ { name: "name", description: null, type: { kind: "SCALAR", name: "String", ofType: null }, defaultValue: null, }, ], type: { kind: "SCALAR", name: "String", ofType: null }, }, ], inputFields: null, enumValues: null, }, { kind: "OBJECT", name: "Mutation", description: null, fields: [ { name: "setGreeting", description: "Change the greeting", args: [ { name: "message", description: null, type: { kind: "NON_NULL", name: null, ofType: { kind: "SCALAR", name: "String", ofType: null }, }, defaultValue: null, }, ], type: { kind: "SCALAR", name: "String", ofType: null }, }, ], inputFields: null, enumValues: null, }, { kind: "SCALAR", name: "String", description: null, fields: null, inputFields: null, enumValues: null, }, ], }, }, }); const gqlResult = yield* executor.graphql.addIntegration({ endpoint: "https://example.com/graphql", name: "Example GraphQL", introspectionJson, slug: "example-graphql", }); console.log("Registered GraphQL integration:", gqlResult); yield* executor.connections.create({ owner: "org", name: ConnectionName.make("default"), integration: IntegrationSlug.make("example-graphql"), template: AuthTemplateSlug.make("none"), value: "", }); const graphqlTools = yield* executor.tools.list({ integration: IntegrationSlug.make("example-graphql"), }); console.log( "Tools under 'example-graphql':", graphqlTools.map((t) => ({ address: String(t.address), requiresApproval: t.annotations?.requiresApproval ?? false, })), ); // ------------------------------------------------------------------------- // Other plugin extensions — shown but not exercised (they need real external // infrastructure). Their extension methods exist and would register real // integrations + connections the same way. // // removed: v1 `executor.secrets.set/get/list` and credential bindings — a // connection now IS the credential (see the OpenAPI flow above), and its value // lives in a registered provider rather than a free-floating secret store. // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Other plugin extensions (not exercised in this demo)"); console.log("-".repeat(72)); console.log(" executor.keychain.isSupported:", executor.keychain.isSupported); console.log(" executor.keychain.displayName:", executor.keychain.displayName); console.log(" executor.fileSecrets.filePath: ", executor.fileSecrets.filePath); // executor.mcp.addServer({ transport: "remote", name: "...", endpoint: "...", slug: "..." }); // Google catalog rows are added through executor.openapi.addSpec with specFormat "google-discovery". // executor.onepassword.configure({ auth: { kind: "desktop-app", accountName: "..." }, vaultId: "..." }); // ------------------------------------------------------------------------- // Execute a tool over its connection. The executor resolves the connection's // credential (from the `memory` provider) and hands it to the owning plugin's // invokeTool, which renders it through the auth template onto the request. // (The example.com host isn't real, so this surfaces a transport-level // failure — the point is the resolve + dispatch path, not a live response.) // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Execute over a connection"); console.log("-".repeat(72)); const listItemsTool = exampleTools.find((t) => String(t.name).startsWith("items__list")); if (listItemsTool) { const outcome = yield* Effect.result( executor.execute(ToolAddress.make(String(listItemsTool.address)), {}), ); console.log( `execute ${String(listItemsTool.address)}:`, Result.isSuccess(outcome) ? "ok" : `failed (${outcome.failure.constructor.name})`, ); } // ------------------------------------------------------------------------- // Whole-catalog tools listing + filtering // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Whole catalog"); console.log("-".repeat(72)); const allTools = yield* executor.tools.list(); console.log(`Total tools: ${allTools.length}`); const allIntegrations = yield* executor.integrations.list(); console.log( `Total integrations: ${allIntegrations.length}`, allIntegrations.map((i) => String(i.slug)), ); const allConnections = yield* executor.connections.list(); console.log( `Total connections: ${allConnections.length}`, allConnections.map((c) => String(c.address)), ); const mutationTools = yield* executor.tools.list({ query: "create" }); console.log( "Tools matching 'create':", mutationTools.map((t) => String(t.address)), ); // ------------------------------------------------------------------------- // Shutdown — close() is called on every plugin that declared a `close` hook // (the cache-backed ones like MCP tear down their connection pool). // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Shutdown"); console.log("-".repeat(72)); yield* executor.close();Lines 1–500 of 517. Load more
// --------------------------------------------------------------------------- // examples/all-plugins // // Wires every ported plugin into a single Executor and walks the common v2 // flows: credential providers, integration registration, connection creation // (a connection IS the credential), per-connection tool production, execution, // filtered listing, and shutdown. // // This is what an app/local or app/cloud bootstrap file looks like under the // v2 SDK shape — minus the HTTP API layer, runtime lifecycle, and owner/tenant // persistence that real apps add on top. // // Runs against the SDK's ephemeral in-memory FumaDB backend so you can // `bun run src/main.ts` and watch the whole surface exercise itself. Plugins // that need external infra (keychain prompts, 1Password unlock, MCP transport, // WorkOS Vault, Google OAuth) are wired so their credential providers and // extensions exist, but the flows that hit their backends are skipped by // default. // --------------------------------------------------------------------------- import { Cause, Effect, Redacted, Result } from "effect"; import { AuthTemplateSlug, ConnectionName, createExecutor, credentialValueToWrite, IntegrationSlug, ProviderItemId, ProviderKey, Tenant, ToolAddress, type CredentialProvider, } from "@executor-js/sdk"; import { fileSecretsPlugin } from "@executor-js/plugin-file-secrets"; import { googleCatalog, googleDiscoveryAdapter, } from "@executor-js/plugin-openapi/providers/google"; import { graphqlPlugin } from "@executor-js/plugin-graphql"; import { keychainPlugin } from "@executor-js/plugin-keychain"; import { mcpPlugin } from "@executor-js/plugin-mcp"; import { onepasswordPlugin } from "@executor-js/plugin-onepassword"; import { openApiPlugin, variable } from "@executor-js/plugin-openapi"; import { microsoftCatalog, microsoftGraphAdapter, } from "@executor-js/plugin-openapi/providers/microsoft"; import { workosVaultPlugin } from "@executor-js/plugin-workos-vault"; // --------------------------------------------------------------------------- // 1. Build the ExecutorConfig. // // Three pieces: tenant, plugins, and credential providers. The executor // auto-registers every `plugin.credentialProviders`; `config.providers` adds // inline ones (registered first, so they win as the default writable store). // Compare to v1, where you'd pass pre-built ToolRegistry, SourceRegistry, // SecretStore, and PolicyEngine service instances plus a scope stack. // --------------------------------------------------------------------------- // A connection's value lives in a writable credential provider. This tiny // in-memory store is enough for a script; the keychain / file-secrets / // 1Password plugins below contribute durable ones. Providers are Effect-native, // so `get`/`set` return `Effect`s, and `get` hands back a `Redacted` so a // credential cannot land in a log by accident. const memory = new Map<string, string>(); const memoryProvider: CredentialProvider = { key: ProviderKey.make("memory"), writable: true, get: (id: ProviderItemId) => Effect.sync(() => { const value = memory.get(String(id)); return value === undefined ? null : Redacted.make(value); }), set: (id: ProviderItemId, value: string | Redacted.Redacted<string>) => Effect.sync(() => { memory.set(String(id), credentialValueToWrite(value)); }), }; const plugins = [ // Credential providers — three of them contributed by three plugins. The // executor auto-registers each one at startup via `plugin.credentialProviders` // (the v2 successor to v1's `secretProviders`). A connection routes its value // through one of these. keychainPlugin(), fileSecretsPlugin(), onepasswordPlugin(), // Integration plugins — these declare their own schemas (tables), register // integrations via their extension methods (`addSpec` / `addServer` / // `addIntegration`), and produce tools per connection. graphqlPlugin(), mcpPlugin({ dangerouslyAllowStdioMCP: false }), openApiPlugin({ presets: [...googleCatalog, ...microsoftCatalog], specFormats: [googleDiscoveryAdapter, microsoftGraphAdapter], }), // workos-vault is a cloud-hosted credential provider. It would contribute a // "workos-vault" provider if credentials were available. We skip it here // because it needs a real WorkOS API key; uncomment and supply credentials to // wire it in. // // workosVaultPlugin({ // credentials: { // apiKey: process.env.WORKOS_API_KEY!, // clientId: process.env.WORKOS_CLIENT_ID!, // }, // }), ] as const; // Silence the unused-import warning for workos-vault (kept in scope as // documentation; uncomment the plugin entry above to use it). void workosVaultPlugin; // --------------------------------------------------------------------------- // 2. A tiny OpenAPI spec we'll use to demonstrate integration + connection // registration. Four operations, all deterministic. // --------------------------------------------------------------------------- const exampleOpenApiSpec = JSON.stringify({ openapi: "3.0.0", info: { title: "Example API", version: "1.0.0" }, servers: [{ url: "https://example.com/api" }], paths: { "/items": { get: { operationId: "items.list", tags: ["items"], summary: "List items", responses: { "200": { description: "ok", content: { "application/json": { schema: { type: "array", items: { $ref: "#/components/schemas/Item" }, }, }, }, }, }, }, post: { operationId: "items.create", tags: ["items"], summary: "Create an item", requestBody: { content: { "application/json": { schema: { $ref: "#/components/schemas/Item" }, }, }, }, responses: { "201": { description: "created" } }, }, }, "/items/{id}": { get: { operationId: "items.get", tags: ["items"], parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }], responses: { "200": { description: "ok" } }, }, delete: { operationId: "items.delete", tags: ["items"], parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }], responses: { "204": { description: "deleted" } }, }, }, }, components: { schemas: { Item: { type: "object", properties: { id: { type: "string" }, name: { type: "string" }, }, required: ["id", "name"], }, }, }, }); // --------------------------------------------------------------------------- // 3. Main program — builds the executor and walks every surface. // --------------------------------------------------------------------------- const program = Effect.gen(function* () { console.log("=".repeat(72)); console.log("Building executor with every ported plugin"); console.log("=".repeat(72)); const executor = yield* createExecutor({ tenant: Tenant.make("example-tenant"), plugins, providers: [memoryProvider], onElicitation: "accept-all" as const, // `redirectUri` is intentionally omitted: this example never runs an // interactive OAuth flow. A host that serves OAuth must pass // `${webBaseUrl}/oauth/callback` here (there is no localhost default). }); // Every plugin's extension is accessible as `executor[pluginId]`. // TypeScript knows about each one — hovering over `executor` in your // editor shows the full merged surface. console.log("\nExecutor built. Plugin extensions:"); console.log(" executor.keychain ", typeof executor.keychain); console.log(" executor.fileSecrets ", typeof executor.fileSecrets); console.log(" executor.onepassword ", typeof executor.onepassword); console.log(" executor.graphql ", typeof executor.graphql); console.log(" executor.mcp ", typeof executor.mcp); console.log(" executor.openapi ", typeof executor.openapi); // ------------------------------------------------------------------------- // Credential providers — the inline `memory` store plus whichever plugin // providers were reachable (keychain/file/1Password register at startup). // A connection routes its value through one of these; there is no separate // secret store in v2 (a connection IS the saved credential). // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Credential providers"); console.log("-".repeat(72)); const providerKeys = yield* executor.providers.list(); console.log( "Registered providers:", providerKeys.map((k) => String(k)), ); // ------------------------------------------------------------------------- // Integration: OpenAPI — register a tiny spec as an integration. The // `authenticationTemplate` declares WHERE a connection's value renders on // each request (here an `X-API-Key` header); `variable("token")` is the slot // the resolved credential fills. // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Integration: OpenAPI"); console.log("-".repeat(72)); const addSpecResult = yield* executor.openapi.addSpec({ spec: { kind: "blob", value: exampleOpenApiSpec }, slug: "example-api", description: "Example API", baseUrl: "https://example.com/api", authenticationTemplate: [ { slug: "apiKey", type: "apiKey", headers: { "X-API-Key": [variable("token")] }, }, ], }); console.log("Registered OpenAPI integration:", { slug: String(addSpecResult.slug), toolCount: addSpecResult.toolCount, }); // A connection is the credential. Creating one with an inline `value` writes // it to the default writable provider (`memory`) and produces the // integration's per-connection tools, addressed // `tools.example-api.org.default.<tool>`. const openApiConnection = yield* executor.connections.create({ owner: "org", name: ConnectionName.make("default"), integration: IntegrationSlug.make("example-api"), template: AuthTemplateSlug.make("apiKey"), value: "sk-example-redacted", }); console.log("Created connection:", { address: String(openApiConnection.address), provider: String(openApiConnection.provider), }); const exampleTools = yield* executor.tools.list({ integration: IntegrationSlug.make("example-api"), }); console.log( "Tools under 'example-api':", exampleTools.map((t) => String(t.address)), ); // Annotations are derived at read time via plugin.resolveAnnotations. // GET tools are auto-approved, POST/DELETE require approval: console.log( "Annotations on example-api tools:", exampleTools.map((t) => ({ name: String(t.name), requiresApproval: t.annotations?.requiresApproval ?? false, })), ); // `tools.schema` walks the read path: reads the tool row, attaches matching // $defs (the `Item` schema) for $ref resolution. const getItemTool = exampleTools.find((t) => String(t.name).startsWith("items__get")); if (getItemTool) { const getItemSchema = yield* executor.tools.schema(getItemTool.address); console.log( "Schema for items.get has $defs?", getItemSchema?.inputSchema && typeof getItemSchema.inputSchema === "object" && "$defs" in getItemSchema.inputSchema, ); } // ------------------------------------------------------------------------- // Integration: GraphQL — introspect via a canned JSON doc so we don't need a // real server running, then connect (this endpoint needs no credential, so // the connection carries an empty value through a "none" template). // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Integration: GraphQL"); console.log("-".repeat(72)); const introspectionJson = JSON.stringify({ data: { __schema: { queryType: { name: "Query" }, mutationType: { name: "Mutation" }, types: [ { kind: "OBJECT", name: "Query", description: null, fields: [ { name: "hello", description: "Greet someone", args: [ { name: "name", description: null, type: { kind: "SCALAR", name: "String", ofType: null }, defaultValue: null, }, ], type: { kind: "SCALAR", name: "String", ofType: null }, }, ], inputFields: null, enumValues: null, }, { kind: "OBJECT", name: "Mutation", description: null, fields: [ { name: "setGreeting", description: "Change the greeting", args: [ { name: "message", description: null, type: { kind: "NON_NULL", name: null, ofType: { kind: "SCALAR", name: "String", ofType: null }, }, defaultValue: null, }, ], type: { kind: "SCALAR", name: "String", ofType: null }, }, ], inputFields: null, enumValues: null, }, { kind: "SCALAR", name: "String", description: null, fields: null, inputFields: null, enumValues: null, }, ], }, }, }); const gqlResult = yield* executor.graphql.addIntegration({ endpoint: "https://example.com/graphql", name: "Example GraphQL", introspectionJson, slug: "example-graphql", }); console.log("Registered GraphQL integration:", gqlResult); yield* executor.connections.create({ owner: "org", name: ConnectionName.make("default"), integration: IntegrationSlug.make("example-graphql"), template: AuthTemplateSlug.make("none"), value: "", }); const graphqlTools = yield* executor.tools.list({ integration: IntegrationSlug.make("example-graphql"), }); console.log( "Tools under 'example-graphql':", graphqlTools.map((t) => ({ address: String(t.address), requiresApproval: t.annotations?.requiresApproval ?? false, })), ); // ------------------------------------------------------------------------- // Other plugin extensions — shown but not exercised (they need real external // infrastructure). Their extension methods exist and would register real // integrations + connections the same way. // // removed: v1 `executor.secrets.set/get/list` and credential bindings — a // connection now IS the credential (see the OpenAPI flow above), and its value // lives in a registered provider rather than a free-floating secret store. // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Other plugin extensions (not exercised in this demo)"); console.log("-".repeat(72)); console.log(" executor.keychain.isSupported:", executor.keychain.isSupported); console.log(" executor.keychain.displayName:", executor.keychain.displayName); console.log(" executor.fileSecrets.filePath: ", executor.fileSecrets.filePath); // executor.mcp.addServer({ transport: "remote", name: "...", endpoint: "...", slug: "..." }); // Google catalog rows are added through executor.openapi.addSpec with specFormat "google-discovery". // executor.onepassword.configure({ auth: { kind: "desktop-app", accountName: "..." }, vaultId: "..." }); // ------------------------------------------------------------------------- // Execute a tool over its connection. The executor resolves the connection's // credential (from the `memory` provider) and hands it to the owning plugin's // invokeTool, which renders it through the auth template onto the request. // (The example.com host isn't real, so this surfaces a transport-level // failure — the point is the resolve + dispatch path, not a live response.) // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Execute over a connection"); console.log("-".repeat(72)); const listItemsTool = exampleTools.find((t) => String(t.name).startsWith("items__list")); if (listItemsTool) { const outcome = yield* Effect.result( executor.execute(ToolAddress.make(String(listItemsTool.address)), {}), ); console.log( `execute ${String(listItemsTool.address)}:`, Result.isSuccess(outcome) ? "ok" : `failed (${outcome.failure.constructor.name})`, ); } // ------------------------------------------------------------------------- // Whole-catalog tools listing + filtering // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Whole catalog"); console.log("-".repeat(72)); const allTools = yield* executor.tools.list(); console.log(`Total tools: ${allTools.length}`); const allIntegrations = yield* executor.integrations.list(); console.log( `Total integrations: ${allIntegrations.length}`, allIntegrations.map((i) => String(i.slug)), ); const allConnections = yield* executor.connections.list(); console.log( `Total connections: ${allConnections.length}`, allConnections.map((c) => String(c.address)), ); const mutationTools = yield* executor.tools.list({ query: "create" }); console.log( "Tools matching 'create':", mutationTools.map((t) => String(t.address)), ); // ------------------------------------------------------------------------- // Shutdown — close() is called on every plugin that declared a `close` hook // (the cache-backed ones like MCP tear down their connection pool). // ------------------------------------------------------------------------- console.log("\n" + "-".repeat(72)); console.log("Shutdown"); console.log("-".repeat(72)); yield* executor.close();