@hocuspocus/extension-webhook 3.4.4 → 3.4.6-rc.0

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 (142) hide show
  1. package/dist/hocuspocus-webhook.cjs +169 -168
  2. package/dist/hocuspocus-webhook.cjs.map +1 -1
  3. package/dist/hocuspocus-webhook.esm.js +140 -167
  4. package/dist/hocuspocus-webhook.esm.js.map +1 -1
  5. package/dist/index.d.ts +61 -0
  6. package/dist/index.js +142 -0
  7. package/package.json +6 -6
  8. package/dist/node_modules/@tiptap/pm/model/index.d.ts +0 -1
  9. package/dist/node_modules/@tiptap/pm/state/index.d.ts +0 -1
  10. package/dist/node_modules/@tiptap/pm/transform/index.d.ts +0 -1
  11. package/dist/node_modules/@tiptap/pm/view/index.d.ts +0 -1
  12. package/dist/packages/common/src/CloseEvents.d.ts +0 -29
  13. package/dist/packages/common/src/auth.d.ts +0 -13
  14. package/dist/packages/common/src/awarenessStatesToArray.d.ts +0 -3
  15. package/dist/packages/common/src/index.d.ts +0 -4
  16. package/dist/packages/common/src/types.d.ts +0 -10
  17. package/dist/packages/extension-database/src/Database.d.ts +0 -30
  18. package/dist/packages/extension-database/src/index.d.ts +0 -1
  19. package/dist/packages/extension-logger/src/Logger.d.ts +0 -67
  20. package/dist/packages/extension-logger/src/index.d.ts +0 -1
  21. package/dist/packages/extension-redis/src/Redis.d.ts +0 -124
  22. package/dist/packages/extension-redis/src/index.d.ts +0 -1
  23. package/dist/packages/extension-s3/src/S3.d.ts +0 -44
  24. package/dist/packages/extension-s3/src/index.d.ts +0 -1
  25. package/dist/packages/extension-sqlite/src/SQLite.d.ts +0 -27
  26. package/dist/packages/extension-sqlite/src/index.d.ts +0 -1
  27. package/dist/packages/extension-throttle/src/index.d.ts +0 -30
  28. package/dist/packages/extension-webhook/src/index.d.ts +0 -56
  29. package/dist/packages/provider/src/EventEmitter.d.ts +0 -9
  30. package/dist/packages/provider/src/HocuspocusProvider.d.ts +0 -116
  31. package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +0 -119
  32. package/dist/packages/provider/src/IncomingMessage.d.ts +0 -17
  33. package/dist/packages/provider/src/MessageReceiver.d.ts +0 -12
  34. package/dist/packages/provider/src/MessageSender.d.ts +0 -9
  35. package/dist/packages/provider/src/OutgoingMessage.d.ts +0 -9
  36. package/dist/packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts +0 -8
  37. package/dist/packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts +0 -9
  38. package/dist/packages/provider/src/OutgoingMessages/CloseMessage.d.ts +0 -9
  39. package/dist/packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts +0 -9
  40. package/dist/packages/provider/src/OutgoingMessages/StatelessMessage.d.ts +0 -8
  41. package/dist/packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts +0 -9
  42. package/dist/packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts +0 -9
  43. package/dist/packages/provider/src/OutgoingMessages/UpdateMessage.d.ts +0 -8
  44. package/dist/packages/provider/src/index.d.ts +0 -3
  45. package/dist/packages/provider/src/types.d.ts +0 -93
  46. package/dist/packages/server/src/ClientConnection.d.ts +0 -63
  47. package/dist/packages/server/src/Connection.d.ts +0 -75
  48. package/dist/packages/server/src/DirectConnection.d.ts +0 -14
  49. package/dist/packages/server/src/Document.d.ts +0 -92
  50. package/dist/packages/server/src/Hocuspocus.d.ts +0 -80
  51. package/dist/packages/server/src/IncomingMessage.d.ts +0 -25
  52. package/dist/packages/server/src/MessageReceiver.d.ts +0 -11
  53. package/dist/packages/server/src/OutgoingMessage.d.ts +0 -23
  54. package/dist/packages/server/src/Server.d.ts +0 -32
  55. package/dist/packages/server/src/index.d.ts +0 -9
  56. package/dist/packages/server/src/types.d.ts +0 -342
  57. package/dist/packages/server/src/util/debounce.d.ts +0 -6
  58. package/dist/packages/server/src/util/getParameters.d.ts +0 -6
  59. package/dist/packages/transformer/src/Prosemirror.d.ts +0 -11
  60. package/dist/packages/transformer/src/Tiptap.d.ts +0 -10
  61. package/dist/packages/transformer/src/index.d.ts +0 -3
  62. package/dist/packages/transformer/src/types.d.ts +0 -5
  63. package/dist/playground/backend/src/default.d.ts +0 -1
  64. package/dist/playground/backend/src/deno.d.ts +0 -1
  65. package/dist/playground/backend/src/express.d.ts +0 -1
  66. package/dist/playground/backend/src/hono.d.ts +0 -1
  67. package/dist/playground/backend/src/koa.d.ts +0 -1
  68. package/dist/playground/backend/src/load-document.d.ts +0 -1
  69. package/dist/playground/backend/src/redis.d.ts +0 -1
  70. package/dist/playground/backend/src/s3-redis.d.ts +0 -1
  71. package/dist/playground/backend/src/s3.d.ts +0 -1
  72. package/dist/playground/backend/src/slow.d.ts +0 -1
  73. package/dist/playground/backend/src/tiptapcollab.d.ts +0 -1
  74. package/dist/playground/backend/src/webhook.d.ts +0 -1
  75. package/dist/playground/frontend/app/SocketContext1.d.ts +0 -2
  76. package/dist/playground/frontend/app/SocketContext2.d.ts +0 -2
  77. package/dist/playground/frontend/next.config.d.ts +0 -3
  78. package/dist/tests/extension-database/fetch.d.ts +0 -1
  79. package/dist/tests/extension-logger/onListen.d.ts +0 -1
  80. package/dist/tests/extension-redis/onAwarenessChange.d.ts +0 -1
  81. package/dist/tests/extension-redis/onChange.d.ts +0 -1
  82. package/dist/tests/extension-redis/onStateless.d.ts +0 -1
  83. package/dist/tests/extension-redis/onStoreDocument.d.ts +0 -1
  84. package/dist/tests/extension-s3/fetch.d.ts +0 -1
  85. package/dist/tests/extension-throttle/banning.d.ts +0 -1
  86. package/dist/tests/extension-throttle/configuration.d.ts +0 -1
  87. package/dist/tests/provider/hasUnsyncedChanges.d.ts +0 -1
  88. package/dist/tests/provider/observe.d.ts +0 -1
  89. package/dist/tests/provider/observeDeep.d.ts +0 -1
  90. package/dist/tests/provider/onAuthenticated.d.ts +0 -1
  91. package/dist/tests/provider/onAuthenticationFailed.d.ts +0 -1
  92. package/dist/tests/provider/onAwarenessChange.d.ts +0 -1
  93. package/dist/tests/provider/onAwarenessUpdate.d.ts +0 -1
  94. package/dist/tests/provider/onClose.d.ts +0 -1
  95. package/dist/tests/provider/onConnect.d.ts +0 -1
  96. package/dist/tests/provider/onDisconnect.d.ts +0 -1
  97. package/dist/tests/provider/onMessage.d.ts +0 -1
  98. package/dist/tests/provider/onOpen.d.ts +0 -1
  99. package/dist/tests/provider/onStateless.d.ts +0 -1
  100. package/dist/tests/provider/onSynced.d.ts +0 -1
  101. package/dist/tests/providerwebsocket/configuration.d.ts +0 -1
  102. package/dist/tests/server/address.d.ts +0 -1
  103. package/dist/tests/server/afterLoadDocument.d.ts +0 -1
  104. package/dist/tests/server/afterStoreDocument.d.ts +0 -1
  105. package/dist/tests/server/afterUnloadDocument.d.ts +0 -1
  106. package/dist/tests/server/beforeBroadcastStateless.d.ts +0 -1
  107. package/dist/tests/server/beforeHandleMessage.d.ts +0 -1
  108. package/dist/tests/server/beforeSync.d.ts +0 -1
  109. package/dist/tests/server/beforeUnloadDocument.d.ts +0 -1
  110. package/dist/tests/server/closeConnections.d.ts +0 -1
  111. package/dist/tests/server/getConnectionsCount.d.ts +0 -1
  112. package/dist/tests/server/getDocumentsCount.d.ts +0 -1
  113. package/dist/tests/server/listen.d.ts +0 -1
  114. package/dist/tests/server/onAuthenticate.d.ts +0 -1
  115. package/dist/tests/server/onAwarenessUpdate.d.ts +0 -1
  116. package/dist/tests/server/onChange.d.ts +0 -1
  117. package/dist/tests/server/onClose.d.ts +0 -1
  118. package/dist/tests/server/onConfigure.d.ts +0 -1
  119. package/dist/tests/server/onConnect.d.ts +0 -1
  120. package/dist/tests/server/onDestroy.d.ts +0 -1
  121. package/dist/tests/server/onDisconnect.d.ts +0 -1
  122. package/dist/tests/server/onListen.d.ts +0 -1
  123. package/dist/tests/server/onLoadDocument.d.ts +0 -1
  124. package/dist/tests/server/onRequest.d.ts +0 -1
  125. package/dist/tests/server/onStateless.d.ts +0 -1
  126. package/dist/tests/server/onStoreDocument.d.ts +0 -1
  127. package/dist/tests/server/onTokenSync.d.ts +0 -1
  128. package/dist/tests/server/onUpgrade.d.ts +0 -1
  129. package/dist/tests/server/openDirectConnection.d.ts +0 -1
  130. package/dist/tests/server/websocketError.d.ts +0 -1
  131. package/dist/tests/transformer/TiptapTransformer.d.ts +0 -1
  132. package/dist/tests/utils/createDirectory.d.ts +0 -1
  133. package/dist/tests/utils/flushRedis.d.ts +0 -1
  134. package/dist/tests/utils/index.d.ts +0 -9
  135. package/dist/tests/utils/newHocuspocus.d.ts +0 -2
  136. package/dist/tests/utils/newHocuspocusProvider.d.ts +0 -3
  137. package/dist/tests/utils/newHocuspocusProviderWebsocket.d.ts +0 -4
  138. package/dist/tests/utils/randomInteger.d.ts +0 -1
  139. package/dist/tests/utils/redisConnectionSettings.d.ts +0 -4
  140. package/dist/tests/utils/removeDirectory.d.ts +0 -1
  141. package/dist/tests/utils/retryableAssertion.d.ts +0 -2
  142. package/dist/tests/utils/sleep.d.ts +0 -1
@@ -1,170 +1,143 @@
1
- import { createHmac } from 'node:crypto';
2
- import { Forbidden } from '@hocuspocus/common';
3
- import { TiptapTransformer } from '@hocuspocus/transformer';
4
- import axios from 'axios';
1
+ import { createHmac } from "node:crypto";
2
+ import { Forbidden } from "@hocuspocus/common";
3
+ import { TiptapTransformer } from "@hocuspocus/transformer";
4
+ import axios from "axios";
5
5
 
6
- var Events;
7
- (function (Events) {
8
- Events["onChange"] = "change";
9
- Events["onConnect"] = "connect";
10
- Events["onCreate"] = "create";
11
- Events["onDisconnect"] = "disconnect";
12
- })(Events || (Events = {}));
13
- class Webhook {
14
- /**
15
- * Constructor
16
- */
17
- constructor(configuration) {
18
- this.configuration = {
19
- debounce: 2000,
20
- debounceMaxWait: 10000,
21
- secret: "",
22
- transformer: TiptapTransformer,
23
- url: "",
24
- events: [Events.onChange],
25
- };
26
- this.debounced = new Map();
27
- this.configuration = {
28
- ...this.configuration,
29
- ...configuration,
30
- };
31
- if (!this.configuration.url) {
32
- throw new Error("url is required!");
33
- }
34
- }
35
- /**
36
- * Create a signature for the response body
37
- */
38
- createSignature(body) {
39
- const hmac = createHmac("sha256", this.configuration.secret);
40
- return `sha256=${hmac.update(body).digest("hex")}`;
41
- }
42
- /**
43
- * debounce the given function, using the given identifier
44
- */
45
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
46
- debounce(id, func) {
47
- const old = this.debounced.get(id);
48
- const start = (old === null || old === void 0 ? void 0 : old.start) || Date.now();
49
- const run = () => {
50
- this.debounced.delete(id);
51
- func();
52
- };
53
- if (old === null || old === void 0 ? void 0 : old.timeout)
54
- clearTimeout(old.timeout);
55
- if (Date.now() - start >= this.configuration.debounceMaxWait)
56
- return run();
57
- this.debounced.set(id, {
58
- start,
59
- timeout: setTimeout(run, this.configuration.debounce),
60
- });
61
- }
62
- /**
63
- * Send a request to the given url containing the given data
64
- */
65
- async sendRequest(event, payload) {
66
- const json = JSON.stringify({ event, payload });
67
- return axios.post(this.configuration.url, json, {
68
- headers: {
69
- "X-Hocuspocus-Signature-256": this.createSignature(json),
70
- "Content-Type": "application/json",
71
- },
72
- });
73
- }
74
- /**
75
- * onChange hook
76
- */
77
- async onChange(data) {
78
- if (!this.configuration.events.includes(Events.onChange)) {
79
- return;
80
- }
81
- const save = async () => {
82
- try {
83
- await this.sendRequest(Events.onChange, {
84
- document: this.configuration.transformer.fromYdoc(data.document),
85
- documentName: data.documentName,
86
- context: data.context,
87
- requestHeaders: data.requestHeaders,
88
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
89
- });
90
- }
91
- catch (e) {
92
- console.error(`Caught error in extension-webhook: ${e}`);
93
- }
94
- };
95
- if (!this.configuration.debounce) {
96
- return save();
97
- }
98
- this.debounce(data.documentName, save);
99
- }
100
- /**
101
- * onLoadDocument hook
102
- */
103
- async onLoadDocument(data) {
104
- if (!this.configuration.events.includes(Events.onCreate)) {
105
- return;
106
- }
107
- try {
108
- const response = await this.sendRequest(Events.onCreate, {
109
- documentName: data.documentName,
110
- requestHeaders: data.requestHeaders,
111
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
112
- });
113
- if (response.status !== 200 || !response.data)
114
- return;
115
- const document = typeof response.data === "string"
116
- ? JSON.parse(response.data)
117
- : response.data;
118
- // eslint-disable-next-line guard-for-in,no-restricted-syntax
119
- for (const fieldName in document) {
120
- if (data.document.isEmpty(fieldName)) {
121
- data.document.merge(this.configuration.transformer.toYdoc(document[fieldName], fieldName));
122
- }
123
- }
124
- }
125
- catch (e) {
126
- console.error(`Caught error in extension-webhook: ${e}`);
127
- }
128
- }
129
- /**
130
- * onConnect hook
131
- */
132
- async onConnect(data) {
133
- if (!this.configuration.events.includes(Events.onConnect)) {
134
- return;
135
- }
136
- try {
137
- const response = await this.sendRequest(Events.onConnect, {
138
- documentName: data.documentName,
139
- requestHeaders: data.requestHeaders,
140
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
141
- });
142
- return typeof response.data === "string" && response.data.length > 0
143
- ? JSON.parse(response.data)
144
- : response.data;
145
- }
146
- catch (e) {
147
- console.error(`Caught error in extension-webhook: ${e}`);
148
- throw Forbidden;
149
- }
150
- }
151
- async onDisconnect(data) {
152
- if (!this.configuration.events.includes(Events.onDisconnect)) {
153
- return;
154
- }
155
- try {
156
- await this.sendRequest(Events.onDisconnect, {
157
- documentName: data.documentName,
158
- requestHeaders: data.requestHeaders,
159
- requestParameters: Object.fromEntries(data.requestParameters.entries()),
160
- context: data.context,
161
- });
162
- }
163
- catch (e) {
164
- console.error(`Caught error in extension-webhook: ${e}`);
165
- }
166
- }
167
- }
6
+ //#region packages/extension-webhook/src/index.ts
7
+ let Events = /* @__PURE__ */ function(Events) {
8
+ Events["onChange"] = "change";
9
+ Events["onConnect"] = "connect";
10
+ Events["onCreate"] = "create";
11
+ Events["onDisconnect"] = "disconnect";
12
+ return Events;
13
+ }({});
14
+ var Webhook = class {
15
+ /**
16
+ * Constructor
17
+ */
18
+ constructor(configuration) {
19
+ this.configuration = {
20
+ debounce: 2e3,
21
+ debounceMaxWait: 1e4,
22
+ secret: "",
23
+ transformer: TiptapTransformer,
24
+ url: "",
25
+ events: [Events.onChange]
26
+ };
27
+ this.debounced = /* @__PURE__ */ new Map();
28
+ this.configuration = {
29
+ ...this.configuration,
30
+ ...configuration
31
+ };
32
+ if (!this.configuration.url) throw new Error("url is required!");
33
+ }
34
+ /**
35
+ * Create a signature for the response body
36
+ */
37
+ createSignature(body) {
38
+ return `sha256=${createHmac("sha256", this.configuration.secret).update(body).digest("hex")}`;
39
+ }
40
+ /**
41
+ * debounce the given function, using the given identifier
42
+ */
43
+ debounce(id, func) {
44
+ const old = this.debounced.get(id);
45
+ const start = old?.start || Date.now();
46
+ const run = () => {
47
+ this.debounced.delete(id);
48
+ func();
49
+ };
50
+ if (old?.timeout) clearTimeout(old.timeout);
51
+ if (Date.now() - start >= this.configuration.debounceMaxWait) return run();
52
+ this.debounced.set(id, {
53
+ start,
54
+ timeout: setTimeout(run, this.configuration.debounce)
55
+ });
56
+ }
57
+ /**
58
+ * Send a request to the given url containing the given data
59
+ */
60
+ async sendRequest(event, payload) {
61
+ const json = JSON.stringify({
62
+ event,
63
+ payload
64
+ });
65
+ return axios.post(this.configuration.url, json, { headers: {
66
+ "X-Hocuspocus-Signature-256": this.createSignature(json),
67
+ "Content-Type": "application/json"
68
+ } });
69
+ }
70
+ /**
71
+ * onChange hook
72
+ */
73
+ async onChange(data) {
74
+ if (!this.configuration.events.includes(Events.onChange)) return;
75
+ const save = async () => {
76
+ try {
77
+ await this.sendRequest(Events.onChange, {
78
+ document: this.configuration.transformer.fromYdoc(data.document),
79
+ documentName: data.documentName,
80
+ context: data.context,
81
+ requestHeaders: data.requestHeaders,
82
+ requestParameters: Object.fromEntries(data.requestParameters.entries())
83
+ });
84
+ } catch (e) {
85
+ console.error(`Caught error in extension-webhook: ${e}`);
86
+ }
87
+ };
88
+ if (!this.configuration.debounce) return save();
89
+ this.debounce(data.documentName, save);
90
+ }
91
+ /**
92
+ * onLoadDocument hook
93
+ */
94
+ async onLoadDocument(data) {
95
+ if (!this.configuration.events.includes(Events.onCreate)) return;
96
+ try {
97
+ const response = await this.sendRequest(Events.onCreate, {
98
+ documentName: data.documentName,
99
+ requestHeaders: data.requestHeaders,
100
+ requestParameters: Object.fromEntries(data.requestParameters.entries())
101
+ });
102
+ if (response.status !== 200 || !response.data) return;
103
+ const document = typeof response.data === "string" ? JSON.parse(response.data) : response.data;
104
+ for (const fieldName in document) if (data.document.isEmpty(fieldName)) data.document.merge(this.configuration.transformer.toYdoc(document[fieldName], fieldName));
105
+ } catch (e) {
106
+ console.error(`Caught error in extension-webhook: ${e}`);
107
+ }
108
+ }
109
+ /**
110
+ * onConnect hook
111
+ */
112
+ async onConnect(data) {
113
+ if (!this.configuration.events.includes(Events.onConnect)) return;
114
+ try {
115
+ const response = await this.sendRequest(Events.onConnect, {
116
+ documentName: data.documentName,
117
+ requestHeaders: data.requestHeaders,
118
+ requestParameters: Object.fromEntries(data.requestParameters.entries())
119
+ });
120
+ return typeof response.data === "string" && response.data.length > 0 ? JSON.parse(response.data) : response.data;
121
+ } catch (e) {
122
+ console.error(`Caught error in extension-webhook: ${e}`);
123
+ throw Forbidden;
124
+ }
125
+ }
126
+ async onDisconnect(data) {
127
+ if (!this.configuration.events.includes(Events.onDisconnect)) return;
128
+ try {
129
+ await this.sendRequest(Events.onDisconnect, {
130
+ documentName: data.documentName,
131
+ requestHeaders: data.requestHeaders,
132
+ requestParameters: Object.fromEntries(data.requestParameters.entries()),
133
+ context: data.context
134
+ });
135
+ } catch (e) {
136
+ console.error(`Caught error in extension-webhook: ${e}`);
137
+ }
138
+ }
139
+ };
168
140
 
141
+ //#endregion
169
142
  export { Events, Webhook };
170
- //# sourceMappingURL=hocuspocus-webhook.esm.js.map
143
+ //# sourceMappingURL=hocuspocus-webhook.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hocuspocus-webhook.esm.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hocuspocus-webhook.esm.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { createHmac } from \"node:crypto\";\nimport { Forbidden } from \"@hocuspocus/common\";\nimport type {\n\tExtension,\n\tonChangePayload,\n\tonConnectPayload,\n\tonDisconnectPayload,\n\tonLoadDocumentPayload,\n} from \"@hocuspocus/server\";\nimport type { Transformer } from \"@hocuspocus/transformer\";\nimport { TiptapTransformer } from \"@hocuspocus/transformer\";\nimport axios from \"axios\";\nimport type { Doc } from \"yjs\";\n\nexport enum Events {\n\tonChange = \"change\",\n\tonConnect = \"connect\",\n\tonCreate = \"create\",\n\tonDisconnect = \"disconnect\",\n}\n\nexport interface Configuration {\n\tdebounce: number | false | null;\n\tdebounceMaxWait: number;\n\tsecret: string;\n\ttransformer:\n\t\t| Transformer\n\t\t| {\n\t\t\t\ttoYdoc: (document: any) => Doc;\n\t\t\t\tfromYdoc: (document: Doc) => any;\n\t\t };\n\turl: string;\n\tevents: Array<Events>;\n}\n\nexport class Webhook implements Extension {\n\tconfiguration: Configuration = {\n\t\tdebounce: 2000,\n\t\tdebounceMaxWait: 10000,\n\t\tsecret: \"\",\n\t\ttransformer: TiptapTransformer,\n\t\turl: \"\",\n\t\tevents: [Events.onChange],\n\t};\n\n\tdebounced: Map<string, { timeout: NodeJS.Timeout; start: number }> =\n\t\tnew Map();\n\n\t/**\n\t * Constructor\n\t */\n\tconstructor(configuration?: Partial<Configuration>) {\n\t\tthis.configuration = {\n\t\t\t...this.configuration,\n\t\t\t...configuration,\n\t\t};\n\n\t\tif (!this.configuration.url) {\n\t\t\tthrow new Error(\"url is required!\");\n\t\t}\n\t}\n\n\t/**\n\t * Create a signature for the response body\n\t */\n\tcreateSignature(body: string): string {\n\t\tconst hmac = createHmac(\"sha256\", this.configuration.secret);\n\n\t\treturn `sha256=${hmac.update(body).digest(\"hex\")}`;\n\t}\n\n\t/**\n\t * debounce the given function, using the given identifier\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\tdebounce(id: string, func: Function) {\n\t\tconst old = this.debounced.get(id);\n\t\tconst start = old?.start || Date.now();\n\n\t\tconst run = () => {\n\t\t\tthis.debounced.delete(id);\n\t\t\tfunc();\n\t\t};\n\n\t\tif (old?.timeout) clearTimeout(old.timeout);\n\t\tif (Date.now() - start >= this.configuration.debounceMaxWait) return run();\n\n\t\tthis.debounced.set(id, {\n\t\t\tstart,\n\t\t\ttimeout: setTimeout(run, <number>this.configuration.debounce),\n\t\t});\n\t}\n\n\t/**\n\t * Send a request to the given url containing the given data\n\t */\n\tasync sendRequest(event: Events, payload: any) {\n\t\tconst json = JSON.stringify({ event, payload });\n\n\t\treturn axios.post(this.configuration.url, json, {\n\t\t\theaders: {\n\t\t\t\t\"X-Hocuspocus-Signature-256\": this.createSignature(json),\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * onChange hook\n\t */\n\tasync onChange(data: onChangePayload) {\n\t\tif (!this.configuration.events.includes(Events.onChange)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst save = async () => {\n\t\t\ttry {\n\t\t\t\tawait this.sendRequest(Events.onChange, {\n\t\t\t\t\tdocument: this.configuration.transformer.fromYdoc(data.document),\n\t\t\t\t\tdocumentName: data.documentName,\n\t\t\t\t\tcontext: data.context,\n\t\t\t\t\trequestHeaders: data.requestHeaders,\n\t\t\t\t\trequestParameters: Object.fromEntries(\n\t\t\t\t\t\tdata.requestParameters.entries(),\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tconsole.error(`Caught error in extension-webhook: ${e}`);\n\t\t\t}\n\t\t};\n\n\t\tif (!this.configuration.debounce) {\n\t\t\treturn save();\n\t\t}\n\n\t\tthis.debounce(data.documentName, save);\n\t}\n\n\t/**\n\t * onLoadDocument hook\n\t */\n\tasync onLoadDocument(data: onLoadDocumentPayload) {\n\t\tif (!this.configuration.events.includes(Events.onCreate)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await this.sendRequest(Events.onCreate, {\n\t\t\t\tdocumentName: data.documentName,\n\t\t\t\trequestHeaders: data.requestHeaders,\n\t\t\t\trequestParameters: Object.fromEntries(data.requestParameters.entries()),\n\t\t\t});\n\n\t\t\tif (response.status !== 200 || !response.data) return;\n\n\t\t\tconst document =\n\t\t\t\ttypeof response.data === \"string\"\n\t\t\t\t\t? JSON.parse(response.data)\n\t\t\t\t\t: response.data;\n\n\t\t\t// eslint-disable-next-line guard-for-in,no-restricted-syntax\n\t\t\tfor (const fieldName in document) {\n\t\t\t\tif (data.document.isEmpty(fieldName)) {\n\t\t\t\t\tdata.document.merge(\n\t\t\t\t\t\tthis.configuration.transformer.toYdoc(\n\t\t\t\t\t\t\tdocument[fieldName],\n\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.error(`Caught error in extension-webhook: ${e}`);\n\t\t}\n\t}\n\n\t/**\n\t * onConnect hook\n\t */\n\tasync onConnect(data: onConnectPayload) {\n\t\tif (!this.configuration.events.includes(Events.onConnect)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await this.sendRequest(Events.onConnect, {\n\t\t\t\tdocumentName: data.documentName,\n\t\t\t\trequestHeaders: data.requestHeaders,\n\t\t\t\trequestParameters: Object.fromEntries(data.requestParameters.entries()),\n\t\t\t});\n\n\t\t\treturn typeof response.data === \"string\" && response.data.length > 0\n\t\t\t\t? JSON.parse(response.data)\n\t\t\t\t: response.data;\n\t\t} catch (e) {\n\t\t\tconsole.error(`Caught error in extension-webhook: ${e}`);\n\t\t\tthrow Forbidden;\n\t\t}\n\t}\n\n\tasync onDisconnect(data: onDisconnectPayload) {\n\t\tif (!this.configuration.events.includes(Events.onDisconnect)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.sendRequest(Events.onDisconnect, {\n\t\t\t\tdocumentName: data.documentName,\n\t\t\t\trequestHeaders: data.requestHeaders,\n\t\t\t\trequestParameters: Object.fromEntries(data.requestParameters.entries()),\n\t\t\t\tcontext: data.context,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tconsole.error(`Caught error in extension-webhook: ${e}`);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { Transformer } from "@hocuspocus/transformer";
2
+ import * as axios0 from "axios";
3
+ import { Extension, onChangePayload, onConnectPayload, onDisconnectPayload, onLoadDocumentPayload } from "@hocuspocus/server";
4
+ import { Doc } from "yjs";
5
+
6
+ //#region packages/extension-webhook/src/index.d.ts
7
+ declare enum Events {
8
+ onChange = "change",
9
+ onConnect = "connect",
10
+ onCreate = "create",
11
+ onDisconnect = "disconnect"
12
+ }
13
+ interface Configuration {
14
+ debounce: number | false | null;
15
+ debounceMaxWait: number;
16
+ secret: string;
17
+ transformer: Transformer | {
18
+ toYdoc: (document: any) => Doc;
19
+ fromYdoc: (document: Doc) => any;
20
+ };
21
+ url: string;
22
+ events: Array<Events>;
23
+ }
24
+ declare class Webhook implements Extension {
25
+ configuration: Configuration;
26
+ debounced: Map<string, {
27
+ timeout: NodeJS.Timeout;
28
+ start: number;
29
+ }>;
30
+ /**
31
+ * Constructor
32
+ */
33
+ constructor(configuration?: Partial<Configuration>);
34
+ /**
35
+ * Create a signature for the response body
36
+ */
37
+ createSignature(body: string): string;
38
+ /**
39
+ * debounce the given function, using the given identifier
40
+ */
41
+ debounce(id: string, func: Function): void;
42
+ /**
43
+ * Send a request to the given url containing the given data
44
+ */
45
+ sendRequest(event: Events, payload: any): Promise<axios0.AxiosResponse<any, any, {}>>;
46
+ /**
47
+ * onChange hook
48
+ */
49
+ onChange(data: onChangePayload): Promise<void>;
50
+ /**
51
+ * onLoadDocument hook
52
+ */
53
+ onLoadDocument(data: onLoadDocumentPayload): Promise<void>;
54
+ /**
55
+ * onConnect hook
56
+ */
57
+ onConnect(data: onConnectPayload): Promise<any>;
58
+ onDisconnect(data: onDisconnectPayload): Promise<void>;
59
+ }
60
+ //#endregion
61
+ export { Configuration, Events, Webhook };
package/dist/index.js ADDED
@@ -0,0 +1,142 @@
1
+ import { createHmac } from "node:crypto";
2
+ import { Forbidden } from "@hocuspocus/common";
3
+ import { TiptapTransformer } from "@hocuspocus/transformer";
4
+ import axios from "axios";
5
+
6
+ //#region packages/extension-webhook/src/index.ts
7
+ let Events = /* @__PURE__ */ function(Events) {
8
+ Events["onChange"] = "change";
9
+ Events["onConnect"] = "connect";
10
+ Events["onCreate"] = "create";
11
+ Events["onDisconnect"] = "disconnect";
12
+ return Events;
13
+ }({});
14
+ var Webhook = class {
15
+ /**
16
+ * Constructor
17
+ */
18
+ constructor(configuration) {
19
+ this.configuration = {
20
+ debounce: 2e3,
21
+ debounceMaxWait: 1e4,
22
+ secret: "",
23
+ transformer: TiptapTransformer,
24
+ url: "",
25
+ events: [Events.onChange]
26
+ };
27
+ this.debounced = /* @__PURE__ */ new Map();
28
+ this.configuration = {
29
+ ...this.configuration,
30
+ ...configuration
31
+ };
32
+ if (!this.configuration.url) throw new Error("url is required!");
33
+ }
34
+ /**
35
+ * Create a signature for the response body
36
+ */
37
+ createSignature(body) {
38
+ return `sha256=${createHmac("sha256", this.configuration.secret).update(body).digest("hex")}`;
39
+ }
40
+ /**
41
+ * debounce the given function, using the given identifier
42
+ */
43
+ debounce(id, func) {
44
+ const old = this.debounced.get(id);
45
+ const start = old?.start || Date.now();
46
+ const run = () => {
47
+ this.debounced.delete(id);
48
+ func();
49
+ };
50
+ if (old?.timeout) clearTimeout(old.timeout);
51
+ if (Date.now() - start >= this.configuration.debounceMaxWait) return run();
52
+ this.debounced.set(id, {
53
+ start,
54
+ timeout: setTimeout(run, this.configuration.debounce)
55
+ });
56
+ }
57
+ /**
58
+ * Send a request to the given url containing the given data
59
+ */
60
+ async sendRequest(event, payload) {
61
+ const json = JSON.stringify({
62
+ event,
63
+ payload
64
+ });
65
+ return axios.post(this.configuration.url, json, { headers: {
66
+ "X-Hocuspocus-Signature-256": this.createSignature(json),
67
+ "Content-Type": "application/json"
68
+ } });
69
+ }
70
+ /**
71
+ * onChange hook
72
+ */
73
+ async onChange(data) {
74
+ if (!this.configuration.events.includes(Events.onChange)) return;
75
+ const save = async () => {
76
+ try {
77
+ await this.sendRequest(Events.onChange, {
78
+ document: this.configuration.transformer.fromYdoc(data.document),
79
+ documentName: data.documentName,
80
+ context: data.context,
81
+ requestHeaders: data.requestHeaders,
82
+ requestParameters: Object.fromEntries(data.requestParameters.entries())
83
+ });
84
+ } catch (e) {
85
+ console.error(`Caught error in extension-webhook: ${e}`);
86
+ }
87
+ };
88
+ if (!this.configuration.debounce) return save();
89
+ this.debounce(data.documentName, save);
90
+ }
91
+ /**
92
+ * onLoadDocument hook
93
+ */
94
+ async onLoadDocument(data) {
95
+ if (!this.configuration.events.includes(Events.onCreate)) return;
96
+ try {
97
+ const response = await this.sendRequest(Events.onCreate, {
98
+ documentName: data.documentName,
99
+ requestHeaders: data.requestHeaders,
100
+ requestParameters: Object.fromEntries(data.requestParameters.entries())
101
+ });
102
+ if (response.status !== 200 || !response.data) return;
103
+ const document = typeof response.data === "string" ? JSON.parse(response.data) : response.data;
104
+ for (const fieldName in document) if (data.document.isEmpty(fieldName)) data.document.merge(this.configuration.transformer.toYdoc(document[fieldName], fieldName));
105
+ } catch (e) {
106
+ console.error(`Caught error in extension-webhook: ${e}`);
107
+ }
108
+ }
109
+ /**
110
+ * onConnect hook
111
+ */
112
+ async onConnect(data) {
113
+ if (!this.configuration.events.includes(Events.onConnect)) return;
114
+ try {
115
+ const response = await this.sendRequest(Events.onConnect, {
116
+ documentName: data.documentName,
117
+ requestHeaders: data.requestHeaders,
118
+ requestParameters: Object.fromEntries(data.requestParameters.entries())
119
+ });
120
+ return typeof response.data === "string" && response.data.length > 0 ? JSON.parse(response.data) : response.data;
121
+ } catch (e) {
122
+ console.error(`Caught error in extension-webhook: ${e}`);
123
+ throw Forbidden;
124
+ }
125
+ }
126
+ async onDisconnect(data) {
127
+ if (!this.configuration.events.includes(Events.onDisconnect)) return;
128
+ try {
129
+ await this.sendRequest(Events.onDisconnect, {
130
+ documentName: data.documentName,
131
+ requestHeaders: data.requestHeaders,
132
+ requestParameters: Object.fromEntries(data.requestParameters.entries()),
133
+ context: data.context
134
+ });
135
+ } catch (e) {
136
+ console.error(`Caught error in extension-webhook: ${e}`);
137
+ }
138
+ }
139
+ };
140
+
141
+ //#endregion
142
+ export { Events, Webhook };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/extension-webhook",
3
- "version": "3.4.4",
3
+ "version": "3.4.6-rc.0",
4
4
  "description": "hocuspocus webhook extension",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
@@ -14,7 +14,7 @@
14
14
  "type": "module",
15
15
  "main": "dist/hocuspocus-webhook.cjs",
16
16
  "module": "dist/hocuspocus-webhook.esm.js",
17
- "types": "dist/packages/extension-webhook/src/index.d.ts",
17
+ "types": "dist/index.d.ts",
18
18
  "exports": {
19
19
  "source": {
20
20
  "import": "./src/index.ts"
@@ -22,7 +22,7 @@
22
22
  "default": {
23
23
  "import": "./dist/hocuspocus-webhook.esm.js",
24
24
  "require": "./dist/hocuspocus-webhook.cjs",
25
- "types": "./dist/packages/extension-webhook/src/index.d.ts"
25
+ "types": "./dist/index.d.ts"
26
26
  }
27
27
  },
28
28
  "files": [
@@ -30,9 +30,9 @@
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
- "@hocuspocus/common": "^3.4.4",
34
- "@hocuspocus/server": "^3.4.4",
35
- "@hocuspocus/transformer": "^3.4.4",
33
+ "@hocuspocus/common": "^3.4.6-rc.0",
34
+ "@hocuspocus/server": "^3.4.6-rc.0",
35
+ "@hocuspocus/transformer": "^3.4.6-rc.0",
36
36
  "axios": "^1.12.2"
37
37
  },
38
38
  "peerDependencies": {
@@ -1 +0,0 @@
1
- export * from 'prosemirror-model';
@@ -1 +0,0 @@
1
- export * from 'prosemirror-state';
@@ -1 +0,0 @@
1
- export * from 'prosemirror-transform';
@@ -1 +0,0 @@
1
- export * from 'prosemirror-view';
@@ -1,29 +0,0 @@
1
- export interface CloseEvent {
2
- code: number;
3
- reason: string;
4
- }
5
- /**
6
- * The server is terminating the connection because a data frame was received
7
- * that is too large.
8
- * See: https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
9
- */
10
- export declare const MessageTooBig: CloseEvent;
11
- /**
12
- * The server successfully processed the request, asks that the requester reset
13
- * its document view, and is not returning any content.
14
- */
15
- export declare const ResetConnection: CloseEvent;
16
- /**
17
- * Similar to Forbidden, but specifically for use when authentication is required and has
18
- * failed or has not yet been provided.
19
- */
20
- export declare const Unauthorized: CloseEvent;
21
- /**
22
- * The request contained valid data and was understood by the server, but the server
23
- * is refusing action.
24
- */
25
- export declare const Forbidden: CloseEvent;
26
- /**
27
- * The server timed out waiting for the request.
28
- */
29
- export declare const ConnectionTimeout: CloseEvent;