@rstreamlabs/rstream 1.4.0 → 1.6.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/dist/index.mjs CHANGED
@@ -6,11 +6,11 @@ var RstreamAuthRessource = class {
6
6
  constructor(client) {
7
7
  this.client = client;
8
8
  }
9
- async createShortTermToken(params, options) {
9
+ async createAuthToken(params, options) {
10
10
  const credentials = options?.credentials || this.client.credentials;
11
11
  if (!credentials || !("clientId" in credentials)) {
12
12
  throw new Error(
13
- "Application credentials (client id, client secret) are required to create a short term token."
13
+ "Application credentials (client id, client secret) are required to create an auth token."
14
14
  );
15
15
  }
16
16
  const now = Math.floor(Date.now() / 1e3);
@@ -22,9 +22,10 @@ var RstreamAuthRessource = class {
22
22
  // Expiration time
23
23
  type: "app",
24
24
  clientId: credentials.clientId,
25
+ permissions: null,
25
26
  metadata: {
26
27
  engine: this.client.engine,
27
- permissions: params?.permissions
28
+ scopes: params?.scopes
28
29
  }
29
30
  };
30
31
  const pk = crypto.createPrivateKey({
@@ -91,6 +92,8 @@ var tunnelSchema = z2.object({
91
92
  // common properties
92
93
  client_id: z2.string(),
93
94
  user_id: z2.string(),
95
+ project_id: z2.string(),
96
+ workspace_id: z2.string(),
94
97
  status: z2.enum(["online", "offline"]),
95
98
  // tunnel properties
96
99
  id: z2.string(),
@@ -132,66 +135,89 @@ var listTunnelsResponseSchema = z2.array(tunnelSchema);
132
135
 
133
136
  // src/auth.ts
134
137
  import * as z3 from "zod";
135
- var createShortTermTokenParamsSchema = z3.object({
136
- expires_in: z3.number().default(60),
137
- // 1 minute
138
- permissions: z3.object({
139
- // Permissions for creating a tunnel
140
- create: z3.union([
141
- z3.boolean(),
142
- z3.object({
143
- filters: filters(tunnelSchema).optional()
144
- })
145
- ]).optional(),
146
- // Permissions for connecting to a tunnel
147
- connect: z3.union([
148
- z3.boolean(),
149
- z3.object({
150
- filters: filters(tunnelSchema).optional(),
151
- params: filters(
152
- z3.object({
153
- path: z3.string().optional()
154
- })
155
- ).optional()
156
- })
157
- ]).optional(),
158
- // Permissions for listing tunnels
159
- list: z3.union([
160
- z3.boolean(),
161
- z3.object({
162
- filters: filters(tunnelSchema).optional(),
163
- select: select(tunnelSchema).optional()
164
- })
165
- ]).optional()
166
- }),
167
- // Additional metadata
168
- metadata: z3.unknown().optional()
138
+ var authTokenPermissionsSchema = z3.array(z3.string());
139
+ var authTokenTunnelsScopesSchema = z3.object({
140
+ // Scopes for creating tunnels
141
+ create: z3.union([
142
+ z3.boolean(),
143
+ z3.object({
144
+ filters: filters(
145
+ tunnelSchema.omit({
146
+ client_id: true,
147
+ project_id: true,
148
+ workspace_id: true,
149
+ user_id: true,
150
+ status: true,
151
+ creation_date: true
152
+ })
153
+ ).optional()
154
+ })
155
+ ]).optional(),
156
+ // Scopes for connecting to tunnels
157
+ connect: z3.union([
158
+ z3.boolean(),
159
+ z3.object({
160
+ filters: filters(tunnelSchema).optional(),
161
+ params: filters(
162
+ z3.object({
163
+ path: z3.string().optional()
164
+ })
165
+ ).optional()
166
+ })
167
+ ]).optional(),
168
+ // Scopes for listing tunnels
169
+ list: z3.union([
170
+ z3.boolean(),
171
+ z3.object({
172
+ filters: filters(tunnelSchema).optional(),
173
+ select: select(tunnelSchema).optional()
174
+ })
175
+ ]).optional()
169
176
  });
170
- var createShortTermTokenResponseSchema = z3.object({
171
- token: z3.string()
177
+ var authTokenScopesSchema = z3.object({
178
+ tunnels: authTokenTunnelsScopesSchema.optional()
179
+ // Scopes related to tunnels
172
180
  });
173
- var rstreamAuthPayloadSchema = z3.discriminatedUnion("type", [
181
+ var authTokenSchema = z3.union([
182
+ z3.object({
183
+ type: z3.literal("auth"),
184
+ userId: z3.string(),
185
+ permissions: authTokenPermissionsSchema.nullable()
186
+ }),
174
187
  z3.object({
175
188
  type: z3.literal("pat")
176
189
  }),
177
190
  z3.object({
178
191
  type: z3.literal("app"),
179
- clientId: z3.string()
192
+ clientId: z3.string(),
193
+ permissions: authTokenPermissionsSchema.nullable()
180
194
  })
181
195
  ]).and(
182
196
  z3.object({
183
197
  metadata: z3.object({
184
198
  engine: z3.string().optional(),
185
- permissions: createShortTermTokenParamsSchema.shape.permissions.optional()
199
+ scopes: authTokenScopesSchema.optional()
186
200
  }).optional()
187
201
  })
188
202
  );
203
+ var createAuthTokenParamsSchema = z3.object({
204
+ expires_in: z3.number().default(60),
205
+ // 1 minute
206
+ scopes: authTokenScopesSchema.optional(),
207
+ metadata: z3.unknown().optional()
208
+ // Additional metadata
209
+ });
210
+ var createAuthTokenResponseSchema = z3.object({
211
+ token: z3.string()
212
+ });
189
213
 
190
214
  // src/client.ts
191
215
  import * as z4 from "zod";
192
216
  var clientSchema = z4.object({
193
217
  id: z4.string(),
194
218
  user_id: z4.string(),
219
+ project_id: z4.string(),
220
+ workspace_id: z4.string(),
195
221
  status: z4.enum(["online", "offline"]),
196
222
  details: z4.object({
197
223
  agent: z4.string().optional(),
@@ -355,7 +381,13 @@ var RstreamClient = class {
355
381
  this.cfg = config;
356
382
  }
357
383
  get engine() {
358
- return this.cfg?.engine || process.env.RSTREAM_DEFAULT_ENGINE || "engine.rstream.io:443";
384
+ if (this.cfg?.engine) {
385
+ return this.cfg.engine;
386
+ }
387
+ if (process.env.RSTREAM_DEFAULT_ENGINE) {
388
+ return process.env.RSTREAM_DEFAULT_ENGINE;
389
+ }
390
+ return void 0;
359
391
  }
360
392
  get credentials() {
361
393
  if (this.cfg?.credentials && "token" in this.cfg.credentials) {
@@ -378,7 +410,13 @@ var RstreamClient = class {
378
410
  return void 0;
379
411
  }
380
412
  get api() {
381
- return `https://${this.engine}/api`;
413
+ const engine = this.engine;
414
+ if (!engine) {
415
+ throw new Error(
416
+ "Engine URL is not defined. Please provide an engine in the rstream client configuration or set the RSTREAM_DEFAULT_ENGINE environment variable."
417
+ );
418
+ }
419
+ return `https://${engine}/api`;
382
420
  }
383
421
  get auth() {
384
422
  return new RstreamAuthRessource(this);
@@ -398,7 +436,7 @@ var RstreamClient = class {
398
436
  return credentials.token;
399
437
  }
400
438
  if (credentials && "clientId" in credentials) {
401
- return (await this.auth.createShortTermToken(void 0, {
439
+ return (await this.auth.createAuthToken(void 0, {
402
440
  credentials: {
403
441
  clientId: credentials.clientId,
404
442
  clientSecret: credentials.clientSecret
@@ -442,11 +480,16 @@ var Watch = class {
442
480
  throw new Error("Watch: Connection already started or closed.");
443
481
  }
444
482
  this.connectionState = "connecting";
445
- const token = await this.config.auth.token();
446
- const payload = rstreamAuthPayloadSchema.parse(
483
+ const token = typeof this.config.auth === "function" ? await this.config.auth() : this.config.auth;
484
+ const payload = authTokenSchema.parse(
447
485
  jwt2.decode(token, { complete: false })
448
486
  );
449
- const base = `https://${this.config.engine || payload.metadata?.engine || "engine.rstream.io:443"}`;
487
+ if (this.config.engine === void 0 && payload.metadata?.engine === void 0) {
488
+ throw new Error(
489
+ "Watch: No engine specified in configuration or token metadata."
490
+ );
491
+ }
492
+ const base = `https://${this.config.engine || payload.metadata?.engine}`;
450
493
  if (this.config.transport === "sse") {
451
494
  const url = new URL(`/api/sse`, base);
452
495
  url.searchParams.set("rstream.token", token);
@@ -470,6 +513,13 @@ var Watch = class {
470
513
  this.disconnect();
471
514
  }
472
515
  };
516
+ if (this.connection instanceof WebSocket) {
517
+ this.connection.onclose = () => {
518
+ if (this.connectionState !== "closed") {
519
+ this.disconnect();
520
+ }
521
+ };
522
+ }
473
523
  }
474
524
  disconnect() {
475
525
  if (this.connection) {
@@ -485,6 +535,93 @@ var Watch = class {
485
535
  }
486
536
  }
487
537
  };
538
+
539
+ // src/webtty.ts
540
+ import * as z6 from "zod";
541
+ var osFamilies = [
542
+ "linux",
543
+ "macos",
544
+ "windows",
545
+ "netbsd",
546
+ "openbsd",
547
+ "freebsd"
548
+ ];
549
+ var architectures = [
550
+ "x86_i386",
551
+ "x86_i686",
552
+ "x86_64",
553
+ "x86_64_v2",
554
+ "x86_64_v3",
555
+ "x86_64_v4",
556
+ "armv6",
557
+ "armv6hf",
558
+ "armv7",
559
+ "armv7hf",
560
+ "arm64",
561
+ "mips",
562
+ "mipsle",
563
+ "mips64",
564
+ "mips64le",
565
+ "ppc64",
566
+ "ppc64le",
567
+ "riscv64"
568
+ ];
569
+ var webttyServerSchema = z6.object({
570
+ tunnel_id: z6.string(),
571
+ host: z6.string(),
572
+ token_auth: z6.boolean(),
573
+ os_family: z6.enum(osFamilies).optional(),
574
+ arch: z6.enum(architectures).optional(),
575
+ os_id: z6.string().optional(),
576
+ // /etc/os-release::ID (ubuntu, debian, rocky, etc.)
577
+ os_version_id: z6.string().optional(),
578
+ // /etc/os-release::VERSION_ID (24.04, 22.04, 11, 10.0.19045, ...)
579
+ os_version_codename: z6.string().optional(),
580
+ // /etc/os-release::VERSION_CODENAME (jammy, noble...)
581
+ os_pretty_name: z6.string().optional(),
582
+ // /etc/os-release::PRETTY_NAME
583
+ kernel_release: z6.string().optional(),
584
+ // uname -r
585
+ hostname: z6.string().optional(),
586
+ // uname -n
587
+ labels: z6.record(z6.string(), z6.string().optional()).optional()
588
+ });
589
+ function parser(tunnel) {
590
+ if (tunnel.status !== "online") return null;
591
+ if (tunnel.publish !== true) return null;
592
+ if (tunnel.protocol !== "http") return null;
593
+ const tunnelLabels = tunnel.labels ?? {};
594
+ if (tunnelLabels["application-protocol"] !== "rstream.webtty") {
595
+ return null;
596
+ }
597
+ const labels = {};
598
+ for (const [key, value] of Object.entries(tunnelLabels)) {
599
+ if (!key.startsWith("rstream.webtty.label.")) continue;
600
+ const labelKey = key.slice("rstream.webtty.label.".length);
601
+ if (labelKey.length === 0) continue;
602
+ labels[labelKey] = value;
603
+ }
604
+ const candidate = {
605
+ tunnel_id: tunnel.id,
606
+ host: tunnel.host,
607
+ token_auth: tunnel.token_auth === true,
608
+ os_family: tunnelLabels["rstream.webtty.os_family"],
609
+ arch: tunnelLabels["rstream.webtty.arch"],
610
+ os_id: tunnelLabels["rstream.webtty.os_id"],
611
+ os_version_id: tunnelLabels["rstream.webtty.os_version_id"],
612
+ os_version_codename: tunnelLabels["rstream.webtty.os_version_codename"],
613
+ os_pretty_name: tunnelLabels["rstream.webtty.os_pretty_name"],
614
+ kernel_release: tunnelLabels["rstream.webtty.kernel_release"],
615
+ hostname: tunnelLabels["rstream.webtty.hostname"],
616
+ labels: Object.keys(labels).length > 0 ? labels : void 0
617
+ };
618
+ const parsed = webttyServerSchema.safeParse(candidate);
619
+ if (!parsed.success) return null;
620
+ return parsed.data;
621
+ }
622
+ function parseWebTTYServers(tunnels) {
623
+ return tunnels.map((tunnel) => parser(tunnel)).filter((server) => server !== null);
624
+ }
488
625
  export {
489
626
  RstreamClient as Rstream,
490
627
  RstreamAuthRessource,
@@ -493,14 +630,19 @@ export {
493
630
  RstreamTunnelsRessource,
494
631
  RstreamWebHooksRessource,
495
632
  Watch,
633
+ authTokenPermissionsSchema,
634
+ authTokenSchema,
635
+ authTokenScopesSchema,
636
+ authTokenTunnelsScopesSchema,
496
637
  clientSchema,
497
- createShortTermTokenParamsSchema,
498
- createShortTermTokenResponseSchema,
638
+ createAuthTokenParamsSchema,
639
+ createAuthTokenResponseSchema,
499
640
  eventSchema,
500
641
  listClientsParamsSchema,
501
642
  listClientsResponseSchema,
502
643
  listTunnelsParamsSchema,
503
644
  listTunnelsResponseSchema,
504
- rstreamAuthPayloadSchema,
505
- tunnelSchema
645
+ parseWebTTYServers,
646
+ tunnelSchema,
647
+ webttyServerSchema
506
648
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rstreamlabs/rstream",
3
- "version": "1.4.0",
4
- "description": "JS SDK for rstream.",
3
+ "version": "1.6.1",
4
+ "description": "JS/TS SDK for rstream - serverless networking",
5
5
  "author": "@uartnet <hello@rstream.io>",
6
6
  "license": "Apache-2.0",
7
7
  "main": "./dist/index.js",
@@ -19,17 +19,17 @@
19
19
  "type-check": "tsc --noEmit"
20
20
  },
21
21
  "devDependencies": {
22
- "@turbo/gen": "^2.5.8",
22
+ "@turbo/gen": "^2.7.4",
23
23
  "@types/jsonwebtoken": "^9.0.10",
24
- "@types/node": "^24",
24
+ "@types/node": "^25",
25
25
  "eslint-config": "*",
26
- "eslint": "9.36.0",
27
- "tsup": "^8.5.0",
26
+ "eslint": "9.39.2",
27
+ "tsup": "^8.5.1",
28
28
  "typescript-config": "*",
29
- "typescript": "5.9.2"
29
+ "typescript": "5.9.3"
30
30
  },
31
31
  "dependencies": {
32
- "jsonwebtoken": "^9.0.2",
32
+ "jsonwebtoken": "^9.0.3",
33
33
  "zod": "^3.25.76"
34
34
  },
35
35
  "publishConfig": {