{"id":16557111,"url":"https://github.com/jnsougata/discohook","last_synced_at":"2025-03-16T20:30:21.785Z","repository":{"id":63957374,"uuid":"532480683","full_name":"jnsougata/discohook","owner":"jnsougata","description":"Discord Interaction API Wrapper for Serverless Applications","archived":false,"fork":false,"pushed_at":"2025-03-03T15:32:04.000Z","size":704,"stargazers_count":44,"open_issues_count":3,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-16T05:12:21.259Z","etag":null,"topics":["aws-lambda","cloud-functions","collaborate","communityexchange","deta","discord","discord-interactions","google-cloud-function","google-cloud-functions","python","serverless","vercel-deployment","vercel-serverless-functions"],"latest_commit_sha":null,"homepage":"https://discohook.readthedocs.io/en/latest","language":"Python","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/jnsougata.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"jnsougata"}},"created_at":"2022-09-04T08:26:58.000Z","updated_at":"2025-03-03T15:32:07.000Z","dependencies_parsed_at":"2024-04-26T11:42:02.450Z","dependency_job_id":"0a805466-8712-4027-8111-04f50a854dd2","html_url":"https://github.com/jnsougata/discohook","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnsougata%2Fdiscohook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnsougata%2Fdiscohook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnsougata%2Fdiscohook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jnsougata%2Fdiscohook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jnsougata","download_url":"https://codeload.github.com/jnsougata/discohook/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243928137,"owners_count":20370238,"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":["aws-lambda","cloud-functions","collaborate","communityexchange","deta","discord","discord-interactions","google-cloud-function","google-cloud-functions","python","serverless","vercel-deployment","vercel-serverless-functions"],"created_at":"2024-10-11T20:06:33.393Z","updated_at":"2025-03-16T20:30:21.779Z","avatar_url":"https://github.com/jnsougata.png","language":"Python","funding_links":["https://github.com/sponsors/jnsougata"],"categories":[],"sub_categories":[],"readme":"![image](https://github.com/jnsougata/discohook/assets/53375272/3bf58705-24c8-47ba-98f8-dffca05c1f82)\n\n# discohook\n\n### Installation\n\n```bash\npip install discohook\n```\nor\n```bash\npip install git+https://github.com/jnsougata/discohook.git\n```\n\n### Links\n- [Documentation](https://discohook.readthedocs.io/en/latest/)\n- [Discord](https://discord.gg/5PwqKbM7wu)\n- [Examples](examples)\n\n\n## Quickstart\n\n```python\nimport os\n\nimport discohook\n\nDISCORD_TOKEN = os.environ[\"DISCORD_TOKEN\"]\nPUBLIC_KEY = os.environ[\"PUBLIC_KEY\"]\nAPPLICATION_ID = os.environ[\"APPLICATION_ID\"]\nAPPLICATION_PASSWORD = os.environ[\"APPLICATION_PASSWORD\"]\n\napp = discohook.Client(\n    application_id=APPLICATION_ID,\n    public_key=PUBLIC_KEY,\n    token=DISCORD_TOKEN,\n    password=APPLICATION_PASSWORD,  # Must be provided if you want to use the dashboard.\n    default_help_command=True,  # This will enable your bot to use  default help command (/help).\n)\n\n\n# Adding a error handler for all interactions\n@app.on_interaction_error()\nasync def handler(i: discohook.Interaction, err: Exception):\n    user_response = \"Some error occurred! Please contact the developer.\"\n    if i.responded:\n        await i.response.followup(user_response, ephemeral=True)\n    else:\n        await i.response.send(user_response, ephemeral=True)\n\n    await app.send(\"12345678910\", f\"Error: {err}\")  # send error to a channel in development server\n\n\n# Adding a error handler for any serverside exception\n@app.on_error()\nasync def handler(_request, err: Exception):\n    # request: starlette.requests.Request\n    # err is the error object\n    await app.send(\"12345678910\", f\"Error: {err}\")  # send error to a channel in development server\n    # If you don't have reference to `app` object, you can use `request.app` to get the app object.\n\n\n# Note: ApplicationCommand is a decorator factory.\n# It will return a decorator which will register the function as a command.\n# The decorator for different command types are different and take a different set of arguments.\n# If name is not provided, it will use the callback function name as the command name\n# If command description is not provided for slash command and function's docstring is not found, it will raise ValueError.\n\n\n# Making slash command\n@app.load\n@discohook.command.slash()\nasync def ping(i: discohook.Interaction):\n    \"\"\"Ping the bot.\"\"\"\n    await i.response.send(\"Pong!\")\n\n\n# Making user command\n@app.load\n@discohook.command.user()\nasync def avatar(i: discohook.Interaction, user: discohook.User):\n    embed = discohook.Embed()\n    embed.set_image(img=user.avatar.url)\n    await i.response.send(embed=embed)\n\n\n# Making message command\n@app.load\n@discohook.command.message()\nasync def quote(i: discohook.Interaction, message: discohook.Message):\n    embed = discohook.Embed()\n    embed.set_author(name=message.author.name, icon_url=message.author.avatar.url)\n    embed.description = message.content\n    await i.response.send(embed=embed)\n\n```\n### Deployment\nDeploy the snippet above to your serverless function, and you're good to go to the next step.\nRemember to replace the variables with your own.\nCommand will not be automatically registered.\nWe provide a dashboard to register commands.\nWe will talk about it later.\n\n### Developer Portal Setup\n**1.** Head over to the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application. Once you've created the application, go to the \"Bot\" tab and create a new bot. Generate new token by using `Reset Token` and copy the bot token and paste it in the `APPLICATION_TOKEN` variable.\n![image](https://user-images.githubusercontent.com/53375272/205481601-934f7304-96a1-493f-82ed-91a3890e6352.png)\n**2.** Then go to the `General Information` tab and copy the `Application ID` and paste it in the `APPLICATION_ID` variable and copy the `Public Key` and paste it in the `APPLICATION_PUBLIC_KEY` variable.\n\n![image](https://user-images.githubusercontent.com/53375272/205481675-5e2f338f-7524-4e70-af65-bacfa48d1541.png)\n\n**3.** Then take you serverless instance `URL` i.e. `https://example.io` and add `/interactions` to it (i.e. `https://example.io/interactions`). Then head over to the general information tab and paste it in the `Interactions Endpoint URL` field. If everything is correct, you should see a confirmation message. Make sure you deploy the above code to your serverless instance before doing this.\n\n![image](https://user-images.githubusercontent.com/53375272/205481706-3ecae6ba-1c98-4b55-bcfd-bf42ac1ad10e.png)\n\n\n#### Registering Commands\nYou can sync commands by just visiting the dashboard.\nThe dashboard will be available at `https://example.io/api/dash `. \n\n![image](https://github.com/jnsougata/discohook/assets/53375272/b174878b-7aac-4e05-83cc-62f00dfa8c80)\n\nOnce you visit the dashboard, it will automatically register all the commands. \nYou can also register commands manually by using the bash command below.   \n```bash\ncurl -d \"{\\\"password\\\":  \\\"$(echo -n very_secure_password | sha256sum | awk '{ print $1 }')\\\"}\" -X POST https://example.io/api/sync\n```\n\n**🎉 Boom!** You're done. Now you can test your bot by using ` /help ` command in your server.\n\n#### Why we didn't add auto registration?\nAs this library is meant to be used in serverless functions,\nwe didn't add auto registration as at each invocation the scripts will be reloaded\nand the commands will be re-registered again.\nThis will cause rate limit issues and also due to command registration being a slow process,\nit will cause significant latency.\nSo we decided to add a dashboard to register commands.\nWhich is a lot faster and also doesn't cause any rate limit issues if used properly.\nThrough the dashboard, you can also delete commands and sync the edited commands.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjnsougata%2Fdiscohook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjnsougata%2Fdiscohook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjnsougata%2Fdiscohook/lists"}