@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.
@@ -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("cancelled");
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.message && hub.provider ? /* @__PURE__ */ jsx2("p", { role: hub.connectStatus.status === "failed" ? "alert" : "status", children: hub.connectStatus.message }) : null,
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":";;;;;;;AAAA,SAAS,WAAW,gBAAgB;;;ACG7B,IAAM,sBAAsB;AAC5B,IAAM,6BAA6B;AACnC,IAAM,kCAAkC;AACxC,IAAM,mBAAmB,IAAI,KAAK;AACzC,IAAM,0BAA0B;AAChC,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;AAIhB,SAAS,YAAY,MAA0B;AACpD,MAAI,CAAC,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,EAAG,QAAO;AAC3D,MAAI;AACF,UAAM,SAAS,OAAO,WAAW,cAAc,0BAA0B,OAAO,SAAS;AACzF,UAAM,MAAM,IAAI,IAAI,MAAM,MAAM;AAChC,WAAO,IAAI,WAAW,UAAU,CAAC,IAAI,YAAY,CAAC,IAAI,WAAW,MAAM;AAAA,EACzE,QAAQ;AAAE,WAAO;AAAA,EAAK;AACxB;AAEA,SAAS,kBAAkB,YAAoB,QAAkC,OAA0C;AACzH,QAAM,WAAW,IAAI,IAAI,OAAO,OAAO,gBAAc,WAAW,eAAe,UAAU,EAAE,IAAI,gBAAc,CAAC,WAAW,IAAI,UAAU,CAAC,CAAC;AACzI,SAAO,MAAM,KAAK,gBAAc;AAC9B,QAAI,WAAW,eAAe,cAAc,WAAW,WAAW,YAAY,WAAW,WAAW,YAAa,QAAO;AACxH,UAAM,MAAM,SAAS,IAAI,WAAW,EAAE;AACtC,WAAO,CAAC,OAAO,IAAI,cAAc,WAAW,aAAa,IAAI,WAAW,WAAW;AAAA,EACrF,CAAC;AACH;AAEA,SAAS,WAAW,OAAqB;AACvC,MAAI;AAAE,QAAI,CAAC,MAAM,OAAQ,OAAM,MAAM;AAAA,EAAE,QAAQ;AAAA,EAAmC;AACpF;AAEA,SAAS,UAAa,SAAqB,QAAiC;AAC1E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO,SAAS;AAAE,aAAO,IAAI,aAAa,WAAW,YAAY,CAAC;AAAG;AAAA,IAAO;AAChF,UAAM,UAAU,MAAM,OAAO,IAAI,aAAa,WAAW,YAAY,CAAC;AACtE,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,YAAQ,KAAK,WAAS;AAAE,aAAO,oBAAoB,SAAS,OAAO;AAAG,cAAQ,KAAK;AAAA,IAAE,GAAG,WAAS;AAAE,aAAO,oBAAoB,SAAS,OAAO;AAAG,aAAO,KAAK;AAAA,IAAE,CAAC;AAAA,EAClK,CAAC;AACH;AAEA,SAAS,kBAAkB,OAUK;AAC9B,SAAO,IAAI,QAAQ,aAAW;AAC5B,QAAI,UAAU;AACd,QAAI,WAAW;AACf,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,UAAM,SAAS,CAAC,WAA+B;AAC7C,UAAI,QAAS;AACb,gBAAU;AACV,UAAI,WAAW,OAAW,QAAO,aAAa,MAAM;AACpD,UAAI,cAAc,OAAW,QAAO,aAAa,SAAS;AAC1D,YAAM,OAAO,oBAAoB,SAAS,OAAO;AACjD,eAAS,MAAM;AACf,iBAAW,MAAM,KAAK;AACtB,cAAQ,MAAM;AAAA,IAChB;AACA,UAAM,UAAU,MAAM,OAAO,WAAW;AACxC,UAAM,QAAQ,YAAY;AACxB,UAAI,WAAW,SAAU;AACzB,iBAAW;AACX,UAAI,CAAC,MAAM,UAAU,KAAK,MAAM,OAAO,SAAS;AAAE,eAAO,WAAW;AAAG;AAAA,MAAO;AAC9E,UAAI;AACF,cAAM,QAAQ,MAAM,MAAM,OAAO,YAAY,MAAM,UAAU,MAAM,MAAM;AACzE,YAAI,MAAM,UAAU,KAAK,kBAAkB,MAAM,YAAY,MAAM,QAAQ,KAAK,GAAG;AAAE,iBAAO,WAAW;AAAG;AAAA,QAAO;AAAA,MACnH,QAAQ;AAAA,MAAqE;AAC7E,iBAAW;AACX,UAAI,CAAC,QAAS,UAAS,OAAO,WAAW,OAAO,gBAAgB;AAAA,IAClE;AACA,QAAI,MAAM,OAAO,SAAS;AAAE,aAAO,WAAW;AAAG;AAAA,IAAO;AACxD,UAAM,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAC9D,QAAI;AACF,YAAM,YAAY,IAAI,iBAAiB,mBAAmB;AAC1D,gBAAU,YAAY,WAAS;AAC7B,cAAM,UAAU,MAAM;AACtB,YAAI,CAAC,WAAW,QAAQ,aAAa,MAAM,cAAc,QAAQ,UAAU,MAAM,SAAS,QAAQ,YAAY,MAAM,aAAc;AAClI,YAAI,QAAQ,SAAS,gCAAiC,QAAO,QAAQ;AACrE,YAAI,QAAQ,SAAS,4BAA4B;AAC/C,cAAI,WAAW,OAAW,QAAO,aAAa,MAAM;AACpD,eAAK,MAAM;AAAA,QACb;AAAA,MACF;AACA,gBAAU;AAAA,IACZ,QAAQ;AAAA,IAA0D;AAClE,aAAS,OAAO,WAAW,OAAO,gBAAgB;AAClD,gBAAY,OAAO,WAAW,MAAM,OAAO,YAAY,GAAG,gBAAgB;AAAA,EAC5E,CAAC;AACH;AAGA,eAAsB,iBAAiB,OASP;AAC9B,QAAM,WAAW,YAAY,MAAM,YAAY;AAC/C,MAAI,CAAC,SAAU,OAAM,IAAI,UAAU,8BAA8B;AACjE,QAAM,QAAQ,OAAO,KAAK,IAAI,UAAU,cAAc;AACtD,MAAI,CAAC,MAAO,QAAO;AAEnB,MAAI;AAAE,UAAM,SAAS;AAAA,EAAK,QAAQ;AAAA,EAA2C;AAC7E,QAAM,QAAQ,OAAO,WAAW;AAChC,QAAM,eAAe,OAAO,WAAW;AACvC,WAAS,aAAa,IAAI,YAAY,MAAM,UAAU;AACtD,WAAS,aAAa,IAAI,SAAS,KAAK;AACxC,WAAS,aAAa,IAAI,WAAW,YAAY;AACjD,QAAM,UAAU,IAAI,gBAAgB;AACpC,QAAM,UAAU,MAAM,QAAQ,MAAM;AACpC,QAAM,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAC9D,QAAM,gBAAgB,OAAO,WAAW,MAAM,QAAQ,MAAM,GAAG,uBAAuB;AACtF,MAAI;AACF,QAAI,CAAC,MAAM,UAAU,EAAG,QAAO;AAC/B,UAAM,QAAQ,MAAM,UAAU,MAAM,OAAO,WAAW,MAAM,UAAU,MAAM,YAAY;AAAA,MACtF,WAAW,SAAS;AAAA,MACpB,GAAI,MAAM,yBAAyB,SAAY,CAAC,IAAI,EAAE,sBAAsB,MAAM,qBAAqB;AAAA,IACzG,GAAG,QAAQ,MAAM,GAAG,QAAQ,MAAM;AAClC,QAAI,CAAC,MAAM,UAAU,KAAK,MAAM,OAAO,QAAS,QAAO;AACvD,QAAI;AACJ,QAAI;AAAE,iBAAW,IAAI,IAAI,MAAM,WAAW;AAAA,IAAE,QAAQ;AAAE,aAAO;AAAA,IAAc;AAC3E,QAAI,SAAS,aAAa,YAAY,SAAS,YAAY,SAAS,SAAU,QAAO;AACrF,WAAO,aAAa,aAAa;AACjC,UAAM,iBAAiB,IAAI,gBAAgB;AAC3C,UAAM,YAAY,MAAM,eAAe,MAAM;AAC7C,UAAM,OAAO,iBAAiB,SAAS,WAAW,EAAE,MAAM,KAAK,CAAC;AAChE,QAAI,MAAM,OAAO,QAAS,WAAU;AACpC,UAAM,UAAU,kBAAkB,EAAE,GAAG,OAAO,OAAO,OAAO,cAAc,QAAQ,eAAe,OAAO,CAAC;AACzG,QAAI;AACF,YAAM,SAAS,OAAO,SAAS;AAC/B,aAAO,MAAM;AAAA,IACf,QAAQ;AACN,qBAAe,MAAM;AACrB,YAAM;AACN,aAAO;AAAA,IACT,UAAE;AACA,YAAM,OAAO,oBAAoB,SAAS,SAAS;AAAA,IACrD;AAAA,EACF,QAAQ;AACN,WAAO,MAAM,OAAO,WAAW,QAAQ,OAAO,UAAU,cAAc;AAAA,EACxE,UAAE;AACA,WAAO,aAAa,aAAa;AACjC,UAAM,OAAO,oBAAoB,SAAS,OAAO;AACjD,eAAW,KAAK;AAAA,EAClB;AACF;;;AD/H4B,cAEpB,YAFoB;AA1BrB,SAAS,uBAAuB,EAAE,WAAW,GAAgC;AAClF,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA6C,UAAU;AACjF,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AAEvC,YAAU,MAAM;AACd,UAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACzD,UAAM,WAAW,OAAO,IAAI,UAAU;AACtC,UAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,UAAM,UAAU,OAAO,IAAI,SAAS;AACpC,QAAI,CAAC,YAAY,CAAC,SAAS,CAAC,SAAS;AAAE,gBAAU,yCAAyC;AAAG,eAAS,QAAQ;AAAG;AAAA,IAAO;AACxH,UAAM,UAAU,OAAO,IAAI,mBAAmB,KAAK,OAAO,IAAI,OAAO,MAC/D,OAAO,IAAI,gBAAgB,MAAM,UAAU,OAAO,IAAI,WAAW,KAAK,wCAAwC;AACpH,QAAI;AACF,YAAM,UAAU,IAAI,iBAAiB,mBAAmB;AACxD,cAAQ,YAAY,EAAE,MAAM,UAAU,kCAAkC,4BAA4B,UAAU,OAAO,QAAQ,CAAC;AAC9H,cAAQ,MAAM;AAAA,IAChB,QAAQ;AAAA,IAAiE;AACzE,QAAI,SAAS;AAAE,gBAAU,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAG,eAAS,QAAQ;AAAG;AAAA,IAAO;AAC5E,WAAO,MAAM;AACb,UAAM,QAAQ,OAAO,WAAW,MAAM,SAAS,UAAU,GAAG,GAAG;AAC/D,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,CAAC;AAEL,QAAM,cAAc,YAAY,UAAU;AAC1C,QAAM,cAAc,cAAc,GAAG,YAAY,QAAQ,GAAG,YAAY,MAAM,GAAG,YAAY,IAAI,KAAK;AACtG,SAAO,qBAAC,UAAK,aAAU,UAAS,OAAO,EAAE,UAAU,KAAK,QAAQ,aAAa,SAAS,IAAI,WAAW,SAAS,GAC3G;AAAA,cAAU,aAAa,oBAAC,OAAE,4CAAyB,IAAO,UAAU,aACjE,oBAAC,OAAE,oFAAsE,IACzE,qBAAC,OAAE;AAAA;AAAA,MAAoC;AAAA,OAAO;AAAA,IAClD,oBAAC,OAAE,MAAM,aAAa,oCAAsB;AAAA,KAC9C;AACF;;;AEGA,SAAS,OAAO,OAAyC;AACvD,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AACzH,SAAO;AACT;AAEA,SAAS,MAAM,OAA2B;AACxC,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAC3E,SAAO;AACT;AAEA,SAAS,WAAc,OAAgB,KAAkB;AACvD,QAAM,OAAO,MAAM,OAAO,KAAK,EAAE,GAAG,CAAC;AACrC,MAAI,KAAK,KAAK,SAAO,QAAQ,QAAQ,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,CAAC,EAAG,OAAM,IAAI,MAAM,gCAAgC;AACrI,SAAO;AACT;AAEA,SAAS,YAAe,OAAgB,KAAgB;AACtD,SAAO,OAAO,OAAO,KAAK,EAAE,GAAG,CAAC;AAClC;AAEA,SAAS,QAAQ,OAAuB;AACtC,MAAI,CAAC,8BAA8B,KAAK,KAAK,EAAG,OAAM,IAAI,UAAU,kCAAkC;AACtG,SAAO,mBAAmB,KAAK;AACjC;AAGO,SAAS,4BAA4B,SAA+B,WAAW,qBAA4C;AAChI,MAAI,CAAC,0CAA0C,KAAK,QAAQ,EAAG,OAAM,IAAI,UAAU,gCAAgC;AAEnH,iBAAe,KAAK,UAAmC,MAAc,QAA2C,QAAsB,MAAiC;AACrK,QAAI,CAAC,CAAC,SAAS,QAAQ,SAAS,WAAW,SAAS,WAAW,EAAE,MAAM,UAAQ,OAAO,SAAS,YAAY,KAAK,KAAK,CAAC,GAAG;AACvH,YAAM,IAAI,UAAU,oCAAoC;AAAA,IAC1D;AACA,UAAM,WAAW,MAAM,QAAQ;AAAA,MAC7B;AAAA,MACA,MAAM,GAAG,QAAQ,GAAG,IAAI;AAAA,MACxB,MAAM,EAAE,QAAQ,QAAQ,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,SAAS,EAAE,gBAAgB,mBAAmB,GAAG,MAAM,KAAK,UAAU,IAAI,EAAE,EAAG;AAAA,IACzI,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI;AACJ,UAAI;AACF,cAAM,QAAQ,OAAO,MAAM,SAAS,KAAK,CAAC;AAC1C,YAAI,OAAO,MAAM,SAAS,SAAU,QAAO,MAAM;AAAA,MACnD,QAAQ;AAAA,MAAoE;AAC5E,YAAM,IAAI,MAAM,gCAAgC,SAAS,MAAM,GAAG,OAAO,KAAK,IAAI,KAAK,EAAE,IAAI;AAAA,IAC/F;AACA,WAAO,SAAS,KAAK;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,MAAM,UAAU,UAAU,QAAQ;AAAE,aAAO,WAAwB,MAAM,KAAK,UAAU,cAAc,OAAO,MAAM,GAAG,WAAW;AAAA,IAAE;AAAA,IACnI,MAAM,YAAY,UAAU,QAAQ;AAAE,aAAO,WAA0B,MAAM,KAAK,UAAU,gBAAgB,OAAO,MAAM,GAAG,aAAa;AAAA,IAAE;AAAA,IAC3I,MAAM,WAAW,UAAU,YAAY,OAAO,QAAQ;AACpD,YAAM,WAAW,OAAO,MAAM,KAAK,UAAU,gBAAgB,QAAQ,UAAU,CAAC,UAAU,QAAQ,QAAQ,KAAK,CAAC;AAChH,UAAI,OAAO,SAAS,gBAAgB,SAAU,OAAM,IAAI,MAAM,6BAA6B;AAC3F,aAAO;AAAA,IACT;AAAA,IACA,MAAM,cAAc,UAAU,YAAY,QAAQ,UAAU,QAAQ;AAClE,aAAO,YAA2B,MAAM,KAAK,UAAU,gBAAgB,QAAQ,UAAU,CAAC,gBAAgB,QAAQ,QAAQ,EAAE,QAAQ,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS,EAAG,CAAC,GAAG,YAAY;AAAA,IACtM;AAAA,IACA,MAAM,OAAO,UAAU,cAAc,QAAQ;AAAE,aAAO,YAA2B,MAAM,KAAK,UAAU,gBAAgB,QAAQ,YAAY,CAAC,IAAI,UAAU,MAAM,GAAG,YAAY;AAAA,IAAE;AAAA,IAChL,MAAM,OAAO,UAAU,cAAc,QAAQ;AAC3C,YAAM,WAAW,OAAO,MAAM,KAAK,UAAU,gBAAgB,QAAQ,YAAY,CAAC,WAAW,QAAQ,MAAM,CAAC;AAC5G,aAAO,SAAS,UAAU;AAC1B,aAAO,SAAS,MAAM;AACtB,aAAO;AAAA,IACT;AAAA,IACA,MAAM,QAAQ,UAAU,YAAY,OAAO,QAAQ;AACjD,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,IAAK,OAAM,IAAI,UAAU,sCAAiC;AAC/G,YAAM,SAAS,IAAI,gBAAgB,EAAE,OAAO,IAAI,OAAO,OAAO,KAAK,EAAE,CAAC;AACtE,aAAO,WAAoB,MAAM,KAAK,UAAU,cAAc,QAAQ,UAAU,CAAC,YAAY,MAAM,IAAI,OAAO,MAAM,GAAG,OAAO;AAAA,IAChI;AAAA,IACA,MAAM,SAAS,UAAU,cAAc,QAAQ;AAC7C,YAAM,SAAS,IAAI,gBAAgB,EAAE,aAAa,CAAC;AACnD,aAAO,WAAsB,MAAM,KAAK,UAAU,aAAa,MAAM,IAAI,OAAO,MAAM,GAAG,UAAU;AAAA,IACrG;AAAA,IACA,MAAM,UAAU,UAAU,cAAc,YAAY,UAAU,QAAQ;AACpE,aAAO,YAAuB,MAAM,KAAK,UAAU,aAAa,OAAO,QAAQ,EAAE,cAAc,YAAY,SAAS,CAAC,GAAG,QAAQ;AAAA,IAClI;AAAA,IACA,MAAM,YAAY,UAAU,cAAc,YAAY,QAAQ;AAC5D,YAAM,WAAW,OAAO,MAAM,KAAK,UAAU,aAAa,UAAU,QAAQ,EAAE,cAAc,WAAW,CAAC,CAAC;AACzG,UAAI,SAAS,iBAAiB,gBAAgB,SAAS,eAAe,cAAc,OAAO,SAAS,YAAY,WAAW;AACzH,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACF;;;AChIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,QAAQ,MAAM,OAAO,YAAY,MAAM,aAAa,UAAU,mBAAoC;AAC3G,SAAS,aAAAA,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgC;;;ACe9D,IAAM,eAAe;AAErB,SAAS,WAAW,UAA8E;AACvG,SAAO,KAAK,UAAU,CAAC,SAAS,QAAQ,SAAS,WAAW,SAAS,WAAW,CAAC;AACnF;AAEO,SAAS,gBAAgB,UAAmD;AACjF,SAAO,EAAE,YAAY,SAAS,YAAY,OAAO,SAAS,OAAO,UAAU,SAAS,SAAS;AAC/F;AAEO,SAAS,YACd,WACA,aACA,aACA,KACA,wBAAwB,OACxB,yBAA4C,CAAC,GAClB;AAC3B,SAAO,UAAU,IAAI,cAAY;AAC/B,UAAM,WAAW,YAAY,OAAO,gBAAc,WAAW,eAAe,SAAS,UAAU;AAC/F,WAAO;AAAA,MACL,GAAG,gBAAgB,QAAQ;AAAA,MAC3B,MAAM;AAAA,MACN,UAAU,SAAS;AAAA,MACnB,sBAAsB,SAAS,KAAK,aAAW,QAAQ,OAAO,YAAY,SAAS,UAAU,CAAC,IAC1F,YAAY,SAAS,UAAU,KAAK,OAAO;AAAA,MAC/C,YAAY,uBAAuB,SAAS,SAAS,UAAU,IAAI,OAAO,SAAS,aAAa,WAC5F,SAAS,cAAc,IAAI,EAAE,WAAW,eAAe,YAAY,SAAS,WAAW,CAAC,IACxF,SAAS,aAAa,YACpB,SAAS,cAAc,IAAI,EAAE,WAAW,mBAAmB,YAAY,SAAS,WAAW,CAAC,IAC5F;AAAA,MACN,aAAa,SAAS,IAAI,iBAAe;AAAA,QACvC,IAAI,WAAW;AAAA,QACf,gBAAgB,WAAW,kBAAkB,WAAW;AAAA,QACxD,aAAa,WAAW,WAAW,WAAW,cAAc,WAAW,OAAO,WAAW,KAAK,GAAG;AAAA,QACjG,YAAY,WAAW,WAAW,YAAY,WAAW,WAAW,cAAc,YAAY;AAAA,QAC9F,QAAQ,WAAW,qBAAqB;AAAA,QACxC,cAAc;AAAA,UACZ,QAAQ,IAAI,EAAE,WAAW,iBAAiB,cAAc,WAAW,GAAG,CAAC;AAAA,UACvE,YAAY,IAAI,EAAE,WAAW,qBAAqB,cAAc,WAAW,GAAG,CAAC;AAAA,UAC/E,MAAM,IAAI,EAAE,WAAW,qBAAqB,cAAc,WAAW,GAAG,CAAC;AAAA,UACzE,iBAAiB,IAAI,EAAE,WAAW,iBAAiB,cAAc,WAAW,GAAG,CAAC;AAAA,UAChF,kBAAkB,IAAI,EAAE,WAAW,iBAAiB,cAAc,WAAW,GAAG,CAAC;AAAA,QACnF;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF,CAAC;AACH;AAEA,IAAM,UAAU;AAAA,EACd,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,EACjC,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,EAC7B,EAAE,OAAO,QAAQ,OAAO,OAAO;AACjC;AAGO,SAAS,kBACd,OACA,UACA,cACA,KACA,iBAC8B;AAC9B,QAAM,YAAY,IAAI,IAAI,SAAS,OAAO,YAAU,OAAO,iBAAiB,YAAY,EAAE,IAAI,YAAU,CAAC,OAAO,YAAY,OAAO,QAAQ,CAAC,CAAC;AAC7I,QAAM,SAAuC;AAAA,IAC3C,EAAE,IAAI,UAAU,OAAO,6BAA6B,MAAM,CAAC,EAAE;AAAA,IAC7D,EAAE,IAAI,SAAS,OAAO,gBAAgB,WAAW,MAAM,MAAM,CAAC,EAAE;AAAA,EAClE;AACA,QAAM,SAAyC,CAAC;AAChD,QAAM,QAAwC,CAAC;AAC/C,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,UAAU,IAAI,KAAK,IAAI;AACxC,UAAM,WAAW,kBAAkB,MAAM,QAAQ;AACjD,UAAM,MAAM;AAAA,MACV,YAAY,KAAK;AAAA,MACjB,OAAO,KAAK,SAAS,KAAK;AAAA,MAC1B,WAAW,KAAK,QAAQ;AAAA,MACxB,UAAU,KAAK,SAAS,gBAAgB,UAAU,KAAK,SAAS,WAAW,KAAK,SAAS,SAAY,YAAY;AAAA,MACjH,UAAU,UAAU,YAAY,YAAY;AAAA,MAC5C,iBAAiB,WAAW,CAAC,EAAE,OAAO,SAAS,UAAU,OAAO,SAAS,MAAM,CAAC,IAAI;AAAA,MACpF,aAAa,UAAU,gBAAgB,WAAW,oBAAoB;AAAA,MACtE,UAAU,CAAC,YAAY,aAAa,UAAa,IAAI,EAAE,WAAW,gBAAgB,cAAc,YAAY,KAAK,KAAK,CAAC;AAAA,MACvH,UAAU,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,cAAc,cAAc,YAAY,KAAK,KAAK,CAAC;AAAA,IAC/F;AACA,QAAI,KAAK,SAAS,OAAQ,OAAM,KAAK,GAAG;AAAA,QACnC,QAAO,KAAK,GAAG;AAAA,EACtB;AACA,SAAO,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AACpD,QAAM,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AACnD,SAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,GAAI,MAAM,OAAO;AAC1C,SAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,GAAI,MAAM,MAAM;AACzC,SAAO,EAAE,kBAAkB,OAAO;AACpC;;;ACtHA,SAAS,aAAa,aAAAC,YAAW,SAAS,QAAQ,YAAAC,iBAAgB;AA+ClE,SAAS,iBAAiB,OAA0B;AAClD,MAAI,OAAO,WAAW,YAAa,QAAO,EAAE,OAAO,YAAY,MAAM,cAAc,KAAK;AACxF,QAAM,QAAQ,IAAI,IAAI,OAAO,SAAS,IAAI,EAAE;AAC5C,SAAO,EAAE,OAAO,YAAY,MAAM,IAAI,aAAa,GAAG,cAAc,MAAM,IAAI,YAAY,EAAE;AAC9F;AAEA,SAAS,UAAU,YAA2B,cAAmC;AAC/E,MAAI,OAAO,WAAW,YAAa;AACnC,QAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,MAAI,WAAY,KAAI,aAAa,IAAI,eAAe,UAAU;AAAA,MACzD,KAAI,aAAa,OAAO,aAAa;AAC1C,MAAI,aAAc,KAAI,aAAa,IAAI,cAAc,YAAY;AAAA,MAC5D,KAAI,aAAa,OAAO,YAAY;AACzC,SAAO,QAAQ,UAAU,OAAO,QAAQ,OAAO,IAAI,GAAG;AACxD;AAGO,SAAS,mBAAmB,EAAE,UAAU,QAAQ,KAAK,cAAc,sBAAsB,aAAa,gBAAgB,GAA8B;AACzJ,QAAM,QAAQ,WAAW,QAAQ;AACjC,QAAM,cAAc,OAAO,KAAK;AAChC,cAAY,UAAU;AACtB,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAoB,MAAM,iBAAiB,KAAK,CAAC;AACnF,QAAM,mBAAmB,UAAU,UAAU,QAAQ,YAAY,EAAE,OAAO,YAAY,MAAM,cAAc,KAAK;AAC/G,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAiB,IAAI;AACjD,QAAM,gBAAgB,QAAQ,UAAU,QAAQ,SAAS;AACzD,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAAwH,EAAE,OAAO,QAAQ,OAAO,CAAC;AAC3L,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,eAAe,OAA+B,IAAI;AAExD,EAAAC,WAAU,MAAM;AACd,UAAM,QAAQ,MAAM,aAAa,iBAAiB,KAAK,CAAC;AACxD,WAAO,iBAAiB,YAAY,KAAK;AACzC,WAAO,MAAM,OAAO,oBAAoB,YAAY,KAAK;AAAA,EAC3D,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,YAAY,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,MAAM,OAAO,UAAU,UAAU,MAAM,GAAG,MAAM,CAAC,QAAQ,KAAK,GAAG,SAAS,MAAM,MAAM,CAAC;AAC5I,QAAM,cAAc,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,MAAM,OAAO,YAAY,UAAU,MAAM,GAAG,MAAM,CAAC,QAAQ,KAAK,GAAG,SAAS,MAAM,MAAM,CAAC;AAChJ,QAAM,eAAe,UAAU,WAAW,UAAU,UAAU,QAAQ,CAAC;AACvE,QAAM,iBAAiB,YAAY,WAAW,UAAU,YAAY,QAAQ,CAAC;AAC7E,QAAM,WAAW,aAAa,KAAK,UAAQ,KAAK,eAAe,iBAAiB,UAAU,KAAK;AAC/F,QAAM,aAAa,eAAe,KAAK,UAAQ,KAAK,OAAO,iBAAiB,gBAAgB,KAAK,eAAe,UAAU,UAAU,KAAK;AACzI,QAAM,kBAAkB,eAAe,QAAQ,IAAI,EAAE,WAAW,iBAAiB,cAAc,WAAW,GAAG,CAAC;AAC9G,QAAM,SAAS,iBAAiB;AAAA,IAC9B,SAAS,mBAAmB,YAAY,WAAW;AAAA,IACnD,MAAM,CAAC,QAAQ,OAAO,UAAU,YAAY,YAAY,IAAI,eAAe;AAAA,IAC3E,SAAS,MAAM;AAAA,IACf,MAAM,OAAO,EAAE,OAAO,MAAM;AAC1B,UAAI,CAAC,YAAY,CAAC,WAAY,OAAM,IAAI,MAAM,sBAAsB;AACpE,YAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC1C,OAAO,QAAQ,UAAU,SAAS,YAAY,cAAc,MAAM;AAAA,QAClE,OAAO,SAAS,UAAU,WAAW,IAAI,MAAM;AAAA,MACjD,CAAC;AACD,UAAI,MAAM,KAAK,UAAQ,CAAC,KAAK,KAAK,WAAW,GAAG,SAAS,UAAU,GAAG,CAAC,KAAK,SAAS,KAAK,YAAU,OAAO,iBAAiB,WAAW,EAAE,GAAG;AAC1I,cAAM,IAAI,MAAM,uDAAuD;AAAA,MACzE;AACA,aAAO,EAAE,OAAO,UAAU,WAAW,MAAM,UAAU,aAAa;AAAA,IACpE;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,qBAAkD;AAAA,IAC9D,aAAa;AAAA,IACb,QAAQ,OAAO,OAAO,EAAE,OAAO,MAAM;AACnC,UAAI,MAAM,UAAU,YAAY,QAAS,OAAM,IAAI,MAAM,8DAA8D;AACvH,YAAM,SAAS,MAAM;AACrB,YAAM,UAAU,CAAC,gBAAmD,YAAoB,aAA8B,EAAE,OAAO,MAAM,OAAO,MAAM,MAAM,MAAM,gBAAgB,QAAQ,CAAC;AACvL,UAAI,MAAM,SAAS,WAAW;AAC5B,YAAI,CAAC,IAAI,EAAE,WAAW,mBAAmB,YAAY,MAAM,WAAW,CAAC,EAAG,OAAM,IAAI,MAAM,kCAAkC;AAC5H,cAAM,UAAU,MAAM,OAAO,cAAc,QAAQ,MAAM,YAAY,MAAM,QAAQ,MAAM,UAAU,MAAM;AACzG,YAAI,QAAQ,eAAe,MAAM,cAAc,QAAQ,WAAW,SAAU,OAAM,IAAI,MAAM,+CAA+C;AAC3I,YAAI;AACF,gBAAM,UAAU,MAAM,OAAO,YAAY,QAAQ,MAAM;AACvD,iBAAO,QAAQ,KAAK,UAAQ,KAAK,OAAO,QAAQ,MAAM,KAAK,WAAW,QAAQ,IAC1E,QAAQ,YAAY,gCAAgC,IAAI,QAAQ,kBAAkB,iEAAiE;AAAA,QACzJ,QAAQ;AAAE,iBAAO,QAAQ,kBAAkB,mCAAmC;AAAA,QAAE;AAAA,MAClF;AACA,UAAI,MAAM,SAAS,UAAU;AAC3B,YAAI,CAAC,IAAI,EAAE,WAAW,qBAAqB,cAAc,MAAM,aAAa,CAAC,EAAG,OAAM,IAAI,MAAM,4BAA4B;AAC5H,cAAM,OAAO,OAAO,QAAQ,MAAM,cAAc,MAAM;AACtD,YAAI;AACF,gBAAM,UAAU,MAAM,OAAO,YAAY,QAAQ,MAAM;AACvD,iBAAO,QAAQ,KAAK,UAAQ,KAAK,OAAO,MAAM,gBAAgB,KAAK,WAAW,QAAQ,IAClF,QAAQ,kBAAkB,wDAAwD,IAAI,QAAQ,YAAY,uCAAuC;AAAA,QACvJ,QAAQ;AAAE,iBAAO,QAAQ,kBAAkB,+BAA+B;AAAA,QAAE;AAAA,MAC9E;AACA,UAAI,MAAM,SAAS,UAAU;AAC3B,YAAI,CAAC,IAAI,EAAE,WAAW,qBAAqB,cAAc,MAAM,aAAa,CAAC,EAAG,OAAM,IAAI,MAAM,iCAAiC;AACjI,cAAM,SAAS,MAAM,OAAO,OAAO,QAAQ,MAAM,cAAc,MAAM;AACrE,YAAI,OAAO,WAAW,OAAO,MAAM,aAAc,OAAM,IAAI,MAAM,kCAAkC;AACnG,eAAO,QAAQ,YAAY,oBAAoB,OAAO,OAAO,OAAO,WAAW,KAAK,GAAG,CAAC,GAAG;AAAA,MAC7F;AACA,UAAI,CAAC,IAAI,EAAE,WAAW,MAAM,SAAS,QAAQ,eAAe,gBAAgB,cAAc,MAAM,cAAc,YAAY,MAAM,WAAW,CAAC,GAAG;AAC7I,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AACA,UAAI,MAAM,SAAS,OAAO;AACxB,cAAM,SAAS,MAAM,OAAO,UAAU,QAAQ,MAAM,cAAc,MAAM,YAAY,MAAM,UAAU,MAAM;AAC1G,YAAI,OAAO,iBAAiB,MAAM,gBAAgB,OAAO,eAAe,MAAM,cAAc,OAAO,aAAa,MAAM,UAAU;AAC9H,gBAAM,IAAI,MAAM,+CAA+C;AAAA,QACjE;AAAA,MACF,MAAO,OAAM,OAAO,YAAY,QAAQ,MAAM,cAAc,MAAM,YAAY,MAAM;AACpF,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,SAAS,QAAQ,MAAM,cAAc,MAAM;AACxE,cAAM,WAAW,QAAQ,KAAK,YAAU,OAAO,eAAe,MAAM,UAAU;AAC9E,cAAM,UAAU,MAAM,SAAS,QAAQ,UAAU,aAAa,MAAM,WAAW,aAAa;AAC5F,eAAO,UACH,QAAQ,YAAY,gCAAgC,IAAI,QAAQ,kBAAkB,gEAAgE;AAAA,MACxJ,QAAQ;AAAE,eAAO,QAAQ,kBAAkB,gDAAgD;AAAA,MAAE;AAAA,IAC/F;AAAA,IACA,aAAa,WAAS;AAAE,UAAI,MAAM,UAAU,YAAY,SAAS;AAAE,oBAAY,MAAM;AAAG,eAAO,MAAM;AAAA,MAAE;AAAA,IAAE;AAAA,EAC3G,CAAC;AAED,EAAAA,WAAU,MAAM;AACd,iBAAa,SAAS,MAAM;AAC5B,iBAAa,UAAU;AACvB,cAAU,IAAI;AACd,qBAAiB,EAAE,OAAO,QAAQ,OAAO,CAAC;AAC1C,kBAAc,KAAK;AACnB,UAAM,MAAM;AACZ,WAAO,MAAM;AAAE,mBAAa,SAAS,MAAM;AAAG,mBAAa,UAAU;AAAA,IAAK;AAAA,EAC5E,GAAG,CAAC,OAAO,QAAQ,MAAM,KAAK,CAAC;AAE/B,QAAM,iBAAiB,YAAY,CAAC,eAA8B;AAChE,UAAM,OAAO,EAAE,OAAO,YAAY,cAAc,KAAK;AACrD,iBAAa,IAAI;AACjB,cAAU,YAAY,IAAI;AAAA,EAC5B,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,mBAAmB,YAAY,CAAC,YAAoB,iBAAgC;AACxF,QAAI,gBAAgB,CAAC,eAAe,KAAK,UAAQ,KAAK,OAAO,gBAAgB,KAAK,eAAe,UAAU,EAAG;AAC9G,iBAAa,EAAE,OAAO,YAAY,aAAa,CAAC;AAChD,cAAU,YAAY,YAAY;AAAA,EACpC,GAAG,CAAC,OAAO,cAAc,CAAC;AAE1B,QAAM,aAAa,YAAY,OAAO,QAAqB,yBAA+E;AACxI,QAAI,CAAC,IAAI,EAAE,WAAW,eAAe,YAAY,OAAO,WAAW,CAAC,EAAG,QAAO;AAC9E,QAAI,YAAY,WAAW,SAAS;AAAE,uBAAiB,EAAE,OAAO,QAAQ,UAAU,SAAS,sCAAsC,CAAC;AAAG,aAAO;AAAA,IAAc;AAC1J,iBAAa,SAAS,MAAM;AAC5B,UAAM,aAAa,IAAI,gBAAgB;AACvC,iBAAa,UAAU;AACvB,qBAAiB,EAAE,OAAO,QAAQ,WAAW,YAAY,OAAO,WAAW,CAAC;AAC5E,UAAM,SAAS,MAAM,iBAAiB;AAAA,MACpC;AAAA,MAAQ;AAAA,MAAU,YAAY,OAAO;AAAA,MAAY,QAAQ,YAAY;AAAA,MACrE;AAAA,MAAc;AAAA,MAAsB,QAAQ,WAAW;AAAA,MACvD,WAAW,MAAM,YAAY,YAAY,SAAS,CAAC,WAAW,OAAO;AAAA,IACvE,CAAC;AACD,QAAI,aAAa,YAAY,cAAc,YAAY,YAAY,MAAO,QAAO;AACjF,iBAAa,UAAU;AACvB,QAAI,WAAW,aAAa;AAC1B,kBAAY,MAAM;AAClB,gBAAU,IAAI;AACd,uBAAiB,EAAE,OAAO,QAAQ,aAAa,SAAS,uBAAuB,CAAC;AAAA,IAClF,MAAO,kBAAiB,EAAE,OAAO,QAAQ,UAAU,YAAY,OAAO,YAAY,SAAS,WAAW,YAAY,mCAAmC,WAAW,eAAe,8DAA8D,WAAW,WAAW,sDAAsD,WAAW,cAAc,8BAA8B,uCAAuC,CAAC;AACxZ,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,aAAa,QAAQ,UAAU,cAAc,KAAK,CAAC;AAE5D,QAAM,eAAe,YAAY,CAAC,WAAwB;AACxD,QAAI,aAAa,YAAY,SAAS,OAAO,UAAU,GAAG;AACxD,kBAAY,UAAU,MAAM;AAC5B;AAAA,IACF;AACA,QAAI,OAAO,aAAa,aAAa,OAAO,aAAa,UAAU;AACjE,UAAI,qBAAsB,sBAAqB,MAAM;AAAA,UAChD,kBAAiB,EAAE,OAAO,QAAQ,UAAU,SAAS,uDAAuD,CAAC;AAClH;AAAA,IACF;AACA,QAAI,CAAC,OAAO,YAAY;AACtB,uBAAiB,EAAE,OAAO,QAAQ,UAAU,SAAS,kDAAkD,CAAC;AACxG;AAAA,IACF;AACA,QAAI,OAAO,aAAa,WAAW;AACjC,UAAI,IAAI,EAAE,WAAW,mBAAmB,YAAY,OAAO,WAAW,CAAC,EAAG,WAAU,EAAE,OAAO,MAAM,WAAW,UAAU,OAAO,CAAC;AAAA,UAC3H,kBAAiB,EAAE,OAAO,QAAQ,UAAU,SAAS,mCAAmC,CAAC;AAC9F;AAAA,IACF;AACA,QAAI,OAAO,aAAa,UAAU;AAChC,UAAI,CAAC,IAAI,EAAE,WAAW,eAAe,YAAY,OAAO,WAAW,CAAC,GAAG;AACrE,yBAAiB,EAAE,OAAO,QAAQ,UAAU,SAAS,mCAAmC,CAAC;AAAG;AAAA,MAC9F;AACA,UAAI,OAAO,sBAAsB,OAAQ,WAAU,EAAE,OAAO,MAAM,SAAS,UAAU,OAAO,CAAC;AAAA,UACxF,MAAK,WAAW,MAAM;AAC3B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,KAAK,sBAAsB,aAAa,OAAO,UAAU,CAAC;AAE9D,QAAM,gBAAgB,YAAY,MAAM;AACtC,iBAAa,SAAS,MAAM;AAC5B,iBAAa,UAAU;AACvB,cAAU,IAAI;AACd,qBAAiB,cAAY,EAAE,OAAO,QAAQ,UAAU,YAAY,QAAQ,UAAU,QAAQ,QAAQ,aAAa,QAAW,SAAS,4BAA4B,EAAE;AAAA,EACvK,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,OAAO;AAAA,IAAQ,MAAM;AAAA,MAAY;AAAA,MAAc;AAAA,MAAgB,iBAAiB,cAAc,iBAAiB,eACjH,EAAE,CAAC,iBAAiB,UAAU,GAAG,iBAAiB,aAAa,IAAI,CAAC;AAAA,MAAG;AAAA,MAAK,CAAC,CAAC;AAAA,MAChF,aAAa;AAAA,IAAW;AAAA,IAC1B,CAAC,cAAc,gBAAgB,iBAAiB,YAAY,iBAAiB,cAAc,KAAK,sBAAsB,WAAW;AAAA,EAAC;AAClI,QAAM,UAAU,OAAO,WAAW,WAAW,aACzC,kBAAkB,OAAO,MAAM,OAAO,OAAO,MAAM,UAAU,WAAW,IAAI,KAAK,CAAC,MAAM,mBAAmB,kBAAkB,EAAE,YAAY,MAAM,eAAe,CAAC,CAAC,IAAI;AAE1K,SAAO;AAAA,IACL;AAAA,IAAW;AAAA,IAAa;AAAA,IAAQ;AAAA,IAAM;AAAA,IAAU;AAAA,IAAY,QAAQ;AAAA,IAAe;AAAA,IACnF,eAAe,cAAc,UAAU,QAAQ,gBAAgB,EAAE,OAAO,QAAQ,QAAiB,YAAY,OAAU;AAAA,IACvH,WAAW;AAAA,IAAkB;AAAA,IAAgB;AAAA,IAAkB;AAAA,IAAc;AAAA,IAAY;AAAA,IACzF;AAAA,IAAO,YAAY,eAAe,QAAQ,MAAM,QAAQ,EAAE,QAAQ,OAAgB;AAAA,IAAG;AAAA,IACrF,SAAS,MAAM;AAAE,gBAAU,MAAM;AAAG,kBAAY,MAAM;AAAG,aAAO,MAAM;AAAA,IAAE;AAAA,IACxE,cAAc,CAAC,YAAoB,QAAgB,aAA2C;AAAE,oBAAc,KAAK;AAAG,aAAO,MAAM,IAAI,EAAE,MAAM,WAAW,UAAU,OAAO,YAAY,QAAQ,SAAS,CAAC;AAAA,IAAE;AAAA,IAC3M,QAAQ,CAAC,iBAAyB;AAAE,oBAAc,KAAK;AAAG,aAAO,MAAM,IAAI,EAAE,MAAM,UAAU,UAAU,OAAO,aAAa,CAAC;AAAA,IAAE;AAAA,IAC9H,MAAM,CAAC,iBAAyB;AAAE,oBAAc,KAAK;AAAG,aAAO,MAAM,IAAI,EAAE,MAAM,UAAU,UAAU,OAAO,aAAa,CAAC;AAAA,IAAE;AAAA,IAC5H,aAAa,CAAC,cAAsB,YAAoB,aAAgC;AAAE,oBAAc,KAAK;AAAG,aAAO,MAAM,IAAI,EAAE,MAAM,OAAO,UAAU,OAAO,cAAc,YAAY,SAAS,CAAC;AAAA,IAAE;AAAA,IACvM,eAAe,CAAC,cAAsB,eAAuB;AAAE,oBAAc,KAAK;AAAG,aAAO,MAAM,IAAI,EAAE,MAAM,SAAS,UAAU,OAAO,cAAc,WAAW,CAAC;AAAA,IAAE;AAAA,EACtK;AACF;;;AFhJkB,SAoLE,UApLF,OAAAC,MA6Bd,QAAAC,aA7Bc;AAvClB,IAAM,mBAA2D;AAAA,EAC/D,WAAW;AAAA,EACX,eAAe;AAAA,EACf,OAAO;AAAA,EACP,SAAS;AACX;AAMO,SAAS,eAAe,OAAuC;AACpE,SAAO,iBAAiB,KAAK;AAC/B;AAGO,SAAS,oBAAoB,YAAsH;AACxJ,QAAM,SAAS,CAAC,OAA2B,WAAmB,EAAE,OAAO,OAAO,MAAM,eAAe,KAAK,EAAE;AAC1G,MAAI,WAAW,WAAW,UAAW,QAAO,OAAO,iBAAiB,eAAe;AACnF,MAAI,WAAW,WAAW,qBAAsB,QAAO,OAAO,SAAS,oBAAoB;AAC3F,MAAI,WAAW,WAAW,eAAe,WAAW,WAAW,YAAa,QAAO,OAAO,SAAS,iBAAiB;AACpH,MAAI,WAAW,WAAW,eAAgB,QAAO,OAAO,WAAW,cAAc;AACjF,SAAO,OAAO,aAAa,WAAW;AACxC;AAEA,SAAS,cAAsB;AAC7B,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,MAAI,aAAa,OAAO,aAAa;AACrC,MAAI,aAAa,OAAO,YAAY;AACpC,SAAO,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM,GAAG,IAAI,IAAI;AAChD;AAEA,SAAS,YAAY,YAA2B,eAA+B;AAC7E,SAAO,WAAW,gBAAgB,KAAK,KAAK,WAAW,aAAa,KAAK,KAAK;AAChF;AAEA,SAAS,cAAc,EAAE,YAAY,SAAS,GAAqE;AACjH,QAAM,SAAS,SAAS,YAAY,UAAU;AAC9C,SAAO,SAAS,gBAAAD,KAAC,cAAW,MAAM,OAAO,QAAQ,WAAW,MAAK,MAAK,WAAU,gCAAgC,iBAAO,OAAM,IAAgB;AAC/I;AAEA,SAAS,qBAAqB,EAAE,YAAY,UAAU,KAAK,GAAoF;AAC7I,QAAM,UAAU,SAAS,mBAAmB,UAAU;AACtD,SAAO,UAAU,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAAO,MAAK;AAAA,MAAS,SAAQ;AAAA,MAAU,MAAK;AAAA,MAAK,UAAU,QAAQ,QAAQ;AAAA,MAC3F,SAAS,QAAQ;AAAA,MAAW,kBAAQ;AAAA;AAAA,EAAM,IAAY;AAC1D;AAEA,SAAS,eAAe,EAAE,UAAU,aAAa,WAAW,SAAS,OAAO,MAAM,SAAS,UAAU,WAAW,MAAM,GAWnH;AACD,QAAM,CAAC,OAAO,QAAQ,IAAIE,UAAS,EAAE;AACrC,QAAM,SAAS,IAAI,IAAI,UAAU,IAAI,cAAY,CAAC,SAAS,YAAY,SAAS,KAAK,CAAC,CAAC;AACvF,QAAM,QAAQ,CAAC,eAA8B,OAAO,IAAI,WAAW,UAAU,KAAK,WAAW,eAAe,WAAW;AACvH,QAAM,OAAO,YAAY,OAAO,gBAAc,WAAW,WAAW,SAAS,EAC1E,IAAI,iBAAe,EAAE,YAAY,UAAU,MAAM,UAAU,GAAG,MAAM,YAAY,YAAY,MAAM,UAAU,CAAC,EAAE,EAAE,EACjH,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,cAAc,EAAE,QAAQ,KAAK,EAAE,KAAK,cAAc,EAAE,IAAI,KAAK,EAAE,WAAW,GAAG,cAAc,EAAE,WAAW,EAAE,CAAC;AACxI,QAAM,WAAW,KAAK,OAAO,SAAO,GAAG,IAAI,QAAQ,IAAI,IAAI,IAAI,GAAG,kBAAkB,EAAE,SAAS,MAAM,KAAK,EAAE,kBAAkB,CAAC,CAAC;AAChI,SAAO,gBAAAD,MAAC,aAAQ,WAAU,qBAAoB,mBAAgB,wBAAuB,aAAW,WAAW,QACzG;AAAA,oBAAAA,MAAC,YACC;AAAA,sBAAAD,KAAC,QAAG,IAAG,wBAAuB,WAAU,WAAW,mBAAS,OAAM;AAAA,MACjE,SAAS,cAAc,gBAAAA,KAAC,OAAE,WAAU,iCAAiC,mBAAS,aAAY,IAAO;AAAA,OACpG;AAAA,IACC,KAAK,SAAS,KAAK,CAAC,QAAQ,gBAAAA,KAAC,SAAM,MAAK,UAAS,cAAW,mBAAkB,aAAY,yBAAmB,OAAO,OAAO,UAAU,WAAS,SAAS,MAAM,OAAO,KAAK,GAAG,IAAK;AAAA,IACjL,QAAQ,gBAAAC,MAAC,SAAI,MAAK,SAAQ,WAAU,0GACnC;AAAA,sBAAAD,KAAC,OAAE,WAAU,8BAA8B,iBAAM;AAAA,MACjD,gBAAAA,KAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,SAAS,mBAAK;AAAA,OAC3E,IAAS,WAAW,KAAK,WAAW,IAAI,gBAAAA,KAAC,OAAE,MAAK,UAAS,WAAU,sCAAqC,8CAA2B,IAC/H,KAAK,WAAW,IAAI,gBAAAC,MAAC,QAAK,aAAU,QAAO,WAAU,iBAAgB;AAAA,sBAAAD,KAAC,OAAE,WAAU,iCAAiC,mBAAS,cAAc,8BAA6B;AAAA,MAAI,gBAAAA,KAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,OAAO,6BAAe;AAAA,OAAS,IACzP,SAAS,WAAW,IAAI,gBAAAA,KAAC,OAAE,MAAK,UAAS,WAAU,sCAAqC,4CAA8B,IACtH,gBAAAA,KAAC,QAAG,WAAU,wDAAuD,cAAY,SAAS,OACzF,mBAAS,IAAI,CAAC,EAAE,YAAY,UAAU,KAAK,MAAM;AAChD,YAAM,QAAQ,oBAAoB,UAAU;AAC5C,aAAO,gBAAAA,KAAC,QAAuB,eAAa,eAAe,WAAW,EAAE,IAAI,WAAU,WACpF,0BAAAC,MAAC,QAAK,aAAU,QAAO,yBAAuB,MAAM,OAAO,WAAU,0CACrE;AAAA,wBAAAA,MAAC,SAAI,WAAU,mCACb;AAAA,0BAAAD,KAAC,SAAI,WAAU,4EAA2E,0BAAAA,KAAC,gBAAa,IAAI,WAAW,YAAY,aAAa,UAAU,MAAM,IAAI,WAAU,uBAAsB,GAAE;AAAA,UACtM,gBAAAC,MAAC,SAAI,WAAU,WACb;AAAA,4BAAAD,KAAC,OAAE,WAAU,oDAAoD,oBAAS;AAAA,YAC1E,gBAAAA,KAAC,cAAW,MAAM,MAAM,MAAM,MAAK,MAAK,WAAU,QAAQ,gBAAM,OAAM;AAAA,aACxE;AAAA,WACF;AAAA,QACA,gBAAAA,KAAC,OAAE,WAAU,gDAAgD,gBAAK;AAAA,QAClE,gBAAAC,MAAC,SAAI,WAAU,qBACb;AAAA,0BAAAD,KAAC,iBAAc,YAAwB,UAAoB;AAAA,UAC3D,gBAAAC,MAAC,SAAI,WAAU,iEACb;AAAA,4BAAAD,KAAC,wBAAqB,YAAwB,UAAoB,MAAY;AAAA,YAC7E,UAAU,UAAU,IAAI,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAAO,MAAK;AAAA,gBAAS,SAAQ;AAAA,gBAAU,MAAK;AAAA,gBAAK,cAAY,UAAU,QAAQ,YAAY,IAAI;AAAA,gBACvH,SAAS,MAAM,SAAS,UAAU;AAAA,gBAAG;AAAA;AAAA,YAAM,IAAY;AAAA,aAC3D;AAAA,WACF;AAAA,SACA,KAlBc,WAAW,EAmB3B;AAAA,IACF,CAAC,GACH;AAAA,IACH,SAAS;AAAA,KACZ;AACF;AAGO,SAAS,qBAAqB,OAAkC;AACrE,QAAM,MAAM,mBAAmB,KAAK;AACpC,QAAM,QAAQ,WAAW,MAAM,QAAQ;AACvC,QAAM,cAAcG,QAAO,KAAK;AAChC,cAAY,UAAU;AACtB,QAAM,eAAeA,QAAO,IAAI,MAAM;AACtC,eAAa,UAAU,IAAI;AAC3B,QAAM,CAAC,OAAO,QAAQ,IAAID,UAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,EAAE;AAC3C,QAAM,CAAC,MAAM,OAAO,IAAIA,UAA0B,UAAU;AAC5D,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAkE,IAAI;AAC9F,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAgE,EAAE,OAAO,KAAK,CAAC,EAAE,CAAC;AAClI,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,EAAE,OAAO,OAAO,GAAG,CAAC;AAC7D,QAAM,SAAS,SAAS,UAAU,QAAQ,SAAS,QAAQ;AAC3D,QAAM,YAAY,CAAC,UAAkB,YAAY,EAAE,OAAO,MAAM,CAAC;AACjE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAA4E,EAAE,OAAO,OAAO,OAAU,CAAC;AACjJ,QAAM,WAAW,cAAc,UAAU,QAAQ,cAAc,QAAQ;AACvE,QAAM,cAAc,CAAC,UAAmD,iBAAiB,EAAE,OAAO,MAAM,CAAC;AACzG,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAAS,EAAE,OAAO,QAAQ,CAAC,EAA4B,CAAC;AACpG,QAAM,aAAa,eAAe,UAAU,QAAQ,eAAe,SAAS,CAAC;AAC7E,QAAM,gBAAgB,CAAC,WAAmC,kBAAkB,EAAE,OAAO,OAAO,CAAC;AAE7F,EAAAE,WAAU,MAAM;AAAE,cAAU,EAAE;AAAG,gBAAY,MAAS;AAAG,kBAAc,CAAC,CAAC;AAAA,EAAE,GAAG,CAAC,KAAK,CAAC;AACrF,QAAM,UAAU,IAAI,WAAW,WAAW,aAAa,IAAI,cAAc,WAAW;AACpF,QAAM,QAAQ,IAAI,UAAU,WAAW,UAAU,IAAI,UAAU,UAC3D,IAAI,YAAY,WAAW,UAAU,IAAI,YAAY,UAAU;AACnE,QAAM,gBAAgB,IAAI,WAAW,WAAW,WAAW,IAAI,WAAW,UAAU;AACpF,QAAM,eAAe,IAAI,WAAW,WAAW,cAAc,IAAI,WAAW,MAAM,UAAU;AAC5F,QAAM,eAAe,IAAI,WAAW,WAAW,eAAe,IAAI,WAAW,MAAM,mBAAmB;AACtG,QAAM,OAAO,IAAI,KAAK,IAAI,SAAO;AAC/B,UAAM,aAAa,iBAAiB,UAAU,QAAQ,iBAAiB,IAAI,IAAI,UAAU,IAAI;AAC7F,WAAO;AAAA,MACL,GAAG;AAAA,MACH,sBAAsB,IAAI,YAAY,KAAK,gBAAc,WAAW,OAAO,UAAU,IAAI,cAAc,OAAO;AAAA,MAC9G,aAAa,IAAI,YAAY,IAAI,gBAAc;AAC7C,cAAM,SAAS,IAAI,YAAY,WAAW,UACtC,IAAI,YAAY,MAAM,KAAK,UAAQ,KAAK,OAAO,WAAW,EAAE,IAAI;AACpE,eAAO,SAAS;AAAA,UACd,GAAG;AAAA,UACH,QAAQ,MAAM,uBAAuB,MAAM,KAAK,WAAW;AAAA,UAC3D,SAAS,MAAM,uBAAuB,MAAM;AAAA,QAC9C,IAAI;AAAA,MACN,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACD,QAAM,cAAc,KAAK,KAAK,SAAO,IAAI,eAAe,IAAI,UAAU,UAAU;AAChF,QAAM,iBAAiB,IAAI,YAAY,WAAW,UAAU,IAAI,YAAY,QAAQ,CAAC;AACrF,QAAM,eAAe,eAAe,OAAO,gBAAc,WAAW,WAAW,SAAS,EAAE;AAC1F,QAAM,aAAa,MAAM,UAAU,QAAQ,KAAK,QAAQ,IAAI,YAAY,WAAW,WAAW,iBAAiB,IAAI,YAAY;AAC/H,QAAM,eAAe,MAAM,QAAQ,EAAE,OAAO,OAAO,WAAW,CAAC;AAC/D,EAAAA,WAAU,MAAM;AACd,QAAI,IAAI,cAAc,WAAW,YAAa,cAAa;AAAA,EAC7D,GAAG,CAAC,IAAI,cAAc,QAAQ,KAAK,CAAC;AAGpC,QAAM,qBAAqB,IAAI,IAAI,eAAe,OAAO,gBAAc,WAAW,WAAW,SAAS,EAAE,IAAI,gBAAc,WAAW,UAAU,CAAC;AAChJ,QAAMC,eAAc,MAAM,YAAY,IAAI,YAAY,WAAW,UAAU,CAAC,IAAI,MAAM,WAClF,KAAK,OAAO,SAAO,CAAC,mBAAmB,IAAI,IAAI,UAAU,CAAC,EAAE,IAAI,UAAQ,EAAE,GAAG,KAAK,aAAa,CAAC,GAAG,sBAAsB,KAAK,EAAE,IAChI;AACJ,QAAM,gBAAgB,IAAI,UAAU,WAAW,UAC3C,IAAI,UAAU,MAAM,KAAK,cAAY,SAAS,eAAe,IAAI,cAAc,UAAU,IAAI;AACjG,QAAM,qBAAqB,IAAI;AAC/B,QAAM,cAAc,IAAI,OAAO,WAAW,UAAU,IAAI,OAAO,UAC3D,IAAI,OAAO,WAAW,WAAW,IAAI,OAAO,MAAM,YAChD,mBAAmB,IAAI,OAAO,MAAM,MAAM,MAAM,sDAAsD;AAC5G,QAAM,wBAAwBC,SAAQ,MAAM,IAAI,aAAa;AAAA,IAC3D,CAAC,IAAI,WAAW,EAAE,GAAG;AAAA,MACnB,GAAG,IAAI;AAAA,MACP,SAAS,IAAI,OAAO,WAAW;AAAA,MAC/B,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,EACF,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,IAAI,SAAS,IAAI,OAAO,QAAQ,SAAS,WAAW,CAAC;AAE9E,QAAM,cAAc,MAAM;AACxB,QAAI,IAAI,cAAc,WAAW,UAAW,KAAI,cAAc;AAAA,QACzD,KAAI,UAAU,IAAI;AACvB,cAAU,EAAE;AAAG,gBAAY,MAAS;AAAG,kBAAc,CAAC,CAAC;AAAA,EACzD;AAEA,QAAM,UAAU,gBAAAN;AAAA,IAAC;AAAA;AAAA,MACf,OAAO,MAAM,SAAS;AAAA,MAAgB,QAAQ,MAAM;AAAA,MAAQ,MAAMK;AAAA,MAClE;AAAA,MAAc,eAAe;AAAA,MAAU,gBAAgB;AAAA,MAAU,wBAAwB;AAAA,MACzF;AAAA,MAAY,cAAc;AAAA,MAC1B,oBAAoB,CAAC,YAAY,iBAAiB,oBAAoB,cAAY;AAAA,QAChF;AAAA,QAAO,KAAK,EAAE,GAAI,QAAQ,UAAU,QAAQ,QAAQ,MAAM,CAAC,GAAI,CAAC,UAAU,GAAG,aAAa;AAAA,MAC5F,EAAE;AAAA,MACF,WAAW,SAAO;AAAE,cAAM,WAAW,IAAI,UAAU,WAAW,UAAU,IAAI,UAAU,MAAM,KAAK,UAAQ,KAAK,eAAe,IAAI,UAAU,IAAI;AAAM,YAAI,SAAU,KAAI,aAAa,QAAQ;AAAA,MAAE;AAAA,MAC9L,UAAU,CAAC,YAAY,QAAQ,IAAI,iBAAiB,IAAI,YAAY,WAAW,EAAE;AAAA,MACjF,cAAc,gBAAc;AAAE,aAAK,IAAI,OAAO,WAAW,EAAE;AAAA,MAAE;AAAA,MAC7D,sBAAsB,MAAM;AAAA,MAAsB,SAAS,MAAM,IAAI,QAAQ;AAAA,MAC7E,SAAS,IAAI,UAAU,WAAW,aAAa,IAAI,YAAY,WAAW;AAAA,MAAW;AAAA,MACrF,aAAa;AAAA,MACb,gBAAgB,IAAI,cAAc,WAAW,YAAY,IAAI,cAAc,cAAc,OAAO;AAAA,MAChG,0BAAwB;AAAA,MACxB,mBAAmB,MAAM,YAAY,KAAK,SAAS,IAAI,+FAA+F;AAAA;AAAA,EACxJ;AAEA,SAAO,gBAAAJ,MAAC,aAAQ,WAAW,MAAM,WAC9B;AAAA,QAAI,cAAc,WAAW,YAAY,gBAAAA,MAAC,SAAI,MAAK,UAAS,WAAU,0CACrE;AAAA,sBAAAD,KAAC,UAAK,6CAA+B;AAAA,MACrC,gBAAAA,KAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,IAAI,eAAe,+BAAiB;AAAA,OACvF,IAAS;AAAA,IACR,IAAI,WAAW,WAAW,YAAY,gBAAAA,KAAC,OAAE,MAAK,UAAS,uCAAoB,IAAO;AAAA,IAClF,gBAAgB,gBAAAA,KAAC,OAAE,MAAK,SAAS,yBAAc,IAAO;AAAA,IACtD,eAAe,gBAAAA,KAAC,OAAE,MAAM,eAAe,UAAU,UAAW,wBAAa,IAAO;AAAA,IAChF,IAAI,cAAc,WAAW,WAAW,gBAAAC,MAAC,SAAI,MAAK,SAAQ,WAAU,mEACnE;AAAA,sBAAAD,KAAC,OAAE,eAAY,6BAA6B,cAAI,cAAc,SAAQ;AAAA,MACrE,gBAAgB,gBAAAA,KAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,UAAU,SAAS,SAAS,MAAM,IAAI,aAAa,aAAa,GAAG,8BAAgB,IAAY;AAAA,OAC1J,IAAS,IAAI,cAAc,WAAW,IAAI,WAAW,gBAAAA,KAAC,OAAE,MAAK,UAAU,cAAI,cAAc,SAAQ,IAAO;AAAA,IACvG,IAAI,WAAW,gBAAAC,MAAA,YACZ;AAAA,YAAM,YAAY,sBAAuB,aAAa,aAAa,gBAAAA,MAAC,SAAI,WAAU,kDACjF;AAAA,cAAM,YAAY,qBAAqB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAI,WAAU;AAAA,YAAmD,eAAY;AAAA,YACpH,cAAY,cAAc,YAAY,oBAAoB,IAAI,SAAS,KAAK,CAAC;AAAA,YAAI,MAAK;AAAA,YACtF;AAAA,8BAAAD,KAAC,UAAK,WAAU,mDAAmD,sBAAY,oBAAoB,IAAI,SAAS,KAAK,GAAE;AAAA,cACvH,gBAAAA,KAAC,iBAAc,YAAY,oBAAoB,UAAU,MAAM,UAAU;AAAA,cACzE,gBAAAA,KAAC,wBAAqB,YAAY,oBAAoB,UAAU,MAAM,UAAU,MAAM,SAAS;AAAA;AAAA;AAAA,QACjG,IAAS;AAAA,QACR,aAAa,aAAa,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAO,MAAK;AAAA,YAAS,SAAQ;AAAA,YAAU,WAAU;AAAA,YAAU,UAAU;AAAA,YAC/F,SAAS,MAAM,IAAI,aAAa,IAAI,QAAS;AAAA,YAAG;AAAA;AAAA,QAAuB,IAAY;AAAA,SACvF,IAAS;AAAA,MACT,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACD,UAAU,gBAAgB,IAAI,QAAQ;AAAA,UACtC,aAAa,aAAa,eAAe,CAAC;AAAA,UAC1C,sBAAsB,IAAI,YAAY,MAAM;AAAA,UAC5C,oBAAoB,kBAAgB,IAAI,iBAAiB,IAAI,SAAU,YAAY,YAAY;AAAA,UAC/F;AAAA,UACA,SAAS,IAAI,YAAY,WAAW,aAAa,IAAI,OAAO,WAAW;AAAA,UACvE,OAAO;AAAA,UACP,UAAU,YAAY;AAAA,UACtB,SAAS,MAAM,IAAI,QAAQ;AAAA,UAC3B,kBAAkB,kBAAgB;AAAE,iBAAK,IAAI,KAAK,YAAY;AAAA,UAAE;AAAA,UAChE,cAAc,kBAAgB;AAAE,iBAAK,IAAI,OAAO,YAAY;AAAA,UAAE;AAAA,UAC9D,kBAAkB,CAAC,cAAc,YAAY,aAAa;AACxD,gBAAI,aAAa,WAAW,aAAa,SAAS,aAAa,OAAQ;AACvE,iBAAK,IAAI,YAAY,cAAc,YAAY,QAAQ;AAAA,UACzD;AAAA,UACA,iBAAiB,CAAC,cAAc,eAAe;AAAE,iBAAK,IAAI,cAAc,cAAc,UAAU;AAAA,UAAE;AAAA;AAAA,MAClG;AAAA,OACF,IAAM,gBAAAA,KAAA,YACH,gBAAM,WAAW,gBAAAC,MAAC,QAAK,OAAO,YAAY,eAAe,WAAS,QAAQ,EAAE,OAAO,OAAO,UAAU,YAAY,YAAY,WAAW,CAAC,GACvI;AAAA,sBAAAA,MAAC,YAAS,cAAW,qBAAoB,WAAU,gEACjD;AAAA,wBAAAA,MAAC,eAAY,OAAM,YAAW;AAAA;AAAA,UAAS;AAAA,UAAK,IAAI,YAAY,WAAW,UAAU,gBAAAD,KAAC,UAAK,WAAU,2CAA2C,wBAAa,IAAU;AAAA,WAAK;AAAA,QACxK,gBAAAC,MAAC,eAAY,OAAM,WAAU;AAAA;AAAA,UAAgB;AAAA,UAAK,IAAI,UAAU,WAAW,WAAW,IAAI,YAAY,WAAW,UAAU,gBAAAD,KAAC,UAAK,WAAU,2CAA2C,UAAAK,aAAY,QAAO,IAAU;AAAA,WAAK;AAAA,SAC1N;AAAA,MACA,gBAAAJ,MAAC,eAAY,OAAM,YAClB;AAAA,YAAI,cAAc,WAAW,eAAe,IAAI,cAAc,UAAU,gBAAAD,KAAC,OAAE,MAAK,UAAS,WAAU,gBAAgB,cAAI,cAAc,SAAQ,IAAO;AAAA,QACrJ,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAA2B,UAAU,MAAM;AAAA,YAAU,aAAa;AAAA,YAAgB,WAAW,IAAI,UAAU,WAAW,UAAU,IAAI,UAAU,QAAQ,CAAC;AAAA,YACtJ,SAAS,IAAI,YAAY,WAAW;AAAA,YAAW,OAAO,IAAI,YAAY,WAAW,UAAU,IAAI,YAAY,UAAU;AAAA,YAAM,MAAM;AAAA,YACjI,SAAS,MAAM,IAAI,QAAQ;AAAA,YAAG,UAAU,gBAAc,IAAI,iBAAiB,WAAW,YAAY,WAAW,EAAE;AAAA,YAC/G,WAAW,gBAAc,MAAM,IAAI,EAAE,WAAW,iBAAiB,cAAc,WAAW,GAAG,CAAC;AAAA,YAC9F,OAAO,MAAM,QAAQ,EAAE,OAAO,OAAO,UAAU,CAAC;AAAA;AAAA,UAJ7B;AAAA,QAIgC;AAAA,SACrD;AAAA,MACA,gBAAAA,KAAC,eAAY,OAAM,WAAW,mBAAQ;AAAA,OACxC,IAAU,SACZ;AAAA,IACC,IAAI,QAAQ,SAAS,YAAY,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACjC,MAAI;AAAA,QACJ,cAAc,UAAQ;AAAE,cAAI,CAAC,KAAM,aAAY;AAAA,QAAE;AAAA,QACjD,YAAY,IAAI,OAAO,SAAS;AAAA,QAChC,OAAO,IAAI,OAAO,SAAS;AAAA,QAC3B,aAAa,IAAI,OAAO,SAAS;AAAA,QACjC,OAAO;AAAA,QACP,eAAe;AAAA,QACf,MAAM;AAAA,QACN,OAAO;AAAA,QACP,WAAW,OAAO,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,QACxC,UAAU,MAAM;AACd,gBAAM,SAAS;AACf,gBAAM,SAAS,IAAI,QAAQ,SAAS;AACpC,gBAAM,kBAAkB,IAAI;AAC5B,oBAAU,EAAE;AACZ,cAAI,OAAQ,MAAK,IAAI,aAAa,QAAQ,QAAQ,QAAQ,EAAE,KAAK,YAAU;AACzE,gBAAI,OAAO,aAAa,YAAY,YAAY,SAAS,aAAa,YAAY,iBAAiB;AACjG,kBAAI,UAAU,IAAI;AAAG,0BAAY,MAAS;AAAG,2BAAa;AAAA,YAC5D;AAAA,UACF,CAAC;AAAA,QACH;AAAA,QACA,gBAAM,uBAAuB,EAAE,UAAU,IAAI,OAAO,UAAU,OAAO,UAAU,UAAU,YAAY,CAAC;AAAA;AAAA,IAAE,IAAyB;AAAA,IAClI,IAAI,QAAQ,SAAS,UAAU,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAC/B,MAAI;AAAA,QACJ,cAAc,UAAQ;AAAE,cAAI,CAAC,KAAM,aAAY;AAAA,QAAE;AAAA,QACjD,YAAY,IAAI,OAAO,SAAS;AAAA,QAChC,OAAO,IAAI,OAAO,SAAS;AAAA,QAC3B,YAAY,IAAI,OAAO,SAAS,wBAAwB,CAAC;AAAA,QACzD,QAAQ;AAAA,QACR,eAAe,CAAC,KAAK,UAAU,cAAc,EAAE,GAAG,YAAY,CAAC,GAAG,GAAG,MAAM,CAAC;AAAA,QAC5E,MAAM;AAAA,QACN,OAAO,IAAI,cAAc,WAAW,WAAW,IAAI,cAAc,UAAU;AAAA,QAC3E,WAAW,CAAC,YAAY,IAAI,OAAO,SAAS,wBAAwB,CAAC,GAAG,MAAM,WAAS,CAAC,MAAM,YAAY,CAAC,CAAC,WAAW,MAAM,GAAG,GAAG,KAAK,CAAC;AAAA,QACzI,UAAU,MAAM;AACd,gBAAM,SAAS,IAAI,QAAQ;AAC3B,gBAAM,kBAAkB,IAAI;AAC5B,cAAI,OAAQ,MAAK,IAAI,WAAW,QAAQ,UAAU,EAAE,KAAK,YAAU;AACjE,gBAAI,WAAW,eAAe,YAAY,YAAY,SAAS,aAAa,YAAY,gBAAiB,eAAc,CAAC,CAAC;AAAA,UAC3H,CAAC;AAAA,QACH;AAAA;AAAA,IACF,IAAK;AAAA,KACP;AACF;","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
- /** Stored overrides are shown; app-specific effective policy is never guessed. */
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.60.173",
3
+ "version": "0.60.174",
4
4
  "packageManager": "pnpm@11.24.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [