@rstreamlabs/tunnels 3.7.0 → 3.8.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.
@@ -243,7 +243,7 @@ var routingPathSchema = z3.object({
243
243
  crossRegionRoutingAllowed: z3.boolean(),
244
244
  ingress: routingNodeSchema,
245
245
  owner: routingNodeSchema,
246
- agentTarget: routingNodeSchema
246
+ anchor: routingNodeSchema
247
247
  });
248
248
  var routingSchema = z3.discriminatedUnion("decision", [
249
249
  z3.object({
package/dist/index.d.mts CHANGED
@@ -614,7 +614,7 @@ declare const streamSummaryEventSchema: z.ZodObject<{
614
614
  region: z.ZodString;
615
615
  generation: z.ZodOptional<z.ZodString>;
616
616
  }, z.core.$strip>;
617
- agentTarget: z.ZodObject<{
617
+ anchor: z.ZodObject<{
618
618
  engineId: z.ZodString;
619
619
  region: z.ZodString;
620
620
  generation: z.ZodOptional<z.ZodString>;
@@ -2747,7 +2747,7 @@ declare const projectLogEventsSchema: z.ZodObject<{
2747
2747
  region: z.ZodString;
2748
2748
  generation: z.ZodOptional<z.ZodString>;
2749
2749
  }, z.core.$strip>;
2750
- agentTarget: z.ZodObject<{
2750
+ anchor: z.ZodObject<{
2751
2751
  engineId: z.ZodString;
2752
2752
  region: z.ZodString;
2753
2753
  generation: z.ZodOptional<z.ZodString>;
@@ -4878,7 +4878,7 @@ declare const eventSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject
4878
4878
  region: z.ZodString;
4879
4879
  generation: z.ZodOptional<z.ZodString>;
4880
4880
  }, z.core.$strip>;
4881
- agentTarget: z.ZodObject<{
4881
+ anchor: z.ZodObject<{
4882
4882
  engineId: z.ZodString;
4883
4883
  region: z.ZodString;
4884
4884
  generation: z.ZodOptional<z.ZodString>;
@@ -6174,7 +6174,7 @@ declare const streamSummarySchema: z.ZodObject<{
6174
6174
  region: z.ZodString;
6175
6175
  generation: z.ZodOptional<z.ZodString>;
6176
6176
  }, z.core.$strip>;
6177
- agentTarget: z.ZodObject<{
6177
+ anchor: z.ZodObject<{
6178
6178
  engineId: z.ZodString;
6179
6179
  region: z.ZodString;
6180
6180
  generation: z.ZodOptional<z.ZodString>;
package/dist/index.d.ts CHANGED
@@ -614,7 +614,7 @@ declare const streamSummaryEventSchema: z.ZodObject<{
614
614
  region: z.ZodString;
615
615
  generation: z.ZodOptional<z.ZodString>;
616
616
  }, z.core.$strip>;
617
- agentTarget: z.ZodObject<{
617
+ anchor: z.ZodObject<{
618
618
  engineId: z.ZodString;
619
619
  region: z.ZodString;
620
620
  generation: z.ZodOptional<z.ZodString>;
@@ -2747,7 +2747,7 @@ declare const projectLogEventsSchema: z.ZodObject<{
2747
2747
  region: z.ZodString;
2748
2748
  generation: z.ZodOptional<z.ZodString>;
2749
2749
  }, z.core.$strip>;
2750
- agentTarget: z.ZodObject<{
2750
+ anchor: z.ZodObject<{
2751
2751
  engineId: z.ZodString;
2752
2752
  region: z.ZodString;
2753
2753
  generation: z.ZodOptional<z.ZodString>;
@@ -4878,7 +4878,7 @@ declare const eventSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject
4878
4878
  region: z.ZodString;
4879
4879
  generation: z.ZodOptional<z.ZodString>;
4880
4880
  }, z.core.$strip>;
4881
- agentTarget: z.ZodObject<{
4881
+ anchor: z.ZodObject<{
4882
4882
  engineId: z.ZodString;
4883
4883
  region: z.ZodString;
4884
4884
  generation: z.ZodOptional<z.ZodString>;
@@ -6174,7 +6174,7 @@ declare const streamSummarySchema: z.ZodObject<{
6174
6174
  region: z.ZodString;
6175
6175
  generation: z.ZodOptional<z.ZodString>;
6176
6176
  }, z.core.$strip>;
6177
- agentTarget: z.ZodObject<{
6177
+ anchor: z.ZodObject<{
6178
6178
  engineId: z.ZodString;
6179
6179
  region: z.ZodString;
6180
6180
  generation: z.ZodOptional<z.ZodString>;
package/dist/index.js CHANGED
@@ -541,7 +541,7 @@ var routingPathSchema = z3.object({
541
541
  crossRegionRoutingAllowed: z3.boolean(),
542
542
  ingress: routingNodeSchema,
543
543
  owner: routingNodeSchema,
544
- agentTarget: routingNodeSchema
544
+ anchor: routingNodeSchema
545
545
  });
546
546
  var routingSchema = z3.discriminatedUnion("decision", [
547
547
  z3.object({
@@ -1781,6 +1781,7 @@ var defaultTURNPort = 3478;
1781
1781
  var defaultTURNSPort = 5349;
1782
1782
  var defaultTURNCredentialTTLSeconds = 10 * 60;
1783
1783
  var maxTURNCredentialTTLSeconds = 60 * 60;
1784
+ var maxTURNKeyringBytes = 8 * 1024;
1784
1785
  var turnTokenClaimsSchema = z8.object({
1785
1786
  exp: z8.number().int().optional(),
1786
1787
  iat: z8.number().int().optional(),
@@ -1909,6 +1910,75 @@ function resolveMode(credentials, mode) {
1909
1910
  }
1910
1911
  return "api";
1911
1912
  }
1913
+ async function readBoundedTURNKeyring(reader, chunks = [], size = 0) {
1914
+ const result = await reader.read();
1915
+ if (result.done) {
1916
+ return Buffer.concat(chunks, size).toString("utf8");
1917
+ }
1918
+ const nextSize = size + result.value.byteLength;
1919
+ if (nextSize > maxTURNKeyringBytes) {
1920
+ await reader.cancel();
1921
+ throw new Error("TURN keyring response exceeds the 8 KiB limit.");
1922
+ }
1923
+ return await readBoundedTURNKeyring(
1924
+ reader,
1925
+ [...chunks, result.value],
1926
+ nextSize
1927
+ );
1928
+ }
1929
+ function parseTURNServerPublicKeyHex(value) {
1930
+ const normalized = value.trim();
1931
+ if (normalized.length === 0 || normalized.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(normalized)) {
1932
+ throw new Error("TURN keyring must contain hexadecimal DER key material.");
1933
+ }
1934
+ try {
1935
+ const key = import_crypto.default.createPublicKey({
1936
+ key: Buffer.from(normalized, "hex"),
1937
+ format: "der",
1938
+ type: "spki"
1939
+ });
1940
+ if (key.asymmetricKeyType !== "ec") {
1941
+ throw new Error("TURN keyring public key must be an EC key.");
1942
+ }
1943
+ return key;
1944
+ } catch (error) {
1945
+ if (error instanceof Error && error.message.startsWith("TURN keyring")) {
1946
+ throw error;
1947
+ }
1948
+ throw new Error("TURN keyring contains an invalid DER public key.", {
1949
+ cause: error
1950
+ });
1951
+ }
1952
+ }
1953
+ function parseAPPPrivateKey(value) {
1954
+ try {
1955
+ const key = import_crypto.default.createPrivateKey({
1956
+ key: Buffer.from(value, "hex"),
1957
+ format: "der",
1958
+ type: "pkcs8"
1959
+ });
1960
+ if (key.asymmetricKeyType !== "ec") {
1961
+ throw new Error("TURN APP client secret must contain an EC private key.");
1962
+ }
1963
+ return key;
1964
+ } catch (error) {
1965
+ if (error instanceof Error && error.message.startsWith("TURN APP")) {
1966
+ throw error;
1967
+ }
1968
+ throw new Error("TURN APP client secret contains an invalid private key.", {
1969
+ cause: error
1970
+ });
1971
+ }
1972
+ }
1973
+ function requireMatchingCurve(privateKey, publicKey) {
1974
+ const privateCurve = privateKey.asymmetricKeyDetails?.namedCurve;
1975
+ const publicCurve = publicKey.asymmetricKeyDetails?.namedCurve;
1976
+ if (!privateCurve || privateCurve !== publicCurve) {
1977
+ throw new Error(
1978
+ "TURN APP client and server keys must use the same named curve."
1979
+ );
1980
+ }
1981
+ }
1912
1982
  async function loadTURNServerPublicKeyHex(clusterDomain, options) {
1913
1983
  const configuredKey = normalizeOptionalString2(options.keyringBaseUrl);
1914
1984
  const keyringBaseURL = configuredKey ?? normalizeOptionalString2(options.apiUrl) ?? "https://rstream.io";
@@ -1916,11 +1986,19 @@ async function loadTURNServerPublicKeyHex(clusterDomain, options) {
1916
1986
  `/keyrings/turn/${clusterDomain}.spki.der.hex`,
1917
1987
  keyringBaseURL
1918
1988
  );
1919
- const response = await fetch(url);
1989
+ const response = await fetch(url, { redirect: "manual" });
1990
+ if (response.status >= 300 && response.status < 400) {
1991
+ throw new Error(
1992
+ "TURN keyring request was redirected; redirects are refused."
1993
+ );
1994
+ }
1920
1995
  if (!response.ok) {
1921
- throw new Error("Failed to load TURN keyring.");
1996
+ throw new Error(`TURN keyring request returned HTTP ${response.status}.`);
1997
+ }
1998
+ if (!response.body) {
1999
+ throw new Error("TURN keyring response body is missing.");
1922
2000
  }
1923
- return (await response.text()).trim();
2001
+ return (await readBoundedTURNKeyring(response.body.getReader())).trim();
1924
2002
  }
1925
2003
  async function createAPITURNCredentials(options) {
1926
2004
  const projectId = normalizeOptionalString2(options.projectId);
@@ -2019,17 +2097,10 @@ async function createAPPTURNCredentials(options) {
2019
2097
  const ttlSeconds = normalizeTTLSeconds(options.ttlSeconds);
2020
2098
  const exp = normalizeNow(options.now) + ttlSeconds;
2021
2099
  const username = `v1:${exp}:app:${projectEndpoint}:${clientId}`;
2022
- const clientPrivateKey = import_crypto.default.createPrivateKey({
2023
- key: Buffer.from(clientSecret, "hex"),
2024
- format: "der",
2025
- type: "pkcs8"
2026
- });
2100
+ const clientPrivateKey = parseAPPPrivateKey(clientSecret);
2027
2101
  const serverPublicKeyHex = normalizeOptionalString2(options.serverPublicKeyHex) ?? await loadTURNServerPublicKeyHex(clusterDomain, options);
2028
- const serverPublicKey = import_crypto.default.createPublicKey({
2029
- key: Buffer.from(serverPublicKeyHex, "hex"),
2030
- format: "der",
2031
- type: "spki"
2032
- });
2102
+ const serverPublicKey = parseTURNServerPublicKeyHex(serverPublicKeyHex);
2103
+ requireMatchingCurve(clientPrivateKey, serverPublicKey);
2033
2104
  const sharedSecret = import_crypto.default.diffieHellman({
2034
2105
  privateKey: clientPrivateKey,
2035
2106
  publicKey: serverPublicKey
package/dist/index.mjs CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  webTTYTransportSchema,
49
49
  webhookEventsSchema,
50
50
  wsEventsSchema
51
- } from "./chunk-K6TZT3PB.mjs";
51
+ } from "./chunk-3VBF43NB.mjs";
52
52
 
53
53
  // src/auth-resource.ts
54
54
  import { createAuthTokenParamsSchema } from "@rstreamlabs/rstream/auth-token";
@@ -418,6 +418,7 @@ var defaultTURNPort = 3478;
418
418
  var defaultTURNSPort = 5349;
419
419
  var defaultTURNCredentialTTLSeconds = 10 * 60;
420
420
  var maxTURNCredentialTTLSeconds = 60 * 60;
421
+ var maxTURNKeyringBytes = 8 * 1024;
421
422
  var turnTokenClaimsSchema = z.object({
422
423
  exp: z.number().int().optional(),
423
424
  iat: z.number().int().optional(),
@@ -546,6 +547,75 @@ function resolveMode(credentials, mode) {
546
547
  }
547
548
  return "api";
548
549
  }
550
+ async function readBoundedTURNKeyring(reader, chunks = [], size = 0) {
551
+ const result = await reader.read();
552
+ if (result.done) {
553
+ return Buffer.concat(chunks, size).toString("utf8");
554
+ }
555
+ const nextSize = size + result.value.byteLength;
556
+ if (nextSize > maxTURNKeyringBytes) {
557
+ await reader.cancel();
558
+ throw new Error("TURN keyring response exceeds the 8 KiB limit.");
559
+ }
560
+ return await readBoundedTURNKeyring(
561
+ reader,
562
+ [...chunks, result.value],
563
+ nextSize
564
+ );
565
+ }
566
+ function parseTURNServerPublicKeyHex(value) {
567
+ const normalized = value.trim();
568
+ if (normalized.length === 0 || normalized.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(normalized)) {
569
+ throw new Error("TURN keyring must contain hexadecimal DER key material.");
570
+ }
571
+ try {
572
+ const key = crypto.createPublicKey({
573
+ key: Buffer.from(normalized, "hex"),
574
+ format: "der",
575
+ type: "spki"
576
+ });
577
+ if (key.asymmetricKeyType !== "ec") {
578
+ throw new Error("TURN keyring public key must be an EC key.");
579
+ }
580
+ return key;
581
+ } catch (error) {
582
+ if (error instanceof Error && error.message.startsWith("TURN keyring")) {
583
+ throw error;
584
+ }
585
+ throw new Error("TURN keyring contains an invalid DER public key.", {
586
+ cause: error
587
+ });
588
+ }
589
+ }
590
+ function parseAPPPrivateKey(value) {
591
+ try {
592
+ const key = crypto.createPrivateKey({
593
+ key: Buffer.from(value, "hex"),
594
+ format: "der",
595
+ type: "pkcs8"
596
+ });
597
+ if (key.asymmetricKeyType !== "ec") {
598
+ throw new Error("TURN APP client secret must contain an EC private key.");
599
+ }
600
+ return key;
601
+ } catch (error) {
602
+ if (error instanceof Error && error.message.startsWith("TURN APP")) {
603
+ throw error;
604
+ }
605
+ throw new Error("TURN APP client secret contains an invalid private key.", {
606
+ cause: error
607
+ });
608
+ }
609
+ }
610
+ function requireMatchingCurve(privateKey, publicKey) {
611
+ const privateCurve = privateKey.asymmetricKeyDetails?.namedCurve;
612
+ const publicCurve = publicKey.asymmetricKeyDetails?.namedCurve;
613
+ if (!privateCurve || privateCurve !== publicCurve) {
614
+ throw new Error(
615
+ "TURN APP client and server keys must use the same named curve."
616
+ );
617
+ }
618
+ }
549
619
  async function loadTURNServerPublicKeyHex(clusterDomain, options) {
550
620
  const configuredKey = normalizeOptionalString2(options.keyringBaseUrl);
551
621
  const keyringBaseURL = configuredKey ?? normalizeOptionalString2(options.apiUrl) ?? "https://rstream.io";
@@ -553,11 +623,19 @@ async function loadTURNServerPublicKeyHex(clusterDomain, options) {
553
623
  `/keyrings/turn/${clusterDomain}.spki.der.hex`,
554
624
  keyringBaseURL
555
625
  );
556
- const response = await fetch(url);
626
+ const response = await fetch(url, { redirect: "manual" });
627
+ if (response.status >= 300 && response.status < 400) {
628
+ throw new Error(
629
+ "TURN keyring request was redirected; redirects are refused."
630
+ );
631
+ }
557
632
  if (!response.ok) {
558
- throw new Error("Failed to load TURN keyring.");
633
+ throw new Error(`TURN keyring request returned HTTP ${response.status}.`);
634
+ }
635
+ if (!response.body) {
636
+ throw new Error("TURN keyring response body is missing.");
559
637
  }
560
- return (await response.text()).trim();
638
+ return (await readBoundedTURNKeyring(response.body.getReader())).trim();
561
639
  }
562
640
  async function createAPITURNCredentials(options) {
563
641
  const projectId = normalizeOptionalString2(options.projectId);
@@ -656,17 +734,10 @@ async function createAPPTURNCredentials(options) {
656
734
  const ttlSeconds = normalizeTTLSeconds(options.ttlSeconds);
657
735
  const exp = normalizeNow(options.now) + ttlSeconds;
658
736
  const username = `v1:${exp}:app:${projectEndpoint}:${clientId}`;
659
- const clientPrivateKey = crypto.createPrivateKey({
660
- key: Buffer.from(clientSecret, "hex"),
661
- format: "der",
662
- type: "pkcs8"
663
- });
737
+ const clientPrivateKey = parseAPPPrivateKey(clientSecret);
664
738
  const serverPublicKeyHex = normalizeOptionalString2(options.serverPublicKeyHex) ?? await loadTURNServerPublicKeyHex(clusterDomain, options);
665
- const serverPublicKey = crypto.createPublicKey({
666
- key: Buffer.from(serverPublicKeyHex, "hex"),
667
- format: "der",
668
- type: "spki"
669
- });
739
+ const serverPublicKey = parseTURNServerPublicKeyHex(serverPublicKeyHex);
740
+ requireMatchingCurve(clientPrivateKey, serverPublicKey);
670
741
  const sharedSecret = crypto.diffieHellman({
671
742
  privateKey: clientPrivateKey,
672
743
  publicKey: serverPublicKey
package/dist/openapi.js CHANGED
@@ -280,7 +280,7 @@ var routingPathSchema = z3.object({
280
280
  crossRegionRoutingAllowed: z3.boolean(),
281
281
  ingress: routingNodeSchema,
282
282
  owner: routingNodeSchema,
283
- agentTarget: routingNodeSchema
283
+ anchor: routingNodeSchema
284
284
  });
285
285
  var routingSchema = z3.discriminatedUnion("decision", [
286
286
  z3.object({
package/dist/openapi.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  engineOpenApiDocument,
3
3
  engineOpenApiJson
4
- } from "./chunk-K6TZT3PB.mjs";
4
+ } from "./chunk-3VBF43NB.mjs";
5
5
  export {
6
6
  engineOpenApiDocument,
7
7
  engineOpenApiJson
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rstreamlabs/tunnels",
3
- "version": "3.7.0",
3
+ "version": "3.8.1",
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": {
@@ -38,16 +38,16 @@
38
38
  "type-check": "tsc --noEmit"
39
39
  },
40
40
  "devDependencies": {
41
- "@turbo/gen": "^2.10.0",
41
+ "@turbo/gen": "^2.10.6",
42
42
  "@types/node": "^26",
43
- "eslint": "9.39.4",
43
+ "eslint": "9.39.5",
44
44
  "eslint-config": "*",
45
45
  "tsup": "^8.5.1",
46
- "typescript": "5.9.3",
46
+ "typescript": "6.0.3",
47
47
  "typescript-config": "*"
48
48
  },
49
49
  "dependencies": {
50
- "@rstreamlabs/rstream": "3.7.0",
50
+ "@rstreamlabs/rstream": "3.8.0",
51
51
  "@types/jsonwebtoken": "^9.0.10",
52
52
  "jsonwebtoken": "^9.0.3",
53
53
  "zod": "^4.4.3"