678 lines
30 KiB
JavaScript
678 lines
30 KiB
JavaScript
// @jsx h
|
|
// @jsxImportSource preact
|
|
|
|
import eveApiExample from "../highlight/eve-api-example.ts" with { type: "text" };
|
|
import subscriptionExamples from "../highlight/subscription-examples.ts" with { type: "text" };
|
|
import websocketExample from "../highlight/websocket-example.ts" with { type: "text" };
|
|
import { useSyntaxHighlighting } from "../hooks/useSyntaxHighlighting.js";
|
|
import { CodeBlock } from "./CodeBlock.jsx";
|
|
|
|
/**
|
|
* API Section - Comprehensive guide to available APIs
|
|
* Covers window.eve API and WebSocket alternatives
|
|
*/
|
|
export const APISection = () => {
|
|
useSyntaxHighlighting();
|
|
|
|
return (
|
|
<div class="space-y-6">
|
|
<h2 class="text-3xl font-bold">API Reference</h2>
|
|
|
|
<div class="card bg-base-100 shadow-xl">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-info mb-4">Understanding Arxlet APIs</h3>
|
|
<div class="space-y-4">
|
|
<p>
|
|
Your Arxlet has access to powerful APIs that let you interact with Nostr data, manage user profiles, and
|
|
create real-time applications. Think of these APIs as your toolkit for building social, decentralized
|
|
applications within the CCN ecosystem.
|
|
</p>
|
|
|
|
<p>
|
|
<strong>Two approaches available:</strong> You can use the convenient <code>window.eve</code> API
|
|
(recommended for most cases) or connect directly via WebSocket for advanced scenarios. Both give you full
|
|
access to Nostr events and CCN features.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card bg-base-100 shadow-xl">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-primary mb-4">🎯 Which API Should You Use?</h3>
|
|
|
|
<div class="grid md:grid-cols-2 gap-6">
|
|
<div class="border-2 border-primary rounded-lg p-4">
|
|
<h4 class="font-bold text-primary mb-3">✨ window.eve API (Recommended)</h4>
|
|
<p class="text-sm mb-3">
|
|
<strong>Best for most Arxlets.</strong> This high-level API handles all the complex Nostr protocol
|
|
details for you.
|
|
</p>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Simple promise-based functions</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Automatic error handling</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Built-in RxJS observables for real-time data</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Profile and avatar helpers</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Perfect for beginners</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-2 border-accent rounded-lg p-4">
|
|
<h4 class="font-bold text-accent mb-3">⚡ Direct WebSocket</h4>
|
|
<p class="text-sm mb-3">
|
|
<strong>For advanced use cases.</strong> Direct connection to the Nostr relay with full protocol
|
|
control.
|
|
</p>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Maximum performance and control</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Custom subscription management</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Raw Nostr protocol access</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-warning">!</span>
|
|
<span>Requires Nostr protocol knowledge</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-warning">!</span>
|
|
<span>More complex error handling</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-info mt-6">
|
|
<span>
|
|
💡 <strong>Our Recommendation:</strong> Start with <code>window.eve</code> for your first Arxlet. You can
|
|
always switch to WebSocket later if you need more control or performance.
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* window.eve API */}
|
|
<div class="card bg-base-200 shadow-xl">
|
|
<div class="card-body">
|
|
<h3 id="window-eve-api" class="card-title text-primary mb-4">
|
|
🚀 window.eve API - Your Main Toolkit
|
|
</h3>
|
|
<div class="space-y-4 mb-6">
|
|
<p>
|
|
The <code>window.eve</code> API is your primary interface for working with Nostr data in Arxlets. It
|
|
provides simple, promise-based functions that handle all the complex protocol details behind the scenes.
|
|
</p>
|
|
|
|
<p>
|
|
<strong>How it works:</strong> Each function communicates with the local Nostr relay, processes the
|
|
results, and returns clean JavaScript objects. No need to understand Nostr protocol internals - just call
|
|
the functions and get your data.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="space-y-6">
|
|
<div>
|
|
<h4 class="font-bold text-lg mb-4 text-success">📤 Publishing & Writing Data</h4>
|
|
<div class="space-y-4">
|
|
<div class="border-l-4 border-success pl-4">
|
|
<h5 class="font-bold">publish(event)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Publishes a Nostr event to the relay. This is how you save data, post messages, or create any
|
|
content.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Posting messages, saving user preferences, creating notes, updating
|
|
profiles
|
|
</p>
|
|
<div class="badge badge-outline">Promise<void></div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-success pl-4">
|
|
<h5 class="font-bold">signEvent(event)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Signs an unsigned Nostr event with the user's private key. Required before publishing most events.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Preparing events for publication, authenticating user actions
|
|
</p>
|
|
<div class="badge badge-outline">Promise<NostrEvent></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-bold text-lg mb-4 text-info">🔍 Reading & Querying Data</h4>
|
|
<div class="space-y-4">
|
|
<div class="border-l-4 border-info pl-4">
|
|
<h5 class="font-bold">getSingleEventById(id)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Retrieves a specific event when you know its exact ID. Perfect for loading specific posts or data.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Loading a specific message, fetching referenced content, getting event
|
|
details
|
|
</p>
|
|
<div class="badge badge-outline">Promise<NostrEvent | null></div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-info pl-4">
|
|
<h5 class="font-bold">getSingleEventWithFilter(filter)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Gets the first event matching your criteria. Useful when you expect only one result or want the most
|
|
recent.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Getting a user's latest profile, finding the most recent post, checking
|
|
if something exists
|
|
</p>
|
|
<div class="badge badge-outline">Promise<NostrEvent | null></div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-info pl-4">
|
|
<h5 class="font-bold">getAllEventsWithFilter(filter)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Gets all events matching your criteria. Use this for lists, feeds, or when you need multiple
|
|
results.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Building feeds, loading message history, getting all posts by a user
|
|
</p>
|
|
<div class="badge badge-outline">Promise<NostrEvent[]></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-bold text-lg mb-4 text-accent">🔄 Real-time Subscriptions</h4>
|
|
<div class="space-y-4">
|
|
<div class="border-l-4 border-accent pl-4">
|
|
<h5 class="font-bold">subscribeToEvents(filter)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Creates a live stream of events matching your filter. Your app updates automatically when new events
|
|
arrive.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Live chat, real-time feeds, notifications, collaborative features
|
|
</p>
|
|
<div class="badge badge-outline">Observable<NostrEvent></div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-accent pl-4">
|
|
<h5 class="font-bold">subscribeToProfile(pubkey)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Watches for profile changes for a specific user. Updates automatically when they change their name,
|
|
bio, avatar, etc.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> User profile displays, contact lists, member directories
|
|
</p>
|
|
<div class="badge badge-outline">Observable<Profile></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-bold text-lg mb-4 text-warning">👤 User & Profile Helpers</h4>
|
|
<div class="space-y-4">
|
|
<div class="border-l-4 border-warning pl-4">
|
|
<h5 class="font-bold">getProfile(pubkey)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Retrieves user profile information (name, bio, avatar, etc.) for any user by their public key.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Displaying user info, building contact lists, showing message authors
|
|
</p>
|
|
<div class="badge badge-outline">Promise<Profile | null></div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-warning pl-4">
|
|
<h5 class="font-bold">getAvatar(pubkey)</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Quick helper to get just the avatar URL from a user's profile. Saves you from parsing the full
|
|
profile.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Profile pictures, user avatars in lists, message author images
|
|
</p>
|
|
<div class="badge badge-outline">Promise<string | null></div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-warning pl-4">
|
|
<h5 class="font-bold">publicKey</h5>
|
|
<p class="text-sm opacity-80 mb-2">
|
|
Gets the current user's public key. This identifies the user and is needed for many operations.
|
|
</p>
|
|
<p class="text-sm mb-2">
|
|
<strong>Use cases:</strong> Identifying the current user, filtering their content, permission checks
|
|
</p>
|
|
<div class="badge badge-outline">Promise<string></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8">
|
|
<h4 class="font-semibold mb-3 text-lg">Practical Example:</h4>
|
|
<p class="mb-3 text-sm">
|
|
Here's how these functions work together in a real Arxlet. This example shows fetching events, displaying
|
|
user profiles, and handling real-time updates:
|
|
</p>
|
|
<CodeBlock language="typescript" code={eveApiExample} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Real-time Subscriptions */}
|
|
<div class="card bg-base-200 shadow-xl">
|
|
<div class="card-body">
|
|
<h3 id="real-time-subscriptions" class="card-title text-accent mb-4">
|
|
🔄 Understanding Real-time Subscriptions
|
|
</h3>
|
|
|
|
<div class="space-y-4 mb-6">
|
|
<p>
|
|
<strong>What are subscriptions?</strong> Think of subscriptions as "live feeds" that automatically notify
|
|
your Arxlet when new data arrives. Instead of repeatedly asking "is there new data?", subscriptions push
|
|
updates to you instantly.
|
|
</p>
|
|
|
|
<p>
|
|
<strong>How they work:</strong> When you subscribe to events or profiles, you get an RxJS Observable - a
|
|
stream of data that flows over time. Your Arxlet can "listen" to this stream and update the UI whenever
|
|
new data arrives.
|
|
</p>
|
|
|
|
<p>
|
|
<strong>Why use them?</strong> Subscriptions make your Arxlet feel alive and responsive. Users see new
|
|
messages instantly, profile changes update immediately, and collaborative features work in real-time.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid md:grid-cols-2 gap-6 mb-6">
|
|
<div class="border-2 border-accent rounded-lg p-4">
|
|
<h4 class="font-bold text-accent mb-3">🎯 Event Subscriptions</h4>
|
|
<p class="text-sm mb-3">
|
|
<code>subscribeToEvents(filter)</code> gives you a live stream of events matching your criteria.
|
|
</p>
|
|
<div class="space-y-2 text-sm">
|
|
<div>
|
|
<strong>Perfect for:</strong>
|
|
</div>
|
|
<ul class="list-disc list-inside space-y-1 ml-2">
|
|
<li>Live chat applications</li>
|
|
<li>Real-time feeds and timelines</li>
|
|
<li>Notification systems</li>
|
|
<li>Collaborative tools</li>
|
|
<li>Activity monitoring</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-2 border-warning rounded-lg p-4">
|
|
<h4 class="font-bold text-warning mb-3">👤 Profile Subscriptions</h4>
|
|
<p class="text-sm mb-3">
|
|
<code>subscribeToProfile(pubkey)</code> watches for changes to a specific user's profile.
|
|
</p>
|
|
<div class="space-y-2 text-sm">
|
|
<div>
|
|
<strong>Perfect for:</strong>
|
|
</div>
|
|
<ul class="list-disc list-inside space-y-1 ml-2">
|
|
<li>User profile displays</li>
|
|
<li>Contact lists that stay current</li>
|
|
<li>Member directories</li>
|
|
<li>Avatar/name displays</li>
|
|
<li>User status indicators</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-6">
|
|
<h4 class="font-semibold mb-3 text-lg">How to Use Subscriptions:</h4>
|
|
<p class="mb-3 text-sm">
|
|
Here's a complete example showing how to set up subscriptions, handle incoming data, and clean up
|
|
properly:
|
|
</p>
|
|
<CodeBlock language="typescript" code={subscriptionExamples} />
|
|
</div>
|
|
|
|
<div class="grid md:grid-cols-2 gap-4">
|
|
<div class="alert alert-warning">
|
|
<div>
|
|
<h4 class="font-bold mb-2">! Memory Management</h4>
|
|
<div class="text-sm space-y-1">
|
|
<p>
|
|
Always call <code>unsubscribe()</code> when:
|
|
</p>
|
|
<ul class="list-disc list-inside ml-2">
|
|
<li>Your component unmounts</li>
|
|
<li>User navigates away</li>
|
|
<li>You no longer need the data</li>
|
|
<li>Your Arxlet is closing</li>
|
|
</ul>
|
|
<p class="mt-2">
|
|
<strong>Why?</strong> Prevents memory leaks and unnecessary disk i/o.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-success">
|
|
<div>
|
|
<h4 class="font-bold mb-2">✨ Pro Tips</h4>
|
|
<div class="text-sm space-y-1">
|
|
<ul class="list-disc list-inside">
|
|
<li>Use specific filters to reduce data volume</li>
|
|
<li>Debounce rapid updates for better UX</li>
|
|
<li>Cache data to avoid duplicate processing</li>
|
|
<li>
|
|
Handle errors gracefully with <code>catchError</code>
|
|
</li>
|
|
<li>
|
|
Consider using <code>takeUntil</code> for automatic cleanup
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* WebSocket Alternative */}
|
|
<div class="card bg-base-200 shadow-xl">
|
|
<div class="card-body">
|
|
<h3 id="websocket-alternative" class="card-title text-accent mb-4">
|
|
🔌 Direct WebSocket Connection - Advanced Usage
|
|
</h3>
|
|
|
|
<div class="space-y-4 mb-6">
|
|
<p>
|
|
<strong>What is the WebSocket approach?</strong> Instead of using the convenient <code>window.eve</code>{" "}
|
|
API, you can connect directly to the Nostr relay at <code>ws://localhost:6942</code> and speak the raw
|
|
Nostr protocol.
|
|
</p>
|
|
|
|
<p>
|
|
<strong>Why would you use this?</strong> Direct WebSocket gives you maximum control and performance. You
|
|
can implement custom subscription logic, handle multiple concurrent subscriptions efficiently, or
|
|
integrate with existing Nostr libraries.
|
|
</p>
|
|
|
|
<p>
|
|
<strong>The trade-off:</strong> You'll need to understand the Nostr protocol, handle JSON message parsing,
|
|
manage connection states, and implement your own error handling. It's more work but gives you complete
|
|
flexibility.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="mb-6">
|
|
<h4 class="font-semibold mb-3 text-lg">WebSocket Implementation Example:</h4>
|
|
<p class="mb-3 text-sm">
|
|
Here's how to establish a WebSocket connection and communicate using standard Nostr protocol messages:
|
|
</p>
|
|
<CodeBlock language="typescript" code={websocketExample} />
|
|
</div>
|
|
|
|
<div class="grid md:grid-cols-2 gap-6 mb-6">
|
|
<div class="border-2 border-success rounded-lg p-4">
|
|
<h4 class="font-bold text-success mb-3">✨ Use window.eve When:</h4>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Building your first Arxlet</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>You want simple, clean code</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Standard CRUD operations are enough</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>You prefer promise-based APIs</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>Built-in RxJS observables work for you</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-success">✓</span>
|
|
<span>You don't need custom protocol handling</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-2 border-accent rounded-lg p-4">
|
|
<h4 class="font-bold text-accent mb-3">⚡ Use WebSocket When:</h4>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-accent">⚡</span>
|
|
<span>You need maximum performance</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-accent">⚡</span>
|
|
<span>Custom subscription management required</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-accent">⚡</span>
|
|
<span>Integrating existing Nostr libraries</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-accent">⚡</span>
|
|
<span>You understand the Nostr protocol</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-accent">⚡</span>
|
|
<span>Need fine-grained connection control</span>
|
|
</div>
|
|
<div class="flex items-start gap-2">
|
|
<span class="text-accent">⚡</span>
|
|
<span>Building high-frequency applications</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-info">
|
|
<div>
|
|
<h4 class="font-bold mb-2">🎯 Choosing the Right Approach</h4>
|
|
<div class="text-sm space-y-2">
|
|
<p>
|
|
<strong>Start with window.eve:</strong> Even if you think you might need WebSocket later, begin with
|
|
the high-level API. You can always refactor specific parts to use WebSocket once you understand your
|
|
performance requirements.
|
|
</p>
|
|
<p>
|
|
<strong>Hybrid approach:</strong> Many successful Arxlets use <code>window.eve</code> for most
|
|
operations and WebSocket only for specific high-performance features like real-time chat or live
|
|
collaboration.
|
|
</p>
|
|
<p>
|
|
<strong>Migration path:</strong> The data structures are the same, so you can gradually migrate from{" "}
|
|
<code>window.eve</code>
|
|
to WebSocket for specific features without rewriting your entire application.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Best Practices */}
|
|
<div class="card bg-base-200 shadow-xl">
|
|
<div class="card-body">
|
|
<h3 id="best-practices" class="card-title text-warning mb-4">
|
|
💡 Best Practices for Robust Arxlets
|
|
</h3>
|
|
|
|
<div class="space-y-6">
|
|
<div class="border-l-4 border-error pl-4">
|
|
<h4 class="font-bold text-lg text-error mb-3">🛡 Error Handling & Reliability</h4>
|
|
<div class="space-y-3 text-sm">
|
|
<div>
|
|
<strong>Always use try-catch blocks:</strong>
|
|
<p>
|
|
Network requests can fail, relays can be down, or data might be malformed. Wrap all API calls to
|
|
prevent crashes.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Check for null/undefined returns:</strong>
|
|
<p>
|
|
Query methods return <code>null</code> when no data is found. Always check before using the result.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Provide meaningful user feedback:</strong>
|
|
<p>
|
|
Show loading states, error messages, and success confirmations. Users should know what's happening.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Implement retry logic for critical operations:</strong>
|
|
<p>Publishing events or loading essential data should retry on failure with exponential backoff.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-success pl-4">
|
|
<h4 class="font-bold text-lg text-success mb-3">⚡ Performance & Efficiency</h4>
|
|
<div class="space-y-3 text-sm">
|
|
<div>
|
|
<strong>Use specific, narrow filters:</strong>
|
|
<p>
|
|
Instead of fetching all events and filtering in JavaScript, use precise Nostr filters to reduce data
|
|
transfer.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Cache frequently accessed data:</strong>
|
|
<p>Profile information, avatars, and static content should be cached to avoid repeated API calls.</p>
|
|
</div>
|
|
<div>
|
|
<strong>Implement pagination for large datasets:</strong>
|
|
<p>
|
|
Don't load thousands of events at once. Use <code>limit</code> and <code>until</code> parameters for
|
|
pagination.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Debounce rapid user actions:</strong>
|
|
<p>
|
|
If users can trigger API calls quickly (like typing in search), debounce to avoid overwhelming the
|
|
relay.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Unsubscribe from observables:</strong>
|
|
<p>Always clean up subscriptions to prevent memory leaks and unnecessary network traffic.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-info pl-4">
|
|
<h4 class="font-bold text-lg text-info mb-3">🎯 User Experience</h4>
|
|
<div class="space-y-3 text-sm">
|
|
<div>
|
|
<strong>Show loading states:</strong>
|
|
<p>Use spinners, skeletons, or progress indicators while data loads. Empty screens feel broken.</p>
|
|
</div>
|
|
<div>
|
|
<strong>Handle empty states gracefully:</strong>
|
|
<p>When no data is found, show helpful messages or suggestions rather than blank areas.</p>
|
|
</div>
|
|
<div>
|
|
<strong>Implement optimistic updates:</strong>
|
|
<p>
|
|
Update the UI immediately when users take actions, then sync with the server. Makes apps feel
|
|
faster.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Provide offline indicators:</strong>
|
|
<p>Let users know when they're disconnected or when operations might not work.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="border-l-4 border-warning pl-4">
|
|
<h4 class="font-bold text-lg text-warning mb-3">🔒 Security & Privacy</h4>
|
|
<div class="space-y-3 text-sm">
|
|
<div>
|
|
<strong>Validate all user inputs:</strong>
|
|
<p>Never trust user input. Validate, sanitize, and escape data before using it in events or UI.</p>
|
|
</div>
|
|
<div>
|
|
<strong>Be mindful of public data:</strong>
|
|
<p>
|
|
Remember that events are visible to everyone in your CCN by default. Don't accidentally expose
|
|
private information.
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<strong>Handle signing errors gracefully:</strong>
|
|
<p>Users might reject signing requests. Always have fallbacks and clear error messages.</p>
|
|
</div>
|
|
<div>
|
|
<strong>Respect user privacy preferences:</strong>
|
|
<p>Some users prefer pseudonymous usage. Don't force real names or personal information.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-success mt-6">
|
|
<div>
|
|
<h4 class="font-bold mb-2">🚀 Quick Checklist for Production Arxlets</h4>
|
|
<div class="grid md:grid-cols-2 gap-4 text-sm">
|
|
<div>
|
|
<strong>Code Quality:</strong>
|
|
<ul class="list-disc list-inside mt-1 space-y-1">
|
|
<li>All API calls wrapped in try-catch</li>
|
|
<li>Null checks before using data</li>
|
|
<li>Subscriptions properly cleaned up</li>
|
|
<li>Input validation implemented</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<strong>User Experience:</strong>
|
|
<ul class="list-disc list-inside mt-1 space-y-1">
|
|
<li>Loading states for all async operations</li>
|
|
<li>Error messages are user-friendly</li>
|
|
<li>Empty states handled gracefully</li>
|
|
<li>Performance tested with large datasets</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|