async function getPremiumDIDs() { return new Promise((resolve, reject) => { fetch(`https://portal.bulkvs.com/api/v1.0/tnRecord?Status=Active&Trunk%20Group=${process.env.TRUNK_GROUP}`, { headers: { "Authorization": `Bearer ${process.env.BVS_TOKEN}`, } }) .then(res => { if (!res.ok) { throw new Error(`Error fetching DIDs: ${res.status} ${res.statusText}`); } return res.json(); }) .then(data => { // data.forEach(record => { // console.log(record.ReferenceID); // }); // data is array of objects. If object.ReferenceID.split(";;")[0] is premDID, then [1] is the user id, and anything after is a note const dids = data.filter(record => record.ReferenceID && record.ReferenceID.startsWith(";;")).map(record => { // Get all flags (just keep looking at the next split item until its not a valid flag, after that, it's all a custom note, most likely to be used fo) let validFlags = ["bypassNitroReq"]; let flags = []; let note = ""; let splitReference = record.ReferenceID.split(";;"); for (let i = 1; i < splitReference.length; i++) { if (validFlags.includes(splitReference[i])) { flags.push(splitReference[i]); } } return { did: record.TN, userId: record.ReferenceID.split(";;")[1], flags: flags, rawRef: record.ReferenceID } }); resolve(dids); }) .catch(error => { console.error("Error fetching DIDs:", error); reject(error); }); }); } async function getAllDIDs() { // Use the same BVS API endpoint, but just get all the results, not just premium ones. return new Promise((resolve, reject) => { fetch(`https://portal.bulkvs.com/api/v1.0/tnRecord?Status=Active&Trunk%20Group=${process.env.TRUNK_GROUP}`, { headers: { "Authorization": `Bearer ${process.env.BVS_TOKEN}`, } }) .then(res => { if (!res.ok) { throw new Error(`Error fetching DIDs: ${res.status} ${res.statusText}`); } return res.json(); }) .then(data => { const dids = data.map(record => record.TN); resolve(dids); }) .catch(error => { console.error("Error fetching DIDs:", error); reject(error); }); }); } async function getAccountInfo() { const res = await fetch("https://portal.bulkvs.com/api/v1.0/accountDetail", { headers: { "Authorization": `Bearer ${process.env.BVS_TOKEN}`, } }); if (!res.ok) { throw new Error(`BVS_TOKEN is invalid: ${res.status} ${res.statusText}`); } return res.json(); } async function searchDIDs(query) { // console.log(`q is ${query}`) // Query will either be NPA, or NPANXX. Validate with regex, then use the API to find some. // API Example: GET https://portal.bulkvs.com/api/v1.0/orderTn?Npa=310&Nxx=906&Lca=true&Limit=100 query = query.replace(/\D/g, ""); // Remove all non-digit characters // Validate query w regex if (!/^\d{3}$/.test(query) && !/^\d{6}$/.test(query)) { throw new Error("Query must be either NPA (3 digits) or NPANXX (6 digits)"); } const res = await fetch(`https://portal.bulkvs.com/api/v1.0/orderTn?Npa=${query.slice(0, 3)}&Nxx=${query.slice(3, 6)}&Lca=true&Limit=100`, { headers: { "Authorization": `Bearer ${process.env.BVS_TOKEN}`, } }); if (!res.ok) { throw new Error(`Error searching DIDs: ${res.status} ${res.statusText}`); } return res.json(); } async function searchPurchasableDIDs(query) { // console.log(`Searching purchasable DIDs with query ${query}`); // Use searchDIDs, then filter down to 6 random from the results where the Nrc value == "0.05" and Mrc == "0.06" const dids = await searchDIDs(query).catch(error => { console.error("Error searching DIDs:", error); return []; }); // console.log(dids) const purchasableDIDs = dids.filter(did => did.Nrc <= "0.50" && did.Mrc <= "0.15"); // console.log(purchasableDIDs) // Shuffle the purchasableDIDs array, then take the first 6 let shuffled = [...purchasableDIDs]; for (let i = 0; i < 5; i++) { shuffled = shuffled.sort(() => 0.5 - Math.random()); } // shuffle more return shuffled.slice(0, 6); } async function purchaseDID(did, userId) { // POST /orderTn with body: /* { "TN": "did to purchase", "Lidb": "LITENET", "Portout Pin": `${random 12 digit number}`, "ReferenceID": `;;${userId}`, "Trunk Group": `${process.env.TRUNK_GROUP}`, "Sms": false, "Mms": false, "Webhook": "Default" } */ let portoutPin = ""; const digits = "0123456789"; for (let i = 0; i < 12; i++) { portoutPin += digits[Math.floor(Math.random() * digits.length)]; } const res = await fetch("https://portal.bulkvs.com/api/v1.0/orderTn", { method: "POST", headers: { "Authorization": `Bearer ${process.env.BVS_TOKEN}`, "Content-Type": "application/json" }, body: JSON.stringify({ "TN": did, "Lidb": "LITENET", "Portout Pin": portoutPin, "ReferenceID": `;;${userId}`, "Trunk Group": `${process.env.TRUNK_GROUP}`, "Sms": false, "Mms": false, "Webhook": "Default" }) }); // If response is 404, check body.json().Description, return the json body. if (res.status === 404) { const errorData = await res.json(); throw new Error(`Error purchasing DID: ${res.status} ${res.statusText} - ${errorData.Description}`); } if (!res.ok) { throw new Error(`Error purchasing DID: ${res.status} ${res.statusText}`); } return res.json(); } function formatPhoneNumber(input) { if (/^\d{10}$/.test(input)) { input = `1${input}`; } // Regex to make sure it's a valid 11 digit NA phone number. if (!/^\d{11}$/.test(input)) { throw new Error("Phone number must be 10 or 11 digits, including country code (1 for US/Canada)."); } // Format to human readable format: +1 (310) 906-1234 return `+${input[0]} (${input.slice(1, 4)}) ${input.slice(4, 7)}-${input.slice(7)}`; } function deleteDID(did) { // API to delete msg, DELETE https://portal.bulkvs.com/api/v1.0/tnRecord?Number=did return fetch(`https://portal.bulkvs.com/api/v1.0/tnRecord?Number=${did}`, { method: "DELETE", headers: { "Authorization": `Bearer ${process.env.BVS_TOKEN}`, } }) .then(res => { if (!res.ok) { throw new Error(`Error deleting DID: ${res.status} ${res.statusText}`); } return res.json(); }); } module.exports = { getAllDIDs, getAccountInfo, getPremiumDIDs, searchDIDs, searchPurchasableDIDs, purchaseDID, formatPhoneNumber, deleteDID }