Build decentralized applications with MULTIPASS authentication, IPFS storage, and NOSTR social features
Checking connection...
Quick Start: Include common.js, call connectNostr(), then use publishNote() or uploadPhotoToIPFS()
Learn how to build decentralized applications with Astroport.ONE step by step
Build decentralized applications 10x faster with NOSTR, IPFS, and Web3 technologies.
Traditional web development requires months to build authentication, file storage, and social features. With Astroport.ONE, you get all of this in days instead of months.
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/nostr.bundle.js"></script>
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/common.js"></script>
const pubkey = await connectNostr();
await publishNote('Hello Web3! ' + window.location.href, [['r', window.location.href]]);
Decentralized identity with NOSTR keys. No passwords, no central database.
Files stored on IPFS with automatic metadata tracking (SHA256).
Cryptographically signed events published to decentralized relays.
Astroport stations automatically process your events according to predefined rules.
Understanding which library to use and when
Purpose: Public NOSTR operations and client-side utilities
When to use: For all public-facing features in your application
connectNostr() - Connect to NOSTR walletpublishNote() - Publish public notes (kind 1)uploadPhotoToIPFS() - Upload files to IPFSsendLike() - Send reactions (kind 7)hexToNpub() / npubToHex() - Format conversionfetchUserFollowsWithMetadata() - Get user networkPurpose: Private/encrypted operations and sensitive data
When to use: For encrypted messages, private keys, sensitive operations
encryptDM() - Encrypt direct messages (NIP-04)decryptDM() - Decrypt received messagessignEvent() - Sign events with private keygenerateKeys() - Generate new keypairs| Use Case | Library | Reason |
|---|---|---|
| User authentication | common.js |
Public operation, uses NIP-07 extension |
| Publishing posts | common.js |
Public content, no encryption needed |
| File uploads | common.js |
Public IPFS storage with metadata |
| Direct messages | nostr.private.js |
Requires encryption (NIP-04) |
| Private keys | nostr.private.js |
Sensitive operations only |
<!-- Required: NostrTools Bundle -->
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/nostr.bundle.js"></script>
<!-- Core Library: Public Operations -->
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/common.js"></script>
<!-- Optional: Private/Encrypted Operations -->
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/nostr.private.js"></script>
The CSS Revolution: Separating Events from Processing
Just like CSS separated style from content in 1996, Astroport.ONE separates events from their processing. This allows your events to be processed by any Astroport station according to smart contract rules.
// Everything coupled together
app.post('/upload',
authenticate(),
validate(),
saveToDB(),
processFile(),
notifyUsers()
);
Problem: 6 months of infrastructure development, hard to scale, vendor lock-in
// Event separated from processing
const event = {
kind: 21, // Video upload
content: videoData,
tags: [['url', ipfsUrl]]
};
await publishToNostr(event);
// Smart contracts handle the rest
Result: 1 week of development, scalable, interoperable
Creates NOSTR events
Stores events
Smart contracts process events
To enable smart contract processing, you need to identify different event types in your application:
kind: 1 - Text notes (posts, comments)kind: 7 - Reactions (likes, emojis)kind: 21 - Short videos (NIP-71)kind: 22 - Long videos (NIP-71)kind: 1063 - File uploads (NIP-94)kind: 42 - Channel messages (NIP-28)kind: 1111 - Comments on URLs (NIP-22)Use tags to add context that smart contracts can use:
const event = {
kind: 1,
content: "My post",
tags: [
['t', 'myapp'], // Topic/category
['g', '48.86,2.35'], // Geolocation
['r', 'https://...'], // Reference URL
['p', 'pubkey'], // Reference pubkey
['custom', 'value'] // Custom data
]
};
How Astroport stations automatically process your events
Smart contracts are executable rules that run on Astroport stations. They automatically process NOSTR events according to predefined logic, without requiring manual intervention.
When you publish a video upload event (kind 21), a smart contract automatically:
// Your app publishes this event
const videoEvent = {
kind: 21,
content: "My video",
tags: [
['url', '/ipfs/QmXXX'],
['title', 'My Video Title'],
['thumbnail', '/ipfs/QmYYY']
]
};
// Smart contract on Astroport station automatically:
// 1. Validates the event structure
// 2. Checks IPFS file exists
// 3. Generates additional thumbnails if needed
// 4. Updates video database
// 5. Notifies subscribers
// 6. Processes payment if required
Smart contracts rely on event structure to know how to process them. Make sure your events follow NOSTR standards:
hexToNpub() and validation functions from common.jsUpload cookies to enable automated scraping and data synchronization with external services
The Cookie System allows you to upload browser cookies (Netscape format) for specific domains. These cookies enable automated scrapers to authenticate and sync data from external websites like YouTube, Leboncoin, and more.
Quick Start:
.DOMAIN.cookie (leading dot)β Currently Functional: YouTube cookie system is fully operational.
.youtube.com.cookie via Cookie Manager~/.zen/game/nostr/EMAIL/.youtube.com.cookieyoutube.com.sh automatically runsAstroport.ONE/IA/youtube.com.sh - Bash scraper scriptUPassport/templates/youtube.html - Video display interfaceπ Extensible System: You can create scrapers for any domain following the same pattern as YouTube and Leboncoin.
The Leboncoin scraper demonstrates a more complex implementation with Python backend:
.DOMAIN.cookie via Cookie ManagerDOMAIN.sh in Astroport.ONE/IA/
#!/bin/bash
# DOMAIN.sh - Auto-scraper for DOMAIN
PLAYER=$1
COOKIE_FILE="$HOME/.zen/game/nostr/$PLAYER/.DOMAIN.cookie"
if [ ! -f "$COOKIE_FILE" ]; then
echo "Cookie not found: $COOKIE_FILE"
exit 1
fi
# Your scraping logic here
python3 scraper_DOMAIN.py "$COOKIE_FILE" [...args]
scraper_DOMAIN.py for complex logic
#!/usr/bin/env python3
# scraper_DOMAIN.py - Python backend for DOMAIN scraper
import sys
from get_cookie import read_cookie_from_file
cookie_file = sys.argv[1]
cookie = read_cookie_from_file(cookie_file)
# Your scraping logic here
# Use cookie for authentication
# Publish results to NOSTR
bash Astroport.ONE/IA/DOMAIN.sh user@email.com
Astroport.ONE/IA/youtube.com.sh - Uses yt-dlpAstroport.ONE/IA/leboncoin.fr.sh - Bash wrapperAstroport.ONE/IA/scraper_leboncoin.py - Python backendRequired Format: Netscape HTTP Cookie File format (exported from browser extensions)
Each cookie file must contain cookies for one domain only (and its subdomains).
# Netscape HTTP Cookie File
# https://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
.youtube.com TRUE / TRUE 1796910450 __Secure-Install uuid-value
.youtube.com TRUE / TRUE 1796910450 VISITOR_INFO1_LIVE visitor-id
.youtube.com TRUE / TRUE 1793886482 PREF preference-value
Cookies are stored in your MULTIPASS directory:
~/.zen/game/nostr/EMAIL/
βββ .youtube.com.cookie # YouTube cookies (single-domain)
βββ .leboncoin.fr.cookie # Leboncoin cookies (single-domain)
βββ .DOMAIN.cookie # Any domain cookie (single-domain)
βββ APP/
βββ uDRIVE/ # Scraped content (videos, music, etc.)
Astroport.ONE/IA/youtube.com.sh - YouTube video syncAstroport.ONE/IA/leboncoin.fr.sh - Leboncoin ad scraperAstroport.ONE/IA/scraper_leboncoin.py - Python backend exampleReal-world code examples you can use in your applications
Access: Open NOSTR Console
The NOSTR Console is a powerful real-time event monitoring tool that displays all NOSTR events from the last 48 hours, similar to a browser's network console. It's perfect for debugging, monitoring, and understanding NOSTR event flows.
kind (0=Metadata, 1=Text Note, 3=Contacts, etc.)pubkey (hex or npub format)#e, #p, #t, #g, etc.)The console uses common.js to connect to the relay and subscribes to events from the last 48 hours using multiple filters:
// The console automatically subscribes to:
- Regular events (kinds 0-7)
- Parameterized replaceable events (kinds 10000-10009)
- Other common event types
- All within the last 48 hours
// Uses window.nostrRelay from common.js
const subscription = window.nostrRelay.sub(filters);
subscription.on('event', (event) => {
// Events are displayed in real-time
});
subscription.on('eose', () => {
// End of stored events
});
common.js is loaded. Click the status indicator to see detailed connection information.
// Include libraries
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/nostr.bundle.js"></script>
<script src="https://ipfs.copylaradio.com/ipns/copylaradio.com/common.js"></script>
// Connect user
async function login() {
try {
const pubkey = await connectNostr(true); // true = force NIP-42 auth
console.log('User connected:', pubkey);
// Convert to npub for display
const npub = hexToNpub(pubkey);
console.log('User npub:', npub);
return pubkey;
} catch (error) {
console.error('Login failed:', error);
}
}
// Publish a simple text post
async function publishPost(content) {
const result = await publishNote(content);
if (result.success && result.eventId) {
console.log('Post published:', result.eventId);
return result.event;
}
throw new Error('Failed to publish: ' + result.errors.join(', '));
}
// Publish a post with tags (for smart contract processing)
async function publishPostWithTags(content, tags) {
const result = await publishNote(content, tags);
if (result.success && result.eventId) {
console.log('Post with tags published:', result.eventId);
return result.event;
}
throw new Error('Failed to publish: ' + result.errors.join(', '));
}
// Example: Post with geolocation and URL
await publishPostWithTags('Hello from Paris! ' + window.location.href, [
['g', '48.86,2.35'], // Geolocation tag
['t', 'travel'], // Topic tag
['r', window.location.href] // Reference URL
]);
// Upload a file to IPFS
async function uploadFile(file) {
// Upload to IPFS (automatically creates metadata)
const result = await uploadPhotoToIPFS(file);
console.log('File uploaded:', result.cid);
console.log('IPFS URL:', result.ipfs_url);
console.log('Metadata:', result.info);
// The event is automatically published to NOSTR
// Smart contracts will process it automatically
return result;
}
// Handle file input
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (file) {
const result = await uploadFile(file);
console.log('Upload complete:', result);
}
});
// Subscribe to events from a specific user
async function subscribeToUser(pubkey) {
// Connect to relay first
await connectToRelay();
// Subscribe to user's posts
const sub = window.nostrRelay.sub([{
kinds: [1], // Text notes
authors: [pubkey],
limit: 10
}]);
sub.on('event', (event) => {
console.log('New post:', event.content);
// Process the event in your app
displayPost(event);
});
return sub;
}
// Subscribe to events with specific tags (for smart contract results)
async function subscribeToTaggedEvents(tag) {
await connectToRelay();
const sub = window.nostrRelay.sub([{
kinds: [1],
'#t': [tag], // Events with this tag
limit: 50
}]);
sub.on('event', (event) => {
// Smart contract may have added additional tags
console.log('Event with tag:', event);
});
return sub;
}
Complete reference for common.js functions
connectNostr(forceAuth = false)Description: Connect to NOSTR wallet and optionally authenticate with NIP-42
Parameters:
forceAuth (boolean, optional): If true, forces NIP-42 authenticationReturns: Promise resolving to user's hex pubkey
const pubkey = await connectNostr(true);
publishNote(content, additionalTags = [], kind = 1, options = {})Description: Publish a NOSTR note event
Parameters:
content (string): Note contentadditionalTags (array, optional): Additional tags for the eventkind (number, optional): Event kind (default: 1)options (object, optional): Additional optionsReturns: Promise resolving to result object with success, event, eventId, etc.
const result = await publishNote('Hello!', [['t', 'greeting']]);
if (result.success) {
console.log('Event ID:', result.eventId);
}
uploadPhotoToIPFS(file)Description: Upload a file to IPFS and publish metadata to NOSTR
Parameters:
file (File): File object from inputReturns: Promise resolving to upload result with CID, IPFS URL, and metadata
const result = await uploadPhotoToIPFS(file);
console.log(result.cid, result.ipfs_url, result.info);
hexToNpub(hex) / npubToHex(npub)Description: Convert between hex and npub (bech32) formats
Parameters:
hex (string): 64-character hex pubkeynpub (string): bech32-encoded npubReturns: Converted string or null if invalid
const npub = hexToNpub('60c1133d148ae0d2c4b42506fb4abacac903032680b178010c942bd538643f78');
const hex = npubToHex(npub);
sendLike(eventId, authorPubkey, content = "+")Description: Send a reaction (like) to an event (NIP-25)
Parameters:
eventId (string): ID of the event to react toauthorPubkey (string): Author's pubkeycontent (string, optional): Reaction content (default: "+")Returns: Promise resolving to published reaction event
await sendLike(eventId, authorPubkey, 'β€οΈ');
Enable decentralized login with NOSTR keys. No passwords, no email, no central database.
Upload files to IPFS and publish metadata on NOSTR. View recent uploads from the community.
Add likes, reactions, comments, and shares to any content or URL. Comments and shares are linked to this page.
Add real-time chat to any page. Messages are stored on NOSTR relays using NIP-28 (Public Chat Channels).
UMAP_0.00_0.00
Explore existing applications and learn from their implementation.
https://ipfs.copylaradio.com/ipns/copylaradio.com/common.jsAdd MULTIPASS authentication to your website in 3 steps:
Ensure proper authentication before uploading to prevent 403 errors:
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β Browser βββββ>β NOSTR Wallet βββββ>β Relay βββββ>β Backend β
β (Connect) β β (NIP-42) β β (MULTIPASS) β β (Verify) β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
Step 1: Step 2: Step 3: Step 4:
Click Connect Send kind 22242 Check MULTIPASS Check recent event
auth event Accept/Reject 24h window
β
SUCCESS: User can upload files
β FAILURE: Create MULTIPASS account first (/g1)
uploadPhotoToIPFS() now checks auth automaticallyensureAuthentication() for custom workflows/api/test-nostr?npub=YOUR_KEY to verify auth status
Post a Comment
You need to connect with MULTIPASS to post comments.