@rstreamlabs/tunnels 1.0.11 → 3.0.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/README.md +25 -14
- package/dist/{chunk-NHUJ3FYM.mjs → chunk-UUZYVELQ.mjs} +14 -46
- package/dist/index.d.mts +157 -1691
- package/dist/index.d.ts +157 -1691
- package/dist/index.js +322 -551
- package/dist/index.mjs +118 -306
- package/dist/openapi.js +12 -43
- package/dist/openapi.mjs +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -13,211 +13,13 @@ import {
|
|
|
13
13
|
streamSummarySchema,
|
|
14
14
|
streamTLSInfoSchema,
|
|
15
15
|
tunnelFilterSchema,
|
|
16
|
-
tunnelSchema,
|
|
17
16
|
webhookEventsSchema,
|
|
18
17
|
wsEventsSchema
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UUZYVELQ.mjs";
|
|
20
19
|
|
|
21
20
|
// src/auth-resource.ts
|
|
21
|
+
import { createAuthTokenParamsSchema } from "@rstreamlabs/rstream/auth-token";
|
|
22
22
|
import { createClientCredentialsToken } from "@rstreamlabs/rstream";
|
|
23
|
-
|
|
24
|
-
// src/zod.ts
|
|
25
|
-
import * as z from "zod";
|
|
26
|
-
var StringFilter = z.union([
|
|
27
|
-
z.string(),
|
|
28
|
-
z.object({ exact: z.string() }).strict(),
|
|
29
|
-
z.object({ oneof: z.array(z.string()) }).strict(),
|
|
30
|
-
z.object({ regex: z.string() }).strict()
|
|
31
|
-
]);
|
|
32
|
-
function transform(field) {
|
|
33
|
-
if (field instanceof z.ZodOptional) {
|
|
34
|
-
return z.optional(transform(field.unwrap()));
|
|
35
|
-
}
|
|
36
|
-
if (field instanceof z.ZodString) {
|
|
37
|
-
return z.optional(StringFilter);
|
|
38
|
-
}
|
|
39
|
-
if (field instanceof z.ZodRecord) {
|
|
40
|
-
return z.optional(z.record(field.keyType, transform(field.valueType)));
|
|
41
|
-
}
|
|
42
|
-
return z.optional(field);
|
|
43
|
-
}
|
|
44
|
-
function filters(base) {
|
|
45
|
-
const entries = Object.entries(base.shape).map(([key, field]) => [
|
|
46
|
-
key,
|
|
47
|
-
transform(field)
|
|
48
|
-
]);
|
|
49
|
-
const shape = Object.fromEntries(entries);
|
|
50
|
-
const node = z.lazy(
|
|
51
|
-
() => z.union([
|
|
52
|
-
z.object(shape).strict(),
|
|
53
|
-
z.object({ AND: z.array(node) }).strict(),
|
|
54
|
-
z.object({ OR: z.array(node) }).strict()
|
|
55
|
-
])
|
|
56
|
-
);
|
|
57
|
-
return node;
|
|
58
|
-
}
|
|
59
|
-
function select(base) {
|
|
60
|
-
const entries = Object.entries(base.shape).map(([key]) => {
|
|
61
|
-
return [key, z.boolean().optional()];
|
|
62
|
-
});
|
|
63
|
-
const shape = Object.fromEntries(entries);
|
|
64
|
-
return z.object(shape).strict();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// src/auth.ts
|
|
68
|
-
import * as z2 from "zod";
|
|
69
|
-
var nonEmptyStringSchema = z2.string().trim().min(1);
|
|
70
|
-
var authTokenPermissionsSchema = z2.array(z2.string());
|
|
71
|
-
var authTokenTunnelsScopesSchema = z2.object({
|
|
72
|
-
// Scopes for creating tunnels
|
|
73
|
-
create: z2.union([
|
|
74
|
-
z2.boolean(),
|
|
75
|
-
z2.object({
|
|
76
|
-
filters: filters(
|
|
77
|
-
tunnelSchema.omit({
|
|
78
|
-
client_id: true,
|
|
79
|
-
user_id: true,
|
|
80
|
-
workspace_id: true,
|
|
81
|
-
project_id: true,
|
|
82
|
-
cluster_id: true,
|
|
83
|
-
plan: true,
|
|
84
|
-
provider: true,
|
|
85
|
-
region: true,
|
|
86
|
-
status: true,
|
|
87
|
-
id: true,
|
|
88
|
-
creation_date: true
|
|
89
|
-
})
|
|
90
|
-
).optional()
|
|
91
|
-
}).strict()
|
|
92
|
-
]).optional(),
|
|
93
|
-
// Scopes for connecting to tunnels
|
|
94
|
-
connect: z2.union([
|
|
95
|
-
z2.boolean(),
|
|
96
|
-
z2.object({
|
|
97
|
-
filters: filters(tunnelSchema).optional(),
|
|
98
|
-
params: filters(
|
|
99
|
-
z2.object({
|
|
100
|
-
path: z2.string().optional()
|
|
101
|
-
})
|
|
102
|
-
).optional()
|
|
103
|
-
}).strict()
|
|
104
|
-
]).optional(),
|
|
105
|
-
// Scopes for listing tunnels
|
|
106
|
-
list: z2.union([
|
|
107
|
-
z2.boolean(),
|
|
108
|
-
z2.object({
|
|
109
|
-
filters: filters(tunnelSchema).optional(),
|
|
110
|
-
select: select(tunnelSchema).optional()
|
|
111
|
-
}).strict()
|
|
112
|
-
]).optional()
|
|
113
|
-
}).strict().superRefine((scopes, ctx) => {
|
|
114
|
-
if (scopes.create === void 0 && scopes.connect === void 0 && scopes.list === void 0) {
|
|
115
|
-
ctx.addIssue({
|
|
116
|
-
code: z2.ZodIssueCode.custom,
|
|
117
|
-
message: "At least one tunnel scope action is required."
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
var authTokenScopesSchema = z2.object({
|
|
122
|
-
tunnels: authTokenTunnelsScopesSchema.optional()
|
|
123
|
-
// Scopes related to tunnels
|
|
124
|
-
}).strict().superRefine((scopes, ctx) => {
|
|
125
|
-
if (scopes.tunnels === void 0) {
|
|
126
|
-
ctx.addIssue({
|
|
127
|
-
code: z2.ZodIssueCode.custom,
|
|
128
|
-
message: "Tunnel scopes are required.",
|
|
129
|
-
path: ["tunnels"]
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
var authTokenTunnelGrantLeafSchema = z2.object({
|
|
134
|
-
workspaces: z2.array(nonEmptyStringSchema).min(1).optional(),
|
|
135
|
-
projects: z2.array(nonEmptyStringSchema).min(1).optional(),
|
|
136
|
-
scopes: authTokenScopesSchema.optional()
|
|
137
|
-
}).strict().superRefine((grant, ctx) => {
|
|
138
|
-
if (grant.workspaces !== void 0 && grant.projects !== void 0) {
|
|
139
|
-
ctx.addIssue({
|
|
140
|
-
code: z2.ZodIssueCode.custom,
|
|
141
|
-
message: "A grant cannot target workspaces and projects at the same time.",
|
|
142
|
-
path: ["projects"]
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
if (grant.workspaces === void 0 && grant.projects === void 0 && grant.scopes === void 0) {
|
|
146
|
-
ctx.addIssue({
|
|
147
|
-
code: z2.ZodIssueCode.custom,
|
|
148
|
-
message: "A grant must target workspaces, projects, or scopes.",
|
|
149
|
-
path: ["workspaces"]
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
var authTokenTunnelGrantSchema = z2.lazy(
|
|
154
|
-
() => z2.union([
|
|
155
|
-
authTokenTunnelGrantLeafSchema,
|
|
156
|
-
z2.object({ AND: z2.array(authTokenTunnelGrantSchema).min(1) }).strict(),
|
|
157
|
-
z2.object({ OR: z2.array(authTokenTunnelGrantSchema).min(1) }).strict()
|
|
158
|
-
])
|
|
159
|
-
);
|
|
160
|
-
var authTokenCommonSchema = {
|
|
161
|
-
aud: z2.union([z2.string(), z2.array(z2.string())]).optional(),
|
|
162
|
-
exp: z2.number().optional(),
|
|
163
|
-
tunnelsGrants: authTokenTunnelGrantSchema.optional(),
|
|
164
|
-
iat: z2.number().optional(),
|
|
165
|
-
iss: z2.string().optional(),
|
|
166
|
-
jti: z2.string().optional(),
|
|
167
|
-
metadata: z2.object({
|
|
168
|
-
engine: z2.string().optional()
|
|
169
|
-
}).strict().optional(),
|
|
170
|
-
nbf: z2.number().optional(),
|
|
171
|
-
sub: z2.string().optional()
|
|
172
|
-
};
|
|
173
|
-
var authTokenSchema = z2.union([
|
|
174
|
-
z2.object({
|
|
175
|
-
type: z2.literal("auth"),
|
|
176
|
-
userId: z2.string(),
|
|
177
|
-
permissions: authTokenPermissionsSchema.nullable(),
|
|
178
|
-
...authTokenCommonSchema
|
|
179
|
-
}).strict(),
|
|
180
|
-
z2.object({
|
|
181
|
-
type: z2.literal("pat"),
|
|
182
|
-
tokendpoint: z2.string().optional(),
|
|
183
|
-
token_endpoint: z2.string().optional(),
|
|
184
|
-
...authTokenCommonSchema
|
|
185
|
-
}).strict(),
|
|
186
|
-
z2.object({
|
|
187
|
-
type: z2.literal("app"),
|
|
188
|
-
clientId: z2.string(),
|
|
189
|
-
permissions: authTokenPermissionsSchema.nullable(),
|
|
190
|
-
...authTokenCommonSchema
|
|
191
|
-
}).strict()
|
|
192
|
-
]);
|
|
193
|
-
var tokenSchema = authTokenSchema;
|
|
194
|
-
var createAuthTokenParamsSchema = z2.object({
|
|
195
|
-
expires_in: z2.number().int().min(1).max(3600).default(60),
|
|
196
|
-
scopes: authTokenScopesSchema.optional(),
|
|
197
|
-
tunnelsGrants: authTokenTunnelGrantSchema.optional(),
|
|
198
|
-
metadata: z2.unknown().optional()
|
|
199
|
-
// Additional metadata
|
|
200
|
-
}).strict().superRefine((params, ctx) => {
|
|
201
|
-
if (params.scopes !== void 0 && params.tunnelsGrants !== void 0) {
|
|
202
|
-
ctx.addIssue({
|
|
203
|
-
code: z2.ZodIssueCode.custom,
|
|
204
|
-
message: "Use either scopes or tunnelsGrants, not both.",
|
|
205
|
-
path: ["tunnelsGrants"]
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
if (params.scopes === void 0 && params.tunnelsGrants === void 0) {
|
|
209
|
-
ctx.addIssue({
|
|
210
|
-
code: z2.ZodIssueCode.custom,
|
|
211
|
-
message: "Explicit scopes or tunnelsGrants are required.",
|
|
212
|
-
path: ["scopes"]
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
var createAuthTokenResponseSchema = z2.object({
|
|
217
|
-
token: z2.string()
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// src/auth-resource.ts
|
|
221
23
|
import { isClientCredentials } from "@rstreamlabs/rstream";
|
|
222
24
|
var RstreamAuthResource = class {
|
|
223
25
|
client;
|
|
@@ -246,7 +48,7 @@ var RstreamAuthResource = class {
|
|
|
246
48
|
if (options?.projectId !== void 0 || options?.workspaceId !== void 0) {
|
|
247
49
|
return options;
|
|
248
50
|
}
|
|
249
|
-
if (
|
|
51
|
+
if (!tunnelResourcesNeedDefaultTarget(tokenParams.resources?.tunnels)) {
|
|
250
52
|
return options ?? {};
|
|
251
53
|
}
|
|
252
54
|
const target = await this.client.getEngineAuthTokenTarget();
|
|
@@ -263,8 +65,8 @@ function createAuthTokenFromClientCredentials(credentials, params, options) {
|
|
|
263
65
|
metadata: {
|
|
264
66
|
engine: options?.engine
|
|
265
67
|
},
|
|
266
|
-
|
|
267
|
-
|
|
68
|
+
permissions: null,
|
|
69
|
+
resources: normalizeAuthTokenResources(tokenParams, options)
|
|
268
70
|
};
|
|
269
71
|
const { token } = createClientCredentialsToken(credentials, {
|
|
270
72
|
claims: payload,
|
|
@@ -272,70 +74,73 @@ function createAuthTokenFromClientCredentials(credentials, params, options) {
|
|
|
272
74
|
});
|
|
273
75
|
return { token };
|
|
274
76
|
}
|
|
275
|
-
function
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
return void 0;
|
|
77
|
+
function normalizeAuthTokenResources(params, options) {
|
|
78
|
+
return {
|
|
79
|
+
tunnels: applyDefaultTunnelResourceTarget(
|
|
80
|
+
requireTunnelResource(params),
|
|
81
|
+
options
|
|
82
|
+
)
|
|
83
|
+
};
|
|
284
84
|
}
|
|
285
|
-
function
|
|
85
|
+
function requireTunnelResource(params) {
|
|
86
|
+
const tunnels = params.resources?.tunnels;
|
|
87
|
+
if (tunnels !== void 0) return tunnels;
|
|
88
|
+
throw new Error("Explicit resources.tunnels is required.");
|
|
89
|
+
}
|
|
90
|
+
function applyDefaultTunnelResourceTarget(resource, options, inheritedTarget = false) {
|
|
286
91
|
if (options?.projectScoped === false) {
|
|
287
|
-
return
|
|
92
|
+
return resource;
|
|
288
93
|
}
|
|
289
|
-
if ("AND" in
|
|
290
|
-
const branchHasTarget = inheritedTarget ||
|
|
94
|
+
if ("AND" in resource) {
|
|
95
|
+
const branchHasTarget = inheritedTarget || resource.AND.some((child) => tunnelResourceTreeHasTarget(child));
|
|
291
96
|
return {
|
|
292
|
-
AND:
|
|
293
|
-
(
|
|
97
|
+
AND: resource.AND.map(
|
|
98
|
+
(child) => applyDefaultTunnelResourceTarget(child, options, branchHasTarget)
|
|
294
99
|
)
|
|
295
100
|
};
|
|
296
101
|
}
|
|
297
|
-
if ("OR" in
|
|
102
|
+
if ("OR" in resource) {
|
|
298
103
|
return {
|
|
299
|
-
OR:
|
|
300
|
-
(
|
|
104
|
+
OR: resource.OR.map(
|
|
105
|
+
(child) => applyDefaultTunnelResourceTarget(child, options, inheritedTarget)
|
|
301
106
|
)
|
|
302
107
|
};
|
|
303
108
|
}
|
|
304
|
-
if (
|
|
305
|
-
return
|
|
109
|
+
if (resource.scopes === void 0 || tunnelResourceHasTarget(resource) || inheritedTarget) {
|
|
110
|
+
return resource;
|
|
306
111
|
}
|
|
307
|
-
return { ...
|
|
112
|
+
return { ...normalizeTunnelResourceTarget(options), scopes: resource.scopes };
|
|
308
113
|
}
|
|
309
|
-
function
|
|
310
|
-
if (
|
|
114
|
+
function tunnelResourcesNeedDefaultTarget(resource, inheritedTarget = false) {
|
|
115
|
+
if (resource === void 0) {
|
|
311
116
|
return false;
|
|
312
117
|
}
|
|
313
|
-
if ("AND" in
|
|
314
|
-
const branchHasTarget = inheritedTarget ||
|
|
315
|
-
return
|
|
316
|
-
(
|
|
118
|
+
if ("AND" in resource) {
|
|
119
|
+
const branchHasTarget = inheritedTarget || resource.AND.some((child) => tunnelResourceTreeHasTarget(child));
|
|
120
|
+
return resource.AND.some(
|
|
121
|
+
(child) => tunnelResourcesNeedDefaultTarget(child, branchHasTarget)
|
|
317
122
|
);
|
|
318
123
|
}
|
|
319
|
-
if ("OR" in
|
|
320
|
-
return
|
|
321
|
-
(
|
|
124
|
+
if ("OR" in resource) {
|
|
125
|
+
return resource.OR.some(
|
|
126
|
+
(child) => tunnelResourcesNeedDefaultTarget(child, inheritedTarget)
|
|
322
127
|
);
|
|
323
128
|
}
|
|
324
|
-
return
|
|
129
|
+
return resource.scopes !== void 0 && !tunnelResourceHasTarget(resource) && !inheritedTarget;
|
|
325
130
|
}
|
|
326
|
-
function
|
|
327
|
-
return
|
|
131
|
+
function tunnelResourceHasTarget(resource) {
|
|
132
|
+
return resource.projects !== void 0 || resource.workspaces !== void 0;
|
|
328
133
|
}
|
|
329
|
-
function
|
|
330
|
-
if ("AND" in
|
|
331
|
-
return
|
|
134
|
+
function tunnelResourceTreeHasTarget(resource) {
|
|
135
|
+
if ("AND" in resource) {
|
|
136
|
+
return resource.AND.some((child) => tunnelResourceTreeHasTarget(child));
|
|
332
137
|
}
|
|
333
|
-
if ("OR" in
|
|
334
|
-
return
|
|
138
|
+
if ("OR" in resource) {
|
|
139
|
+
return resource.OR.some((child) => tunnelResourceTreeHasTarget(child));
|
|
335
140
|
}
|
|
336
|
-
return
|
|
141
|
+
return tunnelResourceHasTarget(resource);
|
|
337
142
|
}
|
|
338
|
-
function
|
|
143
|
+
function normalizeTunnelResourceTarget(options) {
|
|
339
144
|
const projectId = normalizeOptionalString(options?.projectId);
|
|
340
145
|
const workspaceId = normalizeOptionalString(options?.workspaceId);
|
|
341
146
|
if (projectId !== void 0 && workspaceId !== void 0) {
|
|
@@ -351,7 +156,7 @@ function normalizeTunnelGrantTarget(options) {
|
|
|
351
156
|
return {};
|
|
352
157
|
}
|
|
353
158
|
throw new Error(
|
|
354
|
-
"Project ID or workspace ID is required when using scope-only tunnel
|
|
159
|
+
"Project ID or workspace ID is required when using scope-only tunnel resources."
|
|
355
160
|
);
|
|
356
161
|
}
|
|
357
162
|
function normalizeOptionalString(value) {
|
|
@@ -508,6 +313,7 @@ async function resolveManagedTunnelsProject(config) {
|
|
|
508
313
|
}
|
|
509
314
|
|
|
510
315
|
// src/tunnels-resource.ts
|
|
316
|
+
import { tunnelSchema } from "@rstreamlabs/rstream/tunnel";
|
|
511
317
|
function tunnelPathId(id) {
|
|
512
318
|
const normalized = id.trim();
|
|
513
319
|
if (!normalized) {
|
|
@@ -547,21 +353,21 @@ import { readEnvironment as readEnvironment2 } from "@rstreamlabs/rstream";
|
|
|
547
353
|
import { isClientCredentials as isClientCredentials2 } from "@rstreamlabs/rstream";
|
|
548
354
|
import { isTokenCredentials as isTokenCredentials2 } from "@rstreamlabs/rstream";
|
|
549
355
|
import { RstreamClient as RstreamClient2 } from "@rstreamlabs/rstream";
|
|
550
|
-
import { turnCredentialsSchema } from "@rstreamlabs/rstream";
|
|
551
|
-
import * as
|
|
356
|
+
import { turnCredentialsSchema } from "@rstreamlabs/rstream/turn";
|
|
357
|
+
import * as z from "zod";
|
|
552
358
|
import crypto from "crypto";
|
|
553
359
|
var defaultTURNPort = 3478;
|
|
554
360
|
var defaultTURNSPort = 5349;
|
|
555
361
|
var defaultTURNCredentialTTLSeconds = 10 * 60;
|
|
556
362
|
var maxTURNCredentialTTLSeconds = 60 * 60;
|
|
557
|
-
var turnTokenClaimsSchema =
|
|
558
|
-
exp:
|
|
559
|
-
iat:
|
|
560
|
-
token_endpoint:
|
|
561
|
-
tokendpoint:
|
|
562
|
-
type:
|
|
363
|
+
var turnTokenClaimsSchema = z.object({
|
|
364
|
+
exp: z.number().int().optional(),
|
|
365
|
+
iat: z.number().int().optional(),
|
|
366
|
+
token_endpoint: z.string().regex(/^[0-9a-f]{8}$/i).optional(),
|
|
367
|
+
tokendpoint: z.string().regex(/^[0-9a-f]{8}$/i).optional(),
|
|
368
|
+
type: z.enum(["app", "auth", "pat"])
|
|
563
369
|
});
|
|
564
|
-
var turnCredentialModeSchema =
|
|
370
|
+
var turnCredentialModeSchema = z.enum(["api", "app", "pat"]);
|
|
565
371
|
function normalizeOptionalString2(value) {
|
|
566
372
|
const normalized = value?.trim();
|
|
567
373
|
return normalized ? normalized : void 0;
|
|
@@ -587,6 +393,9 @@ function normalizeTTLSeconds(ttlSeconds) {
|
|
|
587
393
|
}
|
|
588
394
|
return ttl;
|
|
589
395
|
}
|
|
396
|
+
function createAPITURNCredentialsParams(ttlSeconds) {
|
|
397
|
+
return ttlSeconds === void 0 ? {} : { ttlSeconds: normalizeTTLSeconds(ttlSeconds) };
|
|
398
|
+
}
|
|
590
399
|
function normalizePort(port, fallback, name) {
|
|
591
400
|
const normalized = port ?? fallback;
|
|
592
401
|
if (!Number.isInteger(normalized) || normalized < 1 || normalized > 65535) {
|
|
@@ -616,19 +425,21 @@ function parseTURNTokenClaims(token) {
|
|
|
616
425
|
if (!payloadPart) {
|
|
617
426
|
throw new Error("Invalid token format.");
|
|
618
427
|
}
|
|
619
|
-
|
|
620
|
-
try {
|
|
621
|
-
const payload = Buffer.from(payloadPart, "base64url").toString("utf8");
|
|
622
|
-
decoded = JSON.parse(payload);
|
|
623
|
-
} catch {
|
|
624
|
-
throw new Error("Invalid token format.");
|
|
625
|
-
}
|
|
428
|
+
const decoded = parseTURNTokenPayload(payloadPart);
|
|
626
429
|
const parsed = turnTokenClaimsSchema.safeParse(decoded);
|
|
627
430
|
if (!parsed.success) {
|
|
628
431
|
throw new Error("Invalid token format.");
|
|
629
432
|
}
|
|
630
433
|
return parsed.data;
|
|
631
434
|
}
|
|
435
|
+
function parseTURNTokenPayload(payloadPart) {
|
|
436
|
+
try {
|
|
437
|
+
const payload = Buffer.from(payloadPart, "base64url").toString("utf8");
|
|
438
|
+
return JSON.parse(payload);
|
|
439
|
+
} catch {
|
|
440
|
+
throw new Error("Invalid token format.");
|
|
441
|
+
}
|
|
442
|
+
}
|
|
632
443
|
function requirePATExpiration(claims, now) {
|
|
633
444
|
const exp = claims.exp;
|
|
634
445
|
if (typeof exp !== "number") {
|
|
@@ -702,8 +513,12 @@ async function createAPITURNCredentials(options) {
|
|
|
702
513
|
apiUrl: options.apiUrl,
|
|
703
514
|
credentials: options.credentials
|
|
704
515
|
});
|
|
516
|
+
const params = createAPITURNCredentialsParams(options.ttlSeconds);
|
|
705
517
|
if (projectId) {
|
|
706
|
-
return await client.tunnels.projects.createTurnCredentials(
|
|
518
|
+
return await client.tunnels.projects.createTurnCredentials(
|
|
519
|
+
projectId,
|
|
520
|
+
params
|
|
521
|
+
);
|
|
707
522
|
}
|
|
708
523
|
if (!projectEndpoint) {
|
|
709
524
|
throw new Error(
|
|
@@ -711,7 +526,8 @@ async function createAPITURNCredentials(options) {
|
|
|
711
526
|
);
|
|
712
527
|
}
|
|
713
528
|
return await client.tunnels.projects.createTurnCredentialsByEndpoint(
|
|
714
|
-
projectEndpoint
|
|
529
|
+
projectEndpoint,
|
|
530
|
+
params
|
|
715
531
|
);
|
|
716
532
|
}
|
|
717
533
|
function createPATTURNCredentials(options) {
|
|
@@ -829,7 +645,8 @@ async function createTURNCredentials(options) {
|
|
|
829
645
|
apiUrl: options.apiUrl,
|
|
830
646
|
credentials: controlPlaneCredentials,
|
|
831
647
|
projectEndpoint,
|
|
832
|
-
projectId: options.projectId
|
|
648
|
+
projectId: options.projectId,
|
|
649
|
+
ttlSeconds: options.ttlSeconds
|
|
833
650
|
});
|
|
834
651
|
}
|
|
835
652
|
const clusterDomain = normalizeClusterDomain(options.clusterDomain) ?? (projectEndpoint && options.engine ? deriveClusterDomainFromEngine(projectEndpoint, options.engine) : void 0);
|
|
@@ -1065,9 +882,11 @@ var RstreamTunnelsClient = class {
|
|
|
1065
882
|
async getEngineAuthTokenParams() {
|
|
1066
883
|
const target = await this.getEngineAuthTokenTarget();
|
|
1067
884
|
return {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
885
|
+
resources: {
|
|
886
|
+
tunnels: {
|
|
887
|
+
...target,
|
|
888
|
+
scopes: engineAuthTokenScopes
|
|
889
|
+
}
|
|
1071
890
|
}
|
|
1072
891
|
};
|
|
1073
892
|
}
|
|
@@ -1149,6 +968,7 @@ function normalizeOptionalString3(value) {
|
|
|
1149
968
|
}
|
|
1150
969
|
|
|
1151
970
|
// src/watch.ts
|
|
971
|
+
import { authTokenSchema } from "@rstreamlabs/rstream/auth-token";
|
|
1152
972
|
import jwt from "jsonwebtoken";
|
|
1153
973
|
var maxWatchTokenLifetimeSeconds = 3600;
|
|
1154
974
|
var watchTokenIssuedAtSkewSeconds = 300;
|
|
@@ -1176,37 +996,38 @@ function validateWatchQueryToken(token) {
|
|
|
1176
996
|
"Watch requires a token with a bounded lifetime of at most 3600 seconds."
|
|
1177
997
|
);
|
|
1178
998
|
}
|
|
1179
|
-
if (!
|
|
999
|
+
if (!hasWatchOnlyTunnelResources(parsed.data)) {
|
|
1180
1000
|
throw new Error(
|
|
1181
|
-
"Watch requires a fine-grained token limited to tunnel list
|
|
1001
|
+
"Watch requires a fine-grained token limited to tunnel list resources for URL-based authentication."
|
|
1182
1002
|
);
|
|
1183
1003
|
}
|
|
1184
1004
|
}
|
|
1185
|
-
function
|
|
1005
|
+
function hasWatchOnlyTunnelResources(token) {
|
|
1186
1006
|
if (!hasWatchOnlyPermissions(token.permissions)) {
|
|
1187
1007
|
return false;
|
|
1188
1008
|
}
|
|
1189
|
-
|
|
1009
|
+
const resource = token.resources?.tunnels;
|
|
1010
|
+
if (resource === void 0) {
|
|
1190
1011
|
return false;
|
|
1191
1012
|
}
|
|
1192
|
-
return
|
|
1013
|
+
return hasWatchOnlyTunnelResource(resource);
|
|
1193
1014
|
}
|
|
1194
|
-
function
|
|
1195
|
-
return
|
|
1015
|
+
function hasWatchOnlyTunnelResource(resource) {
|
|
1016
|
+
return watchResourceBranches(resource).every(
|
|
1196
1017
|
(branch) => branch.hasList && !branch.hasMutationOrConnect
|
|
1197
1018
|
);
|
|
1198
1019
|
}
|
|
1199
|
-
function
|
|
1200
|
-
if ("AND" in
|
|
1201
|
-
return
|
|
1202
|
-
(branches, child) =>
|
|
1020
|
+
function watchResourceBranches(resource) {
|
|
1021
|
+
if ("AND" in resource) {
|
|
1022
|
+
return resource.AND.reduce(
|
|
1023
|
+
(branches, child) => combineWatchResourceBranches(branches, child),
|
|
1203
1024
|
[{ hasList: false, hasMutationOrConnect: false }]
|
|
1204
1025
|
);
|
|
1205
1026
|
}
|
|
1206
|
-
if ("OR" in
|
|
1207
|
-
return
|
|
1027
|
+
if ("OR" in resource) {
|
|
1028
|
+
return resource.OR.flatMap(watchResourceBranches);
|
|
1208
1029
|
}
|
|
1209
|
-
const tunnels =
|
|
1030
|
+
const tunnels = resource.scopes?.tunnels;
|
|
1210
1031
|
if (tunnels === void 0) {
|
|
1211
1032
|
return [{ hasList: false, hasMutationOrConnect: false }];
|
|
1212
1033
|
}
|
|
@@ -1217,9 +1038,9 @@ function watchGrantBranches(grant) {
|
|
|
1217
1038
|
}
|
|
1218
1039
|
];
|
|
1219
1040
|
}
|
|
1220
|
-
function
|
|
1041
|
+
function combineWatchResourceBranches(branches, child) {
|
|
1221
1042
|
return branches.flatMap(
|
|
1222
|
-
(branch) =>
|
|
1043
|
+
(branch) => watchResourceBranches(child).map((childBranch) => ({
|
|
1223
1044
|
hasList: branch.hasList || childBranch.hasList,
|
|
1224
1045
|
hasMutationOrConnect: branch.hasMutationOrConnect || childBranch.hasMutationOrConnect
|
|
1225
1046
|
}))
|
|
@@ -1230,7 +1051,7 @@ function hasWatchOnlyPermissions(permissions) {
|
|
|
1230
1051
|
return true;
|
|
1231
1052
|
}
|
|
1232
1053
|
return permissions.every(
|
|
1233
|
-
(permission) => permission === "tunnels.resources.read-only"
|
|
1054
|
+
(permission) => permission === "tunnels.resources.read-only"
|
|
1234
1055
|
);
|
|
1235
1056
|
}
|
|
1236
1057
|
var Watch = class {
|
|
@@ -1315,7 +1136,7 @@ var Watch = class {
|
|
|
1315
1136
|
};
|
|
1316
1137
|
|
|
1317
1138
|
// src/webtty.ts
|
|
1318
|
-
import * as
|
|
1139
|
+
import * as z2 from "zod";
|
|
1319
1140
|
var osFamilies = [
|
|
1320
1141
|
"linux",
|
|
1321
1142
|
"macos",
|
|
@@ -1324,25 +1145,25 @@ var osFamilies = [
|
|
|
1324
1145
|
"openbsd",
|
|
1325
1146
|
"freebsd"
|
|
1326
1147
|
];
|
|
1327
|
-
var webttyServerSchema =
|
|
1328
|
-
tunnel_id:
|
|
1329
|
-
host:
|
|
1330
|
-
token_auth:
|
|
1331
|
-
os_family:
|
|
1332
|
-
arch:
|
|
1333
|
-
os_id:
|
|
1148
|
+
var webttyServerSchema = z2.object({
|
|
1149
|
+
tunnel_id: z2.string(),
|
|
1150
|
+
host: z2.string(),
|
|
1151
|
+
token_auth: z2.boolean(),
|
|
1152
|
+
os_family: z2.enum(osFamilies).optional(),
|
|
1153
|
+
arch: z2.string().optional(),
|
|
1154
|
+
os_id: z2.string().optional(),
|
|
1334
1155
|
// /etc/os-release::ID (ubuntu, debian, rocky, etc.)
|
|
1335
|
-
os_version_id:
|
|
1156
|
+
os_version_id: z2.string().optional(),
|
|
1336
1157
|
// /etc/os-release::VERSION_ID (24.04, 22.04, 11, 10.0.19045, ...)
|
|
1337
|
-
os_version_codename:
|
|
1158
|
+
os_version_codename: z2.string().optional(),
|
|
1338
1159
|
// /etc/os-release::VERSION_CODENAME (jammy, noble...)
|
|
1339
|
-
os_pretty_name:
|
|
1160
|
+
os_pretty_name: z2.string().optional(),
|
|
1340
1161
|
// /etc/os-release::PRETTY_NAME
|
|
1341
|
-
kernel_release:
|
|
1162
|
+
kernel_release: z2.string().optional(),
|
|
1342
1163
|
// uname -r
|
|
1343
|
-
hostname:
|
|
1164
|
+
hostname: z2.string().optional(),
|
|
1344
1165
|
// uname -n
|
|
1345
|
-
labels:
|
|
1166
|
+
labels: z2.record(z2.string(), z2.string().optional()).optional()
|
|
1346
1167
|
});
|
|
1347
1168
|
function parser(tunnel) {
|
|
1348
1169
|
if (tunnel.status !== "online") return null;
|
|
@@ -1394,18 +1215,11 @@ export {
|
|
|
1394
1215
|
RstreamWebhookResource as RstreamWebhookRessource,
|
|
1395
1216
|
RstreamTunnelsClient as Tunnels,
|
|
1396
1217
|
Watch,
|
|
1397
|
-
authTokenPermissionsSchema,
|
|
1398
|
-
authTokenSchema,
|
|
1399
|
-
authTokenScopesSchema,
|
|
1400
|
-
authTokenTunnelGrantSchema,
|
|
1401
|
-
authTokenTunnelsScopesSchema,
|
|
1402
1218
|
clientFilterSchema,
|
|
1403
1219
|
clientSchema,
|
|
1404
1220
|
createAPITURNCredentials,
|
|
1405
1221
|
createAPPTURNCredentials,
|
|
1406
1222
|
createAuthTokenFromClientCredentials,
|
|
1407
|
-
createAuthTokenParamsSchema,
|
|
1408
|
-
createAuthTokenResponseSchema,
|
|
1409
1223
|
createPATTURNCredentials,
|
|
1410
1224
|
createTURNCredentials,
|
|
1411
1225
|
engineOpenApiDocument,
|
|
@@ -1426,9 +1240,7 @@ export {
|
|
|
1426
1240
|
streamEndpointSchema,
|
|
1427
1241
|
streamSummarySchema,
|
|
1428
1242
|
streamTLSInfoSchema,
|
|
1429
|
-
tokenSchema,
|
|
1430
1243
|
tunnelFilterSchema,
|
|
1431
|
-
tunnelSchema,
|
|
1432
1244
|
turnCredentialModeSchema,
|
|
1433
1245
|
webhookEventsSchema,
|
|
1434
1246
|
webttyServerSchema,
|