@hocuspocus/extension-webhook 1.0.1 → 1.0.2

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.
@@ -143,7 +143,7 @@ class Webhook {
143
143
  }
144
144
  }
145
145
  async onDisconnect(data) {
146
- if (!this.configuration.events.includes(exports.Events.onConnect)) {
146
+ if (!this.configuration.events.includes(exports.Events.onDisconnect)) {
147
147
  return;
148
148
  }
149
149
  await this.sendRequest(exports.Events.onDisconnect, {
@@ -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'\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
+ {"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.onDisconnect)) {\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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"}
@@ -135,7 +135,7 @@ class Webhook {
135
135
  }
136
136
  }
137
137
  async onDisconnect(data) {
138
- if (!this.configuration.events.includes(Events.onConnect)) {
138
+ if (!this.configuration.events.includes(Events.onDisconnect)) {
139
139
  return;
140
140
  }
141
141
  await this.sendRequest(Events.onDisconnect, {
@@ -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'\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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"}
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.onDisconnect)) {\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,5 +1,5 @@
1
1
  import { Doc } from 'yjs';
2
- import { Extensions } from '@tiptap/core/dist/packages/core/src/types';
2
+ import { Extensions } from '@tiptap/core';
3
3
  import { Transformer } from './types';
4
4
  export declare class Tiptap implements Transformer {
5
5
  defaultExtensions: Extensions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/extension-webhook",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "hocuspocus webhook extension",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
@@ -29,9 +29,9 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "@hocuspocus/common": "^1.0.1",
33
- "@hocuspocus/server": "^1.0.1",
34
- "@hocuspocus/transformer": "^1.0.1",
32
+ "@hocuspocus/common": "^1.0.2",
33
+ "@hocuspocus/server": "^1.0.2",
34
+ "@hocuspocus/transformer": "^1.0.2",
35
35
  "axios": "^1.2.2"
36
36
  },
37
37
  "peerDependencies": {
package/src/index.ts CHANGED
@@ -182,7 +182,7 @@ export class Webhook implements Extension {
182
182
  }
183
183
 
184
184
  async onDisconnect(data: onDisconnectPayload) {
185
- if (!this.configuration.events.includes(Events.onConnect)) {
185
+ if (!this.configuration.events.includes(Events.onDisconnect)) {
186
186
  return
187
187
  }
188
188