Add operator Integrations page (integration registry console)
The operator surface for the integration registry: manage platform/pooled external-API credentials across every scope and inspect cross-tenant usage (metadata only — secrets are write-only). Talks to arcadia-llm-gateway's /api/v1/integrations* endpoints via a gateway-pointed ArcadiaClient. - gateway.ts: second ArcadiaClient at VITE_LLM_GATEWAY_URL, reusing the arcadia-app JWT (the gateway validates it via the shared Guardian secret; CORS already allows *.sky-ai.com + localhost — no proxy). - lib/arcadia/integrations.ts: operator API client (any-scope create, scope filter, cross-tenant usage). Pure functions over an injected client — extraction-ready to share with arcadia-console. - routes/integrations.tsx: scope filter + per-card scope badge, create platform/pooled credentials, credentials/usage, Test (surfaces the expiry/budget gate), enable toggle, delete. The route/nav/capability wiring (routes.ts, app-shell, capabilities.ts) lands with the in-flight capability framework, not here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
app/lib/gateway.ts
Normal file
38
app/lib/gateway.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// Arcadia LLM-gateway client.
|
||||
//
|
||||
// The integration registry lives on arcadia-llm-gateway, not arcadia-app, so
|
||||
// it needs its own ArcadiaClient pointed at a different base URL. Everything
|
||||
// else is identical to the arcadia-app client: the same access token (the
|
||||
// gateway validates arcadia-app JWTs via the shared Guardian secret) and the
|
||||
// same 401 cleanup. The gateway's CORS already allows localhost + any
|
||||
// *.sky-ai.com origin, so the browser calls it directly.
|
||||
|
||||
import { createArcadiaClient, type ArcadiaClient } from "@crema/arcadia-client"
|
||||
|
||||
const GATEWAY_URL = import.meta.env.VITE_LLM_GATEWAY_URL ?? "http://localhost:4015"
|
||||
|
||||
const ACCESS_TOKEN_KEY = "arcadia_access_token"
|
||||
const REFRESH_TOKEN_KEY = "arcadia_refresh_token"
|
||||
|
||||
let client: ArcadiaClient | null = null
|
||||
|
||||
export function gatewayClient(): ArcadiaClient {
|
||||
if (!client) {
|
||||
client = createArcadiaClient({
|
||||
baseUrl: GATEWAY_URL,
|
||||
getToken: () =>
|
||||
typeof window === "undefined" ? null : sessionStorage.getItem(ACCESS_TOKEN_KEY),
|
||||
onUnauthorized: () => {
|
||||
if (typeof window !== "undefined") {
|
||||
sessionStorage.removeItem(ACCESS_TOKEN_KEY)
|
||||
sessionStorage.removeItem(REFRESH_TOKEN_KEY)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
export function useGatewayClient(): ArcadiaClient {
|
||||
return gatewayClient()
|
||||
}
|
||||
Reference in New Issue
Block a user