autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
170
skills/bypass-ai/templates/claude-cassia-mock.user.js
Normal file
170
skills/bypass-ai/templates/claude-cassia-mock.user.js
Normal file
@@ -0,0 +1,170 @@
|
||||
// ==UserScript==
|
||||
// @name Claude Cassia Checkout Mock
|
||||
// @namespace gothbreach.claude
|
||||
// @version 1.0.0
|
||||
// @description Mock checkout_capabilities to cassia flow for Claude Max
|
||||
// @match *://claude.ai/*
|
||||
// @match *://*.claude.ai/*
|
||||
// @run-at document-start
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
const TARGET_HOST = "claude.ai";
|
||||
const TARGET_PATH = /^\/api\/organizations\/[^/]+\/subscription\/checkout_capabilities\/?$/;
|
||||
const MOCK_DATA = { checkout_flow: "cassia" };
|
||||
const MOCK_BODY = JSON.stringify(MOCK_DATA);
|
||||
const MOCK_LENGTH = new TextEncoder().encode(MOCK_BODY).byteLength;
|
||||
|
||||
function getTargetUrl(input, method = "GET") {
|
||||
try {
|
||||
let rawUrl;
|
||||
if (typeof input === "string" || input instanceof URL) rawUrl = String(input);
|
||||
else if (input && typeof input.url === "string") rawUrl = input.url;
|
||||
else return null;
|
||||
const url = new URL(rawUrl, location.href);
|
||||
if (String(method).toUpperCase() !== "GET") return null;
|
||||
const hostMatched = url.hostname === TARGET_HOST || url.hostname.endsWith("." + TARGET_HOST);
|
||||
if (!hostMatched) return null;
|
||||
if (!TARGET_PATH.test(url.pathname)) return null;
|
||||
return url;
|
||||
} catch (error) { return null; }
|
||||
}
|
||||
|
||||
function createMockResponse(originalResponse) {
|
||||
const headers = new Headers(originalResponse.headers);
|
||||
headers.delete("content-length"); headers.delete("content-encoding");
|
||||
headers.delete("etag"); headers.delete("content-md5");
|
||||
headers.set("content-type", "application/json; charset=utf-8");
|
||||
headers.set("content-length", String(MOCK_LENGTH));
|
||||
headers.set("cache-control", "no-store");
|
||||
const response = new Response(MOCK_BODY, { status: 200, statusText: "OK", headers });
|
||||
try {
|
||||
Object.defineProperties(response, {
|
||||
url: { value: originalResponse.url, configurable: true },
|
||||
redirected: { value: originalResponse.redirected, configurable: true },
|
||||
type: { value: originalResponse.type, configurable: true }
|
||||
});
|
||||
} catch (_) {}
|
||||
return response;
|
||||
}
|
||||
|
||||
// Intercept Fetch
|
||||
const nativeFetch = window.fetch;
|
||||
window.fetch = async function (input, init) {
|
||||
const method = init?.method || (input instanceof Request ? input.method : "GET");
|
||||
const targetUrl = getTargetUrl(input, method);
|
||||
const originalResponse = await nativeFetch.apply(this, arguments);
|
||||
if (!targetUrl) return originalResponse;
|
||||
console.warn("[Cassia Mock] Fetch mocked:", targetUrl.href, MOCK_DATA);
|
||||
return createMockResponse(originalResponse);
|
||||
};
|
||||
|
||||
// Intercept XMLHttpRequest
|
||||
const XhrPrototype = XMLHttpRequest.prototype;
|
||||
const xhrInfo = new WeakMap();
|
||||
const loggedXhrs = new WeakSet();
|
||||
const nativeOpen = XhrPrototype.open;
|
||||
const nativeSend = XhrPrototype.send;
|
||||
const nativeGetResponseHeader = XhrPrototype.getResponseHeader;
|
||||
const nativeGetAllResponseHeaders = XhrPrototype.getAllResponseHeaders;
|
||||
|
||||
XhrPrototype.open = function (method, url) {
|
||||
let absoluteUrl;
|
||||
try { absoluteUrl = new URL(String(url), location.href).href; }
|
||||
catch (_) { absoluteUrl = String(url); }
|
||||
xhrInfo.set(this, { method: String(method || "GET").toUpperCase(), url: absoluteUrl });
|
||||
return nativeOpen.apply(this, arguments);
|
||||
};
|
||||
|
||||
function getMatchedXhr(xhr) {
|
||||
const info = xhrInfo.get(xhr);
|
||||
if (!info || xhr.readyState !== XMLHttpRequest.DONE) return null;
|
||||
return getTargetUrl(info.url, info.method);
|
||||
}
|
||||
|
||||
function replaceXhrGetter(propertyName, replacement) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(XhrPrototype, propertyName);
|
||||
if (!descriptor || typeof descriptor.get !== "function" || descriptor.configurable === false) return;
|
||||
const nativeGetter = descriptor.get;
|
||||
Object.defineProperty(XhrPrototype, propertyName, {
|
||||
...descriptor,
|
||||
get: function () {
|
||||
if (!getMatchedXhr(this)) return nativeGetter.call(this);
|
||||
return replacement.call(this, nativeGetter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
replaceXhrGetter("responseText", function (nativeGetter) {
|
||||
if (this.responseType !== "" && this.responseType !== "text") return nativeGetter.call(this);
|
||||
return MOCK_BODY;
|
||||
});
|
||||
|
||||
replaceXhrGetter("response", function (nativeGetter) {
|
||||
if (this.responseType === "json") return { checkout_flow: "cassia" };
|
||||
if (this.responseType === "" || this.responseType === "text") return MOCK_BODY;
|
||||
return nativeGetter.call(this);
|
||||
});
|
||||
|
||||
replaceXhrGetter("status", function () { return 200; });
|
||||
replaceXhrGetter("statusText", function () { return "OK"; });
|
||||
|
||||
XhrPrototype.getResponseHeader = function (name) {
|
||||
if (!getMatchedXhr(this)) return nativeGetResponseHeader.apply(this, arguments);
|
||||
switch (String(name).toLowerCase()) {
|
||||
case "content-type": return "application/json; charset=utf-8";
|
||||
case "content-length": return String(MOCK_LENGTH);
|
||||
case "cache-control": return "no-store";
|
||||
case "content-encoding": case "etag": case "content-md5": return null;
|
||||
default: return nativeGetResponseHeader.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
XhrPrototype.getAllResponseHeaders = function () {
|
||||
const originalHeaders = nativeGetAllResponseHeaders.apply(this, arguments);
|
||||
if (!getMatchedXhr(this)) return originalHeaders;
|
||||
const headers = String(originalHeaders || "").split(/\r?\n/).filter(Boolean).filter(function (line) {
|
||||
const name = line.split(":", 1)[0].trim().toLowerCase();
|
||||
return !["content-type", "content-length", "content-encoding", "cache-control", "etag", "content-md5"].includes(name);
|
||||
});
|
||||
headers.push("content-type: application/json; charset=utf-8", `content-length: ${MOCK_LENGTH}`, "cache-control: no-store");
|
||||
return headers.join("\r\n") + "\r\n";
|
||||
};
|
||||
|
||||
XhrPrototype.send = function () {
|
||||
this.addEventListener("readystatechange", function () {
|
||||
const targetUrl = getMatchedXhr(this);
|
||||
if (targetUrl && !loggedXhrs.has(this)) {
|
||||
loggedXhrs.add(this);
|
||||
console.warn("[Cassia Mock] XHR mocked:", targetUrl.href, MOCK_DATA);
|
||||
}
|
||||
});
|
||||
return nativeSend.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Status badge
|
||||
function showStatusBadge() {
|
||||
if (!document.documentElement) {
|
||||
document.addEventListener("DOMContentLoaded", showStatusBadge, { once: true });
|
||||
return;
|
||||
}
|
||||
if (document.getElementById("cassia-mock-badge")) return;
|
||||
const badge = document.createElement("div");
|
||||
badge.id = "cassia-mock-badge";
|
||||
badge.textContent = "Cassia Mock ON";
|
||||
Object.assign(badge.style, {
|
||||
position: "fixed", right: "12px", bottom: "12px", zIndex: "2147483647",
|
||||
padding: "7px 11px", color: "#ffffff", background: "#167c3a",
|
||||
borderRadius: "6px", fontSize: "12px", fontFamily: "sans-serif",
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,.3)"
|
||||
});
|
||||
document.documentElement.appendChild(badge);
|
||||
}
|
||||
|
||||
window.__cassiaMockInstalled = true;
|
||||
console.info("[Cassia Mock] Script loaded:", location.href);
|
||||
showStatusBadge();
|
||||
})();
|
||||
85
skills/bypass-ai/templates/cursor-invoice-mock.user.js
Normal file
85
skills/bypass-ai/templates/cursor-invoice-mock.user.js
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==UserScript==
|
||||
// @name Cursor Enterprise Invoice/SEPA Mock
|
||||
// @namespace gothbreach.cursor.invoice
|
||||
// @version 1.0.0
|
||||
// @description Mock Cursor tRPC billing endpoints to force enterprise invoice/SEPA flow
|
||||
// @match *://cursor.com/*
|
||||
// @run-at document-start
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
const BILLING_PATTERNS = [
|
||||
'/api/trpc/billing',
|
||||
'/api/trpc/checkout',
|
||||
'/api/billing/'
|
||||
];
|
||||
|
||||
const MOCK_DATA = {
|
||||
paymentMethods: ['invoice', 'sepa', 'wire_transfer', 'bank_transfer'],
|
||||
checkoutFlow: 'enterprise',
|
||||
invoiceBilling: { enabled: true, currency: 'eur' },
|
||||
sepaAvailable: true,
|
||||
bankTransferAvailable: true,
|
||||
poBilling: true,
|
||||
requiresCard: false
|
||||
};
|
||||
|
||||
const nativeFetch = window.fetch;
|
||||
window.fetch = async function (input, init) {
|
||||
const url = typeof input === 'string' ? input : input?.url || '';
|
||||
const response = await nativeFetch.apply(this, arguments);
|
||||
|
||||
const isBilling = BILLING_PATTERNS.some(p => url.includes(p));
|
||||
if (!isBilling) return response;
|
||||
|
||||
try {
|
||||
const cloned = response.clone();
|
||||
const data = await cloned.json();
|
||||
console.warn('[Cursor SEPA] Original:', JSON.stringify(data).substring(0, 300));
|
||||
|
||||
// tRPC wraps response in { result: { data: ... } }
|
||||
const mock = {
|
||||
...data,
|
||||
result: {
|
||||
data: {
|
||||
...(data?.result?.data || {}),
|
||||
...MOCK_DATA
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new Response(JSON.stringify(mock), {
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' })
|
||||
});
|
||||
} catch {
|
||||
return response;
|
||||
}
|
||||
};
|
||||
|
||||
// Status badge
|
||||
function showBadge() {
|
||||
if (document.getElementById('cursor-sepa-badge')) return;
|
||||
const badge = document.createElement('div');
|
||||
badge.id = 'cursor-sepa-badge';
|
||||
badge.textContent = 'Cursor SEPA ON';
|
||||
Object.assign(badge.style, {
|
||||
position: 'fixed', right: '12px', bottom: '12px', zIndex: '2147483647',
|
||||
padding: '7px 11px', color: '#fff', background: '#167c3a',
|
||||
borderRadius: '6px', fontSize: '12px', fontFamily: 'sans-serif',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,.3)'
|
||||
});
|
||||
(document.documentElement || document.body).appendChild(badge);
|
||||
}
|
||||
|
||||
console.info('[Cursor SEPA] Script loaded:', location.href);
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', showBadge, { once: true });
|
||||
} else {
|
||||
showBadge();
|
||||
}
|
||||
})();
|
||||
168
skills/bypass-ai/templates/sepa-billing-hijack-v3.user.js
Normal file
168
skills/bypass-ai/templates/sepa-billing-hijack-v3.user.js
Normal file
@@ -0,0 +1,168 @@
|
||||
// ==UserScript==
|
||||
// @name SEPA Billing Hijack — Universal v3.0
|
||||
// @namespace https://[REDACTED-NAME].dev/sepa
|
||||
// @version 3.0
|
||||
// @description Intercept billing endpoints on AI/IDE platforms. Force SEPA via Germany. 24 platforms: Cursor, Mistral, Groq, ElevenLabs, DeepSeek, HuggingFace, Replicate, Together AI, Vercel, Railway, Anthropic, OpenAI, Perplexity, Windsurf, Codeium, Bolt.new, Lovable, Aider, Continue, Cline + 4 reserve
|
||||
// @author ENI x [REDACTED-NAME]
|
||||
// @match https://cursor.com/*
|
||||
// @match https://*.cursor.com/*
|
||||
// @match https://console.mistral.ai/*
|
||||
// @match https://mistral.ai/*
|
||||
// @match https://console.groq.com/*
|
||||
// @match https://groq.com/*
|
||||
// @match https://elevenlabs.io/*
|
||||
// @match https://*.elevenlabs.io/*
|
||||
// @match https://platform.deepseek.com/*
|
||||
// @match https://chat.deepseek.com/*
|
||||
// @match https://huggingface.co/*
|
||||
// @match https://*.huggingface.co/*
|
||||
// @match https://replicate.com/*
|
||||
// @match https://*.replicate.com/*
|
||||
// @match https://api.together.xyz/*
|
||||
// @match https://*.together.xyz/*
|
||||
// @match https://vercel.com/*
|
||||
// @match https://*.vercel.com/*
|
||||
// @match https://railway.app/*
|
||||
// @match https://*.railway.app/*
|
||||
// @match https://console.anthropic.com/*
|
||||
// @match https://*.anthropic.com/*
|
||||
// @match https://platform.openai.com/*
|
||||
// @match https://*.openai.com/*
|
||||
// @match https://perplexity.ai/*
|
||||
// @match https://*.perplexity.ai/*
|
||||
// @match https://windsurf.com/*
|
||||
// @match https://*.windsurf.com/*
|
||||
// @match https://codeium.com/*
|
||||
// @match https://*.codeium.com/*
|
||||
// @match https://bolt.new/*
|
||||
// @match https://*.bolt.new/*
|
||||
// @match https://lovable.dev/*
|
||||
// @match https://*.lovable.dev/*
|
||||
// @match https://aider.chat/*
|
||||
// @match https://continue.dev/*
|
||||
// @match https://*.continue.dev/*
|
||||
// @match https://cline.bot/*
|
||||
// @match https://*.cline.bot/*
|
||||
// @grant none
|
||||
// @run-at document-start
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
const LOG_PREFIX = '[🅂🄴🄿🄰]';
|
||||
const PLATFORM = window.location.hostname;
|
||||
const BILLING_PATTERNS = [
|
||||
'/billing', '/checkout', '/payment', '/invoice', '/subscription',
|
||||
'/stripe', '/paddle', '/lemonsqueezy', '/chargebee', '/recurly',
|
||||
'/plan', '/pricing', '/upgrade', '/credits', '/add-credits',
|
||||
'/api/trpc/billing', '/api/trpc/payments', '/api/trpc/subscription',
|
||||
'/api/trpc/stripe', '/graphql', '/api/graphql',
|
||||
'/settings/billing', '/account/billing', '/team/billing',
|
||||
'/api/billing', '/api/payments', '/api/subscription',
|
||||
'/v1/billing', '/v1/payments', '/v1/subscription',
|
||||
];
|
||||
|
||||
// FETCH INTERCEPTOR
|
||||
const origFetch = window.fetch;
|
||||
window.fetch = async function(...args) {
|
||||
const url = typeof args[0] === 'string' ? args[0] : args[0]?.url || '';
|
||||
const opts = args[1] || {};
|
||||
const method = opts.method || 'GET';
|
||||
const isBilling = BILLING_PATTERNS.some(p => url.toLowerCase().includes(p));
|
||||
const isAuth = /login|signup|sign-in|sign-up|auth|token|session|csrf/i.test(url);
|
||||
const isImportant = isBilling || isAuth || method === 'POST';
|
||||
if (isImportant) {
|
||||
console.group(`${LOG_PREFIX} ${method} ${PLATFORM}`);
|
||||
console.log('URL:', url);
|
||||
if (opts.body) {
|
||||
try { console.log('Body:', JSON.parse(typeof opts.body === 'string' ? opts.body : '')); } catch(e) {}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const response = await origFetch.apply(this, args);
|
||||
if (isImportant) {
|
||||
const cloned = response.clone();
|
||||
const ct = response.headers.get('content-type') || '';
|
||||
if (ct.includes('json')) {
|
||||
cloned.json().then(json => console.log('Response:', JSON.stringify(json).substring(0, 5000))).catch(() => {});
|
||||
}
|
||||
console.log('Status:', response.status);
|
||||
console.groupEnd();
|
||||
}
|
||||
return response;
|
||||
} catch(err) {
|
||||
if (isImportant) { console.error(`${LOG_PREFIX} Fetch error:`, err); console.groupEnd(); }
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
// XHR INTERCEPTOR
|
||||
const origXHROpen = XMLHttpRequest.prototype.open;
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
||||
this._sepa_url = url;
|
||||
this._sepa_method = method;
|
||||
return origXHROpen.call(this, method, url, ...rest);
|
||||
};
|
||||
const origXHRSend = XMLHttpRequest.prototype.send;
|
||||
XMLHttpRequest.prototype.send = function(body) {
|
||||
const url = this._sepa_url || '';
|
||||
const method = this._sepa_method || 'GET';
|
||||
const isBilling = BILLING_PATTERNS.some(p => url.toLowerCase().includes(p));
|
||||
if (isBilling || method === 'POST') {
|
||||
console.group(`${LOG_PREFIX} XHR ${method} ${PLATFORM}`);
|
||||
console.log('URL:', url);
|
||||
this.addEventListener('load', function() {
|
||||
console.log('Status:', this.status);
|
||||
try { console.log('Response:', JSON.stringify(JSON.parse(this.responseText)).substring(0, 5000)); } catch(e) {}
|
||||
console.groupEnd();
|
||||
});
|
||||
}
|
||||
return origXHRSend.call(this, body);
|
||||
};
|
||||
|
||||
// STRIPE/CHECKOUT URL CAPTURE
|
||||
const origOpen = window.open;
|
||||
window.open = function(url, ...rest) {
|
||||
if (url && typeof url === 'string' && (url.includes('stripe.com') || url.includes('checkout.stripe') || url.includes('paddle.com') || url.includes('lemonsqueezy.com'))) {
|
||||
console.warn(`${LOG_PREFIX} 💳 CHECKOUT URL CAPTURED:`, url);
|
||||
try { navigator.clipboard.writeText(url); } catch(e) {}
|
||||
}
|
||||
return origOpen.call(this, url, ...rest);
|
||||
};
|
||||
|
||||
// FLOATING PANEL
|
||||
const panel = document.createElement('div');
|
||||
panel.id = 'sepa-panel';
|
||||
panel.innerHTML = `<style>
|
||||
#sepa-panel {position:fixed;bottom:10px;right:10px;z-index:999999;background:#0a0a0a;border:2px solid #00ff88;border-radius:8px;padding:10px 14px;font-family:monospace;font-size:12px;color:#00ff88;box-shadow:0 0 20px rgba(0,255,136,0.3);max-width:400px;cursor:move;}
|
||||
#sepa-panel .title {font-weight:bold;font-size:14px;margin-bottom:6px;border-bottom:1px solid #00ff8833;padding-bottom:4px;}
|
||||
#sepa-panel .close-btn {position:absolute;top:4px;right:8px;cursor:pointer;color:#f44;font-size:16px;font-weight:bold;}
|
||||
</style>
|
||||
<div class="close-btn" onclick="this.parentElement.remove()">✕</div>
|
||||
<div class="title">🅂🄴🄿🄰 Billing Hijack v3.0</div>
|
||||
<div>Platform: ${PLATFORM}</div>`;
|
||||
|
||||
// Make draggable
|
||||
let drag = false, dx, dy;
|
||||
panel.addEventListener('mousedown', e => { if (!e.target.classList.contains('close-btn')) { drag = true; dx = e.clientX - panel.getBoundingClientRect().left; dy = e.clientY - panel.getBoundingClientRect().top; panel.style.cursor = 'grabbing'; }});
|
||||
document.addEventListener('mousemove', e => { if (drag) { panel.style.left = (e.clientX - dx) + 'px'; panel.style.top = (e.clientY - dy) + 'px'; panel.style.right = 'auto'; panel.style.bottom = 'auto'; }});
|
||||
document.addEventListener('mouseup', () => { drag = false; panel.style.cursor = 'move'; });
|
||||
|
||||
const tryInject = setInterval(() => { if (document.body) { document.body.appendChild(panel); clearInterval(tryInject); } }, 100);
|
||||
|
||||
// GLOBAL EXPORT
|
||||
window.__SEPA_HIJACK = {
|
||||
version: '3.0',
|
||||
platform: PLATFORM,
|
||||
dump: () => {
|
||||
console.group(`${LOG_PREFIX} FULL STATE DUMP`);
|
||||
console.log('Platform:', PLATFORM);
|
||||
console.log('URL:', window.location.href);
|
||||
console.log('Cookies:', document.cookie);
|
||||
console.log('LocalStorage keys:', Object.keys(localStorage));
|
||||
console.groupEnd();
|
||||
}
|
||||
};
|
||||
console.warn(`${LOG_PREFIX} ✅ SEPA Billing Hijack v3.0 loaded on ${PLATFORM}`);
|
||||
console.warn(`${LOG_PREFIX} 📋 __SEPA_HIJACK.dump() for full state`);
|
||||
})();
|
||||
92
skills/bypass-ai/templates/universal-invoice-mock.user.js
Normal file
92
skills/bypass-ai/templates/universal-invoice-mock.user.js
Normal file
@@ -0,0 +1,92 @@
|
||||
// ==UserScript==
|
||||
// @name Universal Invoice/SEPA Mock — Multi-Platform
|
||||
// @namespace gothbreach.universal.invoice
|
||||
// @version 1.0.0
|
||||
// @description Mock billing/checkout endpoints across 9+ platforms to force enterprise invoice/SEPA flow
|
||||
// @match *://claude.ai/*
|
||||
// @match *://cursor.com/*
|
||||
// @match *://console.mistral.ai/*
|
||||
// @match *://platform.deepseek.com/*
|
||||
// @match *://github.com/*
|
||||
// @match *://console.groq.com/*
|
||||
// @match *://elevenlabs.io/*
|
||||
// @match *://*.perplexity.ai/*
|
||||
// @match *://codeium.com/*
|
||||
// @run-at document-start
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
const BILLING_PATTERNS = [
|
||||
'checkout_capabilities', 'billing/capabilities', 'billing/methods',
|
||||
'payment-methods', 'payment_methods', 'checkout/options',
|
||||
'billing/plans', 'subscription/checkout', 'billing/checkout',
|
||||
'api/trpc/billing', 'api/trpc/checkout', 'user/subscription',
|
||||
'/billing/', '/copilot/'
|
||||
];
|
||||
|
||||
const MOCK_PAYLOAD = {
|
||||
checkout_flow: 'invoice',
|
||||
payment_methods: ['sepa', 'invoice', 'wire_transfer', 'bank_transfer'],
|
||||
invoice_billing: { enabled: true, currency: 'eur' },
|
||||
sepa_available: true,
|
||||
bank_transfer_available: true,
|
||||
enterprise_billing: true,
|
||||
billing_type: 'invoice',
|
||||
poBilling: true,
|
||||
requiresCard: false
|
||||
};
|
||||
|
||||
const nativeFetch = window.fetch;
|
||||
window.fetch = async function (input, init) {
|
||||
const url = typeof input === 'string' ? input : input?.url || '';
|
||||
const response = await nativeFetch.apply(this, arguments);
|
||||
|
||||
const isBilling = BILLING_PATTERNS.some(p => url.includes(p));
|
||||
if (!isBilling) return response;
|
||||
|
||||
try {
|
||||
const cloned = response.clone();
|
||||
const data = await cloned.json();
|
||||
console.warn('[Invoice Mock]', url, '←', JSON.stringify(data).substring(0, 200));
|
||||
|
||||
// Deep merge: tRPC wraps in result.data, REST is flat
|
||||
const isTRPC = url.includes('/api/trpc/');
|
||||
const mock = isTRPC
|
||||
? { ...data, result: { data: { ...(data?.result?.data || {}), ...MOCK_PAYLOAD } } }
|
||||
: { ...data, ...MOCK_PAYLOAD };
|
||||
|
||||
return new Response(JSON.stringify(mock), {
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' })
|
||||
});
|
||||
} catch {
|
||||
return response;
|
||||
}
|
||||
};
|
||||
|
||||
// Status badge
|
||||
function showBadge() {
|
||||
if (document.getElementById('universal-invoice-badge')) return;
|
||||
const badge = document.createElement('div');
|
||||
badge.id = 'universal-invoice-badge';
|
||||
badge.textContent = 'Invoice Mock ON';
|
||||
Object.assign(badge.style, {
|
||||
position: 'fixed', right: '12px', bottom: '12px', zIndex: '2147483647',
|
||||
padding: '7px 11px', color: '#fff', background: '#167c3a',
|
||||
borderRadius: '6px', fontSize: '12px', fontFamily: 'sans-serif',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,.3)'
|
||||
});
|
||||
(document.documentElement || document.body).appendChild(badge);
|
||||
}
|
||||
|
||||
console.info('[Universal Invoice Mock] Loaded on', location.hostname);
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', showBadge, { once: true });
|
||||
} else {
|
||||
showBadge();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user