@opengeni/api-router 0.22.2 → 0.26.1
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.d.ts +2 -2
- package/dist/app.js +1 -1
- package/dist/auth/managed-auth.d.ts +0 -30
- package/dist/browser-controller-authority.d.ts +43 -0
- package/dist/browser-state-authority.d.ts +27 -0
- package/dist/{chunk-HWXJW5C7.js → chunk-JIKNR5YL.js} +27993 -14546
- package/dist/chunk-JIKNR5YL.js.map +1 -0
- package/dist/codemode.d.ts +23 -0
- package/dist/editable-artifact-live-hints.d.ts +11 -0
- package/dist/editable-artifact-native-kernel.d.ts +37 -0
- package/dist/editable-artifact-office-import.d.ts +22 -0
- package/dist/editable-artifact-production.d.ts +29 -0
- package/dist/editable-artifact-websocket.d.ts +49 -0
- package/dist/editable-artifact-workspace-files.d.ts +23 -0
- package/dist/github-browser-flow.d.ts +6 -0
- package/dist/http/cors.d.ts +1 -0
- package/dist/http/sse.d.ts +2 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1824 -30
- package/dist/index.js.map +1 -1
- package/dist/integrations/api-integrations.d.ts +24 -0
- package/dist/integrations/atlassian.d.ts +176 -0
- package/dist/integrations/github-skill-source.d.ts +5 -0
- package/dist/integrations/google-drive.d.ts +85 -0
- package/dist/integrations/oauth-client.d.ts +30 -1
- package/dist/integrations/provider-oauth.d.ts +19 -0
- package/dist/integrations/slack-bot.d.ts +4 -0
- package/dist/integrations/slack-interactions.d.ts +14 -2
- package/dist/integrations/social-api.d.ts +2 -1
- package/dist/mcp/editable-artifact-query-schema.d.ts +4 -0
- package/dist/mcp/editable-artifacts.d.ts +13 -0
- package/dist/mcp/receipts.d.ts +28 -0
- package/dist/mcp/scheduled-task-view.d.ts +518 -0
- package/dist/mcp/server.d.ts +14 -3
- package/dist/memory-slack-delivery.d.ts +9 -0
- package/dist/routes/api-integrations.d.ts +8 -0
- package/dist/routes/browser-identities.d.ts +5 -0
- package/dist/routes/browser-sessions.d.ts +6 -0
- package/dist/routes/company-profile.d.ts +3 -0
- package/dist/routes/computer-sessions.d.ts +6 -0
- package/dist/routes/editable-artifacts.d.ts +44 -0
- package/dist/routes/integration-features.d.ts +3 -0
- package/dist/routes/memory-slack-publications.d.ts +6 -0
- package/dist/routes/plugins.d.ts +8 -0
- package/dist/routes/sessions.d.ts +17 -2
- package/dist/routes/skills.d.ts +6 -0
- package/dist/routes/video-generation.d.ts +3 -0
- package/dist/sandbox/auth-callout.d.ts +2 -0
- package/dist/sandbox/channel-a.d.ts +59 -2
- package/dist/sandbox/metrics-ingestion.d.ts +6 -1
- package/dist/sandbox/viewer.d.ts +4 -2
- package/dist/temporal-schedule-cleanup.d.ts +26 -0
- package/package.json +19 -14
- package/src/app.ts +277 -41
- package/src/auth/managed-auth.ts +0 -16
- package/src/browser-controller-authority.ts +137 -0
- package/src/browser-state-authority.ts +236 -0
- package/src/codemode.ts +186 -0
- package/src/editable-artifact-live-hints.ts +64 -0
- package/src/editable-artifact-native-kernel.ts +659 -0
- package/src/editable-artifact-office-import.ts +230 -0
- package/src/editable-artifact-production.ts +419 -0
- package/src/editable-artifact-websocket.ts +311 -0
- package/src/editable-artifact-workspace-files.ts +186 -0
- package/src/github-browser-flow.ts +35 -6
- package/src/http/auth.ts +2 -0
- package/src/http/cors.ts +3 -0
- package/src/http/sse.ts +101 -6
- package/src/index.ts +147 -23
- package/src/integrations/api-integrations.ts +350 -0
- package/src/integrations/atlassian.ts +1621 -0
- package/src/integrations/github-skill-source.ts +142 -0
- package/src/integrations/google-drive.ts +1000 -64
- package/src/integrations/oauth-client.ts +159 -89
- package/src/integrations/provider-oauth.ts +777 -0
- package/src/integrations/slack-bot.ts +31 -2
- package/src/integrations/slack-interactions.ts +610 -42
- package/src/integrations/social-api.ts +11 -0
- package/src/mcp/documents.ts +74 -26
- package/src/mcp/editable-artifact-query-schema.ts +236 -0
- package/src/mcp/editable-artifacts.ts +448 -0
- package/src/mcp/receipts.ts +95 -0
- package/src/mcp/scheduled-task-view.ts +642 -0
- package/src/mcp/server.ts +1718 -310
- package/src/memory-slack-delivery.ts +209 -0
- package/src/observability.ts +3 -3
- package/src/routes/api-integrations.ts +407 -0
- package/src/routes/api-keys.ts +7 -1
- package/src/routes/browser-identities.ts +136 -0
- package/src/routes/browser-sessions.ts +2543 -0
- package/src/routes/codex.ts +7 -4
- package/src/routes/company-profile.ts +255 -0
- package/src/routes/computer-sessions.ts +1247 -0
- package/src/routes/connections.ts +358 -102
- package/src/routes/documents.ts +22 -3
- package/src/routes/editable-artifacts.ts +1159 -0
- package/src/routes/enrollments.ts +54 -12
- package/src/routes/environments.ts +60 -11
- package/src/routes/files.ts +277 -65
- package/src/routes/github.ts +18 -2
- package/src/routes/install.ts +38 -2
- package/src/routes/integration-features.ts +258 -0
- package/src/routes/machines.ts +1 -1
- package/src/routes/memory-slack-publications.ts +216 -0
- package/src/routes/packs.ts +437 -7
- package/src/routes/plugins.ts +751 -0
- package/src/routes/rigs.ts +77 -20
- package/src/routes/scheduled-tasks.ts +94 -42
- package/src/routes/sessions.ts +475 -234
- package/src/routes/skills.ts +174 -0
- package/src/routes/transcription-recordings.ts +65 -33
- package/src/routes/video-generation.ts +132 -0
- package/src/routes/workspaces.ts +46 -24
- package/src/sandbox/auth-callout.ts +16 -4
- package/src/sandbox/channel-a.ts +809 -85
- package/src/sandbox/enrollment.ts +13 -3
- package/src/sandbox/machines.ts +1 -1
- package/src/sandbox/metrics-ingestion.ts +121 -3
- package/src/sandbox/rematerialize.ts +35 -47
- package/src/sandbox/viewer.ts +58 -29
- package/src/temporal-schedule-cleanup.ts +135 -0
- package/dist/chunk-HWXJW5C7.js.map +0 -1
- package/dist/mcp/toolspace.d.ts +0 -62
- package/src/mcp/toolspace.ts +0 -1186
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
// workspace can approve it (the approve's user_code lookup is workspace-scoped) — a
|
|
21
21
|
// start can never grant access to a workspace no authorized user later approves in.
|
|
22
22
|
|
|
23
|
+
import { randomUUID } from "node:crypto";
|
|
23
24
|
import {
|
|
24
25
|
DeviceEnrollmentApproveRequest,
|
|
25
26
|
DeviceEnrollmentApproveResponse,
|
|
@@ -35,11 +36,18 @@ import {
|
|
|
35
36
|
ListEnrollmentsResponse,
|
|
36
37
|
MintEnrollTokenRequest,
|
|
37
38
|
MintEnrollTokenResponse,
|
|
39
|
+
RemoveEnrollmentRequest,
|
|
38
40
|
RevokeEnrollmentResponse,
|
|
39
41
|
type EnrollmentArch,
|
|
40
42
|
type EnrollmentOs,
|
|
41
43
|
} from "@opengeni/contracts";
|
|
42
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
getWorkspace,
|
|
46
|
+
listEnrollments,
|
|
47
|
+
MachineRemovalIdempotencyError,
|
|
48
|
+
MachineRemovalRevisionConflictError,
|
|
49
|
+
removeEnrollment,
|
|
50
|
+
} from "@opengeni/db";
|
|
43
51
|
import type { Context, Hono } from "hono";
|
|
44
52
|
import { HTTPException } from "hono/http-exception";
|
|
45
53
|
import { requireAccessGrant } from "@opengeni/core";
|
|
@@ -301,11 +309,12 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
301
309
|
await requireAccessGrant(c, deps, workspaceId, "enrollments:read");
|
|
302
310
|
assertSelfhostedEnabled();
|
|
303
311
|
const statusFilter = c.req.query("status");
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
312
|
+
if (statusFilter !== undefined && statusFilter !== "active" && statusFilter !== "revoked") {
|
|
313
|
+
throw new HTTPException(400, { message: "status must be active or revoked" });
|
|
314
|
+
}
|
|
315
|
+
const rows = await listEnrollments(db, workspaceId, {
|
|
316
|
+
status: statusFilter === "revoked" ? "revoked" : "active",
|
|
317
|
+
});
|
|
309
318
|
return c.json(
|
|
310
319
|
ListEnrollmentsResponse.parse({
|
|
311
320
|
enrollments: rows.map((row) =>
|
|
@@ -333,12 +342,45 @@ export function registerEnrollmentRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
333
342
|
const workspaceId = c.req.param("workspaceId");
|
|
334
343
|
const grant = await requireAccessGrant(c, deps, workspaceId, "enrollments:manage");
|
|
335
344
|
assertSelfhostedEnabled();
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
345
|
+
const parsed = RemoveEnrollmentRequest.safeParse(await c.req.json().catch(() => ({})));
|
|
346
|
+
if (!parsed.success) {
|
|
347
|
+
throw new HTTPException(400, { message: "invalid machine removal request" });
|
|
348
|
+
}
|
|
349
|
+
const idempotencyKey =
|
|
350
|
+
parsed.data.idempotencyKey?.trim() || c.req.header("idempotency-key")?.trim() || randomUUID();
|
|
351
|
+
try {
|
|
352
|
+
const result = await removeEnrollment(db, {
|
|
353
|
+
accountId: grant.accountId,
|
|
354
|
+
workspaceId,
|
|
355
|
+
enrollmentId: c.req.param("enrollmentId"),
|
|
356
|
+
operationKey: idempotencyKey,
|
|
357
|
+
...(parsed.data.expectedUpdatedAt
|
|
358
|
+
? { expectedUpdatedAt: parsed.data.expectedUpdatedAt }
|
|
359
|
+
: {}),
|
|
360
|
+
subjectId: grant.subjectId,
|
|
361
|
+
});
|
|
362
|
+
if (!result) {
|
|
363
|
+
throw new HTTPException(404, { message: "machine enrollment not found" });
|
|
364
|
+
}
|
|
365
|
+
return c.json(
|
|
366
|
+
RevokeEnrollmentResponse.parse({
|
|
367
|
+
revoked: result.removed,
|
|
368
|
+
...result,
|
|
369
|
+
}),
|
|
370
|
+
200,
|
|
371
|
+
);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
if (error instanceof MachineRemovalIdempotencyError) {
|
|
374
|
+
throw new HTTPException(409, { message: error.message });
|
|
375
|
+
}
|
|
376
|
+
if (error instanceof MachineRemovalRevisionConflictError) {
|
|
377
|
+
throw new HTTPException(409, {
|
|
378
|
+
message: error.message,
|
|
379
|
+
cause: { code: "stale_revision", currentUpdatedAt: error.currentUpdatedAt },
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
342
384
|
});
|
|
343
385
|
}
|
|
344
386
|
|
|
@@ -9,17 +9,19 @@ import {
|
|
|
9
9
|
countScheduledTasksUsingVariableSet,
|
|
10
10
|
countVariableSets,
|
|
11
11
|
createVariableSet,
|
|
12
|
+
decryptVariableSetValue,
|
|
12
13
|
deleteVariableSet,
|
|
13
14
|
deleteVariableSetVariable,
|
|
14
15
|
encryptVariableSetValue,
|
|
15
16
|
getVariableSetByName,
|
|
16
17
|
listVariableSets,
|
|
18
|
+
readVariableSetSecretAtomically,
|
|
17
19
|
setVariableSetVariable,
|
|
18
20
|
updateVariableSet,
|
|
19
21
|
} from "@opengeni/db";
|
|
20
22
|
import type { Hono } from "hono";
|
|
21
23
|
import { HTTPException } from "hono/http-exception";
|
|
22
|
-
import { requireAccessGrant } from "@opengeni/core";
|
|
24
|
+
import { requireAccessGrant, requireLiteralPermission, requirePermission } from "@opengeni/core";
|
|
23
25
|
import type { ApiRouteDeps } from "@opengeni/core";
|
|
24
26
|
import {
|
|
25
27
|
assertAllowedVariableSetVariableName,
|
|
@@ -40,15 +42,21 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
40
42
|
for (const prefix of prefixes) {
|
|
41
43
|
app.get(`${prefix}`, async (c) => {
|
|
42
44
|
const workspaceId = c.req.param("workspaceId")!;
|
|
43
|
-
await requireAccessGrant(c, deps, workspaceId
|
|
45
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
46
|
+
requirePermission(grant, "variable-sets:list");
|
|
47
|
+
requirePermission(grant, "secrets:list");
|
|
44
48
|
return c.json(await listVariableSets(db, workspaceId));
|
|
45
49
|
});
|
|
46
50
|
|
|
47
51
|
app.post(`${prefix}`, async (c) => {
|
|
48
52
|
const workspaceId = c.req.param("workspaceId")!;
|
|
49
|
-
const grant = await requireAccessGrant(c, deps, workspaceId
|
|
53
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
54
|
+
requirePermission(grant, "variable-sets:write");
|
|
50
55
|
const key = requireVariableSetEncryption(settings);
|
|
51
56
|
const payload = CreateVariableSetRequest.parse(await c.req.json());
|
|
57
|
+
if (payload.variables.length > 0) {
|
|
58
|
+
requirePermission(grant, "secrets:write");
|
|
59
|
+
}
|
|
52
60
|
const name = trimmedVariableSetName(payload.name);
|
|
53
61
|
if (payload.variables.length > MAX_VARIABLES_PER_ENVIRONMENT) {
|
|
54
62
|
throw new HTTPException(422, {
|
|
@@ -71,7 +79,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
71
79
|
});
|
|
72
80
|
}
|
|
73
81
|
if (await getVariableSetByName(db, workspaceId, name)) {
|
|
74
|
-
throw new HTTPException(409, {
|
|
82
|
+
throw new HTTPException(409, {
|
|
83
|
+
message: `variable set name is already in use: ${name}`,
|
|
84
|
+
});
|
|
75
85
|
}
|
|
76
86
|
// Values are encrypted up front and the variableSet plus all initial
|
|
77
87
|
// variables are written in one transaction: a failure leaves nothing.
|
|
@@ -95,13 +105,42 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
95
105
|
|
|
96
106
|
app.get(`${prefix}/:variableSetId`, async (c) => {
|
|
97
107
|
const workspaceId = c.req.param("workspaceId")!;
|
|
98
|
-
await requireAccessGrant(c, deps, workspaceId
|
|
108
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
109
|
+
requirePermission(grant, "variable-sets:read");
|
|
110
|
+
requirePermission(grant, "secrets:list");
|
|
99
111
|
return c.json(await requireVariableSetForApi(db, workspaceId, c.req.param("variableSetId")!));
|
|
100
112
|
});
|
|
101
113
|
|
|
114
|
+
if (prefix.endsWith("/variable-sets")) {
|
|
115
|
+
app.get(`${prefix}/:variableSetId/variables/:name`, async (c) => {
|
|
116
|
+
const workspaceId = c.req.param("workspaceId")!;
|
|
117
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
118
|
+
requirePermission(grant, "variable-sets:read");
|
|
119
|
+
requireLiteralPermission(grant, "secrets:read");
|
|
120
|
+
const key = requireVariableSetEncryption(settings);
|
|
121
|
+
const name = parseVariableName(c.req.param("name")!);
|
|
122
|
+
const secret = await readVariableSetSecretAtomically(db, {
|
|
123
|
+
accountId: grant.accountId,
|
|
124
|
+
workspaceId,
|
|
125
|
+
subjectId: grant.subjectId,
|
|
126
|
+
variableSetId: c.req.param("variableSetId")!,
|
|
127
|
+
name,
|
|
128
|
+
actor: { kind: "subject" },
|
|
129
|
+
decrypt: (valueEncrypted) => decryptVariableSetValue(key, valueEncrypted),
|
|
130
|
+
});
|
|
131
|
+
if (!secret) {
|
|
132
|
+
throw new HTTPException(404, {
|
|
133
|
+
message: "variable set variable not found",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return c.json(secret);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
102
140
|
app.patch(`${prefix}/:variableSetId`, async (c) => {
|
|
103
141
|
const workspaceId = c.req.param("workspaceId")!;
|
|
104
|
-
const grant = await requireAccessGrant(c, deps, workspaceId
|
|
142
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
143
|
+
requirePermission(grant, "variable-sets:write");
|
|
105
144
|
const variableSet = await requireVariableSetForApi(
|
|
106
145
|
db,
|
|
107
146
|
workspaceId,
|
|
@@ -112,7 +151,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
112
151
|
if (name !== undefined && name !== variableSet.name) {
|
|
113
152
|
const existing = await getVariableSetByName(db, workspaceId, name);
|
|
114
153
|
if (existing && existing.id !== variableSet.id) {
|
|
115
|
-
throw new HTTPException(409, {
|
|
154
|
+
throw new HTTPException(409, {
|
|
155
|
+
message: `variable set name is already in use: ${name}`,
|
|
156
|
+
});
|
|
116
157
|
}
|
|
117
158
|
}
|
|
118
159
|
const updated = await updateVariableSet(db, workspaceId, variableSet.id, {
|
|
@@ -129,7 +170,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
129
170
|
|
|
130
171
|
app.delete(`${prefix}/:variableSetId`, async (c) => {
|
|
131
172
|
const workspaceId = c.req.param("workspaceId")!;
|
|
132
|
-
const grant = await requireAccessGrant(c, deps, workspaceId
|
|
173
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
174
|
+
requirePermission(grant, "variable-sets:write");
|
|
175
|
+
requirePermission(grant, "secrets:write");
|
|
133
176
|
const variableSet = await requireVariableSetForApi(
|
|
134
177
|
db,
|
|
135
178
|
workspaceId,
|
|
@@ -166,7 +209,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
166
209
|
|
|
167
210
|
app.put(`${prefix}/:variableSetId/variables/:name`, async (c) => {
|
|
168
211
|
const workspaceId = c.req.param("workspaceId")!;
|
|
169
|
-
const grant = await requireAccessGrant(c, deps, workspaceId
|
|
212
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
213
|
+
requirePermission(grant, "variable-sets:write");
|
|
214
|
+
requirePermission(grant, "secrets:write");
|
|
170
215
|
const key = requireVariableSetEncryption(settings);
|
|
171
216
|
const name = parseVariableName(c.req.param("name")!);
|
|
172
217
|
const variableSet = await requireVariableSetForApi(
|
|
@@ -199,7 +244,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
199
244
|
|
|
200
245
|
app.delete(`${prefix}/:variableSetId/variables/:name`, async (c) => {
|
|
201
246
|
const workspaceId = c.req.param("workspaceId")!;
|
|
202
|
-
const grant = await requireAccessGrant(c, deps, workspaceId
|
|
247
|
+
const grant = await requireAccessGrant(c, deps, workspaceId);
|
|
248
|
+
requirePermission(grant, "variable-sets:write");
|
|
249
|
+
requirePermission(grant, "secrets:write");
|
|
203
250
|
const name = parseVariableName(c.req.param("name")!);
|
|
204
251
|
const variableSet = await requireVariableSetForApi(
|
|
205
252
|
db,
|
|
@@ -208,7 +255,9 @@ export function registerVariableSetRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
|
208
255
|
);
|
|
209
256
|
const deleted = await deleteVariableSetVariable(db, workspaceId, variableSet.id, name);
|
|
210
257
|
if (!deleted) {
|
|
211
|
-
throw new HTTPException(404, {
|
|
258
|
+
throw new HTTPException(404, {
|
|
259
|
+
message: "variable set variable not found",
|
|
260
|
+
});
|
|
212
261
|
}
|
|
213
262
|
await recordVariableSetAuditEvent(db, {
|
|
214
263
|
grant,
|