{"id":15103040,"url":"https://github.com/meteor-community-packages/meteor-user-status","last_synced_at":"2025-12-17T14:16:48.081Z","repository":{"id":41826716,"uuid":"10854196","full_name":"Meteor-Community-Packages/meteor-user-status","owner":"Meteor-Community-Packages","description":"Track user connection state and inactivity in Meteor.","archived":false,"fork":false,"pushed_at":"2025-02-19T13:00:20.000Z","size":611,"stargazers_count":557,"open_issues_count":32,"forks_count":85,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-05-29T11:35:49.000Z","etag":null,"topics":["hacktoberfest","meteor"],"latest_commit_sha":null,"homepage":"","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/Meteor-Community-Packages.png","metadata":{"files":{"readme":"README.md","changelog":"History.md","contributing":"Contributing.md","funding":null,"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},"funding":{"github":["storytellercz","jankapunkt"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2013-06-21T22:36:42.000Z","updated_at":"2025-03-17T20:36:13.000Z","dependencies_parsed_at":"2023-01-31T18:30:32.499Z","dependency_job_id":"b102a808-796b-445f-bf24-b6699c962351","html_url":"https://github.com/Meteor-Community-Packages/meteor-user-status","commit_stats":{"total_commits":188,"total_committers":22,"mean_commits":8.545454545454545,"dds":0.574468085106383,"last_synced_commit":"8cb45620af218d042e99846393ae3e5a0b973b33"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/Meteor-Community-Packages/meteor-user-status","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-user-status","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-user-status/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-user-status/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-user-status/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Meteor-Community-Packages","download_url":"https://codeload.github.com/Meteor-Community-Packages/meteor-user-status/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-user-status/sbom","scorecard":{"id":93072,"data":{"date":"2025-08-11","repo":{"name":"github.com/Meteor-Community-Packages/meteor-user-status","commit":"8cb45620af218d042e99846393ae3e5a0b973b33"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.7,"checks":[{"name":"Code-Review","score":3,"reason":"Found 2/6 approved changesets -- score normalized to 3","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":"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":"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":"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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:28","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:29","Warn: no topLevel permission defined: .github/workflows/codeql.yml:1","Warn: no topLevel permission defined: .github/workflows/comment-issue.yml:1","Warn: no topLevel permission defined: .github/workflows/lint.yml:1","Warn: no topLevel permission defined: .github/workflows/testsuite.yml:1","Info: no jobLevel write permissions found"],"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":"Pinned-Dependencies","score":1,"reason":"dependency not pinned by hash detected -- score normalized to 1","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/codeql.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql.yml:74: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/codeql.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/comment-issue.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/comment-issue.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/lint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/lint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/lint.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/lint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/testsuite.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/testsuite.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/testsuite.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/Meteor-Community-Packages/meteor-user-status/testsuite.yml/master?enable=pin","Warn: downloadThenRun not pinned by hash: .github/workflows/testsuite.yml:30","Warn: npmCommand not pinned by hash: .github/workflows/testsuite.yml:31","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   1 out of   2 npmCommand dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned"],"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":"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: 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":"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":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"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":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/Meteor-Community-Packages/.github/SECURITY.md:1","Info: Found linked content: github.com/Meteor-Community-Packages/.github/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/Meteor-Community-Packages/.github/SECURITY.md:1","Info: Found text in security policy: github.com/Meteor-Community-Packages/.github/SECURITY.md:1"],"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":"SAST","score":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 0 commits out of 26 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":4,"reason":"6 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5"],"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-15T08:16:47.032Z","repository_id":41826716,"created_at":"2025-08-15T08:16:47.032Z","updated_at":"2025-08-15T08:16:47.032Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27783730,"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-12-17T02:00:08.291Z","response_time":55,"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":["hacktoberfest","meteor"],"created_at":"2024-09-25T19:20:21.014Z","updated_at":"2025-12-17T14:16:48.055Z","avatar_url":"https://github.com/Meteor-Community-Packages.png","language":"JavaScript","funding_links":["https://github.com/sponsors/storytellercz","https://github.com/sponsors/jankapunkt"],"categories":[],"sub_categories":[],"readme":"user-status\n===========\n\n## What's this do?\n\nKeeps track of user connection data, such as IP addresses, user agents, and\nclient-side activity, and tracks this information in `Meteor.users` as well as\nsome other objects. This allows you to easily see users that are online, for\napplications such as rendering the users box below showing online users in green\nand idle users in orange.\n\n![User online states](https://raw.github.com/Meteor-Community-Packages/meteor-user-status/master/docs/example.png)\n\nFor a complete example of what can be tracked, including inactivity, IP\naddresses, and user agents, check out a demo app at\nhttp://user-status.meteor.com, or its\n[source](https://github.com/Meteor-Community-Packages/meteor-user-status/tree/master/demo).\n\n## Install\n\nInstall using Meteor:\n\n```sh\n$ meteor add mizzao:user-status\n```\n\nAdditionally, note that to read client IP addresses properly, you must set the\n`HTTP_FORWARDED_COUNT` environment variable for your app, and make sure that IP\naddress headers are forwarded for any reverse proxy installed in front of the\napp. See the [Meteor docs on this](http://docs.meteor.com/#meteor_onconnection)\nfor more details.\n\n## Basic Usage - Online State\n\nThis package maintains two types of status: a general user online flag in `Meteor.users`, and some additional data for each session. It uses [timesync](https://github.com/Meteor-Community-Packages/meteor-timesync) to maintain the server's time across all clients, regardless of whether they have the correct time.\n\n`Meteor.users` receives a `status` field will be updated automatically if the user logs in or logs out, closes their browser, or otherwise disconnects. A user is online if at least one connection with that `userId` is logged in. It contains the following fields:\n\n- `online`: `true` if there is at least one connection online for this user\n- `lastLogin`: information about the most recent login of the user, with the fields `date`, `ipAddr`, and `userAgent`.\n- `idle`: `true` if all connections for this user are idle. Requires idle tracking to be turned on for all connections, as below.\n- `lastActivity`: if the user was idle, the last time an action was observed. This field is only available when the user is online and idle. It does not maintain the user's last activity in real time or a stored value indefinitely - `lastLogin` is a coarse approximation to that. For more information, see https://github.com/Meteor-Community-Packages/meteor-user-status/issues/80.\n\nTo make this available on the client, use a reactive cursor, such as by creating a publication on the server:\n\n```javascript\nMeteor.publish(\"userStatus\", function() {\n  return Meteor.users.find({ \"status.online\": true }, { fields: { ... } });\n});\n```\n\nor you can use this to do certain actions when users go online and offline.\n\n```javascript\nMeteor.users.find({ \"status.online\": true }).observe({\n  added: function(id) {\n    // id just came online\n  },\n  removed: function(id) {\n    // id just went offline\n  }\n});\n```\n\nYou can use a reactive cursor to select online users in a client-side template helper:\n\n```javascript\nTemplate.foo.usersOnline = function() {\n  return Meteor.users.find({ \"status.online\": true })\n};\n```\n\nMaking this directly available on the client allows for useful template renderings of user state. For example, with something like the following you get the picture above (using bootstrap classes).\n\n```\n\u003ctemplate name=\"userPill\"\u003e\n    \u003cspan class=\"label {{labelClass}}\"\u003e{{username}}\u003c/span\u003e\n\u003c/template\u003e\n```\n\n```javascript\nTemplate.userPill.labelClass = function() {\n  if (this.status.idle)\n    return \"label-warning\"\n  else if (this.status.online)\n    return \"label-success\"\n  else\n    return \"label-default\"\n};\n```\n\n## Advanced Usage and Idle Tracking\n\n### Client API\n\nOn the client, the `UserStatus` object provides for seamless automatic monitoring of a client's idle state. By default, it will listen for all clicks and keypresses in `window` as signals of a user's action. It has the following functions:\n\n- `startMonitor`: a function taking an object with fields `threshold` (the amount of time before a user is counted as idle), `interval` (how often to check if a client has gone idle), and `idleOnBlur` (whether to count a window blur as a user going idle.) This function enables idle tracking on the client.\n- `stopMonitor`: stops the running monitor.\n- `pingMonitor`: if the automatic event handlers aren't catching what you need, you can manually ping the monitor to signal that a user is doing something and reset the idle monitor.\n- `isIdle`: a reactive variable signifying whether the user is currently idle or not.\n- `isMonitoring`: a reactive variable for whether the monitor is running.\n- `lastActivity`: a reactive variable for the last action recorded by the user (according to [server time](https://github.com/Meteor-Community-Packages/meteor-timesync)). Since this variable will be invalidated a lot and cause many recomputations, it's best only used for debugging or diagnostics (as in the demo).\n\nFor an example of how the above functions are used, see the demo.\n\n### Server API\n\nThe `UserStatus.connections` (in-memory) collection contains information for all connections on the server, in the following fields:\n\n- `_id`: the connection id.\n- `userId`: the user id, if the connection is authenticated.\n- `ipAddr`: the remote address of the connection. A user logged in from different places will have one document per connection.\n- `userAgent`: the user agent of the connection.\n- `loginTime`: if authenticated, when the user logged in with this connection.\n- `idle`: `true` if idle monitoring is enabled on this connection and the client has gone idle.\n\n#### startupQuerySelector (Optional)\n\nOn startup `meteor-user-status` automatically resets all users to `offline` and then marks each `online` as connections are reestablished. \n\nTo customize this functionality you can use the `startupQuerySelector` [Meteor package option](https://docs.meteor.com/api/packagejs.html#options) like this:\n```javascript\n  \"packages\": {\n    \"mizzao:user-status\": {\n      \"startupQuerySelector\": { \"$or\": [{ \"status.online\": true }, { \"status.idle\": { \"$exists\": true } }, { \"status.lastActivity\": { \"$exists\": true } }] }\n    }\n  }\n```\nThe above example reduces server/database load during startup if you have a large number of users.\n\n#### Usage with collection2\n\nIf your project is using `aldeed:collection2` with a schema attached to `Meteor.users`, you need to add the following items to the schema to allow modifications of the status:\n\n```javascript\nimport SimpleSchema from 'simpl-schema';\n\nconst userSchema = new SimpleSchema({\n    status: {\n        type: Object,\n        optional: true,\n    },\n    'status.lastLogin': {\n        type: Object,\n        optional: true,\n    },\n    'status.lastLogin.date': {\n        type: Date,\n        optional: true,\n    },\n    'status.lastLogin.ipAddr': {\n        type: String,\n        optional: true,\n    },\n    'status.lastLogin.userAgent': {\n        type: String,\n        optional: true,\n    },\n    'status.idle': {\n        type: Boolean,\n        optional: true,\n    },\n    'status.lastActivity': {\n        type: Date,\n        optional: true,\n    },\n    'status.online': {\n        type: Boolean,\n        optional: true,\n    },\n});\n\n// attaching the Schema to Meteor.users will extend it\nMeteor.users.attachSchema(userSchema);\n\n```\n\n#### Events\n\nThe `UserStatus.events` object is an `EventEmitter` on which you can listen for connections logging in and out. Logging out includes closing the browser; reopening the browser will trigger a new login event. The following events are supported:\n\n#### `UserStatus.events.on(\"connectionLogin\", function(fields) { ... })`\n\n`fields` contains `userId`, `connectionId`, `ipAddr`, `userAgent`, and `loginTime`.\n\n#### `UserStatus.events.on(\"connectionLogout\", function(fields) { ... })`\n\n`fields` contains `userId`, `connectionId`, `lastActivity`, and `logoutTime`.\n\n#### `UserStatus.events.on(\"connectionIdle\", function(fields) { ... })`\n\n`fields` contains `userId`, `connectionId`, and `lastActivity`.\n\n#### `UserStatus.events.on(\"connectionActive\", function(fields) { ... })`\n\n`fields` contains `userId`, `connectionId`, and `lastActivity`.\n\nCheck out https://github.com/mizzao/meteor-accounts-testing for a simple accounts drop-in that you can use to test your app - this is also used in the demo.\n\n#### Startup selector\nBy default, the startup selector for resetting user status is `{}`.\nIf you want to change that you can set the default selector in your settings.json file:\n\n```json\n{\n  \"packages\": {\n    \"mizzao:user-status\": {\n      \"startupQuerySelector\": {\n        // your selector here, for example:\n        \"profile.name\": \"admin\"\n      }\n    }\n  }\n}\n```\n\n## Testing\n\nThere are some `Tinytest` unit tests that are used to test the logic in this package, but general testing with many users and connections is hard. Hence, we have set up a demo app (http://user-status.meteor.com) for testing that is also hosted as a proof of concept. If you think you've found a bug in the package, try to replicate it on the demo app and post an issue with steps to reproduce.\n\n## Contributing\n\nSee [Contributing.md](Contributing.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeteor-community-packages%2Fmeteor-user-status","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeteor-community-packages%2Fmeteor-user-status","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeteor-community-packages%2Fmeteor-user-status/lists"}