{"id":22733913,"url":"https://github.com/permutive-engineering/fs2-pubsub","last_synced_at":"2025-05-09T02:59:48.787Z","repository":{"id":37445039,"uuid":"164690350","full_name":"permutive-engineering/fs2-pubsub","owner":"permutive-engineering","description":"Google Cloud Pub/Sub stream-based client built on top of cats-effect, fs2 and http4s.","archived":false,"fork":false,"pushed_at":"2025-04-21T08:54:36.000Z","size":677,"stargazers_count":50,"open_issues_count":4,"forks_count":15,"subscribers_count":28,"default_branch":"main","last_synced_at":"2025-05-09T02:59:43.301Z","etag":null,"topics":["cats-effect","fp","fs2","google-pubsub","scala","streaming"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/permutive-engineering.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-08T16:33:02.000Z","updated_at":"2025-03-01T00:01:36.000Z","dependencies_parsed_at":"2024-02-15T06:24:00.746Z","dependency_job_id":"af322b60-a8d2-4e2b-8095-6505c354c34b","html_url":"https://github.com/permutive-engineering/fs2-pubsub","commit_stats":null,"previous_names":["permutive-engineering/fs2-pubsub","permutive-engineering/fs2-google-pubsub"],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permutive-engineering%2Ffs2-pubsub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permutive-engineering%2Ffs2-pubsub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permutive-engineering%2Ffs2-pubsub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/permutive-engineering%2Ffs2-pubsub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/permutive-engineering","download_url":"https://codeload.github.com/permutive-engineering/fs2-pubsub/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253181418,"owners_count":21866991,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cats-effect","fp","fs2","google-pubsub","scala","streaming"],"created_at":"2024-12-10T20:16:58.244Z","updated_at":"2025-05-09T02:59:48.771Z","avatar_url":"https://github.com/permutive-engineering.png","language":"Scala","funding_links":[],"categories":["\u003ca name=\"Scala\"\u003e\u003c/a\u003eScala"],"sub_categories":[],"readme":"Google Cloud Pub/Sub stream-based client built on top of cats-effect, fs2 and http4s.\n\n---\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Publishing messages to a Pub/Sub topic](#publishing-messages-to-a-pubsub-topic)\n    - [Configuring the publisher](#configuring-the-publisher)\n    - [Using gRPC (only available on 2.13 or 3.x)](#using-grpc-only-available-on-213-or-3x)\n    - [Publishing messages asynchronously (in batches)](#publishing-messages-asynchronously-in-batches)\n  - [Subscribing to a Pub/Sub subscription](#subscribing-to-a-pubsub-subscription)\n    - [Configuring the subscriber](#configuring-the-subscriber)\n    - [Using gRPC (only available on 2.13 or 3.x)](#using-grpc-only-available-on-213-or-3x)\n    - [Creating a raw subscriber](#creating-a-raw-subscriber)\n  - [Pureconfig integration](#pureconfig-integration)\n- [Migrating from `fs2-google-pubsub`](#migrating-from-fs2-google-pubsub)\n- [Contributors to this project](#contributors-to-this-project)\n\n## Installation\n\nAdd the following line to your `build.sbt` file:\n\n```sbt\nlibraryDependencies += \"com.permutive\" %% \"fs2-pubsub\" % \"1.1.0\"\n```\n\nThe library is published for Scala versions: `2.12`, `2.13` and `3`.\n\n## Usage\n\nTo start using the library, you'll need an http4s `Client` with permission to\ncall Pub/Sub APIs in GCP. You can create one using [`gcp-auth`]:\n\n```scala\nimport org.http4s.ember.client.EmberClientBuilder\nimport cats.effect.IO\nimport cats.syntax.all._\nimport com.permutive.gcp.auth.TokenProvider\n\nval client = EmberClientBuilder\n  .default[IO]\n  .withHttp2\n  .build\n  .mproduct(client =\u003e TokenProvider.userAccount(client).toResource)\n  .map { case (client, tokenProvider) =\u003e tokenProvider.clientMiddleware(client) }\n```\n\n\n### Publishing messages to a Pub/Sub topic\n\nTo publish messages to Pub/Sub, you can use the `PubsubPublisher` class:\n\n```scala\nimport fs2.pubsub._\n\nval publisher: PubSubPublisher[IO, String] = PubSubPublisher\n    .http[IO, String]\n    .projectId(ProjectId(\"my-project\"))\n    .topic(Topic(\"my-topic\"))\n    .defaultUri\n    .httpClient(client)\n    .noRetry\n```\n\nThen you can use any of the `PubSubPublisher` methods to send messages to Pub/Sub.\n\n```scala\n// Producing a single message\n\npublisher.publishOne(\"message\")\n```\n\n```scala\n// Producing multiple messages\n\nval records = List(\n   PubSubRecord.Publisher(\"message1\"),\n   PubSubRecord.Publisher(\"message2\"),\n   PubSubRecord.Publisher(\"message3\")\n)\n\npublisher.publishMany(records)\n```\n\n```scala\n// Producing a message with attributes\n\npublisher.publishOne(\"message\", \"key\" -\u003e \"value\")\n```\n\n```scala\n// Producing a message using the record type\n\nval record = PubSubRecord.Publisher(\"message\").withAttribute(\"key\", \"value\")\n\npublisher.publishOne(record)\n```\n\n#### Configuring the publisher\n\nThere are several configuration options available for the publisher:\n\n- `projectId`: The GCP project ID.\n- `topic`: The Pub/Sub topic name.\n- `uri`: The URI of the Pub/Sub API. By default, it uses the Google Cloud\nPub/Sub API.\n- `httpClient`: The http4s `Client` to use for making requests to the\nPub/Sub API.\n- `retry`: The retry policy to use when sending messages to Pub/Sub. By\ndefault, it retries up to 3 times with exponential backoff.\n\nThese configurations can either by provided by using a configuration object\n(`PubSubPublisher.Config`) or by using the builder pattern.\n\n#### Using gRPC (only available on 2.13 or 3.x)\n\nYou can use `PubSubPublisher.grpc` to create a publisher that uses gRPC to connect\nto Pub/Sub.\n\nThis type of publisher is only available on Scala `2.13` or `3.x`.\n\n#### Publishing messages asynchronously (in batches)\n\nIn order to publish messages asynchronously, you can use the `PubSubPublisher.Async`.\nYou can create an instance of this class from a regular `PubSubPublisher` by using the\n`batching` method:\n\n```scala\nimport cats.effect.Resource\nimport scala.concurrent.duration._\n\nval asyncPublisher: Resource[IO, PubSubPublisher.Async[IO, String]] = \n   publisher\n    .batching\n    .batchSize(10)\n    .maxLatency(1.second)\n```\n\nThen you can use any of the `PubSubPublisher.Async` methods to send messages to Pub/Sub.\nThese methods are the same ones you'll find in the regular `PubSubPublisher`, with\nthe difference that they return a `F[Unit]` instead of a `F[MessageId]` and that\nthey expect a `PubSubRecord.Publisher.WithCallback` instead of a regular\n`PubSubRecord.Publisher`.\n\nIn order to construct such class you can either use the `PubSubRecord.Publisher.WithCallback`\nconstructor or use the `withCallback` method on a regular `PubSubRecord.Publisher`:\n\n```scala\nval recordWithCallback = PubSubRecord.Publisher(\"message\").withCallback { _ =\u003e\n  IO(println(\"Message sent!\"))\n}\n```\n\n### Subscribing to a Pub/Sub subscription\n\nTo subscribe to a Pub/Sub subscription, you can use the `PubSubSubscriber` class:\n\n```scala\nimport fs2.Stream\n\nval subscriber: Stream[IO, Option[String]] = PubSubSubscriber\n    .http[IO]\n    .projectId(ProjectId(\"my-project\"))\n    .subscription(Subscription(\"my-subscription\"))\n    .defaultUri\n    .httpClient(client)\n    .noRetry\n    .noErrorHandling\n    .withDefaults\n    .decodeTo[String]\n    .subscribeAndAck\n```\n\n#### Configuring the subscriber\n\nThere are several configuration options available for the subscriber:\n\n- `projectId`: The GCP project ID.\n- `subscription`: The Pub/Sub subscription name.\n- `uri`: The URI of the Pub/Sub API. By default, it uses the Google Cloud\nPub/Sub API.\n- `httpClient`: The http4s `Client` to use for making requests to the\nPub/Sub API.\n- `retry`: The retry policy to use when receiving messages from Pub/Sub. By\ndefault, it retries up to 3 times with exponential backoff.\n- `errorHandling`: The error handling policy to use when performing operations\nsuch as decoding messages or acknowledging them.\n- `batchSize`: The maximum number of messages to acknowledge at once.\n- `maxLatency`: The maximum time to wait for a batch of messages before \nacknowledging them.\n- `maxMessages`: The maximum number of messages to receive in a single batch.\n- `readConcurrency`: The number of concurrent reads from the subscription.\n\nThese configurations can either by provided by using a configuration object\n(`PubSubSubscriber.Config`) or by using the builder pattern.\n\n#### Using gRPC (only available on 2.13 or 3.x)\n\nYou can use `PubSubSubscriber.grpc` to create a subscriber that uses gRPC to connect\nto Pub/Sub.\n\nThis type of subscriber is only available on Scala `2.13` or `3.x`.\n\n#### Creating a raw subscriber\n\nThere are two types of subscribers available in the library: raw and decoded.\n\nThe raw subscriber returns the raw message received from Pub/Sub, while the\ndecoded subscriber decodes the message to a specific type.\n\nThe former is useful when you want to handle the message yourself, while the\nlatter is useful when you want to work with a specific type. You can create\na raw subscriber by using the `raw` method instead of `decodeTo`.\n\n### Pureconfig integration\n\nThe library provides a way to load the configuration from a `ConfigSource` using\n[`pureconfig`].\n\nYou just need to add the following line to your `build.sbt` file:\n\n```sbt\nlibraryDependencies += \"com.permutive\" %% \"fs2-pubsub-pureconfig\" % \"1.1.0\"\n```\n\nAnd then add the following import when you want to use the `pureconfig` integration:\n\n\n```scala\nimport pureconfig.ConfigSource\n\nimport fs2.pubsub.PubSubPublisher\nimport fs2.pubsub.pureconfig._\n\nval config = ConfigSource.default.loadOrThrow[PubSubPublisher.Config]\n\nPubSubPublisher\n    .http[IO, String]\n    .fromConfig(config)\n    .httpClient(client)\n    .noRetry\n```\n\n## Migrating from `fs2-google-pubsub`\n\nThe most important thing you need to take into account while migrating is that\nthe library no longer creates an authenticated `Client` for you. You need to\nprovide one yourself using [`permutive-engineering/gcp-auth`][`gcp-auth`].\n\nYou can use the following table to\nfind the equivalent classes and methods in `fs2-pubsub`:\n\n| `fs2-google-pubsub`                                                                                                                                                                                                                                                                   | `fs2-pubsub`                                         |\n|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|\n| [`com.permutive.pubsub.consumer.ConsumerRecord`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/consumer/ConsumerRecord.scala)                                        | `fs2.pubsub.PubSubRecord.Publisher`                  |\n| [`com.permutive.pubsub.consumer.ConsumerRecord`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/consumer/ConsumerRecord.scala)                                        | `fs2.pubsub.PubSubRecord.Publisher`                  |\n| [`com.permutive.pubsub.consumer.decoder.MessageDecoder`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/consumer/decoder/MessageDecoder.scala)                        | `fs2.pubsub.MessageDecoder`                          |\n| [`com.permutive.pubsub.consumer.grpc.PubsubGoogleConsumer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-grpc/src/main/scala/com/permutive/pubsub/consumer/grpc/PubsubGoogleConsumer.scala)             | `fs2.pubsub.PubSubSubscriber.grpc`                   |\n| [`com.permutive.pubsub.consumer.grpc.PubsubGoogleConsumerConfig`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-grpc/src/main/scala/com/permutive/pubsub/consumer/grpc/PubsubGoogleConsumerConfig.scala) | `fs2.pubsub.PubSubSubscriber.Config`                 |\n| [`com.permutive.pubsub.consumer.http.PubsubHttpConsumer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/consumer/http/PubsubHttpConsumer.scala)                 | `fs2.pubsub.PubSubSubscriber.http`                   |\n| [`com.permutive.pubsub.consumer.http.PubsubHttpConsumerConfig`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/consumer/http/PubsubHttpConsumerConfig.scala)     | `fs2.pubsub.PubSubSubscriber.Config`                 |\n| [`com.permutive.pubsub.consumer.http.PubsubMessage`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/consumer/http/PubsubMessage.scala)                           | `fs2.pubsub.PubSubRecord.Subscriber`                 |\n| [`com.permutive.pubsub.consumer.Model.ProjectId`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/consumer/Model.scala)                                                | `fs2.pubsub.ProjectId`                               |\n| [`com.permutive.pubsub.consumer.Model.Subscription`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/consumer/Model.scala)                                             | `fs2.pubsub.Subscription`                            |\n| [`com.permutive.pubsub.http.crypto.*`](https://github.com/permutive-engineering/fs2-google-pubsub/tree/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/http/crypto)                                                               | [`permutive-engineering/gcp-auth`][`gcp-auth`]       |\n| [`com.permutive.pubsub.http.oauth.*`](https://github.com/permutive-engineering/fs2-google-pubsub/tree/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/http/oauth)                                                                 | [`permutive-engineering/gcp-auth`][`gcp-auth`]       |\n| [`com.permutive.pubsub.http.util.RefreshableEffect`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/http/util/RefreshableEffect.scala)                           | [`permutive-engineering/refreshable`][`refreshable`] |\n| [`com.permutive.pubsub.producer.AsyncPubsubProducer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/AsyncPubsubProducer.scala)                              | `fs2.pubsub.PubSubPublisher.Async`                   |\n| [`com.permutive.pubsub.producer.encoder.MessageEncoder`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/encoder/MessageEncoder.scala)                        | `fs2.pubsub.MessageEncoder`                          |\n| [`com.permutive.pubsub.producer.grpc.GooglePubsubProducer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-grpc/src/main/scala/com/permutive/pubsub/producer/grpc/GooglePubsubProducer.scala)             | `fs2.pubsub.PubSubPublisher.grpc`                    |\n| [`com.permutive.pubsub.producer.grpc.PubsubProducerConfig`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-grpc/src/main/scala/com/permutive/pubsub/producer/grpc/PubsubProducerConfig.scala)             | `fs2.pubsub.PubSubPublisher.Config`                  |\n| [`com.permutive.pubsub.producer.http.BatchingHttpProducerConfig`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/producer/http/BatchingHttpProducerConfig.scala) | `fs2.pubsub.PubSubPublisher.Async.Config`            |\n| [`com.permutive.pubsub.producer.http.BatchingHttpPubsubProducer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/producer/http/BatchingHttpPubsubProducer.scala) | `fs2.pubsub.PubSubPublisher.Async.http`              |\n| [`com.permutive.pubsub.producer.http.HttpPubsubProducer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/producer/http/HttpPubsubProducer.scala)                 | `fs2.pubsub.PubSubPublisher.http`                    |\n| [`com.permutive.pubsub.producer.http.PubsubHttpProducerConfig`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub-http/src/main/scala/com/permutive/pubsub/producer/http/PubsubHttpProducerConfig.scala)     | `fs2.pubsub.PubSubPublisher.Config`                  |\n| [`com.permutive.pubsub.producer.Model.AsyncRecord`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/Model.scala)                                              | `fs2.pubsub.PubSubRecord.Subscriber.WithCallback`    |\n| [`com.permutive.pubsub.producer.Model.MessageId`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/Model.scala)                                                | `fs2.pubsub.MessageId`                               |\n| [`com.permutive.pubsub.producer.Model.ProjectId`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/Model.scala)                                                | `fs2.pubsub.ProjectId`                               |\n| [`com.permutive.pubsub.producer.Model.SimpleRecord`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/Model.scala)                                             | `fs2.pubsub.PubSubRecord.Subscriber`                 |\n| [`com.permutive.pubsub.producer.Model.Topic`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/Model.scala)                                                    | `fs2.pubsub.Topic`                                   |\n| [`com.permutive.pubsub.producer.PubsubProducer`](https://github.com/permutive-engineering/fs2-google-pubsub/blob/a54ad7e698c89aaa6cc280ad482faa7f7ee210e2/fs2-google-pubsub/src/main/scala/com/permutive/pubsub/producer/PubsubProducer.scala)                                        | `fs2.pubsub.PubSubPublisher`                         |\n\n## Contributors to this project\n\n| \u003ca href=\"https://github.com/CremboC\"\u003e\u003cimg alt=\"CremboC\" src=\"https://avatars.githubusercontent.com/u/880130?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/bastewart\"\u003e\u003cimg alt=\"bastewart\" src=\"https://avatars.githubusercontent.com/u/10614835?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/TimWSpence\"\u003e\u003cimg alt=\"TimWSpence\" src=\"https://avatars.githubusercontent.com/u/3360080?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/travisbrown\"\u003e\u003cimg alt=\"travisbrown\" src=\"https://avatars.githubusercontent.com/u/316049?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/alejandrohdezma\"\u003e\u003cimg alt=\"alejandrohdezma\" src=\"https://avatars.githubusercontent.com/u/9027541?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/ChristianJohnston97\"\u003e\u003cimg alt=\"ChristianJohnston97\" src=\"https://avatars.githubusercontent.com/u/25692533?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/janstenpickle\"\u003e\u003cimg alt=\"janstenpickle\" src=\"https://avatars.githubusercontent.com/u/1926225?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e |\n| :--: | :--: | :--: | :--: | :--: | :--: | :--: |\n| \u003ca href=\"https://github.com/CremboC\"\u003e\u003csub\u003e\u003cb\u003eCremboC\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/bastewart\"\u003e\u003csub\u003e\u003cb\u003ebastewart\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/TimWSpence\"\u003e\u003csub\u003e\u003cb\u003eTimWSpence\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/travisbrown\"\u003e\u003csub\u003e\u003cb\u003etravisbrown\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/alejandrohdezma\"\u003e\u003csub\u003e\u003cb\u003ealejandrohdezma\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/ChristianJohnston97\"\u003e\u003csub\u003e\u003cb\u003eChristianJohnston97\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/janstenpickle\"\u003e\u003csub\u003e\u003cb\u003ejanstenpickle\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e |\n\n| \u003ca href=\"https://github.com/chrisjl154\"\u003e\u003cimg alt=\"chrisjl154\" src=\"https://avatars.githubusercontent.com/u/13693531?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/marcelocarlos\"\u003e\u003cimg alt=\"marcelocarlos\" src=\"https://avatars.githubusercontent.com/u/16080771?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/desbo\"\u003e\u003cimg alt=\"desbo\" src=\"https://avatars.githubusercontent.com/u/1064734?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/kythyra\"\u003e\u003cimg alt=\"kythyra\" src=\"https://avatars.githubusercontent.com/u/59971230?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/mcgizzle\"\u003e\u003cimg alt=\"mcgizzle\" src=\"https://avatars.githubusercontent.com/u/16902920?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/istreeter\"\u003e\u003cimg alt=\"istreeter\" src=\"https://avatars.githubusercontent.com/u/2102676?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/Joe8Bit\"\u003e\u003cimg alt=\"Joe8Bit\" src=\"https://avatars.githubusercontent.com/u/467683?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e |\n| :--: | :--: | :--: | :--: | :--: | :--: | :--: |\n| \u003ca href=\"https://github.com/chrisjl154\"\u003e\u003csub\u003e\u003cb\u003echrisjl154\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/marcelocarlos\"\u003e\u003csub\u003e\u003cb\u003emarcelocarlos\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/desbo\"\u003e\u003csub\u003e\u003cb\u003edesbo\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/kythyra\"\u003e\u003csub\u003e\u003cb\u003ekythyra\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/mcgizzle\"\u003e\u003csub\u003e\u003cb\u003emcgizzle\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/istreeter\"\u003e\u003csub\u003e\u003cb\u003eistreeter\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e | \u003ca href=\"https://github.com/Joe8Bit\"\u003e\u003csub\u003e\u003cb\u003eJoe8Bit\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e |\n\n| \u003ca href=\"https://github.com/arunas-cesonis\"\u003e\u003cimg alt=\"arunas-cesonis\" src=\"https://avatars.githubusercontent.com/u/35488648?v=4\u0026s=120\" width=\"120px\" /\u003e\u003c/a\u003e |\n| :--: |\n| \u003ca href=\"https://github.com/arunas-cesonis\"\u003e\u003csub\u003e\u003cb\u003earunas-cesonis\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e |\n\n[`gcp-auth`]: https://github.com/permutive-engineering/gcp-auth/\n[`refreshable`]: https://github.com/permutive-engineering/refreshable/\n[`pureconfig`]: https://pureconfig.github.io/","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpermutive-engineering%2Ffs2-pubsub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpermutive-engineering%2Ffs2-pubsub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpermutive-engineering%2Ffs2-pubsub/lists"}