-
Notifications
You must be signed in to change notification settings - Fork 0
integrated prettier and format script in package.json #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughIntroduces Prettier configuration and formatting updates across the codebase. Adds new account retrieval and usage-reporting methods to Telegram and Twitter account managers. Refactors tests for modular redis checks and rotation flows. Updates package.json with a formatting script and Prettier devDependency. Minor README subtitle and type declaration quoting change. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer/Tooling
participant App as App
participant TGM as TelegramAccountManager
participant TwM as TwitterAccountManager
participant Redis as Redis
note over App: Account usage listing
App->>TGM: getAllAccountsUsage()
TGM->>TGM: fetchAllAccounts()
TGM->>Redis: GET telegram-accounts
Redis-->>TGM: Encrypted accounts JSON
TGM->>TGM: Decrypt & parse
TGM-->>App: [{accountId, lastUsed?, totalRequests?}, ...]
App->>TwM: getAllAccountsUsage()
TwM->>TwM: fetchAllAccounts()
TwM->>Redis: GET twitter-accounts
Redis-->>TwM: Encrypted accounts JSON
TwM->>TwM: Decrypt, build accountId
TwM->>Redis: HGET usage:{accountId}
Redis-->>TwM: {total_requests, last_request}
TwM-->>App: Accounts with usage
note over TwM,Redis: trackApiKeyUsageLocal() updates usage counters on demand
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/index.ts (1)
31-35
: Don’t reach into a manager’s protected Redis client.Accessing
(telegramAccountManager as any).redisClient
breaks encapsulation and risks connection state conflicts. Use a short‑lived client here or expose a proper helper on the manager.- const redisClient = (telegramAccountManager as any).redisClient; - await redisClient.connect?.(); - const sessionKey = `telegram_session:${account.accountId}`; - let sessionStr = await redisClient.get(sessionKey); - const isInteractive = Boolean(process.stdin.isTTY); + const sessionKey = `telegram_session:${account.accountId}`; + const tmpRedis = createClient({ url: process.env.REDIS_URL }); + await tmpRedis.connect(); + let sessionStr = await tmpRedis.get(sessionKey); + await tmpRedis.quit(); + const isInteractive = Boolean(process.stdin.isTTY);Add import:
import { StringSession } from 'telegram/sessions'; +import { createClient } from 'redis';
src/utils/redisUtils.ts (1)
1-6
: Use env Redis URL; drop unused import.Hardcoding
redis://localhost:6379
breaks non-local deployments. Alsocrypto
isn’t used.-import crypto from 'crypto'; -import { createClient } from 'redis'; +import 'dotenv/config'; +import { createClient } from 'redis'; @@ -const redisClient = createClient({ url: 'redis://localhost:6379' }); +const redisClient = createClient({ url: process.env.REDIS_URL || 'redis://localhost:6379' });
🧹 Nitpick comments (15)
src/utils/showEnvVariables.ts (1)
41-44
: Harden per-field decryption; avoid crashing on non-cipher fields.When
accounts = [{ error: 'Failed to parse' }]
and--decrypt
is used,decrypt()
will throw. Guard or fallback to masked value.- Object.entries(acc).forEach(([k, v]) => { - const shown = decryptFlag && decryptFn ? decryptFn(v as string) : mask(v as string); - console.log(` ${k}: ${shown}`); - }); + Object.entries(acc).forEach(([k, v]) => { + let shown = mask(v as string); + if (decryptFlag && decryptFn && k !== 'error') { + try { + shown = decryptFn(v as string); + } catch { + shown = '(decrypt failed)'; + } + } + console.log(` ${k}: ${shown}`); + });src/utils/moveEnvToRedis.ts (2)
32-40
: Whitelist “other” vars via explicit opt‑in.Store non‑Twitter/Telegram env only if
MOVE_ALL_ENV=1
.- for (const [key, value] of Object.entries(envVars)) { + const allowOther = process.env.MOVE_ALL_ENV === '1'; + for (const [key, value] of Object.entries(envVars)) { if (twitterKeys.includes(key)) { twitterAccount[key] = encrypt(value); } else if (telegramKeys.includes(key)) { telegramAccount[key] = encrypt(value); - } else { - otherVars[key] = encrypt(value); + } else if (allowOther) { + otherVars[key] = encrypt(value); } }
72-72
: Close Redis gracefully; avoid forceprocess.exit(0)
.Use finally/quit; let the process exit naturally.
-moveEnvToRedis().then(() => process.exit(0)); +moveEnvToRedis() + .finally(async () => { + if (redisClient.isOpen) await redisClient.quit(); + });src/services/BaseAccountManager.ts (2)
21-23
: Constructor log may print undefined platform.
this.platform
might not be initialized during base constructor. Guard the label.- this.redisClient.on('error', (err) => { - console.error(`Redis Client Error in ${this.platform}AccountManager:`, err); - }); + this.redisClient.on('error', (err) => { + const p = (this as any).platform ?? 'Base'; + console.error(`Redis Client Error in ${p}AccountManager:`, err); + });
46-47
: Lock TTL likely too short for API calls.15s may expire mid‑request, allowing concurrent claim of the same account. Bump TTL and/or make it configurable.
- const ok = await this.redisClient.set(lockKey, '1', { NX: true, PX: 15000 }); + const ttlMs = Number(process.env.ACCOUNT_LOCK_TTL_MS ?? '300000'); // default 5m + const ok = await this.redisClient.set(lockKey, '1', { NX: true, PX: ttlMs });Optional: emit heartbeats or extend the lock while in-flight.
src/utils/redisUtils.ts (1)
12-17
: Prefer client’sisOpen
over separate flag.Avoid desync between
redisConnected
and actual client state.-async function ensureRedisConnected() { - if (!redisConnected) { - await redisClient.connect(); - redisConnected = true; - } -} +async function ensureRedisConnected() { + if (!redisClient.isOpen) { + await redisClient.connect(); + } +}src/tests/testRotation.ts (2)
12-12
: Use a type‑only import or drop the unused interface.
TwitterAccount
isn’t referenced as a type anywhere in this file. Remove it or import it as a type‑only to avoid an unnecessary runtime import in certain bundlers.-import { twitterAccountManager, TwitterAccount } from '../services/twitterAccountManager'; +import { twitterAccountManager } from '../services/twitterAccountManager'; +// or, if you plan to annotate helpers later: +// import type { TwitterAccount } from '../services/twitterAccountManager';
24-28
: This empty-result branch is effectively unreachable.
twitterAccountManager.getAllAccountsUsage()
currently throws when no accounts exist (upstreamfetchAllAccounts()
), andmain()
already preflights Redis viatestRedisConnection()
. Consider removing this branch to reduce confusion.If you prefer returning an empty array instead of throwing, align that in
TwitterAccountManager
and keep this branch; otherwise remove it.src/services/telegramAccountManager.ts (2)
60-61
: Unify Redis usage reads with the manager’s own client (consistency with Twitter).This calls a global
getApiKeyUsage(...)
that manages its own connection, while the rest of this class usesthis.redisClient
. Prefer a local helper like Twitter’sgetApiKeyUsageLocal
for connection reuse and fewer sockets.- const usage = await getApiKeyUsage({ accountId, platform: 'telegram' }); + const usage = await this.getApiKeyUsageLocal(accountId);Add a local helper (outside this range):
private async getApiKeyUsageLocal( accountId: string ): Promise<{ total_requests: number; last_request: string | null }> { await this.ensureConnected(); const key = `telegram_accounts:${accountId}`; const data = await this.redisClient.hGetAll(key); return { total_requests: data?.total_requests ? parseInt(data.total_requests, 10) : 0, last_request: data?.last_request ?? null }; }You can then drop the
getApiKeyUsage
import.
19-20
: Remove unusedusageKeyPrefix
or use it when composing keys.Search shows only the abstract declaration and per-platform assignments (src/services/BaseAccountManager.ts:15, src/services/twitterAccountManager.ts:19, src/services/telegramAccountManager.ts:19) with no other references. Either remove the abstract property and the concrete assignments, or reference
this.usageKeyPrefix
in BaseAccountManager when building usage/storage keys.src/tests/testTelegramRotation.ts (3)
13-13
: Drop the unused interface or import it as type‑only.
TelegramAccount
isn’t referenced as a type; avoid unnecessary runtime import.-import { telegramAccountManager, TelegramAccount } from '../services/telegramAccountManager'; +import { telegramAccountManager } from '../services/telegramAccountManager'; +// or: +// import type { TelegramAccount } from '../services/telegramAccountManager';
31-36
: Be careful printing identifiers; prefer masked IDs in logs.Until
TelegramAccountManager
switches to hashedaccountId
, logs expose decrypted API IDs. Either mask the value here, or adopt the hashed id change in the manager (recommended).Example for the first occurrence:
- console.log(` Account ${index + 1}: ${account.accountId}`); + const id = String(account.accountId); + console.log(` Account ${index + 1}: ${id.slice(0, 8)}…`);Replicate for other prints in this file.
Also applies to: 64-68, 75-76
145-146
: Add an ESM‑safe main guard.Same note as the Twitter test: extend the guard to work under
"type": "module"
.Reuse the verification script from the Twitter test comment to decide whether to add an ESM path.
src/services/twitterAccountManager.ts (2)
45-63
: Bound or batch the per‑account Redis reads to improve scalability.The loop awaits each
hGetAll
sequentially. For N accounts this adds latency. Batch withPromise.all
(or a small concurrency limit) after synchronous decrypts.Example sketch:
const accounts = encryptedAccounts.map((ea, i) => { const credentials = { /* decrypt */ }; const token = credentials.TWITTER_AUTH_TOKEN; const accountId = `twitter_${createHash('sha256').update(token).digest('hex').slice(0, 12)}`; return { accountId, credentials }; }); const usages = await Promise.all( accounts.map(a => this.getApiKeyUsageLocal(a.accountId)) ); return accounts.map((a, i) => ({ ...a, lastUsed: usages[i].last_request || undefined, totalRequests: usages[i].total_requests }));If Redis load is a concern, use a limiter (e.g., p‑limit) to cap concurrency.
19-20
:usageKeyPrefix
appears unused in this class.Either use it to compose keys (
${usageKeyPrefix}:${accountId}
) or remove to avoid drift with Telegram.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (20)
.prettierrc
(1 hunks)README.md
(1 hunks)package.json
(1 hunks)src/fetchTelegramMessages.ts
(4 hunks)src/index.ts
(5 hunks)src/lib/encryption.ts
(1 hunks)src/lib/utils/string.ts
(1 hunks)src/services/BaseAccountManager.ts
(1 hunks)src/services/telegramAccountManager.ts
(1 hunks)src/services/twitterAccountManager.ts
(1 hunks)src/telegram.ts
(1 hunks)src/tests/rotationDemo.ts
(2 hunks)src/tests/telegramRotationDemo.ts
(2 hunks)src/tests/testRotation.ts
(2 hunks)src/tests/testTelegramRotation.ts
(2 hunks)src/twitterApi.ts
(6 hunks)src/types/input.d.ts
(1 hunks)src/utils/moveEnvToRedis.ts
(1 hunks)src/utils/redisUtils.ts
(4 hunks)src/utils/showEnvVariables.ts
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (9)
src/utils/showEnvVariables.ts (2)
src/lib/encryption.ts (1)
decrypt
(27-39)src/lib/utils/string.ts (1)
mask
(7-10)
src/tests/telegramRotationDemo.ts (1)
src/services/telegramAccountManager.ts (1)
telegramAccountManager
(105-105)
src/tests/rotationDemo.ts (1)
src/services/twitterAccountManager.ts (1)
twitterAccountManager
(117-117)
src/services/twitterAccountManager.ts (1)
src/lib/encryption.ts (1)
decrypt
(27-39)
src/tests/testTelegramRotation.ts (1)
src/services/telegramAccountManager.ts (1)
telegramAccountManager
(105-105)
src/services/telegramAccountManager.ts (2)
src/lib/encryption.ts (1)
decrypt
(27-39)src/utils/redisUtils.ts (2)
getApiKeyUsage
(66-99)trackApiKeyUsage
(18-52)
src/tests/testRotation.ts (1)
src/services/twitterAccountManager.ts (1)
twitterAccountManager
(117-117)
src/utils/moveEnvToRedis.ts (1)
src/lib/encryption.ts (1)
encrypt
(19-25)
src/twitterApi.ts (1)
src/services/twitterAccountManager.ts (2)
TwitterAccount
(5-14)twitterAccountManager
(117-117)
🔇 Additional comments (26)
src/lib/utils/string.ts (1)
8-9
: LGTM! Formatting consistency maintained.The indentation adjustments align with the Prettier configuration while preserving the function's logic and behavior.
README.md (1)
3-3
: LGTM! Helpful descriptive subtitle added.The new subtitle clearly describes the purpose of the ingestion engine, improving documentation clarity for new users and contributors.
src/lib/encryption.ts (3)
10-16
: LGTM! Formatting improvements while preserving security.The formatting changes improve readability while maintaining all security validations and key management logic.
20-25
: LGTM! Consistent formatting applied to encryption function.The formatting updates maintain the secure encryption implementation with proper IV generation and auth tag handling.
28-39
: LGTM! Decryption function formatting maintained securely.All security-critical operations (format validation, scheme checking, auth tag verification) are preserved with improved formatting.
src/tests/telegramRotationDemo.ts (2)
4-4
: LGTM! Minor formatting improvement.The addition of a blank line after the header comment improves readability without affecting functionality.
16-98
: LGTM! Consistent formatting applied throughout.The formatting changes improve code consistency and readability while preserving all demo functionality, error handling, and account rotation simulation logic.
package.json (2)
9-11
: LGTM! Essential formatting script added.The new
format
script enables consistent code formatting across the project using Prettier.
14-14
: Verify Prettier version for security and compatibility.Ensure the Prettier version is secure and compatible with the project's Node.js version.
Based on the search results, there are security concerns with Prettier:
- CVE-2025-8263: A vulnerability affecting Prettier up to version 3.6.2, with a recommendation to upgrade to the latest version beyond 3.6.2
- No direct vulnerabilities for 3.6.2: Snyk shows no direct vulnerabilities for this specific version
However, the CVE suggests upgrading beyond 3.6.2 for security. Let me check the latest version:Based on the search results, the latest version of Prettier is 3.6.2, which is the version used in this PR. However, CVE-2025-8263 affects Prettier up to version 3.6.2 and recommends upgrading to the latest version beyond 3.6.2.
The contradiction here is that 3.6.2 is currently the latest version, but the CVE suggests upgrading beyond 3.6.2. This indicates that the CVE has a CVSS base score of 4.3 (Medium severity) and relates to inefficient regular expression complexity in the parseNestedCSS function.
Given that:
- No direct vulnerabilities have been found for Prettier in Snyk's vulnerability database
- The CVE affects CSS parsing specifically and has medium severity
- 3.6.2 is currently the latest available version
- This is a development dependency used only for formatting
The risk is acceptable for now, but monitoring for updates is recommended.
.prettierrc (1)
1-10
: LGTM! Well-configured Prettier settings.The configuration provides sensible defaults with appropriate line width (120), consistent quote style (single quotes), and proper formatting rules that align with modern JavaScript/TypeScript best practices.
src/types/input.d.ts (1)
1-1
: LGTM! Quote style consistency applied.The change from double quotes to single quotes aligns with the new Prettier configuration while maintaining the module declaration functionality.
src/fetchTelegramMessages.ts (4)
1-1
: LGTM! Import formatting consistency maintained.The formatting adjustments align with the Prettier configuration while preserving all functionality.
13-13
: LGTM! Error message formatting improved.The quote style change maintains error message clarity and consistency.
41-41
: LGTM! Parameter formatting consistency.The formatting change improves readability without affecting the API call functionality.
47-47
: LGTM! String literal formatting consistency.Both property access checks and console messages now use consistent single-quote formatting as per the Prettier configuration.
Also applies to: 57-57
src/telegram.ts (1)
26-29
: Double‑check printing of session secrets.Even behind
PRINT_TG_SESSION === '1'
, this prints a highly sensitive session string. Confirm this never runs in shared logs/CI; consider writing to a file path explicitly passed via CLI instead.src/index.ts (1)
37-39
: Good guard for non‑interactive runs.Clear message and early fail if no session in Redis and no TTY.
src/twitterApi.ts (1)
154-156
: Good: usage tracking after successful fetch.This aligns with the locking flow in the account manager.
src/tests/rotationDemo.ts (1)
90-91
: Nice: deterministic cleanup.Disconnecting the manager in finally avoids Redis leaks during demos.
src/services/BaseAccountManager.ts (1)
68-72
: Graceful disconnect logic looks good.Straightforward and idempotent.
src/utils/redisUtils.ts (1)
134-135
: LGTM on batch usage mapping.Null handling and defaulting are correct.
src/tests/testRotation.ts (2)
39-55
: Rotation flow looks solid.Good, straightforward exercise of “select earliest → mark used → wait → repeat,” with a final consistency probe. No issues spotted here.
If you flip
TwitterAccountManager.getAllAccountsUsage()
to usage‑only (see manager comment), this test remains valid since it doesn’t rely on credentials.Also applies to: 59-76
142-144
: Keep CJS guard — no ESM guard neededpackage.json has no "type" field and tsconfig.json sets compilerOptions.module = "commonjs", so require.main === module is sufficient.
Location: src/tests/testRotation.ts (lines 142–144)src/services/telegramAccountManager.ts (1)
31-41
: Parsing and “no accounts” error handling look good.Clear failures for missing keys and malformed JSON, and a guard to ensure at least one decrypted account.
Also applies to: 74-79
src/tests/testTelegramRotation.ts (1)
43-57
: Rotation flow is clean and mirrors the Twitter test.Straightforward iterations with a timestamp guard and final verification. Looks good.
Also applies to: 72-79
src/services/twitterAccountManager.ts (1)
56-59
: Good call on hashing the token foraccountId
.Stable, non‑reversible ID that’s safe to log and use as a Redis key component.
Do your Twitter auth tokens rotate in practice? If so, usage history will fragment across IDs. If there’s a stable user identifier available (e.g., account numeric ID), consider hashing that instead.
// Generate account ID from API ID (for uniqueness) | ||
const accountId = `telegram_${credentials.TELEGRAM_API_ID}`; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid leaking raw TELEGRAM_API_ID in accountId; hash it like Twitter.
accountId = telegram_${TELEGRAM_API_ID}
exposes the decrypted API ID in logs and Redis keys. Use a stable, non‑reversible hash (mirrors Twitter).
- // Generate account ID from API ID (for uniqueness)
- const accountId = `telegram_${credentials.TELEGRAM_API_ID}`;
+ // Generate stable, non-reversible account ID (SHA-256, 12 hex chars)
+ const idSource = credentials.TELEGRAM_API_ID;
+ const accountId = `telegram_${createHash('sha256').update(idSource).digest('hex').slice(0, 12)}`;
Also add the import:
-import { BaseAccountManager, BaseAccount } from './BaseAccountManager';
+import { BaseAccountManager, BaseAccount } from './BaseAccountManager';
+import { createHash } from 'crypto';
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// Generate account ID from API ID (for uniqueness) | |
const accountId = `telegram_${credentials.TELEGRAM_API_ID}`; | |
import { BaseAccountManager, BaseAccount } from './BaseAccountManager'; | |
import { createHash } from 'crypto'; | |
// Generate stable, non-reversible account ID (SHA-256, 12 hex chars) | |
const idSource = credentials.TELEGRAM_API_ID; | |
const accountId = `telegram_${createHash('sha256').update(idSource).digest('hex').slice(0, 12)}`; |
🤖 Prompt for AI Agents
In src/services/telegramAccountManager.ts around lines 56 to 58, the code builds
accountId by concatenating the raw TELEGRAM_API_ID which may leak sensitive
data; instead compute a stable non‑reversible hash (e.g., SHA‑256 hex) of
credentials.TELEGRAM_API_ID and use `telegram_<hash>` as the accountId, and add
the required import from Node's crypto module (e.g., import { createHash } from
'crypto') so the hash computation is deterministic and irreversible.
async getAllAccountsUsage(): Promise<TwitterAccount[]> { | ||
return await this.fetchAllAccounts(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getAllAccountsUsage
should not return credentials; split the API.
The method name implies usage‑only, but it returns full accounts incl. decrypted credentials. Align with the Telegram manager and reduce accidental exposure.
- async getAllAccountsUsage(): Promise<TwitterAccount[]> {
- return await this.fetchAllAccounts();
- }
+ async getAllAccountsUsage(): Promise<
+ Array<{ accountId: string; lastUsed?: string; totalRequests?: number }>
+ > {
+ const accounts = await this.fetchAllAccounts();
+ return accounts.map(({ accountId, lastUsed, totalRequests }) => ({
+ accountId,
+ lastUsed,
+ totalRequests
+ }));
+ }
+
+ /**
+ * Get all accounts with credentials (full info)
+ */
+ async getAllAccountsWithCredentials(): Promise<TwitterAccount[]> {
+ return await this.fetchAllAccounts();
+ }
The current tests use only usage fields, so this change should be non‑breaking.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
async getAllAccountsUsage(): Promise<TwitterAccount[]> { | |
return await this.fetchAllAccounts(); | |
} | |
async getAllAccountsUsage(): Promise< | |
Array<{ accountId: string; lastUsed?: string; totalRequests?: number }> | |
> { | |
const accounts = await this.fetchAllAccounts(); | |
return accounts.map(({ accountId, lastUsed, totalRequests }) => ({ | |
accountId, | |
lastUsed, | |
totalRequests | |
})); | |
} | |
/** | |
* Get all accounts with credentials (full info) | |
*/ | |
async getAllAccountsWithCredentials(): Promise<TwitterAccount[]> { | |
return await this.fetchAllAccounts(); | |
} |
🤖 Prompt for AI Agents
In src/services/twitterAccountManager.ts around lines 111-113,
getAllAccountsUsage currently returns full accounts including credentials by
calling fetchAllAccounts; change it to return usage-only data (no decrypted
credentials) to match the Telegram manager: either add a new
fetchAllAccountsUsage() that returns sanitized TwitterAccountUsage objects or
map the result of fetchAllAccounts() to strip credential fields before
returning, and keep a separate fetchAllAccounts()/getAllAccounts() API that
continues to return full accounts when truly needed; update return types
accordingly and ensure existing tests still pass since they only rely on usage
fields.
const apiId = 26767039; | ||
const apiHash = "5c9c82971de30b5e71030c27878b8115"; | ||
const stringSession = new StringSession(""); // empty = new login | ||
const apiHash = '5c9c82971de30b5e71030c27878b8115'; | ||
const stringSession = new StringSession(''); // empty = new login | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove hardcoded Telegram credentials; load from env.
Leaking apiId
/apiHash
in source is a critical secret exposure risk. Read from environment and validate.
+import 'dotenv/config';
// Replace these with your values
-const apiId = 26767039;
-const apiHash = '5c9c82971de30b5e71030c27878b8115';
-const stringSession = new StringSession(''); // empty = new login
+const apiId = Number(process.env.TELEGRAM_API_ID);
+const apiHash = process.env.TELEGRAM_API_HASH || '';
+const stringSession = new StringSession(process.env.TELEGRAM_SESSION || ''); // empty = new login
+if (!Number.isFinite(apiId) || !apiHash) {
+ throw new Error('Missing TELEGRAM_API_ID/TELEGRAM_API_HASH in environment');
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const apiId = 26767039; | |
const apiHash = "5c9c82971de30b5e71030c27878b8115"; | |
const stringSession = new StringSession(""); // empty = new login | |
const apiHash = '5c9c82971de30b5e71030c27878b8115'; | |
const stringSession = new StringSession(''); // empty = new login | |
import 'dotenv/config'; | |
const apiId = Number(process.env.TELEGRAM_API_ID); | |
const apiHash = process.env.TELEGRAM_API_HASH || ''; | |
const stringSession = new StringSession(process.env.TELEGRAM_SESSION || ''); // empty = new login | |
if (!Number.isFinite(apiId) || !apiHash) { | |
throw new Error('Missing TELEGRAM_API_ID/TELEGRAM_API_HASH in environment'); | |
} |
🤖 Prompt for AI Agents
In src/telegram.ts around lines 7 to 10 the Telegram credentials are hardcoded
(apiId/apiHash/stringSession); replace them with environment-driven values: read
API_ID (parseInt) and API_HASH (string) from process.env (optionally load dotenv
earlier), read STRING_SESSION from env or keep empty fallback, validate that
API_ID and API_HASH are present and API_ID is a valid number, and if not throw
or exit with a clear error so the app never runs with embedded secrets.
const res = await fetch(url, { method: 'GET', headers }); | ||
if (!res.ok) { | ||
console.error("Viewer API request failed:", res.status, res.statusText); | ||
console.error('Viewer API request failed:', res.status, res.statusText); | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a timeout to external requests (Viewer).
Network calls can hang indefinitely; use AbortController.
- const res = await fetch(url, { method: 'GET', headers });
+ const controller = new AbortController();
+ const t = setTimeout(() => controller.abort(), 10000);
+ let res: Response;
+ try {
+ res = await fetch(url, { method: 'GET', headers, signal: controller.signal });
+ } finally {
+ clearTimeout(t);
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const res = await fetch(url, { method: 'GET', headers }); | |
if (!res.ok) { | |
console.error("Viewer API request failed:", res.status, res.statusText); | |
console.error('Viewer API request failed:', res.status, res.statusText); | |
return null; | |
const controller = new AbortController(); | |
const t = setTimeout(() => controller.abort(), 10000); | |
let res: Response; | |
try { | |
res = await fetch(url, { method: 'GET', headers, signal: controller.signal }); | |
} finally { | |
clearTimeout(t); | |
} | |
if (!res.ok) { | |
console.error('Viewer API request failed:', res.status, res.statusText); | |
return null; |
const response = await fetch(url, { | ||
method: "POST", | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify(body), | ||
body: JSON.stringify(body) | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a timeout to HomeTimeline request.
Same reasoning; prevent hung cron workers.
- const response = await fetch(url, {
- method: 'POST',
- headers,
- body: JSON.stringify(body)
- });
+ const controller = new AbortController();
+ const t = setTimeout(() => controller.abort(), 15000);
+ let response: Response;
+ try {
+ response = await fetch(url, {
+ method: 'POST',
+ headers,
+ body: JSON.stringify(body),
+ signal: controller.signal
+ });
+ } finally {
+ clearTimeout(t);
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const response = await fetch(url, { | |
method: "POST", | |
method: 'POST', | |
headers, | |
body: JSON.stringify(body), | |
body: JSON.stringify(body) | |
}); | |
const controller = new AbortController(); | |
const t = setTimeout(() => controller.abort(), 15000); | |
let response: Response; | |
try { | |
response = await fetch(url, { | |
method: 'POST', | |
headers, | |
body: JSON.stringify(body), | |
signal: controller.signal | |
}); | |
} finally { | |
clearTimeout(t); | |
} |
🤖 Prompt for AI Agents
In src/twitterApi.ts around lines 105-109, the fetch POST for the HomeTimeline
request has no timeout and can hang; add an AbortController-based timeout:
create an AbortController, pass controller.signal into fetch options, start a
timer (use a configurable constant like HOME_TIMELINE_TIMEOUT_MS) that calls
controller.abort() after the timeout, and clear the timer once fetch completes;
also handle the abort error path (treat as a timeout error) in the surrounding
try/catch so cron workers fail fast and the request is retried/handled
appropriately.
const envVars: Record<string, string> = {}; | ||
const EXCLUDE = new Set(['ENCRYPTION_KEY']); | ||
for (const [key, value] of Object.entries(process.env)) { | ||
if (!value || EXCLUDE.has(key)) continue; | ||
envVars[key] = value; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid dumping all env vars into Redis by default.
Current logic encrypts and stores every env var except ENCRYPTION_KEY
, which can capture unrelated secrets (CI tokens, app creds). Gate “other” vars behind an explicit flag or a whitelist.
- const envVars: Record<string, string> = {};
+ const envVars: Record<string, string> = {};
const EXCLUDE = new Set(['ENCRYPTION_KEY']);
(see loop change below)
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/utils/moveEnvToRedis.ts around lines 16 to 21, the current loop copies
every env var except ENCRYPTION_KEY into Redis which risks leaking unrelated
secrets; change the logic to only move a safe whitelist of env keys by default
(e.g., APP_NAME, NODE_ENV, PORT, etc.), and require an explicit opt-in flag
(ENV_REDIS_MOVE_ALLOW_OTHERS or similar) to include all other vars; retain
ENCRYPTION_KEY in the exclusion set, log when non-whitelisted vars are skipped,
and if the opt-in flag is set, then allow copying the remaining vars while still
excluding ENCRYPTION_KEY.
await redisClient.connect(); | ||
await showAccounts(redisClient, decryptFlag, decryptFn); | ||
await redisClient.quit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure Redis is closed on error (use try/finally).
If showAccounts
throws (e.g., bad JSON), quit()
is never called. Wrap connect/quit in try/finally.
- await redisClient.connect();
- await showAccounts(redisClient, decryptFlag, decryptFn);
- await redisClient.quit();
+ await redisClient.connect();
+ try {
+ await showAccounts(redisClient, decryptFlag, decryptFn);
+ } finally {
+ await redisClient.quit();
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
await redisClient.connect(); | |
await showAccounts(redisClient, decryptFlag, decryptFn); | |
await redisClient.quit(); | |
await redisClient.connect(); | |
try { | |
await showAccounts(redisClient, decryptFlag, decryptFn); | |
} finally { | |
await redisClient.quit(); | |
} |
🤖 Prompt for AI Agents
In src/utils/showEnvVariables.ts around lines 12 to 14, the code calls await
redisClient.connect(); then await showAccounts(...); then await
redisClient.quit(); but if showAccounts throws, quit() never runs; wrap the
showAccounts call (and any subsequent work) in a try/finally so that
redisClient.quit() is always awaited in the finally block (optionally checking a
connected flag or catching errors from quit), i.e., connect first, then try {
await showAccounts(...) } finally { await redisClient.quit(); } to ensure Redis
is closed on error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks jack for the pr. ignore code rabbits review. formatting files causes this
Summary by CodeRabbit