This package uses Convex as the notifier backend.
Defined in convex/schema.ts.
Primary tables:
packagessubscribersdiscordSubscriberDetailsslackSubscriberDetailssubscriptionspendingReleaseChecks
Stores one record per tracked package name.
Important fields:
namecurrentVersionecosystemlastCheckedgithubRepoUrloptional
githubRepoUrl is stored so /npmlist can render GitHub release links without doing live network fetches.
Stores top-level subscriber identities.
This now includes:
- Slack workspaces
- Discord guilds
subscribers.type determines which detail table and delivery path apply.
Stores Discord-specific connection details:
- guild ID
- guild name
Stores Slack-specific connection details:
- bot token
- webhook URL
- default webhook channel name
- default webhook channel ID
Stores channel-aware package subscriptions.
Important fields:
packageIdsubscriberIdlastNotifiedVersionminUpdateTypechannelIdoptionalchannelNameoptional
If channelId is missing, the subscription targets the workspace default channel.
Stores delayed enrichment work for a specific Slack notification message.
Important fields:
subscriberIdchannelIdmessageTsfullTextcommentTsoptionalretryCountpackages
These rows are currently Slack-only. Each package entry tracks two independent concerns:
- whether the original Slack line still needs GitHub link backfill
- whether an AI summary for that package is still pending
Defined in:
Pattern:
- Slack hits an HTTP endpoint.
- The HTTP handler returns immediately with an ephemeral response.
- The real work is scheduled via Convex.
- A follow-up message is posted back to Slack.
This keeps slash commands responsive while still allowing async work.
Defined in:
Pattern:
- Discord hits
/discord/interactions. - The HTTP handler verifies the Ed25519 signature.
- It immediately returns a deferred ephemeral interaction response.
- The real work is scheduled via Convex.
- The deferred reply is edited with the final result.
Discord install and command registration also use:
GET /discord/installPOST /discord/register-commands
Defined in:
The poller:
- loads tracked packages
- fetches npm metadata
- determines whether an update is available
- stores the newest version
- stores GitHub repo metadata when available
- groups matching subscriptions by subscriber-specific target
- sends one notification per target channel
- for Slack, adds a pending reaction and queues an enrichment job for the posted message
- for Discord, sends the base notification only
The notifier uses a two-stage enrichment flow.
Stage 1 happens during polling for both Slack and Discord:
- polling fetches npm metadata anyway
- if a GitHub repo URL can be derived from
repository, it is normalized and stored onpackages.githubRepoUrl - the outgoing Slack message includes the best release links available at send time
Stage 2 happens in convex/releaseChecks.ts for Slack only:
- the notifier retries on a backoff schedule:
1h,3h,6h,12h,24h - each retry re-fetches npm metadata and structured GitHub evidence
- if the message line can now be improved, the original Slack message is edited in place
- if the evidence is strong enough, the notifier calls OpenAI to produce a short thread summary
- the original message reaction reflects overall state: pending, ready, or abandoned
This design handles the common npm-first / GitHub-later case without requiring open-ended web search.
Helper logic lives in:
Rules:
- package name links to npm
- update notification version links prefer GitHub releases when the manifest indicates GitHub
/npmlistversion links use storedgithubRepoUrl- if no GitHub metadata is available,
/npmlistshows plain version text
AI summarization is intentionally constrained:
- structured evidence is gathered from npm metadata plus GitHub release/compare APIs
- OpenAI is only used to compress that evidence into short Slack text
- the model is not expected to discover facts on the open web
- if the evidence is weak, the summary is skipped rather than guessed
Notifier tests live in:
Current coverage focuses on:
- multi-channel tracking semantics
/npmuntrackall-channel behavior/npmlistformatting and link behavior- GitHub metadata persistence during polling
- delayed enrichment, Slack reactions, and AI summary posting
Test stack:
vitestconvex-test- edge-runtime environment
Recommended places to update docs:
- user-facing Discord behavior:
docs/discord.md - user-facing Slack behavior:
docs/slack.md - internal implementation notes:
docs/architecture.md - deployment/configuration:
docs/deployment.md - troubleshooting:
docs/runbook.md - short package overview:
README.md