{"id":27401269,"url":"https://github.com/edjcase/motoko_atproto","last_synced_at":"2026-01-23T16:36:44.380Z","repository":{"id":272384740,"uuid":"912910640","full_name":"edjCase/motoko_atproto","owner":"edjCase","description":"Motoko implementation of atproto components","archived":false,"fork":false,"pushed_at":"2026-01-01T19:06:11.000Z","size":710,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-07T02:34:19.156Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Motoko","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edjCase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-06T16:37:48.000Z","updated_at":"2026-01-05T19:38:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"cd2d0f95-0a69-4958-be33-1e43776f48ac","html_url":"https://github.com/edjCase/motoko_atproto","commit_stats":null,"previous_names":["edjcase/motoko_atproto"],"tags_count":0,"template":false,"template_full_name":"edjCase/motoko-library-template","purl":"pkg:github/edjCase/motoko_atproto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edjCase%2Fmotoko_atproto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edjCase%2Fmotoko_atproto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edjCase%2Fmotoko_atproto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edjCase%2Fmotoko_atproto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edjCase","download_url":"https://codeload.github.com/edjCase/motoko_atproto/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edjCase%2Fmotoko_atproto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28695597,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T15:57:05.722Z","status":"ssl_error","status_checked_at":"2026-01-23T15:56:27.656Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-14T03:54:35.980Z","updated_at":"2026-01-23T16:36:44.373Z","avatar_url":"https://github.com/edjCase.png","language":"Motoko","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Motoko AT Protocol Library\n\n[![MOPS](https://img.shields.io/badge/MOPS-atproto-blue)](https://mops.one/atproto)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/edjCase/motoko_atproto/blob/main/LICENSE)\n\nA comprehensive Motoko library for building AT Protocol (ATProto) applications on the Internet Computer. This library provides core data structures, repository management, cryptographic operations, and utilities for implementing Personal Data Servers (PDS) and other AT Protocol services.\n\n## Package\n\n### MOPS\n\n```bash\nmops add atproto\n```\n\nTo set up MOPS package manager, follow the instructions from the [MOPS Site](https://mops.one)\n\n## Overview\n\nThe AT Protocol (Authenticated Transfer Protocol) is the foundation for decentralized social networks like Bluesky. This library provides Motoko implementations of:\n\n- **Repository Management**: Full IPLD-based repository with commit history and Merkle Search Trees\n- **Identity \u0026 DIDs**: AT URI parsing and DID document handling\n- **Cryptographic Primitives**: CID generation, DAG-CBOR encoding, and commit signing\n- **Data Structures**: Blob references, strong references, and lexicon validators\n- **Merkle Search Trees**: Efficient key-value storage with cryptographic proofs\n\n## Quick Start\n\n### Example 1: Working with AT URIs\n\n```motoko\nimport AtUri \"mo:atproto/AtUri\";\nimport DID \"mo:did\";\n\n// Create an AT URI\nlet uri : AtUri.AtUri = {\n  authority = #plc(myPlcDid);\n  collection = ?{\n    id = \"app.bsky.feed.post\";\n    recordKey = ?\"3jzfcijpj2z2a\";\n  };\n};\n\n// Convert to text representation\nlet uriText = AtUri.toText(uri);\n// Result: \"at://did:plc:xxx/app.bsky.feed.post/3jzfcijpj2z2a\"\n\n// Parse from text\nswitch (AtUri.fromText(\"at://alice.bsky.social/app.bsky.feed.post/123\")) {\n  case (?parsedUri) {\n    Debug.print(\"Successfully parsed AT URI\");\n  };\n  case (null) {\n    Debug.print(\"Invalid AT URI format\");\n  };\n};\n```\n\n### Example 2: Creating a Repository\n\n```motoko\nimport Repository \"mo:atproto/Repository\";\nimport DID \"mo:did\";\nimport TID \"mo:tid\";\nimport Result \"mo:core/Result\";\n\n// Initialize an empty repository\nlet did = myPlcDid; // Your PLC DID\nlet rev = TID.now(); // Current timestamp\nlet signFunc = func(data : Blob) : async* Result.Result\u003cBlob, Text\u003e {\n  // Your signing implementation\n};\n\nlet repo = await* Repository.empty(did, rev, signFunc);\n\n// Create a new record\nlet createOp : Repository.WriteOperation = #create({\n  key = {\n    collection = \"app.bsky.feed.post\";\n    recordKey = \"3jzfcijpj2z2a\";\n  };\n  value = myPostRecord; // DAG-CBOR encoded value\n});\n\n// Apply the operation\nswitch (await* Repository.applyWrites(repo, [createOp], signFunc)) {\n  case (#ok({ repository = newRepo; results })) {\n    Debug.print(\"Record created successfully\");\n  };\n  case (#err(error)) {\n    Debug.print(\"Error: \" # error);\n  };\n};\n```\n\n### Example 3: Merkle Search Tree Operations\n\n```motoko\nimport MST \"mo:atproto/MerkleSearchTree\";\nimport CID \"mo:cid\";\n\n// Create an empty Merkle Search Tree\nlet mst = MST.empty();\n\n// Add entries\nlet recordCid = myCidValue;\nswitch (MST.add(mst, \"app.bsky.feed.post/123\", recordCid)) {\n  case (#ok(newMst)) {\n    Debug.print(\"Entry added to MST\");\n    \n    // Retrieve the entry\n    switch (MST.get(newMst, \"app.bsky.feed.post/123\")) {\n      case (?cid) {\n        Debug.print(\"Found CID: \" # CID.toText(cid));\n      };\n      case (null) {\n        Debug.print(\"Entry not found\");\n      };\n    };\n  };\n  case (#err(error)) {\n    Debug.print(\"Error: \" # error);\n  };\n};\n```\n\n### Example 4: Working with Commits\n\n```motoko\nimport Commit \"mo:atproto/Commit\";\nimport CIDBuilder \"mo:atproto/CIDBuilder\";\nimport TID \"mo:tid\";\n\n// Create an unsigned commit\nlet unsignedCommit : Commit.UnsignedCommit = {\n  did = myPlcDid;\n  version = 3;\n  data = mstRootCid; // CID of MST root\n  rev = TID.now();\n  prev = ?previousCommitCid;\n};\n\n// Generate CID for the unsigned commit\nlet commitCid = CIDBuilder.fromUnsignedCommit(unsignedCommit);\n\n// Sign the commit\nlet signature = await signData(commitBlob);\nlet signedCommit : Commit.Commit = {\n  did = unsignedCommit.did;\n  version = unsignedCommit.version;\n  data = unsignedCommit.data;\n  rev = unsignedCommit.rev;\n  prev = unsignedCommit.prev;\n  sig = signature;\n};\n```\n\n### Example 5: Blob References\n\n```motoko\nimport BlobRef \"mo:atproto/Lexicons/BlobRef\";\nimport CID \"mo:cid\";\nimport Json \"mo:json\";\n\n// Create a blob reference\nlet blobRef : BlobRef.BlobRef = {\n  ref = blobCid;\n  mimeType = \"image/jpeg\";\n  size = 245678;\n};\n\n// Convert to JSON for AT Protocol messages\nlet blobJson = BlobRef.toJson(blobRef);\n// Result: {\"$type\": \"blob\", \"ref\": {\"$link\": \"...\"}, \"mimeType\": \"image/jpeg\", \"size\": 245678}\n```\n\n## Core Components\n\n### Repository\n\nThe `Repository` module provides a complete implementation of an AT Protocol repository with:\n\n- **Write Operations**: Create, update, and delete records\n- **Commit History**: Full history of all repository changes\n- **Record Storage**: Efficient storage and retrieval of DAG-CBOR encoded records\n- **Export/Import**: CAR file generation for repository synchronization\n- **Validation**: Ensures repository integrity and proper commit chains\n\n### Merkle Search Tree\n\nA specialized data structure for efficient, cryptographically verifiable key-value storage:\n\n- **Ordered Storage**: Keys are stored in lexicographic order\n- **Cryptographic Proofs**: Each node has a CID for verification\n- **Efficient Updates**: Minimal tree modifications on changes\n- **Range Queries**: Support for prefix-based searches\n- **Historical Nodes**: Optional retention of previous tree states\n\n### AT URIs\n\nParse and construct AT Protocol URIs with support for:\n\n- **Handle Authorities**: `at://alice.bsky.social/...`\n- **DID Authorities**: `at://did:plc:xyz.../...`\n- **Collection Paths**: References to specific collections\n- **Record Keys**: Direct links to individual records\n\n### DID Documents\n\nWork with Decentralized Identifier documents:\n\n- **Verification Methods**: Public key management\n- **Service Endpoints**: PDS and other service discovery\n- **JSON Serialization**: Standard DID document format\n- **Key References**: Support for key rotation\n\n## Use Cases\n\n• **Personal Data Servers**: Build PDS implementations for the AT Protocol\n• **Social Media Clients**: Create Bluesky and AT Protocol clients\n• **Repository Management**: Implement repository operations for any AT Protocol service\n• **Identity Services**: Handle DID resolution and verification\n• **Data Synchronization**: Export and import repositories using CAR files\n• **Federated Services**: Build relays, app views, and other AT Protocol infrastructure\n• **DAO Social Presence**: Enable organizations to manage collective social media identities\n\n## API Reference\n\n### Core Types\n\n```motoko\n// AT URI structure\npublic type AtUri = {\n  authority : { #handle : Text; #plc : DID.Plc.DID };\n  collection : ?{\n    id : Text;\n    recordKey : ?Text;\n  };\n};\n\n// Repository metadata\npublic type MetaData = {\n  head : CID.CID;\n  rev : TID.TID;\n  active : Bool;\n  status : ?Text;\n};\n\n// Write operations\npublic type WriteOperation = {\n  #create : { key : Key; value : DagCbor.Value };\n  #update : { key : Key; value : DagCbor.Value };\n  #delete : { key : Key };\n};\n\n// Commit structure\npublic type Commit = {\n  did : DID.Plc.DID;\n  version : Nat;\n  data : CID.CID;\n  rev : TID.TID;\n  prev : ?CID.CID;\n  sig : Blob;\n};\n```\n\n### Repository Functions\n\n```motoko\n// Create an empty repository\npublic func empty(\n  did : DID.Plc.DID,\n  rev : TID.TID,\n  signFunc : (Blob) -\u003e async* Result.Result\u003cBlob, Text\u003e\n) : async* Result.Result\u003cRepository, Text\u003e;\n\n// Apply write operations\npublic func applyWrites(\n  repo : Repository,\n  writes : [WriteOperation],\n  signFunc : (Blob) -\u003e async* Result.Result\u003cBlob, Text\u003e\n) : async* Result.Result\u003c{\n  repository : Repository;\n  results : [WriteResult];\n}, Text\u003e;\n\n// Get a record by key\npublic func getRecord(\n  repo : Repository,\n  key : Key\n) : ?RecordData;\n\n// List all records in a collection\npublic func listRecords(\n  repo : Repository,\n  collection : Text\n) : [(Text, RecordData)];\n\n// Export repository as CAR file\npublic func exportCar(\n  repo : Repository,\n  since : ?TID.TID\n) : Result.Result\u003cBlob, Text\u003e;\n```\n\n### Merkle Search Tree Functions\n\n```motoko\n// Create an empty MST\npublic func empty() : MerkleSearchTree;\n\n// Add an entry (fails if key exists)\npublic func add(\n  mst : MerkleSearchTree,\n  key : Text,\n  value : CID.CID\n) : Result.Result\u003cMerkleSearchTree, Text\u003e;\n\n// Put an entry (creates or updates)\npublic func put(\n  mst : MerkleSearchTree,\n  key : Text,\n  value : CID.CID\n) : Result.Result\u003cMerkleSearchTree, Text\u003e;\n\n// Remove an entry\npublic func remove(\n  mst : MerkleSearchTree,\n  key : Text\n) : Result.Result\u003c(MerkleSearchTree, CID.CID), Text\u003e;\n\n// Get an entry\npublic func get(\n  mst : MerkleSearchTree,\n  key : Text\n) : ?CID.CID;\n\n// Validate MST structure\npublic func validate(\n  mst : MerkleSearchTree\n) : Result.Result\u003c(), Text\u003e;\n```\n\n### AT URI Functions\n\n```motoko\n// Convert AT URI to text\npublic func toText(uri : AtUri) : Text;\n\n// Parse AT URI from text\npublic func fromText(path : Text) : ?AtUri;\n```\n\n### CID Builder Functions\n\n```motoko\n// Create CID from blob\npublic func fromBlob(blob : Blob) : CID.CID;\n\n// Create CID from commit\npublic func fromCommit(commit : Commit) : CID.CID;\n\n// Create CID from MST node\npublic func fromMSTNode(node : MerkleNode.Node) : CID.CID;\n\n// Create CID from DAG-CBOR value\npublic func fromDagCbor(cbor : DagCbor.Value) : CID.CID;\n```\n\n## Project Structure\n\n```\nsrc/\n├── AtUri.mo                    # AT Protocol URI parsing and construction\n├── Repository.mo               # Repository management and operations\n├── MerkleSearchTree.mo         # Merkle Search Tree implementation\n├── MerkleNode.mo              # MST node structure\n├── Commit.mo                   # Commit structures\n├── CIDBuilder.mo              # CID generation utilities\n├── DagCborBuilder.mo          # DAG-CBOR encoding helpers\n├── JsonDagCborMapper.mo       # JSON to DAG-CBOR conversion\n├── DIDDocument.mo             # DID document handling\n└── Lexicons/\n    ├── BlobRef.mo             # Blob reference types\n    ├── StrongRef.mo           # Strong reference types\n    ├── LexiconValidator.mo    # Schema validation\n    └── App/Bsky/...           # Bluesky lexicon types\n    └── Com/Atproto/...        # AT Protocol lexicon types\n```\n\n## Testing\n\n```bash\nmops test\n```\n\n## Real-World Usage\n\nThis library is used by:\n\n- **[motoko_atproto_pds](https://github.com/edjCase/motoko_atproto_pds)**: A complete PDS implementation for the Internet Computer, enabling DAOs and organizations to manage AT Protocol identities and post to Bluesky\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues and pull requests.\n\n## Dependencies\n\nThis library builds upon several excellent Motoko packages:\n\n- **[cid](https://mops.one/cid)**: Content Identifier implementation\n- **[dag-cbor](https://mops.one/dag-cbor)**: DAG-CBOR encoding/decoding\n- **[did](https://mops.one/did)**: Decentralized Identifier utilities\n- **[tid](https://mops.one/tid)**: Timestamp Identifier generation\n- **[sha2](https://mops.one/sha2)**: SHA-256 hashing\n- **[json](https://mops.one/json)**: JSON encoding/decoding\n- **[core](https://mops.one/core)**: Core Motoko utilities\n\n## Resources\n\n- [AT Protocol Documentation](https://atproto.com/)\n- [Bluesky Social](https://bsky.app/)\n- [Internet Computer Documentation](https://internetcomputer.org/docs)\n- [Motoko Documentation](https://internetcomputer.org/docs/current/motoko/main/motoko)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedjcase%2Fmotoko_atproto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedjcase%2Fmotoko_atproto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedjcase%2Fmotoko_atproto/lists"}