@rstreamlabs/tunnels 3.8.3 → 3.10.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 +54 -0
- package/dist/{chunk-3VBF43NB.mjs → chunk-DQN5T7CI.mjs} +207 -9
- package/dist/index.d.mts +321 -256
- package/dist/index.d.ts +321 -256
- package/dist/index.js +1113 -157
- package/dist/index.mjs +778 -142
- package/dist/node-engine-http-6DJZZEME.mjs +102 -0
- package/dist/openapi.d.mts +260 -10
- package/dist/openapi.d.ts +260 -10
- package/dist/openapi.js +207 -9
- package/dist/openapi.mjs +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -340,3 +340,57 @@ npm --workspace @rstreamlabs/tunnels run type-check
|
|
|
340
340
|
npm --workspace @rstreamlabs/tunnels run lint
|
|
341
341
|
npm --workspace @rstreamlabs/tunnels run build
|
|
342
342
|
```
|
|
343
|
+
|
|
344
|
+
## Building
|
|
345
|
+
|
|
346
|
+
`npm run build` emits declarations with TypeScript before bundling them. This
|
|
347
|
+
keeps inferred schema property order deterministic; per-module declaration
|
|
348
|
+
emission during asynchronous bundling can otherwise change published archive
|
|
349
|
+
bytes between identical builds. `.generated/types/` is temporary build output. The watch
|
|
350
|
+
command continues to infer declarations directly for development.
|
|
351
|
+
|
|
352
|
+
## Certificate-only Engine access
|
|
353
|
+
|
|
354
|
+
Node.js clients may reuse a certificate identity for Engine inventory, TURN
|
|
355
|
+
issuance and SSE watch streams:
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
const client = new RstreamTunnelsClient({
|
|
359
|
+
engine: "<project-engine-host>:443",
|
|
360
|
+
tls: { cert: deviceCertificatePEM, key: devicePrivateKeyPEM },
|
|
361
|
+
});
|
|
362
|
+
try {
|
|
363
|
+
const turn = await client.turn.createCredentials({ ttlSeconds: 600 });
|
|
364
|
+
const tunnels = await client.tunnels.list();
|
|
365
|
+
} finally {
|
|
366
|
+
await client.close();
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Grant the enrolled credential `turn.credentials.create` and the required Engine
|
|
371
|
+
permissions, restricted to its project. Do not also pass token credentials.
|
|
372
|
+
The client anonymously discovers `/.well-known/rstream/engine` and caches its
|
|
373
|
+
project-bound HTTPS `mtlsApiUrl` in memory, normally for one hour. Discovery uses
|
|
374
|
+
verified server TLS without the certificate, cookies, Control plane headers or
|
|
375
|
+
redirects. Optional `mtlsApiUrl` config provides an explicit deployment override;
|
|
376
|
+
no shared YAML change is required. The ordinary browser host never requests a
|
|
377
|
+
client certificate. Browser/token behavior is unchanged.
|
|
378
|
+
|
|
379
|
+
Node.js uses HTTPS/TCP. Certificate watch streams use SSE with this reusable
|
|
380
|
+
client; the WebSocket watch adapter rejects certificate mode. The Engine itself
|
|
381
|
+
also implements HTTP/3, which the Go SDK supports for API/SSE calls.
|
|
382
|
+
|
|
383
|
+
Automatic TURN mode prefers eligible local PAT/APP derivation with known relay
|
|
384
|
+
metadata, then the Control plane, and finally the configured Engine on network
|
|
385
|
+
unavailability or HTTP 502/503/504. Certificate mode goes directly to Engine.
|
|
386
|
+
Auth, TLS verification, schema, throttling and caller cancellation errors never
|
|
387
|
+
cause fallback. Explicit `api`, `engine`, `pat` and `app` modes remain available.
|
|
388
|
+
The default total budget is ten seconds; the automatic Control plane phase gets
|
|
389
|
+
at most five seconds. APP API proofs are locally signed with issuance-only rights.
|
|
390
|
+
|
|
391
|
+
Both managed APIs return `{username, credential, urls, ttl}`; TTL is effective
|
|
392
|
+
remaining seconds, clipped to all backing-proof expirations. Issuance needs
|
|
393
|
+
`turn.credentials.create`; local derivation needs `turn.relay.allocate`. Relay
|
|
394
|
+
membership, scope, revocation and quotas are still checked. Treat the returned
|
|
395
|
+
username/password as opaque and renew before expiry. See the shared PAT/APP
|
|
396
|
+
fixtures and real HTTPS tests in `test/mtls.test.cjs`.
|
|
@@ -1000,6 +1000,19 @@ var watchParamsSchema = z7.object({
|
|
|
1000
1000
|
tunnels: tunnelFilterSchema.optional()
|
|
1001
1001
|
});
|
|
1002
1002
|
var enginePermissions = {
|
|
1003
|
+
"turn.credentials.create": {
|
|
1004
|
+
name: "TURN Credentials: Create",
|
|
1005
|
+
description: "Issue short-lived TURN credentials through either the Control plane or Engine API.",
|
|
1006
|
+
rules: [
|
|
1007
|
+
{
|
|
1008
|
+
resource: [
|
|
1009
|
+
"api.turn-server.credentials",
|
|
1010
|
+
"engine.turn-server.credentials"
|
|
1011
|
+
],
|
|
1012
|
+
action: "create"
|
|
1013
|
+
}
|
|
1014
|
+
]
|
|
1015
|
+
},
|
|
1003
1016
|
"tunnels.resources.read-only": {
|
|
1004
1017
|
name: "Discovery: Read-Only",
|
|
1005
1018
|
description: "Read active clients, active tunnels, and live state events.",
|
|
@@ -1079,13 +1092,13 @@ var engineOpenApiDocument = {
|
|
|
1079
1092
|
}
|
|
1080
1093
|
}
|
|
1081
1094
|
],
|
|
1082
|
-
security: [
|
|
1083
|
-
{
|
|
1084
|
-
bearerAuth: []
|
|
1085
|
-
}
|
|
1086
|
-
],
|
|
1095
|
+
security: [{ bearerAuth: [] }, { mutualTLS: [] }],
|
|
1087
1096
|
components: {
|
|
1088
1097
|
securitySchemes: {
|
|
1098
|
+
mutualTLS: {
|
|
1099
|
+
type: "mutualTLS",
|
|
1100
|
+
description: "EE project API only, on the dedicated authority returned by anonymous HTTPS discovery. Present one registered client certificate without a bearer or query token. Ordinary browser-facing hosts never request a client certificate."
|
|
1101
|
+
},
|
|
1089
1102
|
bearerAuth: {
|
|
1090
1103
|
type: "http",
|
|
1091
1104
|
scheme: "bearer",
|
|
@@ -1153,6 +1166,64 @@ var engineOpenApiDocument = {
|
|
|
1153
1166
|
Forbidden: errorResponse("The token is not authorized.")
|
|
1154
1167
|
},
|
|
1155
1168
|
schemas: {
|
|
1169
|
+
EngineDiscovery: {
|
|
1170
|
+
type: "object",
|
|
1171
|
+
required: ["version", "projectEndpoint", "mtlsApiUrl", "capabilities"],
|
|
1172
|
+
properties: {
|
|
1173
|
+
version: { type: "integer", const: 1 },
|
|
1174
|
+
projectEndpoint: { type: "string" },
|
|
1175
|
+
mtlsApiUrl: {
|
|
1176
|
+
type: "string",
|
|
1177
|
+
format: "uri",
|
|
1178
|
+
example: "https://project.mtls.engine.example/api"
|
|
1179
|
+
},
|
|
1180
|
+
capabilities: {
|
|
1181
|
+
type: "array",
|
|
1182
|
+
items: { type: "string" },
|
|
1183
|
+
examples: [["engine-api-mtls", "turn-credentials-v2"]]
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
},
|
|
1187
|
+
CreateTURNCredentials: {
|
|
1188
|
+
type: "object",
|
|
1189
|
+
additionalProperties: false,
|
|
1190
|
+
properties: {
|
|
1191
|
+
ttlSeconds: {
|
|
1192
|
+
type: "integer",
|
|
1193
|
+
minimum: 1,
|
|
1194
|
+
maximum: 3600,
|
|
1195
|
+
default: 600
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
TURNCredentials: {
|
|
1200
|
+
type: "object",
|
|
1201
|
+
required: ["username", "credential", "urls", "ttl"],
|
|
1202
|
+
properties: {
|
|
1203
|
+
username: {
|
|
1204
|
+
type: "string",
|
|
1205
|
+
maxLength: 512,
|
|
1206
|
+
description: "Opaque short-lived v2 issued identity. Do not parse in clients."
|
|
1207
|
+
},
|
|
1208
|
+
credential: {
|
|
1209
|
+
type: "string",
|
|
1210
|
+
maxLength: 1024,
|
|
1211
|
+
description: "Short-lived TURN password."
|
|
1212
|
+
},
|
|
1213
|
+
urls: {
|
|
1214
|
+
type: "array",
|
|
1215
|
+
minItems: 1,
|
|
1216
|
+
maxItems: 16,
|
|
1217
|
+
items: { type: "string", maxLength: 2048 }
|
|
1218
|
+
},
|
|
1219
|
+
ttl: {
|
|
1220
|
+
type: "integer",
|
|
1221
|
+
minimum: 1,
|
|
1222
|
+
maximum: 3600,
|
|
1223
|
+
description: "Effective remaining lifetime in seconds, clipped to identity, source credential and certificate expiry."
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1156
1227
|
Client: jsonSchemaFor(clientSchema),
|
|
1157
1228
|
Event: jsonSchemaFor(wsEventsSchema),
|
|
1158
1229
|
ListClientsParams: jsonSchemaFor(listClientsParamsSchema),
|
|
@@ -1187,6 +1258,133 @@ var engineOpenApiDocument = {
|
|
|
1187
1258
|
"read-managed-webtty-recordings": ["webtty.logs.read-only"]
|
|
1188
1259
|
},
|
|
1189
1260
|
paths: {
|
|
1261
|
+
"/.well-known/rstream/engine": {
|
|
1262
|
+
get: {
|
|
1263
|
+
tags: ["Discovery"],
|
|
1264
|
+
summary: "Discover the dedicated project mTLS API.",
|
|
1265
|
+
operationId: "get_engine_discovery",
|
|
1266
|
+
description: "Anonymous GET on the ordinary project Engine authority. Follow the returned HTTPS URL; do not infer an mTLS hostname. Cache per client using Cache-Control (normally one hour). No certificate, bearer token, cookie or redirect is required. Available only where an explicit EE mapping is configured.",
|
|
1267
|
+
security: [],
|
|
1268
|
+
responses: {
|
|
1269
|
+
"200": {
|
|
1270
|
+
description: "Project-bound discovery. Capabilities describe enabled server features; callers still need the corresponding rights.",
|
|
1271
|
+
headers: {
|
|
1272
|
+
"Cache-Control": {
|
|
1273
|
+
schema: { type: "string" },
|
|
1274
|
+
example: "public, max-age=3600"
|
|
1275
|
+
}
|
|
1276
|
+
},
|
|
1277
|
+
content: {
|
|
1278
|
+
"application/json": {
|
|
1279
|
+
schema: { $ref: "#/components/schemas/EngineDiscovery" }
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
"404": {
|
|
1284
|
+
description: "Dedicated mTLS API is not configured on this authority."
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
"/api/turn-server/credentials": {
|
|
1290
|
+
post: {
|
|
1291
|
+
tags: ["TURN"],
|
|
1292
|
+
summary: "Issue short-lived project TURN credentials.",
|
|
1293
|
+
operationId: "create_engine_turn_credentials",
|
|
1294
|
+
description: "EE managed projects. Same request and response contract as Control plane project TURN issuance. Empty body is valid. Issued credentials require turn.credentials.create only; turn.relay.allocate applies to local PAT/APP derivation. Issuance does not allocate a relay and does not bypass relay quotas or revocation checks.",
|
|
1295
|
+
security: [{ bearerAuth: [] }, { mutualTLS: [] }],
|
|
1296
|
+
requestBody: {
|
|
1297
|
+
required: false,
|
|
1298
|
+
content: {
|
|
1299
|
+
"application/json": {
|
|
1300
|
+
schema: { $ref: "#/components/schemas/CreateTURNCredentials" }
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
responses: {
|
|
1305
|
+
"200": {
|
|
1306
|
+
description: "Short-lived project TURN credentials.",
|
|
1307
|
+
headers: {
|
|
1308
|
+
"Cache-Control": {
|
|
1309
|
+
schema: { type: "string" },
|
|
1310
|
+
example: "no-store"
|
|
1311
|
+
}
|
|
1312
|
+
},
|
|
1313
|
+
content: {
|
|
1314
|
+
"application/json": {
|
|
1315
|
+
schema: { $ref: "#/components/schemas/TURNCredentials" }
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
},
|
|
1319
|
+
"400": {
|
|
1320
|
+
description: "Malformed, unknown or out-of-range request fields; body exceeds 4 KiB.",
|
|
1321
|
+
headers: {
|
|
1322
|
+
"Cache-Control": {
|
|
1323
|
+
schema: { type: "string" },
|
|
1324
|
+
example: "no-store"
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1328
|
+
"401": {
|
|
1329
|
+
description: "Missing, invalid, expired or mixed authentication proofs.",
|
|
1330
|
+
headers: {
|
|
1331
|
+
"Cache-Control": {
|
|
1332
|
+
schema: { type: "string" },
|
|
1333
|
+
example: "no-store"
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
"403": {
|
|
1338
|
+
description: "Missing turn.credentials.create permission, workspace membership or project resource scope.",
|
|
1339
|
+
headers: {
|
|
1340
|
+
"Cache-Control": {
|
|
1341
|
+
schema: { type: "string" },
|
|
1342
|
+
example: "no-store"
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
},
|
|
1346
|
+
"404": {
|
|
1347
|
+
description: "Project not found.",
|
|
1348
|
+
headers: {
|
|
1349
|
+
"Cache-Control": {
|
|
1350
|
+
schema: { type: "string" },
|
|
1351
|
+
example: "no-store"
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
},
|
|
1355
|
+
"409": {
|
|
1356
|
+
description: "Project or serving infrastructure is inactive.",
|
|
1357
|
+
headers: {
|
|
1358
|
+
"Cache-Control": {
|
|
1359
|
+
schema: { type: "string" },
|
|
1360
|
+
example: "no-store"
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
},
|
|
1364
|
+
"429": {
|
|
1365
|
+
description: "Rate limit exceeded; do not retry through another issuer.",
|
|
1366
|
+
headers: {
|
|
1367
|
+
"Cache-Control": {
|
|
1368
|
+
schema: { type: "string" },
|
|
1369
|
+
example: "no-store"
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
},
|
|
1373
|
+
"503": {
|
|
1374
|
+
description: "Authentication backend, serving metadata or issued keyring unavailable.",
|
|
1375
|
+
headers: {
|
|
1376
|
+
"Cache-Control": {
|
|
1377
|
+
schema: { type: "string" },
|
|
1378
|
+
example: "no-store"
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
},
|
|
1383
|
+
"x-rstream-required-rules": [
|
|
1384
|
+
{ resource: "engine.turn-server.credentials", action: "create" }
|
|
1385
|
+
]
|
|
1386
|
+
}
|
|
1387
|
+
},
|
|
1190
1388
|
"/api/openapi.json": {
|
|
1191
1389
|
get: {
|
|
1192
1390
|
tags: ["Discovery"],
|
|
@@ -1213,7 +1411,7 @@ var engineOpenApiDocument = {
|
|
|
1213
1411
|
summary: "List visible engine clients.",
|
|
1214
1412
|
operationId: "list_engine_clients",
|
|
1215
1413
|
parameters: [{ $ref: "#/components/parameters/ListClientsParams" }],
|
|
1216
|
-
security: [{ bearerAuth: [] }],
|
|
1414
|
+
security: [{ bearerAuth: [] }, { mutualTLS: [] }],
|
|
1217
1415
|
responses: {
|
|
1218
1416
|
"200": jsonArrayResponse(
|
|
1219
1417
|
"Visible clients.",
|
|
@@ -1232,7 +1430,7 @@ var engineOpenApiDocument = {
|
|
|
1232
1430
|
summary: "List visible engine tunnels.",
|
|
1233
1431
|
operationId: "list_engine_tunnels",
|
|
1234
1432
|
parameters: [{ $ref: "#/components/parameters/ListTunnelsParams" }],
|
|
1235
|
-
security: [{ bearerAuth: [] }],
|
|
1433
|
+
security: [{ bearerAuth: [] }, { mutualTLS: [] }],
|
|
1236
1434
|
responses: {
|
|
1237
1435
|
"200": jsonArrayResponse(
|
|
1238
1436
|
"Visible tunnels. Fine-grained list scopes may filter objects and project fields.",
|
|
@@ -1252,7 +1450,7 @@ var engineOpenApiDocument = {
|
|
|
1252
1450
|
summary: "Subscribe to visible engine state through Server-Sent Events.",
|
|
1253
1451
|
operationId: "watch_engine_events_sse",
|
|
1254
1452
|
parameters: [{ $ref: "#/components/parameters/WatchParams" }],
|
|
1255
|
-
security: [{ bearerAuth: [] }],
|
|
1453
|
+
security: [{ bearerAuth: [] }, { mutualTLS: [] }],
|
|
1256
1454
|
responses: {
|
|
1257
1455
|
"200": streamResponse(
|
|
1258
1456
|
"SSE stream. Each event is emitted as a data line containing a JSON Event object."
|
|
@@ -1271,7 +1469,7 @@ var engineOpenApiDocument = {
|
|
|
1271
1469
|
summary: "Subscribe to visible engine state through a WebSocket upgrade.",
|
|
1272
1470
|
operationId: "watch_engine_events_websocket",
|
|
1273
1471
|
parameters: [{ $ref: "#/components/parameters/WatchParams" }],
|
|
1274
|
-
security: [{ bearerAuth: [] }],
|
|
1472
|
+
security: [{ bearerAuth: [] }, { mutualTLS: [] }],
|
|
1275
1473
|
responses: {
|
|
1276
1474
|
"101": {
|
|
1277
1475
|
description: "WebSocket connection accepted. Frames contain JSON Event objects."
|