{"id":44467590,"url":"https://github.com/tyler-g/purrrf","last_synced_at":"2026-02-12T20:22:05.600Z","repository":{"id":65371555,"uuid":"82312265","full_name":"tyler-g/purrrf","owner":"tyler-g","description":"get a grip on your js purrrformance","archived":false,"fork":false,"pushed_at":"2017-02-24T00:31:19.000Z","size":514,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-07T07:59:28.364Z","etag":null,"topics":["execution","performance","time","timing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tyler-g.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":"2017-02-17T15:48:31.000Z","updated_at":"2024-08-31T19:41:38.000Z","dependencies_parsed_at":"2023-01-19T22:45:18.537Z","dependency_job_id":null,"html_url":"https://github.com/tyler-g/purrrf","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/tyler-g/purrrf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tyler-g%2Fpurrrf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tyler-g%2Fpurrrf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tyler-g%2Fpurrrf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tyler-g%2Fpurrrf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tyler-g","download_url":"https://codeload.github.com/tyler-g/purrrf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tyler-g%2Fpurrrf/sbom","scorecard":{"id":904806,"data":{"date":"2025-08-11","repo":{"name":"github.com/tyler-g/purrrf","commit":"38d352c942f72945a52942e1eaeb2d86a65e4b9a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"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/24 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":"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":"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":"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":"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: ISC 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":"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":"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 7 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"}}]},"last_synced_at":"2025-08-24T16:57:45.456Z","repository_id":65371555,"created_at":"2025-08-24T16:57:45.456Z","updated_at":"2025-08-24T16:57:45.456Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29380601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T19:05:20.189Z","status":"ssl_error","status_checked_at":"2026-02-12T19:01:44.216Z","response_time":55,"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":["execution","performance","time","timing"],"created_at":"2026-02-12T20:22:04.852Z","updated_at":"2026-02-12T20:22:05.595Z","avatar_url":"https://github.com/tyler-g.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# purrrf\n\n![Build Status](https://img.shields.io/travis/tyler-g/purrrf.svg)\n[![codecov](https://codecov.io/gh/tyler-g/purrrf/branch/master/graph/badge.svg)](https://codecov.io/gh/tyler-g/purrrf)\n![Downloads](https://img.shields.io/npm/dm/purrrf.svg)\n![Downloads](https://img.shields.io/npm/dt/purrrf.svg)\n![npm version](https://img.shields.io/npm/v/purrrf.svg)\n![dependencies](https://img.shields.io/david/tyler-g/purrrf.svg)\n![dev dependencies](https://img.shields.io/david/dev/tyler-g/purrrf.svg)\n![License](https://img.shields.io/npm/l/purrrf.svg)\n\na lightweight utility for measuring accurate performance timings in the browser or in nodejs. \n\n*2.5KB gzipped!*\n\n\u003cimg src=\"https://github.com/tyler-g/purrrf/blob/master/jimmy.jpg?raw=true\" width=\"420\" alt=\"jimmy\" /\u003e\n\n## Getting Started\n\nInstall it via npm:\n\n```shell\nnpm install purrrf\n```\n\nAnd include in your project:\n\n#### Node\n```javascript\nvar purrrf = require('purrrf'); // nodejs, requirejs, or any framework that supports require\n```\n#### Browser\n*purrrf.js* and *purrrf-min.js* are included in the browser folder of every release\n(for browser projects not using any framework supporting require)\n```html\n\u003cscript src=\"purrrf.js\"\u003e\u003c/script\u003e\n```\n```javascript\nvar purrrf = window._purrrf;\n```\n\n## Usage\n\n#### Setting the Reference Point\n```javascript\n\n// set the reference point for all future times\n// it is a good habit to call this as early as possible, so its clear where your start reference time is in the code\npurrrf.setStart();\n15.2 // returns time in ms as the new reference start\n\n```\n*Note: Setting the reference point is not required, but it is a good way to ensure you know where your reference is. If it is not set, your reference point will be 0, which depends on the context. In node, 0 is the point at which your process has started. In the browser, 0 is the point at which the page is requested to be loaded.*\n\n#### Pushing Time Events\n```javascript\n\n// push an event to the master list\npurrrf.push('someEventName'); \n78.55 // returns time in ms from reference start at which event occurred\n\n```\n\n#### Pushing Time Events Using Groups\n```javascript\n\n// push an event to the master list with a group name. \n// If the group name was used on a previous event, it will return the time difference in ms between the this event and the most recent event with the same group name\npurrrf.push('someEventNameStart', 'groupTask');\n100.52\n\n/* do other stuff that takes 50ms */\n\npurrrf.push('someEventNameEnd', 'groupTask'); \n50 // returns the time difference in ms between 'someEventNameEnd' and 'someEventNameStart'\n\n// note if you had not passed the 'groupTask' parameter above, it would return the time of that event, eg:\npurrrf.push('someEventNameEnd');\n150.52 // because no group parameter is specified, it returns the time in ms from reference start\n```\n\n#### Get Times from Pushed Events\n```javascript\n\n// get the time in ms from reference start for any event\npurrrf.getTime('someEventName'); \n78.55 // returns time in ms from reference start at which event occurred\n\npurrrf.getTime('someEventNameThatDoesNotExist');\nfalse // returns false\n\n```\n\n#### Get Time Difference between any Two Events\n```javascript\n\n// you can also at any time get the time difference between any two known events\n// The second parameter is the reference point. Thus if first event occurred before the second, a negative value will be returned\npurrrf.getTimeDiff('someEventNameEnd', 'someEventNameStart');\n50 // returns the time difference in ms between 'someEventNameEnd' and 'someEventNameStart'\n\n```\n\n#### Automatically Push Time Events from Event Listeners\nIn case your project already has events that fire at significant times in which you would like to track, you can bind to those events and automatically push Time Events to purrrf.\n\n```javascript\n\n// You must first set the context on which to listen for events\npurrrf.setContext(document); // browser\n/* or */\npurrrf.setContext(myEventEmitter); // node (where eventEmitter is an instance of EventEmitter)\n\n```\n```javascript\n\n// every time 'eventToListenForOnTheContext' event fires, 'eventToPushToPurrrfWhenThatHappens' will get pushed to purrrf\npurrrf.bind('eventToListenForOnTheContext', 'eventToPushToPurrrfWhenThatHappens', 'optionalGroupName');\n\n// binding returns a Promise which resolves when the event being listened for is fired\npurrrf.bind('eventToListenForOnTheContext', 'eventToPushToPurrrfWhenThatHappens', 'optionalGroupName').then(function(result) {\n    // result is the time returned from pushing event `eventToPushToPurrrfWhenThatHappens`\n    console.log('eventToPushToPurrrfWhenThatHappens was pushed to purrrf after x ms from reference start', result);\n    // this follows the same rules as what returns from purrrf.push (see above). \n    // If an group name was passed, and a Time Event with that group name has previously been pushed, \n    // then result will be the time difference in ms between those two Time Events\n});\n\n```\n\n#### Get the master list (generally not needed)\n```javascript\n\n// you can pull the event map at any time which contains all collected data on every event pushed to the master list\npurrrf.getMap(); // returns object map. The keys of this object are event names. Thus note if you pushed the same event name to the master list, the latter will override the former.\n\n// if you'd rather get an ordered event list...\npurrrf.getMap({ ordered: true }); // returns an array (not an object!) which contains the pushed events in the order in which they were received\n\n```\n*Note: The times in the master map are always absolute times.  This means that regardless of if or when you called `.setStart()` these times in the map will not be relative to that point.  However there is a special key `_config` returned in the map which contains the offset.  The offset is 0 by default, but if `.setStart()` was called, offset will contain the time at which it was called.  Thus it can be used to calculate relative times.  If you retrieve the map as an ordered array (using `purrrf.getMap({ ordered: true })`) note there is no special `_config` key, as doing so would pollute the array.*\n\n## License\n\nISC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftyler-g%2Fpurrrf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftyler-g%2Fpurrrf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftyler-g%2Fpurrrf/lists"}