122 lines · 6.0 KB · TypeScript
RawDownload
import type {  AuthTemplateSlug,  ConnectionAddress,  ConnectionName,  IntegrationSlug,  OAuthClientSlug,  Owner,  ProviderItemId,  ProviderKey,} from "./ids";import type { HealthCheckResult, HealthCheckSpec } from "./health-check"; /* A Connection is THE saved credential — secret, account, and connection are one * concept — bound to exactly ONE integration (born wired; there is no unwired * state and no separate "connect" step). Named, owner-scoped. Its value lives in * a provider (the default store for pasted values, or an external one like * 1Password) and is applied to the integration's template lazily, per call — * never pre-baked. Reusing a credential across a provider's APIs is a property of * the integration grain (bundle the provider), not of the connection. */ export interface Connection {  readonly owner: Owner;  readonly name: ConnectionName;  /** The one integration this credential is for. */  readonly integration: IntegrationSlug;  /** Which of the integration's auth methods this credential is applied through. */  readonly template: AuthTemplateSlug;  /** Which backend resolves the value — the default store, or e.g. "1password".   *  Never the value itself. */  readonly provider: ProviderKey;  /** Callable handle `tools.<integration>.<owner>.<connection>`. Append `.<tool>`   *  to reach one of its tools. */  readonly address: ConnectionAddress;  /** Optional human label (which account). Not load-bearing. */  readonly identityLabel?: string | null;  /** User-curated description of what this connection is for. Agent-visible:   *  surfaces next to the connection's prefix in the execute-tool inventory   *  and in `connections.list`, so it is the place to give agents context a   *  spec can't (e.g. "the staging CRM — reads only"). */  readonly description?: string | null;  /** Epoch ms when an OAuth access token expires; null/absent for static creds. */  readonly expiresAt?: number | null;  /** The OAuth app (`oauth_client` slug) that minted this connection, when it   *  came from an OAuth flow; null for static credentials. Lets the UI map a   *  connection back to the app backing it. Never a secret — just the slug. */  readonly oauthClient?: OAuthClientSlug | null;  /** The OWNER of `oauthClient` — a Personal connection may be minted through a   *  shared Workspace app, so the app's owner differs from this connection's.   *  Stored at mint so refresh/reconnect load the client by an explicit   *  `(slug, owner)` instead of re-deriving the owner. Null for static creds. */  readonly oauthClientOwner?: Owner | null;  /** The scope set the provider actually GRANTED (space-delimited), recorded at   *  connect/refresh. Load-bearing: compared against the integration's currently   *  declared scopes to decide whether this connection must reconnect to grant   *  newly-needed access. Null for static creds / when the AS omitted `scope`. */  readonly oauthScope?: string | null;  /** Last health-check verdict, persisted by every `checkHealth` run. Answers   *  "has this expired?" at a glance in the connections list without probing.   *  Null/absent = never checked. */  readonly lastHealth?: HealthCheckResult | null;} /** Identify one connection — unique by (owner, integration, name). */export interface ConnectionRef {  readonly owner: Owner;  readonly name: ConnectionName;  readonly integration: IntegrationSlug;} /** Where a single credential input comes from. `value` is pasted raw and written *  to the default provider; `from` references an external provider (1Password, *  keychain) by opaque id — we store the routing and resolve on demand, never *  holding the value. Applied to a template lazily, never pre-baked into *  `Bearer …`. */export type ConnectionInputOrigin =  | { readonly value: string }  | { readonly from: { readonly provider: ProviderKey; readonly id: ProviderItemId } }; /** The value origin(s) for a new credential. A connection resolves a MAP of named *  inputs (`variable → value`); a single-secret connection uses the one `token` *  variable, an apiKey method with two distinct inputs (e.g. Datadog) carries one *  per variable. `value` / `from` are sugar for the single `token` input; `values` *  is pasted multi-input; `inputs` is the canonical per-variable origin map (mixes *  pasted + external). All inputs of one connection share one provider. */export type ConnectionValueInput =  | { readonly value: string }  | { readonly from: { readonly provider: ProviderKey; readonly id: ProviderItemId } }  | { readonly values: Record<string, string> }  | { readonly inputs: Record<string, ConnectionInputOrigin> }; /** Save a credential for one integration (born wired). `template` picks which of *  the integration's auth methods to apply it through. For OAuth, use *  `oauth.start` instead. */export type CreateConnectionInput = {  readonly owner: Owner;  readonly name: ConnectionName;  readonly integration: IntegrationSlug;  readonly template: AuthTemplateSlug;  readonly identityLabel?: string | null;  readonly description?: string | null;} & ConnectionValueInput; /** Validate an in-flight credential WITHOUT saving it (the key-first connect *  flow). Resolves the pasted value(s) the same way `create` would, then runs *  the integration's declared health check so the UI can confirm the key works *  and derive a connection name from the returned identity before anything is *  persisted. `spec` overrides the integration's declared check (used by the *  editor to preview a candidate against a live key). */export type ValidateConnectionInput = {  readonly owner: Owner;  readonly integration: IntegrationSlug;  readonly template: AuthTemplateSlug;  readonly spec?: HealthCheckSpec;} & ConnectionValueInput; /** Edit a connection's user-curated metadata. Only the provided fields change; *  credentials and OAuth lifecycle are untouchable here (recreate or refresh *  instead). */export interface UpdateConnectionInput {  readonly description?: string | null;  readonly identityLabel?: string | null;}