@ricsam/r5d-api 0.0.1 → 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 +66 -43
- package/dist/cjs/index.cjs +257 -0
- package/dist/cjs/package.json +5 -0
- package/dist/mjs/index.mjs +232 -0
- package/dist/mjs/package.json +5 -0
- package/dist/types/index.d.ts +211 -0
- package/package.json +28 -7
package/README.md
CHANGED
|
@@ -1,45 +1,68 @@
|
|
|
1
1
|
# @ricsam/r5d-api
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
3
|
+
Typed Node.js API client for the r5d.dev CLI backend surface.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ricsam/r5d-api
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { BinctlClient } from "@ricsam/r5d-api";
|
|
15
|
+
|
|
16
|
+
const client = new BinctlClient({
|
|
17
|
+
baseUrl: "https://r5d.dev",
|
|
18
|
+
token: process.env.BINCTL_TOKEN,
|
|
19
|
+
// or apiKey: process.env.BINCTL_API_KEY
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const projects = await client.projects.list();
|
|
23
|
+
console.log(projects);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Auth
|
|
27
|
+
|
|
28
|
+
`BinctlClient` supports:
|
|
29
|
+
- interactive token (`bin_tok_*`)
|
|
30
|
+
- API key (`bin_key_*`)
|
|
31
|
+
|
|
32
|
+
Set either `token` or `apiKey` in client options, or later via:
|
|
33
|
+
- `client.setToken(...)`
|
|
34
|
+
- `client.setApiKey(...)`
|
|
35
|
+
|
|
36
|
+
Trusted server-side callers that authenticate through custom headers, such as a session cookie, can pass `headers` with `authMode: "headers"`.
|
|
37
|
+
|
|
38
|
+
## Main API Surface
|
|
39
|
+
|
|
40
|
+
- `auth.loginStart()`
|
|
41
|
+
- `auth.loginPoll(requestId, { pollCode })`
|
|
42
|
+
- `auth.status()`
|
|
43
|
+
- `auth.logout()`
|
|
44
|
+
- `auth.apiKeys.create/list/revoke`
|
|
45
|
+
- `projects.list()`
|
|
46
|
+
- `projects.create({ name?, orgId? })`
|
|
47
|
+
- `projects.describe(projectRef)`
|
|
48
|
+
- `projects.update(projectRef, { name?, mode? })`
|
|
49
|
+
- `projects.delete(projectRef)`
|
|
50
|
+
- `projects.branches.list/describe(projectRef, ...)`
|
|
51
|
+
- `projects.sessions.list(projectRef, { branch? })`
|
|
52
|
+
- `projects.sessions.create(projectRef, { branchName, name? })`
|
|
53
|
+
- `sessions.describe(sessionId)`
|
|
54
|
+
- `sessions.update(sessionId, { name })`
|
|
55
|
+
- `sessions.delete(sessionId)`
|
|
56
|
+
- `sessions.conversation(sessionId)`
|
|
57
|
+
- `sessions.prompt(sessionId, { message, mode, model })`
|
|
58
|
+
- `sessions.answerQuestions(sessionId, { answers })`
|
|
59
|
+
- `sessions.applyRequiredEnvs(sessionId, { envs })`
|
|
60
|
+
|
|
61
|
+
## Errors
|
|
62
|
+
|
|
63
|
+
Non-2xx responses throw `BinctlApiError` with:
|
|
64
|
+
- `status`
|
|
65
|
+
- `path`
|
|
66
|
+
- `body`
|
|
67
|
+
|
|
68
|
+
Project responses expose `mode: "greenfield" | "prod"`, derived from the database-backed `projects.backwardsCompatible` flag.
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
21
|
+
BinctlApiError: () => BinctlApiError,
|
|
22
|
+
BinctlClient: () => BinctlClient
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
|
+
class BinctlApiError extends Error {
|
|
26
|
+
status;
|
|
27
|
+
path;
|
|
28
|
+
body;
|
|
29
|
+
constructor(message, input) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "BinctlApiError";
|
|
32
|
+
this.status = input.status;
|
|
33
|
+
this.path = input.path;
|
|
34
|
+
this.body = input.body;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function normalizeBaseUrl(url) {
|
|
38
|
+
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
39
|
+
}
|
|
40
|
+
function withQuery(path, query) {
|
|
41
|
+
if (!query) {
|
|
42
|
+
return path;
|
|
43
|
+
}
|
|
44
|
+
const params = new URLSearchParams();
|
|
45
|
+
for (const [key, value] of Object.entries(query)) {
|
|
46
|
+
if (value === void 0) continue;
|
|
47
|
+
params.set(key, value);
|
|
48
|
+
}
|
|
49
|
+
const queryString = params.toString();
|
|
50
|
+
return queryString.length > 0 ? `${path}?${queryString}` : path;
|
|
51
|
+
}
|
|
52
|
+
class BinctlClient {
|
|
53
|
+
fetchImpl;
|
|
54
|
+
baseUrl;
|
|
55
|
+
token;
|
|
56
|
+
apiKey;
|
|
57
|
+
extraHeaders;
|
|
58
|
+
authMode;
|
|
59
|
+
constructor(options = {}) {
|
|
60
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
61
|
+
this.baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://r5d.dev");
|
|
62
|
+
this.token = options.token;
|
|
63
|
+
this.apiKey = options.apiKey;
|
|
64
|
+
this.extraHeaders = options.headers ?? {};
|
|
65
|
+
this.authMode = options.authMode ?? "bearer";
|
|
66
|
+
}
|
|
67
|
+
setBaseUrl(baseUrl) {
|
|
68
|
+
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
69
|
+
}
|
|
70
|
+
setToken(token) {
|
|
71
|
+
this.token = token;
|
|
72
|
+
}
|
|
73
|
+
setApiKey(apiKey) {
|
|
74
|
+
this.apiKey = apiKey;
|
|
75
|
+
}
|
|
76
|
+
resolveBearerToken() {
|
|
77
|
+
return this.token ?? this.apiKey;
|
|
78
|
+
}
|
|
79
|
+
async request(input) {
|
|
80
|
+
const authMode = input.auth ?? "auto";
|
|
81
|
+
const bearerToken = this.resolveBearerToken();
|
|
82
|
+
const headers = {
|
|
83
|
+
...this.extraHeaders,
|
|
84
|
+
Accept: "application/json"
|
|
85
|
+
};
|
|
86
|
+
if (authMode === "auto") {
|
|
87
|
+
if (!bearerToken) {
|
|
88
|
+
if (this.authMode !== "headers") {
|
|
89
|
+
throw new BinctlApiError("Authentication required. Set token or apiKey in BinctlClient.", {
|
|
90
|
+
status: 401,
|
|
91
|
+
path: input.path,
|
|
92
|
+
body: { error: "Missing credentials" }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
headers.Authorization = `Bearer ${bearerToken}`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const hasBody = input.body !== void 0;
|
|
100
|
+
if (hasBody) {
|
|
101
|
+
headers["Content-Type"] = "application/json";
|
|
102
|
+
}
|
|
103
|
+
const pathWithQuery = withQuery(input.path, input.query);
|
|
104
|
+
const response = await this.fetchImpl(`${this.baseUrl}${pathWithQuery}`, {
|
|
105
|
+
method: input.method,
|
|
106
|
+
headers,
|
|
107
|
+
body: hasBody ? JSON.stringify(input.body) : void 0
|
|
108
|
+
});
|
|
109
|
+
const text = await response.text();
|
|
110
|
+
const payload = text.length > 0 ? safeJsonParse(text) : null;
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
const message = typeof payload === "object" && payload && "error" in payload && typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
|
|
113
|
+
throw new BinctlApiError(message, {
|
|
114
|
+
status: response.status,
|
|
115
|
+
path: pathWithQuery,
|
|
116
|
+
body: payload
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return payload;
|
|
120
|
+
}
|
|
121
|
+
auth = {
|
|
122
|
+
loginStart: (input) => this.request({
|
|
123
|
+
method: "POST",
|
|
124
|
+
path: "/api/binctl/auth/login/start",
|
|
125
|
+
auth: "none",
|
|
126
|
+
body: {
|
|
127
|
+
baseUrl: input?.baseUrl
|
|
128
|
+
}
|
|
129
|
+
}),
|
|
130
|
+
loginPoll: (requestId, input) => this.request({
|
|
131
|
+
method: "GET",
|
|
132
|
+
path: `/api/binctl/auth/login/poll/${encodeURIComponent(requestId)}`,
|
|
133
|
+
auth: "none",
|
|
134
|
+
query: {
|
|
135
|
+
pollCode: input.pollCode
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
logout: () => this.request({
|
|
139
|
+
method: "POST",
|
|
140
|
+
path: "/api/binctl/auth/logout",
|
|
141
|
+
body: {}
|
|
142
|
+
}),
|
|
143
|
+
status: () => this.request({
|
|
144
|
+
method: "GET",
|
|
145
|
+
path: "/api/binctl/auth/status"
|
|
146
|
+
}),
|
|
147
|
+
apiKeys: {
|
|
148
|
+
create: (input) => this.request({
|
|
149
|
+
method: "POST",
|
|
150
|
+
path: "/api/binctl/auth/api-keys",
|
|
151
|
+
body: input
|
|
152
|
+
}),
|
|
153
|
+
list: () => this.request({
|
|
154
|
+
method: "GET",
|
|
155
|
+
path: "/api/binctl/auth/api-keys"
|
|
156
|
+
}),
|
|
157
|
+
revoke: (keyId) => this.request({
|
|
158
|
+
method: "DELETE",
|
|
159
|
+
path: `/api/binctl/auth/api-keys/${encodeURIComponent(keyId)}`
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
projects = {
|
|
164
|
+
list: () => this.request({
|
|
165
|
+
method: "GET",
|
|
166
|
+
path: "/api/binctl/projects"
|
|
167
|
+
}),
|
|
168
|
+
create: (input = {}) => this.request({
|
|
169
|
+
method: "POST",
|
|
170
|
+
path: "/api/binctl/projects",
|
|
171
|
+
body: input
|
|
172
|
+
}),
|
|
173
|
+
describe: (projectRef) => this.request({
|
|
174
|
+
method: "GET",
|
|
175
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}`
|
|
176
|
+
}),
|
|
177
|
+
update: (projectRef, input) => this.request({
|
|
178
|
+
method: "PUT",
|
|
179
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}`,
|
|
180
|
+
body: input
|
|
181
|
+
}),
|
|
182
|
+
delete: (projectRef) => this.request({
|
|
183
|
+
method: "DELETE",
|
|
184
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}`
|
|
185
|
+
}),
|
|
186
|
+
branches: {
|
|
187
|
+
list: (projectRef) => this.request({
|
|
188
|
+
method: "GET",
|
|
189
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/branches`
|
|
190
|
+
}),
|
|
191
|
+
describe: (projectRef, branch) => this.request({
|
|
192
|
+
method: "GET",
|
|
193
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/branches/${encodeURIComponent(branch)}`
|
|
194
|
+
})
|
|
195
|
+
},
|
|
196
|
+
sessions: {
|
|
197
|
+
list: (projectRef, input) => this.request({
|
|
198
|
+
method: "GET",
|
|
199
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/sessions`,
|
|
200
|
+
query: {
|
|
201
|
+
branch: input?.branch
|
|
202
|
+
}
|
|
203
|
+
}),
|
|
204
|
+
create: (projectRef, input) => this.request({
|
|
205
|
+
method: "POST",
|
|
206
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/sessions`,
|
|
207
|
+
body: input
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
sessions = {
|
|
212
|
+
describe: (sessionId) => this.request({
|
|
213
|
+
method: "GET",
|
|
214
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}`
|
|
215
|
+
}),
|
|
216
|
+
update: (sessionId, input) => this.request({
|
|
217
|
+
method: "PUT",
|
|
218
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}`,
|
|
219
|
+
body: input
|
|
220
|
+
}),
|
|
221
|
+
delete: (sessionId) => this.request({
|
|
222
|
+
method: "DELETE",
|
|
223
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}`
|
|
224
|
+
}),
|
|
225
|
+
conversation: (sessionId) => this.request({
|
|
226
|
+
method: "GET",
|
|
227
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/conversation`
|
|
228
|
+
}),
|
|
229
|
+
prompt: (sessionId, input) => this.request({
|
|
230
|
+
method: "POST",
|
|
231
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/prompt`,
|
|
232
|
+
body: input
|
|
233
|
+
}),
|
|
234
|
+
answerQuestions: (sessionId, input) => this.request({
|
|
235
|
+
method: "POST",
|
|
236
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/answer-questions`,
|
|
237
|
+
body: input
|
|
238
|
+
}),
|
|
239
|
+
applyRequiredEnvs: (sessionId, input) => this.request({
|
|
240
|
+
method: "POST",
|
|
241
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/apply-required-envs`,
|
|
242
|
+
body: input
|
|
243
|
+
})
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function safeJsonParse(text) {
|
|
247
|
+
try {
|
|
248
|
+
return JSON.parse(text);
|
|
249
|
+
} catch {
|
|
250
|
+
return { raw: text };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
254
|
+
0 && (module.exports = {
|
|
255
|
+
BinctlApiError,
|
|
256
|
+
BinctlClient
|
|
257
|
+
});
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
class BinctlApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
path;
|
|
4
|
+
body;
|
|
5
|
+
constructor(message, input) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "BinctlApiError";
|
|
8
|
+
this.status = input.status;
|
|
9
|
+
this.path = input.path;
|
|
10
|
+
this.body = input.body;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function normalizeBaseUrl(url) {
|
|
14
|
+
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
15
|
+
}
|
|
16
|
+
function withQuery(path, query) {
|
|
17
|
+
if (!query) {
|
|
18
|
+
return path;
|
|
19
|
+
}
|
|
20
|
+
const params = new URLSearchParams();
|
|
21
|
+
for (const [key, value] of Object.entries(query)) {
|
|
22
|
+
if (value === void 0) continue;
|
|
23
|
+
params.set(key, value);
|
|
24
|
+
}
|
|
25
|
+
const queryString = params.toString();
|
|
26
|
+
return queryString.length > 0 ? `${path}?${queryString}` : path;
|
|
27
|
+
}
|
|
28
|
+
class BinctlClient {
|
|
29
|
+
fetchImpl;
|
|
30
|
+
baseUrl;
|
|
31
|
+
token;
|
|
32
|
+
apiKey;
|
|
33
|
+
extraHeaders;
|
|
34
|
+
authMode;
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
37
|
+
this.baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://r5d.dev");
|
|
38
|
+
this.token = options.token;
|
|
39
|
+
this.apiKey = options.apiKey;
|
|
40
|
+
this.extraHeaders = options.headers ?? {};
|
|
41
|
+
this.authMode = options.authMode ?? "bearer";
|
|
42
|
+
}
|
|
43
|
+
setBaseUrl(baseUrl) {
|
|
44
|
+
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
45
|
+
}
|
|
46
|
+
setToken(token) {
|
|
47
|
+
this.token = token;
|
|
48
|
+
}
|
|
49
|
+
setApiKey(apiKey) {
|
|
50
|
+
this.apiKey = apiKey;
|
|
51
|
+
}
|
|
52
|
+
resolveBearerToken() {
|
|
53
|
+
return this.token ?? this.apiKey;
|
|
54
|
+
}
|
|
55
|
+
async request(input) {
|
|
56
|
+
const authMode = input.auth ?? "auto";
|
|
57
|
+
const bearerToken = this.resolveBearerToken();
|
|
58
|
+
const headers = {
|
|
59
|
+
...this.extraHeaders,
|
|
60
|
+
Accept: "application/json"
|
|
61
|
+
};
|
|
62
|
+
if (authMode === "auto") {
|
|
63
|
+
if (!bearerToken) {
|
|
64
|
+
if (this.authMode !== "headers") {
|
|
65
|
+
throw new BinctlApiError("Authentication required. Set token or apiKey in BinctlClient.", {
|
|
66
|
+
status: 401,
|
|
67
|
+
path: input.path,
|
|
68
|
+
body: { error: "Missing credentials" }
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
headers.Authorization = `Bearer ${bearerToken}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const hasBody = input.body !== void 0;
|
|
76
|
+
if (hasBody) {
|
|
77
|
+
headers["Content-Type"] = "application/json";
|
|
78
|
+
}
|
|
79
|
+
const pathWithQuery = withQuery(input.path, input.query);
|
|
80
|
+
const response = await this.fetchImpl(`${this.baseUrl}${pathWithQuery}`, {
|
|
81
|
+
method: input.method,
|
|
82
|
+
headers,
|
|
83
|
+
body: hasBody ? JSON.stringify(input.body) : void 0
|
|
84
|
+
});
|
|
85
|
+
const text = await response.text();
|
|
86
|
+
const payload = text.length > 0 ? safeJsonParse(text) : null;
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const message = typeof payload === "object" && payload && "error" in payload && typeof payload.error === "string" ? payload.error : `Request failed (${response.status})`;
|
|
89
|
+
throw new BinctlApiError(message, {
|
|
90
|
+
status: response.status,
|
|
91
|
+
path: pathWithQuery,
|
|
92
|
+
body: payload
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return payload;
|
|
96
|
+
}
|
|
97
|
+
auth = {
|
|
98
|
+
loginStart: (input) => this.request({
|
|
99
|
+
method: "POST",
|
|
100
|
+
path: "/api/binctl/auth/login/start",
|
|
101
|
+
auth: "none",
|
|
102
|
+
body: {
|
|
103
|
+
baseUrl: input?.baseUrl
|
|
104
|
+
}
|
|
105
|
+
}),
|
|
106
|
+
loginPoll: (requestId, input) => this.request({
|
|
107
|
+
method: "GET",
|
|
108
|
+
path: `/api/binctl/auth/login/poll/${encodeURIComponent(requestId)}`,
|
|
109
|
+
auth: "none",
|
|
110
|
+
query: {
|
|
111
|
+
pollCode: input.pollCode
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
logout: () => this.request({
|
|
115
|
+
method: "POST",
|
|
116
|
+
path: "/api/binctl/auth/logout",
|
|
117
|
+
body: {}
|
|
118
|
+
}),
|
|
119
|
+
status: () => this.request({
|
|
120
|
+
method: "GET",
|
|
121
|
+
path: "/api/binctl/auth/status"
|
|
122
|
+
}),
|
|
123
|
+
apiKeys: {
|
|
124
|
+
create: (input) => this.request({
|
|
125
|
+
method: "POST",
|
|
126
|
+
path: "/api/binctl/auth/api-keys",
|
|
127
|
+
body: input
|
|
128
|
+
}),
|
|
129
|
+
list: () => this.request({
|
|
130
|
+
method: "GET",
|
|
131
|
+
path: "/api/binctl/auth/api-keys"
|
|
132
|
+
}),
|
|
133
|
+
revoke: (keyId) => this.request({
|
|
134
|
+
method: "DELETE",
|
|
135
|
+
path: `/api/binctl/auth/api-keys/${encodeURIComponent(keyId)}`
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
projects = {
|
|
140
|
+
list: () => this.request({
|
|
141
|
+
method: "GET",
|
|
142
|
+
path: "/api/binctl/projects"
|
|
143
|
+
}),
|
|
144
|
+
create: (input = {}) => this.request({
|
|
145
|
+
method: "POST",
|
|
146
|
+
path: "/api/binctl/projects",
|
|
147
|
+
body: input
|
|
148
|
+
}),
|
|
149
|
+
describe: (projectRef) => this.request({
|
|
150
|
+
method: "GET",
|
|
151
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}`
|
|
152
|
+
}),
|
|
153
|
+
update: (projectRef, input) => this.request({
|
|
154
|
+
method: "PUT",
|
|
155
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}`,
|
|
156
|
+
body: input
|
|
157
|
+
}),
|
|
158
|
+
delete: (projectRef) => this.request({
|
|
159
|
+
method: "DELETE",
|
|
160
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}`
|
|
161
|
+
}),
|
|
162
|
+
branches: {
|
|
163
|
+
list: (projectRef) => this.request({
|
|
164
|
+
method: "GET",
|
|
165
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/branches`
|
|
166
|
+
}),
|
|
167
|
+
describe: (projectRef, branch) => this.request({
|
|
168
|
+
method: "GET",
|
|
169
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/branches/${encodeURIComponent(branch)}`
|
|
170
|
+
})
|
|
171
|
+
},
|
|
172
|
+
sessions: {
|
|
173
|
+
list: (projectRef, input) => this.request({
|
|
174
|
+
method: "GET",
|
|
175
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/sessions`,
|
|
176
|
+
query: {
|
|
177
|
+
branch: input?.branch
|
|
178
|
+
}
|
|
179
|
+
}),
|
|
180
|
+
create: (projectRef, input) => this.request({
|
|
181
|
+
method: "POST",
|
|
182
|
+
path: `/api/binctl/projects/${encodeURIComponent(projectRef)}/sessions`,
|
|
183
|
+
body: input
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
sessions = {
|
|
188
|
+
describe: (sessionId) => this.request({
|
|
189
|
+
method: "GET",
|
|
190
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}`
|
|
191
|
+
}),
|
|
192
|
+
update: (sessionId, input) => this.request({
|
|
193
|
+
method: "PUT",
|
|
194
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}`,
|
|
195
|
+
body: input
|
|
196
|
+
}),
|
|
197
|
+
delete: (sessionId) => this.request({
|
|
198
|
+
method: "DELETE",
|
|
199
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}`
|
|
200
|
+
}),
|
|
201
|
+
conversation: (sessionId) => this.request({
|
|
202
|
+
method: "GET",
|
|
203
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/conversation`
|
|
204
|
+
}),
|
|
205
|
+
prompt: (sessionId, input) => this.request({
|
|
206
|
+
method: "POST",
|
|
207
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/prompt`,
|
|
208
|
+
body: input
|
|
209
|
+
}),
|
|
210
|
+
answerQuestions: (sessionId, input) => this.request({
|
|
211
|
+
method: "POST",
|
|
212
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/answer-questions`,
|
|
213
|
+
body: input
|
|
214
|
+
}),
|
|
215
|
+
applyRequiredEnvs: (sessionId, input) => this.request({
|
|
216
|
+
method: "POST",
|
|
217
|
+
path: `/api/binctl/sessions/${encodeURIComponent(sessionId)}/apply-required-envs`,
|
|
218
|
+
body: input
|
|
219
|
+
})
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function safeJsonParse(text) {
|
|
223
|
+
try {
|
|
224
|
+
return JSON.parse(text);
|
|
225
|
+
} catch {
|
|
226
|
+
return { raw: text };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
BinctlApiError,
|
|
231
|
+
BinctlClient
|
|
232
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
export type ChatMode = "ask" | "plan" | "build" | "agent" | "explore" | "review" | "test" | "research";
|
|
2
|
+
export type ModelTier = "low" | "medium" | "high" | "max";
|
|
3
|
+
export type BinctlProject = {
|
|
4
|
+
id: string;
|
|
5
|
+
slug: string | null;
|
|
6
|
+
name: string | null;
|
|
7
|
+
mode: "greenfield" | "prod";
|
|
8
|
+
createdAt: string;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
};
|
|
11
|
+
export type BinctlProjectDescription = BinctlProject & {
|
|
12
|
+
orgId: string | null;
|
|
13
|
+
};
|
|
14
|
+
export type BinctlBranch = {
|
|
15
|
+
branchName: string;
|
|
16
|
+
sessionCount: number;
|
|
17
|
+
lastSessionAt: string | null;
|
|
18
|
+
};
|
|
19
|
+
export type BinctlSessionSummary = {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string | null;
|
|
22
|
+
branchName: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
};
|
|
26
|
+
export type BinctlSessionDescription = {
|
|
27
|
+
id: string;
|
|
28
|
+
projectId: string;
|
|
29
|
+
projectSlug: string | null;
|
|
30
|
+
projectName: string | null;
|
|
31
|
+
branchName: string;
|
|
32
|
+
name: string | null;
|
|
33
|
+
fixedMode?: ChatMode | null;
|
|
34
|
+
fixedTier?: ModelTier | null;
|
|
35
|
+
createdAt: string;
|
|
36
|
+
updatedAt: string;
|
|
37
|
+
};
|
|
38
|
+
export type BinctlPendingQuestionOption = {
|
|
39
|
+
id: string;
|
|
40
|
+
label: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
};
|
|
43
|
+
export type BinctlPendingQuestion = {
|
|
44
|
+
id: string;
|
|
45
|
+
question: string;
|
|
46
|
+
allowMultiple?: boolean;
|
|
47
|
+
options: BinctlPendingQuestionOption[];
|
|
48
|
+
};
|
|
49
|
+
export type BinctlRequiredEnv = {
|
|
50
|
+
target: "backend" | "frontend";
|
|
51
|
+
name: string;
|
|
52
|
+
optional: boolean;
|
|
53
|
+
generateScript?: string;
|
|
54
|
+
description: string;
|
|
55
|
+
};
|
|
56
|
+
export type BinctlConversationResponse = {
|
|
57
|
+
session: BinctlSessionDescription;
|
|
58
|
+
conversation: unknown;
|
|
59
|
+
thread: unknown[];
|
|
60
|
+
pendingQuestions: BinctlPendingQuestion[];
|
|
61
|
+
requiredEnvs: BinctlRequiredEnv[];
|
|
62
|
+
};
|
|
63
|
+
export type BinctlLoginStartResponse = {
|
|
64
|
+
requestId: string;
|
|
65
|
+
pollCode: string;
|
|
66
|
+
loginUrl: string;
|
|
67
|
+
expiresAt: string;
|
|
68
|
+
intervalMs: number;
|
|
69
|
+
};
|
|
70
|
+
export type BinctlLoginPollResponse = {
|
|
71
|
+
status: "pending";
|
|
72
|
+
expiresAt: string;
|
|
73
|
+
intervalMs: number;
|
|
74
|
+
} | {
|
|
75
|
+
status: "approved";
|
|
76
|
+
token: string;
|
|
77
|
+
credentialId: string;
|
|
78
|
+
} | {
|
|
79
|
+
status: "expired" | "consumed";
|
|
80
|
+
};
|
|
81
|
+
export type BinctlAuthStatusResponse = {
|
|
82
|
+
authenticated: true;
|
|
83
|
+
source: "session" | "binctl";
|
|
84
|
+
user: {
|
|
85
|
+
id: string;
|
|
86
|
+
email: string;
|
|
87
|
+
name: string | null;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
export type BinctlApiKey = {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
lastUsedAt: string | null;
|
|
95
|
+
};
|
|
96
|
+
export type BinctlProjectCreateInput = {
|
|
97
|
+
name?: string;
|
|
98
|
+
orgId?: string;
|
|
99
|
+
};
|
|
100
|
+
export type BinctlProjectUpdateInput = {
|
|
101
|
+
name?: string;
|
|
102
|
+
mode?: "greenfield" | "prod";
|
|
103
|
+
};
|
|
104
|
+
export type BinctlSessionCreateInput = {
|
|
105
|
+
name?: string;
|
|
106
|
+
branchName: string;
|
|
107
|
+
};
|
|
108
|
+
export type BinctlSessionUpdateInput = {
|
|
109
|
+
name: string | null;
|
|
110
|
+
};
|
|
111
|
+
export type BinctlClientOptions = {
|
|
112
|
+
baseUrl?: string;
|
|
113
|
+
token?: string;
|
|
114
|
+
apiKey?: string;
|
|
115
|
+
fetch?: typeof fetch;
|
|
116
|
+
headers?: Record<string, string>;
|
|
117
|
+
authMode?: "bearer" | "headers";
|
|
118
|
+
};
|
|
119
|
+
export declare class BinctlApiError extends Error {
|
|
120
|
+
readonly status: number;
|
|
121
|
+
readonly path: string;
|
|
122
|
+
readonly body: unknown;
|
|
123
|
+
constructor(message: string, input: {
|
|
124
|
+
status: number;
|
|
125
|
+
path: string;
|
|
126
|
+
body: unknown;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
export declare class BinctlClient {
|
|
130
|
+
private readonly fetchImpl;
|
|
131
|
+
private baseUrl;
|
|
132
|
+
private token?;
|
|
133
|
+
private apiKey?;
|
|
134
|
+
private readonly extraHeaders;
|
|
135
|
+
private readonly authMode;
|
|
136
|
+
constructor(options?: BinctlClientOptions);
|
|
137
|
+
setBaseUrl(baseUrl: string): void;
|
|
138
|
+
setToken(token?: string): void;
|
|
139
|
+
setApiKey(apiKey?: string): void;
|
|
140
|
+
private resolveBearerToken;
|
|
141
|
+
private request;
|
|
142
|
+
readonly auth: {
|
|
143
|
+
loginStart: (input?: {
|
|
144
|
+
baseUrl?: string;
|
|
145
|
+
}) => Promise<BinctlLoginStartResponse>;
|
|
146
|
+
loginPoll: (requestId: string, input: {
|
|
147
|
+
pollCode: string;
|
|
148
|
+
}) => Promise<BinctlLoginPollResponse>;
|
|
149
|
+
logout: () => Promise<{
|
|
150
|
+
success: boolean;
|
|
151
|
+
revokedCredential: boolean;
|
|
152
|
+
}>;
|
|
153
|
+
status: () => Promise<BinctlAuthStatusResponse>;
|
|
154
|
+
apiKeys: {
|
|
155
|
+
create: (input: {
|
|
156
|
+
name: string;
|
|
157
|
+
}) => Promise<{
|
|
158
|
+
id: string;
|
|
159
|
+
apiKey: string;
|
|
160
|
+
name: string;
|
|
161
|
+
createdAt: string;
|
|
162
|
+
}>;
|
|
163
|
+
list: () => Promise<BinctlApiKey[]>;
|
|
164
|
+
revoke: (keyId: string) => Promise<{
|
|
165
|
+
success: boolean;
|
|
166
|
+
}>;
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
readonly projects: {
|
|
170
|
+
list: () => Promise<BinctlProject[]>;
|
|
171
|
+
create: (input?: BinctlProjectCreateInput) => Promise<BinctlProjectDescription>;
|
|
172
|
+
describe: (projectRef: string) => Promise<BinctlProjectDescription>;
|
|
173
|
+
update: (projectRef: string, input: BinctlProjectUpdateInput) => Promise<BinctlProjectDescription>;
|
|
174
|
+
delete: (projectRef: string) => Promise<{
|
|
175
|
+
success: boolean;
|
|
176
|
+
}>;
|
|
177
|
+
branches: {
|
|
178
|
+
list: (projectRef: string) => Promise<BinctlBranch[]>;
|
|
179
|
+
describe: (projectRef: string, branch: string) => Promise<{
|
|
180
|
+
project: BinctlProject;
|
|
181
|
+
branchName: string;
|
|
182
|
+
sessions: BinctlSessionSummary[];
|
|
183
|
+
}>;
|
|
184
|
+
};
|
|
185
|
+
sessions: {
|
|
186
|
+
list: (projectRef: string, input?: {
|
|
187
|
+
branch?: string;
|
|
188
|
+
}) => Promise<BinctlSessionSummary[]>;
|
|
189
|
+
create: (projectRef: string, input: BinctlSessionCreateInput) => Promise<BinctlSessionDescription>;
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
readonly sessions: {
|
|
193
|
+
describe: (sessionId: string) => Promise<BinctlSessionDescription>;
|
|
194
|
+
update: (sessionId: string, input: BinctlSessionUpdateInput) => Promise<BinctlSessionDescription>;
|
|
195
|
+
delete: (sessionId: string) => Promise<{
|
|
196
|
+
success: boolean;
|
|
197
|
+
}>;
|
|
198
|
+
conversation: (sessionId: string) => Promise<BinctlConversationResponse>;
|
|
199
|
+
prompt: (sessionId: string, input: {
|
|
200
|
+
message: string;
|
|
201
|
+
mode: ChatMode;
|
|
202
|
+
model: ModelTier;
|
|
203
|
+
}) => Promise<BinctlConversationResponse>;
|
|
204
|
+
answerQuestions: (sessionId: string, input: {
|
|
205
|
+
answers: string[];
|
|
206
|
+
}) => Promise<BinctlConversationResponse>;
|
|
207
|
+
applyRequiredEnvs: (sessionId: string, input: {
|
|
208
|
+
envs: string[];
|
|
209
|
+
}) => Promise<BinctlConversationResponse>;
|
|
210
|
+
};
|
|
211
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/r5d-api",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/cjs/index.cjs",
|
|
6
|
+
"module": "./dist/mjs/index.mjs",
|
|
7
|
+
"types": "./dist/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"import": "./dist/mjs/index.mjs",
|
|
12
|
+
"require": "./dist/cjs/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/ricsam/r5d-dev.git",
|
|
18
|
+
"directory": "binctl-packages/binctl-api"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false
|
|
10
31
|
}
|