@rstreamlabs/tunnels 3.8.1 → 3.8.2
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 +7 -2
- package/dist/index.d.mts +235 -223
- package/dist/index.d.ts +235 -223
- package/dist/index.js +94 -43
- package/dist/index.mjs +90 -39
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1766,9 +1766,9 @@ var RstreamTunnelsResource = class {
|
|
|
1766
1766
|
};
|
|
1767
1767
|
|
|
1768
1768
|
// src/tunnels.ts
|
|
1769
|
-
var import_rstream11 = require("@rstreamlabs/rstream");
|
|
1770
1769
|
var import_rstream12 = require("@rstreamlabs/rstream");
|
|
1771
1770
|
var import_rstream13 = require("@rstreamlabs/rstream");
|
|
1771
|
+
var import_rstream14 = require("@rstreamlabs/rstream");
|
|
1772
1772
|
|
|
1773
1773
|
// src/turn.ts
|
|
1774
1774
|
var import_rstream8 = require("@rstreamlabs/rstream");
|
|
@@ -1831,14 +1831,14 @@ function normalizeTURNPort(port) {
|
|
|
1831
1831
|
function normalizeTURNSPort(port) {
|
|
1832
1832
|
return normalizePort(port, defaultTURNSPort, "TURNS port");
|
|
1833
1833
|
}
|
|
1834
|
-
function createTURNURLs(
|
|
1834
|
+
function createTURNURLs(turnDomain, turnPort, turnsPort) {
|
|
1835
1835
|
const normalizedTURNPort = normalizeTURNPort(turnPort);
|
|
1836
1836
|
const normalizedTURNSPort = normalizeTURNSPort(turnsPort);
|
|
1837
1837
|
return [
|
|
1838
|
-
`turn:${
|
|
1839
|
-
`turn:${
|
|
1840
|
-
`turns:${
|
|
1841
|
-
`turns:${
|
|
1838
|
+
`turn:${turnDomain}:${normalizedTURNPort}?transport=udp`,
|
|
1839
|
+
`turn:${turnDomain}:${normalizedTURNPort}?transport=tcp`,
|
|
1840
|
+
`turns:${turnDomain}:${normalizedTURNSPort}?transport=udp`,
|
|
1841
|
+
`turns:${turnDomain}:${normalizedTURNSPort}?transport=tcp`
|
|
1842
1842
|
];
|
|
1843
1843
|
}
|
|
1844
1844
|
function parseTURNTokenClaims(token) {
|
|
@@ -2030,9 +2030,14 @@ async function createAPITURNCredentials(options) {
|
|
|
2030
2030
|
);
|
|
2031
2031
|
}
|
|
2032
2032
|
function createPATTURNCredentials(options) {
|
|
2033
|
-
const
|
|
2034
|
-
|
|
2035
|
-
|
|
2033
|
+
const legacyDomain = normalizeClusterDomain(options.clusterDomain);
|
|
2034
|
+
const turnDomain = normalizeClusterDomain(options.turnDomain) ?? legacyDomain;
|
|
2035
|
+
const turnRealm = normalizeClusterDomain(options.turnRealm) ?? legacyDomain;
|
|
2036
|
+
if (!turnDomain) {
|
|
2037
|
+
throw new Error("TURN domain is required for TURN PAT mode.");
|
|
2038
|
+
}
|
|
2039
|
+
if (!turnRealm) {
|
|
2040
|
+
throw new Error("TURN realm is required for TURN PAT mode.");
|
|
2036
2041
|
}
|
|
2037
2042
|
const projectEndpoint = normalizeOptionalString2(options.projectEndpoint);
|
|
2038
2043
|
if (!projectEndpoint) {
|
|
@@ -2046,12 +2051,19 @@ function createPATTURNCredentials(options) {
|
|
|
2046
2051
|
if (claims.type !== "pat") {
|
|
2047
2052
|
throw new Error("TURN PAT mode requires a PAT token.");
|
|
2048
2053
|
}
|
|
2049
|
-
const
|
|
2054
|
+
const claimsTokenEndpoint = normalizeOptionalString2(
|
|
2055
|
+
claims.token_endpoint ?? claims.tokendpoint
|
|
2056
|
+
);
|
|
2057
|
+
const configuredTokenEndpoint = normalizeOptionalString2(
|
|
2058
|
+
options.tokenEndpoint
|
|
2059
|
+
);
|
|
2060
|
+
const tokenEndpoint = configuredTokenEndpoint ?? claimsTokenEndpoint;
|
|
2050
2061
|
if (!tokenEndpoint) {
|
|
2051
|
-
throw new Error(
|
|
2062
|
+
throw new Error(
|
|
2063
|
+
"TURN PAT mode requires a PAT token carrying a token endpoint."
|
|
2064
|
+
);
|
|
2052
2065
|
}
|
|
2053
|
-
|
|
2054
|
-
if (claimsTokenEndpoint !== void 0 && claimsTokenEndpoint !== tokenEndpoint) {
|
|
2066
|
+
if (configuredTokenEndpoint !== void 0 && claimsTokenEndpoint !== void 0 && claimsTokenEndpoint !== configuredTokenEndpoint) {
|
|
2055
2067
|
throw new Error("Token endpoint does not match the PAT token.");
|
|
2056
2068
|
}
|
|
2057
2069
|
const now = normalizeNow(options.now);
|
|
@@ -2064,7 +2076,7 @@ function createPATTURNCredentials(options) {
|
|
|
2064
2076
|
import_crypto.default.hkdfSync(
|
|
2065
2077
|
"sha256",
|
|
2066
2078
|
tokenHash,
|
|
2067
|
-
Buffer.from(
|
|
2079
|
+
Buffer.from(turnRealm, "utf8"),
|
|
2068
2080
|
Buffer.from("turn-pat-v1", "utf8"),
|
|
2069
2081
|
32
|
|
2070
2082
|
)
|
|
@@ -2073,14 +2085,19 @@ function createPATTURNCredentials(options) {
|
|
|
2073
2085
|
return import_turn.turnCredentialsSchema.parse({
|
|
2074
2086
|
credential,
|
|
2075
2087
|
ttl,
|
|
2076
|
-
urls: createTURNURLs(
|
|
2088
|
+
urls: createTURNURLs(turnDomain, options.turnPort, options.turnsPort),
|
|
2077
2089
|
username
|
|
2078
2090
|
});
|
|
2079
2091
|
}
|
|
2080
2092
|
async function createAPPTURNCredentials(options) {
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
|
|
2093
|
+
const legacyDomain = normalizeClusterDomain(options.clusterDomain);
|
|
2094
|
+
const turnDomain = normalizeClusterDomain(options.turnDomain) ?? legacyDomain;
|
|
2095
|
+
const turnRealm = normalizeClusterDomain(options.turnRealm) ?? legacyDomain;
|
|
2096
|
+
if (!turnDomain) {
|
|
2097
|
+
throw new Error("TURN domain is required for TURN APP mode.");
|
|
2098
|
+
}
|
|
2099
|
+
if (!turnRealm) {
|
|
2100
|
+
throw new Error("TURN realm is required for TURN APP mode.");
|
|
2084
2101
|
}
|
|
2085
2102
|
const projectEndpoint = normalizeOptionalString2(options.projectEndpoint);
|
|
2086
2103
|
if (!projectEndpoint) {
|
|
@@ -2098,7 +2115,7 @@ async function createAPPTURNCredentials(options) {
|
|
|
2098
2115
|
const exp = normalizeNow(options.now) + ttlSeconds;
|
|
2099
2116
|
const username = `v1:${exp}:app:${projectEndpoint}:${clientId}`;
|
|
2100
2117
|
const clientPrivateKey = parseAPPPrivateKey(clientSecret);
|
|
2101
|
-
const serverPublicKeyHex = normalizeOptionalString2(options.serverPublicKeyHex) ?? await loadTURNServerPublicKeyHex(
|
|
2118
|
+
const serverPublicKeyHex = normalizeOptionalString2(options.serverPublicKeyHex) ?? await loadTURNServerPublicKeyHex(turnRealm, options);
|
|
2102
2119
|
const serverPublicKey = parseTURNServerPublicKeyHex(serverPublicKeyHex);
|
|
2103
2120
|
requireMatchingCurve(clientPrivateKey, serverPublicKey);
|
|
2104
2121
|
const sharedSecret = import_crypto.default.diffieHellman({
|
|
@@ -2109,7 +2126,7 @@ async function createAPPTURNCredentials(options) {
|
|
|
2109
2126
|
import_crypto.default.hkdfSync(
|
|
2110
2127
|
"sha256",
|
|
2111
2128
|
sharedSecret,
|
|
2112
|
-
Buffer.from(
|
|
2129
|
+
Buffer.from(turnRealm, "utf8"),
|
|
2113
2130
|
Buffer.from("turn-app-v1", "utf8"),
|
|
2114
2131
|
32
|
|
2115
2132
|
)
|
|
@@ -2118,7 +2135,7 @@ async function createAPPTURNCredentials(options) {
|
|
|
2118
2135
|
return import_turn.turnCredentialsSchema.parse({
|
|
2119
2136
|
credential,
|
|
2120
2137
|
ttl: ttlSeconds,
|
|
2121
|
-
urls: createTURNURLs(
|
|
2138
|
+
urls: createTURNURLs(turnDomain, options.turnPort, options.turnsPort),
|
|
2122
2139
|
username
|
|
2123
2140
|
});
|
|
2124
2141
|
}
|
|
@@ -2141,28 +2158,31 @@ async function createTURNCredentials(options) {
|
|
|
2141
2158
|
ttlSeconds: options.ttlSeconds
|
|
2142
2159
|
});
|
|
2143
2160
|
}
|
|
2144
|
-
const
|
|
2161
|
+
const legacyDomain = normalizeClusterDomain(options.clusterDomain);
|
|
2162
|
+
const turnDomain = normalizeClusterDomain(options.turnDomain) ?? legacyDomain ?? (projectEndpoint && options.engine ? deriveClusterDomainFromEngine(projectEndpoint, options.engine) : void 0);
|
|
2163
|
+
const turnRealm = normalizeClusterDomain(options.turnRealm) ?? legacyDomain;
|
|
2145
2164
|
if (mode === "pat") {
|
|
2146
2165
|
if (!(0, import_rstream9.isTokenCredentials)(credentials)) {
|
|
2147
2166
|
throw new Error("A PAT token is required for TURN PAT mode.");
|
|
2148
2167
|
}
|
|
2149
2168
|
return createPATTURNCredentials({
|
|
2150
|
-
clusterDomain: requireOption(
|
|
2151
|
-
clusterDomain,
|
|
2152
|
-
"Cluster domain is required for TURN PAT mode."
|
|
2153
|
-
),
|
|
2154
2169
|
now: options.now,
|
|
2155
2170
|
projectEndpoint: requireOption(
|
|
2156
2171
|
projectEndpoint,
|
|
2157
2172
|
"Project endpoint is required for TURN PAT mode."
|
|
2158
2173
|
),
|
|
2159
2174
|
token: credentials.token,
|
|
2160
|
-
tokenEndpoint:
|
|
2161
|
-
normalizeOptionalString2(options.tokenEndpoint),
|
|
2162
|
-
"Token endpoint is required for TURN PAT mode."
|
|
2163
|
-
),
|
|
2175
|
+
tokenEndpoint: options.tokenEndpoint,
|
|
2164
2176
|
ttlSeconds: options.ttlSeconds,
|
|
2177
|
+
turnDomain: requireOption(
|
|
2178
|
+
turnDomain,
|
|
2179
|
+
"TURN domain is required for TURN PAT mode."
|
|
2180
|
+
),
|
|
2165
2181
|
turnPort: options.turnPort,
|
|
2182
|
+
turnRealm: requireOption(
|
|
2183
|
+
turnRealm,
|
|
2184
|
+
"TURN realm is required for TURN PAT mode."
|
|
2185
|
+
),
|
|
2166
2186
|
turnsPort: options.turnsPort
|
|
2167
2187
|
});
|
|
2168
2188
|
}
|
|
@@ -2173,10 +2193,6 @@ async function createTURNCredentials(options) {
|
|
|
2173
2193
|
apiUrl: options.apiUrl,
|
|
2174
2194
|
clientId: credentials.clientId,
|
|
2175
2195
|
clientSecret: credentials.clientSecret,
|
|
2176
|
-
clusterDomain: requireOption(
|
|
2177
|
-
clusterDomain,
|
|
2178
|
-
"Cluster domain is required for TURN APP mode."
|
|
2179
|
-
),
|
|
2180
2196
|
keyringBaseUrl: options.keyringBaseUrl,
|
|
2181
2197
|
now: options.now,
|
|
2182
2198
|
projectEndpoint: requireOption(
|
|
@@ -2185,24 +2201,36 @@ async function createTURNCredentials(options) {
|
|
|
2185
2201
|
),
|
|
2186
2202
|
serverPublicKeyHex: options.serverPublicKeyHex,
|
|
2187
2203
|
ttlSeconds: options.ttlSeconds,
|
|
2204
|
+
turnDomain: requireOption(
|
|
2205
|
+
turnDomain,
|
|
2206
|
+
"TURN domain is required for TURN APP mode."
|
|
2207
|
+
),
|
|
2188
2208
|
turnPort: options.turnPort,
|
|
2209
|
+
turnRealm: requireOption(
|
|
2210
|
+
turnRealm,
|
|
2211
|
+
"TURN realm is required for TURN APP mode."
|
|
2212
|
+
),
|
|
2189
2213
|
turnsPort: options.turnsPort
|
|
2190
2214
|
});
|
|
2191
2215
|
}
|
|
2192
2216
|
|
|
2193
2217
|
// src/turn-resource.ts
|
|
2218
|
+
var import_rstream11 = require("@rstreamlabs/rstream");
|
|
2194
2219
|
var RstreamTURNResource = class {
|
|
2195
2220
|
client;
|
|
2196
2221
|
constructor(client) {
|
|
2197
2222
|
this.client = client;
|
|
2198
2223
|
}
|
|
2199
2224
|
async createCredentials(options = {}) {
|
|
2200
|
-
const
|
|
2225
|
+
const credentials = options.credentials ?? this.client.credentials;
|
|
2226
|
+
const localMode = options.mode === "app" || options.mode === "pat" || options.mode === void 0 && (0, import_rstream11.isClientCredentials)(credentials);
|
|
2227
|
+
const target = localMode && (options.turnDomain === void 0 || options.turnRealm === void 0) && options.clusterDomain === void 0 ? await this.client.getTURNTarget() : void 0;
|
|
2228
|
+
const engine = options.engine ?? (options.clusterDomain === void 0 && options.turnDomain === void 0 && target === void 0 ? await this.client.getEngine().catch(() => void 0) : void 0);
|
|
2201
2229
|
return await createTURNCredentials({
|
|
2202
2230
|
apiUrl: options.apiUrl ?? this.client.apiUrl,
|
|
2203
2231
|
clusterDomain: options.clusterDomain,
|
|
2204
2232
|
controlPlaneCredentials: options.controlPlaneCredentials ?? this.client.controlPlaneCredentials,
|
|
2205
|
-
credentials
|
|
2233
|
+
credentials,
|
|
2206
2234
|
engine,
|
|
2207
2235
|
keyringBaseUrl: options.keyringBaseUrl,
|
|
2208
2236
|
mode: options.mode,
|
|
@@ -2212,8 +2240,10 @@ var RstreamTURNResource = class {
|
|
|
2212
2240
|
serverPublicKeyHex: options.serverPublicKeyHex,
|
|
2213
2241
|
tokenEndpoint: options.tokenEndpoint,
|
|
2214
2242
|
ttlSeconds: options.ttlSeconds,
|
|
2215
|
-
|
|
2216
|
-
|
|
2243
|
+
turnDomain: options.turnDomain ?? target?.turnDomain,
|
|
2244
|
+
turnPort: options.turnPort ?? target?.turnPort,
|
|
2245
|
+
turnRealm: options.turnRealm ?? target?.turnRealm,
|
|
2246
|
+
turnsPort: options.turnsPort ?? target?.turnsPort
|
|
2217
2247
|
});
|
|
2218
2248
|
}
|
|
2219
2249
|
};
|
|
@@ -2394,7 +2424,7 @@ var RstreamTunnelsClient = class {
|
|
|
2394
2424
|
this.config?.projectEndpoint
|
|
2395
2425
|
);
|
|
2396
2426
|
if (region !== void 0) {
|
|
2397
|
-
if (normalizeOptionalString3(this.config?.engine) !== void 0 || (0,
|
|
2427
|
+
if (normalizeOptionalString3(this.config?.engine) !== void 0 || (0, import_rstream14.readEnvironment)().engine !== void 0) {
|
|
2398
2428
|
throw new Error(
|
|
2399
2429
|
"Region selection cannot be combined with an explicit engine override."
|
|
2400
2430
|
);
|
|
@@ -2406,17 +2436,17 @@ var RstreamTunnelsClient = class {
|
|
|
2406
2436
|
}
|
|
2407
2437
|
const project = await this.getManagedProject();
|
|
2408
2438
|
if (project !== void 0) {
|
|
2409
|
-
const engine = (0,
|
|
2439
|
+
const engine = (0, import_rstream12.getTunnelsProjectEngine)(project, region);
|
|
2410
2440
|
if (engine) return normalizeEngineAddress(engine);
|
|
2411
2441
|
}
|
|
2412
2442
|
throw new Error(
|
|
2413
2443
|
"Failed to resolve the selected regional engine from the managed tunnels project."
|
|
2414
2444
|
);
|
|
2415
2445
|
}
|
|
2416
|
-
if (projectEndpoint !== void 0 && normalizeOptionalString3(this.config?.engine) === void 0 && (0,
|
|
2446
|
+
if (projectEndpoint !== void 0 && normalizeOptionalString3(this.config?.engine) === void 0 && (0, import_rstream14.readEnvironment)().engine === void 0) {
|
|
2417
2447
|
const project = await this.getManagedProject();
|
|
2418
2448
|
if (project !== void 0) {
|
|
2419
|
-
const engine = (0,
|
|
2449
|
+
const engine = (0, import_rstream12.getTunnelsProjectEngine)(project);
|
|
2420
2450
|
if (engine) {
|
|
2421
2451
|
return normalizeEngineAddress(engine);
|
|
2422
2452
|
}
|
|
@@ -2435,6 +2465,27 @@ var RstreamTunnelsClient = class {
|
|
|
2435
2465
|
region: this.config?.region
|
|
2436
2466
|
});
|
|
2437
2467
|
}
|
|
2468
|
+
async getTURNTarget() {
|
|
2469
|
+
const project = await this.getManagedProject();
|
|
2470
|
+
if (project === void 0) {
|
|
2471
|
+
throw new Error(
|
|
2472
|
+
"Managed project endpoint is required to resolve the TURN target."
|
|
2473
|
+
);
|
|
2474
|
+
}
|
|
2475
|
+
const turnDomain = project.turnDomain?.trim() || project.domain.trim();
|
|
2476
|
+
const turnRealm = project.turnRealm?.trim();
|
|
2477
|
+
if (!turnRealm) {
|
|
2478
|
+
throw new Error(
|
|
2479
|
+
"Managed project metadata does not expose the TURN realm; use API credential mode or provide turnRealm explicitly."
|
|
2480
|
+
);
|
|
2481
|
+
}
|
|
2482
|
+
return {
|
|
2483
|
+
turnDomain,
|
|
2484
|
+
turnPort: project.turnPort,
|
|
2485
|
+
turnRealm,
|
|
2486
|
+
turnsPort: project.turnsPort
|
|
2487
|
+
};
|
|
2488
|
+
}
|
|
2438
2489
|
async getManagedProject() {
|
|
2439
2490
|
const projectEndpoint = normalizeOptionalString3(
|
|
2440
2491
|
this.config?.projectEndpoint
|
|
@@ -2511,7 +2562,7 @@ var RstreamTunnelsClient = class {
|
|
|
2511
2562
|
if (!credentials) {
|
|
2512
2563
|
return void 0;
|
|
2513
2564
|
}
|
|
2514
|
-
if (!(0,
|
|
2565
|
+
if (!(0, import_rstream13.isClientCredentials)(credentials)) {
|
|
2515
2566
|
return credentials.token;
|
|
2516
2567
|
}
|
|
2517
2568
|
const tokenParams = await this.getEngineAuthTokenParams();
|
package/dist/index.mjs
CHANGED
|
@@ -404,7 +404,7 @@ var RstreamTunnelsResource = class {
|
|
|
404
404
|
|
|
405
405
|
// src/tunnels.ts
|
|
406
406
|
import { getTunnelsProjectEngine as getTunnelsProjectEngine2 } from "@rstreamlabs/rstream";
|
|
407
|
-
import { isClientCredentials as
|
|
407
|
+
import { isClientCredentials as isClientCredentials4 } from "@rstreamlabs/rstream";
|
|
408
408
|
import { readEnvironment as readEnvironment2 } from "@rstreamlabs/rstream";
|
|
409
409
|
|
|
410
410
|
// src/turn.ts
|
|
@@ -468,14 +468,14 @@ function normalizeTURNPort(port) {
|
|
|
468
468
|
function normalizeTURNSPort(port) {
|
|
469
469
|
return normalizePort(port, defaultTURNSPort, "TURNS port");
|
|
470
470
|
}
|
|
471
|
-
function createTURNURLs(
|
|
471
|
+
function createTURNURLs(turnDomain, turnPort, turnsPort) {
|
|
472
472
|
const normalizedTURNPort = normalizeTURNPort(turnPort);
|
|
473
473
|
const normalizedTURNSPort = normalizeTURNSPort(turnsPort);
|
|
474
474
|
return [
|
|
475
|
-
`turn:${
|
|
476
|
-
`turn:${
|
|
477
|
-
`turns:${
|
|
478
|
-
`turns:${
|
|
475
|
+
`turn:${turnDomain}:${normalizedTURNPort}?transport=udp`,
|
|
476
|
+
`turn:${turnDomain}:${normalizedTURNPort}?transport=tcp`,
|
|
477
|
+
`turns:${turnDomain}:${normalizedTURNSPort}?transport=udp`,
|
|
478
|
+
`turns:${turnDomain}:${normalizedTURNSPort}?transport=tcp`
|
|
479
479
|
];
|
|
480
480
|
}
|
|
481
481
|
function parseTURNTokenClaims(token) {
|
|
@@ -667,9 +667,14 @@ async function createAPITURNCredentials(options) {
|
|
|
667
667
|
);
|
|
668
668
|
}
|
|
669
669
|
function createPATTURNCredentials(options) {
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
670
|
+
const legacyDomain = normalizeClusterDomain(options.clusterDomain);
|
|
671
|
+
const turnDomain = normalizeClusterDomain(options.turnDomain) ?? legacyDomain;
|
|
672
|
+
const turnRealm = normalizeClusterDomain(options.turnRealm) ?? legacyDomain;
|
|
673
|
+
if (!turnDomain) {
|
|
674
|
+
throw new Error("TURN domain is required for TURN PAT mode.");
|
|
675
|
+
}
|
|
676
|
+
if (!turnRealm) {
|
|
677
|
+
throw new Error("TURN realm is required for TURN PAT mode.");
|
|
673
678
|
}
|
|
674
679
|
const projectEndpoint = normalizeOptionalString2(options.projectEndpoint);
|
|
675
680
|
if (!projectEndpoint) {
|
|
@@ -683,12 +688,19 @@ function createPATTURNCredentials(options) {
|
|
|
683
688
|
if (claims.type !== "pat") {
|
|
684
689
|
throw new Error("TURN PAT mode requires a PAT token.");
|
|
685
690
|
}
|
|
686
|
-
const
|
|
691
|
+
const claimsTokenEndpoint = normalizeOptionalString2(
|
|
692
|
+
claims.token_endpoint ?? claims.tokendpoint
|
|
693
|
+
);
|
|
694
|
+
const configuredTokenEndpoint = normalizeOptionalString2(
|
|
695
|
+
options.tokenEndpoint
|
|
696
|
+
);
|
|
697
|
+
const tokenEndpoint = configuredTokenEndpoint ?? claimsTokenEndpoint;
|
|
687
698
|
if (!tokenEndpoint) {
|
|
688
|
-
throw new Error(
|
|
699
|
+
throw new Error(
|
|
700
|
+
"TURN PAT mode requires a PAT token carrying a token endpoint."
|
|
701
|
+
);
|
|
689
702
|
}
|
|
690
|
-
|
|
691
|
-
if (claimsTokenEndpoint !== void 0 && claimsTokenEndpoint !== tokenEndpoint) {
|
|
703
|
+
if (configuredTokenEndpoint !== void 0 && claimsTokenEndpoint !== void 0 && claimsTokenEndpoint !== configuredTokenEndpoint) {
|
|
692
704
|
throw new Error("Token endpoint does not match the PAT token.");
|
|
693
705
|
}
|
|
694
706
|
const now = normalizeNow(options.now);
|
|
@@ -701,7 +713,7 @@ function createPATTURNCredentials(options) {
|
|
|
701
713
|
crypto.hkdfSync(
|
|
702
714
|
"sha256",
|
|
703
715
|
tokenHash,
|
|
704
|
-
Buffer.from(
|
|
716
|
+
Buffer.from(turnRealm, "utf8"),
|
|
705
717
|
Buffer.from("turn-pat-v1", "utf8"),
|
|
706
718
|
32
|
|
707
719
|
)
|
|
@@ -710,14 +722,19 @@ function createPATTURNCredentials(options) {
|
|
|
710
722
|
return turnCredentialsSchema.parse({
|
|
711
723
|
credential,
|
|
712
724
|
ttl,
|
|
713
|
-
urls: createTURNURLs(
|
|
725
|
+
urls: createTURNURLs(turnDomain, options.turnPort, options.turnsPort),
|
|
714
726
|
username
|
|
715
727
|
});
|
|
716
728
|
}
|
|
717
729
|
async function createAPPTURNCredentials(options) {
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
|
|
730
|
+
const legacyDomain = normalizeClusterDomain(options.clusterDomain);
|
|
731
|
+
const turnDomain = normalizeClusterDomain(options.turnDomain) ?? legacyDomain;
|
|
732
|
+
const turnRealm = normalizeClusterDomain(options.turnRealm) ?? legacyDomain;
|
|
733
|
+
if (!turnDomain) {
|
|
734
|
+
throw new Error("TURN domain is required for TURN APP mode.");
|
|
735
|
+
}
|
|
736
|
+
if (!turnRealm) {
|
|
737
|
+
throw new Error("TURN realm is required for TURN APP mode.");
|
|
721
738
|
}
|
|
722
739
|
const projectEndpoint = normalizeOptionalString2(options.projectEndpoint);
|
|
723
740
|
if (!projectEndpoint) {
|
|
@@ -735,7 +752,7 @@ async function createAPPTURNCredentials(options) {
|
|
|
735
752
|
const exp = normalizeNow(options.now) + ttlSeconds;
|
|
736
753
|
const username = `v1:${exp}:app:${projectEndpoint}:${clientId}`;
|
|
737
754
|
const clientPrivateKey = parseAPPPrivateKey(clientSecret);
|
|
738
|
-
const serverPublicKeyHex = normalizeOptionalString2(options.serverPublicKeyHex) ?? await loadTURNServerPublicKeyHex(
|
|
755
|
+
const serverPublicKeyHex = normalizeOptionalString2(options.serverPublicKeyHex) ?? await loadTURNServerPublicKeyHex(turnRealm, options);
|
|
739
756
|
const serverPublicKey = parseTURNServerPublicKeyHex(serverPublicKeyHex);
|
|
740
757
|
requireMatchingCurve(clientPrivateKey, serverPublicKey);
|
|
741
758
|
const sharedSecret = crypto.diffieHellman({
|
|
@@ -746,7 +763,7 @@ async function createAPPTURNCredentials(options) {
|
|
|
746
763
|
crypto.hkdfSync(
|
|
747
764
|
"sha256",
|
|
748
765
|
sharedSecret,
|
|
749
|
-
Buffer.from(
|
|
766
|
+
Buffer.from(turnRealm, "utf8"),
|
|
750
767
|
Buffer.from("turn-app-v1", "utf8"),
|
|
751
768
|
32
|
|
752
769
|
)
|
|
@@ -755,7 +772,7 @@ async function createAPPTURNCredentials(options) {
|
|
|
755
772
|
return turnCredentialsSchema.parse({
|
|
756
773
|
credential,
|
|
757
774
|
ttl: ttlSeconds,
|
|
758
|
-
urls: createTURNURLs(
|
|
775
|
+
urls: createTURNURLs(turnDomain, options.turnPort, options.turnsPort),
|
|
759
776
|
username
|
|
760
777
|
});
|
|
761
778
|
}
|
|
@@ -778,28 +795,31 @@ async function createTURNCredentials(options) {
|
|
|
778
795
|
ttlSeconds: options.ttlSeconds
|
|
779
796
|
});
|
|
780
797
|
}
|
|
781
|
-
const
|
|
798
|
+
const legacyDomain = normalizeClusterDomain(options.clusterDomain);
|
|
799
|
+
const turnDomain = normalizeClusterDomain(options.turnDomain) ?? legacyDomain ?? (projectEndpoint && options.engine ? deriveClusterDomainFromEngine(projectEndpoint, options.engine) : void 0);
|
|
800
|
+
const turnRealm = normalizeClusterDomain(options.turnRealm) ?? legacyDomain;
|
|
782
801
|
if (mode === "pat") {
|
|
783
802
|
if (!isTokenCredentials2(credentials)) {
|
|
784
803
|
throw new Error("A PAT token is required for TURN PAT mode.");
|
|
785
804
|
}
|
|
786
805
|
return createPATTURNCredentials({
|
|
787
|
-
clusterDomain: requireOption(
|
|
788
|
-
clusterDomain,
|
|
789
|
-
"Cluster domain is required for TURN PAT mode."
|
|
790
|
-
),
|
|
791
806
|
now: options.now,
|
|
792
807
|
projectEndpoint: requireOption(
|
|
793
808
|
projectEndpoint,
|
|
794
809
|
"Project endpoint is required for TURN PAT mode."
|
|
795
810
|
),
|
|
796
811
|
token: credentials.token,
|
|
797
|
-
tokenEndpoint:
|
|
798
|
-
normalizeOptionalString2(options.tokenEndpoint),
|
|
799
|
-
"Token endpoint is required for TURN PAT mode."
|
|
800
|
-
),
|
|
812
|
+
tokenEndpoint: options.tokenEndpoint,
|
|
801
813
|
ttlSeconds: options.ttlSeconds,
|
|
814
|
+
turnDomain: requireOption(
|
|
815
|
+
turnDomain,
|
|
816
|
+
"TURN domain is required for TURN PAT mode."
|
|
817
|
+
),
|
|
802
818
|
turnPort: options.turnPort,
|
|
819
|
+
turnRealm: requireOption(
|
|
820
|
+
turnRealm,
|
|
821
|
+
"TURN realm is required for TURN PAT mode."
|
|
822
|
+
),
|
|
803
823
|
turnsPort: options.turnsPort
|
|
804
824
|
});
|
|
805
825
|
}
|
|
@@ -810,10 +830,6 @@ async function createTURNCredentials(options) {
|
|
|
810
830
|
apiUrl: options.apiUrl,
|
|
811
831
|
clientId: credentials.clientId,
|
|
812
832
|
clientSecret: credentials.clientSecret,
|
|
813
|
-
clusterDomain: requireOption(
|
|
814
|
-
clusterDomain,
|
|
815
|
-
"Cluster domain is required for TURN APP mode."
|
|
816
|
-
),
|
|
817
833
|
keyringBaseUrl: options.keyringBaseUrl,
|
|
818
834
|
now: options.now,
|
|
819
835
|
projectEndpoint: requireOption(
|
|
@@ -822,24 +838,36 @@ async function createTURNCredentials(options) {
|
|
|
822
838
|
),
|
|
823
839
|
serverPublicKeyHex: options.serverPublicKeyHex,
|
|
824
840
|
ttlSeconds: options.ttlSeconds,
|
|
841
|
+
turnDomain: requireOption(
|
|
842
|
+
turnDomain,
|
|
843
|
+
"TURN domain is required for TURN APP mode."
|
|
844
|
+
),
|
|
825
845
|
turnPort: options.turnPort,
|
|
846
|
+
turnRealm: requireOption(
|
|
847
|
+
turnRealm,
|
|
848
|
+
"TURN realm is required for TURN APP mode."
|
|
849
|
+
),
|
|
826
850
|
turnsPort: options.turnsPort
|
|
827
851
|
});
|
|
828
852
|
}
|
|
829
853
|
|
|
830
854
|
// src/turn-resource.ts
|
|
855
|
+
import { isClientCredentials as isClientCredentials3 } from "@rstreamlabs/rstream";
|
|
831
856
|
var RstreamTURNResource = class {
|
|
832
857
|
client;
|
|
833
858
|
constructor(client) {
|
|
834
859
|
this.client = client;
|
|
835
860
|
}
|
|
836
861
|
async createCredentials(options = {}) {
|
|
837
|
-
const
|
|
862
|
+
const credentials = options.credentials ?? this.client.credentials;
|
|
863
|
+
const localMode = options.mode === "app" || options.mode === "pat" || options.mode === void 0 && isClientCredentials3(credentials);
|
|
864
|
+
const target = localMode && (options.turnDomain === void 0 || options.turnRealm === void 0) && options.clusterDomain === void 0 ? await this.client.getTURNTarget() : void 0;
|
|
865
|
+
const engine = options.engine ?? (options.clusterDomain === void 0 && options.turnDomain === void 0 && target === void 0 ? await this.client.getEngine().catch(() => void 0) : void 0);
|
|
838
866
|
return await createTURNCredentials({
|
|
839
867
|
apiUrl: options.apiUrl ?? this.client.apiUrl,
|
|
840
868
|
clusterDomain: options.clusterDomain,
|
|
841
869
|
controlPlaneCredentials: options.controlPlaneCredentials ?? this.client.controlPlaneCredentials,
|
|
842
|
-
credentials
|
|
870
|
+
credentials,
|
|
843
871
|
engine,
|
|
844
872
|
keyringBaseUrl: options.keyringBaseUrl,
|
|
845
873
|
mode: options.mode,
|
|
@@ -849,8 +877,10 @@ var RstreamTURNResource = class {
|
|
|
849
877
|
serverPublicKeyHex: options.serverPublicKeyHex,
|
|
850
878
|
tokenEndpoint: options.tokenEndpoint,
|
|
851
879
|
ttlSeconds: options.ttlSeconds,
|
|
852
|
-
|
|
853
|
-
|
|
880
|
+
turnDomain: options.turnDomain ?? target?.turnDomain,
|
|
881
|
+
turnPort: options.turnPort ?? target?.turnPort,
|
|
882
|
+
turnRealm: options.turnRealm ?? target?.turnRealm,
|
|
883
|
+
turnsPort: options.turnsPort ?? target?.turnsPort
|
|
854
884
|
});
|
|
855
885
|
}
|
|
856
886
|
};
|
|
@@ -1072,6 +1102,27 @@ var RstreamTunnelsClient = class {
|
|
|
1072
1102
|
region: this.config?.region
|
|
1073
1103
|
});
|
|
1074
1104
|
}
|
|
1105
|
+
async getTURNTarget() {
|
|
1106
|
+
const project = await this.getManagedProject();
|
|
1107
|
+
if (project === void 0) {
|
|
1108
|
+
throw new Error(
|
|
1109
|
+
"Managed project endpoint is required to resolve the TURN target."
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
const turnDomain = project.turnDomain?.trim() || project.domain.trim();
|
|
1113
|
+
const turnRealm = project.turnRealm?.trim();
|
|
1114
|
+
if (!turnRealm) {
|
|
1115
|
+
throw new Error(
|
|
1116
|
+
"Managed project metadata does not expose the TURN realm; use API credential mode or provide turnRealm explicitly."
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
return {
|
|
1120
|
+
turnDomain,
|
|
1121
|
+
turnPort: project.turnPort,
|
|
1122
|
+
turnRealm,
|
|
1123
|
+
turnsPort: project.turnsPort
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1075
1126
|
async getManagedProject() {
|
|
1076
1127
|
const projectEndpoint = normalizeOptionalString3(
|
|
1077
1128
|
this.config?.projectEndpoint
|
|
@@ -1148,7 +1199,7 @@ var RstreamTunnelsClient = class {
|
|
|
1148
1199
|
if (!credentials) {
|
|
1149
1200
|
return void 0;
|
|
1150
1201
|
}
|
|
1151
|
-
if (!
|
|
1202
|
+
if (!isClientCredentials4(credentials)) {
|
|
1152
1203
|
return credentials.token;
|
|
1153
1204
|
}
|
|
1154
1205
|
const tokenParams = await this.getEngineAuthTokenParams();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstreamlabs/tunnels",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.2",
|
|
4
4
|
"description": "JS/TS SDK for the rstream Engine API and tunnel runtime APIs.",
|
|
5
5
|
"author": "@uartnet <hello@rstream.io>",
|
|
6
6
|
"repository": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"typescript-config": "*"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@rstreamlabs/rstream": "3.8.
|
|
50
|
+
"@rstreamlabs/rstream": "3.8.1",
|
|
51
51
|
"@types/jsonwebtoken": "^9.0.10",
|
|
52
52
|
"jsonwebtoken": "^9.0.3",
|
|
53
53
|
"zod": "^4.4.3"
|