Skip to content

Commit f95b1c8

Browse files
authored
Merge pull request #293 from cloudflare/fix/sdk-fixes
Fix: SDK functionalities addition + Auth redesign
2 parents ba1847d + dc48247 commit f95b1c8

35 files changed

+1818
-541
lines changed

sdk/README.md

Lines changed: 287 additions & 73 deletions
Large diffs are not rendered by default.

sdk/bun.lock

Lines changed: 197 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sdk/package.json

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
11
{
22
"name": "@cf-vibesdk/sdk",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"type": "module",
55
"exports": {
66
".": {
77
"types": "./dist/index.d.ts",
88
"default": "./dist/index.js"
9-
},
10-
"./node": {
11-
"types": "./dist/node.d.ts",
12-
"default": "./dist/node.js"
139
}
1410
},
1511
"files": [
1612
"dist"
1713
],
14+
"engines": {
15+
"node": ">=22"
16+
},
1817
"publishConfig": {
1918
"access": "public"
2019
},
2120
"scripts": {
22-
"build": "rm -rf ./dist && bun build ./src/index.ts ./src/node.ts --outdir ./dist --target bun",
23-
"bundle-types": "dts-bundle-generator --export-referenced-types false --project ./tsconfig.protocol.json -o ./dist/index.d.ts ./src/index.ts && dts-bundle-generator --export-referenced-types false --project ./tsconfig.protocol.json -o ./dist/node.d.ts ./src/node.ts",
21+
"build": "rm -rf ./dist && bun build ./src/index.ts --outdir ./dist --target browser",
22+
"bundle-types": "dts-bundle-generator --export-referenced-types false --project ./tsconfig.protocol.json -o ./dist/index.d.ts ./src/index.ts",
2423
"typecheck": "tsc -p ./tsconfig.json --noEmit",
2524
"test": "bun test test/*.test.ts",
2625
"test:integration": "bun test --timeout 600000 test/integration/*.test.ts"
2726
},
28-
"dependencies": {
29-
"ws": "^8.18.3"
30-
},
3127
"devDependencies": {
32-
"@types/ws": "^8.18.1",
28+
"@cloudflare/workers-types": "^4.20241218.0",
29+
"@types/node": "^25.0.3",
3330
"dts-bundle-generator": "^9.5.1",
34-
"typescript": "^5.9.3"
31+
"miniflare": "^4.20251217.0",
32+
"typescript": "^5.9.3",
33+
"wrangler": "^4.14.1"
3534
}
3635
}
37-
38-

sdk/src/blueprint.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
/**
2-
* Utility for checking if a value is a plain object.
3-
*/
4-
export function isRecord(v: unknown): v is Record<string, unknown> {
5-
return Boolean(v) && typeof v === 'object' && !Array.isArray(v);
6-
}
1+
import { isRecord } from './utils';
72

83
/**
94
* Blueprint structure as streamed from the agent.

sdk/src/client.ts

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ import type {
22
ApiResponse,
33
AppDetails,
44
AppListItem,
5+
AppVisibility,
6+
AppWithFavoriteStatus,
57
BuildOptions,
68
BuildStartEvent,
79
Credentials,
10+
DeleteResult,
811
PublicAppsQuery,
12+
ToggleResult,
913
VibeClientOptions,
14+
VisibilityUpdateResult,
1015
} from './types';
1116
import { HttpClient } from './http';
1217
import { parseNdjsonStream } from './ndjson';
@@ -25,7 +30,7 @@ function toQueryString(query: Record<string, string | number | undefined>): stri
2530
export class VibeClient {
2631
private http: HttpClient;
2732

28-
constructor(private options: VibeClientOptions) {
33+
constructor(options: VibeClientOptions) {
2934
this.http = new HttpClient(options);
3035
}
3136

@@ -35,9 +40,6 @@ export class VibeClient {
3540

3641
/**
3742
* Creates a new agent/app from a prompt and returns a BuildSession.
38-
*
39-
* Current platform requirement: `token` must be a valid JWT access token.
40-
* Later: `apiKey` will be exchanged for a short-lived JWT.
4143
*/
4244
async build(prompt: string, options: BuildOptions = {}): Promise<BuildSession> {
4345
const body = {
@@ -48,7 +50,6 @@ export class VibeClient {
4850
behaviorType: options.behaviorType,
4951
projectType: options.projectType,
5052
images: options.images,
51-
// Future: credentials
5253
credentials: options.credentials,
5354
};
5455

@@ -79,12 +80,13 @@ export class VibeClient {
7980
throw new Error('No start event received from /api/agent');
8081
}
8182

82-
const session = new BuildSession(this.options, start, {
83-
getAuthToken: () => this.http.getToken(),
83+
const session = new BuildSession(start, {
84+
httpClient: this.http,
8485
...(options.credentials ? { defaultCredentials: options.credentials } : {}),
8586
});
87+
8688
if (options.autoConnect ?? true) {
87-
session.connect();
89+
await session.connect();
8890
if (options.autoGenerate ?? true) {
8991
session.startGeneration();
9092
}
@@ -109,13 +111,14 @@ export class VibeClient {
109111
websocketUrl: data.data.websocketUrl,
110112
};
111113

112-
return new BuildSession(this.options, start, {
113-
getAuthToken: () => this.http.getToken(),
114+
return new BuildSession(start, {
115+
httpClient: this.http,
114116
...(options.credentials ? { defaultCredentials: options.credentials } : {}),
115117
});
116118
}
117119

118120
apps = {
121+
/** List public apps with optional filtering and pagination. */
119122
listPublic: async (query: PublicAppsQuery = {}) => {
120123
const qs = toQueryString({
121124
limit: query.limit,
@@ -132,20 +135,72 @@ export class VibeClient {
132135
);
133136
},
134137

138+
/** List all apps owned by the authenticated user. */
135139
listMine: async () => {
136-
return this.http.fetchJson<ApiResponse<{ apps: AppListItem[] }>>('/api/apps', {
140+
return this.http.fetchJson<ApiResponse<{ apps: AppWithFavoriteStatus[] }>>('/api/apps', {
141+
method: 'GET',
142+
headers: await this.http.headers(),
143+
});
144+
},
145+
146+
/** List recent apps (last 10) for the authenticated user. */
147+
listRecent: async () => {
148+
return this.http.fetchJson<ApiResponse<{ apps: AppWithFavoriteStatus[] }>>('/api/apps/recent', {
137149
method: 'GET',
138150
headers: await this.http.headers(),
139151
});
140152
},
141153

154+
/** List favorite apps for the authenticated user. */
155+
listFavorites: async () => {
156+
return this.http.fetchJson<ApiResponse<{ apps: AppWithFavoriteStatus[] }>>('/api/apps/favorites', {
157+
method: 'GET',
158+
headers: await this.http.headers(),
159+
});
160+
},
161+
162+
/** Get detailed information about a specific app. */
142163
get: async (appId: string) => {
143164
return this.http.fetchJson<ApiResponse<AppDetails>>(`/api/apps/${appId}`, {
144165
method: 'GET',
145166
headers: await this.http.headers(),
146167
});
147168
},
148169

170+
/** Delete an app (owner only). */
171+
delete: async (appId: string) => {
172+
return this.http.fetchJson<ApiResponse<DeleteResult>>(`/api/apps/${appId}`, {
173+
method: 'DELETE',
174+
headers: await this.http.headers(),
175+
});
176+
},
177+
178+
/** Update app visibility (owner only). */
179+
setVisibility: async (appId: string, visibility: AppVisibility) => {
180+
return this.http.fetchJson<ApiResponse<VisibilityUpdateResult>>(`/api/apps/${appId}/visibility`, {
181+
method: 'PUT',
182+
headers: await this.http.headers({ 'Content-Type': 'application/json' }),
183+
body: JSON.stringify({ visibility }),
184+
});
185+
},
186+
187+
/** Toggle star/bookmark status on an app. */
188+
toggleStar: async (appId: string) => {
189+
return this.http.fetchJson<ApiResponse<ToggleResult>>(`/api/apps/${appId}/star`, {
190+
method: 'POST',
191+
headers: await this.http.headers(),
192+
});
193+
},
194+
195+
/** Toggle favorite status on an app. */
196+
toggleFavorite: async (appId: string) => {
197+
return this.http.fetchJson<ApiResponse<ToggleResult>>(`/api/apps/${appId}/favorite`, {
198+
method: 'POST',
199+
headers: await this.http.headers(),
200+
});
201+
},
202+
203+
/** Generate a git clone token for an app (owner only). */
149204
getGitCloneToken: async (appId: string) => {
150205
return this.http.fetchJson<
151206
ApiResponse<{ token: string; expiresIn: number; expiresAt: string; cloneUrl: string }>

sdk/src/http.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ export class HttpClient {
3737
}
3838

3939
private get fetchFn(): typeof fetch {
40-
return this.opts.fetchFn ?? fetch;
40+
// Wrap global fetch to preserve context in Workers runtime
41+
// See: https://developers.cloudflare.com/workers/observability/errors/#illegal-invocation-errors
42+
return this.opts.fetchFn ?? ((...args: Parameters<typeof fetch>) => fetch(...args));
4143
}
4244

4345
getToken(): string | undefined {
@@ -158,4 +160,25 @@ export class HttpClient {
158160

159161
throw lastError ?? new Error(`Failed after ${this.retryCfg.maxRetries} retries`);
160162
}
163+
164+
/**
165+
* Request a WebSocket ticket for secure agent connection.
166+
* Tickets are single-use and short-lived (15 seconds).
167+
*/
168+
async getWsTicket(agentId: string): Promise<{ ticket: string; expiresIn: number; expiresAt: string }> {
169+
const resp = await this.fetchJson<ApiResponse<{ ticket: string; expiresIn: number; expiresAt: string }>>(
170+
'/api/ws-ticket',
171+
{
172+
method: 'POST',
173+
headers: await this.headers({ 'Content-Type': 'application/json' }),
174+
body: JSON.stringify({ resourceType: 'agent', resourceId: agentId }),
175+
},
176+
);
177+
178+
if (!resp.success) {
179+
throw new Error(resp.error.message || 'Failed to get WebSocket ticket');
180+
}
181+
182+
return resp.data;
183+
}
161184
}

sdk/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ export { BuildSession } from './session';
55
export { WorkspaceStore } from './workspace';
66
export { SessionStateStore } from './state';
77

8-
export { isRecord, blueprintToMarkdown, BlueprintStreamParser } from './blueprint';
8+
export { blueprintToMarkdown, BlueprintStreamParser } from './blueprint';
99
export type { Blueprint } from './blueprint';
1010

11-
export { withTimeout, TimeoutError } from './utils';
11+
export { isRecord, withTimeout, TimeoutError } from './utils';
1212

1313
export type {
1414
AgentConnection,
@@ -18,18 +18,24 @@ export type {
1818
ApiResponse,
1919
AppDetails,
2020
AppListItem,
21+
AppVisibility,
22+
AppWithFavoriteStatus,
2123
BehaviorType,
2224
BuildOptions,
2325
BuildStartEvent,
2426
CodeGenArgs,
2527
Credentials,
28+
DeleteResult,
2629
FileTreeNode,
2730
PhaseEventType,
2831
ProjectType,
2932
PublicAppsQuery,
3033
SessionDeployable,
3134
SessionFiles,
35+
ToggleResult,
36+
UrlProvider,
3237
VibeClientOptions,
38+
VisibilityUpdateResult,
3339
WaitForPhaseOptions,
3440
WaitOptions,
3541
} from './types';

sdk/src/node.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

sdk/src/protocol.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ export type {
2323
CodeGenArgs as PlatformCodeGenArgs,
2424
AgentPreviewResponse,
2525
} from '../../worker/api/controllers/agent/types';
26+
27+
export type { ImageAttachment } from '../../worker/types/image-attachment';

0 commit comments

Comments
 (0)