@meshagent/meshagent 0.36.3 → 0.37.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/browser/agent-client.d.ts +2 -10
  3. package/dist/browser/agent-client.js +2 -30
  4. package/dist/browser/agent.d.ts +22 -22
  5. package/dist/browser/agent.js +36 -16
  6. package/dist/browser/containers-client.d.ts +7 -19
  7. package/dist/browser/containers-client.js +27 -21
  8. package/dist/browser/data-types.d.ts +12 -0
  9. package/dist/browser/data-types.js +39 -1
  10. package/dist/browser/database-client.d.ts +134 -47
  11. package/dist/browser/database-client.js +359 -133
  12. package/dist/browser/index.d.ts +1 -0
  13. package/dist/browser/index.js +1 -0
  14. package/dist/browser/meshagent-client.js +12 -1
  15. package/dist/browser/participant-token.d.ts +189 -22
  16. package/dist/browser/participant-token.js +1001 -189
  17. package/dist/browser/room-client.d.ts +1 -1
  18. package/dist/browser/services-client.d.ts +1 -1
  19. package/dist/browser/version.d.ts +1 -0
  20. package/dist/browser/version.js +4 -0
  21. package/dist/esm/agent-client.d.ts +2 -10
  22. package/dist/esm/agent-client.js +1 -28
  23. package/dist/esm/agent.d.ts +22 -22
  24. package/dist/esm/agent.js +33 -14
  25. package/dist/esm/containers-client.d.ts +7 -19
  26. package/dist/esm/containers-client.js +27 -21
  27. package/dist/esm/data-types.d.ts +12 -0
  28. package/dist/esm/data-types.js +36 -0
  29. package/dist/esm/database-client.d.ts +134 -47
  30. package/dist/esm/database-client.js +352 -132
  31. package/dist/esm/index.d.ts +1 -0
  32. package/dist/esm/index.js +1 -0
  33. package/dist/esm/meshagent-client.js +12 -1
  34. package/dist/esm/participant-token.d.ts +189 -22
  35. package/dist/esm/participant-token.js +992 -188
  36. package/dist/esm/room-client.d.ts +1 -1
  37. package/dist/esm/services-client.d.ts +1 -1
  38. package/dist/esm/version.d.ts +1 -0
  39. package/dist/esm/version.js +1 -0
  40. package/dist/node/agent-client.d.ts +2 -10
  41. package/dist/node/agent-client.js +2 -30
  42. package/dist/node/agent.d.ts +22 -22
  43. package/dist/node/agent.js +36 -16
  44. package/dist/node/containers-client.d.ts +7 -19
  45. package/dist/node/containers-client.js +27 -21
  46. package/dist/node/data-types.d.ts +12 -0
  47. package/dist/node/data-types.js +39 -1
  48. package/dist/node/database-client.d.ts +134 -47
  49. package/dist/node/database-client.js +359 -133
  50. package/dist/node/index.d.ts +1 -0
  51. package/dist/node/index.js +1 -0
  52. package/dist/node/meshagent-client.js +12 -1
  53. package/dist/node/participant-token.d.ts +189 -22
  54. package/dist/node/participant-token.js +1001 -189
  55. package/dist/node/room-client.d.ts +1 -1
  56. package/dist/node/services-client.d.ts +1 -1
  57. package/dist/node/version.d.ts +1 -0
  58. package/dist/node/version.js +4 -0
  59. package/package.json +1 -1
@@ -1,19 +1,87 @@
1
1
  import { decodeJwt, jwtVerify, SignJWT } from "jose";
2
2
  import { parseApiKey } from "./api_keys";
3
+ import { __version__ } from "./version";
4
+ function matchesGrantPattern(patterns, value, allowIfUnset) {
5
+ if (!patterns) {
6
+ return allowIfUnset;
7
+ }
8
+ return patterns.some((pattern) => value === pattern
9
+ || (pattern.endsWith("*")
10
+ && value.startsWith(pattern.slice(0, -1))));
11
+ }
3
12
  function getEnvValue(name) {
4
13
  if (typeof process === "undefined") {
5
14
  return undefined;
6
15
  }
7
16
  return process.env?.[name];
8
17
  }
18
+ function normalizeNamespace(namespace) {
19
+ return namespace ?? [];
20
+ }
21
+ function namespacesEqual(left, right) {
22
+ const normalizedLeft = normalizeNamespace(left);
23
+ const normalizedRight = normalizeNamespace(right);
24
+ if (normalizedLeft.length !== normalizedRight.length) {
25
+ return false;
26
+ }
27
+ return normalizedLeft.every((value, index) => value === normalizedRight[index]);
28
+ }
29
+ function isRecord(value) {
30
+ return typeof value === "object" && value !== null;
31
+ }
32
+ function asStringList(value) {
33
+ return Array.isArray(value) && value.every((item) => typeof item === "string")
34
+ ? value
35
+ : undefined;
36
+ }
9
37
  export class AgentsGrant {
10
- constructor({ registerAgent, registerPublicToolkit, registerPrivateToolkit, call, useAgents, useTools, } = {}) {
38
+ constructor({ registerAgent, registerPublicToolkit, registerPrivateToolkit, call, useAgents, useTools, allowedToolkits, } = {}) {
11
39
  this.registerAgent = registerAgent ?? true;
12
40
  this.registerPublicToolkit = registerPublicToolkit ?? true;
13
41
  this.registerPrivateToolkit = registerPrivateToolkit ?? true;
14
42
  this.call = call ?? true;
15
43
  this.useAgents = useAgents ?? true;
16
44
  this.useTools = useTools ?? true;
45
+ this.allowedToolkits = allowedToolkits;
46
+ }
47
+ toJSON() {
48
+ const json = {};
49
+ if (this.registerAgent !== true) {
50
+ json["register_agent"] = this.registerAgent;
51
+ }
52
+ if (this.registerPublicToolkit !== true) {
53
+ json["register_public_toolkit"] = this.registerPublicToolkit;
54
+ }
55
+ if (this.registerPrivateToolkit !== true) {
56
+ json["register_private_toolkit"] = this.registerPrivateToolkit;
57
+ }
58
+ if (this.call !== true) {
59
+ json["call"] = this.call;
60
+ }
61
+ if (this.useAgents !== true) {
62
+ json["use_agents"] = this.useAgents;
63
+ }
64
+ if (this.useTools !== true) {
65
+ json["use_tools"] = this.useTools;
66
+ }
67
+ if (this.allowedToolkits !== undefined) {
68
+ json["allowed_toolkits"] = this.allowedToolkits;
69
+ }
70
+ return json;
71
+ }
72
+ static fromJSON(obj) {
73
+ if (!isRecord(obj)) {
74
+ return new AgentsGrant();
75
+ }
76
+ return new AgentsGrant({
77
+ registerAgent: obj.register_agent ?? obj.registerAgent,
78
+ registerPublicToolkit: obj.register_public_toolkit ?? obj.registerPublicToolkit,
79
+ registerPrivateToolkit: obj.register_private_toolkit ?? obj.registerPrivateToolkit,
80
+ call: obj.call,
81
+ useAgents: obj.use_agents ?? obj.useAgents,
82
+ useTools: obj.use_tools ?? obj.useTools,
83
+ allowedToolkits: asStringList(obj.allowed_toolkits ?? obj.allowedToolkits),
84
+ });
17
85
  }
18
86
  }
19
87
  export class LivekitGrant {
@@ -23,61 +91,367 @@ export class LivekitGrant {
23
91
  canJoinBreakoutRoom(name) {
24
92
  return !this.breakoutRooms || this.breakoutRooms.includes(name);
25
93
  }
94
+ toJSON() {
95
+ const json = {};
96
+ if (this.breakoutRooms !== undefined) {
97
+ json["breakout_rooms"] = this.breakoutRooms;
98
+ }
99
+ return json;
100
+ }
101
+ static fromJSON(obj) {
102
+ if (!isRecord(obj)) {
103
+ return new LivekitGrant();
104
+ }
105
+ return new LivekitGrant({
106
+ breakoutRooms: asStringList(obj.breakout_rooms ?? obj.breakoutRooms),
107
+ });
108
+ }
26
109
  }
27
110
  export class QueuesGrant {
28
- constructor({ send, receive, list } = {}) {
29
- this.list = true;
111
+ constructor({ send, receive, list, } = {}) {
30
112
  this.send = send;
31
113
  this.receive = receive;
32
114
  this.list = list ?? true;
33
115
  }
34
- canSend(q) {
35
- return !this.send || this.send.includes(q);
116
+ canSend(queue) {
117
+ return !this.send || this.send.includes(queue);
36
118
  }
37
- canReceive(q) {
38
- return !this.receive || this.receive.includes(q);
119
+ canReceive(queue) {
120
+ return !this.receive || this.receive.includes(queue);
121
+ }
122
+ toJSON() {
123
+ const json = {};
124
+ if (this.send !== undefined) {
125
+ json["send"] = this.send;
126
+ }
127
+ if (this.receive !== undefined) {
128
+ json["receive"] = this.receive;
129
+ }
130
+ if (this.list !== true) {
131
+ json["list"] = this.list;
132
+ }
133
+ return json;
134
+ }
135
+ static fromJSON(obj) {
136
+ if (!isRecord(obj)) {
137
+ return new QueuesGrant();
138
+ }
139
+ return new QueuesGrant({
140
+ send: asStringList(obj.send),
141
+ receive: asStringList(obj.receive),
142
+ list: obj.list,
143
+ });
39
144
  }
40
145
  }
41
146
  export class MessagingGrant {
42
- constructor({ broadcast, list, send } = {}) {
147
+ constructor({ broadcast, list, send, } = {}) {
43
148
  this.broadcast = broadcast ?? true;
44
149
  this.list = list ?? true;
45
150
  this.send = send ?? true;
46
151
  }
152
+ toJSON() {
153
+ const json = {};
154
+ if (this.broadcast !== true) {
155
+ json["broadcast"] = this.broadcast;
156
+ }
157
+ if (this.list !== true) {
158
+ json["list"] = this.list;
159
+ }
160
+ if (this.send !== true) {
161
+ json["send"] = this.send;
162
+ }
163
+ return json;
164
+ }
165
+ static fromJSON(obj) {
166
+ if (!isRecord(obj)) {
167
+ return new MessagingGrant();
168
+ }
169
+ return new MessagingGrant({
170
+ broadcast: obj.broadcast,
171
+ list: obj.list,
172
+ send: obj.send,
173
+ });
174
+ }
47
175
  }
48
176
  export class TableGrant {
49
- constructor({ name, write, read, alter }) {
50
- this.write = false;
51
- this.read = true;
52
- this.alter = false;
177
+ constructor({ name, namespace, write, read, alter, }) {
53
178
  this.name = name;
179
+ this.namespace = namespace;
54
180
  this.write = write ?? false;
55
181
  this.read = read ?? true;
56
182
  this.alter = alter ?? false;
57
183
  }
184
+ toJSON() {
185
+ const json = {
186
+ name: this.name,
187
+ };
188
+ if (this.namespace !== undefined) {
189
+ json["namespace"] = this.namespace;
190
+ }
191
+ if (this.write !== false) {
192
+ json["write"] = this.write;
193
+ }
194
+ if (this.read !== true) {
195
+ json["read"] = this.read;
196
+ }
197
+ if (this.alter !== false) {
198
+ json["alter"] = this.alter;
199
+ }
200
+ return json;
201
+ }
202
+ static fromJSON(obj) {
203
+ if (!isRecord(obj) || typeof obj.name !== "string") {
204
+ throw new Error("TableGrant requires a name");
205
+ }
206
+ return new TableGrant({
207
+ name: obj.name,
208
+ namespace: asStringList(obj.namespace),
209
+ write: obj.write,
210
+ read: obj.read,
211
+ alter: obj.alter,
212
+ });
213
+ }
58
214
  }
59
215
  export class DatabaseGrant {
60
- constructor({ tables, listTables } = {}) {
61
- this.listTables = true;
216
+ constructor({ tables, listTables, } = {}) {
62
217
  this.tables = tables;
63
218
  this.listTables = listTables ?? true;
64
219
  }
65
- _match(table) {
66
- if (!this.tables)
67
- return undefined;
68
- return this.tables.find(t => t.name === table);
220
+ matchingTables(table, namespace) {
221
+ if (this.tables === undefined) {
222
+ return [];
223
+ }
224
+ return this.tables.filter((tableGrant) => {
225
+ if (tableGrant.name !== table) {
226
+ return false;
227
+ }
228
+ if (tableGrant.namespace === undefined) {
229
+ return true;
230
+ }
231
+ return namespacesEqual(tableGrant.namespace, namespace);
232
+ });
69
233
  }
70
- canWrite(table) {
71
- const t = this._match(table);
72
- return t ? t.write : this.tables === undefined;
234
+ canWrite(table, namespace) {
235
+ if (this.tables === undefined) {
236
+ return true;
237
+ }
238
+ const matches = this.matchingTables(table, namespace);
239
+ if (matches.length === 0) {
240
+ return false;
241
+ }
242
+ return matches.some((tableGrant) => tableGrant.write);
73
243
  }
74
- canRead(table) {
75
- const t = this._match(table);
76
- return t ? t.read : this.tables === undefined;
244
+ canRead(table, namespace) {
245
+ if (this.tables === undefined) {
246
+ return true;
247
+ }
248
+ const matches = this.matchingTables(table, namespace);
249
+ if (matches.length === 0) {
250
+ return false;
251
+ }
252
+ return matches.some((tableGrant) => tableGrant.read);
77
253
  }
78
- canAlter(table) {
79
- const t = this._match(table);
80
- return t ? t.alter : this.tables === undefined;
254
+ canAlter(table, namespace) {
255
+ if (this.tables === undefined) {
256
+ return true;
257
+ }
258
+ const matches = this.matchingTables(table, namespace);
259
+ if (matches.length === 0) {
260
+ return false;
261
+ }
262
+ return matches.some((tableGrant) => tableGrant.alter);
263
+ }
264
+ canAccess(table, namespace) {
265
+ return (this.canRead(table, namespace)
266
+ || this.canWrite(table, namespace)
267
+ || this.canAlter(table, namespace));
268
+ }
269
+ toJSON() {
270
+ const json = {};
271
+ if (this.tables !== undefined) {
272
+ json["tables"] = this.tables.map((tableGrant) => tableGrant.toJSON());
273
+ }
274
+ if (this.listTables !== true) {
275
+ json["list_tables"] = this.listTables;
276
+ }
277
+ return json;
278
+ }
279
+ static fromJSON(obj) {
280
+ if (!isRecord(obj)) {
281
+ return new DatabaseGrant();
282
+ }
283
+ return new DatabaseGrant({
284
+ tables: Array.isArray(obj.tables)
285
+ ? obj.tables.map((tableGrant) => TableGrant.fromJSON(tableGrant))
286
+ : undefined,
287
+ listTables: obj.list_tables ?? obj.listTables,
288
+ });
289
+ }
290
+ }
291
+ export class MemoryPermissions {
292
+ constructor({ create, drop, inspect, query, upsert, ingest, recall, optimize, } = {}) {
293
+ this.create = create ?? true;
294
+ this.drop = drop ?? true;
295
+ this.inspect = inspect ?? true;
296
+ this.query = query ?? true;
297
+ this.upsert = upsert ?? true;
298
+ this.ingest = ingest ?? true;
299
+ this.recall = recall ?? true;
300
+ this.optimize = optimize ?? true;
301
+ }
302
+ toJSON() {
303
+ const json = {};
304
+ if (this.create !== true) {
305
+ json["create"] = this.create;
306
+ }
307
+ if (this.drop !== true) {
308
+ json["drop"] = this.drop;
309
+ }
310
+ if (this.inspect !== true) {
311
+ json["inspect"] = this.inspect;
312
+ }
313
+ if (this.query !== true) {
314
+ json["query"] = this.query;
315
+ }
316
+ if (this.upsert !== true) {
317
+ json["upsert"] = this.upsert;
318
+ }
319
+ if (this.ingest !== true) {
320
+ json["ingest"] = this.ingest;
321
+ }
322
+ if (this.recall !== true) {
323
+ json["recall"] = this.recall;
324
+ }
325
+ if (this.optimize !== true) {
326
+ json["optimize"] = this.optimize;
327
+ }
328
+ return json;
329
+ }
330
+ static fromJSON(obj) {
331
+ if (!isRecord(obj)) {
332
+ return new MemoryPermissions();
333
+ }
334
+ return new MemoryPermissions({
335
+ create: obj.create,
336
+ drop: obj.drop,
337
+ inspect: obj.inspect,
338
+ query: obj.query,
339
+ upsert: obj.upsert,
340
+ ingest: obj.ingest,
341
+ recall: obj.recall,
342
+ optimize: obj.optimize,
343
+ });
344
+ }
345
+ }
346
+ export class MemoryEntryGrant {
347
+ constructor({ name, namespace, permissions, }) {
348
+ this.name = name;
349
+ this.namespace = namespace;
350
+ this.permissions = permissions ?? new MemoryPermissions();
351
+ }
352
+ toJSON() {
353
+ const json = {
354
+ name: this.name,
355
+ };
356
+ if (this.namespace !== undefined) {
357
+ json["namespace"] = this.namespace;
358
+ }
359
+ json["permissions"] = this.permissions.toJSON();
360
+ return json;
361
+ }
362
+ static fromJSON(obj) {
363
+ if (!isRecord(obj) || typeof obj.name !== "string") {
364
+ throw new Error("MemoryEntryGrant requires a name");
365
+ }
366
+ return new MemoryEntryGrant({
367
+ name: obj.name,
368
+ namespace: asStringList(obj.namespace),
369
+ permissions: MemoryPermissions.fromJSON(obj.permissions),
370
+ });
371
+ }
372
+ }
373
+ export class MemoryGrant {
374
+ constructor({ list, memories, } = {}) {
375
+ this.list = list ?? true;
376
+ this.memories = memories;
377
+ }
378
+ matchingMemories(name, namespace) {
379
+ if (this.memories === undefined) {
380
+ return [];
381
+ }
382
+ return this.memories.filter((memoryGrant) => {
383
+ if (memoryGrant.name !== name) {
384
+ return false;
385
+ }
386
+ if (memoryGrant.namespace === undefined) {
387
+ return true;
388
+ }
389
+ return namespacesEqual(memoryGrant.namespace, namespace);
390
+ });
391
+ }
392
+ can(name, namespace, permission) {
393
+ if (this.memories === undefined) {
394
+ return true;
395
+ }
396
+ const matches = this.matchingMemories(name, namespace);
397
+ if (matches.length === 0) {
398
+ return false;
399
+ }
400
+ return matches.some((memoryGrant) => memoryGrant.permissions[permission]);
401
+ }
402
+ canCreate(name, namespace) {
403
+ return this.can(name, namespace, "create");
404
+ }
405
+ canDrop(name, namespace) {
406
+ return this.can(name, namespace, "drop");
407
+ }
408
+ canInspect(name, namespace) {
409
+ return this.can(name, namespace, "inspect");
410
+ }
411
+ canQuery(name, namespace) {
412
+ return this.can(name, namespace, "query");
413
+ }
414
+ canUpsert(name, namespace) {
415
+ return this.can(name, namespace, "upsert");
416
+ }
417
+ canIngest(name, namespace) {
418
+ return this.can(name, namespace, "ingest");
419
+ }
420
+ canRecall(name, namespace) {
421
+ return this.can(name, namespace, "recall");
422
+ }
423
+ canOptimize(name, namespace) {
424
+ return this.can(name, namespace, "optimize");
425
+ }
426
+ canAccessExisting(name, namespace) {
427
+ return (this.canDrop(name, namespace)
428
+ || this.canInspect(name, namespace)
429
+ || this.canQuery(name, namespace)
430
+ || this.canUpsert(name, namespace)
431
+ || this.canIngest(name, namespace)
432
+ || this.canRecall(name, namespace)
433
+ || this.canOptimize(name, namespace));
434
+ }
435
+ toJSON() {
436
+ const json = {};
437
+ if (this.list !== true) {
438
+ json["list"] = this.list;
439
+ }
440
+ if (this.memories !== undefined) {
441
+ json["memories"] = this.memories.map((memoryGrant) => memoryGrant.toJSON());
442
+ }
443
+ return json;
444
+ }
445
+ static fromJSON(obj) {
446
+ if (!isRecord(obj)) {
447
+ return new MemoryGrant();
448
+ }
449
+ return new MemoryGrant({
450
+ list: obj.list,
451
+ memories: Array.isArray(obj.memories)
452
+ ? obj.memories.map((memoryGrant) => MemoryEntryGrant.fromJSON(memoryGrant))
453
+ : undefined,
454
+ });
81
455
  }
82
456
  }
83
457
  export class SyncPathGrant {
@@ -85,26 +459,67 @@ export class SyncPathGrant {
85
459
  this.path = path;
86
460
  this.readOnly = readOnly ?? false;
87
461
  }
462
+ toJSON() {
463
+ const json = {
464
+ path: this.path,
465
+ };
466
+ if (this.readOnly !== false) {
467
+ json["read_only"] = this.readOnly;
468
+ }
469
+ return json;
470
+ }
471
+ static fromJSON(obj) {
472
+ if (!isRecord(obj) || typeof obj.path !== "string") {
473
+ throw new Error("SyncPathGrant requires a path");
474
+ }
475
+ return new SyncPathGrant({
476
+ path: obj.path,
477
+ readOnly: obj.read_only ?? obj.readOnly,
478
+ });
479
+ }
88
480
  }
89
481
  export class SyncGrant {
90
482
  constructor({ paths } = {}) {
91
483
  this.paths = paths;
92
484
  }
93
- matches(p, path) {
94
- return p.path === path || (p.path.endsWith("*") && path.startsWith(p.path.slice(0, -1)));
485
+ matches(pathGrant, path) {
486
+ return pathGrant.path === path
487
+ || (pathGrant.path.endsWith("*")
488
+ && path.startsWith(pathGrant.path.slice(0, -1)));
95
489
  }
96
490
  canRead(path) {
97
- if (this.paths) {
98
- return this.paths.some(p => this.matches(p, path));
491
+ if (this.paths === undefined) {
492
+ return true;
99
493
  }
100
- return true;
494
+ return this.paths.some((pathGrant) => this.matches(pathGrant, path));
101
495
  }
102
496
  canWrite(path) {
103
- if (this.paths) {
104
- const p = this.paths.find(pp => this.matches(pp, path));
105
- return p ? !p.readOnly : false;
497
+ if (this.paths === undefined) {
498
+ return true;
106
499
  }
107
- return true;
500
+ for (const pathGrant of this.paths) {
501
+ if (this.matches(pathGrant, path)) {
502
+ return !pathGrant.readOnly;
503
+ }
504
+ }
505
+ return false;
506
+ }
507
+ toJSON() {
508
+ const json = {};
509
+ if (this.paths !== undefined) {
510
+ json["paths"] = this.paths.map((pathGrant) => pathGrant.toJSON());
511
+ }
512
+ return json;
513
+ }
514
+ static fromJSON(obj) {
515
+ if (!isRecord(obj)) {
516
+ return new SyncGrant();
517
+ }
518
+ return new SyncGrant({
519
+ paths: Array.isArray(obj.paths)
520
+ ? obj.paths.map((pathGrant) => SyncPathGrant.fromJSON(pathGrant))
521
+ : undefined,
522
+ });
108
523
  }
109
524
  }
110
525
  export class StoragePathGrant {
@@ -112,112 +527,516 @@ export class StoragePathGrant {
112
527
  this.path = path;
113
528
  this.readOnly = readOnly ?? false;
114
529
  }
530
+ toJSON() {
531
+ const json = {
532
+ path: this.path,
533
+ };
534
+ if (this.readOnly !== false) {
535
+ json["read_only"] = this.readOnly;
536
+ }
537
+ return json;
538
+ }
539
+ static fromJSON(obj) {
540
+ if (!isRecord(obj) || typeof obj.path !== "string") {
541
+ throw new Error("StoragePathGrant requires a path");
542
+ }
543
+ return new StoragePathGrant({
544
+ path: obj.path,
545
+ readOnly: obj.read_only ?? obj.readOnly,
546
+ });
547
+ }
115
548
  }
116
549
  export class StorageGrant {
117
550
  constructor({ paths } = {}) {
118
551
  this.paths = paths;
119
552
  }
120
- matches(p, path) {
121
- return path.startsWith(p.path);
122
- }
123
553
  canRead(path) {
124
- if (!this.paths)
554
+ if (this.paths === undefined) {
125
555
  return true;
126
- return this.paths.some(p => this.matches(p, path));
556
+ }
557
+ return this.paths.some((pathGrant) => path.startsWith(pathGrant.path));
127
558
  }
128
559
  canWrite(path) {
129
- if (!this.paths)
560
+ if (this.paths === undefined) {
130
561
  return true;
131
- const p = this.paths.find(pp => this.matches(pp, path));
132
- return p ? !p.readOnly : false;
562
+ }
563
+ for (const pathGrant of this.paths) {
564
+ if (path.startsWith(pathGrant.path)) {
565
+ return !pathGrant.readOnly;
566
+ }
567
+ }
568
+ return false;
569
+ }
570
+ toJSON() {
571
+ const json = {};
572
+ if (this.paths !== undefined) {
573
+ json["paths"] = this.paths.map((pathGrant) => pathGrant.toJSON());
574
+ }
575
+ return json;
576
+ }
577
+ static fromJSON(obj) {
578
+ if (!isRecord(obj)) {
579
+ return new StorageGrant();
580
+ }
581
+ return new StorageGrant({
582
+ paths: Array.isArray(obj.paths)
583
+ ? obj.paths.map((pathGrant) => StoragePathGrant.fromJSON(pathGrant))
584
+ : undefined,
585
+ });
586
+ }
587
+ }
588
+ export class ContainerRegistryGrant {
589
+ constructor({ list, pull, run, write, } = {}) {
590
+ this.list = list;
591
+ this.pull = pull;
592
+ this.run = run;
593
+ this.write = write;
594
+ }
595
+ canList(repository) {
596
+ if (this.list !== undefined) {
597
+ return matchesGrantPattern(this.list, repository, false);
598
+ }
599
+ if (this.pull === undefined && this.run === undefined && this.write === undefined) {
600
+ return true;
601
+ }
602
+ return [this.pull, this.run, this.write]
603
+ .filter((patterns) => patterns !== undefined)
604
+ .some((patterns) => matchesGrantPattern(patterns, repository, false));
605
+ }
606
+ canPull(repository) {
607
+ return matchesGrantPattern(this.pull, repository, true);
608
+ }
609
+ canRun(repository) {
610
+ return matchesGrantPattern(this.run, repository, true);
611
+ }
612
+ canWrite(repository) {
613
+ return matchesGrantPattern(this.write, repository, true);
614
+ }
615
+ toJSON() {
616
+ const json = {};
617
+ if (this.list !== undefined) {
618
+ json["list"] = this.list;
619
+ }
620
+ if (this.pull !== undefined) {
621
+ json["pull"] = this.pull;
622
+ }
623
+ if (this.run !== undefined) {
624
+ json["run"] = this.run;
625
+ }
626
+ if (this.write !== undefined) {
627
+ json["write"] = this.write;
628
+ }
629
+ return json;
630
+ }
631
+ static fromJSON(obj) {
632
+ if (!isRecord(obj)) {
633
+ return new ContainerRegistryGrant();
634
+ }
635
+ return new ContainerRegistryGrant({
636
+ list: asStringList(obj.list),
637
+ pull: asStringList(obj.pull),
638
+ run: asStringList(obj.run),
639
+ write: asStringList(obj.write),
640
+ });
133
641
  }
134
642
  }
135
643
  export class ContainersGrant {
136
- constructor({ logs, pull, run, useContainers } = {}) {
644
+ constructor({ logs, pull, run, registry, useContainers, } = {}) {
137
645
  this.logs = logs ?? true;
138
646
  this.pull = pull;
139
647
  this.run = run;
648
+ this.registry = registry;
140
649
  this.useContainers = useContainers ?? true;
141
650
  }
142
- match(list, tag) {
143
- if (!list) {
651
+ canPull(tag) {
652
+ return matchesGrantPattern(this.pull, tag, true);
653
+ }
654
+ canRun(tag) {
655
+ return matchesGrantPattern(this.run, tag, true);
656
+ }
657
+ canRegistryList(repository) {
658
+ if (this.registry === undefined) {
144
659
  return true;
145
660
  }
146
- return list.some(t => tag === t || tag.startsWith(t.endsWith("*") ? t.slice(0, -1) : t));
661
+ return this.registry.canList(repository);
147
662
  }
148
- canPull(tag) {
149
- return this.match(this.pull, tag);
663
+ canRegistryPull(repository) {
664
+ if (this.registry === undefined) {
665
+ return true;
666
+ }
667
+ return this.registry.canPull(repository);
150
668
  }
151
- canRun(tag) {
152
- return this.match(this.run, tag);
669
+ canRegistryRun(repository) {
670
+ if (this.registry === undefined) {
671
+ return true;
672
+ }
673
+ return this.registry.canRun(repository);
674
+ }
675
+ canRegistryWrite(repository) {
676
+ if (this.registry === undefined) {
677
+ return true;
678
+ }
679
+ return this.registry.canWrite(repository);
680
+ }
681
+ toJSON() {
682
+ const json = {};
683
+ if (this.logs !== true) {
684
+ json["logs"] = this.logs;
685
+ }
686
+ if (this.pull !== undefined) {
687
+ json["pull"] = this.pull;
688
+ }
689
+ if (this.run !== undefined) {
690
+ json["run"] = this.run;
691
+ }
692
+ if (this.registry !== undefined) {
693
+ json["registry"] = this.registry.toJSON();
694
+ }
695
+ if (this.useContainers !== true) {
696
+ json["use_containers"] = this.useContainers;
697
+ }
698
+ return json;
699
+ }
700
+ static fromJSON(obj) {
701
+ if (!isRecord(obj)) {
702
+ return new ContainersGrant();
703
+ }
704
+ return new ContainersGrant({
705
+ logs: obj.logs,
706
+ pull: asStringList(obj.pull),
707
+ run: asStringList(obj.run),
708
+ registry: obj.registry ? ContainerRegistryGrant.fromJSON(obj.registry) : undefined,
709
+ useContainers: obj.use_containers ?? obj.useContainers,
710
+ });
153
711
  }
154
712
  }
155
713
  export class DeveloperGrant {
156
714
  constructor({ logs } = {}) {
157
715
  this.logs = logs ?? true;
158
716
  }
717
+ toJSON() {
718
+ const json = {};
719
+ if (this.logs !== true) {
720
+ json["logs"] = this.logs;
721
+ }
722
+ return json;
723
+ }
724
+ static fromJSON(obj) {
725
+ if (!isRecord(obj)) {
726
+ return new DeveloperGrant();
727
+ }
728
+ return new DeveloperGrant({
729
+ logs: obj.logs,
730
+ });
731
+ }
159
732
  }
160
733
  export class AdminGrant {
734
+ constructor({ config } = {}) {
735
+ this.config = config ?? true;
736
+ }
737
+ toJSON() {
738
+ const json = {};
739
+ if (this.config !== true) {
740
+ json["config"] = this.config;
741
+ }
742
+ return json;
743
+ }
744
+ static fromJSON(obj) {
745
+ if (!isRecord(obj)) {
746
+ return new AdminGrant();
747
+ }
748
+ return new AdminGrant({
749
+ config: obj.config,
750
+ });
751
+ }
752
+ }
753
+ export class OAuthEndpoint {
754
+ constructor({ endpoint, clientId }) {
755
+ this.endpoint = endpoint;
756
+ this.clientId = clientId;
757
+ }
758
+ toJSON() {
759
+ return {
760
+ endpoint: this.endpoint,
761
+ client_id: this.clientId,
762
+ };
763
+ }
764
+ static fromJSON(obj) {
765
+ if (!isRecord(obj) || typeof obj.endpoint !== "string") {
766
+ throw new Error("OAuthEndpoint requires an endpoint");
767
+ }
768
+ const clientId = obj.client_id ?? obj.clientId;
769
+ if (typeof clientId !== "string") {
770
+ throw new Error("OAuthEndpoint requires a client_id");
771
+ }
772
+ return new OAuthEndpoint({
773
+ endpoint: obj.endpoint,
774
+ clientId,
775
+ });
776
+ }
161
777
  }
162
778
  export class SecretsGrant {
163
- canRequestOauthToken(authorizationEndpoint) {
164
- if (!this.requestOauthToken) {
779
+ constructor({ requestOauthToken } = {}) {
780
+ this.requestOauthToken = requestOauthToken;
781
+ }
782
+ canRequestOauthToken({ connector, oauth, } = {}) {
783
+ void connector;
784
+ if (this.requestOauthToken === undefined) {
165
785
  return true;
166
786
  }
167
- return this.requestOauthToken.some(t => t === authorizationEndpoint || ((t.endsWith("*") && authorizationEndpoint.startsWith(t.slice(0, -1)))));
787
+ const authorizationEndpoint = typeof oauth?.authorization_endpoint === "string"
788
+ ? oauth.authorization_endpoint.trim()
789
+ : "";
790
+ const clientId = typeof oauth?.client_id === "string"
791
+ ? oauth.client_id.trim()
792
+ : "";
793
+ if (authorizationEndpoint === "" || clientId === "") {
794
+ return false;
795
+ }
796
+ return this.requestOauthToken.some((endpointGrant) => ((endpointGrant.endpoint === authorizationEndpoint
797
+ || (endpointGrant.endpoint.endsWith("*")
798
+ && authorizationEndpoint.startsWith(endpointGrant.endpoint.slice(0, -1))))
799
+ && endpointGrant.clientId === clientId));
800
+ }
801
+ toJSON() {
802
+ const json = {};
803
+ if (this.requestOauthToken !== undefined) {
804
+ json["request_oauth_token"] = this.requestOauthToken.map((endpointGrant) => endpointGrant.toJSON());
805
+ }
806
+ return json;
807
+ }
808
+ static fromJSON(obj) {
809
+ if (!isRecord(obj)) {
810
+ return new SecretsGrant();
811
+ }
812
+ const requestOauthToken = obj.request_oauth_token ?? obj.requestOauthToken;
813
+ return new SecretsGrant({
814
+ requestOauthToken: Array.isArray(requestOauthToken)
815
+ ? requestOauthToken.map((endpointGrant) => OAuthEndpoint.fromJSON(endpointGrant))
816
+ : undefined,
817
+ });
818
+ }
819
+ }
820
+ export class TunnelsGrant {
821
+ constructor({ ports } = {}) {
822
+ this.ports = ports;
823
+ }
824
+ toJSON() {
825
+ const json = {};
826
+ if (this.ports !== undefined) {
827
+ json["ports"] = this.ports;
828
+ }
829
+ return json;
830
+ }
831
+ static fromJSON(obj) {
832
+ if (!isRecord(obj)) {
833
+ return new TunnelsGrant();
834
+ }
835
+ return new TunnelsGrant({
836
+ ports: asStringList(obj.ports),
837
+ });
838
+ }
839
+ }
840
+ export class ServicesGrant {
841
+ constructor({ list } = {}) {
842
+ this.list = list ?? true;
843
+ }
844
+ toJSON() {
845
+ const json = {};
846
+ if (this.list !== true) {
847
+ json["list"] = this.list;
848
+ }
849
+ return json;
850
+ }
851
+ static fromJSON(obj) {
852
+ if (!isRecord(obj)) {
853
+ return new ServicesGrant();
854
+ }
855
+ return new ServicesGrant({
856
+ list: obj.list,
857
+ });
858
+ }
859
+ }
860
+ export class LLMGrant {
861
+ constructor({ models } = {}) {
862
+ this.models = models;
863
+ }
864
+ canUseProvider(provider) {
865
+ const normalizedProvider = provider.trim();
866
+ if (normalizedProvider === "") {
867
+ return false;
868
+ }
869
+ if (!this.models) {
870
+ return true;
871
+ }
872
+ const prefix = `${normalizedProvider}/`;
873
+ return this.models.some((pattern) => pattern.trim().startsWith(prefix));
874
+ }
875
+ canUseModel(provider, model) {
876
+ const normalizedProvider = provider.trim();
877
+ const normalizedModel = model.trim();
878
+ if (normalizedProvider === "" || normalizedModel === "") {
879
+ return false;
880
+ }
881
+ return matchesGrantPattern(this.models, `${normalizedProvider}/${normalizedModel}`, true);
882
+ }
883
+ toJSON() {
884
+ const json = {};
885
+ if (this.models !== undefined) {
886
+ json["models"] = this.models;
887
+ }
888
+ return json;
889
+ }
890
+ static fromJSON(obj) {
891
+ if (!isRecord(obj)) {
892
+ return new LLMGrant();
893
+ }
894
+ return new LLMGrant({
895
+ models: asStringList(obj.models),
896
+ });
168
897
  }
169
898
  }
170
899
  export class ApiScope {
171
- constructor({ livekit, queues, messaging, database, sync, storage, containers, developer, agents, admin, secrets, } = {}) {
900
+ constructor({ livekit, queues, messaging, database, memory, sync, storage, containers, developer, agents, llm, admin, secrets, tunnels, services, } = {}) {
172
901
  this.livekit = livekit;
173
902
  this.queues = queues;
174
903
  this.messaging = messaging;
175
904
  this.database = database;
905
+ this.memory = memory;
176
906
  this.sync = sync;
177
907
  this.storage = storage;
178
908
  this.containers = containers;
179
909
  this.developer = developer;
180
910
  this.agents = agents;
911
+ this.llm = llm;
181
912
  this.admin = admin;
182
913
  this.secrets = secrets;
914
+ this.tunnels = tunnels;
915
+ this.services = services;
183
916
  }
184
- static agentDefault() {
185
- const s = new ApiScope();
186
- s.livekit = new LivekitGrant();
187
- s.queues = new QueuesGrant();
188
- s.messaging = new MessagingGrant();
189
- s.database = new DatabaseGrant();
190
- s.sync = new SyncGrant();
191
- s.storage = new StorageGrant();
192
- s.containers = new ContainersGrant();
193
- s.developer = new DeveloperGrant();
194
- s.agents = new AgentsGrant();
195
- return s;
917
+ static agentDefault({ tunnels = false } = {}) {
918
+ return new ApiScope({
919
+ livekit: new LivekitGrant(),
920
+ queues: new QueuesGrant(),
921
+ messaging: new MessagingGrant(),
922
+ database: new DatabaseGrant(),
923
+ memory: new MemoryGrant(),
924
+ sync: new SyncGrant(),
925
+ storage: new StorageGrant(),
926
+ containers: new ContainersGrant(),
927
+ developer: new DeveloperGrant(),
928
+ agents: new AgentsGrant(),
929
+ llm: new LLMGrant(),
930
+ secrets: new SecretsGrant(),
931
+ services: new ServicesGrant(),
932
+ tunnels: tunnels ? new TunnelsGrant() : undefined,
933
+ });
196
934
  }
197
935
  static userDefault() {
198
- const s = new ApiScope();
199
- s.livekit = new LivekitGrant();
200
- s.queues = new QueuesGrant();
201
- s.messaging = new MessagingGrant();
202
- s.database = new DatabaseGrant();
203
- s.sync = new SyncGrant();
204
- s.storage = new StorageGrant();
205
- s.containers = new ContainersGrant();
206
- s.developer = new DeveloperGrant();
207
- s.agents = new AgentsGrant();
208
- s.secrets = new SecretsGrant();
209
- return s;
936
+ return new ApiScope({
937
+ livekit: new LivekitGrant(),
938
+ queues: new QueuesGrant(),
939
+ messaging: new MessagingGrant(),
940
+ database: new DatabaseGrant(),
941
+ memory: new MemoryGrant(),
942
+ sync: new SyncGrant(),
943
+ storage: new StorageGrant(),
944
+ containers: new ContainersGrant(),
945
+ developer: new DeveloperGrant(),
946
+ agents: new AgentsGrant(),
947
+ secrets: new SecretsGrant(),
948
+ services: new ServicesGrant(),
949
+ });
210
950
  }
211
951
  static full() {
212
- const s = ApiScope.agentDefault();
213
- s.admin = new AdminGrant();
214
- return s;
952
+ return new ApiScope({
953
+ livekit: new LivekitGrant(),
954
+ queues: new QueuesGrant(),
955
+ messaging: new MessagingGrant(),
956
+ database: new DatabaseGrant(),
957
+ memory: new MemoryGrant(),
958
+ sync: new SyncGrant(),
959
+ storage: new StorageGrant(),
960
+ containers: new ContainersGrant(),
961
+ developer: new DeveloperGrant(),
962
+ agents: new AgentsGrant(),
963
+ llm: new LLMGrant(),
964
+ admin: new AdminGrant(),
965
+ secrets: new SecretsGrant(),
966
+ tunnels: new TunnelsGrant(),
967
+ services: new ServicesGrant(),
968
+ });
215
969
  }
216
970
  toJSON() {
217
- return { ...this };
971
+ const json = {};
972
+ if (this.livekit !== undefined) {
973
+ json["livekit"] = this.livekit.toJSON();
974
+ }
975
+ if (this.queues !== undefined) {
976
+ json["queues"] = this.queues.toJSON();
977
+ }
978
+ if (this.messaging !== undefined) {
979
+ json["messaging"] = this.messaging.toJSON();
980
+ }
981
+ if (this.database !== undefined) {
982
+ json["database"] = this.database.toJSON();
983
+ }
984
+ if (this.memory !== undefined) {
985
+ json["memory"] = this.memory.toJSON();
986
+ }
987
+ if (this.sync !== undefined) {
988
+ json["sync"] = this.sync.toJSON();
989
+ }
990
+ if (this.storage !== undefined) {
991
+ json["storage"] = this.storage.toJSON();
992
+ }
993
+ if (this.containers !== undefined) {
994
+ json["containers"] = this.containers.toJSON();
995
+ }
996
+ if (this.developer !== undefined) {
997
+ json["developer"] = this.developer.toJSON();
998
+ }
999
+ if (this.agents !== undefined) {
1000
+ json["agents"] = this.agents.toJSON();
1001
+ }
1002
+ if (this.llm !== undefined) {
1003
+ json["llm"] = this.llm.toJSON();
1004
+ }
1005
+ if (this.admin !== undefined) {
1006
+ json["admin"] = this.admin.toJSON();
1007
+ }
1008
+ if (this.secrets !== undefined) {
1009
+ json["secrets"] = this.secrets.toJSON();
1010
+ }
1011
+ if (this.tunnels !== undefined) {
1012
+ json["tunnels"] = this.tunnels.toJSON();
1013
+ }
1014
+ if (this.services !== undefined) {
1015
+ json["services"] = this.services.toJSON();
1016
+ }
1017
+ return json;
218
1018
  }
219
1019
  static fromJSON(obj) {
220
- return Object.assign(new ApiScope(), obj);
1020
+ if (!isRecord(obj)) {
1021
+ return new ApiScope();
1022
+ }
1023
+ return new ApiScope({
1024
+ livekit: obj.livekit ? LivekitGrant.fromJSON(obj.livekit) : undefined,
1025
+ queues: obj.queues ? QueuesGrant.fromJSON(obj.queues) : undefined,
1026
+ messaging: obj.messaging ? MessagingGrant.fromJSON(obj.messaging) : undefined,
1027
+ database: obj.database ? DatabaseGrant.fromJSON(obj.database) : undefined,
1028
+ memory: obj.memory ? MemoryGrant.fromJSON(obj.memory) : undefined,
1029
+ sync: obj.sync ? SyncGrant.fromJSON(obj.sync) : undefined,
1030
+ storage: obj.storage ? StorageGrant.fromJSON(obj.storage) : undefined,
1031
+ containers: obj.containers ? ContainersGrant.fromJSON(obj.containers) : undefined,
1032
+ developer: obj.developer ? DeveloperGrant.fromJSON(obj.developer) : undefined,
1033
+ agents: obj.agents ? AgentsGrant.fromJSON(obj.agents) : undefined,
1034
+ llm: obj.llm ? LLMGrant.fromJSON(obj.llm) : undefined,
1035
+ admin: obj.admin ? AdminGrant.fromJSON(obj.admin) : undefined,
1036
+ secrets: obj.secrets ? SecretsGrant.fromJSON(obj.secrets) : undefined,
1037
+ tunnels: obj.tunnels ? TunnelsGrant.fromJSON(obj.tunnels) : undefined,
1038
+ services: obj.services ? ServicesGrant.fromJSON(obj.services) : undefined,
1039
+ });
221
1040
  }
222
1041
  }
223
1042
  export class ParticipantGrant {
@@ -250,12 +1069,14 @@ export class ParticipantGrant {
250
1069
  }
251
1070
  }
252
1071
  function compareSemver(a, b) {
253
- const pa = a.split(".").map(n => parseInt(n, 10));
254
- const pb = b.split(".").map(n => parseInt(n, 10));
255
- for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
256
- const x = pa[i] || 0, y = pb[i] || 0;
257
- if (x !== y)
258
- return x - y;
1072
+ const pa = a.split(".").map((value) => parseInt(value, 10));
1073
+ const pb = b.split(".").map((value) => parseInt(value, 10));
1074
+ for (let index = 0; index < Math.max(pa.length, pb.length); index += 1) {
1075
+ const left = pa[index] || 0;
1076
+ const right = pb[index] || 0;
1077
+ if (left !== right) {
1078
+ return left - right;
1079
+ }
259
1080
  }
260
1081
  return 0;
261
1082
  }
@@ -264,14 +1085,14 @@ export class ParticipantToken {
264
1085
  this.name = name;
265
1086
  this.projectId = projectId;
266
1087
  this.apiKeyId = apiKeyId;
267
- this.version = version;
1088
+ this.version = version ?? __version__;
268
1089
  this.extra = extra ?? {};
269
1090
  this.grants = grants ?? [];
270
1091
  }
271
1092
  get role() {
272
- for (const g of this.grants) {
273
- if (g.name === "role" && g.scope !== "user") {
274
- return String(g.scope);
1093
+ for (const grant of this.grants) {
1094
+ if (grant.name === "role" && grant.scope !== "user") {
1095
+ return String(grant.scope);
275
1096
  }
276
1097
  }
277
1098
  return "user";
@@ -293,8 +1114,10 @@ export class ParticipantToken {
293
1114
  return true;
294
1115
  }
295
1116
  addTunnelGrant(ports) {
296
- const portsStr = ports.join(",");
297
- this.grants.push(new ParticipantGrant({ name: "tunnel_ports", scope: portsStr }));
1117
+ this.grants.push(new ParticipantGrant({
1118
+ name: "tunnel_ports",
1119
+ scope: ports.join(","),
1120
+ }));
298
1121
  }
299
1122
  addRoleGrant(role) {
300
1123
  this.grants.push(new ParticipantGrant({ name: "role", scope: role }));
@@ -303,132 +1126,113 @@ export class ParticipantToken {
303
1126
  this.grants.push(new ParticipantGrant({ name: "room", scope: roomName }));
304
1127
  }
305
1128
  addApiGrant(grant) {
1129
+ for (const existingGrant of this.grants) {
1130
+ if (existingGrant.name === "api") {
1131
+ throw new Error("can only have a single api grant");
1132
+ }
1133
+ }
306
1134
  this.grants.push(new ParticipantGrant({ name: "api", scope: grant }));
307
1135
  }
308
1136
  grantScope(name) {
309
- return this.grants.find(g => g.name === name)?.scope;
1137
+ return this.grants.find((grant) => grant.name === name)?.scope;
310
1138
  }
311
1139
  getApiGrant() {
312
- const api = this.grantScope("api");
313
- if (api && typeof api !== "string") {
314
- return api;
315
- }
316
- if (this.version && compareSemver(this.version, "0.6.0") < 0 && !api) {
317
- return new ApiScope({
318
- livekit: new LivekitGrant(),
319
- queues: new QueuesGrant(),
320
- messaging: new MessagingGrant(),
321
- database: new DatabaseGrant(),
322
- sync: new SyncGrant(),
323
- storage: new StorageGrant(),
324
- agents: new AgentsGrant(),
325
- developer: new DeveloperGrant(),
326
- });
1140
+ const apiGrant = this.grantScope("api");
1141
+ if (apiGrant && typeof apiGrant !== "string") {
1142
+ return apiGrant;
327
1143
  }
328
- return api;
1144
+ return undefined;
329
1145
  }
330
1146
  toJson() {
331
- const base = {
1147
+ const json = {
1148
+ ...(this.extra ?? {}),
332
1149
  name: this.name,
333
- grants: this.grants.map(g => g.toJson()),
1150
+ grants: this.grants.map((grant) => grant.toJson()),
334
1151
  };
335
- if (this.projectId) {
336
- base["sub"] = this.projectId;
1152
+ if (this.projectId !== undefined) {
1153
+ json["sub"] = this.projectId;
337
1154
  }
338
- if (this.apiKeyId) {
339
- base["kid"] = this.apiKeyId;
1155
+ if (this.apiKeyId !== undefined) {
1156
+ json["kid"] = this.apiKeyId;
340
1157
  }
341
- if (this.version) {
342
- base["version"] = this.version;
1158
+ if (this.version !== undefined) {
1159
+ json["version"] = this.version;
343
1160
  }
344
- return base;
1161
+ return json;
345
1162
  }
346
- async toJwt({ token, expiration, apiKey } = {}) {
347
- let apiGrant = null;
348
- for (const g of this.grants) {
349
- if (g.name === "api") {
350
- apiGrant = g;
351
- break;
352
- }
1163
+ async toJwt({ token, expiration, apiKey, } = {}) {
1164
+ const apiGrant = this.grants.find((grant) => grant.name === "api");
1165
+ if (!apiGrant && compareSemver(this.version, "0.3.5") > 0) {
1166
+ console.warn("there is no ApiScope in the participant token, this participant will not be able to make calls to the the room API. Use addApiGrant to add an ApiScope to this token.");
353
1167
  }
354
- if (!apiGrant && this.version && compareSemver(this.version, "0.5.3") >= 0) {
355
- console.error("ParticipantToken.toJwt: No API grant found, but version is >= 0.5.3. " +
356
- "This may cause issues with older clients that expect an API grant.");
357
- }
358
- let resolvedSecret = token;
359
- let resolvedKid = this.apiKeyId;
360
- let resolvedSub = this.projectId;
361
- const apiKeyValue = apiKey ?? getEnvValue("MESHAGENT_API_KEY");
362
- if (apiKeyValue) {
363
- const parsed = parseApiKey(apiKeyValue);
364
- resolvedSecret ?? (resolvedSecret = parsed.secret);
365
- resolvedKid = parsed.id;
366
- resolvedSub = parsed.projectId;
367
- }
368
- let usingDefaultSecret = false;
369
- if (!resolvedSecret) {
370
- const envSecret = getEnvValue("MESHAGENT_SECRET");
371
- if (!envSecret) {
372
- throw new Error("ParticipantToken.toJwt: No secret provided. Pass `token`, `apiKey`, or set MESHAGENT_SECRET / MESHAGENT_API_KEY.");
373
- }
374
- resolvedSecret = envSecret;
375
- usingDefaultSecret = true;
376
- }
377
- const secretKey = new TextEncoder().encode(resolvedSecret);
378
1168
  const payload = this.toJson();
379
- if (resolvedSub) {
380
- payload["sub"] = resolvedSub;
381
- }
382
- else {
383
- delete payload["sub"];
1169
+ const resolvedApiKey = apiKey ?? getEnvValue("MESHAGENT_API_KEY");
1170
+ let resolvedSecret = token;
1171
+ if (resolvedApiKey !== undefined) {
1172
+ const parsed = parseApiKey(resolvedApiKey);
1173
+ resolvedSecret = parsed.secret;
1174
+ payload["kid"] = parsed.id;
1175
+ payload["sub"] = parsed.projectId;
384
1176
  }
385
- if (usingDefaultSecret) {
1177
+ else if (resolvedSecret === undefined) {
386
1178
  delete payload["kid"];
387
1179
  }
388
- else if (resolvedKid) {
389
- payload["kid"] = resolvedKid;
1180
+ if (resolvedSecret === undefined) {
1181
+ resolvedSecret = getEnvValue("MESHAGENT_SECRET");
390
1182
  }
391
- else {
392
- delete payload["kid"];
1183
+ if (resolvedSecret === undefined) {
1184
+ throw new Error("ParticipantToken.toJwt: No secret provided. Pass `token`, `apiKey`, or set MESHAGENT_SECRET / MESHAGENT_API_KEY.");
393
1185
  }
394
- if (expiration) {
1186
+ if (expiration !== undefined) {
395
1187
  payload.exp = Math.floor(expiration.getTime() / 1000);
396
1188
  }
397
- const jwt = new SignJWT(payload)
398
- .setProtectedHeader({ alg: "HS256", typ: "JWT" });
399
- const jwtToken = await jwt.sign(secretKey);
400
- return jwtToken;
1189
+ const secretKey = new TextEncoder().encode(resolvedSecret);
1190
+ return await new SignJWT(payload)
1191
+ .setProtectedHeader({ alg: "HS256", typ: "JWT" })
1192
+ .sign(secretKey);
401
1193
  }
402
1194
  static fromJson(json) {
403
- const { name, sub, grants, kid, version, ...rest } = json;
404
- const extra = { ...rest };
405
- const v = version ? version : "0.5.3";
1195
+ const data = { ...json };
1196
+ if (typeof data.name !== "string") {
1197
+ throw new Error(`Participant token does not have a name ${JSON.stringify(json)}`);
1198
+ }
1199
+ const name = data.name;
1200
+ delete data.name;
1201
+ const grantsRaw = Array.isArray(data.grants) ? data.grants : [];
1202
+ delete data.grants;
1203
+ const projectId = typeof data.sub === "string" ? data.sub : undefined;
1204
+ delete data.sub;
1205
+ const apiKeyId = typeof data.kid === "string" ? data.kid : undefined;
1206
+ delete data.kid;
1207
+ const version = typeof data.version === "string" ? data.version : __version__;
1208
+ delete data.version;
406
1209
  return new ParticipantToken({
407
- name: name,
408
- projectId: sub,
409
- apiKeyId: kid,
410
- version: v,
411
- grants: grants?.map((g) => ParticipantGrant.fromJson(g)),
412
- extra,
1210
+ name,
1211
+ projectId,
1212
+ apiKeyId,
1213
+ grants: grantsRaw.map((grant) => ParticipantGrant.fromJson(grant)),
1214
+ extra: data,
1215
+ version,
413
1216
  });
414
1217
  }
415
1218
  static async fromJwt(jwtStr, options = {}) {
416
- const { token, verify = true } = options ?? {};
1219
+ const { token, verify = true } = options;
417
1220
  if (verify) {
418
- const secretKey = new TextEncoder().encode(token);
1221
+ const verificationToken = token ?? getEnvValue("MESHAGENT_SECRET");
1222
+ if (verificationToken === undefined) {
1223
+ throw new Error("Failed to verify JWT: no token provided");
1224
+ }
1225
+ const secretKey = new TextEncoder().encode(verificationToken);
419
1226
  const { payload } = await jwtVerify(jwtStr, secretKey, {
420
1227
  algorithms: ["HS256"],
421
1228
  });
422
1229
  return ParticipantToken.fromJson(payload);
423
1230
  }
424
- else {
425
- try {
426
- const payload = decodeJwt(jwtStr);
427
- return ParticipantToken.fromJson(payload);
428
- }
429
- catch (err) {
430
- throw new Error("Failed to decode JWT");
431
- }
1231
+ try {
1232
+ return ParticipantToken.fromJson(decodeJwt(jwtStr));
1233
+ }
1234
+ catch {
1235
+ throw new Error("Failed to decode JWT");
432
1236
  }
433
1237
  }
434
1238
  }