@manaobot/kick 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +163 -0
  2. package/biome.json +44 -0
  3. package/bun.lock +78 -0
  4. package/example/01-authorize-bot/.env.example +7 -0
  5. package/example/01-authorize-bot/index.ts +60 -0
  6. package/example/02-webhook/.env.example +7 -0
  7. package/example/02-webhook/index.ts +80 -0
  8. package/example/03-ngrok/.env.example +7 -0
  9. package/example/03-ngrok/index.ts +92 -0
  10. package/example/04-categories-api/.env.example +7 -0
  11. package/example/04-categories-api/index.ts +77 -0
  12. package/example/05-users-api/.env.example +7 -0
  13. package/example/05-users-api/index.ts +60 -0
  14. package/example/06-channels-api/.env.example +7 -0
  15. package/example/06-channels-api/index.ts +60 -0
  16. package/example/07-channel-rewards-api/.env.example +7 -0
  17. package/example/07-channel-rewards-api/index.ts +60 -0
  18. package/example/08-basic-chat-bot/.env.example +7 -0
  19. package/example/08-basic-chat-bot/index.ts +102 -0
  20. package/package.json +23 -0
  21. package/qodana.yaml +31 -0
  22. package/src/KickClient.ts +172 -0
  23. package/src/Logger.ts +25 -0
  24. package/src/api/CategoriesAPI.ts +45 -0
  25. package/src/api/ChannelRewardsAPI.ts +121 -0
  26. package/src/api/ChannelsAPI.ts +63 -0
  27. package/src/api/KicksAPI.ts +37 -0
  28. package/src/api/LivestreamsAPI.ts +65 -0
  29. package/src/api/ModerationAPI.ts +60 -0
  30. package/src/api/UsersAPI.ts +72 -0
  31. package/src/auth/AuthManager.ts +64 -0
  32. package/src/auth/CallbackServer.ts +57 -0
  33. package/src/auth/OAuth.ts +55 -0
  34. package/src/auth/PKCE.ts +13 -0
  35. package/src/auth/TokenManager.ts +53 -0
  36. package/src/chat/ChatClient.ts +48 -0
  37. package/src/rest/RestClient.ts +39 -0
  38. package/src/webhooks/NgrokAdapter.ts +46 -0
  39. package/src/webhooks/WebhookRouter.ts +135 -0
  40. package/src/webhooks/WebhookServer.ts +41 -0
  41. package/tsconfig.json +29 -0
  42. package/types/api.d.ts +158 -0
  43. package/types/auth.d.ts +38 -0
  44. package/types/chat.d.ts +14 -0
  45. package/types/client.d.ts +67 -0
  46. package/types/index.d.ts +4 -0
  47. package/types/webhooks.d.ts +35 -0
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ <p align="center">
2
+ <a href="https://github.com/tinarskii/manao">
3
+ <img src="https://raw.githubusercontent.com/tinarskii/manao/main/docs/manao.svg" height="64px" width="auto" />
4
+ <h2 align="center">@manaobot/kick</h2>
5
+ </a>
6
+ <p align="center">
7
+ Minimal, type-safe JavaScript SDK for building Kick.com bots.
8
+ Designed for Bun. Works anywhere.
9
+ </p>
10
+ <div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;">
11
+ <img src="https://img.shields.io/npm/v/@manaobot/kick?color=00e701" alt="npm version">
12
+ <img src="https://img.shields.io/github/license/tinarskii/manao" />
13
+ <img src="https://img.shields.io/badge/Bun-%E2%9C%93-black?logo=bun" alt="Bun Compatible">
14
+ <a href="https://discord.gg/vkW7YMyYaf"><img src="https://img.shields.io/discord/964718161624715304" /></a>
15
+ </div>
16
+ </p>
17
+
18
+ ---
19
+
20
+ ## ⚡ About
21
+
22
+ `@manaobot/kick` is a lightweight TypeScript SDK for building Kick.com bots, tools, and automation.
23
+ This library focuses on **OAuth**, **Webhooks**, and **REST APIs**, everything required to build production-grade Kick bots.
24
+
25
+ ---
26
+
27
+ ## 📦 Installation
28
+
29
+ ```bash
30
+ bun add @manaobot/kick
31
+ ````
32
+
33
+ ---
34
+
35
+ ## 🚀 Quick Start
36
+
37
+ ```ts
38
+ import { KickClient } from "@manaobot/kick";
39
+
40
+ const kick = new KickClient({
41
+ clientId: process.env.KICK_CLIENT_ID!,
42
+ clientSecret: process.env.KICK_CLIENT_SECRET!,
43
+ redirectUri: "http://localhost:3000/callback",
44
+ scopes: ["chat:write"],
45
+ });
46
+
47
+ if (!process.env.KICK_REFRESH_TOKEN) {
48
+ console.log(kick.getAuthURL());
49
+ kick.auth.createCallbackServer({ port: 3000 });
50
+ await kick.auth.waitForAuthorization();
51
+ }
52
+
53
+ await kick.chat.send({
54
+ content: "Hello from Kick SDK!"
55
+ });
56
+ ```
57
+
58
+ ---
59
+
60
+ ## ✨ Features
61
+
62
+ ### 🔐 Authentication
63
+
64
+ * OAuth2 Authorization Code Flow
65
+ * Automatic token refresh
66
+ * PKCE support
67
+ * Built-in callback server
68
+
69
+ ---
70
+
71
+ ### 🧩 Webhooks
72
+
73
+ ```ts
74
+ kick.webhooks.on("chat.message.sent", (event) => {
75
+ console.log(event.content);
76
+ });
77
+ ```
78
+
79
+ * Signature verification
80
+ * ngrok integration
81
+ * Event subscription helpers
82
+
83
+ ---
84
+
85
+ ### 💬 Chat
86
+
87
+ ```ts
88
+ await kick.chat.send({ content: "Hello chat!" });
89
+ ```
90
+
91
+ ---
92
+
93
+ ### 🌐 REST APIs
94
+
95
+ Available via:
96
+
97
+ ```ts
98
+ kick.api.*
99
+ ```
100
+
101
+ Currently supported:
102
+
103
+ * Categories API
104
+ * Users API
105
+ * Channels API
106
+ * Channel Rewards API
107
+ * Moderation API
108
+ * Livestreams API
109
+ * KICKs Leaderboard API
110
+
111
+ ---
112
+
113
+ ## 📚 Examples
114
+
115
+ The repository includes numbered examples:
116
+
117
+ | Example | Description |
118
+ | ------------------------ | ------------------------ |
119
+ | `01-authorize-bot` | OAuth authorization |
120
+ | `02-webhook` | Webhook handling |
121
+ | `03-ngrok` | Public webhook tunneling |
122
+ | `04-categories-api` | Categories API |
123
+ | `05-users-api` | Users API |
124
+ | `06-channels-api` | Channels API |
125
+ | `07-channel-rewards-api` | Channel rewards |
126
+ | `08-basic-chat-bot` | Full bot template |
127
+
128
+ Run examples with:
129
+
130
+ ```bash
131
+ bun example/08-basic-chat-bot
132
+ ```
133
+
134
+ ---
135
+
136
+ ## 🤝 Contributing
137
+
138
+ Pull requests are welcome.
139
+
140
+ If you want to help:
141
+
142
+ * improve typings
143
+ * add new API modules
144
+ * write examples
145
+
146
+ Join the Discord server:
147
+
148
+ [https://discord.gg/vkW7YMyYaf](https://discord.gg/vkW7YMyYaf)
149
+
150
+ ---
151
+
152
+ ## 📜 License
153
+
154
+ GPL-3.0 License
155
+ See LICENSE file for details.
156
+
157
+ ---
158
+
159
+ ## ❤️ Part of the Manao Ecosystem
160
+
161
+ This SDK powers the **ManaoBot** project:
162
+
163
+ [https://github.com/tinarskii/manao](https://github.com/tinarskii/manao)
package/biome.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
3
+ "vcs": {
4
+ "enabled": false,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": false
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false,
10
+ "experimentalScannerIgnores": ["dist", "node_modules", "tsconfig.json"]
11
+ },
12
+ "formatter": {
13
+ "enabled": true,
14
+ "indentStyle": "space",
15
+ "indentWidth": 2
16
+ },
17
+ "linter": {
18
+ "enabled": true,
19
+ "rules": {
20
+ "recommended": true
21
+ }
22
+ },
23
+ "javascript": {
24
+ "formatter": {
25
+ "quoteStyle": "double",
26
+ "semicolons": "always",
27
+ "lineEnding": "crlf",
28
+ "arrowParentheses": "always",
29
+ "bracketSpacing": true,
30
+ "bracketSameLine": false
31
+ },
32
+ "parser": {
33
+ "unsafeParameterDecoratorsEnabled": true
34
+ }
35
+ },
36
+ "assist": {
37
+ "enabled": true,
38
+ "actions": {
39
+ "source": {
40
+ "organizeImports": "on"
41
+ }
42
+ }
43
+ }
44
+ }
package/bun.lock ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "kick.js",
6
+ "dependencies": {
7
+ "consola": "^3.4.2",
8
+ },
9
+ "devDependencies": {
10
+ "@biomejs/biome": "2.3.14",
11
+ "@ngrok/ngrok": "^1.7.0",
12
+ "@types/bun": "^1.3.8",
13
+ },
14
+ "peerDependencies": {
15
+ "typescript": "^5",
16
+ },
17
+ },
18
+ },
19
+ "packages": {
20
+ "@biomejs/biome": ["@biomejs/biome@2.3.14", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.14", "@biomejs/cli-darwin-x64": "2.3.14", "@biomejs/cli-linux-arm64": "2.3.14", "@biomejs/cli-linux-arm64-musl": "2.3.14", "@biomejs/cli-linux-x64": "2.3.14", "@biomejs/cli-linux-x64-musl": "2.3.14", "@biomejs/cli-win32-arm64": "2.3.14", "@biomejs/cli-win32-x64": "2.3.14" }, "bin": { "biome": "bin/biome" } }, "sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA=="],
21
+
22
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A=="],
23
+
24
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA=="],
25
+
26
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ=="],
27
+
28
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg=="],
29
+
30
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA=="],
31
+
32
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ=="],
33
+
34
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A=="],
35
+
36
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ=="],
37
+
38
+ "@ngrok/ngrok": ["@ngrok/ngrok@1.7.0", "", { "optionalDependencies": { "@ngrok/ngrok-android-arm64": "1.7.0", "@ngrok/ngrok-darwin-arm64": "1.7.0", "@ngrok/ngrok-darwin-universal": "1.7.0", "@ngrok/ngrok-darwin-x64": "1.7.0", "@ngrok/ngrok-freebsd-x64": "1.7.0", "@ngrok/ngrok-linux-arm-gnueabihf": "1.7.0", "@ngrok/ngrok-linux-arm64-gnu": "1.7.0", "@ngrok/ngrok-linux-arm64-musl": "1.7.0", "@ngrok/ngrok-linux-x64-gnu": "1.7.0", "@ngrok/ngrok-linux-x64-musl": "1.7.0", "@ngrok/ngrok-win32-arm64-msvc": "1.7.0", "@ngrok/ngrok-win32-ia32-msvc": "1.7.0", "@ngrok/ngrok-win32-x64-msvc": "1.7.0" } }, "sha512-P06o9TpxrJbiRbHQkiwy/rUrlXRupc+Z8KT4MiJfmcdWxvIdzjCaJOdnNkcOTs6DMyzIOefG5tvk/HLdtjqr0g=="],
39
+
40
+ "@ngrok/ngrok-android-arm64": ["@ngrok/ngrok-android-arm64@1.7.0", "", { "os": "android", "cpu": "arm64" }, "sha512-8tco3ID6noSaNy+CMS7ewqPoIkIM6XO5COCzsUp3Wv3XEbMSyn65RN6cflX2JdqLfUCHcMyD0ahr9IEiHwqmbQ=="],
41
+
42
+ "@ngrok/ngrok-darwin-arm64": ["@ngrok/ngrok-darwin-arm64@1.7.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+dmJSOzSO+MNDVrPOca2yYDP1W3KfP4qOlAkarIeFRIfqonQwq3QCBmcR7HAlZocLsSqEwyG6KP4RRvAuT0WGQ=="],
43
+
44
+ "@ngrok/ngrok-darwin-universal": ["@ngrok/ngrok-darwin-universal@1.7.0", "", { "os": "darwin" }, "sha512-fDEfewyE2pWGFBhOSwQZObeHUkc65U1l+3HIgSOe094TMHsqmyJD0KTCgW9KSn0VP4OvDZbAISi1T3nvqgZYhQ=="],
45
+
46
+ "@ngrok/ngrok-darwin-x64": ["@ngrok/ngrok-darwin-x64@1.7.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-+fwMi5uHd9G8BS42MMa9ye6exI5lwTcjUO6Ut497Vu0qgLONdVRenRqnEePV+Q3KtQR7NjqkMnomVfkr9MBjtw=="],
47
+
48
+ "@ngrok/ngrok-freebsd-x64": ["@ngrok/ngrok-freebsd-x64@1.7.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2OGgbrjy3yLRrqAz5N6hlUKIWIXSpR5RjQa2chtZMsSbszQ6c9dI+uVQfOKAeo05tHMUgrYAZ7FocC+ig0dzdQ=="],
49
+
50
+ "@ngrok/ngrok-linux-arm-gnueabihf": ["@ngrok/ngrok-linux-arm-gnueabihf@1.7.0", "", { "os": "linux", "cpu": "arm" }, "sha512-SN9YIfEQiR9xN90QVNvdgvAemqMLoFVSeTWZs779145hQMhvF9Qd9rnWi6J+2uNNK10OczdV1oc/nq1es7u/3g=="],
51
+
52
+ "@ngrok/ngrok-linux-arm64-gnu": ["@ngrok/ngrok-linux-arm64-gnu@1.7.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-KDMgzPKFU2kbpVSaA2RZBBia5IPdJEe063YlyVFnSMJmPYWCUnMwdybBsucXfV9u1Lw/ZjKTKotIlbTWGn3HGw=="],
53
+
54
+ "@ngrok/ngrok-linux-arm64-musl": ["@ngrok/ngrok-linux-arm64-musl@1.7.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-e66vUdVrBlQ0lT9ZdamB4U604zt5Gualt8/WVcUGzbu8s5LajWd6g/mzZCUjK4UepjvMpfgmCp1/+rX7Rk8d5A=="],
55
+
56
+ "@ngrok/ngrok-linux-x64-gnu": ["@ngrok/ngrok-linux-x64-gnu@1.7.0", "", { "os": "linux", "cpu": "x64" }, "sha512-M6gF0DyOEFqXLfWxObfL3bxYZ4+PnKBHuyLVaqNfFN9Y5utY2mdPOn5422Ppbk4XoIK5/YkuhRqPJl/9FivKEw=="],
57
+
58
+ "@ngrok/ngrok-linux-x64-musl": ["@ngrok/ngrok-linux-x64-musl@1.7.0", "", { "os": "linux", "cpu": "x64" }, "sha512-4Ijm0dKeoyzZTMaYxR2EiNjtlK81ebflg/WYIO1XtleFrVy4UJEGnxtxEidYoT4BfCqi4uvXiK2Mx216xXKvog=="],
59
+
60
+ "@ngrok/ngrok-win32-arm64-msvc": ["@ngrok/ngrok-win32-arm64-msvc@1.7.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-u7qyWIJI2/YG1HTBnHwUR1+Z2tyGfAsUAItJK/+N1G0FeWJhIWQvSIFJHlaPy4oW1Dc8mSDBX9qvVsiQgLaRFg=="],
61
+
62
+ "@ngrok/ngrok-win32-ia32-msvc": ["@ngrok/ngrok-win32-ia32-msvc@1.7.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-/UdYUsLNv/Q8j9YJsyIfq/jLCoD8WP+NidouucTUzSoDtmOsXBBT3itLrmPiZTEdEgKiFYLuC1Zon8XQQvbVLA=="],
63
+
64
+ "@ngrok/ngrok-win32-x64-msvc": ["@ngrok/ngrok-win32-x64-msvc@1.7.0", "", { "os": "win32", "cpu": "x64" }, "sha512-UFJg/duEWzZlLkEs61Gz6/5nYhGaKI62I8dvUGdBR3NCtIMagehnFaFxmnXZldyHmCM8U0aCIFNpWRaKcrQkoA=="],
65
+
66
+ "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
67
+
68
+ "@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="],
69
+
70
+ "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
71
+
72
+ "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
73
+
74
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
75
+
76
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
77
+ }
78
+ }
@@ -0,0 +1,7 @@
1
+ KICK_CLIENT_ID=[YOUR_CLIENT_ID_HERE]
2
+ KICK_CLIENT_SECRET=[YOUR_CLIENT_SECRET_HERE]
3
+
4
+ # These two lines below are the lines you need to fill in after getting tokens
5
+ # After running the ./index.ts file
6
+ KICK_ACCESS_TOKEN=
7
+ KICK_REFRESH_TOKEN=
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Example 01: Authorizing a bot application
3
+ *
4
+ * This template demonstrates how to authorize a bot application using the ManaoKick library.
5
+ * The bot will send a message to the chat once authorized.
6
+ * In the first run, it will print the access and refresh tokens to the console for
7
+ * you to save in your environment variables file (.env).
8
+ *
9
+ * Before running this code, ensure you have the following environment variables set:
10
+ * - KICK_CLIENT_ID
11
+ * - KICK_CLIENT_SECRET
12
+ *
13
+ * Currently, the bot cannot receive messages from the chat.
14
+ *
15
+ * SCOPES: ["chat:write"]
16
+ * Make sure to refresh the tokens and update your environment variables when scopes change.
17
+ */
18
+
19
+ import { KickClient } from "../../src/KickClient.ts";
20
+ import type { KickTokenResponse } from "../../types";
21
+
22
+ // Initialize the KickClient with necessary credentials and scopes
23
+ const kick = new KickClient({
24
+ clientId: Bun.env.KICK_CLIENT_ID!,
25
+ clientSecret: Bun.env.KICK_CLIENT_SECRET!,
26
+ redirectUri: "http://localhost:3000/callback",
27
+ scopes: ["chat:write", "events:subscribe"],
28
+ showLog: false,
29
+ auth: {
30
+ initialTokens: Bun.env.KICK_REFRESH_TOKEN
31
+ ? {
32
+ access_token: Bun.env.KICK_ACCESS_TOKEN!,
33
+ refresh_token: Bun.env.KICK_REFRESH_TOKEN!,
34
+ }
35
+ : undefined,
36
+ onTokenUpdate: (tokens: KickTokenResponse) => {
37
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
38
+ console.log("\n[!] Copy these into your .env file:\n");
39
+ console.log(`KICK_ACCESS_TOKEN=${tokens.access_token}`);
40
+ console.log(`KICK_REFRESH_TOKEN=${tokens.refresh_token}`);
41
+ console.log(`\n====> Scopes granted: ${tokens.scope}`);
42
+ }
43
+
44
+ Bun.env.KICK_ACCESS_TOKEN = tokens.access_token;
45
+ Bun.env.KICK_REFRESH_TOKEN = tokens.refresh_token;
46
+ },
47
+ },
48
+ });
49
+ // If no refresh token is found, initiate the authorization flow
50
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
51
+ console.log(`Authorize the application by visiting:\n${kick.getAuthURL()}`);
52
+ kick.auth.createCallbackServer({ port: 3000 });
53
+ await kick.auth.waitForAuthorization();
54
+ }
55
+
56
+ // Confirm successful authorization
57
+ console.log("\n[✔] Application authorized successfully!");
58
+ await kick.chat.send({
59
+ content: "Hello from ManaoKick library!",
60
+ });
@@ -0,0 +1,7 @@
1
+ KICK_CLIENT_ID=[YOUR_CLIENT_ID_HERE]
2
+ KICK_CLIENT_SECRET=[YOUR_CLIENT_SECRET_HERE]
3
+
4
+ # These two lines below are the lines you need to fill in after getting tokens
5
+ # After running the ./index.ts file
6
+ KICK_ACCESS_TOKEN=
7
+ KICK_REFRESH_TOKEN=
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Example 02: Subscribing to webhooks
3
+ *
4
+ * This template demonstrates how to subscribe to webhooks using the ManaoKick library.
5
+ * The bot will respond to a specific chat message event once authorized. (!ping -> pong 🏓)
6
+ * In the first run, it will print the access and refresh tokens to the console for
7
+ * you to save in your environment variables file (.env).
8
+ *
9
+ * Before running this code, ensure you have the following environment variables set:
10
+ * - KICK_CLIENT_ID
11
+ * - KICK_CLIENT_SECRET
12
+ *
13
+ * Please note that Kick server cannot access localhost webhooks. To test webhooks,
14
+ * consider using a tunneling service like ngrok to expose your local server to the internet.
15
+ *
16
+ * Simple bot template with ngrok adapter can be found in the next example: example/03-ngrok
17
+ *
18
+ * SCOPES: ["chat:write", "events:subscribe"]
19
+ * Make sure to refresh the tokens and update your environment variables when scopes change.
20
+ */
21
+
22
+ import { KickClient } from "../../src/KickClient.ts";
23
+ import type { ChatMessageEvent, KickTokenResponse } from "../../types";
24
+
25
+ // Initialize the KickClient with necessary credentials and scopes
26
+ const kick = new KickClient({
27
+ clientId: Bun.env.KICK_CLIENT_ID!,
28
+ clientSecret: Bun.env.KICK_CLIENT_SECRET!,
29
+ redirectUri: "http://localhost:3000/callback",
30
+ scopes: ["chat:write", "events:subscribe"],
31
+ showLog: false,
32
+ auth: {
33
+ initialTokens: Bun.env.KICK_REFRESH_TOKEN
34
+ ? {
35
+ access_token: Bun.env.KICK_ACCESS_TOKEN!,
36
+ refresh_token: Bun.env.KICK_REFRESH_TOKEN!,
37
+ }
38
+ : undefined,
39
+ onTokenUpdate: (tokens: KickTokenResponse) => {
40
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
41
+ console.log("\n[!] Copy these into your .env file:\n");
42
+ console.log(`KICK_ACCESS_TOKEN=${tokens.access_token}`);
43
+ console.log(`KICK_REFRESH_TOKEN=${tokens.refresh_token}`);
44
+ console.log(`\n====> Scopes granted: ${tokens.scope}`);
45
+ }
46
+
47
+ Bun.env.KICK_ACCESS_TOKEN = tokens.access_token;
48
+ Bun.env.KICK_REFRESH_TOKEN = tokens.refresh_token;
49
+ },
50
+ },
51
+ });
52
+ // If no refresh token is found, initiate the authorization flow
53
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
54
+ console.log(`Authorize the application by visiting:\n${kick.getAuthURL()}`);
55
+ kick.auth.createCallbackServer({ port: 3000 });
56
+ await kick.auth.waitForAuthorization();
57
+ }
58
+
59
+ // Confirm successful authorization
60
+ console.log("\n[✔] Application authorized successfully!");
61
+ await kick.chat.send({
62
+ content: "Hello from ManaoKick library!",
63
+ });
64
+
65
+ // Create a webhook server to listen for incoming events
66
+ kick.webhooks.createServer({ port: 5000, path: "/kick/webhook" });
67
+
68
+ // Subscribe to webhooks once authorized
69
+ kick.auth.onAuthorized(async () => {
70
+ await kick.webhooks.subscribe({
71
+ events: [{ name: "chat.message.sent" }],
72
+ });
73
+ });
74
+
75
+ // Handle incoming chat message events
76
+ kick.webhooks.on("chat.message.sent", async (event: ChatMessageEvent) => {
77
+ if (event.content === "!ping") {
78
+ await kick.chat.send({ content: "pong 🏓" });
79
+ }
80
+ });
@@ -0,0 +1,7 @@
1
+ KICK_CLIENT_ID=[YOUR_CLIENT_ID_HERE]
2
+ KICK_CLIENT_SECRET=[YOUR_CLIENT_SECRET_HERE]
3
+
4
+ # These two lines below are the lines you need to fill in after getting tokens
5
+ # After running the ./index.ts file
6
+ KICK_ACCESS_TOKEN=
7
+ KICK_REFRESH_TOKEN=
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Example 03: Using ngrok adapter to expose local webhooks
3
+ *
4
+ * This template demonstrates how to use the ngrok adapter to expose local webhooks using the ManaoKick library.
5
+ * The bot will respond to a specific chat message event once authorized. (!ping -> pong 🏓)
6
+ * In the first run, it will print the access and refresh tokens to the console for
7
+ * you to save in your environment variables file (.env).
8
+ *
9
+ * Before running this code, ensure you have the following environment variables set:
10
+ * - KICK_CLIENT_ID
11
+ * - KICK_CLIENT_SECRET
12
+ *
13
+ * Additionally, set the NGROK_AUTHTOKEN environment variable with your ngrok authtoken.
14
+ * You can get an authtoken by signing up at https://ngrok.com/.
15
+ *
16
+ * Make sure to enable webhooks in Kick Developer Portal for your application, and ensure
17
+ * the webhook URL matches the one provided by ngrok.
18
+ *
19
+ * SCOPES: ["chat:write", "events:subscribe"]
20
+ * Make sure to refresh the tokens and update your environment variables when scopes change.
21
+ *
22
+ */
23
+
24
+ import { KickClient } from "../../src/KickClient.ts";
25
+ import type { ChatMessageEvent, KickTokenResponse } from "../../types";
26
+
27
+ // Initialize the KickClient with necessary credentials and scopes
28
+ const kick = new KickClient({
29
+ clientId: Bun.env.KICK_CLIENT_ID!,
30
+ clientSecret: Bun.env.KICK_CLIENT_SECRET!,
31
+ redirectUri: "http://localhost:3000/callback",
32
+ scopes: ["chat:write", "events:subscribe"],
33
+ showLog: false,
34
+ auth: {
35
+ initialTokens: Bun.env.KICK_REFRESH_TOKEN
36
+ ? {
37
+ access_token: Bun.env.KICK_ACCESS_TOKEN!,
38
+ refresh_token: Bun.env.KICK_REFRESH_TOKEN!,
39
+ }
40
+ : undefined,
41
+ onTokenUpdate: (tokens: KickTokenResponse) => {
42
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
43
+ console.log("\n[!] Copy these into your .env file:\n");
44
+ console.log(`KICK_ACCESS_TOKEN=${tokens.access_token}`);
45
+ console.log(`KICK_REFRESH_TOKEN=${tokens.refresh_token}`);
46
+ console.log(`\n====> Scopes granted: ${tokens.scope}`);
47
+ }
48
+
49
+ Bun.env.KICK_ACCESS_TOKEN = tokens.access_token;
50
+ Bun.env.KICK_REFRESH_TOKEN = tokens.refresh_token;
51
+ },
52
+ },
53
+ });
54
+ // If no refresh token is found, initiate the authorization flow
55
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
56
+ console.log(`Authorize the application by visiting:\n${kick.getAuthURL()}`);
57
+ kick.auth.createCallbackServer({ port: 3000 });
58
+ await kick.auth.waitForAuthorization();
59
+ }
60
+
61
+ // Confirm successful authorization
62
+ console.log("\n[✔] Application authorized successfully!");
63
+ await kick.chat.send({
64
+ content: "Hello from ManaoKick library!",
65
+ });
66
+
67
+ // Handle incoming chat message events
68
+ kick.webhooks.on("chat.message.sent", async (event: ChatMessageEvent) => {
69
+ if (event.content === "!ping") {
70
+ await kick.chat.send({ content: "pong 🏓" });
71
+ }
72
+ });
73
+
74
+ // Set up ngrok to expose the webhook endpoint
75
+ const { url, close } = await kick.webhooks.ngrok({
76
+ port: 5000, // Use the same port as the webhook server
77
+ path: "/kick/webhook",
78
+ domain: "topical-goshawk-leading.ngrok-free.app", // <==== Replace with YOUR OWN ngrok domain!
79
+ authtoken: Bun.env.NGROK_AUTHTOKEN,
80
+ });
81
+
82
+ console.log(`[✔] ngrok tunnel established at: ${url}`);
83
+
84
+ // Create a webhook server to listen for incoming events
85
+ kick.webhooks.createServer({ port: 5000, path: "/kick/webhook" }); // Use port that ngrok will forward to
86
+
87
+ // Subscribe to webhooks once authorized
88
+ kick.auth.onAuthorized(async () => {
89
+ await kick.webhooks.subscribe({
90
+ events: [{ name: "chat.message.sent" }],
91
+ });
92
+ });
@@ -0,0 +1,7 @@
1
+ KICK_CLIENT_ID=[YOUR_CLIENT_ID_HERE]
2
+ KICK_CLIENT_SECRET=[YOUR_CLIENT_SECRET_HERE]
3
+
4
+ # These two lines below are the lines you need to fill in after getting tokens
5
+ # After running the ./index.ts file
6
+ KICK_ACCESS_TOKEN=
7
+ KICK_REFRESH_TOKEN=
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Example 04: Using Categories API
3
+ *
4
+ * This template demonstrates how to use the Categories API with the ManaoKick library.
5
+ * The bot will send a message to the chat once authorized.
6
+ * In the first run, it will print the access and refresh tokens to the console for
7
+ * you to save in your environment variables file (.env).
8
+ *
9
+ * Before running this code, ensure you have the following environment variables set:
10
+ * - KICK_CLIENT_ID
11
+ * - KICK_CLIENT_SECRET
12
+ *
13
+ * SCOPES: []
14
+ * Make sure to refresh the tokens and update your environment variables when scopes change.
15
+ */
16
+
17
+ import { KickClient } from "../../src/KickClient.ts";
18
+ import type { KickTokenResponse } from "../../types";
19
+ import { logger } from "../../src/Logger.ts";
20
+
21
+ // Initialize the KickClient with necessary credentials and scopes
22
+ const kick = new KickClient({
23
+ clientId: Bun.env.KICK_CLIENT_ID!,
24
+ clientSecret: Bun.env.KICK_CLIENT_SECRET!,
25
+ redirectUri: "http://localhost:3000/callback",
26
+ scopes: ["kicks:read"],
27
+ showLog: false,
28
+ auth: {
29
+ initialTokens: Bun.env.KICK_REFRESH_TOKEN
30
+ ? {
31
+ access_token: Bun.env.KICK_ACCESS_TOKEN!,
32
+ refresh_token: Bun.env.KICK_REFRESH_TOKEN!,
33
+ }
34
+ : undefined,
35
+ onTokenUpdate: (tokens: KickTokenResponse) => {
36
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
37
+ console.log("\n[!] Copy these into your .env file:\n");
38
+ console.log(`KICK_ACCESS_TOKEN=${tokens.access_token}`);
39
+ console.log(`KICK_REFRESH_TOKEN=${tokens.refresh_token}`);
40
+ console.log(`\n====> Scopes granted: ${tokens.scope}`);
41
+ }
42
+
43
+ Bun.env.KICK_ACCESS_TOKEN = tokens.access_token;
44
+ Bun.env.KICK_REFRESH_TOKEN = tokens.refresh_token;
45
+ },
46
+ },
47
+ });
48
+
49
+ // If no refresh token is found, initiate the authorization flow
50
+ if (!Bun.env.KICK_REFRESH_TOKEN) {
51
+ console.log(`Authorize the application by visiting:\n${kick.getAuthURL()}`);
52
+ kick.auth.createCallbackServer({ port: 3000 });
53
+ await kick.auth.waitForAuthorization();
54
+ }
55
+
56
+ // Confirm successful authorization
57
+ console.log("\n[✔] Application authorized successfully!");
58
+
59
+ const name = (
60
+ await logger.prompt("Search categories by name (seperated with commas): ", {
61
+ type: "text",
62
+ })
63
+ ).split(",");
64
+
65
+ let limit = Number(
66
+ await logger.prompt("Limit (default 10): ", {
67
+ type: "text",
68
+ }),
69
+ );
70
+
71
+ if (isNaN(limit) || limit <= 0) {
72
+ limit = 10;
73
+ }
74
+
75
+ const categories = await kick.api.categories.get({ name, limit });
76
+ console.log("\n[✔] Categories fetched successfully!");
77
+ console.log(categories);
@@ -0,0 +1,7 @@
1
+ KICK_CLIENT_ID=[YOUR_CLIENT_ID_HERE]
2
+ KICK_CLIENT_SECRET=[YOUR_CLIENT_SECRET_HERE]
3
+
4
+ # These two lines below are the lines you need to fill in after getting tokens
5
+ # After running the ./index.ts file
6
+ KICK_ACCESS_TOKEN=
7
+ KICK_REFRESH_TOKEN=