{"id":20229230,"url":"https://github.com/hisco/rolling-windows","last_synced_at":"2025-10-24T19:47:42.416Z","repository":{"id":65491231,"uuid":"134104649","full_name":"hisco/rolling-windows","owner":"hisco","description":"Store your data efficiently in rolling window buckets store, written in pure JS.","archived":false,"fork":false,"pushed_at":"2020-05-23T11:55:00.000Z","size":199,"stargazers_count":7,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-08T11:44:17.476Z","etag":null,"topics":["bining","bucket","bucketing","dispose-buckets","javascript","multiple-counters","rolling-ring","rolling-windows","sliding-window","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/rolling-windows","language":"JavaScript","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/hisco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-19T23:16:08.000Z","updated_at":"2020-02-21T22:41:29.000Z","dependencies_parsed_at":"2023-01-25T18:45:30.644Z","dependency_job_id":null,"html_url":"https://github.com/hisco/rolling-windows","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hisco/rolling-windows","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hisco%2Frolling-windows","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hisco%2Frolling-windows/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hisco%2Frolling-windows/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hisco%2Frolling-windows/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hisco","download_url":"https://codeload.github.com/hisco/rolling-windows/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hisco%2Frolling-windows/sbom","scorecard":{"id":465490,"data":{"date":"2025-08-11","repo":{"name":"github.com/hisco/rolling-windows","commit":"729099ef66b517f9ab98ed9e719d1bda4d23c6ca"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/14 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"18 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-g6ww-v8xp-vmwg"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T12:22:46.483Z","repository_id":65491231,"created_at":"2025-08-19T12:22:46.483Z","updated_at":"2025-08-19T12:22:46.483Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280857799,"owners_count":26403193,"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","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["bining","bucket","bucketing","dispose-buckets","javascript","multiple-counters","rolling-ring","rolling-windows","sliding-window","typescript"],"created_at":"2024-11-14T07:34:56.402Z","updated_at":"2025-10-24T19:47:42.394Z","avatar_url":"https://github.com/hisco.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rolling time window store\n\n[![Greenkeeper badge](https://badges.greenkeeper.io/hisco/rolling-windows.svg)](https://greenkeeper.io/)\n[![NPM Version][npm-image]][npm-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\n  Store your data efficiently in rolling window buckets store.\n  This technique is also named:\n  * Rolling ring\n  * Bucketing\n  * Bining\n  * Sliding window\n\n  Rolling windows module can be used by both browser and Node.js.\n\n## High perormance\nAll rolling windows were built with great concern of memory and CPU consumption.\nWe don't use arrays under the hood.\n\nInside this module you will be able to find\n  * Super-high test coverage\n  * class _WindowCore_ - A very simple \u0026 basic window, it only manages to additions and disposals of buckets. \n  * class _TimeWindowCore_ - Window that adds and dispose buckets based on a configurable interval.\n  * class _WindowSingleCounter_ - Window with counter in every bucket.\n  * class _WindowSingleStackedCounter_ - Widnow with stacked counter (Based on previous bucket). \n  * class _TimeBasedWindowCounter_ - Window with counter in every bucket it adds and dispose buckets based on a configurable interval.\n  * class _WindowMultipleCounters_ - Window with multiple counters in every bucket. \n  * class _TimeBasedWindowMultipleCounters_ - Window with multiple counters in every bucket it adds and dispose buckets based on a configurable interval. \n  * class _GenericTimeBasedStore_ - Window with generic object in any bucket that you can store any info in the last bucket and query all at once.\n\nSpeed and quality are the greatest concerns, this module was built with proper data structures and with some V8 micro-optimizations for even better CPU and memory consumption.\n\n## What is a rolling window?\n\nA rolling window is a technique to process and store a subset of an endless stream of data while perserving the order of processing/disposel of the data.\n\nThe window can be considerd as an actual window, while through the window you see at any given time data at a maximum size of the window.\nSimiliar to a very long train passing and you can see only a few railroas cars at any given time.\n\nIt is used in mathemtics to analyze a subset of a bigger set of data points, usally over time.\n\nFor example if your planing to count all the requests your server is getting at any last 24 hours, you cannot use a simple stright forward single counter `count++` because you will not know how to descrease the count.\n  * You cannot reset the count `count=0` you will lose all your data.\n  * You can store a timestamp of every request however, this will consume a lot of memory and CPU because you will store every individual timestamp.\n\nNo worries you can just use a 'Rolling window'!\n\n## Simple to use\n\n### Using Javascript\n```js\n    //Require all `rolling time window` module\n    const rollingTimeWindow = require('rolling-time-window');\n    //Now you can use `rollingTimeWindow.TimeBasedWindowCounter` etc...\n\n    //Directly load the desired class\n    const {WindowSingleCounter ,GenericTimeBasedStore} = require('rolling-time-window');\n\n```\n\n### Using TypeScript\n```ts\n    import {TimeBasedWindowCounter , GenericTimeBasedStore} from 'rolling-time-window';\n\n```\n\n## Why not just array?\n\nThe most common and simple implementation of rolling window is sometimes handled by an array under the hood.\n\n### Arrays would have consumed more CPU in this use case\nArray is an implementation of a stack data structure and is the best implementation when you need to push/pop something at the end of the stack.\nHowever, when it is also requeired to remove something at the beging of the stack the array will need to *Move* all elements and re-index the entire array with o(n) complexity (Imagine an array with millions of elements). \nWhile with linked list it's only o(1) complexity at any size of array.\n\nExample of a bad practice:\n```js\nvar a = [1,2,3,4,5];\na.shift() // Will cause o(n) operations\n```\n\n\n### Array would have have wasted more memory\nUnder the hood arrays are dynamic data strucure these change per the programtic demand in run time.\nGenerally these are the recomendations of using arrays:\n  * Don't pre-allocate large arrays to their maximum size, instead grow as you go.\n  * Use contiguous keys starting at 0 for arrays\n  * Don't delete elements in arrays.\n  * Don't load uninitialized or deleted elements\n \nAny deviation from these recomdations will cause the js engine (V8) to move the entire array from one implemnetation of array to the other, this will waste both memory \u0026 CPU.\n\nExample of a bad practice:\n```js\nvar a = new Array();\na[0] = 20;   // JS engine allocates\na[1] = 100;\na[2] = 100.5;   // JS engine allocates, converts\na[3] = true; // JS engine allocates, converts\n```\n\nExample of a better practice:\n```js\nvar a = [20, 100, 100.5, true];\n```\n\nExample of a bad practice:\n```js\nvar a = [1,2,3,4,5];\na.shift() // Will cause o(n) operations\n```\n\n## API\n\nAll rolling windows handles the basic concept rolling windows some in addition also handels a configurable internal time interval.\nA few concepts that will ease the API description:\n  * Window / Rolling window - The actual instance the implements the technique or the technique in general.\n  * Bucket - A window has multiple buckets/bins that store the data of that window fraction.\n  * Tick - The action of addind a bucket at the end of the window and when maximum window size passed it will also remove the bucket at the beginning of the window.\n  * Bucket value - The value the bucket points on, it can be a single numeric value, an object , array, etc...\n\nThe follwing is *not* a complete module decleration, I sugesst to require the module with TypeScript, it will give you a full view on the entire module.\n\nThe following will assist you to gasp what the module can do for you before you install it.\nIf you are not famillier with TypeScript you can go a head and jump to the exampels.\n```ts\n    class WindowBucket\u003cT\u003e{\n        constructor(public bucketValue : T);\n    }\n    class SingleValue\u003cT\u003e{\n        constructor(public value : T);\n    }\n    interface TimeWindowCoreOptions\u003cT\u003e{\n        timeWindow : number,\n        bucketsFrequancy : number,\n        defaultValueFactory : defaultValueFactory\u003cT\u003e,\n        onRemoved : onRemoved\u003cBucketValue\u003cT\u003e\u003e;\n    }\n    interface TimeWindowCounterOptions extends TimeWindowCoreOptions\u003cnumber\u003e{\n        defaultNumber : number\n    }\n    type defaultValueFactory\u003cT\u003e = ()=\u003eT;\n    type onRemoved\u003cT\u003e = ()=\u003eT;\n    type iterationSyncCallback\u003cT\u003e = (windowBucket:WindowBucket\u003cT\u003e,i:number)=\u003evoid;\n    type iterationAsyncCallback\u003cT\u003e = (windowBucket:WindowBucket\u003cT\u003e, i:number , next : ()=\u003evoid)=\u003evoid;\n    interface WindowCoreOptions\u003cT\u003e{\n        bucketsCount : number;\n        defaultValueFactory : defaultValueFactory\u003cT\u003e;\n        onRemoved :onRemoved\u003cBucketValue\u003cT\u003e\u003e;\n        preFillWindow : boolean;\n    }\n    class WindowCore\u003cT\u003e{\n        bucketsCount:number;\n        defaultValueFactory:defaultValueFactory\u003cT\u003e;\n        onRemoved:onRemoved\u003cBucketValue\u003cT\u003e\u003e;\n\n        constructor(\n            options : WindowCoreOptions\u003cT\u003e\n        );\n        \n        tick():void;\n        getLastBucket():WindowBucket\u003cT\u003e;\n        iterate(iterationCallback:iterationSyncCallback\u003cT\u003e);\n        asyncIterate(iterationCallback : iterationAsyncCallback\u003cT\u003e , done : (total:number)=\u003evoid);\n        setPublicOn(instance : any):void;\n    }\n    class TimeWindowCore\u003cT\u003e extends WindowCore\u003cTimePoint\u003e{\n        constructor(options : TimeWindowCoreOptions\u003cT\u003e);\n        contatiner:WindowCore\u003cT\u003e;\n        start():void;\n        pause():void;\n    }\n    class WindowSingleCounter extends TimeWindowCore\u003cSingleValue\u003cnumber\u003e\u003e{\n        constructor(options : TimeWindowCounterOptions);\n        contatiner:TimeWindowCore\u003cnumber\u003e;\n        increase():number;\n        decrease():number;\n        increaseBy(by:number):number;\n        decreaseBy(by:number):number;\n        toArray():number[];\n    }\n    class WindowSingleStackedCounter extends WindowSingleCounter{\n\n    }\n    class TimePoint {\n        at:number;\n        value:number;\n    }\n    class TimeBasedWindowCounter extends WindowSingleCounter{\n        toDateArray():WindowBucket\u003cnumber\u003e[]\n    }\n    class MultiValue{\n        [key:string]:number|any;\n    }\n    class WindowMultipleCounters extends TimeWindowCore\u003cTimePoint\u003cMultiValue\u003e\u003e{\n        toArray():MultiValue[];\n        contatiner:TimeWindowCore\u003cMultiValue\u003e;\n        increase(key:string):number;\n        decrease(key:string):number;\n        increaseBy(key:string,by:number):number;\n        decreaseBy(key:string,by:number):number;\n    }\n    class TimeBasedWindowMultipleCounters extends WindowMultipleCounters{\n        toDateArray():WindowBucket\u003cTimePoint\u003cMultiValue\u003e\u003e[]\n        increase(key:string):number;\n        decrease(key:string):number;\n        increaseBy(key:string,by:number):number;\n        decreaseBy(key:string,by:number):number;\n    }\n    class GenericTimeBaseStore extends TimeBasedWindowMultipleCounters{\n        setInLast\u003cT\u003e(key:string , value:number);\n        getFromLast\u003cT\u003e(key:string ):number;\n    }\n```\n\n##Examples\n\n###Simple use of multiple counters\n```js\nconst {TimeBasedWindowMultipleCounters} = require('rolling-windows');\n\nconst rollingTimeCounters = new TimeBasedWindowMultipleCounters({\n    timeWindow : 1000*60, //I want to have information up to 1 minute\n    bucketsFrequancy : 1000*10,//I want to have bucket every 10 seconds\n});\n//Start the internal\nrollingTimeCounters.start();\n\n//You can count any event\nrollingTimeCounters.increaseBy(\"eventName\" , 50);\n\n//You can iterate over your bucket\nrollingTimeCounters.iterateValues((timePoint)=\u003e{\n    //This is the bucket value in our case it's a TimePoint    \n    console.log(`At ${timePoint.date} the count was ${timePoint.value.eventName} `);\n})\n```\n\n#Simple use of single counter\n```js\nconst {WindowSingleCounter} = require('rolling-windows');\n\nconst counter = new WindowSingleCounter({\n    timeWindow : 1000*60*60, //I want to have information up tp an hour\n    bucketsFrequancy : 1000*20,//I want to have bucket per 20 seconds\n});\n//increase\ncounter.increase();\n\n\n//I can iterate over your bucket and calculate total\nlet total = 0;\ncounter.iterateValues((singleValue)=\u003e{  \n    total+= singleValue.value;\n});\nconsole.log(total);\n\ncounter.start();\n```\n\nSome cool examples of what you can do with these rolling windows.\n\n###Count the status code of your http server\n```js\nconst {TimeBasedWindowMultipleCounters} = require('rolling-windows');\n\nconst rollingTimeCounters = new TimeBasedWindowMultipleCounters({\n    timeWindow : 1000*20, //I want to have information up to 20 seconds\n    bucketsFrequancy : 1000*2,//I want to have bucket per 2 seconds\n});\nrollingTimeCounters.start();\n\nconst server = require('http').createServer((req, res) =\u003e {\n    if (req.url == '/info'){\n        res.setHeader('Content-Type', 'application/json');\n\n        \n        const results = {\n            aggregated : {\n                '500' : 0,\n                '200' : 0\n            },\n            rawBucketsData : [],\n            dateArray : rollingTimeCounters.toDateArray()\n        }\n        rollingTimeCounters.iterateValues((multiValue)=\u003e{\n            const values = multiValue.value;\n            results.rawBucketsData.push(values);\n            if (values[\"200\"])\n                results.aggregated[\"200\"]+= values[\"200\"];\n            if (values[\"500\"])\n                results.aggregated[\"500\"]+= values[\"500\"];\n        });\n        res.writeHead(200);\n        res.end(JSON.stringify(results));\n    }\n    else if (req.url == '/'){\n        res.setHeader('Content-Type', 'text/palin');\n        let isError = Math.floor(Math.random()*2) === 1;\n        if (isError){\n            rollingTimeCounters.increase(500);\n            res.writeHead(500);\n            res.end('I\\'m going to report that you just had an error');\n        }\n        else{\n            rollingTimeCounters.increase(200);\n            res.writeHead(200);\n            res.end('ok');\n        }\n    }\n    else{\n        res.writeHead(404);\n        res.end(`Please use only the \"/\" or \"/info\" pages`)\n    }\n  }).listen(3030);\n```\n###Rate limit your client http requests per client account\n\nIn the following example I want to:\n   * Limit account to 1K requests an hour.\n   * Notify the client on the quata left at any given request.\n\n```js\nconst REQUEST_LIMIT_PER_HOUR = 1000;\nconst {TimeBasedWindowMultipleCounters} = require('rolling-windows');\nconst querystring = require('querystring');\n\nconst rollingTimeCounters = new TimeBasedWindowMultipleCounters({\n    timeWindow : 1000*60*60, //I want to have information up to 1 hour\n    bucketsFrequancy : 1000*2,//I want to have bucket every 1 minute\n});\n//Start the internal interval\nrollingTimeCounters.start();\n\nfunction verifyRateLimitAndSetHeaders(clientAccount , res ){\n    let shouldBlock = false;\n    //If the account already passed the limit we need to block it\n    let requestsThisHour = 0;\n    //Find requests count of the last hour - the full window\n    rollingTimeCounters.iterateValues((singleValue)=\u003e{\n        const multiValues = singleValue.value;\n        const counter = multiValues[clientAccount];\n        if (typeof counter == 'number')\n            requestsThisHour+=counter;\n    });\n    if (shouldBlock){\n        return false;\n    }\n    else {\n        //Request passed - count it\n        rollingTimeCounters.increase(clientAccount);\n        //Sending rate limits information to the client\n        res.setHeader('X-RateLimit-Reset' , rollingTimeCounters.getTimeToNextTick());\n        res.setHeader('X-RateLimit-Remaining' , REQUEST_LIMIT_PER_HOUR - requestsThisHour-1 );\n        res.setHeader('X-RateLimit-Limit' , REQUEST_LIMIT_PER_HOUR);\n        return true;\n    }\n    \n    //Find if this account passed one of the limits\n}\nrequire('http').createServer((req, res) =\u003e {\n    if (/^\\/\\??/.test(req.url)){\n        req.query = querystring.parse(req.url.replace(/^\\/\\??/ , ''));\n        const clientAccount = req.query.clientAccount;\n        if (clientAccount){\n            res.setHeader('Content-Type', 'text/json');\n            const canPass = verifyRateLimitAndSetHeaders(clientAccount , res);\n            if (canPass){\n                //Request is within account limits\n                res.writeHead(200);\n                res.end(`{\"status\" : \"Passed\"}`);\n            }\n            else {\n                //Request blocked\n                res.writeHead(429);\n                res.end(`{\"status\" : \"Blocked\"}`);\n            }\n        }\n       else{\n            res.writeHead(401);\n            res.end(`Please send \\`clientAccount\\` in query string to use this API `)\n       }\n    }\n    else{\n        res.writeHead(404);\n        res.end(`Please use only the root \"/\" `)\n    }\n  }).listen(3030);\n```\n\n## License\n\n  [MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/rolling-windows.svg\n[npm-url]: https://npmjs.org/package/rolling-windows\n[travis-image]: https://img.shields.io/travis/hisco/rolling-windows/master.svg?style=flat-square\n[travis-url]: https://travis-ci.org/hisco/rolling-windows\n[coveralls-image]: https://coveralls.io/repos/github/hisco/rolling-windows/badge.svg?branch=master\n[coveralls-url]: https://coveralls.io/github/hisco/rolling-windows?branch=master\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhisco%2Frolling-windows","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhisco%2Frolling-windows","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhisco%2Frolling-windows/lists"}