@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.
Files changed (124) hide show
  1. package/dist/app.d.ts +2 -2
  2. package/dist/app.js +1 -1
  3. package/dist/auth/managed-auth.d.ts +0 -30
  4. package/dist/browser-controller-authority.d.ts +43 -0
  5. package/dist/browser-state-authority.d.ts +27 -0
  6. package/dist/{chunk-HWXJW5C7.js → chunk-JIKNR5YL.js} +27993 -14546
  7. package/dist/chunk-JIKNR5YL.js.map +1 -0
  8. package/dist/codemode.d.ts +23 -0
  9. package/dist/editable-artifact-live-hints.d.ts +11 -0
  10. package/dist/editable-artifact-native-kernel.d.ts +37 -0
  11. package/dist/editable-artifact-office-import.d.ts +22 -0
  12. package/dist/editable-artifact-production.d.ts +29 -0
  13. package/dist/editable-artifact-websocket.d.ts +49 -0
  14. package/dist/editable-artifact-workspace-files.d.ts +23 -0
  15. package/dist/github-browser-flow.d.ts +6 -0
  16. package/dist/http/cors.d.ts +1 -0
  17. package/dist/http/sse.d.ts +2 -0
  18. package/dist/index.d.ts +3 -2
  19. package/dist/index.js +1824 -30
  20. package/dist/index.js.map +1 -1
  21. package/dist/integrations/api-integrations.d.ts +24 -0
  22. package/dist/integrations/atlassian.d.ts +176 -0
  23. package/dist/integrations/github-skill-source.d.ts +5 -0
  24. package/dist/integrations/google-drive.d.ts +85 -0
  25. package/dist/integrations/oauth-client.d.ts +30 -1
  26. package/dist/integrations/provider-oauth.d.ts +19 -0
  27. package/dist/integrations/slack-bot.d.ts +4 -0
  28. package/dist/integrations/slack-interactions.d.ts +14 -2
  29. package/dist/integrations/social-api.d.ts +2 -1
  30. package/dist/mcp/editable-artifact-query-schema.d.ts +4 -0
  31. package/dist/mcp/editable-artifacts.d.ts +13 -0
  32. package/dist/mcp/receipts.d.ts +28 -0
  33. package/dist/mcp/scheduled-task-view.d.ts +518 -0
  34. package/dist/mcp/server.d.ts +14 -3
  35. package/dist/memory-slack-delivery.d.ts +9 -0
  36. package/dist/routes/api-integrations.d.ts +8 -0
  37. package/dist/routes/browser-identities.d.ts +5 -0
  38. package/dist/routes/browser-sessions.d.ts +6 -0
  39. package/dist/routes/company-profile.d.ts +3 -0
  40. package/dist/routes/computer-sessions.d.ts +6 -0
  41. package/dist/routes/editable-artifacts.d.ts +44 -0
  42. package/dist/routes/integration-features.d.ts +3 -0
  43. package/dist/routes/memory-slack-publications.d.ts +6 -0
  44. package/dist/routes/plugins.d.ts +8 -0
  45. package/dist/routes/sessions.d.ts +17 -2
  46. package/dist/routes/skills.d.ts +6 -0
  47. package/dist/routes/video-generation.d.ts +3 -0
  48. package/dist/sandbox/auth-callout.d.ts +2 -0
  49. package/dist/sandbox/channel-a.d.ts +59 -2
  50. package/dist/sandbox/metrics-ingestion.d.ts +6 -1
  51. package/dist/sandbox/viewer.d.ts +4 -2
  52. package/dist/temporal-schedule-cleanup.d.ts +26 -0
  53. package/package.json +19 -14
  54. package/src/app.ts +277 -41
  55. package/src/auth/managed-auth.ts +0 -16
  56. package/src/browser-controller-authority.ts +137 -0
  57. package/src/browser-state-authority.ts +236 -0
  58. package/src/codemode.ts +186 -0
  59. package/src/editable-artifact-live-hints.ts +64 -0
  60. package/src/editable-artifact-native-kernel.ts +659 -0
  61. package/src/editable-artifact-office-import.ts +230 -0
  62. package/src/editable-artifact-production.ts +419 -0
  63. package/src/editable-artifact-websocket.ts +311 -0
  64. package/src/editable-artifact-workspace-files.ts +186 -0
  65. package/src/github-browser-flow.ts +35 -6
  66. package/src/http/auth.ts +2 -0
  67. package/src/http/cors.ts +3 -0
  68. package/src/http/sse.ts +101 -6
  69. package/src/index.ts +147 -23
  70. package/src/integrations/api-integrations.ts +350 -0
  71. package/src/integrations/atlassian.ts +1621 -0
  72. package/src/integrations/github-skill-source.ts +142 -0
  73. package/src/integrations/google-drive.ts +1000 -64
  74. package/src/integrations/oauth-client.ts +159 -89
  75. package/src/integrations/provider-oauth.ts +777 -0
  76. package/src/integrations/slack-bot.ts +31 -2
  77. package/src/integrations/slack-interactions.ts +610 -42
  78. package/src/integrations/social-api.ts +11 -0
  79. package/src/mcp/documents.ts +74 -26
  80. package/src/mcp/editable-artifact-query-schema.ts +236 -0
  81. package/src/mcp/editable-artifacts.ts +448 -0
  82. package/src/mcp/receipts.ts +95 -0
  83. package/src/mcp/scheduled-task-view.ts +642 -0
  84. package/src/mcp/server.ts +1718 -310
  85. package/src/memory-slack-delivery.ts +209 -0
  86. package/src/observability.ts +3 -3
  87. package/src/routes/api-integrations.ts +407 -0
  88. package/src/routes/api-keys.ts +7 -1
  89. package/src/routes/browser-identities.ts +136 -0
  90. package/src/routes/browser-sessions.ts +2543 -0
  91. package/src/routes/codex.ts +7 -4
  92. package/src/routes/company-profile.ts +255 -0
  93. package/src/routes/computer-sessions.ts +1247 -0
  94. package/src/routes/connections.ts +358 -102
  95. package/src/routes/documents.ts +22 -3
  96. package/src/routes/editable-artifacts.ts +1159 -0
  97. package/src/routes/enrollments.ts +54 -12
  98. package/src/routes/environments.ts +60 -11
  99. package/src/routes/files.ts +277 -65
  100. package/src/routes/github.ts +18 -2
  101. package/src/routes/install.ts +38 -2
  102. package/src/routes/integration-features.ts +258 -0
  103. package/src/routes/machines.ts +1 -1
  104. package/src/routes/memory-slack-publications.ts +216 -0
  105. package/src/routes/packs.ts +437 -7
  106. package/src/routes/plugins.ts +751 -0
  107. package/src/routes/rigs.ts +77 -20
  108. package/src/routes/scheduled-tasks.ts +94 -42
  109. package/src/routes/sessions.ts +475 -234
  110. package/src/routes/skills.ts +174 -0
  111. package/src/routes/transcription-recordings.ts +65 -33
  112. package/src/routes/video-generation.ts +132 -0
  113. package/src/routes/workspaces.ts +46 -24
  114. package/src/sandbox/auth-callout.ts +16 -4
  115. package/src/sandbox/channel-a.ts +809 -85
  116. package/src/sandbox/enrollment.ts +13 -3
  117. package/src/sandbox/machines.ts +1 -1
  118. package/src/sandbox/metrics-ingestion.ts +121 -3
  119. package/src/sandbox/rematerialize.ts +35 -47
  120. package/src/sandbox/viewer.ts +58 -29
  121. package/src/temporal-schedule-cleanup.ts +135 -0
  122. package/dist/chunk-HWXJW5C7.js.map +0 -1
  123. package/dist/mcp/toolspace.d.ts +0 -62
  124. package/src/mcp/toolspace.ts +0 -1186
@@ -150,7 +150,12 @@ export function codexModelsForPicker(liveSlugs: readonly string[]): Array<{
150
150
  }));
151
151
  }
152
152
  import { createSignedState, readSignedState } from "@opengeni/github";
153
- import { hasPermission, requireAccessGrant, type ApiRouteDeps } from "@opengeni/core";
153
+ import {
154
+ getManagedSession,
155
+ hasPermission,
156
+ requireAccessGrant,
157
+ type ApiRouteDeps,
158
+ } from "@opengeni/core";
154
159
  import type { Context, Hono } from "hono";
155
160
  import { HTTPException } from "hono/http-exception";
156
161
  import * as z from "zod/v4";
@@ -190,9 +195,7 @@ async function managedCookieHuman(
190
195
  ) {
191
196
  return null;
192
197
  }
193
- const session = await deps.managedAuth.api.getSession({
194
- headers: c.req.raw.headers,
195
- });
198
+ const session = await getManagedSession(c, deps.managedAuth);
196
199
  if (!session?.user?.id || !session.session?.id) return null;
197
200
  return {
198
201
  subjectId: `user:${session.user.id}`,
@@ -0,0 +1,255 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import {
3
+ ActivateCompanyProfileRevisionRequest,
4
+ CompanyProfileConflictResponse,
5
+ CompanyProfileDiffRequest,
6
+ CompanyProfileDiffResponse,
7
+ CompanyProfileListQuery,
8
+ CompanyProfileListResponse,
9
+ CompanyProfileMutationResponse,
10
+ CompanyProfileOperationReuseResponse,
11
+ CompanyProfileRevision,
12
+ RollbackCompanyProfileRequest,
13
+ UpdateCompanyProfileRequest,
14
+ } from "@opengeni/contracts";
15
+ import {
16
+ requireAccessGrant,
17
+ requireAccessGrantAuthorization,
18
+ type AccessGrantAuthorization,
19
+ type ApiRouteDeps,
20
+ } from "@opengeni/core";
21
+ import {
22
+ activateCompanyProfileRevision,
23
+ CompanyProfileConflictError,
24
+ CompanyProfileInvalidOperationError,
25
+ CompanyProfileNotFoundError,
26
+ CompanyProfileOperationReuseError,
27
+ diffCompanyProfileRevisions,
28
+ getCompanyProfileRevision,
29
+ listCompanyProfile,
30
+ rollbackCompanyProfileRevision,
31
+ updateCompanyProfile,
32
+ } from "@opengeni/db";
33
+ import type { Context, Hono } from "hono";
34
+ import { HTTPException } from "hono/http-exception";
35
+ import { z } from "zod";
36
+
37
+ const RevisionId = z.string().uuid();
38
+
39
+ async function parseBody<S extends z.ZodType>(context: Context, schema: S): Promise<z.infer<S>> {
40
+ const parsed = schema.safeParse(await context.req.json().catch(() => null));
41
+ if (!parsed.success) throw new HTTPException(422, { message: "Invalid company-profile request" });
42
+ return parsed.data;
43
+ }
44
+
45
+ function requireDirectAccountAdmin(access: AccessGrantAuthorization): void {
46
+ const { grant } = access;
47
+ if (
48
+ !access.contextIntegrity ||
49
+ access.authenticatedSubjectId !== grant.subjectId ||
50
+ grant.principalKind !== "human_session" ||
51
+ grant.serviceInitiator ||
52
+ grant.serviceInitiatorContext ||
53
+ grant.subjectId.startsWith("api_key:")
54
+ ) {
55
+ throw new HTTPException(403, {
56
+ message: "Company-profile administration requires a direct human-authorized request",
57
+ });
58
+ }
59
+ if (!access.accountGrant?.permissions.includes("account:admin")) {
60
+ throw new HTTPException(403, { message: "missing permission: account:admin" });
61
+ }
62
+ }
63
+
64
+ function profileError(context: Context, error: unknown): Response {
65
+ if (error instanceof CompanyProfileConflictError) {
66
+ return context.json(
67
+ CompanyProfileConflictResponse.parse({
68
+ code: error.code,
69
+ message: error.message,
70
+ currentHead: error.currentHead,
71
+ }),
72
+ 409,
73
+ );
74
+ }
75
+ if (error instanceof CompanyProfileOperationReuseError) {
76
+ return context.json(
77
+ CompanyProfileOperationReuseResponse.parse({ code: error.code, message: error.message }),
78
+ 409,
79
+ );
80
+ }
81
+ if (error instanceof CompanyProfileNotFoundError) {
82
+ return context.json({ code: "COMPANY_PROFILE_NOT_FOUND", message: error.message }, 404);
83
+ }
84
+ if (error instanceof CompanyProfileInvalidOperationError) {
85
+ return context.json({ code: "INVALID_COMPANY_PROFILE_OPERATION", message: error.message }, 422);
86
+ }
87
+ throw error;
88
+ }
89
+
90
+ function revisionId(context: Context): string {
91
+ const parsed = RevisionId.safeParse(context.req.param("revisionId"));
92
+ if (!parsed.success)
93
+ throw new HTTPException(422, { message: "Invalid company-profile revision id" });
94
+ return parsed.data;
95
+ }
96
+
97
+ export function registerCompanyProfileRoutes(app: Hono, deps: ApiRouteDeps): void {
98
+ const base = "/v1/workspaces/:workspaceId/company-profile";
99
+
100
+ app.get(base, async (context) => {
101
+ const workspaceId = context.req.param("workspaceId");
102
+ const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:read");
103
+ const query = CompanyProfileListQuery.safeParse({
104
+ afterRevision: context.req.query("afterRevision"),
105
+ limit: context.req.query("limit"),
106
+ });
107
+ if (!query.success) throw new HTTPException(422, { message: "Invalid company-profile query" });
108
+ return context.json(
109
+ CompanyProfileListResponse.parse(
110
+ await listCompanyProfile(deps.db, {
111
+ accountId: grant.accountId,
112
+ workspaceId,
113
+ limit: query.data.limit,
114
+ ...(query.data.afterRevision === undefined
115
+ ? {}
116
+ : { afterRevision: query.data.afterRevision }),
117
+ }),
118
+ ),
119
+ );
120
+ });
121
+
122
+ app.put(base, async (context) => {
123
+ const workspaceId = context.req.param("workspaceId");
124
+ const access = await requireAccessGrantAuthorization(
125
+ context,
126
+ deps,
127
+ workspaceId,
128
+ "workspace:read",
129
+ );
130
+ requireDirectAccountAdmin(access);
131
+ const request = await parseBody(context, UpdateCompanyProfileRequest);
132
+ try {
133
+ return context.json(
134
+ CompanyProfileMutationResponse.parse(
135
+ await updateCompanyProfile(deps.db, {
136
+ operationId: request.operationId ?? randomUUID(),
137
+ accountId: access.grant.accountId,
138
+ workspaceId,
139
+ profile: request.profile,
140
+ expectedCurrentRevisionId: request.expectedCurrentRevisionId,
141
+ expectedActivationVersion: request.expectedActivationVersion,
142
+ actorSubjectId: access.grant.subjectId,
143
+ principalKind: "human_session",
144
+ reason: request.reason,
145
+ }),
146
+ ),
147
+ );
148
+ } catch (error) {
149
+ return profileError(context, error);
150
+ }
151
+ });
152
+
153
+ app.get(`${base}/diff`, async (context) => {
154
+ const workspaceId = context.req.param("workspaceId");
155
+ const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:read");
156
+ const request = CompanyProfileDiffRequest.safeParse({
157
+ fromRevisionId: context.req.query("fromRevisionId"),
158
+ toRevisionId: context.req.query("toRevisionId"),
159
+ });
160
+ if (!request.success) throw new HTTPException(422, { message: "Invalid company-profile diff" });
161
+ try {
162
+ return context.json(
163
+ CompanyProfileDiffResponse.parse(
164
+ await diffCompanyProfileRevisions(deps.db, {
165
+ accountId: grant.accountId,
166
+ workspaceId,
167
+ ...request.data,
168
+ }),
169
+ ),
170
+ );
171
+ } catch (error) {
172
+ return profileError(context, error);
173
+ }
174
+ });
175
+
176
+ app.post(`${base}/rollback`, async (context) => {
177
+ const workspaceId = context.req.param("workspaceId");
178
+ const access = await requireAccessGrantAuthorization(
179
+ context,
180
+ deps,
181
+ workspaceId,
182
+ "workspace:read",
183
+ );
184
+ requireDirectAccountAdmin(access);
185
+ const request = await parseBody(context, RollbackCompanyProfileRequest);
186
+ try {
187
+ return context.json(
188
+ CompanyProfileMutationResponse.parse(
189
+ await rollbackCompanyProfileRevision(deps.db, {
190
+ operationId: request.operationId ?? randomUUID(),
191
+ accountId: access.grant.accountId,
192
+ workspaceId,
193
+ targetRevisionId: request.targetRevisionId,
194
+ expectedCurrentRevisionId: request.expectedCurrentRevisionId,
195
+ expectedActivationVersion: request.expectedActivationVersion,
196
+ actorSubjectId: access.grant.subjectId,
197
+ principalKind: "human_session",
198
+ reason: request.reason,
199
+ }),
200
+ ),
201
+ );
202
+ } catch (error) {
203
+ return profileError(context, error);
204
+ }
205
+ });
206
+
207
+ app.get(`${base}/revisions/:revisionId`, async (context) => {
208
+ const workspaceId = context.req.param("workspaceId");
209
+ const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:read");
210
+ try {
211
+ return context.json(
212
+ CompanyProfileRevision.parse(
213
+ await getCompanyProfileRevision(deps.db, {
214
+ accountId: grant.accountId,
215
+ workspaceId,
216
+ revisionId: revisionId(context),
217
+ }),
218
+ ),
219
+ );
220
+ } catch (error) {
221
+ return profileError(context, error);
222
+ }
223
+ });
224
+
225
+ app.post(`${base}/revisions/:revisionId/activate`, async (context) => {
226
+ const workspaceId = context.req.param("workspaceId");
227
+ const access = await requireAccessGrantAuthorization(
228
+ context,
229
+ deps,
230
+ workspaceId,
231
+ "workspace:read",
232
+ );
233
+ requireDirectAccountAdmin(access);
234
+ const request = await parseBody(context, ActivateCompanyProfileRevisionRequest);
235
+ try {
236
+ return context.json(
237
+ CompanyProfileMutationResponse.parse(
238
+ await activateCompanyProfileRevision(deps.db, {
239
+ operationId: request.operationId ?? randomUUID(),
240
+ accountId: access.grant.accountId,
241
+ workspaceId,
242
+ revisionId: revisionId(context),
243
+ expectedCurrentRevisionId: request.expectedCurrentRevisionId,
244
+ expectedActivationVersion: request.expectedActivationVersion,
245
+ actorSubjectId: access.grant.subjectId,
246
+ principalKind: "human_session",
247
+ reason: request.reason,
248
+ }),
249
+ ),
250
+ );
251
+ } catch (error) {
252
+ return profileError(context, error);
253
+ }
254
+ });
255
+ }