@tangle-network/agent-app 0.60.173 → 0.60.174
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/integrations-react/index.d.ts +1 -1
- package/dist/integrations-react/index.js +18 -14
- package/dist/integrations-react/index.js.map +1 -1
- package/dist/integrations-react/panel.d.ts +3 -1
- package/dist/integrations-react/popup.d.ts +1 -1
- package/dist/integrations-react/projection.d.ts +15 -3
- package/dist/integrations-react/use-hub-integrations.d.ts +4 -2
- package/package.json +1 -1
|
@@ -3,4 +3,4 @@ export { createHubIntegrationsClient, type HubIntegrationsClient, type HubIntegr
|
|
|
3
3
|
export { connectionTone, HubIntegrationsPanel, hubConnectionStatus, type HubAccountStatus, type HubConnectionState, type HubIntegrationsAccounts, type HubIntegrationsPanelProps } from './panel';
|
|
4
4
|
export { HUB_CONNECT_CHANNEL, HUB_CONNECTED_MESSAGE_TYPE, HUB_CONNECT_FAILED_MESSAGE_TYPE, POPUP_TIMEOUT_MS } from './popup';
|
|
5
5
|
export { useHubIntegrations, type HubHostConnect, type HubWriteReceipt, type UseHubIntegrationsOptions } from './use-hub-integrations';
|
|
6
|
-
export { type HubIntegrationCapabilities, type HubIntegrationCapability } from './projection';
|
|
6
|
+
export { type HubActionPolicy, type HubActionPolicyDisplay, type HubIntegrationCapabilities, type HubIntegrationCapability } from './projection';
|
|
@@ -102,7 +102,7 @@ function waitForConnection(input) {
|
|
|
102
102
|
candidate.onmessage = (event) => {
|
|
103
103
|
const message = event.data;
|
|
104
104
|
if (!message || message.provider !== input.providerId || message.nonce !== input.nonce || message.context !== input.contextToken) return;
|
|
105
|
-
if (message.type === HUB_CONNECT_FAILED_MESSAGE_TYPE) finish("
|
|
105
|
+
if (message.type === HUB_CONNECT_FAILED_MESSAGE_TYPE) finish("failed");
|
|
106
106
|
if (message.type === HUB_CONNECTED_MESSAGE_TYPE) {
|
|
107
107
|
if (pollId !== void 0) window.clearTimeout(pollId);
|
|
108
108
|
void check();
|
|
@@ -187,7 +187,7 @@ function HubConnectCallbackPage({ returnHref }) {
|
|
|
187
187
|
setPhase("failed");
|
|
188
188
|
return;
|
|
189
189
|
}
|
|
190
|
-
const failure = params.get("error_description") || params.get("error");
|
|
190
|
+
const failure = params.get("error_description") || params.get("error") || (params.get("hub_connection") === "error" ? params.get("hub_error") || "Please restart the connection flow." : null);
|
|
191
191
|
try {
|
|
192
192
|
const channel = new BroadcastChannel(HUB_CONNECT_CHANNEL);
|
|
193
193
|
channel.postMessage({ type: failure ? HUB_CONNECT_FAILED_MESSAGE_TYPE : HUB_CONNECTED_MESSAGE_TYPE, provider, nonce, context });
|
|
@@ -352,7 +352,7 @@ var OPTIONS = [
|
|
|
352
352
|
{ value: "ask", label: "Ask" },
|
|
353
353
|
{ value: "deny", label: "Deny" }
|
|
354
354
|
];
|
|
355
|
-
function permissionDetails(tools, policies, connectionId, can) {
|
|
355
|
+
function permissionDetails(tools, policies, connectionId, can, getActionPolicy) {
|
|
356
356
|
const overrides = new Map(policies.filter((policy) => policy.connectionId === connectionId).map((policy) => [policy.actionPath, policy.decision]));
|
|
357
357
|
const groups = [
|
|
358
358
|
{ id: "writes", title: "Write and unknown actions", rows: [] },
|
|
@@ -362,16 +362,17 @@ function permissionDetails(tools, policies, connectionId, can) {
|
|
|
362
362
|
const reads = [];
|
|
363
363
|
for (const tool of tools) {
|
|
364
364
|
const override = overrides.get(tool.path);
|
|
365
|
+
const enforced = getActionPolicy?.(tool, override);
|
|
365
366
|
const row = {
|
|
366
367
|
actionPath: tool.path,
|
|
367
368
|
title: tool.title ?? tool.path,
|
|
368
369
|
riskLabel: tool.risk ?? "unknown",
|
|
369
370
|
riskTone: tool.risk === "destructive" ? "error" : tool.risk === "write" || tool.risk === void 0 ? "warning" : "neutral",
|
|
370
|
-
decision: override ?? null,
|
|
371
|
-
decisionOptions: OPTIONS,
|
|
372
|
-
sourceLabel: override ? "Stored override" : "No stored override",
|
|
373
|
-
canReset: override !== void 0 && can({ operation: "policy.reset", connectionId, actionPath: tool.path }),
|
|
374
|
-
disabled: !can({ operation: "policy.set", connectionId, actionPath: tool.path })
|
|
371
|
+
decision: enforced?.decision ?? override ?? null,
|
|
372
|
+
decisionOptions: enforced ? [{ value: enforced.decision, label: enforced.label }] : OPTIONS,
|
|
373
|
+
sourceLabel: enforced?.sourceLabel ?? (override ? "Stored override" : "No stored override"),
|
|
374
|
+
canReset: !enforced && override !== void 0 && can({ operation: "policy.reset", connectionId, actionPath: tool.path }),
|
|
375
|
+
disabled: !!enforced || !can({ operation: "policy.set", connectionId, actionPath: tool.path })
|
|
375
376
|
};
|
|
376
377
|
if (tool.risk === "read") reads.push(row);
|
|
377
378
|
else writes.push(row);
|
|
@@ -399,7 +400,7 @@ function updateUrl(providerId, connectionId) {
|
|
|
399
400
|
else url.searchParams.delete("connection");
|
|
400
401
|
window.history.pushState(window.history.state, "", url);
|
|
401
402
|
}
|
|
402
|
-
function useHubIntegrations({ identity, client, can, callbackPath, onUnsupportedConnect, hostConnect }) {
|
|
403
|
+
function useHubIntegrations({ identity, client, can, callbackPath, onUnsupportedConnect, hostConnect, getActionPolicy }) {
|
|
403
404
|
const scope = contextKey(identity);
|
|
404
405
|
const activeScope = useRef(scope);
|
|
405
406
|
activeScope.current = scope;
|
|
@@ -544,7 +545,7 @@ function useHubIntegrations({ identity, client, can, callbackPath, onUnsupported
|
|
|
544
545
|
connections.retry();
|
|
545
546
|
setDialog(null);
|
|
546
547
|
setConnectStatus({ scope, status: "connected", message: "Connection verified." });
|
|
547
|
-
} else setConnectStatus({ scope, status: "failed", message: result === "blocked" ? "Allow the popup and try again." : result === "unverified" ? "Could not verify a new connection. Refresh and try again." : result === "cancelled" ? "Connection was cancelled." : "This connection flow is unavailable." });
|
|
548
|
+
} else setConnectStatus({ scope, status: "failed", providerId: target.providerId, message: result === "blocked" ? "Allow the popup and try again." : result === "unverified" ? "Could not verify a new connection. Refresh and try again." : result === "failed" ? "Could not connect your account. Please try again." : result === "cancelled" ? "Connection was cancelled." : "This connection flow is unavailable." });
|
|
548
549
|
return result;
|
|
549
550
|
}, [can, connections, client, identity, callbackPath, scope]);
|
|
550
551
|
const beginConnect = useCallback((target) => {
|
|
@@ -580,7 +581,7 @@ function useHubIntegrations({ identity, client, can, callbackPath, onUnsupported
|
|
|
580
581
|
pendingPopup.current?.abort();
|
|
581
582
|
pendingPopup.current = null;
|
|
582
583
|
setDialog(null);
|
|
583
|
-
setConnectStatus({ scope, status: "failed", message: "Connection was cancelled." });
|
|
584
|
+
setConnectStatus((current) => ({ scope, status: "failed", providerId: current.scope === scope ? current.providerId : void 0, message: "Connection was cancelled." }));
|
|
584
585
|
}, [scope]);
|
|
585
586
|
const rows = useMemo(
|
|
586
587
|
() => catalogRows(
|
|
@@ -593,7 +594,7 @@ function useHubIntegrations({ identity, client, can, callbackPath, onUnsupported
|
|
|
593
594
|
),
|
|
594
595
|
[providerList, connectionList, visibleSelection.providerId, visibleSelection.connectionId, can, onUnsupportedConnect, hostConnect]
|
|
595
596
|
);
|
|
596
|
-
const details = detail.status === "ready" && connection ? permissionDetails(detail.value.tools, detail.value.policies, connection.id, can) : void 0;
|
|
597
|
+
const details = detail.status === "ready" && connection ? permissionDetails(detail.value.tools, detail.value.policies, connection.id, can, (tool, storedDecision) => getActionPolicy?.({ connection, tool, storedDecision })) : void 0;
|
|
597
598
|
return {
|
|
598
599
|
providers,
|
|
599
600
|
connections,
|
|
@@ -795,6 +796,7 @@ function HubIntegrationsPanel(props) {
|
|
|
795
796
|
}, [hub.connectStatus.status, scope]);
|
|
796
797
|
const connectedProviders = new Set(connectionList.filter((connection) => connection.status !== "revoked").map((connection) => connection.providerId));
|
|
797
798
|
const catalogRows2 = props.accounts && hub.connections.status === "error" ? [] : props.accounts ? rows.filter((row) => !connectedProviders.has(row.providerId)).map((row) => ({ ...row, connections: [], selectedConnectionId: null })) : rows;
|
|
799
|
+
const retryProvider = hub.providers.status === "ready" ? hub.providers.value.find((provider) => provider.providerId === hub.connectStatus.providerId) : void 0;
|
|
798
800
|
const selectedConnection = hub.connection;
|
|
799
801
|
const detailError = hub.detail.status === "error" ? hub.detail.message : hub.detail.status === "ready" && hub.detail.value.truncated ? `Showing at most ${hub.detail.value.tools.length} actions. The provider catalog may be incomplete.` : null;
|
|
800
802
|
const detailsByConnectionId = useMemo2(() => hub.connection ? {
|
|
@@ -841,7 +843,6 @@ function HubIntegrationsPanel(props) {
|
|
|
841
843
|
loading: hub.providers.status === "loading" || hub.connections.status === "loading",
|
|
842
844
|
error,
|
|
843
845
|
actionError: mutationError,
|
|
844
|
-
connectError: hub.connectStatus.status === "failed" ? hub.connectStatus.message : null,
|
|
845
846
|
busyProviderId: hub.connectStatus.status === "pending" ? hub.connectStatus.providerId ?? null : null,
|
|
846
847
|
reserveConnectionContext: true,
|
|
847
848
|
emptyCatalogLabel: props.accounts && rows.length > 0 ? "Every available integration has a connected account. Manage an account to connect another." : void 0
|
|
@@ -855,7 +856,10 @@ function HubIntegrationsPanel(props) {
|
|
|
855
856
|
hub.writeState.status === "pending" ? /* @__PURE__ */ jsx2("p", { role: "status", children: "Saving Hub settings\u2026" }) : null,
|
|
856
857
|
mutationError ? /* @__PURE__ */ jsx2("p", { role: "alert", children: mutationError }) : null,
|
|
857
858
|
writeMessage ? /* @__PURE__ */ jsx2("p", { role: writeWarning ? "alert" : "status", children: writeMessage }) : null,
|
|
858
|
-
hub.connectStatus.
|
|
859
|
+
hub.connectStatus.status === "failed" ? /* @__PURE__ */ jsxs2("div", { role: "alert", className: "mb-4 flex flex-wrap items-center gap-3 text-sm text-destructive", children: [
|
|
860
|
+
/* @__PURE__ */ jsx2("p", { "data-testid": "integration-connect-error", children: hub.connectStatus.message }),
|
|
861
|
+
retryProvider ? /* @__PURE__ */ jsx2(Button, { type: "button", variant: "outline", disabled: pending, onClick: () => hub.beginConnect(retryProvider), children: "Retry connection" }) : null
|
|
862
|
+
] }) : hub.connectStatus.message && hub.provider ? /* @__PURE__ */ jsx2("p", { role: "status", children: hub.connectStatus.message }) : null,
|
|
859
863
|
hub.provider ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
860
864
|
props.accounts && selectedConnection || selectedRow?.canConnect ? /* @__PURE__ */ jsxs2("div", { className: "mb-4 flex min-w-0 flex-wrap items-center gap-2", children: [
|
|
861
865
|
props.accounts && selectedConnection ? /* @__PURE__ */ jsxs2(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/integrations-react/callback.tsx","../../src/integrations-react/popup.ts","../../src/integrations-react/client.ts","../../src/integrations-react/panel.tsx","../../src/integrations-react/projection.ts","../../src/integrations-react/use-hub-integrations.ts"],"sourcesContent":["import { useEffect, useState } from 'react'\nimport { HUB_CONNECTED_MESSAGE_TYPE, HUB_CONNECT_CHANNEL, HUB_CONNECT_FAILED_MESSAGE_TYPE, localAppUrl } from './popup'\n\nexport interface HubConnectCallbackPageProps {\n /** Local settings destination owned by the consuming app. */\n returnHref: string\n}\n\n/** The callback only signals completion; the opener verifies fresh Hub state. */\nexport function HubConnectCallbackPage({ returnHref }: HubConnectCallbackPageProps) {\n const [phase, setPhase] = useState<'checking' | 'returned' | 'failed'>('checking')\n const [reason, setReason] = useState('')\n\n useEffect(() => {\n const params = new URLSearchParams(window.location.search)\n const provider = params.get('provider')\n const nonce = params.get('nonce')\n const context = params.get('context')\n if (!provider || !nonce || !context) { setReason('This connection callback is incomplete.'); setPhase('failed'); return }\n const failure = params.get('error_description') || params.get('error')\n try {\n const channel = new BroadcastChannel(HUB_CONNECT_CHANNEL)\n channel.postMessage({ type: failure ? HUB_CONNECT_FAILED_MESSAGE_TYPE : HUB_CONNECTED_MESSAGE_TYPE, provider, nonce, context })\n channel.close()\n } catch { /* The opener also polls the authoritative connection list. */ }\n if (failure) { setReason(failure.slice(0, 200)); setPhase('failed'); return }\n window.close()\n const timer = window.setTimeout(() => setPhase('returned'), 150)\n return () => window.clearTimeout(timer)\n }, [])\n\n const destination = localAppUrl(returnHref)\n const localReturn = destination ? `${destination.pathname}${destination.search}${destination.hash}` : '/'\n return <main aria-live=\"polite\" style={{ maxWidth: 560, margin: '20vh auto', padding: 24, textAlign: 'center' }}>\n {phase === 'checking' ? <p>Checking your connection…</p> : phase === 'returned'\n ? <p>Return to the app to check your connection. You can close this window.</p>\n : <p>Could not complete the connection. {reason}</p>}\n <a href={localReturn}>Return to integrations</a>\n </main>\n}\n","import type { HubConnection } from '@tangle-network/hub-sdk'\nimport type { HubIntegrationsClient, HubIntegrationsIdentity } from './client'\n\nexport const HUB_CONNECT_CHANNEL = 'tangle:hub-connect'\nexport const HUB_CONNECTED_MESSAGE_TYPE = 'tangle:hub-connected'\nexport const HUB_CONNECT_FAILED_MESSAGE_TYPE = 'tangle:hub-connect-failed'\nexport const POPUP_TIMEOUT_MS = 5 * 60 * 1000\nconst PRE_REDIRECT_TIMEOUT_MS = 30_000\nconst POLL_INTERVAL_MS = 2500\nconst POPUP_FEATURES = 'popup=yes,width=520,height=680'\n\nexport type PopupConnectResult = 'connected' | 'blocked' | 'cancelled' | 'unverified' | 'unavailable'\n\nexport function localAppUrl(path: string): URL | null {\n if (!path.startsWith('/') || path.startsWith('//')) return null\n try {\n const origin = typeof window === 'undefined' ? 'https://local.invalid' : window.location.origin\n const url = new URL(path, origin)\n return url.origin === origin && !url.username && !url.password ? url : null\n } catch { return null }\n}\n\nfunction updatedConnection(providerId: string, before: readonly HubConnection[], after: readonly HubConnection[]): boolean {\n const previous = new Map(before.filter(connection => connection.providerId === providerId).map(connection => [connection.id, connection]))\n return after.some(connection => {\n if (connection.providerId !== providerId || connection.status !== 'active' || connection.health === 'unhealthy') return false\n const old = previous.get(connection.id)\n return !old || old.updatedAt !== connection.updatedAt || old.status !== connection.status\n })\n}\n\nfunction closePopup(popup: Window): void {\n try { if (!popup.closed) popup.close() } catch { /* COOP may sever the handle. */ }\n}\n\nfunction withAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) { reject(new DOMException('Aborted', 'AbortError')); return }\n const onAbort = () => reject(new DOMException('Aborted', 'AbortError'))\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(value => { signal.removeEventListener('abort', onAbort); resolve(value) }, error => { signal.removeEventListener('abort', onAbort); reject(error) })\n })\n}\n\nfunction waitForConnection(input: {\n popup: Window\n client: HubIntegrationsClient\n identity: HubIntegrationsIdentity\n providerId: string\n before: readonly HubConnection[]\n nonce: string\n contextToken: string\n signal: AbortSignal\n isCurrent: () => boolean\n}): Promise<PopupConnectResult> {\n return new Promise(resolve => {\n let settled = false\n let checking = false\n let pollId: number | undefined\n let timeoutId: number | undefined\n let channel: BroadcastChannel | undefined\n const finish = (result: PopupConnectResult) => {\n if (settled) return\n settled = true\n if (pollId !== undefined) window.clearTimeout(pollId)\n if (timeoutId !== undefined) window.clearTimeout(timeoutId)\n input.signal.removeEventListener('abort', onAbort)\n channel?.close()\n closePopup(input.popup)\n resolve(result)\n }\n const onAbort = () => finish('cancelled')\n const check = async () => {\n if (settled || checking) return\n checking = true\n if (!input.isCurrent() || input.signal.aborted) { finish('cancelled'); return }\n try {\n const after = await input.client.connections(input.identity, input.signal)\n if (input.isCurrent() && updatedConnection(input.providerId, input.before, after)) { finish('connected'); return }\n } catch { /* A lost read is never evidence of a connection. Keep polling. */ }\n checking = false\n if (!settled) pollId = window.setTimeout(check, POLL_INTERVAL_MS)\n }\n if (input.signal.aborted) { finish('cancelled'); return }\n input.signal.addEventListener('abort', onAbort, { once: true })\n try {\n const candidate = new BroadcastChannel(HUB_CONNECT_CHANNEL)\n candidate.onmessage = event => {\n const message = event.data as Record<string, unknown> | null\n if (!message || message.provider !== input.providerId || message.nonce !== input.nonce || message.context !== input.contextToken) return\n if (message.type === HUB_CONNECT_FAILED_MESSAGE_TYPE) finish('cancelled')\n if (message.type === HUB_CONNECTED_MESSAGE_TYPE) {\n if (pollId !== undefined) window.clearTimeout(pollId)\n void check()\n }\n }\n channel = candidate\n } catch { /* Polling covers browsers without BroadcastChannel. */ }\n pollId = window.setTimeout(check, POLL_INTERVAL_MS)\n timeoutId = window.setTimeout(() => finish('unverified'), POPUP_TIMEOUT_MS)\n })\n}\n\n/** Opens before the first await, preserving the initiating user gesture. */\nexport async function connectWithPopup(input: {\n client: HubIntegrationsClient\n identity: HubIntegrationsIdentity\n providerId: string\n before: readonly HubConnection[]\n callbackPath: string\n connectionParameters?: Record<string, string>\n signal: AbortSignal\n isCurrent: () => boolean\n}): Promise<PopupConnectResult> {\n const callback = localAppUrl(input.callbackPath)\n if (!callback) throw new TypeError('Callback path must be local.')\n const popup = window.open('', '_blank', POPUP_FEATURES)\n if (!popup) return 'blocked'\n // Keep the parent handle for navigation while removing the provider page's opener.\n try { popup.opener = null } catch { /* Some browsers make this read-only. */ }\n const nonce = crypto.randomUUID()\n const contextToken = crypto.randomUUID()\n callback.searchParams.set('provider', input.providerId)\n callback.searchParams.set('nonce', nonce)\n callback.searchParams.set('context', contextToken)\n const timeout = new AbortController()\n const onAbort = () => timeout.abort()\n input.signal.addEventListener('abort', onAbort, { once: true })\n const preRedirectId = window.setTimeout(() => timeout.abort(), PRE_REDIRECT_TIMEOUT_MS)\n try {\n if (!input.isCurrent()) return 'cancelled'\n const start = await withAbort(input.client.startOAuth(input.identity, input.providerId, {\n returnUrl: callback.href,\n ...(input.connectionParameters === undefined ? {} : { connectionParameters: input.connectionParameters }),\n }, timeout.signal), timeout.signal)\n if (!input.isCurrent() || input.signal.aborted) return 'cancelled'\n let redirect: URL\n try { redirect = new URL(start.redirectUrl) } catch { return 'unavailable' }\n if (redirect.protocol !== 'https:' || redirect.username || redirect.password) return 'unavailable'\n window.clearTimeout(preRedirectId)\n const waitController = new AbortController()\n const abortWait = () => waitController.abort()\n input.signal.addEventListener('abort', abortWait, { once: true })\n if (input.signal.aborted) abortWait()\n const waiting = waitForConnection({ ...input, popup, nonce, contextToken, signal: waitController.signal })\n try {\n popup.location.href = redirect.href\n return await waiting\n } catch {\n waitController.abort()\n await waiting\n return 'unavailable'\n } finally {\n input.signal.removeEventListener('abort', abortWait)\n }\n } catch {\n return input.signal.aborted || timeout.signal.aborted ? 'cancelled' : 'unavailable'\n } finally {\n window.clearTimeout(preRedirectId)\n input.signal.removeEventListener('abort', onAbort)\n closePopup(popup)\n }\n}\n","import type {\n HubApiKeyConnectionMetadata,\n HubConnection,\n HubConnectionHealthResponse,\n HubOAuthStartResponse,\n HubPolicy,\n HubPolicyDecision,\n HubProvider,\n HubTool,\n} from '@tangle-network/hub-sdk'\n\n/** The host must bind each request to this server-verified identity. */\nexport interface HubIntegrationsIdentity {\n readonly userId: string\n readonly sessionId: string\n readonly workspaceId: string\n}\n\nexport interface HubSettingsRequest {\n readonly identity: HubIntegrationsIdentity\n readonly path: string\n readonly init: RequestInit\n}\n\n/**\n * The host supplies its authenticated fetch, CSRF protection and expected\n * identity check. The browser never receives a Hub credential or SDK client.\n */\nexport type HubSettingsRequestFn = (request: HubSettingsRequest) => Promise<Response>\n\nexport interface HubIntegrationsClient {\n providers(identity: HubIntegrationsIdentity, signal?: AbortSignal): Promise<HubProvider[]>\n connections(identity: HubIntegrationsIdentity, signal?: AbortSignal): Promise<HubConnection[]>\n startOAuth(identity: HubIntegrationsIdentity, providerId: string, input: { returnUrl: string; connectionParameters?: Record<string, string> }, signal?: AbortSignal): Promise<HubOAuthStartResponse>\n connectApiKey(identity: HubIntegrationsIdentity, providerId: string, apiKey: string, metadata?: HubApiKeyConnectionMetadata, signal?: AbortSignal): Promise<HubConnection>\n revoke(identity: HubIntegrationsIdentity, connectionId: string, signal?: AbortSignal): Promise<HubConnection>\n health(identity: HubIntegrationsIdentity, connectionId: string, signal?: AbortSignal): Promise<HubConnectionHealthResponse>\n actions(identity: HubIntegrationsIdentity, providerId: string, limit: number, signal?: AbortSignal): Promise<HubTool[]>\n policies(identity: HubIntegrationsIdentity, connectionId: string, signal?: AbortSignal): Promise<HubPolicy[]>\n setPolicy(identity: HubIntegrationsIdentity, connectionId: string, actionPath: string, decision: HubPolicyDecision, signal?: AbortSignal): Promise<HubPolicy>\n resetPolicy(identity: HubIntegrationsIdentity, connectionId: string, actionPath: string, signal?: AbortSignal): Promise<void>\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error('Invalid Hub settings response.')\n return value as Record<string, unknown>\n}\n\nfunction array(value: unknown): unknown[] {\n if (!Array.isArray(value)) throw new Error('Invalid Hub settings response.')\n return value\n}\n\nfunction namedArray<T>(value: unknown, key: string): T[] {\n const rows = array(object(value)[key])\n if (rows.some(row => row === null || typeof row !== 'object' || Array.isArray(row))) throw new Error('Invalid Hub settings response.')\n return rows as T[]\n}\n\nfunction namedObject<T>(value: unknown, key: string): T {\n return object(object(value)[key]) as T\n}\n\nfunction segment(value: string): string {\n if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value)) throw new TypeError('Invalid Hub settings identifier.')\n return encodeURIComponent(value)\n}\n\n/** Finite browser transport for the server-owned `createHubSettingsRoutes` API. */\nexport function createHubIntegrationsClient(request: HubSettingsRequestFn, basePath = '/api/hub/settings'): HubIntegrationsClient {\n if (!/^\\/(?:[A-Za-z0-9_-]+\\/)*[A-Za-z0-9_-]+$/.test(basePath)) throw new TypeError('Invalid Hub settings basePath.')\n\n async function call(identity: HubIntegrationsIdentity, path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE', signal?: AbortSignal, body?: object): Promise<unknown> {\n if (![identity.userId, identity.sessionId, identity.workspaceId].every(part => typeof part === 'string' && part.trim())) {\n throw new TypeError('Hub settings identity is required.')\n }\n const response = await request({\n identity,\n path: `${basePath}${path}`,\n init: { method, signal, ...(body === undefined ? {} : { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) },\n })\n if (!response.ok) {\n let code: string | undefined\n try {\n const error = object(await response.json())\n if (typeof error.code === 'string') code = error.code\n } catch { /* Status remains authoritative when a response is unreadable. */ }\n throw new Error(`Hub settings request failed (${response.status}${code ? `, ${code}` : ''}).`)\n }\n return response.json()\n }\n\n return {\n async providers(identity, signal) { return namedArray<HubProvider>(await call(identity, '/providers', 'GET', signal), 'providers') },\n async connections(identity, signal) { return namedArray<HubConnection>(await call(identity, '/connections', 'GET', signal), 'connections') },\n async startOAuth(identity, providerId, input, signal) {\n const response = object(await call(identity, `/connections/${segment(providerId)}/start`, 'POST', signal, input))\n if (typeof response.redirectUrl !== 'string') throw new Error('Invalid Hub OAuth response.')\n return response as unknown as HubOAuthStartResponse\n },\n async connectApiKey(identity, providerId, apiKey, metadata, signal) {\n return namedObject<HubConnection>(await call(identity, `/connections/${segment(providerId)}/connect-key`, 'POST', signal, { apiKey, ...(metadata === undefined ? {} : { metadata }) }), 'connection')\n },\n async revoke(identity, connectionId, signal) { return namedObject<HubConnection>(await call(identity, `/connections/${segment(connectionId)}`, 'DELETE', signal), 'connection') },\n async health(identity, connectionId, signal) {\n const response = object(await call(identity, `/connections/${segment(connectionId)}/health`, 'POST', signal))\n object(response.connection)\n object(response.health)\n return response as unknown as HubConnectionHealthResponse\n },\n async actions(identity, providerId, limit, signal) {\n if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new TypeError('Hub action limit must be 1–200.')\n const search = new URLSearchParams({ query: '', limit: String(limit) })\n return namedArray<HubTool>(await call(identity, `/providers/${segment(providerId)}/actions?${search}`, 'GET', signal), 'tools')\n },\n async policies(identity, connectionId, signal) {\n const search = new URLSearchParams({ connectionId })\n return namedArray<HubPolicy>(await call(identity, `/policies?${search}`, 'GET', signal), 'policies')\n },\n async setPolicy(identity, connectionId, actionPath, decision, signal) {\n return namedObject<HubPolicy>(await call(identity, '/policies', 'PUT', signal, { connectionId, actionPath, decision }), 'policy')\n },\n async resetPolicy(identity, connectionId, actionPath, signal) {\n const response = object(await call(identity, '/policies', 'DELETE', signal, { connectionId, actionPath }))\n if (response.connectionId !== connectionId || response.actionPath !== actionPath || typeof response.deleted !== 'boolean') {\n throw new Error('Invalid Hub policy reset response.')\n }\n },\n }\n}\n","import type { HubApiKeyConnectionMetadata, HubConnection, HubProvider } from '@tangle-network/hub-sdk'\nimport {\n ApiKeyConnectDialog,\n IntegrationConnectionDetail,\n IntegrationsCatalog,\n OAuthConnectionParameterDialog,\n ProviderIcon,\n type IntegrationDisplayAction,\n type IntegrationsCatalogProps,\n type IntegrationSort,\n} from '@tangle-network/sandbox-ui/integrations'\nimport { Button, Card, Input, StatusPill, Tabs, TabsContent, TabsList, TabsTrigger, type StatusTone } from '@tangle-network/ui/primitives'\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport type { HubIntegrationsClient, HubIntegrationsIdentity } from './client'\nimport { contextKey, displayProvider, type HubIntegrationCapabilities } from './projection'\nimport { type HubHostConnect, useHubIntegrations } from './use-hub-integrations'\n\n/** Host-owned access state for one account, such as whether this agent can use it. */\nexport interface HubAccountStatus {\n label: string\n tone?: StatusTone\n}\n\n/**\n * Shows each connected account once, with its host status and one inline host\n * control. A separate tab offers providers without an account;\n * Manage opens permissions, Test, Disconnect and Connect another account.\n */\nexport interface HubIntegrationsAccounts {\n title: string\n description?: string\n /** Shown in the Accounts tab before any account exists. */\n emptyLabel?: string\n getStatus?: (connection: HubConnection) => HubAccountStatus | undefined\n /** The host authorizes this control and supplies its new status only after its server confirms. */\n getPrimaryAction?: (connection: HubConnection) => IntegrationDisplayAction | undefined\n /** Host-owned rows rendered after the accounts, such as access to an account that is no longer connected. */\n footer?: ReactNode\n}\n\nexport interface HubIntegrationsPanelProps {\n identity: HubIntegrationsIdentity\n client: HubIntegrationsClient\n can: HubIntegrationCapabilities\n callbackPath: string\n title?: string\n /** Compact, icon-led tiles or descriptive cards. Defaults to cards. */\n layout?: IntegrationsCatalogProps['layout']\n className?: string\n onRequestIntegration?: (prefill: string) => void\n onUnsupportedConnect?: (provider: HubProvider) => void\n /**\n * App-owned connection for these providers, such as a number the app\n * provisions itself. Their catalog rows stay visible and connectable, and\n * choosing one calls `onConnect` instead of running a Hub flow.\n */\n hostConnect?: HubHostConnect\n /** Host-owned context and actions; the host authorizes and confirms their effects. */\n getConnectionContext?: (connection: HubConnection) => string | undefined\n getConnectionActions?: (connection: HubConnection) => readonly IntegrationDisplayAction[]\n accounts?: HubIntegrationsAccounts\n /** Host-owned, transient fields for providers that require API-key metadata. */\n renderApiKeyMetadata?: (input: {\n provider: HubProvider\n value: HubApiKeyConnectionMetadata | undefined\n onChange: (value: HubApiKeyConnectionMetadata | undefined) => void\n }) => ReactNode\n}\n\n/** The connection states a tile shows, in the shared StatusPill vocabulary. */\nexport type HubConnectionState = 'connected' | 'not_connected' | 'error' | 'pending'\n\nconst CONNECTION_TONES: Record<HubConnectionState, StatusTone> = {\n connected: 'success',\n not_connected: 'neutral',\n error: 'danger',\n pending: 'warning',\n}\n\n/**\n * The one mapping from connection state to StatusPill tone. Amber means\n * pending only: \"Not connected\" is neutral, never warning.\n */\nexport function connectionTone(state: HubConnectionState): StatusTone {\n return CONNECTION_TONES[state]\n}\n\n/** The state and label a Hub connection's tile shows. */\nexport function hubConnectionStatus(connection: Pick<HubConnection, 'status' | 'health'>): { state: HubConnectionState; label: string; tone: StatusTone } {\n const status = (state: HubConnectionState, label: string) => ({ state, label, tone: connectionTone(state) })\n if (connection.status === 'revoked') return status('not_connected', 'Not connected')\n if (connection.status === 'reconnect_required') return status('error', 'Reconnect required')\n if (connection.status === 'unhealthy' || connection.health === 'unhealthy') return status('error', 'Needs attention')\n if (connection.health === 'rate_limited') return status('pending', 'Rate limited')\n return status('connected', 'Connected')\n}\n\nfunction catalogHref(): string {\n if (typeof window === 'undefined') return '/'\n const url = new URL(window.location.href)\n url.searchParams.delete('integration')\n url.searchParams.delete('connection')\n return `${url.pathname}${url.search}${url.hash}`\n}\n\nfunction accountName(connection: HubConnection, providerTitle: string): string {\n return connection.accountDisplay?.trim() || connection.displayName?.trim() || providerTitle\n}\n\nfunction AccountStatus({ connection, accounts }: { connection: HubConnection; accounts: HubIntegrationsAccounts }) {\n const status = accounts.getStatus?.(connection)\n return status ? <StatusPill tone={status.tone ?? 'neutral'} size=\"sm\" className=\"max-w-full whitespace-normal\">{status.label}</StatusPill> : null\n}\n\nfunction AccountPrimaryAction({ connection, accounts, busy }: { connection: HubConnection; accounts: HubIntegrationsAccounts; busy: boolean }) {\n const primary = accounts.getPrimaryAction?.(connection)\n return primary ? <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={busy || primary.disabled}\n onClick={primary.onSelect}>{primary.label}</Button> : null\n}\n\nfunction HubAccountList({ accounts, connections, providers, loading, error, busy, onRetry, onManage, canManage, onAdd }: {\n accounts: HubIntegrationsAccounts\n connections: readonly HubConnection[]\n providers: readonly HubProvider[]\n loading: boolean\n error: string | null\n busy: boolean\n onRetry: () => void\n onManage: (connection: HubConnection) => void\n canManage: (connection: HubConnection) => boolean\n onAdd: () => void\n}) {\n const [query, setQuery] = useState('')\n const titles = new Map(providers.map(provider => [provider.providerId, provider.title]))\n const title = (connection: HubConnection) => titles.get(connection.providerId) ?? connection.displayName ?? connection.providerId\n const rows = connections.filter(connection => connection.status !== 'revoked')\n .map(connection => ({ connection, provider: title(connection), name: accountName(connection, title(connection)) }))\n .sort((a, b) => a.provider.localeCompare(b.provider) || a.name.localeCompare(b.name) || a.connection.id.localeCompare(b.connection.id))\n const matching = rows.filter(row => `${row.provider} ${row.name}`.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()))\n return <section className=\"min-w-0 space-y-4\" aria-labelledby=\"hub-accounts-heading\" aria-busy={loading || undefined}>\n <header>\n <h2 id=\"hub-accounts-heading\" className=\"sr-only\">{accounts.title}</h2>\n {accounts.description ? <p className=\"text-sm text-muted-foreground\">{accounts.description}</p> : null}\n </header>\n {rows.length > 0 && !error ? <Input type=\"search\" aria-label=\"Search accounts\" placeholder=\"Search accounts…\" value={query} onChange={event => setQuery(event.target.value)} /> : null}\n {error ? <div role=\"alert\" className=\"flex flex-wrap items-center gap-3 rounded-xl border border-destructive/40 p-4 text-sm text-destructive\">\n <p className=\"min-w-0 flex-1 break-words\">{error}</p>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onRetry}>Retry</Button>\n </div> : loading && rows.length === 0 ? <p role=\"status\" className=\"py-4 text-sm text-muted-foreground\">Loading connected accounts…</p>\n : rows.length === 0 ? <Card data-slot=\"card\" className=\"space-y-3 p-5\"><p className=\"text-sm text-muted-foreground\">{accounts.emptyLabel ?? 'No accounts connected yet.'}</p><Button type=\"button\" variant=\"outline\" onClick={onAdd}>Add integration</Button></Card>\n : matching.length === 0 ? <p role=\"status\" className=\"py-6 text-sm text-muted-foreground\">No accounts match your search.</p>\n : <ul className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\" aria-label={accounts.title}>\n {matching.map(({ connection, provider, name }) => {\n const state = hubConnectionStatus(connection)\n return <li key={connection.id} data-testid={`hub-account-${connection.id}`} className=\"min-w-0\">\n <Card data-slot=\"card\" data-connection-state={state.state} className=\"flex h-full min-w-0 flex-col gap-4 p-4\">\n <div className=\"flex min-w-0 items-center gap-4\">\n <div className=\"flex size-16 shrink-0 items-center justify-center rounded-xl bg-muted/50\"><ProviderIcon id={connection.providerId} displayName={provider} size={48} className=\"shrink-0 rounded-lg\" /></div>\n <div className=\"min-w-0\">\n <p className=\"text-base font-semibold [overflow-wrap:anywhere]\">{provider}</p>\n <StatusPill tone={state.tone} size=\"sm\" className=\"mt-1\">{state.label}</StatusPill>\n </div>\n </div>\n <p className=\"text-sm font-medium [overflow-wrap:anywhere]\">{name}</p>\n <div className=\"mt-auto space-y-4\">\n <AccountStatus connection={connection} accounts={accounts} />\n <div className=\"flex flex-wrap items-center gap-2 border-t border-border pt-3\">\n <AccountPrimaryAction connection={connection} accounts={accounts} busy={busy} />\n {canManage(connection) ? <Button type=\"button\" variant=\"outline\" size=\"sm\" aria-label={`Manage ${provider} account ${name}`}\n onClick={() => onManage(connection)}>Manage</Button> : null}\n </div>\n </div>\n </Card>\n </li>\n })}\n </ul>}\n {accounts.footer}\n </section>\n}\n\n/** Embeddable settings surface. The app supplies authenticated transport and grants. */\nexport function HubIntegrationsPanel(props: HubIntegrationsPanelProps) {\n const hub = useHubIntegrations(props)\n const scope = contextKey(props.identity)\n const activeScope = useRef(scope)\n activeScope.current = scope\n const activeDialog = useRef(hub.dialog)\n activeDialog.current = hub.dialog\n const [query, setQuery] = useState('')\n const [category, setCategory] = useState('')\n const [sort, setSort] = useState<IntegrationSort>('featured')\n const [view, setView] = useState<{ scope: string; value: 'accounts' | 'catalog' } | null>(null)\n const [catalogSelection, setCatalogSelection] = useState<{ scope: string; ids: Record<string, string | null> }>({ scope, ids: {} })\n const [keyInput, setKeyInput] = useState({ scope, value: '' })\n const apiKey = keyInput.scope === scope ? keyInput.value : ''\n const setApiKey = (value: string) => setKeyInput({ scope, value })\n const [metadataInput, setMetadataInput] = useState<{ scope: string; value: HubApiKeyConnectionMetadata | undefined }>({ scope, value: undefined })\n const metadata = metadataInput.scope === scope ? metadataInput.value : undefined\n const setMetadata = (value: HubApiKeyConnectionMetadata | undefined) => setMetadataInput({ scope, value })\n const [parameterInput, setParameterInput] = useState({ scope, values: {} as Record<string, string> })\n const parameters = parameterInput.scope === scope ? parameterInput.values : {}\n const setParameters = (values: Record<string, string>) => setParameterInput({ scope, values })\n\n useEffect(() => { setApiKey(''); setMetadata(undefined); setParameters({}) }, [scope])\n const pending = hub.writeState.status === 'pending' || hub.connectStatus.status === 'pending'\n const error = hub.providers.status === 'error' ? hub.providers.message\n : hub.connections.status === 'error' ? hub.connections.message : null\n const mutationError = hub.writeState.status === 'failed' ? hub.writeState.message : null\n const writeMessage = hub.writeState.status === 'succeeded' ? hub.writeState.value.message : null\n const writeWarning = hub.writeState.status === 'succeeded' && hub.writeState.value.reconciliation === 'refresh-failed'\n const rows = hub.rows.map(row => {\n const selectedId = catalogSelection.scope === scope ? catalogSelection.ids[row.providerId] : null\n return {\n ...row,\n selectedConnectionId: row.connections.some(connection => connection.id === selectedId) ? selectedId ?? null : null,\n connections: row.connections.map(connection => {\n const source = hub.connections.status === 'ready'\n ? hub.connections.value.find(item => item.id === connection.id) : undefined\n return source ? {\n ...connection,\n detail: props.getConnectionContext?.(source) ?? connection.detail,\n actions: props.getConnectionActions?.(source),\n } : connection\n }),\n }\n })\n const selectedRow = rows.find(row => row.providerId === hub.provider?.providerId)\n const connectionList = hub.connections.status === 'ready' ? hub.connections.value : []\n const accountCount = connectionList.filter(connection => connection.status !== 'revoked').length\n const activeView = view?.scope === scope ? view.value : hub.connections.status === 'ready' && accountCount === 0 ? 'catalog' : 'accounts'\n const showAccounts = () => setView({ scope, value: 'accounts' })\n useEffect(() => {\n if (hub.connectStatus.status === 'connected') showAccounts()\n }, [hub.connectStatus.status, scope])\n // With an account list, the catalog offers providers without a connected account.\n // The Hub keeps revoked connections listed; a provider with only those is connectable again.\n const connectedProviders = new Set(connectionList.filter(connection => connection.status !== 'revoked').map(connection => connection.providerId))\n const catalogRows = props.accounts && hub.connections.status === 'error' ? [] : props.accounts\n ? rows.filter(row => !connectedProviders.has(row.providerId)).map(row => ({ ...row, connections: [], selectedConnectionId: null }))\n : rows\n const selectedConnection = hub.connection\n const detailError = hub.detail.status === 'error' ? hub.detail.message\n : hub.detail.status === 'ready' && hub.detail.value.truncated\n ? `Showing at most ${hub.detail.value.tools.length} actions. The provider catalog may be incomplete.` : null\n const detailsByConnectionId = useMemo(() => hub.connection ? {\n [hub.connection.id]: {\n ...hub.details,\n loading: hub.detail.status === 'loading',\n busy: pending,\n error: detailError,\n },\n } : {}, [hub.connection, hub.details, hub.detail.status, pending, detailError])\n\n const closeDialog = () => {\n if (hub.connectStatus.status === 'pending') hub.cancelConnect()\n else hub.setDialog(null)\n setApiKey(''); setMetadata(undefined); setParameters({})\n }\n\n const catalog = <IntegrationsCatalog\n title={props.title ?? 'Integrations'} layout={props.layout} rows={catalogRows}\n query={query} onQueryChange={setQuery} categoryFilter={category} onCategoryFilterChange={setCategory}\n sort={sort} onSortChange={setSort}\n onSelectConnection={(providerId, connectionId) => setCatalogSelection(current => ({\n scope, ids: { ...(current.scope === scope ? current.ids : {}), [providerId]: connectionId },\n }))}\n onConnect={row => { const provider = hub.providers.status === 'ready' ? hub.providers.value.find(item => item.providerId === row.providerId) : null; if (provider) hub.beginConnect(provider) }}\n onManage={(connection, row) => hub.selectConnection(row.providerId, connection.id)}\n onDisconnect={connection => { void hub.revoke(connection.id) }}\n onRequestIntegration={props.onRequestIntegration} onRetry={() => hub.refresh()}\n loading={hub.providers.status === 'loading' || hub.connections.status === 'loading'} error={error}\n actionError={mutationError} connectError={hub.connectStatus.status === 'failed' ? hub.connectStatus.message : null}\n busyProviderId={hub.connectStatus.status === 'pending' ? hub.connectStatus.providerId ?? null : null}\n reserveConnectionContext\n emptyCatalogLabel={props.accounts && rows.length > 0 ? 'Every available integration has a connected account. Manage an account to connect another.' : undefined}\n />\n\n return <section className={props.className}>\n {hub.connectStatus.status === 'pending' ? <div role=\"status\" className=\"mb-4 flex flex-wrap items-center gap-3\">\n <span>Finish connecting in the popup.</span>\n <Button type=\"button\" variant=\"outline\" onClick={hub.cancelConnect}>Cancel connection</Button>\n </div> : null}\n {hub.writeState.status === 'pending' ? <p role=\"status\">Saving Hub settings…</p> : null}\n {mutationError ? <p role=\"alert\">{mutationError}</p> : null}\n {writeMessage ? <p role={writeWarning ? 'alert' : 'status'}>{writeMessage}</p> : null}\n {hub.connectStatus.message && hub.provider ? <p role={hub.connectStatus.status === 'failed' ? 'alert' : 'status'}>{hub.connectStatus.message}</p> : null}\n {hub.provider ? <>\n {(props.accounts && selectedConnection) || selectedRow?.canConnect ? <div className=\"mb-4 flex min-w-0 flex-wrap items-center gap-2\">\n {props.accounts && selectedConnection ? <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" data-testid=\"hub-account-access\"\n aria-label={`Access for ${accountName(selectedConnection, hub.provider.title)}`} role=\"group\">\n <span className=\"min-w-0 max-w-full truncate text-sm font-medium\">{accountName(selectedConnection, hub.provider.title)}</span>\n <AccountStatus connection={selectedConnection} accounts={props.accounts} />\n <AccountPrimaryAction connection={selectedConnection} accounts={props.accounts} busy={pending} />\n </div> : null}\n {selectedRow?.canConnect ? <Button type=\"button\" variant=\"outline\" className=\"ml-auto\" disabled={pending}\n onClick={() => hub.beginConnect(hub.provider!)}>Connect another account</Button> : null}\n </div> : null}\n <IntegrationConnectionDetail\n provider={displayProvider(hub.provider)}\n connections={selectedRow?.connections ?? []}\n selectedConnectionId={hub.connection?.id ?? null}\n onSelectConnection={connectionId => hub.selectConnection(hub.provider!.providerId, connectionId)}\n detailsByConnectionId={detailsByConnectionId}\n loading={hub.connections.status === 'loading' || hub.detail.status === 'loading'}\n error={detailError}\n backHref={catalogHref()}\n onRetry={() => hub.refresh()}\n onTestConnection={connectionId => { void hub.test(connectionId) }}\n onDisconnect={connectionId => { void hub.revoke(connectionId) }}\n onDecisionChange={(connectionId, actionPath, decision) => {\n if (decision !== 'allow' && decision !== 'ask' && decision !== 'deny') return\n void hub.setDecision(connectionId, actionPath, decision)\n }}\n onResetDecision={(connectionId, actionPath) => { void hub.resetDecision(connectionId, actionPath) }}\n />\n </> : <>\n {props.accounts ? <Tabs value={activeView} onValueChange={value => setView({ scope, value: value === 'catalog' ? 'catalog' : 'accounts' })}>\n <TabsList aria-label=\"Integration views\" className=\"mb-5 grid h-auto w-full grid-cols-2 sm:inline-flex sm:w-auto\">\n <TabsTrigger value=\"accounts\">Accounts{' '}{hub.connections.status === 'ready' ? <span className=\"ml-2 tabular-nums text-muted-foreground\">{accountCount}</span> : null}</TabsTrigger>\n <TabsTrigger value=\"catalog\">Add integration{' '}{hub.providers.status === 'ready' && hub.connections.status === 'ready' ? <span className=\"ml-2 tabular-nums text-muted-foreground\">{catalogRows.length}</span> : null}</TabsTrigger>\n </TabsList>\n <TabsContent value=\"accounts\">\n {hub.connectStatus.status === 'connected' && hub.connectStatus.message ? <p role=\"status\" className=\"mb-3 text-sm\">{hub.connectStatus.message}</p> : null}\n <HubAccountList key={scope} accounts={props.accounts} connections={connectionList} providers={hub.providers.status === 'ready' ? hub.providers.value : []}\n loading={hub.connections.status === 'loading'} error={hub.connections.status === 'error' ? hub.connections.message : null} busy={pending}\n onRetry={() => hub.refresh()} onManage={connection => hub.selectConnection(connection.providerId, connection.id)}\n canManage={connection => props.can({ operation: 'policies.list', connectionId: connection.id })}\n onAdd={() => setView({ scope, value: 'catalog' })} />\n </TabsContent>\n <TabsContent value=\"catalog\">{catalog}</TabsContent>\n </Tabs> : catalog}\n </>}\n {hub.dialog?.kind === 'api-key' ? <ApiKeyConnectDialog\n open\n onOpenChange={open => { if (!open) closeDialog() }}\n providerId={hub.dialog.provider.providerId}\n title={hub.dialog.provider.title}\n description={hub.dialog.provider.authHint}\n value={apiKey}\n onValueChange={setApiKey}\n busy={pending}\n error={mutationError}\n canSubmit={apiKey.trim().length > 0 && !pending}\n onSubmit={() => {\n const secret = apiKey\n const target = hub.dialog?.provider.providerId\n const submittedDialog = hub.dialog\n setApiKey('')\n if (target) void hub.submitApiKey(target, secret, metadata).then(result => {\n if (result.succeeded && activeScope.current === scope && activeDialog.current === submittedDialog) {\n hub.setDialog(null); setMetadata(undefined); showAccounts()\n }\n })\n }}\n >{props.renderApiKeyMetadata?.({ provider: hub.dialog.provider, value: metadata, onChange: setMetadata })}</ApiKeyConnectDialog> : null}\n {hub.dialog?.kind === 'oauth' ? <OAuthConnectionParameterDialog\n open\n onOpenChange={open => { if (!open) closeDialog() }}\n providerId={hub.dialog.provider.providerId}\n title={hub.dialog.provider.title}\n parameters={hub.dialog.provider.connectionParameters ?? []}\n values={parameters}\n onValueChange={(key, value) => setParameters({ ...parameters, [key]: value })}\n busy={pending}\n error={hub.connectStatus.status === 'failed' ? hub.connectStatus.message : null}\n canSubmit={!pending && (hub.dialog.provider.connectionParameters ?? []).every(field => !field.required || !!parameters[field.key]?.trim())}\n onSubmit={() => {\n const target = hub.dialog?.provider\n const submittedDialog = hub.dialog\n if (target) void hub.startOAuth(target, parameters).then(result => {\n if (result === 'connected' && activeScope.current === scope && activeDialog.current === submittedDialog) setParameters({})\n })\n }}\n /> : null}\n </section>\n}\n","import type { HubConnection, HubPolicy, HubProvider, HubTool } from '@tangle-network/hub-sdk'\nimport type {\n IntegrationConnectionDetails,\n IntegrationDisplayProvider,\n IntegrationPermissionDisplay,\n IntegrationPermissionGroup,\n IntegrationsProviderRow,\n} from '@tangle-network/sandbox-ui/integrations'\n\nexport type HubIntegrationCapability =\n | { operation: 'oauth.start' | 'api-key.connect'; providerId: string }\n | { operation: 'connection.revoke' | 'connection.health' | 'policies.list'; connectionId: string }\n | { operation: 'policy.set' | 'policy.reset'; connectionId: string; actionPath: string }\n\n/** Display hints only. `createHubSettingsRoutes.authorize` remains authoritative. */\nexport type HubIntegrationCapabilities = (intent: HubIntegrationCapability) => boolean\n\nexport const ACTION_LIMIT = 200\n\nexport function contextKey(identity: { userId: string; sessionId: string; workspaceId: string }): string {\n return JSON.stringify([identity.userId, identity.sessionId, identity.workspaceId])\n}\n\nexport function displayProvider(provider: HubProvider): IntegrationDisplayProvider {\n return { providerId: provider.providerId, title: provider.title, category: provider.category }\n}\n\nexport function catalogRows(\n providers: readonly HubProvider[],\n connections: readonly HubConnection[],\n selectedIds: Readonly<Record<string, string | null>>,\n can: HubIntegrationCapabilities,\n hasUnsupportedConnect = false,\n hostConnectProviderIds: readonly string[] = [],\n): IntegrationsProviderRow[] {\n return providers.map(provider => {\n const accounts = connections.filter(connection => connection.providerId === provider.providerId)\n return {\n ...displayProvider(provider),\n kind: 'provider',\n authKind: provider.authKind,\n selectedConnectionId: accounts.some(account => account.id === selectedIds[provider.providerId])\n ? selectedIds[provider.providerId] ?? null : null,\n canConnect: hostConnectProviderIds.includes(provider.providerId) ? true : provider.authKind === 'oauth2'\n ? provider.configured && can({ operation: 'oauth.start', providerId: provider.providerId })\n : provider.authKind === 'api_key'\n ? provider.configured && can({ operation: 'api-key.connect', providerId: provider.providerId })\n : hasUnsupportedConnect,\n connections: accounts.map(connection => ({\n id: connection.id,\n accountDisplay: connection.accountDisplay ?? connection.displayName,\n statusLabel: connection.status === 'active' ? 'Connected' : connection.status.replaceAll('_', ' '),\n statusTone: connection.status === 'active' && connection.health !== 'unhealthy' ? 'success' : 'warning',\n detail: connection.providerAccountId ?? undefined,\n capabilities: {\n manage: can({ operation: 'policies.list', connectionId: connection.id }),\n disconnect: can({ operation: 'connection.revoke', connectionId: connection.id }),\n test: can({ operation: 'connection.health', connectionId: connection.id }),\n editPermissions: can({ operation: 'policies.list', connectionId: connection.id }),\n resetPermissions: can({ operation: 'policies.list', connectionId: connection.id }),\n },\n })),\n }\n })\n}\n\nconst OPTIONS = [\n { value: 'allow', label: 'Allow' },\n { value: 'ask', label: 'Ask' },\n { value: 'deny', label: 'Deny' },\n] as const\n\n/** Stored overrides are shown; app-specific effective policy is never guessed. */\nexport function permissionDetails(\n tools: readonly HubTool[],\n policies: readonly HubPolicy[],\n connectionId: string,\n can: HubIntegrationCapabilities,\n): IntegrationConnectionDetails {\n const overrides = new Map(policies.filter(policy => policy.connectionId === connectionId).map(policy => [policy.actionPath, policy.decision]))\n const groups: IntegrationPermissionGroup[] = [\n { id: 'writes', title: 'Write and unknown actions', rows: [] },\n { id: 'reads', title: 'Read actions', collapsed: true, rows: [] },\n ]\n const writes: IntegrationPermissionDisplay[] = []\n const reads: IntegrationPermissionDisplay[] = []\n for (const tool of tools) {\n const override = overrides.get(tool.path)\n const row = {\n actionPath: tool.path,\n title: tool.title ?? tool.path,\n riskLabel: tool.risk ?? 'unknown',\n riskTone: tool.risk === 'destructive' ? 'error' : tool.risk === 'write' || tool.risk === undefined ? 'warning' : 'neutral',\n decision: override ?? null,\n decisionOptions: OPTIONS,\n sourceLabel: override ? 'Stored override' : 'No stored override',\n canReset: override !== undefined && can({ operation: 'policy.reset', connectionId, actionPath: tool.path }),\n disabled: !can({ operation: 'policy.set', connectionId, actionPath: tool.path }),\n } as const\n if (tool.risk === 'read') reads.push(row)\n else writes.push(row)\n }\n writes.sort((a, b) => a.title.localeCompare(b.title))\n reads.sort((a, b) => a.title.localeCompare(b.title))\n groups[0] = { ...groups[0]!, rows: writes }\n groups[1] = { ...groups[1]!, rows: reads }\n return { permissionGroups: groups }\n}\n","import type { HubApiKeyConnectionMetadata, HubConnection, HubPolicyDecision, HubProvider } from '@tangle-network/hub-sdk'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { confirmWrite, useAsyncResource, useConfirmedMutation } from '../web-react/async'\nimport type { HubIntegrationsClient, HubIntegrationsIdentity } from './client'\nimport { connectWithPopup, type PopupConnectResult } from './popup'\nimport { ACTION_LIMIT, catalogRows, contextKey, permissionDetails, type HubIntegrationCapabilities } from './projection'\n\ntype Selection = { scope: string; providerId: string | null; connectionId: string | null }\ntype Dialog = { scope: string; kind: 'api-key' | 'oauth'; provider: HubProvider } | null\n\nexport interface UseHubIntegrationsOptions {\n identity: HubIntegrationsIdentity\n client: HubIntegrationsClient\n /** Display only. The host server must authorize every exact operation. */\n can: HubIntegrationCapabilities\n /** Local app route that renders `HubConnectCallbackPage`. */\n callbackPath: string\n /** Optional host handler for custom/native signup. No Platform redirect is assumed. */\n onUnsupportedConnect?: (provider: HubProvider) => void\n /**\n * App-owned connection for these providers, such as a number the app\n * provisions itself. Their catalog rows stay visible and connectable, and\n * choosing one calls `onConnect` instead of running a Hub flow.\n */\n hostConnect?: HubHostConnect\n}\n\nexport interface HubHostConnect {\n providerIds: readonly string[]\n onConnect: (provider: HubProvider) => void\n}\n\ntype WriteInput =\n | { kind: 'api-key'; identity: HubIntegrationsIdentity; scope: string; providerId: string; apiKey: string; metadata?: HubApiKeyConnectionMetadata }\n | { kind: 'revoke'; identity: HubIntegrationsIdentity; scope: string; connectionId: string }\n | { kind: 'health'; identity: HubIntegrationsIdentity; scope: string; connectionId: string }\n | { kind: 'set'; identity: HubIntegrationsIdentity; scope: string; connectionId: string; actionPath: string; decision: HubPolicyDecision }\n | { kind: 'reset'; identity: HubIntegrationsIdentity; scope: string; connectionId: string; actionPath: string }\n\nexport interface HubWriteReceipt {\n scope: string\n kind: WriteInput['kind']\n reconciliation: 'verified' | 'refresh-failed'\n message: string\n}\n\nfunction initialSelection(scope: string): Selection {\n if (typeof window === 'undefined') return { scope, providerId: null, connectionId: null }\n const query = new URL(window.location.href).searchParams\n return { scope, providerId: query.get('integration'), connectionId: query.get('connection') }\n}\n\nfunction updateUrl(providerId: string | null, connectionId: string | null): void {\n if (typeof window === 'undefined') return\n const url = new URL(window.location.href)\n if (providerId) url.searchParams.set('integration', providerId)\n else url.searchParams.delete('integration')\n if (connectionId) url.searchParams.set('connection', connectionId)\n else url.searchParams.delete('connection')\n window.history.pushState(window.history.state, '', url)\n}\n\n/** Identity-bound Hub settings controller; connection state is always server-read. */\nexport function useHubIntegrations({ identity, client, can, callbackPath, onUnsupportedConnect, hostConnect }: UseHubIntegrationsOptions) {\n const scope = contextKey(identity)\n const activeScope = useRef(scope)\n activeScope.current = scope\n const [selection, setSelection] = useState<Selection>(() => initialSelection(scope))\n const visibleSelection = selection.scope === scope ? selection : { scope, providerId: null, connectionId: null }\n const [dialog, setDialog] = useState<Dialog>(null)\n const visibleDialog = dialog?.scope === scope ? dialog : null\n const [connectStatus, setConnectStatus] = useState<{ scope: string; status: 'idle' | 'pending' | 'connected' | 'failed'; providerId?: string; message?: string }>({ scope, status: 'idle' })\n const [writeScope, setWriteScope] = useState(scope)\n const pendingPopup = useRef<AbortController | null>(null)\n\n useEffect(() => {\n const onPop = () => setSelection(initialSelection(scope))\n window.addEventListener('popstate', onPop)\n return () => window.removeEventListener('popstate', onPop)\n }, [scope])\n\n const providers = useAsyncResource({ load: ({ signal }) => client.providers(identity, signal), deps: [client, scope], isEmpty: () => false })\n const connections = useAsyncResource({ load: ({ signal }) => client.connections(identity, signal), deps: [client, scope], isEmpty: () => false })\n const providerList = providers.status === 'ready' ? providers.value : []\n const connectionList = connections.status === 'ready' ? connections.value : []\n const provider = providerList.find(item => item.providerId === visibleSelection.providerId) ?? null\n const connection = connectionList.find(item => item.id === visibleSelection.connectionId && item.providerId === provider?.providerId) ?? null\n const canReadPolicies = connection !== null && can({ operation: 'policies.list', connectionId: connection.id })\n const detail = useAsyncResource({\n enabled: canReadPolicies && connection?.status === 'active',\n deps: [client, scope, provider?.providerId, connection?.id, canReadPolicies],\n isEmpty: () => false,\n load: async ({ signal }) => {\n if (!provider || !connection) throw new Error('Choose a connection.')\n const [tools, policies] = await Promise.all([\n client.actions(identity, provider.providerId, ACTION_LIMIT, signal),\n client.policies(identity, connection.id, signal),\n ])\n if (tools.some(tool => !tool.path.startsWith(`${provider.providerId}.`)) || policies.some(policy => policy.connectionId !== connection.id)) {\n throw new Error('Hub settings response changed connection or provider.')\n }\n return { tools, policies, truncated: tools.length >= ACTION_LIMIT }\n },\n })\n\n const write = useConfirmedMutation<WriteInput, HubWriteReceipt>({\n concurrency: 'reject',\n mutate: async (input, { signal }) => {\n if (input.scope !== activeScope.current) throw new Error('Integration context changed. Retry in the current workspace.')\n const origin = input.identity\n const receipt = (reconciliation: HubWriteReceipt['reconciliation'], message: string) => confirmWrite<HubWriteReceipt>({ scope: input.scope, kind: input.kind, reconciliation, message })\n if (input.kind === 'api-key') {\n if (!can({ operation: 'api-key.connect', providerId: input.providerId })) throw new Error('Connection setup is unavailable.')\n const created = await client.connectApiKey(origin, input.providerId, input.apiKey, input.metadata, signal)\n if (created.providerId !== input.providerId || created.status !== 'active') throw new Error('Hub did not confirm the requested connection.')\n try {\n const current = await client.connections(origin, signal)\n return current.some(item => item.id === created.id && item.status === 'active')\n ? receipt('verified', 'Connection saved and verified.') : receipt('refresh-failed', 'Connection saved; current account state could not be confirmed.')\n } catch { return receipt('refresh-failed', 'Connection saved; refresh failed.') }\n }\n if (input.kind === 'revoke') {\n if (!can({ operation: 'connection.revoke', connectionId: input.connectionId })) throw new Error('Disconnect is unavailable.')\n await client.revoke(origin, input.connectionId, signal)\n try {\n const current = await client.connections(origin, signal)\n return current.some(item => item.id === input.connectionId && item.status === 'active')\n ? receipt('refresh-failed', 'Disconnected, but the current account state disagrees.') : receipt('verified', 'Connection disconnected and verified.')\n } catch { return receipt('refresh-failed', 'Disconnected; refresh failed.') }\n }\n if (input.kind === 'health') {\n if (!can({ operation: 'connection.health', connectionId: input.connectionId })) throw new Error('Connection test is unavailable.')\n const result = await client.health(origin, input.connectionId, signal)\n if (result.connection.id !== input.connectionId) throw new Error('Hub returned another connection.')\n return receipt('verified', `Connection test: ${result.health.status.replaceAll('_', ' ')}.`)\n }\n if (!can({ operation: input.kind === 'set' ? 'policy.set' : 'policy.reset', connectionId: input.connectionId, actionPath: input.actionPath })) {\n throw new Error('Permission editing is unavailable.')\n }\n if (input.kind === 'set') {\n const stored = await client.setPolicy(origin, input.connectionId, input.actionPath, input.decision, signal)\n if (stored.connectionId !== input.connectionId || stored.actionPath !== input.actionPath || stored.decision !== input.decision) {\n throw new Error('Hub did not confirm the requested permission.')\n }\n } else await client.resetPolicy(origin, input.connectionId, input.actionPath, signal)\n try {\n const current = await client.policies(origin, input.connectionId, signal)\n const override = current.find(policy => policy.actionPath === input.actionPath)\n const matches = input.kind === 'set' ? override?.decision === input.decision : override === undefined\n return matches\n ? receipt('verified', 'Permission saved and verified.') : receipt('refresh-failed', 'Permission write was accepted; current policy state disagrees.')\n } catch { return receipt('refresh-failed', 'Permission write was accepted; refresh failed.') }\n },\n onSucceeded: value => { if (value.scope === activeScope.current) { connections.retry(); detail.retry() } },\n })\n\n useEffect(() => {\n pendingPopup.current?.abort()\n pendingPopup.current = null\n setDialog(null)\n setConnectStatus({ scope, status: 'idle' })\n setWriteScope(scope)\n write.reset()\n return () => { pendingPopup.current?.abort(); pendingPopup.current = null }\n }, [scope, client, write.reset])\n\n const selectProvider = useCallback((providerId: string | null) => {\n const next = { scope, providerId, connectionId: null }\n setSelection(next)\n updateUrl(providerId, null)\n }, [scope])\n\n const selectConnection = useCallback((providerId: string, connectionId: string | null) => {\n if (connectionId && !connectionList.some(item => item.id === connectionId && item.providerId === providerId)) return\n setSelection({ scope, providerId, connectionId })\n updateUrl(providerId, connectionId)\n }, [scope, connectionList])\n\n const startOAuth = useCallback(async (target: HubProvider, connectionParameters?: Record<string, string>): Promise<PopupConnectResult> => {\n if (!can({ operation: 'oauth.start', providerId: target.providerId })) return 'unavailable'\n if (connections.status !== 'ready') { setConnectStatus({ scope, status: 'failed', message: 'Load connections before connecting.' }); return 'unavailable' }\n pendingPopup.current?.abort()\n const controller = new AbortController()\n pendingPopup.current = controller\n setConnectStatus({ scope, status: 'pending', providerId: target.providerId })\n const result = await connectWithPopup({\n client, identity, providerId: target.providerId, before: connections.value,\n callbackPath, connectionParameters, signal: controller.signal,\n isCurrent: () => activeScope.current === scope && !controller.signal.aborted,\n })\n if (pendingPopup.current !== controller || activeScope.current !== scope) return result\n pendingPopup.current = null\n if (result === 'connected') {\n connections.retry()\n setDialog(null)\n setConnectStatus({ scope, status: 'connected', message: 'Connection verified.' })\n } else setConnectStatus({ scope, status: 'failed', message: result === 'blocked' ? 'Allow the popup and try again.' : result === 'unverified' ? 'Could not verify a new connection. Refresh and try again.' : result === 'cancelled' ? 'Connection was cancelled.' : 'This connection flow is unavailable.' })\n return result\n }, [can, connections, client, identity, callbackPath, scope])\n\n const beginConnect = useCallback((target: HubProvider) => {\n if (hostConnect?.providerIds.includes(target.providerId)) {\n hostConnect.onConnect(target)\n return\n }\n if (target.authKind !== 'api_key' && target.authKind !== 'oauth2') {\n if (onUnsupportedConnect) onUnsupportedConnect(target)\n else setConnectStatus({ scope, status: 'failed', message: 'This provider needs an app-specific connection flow.' })\n return\n }\n if (!target.configured) {\n setConnectStatus({ scope, status: 'failed', message: 'This provider is not configured for connection.' })\n return\n }\n if (target.authKind === 'api_key') {\n if (can({ operation: 'api-key.connect', providerId: target.providerId })) setDialog({ scope, kind: 'api-key', provider: target })\n else setConnectStatus({ scope, status: 'failed', message: 'Connection setup is unavailable.' })\n return\n }\n if (target.authKind === 'oauth2') {\n if (!can({ operation: 'oauth.start', providerId: target.providerId })) {\n setConnectStatus({ scope, status: 'failed', message: 'Connection setup is unavailable.' }); return\n }\n if (target.connectionParameters?.length) setDialog({ scope, kind: 'oauth', provider: target })\n else void startOAuth(target)\n return\n }\n }, [can, onUnsupportedConnect, hostConnect, scope, startOAuth])\n\n const cancelConnect = useCallback(() => {\n pendingPopup.current?.abort()\n pendingPopup.current = null\n setDialog(null)\n setConnectStatus({ scope, status: 'failed', message: 'Connection was cancelled.' })\n }, [scope])\n\n const rows = useMemo(() => catalogRows(providerList, connectionList, visibleSelection.providerId && visibleSelection.connectionId\n ? { [visibleSelection.providerId]: visibleSelection.connectionId } : {}, can, !!onUnsupportedConnect,\n hostConnect?.providerIds),\n [providerList, connectionList, visibleSelection.providerId, visibleSelection.connectionId, can, onUnsupportedConnect, hostConnect])\n const details = detail.status === 'ready' && connection\n ? permissionDetails(detail.value.tools, detail.value.policies, connection.id, can) : undefined\n\n return {\n providers, connections, detail, rows, provider, connection, dialog: visibleDialog, setDialog,\n connectStatus: connectStatus.scope === scope ? connectStatus : { scope, status: 'idle' as const, providerId: undefined },\n selection: visibleSelection, selectProvider, selectConnection, beginConnect, startOAuth, cancelConnect,\n write, writeState: writeScope === scope ? write.state : { status: 'idle' as const }, details,\n refresh: () => { providers.retry(); connections.retry(); detail.retry() },\n submitApiKey: (providerId: string, apiKey: string, metadata?: HubApiKeyConnectionMetadata) => { setWriteScope(scope); return write.run({ kind: 'api-key', identity, scope, providerId, apiKey, metadata }) },\n revoke: (connectionId: string) => { setWriteScope(scope); return write.run({ kind: 'revoke', identity, scope, connectionId }) },\n test: (connectionId: string) => { setWriteScope(scope); return write.run({ kind: 'health', identity, scope, connectionId }) },\n setDecision: (connectionId: string, actionPath: string, decision: HubPolicyDecision) => { setWriteScope(scope); return write.run({ kind: 'set', identity, scope, connectionId, actionPath, decision }) },\n resetDecision: (connectionId: string, actionPath: string) => { setWriteScope(scope); return write.run({ kind: 'reset', identity, scope, connectionId, actionPath }) },\n }\n}\n"],"mappings":"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","names":["useEffect","useMemo","useRef","useState","useEffect","useState","useState","useEffect","jsx","jsxs","useState","useRef","useEffect","catalogRows","useMemo"]}
|
|
1
|
+
{"version":3,"sources":["../../src/integrations-react/callback.tsx","../../src/integrations-react/popup.ts","../../src/integrations-react/client.ts","../../src/integrations-react/panel.tsx","../../src/integrations-react/projection.ts","../../src/integrations-react/use-hub-integrations.ts"],"sourcesContent":["import { useEffect, useState } from 'react'\nimport { HUB_CONNECTED_MESSAGE_TYPE, HUB_CONNECT_CHANNEL, HUB_CONNECT_FAILED_MESSAGE_TYPE, localAppUrl } from './popup'\n\nexport interface HubConnectCallbackPageProps {\n /** Local settings destination owned by the consuming app. */\n returnHref: string\n}\n\n/** The callback only signals completion; the opener verifies fresh Hub state. */\nexport function HubConnectCallbackPage({ returnHref }: HubConnectCallbackPageProps) {\n const [phase, setPhase] = useState<'checking' | 'returned' | 'failed'>('checking')\n const [reason, setReason] = useState('')\n\n useEffect(() => {\n const params = new URLSearchParams(window.location.search)\n const provider = params.get('provider')\n const nonce = params.get('nonce')\n const context = params.get('context')\n if (!provider || !nonce || !context) { setReason('This connection callback is incomplete.'); setPhase('failed'); return }\n const failure = params.get('error_description') || params.get('error')\n || (params.get('hub_connection') === 'error' ? params.get('hub_error') || 'Please restart the connection flow.' : null)\n try {\n const channel = new BroadcastChannel(HUB_CONNECT_CHANNEL)\n channel.postMessage({ type: failure ? HUB_CONNECT_FAILED_MESSAGE_TYPE : HUB_CONNECTED_MESSAGE_TYPE, provider, nonce, context })\n channel.close()\n } catch { /* The opener also polls the authoritative connection list. */ }\n if (failure) { setReason(failure.slice(0, 200)); setPhase('failed'); return }\n window.close()\n const timer = window.setTimeout(() => setPhase('returned'), 150)\n return () => window.clearTimeout(timer)\n }, [])\n\n const destination = localAppUrl(returnHref)\n const localReturn = destination ? `${destination.pathname}${destination.search}${destination.hash}` : '/'\n return <main aria-live=\"polite\" style={{ maxWidth: 560, margin: '20vh auto', padding: 24, textAlign: 'center' }}>\n {phase === 'checking' ? <p>Checking your connection…</p> : phase === 'returned'\n ? <p>Return to the app to check your connection. You can close this window.</p>\n : <p>Could not complete the connection. {reason}</p>}\n <a href={localReturn}>Return to integrations</a>\n </main>\n}\n","import type { HubConnection } from '@tangle-network/hub-sdk'\nimport type { HubIntegrationsClient, HubIntegrationsIdentity } from './client'\n\nexport const HUB_CONNECT_CHANNEL = 'tangle:hub-connect'\nexport const HUB_CONNECTED_MESSAGE_TYPE = 'tangle:hub-connected'\nexport const HUB_CONNECT_FAILED_MESSAGE_TYPE = 'tangle:hub-connect-failed'\nexport const POPUP_TIMEOUT_MS = 5 * 60 * 1000\nconst PRE_REDIRECT_TIMEOUT_MS = 30_000\nconst POLL_INTERVAL_MS = 2500\nconst POPUP_FEATURES = 'popup=yes,width=520,height=680'\n\nexport type PopupConnectResult = 'connected' | 'blocked' | 'failed' | 'cancelled' | 'unverified' | 'unavailable'\n\nexport function localAppUrl(path: string): URL | null {\n if (!path.startsWith('/') || path.startsWith('//')) return null\n try {\n const origin = typeof window === 'undefined' ? 'https://local.invalid' : window.location.origin\n const url = new URL(path, origin)\n return url.origin === origin && !url.username && !url.password ? url : null\n } catch { return null }\n}\n\nfunction updatedConnection(providerId: string, before: readonly HubConnection[], after: readonly HubConnection[]): boolean {\n const previous = new Map(before.filter(connection => connection.providerId === providerId).map(connection => [connection.id, connection]))\n return after.some(connection => {\n if (connection.providerId !== providerId || connection.status !== 'active' || connection.health === 'unhealthy') return false\n const old = previous.get(connection.id)\n return !old || old.updatedAt !== connection.updatedAt || old.status !== connection.status\n })\n}\n\nfunction closePopup(popup: Window): void {\n try { if (!popup.closed) popup.close() } catch { /* COOP may sever the handle. */ }\n}\n\nfunction withAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) { reject(new DOMException('Aborted', 'AbortError')); return }\n const onAbort = () => reject(new DOMException('Aborted', 'AbortError'))\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(value => { signal.removeEventListener('abort', onAbort); resolve(value) }, error => { signal.removeEventListener('abort', onAbort); reject(error) })\n })\n}\n\nfunction waitForConnection(input: {\n popup: Window\n client: HubIntegrationsClient\n identity: HubIntegrationsIdentity\n providerId: string\n before: readonly HubConnection[]\n nonce: string\n contextToken: string\n signal: AbortSignal\n isCurrent: () => boolean\n}): Promise<PopupConnectResult> {\n return new Promise(resolve => {\n let settled = false\n let checking = false\n let pollId: number | undefined\n let timeoutId: number | undefined\n let channel: BroadcastChannel | undefined\n const finish = (result: PopupConnectResult) => {\n if (settled) return\n settled = true\n if (pollId !== undefined) window.clearTimeout(pollId)\n if (timeoutId !== undefined) window.clearTimeout(timeoutId)\n input.signal.removeEventListener('abort', onAbort)\n channel?.close()\n closePopup(input.popup)\n resolve(result)\n }\n const onAbort = () => finish('cancelled')\n const check = async () => {\n if (settled || checking) return\n checking = true\n if (!input.isCurrent() || input.signal.aborted) { finish('cancelled'); return }\n try {\n const after = await input.client.connections(input.identity, input.signal)\n if (input.isCurrent() && updatedConnection(input.providerId, input.before, after)) { finish('connected'); return }\n } catch { /* A lost read is never evidence of a connection. Keep polling. */ }\n checking = false\n if (!settled) pollId = window.setTimeout(check, POLL_INTERVAL_MS)\n }\n if (input.signal.aborted) { finish('cancelled'); return }\n input.signal.addEventListener('abort', onAbort, { once: true })\n try {\n const candidate = new BroadcastChannel(HUB_CONNECT_CHANNEL)\n candidate.onmessage = event => {\n const message = event.data as Record<string, unknown> | null\n if (!message || message.provider !== input.providerId || message.nonce !== input.nonce || message.context !== input.contextToken) return\n if (message.type === HUB_CONNECT_FAILED_MESSAGE_TYPE) finish('failed')\n if (message.type === HUB_CONNECTED_MESSAGE_TYPE) {\n if (pollId !== undefined) window.clearTimeout(pollId)\n void check()\n }\n }\n channel = candidate\n } catch { /* Polling covers browsers without BroadcastChannel. */ }\n pollId = window.setTimeout(check, POLL_INTERVAL_MS)\n timeoutId = window.setTimeout(() => finish('unverified'), POPUP_TIMEOUT_MS)\n })\n}\n\n/** Opens before the first await, preserving the initiating user gesture. */\nexport async function connectWithPopup(input: {\n client: HubIntegrationsClient\n identity: HubIntegrationsIdentity\n providerId: string\n before: readonly HubConnection[]\n callbackPath: string\n connectionParameters?: Record<string, string>\n signal: AbortSignal\n isCurrent: () => boolean\n}): Promise<PopupConnectResult> {\n const callback = localAppUrl(input.callbackPath)\n if (!callback) throw new TypeError('Callback path must be local.')\n const popup = window.open('', '_blank', POPUP_FEATURES)\n if (!popup) return 'blocked'\n // Keep the parent handle for navigation while removing the provider page's opener.\n try { popup.opener = null } catch { /* Some browsers make this read-only. */ }\n const nonce = crypto.randomUUID()\n const contextToken = crypto.randomUUID()\n callback.searchParams.set('provider', input.providerId)\n callback.searchParams.set('nonce', nonce)\n callback.searchParams.set('context', contextToken)\n const timeout = new AbortController()\n const onAbort = () => timeout.abort()\n input.signal.addEventListener('abort', onAbort, { once: true })\n const preRedirectId = window.setTimeout(() => timeout.abort(), PRE_REDIRECT_TIMEOUT_MS)\n try {\n if (!input.isCurrent()) return 'cancelled'\n const start = await withAbort(input.client.startOAuth(input.identity, input.providerId, {\n returnUrl: callback.href,\n ...(input.connectionParameters === undefined ? {} : { connectionParameters: input.connectionParameters }),\n }, timeout.signal), timeout.signal)\n if (!input.isCurrent() || input.signal.aborted) return 'cancelled'\n let redirect: URL\n try { redirect = new URL(start.redirectUrl) } catch { return 'unavailable' }\n if (redirect.protocol !== 'https:' || redirect.username || redirect.password) return 'unavailable'\n window.clearTimeout(preRedirectId)\n const waitController = new AbortController()\n const abortWait = () => waitController.abort()\n input.signal.addEventListener('abort', abortWait, { once: true })\n if (input.signal.aborted) abortWait()\n const waiting = waitForConnection({ ...input, popup, nonce, contextToken, signal: waitController.signal })\n try {\n popup.location.href = redirect.href\n return await waiting\n } catch {\n waitController.abort()\n await waiting\n return 'unavailable'\n } finally {\n input.signal.removeEventListener('abort', abortWait)\n }\n } catch {\n return input.signal.aborted || timeout.signal.aborted ? 'cancelled' : 'unavailable'\n } finally {\n window.clearTimeout(preRedirectId)\n input.signal.removeEventListener('abort', onAbort)\n closePopup(popup)\n }\n}\n","import type {\n HubApiKeyConnectionMetadata,\n HubConnection,\n HubConnectionHealthResponse,\n HubOAuthStartResponse,\n HubPolicy,\n HubPolicyDecision,\n HubProvider,\n HubTool,\n} from '@tangle-network/hub-sdk'\n\n/** The host must bind each request to this server-verified identity. */\nexport interface HubIntegrationsIdentity {\n readonly userId: string\n readonly sessionId: string\n readonly workspaceId: string\n}\n\nexport interface HubSettingsRequest {\n readonly identity: HubIntegrationsIdentity\n readonly path: string\n readonly init: RequestInit\n}\n\n/**\n * The host supplies its authenticated fetch, CSRF protection and expected\n * identity check. The browser never receives a Hub credential or SDK client.\n */\nexport type HubSettingsRequestFn = (request: HubSettingsRequest) => Promise<Response>\n\nexport interface HubIntegrationsClient {\n providers(identity: HubIntegrationsIdentity, signal?: AbortSignal): Promise<HubProvider[]>\n connections(identity: HubIntegrationsIdentity, signal?: AbortSignal): Promise<HubConnection[]>\n startOAuth(identity: HubIntegrationsIdentity, providerId: string, input: { returnUrl: string; connectionParameters?: Record<string, string> }, signal?: AbortSignal): Promise<HubOAuthStartResponse>\n connectApiKey(identity: HubIntegrationsIdentity, providerId: string, apiKey: string, metadata?: HubApiKeyConnectionMetadata, signal?: AbortSignal): Promise<HubConnection>\n revoke(identity: HubIntegrationsIdentity, connectionId: string, signal?: AbortSignal): Promise<HubConnection>\n health(identity: HubIntegrationsIdentity, connectionId: string, signal?: AbortSignal): Promise<HubConnectionHealthResponse>\n actions(identity: HubIntegrationsIdentity, providerId: string, limit: number, signal?: AbortSignal): Promise<HubTool[]>\n policies(identity: HubIntegrationsIdentity, connectionId: string, signal?: AbortSignal): Promise<HubPolicy[]>\n setPolicy(identity: HubIntegrationsIdentity, connectionId: string, actionPath: string, decision: HubPolicyDecision, signal?: AbortSignal): Promise<HubPolicy>\n resetPolicy(identity: HubIntegrationsIdentity, connectionId: string, actionPath: string, signal?: AbortSignal): Promise<void>\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error('Invalid Hub settings response.')\n return value as Record<string, unknown>\n}\n\nfunction array(value: unknown): unknown[] {\n if (!Array.isArray(value)) throw new Error('Invalid Hub settings response.')\n return value\n}\n\nfunction namedArray<T>(value: unknown, key: string): T[] {\n const rows = array(object(value)[key])\n if (rows.some(row => row === null || typeof row !== 'object' || Array.isArray(row))) throw new Error('Invalid Hub settings response.')\n return rows as T[]\n}\n\nfunction namedObject<T>(value: unknown, key: string): T {\n return object(object(value)[key]) as T\n}\n\nfunction segment(value: string): string {\n if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value)) throw new TypeError('Invalid Hub settings identifier.')\n return encodeURIComponent(value)\n}\n\n/** Finite browser transport for the server-owned `createHubSettingsRoutes` API. */\nexport function createHubIntegrationsClient(request: HubSettingsRequestFn, basePath = '/api/hub/settings'): HubIntegrationsClient {\n if (!/^\\/(?:[A-Za-z0-9_-]+\\/)*[A-Za-z0-9_-]+$/.test(basePath)) throw new TypeError('Invalid Hub settings basePath.')\n\n async function call(identity: HubIntegrationsIdentity, path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE', signal?: AbortSignal, body?: object): Promise<unknown> {\n if (![identity.userId, identity.sessionId, identity.workspaceId].every(part => typeof part === 'string' && part.trim())) {\n throw new TypeError('Hub settings identity is required.')\n }\n const response = await request({\n identity,\n path: `${basePath}${path}`,\n init: { method, signal, ...(body === undefined ? {} : { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) },\n })\n if (!response.ok) {\n let code: string | undefined\n try {\n const error = object(await response.json())\n if (typeof error.code === 'string') code = error.code\n } catch { /* Status remains authoritative when a response is unreadable. */ }\n throw new Error(`Hub settings request failed (${response.status}${code ? `, ${code}` : ''}).`)\n }\n return response.json()\n }\n\n return {\n async providers(identity, signal) { return namedArray<HubProvider>(await call(identity, '/providers', 'GET', signal), 'providers') },\n async connections(identity, signal) { return namedArray<HubConnection>(await call(identity, '/connections', 'GET', signal), 'connections') },\n async startOAuth(identity, providerId, input, signal) {\n const response = object(await call(identity, `/connections/${segment(providerId)}/start`, 'POST', signal, input))\n if (typeof response.redirectUrl !== 'string') throw new Error('Invalid Hub OAuth response.')\n return response as unknown as HubOAuthStartResponse\n },\n async connectApiKey(identity, providerId, apiKey, metadata, signal) {\n return namedObject<HubConnection>(await call(identity, `/connections/${segment(providerId)}/connect-key`, 'POST', signal, { apiKey, ...(metadata === undefined ? {} : { metadata }) }), 'connection')\n },\n async revoke(identity, connectionId, signal) { return namedObject<HubConnection>(await call(identity, `/connections/${segment(connectionId)}`, 'DELETE', signal), 'connection') },\n async health(identity, connectionId, signal) {\n const response = object(await call(identity, `/connections/${segment(connectionId)}/health`, 'POST', signal))\n object(response.connection)\n object(response.health)\n return response as unknown as HubConnectionHealthResponse\n },\n async actions(identity, providerId, limit, signal) {\n if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new TypeError('Hub action limit must be 1–200.')\n const search = new URLSearchParams({ query: '', limit: String(limit) })\n return namedArray<HubTool>(await call(identity, `/providers/${segment(providerId)}/actions?${search}`, 'GET', signal), 'tools')\n },\n async policies(identity, connectionId, signal) {\n const search = new URLSearchParams({ connectionId })\n return namedArray<HubPolicy>(await call(identity, `/policies?${search}`, 'GET', signal), 'policies')\n },\n async setPolicy(identity, connectionId, actionPath, decision, signal) {\n return namedObject<HubPolicy>(await call(identity, '/policies', 'PUT', signal, { connectionId, actionPath, decision }), 'policy')\n },\n async resetPolicy(identity, connectionId, actionPath, signal) {\n const response = object(await call(identity, '/policies', 'DELETE', signal, { connectionId, actionPath }))\n if (response.connectionId !== connectionId || response.actionPath !== actionPath || typeof response.deleted !== 'boolean') {\n throw new Error('Invalid Hub policy reset response.')\n }\n },\n }\n}\n","import type { HubApiKeyConnectionMetadata, HubConnection, HubProvider } from '@tangle-network/hub-sdk'\nimport {\n ApiKeyConnectDialog,\n IntegrationConnectionDetail,\n IntegrationsCatalog,\n OAuthConnectionParameterDialog,\n ProviderIcon,\n type IntegrationDisplayAction,\n type IntegrationsCatalogProps,\n type IntegrationSort,\n} from '@tangle-network/sandbox-ui/integrations'\nimport { Button, Card, Input, StatusPill, Tabs, TabsContent, TabsList, TabsTrigger, type StatusTone } from '@tangle-network/ui/primitives'\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport type { HubIntegrationsClient, HubIntegrationsIdentity } from './client'\nimport { contextKey, displayProvider, type HubActionPolicy, type HubIntegrationCapabilities } from './projection'\nimport { type HubHostConnect, useHubIntegrations } from './use-hub-integrations'\n\n/** Host-owned access state for one account, such as whether this agent can use it. */\nexport interface HubAccountStatus {\n label: string\n tone?: StatusTone\n}\n\n/**\n * Shows each connected account once, with its host status and one inline host\n * control. A separate tab offers providers without an account;\n * Manage opens permissions, Test, Disconnect and Connect another account.\n */\nexport interface HubIntegrationsAccounts {\n title: string\n description?: string\n /** Shown in the Accounts tab before any account exists. */\n emptyLabel?: string\n getStatus?: (connection: HubConnection) => HubAccountStatus | undefined\n /** The host authorizes this control and supplies its new status only after its server confirms. */\n getPrimaryAction?: (connection: HubConnection) => IntegrationDisplayAction | undefined\n /** Host-owned rows rendered after the accounts, such as access to an account that is no longer connected. */\n footer?: ReactNode\n}\n\nexport interface HubIntegrationsPanelProps {\n identity: HubIntegrationsIdentity\n client: HubIntegrationsClient\n can: HubIntegrationCapabilities\n /** Host-enforced execution policy, displayed read-only for each action. */\n getActionPolicy?: HubActionPolicy\n callbackPath: string\n title?: string\n /** Compact, icon-led tiles or descriptive cards. Defaults to cards. */\n layout?: IntegrationsCatalogProps['layout']\n className?: string\n onRequestIntegration?: (prefill: string) => void\n onUnsupportedConnect?: (provider: HubProvider) => void\n /**\n * App-owned connection for these providers, such as a number the app\n * provisions itself. Their catalog rows stay visible and connectable, and\n * choosing one calls `onConnect` instead of running a Hub flow.\n */\n hostConnect?: HubHostConnect\n /** Host-owned context and actions; the host authorizes and confirms their effects. */\n getConnectionContext?: (connection: HubConnection) => string | undefined\n getConnectionActions?: (connection: HubConnection) => readonly IntegrationDisplayAction[]\n accounts?: HubIntegrationsAccounts\n /** Host-owned, transient fields for providers that require API-key metadata. */\n renderApiKeyMetadata?: (input: {\n provider: HubProvider\n value: HubApiKeyConnectionMetadata | undefined\n onChange: (value: HubApiKeyConnectionMetadata | undefined) => void\n }) => ReactNode\n}\n\n/** The connection states a tile shows, in the shared StatusPill vocabulary. */\nexport type HubConnectionState = 'connected' | 'not_connected' | 'error' | 'pending'\n\nconst CONNECTION_TONES: Record<HubConnectionState, StatusTone> = {\n connected: 'success',\n not_connected: 'neutral',\n error: 'danger',\n pending: 'warning',\n}\n\n/**\n * The one mapping from connection state to StatusPill tone. Amber means\n * pending only: \"Not connected\" is neutral, never warning.\n */\nexport function connectionTone(state: HubConnectionState): StatusTone {\n return CONNECTION_TONES[state]\n}\n\n/** The state and label a Hub connection's tile shows. */\nexport function hubConnectionStatus(connection: Pick<HubConnection, 'status' | 'health'>): { state: HubConnectionState; label: string; tone: StatusTone } {\n const status = (state: HubConnectionState, label: string) => ({ state, label, tone: connectionTone(state) })\n if (connection.status === 'revoked') return status('not_connected', 'Not connected')\n if (connection.status === 'reconnect_required') return status('error', 'Reconnect required')\n if (connection.status === 'unhealthy' || connection.health === 'unhealthy') return status('error', 'Needs attention')\n if (connection.health === 'rate_limited') return status('pending', 'Rate limited')\n return status('connected', 'Connected')\n}\n\nfunction catalogHref(): string {\n if (typeof window === 'undefined') return '/'\n const url = new URL(window.location.href)\n url.searchParams.delete('integration')\n url.searchParams.delete('connection')\n return `${url.pathname}${url.search}${url.hash}`\n}\n\nfunction accountName(connection: HubConnection, providerTitle: string): string {\n return connection.accountDisplay?.trim() || connection.displayName?.trim() || providerTitle\n}\n\nfunction AccountStatus({ connection, accounts }: { connection: HubConnection; accounts: HubIntegrationsAccounts }) {\n const status = accounts.getStatus?.(connection)\n return status ? <StatusPill tone={status.tone ?? 'neutral'} size=\"sm\" className=\"max-w-full whitespace-normal\">{status.label}</StatusPill> : null\n}\n\nfunction AccountPrimaryAction({ connection, accounts, busy }: { connection: HubConnection; accounts: HubIntegrationsAccounts; busy: boolean }) {\n const primary = accounts.getPrimaryAction?.(connection)\n return primary ? <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={busy || primary.disabled}\n onClick={primary.onSelect}>{primary.label}</Button> : null\n}\n\nfunction HubAccountList({ accounts, connections, providers, loading, error, busy, onRetry, onManage, canManage, onAdd }: {\n accounts: HubIntegrationsAccounts\n connections: readonly HubConnection[]\n providers: readonly HubProvider[]\n loading: boolean\n error: string | null\n busy: boolean\n onRetry: () => void\n onManage: (connection: HubConnection) => void\n canManage: (connection: HubConnection) => boolean\n onAdd: () => void\n}) {\n const [query, setQuery] = useState('')\n const titles = new Map(providers.map(provider => [provider.providerId, provider.title]))\n const title = (connection: HubConnection) => titles.get(connection.providerId) ?? connection.displayName ?? connection.providerId\n const rows = connections.filter(connection => connection.status !== 'revoked')\n .map(connection => ({ connection, provider: title(connection), name: accountName(connection, title(connection)) }))\n .sort((a, b) => a.provider.localeCompare(b.provider) || a.name.localeCompare(b.name) || a.connection.id.localeCompare(b.connection.id))\n const matching = rows.filter(row => `${row.provider} ${row.name}`.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()))\n return <section className=\"min-w-0 space-y-4\" aria-labelledby=\"hub-accounts-heading\" aria-busy={loading || undefined}>\n <header>\n <h2 id=\"hub-accounts-heading\" className=\"sr-only\">{accounts.title}</h2>\n {accounts.description ? <p className=\"text-sm text-muted-foreground\">{accounts.description}</p> : null}\n </header>\n {rows.length > 0 && !error ? <Input type=\"search\" aria-label=\"Search accounts\" placeholder=\"Search accounts…\" value={query} onChange={event => setQuery(event.target.value)} /> : null}\n {error ? <div role=\"alert\" className=\"flex flex-wrap items-center gap-3 rounded-xl border border-destructive/40 p-4 text-sm text-destructive\">\n <p className=\"min-w-0 flex-1 break-words\">{error}</p>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onRetry}>Retry</Button>\n </div> : loading && rows.length === 0 ? <p role=\"status\" className=\"py-4 text-sm text-muted-foreground\">Loading connected accounts…</p>\n : rows.length === 0 ? <Card data-slot=\"card\" className=\"space-y-3 p-5\"><p className=\"text-sm text-muted-foreground\">{accounts.emptyLabel ?? 'No accounts connected yet.'}</p><Button type=\"button\" variant=\"outline\" onClick={onAdd}>Add integration</Button></Card>\n : matching.length === 0 ? <p role=\"status\" className=\"py-6 text-sm text-muted-foreground\">No accounts match your search.</p>\n : <ul className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\" aria-label={accounts.title}>\n {matching.map(({ connection, provider, name }) => {\n const state = hubConnectionStatus(connection)\n return <li key={connection.id} data-testid={`hub-account-${connection.id}`} className=\"min-w-0\">\n <Card data-slot=\"card\" data-connection-state={state.state} className=\"flex h-full min-w-0 flex-col gap-4 p-4\">\n <div className=\"flex min-w-0 items-center gap-4\">\n <div className=\"flex size-16 shrink-0 items-center justify-center rounded-xl bg-muted/50\"><ProviderIcon id={connection.providerId} displayName={provider} size={48} className=\"shrink-0 rounded-lg\" /></div>\n <div className=\"min-w-0\">\n <p className=\"text-base font-semibold [overflow-wrap:anywhere]\">{provider}</p>\n <StatusPill tone={state.tone} size=\"sm\" className=\"mt-1\">{state.label}</StatusPill>\n </div>\n </div>\n <p className=\"text-sm font-medium [overflow-wrap:anywhere]\">{name}</p>\n <div className=\"mt-auto space-y-4\">\n <AccountStatus connection={connection} accounts={accounts} />\n <div className=\"flex flex-wrap items-center gap-2 border-t border-border pt-3\">\n <AccountPrimaryAction connection={connection} accounts={accounts} busy={busy} />\n {canManage(connection) ? <Button type=\"button\" variant=\"outline\" size=\"sm\" aria-label={`Manage ${provider} account ${name}`}\n onClick={() => onManage(connection)}>Manage</Button> : null}\n </div>\n </div>\n </Card>\n </li>\n })}\n </ul>}\n {accounts.footer}\n </section>\n}\n\n/** Embeddable settings surface. The app supplies authenticated transport and grants. */\nexport function HubIntegrationsPanel(props: HubIntegrationsPanelProps) {\n const hub = useHubIntegrations(props)\n const scope = contextKey(props.identity)\n const activeScope = useRef(scope)\n activeScope.current = scope\n const activeDialog = useRef(hub.dialog)\n activeDialog.current = hub.dialog\n const [query, setQuery] = useState('')\n const [category, setCategory] = useState('')\n const [sort, setSort] = useState<IntegrationSort>('featured')\n const [view, setView] = useState<{ scope: string; value: 'accounts' | 'catalog' } | null>(null)\n const [catalogSelection, setCatalogSelection] = useState<{ scope: string; ids: Record<string, string | null> }>({ scope, ids: {} })\n const [keyInput, setKeyInput] = useState({ scope, value: '' })\n const apiKey = keyInput.scope === scope ? keyInput.value : ''\n const setApiKey = (value: string) => setKeyInput({ scope, value })\n const [metadataInput, setMetadataInput] = useState<{ scope: string; value: HubApiKeyConnectionMetadata | undefined }>({ scope, value: undefined })\n const metadata = metadataInput.scope === scope ? metadataInput.value : undefined\n const setMetadata = (value: HubApiKeyConnectionMetadata | undefined) => setMetadataInput({ scope, value })\n const [parameterInput, setParameterInput] = useState({ scope, values: {} as Record<string, string> })\n const parameters = parameterInput.scope === scope ? parameterInput.values : {}\n const setParameters = (values: Record<string, string>) => setParameterInput({ scope, values })\n\n useEffect(() => { setApiKey(''); setMetadata(undefined); setParameters({}) }, [scope])\n const pending = hub.writeState.status === 'pending' || hub.connectStatus.status === 'pending'\n const error = hub.providers.status === 'error' ? hub.providers.message\n : hub.connections.status === 'error' ? hub.connections.message : null\n const mutationError = hub.writeState.status === 'failed' ? hub.writeState.message : null\n const writeMessage = hub.writeState.status === 'succeeded' ? hub.writeState.value.message : null\n const writeWarning = hub.writeState.status === 'succeeded' && hub.writeState.value.reconciliation === 'refresh-failed'\n const rows = hub.rows.map(row => {\n const selectedId = catalogSelection.scope === scope ? catalogSelection.ids[row.providerId] : null\n return {\n ...row,\n selectedConnectionId: row.connections.some(connection => connection.id === selectedId) ? selectedId ?? null : null,\n connections: row.connections.map(connection => {\n const source = hub.connections.status === 'ready'\n ? hub.connections.value.find(item => item.id === connection.id) : undefined\n return source ? {\n ...connection,\n detail: props.getConnectionContext?.(source) ?? connection.detail,\n actions: props.getConnectionActions?.(source),\n } : connection\n }),\n }\n })\n const selectedRow = rows.find(row => row.providerId === hub.provider?.providerId)\n const connectionList = hub.connections.status === 'ready' ? hub.connections.value : []\n const accountCount = connectionList.filter(connection => connection.status !== 'revoked').length\n const activeView = view?.scope === scope ? view.value : hub.connections.status === 'ready' && accountCount === 0 ? 'catalog' : 'accounts'\n const showAccounts = () => setView({ scope, value: 'accounts' })\n useEffect(() => {\n if (hub.connectStatus.status === 'connected') showAccounts()\n }, [hub.connectStatus.status, scope])\n // With an account list, the catalog offers providers without a connected account.\n // The Hub keeps revoked connections listed; a provider with only those is connectable again.\n const connectedProviders = new Set(connectionList.filter(connection => connection.status !== 'revoked').map(connection => connection.providerId))\n const catalogRows = props.accounts && hub.connections.status === 'error' ? [] : props.accounts\n ? rows.filter(row => !connectedProviders.has(row.providerId)).map(row => ({ ...row, connections: [], selectedConnectionId: null }))\n : rows\n const retryProvider = hub.providers.status === 'ready'\n ? hub.providers.value.find(provider => provider.providerId === hub.connectStatus.providerId) : undefined\n const selectedConnection = hub.connection\n const detailError = hub.detail.status === 'error' ? hub.detail.message\n : hub.detail.status === 'ready' && hub.detail.value.truncated\n ? `Showing at most ${hub.detail.value.tools.length} actions. The provider catalog may be incomplete.` : null\n const detailsByConnectionId = useMemo(() => hub.connection ? {\n [hub.connection.id]: {\n ...hub.details,\n loading: hub.detail.status === 'loading',\n busy: pending,\n error: detailError,\n },\n } : {}, [hub.connection, hub.details, hub.detail.status, pending, detailError])\n\n const closeDialog = () => {\n if (hub.connectStatus.status === 'pending') hub.cancelConnect()\n else hub.setDialog(null)\n setApiKey(''); setMetadata(undefined); setParameters({})\n }\n\n const catalog = <IntegrationsCatalog\n title={props.title ?? 'Integrations'} layout={props.layout} rows={catalogRows}\n query={query} onQueryChange={setQuery} categoryFilter={category} onCategoryFilterChange={setCategory}\n sort={sort} onSortChange={setSort}\n onSelectConnection={(providerId, connectionId) => setCatalogSelection(current => ({\n scope, ids: { ...(current.scope === scope ? current.ids : {}), [providerId]: connectionId },\n }))}\n onConnect={row => { const provider = hub.providers.status === 'ready' ? hub.providers.value.find(item => item.providerId === row.providerId) : null; if (provider) hub.beginConnect(provider) }}\n onManage={(connection, row) => hub.selectConnection(row.providerId, connection.id)}\n onDisconnect={connection => { void hub.revoke(connection.id) }}\n onRequestIntegration={props.onRequestIntegration} onRetry={() => hub.refresh()}\n loading={hub.providers.status === 'loading' || hub.connections.status === 'loading'} error={error}\n actionError={mutationError}\n busyProviderId={hub.connectStatus.status === 'pending' ? hub.connectStatus.providerId ?? null : null}\n reserveConnectionContext\n emptyCatalogLabel={props.accounts && rows.length > 0 ? 'Every available integration has a connected account. Manage an account to connect another.' : undefined}\n />\n\n return <section className={props.className}>\n {hub.connectStatus.status === 'pending' ? <div role=\"status\" className=\"mb-4 flex flex-wrap items-center gap-3\">\n <span>Finish connecting in the popup.</span>\n <Button type=\"button\" variant=\"outline\" onClick={hub.cancelConnect}>Cancel connection</Button>\n </div> : null}\n {hub.writeState.status === 'pending' ? <p role=\"status\">Saving Hub settings…</p> : null}\n {mutationError ? <p role=\"alert\">{mutationError}</p> : null}\n {writeMessage ? <p role={writeWarning ? 'alert' : 'status'}>{writeMessage}</p> : null}\n {hub.connectStatus.status === 'failed' ? <div role=\"alert\" className=\"mb-4 flex flex-wrap items-center gap-3 text-sm text-destructive\">\n <p data-testid=\"integration-connect-error\">{hub.connectStatus.message}</p>\n {retryProvider ? <Button type=\"button\" variant=\"outline\" disabled={pending} onClick={() => hub.beginConnect(retryProvider)}>Retry connection</Button> : null}\n </div> : hub.connectStatus.message && hub.provider ? <p role=\"status\">{hub.connectStatus.message}</p> : null}\n {hub.provider ? <>\n {(props.accounts && selectedConnection) || selectedRow?.canConnect ? <div className=\"mb-4 flex min-w-0 flex-wrap items-center gap-2\">\n {props.accounts && selectedConnection ? <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\" data-testid=\"hub-account-access\"\n aria-label={`Access for ${accountName(selectedConnection, hub.provider.title)}`} role=\"group\">\n <span className=\"min-w-0 max-w-full truncate text-sm font-medium\">{accountName(selectedConnection, hub.provider.title)}</span>\n <AccountStatus connection={selectedConnection} accounts={props.accounts} />\n <AccountPrimaryAction connection={selectedConnection} accounts={props.accounts} busy={pending} />\n </div> : null}\n {selectedRow?.canConnect ? <Button type=\"button\" variant=\"outline\" className=\"ml-auto\" disabled={pending}\n onClick={() => hub.beginConnect(hub.provider!)}>Connect another account</Button> : null}\n </div> : null}\n <IntegrationConnectionDetail\n provider={displayProvider(hub.provider)}\n connections={selectedRow?.connections ?? []}\n selectedConnectionId={hub.connection?.id ?? null}\n onSelectConnection={connectionId => hub.selectConnection(hub.provider!.providerId, connectionId)}\n detailsByConnectionId={detailsByConnectionId}\n loading={hub.connections.status === 'loading' || hub.detail.status === 'loading'}\n error={detailError}\n backHref={catalogHref()}\n onRetry={() => hub.refresh()}\n onTestConnection={connectionId => { void hub.test(connectionId) }}\n onDisconnect={connectionId => { void hub.revoke(connectionId) }}\n onDecisionChange={(connectionId, actionPath, decision) => {\n if (decision !== 'allow' && decision !== 'ask' && decision !== 'deny') return\n void hub.setDecision(connectionId, actionPath, decision)\n }}\n onResetDecision={(connectionId, actionPath) => { void hub.resetDecision(connectionId, actionPath) }}\n />\n </> : <>\n {props.accounts ? <Tabs value={activeView} onValueChange={value => setView({ scope, value: value === 'catalog' ? 'catalog' : 'accounts' })}>\n <TabsList aria-label=\"Integration views\" className=\"mb-5 grid h-auto w-full grid-cols-2 sm:inline-flex sm:w-auto\">\n <TabsTrigger value=\"accounts\">Accounts{' '}{hub.connections.status === 'ready' ? <span className=\"ml-2 tabular-nums text-muted-foreground\">{accountCount}</span> : null}</TabsTrigger>\n <TabsTrigger value=\"catalog\">Add integration{' '}{hub.providers.status === 'ready' && hub.connections.status === 'ready' ? <span className=\"ml-2 tabular-nums text-muted-foreground\">{catalogRows.length}</span> : null}</TabsTrigger>\n </TabsList>\n <TabsContent value=\"accounts\">\n {hub.connectStatus.status === 'connected' && hub.connectStatus.message ? <p role=\"status\" className=\"mb-3 text-sm\">{hub.connectStatus.message}</p> : null}\n <HubAccountList key={scope} accounts={props.accounts} connections={connectionList} providers={hub.providers.status === 'ready' ? hub.providers.value : []}\n loading={hub.connections.status === 'loading'} error={hub.connections.status === 'error' ? hub.connections.message : null} busy={pending}\n onRetry={() => hub.refresh()} onManage={connection => hub.selectConnection(connection.providerId, connection.id)}\n canManage={connection => props.can({ operation: 'policies.list', connectionId: connection.id })}\n onAdd={() => setView({ scope, value: 'catalog' })} />\n </TabsContent>\n <TabsContent value=\"catalog\">{catalog}</TabsContent>\n </Tabs> : catalog}\n </>}\n {hub.dialog?.kind === 'api-key' ? <ApiKeyConnectDialog\n open\n onOpenChange={open => { if (!open) closeDialog() }}\n providerId={hub.dialog.provider.providerId}\n title={hub.dialog.provider.title}\n description={hub.dialog.provider.authHint}\n value={apiKey}\n onValueChange={setApiKey}\n busy={pending}\n error={mutationError}\n canSubmit={apiKey.trim().length > 0 && !pending}\n onSubmit={() => {\n const secret = apiKey\n const target = hub.dialog?.provider.providerId\n const submittedDialog = hub.dialog\n setApiKey('')\n if (target) void hub.submitApiKey(target, secret, metadata).then(result => {\n if (result.succeeded && activeScope.current === scope && activeDialog.current === submittedDialog) {\n hub.setDialog(null); setMetadata(undefined); showAccounts()\n }\n })\n }}\n >{props.renderApiKeyMetadata?.({ provider: hub.dialog.provider, value: metadata, onChange: setMetadata })}</ApiKeyConnectDialog> : null}\n {hub.dialog?.kind === 'oauth' ? <OAuthConnectionParameterDialog\n open\n onOpenChange={open => { if (!open) closeDialog() }}\n providerId={hub.dialog.provider.providerId}\n title={hub.dialog.provider.title}\n parameters={hub.dialog.provider.connectionParameters ?? []}\n values={parameters}\n onValueChange={(key, value) => setParameters({ ...parameters, [key]: value })}\n busy={pending}\n error={hub.connectStatus.status === 'failed' ? hub.connectStatus.message : null}\n canSubmit={!pending && (hub.dialog.provider.connectionParameters ?? []).every(field => !field.required || !!parameters[field.key]?.trim())}\n onSubmit={() => {\n const target = hub.dialog?.provider\n const submittedDialog = hub.dialog\n if (target) void hub.startOAuth(target, parameters).then(result => {\n if (result === 'connected' && activeScope.current === scope && activeDialog.current === submittedDialog) setParameters({})\n })\n }}\n /> : null}\n </section>\n}\n","import type { HubConnection, HubPolicy, HubPolicyDecision, HubProvider, HubTool } from '@tangle-network/hub-sdk'\nimport type {\n IntegrationConnectionDetails,\n IntegrationDisplayProvider,\n IntegrationPermissionDisplay,\n IntegrationPermissionGroup,\n IntegrationsProviderRow,\n} from '@tangle-network/sandbox-ui/integrations'\n\nexport type HubIntegrationCapability =\n | { operation: 'oauth.start' | 'api-key.connect'; providerId: string }\n | { operation: 'connection.revoke' | 'connection.health' | 'policies.list'; connectionId: string }\n | { operation: 'policy.set' | 'policy.reset'; connectionId: string; actionPath: string }\n\n/** Display hints only. `createHubSettingsRoutes.authorize` remains authoritative. */\nexport type HubIntegrationCapabilities = (intent: HubIntegrationCapability) => boolean\n\n/** Display of a policy enforced by the consuming app, never browser authority. */\nexport interface HubActionPolicyDisplay {\n decision: HubPolicyDecision\n label: string\n sourceLabel: string\n}\n\n/** Return only policies the host enforces independently of stored Hub overrides. */\nexport type HubActionPolicy = (input: { connection: HubConnection; tool: HubTool; storedDecision?: HubPolicyDecision }) => HubActionPolicyDisplay | undefined\n\nexport const ACTION_LIMIT = 200\n\nexport function contextKey(identity: { userId: string; sessionId: string; workspaceId: string }): string {\n return JSON.stringify([identity.userId, identity.sessionId, identity.workspaceId])\n}\n\nexport function displayProvider(provider: HubProvider): IntegrationDisplayProvider {\n return { providerId: provider.providerId, title: provider.title, category: provider.category }\n}\n\nexport function catalogRows(\n providers: readonly HubProvider[],\n connections: readonly HubConnection[],\n selectedIds: Readonly<Record<string, string | null>>,\n can: HubIntegrationCapabilities,\n hasUnsupportedConnect = false,\n hostConnectProviderIds: readonly string[] = [],\n): IntegrationsProviderRow[] {\n return providers.map(provider => {\n const accounts = connections.filter(connection => connection.providerId === provider.providerId)\n return {\n ...displayProvider(provider),\n kind: 'provider',\n authKind: provider.authKind,\n selectedConnectionId: accounts.some(account => account.id === selectedIds[provider.providerId])\n ? selectedIds[provider.providerId] ?? null : null,\n canConnect: hostConnectProviderIds.includes(provider.providerId) ? true : provider.authKind === 'oauth2'\n ? provider.configured && can({ operation: 'oauth.start', providerId: provider.providerId })\n : provider.authKind === 'api_key'\n ? provider.configured && can({ operation: 'api-key.connect', providerId: provider.providerId })\n : hasUnsupportedConnect,\n connections: accounts.map(connection => ({\n id: connection.id,\n accountDisplay: connection.accountDisplay ?? connection.displayName,\n statusLabel: connection.status === 'active' ? 'Connected' : connection.status.replaceAll('_', ' '),\n statusTone: connection.status === 'active' && connection.health !== 'unhealthy' ? 'success' : 'warning',\n detail: connection.providerAccountId ?? undefined,\n capabilities: {\n manage: can({ operation: 'policies.list', connectionId: connection.id }),\n disconnect: can({ operation: 'connection.revoke', connectionId: connection.id }),\n test: can({ operation: 'connection.health', connectionId: connection.id }),\n editPermissions: can({ operation: 'policies.list', connectionId: connection.id }),\n resetPermissions: can({ operation: 'policies.list', connectionId: connection.id }),\n },\n })),\n }\n })\n}\n\nconst OPTIONS = [\n { value: 'allow', label: 'Allow' },\n { value: 'ask', label: 'Ask' },\n { value: 'deny', label: 'Deny' },\n] as const\n\n/** Host-enforced policy takes precedence; other defaults remain unknown. */\nexport function permissionDetails(\n tools: readonly HubTool[],\n policies: readonly HubPolicy[],\n connectionId: string,\n can: HubIntegrationCapabilities,\n getActionPolicy?: (tool: HubTool, storedDecision?: HubPolicyDecision) => HubActionPolicyDisplay | undefined,\n): IntegrationConnectionDetails {\n const overrides = new Map(policies.filter(policy => policy.connectionId === connectionId).map(policy => [policy.actionPath, policy.decision]))\n const groups: IntegrationPermissionGroup[] = [\n { id: 'writes', title: 'Write and unknown actions', rows: [] },\n { id: 'reads', title: 'Read actions', collapsed: true, rows: [] },\n ]\n const writes: IntegrationPermissionDisplay[] = []\n const reads: IntegrationPermissionDisplay[] = []\n for (const tool of tools) {\n const override = overrides.get(tool.path)\n const enforced = getActionPolicy?.(tool, override)\n const row = {\n actionPath: tool.path,\n title: tool.title ?? tool.path,\n riskLabel: tool.risk ?? 'unknown',\n riskTone: tool.risk === 'destructive' ? 'error' : tool.risk === 'write' || tool.risk === undefined ? 'warning' : 'neutral',\n decision: enforced?.decision ?? override ?? null,\n decisionOptions: enforced ? [{ value: enforced.decision, label: enforced.label }] : OPTIONS,\n sourceLabel: enforced?.sourceLabel ?? (override ? 'Stored override' : 'No stored override'),\n canReset: !enforced && override !== undefined && can({ operation: 'policy.reset', connectionId, actionPath: tool.path }),\n disabled: !!enforced || !can({ operation: 'policy.set', connectionId, actionPath: tool.path }),\n } as const\n if (tool.risk === 'read') reads.push(row)\n else writes.push(row)\n }\n writes.sort((a, b) => a.title.localeCompare(b.title))\n reads.sort((a, b) => a.title.localeCompare(b.title))\n groups[0] = { ...groups[0]!, rows: writes }\n groups[1] = { ...groups[1]!, rows: reads }\n return { permissionGroups: groups }\n}\n","import type { HubApiKeyConnectionMetadata, HubConnection, HubPolicyDecision, HubProvider } from '@tangle-network/hub-sdk'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { confirmWrite, useAsyncResource, useConfirmedMutation } from '../web-react/async'\nimport type { HubIntegrationsClient, HubIntegrationsIdentity } from './client'\nimport { connectWithPopup, type PopupConnectResult } from './popup'\nimport { ACTION_LIMIT, catalogRows, contextKey, permissionDetails, type HubActionPolicy, type HubIntegrationCapabilities } from './projection'\n\ntype Selection = { scope: string; providerId: string | null; connectionId: string | null }\ntype Dialog = { scope: string; kind: 'api-key' | 'oauth'; provider: HubProvider } | null\n\nexport interface UseHubIntegrationsOptions {\n identity: HubIntegrationsIdentity\n client: HubIntegrationsClient\n /** Display only. The host server must authorize every exact operation. */\n can: HubIntegrationCapabilities\n /** Display only; the host server enforces these policies. */\n getActionPolicy?: HubActionPolicy\n /** Local app route that renders `HubConnectCallbackPage`. */\n callbackPath: string\n /** Optional host handler for custom/native signup. No Platform redirect is assumed. */\n onUnsupportedConnect?: (provider: HubProvider) => void\n /**\n * App-owned connection for these providers, such as a number the app\n * provisions itself. Their catalog rows stay visible and connectable, and\n * choosing one calls `onConnect` instead of running a Hub flow.\n */\n hostConnect?: HubHostConnect\n}\n\nexport interface HubHostConnect {\n providerIds: readonly string[]\n onConnect: (provider: HubProvider) => void\n}\n\ntype WriteInput =\n | { kind: 'api-key'; identity: HubIntegrationsIdentity; scope: string; providerId: string; apiKey: string; metadata?: HubApiKeyConnectionMetadata }\n | { kind: 'revoke'; identity: HubIntegrationsIdentity; scope: string; connectionId: string }\n | { kind: 'health'; identity: HubIntegrationsIdentity; scope: string; connectionId: string }\n | { kind: 'set'; identity: HubIntegrationsIdentity; scope: string; connectionId: string; actionPath: string; decision: HubPolicyDecision }\n | { kind: 'reset'; identity: HubIntegrationsIdentity; scope: string; connectionId: string; actionPath: string }\n\nexport interface HubWriteReceipt {\n scope: string\n kind: WriteInput['kind']\n reconciliation: 'verified' | 'refresh-failed'\n message: string\n}\n\nfunction initialSelection(scope: string): Selection {\n if (typeof window === 'undefined') return { scope, providerId: null, connectionId: null }\n const query = new URL(window.location.href).searchParams\n return { scope, providerId: query.get('integration'), connectionId: query.get('connection') }\n}\n\nfunction updateUrl(providerId: string | null, connectionId: string | null): void {\n if (typeof window === 'undefined') return\n const url = new URL(window.location.href)\n if (providerId) url.searchParams.set('integration', providerId)\n else url.searchParams.delete('integration')\n if (connectionId) url.searchParams.set('connection', connectionId)\n else url.searchParams.delete('connection')\n window.history.pushState(window.history.state, '', url)\n}\n\n/** Identity-bound Hub settings controller; connection state is always server-read. */\nexport function useHubIntegrations({ identity, client, can, callbackPath, onUnsupportedConnect, hostConnect, getActionPolicy }: UseHubIntegrationsOptions) {\n const scope = contextKey(identity)\n const activeScope = useRef(scope)\n activeScope.current = scope\n const [selection, setSelection] = useState<Selection>(() => initialSelection(scope))\n const visibleSelection = selection.scope === scope ? selection : { scope, providerId: null, connectionId: null }\n const [dialog, setDialog] = useState<Dialog>(null)\n const visibleDialog = dialog?.scope === scope ? dialog : null\n const [connectStatus, setConnectStatus] = useState<{ scope: string; status: 'idle' | 'pending' | 'connected' | 'failed'; providerId?: string; message?: string }>({ scope, status: 'idle' })\n const [writeScope, setWriteScope] = useState(scope)\n const pendingPopup = useRef<AbortController | null>(null)\n\n useEffect(() => {\n const onPop = () => setSelection(initialSelection(scope))\n window.addEventListener('popstate', onPop)\n return () => window.removeEventListener('popstate', onPop)\n }, [scope])\n\n const providers = useAsyncResource({ load: ({ signal }) => client.providers(identity, signal), deps: [client, scope], isEmpty: () => false })\n const connections = useAsyncResource({ load: ({ signal }) => client.connections(identity, signal), deps: [client, scope], isEmpty: () => false })\n const providerList = providers.status === 'ready' ? providers.value : []\n const connectionList = connections.status === 'ready' ? connections.value : []\n const provider = providerList.find(item => item.providerId === visibleSelection.providerId) ?? null\n const connection = connectionList.find(item => item.id === visibleSelection.connectionId && item.providerId === provider?.providerId) ?? null\n const canReadPolicies = connection !== null && can({ operation: 'policies.list', connectionId: connection.id })\n const detail = useAsyncResource({\n enabled: canReadPolicies && connection?.status === 'active',\n deps: [client, scope, provider?.providerId, connection?.id, canReadPolicies],\n isEmpty: () => false,\n load: async ({ signal }) => {\n if (!provider || !connection) throw new Error('Choose a connection.')\n const [tools, policies] = await Promise.all([\n client.actions(identity, provider.providerId, ACTION_LIMIT, signal),\n client.policies(identity, connection.id, signal),\n ])\n if (tools.some(tool => !tool.path.startsWith(`${provider.providerId}.`)) || policies.some(policy => policy.connectionId !== connection.id)) {\n throw new Error('Hub settings response changed connection or provider.')\n }\n return { tools, policies, truncated: tools.length >= ACTION_LIMIT }\n },\n })\n\n const write = useConfirmedMutation<WriteInput, HubWriteReceipt>({\n concurrency: 'reject',\n mutate: async (input, { signal }) => {\n if (input.scope !== activeScope.current) throw new Error('Integration context changed. Retry in the current workspace.')\n const origin = input.identity\n const receipt = (reconciliation: HubWriteReceipt['reconciliation'], message: string) => confirmWrite<HubWriteReceipt>({ scope: input.scope, kind: input.kind, reconciliation, message })\n if (input.kind === 'api-key') {\n if (!can({ operation: 'api-key.connect', providerId: input.providerId })) throw new Error('Connection setup is unavailable.')\n const created = await client.connectApiKey(origin, input.providerId, input.apiKey, input.metadata, signal)\n if (created.providerId !== input.providerId || created.status !== 'active') throw new Error('Hub did not confirm the requested connection.')\n try {\n const current = await client.connections(origin, signal)\n return current.some(item => item.id === created.id && item.status === 'active')\n ? receipt('verified', 'Connection saved and verified.') : receipt('refresh-failed', 'Connection saved; current account state could not be confirmed.')\n } catch { return receipt('refresh-failed', 'Connection saved; refresh failed.') }\n }\n if (input.kind === 'revoke') {\n if (!can({ operation: 'connection.revoke', connectionId: input.connectionId })) throw new Error('Disconnect is unavailable.')\n await client.revoke(origin, input.connectionId, signal)\n try {\n const current = await client.connections(origin, signal)\n return current.some(item => item.id === input.connectionId && item.status === 'active')\n ? receipt('refresh-failed', 'Disconnected, but the current account state disagrees.') : receipt('verified', 'Connection disconnected and verified.')\n } catch { return receipt('refresh-failed', 'Disconnected; refresh failed.') }\n }\n if (input.kind === 'health') {\n if (!can({ operation: 'connection.health', connectionId: input.connectionId })) throw new Error('Connection test is unavailable.')\n const result = await client.health(origin, input.connectionId, signal)\n if (result.connection.id !== input.connectionId) throw new Error('Hub returned another connection.')\n return receipt('verified', `Connection test: ${result.health.status.replaceAll('_', ' ')}.`)\n }\n if (!can({ operation: input.kind === 'set' ? 'policy.set' : 'policy.reset', connectionId: input.connectionId, actionPath: input.actionPath })) {\n throw new Error('Permission editing is unavailable.')\n }\n if (input.kind === 'set') {\n const stored = await client.setPolicy(origin, input.connectionId, input.actionPath, input.decision, signal)\n if (stored.connectionId !== input.connectionId || stored.actionPath !== input.actionPath || stored.decision !== input.decision) {\n throw new Error('Hub did not confirm the requested permission.')\n }\n } else await client.resetPolicy(origin, input.connectionId, input.actionPath, signal)\n try {\n const current = await client.policies(origin, input.connectionId, signal)\n const override = current.find(policy => policy.actionPath === input.actionPath)\n const matches = input.kind === 'set' ? override?.decision === input.decision : override === undefined\n return matches\n ? receipt('verified', 'Permission saved and verified.') : receipt('refresh-failed', 'Permission write was accepted; current policy state disagrees.')\n } catch { return receipt('refresh-failed', 'Permission write was accepted; refresh failed.') }\n },\n onSucceeded: value => { if (value.scope === activeScope.current) { connections.retry(); detail.retry() } },\n })\n\n useEffect(() => {\n pendingPopup.current?.abort()\n pendingPopup.current = null\n setDialog(null)\n setConnectStatus({ scope, status: 'idle' })\n setWriteScope(scope)\n write.reset()\n return () => { pendingPopup.current?.abort(); pendingPopup.current = null }\n }, [scope, client, write.reset])\n\n const selectProvider = useCallback((providerId: string | null) => {\n const next = { scope, providerId, connectionId: null }\n setSelection(next)\n updateUrl(providerId, null)\n }, [scope])\n\n const selectConnection = useCallback((providerId: string, connectionId: string | null) => {\n if (connectionId && !connectionList.some(item => item.id === connectionId && item.providerId === providerId)) return\n setSelection({ scope, providerId, connectionId })\n updateUrl(providerId, connectionId)\n }, [scope, connectionList])\n\n const startOAuth = useCallback(async (target: HubProvider, connectionParameters?: Record<string, string>): Promise<PopupConnectResult> => {\n if (!can({ operation: 'oauth.start', providerId: target.providerId })) return 'unavailable'\n if (connections.status !== 'ready') { setConnectStatus({ scope, status: 'failed', message: 'Load connections before connecting.' }); return 'unavailable' }\n pendingPopup.current?.abort()\n const controller = new AbortController()\n pendingPopup.current = controller\n setConnectStatus({ scope, status: 'pending', providerId: target.providerId })\n const result = await connectWithPopup({\n client, identity, providerId: target.providerId, before: connections.value,\n callbackPath, connectionParameters, signal: controller.signal,\n isCurrent: () => activeScope.current === scope && !controller.signal.aborted,\n })\n if (pendingPopup.current !== controller || activeScope.current !== scope) return result\n pendingPopup.current = null\n if (result === 'connected') {\n connections.retry()\n setDialog(null)\n setConnectStatus({ scope, status: 'connected', message: 'Connection verified.' })\n } else setConnectStatus({ scope, status: 'failed', providerId: target.providerId, message: result === 'blocked' ? 'Allow the popup and try again.' : result === 'unverified' ? 'Could not verify a new connection. Refresh and try again.' : result === 'failed' ? 'Could not connect your account. Please try again.' : result === 'cancelled' ? 'Connection was cancelled.' : 'This connection flow is unavailable.' })\n return result\n }, [can, connections, client, identity, callbackPath, scope])\n\n const beginConnect = useCallback((target: HubProvider) => {\n if (hostConnect?.providerIds.includes(target.providerId)) {\n hostConnect.onConnect(target)\n return\n }\n if (target.authKind !== 'api_key' && target.authKind !== 'oauth2') {\n if (onUnsupportedConnect) onUnsupportedConnect(target)\n else setConnectStatus({ scope, status: 'failed', message: 'This provider needs an app-specific connection flow.' })\n return\n }\n if (!target.configured) {\n setConnectStatus({ scope, status: 'failed', message: 'This provider is not configured for connection.' })\n return\n }\n if (target.authKind === 'api_key') {\n if (can({ operation: 'api-key.connect', providerId: target.providerId })) setDialog({ scope, kind: 'api-key', provider: target })\n else setConnectStatus({ scope, status: 'failed', message: 'Connection setup is unavailable.' })\n return\n }\n if (target.authKind === 'oauth2') {\n if (!can({ operation: 'oauth.start', providerId: target.providerId })) {\n setConnectStatus({ scope, status: 'failed', message: 'Connection setup is unavailable.' }); return\n }\n if (target.connectionParameters?.length) setDialog({ scope, kind: 'oauth', provider: target })\n else void startOAuth(target)\n return\n }\n }, [can, onUnsupportedConnect, hostConnect, scope, startOAuth])\n\n const cancelConnect = useCallback(() => {\n pendingPopup.current?.abort()\n pendingPopup.current = null\n setDialog(null)\n setConnectStatus(current => ({ scope, status: 'failed', providerId: current.scope === scope ? current.providerId : undefined, message: 'Connection was cancelled.' }))\n }, [scope])\n\n const rows = useMemo(() => catalogRows(providerList, connectionList, visibleSelection.providerId && visibleSelection.connectionId\n ? { [visibleSelection.providerId]: visibleSelection.connectionId } : {}, can, !!onUnsupportedConnect,\n hostConnect?.providerIds),\n [providerList, connectionList, visibleSelection.providerId, visibleSelection.connectionId, can, onUnsupportedConnect, hostConnect])\n const details = detail.status === 'ready' && connection\n ? permissionDetails(detail.value.tools, detail.value.policies, connection.id, can, (tool, storedDecision) => getActionPolicy?.({ connection, tool, storedDecision })) : undefined\n\n return {\n providers, connections, detail, rows, provider, connection, dialog: visibleDialog, setDialog,\n connectStatus: connectStatus.scope === scope ? connectStatus : { scope, status: 'idle' as const, providerId: undefined },\n selection: visibleSelection, selectProvider, selectConnection, beginConnect, startOAuth, cancelConnect,\n write, writeState: writeScope === scope ? write.state : { status: 'idle' as const }, details,\n refresh: () => { providers.retry(); connections.retry(); detail.retry() },\n submitApiKey: (providerId: string, apiKey: string, metadata?: HubApiKeyConnectionMetadata) => { setWriteScope(scope); return write.run({ kind: 'api-key', identity, scope, providerId, apiKey, metadata }) },\n revoke: (connectionId: string) => { setWriteScope(scope); return write.run({ kind: 'revoke', identity, scope, connectionId }) },\n test: (connectionId: string) => { setWriteScope(scope); return write.run({ kind: 'health', identity, scope, connectionId }) },\n setDecision: (connectionId: string, actionPath: string, decision: HubPolicyDecision) => { setWriteScope(scope); return write.run({ kind: 'set', identity, scope, connectionId, actionPath, decision }) },\n resetDecision: (connectionId: string, actionPath: string) => { setWriteScope(scope); return write.run({ kind: 'reset', identity, scope, connectionId, actionPath }) },\n }\n}\n"],"mappings":"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","names":["useEffect","useMemo","useRef","useState","useEffect","useState","useState","useEffect","jsx","jsxs","useState","useRef","useEffect","catalogRows","useMemo"]}
|
|
@@ -3,7 +3,7 @@ import { type IntegrationDisplayAction, type IntegrationsCatalogProps } from '@t
|
|
|
3
3
|
import { type StatusTone } from '@tangle-network/ui/primitives';
|
|
4
4
|
import { type ReactNode } from 'react';
|
|
5
5
|
import type { HubIntegrationsClient, HubIntegrationsIdentity } from './client';
|
|
6
|
-
import { type HubIntegrationCapabilities } from './projection';
|
|
6
|
+
import { type HubActionPolicy, type HubIntegrationCapabilities } from './projection';
|
|
7
7
|
import { type HubHostConnect } from './use-hub-integrations';
|
|
8
8
|
/** Host-owned access state for one account, such as whether this agent can use it. */
|
|
9
9
|
export interface HubAccountStatus {
|
|
@@ -30,6 +30,8 @@ export interface HubIntegrationsPanelProps {
|
|
|
30
30
|
identity: HubIntegrationsIdentity;
|
|
31
31
|
client: HubIntegrationsClient;
|
|
32
32
|
can: HubIntegrationCapabilities;
|
|
33
|
+
/** Host-enforced execution policy, displayed read-only for each action. */
|
|
34
|
+
getActionPolicy?: HubActionPolicy;
|
|
33
35
|
callbackPath: string;
|
|
34
36
|
title?: string;
|
|
35
37
|
/** Compact, icon-led tiles or descriptive cards. Defaults to cards. */
|
|
@@ -4,7 +4,7 @@ export declare const HUB_CONNECT_CHANNEL = "tangle:hub-connect";
|
|
|
4
4
|
export declare const HUB_CONNECTED_MESSAGE_TYPE = "tangle:hub-connected";
|
|
5
5
|
export declare const HUB_CONNECT_FAILED_MESSAGE_TYPE = "tangle:hub-connect-failed";
|
|
6
6
|
export declare const POPUP_TIMEOUT_MS: number;
|
|
7
|
-
export type PopupConnectResult = 'connected' | 'blocked' | 'cancelled' | 'unverified' | 'unavailable';
|
|
7
|
+
export type PopupConnectResult = 'connected' | 'blocked' | 'failed' | 'cancelled' | 'unverified' | 'unavailable';
|
|
8
8
|
export declare function localAppUrl(path: string): URL | null;
|
|
9
9
|
/** Opens before the first await, preserving the initiating user gesture. */
|
|
10
10
|
export declare function connectWithPopup(input: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HubConnection, HubPolicy, HubProvider, HubTool } from '@tangle-network/hub-sdk';
|
|
1
|
+
import type { HubConnection, HubPolicy, HubPolicyDecision, HubProvider, HubTool } from '@tangle-network/hub-sdk';
|
|
2
2
|
import type { IntegrationConnectionDetails, IntegrationDisplayProvider, IntegrationsProviderRow } from '@tangle-network/sandbox-ui/integrations';
|
|
3
3
|
export type HubIntegrationCapability = {
|
|
4
4
|
operation: 'oauth.start' | 'api-key.connect';
|
|
@@ -13,6 +13,18 @@ export type HubIntegrationCapability = {
|
|
|
13
13
|
};
|
|
14
14
|
/** Display hints only. `createHubSettingsRoutes.authorize` remains authoritative. */
|
|
15
15
|
export type HubIntegrationCapabilities = (intent: HubIntegrationCapability) => boolean;
|
|
16
|
+
/** Display of a policy enforced by the consuming app, never browser authority. */
|
|
17
|
+
export interface HubActionPolicyDisplay {
|
|
18
|
+
decision: HubPolicyDecision;
|
|
19
|
+
label: string;
|
|
20
|
+
sourceLabel: string;
|
|
21
|
+
}
|
|
22
|
+
/** Return only policies the host enforces independently of stored Hub overrides. */
|
|
23
|
+
export type HubActionPolicy = (input: {
|
|
24
|
+
connection: HubConnection;
|
|
25
|
+
tool: HubTool;
|
|
26
|
+
storedDecision?: HubPolicyDecision;
|
|
27
|
+
}) => HubActionPolicyDisplay | undefined;
|
|
16
28
|
export declare const ACTION_LIMIT = 200;
|
|
17
29
|
export declare function contextKey(identity: {
|
|
18
30
|
userId: string;
|
|
@@ -21,5 +33,5 @@ export declare function contextKey(identity: {
|
|
|
21
33
|
}): string;
|
|
22
34
|
export declare function displayProvider(provider: HubProvider): IntegrationDisplayProvider;
|
|
23
35
|
export declare function catalogRows(providers: readonly HubProvider[], connections: readonly HubConnection[], selectedIds: Readonly<Record<string, string | null>>, can: HubIntegrationCapabilities, hasUnsupportedConnect?: boolean, hostConnectProviderIds?: readonly string[]): IntegrationsProviderRow[];
|
|
24
|
-
/**
|
|
25
|
-
export declare function permissionDetails(tools: readonly HubTool[], policies: readonly HubPolicy[], connectionId: string, can: HubIntegrationCapabilities): IntegrationConnectionDetails;
|
|
36
|
+
/** Host-enforced policy takes precedence; other defaults remain unknown. */
|
|
37
|
+
export declare function permissionDetails(tools: readonly HubTool[], policies: readonly HubPolicy[], connectionId: string, can: HubIntegrationCapabilities, getActionPolicy?: (tool: HubTool, storedDecision?: HubPolicyDecision) => HubActionPolicyDisplay | undefined): IntegrationConnectionDetails;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { HubApiKeyConnectionMetadata, HubConnection, HubPolicyDecision, HubProvider } from '@tangle-network/hub-sdk';
|
|
2
2
|
import type { HubIntegrationsClient, HubIntegrationsIdentity } from './client';
|
|
3
3
|
import { type PopupConnectResult } from './popup';
|
|
4
|
-
import { type HubIntegrationCapabilities } from './projection';
|
|
4
|
+
import { type HubActionPolicy, type HubIntegrationCapabilities } from './projection';
|
|
5
5
|
type Selection = {
|
|
6
6
|
scope: string;
|
|
7
7
|
providerId: string | null;
|
|
@@ -17,6 +17,8 @@ export interface UseHubIntegrationsOptions {
|
|
|
17
17
|
client: HubIntegrationsClient;
|
|
18
18
|
/** Display only. The host server must authorize every exact operation. */
|
|
19
19
|
can: HubIntegrationCapabilities;
|
|
20
|
+
/** Display only; the host server enforces these policies. */
|
|
21
|
+
getActionPolicy?: HubActionPolicy;
|
|
20
22
|
/** Local app route that renders `HubConnectCallbackPage`. */
|
|
21
23
|
callbackPath: string;
|
|
22
24
|
/** Optional host handler for custom/native signup. No Platform redirect is assumed. */
|
|
@@ -70,7 +72,7 @@ export interface HubWriteReceipt {
|
|
|
70
72
|
message: string;
|
|
71
73
|
}
|
|
72
74
|
/** Identity-bound Hub settings controller; connection state is always server-read. */
|
|
73
|
-
export declare function useHubIntegrations({ identity, client, can, callbackPath, onUnsupportedConnect, hostConnect }: UseHubIntegrationsOptions): {
|
|
75
|
+
export declare function useHubIntegrations({ identity, client, can, callbackPath, onUnsupportedConnect, hostConnect, getActionPolicy }: UseHubIntegrationsOptions): {
|
|
74
76
|
providers: import("../web-react/async").AsyncResourceState<HubProvider[]>;
|
|
75
77
|
connections: import("../web-react/async").AsyncResourceState<HubConnection[]>;
|
|
76
78
|
detail: import("../web-react/async").AsyncResourceState<{
|
package/package.json
CHANGED