Files
worldmonitor/package.json
Elie Habib 9b2c944eae fix(telegram): show copyable /start command for pairing (#2584)
* fix(telegram): show /start command with copy button instead of unreliable deep link

Telegram desktop ignores ?start=TOKEN for already-started bots — the
deep link opens the conversation but sends /start without the payload.

Replace the "Open Telegram" button UI with a copyable /start TOKEN command
so users can paste it directly into the bot, which works on all clients.

The deep link on the bot username is kept as a convenience to open
Telegram, but pairing no longer depends on the start parameter being
forwarded.

* fix(telegram): add Open Telegram button alongside copy command

* feat(telegram): add QR code to pairing UI for mobile users

Generates an inline SVG QR code (uqr, no canvas required) encoding the
t.me deep link so mobile users can scan instead of copy/paste. Desktop
users still have the copy command + Open Telegram button.

Layout: QR on the left (88×88), copy row + Open Telegram on the right.

* fix(telegram): implement full layered pairing UX

- Open Telegram is now the primary action (button first)
- Copy /start command is the visible fallback, always shown
- QR code moves to right side as mobile convenience (not primary path)
- Polling never calls reloadNotifSection on expiry; instead renders an
  in-place expired state with Generate new code button so users don't
  lose context
- Generate new code and Try again re-use the same startTelegramPairing
  handler without backing out
- Countdown shows Waiting... Ns instead of bare Ns
- Clipboard fallback via execCommand when navigator.clipboard unavailable
- Loading state shows Generating code... while token is being created

* fix(telegram): fix clipboard fallback for unavailable Clipboard API

Two bugs from review:
- navigator.clipboard may be undefined; accessing .writeText on it threw
  synchronously before .catch could run
- document.execCommand('copy') without a selected element copies nothing

Fix: guard with navigator.clipboard?.writeText, and in the fallback create
a temporary off-screen textarea, select its content, then execCommand.
2026-04-01 00:02:26 +04:00

137 lines
7.2 KiB
JSON

{
"name": "world-monitor",
"private": true,
"version": "2.6.5",
"license": "AGPL-3.0-only",
"type": "module",
"scripts": {
"lint": "biome lint ./src ./server ./api ./tests ./e2e ./scripts ./middleware.ts",
"lint:fix": "biome check ./src ./server ./api ./tests ./e2e ./scripts ./middleware.ts --fix",
"lint:boundaries": "node scripts/lint-boundaries.mjs",
"lint:unicode": "node scripts/check-unicode-safety.mjs",
"lint:unicode:staged": "node scripts/check-unicode-safety.mjs --staged",
"lint:md": "markdownlint-cli2 '**/*.md' '!**/node_modules/**' '!.agent/**' '!.agents/**' '!.claude/**' '!.factory/**' '!.windsurf/**' '!skills/**' '!docs/internal/**' '!docs/Docs_To_Review/**' '!todos/**' '!docs/plans/**'",
"version:sync": "node scripts/sync-desktop-version.mjs",
"version:check": "node scripts/sync-desktop-version.mjs --check",
"dev": "vite",
"dev:tech": "cross-env VITE_VARIANT=tech vite",
"dev:finance": "cross-env VITE_VARIANT=finance vite",
"dev:happy": "cross-env VITE_VARIANT=happy vite",
"dev:commodity": "cross-env VITE_VARIANT=commodity vite",
"postinstall": "cd blog-site && npm ci --prefer-offline",
"build:blog": "cd blog-site && npm run build && rm -rf ../public/blog && mkdir -p ../public/blog && cp -r dist/* ../public/blog/",
"build:pro": "cd pro-test && npm install && npm run build",
"build": "npm run build:blog && tsc && vite build",
"build:sidecar-sebuf": "node scripts/build-sidecar-sebuf.mjs",
"build:desktop": "node scripts/build-sidecar-sebuf.mjs && node scripts/build-sidecar-handlers.mjs && tsc && vite build",
"build:full": "npm run build:blog && cross-env-shell VITE_VARIANT=full \"tsc && vite build\"",
"build:tech": "cross-env-shell VITE_VARIANT=tech \"tsc && vite build\"",
"build:finance": "cross-env-shell VITE_VARIANT=finance \"tsc && vite build\"",
"build:happy": "cross-env-shell VITE_VARIANT=happy \"tsc && vite build\"",
"build:commodity": "cross-env-shell VITE_VARIANT=commodity \"tsc && vite build\"",
"typecheck": "tsc --noEmit",
"typecheck:api": "tsc --noEmit -p tsconfig.api.json",
"typecheck:all": "tsc --noEmit && tsc --noEmit -p tsconfig.api.json",
"tauri": "tauri",
"preview": "vite preview",
"test:e2e:full": "cross-env VITE_VARIANT=full playwright test",
"test:e2e:tech": "cross-env VITE_VARIANT=tech playwright test",
"test:e2e:finance": "cross-env VITE_VARIANT=finance playwright test",
"test:e2e:runtime": "cross-env VITE_VARIANT=full playwright test e2e/runtime-fetch.spec.ts",
"test:e2e": "npm run test:e2e:runtime && npm run test:e2e:full && npm run test:e2e:tech && npm run test:e2e:finance",
"test:data": "tsx --test tests/*.test.mjs tests/*.test.mts",
"test:feeds": "node scripts/validate-rss-feeds.mjs",
"test:sidecar": "node --test src-tauri/sidecar/local-api-server.test.mjs api/_cors.test.mjs api/youtube/embed.test.mjs api/cyber-threats.test.mjs api/usni-fleet.test.mjs scripts/ais-relay-rss.test.cjs api/loaders-xml-wms-regression.test.mjs",
"test:e2e:visual:full": "cross-env VITE_VARIANT=full playwright test -g \"matches golden screenshots per layer and zoom\"",
"test:e2e:visual:tech": "cross-env VITE_VARIANT=tech playwright test -g \"matches golden screenshots per layer and zoom\"",
"test:e2e:visual": "npm run test:e2e:visual:full && npm run test:e2e:visual:tech",
"test:e2e:visual:update:full": "cross-env VITE_VARIANT=full playwright test -g \"matches golden screenshots per layer and zoom\" --update-snapshots",
"test:e2e:visual:update:tech": "cross-env VITE_VARIANT=tech playwright test -g \"matches golden screenshots per layer and zoom\" --update-snapshots",
"test:e2e:visual:update": "npm run test:e2e:visual:update:full && npm run test:e2e:visual:update:tech",
"desktop:dev": "npm run version:sync && cross-env VITE_DESKTOP_RUNTIME=1 tauri dev -f devtools",
"desktop:build:full": "npm run version:sync && cross-env VITE_VARIANT=full VITE_DESKTOP_RUNTIME=1 tauri build",
"desktop:build:tech": "npm run version:sync && cross-env VITE_VARIANT=tech VITE_DESKTOP_RUNTIME=1 tauri build --config src-tauri/tauri.tech.conf.json",
"desktop:build:finance": "npm run version:sync && cross-env VITE_VARIANT=finance VITE_DESKTOP_RUNTIME=1 tauri build --config src-tauri/tauri.finance.conf.json",
"desktop:package:macos:full": "node scripts/desktop-package.mjs --os macos --variant full",
"desktop:package:macos:tech": "node scripts/desktop-package.mjs --os macos --variant tech",
"desktop:package:windows:full": "node scripts/desktop-package.mjs --os windows --variant full",
"desktop:package:windows:tech": "node scripts/desktop-package.mjs --os windows --variant tech",
"desktop:package:macos:full:sign": "node scripts/desktop-package.mjs --os macos --variant full --sign",
"desktop:package:macos:tech:sign": "node scripts/desktop-package.mjs --os macos --variant tech --sign",
"desktop:package:windows:full:sign": "node scripts/desktop-package.mjs --os windows --variant full --sign",
"desktop:package:windows:tech:sign": "node scripts/desktop-package.mjs --os windows --variant tech --sign",
"desktop:package": "node scripts/desktop-package.mjs"
},
"devDependencies": {
"@biomejs/biome": "^2.4.7",
"@bufbuild/buf": "^1.66.0",
"@playwright/test": "^1.52.0",
"@tauri-apps/cli": "^2.10.0",
"@types/canvas-confetti": "^1.9.0",
"@types/d3": "^7.4.3",
"@types/dompurify": "^3.0.5",
"@types/geojson": "^7946.0.14",
"@types/maplibre-gl": "^1.13.2",
"@types/marked": "^5.0.2",
"@types/papaparse": "^5.5.2",
"@types/supercluster": "^7.1.3",
"@types/three": "^0.183.1",
"@types/topojson-client": "^3.1.5",
"@types/topojson-specification": "^1.0.5",
"cross-env": "^10.1.0",
"esbuild": "^0.27.3",
"h3-js": "^4.4.0",
"markdownlint-cli2": "^0.21.0",
"tsx": "^4.21.0",
"typescript": "^5.7.2",
"vite": "^6.0.7",
"vite-plugin-pwa": "^1.2.0"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.79.0",
"@aws-sdk/client-s3": "^3.1009.0",
"@clerk/clerk-js": "^5.56.0",
"@deck.gl/aggregation-layers": "^9.2.6",
"@deck.gl/core": "^9.2.6",
"@deck.gl/geo-layers": "^9.2.6",
"@deck.gl/layers": "^9.2.6",
"@deck.gl/mapbox": "^9.2.6",
"@protomaps/basemaps": "^5.7.1",
"@sentry/browser": "^10.39.0",
"@upstash/ratelimit": "^2.0.8",
"@upstash/redis": "^1.36.1",
"@vercel/analytics": "^2.0.0",
"@xenova/transformers": "^2.17.2",
"canvas-confetti": "^1.9.4",
"convex": "^1.32.0",
"d3": "^7.9.0",
"deck.gl": "^9.2.6",
"dompurify": "^3.1.7",
"fast-xml-parser": "^5.3.7",
"globe.gl": "^2.45.0",
"hls.js": "^1.6.15",
"i18next": "^25.8.10",
"i18next-browser-languagedetector": "^8.2.1",
"jose": "^6.0.11",
"maplibre-gl": "^5.16.0",
"marked": "^17.0.3",
"onnxruntime-web": "^1.23.2",
"papaparse": "^5.5.3",
"pmtiles": "^4.4.0",
"preact": "^10.25.4",
"satellite.js": "^6.0.2",
"supercluster": "^8.0.1",
"telegram": "^2.26.22",
"topojson-client": "^3.1.0",
"uqr": "^0.1.2",
"ws": "^8.19.0",
"youtubei.js": "^16.0.1"
},
"overrides": {
"fast-xml-parser": "^5.3.7",
"serialize-javascript": "^7.0.4",
"node-forge": "^1.4.0",
"srvx": "^0.11.13"
}
}