@cf-vibesdk/sdk 0.0.2 → 0.0.3
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/README.md +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +119 -41
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1326,6 +1326,12 @@ export interface AgentConnectionData {
|
|
|
1326
1326
|
agentId: string;
|
|
1327
1327
|
}
|
|
1328
1328
|
export type AgentPreviewResponse = PreviewType;
|
|
1329
|
+
type RetryConfig = {
|
|
1330
|
+
enabled?: boolean;
|
|
1331
|
+
initialDelayMs?: number;
|
|
1332
|
+
maxDelayMs?: number;
|
|
1333
|
+
maxRetries?: number;
|
|
1334
|
+
};
|
|
1329
1335
|
type BehaviorType$1 = BehaviorType;
|
|
1330
1336
|
type ProjectType$1 = ProjectType;
|
|
1331
1337
|
export type Credentials = NonNullable<CodeGenArgs["credentials"]>;
|
|
@@ -1525,6 +1531,8 @@ export type VibeClientOptions = {
|
|
|
1525
1531
|
/** Optional WebSocket factory for Node/Bun runtimes. */
|
|
1526
1532
|
webSocketFactory?: AgentConnectionOptions["webSocketFactory"];
|
|
1527
1533
|
fetchFn?: typeof fetch;
|
|
1534
|
+
/** HTTP retry configuration for transient failures (5xx, network errors). */
|
|
1535
|
+
retry?: RetryConfig;
|
|
1528
1536
|
};
|
|
1529
1537
|
type GenerationState = {
|
|
1530
1538
|
status: "idle";
|
|
@@ -1593,6 +1601,7 @@ export declare class SessionStateStore {
|
|
|
1593
1601
|
onChange(cb: (next: SessionState, prev: SessionState) => void): () => void;
|
|
1594
1602
|
applyWsMessage(msg: AgentWsServerMessage): void;
|
|
1595
1603
|
private setState;
|
|
1604
|
+
clear(): void;
|
|
1596
1605
|
}
|
|
1597
1606
|
type WorkspaceChange = {
|
|
1598
1607
|
type: "reset";
|
|
@@ -1616,6 +1625,7 @@ export declare class WorkspaceStore {
|
|
|
1616
1625
|
/** Apply a single file upsert from WS file events. */
|
|
1617
1626
|
applyFileUpsert(file: unknown): void;
|
|
1618
1627
|
applyWsMessage(msg: AgentWsServerMessage): void;
|
|
1628
|
+
clear(): void;
|
|
1619
1629
|
}
|
|
1620
1630
|
type WaitUntilReadyOptions = WaitOptions;
|
|
1621
1631
|
type BuildSessionConnectOptions = AgentConnectionOptions & {
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// src/retry.ts
|
|
3
|
+
function normalizeRetryConfig(retry, defaults) {
|
|
4
|
+
return {
|
|
5
|
+
enabled: retry?.enabled ?? defaults.enabled,
|
|
6
|
+
initialDelayMs: retry?.initialDelayMs ?? defaults.initialDelayMs,
|
|
7
|
+
maxDelayMs: retry?.maxDelayMs ?? defaults.maxDelayMs,
|
|
8
|
+
maxRetries: retry?.maxRetries ?? defaults.maxRetries
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function computeBackoffMs(attempt, cfg) {
|
|
12
|
+
const base = Math.min(cfg.maxDelayMs, cfg.initialDelayMs * Math.pow(2, Math.max(0, attempt)));
|
|
13
|
+
const jitter = base * 0.2;
|
|
14
|
+
return Math.max(0, Math.floor(base - jitter + Math.random() * jitter * 2));
|
|
15
|
+
}
|
|
16
|
+
function sleep(ms) {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
|
|
2
20
|
// src/http.ts
|
|
21
|
+
var HTTP_RETRY_DEFAULTS = {
|
|
22
|
+
enabled: true,
|
|
23
|
+
initialDelayMs: 1000,
|
|
24
|
+
maxDelayMs: 1e4,
|
|
25
|
+
maxRetries: 3
|
|
26
|
+
};
|
|
27
|
+
function isRetryableStatus(status) {
|
|
28
|
+
return status >= 500 && status < 600;
|
|
29
|
+
}
|
|
30
|
+
|
|
3
31
|
class HttpClient {
|
|
4
32
|
opts;
|
|
5
33
|
cachedAccessToken = null;
|
|
34
|
+
retryCfg;
|
|
6
35
|
constructor(opts) {
|
|
7
36
|
this.opts = opts;
|
|
37
|
+
this.retryCfg = normalizeRetryConfig(opts.retry, HTTP_RETRY_DEFAULTS);
|
|
8
38
|
}
|
|
9
39
|
get baseUrl() {
|
|
10
40
|
return this.opts.baseUrl.replace(/\/$/, "");
|
|
@@ -34,7 +64,7 @@ class HttpClient {
|
|
|
34
64
|
}
|
|
35
65
|
});
|
|
36
66
|
if (!resp.ok) {
|
|
37
|
-
const text = await resp.text().catch(() => "");
|
|
67
|
+
const text = (await resp.text().catch(() => "")).slice(0, 1000);
|
|
38
68
|
if (resp.status === 401) {
|
|
39
69
|
throw new Error(`HTTP 401 for /api/auth/exchange-api-key: invalid API key (regenerate in Settings \u2192 API Keys). ${text || ""}`.trim());
|
|
40
70
|
}
|
|
@@ -60,21 +90,59 @@ class HttpClient {
|
|
|
60
90
|
}
|
|
61
91
|
async fetchJson(path, init) {
|
|
62
92
|
const url = `${this.baseUrl}${path}`;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
93
|
+
let lastError = null;
|
|
94
|
+
for (let attempt = 0;attempt <= this.retryCfg.maxRetries; attempt++) {
|
|
95
|
+
try {
|
|
96
|
+
const resp = await this.fetchFn(url, init);
|
|
97
|
+
if (!resp.ok) {
|
|
98
|
+
const text = (await resp.text().catch(() => "")).slice(0, 1000);
|
|
99
|
+
const error = new Error(`HTTP ${resp.status} for ${path}: ${text || resp.statusText}`);
|
|
100
|
+
if (this.retryCfg.enabled && isRetryableStatus(resp.status) && attempt < this.retryCfg.maxRetries) {
|
|
101
|
+
lastError = error;
|
|
102
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
return await resp.json();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof TypeError && this.retryCfg.enabled && attempt < this.retryCfg.maxRetries) {
|
|
110
|
+
lastError = error;
|
|
111
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
67
116
|
}
|
|
68
|
-
|
|
117
|
+
throw lastError ?? new Error(`Failed after ${this.retryCfg.maxRetries} retries`);
|
|
69
118
|
}
|
|
70
119
|
async fetchRaw(path, init) {
|
|
71
120
|
const url = `${this.baseUrl}${path}`;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
121
|
+
let lastError = null;
|
|
122
|
+
for (let attempt = 0;attempt <= this.retryCfg.maxRetries; attempt++) {
|
|
123
|
+
try {
|
|
124
|
+
const resp = await this.fetchFn(url, init);
|
|
125
|
+
if (!resp.ok) {
|
|
126
|
+
const text = (await resp.text().catch(() => "")).slice(0, 1000);
|
|
127
|
+
const error = new Error(`HTTP ${resp.status} for ${path}: ${text || resp.statusText}`);
|
|
128
|
+
if (this.retryCfg.enabled && isRetryableStatus(resp.status) && attempt < this.retryCfg.maxRetries) {
|
|
129
|
+
lastError = error;
|
|
130
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
return resp;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof TypeError && this.retryCfg.enabled && attempt < this.retryCfg.maxRetries) {
|
|
138
|
+
lastError = error;
|
|
139
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
76
144
|
}
|
|
77
|
-
|
|
145
|
+
throw lastError ?? new Error(`Failed after ${this.retryCfg.maxRetries} retries`);
|
|
78
146
|
}
|
|
79
147
|
}
|
|
80
148
|
|
|
@@ -137,6 +205,10 @@ class TypedEmitter {
|
|
|
137
205
|
for (const cb of set)
|
|
138
206
|
cb(payload);
|
|
139
207
|
}
|
|
208
|
+
clear() {
|
|
209
|
+
this.listeners.clear();
|
|
210
|
+
this.anyListeners.clear();
|
|
211
|
+
}
|
|
140
212
|
}
|
|
141
213
|
|
|
142
214
|
// src/state.ts
|
|
@@ -147,9 +219,10 @@ var INITIAL_STATE = {
|
|
|
147
219
|
cloudflare: { status: "idle" }
|
|
148
220
|
};
|
|
149
221
|
function extractPhaseInfo(msg) {
|
|
222
|
+
const phase = msg?.phase;
|
|
150
223
|
return {
|
|
151
|
-
name:
|
|
152
|
-
description:
|
|
224
|
+
name: phase?.name,
|
|
225
|
+
description: phase?.description
|
|
153
226
|
};
|
|
154
227
|
}
|
|
155
228
|
|
|
@@ -299,6 +372,10 @@ class SessionStateStore {
|
|
|
299
372
|
this.state = next;
|
|
300
373
|
this.emitter.emit("change", { prev, next });
|
|
301
374
|
}
|
|
375
|
+
clear() {
|
|
376
|
+
this.state = INITIAL_STATE;
|
|
377
|
+
this.emitter.clear();
|
|
378
|
+
}
|
|
302
379
|
}
|
|
303
380
|
|
|
304
381
|
// src/ws.ts
|
|
@@ -308,23 +385,15 @@ function toWsCloseEvent(ev) {
|
|
|
308
385
|
reason: typeof ev.reason === "string" ? ev.reason : ""
|
|
309
386
|
};
|
|
310
387
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
maxRetries: retry?.maxRetries ?? Infinity
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function computeBackoffMs(attempt, cfg) {
|
|
321
|
-
const base = Math.min(cfg.maxDelayMs, cfg.initialDelayMs * Math.pow(2, Math.max(0, attempt)));
|
|
322
|
-
const jitter = base * 0.2;
|
|
323
|
-
return Math.max(0, Math.floor(base - jitter + Math.random() * jitter * 2));
|
|
324
|
-
}
|
|
388
|
+
var WS_RETRY_DEFAULTS = {
|
|
389
|
+
enabled: true,
|
|
390
|
+
initialDelayMs: 1000,
|
|
391
|
+
maxDelayMs: 30000,
|
|
392
|
+
maxRetries: Infinity
|
|
393
|
+
};
|
|
325
394
|
function createAgentConnection(url, options = {}) {
|
|
326
395
|
const emitter = new TypedEmitter;
|
|
327
|
-
const retryCfg = normalizeRetryConfig(options.retry);
|
|
396
|
+
const retryCfg = normalizeRetryConfig(options.retry, WS_RETRY_DEFAULTS);
|
|
328
397
|
const headers = { ...options.headers ?? {} };
|
|
329
398
|
if (options.origin)
|
|
330
399
|
headers.Origin = options.origin;
|
|
@@ -501,7 +570,7 @@ function createAgentConnection(url, options = {}) {
|
|
|
501
570
|
}
|
|
502
571
|
if (ws.on) {
|
|
503
572
|
ws.on("open", () => onOpen());
|
|
504
|
-
ws.on("close", (code, reason) => onClose({ code, reason }));
|
|
573
|
+
ws.on("close", (code, reason) => onClose({ code: typeof code === "number" ? code : undefined, reason: typeof reason === "string" ? reason : undefined }));
|
|
505
574
|
ws.on("error", (error) => onError(error));
|
|
506
575
|
ws.on("message", (data) => onMessage(data));
|
|
507
576
|
}
|
|
@@ -514,8 +583,12 @@ function createAgentConnection(url, options = {}) {
|
|
|
514
583
|
return;
|
|
515
584
|
}
|
|
516
585
|
pendingSends.push(data);
|
|
517
|
-
if (pendingSends.length > maxPendingSends)
|
|
586
|
+
if (pendingSends.length > maxPendingSends) {
|
|
518
587
|
pendingSends.shift();
|
|
588
|
+
emitter.emit("ws:error", {
|
|
589
|
+
error: new Error(`Message queue overflow: dropped oldest message (queue size: ${maxPendingSends})`)
|
|
590
|
+
});
|
|
591
|
+
}
|
|
519
592
|
}
|
|
520
593
|
function close() {
|
|
521
594
|
closedByUser = true;
|
|
@@ -553,25 +626,24 @@ function createAgentConnection(url, options = {}) {
|
|
|
553
626
|
function isRecord(value) {
|
|
554
627
|
return typeof value === "object" && value !== null;
|
|
555
628
|
}
|
|
629
|
+
function isFileOutputType(value) {
|
|
630
|
+
if (!isRecord(value))
|
|
631
|
+
return false;
|
|
632
|
+
return typeof value.filePath === "string" && typeof value.fileContents === "string";
|
|
633
|
+
}
|
|
556
634
|
function extractGeneratedFilesFromState(state) {
|
|
557
635
|
const out = [];
|
|
558
636
|
for (const file of Object.values(state.generatedFilesMap ?? {})) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
out.push({ path, content });
|
|
563
|
-
}
|
|
637
|
+
if (!isFileOutputType(file))
|
|
638
|
+
continue;
|
|
639
|
+
out.push({ path: file.filePath, content: file.fileContents });
|
|
564
640
|
}
|
|
565
641
|
return out;
|
|
566
642
|
}
|
|
567
643
|
function extractGeneratedFileFromMessageFile(file) {
|
|
568
|
-
if (!
|
|
569
|
-
return null;
|
|
570
|
-
const path = file.filePath;
|
|
571
|
-
const content = file.fileContents;
|
|
572
|
-
if (typeof path !== "string" || typeof content !== "string")
|
|
644
|
+
if (!isFileOutputType(file))
|
|
573
645
|
return null;
|
|
574
|
-
return { path, content };
|
|
646
|
+
return { path: file.filePath, content: file.fileContents };
|
|
575
647
|
}
|
|
576
648
|
|
|
577
649
|
class WorkspaceStore {
|
|
@@ -624,6 +696,10 @@ class WorkspaceStore {
|
|
|
624
696
|
break;
|
|
625
697
|
}
|
|
626
698
|
}
|
|
699
|
+
clear() {
|
|
700
|
+
this.files.clear();
|
|
701
|
+
this.emitter.clear();
|
|
702
|
+
}
|
|
627
703
|
}
|
|
628
704
|
|
|
629
705
|
// src/session.ts
|
|
@@ -843,6 +919,8 @@ class BuildSession {
|
|
|
843
919
|
close() {
|
|
844
920
|
this.connection?.close();
|
|
845
921
|
this.connection = null;
|
|
922
|
+
this.workspace.clear();
|
|
923
|
+
this.state.clear();
|
|
846
924
|
}
|
|
847
925
|
assertConnected() {
|
|
848
926
|
if (!this.connection) {
|