@opengeni/core 3.0.1 → 4.0.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.
Files changed (89) hide show
  1. package/README.md +1 -1
  2. package/dist/application/connect-operation.d.ts +3 -0
  3. package/dist/application/sandbox-recovery.d.ts +49 -0
  4. package/dist/{chunk-H7X52RI2.js → chunk-TFHSE7XR.js} +13 -2
  5. package/dist/chunk-TFHSE7XR.js.map +1 -0
  6. package/dist/dependencies.d.ts +1 -1
  7. package/dist/domain/capabilities.d.ts +2 -2
  8. package/dist/domain/connection-account-selection-error.d.ts +6 -0
  9. package/dist/domain/connector-tool-permissions.d.ts +27 -0
  10. package/dist/domain/editable-artifacts/agent-application.d.ts +8 -0
  11. package/dist/domain/environments.d.ts +3 -7
  12. package/dist/domain/insights-timing.d.ts +16 -0
  13. package/dist/domain/insights.d.ts +4 -1
  14. package/dist/domain/knowledge-files.d.ts +1 -1
  15. package/dist/domain/knowledge-preparation.d.ts +9 -0
  16. package/dist/domain/knowledge-preparation.test.d.ts +1 -0
  17. package/dist/domain/mcp-account-bindings.d.ts +19 -0
  18. package/dist/domain/native-mcp-connection-admission.d.ts +3 -0
  19. package/dist/domain/organization-integration-catalog.d.ts +15 -0
  20. package/dist/domain/personal-connection-delegations.d.ts +19 -10
  21. package/dist/domain/pr-review.d.ts +56 -4
  22. package/dist/domain/scheduled-tasks.d.ts +8 -5
  23. package/dist/domain/session-file-access.d.ts +4 -0
  24. package/dist/domain/sessions.d.ts +8 -6
  25. package/dist/domain/skills.d.ts +29 -1
  26. package/dist/editable-artifacts.js +1 -1
  27. package/dist/index.d.ts +7 -5
  28. package/dist/index.js +4868 -4803
  29. package/dist/index.js.map +1 -1
  30. package/dist/sandbox/routing.d.ts +2 -1
  31. package/dist/sandbox/runtime-settings.d.ts +1 -15
  32. package/package.json +11 -19
  33. package/src/application/composer-submit.ts +2 -1
  34. package/src/application/connect-operation.ts +32 -3
  35. package/src/application/sandbox-recovery.ts +55 -0
  36. package/src/application/user-resource-grants.ts +1 -16
  37. package/src/dependencies.ts +5 -1
  38. package/src/domain/capabilities.ts +169 -122
  39. package/src/domain/connection-account-selection-error.ts +9 -0
  40. package/src/domain/connector-tool-permissions.ts +305 -0
  41. package/src/domain/editable-artifacts/agent-application.ts +31 -2
  42. package/src/domain/environments.ts +4 -9
  43. package/src/domain/file-owner.ts +16 -1
  44. package/src/domain/insights-timing.ts +95 -0
  45. package/src/domain/insights.ts +59 -35
  46. package/src/domain/knowledge-files.ts +10 -3
  47. package/src/domain/knowledge-messages.ts +1 -0
  48. package/src/domain/knowledge-preparation.test.ts +251 -0
  49. package/src/domain/knowledge-preparation.ts +126 -0
  50. package/src/domain/mcp-account-bindings.ts +152 -0
  51. package/src/domain/native-mcp-connection-admission.ts +14 -0
  52. package/src/domain/organization-integration-catalog.ts +83 -0
  53. package/src/domain/personal-connection-delegations.ts +226 -177
  54. package/src/domain/pr-review.ts +22 -6
  55. package/src/domain/resources.ts +9 -2
  56. package/src/domain/scheduled-tasks.ts +200 -155
  57. package/src/domain/session-file-access.ts +47 -0
  58. package/src/domain/session-tool-policy.ts +12 -4
  59. package/src/domain/sessions.ts +390 -261
  60. package/src/domain/skills.ts +9 -0
  61. package/src/index.ts +10 -6
  62. package/src/rigs/index.ts +17 -17
  63. package/src/sandbox/routing.ts +18 -7
  64. package/src/sandbox/runtime-settings.ts +7 -91
  65. package/dist/application/host-mcp-owner.d.ts +0 -6
  66. package/dist/application/host-mcp-resolvers.d.ts +0 -13
  67. package/dist/chunk-5WZYFL45.js +0 -266
  68. package/dist/chunk-5WZYFL45.js.map +0 -1
  69. package/dist/chunk-H7X52RI2.js.map +0 -1
  70. package/dist/domain/connection-authority.d.ts +0 -97
  71. package/dist/domain/connection-authority.js +0 -169
  72. package/dist/domain/connection-authority.js.map +0 -1
  73. package/dist/domain/host-mcp-authority-source-admission.d.ts +0 -10
  74. package/dist/domain/host-mcp-task-admission.d.ts +0 -18
  75. package/dist/domain/packs.d.ts +0 -59
  76. package/dist/domain/product-integration-pack.d.ts +0 -44
  77. package/dist/domain/product-integration-skill.gen.d.ts +0 -5
  78. package/dist/remote-mcp-credentials.d.ts +0 -23
  79. package/dist/remote-mcp-credentials.js +0 -11
  80. package/dist/remote-mcp-credentials.js.map +0 -1
  81. package/src/application/host-mcp-owner.ts +0 -41
  82. package/src/application/host-mcp-resolvers.ts +0 -84
  83. package/src/domain/connection-authority.ts +0 -329
  84. package/src/domain/host-mcp-authority-source-admission.ts +0 -25
  85. package/src/domain/host-mcp-task-admission.ts +0 -121
  86. package/src/domain/packs.ts +0 -699
  87. package/src/domain/product-integration-pack.ts +0 -42
  88. package/src/domain/product-integration-skill.gen.ts +0 -52
  89. package/src/remote-mcp-credentials.ts +0 -361
@@ -1,361 +0,0 @@
1
- import type { Settings } from "@opengeni/config";
2
- import { environmentsEncryptionKeyBytes } from "@opengeni/config";
3
- import {
4
- resolveHostMcpResolverRoute,
5
- hostMcpResolverRouteIsCurrent,
6
- type Database,
7
- type HostMcpResolverRoute,
8
- } from "@opengeni/db";
9
- import {
10
- McpConnectionResourceScope,
11
- hostMcpCredentialUseGuard,
12
- type ConnectionCredentialsPort,
13
- type McpCredentialsRequest,
14
- type McpCredentialResolution,
15
- type McpGatewayCredentialsRequest,
16
- type McpGatewayCredentialResolution,
17
- } from "@opengeni/contracts";
18
- import { pinnedFetch, readResponseJsonBounded, validateHttpUrl } from "@opengeni/network";
19
- import { z } from "zod";
20
-
21
- const configuration = z
22
- .array(
23
- z
24
- .object({
25
- accountId: z.string().uuid(),
26
- url: z.string().max(2048),
27
- bearerToken: z
28
- .string()
29
- .min(1)
30
- .max(8192)
31
- .regex(/^[^\r\n]+$/),
32
- timeoutMs: z.number().int().min(100).max(30_000).default(10_000),
33
- })
34
- .strict(),
35
- )
36
- .max(128);
37
-
38
- const scope = {
39
- accountId: z.string(),
40
- workspaceId: z.string(),
41
- sessionId: z.string(),
42
- providerDomain: z.string(),
43
- provider: z.string().optional(),
44
- scopes: z.array(z.string()).max(256).optional(),
45
- resource: z.string().optional(),
46
- selectedResources: z.array(McpConnectionResourceScope).max(256).optional(),
47
- };
48
- const resolution = z.discriminatedUnion("status", [
49
- z
50
- .object({
51
- ...scope,
52
- status: z.literal("ok"),
53
- connectionId: z.string().min(1),
54
- headers: z.record(z.string(), z.string()),
55
- placements: z
56
- .array(
57
- z
58
- .object({
59
- carrier: z.enum(["header", "query", "cookie"]),
60
- name: z.string(),
61
- value: z.string(),
62
- prefix: z.string().optional(),
63
- })
64
- .strict(),
65
- )
66
- .max(64)
67
- .optional(),
68
- expiresAt: z.string().datetime({ offset: true }),
69
- })
70
- .strict(),
71
- z
72
- .object({
73
- ...scope,
74
- status: z.literal("auth_needed"),
75
- connectionId: z.string().optional(),
76
- reason: z.enum([
77
- "missing_connection",
78
- "expired",
79
- "insufficient_scope",
80
- "refresh_failed",
81
- "personal_authority_unavailable",
82
- "unsupported_auth",
83
- "resource_scope_unavailable",
84
- ]),
85
- authorizationUrl: z.string().optional(),
86
- })
87
- .strict(),
88
- ]);
89
- const gatewayResolution = z.discriminatedUnion("status", [
90
- resolution.options[0].omit({ sessionId: true }).extend({ requestId: z.string().uuid() }),
91
- resolution.options[1].omit({ sessionId: true }).extend({ requestId: z.string().uuid() }),
92
- ]);
93
- const responseEnvelope = z
94
- .object({
95
- version: z.literal(1),
96
- requestId: z.string().uuid(),
97
- destinationUrl: z.string(),
98
- resolution: z.union([resolution, gatewayResolution]),
99
- })
100
- .strict();
101
-
102
- type RemoteResolution = McpCredentialResolution | McpGatewayCredentialResolution;
103
- function normalizeResolution(
104
- value: z.infer<typeof resolution> | z.infer<typeof gatewayResolution>,
105
- ): RemoteResolution {
106
- const common = {
107
- accountId: value.accountId,
108
- workspaceId: value.workspaceId,
109
- ...("sessionId" in value ? { sessionId: value.sessionId } : { requestId: value.requestId }),
110
- providerDomain: value.providerDomain,
111
- ...(value.provider !== undefined ? { provider: value.provider } : {}),
112
- ...(value.scopes !== undefined ? { scopes: value.scopes } : {}),
113
- ...(value.resource !== undefined ? { resource: value.resource } : {}),
114
- ...(value.selectedResources !== undefined
115
- ? { selectedResources: value.selectedResources }
116
- : {}),
117
- };
118
- if (value.status === "auth_needed")
119
- return {
120
- ...common,
121
- status: "auth_needed",
122
- reason: value.reason,
123
- ...(value.connectionId !== undefined ? { connectionId: value.connectionId } : {}),
124
- ...(value.authorizationUrl !== undefined ? { authorizationUrl: value.authorizationUrl } : {}),
125
- };
126
- return {
127
- ...common,
128
- status: "ok",
129
- connectionId: value.connectionId,
130
- headers: value.headers,
131
- expiresAt: value.expiresAt,
132
- ...(value.placements !== undefined
133
- ? {
134
- placements: value.placements.map((placement) => ({
135
- carrier: placement.carrier,
136
- name: placement.name,
137
- value: placement.value,
138
- ...(placement.prefix !== undefined ? { prefix: placement.prefix } : {}),
139
- })),
140
- }
141
- : {}),
142
- };
143
- }
144
-
145
- /** Optional standalone transport for the existing request-time host port.
146
- * No successful credential is cached or persisted. The host must authorize
147
- * every immutable request context, including revocation and binding generation.
148
- */
149
- export function createRemoteMcpCredentialsPort(
150
- settings: Pick<
151
- Settings,
152
- "hostMcpCredentialResolversJson" | "environment" | "integrationsAllowPrivateNetworkTargets"
153
- >,
154
- transport: typeof pinnedFetch = pinnedFetch,
155
- routes?: {
156
- resolve: (input: { accountId: string; workspaceId: string }) => Promise<HostMcpResolverRoute>;
157
- isCurrent: (
158
- input: { accountId: string; workspaceId: string },
159
- route: HostMcpResolverRoute,
160
- ) => Promise<boolean>;
161
- },
162
- ): ConnectionCredentialsPort {
163
- if (!settings.hostMcpCredentialResolversJson && !routes) return {};
164
- let entries: z.infer<typeof configuration>;
165
- try {
166
- entries = configuration.parse(JSON.parse(settings.hostMcpCredentialResolversJson || "[]"));
167
- for (const entry of entries) validateHttpUrl(entry.url);
168
- if (new Set(entries.map((entry) => entry.accountId)).size !== entries.length) throw new Error();
169
- } catch {
170
- // Configuration includes credentials: never return parser input or causes.
171
- throw new Error("Invalid host MCP credential resolver configuration");
172
- }
173
- const byAccount = new Map(entries.map((entry) => [entry.accountId, entry]));
174
- const active = new Map<string, Promise<RemoteResolution>>();
175
- let physicalRequests = 0;
176
- const resolveRemote = async (
177
- input: McpCredentialsRequest | McpGatewayCredentialsRequest,
178
- ): Promise<RemoteResolution> => {
179
- const serialized = JSON.stringify(input);
180
- const request: McpCredentialsRequest | McpGatewayCredentialsRequest = JSON.parse(serialized);
181
- const unavailable = (reason: "unsupported_auth" | "refresh_failed"): RemoteResolution => ({
182
- status: "auth_needed",
183
- accountId: request.accountId,
184
- workspaceId: request.workspaceId,
185
- ...("sessionId" in request
186
- ? { sessionId: request.sessionId }
187
- : { requestId: request.requestId }),
188
- providerDomain: request.connectionRef.providerDomain,
189
- ...(request.connectionRef.provider !== undefined
190
- ? { provider: request.connectionRef.provider }
191
- : {}),
192
- ...(request.connectionRef.connectionId !== undefined
193
- ? { connectionId: request.connectionRef.connectionId }
194
- : {}),
195
- ...(request.connectionRef.scopes !== undefined
196
- ? { scopes: request.connectionRef.scopes }
197
- : {}),
198
- ...(request.connectionRef.resource !== undefined
199
- ? { resource: request.connectionRef.resource }
200
- : {}),
201
- ...(request.connectionRef.selectedResources !== undefined
202
- ? { selectedResources: request.connectionRef.selectedResources }
203
- : {}),
204
- reason,
205
- });
206
- let route: HostMcpResolverRoute = { mode: "legacy" };
207
- try {
208
- if (routes) route = await routes.resolve(request);
209
- } catch {
210
- return unavailable("refresh_failed");
211
- }
212
- if (route.mode === "denied") return unavailable("unsupported_auth");
213
- const config = route.mode === "namespace" ? route : byAccount.get(request.accountId);
214
- if (!config || request.connectionRef.authoritySource !== "host")
215
- return unavailable("unsupported_auth");
216
- const current = async () => {
217
- try {
218
- return routes ? await routes.isCurrent(request, route) : true;
219
- } catch {
220
- return false;
221
- }
222
- };
223
- const finish = async (value: RemoteResolution): Promise<RemoteResolution> => {
224
- if (!(await current())) return unavailable("refresh_failed");
225
- const result = structuredClone(value);
226
- if (result.status === "ok" && routes) result[hostMcpCredentialUseGuard] = current;
227
- return result;
228
- };
229
- // Snapshot before any asynchronous operation; never retain mutable caller
230
- // objects as the authority for a delayed response.
231
- if (new TextEncoder().encode(serialized).byteLength > 65_536)
232
- return unavailable("refresh_failed");
233
- const activeKey = JSON.stringify([
234
- route.mode === "namespace" ? [route.id, route.generation] : "legacy",
235
- serialized,
236
- ]);
237
- const pending = active.get(activeKey);
238
- if (pending) return finish(await pending);
239
- if (physicalRequests >= 128) return unavailable("refresh_failed");
240
- const run = async (): Promise<RemoteResolution> => {
241
- const requestId = crypto.randomUUID();
242
- const controller = new AbortController();
243
- let timer: ReturnType<typeof setTimeout> | undefined;
244
- const deadline = new Promise<never>((_, reject) => {
245
- timer = setTimeout(() => {
246
- controller.abort();
247
- reject(new Error("Host resolver deadline"));
248
- }, config.timeoutMs);
249
- });
250
- try {
251
- physicalRequests++;
252
- return await Promise.race([
253
- deadline,
254
- (async () => {
255
- if (!(await current())) return unavailable("refresh_failed");
256
- const response = await transport(
257
- config.url,
258
- {
259
- method: "POST",
260
- redirect: "manual",
261
- signal: controller.signal,
262
- headers: {
263
- Authorization: `Bearer ${config.bearerToken}`,
264
- "Content-Type": "application/json",
265
- },
266
- body: JSON.stringify({ version: 1, requestId, request }),
267
- },
268
- settings,
269
- { requireHttpsOutsideLocalTest: true, label: "Host MCP credential resolver" },
270
- );
271
- if (!response.ok) {
272
- await response.body?.cancel();
273
- return unavailable("refresh_failed");
274
- }
275
- const parsed = responseEnvelope.parse(
276
- await readResponseJsonBounded(response, 65_536, "Host MCP credential resolver", {
277
- signal: controller.signal,
278
- }),
279
- );
280
- if (
281
- parsed.requestId !== requestId ||
282
- parsed.destinationUrl !== request.destinationUrl ||
283
- parsed.resolution.accountId !== request.accountId ||
284
- parsed.resolution.workspaceId !== request.workspaceId ||
285
- ("sessionId" in request
286
- ? !("sessionId" in parsed.resolution) ||
287
- parsed.resolution.sessionId !== request.sessionId
288
- : !("requestId" in parsed.resolution) ||
289
- parsed.resolution.requestId !== request.requestId)
290
- )
291
- return unavailable("refresh_failed");
292
- if (
293
- parsed.resolution.status === "ok" &&
294
- (Date.parse(parsed.resolution.expiresAt) <= Date.now() + 5_000 ||
295
- Date.parse(parsed.resolution.expiresAt) > Date.now() + 900_000)
296
- ) {
297
- return unavailable("refresh_failed");
298
- }
299
- // Existing buildHostConnectionTokenResolver validates the precise
300
- // connection, provider, scopes, resources and credential placements.
301
- return normalizeResolution(parsed.resolution);
302
- })().finally(() => {
303
- physicalRequests--;
304
- }),
305
- ]);
306
- } catch {
307
- return unavailable("refresh_failed");
308
- } finally {
309
- clearTimeout(timer);
310
- }
311
- };
312
- const task = run();
313
- active.set(activeKey, task);
314
- try {
315
- return finish(await task);
316
- } finally {
317
- if (active.get(activeKey) === task) active.delete(activeKey);
318
- }
319
- };
320
- return {
321
- mcpAuthoritySource: "host",
322
- async mcpCredentials(input) {
323
- const result = await resolveRemote(input);
324
- if (!("sessionId" in result)) throw new Error("Invalid host turn credential scope");
325
- return result;
326
- },
327
- async mcpGatewayCredentials(input) {
328
- const result = await resolveRemote(input);
329
- if (!("requestId" in result)) throw new Error("Invalid host gateway credential scope");
330
- return result;
331
- },
332
- };
333
- }
334
-
335
- /** Native standalone transport; the database remains authoritative on every
336
- * resolution/use. Embedded in-process ports retain their existing precedence. */
337
- export function createNativeRemoteMcpCredentialsPort(
338
- settings: Settings,
339
- db: Database,
340
- transport: typeof pinnedFetch = pinnedFetch,
341
- ): ConnectionCredentialsPort {
342
- return createRemoteMcpCredentialsPort(settings, transport, {
343
- resolve: (request) =>
344
- resolveHostMcpResolverRoute(db, request, environmentsEncryptionKeyBytes(settings)),
345
- isCurrent: (request, route) => hostMcpResolverRouteIsCurrent(db, request, route),
346
- });
347
- }
348
-
349
- /** Parses only server configuration; never return parser errors containing secrets. */
350
- export function hasLegacyHostMcpResolver(
351
- settings: Pick<Settings, "hostMcpCredentialResolversJson">,
352
- accountId: string,
353
- ): boolean {
354
- try {
355
- return configuration
356
- .parse(JSON.parse(settings.hostMcpCredentialResolversJson || "[]"))
357
- .some((entry) => entry.accountId === accountId);
358
- } catch {
359
- throw new Error("Invalid host MCP credential resolver configuration");
360
- }
361
- }