{"id":49659396,"url":"https://github.com/sockudo/sockudo-http-swift","last_synced_at":"2026-05-06T11:05:05.488Z","repository":{"id":348024120,"uuid":"1195300639","full_name":"sockudo/sockudo-http-swift","owner":"sockudo","description":"Sockudo Swift HTTP server SDK","archived":false,"fork":false,"pushed_at":"2026-04-20T18:25:30.000Z","size":1849,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T20:30:21.948Z","etag":null,"topics":["http","realtime","sdk","sockudo","swift"],"latest_commit_sha":null,"homepage":null,"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/sockudo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2026-03-29T13:57:58.000Z","updated_at":"2026-04-20T18:25:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sockudo/sockudo-http-swift","commit_stats":null,"previous_names":["sockudo/sockudo-http-swift"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/sockudo/sockudo-http-swift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockudo%2Fsockudo-http-swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockudo%2Fsockudo-http-swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockudo%2Fsockudo-http-swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockudo%2Fsockudo-http-swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sockudo","download_url":"https://codeload.github.com/sockudo/sockudo-http-swift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockudo%2Fsockudo-http-swift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32690549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":["http","realtime","sdk","sockudo","swift"],"created_at":"2026-05-06T11:04:49.383Z","updated_at":"2026-05-06T11:05:05.481Z","avatar_url":"https://github.com/sockudo.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sockudo Swift HTTP Server SDK\n\nA Swift server SDK for interacting with the [Sockudo](https://github.com/sockudo/sockudo) WebSocket server HTTP API. Publish events, authorize channels, authenticate users, and handle webhooks from your Swift applications.\n\n- [Supported platforms](#supported-platforms)\n- [Installation](#installation)\n- [Usage](#usage)\n- [License](#license)\n\n## Supported platforms\n\n- Swift 5.9 and above\n\n### Deployment targets\n\n- iOS 13.0 and above\n- macOS 10.15 and above\n- tvOS 13.0 and above\n- watchOS 6.0 and above\n\n## Installation\n\nTo integrate the library using [Swift Package Manager](https://swift.org/package-manager/), add it as a dependency in Xcode via **File \u003e Add Package Dependencies**. The package repository URL is:\n\n```\nhttps://github.com/sockudo/sockudo-http-swift.git\n```\n\nAlternatively, add it as a dependency in your `Package.swift` file:\n\n```swift\n// swift-tools-version:5.9\nimport PackageDescription\n\nlet package = Package(\n    name: \"YourPackage\",\n    products: [\n        .library(\n            name: \"YourPackage\",\n            targets: [\"YourPackage\"]),\n    ],\n    dependencies: [\n        .package(url: \"https://github.com/sockudo/sockudo-http-swift.git\",\n                 .upToNextMajor(from: \"1.0.0\")),\n    ],\n    targets: [\n        .target(\n            name: \"YourPackage\",\n            dependencies: [\n                .product(name: \"Sockudo\", package: \"sockudo-http-swift\")\n            ]),\n    ]\n)\n```\n\nThen include `import Sockudo` in any source file where you want to use the native Sockudo module.\n\nThis package exports both products:\n\n- `Sockudo`: native Sockudo module and recommended default for new integrations\n- `Pusher`: compatibility module for existing Pusher-shaped integrations\n\nExamples in this README use the native `Sockudo` module. If you are migrating an existing Pusher integration, you can depend on `.product(name: \"Pusher\", package: \"sockudo-http-swift\")` and keep `import Pusher`.\n\n## Usage\n\n**Note:** Certain initializers or methods throw an error if invalid parameters are provided or an operation fails. The use of `try!` in the examples below is for brevity and is not recommended for production code.\n\n### Configuration\n\nCreate a `Sockudo` instance using your app credentials and point it at your self-hosted server:\n\n```swift\nimport Sockudo\n\nlet sockudo = Sockudo(options: try! SockudoClientOptions(\n    appId: 123456,\n    key: \"YOUR_APP_KEY\",\n    secret: \"YOUR_APP_SECRET\",\n    host: \"127.0.0.1\",\n    port: 6001\n))\n```\n\nFor end-to-end encrypted channels, pass an `encryptionMasterKey`:\n\n```swift\nlet sockudo = Sockudo(options: try! SockudoClientOptions(\n    appId: 123456,\n    key: \"YOUR_APP_KEY\",\n    secret: \"YOUR_APP_SECRET\",\n    host: \"127.0.0.1\",\n    port: 6001,\n    encryptionMasterKey: \"YOUR_BASE64_ENCODED_MASTER_KEY\"\n))\n```\n\n### Triggering events\n\nUse the `trigger(event:callback:)` method to trigger an event on one or more channels.\n\n#### A single channel\n\n```swift\nlet publicChannel = Channel(name: \"my-channel\", type: .public)\nlet publicEvent = try! Event(name: \"my-event\",\n                             data: \"hello world!\",\n                             channel: publicChannel)\n\nsockudo.trigger(event: publicEvent) { result in\n    switch result {\n        case .success(let channelSummaries):\n            // Inspect `channelSummaries`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Multiple channels\n\n```swift\nlet channelOne = Channel(name: \"my-channel\", type: .public)\nlet channelTwo = Channel(name: \"my-other-channel\", type: .public)\nlet multichannelEvent = try! Event(name: \"my-multichannel-event\",\n                                   data: \"hello world!\",\n                                   channels: [channelOne, channelTwo])\n\nsockudo.trigger(event: multichannelEvent) { result in\n    switch result {\n        case .success(let channelSummaries):\n            // Inspect `channelSummaries`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Event batches\n\nSend multiple events in a single API call (max 10 per call) using `trigger(events:callback:)`:\n\n```swift\nlet eventOne = try! Event(name: \"my-event\",\n                          data: \"hello world!\",\n                          channel: Channel(name: \"my-channel\", type: .public))\nlet eventTwo = try! Event(name: \"my-other-event\",\n                          data: \"hello world, again!\",\n                          channel: Channel(name: \"my-other-channel\", type: .public))\n\nsockudo.trigger(events: [eventOne, eventTwo]) { result in\n    switch result {\n        case .success(let channelInfoList):\n            // Inspect `channelInfoList`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Excluding recipients\n\nPrevent the triggering client from receiving its own event by specifying its `socketId`:\n\n```swift\nlet excludedClientEvent = try! Event(name: \"my-event\",\n                                     data: \"hello world!\",\n                                     channel: Channel(name: \"my-channel\", type: .public),\n                                     socketId: \"123.456\")\n\nsockudo.trigger(event: excludedClientEvent) { result in\n    switch result {\n        case .success(let channelSummaries):\n            // Inspect `channelSummaries`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Idempotency key\n\nAttach an idempotency key so the server deduplicates the event on retries:\n\n```swift\nlet event = try! Event(name: \"my-event\",\n                       data: \"hello world!\",\n                       channel: Channel(name: \"my-channel\", type: .public),\n                       idempotencyKey: \"unique-key-for-this-event\")\n\nsockudo.trigger(event: event) { result in\n    switch result {\n        case .success(let channelSummaries):\n            // Inspect `channelSummaries`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n**Note:** The `trigger(…)` method is asynchronous. In non-GUI contexts, use a semaphore if you need to wait for the result:\n\n```swift\nlet sema = DispatchSemaphore(value: 0)\nsockudo.trigger(event: publicEvent) { result in\n    // Handle result\n    sema.signal()\n}\nsema.wait()\n```\n\n### Authenticating channel subscriptions\n\nUsers attempting to subscribe to a private or presence channel must first be authenticated. Generate an authentication token to return to the subscribing client.\n\n#### Private channels\n\n```swift\nlet userSocketId = \"123.456\"\nlet privateChannel = Channel(name: \"my-channel\", type: .private)\n\nsockudo.authenticate(channel: privateChannel,\n                     socketId: userSocketId) { result in\n    switch result {\n        case .success(let authToken):\n            // Return `authToken` to the client\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Presence channels\n\nFor presence channels, include user identity data:\n\n```swift\nlet userData = PresenceUserAuthData(userId: \"USER_ID\", userInfo: [\"name\": \"Jane Smith\"])\nlet presenceChannel = Channel(name: \"my-channel\", type: .presence)\n\nsockudo.authenticate(channel: presenceChannel,\n                     socketId: \"USER_SOCKET_ID\",\n                     userData: userData) { result in\n    switch result {\n        case .success(let authToken):\n            // Return `authToken` to the client\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n### User authentication\n\nAuthenticate a user for server-to-user event delivery:\n\n```swift\nlet userAuthData = UserAuthData(userId: \"USER_ID\", userInfo: [\"name\": \"Jane Smith\"])\n\nsockudo.authenticateUser(socketId: \"USER_SOCKET_ID\",\n                         userData: userAuthData) { result in\n    switch result {\n        case .success(let authToken):\n            // Return `authToken` to the client\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n### Verifying webhooks\n\nVerify that a received webhook request originated from your Sockudo server. Valid webhooks contain special headers with your application key and an HMAC signature of the payload:\n\n```swift\nsockudo.verifyWebhook(request: receivedWebhookRequest) { result in\n    switch result {\n        case .success(let webhook):\n            // Inspect `webhook`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n### End-to-end encryption\n\nThis library supports end-to-end encryption of private channels. Only you and your connected clients can read the messages.\n\n1. Set up private channel authentication on your server.\n\n2. Generate a 32-byte master encryption key encoded as Base64. **Never share this key.**\n\n   ```bash\n   openssl rand -base64 32\n   ```\n\n3. Pass the key to `SockudoClientOptions`:\n\n   ```swift\n   let options = try! SockudoClientOptions(\n       appId: 123456,\n       key: \"YOUR_APP_KEY\",\n       secret: \"YOUR_APP_SECRET\",\n       host: \"127.0.0.1\",\n       port: 6001,\n       encryptionMasterKey: \"\u003cMASTER KEY FROM PREVIOUS COMMAND\u003e\"\n   )\n   ```\n\n4. Use channels of type `encrypted`. Encrypted channel names must be prefixed with `private-encrypted-`.\n\n5. Subscribe to these channels in your client. Only clients with the matching key can decrypt messages.\n\n**Note:** You cannot trigger a single event on a mix of encrypted and unencrypted channels in one call. Each requires a separate API request.\n\n### Application state queries\n\n#### Fetch all occupied channels\n\n```swift\n// All occupied channels\nsockudo.channels { result in\n    switch result {\n        case .success(let channelSummaries):\n            // Inspect `channelSummaries`\n        case .failure(let error):\n            // Handle error\n    }\n}\n\n// Only occupied presence channels (with user counts)\nsockudo.channels(withFilter: .presence,\n                 attributeOptions: .userCount) { result in\n    switch result {\n        case .success(let channelSummaries):\n            // Inspect `channelSummaries`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Fetch information about a channel\n\n```swift\nlet presenceChannel = Channel(name: \"my-channel\", type: .presence)\nsockudo.channelInfo(for: presenceChannel,\n                    attributeOptions: [.userCount]) { result in\n    switch result {\n        case .success(let channelInfo):\n            // Inspect `channelInfo`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n**Note:** If the channel is not occupied, the returned `ChannelInfo` will have `isOccupied` set to `false` and no attributes will be populated.\n\n#### Fetch users subscribed to a presence channel\n\n```swift\nlet presenceChannel = Channel(name: \"my-channel\", type: .presence)\nsockudo.users(for: presenceChannel) { result in\n    switch result {\n        case .success(let users):\n            // Inspect `users`\n        case .failure(let error):\n            // Handle error\n    }\n}\n```\n\n#### Fetch channel history\n\n```swift\nlet channel = Channel(name: \"my-channel\", type: .public)\nsockudo.history(\n    for: channel,\n    options: .init(limit: 50, direction: \"newest_first\")\n) { result in\n    print(result)\n}\n\nsockudo.history(\n    for: channel,\n    options: .init(cursor: \"opaque-cursor-from-previous-page\")\n) { result in\n    print(result)\n}\n```\n\n#### Fetch presence history and snapshots\n\n```swift\nlet presenceChannel = Channel(name: \"my-channel\", type: .presence)\nsockudo.presenceHistory(\n    for: presenceChannel,\n    options: .init(limit: 50, direction: \"newest_first\")\n) { result in\n    print(result)\n}\n\nsockudo.presenceHistory(\n    for: presenceChannel,\n    options: .init(cursor: \"opaque-cursor-from-previous-page\")\n) { result in\n    print(result)\n}\n\nsockudo.presenceSnapshot(\n    for: presenceChannel,\n    options: .init(atSerial: 4)\n) { result in\n    print(result)\n}\n```\n\n## License\n\nThe library is completely open source and released under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsockudo%2Fsockudo-http-swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsockudo%2Fsockudo-http-swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsockudo%2Fsockudo-http-swift/lists"}