Intercepts Rork snapshot data and allows exporting code which stupidly is a premium feature of rork
// ==UserScript==
// @name Rork Downloader
// @namespace https://github.com/deeeeone/userscripts
// @version 1.4
// @description Intercepts Rork snapshot data and allows exporting code which stupidly is a premium feature of rork
// @author Custom
// @match https://rork.com/p/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// we need jszip to zip everything up
const jszipScript = document.createElement('script');
jszipScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.0/jszip.min.js';
document.head.appendChild(jszipScript);
let latestSnapshot = null;
let latestSnapshotId = null;
function saveSnapshotToDB(id, snapshotObj) {
return new Promise((resolve, reject) => {
const req = indexedDB.open('rorkSnapshots', 1);
req.onupgradeneeded = function(e) {
const db = e.target.result;
if (!db.objectStoreNames.contains('snapshots')) {
db.createObjectStore('snapshots');
}
};
req.onsuccess = function(e) {
const db = e.target.result;
const tx = db.transaction('snapshots', 'readwrite');
const store = tx.objectStore('snapshots');
store.put(snapshotObj, id);
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
};
req.onerror = () => reject(req.error);
});
}
function getSnapshotFromDB(id) {
return new Promise((resolve, reject) => {
const req = indexedDB.open('rorkSnapshots', 1);
req.onupgradeneeded = function(e) {
e.target.result.createObjectStore('snapshots');
};
req.onsuccess = function(e) {
const db = e.target.result;
const tx = db.transaction('snapshots', 'readonly');
const store = tx.objectStore('snapshots');
const getReq = store.get(id);
getReq.onsuccess = () => resolve(getReq.result);
getReq.onerror = () => reject(getReq.error);
};
req.onerror = () => reject(req.error);
});
}
// cheating but idc it works
const originalFetch = window.fetch;
window.fetch = async function(...args) {
const response = await originalFetch.apply(this, args);
const url = args[0];
if (typeof url === 'string' && url.includes('/trpc/projects.fetchSnapshot')) {
response.clone().json().then(data => {
try {
const json = data.result?.data?.json;
if (!json) return;
latestSnapshot = json.snapshot;
latestSnapshotId = json.snapshotId;
// Save to IndexedDB
saveSnapshotToDB(latestSnapshotId, latestSnapshot).catch(console.error);
console.log('Rork snapshot stored:', latestSnapshotId);
} catch (err) {
console.error('Error parsing Rork snapshot:', err);
}
}).catch(console.error);
}
return response;
};
// build zip file from the snapshot object
function buildZip(snapshotObj) {
const zip = new JSZip();
for (const [path, entry] of Object.entries(snapshotObj)) {
if (entry.type === 'folder') {
zip.folder(path);
} else if (entry.type === 'file') {
zip.file(path, entry.contents);
}
}
return zip;
}
// download zip file
async function downloadSnapshot(id, snapshotObj) {
if (!window.JSZip) {
alert('JSZip not loaded yet. Please try again in a moment.');
return;
}
const zip = buildZip(snapshotObj);
const blob = await zip.generateAsync({ type: 'blob' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `rork_snapshot_${id}.zip`;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}
// add into header
function insertButton() {
const header = document.querySelector('header');
if (!header) return;
if (document.getElementById('rork-download-btn')) return;
const btn = document.createElement('button');
btn.id = 'rork-download-btn';
btn.innerText = 'Download Snapshot';
btn.style.backgroundColor = '#10B981'; // emerald cause why not
btn.style.color = '#FFFFFF';
btn.style.border = 'none';
btn.style.padding = '8px 12px';
btn.style.marginLeft = '10px';
btn.style.borderRadius = '4px';
btn.style.fontSize = '14px';
btn.style.cursor = 'pointer';
btn.addEventListener('click', async () => {
if (latestSnapshot && latestSnapshotId) {
await downloadSnapshot(latestSnapshotId, latestSnapshot);
} else if (latestSnapshotId) {
// load everything from indexeddb
const stored = await getSnapshotFromDB(latestSnapshotId);
if (stored) {
await downloadSnapshot(latestSnapshotId, stored);
} else {
alert('Snapshot data not available yet. Please wait for the project to load.');
}
} else {
alert('No snapshot captured yet. Please wait for the project to load.');
}
});
header.appendChild(btn);
}
// wait WAIT WAITTT
function waitForHeader() {
const header = document.querySelector('header');
if (header) {
insertButton();
} else {
requestAnimationFrame(waitForHeader);
}
}
document.addEventListener('DOMContentLoaded', () => {
waitForHeader();
});
})();