577cd68cb5
Closes the loop on https://github.com/twentyhq/twenty/pull/22984#discussion_r3673946334, where the Slack app claimed a `team_id` on connect and never released it. The `onDisconnect` hook it waited on merged in #23538, and `twenty-sdk` 2.27.0 ships the `onDisconnectLogicFunction` manifest field, so this bumps the app to it. ## Disconnect `slack-team-release` releases the server-scoped `slack-team:{teamId}` claim, so another Twenty workspace can connect that Slack team afterwards. `kv.delete` on a SERVER key only clears a claim the calling workspace owns, and the result reports a team only when that delete actually removed something. The connection is already deleted when the hook runs, so `getConnection` cannot resolve the `team_id` anymore. `claimSlackTeam` records `teamId` under a workspace-scoped `slack-connected-account-team:{connectedAccountId}` key, written before the claim itself so a failure between the two cannot leave a claim nothing can resolve, and the release reads it back from there. That also retires the TODO the review comment pointed at. The release is skipped when a live connection still maps to the same team, excluding the disconnecting account explicitly. That covers a reconnect that re-claimed the team while the job was queued, and a second connection to the same Slack workspace, whose claim would otherwise have been dropped along with the first. The recorded team is cleared either way, so the disconnecting account leaves nothing behind. ## Uninstall Uninstalling the app drops its connections through the `connectionProvider` and `application` cascades, which never reach the disconnect hook, and the same operation deletes the app's logic functions so the hook could not run anyway. The app declares an `uninstallLogicFunction`: it runs before the app's metadata is deleted, lists the remaining Slack connections, and releases each claim through the same `releaseSlackTeamClaim` util. It deliberately skips the live-connection check, since at that point every connection is still listed. ## Known limits A disconnect immediately followed by a reconnect has a window where the queued release can clear a claim the reconnect just took. It self-heals, because the reconnect's own onConnect re-claims the same key moments later. Closing it properly needs a compare-and-set on the claim, which the key-value store does not expose. No unit tests are added for the release path. Earlier revisions of this branch had specs for the disconnect guard, the uninstall sweep and the no-op-release result; they were dropped, so those branches carry no regression coverage. The app's existing 34 tests still pass, along with lint, typecheck and `twenty dev:build`, the last being what used to fail with `Duplicate universal identifiers` on the older SDK.