### Import Peerbit Document Store Modules Source: https://github.com/dao-xyz/peerbit/blob/master/docs/getting-started.md Demonstrates how to import necessary modules for the Peerbit document store. This includes importing the main DocumentStore class and related types. ```typescript import { DocumentStore } from '@peerbit/document' import { Peerbit } from 'peerbit' import { Entry } from '@peerbit/collections' ``` -------------------------------- ### Search for Document from Another Peer Source: https://github.com/dao-xyz/peerbit/blob/master/docs/getting-started.md Demonstrates how to search for a document from another peer's database. This example shows how to connect to another client and query their document store for specific entries. ```typescript const otherClient = await Peerbit.connect(peerAddress) const otherDb = await new DocumentStore({ id: 'my-document-store' }).open(otherClient) const results = await otherDb.get(entry.hash) console.log('Found document from other client:', results) ``` -------------------------------- ### Set up Peerbit Test Domain Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/custom.md This command sets up a test domain for accessing the Peerbit node. It requires administrator privileges (sudo) as it may install Docker if not already present. An email address is needed for the setup process. ```bash sudo peerbit domain test --email ``` -------------------------------- ### Display Peerbit Start Command Help Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/custom.md Displays help information specifically for the 'peerbit start' command. This provides details on options and arguments related to starting the Peerbit node. ```bash peerbit start --help ``` -------------------------------- ### Start Peerbit Node Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/custom.md Starts the Peerbit client as a background process. The output and errors are redirected to a log file named 'log.txt'. This command is used to run the Peerbit node after initial setup. ```bash peerbit start > log.txt 2>&1 & ``` -------------------------------- ### Install Peerbit Document Store Package Source: https://github.com/dao-xyz/peerbit/blob/master/docs/getting-started.md Installs the Peerbit document store package using npm. This package provides functionality for storing and managing documents within the Peerbit network. ```sh npm install @peerbit/document ``` -------------------------------- ### Install Peerbit using npm Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/client/README.md Installs the Peerbit package using npm. This is the first step to using Peerbit in your project. ```sh npm install peerbit ``` -------------------------------- ### TypeScript RPC Request/Response Example Source: https://github.com/dao-xyz/peerbit/blob/master/packages/programs/rpc/README.md Demonstrates how to define and use RPC services in TypeScript within the Peerbit framework. It shows the setup of query and response types, and how to send requests and handle responses between peers. Dependencies include the '@variant' decorator and the 'Program' class. ```typescript import { Program, field, RPC, variant } from '@peerbit/core'; @variant("hello") class Hello { constructor() { } } @variant("world") class World { constructor() { } } @variant("rpc-test") class RPCTest extends Program { @field({ type: RPC }) rpc: RPC; async setup(): Promise { await this.rpc.setup({ responseType: Hello, queryType: World, context: this, responseHandler: (resp, from) => { return resp; }, }); } } // Usage example: const peer = await Peerbit.create () const rpcTest = peer.open(new RPCTest()); await rpcTest.rpc.request( new Hello(), (resp) => { console.log(resp) }); ``` -------------------------------- ### Memory Configuration Example Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/client/README.md Demonstrates Peerbit memory configuration options, determining whether data persists between sessions or only in memory. This includes data and encryption keys. ```typescript const db = await PeerBIT.open('my-db', { directory: './my-db' }); ``` -------------------------------- ### Insert First Document into Peerbit Store Source: https://github.com/dao-xyz/peerbit/blob/master/docs/getting-started.md Illustrates how to insert the first document into a Peerbit document store. This involves creating a new entry with specific data and then saving it to the database. ```typescript const entry = await db.put({ title: 'Hello', content: 'World' }) console.log('Document inserted:', entry.hash) ``` -------------------------------- ### Install Node.js v19.x on Ubuntu Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/custom.md This code snippet installs Node.js version 19.x on Ubuntu-based Linux distributions using NodeSource's setup script. It's a prerequisite for installing the Peerbit CLI. ```bash curl -fsSL https://deb.nodesource.com/setup_19.x | sudo -E bash - && sudo apt-get install -y nodejs ``` -------------------------------- ### Install Peerbit CLI Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/custom.md Installs the Peerbit server CLI globally using npm. This command should be run after Node.js has been successfully installed. ```bash npm install -g @peerbit/server ``` -------------------------------- ### Define a Peerbit Document Database Source: https://github.com/dao-xyz/peerbit/blob/master/docs/getting-started.md Shows how to define a new document database using the Peerbit document store. This involves creating a DocumentStore instance with specific configuration, such as the database name and replication settings. ```typescript const db = await new DocumentStore({ id: 'my-document-store' }).open(peer) ``` -------------------------------- ### Install Project Dependencies with pnpm Source: https://github.com/dao-xyz/peerbit/blob/master/README.md Installs all necessary dependencies for the Peerbit project using pnpm. Ensure you have the correct pnpm version installed before running this command. ```shell pnpm install ``` -------------------------------- ### Program Definition Example (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/program/README.md This example demonstrates the structure of a Peerbit Program definition, showcasing how to define properties and potentially associated logic. It relies on Peerbit's core classes and decorators for data handling. ```typescript import { Program, Field, Variant, Vec, Option, StringEncrypted, BytesEncrypted, JSONValue, State, Timestamp } from "@peerbit/program"; @Variant("post") export class Post extends Program { @Field({ type: "string" }) title: string; @Field({ type: "string" }) content: string; @Field({ type: "string[]" }) tags: string[]; @Field({ type: Option }) author: Option; constructor(properties?: { title: string; content: string; tags: string[]; author?: string }) { super(properties); this.title = properties!.title; this.content = properties!.content; this.tags = properties!.tags; this.author = properties?.author; } } ``` -------------------------------- ### Multi-signed Posts Example (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/program/document-store/README.md Demonstrates how to override signers for insertions in Peerbit, allowing for multi-signature functionality. This example showcases the use of a `REQUIRED_SIGNER` for local testing, with notes on implementing remote signer functions for real-world scenarios. ```typescript import { Program, ProgramDocument, ProgramSystem } from '@peerbit/program'; import { Entry, Ed25519Keypair } from '@peerivity/crypto'; // Assume ProgramSystem and Program are defined elsewhere interface SignedEntry extends Entry { signatures: Map; } interface MultisigDocument extends ProgramDocument { data: any; requiredSigners: string[]; } async function signEntryWithKeys(entry: Entry, keys: Ed25519Keypair[]): Promise { const signedEntry: SignedEntry = { ...entry, signatures: new Map() }; for (const key of keys) { const signature = await key.sign(entry.hash()); signedEntry.signatures.set(key.getPublic(), signature); } return signedEntry; } async function insertWithMultisig(program: Program, data: any, requiredSigners: string[]): Promise { const document: MultisigDocument = { data: data, requiredSigners: requiredSigners, id: ProgramSystem.getNewId(), timestamp: Date.now(), program: program.id }; // In a real scenario, you would fetch or generate keypairs for requiredSigners // For this example, we simulate having them locally. const localKeypair = await Ed25519Keypair.create(); // Example local keypair const requiredKeypair = await Ed25519Keypair.create(); // Example required signer keypair const entry = ProgramSystem.createEntry(document); const signedEntry = await signEntryWithKeys(entry, [localKeypair, requiredKeypair]); // Add signatures from required signers (simulated) for (const signer of requiredSigners) { if (signer !== localKeypair.getPublic()) { // Avoid double signing if local is required // In a real app, this would involve a remote call or another local keypair const remoteSignature = await requiredKeypair.sign(entry.hash()); signedEntry.signatures.set(signer, remoteSignature); } } // Validate signatures here before insertion // ... insertion logic ... console.log('Entry signed and ready for insertion:', signedEntry); } // Example Usage: async function main() { // Assume 'myProgram' is an instance of a Peerbit Program const myProgram = {} as Program; // Placeholder const REQUIRED_SIGNER = 'some-public-key'; // Replace with actual public key await insertWithMultisig(myProgram, { message: 'Hello, world!' }, [REQUIRED_SIGNER]); } main(); ``` -------------------------------- ### Get Hetzner Cloud Peerbit Spawn Help Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/automatic.md Displays help information and available options for spawning Peerbit nodes on Hetzner Cloud using the CLI. ```sh peerbit remote spawn hetzner --help ``` -------------------------------- ### Encrypted Log Example - TypeScript Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/encryption/README.md Demonstrates how to create and manage an encrypted log in Peerbit. This example shows the basic setup for adding entries to a log where the content is end-to-end encrypted. ```typescript import { Peerbit } from 'peerbit'; // Assume 'peerbit' is an initialized Peerbit instance const peerbit = await Peerbit.create(); // Create an encrypted log const log = await peerbit.open_log('my-encrypted-log', { encryption: { type: 'x25519-trytes', keys: ['RECEIVER_PUBLIC_KEY_1', 'RECEIVER_PUBLIC_KEY_2'] } }); // Append an entry to the encrypted log const hash = await log.append('My secret message'); console.log('Encrypted entry appended with hash:', hash); ``` -------------------------------- ### Get AWS Peerbit Spawn Help Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/automatic.md Displays help information and available options for spawning Peerbit nodes on AWS using the CLI. ```sh peerbit remote spawn aws --help ``` -------------------------------- ### Open and Manipulate Documents with Peerbit in TypeScript Source: https://context7.com/dao-xyz/peerbit/llms.txt Demonstrates opening a Peerbit program, inserting, updating, and deleting documents within a PostsDB store. It also shows how to retrieve a document by its ID and stop the Peerbit peer. This example assumes a previously defined PostsDB class. ```typescript import { Peerbit } from '@peerbit/peerbit'; const peer = await Peerbit.create({ directory: './peer1' }); // Open the program (creates or loads existing) const store = await peer.open(new PostsDB()); console.log(store.address); // Content-addressed program ID // Insert documents await store.posts.put(new Post('Hello distributed world!')); await store.posts.put(new Post('Second post')); // Update a document (requires mutable documents) const post = new Post('Updated message'); post.id = 'existing-id'; await store.posts.put(post); // Delete a document await store.posts.del('document-id'); // Get a document by ID const doc = await store.posts.index.get('document-id'); console.log(doc?.message); // Stop the peer await peer.stop(); ``` -------------------------------- ### Bootstrap Peerbit Node Connection Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/client/README.md Shows how to bootstrap a Peerbit node to connect to the network using a public bootstrap list. This is the simplest way to get a node online. ```typescript const peer = await new PeerBIT() .addNetwork(network) .connect('multiaddr string'); ``` -------------------------------- ### Using Default Indexer (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/docs/topics/sqlite-integration/README.md Shows the default way to initialize the Peerbit client without explicitly providing an indexer, which defaults to using the `@peerbit/indexer-sqlite3` implementation. This is the simplest way to start using Peerbit with its standard indexing. ```typescript import { Peerbit } from 'peerbit' const client = await Peerbit.create() // if not passed, the default will be @peerbit/indexer-sqlite3 for indexer ``` -------------------------------- ### Define Forum Database using Composition (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/program/composition/README.md This example demonstrates how to define a forum database program by composing it with the Document Store program. It shows how to include external programs by adding them to your class definition, leveraging existing functionalities for building new ones. ```typescript import { Program, ProgramDB } from '@peerbit/program'; import { DocumentStore, Identity } from '@peerbit/programs'; interface Post { id: string; title: string; content: string; } export class Forum extends Program { private _postStore: DocumentStore; constructor(db: ProgramDB, private _identity: Identity) { super(db); } async open(): Promise { this._postStore = await this.add( new DocumentStore(this.db, { identity: this._identity, }) ); await super.open(); } async addPost(post: Post): Promise { return this._postStore.put(post); } async getPosts(): Promise { return this._postStore.get(); } } ``` -------------------------------- ### Configure Access Control for Documents Source: https://context7.com/dao-xyz/peerbit/llms.txt Control read, write, and search access to documents using fine-grained permissions. This example demonstrates setting write access to only allow the author and read/search access to anyone. ```typescript import { Peerbit } from '@peerbit/peerbit'; import { Documents } from '@peerbit/document'; import { Program } from '@peerbit/program'; import { AccessError } from '@peerbit/crypto'; import { variant, field } from '@dao-xyz/borsh'; @variant(0) class PrivateNote { @field({ type: 'string' }) id: string; @field({ type: 'string' }) content: string; constructor(id: string, content: string) { this.id = id; this.content = content; } } @variant('notes-db') class NotesDB extends Program { @field({ type: Documents }) notes: Documents; constructor() { super(); this.notes = new Documents(); } async open(): Promise { await this.notes.open({ type: PrivateNote, // Control write access canPerform: async ({ type, value, entry }) => { if (type === 'put') { // Only allow specific peers to write const authorKey = entry.signatures[0].publicKey; return authorKey.equals(this.node.identity.publicKey); } return true; }, index: { // Control search access canSearch: async (request) => { // Allow anyone to search return true; }, // Control read access canRead: async (document) => { // Allow anyone to read return true; } } }); } } const peer = await Peerbit.create(); const notes = await peer.open(new NotesDB()); // This succeeds (author is self) await notes.notes.put(new PrivateNote('1', 'My note')); await peer.stop(); ``` -------------------------------- ### Launch a Deployed Peerbit Program Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/publish/README.md After a Peerbit program has been installed on a remote node, this command is used to launch and run the specified program. Replace PROGRAM_NAME with the actual name of the program. ```sh program open --variant PROGRAM_NAME ``` -------------------------------- ### Configure Replication Strategy for Documents Source: https://context7.com/dao-xyz/peerbit/llms.txt Control how data is replicated across peers using custom replication domains. This example sets up a domain based on a timestamp property and replicates data to 50% of peers. ```typescript import { Peerbit } from '@peerbit/peerbit'; import { Documents, createDocumentDomainFromProperty } from '@peerbit/document'; import { Program } from '@peerbit/program'; import { variant, field } from '@dao-xyz/borsh'; @variant(0) class TimestampedEvent { @field({ type: 'string' }) id: string; @field({ type: 'u64' }) timestamp: bigint; @field({ type: 'string' }) data: string; constructor(id: string, timestamp: bigint, data: string) { this.id = id; this.timestamp = timestamp; this.data = data; } } @variant('events-db') class EventsDB extends Program { @field({ type: Documents }) events: Documents; constructor() { super(); this.events = new Documents(); } async open(): Promise { await this.events.open({ type: TimestampedEvent, // Create custom replication domain based on timestamp domain: createDocumentDomainFromProperty({ property: 'timestamp', resolution: 'u64' }), // Control replication behavior replicate: { factor: 0.5 // Replicate to 50% of peers } }); } } const peer = await Peerbit.create(); const events = await peer.open(new EventsDB()); await events.events.put( new TimestampedEvent('evt1', BigInt(Date.now()), 'Event data') ); await peer.stop(); ``` -------------------------------- ### Query Documents with Filters, Sorting, and Pagination in TypeScript Source: https://context7.com/dao-xyz/peerbit/llms.txt Demonstrates how to search and query documents using filters, sorting, and pagination with the Peerbit document API. It includes examples for searching all documents, applying query filters, sorting results, and paginating fetched data. Dependencies include `@peerbit/document` and `@peerbit/indexer-interface`. ```typescript import { SearchRequest, Sort, SortDirection } from '@peerbit/document'; import { StringMatch } from '@peerbit/indexer-interface'; const peer = await Peerbit.create(); const store = await peer.open(new PostsDB()); // Search all documents const allPosts = await store.posts.index.search( new SearchRequest({ query: [] }), { local: true, // Search local data remote: false // Don't query remote peers } ); // Search with query filter const filtered = await store.posts.index.search( new SearchRequest({ query: [ new StringMatch({ key: 'message', value: 'hello' }) ] }) ); // Search with sorting const sorted = await store.posts.index.search( new SearchRequest({ query: [], sort: [ new Sort({ key: ['timestamp'], direction: SortDirection.DESC }) ] }) ); // Paginated search const paginated = await store.posts.index.search( new SearchRequest({ query: [], fetch: 10 // Limit results }) ); await peer.stop(); ``` -------------------------------- ### Connect to a Group of Nodes and Deploy Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/publish/README.md This command allows for simultaneous deployment of a Peerbit package to multiple remote nodes by connecting to a predefined group. It first establishes a connection to the group and then proceeds with the installation of the package. ```sh peerbit remote connect --group X install ./my-package.tgz ``` -------------------------------- ### Display Peerbit Help Information Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/server/custom.md Displays general help information for the Peerbit CLI. This is useful for understanding the available commands and their basic usage. ```bash peerbit --help ``` -------------------------------- ### Create a Document Store in TypeScript Source: https://github.com/dao-xyz/peerbit/blob/master/docs/README.md Demonstrates how to initialize a document store for storing and managing posts. This is a fundamental operation for managing data in Peerbit. ```typescript const docStore = await peerbit.open(new DocumentStore(), { identity: "my-identity", name: "my-document-store" }); await docStore.create(); ``` -------------------------------- ### Install Packaged Peerbit Build on Remote Node Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/deploy/publish/README.md This command installs a previously built and packaged Peerbit program (.tgz file) onto a connected remote node. Ensure you are connected to the node before executing this command. ```sh install the-name-of-your-build.tgz ``` -------------------------------- ### Define and Use a Document Store with Peerbit Source: https://github.com/dao-xyz/peerbit/blob/master/docs/topics/sqlite-integration/README.md This TypeScript example demonstrates defining a 'Post' document structure and a 'Channel' program that utilizes the 'Documents' store for managing these posts. It includes opening the store, adding a new post, and searching for posts based on message content. The 'Documents' store automatically creates an index for the 'Post' type. ```typescript import { Documents } from "@peerbit/document"; import { Program, ProgramArgs } from "@peerbit/program"; import { variant, field } from "@peerbit/json-rpc"; import { sha256Sync } from "@peerbit/crypto"; import { SearchRequest } from "@peerbit/query"; import { option } from "@peerbit/collections"; import { uuid } from "@peerbit/crypto"; @variant(0) // version 0 export class Post { @field({ type: "string" }) id: string; @field({ type: "string" }) message: string; @field({ type: option("string") }) parentPostId?: string; // if this value exists, then this post is a comment constructor(message: string) { this.id = uuid(); this.message = message; } } export interface ChannelArgs { } @variant("channel") export class Channel extends Program { // Documents provide document store functionality around posts @field({ type: Documents }) posts: Documents; constructor() { super(); this.posts = new Documents({ id: sha256Sync(new TextEncoder().encode("posts")), }); } // Setup will be called on 'open' await open(): Promise { await this.posts.open({ type: Post }); } } const channel = await client.open(new Channel()) await channel.posts.put(new Post("Hello World!")) // find the post const result = await channel.posts.index.search(new SearchRequest({message: 'Hello World!'})) console.log(result) // [Post] ``` -------------------------------- ### Publish and Subscribe Messaging with DirectSub Source: https://context7.com/dao-xyz/peerbit/llms.txt Utilize the low-level pubsub layer (DirectSub) for custom messaging patterns between peers. This example demonstrates subscribing to a topic, listening for messages, publishing messages, and managing subscribers. ```typescript import { Peerbit } from '@peerbit/peerbit'; const peer1 = await Peerbit.create(); const peer2 = await Peerbit.create(); // Access pubsub service const pubsub1 = peer1.services.pubsub; const pubsub2 = peer2.services.pubsub; // Connect peers await peer2.dial(peer1.getMultiaddrs()); // Subscribe to topic await pubsub2.subscribe('my-topic'); // Listen for messages pubsub2.addEventListener('data', (event) => { const data = event.detail; console.log('Received:', new TextDecoder().decode(data.data)); }); // Publish message await pubsub1.publish( new TextEncoder().encode('Hello from peer1'), { topics: ['my-topic'] } ); // Get subscribers const subscribers = await pubsub1.getSubscribers('my-topic'); console.log('Subscribers:', subscribers?.size); // Unsubscribe await pubsub2.unsubscribe('my-topic'); await peer1.stop(); await peer2.stop(); ``` -------------------------------- ### Encrypted Document Store Example - TypeScript Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/encryption/README.md Illustrates how to set up and use an encrypted document store in Peerbit. Document stores extend the log functionality and can also leverage E2E encryption for storing sensitive data. ```typescript import { Peerbit } from 'peerbit'; // Assume 'peerbit' is an initialized Peerbit instance const peerbit = await Peerbit.create(); // Create an encrypted document store const docStore = await peerbit.open_document_store('my-encrypted-docs', { encryption: { type: 'x25519-trytes', keys: ['RECEIVER_PUBLIC_KEY_1', 'RECEIVER_PUBLIC_KEY_2'] } }); // Add a document to the encrypted store const hash = await docStore.put({ id: 'doc1', content: 'This is a secret document.' }); console.log('Encrypted document stored with hash:', hash); // Retrieve the document (will be decrypted automatically if the key is available) const doc = await docStore.get('doc1'); console.log('Retrieved document:', doc); ``` -------------------------------- ### Listen to Program and Network Events in TypeScript Source: https://context7.com/dao-xyz/peerbit/llms.txt Demonstrates how to subscribe to various program lifecycle and network events within Peerbit. This includes listening for peers joining or leaving, document changes, program open/close events, and waiting for specific peers to become ready. Dependencies include `@peerbit/peerbit`. ```typescript import { Peerbit } from '@peerbit/peerbit'; const peer = await Peerbit.create(); const store = await peer.open(new PostsDB()); // Listen for new peers joining store.events.addEventListener('join', (event) => { const publicKey = event.detail; // PublicSignKey console.log('Peer joined:', publicKey.hashcode()); }); // Listen for peers leaving store.events.addEventListener('leave', (event) => { const publicKey = event.detail; console.log('Peer left:', publicKey.hashcode()); }); // Listen for document changes store.posts.events.addEventListener('change', (event) => { const change = event.detail; // DocumentsChange console.log('Documents changed:', change.added.length, 'added'); }); // Listen for program lifecycle store.events.addEventListener('open', (event) => { console.log('Program opened'); }); store.events.addEventListener('close', (event) => { console.log('Program closed'); }); // Wait for specific peer to be ready await store.waitFor(peer2.identity.publicKey, { timeout: 10000 }); await peer.stop(); ``` -------------------------------- ### Bootstrap to Network in TypeScript Source: https://context7.com/dao-xyz/peerbit/llms.txt Shows how to connect to bootstrap nodes to join the distributed network and manually dial/hang up specific peers. This includes bootstrapping to default nodes, custom addresses, and managing direct peer connections. Dependencies include `@peerbit/peerbit` and `@multiformats/multiaddr`. ```typescript import { Peerbit } from '@peerbit/peerbit'; import { multiaddr } from '@multiformats/multiaddr'; const peer = await Peerbit.create(); // Bootstrap to default nodes await peer.bootstrap(); // Bootstrap to custom addresses await peer.bootstrap([ '/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', '/dns4/bootstrap.example.com/tcp/4001/p2p/QmExample123' ]); // Manually dial specific peers const addr = multiaddr('/ip4/192.168.1.100/tcp/4001/p2p/QmPeerID'); await peer.dial(addr); // Hang up connection await peer.hangUp(addr); await peer.stop(); ``` -------------------------------- ### Owned Document Migration (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/program/document-store/README.md Presents a strategy for migrating documents in a decentralized P2P setup where each peer migrates their own documents. This involves running a migration job on open that iterates over local documents and re-inserts them in the new format. ```typescript import { Program, ProgramDocument, ProgramSystem, DocumentStore } from '@peerbit/program'; // Assume PostV0 and PostV1 interfaces are defined as in the polymorphic migration example interface PostV0 extends ProgramDocument { message: string; author: string; } interface PostV1 extends ProgramDocument { content: string; writer: string; timestamp: number; } function migratePostV0ToV1(postV0: PostV0): PostV1 { return { ...postV0, id: postV0.id, timestamp: postV0.timestamp, content: postV0.message, writer: postV0.author }; } class MigratableDocumentStore extends DocumentStore { constructor(program: Program, options?: any) { super(program, options); } async onOpen(): Promise { await super.onOpen(); console.log('Running migration job on open...'); await this.migrateOwnedDocuments(); } async migrateOwnedDocuments(): Promise { const documents = await this.getWhere({ author: this.program.identity.publicKey }); // Example: filter by own documents for (const doc of documents) { if (this.isPostV0(doc)) { console.log(`Migrating document ${doc.id} from V0 to V1...`); const postV1 = migratePostV0ToV1(doc); // Re-insert the document with the new type await this.put(postV1); // Optionally, delete the old V0 document if desired and possible // await this.del(doc.id); } } console.log('Migration job finished.'); } isPostV0(doc: PostV0 | PostV1): doc is PostV0 { // Type guard to check if it's a V0 document return (doc as PostV0).message !== undefined; } } // Example Usage: async function runOwnedMigration() { // Assume 'myProgram' is an instance of a Peerbit Program const myProgram = {} as Program; // Placeholder myProgram.identity = { publicKey: 'my-public-key' }; // Mock identity const store = new MigratableDocumentStore(myProgram, { // ... store options ... }); await store.open(); // This will trigger onOpen and the migration job // Simulate having some V0 documents const postV0_1: PostV0 = { id: ProgramSystem.getNewId(), timestamp: Date.now(), program: myProgram.id, message: 'First post', author: 'my-public-key' }; const postV0_2: PostV0 = { id: ProgramSystem.getNewId(), timestamp: Date.now(), program: myProgram.id, message: 'Second post', author: 'my-public-key' }; await store.put(postV0_1); await store.put(postV0_2); console.log('Documents after initial insertion (simulated):', await store.getWhere({})); // Re-opening or re-running migration would process these. } runOwnedMigration(); ``` -------------------------------- ### Manage Trusted Network Peers in TypeScript Source: https://github.com/dao-xyz/peerbit/blob/master/packages/programs/acl/trusted-network/README.md This snippet illustrates the process of setting up two peers, opening a `StringStore` program on the first peer, and then establishing trust relationships between them. It shows how to add another peer's public key to the network and how the second peer joins the network to receive the trust graph. ```typescript // Later const peer1 = await Peerbit.create(LIBP2P_CLIENT, {... options ...}) const peer2 = await Peerbit.create(LIBP2P_CLIENT_2, {... options ...}) const programPeer1 = await peer1.open(new StringStore({log: new Log(), network: new TrustedNetwork()}), {... options ...}) // add trust to another peer await program.network.add(peer2.identity.publicKey) // peer2 also has to "join" the network, in practice this means that peer2 adds a record telling that its Peer ID trusts its libp2p Id const programPeer2 = await peer2.open(programPeer1.address, {... options ...}) await peer2.join(programPeer2) // This might fail with "AccessError" if you do this too quickly after "open", because it has not yet received the full trust graph from peer1 yet ``` -------------------------------- ### Build Project with pnpm Source: https://github.com/dao-xyz/peerbit/blob/master/Agents.md Builds the project using the pnpm build script. This command compiles the project's code and prepares it for further use or deployment. ```bash pnpm run build ``` -------------------------------- ### Get Subscribers Count (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/packages/transport/pubsub/README.md Retrieves the aggregated number of subscribers for a given topic. This method provides an accurate count by considering subscribers from immediate peers and potentially other network paths, going beyond simple direct peer information. ```typescript .getSubscribers(topic) ``` -------------------------------- ### Centralized Authority Document Migration (TypeScript) Source: https://github.com/dao-xyz/peerbit/blob/master/docs/modules/program/document-store/README.md Provides an example of a centralized authority approach to document migration in a P2P network. A trusted authority can insert and mutate documents, with peers verifying operations based on the authority's public key in the `canPerform` callback. ```typescript import { Program, ProgramDocument, ProgramSystem, DocumentStore } from '@peerbit/program'; import { Ed25519Keypair } from '@peerivity/crypto'; // Assume PostV0 and PostV1 interfaces are defined interface PostV0 extends ProgramDocument { message: string; author: string; } interface PostV1 extends ProgramDocument { content: string; writer: string; timestamp: number; } function migratePostV0ToV1(postV0: PostV0): PostV1 { return { ...postV0, id: postV0.id, timestamp: postV0.timestamp, content: postV0.message, writer: postV0.author }; } // Define the trusted authority's keypair let centralAuthorityKeypair: Ed25519Keypair; async function initializeAuthority() { centralAuthorityKeypair = await Ed25519Keypair.create(); console.log('Central Authority Public Key:', centralAuthorityKeypair.getPublic()); } class CentralizedMigrationStore extends DocumentStore { constructor(program: Program, options?: any) { super(program, options); } async canPerform(op: any): Promise { // Allow operations from the central authority if (op.signer === centralAuthorityKeypair.getPublic()) { return true; } // Fallback to default checks for other operations (e.g., owner permissions) return super.canPerform(op); } async performMigrationAsAuthority(docId: string): Promise { if (!centralAuthorityKeypair) { throw new Error('Central authority not initialized.'); } const doc = await this.get(docId); if (this.isPostV0(doc)) { console.log(`Authority migrating document ${docId} from V0 to V1...`); const postV1 = migratePostV0ToV1(doc); // Create a new entry signed by the central authority const entry = this.createEntry(postV1); const signedEntry = await centralAuthorityKeypair.sign(entry.hash()); entry.signatures.set(centralAuthorityKeypair.getPublic(), signedEntry); // Use put operation with the signed entry await this.put(postV1, { from: centralAuthorityKeypair.getPublic() }); // Assuming put can accept pre-signed entries or use internal method // Optionally delete the old document, also signed by authority // await this.del(docId, { from: centralAuthorityKeypair.getPublic() }); console.log(`Document ${docId} migrated successfully by authority.`); } } isPostV0(doc: PostV0 | PostV1): doc is PostV0 { return (doc as PostV0).message !== undefined; } } // Example Usage: async function runCentralizedMigration() { await initializeAuthority(); // Assume 'myProgram' is an instance of a Peerbit Program const myProgram = {} as Program; // Placeholder myProgram.identity = { publicKey: 'some-peer-key' }; // A regular peer's identity const store = new CentralizedMigrationStore(myProgram, { // ... store options ... }); await store.open(); // Simulate having a V0 document owned by someone else const authoritySigner = await Ed25519Keypair.create(); // Simulating another user const postV0_other: PostV0 = { id: ProgramSystem.getNewId(), timestamp: Date.now(), program: myProgram.id, message: "Document to be migrated by authority", author: authoritySigner.getPublic() }; await store.put(postV0_other); console.log('Document before centralized migration:', await store.get(postV0_other.id)); // Authority performs the migration await store.performMigrationAsAuthority(postV0_other.id); console.log('Document after centralized migration:', await store.get(postV0_other.id)); } runCentralizedMigration(); ```