{"id":16687832,"url":"https://github.com/picohz/metropolis","last_synced_at":"2026-05-16T01:35:15.510Z","repository":{"id":91021396,"uuid":"442792824","full_name":"picoHz/Metropolis","owner":"picoHz","description":"🏙️ Async/await-based Matrix client library in Swift","archived":false,"fork":false,"pushed_at":"2022-01-15T01:57:43.000Z","size":92,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-08T19:26:33.285Z","etag":null,"topics":["async-await","ios","macos","matrix","matrix-org","rest-api","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/picoHz.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}},"created_at":"2021-12-29T14:10:39.000Z","updated_at":"2023-12-11T05:27:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"049f8993-0866-43e3-bef3-db1e7b77e8fb","html_url":"https://github.com/picoHz/Metropolis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/picoHz/Metropolis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/picoHz%2FMetropolis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/picoHz%2FMetropolis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/picoHz%2FMetropolis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/picoHz%2FMetropolis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/picoHz","download_url":"https://codeload.github.com/picoHz/Metropolis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/picoHz%2FMetropolis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33087028,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T20:25:35.270Z","status":"ssl_error","status_checked_at":"2026-05-15T20:25:34.732Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["async-await","ios","macos","matrix","matrix-org","rest-api","swift"],"created_at":"2024-10-12T15:25:16.731Z","updated_at":"2026-05-16T01:35:15.494Z","avatar_url":"https://github.com/picoHz.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003ch1\u003eMetropolis\u003c/h1\u003e\n        \n\u003ca href=\"https://unsplash.com/photos/ZETyWNCn5bw\"\u003e\n\u003cimg alt=\"metropolis\" src=\"metropolis.png\" height=\"100\" /\u003e\n\u003c/a\u003e\n\nAsync/await-based Matrix client library in Swift\n\n\u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-56f.svg\" alt=\"MIT License\"\u003e\u003c/a\u003e\n\u003ca href=\"https://swift.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/Swift-5.5-F05138?logo=swift\u0026logoColor=white\" alt=\"Swift 5.5\"\u003e\u003c/a\u003e\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\u003ch4\u003e🚧 This package is not production-ready 🚧\u003c/h4\u003e  \n\u003c/div\u003e\n\n- [About](#about)\n- [Supported Features](#supported-features)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Anonymous Access](#anonymous-access)\n  - [Authorization](#authorization)\n  - [User-Interactive Authentication](#user-interactive-authentication)\n  - [Custom Authorization Method](#custom-authorization-method)\n  - [Pagination](#pagination)\n  - [Media Downloading and Uploading](#media-downloading-and-uploading)\n  - [Handling Schema-free JSON Objects](handling-schema-free-json-objects)\n- [Testing](#testing)\n- [License](#license)\n\n## About\n\nMetropolis is an asynchronous client library for [Matrix Messaging Protocol](https://matrix.org/)\nwritten in pure Swift.\nIt provides a low-level wrapper for client-server API integrated with the Swift type system.\n\n### What is Matrix?\n\n\u003e Matrix is an open standard for interoperable, decentralised, real-time communication over IP. It can be used to power Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication - or anywhere you need a standard HTTP API for publishing and subscribing to data whilst tracking the conversation history.\n\n\u003cdiv align=\"right\"\u003ehttps://matrix.org/faq\u003c/div\u003e\n\n## Supported Features\n\n- [x] Account Management\n- [x] Session Management\n- [x] Device Management\n- [x] Room Directory\n- [x] Room Participation\n- [x] Presence\n- [x] Media\n- [x] User Data\n- [x] User Directory\n- [x] Full Text Search\n- [ ] Push Notifications\n- [ ] End-To-End Encryption\n\n## Installation\n\n### Swift Package Manager\n\nMetropolis supports installation via Swift Package Manager.\nTo add the package as your project's dependency, put the repository url into the dependencies section in `Package.swift` like this:\n\n```swift\n// swift-tools-version:5.5\nimport PackageDescription\n\nlet package = Package(\n    name: \"PackageName\",\n    dependencies: [\n        .package(url: \"https://github.com/picoHz/Metropolis.git\", .branch(\"main\"))\n    ]\n)\n```\nYou can also add dependencies from Xcode.\nhttps://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app\n\n## Usage\n\nNote that this library is basically just a thin wrapper of Matrix client-server API and does not provide high-level functionalities, so you need to read the [Matrix Specification](https://spec.matrix.org/v1.1/client-server-api) to understand how these endpoints work.\n\n### Anonymous Access\n\nPublic endpoints are accessible without login.\n\n```swift\nlet client = try MPClient(url: URL(string: \"https://matrix.org\")!)\ntry await client.checkUsernameAvailability(username: \"metro\")\n```\n\n### Authorization\n\n```swift \nlet client = try MPClient(url: URL(string: \"https://matrix.org\")!)\n\nlet method = MPPasswordAuth(\n    identifier: .user(user: \"metro\"),\n    password: \"pass\")\n\nlet authClient = try await client.login(method: method)\n```\n\n#### Custom Authorization Method\n\n`client.login()` method accepts any objects that conform to `MPAuthMethod` protocol.\n\n```swift\npublic protocol MPAuthMethod: Encodable {\n    var type: String { get }\n}\n```\n\n```swift\npublic struct CustomAuth: MPAuthMethod {\n    let type: String = \"com.example.custom\"\n    var customName: String\n    var customList: [String]\n}\n\nlet authClient = try await client.login(method: CustomAuth(customName: \"aaa\", customList: [\"bbb\"]))\n\n```\n\nThe property names will be converted to snakecase.\nFor example, `CustomAuth` will be encoded into the following JSON.\n\n```json\n{\n    \"type\": \"com.example.custom\",\n    \"custom_name\": \"aaa\",\n    \"custom_list\": [\"bbb\"]\n}\n```\n\n### User-Interactive Authentication\n\n```swift\nvar interactiveAuth = try await authClient.changePassword(newPassword: \"new_password\")\n\nguard case .failure(var state) = try await interactiveAuth.authenticate(method: method) {\n    return\n}\n\nwhile true {\n    if !state.flows[0].stages.contains(\"m.login.password\") {\n        // Password authentication is not supported.\n        break\n    }\n\n    // Ask user to authenticate.\n    let method = MPPasswordAuth(\n        identifier: .user(user: \"metro\"),\n        password: \"old_password\")\n\n    switch try await interactiveAuth.authenticate(method: method, state: state) {\n    case .success(_):\n        break\n    case .failure(let newState):\n        // Authentication failed or needs additional authentication.\n        state = newState\n        continue\n    }\n}\n```\n\n### Pagination\n\nPaginated endpoints return a stream object that implements [`AsyncSequence`](https://developer.apple.com/documentation/swift/asyncsequence).\n\n```swift\nlet stream = try await client.getPublicRooms(limit: 100)\n\nfor try await chunk in stream {\n    // Fetch results.\n}\n\n// Iterate manually.\nvar iter = stream.makeAsyncIterator()\nlet chunk = try await iter.next()\n\n// Get an estimated room count from the iterator.\niter.totalRoomCountEstimate\n\n// Resume the iteration using a pagination token.\nlet newStream = try await client.getPublicRooms(limit: 100, since: iter.nextBatch)\n```\n\n#### Backward Pagination\n\nPublic Room Directory supports bidirectional pagination.\nYou can make a backward iterator using `prevBatch` token.\n\n```swift\nlet stream = try await client.getPublicRooms(limit: 100)\n\nvar iter = stream.makeAsyncIterator()\nwhile try await iter.next() != nil {}\n\nlet backwardStream = try await client.getPublicRooms(limit: 100, since: iter.prevBatch)\nfor try await chunk in backwardStream {\n    // Fetch backward results.\n}\n```\n\n### Media Downloading and Uploading\n\nMetropolis does not directly provide methods to download/upload media.\nInstead, it provides the following methods returning URLs for downloading or uploading so you can use your favorite HTTP client library to handle them.\n\n```swift\npublic protocol MPMediaAPI {\n    func getMediaDownloadUrl(serverName: String, mediaId: String) -\u003e URL\n    func getMediaThumbnailUrl(serverName: String, mediaId: String) -\u003e URL\n    func getMediaUploadUrl() -\u003e URL\n}\n```\n\n### Handling Schema-free JSON Objects\n\nSome endpoints use unstructured (a.k.a schema-free) JSON objects.\nMetropolis handles them with [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON).\n\n```swift\nlet profile: JSON = try await client.getProfile(userId: \"@metro@example.com\")\n\n// Access as a JSON object\nif let displayName = profile.dictionaryValue[\"displayname\"].string {\n    print(displayName)\n}\n\n// Decode as a struct\nstruct Profile: Decodable { var displayname: String }\nlet data = try JSONDecoder().decode(Profile.self, from: profile.rawData())\nprint(data.displayname)\n```\n\n## Testing\n\nTo run tests, you need running a matrix instance on `localhost:8080`.\n\nThe following commands run up-to-date demo server instances.\nPlease check [Synapse Documantation](https://github.com/matrix-org/synapse#quick-start)\nfor more information about Matrix servers.\n\n```bash\ngit clone https://github.com/matrix-org/synapse.git\ncd synapse\n\npython3 -m venv ./env\nsource ./env/bin/activate\npip install -e \".[all,dev]\"\n\n./demo/start.sh\n```\n\nIf there is already a running matrix instance on `localhost:8080`,\nyou can simply run `swift test`.\n\n## License\n\nMetropolis is released under the MIT license.\n\nHeadline Photo by [Leonhard Niederwimmer](https://unsplash.com/@lnlnln) on [Unsplash](https://unsplash.com/photos/ZETyWNCn5bw)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpicohz%2Fmetropolis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpicohz%2Fmetropolis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpicohz%2Fmetropolis/lists"}