{"id":28291727,"url":"https://github.com/arqo123/speedgoose","last_synced_at":"2026-04-01T18:54:39.548Z","repository":{"id":49753075,"uuid":"517815990","full_name":"arqo123/speedgoose","owner":"arqo123","description":"Next-level mongoose caching layer with event based cache clearing ","archived":false,"fork":false,"pushed_at":"2026-03-23T21:24:01.000Z","size":1426,"stargazers_count":67,"open_issues_count":6,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-03-24T19:36:55.778Z","etag":null,"topics":["cache","cachegoose","mongodb","mongoose","nodejs","nosql","redis"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/arqo123.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["arqo123"],"custom":["https://www.buymeacoffee.com/arqo123"]}},"created_at":"2022-07-25T20:46:46.000Z","updated_at":"2026-03-23T21:24:03.000Z","dependencies_parsed_at":"2022-08-12T20:21:47.412Z","dependency_job_id":"56a0be2f-4fb4-4f4e-9fa8-0370f1323a54","html_url":"https://github.com/arqo123/speedgoose","commit_stats":{"total_commits":130,"total_committers":1,"mean_commits":130.0,"dds":0.0,"last_synced_commit":"6cb54245892ea8bff29036e8d3ef4fbab2d44f68"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/arqo123/speedgoose","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arqo123%2Fspeedgoose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arqo123%2Fspeedgoose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arqo123%2Fspeedgoose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arqo123%2Fspeedgoose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arqo123","download_url":"https://codeload.github.com/arqo123/speedgoose/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arqo123%2Fspeedgoose/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290977,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: 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":["cache","cachegoose","mongodb","mongoose","nodejs","nosql","redis"],"created_at":"2025-05-22T04:11:56.089Z","updated_at":"2026-04-01T18:54:39.538Z","avatar_url":"https://github.com/arqo123.png","language":"TypeScript","funding_links":["https://github.com/sponsors/arqo123","https://www.buymeacoffee.com/arqo123"],"categories":[],"sub_categories":[],"readme":"\u003cdiv id=\"top\"\u003e\u003c/div\u003e\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n \u003cimg src=\"speedgoose.png\" alt=\"Logo\" width=\"180\" \u003e\n \n\u003c/div\u003e\n\n## About The Project\n\n[![npm version](https://img.shields.io/npm/v/speedgoose.svg?style=flat-square)](https://www.npmjs.org/package/speedgoose)\n[![codecov](https://codecov.io/gh/arqo123/speedgoose/branch/master/graph/badge.svg?token=33R2CJ6I2C)](https://codecov.io/gh/arqo123/speedgoose)\n[![Known Vulnerabilities](https://snyk.io//test/github/arqo123/speedgoose/badge.svg?targetFile=package.json)](https://snyk.io//test/github/arqo123/speedgoose?targetFile=package.json)\n![NPM download/month](https://img.shields.io/npm/dm/speedgoose.svg)\n\nThis project is a next-level mongoose caching library that is fully written in typescript.\nIt's caching on two levels. Shared - with Redis. And local inside memory. Supports all mongoose operations like find,findOne, count, aggregate... and others. Also supports lean queries. Why it is different?\n\n-   It supports caching not only JSON objects in Redis but also the whole Mongoose. Document instances in local memory to speed up code, and prevent unnecessary hydrations. Also supports full in-memory caching, without Redis.\n-   It has an auto-clearing ability based on mongoose events. So if the query was cached for some records, and in the meantime, those records change, all cached-related results will be cleared.\n-   It supports deep hydration, for caching not only the root document instances but also those that are populated.\n-   Supports custom eventing. For example, if you want to remove given results from cache, but removal logic is not based on removing documents from DB but rather field based (like deleted: true), then you can apply a `wasRecordDeleted` callback as an option for the plugin.\n-   Supports multitenancy by clearing cached results only for a related tenant.\n-   It has a `cachePopulate` method that solves the N+1 problem with Mongoose population.\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Compatibility\n\n| Speedgoose | Mongoose | Node.js |\n|------------|----------|---------|\n| 2.x (latest) | 9.x   | \u003e= 20.19 |\n| 2.x        | 8.x      | \u003e= 16    |\n| 1.x        | 7.x      | \u003e= 14    |\n\n## Performance\n\nSpeedgoose delivers **massive speedups** on cached reads. Benchmarks below were run against an in-memory MongoDB (mongodb-memory-server) with 500 users and 1,000 posts with relations, using the IN_MEMORY cache strategy.\n\n| Operation | Uncached | Cached | Speedup |\n|-----------|----------|--------|---------|\n| `findOne` | ~1.4 ms  | ~0.03 ms | **~50x** |\n| `find` (20 results) | ~1.5 ms | ~0.02 ms | **~75x** |\n| `aggregate` ($group) | ~3.9 ms | ~0.02 ms | **~200x** |\n| `populate` (10 docs) | ~4.4 ms | ~0.02 ms | **~230x** |\n\n\u003e Results may vary depending on hardware, dataset size, and query complexity. With Redis or DragonflyDB as the shared cache, latencies will be slightly higher than in-memory but still significantly faster than hitting MongoDB directly.\n\nRun the benchmarks yourself:\n\n```console\nyarn benchmark\n```\n\n\u003c!-- GETTING STARTED --\u003e\n\n## Getting Started\n\nThis is an example of how you may give instructions on setting up your project locally.\nTo get a local copy up and running follow these simple example steps.\n\n### Installation\n\n```console\n$ npm install speedgoose\n# or\n$ yarn add speedgoose\n```\n\n\u003e **⚠️ Mongoose compatibility:** Speedgoose v2.3.0+ requires **mongoose 9.x**. If your project uses mongoose 8.x, pin speedgoose to `2.2.x`. See the [Compatibility](#compatibility) table above.\n\n1. Simple wrap your mongoose with the library (required)\n\n```ts\nimport { applySpeedGooseCacheLayer } from 'speedgoose';\nimport mongoose from 'mongoose';\n\napplySpeedGooseCacheLayer(mongoose, {\n    redisUri: process.env.REDIS_URI,\n});\n```\n\n\u003e 💡 **Pro tip:** For best performance, consider using [DragonflyDB](https://dragonflydb.io/) as a drop-in Redis replacement. It's fully compatible with speedgoose and offers significantly better performance.\n\n**Using a pre-built ioredis client:**\n\nIf you already have a configured ioredis client (e.g., with TLS, Sentinel, or cluster settings), you can pass it directly instead of a URI:\n\n```ts\nimport Redis from 'ioredis';\nimport { applySpeedGooseCacheLayer } from 'speedgoose';\nimport mongoose from 'mongoose';\n\nconst myRedisClient = new Redis({\n    host: 'my-redis.example.com',\n    port: 6380,\n    tls: { rejectUnauthorized: false },\n});\n\napplySpeedGooseCacheLayer(mongoose, {\n    redisClient: myRedisClient,\n});\n```\n\n\u003e When `redisClient` is provided, `redisUri` and `redisOptions` are ignored. Speedgoose will use your client directly for cache operations and PubSub publishing, and call `duplicate()` on it for the PubSub subscriber connection.\n\n2. To enable auto-clearing for a given schema, just add the plugin to it (required)\n\n```ts\nimport { SpeedGooseCacheAutoCleaner } from 'speedgoose';\n\nSchema.plugin(SpeedGooseCacheAutoCleaner);\n//additionally you can pass options for example callback for setting the record as deleted\nSchema.plugin(SpeedGooseCacheAutoCleaner, { wasRecordDeletedCallback });\n```\n\n\u003c!-- USAGE EXAMPLES --\u003e\n\n## Usage\n\n1. With find, count, etc...\n\n```ts\n// with findOne\nconst result  = await model\u003cSomeModelType\u003e.findOne({}).cacheQuery()\n```\n\n```ts\n// with count\nconst result  = await model\u003cSomeModelType\u003e.count({age: {$gt : 25}}).cacheQuery()\n```\n\n```ts\n// with sorting query\nconst result  = await model\u003cSomeModelType\u003e.find({}).sort({fieldA : 1}).cacheQuery()\n```\n\n```ts\n// with lean query\nconst result  = await model\u003cSomeModelType\u003e.find({}).lean().cacheQuery()\n```\n\n2. With aggregation\n\n```ts\nconst result = await model.aggregate\u003cAggregationResultType\u003e([]).cachePipeline()\n```\n\n3. Checking if key was set under the key. \n\n```ts\nconst isQueryCached = await model\u003cSomeModelType\u003e.find({}).sort({fieldA : 1}).isCached()\nconst isPipelineCached = await model.aggregate\u003cAggregationResultType\u003e([]).isCached()\n```\n\n4. With cache-based population\n\n```ts\nconst result = await model.find\u003cResultType\u003e({}).cachePopulate('user')\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003c!-- Multitenancy --\u003e\n\n## :briefcase: Multitenancy\n\nFor enabling multitenancy, you have to pass multitenantKey into wrapper config, so it will look like\n\n```ts\napplySpeedGooseCacheLayer(mongoose, {\n    redisUri: process.env.REDIS_URI,\n    multitenancyConfig: {\n        multitenantKey: 'tenantId',\n    },\n});\n```\n\nSpeedGooseCacheAutoCleaner plugin clears the cache for a given model each time when new record appears, or some record was deleted. In multitenancy, we won't clear the cache for all of the clients - as the change appears only for one tenant.\nSpeedGoose will handle it for You! But to make it work, you have to follow the rules:\n\n1. Tenant key must be in the root of mongo documents\n2. You have to somehow pass tenant value while running `cacheQuery()` or `cachePipeline()`.\n\n-   In the case of `cacheQuery()` you can simply include tenant filtering condition in the root of query, so tenantValue will be automatically set from there\n    example:\n\n```ts\nconst result = await model\u003cSomeModelType\u003e.find({\n   someCondition : {$gt: 123},\n   tenantId: \"someTenantUniqueValue\",\n   ... //rest of the query\n}).cacheQuery()\n```\n\n-   In other cases for `cacheQuery()` and `cachePipeline()` you have to pass tenantValue manually by passing params\n\n```ts\n/// with cachePipeline()\nconst result = await model.aggregate\u003cAggregationResultType\u003e([]).cachePipeline({ multitenantValue: 'someTenantUniqueValue' });\n```\n\n```ts\n/// with cacheQuery()\nconst result = await model\u003cSomeModelType\u003e.find({}).cacheQuery({multitenantValue : 'someTenantUniqueValue'})\n```\n\n\u003c!-- Debugging --\u003e\n\n## :electric_plug: Auto-cleaner Plugin\n\nThis plugin works on mongoose Document and Query/Model operations events. In the case of Document events, we already know which of the document was changed - as it was the parent of the event. But records affected by Query/Model events are predicted according to query conditions and options. Currently supported Mongoose events:\n\n1. Deleting operations -\u003e `findByIdAndRemove, findByIdAndDelete, findOneAndDelete, findOneAndRemove, deleteOne, deleteMany, remove`\n2. Saving operations -\u003e `updateOne, findOneAndUpdate, findByIdAndUpdate, updateMany, save, insertMany`\n\nIf anything is missing and it's worth implementing - let me know!\n\n\u003c!-- Debugging --\u003e\n\n## :bug: Debugging\n\nFor enabling debug mode, you have to pass multitenantKey into wrapper config, so it will look like\n\n```ts\napplySpeedGooseCacheLayer(mongoose, {\n  redisUri: process.env.REDIS_URI,\n  debugConfig?: {\n        enabled?: true,\n        /** Optional: An array of mongoose models to debug, if not set then the debugger will log operations for all of the models */\n        debugModels?: ['yourModelName'],\n        /** Optional: An array of operations to debug, if not set then the debugger will log all operations */\n        debugOperations?: SpeedGooseDebuggerOperations[],\n    }\n})\n```\n\n \u003c!-- Options --\u003e\n\n## :wrench: Configuration and method options\n\n#### applySpeedGooseCacheLayer(mongoose, speedgooseConfig)\n\n```ts\n    /** Connection string for Redis containing URL, credentials, and port. It's required to make cache sync working */\n    redisUri?: string;\n    /** Connection options for Redis. */\n    redisOptions?: RedisOptions;\n    /** Pre-built ioredis client. When provided, redisUri and redisOptions are ignored. */\n    redisClient?: Redis;\n    /** Config for multitenancy. */\n    multitenancyConfig?: {\n        /** If set, then the cache will work for multitenancy. It has to be a multitenancy field indicator, that is set at the root of every MongoDB record. */\n        multitenantKey: string;\n    },\n    /** You can pass the default TTL value for all operations, which will not have it passed as a parameter. Value is in seconds. By default is 60 seconds */\n    defaultTtl?: number;\n    /** If true then will perform TTL refreshing on every read. By default is disabled */\n    refreshTtlOnRead?: boolean;\n    /** Config for debugging mode supported with debug-js */\n    debugConfig?: {\n        /** When set to true, it will log all operations or operations only for enabled namespaces*/\n        enabled?: boolean,\n        /** An array of mongoose models to debug, if not set then the debugger will log operations for all of the models */\n        debugModels?: string[],\n        /** An array of operations to debug, if not set then the debugger will log all operations */\n        debugOperations?: SpeedGooseDebuggerOperations[],\n    },\n    /** Cache strategy for shared results, by default it is SharedCacheStrategies.REDIS\n     * Available strategies: SharedCacheStrategies.REDIS and SharedCacheStrategies.IN_MEMORY */\n    sharedCacheStrategy?: SharedCacheStrategies,\n    /** Indicates if caching is enabled or disabled, by default is enabled */\n    enabled?: boolean,\n    /** If true, clears model-level cache also on update events. Useful for aggregates that don't include record _id (e.g. $group with _id: null). Default: false */\n    clearModelCacheOnUpdate?: boolean\n    }\n```\n\n#### `cacheQuery(operationParams)` and `cachePipeline(operationParams)`\n\n```ts\n{\n    /** It tells to speedgoose for how long a given query should exist in the cache. Value is in seconds. By default is 60 seconds. Set 0 to make it disabled. */\n    TTL?: number;\n    /** Useful only when using multitenancy. Could be set to distinguish cache keys between tenants.*/\n    multitenantValue?: string;\n    /** Your custom caching key.*/\n    cacheKey?: string;\n    /** It tells to speedgoose to refresh the ttl time when it reads from a cached results.*/\n    refreshTtlOnRead?: boolean;\n}\n```\n\n#### `SpeedGooseCacheAutoCleaner(...)`\n\n```ts\n{\n    /**\n     * Could be set to check if a given record was deleted. Useful when records are removed by setting some deletion indicator like \"deleted\" : true\n     * @param {Document} record mongoose document for which event was triggered\n    **/\n    wasRecordDeletedCallback?: \u003cT\u003e(record: Document\u003cT\u003e) =\u003e boolean\n}\n```\n\n#### `clearCacheForKeys(cacheKey)`\n\n```ts\n/**\n * Can be used for manually clearing the cache for a given cache key\n * @param {string} key cache key\n*/\nclearCacheForKeys(cacheKey: string) : Promise\u003cvoid\u003e\n```\n\n#### `clearCachedResultsForModel(modelName,tenantId)`\n\n```ts\n/**\n * Can be used for manually clearing the cache for given modelName.\n * @param {string} modelName name of registered mongoose model\n * @param {string} multitenantValue [optional] unique value of your tenant\n*/\nclearCachedResultsForModel(modelName: string, multitenantValue?: string) : Promise\u003cvoid\u003e\n```\n\nIf your app relies on aggregate caches that do not include document identifiers (for example `$group: { _id: null }`), you can either:\n- enable `clearModelCacheOnUpdate: true` to invalidate model cache automatically on updates,\n- or call `clearCachedResultsForModel(modelName, tenantId)` manually in your update flow.\n \n\n\u003c!-- CACHE POPULATE --\u003e\n\n## :recycle: Cache-based Population\n\nSpeedgoose introduces a powerful `cachePopulate` method to solve the common N+1 problem in MongoDB population. Instead of making separate database queries for each populated document, `cachePopulate` leverages caching to significantly reduce database load and improve response times.\n\n### How It Works\n\nThe `cachePopulate` method intercepts Mongoose `populate` calls and first attempts to retrieve the referenced documents from the cache. If some documents are not found in the cache, it fetches them from the database in a single, efficient query and then caches them for future use. This process is transparent to the developer and requires minimal code changes.\n\nHere's a flowchart illustrating the logic:\n\n```mermaid\ngraph TD\n    A[\"Query with .cachePopulate()\"] --\u003e B{Are populated documents in cache?}\n    B --\u003e|Yes| C[Retrieve from cache]\n    B --\u003e|No| D[Fetch from database]\n    D --\u003e E[Cache new documents]\n    E --\u003e C\n    C --\u003e F[Return populated results]\n```\n\n### Usage Examples\n\nUsing `cachePopulate` is as simple as replacing `.populate()` with `.cachePopulate()` in your queries.\n\n**Basic Population:**\n\n```typescript\n// From\nconst result = await MyModel.find({}).populate('user');\n\n// To\nconst result = await MyModel.find({}).cachePopulate('user');\n\n// or \nconst result = await MyModel.find({}).cachePopulate({ path: 'user' });\n```\n\n**Multiple Populations:**\n\nYou can cache multiple population paths in two ways:\n\n```typescript\n// 1) Pass a space-delimited string\nconst result = await MyModel.find({}).cachePopulate(\"user comments\");\n\n// 2) Pass an array of configuration objects\n// The second approach is the best when you need to specify different options (such as field selection or deep population) for each path.\n// You can read about it down below.\nconst result = await MyModel.find({}).cachePopulate([\n    { path: 'user' },\n    { path: 'comments' }\n]);\n```\n\n**Selecting Specific Fields:**\n\nJust like with Mongoose's `populate`, you can use the `select` option to specify which fields of the populated document to return.\n\n```typescript\nconst result = await MyModel.find({}).cachePopulate({\n    path: 'user',\n    select: 'name email' // or { name: 1, email: 1 }\n});\n```\n\n**Custom TTL:**\n\nYou can set a custom Time-To-Live (TTL) for the cached populated documents.\n\n```typescript\nconst result = await MyModel.find({}).cachePopulate({\n    path: 'user',\n    ttl: 300 // 5 minutes\n});\n```\n\n**TTL Inheritance:**\n\nThe `ttlInheritance` option controls how the TTL is applied when a global TTL is also configured.\n\n*   `'fallback'` (default): The `ttl` from `cachePopulate` is used only if no global TTL is set.\n*   `'override'`: The `ttl` from `cachePopulate` always takes precedence over the global TTL.\n\n```typescript\nconst result = await MyModel.find({}).cachePopulate({\n    path: 'user',\n    ttl: 300,\n    ttlInheritance: TtlInheritance.OVERRIDE\n});\n```\n\n### Supported Options\n\nThe `cachePopulate` method could accept arguments in a different form:\n1) Space-delimited string. For example `.cachePopulate('field1 field2')`.\n2) `SpeedGoosePopulateOptions`.\n3) An array of `SpeedGoosePopulateOptions`.\n\nThe `SpeedGoosePopulateOptions` object has these properties:\n\n| Option          | Type                         | Description                                                                                                                            |\n| --------------- |------------------------------| -------------------------------------------------------------------------------------------------------------------------------------- |\n| `path`          | `string`                     | The field to populate.                                                                                                                 |\n| `select`        | `string` or `object`         | Specifies which document fields to include or exclude.                                                                                 |\n| `ttl`           | `number`                     | The Time-To-Live for the cached populated documents, in seconds.                                                                       |\n| `ttlInheritance`| `'override'` or `'fallback'` | Controls how the `ttl` option interacts with a globally configured TTL. Defaults to `'fallback'`.                                      |\n| `invalidationScope`| `'parents'` or `'full'`         |  Controls the scope of cache invalidation when a child document changes.                                      |\n\n### Parent Cache Invalidation\n\nA key feature of `cachePopulate` is its intelligent cache invalidation. When a populated document is updated or deleted, Speedgoose automatically invalidates the cache for any parent documents that reference it. This ensures that your application always serves fresh data.\n\nFor example, if a `User` document is updated, any `Article` documents that have that user populated will have their `cachePopulate` cache cleared for the `user` field. This is handled automatically by the `SpeedGooseCacheAutoCleaner` plugin.\n\n\u003c!-- ROADMAP --\u003e\n\n## :dart: Roadmap\n\n-   [ ] Separated documentation\n-   [x] Add more examples\n-   [x] Deep hydration for nested documents \n-   [x] Cache-based population\n-   [x] Manual cache clearing for custom keys\n-   [x] Refreshing TTL on read\n-   [x] Support for clustered servers \n-   [x] Flowchart of logic\n-   [x] Tests\n    -   [x] commonUtils\n    -   [x] debuggerUtils\n    -   [x] mongooseUtils\n    -   [x] queryUtils\n    -   [x] cacheClientUtils\n    -   [x] cacheKeyUtils\n    -   [x] hydrationUtils\n    -   [x] redisUtils\n    -   [x] extendAggregate\n    -   [x] extendQuery\n    -   [x] mongooseModelEvents\n    -   [x] wrapper\n    -   [x] inMemory caching strategy\n    -   [x] Redis caching strategy\n    -   [x] Integration / real-world app tests\n    -   [x] Performance benchmarks\n-   [x] Multitenancy (tenant field indicator) support\n-   [x] Debugging mode\n-   [x] Support for more cache storage\n    -   [x] In memory\n    -   [x] Redis\n\nSee the [open issues](https://github.com/arqo123/speedgoose/issues) for a full list of proposed features (and known issues).\n\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003c!-- CONTRIBUTING --\u003e\n\n## :ticket: Contributing\n\nWant to contribute? Great! Open a new issue or pull request with the solution for a given bug/feature. Any ideas for extending this library are more than welcome.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003c!-- Known bugs --\u003e\n\n## :warning: Known bugs\n\n-   Let me know if there are any, I will resolve them fast as SpeedGoose is!\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003c!-- LICENSE --\u003e\n\n## :heart: License\n\nDistributed under the MIT License. See `LICENSE.txt` for more information.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farqo123%2Fspeedgoose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farqo123%2Fspeedgoose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farqo123%2Fspeedgoose/lists"}