tarunpoonia905/OfcDevShopBotPublic · Bot Template

ProfileTelegram

AIDEV SHOP appears to be a Telegram automation bot. Commands include /confirm_delete_stock, /addstock_id, /extkey_menu, /partner_api, /apidelete, /buy_hack_cat, /admin_manage_products, /check_buy. Observed in code: messaging, keyboards, payments, libs, web, http, games.

Utilityutility
228 commands0 envUpdated 12d agoCreated Oct 18, 2026
Back to folder

commands/_wz.js

javascript · 1328 lines

Raw
1/**#command2name: /wz3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12/*#SIZE_V1*/try{(function(){var z=Bot.getProperty("ui_btn_size");var mx=z==="large"?1:(z==="medium"?2:0);if(!mx||Api.__sz)return;var NAV=/^[◀▶⬅➡«»‹›⏪⏩]|\d+\s*\/\s*\d+|prev|next|page/i;var T=function(m){try{var o=typeof m==="string"?JSON.parse(m):m;if(!o||!o.inline_keyboard)return m;var out=[],cnt=0;o.inline_keyboard.forEach(function(row){var nav=row.some(function(b){return NAV.test(String(b.text||"").trim());});if(row.length<=mx||nav){out.push(row);cnt+=row.length;return;}for(var i=0;i<row.length;i+=mx){var c=row.slice(i,i+mx);out.push(c);cnt+=c.length;}});if(cnt>100||out.length>100)return m;o.inline_keyboard=out;return typeof m==="string"?JSON.stringify(o):o;}catch(e){return m;}};["sendMessage","editMessageText","editMessageCaption","editMessageReplyMarkup","sendPhoto","sendVideo","sendAnimation","sendDocument"].forEach(function(n){var f=Api[n];if(typeof f!=="function")return;Api[n]=function(p){try{if(p&&p.reply_markup)p.reply_markup=T(p.reply_markup);}catch(e){}return f.apply(Api,arguments);};});Api.__sz=true;})();}catch(__szE){}13/*#ANIM_V1*/try{(function(){var M={party:"5046509860389126442",fire:"5104841245755180586",heart:"5159385139981059251",like:"5107584321108051014"};var a=Bot.getProperty("ui_anim");if(!a||!M[a]||Api.__an)return;var E=M[a];var OK=/PURCHASE SUCCESSFUL|PAYMENT SUCCESSFUL|Payment verified|CONGRATULATIONS/i;var priv=function(p){return p&&p.chat_id&&String(p.chat_id).charAt(0)!=="-";};["sendMessage","sendPhoto","sendVideo","sendAnimation"].forEach(function(n){var f=Api[n];if(typeof f!=="function")return;Api[n]=function(p){try{if(priv(p)&&!p.message_effect_id&&OK.test(String(p.text||p.caption||"")))p.message_effect_id=E;}catch(e){}return f.apply(Api,arguments);};});var fe=Api.editMessageText;if(typeof fe==="function"){Api.editMessageText=function(p){var r=fe.apply(Api,arguments);try{if(priv(p)&&OK.test(String(p.text||"")))Api.sendMessage({chat_id:p.chat_id,text:"🎉",message_effect_id:E});}catch(e){}return r;};}Api.__an=true;})();}catch(__anE){}14/*#PREMIUM_UI_V1*/try{(function(){if(Bot.getProperty("ui_premium")!==true||Api.__pm)return;var R=function(t,c){var s=(String(t||"")+" "+String(c||"")).toLowerCase();if(/back|cancel|close|delete|remove|clear|reject|stop|ban|exit/.test(s))return"danger";if(/pay|buy|confirm|verify|paid|add|deposit|shop|claim|yes|receive|wallet|download|update/.test(s))return"success";return"primary";};var T=function(m){try{var o=typeof m==="string"?JSON.parse(m):m;if(!o||!o.inline_keyboard)return m;o.inline_keyboard.forEach(function(row){row.forEach(function(b){if(b.copy_text||b.url||b.callback_data||b.web_app){b.style=R(b.text,b.callback_data||b.url);if(!b.icon_custom_emoji_id&&b.text&&!/^[\u2600-\u27BF\uD83C-\uD83E]/.test(String(b.text).trim())&&!/^[✦✨💎]/.test(b.text))b.text="✦ "+b.text;}});});return typeof m==="string"?JSON.stringify(o):o;}catch(e){return m;}};["sendMessage","editMessageText","editMessageCaption","editMessageReplyMarkup","sendPhoto","sendVideo","sendAnimation","sendDocument"].forEach(function(n){var f=Api[n];if(typeof f!=="function")return;Api[n]=function(p){try{if(p&&p.reply_markup)p.reply_markup=T(p.reply_markup);}catch(e){}return f.apply(Api,arguments);};});Api.__pm=true;})();}catch(__pmE){}15 16 17// =========================================================================18// 🧭 ADMIN GUIDED WIZARD  —  "ek ek karke puchna" (no typed formats)19//20// Every admin button opens a flow:   /wz go <flow>21//   • choices are shown as BUTTONS (category / panel / plan / user type ...)22//   • values are asked ONE AT A TIME (panel name -> days -> PID -> price ...)23//   • a summary + Confirm button is shown before anything is saved24//25// Text answers arrive through the wildcard command (_.js), which forwards them26// here with options.wz_text = true while a wizard is active.27// Wizard state lives in the User property "wz_state" (auto-expires).28// Everything is saved in the SAME properties the old typed commands used.29// =========================================================================30 31try {32  var ownerId = String(Bot.getProperty("owner_id") || "7127818616");33  var me = String(chat.chatid);34  var isCo = !!Bot.getProperty("co_admin_" + me);35  var isOwner = (me === ownerId);36  if (!isOwner && !isCo) { Bot.sendMessage("❌ Restricted command!"); return; }37 38  var opt = (typeof options !== "undefined" && options) ? options : {};39  var isText = !!opt.wz_text;40  var rawText = "";41  if (isText) {42    rawText = String(opt.text || ((typeof message !== "undefined" && message) ? message : "")).trim();43  }44  var cmd = (!isText && typeof params !== "undefined" && params) ? String(params).trim() : "";45  var cmdParts = cmd.split(/\s+/);46  var verb = (cmdParts[0] || "").toLowerCase();47  var arg = cmdParts.slice(1).join(" ").trim();48 49  // ---------------------------------------------------------------- helpers50  var qid = (!isText && request) ? (request.id || (request.callback_query && request.callback_query.id)) : null;51  var mid = null;52  if (!isText && request) {53    mid = (request.message && request.message.message_id) ||54          (request.callback_query && request.callback_query.message && request.callback_query.message.message_id) || null;55  }56  if (qid) { try { Api.answerCallbackQuery({ callback_query_id: String(qid) }); } catch (e) {} }57 58  function esc(s) { return String(s === undefined || s === null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); }59  function short(s, n) { s = String(s || ""); return s.length > n ? s.slice(0, n - 1) + "…" : s; }60 61  function show(text, rows) {62    var kb = JSON.stringify({ inline_keyboard: rows || [] });63    if (mid && !isText) {64      try {65        Api.editMessageText({ chat_id: me, message_id: Number(mid), text: text, parse_mode: "HTML", reply_markup: kb });66        return;67      } catch (e) {}68    }69    Api.sendMessage({ chat_id: me, text: text, parse_mode: "HTML", reply_markup: kb });70  }71 72  var NAV_CANCEL = { text: "❌ Cancel", callback_data: "/wz cancel", style: "danger" };73  var NAV_BACK = { text: "⬅️ Back", callback_data: "/wz back", style: "danger" };74  var BACK_ADMIN = [{ text: "🔙 Back to Admin", callback_data: "/admin", style: "danger" }];75 76  function prods() {77    var p = Bot.getProperty("stored_products");78    if (typeof p === "string") { try { p = JSON.parse(p); } catch (e) { p = []; } }79    return Array.isArray(p) ? p : [];80  }81  // ---- Multi website (api_registry) helpers82  function sitesReg() {83    var r = Bot.getProperty("api_registry");84    if (typeof r === "string") { try { r = JSON.parse(r); } catch (e) { r = {}; } }85    return (r && typeof r === "object") ? r : {};86  }87  function siteIds() { return Object.keys(sitesReg()); }88  function siteName(id) { var x = sitesReg()[id]; return x ? String(x.name || id) : String(id); }89  function hostOf(u) { return String(u || "").replace(/^https?:\/\//i, "").split("/")[0]; }90  function maskKey(k) {91    k = String(k || "");92    if (!k) return "Not set";93    if (k.length <= 8) return k.slice(0, 2) + "****";94    return k.slice(0, 4) + "••••" + k.slice(-4);95  }96  function idCats() {97    var c = Bot.getProperty("ff_categories");98    return (c && typeof c === "object") ? c : {};99  }100  function planLabel(pl) {101    var base = pl.durationDisplay || pl.name_on_website || (String(pl.days) + " " + (pl.unit || "day"));102    return String(base);103  }104  function planValueUnit(pl) {105    return { value: String(pl.days === undefined ? "" : pl.days).replace(/[^0-9.]/g, ""), unit: pl.unit || "day" };106  }107 108  // duration label -> {value, unit}  (same rules as the old /addplan)109  function parseDuration(durationText) {110    var lower = durationText.toLowerCase();111    var durMatch = lower.match(/^([0-9]+(?:\.[0-9]+)?)\s*(d|day|days|h|hr|hrs|hour|hours|m|min|mins|minute|minutes)(?:\s+(.+))?$/);112    var numericOnly = durationText.match(/^([0-9]+(?:\.[0-9]+)?)/);113    var value = durMatch ? durMatch[1] : (numericOnly ? numericOnly[1] : "0");114    var unitRaw = durMatch ? durMatch[2] : "d";115    var unit = "day";116    if (/^h/.test(unitRaw)) unit = "hour";117    else if (/^m/.test(unitRaw)) unit = "minute";118    return { value: String(value), unit: unit };119  }120 121  // ------------------------------------------------------------- validators122  function vName(s) {123    s = s.replace(/\s+/g, " ").trim();124    if (!s) return { err: "Naam khaali nahi ho sakta." };125    if (s.length > 60) return { err: "Naam 60 characters se chhota rakhein." };126    if (s.indexOf("|") !== -1) return { err: "Naam mein | ka use na karein." };127    return { val: s };128  }129  function vEmoji(s) {130    s = s.replace(/\s+/g, "");131    if (!/^\d{5,30}$/.test(s)) return { err: "Emoji ID sirf numbers ka hota hai (jaise 5226656353744862682). Ya Skip dabayein." };132    return { val: s };133  }134  function vDur(s) {135    s = s.replace(/\s+/g, " ").trim();136    if (!s) return { err: "Duration khaali nahi ho sakta." };137    if (s.length > 40 || s.indexOf("|") !== -1) return { err: "Duration chhota rakhein (max 40 characters, | nahi)." };138    // 7 / 7d / 7 day  -> "7 Days" ; 1h -> "1 Hour" ; 30m -> "30 Minutes"139    // (the buy flow maps "N Days" to the correct API name per product; custom labels stay as typed)140    var m = s.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(d|day|days|h|hr|hrs|hour|hours|m|min|mins|minute|minutes)?$/);141    if (m) {142      var n = m[1], u = m[2] || "d", one = Number(n) === 1;143      if (Number(n) <= 0) return { err: "Duration 0 se zyada hona chahiye." };144      if (/^d/.test(u)) return { val: n + (one ? " Day" : " Days") };145      if (/^h/.test(u)) return { val: n + (one ? " Hour" : " Hours") };146      return { val: n + (one ? " Minute" : " Minutes") };147    }148    return { val: s };149  }150  function vPid(s) {151    s = s.trim();152    if (!/^[A-Za-z0-9_\-]{1,40}$/.test(s)) return { err: "PID mein sirf letters/numbers/_/- hone chahiye." };153    return { val: s };154  }155  function vPrice(s) {156    var n = parseFloat(String(s).replace(/[₹,\s]/g, ""));157    if (isNaN(n) || n <= 0 || n > 10000000) return { err: "Valid price bhejein (number, 0 se zyada)." };158    return { val: n };159  }160  function vPrice0(s) {161    var n = parseFloat(String(s).replace(/[₹,\s]/g, ""));162    if (isNaN(n) || n < 0 || n > 10000000) return { err: "Valid price bhejein (number)." };163    return { val: n };164  }165  function vUser(s) {166    s = s.replace(/\s+/g, "");167    if (!/^\d{5,15}$/.test(s)) return { err: "User ID sirf numbers (5-15 digits) ka hona chahiye." };168    return { val: s };169  }170  function vPct(s) {171    var n = parseFloat(String(s).replace(/%/g, ""));172    if (isNaN(n) || n <= 0 || n > 100) return { err: "Percent 1 se 100 ke beech bhejein." };173    return { val: n };174  }175  function vUrl(s) {176    s = s.trim().replace(/\/+$/, "");177    if (!/^https?:\/\/.+/i.test(s)) return { err: "Valid URL bhejein, http:// ya https:// se shuru honi chahiye." };178    return { val: s };179  }180  function vApiKey(s) {181    s = s.trim();182    if (s.length < 6) return { err: "Valid API key bhejein." };183    return { val: s };184  }185  function vPrompt(s) {186    s = s.trim();187    if (s.length < 10 || s.length > 2000) return { err: "Prompt 10-2000 characters ke beech hona chahiye." };188    return { val: s };189  }190  function vLines(s) {191    var arr = s.split("\n").map(function (x) { return x.trim(); }).filter(Boolean);192    if (!arr.length) return { err: "Kam se kam ek line bhejein." };193    return { val: arr };194  }195  function vAccounts(s) {196    var arr = s.split("\n").map(function (x) { return x.trim(); }).filter(function (x) { return x && x.indexOf("|") !== -1; });197    if (!arr.length) return { err: "Har line is format mein ho: email|password" };198    return { val: arr };199  }200  function cleanUser(v) {201    return String(v || "").trim().replace(/^https?:\/\/(www\.)?t\.me\//i, "").replace(/^t\.me\//i, "").replace(/^@/, "").split(/[?\/\s]/)[0];202  }203  function vBotUser(s) {204    var u = cleanUser(s);205    if (!/^[A-Za-z][A-Za-z0-9_]{1,28}bot$/i.test(u)) return { err: "Bot username 5-32 characters ka ho, letters/numbers/_ aur 'bot' par khatam (jaise MyShopBot)." };206    return { val: u };207  }208  function vAdminUser(s) {209    var u = cleanUser(s);210    if (!/^[A-Za-z][A-Za-z0-9_]{4,31}$/.test(u)) return { err: "Username 5-32 characters ka ho, sirf letters/numbers/_ (jaise YourName)." };211    return { val: u };212  }213 214  // ------------------------------------------------------------ step makers215  var CAT_LABELS = { root: "ANDROID ROOT", nonroot: "ANDROID NON ROOT", iphone: "iPHONE", both: "BOTH" };216  var DEFAULT_EMOJI = "5226656353744862682";217  var DEFAULT_ID_EMOJI = "5323261730283863478";218 219  function T(k, q, v, x) { return { k: k, t: "text", q: q, v: v, x: x || {} }; }220  var S_CAT = { k: "cat", t: "cat", q: "📂 <b>Category chuniye:</b>" };221  var S_PROD = { k: "pi", t: "prod", q: "📦 <b>Panel / Product chuniye:</b>" };222  var S_PLAN = { k: "li", t: "plan", q: "⏱ <b>Plan chuniye:</b>" };223  var S_IDCAT = { k: "slug", t: "idcat", q: "📁 <b>ID Category chuniye:</b>" };224  var S_NAME = T("pn", "📦 <b>Panel ka naam bhejein</b>\n<i>Jaise: MST PANEL, DRIP CLIENT</i>", vName);225  var S_EMOJI = T("emoji", "💎 <b>Premium Emoji ID bhejein</b> (optional)\n<i>Nahi hai to Skip dabayein.</i>", vEmoji, { skip: { l: "⏭ Skip (default emoji)", v: "" } });226  var S_DUR = T("dur", "⏳ <b>Kitne din / kitna time?</b>\n<i>Button dabayein ya likhein: <code>7d</code>, <code>1h</code>, <code>30m</code> ya exact API naam. Sirf number likhoge to Days maana jayega.</i>\n\n<b>Examples:</b> <code>3 Hours</code>, <code>1 Day</code>, <code>7 Days</code>.\n<i>Aapke shop ki displayed validity hamesha ⏳ hi rahegi — ye sirf API ke liye hai.</i>\n\nAgar API wahi duration naam use karta hai, to wahi exact value bhejein. Website se copy karke laate ho to usko bhi last mein isi tarah lagana padta hai.", vDur,227    { quick: [["1 Day", "1d"], ["3 Days", "3d"], ["7 Days", "7d"], ["15 Days", "15d"], ["30 Days", "30d"], ["1 Hour", "1h"]] });228  var S_PID = T("pid", "🆔 <b>Is plan ka PID bhejein</b>\n<i>API wale product ki ID. Agar sirf manual keys se chalana hai to niche wala button dabayein.</i>", vPid, { skip: { l: "🔑 Manual keys (no PID)", v: "0" } });229  var S_PRICE = T("price", "💰 <b>Price kitna hoga?</b> (₹, number)", vPrice);230  var S_RPRICE = T("rprice", "👑 <b>Reseller price kitna hoga?</b> (₹, number)", vPrice0, { skipSame: true });231  var S_PRODCAT = { k: "pi", t: "prodcat", q: "📦 <b>Panel chuniye</b> (is category ke andar jo panels hain):" };232  var S_UNIT = { k: "unit", t: "unit", q: function (st) {233    var pr = prods()[st.d.pi]; var lines = [];234    var pls = pr && pr.plans ? pr.plans : [];235    for (var i = 0; i < pls.length; i++) lines.push("• " + esc(planLabel(pls[i])) + " — ₹" + pls[i].normal_price);236    return "⏱ <b>Kitne Hours ya Days ka key add karna hai?</b>\n" +237           (lines.length ? "\n<b>Abhi ye add hain:</b>\n" + lines.join("\n") + "\n" : "") + "\n<i>Pehle Hours ya Days chuniye, phir number likhna hai.</i>";238  } };239  var S_NUM = T("num", "🔢 <b>Kitne?</b>\n<i>Sirf number likhein. Jaise 12 ya 3</i>", function (s) {240    var m = String(s).trim().toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(h|hr|hrs|hour|hours|d|day|days)?$/);241    var n = m ? parseFloat(m[1]) : NaN;242    if (isNaN(n) || n <= 0 || n > 9999) return { err: "Valid number bhejein (0 se zyada), jaise 12." };243    return { val: String(n) };244  });245  var S_PRICE_PUB = T("price", "💰 <b>Price kitna?</b>\n<i>Ye public/normal users ko dikhega (₹)</i>", vPrice);246  var S_RPRICE_Q = T("rprice", "👑 <b>Reseller price kitna?</b>\n<i>Ye resellers ko dikhega (₹)</i>", vPrice0);247  var S_PID_REQ = T("pid", "🆔 <b>PID bhejein</b>\n<i>Website wali product ID, jisse key apne aap generate hoti hai.</i>", vPid);248  var S_USER = T("uid", "👤 <b>User ID bhejein</b>\n<i>Sirf number, jaise <code>123456789</code></i>", vUser);249  var S_AMT = T("amt", "💵 <b>Amount kitna?</b> (₹, number)", vPrice);250 251  // --------------------------------------------------------------- savers252  function saveProductAndPlan(d) {253    var list = prods();254    var pName = d.pn;255    var idx = -1;256    for (var i = 0; i < list.length; i++) {257      if (list[i] && list[i].name && list[i].name.trim().toLowerCase() === pName.toLowerCase()) { idx = i; break; }258    }259    var isNewProduct = idx === -1;260    if (isNewProduct) {261      list.push({ name: pName, emoji: d.emoji || DEFAULT_EMOJI, category: d.cat || "both", plans: [] });262      idx = list.length - 1;263    } else if (d.cat) {264      // Add Product on an existing panel = update emoji/category, keep plans.265      list[idx].category = d.cat;266      if (d.emoji) list[idx].emoji = d.emoji;267      delete list[idx].id;268    }269    if (!Array.isArray(list[idx].plans)) list[idx].plans = [];270 271    var durationText = d.dur;272    var pd = parseDuration(durationText);273    var pDays = pd.value, pUnit = pd.unit;274    var cleanProdName = pName.toUpperCase();275    var suffix = (pUnit === "day") ? pDays : (pDays + "_" + pUnit);276    Bot.setProperty("price_normal_" + cleanProdName + "_" + suffix, d.price, "number");277    Bot.setProperty("price_reseller_" + cleanProdName + "_" + suffix, d.rprice, "number");278 279    var plan = {280      days: pDays, unit: pUnit, durationDisplay: durationText,281      normal_price: d.price, reseller_price: d.rprice,282      name_on_website: durationText, api_duration: durationText,283      pid: d.pid, product_id: d.pid, variant_id: d.pid284    };285    var updated = false;286    for (var p = 0; p < list[idx].plans.length; p++) {287      var pl = list[idx].plans[p];288      if (String(pl.days) === pDays && (pl.unit || "day") === pUnit) { list[idx].plans[p] = plan; updated = true; break; }289    }290    if (!updated) list[idx].plans.push(plan);291    Bot.setProperty("stored_products", list, "json");292    return { idx: idx, isNewProduct: isNewProduct, planUpdated: updated };293  }294 295  function setPlanPrices(pi, li, which, price) {296    var list = prods();297    if (!list[pi] || !list[pi].plans || !list[pi].plans[li]) return false;298    var pl = list[pi].plans[li];299    var vu = planValueUnit(pl);300    var suffix = (vu.unit === "day") ? vu.value : (vu.value + "_" + vu.unit);301    var key = (which === "n" ? "price_normal_" : "price_reseller_") + String(list[pi].name).trim().toUpperCase() + "_" + suffix;302    Bot.setProperty(key, price, "number");303    if (which === "n") pl.normal_price = price; else pl.reseller_price = price;304    Bot.setProperty("stored_products", list, "json");305    return true;306  }307 308  // -------------------------------------------------------------- flow table309  function durLabel(d) {310    if (d.dur) return d.dur;311    if (d.num && d.unit) {312      var one = Number(d.num) === 1;313      return d.num + (d.unit === "h" ? (one ? " Hour" : " Hours") : (one ? " Day" : " Days"));314    }315    return "";316  }317 318  function recap(d) {319    var L = [];320    if (d.cat) L.push("📂 Category: <b>" + esc(CAT_LABELS[d.cat] || d.cat) + "</b>");321    if (d.pn) L.push("📦 Panel: <b>" + esc(d.pn) + "</b>");322    if (d.pl) L.push("⏱ Plan: <b>" + esc(d.pl) + "</b>");323    if (d.catName) L.push("📁 ID Category: <b>" + esc(d.catName) + "</b>");324    if (d.emoji) L.push("💎 Emoji: <code>" + esc(d.emoji) + "</code>");325    if (durLabel(d)) L.push("⏳ Duration: <b>" + esc(durLabel(d)) + "</b>");326    if (d.swn) L.push("🌐 Website: <b>" + esc(d.swn) + "</b>");327    if (d.pid) L.push("🆔 PID: <code>" + esc(d.pid) + "</code>");328    if (d.price !== undefined) L.push("💰 Price: <b>₹" + d.price + "</b>");329    if (d.rprice !== undefined) L.push("👑 Reseller: <b>₹" + d.rprice + "</b>");330    if (d.uid) L.push("👤 User ID: <code>" + esc(d.uid) + "</code>");331    if (d.amt !== undefined) L.push("💵 Amount: <b>₹" + d.amt + "</b>");332    return L.join("\n");333  }334 335  function planSummary(d) {336    return recap(d);337  }338 339  var F = {};340 341  F.add_product = {342    title: "➕ ADD PRODUCT",343    steps: [S_CAT, S_NAME, S_EMOJI, S_DUR, S_PID, S_PRICE, S_RPRICE],344    sum: planSummary,345    run: function (d) {346      var r = saveProductAndPlan(d);347      return {348        text: "<blockquote>✅ <b>" + (r.isNewProduct ? "Product Add Ho Gaya!" : "Product Update Ho Gaya!") + "</b></blockquote>\n\n" + recap(d) +349              "\n\n<i>" + (r.planUpdated ? "Ye plan pehle se tha, update kar diya." : "Plan bhi add ho gaya. Ab ye store mein dikhega.") + "</i>",350        rows: [351          [{ text: "➕ Isi Panel mein aur Plan", callback_data: "/wz more " + r.idx, style: "success" }],352          [{ text: "🔑 Keys Add Karein", callback_data: "/wz go add_key", style: "primary" }],353          [{ text: "➕ Naya Product", callback_data: "/wz go add_product", style: "success" }]354        ]355      };356    }357  };358 359  F.add_plan = {360    title: "📋 ADD PLAN",361    steps: [S_PROD, S_DUR, S_PID, S_PRICE, S_RPRICE],362    sum: planSummary,363    run: function (d) {364      var r = saveProductAndPlan(d);365      return {366        text: "<blockquote>✅ <b>" + (r.planUpdated ? "Plan Update Ho Gaya!" : "Plan Add Ho Gaya!") + "</b></blockquote>\n\n" + recap(d),367        rows: [368          [{ text: "➕ Isi Panel mein aur Plan", callback_data: "/wz more " + r.idx, style: "success" }],369          [{ text: "🔑 Keys Add Karein", callback_data: "/wz go add_key", style: "primary" }]370        ]371      };372    }373  };374 375  F.quick_add = {376    title: "⚡ QUICK ADD API KEY",377    steps: [S_CAT, S_PRODCAT, S_UNIT, S_NUM, S_PRICE_PUB, S_RPRICE_Q, S_PID_REQ],378    sum: function (d) {379      var txt = recap(d);380      var pr = prods()[d.pi], pd = parseDuration(durLabel(d));381      var pls = pr && pr.plans ? pr.plans : [];382      for (var i = 0; i < pls.length; i++) {383        if (String(pls[i].days) === pd.value && (pls[i].unit || "day") === pd.unit) {384          txt += "\n\n⚠️ <i>Ye time pehle se hai (₹" + pls[i].normal_price + "). Confirm karne par update ho jayega.</i>";385          break;386        }387      }388      return txt;389    },390    run: function (d) {391      d.dur = durLabel(d);392      var r = saveProductAndPlan({ pn: d.pn, dur: d.dur, pid: d.pid, price: d.price, rprice: d.rprice });393      return {394        text: "<blockquote>✅ <b>" + (r.planUpdated ? "Update Ho Gaya!" : "Add Ho Gaya!") + "</b></blockquote>\n\n" + recap(d),395        rows: [396          [{ text: "⚡ Isi Panel mein aur Add", callback_data: "/wz qmore " + r.idx, style: "success" }],397          [{ text: "⚡ Dusra Panel / Category", callback_data: "/wz go quick_add", style: "primary" }]398        ]399      };400    }401  };402 403  F.rem_plan = {404    title: "🗑 REMOVE PLAN",405    own: true,406    steps: [S_PROD, S_PLAN],407    sum: function (d) { return recap(d) + "\n\n⚠️ <i>Ye plan delete ho jayega. Agar ye aakhri plan hai to poora panel bhi hat jayega.</i>"; },408    run: function (d) {409      var list = prods();410      var p = list[d.pi];411      if (!p || !p.plans || !p.plans[d.li]) return { text: "❌ Plan nahi mila (shayad pehle hi hat chuka hai)." };412      p.plans.splice(d.li, 1);413      var msg;414      if (p.plans.length === 0) { list.splice(d.pi, 1); msg = "🗑 <b>" + esc(d.pn) + "</b> ka aakhri plan tha, isliye poora panel bhi remove ho gaya."; }415      else { msg = "✅ <b>" + esc(d.pn) + "</b> se <b>" + esc(d.pl) + "</b> plan remove ho gaya."; }416      Bot.setProperty("stored_products", list, "json");417      return { text: msg };418    }419  };420 421  F.add_key = {422    title: "🔑 ADD KEYS",423    steps: [S_PROD, S_PLAN, T("keys", "🔑 <b>Keys bhejein</b>\n<i>Ek line mein ek key. Kai keys ek saath paste kar sakte hain.</i>", vLines)],424    noconfirm: true,425    run: function (d) {426      var list = prods();427      var product = list[d.pi];428      var plan = product && product.plans ? product.plans[d.li] : null;429      if (!product || !plan) return { text: "❌ Plan nahi mila." };430      var vu = planValueUnit(plan);431      var value = vu.value, unit = vu.unit;432      var cleanName = product.name.trim().toUpperCase();433      var stockKey = "manual_keys_" + cleanName + "_" + value + "_" + unit;434      var stock = Bot.getProperty(stockKey) || [];435      if (typeof stock === "string") {436        try { stock = JSON.parse(stock); } catch (e) { stock = stock.split("\n").map(function (x) { return x.trim(); }).filter(Boolean); }437      }438      if (!Array.isArray(stock)) stock = [];439      // v63: unlimited keys — O(n) dedupe (object map), koi count limit nahi440      var seenK = {};441      for (var sq = 0; sq < stock.length; sq++) seenK[String(stock[sq])] = true;442      var added = 0;443      for (var q = 0; q < d.keys.length; q++) {444        var kk = String(d.keys[q]);445        if (!seenK[kk]) { seenK[kk] = true; stock.push(d.keys[q]); added++; }446      }447      Bot.setProperty(stockKey, stock, "json");448      if (unit === "day") {449        Bot.setProperty("manual_keys_" + cleanName + "_" + value, stock, "json");450        Bot.setProperty("stock_" + product.name.trim() + "_" + value + "_Day", stock, "json");451        Bot.setProperty("stock_" + d.pi + "_" + d.li, stock, "json");452      }453      return {454        text: "<blockquote><b>✅ KEYS ADD HO GAYI</b></blockquote>\n\n📦 Panel: <b>" + esc(product.name) + "</b>\n⏱ Plan: <b>" + esc(d.pl) + "</b>\n🔑 Nayi keys: <b>" + added +455              "</b>" + (added < d.keys.length ? " <i>(" + (d.keys.length - added) + " duplicate skip)</i>" : "") + "\n📦 Total stock: <b>" + stock.length + "</b>",456        rows: [[{ text: "🔑 Aur Keys Add Karein", callback_data: "/wz go add_key", style: "success" }]]457      };458    }459  };460 461  F.rem_key = {462    title: "🗑 REMOVE KEY",463    own: true,464    steps: [S_PROD, S_PLAN],465    noconfirm: true,466    run: function (d) {467      var list = prods();468      var product = list[d.pi];469      var plan = product && product.plans ? product.plans[d.li] : null;470      if (!product || !plan) return { text: "❌ Plan nahi mila." };471      var vu = planValueUnit(plan);472      if (vu.unit !== "day") return { text: "ℹ️ Key remove abhi sirf <b>Day</b> plans ke liye available hai." };473      var cleanPlanDays = vu.value + "_Day";474      var keyStock = Bot.getProperty("stock_" + product.name.trim() + "_" + cleanPlanDays) || [];475      if (!Array.isArray(keyStock) || keyStock.length === 0) return { text: "❌ <b>" + esc(product.name) + " (" + esc(cleanPlanDays) + ")</b> ka stock khaali hai!" };476      var rows = [];477      for (var i = 0; i < keyStock.length && i < 90; i++) {478        var fk = String(keyStock[i]);479        var sk = fk.length > 15 ? fk.substring(0, 12) + "..." : fk;480        rows.push([{ text: "🗑️ Key " + (i + 1) + " [" + sk + "]", callback_data: "/deletekey_now " + i + "|" + product.name.trim() + "|" + cleanPlanDays }]);481      }482      return {483        text: "<blockquote><b>🗑️ REMOVE KEY CHUNIYE</b>\n\n• Panel: <code>" + esc(product.name) + "</code>\n• Plan: <code>" + esc(cleanPlanDays) + "</code>\n• Total Keys: <code>" + keyStock.length + "</code></blockquote>",484        rows: rows485      };486    }487  };488 489  // ----- FF ID categories490  F.id_add_cat = {491    title: "📁 ADD ID CATEGORY",492    own: true,493    steps: [T("catName", "📁 <b>Category ka naam bhejein</b>\n<i>Jaise: Facebook Id</i>", vName),494            T("emoji", "💎 <b>Emoji ID bhejein</b> (optional)", vEmoji, { skip: { l: "⏭ Skip (default emoji)", v: "" } })],495    sum: function (d) { return recap(d); },496    run: function (d) {497      var slug = d.catName.toLowerCase().replace(/[^a-z0-9]/g, "");498      if (!slug) return { text: "❌ Naam mein kam se kam ek letter/number hona chahiye." };499      var cats = idCats();500      if (cats[slug]) return { text: "⚠️ <b>" + esc(cats[slug].name) + "</b> category pehle se hai. Naya naam chuniye." };501      var em = d.emoji || DEFAULT_ID_EMOJI;502      cats[slug] = { name: d.catName, emoji_id: em, normal_price: 0, reseller_price: 0 };503      Bot.setProperty("ff_categories", cats, "json");504      Bot.setProperty("ff_stock_" + slug, [], "json");505      return {506        text: "✅ <b>ID Category Add Ho Gayi!</b>\n\n• Icon: <tg-emoji emoji-id='" + esc(em) + "'>✨</tg-emoji>\n• Naam: <code>" + esc(d.catName) + "</code>\n\n<i>Ab price set karein aur stock add karein.</i>",507        rows: [[{ text: "💰 Set Normal Price", callback_data: "/wz go id_price_n", style: "primary" }, { text: "➕ Add Stock", callback_data: "/wz go id_add_stock", style: "success" }]]508      };509    }510  };511 512  F.id_rem_cat = {513    title: "🗑 REMOVE ID CATEGORY",514    own: true,515    steps: [S_IDCAT],516    sum: function (d) { return recap(d) + "\n\n⚠️ <i>Category aur uska poora stock delete ho jayega.</i>"; },517    run: function (d) {518      var cats = idCats();519      if (!cats[d.slug]) return { text: "❌ Category nahi mili." };520      var nm = cats[d.slug].name;521      delete cats[d.slug];522      Bot.setProperty("ff_categories", cats, "json");523      Bot.setProperty("ff_stock_" + d.slug, null);524      return { text: "🗑 <b>Category delete ho gayi:</b> <code>" + esc(nm) + "</code>" };525    }526  };527 528  F.id_add_stock = {529    title: "📥 ADD ID STOCK",530    own: true,531    steps: [S_IDCAT, T("accts", "📥 <b>Accounts bhejein</b>\n<i>Har line: <code>email|password</code>. Kai accounts ek saath paste kar sakte hain.</i>", vAccounts)],532    noconfirm: true,533    run: function (d) {534      var cats = idCats();535      if (!cats[d.slug]) return { text: "❌ Category nahi mili." };536      var cur = Bot.getProperty("ff_stock_" + d.slug) || [];537      if (!Array.isArray(cur)) cur = [];538      for (var i = 0; i < d.accts.length; i++) cur.push(d.accts[i]);539      Bot.setProperty("ff_stock_" + d.slug, cur, "json");540      return {541        text: "⚡ <b>Stock Add Ho Gaya!</b>\n\n• <code>" + d.accts.length + " accounts</code> ➔ <b>" + esc(cats[d.slug].name) + "</b>\n• Total stock: <b>" + cur.length + "</b>",542        rows: [[{ text: "📥 Aur Stock Add Karein", callback_data: "/wz go id_add_stock", style: "success" }]]543      };544    }545  };546 547  function idPriceFlow(which) {548    return {549      title: which === "n" ? "💰 ID NORMAL PRICE" : "👑 ID RESELLER PRICE",550      own: true,551      steps: [S_IDCAT, T("price", which === "n" ? "💰 <b>Normal price kitna?</b> (₹)" : "👑 <b>Reseller price kitna?</b> (₹)", vPrice)],552      sum: function (d) { return recap(d); },553      run: function (d) {554        var cats = idCats();555        if (!cats[d.slug]) return { text: "❌ Category nahi mili." };556        if (which === "n") cats[d.slug].normal_price = d.price; else cats[d.slug].reseller_price = d.price;557        Bot.setProperty("ff_categories", cats, "json");558        return { text: "✅ <b>" + (which === "n" ? "Normal" : "Reseller") + " Price Update!</b>\n\n• Category: <code>" + esc(cats[d.slug].name) + "</code>\n• Naya price: <code>₹" + d.price + "</code>" };559      }560    };561  }562  F.id_price_n = idPriceFlow("n");563  F.id_price_r = idPriceFlow("r");564 565  // ----- all-product prices566  function allPriceFlow(which) {567    return {568      title: which === "n" ? "💰 NORMAL PRICE (PANEL PLAN)" : "👑 RESELLER PRICE (PANEL PLAN)",569      own: true,570      steps: [S_PROD, S_PLAN, T("price", which === "n" ? "💰 <b>Naya normal price kitna?</b> (₹)" : "👑 <b>Naya reseller price kitna?</b> (₹)", vPrice)],571      sum: function (d) { return recap(d); },572      run: function (d) {573        if (!setPlanPrices(d.pi, d.li, which, d.price)) return { text: "❌ Plan nahi mila." };574        return { text: "✅ <b>" + (which === "n" ? "Normal" : "Reseller") + " Price Update Ho Gaya!</b>\n\n" + recap(d) };575      }576    };577  }578  F.all_price_n = allPriceFlow("n");579  F.all_price_r = allPriceFlow("r");580 581  // ----- balances582  F.bal_add = {583    title: "➕ ADD BALANCE",584    steps: [S_USER, S_AMT],585    sum: function (d) { return recap(d); },586    run: function (d) {587      var credited = false;588      try { Libs.ResourcesLib.anotherUserRes("balance", d.uid).add(d.amt); credited = true; } catch (e1) {}589      if (!credited) {590        // Fallback store (same one /menu adds on top). Only used if the wallet resource failed,591        // so the amount is never credited twice.592        var prev = Number(Bot.getProperty("balance" + d.uid) || 0);593        Bot.setProperty("balance" + d.uid, (prev + d.amt).toFixed(2), "string");594      }595      try {596        Api.sendMessage({597          chat_id: d.uid, parse_mode: "HTML",598          text: "<blockquote><tg-emoji emoji-id='6192822213486321961'>🗣</tg-emoji> Admin Added: " + d.amt + "\n" +599                "<tg-emoji emoji-id='6266967801580231067'>💎</tg-emoji> Balance Credited!\n" +600                "<tg-emoji emoji-id='6267068789146260253'>💰</tg-emoji> Wallet Updated\n" +601                "<tg-emoji emoji-id='5866053971960929280'>🛒</tg-emoji> /start TO SHOP NOW</blockquote>"602        });603      } catch (e2) {}604      return { text: "✅ <b>Balance Add Ho Gaya!</b>\n\n👤 User: <code>" + esc(d.uid) + "</code>\n💵 Added: <b>₹" + d.amt + "</b>",605               rows: [[{ text: "➕ Aur Balance Add", callback_data: "/wz go bal_add", style: "success" }]] };606    }607  };608 609  F.bal_rem = {610    title: "➖ REMOVE BALANCE",611    steps: [S_USER, S_AMT],612    sum: function (d) { return recap(d); },613    run: function (d) {614      var wallet = Libs.ResourcesLib.anotherUserRes("balance", d.uid);615      var cur = Number(wallet.value()) || 0;616      var legacy = Number(Bot.getProperty("balance" + d.uid) || 0);617      var total = cur + legacy;618      if (d.amt > total) {619        return { text: "❌ <b>Insufficient Balance</b>\n\nMember balance: <code>₹" + total.toFixed(2) + "</code>\nRemove requested: <code>₹" + d.amt.toFixed(2) + "</code>" };620      }621      var fromRes = Math.min(cur, d.amt);622      if (fromRes > 0) wallet.remove(fromRes);623      var rem = d.amt - fromRes;624      if (rem > 0) Bot.setProperty("balance" + d.uid, Math.max(0, legacy - rem), "float");625      var after = (total - d.amt).toFixed(2);626      try {627        Api.sendMessage({ chat_id: d.uid, parse_mode: "HTML",628          text: "<blockquote><b>💳 BALANCE UPDATED</b>\n\n• Removed by Admin: <code>₹" + d.amt.toFixed(2) + "</code>\n• Remaining Balance: <code>₹" + after + "</code>\n\nUse /balance to check your wallet.</blockquote>" });629      } catch (e) {}630      return { text: "✅ <b>Balance Remove Ho Gaya</b>\n\nMember: <code>" + esc(d.uid) + "</code>\nRemoved: <code>₹" + d.amt.toFixed(2) + "</code>\nRemaining: <code>₹" + after + "</code>" };631    }632  };633 634  // ----- reseller / role635  F.reseller_add = {636    title: "👑 ADD RESELLER",637    steps: [S_USER],638    sum: function (d) { return recap(d) + "\n\n<i>User turant Reseller ban jayega (payment nahi lagegi).</i>"; },639    run: function (d) {640      if (Bot.getProperty("is_reseller_" + d.uid) === true) return { text: "🔰 Ye user (<code>" + esc(d.uid) + "</code>) <b>pehle se Reseller hai!</b>" };641      Bot.setProperty("is_reseller_" + d.uid, true, "boolean");642      try {643        Api.sendMessage({ chat_id: d.uid, parse_mode: "HTML",644          text: "<blockquote><b><tg-emoji emoji-id='6064138396228392033'>✨</tg-emoji> CONGRATULATIONS <tg-emoji emoji-id='6064138396228392033'>✨</tg-emoji></b>\n\n<tg-emoji emoji-id='5346024644635804737'>🔰</tg-emoji> You Are Now A Reseller.\nCheck Your Discounted Store /start To Check Now<tg-emoji emoji-id='6298298582982199311'>💰</tg-emoji></blockquote>" });645      } catch (e) {}646      return { text: "✅ User <code>" + esc(d.uid) + "</code> ab <b>Reseller</b> hai." };647    }648  };649 650  F.reseller_rem = {651    title: "☠ REMOVE RESELLER",652    steps: [S_USER],653    own: true,654    sum: function (d) { return recap(d); },655    run: function (d) {656      Bot.setProperty("is_reseller_" + d.uid, false, "boolean");657      try {658        Api.sendMessage({ chat_id: d.uid, parse_mode: "HTML",659          text: "<blockquote><b>⚠️ ROLE REMOVED</b>\n\nAapka <b>Reseller Role</b> admin dwara remove kar diya gaya hai. Ab aapko normal prices show hongi.</blockquote>" });660      } catch (e) {}661      return { text: "✅ User <code>" + esc(d.uid) + "</code> ka reseller role hata diya." };662    }663  };664 665  F.role = {666    title: "🪪 VIEW ROLE",667    steps: [S_USER],668    noconfirm: true,669    run: function (d) {670      var role = "Normal User";671      if (String(d.uid) === ownerId) role = "Owner / Admin 👑";672      else if (Bot.getProperty("co_admin_" + d.uid)) role = "Co-Admin 🛡";673      else if (Bot.getProperty("is_reseller_" + d.uid)) role = "Reseller 🔰";674      var nm = "N/A", un = "N/A";675      if (String(d.uid) === String(user.telegramid)) { nm = user.first_name || "N/A"; un = user.username ? "@" + user.username : "N/A"; }676      return { text: "<blockquote><b>📞 USER ROLE</b>\n\n• Name: " + esc(nm) + "\n• Username: " + esc(un) + "\n• User ID: <code>" + esc(d.uid) + "</code>\n• Role: " + role + "</blockquote>",677               rows: [[{ text: "🔎 Aur Check Karein", callback_data: "/wz go role", style: "primary" }]] };678    }679  };680 681  // ----- fees682  F.fee_setprice = {683    title: "⚙️ RESELLER UPGRADE FEE",684    steps: [T("price", "💰 <b>Reseller upgrade fee kitni?</b> (₹, poora number)\n<i>Current: " + esc(Bot.getProperty("reseller_upgrade_price") || Bot.getProperty("reseller_price") || "Not set") + "</i>", function (s) {685      var n = parseInt(s, 10);686      if (isNaN(n) || n <= 0) return { err: "Valid number bhejein (0 se zyada)." };687      return { val: n };688    })],689    own: true,690    sum: function (d) { return recap(d); },691    run: function (d) {692      // ⚠️ FIX: pehle ye sirf "reseller_price" save karta tha, jabki asli693      // "💼 Reseller Upgrade" button (/reseller_upgrade) "reseller_upgrade_price"694      // padhta hai — isliye admin yaha se fee set karta tha lekin button695      // "price admin ne abhi set nahi kiya" dikhata rehta tha. Ab dono keys696      // saath me set hoti hain taaki /reseller (legacy) aur /reseller_upgrade697      // (button flow) dono sync me rahein.698      Bot.setProperty("reseller_price", d.price, "integer");699      Bot.setProperty("reseller_upgrade_price", d.price, "number");700      return { text: "👑 <b>Reseller upgrade fee update:</b> ₹" + d.price };701    }702  };703  F.fee_upgrade = {704    title: "💎 RESELLER PRICE",705    steps: [T("price", "💰 <b>Reseller upgrade price kitna?</b> (₹)\n<i>Current: " + esc(Bot.getProperty("reseller_upgrade_price") || "Not set") + "</i>", vPrice)],706    sum: function (d) { return recap(d); },707    run: function (d) {708      Bot.setProperty("reseller_upgrade_price", d.price, "number");709      Bot.setProperty("reseller_price", d.price, "integer"); // legacy /reseller command isi key se padhta hai — sync rakhte hain710      return { text: "✅ <b>Reseller upgrade price set:</b> ₹" + d.price.toFixed(2) };711    }712  };713 714  // ----- AI support (multi-API, OpenAI-compatible)715  F.ai_api_add = {716    title: "🤖 ADD AI API",717    steps: [718      T("name", "🤖 <b>AI API ka naam</b> bhejein (sirf pehchaan ke liye)\n<i>Jaise: OpenAI Main, Gemini Backup</i>", vName),719      T("url", "🔗 <b>Base URL</b> bhejein (OpenAI-compatible /chat/completions ke bina)\n<i>Jaise: https://api.openai.com/v1</i>", vUrl,720        { quick: [["OpenAI", "https://api.openai.com/v1"], ["Groq", "https://api.groq.com/openai/v1"], ["OpenRouter", "https://openrouter.ai/api/v1"]] }),721      T("model", "🧠 <b>Model ka naam</b> bhejein\n<i>Jaise: gpt-4o-mini, llama-3.3-70b-versatile</i>", vName),722      T("key", "🔑 <b>API Key</b> bhejein", vApiKey)723    ],724    sum: function (d) {725      var maskedKey = d.key.length > 8 ? (d.key.slice(0, 4) + "••••" + d.key.slice(-4)) : "Configured";726      return "🤖 Name: <b>" + esc(d.name) + "</b>\n🔗 URL: <code>" + esc(d.url) + "</code>\n🧠 Model: <code>" + esc(d.model) + "</code>\n🔑 Key: <code>" + esc(maskedKey) + "</code>";727    },728    run: function (d) {729      var list = Bot.getProperty("ai_api_configs") || [];730      var newId = "ai" + Date.now();731      list.push({ id: newId, name: d.name, base_url: d.url, model: d.model, api_key: d.key });732      Bot.setProperty("ai_api_configs", list, "json");733      Bot.setProperty("ai_active_api_id", newId, "string");734      return {735        text: "✅ <b>AI API Added & Activated!</b>\n\n🤖 " + esc(d.name) + "\n🧠 " + esc(d.model),736        rows: [[{ text: "⬅️ Back to AI Manager", callback_data: "/admin_ai", style: "danger" }]]737      };738    }739  };740  F.ai_prompt = {741    title: "✏️ AI SYSTEM PROMPT",742    steps: [T("prompt", "✏️ <b>AI ko kya instruction follow karni chahiye?</b>\n<i>Current: " + esc(Bot.getProperty("ai_system_prompt") || "You are a helpful support assistant.") + "</i>", vPrompt)],743    sum: function (d) { return "✏️ Prompt:\n<i>" + esc(d.prompt) + "</i>"; },744    run: function (d) {745      Bot.setProperty("ai_system_prompt", d.prompt, "string");746      return { text: "✅ AI system prompt update ho gaya.", rows: [[{ text: "⬅️ Back to AI Manager", callback_data: "/admin_ai", style: "danger" }]] };747    }748  };749 750  // =====================================================================751  // 🌐 MULTI WEBSITE (API) + 🆔 PID EDIT752  // Har website = api_registry ka ek entry (URL + API key + Master key).753  // Product ko website assign karne par us product ki keys usi website se754  // kharidi jaati hain (product.api_id). Assign nahi to Default (Active) website.755  // =====================================================================756  var S_SITE = { k: "sid", t: "site", q: "🌐 <b>Website chuniye:</b>" };757  var S_SITEOPT = { k: "sid", t: "siteopt", q: "🌐 <b>Is product ki key kaunsi website se leni hai?</b>\n<i>Is panel ke saare plans usi website ke API se kharide jayenge.</i>" };758  function vMasterKey(s) {759    s = s.trim();760    if (s.length < 4) return { err: "Valid master key bhejein." };761    return { val: s };762  }763  // API type shortcuts: gk_post / gk_get (generate_key style, e.g. hkmodz) or reseller_v1 (standard)764  function vMode(s) {765    s = String(s).trim().toLowerCase();766    if (s === "gk_post" || s === "gk_get" || s === "reseller_v1") return { val: s };767    return { err: "Neeche ke buttons me se API type chuniye." };768  }769  function modeToFields(v) {770    if (v === "gk_get") return { mode: "generate_key", method: "GET" };771    if (v === "gk_post") return { mode: "generate_key", method: "POST" };772    return { mode: "reseller_v1", method: "POST" };773  }774  function modeLabel(x) {775    x = x || {};776    if (String(x.mode) === "generate_key") return "Generate Key (" + String(x.method || "POST").toUpperCase() + ")";777    return "Standard (reseller_v1)";778  }779  function vExtra(s) {780    s = String(s).trim().replace(/^[?&]+/, "");781    if (!/^[A-Za-z0-9_.\-]+=[^&\s]*(&[A-Za-z0-9_.\-]+=[^&\s]*)*$/.test(s)) return { err: "Format: <code>naam=value&naam2=value2</code> (space nahi). Nahi chahiye to Skip dabayein." };782    return { val: s };783  }784  var MODE_QUICK = [["Generate Key — POST", "gk_post"], ["Generate Key — GET", "gk_get"], ["Standard (reseller_v1)", "reseller_v1"]];785  function newSiteId(name) {786    var reg = sitesReg();787    var base = String(name || "site").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 20) || "site";788    if (base === "default") base = "site";789    var id = base, n = 2;790    while (reg[id]) { id = base + "_" + n; n++; }791    return id;792  }793  function productsUsing(id) {794    var out = [], pl = prods();795    for (var i = 0; i < pl.length; i++) { if (pl[i] && pl[i].name && String(pl[i].api_id || "") === String(id)) out.push(pl[i].name); }796    return out;797  }798 799  F.sites = { title: "👤 ACCOUNTS (PANEL API)", menu: [800    ["➕ Naya Account Add", "/wz go site_add"],801    ["🔗 Product ko Website Do", "/wz go site_prod"],802    ["📋 Accounts List + Test", "/wz go site_list"],803    ["✏️ Account Edit (URL / Key / Master / Type)", "/wz go site_edit"],804    ["⭐ Default (Active) Account", "/wz go site_active"],805    ["⏯ Account ON / OFF", "/wz go site_toggle"],806    ["🗑 Account Remove", "/wz go site_rem"],807    ["🆔 Plan ka PID Badlo", "/wz go pid_edit"]808  ] };809 810  F.site_add = {811    title: "➕ NAYI WEBSITE",812    steps: [813      T("sname", "🌐 <b>Website ka naam</b> bhejein (sirf pehchaan ke liye)\n<i>Jaise: KeyPanel, Site 2</i>", vName),814      T("surl", "🔗 <b>Website ka API URL</b> bhejein\n<i>Jaise: https://keypanel.shop/reseller_gateway.php</i>", vUrl),815      T("skey", "🔑 <b>API Key</b> bhejein", vApiKey),816      T("smaster", "🗝 <b>Master Key</b> bhejein (agar website me alag hai)\n<i>Nahi hai to neeche button dabayein, API key hi master key rahegi.</i>", vMasterKey, { skip: { l: "↩️ API key hi master key", v: "" } }),817      T("smode", "⚙️ <b>API type chuniye</b>\n<i>hkmodz jaisi <code>generate_key.php</code> wali site ke liye <b>Generate Key</b> (pehle POST, na chale to GET). Purani reseller_gateway wali site ke liye <b>Standard</b>.</i>", vMode, { quick: MODE_QUICK }),818      T("sextra", "➕ <b>Extra parameters</b> (optional)\n<i>Agar website kuch aur fixed field maangti hai to aise bhejein: <code>type=1&amp;server=2</code>. Nahi chahiye to Skip dabayein.</i>", vExtra, { skip: { l: "⏭ Skip", v: "" } })819    ],820    sum: function (d) {821      return "🌐 Naam: <b>" + esc(d.sname) + "</b>\n🔗 URL: <code>" + esc(d.surl) + "</code>\n🔑 API Key: <code>" + esc(maskKey(d.skey)) + "</code>\n🗝 Master Key: <code>" + esc(d.smaster ? maskKey(d.smaster) : "Same as API key") + "</code>\n⚙️ Type: <b>" + esc(modeLabel(modeToFields(d.smode))) + "</b>" + (d.sextra ? "\n➕ Extra: <code>" + esc(d.sextra) + "</code>" : "");822    },823    run: function (d) {824      var reg = sitesReg();825      var id = newSiteId(d.sname);826      reg[id] = {827        id: id, name: d.sname, url: d.surl, api_key: d.skey,828        master_key: d.smaster || d.skey, master_custom: !!d.smaster,829        mode: modeToFields(d.smode).mode, method: modeToFields(d.smode).method, extra: d.sextra || "",830        android_required: false, policy: "", side: "", user_number: "",831        enabled: true, updated_at: new Date().toISOString()832      };833      Bot.setProperty("api_registry", reg, "json");834      var act = String(Bot.getProperty("active_reseller_api") || "");835      if (!act || !reg[act]) Bot.setProperty("active_reseller_api", id, "string");836      return {837        text: "<blockquote>✅ <b>Account Add Ho Gaya!</b></blockquote>\n\n🌐 <b>" + esc(d.sname) + "</b> (<code>" + esc(id) + "</code>)\n\n<i>Pehle 🧪 Test Connection dabao. Phir kisi panel ko ye account do aur plan me PID daalo.</i>",838        rows: [839          [{ text: "🧪 Test Connection", callback_data: "/extkey_test " + id, style: "success" }],840          [{ text: "🔗 Panel ko ye Account Do", callback_data: "/wz go site_prod", style: "primary" }],841          [{ text: "➕ Ek aur Account", callback_data: "/wz go site_add", style: "primary" }]842        ]843      };844    }845  };846 847  F.site_prod = {848    title: "🔗 PRODUCT KO WEBSITE",849    steps: [S_PROD, S_SITEOPT],850    sum: function (d) { return recap(d); },851    run: function (d) {852      var list = prods();853      if (!list[d.pi]) return { text: "❌ Panel nahi mila." };854      if (d.sid) list[d.pi].api_id = d.sid; else delete list[d.pi].api_id;855      Bot.setProperty("stored_products", list, "json");856      return {857        text: "<blockquote>✅ <b>Website Set Ho Gayi!</b></blockquote>\n\n📦 <b>" + esc(d.pn) + "</b> → 🌐 <b>" + esc(d.swn) + "</b>\n\n<i>Ab is panel ke saare plans isi website ke API se kharide jayenge. Plan ka PID bhi isi website ka hona chahiye.</i>",858        rows: [859          [{ text: "🆔 PID Badlo", callback_data: "/wz go pid_edit", style: "primary" }],860          [{ text: "🔗 Dusre Product ko Website", callback_data: "/wz go site_prod", style: "success" }]861        ]862      };863    }864  };865 866  F.site_list = { title: "📋 WEBSITES LIST", steps: [], noconfirm: true,867    run: function () {868      var reg = sitesReg(); var ids = Object.keys(reg);869      var act = String(Bot.getProperty("active_reseller_api") || "");870      if (!ids.length) return { text: "<blockquote>🌐 <b>WEBSITES</b></blockquote>\n\n<i>Abhi koi website add nahi hai.</i>", rows: [[{ text: "➕ Nayi Website Add", callback_data: "/wz go site_add", style: "success" }]] };871      var all = prods(), unassigned = [];872      for (var i = 0; i < all.length; i++) { if (all[i] && all[i].name && !(all[i].api_id && reg[all[i].api_id])) unassigned.push(all[i].name); }873      var L = [], rows = [];874      for (var k = 0; k < ids.length; k++) {875        var x = reg[ids[k]] || {};876        var used = productsUsing(ids[k]);877        if (ids[k] === act) used = used.concat(unassigned.map(function (n) { return n + " (default)"; }));878        L.push("🌐 <b>" + esc(x.name || ids[k]) + "</b> (<code>" + esc(ids[k]) + "</code>)" + (ids[k] === act ? " ⭐" : "") + (x.enabled === false ? " 🔴 OFF" : " 🟢 ON") +879          "\n   🔗 " + esc(hostOf(x.url)) + " • ⚙️ " + esc(modeLabel(x)) + "\n   🔑 <code>" + esc(maskKey(x.api_key)) + "</code> • 🗝 <code>" + esc(x.master_custom ? maskKey(x.master_key) : "Same as API key") + "</code>" +880          "\n   📦 " + (used.length ? esc(used.join(", ")) : "<i>koi product nahi</i>"));881        if (rows.length < 8) rows.push([{ text: "🧪 Test: " + short(x.name || ids[k], 24), callback_data: "/extkey_test " + ids[k], style: "primary" }]);882      }883      return { text: "<blockquote>🌐 <b>WEBSITES</b></blockquote>  <i>⭐ = Default (Active)</i>\n\n" + L.join("\n\n"), rows: rows };884    } };885 886  F.site_edit = { title: "✏️ WEBSITE EDIT", menu: [887    ["📝 Naam badlo", "/wz go site_e_name"],888    ["🔗 URL badlo", "/wz go site_e_url"],889    ["🔑 API Key badlo", "/wz go site_e_key"],890    ["🗝 Master Key badlo", "/wz go site_e_master"],891    ["⚙️ API Type badlo (Generate Key / Standard)", "/wz go site_e_mode"],892    ["➕ Extra Parameters badlo", "/wz go site_e_extra"]893  ] };894  function siteEditFlow(title, field, q, v, x) {895    return {896      title: title,897      steps: [S_SITE, T("sval", q, v, x)],898      sum: function (d) {899        var shown = (field === "api_key" || field === "master_key") ? (d.sval ? maskKey(d.sval) : "Same as API key") : (field === "mode" ? modeLabel(modeToFields(d.sval)) : (field === "extra" ? (d.sval || "(khaali)") : d.sval));900        return "🌐 Website: <b>" + esc(d.swn) + "</b>\n✏️ Naya: <code>" + esc(shown) + "</code>";901      },902      run: function (d) {903        var reg = sitesReg(); var x0 = reg[d.sid];904        if (!x0) return { text: "❌ Website nahi mili." };905        if (field === "name") x0.name = d.sval;906        else if (field === "url") x0.url = d.sval;907        else if (field === "api_key") { x0.api_key = d.sval; if (!x0.master_custom) x0.master_key = d.sval; }908        else if (field === "master_key") { x0.master_custom = !!d.sval; x0.master_key = d.sval || x0.api_key || ""; }909        else if (field === "mode") { var mf = modeToFields(d.sval); x0.mode = mf.mode; x0.method = mf.method; }910        else if (field === "extra") { x0.extra = d.sval || ""; }911        x0.updated_at = new Date().toISOString();912        reg[d.sid] = x0;913        Bot.setProperty("api_registry", reg, "json");914        return {915          text: "✅ <b>Website update ho gayi:</b> " + esc(x0.name || d.sid),916          rows: [[{ text: "🧪 Test Connection", callback_data: "/extkey_test " + d.sid, style: "primary" }], [{ text: "⬅️ Website Menu", callback_data: "/wz go sites", style: "primary" }]]917        };918      }919    };920  }921  F.site_e_name = siteEditFlow("📝 WEBSITE NAAM", "name", "📝 <b>Naya naam</b> bhejein", vName);922  F.site_e_url = siteEditFlow("🔗 WEBSITE URL", "url", "🔗 <b>Naya API URL</b> bhejein", vUrl);923  F.site_e_key = siteEditFlow("🔑 WEBSITE API KEY", "api_key", "🔑 <b>Nayi API Key</b> bhejein", vApiKey);924  F.site_e_mode = siteEditFlow("⚙️ ACCOUNT API TYPE", "mode", "⚙️ <b>Naya API type chuniye</b>", vMode, { quick: MODE_QUICK });925  F.site_e_extra = siteEditFlow("➕ ACCOUNT EXTRA PARAMS", "extra", "➕ <b>Extra parameters bhejein</b>\n<i>Format: <code>naam=value&amp;naam2=value2</code>. Hatana ho to Skip dabayein.</i>", vExtra, { skip: { l: "🗑 Khaali karo", v: "" } });926  F.site_e_master = siteEditFlow("🗝 WEBSITE MASTER KEY", "master_key", "🗝 <b>Nayi Master Key</b> bhejein\n<i>Alag master key nahi hai to neeche button dabayein.</i>", vMasterKey, { skip: { l: "↩️ API key hi master key", v: "" } });927 928  F.site_active = { title: "⭐ DEFAULT WEBSITE", steps: [S_SITE],929    sum: function (d) { return recap(d) + "\n\n<i>Jin products ko alag website assign nahi hai, wo isi se keys kharidenge.</i>"; },930    run: function (d) {931      if (!sitesReg()[d.sid]) return { text: "❌ Website nahi mili." };932      Bot.setProperty("active_reseller_api", d.sid, "string");933      return { text: "✅ <b>Default (Active) website:</b> " + esc(d.swn) };934    } };935 936  F.site_toggle = { title: "⏯ WEBSITE ON / OFF", steps: [S_SITE], noconfirm: true,937    run: function (d) {938      var reg = sitesReg(); var x0 = reg[d.sid];939      if (!x0) return { text: "❌ Website nahi mili." };940      x0.enabled = (x0.enabled === false);941      reg[d.sid] = x0; Bot.setProperty("api_registry", reg, "json");942      return { text: "🌐 <b>" + esc(x0.name || d.sid) + "</b> ab " + (x0.enabled ? "🟢 ON" : "🔴 OFF") + " hai.\n<i>OFF website ke products kharid nahi honge.</i>" };943    } };944 945  F.site_rem = { title: "🗑 WEBSITE REMOVE", steps: [S_SITE],946    sum: function (d) { var u = productsUsing(d.sid); return recap(d) + (u.length ? "\n\n⚠️ <i>Ye website in products par lagi hai: " + esc(u.join(", ")) + ". Remove karne par ye Default website par chale jayenge.</i>" : ""); },947    run: function (d) {948      var reg = sitesReg();949      if (!reg[d.sid]) return { text: "❌ Website nahi mili." };950      if (String(Bot.getProperty("active_reseller_api") || "") === d.sid) return { text: "❌ Ye <b>Default (Active)</b> website hai. Pehle ⭐ Default Website se dusri website set karein, phir remove karein." };951      var list = prods(), cleared = 0;952      for (var i = 0; i < list.length; i++) { if (list[i] && String(list[i].api_id || "") === d.sid) { delete list[i].api_id; cleared++; } }953      if (cleared) Bot.setProperty("stored_products", list, "json");954      delete reg[d.sid];955      Bot.setProperty("api_registry", reg, "json");956      return { text: "🗑 <b>" + esc(d.swn) + "</b> remove ho gayi." + (cleared ? "\n<i>" + cleared + " product Default website par chale gaye.</i>" : "") };957    } };958 959  F.pid_edit = {960    title: "🆔 PID BADLO",961    steps: [S_PROD, S_PLAN, T("pid", function (st) {962      var p = prods()[st.d.pi]; var pl = p && p.plans && p.plans[st.d.li];963      var cur = pl ? (pl.pid || pl.product_id || pl.variant_id || "—") : "—";964      return "🆔 <b>Naya PID bhejein</b>\n<i>Abhi ka PID: <code>" + esc(cur) + "</code></i>";965    }, vPid, { skip: { l: "🔑 Manual keys (no PID)", v: "0" } })],966    sum: function (d) {967      var p = prods()[d.pi]; var pl = p && p.plans && p.plans[d.li];968      var old = pl ? (pl.pid || pl.product_id || pl.variant_id || "—") : "—";969      return recap(d) + "\n🔁 Purana PID: <code>" + esc(old) + "</code>";970    },971    run: function (d) {972      var list = prods(); var p = list[d.pi]; var pl = p && p.plans && p.plans[d.li];973      if (!pl) return { text: "❌ Plan nahi mila (shayad pehle hi hat chuka hai)." };974      pl.pid = d.pid; pl.product_id = d.pid; pl.variant_id = d.pid;975      Bot.setProperty("stored_products", list, "json");976      return {977        text: "<blockquote>✅ <b>PID Update Ho Gaya!</b></blockquote>\n\n📦 <b>" + esc(d.pn) + "</b> • ⏱ <b>" + esc(d.pl) + "</b>\n🆔 Naya PID: <code>" + esc(d.pid) + "</code>",978        rows: [[{ text: "🆔 Aur PID Badlo", callback_data: "/wz go pid_edit", style: "primary" }]]979      };980    }981  };982 983  // ----- discounts984  F.discount = { title: "💸 SET DISCOUNT", menu: [985    ["🌍 Sab par (Global)", "/wz go disc_global"],986    ["📦 Poore Panel par", "/wz go disc_prod"],987    ["⏱ Ek Plan par", "/wz go disc_plan"],988    ["🗑 Discount Hatao", "/wz go disc_remove"]989  ] };990  F.disc_remove = { title: "🗑 DISCOUNT HATAO", menu: [991    ["🌍 Global hatao", "/wz go disc_rem_global"],992    ["📦 Panel ka hatao", "/wz go disc_rem_prod"],993    ["⏱ Plan ka hatao", "/wz go disc_rem_plan"]994  ] };995  F.disc_global = { title: "🌍 GLOBAL DISCOUNT", steps: [T("pct", "💸 <b>Kitne % discount?</b> (1-100)", vPct)],996    sum: function (d) { return "💸 Discount: <b>" + d.pct + "%</b> (sabhi products/plans par)"; },997    run: function (d) { Bot.setProperty("auto_discount_global", d.pct, "number"); return { text: "✅ <b>Global Discount set:</b> -" + d.pct + "%" }; } };998  F.disc_prod = { title: "📦 PANEL DISCOUNT", steps: [S_PROD, T("pct", "💸 <b>Kitne % discount?</b> (1-100)", vPct)],999    sum: function (d) { return recap(d) + "\n💸 Discount: <b>" + d.pct + "%</b> (panel ke sabhi plans)"; },1000    run: function (d) { Bot.setProperty("auto_discount_" + d.pn.toUpperCase() + "_ALL", d.pct, "number"); return { text: "✅ <b>Discount Set!</b>\n\n📦 " + esc(d.pn) + "\n💸 -" + d.pct + "% (sabhi plans)" }; } };1001  function planDiscKey(d) {1002    var list = prods(); var pl = list[d.pi] && list[d.pi].plans ? list[d.pi].plans[d.li] : null;1003    if (!pl) return null;1004    var vu = planValueUnit(pl);1005    return "auto_discount_" + String(list[d.pi].name).trim().toUpperCase() + "_" + vu.value + "_" + vu.unit.toUpperCase();1006  }1007  F.disc_plan = { title: "⏱ PLAN DISCOUNT", steps: [S_PROD, S_PLAN, T("pct", "💸 <b>Kitne % discount?</b> (1-100)", vPct)],1008    sum: function (d) { return recap(d) + "\n💸 Discount: <b>" + d.pct + "%</b>"; },1009    run: function (d) { var k = planDiscKey(d); if (!k) return { text: "❌ Plan nahi mila." }; Bot.setProperty(k, d.pct, "number"); return { text: "✅ <b>Discount Set!</b>\n\n" + recap(d) + "\n💸 -" + d.pct + "%" }; } };1010  F.disc_rem_global = { title: "🗑 GLOBAL DISCOUNT HATAO", steps: [], sum: function () { return "Global discount hata diya jayega."; },1011    run: function () { Bot.setProperty("auto_discount_global", null, "number"); return { text: "✅ Global discount hata diya gaya." }; } };1012  F.disc_rem_prod = { title: "🗑 PANEL DISCOUNT HATAO", steps: [S_PROD], sum: function (d) { return recap(d); },1013    run: function (d) { Bot.setProperty("auto_discount_" + d.pn.toUpperCase() + "_ALL", null, "number"); return { text: "✅ Discount hata diya: <code>" + esc(d.pn) + "</code>" }; } };1014  F.disc_rem_plan = { title: "🗑 PLAN DISCOUNT HATAO", steps: [S_PROD, S_PLAN], sum: function (d) { return recap(d); },1015    run: function (d) { var k = planDiscKey(d); if (!k) return { text: "❌ Plan nahi mila." }; Bot.setProperty(k, null, "number"); return { text: "✅ Discount hata diya gaya:\n\n" + recap(d) }; } };1016 1017  // ----- member custom price1018  function memberKey(d) {1019    var list = prods(); var pl = list[d.pi] && list[d.pi].plans ? list[d.pi].plans[d.li] : null;1020    if (!pl) return { err: "Plan nahi mila." };1021    var vu = planValueUnit(pl);1022    if (vu.unit === "minute") return { err: "Member price sirf Hour/Day plans par lag sakta hai." };1023    var clean = String(list[d.pi].name).toUpperCase().replace(/\s+/g, " ").trim();1024    var keyProduct = clean.replace(/[^A-Z0-9_-]/g, "_");1025    var suffix = vu.unit === "day" ? vu.value : vu.value + "_hour";1026    return { key: "member_custom_price_" + d.uid + "_" + keyProduct + "_" + suffix };1027  }1028  F.mp_set = { title: "👤 MEMBER CUSTOM PRICE", steps: [S_USER, S_PROD, S_PLAN, T("price", "💰 <b>Is member ke liye price kitna?</b> (₹)", vPrice0)],1029    sum: function (d) { return recap(d) + "\n\n<i>Global price nahi badlega, sirf is member par lagega.</i>"; },1030    run: function (d) { var k = memberKey(d); if (k.err) return { text: "❌ " + k.err }; Bot.setProperty(k.key, d.price, "number"); return { text: "✅ <b>Member price set!</b>\n\n" + recap(d) }; } };1031  F.mp_rem = { title: "🗑 MEMBER PRICE HATAO", steps: [S_USER, S_PROD, S_PLAN], sum: function (d) { return recap(d); },1032    run: function (d) { var k = memberKey(d); if (k.err) return { text: "❌ " + k.err }; Bot.setProperty(k.key, null, "number"); return { text: "✅ Member custom price hata diya.\n\n" + recap(d) }; } };1033 1034  // ----- co-admins / ownership / identity  (owner only)1035  F.coadmin = { title: "👑 CO-ADMINS", own: true, menu: [1036    ["➕ Co-Admin Add", "/wz go co_add"], ["➖ Co-Admin Remove", "/wz go co_rem"], ["📋 List Dekhein", "/wz go co_list"]1037  ] };1038  F.co_add = { title: "➕ CO-ADMIN ADD", steps: [S_USER], own: true, sum: function (d) { return recap(d); },1039    run: function (d) {1040      if (String(d.uid) === ownerId) return { text: "❌ Owner khud ko co-admin nahi bana sakta!" };1041      var list = Bot.getProperty("co_admin_list") || [];1042      Bot.setProperty("co_admin_" + d.uid, true, "boolean");1043      if (list.indexOf(d.uid) === -1) { list.push(d.uid); Bot.setProperty("co_admin_list", list, "json"); }1044      try { Api.sendMessage({ chat_id: d.uid, parse_mode: "HTML", text: "<blockquote>👑 <b>YOU ARE NOW A CO-ADMIN!</b></blockquote>\n\n<i>Admin panel ke liye /admin use karein.</i>" }); } catch (e) {}1045      return { text: "✅ <b>Co-Admin Added!</b> User <code>" + esc(d.uid) + "</code> ab admin panel use kar sakta hai." };1046    } };1047  F.co_rem = { title: "➖ CO-ADMIN REMOVE", steps: [S_USER], own: true, sum: function (d) { return recap(d); },1048    run: function (d) {1049      var list = Bot.getProperty("co_admin_list") || [];1050      Bot.setProperty("co_admin_" + d.uid, null, "boolean");1051      var i = list.indexOf(d.uid);1052      if (i > -1) { list.splice(i, 1); Bot.setProperty("co_admin_list", list, "json"); }1053      return { text: "✅ <b>Co-Admin Removed!</b> User <code>" + esc(d.uid) + "</code> ka access hat gaya." };1054    } };1055  F.co_list = { title: "📋 CO-ADMIN LIST", steps: [], noconfirm: true, own: true,1056    run: function () {1057      var list = Bot.getProperty("co_admin_list") || [];1058      return { text: "<blockquote>👑 <b>CO-ADMIN LIST</b></blockquote>\n\n" + (list.length ? list.map(function (x) { return "• <code>" + esc(x) + "</code>"; }).join("\n") : "<i>Koi co-admin nahi hai.</i>") };1059    } };1060 1061  F.transfer = { title: "🔁 SET USER ID / TRANSFER OWNERSHIP", own: true,1062    steps: [T("uid", "🆔 <b>Naye Owner ka User ID bhejein</b>\n<i>Sirf number. ⚠️ Confirm ke baad aap Owner nahi rahenge — ID dobara check kar lein.</i>", vUser)],1063    noconfirm: true,1064    run: function (d) {1065      if (String(d.uid) === ownerId) return { text: "ℹ️ Ye ID pehle se Owner ki hai." };1066      User.setProperty("pending_ownership_transfer_to", d.uid, "string");1067      return {1068        text: "<blockquote>⚠️ <b>CONFIRM OWNERSHIP TRANSFER</b></blockquote>\n\nAap ownership <code>" + esc(d.uid) + "</code> ko transfer karne wale hain.\n<b>Ye action turant apply hoga aur aap Owner nahi rahenge!</b>\n\n<i>Kya aap sure hain?</i>",1069        rows: [[{ text: "Confirm Transfer", callback_data: "/confirm_ownership_transfer", style: "danger", icon_custom_emoji_id: "6215386799133433653" },1070                { text: "Cancel", callback_data: "/cancel_ownership_transfer", style: "primary" }]]1071      };1072    } };1073 1074  F.idb = { title: "🤖 SET BOT USERNAME", own: true,1075    steps: [T("bu", "🤖 <b>Bot ka username bhejein</b> (jaise <code>@MyShopBot</code>)\n<i>Current: @" + esc(String(Bot.getProperty("bot_username") || "JASSMODZSHOP_BOT").replace(/^@/, "")) + "</i>", vBotUser)],1076    noconfirm: true,1077    run: function (d) {1078      Bot.setProperty("bot_username", d.bu, "string");1079      return { text: "✅ <b>Bot username update:</b> <code>@" + esc(d.bu) + "</code>\n\n🔗 Referral link:\n<code>https://t.me/JASSMODZSHOP_BOT?start=_tgr_uXY38UUxODY9</code>",1080               rows: [[{ text: "🪪 Identity Settings", callback_data: "/bot_identity", style: "primary" }]] };1081    } };1082  F.ida = { title: "📞 SET ADMIN USERNAME", own: true,1083    steps: [T("au", "📞 <b>Admin ka @username bhejein</b> (jaise <code>@YourName</code>)", vAdminUser)],1084    noconfirm: true,1085    run: function (d) {1086      Bot.setProperty("admin_username", d.au, "string");1087      Bot.setProperty("support_link", "https://t.me/" + d.au, "string");1088      return { text: "✅ <b>Admin username update:</b> <code>@" + esc(d.au) + "</code>\n\n📞 Support ka <b>Contact Admin</b> ab <code>https://t.me/" + esc(d.au) + "</code> par khulega.",1089               rows: [[{ text: "🪪 Identity Settings", callback_data: "/bot_identity", style: "primary" }]] };1090    } };1091 1092  // ------------------------------------------------------------ the engine1093  function loadState() {1094    var st = User.getProperty("wz_state");1095    if (typeof st === "string") { try { st = JSON.parse(st); } catch (e) { st = null; } }1096    if (st && st.t && (Date.now() - st.t) > 20 * 60 * 1000) { st = null; }1097    if (!(st && st.f && F[st.f])) { clearState(); return null; }   // expired/unknown -> never leave a stale state1098    return st;1099  }1100  function saveState(st) { st.t = Date.now(); User.setProperty("wz_state", st, "json"); }1101  function clearState() { User.setProperty("wz_state", null, "json"); }1102 1103  function ownerGuard(fl) {1104    if (fl.own && !isOwner) { show("❌ Ye option sirf <b>Owner</b> ke liye hai.", [BACK_ADMIN]); return false; }1105    return true;1106  }1107 1108  function finish(st) {1109    var fl = F[st.f];1110    var res = fl.run(st.d);1111    clearState();1112    var rows = (res.rows || []).slice();1113    rows.push(BACK_ADMIN);1114    // results are always sent fresh so the history stays readable1115    Api.sendMessage({ chat_id: me, text: res.text, parse_mode: "HTML", reply_markup: JSON.stringify({ inline_keyboard: rows }) });1116  }1117 1118  function chooseRows(sp, st) {1119    var rows = [];1120    if (sp.t === "cat") {1121      var ks = ["root", "nonroot", "iphone", "both"];1122      for (var i = 0; i < ks.length; i++) rows.push([{ text: CAT_LABELS[ks[i]], callback_data: "/wz c " + ks[i], style: "danger" }]);1123    } else if (sp.t === "prodcat") {1124      var all = prods();1125      for (var pc = 0; pc < all.length && rows.length < 60; pc++) {1126        if (all[pc] && all[pc].name && inCat(all[pc], st.d.cat)) {1127          rows.push([{ text: short(all[pc].name, 30) + " (" + ((all[pc].plans || []).length) + ")", callback_data: "/wz c " + pc, style: "primary" }]);1128        }1129      }1130    } else if (sp.t === "unit") {1131      rows.push([{ text: "⏰ Hours", callback_data: "/wz c h", style: "primary" }, { text: "📅 Days", callback_data: "/wz c d", style: "primary" }]);1132    } else if (sp.t === "prod") {1133      var pl = prods();1134      for (var j = 0; j < pl.length && j < 60; j++) {1135        if (pl[j] && pl[j].name) rows.push([{ text: (j + 1) + ". " + short(pl[j].name, 34), callback_data: "/wz c " + j, style: "primary" }]);1136      }1137    } else if (sp.t === "plan") {1138      var pr = prods()[st.d.pi];1139      var plans = pr && pr.plans ? pr.plans : [];1140      for (var k = 0; k < plans.length && k < 60; k++) {1141        rows.push([{ text: short(planLabel(plans[k]), 26) + " • ₹" + plans[k].normal_price, callback_data: "/wz c " + k, style: "primary" }]);1142      }1143    } else if (sp.t === "site" || sp.t === "siteopt") {1144      var sr = sitesReg(); var sids = Object.keys(sr);1145      if (sp.t === "siteopt") rows.push([{ text: "↩️ Default (Active) website", callback_data: "/wz c none", style: "success" }]);1146      for (var si = 0; si < sids.length && si < 40; si++) {1147        var sx = sr[sids[si]] || {};1148        rows.push([{ text: "🌐 " + short(sx.name || sids[si], 20) + " • " + short(hostOf(sx.url), 22) + (sx.enabled === false ? " (OFF)" : ""), callback_data: "/wz c " + si, style: "primary" }]);1149      }1150    } else if (sp.t === "idcat") {1151      var cs = idCats(); var slugs = Object.keys(cs);1152      for (var m = 0; m < slugs.length && m < 60; m++) rows.push([{ text: "📁 " + short(cs[slugs[m]].name || slugs[m], 30), callback_data: "/wz c " + m, style: "primary" }]);1153    }1154    return rows;1155  }1156 1157  // panel belongs to a category (root/nonroot/iphone); "both"/unset panels show under every category1158  function inCat(p, cat) {1159    var c = String(p.category || "both");1160    return cat === "both" ? c === "both" : (c === cat || c === "both");1161  }1162 1163  function render(st) {1164    var fl = F[st.f];1165    if (fl.menu) {1166      var mrows = fl.menu.map(function (m) { return [{ text: m[0], callback_data: m[1], style: "primary" }]; });1167      mrows.push(BACK_ADMIN);1168      show("<blockquote><b>" + fl.title + "</b></blockquote>\n\nKya karna hai?", mrows);1169      return;1170    }1171    var steps = fl.steps;1172    if (st.s >= steps.length) {1173      if (fl.noconfirm || !fl.sum) { finish(st); return; }1174      show("<blockquote><b>" + fl.title + "</b> • Confirm</blockquote>\n\n" + fl.sum(st.d) + "\n\n<b>Sab sahi hai?</b>",1175        [[{ text: "✅ Confirm & Save", callback_data: "/wz ok", style: "success" }], [NAV_BACK, NAV_CANCEL]]);1176      return;1177    }1178    var sp = steps[st.s];1179    var head = "<blockquote><b>" + fl.title + "</b>  •  Step " + (st.s + 1) + "/" + steps.length + "</blockquote>\n\n";1180    var rc = recap(st.d);1181    var body = (rc ? rc + "\n\n" : "") + (typeof sp.q === "function" ? sp.q(st) : sp.q);1182    var rows = [];1183    if (sp.t === "text") {1184      if (sp.x.quick) {1185        var row = [];1186        for (var q = 0; q < sp.x.quick.length; q++) {1187          row.push({ text: sp.x.quick[q][0], callback_data: "/wz c " + sp.x.quick[q][1], style: "primary" });1188          if (row.length === 3) { rows.push(row); row = []; }1189        }1190        if (row.length) rows.push(row);1191      }1192      if (sp.x.skip) rows.push([{ text: sp.x.skip.l, callback_data: "/wz skip", style: "success" }]);1193      if (sp.x.skipSame) rows.push([{ text: "🟰 Same as user price", callback_data: "/wz skip", style: "success" }]);1194    } else {1195      rows = chooseRows(sp, st);1196      if (!rows.length) {1197        clearState();1198        show("❌ " + (sp.t === "prodcat" ? "Is category mein abhi koi panel nahi hai. Pehle Add Product se panel banayein." : sp.t === "idcat" ? "Koi ID category nahi hai. Pehle ID category add karein." : sp.t === "plan" ? "Is panel mein koi plan nahi hai." : (sp.t === "site" || sp.t === "siteopt") ? "Abhi koi website add nahi hai. Pehle Multi Website me Nayi Website Add karein." : "Abhi koi product nahi hai. Pehle Add Product karein.") , [BACK_ADMIN]);1199        return;1200      }1201    }1202    rows.push(st.s > 0 ? [NAV_BACK, NAV_CANCEL] : [NAV_CANCEL]);1203    show(head + body, rows);1204  }1205 1206  // apply a value to the current step (buttons + text)1207  function applyChoice(st, token) {1208    var sp = F[st.f].steps[st.s];1209    if (!sp) return false;1210    if (sp.t === "cat") { if (!CAT_LABELS[token]) return false; st.d.cat = token; }1211    else if (sp.t === "prod") {1212      var i = parseInt(token, 10); var pl = prods();1213      if (isNaN(i) || !pl[i]) return false;1214      st.d.pi = i; st.d.pn = pl[i].name;1215    } else if (sp.t === "prodcat") {1216      var q = parseInt(token, 10); var pq = prods();1217      if (isNaN(q) || !pq[q] || !inCat(pq[q], st.d.cat)) return false;1218      st.d.pi = q; st.d.pn = pq[q].name;1219    } else if (sp.t === "unit") {1220      if (token !== "h" && token !== "d") return false;1221      st.d.unit = token;1222    } else if (sp.t === "plan") {1223      var l = parseInt(token, 10); var pr = prods()[st.d.pi];1224      if (isNaN(l) || !pr || !pr.plans || !pr.plans[l]) return false;1225      st.d.li = l; st.d.pl = planLabel(pr.plans[l]);1226    } else if (sp.t === "site" || sp.t === "siteopt") {1227      if (sp.t === "siteopt" && token === "none") { st.d.sid = ""; st.d.swn = "Default (Active) website"; }1228      else {1229        var xi = parseInt(token, 10); var xids = siteIds();1230        if (isNaN(xi) || !xids[xi]) return false;1231        st.d.sid = xids[xi]; st.d.swn = siteName(xids[xi]);1232      }1233    } else if (sp.t === "idcat") {1234      var m = parseInt(token, 10); var cs = idCats(); var sl = Object.keys(cs);1235      if (isNaN(m) || !sl[m]) return false;1236      st.d.slug = sl[m]; st.d.catName = cs[sl[m]].name || sl[m];1237    } else if (sp.t === "text") {1238      var res = sp.v(String(token));   // quick buttons pass a ready value1239      if (res.err) return false;1240      st.d[sp.k] = res.val;1241    } else return false;1242    st.s++;1243    return true;1244  }1245 1246  // --------------------------------------------------------------- dispatch1247  if (isText) {1248    var st0 = loadState();1249    if (!st0) { Bot.sendMessage("ℹ️ Koi active wizard nahi hai. /admin se option chuniye."); return; }1250    try { if (request && request.message_id) Api.deleteMessage({ chat_id: me, message_id: request.message_id }); } catch (de) {}1251    var fl0 = F[st0.f];1252    var sp0 = fl0.steps ? fl0.steps[st0.s] : null;1253    if (!sp0 || sp0.t !== "text") { Bot.sendMessage("👆 Upar diye gaye <b>buttons</b> se chuniye.", { parse_mode: "HTML" }); return; }1254    var rr = sp0.v(rawText);1255    if (rr.err) {1256      Api.sendMessage({ chat_id: me, parse_mode: "HTML", text: "❌ " + esc(rr.err) + "\n\nDobara bhejein:",1257        reply_markup: JSON.stringify({ inline_keyboard: [[NAV_CANCEL]] }) });1258      return;1259    }1260    st0.d[sp0.k] = rr.val; st0.s++;1261    saveState(st0);1262    render(st0);1263    return;1264  }1265 1266  if (verb === "go") {1267    var name = arg.split(/\s+/)[0];1268    var fl = F[name];1269    if (!fl) { show("⚠️ Unknown option.", [BACK_ADMIN]); return; }1270    if (!ownerGuard(fl)) return;1271    var st = { f: name, s: 0, d: {} };1272    if (fl.menu) { clearState(); render(st); return; }1273    saveState(st);1274    render(st);1275    return;1276  }1277 1278  if (verb === "more") {1279    // add another plan to a panel that was just created1280    var pi = parseInt(arg, 10); var pls = prods();1281    if (isNaN(pi) || !pls[pi]) { show("❌ Panel nahi mila.", [BACK_ADMIN]); return; }1282    var stm = { f: "add_plan", s: 1, d: { pi: pi, pn: pls[pi].name } };1283    saveState(stm); render(stm); return;1284  }1285 1286  if (verb === "qmore") {1287    var qi = parseInt(arg, 10); var qp = prods();1288    if (isNaN(qi) || !qp[qi]) { show("❌ Panel nahi mila.", [BACK_ADMIN]); return; }1289    var cat0 = (qp[qi].category && CAT_LABELS[qp[qi].category]) ? qp[qi].category : "both";1290    var stq = { f: "quick_add", s: 2, d: { cat: cat0, pi: qi, pn: qp[qi].name } };1291    saveState(stq); render(stq); return;1292  }1293 1294  if (verb === "cancel") {1295    clearState();1296    show("❌ <b>Cancel ho gaya.</b>", [BACK_ADMIN]);1297    return;1298  }1299 1300  var cur = loadState();1301  if (!cur) { show("⌛ Session expire ho gaya. /admin se dobara shuru karein.", [BACK_ADMIN]); return; }1302  if (!ownerGuard(F[cur.f])) return;1303 1304  if (verb === "back") {1305    if (cur.s > 0) cur.s--;1306    saveState(cur); render(cur); return;1307  }1308  if (verb === "skip") {1309    var spk = F[cur.f].steps[cur.s];1310    if (spk && spk.t === "text" && spk.x.skip) { cur.d[spk.k] = spk.x.skip.v; cur.s++; }1311    else if (spk && spk.x && spk.x.skipSame) { cur.d[spk.k] = cur.d.price; cur.s++; }1312    saveState(cur); render(cur); return;1313  }1314  if (verb === "c") {1315    if (!applyChoice(cur, arg)) { render(cur); return; }1316    saveState(cur); render(cur); return;1317  }1318  if (verb === "ok") {1319    var flo = F[cur.f];1320    if (cur.s < flo.steps.length) { render(cur); return; }1321    finish(cur); return;1322  }1323 1324  show("⚠️ Unknown action.", [BACK_ADMIN]);1325 1326} catch (err) {1327  Bot.sendMessage("⚠️ Wizard Error: " + err.message);1328}
commands/_wz.js · tarunpoonia905/OfcDevShopBot · TeleDevs