@meshagent/meshagent 0.44.13 → 0.45.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/browser/index.d.ts +1 -1
  3. package/dist/browser/index.js +1 -1
  4. package/dist/browser/meshagent-client.d.ts +390 -372
  5. package/dist/browser/meshagent-client.js +841 -1040
  6. package/dist/browser/oauth-scopes.d.ts +1 -1
  7. package/dist/browser/oauth-scopes.js +64 -14
  8. package/dist/browser/participant-token.d.ts +68 -20
  9. package/dist/browser/participant-token.js +232 -61
  10. package/dist/browser/room-client.d.ts +4 -8
  11. package/dist/browser/room-client.js +4 -10
  12. package/dist/browser/services-client.d.ts +11 -0
  13. package/dist/browser/services-client.js +17 -0
  14. package/dist/browser/sqlite-client.d.ts +326 -0
  15. package/dist/browser/sqlite-client.js +630 -0
  16. package/dist/browser/toolkit-config.d.ts +7 -1
  17. package/dist/browser/toolkit-config.js +41 -22
  18. package/dist/esm/index.d.ts +1 -1
  19. package/dist/esm/index.js +1 -1
  20. package/dist/esm/meshagent-client.d.ts +390 -372
  21. package/dist/esm/meshagent-client.js +841 -1038
  22. package/dist/esm/oauth-scopes.d.ts +1 -1
  23. package/dist/esm/oauth-scopes.js +64 -14
  24. package/dist/esm/participant-token.d.ts +68 -20
  25. package/dist/esm/participant-token.js +228 -59
  26. package/dist/esm/room-client.d.ts +4 -8
  27. package/dist/esm/room-client.js +4 -10
  28. package/dist/esm/services-client.d.ts +11 -0
  29. package/dist/esm/services-client.js +17 -0
  30. package/dist/esm/sqlite-client.d.ts +326 -0
  31. package/dist/esm/sqlite-client.js +625 -0
  32. package/dist/esm/toolkit-config.d.ts +7 -1
  33. package/dist/esm/toolkit-config.js +41 -22
  34. package/dist/node/index.d.ts +1 -1
  35. package/dist/node/index.js +1 -1
  36. package/dist/node/meshagent-client.d.ts +390 -372
  37. package/dist/node/meshagent-client.js +841 -1040
  38. package/dist/node/oauth-scopes.d.ts +1 -1
  39. package/dist/node/oauth-scopes.js +64 -14
  40. package/dist/node/participant-token.d.ts +68 -20
  41. package/dist/node/participant-token.js +232 -61
  42. package/dist/node/room-client.d.ts +4 -8
  43. package/dist/node/room-client.js +4 -10
  44. package/dist/node/services-client.d.ts +11 -0
  45. package/dist/node/services-client.js +17 -0
  46. package/dist/node/sqlite-client.d.ts +326 -0
  47. package/dist/node/sqlite-client.js +630 -0
  48. package/dist/node/toolkit-config.d.ts +7 -1
  49. package/dist/node/toolkit-config.js +41 -22
  50. package/package.json +1 -1
  51. package/dist/browser/secrets-client.d.ts +0 -112
  52. package/dist/browser/secrets-client.js +0 -300
  53. package/dist/esm/secrets-client.d.ts +0 -112
  54. package/dist/esm/secrets-client.js +0 -296
  55. package/dist/node/secrets-client.d.ts +0 -112
  56. package/dist/node/secrets-client.js +0 -300
@@ -1,7 +1,5 @@
1
1
  import { meshagentBaseUrl } from "./helpers.js";
2
2
  import { ForbiddenException, RoomException } from "./requirement.js";
3
- import { ApiScope } from "./participant-token.js";
4
- import { decoder, encoder } from "./utils.js";
5
3
  export class RoomSession {
6
4
  constructor({ id, roomId, roomName, createdAt, isActive, participants, kind = "room", agentId, agentName, }) {
7
5
  this.id = id;
@@ -27,226 +25,75 @@ export class RoomSession {
27
25
  };
28
26
  }
29
27
  }
30
- function cloneJsonValue(value) {
31
- if (Array.isArray(value)) {
32
- return value.map((item) => cloneJsonValue(item));
33
- }
34
- if (value != null && typeof value === "object") {
35
- const result = {};
36
- for (const [key, item] of Object.entries(value)) {
37
- result[key] = cloneJsonValue(item);
38
- }
39
- return result;
40
- }
41
- return value;
42
- }
43
- function formatTemplateString(value, values) {
44
- return value.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (token, key) => values[key] ?? token);
45
- }
46
- function formatJsonValue(value, values) {
28
+ function applyTemplateValues(value, values) {
47
29
  if (typeof value === "string") {
48
- return formatTemplateString(value, values);
30
+ return Object.entries(values).reduce((current, [key, replacement]) => current.split(`{${key}}`).join(replacement), value);
49
31
  }
50
32
  if (Array.isArray(value)) {
51
- return value.map((item) => formatJsonValue(item, values));
33
+ return value.map((item) => applyTemplateValues(item, values));
52
34
  }
53
- if (value != null && typeof value === "object") {
35
+ if (value !== null && typeof value === "object") {
54
36
  const result = {};
55
- for (const [key, item] of Object.entries(value)) {
56
- result[key] = formatJsonValue(item, values);
37
+ for (const [key, entry] of Object.entries(value)) {
38
+ result[key] = applyTemplateValues(entry, values);
57
39
  }
58
40
  return result;
59
41
  }
60
42
  return value;
61
43
  }
62
- function objectOrUndefined(value) {
63
- return value != null && typeof value === "object" && !Array.isArray(value)
64
- ? value
65
- : undefined;
66
- }
67
- function objectArray(value) {
68
- return Array.isArray(value)
69
- ? value.filter((item) => objectOrUndefined(item) !== undefined)
70
- : undefined;
71
- }
72
- function stringValue(value) {
73
- return typeof value === "string" ? value : undefined;
74
- }
75
- function booleanValue(value) {
76
- return typeof value === "boolean" ? value : undefined;
77
- }
78
- function normalizeRoomMount(value) {
79
- return {
80
- path: stringValue(value.path) ?? "",
81
- ...(stringValue(value.subpath) !== undefined ? { subpath: stringValue(value.subpath) } : {}),
82
- ...(booleanValue(value.read_only) !== undefined ? { read_only: booleanValue(value.read_only) } : {}),
83
- };
84
- }
85
- function normalizeProjectMount(value) {
86
- return {
87
- path: stringValue(value.path) ?? "",
88
- ...(stringValue(value.subpath) !== undefined ? { subpath: stringValue(value.subpath) } : {}),
89
- read_only: booleanValue(value.read_only) ?? true,
90
- };
91
- }
92
- function normalizeImageMount(value) {
93
- return {
94
- path: stringValue(value.path) ?? "",
95
- ...(stringValue(value.subpath) !== undefined ? { subpath: stringValue(value.subpath) } : {}),
96
- read_only: booleanValue(value.read_only) ?? true,
97
- image: stringValue(value.image) ?? "",
98
- };
99
- }
100
- function normalizeFileMount(value) {
101
- return {
102
- path: stringValue(value.path) ?? "",
103
- ...(stringValue(value.subpath) !== undefined ? { subpath: stringValue(value.subpath) } : {}),
104
- read_only: booleanValue(value.read_only) ?? true,
105
- text: stringValue(value.text) ?? "",
106
- };
107
- }
108
- function normalizeEmptyDirMount(value) {
109
- return {
110
- path: stringValue(value.path) ?? "",
111
- read_only: booleanValue(value.read_only) ?? false,
112
- };
113
- }
114
- function normalizeConfigMount(value) {
115
- return {
116
- path: stringValue(value.path) ?? "/var/run/meshagent",
117
- };
118
- }
119
- function normalizeContainerMountSpec(value) {
120
- const source = objectOrUndefined(value) ?? {};
121
- const room = objectArray(source.room)?.map(normalizeRoomMount);
122
- const project = objectArray(source.project)?.map(normalizeProjectMount);
123
- const images = objectArray(source.images)?.map(normalizeImageMount);
124
- const files = objectArray(source.files)?.map(normalizeFileMount);
125
- const emptyDirs = objectArray(source.empty_dirs)?.map(normalizeEmptyDirMount);
126
- const configs = objectArray(source.configs)?.map(normalizeConfigMount);
127
- return {
128
- ...(room !== undefined ? { room } : {}),
129
- ...(project !== undefined ? { project } : {}),
130
- ...(images !== undefined ? { images } : {}),
131
- ...(files !== undefined ? { files } : {}),
132
- ...(emptyDirs !== undefined ? { empty_dirs: emptyDirs } : {}),
133
- ...(configs !== undefined ? { configs } : {}),
134
- };
135
- }
136
- function normalizeAgentSpec(agent, values) {
137
- const formatted = formatJsonValue(agent, values);
138
- const spec = cloneJsonValue(formatted);
139
- if (spec.email != null && spec.email.public == null) {
140
- spec.email = { ...spec.email, public: false };
141
- }
142
- if (spec.channels?.email) {
143
- spec.channels = {
144
- ...spec.channels,
145
- email: spec.channels.email.map((channel) => ({
146
- ...channel,
147
- private: channel.private ?? false,
148
- })),
149
- };
150
- }
151
- if (spec.channels?.messaging) {
152
- spec.channels = {
153
- ...spec.channels,
154
- messaging: spec.channels.messaging.map((channel) => ({
155
- ...channel,
156
- protocol: channel.protocol ?? "meshagent.agent-message.v1",
157
- })),
158
- };
159
- }
160
- return spec;
161
- }
162
- export function normalizeServiceSpec(service) {
163
- const normalized = cloneJsonValue(service);
164
- if (normalized.container?.storage != null) {
165
- normalized.container = {
166
- ...normalized.container,
167
- storage: normalizeContainerMountSpec(normalized.container.storage),
44
+ function normalizeServiceSpec(service) {
45
+ const storage = service.container?.storage;
46
+ const agents = service.agents?.map((agent) => ({
47
+ ...agent,
48
+ email: agent.email == null
49
+ ? agent.email
50
+ : {
51
+ ...agent.email,
52
+ public: agent.email.public ?? false,
53
+ },
54
+ channels: agent.channels == null
55
+ ? agent.channels
56
+ : {
57
+ ...agent.channels,
58
+ messaging: agent.channels.messaging?.map((channel) => ({
59
+ ...channel,
60
+ protocol: channel.protocol ?? "meshagent.agent-message.v1",
61
+ })),
62
+ },
63
+ }));
64
+ const container = service.container == null
65
+ ? service.container
66
+ : {
67
+ ...service.container,
68
+ storage: storage == null
69
+ ? storage
70
+ : {
71
+ ...storage,
72
+ configs: storage.configs?.map((config) => ({
73
+ ...config,
74
+ path: config.path ?? "/var/run/meshagent",
75
+ })),
76
+ files: storage.files?.map((file) => ({
77
+ ...file,
78
+ read_only: file.read_only ?? true,
79
+ })),
80
+ },
168
81
  };
169
- }
170
- return normalized;
82
+ return { ...service, agents, container };
171
83
  }
172
84
  export class ServiceTemplateSpec {
173
- constructor({ version = "v1", kind = "ServiceTemplate", variables, metadata, ports = [], container, external, agents = [], }) {
174
- this.version = version;
175
- this.kind = kind;
176
- this.variables = variables;
177
- this.metadata = metadata;
178
- this.ports = ports;
179
- this.container = container;
180
- this.external = external;
181
- this.agents = agents;
85
+ constructor(template) {
86
+ this.template = template;
182
87
  }
183
88
  static fromJson(json) {
184
- const metadata = objectOrUndefined(json.metadata);
185
- if (metadata === undefined || typeof metadata.name !== "string") {
186
- throw new RoomException("Invalid service template payload: missing metadata.name");
187
- }
188
- return new ServiceTemplateSpec({
189
- version: stringValue(json.version) ?? "v1",
190
- kind: stringValue(json.kind) ?? "ServiceTemplate",
191
- variables: objectArray(json.variables),
192
- metadata: cloneJsonValue(metadata),
193
- ports: (objectArray(json.ports) ?? []),
194
- container: objectOrUndefined(json.container),
195
- external: objectOrUndefined(json.external),
196
- agents: objectArray(json.agents) ?? [],
197
- });
198
- }
199
- toJson() {
200
- return {
201
- version: this.version,
202
- kind: this.kind,
203
- ...(this.variables != null ? { variables: cloneJsonValue(this.variables) } : {}),
204
- metadata: cloneJsonValue(this.metadata),
205
- ...(this.ports.length > 0 ? { ports: cloneJsonValue(this.ports) } : {}),
206
- ...(this.container != null ? { container: cloneJsonValue(this.container) } : {}),
207
- ...(this.external != null ? { external: cloneJsonValue(this.external) } : {}),
208
- ...(this.agents.length > 0 ? { agents: cloneJsonValue(this.agents) } : {}),
209
- };
89
+ return new ServiceTemplateSpec(json);
210
90
  }
211
91
  toServiceSpec({ values = {} } = {}) {
212
- const service = {
213
- version: "v1",
92
+ const templated = applyTemplateValues(this.template, values);
93
+ return normalizeServiceSpec({
94
+ ...templated,
214
95
  kind: "Service",
215
- metadata: cloneJsonValue(this.metadata),
216
- agents: this.agents.map((agent) => normalizeAgentSpec(agent, values)),
217
- ports: cloneJsonValue(this.ports),
218
- };
219
- if (this.container != null) {
220
- const formattedContainer = formatJsonValue(this.container, values);
221
- const image = stringValue(formattedContainer.image);
222
- if (image === undefined || image.length === 0) {
223
- throw new RoomException("ServiceTemplateSpec.image is required to build a ServiceSpec");
224
- }
225
- service.container = {
226
- ...(booleanValue(formattedContainer.private) !== undefined ? { private: booleanValue(formattedContainer.private) } : {}),
227
- ...(stringValue(formattedContainer.command) !== undefined ? { command: stringValue(formattedContainer.command) } : {}),
228
- ...(stringValue(formattedContainer.working_dir) !== undefined ? { working_dir: stringValue(formattedContainer.working_dir) } : {}),
229
- image,
230
- ...(Array.isArray(formattedContainer.environment)
231
- ? { environment: formattedContainer.environment }
232
- : {}),
233
- ...(objectOrUndefined(formattedContainer.storage) !== undefined
234
- ? { storage: normalizeContainerMountSpec(formattedContainer.storage) }
235
- : {}),
236
- ...(booleanValue(formattedContainer.on_demand) !== undefined ? { on_demand: booleanValue(formattedContainer.on_demand) } : {}),
237
- ...(booleanValue(formattedContainer.writable_root_fs) !== undefined
238
- ? { writable_root_fs: booleanValue(formattedContainer.writable_root_fs) }
239
- : {}),
240
- };
241
- }
242
- if (this.external != null) {
243
- const formattedExternal = formatJsonValue(this.external, values);
244
- const url = stringValue(formattedExternal.url);
245
- if (url !== undefined) {
246
- service.external = { url };
247
- }
248
- }
249
- return normalizeServiceSpec(service);
96
+ });
250
97
  }
251
98
  }
252
99
  function pruneUndefinedValues(value) {
@@ -271,28 +118,62 @@ function pruneUndefinedValues(value) {
271
118
  }
272
119
  return value;
273
120
  }
274
- function pruneNullishValues(value) {
275
- if (Array.isArray(value)) {
276
- return value
277
- .map((item) => pruneNullishValues(item))
278
- .filter((item) => item !== undefined);
121
+ function validateServiceSpec(service) {
122
+ const container = service.container;
123
+ if (container == null) {
124
+ return;
279
125
  }
280
- if (value === null || value === undefined) {
281
- return undefined;
126
+ if (typeof container.run_as === "string") {
127
+ throw new Error("container.run_as must be an object with an email field");
282
128
  }
283
- if (typeof value === "object") {
284
- const result = {};
285
- for (const [key, entryValue] of Object.entries(value)) {
286
- const normalized = pruneNullishValues(entryValue);
287
- if (normalized !== undefined) {
288
- result[key] = normalized;
289
- }
129
+ const environment = container.environment ?? [];
130
+ const hasSecretEnvironment = environment.some((entry) => entry.secret != null);
131
+ if (hasSecretEnvironment && container.run_as == null) {
132
+ throw new Error("container.run_as is required when using SecretValue");
133
+ }
134
+ for (const entry of environment) {
135
+ const secret = entry.secret;
136
+ if (secret == null) {
137
+ continue;
138
+ }
139
+ const unsupportedFields = Object.keys(secret).filter((key) => key !== "id");
140
+ if (unsupportedFields.length > 0) {
141
+ throw new Error(`unsupported SecretValue fields: ${unsupportedFields.join(", ")}`);
290
142
  }
291
- return result;
292
143
  }
293
- return value;
144
+ const pullSecret = container.pull_secret;
145
+ if (pullSecret != null) {
146
+ const unsupportedFields = Object.keys(pullSecret).filter((key) => key !== "id");
147
+ if (unsupportedFields.length > 0) {
148
+ throw new Error(`unsupported SecretValue fields: ${unsupportedFields.join(", ")}`);
149
+ }
150
+ }
151
+ }
152
+ const defaultServiceRunAsScopes = ["secrets:proxy"];
153
+ function normalizeServiceRunAs(runAs) {
154
+ if (runAs == null) {
155
+ return runAs;
156
+ }
157
+ const email = runAs.email.trim().toLowerCase();
158
+ if (email.length === 0) {
159
+ throw new Error("container.run_as.email is required");
160
+ }
161
+ const scopes = runAs.scopes == null ? defaultServiceRunAsScopes : runAs.scopes;
162
+ const normalizedScopes = [];
163
+ for (const scope of scopes) {
164
+ const normalized = scope.trim();
165
+ if (normalized.length === 0 || normalizedScopes.includes(normalized)) {
166
+ continue;
167
+ }
168
+ normalizedScopes.push(normalized);
169
+ }
170
+ return {
171
+ email,
172
+ scopes: normalizedScopes.length === 0 ? [...defaultServiceRunAsScopes] : normalizedScopes,
173
+ };
294
174
  }
295
175
  function serializeServiceSpec(service) {
176
+ validateServiceSpec(service);
296
177
  const agents = service.agents?.map((agent) => ({
297
178
  ...agent,
298
179
  channels: agent.channels == null
@@ -305,8 +186,15 @@ function serializeServiceSpec(service) {
305
186
  })),
306
187
  },
307
188
  }));
189
+ const container = service.container == null
190
+ ? service.container
191
+ : {
192
+ ...service.container,
193
+ run_as: normalizeServiceRunAs(service.container.run_as),
194
+ };
308
195
  return pruneUndefinedValues({
309
196
  ...service,
197
+ container,
310
198
  agents,
311
199
  });
312
200
  }
@@ -315,45 +203,6 @@ function serializeCreateServiceSpec(service) {
315
203
  delete payload.id;
316
204
  return payload;
317
205
  }
318
- export class ManagedAgentGrant {
319
- constructor({ admin = false } = {}) {
320
- this.admin = admin;
321
- }
322
- static fromJson(json) {
323
- return new ManagedAgentGrant({ admin: json["admin"] === true });
324
- }
325
- toJson() {
326
- return { admin: this.admin };
327
- }
328
- }
329
- const globalScope = globalThis;
330
- function bytesToBase64(bytes) {
331
- if (globalScope.Buffer) {
332
- return globalScope.Buffer.from(bytes).toString("base64");
333
- }
334
- if (!globalScope.btoa) {
335
- throw new Error("base64 encoding is not available in this runtime");
336
- }
337
- let binary = "";
338
- for (const byte of bytes) {
339
- binary += String.fromCharCode(byte);
340
- }
341
- return globalScope.btoa(binary);
342
- }
343
- function base64ToBytes(base64) {
344
- if (globalScope.Buffer) {
345
- return Uint8Array.from(globalScope.Buffer.from(base64, "base64"));
346
- }
347
- if (!globalScope.atob) {
348
- throw new Error("base64 decoding is not available in this runtime");
349
- }
350
- const binary = globalScope.atob(base64);
351
- const bytes = new Uint8Array(binary.length);
352
- for (let index = 0; index < binary.length; index += 1) {
353
- bytes[index] = binary.charCodeAt(index);
354
- }
355
- return bytes;
356
- }
357
206
  function toFetchBody(body) {
358
207
  if (body == null) {
359
208
  return undefined;
@@ -365,11 +214,16 @@ function toFetchBody(body) {
365
214
  copy.set(body);
366
215
  return copy.buffer;
367
216
  }
368
- function normalizeBinary(data) {
369
- if (data instanceof Uint8Array) {
370
- return data;
217
+ function bytesToBase64(value) {
218
+ const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
219
+ if (typeof Buffer !== "undefined") {
220
+ return Buffer.from(bytes).toString("base64");
371
221
  }
372
- return new Uint8Array(data);
222
+ let binary = "";
223
+ for (const byte of bytes) {
224
+ binary += String.fromCharCode(byte);
225
+ }
226
+ return btoa(binary);
373
227
  }
374
228
  export class Meshagent {
375
229
  constructor({ baseUrl, token } = {}) {
@@ -428,11 +282,10 @@ export class Meshagent {
428
282
  catch {
429
283
  message = "<unable to read body>";
430
284
  }
431
- const errorMessage = `Failed to ${action}. Status code: ${response.status}, body: ${message}`;
432
285
  if (response.status === 403) {
433
- throw new ForbiddenException(errorMessage);
286
+ throw new ForbiddenException(`Failed to ${action}. Status code: ${response.status}, body: ${message}`);
434
287
  }
435
- throw new RoomException(errorMessage);
288
+ throw new RoomException(`Failed to ${action}. Status code: ${response.status}, body: ${message}`);
436
289
  }
437
290
  switch (responseType) {
438
291
  case "json":
@@ -449,22 +302,46 @@ export class Meshagent {
449
302
  return undefined;
450
303
  }
451
304
  }
452
- parseRoomShare(data) {
453
- if (!data || typeof data !== "object") {
454
- throw new RoomException("Invalid room share payload: expected object");
455
- }
456
- const { id, project_id: projectId, projectId: projectIdAlt, settings } = data;
457
- if (typeof id !== "string") {
458
- throw new RoomException("Invalid room share payload: missing id");
459
- }
460
- const finalProjectId = typeof projectIdAlt === "string" ? projectIdAlt : typeof projectId === "string" ? projectId : undefined;
461
- if (!finalProjectId) {
462
- throw new RoomException("Invalid room share payload: missing project id");
463
- }
305
+ secretPayload(input) {
306
+ const payload = {};
307
+ if (input.projectId !== undefined)
308
+ payload.project_id = input.projectId;
309
+ if (input.name !== undefined)
310
+ payload.name = input.name;
311
+ if (input.type !== undefined)
312
+ payload.type = input.type;
313
+ if (input.httpOnly !== undefined)
314
+ payload.http_only = input.httpOnly;
315
+ if (input.metadata !== undefined)
316
+ payload.metadata = input.metadata;
317
+ if (input.annotations !== undefined)
318
+ payload.annotations = input.annotations;
319
+ return payload;
320
+ }
321
+ secretSearchPayload(input) {
322
+ const payload = {
323
+ page_size: input.pageSize ?? 100,
324
+ };
325
+ if (input.filter !== undefined)
326
+ payload.filter = input.filter;
327
+ if (input.name !== undefined)
328
+ payload.name = input.name;
329
+ if (input.type !== undefined)
330
+ payload.type = input.type;
331
+ if (input.httpOnly !== undefined)
332
+ payload.http_only = input.httpOnly;
333
+ if (input.metadata !== undefined)
334
+ payload.metadata = input.metadata;
335
+ if (input.annotations !== undefined)
336
+ payload.annotations = input.annotations;
337
+ if (input.continuationToken !== undefined)
338
+ payload.continuation_token = input.continuationToken;
339
+ return payload;
340
+ }
341
+ secretVersionPayload(input) {
464
342
  return {
465
- id,
466
- projectId: finalProjectId,
467
- settings: (settings && typeof settings === "object") ? settings : {},
343
+ value_base64: bytesToBase64(input.value),
344
+ set_current: input.setCurrent ?? true,
468
345
  };
469
346
  }
470
347
  parseRoomSession(data) {
@@ -494,34 +371,33 @@ export class Meshagent {
494
371
  createdAt: new Date(created),
495
372
  isActive: isActiveValue,
496
373
  participants: participants && typeof participants === "object" ? participants : undefined,
497
- kind: typeof kind === "string" ? kind : "room",
374
+ kind: typeof kind === "string" ? kind : undefined,
498
375
  agentId: typeof agentId === "string" ? agentId : typeof agentIdRaw === "string" ? agentIdRaw : undefined,
499
376
  agentName: typeof agentName === "string" ? agentName : typeof agentNameRaw === "string" ? agentNameRaw : undefined,
500
377
  });
501
378
  }
502
- parseManagedAgent(data) {
379
+ parseRoom(data) {
503
380
  if (!data || typeof data !== "object") {
504
- throw new RoomException("Invalid managed agent payload");
381
+ throw new RoomException("Invalid room payload");
505
382
  }
506
- const { id, name, configuration } = data;
383
+ const { id, name, metadata, annotations } = data;
507
384
  if (typeof id !== "string" || typeof name !== "string") {
508
- throw new RoomException("Invalid managed agent payload: missing id or name");
385
+ throw new RoomException("Invalid room payload: missing id or name");
509
386
  }
510
387
  return {
511
388
  id,
512
389
  name,
513
- configuration: configuration && typeof configuration === "object" && !Array.isArray(configuration)
514
- ? configuration
515
- : {},
390
+ metadata: metadata && typeof metadata === "object" ? metadata : {},
391
+ annotations: annotations && typeof annotations === "object" ? annotations : {},
516
392
  };
517
393
  }
518
- parseRoom(data) {
394
+ parseGroup(data) {
519
395
  if (!data || typeof data !== "object") {
520
- throw new RoomException("Invalid room payload");
396
+ throw new RoomException("Invalid group payload");
521
397
  }
522
398
  const { id, name, metadata, annotations } = data;
523
399
  if (typeof id !== "string" || typeof name !== "string") {
524
- throw new RoomException("Invalid room payload: missing id or name");
400
+ throw new RoomException("Invalid group payload: missing id or name");
525
401
  }
526
402
  return {
527
403
  id,
@@ -681,53 +557,170 @@ export class Meshagent {
681
557
  createdAt: new Date(createdAtValue),
682
558
  };
683
559
  }
684
- parseProjectRoomGrant(data) {
685
- if (!data || typeof data !== "object") {
686
- throw new RoomException("Invalid room grant payload");
687
- }
688
- const roomData = data.room;
689
- const room = this.parseRoom(roomData);
690
- const userId = data.user_id ?? data.userId;
691
- if (typeof userId !== "string") {
692
- throw new RoomException("Invalid room grant payload: missing user_id");
560
+ parseAccessResource(resource) {
561
+ if (!resource || typeof resource !== "object" || typeof resource.type !== "string" || typeof resource.id !== "string") {
562
+ throw new RoomException("Invalid access resource payload");
693
563
  }
694
- const permissionsRaw = data.permissions;
695
- const permissions = permissionsRaw && typeof permissionsRaw === "object" ? ApiScope.fromJSON(permissionsRaw) : new ApiScope();
696
- return { room, userId, permissions };
564
+ return {
565
+ type: resource.type,
566
+ id: resource.id,
567
+ name: typeof resource.name === "string" ? resource.name : null,
568
+ metadata: resource.metadata && typeof resource.metadata === "object" ? resource.metadata : {},
569
+ annotations: resource.annotations && typeof resource.annotations === "object" ? resource.annotations : {},
570
+ };
697
571
  }
698
- parseProjectRoomGrantCount(data) {
699
- const roomData = (data && typeof data === "object") ? (data.room ?? { id: data.room_id, name: data.room_name, metadata: data.metadata ?? {} }) : undefined;
700
- if (!roomData) {
701
- throw new RoomException("Invalid room grant count payload: missing room");
702
- }
703
- const room = this.parseRoom(roomData);
704
- const count = data.count;
705
- if (typeof count !== "number") {
706
- throw new RoomException("Invalid room grant count payload: missing count");
572
+ parseAccessSubject(subject) {
573
+ if (!subject || typeof subject !== "object" || typeof subject.type !== "string" || typeof subject.id !== "string") {
574
+ throw new RoomException("Invalid access subject payload");
707
575
  }
708
- return { room, count };
576
+ return {
577
+ type: subject.type,
578
+ id: subject.id,
579
+ name: typeof subject.name === "string" ? subject.name : null,
580
+ firstName: typeof subject.first_name === "string" ? subject.first_name : null,
581
+ lastName: typeof subject.last_name === "string" ? subject.last_name : null,
582
+ email: typeof subject.email === "string" ? subject.email : null,
583
+ objectType: typeof subject.object_type === "string" ? subject.object_type : null,
584
+ relation: typeof subject.relation === "string" ? subject.relation : null,
585
+ };
586
+ }
587
+ serializeAccessSubject(subject) {
588
+ return {
589
+ type: subject.type,
590
+ id: subject.id,
591
+ ...(subject.name !== undefined ? { name: subject.name } : {}),
592
+ ...(subject.firstName !== undefined ? { first_name: subject.firstName } : {}),
593
+ ...(subject.lastName !== undefined ? { last_name: subject.lastName } : {}),
594
+ ...(subject.email !== undefined ? { email: subject.email } : {}),
595
+ ...(subject.objectType !== undefined ? { object_type: subject.objectType } : {}),
596
+ ...(subject.relation !== undefined ? { relation: subject.relation } : {}),
597
+ };
709
598
  }
710
- parseProjectUserGrantCount(data) {
599
+ serializeAccessResource(resource) {
600
+ return {
601
+ type: resource.type,
602
+ id: resource.id,
603
+ ...(resource.name !== undefined ? { name: resource.name } : {}),
604
+ ...(resource.metadata !== undefined ? { metadata: resource.metadata } : {}),
605
+ ...(resource.annotations !== undefined ? { annotations: resource.annotations } : {}),
606
+ };
607
+ }
608
+ parseProjectMember(data) {
711
609
  if (!data || typeof data !== "object") {
712
- throw new RoomException("Invalid room grant user count payload");
713
- }
714
- const { user_id: userIdRaw, userId, count, first_name: firstNameRaw, firstName, last_name: lastNameRaw, lastName, email } = data;
715
- const userIdValue = typeof userId === "string" ? userId : userIdRaw;
716
- if (typeof userIdValue !== "string") {
717
- throw new RoomException("Invalid room grant user count payload: missing user_id");
718
- }
719
- if (typeof count !== "number") {
720
- throw new RoomException("Invalid room grant user count payload: missing count");
610
+ throw new RoomException("Invalid project member payload");
611
+ }
612
+ const user = data.user && typeof data.user === "object" ? data.user : data;
613
+ const directRoles = Array.isArray(data.direct_roles)
614
+ ? data.direct_roles.filter((item) => item === "member" ||
615
+ item === "admin" ||
616
+ item === "developer" ||
617
+ item === "room_creator" ||
618
+ item === "agent_creator" ||
619
+ item === "mailbox_creator" ||
620
+ item === "route_creator" ||
621
+ item === "scheduled_task_creator" ||
622
+ item === "llm_proxy_user" ||
623
+ item === "usage_reporter" ||
624
+ item === "billing_manager" ||
625
+ item === "group_manager")
626
+ : [];
627
+ const id = typeof user.id === "string" ? user.id : "";
628
+ const email = typeof user.email === "string" ? user.email : "";
629
+ return {
630
+ id,
631
+ email,
632
+ firstName: typeof user.first_name === "string" ? user.first_name : null,
633
+ lastName: typeof user.last_name === "string" ? user.last_name : null,
634
+ directRoles,
635
+ };
636
+ }
637
+ parseGroupMember(data) {
638
+ if (!data || typeof data !== "object") {
639
+ throw new RoomException("Invalid group member payload");
721
640
  }
722
- if (typeof email !== "string") {
723
- throw new RoomException("Invalid room grant user count payload: missing email");
641
+ const directRoles = Array.isArray(data.direct_roles)
642
+ ? data.direct_roles.filter((item) => item === "member" || item === "manager")
643
+ : [];
644
+ return {
645
+ subject: this.parseAccessSubject(data.subject),
646
+ directRoles,
647
+ };
648
+ }
649
+ parseProjectRoomGrant(data) {
650
+ if (!data || typeof data !== "object") {
651
+ throw new RoomException("Invalid room grant payload");
724
652
  }
653
+ const parsedResource = this.parseAccessResource(data.resource);
654
+ const parsedSubject = this.parseAccessSubject(data.subject);
655
+ const parsedDirectRoles = Array.isArray(data.direct_roles)
656
+ ? data.direct_roles.filter((item) => item === "member" ||
657
+ item === "viewer" ||
658
+ item === "operator" ||
659
+ item === "developer" ||
660
+ item === "admin" ||
661
+ item === "room_creator" ||
662
+ item === "room_inventory" ||
663
+ item === "room_manager" ||
664
+ item === "session_inventory" ||
665
+ item === "agent_creator" ||
666
+ item === "agent_inventory" ||
667
+ item === "agent_manager" ||
668
+ item === "repository_creator" ||
669
+ item === "repository_inventory" ||
670
+ item === "repository_manager" ||
671
+ item === "feed_creator" ||
672
+ item === "feed_inventory" ||
673
+ item === "feed_manager" ||
674
+ item === "oauth_client_creator" ||
675
+ item === "oauth_client_inventory" ||
676
+ item === "oauth_client_manager" ||
677
+ item === "api_key_creator" ||
678
+ item === "api_key_inventory" ||
679
+ item === "api_key_manager" ||
680
+ item === "service_creator" ||
681
+ item === "service_inventory" ||
682
+ item === "service_manager" ||
683
+ item === "service_account_creator" ||
684
+ item === "service_account_inventory" ||
685
+ item === "service_account_manager" ||
686
+ item === "participant_token_creator" ||
687
+ item === "mailbox_creator" ||
688
+ item === "mailbox_inventory" ||
689
+ item === "mailbox_manager" ||
690
+ item === "route_creator" ||
691
+ item === "route_inventory" ||
692
+ item === "route_manager" ||
693
+ item === "scheduled_task_creator" ||
694
+ item === "scheduled_task_inventory" ||
695
+ item === "scheduled_task_manager" ||
696
+ item === "feed_subscription_creator" ||
697
+ item === "feed_subscription_inventory" ||
698
+ item === "feed_subscription_manager" ||
699
+ item === "llm_logger_creator" ||
700
+ item === "llm_logger_inventory" ||
701
+ item === "llm_logger_manager" ||
702
+ item === "llm_proxy_user" ||
703
+ item === "usage_reporter" ||
704
+ item === "billing_manager" ||
705
+ item === "group_manager" ||
706
+ item === "reader" ||
707
+ item === "subscriber" ||
708
+ item === "publisher" ||
709
+ item === "manager" ||
710
+ item === "list")
711
+ : [];
712
+ const room = {
713
+ id: parsedResource.id,
714
+ name: parsedResource.name ?? parsedResource.id,
715
+ metadata: parsedResource.metadata ?? {},
716
+ annotations: parsedResource.annotations ?? {},
717
+ };
725
718
  return {
726
- userId: userIdValue,
727
- count,
728
- firstName: typeof firstName === "string" ? firstName : firstNameRaw,
729
- lastName: typeof lastName === "string" ? lastName : lastNameRaw,
730
- email,
719
+ resource: parsedResource,
720
+ subject: parsedSubject,
721
+ directRoles: parsedDirectRoles,
722
+ room,
723
+ userId: parsedSubject.id,
731
724
  };
732
725
  }
733
726
  parseBalance(data) {
@@ -776,196 +769,13 @@ export class Meshagent {
776
769
  createdAt: new Date(createdValue),
777
770
  };
778
771
  }
779
- parseSecret(data) {
780
- if (!data || typeof data !== "object") {
781
- throw new RoomException("Invalid secret payload");
782
- }
783
- const type = data.type;
784
- if (type === "docker") {
785
- const server = data.server;
786
- const username = data.username;
787
- const password = data.password;
788
- if (typeof server !== "string" || typeof username !== "string" || typeof password !== "string") {
789
- throw new RoomException("Invalid docker secret payload");
790
- }
791
- return {
792
- id: typeof data.id === "string" ? data.id : undefined,
793
- name: data.name,
794
- type: "docker",
795
- server,
796
- username,
797
- password,
798
- email: typeof data.email === "string" ? data.email : undefined,
799
- };
800
- }
801
- if (type === "keys") {
802
- const record = data.data;
803
- if (!record || typeof record !== "object") {
804
- throw new RoomException("Invalid keys secret payload");
805
- }
806
- return {
807
- id: typeof data.id === "string" ? data.id : undefined,
808
- name: data.name,
809
- type: "keys",
810
- data: record,
811
- };
812
- }
813
- throw new RoomException(`Unknown secret type: ${type}`);
814
- }
815
- parseManagedSecretInfo(data) {
816
- if (!data || typeof data !== "object") {
817
- throw new RoomException("Invalid managed secret payload");
818
- }
819
- const { id, type, name, delegated_to: delegatedToRaw, delegatedTo } = data;
820
- if (typeof id !== "string" || typeof type !== "string" || typeof name !== "string") {
821
- throw new RoomException("Invalid managed secret payload: missing id, type, or name");
822
- }
823
- const delegatedToValue = typeof delegatedTo === "string"
824
- ? delegatedTo
825
- : typeof delegatedToRaw === "string"
826
- ? delegatedToRaw
827
- : null;
828
- return {
829
- id,
830
- type,
831
- name,
832
- delegatedTo: delegatedToValue,
833
- };
834
- }
835
- parseManagedSecret(data) {
836
- const secret = this.parseManagedSecretInfo(data);
837
- const dataBase64 = data.data_base64 ?? data.dataBase64;
838
- if (typeof dataBase64 !== "string") {
839
- throw new RoomException("Invalid managed secret payload: missing data_base64");
840
- }
841
- return {
842
- ...secret,
843
- dataBase64,
844
- data: base64ToBytes(dataBase64),
845
- };
846
- }
847
- parseSecretPayload(secret, rawData) {
848
- let payload;
849
- try {
850
- payload = JSON.parse(decoder.decode(rawData));
851
- }
852
- catch {
853
- throw new RoomException(`Invalid secret payload for ${secret.id}`);
854
- }
855
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
856
- throw new RoomException(`Invalid secret payload for ${secret.id}`);
857
- }
858
- if (secret.type === "docker") {
859
- const { server, username, password, email } = payload;
860
- if (typeof server !== "string" || typeof username !== "string" || typeof password !== "string") {
861
- throw new RoomException(`Invalid secret payload for ${secret.id}`);
862
- }
863
- return {
864
- id: secret.id,
865
- name: secret.name,
866
- type: "docker",
867
- server,
868
- username,
869
- password,
870
- email: typeof email === "string" ? email : "none@example.com",
871
- };
872
- }
873
- const entries = Object.entries(payload);
874
- if (entries.some(([, value]) => typeof value !== "string")) {
875
- throw new RoomException(`Invalid secret payload for ${secret.id}`);
876
- }
877
- return {
878
- id: secret.id,
879
- name: secret.name,
880
- type: "keys",
881
- data: Object.fromEntries(entries),
882
- };
883
- }
884
- toSecretPayload(secret) {
885
- if (secret.type === "docker") {
886
- return {
887
- name: secret.name,
888
- type: secret.type,
889
- data: {
890
- server: secret.server,
891
- username: secret.username,
892
- password: secret.password,
893
- email: secret.email ?? "none@example.com",
894
- },
895
- };
896
- }
897
- return {
898
- name: secret.name,
899
- type: secret.type,
900
- data: { ...secret.data },
901
- };
902
- }
903
- parseConnectorRef(data) {
904
- if (data == null) {
905
- return null;
906
- }
907
- if (typeof data !== "object") {
908
- throw new RoomException("Invalid connector payload");
909
- }
910
- const { openai_connector_id: openaiConnectorIdRaw, openaiConnectorId, server_url: serverUrlRaw, serverUrl, client_secret_id: clientSecretIdRaw, clientSecretId, } = data;
911
- return {
912
- openaiConnectorId: typeof openaiConnectorId === "string"
913
- ? openaiConnectorId
914
- : typeof openaiConnectorIdRaw === "string"
915
- ? openaiConnectorIdRaw
916
- : null,
917
- serverUrl: typeof serverUrl === "string"
918
- ? serverUrl
919
- : typeof serverUrlRaw === "string"
920
- ? serverUrlRaw
921
- : null,
922
- clientSecretId: typeof clientSecretId === "string"
923
- ? clientSecretId
924
- : typeof clientSecretIdRaw === "string"
925
- ? clientSecretIdRaw
926
- : null,
927
- };
928
- }
929
- serializeConnectorRef(connector) {
930
- if (connector == null) {
931
- return null;
932
- }
933
- const payload = {};
934
- if (connector.openaiConnectorId) {
935
- payload.openai_connector_id = connector.openaiConnectorId;
936
- }
937
- if (connector.serverUrl) {
938
- payload.server_url = connector.serverUrl;
939
- }
940
- if (connector.clientSecretId) {
941
- payload.client_secret_id = connector.clientSecretId;
942
- }
943
- return payload;
944
- }
945
- parseExternalOAuthClientRegistration(data) {
946
- if (!data || typeof data !== "object") {
947
- throw new RoomException("Invalid external oauth registration payload");
948
- }
949
- const { id, delegated_to: delegatedToRaw, delegatedTo, connector, oauth, client_id: clientIdRaw, clientId, client_secret: clientSecretRaw, clientSecret, } = data;
950
- const delegatedToValue = typeof delegatedTo === "string" ? delegatedTo : delegatedToRaw;
951
- const clientIdValue = typeof clientId === "string" ? clientId : clientIdRaw;
952
- const clientSecretValue = typeof clientSecret === "string" ? clientSecret : clientSecretRaw;
953
- if (typeof id !== "string" || typeof delegatedToValue !== "string" || typeof clientIdValue !== "string") {
954
- throw new RoomException("Invalid external oauth registration payload: missing fields");
955
- }
956
- return {
957
- id,
958
- delegatedTo: delegatedToValue,
959
- connector: this.parseConnectorRef(connector),
960
- oauth: oauth && typeof oauth === "object" ? oauth : null,
961
- clientId: clientIdValue,
962
- clientSecret: typeof clientSecretValue === "string" ? clientSecretValue : null,
963
- };
964
- }
965
772
  parseOAuthClient(data) {
966
773
  if (!data || typeof data !== "object") {
967
774
  throw new RoomException("Invalid OAuth client payload");
968
775
  }
776
+ if ("client" in data && data.client && typeof data.client === "object") {
777
+ data = data.client;
778
+ }
969
779
  const { client_id: clientIdRaw, clientId, client_secret: clientSecretRaw, clientSecret, grant_types: grantTypesRaw, grantTypes, response_types: responseTypesRaw, responseTypes, redirect_uris: redirectUrisRaw, redirectUris, scope, project_id: projectIdRaw, projectId, metadata } = data;
970
780
  const clientIdValue = typeof clientId === "string" ? clientId : clientIdRaw;
971
781
  const clientSecretValue = typeof clientSecret === "string" ? clientSecret : clientSecretRaw;
@@ -991,6 +801,7 @@ export class Meshagent {
991
801
  scope,
992
802
  projectId: projectIdValue,
993
803
  metadata: metadata && typeof metadata === "object" ? metadata : {},
804
+ official: Boolean(data.official),
994
805
  };
995
806
  }
996
807
  parseRoomConnectionInfo(data) {
@@ -1031,45 +842,6 @@ export class Meshagent {
1031
842
  responseType: "arrayBuffer",
1032
843
  });
1033
844
  }
1034
- async getProjectRole(projectId) {
1035
- const payload = await this.request(`/accounts/projects/${projectId}/role`, {
1036
- action: "fetch project role",
1037
- });
1038
- const role = payload?.role;
1039
- if (role !== "member" && role !== "admin" && role !== "developer") {
1040
- throw new RoomException("Invalid role payload");
1041
- }
1042
- return role;
1043
- }
1044
- async createShare(projectId, settings) {
1045
- return await this.request(`/accounts/projects/${projectId}/shares`, {
1046
- method: "POST",
1047
- json: { settings: settings ?? {} },
1048
- action: "create share",
1049
- });
1050
- }
1051
- async deleteShare(projectId, shareId) {
1052
- await this.request(`/accounts/projects/${projectId}/shares/${shareId}`, {
1053
- method: "DELETE",
1054
- action: "delete share",
1055
- responseType: "void",
1056
- });
1057
- }
1058
- async updateShare(projectId, shareId, settings) {
1059
- await this.request(`/accounts/projects/${projectId}/shares/${shareId}`, {
1060
- method: "PUT",
1061
- json: { settings: settings ?? {} },
1062
- action: "update share",
1063
- responseType: "void",
1064
- });
1065
- }
1066
- async listShares(projectId) {
1067
- const data = await this.request(`/accounts/projects/${projectId}/shares`, {
1068
- action: "list shares",
1069
- });
1070
- const shares = Array.isArray(data?.shares) ? data.shares : [];
1071
- return shares.map((item) => this.parseRoomShare(item));
1072
- }
1073
845
  async createProject(name, settings) {
1074
846
  return await this.request(`/accounts/projects`, {
1075
847
  method: "POST",
@@ -1078,39 +850,15 @@ export class Meshagent {
1078
850
  });
1079
851
  }
1080
852
  async addUserToProject(projectId, userId, options = {}) {
1081
- const { isAdmin, isDeveloper, canCreateRooms, inviteRedirectUrl } = options;
853
+ const { roles = ["member"], email, inviteRedirectUrl } = options;
1082
854
  return await this.request(`/accounts/projects/${projectId}/users`, {
1083
855
  method: "POST",
1084
856
  json: {
1085
857
  project_id: projectId,
1086
858
  user_id: userId,
1087
- ...(isAdmin !== undefined ? { is_admin: isAdmin } : {}),
1088
- ...(isDeveloper !== undefined ? { is_developer: isDeveloper } : {}),
1089
- ...(canCreateRooms !== undefined
1090
- ? { can_create_rooms: canCreateRooms }
1091
- : {}),
1092
- ...(inviteRedirectUrl !== undefined
1093
- ? { invite_redirect_url: inviteRedirectUrl }
1094
- : {}),
1095
- },
1096
- action: "add user to project",
1097
- });
1098
- }
1099
- async addUserToProjectByEmail(projectId, email, options = {}) {
1100
- const { isAdmin, isDeveloper, canCreateRooms, inviteRedirectUrl } = options;
1101
- return await this.request(`/accounts/projects/${projectId}/users`, {
1102
- method: "POST",
1103
- json: {
1104
- project_id: projectId,
1105
- email,
1106
- ...(isAdmin !== undefined ? { is_admin: isAdmin } : {}),
1107
- ...(isDeveloper !== undefined ? { is_developer: isDeveloper } : {}),
1108
- ...(canCreateRooms !== undefined
1109
- ? { can_create_rooms: canCreateRooms }
1110
- : {}),
1111
- ...(inviteRedirectUrl !== undefined
1112
- ? { invite_redirect_url: inviteRedirectUrl }
1113
- : {}),
859
+ roles,
860
+ ...(email !== undefined ? { email } : {}),
861
+ ...(inviteRedirectUrl !== undefined ? { invite_redirect_url: inviteRedirectUrl } : {}),
1114
862
  },
1115
863
  action: "add user to project",
1116
864
  });
@@ -1128,79 +876,281 @@ export class Meshagent {
1128
876
  action: "update project settings",
1129
877
  });
1130
878
  }
879
+ async updateUserInProject(projectId, userId, roles) {
880
+ return await this.request(`/accounts/projects/${projectId}/users/${userId}`, {
881
+ method: "PUT",
882
+ json: { roles },
883
+ action: "update project user",
884
+ });
885
+ }
1131
886
  async getUsersInProjectPage(projectId, options = {}) {
1132
- const { count = 100, offset = 0, filter } = options;
887
+ const { pageSize = 100, continuationToken, filter, email } = options;
1133
888
  const data = await this.request(`/accounts/projects/${projectId}/users`, {
1134
- query: { count, offset, filter },
889
+ query: { page_size: pageSize, continuation_token: continuationToken, filter, email },
1135
890
  action: "fetch project users",
1136
891
  });
1137
- const users = Array.isArray(data?.users) ? data.users : [];
1138
- return { users, total: typeof data?.total === "number" ? data.total : users.length };
1139
- }
1140
- async getUsersInProject(projectId) {
1141
- const page = await this.getUsersInProjectPage(projectId);
1142
- return { users: page.users, total: page.total };
892
+ const users = Array.isArray(data?.users) ? data.users : [];
893
+ return { users: users.map((user) => this.parseProjectMember(user)), continuationToken: data?.continuation_token ?? null };
894
+ }
895
+ async getUsersInProject(projectId) {
896
+ const page = await this.getUsersInProjectPage(projectId);
897
+ return page.users;
898
+ }
899
+ async getUserProfile(userId) {
900
+ return await this.request(`/accounts/profiles/${userId}`, {
901
+ action: "fetch user profile",
902
+ });
903
+ }
904
+ async updateUserProfile(userId, firstName, lastName) {
905
+ return await this.request(`/accounts/profiles/${userId}`, {
906
+ method: "PUT",
907
+ json: { first_name: firstName, last_name: lastName },
908
+ action: "update user profile",
909
+ });
910
+ }
911
+ async listProjects() {
912
+ return await this.request(`/accounts/projects`, {
913
+ action: "list projects",
914
+ });
915
+ }
916
+ async getProject(projectId) {
917
+ return await this.request(`/accounts/projects/${projectId}`, {
918
+ action: "get project",
919
+ });
920
+ }
921
+ async getProjectByKey(projectKey) {
922
+ return await this.request(`/accounts/projects/by-key/${encodeURIComponent(projectKey)}`, {
923
+ action: "get project by key",
924
+ });
925
+ }
926
+ async listServiceAccounts(projectId, options = {}) {
927
+ const params = new URLSearchParams();
928
+ if (options.pageSize !== undefined)
929
+ params.set("page_size", String(options.pageSize));
930
+ if (options.continuationToken !== undefined)
931
+ params.set("continuation_token", options.continuationToken);
932
+ if (options.filter !== undefined)
933
+ params.set("filter", options.filter);
934
+ if (options.view !== undefined)
935
+ params.set("view", options.view);
936
+ const query = params.toString();
937
+ return await this.request(`/accounts/projects/${projectId}/service-accounts${query ? `?${query}` : ""}`, {
938
+ action: "list service accounts",
939
+ });
940
+ }
941
+ async createServiceAccount(projectId, name, options = {}) {
942
+ return await this.request(`/accounts/projects/${projectId}/service-accounts`, {
943
+ method: "POST",
944
+ json: { name, ...options },
945
+ action: "create service account",
946
+ });
947
+ }
948
+ async mintParticipantToken(projectId, options) {
949
+ const json = options.grants !== undefined
950
+ ? { name: options.name, grants: options.grants }
951
+ : {
952
+ name: options.name,
953
+ room_name: options.roomName,
954
+ role: options.role,
955
+ api: options.api,
956
+ };
957
+ const data = await this.request(`/accounts/projects/${projectId}/participant-tokens`, {
958
+ method: "POST",
959
+ json,
960
+ action: "mint participant token",
961
+ });
962
+ if (typeof data?.token !== "string" || data.token.trim() === "") {
963
+ throw new Error("Invalid participant token mint response");
964
+ }
965
+ return data.token;
966
+ }
967
+ async createApiKey(projectId, serviceAccountId, name, description) {
968
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/api-keys`, {
969
+ method: "POST",
970
+ json: { name, description },
971
+ action: "create api key",
972
+ });
973
+ }
974
+ async deleteApiKey(projectId, serviceAccountId, id) {
975
+ await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/api-keys/${id}`, {
976
+ method: "DELETE",
977
+ action: "delete api key",
978
+ responseType: "void",
979
+ });
980
+ }
981
+ async revokeApiKeysByMsid(projectId, serviceAccountId, msid) {
982
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/api-keys:revoke`, {
983
+ method: "POST",
984
+ json: { msid },
985
+ action: "revoke api keys",
986
+ });
987
+ }
988
+ async listApiKeys(projectId, serviceAccountId) {
989
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/api-keys`, {
990
+ action: "list api keys",
991
+ });
992
+ }
993
+ async createUserSecret(input) {
994
+ return await this.request(`/accounts/users/me/secrets`, {
995
+ method: "POST",
996
+ json: this.secretPayload(input),
997
+ action: "create user secret",
998
+ });
999
+ }
1000
+ async listUserSecrets(options = {}) {
1001
+ return await this.request(`/accounts/users/me/secrets`, {
1002
+ query: {
1003
+ page_size: options.pageSize ?? 100,
1004
+ continuation_token: options.continuationToken,
1005
+ filter: options.filter,
1006
+ },
1007
+ action: "list user secrets",
1008
+ });
1009
+ }
1010
+ async searchUserSecrets(input = {}) {
1011
+ return await this.request(`/accounts/users/me/secrets:search`, {
1012
+ method: "POST",
1013
+ json: this.secretSearchPayload(input),
1014
+ action: "search user secrets",
1015
+ });
1016
+ }
1017
+ async getUserSecret(secretId, options = {}) {
1018
+ return await this.request(`/accounts/users/me/secrets/${secretId}`, {
1019
+ query: {
1020
+ include_value: options.includeValue ? "true" : undefined,
1021
+ },
1022
+ action: "get user secret",
1023
+ });
1024
+ }
1025
+ async updateUserSecret(secretId, input) {
1026
+ return await this.request(`/accounts/users/me/secrets/${secretId}`, {
1027
+ method: "PATCH",
1028
+ json: this.secretPayload(input),
1029
+ action: "update user secret",
1030
+ });
1031
+ }
1032
+ async deleteUserSecret(secretId) {
1033
+ await this.request(`/accounts/users/me/secrets/${secretId}`, {
1034
+ method: "DELETE",
1035
+ action: "delete user secret",
1036
+ responseType: "void",
1037
+ });
1038
+ }
1039
+ async listUserSecretVersions(secretId) {
1040
+ const page = await this.request(`/accounts/users/me/secrets/${secretId}/versions`, {
1041
+ action: "list user secret versions",
1042
+ });
1043
+ return page.versions;
1044
+ }
1045
+ async createUserSecretVersion(secretId, input) {
1046
+ return await this.request(`/accounts/users/me/secrets/${secretId}/versions`, {
1047
+ method: "POST",
1048
+ json: this.secretVersionPayload(input),
1049
+ action: "create user secret version",
1050
+ });
1051
+ }
1052
+ async listUserSecretProxyAccess(secretId, options = {}) {
1053
+ return await this.request(`/accounts/users/me/secrets/${secretId}/access`, {
1054
+ query: {
1055
+ page_size: options.pageSize ?? 100,
1056
+ continuation_token: options.continuationToken,
1057
+ },
1058
+ action: "list user secret proxy access",
1059
+ });
1060
+ }
1061
+ async grantUserSecretProxyAccess(secretId, serviceAccountId) {
1062
+ await this.request(`/accounts/users/me/secrets/${secretId}/access:grant-proxy`, {
1063
+ method: "POST",
1064
+ json: { subject: { type: "service_account", id: serviceAccountId } },
1065
+ action: "grant user secret proxy access",
1066
+ responseType: "void",
1067
+ });
1068
+ }
1069
+ async revokeUserSecretProxyAccess(secretId, serviceAccountId) {
1070
+ await this.request(`/accounts/users/me/secrets/${secretId}/access:revoke-proxy`, {
1071
+ method: "POST",
1072
+ json: { subject: { type: "service_account", id: serviceAccountId } },
1073
+ action: "revoke user secret proxy access",
1074
+ responseType: "void",
1075
+ });
1076
+ }
1077
+ async createServiceAccountSecret(projectId, serviceAccountId, input) {
1078
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets`, {
1079
+ method: "POST",
1080
+ json: this.secretPayload(input),
1081
+ action: "create service account secret",
1082
+ });
1083
+ }
1084
+ async listServiceAccountSecrets(projectId, serviceAccountId, options = {}) {
1085
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets`, {
1086
+ query: {
1087
+ page_size: options.pageSize ?? 100,
1088
+ continuation_token: options.continuationToken,
1089
+ filter: options.filter,
1090
+ },
1091
+ action: "list service account secrets",
1092
+ });
1143
1093
  }
1144
- async getUserProfile(userId) {
1145
- return await this.request(`/accounts/profiles/${userId}`, {
1146
- action: "fetch user profile",
1094
+ async searchServiceAccountSecrets(projectId, serviceAccountId, input = {}) {
1095
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets:search`, {
1096
+ method: "POST",
1097
+ json: this.secretSearchPayload(input),
1098
+ action: "search service account secrets",
1147
1099
  });
1148
1100
  }
1149
- async updateUserProfile(userId, firstName, lastName) {
1150
- return await this.request(`/accounts/profiles/${userId}`, {
1151
- method: "PUT",
1152
- json: { first_name: firstName, last_name: lastName },
1153
- action: "update user profile",
1101
+ async getServiceAccountSecret(projectId, serviceAccountId, secretId, options = {}) {
1102
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets/${secretId}`, {
1103
+ query: {
1104
+ include_value: options.includeValue ? "true" : undefined,
1105
+ },
1106
+ action: "get service account secret",
1154
1107
  });
1155
1108
  }
1156
- async listProjects() {
1157
- return await this.request(`/accounts/projects`, {
1158
- action: "list projects",
1109
+ async updateServiceAccountSecret(projectId, serviceAccountId, secretId, input) {
1110
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets/${secretId}`, {
1111
+ method: "PATCH",
1112
+ json: this.secretPayload(input),
1113
+ action: "update service account secret",
1159
1114
  });
1160
1115
  }
1161
- async getProject(projectId) {
1162
- return await this.request(`/accounts/projects/${projectId}`, {
1163
- action: "get project",
1116
+ async deleteServiceAccountSecret(projectId, serviceAccountId, secretId) {
1117
+ await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets/${secretId}`, {
1118
+ method: "DELETE",
1119
+ action: "delete service account secret",
1120
+ responseType: "void",
1164
1121
  });
1165
1122
  }
1166
- async getProjectByKey(projectKey) {
1167
- return await this.request(`/accounts/projects/by-key/${encodeURIComponent(projectKey)}`, {
1168
- action: "get project by key",
1123
+ async listServiceAccountSecretVersions(projectId, serviceAccountId, secretId) {
1124
+ const page = await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets/${secretId}/versions`, {
1125
+ action: "list service account secret versions",
1169
1126
  });
1127
+ return page.versions;
1170
1128
  }
1171
- async createAgent(params) {
1172
- const { projectId, configuration, ifNotExists = false, permissions } = params;
1173
- const permissionsJson = permissions == null
1174
- ? undefined
1175
- : Object.fromEntries(Object.entries(permissions).map(([userId, grant]) => [userId, grant.toJson()]));
1176
- const data = await this.request(`/accounts/projects/${this.encodePathComponent(projectId)}/agents`, {
1129
+ async createServiceAccountSecretVersion(projectId, serviceAccountId, secretId, input) {
1130
+ return await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/secrets/${secretId}/versions`, {
1177
1131
  method: "POST",
1178
- json: {
1179
- configuration: pruneNullishValues(configuration),
1180
- if_not_exists: ifNotExists,
1181
- ...(permissionsJson !== undefined ? { permissions: permissionsJson } : {}),
1182
- },
1183
- action: "create agent",
1132
+ json: this.secretVersionPayload(input),
1133
+ action: "create service account secret version",
1184
1134
  });
1185
- return this.parseManagedAgent(data);
1186
1135
  }
1187
- async createApiKey(projectId, name, description) {
1188
- return await this.request(`/accounts/projects/${projectId}/api-keys`, {
1189
- method: "POST",
1190
- json: { name, description },
1191
- action: "create api key",
1136
+ async listServiceAccountPullSecrets(projectId, serviceAccountId) {
1137
+ const page = await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/pull-secrets`, {
1138
+ action: "list service account pull secrets",
1192
1139
  });
1140
+ return page.secrets;
1193
1141
  }
1194
- async deleteApiKey(projectId, id) {
1195
- await this.request(`/accounts/projects/${projectId}/api-keys/${id}`, {
1196
- method: "DELETE",
1197
- action: "delete api key",
1142
+ async addServiceAccountPullSecret(projectId, serviceAccountId, secretId) {
1143
+ await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/pull-secrets/${secretId}`, {
1144
+ method: "PUT",
1145
+ action: "add service account pull secret",
1198
1146
  responseType: "void",
1199
1147
  });
1200
1148
  }
1201
- async listApiKeys(projectId) {
1202
- return await this.request(`/accounts/projects/${projectId}/api-keys`, {
1203
- action: "list api keys",
1149
+ async removeServiceAccountPullSecret(projectId, serviceAccountId, secretId) {
1150
+ await this.request(`/accounts/projects/${projectId}/service-accounts/${serviceAccountId}/pull-secrets/${secretId}`, {
1151
+ method: "DELETE",
1152
+ action: "remove service account pull secret",
1153
+ responseType: "void",
1204
1154
  });
1205
1155
  }
1206
1156
  async getPricing() {
@@ -1311,6 +1261,40 @@ export class Meshagent {
1311
1261
  const sessions = Array.isArray(data?.sessions) ? data.sessions : [];
1312
1262
  return sessions.map((item) => this.parseRoomSession(item));
1313
1263
  }
1264
+ async listRecentRoomSessions(projectId, roomName, options = {}) {
1265
+ const params = new URLSearchParams();
1266
+ if (options.limit !== undefined) {
1267
+ params.set("limit", String(options.limit));
1268
+ }
1269
+ const query = params.size > 0 ? `?${params.toString()}` : "";
1270
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${encodeURIComponent(roomName)}/sessions${query}`, { action: "list recent room sessions" });
1271
+ const sessions = Array.isArray(data?.sessions) ? data.sessions : [];
1272
+ return sessions.map((item) => this.parseRoomSession(item));
1273
+ }
1274
+ async listRecentSingleAgentSessions(projectId, agentName, options = {}) {
1275
+ const params = new URLSearchParams();
1276
+ if (options.limit !== undefined) {
1277
+ params.set("limit", String(options.limit));
1278
+ }
1279
+ const query = params.size > 0 ? `?${params.toString()}` : "";
1280
+ const data = await this.request(`/accounts/projects/${projectId}/agents/${encodeURIComponent(agentName)}/sessions${query}`, { action: "list recent agent sessions" });
1281
+ const sessions = Array.isArray(data?.sessions) ? data.sessions : [];
1282
+ return sessions.map((item) => this.parseRoomSession(item));
1283
+ }
1284
+ async createAgent(params) {
1285
+ const body = {
1286
+ configuration: params.configuration,
1287
+ if_not_exists: params.ifNotExists ?? false,
1288
+ };
1289
+ if (params.permissions != null) {
1290
+ body.permissions = params.permissions;
1291
+ }
1292
+ return await this.request(`/accounts/projects/${params.projectId}/agents`, {
1293
+ method: "POST",
1294
+ json: body,
1295
+ action: "create agent",
1296
+ });
1297
+ }
1314
1298
  async listSessionEvents(projectId, sessionId) {
1315
1299
  const data = await this.request(`/accounts/projects/${projectId}/sessions/${sessionId}/events`, {
1316
1300
  action: "list session events",
@@ -1339,34 +1323,6 @@ export class Meshagent {
1339
1323
  const metrics = data?.["metrics"];
1340
1324
  return Array.isArray(metrics) ? metrics : [];
1341
1325
  }
1342
- async createWebhook(projectId, params) {
1343
- const { name, url, events, description = "", action: webhookAction = "", payload = null } = params;
1344
- return await this.request(`/accounts/projects/${projectId}/webhooks`, {
1345
- method: "POST",
1346
- json: { name, description, url, events, action: webhookAction, payload },
1347
- action: "create webhook",
1348
- });
1349
- }
1350
- async updateWebhook(projectId, webhookId, params) {
1351
- const { name, url, events, description = "", action: webhookAction = null, payload = null } = params;
1352
- return await this.request(`/accounts/projects/${projectId}/webhooks/${webhookId}`, {
1353
- method: "PUT",
1354
- json: { name, description, url, events, action: webhookAction, payload },
1355
- action: "update webhook",
1356
- });
1357
- }
1358
- async listWebhooks(projectId) {
1359
- return await this.request(`/accounts/projects/${projectId}/webhooks`, {
1360
- action: "list webhooks",
1361
- });
1362
- }
1363
- async deleteWebhook(projectId, webhookId) {
1364
- await this.request(`/accounts/projects/${projectId}/webhooks/${webhookId}`, {
1365
- method: "DELETE",
1366
- action: "delete webhook",
1367
- responseType: "void",
1368
- });
1369
- }
1370
1326
  async createMailbox(params) {
1371
1327
  const { projectId, address, room, queue, isPublic } = params;
1372
1328
  await this.request(`/accounts/projects/${projectId}/mailboxes`, {
@@ -1399,18 +1355,24 @@ export class Meshagent {
1399
1355
  return { address, room, roomId: room_id, queue };
1400
1356
  }
1401
1357
  async listMailboxesPage(projectId, options = {}) {
1402
- const { count = 100, offset = 0, filter } = options;
1358
+ const { pageSize = 100, continuationToken, filter } = options;
1403
1359
  const data = await this.request(`/accounts/projects/${projectId}/mailboxes`, {
1404
- query: { count, offset, filter },
1360
+ query: { page_size: pageSize, continuation_token: continuationToken, filter },
1405
1361
  action: "list mailboxes",
1406
1362
  });
1407
1363
  const mailboxes = Array.isArray(data?.mailboxes) ? data.mailboxes : [];
1408
1364
  const parsed = mailboxes.map((item) => this.parseMailbox(item));
1409
- return { mailboxes: parsed, total: typeof data?.total === "number" ? data.total : parsed.length };
1365
+ return { mailboxes: parsed, total: typeof data?.total === "number" ? data.total : parsed.length, continuationToken: data.continuation_token ?? null };
1410
1366
  }
1411
1367
  async listMailboxes(projectId, options = {}) {
1412
- const page = await this.listMailboxesPage(projectId, options);
1413
- return page.mailboxes;
1368
+ const mailboxes = [];
1369
+ let continuationToken;
1370
+ do {
1371
+ const page = await this.listMailboxesPage(projectId, { ...options, continuationToken });
1372
+ mailboxes.push(...page.mailboxes);
1373
+ continuationToken = page.continuationToken ?? undefined;
1374
+ } while (continuationToken);
1375
+ return mailboxes;
1414
1376
  }
1415
1377
  async deleteMailbox(projectId, address) {
1416
1378
  await this.request(`/accounts/projects/${projectId}/mailboxes/${address}`, {
@@ -1457,18 +1419,24 @@ export class Meshagent {
1457
1419
  return this.parseFeed(data.feed);
1458
1420
  }
1459
1421
  async listFeedsPage(projectId, options = {}) {
1460
- const { count = 100, offset = 0, filter } = options;
1422
+ const { pageSize = 100, continuationToken, filter, view } = options;
1461
1423
  const data = await this.request(`/accounts/projects/${projectId}/feeds`, {
1462
- query: { count, offset, filter },
1424
+ query: { page_size: pageSize, continuation_token: continuationToken, filter, view },
1463
1425
  action: "list feeds",
1464
1426
  });
1465
1427
  const feeds = Array.isArray(data?.feeds) ? data.feeds : [];
1466
1428
  const parsed = feeds.map((item) => this.parseFeed(item));
1467
- return { feeds: parsed, total: typeof data?.total === "number" ? data.total : parsed.length };
1429
+ return { feeds: parsed, total: typeof data?.total === "number" ? data.total : parsed.length, continuationToken: data.continuation_token ?? null };
1468
1430
  }
1469
1431
  async listFeeds(projectId, options = {}) {
1470
- const page = await this.listFeedsPage(projectId, options);
1471
- return page.feeds;
1432
+ const feeds = [];
1433
+ let continuationToken;
1434
+ do {
1435
+ const page = await this.listFeedsPage(projectId, { ...options, continuationToken });
1436
+ feeds.push(...page.feeds);
1437
+ continuationToken = page.continuationToken ?? undefined;
1438
+ } while (continuationToken);
1439
+ return feeds;
1472
1440
  }
1473
1441
  async listRoomFeedsPage(projectId, roomName, options = {}) {
1474
1442
  const { count = 100, offset = 0, filter } = options;
@@ -1627,12 +1595,28 @@ export class Meshagent {
1627
1595
  });
1628
1596
  return this.parseProjectRepository(data);
1629
1597
  }
1630
- async listRepositories(projectId) {
1598
+ async listRepositoriesPage(projectId, options = {}) {
1599
+ const { pageSize = 100, view, continuationToken } = options;
1631
1600
  const data = await this.request(`/accounts/projects/${projectId}/repositories`, {
1601
+ query: { page_size: pageSize, view, continuation_token: continuationToken },
1632
1602
  action: "list repositories",
1633
1603
  });
1634
1604
  const repositories = Array.isArray(data?.repositories) ? data.repositories : [];
1635
- return repositories.map((item) => this.parseProjectRepository(item));
1605
+ return {
1606
+ repositories: repositories.map((item) => this.parseProjectRepository(item)),
1607
+ total: Number(data.total ?? repositories.length),
1608
+ continuationToken: data.continuation_token ?? null,
1609
+ };
1610
+ }
1611
+ async listRepositories(projectId, options = {}) {
1612
+ const repositories = [];
1613
+ let continuationToken;
1614
+ do {
1615
+ const page = await this.listRepositoriesPage(projectId, { view: options.view, continuationToken });
1616
+ repositories.push(...page.repositories);
1617
+ continuationToken = page.continuationToken ?? undefined;
1618
+ } while (continuationToken);
1619
+ return repositories;
1636
1620
  }
1637
1621
  async deleteRepository(projectId, repositoryId) {
1638
1622
  await this.request(`/accounts/projects/${projectId}/repositories/${repositoryId}`, {
@@ -1722,279 +1706,14 @@ export class Meshagent {
1722
1706
  responseType: "void",
1723
1707
  });
1724
1708
  }
1725
- async createProjectSecret(params) {
1726
- const { projectId, name, type, data } = params;
1727
- const payload = await this.request(`/accounts/projects/${projectId}/secrets`, {
1728
- method: "POST",
1729
- json: {
1730
- name,
1731
- type,
1732
- data_base64: bytesToBase64(normalizeBinary(data)),
1733
- },
1734
- action: "create project secret",
1735
- });
1736
- if (!payload || typeof payload !== "object" || typeof payload.id !== "string") {
1737
- throw new RoomException("Invalid create project secret response payload");
1738
- }
1739
- return payload.id;
1740
- }
1741
- async updateProjectSecret(params) {
1742
- const { projectId, secretId, name, type, data } = params;
1743
- await this.request(`/accounts/projects/${projectId}/secrets/${secretId}`, {
1744
- method: "PUT",
1745
- json: {
1746
- name,
1747
- type,
1748
- data_base64: bytesToBase64(normalizeBinary(data)),
1749
- },
1750
- action: "update project secret",
1751
- responseType: "void",
1752
- });
1753
- }
1754
- async getProjectSecret(projectId, secretId) {
1755
- const data = await this.request(`/accounts/projects/${projectId}/secrets/${secretId}`, {
1756
- action: "fetch project secret",
1757
- });
1758
- return this.parseManagedSecret(data);
1759
- }
1760
- async listProjectSecrets(projectId) {
1761
- const data = await this.request(`/accounts/projects/${projectId}/secrets`, {
1762
- action: "list project secrets",
1763
- });
1764
- const secrets = Array.isArray(data?.secrets) ? data.secrets : [];
1765
- return secrets.map((item) => this.parseManagedSecretInfo(item));
1766
- }
1767
- async deleteProjectSecret(projectId, secretId) {
1768
- await this.request(`/accounts/projects/${projectId}/secrets/${secretId}`, {
1769
- method: "DELETE",
1770
- action: "delete project secret",
1771
- responseType: "void",
1772
- });
1773
- }
1774
- async createRoomSecret(params) {
1775
- const { projectId, roomName, data, secretId, name, type, delegatedTo, forIdentity } = params;
1776
- const payload = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/secrets`, {
1777
- method: "POST",
1778
- json: {
1779
- data_base64: bytesToBase64(normalizeBinary(data)),
1780
- secret_id: secretId,
1781
- name,
1782
- type,
1783
- delegated_to: delegatedTo,
1784
- for_identity: forIdentity,
1785
- },
1786
- action: "create room secret",
1787
- });
1788
- if (!payload || typeof payload !== "object" || typeof payload.id !== "string") {
1789
- throw new RoomException("Invalid create room secret response payload");
1790
- }
1791
- return payload.id;
1792
- }
1793
- async updateRoomSecret(params) {
1794
- const { projectId, roomName, secretId, data, name, type, delegatedTo, forIdentity } = params;
1795
- await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/secrets/${secretId}`, {
1796
- method: "PUT",
1797
- json: {
1798
- data_base64: bytesToBase64(normalizeBinary(data)),
1799
- name,
1800
- type,
1801
- delegated_to: delegatedTo,
1802
- for_identity: forIdentity,
1803
- },
1804
- action: "update room secret",
1805
- responseType: "void",
1806
- });
1807
- }
1808
- async getRoomSecret(params) {
1809
- const { projectId, roomName, secretId, delegatedTo, forIdentity } = params;
1810
- const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/secrets/${secretId}`, {
1811
- query: {
1812
- delegated_to: delegatedTo,
1813
- for_identity: forIdentity,
1814
- },
1815
- action: "fetch room secret",
1816
- });
1817
- return this.parseManagedSecret(data);
1818
- }
1819
- async listRoomSecrets(params) {
1820
- const { projectId, roomName, forIdentity } = params;
1821
- const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/secrets`, {
1822
- query: {
1823
- for_identity: forIdentity,
1824
- },
1825
- action: "list room secrets",
1826
- });
1827
- const secrets = Array.isArray(data?.secrets) ? data.secrets : [];
1828
- return secrets.map((item) => this.parseManagedSecretInfo(item));
1829
- }
1830
- async deleteRoomSecret(params) {
1831
- const { projectId, roomName, secretId, delegatedTo, forIdentity } = params;
1832
- await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/secrets/${secretId}`, {
1833
- method: "DELETE",
1834
- query: {
1835
- delegated_to: delegatedTo,
1836
- for_identity: forIdentity,
1837
- },
1838
- action: "delete room secret",
1839
- responseType: "void",
1840
- });
1841
- }
1842
- async createSecret(projectId, secret) {
1843
- await this.createProjectSecret({
1844
- projectId,
1845
- name: secret.name,
1846
- type: secret.type,
1847
- data: encoder.encode(JSON.stringify(this.toSecretPayload(secret).data)),
1848
- });
1849
- }
1850
- async updateSecret(projectId, secret) {
1851
- if (!secret.id) {
1852
- throw new RoomException("Secret id is required to update a secret");
1853
- }
1854
- await this.updateProjectSecret({
1855
- projectId,
1856
- secretId: secret.id,
1857
- name: secret.name,
1858
- type: secret.type,
1859
- data: encoder.encode(JSON.stringify(this.toSecretPayload(secret).data)),
1860
- });
1861
- }
1862
- async deleteSecret(projectId, secretId) {
1863
- await this.deleteProjectSecret(projectId, secretId);
1864
- }
1865
- async listSecrets(projectId) {
1866
- const secretInfos = await this.listProjectSecrets(projectId);
1867
- const secrets = await Promise.all(secretInfos.map(async (secretInfo) => {
1868
- const secret = await this.getProjectSecret(projectId, secretInfo.id);
1869
- return this.parseSecretPayload(secret, secret.data);
1870
- }));
1871
- return secrets;
1872
- }
1873
- async createProjectExternalOAuthRegistration(params) {
1874
- const { projectId, oauth, clientId, clientSecret, delegatedTo, connector } = params;
1875
- const payload = await this.request(`/accounts/projects/${projectId}/external-oauth`, {
1876
- method: "POST",
1877
- json: {
1878
- oauth,
1879
- client_id: clientId,
1880
- client_secret: clientSecret,
1881
- delegated_to: delegatedTo,
1882
- connector: this.serializeConnectorRef(connector),
1883
- },
1884
- action: "create project external oauth registration",
1885
- });
1886
- if (!payload || typeof payload !== "object" || typeof payload.id !== "string") {
1887
- throw new RoomException("Invalid create project external oauth registration response payload");
1888
- }
1889
- return payload.id;
1890
- }
1891
- async updateProjectExternalOAuthRegistration(params) {
1892
- const { projectId, registrationId, oauth, clientId, clientSecret, delegatedTo, connector } = params;
1893
- await this.request(`/accounts/projects/${projectId}/external-oauth/${registrationId}`, {
1894
- method: "PUT",
1895
- json: {
1896
- oauth,
1897
- client_id: clientId,
1898
- client_secret: clientSecret,
1899
- delegated_to: delegatedTo,
1900
- connector: this.serializeConnectorRef(connector),
1901
- },
1902
- action: "update project external oauth registration",
1903
- responseType: "void",
1904
- });
1905
- }
1906
- async listProjectExternalOAuthRegistrations(params) {
1907
- const { projectId, delegatedTo } = params;
1908
- const data = await this.request(`/accounts/projects/${projectId}/external-oauth`, {
1909
- query: {
1910
- delegated_to: delegatedTo,
1911
- },
1912
- action: "list project external oauth registrations",
1913
- });
1914
- const registrations = Array.isArray(data?.registrations) ? data.registrations : [];
1915
- return registrations.map((item) => this.parseExternalOAuthClientRegistration(item));
1916
- }
1917
- async deleteProjectExternalOAuthRegistration(params) {
1918
- const { projectId, registrationId, delegatedTo } = params;
1919
- await this.request(`/accounts/projects/${projectId}/external-oauth/${registrationId}`, {
1920
- method: "DELETE",
1921
- query: {
1922
- delegated_to: delegatedTo,
1923
- },
1924
- action: "delete project external oauth registration",
1925
- responseType: "void",
1926
- });
1927
- }
1928
- async createRoomExternalOAuthRegistration(params) {
1929
- const { projectId, roomName, oauth, clientId, clientSecret, delegatedTo, connector } = params;
1930
- const payload = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/external-oauth`, {
1931
- method: "POST",
1932
- json: {
1933
- oauth,
1934
- client_id: clientId,
1935
- client_secret: clientSecret,
1936
- delegated_to: delegatedTo,
1937
- connector: this.serializeConnectorRef(connector),
1938
- },
1939
- action: "create room external oauth registration",
1940
- });
1941
- if (!payload || typeof payload !== "object" || typeof payload.id !== "string") {
1942
- throw new RoomException("Invalid create room external oauth registration response payload");
1943
- }
1944
- return payload.id;
1945
- }
1946
- async updateRoomExternalOAuthRegistration(params) {
1947
- const { projectId, roomName, registrationId, oauth, clientId, clientSecret, delegatedTo, connector } = params;
1948
- await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/external-oauth/${registrationId}`, {
1949
- method: "PUT",
1950
- json: {
1951
- oauth,
1952
- client_id: clientId,
1953
- client_secret: clientSecret,
1954
- delegated_to: delegatedTo,
1955
- connector: this.serializeConnectorRef(connector),
1956
- },
1957
- action: "update room external oauth registration",
1958
- responseType: "void",
1959
- });
1960
- }
1961
- async listRoomExternalOAuthRegistrations(params) {
1962
- const { projectId, roomName, delegatedTo } = params;
1963
- const data = await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/external-oauth`, {
1964
- query: {
1965
- delegated_to: delegatedTo,
1966
- },
1967
- action: "list room external oauth registrations",
1968
- });
1969
- const registrations = Array.isArray(data?.registrations) ? data.registrations : [];
1970
- return registrations.map((item) => this.parseExternalOAuthClientRegistration(item));
1971
- }
1972
- async deleteRoomExternalOAuthRegistration(params) {
1973
- const { projectId, roomName, registrationId, delegatedTo } = params;
1974
- await this.request(`/accounts/projects/${projectId}/rooms/${roomName}/external-oauth/${registrationId}`, {
1975
- method: "DELETE",
1976
- query: {
1977
- delegated_to: delegatedTo,
1978
- },
1979
- action: "delete room external oauth registration",
1980
- responseType: "void",
1981
- });
1982
- }
1983
1709
  async createRoom(params) {
1984
- const { projectId, name, ifNotExists = false, metadata, annotations, permissions } = params;
1710
+ const { projectId, name, ifNotExists = false, metadata, annotations } = params;
1985
1711
  const payload = {
1986
1712
  name,
1987
1713
  if_not_exists: Boolean(ifNotExists),
1988
1714
  metadata,
1989
1715
  annotations,
1990
1716
  };
1991
- if (permissions) {
1992
- const serialized = {};
1993
- for (const [key, value] of Object.entries(permissions)) {
1994
- serialized[key] = value instanceof ApiScope ? value.toJSON() : value;
1995
- }
1996
- payload["permissions"] = serialized;
1997
- }
1998
1717
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
1999
1718
  method: "POST",
2000
1719
  json: payload,
@@ -2030,78 +1749,103 @@ export class Meshagent {
2030
1749
  responseType: "void",
2031
1750
  });
2032
1751
  }
2033
- async connectRoom(projectId, room) {
2034
- const data = await this.request(`/accounts/projects/${projectId}/rooms/${room}/connect`, {
1752
+ async createGroup(params) {
1753
+ const { projectId, name, metadata, annotations } = params;
1754
+ const data = await this.request(`/accounts/projects/${projectId}/groups`, {
2035
1755
  method: "POST",
2036
- json: {},
2037
- action: "connect room",
1756
+ json: { name, metadata, annotations },
1757
+ action: "create group",
2038
1758
  });
2039
- return this.parseRoomConnectionInfo(data);
1759
+ return this.parseGroup(data);
2040
1760
  }
2041
- async createRoomGrant(params) {
2042
- const { projectId, roomId, userId, permissions } = params;
2043
- await this.request(`/accounts/projects/${projectId}/room-grants`, {
2044
- method: "POST",
2045
- json: {
2046
- room_id: roomId,
2047
- user_id: userId,
2048
- permissions: permissions.toJSON(),
2049
- },
2050
- action: "create room grant",
1761
+ async getGroup(projectId, groupId) {
1762
+ const data = await this.request(`/accounts/projects/${projectId}/groups/${groupId}`, {
1763
+ action: "fetch group",
1764
+ });
1765
+ return this.parseGroup(data);
1766
+ }
1767
+ async updateGroup(projectId, groupId, name, options = {}) {
1768
+ const payload = { name };
1769
+ if (options.metadata !== undefined) {
1770
+ payload["metadata"] = options.metadata;
1771
+ }
1772
+ if (options.annotations !== undefined) {
1773
+ payload["annotations"] = options.annotations;
1774
+ }
1775
+ await this.request(`/accounts/projects/${projectId}/groups/${groupId}`, {
1776
+ method: "PUT",
1777
+ json: payload,
1778
+ action: "update group",
2051
1779
  responseType: "void",
2052
1780
  });
2053
1781
  }
2054
- async createRoomGrantByEmail(params) {
2055
- const { projectId, roomId, email, permissions, inviteRedirectUrl } = params;
2056
- await this.request(`/accounts/projects/${projectId}/room-grants`, {
2057
- method: "POST",
2058
- json: {
2059
- room_id: roomId,
2060
- email,
2061
- permissions: permissions.toJSON(),
2062
- ...(inviteRedirectUrl !== undefined
2063
- ? { invite_redirect_url: inviteRedirectUrl }
2064
- : {}),
2065
- },
2066
- action: "create room grant",
1782
+ async deleteGroup(projectId, groupId) {
1783
+ await this.request(`/accounts/projects/${projectId}/groups/${groupId}`, {
1784
+ method: "DELETE",
1785
+ action: "delete group",
2067
1786
  responseType: "void",
2068
1787
  });
2069
1788
  }
2070
- async updateRoomGrant(params) {
2071
- const { projectId, roomId, userId, permissions, grantId } = params;
2072
- const gid = grantId ?? "unused";
2073
- await this.request(`/accounts/projects/${projectId}/room-grants/${gid}`, {
2074
- method: "PUT",
2075
- json: {
2076
- room_id: roomId,
2077
- user_id: userId,
2078
- permissions: permissions.toJSON(),
1789
+ async listGroupsPage(projectId, options = {}) {
1790
+ const data = await this.request(`/accounts/projects/${projectId}/groups`, {
1791
+ query: {
1792
+ page_size: options.pageSize ?? 50,
1793
+ continuation_token: options.continuationToken,
1794
+ filter: options.filter,
2079
1795
  },
2080
- action: "update room grant",
1796
+ action: "list groups",
1797
+ });
1798
+ const groups = Array.isArray(data?.groups) ? data.groups : [];
1799
+ return {
1800
+ groups: groups.map((item) => this.parseGroup(item)),
1801
+ continuationToken: data?.continuation_token ?? null,
1802
+ };
1803
+ }
1804
+ async listGroups(projectId, options = {}) {
1805
+ const page = await this.listGroupsPage(projectId, options);
1806
+ return page.groups;
1807
+ }
1808
+ async setGroupMember(params) {
1809
+ const { projectId, groupId, subject, role = "member" } = params;
1810
+ await this.request(`/accounts/projects/${projectId}/groups/${groupId}/members`, {
1811
+ method: "POST",
1812
+ json: { subject, role },
1813
+ action: "set group member",
2081
1814
  responseType: "void",
2082
1815
  });
2083
1816
  }
2084
- async deleteRoomGrant(projectId, roomId, userId) {
2085
- const room = this.encodePathComponent(roomId);
2086
- const user = this.encodePathComponent(userId);
2087
- await this.request(`/accounts/projects/${projectId}/room-grants/${room}/${user}`, {
1817
+ async listGroupMembersPage(projectId, groupId, options = {}) {
1818
+ const data = await this.request(`/accounts/projects/${projectId}/groups/${groupId}/members`, {
1819
+ query: { page_size: options.pageSize ?? 50, continuation_token: options.continuationToken },
1820
+ action: "list group members",
1821
+ });
1822
+ const members = Array.isArray(data?.members) ? data.members : [];
1823
+ return { members: members.map((item) => this.parseGroupMember(item)), continuationToken: data?.continuation_token ?? null };
1824
+ }
1825
+ async listGroupMembers(projectId, groupId, options = {}) {
1826
+ const page = await this.listGroupMembersPage(projectId, groupId, options);
1827
+ return page.members;
1828
+ }
1829
+ async deleteGroupMember(params) {
1830
+ const { projectId, groupId, subjectType, subjectId } = params;
1831
+ await this.request(`/accounts/projects/${projectId}/groups/${groupId}/members/${subjectType}/${subjectId}`, {
2088
1832
  method: "DELETE",
2089
- action: "delete room grant",
1833
+ action: "delete group member",
2090
1834
  responseType: "void",
2091
1835
  });
2092
1836
  }
2093
- async getRoomGrant(projectId, roomId, userId) {
2094
- const room = this.encodePathComponent(roomId);
2095
- const user = this.encodePathComponent(userId);
2096
- const data = await this.request(`/accounts/projects/${projectId}/room-grants/${room}/${user}`, {
2097
- action: "fetch room grant",
1837
+ async connectRoom(projectId, room) {
1838
+ const data = await this.request(`/accounts/projects/${projectId}/rooms/${room}/connect`, {
1839
+ method: "POST",
1840
+ json: {},
1841
+ action: "connect room",
2098
1842
  });
2099
- return this.parseProjectRoomGrant(data);
1843
+ return this.parseRoomConnectionInfo(data);
2100
1844
  }
2101
1845
  async listRooms(projectId, options = {}) {
2102
- const { limit = 50, offset = 0, orderBy = "room_name" } = options;
1846
+ const { pageSize = 50, continuationToken, filter, view } = options;
2103
1847
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
2104
- query: { limit, offset, order_by: orderBy },
1848
+ query: { page_size: pageSize, continuation_token: continuationToken, filter, view },
2105
1849
  action: "list rooms",
2106
1850
  });
2107
1851
  const rooms = Array.isArray(data?.rooms) ? data.rooms : [];
@@ -2132,16 +1876,23 @@ export class Meshagent {
2132
1876
  return this.parseRoute(data.route);
2133
1877
  }
2134
1878
  async listRoutesPage(projectId, options = {}) {
2135
- const { count = 100, offset = 0, filter } = options;
1879
+ const { pageSize = 100, continuationToken, filter } = options;
2136
1880
  const data = await this.request(`/accounts/projects/${projectId}/routes`, {
2137
- query: { count, offset, filter },
1881
+ query: { page_size: pageSize, continuation_token: continuationToken, filter },
2138
1882
  action: "list routes",
2139
1883
  });
2140
1884
  const routes = Array.isArray(data.routes) ? data.routes.map((item) => this.parseRoute(item)) : [];
2141
- return { routes, total: Number(data.total ?? routes.length) };
1885
+ return { routes, total: Number(data.total ?? routes.length), continuationToken: data.continuation_token ?? null };
2142
1886
  }
2143
1887
  async listRoutes(projectId, options = {}) {
2144
- return (await this.listRoutesPage(projectId, options)).routes;
1888
+ const routes = [];
1889
+ let continuationToken;
1890
+ do {
1891
+ const page = await this.listRoutesPage(projectId, { ...options, continuationToken });
1892
+ routes.push(...page.routes);
1893
+ continuationToken = page.continuationToken ?? undefined;
1894
+ } while (continuationToken);
1895
+ return routes;
2145
1896
  }
2146
1897
  async listRoomRoutesPage(params) {
2147
1898
  const { projectId, roomName, count = 100, offset = 0, filter } = params;
@@ -2177,63 +1928,115 @@ export class Meshagent {
2177
1928
  responseType: "void",
2178
1929
  });
2179
1930
  }
2180
- async listRoomGrants(projectId, options = {}) {
2181
- const { limit = 50, offset = 0, orderBy = "room_name" } = options;
2182
- const data = await this.request(`/accounts/projects/${projectId}/room-grants`, {
2183
- query: { limit, offset, order_by: orderBy },
2184
- action: "list room grants",
1931
+ async testAccess(projectId, params) {
1932
+ const data = await this.request(`/accounts/projects/${projectId}/access:test`, {
1933
+ method: "POST",
1934
+ json: {
1935
+ subject: this.serializeAccessSubject(params.subject),
1936
+ resource: this.serializeAccessResource(params.resource),
1937
+ relation: params.relation,
1938
+ },
1939
+ action: "test access",
1940
+ });
1941
+ return {
1942
+ allowed: data?.allowed === true,
1943
+ resource: data?.resource && typeof data.resource === "object" ? this.parseAccessResource(data.resource) : undefined,
1944
+ subject: data?.subject && typeof data.subject === "object" ? this.parseAccessSubject(data.subject) : undefined,
1945
+ relation: typeof data?.relation === "string" ? data.relation : undefined,
1946
+ };
1947
+ }
1948
+ async getEffectiveAccess(projectId, params) {
1949
+ const data = await this.request(`/accounts/projects/${projectId}/access:effective`, {
1950
+ method: "POST",
1951
+ json: {
1952
+ subject: this.serializeAccessSubject(params.subject),
1953
+ resource: this.serializeAccessResource(params.resource),
1954
+ ...(params.relations ? { relations: params.relations } : {}),
1955
+ },
1956
+ action: "get effective access",
2185
1957
  });
2186
- const grants = Array.isArray(data?.room_grants) ? data.room_grants : [];
2187
- return grants.map((item) => this.parseProjectRoomGrant(item));
1958
+ return {
1959
+ resource: this.parseAccessResource(data?.resource),
1960
+ subject: this.parseAccessSubject(data?.subject),
1961
+ effectiveRoles: Array.isArray(data?.effective_roles) ? data.effective_roles.filter((item) => typeof item === "string") : [],
1962
+ capabilities: data?.capabilities && typeof data.capabilities === "object" ? data.capabilities : {},
1963
+ };
1964
+ }
1965
+ async listAccessBindings(projectId, params) {
1966
+ const page = await this.listAccessBindingsPage(projectId, params);
1967
+ return page.accessGrants;
2188
1968
  }
2189
- async listRoomGrantsByUser(projectId, userId, options = {}) {
2190
- const { limit = 50, offset = 0 } = options;
2191
- const encodedUser = this.encodePathComponent(userId);
2192
- const data = await this.request(`/accounts/projects/${projectId}/room-grants/by-user/${encodedUser}`, {
2193
- query: { limit, offset },
2194
- action: "list room grants by user",
1969
+ async listAccessBindingsPage(projectId, params) {
1970
+ const data = await this.request(`/accounts/projects/${projectId}/access:bindings`, {
1971
+ method: "POST",
1972
+ json: {
1973
+ subject: this.serializeAccessSubject(params.subject),
1974
+ },
1975
+ action: "list access bindings",
2195
1976
  });
2196
- const grants = Array.isArray(data?.room_grants) ? data.room_grants : [];
2197
- return grants.map((item) => this.parseProjectRoomGrant(item));
1977
+ return {
1978
+ accessGrants: Array.isArray(data?.access_grants)
1979
+ ? data.access_grants.map((item) => this.parseProjectRoomGrant(item))
1980
+ : [],
1981
+ };
2198
1982
  }
2199
- async listRoomGrantsByRoom(projectId, roomId, options = {}) {
2200
- const { limit = 50, offset = 0 } = options;
2201
- const encodedRoom = this.encodePathComponent(roomId);
2202
- const data = await this.request(`/accounts/projects/${projectId}/room-grants/by-room/${encodedRoom}`, {
2203
- query: { limit, offset },
2204
- action: "list room grants by room",
1983
+ async getResourcePolicyPage(projectId, params) {
1984
+ this.validateResourcePolicyType(params.resourceType);
1985
+ const data = await this.request(`/accounts/projects/${projectId}/iam/${params.resourceType}/${params.resourceId}/policy`, {
1986
+ method: "GET",
1987
+ query: { page_size: params.pageSize ?? 50, continuation_token: params.continuationToken },
1988
+ action: "get resource policy",
2205
1989
  });
2206
- const grants = Array.isArray(data?.room_grants) ? data.room_grants : [];
2207
- return grants.map((item) => this.parseProjectRoomGrant(item));
1990
+ return {
1991
+ resource: this.parseAccessResource(data?.resource),
1992
+ accessGrants: Array.isArray(data?.access_grants)
1993
+ ? data.access_grants.map((item) => this.parseProjectRoomGrant(item))
1994
+ : [],
1995
+ continuationToken: typeof data?.continuation_token === "string" ? data.continuation_token : null,
1996
+ };
2208
1997
  }
2209
- async listUniqueRoomsWithGrants(projectId, options = {}) {
2210
- const { limit = 50, offset = 0 } = options;
2211
- const data = await this.request(`/accounts/projects/${projectId}/room-grants/by-room`, {
2212
- query: { limit, offset },
2213
- action: "list unique rooms with grants",
1998
+ async getResourcePolicy(projectId, params) {
1999
+ const grants = [];
2000
+ let continuationToken = params.continuationToken;
2001
+ do {
2002
+ const page = await this.getResourcePolicyPage(projectId, { ...params, continuationToken });
2003
+ grants.push(...page.accessGrants);
2004
+ continuationToken = page.continuationToken ?? undefined;
2005
+ } while (continuationToken);
2006
+ return grants;
2007
+ }
2008
+ async grantResourcePolicy(projectId, params) {
2009
+ this.validateResourcePolicyType(params.resourceType);
2010
+ await this.request(`/accounts/projects/${projectId}/iam/${params.resourceType}/${params.resourceId}/policy:grant`, {
2011
+ method: "POST",
2012
+ json: {
2013
+ subject: this.serializeAccessSubject(params.subject),
2014
+ roles: params.roles,
2015
+ ...(params.inviteRedirectUrl ? { invite_redirect_url: params.inviteRedirectUrl } : {}),
2016
+ },
2017
+ action: "grant resource policy",
2214
2018
  });
2215
- const rooms = Array.isArray(data?.rooms) ? data.rooms : [];
2216
- return rooms.map((item) => this.parseProjectRoomGrantCount(item));
2217
2019
  }
2218
- async listUniqueUsersWithGrantsPage(projectId, options = {}) {
2219
- const { limit = 100, offset = 0, filter } = options;
2220
- const data = await this.request(`/accounts/projects/${projectId}/room-grants/by-user`, {
2221
- query: { limit, offset, filter },
2222
- action: "list unique users with grants",
2020
+ async revokeResourcePolicy(projectId, params) {
2021
+ this.validateResourcePolicyType(params.resourceType);
2022
+ await this.request(`/accounts/projects/${projectId}/iam/${params.resourceType}/${params.resourceId}/policy:revoke`, {
2023
+ method: "POST",
2024
+ json: {
2025
+ subject: this.serializeAccessSubject(params.subject),
2026
+ },
2027
+ action: "revoke resource policy",
2223
2028
  });
2224
- const users = Array.isArray(data?.users) ? data.users : [];
2225
- const parsed = users.map((item) => this.parseProjectUserGrantCount(item));
2226
- return { users: parsed, total: typeof data?.total === "number" ? data.total : parsed.length };
2227
2029
  }
2228
- async listUniqueUsersWithGrants(projectId, options = {}) {
2229
- const page = await this.listUniqueUsersWithGrantsPage(projectId, options);
2230
- return page.users;
2030
+ validateResourcePolicyType(resourceType) {
2031
+ if (resourceType === "agent") {
2032
+ throw new Error("managed agent resource policies are not supported; use agent run_as instead");
2033
+ }
2231
2034
  }
2232
2035
  async createOAuthClient(projectId, params) {
2233
- const { grantTypes, responseTypes, redirectUris, scope, metadata = {} } = params;
2036
+ const { grantTypes, responseTypes, redirectUris, scope, metadata = {}, official = false } = params;
2234
2037
  const data = await this.request(`/accounts/projects/${projectId}/oauth/clients`, {
2235
2038
  method: "POST",
2236
- json: { grant_types: grantTypes, response_types: responseTypes, redirect_uris: redirectUris, scope, metadata },
2039
+ json: { grant_types: grantTypes, response_types: responseTypes, redirect_uris: redirectUris, scope, metadata, official },
2237
2040
  action: "create oauth client",
2238
2041
  });
2239
2042
  return this.parseOAuthClient(data);