Skip to content

Commit 36ba678

Browse files
feat: SDK API expansion — computer lifecycle, session listing, and cleanup (#51)
* feat: add listMachineTemplates and getMachineTemplate for template discovery Adds REST API client for the Factory v0 machine templates endpoint, enabling SDK users to discover available workspace templates programmatically without needing the web UI. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * fix: improve API schema validation and error reporting Remove .passthrough() from REST API response schemas — these are terminal types, not proxied protocol messages, so stripping unknown keys is correct. Fix getMachineTemplate to report schema parse failures accurately instead of fabricating a 404. Remove unreachable 204 branch from factoryFetch. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat: auto-provision ephemeral sandboxes in connectDaemon connectDaemon() now automatically provisions an e2b sandbox when called with MachineType.Ephemeral and no sandboxId. The SDK calls POST /api/workspaces/{workspaceId}/sandbox/create, then connects to the new sandbox with a default retry budget of 30 (60s) to account for daemon startup time. Also adds createSandbox() as a standalone exported function, generalizes factoryFetch to support POST requests, and makes sandboxId optional on SDKMachineConfig.Ephemeral. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat: add session management methods to DaemonSession for parity with DroidSession Adds 15 methods to DaemonClient and 16 passthrough methods to DaemonSession (including enterSpecMode convenience wrapper) so daemon-mode users have the same capabilities as exec-mode users: updateSettings, compactSession, forkSession, getContextBreakdown, renameSession, getRewindInfo, executeRewind, addMcpServer, removeMcpServer, toggleMcpServer, listMcpServers, listMcpTools, authenticateMcpServer, listSkills, and enterSpecMode. Also adds ContextBreakdownResultSchema for the daemon's get_context_breakdown response (richer than exec-mode's get_context_stats). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat: add listComputers and getComputer for computer discovery Wraps GET /api/v0/computers and GET /api/v0/computers/{computerId} so SDK users can discover their registered computers programmatically, matching the existing listMachineTemplates/getMachineTemplate pattern. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat: add computer lifecycle methods, remove non-functional sandbox methods Add 8 computer lifecycle functions (createComputer, getComputerByName, updateComputer, deleteComputer, restartComputer, refreshComputer, getComputerMetrics, retryInstallDeps) with full schemas, types, and tests. Extend factoryFetch to support PATCH, DELETE, and 204 No Content responses. Remove createSandbox, downloadSandboxFiles, restartSandbox and associated auto-provisioning logic — these endpoints use non-v0 auth that rejects API keys, and the sandbox infrastructure is being deprecated. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * feat: add remote session listing to listSessions Extend listSessions to fetch sessions from the Factory API when an apiKey is provided, with optional computerId filter and cursor-based pagination. Local file-based listing is unchanged when apiKey is omitted. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * refactor: remove MachineType.Ephemeral Ephemeral sandbox infrastructure is being deprecated and the endpoints never accepted Factory API keys. Remove the Ephemeral machine type, its URL resolution, and associated tests. The SDK now supports Local and Computer machine types only. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * style: fix prettier formatting Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> * refactor: simplify API layer and separate local/remote session listing - Extract parseResponse helper to deduplicate 11 safeParse+throw blocks in api.ts - Extract FactoryApiOptions/ComputerApiOptions base interfaces in api-types.ts - Export listRemoteSessions and related types from public API - Remove remote API branch from listSessions() to keep it local-only - Clean up ListSessionsOptions to remove mixed local/remote fields Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --------- Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
1 parent 1c1a37b commit 36ba678

14 files changed

Lines changed: 2718 additions & 45 deletions

File tree

src/api-types.ts

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import { z } from 'zod';
2+
3+
const EnvironmentVariableSchema = z.object({
4+
key: z.string(),
5+
value: z.string(),
6+
});
7+
8+
export const MachineTemplateBuildStatusSchema = z.object({
9+
status: z.enum(['building', 'success', 'failed']),
10+
failureReason: z.enum(['setup_script_error', 'system_error']).optional(),
11+
buildStartedAt: z.number().int().optional(),
12+
builtAt: z.number().int().optional(),
13+
logs: z.string().optional(),
14+
});
15+
16+
export type MachineTemplateBuildStatus = z.infer<
17+
typeof MachineTemplateBuildStatusSchema
18+
>;
19+
20+
export const MachineTemplateSchema = z.object({
21+
templateId: z.string(),
22+
repoUrl: z.string(),
23+
templateName: z.string(),
24+
defaultBranch: z.string(),
25+
createdBy: z.string(),
26+
createdAt: z.number().int().optional(),
27+
buildStatus: MachineTemplateBuildStatusSchema.optional(),
28+
lastUpdatedAt: z.number().int().nullable().optional(),
29+
environmentVariables: z.array(EnvironmentVariableSchema).optional(),
30+
userEnvironmentVariablesByUser: z.array(EnvironmentVariableSchema).optional(),
31+
setupScript: z.string().optional(),
32+
});
33+
34+
export type MachineTemplate = z.infer<typeof MachineTemplateSchema>;
35+
36+
export const MachineTemplateListResponseSchema = z.object({
37+
templates: z.array(MachineTemplateSchema),
38+
pagination: z.object({
39+
hasMore: z.boolean(),
40+
nextCursor: z.string().nullable(),
41+
}),
42+
});
43+
44+
export type MachineTemplateListResponse = z.infer<
45+
typeof MachineTemplateListResponseSchema
46+
>;
47+
48+
export interface FactoryApiOptions {
49+
apiKey: string;
50+
baseUrl?: string;
51+
}
52+
53+
export interface ComputerApiOptions extends FactoryApiOptions {
54+
computerId: string;
55+
}
56+
57+
export interface ListMachineTemplatesOptions extends FactoryApiOptions {
58+
limit?: number;
59+
cursor?: string;
60+
}
61+
62+
export interface GetMachineTemplateOptions extends FactoryApiOptions {
63+
templateId: string;
64+
}
65+
66+
export const ComputerSchema = z
67+
.object({
68+
id: z.string(),
69+
name: z.string(),
70+
hostname: z.string().optional(),
71+
providerType: z.enum(['byom', 'e2b']),
72+
status: z.enum(['provisioning', 'active', 'error']).optional(),
73+
createdAt: z.number().int(),
74+
relayClientUrl: z.string().optional(),
75+
remoteUser: z.string().optional(),
76+
})
77+
.passthrough();
78+
79+
export type Computer = z.infer<typeof ComputerSchema>;
80+
81+
export const ComputerListResponseSchema = z.object({
82+
computers: z.array(ComputerSchema),
83+
});
84+
85+
export type ComputerListResponse = z.infer<typeof ComputerListResponseSchema>;
86+
87+
export interface ListComputersOptions extends FactoryApiOptions {}
88+
89+
export interface GetComputerOptions extends ComputerApiOptions {}
90+
91+
export interface CreateComputerOptions extends FactoryApiOptions {
92+
name: string;
93+
remoteUser: string;
94+
provider?: 'byom' | 'e2b';
95+
hostId?: string;
96+
repos?: string[];
97+
autoInstallDeps?: boolean;
98+
serviceAccountId?: string;
99+
}
100+
101+
export interface GetComputerByNameOptions extends FactoryApiOptions {
102+
name: string;
103+
}
104+
105+
export interface UpdateComputerOptions extends ComputerApiOptions {
106+
name?: string;
107+
remoteUser?: string;
108+
hostId?: string;
109+
}
110+
111+
export interface DeleteComputerOptions extends ComputerApiOptions {}
112+
113+
export interface RestartComputerOptions extends ComputerApiOptions {}
114+
115+
export interface RefreshComputerOptions extends ComputerApiOptions {}
116+
117+
export const RefreshComputerResponseSchema = z.object({
118+
configured: z.number().int(),
119+
});
120+
121+
export type RefreshComputerResponse = z.infer<
122+
typeof RefreshComputerResponseSchema
123+
>;
124+
125+
export const ComputerMetricSchema = z.object({
126+
timestamp: z.string(),
127+
cpuUsedPct: z.number(),
128+
cpuCount: z.number(),
129+
memUsed: z.number(),
130+
memTotal: z.number(),
131+
diskUsed: z.number(),
132+
diskTotal: z.number(),
133+
});
134+
135+
export type ComputerMetric = z.infer<typeof ComputerMetricSchema>;
136+
137+
export const ComputerMetricsResponseSchema = z.array(ComputerMetricSchema);
138+
139+
export type ComputerMetricsResponse = z.infer<
140+
typeof ComputerMetricsResponseSchema
141+
>;
142+
143+
export interface GetComputerMetricsOptions extends ComputerApiOptions {
144+
start?: string;
145+
}
146+
147+
export interface RetryInstallDepsOptions extends ComputerApiOptions {}
148+
149+
export const RemoteSessionSchema = z.object({
150+
sessionId: z.string(),
151+
title: z.string().optional(),
152+
status: z.enum(['idle', 'pending', 'running']),
153+
messageCount: z.number().int(),
154+
createdAt: z.number().int(),
155+
updatedAt: z.number().int(),
156+
completedAt: z.number().int().optional(),
157+
computerId: z.string().optional(),
158+
});
159+
160+
export type RemoteSession = z.infer<typeof RemoteSessionSchema>;
161+
162+
export const RemoteSessionListResponseSchema = z.object({
163+
sessions: z.array(RemoteSessionSchema),
164+
pagination: z.object({
165+
hasMore: z.boolean(),
166+
nextCursor: z.string().nullable(),
167+
}),
168+
});
169+
170+
export type RemoteSessionListResponse = z.infer<
171+
typeof RemoteSessionListResponseSchema
172+
>;
173+
174+
export interface ListRemoteSessionsOptions extends FactoryApiOptions {
175+
computerId?: string;
176+
limit?: number;
177+
cursor?: string;
178+
}

0 commit comments

Comments
 (0)