{"id":30029930,"url":"https://github.com/mattt/eventsource","last_synced_at":"2026-03-02T12:09:37.029Z","repository":{"id":290536911,"uuid":"973716108","full_name":"mattt/EventSource","owner":"mattt","description":"A lightweight, spec-compliant Server-Sent Events (SSE) client for Swift with AsyncSequence support.","archived":false,"fork":false,"pushed_at":"2025-10-31T10:23:55.000Z","size":71,"stargazers_count":87,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-02-18T13:06:24.519Z","etag":null,"topics":["server-sent-events","sse"],"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/mattt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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-04-27T15:34:31.000Z","updated_at":"2026-02-17T18:13:42.000Z","dependencies_parsed_at":"2026-01-14T06:00:16.166Z","dependency_job_id":null,"html_url":"https://github.com/mattt/EventSource","commit_stats":null,"previous_names":["loopwork-ai/eventsource","loopwork/eventsource","mattt/eventsource"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/mattt/EventSource","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattt%2FEventSource","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattt%2FEventSource/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattt%2FEventSource/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattt%2FEventSource/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mattt","download_url":"https://codeload.github.com/mattt/EventSource/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattt%2FEventSource/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29619073,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T13:04:20.082Z","status":"ssl_error","status_checked_at":"2026-02-19T13:03:33.775Z","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":["server-sent-events","sse"],"created_at":"2025-08-06T18:10:10.761Z","updated_at":"2026-02-19T15:00:50.308Z","avatar_url":"https://github.com/mattt.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EventSource\n\nA lightweight, spec-compliant Server-Sent Events (SSE) client for Swift.\n\n## Features\n\n- [x] Full implementation of the [Server-Sent Events specification][spec]\n- [x] Automatic connection management and reconnection with configurable retry intervals\n- [x] Event parsing that handles all standard fields (`id`, `event`, `data`, `retry`)\n- [x] Support for different line break formats (`LF`, `CR`, `CRLF`)\n- [x] Multi-line data aggregation\n- [x] `AsyncSequence` support for streaming events\n- [x] Works on all Apple platforms and Linux\n\n## Requirements\n\n- Swift 6.0+ / Xcode 16+\n\n## Installation\n\n### Swift Package Manager\n\nAdd the following to your `Package.swift` file:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/mattt/EventSource.git\", from: \"1.4.0\")\n]\n```\n\n### AsyncHTTPClient support\n\nEventSource can optionally integrate with\n[AsyncHTTPClient](https://github.com/swift-server/async-http-client)\nthrough a package trait (Swift 6.1+):\n\n```swift\ndependencies: [\n    .package(\n        url: \"https://github.com/mattt/EventSource.git\",\n        from: \"1.4.0\",\n        traits: [\"AsyncHTTPClient\"]\n    )\n]\n```\n\nBuild and test with the trait enabled:\n\n```bash\nswift build --traits AsyncHTTPClient\nswift test --traits AsyncHTTPClient\n```\n\n\u003e [!NOTE]\n\u003e `AsyncHTTPClient` uses SwiftNIO instead of Foundation URL Loading System.\n\u003e If traffic is routed through `AsyncHTTPClient`, `URLProtocol`-based interception\n\u003e does not apply.\n\u003e On Linux, EventSource starts with URLSession transport and switches to\n\u003e AsyncHTTPClient only after a retryable URLSession failure. Once switched,\n\u003e that EventSource instance continues using AsyncHTTPClient for reconnect attempts.\n\n## Usage\n\n### Connecting to an EventSource\n\nCreate an `EventSource` with a URL to establish\na persistent connection to an SSE endpoint.\nThe API mirrors the JavaScript [EventSource interface][mdn]\nwith event handlers for connection lifecycle management.\n\n```swift\nimport EventSource\nimport Foundation\n\n// Initialize with SSE endpoint URL\nlet sse = EventSource(url: URL(string: \"https://example.com/events\")!)\n\n// Create an EventSource with the URL\nlet sse = EventSource(url: url)\n\n// Set up event handlers\nsse.onOpen = {\n    print(\"Connection established\")\n}\n\nsse.onMessage = { e in\n    print(\"Received event: \\(e.event): \\(e.data)\")\n}\n\nsse.onError = { error in\n    if let error = error {\n        print(\"Error: \\(error)\")\n    } else {\n        print(\"Connection closed\")\n    }\n}\n\n// Later, when done\nTask {\n    await sse.close()\n}\n```\n\n### Processing an AsyncSequence of Server-Sent Events\n\nAlternatively, you can process server-sent event data with\nSwift's modern `AsyncSequence` API for greater flexibility and control.\nUse this approach when you need custom request configuration\nor direct integration with existing async / URL Loading System code.\n\n```swift\nimport EventSource\nimport Foundation\n\nTask {\n    // Create a request to the SSE endpoint\n    let url = URL(string: \"https://example.com/events\")!\n    let request = URLRequest(url: url)\n\n    do {\n        let (stream, _) = try await URLSession.shared.bytes(for: request)\n\n        // Iterate through events as they arrive\n        for try await event in stream.events {\n            switch event.event {\n            case \"update\":\n                handleUpdate(event.data)\n            case \"error\":\n                handleError(event.data)\n            default:\n                print(\"Received: \\(event.data)\")\n            }\n        }\n    } catch {\n        print(\"Stream error: \\(error.localizedDescription)\")\n    }\n}\n```\n\n### Parsing Server-Sent Events Directly\n\nUse the low-level parser directly to process raw SSE data.\nThis approach is ideal for custom networking stacks, testing,\nor scenarios where you need precise control over state management.\n\n```swift\nimport EventSource\nimport Foundation\n\n// Create a parser instance\nlet parser = EventSource.Parser()\n\n// Process raw SSE data byte-by-byte\nlet rawData = \"\"\"\n    id: 123\n    event: update\n    data: {\"key\": \"value\"}\n\n    data: Another message\n\n    \"\"\".utf8\n\n// Parse the data\nTask {\n    // Feed bytes to the parser\n    for byte in rawData { await parser.consume(byte) }\n    await parser.finish()\n\n    // Extract all parsed events\n    while let event = await parser.getNextEvent() {\n        handleEvent(event)\n    }\n\n    // Access state for reconnection logic\n    print(\"Last Event ID: \\(await parser.getLastEventId())\")\n    print(\"Reconnection time: \\(await parser.getReconnectionTime())ms\")\n}\n```\n\n## Examples\n\n### Working with Streaming APIs\n\nInference providers like Anthropic and OpenAI offer APIs\nwith endpoints that stream tokens as they're generated.\nHere's a simplified example of how you might consume server-sent events\nfor such an API:\n\n```swift\nimport EventSource\nimport Foundation\n\n// Simple model for LLM token streaming\nstruct TokenChunk: Codable {\n    let text: String\n    let isComplete: Bool\n}\n\n// Create a request to the LLM streaming endpoint\nlet url = URL(string: \"https://api.example.com/completions\")!\nvar request = URLRequest(url: url)\nrequest.httpMethod = \"POST\"\nrequest.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\nrequest.setValue(\"Bearer YOUR_API_KEY\", forHTTPHeaderField: \"Authorization\")\n\n// Track the full response\nvar completedText = \"\"\n\n// Process the stream asynchronously\nTask {\n    do {\n        // Get a byte stream from URLSession\n        let (byteStream, response) = try await URLSession.shared.bytes(for: request)\n\n        // Ensure response is valid\n        guard let httpResponse = response as? HTTPURLResponse,\n            httpResponse.statusCode == 200,\n            let contentType = httpResponse.value(forHTTPHeaderField: \"Content-Type\"),\n            contentType.contains(\"text/event-stream\")\n        else {\n            throw NSError(domain: NSURLErrorDomain,\n                        code: NSURLErrorBadServerResponse,\n                        userInfo: nil)\n        }\n\n        let decoder = JSONDecoder()\n\n        // Stream events asynchronously\n        for try await event in byteStream.events {\n            // Decode each chunk as it arrives\n            let chunk = try decoder.decode(TokenChunk.self,\n                                           from: Data(event.data.utf8))\n\n            // Add the new token to our result\n            completedText += chunk.text\n            print(\"Text so far: \\(completedText)\")\n\n            // Check if the response is complete\n            if chunk.isComplete {\n                print(\"Final response: \\(completedText)\")\n                break\n            }\n        }\n    } catch {\n        print(\"Stream error: \\(error.localizedDescription)\")\n    }\n}\n```\n\n## License\n\nThis project is available under the MIT license.\nSee the LICENSE file for more info.\n\n[mdn]: https://developer.mozilla.org/en-US/docs/Web/API/EventSource\n[spec]: https://html.spec.whatwg.org/multipage/server-sent-events.html#the-eventsource-interface\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattt%2Feventsource","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmattt%2Feventsource","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattt%2Feventsource/lists"}