UNPKG

ws402

Version:

WebSocket implementation of X402 protocol for pay-as-you-go digital resources with automatic refunds

461 lines (378 loc) 15 kB
# 📄 WS402: HTTP Resources with WebSocket Time Tracking ## 🎯 Use Case: PDF and HTTP Resources ### The Problem You want to serve a PDF (or image, document, etc.) via regular HTTP, but charge based on the time the user has it open/consuming. ### The Solution **Two separate channels:** 1. **HTTP** Serves the complete resource (PDF) 2. **WebSocket** Tracks usage time ## 🔄 Complete Flow ``` ┌──────────────────────────────────────────────────────────────┐ PHASE 1: REQUEST AND PAYMENT └──────────────────────────────────────────────────────────────┘ Client Server 1. HTTP GET /api/resource/pdf-report-2024/schema ├──────────────────────────────────────────────────► └─► Returns WS402 Schema { websocketEndpoint: "ws://...", pricing: { 2. Schema received pricePerSecond: 5, │◄──────────────────────────────────── estimatedTime: 600s, totalPrice: 3000 wei } } 3. WebSocket connect ws://server/ws402?resourceId=pdf-report-2024 ├──────────────────────────────────────────────────► └─► Connection established 4. Send payment_proof (3000 wei total) ├──────────────────────────────────────────────────► └─► Verify payment └─► Create session └─► Generate HTTP token 5. session_started + http_access_granted { type: "http_access_granted", httpToken: "http_123abc...", resourceUrl: "http://server/api/resource/pdf-report-2024?token=http_123abc" } │◄──────────────────────────────────────────────── ┌──────────────────────────────────────────────────────────────┐ PHASE 2: RESOURCE DOWNLOAD (HTTP) └──────────────────────────────────────────────────────────────┘ Client Server 6. HTTP GET /api/resource/pdf-report-2024?token=http_123abc ├──────────────────────────────────────────────────► └─► Verify token └─► Check session active └─► Serve PDF file 7. PDF file received (COMPLETE!) [binary PDF data...] │◄──────────────────────────────────────────────── [Client opens PDF in browser] [WebSocket remains active in background] ┌──────────────────────────────────────────────────────────────┐ PHASE 3: TIME TRACKING (WebSocket in background) └──────────────────────────────────────────────────────────────┘ Client Server [WebSocket connection remains open] 8. usage_update (every 3 seconds) { elapsedSeconds: 3, consumedAmount: 15 wei (3s × 5wei), remainingBalance: 2985 wei } │◄──────────────────────────────────────────────── 9. usage_update { elapsedSeconds: 6, consumedAmount: 30 wei, remainingBalance: 2970 wei } │◄──────────────────────────────────────────────── [User reads PDF for 2 minutes...] 10. usage_update { elapsedSeconds: 120, consumedAmount: 600 wei (2min), remainingBalance: 2400 wei } │◄──────────────────────────────────────────────── ┌──────────────────────────────────────────────────────────────┐ PHASE 4: CLIENT FINISHES AND DISCONNECTS └──────────────────────────────────────────────────────────────┘ Client Server [User closes PDF or page] 11. WebSocket close ├──────────────────────────────────────────────────► └─► Detect disconnect └─► Calculate usage: Paid: 3000 wei Used: 600 wei (2 min) Refund: 2400 wei └─► Issue refund └─► Remove HTTP token └─► End session [Refund processed automatically] ``` ## 💡 Key Features ### 1. Two Independent Channels ```javascript // HTTP Channel - To serve the resource GET /api/resource/pdf-123?token=abc Downloads complete PDF // WebSocket Channel - For time tracking ws://server/ws402?resourceId=pdf-123 Tracks usage time Sends updates every 3 seconds Processes refund on disconnect ``` ### 2. HTTP Access Token ```javascript // After payment, you receive an HTTP token: { type: "http_access_granted", httpToken: "http_1699123456_abc123", resourceUrl: "http://server/api/resource/pdf-123?token=http_1699123456_abc123" } // This token: // Only valid while WebSocket session is active // Linked to a specific resource // Allows downloading the resource via HTTP // Becomes invalid when WebSocket closes ``` ### 3. Continuous Tracking While the WebSocket is open: - **Time is tracked automatically** - **Updates every 3 seconds** - **Balance deducted in real-time** - **Client can see usage** ## 📊 Method Comparison ### Method 1: Resource via WebSocket (previous) ``` Pros: - Single channel - Full streaming control Cons: - More complex for large files - Doesn't use HTTP cache - More client-side code ``` ### Method 2: Resource via HTTP + Tracking via WebSocket (new) ``` Pros: - Uses regular HTTP (easy for PDFs, images) - Leverages HTTP cache if desired - Client can use <iframe>, <img>, etc. - Simpler for static documents Cons: - Two connections (HTTP + WebSocket) - Need to manage tokens ``` ## 🔧 Implementation ### Server ```javascript // 1. Client pays via WebSocket ws402.attach(wss); ws402.on('paymentVerified', (session) => { // 2. Generate HTTP token const httpToken = generateToken(); // 3. Save token (linked to session) httpSessions.set(httpToken, { sessionId: session.sessionId, resourceId: session.resourceId, }); // 4. Send token to client ws.send({ type: 'http_access_granted', httpToken: httpToken, resourceUrl: `/api/resource/${resourceId}?token=${httpToken}` }); }); // 5. Protected HTTP route app.get('/api/resource/:id', (req, res) => { const token = req.query.token; // Verify token const session = httpSessions.get(token); if (!session) { return res.status(403).json({ error: 'Invalid token' }); } // Serve resource res.sendFile(pdfPath); // WebSocket continues tracking time in background! }); // 6. On WebSocket close automatic refund ws402.on('sessionEnd', (session) => { // Remove HTTP token removeTokenBySession(session.sessionId); // Refund processed automatically by WS402 }); ``` ### Client ```javascript // 1. Get schema const schema = await fetch('/api/resource/pdf-123/schema').then(r => r.json()); // 2. Connect WebSocket and pay const ws = new WebSocket(schema.websocketEndpoint); ws.send({ type: 'payment_proof', proof: {...} }); // 3. Receive HTTP token ws.onmessage = (msg) => { if (msg.type === 'http_access_granted') { // 4. Load PDF via HTTP const iframe = document.createElement('iframe'); iframe.src = msg.resourceUrl; // With token included document.body.appendChild(iframe); // WebSocket remains open tracking time! } if (msg.type === 'usage_update') { // Display real-time consumption console.log('Used:', msg.consumedAmount); } }; // 5. When finished, close WebSocket window.onbeforeunload = () => { ws.close(); // Trigger refund }; ``` ## 🎯 Real Use Case: PDF Report ```javascript Configuration: - PDF: 50 pages - Estimated reading time: 10 minutes (600 seconds) - Price: 5 wei/second - Initial payment: 3000 wei Flow: 1. User pays 3000 wei 2. User downloads complete PDF (HTTP) 3. User reads for 3 minutes (WebSocket tracks) 4. User closes PDF 5. Time used: 180 seconds = 900 wei 6. Refund: 2100 wei (70% returned!) User only paid for 3 minutes of reading ``` ## ✅ Design Advantages 1. **Simple for client** - PDF loads normally in `<iframe>` - No special JavaScript needed for PDF 2. **Flexible** - Works with PDFs, images, HTML5 videos - Uses native browser capabilities 3. **Fair** - Real-time tracking - Automatic refund - User pays only what they use 4. **Secure** - HTTP token linked to WebSocket session - Token invalidated on WebSocket close - Cannot reuse token ## 📝 Compatible Resource Types ```javascript PDFs (iframe or download) Images (img tag) Videos (video tag with HTTP) Documents (Word, Excel via download) Audio (audio tag) ZIP files (download) Anything servable via HTTP! ``` ## 🚀 How to Use 1. **Install** (when published): ```bash npm install ws402 ``` 2. **Import**: ```javascript const { WS402, MockPaymentProvider } = require('ws402'); ``` 3. **Use the example**: ```bash node http-resource-tracking-example.js ``` 4. **Visit**: ``` http://localhost:3000 ``` Complete example ready to use! 🎉 ## 💰 Payment Flow Summary ``` ┌─────────────────────────────────────────────────┐ TRANSACTION SUMMARY ├─────────────────────────────────────────────────┤ Paid initially: 3000 wei (10 minutes) Actually consumed: 600 wei (2 minutes) Automatic refund: 2400 wei (80% returned) User only paid for what they used! └─────────────────────────────────────────────────┘ ``` ## 🔑 Key Concepts ### Session Lifecycle ```javascript 1. WebSocket connects Session created 2. Payment verified HTTP token generated 3. Resource accessed via HTTP Token validated 4. Time tracked via WebSocket Updates sent 5. WebSocket closes Refund processed 6. HTTP token invalidated Session ended ``` ### Token Security ```javascript Token only valid while session active Token tied to specific resource Token cannot be shared/reused Token expires on disconnect One token per session ``` ## 📈 Usage Scenarios ### Scenario 1: Quick Preview ``` User wants to preview a document Pays for 10 minutes Views for 30 seconds Disconnects Gets 98% refund ``` ### Scenario 2: Full Consumption ``` User wants to read entire document Pays for 10 minutes Reads for full 10 minutes Disconnects No refund (used everything) ``` ### Scenario 3: Interrupted Session ``` User starts reading Pays for 10 minutes Connection drops after 2 minutes Automatic refund for 8 minutes ``` ## 🛡️ Security Features - Payment verified before resource access - Token-based HTTP protection - Session validation on each request - Automatic token cleanup - No token reuse possible - Time tracking cannot be manipulated ## 🎨 Client UI Integration ### Example: PDF Viewer ```html <iframe id="pdfViewer" style="width:100%; height:600px;"></iframe> <div id="tracking"> Time used: <span id="time">0</span>s Balance: <span id="balance">0</span> wei </div> <script> ws.onmessage = (msg) => { if (msg.type === 'http_access_granted') { document.getElementById('pdfViewer').src = msg.resourceUrl; } if (msg.type === 'usage_update') { document.getElementById('time').textContent = msg.elapsedSeconds; document.getElementById('balance').textContent = msg.remainingBalance; } }; </script> ``` ## 📚 Additional Resources - See `http-resource-tracking-example.js` for complete working example - See `middlewareHTTP.ts` for middleware implementation - See main README.md for general WS402 documentation --- **Built for fair, transparent, pay-as-you-go access to digital resources** 🚀