@mastra/factory 0.24.0-alpha.12 → 0.24.0-alpha.14
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/factory.d.ts.map +1 -1
- package/dist/factory.js +33 -4
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +5 -2
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/routes/fs.d.ts +31 -23
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +214 -61
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/session-access.d.ts +55 -0
- package/dist/routes/session-access.d.ts.map +1 -0
- package/dist/routes/session-access.js +165 -0
- package/dist/routes/session-access.js.map +1 -0
- package/dist/routes/source-control-sessions.d.ts +5 -0
- package/dist/routes/source-control-sessions.d.ts.map +1 -1
- package/dist/routes/source-control-sessions.js +86 -9
- package/dist/routes/source-control-sessions.js.map +1 -1
- package/dist/routes/surface.d.ts +5 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +2 -2
- package/dist/routes/surface.js.map +1 -1
- package/dist/session/resource-migration.d.ts +18 -0
- package/dist/session/resource-migration.d.ts.map +1 -1
- package/dist/session/resource-migration.js +33 -1
- package/dist/session/resource-migration.js.map +1 -1
- package/dist/session/session-threads.d.ts +9 -0
- package/dist/session/session-threads.d.ts.map +1 -1
- package/dist/session/session-threads.js +24 -4
- package/dist/session/session-threads.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +15 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +29 -0
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +5 -1
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +7 -0
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/tools/session-tools.d.ts.map +1 -1
- package/dist/tools/session-tools.js +1 -1
- package/dist/tools/session-tools.js.map +1 -1
- package/dist/workspace.d.ts +5 -2
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +11 -1
- package/dist/workspace.js.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-access.js","names":[],"sources":["../../src/routes/session-access.ts"],"sourcesContent":["import { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { Context, MiddlewareHandler } from 'hono';\n\nimport type { SourceControlSessionLookup } from '../session/factory-session.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { SourceControlSession } from '../storage/domains/source-control/base.js';\nimport type { RouteAuth } from './route.js';\n\n/**\n * Whether the viewer may read a visible session's conversation. A session on its owner's memory is\n * the owner's alone, whatever its row says.\n */\nexport function canReadSessionResource(\n session: Pick<SourceControlSession, 'userId'>,\n resourceId: string,\n viewer: { userId: string },\n): boolean {\n return viewer.userId === session.userId || resourceId !== session.userId;\n}\n\n/** Whether a viewer may read or drive a session: same org, and the owner when it is private. */\nexport function canViewSourceControlSession(\n session: Pick<SourceControlSession, 'orgId' | 'userId' | 'visibility'>,\n viewer: { orgId?: string; userId: string },\n): boolean {\n if (session.orgId !== viewer.orgId) return false;\n return session.visibility !== 'private' || session.userId === viewer.userId;\n}\n\n/** The controller reads the guard needs to find which resource a session runs on. */\nexport interface SessionResourceLookup {\n getSession(sessionId: string): Promise<{ identity: { getResourceId(): string } } | undefined>;\n queryThreadById(input: { threadId: string }): Promise<{ resourceId: string } | null>;\n}\n\ntype Viewer = { orgId?: string; userId: string };\n\nconst SESSION_PATH = /\\/agent-controller\\/[^/]+\\/sessions\\/([^/]+)/;\nconst CREATE_SESSION_PATH = /\\/agent-controller\\/[^/]+\\/sessions\\/?$/;\nconst SET_RESOURCE_PATH = /\\/agent-controller\\/[^/]+\\/sessions\\/[^/]+\\/resource\\/?$/;\nconst OM_CONFIG_PATH = /^\\/web\\/config\\/om(\\/|$)/;\nconst MEMORY_PATH = /^\\/api\\/memory(\\/|$)/;\nconst ACTIVE_RUNS_PATH = /\\/agent-controller\\/[^/]+\\/active-runs\\/?$/;\n\nasync function bodyField(c: Context, field: string): Promise<string | undefined> {\n // Read a clone: the Mastra adapter clones `c.req.raw` again to parse params,\n // which throws once anything has consumed the original body.\n const body = await c.req.raw\n .clone()\n .json()\n .catch(() => undefined);\n const value = (body as Record<string, unknown> | undefined)?.[field];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction decodeSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\n/** The value of `field` from the query or the body; `null` when they differ, since handlers read one or the other. */\nasync function queryOrBody(c: Context, field: string): Promise<string | undefined | null> {\n const fromQuery = c.req.query(field) || undefined;\n const fromBody = c.req.method === 'GET' ? undefined : await bodyField(c, field);\n if (fromQuery && fromBody && fromQuery !== fromBody) return null;\n return fromQuery ?? fromBody;\n}\n\n/** The sessions and memory resources a request addresses. `null` when it names one ambiguously. */\nasync function addressed(c: Context): Promise<{ sessionIds: string[]; resourceIds: string[] } | null> {\n const path = c.req.path;\n const method = c.req.method;\n const sessionMatch = SESSION_PATH.exec(path);\n if (sessionMatch) {\n const sessionId = decodeSegment(sessionMatch[1]!);\n // Re-keying moves the session onto `newResourceId`, so that resource must be reachable too.\n const target = method === 'POST' && SET_RESOURCE_PATH.test(path) ? await bodyField(c, 'newResourceId') : undefined;\n return { sessionIds: [sessionId], resourceIds: target ? [target] : [] };\n }\n if (method === 'POST' && CREATE_SESSION_PATH.test(path)) {\n // Get-or-create: without a `sessionId` the session is addressed by its resourceId.\n const [sessionId, resourceId] = await Promise.all([bodyField(c, 'sessionId'), bodyField(c, 'resourceId')]);\n const id = sessionId ?? resourceId;\n return { sessionIds: id ? [id] : [], resourceIds: resourceId ? [resourceId] : [] };\n }\n if (OM_CONFIG_PATH.test(path)) {\n const sessionId = await queryOrBody(c, 'sessionId');\n if (sessionId === null) return null;\n return { sessionIds: sessionId ? [sessionId] : [], resourceIds: [] };\n }\n if (MEMORY_PATH.test(path)) {\n const resourceId = await queryOrBody(c, 'resourceId');\n if (resourceId === null) return null;\n return { sessionIds: [], resourceIds: resourceId ? [resourceId] : [] };\n }\n return { sessionIds: [], resourceIds: [] };\n}\n\n/**\n * Keeps private sessions private. A memory resource says who may read it: a\n * private session runs on its owner's user id, a shared one on its Factory's\n * id, and a session from before resources were shared on its own id. So a\n * caller reaches a resource only when it is their own user id, a Factory in\n * their organization, or a session id whose session they can view; any other\n * resource (another person's user id) answers 404.\n *\n * Session routes (stream, messages, threads, state, OM settings) resolve the\n * session from an in-memory map or its stored thread with no ownership check,\n * so both the session row and the resource it runs on are checked. Memory\n * routes trust a client-supplied resourceId or threadId, so they are bound to\n * the authorized resource, or the caller's own user id when none is named. The\n * controller-wide active-runs list drops runs on unreachable resources.\n * Denials answer 404 so ids do not leak existence. With auth disabled there is\n * no tenant to protect and everything passes through.\n */\nexport function createSessionAccessGuard({\n auth,\n sessions,\n projects,\n controller,\n}: {\n auth: RouteAuth;\n sessions: Pick<SourceControlSessionLookup, 'getBySessionId'>;\n projects: Pick<FactoryProjectsStorage, 'get'>;\n /** Resolved per request: the controller is built after the server config. */\n controller: () => SessionResourceLookup | undefined;\n}): MiddlewareHandler {\n const canReachResource = async (resourceId: string, viewer: Viewer): Promise<boolean> => {\n if (resourceId === viewer.userId) return true;\n const session = await sessions.getBySessionId(resourceId);\n if (session) return canViewSourceControlSession(session, viewer);\n if (!viewer.orgId) return false;\n return (await projects.get({ orgId: viewer.orgId, id: resourceId })) !== null;\n };\n\n const sessionResourceId = async (sessionId: string): Promise<string> => {\n const lookup = controller();\n if (!lookup) return sessionId;\n const live = await lookup.getSession(sessionId);\n if (live) return live.identity.getResourceId();\n return (await lookup.queryThreadById({ threadId: sessionId }))?.resourceId ?? sessionId;\n };\n\n const canReachSession = async (sessionId: string, viewer: Viewer): Promise<boolean> => {\n const session = await sessions.getBySessionId(sessionId);\n if (session && !canViewSourceControlSession(session, viewer)) return false;\n const resourceId = await sessionResourceId(sessionId);\n // A session on its own id was just checked by its row; one without a row is nobody's private session.\n if (resourceId === sessionId) return true;\n return canReachResource(resourceId, viewer);\n };\n\n return async (c, next) => {\n if (!auth.enabled()) return next();\n const ctx = c as unknown as Context;\n const target = await addressed(ctx);\n if (!target) return c.json({ error: 'The query and body must name the same session' }, 400);\n const isMemory = MEMORY_PATH.test(ctx.req.path);\n const isActiveRuns = ctx.req.method === 'GET' && ACTIVE_RUNS_PATH.test(ctx.req.path);\n if (!target.sessionIds.length && !target.resourceIds.length && !isMemory && !isActiveRuns) return next();\n\n await auth.ensureUser(ctx);\n const viewer = auth.tenant(ctx);\n if (!viewer) return c.json({ error: 'Session not found' }, 404);\n for (const sessionId of target.sessionIds) {\n if (!(await canReachSession(sessionId, viewer))) return c.json({ error: 'Session not found' }, 404);\n }\n for (const resourceId of target.resourceIds) {\n if (!(await canReachResource(resourceId, viewer))) return c.json({ error: 'Session not found' }, 404);\n }\n\n if (isMemory) {\n // Memory routes only check that a thread belongs to the request's resource\n // when one is bound server-side. Bind the resource just authorized, or the\n // caller's own user id, so a threadId cannot reach another resource's thread.\n const requestContext = ctx.get('requestContext') as RequestContext | undefined;\n requestContext?.set(MASTRA_RESOURCE_ID_KEY, target.resourceIds[0] ?? viewer.userId);\n }\n if (!isActiveRuns) return next();\n await next();\n await filterActiveRuns(ctx, resourceId => canReachResource(resourceId, viewer));\n };\n}\n\n/** Drops runs on resources the caller cannot reach from the controller-wide active-runs list. */\nasync function filterActiveRuns(c: Context, canReach: (resourceId: string) => Promise<boolean>): Promise<void> {\n if (!c.res.ok) return;\n const body = (await c.res\n .clone()\n .json()\n .catch(() => undefined)) as { runs?: Array<{ resourceId?: unknown }> } | undefined;\n if (!body || !Array.isArray(body.runs)) return;\n const resourceIds = [\n ...new Set(body.runs.flatMap(run => (typeof run.resourceId === 'string' ? [run.resourceId] : []))),\n ];\n const reachable = new Map(await Promise.all(resourceIds.map(async id => [id, await canReach(id)] as const)));\n const runs = body.runs.filter(run => typeof run.resourceId !== 'string' || reachable.get(run.resourceId));\n if (runs.length === body.runs.length) return;\n const headers = new Headers(c.res.headers);\n headers.delete('content-length');\n c.res.headers.delete('content-length');\n c.res = new Response(JSON.stringify({ ...body, runs }), { status: c.res.status, headers });\n}\n"],"mappings":"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"}
|
|
@@ -24,6 +24,11 @@ export interface SourceControlSessionRoutesOptions {
|
|
|
24
24
|
/** How long recreate waits for an aborted run to settle before destroying. */
|
|
25
25
|
abortSettleTimeoutMs?: number;
|
|
26
26
|
workItems?: Pick<WorkItemsStorage, 'clearSessionReferences' | 'hasRunBindingForSession'>;
|
|
27
|
+
/** Moves a thread, with everything keyed by its resource, when a session's visibility changes. */
|
|
28
|
+
moveThread?: (input: {
|
|
29
|
+
threadId: string;
|
|
30
|
+
resourceId: string;
|
|
31
|
+
}) => Promise<unknown>;
|
|
27
32
|
}
|
|
28
33
|
export declare function buildSourceControlSessionRoutes(options: SourceControlSessionRoutesOptions): ApiRoute[];
|
|
29
34
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-control-sessions.d.ts","sourceRoot":"","sources":["../../src/routes/source-control-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOnE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"source-control-sessions.d.ts","sourceRoot":"","sources":["../../src/routes/source-control-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOnE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAUrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAGV,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAS5C,eAAO,MAAM,0BAA0B,kBAAkB,CAAC;AAc1D,KAAK,wBAAwB,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC;AAE1G,MAAM,WAAW,iCAAiC;IAChD,IAAI,EAAE,SAAS,CAAC;IAChB,cAAc,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACtD,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,wBAAwB,CAAC;IACjC,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IACnD,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,mFAAmF;IACnF,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,sGAAsG;IACtG,UAAU,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;IAC5D,8EAA8E;IAC9E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,wBAAwB,GAAG,yBAAyB,CAAC,CAAC;IACzF,kGAAkG;IAClG,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;AA8XD,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,iCAAiC,GAAG,QAAQ,EAAE,CA8TtG"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isValidGitRef } from "../sandbox/git-ref.js";
|
|
2
|
+
import { canReadSessionResource, canViewSourceControlSession } from "./session-access.js";
|
|
2
3
|
import { waitForPendingFilesystemCapture } from "../session/filesystem-capture.js";
|
|
3
|
-
import { listFactorySessionThreads, sessionMemoryResourceId } from "../session/session-threads.js";
|
|
4
|
+
import { listFactorySessionThreads, sessionMemoryResourceId, sessionThreadsToMove, userSessionResourceFor } from "../session/session-threads.js";
|
|
4
5
|
import { normalizeSessionTitle } from "../session/session-title.js";
|
|
5
6
|
import { reclaimDeletedSessionSandbox } from "../integrations/github/sandbox-release.js";
|
|
6
7
|
import { seedSessionOrg } from "../session/org-seed.js";
|
|
@@ -13,6 +14,7 @@ function loose(c) {
|
|
|
13
14
|
return c;
|
|
14
15
|
}
|
|
15
16
|
const USER_SESSION_BRANCH_PREFIX = "user/session-";
|
|
17
|
+
const SLACK_SESSION_BRANCH_PREFIX = "slack/";
|
|
16
18
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
17
19
|
const MAX_SESSION_OWNER_PROFILES = 100;
|
|
18
20
|
const MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES = 500;
|
|
@@ -111,14 +113,14 @@ async function resolveSession(sourceControls, sessionId) {
|
|
|
111
113
|
return matches[0] ?? null;
|
|
112
114
|
}
|
|
113
115
|
/**
|
|
114
|
-
* Start the live conversation for a user session on its own thread (thread id === session id), under
|
|
115
|
-
*
|
|
116
|
+
* Start the live conversation for a user session on its own thread (thread id === session id), under the resource
|
|
117
|
+
* its visibility gives it. Agent-controller
|
|
116
118
|
* routes only act on started sessions, so the first prompt the page sends right after creation always lands on the
|
|
117
119
|
* thread the page reads, with the org and Factory address already in state. Get-or-create, so retried or repeated
|
|
118
120
|
* creates are safe.
|
|
119
121
|
*/
|
|
120
|
-
async function startUserSessionConversation(controller, session) {
|
|
121
|
-
if (!controller) return;
|
|
122
|
+
async function startUserSessionConversation(controller, session, resourceId = userSessionResourceFor(session, session.visibility === "org" ? "org" : "private")) {
|
|
123
|
+
if (!controller) return void 0;
|
|
122
124
|
const requestContext = new RequestContext();
|
|
123
125
|
requestContext.set("user", {
|
|
124
126
|
workosId: session.userId,
|
|
@@ -126,7 +128,7 @@ async function startUserSessionConversation(controller, session) {
|
|
|
126
128
|
});
|
|
127
129
|
const live = await controller.createSession({
|
|
128
130
|
id: session.sessionId,
|
|
129
|
-
resourceId
|
|
131
|
+
resourceId,
|
|
130
132
|
threadId: session.sessionId,
|
|
131
133
|
ownerId: session.userId,
|
|
132
134
|
requestContext
|
|
@@ -136,6 +138,7 @@ async function startUserSessionConversation(controller, session) {
|
|
|
136
138
|
factoryProjectId: session.factoryProjectId,
|
|
137
139
|
...session.projectRepositoryId ? { projectRepositoryId: session.projectRepositoryId } : {}
|
|
138
140
|
});
|
|
141
|
+
return live;
|
|
139
142
|
}
|
|
140
143
|
function isJsonObject(value) {
|
|
141
144
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -256,6 +259,8 @@ function projectSessionRoutes(path, options, resolveOwnerProfiles) {
|
|
|
256
259
|
const sessionId = requestedSessionId ?? globalThis.crypto.randomUUID();
|
|
257
260
|
if (body.title !== void 0 && typeof body.title !== "string") return c.json({ error: "Invalid title" }, 400);
|
|
258
261
|
const normalizedTitle = body.title === void 0 ? null : normalizeSessionTitle(body.title);
|
|
262
|
+
if (body.visibility !== void 0 && body.visibility !== "private" && body.visibility !== "org") return c.json({ error: "visibility must be 'private' or 'org'" }, 400);
|
|
263
|
+
const visibility = body.visibility ?? "org";
|
|
259
264
|
let branch;
|
|
260
265
|
if (body.branch === void 0) branch = `${USER_SESSION_BRANCH_PREFIX}${sessionId}`;
|
|
261
266
|
else if (isValidGitRef(body.branch)) branch = body.branch;
|
|
@@ -277,7 +282,7 @@ function projectSessionRoutes(path, options, resolveOwnerProfiles) {
|
|
|
277
282
|
branch,
|
|
278
283
|
baseBranch,
|
|
279
284
|
title: normalizedTitle,
|
|
280
|
-
visibility
|
|
285
|
+
visibility
|
|
281
286
|
}).catch(async (error) => {
|
|
282
287
|
if (!(error instanceof UniqueViolationError) || !requestedSessionId) throw error;
|
|
283
288
|
const conflict = await project.sourceControl.sessions.getBySessionId(sessionId);
|
|
@@ -325,16 +330,44 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
325
330
|
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
326
331
|
if ("response" in resolved) return resolved.response;
|
|
327
332
|
const session = (await resolveSession(options.sourceControls, c.req.param("sessionId")))?.session;
|
|
328
|
-
if (!session || session
|
|
333
|
+
if (!session || !canViewSourceControlSession(session, resolved.tenant)) return c.json({ error: "Session not found" }, 404);
|
|
334
|
+
const resourceId = await sessionMemoryResourceId(options.controller, session, options.workItems);
|
|
335
|
+
if (!canReadSessionResource(session, resourceId, resolved.tenant)) return c.json({ error: "Session not found" }, 404);
|
|
329
336
|
const owners = await resolveOwnerProfiles([session.userId]);
|
|
330
337
|
const recreateSandbox = canRecreateSandbox(options) && await sessionManagePermission(loose(c), options.auth, resolved.tenant, session) === "allowed";
|
|
331
|
-
const resourceId = await sessionMemoryResourceId(options.controller, session, options.workItems);
|
|
332
338
|
return c.json({ session: {
|
|
333
339
|
...withCapabilities(withOwnerProfile(session, owners), recreateSandbox),
|
|
334
340
|
resourceId
|
|
335
341
|
} });
|
|
336
342
|
}
|
|
337
343
|
}),
|
|
344
|
+
registerApiRoute("/web/user-sessions/:sessionId/sandbox/start", {
|
|
345
|
+
method: "POST",
|
|
346
|
+
requiresAuth: false,
|
|
347
|
+
handler: async (c) => {
|
|
348
|
+
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
349
|
+
if ("response" in resolved) return resolved.response;
|
|
350
|
+
const session = (await resolveSession(options.sourceControls, c.req.param("sessionId")))?.session;
|
|
351
|
+
if (!session) return c.json({ error: "Session not found" }, 404);
|
|
352
|
+
const permission = await sessionManagePermission(loose(c), options.auth, resolved.tenant, session);
|
|
353
|
+
if (permission === "not-found") return c.json({ error: "Session not found" }, 404);
|
|
354
|
+
if (permission === "forbidden") return c.json({ error: "Only the session's owner or an organization admin can start its sandbox." }, 403);
|
|
355
|
+
const controller = options.controller;
|
|
356
|
+
if (!controller) return c.json({ error: "Sessions are not available on this server." }, 503);
|
|
357
|
+
try {
|
|
358
|
+
const sandbox = (await controller.getSession(session.sessionId) ?? await startUserSessionConversation(controller, session, await sessionMemoryResourceId(controller, session, options.workItems)))?.getWorkspace()?.sandbox;
|
|
359
|
+
if (!sandbox?.start) return c.json({ error: "This session has no sandbox to start." }, 409);
|
|
360
|
+
await sandbox.start();
|
|
361
|
+
return c.json({ started: true });
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error("[Factory Sessions] Failed to start session sandbox", {
|
|
364
|
+
sessionId: session.sessionId,
|
|
365
|
+
error
|
|
366
|
+
});
|
|
367
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}),
|
|
338
371
|
registerApiRoute("/web/user-sessions/:sessionId/sandbox/recreate", {
|
|
339
372
|
method: "POST",
|
|
340
373
|
requiresAuth: false,
|
|
@@ -428,6 +461,50 @@ function buildSourceControlSessionRoutes(options) {
|
|
|
428
461
|
return c.json({ removed: true });
|
|
429
462
|
}
|
|
430
463
|
}),
|
|
464
|
+
registerApiRoute("/web/user-sessions/:sessionId/visibility", {
|
|
465
|
+
method: "PUT",
|
|
466
|
+
requiresAuth: false,
|
|
467
|
+
handler: async (c) => {
|
|
468
|
+
const resolved = await resolveOrgTenant(loose(c), options.auth);
|
|
469
|
+
if ("response" in resolved) return resolved.response;
|
|
470
|
+
const visibility = (await c.req.json().catch(() => void 0))?.visibility;
|
|
471
|
+
if (visibility !== "private" && visibility !== "org") return c.json({ error: "visibility must be 'private' or 'org'" }, 400);
|
|
472
|
+
const sessionId = c.req.param("sessionId");
|
|
473
|
+
const match = await resolveSession(options.sourceControls, sessionId);
|
|
474
|
+
const row = match?.session;
|
|
475
|
+
if (!match || !row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
|
|
476
|
+
if (!options.workItems) return c.json({ error: "Session visibility can't be changed yet: Factory storage is still starting up. Try again in a moment." }, 503);
|
|
477
|
+
if (row.branch.startsWith(SLACK_SESSION_BRANCH_PREFIX) || row.factoryProjectId !== null && await options.workItems.hasRunBindingForSession({
|
|
478
|
+
orgId: row.orgId,
|
|
479
|
+
factoryProjectId: row.factoryProjectId,
|
|
480
|
+
sessionId
|
|
481
|
+
})) return c.json({ error: "Only user sessions can change visibility" }, 409);
|
|
482
|
+
if (visibility === "org" && !row.factoryProjectId) return c.json({ error: "This session isn't linked to a Factory, so it can't be shared." }, 409);
|
|
483
|
+
const resourceId = userSessionResourceFor(row, visibility);
|
|
484
|
+
const controller = options.controller;
|
|
485
|
+
const threadIds = controller ? await sessionThreadsToMove(controller, row, resourceId) : [];
|
|
486
|
+
if (threadIds.length > 0 && !options.moveThread) return c.json({ error: "Changing session visibility is not available on this server." }, 503);
|
|
487
|
+
if (controller?.listActiveThreadRuns().some((run) => threadIds.includes(run.threadId))) return c.json({ error: "Wait for the session to finish its run before changing visibility" }, 409);
|
|
488
|
+
const moveThreads = async () => {
|
|
489
|
+
for (const threadId of threadIds) await options.moveThread({
|
|
490
|
+
threadId,
|
|
491
|
+
resourceId
|
|
492
|
+
});
|
|
493
|
+
};
|
|
494
|
+
if (visibility === "private") await moveThreads();
|
|
495
|
+
const updated = await match.sourceControl.sessions.setVisibility({
|
|
496
|
+
sessionId,
|
|
497
|
+
visibility
|
|
498
|
+
});
|
|
499
|
+
if (!updated) return c.json({ error: "Session not found" }, 404);
|
|
500
|
+
if (visibility === "org") await moveThreads();
|
|
501
|
+
const live = await controller?.getSession(sessionId);
|
|
502
|
+
if (live && threadIds.length > 0) await controller.deleteSession({ sessionId });
|
|
503
|
+
else if (live) await controller.setResourceId(live, { resourceId });
|
|
504
|
+
const owners = await resolveOwnerProfiles([updated.userId]);
|
|
505
|
+
return c.json({ session: withOwnerProfile(updated, owners) });
|
|
506
|
+
}
|
|
507
|
+
}),
|
|
431
508
|
registerApiRoute("/web/user-sessions/:sessionId/title", {
|
|
432
509
|
method: "POST",
|
|
433
510
|
requiresAuth: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-control-sessions.js","names":[],"sources":["../../src/routes/source-control-sessions.ts"],"sourcesContent":["import type { MountedMastraCode } from '@mastra/code-sdk';\nimport { resolveModel } from '@mastra/code-sdk/agents/model';\nimport { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute, IUserProvider } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport { UniqueViolationError } from '@mastra/core/storage';\nimport type { Context } from 'hono';\n\nimport { reclaimDeletedSessionSandbox } from '../integrations/github/sandbox-release.js';\nimport { isValidGitRef } from '../sandbox/git-ref.js';\nimport type { SessionRetirementCoordinator } from '../sandbox/session-retirement.js';\nimport { waitForPendingFilesystemCapture } from '../session/filesystem-capture.js';\nimport { seedSessionOrg } from '../session/org-seed.js';\nimport { sessionMemoryResourceId, listFactorySessionThreads } from '../session/session-threads.js';\nimport { normalizeSessionTitle } from '../session/session-title.js';\nimport type { FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type {\n ProjectRepository,\n SourceControlSession,\n SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { RouteAuth } from './route.js';\n\ntype RouteContext = Context;\n\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\nexport const USER_SESSION_BRANCH_PREFIX = 'user/session-';\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\nconst MAX_SESSION_OWNER_PROFILES = 100;\nconst MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES = 500;\nconst SESSION_OWNER_PROFILE_TTL_MS = 5 * 60_000;\n\ninterface SessionOwnerProfile {\n id: string;\n name: string;\n avatarUrl?: string;\n}\n\ntype SessionOwnerUserProvider = Pick<IUserProvider, 'getUser'> & Partial<Pick<IUserProvider, 'getUsers'>>;\n\nexport interface SourceControlSessionRoutesOptions {\n auth: RouteAuth;\n sourceControls: readonly SourceControlStorageHandle[];\n projects: Pick<FactoryProjectsStorage, 'get'>;\n users?: SessionOwnerUserProvider;\n controller?: MountedMastraCode['controller'];\n memorySettings: Pick<MemorySettingsStorage, 'get'>;\n sessionRetirement?: SessionRetirementCoordinator;\n /** Whether the host sandbox can recreate a session's sandbox (false for local). */\n sandboxRecreateSupported?: boolean;\n /** Turn-end file listings, cleared on recreate so the panel stops showing the old sandbox's files. */\n filesystem?: Pick<FilesystemStorage, 'deleteResourceFiles'>;\n /** How long recreate waits for an aborted run to settle before destroying. */\n abortSettleTimeoutMs?: number;\n workItems?: Pick<WorkItemsStorage, 'clearSessionReferences' | 'hasRunBindingForSession'>;\n}\n\nconst ABORT_SETTLE_TIMEOUT_MS = 5_000;\nconst ABORT_SETTLE_POLL_MS = 50;\n\ntype SessionManagePermission = 'allowed' | 'forbidden' | 'not-found';\n\n/**\n * Who may manage a session's sandbox: its owner, or an org admin. Private\n * sessions stay owner-only and look missing to everyone else, matching the\n * session GET. The admin check is a provider call, so owners skip it.\n */\nasync function sessionManagePermission(\n c: RouteContext,\n auth: RouteAuth,\n tenant: { orgId: string; userId: string },\n session: SourceControlSession,\n): Promise<SessionManagePermission> {\n if (session.orgId !== tenant.orgId) return 'not-found';\n const isOwner = session.userId === tenant.userId;\n if (session.visibility === 'private' && !isOwner) return 'not-found';\n if (isOwner) return 'allowed';\n return (await auth.isOrganizationAdmin(c, session.orgId)) ? 'allowed' : 'forbidden';\n}\n\nfunction canRecreateSandbox(options: SourceControlSessionRoutesOptions): boolean {\n return Boolean(options.sessionRetirement) && options.sandboxRecreateSupported === true;\n}\n\nfunction withCapabilities<T extends object>(session: T, recreateSandbox: boolean) {\n return { ...session, capabilities: { recreateSandbox } };\n}\n\n/** Abort the session's active run and wait (bounded) for it to stop. Returns whether a run was aborted. */\nasync function abortActiveRun(\n controller: MountedMastraCode['controller'] | undefined,\n sessionId: string,\n settleTimeoutMs: number,\n): Promise<boolean> {\n if (!controller) return false;\n try {\n const live = await controller.getSession(sessionId);\n if (!live?.stream.isActive()) return false;\n live.abort();\n const deadline = Date.now() + settleTimeoutMs;\n while (live.stream.isActive() && Date.now() < deadline) {\n await new Promise(resolve => setTimeout(resolve, ABORT_SETTLE_POLL_MS));\n }\n if (live.stream.isActive()) {\n console.warn('[Factory Sessions] Aborted run did not settle before sandbox recreate', { sessionId });\n }\n return true;\n } catch (error) {\n console.warn('[Factory Sessions] Failed to abort the active run before sandbox recreate', { sessionId, error });\n return false;\n }\n}\n\ninterface ResolvedProjectRepository {\n sourceControl: SourceControlStorageHandle;\n project: ProjectRepository;\n factoryProjectId: string;\n defaultBranch: string;\n}\n\nasync function resolveOrgTenant(\n c: RouteContext,\n auth: RouteAuth,\n): Promise<{ tenant: { orgId: string; userId: string } } | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized', reason: 'auth_required' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'Source-control sessions require an organization.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\nasync function resolveProjectRepository(\n sourceControls: readonly SourceControlStorageHandle[],\n orgId: string,\n projectRepositoryId: string,\n): Promise<ResolvedProjectRepository | null> {\n const matches = (\n await Promise.all(\n sourceControls.map(async sourceControl => {\n const project = await sourceControl.projectRepositories.get({ orgId, id: projectRepositoryId });\n if (!project) return null;\n const repository = await sourceControl.repositories.get({ orgId, id: project.repositoryId });\n if (!repository) return null;\n const connection = await sourceControl.connections.get({ orgId, id: project.connectionId });\n if (!connection) return null;\n return {\n sourceControl,\n project,\n factoryProjectId: connection.factoryProjectId,\n defaultBranch: project.branch ?? repository.defaultBranch,\n };\n }),\n )\n ).filter((match): match is ResolvedProjectRepository => match !== null);\n if (matches.length > 1) {\n throw new Error('Factory project repository exists in multiple source-control providers.');\n }\n return matches[0] ?? null;\n}\n\nasync function resolveSession(\n sourceControls: readonly SourceControlStorageHandle[],\n sessionId: string,\n): Promise<{ sourceControl: SourceControlStorageHandle; session: SourceControlSession } | null> {\n const matches = (\n await Promise.all(\n sourceControls.map(async sourceControl => ({\n sourceControl,\n session: await sourceControl.sessions.getBySessionId(sessionId),\n })),\n )\n ).filter(\n (match): match is { sourceControl: SourceControlStorageHandle; session: SourceControlSession } =>\n match.session !== null,\n );\n if (matches.length > 1) throw new Error('Factory session exists in multiple source-control providers.');\n return matches[0] ?? null;\n}\n\n/**\n * Start the live conversation for a user session on its own thread (thread id === session id), under its owner's\n * resource. Agent-controller\n * routes only act on started sessions, so the first prompt the page sends right after creation always lands on the\n * thread the page reads, with the org and Factory address already in state. Get-or-create, so retried or repeated\n * creates are safe.\n */\nasync function startUserSessionConversation(\n controller: SourceControlSessionRoutesOptions['controller'],\n session: SourceControlSession,\n): Promise<void> {\n if (!controller) return;\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: session.userId, organizationId: session.orgId });\n const live = await controller.createSession({\n id: session.sessionId,\n resourceId: session.userId,\n threadId: session.sessionId,\n ownerId: session.userId,\n requestContext,\n });\n await seedSessionOrg(live, session.orgId);\n // Server-side gates (the transition tool, factory-phase processor) resolve the session address from state, so\n // seed it here rather than waiting for the page to connect.\n if (session.factoryProjectId) {\n await live.state.set({\n factoryProjectId: session.factoryProjectId,\n ...(session.projectRepositoryId ? { projectRepositoryId: session.projectRepositoryId } : {}),\n });\n }\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction createSessionNaming() {\n const inFlight = new Map<string, Promise<string | null>>();\n return (sessionId: string, run: () => Promise<string | null>) => {\n const pending = inFlight.get(sessionId);\n if (pending) return pending;\n const started = run().finally(() => inFlight.delete(sessionId));\n inFlight.set(sessionId, started);\n return started;\n };\n}\n\nfunction titleModel(modelId: string) {\n return ({ requestContext }: { requestContext: RequestContext }) =>\n resolveModel(modelId, { remapForCodexOAuth: true, requestContext });\n}\n\nfunction createSessionOwnerProfileResolver(users: SessionOwnerUserProvider | undefined) {\n const cache = new Map<string, { profile?: SessionOwnerProfile; expiresAt: number }>();\n const cacheProfile = (userId: string, profile: SessionOwnerProfile | undefined, expiresAt: number) => {\n cache.delete(userId);\n cache.set(userId, { profile, expiresAt });\n if (cache.size > MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES) {\n const oldestUserId = cache.keys().next().value;\n if (oldestUserId !== undefined) cache.delete(oldestUserId);\n }\n };\n\n return async (userIds: string[]): Promise<Map<string, SessionOwnerProfile>> => {\n if (!users) return new Map();\n const requestedUserIds = [...new Set(userIds)].slice(0, MAX_SESSION_OWNER_PROFILES);\n const profiles = new Map<string, SessionOwnerProfile>();\n const unresolvedUserIds: string[] = [];\n const now = Date.now();\n\n for (const userId of requestedUserIds) {\n const cached = cache.get(userId);\n if (!cached || cached.expiresAt <= now) {\n cache.delete(userId);\n unresolvedUserIds.push(userId);\n } else if (cached.profile) {\n profiles.set(userId, cached.profile);\n }\n }\n if (unresolvedUserIds.length === 0) return profiles;\n\n let resolvedUsers: Array<Awaited<ReturnType<SessionOwnerUserProvider['getUser']>>>;\n if (users.getUsers) {\n try {\n resolvedUsers = await users.getUsers(unresolvedUserIds);\n } catch (error) {\n console.warn('[Factory Sessions] Bulk owner profile lookup failed; falling back to individual lookups', {\n error: error instanceof Error ? error.message : String(error),\n });\n resolvedUsers = (await Promise.allSettled(unresolvedUserIds.map(userId => users.getUser(userId))))\n .filter(result => result.status === 'fulfilled')\n .map(result => result.value);\n }\n } else {\n resolvedUsers = (await Promise.allSettled(unresolvedUserIds.map(userId => users.getUser(userId))))\n .filter(result => result.status === 'fulfilled')\n .map(result => result.value);\n }\n\n for (const user of resolvedUsers) {\n if (!user) continue;\n const name = user.name?.trim() || user.email?.trim();\n if (!name) continue;\n profiles.set(user.id, {\n id: user.id,\n name,\n ...(user.avatarUrl ? { avatarUrl: user.avatarUrl } : {}),\n });\n }\n const expiresAt = now + SESSION_OWNER_PROFILE_TTL_MS;\n for (const userId of unresolvedUserIds) cacheProfile(userId, profiles.get(userId), expiresAt);\n return profiles;\n };\n}\n\nfunction withOwnerProfile(session: SourceControlSession, owners: Map<string, SessionOwnerProfile>) {\n const owner = owners.get(session.userId);\n return owner ? { ...session, owner } : session;\n}\n\nfunction projectSessionRoutes(\n path: '/web/source-control/projects/:id/sessions' | '/web/github/projects/:id/sessions',\n options: SourceControlSessionRoutesOptions,\n resolveOwnerProfiles: ReturnType<typeof createSessionOwnerProfileResolver>,\n): ApiRoute[] {\n return [\n registerApiRoute(path, {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository(options.sourceControls, orgId, projectRepositoryId)\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n const sessions = await project.sourceControl.sessions.list({\n projectRepositoryId: project.project.id,\n viewerUserId: userId,\n });\n const owners = await resolveOwnerProfiles(sessions.map(session => session.userId));\n return c.json({ sessions: sessions.map(session => withOwnerProfile(session, owners)) });\n },\n }),\n registerApiRoute(path, {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository(options.sourceControls, orgId, projectRepositoryId)\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isJsonObject(body)) return c.json({ error: 'Invalid JSON body' }, 400);\n if (body.baseBranch !== undefined && typeof body.baseBranch !== 'string') {\n return c.json({ error: 'Invalid baseBranch' }, 400);\n }\n const baseBranch = body.baseBranch ?? project.defaultBranch;\n if (!isValidGitRef(baseBranch)) return c.json({ error: 'Invalid baseBranch' }, 400);\n if (\n body.sessionId !== undefined &&\n (typeof body.sessionId !== 'string' || !UUID_PATTERN.test(body.sessionId))\n ) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const requestedSessionId = body.sessionId;\n const sessionId = requestedSessionId ?? globalThis.crypto.randomUUID();\n if (body.title !== undefined && typeof body.title !== 'string') {\n return c.json({ error: 'Invalid title' }, 400);\n }\n const normalizedTitle = body.title === undefined ? null : normalizeSessionTitle(body.title);\n let branch: string;\n if (body.branch === undefined) branch = `${USER_SESSION_BRANCH_PREFIX}${sessionId}`;\n else if (isValidGitRef(body.branch)) branch = body.branch;\n else return c.json({ error: 'Invalid branch' }, 400);\n\n if (requestedSessionId) {\n const existing = await project.sourceControl.sessions.getBySessionId(sessionId);\n if (existing) {\n if (\n existing.projectRepositoryId !== project.project.id ||\n existing.orgId !== orgId ||\n existing.userId !== userId ||\n existing.branch !== branch\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n await startUserSessionConversation(options.controller, existing);\n return c.json({ session: withCapabilities(existing, canRecreateSandbox(options)) });\n }\n }\n\n const session = await project.sourceControl.sessions\n .create({\n sessionId,\n projectRepositoryId: project.project.id,\n factoryProjectId: project.factoryProjectId,\n orgId,\n userId,\n branch,\n baseBranch,\n title: normalizedTitle,\n visibility: 'org',\n })\n .catch(async error => {\n if (!(error instanceof UniqueViolationError) || !requestedSessionId) throw error;\n const conflict = await project.sourceControl.sessions.getBySessionId(sessionId);\n if (!conflict) throw error;\n return conflict;\n });\n if (\n requestedSessionId &&\n (session.sessionId !== sessionId ||\n session.projectRepositoryId !== project.project.id ||\n session.orgId !== orgId ||\n session.userId !== userId ||\n session.branch !== branch)\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n await startUserSessionConversation(options.controller, session);\n // The creator owns the session, so no admin check is needed.\n return c.json({ session: withCapabilities(session, canRecreateSandbox(options)) });\n },\n }),\n ];\n}\n\nexport function buildSourceControlSessionRoutes(options: SourceControlSessionRoutesOptions): ApiRoute[] {\n const nameSession = createSessionNaming();\n const resolveOwnerProfiles = createSessionOwnerProfileResolver(options.users);\n return [\n registerApiRoute('/web/factory/projects/:id/sessions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const factoryProjectId = c.req.param('id');\n const project = factoryProjectId ? await options.projects.get({ orgId, id: factoryProjectId }) : null;\n if (!project) return c.json({ error: 'Factory not found' }, 404);\n // Storage is partitioned per provider; a Factory's sessions can live in any of them.\n const sessions = (\n await Promise.all(\n options.sourceControls.map(sourceControl =>\n sourceControl.sessions.listByProject({ orgId, factoryProjectId: project.id, viewerUserId: userId }),\n ),\n )\n ).flat();\n const owners = await resolveOwnerProfiles(sessions.map(session => session.userId));\n return c.json({ sessions: sessions.map(session => withOwnerProfile(session, owners)) });\n },\n }),\n ...projectSessionRoutes('/web/source-control/projects/:id/sessions', options, resolveOwnerProfiles),\n // Compatibility for existing clients; new code uses the provider-neutral path.\n ...projectSessionRoutes('/web/github/projects/:id/sessions', options, resolveOwnerProfiles),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (\n !session ||\n session.orgId !== resolved.tenant.orgId ||\n (session.visibility === 'private' && session.userId !== resolved.tenant.userId)\n ) {\n return c.json({ error: 'Session not found' }, 404);\n }\n const owners = await resolveOwnerProfiles([session.userId]);\n const recreateSandbox =\n canRecreateSandbox(options) &&\n (await sessionManagePermission(loose(c), options.auth, resolved.tenant, session)) === 'allowed';\n // The client opens the session by its id and creates it under this resource.\n const resourceId = await sessionMemoryResourceId(options.controller, session, options.workItems);\n return c.json({\n session: { ...withCapabilities(withOwnerProfile(session, owners), recreateSandbox), resourceId },\n });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId/sandbox/recreate', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (!match || !session) return c.json({ error: 'Session not found' }, 404);\n const permission = await sessionManagePermission(loose(c), options.auth, resolved.tenant, session);\n if (permission === 'not-found') return c.json({ error: 'Session not found' }, 404);\n if (permission === 'forbidden') {\n return c.json({ error: \"Only the session's owner or an organization admin can recreate its sandbox.\" }, 403);\n }\n const sessionRetirement = options.sessionRetirement;\n if (!sessionRetirement || !canRecreateSandbox(options)) {\n return c.json({ error: 'Recreating sandboxes is not available on this server.' }, 503);\n }\n\n const aborted = await abortActiveRun(\n options.controller,\n session.sessionId,\n options.abortSettleTimeoutMs ?? ABORT_SETTLE_TIMEOUT_MS,\n );\n await waitForPendingFilesystemCapture(session.sessionId).catch(error => {\n console.warn('[Factory Sessions] Failed to drain filesystem capture before sandbox recreate', {\n sessionId: session.sessionId,\n error,\n });\n });\n try {\n const outcome = await sessionRetirement.recreateSessionSandbox({\n sourceControl: match.sourceControl,\n orgId: session.orgId,\n sessionId: session.sessionId,\n });\n if (outcome === 'not-found') return c.json({ error: 'Session not found' }, 404);\n // The captured listings describe the destroyed sandbox; the next turn re-captures.\n await options.filesystem?.deleteResourceFiles({ resourceId: session.sessionId }).catch(error => {\n console.warn('[Factory Sessions] Failed to clear file listings after sandbox recreate', {\n sessionId: session.sessionId,\n error,\n });\n });\n return c.json({ recreated: true, aborted });\n } catch (error) {\n console.error('[Factory Sessions] Failed to recreate session sandbox', {\n sessionId: session.sessionId,\n error,\n });\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (\n !match ||\n !session ||\n session.orgId !== resolved.tenant.orgId ||\n session.userId !== resolved.tenant.userId\n ) {\n return c.json({ error: 'Session not found' }, 404);\n }\n try {\n // Drain the turn's queued filesystem capture while the thread and sandbox still exist.\n // A failed drain only costs the snapshot; it must not block teardown.\n await waitForPendingFilesystemCapture(session.sessionId).catch(error => {\n console.warn('[Factory Sessions] Failed to drain filesystem capture before delete', {\n sessionId: session.sessionId,\n error,\n });\n });\n await options.controller?.deleteSession({ sessionId: session.sessionId });\n } catch (error) {\n console.error('[Factory Sessions] Failed to tear down live controller session', {\n sessionId: session.sessionId,\n error,\n });\n }\n if (options.sessionRetirement) {\n await options.sessionRetirement.retireSession({\n sourceControl: match.sourceControl,\n ...(options.workItems ? { workItems: options.workItems } : {}),\n orgId: session.orgId,\n sessionId: session.sessionId,\n deleteSession: true,\n });\n } else {\n await options.workItems?.clearSessionReferences({ orgId: session.orgId, sessionId: session.sessionId });\n await match.sourceControl.sessions.delete(session.id);\n void reclaimDeletedSessionSandbox({ session }).catch((error: unknown) => {\n console.error('[Factory Sessions] Failed to reclaim sandbox for deleted session', {\n sessionId: session.sessionId,\n sandboxId: session.sandboxId,\n error,\n });\n });\n }\n return c.json({ removed: true });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId/title', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const sessionId = c.req.param('sessionId');\n const match = await resolveSession(options.sourceControls, sessionId);\n const row = match?.session;\n if (!match || !row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) {\n return c.json({ error: 'Session not found' }, 404);\n }\n if (!options.controller) return c.json({ error: 'Sessions are not available on this server.' }, 503);\n const threads = await listFactorySessionThreads(options.controller, row, options.workItems);\n const thread = threads.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];\n if (!thread) return c.json({ error: 'This session has no conversation to name yet.' }, 409);\n const stored = await options.memorySettings.get({ orgId: row.orgId, userId: row.userId });\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: row.userId, organizationId: row.orgId });\n try {\n const title = await nameSession(sessionId, async () => {\n const generated = await options.controller!.generateThreadTitle({\n threadId: thread.id,\n sessionId,\n requestContext,\n ...(stored?.observerModelId ? { model: titleModel(stored.observerModelId) } : {}),\n });\n const named = generated ? normalizeSessionTitle(generated) : null;\n if (named) await match.sourceControl.sessions.rename({ sessionId, title: named });\n return named;\n });\n if (!title) return c.json({ error: 'The model returned an empty title. Try again.' }, 502);\n return c.json({ title });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n ];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"source-control-sessions.js","names":[],"sources":["../../src/routes/source-control-sessions.ts"],"sourcesContent":["import type { MountedMastraCode } from '@mastra/code-sdk';\nimport { resolveModel } from '@mastra/code-sdk/agents/model';\nimport { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute, IUserProvider } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport { UniqueViolationError } from '@mastra/core/storage';\nimport type { Context } from 'hono';\n\nimport { reclaimDeletedSessionSandbox } from '../integrations/github/sandbox-release.js';\nimport { isValidGitRef } from '../sandbox/git-ref.js';\nimport type { SessionRetirementCoordinator } from '../sandbox/session-retirement.js';\nimport { waitForPendingFilesystemCapture } from '../session/filesystem-capture.js';\nimport { seedSessionOrg } from '../session/org-seed.js';\nimport {\n sessionMemoryResourceId,\n listFactorySessionThreads,\n sessionThreadsToMove,\n userSessionResourceFor,\n} from '../session/session-threads.js';\nimport { normalizeSessionTitle } from '../session/session-title.js';\nimport type { FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type {\n ProjectRepository,\n SourceControlSession,\n SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { RouteAuth } from './route.js';\nimport { canReadSessionResource, canViewSourceControlSession } from './session-access.js';\n\ntype RouteContext = Context;\n\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\nexport const USER_SESSION_BRANCH_PREFIX = 'user/session-';\n// Slack thread sessions live on `slack/<thread>` branches (integrations/slack/slack.ts threadBranch).\nconst SLACK_SESSION_BRANCH_PREFIX = 'slack/';\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\nconst MAX_SESSION_OWNER_PROFILES = 100;\nconst MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES = 500;\nconst SESSION_OWNER_PROFILE_TTL_MS = 5 * 60_000;\n\ninterface SessionOwnerProfile {\n id: string;\n name: string;\n avatarUrl?: string;\n}\n\ntype SessionOwnerUserProvider = Pick<IUserProvider, 'getUser'> & Partial<Pick<IUserProvider, 'getUsers'>>;\n\nexport interface SourceControlSessionRoutesOptions {\n auth: RouteAuth;\n sourceControls: readonly SourceControlStorageHandle[];\n projects: Pick<FactoryProjectsStorage, 'get'>;\n users?: SessionOwnerUserProvider;\n controller?: MountedMastraCode['controller'];\n memorySettings: Pick<MemorySettingsStorage, 'get'>;\n sessionRetirement?: SessionRetirementCoordinator;\n /** Whether the host sandbox can recreate a session's sandbox (false for local). */\n sandboxRecreateSupported?: boolean;\n /** Turn-end file listings, cleared on recreate so the panel stops showing the old sandbox's files. */\n filesystem?: Pick<FilesystemStorage, 'deleteResourceFiles'>;\n /** How long recreate waits for an aborted run to settle before destroying. */\n abortSettleTimeoutMs?: number;\n workItems?: Pick<WorkItemsStorage, 'clearSessionReferences' | 'hasRunBindingForSession'>;\n /** Moves a thread, with everything keyed by its resource, when a session's visibility changes. */\n moveThread?: (input: { threadId: string; resourceId: string }) => Promise<unknown>;\n}\n\nconst ABORT_SETTLE_TIMEOUT_MS = 5_000;\nconst ABORT_SETTLE_POLL_MS = 50;\n\ntype SessionManagePermission = 'allowed' | 'forbidden' | 'not-found';\n\n/**\n * Who may manage a session's sandbox: its owner, or an org admin. Private\n * sessions stay owner-only and look missing to everyone else, matching the\n * session GET. The admin check is a provider call, so owners skip it.\n */\nasync function sessionManagePermission(\n c: RouteContext,\n auth: RouteAuth,\n tenant: { orgId: string; userId: string },\n session: SourceControlSession,\n): Promise<SessionManagePermission> {\n if (session.orgId !== tenant.orgId) return 'not-found';\n const isOwner = session.userId === tenant.userId;\n if (session.visibility === 'private' && !isOwner) return 'not-found';\n if (isOwner) return 'allowed';\n return (await auth.isOrganizationAdmin(c, session.orgId)) ? 'allowed' : 'forbidden';\n}\n\nfunction canRecreateSandbox(options: SourceControlSessionRoutesOptions): boolean {\n return Boolean(options.sessionRetirement) && options.sandboxRecreateSupported === true;\n}\n\nfunction withCapabilities<T extends object>(session: T, recreateSandbox: boolean) {\n return { ...session, capabilities: { recreateSandbox } };\n}\n\n/** Abort the session's active run and wait (bounded) for it to stop. Returns whether a run was aborted. */\nasync function abortActiveRun(\n controller: MountedMastraCode['controller'] | undefined,\n sessionId: string,\n settleTimeoutMs: number,\n): Promise<boolean> {\n if (!controller) return false;\n try {\n const live = await controller.getSession(sessionId);\n if (!live?.stream.isActive()) return false;\n live.abort();\n const deadline = Date.now() + settleTimeoutMs;\n while (live.stream.isActive() && Date.now() < deadline) {\n await new Promise(resolve => setTimeout(resolve, ABORT_SETTLE_POLL_MS));\n }\n if (live.stream.isActive()) {\n console.warn('[Factory Sessions] Aborted run did not settle before sandbox recreate', { sessionId });\n }\n return true;\n } catch (error) {\n console.warn('[Factory Sessions] Failed to abort the active run before sandbox recreate', { sessionId, error });\n return false;\n }\n}\n\ninterface ResolvedProjectRepository {\n sourceControl: SourceControlStorageHandle;\n project: ProjectRepository;\n factoryProjectId: string;\n defaultBranch: string;\n}\n\nasync function resolveOrgTenant(\n c: RouteContext,\n auth: RouteAuth,\n): Promise<{ tenant: { orgId: string; userId: string } } | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized', reason: 'auth_required' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'Source-control sessions require an organization.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\nasync function resolveProjectRepository(\n sourceControls: readonly SourceControlStorageHandle[],\n orgId: string,\n projectRepositoryId: string,\n): Promise<ResolvedProjectRepository | null> {\n const matches = (\n await Promise.all(\n sourceControls.map(async sourceControl => {\n const project = await sourceControl.projectRepositories.get({ orgId, id: projectRepositoryId });\n if (!project) return null;\n const repository = await sourceControl.repositories.get({ orgId, id: project.repositoryId });\n if (!repository) return null;\n const connection = await sourceControl.connections.get({ orgId, id: project.connectionId });\n if (!connection) return null;\n return {\n sourceControl,\n project,\n factoryProjectId: connection.factoryProjectId,\n defaultBranch: project.branch ?? repository.defaultBranch,\n };\n }),\n )\n ).filter((match): match is ResolvedProjectRepository => match !== null);\n if (matches.length > 1) {\n throw new Error('Factory project repository exists in multiple source-control providers.');\n }\n return matches[0] ?? null;\n}\n\nasync function resolveSession(\n sourceControls: readonly SourceControlStorageHandle[],\n sessionId: string,\n): Promise<{ sourceControl: SourceControlStorageHandle; session: SourceControlSession } | null> {\n const matches = (\n await Promise.all(\n sourceControls.map(async sourceControl => ({\n sourceControl,\n session: await sourceControl.sessions.getBySessionId(sessionId),\n })),\n )\n ).filter(\n (match): match is { sourceControl: SourceControlStorageHandle; session: SourceControlSession } =>\n match.session !== null,\n );\n if (matches.length > 1) throw new Error('Factory session exists in multiple source-control providers.');\n return matches[0] ?? null;\n}\n\n/**\n * Start the live conversation for a user session on its own thread (thread id === session id), under the resource\n * its visibility gives it. Agent-controller\n * routes only act on started sessions, so the first prompt the page sends right after creation always lands on the\n * thread the page reads, with the org and Factory address already in state. Get-or-create, so retried or repeated\n * creates are safe.\n */\nasync function startUserSessionConversation(\n controller: SourceControlSessionRoutesOptions['controller'],\n session: SourceControlSession,\n // Its owner's resource while private, its Factory's when created shared (a run from a board card).\n resourceId: string = userSessionResourceFor(session, session.visibility === 'org' ? 'org' : 'private'),\n) {\n if (!controller) return undefined;\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: session.userId, organizationId: session.orgId });\n const live = await controller.createSession({\n id: session.sessionId,\n resourceId,\n threadId: session.sessionId,\n ownerId: session.userId,\n requestContext,\n });\n await seedSessionOrg(live, session.orgId);\n // Server-side gates (the transition tool, factory-phase processor) resolve the session address from state, so\n // seed it here rather than waiting for the page to connect.\n if (session.factoryProjectId) {\n await live.state.set({\n factoryProjectId: session.factoryProjectId,\n ...(session.projectRepositoryId ? { projectRepositoryId: session.projectRepositoryId } : {}),\n });\n }\n return live;\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction createSessionNaming() {\n const inFlight = new Map<string, Promise<string | null>>();\n return (sessionId: string, run: () => Promise<string | null>) => {\n const pending = inFlight.get(sessionId);\n if (pending) return pending;\n const started = run().finally(() => inFlight.delete(sessionId));\n inFlight.set(sessionId, started);\n return started;\n };\n}\n\nfunction titleModel(modelId: string) {\n return ({ requestContext }: { requestContext: RequestContext }) =>\n resolveModel(modelId, { remapForCodexOAuth: true, requestContext });\n}\n\nfunction createSessionOwnerProfileResolver(users: SessionOwnerUserProvider | undefined) {\n const cache = new Map<string, { profile?: SessionOwnerProfile; expiresAt: number }>();\n const cacheProfile = (userId: string, profile: SessionOwnerProfile | undefined, expiresAt: number) => {\n cache.delete(userId);\n cache.set(userId, { profile, expiresAt });\n if (cache.size > MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES) {\n const oldestUserId = cache.keys().next().value;\n if (oldestUserId !== undefined) cache.delete(oldestUserId);\n }\n };\n\n return async (userIds: string[]): Promise<Map<string, SessionOwnerProfile>> => {\n if (!users) return new Map();\n const requestedUserIds = [...new Set(userIds)].slice(0, MAX_SESSION_OWNER_PROFILES);\n const profiles = new Map<string, SessionOwnerProfile>();\n const unresolvedUserIds: string[] = [];\n const now = Date.now();\n\n for (const userId of requestedUserIds) {\n const cached = cache.get(userId);\n if (!cached || cached.expiresAt <= now) {\n cache.delete(userId);\n unresolvedUserIds.push(userId);\n } else if (cached.profile) {\n profiles.set(userId, cached.profile);\n }\n }\n if (unresolvedUserIds.length === 0) return profiles;\n\n let resolvedUsers: Array<Awaited<ReturnType<SessionOwnerUserProvider['getUser']>>>;\n if (users.getUsers) {\n try {\n resolvedUsers = await users.getUsers(unresolvedUserIds);\n } catch (error) {\n console.warn('[Factory Sessions] Bulk owner profile lookup failed; falling back to individual lookups', {\n error: error instanceof Error ? error.message : String(error),\n });\n resolvedUsers = (await Promise.allSettled(unresolvedUserIds.map(userId => users.getUser(userId))))\n .filter(result => result.status === 'fulfilled')\n .map(result => result.value);\n }\n } else {\n resolvedUsers = (await Promise.allSettled(unresolvedUserIds.map(userId => users.getUser(userId))))\n .filter(result => result.status === 'fulfilled')\n .map(result => result.value);\n }\n\n for (const user of resolvedUsers) {\n if (!user) continue;\n const name = user.name?.trim() || user.email?.trim();\n if (!name) continue;\n profiles.set(user.id, {\n id: user.id,\n name,\n ...(user.avatarUrl ? { avatarUrl: user.avatarUrl } : {}),\n });\n }\n const expiresAt = now + SESSION_OWNER_PROFILE_TTL_MS;\n for (const userId of unresolvedUserIds) cacheProfile(userId, profiles.get(userId), expiresAt);\n return profiles;\n };\n}\n\nfunction withOwnerProfile(session: SourceControlSession, owners: Map<string, SessionOwnerProfile>) {\n const owner = owners.get(session.userId);\n return owner ? { ...session, owner } : session;\n}\n\nfunction projectSessionRoutes(\n path: '/web/source-control/projects/:id/sessions' | '/web/github/projects/:id/sessions',\n options: SourceControlSessionRoutesOptions,\n resolveOwnerProfiles: ReturnType<typeof createSessionOwnerProfileResolver>,\n): ApiRoute[] {\n return [\n registerApiRoute(path, {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository(options.sourceControls, orgId, projectRepositoryId)\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n const sessions = await project.sourceControl.sessions.list({\n projectRepositoryId: project.project.id,\n viewerUserId: userId,\n });\n const owners = await resolveOwnerProfiles(sessions.map(session => session.userId));\n return c.json({ sessions: sessions.map(session => withOwnerProfile(session, owners)) });\n },\n }),\n registerApiRoute(path, {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository(options.sourceControls, orgId, projectRepositoryId)\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isJsonObject(body)) return c.json({ error: 'Invalid JSON body' }, 400);\n if (body.baseBranch !== undefined && typeof body.baseBranch !== 'string') {\n return c.json({ error: 'Invalid baseBranch' }, 400);\n }\n const baseBranch = body.baseBranch ?? project.defaultBranch;\n if (!isValidGitRef(baseBranch)) return c.json({ error: 'Invalid baseBranch' }, 400);\n if (\n body.sessionId !== undefined &&\n (typeof body.sessionId !== 'string' || !UUID_PATTERN.test(body.sessionId))\n ) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const requestedSessionId = body.sessionId;\n const sessionId = requestedSessionId ?? globalThis.crypto.randomUUID();\n if (body.title !== undefined && typeof body.title !== 'string') {\n return c.json({ error: 'Invalid title' }, 400);\n }\n const normalizedTitle = body.title === undefined ? null : normalizeSessionTitle(body.title);\n // Sessions start shared on the Factory. Only a session someone opens for themselves (New session) asks for\n // `private`.\n if (body.visibility !== undefined && body.visibility !== 'private' && body.visibility !== 'org') {\n return c.json({ error: \"visibility must be 'private' or 'org'\" }, 400);\n }\n const visibility = body.visibility ?? 'org';\n let branch: string;\n if (body.branch === undefined) branch = `${USER_SESSION_BRANCH_PREFIX}${sessionId}`;\n else if (isValidGitRef(body.branch)) branch = body.branch;\n else return c.json({ error: 'Invalid branch' }, 400);\n\n if (requestedSessionId) {\n const existing = await project.sourceControl.sessions.getBySessionId(sessionId);\n if (existing) {\n if (\n existing.projectRepositoryId !== project.project.id ||\n existing.orgId !== orgId ||\n existing.userId !== userId ||\n existing.branch !== branch\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n await startUserSessionConversation(options.controller, existing);\n return c.json({ session: withCapabilities(existing, canRecreateSandbox(options)) });\n }\n }\n\n const session = await project.sourceControl.sessions\n .create({\n sessionId,\n projectRepositoryId: project.project.id,\n factoryProjectId: project.factoryProjectId,\n orgId,\n userId,\n branch,\n baseBranch,\n title: normalizedTitle,\n visibility,\n })\n .catch(async error => {\n if (!(error instanceof UniqueViolationError) || !requestedSessionId) throw error;\n const conflict = await project.sourceControl.sessions.getBySessionId(sessionId);\n if (!conflict) throw error;\n return conflict;\n });\n if (\n requestedSessionId &&\n (session.sessionId !== sessionId ||\n session.projectRepositoryId !== project.project.id ||\n session.orgId !== orgId ||\n session.userId !== userId ||\n session.branch !== branch)\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n await startUserSessionConversation(options.controller, session);\n // The creator owns the session, so no admin check is needed.\n return c.json({ session: withCapabilities(session, canRecreateSandbox(options)) });\n },\n }),\n ];\n}\n\nexport function buildSourceControlSessionRoutes(options: SourceControlSessionRoutesOptions): ApiRoute[] {\n const nameSession = createSessionNaming();\n const resolveOwnerProfiles = createSessionOwnerProfileResolver(options.users);\n return [\n registerApiRoute('/web/factory/projects/:id/sessions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const factoryProjectId = c.req.param('id');\n const project = factoryProjectId ? await options.projects.get({ orgId, id: factoryProjectId }) : null;\n if (!project) return c.json({ error: 'Factory not found' }, 404);\n // Storage is partitioned per provider; a Factory's sessions can live in any of them.\n const sessions = (\n await Promise.all(\n options.sourceControls.map(sourceControl =>\n sourceControl.sessions.listByProject({ orgId, factoryProjectId: project.id, viewerUserId: userId }),\n ),\n )\n ).flat();\n const owners = await resolveOwnerProfiles(sessions.map(session => session.userId));\n return c.json({ sessions: sessions.map(session => withOwnerProfile(session, owners)) });\n },\n }),\n ...projectSessionRoutes('/web/source-control/projects/:id/sessions', options, resolveOwnerProfiles),\n // Compatibility for existing clients; new code uses the provider-neutral path.\n ...projectSessionRoutes('/web/github/projects/:id/sessions', options, resolveOwnerProfiles),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (!session || !canViewSourceControlSession(session, resolved.tenant)) {\n return c.json({ error: 'Session not found' }, 404);\n }\n // The client opens the session by its id and creates it under this resource.\n const resourceId = await sessionMemoryResourceId(options.controller, session, options.workItems);\n if (!canReadSessionResource(session, resourceId, resolved.tenant)) {\n return c.json({ error: 'Session not found' }, 404);\n }\n const owners = await resolveOwnerProfiles([session.userId]);\n const recreateSandbox =\n canRecreateSandbox(options) &&\n (await sessionManagePermission(loose(c), options.auth, resolved.tenant, session)) === 'allowed';\n return c.json({\n session: { ...withCapabilities(withOwnerProfile(session, owners), recreateSandbox), resourceId },\n });\n },\n }),\n // Start a session's sandbox without sending it a message, for the Files tab.\n // Brings the controller session online as the row's owner, as a delivered\n // message would, then starts its sandbox; a running sandbox returns at once.\n registerApiRoute('/web/user-sessions/:sessionId/sandbox/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (!session) return c.json({ error: 'Session not found' }, 404);\n const permission = await sessionManagePermission(loose(c), options.auth, resolved.tenant, session);\n if (permission === 'not-found') return c.json({ error: 'Session not found' }, 404);\n if (permission === 'forbidden') {\n return c.json({ error: \"Only the session's owner or an organization admin can start its sandbox.\" }, 403);\n }\n const controller = options.controller;\n if (!controller) return c.json({ error: 'Sessions are not available on this server.' }, 503);\n\n try {\n const live =\n (await controller.getSession(session.sessionId)) ??\n (await startUserSessionConversation(\n controller,\n session,\n await sessionMemoryResourceId(controller, session, options.workItems),\n ));\n const sandbox = live?.getWorkspace()?.sandbox;\n if (!sandbox?.start) return c.json({ error: 'This session has no sandbox to start.' }, 409);\n await sandbox.start();\n return c.json({ started: true });\n } catch (error) {\n console.error('[Factory Sessions] Failed to start session sandbox', { sessionId: session.sessionId, error });\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId/sandbox/recreate', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (!match || !session) return c.json({ error: 'Session not found' }, 404);\n const permission = await sessionManagePermission(loose(c), options.auth, resolved.tenant, session);\n if (permission === 'not-found') return c.json({ error: 'Session not found' }, 404);\n if (permission === 'forbidden') {\n return c.json({ error: \"Only the session's owner or an organization admin can recreate its sandbox.\" }, 403);\n }\n const sessionRetirement = options.sessionRetirement;\n if (!sessionRetirement || !canRecreateSandbox(options)) {\n return c.json({ error: 'Recreating sandboxes is not available on this server.' }, 503);\n }\n\n const aborted = await abortActiveRun(\n options.controller,\n session.sessionId,\n options.abortSettleTimeoutMs ?? ABORT_SETTLE_TIMEOUT_MS,\n );\n await waitForPendingFilesystemCapture(session.sessionId).catch(error => {\n console.warn('[Factory Sessions] Failed to drain filesystem capture before sandbox recreate', {\n sessionId: session.sessionId,\n error,\n });\n });\n try {\n const outcome = await sessionRetirement.recreateSessionSandbox({\n sourceControl: match.sourceControl,\n orgId: session.orgId,\n sessionId: session.sessionId,\n });\n if (outcome === 'not-found') return c.json({ error: 'Session not found' }, 404);\n // The captured listings describe the destroyed sandbox; the next turn re-captures.\n await options.filesystem?.deleteResourceFiles({ resourceId: session.sessionId }).catch(error => {\n console.warn('[Factory Sessions] Failed to clear file listings after sandbox recreate', {\n sessionId: session.sessionId,\n error,\n });\n });\n return c.json({ recreated: true, aborted });\n } catch (error) {\n console.error('[Factory Sessions] Failed to recreate session sandbox', {\n sessionId: session.sessionId,\n error,\n });\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const match = await resolveSession(options.sourceControls, c.req.param('sessionId'));\n const session = match?.session;\n if (\n !match ||\n !session ||\n session.orgId !== resolved.tenant.orgId ||\n session.userId !== resolved.tenant.userId\n ) {\n return c.json({ error: 'Session not found' }, 404);\n }\n try {\n // Drain the turn's queued filesystem capture while the thread and sandbox still exist.\n // A failed drain only costs the snapshot; it must not block teardown.\n await waitForPendingFilesystemCapture(session.sessionId).catch(error => {\n console.warn('[Factory Sessions] Failed to drain filesystem capture before delete', {\n sessionId: session.sessionId,\n error,\n });\n });\n await options.controller?.deleteSession({ sessionId: session.sessionId });\n } catch (error) {\n console.error('[Factory Sessions] Failed to tear down live controller session', {\n sessionId: session.sessionId,\n error,\n });\n }\n if (options.sessionRetirement) {\n await options.sessionRetirement.retireSession({\n sourceControl: match.sourceControl,\n ...(options.workItems ? { workItems: options.workItems } : {}),\n orgId: session.orgId,\n sessionId: session.sessionId,\n deleteSession: true,\n });\n } else {\n await options.workItems?.clearSessionReferences({ orgId: session.orgId, sessionId: session.sessionId });\n await match.sourceControl.sessions.delete(session.id);\n void reclaimDeletedSessionSandbox({ session }).catch((error: unknown) => {\n console.error('[Factory Sessions] Failed to reclaim sandbox for deleted session', {\n sessionId: session.sessionId,\n sandboxId: session.sandboxId,\n error,\n });\n });\n }\n return c.json({ removed: true });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId/visibility', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const body = (await c.req.json().catch(() => undefined)) as { visibility?: unknown } | undefined;\n const visibility = body?.visibility;\n if (visibility !== 'private' && visibility !== 'org') {\n return c.json({ error: \"visibility must be 'private' or 'org'\" }, 400);\n }\n const sessionId = c.req.param('sessionId');\n const match = await resolveSession(options.sourceControls, sessionId);\n const row = match?.session;\n // Only the owner may share or unshare; everyone else gets the same 404\n // as a missing session so org-visible ids are not confirmed either.\n if (!match || !row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) {\n return c.json({ error: 'Session not found' }, 404);\n }\n // Without work-item storage there's no telling whether this is a Factory\n // run, so refuse rather than let a run be made private.\n if (!options.workItems) {\n return c.json(\n {\n error:\n \"Session visibility can't be changed yet: Factory storage is still starting up. Try again in a moment.\",\n },\n 503,\n );\n }\n // Only sessions a person started in the UI can change. Factory runs and\n // Slack threads keep the visibility they were created with: runs and\n // channel threads stay with the team, Slack DMs stay private.\n if (\n row.branch.startsWith(SLACK_SESSION_BRANCH_PREFIX) ||\n (row.factoryProjectId !== null &&\n (await options.workItems.hasRunBindingForSession({\n orgId: row.orgId,\n factoryProjectId: row.factoryProjectId,\n sessionId,\n })))\n ) {\n return c.json({ error: 'Only user sessions can change visibility' }, 409);\n }\n // Sharing puts the session on its Factory's memory; without a Factory there is nowhere to share it to.\n if (visibility === 'org' && !row.factoryProjectId) {\n return c.json({ error: \"This session isn't linked to a Factory, so it can't be shared.\" }, 409);\n }\n const resourceId = userSessionResourceFor(row, visibility);\n const controller = options.controller;\n // The resource says who may read a session, so its threads move with it.\n const threadIds = controller ? await sessionThreadsToMove(controller, row, resourceId) : [];\n if (threadIds.length > 0 && !options.moveThread) {\n return c.json({ error: 'Changing session visibility is not available on this server.' }, 503);\n }\n if (controller?.listActiveThreadRuns().some(run => threadIds.includes(run.threadId))) {\n return c.json({ error: 'Wait for the session to finish its run before changing visibility' }, 409);\n }\n // Write in the order that fails closed: threads leave the Factory before the\n // row says private, and the row says shared before threads reach the Factory.\n // A failed move then leaves the session less visible, never more, and a retry\n // moves what is left.\n const moveThreads = async () => {\n for (const threadId of threadIds) await options.moveThread!({ threadId, resourceId });\n };\n if (visibility === 'private') await moveThreads();\n const updated = await match.sourceControl.sessions.setVisibility({ sessionId, visibility });\n if (!updated) return c.json({ error: 'Session not found' }, 404);\n if (visibility === 'org') await moveThreads();\n // A live session keeps the resource it started on. Drop it so the next\n // request resumes on its moved thread, or point it at the new resource\n // when it has no thread to resume from yet.\n const live = await controller?.getSession(sessionId);\n if (live && threadIds.length > 0) await controller!.deleteSession({ sessionId });\n else if (live) await controller!.setResourceId(live, { resourceId });\n const owners = await resolveOwnerProfiles([updated.userId]);\n return c.json({ session: withOwnerProfile(updated, owners) });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId/title', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), options.auth);\n if ('response' in resolved) return resolved.response;\n const sessionId = c.req.param('sessionId');\n const match = await resolveSession(options.sourceControls, sessionId);\n const row = match?.session;\n if (!match || !row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) {\n return c.json({ error: 'Session not found' }, 404);\n }\n if (!options.controller) return c.json({ error: 'Sessions are not available on this server.' }, 503);\n const threads = await listFactorySessionThreads(options.controller, row, options.workItems);\n const thread = threads.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];\n if (!thread) return c.json({ error: 'This session has no conversation to name yet.' }, 409);\n const stored = await options.memorySettings.get({ orgId: row.orgId, userId: row.userId });\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: row.userId, organizationId: row.orgId });\n try {\n const title = await nameSession(sessionId, async () => {\n const generated = await options.controller!.generateThreadTitle({\n threadId: thread.id,\n sessionId,\n requestContext,\n ...(stored?.observerModelId ? { model: titleModel(stored.observerModelId) } : {}),\n });\n const named = generated ? normalizeSessionTitle(generated) : null;\n if (named) await match.sourceControl.sessions.rename({ sessionId, title: named });\n return named;\n });\n if (!title) return c.json({ error: 'The model returned an empty title. Try again.' }, 502);\n return c.json({ title });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n ];\n}\n"],"mappings":"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"}
|
package/dist/routes/surface.d.ts
CHANGED
|
@@ -84,6 +84,11 @@ export interface FactoryApiRoutesDeps {
|
|
|
84
84
|
feed: CommentsDomain;
|
|
85
85
|
factoryTransitionService?: FactoryTransitionService;
|
|
86
86
|
sessionRetirement?: import('../sandbox/session-retirement.js').SessionRetirementCoordinator;
|
|
87
|
+
/** Moves a thread with its observation vectors onto another memory resource. */
|
|
88
|
+
moveThread?: (input: {
|
|
89
|
+
threadId: string;
|
|
90
|
+
resourceId: string;
|
|
91
|
+
}) => Promise<unknown>;
|
|
87
92
|
onFactoryRuntime?: (runtime: {
|
|
88
93
|
transitionService: FactoryTransitionService;
|
|
89
94
|
startCoordinator: FactoryStartCoordinator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/routes/surface.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/routes/surface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAExG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAG/E,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAQ1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAKlF,OAAO,KAAK,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AAElH,OAAO,KAAK,EAA8B,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAS1G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAiB5C,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IAC7C,+FAA+F;IAC/F,YAAY,EAAE,YAAY,CAAC;IAC3B,qEAAqE;IACrE,IAAI,EAAE,SAAS,CAAC;IAChB,kFAAkF;IAClF,KAAK,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC;IACpD,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,YAAY,GAAG,aAAa,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,qEAAqE;IACrE,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;IACxD,4EAA4E;IAC5E,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,mFAAmF;IACnF,OAAO,EAAE;QACP,MAAM,EAAE,aAAa,CAAC;QACtB,gBAAgB,EAAE,uBAAuB,CAAC;QAC1C,cAAc,EAAE,qBAAqB,CAAC;QACtC,eAAe,EAAE,sBAAsB,CAAC;QACxC,UAAU,EAAE,iBAAiB,CAAC;QAC9B,aAAa,EAAE,oBAAoB,CAAC;QACpC,QAAQ,EAAE,sBAAsB,CAAC;QACjC,WAAW,EAAE,kBAAkB,CAAC;QAChC,SAAS,EAAE,gBAAgB,CAAC;QAC5B,eAAe,EAAE,sBAAsB,CAAC;QACxC,QAAQ,EAAE,uBAAuB,CAAC;KACnC,CAAC;IACF,YAAY,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACzC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,sFAAsF;IACtF,wBAAwB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,aAAa,EAAE,aAAa,CAAC;IAC7B,oFAAoF;IACpF,IAAI,EAAE,cAAc,CAAC;IACrB,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,kCAAkC,EAAE,4BAA4B,CAAC;IAC5F,gFAAgF;IAChF,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC3B,iBAAiB,EAAE,wBAAwB,CAAC;QAC5C,gBAAgB,EAAE,uBAAuB,CAAC;QAC1C,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC3E,KAAK,IAAI,CAAC;CACZ;AAqHD;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,qBAAqB,EAAE,0BAA0B,GAAG,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,EACnG,WAAW,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,EACrD,QAAQ,EAAE,sBAAsB,EAChC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,8BAA8B,EACrC,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,GACxC,OAAO,CAAC,IAAI,CAAC,CAuJf;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,CACR,oBAAoB,EAClB,YAAY,GACZ,cAAc,GACd,MAAM,GACN,SAAS,GACT,OAAO,GACP,gBAAgB,GAChB,oBAAoB,GACpB,sBAAsB,GACtB,cAAc,CACjB,GAAG;IACF,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,IAAI,CACX,oBAAoB,CAAC,SAAS,CAAC,EAC/B,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,eAAe,CAC7F,CAAC;IACF;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,EACD,aAAa,EAAE,MAAM,GACpB,kBAAkB,CAuCpB;AAiGD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,oBAAoB,GAAG,QAAQ,EAAE,CA2N/E"}
|
package/dist/routes/surface.js
CHANGED
|
@@ -396,6 +396,7 @@ function assembleFactoryApiRoutes(deps) {
|
|
|
396
396
|
sandboxRecreateSupported: deps.sandbox !== void 0 && deps.sandbox.provider !== "local",
|
|
397
397
|
filesystem: deps.domains.filesystem,
|
|
398
398
|
...deps.factoryReady ? { workItems: deps.domains.workItems } : {},
|
|
399
|
+
...deps.moveThread ? { moveThread: deps.moveThread } : {},
|
|
399
400
|
...githubStorage ? { githubRepositories: githubStorage.repositories } : {}
|
|
400
401
|
});
|
|
401
402
|
const absentStubs = [
|
|
@@ -437,8 +438,7 @@ function assembleFactoryApiRoutes(deps) {
|
|
|
437
438
|
root: deps.fsRoot,
|
|
438
439
|
sessionFs: {
|
|
439
440
|
auth: deps.auth,
|
|
440
|
-
sessions: sourceControlSessions
|
|
441
|
-
filesystem: deps.domains.filesystem
|
|
441
|
+
sessions: sourceControlSessions
|
|
442
442
|
}
|
|
443
443
|
}),
|
|
444
444
|
...new ConfigRoutes({
|