File size: 3,538 Bytes
a4ad7d1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import "dotenv/config";
import { writeFileSync } from "fs";
import { Transaction, TransactionBuilder } from "@stellar/stellar-sdk";
import { x402Client, x402HTTPClient } from "@x402/fetch";
import { createEd25519Signer, getNetworkPassphrase } from "@x402/stellar";
import { ExactStellarScheme } from "@x402/stellar/exact/client";

const SERVER_URL = process.env.SERVER_URL || "https://tantk-rendergate.hf.space";
const NETWORK = "stellar:testnet";

const signer = createEd25519Signer(process.env.STELLAR_PRIVATE_KEY, NETWORK);
const client = new x402Client().register(
  "stellar:*",
  new ExactStellarScheme(signer, { url: "https://soroban-testnet.stellar.org" }),
);
const httpClient = new x402HTTPClient(client);

async function paidRender(targetUrl) {
  const endpoint = `${SERVER_URL}/render?url=${encodeURIComponent(targetUrl)}`;
  const r1 = await fetch(endpoint);
  if (r1.status !== 402) return await r1.json();

  const pr = httpClient.getPaymentRequiredResponse((n) => r1.headers.get(n));
  let pp = await client.createPaymentPayload(pr);
  const np = getNetworkPassphrase(NETWORK);
  const tx = new Transaction(pp.payload.transaction, np);
  const sd = tx.toEnvelope().v1()?.tx()?.ext()?.sorobanData();
  if (sd) {
    pp = {
      ...pp,
      payload: {
        ...pp.payload,
        transaction: TransactionBuilder.cloneFrom(tx, {
          fee: "1", sorobanData: sd, networkPassphrase: np,
        }).build().toXDR(),
      },
    };
  }
  const headers = httpClient.encodePaymentSignatureHeader(pp);
  const r2 = await fetch(endpoint, { headers });
  return await r2.json();
}

function formatOutput(data, targetUrl) {
  let out = `=== RenderGate: ${targetUrl} ===\n`;
  out += `Payment: ${data.payment?.price} USDC on ${data.payment?.network}\n`;
  out += `Render time: ${data.renderTimeMs}ms\n\n`;

  out += `Title: ${data.title}\n`;
  if (data.description) out += `Description: ${data.description}\n`;
  out += `\n`;

  if (data.headings?.length > 0) {
    out += `Headings (${data.headings.length}):\n`;
    data.headings.slice(0, 15).forEach((h) => {
      out += `  ${h.level}: ${h.text}\n`;
    });
    out += `\n`;
  }

  if (data.links?.length > 0) {
    out += `Links (${data.links.length}):\n`;
    data.links.slice(0, 15).forEach((l) => {
      out += `  ${l.text.substring(0, 50)}${l.href}\n`;
    });
    out += `\n`;
  }

  if (data.refund) {
    out += `*** AUTO-REFUND ***\n`;
    out += `Reason: ${data.refund.reason}\n`;
    out += `Refund amount: ${data.refund.amount}\n`;
    out += `Refund transaction: ${data.refund.transaction}\n`;
    out += `Verify: https://stellar.expert/explorer/testnet/tx/${data.refund.transaction}\n\n`;
  }

  out += `Content (${data.content?.length} chars):\n`;
  out += data.content || "(empty)";
  return out;
}

const sites = [
  { name: "1-twitter", url: "https://x.com/stellarorg" },
  { name: "2-linkedin", url: "https://www.linkedin.com/company/stellar-development-foundation" },
  { name: "3-soroswap", url: "https://soroswap.finance" },
  { name: "4-producthunt", url: "https://www.producthunt.com" },
];

for (const site of sites) {
  console.log(`Rendering ${site.name}...`);
  try {
    const data = await paidRender(site.url);
    const output = formatOutput(data, site.url);
    const path = `demo-output/${site.name}-with.txt`;
    writeFileSync(path, output);
    console.log(`  Saved: ${path} (${data.content?.length} chars, refund: ${!!data.refund})`);
  } catch (err) {
    console.error(`  Failed: ${err.message}`);
  }
}

console.log("Done!");