Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use gcl-slack through Fastify, as a Fastify-plugin or Cloud Functions.
- Loading branch information
1 parent
0e549c1
commit c13c88b
Showing
16 changed files
with
4,901 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module.exports = { | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
testPathIgnorePatterns: [ | ||
'.*/fixtures.ts', | ||
'.*/__fixtures__/*', | ||
'.*/*.fixtures.ts', | ||
'.*/dist/.*', | ||
'.*dist.*', | ||
], | ||
collectCoverageFrom: ['src/**/{!(fixtures),}.ts'], | ||
coverageThreshold: { | ||
global: { | ||
branches: 80, | ||
functions: 80, | ||
lines: 80, | ||
statements: -10, | ||
}, | ||
}, | ||
globals: { | ||
'ts-jest': { | ||
tsconfig: 'tsconfig.jest.json', | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{ | ||
"name": "gcl-slack", | ||
"version": "1.0.0", | ||
"private": false, | ||
"repository": "github:bjerkio/gcl-slack", | ||
"license": "Apache-2.0", | ||
"author": "Bjerk AS", | ||
"main": "./dist/cjs/index.js", | ||
"module": "./dist/index.js", | ||
"source": "src/index.ts", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"dist/" | ||
], | ||
"scripts": { | ||
"build": "tsc && tsc -p tsconfig.cjs.json", | ||
"lint": "eslint 'src/**/*.ts' --fix", | ||
"test": "jest --coverage src", | ||
"prepare": "husky install .github/husky" | ||
}, | ||
"devDependencies": { | ||
"@bjerk/eslint-config": "^1.0.0", | ||
"@types/jest": "^27.0.1", | ||
"eslint": "^7.32.0", | ||
"husky": "^7.0.2", | ||
"jest": "^27.1.0", | ||
"lint-staged": "^11.1.2", | ||
"nock": "^13.1.3", | ||
"prettier": "^2.3.2", | ||
"ts-jest": "^27.0.5", | ||
"typescript": "^3.9" | ||
}, | ||
"dependencies": { | ||
"@slack-wrench/jest-mock-web-client": "^1.3.0", | ||
"@slack/web-api": "^6.4.0", | ||
"axios": "^0.21.1", | ||
"fastify": "^3.20.2", | ||
"pubsub-http-handler": "^2.0.0", | ||
"runtypes": "^6.3.2" | ||
}, | ||
"lint-staged": { | ||
"*.ts": [ | ||
"prettier --write", | ||
"yarn run eslint" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import mockWebApi from '@slack-wrench/jest-mock-web-client'; | ||
module.exports = mockWebApi(jest); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { MockedWebClient } from '@slack-wrench/jest-mock-web-client'; | ||
import { SlackApiMethod } from '../methods/api'; | ||
import { createLogEntry } from './fixtures'; | ||
|
||
describe('api', () => { | ||
const m = new SlackApiMethod({ | ||
token: 'a-token', | ||
defaultChannel: 'my-channel', | ||
}); | ||
|
||
it('must send simple messages to Slack API', async () => { | ||
await m.send(createLogEntry('hello-world')); | ||
|
||
expect( | ||
MockedWebClient.mock.instances[0].chat.postMessage, | ||
).toHaveBeenCalledWith({ | ||
channel: 'my-channel', | ||
text: 'hello-world', | ||
}); | ||
}); | ||
|
||
it('must send simple JSON Objects to Slack API', async () => { | ||
await m.send(createLogEntry({ message: 'hello world message' })); | ||
|
||
expect( | ||
MockedWebClient.mock.instances[0].chat.postMessage, | ||
).toHaveBeenCalledWith({ | ||
channel: 'my-channel', | ||
text: 'hello world message', | ||
}); | ||
}); | ||
|
||
it('must send requests with object to Slack API', async () => { | ||
await m.send( | ||
createLogEntry({ | ||
slack: { | ||
text: 'hello, world', | ||
}, | ||
}), | ||
); | ||
|
||
expect( | ||
MockedWebClient.mock.instances[0].chat.postMessage, | ||
).toHaveBeenCalledWith({ | ||
channel: 'my-channel', | ||
text: 'hello, world', | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* istanbul ignore file */ | ||
import { LogEntry } from '../types'; | ||
|
||
export function createLogEntry(payload: any): LogEntry { | ||
if (typeof payload === 'string') { | ||
return { | ||
insertId: 'insertId', | ||
logName: 'logName', | ||
receiveTimestamp: 'receiveTimestamp', | ||
severity: 'INFO', | ||
timestamp: 'timestamp', | ||
textPayload: payload, | ||
}; | ||
} | ||
|
||
return { | ||
insertId: 'insertId', | ||
logName: 'logName', | ||
receiveTimestamp: 'receiveTimestamp', | ||
severity: 'INFO', | ||
timestamp: 'timestamp', | ||
jsonPayload: payload, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import nock from 'nock'; | ||
import { SlackWebhookMethod } from '../methods/webhook'; | ||
import { createLogEntry } from './fixtures'; | ||
|
||
describe('api', () => { | ||
const m = new SlackWebhookMethod({ | ||
url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX', | ||
}); | ||
const mock = nock('https://hooks.slack.com/'); | ||
|
||
it('must send simple messages to webhook', async () => { | ||
const scope = mock | ||
.post('/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX', { | ||
text: 'hello-world', | ||
}) | ||
.reply(200, 'ok'); | ||
|
||
await m.send(createLogEntry('hello-world')); | ||
|
||
expect(scope.isDone()).toBeTruthy(); | ||
}); | ||
|
||
it('must throw if webhook not replies «ok»', async () => { | ||
const scope = mock | ||
.post('/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX', { | ||
text: 'hello no service', | ||
}) | ||
.reply(404, 'no_service'); | ||
|
||
expect( | ||
m.send(createLogEntry('hello no service')), | ||
).rejects.toThrowErrorMatchingInlineSnapshot( | ||
`"Could not send request to Slack Webhook: no_service"`, | ||
); | ||
}); | ||
|
||
it('must send simple JSON Objects to webhook', async () => { | ||
const scope = mock | ||
.post('/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX', { | ||
text: 'hello world message', | ||
}) | ||
.reply(200, 'ok'); | ||
|
||
await m.send(createLogEntry({ message: 'hello world message' })); | ||
|
||
expect(scope.isDone()).toBeTruthy(); | ||
}); | ||
|
||
it('must send requests with object to webhook', async () => { | ||
const scope = mock | ||
.post('/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX', { | ||
text: 'hello, world', | ||
}) | ||
.reply(200, 'ok'); | ||
|
||
await m.send( | ||
createLogEntry({ | ||
slack: { | ||
text: 'hello, world', | ||
}, | ||
}), | ||
); | ||
|
||
expect(scope.isDone()).toBeTruthy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { PubSubHandler } from 'pubsub-http-handler'; | ||
import { SlackApiMethod } from './methods/api'; | ||
import { SlackWebhookMethod } from './methods/webhook'; | ||
import { LogEntry, SlackConfig, SlackMethod } from './types'; | ||
|
||
export function makeHandler(config: SlackConfig): PubSubHandler<LogEntry> { | ||
if (config.type !== 'api' && config.type !== 'webhook') { | ||
throw new Error('Slack config type was neither set to `api` nor `webhook`'); | ||
} | ||
|
||
let method: SlackMethod; | ||
|
||
if (config.type === 'api') { | ||
method = new SlackApiMethod(config.apiOptions); | ||
} | ||
|
||
if (config.type === 'webhook') { | ||
method = new SlackWebhookMethod(config.webhookOptions); | ||
} | ||
|
||
return async ({ data }) => { | ||
await method.send(data); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { FastifyPluginAsync } from 'fastify'; | ||
import * as phh from 'pubsub-http-handler'; | ||
import { makeHandler } from './handler'; | ||
import { SlackConfig } from './types'; | ||
export { makeHandler } from './handler'; | ||
|
||
export const makePubSubCloudFunctions = ( | ||
config: SlackConfig, | ||
): phh.CloudFunctionFun => { | ||
return phh.createPubSubCloudFunctions(makeHandler(config)); | ||
}; | ||
|
||
export const fastifyPlugin: FastifyPluginAsync<SlackConfig> = async ( | ||
fastify, | ||
config, | ||
) => { | ||
return phh.pubSubFastifyPlugin(fastify, { handler: makeHandler(config) }); | ||
}; | ||
|
||
export const makePubSubServer = ( | ||
config: SlackConfig, | ||
): phh.CreatePubSubHandlerResponse => { | ||
return phh.createPubSubServer(makeHandler(config)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { WebClient } from '@slack/web-api'; | ||
import type { LogEntry, SlackApiOptions, SlackMethod } from '../types'; | ||
|
||
export class SlackApiMethod implements SlackMethod { | ||
private client: WebClient; | ||
|
||
constructor(private readonly config: SlackApiOptions) { | ||
this.client = new WebClient(config.token, config.clientOptions); | ||
} | ||
|
||
async send(entry: LogEntry): Promise<void> { | ||
if (entry.jsonPayload?.slack) { | ||
await this.client.chat.postMessage({ | ||
channel: this.config.defaultChannel, | ||
...entry.jsonPayload.slack, | ||
}); | ||
return; | ||
} | ||
|
||
await this.client.chat.postMessage({ | ||
channel: this.config.defaultChannel, | ||
text: entry.jsonPayload?.message ?? entry.textPayload, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import axios, { AxiosError } from 'axios'; | ||
import type { LogEntry, SlackMethod, SlackWebhookOptions } from '../types'; | ||
|
||
export type WebhookResponse = 'ok' | string; | ||
|
||
export class SlackWebhookMethod implements SlackMethod { | ||
constructor(private readonly config: SlackWebhookOptions) {} | ||
|
||
async send(entry: LogEntry): Promise<void> { | ||
if (entry.jsonPayload?.slack) { | ||
await this.sendRequest(entry.jsonPayload.slack); | ||
return; | ||
} | ||
|
||
await this.sendRequest({ | ||
text: entry.jsonPayload?.message ?? entry.textPayload, | ||
}); | ||
} | ||
|
||
private async sendRequest(data: unknown): Promise<void> { | ||
await axios.post(this.config.url, data).catch((error: AxiosError) => { | ||
if (error.response) { | ||
throw new Error( | ||
`Could not send request to Slack Webhook: ${error.response.data}`, | ||
); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.