// ==UserScript== // @name Stores to Agent // @namespace https://www.reddit.com/user/RobotOilInc // @version 5.2.3 // @author RobotOilInc // @source https://gitlab.com/robotoilinc/stores-to-agents/ // @license MIT // @require https://unpkg.com/@trim21/gm-fetch@0.1.15/dist/gm_fetch.js#sha384-P0KSVCS+YC1OEOII7FniE0zZ0+xpXAOHHT5aY++HbYNTnJbp8R933m5CVq4XJv4O // @require https://unpkg.com/gm-storage@2.0.3/dist/index.umd.min.js#sha384-IforrfCAVNj1KYlzIXNAyX2RADvDkkufuRfcM0qT57QMNdEonuvBRK2WfL8Co3JV // @require https://unpkg.com/gm4-polyfill@1.0.1/gm4-polyfill.js#sha384-nDSbBzN1Jn1VgjQjt5u2BxaPO1pbMS9Gxyi5+yIsKYWzqkYOEh11iQdomqywYPaN // @require https://unpkg.com/jquery@3.7.0/dist/jquery.min.js#sha384-NXgwF8Kv9SSAr+jemKKcbvQsz+teULH/a5UNJvZc6kP47hZgl62M1vGnw6gHQhb1 // @require https://unpkg.com/js-logger@1.6.1/src/logger.min.js#sha384-CGmI56C3Kvs2e+Ftr3UpFkkMgOAXBUkLKS/KVkxDEuGSUYF8qki7CzwWWBz4QM60 // @require https://greasyfork.org/scripts/11562-gm-config-8/code/GM_config%208+.js?version=66657#sha256-229668ef83cd26ac207e9d780e2bba6658e1506ac0b23fb29dc94ae531dd31fb // @description Adds an order directly from stores to your agent // @homepageURL https://greasyfork.org/en/scripts/427774-stores-to-agent // @supportURL https://greasyfork.org/en/scripts/427774-stores-to-agent // @match https://detail.1688.com/offer/* // @match https://*.taobao.com/item.htm* // @match https://*.v.weidian.com/?userid=* // @match https://*.weidian.com/item.html* // @match https://*.yupoo.com/albums/* // @match https://detail.tmall.com/item.htm* // @match https://weidian.com/*itemID=* // @match https://weidian.com/?userid=* // @match https://weidian.com/item.html* // @match https://*.pandabuy.com/* // @match https://www.pandabuy.com/* // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_webRequest // @grant GM_xmlhttpRequest // @grant GM_deleteValue // @grant GM_listValues // @connect basetao.com // @connect cssbuy.com // @connect superbuy.com // @connect ytaopal.com // @connect wegobuy.com // @connect pandabuy.com // @webRequest [{ "selector": "*thor.weidian.com/stardust/*", "action": "cancel" }] // @icon https://i.imgur.com/2lQXuqv.png // @run-at document-end // @downloadURL https://update.greasyfork.icu/scripts/427774/Stores%20to%20Agent.user.js // @updateURL https://update.greasyfork.icu/scripts/427774/Stores%20to%20Agent.meta.js // ==/UserScript== /*! @robotoilinc/stores-to-agents v5.2.3 has been created by RobotOilInc. All rights reserved. */ /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./node_modules/object-to-formdata/src/index.js": /***/ ((module) => { function isUndefined(value) { return value === undefined; } function isNull(value) { return value === null; } function isBoolean(value) { return typeof value === 'boolean'; } function isObject(value) { return value === Object(value); } function isArray(value) { return Array.isArray(value); } function isDate(value) { return value instanceof Date; } function isBlob(value, isReactNative) { return isReactNative ? isObject(value) && !isUndefined(value.uri) : isObject(value) && typeof value.size === 'number' && typeof value.type === 'string' && typeof value.slice === 'function'; } function isFile(value, isReactNative) { return isBlob(value, isReactNative) && typeof value.name === 'string' && (isObject(value.lastModifiedDate) || typeof value.lastModified === 'number'); } function initCfg(value) { return isUndefined(value) ? false : value; } function serialize(obj, cfg, fd, pre) { cfg = cfg || {}; fd = fd || new FormData(); cfg.indices = initCfg(cfg.indices); cfg.nullsAsUndefineds = initCfg(cfg.nullsAsUndefineds); cfg.booleansAsIntegers = initCfg(cfg.booleansAsIntegers); cfg.allowEmptyArrays = initCfg(cfg.allowEmptyArrays); cfg.noAttributesWithArrayNotation = initCfg(cfg.noAttributesWithArrayNotation); cfg.noFilesWithArrayNotation = initCfg(cfg.noFilesWithArrayNotation); cfg.dotsForObjectNotation = initCfg(cfg.dotsForObjectNotation); const isReactNative = typeof fd.getParts === 'function'; if (isUndefined(obj)) { return fd; } else if (isNull(obj)) { if (!cfg.nullsAsUndefineds) { fd.append(pre, ''); } } else if (isBoolean(obj)) { if (cfg.booleansAsIntegers) { fd.append(pre, obj ? 1 : 0); } else { fd.append(pre, obj); } } else if (isArray(obj)) { if (obj.length) { obj.forEach((value, index) => { let key = pre + '[' + (cfg.indices ? index : '') + ']'; if (cfg.noAttributesWithArrayNotation || cfg.noFilesWithArrayNotation && isFile(value, isReactNative)) { key = pre; } serialize(value, cfg, fd, key); }); } else if (cfg.allowEmptyArrays) { fd.append(cfg.noAttributesWithArrayNotation ? pre : pre + '[]', ''); } } else if (isDate(obj)) { fd.append(pre, obj.toISOString()); } else if (isObject(obj) && !isBlob(obj, isReactNative)) { Object.keys(obj).forEach(prop => { const value = obj[prop]; if (isArray(value)) { while (prop.length > 2 && prop.lastIndexOf('[]') === prop.length - 2) { prop = prop.substring(0, prop.length - 2); } } const key = pre ? cfg.dotsForObjectNotation ? pre + '.' + prop : pre + '[' + prop + ']' : prop; serialize(value, cfg, fd, key); }); } else { fd.append(pre, obj); } return fd; } module.exports = { serialize }; /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ var getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. (() => { "use strict"; ;// CONCATENATED MODULE: external "Logger" const external_Logger_namespaceObject = Logger; var external_Logger_default = /*#__PURE__*/__webpack_require__.n(external_Logger_namespaceObject); ;// CONCATENATED MODULE: external "GMStorage" const external_GMStorage_namespaceObject = GMStorage; var external_GMStorage_default = /*#__PURE__*/__webpack_require__.n(external_GMStorage_namespaceObject); ;// CONCATENATED MODULE: ./src/Constants.ts const PandaBuyToken = "PANDABUY_TOKEN"; const PandaBuyUserInfo = "PANDABUY_USERINFO"; ;// CONCATENATED MODULE: ./src/exceptions/PandaBuyError.ts class PandaBuyError extends Error { constructor(message) { super(message); this.name = "PandaBuyError"; } } ;// CONCATENATED MODULE: ./src/helpers/StorageHelper.ts class LocalStorage { constructor() { this.localStorageSupported = typeof window["localStorage"] != "undefined" && window["localStorage"] != null; } // add value to storage add(key, item) { if (this.localStorageSupported) { localStorage.setItem(key, item); } } // get one item by key from storage get(key) { if (this.localStorageSupported) { return localStorage.getItem(key); } return null; } // remove value from storage remove(key) { if (this.localStorageSupported) { localStorage.removeItem(key); } } // clear storage (remove all items from it) clear() { if (this.localStorageSupported) { localStorage.clear(); } } } ;// CONCATENATED MODULE: ./src/agents/login/Pandabuy.ts class PandaBuyLogin { constructor() { this.store = new (external_GMStorage_default())(); this.localStorage = new LocalStorage(); } supports(hostname) { return hostname.includes("pandabuy.com"); } process() { // If we already have a token, don't bother const currentToken = this.store.get(PandaBuyToken, null); if (currentToken !== null && currentToken.length !== 0) { return; } // Don't bother with getting the token, if we aren't loggeed in yet const userInfo = this.localStorage.get(PandaBuyUserInfo); if (userInfo === null || userInfo.length === 0) { return; } // The token should now exist const updatedToken = this.localStorage.get(PandaBuyToken); if (updatedToken === null || updatedToken.length === 0) { throw new PandaBuyError("Could not retrieve token"); } // Store it internally this.store.set(PandaBuyToken, updatedToken); external_Logger_default().info("Updated the PandaBuy Authorization Token"); } } ;// CONCATENATED MODULE: ./src/agents/login/Logins.ts function getLogin(hostname) { const agents = [new PandaBuyLogin()]; let agent = null; Object.values(agents).forEach(value => { if (value.supports(hostname)) { agent = value; } }); return agent; } // EXTERNAL MODULE: ./node_modules/object-to-formdata/src/index.js var src = __webpack_require__("./node_modules/object-to-formdata/src/index.js"); ;// CONCATENATED MODULE: ./src/exceptions/BaseTaoError.ts class BaseTaoError extends Error { constructor(message) { super(message); this.name = "BaseTaoError"; } } ;// CONCATENATED MODULE: ./src/helpers/DetermineStoreSource.ts /** * Determines on website we are buying something. Used for BaseTao and Pandabuy. */ const determineStoreSource = function () { if (window.location.hostname.includes("1688.com")) { return "1688"; } // Check more specific TaoBao pages first if (window.location.hostname.includes("market.m.taobao.com") || window.location.hostname.includes("2.taobao.com")) { return "xianyu"; } if (window.location.hostname.includes("taobao.com")) { return "taobao"; } if (window.location.hostname.includes("weidian.com") || window.location.hostname.includes("koudai.com")) { return "wd"; } if (window.location.hostname.includes("yupoo.com")) { return "yupoo"; } if (window.location.hostname.includes("detail.tmall.com")) { return "tmall"; } throw new Error(`Could not determine store source ${window.location.hostname}`); }; ;// CONCATENATED MODULE: ./node_modules/@trim21/gm-fetch/dist/index.mjs function parseRawHeaders(h) { const s = h.trim(); if (!s) { return new Headers(); } const array = s.split("\r\n").map((value) => { let s = value.split(":"); return [s[0].trim(), s[1].trim()]; }); return new Headers(array); } function parseGMResponse(req, res) { return new ResImpl(res.response, { statusCode: res.status, statusText: res.statusText, headers: parseRawHeaders(res.responseHeaders), finalUrl: res.finalUrl, redirected: res.finalUrl === req.url, }); } class ResImpl { constructor(body, init) { this.rawBody = body; this.init = init; this.body = toReadableStream(body); const { headers, statusCode, statusText, finalUrl, redirected } = init; this.headers = headers; this.status = statusCode; this.statusText = statusText; this.url = finalUrl; this.type = "basic"; this.redirected = redirected; this._bodyUsed = false; } get bodyUsed() { return this._bodyUsed; } get ok() { return this.status < 300; } arrayBuffer() { if (this.bodyUsed) { throw new TypeError("Failed to execute 'arrayBuffer' on 'Response': body stream already read"); } this._bodyUsed = true; return this.rawBody.arrayBuffer(); } blob() { if (this.bodyUsed) { throw new TypeError("Failed to execute 'blob' on 'Response': body stream already read"); } this._bodyUsed = true; // `slice` will use empty string as default value, so need to pass all arguments. return Promise.resolve(this.rawBody.slice(0, this.rawBody.size, this.rawBody.type)); } clone() { if (this.bodyUsed) { throw new TypeError("Failed to execute 'clone' on 'Response': body stream already read"); } return new ResImpl(this.rawBody, this.init); } formData() { if (this.bodyUsed) { throw new TypeError("Failed to execute 'formData' on 'Response': body stream already read"); } this._bodyUsed = true; return this.rawBody.text().then(decode); } async json() { if (this.bodyUsed) { throw new TypeError("Failed to execute 'json' on 'Response': body stream already read"); } this._bodyUsed = true; return JSON.parse(await this.rawBody.text()); } text() { if (this.bodyUsed) { throw new TypeError("Failed to execute 'text' on 'Response': body stream already read"); } this._bodyUsed = true; return this.rawBody.text(); } } function decode(body) { const form = new FormData(); body .trim() .split("&") .forEach(function (bytes) { if (bytes) { const split = bytes.split("="); const name = split.shift()?.replace(/\+/g, " "); const value = split.join("=").replace(/\+/g, " "); form.append(decodeURIComponent(name), decodeURIComponent(value)); } }); return form; } function toReadableStream(value) { return new ReadableStream({ start(controller) { controller.enqueue(value); controller.close(); }, }); } async function GM_fetch(input, init) { const request = new Request(input, init); let data; if (init?.body) { data = await request.text(); } return await XHR(request, init, data); } function XHR(request, init, data) { return new Promise((resolve, reject) => { if (request.signal && request.signal.aborted) { return reject(new DOMException("Aborted", "AbortError")); } GM.xmlHttpRequest({ url: request.url, method: gmXHRMethod(request.method.toUpperCase()), headers: Object.fromEntries(new Headers(init?.headers).entries()), data: data, responseType: "blob", onload(res) { resolve(parseGMResponse(request, res)); }, onabort() { reject(new DOMException("Aborted", "AbortError")); }, ontimeout() { reject(new TypeError("Network request failed, timeout")); }, onerror(err) { reject(new TypeError("Failed to fetch: " + err.finalUrl)); }, }); }); } const httpMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "TRACE", "OPTIONS", "CONNECT"]; // a ts type helper to narrow type function includes(array, element) { return array.includes(element); } function gmXHRMethod(method) { if (includes(httpMethods, method)) { return method; } throw new Error(`unsupported http method ${method}`); } //# sourceMappingURL=index.mjs.map ;// CONCATENATED MODULE: ./src/helpers/Fetch.ts function get(url, init) { return GM_fetch(url, { ...init, method: "GET" }); } function post(url, request) { return GM_fetch(url, { ...request, method: "POST" }); } ;// CONCATENATED MODULE: ./src/helpers/RemoveEmoji.ts /** * Removes all emojis from the input text. * * @param string {string} */ const removeEmoji = string => string.replace(/[^\p{L}\p{N}\p{P}\p{Z}^$\n]/gu, ""); ;// CONCATENATED MODULE: ./src/agents/BaseTao.ts const CSRF_REQUIRED_ERROR = "You need to be logged in on BaseTao to use this extension (CSRF required)."; class BaseTao { constructor() { this.parser = new DOMParser(); } get name() { return "BaseTao"; } async send(order) { // Get proper domain to use const properDomain = await this._getDomain(); // Build the purchase data const purchaseData = await this._buildPurchaseData(properDomain, order); external_Logger_default().info("Sending order to BaseTao...", properDomain, order); // Do the actual call const response = await post(`${properDomain}/best-taobao-agent-service/bt_action/add_cart`, { body: new URLSearchParams((0,src.serialize)(purchaseData)), referrer: `${properDomain}/best-taobao-agent-service/how_make/buy_order.html`, headers: { origin: `${properDomain}`, referrer: `${properDomain}/best-taobao-agent-service/how_make/buy_order.html`, "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36", "x-requested-with": "XMLHttpRequest" } }); const responseData = await response.json(); if (responseData.value === "1") { return; } external_Logger_default().error("Item could not be added", response); throw new BaseTaoError("Item could not be added, make sure you are logged in"); } async _getDomain() { // Try HTTPS (with WWW) first let response = await get("https://www.basetao.com/best-taobao-agent-service/how_make/buy_order.html"); let doc = this.parser.parseFromString(await response.text(), "text/html"); let csrfToken = doc.querySelector("input[name=bt_sb_token]"); if (csrfToken && csrfToken.value.length !== 0) { return "https://www.basetao.com"; } // Try HTTPS (without WWW) after response = await get("https://basetao.com/best-taobao-agent-service/how_make/buy_order.html"); doc = this.parser.parseFromString(await response.text(), "text/html"); csrfToken = doc.querySelector("input[name=bt_sb_token]"); console.log(csrfToken); if (csrfToken && csrfToken.value.length !== 0) { return "https://basetao.com"; } // User is not logged in/there is an issue throw new Error(CSRF_REQUIRED_ERROR); } async _buildPurchaseData(properDomain, order) { // Get the CSRF token const csrf = await this._getCSRF(properDomain); // Build the data we will send const data = { addtime: Date.now(), goodscolor: order.item.color ?? "-", goodsimg: order.item.imageUrl, goodsname: removeEmoji(order.item.name), goodsnum: 1, goodsprice: order.price, goodsremark: this._buildRemark(order) ?? "", goodsseller: removeEmoji(order.shop.name ?? ""), goodssite: determineStoreSource(), goodssize: order.item.size ?? "-", goodsurl: window.location.href, item_id: order.item.id, sellerurl: order.shop.url ?? "", sendprice: order.shipping, siteurl: window.location.hostname, sku_id: 0, type: 1 }; return { bt_sb_token: csrf, data: JSON.stringify(data) }; } async _getCSRF(properDomain) { // Grab data from BaseTao const response = await get(`${properDomain}/best-taobao-agent-service/how_make/buy_order.html`); // Check if user is actually logged in const data = await response.text(); if (data.includes("please sign in again")) { throw new Error(CSRF_REQUIRED_ERROR); } const doc = this.parser.parseFromString(data, "text/html"); const csrfToken = doc.querySelector("input[name=bt_sb_token]"); if (csrfToken && csrfToken.value.length !== 0) { return csrfToken.value; } // Return CSRF throw new Error(CSRF_REQUIRED_ERROR); } _buildRemark(order) { const descriptionParts = []; if (order.item.model !== null) descriptionParts.push(`Model: ${order.item.model}`); if (order.item.other.length !== 0) descriptionParts.push(order.item.other); let description = null; if (descriptionParts.length !== 0) { description = descriptionParts.join(" / "); } return description; } } ;// CONCATENATED MODULE: ./src/exceptions/CSSBuyError.ts class CSSBuyError extends Error { constructor(message) { super(message); this.name = "CSSBuyError"; } } ;// CONCATENATED MODULE: ./src/agents/CSSBuy.ts class CSSBuy { get name() { return "CSSBuy"; } async send(order) { // Build the purchase data const purchaseData = this._buildPurchaseData(order); external_Logger_default().info("Sending order to CSSBuy...", purchaseData); // Do the actual call const response = await post("https://www.cssbuy.com/ajax/fast_ajax.php?action=buyone", { body: new URLSearchParams((0,src.serialize)(purchaseData)), referrer: `https://www.cssbuy.com/?go=item&url=${encodeURIComponent(purchaseData.data.href)}`, referrerPolicy: "strict-origin-when-cross-origin", headers: { "accept": "application/json, text/javascript, */*; q=0.01", "accept-language": "nl,en-US;q=0.9,en;q=0.8,de;q=0.7,und;q=0.6", "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "referrer": `https://www.cssbuy.com/?go=item&url=${encodeURIComponent(purchaseData.data.href)}`, "referrerPolicy": "strict-origin-when-cross-origin", "x-requested-with": "XMLHttpRequest" } }); if ((await response.json()).ret === 0) { return; } external_Logger_default().error("Item could not be added", response); throw new CSSBuyError("Item could not be added"); } _buildPurchaseData(order) { // Build the description const description = this._buildRemark(order); // Create the purchasing data return { data: { buynum: 1, shopid: order.shop.id, picture: order.item.imageUrl, defaultimg: order.item.imageUrl, freight: order.shipping, price: order.price, color: order.item.color, size: order.item.size, total: order.price + order.shipping, buyyourself: 0, seller: order.shop.name, href: window.location.href, title: order.item.name, note: description, option: description } }; } _buildRemark(order) { const descriptionParts = []; if (order.item.model !== null) descriptionParts.push(`Model: ${order.item.model}`); if (order.item.color !== null) descriptionParts.push(`Color: ${order.item.color}`); if (order.item.size !== null) descriptionParts.push(`Size: ${order.item.size}`); if (order.item.other.length !== 0) descriptionParts.push(`${order.item.other}`); let description = null; if (descriptionParts.length !== 0) { description = descriptionParts.join(" / "); } return description; } } ;// CONCATENATED MODULE: ./src/agents/PandaBuy.ts class PandaBuy { constructor() { this.store = new (external_GMStorage_default())(); } get name() { return "PandaBuy"; } async send(order) { const token = this.store.get(PandaBuyToken, null); if (token === null || token.length === 0) { throw new PandaBuyError("We do not have your PandaBuy authorization token yet. Please visit PandaBuy (and login if needed)"); } // Build the purchase data const purchaseData = this._buildPurchaseData(order); external_Logger_default().info("Sending order to PandaBuy...", purchaseData); // Do the actual call await post("https://www.pandabuy.com/gateway/user/cart/add", { credentials: "include", mode: "cors", referrer: `https://www.pandabuy.com/uniorder?text=${encodeURIComponent(window.location.href)}`, referrerPolicy: "strict-origin-when-cross-origin", body: JSON.stringify(purchaseData), headers: { "accept": "application/json, text/plain, */*", "accept-language": "nl,en-US;q=0.9,en;q=0.8,de;q=0.7,und;q=0.6", "authorization": `Bearer ${token}`, "content-type": "application/json;charset=UTF-8", "currency": "CNY", "device": "pc", "lang": "en" } }).then(async response => { const data = await response.json(); if (response.status === 200 && data.msg === null) { return; } // Our token has expired if (response.status === 401) { // Reset the current token GM_setValue(PandaBuyToken, null); external_Logger_default().error("PandaBuy authorization token has expired"); throw new PandaBuyError("Your PandaBuy authorization token has expired. Please visit PandaBuy (or login at PandaBuy) again"); } external_Logger_default().error("Item could not be added", data.msg); throw new PandaBuyError("Item could not be added"); }).catch(err => { // If the error is our own, just rethrow it if (err instanceof PandaBuyError) { throw err; } external_Logger_default().error("An error happened when uploading the order", err); throw new Error("An error happened when adding the order"); }); } _buildPurchaseData(order) { // Build the description const description = this._buildRemark(order); // Create the purchasing data return { storeName: order.shop.name, storeId: order.shop.id, goodsUrl: window.location.href, goodsName: order.item.name, goodsNameCn: order.item.name, goodsAttr: description, goodsAttrCn: description, storageNo: 1, goodsPrice: order.price, goodsNum: 1, fare: order.shipping, remark: "", selected: 1, purchaseType: 1, goodsImg: order.item.imageUrl, servicePrice: "0.00", writePrice: order.price, actPrice: order.price, storeSource: determineStoreSource(), goodsId: order.item.id, seller: order.shop.name, storeUrl: "https://weidian.com/?userid=" + order.shop.id }; } _buildRemark(order) { const descriptionParts = []; if (order.item.model !== null && order.item.model.length !== 0) descriptionParts.push(`Model: ${order.item.model}`); if (order.item.color !== null && order.item.color.length !== 0) descriptionParts.push(`Color: ${order.item.color}`); if (order.item.size !== null && order.item.size.length !== 0) descriptionParts.push(`Size: ${order.item.size}`); if (order.item.other.length !== 0) descriptionParts.push(`${order.item.other}`); let description = null; if (descriptionParts.length !== 0) { description = descriptionParts.join(" / "); } return description; } } ;// CONCATENATED MODULE: ./src/exceptions/SuperBuyError.ts class SuperBuyError extends Error { constructor(message) { super(message); this.name = "SuperBuyError"; } } ;// CONCATENATED MODULE: ./src/helpers/BuildTaoCarts.ts class BuildTaoCarts { purchaseData(order) { // Build the description const description = this._buildRemark(order); // Generate an SKU based on the description let sku = null; if (description !== null && description.length !== 0) { sku = description.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0); } // Create the purchasing data return { type: 1, shopItems: [{ shopLink: "", shopSource: "NOCRAWLER", shopNick: "", shopId: "", goodsItems: [{ beginCount: 0, count: 1, desc: description, freight: order.shipping, freightServiceCharge: 0, goodsAddTime: Math.floor(Date.now() / 1000), goodsCode: `NOCRAWLER-${sku}`, goodsId: window.location.href, goodsLink: window.location.href, goodsName: order.item.name, goodsPrifex: "NOCRAWLER", goodsRemark: description, guideGoodsId: "", is1111Yushou: "no", picture: order.item.imageUrl, platForm: "pc", price: order.price, priceNote: "", serviceCharge: 0, sku: order.item.imageUrl, spm: "", warehouseId: "1" }] }] }; } _buildRemark(order) { const descriptionParts = []; if (order.item.model !== null) descriptionParts.push(`Model: ${order.item.model}`); if (order.item.color !== null) descriptionParts.push(`Color: ${order.item.color}`); if (order.item.size !== null) descriptionParts.push(`Size: ${order.item.size}`); if (order.item.other.length !== 0) descriptionParts.push(`${order.item.other}`); let description = null; if (descriptionParts.length !== 0) { description = descriptionParts.join(" / "); } return description; } } ;// CONCATENATED MODULE: ./src/agents/SuperBuy.ts class SuperBuy { constructor() { this._builder = new BuildTaoCarts(); } get name() { return "SuperBuy"; } async send(order) { // Build the purchase data const purchaseData = this._builder.purchaseData(order); external_Logger_default().info("Sending order to SuperBuy...", purchaseData); // Do the actual call const response = await post("https://front.superbuy.com/cart/add-cart", { body: JSON.stringify(purchaseData), headers: { origin: "https://www.superbuy.com", referer: "https://www.superbuy.com/", "content-type": "application/json;charset=UTF-8", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36" } }); const data = await response.json(); if (data.state === 0 && data.msg === "Success") { return; } external_Logger_default().error("Item could not be added", data.msg); throw new SuperBuyError("Item could not be added"); } } ;// CONCATENATED MODULE: ./src/exceptions/WeGoBuyError.ts class WeGoBuyError extends Error { constructor(message) { super(message); this.name = "WeGoBuyError"; } } ;// CONCATENATED MODULE: ./src/agents/WeGoBuy.ts class WeGoBuy { constructor() { this._builder = new BuildTaoCarts(); } get name() { return "WeGoBuy"; } async send(order) { // Build the purchase data const purchaseData = this._builder.purchaseData(order); external_Logger_default().info("Sending order to WeGoBuy...", purchaseData); // Do the actual call const response = await post("https://front.wegobuy.com/cart/add-cart", { body: JSON.stringify(purchaseData), headers: { origin: "https://www.superbuy.com", referer: "https://www.superbuy.com/", "content-type": "application/json;charset=UTF-8", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36" } }); const data = await response.json(); if (data.state === 0 && data.msg === "Success") { return; } external_Logger_default().error("Item could not be added", data.msg); throw new WeGoBuyError("Item could not be added"); } } ;// CONCATENATED MODULE: ./src/agents/Agents.ts const getAgent = selection => { switch (selection) { case "basetao": return new BaseTao(); case "cssbuy": return new CSSBuy(); case "pandabuy": return new PandaBuy(); case "superbuy": return new SuperBuy(); case "wegobuy": return new WeGoBuy(); default: throw new Error(`Agent '${selection}' is not implemented`); } }; ;// CONCATENATED MODULE: ./src/classes/Item.ts class Item { constructor(id, name, imageUrl, model, color, size, others) { this.id = id; this.name = name; this.imageUrl = imageUrl; this.model = model; this.color = color; this.size = size; this.others = others; } get other() { return this.others.join("\n"); } } ;// CONCATENATED MODULE: ./src/classes/Order.ts class Order { constructor(shop, item, price, shipping) { this.shop = shop; this.item = item; this.price = price; this.shipping = shipping; } } ;// CONCATENATED MODULE: ./src/classes/Shop.ts class Shop { constructor(id, name, url) { this.id = id; this.name = name; this.url = url; } } ;// CONCATENATED MODULE: ./src/helpers/ElementReady.ts /** * Waits for an element satisfying selector to exist, then resolves promise with the element. * Useful for resolving race conditions. */ const elementReady = function (selector) { return new Promise(resolve => { // Check if the element already exists const element = document.querySelector(selector); if (element) { resolve(element); } // It doesn't so, so let's make a mutation observer and wait new MutationObserver((mutationRecords, observer) => { // Query for elements matching the specified selector Array.from(document.querySelectorAll(selector)).forEach(foundElement => { // Resolve the element that we found resolve(foundElement); // Once we have resolved we don't need the observer anymore. observer.disconnect(); }); }).observe(document.documentElement, { childList: true, subtree: true }); }); }; ;// CONCATENATED MODULE: ./src/helpers/RemoveWhitespaces.ts /** * Trims the input text and removes all in between spaces as well. * * @param string {string} */ const removeWhitespaces = string => string.trim().replace(/\s(?=\s)/g, ""); ;// CONCATENATED MODULE: ./src/helpers/Snackbar.ts const Snackbar = function (toast) { // Log the snackbar, for ease of debugging external_Logger_default().info(toast); // Setup toast element const $toast = $(`