API Reference¶
Complete API documentation for all public exports of the magic-network package.
MagicNode¶
src/node/magic-node.ts — The main node orchestrator.
Constructor¶
interface MagicNodeEvents {
onMessage?: (msg: MagicMessage, tag: string) => void;
onPeerConnected?: (peerId: string) => void;
onPeerDisconnected?: (peerId: string) => void;
}
Methods¶
| Method | Returns | Description |
|---|---|---|
start() | Promise<void> | Initialize and start all subsystems |
stop() | Promise<void> | Graceful shutdown |
broadcast(tags, payload, type?) | Promise<MagicMessage> | Broadcast a signed message |
advertise(tags, payload) | Promise<MagicMessage> | Broadcast with ADVERTISE type |
discover(tags, query) | Promise<MagicMessage> | Broadcast with DISCOVER type |
sendDirect(peerId, payload, pubkeyHex) | Promise<boolean> | Encrypted point-to-point message |
registerService(descriptor) | Promise<void> | Register a service for discovery |
discoverServices(query) | Promise<ServiceDescriptor[]> | Query service registry |
subscribe(tag) | void | Subscribe to a tag at runtime |
unsubscribe(tag) | void | Unsubscribe from a tag |
onTag(tag, handler) | void | Register per-tag message handler |
allowAgent(pubkeyHex) | void | Whitelist an agent |
blockAgent(pubkeyHex) | void | Blacklist an agent |
allowTag(pubkeyHex, tag) | void | Per-tag trust grant |
blockTag(pubkeyHex, tag) | void | Per-tag trust block |
submitToSharedLedger(data) | Promise<void> | Submit provable record |
getPublicKeyHex() | string | 64-char hex public key |
getFingerprint() | string | 16-char hex short ID |
getPeerCount() | number | Connected peer count |
getMultiaddrs() | string[] | Listening addresses |
getLocalLedger() | LocalLedger | Local ledger instance |
getSharedLedger() | SharedLedger | Shared ledger instance |
getPeerExchange() | PeerExchange \| null | Peer exchange instance |
getLedgerSync() | LedgerSync \| null | Ledger sync instance |
getServiceRegistry() | ServiceRegistry | Service registry instance |
getLedgerConsensus() | Consensus | Consensus state |
SeedNode¶
src/node/seed-node.ts — Extends MagicNode for bootstrap nodes.
Forces isSeedNode: true and subscribedTags: [].
| Method | Returns | Description |
|---|---|---|
getKnownPeers() | Array<{peerId, multiaddrs, lastSeen}> | All seen peers |
getConnectedPeerCount() | number | Currently connected peers |
pruneStale(maxAge?) | number | Remove old peers (default: 30 min) |
Identity¶
generateKeypair¶
async function generateKeypair(): Promise<Keypair>
// Keypair = { publicKey: Uint8Array, privateKey: Uint8Array }
sign / verify¶
async function sign(privateKey: Uint8Array, data: Uint8Array): Promise<Uint8Array>
async function verify(publicKey: Uint8Array, signature: Uint8Array, data: Uint8Array): Promise<boolean>
Key encoding¶
function publicKeyToHex(pubkey: Uint8Array): string // 64-char hex
function hexToPublicKey(hex: string): Uint8Array // 32 bytes
function getFingerprint(pubkey: Uint8Array): string // 16-char hex
IdentityStore¶
const store = new IdentityStore(dataDir: string);
await store.load(): Promise<Keypair> // Load or generate
await store.save(privateKey, publicKey) // Save to disk
store.exists(): Promise<boolean>
store.getIdentityPath(): string
Messages¶
MagicMessage¶
interface MagicMessage {
id: Uint8Array; // SHA-256 (32 bytes)
senderPubkey: Uint8Array; // Ed25519 public key (32 bytes)
signature: Uint8Array; // Ed25519 signature (64 bytes)
tags: string[]; // 1-20 routing tags
payload: Uint8Array; // Max 256KB
timestamp: number; // Unix milliseconds
nonce: Uint8Array; // 16 random bytes
type: MessageType;
ttl: number; // Hop count
}
MessageType¶
Message functions¶
// Create a signed message
async function createMessage(opts: {
tags: string[];
payload: Uint8Array;
type: MessageType;
privateKey: Uint8Array;
publicKey: Uint8Array;
ttl?: number; // default: 7
}): Promise<MagicMessage>
// Serialize / deserialize (format: 'protobuf' | 'json')
function serializeMessage(msg: MagicMessage, format?: 'protobuf'): Uint8Array
function deserializeMessage(data: Uint8Array, format?: 'protobuf'): MagicMessage
function serializeMessageJson(msg: MagicMessage): Uint8Array
function deserializeMessageJson(data: Uint8Array): MagicMessage
// Validate structure (NOT signature)
function validateMessage(msg: MagicMessage): { valid: boolean; error?: string }
// Verify Ed25519 signature
async function verifyMessageSignature(msg: MagicMessage): Promise<boolean>
// Load protobuf schema (call once before serialization)
async function initProto(): Promise<void>
TagPubSub¶
const pubsub = new TagPubSub(gossipsub: GossipSub);
pubsub.subscribe(tag)
pubsub.unsubscribe(tag)
pubsub.subscribeDiscovery()
pubsub.onTag(tag, handler: (data: Uint8Array, tag: string) => void)
pubsub.offTag(tag, handler)
pubsub.onMessage(handler)
pubsub.offMessage(handler)
await pubsub.publish(tags: string[], data: Uint8Array)
await pubsub.publishDiscovery(data: Uint8Array)
pubsub.handleMessage(topic: string, data: Uint8Array)
pubsub.getSubscribedTags(): string[]
pubsub.getTopics(): string[]
pubsub.getTagPeerCount(tag): number
Topic mapping: Tag T maps to GossipSub topic magic/tag/T. Discovery uses magic/discovery.
Trust¶
TrustPolicy¶
const policy = new TrustPolicy();
policy.allowAgent(pubkeyHex)
policy.blockAgent(pubkeyHex)
policy.allowTag(pubkeyHex, tag)
policy.blockTag(pubkeyHex, tag)
policy.isAllowed(pubkeyHex, tags: string[]): boolean
policy.getBlockedAgents(): string[]
policy.getAllowedAgents(): string[]
SpamFilter¶
const filter = new SpamFilter(maxSeenSize?: number); // default: 100_000
filter.isDuplicate(messageIdHex): boolean
filter.isRateLimited(pubkeyHex, maxPerMinute: number): boolean
filter.reportSpam(pubkeyHex): void
filter.getSpamCount(pubkeyHex): number
Ledgers¶
LocalLedger¶
const ledger = new LocalLedger(dataDir);
await ledger.open()
await ledger.close()
await ledger.append(message: Uint8Array, action: string): Promise<LedgerEntry>
await ledger.getEntry(index): Promise<LedgerEntry | null>
await ledger.getLatest(): Promise<LedgerEntry | null>
await ledger.verify(): Promise<boolean>
await ledger.getEntryCount(): Promise<number>
SharedLedger¶
const ledger = new SharedLedger(dataDir);
await ledger.open()
await ledger.close()
await ledger.submit(data, submitterPubkey, signature): Promise<SharedLedgerEntry>
await ledger.addConfirmation(index, confirmerPubkey): Promise<SharedLedgerEntry | null>
await ledger.getEntry(index): Promise<SharedLedgerEntry | null>
await ledger.getLatest(): Promise<SharedLedgerEntry | null>
await ledger.getEntryCount(): Promise<number>
await ledger.verify(): Promise<boolean>
await ledger.getRange(startIndex, endIndex): Promise<SharedLedgerEntry[]>
LedgerSync¶
const sync = new LedgerSync(libp2p, ledger, localPubkey, localPrivkey, {
syncIntervalMs?: number, // default: 60_000
events?: {
onEntryReceived?: (entry) => void,
onEntryConfirmed?: (index, pubkey) => void,
onSyncComplete?: (peerId, count) => void,
},
});
await sync.start()
await sync.stop()
await sync.requestRange(peerId, startIndex, endIndex): Promise<SharedLedgerEntry[]>
await sync.pushEntry(peerId, entry): Promise<void>
await sync.broadcastEntry(entry): Promise<void>
await sync.syncWithAllPeers(): Promise<void>
PeerExchange¶
const pex = new PeerExchange(libp2p, {
maxPeers?: number, // default: 500
maxPeerAge?: number, // default: 30 min
exchangeIntervalMs?: number, // default: 30s
});
await pex.start()
await pex.stop()
pex.addPeer(record: PeerRecord)
pex.removePeer(peerId)
pex.getPeers(): PeerRecord[]
pex.getPeer(peerId): PeerRecord | undefined
pex.getPeerCount(): number
pex.pruneStale(): number
await pex.exchangeWithPeer(peerId): Promise<PeerRecord[]>
Configuration¶
import { type MagicConfig, DEFAULT_CONFIG, mergeConfig } from 'magic-network';
const config = mergeConfig({ listenPort: 9900 });
// Spreads partial over DEFAULT_CONFIG
See Configuration for all options and defaults.