@hocuspocus/extension-webhook 3.1.2 → 3.1.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.
Files changed (50) hide show
  1. package/dist/hocuspocus-webhook.cjs +14 -11
  2. package/dist/hocuspocus-webhook.cjs.map +1 -1
  3. package/dist/hocuspocus-webhook.esm.js +14 -11
  4. package/dist/hocuspocus-webhook.esm.js.map +1 -1
  5. package/dist/packages/common/src/auth.d.ts +2 -2
  6. package/dist/packages/common/src/index.d.ts +4 -4
  7. package/dist/packages/extension-database/src/Database.d.ts +1 -1
  8. package/dist/packages/extension-database/src/index.d.ts +1 -1
  9. package/dist/packages/extension-logger/src/Logger.d.ts +1 -1
  10. package/dist/packages/extension-logger/src/index.d.ts +1 -1
  11. package/dist/packages/extension-redis/src/index.d.ts +1 -1
  12. package/dist/packages/extension-sqlite/src/SQLite.d.ts +3 -3
  13. package/dist/packages/extension-sqlite/src/index.d.ts +1 -1
  14. package/dist/packages/extension-throttle/src/index.d.ts +1 -1
  15. package/dist/packages/extension-webhook/src/index.d.ts +3 -3
  16. package/dist/packages/provider/src/HocuspocusProvider.d.ts +10 -10
  17. package/dist/packages/provider/src/IncomingMessage.d.ts +3 -3
  18. package/dist/packages/provider/src/MessageReceiver.d.ts +2 -2
  19. package/dist/packages/provider/src/OutgoingMessage.d.ts +2 -2
  20. package/dist/packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts +3 -3
  21. package/dist/packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts +4 -4
  22. package/dist/packages/provider/src/OutgoingMessages/CloseMessage.d.ts +4 -4
  23. package/dist/packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts +4 -4
  24. package/dist/packages/provider/src/OutgoingMessages/StatelessMessage.d.ts +3 -3
  25. package/dist/packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts +4 -4
  26. package/dist/packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts +4 -4
  27. package/dist/packages/provider/src/OutgoingMessages/UpdateMessage.d.ts +3 -3
  28. package/dist/packages/provider/src/index.d.ts +3 -3
  29. package/dist/packages/provider/src/types.d.ts +14 -14
  30. package/dist/packages/server/src/ClientConnection.d.ts +17 -17
  31. package/dist/packages/server/src/Connection.d.ts +6 -6
  32. package/dist/packages/server/src/DirectConnection.d.ts +3 -3
  33. package/dist/packages/server/src/Document.d.ts +4 -4
  34. package/dist/packages/server/src/Hocuspocus.d.ts +8 -8
  35. package/dist/packages/server/src/IncomingMessage.d.ts +3 -3
  36. package/dist/packages/server/src/MessageReceiver.d.ts +3 -3
  37. package/dist/packages/server/src/OutgoingMessage.d.ts +3 -3
  38. package/dist/packages/server/src/Server.d.ts +5 -5
  39. package/dist/packages/server/src/index.d.ts +9 -9
  40. package/dist/packages/server/src/types.d.ts +7 -7
  41. package/dist/packages/server/src/util/getParameters.d.ts +5 -5
  42. package/dist/packages/transformer/src/Prosemirror.d.ts +3 -3
  43. package/dist/packages/transformer/src/Tiptap.d.ts +3 -3
  44. package/dist/packages/transformer/src/index.d.ts +3 -3
  45. package/dist/packages/transformer/src/types.d.ts +1 -1
  46. package/dist/playground/frontend/app/SocketContext1.d.ts +2 -0
  47. package/dist/playground/frontend/app/SocketContext2.d.ts +2 -0
  48. package/package.json +40 -40
  49. package/src/index.ts +207 -201
  50. package/dist/playground/frontend/app/SocketContext.d.ts +0 -2
package/src/index.ts CHANGED
@@ -1,211 +1,217 @@
1
- import { createHmac } from 'crypto'
1
+ import { createHmac } from "crypto";
2
2
  import type {
3
- Extension,
4
- onChangePayload,
5
- onConnectPayload,
6
- onLoadDocumentPayload,
7
- onDisconnectPayload,
8
- } from '@hocuspocus/server'
9
- import type { Doc } from 'yjs'
10
- import type { Transformer } from '@hocuspocus/transformer'
11
- import { TiptapTransformer } from '@hocuspocus/transformer'
12
- import axios from 'axios'
13
- import { Forbidden } from '@hocuspocus/common'
3
+ Extension,
4
+ onChangePayload,
5
+ onConnectPayload,
6
+ onLoadDocumentPayload,
7
+ onDisconnectPayload,
8
+ } from "@hocuspocus/server";
9
+ import type { Doc } from "yjs";
10
+ import type { Transformer } from "@hocuspocus/transformer";
11
+ import { TiptapTransformer } from "@hocuspocus/transformer";
12
+ import axios from "axios";
13
+ import { Forbidden } from "@hocuspocus/common";
14
14
 
15
15
  export enum Events {
16
- onChange = 'change',
17
- onConnect = 'connect',
18
- onCreate = 'create',
19
- onDisconnect = 'disconnect',
16
+ onChange = "change",
17
+ onConnect = "connect",
18
+ onCreate = "create",
19
+ onDisconnect = "disconnect",
20
20
  }
21
21
 
22
22
  export interface Configuration {
23
- debounce: number | false | null,
24
- debounceMaxWait: number,
25
- secret: string,
26
- transformer: Transformer | {
27
- toYdoc: (document: any) => Doc,
28
- fromYdoc: (document: Doc) => any,
29
- },
30
- url: string,
31
- events: Array<Events>,
23
+ debounce: number | false | null;
24
+ debounceMaxWait: number;
25
+ secret: string;
26
+ transformer:
27
+ | Transformer
28
+ | {
29
+ toYdoc: (document: any) => Doc;
30
+ fromYdoc: (document: Doc) => any;
31
+ };
32
+ url: string;
33
+ events: Array<Events>;
32
34
  }
33
35
 
34
36
  export class Webhook implements Extension {
35
-
36
- configuration: Configuration = {
37
- debounce: 2000,
38
- debounceMaxWait: 10000,
39
- secret: '',
40
- transformer: TiptapTransformer,
41
- url: '',
42
- events: [
43
- Events.onChange,
44
- ],
45
- }
46
-
47
- debounced: Map<string, { timeout: NodeJS.Timeout, start: number }> = new Map()
48
-
49
- /**
50
- * Constructor
51
- */
52
- constructor(configuration?: Partial<Configuration>) {
53
- this.configuration = {
54
- ...this.configuration,
55
- ...configuration,
56
- }
57
-
58
- if (!this.configuration.url) {
59
- throw new Error('url is required!')
60
- }
61
- }
62
-
63
- /**
64
- * Create a signature for the response body
65
- */
66
- createSignature(body: string): string {
67
- const hmac = createHmac('sha256', this.configuration.secret)
68
-
69
- return `sha256=${hmac.update(body).digest('hex')}`
70
- }
71
-
72
- /**
73
- * debounce the given function, using the given identifier
74
- */
75
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
76
- debounce(id: string, func: Function) {
77
- const old = this.debounced.get(id)
78
- const start = old?.start || Date.now()
79
-
80
- const run = () => {
81
- this.debounced.delete(id)
82
- func()
83
- }
84
-
85
- if (old?.timeout) clearTimeout(old.timeout)
86
- if (Date.now() - start >= this.configuration.debounceMaxWait) return run()
87
-
88
- this.debounced.set(id, {
89
- start,
90
- timeout: setTimeout(run, <number> this.configuration.debounce),
91
- })
92
- }
93
-
94
- /**
95
- * Send a request to the given url containing the given data
96
- */
97
- async sendRequest(event: Events, payload: any) {
98
- const json = JSON.stringify({ event, payload })
99
-
100
- return axios.post(
101
- this.configuration.url,
102
- json,
103
- { headers: { 'X-Hocuspocus-Signature-256': this.createSignature(json), 'Content-Type': 'application/json' } },
104
- )
105
- }
106
-
107
- /**
108
- * onChange hook
109
- */
110
- async onChange(data: onChangePayload) {
111
- if (!this.configuration.events.includes(Events.onChange)) {
112
- return
113
- }
114
-
115
- const save = async () => {
116
- try {
117
- await this.sendRequest(Events.onChange, {
118
- document: this.configuration.transformer.fromYdoc(data.document),
119
- documentName: data.documentName,
120
- context: data.context,
121
- requestHeaders: data.requestHeaders,
122
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
123
- })
124
- } catch (e) {
125
- console.error(`Caught error in extension-webhook: ${e}`)
126
- }
127
- }
128
-
129
- if (!this.configuration.debounce) {
130
- return save()
131
- }
132
-
133
- this.debounce(data.documentName, save)
134
- }
135
-
136
- /**
137
- * onLoadDocument hook
138
- */
139
- async onLoadDocument(data: onLoadDocumentPayload) {
140
- if (!this.configuration.events.includes(Events.onCreate)) {
141
- return
142
- }
143
-
144
- try {
145
- const response = await this.sendRequest(Events.onCreate, {
146
- documentName: data.documentName,
147
- requestHeaders: data.requestHeaders,
148
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
149
- })
150
-
151
- if (response.status !== 200 || !response.data) return
152
-
153
- const document = typeof response.data === 'string'
154
- ? JSON.parse(response.data)
155
- : response.data
156
-
157
- // eslint-disable-next-line guard-for-in,no-restricted-syntax
158
- for (const fieldName in document) {
159
- if (data.document.isEmpty(fieldName)) {
160
- data.document.merge(
161
- this.configuration.transformer.toYdoc(document[fieldName], fieldName),
162
- )
163
- }
164
- }
165
- } catch (e) {
166
- console.error(`Caught error in extension-webhook: ${e}`)
167
- }
168
- }
169
-
170
- /**
171
- * onConnect hook
172
- */
173
- async onConnect(data: onConnectPayload) {
174
- if (!this.configuration.events.includes(Events.onConnect)) {
175
- return
176
- }
177
-
178
- try {
179
- const response = await this.sendRequest(Events.onConnect, {
180
- documentName: data.documentName,
181
- requestHeaders: data.requestHeaders,
182
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
183
- })
184
-
185
- return typeof response.data === 'string' && response.data.length > 0
186
- ? JSON.parse(response.data)
187
- : response.data
188
- } catch (e) {
189
- console.error(`Caught error in extension-webhook: ${e}`)
190
- throw Forbidden
191
- }
192
- }
193
-
194
- async onDisconnect(data: onDisconnectPayload) {
195
- if (!this.configuration.events.includes(Events.onDisconnect)) {
196
- return
197
- }
198
-
199
- try {
200
- await this.sendRequest(Events.onDisconnect, {
201
- documentName: data.documentName,
202
- requestHeaders: data.requestHeaders,
203
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
204
- context: data.context,
205
- })
206
- } catch (e) {
207
- console.error(`Caught error in extension-webhook: ${e}`)
208
- }
209
- }
210
-
37
+ configuration: Configuration = {
38
+ debounce: 2000,
39
+ debounceMaxWait: 10000,
40
+ secret: "",
41
+ transformer: TiptapTransformer,
42
+ url: "",
43
+ events: [Events.onChange],
44
+ };
45
+
46
+ debounced: Map<string, { timeout: NodeJS.Timeout; start: number }> =
47
+ new Map();
48
+
49
+ /**
50
+ * Constructor
51
+ */
52
+ constructor(configuration?: Partial<Configuration>) {
53
+ this.configuration = {
54
+ ...this.configuration,
55
+ ...configuration,
56
+ };
57
+
58
+ if (!this.configuration.url) {
59
+ throw new Error("url is required!");
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Create a signature for the response body
65
+ */
66
+ createSignature(body: string): string {
67
+ const hmac = createHmac("sha256", this.configuration.secret);
68
+
69
+ return `sha256=${hmac.update(body).digest("hex")}`;
70
+ }
71
+
72
+ /**
73
+ * debounce the given function, using the given identifier
74
+ */
75
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
76
+ debounce(id: string, func: Function) {
77
+ const old = this.debounced.get(id);
78
+ const start = old?.start || Date.now();
79
+
80
+ const run = () => {
81
+ this.debounced.delete(id);
82
+ func();
83
+ };
84
+
85
+ if (old?.timeout) clearTimeout(old.timeout);
86
+ if (Date.now() - start >= this.configuration.debounceMaxWait) return run();
87
+
88
+ this.debounced.set(id, {
89
+ start,
90
+ timeout: setTimeout(run, <number>this.configuration.debounce),
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Send a request to the given url containing the given data
96
+ */
97
+ async sendRequest(event: Events, payload: any) {
98
+ const json = JSON.stringify({ event, payload });
99
+
100
+ return axios.post(this.configuration.url, json, {
101
+ headers: {
102
+ "X-Hocuspocus-Signature-256": this.createSignature(json),
103
+ "Content-Type": "application/json",
104
+ },
105
+ });
106
+ }
107
+
108
+ /**
109
+ * onChange hook
110
+ */
111
+ async onChange(data: onChangePayload) {
112
+ if (!this.configuration.events.includes(Events.onChange)) {
113
+ return;
114
+ }
115
+
116
+ const save = async () => {
117
+ try {
118
+ await this.sendRequest(Events.onChange, {
119
+ document: this.configuration.transformer.fromYdoc(data.document),
120
+ documentName: data.documentName,
121
+ context: data.context,
122
+ requestHeaders: data.requestHeaders,
123
+ requestParameters: Object.fromEntries(
124
+ data.requestParameters.entries(),
125
+ ),
126
+ });
127
+ } catch (e) {
128
+ console.error(`Caught error in extension-webhook: ${e}`);
129
+ }
130
+ };
131
+
132
+ if (!this.configuration.debounce) {
133
+ return save();
134
+ }
135
+
136
+ this.debounce(data.documentName, save);
137
+ }
138
+
139
+ /**
140
+ * onLoadDocument hook
141
+ */
142
+ async onLoadDocument(data: onLoadDocumentPayload) {
143
+ if (!this.configuration.events.includes(Events.onCreate)) {
144
+ return;
145
+ }
146
+
147
+ try {
148
+ const response = await this.sendRequest(Events.onCreate, {
149
+ documentName: data.documentName,
150
+ requestHeaders: data.requestHeaders,
151
+ requestParameters: Object.fromEntries(data.requestParameters.entries()),
152
+ });
153
+
154
+ if (response.status !== 200 || !response.data) return;
155
+
156
+ const document =
157
+ typeof response.data === "string"
158
+ ? JSON.parse(response.data)
159
+ : response.data;
160
+
161
+ // eslint-disable-next-line guard-for-in,no-restricted-syntax
162
+ for (const fieldName in document) {
163
+ if (data.document.isEmpty(fieldName)) {
164
+ data.document.merge(
165
+ this.configuration.transformer.toYdoc(
166
+ document[fieldName],
167
+ fieldName,
168
+ ),
169
+ );
170
+ }
171
+ }
172
+ } catch (e) {
173
+ console.error(`Caught error in extension-webhook: ${e}`);
174
+ }
175
+ }
176
+
177
+ /**
178
+ * onConnect hook
179
+ */
180
+ async onConnect(data: onConnectPayload) {
181
+ if (!this.configuration.events.includes(Events.onConnect)) {
182
+ return;
183
+ }
184
+
185
+ try {
186
+ const response = await this.sendRequest(Events.onConnect, {
187
+ documentName: data.documentName,
188
+ requestHeaders: data.requestHeaders,
189
+ requestParameters: Object.fromEntries(data.requestParameters.entries()),
190
+ });
191
+
192
+ return typeof response.data === "string" && response.data.length > 0
193
+ ? JSON.parse(response.data)
194
+ : response.data;
195
+ } catch (e) {
196
+ console.error(`Caught error in extension-webhook: ${e}`);
197
+ throw Forbidden;
198
+ }
199
+ }
200
+
201
+ async onDisconnect(data: onDisconnectPayload) {
202
+ if (!this.configuration.events.includes(Events.onDisconnect)) {
203
+ return;
204
+ }
205
+
206
+ try {
207
+ await this.sendRequest(Events.onDisconnect, {
208
+ documentName: data.documentName,
209
+ requestHeaders: data.requestHeaders,
210
+ requestParameters: Object.fromEntries(data.requestParameters.entries()),
211
+ context: data.context,
212
+ });
213
+ } catch (e) {
214
+ console.error(`Caught error in extension-webhook: ${e}`);
215
+ }
216
+ }
211
217
  }
@@ -1,2 +0,0 @@
1
- import type { HocuspocusProviderWebsocket } from "@hocuspocus/provider";
2
- export declare const SocketContext: import("react").Context<HocuspocusProviderWebsocket | null>;