Skip to content

Commit

Permalink
feat: add send chat mutation
Browse files Browse the repository at this point in the history
* fix: 🐛 update broken imports

* feat: ✨ add send chat mutation

* feat: ✨ tmi.js types added

* fix: 🐛 tmi wasn't in package.json
  • Loading branch information
ColeWalker authored Nov 22, 2020
1 parent 6358c46 commit 0ff74cd
Show file tree
Hide file tree
Showing 22 changed files with 142 additions and 26 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ type ChatUser {
extend type Subscription {
newChat(channel: String!): Chat
}

extend type Mutation {
sendChat(channel: String!, message: String!): Boolean
}
```

### ChatUserLink
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"graphql-tag": "^2.11.0",
"graphql-tools": "^6.0.18",
"reflect-metadata": "^0.1.13",
"tmi.js": "^1.5.0",
"twitch": "^4.1.3",
"twitch-chat-client": "^4.1.3",
"twitch-pubsub-client": "^4.1.3"
Expand All @@ -54,6 +55,7 @@
"@types/cors": "^2.8.7",
"@types/express": "^4.17.7",
"@types/jest": "^26.0.10",
"@types/tmi.js": "^1.4.2",
"apollo-server": "^2.18.1",
"apollo-server-testing": "^2.18.2",
"concurrently": "^5.3.0",
Expand Down
2 changes: 1 addition & 1 deletion src/channel-points/RedemptionListener.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PubSubClient } from 'twitch-pubsub-client/lib'
import { PubSubClient } from 'twitch-pubsub-client'

export default async function (channelID: string, pubSubClient: PubSubClient) {
return await pubSubClient.onRedemption(channelID, (message) => {
Expand Down
22 changes: 21 additions & 1 deletion src/helpers/RefreshToken.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from 'axios'
import { AuthProvider, StaticAuthProvider } from 'twitch/lib'
import { AuthProvider, StaticAuthProvider } from 'twitch'
import { error } from 'console'
require('dotenv').config()

Expand All @@ -26,3 +26,23 @@ export default async (

return authProvider
}

export async function rawToken(
client_id?: string,
client_secret?: string,
refresh_token?: string
): Promise<string> {
const clientId = client_id || process.env.USER_ID || ''
const clientSecret = client_secret || process.env.SECRET || ''
const refreshToken = refresh_token || process.env.REFRESH_TOKEN || ''
if (!clientId?.length || !clientSecret?.length || !refreshToken?.length) {
throw error('env not loading properly')
}
const raw = await axios.post(
`https://id.twitch.tv/oauth2/token?grant_type=refresh_token&refresh_token=${refreshToken}&client_id=${clientId}&client_secret=${clientSecret}`
)

const accessToken = raw.data.access_token

return accessToken
}
2 changes: 1 addition & 1 deletion src/helpers/ServerSetup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApiClient } from 'twitch/lib'
import { ApiClient } from 'twitch'
import RefreshToken from './RefreshToken'
import express from 'express'
import { PubSub } from 'graphql-subscriptions'
Expand Down
2 changes: 1 addition & 1 deletion src/schema/bit-pubsub-user-link-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createModule, gql } from 'graphql-modules'
import { PubSubBitsMessage } from 'twitch-pubsub-client'
import { ApiClient } from 'twitch/lib'
import { ApiClient } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'
export const BitUserLinkResolvers = {
Bit: {
Expand Down
36 changes: 34 additions & 2 deletions src/schema/chat-pubsub-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createModule, gql } from 'graphql-modules'
import asyncify from 'callback-to-async-iterator'
import { ChatClient } from 'twitch-chat-client'
import RefreshToken from '../helpers/RefreshToken'
import RefreshToken, { rawToken } from '../helpers/RefreshToken'
import tmi from 'tmi.js'

export interface Chat {
channel: string
Expand All @@ -13,7 +14,7 @@ export const ChatPubSubResolvers = {
Subscription: {
newChat: {
subscribe: async (
_: any,
_: unknown,
args: { channel: string },
{ user_id, secret, refresh_token }: GraphQLModules.Context
) => {
Expand Down Expand Up @@ -42,6 +43,33 @@ export const ChatPubSubResolvers = {
},
},
},
Mutation: {
sendChat: async (
_: any,
args: { channel: string; message: string },
{ user_id, secret, refresh_token, twitch_id }: GraphQLModules.Context
) => {
const password = await rawToken(user_id, secret, refresh_token)

try {
const chatClient = tmi.Client({
identity: { username: twitch_id, password },
connection: {
reconnect: true,
},
channels: [args.channel],
})
await chatClient.connect()
await chatClient.say(args.channel, args.message)
await chatClient.disconnect()
} catch (err) {
console.error(err)
return false
}

return true
},
},
}

export const ChatPubSubSchema = gql`
Expand All @@ -68,6 +96,10 @@ export const ChatPubSubSchema = gql`
extend type Subscription {
newChat(channel: String!): Chat
}
extend type Mutation {
sendChat(channel: String!, message: String!): Boolean
}
`

export const ChatPubSubModule = createModule({
Expand Down
2 changes: 1 addition & 1 deletion src/schema/chat-pubsub-user-link-schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createModule, gql } from 'graphql-modules'
import { ApiClient } from 'twitch/lib'
import { ApiClient } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

import { Chat } from './chat-pubsub-type-schema'
Expand Down
2 changes: 1 addition & 1 deletion src/schema/follow-pubsub-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createModule, gql } from 'graphql-modules'
import { ApiClient } from 'twitch/lib'
import { ApiClient } from 'twitch'
import asyncify from 'callback-to-async-iterator'
import RefreshToken from '../helpers/RefreshToken'
import { HelixFollow } from 'twitch'
Expand Down
2 changes: 1 addition & 1 deletion src/schema/game-type-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
validationMock,
} from '../tests/mocks'
import { StreamUserLinkModule } from './stream-user-link-type-schema'
import { ApiClient, HelixGame } from 'twitch/lib'
import { ApiClient, HelixGame } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'
nock(`https://id.twitch.tv`)
.post('/oauth2/token')
Expand Down
4 changes: 2 additions & 2 deletions src/schema/redemption-pubsub-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createModule, gql } from 'graphql-modules'
import asyncify from 'callback-to-async-iterator'
import { PubSubClient } from 'twitch-pubsub-client/lib'
import { ApiClient } from 'twitch/lib'
import { PubSubClient } from 'twitch-pubsub-client'
import { ApiClient } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

export const RedemptionPubSubResolvers = {
Expand Down
4 changes: 2 additions & 2 deletions src/schema/redemption-pubsub-user-link-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createModule, gql } from 'graphql-modules'
import { PubSubRedemptionMessage } from 'twitch-pubsub-client/lib'
import { ApiClient } from 'twitch/lib'
import { PubSubRedemptionMessage } from 'twitch-pubsub-client'
import { ApiClient } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

export const RedemptionUserLinkResolvers = {
Expand Down
2 changes: 1 addition & 1 deletion src/schema/stream-type-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
authenticationMock,
validationMock,
} from '../tests/mocks'
import { ApiClient, HelixStream } from 'twitch/lib'
import { ApiClient, HelixStream } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'
nock(`https://id.twitch.tv`)
.post('/oauth2/token')
Expand Down
3 changes: 1 addition & 2 deletions src/schema/stream-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createModule, gql } from 'graphql-modules'
import { ApiClient, HelixStream, HelixStreamData } from 'twitch'
import { HelixStreamFilter } from 'twitch/lib/API/Helix/Stream/HelixStreamApi'
import RefreshToken from '../helpers/RefreshToken'

export const StreamResolvers = {
Expand All @@ -23,7 +22,7 @@ export const StreamResolvers = {
)?.map((x) => x.id)
}

const streamFilter: HelixStreamFilter = {
const streamFilter: any = {
...args.streamFilter,
game: args.streamFilter?.gameIds
? [...args.streamFilter?.gameIds, ...gameIds]
Expand Down
2 changes: 1 addition & 1 deletion src/schema/subscriber-type-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
authenticationMock,
validationMock,
} from '../tests/mocks'
import { ApiClient, HelixSubscription } from 'twitch/lib'
import { ApiClient, HelixSubscription } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

nock(`https://id.twitch.tv`)
Expand Down
2 changes: 1 addition & 1 deletion src/schema/subscriber-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createModule, gql } from 'graphql-modules'
import { getLatestSub } from '../subscriptions/GetLatestSub'
import { ApiClient, HelixSubscription } from 'twitch/lib'
import { ApiClient, HelixSubscription } from 'twitch'
import { getSubs } from '../subscriptions/GetSubs'
import { getCurrentSubCount } from '../subscriptions/SubCount'
import { getRandomSub } from '../subscriptions/GetRandomSub'
Expand Down
4 changes: 2 additions & 2 deletions src/schema/subscription-pubsub-type-schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createModule, gql } from 'graphql-modules'
import asyncify from 'callback-to-async-iterator'
import { PubSubClient } from 'twitch-pubsub-client/lib'
import { ApiClient } from 'twitch/lib'
import { PubSubClient } from 'twitch-pubsub-client'
import { ApiClient } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

export const SubscriptionPubSubResolvers = {
Expand Down
2 changes: 1 addition & 1 deletion src/schema/subscription-pubsub-user-link-schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createModule, gql } from 'graphql-modules'
import { PubSubSubscriptionMessage } from 'twitch-pubsub-client'
import { ApiClient } from 'twitch/lib'
import { ApiClient } from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

export const SubscriptionPubSubUserLinkResolvers = {
Expand Down
2 changes: 1 addition & 1 deletion src/schema/user-subscriber-link-type-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
HelixBroadcasterType,
HelixUser,
HelixUserType,
} from 'twitch/lib'
} from 'twitch'
import RefreshToken from '../helpers/RefreshToken'
nock(`https://id.twitch.tv`)
.post('/oauth2/token')
Expand Down
2 changes: 1 addition & 1 deletion src/schema/user-type-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
HelixFollow,
HelixUser,
HelixUserType,
} from 'twitch/lib'
} from 'twitch'
import RefreshToken from '../helpers/RefreshToken'

nock(`https://id.twitch.tv`)
Expand Down
2 changes: 1 addition & 1 deletion src/subscriptions/SubscriptionListener.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PubSubClient } from 'twitch-pubsub-client/lib'
import { PubSubClient } from 'twitch-pubsub-client'

import { getCurrentSubCount } from './SubCount'
import { ApiClient } from 'twitch'
Expand Down
63 changes: 61 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1879,6 +1879,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==

"@types/tmi.js@^1.4.2":
version "1.4.2"
resolved "https://registry.yarnpkg.com/@types/tmi.js/-/tmi.js-1.4.2.tgz#0eeecb2665d60ccfe7cec9755c905d3022456975"
integrity sha512-EqIctOMPIleqMAnXeCPe7QYt4/kwKQJWxgi6/PbXxVL+Z1w+Ow64QuAahgCDt82XPtnn8fmjJ77XKsiFiLvooQ==

"@types/websocket@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.1.tgz#039272c196c2c0e4868a0d8a1a27bbb86e9e9138"
Expand Down Expand Up @@ -4780,7 +4785,7 @@ har-schema@^2.0.0:
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=

har-validator@~5.1.3:
har-validator@~5.1.0, har-validator@~5.1.3:
version "5.1.5"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
Expand Down Expand Up @@ -7989,7 +7994,7 @@ pseudomap@^1.0.2:
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=

psl@^1.1.28:
psl@^1.1.24, psl@^1.1.28:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
Expand Down Expand Up @@ -8024,6 +8029,11 @@ pumpify@^1.3.3:
inherits "^2.0.3"
pump "^2.0.0"

punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=

punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
Expand Down Expand Up @@ -8389,6 +8399,32 @@ request-promise-native@^1.0.8:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"

request@2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.0"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.4.3"
tunnel-agent "^0.6.0"
uuid "^3.3.2"

request@^2.88.0, request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
Expand Down Expand Up @@ -9369,6 +9405,14 @@ tiny-relative-date@^1.3.0:
resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==

tmi.js@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/tmi.js/-/tmi.js-1.5.0.tgz#746e7d66bafdc4eb23b4bb0b306a3287c637282b"
integrity sha512-JyWKy9dRkZDG1h6PnpE8fJVsTrW82/yANXoP7R3u02vG7PLCvHGRGTWzBwk0ymMJGX9A+YzDx5tXQDsTeJd/5A==
dependencies:
request "2.88.0"
ws "6.1.3"

tmpl@1.0.x:
version "1.0.4"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
Expand Down Expand Up @@ -9450,6 +9494,14 @@ tough-cookie@^3.0.1:
psl "^1.1.28"
punycode "^2.1.1"

tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
dependencies:
psl "^1.1.24"
punycode "^1.4.1"

tr46@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479"
Expand Down Expand Up @@ -10158,6 +10210,13 @@ write-file-atomic@^3.0.0:
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"

ws@6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.3.tgz#d2d2e5f0e3c700ef2de89080ebc0ac6e1bf3a72d"
integrity sha512-tbSxiT+qJI223AP4iLfQbkbxkwdFcneYinM2+x46Gx2wgvbaOMO36czfdfVUBRTHvzAMRhDd98sA5d/BuWbQdg==
dependencies:
async-limiter "~1.0.0"

ws@^5.2.0:
version "5.2.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"
Expand Down

0 comments on commit 0ff74cd

Please sign in to comment.