diff --git a/packages/plugins/google-discovery/src/api/group.ts b/packages/plugins/google-discovery/src/api/group.ts
index 632e0014ce..c6ddd4e156 100644
--- a/packages/plugins/google-discovery/src/api/group.ts
+++ b/packages/plugins/google-discovery/src/api/group.ts
@@ -2,9 +2,12 @@ import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform";
import { Schema } from "effect";
import { ScopeId } from "@executor/sdk";
+import { GoogleDiscoveryStoredSourceSchema } from "../sdk/stored-source";
+
export { HttpApiSchema };
const scopeIdParam = HttpApiSchema.param("scopeId", ScopeId);
+const namespaceParam = HttpApiSchema.param("namespace", Schema.String);
const AuthPayload = Schema.Union(
Schema.Struct({
@@ -125,4 +128,9 @@ export class GoogleDiscoveryGroup extends HttpApiGroup.make("googleDiscovery")
.addSuccess(HtmlResponse)
.addError(ApiError),
)
+ .add(
+ HttpApiEndpoint.get("getSource")`/scopes/${scopeIdParam}/google-discovery/sources/${namespaceParam}`
+ .addSuccess(Schema.NullOr(GoogleDiscoveryStoredSourceSchema))
+ .addError(ApiError),
+ )
{}
diff --git a/packages/plugins/google-discovery/src/api/handlers.ts b/packages/plugins/google-discovery/src/api/handlers.ts
index f846ace4b2..917517673e 100644
--- a/packages/plugins/google-discovery/src/api/handlers.ts
+++ b/packages/plugins/google-discovery/src/api/handlers.ts
@@ -105,6 +105,12 @@ export const GoogleDiscoveryHandlers = HttpApiBuilder.group(
});
}).pipe(Effect.orDie),
)
+ .handle("getSource", ({ path }) =>
+ Effect.gen(function* () {
+ const ext = yield* GoogleDiscoveryExtensionService;
+ return yield* ext.getSource(path.namespace);
+ }).pipe(Effect.orDie),
+ )
.handle("oauthCallback", ({ urlParams }) =>
Effect.gen(function* () {
const ext = yield* GoogleDiscoveryExtensionService;
diff --git a/packages/plugins/google-discovery/src/react/EditGoogleDiscoverySource.tsx b/packages/plugins/google-discovery/src/react/EditGoogleDiscoverySource.tsx
index 6ccf440d3a..eaf7dd6397 100644
--- a/packages/plugins/google-discovery/src/react/EditGoogleDiscoverySource.tsx
+++ b/packages/plugins/google-discovery/src/react/EditGoogleDiscoverySource.tsx
@@ -1,6 +1,10 @@
+import { useAtomValue, Result } from "@effect-atom/atom-react";
+import { useScope } from "@executor/react/api/scope-context";
import { Badge } from "@executor/react/components/badge";
import { Button } from "@executor/react/components/button";
+import { googleDiscoverySourceAtom } from "./atoms";
+
export default function EditGoogleDiscoverySource({
sourceId,
onSave,
@@ -8,6 +12,13 @@ export default function EditGoogleDiscoverySource({
readonly sourceId: string;
readonly onSave: () => void;
}) {
+ const scopeId = useScope();
+ const sourceResult = useAtomValue(googleDiscoverySourceAtom(scopeId, sourceId));
+
+ const source = Result.isSuccess(sourceResult) ? sourceResult.value : null;
+ const config = source?.config;
+ const authKind = config?.auth.kind ?? "none";
+
return (
@@ -15,21 +26,53 @@ export default function EditGoogleDiscoverySource({
Edit Google Discovery Source
- This source is managed from its Discovery document and can be refreshed from the source header.
+ View configuration for this Google API source. To change authentication,
+ remove and re-add the source with updated OAuth credentials.
- {sourceId}
+ {source?.name ?? sourceId}
+ {config?.discoveryUrl && (
+
+ {config.discoveryUrl}
+
+ )}
Google Discovery
+ {config && (
+
+
+
+
Service
+
+ {config.service}
+
+
+
+
Version
+
+ {config.version}
+
+
+
+
+
+
Authentication
+
+ {authKind === "oauth2" ? "OAuth 2.0" : authKind}
+
+
+
+ )}
+
Done
diff --git a/packages/plugins/google-discovery/src/react/atoms.ts b/packages/plugins/google-discovery/src/react/atoms.ts
index 0715eecee2..ea43b381e3 100644
--- a/packages/plugins/google-discovery/src/react/atoms.ts
+++ b/packages/plugins/google-discovery/src/react/atoms.ts
@@ -1,5 +1,15 @@
+import type { ScopeId } from "@executor/sdk";
import { GoogleDiscoveryClient } from "./client";
+export const googleDiscoverySourceAtom = (
+ scopeId: ScopeId,
+ namespace: string,
+) =>
+ GoogleDiscoveryClient.query("googleDiscovery", "getSource", {
+ path: { scopeId, namespace },
+ timeToLive: "15 seconds",
+ });
+
export const probeGoogleDiscovery = GoogleDiscoveryClient.mutation(
"googleDiscovery",
"probeDiscovery",
diff --git a/packages/plugins/google-discovery/src/sdk/binding-store.ts b/packages/plugins/google-discovery/src/sdk/binding-store.ts
index 1c4dbe08e3..36fc9fbb74 100644
--- a/packages/plugins/google-discovery/src/sdk/binding-store.ts
+++ b/packages/plugins/google-discovery/src/sdk/binding-store.ts
@@ -55,6 +55,9 @@ export interface GoogleDiscoveryBindingStore {
readonly putSource: (source: GoogleDiscoveryStoredSource) => Effect.Effect
;
readonly removeSource: (namespace: string) => Effect.Effect;
readonly listSources: () => Effect.Effect;
+ readonly getSource: (
+ namespace: string,
+ ) => Effect.Effect;
readonly getSourceConfig: (
namespace: string,
) => Effect.Effect;
@@ -120,6 +123,14 @@ const makeStore = (
return entries.map((e) => JSON.parse(e.value) as GoogleDiscoveryStoredSource);
}),
+ getSource: (namespace) =>
+ Effect.gen(function* () {
+ const raw = yield* sources.get(namespace);
+ if (!raw) return null;
+ // @effect-diagnostics-next-line preferSchemaOverJson:off
+ return JSON.parse(raw) as GoogleDiscoveryStoredSource;
+ }),
+
getSourceConfig: (namespace) =>
Effect.gen(function* () {
const raw = yield* sources.get(namespace);
diff --git a/packages/plugins/google-discovery/src/sdk/plugin.ts b/packages/plugins/google-discovery/src/sdk/plugin.ts
index fc57d6e033..485277a6b8 100644
--- a/packages/plugins/google-discovery/src/sdk/plugin.ts
+++ b/packages/plugins/google-discovery/src/sdk/plugin.ts
@@ -15,6 +15,7 @@ import {
import type {
GoogleDiscoveryBindingStore,
+ GoogleDiscoveryStoredSource,
} from "./binding-store";
import { makeInMemoryBindingStore } from "./binding-store";
import { extractGoogleDiscoveryManifest } from "./document";
@@ -110,6 +111,9 @@ export interface GoogleDiscoveryPluginExtension {
readonly completeOAuth: (
input: GoogleDiscoveryOAuthCompleteInput,
) => Effect.Effect;
+ readonly getSource: (
+ namespace: string,
+ ) => Effect.Effect;
}
const DISCOVERY_SERVICE_HOST = "https://www.googleapis.com/discovery/v1/apis";
@@ -293,6 +297,7 @@ export const googleDiscoveryPlugin = (options?: {
runtime: false,
canRemove: true,
canRefresh: true,
+ canEdit: true,
}),
),
),
@@ -558,6 +563,9 @@ export const googleDiscoveryPlugin = (options?: {
scopes: [...session.scopes],
};
}),
+
+ getSource: (namespace: string) =>
+ bindingStore.getSource(namespace),
};
return {
diff --git a/packages/plugins/google-discovery/src/sdk/stored-source.ts b/packages/plugins/google-discovery/src/sdk/stored-source.ts
new file mode 100644
index 0000000000..c59ecd292d
--- /dev/null
+++ b/packages/plugins/google-discovery/src/sdk/stored-source.ts
@@ -0,0 +1,19 @@
+import { Schema } from "effect";
+
+import { GoogleDiscoveryStoredSourceData } from "./types";
+
+// ---------------------------------------------------------------------------
+// Stored source — the shape persisted by the binding store and exposed
+// via the getSource HTTP endpoint.
+// ---------------------------------------------------------------------------
+
+export class GoogleDiscoveryStoredSourceSchema extends Schema.Class(
+ "GoogleDiscoveryStoredSource",
+)({
+ namespace: Schema.String,
+ name: Schema.String,
+ config: GoogleDiscoveryStoredSourceData,
+}) {}
+
+export type GoogleDiscoveryStoredSourceSchemaType =
+ typeof GoogleDiscoveryStoredSourceSchema.Type;