diff --git a/index.js b/index.js index 1a2019e..ba42673 100644 --- a/index.js +++ b/index.js @@ -4171,6 +4171,26 @@ function escapeMarkdownFull(text) { return String(text).replace(/[_*[\]()~`>#+\-=|{}.!\\]/g, '\\$&'); } +/** + + * ensureDataDir executes its scoped Runewager logic and participates in menu/command or utility flow composition. + + * Parameters: See the function signature for exact argument names and accepted values. + + * Returns: Returns the computed value or a Promise resolving to the operation result; may return void for side-effect handlers. + + * Side effects: May mutate runtime stores, pendingAction state, menu state, persistence files, logs, and callback progression. + + * Validation/safety: Uses existing guard utilities (admin checks, input checks, path checks, cooldown checks) where applicable. + + * Timeouts/fallbacks: Timeout and fallback behavior are controlled by the calling flow and global handler/state machine conventions. + + * Errors: Surfaces user-facing error replies and/or logs when inputs, permissions, or dependencies are invalid. + + * System fit: This function is part of the Runewager command/callback/state orchestration pipeline. + + */ + /** * ensureDataDir executes its scoped Runewager logic and participates in menu/command or utility flow composition. @@ -7745,6 +7765,63 @@ bot.action('admin_cat_support', async (ctx) => { }); +/** + + + * adminTestsToolsKeyboard executes its scoped Runewager logic and participates in menu/command or utility flow composition. + + + * Parameters: See the function signature for exact argument names and accepted values. + + + * Returns: Returns the computed value or a Promise resolving to the operation result; may return void for side-effect handlers. + + + * Side effects: May mutate runtime stores, pendingAction state, menu state, persistence files, logs, and callback progression. + + + * Validation/safety: Uses existing guard utilities (admin checks, input checks, path checks, cooldown checks) where applicable. + + + * Timeouts/fallbacks: Timeout and fallback behavior are controlled by the calling flow and global handler/state machine conventions. + + + * Errors: Surfaces user-facing error replies and/or logs when inputs, permissions, or dependencies are invalid. + + + * System fit: This function is part of the Runewager command/callback/state orchestration pipeline. + + + */ + + +function adminTestsToolsKeyboard() { + return Markup.inlineKeyboard([ + [Markup.button.callback('๐Ÿงช Run TestAll', 'admin_cmd_testall'), Markup.button.callback('๐ŸŽ Test Giveaway', 'admin_cmd_testgiveaway')], + [Markup.button.callback('๐Ÿ› View Bug Reports', 'admin_cmd_viewbugs'), Markup.button.callback('๐Ÿ“ค Export Bugs', 'admin_cmd_exportbugs')], + [Markup.button.callback('โœ… Resolve Bug', 'admin_cmd_resolvebug_prompt'), Markup.button.callback('๐Ÿงช Test Content Drop', 'admin_cmd_tiptest')], + [Markup.button.callback('๐Ÿ“Ÿ Open SSHV Console', 'sshv_open')], + [Markup.button.callback('โฌ…๏ธ Admin Dashboard', 'open_admin_dashboard')], + ]); +} + +bot.action('admin_cat_tests', async (ctx) => { + if (!requireAdmin(ctx)) return; + await ctx.answerCbQuery(); + await replaceCallbackPanel(ctx, + `๐Ÿงช *Tests & Bug Tools* + +Use this menu for diagnostics, bug workflows, and test sends. + +โ€ข TestAll = full sanity check +โ€ข Test Giveaway = simulated giveaway flow +โ€ข Test Content Drop = sends one random drop to current target +โ€ข SSHV = VPS console tools`, + { parse_mode: 'Markdown', ...adminTestsToolsKeyboard() }, + ); +}); + + /** @@ -8288,6 +8365,26 @@ bot.action('menu_giveaways', async (ctx) => { await sendGiveawayListPage(ctx, 1); }); +/** + + * sendGiveawayListPage executes its scoped Runewager logic and participates in menu/command or utility flow composition. + + * Parameters: See the function signature for exact argument names and accepted values. + + * Returns: Returns the computed value or a Promise resolving to the operation result; may return void for side-effect handlers. + + * Side effects: May mutate runtime stores, pendingAction state, menu state, persistence files, logs, and callback progression. + + * Validation/safety: Uses existing guard utilities (admin checks, input checks, path checks, cooldown checks) where applicable. + + * Timeouts/fallbacks: Timeout and fallback behavior are controlled by the calling flow and global handler/state machine conventions. + + * Errors: Surfaces user-facing error replies and/or logs when inputs, permissions, or dependencies are invalid. + + * System fit: This function is part of the Runewager command/callback/state orchestration pipeline. + + */ + /** * sendGiveawayListPage executes its scoped Runewager logic and participates in menu/command or utility flow composition. @@ -9957,8 +10054,7 @@ bot.action('announce_send_all', async (ctx) => { await ctx.reply('Legacy "Send All" mapped to the new broadcast flow. Tap "Send Broadcast Now" after reviewing toggles.'); }); -// Legacy aliases -bot.action('announce_send_all', async (ctx) => { +bot.action('announce_send_channel', async (ctx) => { if (!requireAdmin(ctx)) return; const user = getUser(ctx); const action = user.pendingAction; @@ -9975,100 +10071,6 @@ bot.action('announce_send_all', async (ctx) => { // Content Drops System โ€” scheduler + admin commands + callbacks // ========================= -async function resolveTipTargetChatId(rawTarget) { - const t = String(rawTarget || '').trim(); - if (!t) return null; - if (/^-?\d+$/.test(t)) return Number(t); - if (t.startsWith('@')) return t; - return `@${t}`; -} - -async function postTipToConfiguredTarget(tip, telegram) { - const primaryTarget = await resolveTipTargetChatId(tipsStore.targetGroup || broadcastConfigStore.targetGroup); - const fallbackTarget = approvedGroupsStore.size ? Array.from(approvedGroupsStore)[0] : null; - const candidates = [primaryTarget, fallbackTarget].filter(Boolean); - let lastErr = null; - for (const target of candidates) { - try { - // eslint-disable-next-line no-await-in-loop - await telegram.sendMessage(target, formatTipForHtml(tip.text), { parse_mode: 'HTML', disable_notification: true }); - tipsStore.targetGroup = String(target); - broadcastConfigStore.targetGroup = String(target); - return { ok: true, target }; - } catch (e) { - lastErr = e; - } - } - return { ok: false, error: lastErr }; -} - -/** - - * resolveTipTargetChatId executes its scoped Runewager logic and participates in menu/command or utility flow composition. - - * Parameters: See the function signature for exact argument names and accepted values. - - * Returns: Returns the computed value or a Promise resolving to the operation result; may return void for side-effect handlers. - - * Side effects: May mutate runtime stores, pendingAction state, menu state, persistence files, logs, and callback progression. - - * Validation/safety: Uses existing guard utilities (admin checks, input checks, path checks, cooldown checks) where applicable. - - * Timeouts/fallbacks: Timeout and fallback behavior are controlled by the calling flow and global handler/state machine conventions. - - * Errors: Surfaces user-facing error replies and/or logs when inputs, permissions, or dependencies are invalid. - - * System fit: This function is part of the Runewager command/callback/state orchestration pipeline. - - */ - -async function resolveTipTargetChatId(rawTarget) { - const t = String(rawTarget || '').trim(); - if (!t) return null; - if (/^-?\d+$/.test(t)) return Number(t); - if (t.startsWith('@')) return t; - return `@${t}`; -} - -/** - - * postTipToConfiguredTarget executes its scoped Runewager logic and participates in menu/command or utility flow composition. - - * Parameters: See the function signature for exact argument names and accepted values. - - * Returns: Returns the computed value or a Promise resolving to the operation result; may return void for side-effect handlers. - - * Side effects: May mutate runtime stores, pendingAction state, menu state, persistence files, logs, and callback progression. - - * Validation/safety: Uses existing guard utilities (admin checks, input checks, path checks, cooldown checks) where applicable. - - * Timeouts/fallbacks: Timeout and fallback behavior are controlled by the calling flow and global handler/state machine conventions. - - * Errors: Surfaces user-facing error replies and/or logs when inputs, permissions, or dependencies are invalid. - - * System fit: This function is part of the Runewager command/callback/state orchestration pipeline. - - */ - -async function postTipToConfiguredTarget(tip, telegram) { - const primaryTarget = await resolveTipTargetChatId(tipsStore.targetGroup || broadcastConfigStore.targetGroup); - const fallbackTarget = approvedGroupsStore.size ? Array.from(approvedGroupsStore)[0] : null; - const candidates = [primaryTarget, fallbackTarget].filter(Boolean); - let lastErr = null; - for (const target of candidates) { - try { - // eslint-disable-next-line no-await-in-loop - await telegram.sendMessage(target, formatTipForHtml(tip.text), { parse_mode: 'HTML', disable_notification: true }); - tipsStore.targetGroup = String(target); - broadcastConfigStore.targetGroup = String(target); - return { ok: true, target }; - } catch (e) { - lastErr = e; - } - } - return { ok: false, error: lastErr }; -} - /** * resolveTipTargetChatId executes its scoped Runewager logic and participates in menu/command or utility flow composition. diff --git a/test/smoke.test.js b/test/smoke.test.js index a4cd131..6daa561 100644 --- a/test/smoke.test.js +++ b/test/smoke.test.js @@ -147,7 +147,7 @@ function parseRegexLiteral(source, slashIndex) { if (i >= source.length) return null; const patternSource = source.slice(slashIndex + 1, i); let j = i + 1; - while (j < source.length && /[a-z]/i.test(source[j])) j += 1; + while (j < source.length && /[dgimsuvy]/.test(source[j])) j += 1; const flags = source.slice(i + 1, j); return { patternSource, flags, end: j }; } @@ -286,8 +286,8 @@ function extractRegisteredCommands(source) { const idx = source.indexOf(marker); if (idx === -1) return null; - const setIdx = source.indexOf('new Set', idx); - const arrOpen = source.indexOf('[', setIdx); + // Allow formatting variants (new Set([...]) or plain array/object assignment) by scanning for the first array literal after the marker. + const arrOpen = source.indexOf('[', idx); if (arrOpen === -1) return null; let depth = 0;