@hocuspocus/extension-webhook 1.0.0-beta.2 → 1.0.0-beta.4

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.
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var crypto = require('crypto');
6
6
  var transformer = require('@hocuspocus/transformer');
7
7
  var axios = require('axios');
8
+ var common = require('@hocuspocus/common');
8
9
 
9
10
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
11
 
@@ -137,8 +138,8 @@ class Webhook {
137
138
  : response.data;
138
139
  }
139
140
  catch (e) {
140
- // eslint-disable-next-line no-throw-literal
141
- throw null;
141
+ console.error(`Caught error in extension-webhook: ${e}`);
142
+ throw common.Forbidden;
142
143
  }
143
144
  }
144
145
  async onDisconnect(data) {
@@ -1 +1 @@
1
- {"version":3,"file":"hocuspocus-webhook.cjs","sources":["../src/index.ts"],"sourcesContent":["import { createHmac } from 'crypto'\nimport {\n Extension,\n onChangePayload,\n onConnectPayload,\n onLoadDocumentPayload,\n onDisconnectPayload,\n} from '@hocuspocus/server'\nimport { Doc } from 'yjs'\nimport { TiptapTransformer, Transformer } from '@hocuspocus/transformer'\nimport axios, { AxiosResponse } from 'axios'\n\nexport enum Events {\n onChange = 'change',\n onConnect = 'connect',\n onCreate = 'create',\n onDisconnect = 'disconnect',\n}\n\nexport interface Configuration {\n debounce: number | false | null,\n debounceMaxWait: number,\n secret: string,\n transformer: Transformer | {\n toYdoc: (document: any) => Doc,\n fromYdoc: (document: Doc) => any,\n },\n url: string,\n events: Array<Events>,\n}\n\nexport class Webhook implements Extension {\n\n configuration: Configuration = {\n debounce: 2000,\n debounceMaxWait: 10000,\n secret: '',\n transformer: TiptapTransformer,\n url: '',\n events: [\n Events.onChange,\n ],\n }\n\n debounced: Map<string, { timeout: NodeJS.Timeout, start: number }> = new Map()\n\n /**\n * Constructor\n */\n constructor(configuration?: Partial<Configuration>) {\n this.configuration = {\n ...this.configuration,\n ...configuration,\n }\n\n if (!this.configuration.url) {\n throw new Error('url is required!')\n }\n }\n\n /**\n * Create a signature for the response body\n */\n createSignature(body: string): string {\n const hmac = createHmac('sha256', this.configuration.secret)\n\n return `sha256=${hmac.update(body).digest('hex')}`\n }\n\n /**\n * debounce the given function, using the given identifier\n */\n debounce(id: string, func: Function) {\n const old = this.debounced.get(id)\n const start = old?.start || Date.now()\n\n const run = () => {\n this.debounced.delete(id)\n func()\n }\n\n if (old?.timeout) clearTimeout(old.timeout)\n if (Date.now() - start >= this.configuration.debounceMaxWait) return run()\n\n this.debounced.set(id, {\n start,\n timeout: setTimeout(run, <number> this.configuration.debounce),\n })\n }\n\n /**\n * Send a request to the given url containing the given data\n */\n async sendRequest(event: Events, payload: any) {\n const json = JSON.stringify({ event, payload })\n\n return axios.post(\n this.configuration.url,\n json,\n { headers: { 'X-Hocuspocus-Signature-256': this.createSignature(json), 'Content-Type': 'application/json' } },\n )\n }\n\n /**\n * onChange hook\n */\n async onChange(data: onChangePayload) {\n if (!this.configuration.events.includes(Events.onChange)) {\n return\n }\n\n const save = () => {\n this.sendRequest(Events.onChange, {\n document: this.configuration.transformer.fromYdoc(data.document),\n documentName: data.documentName,\n context: data.context,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n }\n\n if (!this.configuration.debounce) {\n return save()\n }\n\n this.debounce(data.documentName, save)\n }\n\n /**\n * onLoadDocument hook\n */\n async onLoadDocument(data: onLoadDocumentPayload) {\n if (!this.configuration.events.includes(Events.onCreate)) {\n return\n }\n\n const response = <AxiosResponse> await this.sendRequest(Events.onCreate, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n if (response.status !== 200 || !response.data) return\n\n const document = typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n\n // eslint-disable-next-line guard-for-in,no-restricted-syntax\n for (const fieldName in document) {\n if (data.document.isEmpty(fieldName)) {\n data.document.merge(\n this.configuration.transformer.toYdoc(document[fieldName], fieldName),\n )\n }\n }\n }\n\n /**\n * onConnect hook\n */\n async onConnect(data: onConnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n try {\n const response = <AxiosResponse> await this.sendRequest(Events.onConnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n return typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n } catch (e) {\n // eslint-disable-next-line no-throw-literal\n throw null\n }\n }\n\n async onDisconnect(data: onDisconnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n await this.sendRequest(Events.onDisconnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n context: data.context,\n })\n }\n\n}\n"],"names":["Events","TiptapTransformer","createHmac","axios"],"mappings":"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"}
1
+ {"version":3,"file":"hocuspocus-webhook.cjs","sources":["../src/index.ts"],"sourcesContent":["import { createHmac } from 'crypto'\nimport {\n Extension,\n onChangePayload,\n onConnectPayload,\n onLoadDocumentPayload,\n onDisconnectPayload,\n} from '@hocuspocus/server'\nimport { Doc } from 'yjs'\nimport { TiptapTransformer, Transformer } from '@hocuspocus/transformer'\nimport axios, { AxiosResponse } from 'axios'\nimport { Forbidden } from '@hocuspocus/common'\n\nexport enum Events {\n onChange = 'change',\n onConnect = 'connect',\n onCreate = 'create',\n onDisconnect = 'disconnect',\n}\n\nexport interface Configuration {\n debounce: number | false | null,\n debounceMaxWait: number,\n secret: string,\n transformer: Transformer | {\n toYdoc: (document: any) => Doc,\n fromYdoc: (document: Doc) => any,\n },\n url: string,\n events: Array<Events>,\n}\n\nexport class Webhook implements Extension {\n\n configuration: Configuration = {\n debounce: 2000,\n debounceMaxWait: 10000,\n secret: '',\n transformer: TiptapTransformer,\n url: '',\n events: [\n Events.onChange,\n ],\n }\n\n debounced: Map<string, { timeout: NodeJS.Timeout, start: number }> = new Map()\n\n /**\n * Constructor\n */\n constructor(configuration?: Partial<Configuration>) {\n this.configuration = {\n ...this.configuration,\n ...configuration,\n }\n\n if (!this.configuration.url) {\n throw new Error('url is required!')\n }\n }\n\n /**\n * Create a signature for the response body\n */\n createSignature(body: string): string {\n const hmac = createHmac('sha256', this.configuration.secret)\n\n return `sha256=${hmac.update(body).digest('hex')}`\n }\n\n /**\n * debounce the given function, using the given identifier\n */\n debounce(id: string, func: Function) {\n const old = this.debounced.get(id)\n const start = old?.start || Date.now()\n\n const run = () => {\n this.debounced.delete(id)\n func()\n }\n\n if (old?.timeout) clearTimeout(old.timeout)\n if (Date.now() - start >= this.configuration.debounceMaxWait) return run()\n\n this.debounced.set(id, {\n start,\n timeout: setTimeout(run, <number> this.configuration.debounce),\n })\n }\n\n /**\n * Send a request to the given url containing the given data\n */\n async sendRequest(event: Events, payload: any) {\n const json = JSON.stringify({ event, payload })\n\n return axios.post(\n this.configuration.url,\n json,\n { headers: { 'X-Hocuspocus-Signature-256': this.createSignature(json), 'Content-Type': 'application/json' } },\n )\n }\n\n /**\n * onChange hook\n */\n async onChange(data: onChangePayload) {\n if (!this.configuration.events.includes(Events.onChange)) {\n return\n }\n\n const save = () => {\n this.sendRequest(Events.onChange, {\n document: this.configuration.transformer.fromYdoc(data.document),\n documentName: data.documentName,\n context: data.context,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n }\n\n if (!this.configuration.debounce) {\n return save()\n }\n\n this.debounce(data.documentName, save)\n }\n\n /**\n * onLoadDocument hook\n */\n async onLoadDocument(data: onLoadDocumentPayload) {\n if (!this.configuration.events.includes(Events.onCreate)) {\n return\n }\n\n const response = <AxiosResponse> await this.sendRequest(Events.onCreate, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n if (response.status !== 200 || !response.data) return\n\n const document = typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n\n // eslint-disable-next-line guard-for-in,no-restricted-syntax\n for (const fieldName in document) {\n if (data.document.isEmpty(fieldName)) {\n data.document.merge(\n this.configuration.transformer.toYdoc(document[fieldName], fieldName),\n )\n }\n }\n }\n\n /**\n * onConnect hook\n */\n async onConnect(data: onConnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n try {\n const response = <AxiosResponse> await this.sendRequest(Events.onConnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n return typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n } catch (e) {\n console.error(`Caught error in extension-webhook: ${e}`)\n throw Forbidden\n }\n }\n\n async onDisconnect(data: onDisconnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n await this.sendRequest(Events.onDisconnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n context: data.context,\n })\n }\n\n}\n"],"names":["Events","TiptapTransformer","createHmac","axios","Forbidden"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { createHmac } from 'crypto';
2
2
  import { TiptapTransformer } from '@hocuspocus/transformer';
3
3
  import axios from 'axios';
4
+ import { Forbidden } from '@hocuspocus/common';
4
5
 
5
6
  var Events;
6
7
  (function (Events) {
@@ -129,8 +130,8 @@ class Webhook {
129
130
  : response.data;
130
131
  }
131
132
  catch (e) {
132
- // eslint-disable-next-line no-throw-literal
133
- throw null;
133
+ console.error(`Caught error in extension-webhook: ${e}`);
134
+ throw Forbidden;
134
135
  }
135
136
  }
136
137
  async onDisconnect(data) {
@@ -1 +1 @@
1
- {"version":3,"file":"hocuspocus-webhook.esm.js","sources":["../src/index.ts"],"sourcesContent":["import { createHmac } from 'crypto'\nimport {\n Extension,\n onChangePayload,\n onConnectPayload,\n onLoadDocumentPayload,\n onDisconnectPayload,\n} from '@hocuspocus/server'\nimport { Doc } from 'yjs'\nimport { TiptapTransformer, Transformer } from '@hocuspocus/transformer'\nimport axios, { AxiosResponse } from 'axios'\n\nexport enum Events {\n onChange = 'change',\n onConnect = 'connect',\n onCreate = 'create',\n onDisconnect = 'disconnect',\n}\n\nexport interface Configuration {\n debounce: number | false | null,\n debounceMaxWait: number,\n secret: string,\n transformer: Transformer | {\n toYdoc: (document: any) => Doc,\n fromYdoc: (document: Doc) => any,\n },\n url: string,\n events: Array<Events>,\n}\n\nexport class Webhook implements Extension {\n\n configuration: Configuration = {\n debounce: 2000,\n debounceMaxWait: 10000,\n secret: '',\n transformer: TiptapTransformer,\n url: '',\n events: [\n Events.onChange,\n ],\n }\n\n debounced: Map<string, { timeout: NodeJS.Timeout, start: number }> = new Map()\n\n /**\n * Constructor\n */\n constructor(configuration?: Partial<Configuration>) {\n this.configuration = {\n ...this.configuration,\n ...configuration,\n }\n\n if (!this.configuration.url) {\n throw new Error('url is required!')\n }\n }\n\n /**\n * Create a signature for the response body\n */\n createSignature(body: string): string {\n const hmac = createHmac('sha256', this.configuration.secret)\n\n return `sha256=${hmac.update(body).digest('hex')}`\n }\n\n /**\n * debounce the given function, using the given identifier\n */\n debounce(id: string, func: Function) {\n const old = this.debounced.get(id)\n const start = old?.start || Date.now()\n\n const run = () => {\n this.debounced.delete(id)\n func()\n }\n\n if (old?.timeout) clearTimeout(old.timeout)\n if (Date.now() - start >= this.configuration.debounceMaxWait) return run()\n\n this.debounced.set(id, {\n start,\n timeout: setTimeout(run, <number> this.configuration.debounce),\n })\n }\n\n /**\n * Send a request to the given url containing the given data\n */\n async sendRequest(event: Events, payload: any) {\n const json = JSON.stringify({ event, payload })\n\n return axios.post(\n this.configuration.url,\n json,\n { headers: { 'X-Hocuspocus-Signature-256': this.createSignature(json), 'Content-Type': 'application/json' } },\n )\n }\n\n /**\n * onChange hook\n */\n async onChange(data: onChangePayload) {\n if (!this.configuration.events.includes(Events.onChange)) {\n return\n }\n\n const save = () => {\n this.sendRequest(Events.onChange, {\n document: this.configuration.transformer.fromYdoc(data.document),\n documentName: data.documentName,\n context: data.context,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n }\n\n if (!this.configuration.debounce) {\n return save()\n }\n\n this.debounce(data.documentName, save)\n }\n\n /**\n * onLoadDocument hook\n */\n async onLoadDocument(data: onLoadDocumentPayload) {\n if (!this.configuration.events.includes(Events.onCreate)) {\n return\n }\n\n const response = <AxiosResponse> await this.sendRequest(Events.onCreate, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n if (response.status !== 200 || !response.data) return\n\n const document = typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n\n // eslint-disable-next-line guard-for-in,no-restricted-syntax\n for (const fieldName in document) {\n if (data.document.isEmpty(fieldName)) {\n data.document.merge(\n this.configuration.transformer.toYdoc(document[fieldName], fieldName),\n )\n }\n }\n }\n\n /**\n * onConnect hook\n */\n async onConnect(data: onConnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n try {\n const response = <AxiosResponse> await this.sendRequest(Events.onConnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n return typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n } catch (e) {\n // eslint-disable-next-line no-throw-literal\n throw null\n }\n }\n\n async onDisconnect(data: onDisconnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n await this.sendRequest(Events.onDisconnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n context: data.context,\n })\n }\n\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hocuspocus-webhook.esm.js","sources":["../src/index.ts"],"sourcesContent":["import { createHmac } from 'crypto'\nimport {\n Extension,\n onChangePayload,\n onConnectPayload,\n onLoadDocumentPayload,\n onDisconnectPayload,\n} from '@hocuspocus/server'\nimport { Doc } from 'yjs'\nimport { TiptapTransformer, Transformer } from '@hocuspocus/transformer'\nimport axios, { AxiosResponse } from 'axios'\nimport { Forbidden } from '@hocuspocus/common'\n\nexport enum Events {\n onChange = 'change',\n onConnect = 'connect',\n onCreate = 'create',\n onDisconnect = 'disconnect',\n}\n\nexport interface Configuration {\n debounce: number | false | null,\n debounceMaxWait: number,\n secret: string,\n transformer: Transformer | {\n toYdoc: (document: any) => Doc,\n fromYdoc: (document: Doc) => any,\n },\n url: string,\n events: Array<Events>,\n}\n\nexport class Webhook implements Extension {\n\n configuration: Configuration = {\n debounce: 2000,\n debounceMaxWait: 10000,\n secret: '',\n transformer: TiptapTransformer,\n url: '',\n events: [\n Events.onChange,\n ],\n }\n\n debounced: Map<string, { timeout: NodeJS.Timeout, start: number }> = new Map()\n\n /**\n * Constructor\n */\n constructor(configuration?: Partial<Configuration>) {\n this.configuration = {\n ...this.configuration,\n ...configuration,\n }\n\n if (!this.configuration.url) {\n throw new Error('url is required!')\n }\n }\n\n /**\n * Create a signature for the response body\n */\n createSignature(body: string): string {\n const hmac = createHmac('sha256', this.configuration.secret)\n\n return `sha256=${hmac.update(body).digest('hex')}`\n }\n\n /**\n * debounce the given function, using the given identifier\n */\n debounce(id: string, func: Function) {\n const old = this.debounced.get(id)\n const start = old?.start || Date.now()\n\n const run = () => {\n this.debounced.delete(id)\n func()\n }\n\n if (old?.timeout) clearTimeout(old.timeout)\n if (Date.now() - start >= this.configuration.debounceMaxWait) return run()\n\n this.debounced.set(id, {\n start,\n timeout: setTimeout(run, <number> this.configuration.debounce),\n })\n }\n\n /**\n * Send a request to the given url containing the given data\n */\n async sendRequest(event: Events, payload: any) {\n const json = JSON.stringify({ event, payload })\n\n return axios.post(\n this.configuration.url,\n json,\n { headers: { 'X-Hocuspocus-Signature-256': this.createSignature(json), 'Content-Type': 'application/json' } },\n )\n }\n\n /**\n * onChange hook\n */\n async onChange(data: onChangePayload) {\n if (!this.configuration.events.includes(Events.onChange)) {\n return\n }\n\n const save = () => {\n this.sendRequest(Events.onChange, {\n document: this.configuration.transformer.fromYdoc(data.document),\n documentName: data.documentName,\n context: data.context,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n }\n\n if (!this.configuration.debounce) {\n return save()\n }\n\n this.debounce(data.documentName, save)\n }\n\n /**\n * onLoadDocument hook\n */\n async onLoadDocument(data: onLoadDocumentPayload) {\n if (!this.configuration.events.includes(Events.onCreate)) {\n return\n }\n\n const response = <AxiosResponse> await this.sendRequest(Events.onCreate, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n if (response.status !== 200 || !response.data) return\n\n const document = typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n\n // eslint-disable-next-line guard-for-in,no-restricted-syntax\n for (const fieldName in document) {\n if (data.document.isEmpty(fieldName)) {\n data.document.merge(\n this.configuration.transformer.toYdoc(document[fieldName], fieldName),\n )\n }\n }\n }\n\n /**\n * onConnect hook\n */\n async onConnect(data: onConnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n try {\n const response = <AxiosResponse> await this.sendRequest(Events.onConnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n })\n\n return typeof response.data === 'string'\n ? JSON.parse(response.data)\n : response.data\n } catch (e) {\n console.error(`Caught error in extension-webhook: ${e}`)\n throw Forbidden\n }\n }\n\n async onDisconnect(data: onDisconnectPayload) {\n if (!this.configuration.events.includes(Events.onConnect)) {\n return\n }\n\n await this.sendRequest(Events.onDisconnect, {\n documentName: data.documentName,\n requestHeaders: data.requestHeaders,\n requestParameters: Object.fromEntries(data.requestParameters.entries()),\n context: data.context,\n })\n }\n\n}\n"],"names":[],"mappings":"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"}
@@ -53,13 +53,6 @@ export declare class Connection {
53
53
  * @private
54
54
  */
55
55
  private handleMessage;
56
- /**
57
- * Handle a ws instance error, which is required to prevent
58
- * the server from crashing when one happens
59
- * See https://github.com/websockets/ws/issues/1777#issuecomment-660803472
60
- * @private
61
- */
62
- private handleError;
63
56
  /**
64
57
  * Get the underlying connection instance
65
58
  * @deprecated
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/extension-webhook",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "hocuspocus webhook extension",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
@@ -29,9 +29,12 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "@hocuspocus/server": "^1.0.0-beta.2",
33
- "@hocuspocus/transformer": "^1.0.0-beta.2",
34
- "axios": "^0.27.2",
32
+ "@hocuspocus/common": "^1.0.0-beta.4",
33
+ "@hocuspocus/server": "^1.0.0-beta.4",
34
+ "@hocuspocus/transformer": "^1.0.0-beta.4",
35
+ "axios": "^0.27.2"
36
+ },
37
+ "peerDependencies": {
35
38
  "yjs": "^13.5.29"
36
39
  },
37
40
  "gitHead": "b3454a4ca289a84ddfb7fa5607a2d4b8d5c37e9d"
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  import { Doc } from 'yjs'
10
10
  import { TiptapTransformer, Transformer } from '@hocuspocus/transformer'
11
11
  import axios, { AxiosResponse } from 'axios'
12
+ import { Forbidden } from '@hocuspocus/common'
12
13
 
13
14
  export enum Events {
14
15
  onChange = 'change',
@@ -175,8 +176,8 @@ export class Webhook implements Extension {
175
176
  ? JSON.parse(response.data)
176
177
  : response.data
177
178
  } catch (e) {
178
- // eslint-disable-next-line no-throw-literal
179
- throw null
179
+ console.error(`Caught error in extension-webhook: ${e}`)
180
+ throw Forbidden
180
181
  }
181
182
  }
182
183