@rstreamlabs/tunnels 1.0.8 → 1.0.10
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 +146 -53
- package/dist/{chunk-7RZ743EF.mjs → chunk-NHUJ3FYM.mjs} +3 -4
- package/dist/index.d.mts +82 -2536
- package/dist/index.d.ts +82 -2536
- package/dist/index.js +139 -28
- package/dist/index.mjs +137 -25
- package/dist/openapi.js +3 -4
- package/dist/openapi.mjs +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -162,8 +162,7 @@ var tunnelSchema = z2.object({
|
|
|
162
162
|
tls_alpns: z2.array(z2.string()).optional(),
|
|
163
163
|
tls_min_version: z2.string().optional(),
|
|
164
164
|
tls_ciphers: z2.array(z2.string()).optional(),
|
|
165
|
-
|
|
166
|
-
mtls_ca_cert_pem: z2.string().optional(),
|
|
165
|
+
mtls_auth: z2.boolean().optional(),
|
|
167
166
|
http_version: z2.enum(["http/1.1", "h2", "h2c", "h3"]).optional(),
|
|
168
167
|
http_use_tls: z2.boolean().optional(),
|
|
169
168
|
upstream_tls: z2.boolean().optional(),
|
|
@@ -263,10 +262,10 @@ var authTokenScopesSchema = z3.object({
|
|
|
263
262
|
});
|
|
264
263
|
}
|
|
265
264
|
});
|
|
266
|
-
var
|
|
265
|
+
var authTokenTunnelGrantLeafSchema = z3.object({
|
|
267
266
|
workspaces: z3.array(nonEmptyStringSchema).min(1).optional(),
|
|
268
267
|
projects: z3.array(nonEmptyStringSchema).min(1).optional(),
|
|
269
|
-
scopes: authTokenScopesSchema
|
|
268
|
+
scopes: authTokenScopesSchema.optional()
|
|
270
269
|
}).strict().superRefine((grant, ctx) => {
|
|
271
270
|
if (grant.workspaces !== void 0 && grant.projects !== void 0) {
|
|
272
271
|
ctx.addIssue({
|
|
@@ -275,18 +274,25 @@ var authTokenTunnelGrantSchema = z3.object({
|
|
|
275
274
|
path: ["projects"]
|
|
276
275
|
});
|
|
277
276
|
}
|
|
278
|
-
if (grant.workspaces === void 0 && grant.projects === void 0) {
|
|
277
|
+
if (grant.workspaces === void 0 && grant.projects === void 0 && grant.scopes === void 0) {
|
|
279
278
|
ctx.addIssue({
|
|
280
279
|
code: z3.ZodIssueCode.custom,
|
|
281
|
-
message: "A grant must target workspaces or
|
|
280
|
+
message: "A grant must target workspaces, projects, or scopes.",
|
|
282
281
|
path: ["workspaces"]
|
|
283
282
|
});
|
|
284
283
|
}
|
|
285
284
|
});
|
|
285
|
+
var authTokenTunnelGrantSchema = z3.lazy(
|
|
286
|
+
() => z3.union([
|
|
287
|
+
authTokenTunnelGrantLeafSchema,
|
|
288
|
+
z3.object({ AND: z3.array(authTokenTunnelGrantSchema).min(1) }).strict(),
|
|
289
|
+
z3.object({ OR: z3.array(authTokenTunnelGrantSchema).min(1) }).strict()
|
|
290
|
+
])
|
|
291
|
+
);
|
|
286
292
|
var authTokenCommonSchema = {
|
|
287
293
|
aud: z3.union([z3.string(), z3.array(z3.string())]).optional(),
|
|
288
294
|
exp: z3.number().optional(),
|
|
289
|
-
tunnelsGrants:
|
|
295
|
+
tunnelsGrants: authTokenTunnelGrantSchema.optional(),
|
|
290
296
|
iat: z3.number().optional(),
|
|
291
297
|
iss: z3.string().optional(),
|
|
292
298
|
jti: z3.string().optional(),
|
|
@@ -305,6 +311,7 @@ var authTokenSchema = z3.union([
|
|
|
305
311
|
}).strict(),
|
|
306
312
|
z3.object({
|
|
307
313
|
type: z3.literal("pat"),
|
|
314
|
+
tokendpoint: z3.string().optional(),
|
|
308
315
|
token_endpoint: z3.string().optional(),
|
|
309
316
|
...authTokenCommonSchema
|
|
310
317
|
}).strict(),
|
|
@@ -319,7 +326,7 @@ var tokenSchema = authTokenSchema;
|
|
|
319
326
|
var createAuthTokenParamsSchema = z3.object({
|
|
320
327
|
expires_in: z3.number().int().min(1).max(3600).default(60),
|
|
321
328
|
scopes: authTokenScopesSchema.optional(),
|
|
322
|
-
tunnelsGrants:
|
|
329
|
+
tunnelsGrants: authTokenTunnelGrantSchema.optional(),
|
|
323
330
|
metadata: z3.unknown().optional()
|
|
324
331
|
// Additional metadata
|
|
325
332
|
}).strict().superRefine((params, ctx) => {
|
|
@@ -357,10 +364,30 @@ var RstreamAuthResource = class {
|
|
|
357
364
|
);
|
|
358
365
|
}
|
|
359
366
|
const engine = options?.engine ?? await this.client.getEngine().catch(() => void 0);
|
|
367
|
+
const scopedOptions = await this.resolveScopeOptions(params, options);
|
|
360
368
|
return createAuthTokenFromClientCredentials(credentials, params, {
|
|
361
|
-
engine
|
|
369
|
+
engine,
|
|
370
|
+
...scopedOptions
|
|
362
371
|
});
|
|
363
372
|
}
|
|
373
|
+
async resolveScopeOptions(params, options) {
|
|
374
|
+
const tokenParams = createAuthTokenParamsSchema.parse(params);
|
|
375
|
+
if (options?.projectScoped === false) {
|
|
376
|
+
return options ?? {};
|
|
377
|
+
}
|
|
378
|
+
if (options?.projectId !== void 0 || options?.workspaceId !== void 0) {
|
|
379
|
+
return options;
|
|
380
|
+
}
|
|
381
|
+
if (tokenParams.scopes === void 0 && !tunnelGrantsNeedDefaultTarget(tokenParams.tunnelsGrants)) {
|
|
382
|
+
return options ?? {};
|
|
383
|
+
}
|
|
384
|
+
const target = await this.client.getEngineAuthTokenTarget();
|
|
385
|
+
return {
|
|
386
|
+
...options,
|
|
387
|
+
projectId: target.projects?.[0],
|
|
388
|
+
workspaceId: target.workspaces?.[0]
|
|
389
|
+
};
|
|
390
|
+
}
|
|
364
391
|
};
|
|
365
392
|
function createAuthTokenFromClientCredentials(credentials, params, options) {
|
|
366
393
|
const tokenParams = createAuthTokenParamsSchema.parse(params);
|
|
@@ -380,13 +407,66 @@ function createAuthTokenFromClientCredentials(credentials, params, options) {
|
|
|
380
407
|
function normalizeAuthTokenTunnelGrants(params, options) {
|
|
381
408
|
const tunnelsGrants = params.tunnelsGrants;
|
|
382
409
|
if (tunnelsGrants !== void 0) {
|
|
383
|
-
return
|
|
410
|
+
return applyDefaultTunnelGrantTarget(tunnelsGrants, options);
|
|
384
411
|
}
|
|
385
412
|
if (params.scopes) {
|
|
386
|
-
return
|
|
413
|
+
return { ...normalizeTunnelGrantTarget(options), scopes: params.scopes };
|
|
387
414
|
}
|
|
388
415
|
return void 0;
|
|
389
416
|
}
|
|
417
|
+
function applyDefaultTunnelGrantTarget(grants, options, inheritedTarget = false) {
|
|
418
|
+
if (options?.projectScoped === false) {
|
|
419
|
+
return grants;
|
|
420
|
+
}
|
|
421
|
+
if ("AND" in grants) {
|
|
422
|
+
const branchHasTarget = inheritedTarget || grants.AND.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
423
|
+
return {
|
|
424
|
+
AND: grants.AND.map(
|
|
425
|
+
(grant) => applyDefaultTunnelGrantTarget(grant, options, branchHasTarget)
|
|
426
|
+
)
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
if ("OR" in grants) {
|
|
430
|
+
return {
|
|
431
|
+
OR: grants.OR.map(
|
|
432
|
+
(grant) => applyDefaultTunnelGrantTarget(grant, options, inheritedTarget)
|
|
433
|
+
)
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
if (grants.scopes === void 0 || tunnelGrantHasTarget(grants) || inheritedTarget) {
|
|
437
|
+
return grants;
|
|
438
|
+
}
|
|
439
|
+
return { ...normalizeTunnelGrantTarget(options), scopes: grants.scopes };
|
|
440
|
+
}
|
|
441
|
+
function tunnelGrantsNeedDefaultTarget(grants, inheritedTarget = false) {
|
|
442
|
+
if (grants === void 0) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
if ("AND" in grants) {
|
|
446
|
+
const branchHasTarget = inheritedTarget || grants.AND.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
447
|
+
return grants.AND.some(
|
|
448
|
+
(grant) => tunnelGrantsNeedDefaultTarget(grant, branchHasTarget)
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
if ("OR" in grants) {
|
|
452
|
+
return grants.OR.some(
|
|
453
|
+
(grant) => tunnelGrantsNeedDefaultTarget(grant, inheritedTarget)
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
return grants.scopes !== void 0 && !tunnelGrantHasTarget(grants) && !inheritedTarget;
|
|
457
|
+
}
|
|
458
|
+
function tunnelGrantHasTarget(grant) {
|
|
459
|
+
return grant.projects !== void 0 || grant.workspaces !== void 0;
|
|
460
|
+
}
|
|
461
|
+
function tunnelGrantTreeHasTarget(grants) {
|
|
462
|
+
if ("AND" in grants) {
|
|
463
|
+
return grants.AND.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
464
|
+
}
|
|
465
|
+
if ("OR" in grants) {
|
|
466
|
+
return grants.OR.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
467
|
+
}
|
|
468
|
+
return tunnelGrantHasTarget(grants);
|
|
469
|
+
}
|
|
390
470
|
function normalizeTunnelGrantTarget(options) {
|
|
391
471
|
const projectId = normalizeOptionalString(options?.projectId);
|
|
392
472
|
const workspaceId = normalizeOptionalString(options?.workspaceId);
|
|
@@ -399,6 +479,9 @@ function normalizeTunnelGrantTarget(options) {
|
|
|
399
479
|
if (workspaceId !== void 0) {
|
|
400
480
|
return { workspaces: [workspaceId] };
|
|
401
481
|
}
|
|
482
|
+
if (options?.projectScoped === false) {
|
|
483
|
+
return {};
|
|
484
|
+
}
|
|
402
485
|
throw new Error(
|
|
403
486
|
"Project ID or workspace ID is required when using scope-only tunnel grants."
|
|
404
487
|
);
|
|
@@ -620,7 +703,7 @@ var routedTunnelSchema = z5.object({
|
|
|
620
703
|
httpUseTls: z5.boolean().optional(),
|
|
621
704
|
upstreamTls: z5.boolean().optional(),
|
|
622
705
|
tokenAuth: z5.boolean().optional(),
|
|
623
|
-
|
|
706
|
+
mtls_auth: z5.boolean().optional()
|
|
624
707
|
});
|
|
625
708
|
var routingSchema = z5.discriminatedUnion("decision", [
|
|
626
709
|
z5.object({ decision: z5.literal("routed"), tunnel: routedTunnelSchema }),
|
|
@@ -862,7 +945,7 @@ var engineOpenApiDocument = {
|
|
|
862
945
|
info: {
|
|
863
946
|
title: "rstream Engine API",
|
|
864
947
|
version: "1.0.0",
|
|
865
|
-
description: "Operational
|
|
948
|
+
description: "Operational Engine API exposed by rstream engine. This surface is scoped to the authenticated engine or project endpoint and covers live clients, live tunnels, and state-change streams."
|
|
866
949
|
},
|
|
867
950
|
servers: [
|
|
868
951
|
{
|
|
@@ -1179,7 +1262,7 @@ async function resolveTunnelsEngine(config) {
|
|
|
1179
1262
|
);
|
|
1180
1263
|
}
|
|
1181
1264
|
throw new Error(
|
|
1182
|
-
"Engine URL is not defined. Provide an engine, use RSTREAM_ENGINE, or configure a managed project endpoint with
|
|
1265
|
+
"Engine URL is not defined. Provide an engine, use RSTREAM_ENGINE, or configure a managed project endpoint with Control plane API access."
|
|
1183
1266
|
);
|
|
1184
1267
|
}
|
|
1185
1268
|
async function resolveManagedTunnelsProject(config) {
|
|
@@ -1255,6 +1338,7 @@ var turnTokenClaimsSchema = z8.object({
|
|
|
1255
1338
|
exp: z8.number().int().optional(),
|
|
1256
1339
|
iat: z8.number().int().optional(),
|
|
1257
1340
|
token_endpoint: z8.string().regex(/^[0-9a-f]{8}$/i).optional(),
|
|
1341
|
+
tokendpoint: z8.string().regex(/^[0-9a-f]{8}$/i).optional(),
|
|
1258
1342
|
type: z8.enum(["app", "auth", "pat"])
|
|
1259
1343
|
});
|
|
1260
1344
|
var turnCredentialModeSchema = z8.enum(["api", "app", "pat"]);
|
|
@@ -1431,7 +1515,8 @@ function createPATTURNCredentials(options) {
|
|
|
1431
1515
|
if (!tokenEndpoint) {
|
|
1432
1516
|
throw new Error("Token endpoint is required for TURN PAT mode.");
|
|
1433
1517
|
}
|
|
1434
|
-
|
|
1518
|
+
const claimsTokenEndpoint = claims.token_endpoint ?? claims.tokendpoint;
|
|
1519
|
+
if (claimsTokenEndpoint !== void 0 && claimsTokenEndpoint !== tokenEndpoint) {
|
|
1435
1520
|
throw new Error("Token endpoint does not match the PAT token.");
|
|
1436
1521
|
}
|
|
1437
1522
|
const now = normalizeNow(options.now);
|
|
@@ -1760,12 +1845,10 @@ var RstreamTunnelsClient = class {
|
|
|
1760
1845
|
async getEngineAuthTokenParams() {
|
|
1761
1846
|
const target = await this.getEngineAuthTokenTarget();
|
|
1762
1847
|
return {
|
|
1763
|
-
tunnelsGrants:
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
}
|
|
1768
|
-
]
|
|
1848
|
+
tunnelsGrants: {
|
|
1849
|
+
...target,
|
|
1850
|
+
scopes: engineAuthTokenScopes
|
|
1851
|
+
}
|
|
1769
1852
|
};
|
|
1770
1853
|
}
|
|
1771
1854
|
async getEngineAuthTokenTarget() {
|
|
@@ -1883,16 +1966,44 @@ function hasWatchOnlyTunnelGrants(token) {
|
|
|
1883
1966
|
if (!hasWatchOnlyPermissions(token.permissions)) {
|
|
1884
1967
|
return false;
|
|
1885
1968
|
}
|
|
1886
|
-
if (
|
|
1969
|
+
if (token.tunnelsGrants === void 0) {
|
|
1887
1970
|
return false;
|
|
1888
1971
|
}
|
|
1889
|
-
return token.tunnelsGrants
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1972
|
+
return hasWatchOnlyTunnelGrant(token.tunnelsGrants);
|
|
1973
|
+
}
|
|
1974
|
+
function hasWatchOnlyTunnelGrant(grant) {
|
|
1975
|
+
return watchGrantBranches(grant).every(
|
|
1976
|
+
(branch) => branch.hasList && !branch.hasMutationOrConnect
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1979
|
+
function watchGrantBranches(grant) {
|
|
1980
|
+
if ("AND" in grant) {
|
|
1981
|
+
return grant.AND.reduce(
|
|
1982
|
+
(branches, child) => combineWatchGrantBranches(branches, child),
|
|
1983
|
+
[{ hasList: false, hasMutationOrConnect: false }]
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
if ("OR" in grant) {
|
|
1987
|
+
return grant.OR.flatMap(watchGrantBranches);
|
|
1988
|
+
}
|
|
1989
|
+
const tunnels = grant.scopes?.tunnels;
|
|
1990
|
+
if (tunnels === void 0) {
|
|
1991
|
+
return [{ hasList: false, hasMutationOrConnect: false }];
|
|
1992
|
+
}
|
|
1993
|
+
return [
|
|
1994
|
+
{
|
|
1995
|
+
hasList: tunnels.list !== void 0,
|
|
1996
|
+
hasMutationOrConnect: tunnels.create !== void 0 || tunnels.connect !== void 0
|
|
1893
1997
|
}
|
|
1894
|
-
|
|
1895
|
-
|
|
1998
|
+
];
|
|
1999
|
+
}
|
|
2000
|
+
function combineWatchGrantBranches(branches, child) {
|
|
2001
|
+
return branches.flatMap(
|
|
2002
|
+
(branch) => watchGrantBranches(child).map((childBranch) => ({
|
|
2003
|
+
hasList: branch.hasList || childBranch.hasList,
|
|
2004
|
+
hasMutationOrConnect: branch.hasMutationOrConnect || childBranch.hasMutationOrConnect
|
|
2005
|
+
}))
|
|
2006
|
+
);
|
|
1896
2007
|
}
|
|
1897
2008
|
function hasWatchOnlyPermissions(permissions) {
|
|
1898
2009
|
if (!Array.isArray(permissions)) {
|
package/dist/index.mjs
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
tunnelSchema,
|
|
17
17
|
webhookEventsSchema,
|
|
18
18
|
wsEventsSchema
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-NHUJ3FYM.mjs";
|
|
20
20
|
|
|
21
21
|
// src/auth-resource.ts
|
|
22
22
|
import { createClientCredentialsToken } from "@rstreamlabs/rstream";
|
|
@@ -130,10 +130,10 @@ var authTokenScopesSchema = z2.object({
|
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
|
-
var
|
|
133
|
+
var authTokenTunnelGrantLeafSchema = z2.object({
|
|
134
134
|
workspaces: z2.array(nonEmptyStringSchema).min(1).optional(),
|
|
135
135
|
projects: z2.array(nonEmptyStringSchema).min(1).optional(),
|
|
136
|
-
scopes: authTokenScopesSchema
|
|
136
|
+
scopes: authTokenScopesSchema.optional()
|
|
137
137
|
}).strict().superRefine((grant, ctx) => {
|
|
138
138
|
if (grant.workspaces !== void 0 && grant.projects !== void 0) {
|
|
139
139
|
ctx.addIssue({
|
|
@@ -142,18 +142,25 @@ var authTokenTunnelGrantSchema = z2.object({
|
|
|
142
142
|
path: ["projects"]
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
|
-
if (grant.workspaces === void 0 && grant.projects === void 0) {
|
|
145
|
+
if (grant.workspaces === void 0 && grant.projects === void 0 && grant.scopes === void 0) {
|
|
146
146
|
ctx.addIssue({
|
|
147
147
|
code: z2.ZodIssueCode.custom,
|
|
148
|
-
message: "A grant must target workspaces or
|
|
148
|
+
message: "A grant must target workspaces, projects, or scopes.",
|
|
149
149
|
path: ["workspaces"]
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
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
|
+
);
|
|
153
160
|
var authTokenCommonSchema = {
|
|
154
161
|
aud: z2.union([z2.string(), z2.array(z2.string())]).optional(),
|
|
155
162
|
exp: z2.number().optional(),
|
|
156
|
-
tunnelsGrants:
|
|
163
|
+
tunnelsGrants: authTokenTunnelGrantSchema.optional(),
|
|
157
164
|
iat: z2.number().optional(),
|
|
158
165
|
iss: z2.string().optional(),
|
|
159
166
|
jti: z2.string().optional(),
|
|
@@ -172,6 +179,7 @@ var authTokenSchema = z2.union([
|
|
|
172
179
|
}).strict(),
|
|
173
180
|
z2.object({
|
|
174
181
|
type: z2.literal("pat"),
|
|
182
|
+
tokendpoint: z2.string().optional(),
|
|
175
183
|
token_endpoint: z2.string().optional(),
|
|
176
184
|
...authTokenCommonSchema
|
|
177
185
|
}).strict(),
|
|
@@ -186,7 +194,7 @@ var tokenSchema = authTokenSchema;
|
|
|
186
194
|
var createAuthTokenParamsSchema = z2.object({
|
|
187
195
|
expires_in: z2.number().int().min(1).max(3600).default(60),
|
|
188
196
|
scopes: authTokenScopesSchema.optional(),
|
|
189
|
-
tunnelsGrants:
|
|
197
|
+
tunnelsGrants: authTokenTunnelGrantSchema.optional(),
|
|
190
198
|
metadata: z2.unknown().optional()
|
|
191
199
|
// Additional metadata
|
|
192
200
|
}).strict().superRefine((params, ctx) => {
|
|
@@ -224,10 +232,30 @@ var RstreamAuthResource = class {
|
|
|
224
232
|
);
|
|
225
233
|
}
|
|
226
234
|
const engine = options?.engine ?? await this.client.getEngine().catch(() => void 0);
|
|
235
|
+
const scopedOptions = await this.resolveScopeOptions(params, options);
|
|
227
236
|
return createAuthTokenFromClientCredentials(credentials, params, {
|
|
228
|
-
engine
|
|
237
|
+
engine,
|
|
238
|
+
...scopedOptions
|
|
229
239
|
});
|
|
230
240
|
}
|
|
241
|
+
async resolveScopeOptions(params, options) {
|
|
242
|
+
const tokenParams = createAuthTokenParamsSchema.parse(params);
|
|
243
|
+
if (options?.projectScoped === false) {
|
|
244
|
+
return options ?? {};
|
|
245
|
+
}
|
|
246
|
+
if (options?.projectId !== void 0 || options?.workspaceId !== void 0) {
|
|
247
|
+
return options;
|
|
248
|
+
}
|
|
249
|
+
if (tokenParams.scopes === void 0 && !tunnelGrantsNeedDefaultTarget(tokenParams.tunnelsGrants)) {
|
|
250
|
+
return options ?? {};
|
|
251
|
+
}
|
|
252
|
+
const target = await this.client.getEngineAuthTokenTarget();
|
|
253
|
+
return {
|
|
254
|
+
...options,
|
|
255
|
+
projectId: target.projects?.[0],
|
|
256
|
+
workspaceId: target.workspaces?.[0]
|
|
257
|
+
};
|
|
258
|
+
}
|
|
231
259
|
};
|
|
232
260
|
function createAuthTokenFromClientCredentials(credentials, params, options) {
|
|
233
261
|
const tokenParams = createAuthTokenParamsSchema.parse(params);
|
|
@@ -247,13 +275,66 @@ function createAuthTokenFromClientCredentials(credentials, params, options) {
|
|
|
247
275
|
function normalizeAuthTokenTunnelGrants(params, options) {
|
|
248
276
|
const tunnelsGrants = params.tunnelsGrants;
|
|
249
277
|
if (tunnelsGrants !== void 0) {
|
|
250
|
-
return
|
|
278
|
+
return applyDefaultTunnelGrantTarget(tunnelsGrants, options);
|
|
251
279
|
}
|
|
252
280
|
if (params.scopes) {
|
|
253
|
-
return
|
|
281
|
+
return { ...normalizeTunnelGrantTarget(options), scopes: params.scopes };
|
|
254
282
|
}
|
|
255
283
|
return void 0;
|
|
256
284
|
}
|
|
285
|
+
function applyDefaultTunnelGrantTarget(grants, options, inheritedTarget = false) {
|
|
286
|
+
if (options?.projectScoped === false) {
|
|
287
|
+
return grants;
|
|
288
|
+
}
|
|
289
|
+
if ("AND" in grants) {
|
|
290
|
+
const branchHasTarget = inheritedTarget || grants.AND.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
291
|
+
return {
|
|
292
|
+
AND: grants.AND.map(
|
|
293
|
+
(grant) => applyDefaultTunnelGrantTarget(grant, options, branchHasTarget)
|
|
294
|
+
)
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if ("OR" in grants) {
|
|
298
|
+
return {
|
|
299
|
+
OR: grants.OR.map(
|
|
300
|
+
(grant) => applyDefaultTunnelGrantTarget(grant, options, inheritedTarget)
|
|
301
|
+
)
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (grants.scopes === void 0 || tunnelGrantHasTarget(grants) || inheritedTarget) {
|
|
305
|
+
return grants;
|
|
306
|
+
}
|
|
307
|
+
return { ...normalizeTunnelGrantTarget(options), scopes: grants.scopes };
|
|
308
|
+
}
|
|
309
|
+
function tunnelGrantsNeedDefaultTarget(grants, inheritedTarget = false) {
|
|
310
|
+
if (grants === void 0) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
if ("AND" in grants) {
|
|
314
|
+
const branchHasTarget = inheritedTarget || grants.AND.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
315
|
+
return grants.AND.some(
|
|
316
|
+
(grant) => tunnelGrantsNeedDefaultTarget(grant, branchHasTarget)
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
if ("OR" in grants) {
|
|
320
|
+
return grants.OR.some(
|
|
321
|
+
(grant) => tunnelGrantsNeedDefaultTarget(grant, inheritedTarget)
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
return grants.scopes !== void 0 && !tunnelGrantHasTarget(grants) && !inheritedTarget;
|
|
325
|
+
}
|
|
326
|
+
function tunnelGrantHasTarget(grant) {
|
|
327
|
+
return grant.projects !== void 0 || grant.workspaces !== void 0;
|
|
328
|
+
}
|
|
329
|
+
function tunnelGrantTreeHasTarget(grants) {
|
|
330
|
+
if ("AND" in grants) {
|
|
331
|
+
return grants.AND.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
332
|
+
}
|
|
333
|
+
if ("OR" in grants) {
|
|
334
|
+
return grants.OR.some((grant) => tunnelGrantTreeHasTarget(grant));
|
|
335
|
+
}
|
|
336
|
+
return tunnelGrantHasTarget(grants);
|
|
337
|
+
}
|
|
257
338
|
function normalizeTunnelGrantTarget(options) {
|
|
258
339
|
const projectId = normalizeOptionalString(options?.projectId);
|
|
259
340
|
const workspaceId = normalizeOptionalString(options?.workspaceId);
|
|
@@ -266,6 +347,9 @@ function normalizeTunnelGrantTarget(options) {
|
|
|
266
347
|
if (workspaceId !== void 0) {
|
|
267
348
|
return { workspaces: [workspaceId] };
|
|
268
349
|
}
|
|
350
|
+
if (options?.projectScoped === false) {
|
|
351
|
+
return {};
|
|
352
|
+
}
|
|
269
353
|
throw new Error(
|
|
270
354
|
"Project ID or workspace ID is required when using scope-only tunnel grants."
|
|
271
355
|
);
|
|
@@ -398,7 +482,7 @@ async function resolveTunnelsEngine(config) {
|
|
|
398
482
|
);
|
|
399
483
|
}
|
|
400
484
|
throw new Error(
|
|
401
|
-
"Engine URL is not defined. Provide an engine, use RSTREAM_ENGINE, or configure a managed project endpoint with
|
|
485
|
+
"Engine URL is not defined. Provide an engine, use RSTREAM_ENGINE, or configure a managed project endpoint with Control plane API access."
|
|
402
486
|
);
|
|
403
487
|
}
|
|
404
488
|
async function resolveManagedTunnelsProject(config) {
|
|
@@ -474,6 +558,7 @@ var turnTokenClaimsSchema = z3.object({
|
|
|
474
558
|
exp: z3.number().int().optional(),
|
|
475
559
|
iat: z3.number().int().optional(),
|
|
476
560
|
token_endpoint: z3.string().regex(/^[0-9a-f]{8}$/i).optional(),
|
|
561
|
+
tokendpoint: z3.string().regex(/^[0-9a-f]{8}$/i).optional(),
|
|
477
562
|
type: z3.enum(["app", "auth", "pat"])
|
|
478
563
|
});
|
|
479
564
|
var turnCredentialModeSchema = z3.enum(["api", "app", "pat"]);
|
|
@@ -650,7 +735,8 @@ function createPATTURNCredentials(options) {
|
|
|
650
735
|
if (!tokenEndpoint) {
|
|
651
736
|
throw new Error("Token endpoint is required for TURN PAT mode.");
|
|
652
737
|
}
|
|
653
|
-
|
|
738
|
+
const claimsTokenEndpoint = claims.token_endpoint ?? claims.tokendpoint;
|
|
739
|
+
if (claimsTokenEndpoint !== void 0 && claimsTokenEndpoint !== tokenEndpoint) {
|
|
654
740
|
throw new Error("Token endpoint does not match the PAT token.");
|
|
655
741
|
}
|
|
656
742
|
const now = normalizeNow(options.now);
|
|
@@ -979,12 +1065,10 @@ var RstreamTunnelsClient = class {
|
|
|
979
1065
|
async getEngineAuthTokenParams() {
|
|
980
1066
|
const target = await this.getEngineAuthTokenTarget();
|
|
981
1067
|
return {
|
|
982
|
-
tunnelsGrants:
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
}
|
|
987
|
-
]
|
|
1068
|
+
tunnelsGrants: {
|
|
1069
|
+
...target,
|
|
1070
|
+
scopes: engineAuthTokenScopes
|
|
1071
|
+
}
|
|
988
1072
|
};
|
|
989
1073
|
}
|
|
990
1074
|
async getEngineAuthTokenTarget() {
|
|
@@ -1102,16 +1186,44 @@ function hasWatchOnlyTunnelGrants(token) {
|
|
|
1102
1186
|
if (!hasWatchOnlyPermissions(token.permissions)) {
|
|
1103
1187
|
return false;
|
|
1104
1188
|
}
|
|
1105
|
-
if (
|
|
1189
|
+
if (token.tunnelsGrants === void 0) {
|
|
1106
1190
|
return false;
|
|
1107
1191
|
}
|
|
1108
|
-
return token.tunnelsGrants
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1192
|
+
return hasWatchOnlyTunnelGrant(token.tunnelsGrants);
|
|
1193
|
+
}
|
|
1194
|
+
function hasWatchOnlyTunnelGrant(grant) {
|
|
1195
|
+
return watchGrantBranches(grant).every(
|
|
1196
|
+
(branch) => branch.hasList && !branch.hasMutationOrConnect
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
function watchGrantBranches(grant) {
|
|
1200
|
+
if ("AND" in grant) {
|
|
1201
|
+
return grant.AND.reduce(
|
|
1202
|
+
(branches, child) => combineWatchGrantBranches(branches, child),
|
|
1203
|
+
[{ hasList: false, hasMutationOrConnect: false }]
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
if ("OR" in grant) {
|
|
1207
|
+
return grant.OR.flatMap(watchGrantBranches);
|
|
1208
|
+
}
|
|
1209
|
+
const tunnels = grant.scopes?.tunnels;
|
|
1210
|
+
if (tunnels === void 0) {
|
|
1211
|
+
return [{ hasList: false, hasMutationOrConnect: false }];
|
|
1212
|
+
}
|
|
1213
|
+
return [
|
|
1214
|
+
{
|
|
1215
|
+
hasList: tunnels.list !== void 0,
|
|
1216
|
+
hasMutationOrConnect: tunnels.create !== void 0 || tunnels.connect !== void 0
|
|
1112
1217
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1218
|
+
];
|
|
1219
|
+
}
|
|
1220
|
+
function combineWatchGrantBranches(branches, child) {
|
|
1221
|
+
return branches.flatMap(
|
|
1222
|
+
(branch) => watchGrantBranches(child).map((childBranch) => ({
|
|
1223
|
+
hasList: branch.hasList || childBranch.hasList,
|
|
1224
|
+
hasMutationOrConnect: branch.hasMutationOrConnect || childBranch.hasMutationOrConnect
|
|
1225
|
+
}))
|
|
1226
|
+
);
|
|
1115
1227
|
}
|
|
1116
1228
|
function hasWatchOnlyPermissions(permissions) {
|
|
1117
1229
|
if (!Array.isArray(permissions)) {
|
package/dist/openapi.js
CHANGED
|
@@ -103,8 +103,7 @@ var tunnelSchema = z2.object({
|
|
|
103
103
|
tls_alpns: z2.array(z2.string()).optional(),
|
|
104
104
|
tls_min_version: z2.string().optional(),
|
|
105
105
|
tls_ciphers: z2.array(z2.string()).optional(),
|
|
106
|
-
|
|
107
|
-
mtls_ca_cert_pem: z2.string().optional(),
|
|
106
|
+
mtls_auth: z2.boolean().optional(),
|
|
108
107
|
http_version: z2.enum(["http/1.1", "h2", "h2c", "h3"]).optional(),
|
|
109
108
|
http_use_tls: z2.boolean().optional(),
|
|
110
109
|
upstream_tls: z2.boolean().optional(),
|
|
@@ -274,7 +273,7 @@ var routedTunnelSchema = z3.object({
|
|
|
274
273
|
httpUseTls: z3.boolean().optional(),
|
|
275
274
|
upstreamTls: z3.boolean().optional(),
|
|
276
275
|
tokenAuth: z3.boolean().optional(),
|
|
277
|
-
|
|
276
|
+
mtls_auth: z3.boolean().optional()
|
|
278
277
|
});
|
|
279
278
|
var routingSchema = z3.discriminatedUnion("decision", [
|
|
280
279
|
z3.object({ decision: z3.literal("routed"), tunnel: routedTunnelSchema }),
|
|
@@ -516,7 +515,7 @@ var engineOpenApiDocument = {
|
|
|
516
515
|
info: {
|
|
517
516
|
title: "rstream Engine API",
|
|
518
517
|
version: "1.0.0",
|
|
519
|
-
description: "Operational
|
|
518
|
+
description: "Operational Engine API exposed by rstream engine. This surface is scoped to the authenticated engine or project endpoint and covers live clients, live tunnels, and state-change streams."
|
|
520
519
|
},
|
|
521
520
|
servers: [
|
|
522
521
|
{
|
package/dist/openapi.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstreamlabs/tunnels",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "JS/TS SDK for the rstream
|
|
3
|
+
"version": "1.0.10",
|
|
4
|
+
"description": "JS/TS SDK for the rstream Engine API and tunnel runtime APIs.",
|
|
5
5
|
"author": "@uartnet <hello@rstream.io>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"typescript-config": "*"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@rstreamlabs/rstream": "2.1.
|
|
46
|
+
"@rstreamlabs/rstream": "2.1.3",
|
|
47
47
|
"jsonwebtoken": "^9.0.3",
|
|
48
48
|
"zod": "^4.3.6"
|
|
49
49
|
},
|