{"id":22521073,"url":"https://github.com/instafluff/comfyjs","last_synced_at":"2025-05-15T03:03:27.607Z","repository":{"id":41562700,"uuid":"166471416","full_name":"instafluff/ComfyJS","owner":"instafluff","description":"Comfiest Twitch Chat Library for JavaScript | NodeJS + Browser Support","archived":false,"fork":false,"pushed_at":"2025-02-23T19:37:22.000Z","size":1542,"stargazers_count":416,"open_issues_count":20,"forks_count":46,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-14T00:59:39.586Z","etag":null,"topics":["browser","chat","chatbot","hacktob","javascript","library","livestream","nodejs","twitch","typescript"],"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/instafluff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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":"instafluff","custom":["https://www.twitch.tv/instafluff","instafluff.tv"]}},"created_at":"2019-01-18T20:55:57.000Z","updated_at":"2025-03-31T01:22:37.000Z","dependencies_parsed_at":"2024-01-13T19:21:34.866Z","dependency_job_id":"a8a2cd07-4932-4ed8-acbb-d62af9f5f237","html_url":"https://github.com/instafluff/ComfyJS","commit_stats":{"total_commits":174,"total_committers":18,"mean_commits":9.666666666666666,"dds":0.6091954022988506,"last_synced_commit":"4ebf9b8b106736f7e1b1ef3c82cb50539091b59e"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instafluff%2FComfyJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instafluff%2FComfyJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instafluff%2FComfyJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instafluff%2FComfyJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/instafluff","download_url":"https://codeload.github.com/instafluff/ComfyJS/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248804790,"owners_count":21164132,"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":["browser","chat","chatbot","hacktob","javascript","library","livestream","nodejs","twitch","typescript"],"created_at":"2024-12-07T05:09:33.999Z","updated_at":"2025-04-14T00:59:51.586Z","avatar_url":"https://github.com/instafluff.png","language":"JavaScript","readme":"# Comfy.JS\n![npm](https://img.shields.io/npm/v/comfy.js?style=flat-square) ![GitHub](https://img.shields.io/github/license/instafluff/comfyjs?style=flat-square) [![](https://data.jsdelivr.com/v1/package/npm/comfy.js/badge)](https://www.jsdelivr.com/package/npm/comfy.js)\n\nWe built this Comfy Twitch Chat Module live on Twitch for Coding Cafe!\n\n**Special Thanks:** *Comfy.JS is possible thanks to [tmi.js](https://tmijs.com/) maintained by [@AlcaDesign](https://github.com/AlcaDesign)*\n\n**Comfy.JS** lets you integrate with Twitch chat for your Twitch channel ***SUPER EASILY*** in just a few lines of code. Here's a quick 3-min video on how to use it: (Click image to open video)\n\n[![ComfyJS How-To Video](https://img.youtube.com/vi/oXpPwnUQCCk/hqdefault.jpg)](https://www.youtube.com/watch?v=oXpPwnUQCCk)\n\n## Instafluff ##\n\u003e *Like these projects? The best way to support my open-source projects is by becoming a Comfy Sponsor on GitHub!*\n\n\u003e https://github.com/sponsors/instafluff\n\n\u003e *Come and hang out with us at the Comfiest Corner on Twitch!*\n\n\u003e https://twitch.tv/instafluff\n\n## Instructions ##\n\n#### Node\n1. Install `comfy.js`\n```\nnpm install comfy.js --save\n```\n\n2. Respond to !commands your channel\n```javascript\nvar ComfyJS = require(\"comfy.js\");\nComfyJS.onCommand = ( user, command, message, flags, extra ) =\u003e {\n  if( flags.broadcaster \u0026\u0026 command === \"test\" ) {\n    console.log( \"!test was typed in chat\" );\n  }\n}\nComfyJS.Init( \"MyTwitchChannel\" );\n```\n\n#### Browser\n1. Download and add `comfy.js` from the `dist` folder or include from the JSDelivr CDN:\n```javascript\n\u003cscript src=\"comfy.min.js\"\u003e\u003c/script\u003e\n```\nOR\n```javascript\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/comfy.js@latest/dist/comfy.min.js\"\u003e\u003c/script\u003e\n```\n\n2. Respond to !commands your channel\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/comfy.js@latest/dist/comfy.min.js\"\u003e\u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cscript type=\"text/javascript\"\u003e\n      ComfyJS.onCommand = ( user, command, message, flags, extra ) =\u003e {\n        if( flags.broadcaster \u0026\u0026 command === \"test\" ) {\n          console.log( \"!test was typed in chat\" );\n        }\n      }\n      ComfyJS.Init( \"MyTwitchChannel\" );\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Flags ##\n\nCurrently, the flags possible in `onCommand()` and `onChat()` are:\n\n- broadcaster\n- mod\n- founder\n- subscriber\n- vip\n- highlighted\n- customReward\n\n## Extra Parameter ##\n\nCurrently, the `extra` parameter for the `onCommand()` contains the following fields:\n\n- id (the message message)\n- channel\n- roomId\n- messageType\n- messageEmotes\n- isEmoteOnly\n- userId\n- username\n- displayName\n- userColor\n- userBadges\n- flags\n- timestamp\n- customRewardId (only works with custom channel rewards with required-text)\n\nIf the message is a command, the `extra` parameter will contain an additional field:\n\n- sinceLastCommand\n\nwhich contains the information on the time periods in `ms` since the last time any user, or the specific user, has used the same\ncommand. This field can be convenient to be used for setting global cooldown or spamming filters. See examples below:\n\n```javascript\nComfyJS.onChat = ( user, message, flags, self, extra ) =\u003e {\n  if( flags.broadcaster \u0026\u0026 command === \"test\" ) {\n    if( extra.sinceLastCommand.any \u003c 100 ) {\n      console.log(\n        `The last '!test' command by any user was sent less than 100 ms ago`\n      );            \n    }\n\n    if( extra.sinceLastCommand.user \u003c 100 ) {\n      console.log(\n        `The last '!test' command by this specific user (as denoted by the 'user' parameter) was sent less than 100 ms ago`\n      );            \n    }\n  }\n}\n```\n\n## Reading Chat Messages ##\n\nYou can read chat messages by using the `onChat()` handler\n\n```javascript\nComfyJS.onChat = ( user, message, flags, self, extra ) =\u003e {\n  console.log( user, message );\n}\n```\n\n## Sending Chat Messages ##\n\nSending Chat Messages can be done through `ComfyJS.Say( message )` but requires an OAUTH password when connecting to chat.\n\n#### Securely adding your password\n1. Get a Twitch Chat OAuth Password Token - [http://twitchapps.com/tmi/](http://twitchapps.com/tmi/)\n2. Install `dotenv`\n```\nnpm install dotenv --save\n```\n3. Create a file named `.env` that looks like this:\n```javascript\nTWITCHUSER=[YOUR-USERNAME-HERE]\nOAUTH=[YOUR-OAUTH-PASS HERE] # e.g. OAUTH=oauth:kjh12bn1hsj78445234\n```\n4. Initialize with the Username and OAUTH password\n```javascript\nvar ComfyJS = require(\"comfy.js\");\nComfyJS.onCommand = ( user, command, message, flags, extra ) =\u003e {\n  if( command === \"test\" ) {\n    ComfyJS.Say( \"replying to !test\" );\n  }\n}\nComfyJS.Init( process.env.TWITCHUSER, process.env.OAUTH );\n```\n\n## Joining a Different Channel ##\n\nYou can join a different channel or groups of channels by specifying in the `Init()`\n\n#### Joining a Single Channel\n\n```javascript\nComfyJS.Init( \"MyTwitchChannel\", null, \"ChannelToJoin\" );\n```\n\n#### Joining Multiple Channels\n\n```javascript\nComfyJS.Init( \"MyTwitchChannel\", null, [ \"ChannelA\", \"ChannelB\", \"ChannelC\" ] );\n```\n\n## Channel Point Reward Redemptions\n\nChannel Point Reward Redemptions require extra Twitch OAuth permission scopes (and ***must be the OAuth of the channel owner***!)\n\nYou can use this tool: [https://twitchapps.com/tokengen/](https://twitchapps.com/tokengen/)\n\nScopes: `channel:manage:redemptions channel:read:redemptions user:read:email chat:edit chat:read`\n\nInstafluff's Scopes List: `user:read:email user:read:chat chat:edit chat:read user:read:whispers user:manage:whispers channel:read:redemptions channel:read:hype_train channel:read:ads channel:read:charity channel:read:goals channel:read:guest_star channel:read:polls channel:read:predictions moderator:read:chatters moderator:read:followers user:write:chat channel:manage:redemptions moderator:manage:shoutouts channel:manage:polls channel:manage:predictions channel:manage:broadcast channel:manage:raids moderator:manage:announcements moderator:manage:automod moderator:manage:banned_users moderator:manage:chat_messages clips:edit`\n\n```javascript\nComfyJS.onReward = ( user, reward, cost, message, extra ) =\u003e {\n  console.log( user + \" redeemed \" + reward + \" for \" + cost );\n}\n```\n\nComfy.JS includes functions to manage Channel Point Rewards. These functions require the ClientID used in getting the Twitch OAuth password for the channel.\n - **GetChannelRewards**`( clientId, manageableOnly = true )`\n    - Gets the channel's rewards\n - **CreateChannelReward**`( clientId, rewardInfo )`\n    - Creates a channel point reward\n - **UpdateChannelReward**`( clientId, rewardId, rewardInfo )`\n    - Updates a channel point reward *(Only rewards created with this ClientID can be updated)*\n - **DeleteChannelReward**`( clientId, rewardId )`\n    - Deletes a channel point reward *(Only rewards created with this ClientID can be deleted)*\n\n```javascript\nlet channelRewards = await ComfyJS.GetChannelRewards( clientId, true );\n\nlet customReward = await ComfyJS.CreateChannelReward( clientId, {\n    title: \"Test Reward\",\n    prompt: \"Test Description\",\n    cost: 100,\n    is_enabled: true,\n    background_color: \"#00E5CB\",\n    is_user_input_required: false,\n    is_max_per_stream_enabled: false,\n    max_per_stream: 0,\n    is_max_per_user_per_stream_enabled: false,\n    max_per_user_per_stream: 0,\n    is_global_cooldown_enabled: false,\n    global_cooldown_seconds: 0,\n    should_redemptions_skip_request_queue: true\n} );\n\nlet updatedReward = await ComfyJS.UpdateChannelReward( clientId, customReward.id, {\n    title: \"Test Reward (Updated)\",\n    prompt: \"Updated Description\",\n    cost: 200,\n    is_enabled: true,\n} );\n\nawait ComfyJS.DeleteChannelReward( clientId, customReward.id );\n```\n\n## Disconnecting from Server\n\nYou can disconnect from the server and all channels by using `Disconnect()`.\n\n```javascript\nComfyJS.Disconnect();\n```\n\n## All Supported Events ##\n - **onCommand**`( user, command, message, flags, extra )`\n    - Responds to \"!\" commands\n - **onChat**`( user, message, flags, self, extra )`\n    - Responds to user chatting\n - **onWhisper**`( user, message, flags, self, extra )`\n    - **REQUIRES EXTRA PERMISSION SCOPES**\n    - Responds to user whisper event\n    - Requires one of the following OAuth scopes: `user:read:whispers`, `user:manage:whispers`\n - **onMessageDeleted**`( id, extra )`\n    - Responds to chat message deleted\n - **onReward**`( user, reward, cost, message, extra )`\n    - **REQUIRES EXTRA PERMISSION SCOPES**\n    - Responds to Channel Point Redemptions\n - **onJoin**`( user, self, extra )`\n    - Responds to user joining the chat\n - **onPart**`( user, self, extra )`\n    - Responds to user leaving the chat\n - **onHosted**`( user, viewers, autohost, extra )`\n    - Responds to channel being hosted\n    - Requires being authorized as the broadcaster\n - **onBan**`( bannedUsername, extra )`\n    - Responds to a user being banned\n - **onTimeout**`( timedOutUsername, durationInSeconds, extra )`\n    - Responds to a user being timed out\n - **onRaid**`( user, viewers, extra )`\n    - Responds to raid event\n - **onCheer**`( user, message, bits, flags, extra )`\n    - Responds to user cheering\n - **onSub**`( user, message, subTierInfo, extra )`\n    - Responds to user channel subscription\n - **onResub**`( user, message, streamMonths, cumulativeMonths, subTierInfo, extra )`\n    - Responds to user channel subscription anniversary\n - **onSubGift**`( gifterUser, streakMonths, recipientUser, senderCount, subTierInfo, extra )`\n    - Responds to user gift subscription\n - **onSubMysteryGift**`( gifterUser, numbOfSubs, senderCount, subTierInfo, extra )`\n    - Responds to user sending gift subscriptions\n - **onGiftSubContinue**`( user, sender, extra )`\n    - Responds to user continuing gift subscription\n - **onHypeTrain**`( \"begin\" | \"progress\" | \"end\", level, progressToNextLevel, goalToNextLevel, totalHype, timeRemainingInMS, extra )`\n    - **REQUIRES EXTRA PERMISSION SCOPES**\n    - Responds to when a Hype Train is happening\n    - Requires one of the following OAuth scopes: `channel:read:hype_train`\n - **onShoutout**`( channelDisplayName, viewerCount, timeRemainingInMS, extra )`\n    - **REQUIRES EXTRA PERMISSION SCOPES**\n    - Responds to when streamers shoutout another channel\n    - Requires one of the following OAuth scopes: `moderator:read:shoutouts`, `moderator:manage:shoutouts`\n - **onPoll**`( \"begin\" | \"progress\" | \"end\" | \"archive\" | \"close\" | \"delete\", title, choices, votes, timeRemainingInMS, extra )`\n    - **REQUIRES EXTRA PERMISSION SCOPES**\n    - Responds to when a stream poll is happening\n    - Requires one of the following OAuth scopes: `channel:read:polls`, `channel:manage:polls`\n    - Choices and votes are sorted by # of votes automatically. Top voted choice(s) will be the first elements in `choices` and `votes`\n - **onPrediction**`( \"begin\" | \"progress\" | \"lock\" | \"end\" | \"cancel\", title, outcomes, topPredictors, timeRemainingInMS, extra )`\n    - **REQUIRES EXTRA PERMISSION SCOPES**\n    - Responds to when a stream prediction is happening\n    - Requires one of the following OAuth scopes: `channel:read:predictions`, `channel:manage:predictions`\n - **onConnected**`( address, port, isFirstConnect )`\n    - Responds when connecting to the Twitch chat.\n - **onReconnect**`( reconnectCount )`\n    - Responds when attempting to reconnect to the Twitch chat.\n - **onError**`( error )`\n    - Hook for Errors\n\n\n## Credits ##\nThank you to all the participants of this project!\n\n**Instafluff, Instafriend, Neo_TA, ChatTranslator, fydo, That_MS_Gamer, MrRayKoma, Amarogine, HunWalk, simrose4u, sparky_pugwash, soggycoffee, blackdawn1980, BooobieTrap, lizardqueen, TastyGamers101, MalForTheWin, SourBeers, Stay_Hydrated_Bot, codeaurora, DutchGamer46, TheHungerService, BungalowGlow, koralina_211, TominationTime, itsDeke, fd_god92, SushiDay, FlyToto_, Docpinecone, katori15, ScrtSolstice, QeraiX, superravemonster, Jwh1o1, Deitypotato, Stobie, Chlapicek99, tehWokes, SuperChihuahua, FranC312, FuriousFur, Moopaloo, CreativeBuilds, donaldwm, Zorchenhimer, Grognardian, ravavyr, Chibigirl24, DR4G0N_S4MUR41, PokemoHero, rekaj3773, cunavrito, TheGeekGeneration, DevMerlin, julieee22, malfunct, blazeninja3, pookiepew, xxMiabellexx, Rlchibi**\n\nThank you to everyone that helped in turning Comfy.JS into a browser module!\n\n**Instafluff, Instafriend, ChatTranslator, Gilokk0, qbotv3, That_MS_Gamer, KitAnnLIVE, simrose4u, MacabreMan2, LuRiMer313, sparky_pugwash, AbbyFabby, sethorizer, julieee22, Numb3rY, Jwh1o1, baileydale, kevkab, Stay_Hydrated_Bot, DrJavaSaurus, stresstest, BungalowGlow, Dr_Zero, NiteCrawla, fd_god92, DrEriksen, codeheir, Talk2meGooseman, sneelps, cottonsmiles, DutchGamer46, LilyHazel, Kyoslilmonster, guthron, DragosNox, sciondragons, HonestDanGames, Xynal, MerlinLeWizard, FablesGames, BrainoidGames, donaldwm, Gharrotey, RIKACHET, HeyOhKei, DevMerlin, CrimsonKnightZero, ellie_pop, ItsNaomiArt, SomaPills, TheSabbyLife, bktdakid31, IsaisChannel, thegooseofwild, itsDeke, bubblesandunicorns, jellydance, MalForTheWin, Chibigirl24, Pearcington, RikuRinku, rockysenpai24, DEAD_P1XL, codeaurora, EndlessMoonfall, fromtheannex, Optik_Nerve, qerwtr546, REAZNxxx, GoonPontoon, JesseSkinner, roberttables, pookiepew, Lannonbr, SoG_Cuicui, Deitypotato, shalomhanukkahbneishimon, UpmostKek, xeiu, skatesubzero, kingswerv, K1ng440, kaisuke, kinbiko, malfunct, BooobieTrap, Kara_Kim**\n\nThanks to everyone who joined in on adding Twitch PubSub support for Channel Point Reward Redemptions to Comfy.JS!\n\n**Instafluff, Instafriend, informathemusic, aRandomTim, shadesofpixie, That_MS_Gamer, ToeNeeHee, httpJunkie, ryanchetty_1, calguru, chrislocality, Atanerah, rekaj3773, moshiko777, fizhes, AnnaCodes, Smokestormx, TheGeekGeneration, SavenaV, KotaKlan, rosebutterfly24, Simpathey, Spationaute, DjDesidera, JupiterZky, judybelle1, Shaezonai, shineslove, airsickmammal, walaber, jellydance, LilyHazel, PainArtist, Nickloop_TTV, VerbatimStudios, silversurfer1989, BellaTriXrbsa, holloway87, Asherroth86, Tiwesday, not_your_point, JenDevelops, tenaciousw, Cuicui_off, stevis5, aranhawaii, DevMerlin, wabes1, jeckle, opti_21, sparky_pugwash, tommunist_64, DutchGamer46, DoctorArgus, simrose4u, DreamGardenPanda, onelineofme, stuyksoft, Simployed, JustinZedly, Rhedone, DrMikachu, Gurkenkater, MrDemonWolf, saltipretzelz, MerlinLeWizard, Kurokirisu, Juscekame, FuriousFur, andresurrego, MissNightcrawler, karatewump, DrillsKibo, florinpop17, Axell99Design, Ahmed_Riad_1, Keegan_GDiegen, PortaalGaming, mjewl, cheppy4444dude, Soccerdude4444, klforthwind, penguinian, 10TenArt, Atndesign, DNIStream, LoveSudoNimh, prosto_artem27, lucasnramos, A_Ninja_For_Jesus_Bruh, RedChrisMS, Lineyatronic, Totte292, A_Gold_Fish, ShiDotMoe, tbdgamer, MatthewDGroves, dota2attitude, mistersyntax, SekaCakes, llamakid29, CryptoCoyote, MurdocTurner, JeanValjean80, walpolea, Jessi8712, butschibuuuu, Cmiley6, TheFlamingWings, hehe24h, cryogen_sw, DrJavaSaurus, rota22_, julieee22, bronick16, ScrtSolstice, ghostlupo86, wake_the_beast, williamcameron2, GizmoPugLife, OG24com**\n","funding_links":["https://github.com/sponsors/instafluff","https://www.twitch.tv/instafluff","instafluff.tv"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finstafluff%2Fcomfyjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finstafluff%2Fcomfyjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finstafluff%2Fcomfyjs/lists"}