Unified · Split
| @@ -6,7 +6,7 @@ import { cn } from "../lib/utils"; · 5 unmodified lines | ||
| 6 | 6 | import { IconPlus, IconCopy, IconCheck } from "./icons"; |
| 7 | 7 | import { LoadableBlock } from "./loadable"; |
| 8 | 8 | import { SourceFavicon } from "./source-favicon"; |
| 9 | −import { getSourceFrontendPaths } from "../source-plugins"; | |
| 9 | +import { getSourceFrontendPaths } from "../plugins"; | |
| 10 | 10 | |
| 11 | 11 | // ── Status dot color ───────────────────────────────────────────────────── |
| 12 | 12 | |
| @@ -324,7 +324,7 @@ function SourceItem(props: { · 311 unmodified lines | ||
| 324 | 324 | return ( |
| 325 | 325 | <div className="group flex items-center gap-2 rounded-md px-2.5 py-1.5 text-[13px] text-sidebar-foreground/60"> |
| 326 | 326 | <div className="flex size-3 shrink-0 items-center justify-center text-muted-foreground/50"> |
| 327 | − <SourceFavicon kind={props.source.kind} className="size-3" /> | |
| 327 | + <SourceFavicon source={props.source} className="size-3" /> | |
| 328 | 328 | </div> |
| 329 | 329 | <span className="flex-1 truncate">{props.source.name}</span> |
| 330 | 330 | <span |
| @@ -352,7 +352,7 @@ function SourceItem(props: { · 21 unmodified lines | ||
| 352 | 352 | )} |
| 353 | 353 | > |
| 354 | 354 | <div className="flex size-3 shrink-0 items-center justify-center text-muted-foreground/50"> |
| 355 | − <SourceFavicon kind={props.source.kind} className="size-3" /> | |
| 355 | + <SourceFavicon source={props.source} className="size-3" /> | |
| 356 | 356 | </div> |
| 357 | 357 | <span className="flex-1 truncate">{props.source.name}</span> |
| 358 | 358 | <span |
| @@ -1,30 +1,25 @@ | ||
| 1 | −import { useMemo, useState } from "react"; | |
| 1 | +import { useState } from "react"; | |
| 2 | 2 | import type { Source } from "@executor/react"; |
| 3 | −import { getGoogleProductIconUrl, getSourceFaviconUrl } from "../lib/source-favicon"; | |
| 3 | +import { getSourceFrontendIconUrl } from "../plugins"; | |
| 4 | 4 | import { cn } from "../lib/utils"; |
| 5 | 5 | |
| 6 | 6 | type SourceKind = Source["kind"] | string; |
| 7 | 7 | |
| 8 | 8 | export function SourceFavicon({ |
| 9 | − endpoint, | |
| 10 | − kind: _kind, | |
| 9 | + source, | |
| 11 | 10 | className, |
| 12 | 11 | size = 16, |
| 13 | 12 | }: { |
| 14 | − endpoint?: string | null; | |
| 15 | − kind: SourceKind; | |
| 13 | + source: Source; | |
| 16 | 14 | className?: string; |
| 17 | 15 | size?: number; |
| 18 | 16 | }) { |
| 19 | − const faviconUrl = useMemo(() => { | |
| 20 | − return getGoogleProductIconUrl(endpoint) ?? getSourceFaviconUrl(endpoint); | |
| 21 | − }, [endpoint]); | |
| 22 | − | |
| 17 | + const faviconUrl = getSourceFrontendIconUrl(source); | |
| 23 | 18 | const [failedUrl, setFailedUrl] = useState<string | null>(null); |
| 24 | 19 | const isFailed = Boolean(faviconUrl && failedUrl === faviconUrl); |
| 25 | 20 | |
| 26 | 21 | if (!faviconUrl || isFailed) { |
| 27 | − return <DefaultSourceIcon kind={_kind} className={className} />; | |
| 22 | + return <DefaultSourceIcon kind={source.kind} className={className} />; | |
| 28 | 23 | } |
| 29 | 24 | |
| 30 | 25 | return ( |
| @@ -1,123 +0,0 @@ | ||
| 1 | −import { parse as parseDomain } from "tldts"; | |
| 2 | − | |
| 3 | −const RAW_HOSTS = new Set([ | |
| 4 | − "raw.githubusercontent.com", | |
| 5 | − "cdn.jsdelivr.net", | |
| 6 | − "unpkg.com", | |
| 7 | − "raw.github.com", | |
| 8 | −]); | |
| 9 | − | |
| 10 | −// --------------------------------------------------------------------------- | |
| 11 | −// Google product icon URLs (official CDN assets) | |
| 12 | −// --------------------------------------------------------------------------- | |
| 13 | − | |
| 14 | −const GOOGLE_SERVICE_ICONS: Record<string, string> = { | |
| 15 | − calendar: "https://ssl.gstatic.com/calendar/images/dynamiclogo_2020q4/calendar_31_2x.png", | |
| 16 | − drive: "https://ssl.gstatic.com/images/branding/product/2x/drive_2020q4_48dp.png", | |
| 17 | − gmail: "https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico", | |
| 18 | − docs: "https://ssl.gstatic.com/docs/documents/images/kix-favicon7.ico", | |
| 19 | − sheets: "https://ssl.gstatic.com/docs/spreadsheets/favicon3.ico", | |
| 20 | − slides: "https://ssl.gstatic.com/docs/presentations/images/favicon5.ico", | |
| 21 | − forms: "https://ssl.gstatic.com/docs/forms/device_home/android_192.png", | |
| 22 | − searchconsole: "https://ssl.gstatic.com/search-console/scfe/search_console-64.png", | |
| 23 | − people: "https://ssl.gstatic.com/images/branding/product/2x/contacts_2022_48dp.png", | |
| 24 | − tasks: "https://ssl.gstatic.com/tasks/images/favicon.ico", | |
| 25 | − chat: "https://ssl.gstatic.com/chat/favicon/favicon_v2.ico", | |
| 26 | − keep: "https://ssl.gstatic.com/keep/icon_2020q4v2_128.png", | |
| 27 | − classroom: "https://ssl.gstatic.com/classroom/favicon.png", | |
| 28 | − admin: "https://ssl.gstatic.com/images/branding/product/2x/admin_2020q4_48dp.png", | |
| 29 | − script: "https://ssl.gstatic.com/script/images/favicon.ico", | |
| 30 | − bigquery: "https://ssl.gstatic.com/bqui1/favicon.ico", | |
| 31 | − cloudresourcemanager: "https://www.gstatic.com/devrel-devsite/prod/v0e0f589edd85502a40d78d7d0825db8ea5ef3b99b1571571945f0f3f764ff61b/cloud/images/favicons/onecloud/favicon.ico", | |
| 32 | − youtube: "https://www.youtube.com/s/desktop/a94e1818/img/favicon_32x32.png", | |
| 33 | −}; | |
| 34 | − | |
| 35 | −/** | |
| 36 | − * For google_discovery endpoints, extract the service name and return | |
| 37 | − * the official product icon URL if we have one. | |
| 38 | − */ | |
| 39 | −const getGoogleServiceIconUrl = (endpoint: string | null | undefined): string | null => { | |
| 40 | − if (!endpoint) return null; | |
| 41 | − try { | |
| 42 | − const url = new URL(endpoint); | |
| 43 | − const host = url.hostname; | |
| 44 | − | |
| 45 | − // Direct service subdomain: "calendar-json.googleapis.com", "gmail.googleapis.com" | |
| 46 | − if (host.endsWith(".googleapis.com")) { | |
| 47 | − const sub = host.replace(/\.googleapis\.com$/, "").replace(/-json$/, ""); | |
| 48 | − if (GOOGLE_SERVICE_ICONS[sub]) return GOOGLE_SERVICE_ICONS[sub]; | |
| 49 | − } | |
| 50 | − | |
| 51 | − // Discovery URL pattern: /discovery/v1/apis/{service}/{version}/rest | |
| 52 | − const discoveryMatch = url.pathname.match(/\/apis\/([^/]+)\//); | |
| 53 | − if (discoveryMatch?.[1] && GOOGLE_SERVICE_ICONS[discoveryMatch[1]]) { | |
| 54 | − return GOOGLE_SERVICE_ICONS[discoveryMatch[1]]; | |
| 55 | − } | |
| 56 | − | |
| 57 | − // $discovery/rest pattern on service subdomains is already handled above | |
| 58 | − } catch { | |
| 59 | − // fall through | |
| 60 | − } | |
| 61 | − return null; | |
| 62 | −}; | |
| 63 | − | |
| 64 | −// --------------------------------------------------------------------------- | |
| 65 | −// General favicon resolution | |
| 66 | −// --------------------------------------------------------------------------- | |
| 67 | − | |
| 68 | −const parseUrl = (value: string | null | undefined): URL | null => { | |
| 69 | − if (!value) { | |
| 70 | − return null; | |
| 71 | − } | |
| 72 | − | |
| 73 | − try { | |
| 74 | − return new URL(value); | |
| 75 | − } catch { | |
| 76 | − return null; | |
| 77 | − } | |
| 78 | −}; | |
| 79 | − | |
| 80 | −const normalizeSeedUrl = (value: string | null | undefined): string | null => { | |
| 81 | − const parsed = parseUrl(value); | |
| 82 | − if (!parsed) { | |
| 83 | − return null; | |
| 84 | − } | |
| 85 | − | |
| 86 | − if (!RAW_HOSTS.has(parsed.hostname)) { | |
| 87 | − return parsed.origin; | |
| 88 | − } | |
| 89 | − | |
| 90 | − const segments = parsed.pathname | |
| 91 | − .split("/") | |
| 92 | − .map((segment) => segment.trim()) | |
| 93 | − .filter((segment) => segment.length > 0); | |
| 94 | − | |
| 95 | − for (const segment of segments) { | |
| 96 | − const withoutExtension = segment.replace(/\.(ya?ml|json)$/i, ""); | |
| 97 | − if (/^[a-z0-9-]+(\.[a-z0-9-]+)+$/i.test(withoutExtension)) { | |
| 98 | − return `https://${withoutExtension}`; | |
| 99 | − } | |
| 100 | − } | |
| 101 | − | |
| 102 | − return parsed.origin; | |
| 103 | −}; | |
| 104 | − | |
| 105 | −export const getGoogleProductIconUrl = getGoogleServiceIconUrl; | |
| 106 | − | |
| 107 | −export const getSourceFaviconUrl = ( | |
| 108 | − value: string | null | undefined, | |
| 109 | −): string | null => { | |
| 110 | − const seedUrl = normalizeSeedUrl(value); | |
| 111 | − if (!seedUrl) { | |
| 112 | − return null; | |
| 113 | − } | |
| 114 | − | |
| 115 | − try { | |
| 116 | − const hostname = new URL(seedUrl).hostname; | |
| 117 | − const parsed = parseDomain(hostname); | |
| 118 | − const domain = parsed.domain ?? hostname; | |
| 119 | − return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=32`; | |
| 120 | − } catch { | |
| 121 | − return null; | |
| 122 | − } | |
| 123 | −}; | |
| @@ -24,7 +24,7 @@ import { AppShell } from "./components/shell"; · 23 unmodified lines | ||
| 24 | 24 | import { |
| 25 | 25 | registeredFrontendPluginRoutes, |
| 26 | 26 | registeredSourceFrontendTypes, |
| 27 | −} from "./source-plugins"; | |
| 27 | +} from "./plugins"; | |
| 28 | 28 | import { |
| 29 | 29 | ExecutorPluginRoutePage, |
| 30 | 30 | SourcePluginAddPage, |
| @@ -32,7 +32,7 @@ import { · 1 unmodified line | ||
| 32 | 32 | SourcePluginDetailPage, |
| 33 | 33 | SourcePluginEditPage, |
| 34 | 34 | SourcePluginsIndexPage, |
| 35 | −} from "./source-plugins/pages"; | |
| 35 | +} from "./plugins/pages"; | |
| 36 | 36 | import { HomePage } from "./views/home"; |
| 37 | 37 | import { SecretsPage } from "./views/secrets"; |
| 38 | 38 | |
| @@ -1,3 +1,4 @@ | ||
| 1 | +import type { Source } from "@executor/react"; | |
| 1 | 2 | import { |
| 2 | 3 | GoogleDiscoveryReactPlugin, |
| 3 | 4 | } from "@executor/plugin-google-discovery-react"; |
| @@ -59,3 +60,6 @@ export const getSourceFrontendPaths = (kind: string) => { · 55 unmodified lines | ||
| 59 | 60 | const definition = getSourceFrontendType(kind); |
| 60 | 61 | return definition ? createSourcePluginPaths(definition.key) : null; |
| 61 | 62 | }; |
| 63 | + | |
| 64 | +export const getSourceFrontendIconUrl = (source: Source) => | |
| 65 | + getSourceFrontendTypeEntry(source.kind)?.definition.getIconUrl?.(source) ?? null; | |
File renamed without changes.
| @@ -8,7 +8,7 @@ import { SourcePluginsResetState } from "../components/source-plugins-reset-stat · 7 unmodified lines | ||
| 8 | 8 | import { |
| 9 | 9 | getSourceFrontendPaths, |
| 10 | 10 | registeredSourceFrontendTypes, |
| 11 | −} from "../source-plugins"; | |
| 11 | +} from "../plugins"; | |
| 12 | 12 | |
| 13 | 13 | export function HomePage() { |
| 14 | 14 | const sources = useSources(); |
| @@ -123,18 +123,6 @@ · 122 unmodified lines | ||
| 123 | 123 | "bun-types": "catalog:", |
| 124 | 124 | }, |
| 125 | 125 | }, |
| 126 | − "packages/auth/mcp-oauth": { | |
| 127 | − "name": "@executor/auth-mcp-oauth", | |
| 128 | − "version": "0.0.0", | |
| 129 | − "dependencies": { | |
| 130 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 131 | − "effect": "catalog:", | |
| 132 | − }, | |
| 133 | − "devDependencies": { | |
| 134 | − "@types/node": "catalog:", | |
| 135 | − "bun-types": "catalog:", | |
| 136 | − }, | |
| 137 | − }, | |
| 138 | 126 | "packages/clients/react": { |
| 139 | 127 | "name": "@executor/react", |
| 140 | 128 | "version": "0.0.0", |
| @@ -587,7 +575,6 @@ · 446 unmodified lines | ||
| 587 | 575 | "name": "@executor/plugin-mcp-sdk", |
| 588 | 576 | "version": "0.0.0", |
| 589 | 577 | "dependencies": { |
| 590 | − "@executor/auth-mcp-oauth": "workspace:*", | |
| 591 | 578 | "@executor/codemode-core": "workspace:*", |
| 592 | 579 | "@executor/ir": "workspace:*", |
| 593 | 580 | "@executor/platform-sdk": "workspace:*", |
| @@ -883,8 +870,6 @@ · 289 unmodified lines | ||
| 883 | 870 | |
| 884 | 871 | "@executor/ai-sdk-adapter": ["@executor/ai-sdk-adapter@workspace:packages/hosts/ai-sdk"], |
| 885 | 872 | |
| 886 | − "@executor/auth-mcp-oauth": ["@executor/auth-mcp-oauth@workspace:packages/auth/mcp-oauth"], | |
| 887 | − | |
| 888 | 873 | "@executor/codemode-core": ["@executor/codemode-core@workspace:packages/kernel/core"], |
| 889 | 874 | |
| 890 | 875 | "@executor/docs": ["@executor/docs@workspace:apps/docs"], |
| @@ -1,23 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "name": "@executor/auth-mcp-oauth", | |
| 3 | − "private": true, | |
| 4 | − "type": "module", | |
| 5 | − "exports": { | |
| 6 | − ".": "./src/index.ts" | |
| 7 | − }, | |
| 8 | − "files": [ | |
| 9 | − "src" | |
| 10 | − ], | |
| 11 | − "scripts": { | |
| 12 | − "typecheck": "bunx tsc --noEmit -p tsconfig.json" | |
| 13 | − }, | |
| 14 | − "dependencies": { | |
| 15 | − "@modelcontextprotocol/sdk": "^1.26.0", | |
| 16 | − "effect": "catalog:" | |
| 17 | − }, | |
| 18 | − "devDependencies": { | |
| 19 | − "@types/node": "catalog:", | |
| 20 | − "bun-types": "catalog:" | |
| 21 | − }, | |
| 22 | − "version": "0.0.0" | |
| 23 | −} | |
| @@ -1,19 +0,0 @@ | ||
| 1 | −{ | |
| 2 | − "compilerOptions": { | |
| 3 | − "target": "ES2022", | |
| 4 | − "module": "ESNext", | |
| 5 | − "moduleResolution": "Bundler", | |
| 6 | − "strict": true, | |
| 7 | − "skipLibCheck": true, | |
| 8 | − "noEmit": true, | |
| 9 | − "lib": ["ES2022"], | |
| 10 | − "types": ["bun-types", "node"] | |
| 11 | − }, | |
| 12 | − "include": [ | |
| 13 | − "src/**/*.ts", | |
| 14 | − "src/**/*.d.ts" | |
| 15 | − ], | |
| 16 | − "exclude": [ | |
| 17 | − "src/**/*.test.ts" | |
| 18 | − ] | |
| 19 | −} | |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
| @@ -1 +1,104 @@ | ||
| 1 | −export * from "../source-plugins/index"; | |
| 1 | +export type { | |
| 2 | + ExecutorFrontendPlugin, | |
| 3 | + ExecutorPluginNavigation, | |
| 4 | + ExecutorPluginRouteContextValue, | |
| 5 | + FrontendPluginRouteDefinition, | |
| 6 | + FrontendPluginRouteParams, | |
| 7 | + FrontendPluginRouteSearch, | |
| 8 | + FrontendSourceDetailRouteDefinition, | |
| 9 | + FrontendSourceTypeDefinition, | |
| 10 | + SourcePluginNavigation, | |
| 11 | + SourcePluginRouteContextValue, | |
| 12 | + SourcePluginRouteParams, | |
| 13 | + SourcePluginRouteSearch, | |
| 14 | +} from "./types"; | |
| 15 | + | |
| 16 | +export { | |
| 17 | + createExecutorPluginPaths, | |
| 18 | + createSourcePluginPaths, | |
| 19 | + executorPluginBasePath, | |
| 20 | + executorPluginRoutePath, | |
| 21 | + executorPluginRoutePattern, | |
| 22 | + normalizeExecutorPluginPath, | |
| 23 | + normalizeSourcePluginPath, | |
| 24 | + sourcePluginAddPath, | |
| 25 | + sourcePluginChildPath, | |
| 26 | + sourcePluginChildPattern, | |
| 27 | + sourcePluginDetailPath, | |
| 28 | + sourcePluginDetailPattern, | |
| 29 | + sourcePluginEditPath, | |
| 30 | + sourcePluginEditPattern, | |
| 31 | + sourcePluginsIndexPath, | |
| 32 | + type ExecutorPluginPaths, | |
| 33 | + type SourcePluginPaths, | |
| 34 | +} from "./paths"; | |
| 35 | + | |
| 36 | +export { | |
| 37 | + defineExecutorFrontendPlugin, | |
| 38 | + defineFrontendPluginRoute, | |
| 39 | + defineFrontendSourceType, | |
| 40 | + registerExecutorFrontendPlugins, | |
| 41 | + type RegisteredFrontendPluginRoute, | |
| 42 | + type RegisteredFrontendSourceType, | |
| 43 | +} from "./registry"; | |
| 44 | + | |
| 45 | +export { | |
| 46 | + ExecutorPluginRouteProvider, | |
| 47 | + useExecutorPlugin, | |
| 48 | + useExecutorPluginNavigation, | |
| 49 | + useExecutorPluginPaths, | |
| 50 | + useExecutorPluginRoute, | |
| 51 | + useExecutorPluginRouteDefinition, | |
| 52 | + useExecutorPluginRouteParams, | |
| 53 | + useExecutorPluginSearch, | |
| 54 | +} from "./plugin-route-context"; | |
| 55 | + | |
| 56 | +export { | |
| 57 | + SourcePluginRouteProvider, | |
| 58 | + useSourcePlugin, | |
| 59 | + useSourcePluginDefinition, | |
| 60 | + useSourcePluginNavigation, | |
| 61 | + useSourcePluginPaths, | |
| 62 | + useSourcePluginRoute, | |
| 63 | + useSourcePluginRouteParams, | |
| 64 | + useSourcePluginSearch, | |
| 65 | +} from "./route-context"; | |
| 66 | + | |
| 67 | +export { | |
| 68 | + cn, | |
| 69 | +} from "./lib/cn"; | |
| 70 | + | |
| 71 | +export { | |
| 72 | + Badge, | |
| 73 | + MethodBadge, | |
| 74 | +} from "./components/badge"; | |
| 75 | +export { | |
| 76 | + CodeBlock, | |
| 77 | +} from "./components/code-block"; | |
| 78 | +export { | |
| 79 | + DocumentPanel, | |
| 80 | +} from "./components/document-panel"; | |
| 81 | +export { | |
| 82 | + IconCheck, | |
| 83 | + IconChevron, | |
| 84 | + IconClose, | |
| 85 | + IconCopy, | |
| 86 | + IconEmpty, | |
| 87 | + IconFolder, | |
| 88 | + IconPencil, | |
| 89 | + IconSearch, | |
| 90 | + IconSpinner, | |
| 91 | + IconTool, | |
| 92 | +} from "./components/icons"; | |
| 93 | +export { | |
| 94 | + EmptyState, | |
| 95 | + LoadableBlock, | |
| 96 | +} from "./components/loadable"; | |
| 97 | +export { | |
| 98 | + Markdown, | |
| 99 | +} from "./components/markdown"; | |
| 100 | +export { | |
| 101 | + SourceToolExplorer, | |
| 102 | + type SourceToolExplorerSearch, | |
| 103 | + parseSourceToolExplorerSearch, | |
| 104 | +} from "./components/source-tool-explorer"; | |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
| @@ -59,6 +59,7 @@ export type FrontendSourceTypeDefinition = { · 58 unmodified lines | ||
| 59 | 59 | kind: string; |
| 60 | 60 | displayName: string; |
| 61 | 61 | description?: string; |
| 62 | + getIconUrl?: (source: Source) => string | null; | |
| 62 | 63 | renderAddPage: ComponentType; |
| 63 | 64 | renderEditPage?: ComponentType<{ source: Source }>; |
| 64 | 65 | renderDetailPage?: ComponentType<{ source: Source }>; |
| @@ -1,104 +1 @@ | ||
| 1 | −export type { | |
| 2 | − ExecutorFrontendPlugin, | |
| 3 | − ExecutorPluginNavigation, | |
| 4 | − ExecutorPluginRouteContextValue, | |
| 5 | − FrontendPluginRouteDefinition, | |
| 6 | − FrontendPluginRouteParams, | |
| 7 | − FrontendPluginRouteSearch, | |
| 8 | − FrontendSourceDetailRouteDefinition, | |
| 9 | − FrontendSourceTypeDefinition, | |
| 10 | − SourcePluginNavigation, | |
| 11 | − SourcePluginRouteContextValue, | |
| 12 | − SourcePluginRouteParams, | |
| 13 | − SourcePluginRouteSearch, | |
| 14 | −} from "./types"; | |
| 15 | − | |
| 16 | −export { | |
| 17 | − createExecutorPluginPaths, | |
| 18 | − createSourcePluginPaths, | |
| 19 | − executorPluginBasePath, | |
| 20 | − executorPluginRoutePath, | |
| 21 | − executorPluginRoutePattern, | |
| 22 | − normalizeExecutorPluginPath, | |
| 23 | − normalizeSourcePluginPath, | |
| 24 | − sourcePluginAddPath, | |
| 25 | − sourcePluginChildPath, | |
| 26 | − sourcePluginChildPattern, | |
| 27 | − sourcePluginDetailPath, | |
| 28 | − sourcePluginDetailPattern, | |
| 29 | − sourcePluginEditPath, | |
| 30 | − sourcePluginEditPattern, | |
| 31 | − sourcePluginsIndexPath, | |
| 32 | − type ExecutorPluginPaths, | |
| 33 | − type SourcePluginPaths, | |
| 34 | −} from "./paths"; | |
| 35 | − | |
| 36 | −export { | |
| 37 | − defineExecutorFrontendPlugin, | |
| 38 | − defineFrontendPluginRoute, | |
| 39 | − defineFrontendSourceType, | |
| 40 | − registerExecutorFrontendPlugins, | |
| 41 | − type RegisteredFrontendPluginRoute, | |
| 42 | − type RegisteredFrontendSourceType, | |
| 43 | −} from "./registry"; | |
| 44 | − | |
| 45 | −export { | |
| 46 | − ExecutorPluginRouteProvider, | |
| 47 | − useExecutorPlugin, | |
| 48 | − useExecutorPluginNavigation, | |
| 49 | − useExecutorPluginPaths, | |
| 50 | − useExecutorPluginRoute, | |
| 51 | − useExecutorPluginRouteDefinition, | |
| 52 | − useExecutorPluginRouteParams, | |
| 53 | − useExecutorPluginSearch, | |
| 54 | −} from "./plugin-route-context"; | |
| 55 | − | |
| 56 | −export { | |
| 57 | − SourcePluginRouteProvider, | |
| 58 | − useSourcePlugin, | |
| 59 | − useSourcePluginDefinition, | |
| 60 | − useSourcePluginNavigation, | |
| 61 | − useSourcePluginPaths, | |
| 62 | − useSourcePluginRoute, | |
| 63 | − useSourcePluginRouteParams, | |
| 64 | − useSourcePluginSearch, | |
| 65 | −} from "./route-context"; | |
| 66 | − | |
| 67 | −export { | |
| 68 | − cn, | |
| 69 | −} from "./lib/cn"; | |
| 70 | − | |
| 71 | −export { | |
| 72 | − Badge, | |
| 73 | − MethodBadge, | |
| 74 | −} from "./components/badge"; | |
| 75 | −export { | |
| 76 | − CodeBlock, | |
| 77 | −} from "./components/code-block"; | |
| 78 | −export { | |
| 79 | − DocumentPanel, | |
| 80 | −} from "./components/document-panel"; | |
| 81 | −export { | |
| 82 | − IconCheck, | |
| 83 | − IconChevron, | |
| 84 | − IconClose, | |
| 85 | − IconCopy, | |
| 86 | − IconEmpty, | |
| 87 | − IconFolder, | |
| 88 | − IconPencil, | |
| 89 | − IconSearch, | |
| 90 | − IconSpinner, | |
| 91 | − IconTool, | |
| 92 | −} from "./components/icons"; | |
| 93 | −export { | |
| 94 | − EmptyState, | |
| 95 | − LoadableBlock, | |
| 96 | −} from "./components/loadable"; | |
| 97 | −export { | |
| 98 | − Markdown, | |
| 99 | −} from "./components/markdown"; | |
| 100 | −export { | |
| 101 | − SourceToolExplorer, | |
| 102 | − type SourceToolExplorerSearch, | |
| 103 | − parseSourceToolExplorerSearch, | |
| 104 | −} from "./components/source-tool-explorer"; | |
| 1 | +export * from "../plugins/index"; | |
| @@ -25,6 +25,9 @@ import * as Effect from "effect/Effect"; · 24 unmodified lines | ||
| 25 | 25 | import * as Schema from "effect/Schema"; |
| 26 | 26 | |
| 27 | 27 | import { |
| 28 | + GOOGLE_DISCOVERY_EXECUTOR_KEY, | |
| 29 | + GOOGLE_DISCOVERY_OAUTH_STORAGE_PREFIX, | |
| 30 | + GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 28 | 31 | GoogleDiscoveryConnectInputSchema, |
| 29 | 32 | GoogleDiscoveryOAuthPopupResultSchema, |
| 30 | 33 | GoogleDiscoverySourceConfigPayloadSchema, |
| @@ -39,7 +42,7 @@ import { · 8 unmodified lines | ||
| 39 | 42 | } from "@executor/plugin-google-discovery-shared"; |
| 40 | 43 | |
| 41 | 44 | type GoogleDiscoveryExecutorExtension = { |
| 42 | − googleDiscovery: { | |
| 45 | + [GOOGLE_DISCOVERY_EXECUTOR_KEY]: { | |
| 43 | 46 | createSource: ( |
| 44 | 47 | input: GoogleDiscoveryConnectInput, |
| 45 | 48 | ) => Effect.Effect<Source, Error>; |
| @@ -77,7 +80,7 @@ const callbackParamsSchema = Schema.Struct({ · 31 unmodified lines | ||
| 77 | 80 | error_description: Schema.optional(Schema.String), |
| 78 | 81 | }); |
| 79 | 82 | |
| 80 | −export const GoogleDiscoveryHttpGroup = HttpApiGroup.make("googleDiscovery") | |
| 83 | +export const GoogleDiscoveryHttpGroup = HttpApiGroup.make(GOOGLE_DISCOVERY_PLUGIN_KEY) | |
| 81 | 84 | .add( |
| 82 | 85 | HttpApiEndpoint.post("createSource")`/workspaces/${workspaceIdParam}/plugins/google-discovery/sources` |
| 83 | 86 | .setPayload(GoogleDiscoveryConnectInputSchema) |
| @@ -129,7 +132,7 @@ export const GoogleDiscoveryHttpGroup = HttpApiGroup.make("googleDiscovery") · 45 unmodified lines | ||
| 129 | 132 | .prefix("/v1"); |
| 130 | 133 | |
| 131 | 134 | export const googleDiscoveryHttpApiExtension = { |
| 132 | − key: "googleDiscovery", | |
| 135 | + key: GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 133 | 136 | group: GoogleDiscoveryHttpGroup, |
| 134 | 137 | } satisfies ExecutorHttpApiExtension<typeof GoogleDiscoveryHttpGroup>; |
| 135 | 138 | |
| @@ -199,7 +202,7 @@ const popupDocument = (payload: GoogleDiscoveryOAuthPopupResult): string => { · 63 unmodified lines | ||
| 199 | 202 | (() => { |
| 200 | 203 | const payload = ${serialized}; |
| 201 | 204 | try { |
| 202 | − window.localStorage.setItem("executor:google-discovery-oauth:" + (payload.ok ? payload.sessionId : "failed"), JSON.stringify(payload)); | |
| 205 | + window.localStorage.setItem("${GOOGLE_DISCOVERY_OAUTH_STORAGE_PREFIX}" + (payload.ok ? payload.sessionId : "failed"), JSON.stringify(payload)); | |
| 203 | 206 | } catch {} |
| 204 | 207 | try { |
| 205 | 208 | if (window.opener) { |
| @@ -218,17 +221,19 @@ export const googleDiscoveryHttpPlugin = (): ExecutorHttpPlugin< · 12 unmodified lines | ||
| 218 | 221 | typeof GoogleDiscoveryHttpGroup, |
| 219 | 222 | GoogleDiscoveryExecutorExtension |
| 220 | 223 | > => ({ |
| 221 | − key: "googleDiscovery", | |
| 224 | + key: GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 222 | 225 | group: GoogleDiscoveryHttpGroup, |
| 223 | 226 | build: ({ executor }) => |
| 224 | − HttpApiBuilder.group(GoogleDiscoveryHttpApi, "googleDiscovery", (handlers) => | |
| 227 | + HttpApiBuilder.group(GoogleDiscoveryHttpApi, GOOGLE_DISCOVERY_PLUGIN_KEY, (handlers) => | |
| 225 | 228 | handlers |
| 226 | 229 | .handle("createSource", ({ path, payload }) => |
| 227 | 230 | resolveRequestedLocalWorkspace( |
| 228 | 231 | "googleDiscovery.createSource", |
| 229 | 232 | path.workspaceId, |
| 230 | 233 | ).pipe( |
| 231 | − Effect.flatMap(() => executor.googleDiscovery.createSource(payload)), | |
| 234 | + Effect.flatMap(() => | |
| 235 | + executor[GOOGLE_DISCOVERY_EXECUTOR_KEY].createSource(payload) | |
| 236 | + ), | |
| 232 | 237 | Effect.mapError((cause) => |
| 233 | 238 | toStorageError("googleDiscovery.createSource", cause) |
| 234 | 239 | ), |
| @@ -240,7 +245,9 @@ export const googleDiscoveryHttpPlugin = (): ExecutorHttpPlugin< · 5 unmodified lines | ||
| 240 | 245 | path.workspaceId, |
| 241 | 246 | ).pipe( |
| 242 | 247 | Effect.flatMap(() => |
| 243 | − executor.googleDiscovery.getSourceConfig(path.sourceId) | |
| 248 | + executor[GOOGLE_DISCOVERY_EXECUTOR_KEY].getSourceConfig( | |
| 249 | + path.sourceId, | |
| 250 | + ) | |
| 244 | 251 | ), |
| 245 | 252 | Effect.mapError((cause) => |
| 246 | 253 | mapPluginStorageError("googleDiscovery.getSourceConfig", cause) |
| @@ -253,7 +260,7 @@ export const googleDiscoveryHttpPlugin = (): ExecutorHttpPlugin< · 6 unmodified lines | ||
| 253 | 260 | path.workspaceId, |
| 254 | 261 | ).pipe( |
| 255 | 262 | Effect.flatMap(() => |
| 256 | − executor.googleDiscovery.updateSource({ | |
| 263 | + executor[GOOGLE_DISCOVERY_EXECUTOR_KEY].updateSource({ | |
| 257 | 264 | sourceId: path.sourceId, |
| 258 | 265 | config: payload, |
| 259 | 266 | }) |
| @@ -269,7 +276,9 @@ export const googleDiscoveryHttpPlugin = (): ExecutorHttpPlugin< · 9 unmodified lines | ||
| 269 | 276 | path.workspaceId, |
| 270 | 277 | ).pipe( |
| 271 | 278 | Effect.flatMap(() => |
| 272 | − executor.googleDiscovery.removeSource(path.sourceId) | |
| 279 | + executor[GOOGLE_DISCOVERY_EXECUTOR_KEY].removeSource( | |
| 280 | + path.sourceId, | |
| 281 | + ) | |
| 273 | 282 | ), |
| 274 | 283 | Effect.map((removed) => ({ removed })), |
| 275 | 284 | Effect.mapError((cause) => |
| @@ -282,14 +291,16 @@ export const googleDiscoveryHttpPlugin = (): ExecutorHttpPlugin< · 6 unmodified lines | ||
| 282 | 291 | "googleDiscovery.startOAuth", |
| 283 | 292 | path.workspaceId, |
| 284 | 293 | ).pipe( |
| 285 | − Effect.flatMap(() => executor.googleDiscovery.startOAuth(payload)), | |
| 294 | + Effect.flatMap(() => | |
| 295 | + executor[GOOGLE_DISCOVERY_EXECUTOR_KEY].startOAuth(payload) | |
| 296 | + ), | |
| 286 | 297 | Effect.mapError((cause) => |
| 287 | 298 | toStorageError("googleDiscovery.startOAuth", cause) |
| 288 | 299 | ), |
| 289 | 300 | ) |
| 290 | 301 | ) |
| 291 | 302 | .handle("oauthCallback", ({ urlParams }) => |
| 292 | − executor.googleDiscovery.completeOAuth({ | |
| 303 | + executor[GOOGLE_DISCOVERY_EXECUTOR_KEY].completeOAuth({ | |
| 293 | 304 | state: urlParams.state, |
| 294 | 305 | code: urlParams.code, |
| 295 | 306 | error: urlParams.error, |
| @@ -24,6 +24,10 @@ import { · 23 unmodified lines | ||
| 24 | 24 | googleDiscoveryHttpApiExtension, |
| 25 | 25 | } from "@executor/plugin-google-discovery-http"; |
| 26 | 26 | import { |
| 27 | + GOOGLE_DISCOVERY_OAUTH_CALLBACK_PATH, | |
| 28 | + GOOGLE_DISCOVERY_OAUTH_STORAGE_PREFIX, | |
| 29 | + GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 30 | + GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 27 | 31 | defaultGoogleDiscoveryUrl, |
| 28 | 32 | type GoogleDiscoveryConnectInput, |
| 29 | 33 | type GoogleDiscoveryConnectionAuth, |
| @@ -31,9 +35,47 @@ import { · 1 unmodified line | ||
| 31 | 35 | type GoogleDiscoveryStartOAuthInput, |
| 32 | 36 | } from "@executor/plugin-google-discovery-shared"; |
| 33 | 37 | |
| 34 | −const OAUTH_STORAGE_PREFIX = "executor:google-discovery-oauth:"; | |
| 35 | 38 | const OAUTH_TIMEOUT_MS = 2 * 60_000; |
| 36 | 39 | |
| 40 | +const GOOGLE_DISCOVERY_SERVICE_ICONS: Record<string, string> = { | |
| 41 | + admin: "https://ssl.gstatic.com/images/branding/product/2x/admin_2020q4_48dp.png", | |
| 42 | + bigquery: "https://ssl.gstatic.com/bqui1/favicon.ico", | |
| 43 | + calendar: "https://ssl.gstatic.com/calendar/images/dynamiclogo_2020q4/calendar_31_2x.png", | |
| 44 | + chat: "https://ssl.gstatic.com/chat/favicon/favicon_v2.ico", | |
| 45 | + classroom: "https://ssl.gstatic.com/classroom/favicon.png", | |
| 46 | + cloudresourcemanager: "https://www.gstatic.com/devrel-devsite/prod/v0e0f589edd85502a40d78d7d0825db8ea5ef3b99b1571571945f0f3f764ff61b/cloud/images/favicons/onecloud/favicon.ico", | |
| 47 | + docs: "https://ssl.gstatic.com/docs/documents/images/kix-favicon7.ico", | |
| 48 | + drive: "https://ssl.gstatic.com/images/branding/product/2x/drive_2020q4_48dp.png", | |
| 49 | + forms: "https://ssl.gstatic.com/docs/forms/device_home/android_192.png", | |
| 50 | + gmail: "https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico", | |
| 51 | + keep: "https://ssl.gstatic.com/keep/icon_2020q4v2_128.png", | |
| 52 | + people: "https://ssl.gstatic.com/images/branding/product/2x/contacts_2022_48dp.png", | |
| 53 | + script: "https://ssl.gstatic.com/script/images/favicon.ico", | |
| 54 | + searchconsole: "https://ssl.gstatic.com/search-console/scfe/search_console-64.png", | |
| 55 | + sheets: "https://ssl.gstatic.com/docs/spreadsheets/favicon3.ico", | |
| 56 | + slides: "https://ssl.gstatic.com/docs/presentations/images/favicon5.ico", | |
| 57 | + tasks: "https://ssl.gstatic.com/tasks/images/favicon.ico", | |
| 58 | + youtube: "https://www.youtube.com/s/desktop/a94e1818/img/favicon_32x32.png", | |
| 59 | +}; | |
| 60 | + | |
| 61 | +const getGoogleDiscoveryServiceKey = ( | |
| 62 | + source: Pick<Source, "namespace">, | |
| 63 | +): string | null => { | |
| 64 | + const namespace = source.namespace?.trim(); | |
| 65 | + if (!namespace || !namespace.startsWith("google.")) { | |
| 66 | + return null; | |
| 67 | + } | |
| 68 | + | |
| 69 | + return namespace.slice("google.".length).replaceAll(".", ""); | |
| 70 | +}; | |
| 71 | + | |
| 72 | +const getGoogleDiscoveryIconUrl = ( | |
| 73 | + source: Pick<Source, "namespace">, | |
| 74 | +): string | null => { | |
| 75 | + const serviceKey = getGoogleDiscoveryServiceKey(source); | |
| 76 | + return serviceKey ? GOOGLE_DISCOVERY_SERVICE_ICONS[serviceKey] ?? null : null; | |
| 77 | +}; | |
| 78 | + | |
| 37 | 79 | const getGoogleDiscoveryHttpClient = |
| 38 | 80 | defineExecutorPluginHttpApiClient<"GoogleDiscoveryReactHttpClient">()( |
| 39 | 81 | "GoogleDiscoveryReactHttpClient", |
| @@ -105,7 +147,7 @@ const waitForOauthPopupResult = async ( · 65 unmodified lines | ||
| 105 | 147 | sessionId: string, |
| 106 | 148 | ): Promise<GoogleDiscoveryOAuthPopupResult> => |
| 107 | 149 | new Promise((resolve, reject) => { |
| 108 | − const storageKey = `${OAUTH_STORAGE_PREFIX}${sessionId}`; | |
| 150 | + const storageKey = `${GOOGLE_DISCOVERY_OAUTH_STORAGE_PREFIX}${sessionId}`; | |
| 109 | 151 | const startedAt = Date.now(); |
| 110 | 152 | |
| 111 | 153 | const cleanup = () => { |
| @@ -168,7 +210,7 @@ function GoogleDiscoverySourceForm(props: { · 56 unmodified lines | ||
| 168 | 210 | const client = getGoogleDiscoveryHttpClient(); |
| 169 | 211 | const secrets = useSecrets(); |
| 170 | 212 | const startOAuth = useAtomSet( |
| 171 | − client.mutation("googleDiscovery", "startOAuth"), | |
| 213 | + client.mutation(GOOGLE_DISCOVERY_PLUGIN_KEY, "startOAuth"), | |
| 172 | 214 | { mode: "promise" }, |
| 173 | 215 | ); |
| 174 | 216 | const submitMutation = useExecutorMutation<GoogleDiscoveryConnectInput, void>(props.onSubmit); |
| @@ -219,7 +261,7 @@ function GoogleDiscoverySourceForm(props: { · 44 unmodified lines | ||
| 219 | 261 | : null, |
| 220 | 262 | clientAuthentication: clientSecretRef ? "client_secret_post" : "none", |
| 221 | 263 | redirectUrl: new URL( |
| 222 | − "/v1/plugins/google-discovery/oauth/callback", | |
| 264 | + GOOGLE_DISCOVERY_OAUTH_CALLBACK_PATH, | |
| 223 | 265 | window.location.origin, |
| 224 | 266 | ).toString(), |
| 225 | 267 | }; |
| @@ -492,7 +534,7 @@ function GoogleDiscoveryAddPage() { · 266 unmodified lines | ||
| 492 | 534 | const installation = useLocalInstallation(); |
| 493 | 535 | const client = getGoogleDiscoveryHttpClient(); |
| 494 | 536 | const createSource = useAtomSet( |
| 495 | − client.mutation("googleDiscovery", "createSource"), | |
| 537 | + client.mutation(GOOGLE_DISCOVERY_PLUGIN_KEY, "createSource"), | |
| 496 | 538 | { mode: "promise" }, |
| 497 | 539 | ); |
| 498 | 540 | |
| @@ -533,7 +575,7 @@ function GoogleDiscoveryEditPage(props: { · 34 unmodified lines | ||
| 533 | 575 | const client = getGoogleDiscoveryHttpClient(); |
| 534 | 576 | const configResult = useAtomValue( |
| 535 | 577 | installation.status === "ready" |
| 536 | − ? client.query("googleDiscovery", "getSourceConfig", { | |
| 578 | + ? client.query(GOOGLE_DISCOVERY_PLUGIN_KEY, "getSourceConfig", { | |
| 537 | 579 | path: { |
| 538 | 580 | workspaceId: installation.data.scopeId, |
| 539 | 581 | sourceId: props.source.id, |
| @@ -548,7 +590,7 @@ function GoogleDiscoveryEditPage(props: { · 8 unmodified lines | ||
| 548 | 590 | }) as never, |
| 549 | 591 | ); |
| 550 | 592 | const updateSource = useAtomSet( |
| 551 | − client.mutation("googleDiscovery", "updateSource"), | |
| 593 | + client.mutation(GOOGLE_DISCOVERY_PLUGIN_KEY, "updateSource"), | |
| 552 | 594 | { mode: "promise" }, |
| 553 | 595 | ); |
| 554 | 596 | |
| @@ -608,12 +650,12 @@ function GoogleDiscoveryDetailPage(props: { · 53 unmodified lines | ||
| 608 | 650 | const installation = useLocalInstallation(); |
| 609 | 651 | const client = getGoogleDiscoveryHttpClient(); |
| 610 | 652 | const removeSource = useAtomSet( |
| 611 | − client.mutation("googleDiscovery", "removeSource"), | |
| 653 | + client.mutation(GOOGLE_DISCOVERY_PLUGIN_KEY, "removeSource"), | |
| 612 | 654 | { mode: "promise" }, |
| 613 | 655 | ); |
| 614 | 656 | const configResult = useAtomValue( |
| 615 | 657 | installation.status === "ready" |
| 616 | − ? client.query("googleDiscovery", "getSourceConfig", { | |
| 658 | + ? client.query(GOOGLE_DISCOVERY_PLUGIN_KEY, "getSourceConfig", { | |
| 617 | 659 | path: { |
| 618 | 660 | workspaceId: installation.data.scopeId, |
| 619 | 661 | sourceId: props.source.id, |
| @@ -710,16 +752,17 @@ function GoogleDiscoveryDetailPage(props: { · 90 unmodified lines | ||
| 710 | 752 | } |
| 711 | 753 | |
| 712 | 754 | const googleDiscoverySourceType = defineFrontendSourceType({ |
| 713 | − key: "google-discovery", | |
| 714 | − kind: "google_discovery", | |
| 755 | + key: GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 756 | + kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 715 | 757 | displayName: "Google Discovery", |
| 716 | 758 | description: "Import Google APIs from discovery documents with plugin-owned OAuth.", |
| 759 | + getIconUrl: getGoogleDiscoveryIconUrl, | |
| 717 | 760 | renderAddPage: GoogleDiscoveryAddPage, |
| 718 | 761 | renderEditPage: GoogleDiscoveryEditPage, |
| 719 | 762 | renderDetailPage: GoogleDiscoveryDetailPage, |
| 720 | 763 | }); |
| 721 | 764 | |
| 722 | 765 | export const GoogleDiscoveryReactPlugin = defineExecutorFrontendPlugin({ |
| 723 | − key: "google-discovery", | |
| 766 | + key: GOOGLE_DISCOVERY_PLUGIN_KEY, | |
| 724 | 767 | sourceTypes: [googleDiscoverySourceType], |
| 725 | 768 | }); |
| @@ -38,6 +38,7 @@ import { · 37 unmodified lines | ||
| 38 | 38 | stableHash, |
| 39 | 39 | toolPathSegments, |
| 40 | 40 | } from "@executor/source-core"; |
| 41 | +import { GOOGLE_DISCOVERY_SOURCE_KIND } from "@executor/plugin-google-discovery-shared"; | |
| 41 | 42 | |
| 42 | 43 | import type { GoogleDiscoveryToolProviderData } from "./types"; |
| 43 | 44 | |
| @@ -284,7 +285,7 @@ const createHttpCapabilityFromGoogleDiscovery = (input: { · 240 unmodified lines | ||
| 284 | 285 | id: executableId, |
| 285 | 286 | capabilityId, |
| 286 | 287 | scopeId: input.serviceScopeId, |
| 287 | − pluginKey: "google_discovery", | |
| 288 | + pluginKey: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 288 | 289 | bindingVersion: EXECUTABLE_BINDING_VERSION, |
| 289 | 290 | binding: input.operation.providerData, |
| 290 | 291 | projection: { |
| @@ -384,7 +385,7 @@ export const createGoogleDiscoveryCatalogSnapshot = (input: { · 93 unmodified lines | ||
| 384 | 385 | createCatalogSnapshotV1FromFragments({ |
| 385 | 386 | import: createCatalogImportMetadata({ |
| 386 | 387 | source: input.source, |
| 387 | − pluginKey: "google_discovery", | |
| 388 | + pluginKey: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 388 | 389 | }), |
| 389 | 390 | fragments: [createGoogleDiscoveryCatalogFragment(input)], |
| 390 | 391 | }); |
| @@ -20,6 +20,8 @@ import { · 19 unmodified lines | ||
| 20 | 20 | provideExecutorRuntime, |
| 21 | 21 | } from "@executor/platform-sdk/runtime"; |
| 22 | 22 | import { |
| 23 | + GOOGLE_DISCOVERY_EXECUTOR_KEY, | |
| 24 | + GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 23 | 25 | GoogleDiscoveryConnectionAuthSchema, |
| 24 | 26 | GoogleDiscoveryOAuthSessionSchema, |
| 25 | 27 | defaultGoogleDiscoveryUrl, |
| @@ -115,7 +117,7 @@ export type GoogleDiscoverySdk = { · 89 unmodified lines | ||
| 115 | 117 | }; |
| 116 | 118 | |
| 117 | 119 | const GoogleDiscoveryExecutorAddInputSchema = Schema.Struct({ |
| 118 | − kind: Schema.Literal("google_discovery"), | |
| 120 | + kind: Schema.Literal(GOOGLE_DISCOVERY_SOURCE_KIND), | |
| 119 | 121 | name: Schema.String, |
| 120 | 122 | service: Schema.String, |
| 121 | 123 | version: Schema.String, |
| @@ -476,7 +478,7 @@ const createGoogleDiscoverySourceSdk = ( · 354 unmodified lines | ||
| 476 | 478 | getSourceConfig: (sourceId: Source["id"]) => |
| 477 | 479 | Effect.gen(function* () { |
| 478 | 480 | const source = yield* host.sources.get(sourceId); |
| 479 | − if (source.kind !== "google_discovery") { | |
| 481 | + if (source.kind !== GOOGLE_DISCOVERY_SOURCE_KIND) { | |
| 480 | 482 | return yield* Effect.fail( |
| 481 | 483 | new Error(`Source ${sourceId} is not a Google Discovery source.`), |
| 482 | 484 | ); |
| @@ -500,7 +502,7 @@ const createGoogleDiscoverySourceSdk = ( · 17 unmodified lines | ||
| 500 | 502 | const createdSource = yield* host.sources.create({ |
| 501 | 503 | source: { |
| 502 | 504 | name: input.name.trim(), |
| 503 | − kind: "google_discovery", | |
| 505 | + kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 504 | 506 | status: "connected", |
| 505 | 507 | enabled: true, |
| 506 | 508 | namespace: deriveGoogleDiscoveryNamespace(input.service), |
| @@ -518,7 +520,7 @@ const createGoogleDiscoverySourceSdk = ( · 11 unmodified lines | ||
| 518 | 520 | updateSource: (input: GoogleDiscoveryUpdateSourceInput) => |
| 519 | 521 | Effect.gen(function* () { |
| 520 | 522 | const source = yield* host.sources.get(input.sourceId as Source["id"]); |
| 521 | − if (source.kind !== "google_discovery") { | |
| 523 | + if (source.kind !== GOOGLE_DISCOVERY_SOURCE_KIND) { | |
| 522 | 524 | return yield* Effect.fail( |
| 523 | 525 | new Error(`Source ${input.sourceId} is not a Google Discovery source.`), |
| 524 | 526 | ); |
| @@ -542,7 +544,7 @@ const createGoogleDiscoverySourceSdk = ( · 17 unmodified lines | ||
| 542 | 544 | removeSource: (sourceId: Source["id"]) => |
| 543 | 545 | Effect.gen(function* () { |
| 544 | 546 | const source = yield* host.sources.get(sourceId); |
| 545 | − if (source.kind !== "google_discovery") { | |
| 547 | + if (source.kind !== GOOGLE_DISCOVERY_SOURCE_KIND) { | |
| 546 | 548 | return yield* Effect.fail( |
| 547 | 549 | new Error(`Source ${sourceId} is not a Google Discovery source.`), |
| 548 | 550 | ); |
| @@ -577,7 +579,7 @@ const googleDiscoverySourceConnector = ( · 28 unmodified lines | ||
| 577 | 579 | oauthSessions: GoogleDiscoveryOAuthSessionStorage; |
| 578 | 580 | }, |
| 579 | 581 | ): ExecutorSourceConnector<GoogleDiscoveryExecutorAddInput> => ({ |
| 580 | − kind: "google_discovery", | |
| 582 | + kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 581 | 583 | displayName: "Google Discovery", |
| 582 | 584 | inputSchema: GoogleDiscoveryExecutorAddInputSchema, |
| 583 | 585 | inputSignatureWidth: 320, |
| @@ -592,11 +594,11 @@ const googleDiscoverySourceConnector = ( · 8 unmodified lines | ||
| 592 | 594 | const createGoogleDiscoverySourceRuntime = (options: { |
| 593 | 595 | storage: GoogleDiscoverySourceStorage; |
| 594 | 596 | }): SourcePluginRuntime => ({ |
| 595 | − kind: "google_discovery", | |
| 597 | + kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 596 | 598 | displayName: "Google Discovery", |
| 597 | 599 | catalogKind: "imported", |
| 598 | 600 | catalogIdentity: ({ source }) => ({ |
| 599 | − kind: "google_discovery", | |
| 601 | + kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 600 | 602 | sourceId: source.id, |
| 601 | 603 | }), |
| 602 | 604 | getIrModel: ({ source }) => |
| @@ -613,7 +615,7 @@ const createGoogleDiscoverySourceRuntime = (options: { · 10 unmodified lines | ||
| 613 | 615 | importMetadata: { |
| 614 | 616 | ...createCatalogImportMetadata({ |
| 615 | 617 | source, |
| 616 | − pluginKey: "google_discovery", | |
| 618 | + pluginKey: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 617 | 619 | }), |
| 618 | 620 | importerVersion: "ir.v1.google_discovery", |
| 619 | 621 | sourceConfigHash: "missing", |
| @@ -647,7 +649,7 @@ const createGoogleDiscoverySourceRuntime = (options: { · 27 unmodified lines | ||
| 647 | 649 | source, |
| 648 | 650 | documents: [ |
| 649 | 651 | { |
| 650 | − documentKind: "google_discovery", | |
| 652 | + documentKind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 651 | 653 | documentKey: stored.discoveryUrl, |
| 652 | 654 | contentText: document, |
| 653 | 655 | fetchedAt: now, |
| @@ -658,7 +660,7 @@ const createGoogleDiscoverySourceRuntime = (options: { · 4 unmodified lines | ||
| 658 | 660 | importMetadata: { |
| 659 | 661 | ...createCatalogImportMetadata({ |
| 660 | 662 | source, |
| 661 | − pluginKey: "google_discovery", | |
| 663 | + pluginKey: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 662 | 664 | }), |
| 663 | 665 | importerVersion: "ir.v1.google_discovery", |
| 664 | 666 | }, |
| @@ -753,8 +755,8 @@ const createGoogleDiscoverySourceRuntime = (options: { · 88 unmodified lines | ||
| 753 | 755 | export const googleDiscoverySdkPlugin = (options: { |
| 754 | 756 | storage: GoogleDiscoverySourceStorage; |
| 755 | 757 | oauthSessions: GoogleDiscoveryOAuthSessionStorage; |
| 756 | −}): ExecutorSdkPlugin<"googleDiscovery", GoogleDiscoverySdk> => ({ | |
| 757 | − key: "googleDiscovery", | |
| 758 | +}): ExecutorSdkPlugin<typeof GOOGLE_DISCOVERY_EXECUTOR_KEY, GoogleDiscoverySdk> => ({ | |
| 759 | + key: GOOGLE_DISCOVERY_EXECUTOR_KEY, | |
| 758 | 760 | sources: [createGoogleDiscoverySourceRuntime(options)], |
| 759 | 761 | sourceConnectors: [googleDiscoverySourceConnector(options)], |
| 760 | 762 | extendExecutor: ({ host, executor }) => { |
| @@ -18,6 +18,7 @@ import { sourceCoreEffectError } from "@executor/source-core"; · 17 unmodified lines | ||
| 18 | 18 | import * as Effect from "effect/Effect"; |
| 19 | 19 | import * as Layer from "effect/Layer"; |
| 20 | 20 | import * as Schema from "effect/Schema"; |
| 21 | +import { GOOGLE_DISCOVERY_SOURCE_KIND } from "@executor/plugin-google-discovery-shared"; | |
| 21 | 22 | |
| 22 | 23 | import type { |
| 23 | 24 | GoogleDiscoveryManifestMethod, |
| @@ -43,7 +44,7 @@ export const googleDiscoveryProviderDataFromDefinition = ( · 19 unmodified lines | ||
| 43 | 44 | definition: GoogleDiscoveryManifestMethod; |
| 44 | 45 | }, |
| 45 | 46 | ): typeof GoogleDiscoveryToolProviderDataSchema.Type => ({ |
| 46 | − kind: "google_discovery", | |
| 47 | + kind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 47 | 48 | service: input.service, |
| 48 | 49 | version: input.version, |
| 49 | 50 | toolId: input.definition.toolId, |
| @@ -467,7 +468,7 @@ export const createGoogleDiscoveryToolFromDefinition = ( · 417 unmodified lines | ||
| 467 | 468 | : {}), |
| 468 | 469 | }, |
| 469 | 470 | sourceKey: input.sourceKey, |
| 470 | − pluginKind: "google_discovery", | |
| 471 | + pluginKind: GOOGLE_DISCOVERY_SOURCE_KIND, | |
| 471 | 472 | pluginData: providerData, |
| 472 | 473 | }; |
| 473 | 474 | |
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | import { Schema } from "effect"; |
| 2 | +import { GOOGLE_DISCOVERY_SOURCE_KIND } from "@executor/plugin-google-discovery-shared"; | |
| 2 | 3 | |
| 3 | 4 | export const GOOGLE_DISCOVERY_HTTP_METHODS = [ |
| 4 | 5 | "get", |
| @@ -52,7 +53,7 @@ export const GoogleDiscoveryInvocationPayloadSchema = Schema.Struct({ · 47 unmodified lines | ||
| 52 | 53 | }); |
| 53 | 54 | |
| 54 | 55 | export const GoogleDiscoveryToolProviderDataSchema = Schema.Struct({ |
| 55 | − kind: Schema.Literal("google_discovery"), | |
| 56 | + kind: Schema.Literal(GOOGLE_DISCOVERY_SOURCE_KIND), | |
| 56 | 57 | service: Schema.String, |
| 57 | 58 | version: Schema.String, |
| 58 | 59 | toolId: Schema.String, |
| @@ -5,6 +5,14 @@ import { · 4 unmodified lines | ||
| 5 | 5 | StringMapSchema, |
| 6 | 6 | } from "@executor/platform-sdk/schema"; |
| 7 | 7 | |
| 8 | +export const GOOGLE_DISCOVERY_SOURCE_KIND = "google_discovery" as const; | |
| 9 | +export const GOOGLE_DISCOVERY_PLUGIN_KEY = "google-discovery" as const; | |
| 10 | +export const GOOGLE_DISCOVERY_EXECUTOR_KEY = "googleDiscovery" as const; | |
| 11 | +export const GOOGLE_DISCOVERY_OAUTH_STORAGE_PREFIX = | |
| 12 | + "executor:google-discovery-oauth:" as const; | |
| 13 | +export const GOOGLE_DISCOVERY_OAUTH_CALLBACK_PATH = | |
| 14 | + `/v1/plugins/${GOOGLE_DISCOVERY_PLUGIN_KEY}/oauth/callback` as const; | |
| 15 | + | |
| 8 | 16 | export const GoogleDiscoveryOAuthClientAuthenticationSchema = Schema.Literal( |
| 9 | 17 | "none", |
| 10 | 18 | "client_secret_post", |
| @@ -6,11 +6,11 @@ import { · 5 unmodified lines | ||
| 6 | 6 | type SourceDiscoveryProbeInput, |
| 7 | 7 | type SourceDiscoveryResult, |
| 8 | 8 | } from "@executor/source-core"; |
| 9 | −import { startMcpOAuthAuthorization } from "@executor/auth-mcp-oauth"; | |
| 10 | 9 | import * as Either from "effect/Either"; |
| 11 | 10 | import * as Effect from "effect/Effect"; |
| 12 | 11 | |
| 13 | 12 | import { createSdkMcpConnector } from "./connection"; |
| 13 | +import { startMcpOAuthAuthorization } from "./oauth"; | |
| 14 | 14 | import { discoverMcpToolsFromConnector } from "./tools"; |
| 15 | 15 | |
| 16 | 16 | export const detectMcpSource = ( |
| @@ -14,7 +14,7 @@ import type { · 13 unmodified lines | ||
| 14 | 14 | import { |
| 15 | 15 | exchangeMcpOAuthAuthorizationCode, |
| 16 | 16 | startMcpOAuthAuthorization, |
| 17 | −} from "@executor/auth-mcp-oauth"; | |
| 17 | +} from "./oauth"; | |
| 18 | 18 | import { |
| 19 | 19 | contentHash, |
| 20 | 20 | createCatalogImportMetadata, |
File renamed without changes.
| @@ -8,7 +8,8 @@ import type { · 7 unmodified lines | ||
| 8 | 8 | OAuthTokens, |
| 9 | 9 | } from "@modelcontextprotocol/sdk/shared/auth.js"; |
| 10 | 10 | import * as Effect from "effect/Effect"; |
| 11 | −import { mcpOAuthEffectError } from "./effect-errors"; | |
| 11 | + | |
| 12 | +import { mcpOAuthEffectError } from "./oauth-effect-errors"; | |
| 12 | 13 | |
| 13 | 14 | type JsonValue = |
| 14 | 15 | | string |
| @@ -123,7 +124,7 @@ export const startMcpOAuthAuthorization = (input: { · 108 unmodified lines | ||
| 123 | 124 | }); |
| 124 | 125 | |
| 125 | 126 | if (result !== "REDIRECT" || !captured.authorizationUrl || !captured.codeVerifier) { |
| 126 | − return yield* mcpOAuthEffectError("index", "OAuth flow did not produce an authorization redirect"); | |
| 127 | + return yield* mcpOAuthEffectError("oauth", "OAuth flow did not produce an authorization redirect"); | |
| 127 | 128 | } |
| 128 | 129 | |
| 129 | 130 | return { |
| @@ -196,7 +197,7 @@ export const exchangeMcpOAuthAuthorizationCode = (input: { · 66 unmodified lines | ||
| 196 | 197 | }); |
| 197 | 198 | |
| 198 | 199 | if (result !== "AUTHORIZED" || !captured.tokens) { |
| 199 | − return yield* mcpOAuthEffectError("index", "OAuth redirect did not complete MCP OAuth setup"); | |
| 200 | + return yield* mcpOAuthEffectError("oauth", "OAuth redirect did not complete MCP OAuth setup"); | |
| 200 | 201 | } |
| 201 | 202 | |
| 202 | 203 | return { |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | "typecheck": "bunx tsc --noEmit -p tsconfig.json" |
| 13 | 13 | }, |
| 14 | 14 | "dependencies": { |
| 15 | − "@executor/auth-mcp-oauth": "workspace:*", | |
| 16 | 15 | "@executor/codemode-core": "workspace:*", |
| 17 | 16 | "@executor/ir": "workspace:*", |
| 18 | 17 | "@executor/platform-sdk": "workspace:*", |