src/types/index.ts and imported across the pipeline services, filters, notifier, and bot commands.
Deal
Raw deal object returned by the CheapShark API. All numeric values arrive as strings and are parsed downstream.Display name of the game as returned by CheapShark.
Metacritic review score as a numeric string. Empty string if no score exists.
Steam user review category label, e.g.
"Very Positive", "Overwhelmingly Positive", "Mixed".Percentage of positive Steam user reviews as a numeric string.
Current discounted price in USD.
Original price in USD before the sale.
Discount percentage as a decimal string (e.g.
"66.661110"). Rounded to an integer and stored in FilteredDeal.savingsPercent.Steam application ID. Used as the canonical identifier throughout the entire pipeline.
CheapShark deal hash. Used to construct the redirect URL:
https://www.cheapshark.com/redirect?dealID={dealID}.URL of the Steam capsule thumbnail image.
FilteredDeal
A deal that has passed both filter layers and is ready to be stored, cached, and sent to users. All numeric fields have been parsed from strings. Prices and scores come from the original CheapShark data — not from GPT.Display name of the game.
Steam application ID.
Current sale price in USD.
Original price in USD.
Discount percentage as a rounded integer (e.g.
66). Parsed from Deal.savings.Metacritic score as an integer.
0 if not available.Steam review category label.
CheapShark redirect URL constructed from
dealID. Sends the user to the active Steam deal page.Brief curation reason provided by GPT, in Spanish. This is the only field sourced from the AI model. Truncated to
config.ai.maxReasonLength (120 characters) even if GPT exceeds the 12-word prompt limit.NotifiedGame
Minimal deduplication record written todata/notified_games.json after each successful broadcast. Only the fields strictly necessary for deduplication are stored.
Steam application ID of the notified game.
ISO 8601 date-time string recording when the game was last notified. Used to enforce the deduplication window (
DEDUP_DAYS, default 7 days).title is intentionally not stored in NotifiedGame. The title is not needed for
deduplication — only the steamAppID and timestamp are required to determine whether a game
has been recently notified.AISelection
Structured output from GPT representing the curation decision. GPT selects which candidate IDs pass and provides a brief reason for each.Array of
steamAppID strings chosen by GPT. Only IDs present in the input candidate set are accepted.Map of
steamAppID to a brief curation reason in Spanish. Keys correspond to entries in selectedIds.AIFilterResult
Union type returned byfilterDealsWithAI. Distinguishes a successful selection from a parse or network failure.
'ok' — GPT responded with valid JSON and the selection was parsed successfully.'error' — GPT returned invalid JSON, the request timed out, or another failure occurred. The pipeline falls back to PipelineResult { status: 'ai_error' }.Present when
status is 'ok'. Contains the selected IDs and reasons.Present when
status is 'error'. Human-readable description of the failure.PipelineResult
Union type returned byfetchDeals (the top-level pipeline orchestrator) and propagated to bot command handlers. Distinguishes three distinct outcomes.
'ok' — pipeline completed successfully and at least one deal is available.'no_deals' — pipeline completed but no deals survived both filter layers.'ai_error' — the AI filter failed. The bot replies with a user-facing error message and does not show deals.Present when
status is 'ok'. The final curated list of deals ready to be formatted and sent.Present when
status is 'ai_error'. Propagated from AIFilterResult.reason.DailySnapshot
Persisted cache record written todata/snapshot.json after each successful pipeline run. The /deals command reads from this snapshot directly rather than re-running the pipeline on every request.
The final curated deal list from the most recent successful pipeline run.
SHA hash of the rule-filtered candidate set. If the same candidates are present on the next run, the pipeline skips the GPT call and reuses the existing snapshot.
ISO 8601 date-time string recording when the snapshot was created. Used to determine whether the snapshot is still valid for the current day.