@chatu-ai/builder-sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +80 -0
- package/dist/client.js +21 -0
- package/dist/parse.test.js +43 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -48,6 +48,52 @@ export interface FileNode {
|
|
|
48
48
|
type: 'file' | 'dir';
|
|
49
49
|
children?: FileNode[];
|
|
50
50
|
}
|
|
51
|
+
export type CredentialScope = 'organization' | 'user' | 'conversation';
|
|
52
|
+
export interface CredentialView {
|
|
53
|
+
id: string;
|
|
54
|
+
scope: CredentialScope;
|
|
55
|
+
provider: string;
|
|
56
|
+
label: string;
|
|
57
|
+
hint?: string | null;
|
|
58
|
+
meta?: Record<string, unknown> | null;
|
|
59
|
+
createdTime: string;
|
|
60
|
+
lastUsedTime?: string | null;
|
|
61
|
+
readOnly: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface DeploySettingView {
|
|
64
|
+
target: string;
|
|
65
|
+
credentialId?: string | null;
|
|
66
|
+
config: Record<string, unknown>;
|
|
67
|
+
lastRunTime?: string | null;
|
|
68
|
+
lastRunStatus?: string | null;
|
|
69
|
+
lastRunMessage?: string | null;
|
|
70
|
+
lastRunUrl?: string | null;
|
|
71
|
+
updatedTime: string;
|
|
72
|
+
}
|
|
73
|
+
export interface GitPushInput {
|
|
74
|
+
remoteUrl: string;
|
|
75
|
+
branch?: string;
|
|
76
|
+
/** 二选一:凭据库 id */
|
|
77
|
+
credentialId?: string;
|
|
78
|
+
/** 二选一:仅本次使用的令牌;save=true 时同时存为用户级凭据 */
|
|
79
|
+
token?: string;
|
|
80
|
+
username?: string;
|
|
81
|
+
save?: boolean;
|
|
82
|
+
label?: string;
|
|
83
|
+
force?: boolean;
|
|
84
|
+
commitMessage?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface GitPushResult {
|
|
87
|
+
ok: boolean;
|
|
88
|
+
error?: string;
|
|
89
|
+
state?: string;
|
|
90
|
+
remoteUrl?: string;
|
|
91
|
+
branch?: string;
|
|
92
|
+
sha?: string;
|
|
93
|
+
output?: string;
|
|
94
|
+
webUrl?: string;
|
|
95
|
+
credentialId?: string | null;
|
|
96
|
+
}
|
|
51
97
|
export interface BuilderClient {
|
|
52
98
|
chat: {
|
|
53
99
|
stream(conversationId: string, prompt: string, opts?: {
|
|
@@ -89,6 +135,40 @@ export interface BuilderClient {
|
|
|
89
135
|
}): Promise<string>;
|
|
90
136
|
downloadUrl(conversationId: string): string;
|
|
91
137
|
};
|
|
138
|
+
/** 凭据库(技术方案 14 §2):列表脱敏,永不返回明文 */
|
|
139
|
+
credentials: {
|
|
140
|
+
list(conversationId?: string): Promise<CredentialView[]>;
|
|
141
|
+
save(input: {
|
|
142
|
+
provider: string;
|
|
143
|
+
label: string;
|
|
144
|
+
secret: string;
|
|
145
|
+
scope: 'user' | 'conversation';
|
|
146
|
+
conversationId?: string;
|
|
147
|
+
meta?: Record<string, unknown>;
|
|
148
|
+
}): Promise<CredentialView>;
|
|
149
|
+
remove(id: string): Promise<void>;
|
|
150
|
+
};
|
|
151
|
+
/** 设置库 + 发布动作 */
|
|
152
|
+
deploy: {
|
|
153
|
+
settings(conversationId: string): Promise<DeploySettingView[]>;
|
|
154
|
+
saveSetting(conversationId: string, input: {
|
|
155
|
+
target: string;
|
|
156
|
+
credentialId?: string | null;
|
|
157
|
+
config?: Record<string, unknown>;
|
|
158
|
+
}): Promise<DeploySettingView>;
|
|
159
|
+
/** 推送到用户 Git 仓库;沙箱未运行时 ok=false, error='SANDBOX_NOT_RUNNING' */
|
|
160
|
+
pushGit(conversationId: string, input: GitPushInput): Promise<GitPushResult>;
|
|
161
|
+
};
|
|
162
|
+
export: {
|
|
163
|
+
/**
|
|
164
|
+
* 导出应用源码 ZIP(含 Dockerfile/DEPLOY.md)。沙箱未运行时服务端返回 409 SANDBOX_NOT_RUNNING —— 调用方先 sandbox.wake()。
|
|
165
|
+
* 返回 Blob 与建议文件名(取自 Content-Disposition)
|
|
166
|
+
*/
|
|
167
|
+
zip(conversationId: string): Promise<{
|
|
168
|
+
blob: Blob;
|
|
169
|
+
fileName: string;
|
|
170
|
+
}>;
|
|
171
|
+
};
|
|
92
172
|
}
|
|
93
173
|
export declare function createBuilderClient(options: BuilderClientOptions): BuilderClient;
|
|
94
174
|
export declare class BuilderApiError extends Error {
|
package/dist/client.js
CHANGED
|
@@ -76,6 +76,27 @@ export function createBuilderClient(options) {
|
|
|
76
76
|
read: (id, path, opts) => req(`/${id}/files/read?${qs({ path, ...opts })}`),
|
|
77
77
|
downloadUrl: id => `${restBase}/${id}/files/download`,
|
|
78
78
|
},
|
|
79
|
+
credentials: {
|
|
80
|
+
list: conversationId => req(`/credentials${conversationId ? `?conversationId=${encodeURIComponent(conversationId)}` : ''}`),
|
|
81
|
+
save: input => req('/credentials', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(input) }),
|
|
82
|
+
remove: async (id) => { await req(`/credentials/${id}`, { method: 'DELETE' }); },
|
|
83
|
+
},
|
|
84
|
+
deploy: {
|
|
85
|
+
settings: id => req(`/${id}/deploy-settings`),
|
|
86
|
+
saveSetting: (id, input) => req(`/${id}/deploy-settings`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify(input) }),
|
|
87
|
+
pushGit: (id, input) => req(`/${id}/export/git`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(input) }),
|
|
88
|
+
},
|
|
89
|
+
export: {
|
|
90
|
+
zip: async (id) => {
|
|
91
|
+
const res = await doFetch(`${restBase}/${id}/export/zip`, auth.apply({}));
|
|
92
|
+
if (!res.ok)
|
|
93
|
+
throw new BuilderApiError(res.status, await res.text().catch(() => ''));
|
|
94
|
+
const cd = res.headers.get('content-disposition') ?? '';
|
|
95
|
+
const m = /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i.exec(cd);
|
|
96
|
+
const fileName = m?.[1] ? decodeURIComponent(m[1]) : 'app.zip';
|
|
97
|
+
return { blob: await res.blob(), fileName };
|
|
98
|
+
},
|
|
99
|
+
},
|
|
79
100
|
};
|
|
80
101
|
}
|
|
81
102
|
/**
|
package/dist/parse.test.js
CHANGED
|
@@ -60,3 +60,46 @@ describe('client req envelope unwrap', () => {
|
|
|
60
60
|
await expect(c.sandbox.status('c1')).rejects.toThrow('会话不存在');
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
|
+
describe('client export.zip', () => {
|
|
64
|
+
it('returns blob and filename from content-disposition', async () => {
|
|
65
|
+
const c = createBuilderClient({
|
|
66
|
+
restBase: 'https://api.test/web/Builder',
|
|
67
|
+
auth: new CookieAuth(),
|
|
68
|
+
transport: { stream: async function* () { }, resubscribe: async function* () { }, cancel: async () => { } },
|
|
69
|
+
fetchImpl: (async () => new Response(new Uint8Array([0x50, 0x4b]), {
|
|
70
|
+
status: 200,
|
|
71
|
+
headers: { 'content-type': 'application/zip', 'content-disposition': 'attachment; filename="my-app.zip"' },
|
|
72
|
+
})),
|
|
73
|
+
});
|
|
74
|
+
const r = await c.export.zip('c1');
|
|
75
|
+
expect(r.fileName).toBe('my-app.zip');
|
|
76
|
+
expect(r.blob.size).toBe(2);
|
|
77
|
+
});
|
|
78
|
+
it('throws BuilderApiError 409 when sandbox not running', async () => {
|
|
79
|
+
const c = createBuilderClient({
|
|
80
|
+
restBase: 'https://api.test/web/Builder',
|
|
81
|
+
auth: new CookieAuth(),
|
|
82
|
+
transport: { stream: async function* () { }, resubscribe: async function* () { }, cancel: async () => { } },
|
|
83
|
+
fetchImpl: (async () => new Response('{"error":"SANDBOX_NOT_RUNNING"}', { status: 409 })),
|
|
84
|
+
});
|
|
85
|
+
await expect(c.export.zip('c1')).rejects.toMatchObject({ status: 409 });
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('client credentials/deploy', () => {
|
|
89
|
+
it('posts pushGit body and unwraps envelope', async () => {
|
|
90
|
+
let captured;
|
|
91
|
+
const c = createBuilderClient({
|
|
92
|
+
restBase: 'https://api.test/web/Builder',
|
|
93
|
+
auth: new CookieAuth(),
|
|
94
|
+
transport: { stream: async function* () { }, resubscribe: async function* () { }, cancel: async () => { } },
|
|
95
|
+
fetchImpl: (async (url, init) => {
|
|
96
|
+
captured = { url, init };
|
|
97
|
+
return new Response(JSON.stringify({ code: 0, data: { ok: true, sha: 'abc', branch: 'main' } }), { status: 200, headers: { 'content-type': 'application/json' } });
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
const r = await c.deploy.pushGit('c1', { remoteUrl: 'https://github.com/a/b.git', credentialId: 'cred-1' });
|
|
101
|
+
expect(r.ok).toBe(true);
|
|
102
|
+
expect(captured?.url).toBe('https://api.test/web/Builder/c1/export/git');
|
|
103
|
+
expect(JSON.parse(String(captured?.init?.body))).toMatchObject({ remoteUrl: 'https://github.com/a/b.git', credentialId: 'cred-1' });
|
|
104
|
+
});
|
|
105
|
+
});
|