Add cloud state sync
This commit is contained in:
@@ -2,3 +2,4 @@ node_modules/
|
||||
.DS_Store
|
||||
.vercel
|
||||
.claude/
|
||||
.env*
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { get, put } from "@vercel/blob";
|
||||
|
||||
const STATE_PATH = process.env.PMA_STATE_PATH || "shared/state.json";
|
||||
|
||||
async function readJsonBlob() {
|
||||
const blob = await get(STATE_PATH, { access: "private" });
|
||||
if (!blob || blob.statusCode !== 200 || !blob.stream) return null;
|
||||
const text = await new Response(blob.stream).text();
|
||||
return text ? JSON.parse(text) : null;
|
||||
}
|
||||
|
||||
export default async function handler(req, res) {
|
||||
res.setHeader("Cache-Control", "no-store");
|
||||
try {
|
||||
if (!process.env.BLOB_READ_WRITE_TOKEN && !process.env.VERCEL_OIDC_TOKEN) {
|
||||
return res.status(503).json({ ok: false, error: "Cloud state is not configured" });
|
||||
}
|
||||
|
||||
if (req.method === "GET") {
|
||||
return res.status(200).json({ ok: true, state: await readJsonBlob() });
|
||||
}
|
||||
|
||||
if (req.method === "POST") {
|
||||
const body = typeof req.body === "string" ? JSON.parse(req.body || "{}") : (req.body || {});
|
||||
if (!body || typeof body !== "object" || !body.items || typeof body.items !== "object") {
|
||||
return res.status(400).json({ ok: false, error: "Invalid state payload" });
|
||||
}
|
||||
const state = { version: 1, updated_at: new Date().toISOString(), items: body.items };
|
||||
await put(STATE_PATH, JSON.stringify(state), {
|
||||
access: "private",
|
||||
allowOverwrite: true,
|
||||
contentType: "application/json",
|
||||
cacheControlMaxAge: 60,
|
||||
});
|
||||
return res.status(200).json({ ok: true, state });
|
||||
}
|
||||
|
||||
res.setHeader("Allow", "GET, POST");
|
||||
return res.status(405).json({ ok: false, error: "Method not allowed" });
|
||||
} catch (err) {
|
||||
const message = err && err.message ? err.message : "State sync failed";
|
||||
return res.status(500).json({ ok: false, error: message });
|
||||
}
|
||||
}
|
||||
+29
-9
@@ -381,9 +381,9 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-h"><h3>Device sync</h3></div>
|
||||
<p class="muted" style="margin:0">Portfolios, returns, reports, suggestions, and chart history are saved in this browser. To make another device match, click <b>Copy Sync</b> here, then open the site on the other device and use <b>Import Sync</b>.</p>
|
||||
<p class="muted" style="margin:0">Portfolios, returns, reports, suggestions, and chart history now sync through the site automatically. <b>Copy Sync</b> and <b>Import Sync</b> remain as a fallback for moving the exact state between devices.</p>
|
||||
</div>
|
||||
<div class="disclaimer">⚠️ <b>Paper trading only — not financial advice.</b> Nothing here places real orders or moves money. The analysis is a transparent heuristic. All portfolios live in this browser's local storage (each device keeps its own).</div>
|
||||
<div class="disclaimer">⚠️ <b>Paper trading only — not financial advice.</b> Nothing here places real orders or moves money. The analysis is a transparent heuristic. Portfolios sync through the site when cloud state is available, with this browser keeping a local backup.</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
@@ -397,7 +397,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
|
||||
/* ============================================================
|
||||
Polymarket Arena — fully client-side.
|
||||
Fetches live markets, scores them, and runs ten competing
|
||||
paper-trading agents. State persists in localStorage.
|
||||
paper-trading agents. State syncs through /api/state when configured and uses localStorage as the on-device cache.
|
||||
============================================================ */
|
||||
|
||||
const GAMMA = "https://gamma-api.polymarket.com";
|
||||
@@ -582,6 +582,24 @@ function loadState(){
|
||||
function saveState(st){localStorage.setItem(AGENTS_KEY,JSON.stringify(st));}
|
||||
function loadSuggestions(){try{const s=localStorage.getItem(SUG_KEY);return s?JSON.parse(s):{date:null,suggestions:[]};}catch(e){return {date:null,suggestions:[]};}}
|
||||
function saveSuggestions(sugs){const p={date:todayStr(),generated_at:nowIso(),suggestions:sugs};localStorage.setItem(SUG_KEY,JSON.stringify(p));return p;}
|
||||
function collectSyncItems(){const items={};SYNC_KEYS.forEach(k=>{const v=localStorage.getItem(k);if(v!=null)items[k]=v;});return items;}
|
||||
function applySyncItems(items){if(!items||typeof items!=="object")return false;SYNC_KEYS.forEach(k=>{if(items[k]!=null)localStorage.setItem(k,items[k]);});return true;}
|
||||
async function pushCloudState(){
|
||||
try{
|
||||
const r=await fetch("/api/state",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:collectSyncItems()})});
|
||||
if(!r.ok)throw new Error("cloud sync unavailable");
|
||||
return true;
|
||||
}catch(e){return false;}
|
||||
}
|
||||
async function pullCloudState(){
|
||||
try{
|
||||
const r=await fetch("/api/state",{cache:"no-store"});
|
||||
if(!r.ok)return false;
|
||||
const d=await r.json();
|
||||
if(d&&d.state&&applySyncItems(d.state.items)){toast("Cloud state loaded for this device.");return true;}
|
||||
}catch(e){}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ---------- Agent mechanics ---------- */
|
||||
const equity=(p)=>p.cash+p.positions.reduce((s,x)=>s+x.shares*x.current_price,0);
|
||||
@@ -995,6 +1013,7 @@ async function runDailyCycle(){
|
||||
}
|
||||
st.date=todayStr();st.last_run=SNAP_TS;
|
||||
saveState(st);
|
||||
await pushCloudState();
|
||||
setStatus("up to date",false);
|
||||
return {suggestions:sugs.length};
|
||||
}finally{SNAP_TS=null;}
|
||||
@@ -1333,8 +1352,7 @@ $("runBtn").addEventListener("click",async()=>{
|
||||
const b64Encode=(s)=>btoa(Array.from(new TextEncoder().encode(s),b=>String.fromCharCode(b)).join(""));
|
||||
const b64Decode=(s)=>new TextDecoder().decode(Uint8Array.from(atob(s),c=>c.charCodeAt(0)));
|
||||
function buildSyncCode(){
|
||||
const data={version:1,exported_at:nowIso(),items:{}};
|
||||
SYNC_KEYS.forEach(k=>{const v=localStorage.getItem(k);if(v!=null)data.items[k]=v;});
|
||||
const data={version:1,exported_at:nowIso(),items:collectSyncItems()};
|
||||
return "PMA1."+b64Encode(JSON.stringify(data));
|
||||
}
|
||||
async function readClipboardOrPrompt(){
|
||||
@@ -1354,25 +1372,27 @@ $("importStateBtn").addEventListener("click",async()=>{
|
||||
const payload=JSON.parse(b64Decode(code.replace(/^PMA1\./,"")));
|
||||
if(!payload||payload.version!==1||!payload.items)throw new Error("Bad sync code");
|
||||
if(!confirm("Import this sync state and replace this device's current local portfolio data?"))return;
|
||||
SYNC_KEYS.forEach(k=>{if(payload.items[k]!=null)localStorage.setItem(k,payload.items[k]);});
|
||||
applySyncItems(payload.items);
|
||||
await pushCloudState();
|
||||
toast("Sync imported. This device now matches the copied state.");
|
||||
renderAll();showTab(location.hash.slice(1)||"portfolio");
|
||||
}catch(e){toast("Import failed. Check that the sync code was copied fully.");}
|
||||
});
|
||||
$("resetBtn").addEventListener("click",()=>{
|
||||
if(!confirm("Reset all ten agents to their $10,000 starting balance?"))return;
|
||||
saveState(defaultState());localStorage.removeItem(SUG_KEY);toast("All agents reset.");renderAll();
|
||||
saveState(defaultState());localStorage.removeItem(SUG_KEY);pushCloudState();toast("All agents reset.");renderAll();
|
||||
});
|
||||
|
||||
/* On load: first visit runs a 7-day backtest; afterwards a live daily update. */
|
||||
(async function init(){
|
||||
showTab(location.hash.slice(1)||"overview");
|
||||
const cloudLoaded=await pullCloudState();
|
||||
renderAll();
|
||||
const st=loadState();
|
||||
const btn=$("runBtn");
|
||||
if(!st.seeded){
|
||||
btn.disabled=true;btn.textContent="Backtesting…";
|
||||
try{await backtestWeek(st);st.date=todayStr();st.last_run=nowIso();saveState(st);renderAll();
|
||||
try{await backtestWeek(st);st.date=todayStr();st.last_run=nowIso();saveState(st);await pushCloudState();renderAll();
|
||||
toast("7-day backtest complete — live tracking begins today.");}
|
||||
catch(e){setStatus("backtest error — click Run",false);}
|
||||
btn.disabled=false;btn.textContent="Run cycle";
|
||||
@@ -1381,7 +1401,7 @@ $("resetBtn").addEventListener("click",()=>{
|
||||
try{await runDailyCycle();renderAll();toast("Daily update ready.");}
|
||||
catch(e){setStatus("error — click Run to retry",false);}
|
||||
btn.disabled=false;btn.textContent="Run cycle";
|
||||
}else{setStatus("up to date",false);}
|
||||
}else{setStatus("up to date",false);if(!cloudLoaded)pushCloudState();}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Generated
+363
@@ -0,0 +1,363 @@
|
||||
{
|
||||
"name": "polymarket-analyst",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@vercel/blob": "2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/blob": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/blob/-/blob-2.5.0.tgz",
|
||||
"integrity": "sha512-ke6WnMMYlUu9nBFmyjwEkC2o03Ku2X7QIeJ3KtlOJzblS/8Xau209zt0ic76rd7IvV5nrKCH/BzP4MkFmoSLuw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@vercel/oidc": "^3.6.1",
|
||||
"async-retry": "^1.3.3",
|
||||
"is-buffer": "^2.0.5",
|
||||
"is-node-process": "^1.2.0",
|
||||
"throttleit": "^2.1.0",
|
||||
"undici": "^6.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/cli-config": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/cli-config/-/cli-config-0.2.0.tgz",
|
||||
"integrity": "sha512-fJRRRB7734BDuXZ89yBEaA2ncYhH7bWX30mk04W80J6VAfQc+4iB8lyzAdaGpFV3/vNlkt9VZt+/uoQoWX6UsQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"xdg-app-paths": "5",
|
||||
"zod": "4.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/cli-exec": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/cli-exec/-/cli-exec-1.0.0.tgz",
|
||||
"integrity": "sha512-kQF8LGie/Hbdq9/psJxLE7owRTcqMQMhgybU04gCeR7cbQAr5t8OrjefDNColJv1QSSucFt4pLwRiARVmlOnug==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"execa": "5.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/oidc": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.8.0.tgz",
|
||||
"integrity": "sha512-r00laGW6Pv778RoR6M2NxX91ycSj+PBwVo+fOb9Bif+F0IyUKt25zrvBzfEzQpeAzbqOgPZyQibEWDdDFApd+A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@vercel/cli-config": "0.2.0",
|
||||
"@vercel/cli-exec": "1.0.0",
|
||||
"jose": "^5.9.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/async-retry": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz",
|
||||
"integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"retry": "0.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.3",
|
||||
"get-stream": "^6.0.0",
|
||||
"human-signals": "^2.1.0",
|
||||
"is-stream": "^2.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^4.0.1",
|
||||
"onetime": "^5.1.2",
|
||||
"signal-exit": "^3.0.3",
|
||||
"strip-final-newline": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=10.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-buffer": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-node-process": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
|
||||
"integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
|
||||
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/onetime": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-fn": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/os-paths": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz",
|
||||
"integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
||||
"integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/strip-final-newline": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/throttleit": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz",
|
||||
"integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
|
||||
"integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/xdg-app-paths": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.5.1.tgz",
|
||||
"integrity": "sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"os-paths": "^4.0.1",
|
||||
"xdg-portable": "^7.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xdg-portable": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz",
|
||||
"integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"os-paths": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz",
|
||||
"integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@vercel/blob": "2.5.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user