gologin-api-wrapper 0.0.1
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.
- package/README.md +63 -0
- package/bin/be-linkedbot-runner.js +3 -0
- package/dist/index.js +140 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# gologin-api-wrapper (local GoLogin API wrapper)
|
|
2
|
+
|
|
3
|
+
This is a small local companion you run on **your own machine** to launch GoLogin profiles locally.
|
|
4
|
+
|
|
5
|
+
The hosted web app (e.g. Vercel) cannot launch local browsers, so it talks to this runner over `http://127.0.0.1`.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js **20.x** installed
|
|
10
|
+
- A GoLogin API token
|
|
11
|
+
|
|
12
|
+
## Setup
|
|
13
|
+
|
|
14
|
+
## Install (recommended)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i -g gologin-api-wrapper
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
1) Create a `.env` file (or export env vars in your shell):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
export GOLOGIN_TOKEN="..."
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Optional (recommended): restrict which web origins can call the localhost API:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export ALLOWED_ORIGINS="https://app.flygen.in,http://localhost:3001"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2) Install deps and build:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install
|
|
36
|
+
npm run build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Run
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gologin-api-wrapper start --port 17327
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Health check:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
curl http://127.0.0.1:17327/health
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Open a GoLogin profile (launches a local headful Orbita):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
curl -X POST http://127.0.0.1:17327/gologin/open \
|
|
55
|
+
-H 'Content-Type: application/json' \
|
|
56
|
+
-d '{"profileId":"YOUR_PROFILE_ID"}'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
- `GET /health`
|
|
62
|
+
- `POST /gologin/open` `{ profileId }` -> `{ profileId, wsEndpoint }`
|
|
63
|
+
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { URL } from "node:url";
|
|
3
|
+
function parseArgs(argv) {
|
|
4
|
+
const cmd = argv[2] ?? "start";
|
|
5
|
+
let port = 17327;
|
|
6
|
+
let host = "127.0.0.1";
|
|
7
|
+
for (let i = 3; i < argv.length; i += 1) {
|
|
8
|
+
const a = argv[i];
|
|
9
|
+
if (a === "--port") {
|
|
10
|
+
const v = argv[i + 1];
|
|
11
|
+
if (v)
|
|
12
|
+
port = Number(v);
|
|
13
|
+
i += 1;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (a === "--host") {
|
|
17
|
+
const v = argv[i + 1];
|
|
18
|
+
if (v)
|
|
19
|
+
host = v;
|
|
20
|
+
i += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { cmd, port, host };
|
|
25
|
+
}
|
|
26
|
+
function sendJson(res, status, body) {
|
|
27
|
+
const buf = Buffer.from(JSON.stringify(body));
|
|
28
|
+
res.statusCode = status;
|
|
29
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
30
|
+
res.setHeader("Content-Length", String(buf.length));
|
|
31
|
+
res.end(buf);
|
|
32
|
+
}
|
|
33
|
+
function applyCors(req, res) {
|
|
34
|
+
// With no-auth localhost API, we should at least avoid blindly enabling CORS in production.
|
|
35
|
+
// Configure a strict allowlist via ALLOWED_ORIGINS="https://app.example.com,http://localhost:3001"
|
|
36
|
+
const origin = req.headers.origin;
|
|
37
|
+
const allow = (process.env.ALLOWED_ORIGINS || "")
|
|
38
|
+
.split(",")
|
|
39
|
+
.map(s => s.trim())
|
|
40
|
+
.filter(Boolean);
|
|
41
|
+
if (!origin)
|
|
42
|
+
return true;
|
|
43
|
+
if (allow.length === 0) {
|
|
44
|
+
// Dev-friendly default: allow all origins if allowlist isn't set.
|
|
45
|
+
// Users can lock it down with ALLOWED_ORIGINS.
|
|
46
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
47
|
+
res.setHeader("Vary", "Origin");
|
|
48
|
+
}
|
|
49
|
+
else if (allow.includes(origin)) {
|
|
50
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
51
|
+
res.setHeader("Vary", "Origin");
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
sendJson(res, 403, { message: "Origin not allowed" });
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
|
|
58
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
59
|
+
res.setHeader("Access-Control-Max-Age", "600");
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
async function readJsonBody(req) {
|
|
63
|
+
const chunks = [];
|
|
64
|
+
for await (const chunk of req) {
|
|
65
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
66
|
+
}
|
|
67
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
68
|
+
if (!raw)
|
|
69
|
+
return {};
|
|
70
|
+
return JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
async function main() {
|
|
73
|
+
// gologin@2.1.29 currently uses JSON import assertions syntax that breaks on Node 23+.
|
|
74
|
+
// In practice, this runner is expected to run on Node 20.x.
|
|
75
|
+
const major = Number(process.versions.node.split(".")[0] || "0");
|
|
76
|
+
if (major !== 20) {
|
|
77
|
+
console.error(`Unsupported Node.js version: ${process.versions.node}. ` +
|
|
78
|
+
"Please use Node 20.x to run gologin-api-wrapper.");
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
const { cmd, port, host } = parseArgs(process.argv);
|
|
82
|
+
if (cmd !== "start") {
|
|
83
|
+
console.error(`Unknown command: ${cmd}. Supported: start`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const gologinToken = process.env.GOLOGIN_TOKEN;
|
|
87
|
+
if (!gologinToken) {
|
|
88
|
+
console.error("GOLOGIN_TOKEN is not set");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
// Lazy-load gologin to ensure the Node version guard runs before the module is evaluated.
|
|
92
|
+
const { GologinApi: GL } = (await import("gologin"));
|
|
93
|
+
const server = http.createServer(async (req, res) => {
|
|
94
|
+
try {
|
|
95
|
+
if (!applyCors(req, res))
|
|
96
|
+
return;
|
|
97
|
+
if (req.method === "OPTIONS") {
|
|
98
|
+
res.statusCode = 204;
|
|
99
|
+
res.end();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
103
|
+
if (req.method === "GET" && url.pathname === "/health") {
|
|
104
|
+
sendJson(res, 200, { ok: true, name: "gologin-api-wrapper" });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (req.method === "POST" && url.pathname === "/gologin/open") {
|
|
108
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
109
|
+
const profileId = (body.profileId || "").trim();
|
|
110
|
+
if (!profileId) {
|
|
111
|
+
sendJson(res, 400, { message: "profileId is required" });
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const gologin = GL({ token: gologinToken });
|
|
115
|
+
// gologin types model launch params as a union; for local launch we combine fields.
|
|
116
|
+
const { browser } = await gologin.launch({
|
|
117
|
+
cloud: false,
|
|
118
|
+
headless: false,
|
|
119
|
+
profileId,
|
|
120
|
+
});
|
|
121
|
+
const wsEndpoint = browser.wsEndpoint();
|
|
122
|
+
const out = { profileId, wsEndpoint };
|
|
123
|
+
sendJson(res, 200, out);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
sendJson(res, 404, { message: "Not found" });
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
130
|
+
sendJson(res, 500, { message });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
server.listen(port, host, () => {
|
|
134
|
+
console.log(`gologin-api-wrapper listening on http://${host}:${port}`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
main().catch(err => {
|
|
138
|
+
console.error(err);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gologin-api-wrapper",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Local GoLogin API wrapper (launches GoLogin locally via a localhost API)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"gologin-api-wrapper": "bin/be-linkedbot-runner.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin",
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": "20.x"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"dev": "tsx src/index.ts start",
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"start": "node dist/index.js start",
|
|
26
|
+
"lint": "eslint src/**/*.ts",
|
|
27
|
+
"type-check": "tsc --noEmit",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"gologin": "^2.1.29"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@eslint/js": "^9.27.0",
|
|
35
|
+
"@types/node": "^22.13.10",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
|
37
|
+
"@typescript-eslint/parser": "^8.33.0",
|
|
38
|
+
"eslint": "^9.27.0",
|
|
39
|
+
"globals": "^15.15.0",
|
|
40
|
+
"tsx": "^4.20.5",
|
|
41
|
+
"typescript": "^5.8.3"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|