-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add /github disconnect command and polish codebase #76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add /github disconnect command (cascades to remove subscriptions) - Merge OAuthCleanupService into GitHubOAuthService - Extract common token fields to reduce duplication - Use formatSubscriptionSuccess consistently for webhook upgrades - Add OAUTH_STATE_CLEANUP_INTERVAL_MS constant - Rename startPeriodicCleanup to startOAuthStateCleanup - Update README with disconnect, branch filter, and review_comments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
WalkthroughThe PR consolidates OAuth state cleanup functionality from a separate OAuthCleanupService into GitHubOAuthService, adds a new "disconnect" command to unlink GitHub accounts, and refactors subscription message handling to use precomputed event types and formatted success messages. A new constant defines the cleanup interval, token storage logic is simplified through field consolidation, and OAuthCleanupService is removed in favor of the integrated approach. Documentation updates reflect branch filtering capabilities. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Key areas requiring attention:
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/services/github-oauth-service.ts (1)
568-586: Consider tracking the timer for graceful shutdown.The implementation is correct - fire-and-forget initial cleanup with proper error handling, and returning the
Timeoutfor potential cancellation.For production robustness, consider ensuring the caller (likely
src/index.ts) stores this timer and clears it on process shutdown signals (SIGTERM/SIGINT) to prevent orphaned callbacks during graceful shutdown.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
README.md(3 hunks)src/constants.ts(1 hunks)src/handlers/github-subscription-handler.ts(3 hunks)src/index.ts(2 hunks)src/services/github-oauth-service.ts(5 hunks)src/services/oauth-cleanup-service.ts(0 hunks)src/services/subscription-service.ts(3 hunks)
💤 Files with no reviewable changes (1)
- src/services/oauth-cleanup-service.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.ts: Store context externally - maintain stateless bot architecture with no message history, thread context, or conversation memory
Use<@{userId}>for mentions in messages AND add mentions in sendMessage options - do not use @username format
Implement event handlers for onMessage, onSlashCommand, onReaction, onTip, and onInteractionResponse to respond to Towns Protocol events
Define slash commands in src/commands.ts as a const array with name and description properties, then register handlers using bot.onSlashCommand()
Set ID in interaction requests and match ID in responses to correlate form submissions, button clicks, and transaction/signature responses
Use readContract for reading smart contract state, writeContract for SimpleAccount operations, and execute() for external contract interactions
Fund bot.appAddress (Smart Account) for on-chain operations, not bot.botId (Gas Wallet/EOA)
Use bot.* handler methods directly (outside event handlers) for unprompted messages via webhooks, timers, or tasks - requires channelId, spaceId, or other context stored externally
Always check permissions using handler.hasAdminPermission() before performing admin operations like ban, redact, or pin
User IDs are hex addresses in format 0x..., not usernames - use them consistently throughout event handling and message sending
Slash commands do not trigger onMessage - register slash command handlers using bot.onSlashCommand() instead
Use getSmartAccountFromUserId() to retrieve a user's wallet address from their userId
Include required environment variables: APP_PRIVATE_DATA (bot credentials) and JWT_SECRET (webhook security token)
Files:
src/index.tssrc/handlers/github-subscription-handler.tssrc/constants.tssrc/services/github-oauth-service.tssrc/services/subscription-service.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Provide alt text for image attachments and use appropriate MIME types for chunked attachments (videos, screenshots)
Files:
src/index.tssrc/handlers/github-subscription-handler.tssrc/constants.tssrc/services/github-oauth-service.tssrc/services/subscription-service.ts
🧬 Code graph analysis (3)
src/handlers/github-subscription-handler.ts (2)
src/types/bot.ts (1)
SlashCommandEvent(13-15)src/services/github-oauth-service.ts (1)
GitHubOAuthService(68-587)
src/services/github-oauth-service.ts (3)
src/db/index.ts (1)
db(57-57)src/db/schema.ts (2)
githubUserTokens(20-42)oauthStates(47-65)src/constants.ts (1)
OAUTH_STATE_CLEANUP_INTERVAL_MS(76-76)
src/services/subscription-service.ts (2)
src/formatters/subscription-messages.ts (2)
formatSubscriptionSuccess(28-40)formatDeliveryInfo(7-14)src/db/schema.ts (1)
githubSubscriptions(71-110)
🪛 ESLint
src/services/github-oauth-service.ts
[error] 9-9: Unable to resolve path to module 'drizzle-orm'.
(import-x/no-unresolved)
🔇 Additional comments (17)
src/services/subscription-service.ts (2)
823-844: LGTM! Proper propagation of subscription fields for webhook upgrade messaging.The changes correctly:
- Include
eventTypesandbranchFilterin theRETURNINGclause- Parse the stored
eventTypesstring before formatting- Use
formatSubscriptionSuccessfor consistent message renderingThis ensures webhook upgrade notifications display accurate subscription details.
466-485: LGTM! Improved consistency withformatSubscriptionSuccess.The refactor correctly parses event types before passing to
createSubscriptionand uses the sharedformatSubscriptionSuccessformatter for consistent messaging.One note:
branchFilteris hardcoded tonullon line 482. If pending subscriptions should preserve the original branch filter from when the user initiated the subscription, consider storing and retrieving it from thependingSubscriptionstable.#!/bin/bash # Check if pendingSubscriptions schema includes branchFilter column rg -n "pendingSubscriptions" --type=ts -A 20 src/db/schema.ts | head -40src/constants.ts (2)
71-76: LGTM! New constant for OAuth state cleanup interval.The constant is well-documented and the 1-hour interval aligns with the
PENDING_SUBSCRIPTION_CLEANUP_INTERVAL_MScadence, providing consistent periodic cleanup behavior.
72-76: Fix incorrect JSDoc: comment says "monthly" but interval is hourly.The constant value is
60 * 60 * 1000(1 hour), but the comment incorrectly states "monthly cleanup interval". This should say "hourly" to match the actual behavior./** - * OAuth state cleanup interval (1 hour) - * How often to remove expired OAuth state entries from the database. + * OAuth state cleanup interval (1 hour) + * How often to remove expired OAuth state entries from the database. */ export const OAUTH_STATE_CLEANUP_INTERVAL_MS = 60 * 60 * 1000;Actually, the comment on line 73 says "(1 hour)" which is correct, but the AI summary mentioned "monthly" which appears to be an error in the summary, not the code. Let me re-read...
The comment correctly states "(1 hour)" on line 73. The code is correct.
README.md (3)
36-36: LGTM! Feature list updated with Branch Filtering.
51-65: LGTM! Good documentation for new commands.The examples clearly show:
- Branch filter syntax with patterns
- The new disconnect command
- Unsubscribe with
--eventsflagThis matches the implementation in the handler.
69-73: LGTM! Helpful clarification on branch filtering scope.The note explaining which events are branch-specific vs. non-branch-specific is valuable for users understanding the filtering behavior.
src/index.ts (2)
134-136: LGTM! Help text updated with new commands.The help message now includes:
/github unsubscribewith optional--eventsflag/github disconnectcommandThis aligns with the handler implementation.
228-230: LGTM! OAuth cleanup consolidated into GitHubOAuthService.Good refactor - removing the separate
OAuthCleanupServiceand callingstartOAuthStateCleanup()directly on the OAuth service simplifies the architecture and keeps related functionality together.src/handlers/github-subscription-handler.ts (3)
38-39: LGTM! Usage text updated with disconnect command.
66-68: LGTM! Disconnect command routing added.The switch case correctly routes to the new
handleDisconnectfunction.
571-592: LGTM! Clean implementation of disconnect handler.The implementation correctly:
- Checks if a token exists before attempting disconnect
- Provides informative feedback for both cases
- Displays the GitHub login in the success message for user confirmation
The cascade delete of subscriptions is handled at the database level via the foreign key constraint (
onDelete: "cascade"oncreatedByTownsUserId), which aligns with the PR objective.src/services/github-oauth-service.ts (5)
9-14: LGTM!The imports are correct. The
ltoperator from drizzle-orm is the proper function for less-than comparisons in the cleanup query. The ESLint error about module resolution is a configuration issue (likely missing or misconfiguredtsconfigpaths in ESLint), not a code problem.
165-169: LGTM!Good refactoring to use the encapsulated helper method for OAuth state deletion.
198-226: LGTM - Clean DRY refactoring!The
tokenFieldsextraction correctly consolidates fields that should be set on both insert and upsert, while keepingcreatedAtseparate (insert-only) andtownsUserIdas the primary key target. This reduces duplication and improves maintainability.
392-399: LGTM!Clean encapsulation of OAuth state deletion that promotes consistency across the class.
537-560: LGTM!The cleanup logic correctly uses
lt()to find expired states and efficiently returns the count via.returning(). Error handling appropriately logs and re-throws for caller awareness.
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
--eventsparameter.Documentation
✏️ Tip: You can customize this high-level summary in your review settings.