From 6301bf4bc307ea6e97caeeb31ca0cacf0c4d45de Mon Sep 17 00:00:00 2001 From: Siddharth Balyan Date: Thu, 8 Oct 2026 17:35:26 +0530 Subject: [PATCH] feat(connectors): a connection operation can target one named account Target carries the account alias and shows it in its snapshot. An open operation is reused only for the same connector AND alias, so connecting gmail 'work' never joins an open operation for the default gmail account. --- tools/connectors/account.py | 11 +++++++---- tools/connectors/live.py | 8 ++++++-- tools/connectors/operation.py | 4 ++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tools/connectors/account.py b/tools/connectors/account.py index bbeb064419..91aac30e6e 100644 --- a/tools/connectors/account.py +++ b/tools/connectors/account.py @@ -23,8 +23,9 @@ class AccountOperationStart: failed: bool = False -def _matching_open_operation(names: list[str], *, profile_home: str | None) -> ConnectionOperation | None: - matches = [live.find_target(name, profile_home=profile_home) for name in names] +def _matching_open_operation(names: list[str], *, alias: str | None, + profile_home: str | None) -> ConnectionOperation | None: + matches = [live.find_target(name, alias=alias, profile_home=profile_home) for name in names] first = next((operation for operation in matches if operation is not None), None) if first is None: return None @@ -38,12 +39,14 @@ def find_or_start_operation( *, action: str, profile_home: str | None, + alias: str | None = None, ) -> AccountOperationStart: + """``alias`` names the one account of ``names[0]`` to connect; the caller passes one name with it.""" with _start_lock: - if operation := _matching_open_operation(names, profile_home=profile_home): + if operation := _matching_open_operation(names, alias=alias, profile_home=profile_home): return AccountOperationStart(operation=operation, started=False) operation = ConnectionOperation( - [Target(name, "connector", action) for name in names], + [Target(name, "connector", action, alias=alias) for name in names], session_key=f"account:{uuid.uuid4().hex}", ) started = AccountOperationStart(operation=operation, started=True) diff --git a/tools/connectors/live.py b/tools/connectors/live.py index cd6ff235bb..c90695c631 100644 --- a/tools/connectors/live.py +++ b/tools/connectors/live.py @@ -63,12 +63,16 @@ def get_by_op_id(op_id: str, *, profile_home: Optional[str] = None) -> Optional[ if key == profile_key and operation.op_id == op_id and not operation.settled), None) -def find_target(name: str, *, profile_home: Optional[str] = None) -> Optional[ConnectionOperation]: +def find_target(name: str, *, alias: Optional[str] = None, + profile_home: Optional[str] = None) -> Optional[ConnectionOperation]: + """The open operation connecting this account: the connector ``name`` and the same ``alias``, + so an open operation for one account is never reused for another account of the same app.""" profile_key = _profile_key(profile_home) with _lock: return next((operation for (key, _), operation in _open.items() if key == profile_key and not operation.settled - and (target := operation.target(name)) is not None and target.kind == "connector"), None) + and (target := operation.target(name)) is not None and target.kind == "connector" + and target.alias == alias), None) def close(operation: ConnectionOperation) -> None: diff --git a/tools/connectors/operation.py b/tools/connectors/operation.py index 3cd35b0ca2..c9caf4e757 100644 --- a/tools/connectors/operation.py +++ b/tools/connectors/operation.py @@ -41,6 +41,8 @@ class Target: extra: dict[str, Any] = field(default_factory=dict) # The install step an ``initiated`` catalog row is in (an ``InstallPhase`` id); drawn only then. phase: Optional[str] = None + # The name of the one hosted account this target connects or repairs; absent for the connector's default account. + alias: Optional[str] = None @property def resolved(self) -> bool: @@ -49,6 +51,8 @@ class Target: def snapshot(self, *, with_url: bool = True) -> dict[str, Any]: out: dict[str, Any] = {"name": self.name, "kind": self.kind, "action": self.action, "state": self.state.value, "resolved": self.resolved} + if self.alias: + out["alias"] = self.alias if self.phase and self.state == TargetState.initiated: out["phase"] = self.phase if self.detail: