{"id":45939850,"url":"https://github.com/etspaceman/kinesis-mock","last_synced_at":"2026-02-28T10:35:00.536Z","repository":{"id":38444741,"uuid":"345898495","full_name":"etspaceman/kinesis-mock","owner":"etspaceman","description":"A Kinesis Mock using Http4s","archived":false,"fork":false,"pushed_at":"2026-01-17T16:13:26.000Z","size":37723,"stargazers_count":57,"open_issues_count":4,"forks_count":18,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-17T17:15:16.925Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Scala","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/etspaceman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","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":"2021-03-09T05:54:19.000Z","updated_at":"2026-01-17T16:13:29.000Z","dependencies_parsed_at":"2023-12-27T01:25:41.607Z","dependency_job_id":"16644804-189f-4ab1-9969-e378df6ffab7","html_url":"https://github.com/etspaceman/kinesis-mock","commit_stats":null,"previous_names":[],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/etspaceman/kinesis-mock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etspaceman%2Fkinesis-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etspaceman%2Fkinesis-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etspaceman%2Fkinesis-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etspaceman%2Fkinesis-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/etspaceman","download_url":"https://codeload.github.com/etspaceman/kinesis-mock/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/etspaceman%2Fkinesis-mock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29930344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T09:58:13.507Z","status":"ssl_error","status_checked_at":"2026-02-28T09:57:57.047Z","response_time":90,"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":[],"created_at":"2026-02-28T10:34:59.989Z","updated_at":"2026-02-28T10:35:00.527Z","avatar_url":"https://github.com/etspaceman.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kinesis Mock\n\n![](https://github.com/etspaceman/kinesis-mock/workflows/Scala%20CI/badge.svg)\n[![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org)\n[![Join the chat at https://gitter.im/etspaceman/kinesis-mock](https://badges.gitter.im/etspaceman/kinesis-mock.svg)](https://gitter.im/etspaceman/kinesis-mock?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n![](https://img.shields.io/github/downloads/etspaceman/kinesis-mock/total)\n[![npm version](https://badge.fury.io/js/kinesis-local.svg)](https://badge.fury.io/js/kinesis-local)\n\n- [Kinesis Mock](#kinesis-mock)\n- [Overview](#overview)\n- [Starting the service](#starting-the-service)\n- [Service Configuration](#service-configuration)\n- [Usage](#usage)\n  * [Configuring AWS SDK Kinesis Client](#configuring-aws-sdk-kinesis-client)\n  * [Configuring the KPL](#configuring-the-kpl)\n  * [Configuring the KCL](#configuring-the-kcl)\n- [Known issues](#known-issues)\n\n# Overview\n\nA mock for the [Kinesis](https://docs.aws.amazon.com/kinesis/latest/APIReference/Welcome.html) API, intended for local testing.\n\n# Starting the service\n\nThere are a few ways to start kinesis-mock.\n\n## Docker\n\nIt is available as a docker image in the GitHub Container Registry:\n\n```shell\ndocker pull ghcr.io/etspaceman/kinesis-mock:0.4.8\ndocker run -p 4567:4567 -p 4568:4568 ghcr.io/etspaceman/kinesis-mock:0.4.8\n```\n\n## NPM\n\nIt is available on [NPM](https://www.npmjs.com/package/kinesis-local) as an executable service.\n\n```shell\nnpm i kinesis-local\nnpx kinesis-local\n```\n\n## Manual\n\nYou can also leverage the following executable options in the release assets:\n\n| File | Description | Launching |\n| ---- | ----------- | --------- |\n| `main.js` | Executable NodeJS file that can be run in any NodeJS enabled environment | `node ./main.js` |\n| `main.js.map` | Source mappings for main.js | |\n| `server.json` | self-signed certificate for TLS. Should be included in the same area as `main.js` | |\n\n# Service Configuration\n\nBelow is the available configuration for the service. Note that it is not recommended to edit the ports in the docker environment (rather you can map\nthese ports to a local one).\n\n| Variable | Data Type | Default Value | Notes                                                                                                                                                                                                                                                                                                                                                   |\n| -------- | --------- | ------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| INITIALIZE_STREAMS | String | | A comma-delimited string of stream names, its optional corresponding shard count and an optional region to initialize during startup. If the shard count is not provided, the default shard count of 4 is used. If the region is not provided, the default region is used. For example: \"my-first-stream:1,my-other-stream::us-west-2,my-last-stream:1\" |\n| KINESIS_MOCK_TLS_PORT | Int | 4567 | Https Only                                                                                                                                                                                                                                                                                                                                              |\n| KINESIS_MOCK_PLAIN_PORT | Int | 4568 | Http Only                                                                                                                                                                                                                                                                                                                                               |\n| KINESIS_MOCK_KEYSTORE_PASSWORD | Int | \u003credacted\u003e | Password for the JKS KeyStore (only for JVM, not JS)\n| KINESIS_MOCK_KEYMANAGER_PASSWORD | Int | \u003credacted\u003e | Password for the JKS KeyManager (only for JVM, not JS)\n| KINESIS_MOCK_CERT_PASSWORD | Int | \u003credacted\u003e | Password used for self-signed certificate (only for JS, not JVM)\n| KINESIS_MOCK_CERT_PATH | Int | server.json | Path to certificate file (only for JS, not JVM)\n| CREATE_STREAM_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| DELETE_STREAM_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| REGISTER_STREAM_CONSUMER_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| START_STREAM_ENCRYPTION_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| STOP_STREAM_ENCRYPTION_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| DEREGISTER_STREAM_CONSUMER_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| MERGE_SHARDS_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| SPLIT_SHARD_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| UPDATE_SHARD_COUNT_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| UPDATE_STREAM_MODE_DURATION | Duration | 500ms |                                                                                                                                                                                                                                                                                                                                                         |\n| SHARD_LIMIT | Int | 50 |                                                                                                                                                                                                                                                                                                                                                         |\n| ON_DEMAND_STREAM_COUNT_LIMIT | Int | 10 |                                                                                                                                                                                                                                                                                                                                                         |\n| AWS_ACCOUNT_ID | String | \"000000000000\" |                                                                                                                                                                                                                                                                                                                                                         |\n| AWS_REGION | String | \"us-east-1\" | Default region in use for operations. E.g. if a region is not provided by the INITIALIZE_STREAMS values.                                                                                                                                                                                                                                                |\n| LOG_LEVEL| String | \"INFO\" | Sets the log-level for kinesis-mock specific logs                                                                                                                                                                                                                                                                                                       |\n| ROOT_LOG_LEVEL | String | \"ERROR\" | Sets the log-level for all dependencies                                                                                                                                                                                                                                                                                                                 |\n| LOAD_DATA_IF_EXISTS | Boolean | true | Loads data from the configured persisted data file if it exists                                                                                                                                                                                                                                                                                         |\n| SHOULD_PERSIST_DATA | Boolean | false | Persists data to disk. Used to keep data during restarts of the service                                                                                                                                                                                                                                                                                 |\n| PERSIST_PATH | String | \"data\" | Path to persist data to. If it doesn't start with \"/\", the path is considered relative to the present working directory.                                                                                                                                                                                                                                |\n| PERSIST_FILE_NAME | String | \"kinesis-data.json\" | File name for persisted data                                                                                                                                                                                                                                                                                                                            |\n| PERSIST_INTERVAL | Duration | 5s | Delay between data persistence                                                                                                                                                                                                                                                                                                                          |\n\n\n## Log Levels\n\nYou can configure the `LOG_LEVEL` of the mock with the following levels in mind:\n\n* `ERROR`- Unhandled errors in the service\n* `WARN` - Handled errors in the service (e.g. bad requests)\n* `INFO` - High-level, low-noise informational messages (default)\n* `DEBUG` - Low-level, high-noise informational messages\n* `TRACE` - Log data bodies going in / out of the service\n\n# Usage\n\nThe image exposes 2 ports for interactions:\n- 4567 (https)\n- 4568 (http)\n\nFor an example docker-compose setup which uses this image, check out the [docker-compose.yml](docker/docker-compose.yml) file.\n\nThere are examples configuring the KPL, KCL and AWS SDK to use this mock in the [integration tests](integration-tests/src/test/scala/kinesis/mock).\n\n## Configuring AWS SDK Kinesis Client\n\n```scala\nimport software.amazon.awssdk.auth.credentials.{AwsCredentials,AwsCredentialsProvider}\nimport software.amazon.awssdk.http.SdkHttpConfigurationOption\nimport software.amazon.awssdk.http.async.SdkAsyncHttpClient\nimport software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient\nimport software.amazon.awssdk.regions.Region\nimport software.amazon.awssdk.services.kinesis.KinesisAsyncClient\nimport software.amazon.awssdk.services.kinesis.model._\nimport software.amazon.awssdk.utils.AttributeMap\n\nobject MyApp {\n  // A mock credentials provider\n  final case class AwsCreds(accessKey: String, secretKey: String)\n    extends AwsCredentials\n    with AwsCredentialsProvider {\n    override def accessKeyId(): String = accessKey\n    override def secretAccessKey(): String = secretKey\n    override def resolveCredentials(): AwsCredentials = this\n  }\n\n  object AwsCreds {\n    val LocalCreds: AwsCreds =\n      AwsCreds(\"mockKinesisAccessKey\", \"mockKinesisSecretKey\")\n  }\n  \n  // The kinesis-mock uses a self-signed certificate\n  private val trustAllCertificates =\n    AttributeMap\n      .builder()\n      .put(\n        SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES,\n        java.lang.Boolean.TRUE\n      )\n      .build()\n  \n  def nettyClient: SdkAsyncHttpClient =\n    NettyNioAsyncHttpClient\n      .builder()\n      .buildWithDefaults(trustAllCertificates)\n\n  val kinesisClient: KinesisAsyncClient = \n    KinesisAsyncClient\n        .builder()\n        .httpClient(nettyClient)\n        .region(Region.US_EAST_1)\n        .credentialsProvider(AwsCreds.LocalCreds)\n        .endpointOverride(URI.create(s\"https://localhost:4567\"))\n        .build()\n}\n```\n\n## Configuring the KPL\n```scala\nimport software.amazon.awssdk.auth.credentials.{AwsCredentials,AwsCredentialsProvider}\nimport software.amazon.awssdk.regions.Region\nimport software.amazon.kinesis.producer._\n\nobject MyApp {\n  // A mock credentials provider\n  final case class AwsCreds(accessKey: String, secretKey: String)\n    extends AwsCredentials\n    with AwsCredentialsProvider {\n    override def accessKeyId(): String = accessKey\n    override def secretAccessKey(): String = secretKey\n    override def resolveCredentials(): AwsCredentials = this\n  }\n\n  object AwsCreds {\n    val LocalCreds: AwsCreds =\n      AwsCreds(\"mockKinesisAccessKey\", \"mockKinesisSecretKey\")\n  }\n  \n  val kplProducer = new KinesisProducer(\n    new KinesisProducerConfiguration()\n      .setCredentialsProvider(AwsCreds.LocalCreds)\n      .setRegion(Region.US_EAST_1.id())\n      .setKinesisEndpoint(\"localhost\")\n      .setKinesisPort(4567L)\n      .setCloudwatchEndpoint(\"localhost\")\n      .setCloudwatchPort(4566L) // Using localstack's Cloudwatch port\n      .setVerifyCertificate(false)\n    )\n}\n```\n\n## Configuring the KCL\n\n```scala\nimport software.amazon.awssdk.auth.credentials.{AwsCredentials,AwsCredentialsProvider}\nimport software.amazon.awssdk.http.SdkHttpConfigurationOption\nimport software.amazon.awssdk.http.async.SdkAsyncHttpClient\nimport software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient\nimport software.amazon.awssdk.regions.Region\nimport software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient\nimport software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient\nimport software.amazon.awssdk.services.kinesis.KinesisAsyncClient\nimport software.amazon.awssdk.services.kinesis.model._\nimport software.amazon.awssdk.utils.AttributeMap\nimport software.amazon.kinesis.checkpoint.CheckpointConfig\nimport software.amazon.kinesis.common._\nimport software.amazon.kinesis.coordinator.{CoordinatorConfig, Scheduler}\nimport software.amazon.kinesis.leases.LeaseManagementConfig\nimport software.amazon.kinesis.leases.dynamodb.{\n  DynamoDBLeaseManagementFactory,\n  DynamoDBLeaseSerializer\n}\nimport software.amazon.kinesis.lifecycle.LifecycleConfig\nimport software.amazon.kinesis.lifecycle.events._\nimport software.amazon.kinesis.metrics.MetricsConfig\nimport software.amazon.kinesis.processor._\nimport software.amazon.kinesis.retrieval.polling.PollingConfig\nimport software.amazon.kinesis.retrieval.RetrievalConfig\n\nobject MyApp {\n  // A mock credentials provider\n  final case class AwsCreds(accessKey: String, secretKey: String)\n    extends AwsCredentials\n    with AwsCredentialsProvider {\n    override def accessKeyId(): String = accessKey\n    override def secretAccessKey(): String = secretKey\n    override def resolveCredentials(): AwsCredentials = this\n  }\n\n  object AwsCreds {\n    val LocalCreds: AwsCreds =\n      AwsCreds(\"mockKinesisAccessKey\", \"mockKinesisSecretKey\")\n  }\n  \n  // The kinesis-mock uses a self-signed certificate\n  private val trustAllCertificates =\n    AttributeMap\n      .builder()\n      .put(\n        SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES,\n        java.lang.Boolean.TRUE\n      )\n      .build()\n  \n  def nettyClient: SdkAsyncHttpClient =\n    NettyNioAsyncHttpClient\n      .builder()\n      .buildWithDefaults(trustAllCertificates)\n\n  val kinesisClient: KinesisAsyncClient = \n    KinesisAsyncClient\n      .builder()\n      .httpClient(nettyClient)\n      .region(Region.US_EAST_1)\n      .credentialsProvider(AwsCreds.LocalCreds)\n      .endpointOverride(URI.create(s\"https://localhost:4567\"))\n      .build()\n\n  val cloudwatchClient: CloudWatchAsyncClient - \n    CloudWatchAsyncClient\n      .builder()\n      .httpClient(nettyClient)\n      .region(Region.US_EAST_1)\n      .credentialsProvider(AwsCreds.LocalCreds)\n      .endpointOverride(URI.create(s\"https://localhost:4566\")) // localstack port\n      .build()\n\n  val dynamoClient: DynamoDbAsyncClient - \n    DynamoDbAsyncClient\n      .builder()\n      .httpClient(nettyClient)\n      .region(Region.US_EAST_1)\n      .credentialsProvider(AwsCreds.LocalCreds)\n      .endpointOverride(URI.create(s\"http://localhost:8000\")) // dynamodb-local port\n      .build()\n    \n  object KCLRecordProcessor extends ShardRecordProcessor {\n    override def initialize(x: InitializationInput): Unit = ()\n    override def processRecords(x: ProcessRecordsInput): Unit = println(s\"GOT RECORDS: $x\")\n    override def leaseLost(x: LeaseLostInput): Unit = ()\n    override def shardEnded(x: ShardEndedInput): Unit = ()\n    override def shutdownRequested(x: ShutdownRequestedInput): Unit = ()\n  }\n\n  object KCLRecordProcessorFactory extends ShardRecordProcessorFactory {\n    override def shardRecordProcessor(): ShardRecordProcessor =\n      KCLRecordProcessor\n    override def shardRecordProcessor(\n      streamIdentifier: StreamIdentifier\n    ): ShardRecordProcessor = KCLRecordProcessor\n  }\n\n  val appName = \"some-app-name\"\n  val workerId = \"some-worker-id\"\n  val streamName = \"some-stream-name\"\n  // kinesis-mock only supports polling consumers today\n  val retrievalSpecificConfig = new PollingConfig(streamName, kinesisClient)\n  // Local setups require us to tweak the lease management configuration\n  val defaultLeaseManagement = new LeaseManagementConfig(\n    appName,\n    appName,\n    dynamoClient,\n    kinesisClient,\n    workerId\n  ).shardSyncIntervalMillis(1000L)\n    .failoverTimeMillis(1000L)\n  val leaseManagementConfig = defaultLeaseManagement.leaseManagementFactory(\n    new DynamoDBLeaseManagementFactory(\n      defaultLeaseManagement.kinesisClient(),\n      defaultLeaseManagement.dynamoDBClient(),\n      defaultLeaseManagement.tableName(),\n      defaultLeaseManagement.workerIdentifier(),\n      defaultLeaseManagement.executorService(),\n      defaultLeaseManagement.failoverTimeMillis(),\n      defaultLeaseManagement.enablePriorityLeaseAssignment(),\n      defaultLeaseManagement.epsilonMillis(),\n      defaultLeaseManagement.maxLeasesForWorker(),\n      defaultLeaseManagement.maxLeasesToStealAtOneTime(),\n      defaultLeaseManagement.maxLeaseRenewalThreads(),\n      defaultLeaseManagement.cleanupLeasesUponShardCompletion(),\n      defaultLeaseManagement.ignoreUnexpectedChildShards(),\n      defaultLeaseManagement.shardSyncIntervalMillis(),\n      defaultLeaseManagement.consistentReads(),\n      defaultLeaseManagement.listShardsBackoffTimeInMillis(),\n      defaultLeaseManagement.maxListShardsRetryAttempts(),\n      defaultLeaseManagement.maxCacheMissesBeforeReload(),\n      defaultLeaseManagement.listShardsCacheAllowedAgeInSeconds(),\n      defaultLeaseManagement.cacheMissWarningModulus(),\n      defaultLeaseManagement.initialLeaseTableReadCapacity().toLong,\n      defaultLeaseManagement.initialLeaseTableWriteCapacity().toLong,\n      defaultLeaseManagement.tableCreatorCallback(),\n      defaultLeaseManagement.dynamoDbRequestTimeout(),\n      defaultLeaseManagement.billingMode(),\n      defaultLeaseManagement.leaseTableDeletionProtectionEnabled(),\n      defaultLeaseManagement.leaseTablePitrEnabled(),\n      defaultLeaseManagement.tags(),\n      new DynamoDBLeaseSerializer(),\n      defaultLeaseManagement.customShardDetectorProvider(),\n      false,\n      LeaseCleanupConfig\n        .builder()\n        .completedLeaseCleanupIntervalMillis(500L)\n        .garbageLeaseCleanupIntervalMillis(500L)\n        .leaseCleanupIntervalMillis(10.seconds.toMillis)\n        .build(),\n      defaultLeaseManagement\n        .workerUtilizationAwareAssignmentConfig()\n        .disableWorkerMetrics(true),\n      defaultLeaseManagement.gracefulLeaseHandoffConfig()\n    )\n  )\n  \n  // Consumer can be executed from this by running scheduler.run()\n  val scheduler = new Scheduler(\n    new CheckpointConfig(),\n    new CoordinatorConfig(appName)\n    .parentShardPollIntervalMillis(1000L),\n    leaseManagementConfig,\n    new LifecycleConfig(),\n    new MetricsConfig(cloudwatchClient, appName),\n    new ProcessorConfig(KCLRecordProcessorFactory),\n    new RetrievalConfig(\n      kinesisClient,\n      streamName,\n      appName\n    ).initialPositionInStreamExtended(\n    InitialPositionInStreamExtended.newInitialPosition(\n        InitialPositionInStream.TRIM_HORIZON\n    )\n    ).retrievalSpecificConfig(retrievalSpecificConfig)\n    .retrievalFactory(retrievalSpecificConfig.retrievalFactory())\n  )\n}\n```\n\n# Known issues\n- Does not currently support SubscribeToShard due to lack of push-promise support (https://github.com/http4s/http4s/issues/4624)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetspaceman%2Fkinesis-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fetspaceman%2Fkinesis-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fetspaceman%2Fkinesis-mock/lists"}