Skip to content

feat(activity): add GitHub Discussions to RecentActivity#1939

Merged
Priyanshu-byte-coder merged 2 commits into
Priyanshu-byte-coder:mainfrom
Ridanshi:fix/local-coding-api-key-auth
Jun 3, 2026
Merged

feat(activity): add GitHub Discussions to RecentActivity#1939
Priyanshu-byte-coder merged 2 commits into
Priyanshu-byte-coder:mainfrom
Ridanshi:fix/local-coding-api-key-auth

Conversation

@Ridanshi
Copy link
Copy Markdown
Contributor

@Ridanshi Ridanshi commented Jun 3, 2026

Closes #1913

Implementation summary

The GitHub REST /user/events endpoint does not reliably surface DiscussionEvent and DiscussionCommentEvent entries — they are absent from the events feed for many users even when they have active discussion participation. This PR adds a parallel GraphQL query to fill that gap without replacing the existing REST event flow.

GraphQL integration details

A new DISCUSSION_COMMENTS_QUERY targets viewer.repositoryDiscussionComments(first: 20), the most reliable GitHub GraphQL field for this purpose. The query returns the 20 most recent discussion comments the authenticated user has made across all repositories, each with createdAt, comment url, and the parent discussion's title, number, url, and repository.nameWithOwner.

fetchDiscussionItemsViaGraphQL(token) wraps the call and always resolves — any error (rate limit, missing scope, disabled discussions) silently returns [] so discussion activity is never a hard dependency of the feed.

The GraphQL fetch runs in parallel with the REST events fetch via Promise.all in both fetchFormattedActivity() and the fetchPublicEvents fallback path.

Activity normalization changes

src/lib/activity-formatter.ts additions:

  • GraphQLDiscussionCommentNode — typed shape for a single GraphQL response node
  • formatGraphQLDiscussionComment(node) — normalizes a GraphQL node into the shared ActivityItem format; sets type: "discussion", builds the title as Commented on discussion #N, and links to the discussion URL (not the comment anchor)
  • mergeActivityItems(restItems, discussionItems) — deduplicates by type-repo-createdAt-title key and returns a newest-first sorted array

src/app/api/metrics/activity/route.ts changes:

  • Imports githubGraphQL from @/lib/github-fetch
  • Adds DISCUSSION_COMMENTS_QUERY, DiscussionCommentsQueryResult, fetchDiscussionItemsViaGraphQL
  • Both fetchFormattedActivity and the fallback path use mergeActivityItems to combine REST and GraphQL results

UI updates

None required. RecentActivity.tsx already renders the "discussion" type with a chat-bubble SVG icon and a "Discussion" badge — the existing code handles discussion items from both REST and GraphQL sources identically.

Tests added

test/activity-formatter.test.ts — 15 new tests (33 total):

formatGraphQLDiscussionComment:

  • type is "discussion"
  • title includes discussion number
  • subtitle is discussion title
  • repo is repository.nameWithOwner
  • URL links to discussion (not comment anchor)
  • createdAt is preserved
  • id includes "gql-disc" and the comment URL
  • handles different discussion numbers

mergeActivityItems:

  • REST items sorted newest-first with empty discussion array
  • Interleaves discussion and REST items chronologically
  • Deduplicates items sharing the same type/repo/createdAt/title key
  • Keeps distinct items differing only by title
  • Returns only REST items when discussion array is empty
  • Returns only discussion items when REST array is empty
  • Returns empty array when both inputs are empty

Verification

npm run lint        # warnings only, no errors
npm run type-check  # no errors in changed files
npm run test test/activity-formatter.test.ts  # 33/33 passed

Ridanshi added 2 commits May 31, 2026 18:53
…iyanshu-byte-coder#1748)

Root cause (confirmed)
----------------------
The initial migration created local_coding_api_keys with a single column
api_key to store SHA-256 hashes. A later migration added api_key_hash as
a nullable column. At the time issue Priyanshu-byte-coder#1748 was filed, the code was split:

  Creation  → insert({ api_key: hash })         # only api_key written
  Auth      → .eq("api_key_hash", hash)          # only api_key_hash read

Every key generated through the UI was therefore permanently invalid;
authentication always returned "Invalid API key".

Applied fix (in place on main branch)
--------------------------------------
Key creation now writes the same SHA-256 hash to BOTH columns:

  insert({ api_key: hash, api_key_hash: hash })

Authentication queries BOTH columns with an OR filter so that pre-existing
rows (with only api_key populated) and newly created rows (with both
populated) authenticate identically:

  .or("api_key_hash.eq.<hash>,api_key.eq.<hash>")

This preserves backward compatibility with any deployment that had keys
created before the api_key_hash column existed.

Regression test suite — test/local-coding-auth-regression.test.ts (9 tests)
-----------------------------------------------------------------------------
Tests added in this commit provide explicit coverage that was absent:

  * Key creation writes hash to api_key AND api_key_hash.
  * POST /local-coding/sync uses OR filter across both columns.
  * Legacy row (api_key only, api_key_hash NULL) still authenticates.
  * Invalid key is rejected by both POST and GET sync handlers.
  * GET /local-coding/sync was previously untested; 4 tests now cover:
      - missing Authorization header → 401
      - invalid key → 401
      - valid key → 200 with session data
      - same OR filter used as POST
  * Hash function consistency: verifies the hash written during creation
    would satisfy the filter used during authentication.

The pre-existing tests in test/local-coding-keys.test.ts and
test/local-coding-sync.test.ts continue to pass unchanged.

Closes Priyanshu-byte-coder#1748
Add parallel GraphQL fetch alongside the REST events endpoint to
reliably surface discussion-comment activity in RecentActivity.

- activity-formatter.ts: GraphQLDiscussionCommentNode interface,
  formatGraphQLDiscussionComment() normalizer, mergeActivityItems()
  dedup+sort helper
- metrics/activity/route.ts: DISCUSSION_COMMENTS_QUERY via
  viewer.repositoryDiscussionComments(first:20); fetchDiscussionItems
  ViaGraphQL() silently returns [] on error; both fetchFormatted
  Activity() and the public-events fallback path run REST + GraphQL
  in parallel via Promise.all
- test/activity-formatter.test.ts: 15 new tests for
  formatGraphQLDiscussionComment and mergeActivityItems
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

@Ridanshi is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added gssoc26 GSSoC 2026 contribution type:feature GSSoC type bonus: new feature type:testing GSSoC type bonus: tests (+10 pts) labels Jun 3, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

@Priyanshu-byte-coder Priyanshu-byte-coder added the quality:clean GSSoC: Clean quality multiplier (×1.2) label Jun 3, 2026
@Priyanshu-byte-coder Priyanshu-byte-coder merged commit e493687 into Priyanshu-byte-coder:main Jun 3, 2026
10 of 11 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

🎉 Merged! Thanks for contributing to DevTrack.

If the project has been useful to you, a ⭐ star on the repo is the easiest way to support it — it helps DevTrack get discovered by more developers.

Keep an eye on open issues for your next contribution!

@Priyanshu-byte-coder Priyanshu-byte-coder added gssoc:approved GSSoC: PR approved for scoring level:intermediate GSSoC: Intermediate difficulty (35 pts) labels Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution level:intermediate GSSoC: Intermediate difficulty (35 pts) quality:clean GSSoC: Clean quality multiplier (×1.2) type:feature GSSoC type bonus: new feature type:testing GSSoC type bonus: tests (+10 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Add GitHub Discussions activity to RecentActivity widget

2 participants