eyez / src /saveDemo.ts
pima5's picture
Upload folder using huggingface_hub
e138613 verified
Raw
History Blame Contribute Delete
5.65 kB
import "dotenv/config";
import { mkdirSync, rmSync, writeFileSync } from "fs";
import {
ARC_EXPLORER_URL,
createArcPaymentClient,
getClientPrivateKey,
} from "./arc.js";
const SERVER_URL = process.env.SERVER_URL || "http://localhost:3001";
const EVM_PRIVATE_KEY = getClientPrivateKey();
const targetUrl =
process.argv[2] || process.env.DEMO_URL || "https://x.com/circle";
const outputDir = "docs/demoOutput";
if (!EVM_PRIVATE_KEY) {
console.error("ERROR: EVM_PRIVATE_KEY or ARC_PRIVATE_KEY not set in .env");
process.exit(1);
}
const { client, httpClient } = createArcPaymentClient(EVM_PRIVATE_KEY);
interface CaptureLogResponse {
title?: string;
description?: string;
captureTimeMs?: number;
content?: string;
headings?: Array<{
level?: string;
text?: string;
}>;
links?: Array<{
text?: string;
href?: string;
}>;
refund?: unknown;
}
function now(): string {
return new Date().toISOString();
}
function preview(text?: string | null, max = 3000): string {
if (!text) return "(empty)";
return text.length > max ? `${text.slice(0, max)}\n... [truncated]` : text;
}
async function recordPlainFetch(url: string): Promise<string> {
const started = Date.now();
const response = await fetch(url, {
headers: {
"user-agent": "eyezDemo/1.0",
},
});
const body = await response.text();
const elapsed = Date.now() - started;
return [
`# Plain fetch demo`,
`Recorded: ${now()}`,
`Target: ${url}`,
`Command: fetch("${url}")`,
``,
`Status: ${response.status} ${response.statusText}`,
`Final URL: ${response.url}`,
`Content-Type: ${response.headers.get("content-type") || "(none)"}`,
`Elapsed: ${elapsed}ms`,
`Body length: ${body.length} chars`,
``,
`## Body preview`,
preview(body),
``,
].join("\n");
}
async function recordPaidCapture(url: string): Promise<string> {
const endpoint = `${SERVER_URL}/capture?url=${encodeURIComponent(url)}`;
const log = [
`# eyez paid capture demo`,
`Recorded: ${now()}`,
`Target: ${url}`,
`Endpoint: ${endpoint}`,
``,
];
const firstTry = await fetch(endpoint);
log.push(`Initial response: ${firstTry.status} ${firstTry.statusText}`);
if (firstTry.status !== 402) {
const body = await firstTry.text();
log.push(`Expected 402 Payment Required but got ${firstTry.status}.`);
log.push(``, `## Response body`, preview(body), ``);
return log.join("\n");
}
const paymentRequired = httpClient.getPaymentRequiredResponse((name) =>
firstTry.headers.get(name),
);
const requirement = paymentRequired.accepts[0];
if (!requirement) {
throw new Error("Payment required response did not include any accepted payments");
}
log.push(`x402 version: ${paymentRequired.x402Version}`);
log.push(`Scheme: ${requirement.scheme}`);
log.push(`Network: ${requirement.network}`);
log.push(`Asset: ${requirement.asset}`);
log.push(`Amount: ${requirement.amount}`);
log.push(`Pay to: ${requirement.payTo}`);
log.push(``, `Creating payment payload...`);
const paymentPayload = await client.createPaymentPayload(paymentRequired);
const headers = httpClient.encodePaymentSignatureHeader(paymentPayload);
const started = Date.now();
const paidResponse = await fetch(endpoint, { headers });
const elapsed = Date.now() - started;
log.push(`Paid response: ${paidResponse.status} ${paidResponse.statusText}`);
log.push(`Paid elapsed: ${elapsed}ms`);
try {
const settlement = httpClient.getPaymentSettleResponse((name) =>
paidResponse.headers.get(name),
);
log.push(`Settlement success: ${settlement.success}`);
log.push(`Settlement tx: ${settlement.transaction}`);
log.push(`Settlement network: ${settlement.network}`);
if (settlement.transaction) {
log.push(`Explorer: ${ARC_EXPLORER_URL}/tx/${settlement.transaction}`);
}
} catch {
log.push(`Settlement header: (missing)`);
}
const data = (await paidResponse.json()) as CaptureLogResponse;
log.push(``, `## Capture result`);
log.push(`Title: ${data.title || "(none)"}`);
if (data.description) log.push(`Description: ${data.description}`);
log.push(`Capture time: ${data.captureTimeMs}ms`);
log.push(`Content length: ${data.content?.length || 0} chars`);
if (data.headings?.length) {
log.push(``, `## Headings`);
for (const heading of data.headings.slice(0, 10)) {
log.push(`${heading.level}: ${heading.text}`);
}
}
if (data.links?.length) {
log.push(``, `## Links`);
for (const link of data.links.slice(0, 10)) {
log.push(`${link.text?.slice(0, 80) || "(untitled)"} -> ${link.href}`);
}
}
if (data.refund) {
log.push(``, `## Refund`);
log.push(JSON.stringify(data.refund, null, 2));
}
log.push(``, `## Content preview`, preview(data.content), ``);
return log.join("\n");
}
rmSync(outputDir, { recursive: true, force: true });
mkdirSync(outputDir, { recursive: true });
console.log(`Recording plain fetch demo for ${targetUrl}...`);
writeFileSync(`${outputDir}/plainFetch.log`, await recordPlainFetch(targetUrl));
console.log(`Recording paid eyez capture demo for ${targetUrl}...`);
writeFileSync(`${outputDir}/eyezCapture.log`, await recordPaidCapture(targetUrl));
writeFileSync(
`${outputDir}/README.md`,
[
`# Demo Output`,
``,
`Generated by \`node dist/saveDemo.js ${targetUrl}\`.`,
``,
`- \`plainFetch.log\`: direct Node fetch against the target URL.`,
`- \`eyezCapture.log\`: x402 paid eyez capture against the same URL.`,
``,
].join("\n"),
);
console.log(`Done. Logs written to ${outputDir}/`);