1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | const validator_1 = __importDefault(require("validator"));
|
6 | const eventsource_1 = __importDefault(require("eventsource"));
|
7 | const url_1 = __importDefault(require("url"));
|
8 | const querystring_1 = __importDefault(require("querystring"));
|
9 | class Client {
|
10 | constructor({ source, target, logger = console, fetch = global.fetch, }) {
|
11 | this.source = source;
|
12 | this.target = target;
|
13 | this.logger = logger;
|
14 | this.fetch = fetch;
|
15 | if (!validator_1.default.isURL(this.source)) {
|
16 | throw new Error("The provided URL is invalid.");
|
17 | }
|
18 | }
|
19 | static async createChannel({ fetch = global.fetch } = {}) {
|
20 | const response = await fetch("https://smee.io/new", {
|
21 | method: "HEAD",
|
22 | redirect: "manual",
|
23 | });
|
24 | const address = response.headers.get("location");
|
25 | if (!address) {
|
26 | throw new Error("Failed to create channel");
|
27 | }
|
28 | return address;
|
29 | }
|
30 | async onmessage(msg) {
|
31 | const data = JSON.parse(msg.data);
|
32 | const target = url_1.default.parse(this.target, true);
|
33 | const mergedQuery = { ...target.query, ...data.query };
|
34 | target.search = querystring_1.default.stringify(mergedQuery);
|
35 | delete data.query;
|
36 | const body = JSON.stringify(data.body);
|
37 | delete data.body;
|
38 | const headers = {};
|
39 | Object.keys(data).forEach((key) => {
|
40 | headers[key] = data[key];
|
41 | });
|
42 | headers["content-length"] = Buffer.byteLength(body);
|
43 | try {
|
44 | const response = await this.fetch(url_1.default.format(target), {
|
45 | method: "POST",
|
46 | mode: data["sec-fetch-mode"],
|
47 | cache: "default",
|
48 | body,
|
49 | headers,
|
50 | });
|
51 | this.logger.info(`POST ${response.url} - ${response.status}`);
|
52 | }
|
53 | catch (err) {
|
54 | this.logger.error(err);
|
55 | }
|
56 | }
|
57 | onopen() {
|
58 | this.logger.info("Connected", this.events.url);
|
59 | }
|
60 | onerror(err) {
|
61 | this.logger.error(err);
|
62 | }
|
63 | start() {
|
64 | const events = new eventsource_1.default(this.source);
|
65 |
|
66 | events.reconnectInterval = 0;
|
67 | events.addEventListener("message", this.onmessage.bind(this));
|
68 | events.addEventListener("open", this.onopen.bind(this));
|
69 | events.addEventListener("error", this.onerror.bind(this));
|
70 | this.logger.info(`Forwarding ${this.source} to ${this.target}`);
|
71 | this.events = events;
|
72 | return events;
|
73 | }
|
74 | }
|
75 | module.exports = Client;
|
76 |
|
\ | No newline at end of file |