@opengeni/api-router 2.5.0 → 2.6.3-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/app.js +1 -1
- package/dist/auth/managed-auth-attempt-context.d.ts +5 -1
- package/dist/auth/managed-auth.d.ts +24 -1
- package/dist/{chunk-QESX7HDK.js → chunk-XTLI3CBH.js} +2236 -387
- package/dist/chunk-XTLI3CBH.js.map +1 -0
- package/dist/http/sse.d.ts +9 -0
- package/dist/index.js +104 -4
- package/dist/index.js.map +1 -1
- package/dist/interaction-metrics.d.ts +2 -0
- package/dist/mcp/company-brain-governed-writes.d.ts +1 -1
- package/dist/mcp/company-profile-agent-admin.d.ts +6 -6
- package/dist/mcp/remember.d.ts +2 -2
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/session-view.d.ts +1 -0
- package/dist/mcp/session-wait.d.ts +19 -0
- package/dist/routes/api-keys.d.ts +2 -0
- package/dist/routes/browser-sessions.d.ts +1 -0
- package/dist/routes/computer-sessions.d.ts +12 -0
- package/dist/routes/managed-auth-session-sets.d.ts +7 -0
- package/dist/routes/workspaces.d.ts +1 -1
- package/dist/sandbox/metrics-ingestion.d.ts +16 -0
- package/dist/workspace-delete-observability.d.ts +10 -0
- package/package.json +19 -19
- package/src/app.ts +172 -20
- package/src/auth/managed-auth-attempt-context.ts +40 -3
- package/src/auth/managed-auth-session-adapter.ts +1 -0
- package/src/auth/managed-auth.ts +164 -4
- package/src/http/sse.ts +279 -45
- package/src/integrations/oauth-client.ts +8 -1
- package/src/integrations/provider-oauth.ts +12 -2
- package/src/interaction-metrics.ts +30 -0
- package/src/mcp/company-brain-governed-writes.ts +38 -23
- package/src/mcp/company-profile-agent-admin.ts +7 -7
- package/src/mcp/remember.ts +19 -8
- package/src/mcp/server.ts +318 -26
- package/src/mcp/session-wait.ts +56 -8
- package/src/routes/api-integrations.ts +2 -2
- package/src/routes/api-keys.ts +149 -7
- package/src/routes/browser-sessions.ts +10 -2
- package/src/routes/capabilities.ts +3 -3
- package/src/routes/codex.ts +483 -74
- package/src/routes/company-profile.ts +64 -0
- package/src/routes/computer-sessions.ts +103 -1
- package/src/routes/integration-facets.ts +8 -5
- package/src/routes/interaction-resources.ts +7 -1
- package/src/routes/managed-auth-session-sets.ts +199 -2
- package/src/routes/organization-memberships.ts +28 -8
- package/src/routes/packs.ts +5 -5
- package/src/routes/plugins.ts +2 -2
- package/src/routes/scheduled-tasks.ts +9 -0
- package/src/routes/sessions.ts +3 -6
- package/src/routes/skills.ts +3 -3
- package/src/routes/workspaces.ts +293 -54
- package/src/sandbox/channel-a.ts +10 -4
- package/src/sandbox/machines.ts +13 -6
- package/src/sandbox/metrics-ingestion.ts +157 -3
- package/src/sandbox/viewer.ts +20 -1
- package/src/workspace-delete-observability.ts +75 -0
- package/dist/chunk-QESX7HDK.js.map +0 -1
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
import {
|
|
34
34
|
getManagedSession,
|
|
35
35
|
organizationMembershipHttpStatus,
|
|
36
|
+
requireCanonicalLocalAccountAdministrator,
|
|
36
37
|
type ApiRouteDeps,
|
|
37
38
|
} from "@opengeni/core";
|
|
38
39
|
import {
|
|
@@ -100,6 +101,25 @@ async function requireManagedHuman(context: Context, deps: ApiRouteDeps) {
|
|
|
100
101
|
return { session, subjectId: `user:${session.user.id}` };
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
async function requireOrganizationAdministrator(
|
|
105
|
+
context: Context,
|
|
106
|
+
deps: ApiRouteDeps,
|
|
107
|
+
organizationId: string,
|
|
108
|
+
): Promise<{ subjectId: string }> {
|
|
109
|
+
if (deps.settings.productAccessMode === "managed") {
|
|
110
|
+
return await requireManagedHuman(context, deps);
|
|
111
|
+
}
|
|
112
|
+
if (deps.settings.productAccessMode === "local") {
|
|
113
|
+
const { subjectId } = await requireCanonicalLocalAccountAdministrator(
|
|
114
|
+
context,
|
|
115
|
+
deps,
|
|
116
|
+
organizationId,
|
|
117
|
+
);
|
|
118
|
+
return { subjectId };
|
|
119
|
+
}
|
|
120
|
+
throw new HTTPException(401, { message: "organization administrator session required" });
|
|
121
|
+
}
|
|
122
|
+
|
|
103
123
|
async function parseBody<S extends z.ZodType>(context: Context, schema: S): Promise<z.infer<S>> {
|
|
104
124
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
105
125
|
if (!parsed.success) {
|
|
@@ -213,12 +233,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
213
233
|
});
|
|
214
234
|
|
|
215
235
|
app.get("/v1/organizations/:organizationId/overview", async (context) => {
|
|
216
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
217
236
|
const organizationId = parseId(
|
|
218
237
|
OrganizationId,
|
|
219
238
|
context.req.param("organizationId"),
|
|
220
239
|
"organization id",
|
|
221
240
|
);
|
|
241
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
222
242
|
try {
|
|
223
243
|
return context.json(
|
|
224
244
|
OrganizationAdministrationOverview.parse(
|
|
@@ -234,12 +254,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
234
254
|
});
|
|
235
255
|
|
|
236
256
|
app.patch("/v1/organizations/:organizationId", async (context) => {
|
|
237
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
238
257
|
const organizationId = parseId(
|
|
239
258
|
OrganizationId,
|
|
240
259
|
context.req.param("organizationId"),
|
|
241
260
|
"organization id",
|
|
242
261
|
);
|
|
262
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
243
263
|
const payload = await parseBody(context, UpdateOrganizationNameRequest);
|
|
244
264
|
try {
|
|
245
265
|
return context.json(
|
|
@@ -257,12 +277,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
257
277
|
});
|
|
258
278
|
|
|
259
279
|
app.patch("/v1/organizations/:organizationId/workspaces/:workspaceId", async (context) => {
|
|
260
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
261
280
|
const organizationId = parseId(
|
|
262
281
|
OrganizationId,
|
|
263
282
|
context.req.param("organizationId"),
|
|
264
283
|
"organization id",
|
|
265
284
|
);
|
|
285
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
266
286
|
const workspaceId = parseId(WorkspaceId, context.req.param("workspaceId"), "workspace id");
|
|
267
287
|
const payload = await parseBody(context, UpdateOrganizationWorkspaceRequest);
|
|
268
288
|
try {
|
|
@@ -284,12 +304,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
284
304
|
});
|
|
285
305
|
|
|
286
306
|
app.post("/v1/organizations/:organizationId/workspaces", async (context) => {
|
|
287
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
288
307
|
const organizationId = parseId(
|
|
289
308
|
OrganizationId,
|
|
290
309
|
context.req.param("organizationId"),
|
|
291
310
|
"organization id",
|
|
292
311
|
);
|
|
312
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
293
313
|
const payload = await parseBody(context, CreateOrganizationWorkspaceRequest);
|
|
294
314
|
try {
|
|
295
315
|
return context.json(
|
|
@@ -311,12 +331,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
311
331
|
app.patch(
|
|
312
332
|
"/v1/organizations/:organizationId/workspaces/:workspaceId/settings",
|
|
313
333
|
async (context) => {
|
|
314
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
315
334
|
const organizationId = parseId(
|
|
316
335
|
OrganizationId,
|
|
317
336
|
context.req.param("organizationId"),
|
|
318
337
|
"organization id",
|
|
319
338
|
);
|
|
339
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
320
340
|
const workspaceId = parseId(WorkspaceId, context.req.param("workspaceId"), "workspace id");
|
|
321
341
|
const payload = await parseBody(context, UpdateWorkspaceSettingsRequest);
|
|
322
342
|
try {
|
|
@@ -642,12 +662,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
642
662
|
);
|
|
643
663
|
|
|
644
664
|
app.get("/v1/organizations/:organizationId/members", async (context) => {
|
|
645
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
646
665
|
const organizationId = parseId(
|
|
647
666
|
OrganizationId,
|
|
648
667
|
context.req.param("organizationId"),
|
|
649
668
|
"organization id",
|
|
650
669
|
);
|
|
670
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
651
671
|
try {
|
|
652
672
|
return context.json(
|
|
653
673
|
ListOrganizationAdministrationMembersResponse.parse({
|
|
@@ -689,12 +709,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
689
709
|
});
|
|
690
710
|
|
|
691
711
|
app.get("/v1/organizations/:organizationId/retention-policy", async (context) => {
|
|
692
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
693
712
|
const organizationId = parseId(
|
|
694
713
|
OrganizationId,
|
|
695
714
|
context.req.param("organizationId"),
|
|
696
715
|
"organization id",
|
|
697
716
|
);
|
|
717
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
698
718
|
try {
|
|
699
719
|
return context.json(
|
|
700
720
|
OrganizationRetentionPolicy.parse(
|
|
@@ -710,12 +730,12 @@ export function registerOrganizationMembershipRoutes(app: Hono, deps: ApiRouteDe
|
|
|
710
730
|
});
|
|
711
731
|
|
|
712
732
|
app.patch("/v1/organizations/:organizationId/retention-policy", async (context) => {
|
|
713
|
-
const { subjectId } = await requireManagedHuman(context, deps);
|
|
714
733
|
const organizationId = parseId(
|
|
715
734
|
OrganizationId,
|
|
716
735
|
context.req.param("organizationId"),
|
|
717
736
|
"organization id",
|
|
718
737
|
);
|
|
738
|
+
const { subjectId } = await requireOrganizationAdministrator(context, deps, organizationId);
|
|
719
739
|
const payload = await parseBody(context, UpdateOrganizationRetentionPolicyRequest);
|
|
720
740
|
try {
|
|
721
741
|
return context.json(
|
package/src/routes/packs.ts
CHANGED
|
@@ -83,7 +83,7 @@ export function registerPackRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
83
83
|
// Built-in pack ids stay reserved so a registration can never shadow them.
|
|
84
84
|
app.post("/v1/workspaces/:workspaceId/packs", async (c) => {
|
|
85
85
|
const workspaceId = c.req.param("workspaceId");
|
|
86
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
86
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
87
87
|
const manifest = RegisterCapabilityPackRequest.parse(await c.req.json());
|
|
88
88
|
if (isBuiltInCapabilityPack(manifest.id)) {
|
|
89
89
|
throw new HTTPException(409, {
|
|
@@ -100,7 +100,7 @@ export function registerPackRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
100
100
|
|
|
101
101
|
app.delete("/v1/workspaces/:workspaceId/packs/:packId", async (c) => {
|
|
102
102
|
const workspaceId = c.req.param("workspaceId");
|
|
103
|
-
await requireAccessGrant(c, deps, workspaceId, "
|
|
103
|
+
await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
104
104
|
const packId = c.req.param("packId");
|
|
105
105
|
if (isBuiltInCapabilityPack(packId)) {
|
|
106
106
|
throw new HTTPException(409, {
|
|
@@ -172,7 +172,7 @@ export function registerPackRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
172
172
|
|
|
173
173
|
app.post("/v1/workspaces/:workspaceId/packs/:packId/install", async (c) => {
|
|
174
174
|
const workspaceId = c.req.param("workspaceId");
|
|
175
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
175
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
176
176
|
const pack = await requirePack(db, workspaceId, c.req.param("packId"));
|
|
177
177
|
const payload = InstallPackRequest.parse(await c.req.json());
|
|
178
178
|
const preview = PackInstallationPreview.parse(
|
|
@@ -393,7 +393,7 @@ export function registerPackRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
393
393
|
|
|
394
394
|
app.delete("/v1/workspaces/:workspaceId/packs/:packId/installation", async (c) => {
|
|
395
395
|
const workspaceId = c.req.param("workspaceId");
|
|
396
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
396
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
397
397
|
const pack = await requirePack(db, workspaceId, c.req.param("packId"));
|
|
398
398
|
const payload = UninstallPackRequest.parse(await c.req.json());
|
|
399
399
|
const requestDigest = sha256(
|
|
@@ -483,7 +483,7 @@ export function registerPackRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
483
483
|
|
|
484
484
|
app.post("/v1/workspaces/:workspaceId/packs/:packId/enable", async (c) => {
|
|
485
485
|
const workspaceId = c.req.param("workspaceId");
|
|
486
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
486
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
487
487
|
const pack = await requirePack(db, workspaceId, c.req.param("packId"));
|
|
488
488
|
if (capabilityPackRequiresInstallationPlan(pack)) {
|
|
489
489
|
throw new HTTPException(409, {
|
package/src/routes/plugins.ts
CHANGED
|
@@ -120,7 +120,7 @@ export function registerPluginRoutes(
|
|
|
120
120
|
|
|
121
121
|
app.post("/v1/workspaces/:workspaceId/plugins/install", async (c) => {
|
|
122
122
|
const workspaceId = c.req.param("workspaceId");
|
|
123
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
123
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
124
124
|
const payload = InstallPluginRequest.parse(await c.req.json());
|
|
125
125
|
const resolved = await resolvePluginPackage({
|
|
126
126
|
deps,
|
|
@@ -253,7 +253,7 @@ export function registerPluginRoutes(
|
|
|
253
253
|
|
|
254
254
|
app.delete("/v1/workspaces/:workspaceId/plugins/:pluginKey", async (c) => {
|
|
255
255
|
const workspaceId = c.req.param("workspaceId");
|
|
256
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
256
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
257
257
|
const pluginKey = decodeURIComponent(c.req.param("pluginKey"));
|
|
258
258
|
const payload = UninstallPluginRequest.parse(await c.req.json());
|
|
259
259
|
try {
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
syncCreatedScheduledTask,
|
|
23
23
|
syncUpdatedScheduledTask,
|
|
24
24
|
updateScheduledTaskForApi,
|
|
25
|
+
validateScheduledTaskMachineTarget,
|
|
25
26
|
validateScheduledTaskTarget,
|
|
26
27
|
validatedScheduledTaskUpdate,
|
|
27
28
|
} from "@opengeni/core";
|
|
@@ -157,6 +158,14 @@ export function registerScheduledTaskRoutes(app: Hono, deps: ApiRouteDeps): void
|
|
|
157
158
|
agentConfig: task.agentConfig,
|
|
158
159
|
missingTargetStatus: 404,
|
|
159
160
|
});
|
|
161
|
+
await validateScheduledTaskMachineTarget({
|
|
162
|
+
settings,
|
|
163
|
+
db,
|
|
164
|
+
grant,
|
|
165
|
+
runMode: task.runMode,
|
|
166
|
+
agentConfig: task.agentConfig,
|
|
167
|
+
requireOnline: true,
|
|
168
|
+
});
|
|
160
169
|
await requireLimit(deps, {
|
|
161
170
|
accountId: grant.accountId,
|
|
162
171
|
workspaceId,
|
package/src/routes/sessions.ts
CHANGED
|
@@ -284,7 +284,7 @@ import {
|
|
|
284
284
|
validateVariableSetAttachment,
|
|
285
285
|
} from "@opengeni/core";
|
|
286
286
|
import { assertSessionExists, boundedLimit } from "../http/common";
|
|
287
|
-
import { sseSessionStream } from "../http/sse";
|
|
287
|
+
import { browserSseDeliveryOptions, sseSessionStream } from "../http/sse";
|
|
288
288
|
import {
|
|
289
289
|
serveWorkspaceCapture,
|
|
290
290
|
serveWorkspaceCaptureFile,
|
|
@@ -2659,6 +2659,7 @@ export function registerSessionRoutes(app: Hono, deps: SessionRouteDeps): void {
|
|
|
2659
2659
|
Number.isFinite(after) ? after : 0,
|
|
2660
2660
|
c.req.raw.signal,
|
|
2661
2661
|
{
|
|
2662
|
+
...browserSseDeliveryOptions(c.req.query("transport")),
|
|
2662
2663
|
observability: deps.observability,
|
|
2663
2664
|
actorEpoch: getManagedAuthRequestActorEpoch(c.req.raw) ?? undefined,
|
|
2664
2665
|
reauthorizeAfterMs:
|
|
@@ -3201,12 +3202,8 @@ export function registerSessionRoutes(app: Hono, deps: SessionRouteDeps): void {
|
|
|
3201
3202
|
// Human take-control: when the desktop is available + this policy is on
|
|
3202
3203
|
// (default), the cell is mode "interactive" — the noVNC viewer drives :0
|
|
3203
3204
|
// (x11vnc runs without -viewonly). Off → mode "read-only" (client disables
|
|
3204
|
-
// take-control).
|
|
3205
|
+
// take-control). Agent interaction uses managed ComputerSession tools.
|
|
3205
3206
|
desktopInteractive: settings.sandboxDesktopInteractive,
|
|
3206
|
-
// P4.3 computer-use: the agent drives the active display; availability
|
|
3207
|
-
// tracks the desktop tier + a desktop-capable backend.
|
|
3208
|
-
computerUseEnabled: settings.computerUseEnabled,
|
|
3209
|
-
computerUseReadOnly: settings.computerUseReadOnly,
|
|
3210
3207
|
// Graceful degrade when scoped stream credentials cannot be minted.
|
|
3211
3208
|
streamTokenSecretAvailable: !streamTokenDegraded(settings),
|
|
3212
3209
|
desktopAcknowledged: acknowledged,
|
package/src/routes/skills.ts
CHANGED
|
@@ -55,7 +55,7 @@ export function registerSkillRoutes(
|
|
|
55
55
|
|
|
56
56
|
app.post("/v1/workspaces/:workspaceId/skills/library/:libraryId/install", async (c) => {
|
|
57
57
|
const workspaceId = c.req.param("workspaceId");
|
|
58
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
58
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
59
59
|
const libraryId = decodeURIComponent(c.req.param("libraryId"));
|
|
60
60
|
const payload = InstallLibrarySkillRequest.parse(await c.req.json());
|
|
61
61
|
let loaded: ReturnType<typeof loadSkillLibrarySkill>;
|
|
@@ -136,7 +136,7 @@ export function registerSkillRoutes(
|
|
|
136
136
|
|
|
137
137
|
app.post("/v1/workspaces/:workspaceId/skills/install", async (c) => {
|
|
138
138
|
const workspaceId = c.req.param("workspaceId");
|
|
139
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
139
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
140
140
|
const payload = InstallSkillRequest.parse(await c.req.json());
|
|
141
141
|
const resolved = await resolveForRoute(payload.url, github);
|
|
142
142
|
if (
|
|
@@ -204,7 +204,7 @@ export function registerSkillRoutes(
|
|
|
204
204
|
|
|
205
205
|
app.delete("/v1/workspaces/:workspaceId/skills/:capabilityId", async (c) => {
|
|
206
206
|
const workspaceId = c.req.param("workspaceId");
|
|
207
|
-
const grant = await requireAccessGrant(c, deps, workspaceId, "
|
|
207
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "capabilities:manage");
|
|
208
208
|
const capabilityId = decodeURIComponent(c.req.param("capabilityId"));
|
|
209
209
|
const payload = UninstallSkillRequest.parse(await c.req.json());
|
|
210
210
|
try {
|