Spaces:
Running
Running
Download tagwren/pro.js from CyberMax-tools/cybermax: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/spaces/CyberMax-tools/cybermax/resolve/main/tagwren/pro.js
- Command line
-
hf download hf://spaces/CyberMax-tools/cybermax/tagwren/pro.js
-
curl -L -o pro.js https://huggingface.co/spaces/CyberMax-tools/cybermax/resolve/main/tagwren/pro.js
10.6 kB
| /* CyberMax Pro unlock with plans, for static web apps (copied into each product's web/ folder; each product stays | |
| * self-contained). Extends pro.js with several plans (monthly, yearly, one-time) and a re-check for subscriptions. | |
| * Config before this script: | |
| * window.CMX_PRO = { id, name, perks: [..], plans: [{ offer, label, price, per, note, best }], free: "one line" } | |
| * Buy: counted link https://data.cybermaxtools.com/buy/<offer>?s=app-<id> -> Stripe Payment Link. | |
| * After checkout Stripe sends the buyer to data.cybermaxtools.com/unlock/<id>?session_id=..., which checks the | |
| * Checkout Session (and, for a subscription, that it is still active) and returns here with #cmx-pro=<session id>. | |
| * The app checks that code once (/unlock/<id>?json=1&session_id=..) and remembers Pro in this browser; it re-checks every | |
| * 3 days, so a cancelled subscription turns off by itself (one tiny request per buyer every 3 days, none for free users). | |
| * The same code (shown on the receipt page and in the Pro box) unlocks Pro on another device. No account, no tracking. | |
| * (c) 2026 CyberMax. All rights reserved. */ | |
| (function () { | |
| "use strict"; | |
| var C = window.CMX_PRO || {}; | |
| if (!C.id) return; | |
| var DATA = "https://data.cybermaxtools.com"; | |
| var KEY = "cmx-pro:" + C.id; | |
| var SID = /^(cs_(live|test)_[A-Za-z0-9]{10,200}|[A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8})$/i; // Stripe order code or Gumroad licence key | |
| var RECHECK = 3 * 864e5; | |
| var listeners = []; | |
| function get() { try { return JSON.parse(localStorage.getItem(KEY) || "null"); } catch (e) { return null; } } | |
| function set(v) { try { if (v) localStorage.setItem(KEY, JSON.stringify(v)); else localStorage.removeItem(KEY); } catch (e) { /* private mode */ } mem = v; } | |
| var mem = get(); | |
| function isPro() { return !!(mem && mem.code); } | |
| function check(code) { | |
| return fetch(DATA + "/unlock/" + encodeURIComponent(C.id) + "?json=1&session_id=" + encodeURIComponent(code)) | |
| .then(function (r) { return r.json(); }) | |
| .then(function (j) { return j && typeof j.pro === "boolean" ? j.pro : null; }) | |
| .catch(function () { return null; }); | |
| } | |
| function unlock(code) { | |
| return check(code).then(function (ok) { | |
| if (ok) { set({ code: code, at: new Date().toISOString(), checked: Date.now() }); apply(); toast("Pro unlocked. Thank you for choosing " + C.name + "!"); } | |
| else if (ok === false) toast("That code is not an active " + C.name + " Pro order."); | |
| else toast("Could not reach the unlock check. Try again in a minute."); | |
| return ok; | |
| }); | |
| } | |
| function recheck() { | |
| if (!isPro() || Date.now() - (mem.checked || 0) < RECHECK) return; | |
| check(mem.code).then(function (ok) { | |
| if (ok === false) { set(null); apply(); toast(C.name + " Pro has ended in this browser. Everything free is still here."); } | |
| else if (ok) set(Object.assign({}, mem, { checked: Date.now() })); | |
| }); | |
| } | |
| function toast(msg) { | |
| var t = document.getElementById("toast"); | |
| if (t) { t.textContent = msg; t.hidden = false; t.classList.add("show"); setTimeout(function () { t.classList.remove("show"); }, 3500); } | |
| var s = document.getElementById("cmx-pro-msg"); | |
| if (s) s.textContent = msg; | |
| } | |
| function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """ }[c]; }); } | |
| function buyUrl(offer, from) { return DATA + "/buy/" + offer + "?s=app-" + C.id + (from ? "-" + from : ""); } | |
| // Convert kit (funnel beacons, real proof, email capture, phone buy bar), loaded from the CyberMax Store; optional: | |
| // if it can't load (offline), the app and the Pro box work exactly the same. | |
| var KIT = "https://cybermaxtools.com/store/convert.js", kitQ = []; | |
| function conv(fn) { | |
| if (window.CMXConvert) return fn(window.CMXConvert); | |
| kitQ.push(fn); | |
| if (kitQ.length > 1 || !navigator.onLine) return; | |
| var sc = document.createElement("script"); sc.src = KIT; sc.async = true; | |
| sc.onload = function () { var q = kitQ.splice(0); q.forEach(function (f) { try { f(window.CMXConvert); } catch (e) { /* */ } }); }; | |
| document.head.appendChild(sc); | |
| } | |
| function box() { | |
| var el = document.getElementById("cmx-pro"); | |
| if (!el) { | |
| el = document.createElement("section"); | |
| el.id = "cmx-pro"; | |
| var anchor = document.querySelector("footer.more") || document.querySelector("main footer") || document.querySelector("footer"); | |
| if (anchor && anchor.parentNode) anchor.parentNode.insertBefore(el, anchor); else (document.querySelector("main") || document.body).appendChild(el); | |
| } | |
| el.className = "cmx-pro"; | |
| return el; | |
| } | |
| function render() { | |
| var el = box(); | |
| if (isPro()) { | |
| el.innerHTML = '<h2>' + esc(C.name) + ' Pro <span class="cmx-pro-badge">on</span></h2><p>Thank you! Pro is on in this browser: ' + C.perks.map(esc).join(" · ") + | |
| '.</p><p class="cmx-pro-small">Your unlock code (paste it on another device): <code style="user-select:all;word-break:break-all">' + esc(mem.code) + | |
| '</code></p>' + ((C.plans || []).some(function (p) { return /\//.test(p.per || ""); }) ? '<p class="cmx-pro-small">Monthly or yearly plan? Cancel any time from the link in your Stripe receipt email.</p>' : ""); | |
| return; | |
| } | |
| var subs = (C.plans || []).some(function (p) { return /\//.test(p.per || ""); }); | |
| var plans = (C.plans || []).map(function (p) { | |
| return '<a class="cmx-plan' + (p.best ? " best" : "") + '" href="' + buyUrl(p.offer) + '" rel="nofollow" data-offer="' + esc(p.offer) + '">' + | |
| (p.best ? "<i>Best value</i>" : "") + "<b>" + esc(p.label) + '</b><span class="cmx-price">' + esc(p.price) + "<small>" + esc(p.per || "") + | |
| '</small></span><span class="cmx-note">' + esc(p.note || "") + "</span></a>"; | |
| }).join(""); | |
| el.innerHTML = '<h2>' + esc(C.name) + ' Pro</h2>' + (C.free ? '<p class="cmx-pro-small">Free: ' + esc(C.free) + "</p>" : "") + | |
| "<ul>" + C.perks.map(function (p) { return "<li>" + esc(p) + "</li>"; }).join("") + '</ul><div class="cmx-plans">' + plans + | |
| '</div><p class="cmx-pro-small">Secure Stripe checkout. Pro turns on the moment you pay; no account needed.' + (subs ? " Subscriptions cancel any time from your receipt email." : " One payment, no subscription.") + | |
| ' 14-day promise: if it doesn\'t work as described, we fix it or refund you in full (<a href="https://cybermaxtools.com/terms#payments" target="_blank" rel="noopener">terms</a>). Questions: <a href="mailto:cybermax.tools@gmail.com">cybermax.tools@gmail.com</a></p><div class="cmx-pro-proof"></div><div class="cmx-pro-cap"></div>' + | |
| '<details><summary>Already bought Pro?</summary><form id="cmx-pro-form"><label>Unlock code <input id="cmx-pro-code" autocomplete="off" placeholder="cs_live_… or Gumroad licence key"></label> <button class="btn ghost" type="submit">Unlock</button></form></details><p id="cmx-pro-msg" class="cmx-pro-small" aria-live="polite"></p>'; | |
| Array.prototype.forEach.call(el.querySelectorAll("a.cmx-plan"), function (a) { a.addEventListener("click", function () { conv(function (K) { K.event("upgrade-click", C.id); }); }); }); | |
| conv(function (K) { | |
| K.proof(el.querySelector(".cmx-pro-proof"), C.id); | |
| K.capture(el.querySelector(".cmx-pro-cap"), { list: "weekly-" + C.id, src: "app-" + C.id, label: "Not ready for Pro? Email me " + C.name + " tips and new features (about once a week)" }); | |
| }); | |
| var f = document.getElementById("cmx-pro-form"); | |
| if (f) f.onsubmit = function (e) { e.preventDefault(); var c = (document.getElementById("cmx-pro-code").value || "").trim(); if (SID.test(c)) unlock(c); else toast("Paste the code from your receipt page (it starts with cs_live_) or your Gumroad licence key."); }; | |
| } | |
| function apply() { | |
| document.documentElement.classList.toggle("cmx-pro", isPro()); | |
| render(); | |
| listeners.forEach(function (fn) { try { fn(isPro()); } catch (e) { /* app hook */ } }); | |
| } | |
| /** Scroll to the Pro box (call when a free user hits a limit); `from` tags the counted buy links. */ | |
| function upsell(reason, from) { | |
| var el = box(); | |
| if (from) Array.prototype.forEach.call(el.querySelectorAll("a.cmx-plan"), function (a) { a.href = buyUrl(a.getAttribute("data-offer"), from); }); | |
| if (reason) toast(reason); | |
| // A real limit: count it, and on phones keep one buy button in reach (no timer; closes with one tap). | |
| conv(function (K) { | |
| K.event("limit", C.id); K.event("upgrade-view", C.id); | |
| var best = (C.plans || []).filter(function (p) { return p.best; })[0] || (C.plans || [])[0]; | |
| if (best && !isPro()) K.sticky({ text: C.name + " Pro: " + best.price + (best.per || ""), cta: "Go Pro", href: buyUrl(best.offer, (from || "limit") + "-bar"), product: C.id }); | |
| }); | |
| el.scrollIntoView({ behavior: "smooth", block: "start" }); | |
| el.classList.add("cmx-pro-flash"); setTimeout(function () { el.classList.remove("cmx-pro-flash"); }, 1600); | |
| } | |
| /** Free monthly allowance kept in this browser: quota("pdf", 5) -> {used, left, take()}. */ | |
| function quota(name, limit) { | |
| var k = "cmx-quota:" + C.id + ":" + name, month = new Date().toISOString().slice(0, 7), q; | |
| try { q = JSON.parse(localStorage.getItem(k) || "null"); } catch (e) { q = null; } | |
| if (!q || q.m !== month) q = { m: month, n: 0 }; | |
| return { | |
| used: q.n, left: Math.max(0, limit - q.n), limit: limit, | |
| take: function () { if (isPro()) return true; if (q.n >= limit) return false; q.n++; try { localStorage.setItem(k, JSON.stringify(q)); } catch (e) { /* */ } this.used = q.n; this.left = Math.max(0, limit - q.n); return true; }, | |
| }; | |
| } | |
| function download(name, data, type) { | |
| var a = document.createElement("a"); | |
| a.href = URL.createObjectURL(data instanceof Blob ? data : new Blob([data], { type: type || "text/csv;charset=utf-8" })); | |
| a.download = name; | |
| document.body.appendChild(a); a.click(); a.remove(); | |
| setTimeout(function () { URL.revokeObjectURL(a.href); }, 2000); | |
| } | |
| window.CMXPro = { isPro: isPro, onChange: function (fn) { listeners.push(fn); fn(isPro()); }, upsell: upsell, quota: quota, download: download, toast: toast }; | |
| var m = /[#&]cmx-pro=([^&]+)/.exec(location.hash || ""); | |
| function start() { | |
| if (m && SID.test(decodeURIComponent(m[1]))) { | |
| var code = decodeURIComponent(m[1]); | |
| history.replaceState(null, "", location.pathname + location.search); | |
| apply(); unlock(code); | |
| } else { apply(); recheck(); } | |
| } | |
| if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start); else start(); | |
| })(); | |