@meshagent/meshagent 0.35.6 → 0.35.8

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 (47) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/containers-client.d.ts +79 -2
  3. package/dist/browser/containers-client.js +341 -19
  4. package/dist/browser/database-client.d.ts +95 -24
  5. package/dist/browser/database-client.js +150 -49
  6. package/dist/browser/messaging-client.d.ts +33 -52
  7. package/dist/browser/messaging-client.js +180 -184
  8. package/dist/browser/participant.d.ts +5 -3
  9. package/dist/browser/participant.js +9 -1
  10. package/dist/browser/room-client.js +2 -0
  11. package/dist/browser/room-event.d.ts +6 -2
  12. package/dist/browser/room-event.js +4 -2
  13. package/dist/browser/secrets-client.d.ts +86 -16
  14. package/dist/browser/secrets-client.js +243 -44
  15. package/dist/browser/storage-client.d.ts +17 -4
  16. package/dist/browser/storage-client.js +104 -16
  17. package/dist/esm/containers-client.d.ts +79 -2
  18. package/dist/esm/containers-client.js +341 -19
  19. package/dist/esm/database-client.d.ts +95 -24
  20. package/dist/esm/database-client.js +150 -49
  21. package/dist/esm/messaging-client.d.ts +33 -52
  22. package/dist/esm/messaging-client.js +179 -180
  23. package/dist/esm/participant.d.ts +5 -3
  24. package/dist/esm/participant.js +9 -1
  25. package/dist/esm/room-client.js +2 -0
  26. package/dist/esm/room-event.d.ts +6 -2
  27. package/dist/esm/room-event.js +4 -2
  28. package/dist/esm/secrets-client.d.ts +86 -16
  29. package/dist/esm/secrets-client.js +243 -44
  30. package/dist/esm/storage-client.d.ts +17 -4
  31. package/dist/esm/storage-client.js +103 -16
  32. package/dist/node/containers-client.d.ts +79 -2
  33. package/dist/node/containers-client.js +341 -19
  34. package/dist/node/database-client.d.ts +95 -24
  35. package/dist/node/database-client.js +150 -49
  36. package/dist/node/messaging-client.d.ts +33 -52
  37. package/dist/node/messaging-client.js +180 -184
  38. package/dist/node/participant.d.ts +5 -3
  39. package/dist/node/participant.js +9 -1
  40. package/dist/node/room-client.js +2 -0
  41. package/dist/node/room-event.d.ts +6 -2
  42. package/dist/node/room-event.js +4 -2
  43. package/dist/node/secrets-client.d.ts +86 -16
  44. package/dist/node/secrets-client.js +243 -44
  45. package/dist/node/storage-client.d.ts +17 -4
  46. package/dist/node/storage-client.js +104 -16
  47. package/package.json +1 -1
@@ -1,37 +1,107 @@
1
- import { RoomClient } from "./room-client";
1
+ import type { ConnectorRef, OAuthClientConfig } from "./meshagent-client";
2
2
  import { FileContent } from "./response";
3
+ import { RoomClient } from "./room-client";
3
4
  export interface SecretInfo {
4
5
  id: string;
5
6
  name: string;
6
- type?: string;
7
+ type: string;
7
8
  delegatedTo?: string | null;
8
9
  }
10
+ export interface OAuthTokenRequest {
11
+ requestId: string;
12
+ authorizationEndpoint: string;
13
+ tokenEndpoint: string;
14
+ challenge?: string | null;
15
+ scopes?: string[] | null;
16
+ clientId?: string | null;
17
+ }
18
+ export type OAuthTokenRequestHandler = (request: OAuthTokenRequest) => Promise<void> | void;
19
+ export interface SecretRequest {
20
+ requestId: string;
21
+ url: string;
22
+ type: string;
23
+ delegateTo?: string | null;
24
+ }
25
+ export type SecretRequestHandler = (request: SecretRequest) => Promise<void> | void;
9
26
  export declare class SecretsClient {
10
- private client;
11
- constructor({ room }: {
27
+ private readonly client;
28
+ private readonly oauthTokenRequestHandler?;
29
+ private readonly secretRequestHandler?;
30
+ private readonly _oauthRequestHandler;
31
+ private readonly _secretRequestHandler;
32
+ constructor({ room, oauthTokenRequestHandler, secretRequestHandler, }: {
12
33
  room: RoomClient;
34
+ oauthTokenRequestHandler?: OAuthTokenRequestHandler;
35
+ secretRequestHandler?: SecretRequestHandler;
13
36
  });
14
37
  private unexpectedResponse;
15
- setSecret({ secretId, data, mimeType, name, delegatedTo, forIdentity, }: {
16
- secretId: string;
38
+ private invoke;
39
+ private serializeConnectorRef;
40
+ private serializeOAuthConfig;
41
+ private parseAccessToken;
42
+ private parseSecretInfo;
43
+ private _handleClientOAuthTokenRequest;
44
+ private _handleClientSecretRequest;
45
+ provideOAuthAuthorization({ requestId, code, }: {
46
+ requestId: string;
47
+ code: string;
48
+ }): Promise<void>;
49
+ rejectOAuthAuthorization({ requestId, error, }: {
50
+ requestId: string;
51
+ error: string;
52
+ }): Promise<void>;
53
+ provideSecret({ requestId, data, }: {
54
+ requestId: string;
17
55
  data: Uint8Array;
18
- mimeType?: string;
19
- name?: string;
20
- delegatedTo?: string;
21
- forIdentity?: string;
22
56
  }): Promise<void>;
23
- getSecret({ secretId, delegatedTo, }: {
24
- secretId: string;
25
- delegatedTo?: string;
26
- }): Promise<FileContent | null>;
57
+ rejectSecret({ requestId, error, }: {
58
+ requestId: string;
59
+ error: string;
60
+ }): Promise<void>;
61
+ getOfflineOAuthToken({ connector, oauth, delegatedTo, delegatedBy, }: {
62
+ connector?: ConnectorRef | null;
63
+ oauth?: OAuthClientConfig | null;
64
+ delegatedTo?: string | null;
65
+ delegatedBy?: string | null;
66
+ }): Promise<string | null>;
67
+ requestOAuthToken({ connector, oauth, timeout, fromParticipantId, redirectUri, delegateTo, }: {
68
+ connector?: ConnectorRef | null;
69
+ oauth?: OAuthClientConfig | null;
70
+ timeout?: number;
71
+ fromParticipantId: string;
72
+ redirectUri: string | URL;
73
+ delegateTo?: string | null;
74
+ }): Promise<string | null>;
27
75
  listSecrets(): Promise<SecretInfo[]>;
28
76
  deleteSecret({ secretId, delegatedTo, }: {
29
77
  secretId: string;
30
- delegatedTo?: string;
78
+ delegatedTo?: string | null;
31
79
  }): Promise<void>;
32
80
  deleteRequestedSecret({ url, type, delegatedTo, }: {
33
81
  url: string;
34
82
  type: string;
35
- delegatedTo?: string;
83
+ delegatedTo?: string | null;
36
84
  }): Promise<void>;
85
+ requestSecret({ fromParticipantId, url, type, timeout, delegateTo, }: {
86
+ fromParticipantId: string;
87
+ url: string;
88
+ type: string;
89
+ timeout?: number;
90
+ delegateTo?: string | null;
91
+ }): Promise<Uint8Array>;
92
+ setSecret({ secretId, type, mimeType, name, delegatedTo, forIdentity, data, }: {
93
+ secretId?: string | null;
94
+ type?: string | null;
95
+ mimeType?: string | null;
96
+ name?: string | null;
97
+ delegatedTo?: string | null;
98
+ forIdentity?: string | null;
99
+ data: Uint8Array;
100
+ }): Promise<void>;
101
+ getSecret({ secretId, type, name, delegatedTo, }: {
102
+ secretId?: string | null;
103
+ type?: string | null;
104
+ name?: string | null;
105
+ delegatedTo?: string | null;
106
+ }): Promise<FileContent | null>;
37
107
  }
@@ -2,85 +2,284 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SecretsClient = void 0;
4
4
  const response_1 = require("./response");
5
+ const room_server_client_1 = require("./room-server-client");
6
+ const utils_1 = require("./utils");
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
5
10
  class SecretsClient {
6
- constructor({ room }) {
11
+ constructor({ room, oauthTokenRequestHandler, secretRequestHandler, }) {
12
+ this._oauthRequestHandler = this._handleClientOAuthTokenRequest.bind(this);
13
+ this._secretRequestHandler = this._handleClientSecretRequest.bind(this);
7
14
  this.client = room;
15
+ this.oauthTokenRequestHandler = oauthTokenRequestHandler;
16
+ this.secretRequestHandler = secretRequestHandler;
17
+ this.client.protocol.addHandler("secrets.request_oauth_token", this._oauthRequestHandler);
18
+ this.client.protocol.addHandler("secrets.request_secret", this._secretRequestHandler);
8
19
  }
9
20
  unexpectedResponse(operation) {
10
- return new Error(`unexpected return type from secrets.${operation}`);
21
+ return new room_server_client_1.RoomServerException(`unexpected return type from secrets.${operation}`);
11
22
  }
12
- async setSecret({ secretId, data, mimeType, name, delegatedTo, forIdentity, }) {
13
- const response = await this.client.invoke({
23
+ async invoke(operation, input) {
24
+ return await this.client.invoke({
14
25
  toolkit: "secrets",
15
- tool: "set_secret",
16
- input: new response_1.BinaryContent({
17
- data,
18
- headers: {
19
- secret_id: secretId,
20
- type: mimeType ?? null,
21
- name: name ?? null,
22
- delegated_to: delegatedTo ?? null,
23
- for_identity: forIdentity ?? null,
24
- has_data: true,
25
- },
26
- }),
26
+ tool: operation,
27
+ input,
27
28
  });
28
- if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
29
- return;
29
+ }
30
+ serializeConnectorRef(connector) {
31
+ if (connector == null) {
32
+ return null;
30
33
  }
31
- throw this.unexpectedResponse("set_secret");
34
+ return {
35
+ openai_connector_id: connector.openaiConnectorId ?? null,
36
+ server_url: connector.serverUrl ?? null,
37
+ client_secret_id: connector.clientSecretId ?? null,
38
+ };
32
39
  }
33
- async getSecret({ secretId, delegatedTo, }) {
34
- const req = {
35
- secret_id: secretId,
36
- type: null,
37
- name: null,
38
- delegated_to: delegatedTo ?? null,
40
+ serializeOAuthConfig(oauth) {
41
+ if (oauth == null) {
42
+ return null;
43
+ }
44
+ return {
45
+ client_id: oauth.client_id,
46
+ client_secret: oauth.client_secret ?? null,
47
+ authorization_endpoint: oauth.authorization_endpoint,
48
+ token_endpoint: oauth.token_endpoint,
49
+ no_pkce: oauth.no_pkce ?? null,
50
+ scopes: oauth.scopes ?? null,
39
51
  };
40
- const response = await this.client.invoke({ toolkit: "secrets", tool: "get_secret", input: req });
41
- if (response instanceof response_1.EmptyContent) {
52
+ }
53
+ parseAccessToken(operation, response) {
54
+ if (!(response instanceof response_1.JsonContent)) {
55
+ throw this.unexpectedResponse(operation);
56
+ }
57
+ const token = response.json["access_token"];
58
+ if (typeof token !== "string" || token.length === 0) {
42
59
  return null;
43
60
  }
44
- if (response instanceof response_1.FileContent) {
45
- return response;
61
+ return token;
62
+ }
63
+ parseSecretInfo(value) {
64
+ if (!isRecord(value) || typeof value["id"] !== "string" || typeof value["name"] !== "string" || typeof value["type"] !== "string") {
65
+ throw this.unexpectedResponse("list_secrets");
46
66
  }
47
- throw this.unexpectedResponse("get_secret");
67
+ const delegatedTo = value["delegated_to"];
68
+ if (delegatedTo !== undefined && delegatedTo !== null && typeof delegatedTo !== "string") {
69
+ throw this.unexpectedResponse("list_secrets");
70
+ }
71
+ return {
72
+ id: value["id"],
73
+ name: value["name"],
74
+ type: value["type"],
75
+ delegatedTo: delegatedTo,
76
+ };
77
+ }
78
+ async _handleClientOAuthTokenRequest(protocol, messageId, type, bytes) {
79
+ void protocol;
80
+ void messageId;
81
+ void type;
82
+ if (bytes == null) {
83
+ throw new room_server_client_1.RoomServerException("invalid secrets.request_oauth_token payload");
84
+ }
85
+ if (this.oauthTokenRequestHandler == null) {
86
+ throw new room_server_client_1.RoomServerException("No oauth token handler registered");
87
+ }
88
+ const [request] = (0, utils_1.unpackMessage)(bytes);
89
+ const requestId = request["request_id"];
90
+ const challenge = request["challenge"];
91
+ const requestPayload = request["request"];
92
+ if (typeof requestId !== "string" || !isRecord(requestPayload)) {
93
+ throw new room_server_client_1.RoomServerException("invalid secrets.request_oauth_token payload");
94
+ }
95
+ const oauth = requestPayload["oauth"];
96
+ if (!isRecord(oauth) || typeof oauth["authorization_endpoint"] !== "string" || typeof oauth["token_endpoint"] !== "string") {
97
+ throw new room_server_client_1.RoomServerException("invalid secrets.request_oauth_token payload");
98
+ }
99
+ const scopes = oauth["scopes"];
100
+ if (scopes !== undefined && scopes !== null && (!Array.isArray(scopes) || scopes.some((scope) => typeof scope !== "string"))) {
101
+ throw new room_server_client_1.RoomServerException("invalid secrets.request_oauth_token payload");
102
+ }
103
+ Promise.resolve(this.oauthTokenRequestHandler({
104
+ requestId,
105
+ authorizationEndpoint: oauth["authorization_endpoint"],
106
+ tokenEndpoint: oauth["token_endpoint"],
107
+ challenge: typeof challenge === "string" ? challenge : null,
108
+ scopes: scopes ?? null,
109
+ clientId: typeof oauth["client_id"] === "string" ? oauth["client_id"] : null,
110
+ })).catch((error) => {
111
+ console.warn("OAuth token request handler threw", error);
112
+ });
113
+ }
114
+ async _handleClientSecretRequest(protocol, messageId, type, bytes) {
115
+ void protocol;
116
+ void messageId;
117
+ void type;
118
+ if (bytes == null) {
119
+ throw new room_server_client_1.RoomServerException("invalid secrets.request_secret payload");
120
+ }
121
+ if (this.secretRequestHandler == null) {
122
+ throw new room_server_client_1.RoomServerException("No secret handler registered");
123
+ }
124
+ const [request] = (0, utils_1.unpackMessage)(bytes);
125
+ const requestId = request["request_id"];
126
+ const requestPayload = request["request"];
127
+ if (typeof requestId !== "string" || !isRecord(requestPayload) || typeof requestPayload["url"] !== "string" || typeof requestPayload["type"] !== "string") {
128
+ throw new room_server_client_1.RoomServerException("invalid secrets.request_secret payload");
129
+ }
130
+ Promise.resolve(this.secretRequestHandler({
131
+ requestId,
132
+ url: requestPayload["url"],
133
+ type: requestPayload["type"],
134
+ delegateTo: typeof requestPayload["delegate_to"] === "string" ? requestPayload["delegate_to"] : null,
135
+ })).catch((error) => {
136
+ console.warn("Secret request handler threw", error);
137
+ });
138
+ }
139
+ async provideOAuthAuthorization({ requestId, code, }) {
140
+ const response = await this.invoke("provide_oauth_authorization", {
141
+ request_id: requestId,
142
+ code,
143
+ error: null,
144
+ });
145
+ if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
146
+ return;
147
+ }
148
+ throw this.unexpectedResponse("provide_oauth_authorization");
149
+ }
150
+ async rejectOAuthAuthorization({ requestId, error, }) {
151
+ const response = await this.invoke("provide_oauth_authorization", {
152
+ request_id: requestId,
153
+ code: null,
154
+ error,
155
+ });
156
+ if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
157
+ return;
158
+ }
159
+ throw this.unexpectedResponse("provide_oauth_authorization");
160
+ }
161
+ async provideSecret({ requestId, data, }) {
162
+ const response = await this.invoke("provide_secret", new response_1.BinaryContent({
163
+ data,
164
+ headers: {
165
+ request_id: requestId,
166
+ error: null,
167
+ },
168
+ }));
169
+ if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
170
+ return;
171
+ }
172
+ throw this.unexpectedResponse("provide_secret");
173
+ }
174
+ async rejectSecret({ requestId, error, }) {
175
+ const response = await this.invoke("provide_secret", new response_1.BinaryContent({
176
+ data: new Uint8Array(0),
177
+ headers: {
178
+ request_id: requestId,
179
+ error,
180
+ },
181
+ }));
182
+ if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
183
+ return;
184
+ }
185
+ throw this.unexpectedResponse("provide_secret");
186
+ }
187
+ async getOfflineOAuthToken({ connector, oauth, delegatedTo, delegatedBy, }) {
188
+ const response = await this.invoke("get_offline_oauth_token", {
189
+ connector: this.serializeConnectorRef(connector),
190
+ oauth: this.serializeOAuthConfig(oauth),
191
+ delegated_to: delegatedTo ?? null,
192
+ delegated_by: delegatedBy ?? null,
193
+ });
194
+ return this.parseAccessToken("get_offline_oauth_token", response);
195
+ }
196
+ async requestOAuthToken({ connector, oauth, timeout = 60 * 5, fromParticipantId, redirectUri, delegateTo, }) {
197
+ const response = await this.invoke("request_oauth_token", {
198
+ connector: this.serializeConnectorRef(connector),
199
+ oauth: this.serializeOAuthConfig(oauth),
200
+ redirect_uri: typeof redirectUri === "string" ? redirectUri : redirectUri.toString(),
201
+ timeout,
202
+ participant_id: fromParticipantId,
203
+ delegate_to: delegateTo ?? null,
204
+ });
205
+ return this.parseAccessToken("request_oauth_token", response);
48
206
  }
49
207
  async listSecrets() {
50
- const response = await this.client.invoke({ toolkit: "secrets", tool: "list_secrets", input: {} });
208
+ const response = await this.invoke("list_secrets", {});
51
209
  if (!(response instanceof response_1.JsonContent)) {
52
210
  throw this.unexpectedResponse("list_secrets");
53
211
  }
54
- const secrets = Array.isArray(response.json?.secrets) ? response.json.secrets : [];
55
- return secrets.map((item) => ({
56
- id: item.id,
57
- name: item.name,
58
- type: item.type,
59
- delegatedTo: item.delegated_to,
60
- }));
212
+ const secrets = response.json["secrets"];
213
+ if (!Array.isArray(secrets)) {
214
+ throw this.unexpectedResponse("list_secrets");
215
+ }
216
+ return secrets.map((item) => this.parseSecretInfo(item));
61
217
  }
62
218
  async deleteSecret({ secretId, delegatedTo, }) {
63
- const req = {
219
+ const response = await this.invoke("delete_secret", {
64
220
  id: secretId,
65
221
  delegated_to: delegatedTo ?? null,
66
- };
67
- const response = await this.client.invoke({ toolkit: "secrets", tool: "delete_secret", input: req });
222
+ });
68
223
  if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
69
224
  return;
70
225
  }
71
226
  throw this.unexpectedResponse("delete_secret");
72
227
  }
73
228
  async deleteRequestedSecret({ url, type, delegatedTo, }) {
74
- const req = {
229
+ const response = await this.invoke("delete_requested_secret", {
75
230
  url,
76
231
  type,
77
232
  delegated_to: delegatedTo ?? null,
78
- };
79
- const response = await this.client.invoke({ toolkit: "secrets", tool: "delete_requested_secret", input: req });
233
+ });
80
234
  if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
81
235
  return;
82
236
  }
83
237
  throw this.unexpectedResponse("delete_requested_secret");
84
238
  }
239
+ async requestSecret({ fromParticipantId, url, type, timeout = 60 * 5, delegateTo, }) {
240
+ const response = await this.invoke("request_secret", {
241
+ url,
242
+ type,
243
+ participant_id: fromParticipantId,
244
+ timeout,
245
+ delegate_to: delegateTo ?? null,
246
+ });
247
+ if (response instanceof response_1.FileContent) {
248
+ return response.data;
249
+ }
250
+ throw this.unexpectedResponse("request_secret");
251
+ }
252
+ async setSecret({ secretId, type, mimeType, name, delegatedTo, forIdentity, data, }) {
253
+ const response = await this.invoke("set_secret", new response_1.BinaryContent({
254
+ data,
255
+ headers: {
256
+ secret_id: secretId ?? null,
257
+ type: type ?? mimeType ?? null,
258
+ name: name ?? null,
259
+ delegated_to: delegatedTo ?? null,
260
+ for_identity: forIdentity ?? null,
261
+ has_data: true,
262
+ },
263
+ }));
264
+ if (response instanceof response_1.EmptyContent || response instanceof response_1.JsonContent) {
265
+ return;
266
+ }
267
+ throw this.unexpectedResponse("set_secret");
268
+ }
269
+ async getSecret({ secretId, type, name, delegatedTo, }) {
270
+ const response = await this.invoke("get_secret", {
271
+ secret_id: secretId ?? null,
272
+ type: type ?? null,
273
+ name: name ?? null,
274
+ delegated_to: delegatedTo ?? null,
275
+ });
276
+ if (response instanceof response_1.EmptyContent) {
277
+ return null;
278
+ }
279
+ if (response instanceof response_1.FileContent) {
280
+ return response;
281
+ }
282
+ throw this.unexpectedResponse("get_secret");
283
+ }
85
284
  }
86
285
  exports.SecretsClient = SecretsClient;
@@ -1,37 +1,50 @@
1
1
  import { RoomClient } from "./room-client";
2
+ import { Protocol } from "./protocol";
2
3
  import { RoomEvent } from "./room-event";
3
4
  import { BinaryContent, FileContent } from "./response";
4
5
  import { EventEmitter } from "./event-emitter";
6
+ type StorageClientRoom = Pick<RoomClient, "invoke" | "invokeStream" | "emit"> & {
7
+ protocol: Pick<Protocol, "addHandler">;
8
+ };
5
9
  export declare class FileHandle {
6
10
  id: number;
7
11
  constructor({ id }: {
8
12
  id: number;
9
13
  });
10
14
  }
11
- declare class StorageEntry {
15
+ export declare class StorageEntry {
12
16
  name: string;
13
17
  isFolder: boolean;
14
18
  size: number | null;
15
- constructor({ name, isFolder, size }: {
19
+ createdAt: Date | null;
20
+ updatedAt: Date | null;
21
+ constructor({ name, isFolder, size, createdAt, updatedAt }: {
16
22
  name: string;
17
23
  isFolder: boolean;
18
24
  size?: number | null;
25
+ createdAt?: Date | null;
26
+ updatedAt?: Date | null;
19
27
  });
20
28
  nameWithoutExtension(): string;
21
29
  }
22
30
  export declare class StorageClient extends EventEmitter<RoomEvent> {
23
31
  private client;
24
32
  constructor({ room }: {
25
- room: RoomClient;
33
+ room: StorageClientRoom;
26
34
  });
27
35
  private _handleFileUpdated;
28
36
  private _handleFileDeleted;
29
37
  private _unexpectedResponseError;
38
+ private _storageEntry;
30
39
  private _invoke;
31
40
  list(path: string): Promise<StorageEntry[]>;
32
- delete(path: string): Promise<void>;
41
+ stat(path: string): Promise<StorageEntry | null>;
42
+ delete(path: string, { recursive, }?: {
43
+ recursive?: boolean | null;
44
+ }): Promise<void>;
33
45
  exists(path: string): Promise<boolean>;
34
46
  private _defaultUploadName;
47
+ private _defaultUploadMimeType;
35
48
  upload(path: string, bytes: Uint8Array, { overwrite, name, mimeType, }?: {
36
49
  overwrite?: boolean;
37
50
  name?: string | null;