Skip to content

Handle missing social-media tokens and assets gracefully#115

Merged
TaprootFreak merged 1 commit into
developfrom
fix/socialmedia-resilient-media
May 20, 2026
Merged

Handle missing social-media tokens and assets gracefully#115
TaprootFreak merged 1 commit into
developfrom
fix/socialmedia-resilient-media

Conversation

@TaprootFreak
Copy link
Copy Markdown

Summary

Stops the steady stream of error [TwitterService]: uploadMedia/tweet/sendPost failed and warn [TelegramService]: 400 Bad Request: invalid file HTTP URL specified: URL host is empty on every Saving/Trade/Mint event by making both services tolerant of (a) missing Twitter OAuth tokens and (b) missing media assets.

Background

On PRD, deuro-deuro-api-* logs ~30 Twitter errors per day and the same number of Telegram 400s. The errors first appeared ~2026-04-23 (the start of the Loki retention window) — i.e. since the Azure → local migration.

Two independent issues:

  1. Twitter OAuth never bootstrapped. /app/.api/twitter.token.json exists as {} (3 bytes, created 2026-04-10, never updated). The TwitterService.onModuleInit() reads it, gets access_token=undefined, and every subsequent v1.uploadMedia() / v2.tweet() fails with an auth error.
  2. Media assets missing. TELEGRAM_IMAGES_DIR=/app/.api/images/telegram and TWITTER_IMAGES_DIR=/app/.api/images/twitter point at directories that do not exist in the container. The .png / .mp4 files (Savings.*, EquityInvest.*, Lending.*) live nowhere in the d-EURO org or on the servers. Telegram-side, bot.sendVideo(group, "/missing/path.mp4") makes node-telegram-bot-api fall back to URL-parsing, producing the URL host is empty 400.

Neither root cause is something the code can fix on its own (a real OAuth flow and real assets are needed). What the code should do is fail silently instead of erroring on every event — that's this PR.

Changes

  • TwitterService.readToken() treats a missing file, empty {}, or malformed JSON as "no token". When the token is missing, the service does not register with SocialMediaService, so no tweets are attempted.
  • TwitterService.sendPost() falls back to text-only when the media asset is missing (instead of trying uploadMedia() on a path that does not exist). Error logging is now structured (${e?.message ?? e}) instead of dumping the raw error object.
  • TelegramService.sendMessage() resolves the video path via existsSync and falls back to doSendMessage (text-only) when missing.
  • resolveMediaPath() in socialmedia/socialmedia.helper.ts centralises the existence check used by both services.
  • assets/socialmedia/{telegram,twitter}/ new directory layout, versioned via .gitkeep. The Dockerfile's COPY --chown=node . . already pulls this into the image at /app/assets/socialmedia/. Once the actual asset files (Savings.mp4, Savings.png, etc.) are dropped here, notifications carry media automatically.
  • assets/socialmedia/README.md documents the expected filenames, formats and container path.
  • .env.example now lists all TWITTER_* vars and points *_IMAGES_DIR at the new in-image asset paths.

Companion change

Required compose update in DFXServer/server:

TELEGRAM_IMAGES_DIR: /app/assets/socialmedia/telegram
TWITTER_IMAGES_DIR:  /app/assets/socialmedia/twitter

…replacing the legacy /app/.api/images/* paths.

Follow-ups (not in this PR)

  • Bootstrap the @dEURO_com OAuth tokens via a one-off 3-legged flow, drop the resulting JSON into the api-data volume, store a copy in Vaultwarden.
  • Drop real Savings.{png,mp4} / EquityInvest.{png,mp4} / Lending.{png,mp4} files into assets/socialmedia/.

Test plan

  • yarn build — passes (CI's only required step).
  • No unit tests added: the repo's jest config has rootDir: "src" but sources live at the repo root, so yarn test finds zero tests today. Reworking the test topology is out of scope.
  • PRD smoke after merge + deploy: monitor {container_name=~"deuro-deuro-api-.+"} |~ "TwitterService|URL host is empty" in Loki — should drop to zero. Text-only Telegram messages for Savings/Trades/Mints should still arrive in the dEURO group.

Loki evidence (last 30 days)

Symptom Count
error [TwitterService]: 234
URL host is empty 57

Both TwitterService and TelegramService fail every Saving/Trade/Mint
notification on PRD: Twitter uploadMedia/tweet returns an auth error
because twitter.token.json is `{}` (the OAuth bootstrap was never run
against @dEURO_com), and Telegram sendVideo throws "URL host is empty"
because node-telegram-bot-api reinterprets a missing local path as a
URL. The /app/.api/images/{telegram,twitter} directories referenced by
the env vars do not exist in the container — assets were lost during
the Azure→local migration.

Changes:

- TwitterService skips registration when access tokens are missing or
  the token file is empty/malformed, instead of constructing a client
  that fails on every call.
- sendPost falls back to text-only when the media asset is missing,
  removes the `throw` paths in the success branch, and logs structured
  error messages instead of opaque objects.
- TelegramService.sendMessage resolves the video path via existsSync
  and falls back to a text-only sendMessage when the asset is missing.
- New socialmedia helper `resolveMediaPath` centralises the file check.
- New assets/socialmedia/{telegram,twitter}/ layout, versioned via
  `.gitkeep`, copied into the image by the existing Dockerfile COPY.
  Companion change in DFXServer/server points the IMAGES_DIR env vars
  at /app/assets/socialmedia/* instead of the legacy /app/.api/images/*.
- README documents the expected asset filenames, formats and container
  path. .env.example reflects the new defaults and the new
  TWITTER_CLIENT_*/TOKEN_JSON/IMAGES_DIR vars.

No unit tests added: the repo's jest config has rootDir="src" but the
sources live at the repo root, so `yarn test` finds zero tests today.
Reworking the test topology is out of scope for this fix.
@TaprootFreak TaprootFreak marked this pull request as ready for review May 20, 2026 12:19
@TaprootFreak TaprootFreak merged commit 9baec29 into develop May 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant