@opengeni/sdk 0.8.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/sdk",
3
- "version": "0.8.0",
3
+ "version": "0.11.0",
4
4
  "description": "Framework-agnostic TypeScript SDK for the OpenGeni API: typed client, session lifecycle, SSE event streaming with reconnect + replay-by-sequence, and proxy re-streaming helpers.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -32,13 +32,7 @@
32
32
  },
33
33
  "scripts": {
34
34
  "typecheck": "tsc --noEmit",
35
- "build": "tsup"
36
- },
37
- "devDependencies": {
38
- "@opengeni/contracts": "workspace:*",
39
- "@opengeni/deployment": "workspace:*",
40
- "tsup": "^8.5.0",
41
- "typescript": "^6.0.3",
42
- "zod": "^4.2.1"
35
+ "build": "tsup",
36
+ "prepublishOnly": "bash ../../scripts/prepublish-guard"
43
37
  }
44
38
  }
package/src/client.ts CHANGED
@@ -18,6 +18,7 @@ import type {
18
18
  CapabilityCatalogItem,
19
19
  CapabilityCatalogResponse,
20
20
  CapabilityInstallation,
21
+ AddDocumentRequest,
21
22
  ClientConfig,
22
23
  ClientSessionEventInput,
23
24
  CompactSessionContextResult,
@@ -32,6 +33,7 @@ import type {
32
33
  CreateFileUploadResponse,
33
34
  CreateGitHubAppManifestRequest,
34
35
  CreateGitHubAppManifestResponse,
36
+ CreateKnowledgeMemoryRequest,
35
37
  CreateScheduledTaskRequest,
36
38
  CreateSessionRequest,
37
39
  CreateWorkspaceEnvironmentRequest,
@@ -45,6 +47,7 @@ import type {
45
47
  DiscoverMcpCapabilitiesResponse,
46
48
  Document,
47
49
  DocumentBase,
50
+ DocumentSearchRequest,
48
51
  DocumentSearchResponse,
49
52
  EnableCapabilityRequest,
50
53
  EnablePackRequest,
@@ -53,6 +56,8 @@ import type {
53
56
  GetPackResponse,
54
57
  GitHubAppInfo,
55
58
  GitHubRepositoriesResponse,
59
+ KnowledgeMemory,
60
+ KnowledgeMemorySearchRequest,
56
61
  ListApiKeysResponse,
57
62
  ListPacksResponse,
58
63
  // Bring-your-own-compute: the Machines dashboard + per-machine metrics (M10).
@@ -111,6 +116,7 @@ import type {
111
116
  PtyResizeRequest,
112
117
  PtyCloseRequest,
113
118
  ToolRef,
119
+ UpdateKnowledgeMemoryRequest,
114
120
  UpdateScheduledTaskRequest,
115
121
  UpdateSessionGoalRequest,
116
122
  UpdateSessionRequest,
@@ -974,7 +980,7 @@ export class OpenGeniClient {
974
980
  }
975
981
 
976
982
  /** Index an uploaded file into the base. The file must be `ready`. */
977
- async addDocument(workspaceId: string, baseId: string, request: { fileId: string }): Promise<Document> {
983
+ async addDocument(workspaceId: string, baseId: string, request: AddDocumentRequest): Promise<Document> {
978
984
  return await this.requestJson<Document>("POST", `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`, request);
979
985
  }
980
986
 
@@ -1004,7 +1010,7 @@ export class OpenGeniClient {
1004
1010
  async searchDocuments(
1005
1011
  workspaceId: string,
1006
1012
  baseId: string,
1007
- request: { query: string; limit?: number },
1013
+ request: Omit<DocumentSearchRequest, "baseIds">,
1008
1014
  ): Promise<DocumentSearchResponse> {
1009
1015
  return await this.requestJson<DocumentSearchResponse>(
1010
1016
  "POST",
@@ -1013,6 +1019,36 @@ export class OpenGeniClient {
1013
1019
  );
1014
1020
  }
1015
1021
 
1022
+ async searchKnowledge(
1023
+ workspaceId: string,
1024
+ request: DocumentSearchRequest,
1025
+ ): Promise<DocumentSearchResponse> {
1026
+ return await this.requestJson<DocumentSearchResponse>("POST", `/v1/workspaces/${workspaceId}/knowledge/search`, request);
1027
+ }
1028
+
1029
+ async listKnowledgeMemories(workspaceId: string, request: KnowledgeMemorySearchRequest = {}): Promise<KnowledgeMemory[]> {
1030
+ const params = new URLSearchParams();
1031
+ if (request.query) params.set("query", request.query);
1032
+ if (request.status) params.set("status", request.status);
1033
+ if (request.kind) params.set("kind", request.kind);
1034
+ if (request.scope) params.set("scope", request.scope);
1035
+ if (request.limit) params.set("limit", String(request.limit));
1036
+ const query = params.toString();
1037
+ return await this.requestJson<KnowledgeMemory[]>("GET", `/v1/workspaces/${workspaceId}/knowledge/memories${query ? `?${query}` : ""}`);
1038
+ }
1039
+
1040
+ async getKnowledgeMemory(workspaceId: string, memoryId: string): Promise<KnowledgeMemory> {
1041
+ return await this.requestJson<KnowledgeMemory>("GET", `/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`);
1042
+ }
1043
+
1044
+ async createKnowledgeMemory(workspaceId: string, request: CreateKnowledgeMemoryRequest): Promise<KnowledgeMemory> {
1045
+ return await this.requestJson<KnowledgeMemory>("POST", `/v1/workspaces/${workspaceId}/knowledge/memories`, request);
1046
+ }
1047
+
1048
+ async updateKnowledgeMemory(workspaceId: string, memoryId: string, request: UpdateKnowledgeMemoryRequest): Promise<KnowledgeMemory> {
1049
+ return await this.requestJson<KnowledgeMemory>("PATCH", `/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`, request);
1050
+ }
1051
+
1016
1052
  // --- Capability packs ------------------------------------------------------------------
1017
1053
 
1018
1054
  /** Built-in + registered packs, with the workspace's installations. */
package/src/index.ts CHANGED
@@ -87,9 +87,15 @@ export type {
87
87
  CompactSessionContextResult,
88
88
  ClientSessionEventInput,
89
89
  CompleteFileUploadResponse,
90
+ ConnectionKind,
91
+ ConnectionMetadata,
92
+ ConnectionResponse,
93
+ ConnectionStatus,
94
+ AddDocumentRequest,
90
95
  CreateApiKeyRequest,
91
96
  CreateApiKeyResponse,
92
97
  CreateCapabilityCatalogItemRequest,
98
+ CreateConnectionRequest,
93
99
  CreateCheckoutRequest,
94
100
  CreateCheckoutResponse,
95
101
  CreateDocumentBaseRequest,
@@ -97,6 +103,7 @@ export type {
97
103
  CreateFileUploadResponse,
98
104
  CreateGitHubAppManifestRequest,
99
105
  CreateGitHubAppManifestResponse,
106
+ CreateKnowledgeMemoryRequest,
100
107
  CreateScheduledTaskRequest,
101
108
  CreateSessionRequest,
102
109
  CreateWorkspaceEnvironmentRequest,
@@ -104,6 +111,7 @@ export type {
104
111
  DiscoverMcpCapabilitiesResponse,
105
112
  Document,
106
113
  DocumentBase,
114
+ DocumentSearchMode,
107
115
  DocumentSearchRequest,
108
116
  DocumentSearchResponse,
109
117
  DocumentSearchResult,
@@ -123,12 +131,23 @@ export type {
123
131
  GitHubRepositoriesResponse,
124
132
  GitHubRepository,
125
133
  GoalSpec,
134
+ IntegrationClientMetadata,
126
135
  KnownPermission,
127
136
  KnownSessionEventType,
128
137
  KnownUsageEventType,
138
+ KnowledgeMemory,
139
+ KnowledgeMemoryKind,
140
+ KnowledgeMemorySearchRequest,
141
+ KnowledgeMemoryStatus,
142
+ KnowledgeSourceKind,
143
+ KnowledgeSourceRef,
129
144
  ListApiKeysResponse,
145
+ ListConnectionsResponse,
130
146
  ListPacksResponse,
131
147
  ListWorkspaceMembersResponse,
148
+ McpServerConnectionRef,
149
+ OAuthStartRequest,
150
+ OAuthStartResponse,
132
151
  PackInstallation,
133
152
  PackInstallationStatus,
134
153
  Permission,
@@ -194,6 +213,8 @@ export type {
194
213
  SessionTurn,
195
214
  SessionTurnSource,
196
215
  SessionTurnStatus,
216
+ ToolAuthNeededPayload,
217
+ UpdateConnectionRequest,
197
218
  // Channel-A structured services (P4.4) — A1 payloads + A2 request/response.
198
219
  SandboxCommandOutputDeltaPayload,
199
220
  FsChangeKind,
@@ -240,6 +261,7 @@ export type {
240
261
  PtyResizeRequest,
241
262
  PtyCloseRequest,
242
263
  ToolRef,
264
+ UpdateKnowledgeMemoryRequest,
243
265
  UpdateScheduledTaskRequest,
244
266
  UpdateSessionGoalRequest,
245
267
  UpdateSessionRequest,
package/src/types.ts CHANGED
@@ -262,6 +262,92 @@ export type SessionMcpServerMetadata = {
262
262
  credentialVersion: number;
263
263
  };
264
264
 
265
+ export type ConnectionKind = "oauth2" | "api_key" | "app_install" | "delegated";
266
+ export type ConnectionStatus = "active" | "needs_reauth" | "revoked" | "error";
267
+
268
+ export type McpServerConnectionRef = {
269
+ connectionId?: string | undefined;
270
+ providerDomain: string;
271
+ kind?: ConnectionKind | undefined;
272
+ scopes?: string[] | undefined;
273
+ resource?: string | undefined;
274
+ subjectScope?: "workspace" | "subject" | undefined;
275
+ };
276
+
277
+ export type ConnectionMetadata = {
278
+ id: string;
279
+ accountId: string;
280
+ workspaceId: string;
281
+ subjectId: string | null;
282
+ providerDomain: string;
283
+ kind: ConnectionKind;
284
+ status: ConnectionStatus;
285
+ grantedScopes: string[];
286
+ expiresAt: string | null;
287
+ lastRefreshAt: string | null;
288
+ lastUsedAt: string | null;
289
+ lastError: string | null;
290
+ version: number;
291
+ metadata: Record<string, unknown>;
292
+ createdBySubjectId: string | null;
293
+ updatedBySubjectId: string | null;
294
+ createdAt: string;
295
+ updatedAt: string;
296
+ };
297
+
298
+ export type CreateConnectionRequest = {
299
+ providerDomain: string;
300
+ kind: ConnectionKind;
301
+ subjectId?: string | null | undefined;
302
+ credential: Record<string, unknown>;
303
+ grantedScopes?: string[] | undefined;
304
+ expiresAt?: string | null | undefined;
305
+ metadata?: Record<string, unknown> | undefined;
306
+ };
307
+
308
+ export type UpdateConnectionRequest = {
309
+ providerDomain?: string | undefined;
310
+ subjectId?: string | null | undefined;
311
+ kind?: ConnectionKind | undefined;
312
+ status?: ConnectionStatus | undefined;
313
+ credential?: Record<string, unknown> | undefined;
314
+ grantedScopes?: string[] | undefined;
315
+ expiresAt?: string | null | undefined;
316
+ metadata?: Record<string, unknown> | undefined;
317
+ };
318
+
319
+ export type ConnectionResponse = {
320
+ connection: ConnectionMetadata;
321
+ };
322
+
323
+ export type ListConnectionsResponse = {
324
+ connections: ConnectionMetadata[];
325
+ };
326
+
327
+ export type OAuthStartRequest = {
328
+ providerDomain?: string | undefined;
329
+ mcpUrl?: string | undefined;
330
+ resource?: string | undefined;
331
+ requestedScopes?: string[] | undefined;
332
+ returnPath?: string | undefined;
333
+ connectionId?: string | undefined;
334
+ };
335
+
336
+ export type OAuthStartResponse = {
337
+ state: string;
338
+ authorizationUrl: string | null;
339
+ expiresAt: string;
340
+ };
341
+
342
+ export type IntegrationClientMetadata = {
343
+ client_id: string;
344
+ client_name: "OpenGeni";
345
+ redirect_uris: string[];
346
+ token_endpoint_auth_method: "none";
347
+ grant_types: Array<"authorization_code" | "refresh_token">;
348
+ response_types: ["code"];
349
+ };
350
+
265
351
  export type Session = {
266
352
  id: string;
267
353
  workspaceId: string;
@@ -270,6 +356,9 @@ export type Session = {
270
356
  initialMessage: string;
271
357
  title: string | null;
272
358
  titleSource: "user" | "agent" | null;
359
+ // Per-session agent persona/system instructions supplied at create; null when
360
+ // the session carried none. Org-visible metadata, never a timeline event.
361
+ instructions: string | null;
273
362
  resources: ResourceRef[];
274
363
  tools: ToolRef[];
275
364
  metadata: Record<string, unknown>;
@@ -343,6 +432,7 @@ export const SESSION_EVENT_TYPES = [
343
432
  "agent.reasoning.delta",
344
433
  "agent.toolCall.created",
345
434
  "agent.toolCall.output",
435
+ "tool.auth_needed",
346
436
  "agent.updated",
347
437
  "sandbox.operation.started",
348
438
  "sandbox.operation.completed",
@@ -398,6 +488,18 @@ export type SessionEvent = {
398
488
  turnId?: string | null | undefined;
399
489
  };
400
490
 
491
+ export type ToolAuthNeededPayload = {
492
+ serverId: string;
493
+ toolName?: string | null | undefined;
494
+ providerDomain: string;
495
+ connectionId?: string | null | undefined;
496
+ reason: "missing_connection" | "expired" | "insufficient_scope" | "refresh_failed";
497
+ scopes?: string[] | undefined;
498
+ resource?: string | undefined;
499
+ authorizationUrl?: string | undefined;
500
+ subjectId?: string | null | undefined;
501
+ };
502
+
401
503
  // Payload shapes for the high-traffic event types. `SessionEvent.payload` is
402
504
  // `unknown` on the wire; these are the documented shapes producers emit today.
403
505
  export type AgentTextDeltaPayload = { text: string };
@@ -611,6 +713,11 @@ export type ScheduledTask = {
611
713
 
612
714
  export type CreateSessionRequest = {
613
715
  initialMessage: string;
716
+ // Per-session agent persona/system instructions (org-visible metadata, not a
717
+ // secret). Delivered system-level, composed AFTER the per-workspace persona —
718
+ // how a host supplies per-agent-type prompts without leaking them into the
719
+ // user-visible timeline. Trimmed, non-empty, max 32768 chars.
720
+ instructions?: string | undefined;
614
721
  resources?: ResourceRef[] | undefined;
615
722
  tools?: ToolRef[] | undefined;
616
723
  metadata?: Record<string, unknown> | undefined;
@@ -673,9 +780,12 @@ export const KNOWN_PERMISSIONS = [
673
780
  "github:manage",
674
781
  "github:use",
675
782
  "api_keys:manage",
783
+ "connections:read",
784
+ "connections:write",
676
785
  "environments:manage",
677
786
  "environments:use",
678
787
  "mcp_servers:attach",
788
+ "toolspace:call",
679
789
  "goals:manage",
680
790
  "enrollments:read",
681
791
  "enrollments:manage",
@@ -1186,6 +1296,8 @@ export type UploadFileInput = {
1186
1296
  // --- Documents -------------------------------------------------------------------
1187
1297
 
1188
1298
  export type DocumentStatus = "queued" | "indexing" | "ready" | "failed";
1299
+ export type KnowledgeSourceKind = "manual_upload" | "meeting_transcript" | "repository" | "email" | "chat" | "document" | "web" | "other";
1300
+ export type DocumentSearchMode = "hybrid" | "vector" | "keyword";
1189
1301
 
1190
1302
  export type DocumentBase = {
1191
1303
  id: string;
@@ -1206,6 +1318,15 @@ export type Document = {
1206
1318
  parser: string;
1207
1319
  chunkCount: number;
1208
1320
  error: string | null;
1321
+ sourceKind: KnowledgeSourceKind;
1322
+ sourceUri: string | null;
1323
+ sourceExternalId: string | null;
1324
+ sourceTitle: string | null;
1325
+ sourceAuthor: string | null;
1326
+ sourceCreatedAt: string | null;
1327
+ sourceUpdatedAt: string | null;
1328
+ sourceVersion: string | null;
1329
+ aclTags: string[];
1209
1330
  createdAt: string;
1210
1331
  updatedAt: string;
1211
1332
  };
@@ -1219,8 +1340,20 @@ export type DocumentSearchResult = {
1219
1340
  title: string;
1220
1341
  text: string;
1221
1342
  score: number;
1343
+ matchType: DocumentSearchMode;
1344
+ vectorScore: number | null;
1345
+ keywordScore: number | null;
1222
1346
  chunkIndex: number;
1223
1347
  metadata: Record<string, unknown>;
1348
+ sourceKind: KnowledgeSourceKind;
1349
+ sourceUri: string | null;
1350
+ sourceExternalId: string | null;
1351
+ sourceTitle: string | null;
1352
+ sourceAuthor: string | null;
1353
+ sourceCreatedAt: string | null;
1354
+ sourceUpdatedAt: string | null;
1355
+ sourceVersion: string | null;
1356
+ aclTags: string[];
1224
1357
  };
1225
1358
 
1226
1359
  export type CreateDocumentBaseRequest = {
@@ -1228,8 +1361,26 @@ export type CreateDocumentBaseRequest = {
1228
1361
  description?: string | undefined;
1229
1362
  };
1230
1363
 
1364
+ export type AddDocumentRequest = {
1365
+ fileId: string;
1366
+ title?: string | undefined;
1367
+ sourceKind?: KnowledgeSourceKind | undefined;
1368
+ sourceUri?: string | undefined;
1369
+ sourceExternalId?: string | undefined;
1370
+ sourceTitle?: string | undefined;
1371
+ sourceAuthor?: string | undefined;
1372
+ sourceCreatedAt?: string | undefined;
1373
+ sourceUpdatedAt?: string | undefined;
1374
+ sourceVersion?: string | undefined;
1375
+ aclTags?: string[] | undefined;
1376
+ };
1377
+
1231
1378
  export type DocumentSearchRequest = {
1232
1379
  query: string;
1380
+ baseIds?: string[] | undefined;
1381
+ mode?: DocumentSearchMode | undefined;
1382
+ sourceKinds?: KnowledgeSourceKind[] | undefined;
1383
+ aclTags?: string[] | undefined;
1233
1384
  limit?: number | undefined;
1234
1385
  };
1235
1386
 
@@ -1237,6 +1388,64 @@ export type DocumentSearchResponse = {
1237
1388
  results: DocumentSearchResult[];
1238
1389
  };
1239
1390
 
1391
+ export type KnowledgeMemoryStatus = "proposed" | "approved" | "rejected";
1392
+ export type KnowledgeMemoryKind = "semantic" | "episodic" | "procedural" | "decision" | "preference";
1393
+
1394
+ export type KnowledgeSourceRef = {
1395
+ kind: "document_chunk" | "document" | "session_event" | "memory" | "external";
1396
+ id: string;
1397
+ uri?: string | undefined;
1398
+ title?: string | undefined;
1399
+ metadata?: Record<string, unknown> | undefined;
1400
+ };
1401
+
1402
+ export type KnowledgeMemory = {
1403
+ id: string;
1404
+ workspaceId: string;
1405
+ status: KnowledgeMemoryStatus;
1406
+ kind: KnowledgeMemoryKind;
1407
+ scope: string;
1408
+ text: string;
1409
+ sourceRefs: KnowledgeSourceRef[];
1410
+ confidence: number;
1411
+ metadata: Record<string, unknown>;
1412
+ createdBySessionId: string | null;
1413
+ reviewedBy: string | null;
1414
+ reviewedAt: string | null;
1415
+ createdAt: string;
1416
+ updatedAt: string;
1417
+ };
1418
+
1419
+ export type CreateKnowledgeMemoryRequest = {
1420
+ status?: KnowledgeMemoryStatus | undefined;
1421
+ kind?: KnowledgeMemoryKind | undefined;
1422
+ scope?: string | undefined;
1423
+ text: string;
1424
+ sourceRefs?: KnowledgeSourceRef[] | undefined;
1425
+ confidence?: number | undefined;
1426
+ metadata?: Record<string, unknown> | undefined;
1427
+ createdBySessionId?: string | undefined;
1428
+ };
1429
+
1430
+ export type UpdateKnowledgeMemoryRequest = {
1431
+ status?: KnowledgeMemoryStatus | undefined;
1432
+ kind?: KnowledgeMemoryKind | undefined;
1433
+ scope?: string | undefined;
1434
+ text?: string | undefined;
1435
+ sourceRefs?: KnowledgeSourceRef[] | undefined;
1436
+ confidence?: number | undefined;
1437
+ metadata?: Record<string, unknown> | undefined;
1438
+ reviewedBy?: string | undefined;
1439
+ };
1440
+
1441
+ export type KnowledgeMemorySearchRequest = {
1442
+ query?: string | undefined;
1443
+ status?: KnowledgeMemoryStatus | undefined;
1444
+ kind?: KnowledgeMemoryKind | undefined;
1445
+ scope?: string | undefined;
1446
+ limit?: number | undefined;
1447
+ };
1448
+
1240
1449
  // --- Capability packs ---------------------------------------------------------
1241
1450
 
1242
1451
  export type CapabilityPackConnectorAuthModel =
@@ -1397,10 +1606,14 @@ export type GetPackResponse = {
1397
1606
 
1398
1607
  export type CapabilityKind = "pack" | "mcp" | "api" | "skill" | "plugin";
1399
1608
 
1400
- export type CapabilitySource = "built_in" | "configured" | "public_registry" | "manual";
1609
+ export type CapabilitySource = "built_in" | "configured" | "public_registry" | "registry" | "manual";
1401
1610
 
1402
1611
  export type CapabilityInstallationStatus = "active" | "disabled";
1403
1612
 
1613
+ export type CapabilityCatalogAuthKind = "oauth2" | "api_key" | "none" | "unknown";
1614
+
1615
+ export type CapabilityCatalogTier = "verified" | "community";
1616
+
1404
1617
  export type CapabilityRuntime = {
1405
1618
  available: boolean;
1406
1619
  mcpServerId?: string | undefined;
@@ -1422,6 +1635,18 @@ export type CapabilityCatalogItem = {
1422
1635
  endpointUrl: string | null;
1423
1636
  installUrl: string | null;
1424
1637
  authModel: string | null;
1638
+ providerDomain: string | null;
1639
+ surfaceType: string | null;
1640
+ transport: string | null;
1641
+ mcpUrl: string | null;
1642
+ authKind: CapabilityCatalogAuthKind | null;
1643
+ credentialFacts: Record<string, unknown>[];
1644
+ tier: CapabilityCatalogTier | null;
1645
+ provenance: string | null;
1646
+ logoAssetPath: string | null;
1647
+ importBatchId: string | null;
1648
+ stale: boolean;
1649
+ staleAt: string | null;
1425
1650
  tools: ToolRef[];
1426
1651
  runtime: CapabilityRuntime;
1427
1652
  enabled: boolean;
@@ -1467,6 +1692,7 @@ export type CreateCapabilityCatalogItemRequest = {
1467
1692
  export type EnableCapabilityRequest = {
1468
1693
  config?: Record<string, unknown> | undefined;
1469
1694
  metadata?: Record<string, unknown> | undefined;
1695
+ connectionRef?: McpServerConnectionRef | undefined;
1470
1696
  /**
1471
1697
  * Credential headers for remote MCP capabilities. Write-only: encrypted at
1472
1698
  * rest, injected only into the runtime MCP client, never returned by the
@@ -1696,6 +1922,10 @@ export type MachineView = {
1696
1922
  os: string;
1697
1923
  arch: string;
1698
1924
  hasDisplay: boolean;
1925
+ /** Non-null only when a display exists but capture is blocked (macOS Screen
1926
+ * Recording / TCC not granted) — the UI can surface "display: capture not
1927
+ * granted". null == capture permitted OR headless. */
1928
+ desktopUnavailableReason?: string | null | undefined;
1699
1929
  allowScreenControl: boolean;
1700
1930
  sharedSessionCount: number;
1701
1931
  lastSeenAt: string | null;