@opengeni/api-router 0.26.1 → 0.30.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 +1 -0
- package/dist/app.js +5 -3
- package/dist/auth/canonical-human-session-admission.d.ts +27 -0
- package/dist/browser-auth-broker.d.ts +20 -0
- package/dist/browser-controller-authority.d.ts +19 -1
- package/dist/browser-network-route.d.ts +8 -0
- package/dist/{chunk-JIKNR5YL.js → chunk-2PQMSRCB.js} +15518 -6863
- package/dist/chunk-2PQMSRCB.js.map +1 -0
- package/dist/controller-data-plane.d.ts +12 -0
- package/dist/http/auth.d.ts +1 -1
- package/dist/http/sse.d.ts +18 -1
- package/dist/index.js +1 -1
- package/dist/integrations/api-integrations.d.ts +2 -2
- package/dist/integrations/fiken.d.ts +233 -0
- package/dist/integrations/google-drive.d.ts +6 -6
- package/dist/integrations/provider-oauth.d.ts +0 -2
- package/dist/integrations/slack-bot.d.ts +171 -1
- package/dist/integrations/slack-interactions.d.ts +17 -5
- package/dist/interaction-holder-heartbeat.d.ts +17 -0
- package/dist/interaction-metrics.d.ts +11 -0
- package/dist/mcp/server.d.ts +3 -2
- package/dist/model-catalog.d.ts +1 -0
- package/dist/routes/canonical-human-identities.d.ts +3 -0
- package/dist/routes/channels.d.ts +3 -0
- package/dist/routes/integration-facets.d.ts +3 -0
- package/dist/routes/interaction-resources.d.ts +5 -0
- package/dist/routes/organization-memberships.d.ts +3 -0
- package/dist/routes/sessions.d.ts +2 -1
- package/dist/routes/slack-task-policy.d.ts +3 -0
- package/dist/routes/supergrok.d.ts +3 -0
- package/dist/sandbox/channel-a.d.ts +8 -1
- package/dist/sandbox/machines.d.ts +2 -2
- package/dist/sandbox/viewer.d.ts +3 -1
- package/dist/slack-reaction-files.d.ts +27 -0
- package/dist/transcription/providers/xai-subscription.d.ts +8 -0
- package/dist/xai-realtime.d.ts +26 -0
- package/dist/xai-subscription-auth.d.ts +23 -0
- package/package.json +17 -16
- package/src/app.ts +352 -49
- package/src/auth/canonical-human-session-admission.ts +116 -0
- package/src/auth/managed-auth.ts +101 -0
- package/src/browser-auth-broker.ts +155 -0
- package/src/browser-controller-authority.ts +50 -1
- package/src/browser-network-route.ts +34 -0
- package/src/controller-data-plane.ts +35 -0
- package/src/http/auth.ts +27 -9
- package/src/http/sse.ts +229 -5
- package/src/integrations/api-integrations.ts +57 -42
- package/src/integrations/fiken.ts +1230 -0
- package/src/integrations/google-drive.ts +31 -26
- package/src/integrations/provider-oauth.ts +70 -91
- package/src/integrations/slack-bot.ts +638 -9
- package/src/integrations/slack-interactions.ts +1583 -73
- package/src/interaction-holder-heartbeat.ts +95 -0
- package/src/interaction-metrics.ts +159 -0
- package/src/mcp/documents.ts +115 -6
- package/src/mcp/server.ts +865 -242
- package/src/model-catalog.ts +19 -6
- package/src/routes/api-integrations.ts +32 -29
- package/src/routes/browser-identities.ts +24 -0
- package/src/routes/browser-sessions.ts +2122 -183
- package/src/routes/canonical-human-identities.ts +156 -0
- package/src/routes/channels.ts +90 -0
- package/src/routes/computer-sessions.ts +441 -86
- package/src/routes/connections.ts +141 -4
- package/src/routes/{integration-features.ts → integration-facets.ts} +63 -63
- package/src/routes/interaction-resources.ts +595 -0
- package/src/routes/organization-memberships.ts +53 -0
- package/src/routes/plugins.ts +2 -1
- package/src/routes/sessions.ts +419 -43
- package/src/routes/skills.ts +92 -10
- package/src/routes/slack-task-policy.ts +115 -0
- package/src/routes/supergrok.ts +717 -0
- package/src/routes/transcription-recordings.ts +9 -2
- package/src/routes/transcriptions.ts +2 -1
- package/src/routes/video-generation.ts +34 -4
- package/src/routes/workspaces.ts +22 -4
- package/src/sandbox/channel-a.ts +29 -2
- package/src/sandbox/machines.ts +5 -5
- package/src/sandbox/viewer.ts +10 -3
- package/src/slack-reaction-files.ts +181 -0
- package/src/transcription/providers/xai-subscription.ts +110 -0
- package/src/transcription/service.ts +17 -2
- package/src/xai-realtime.ts +216 -0
- package/src/xai-subscription-auth.ts +132 -0
- package/dist/chunk-JIKNR5YL.js.map +0 -1
- package/dist/routes/integration-features.d.ts +0 -3
package/src/routes/skills.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
InstallLibrarySkillRequest,
|
|
2
3
|
InstallSkillRequest,
|
|
3
4
|
InstalledSkill,
|
|
5
|
+
ListInstalledSkillsResponse,
|
|
4
6
|
PreviewSkillImportRequest,
|
|
5
7
|
SkillImportPreview,
|
|
6
8
|
SkillUninstallPreview,
|
|
@@ -18,10 +20,13 @@ import {
|
|
|
18
20
|
import {
|
|
19
21
|
getPortableSkillUninstallPreview,
|
|
20
22
|
installPortableSkill,
|
|
23
|
+
listInstalledSkills,
|
|
21
24
|
PortableSkillInstallationVersionConflictError,
|
|
22
25
|
PortableSkillInstallationVersionRequiredError,
|
|
23
26
|
uninstallPortableSkill,
|
|
24
27
|
} from "@opengeni/db";
|
|
28
|
+
import { loadSkillLibrarySkill, skillLibraryRepositoryUrl } from "@opengeni/runtime/skill-library";
|
|
29
|
+
import { createHash } from "node:crypto";
|
|
25
30
|
import { HTTPException } from "hono/http-exception";
|
|
26
31
|
import type { Hono } from "hono";
|
|
27
32
|
|
|
@@ -38,6 +43,78 @@ export function registerSkillRoutes(
|
|
|
38
43
|
): void {
|
|
39
44
|
const github = overrides.github ?? createGitHubSkillSourceClient(deps.settings);
|
|
40
45
|
|
|
46
|
+
app.get("/v1/workspaces/:workspaceId/skills", async (c) => {
|
|
47
|
+
const workspaceId = c.req.param("workspaceId");
|
|
48
|
+
await requireAccessGrant(c, deps, workspaceId, "workspace:read");
|
|
49
|
+
return c.json(
|
|
50
|
+
ListInstalledSkillsResponse.parse({
|
|
51
|
+
skills: await listInstalledSkills(deps.db, workspaceId),
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
app.post("/v1/workspaces/:workspaceId/skills/library/:libraryId/install", async (c) => {
|
|
57
|
+
const workspaceId = c.req.param("workspaceId");
|
|
58
|
+
const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
|
|
59
|
+
const libraryId = decodeURIComponent(c.req.param("libraryId"));
|
|
60
|
+
const payload = InstallLibrarySkillRequest.parse(await c.req.json());
|
|
61
|
+
let loaded: ReturnType<typeof loadSkillLibrarySkill>;
|
|
62
|
+
try {
|
|
63
|
+
loaded = loadSkillLibrarySkill(libraryId, payload.expectedVersion);
|
|
64
|
+
} catch {
|
|
65
|
+
throw new HTTPException(404, { message: "Skill library entry not found" });
|
|
66
|
+
}
|
|
67
|
+
if (loaded.entry.contentSha256 !== payload.expectedContentSha256) {
|
|
68
|
+
throw new HTTPException(409, {
|
|
69
|
+
message:
|
|
70
|
+
"The curated Skill changed after review. Review the current version before installing.",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const files = loaded.skill.files.map((file) => {
|
|
74
|
+
const bytes = new TextEncoder().encode(file.content);
|
|
75
|
+
return {
|
|
76
|
+
path: file.path,
|
|
77
|
+
content: file.content,
|
|
78
|
+
byteSize: bytes.byteLength,
|
|
79
|
+
contentSha256: createHash("sha256").update(bytes).digest("hex"),
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
const installed = await installPortableSkill(deps.db, {
|
|
84
|
+
accountId: grant.accountId,
|
|
85
|
+
workspaceId,
|
|
86
|
+
subjectId: grant.subjectId,
|
|
87
|
+
capabilityId: `skill:${loaded.entry.id}`,
|
|
88
|
+
pluginKey: `skill/library/${loaded.entry.id}`,
|
|
89
|
+
source: "library",
|
|
90
|
+
version: loaded.entry.version,
|
|
91
|
+
sourceUrl: loaded.entry.sourceUrl,
|
|
92
|
+
repositoryUrl: skillLibraryRepositoryUrl(loaded.entry.sourceUrl),
|
|
93
|
+
sourceCommit: loaded.entry.sourceCommit,
|
|
94
|
+
sourcePath: loaded.entry.relativePath,
|
|
95
|
+
name: loaded.entry.name,
|
|
96
|
+
description: loaded.entry.description,
|
|
97
|
+
category: loaded.entry.category,
|
|
98
|
+
tags: [...loaded.entry.tags],
|
|
99
|
+
provenance: "platform",
|
|
100
|
+
sourceProvenance: loaded.entry.provenance,
|
|
101
|
+
contentSha256: loaded.entry.contentSha256,
|
|
102
|
+
totalBytes: files.reduce((total, file) => total + file.byteSize, 0),
|
|
103
|
+
license: loaded.entry.license,
|
|
104
|
+
files,
|
|
105
|
+
...(payload.expectedInstallationVersion !== undefined
|
|
106
|
+
? { expectedInstallationVersion: payload.expectedInstallationVersion }
|
|
107
|
+
: {}),
|
|
108
|
+
});
|
|
109
|
+
return c.json(
|
|
110
|
+
InstalledSkill.parse({ ...installed, status: "installed" }),
|
|
111
|
+
installed.created ? 201 : 200,
|
|
112
|
+
);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw portableSkillMutationHttpError(error);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
41
118
|
app.post("/v1/workspaces/:workspaceId/skills/preview", async (c) => {
|
|
42
119
|
const workspaceId = c.req.param("workspaceId");
|
|
43
120
|
await requireAccessGrant(c, deps, workspaceId, "workspace:read");
|
|
@@ -84,6 +161,7 @@ export function registerSkillRoutes(
|
|
|
84
161
|
source: resolved.preview.source,
|
|
85
162
|
sourceUrl: resolved.preview.sourceUrl,
|
|
86
163
|
repositoryUrl: resolved.preview.repositoryUrl,
|
|
164
|
+
version: resolved.preview.sourceCommit,
|
|
87
165
|
sourceCommit: resolved.preview.sourceCommit,
|
|
88
166
|
sourcePath: resolved.preview.sourcePath,
|
|
89
167
|
name: resolved.preview.name,
|
|
@@ -106,18 +184,10 @@ export function registerSkillRoutes(
|
|
|
106
184
|
});
|
|
107
185
|
return c.json(
|
|
108
186
|
InstalledSkill.parse({ ...installed, status: "installed" }),
|
|
109
|
-
|
|
187
|
+
installed.created ? 201 : 200,
|
|
110
188
|
);
|
|
111
189
|
} catch (error) {
|
|
112
|
-
|
|
113
|
-
throw new HTTPException(400, { message: error.message });
|
|
114
|
-
}
|
|
115
|
-
if (error instanceof PortableSkillInstallationVersionConflictError) {
|
|
116
|
-
throw new HTTPException(409, {
|
|
117
|
-
message: "The Skill changed after preview. Review the current installation again.",
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
throw error;
|
|
190
|
+
throw portableSkillMutationHttpError(error);
|
|
121
191
|
}
|
|
122
192
|
});
|
|
123
193
|
|
|
@@ -159,6 +229,18 @@ export function registerSkillRoutes(
|
|
|
159
229
|
});
|
|
160
230
|
}
|
|
161
231
|
|
|
232
|
+
function portableSkillMutationHttpError(error: unknown): Error {
|
|
233
|
+
if (error instanceof PortableSkillInstallationVersionRequiredError) {
|
|
234
|
+
return new HTTPException(400, { message: error.message });
|
|
235
|
+
}
|
|
236
|
+
if (error instanceof PortableSkillInstallationVersionConflictError) {
|
|
237
|
+
return new HTTPException(409, {
|
|
238
|
+
message: "The Skill changed after review. Review the current installation again.",
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
242
|
+
}
|
|
243
|
+
|
|
162
244
|
async function resolveForRoute(
|
|
163
245
|
url: string,
|
|
164
246
|
github: Parameters<typeof resolveSkillImport>[1],
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
SlackTaskPolicyListResponse,
|
|
4
|
+
SlackTaskPolicyMutationResponse,
|
|
5
|
+
UpdateSlackTaskPolicyRequest,
|
|
6
|
+
} from "@opengeni/contracts";
|
|
7
|
+
import {
|
|
8
|
+
requireAccessGrant,
|
|
9
|
+
requireAccessGrantAuthorization,
|
|
10
|
+
type AccessGrantAuthorization,
|
|
11
|
+
type ApiRouteDeps,
|
|
12
|
+
} from "@opengeni/core";
|
|
13
|
+
import {
|
|
14
|
+
listSlackTaskPolicy,
|
|
15
|
+
SlackTaskPolicyAuthorityError,
|
|
16
|
+
SlackTaskPolicyConflictError,
|
|
17
|
+
SlackTaskPolicyInvalidOperationError,
|
|
18
|
+
SlackTaskPolicyOperationReuseError,
|
|
19
|
+
updateSlackTaskPolicy,
|
|
20
|
+
} from "@opengeni/db";
|
|
21
|
+
import type { Context, Hono } from "hono";
|
|
22
|
+
import { HTTPException } from "hono/http-exception";
|
|
23
|
+
|
|
24
|
+
function requireDirectWorkspaceAdmin(access: AccessGrantAuthorization): void {
|
|
25
|
+
const { grant } = access;
|
|
26
|
+
if (
|
|
27
|
+
!access.contextIntegrity ||
|
|
28
|
+
access.authenticatedSubjectId !== grant.subjectId ||
|
|
29
|
+
grant.principalKind !== "human_session" ||
|
|
30
|
+
grant.serviceInitiator ||
|
|
31
|
+
grant.serviceInitiatorContext ||
|
|
32
|
+
grant.subjectId.startsWith("api_key:")
|
|
33
|
+
) {
|
|
34
|
+
throw new HTTPException(403, {
|
|
35
|
+
message: "Slack task-policy administration requires a direct human-authorized request",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function policyError(context: Context, error: unknown): Response {
|
|
41
|
+
if (error instanceof SlackTaskPolicyConflictError) {
|
|
42
|
+
return context.json(
|
|
43
|
+
{ code: error.code, message: error.message, currentHead: error.currentHead },
|
|
44
|
+
409,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (error instanceof SlackTaskPolicyOperationReuseError) {
|
|
48
|
+
return context.json({ code: error.code, message: error.message }, 409);
|
|
49
|
+
}
|
|
50
|
+
if (error instanceof SlackTaskPolicyAuthorityError) {
|
|
51
|
+
return context.json(
|
|
52
|
+
{ code: "SLACK_TASK_POLICY_AUTHORITY_REQUIRED", message: error.message },
|
|
53
|
+
403,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (error instanceof SlackTaskPolicyInvalidOperationError) {
|
|
57
|
+
return context.json(
|
|
58
|
+
{ code: "INVALID_SLACK_TASK_POLICY_OPERATION", message: error.message },
|
|
59
|
+
422,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function registerSlackTaskPolicyRoutes(app: Hono, deps: ApiRouteDeps): void {
|
|
66
|
+
const base = "/v1/workspaces/:workspaceId/slack-task-policy";
|
|
67
|
+
|
|
68
|
+
app.get(base, async (context) => {
|
|
69
|
+
const workspaceId = context.req.param("workspaceId");
|
|
70
|
+
const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:read");
|
|
71
|
+
return context.json(
|
|
72
|
+
SlackTaskPolicyListResponse.parse(
|
|
73
|
+
await listSlackTaskPolicy(deps.db, {
|
|
74
|
+
accountId: grant.accountId,
|
|
75
|
+
workspaceId,
|
|
76
|
+
}),
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
app.put(base, async (context) => {
|
|
82
|
+
const workspaceId = context.req.param("workspaceId");
|
|
83
|
+
const access = await requireAccessGrantAuthorization(
|
|
84
|
+
context,
|
|
85
|
+
deps,
|
|
86
|
+
workspaceId,
|
|
87
|
+
"workspace:admin",
|
|
88
|
+
);
|
|
89
|
+
requireDirectWorkspaceAdmin(access);
|
|
90
|
+
const parsed = UpdateSlackTaskPolicyRequest.safeParse(
|
|
91
|
+
await context.req.json().catch(() => null),
|
|
92
|
+
);
|
|
93
|
+
if (!parsed.success)
|
|
94
|
+
throw new HTTPException(422, { message: "Invalid Slack task-policy request" });
|
|
95
|
+
try {
|
|
96
|
+
return context.json(
|
|
97
|
+
SlackTaskPolicyMutationResponse.parse(
|
|
98
|
+
await updateSlackTaskPolicy(deps.db, {
|
|
99
|
+
operationId: parsed.data.operationId ?? randomUUID(),
|
|
100
|
+
accountId: access.grant.accountId,
|
|
101
|
+
workspaceId,
|
|
102
|
+
policy: parsed.data.policy,
|
|
103
|
+
expectedCurrentRevisionId: parsed.data.expectedCurrentRevisionId,
|
|
104
|
+
expectedActivationVersion: parsed.data.expectedActivationVersion,
|
|
105
|
+
actorSubjectId: access.grant.subjectId,
|
|
106
|
+
principalKind: "human_session",
|
|
107
|
+
reason: parsed.data.reason,
|
|
108
|
+
}),
|
|
109
|
+
),
|
|
110
|
+
);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
return policyError(context, error);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|