1 |
|
2 | var createLogger = (logger) => ({
|
3 | debug: () => {
|
4 | },
|
5 | info: () => {
|
6 | },
|
7 | warn: console.warn.bind(console),
|
8 | error: console.error.bind(console),
|
9 | ...logger
|
10 | });
|
11 |
|
12 |
|
13 | var emitterEventNames = [
|
14 | "branch_protection_configuration",
|
15 | "branch_protection_configuration.disabled",
|
16 | "branch_protection_configuration.enabled",
|
17 | "branch_protection_rule",
|
18 | "branch_protection_rule.created",
|
19 | "branch_protection_rule.deleted",
|
20 | "branch_protection_rule.edited",
|
21 | "check_run",
|
22 | "check_run.completed",
|
23 | "check_run.created",
|
24 | "check_run.requested_action",
|
25 | "check_run.rerequested",
|
26 | "check_suite",
|
27 | "check_suite.completed",
|
28 | "check_suite.requested",
|
29 | "check_suite.rerequested",
|
30 | "code_scanning_alert",
|
31 | "code_scanning_alert.appeared_in_branch",
|
32 | "code_scanning_alert.closed_by_user",
|
33 | "code_scanning_alert.created",
|
34 | "code_scanning_alert.fixed",
|
35 | "code_scanning_alert.reopened",
|
36 | "code_scanning_alert.reopened_by_user",
|
37 | "commit_comment",
|
38 | "commit_comment.created",
|
39 | "create",
|
40 | "custom_property",
|
41 | "custom_property.created",
|
42 | "custom_property.deleted",
|
43 | "custom_property.updated",
|
44 | "custom_property_values",
|
45 | "custom_property_values.updated",
|
46 | "delete",
|
47 | "dependabot_alert",
|
48 | "dependabot_alert.auto_dismissed",
|
49 | "dependabot_alert.auto_reopened",
|
50 | "dependabot_alert.created",
|
51 | "dependabot_alert.dismissed",
|
52 | "dependabot_alert.fixed",
|
53 | "dependabot_alert.reintroduced",
|
54 | "dependabot_alert.reopened",
|
55 | "deploy_key",
|
56 | "deploy_key.created",
|
57 | "deploy_key.deleted",
|
58 | "deployment",
|
59 | "deployment.created",
|
60 | "deployment_protection_rule",
|
61 | "deployment_protection_rule.requested",
|
62 | "deployment_review",
|
63 | "deployment_review.approved",
|
64 | "deployment_review.rejected",
|
65 | "deployment_review.requested",
|
66 | "deployment_status",
|
67 | "deployment_status.created",
|
68 | "discussion",
|
69 | "discussion.answered",
|
70 | "discussion.category_changed",
|
71 | "discussion.closed",
|
72 | "discussion.created",
|
73 | "discussion.deleted",
|
74 | "discussion.edited",
|
75 | "discussion.labeled",
|
76 | "discussion.locked",
|
77 | "discussion.pinned",
|
78 | "discussion.reopened",
|
79 | "discussion.transferred",
|
80 | "discussion.unanswered",
|
81 | "discussion.unlabeled",
|
82 | "discussion.unlocked",
|
83 | "discussion.unpinned",
|
84 | "discussion_comment",
|
85 | "discussion_comment.created",
|
86 | "discussion_comment.deleted",
|
87 | "discussion_comment.edited",
|
88 | "fork",
|
89 | "github_app_authorization",
|
90 | "github_app_authorization.revoked",
|
91 | "gollum",
|
92 | "installation",
|
93 | "installation.created",
|
94 | "installation.deleted",
|
95 | "installation.new_permissions_accepted",
|
96 | "installation.suspend",
|
97 | "installation.unsuspend",
|
98 | "installation_repositories",
|
99 | "installation_repositories.added",
|
100 | "installation_repositories.removed",
|
101 | "installation_target",
|
102 | "installation_target.renamed",
|
103 | "issue_comment",
|
104 | "issue_comment.created",
|
105 | "issue_comment.deleted",
|
106 | "issue_comment.edited",
|
107 | "issues",
|
108 | "issues.assigned",
|
109 | "issues.closed",
|
110 | "issues.deleted",
|
111 | "issues.demilestoned",
|
112 | "issues.edited",
|
113 | "issues.labeled",
|
114 | "issues.locked",
|
115 | "issues.milestoned",
|
116 | "issues.opened",
|
117 | "issues.pinned",
|
118 | "issues.reopened",
|
119 | "issues.transferred",
|
120 | "issues.unassigned",
|
121 | "issues.unlabeled",
|
122 | "issues.unlocked",
|
123 | "issues.unpinned",
|
124 | "label",
|
125 | "label.created",
|
126 | "label.deleted",
|
127 | "label.edited",
|
128 | "marketplace_purchase",
|
129 | "marketplace_purchase.cancelled",
|
130 | "marketplace_purchase.changed",
|
131 | "marketplace_purchase.pending_change",
|
132 | "marketplace_purchase.pending_change_cancelled",
|
133 | "marketplace_purchase.purchased",
|
134 | "member",
|
135 | "member.added",
|
136 | "member.edited",
|
137 | "member.removed",
|
138 | "membership",
|
139 | "membership.added",
|
140 | "membership.removed",
|
141 | "merge_group",
|
142 | "merge_group.checks_requested",
|
143 | "merge_group.destroyed",
|
144 | "meta",
|
145 | "meta.deleted",
|
146 | "milestone",
|
147 | "milestone.closed",
|
148 | "milestone.created",
|
149 | "milestone.deleted",
|
150 | "milestone.edited",
|
151 | "milestone.opened",
|
152 | "org_block",
|
153 | "org_block.blocked",
|
154 | "org_block.unblocked",
|
155 | "organization",
|
156 | "organization.deleted",
|
157 | "organization.member_added",
|
158 | "organization.member_invited",
|
159 | "organization.member_removed",
|
160 | "organization.renamed",
|
161 | "package",
|
162 | "package.published",
|
163 | "package.updated",
|
164 | "page_build",
|
165 | "personal_access_token_request",
|
166 | "personal_access_token_request.approved",
|
167 | "personal_access_token_request.cancelled",
|
168 | "personal_access_token_request.created",
|
169 | "personal_access_token_request.denied",
|
170 | "ping",
|
171 | "project",
|
172 | "project.closed",
|
173 | "project.created",
|
174 | "project.deleted",
|
175 | "project.edited",
|
176 | "project.reopened",
|
177 | "project_card",
|
178 | "project_card.converted",
|
179 | "project_card.created",
|
180 | "project_card.deleted",
|
181 | "project_card.edited",
|
182 | "project_card.moved",
|
183 | "project_column",
|
184 | "project_column.created",
|
185 | "project_column.deleted",
|
186 | "project_column.edited",
|
187 | "project_column.moved",
|
188 | "projects_v2",
|
189 | "projects_v2.closed",
|
190 | "projects_v2.created",
|
191 | "projects_v2.deleted",
|
192 | "projects_v2.edited",
|
193 | "projects_v2.reopened",
|
194 | "projects_v2_item",
|
195 | "projects_v2_item.archived",
|
196 | "projects_v2_item.converted",
|
197 | "projects_v2_item.created",
|
198 | "projects_v2_item.deleted",
|
199 | "projects_v2_item.edited",
|
200 | "projects_v2_item.reordered",
|
201 | "projects_v2_item.restored",
|
202 | "public",
|
203 | "pull_request",
|
204 | "pull_request.assigned",
|
205 | "pull_request.auto_merge_disabled",
|
206 | "pull_request.auto_merge_enabled",
|
207 | "pull_request.closed",
|
208 | "pull_request.converted_to_draft",
|
209 | "pull_request.demilestoned",
|
210 | "pull_request.dequeued",
|
211 | "pull_request.edited",
|
212 | "pull_request.enqueued",
|
213 | "pull_request.labeled",
|
214 | "pull_request.locked",
|
215 | "pull_request.milestoned",
|
216 | "pull_request.opened",
|
217 | "pull_request.ready_for_review",
|
218 | "pull_request.reopened",
|
219 | "pull_request.review_request_removed",
|
220 | "pull_request.review_requested",
|
221 | "pull_request.synchronize",
|
222 | "pull_request.unassigned",
|
223 | "pull_request.unlabeled",
|
224 | "pull_request.unlocked",
|
225 | "pull_request_review",
|
226 | "pull_request_review.dismissed",
|
227 | "pull_request_review.edited",
|
228 | "pull_request_review.submitted",
|
229 | "pull_request_review_comment",
|
230 | "pull_request_review_comment.created",
|
231 | "pull_request_review_comment.deleted",
|
232 | "pull_request_review_comment.edited",
|
233 | "pull_request_review_thread",
|
234 | "pull_request_review_thread.resolved",
|
235 | "pull_request_review_thread.unresolved",
|
236 | "push",
|
237 | "registry_package",
|
238 | "registry_package.published",
|
239 | "registry_package.updated",
|
240 | "release",
|
241 | "release.created",
|
242 | "release.deleted",
|
243 | "release.edited",
|
244 | "release.prereleased",
|
245 | "release.published",
|
246 | "release.released",
|
247 | "release.unpublished",
|
248 | "repository",
|
249 | "repository.archived",
|
250 | "repository.created",
|
251 | "repository.deleted",
|
252 | "repository.edited",
|
253 | "repository.privatized",
|
254 | "repository.publicized",
|
255 | "repository.renamed",
|
256 | "repository.transferred",
|
257 | "repository.unarchived",
|
258 | "repository_advisory",
|
259 | "repository_advisory.published",
|
260 | "repository_advisory.reported",
|
261 | "repository_dispatch",
|
262 | "repository_dispatch.sample.collected",
|
263 | "repository_import",
|
264 | "repository_ruleset",
|
265 | "repository_ruleset.created",
|
266 | "repository_ruleset.deleted",
|
267 | "repository_ruleset.edited",
|
268 | "repository_vulnerability_alert",
|
269 | "repository_vulnerability_alert.create",
|
270 | "repository_vulnerability_alert.dismiss",
|
271 | "repository_vulnerability_alert.reopen",
|
272 | "repository_vulnerability_alert.resolve",
|
273 | "secret_scanning_alert",
|
274 | "secret_scanning_alert.created",
|
275 | "secret_scanning_alert.reopened",
|
276 | "secret_scanning_alert.resolved",
|
277 | "secret_scanning_alert.revoked",
|
278 | "secret_scanning_alert.validated",
|
279 | "secret_scanning_alert_location",
|
280 | "secret_scanning_alert_location.created",
|
281 | "security_advisory",
|
282 | "security_advisory.published",
|
283 | "security_advisory.updated",
|
284 | "security_advisory.withdrawn",
|
285 | "security_and_analysis",
|
286 | "sponsorship",
|
287 | "sponsorship.cancelled",
|
288 | "sponsorship.created",
|
289 | "sponsorship.edited",
|
290 | "sponsorship.pending_cancellation",
|
291 | "sponsorship.pending_tier_change",
|
292 | "sponsorship.tier_changed",
|
293 | "star",
|
294 | "star.created",
|
295 | "star.deleted",
|
296 | "status",
|
297 | "team",
|
298 | "team.added_to_repository",
|
299 | "team.created",
|
300 | "team.deleted",
|
301 | "team.edited",
|
302 | "team.removed_from_repository",
|
303 | "team_add",
|
304 | "watch",
|
305 | "watch.started",
|
306 | "workflow_dispatch",
|
307 | "workflow_job",
|
308 | "workflow_job.completed",
|
309 | "workflow_job.in_progress",
|
310 | "workflow_job.queued",
|
311 | "workflow_job.waiting",
|
312 | "workflow_run",
|
313 | "workflow_run.completed",
|
314 | "workflow_run.in_progress",
|
315 | "workflow_run.requested"
|
316 | ];
|
317 |
|
318 |
|
319 | function handleEventHandlers(state, webhookName, handler) {
|
320 | if (!state.hooks[webhookName]) {
|
321 | state.hooks[webhookName] = [];
|
322 | }
|
323 | state.hooks[webhookName].push(handler);
|
324 | }
|
325 | function receiverOn(state, webhookNameOrNames, handler) {
|
326 | if (Array.isArray(webhookNameOrNames)) {
|
327 | webhookNameOrNames.forEach(
|
328 | (webhookName) => receiverOn(state, webhookName, handler)
|
329 | );
|
330 | return;
|
331 | }
|
332 | if (["*", "error"].includes(webhookNameOrNames)) {
|
333 | const webhookName = webhookNameOrNames === "*" ? "any" : webhookNameOrNames;
|
334 | const message = `Using the "${webhookNameOrNames}" event with the regular Webhooks.on() function is not supported. Please use the Webhooks.on${webhookName.charAt(0).toUpperCase() + webhookName.slice(1)}() method instead`;
|
335 | throw new Error(message);
|
336 | }
|
337 | if (!emitterEventNames.includes(webhookNameOrNames)) {
|
338 | state.log.warn(
|
339 | `"${webhookNameOrNames}" is not a known webhook name (https://developer.github.com/v3/activity/events/types/)`
|
340 | );
|
341 | }
|
342 | handleEventHandlers(state, webhookNameOrNames, handler);
|
343 | }
|
344 | function receiverOnAny(state, handler) {
|
345 | handleEventHandlers(state, "*", handler);
|
346 | }
|
347 | function receiverOnError(state, handler) {
|
348 | handleEventHandlers(state, "error", handler);
|
349 | }
|
350 |
|
351 |
|
352 | function wrapErrorHandler(handler, error) {
|
353 | let returnValue;
|
354 | try {
|
355 | returnValue = handler(error);
|
356 | } catch (error2) {
|
357 | console.log('FATAL: Error occurred in "error" event handler');
|
358 | console.log(error2);
|
359 | }
|
360 | if (returnValue && returnValue.catch) {
|
361 | returnValue.catch((error2) => {
|
362 | console.log('FATAL: Error occurred in "error" event handler');
|
363 | console.log(error2);
|
364 | });
|
365 | }
|
366 | }
|
367 |
|
368 |
|
369 | function getHooks(state, eventPayloadAction, eventName) {
|
370 | const hooks = [state.hooks[eventName], state.hooks["*"]];
|
371 | if (eventPayloadAction) {
|
372 | hooks.unshift(state.hooks[`${eventName}.${eventPayloadAction}`]);
|
373 | }
|
374 | return [].concat(...hooks.filter(Boolean));
|
375 | }
|
376 | function receiverHandle(state, event) {
|
377 | const errorHandlers = state.hooks.error || [];
|
378 | if (event instanceof Error) {
|
379 | const error = Object.assign(new AggregateError([event], event.message), {
|
380 | event
|
381 | });
|
382 | errorHandlers.forEach((handler) => wrapErrorHandler(handler, error));
|
383 | return Promise.reject(error);
|
384 | }
|
385 | if (!event || !event.name) {
|
386 | const error = new Error("Event name not passed");
|
387 | throw new AggregateError([error], error.message);
|
388 | }
|
389 | if (!event.payload) {
|
390 | const error = new Error("Event name not passed");
|
391 | throw new AggregateError([error], error.message);
|
392 | }
|
393 | const hooks = getHooks(
|
394 | state,
|
395 | "action" in event.payload ? event.payload.action : null,
|
396 | event.name
|
397 | );
|
398 | if (hooks.length === 0) {
|
399 | return Promise.resolve();
|
400 | }
|
401 | const errors = [];
|
402 | const promises = hooks.map((handler) => {
|
403 | let promise = Promise.resolve(event);
|
404 | if (state.transform) {
|
405 | promise = promise.then(state.transform);
|
406 | }
|
407 | return promise.then((event2) => {
|
408 | return handler(event2);
|
409 | }).catch((error) => errors.push(Object.assign(error, { event })));
|
410 | });
|
411 | return Promise.all(promises).then(() => {
|
412 | if (errors.length === 0) {
|
413 | return;
|
414 | }
|
415 | const error = new AggregateError(
|
416 | errors,
|
417 | errors.map((error2) => error2.message).join("\n")
|
418 | );
|
419 | Object.assign(error, {
|
420 | event
|
421 | });
|
422 | errorHandlers.forEach((handler) => wrapErrorHandler(handler, error));
|
423 | throw error;
|
424 | });
|
425 | }
|
426 |
|
427 |
|
428 | function removeListener(state, webhookNameOrNames, handler) {
|
429 | if (Array.isArray(webhookNameOrNames)) {
|
430 | webhookNameOrNames.forEach(
|
431 | (webhookName) => removeListener(state, webhookName, handler)
|
432 | );
|
433 | return;
|
434 | }
|
435 | if (!state.hooks[webhookNameOrNames]) {
|
436 | return;
|
437 | }
|
438 | for (let i = state.hooks[webhookNameOrNames].length - 1; i >= 0; i--) {
|
439 | if (state.hooks[webhookNameOrNames][i] === handler) {
|
440 | state.hooks[webhookNameOrNames].splice(i, 1);
|
441 | return;
|
442 | }
|
443 | }
|
444 | }
|
445 |
|
446 |
|
447 | function createEventHandler(options) {
|
448 | const state = {
|
449 | hooks: {},
|
450 | log: createLogger(options && options.log)
|
451 | };
|
452 | if (options && options.transform) {
|
453 | state.transform = options.transform;
|
454 | }
|
455 | return {
|
456 | on: receiverOn.bind(null, state),
|
457 | onAny: receiverOnAny.bind(null, state),
|
458 | onError: receiverOnError.bind(null, state),
|
459 | removeListener: removeListener.bind(null, state),
|
460 | receive: receiverHandle.bind(null, state)
|
461 | };
|
462 | }
|
463 |
|
464 |
|
465 | import { sign, verify as verify2 } from "@octokit/webhooks-methods";
|
466 |
|
467 |
|
468 | import { verify } from "@octokit/webhooks-methods";
|
469 | async function verifyAndReceive(state, event) {
|
470 | const matchesSignature = await verify(
|
471 | state.secret,
|
472 | event.payload,
|
473 | event.signature
|
474 | ).catch(() => false);
|
475 | if (!matchesSignature) {
|
476 | const error = new Error(
|
477 | "[@octokit/webhooks] signature does not match event payload and secret"
|
478 | );
|
479 | return state.eventHandler.receive(
|
480 | Object.assign(error, { event, status: 400 })
|
481 | );
|
482 | }
|
483 | let payload;
|
484 | try {
|
485 | payload = JSON.parse(event.payload);
|
486 | } catch (error) {
|
487 | error.message = "Invalid JSON";
|
488 | error.status = 400;
|
489 | throw new AggregateError([error], error.message);
|
490 | }
|
491 | return state.eventHandler.receive({
|
492 | id: event.id,
|
493 | name: event.name,
|
494 | payload
|
495 | });
|
496 | }
|
497 |
|
498 |
|
499 | var WEBHOOK_HEADERS = [
|
500 | "x-github-event",
|
501 | "x-hub-signature-256",
|
502 | "x-github-delivery"
|
503 | ];
|
504 | function getMissingHeaders(request) {
|
505 | return WEBHOOK_HEADERS.filter((header) => !(header in request.headers));
|
506 | }
|
507 |
|
508 |
|
509 | function getPayload(request) {
|
510 | if (typeof request.body === "object" && "rawBody" in request && request.rawBody instanceof Buffer) {
|
511 | return Promise.resolve(request.rawBody.toString("utf8"));
|
512 | } else if (typeof request.body === "string") {
|
513 | return Promise.resolve(request.body);
|
514 | }
|
515 | return new Promise((resolve, reject) => {
|
516 | let data = [];
|
517 | request.on(
|
518 | "error",
|
519 | (error) => reject(new AggregateError([error], error.message))
|
520 | );
|
521 | request.on("data", (chunk) => data.push(chunk));
|
522 | request.on(
|
523 | "end",
|
524 | () => (
|
525 |
|
526 |
|
527 | setImmediate(
|
528 | resolve,
|
529 | data.length === 1 ? data[0].toString("utf8") : Buffer.concat(data).toString("utf8")
|
530 | )
|
531 | )
|
532 | );
|
533 | });
|
534 | }
|
535 |
|
536 |
|
537 | function onUnhandledRequestDefault(request, response) {
|
538 | response.writeHead(404, {
|
539 | "content-type": "application/json"
|
540 | });
|
541 | response.end(
|
542 | JSON.stringify({
|
543 | error: `Unknown route: ${request.method} ${request.url}`
|
544 | })
|
545 | );
|
546 | }
|
547 |
|
548 |
|
549 | async function middleware(webhooks, options, request, response, next) {
|
550 | let pathname;
|
551 | try {
|
552 | pathname = new URL(request.url, "http://localhost").pathname;
|
553 | } catch (error) {
|
554 | response.writeHead(422, {
|
555 | "content-type": "application/json"
|
556 | });
|
557 | response.end(
|
558 | JSON.stringify({
|
559 | error: `Request URL could not be parsed: ${request.url}`
|
560 | })
|
561 | );
|
562 | return true;
|
563 | }
|
564 | if (pathname !== options.path) {
|
565 | next?.();
|
566 | return false;
|
567 | } else if (request.method !== "POST") {
|
568 | onUnhandledRequestDefault(request, response);
|
569 | return true;
|
570 | }
|
571 | if (!request.headers["content-type"] || !request.headers["content-type"].startsWith("application/json")) {
|
572 | response.writeHead(415, {
|
573 | "content-type": "application/json",
|
574 | accept: "application/json"
|
575 | });
|
576 | response.end(
|
577 | JSON.stringify({
|
578 | error: `Unsupported "Content-Type" header value. Must be "application/json"`
|
579 | })
|
580 | );
|
581 | return true;
|
582 | }
|
583 | const missingHeaders = getMissingHeaders(request).join(", ");
|
584 | if (missingHeaders) {
|
585 | response.writeHead(400, {
|
586 | "content-type": "application/json"
|
587 | });
|
588 | response.end(
|
589 | JSON.stringify({
|
590 | error: `Required headers missing: ${missingHeaders}`
|
591 | })
|
592 | );
|
593 | return true;
|
594 | }
|
595 | const eventName = request.headers["x-github-event"];
|
596 | const signatureSHA256 = request.headers["x-hub-signature-256"];
|
597 | const id = request.headers["x-github-delivery"];
|
598 | options.log.debug(`${eventName} event received (id: ${id})`);
|
599 | let didTimeout = false;
|
600 | const timeout = setTimeout(() => {
|
601 | didTimeout = true;
|
602 | response.statusCode = 202;
|
603 | response.end("still processing\n");
|
604 | }, 9e3).unref();
|
605 | try {
|
606 | const payload = await getPayload(request);
|
607 | await webhooks.verifyAndReceive({
|
608 | id,
|
609 | name: eventName,
|
610 | payload,
|
611 | signature: signatureSHA256
|
612 | });
|
613 | clearTimeout(timeout);
|
614 | if (didTimeout) return true;
|
615 | response.end("ok\n");
|
616 | return true;
|
617 | } catch (error) {
|
618 | clearTimeout(timeout);
|
619 | if (didTimeout) return true;
|
620 | const err = Array.from(error.errors)[0];
|
621 | const errorMessage = err.message ? `${err.name}: ${err.message}` : "Error: An Unspecified error occurred";
|
622 | response.statusCode = typeof err.status !== "undefined" ? err.status : 500;
|
623 | options.log.error(error);
|
624 | response.end(
|
625 | JSON.stringify({
|
626 | error: errorMessage
|
627 | })
|
628 | );
|
629 | return true;
|
630 | }
|
631 | }
|
632 |
|
633 |
|
634 | function createNodeMiddleware(webhooks, {
|
635 | path = "/api/github/webhooks",
|
636 | log = createLogger()
|
637 | } = {}) {
|
638 | return middleware.bind(null, webhooks, {
|
639 | path,
|
640 | log
|
641 | });
|
642 | }
|
643 |
|
644 |
|
645 | var Webhooks = class {
|
646 | sign;
|
647 | verify;
|
648 | on;
|
649 | onAny;
|
650 | onError;
|
651 | removeListener;
|
652 | receive;
|
653 | verifyAndReceive;
|
654 | constructor(options) {
|
655 | if (!options || !options.secret) {
|
656 | throw new Error("[@octokit/webhooks] options.secret required");
|
657 | }
|
658 | const state = {
|
659 | eventHandler: createEventHandler(options),
|
660 | secret: options.secret,
|
661 | hooks: {},
|
662 | log: createLogger(options.log)
|
663 | };
|
664 | this.sign = sign.bind(null, options.secret);
|
665 | this.verify = verify2.bind(null, options.secret);
|
666 | this.on = state.eventHandler.on;
|
667 | this.onAny = state.eventHandler.onAny;
|
668 | this.onError = state.eventHandler.onError;
|
669 | this.removeListener = state.eventHandler.removeListener;
|
670 | this.receive = state.eventHandler.receive;
|
671 | this.verifyAndReceive = verifyAndReceive.bind(null, state);
|
672 | }
|
673 | };
|
674 | export {
|
675 | Webhooks,
|
676 | createEventHandler,
|
677 | createNodeMiddleware,
|
678 | emitterEventNames
|
679 | };
|