diff --git a/docs/docs/core-concepts.md b/docs/docs/core-concepts.md index b3837040..64a3005d 100644 --- a/docs/docs/core-concepts.md +++ b/docs/docs/core-concepts.md @@ -11,245 +11,103 @@ Hypergraph re-imagines traditional client–server apps as **local-first**, **pe ## Table of Contents -- [Knowledge Graphs and GRC-20](#knowledge-graphs-and-grc-20) +- [Knowledge Graphs](#knowledge-graphs) +- [Hypergraph SDK](#hypergraph-sdk-in-action) - [Spaces](#spaces) - [Identities](#identities) - [Inboxes](#inboxes) - [Events & CRDTs](#events--crdts) - [Security Model](#security-model) +- [GRC-20: The Protocol Under the Hood](#grc-20-the-protocol-under-the-hood) --- -## Knowledge Graphs and GRC-20 +## Knowledge Graphs -Hypergraph adopts **GRC-20** as its canonical data format. Every mutation you perform through the Hypergraph SDK—whether it's adding a note, uploading a photo, or inviting a collaborator—ultimately becomes a set of GRC-20 values bundled into an edit. Once the edit is posted, it becomes part of the global knowledge graph—instantly connecting your data to a world of interoperable apps, spaces, and users. From that moment the edit is immutable and immediately queryable via Hypergraph's hooks and GraphQL APIs. +Traditional databases store data in rows and columns. Knowledge graphs store data as **networks of connected information**—think of it like a mind map where every piece of information can link to any other piece. -### 1. The GRC-20 Standard -The GRC-20 standard defines how knowledge is structured, shared, and connected in a decentralized, composable way—enabling interoperability across web3 applications. It specifies the core building blocks: entities, types, properties, relations, and values. Read the [GRC-20 spec on GitHub](https://github.com/graphprotocol/graph-improvement-proposals/blob/main/grcs/0020-knowledge-graph.md). +### Why Knowledge Graphs? -### 2. Core Data Model Concepts +Imagine you're building a social app. In a traditional database, you might have separate tables for `users`, `posts`, and `likes`. But what if you want to find "posts by photographers that my friends liked"? That requires complex joins across multiple tables. -To illustrate the core pieces of a knowledge graph, we'll break down a single sentence: +In a knowledge graph, the relationships *are* the data: -> **"Teresa, a photographer, owns a Fujifilm camera."** - -#### The Value Model -In GRC-20, each **entity** is a node in the graph with a list of **values**. Each value attaches a **property** (by ID) and a literal value (plus options). Properties define the data type and constraints for their values. **Relations** are first-class objects that connect entities and can have their own properties and metadata. - -**Example property definition:** -```json -{ - "id": "PROFESSION_ATTR_ID", - "data_type": "TEXT" -} -``` - -**Example entity with values:** -```json -{ - "id": "Teresa_ID", - "values": [ - { "property": "PROFESSION_ATTR_ID", "value": "photographer" } - ] -} +```mermaid +graph LR + Teresa[👩 Teresa] -->|profession| Photography[📸 Photography] + Teresa -->|owns| Camera[📷 Fujifilm X100] + Teresa -->|posted| Photo[🖼️ Street Photo] + Alex[👨 Alex] -->|friend_of| Teresa + Alex -->|liked| Photo ``` -**Example in code:** -```ts -Graph.createEntity({ - name: 'Teresa', - types: [PERSON_TYPE_ID], - values: [ - { property: PROFESSION_ATTR_ID, value: 'photographer' } - ] -}); -``` +This makes complex queries natural and fast. Plus, your data model can evolve organically—just add new types of entities and relationships without schema migrations. -#### IDs: Where Do They Come From? -Every entity, attribute, and relation has a unique ID (usually a string, e.g. `PERSON_TYPE_ID`). These are generated per your schema or space, and are required for all operations. +### The Hypergraph Advantage -#### Entities & Types -**Entity:** A unique thing in the graph (e.g., `Teresa`, `Camera`). -**Type:** A category for entities (e.g., `Person`, `Device`). +Hypergraph takes knowledge graphs further by making them: -```ts -const PERSON_TYPE_ID = 'PERSON_TYPE_ID'; -const DEVICE_TYPE_ID = 'DEVICE_TYPE_ID'; -const PROFESSION_ATTR_ID = 'PROFESSION_ATTR_ID'; -const BRAND_ATTR_ID = 'BRAND_ATTR_ID'; +- **🔒 Private by default** — Your personal data stays encrypted on your device +- **🌐 Peer-to-peer** — No central server required; collaborate directly with friends +- **⚡ Real-time** — Changes sync instantly across all your devices +- **🔗 Interoperable** — Your data works across different apps that speak the same protocol -const { id: cameraId, ops: cameraOps } = Graph.createEntity({ - name: 'Camera', - types: [DEVICE_TYPE_ID], - values: [ - { property: BRAND_ATTR_ID, value: 'Fujifilm' }, - ], -}); +> **The magic:** Under the hood, Hypergraph serializes everything using the **GRC-20** standard. As a developer, you just work with simple SDK calls—Hypergraph handles the complex cryptography and networking. If you're curious about the low-level details, check out the [GRC-20 section](#grc-20-advanced) below. -const { id: teresaId, ops: teresaOps } = Graph.createEntity({ - name: 'Teresa', - types: [PERSON_TYPE_ID], - values: [ - { property: PROFESSION_ATTR_ID, value: 'photographer' }, - ], -}); -``` +## Hypergraph SDK in Action -#### Properties vs. Relations -- **Property:** Attaches data to a single entity (e.g., `Camera` → `brand` → `Fujifilm`). -- **Relation:** Connects two entities (e.g., `Teresa` → `owns` → `Camera`). Relations are themselves entities and can have their own properties (e.g., `date_acquired`). +Let's build that photographer example step by step: ```ts -const OWNS_REL_TYPE_ID = 'OWNS_REL_TYPE_ID'; -const DATE_ACQUIRED_ATTR_ID = 'DATE_ACQUIRED_ATTR_ID'; - -import { getEntityRelations } from '@graphprotocol/grc-20'; - -// 1️⃣ Fetch existing owns relations for Teresa -const existingOwns = getEntityRelations(teresaId, PersonSchema, doc).owns; - -// 2️⃣ Only create if none exists pointing to this camera -if (!existingOwns.find(rel => rel.id === cameraId)) { - const { ops: ownsOps } = Graph.createRelation({ - fromEntity: teresaId, - toEntity: cameraId, - relationType: OWNS_REL_TYPE_ID, - values: [ - { property: DATE_ACQUIRED_ATTR_ID, value: Graph.serializeDate(new Date('2020-03-15')) }, - ], - }); - // add ownsOps to your edit batch… -} -``` - -**Relation JSON example:** -```json -{ - "id": "OwnsRelation_ID", - "type": "OWNS_REL_TYPE_ID", - "from_entity": "Teresa_ID", - "to_entity": "Camera_ID", - "entity": "OwnsRelationEntity_ID", // rich relation entity UUID (optional) - "position": "a", - "verified": false -} -``` - -#### Searching and Idempotency -The SDK generates a new ID for every entity or relation you create—even if an identical relation already exists. To avoid duplicates: - -- **Query existing relations** via your GraphQL endpoint with a filter on `from`, `relationType`, and `to`. -- **Use** `getEntityRelations` (from `@graphprotocol/grc-20`) on a local handle to list current relations for an entity: - -```ts -import { getEntityRelations } from '@graphprotocol/grc-20'; - -// Returns all non-deleted owns relations from Teresa -const relations = getEntityRelations(teresaId, PersonSchema, doc).owns; -``` - -- **Check** if a relation linking the same entities already exists before calling `Graph.createRelation`. - -If you call `createRelation` without checking, you'll end up with multiple relation entities of the same type between the same entities. Deduplication is the responsibility of your application or schema governance. - -#### Minimal Edit Example -Bundle all operations into an edit: -```ts -const ops = [...cameraOps, ...teresaOps, ...ownsOps]; -// Publish ops as an edit (see SDK docs for publishing) -``` - -Let's bring together everything we've learned above—including our example sentence—into a complete GRC-20–compliant TypeScript example that is fully composable with Hypergraph. - -```ts title="example.ts" -// Example: "Teresa, a photographer, owns a Fujifilm camera." -// This script uses the @graphprotocol/grc-20 SDK to: -// 1. Create a Camera entity with a brand property -// 2. Create a Teresa entity with a profession property -// 3. Check for an existing 'owns' relation from Teresa to the Camera -// 4. If none exists, create the 'owns' relation entity -// 5. Bundle all operations into a single edit (ops array) - -import { Graph, getEntityRelations } from '@graphprotocol/grc-20'; - -// Replace these with actual IDs from your schema/space -const PERSON_TYPE_ID = 'PERSON_TYPE_ID'; -const DEVICE_TYPE_ID = 'DEVICE_TYPE_ID'; -const PROFESSION_ATTR_ID = 'PROFESSION_ATTR_ID'; -const BRAND_ATTR_ID = 'BRAND_ATTR_ID'; -const OWNS_REL_TYPE_ID = 'OWNS_REL_TYPE_ID'; -const DATE_ACQUIRED_ATTR_ID = 'DATE_ACQUIRED_ATTR_ID'; - -// 1️⃣ Create the Camera entity with a brand property -const { id: cameraId, ops: cameraOps } = Graph.createEntity({ - name: 'Fujifilm camera', - types: [DEVICE_TYPE_ID], - values: [ - { property: BRAND_ATTR_ID, value: 'Fujifilm' }, - ], -}); - -// 2️⃣ Create the Teresa entity with a profession property -const { id: teresaId, ops: teresaOps } = Graph.createEntity({ - name: 'Teresa', - types: [PERSON_TYPE_ID], - values: [ - { property: PROFESSION_ATTR_ID, value: 'photographer' }, - ], -}); - -// 3️⃣ Fetch existing 'owns' relations for Teresa -const existingOwns = getEntityRelations(teresaId, PersonSchema, doc).owns; - -// 4️⃣ Only create if none exists pointing to this camera -let ownsOps = []; -if (!existingOwns.find(rel => rel.id === cameraId)) { - const { ops } = Graph.createRelation({ - fromEntity: teresaId, - toEntity: cameraId, - relationType: OWNS_REL_TYPE_ID, - values: [ - { property: DATE_ACQUIRED_ATTR_ID, value: Graph.serializeDate(new Date('2020-03-15')) }, - ], - }); - ownsOps = ops; +import { useHypergraph } from '@graphprotocol/hypergraph-react'; + +function CreateProfile() { + const { createEntity, createRelation } = useHypergraph(); + + const handleCreateProfile = async () => { + // 1️⃣ Create Teresa as a person + const teresa = await createEntity({ + name: 'Teresa', + type: 'Person', + properties: { + profession: 'photographer', + bio: 'Street photographer based in Tokyo' + } + }); + + // 2️⃣ Create her camera + const camera = await createEntity({ + name: 'Fujifilm X100V', + type: 'Camera', + properties: { + brand: 'Fujifilm', + model: 'X100V' + } + }); + + // 3️⃣ Connect them with an "owns" relationship + await createRelation({ + from: teresa.id, + to: camera.id, + type: 'owns', + properties: { + purchaseDate: '2023-06-15' + } + }); + }; + + return ; } - -// 5️⃣ Combine all ops into a single edit -const ops = [...cameraOps, ...teresaOps, ...ownsOps]; -console.log('Ops ready for publishing:', ops); - -// (Optional) Publish the edit -// Graph.publishEdit({ ops }); ``` ---- - -#### Mental Model Recap -- **Entities** are things. -- **Properties** are facts about things, and define the data type. -- **Relations** connect things (and can have their own properties). -- **Values** are atomic facts (entity, property, value). -- **Edits** are batches of changes. - -#### Cheat Sheet Table -| Concept | Example in Sentence | GRC-20 Term | Code Snippet | -|----------|---------------------|-------------|--------------| -| Entity | Teresa, Camera | Entity | `{ id, name }` | -| Type | Person, Device | Type | `types: [PERSON_TYPE_ID]` | -| Property | profession, brand | Property | `{ id: BRAND_ATTR_ID, data_type: 'TEXT' }` | -| Relation | owns | Relation | `{ from_entity, to_entity, type }` | -| Value | `Teresa → profession → photographer` | Value | `{ property: PROFESSION_ATTR_ID, value: 'photographer' }` | -| Edit | batch of all values | Edit | `ops: [...]` | - ---- -_All of the above is not just theory—Hypergraph puts it to work for you._ **When you call the SDK or its React hooks, Hypergraph turns your mutations into values, bundles them into edits, encrypts them (if the Space is private), and syncs them peer-to-peer or anchors them on-chain if the data is public.** As a developer you think in entities and hooks; behind the scenes Hypergraph speaks pure GRC-20. +That's it! Behind the scenes, Hypergraph: +- Generates unique IDs for each entity +- Encrypts the data (if in a private Space) +- Syncs changes to all connected devices +- Makes everything queryable via GraphQL ---- - -All of these building blocks are specified by the GRC-20 standard and created in code with the GRC-20 SDK. +**Next:** Learn about [Spaces](#spaces)—how Hypergraph organizes people and data into collaborative groups. -### 3. The GRC-20 SDK -The [`@graphprotocol/grc-20`](https://www.npmjs.com/package/@graphprotocol/grc-20) SDK is a toolkit for building, reading, and writing GRC-20-compliant knowledge graphs. It provides APIs for creating entities, types, properties, and relations, and handles serialization, publishing to IPFS, and onchain anchoring—making it easy to implement the GRC-20 standard in your apps. + ## Spaces @@ -313,6 +171,90 @@ When the event log grows large, a peer may emit `sendCompactedUpdate`—a snapsh | Stale clients | Each event carries `lastKnownSpaceEventId`; server rejects out-of-date mutations. | | Key leakage on member removal | **Key rotation** through `removeMember` → generates a new `spaceKey`. | +## GRC-20: The Protocol Under the Hood + +> **⚠️ Advanced Section:** You don't need to understand GRC-20 to build with Hypergraph! This is for developers who want to understand the underlying protocol or need low-level access to the knowledge graph. + +Think of GRC-20 as the "assembly language" of knowledge graphs. While Hypergraph gives you high-level React hooks and intuitive APIs, GRC-20 defines the precise data format that makes everything interoperable. + +### Why Does GRC-20 Exist? + +Imagine if every social app stored data differently—Instagram used JSON, TikTok used XML, Twitter used CSV. Your photos, posts, and connections would be trapped in silos forever. + +GRC-20 solves this by creating a **universal format** for knowledge. Any app that speaks GRC-20 can read, write, and build upon data created by any other GRC-20 app. + +### The Five Building Blocks + +Let's decode the sentence *"Teresa, a photographer, owns a Fujifilm camera"* into its GRC-20 components: + +| **English** | **GRC-20 Term** | **What It Represents** | +|-------------|-----------------|------------------------| +| "Teresa" | **Entity** | A unique thing in the graph | +| "photographer" | **Value** | A piece of data attached to an entity | +| "profession" | **Property** | The type/schema of a value | +| "Person" | **Type** | The category an entity belongs to | +| "owns" | **Relation** | A connection between two entities | + +### Raw GRC-20 Code + +Here's how that sentence looks when written directly with the [`@graphprotocol/grc-20`](https://www.npmjs.com/package/@graphprotocol/grc-20) library: + +```ts title="Low-level GRC-20 example" +import { Graph } from '@graphprotocol/grc-20'; + +// 1️⃣ Define your schema IDs (normally auto-generated) +const PERSON_TYPE = 'schema:type:person'; +const CAMERA_TYPE = 'schema:type:camera'; +const PROFESSION_PROP = 'schema:property:profession'; +const BRAND_PROP = 'schema:property:brand'; +const OWNS_RELATION = 'schema:relation:owns'; + +// 2️⃣ Create entities with their properties +const { id: teresaId, ops: teresaOps } = Graph.createEntity({ + name: 'Teresa', + types: [PERSON_TYPE], + values: [ + { property: PROFESSION_PROP, value: 'photographer' } + ] +}); + +const { id: cameraId, ops: cameraOps } = Graph.createEntity({ + name: 'Fujifilm X100V', + types: [CAMERA_TYPE], + values: [ + { property: BRAND_PROP, value: 'Fujifilm' } + ] +}); + +// 3️⃣ Create the relationship +const { ops: relationOps } = Graph.createRelation({ + fromEntity: teresaId, + toEntity: cameraId, + relationType: OWNS_RELATION +}); + +// 4️⃣ Bundle everything into a single "edit" +const allOperations = [...teresaOps, ...cameraOps, ...relationOps]; + +// 5️⃣ Publish to the network (IPFS, blockchain, etc.) +await Graph.publishEdit({ ops: allOperations }); +``` + +### When Would You Use GRC-20 Directly? + +Most developers should stick with the Hypergraph SDK! But you might drop down to GRC-20 if you're: + +- **Building infrastructure tools** (indexers, validators, etc.) +- **Migrating data** from other formats into the knowledge graph +- **Creating custom query engines** that need maximum performance +- **Debugging issues** at the protocol level + +For typical app development, Hypergraph's React hooks and high-level APIs are much more convenient and handle all the GRC-20 complexity for you. + +--- + +**Want to learn more?** Read the full [GRC-20 specification](https://github.com/graphprotocol/graph-improvement-proposals/blob/main/grcs/0020-knowledge-graph.md) on GitHub. + --- ### Edit on GitHub diff --git a/docs/docs/quickstart.md b/docs/docs/quickstart.md index c8b1919e..ae0357d3 100644 --- a/docs/docs/quickstart.md +++ b/docs/docs/quickstart.md @@ -1,108 +1,73 @@ --- title: Quickstart -description: Spin up the Hypergraph monorepo locally, including sync server, event workers, and example app. +description: Create your first Hypergraph-powered application in minutes with TypeSync. version: 0.0.1 -tags: [quickstart] +tags: [quickstart, typesync] --- -# 🚀 Quickstart +# 🚀 Quickstart: Your First Hypergraph App + +This guide will walk you through creating a new, fully-functional React application powered by Hypergraph using our scaffolding tool, **TypeSync**. In just a few minutes, you'll have a local development environment up and running. + +This approach is perfect for developers who want to quickly build an application on top of Hypergraph without needing to set up the entire monorepo infrastructure. ## Prerequisites -- Node >= 18 (tested on 20+) -- pnpm >= 7 (install via `npm install -g pnpm`) -- Bun (optional, but speeds up the dev server — install via `curl -fsSL https://bun.sh/install | bash`) +- Node.js >= 18 (we recommend v20+) +- pnpm >= 7 (install with `npm install -g pnpm`) -Follow these steps to run the **Hypergraph monorepo** on your machine. +## 1. Get the Hypergraph Toolkit -## 1. Clone the repository +First, clone the Hypergraph repository, which contains TypeSync. ```bash git clone https://github.com/graphprotocol/hypergraph.git cd hypergraph ``` -## 2. Setup - -Install dependencies and initialize the database: +Next, install dependencies and build the required packages. This step ensures that TypeSync and all its components are ready to use. ```bash pnpm install -cd apps/server -cp .env.example .env -pnpm prisma migrate dev -``` - -## 3. Build workspace packages - -Before you run *any* app you must compile the TypeScript workspaces so their `dist/` folders exist: - -```bash -pnpm build # one-off build of every package (hypergraph-react, hypergraph, …) +pnpm build ``` -> Pro-tip: while iterating on library code you can use the watch script instead of running a full build each time: -> -> ```bash -> pnpm --filter @graphprotocol/hypergraph-react dev # tsc -w -> ``` - -After the initial build you can keep a watcher running or rely on the one we start in the next section. +## 2. Launch TypeSync -## 4. Development +TypeSync is a visual tool that helps you define your data schema and then generates a complete starter application based on your design. -Start a watcher to rebuild packages on change: +Navigate to the `typesync` app and start its development server: ```bash -pnpm build --watch +cd apps/typesync +pnpm dev ``` -Then, in separate terminal tabs, run the services: +This will start the TypeSync server. You can now access the **TypeSync Studio** in your browser at `http://localhost:4000`. -```bash -# Terminal tab 1: event workers -cd apps/events -pnpm dev +## 3. Scaffold Your Application -# Terminal tab 2: sync server -cd apps/server -pnpm dev -``` - -**Note:** Whenever you modify the Prisma schema, regenerate the client with: +In the TypeSync Studio: +1. Give your new application a name and a short description. +2. Use the visual editor to define your data models (we call them "types"). For example, you could create a `Post` type with a `title` (Text) and `content` (Text) properties. +3. When you're ready, click "Generate App". -```bash -cd apps/server -pnpm prisma migrate dev -``` +TypeSync will create a new directory for your application (e.g., `./my-awesome-app`) within the `hypergraph` monorepo, containing all the files and dependencies you need. -## 5. Run the Next.js example +## 4. Run Your New App -Ensure packages are built, then: +Once your app is generated, open a **new terminal tab**. Navigate into the newly created app directory, install its dependencies, and start the local development server. ```bash -cd apps/next-example +# In a new terminal, from the `hypergraph/apps/typesync` directory +cd ../../my-awesome-app # Adjust the path to match your app's name +pnpm install pnpm dev ``` -Visit `http://localhost:3000` to see the example app in action. +Your new Hypergraph-powered React application will now be running, typically at `http://localhost:5173`. -> 💡 **Optional:** If you'd rather skip the `pnpm build --watch` process while hacking on `packages/hypergraph-react`, add the package to `transpilePackages` in `apps/next-example/next.config.ts`: -> -> ```ts title="apps/next-example/next.config.ts" -> const nextConfig = { -> transpilePackages: ['@graphprotocol/hypergraph-react'], -> }; -> export default nextConfig; -> ``` - -## 6. Upgrade dependencies - -Keep everything up to date with: - -```bash -pnpm up --interactive --latest -r -``` +You're all set! You can now start building your application by editing the files in the `src` directory. The generated `src/schema.ts` file contains the Hypergraph schema you defined in TypeSync. ---