tturn 0.1.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.
- package/LICENSE +21 -0
- package/README.en.md +108 -0
- package/README.md +14 -0
- package/README.zh-CN.md +107 -0
- package/dist/app.d.ts +1 -0
- package/dist/app.js +47 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +74 -0
- package/dist/credentials.d.ts +2 -0
- package/dist/credentials.js +13 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +29 -0
- package/dist/native-binding.d.ts +22 -0
- package/dist/native-binding.js +34 -0
- package/dist/service.d.ts +12 -0
- package/dist/service.js +37 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.js +2 -0
- package/index.node +0 -0
- package/package.json +50 -0
- package/tturn.win32-x64-msvc.node +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Tturn (English)
|
|
2
|
+
|
|
3
|
+
[English](./README.en.md) | [中文](./README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
`tturn` is a high-performance TURN server package for Node.js.
|
|
6
|
+
It uses an embedded native core (Rust + N-API), so you can install and run it directly from npm without Docker and without an external `turnserver.exe` runtime dependency.
|
|
7
|
+
|
|
8
|
+
## 1) What this project is
|
|
9
|
+
|
|
10
|
+
- Embedded TURN server for Node.js applications.
|
|
11
|
+
- Native data plane implemented in Rust for better throughput and lower overhead than pure JavaScript TURN implementations.
|
|
12
|
+
- Programmatic API and CLI are both provided.
|
|
13
|
+
- Time-limited TURN credentials are generated with HMAC-SHA1 (standard TURN REST style).
|
|
14
|
+
|
|
15
|
+
## 2) Current capabilities
|
|
16
|
+
|
|
17
|
+
- Start / stop TURN service from Node.
|
|
18
|
+
- Issue short-lived credentials.
|
|
19
|
+
- Return WebRTC ICE `urls/username/credential` directly.
|
|
20
|
+
- Health check (`running: boolean`).
|
|
21
|
+
|
|
22
|
+
## 3) Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i tturn
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 4) Quick start (Node API)
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { Tturn } from "tturn";
|
|
32
|
+
|
|
33
|
+
const turn = new Tturn({
|
|
34
|
+
realm: "turn.example.com",
|
|
35
|
+
authSecret: "replace-with-your-secret",
|
|
36
|
+
publicIp: "1.2.3.4",
|
|
37
|
+
listenPort: 3478
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await turn.start();
|
|
41
|
+
|
|
42
|
+
const ice = turn.issueCredential({ ttlSec: 600, userId: "user-1001" });
|
|
43
|
+
console.log(ice);
|
|
44
|
+
|
|
45
|
+
// stop when exiting process
|
|
46
|
+
await turn.stop();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 5) CLI usage
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Start embedded TURN service
|
|
53
|
+
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret tturn start
|
|
54
|
+
|
|
55
|
+
# Print one ICE credential payload
|
|
56
|
+
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret tturn credential
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 6) API options
|
|
60
|
+
|
|
61
|
+
- `realm` (required): TURN realm/domain.
|
|
62
|
+
- `authSecret` (required): shared secret for dynamic credentials.
|
|
63
|
+
- `listenPort` (default `3478`): TURN listening port.
|
|
64
|
+
- `publicIp` (optional, recommended): public relay IP exposed to clients.
|
|
65
|
+
- `listeningIp` (default `0.0.0.0`): bind address.
|
|
66
|
+
- `minPort` / `maxPort`: reserved for relay port range control in next iterations.
|
|
67
|
+
|
|
68
|
+
## 7) Build from source
|
|
69
|
+
|
|
70
|
+
Requirements:
|
|
71
|
+
|
|
72
|
+
- Node.js >= 18
|
|
73
|
+
- Rust toolchain (stable)
|
|
74
|
+
|
|
75
|
+
Commands:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install
|
|
79
|
+
npm run build:native
|
|
80
|
+
./node_modules/.bin/tsc -p tsconfig.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then run demo app:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
node dist/app.js
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Edit fixed config in `src/app.ts` before running.
|
|
90
|
+
|
|
91
|
+
## 8) Verify with Google WebRTC tool
|
|
92
|
+
|
|
93
|
+
1. Start service (`node dist/app.js`).
|
|
94
|
+
2. Copy printed `urls`, `username`, `credential`.
|
|
95
|
+
3. Open Google Trickle ICE tool and paste the ICE server config.
|
|
96
|
+
4. Gather candidates and confirm relay candidates are returned.
|
|
97
|
+
|
|
98
|
+
## 9) Publish to npm
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm login
|
|
102
|
+
npm publish --access public
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Notes:
|
|
106
|
+
|
|
107
|
+
- npm package names must be lowercase, so publish as `tturn`.
|
|
108
|
+
- For production users across multiple platforms, publish prebuilt `.node` artifacts for each target platform/arch.
|
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Tturn
|
|
2
|
+
|
|
3
|
+
[English](./README.en.md) | [中文](./README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
`tturn` is a high-performance TURN server package for Node.js with an embedded native core (Rust + N-API).
|
|
6
|
+
|
|
7
|
+
- No Docker runtime required.
|
|
8
|
+
- No external `turnserver.exe` runtime dependency.
|
|
9
|
+
- Programmatic API and CLI included.
|
|
10
|
+
|
|
11
|
+
Please read full docs:
|
|
12
|
+
|
|
13
|
+
- English: `README.en.md`
|
|
14
|
+
- 中文:`README.zh-CN.md`
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Tturn(中文)
|
|
2
|
+
|
|
3
|
+
[English](./README.en.md) | [中文](./README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
`tturn` 是一个高性能的 Node.js TURN 服务包。
|
|
6
|
+
它使用内嵌原生核心(Rust + N-API),可以直接通过 npm 安装并运行,不依赖 Docker,也不需要额外安装 `turnserver.exe` 作为运行时。
|
|
7
|
+
|
|
8
|
+
## 1)项目介绍
|
|
9
|
+
|
|
10
|
+
- `tturn` 是一个可直接在 Node.js 中运行的 TURN 服务包。
|
|
11
|
+
- 底层是 Rust + N-API 原生实现,性能和资源效率优于纯 JS TURN 实现。
|
|
12
|
+
- 不依赖 Docker,也不需要额外安装 `turnserver.exe` 作为运行时。
|
|
13
|
+
- 同时提供 Node API 和 CLI 两种使用方式。
|
|
14
|
+
|
|
15
|
+
## 2)当前功能
|
|
16
|
+
|
|
17
|
+
- 在 Node 中启动 / 停止 TURN 服务。
|
|
18
|
+
- 生成短时效 TURN 凭证(HMAC-SHA1)。
|
|
19
|
+
- 直接输出 WebRTC 所需的 ICE 参数(`urls/username/credential`)。
|
|
20
|
+
- 基础健康状态检查(`running: boolean`)。
|
|
21
|
+
|
|
22
|
+
## 3)安装
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i tturn
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 4)Node API 快速使用
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { Tturn } from "tturn";
|
|
32
|
+
|
|
33
|
+
const turn = new Tturn({
|
|
34
|
+
realm: "turn.example.com",
|
|
35
|
+
authSecret: "replace-with-your-secret",
|
|
36
|
+
publicIp: "1.2.3.4",
|
|
37
|
+
listenPort: 3478
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await turn.start();
|
|
41
|
+
|
|
42
|
+
const ice = turn.issueCredential({ ttlSec: 600, userId: "user-1001" });
|
|
43
|
+
console.log(ice);
|
|
44
|
+
|
|
45
|
+
await turn.stop();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 5)CLI 用法
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# 启动内置 TURN 服务
|
|
52
|
+
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret tturn start
|
|
53
|
+
|
|
54
|
+
# 生成一组 ICE 凭证
|
|
55
|
+
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret tturn credential
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 6)配置参数说明
|
|
59
|
+
|
|
60
|
+
- `realm`(必填):TURN realm / 域名。
|
|
61
|
+
- `authSecret`(必填):动态凭证签名密钥。
|
|
62
|
+
- `listenPort`(默认 `3478`):TURN 监听端口。
|
|
63
|
+
- `publicIp`(建议配置):客户端访问的公网 IP。
|
|
64
|
+
- `listeningIp`(默认 `0.0.0.0`):本地绑定地址。
|
|
65
|
+
- `minPort` / `maxPort`:预留给后续中继端口范围控制。
|
|
66
|
+
|
|
67
|
+
## 7)源码构建
|
|
68
|
+
|
|
69
|
+
环境要求:
|
|
70
|
+
|
|
71
|
+
- Node.js >= 18
|
|
72
|
+
- Rust 稳定版工具链
|
|
73
|
+
|
|
74
|
+
构建命令:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm install
|
|
78
|
+
npm run build:native
|
|
79
|
+
./node_modules/.bin/tsc -p tsconfig.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
运行示例:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node dist/app.js
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
运行前请先修改 `src/app.ts` 中的固定配置项。
|
|
89
|
+
|
|
90
|
+
## 8)使用 Google WebRTC 工具验证
|
|
91
|
+
|
|
92
|
+
1. 启动服务:`node dist/app.js`
|
|
93
|
+
2. 复制控制台打印的 `urls`、`username`、`credential`
|
|
94
|
+
3. 打开 Google Trickle ICE 页面,填入 ICE Server
|
|
95
|
+
4. 执行采集并确认出现 relay candidate
|
|
96
|
+
|
|
97
|
+
## 9)发布到 npm
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm login
|
|
101
|
+
npm publish --access public
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
说明:
|
|
105
|
+
|
|
106
|
+
- npm 包名必须小写,所以发布名为 `tturn`。
|
|
107
|
+
- 生产环境建议按平台预编译并发布对应 `.node` 二进制文件。
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("./index");
|
|
4
|
+
const APP_CONFIG = {
|
|
5
|
+
realm: "turn.example.com",
|
|
6
|
+
authSecret: "replace-with-your-secret",
|
|
7
|
+
publicIp: "1.2.3.4",
|
|
8
|
+
listenPort: 3478,
|
|
9
|
+
ttlSec: 600
|
|
10
|
+
};
|
|
11
|
+
async function main() {
|
|
12
|
+
const service = new index_1.Tturn({
|
|
13
|
+
realm: APP_CONFIG.realm,
|
|
14
|
+
authSecret: APP_CONFIG.authSecret,
|
|
15
|
+
publicIp: APP_CONFIG.publicIp,
|
|
16
|
+
listenPort: APP_CONFIG.listenPort
|
|
17
|
+
});
|
|
18
|
+
await service.start();
|
|
19
|
+
const ice = service.issueCredential({ ttlSec: APP_CONFIG.ttlSec, userId: "google-test" });
|
|
20
|
+
console.log("[tturn] started.");
|
|
21
|
+
console.log("[tturn] use this ICE server in Google WebRTC tool:");
|
|
22
|
+
console.log(JSON.stringify(ice, null, 2));
|
|
23
|
+
console.log("[tturn] health:", service.health());
|
|
24
|
+
console.log("[tturn] press Ctrl+C to stop.");
|
|
25
|
+
await waitForSignal();
|
|
26
|
+
await service.stop();
|
|
27
|
+
console.log("[tturn] stopped.");
|
|
28
|
+
}
|
|
29
|
+
function waitForSignal() {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const keepAlive = setInterval(() => {
|
|
32
|
+
// Keep Node event loop active while native TURN runs.
|
|
33
|
+
}, 60000);
|
|
34
|
+
const onSignal = () => {
|
|
35
|
+
process.off("SIGINT", onSignal);
|
|
36
|
+
process.off("SIGTERM", onSignal);
|
|
37
|
+
clearInterval(keepAlive);
|
|
38
|
+
resolve();
|
|
39
|
+
};
|
|
40
|
+
process.on("SIGINT", onSignal);
|
|
41
|
+
process.on("SIGTERM", onSignal);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
main().catch((error) => {
|
|
45
|
+
console.error(`[tturn] startup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
});
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
async function run() {
|
|
6
|
+
const command = process.argv[2];
|
|
7
|
+
if (command === "credential") {
|
|
8
|
+
const secret = mustGetEnv("TURN_SECRET");
|
|
9
|
+
const realm = mustGetEnv("TURN_REALM");
|
|
10
|
+
const service = (0, index_1.createTurnService)({ realm, authSecret: secret, publicIp: process.env.TURN_PUBLIC_IP });
|
|
11
|
+
const ice = service.issueCredential({
|
|
12
|
+
ttlSec: process.env.TTURN_TTL_SEC ? Number(process.env.TTURN_TTL_SEC) : 3600,
|
|
13
|
+
userId: process.env.TTURN_USER_ID
|
|
14
|
+
});
|
|
15
|
+
process.stdout.write(`${JSON.stringify(ice, null, 2)}\n`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (command === "start") {
|
|
19
|
+
const secret = mustGetEnv("TURN_SECRET");
|
|
20
|
+
const realm = mustGetEnv("TURN_REALM");
|
|
21
|
+
const service = (0, index_1.createTurnService)({
|
|
22
|
+
realm,
|
|
23
|
+
authSecret: secret,
|
|
24
|
+
publicIp: process.env.TURN_PUBLIC_IP,
|
|
25
|
+
listenPort: process.env.TURN_PORT ? Number(process.env.TURN_PORT) : 3478
|
|
26
|
+
});
|
|
27
|
+
await service.start();
|
|
28
|
+
process.stdout.write("tturn started\n");
|
|
29
|
+
await waitForSignal();
|
|
30
|
+
await service.stop();
|
|
31
|
+
process.stdout.write("tturn stopped\n");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
printUsage();
|
|
35
|
+
process.exitCode = 1;
|
|
36
|
+
}
|
|
37
|
+
function mustGetEnv(name) {
|
|
38
|
+
const value = process.env[name];
|
|
39
|
+
if (!value) {
|
|
40
|
+
throw new Error(`Missing required env: ${name}`);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function printUsage() {
|
|
45
|
+
process.stdout.write([
|
|
46
|
+
"tturn usage:",
|
|
47
|
+
" tturn start # starts embedded native TURN service",
|
|
48
|
+
" tturn credential # prints one ICE server credential JSON",
|
|
49
|
+
"",
|
|
50
|
+
"required env:",
|
|
51
|
+
" TURN_REALM, TURN_SECRET",
|
|
52
|
+
"optional env:",
|
|
53
|
+
" TURN_PUBLIC_IP, TURN_PORT, TTURN_TTL_SEC, TTURN_USER_ID"
|
|
54
|
+
].join("\n") + "\n");
|
|
55
|
+
}
|
|
56
|
+
function waitForSignal() {
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
const keepAlive = setInterval(() => {
|
|
59
|
+
// Keep Node event loop active while native TURN runs.
|
|
60
|
+
}, 60000);
|
|
61
|
+
const onSignal = () => {
|
|
62
|
+
process.off("SIGINT", onSignal);
|
|
63
|
+
process.off("SIGTERM", onSignal);
|
|
64
|
+
clearInterval(keepAlive);
|
|
65
|
+
resolve();
|
|
66
|
+
};
|
|
67
|
+
process.on("SIGINT", onSignal);
|
|
68
|
+
process.on("SIGTERM", onSignal);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
run().catch((error) => {
|
|
72
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTurnCredential = createTurnCredential;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const DEFAULT_TTL_SEC = 3600;
|
|
6
|
+
function createTurnCredential(authSecret, options = {}) {
|
|
7
|
+
const ttlSec = Math.max(60, options.ttlSec ?? DEFAULT_TTL_SEC);
|
|
8
|
+
const expiresAt = Math.floor(Date.now() / 1000) + ttlSec;
|
|
9
|
+
const userPrefix = options.userId ? `${options.userId}:` : "";
|
|
10
|
+
const username = `${userPrefix}${expiresAt}`;
|
|
11
|
+
const password = (0, node_crypto_1.createHmac)("sha1", authSecret).update(username).digest("base64");
|
|
12
|
+
return { username, password, ttlSec, expiresAt };
|
|
13
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createTurnCredential } from "./credentials";
|
|
2
|
+
import { TurnService } from "./service";
|
|
3
|
+
import { TurnServiceOptions } from "./types";
|
|
4
|
+
export * from "./types";
|
|
5
|
+
export { createTurnCredential, TurnService };
|
|
6
|
+
export declare class Tturn extends TurnService {
|
|
7
|
+
}
|
|
8
|
+
export declare function createTurnService(options: TurnServiceOptions): TurnService;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Tturn = exports.TurnService = exports.createTurnCredential = void 0;
|
|
18
|
+
exports.createTurnService = createTurnService;
|
|
19
|
+
const credentials_1 = require("./credentials");
|
|
20
|
+
Object.defineProperty(exports, "createTurnCredential", { enumerable: true, get: function () { return credentials_1.createTurnCredential; } });
|
|
21
|
+
const service_1 = require("./service");
|
|
22
|
+
Object.defineProperty(exports, "TurnService", { enumerable: true, get: function () { return service_1.TurnService; } });
|
|
23
|
+
__exportStar(require("./types"), exports);
|
|
24
|
+
class Tturn extends service_1.TurnService {
|
|
25
|
+
}
|
|
26
|
+
exports.Tturn = Tturn;
|
|
27
|
+
function createTurnService(options) {
|
|
28
|
+
return new service_1.TurnService(options);
|
|
29
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { TurnServiceOptions } from "./types";
|
|
2
|
+
interface NativeCredential {
|
|
3
|
+
username: string;
|
|
4
|
+
password: string;
|
|
5
|
+
ttlSec: number;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
}
|
|
8
|
+
interface NativeTurnService {
|
|
9
|
+
start(detached?: boolean): void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
issueCredential(ttlSec?: number, userId?: string): NativeCredential;
|
|
12
|
+
getIceUrls(): string[];
|
|
13
|
+
health(): {
|
|
14
|
+
running: boolean;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface NativeBinding {
|
|
18
|
+
NativeTurnService: new (options: TurnServiceOptions) => NativeTurnService;
|
|
19
|
+
}
|
|
20
|
+
declare const binding: NativeBinding;
|
|
21
|
+
export type { NativeTurnService, NativeCredential };
|
|
22
|
+
export { binding };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.binding = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
function loadNativeBinding() {
|
|
7
|
+
const root = (0, node_path_1.join)(__dirname, "..");
|
|
8
|
+
const candidates = [
|
|
9
|
+
(0, node_path_1.join)(root, "index.node"),
|
|
10
|
+
(0, node_path_1.join)(root, "native", "index.node"),
|
|
11
|
+
(0, node_path_1.join)(root, binaryName())
|
|
12
|
+
];
|
|
13
|
+
for (const filePath of candidates) {
|
|
14
|
+
if (!(0, node_fs_1.existsSync)(filePath)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
return require(filePath);
|
|
18
|
+
}
|
|
19
|
+
throw new Error([
|
|
20
|
+
"Native binding not found.",
|
|
21
|
+
"Run `npm run build:native` before using Tturn in development.",
|
|
22
|
+
"For published builds, ensure prebuilt `.node` artifacts are bundled."
|
|
23
|
+
].join(" "));
|
|
24
|
+
}
|
|
25
|
+
function binaryName() {
|
|
26
|
+
const platform = process.platform;
|
|
27
|
+
const arch = process.arch;
|
|
28
|
+
if (platform === "win32") {
|
|
29
|
+
return `tturn.${platform}-${arch}-msvc.node`;
|
|
30
|
+
}
|
|
31
|
+
return `tturn.${platform}-${arch}.node`;
|
|
32
|
+
}
|
|
33
|
+
const binding = loadNativeBinding();
|
|
34
|
+
exports.binding = binding;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IceServer, IssueCredentialOptions, StartOptions, TurnServiceOptions } from "./types";
|
|
2
|
+
export declare class TurnService {
|
|
3
|
+
private readonly native;
|
|
4
|
+
constructor(options: TurnServiceOptions);
|
|
5
|
+
start(startOptions?: StartOptions): Promise<void>;
|
|
6
|
+
stop(): Promise<void>;
|
|
7
|
+
issueCredential(issueOptions?: IssueCredentialOptions): IceServer;
|
|
8
|
+
getIceUrls(): string[];
|
|
9
|
+
health(): {
|
|
10
|
+
running: boolean;
|
|
11
|
+
};
|
|
12
|
+
}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TurnService = void 0;
|
|
4
|
+
const native_binding_1 = require("./native-binding");
|
|
5
|
+
class TurnService {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.native = new native_binding_1.binding.NativeTurnService({
|
|
8
|
+
...options,
|
|
9
|
+
listenPort: options.listenPort ?? 3478,
|
|
10
|
+
minPort: options.minPort ?? 49152,
|
|
11
|
+
maxPort: options.maxPort ?? 65535,
|
|
12
|
+
publicIp: options.publicIp ?? options.realm,
|
|
13
|
+
listeningIp: options.listeningIp ?? "0.0.0.0"
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async start(startOptions = {}) {
|
|
17
|
+
this.native.start(Boolean(startOptions.detached));
|
|
18
|
+
}
|
|
19
|
+
async stop() {
|
|
20
|
+
this.native.stop();
|
|
21
|
+
}
|
|
22
|
+
issueCredential(issueOptions = {}) {
|
|
23
|
+
const out = this.native.issueCredential(issueOptions.ttlSec, issueOptions.userId);
|
|
24
|
+
return {
|
|
25
|
+
urls: this.native.getIceUrls(),
|
|
26
|
+
username: out.username,
|
|
27
|
+
credential: out.password
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
getIceUrls() {
|
|
31
|
+
return this.native.getIceUrls();
|
|
32
|
+
}
|
|
33
|
+
health() {
|
|
34
|
+
return this.native.health();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.TurnService = TurnService;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface TurnCredential {
|
|
2
|
+
username: string;
|
|
3
|
+
password: string;
|
|
4
|
+
ttlSec: number;
|
|
5
|
+
expiresAt: number;
|
|
6
|
+
}
|
|
7
|
+
export interface IceServer {
|
|
8
|
+
urls: string[];
|
|
9
|
+
username: string;
|
|
10
|
+
credential: string;
|
|
11
|
+
}
|
|
12
|
+
export interface IssueCredentialOptions {
|
|
13
|
+
ttlSec?: number;
|
|
14
|
+
userId?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface TurnServiceOptions {
|
|
17
|
+
realm: string;
|
|
18
|
+
authSecret: string;
|
|
19
|
+
listenPort?: number;
|
|
20
|
+
minPort?: number;
|
|
21
|
+
maxPort?: number;
|
|
22
|
+
publicIp?: string;
|
|
23
|
+
listeningIp?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface StartOptions {
|
|
26
|
+
detached?: boolean;
|
|
27
|
+
}
|
package/dist/types.js
ADDED
package/index.node
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tturn",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "High-performance TURN server for Node.js with embedded native core",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"turn",
|
|
7
|
+
"webrtc",
|
|
8
|
+
"napi",
|
|
9
|
+
"rust",
|
|
10
|
+
"stun",
|
|
11
|
+
"relay"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "",
|
|
15
|
+
"homepage": "https://github.com/txzh007/ttrun",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/txzh007/ttrun.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/txzh007/ttrun/issues"
|
|
22
|
+
},
|
|
23
|
+
"main": "dist/index.js",
|
|
24
|
+
"types": "dist/index.d.ts",
|
|
25
|
+
"bin": {
|
|
26
|
+
"tturn": "dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"index.node",
|
|
31
|
+
"tturn.*.node",
|
|
32
|
+
"README.md",
|
|
33
|
+
"README.en.md",
|
|
34
|
+
"README.zh-CN.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build:native": "node scripts/build-native.js",
|
|
42
|
+
"build": "npm run build:native && tsc -p tsconfig.json",
|
|
43
|
+
"build:ts": "tsc -p tsconfig.json"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.13.10",
|
|
48
|
+
"typescript": "^5.8.2"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
Binary file
|