@opengeni/api-router 0.30.3 → 2.2.0-canary.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/dist/api-websocket.d.ts +18 -0
- package/dist/app.js +1 -1
- package/dist/auth/managed-auth.d.ts +6 -0
- package/dist/{chunk-WCXHI3FF.js → chunk-3TP54PPX.js} +26692 -15389
- package/dist/chunk-3TP54PPX.js.map +1 -0
- package/dist/codemode.d.ts +8 -1
- package/dist/company-brain-okf.d.ts +24 -0
- package/dist/connected-machine-computer-access.d.ts +11 -0
- package/dist/connection-authority-owner.d.ts +59 -0
- package/dist/connection-ownership.d.ts +47 -0
- package/dist/controller-data-plane.d.ts +16 -0
- package/dist/editable-artifact-websocket.d.ts +5 -15
- package/dist/editable-artifact-workspace-files.d.ts +1 -1
- package/dist/http/api-error.d.ts +10 -0
- package/dist/http/cors.d.ts +5 -0
- package/dist/http/interaction-control-error.d.ts +13 -0
- package/dist/http/sse.d.ts +2 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.js +326 -82
- package/dist/index.js.map +1 -1
- package/dist/integrations/atlassian.d.ts +17 -0
- package/dist/integrations/fiken.d.ts +7 -2
- package/dist/integrations/google-drive.d.ts +18 -0
- package/dist/integrations/oauth-client.d.ts +22 -3
- package/dist/integrations/oauth-profiles.d.ts +195 -0
- package/dist/integrations/personal-github-repositories.d.ts +45 -0
- package/dist/integrations/personal-github.d.ts +40 -0
- package/dist/integrations/pr-review-provider.d.ts +22 -0
- package/dist/integrations/provider-oauth.d.ts +8 -0
- package/dist/integrations/slack-app-home.d.ts +24 -0
- package/dist/integrations/slack-bot.d.ts +157 -9
- package/dist/integrations/slack-interactions.d.ts +39 -5
- package/dist/integrations/slack-routing.d.ts +120 -0
- package/dist/integrations/social-oauth.d.ts +5 -0
- package/dist/interaction-frame-proxy.d.ts +68 -0
- package/dist/mcp/company-brain-governed-writes.d.ts +26 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
- package/dist/mcp/documents.d.ts +1 -0
- package/dist/mcp/remember.d.ts +28 -0
- package/dist/mcp/request-abort.d.ts +19 -0
- package/dist/mcp/scheduled-task-view.d.ts +4 -4
- package/dist/mcp/server.d.ts +15 -2
- package/dist/mcp/session-view.d.ts +4 -0
- package/dist/mcp/session-wait.d.ts +137 -0
- package/dist/routes/automations.d.ts +4 -0
- package/dist/routes/billing.d.ts +5 -0
- package/dist/routes/browser-sessions.d.ts +4 -1
- package/dist/routes/company-brain.d.ts +3 -0
- package/dist/routes/company-profile.d.ts +2 -1
- package/dist/routes/connection-authorities.d.ts +3 -0
- package/dist/routes/personal-github-git-broker.d.ts +29 -0
- package/dist/routes/personal-github.d.ts +3 -0
- package/dist/routes/pr-review.d.ts +3 -0
- package/dist/routes/sessions.d.ts +1 -0
- package/dist/routes/user-resource-authorities.d.ts +3 -0
- package/dist/routes/workspace-capture.d.ts +10 -2
- package/dist/routes/workspace-learning.d.ts +3 -0
- package/dist/routes/workspaces.d.ts +19 -0
- package/dist/sandbox/channel-a.d.ts +11 -1
- package/dist/sandbox/connection-authority.d.ts +3 -0
- package/dist/sandbox/enrollment.d.ts +2 -0
- package/dist/sandbox/machines.d.ts +2 -2
- package/dist/sandbox/metrics-ingestion.d.ts +10 -20
- package/dist/sandbox/viewer.d.ts +24 -1
- package/dist/sandbox-file-artifacts.d.ts +11 -0
- package/dist/scheduled-task-deletion.d.ts +14 -0
- package/dist/slack-reaction-files.d.ts +1 -1
- package/dist/temporal-schedule-cleanup.d.ts +1 -0
- package/package.json +20 -18
- package/src/api-websocket.ts +23 -0
- package/src/app.ts +161 -23
- package/src/auth/managed-auth.ts +25 -3
- package/src/codemode.ts +53 -23
- package/src/codex-realtime.ts +8 -2
- package/src/company-brain-okf.ts +340 -0
- package/src/connected-machine-computer-access.ts +33 -0
- package/src/connection-authority-owner.ts +61 -0
- package/src/connection-ownership.ts +180 -0
- package/src/controller-data-plane.ts +47 -0
- package/src/editable-artifact-native-kernel.ts +26 -15
- package/src/editable-artifact-office-import.ts +28 -3
- package/src/editable-artifact-production.ts +13 -7
- package/src/editable-artifact-websocket.ts +11 -18
- package/src/editable-artifact-workspace-files.ts +31 -6
- package/src/http/api-error.ts +28 -0
- package/src/http/auth.ts +4 -0
- package/src/http/cors.ts +35 -0
- package/src/http/interaction-control-error.ts +164 -0
- package/src/http/sse.ts +112 -66
- package/src/index.ts +46 -6
- package/src/integrations/atlassian.ts +146 -35
- package/src/integrations/fiken.ts +102 -22
- package/src/integrations/google-drive.ts +301 -92
- package/src/integrations/oauth-client.ts +272 -143
- package/src/integrations/oauth-profiles.ts +477 -0
- package/src/integrations/personal-github-repositories.ts +445 -0
- package/src/integrations/personal-github.ts +705 -0
- package/src/integrations/pr-review-provider.ts +246 -0
- package/src/integrations/provider-oauth.ts +121 -5
- package/src/integrations/slack-app-home.ts +300 -0
- package/src/integrations/slack-bot.ts +342 -57
- package/src/integrations/slack-interactions.ts +1898 -259
- package/src/integrations/slack-routing.ts +337 -0
- package/src/integrations/social-oauth.ts +25 -0
- package/src/interaction-frame-proxy.ts +409 -0
- package/src/mcp/company-brain-governed-writes.ts +262 -0
- package/src/mcp/company-profile-agent-admin.ts +205 -0
- package/src/mcp/documents.ts +37 -6
- package/src/mcp/files.ts +16 -1
- package/src/mcp/remember.ts +181 -0
- package/src/mcp/request-abort.ts +44 -0
- package/src/mcp/scheduled-task-view.ts +1 -0
- package/src/mcp/server.ts +719 -369
- package/src/mcp/session-view.ts +54 -0
- package/src/mcp/session-wait.ts +554 -0
- package/src/model-catalog.ts +20 -12
- package/src/routes/api-integrations.ts +4 -0
- package/src/routes/api-keys.ts +1 -0
- package/src/routes/automations.ts +534 -0
- package/src/routes/billing.ts +57 -1
- package/src/routes/browser-sessions.ts +329 -79
- package/src/routes/channels.ts +17 -1
- package/src/routes/codex.ts +50 -0
- package/src/routes/company-brain.ts +367 -0
- package/src/routes/company-profile.ts +1 -1
- package/src/routes/computer-sessions.ts +320 -93
- package/src/routes/connection-authorities.ts +139 -0
- package/src/routes/connections.ts +144 -34
- package/src/routes/documents.ts +353 -4
- package/src/routes/editable-artifacts.ts +11 -3
- package/src/routes/enrollments.ts +116 -26
- package/src/routes/environments.ts +127 -55
- package/src/routes/files.ts +72 -11
- package/src/routes/install.ts +82 -28
- package/src/routes/integration-facets.ts +29 -0
- package/src/routes/interaction-resources.ts +20 -2
- package/src/routes/machines.ts +275 -13
- package/src/routes/organization-memberships.ts +717 -28
- package/src/routes/packs.ts +4 -3
- package/src/routes/personal-github-git-broker.ts +785 -0
- package/src/routes/personal-github.ts +319 -0
- package/src/routes/pr-review.ts +531 -0
- package/src/routes/rigs.ts +104 -39
- package/src/routes/scheduled-tasks.ts +19 -21
- package/src/routes/sessions.ts +775 -38
- package/src/routes/social.ts +14 -2
- package/src/routes/supergrok.ts +23 -4
- package/src/routes/transcription-recordings.ts +8 -2
- package/src/routes/user-resource-authorities.ts +138 -0
- package/src/routes/workspace-artifacts.ts +4 -1
- package/src/routes/workspace-capture.ts +21 -0
- package/src/routes/workspace-learning.ts +228 -0
- package/src/routes/workspaces.ts +59 -6
- package/src/sandbox/auth-callout.ts +38 -12
- package/src/sandbox/channel-a.ts +242 -19
- package/src/sandbox/connection-authority.ts +3 -0
- package/src/sandbox/enrollment.ts +15 -3
- package/src/sandbox/machines.ts +186 -64
- package/src/sandbox/metrics-ingestion.ts +220 -58
- package/src/sandbox/viewer.ts +243 -19
- package/src/sandbox-file-artifacts.ts +329 -0
- package/src/scheduled-task-deletion.ts +127 -0
- package/src/slack-reaction-files.ts +16 -5
- package/src/temporal-schedule-cleanup.ts +13 -0
- package/dist/chunk-WCXHI3FF.js.map +0 -1
package/src/sandbox/machines.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// apps/api/src/sandbox/machines.ts — the M10 Machines-DASHBOARD service (design
|
|
2
2
|
// §10.7). Builds the `MachinesResponse` the dashboard renders: the workspace's
|
|
3
3
|
// enrolled selfhosted machines, each enriched with
|
|
4
|
-
// * STATE —
|
|
5
|
-
// enrollment-derived
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// * STATE — heartbeat + goodbye liveness (online/offline) overlaid with the
|
|
5
|
+
// enrollment-derived display reason (display_unavailable). This list does
|
|
6
|
+
// not ControlRpc-ping; attach, capability negotiation, and fleet tools
|
|
7
|
+
// still probe when they need a live responder.
|
|
8
8
|
// * METRICS — the latest machine_metrics_latest row (or null before a first
|
|
9
9
|
// heartbeat), projected to the contract's MetricSample;
|
|
10
10
|
// * sharedSessionCount — the lease refcount (how many sessions share this one
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import type { Settings } from "@opengeni/config";
|
|
22
22
|
import {
|
|
23
23
|
getSession,
|
|
24
|
+
getLiveEnrollmentConnection,
|
|
24
25
|
listEnrollments,
|
|
25
26
|
listSandboxes,
|
|
26
27
|
readActiveSandbox,
|
|
@@ -30,32 +31,116 @@ import {
|
|
|
30
31
|
type EnrollmentRecord,
|
|
31
32
|
type MachineMetricsRow,
|
|
32
33
|
} from "@opengeni/db";
|
|
33
|
-
import type { EventBus } from "@opengeni/events";
|
|
34
34
|
import { MachineView, MetricSample, type MachinesResponse } from "@opengeni/contracts";
|
|
35
|
-
import {
|
|
36
|
-
NatsControlRpc,
|
|
37
|
-
selfhostedLiveness,
|
|
38
|
-
SelfhostedSession,
|
|
39
|
-
type ControlRpc,
|
|
40
|
-
type NatsRequestConnection,
|
|
41
|
-
} from "@opengeni/runtime/sandbox";
|
|
42
|
-
import { relayConfigFromSettings } from "@opengeni/core";
|
|
35
|
+
import { selfhostedHeartbeatLiveness } from "@opengeni/runtime/sandbox";
|
|
43
36
|
|
|
44
37
|
export type MachinesServices = {
|
|
45
38
|
db: Database;
|
|
46
39
|
settings: Settings;
|
|
47
|
-
bus?: EventBus;
|
|
48
40
|
};
|
|
49
41
|
|
|
50
|
-
const
|
|
42
|
+
const ACTIVE_UPDATE_STATUSES = new Set([
|
|
43
|
+
"requested",
|
|
44
|
+
"accepted",
|
|
45
|
+
"waiting_for_idle",
|
|
46
|
+
"downloading",
|
|
47
|
+
"verifying",
|
|
48
|
+
"applying",
|
|
49
|
+
"restarting",
|
|
50
|
+
]);
|
|
51
51
|
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
function compareAgentVersions(left: string, right: string): number | null {
|
|
53
|
+
const parse = (value: string): { core: number[]; prerelease: string | null } | null => {
|
|
54
|
+
const match = /^(?:v)?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(value.trim());
|
|
55
|
+
if (!match) return null;
|
|
56
|
+
return {
|
|
57
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
58
|
+
prerelease: match[4] ?? null,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
const a = parse(left);
|
|
62
|
+
const b = parse(right);
|
|
63
|
+
if (!a || !b) return null;
|
|
64
|
+
for (let index = 0; index < 3; index += 1) {
|
|
65
|
+
const delta = a.core[index]! - b.core[index]!;
|
|
66
|
+
if (delta !== 0) return Math.sign(delta);
|
|
67
|
+
}
|
|
68
|
+
if (a.prerelease === b.prerelease) return 0;
|
|
69
|
+
if (a.prerelease === null) return 1;
|
|
70
|
+
if (b.prerelease === null) return -1;
|
|
71
|
+
return a.prerelease.localeCompare(b.prerelease);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function runtimeFor(settings: Settings, enrollment: EnrollmentRecord): MachineView["runtime"] {
|
|
75
|
+
const desiredVersion =
|
|
76
|
+
enrollment.agentUpdateChannel === "beta"
|
|
77
|
+
? (settings.agentBetaVersion ?? settings.agentStableVersion)
|
|
78
|
+
: settings.agentStableVersion;
|
|
79
|
+
const update = enrollment.agentUpdate;
|
|
80
|
+
const activeUpdate = update ? ACTIVE_UPDATE_STATUSES.has(update.status) : false;
|
|
81
|
+
const order =
|
|
82
|
+
enrollment.agentVersion && desiredVersion
|
|
83
|
+
? compareAgentVersions(enrollment.agentVersion, desiredVersion)
|
|
84
|
+
: null;
|
|
85
|
+
const versionState = activeUpdate
|
|
86
|
+
? "updating"
|
|
87
|
+
: update?.status === "failed"
|
|
88
|
+
? "update_failed"
|
|
89
|
+
: order === null
|
|
90
|
+
? "unknown"
|
|
91
|
+
: order === 0
|
|
92
|
+
? "current"
|
|
93
|
+
: order < 0
|
|
94
|
+
? "outdated"
|
|
95
|
+
: "ahead";
|
|
96
|
+
const capability = (name: string): boolean => enrollment.agentCapabilities[name] === true;
|
|
97
|
+
return {
|
|
98
|
+
installedVersion: enrollment.agentVersion,
|
|
99
|
+
binarySha256: enrollment.agentBinarySha256,
|
|
100
|
+
updateChannel: enrollment.agentUpdateChannel,
|
|
101
|
+
desiredVersion,
|
|
102
|
+
versionState,
|
|
103
|
+
capabilities: {
|
|
104
|
+
exec: capability("exec"),
|
|
105
|
+
filesystem: capability("filesystem"),
|
|
106
|
+
git: capability("git"),
|
|
107
|
+
pty: capability("pty"),
|
|
108
|
+
desktop: capability("desktop"),
|
|
109
|
+
opStream: capability("opStream"),
|
|
110
|
+
browserBridge: capability("browserBridge"),
|
|
111
|
+
operationResourcePolicy: capability("operationResourcePolicy"),
|
|
112
|
+
operationCpuQuota: capability("operationCpuQuota"),
|
|
113
|
+
},
|
|
114
|
+
update,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function connectionAuthorityFor(
|
|
119
|
+
enrollment: EnrollmentRecord | null,
|
|
120
|
+
liveConnection: EnrollmentRecord | null,
|
|
121
|
+
): MachineView["connectionAuthority"] {
|
|
122
|
+
if (!enrollment) {
|
|
123
|
+
return {
|
|
124
|
+
state: "not_applicable",
|
|
125
|
+
generation: 0,
|
|
126
|
+
supersededCount: 0,
|
|
127
|
+
leaseExpiresAt: null,
|
|
128
|
+
duplicateRunnerDeniedCount: 0,
|
|
129
|
+
duplicateRunnerDeniedAt: null,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
state: liveConnection
|
|
134
|
+
? "active"
|
|
135
|
+
: enrollment.connectionInstanceId && enrollment.connectionLeaseExpiresAt
|
|
136
|
+
? "expired"
|
|
137
|
+
: "unclaimed",
|
|
138
|
+
generation: enrollment.connectionGeneration,
|
|
139
|
+
supersededCount: Math.max(0, enrollment.connectionGeneration - 1),
|
|
140
|
+
leaseExpiresAt: enrollment.connectionLeaseExpiresAt,
|
|
141
|
+
duplicateRunnerDeniedCount: enrollment.connectionDuplicateDeniedCount,
|
|
142
|
+
duplicateRunnerDeniedAt: enrollment.connectionDuplicateDeniedAt,
|
|
143
|
+
};
|
|
59
144
|
}
|
|
60
145
|
|
|
61
146
|
/**
|
|
@@ -83,36 +168,8 @@ export function metricRowToSample(row: MachineMetricsRow): MetricSample {
|
|
|
83
168
|
});
|
|
84
169
|
}
|
|
85
170
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
* disambiguate a probe-miss into reconnecting vs offline). Mirrors the M7 fleet
|
|
89
|
-
* probe. A non-active enrollment is offline without a probe. */
|
|
90
|
-
async function probeEnrollment(
|
|
91
|
-
services: MachinesServices,
|
|
92
|
-
workspaceId: string,
|
|
93
|
-
enrollment: EnrollmentRecord,
|
|
94
|
-
): Promise<{
|
|
95
|
-
state: "online" | "reconnecting" | "offline";
|
|
96
|
-
consented: boolean;
|
|
97
|
-
hasDisplay: boolean;
|
|
98
|
-
}> {
|
|
99
|
-
const { settings, bus } = services;
|
|
100
|
-
let probeResponded = false;
|
|
101
|
-
if (enrollment.status === "active") {
|
|
102
|
-
const session = new SelfhostedSession({
|
|
103
|
-
workspaceId,
|
|
104
|
-
agentId: enrollment.id,
|
|
105
|
-
controlRpc: controlRpc(bus),
|
|
106
|
-
relay: relayConfigFromSettings(settings),
|
|
107
|
-
timeoutMs: PROBE_TIMEOUT_MS,
|
|
108
|
-
});
|
|
109
|
-
try {
|
|
110
|
-
probeResponded = await session.ping();
|
|
111
|
-
} catch {
|
|
112
|
-
probeResponded = false;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const derived = selfhostedLiveness({
|
|
171
|
+
function enrollmentLiveness(enrollment: EnrollmentRecord) {
|
|
172
|
+
return selfhostedHeartbeatLiveness({
|
|
116
173
|
enrollment: {
|
|
117
174
|
status: enrollment.status,
|
|
118
175
|
exposure: enrollment.exposure,
|
|
@@ -122,16 +179,15 @@ async function probeEnrollment(
|
|
|
122
179
|
wentOfflineAt: enrollment.wentOfflineAt,
|
|
123
180
|
wentOfflineReason: enrollment.wentOfflineReason,
|
|
124
181
|
},
|
|
125
|
-
probeResponded,
|
|
126
182
|
});
|
|
127
|
-
return { state: derived.state, consented: derived.consented, hasDisplay: derived.hasDisplay };
|
|
128
183
|
}
|
|
129
184
|
|
|
130
185
|
/**
|
|
131
186
|
* Resolve the dashboard STATE of a machine. State reflects REACHABILITY + the
|
|
132
187
|
* VIEW plane only: an online machine with no display → `display_unavailable` (no
|
|
133
188
|
* desktop stream, but compute — exec/fs/git/terminal — still works); otherwise
|
|
134
|
-
* the liveness state (online/
|
|
189
|
+
* the liveness state (online/offline; list heartbeat never yields reconnecting).
|
|
190
|
+
* It deliberately does NOT fold
|
|
135
191
|
* in screen-control consent: a displayed machine can be VIEWED (read-only) and
|
|
136
192
|
* used for compute regardless of `allowScreenControl` — only INPUT (ComputerUse /
|
|
137
193
|
* an interactive stream) needs that consent, which is a per-capability concern
|
|
@@ -163,7 +219,12 @@ function machineStateFor(
|
|
|
163
219
|
*/
|
|
164
220
|
export async function listMachines(
|
|
165
221
|
services: MachinesServices,
|
|
166
|
-
input: {
|
|
222
|
+
input: {
|
|
223
|
+
accountId?: string;
|
|
224
|
+
workspaceId: string;
|
|
225
|
+
subjectId?: string;
|
|
226
|
+
sessionId?: string | null;
|
|
227
|
+
},
|
|
167
228
|
): Promise<MachinesResponse> {
|
|
168
229
|
const { db } = services;
|
|
169
230
|
const { workspaceId } = input;
|
|
@@ -210,18 +271,59 @@ export async function listMachines(
|
|
|
210
271
|
allowScreenControl: false,
|
|
211
272
|
sharedSessionCount: 1,
|
|
212
273
|
lastSeenAt: null,
|
|
274
|
+
connectionAuthority: connectionAuthorityFor(null, null),
|
|
275
|
+
runtime: null,
|
|
276
|
+
operationPolicy: null,
|
|
213
277
|
metrics: null,
|
|
214
278
|
}),
|
|
215
279
|
);
|
|
216
280
|
}
|
|
217
281
|
|
|
218
282
|
// The workspace's enrolled selfhosted machines. One bulk metrics read joined
|
|
219
|
-
// onto the machines (no N+1).
|
|
220
|
-
const [
|
|
283
|
+
// onto the machines (no N+1). Liveness is the durable heartbeat cursor.
|
|
284
|
+
const [legacySandboxes, enrollments] = await Promise.all([
|
|
221
285
|
listSandboxes(db, workspaceId),
|
|
222
|
-
listEnrollments(
|
|
223
|
-
|
|
286
|
+
listEnrollments(
|
|
287
|
+
db,
|
|
288
|
+
input.accountId && input.subjectId
|
|
289
|
+
? {
|
|
290
|
+
accountId: input.accountId,
|
|
291
|
+
workspaceId,
|
|
292
|
+
subjectId: input.subjectId,
|
|
293
|
+
}
|
|
294
|
+
: workspaceId,
|
|
295
|
+
{ status: "active" },
|
|
296
|
+
),
|
|
224
297
|
]);
|
|
298
|
+
const metricsByEnrollment = new Map<string, MachineMetricsRow>();
|
|
299
|
+
for (const originWorkspaceId of new Set(enrollments.map((entry) => entry.workspaceId))) {
|
|
300
|
+
const originMetrics = await readMachineMetricsLatestForWorkspace(db, originWorkspaceId);
|
|
301
|
+
for (const [enrollmentId, metrics] of originMetrics) {
|
|
302
|
+
metricsByEnrollment.set(enrollmentId, metrics);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const scopedSandboxes = enrollments.flatMap((enrollment) =>
|
|
306
|
+
enrollment.sandboxId
|
|
307
|
+
? [
|
|
308
|
+
{
|
|
309
|
+
id: enrollment.sandboxId,
|
|
310
|
+
accountId: enrollment.accountId,
|
|
311
|
+
workspaceId: enrollment.workspaceId,
|
|
312
|
+
kind: "selfhosted" as const,
|
|
313
|
+
name: enrollment.sandboxName ?? `${enrollment.os} machine`,
|
|
314
|
+
enrollmentId: enrollment.id,
|
|
315
|
+
createdAt: enrollment.createdAt,
|
|
316
|
+
updatedAt: enrollment.updatedAt,
|
|
317
|
+
},
|
|
318
|
+
]
|
|
319
|
+
: [],
|
|
320
|
+
);
|
|
321
|
+
const sandboxes = [
|
|
322
|
+
...legacySandboxes.filter(
|
|
323
|
+
(sandbox) => !scopedSandboxes.some((scoped) => scoped.id === sandbox.id),
|
|
324
|
+
),
|
|
325
|
+
...scopedSandboxes,
|
|
326
|
+
];
|
|
225
327
|
const enrollmentById = new Map(enrollments.map((e) => [e.id, e]));
|
|
226
328
|
|
|
227
329
|
const machineViews = await Promise.all(
|
|
@@ -233,11 +335,26 @@ export async function listMachines(
|
|
|
233
335
|
if (!enrollment) {
|
|
234
336
|
return null;
|
|
235
337
|
}
|
|
236
|
-
const [
|
|
237
|
-
|
|
238
|
-
|
|
338
|
+
const [liveConnection, lease] = await Promise.all([
|
|
339
|
+
enrollment.connectionInstanceId &&
|
|
340
|
+
enrollment.connectionLeaseExpiresAt &&
|
|
341
|
+
Date.parse(enrollment.connectionLeaseExpiresAt) > Date.now()
|
|
342
|
+
? Promise.resolve(enrollment)
|
|
343
|
+
: getLiveEnrollmentConnection(
|
|
344
|
+
db,
|
|
345
|
+
input.accountId && input.subjectId
|
|
346
|
+
? {
|
|
347
|
+
accountId: input.accountId,
|
|
348
|
+
workspaceId,
|
|
349
|
+
subjectId: input.subjectId,
|
|
350
|
+
}
|
|
351
|
+
: enrollment.workspaceId,
|
|
352
|
+
enrollment.id,
|
|
353
|
+
),
|
|
354
|
+
readLease(db, enrollment.workspaceId, sandbox.id),
|
|
239
355
|
]);
|
|
240
|
-
const
|
|
356
|
+
const liveness = enrollmentLiveness(enrollment);
|
|
357
|
+
const state = machineStateFor(liveness.state, liveness.hasDisplay);
|
|
241
358
|
|
|
242
359
|
// sharedSessionCount = the lease refcount for this machine's group. The
|
|
243
360
|
// selfhosted sandbox id IS the lease group key (maxSandboxes:1, N sessions
|
|
@@ -248,6 +365,8 @@ export async function listMachines(
|
|
|
248
365
|
return MachineView.parse({
|
|
249
366
|
sandboxId: sandbox.id,
|
|
250
367
|
enrollmentId: enrollment.id,
|
|
368
|
+
scope: enrollment.scope,
|
|
369
|
+
generation: enrollment.generation,
|
|
251
370
|
name: sandbox.name,
|
|
252
371
|
kind: "selfhosted",
|
|
253
372
|
state,
|
|
@@ -263,6 +382,9 @@ export async function listMachines(
|
|
|
263
382
|
allowScreenControl: enrollment.allowScreenControl,
|
|
264
383
|
sharedSessionCount,
|
|
265
384
|
lastSeenAt: enrollment.lastSeenAt,
|
|
385
|
+
connectionAuthority: connectionAuthorityFor(enrollment, liveConnection),
|
|
386
|
+
runtime: runtimeFor(services.settings, enrollment),
|
|
387
|
+
operationPolicy: enrollment.operationPolicy,
|
|
266
388
|
metrics: metricsRow ? metricRowToSample(metricsRow) : null,
|
|
267
389
|
});
|
|
268
390
|
}),
|