From 3661f784cbfb41952d1c2e0d6c520268bb5b1d58 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 25 Dec 2025 14:00:35 +0100 Subject: [PATCH] fix: default engine auto with graphql primary --- CHANGELOG.md | 6 ++++++ README.md | 6 +++--- src/index.ts | 19 ++----------------- src/lib/engine.ts | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 src/lib/engine.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1adf6c0..a17ccd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## 0.1.1 — Unreleased +### Changed +- Engine default now `auto` (GraphQL primary; Sweetistics only on fallback when configured). + +### Tests +- Add engine resolution tests for auto/default behavior. + ### Fixed - GraphQL read: rotate TweetDetail query IDs with fallback to avoid 404s. diff --git a/README.md b/README.md index 22f5d30..da515ed 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ bird mentions -n 5 ## Engines -- `--engine graphql` (default) — use Twitter/X GraphQL with cookies (Chrome/Firefox/env/flags). +- `--engine auto` (default) — use GraphQL first; if a Sweetistics API key is available, fall back on errors. +- `--engine graphql` — use Twitter/X GraphQL with cookies (Chrome/Firefox/env/flags). - `--engine sweetistics` — use Sweetistics API key (no browser cookies needed). -- `--engine auto` — Sweetistics if a key is available, otherwise GraphQL. Global options: - `--timeout `: abort requests after the given timeout (milliseconds). @@ -74,7 +74,7 @@ Example `~/.config/bird/config.json5`: ```json5 { - engine: "graphql", + engine: "auto", firefoxProfile: "default-release", sweetisticsApiKey: "sweet-...", allowFirefox: true, diff --git a/src/index.ts b/src/index.ts index 94fe2da..1a436c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ import JSON5 from 'json5'; import kleur from 'kleur'; import { resolveCliInvocation } from './lib/cli-args.js'; import { resolveCredentials } from './lib/cookies.js'; +import { resolveEngineMode, shouldUseSweetistics, type EngineMode } from './lib/engine.js'; import { extractTweetId } from './lib/extract-tweet-id.js'; import { SweetisticsClient } from './lib/sweetistics-client.js'; import { type TweetData, TwitterClient } from './lib/twitter-client.js'; @@ -130,12 +131,10 @@ program .option( '--engine ', 'Engine: graphql | sweetistics | auto', - process.env.BIRD_ENGINE || config.engine || 'graphql', + process.env.BIRD_ENGINE || config.engine || 'auto', ) .option('--timeout ', 'Request timeout in milliseconds'); -type EngineMode = 'graphql' | 'sweetistics' | 'auto'; - type MediaSpec = { path: string; alt?: string; mime: string; buffer: Buffer }; function resolveSweetisticsConfig(options: { sweetisticsApiKey?: string; sweetisticsBaseUrl?: string }) { @@ -147,20 +146,6 @@ function resolveSweetisticsConfig(options: { sweetisticsApiKey?: string; sweetis return { apiKey, baseUrl }; } -function resolveEngineMode(value?: string): EngineMode { - const normalized = (value || 'auto').toLowerCase(); - if (normalized === 'graphql' || normalized === 'sweetistics' || normalized === 'auto') { - return normalized; - } - return 'auto'; -} - -function shouldUseSweetistics(engine: EngineMode, hasApiKey: boolean): boolean { - if (engine === 'sweetistics') return true; - if (engine === 'graphql') return false; - return hasApiKey; // auto -} - function resolveTimeoutMs(...values: Array): number | undefined { for (const value of values) { if (value === undefined || value === null || value === '') continue; diff --git a/src/lib/engine.ts b/src/lib/engine.ts new file mode 100644 index 0000000..6ba0be1 --- /dev/null +++ b/src/lib/engine.ts @@ -0,0 +1,15 @@ +export type EngineMode = 'graphql' | 'sweetistics' | 'auto'; + +export function resolveEngineMode(value?: string): EngineMode { + const normalized = (value || 'auto').toLowerCase(); + if (normalized === 'graphql' || normalized === 'sweetistics' || normalized === 'auto') { + return normalized; + } + return 'auto'; +} + +export function shouldUseSweetistics(engine: EngineMode, hasApiKey: boolean): boolean { + if (engine === 'sweetistics') return true; + if (engine === 'graphql') return false; + return false; // auto: GraphQL primary, Sweetistics only as fallback +}