{"id":15501832,"url":"https://github.com/gadicc/discourse2","last_synced_at":"2026-02-25T12:09:22.287Z","repository":{"id":188065591,"uuid":"678055172","full_name":"gadicc/discourse2","owner":"gadicc","description":"Complete Discourse API, strongly typed","archived":false,"fork":false,"pushed_at":"2025-01-28T00:34:12.000Z","size":946,"stargazers_count":8,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-06-11T02:20:00.245Z","etag":null,"topics":["discourse","discourse-api","discourse-forum"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/discourse2","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/gadicc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2023-08-13T14:39:26.000Z","updated_at":"2025-06-08T12:34:45.000Z","dependencies_parsed_at":"2024-10-02T09:06:03.354Z","dependency_job_id":"1cad6e10-2df2-433f-b2f5-865485c56e4c","html_url":"https://github.com/gadicc/discourse2","commit_stats":null,"previous_names":["gadicc/discourse2"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/gadicc/discourse2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gadicc%2Fdiscourse2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gadicc%2Fdiscourse2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gadicc%2Fdiscourse2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gadicc%2Fdiscourse2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gadicc","download_url":"https://codeload.github.com/gadicc/discourse2/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gadicc%2Fdiscourse2/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263445777,"owners_count":23467612,"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","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":["discourse","discourse-api","discourse-forum"],"created_at":"2024-10-02T09:05:59.948Z","updated_at":"2025-10-20T10:46:29.346Z","avatar_url":"https://github.com/gadicc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# discourse2\n\nThe complete Discourse API (strongly typed), always up-to-date.\n\nCopyright (c) 2023 by Gadi Cohen. [MIT Licensed](./LICENSE.txt).\n\n[![NPM Version](https://img.shields.io/npm/v/discourse2?logo=npm)](https://www.npmjs.com/package/discourse2)\n[![JSR](https://jsr.io/badges/@gadicc/discourse2)](https://jsr.io/@gadicc/discourse2)\n[![JSR Score](https://jsr.io/badges/@gadicc/discourse2/score)](https://jsr.io/@gadicc/discourse2)\n![DiscourseAPI Retrieval Date](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fgadicc%2Fdiscourse2%2Frefs%2Fheads%2Fmain%2Fsrc%2Fopenapi-meta.json\u0026query=%24.retrievedAtDate\u0026label=Discourse%20API)\n![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/gadicc/discourse2/release.yml)\n![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/gadicc/db6d371d39faab64858178a049c8e80b/raw/discourse2-lcov-coverage.json)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n\n\u003cimg src=\"./assets/discourse-completion.png\" alt=\"discourse completion\" width=\"700\"/\u003e\n\u003cimg src=\"./assets/discourse-getTopic-type.png\" alt=\"discourse getTopic type\" width=\"500\"/\u003e\n\n[Live Demo on CodeSandbox](https://codesandbox.io/p/sandbox/discourse2-dht4ym).\n\n## Features\n\n- The _entire_ Discourse API (that’s published in the OpenAPI spec).\n- _Always up-to-date_: the OpenAPI spec is checked for changes daily, and the\n  package will automatically rebuild and publish itself on changes. The most\n  recent retrieval is shown as a badge at the top of the README:\n  ![DiscourseAPI Retrieval Date](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fgadicc%2Fdiscourse2%2Frefs%2Fheads%2Fmain%2Fsrc%2Fopenapi-meta.json\u0026query=%24.retrievedAtDate\u0026label=Discourse%20API)\n- Works in both server and browser* environments (*useful for querying public\n  data _without_ API keys and on relevant origin, e.g. latest topics, etc)\n\n## Quick Start\n\n```ts\nimport Discourse from \"discourse2\";\n\nconst discourse = new Discourse(\"https://forums.kiri.art\", {\n  \"Api-Key\": process.env.DISCOURSE_API_KEY,\n  \"Api-Username\": process.env.DISCOURSE_API_USERNAME,\n});\n\nconst result = await discourse.listLatestTopics();\nconsole.log(result);\n```\n\n## APIs\n\nWe check for changes to the Discourse OpenAPI schema twice daily (at 00:20 and\n12:20 UTC). You can see the most recent update on the \"Discourse API\" badge at\nthe top of this README. After such an update, we'll re-build the package, and if\nall tests pass, automatically publish a new release. The build status and latest\nversion can also be found in badges above.\n\nSince the API is updated automatically, **the following list may not include all\nAPIs available in the package**, however, at time of writing (2024-09-29), the\nfollowing APIs were supported: (link is to official docs, in same order).\n\n- **Backups**:\n  [getBackups](https://docs.discourse.org/#tag/Backups/operation/getBackups),\n  [createBackup](https://docs.discourse.org/#tag/Backups/operation/createBackup),\n  [sendDownloadBackupEmail](https://docs.discourse.org/#tag/Backups/operation/sendDownloadBackupEmail),\n  [downloadBackup](https://docs.discourse.org/#tag/Backups/operation/downloadBackup).\n- **Badges**:\n  [adminListBadges](https://docs.discourse.org/#tag/Badges/operation/adminListBadges),\n  [createBadge](https://docs.discourse.org/#tag/Badges/operation/createBadge),\n  [updateBadge](https://docs.discourse.org/#tag/Badges/operation/updateBadge),\n  [deleteBadge](https://docs.discourse.org/#tag/Badges/operation/deleteBadge).\n- **Categories**:\n  [createCategory](https://docs.discourse.org/#tag/Categories/operation/createCategory),\n  [listCategories](https://docs.discourse.org/#tag/Categories/operation/listCategories),\n  [updateCategory](https://docs.discourse.org/#tag/Categories/operation/updateCategory),\n  [listCategoryTopics](https://docs.discourse.org/#tag/Categories/operation/listCategoryTopics),\n  [getCategory](https://docs.discourse.org/#tag/Categories/operation/getCategory).\n- **Groups**:\n  [createGroup](https://docs.discourse.org/#tag/Groups/operation/createGroup)\n  [deleteGroup](https://docs.discourse.org/#tag/Groups/operation/deleteGroup)\n  [updateGroup](https://docs.discourse.org/#tag/Groups/operation/updateGroup)\n  [getGroup](https://docs.discourse.org/#tag/Groups/operation/getGroup)\n  [listGroupMembers](https://docs.discourse.org/#tag/Groups/operation/listGroupMembers)\n  [addGroupMembers](https://docs.discourse.org/#tag/Groups/operation/addGroupMembers)\n  [removeGroupMembers](https://docs.discourse.org/#tag/Groups/operation/removeGroupMembers)\n  [listGroups](https://docs.discourse.org/#tag/Users/Groups/listGroups)\n- **Invites**:\n  [createInvite](https://docs.discourse.org/#tag/Invites/operation/createInvite),\n  [createMultipleInvites](https://docs.discourse.org/#tag/Invites/operation/createMultipleInvites).\n- **Notifications**:\n  [getNotifications](https://docs.discourse.org/#tag/Notifications/operation/getNotifications),\n  [markNotificationsAsRead](https://docs.discourse.org/#tag/Notifications/operation/markNotificationsAsRead).\n- **Posts**:\n  [listPosts](https://docs.discourse.org/#tag/Posts/operation/listPosts),\n  [getPost](https://docs.discourse.org/#tag/Posts/operation/getPost),\n  [updatePost](https://docs.discourse.org/#tag/Posts/operation/updatePost),\n  [deletePost](https://docs.discourse.org/#tag/Posts/operation/deletePost),\n  [postReplies](https://docs.discourse.org/#tag/Posts/operation/postReplies),\n  [lockPost](https://docs.discourse.org/#tag/Posts/operation/lockPost),\n  [performPostAction](https://docs.discourse.org/#tag/Posts/operation/performPostAction).\n- **Topics**:\n  [getSpecificPostsFromTopic](https://docs.discourse.org/#tag/Topics/operation/getSpecificPostsFromTopic),\n  [getTopic](https://docs.discourse.org/#tag/Topics/operation/getTopic),\n  [removeTopic](https://docs.discourse.org/#tag/Topics/operation/removeTopic),\n  [updateTopic](https://docs.discourse.org/#tag/Topics/operation/updateTopic),\n  [inviteToTopic](https://docs.discourse.org/#tag/Topics/operation/inviteToTopic),\n  [bookmarkTopic](https://docs.discourse.org/#tag/Topics/operation/bookmarkTopic),\n  [updateTopicStatus](https://docs.discourse.org/#tag/Topics/operation/updateTopicStatus),\n  [listLatestTopics](https://docs.discourse.org/#tag/Topics/operation/listLatestTopics),\n  [listTopTopics](https://docs.discourse.org/#tag/Topics/operation/listTopTopics),\n  [setNotificationLevel](https://docs.discourse.org/#tag/Topics/operation/setNotificationLevel),\n  [updateTopicTimestamp](https://docs.discourse.org/#tag/Topics/operation/updateTopicTimestamp),\n  [createTopicTimer](https://docs.discourse.org/#tag/Topics/operation/createTopicTimer),\n  [getTopicByExternalId](https://docs.discourse.org/#tag/Topics/operation/getTopicByExternalId).\n- **Private Messages**:\n  [createTopicPostPM](https://docs.discourse.org/#tag/Private-Messages/operation/createTopicPostPM),\n  [listUserPrivateMessages](https://docs.discourse.org/#tag/Private-Messages/operation/listUserPrivateMessages),\n  [getUserSentPrivateMessages](https://docs.discourse.org/#tag/Private-Messages/operation/,getUserSentPrivateMessages).\n- **Search**: [search](https://docs.discourse.org/#tag/Search/operation/search).\n- **Site**: [getSite](https://docs.discourse.org/#tag/Site/operation/getSite),\n  [getSiteBasicInfo](https://docs.discourse.org/#tag/Site/operation/getSiteBasicInfo).\n- **Tags**:\n  [listTagGroups](https://docs.discourse.org/#tag/Tags/operation/listTagGroups),\n  [createTagGroup](https://docs.discourse.org/#tag/Tags/operation/createTagGroup),\n  [getTagGroup](https://docs.discourse.org/#tag/Tags/operation/getTagGroup),\n  [updateTagGroup](https://docs.discourse.org/#tag/Tags/operation/updateTagGroup),\n  [listTags](https://docs.discourse.org/#tag/Tags/operation/listTags),\n  [getTag](https://docs.discourse.org/#tag/Tags/operation/getTag).\n- **Uploads**:\n  [createUpload](https://docs.discourse.org/#tag/Uploads/operation/createUpload),\n  [generatePresignedPut](https://docs.discourse.org/#tag/Uploads/operation/generatePresignedPut),\n  [completeExternalUpload](https://docs.discourse.org/#tag/Uploads/operation/completeExternalUpload),\n  [createMultipartUpload](https://docs.discourse.org/#tag/Uploads/operation/createMultipartUpload),\n  [batchPresignMultipartParts](https://docs.discourse.org/#tag/Uploads/operation/batchPresignMultipartParts),\n  [abortMultipart](https://docs.discourse.org/#tag/Users/Uploads/abortMultipart),\n  [completeMultipart](https://docs.discourse.org/#tag/Users/Uploads/completeMultipart).\n- **Users**:\n  [listUserBadges](https://docs.discourse.org/#tag/Users/operation/listUserBadges)\n  [createUser](https://docs.discourse.org/#tag/Users/operation/createUser)\n  [getUser](https://docs.discourse.org/#tag/Users/operation/getUser)\n  [updateUser](https://docs.discourse.org/#tag/Users/operation/updateUser)\n  [getUserExternalId](https://docs.discourse.org/#tag/Users/operation/getUserExternalId)\n  [getUserIdentiyProviderExternalId](https://docs.discourse.org/#tag/Users/operation/getUserIdentiyProviderExternalId)\n  [updateAvatar](https://docs.discourse.org/#tag/Users/operation/updateAvatar),\n  [updateEmail](https://docs.discourse.org/#tag/Users/operation/updateEmail),\n  [updateUsername](https://docs.discourse.org/#tag/Users/operation/updateUsername),\n  [listUsersPublic](https://docs.discourse.org/#tag/Users/operation/listUsersPublic),\n  [listUserActions](https://docs.discourse.org/#tag/Users/operation/listUserActions),\n  [sendPasswordResetEmail](https://docs.discourse.org/#tag/Users/operation/sendPasswordResetEmail),\n  [changePassword](https://docs.discourse.org/#tag/Users/operation/changePassword),\n  [getUserEmails](https://docs.discourse.org/#tag/Users/operation/getUserEmails).\n- **Admin**:\n  [adminGetUser](https://docs.discourse.org/#tag/Admin/operation/adminGetUser),\n  [deleteUser](https://docs.discourse.org/#tag/Admin/operation/deleteUser),\n  [activateUser](https://docs.discourse.org/#tag/Admin/operation/activateUser),\n  [deactivateUser](https://docs.discourse.org/#tag/Admin/operation/deactivateUser),\n  [suspendUser](https://docs.discourse.org/#tag/Admin/operation/suspendUser),\n  [silenceUser](https://docs.discourse.org/#tag/Admin/operation/silenceUser),\n  [anonymizeUser](https://docs.discourse.org/#tag/Admin/operation/anonymizeUser),\n  [logOutUser](https://docs.discourse.org/#tag/Admin/operation/logOutUser),\n  [refreshGravatar](https://docs.discourse.org/#tag/Admin/operation/refreshGravatar),\n  [adminListUsers](https://docs.discourse.org/#tag/Admin/operation/adminListUsers),\n\n## Notes\n\n1. You can discover the API through TypeScript text completion, or at\n   https://docs.discourse.org/.\n\n1. Some endpoints (like `listLatestTopics`) require auth headers in their\n   OpenAPI spec, but not in practice (provided the requested resource is a\n   publicly visible one). For this reason, if auth headers are required (by\n   spec) but not provided, we'll try the call anyway and let the endpoint\n   decide.\n\n1. By default, **additionalProperties in params** are disallowed. This is to\n   help prevent typos. However, often there are undocumented parameters that\n   still work, in which case, you can disable param validation. e.g.\n\n   ```ts\n   await discourse.updateUser({\n     username: \"user to update\",\n     // @ts-expect-error: not in spec    \u003c-- disable type check\n     title: \"a new title\",\n   }, {\n     validateParams: false, //           \u003c-- disable runtime validation\n   });\n   ```\n\n1. Currently, **the response is not validated**, because unfortunately, the\n   returned data often does not validate against the OpenAPI schema\n   (`additionalProperties`, missing `required` props, wrong types).\n\nI'm still deciding what to do with about this, feedback (in an issue) would be\ngreatly appreciated. In theory I'd like to make this a configurable option, but\nif we don't validate, we really should be returning the data as an `unknown`\ntype so the user performs their own validation, which is a pain, and you'll lose\ntypescript completion. However, on the flip side, what we do now is return a\ntype that is wrong, and TypeScript won't warn about missing (but now required)\nchecks.\n\n1. Installed Discourse extensions / plugins may affect the result! It can add\n   additional properties, etc. Likewise, running older versions of Discourse may\n   return data that doesn't match the current spec.\n\n1. **`createUpload()`** has been modified to accept `{ file?: Blob | File }`, vs\n   the original spec of `{ file: { type: \"string\", format: \"binary }}`.\n\n## TODO\n\n- [x] Validation (params; re response, see note above)\n\n## Development\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n```\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgadicc%2Fdiscourse2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgadicc%2Fdiscourse2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgadicc%2Fdiscourse2/lists"}