import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform";import { Schema } from "effect";import { ScopeId } from "@executor/sdk";import { InternalError } from "@executor/api"; import { GoogleDiscoveryOAuthError, GoogleDiscoveryParseError, GoogleDiscoverySourceError,} from "../sdk/errors";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({ kind: Schema.Literal("none"), }), Schema.Struct({ kind: Schema.Literal("oauth2"), clientIdSecretId: Schema.String, clientSecretSecretId: Schema.NullOr(Schema.String), accessTokenSecretId: Schema.String, refreshTokenSecretId: Schema.NullOr(Schema.String), tokenType: Schema.optional(Schema.String), expiresAt: Schema.NullOr(Schema.Number), scope: Schema.NullOr(Schema.String), scopes: Schema.Array(Schema.String), }),); const ProbePayload = Schema.Struct({ discoveryUrl: Schema.String,}); const ProbeOperation = Schema.Struct({ toolPath: Schema.String, method: Schema.String, pathTemplate: Schema.String, description: Schema.NullOr(Schema.String),}); const ProbeResponse = Schema.Struct({ name: Schema.String, title: Schema.NullOr(Schema.String), service: Schema.String, version: Schema.String, toolCount: Schema.Number, scopes: Schema.Array(Schema.String), operations: Schema.Array(ProbeOperation),}); const AddSourcePayload = Schema.Struct({ name: Schema.String, discoveryUrl: Schema.String, namespace: Schema.optional(Schema.String), auth: AuthPayload,}); const AddSourceResponse = Schema.Struct({ toolCount: Schema.Number, namespace: Schema.String,}); const StartOAuthPayload = Schema.Struct({ name: Schema.String, discoveryUrl: Schema.String, clientIdSecretId: Schema.String, clientSecretSecretId: Schema.optional(Schema.NullOr(Schema.String)), redirectUrl: Schema.String, scopes: Schema.optional(Schema.Array(Schema.String)),}); const StartOAuthResponse = Schema.Struct({ sessionId: Schema.String, authorizationUrl: Schema.String, scopes: Schema.Array(Schema.String),}); const CompleteOAuthPayload = Schema.Struct({ state: Schema.String, code: Schema.optional(Schema.String), error: Schema.optional(Schema.String),}); const CompleteOAuthResponse = Schema.Struct({ kind: Schema.Literal("oauth2"), clientIdSecretId: Schema.String, clientSecretSecretId: Schema.NullOr(Schema.String), accessTokenSecretId: Schema.String, refreshTokenSecretId: Schema.NullOr(Schema.String), tokenType: Schema.String, expiresAt: Schema.NullOr(Schema.Number), scope: Schema.NullOr(Schema.String), scopes: Schema.Array(Schema.String),}); const OAuthCallbackParams = Schema.Struct({ state: Schema.String, code: Schema.optional(Schema.String), error: Schema.optional(Schema.String), error_description: Schema.optional(Schema.String),}); const HtmlResponse = HttpApiSchema.Text({ contentType: "text/html" }); export class GoogleDiscoveryApiError extends Schema.TaggedError<GoogleDiscoveryApiError>()( "GoogleDiscoveryApiError", { message: Schema.String, }, HttpApiSchema.annotations({ status: 400 }),) {} // ---------------------------------------------------------------------------// Group//// Domain errors + the shared opaque 500 (`InternalError`) are declared// once at the group level via `.addError(...)` — every endpoint// inherits them. The domain error carries its HTTP status via// `HttpApiSchema.annotations`; `InternalError` is the public 5xx// surface, translated from `StorageError` at the HTTP edge by// `withCapture`. No per-endpoint `.addError(...)`, no per-handler// InternalError — handlers just `return yield* ext.foo(...)`.// --------------------------------------------------------------------------- export class GoogleDiscoveryGroup extends HttpApiGroup.make("googleDiscovery") .add( HttpApiEndpoint.post("probeDiscovery")`/scopes/${scopeIdParam}/google-discovery/probe` .setPayload(ProbePayload) .addSuccess(ProbeResponse), ) .add( HttpApiEndpoint.post("addSource")`/scopes/${scopeIdParam}/google-discovery/sources` .setPayload(AddSourcePayload) .addSuccess(AddSourceResponse), ) .add( HttpApiEndpoint.post("startOAuth")`/scopes/${scopeIdParam}/google-discovery/oauth/start` .setPayload(StartOAuthPayload) .addSuccess(StartOAuthResponse), ) .add( HttpApiEndpoint.post("completeOAuth")`/scopes/${scopeIdParam}/google-discovery/oauth/complete` .setPayload(CompleteOAuthPayload) .addSuccess(CompleteOAuthResponse), ) .add( HttpApiEndpoint.get("oauthCallback")`/google-discovery/oauth/callback` .setUrlParams(OAuthCallbackParams) .addSuccess(HtmlResponse), ) .add( HttpApiEndpoint.get( "getSource", )`/scopes/${scopeIdParam}/google-discovery/sources/${namespaceParam}` .addSuccess(Schema.NullOr(GoogleDiscoveryStoredSourceSchema)), ) // Errors declared once at the group level — every endpoint inherits. // `InternalError` is the shared opaque 500 translated at the HTTP edge // by `withCapture`. The others are 4xx domain errors carrying their // status via `HttpApiSchema.annotations`; handlers return them through // the typed channel and HttpApi encodes them directly. We only list // errors a Google Discovery *group* endpoint can surface — // `GoogleDiscoveryInvocationError` is thrown inside `invokeTool` which // is reached via the core `tools.invoke` endpoint, not any Google // Discovery-group endpoint, so it doesn't belong here. .addError(InternalError) .addError(GoogleDiscoveryApiError) .addError(GoogleDiscoveryOAuthError) .addError(GoogleDiscoveryParseError) .addError(GoogleDiscoverySourceError) {}
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform";
import { Schema } from "effect";
import { ScopeId } from "@executor/sdk";
import { InternalError } from "@executor/api";
import {
GoogleDiscoveryOAuthError,
GoogleDiscoveryParseError,
GoogleDiscoverySourceError,
} from "../sdk/errors";
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({
kind: Schema.Literal("none"),
}),
Schema.Struct({
kind: Schema.Literal("oauth2"),
clientIdSecretId: Schema.String,
clientSecretSecretId: Schema.NullOr(Schema.String),
accessTokenSecretId: Schema.String,
refreshTokenSecretId: Schema.NullOr(Schema.String),
tokenType: Schema.optional(Schema.String),
expiresAt: Schema.NullOr(Schema.Number),
scope: Schema.NullOr(Schema.String),
scopes: Schema.Array(Schema.String),
}),
);
const ProbePayload = Schema.Struct({
discoveryUrl: Schema.String,
});
const ProbeOperation = Schema.Struct({
toolPath: Schema.String,
method: Schema.String,
pathTemplate: Schema.String,
description: Schema.NullOr(Schema.String),
});
const ProbeResponse = Schema.Struct({
name: Schema.String,
title: Schema.NullOr(Schema.String),
service: Schema.String,
version: Schema.String,
toolCount: Schema.Number,
scopes: Schema.Array(Schema.String),
operations: Schema.Array(ProbeOperation),
});
const AddSourcePayload = Schema.Struct({
name: Schema.String,
discoveryUrl: Schema.String,
namespace: Schema.optional(Schema.String),
auth: AuthPayload,
});
const AddSourceResponse = Schema.Struct({
toolCount: Schema.Number,
namespace: Schema.String,
});
const StartOAuthPayload = Schema.Struct({
name: Schema.String,
discoveryUrl: Schema.String,
clientIdSecretId: Schema.String,
clientSecretSecretId: Schema.optional(Schema.NullOr(Schema.String)),
redirectUrl: Schema.String,
scopes: Schema.optional(Schema.Array(Schema.String)),
});
const StartOAuthResponse = Schema.Struct({
sessionId: Schema.String,
authorizationUrl: Schema.String,
scopes: Schema.Array(Schema.String),
});
const CompleteOAuthPayload = Schema.Struct({
state: Schema.String,
code: Schema.optional(Schema.String),
error: Schema.optional(Schema.String),
});
const CompleteOAuthResponse = Schema.Struct({
kind: Schema.Literal("oauth2"),
clientIdSecretId: Schema.String,
clientSecretSecretId: Schema.NullOr(Schema.String),
accessTokenSecretId: Schema.String,
refreshTokenSecretId: Schema.NullOr(Schema.String),
tokenType: Schema.String,
expiresAt: Schema.NullOr(Schema.Number),
scope: Schema.NullOr(Schema.String),
scopes: Schema.Array(Schema.String),
});
const OAuthCallbackParams = Schema.Struct({
state: Schema.String,
code: Schema.optional(Schema.String),
error: Schema.optional(Schema.String),
error_description: Schema.optional(Schema.String),
});
const HtmlResponse = HttpApiSchema.Text({ contentType: "text/html" });
export class GoogleDiscoveryApiError extends Schema.TaggedError<GoogleDiscoveryApiError>()(
"GoogleDiscoveryApiError",
{
message: Schema.String,
},
HttpApiSchema.annotations({ status: 400 }),
) {}
// ---------------------------------------------------------------------------
// Group
//
// Domain errors + the shared opaque 500 (`InternalError`) are declared
// once at the group level via `.addError(...)` — every endpoint
// inherits them. The domain error carries its HTTP status via
// `HttpApiSchema.annotations`; `InternalError` is the public 5xx
// surface, translated from `StorageError` at the HTTP edge by
// `withCapture`. No per-endpoint `.addError(...)`, no per-handler
// InternalError — handlers just `return yield* ext.foo(...)`.
// ---------------------------------------------------------------------------
export class GoogleDiscoveryGroup extends HttpApiGroup.make("googleDiscovery")
.add(
HttpApiEndpoint.post("probeDiscovery")`/scopes/${scopeIdParam}/google-discovery/probe`
.setPayload(ProbePayload)
.addSuccess(ProbeResponse),
)
.add(
HttpApiEndpoint.post("addSource")`/scopes/${scopeIdParam}/google-discovery/sources`
.setPayload(AddSourcePayload)
.addSuccess(AddSourceResponse),
)
.add(
HttpApiEndpoint.post("startOAuth")`/scopes/${scopeIdParam}/google-discovery/oauth/start`
.setPayload(StartOAuthPayload)
.addSuccess(StartOAuthResponse),
)
.add(
HttpApiEndpoint.post("completeOAuth")`/scopes/${scopeIdParam}/google-discovery/oauth/complete`
.setPayload(CompleteOAuthPayload)
.addSuccess(CompleteOAuthResponse),
)
.add(
HttpApiEndpoint.get("oauthCallback")`/google-discovery/oauth/callback`
.setUrlParams(OAuthCallbackParams)
.addSuccess(HtmlResponse),
)
.add(
HttpApiEndpoint.get(
"getSource",
)`/scopes/${scopeIdParam}/google-discovery/sources/${namespaceParam}`
.addSuccess(Schema.NullOr(GoogleDiscoveryStoredSourceSchema)),
)
// Errors declared once at the group level — every endpoint inherits.
// `InternalError` is the shared opaque 500 translated at the HTTP edge
// by `withCapture`. The others are 4xx domain errors carrying their
// status via `HttpApiSchema.annotations`; handlers return them through
// the typed channel and HttpApi encodes them directly. We only list
// errors a Google Discovery *group* endpoint can surface —
// `GoogleDiscoveryInvocationError` is thrown inside `invokeTool` which
// is reached via the core `tools.invoke` endpoint, not any Google
// Discovery-group endpoint, so it doesn't belong here.
.addError(InternalError)
.addError(GoogleDiscoveryApiError)
.addError(GoogleDiscoveryOAuthError)
.addError(GoogleDiscoveryParseError)
.addError(GoogleDiscoverySourceError) {}