@lidianai/cli 0.1.3 → 0.1.4
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/package.json +1 -1
- package/src/commands/discover.ts +10 -1
- package/src/lib/output.ts +7 -1
- package/dist/index.js +0 -569
package/package.json
CHANGED
package/src/commands/discover.ts
CHANGED
|
@@ -18,12 +18,21 @@ export interface DiscoverApiResponse {
|
|
|
18
18
|
name: string;
|
|
19
19
|
description: string | null;
|
|
20
20
|
endpointBase: string;
|
|
21
|
-
authType: "none" | "api_key" | "bearer" | "basic" | "oauth2" | "custom";
|
|
22
21
|
defaultCostPerUse: number;
|
|
23
22
|
isActive: boolean;
|
|
23
|
+
requiresClientAuth: boolean;
|
|
24
|
+
paymentModes: Array<"x402" | "prepaid_credits">;
|
|
25
|
+
isExecutable: boolean;
|
|
24
26
|
openapiSpecUrl: string | null;
|
|
25
27
|
createdAt: string;
|
|
26
28
|
updatedAt: string;
|
|
29
|
+
endpoints?: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
path: string;
|
|
32
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
33
|
+
description?: string | null;
|
|
34
|
+
pricingCents: number;
|
|
35
|
+
}>;
|
|
27
36
|
matchScore?: number;
|
|
28
37
|
matchPercent?: number;
|
|
29
38
|
}>;
|
package/src/lib/output.ts
CHANGED
|
@@ -42,9 +42,15 @@ export const printDiscoverResult = (
|
|
|
42
42
|
const confidence = item.matchPercent
|
|
43
43
|
? ` confidence=${item.matchPercent.toFixed(1)}%`
|
|
44
44
|
: "";
|
|
45
|
+
const modes = item.paymentModes.join(",");
|
|
45
46
|
print(
|
|
46
|
-
`- ${item.name} (${item.id})
|
|
47
|
+
`- ${item.name} (${item.id}) cost=${item.defaultCostPerUse}c (${formatUsd(item.defaultCostPerUse)}) executable=${String(item.isExecutable)} requiresClientAuth=${String(item.requiresClientAuth)} paymentModes=${modes}${confidence}`,
|
|
47
48
|
);
|
|
49
|
+
for (const endpoint of item.endpoints ?? []) {
|
|
50
|
+
print(
|
|
51
|
+
` · endpoint=${endpoint.id} ${endpoint.method} ${endpoint.path} cost=${endpoint.pricingCents}c (${formatUsd(endpoint.pricingCents)})`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
48
54
|
}
|
|
49
55
|
};
|
|
50
56
|
|
package/dist/index.js
DELETED
|
@@ -1,569 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
// @bun
|
|
3
|
-
|
|
4
|
-
// src/commands/account.ts
|
|
5
|
-
var runAccountCommand = async (http, apiKey) => {
|
|
6
|
-
return http.get("/v1/account", apiKey);
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
// src/lib/errors.ts
|
|
10
|
-
class CliError extends Error {
|
|
11
|
-
code;
|
|
12
|
-
constructor(message, code = 1) {
|
|
13
|
-
super(message);
|
|
14
|
-
this.name = "CliError";
|
|
15
|
-
this.code = code;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// src/lib/x402.ts
|
|
20
|
-
var requestPaymentRequirements = async (http, apiKey, endpointId, network) => {
|
|
21
|
-
return http.post("/v1/payments/requirements", { endpointId, ...network ? { network } : {} }, apiKey);
|
|
22
|
-
};
|
|
23
|
-
var verifyPaymentAddress = async (http, apiKey, payTo) => {
|
|
24
|
-
return http.post("/v1/payments/verify", { payTo }, apiKey);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// src/commands/consume.ts
|
|
28
|
-
var runConsumeCommand = async (http, apiKey, input) => {
|
|
29
|
-
if (!isUuid(input.endpointId)) {
|
|
30
|
-
throw new CliError("endpointId must be a valid UUID.");
|
|
31
|
-
}
|
|
32
|
-
if (input.paymentRail === "x402") {
|
|
33
|
-
const requirements = await requestPaymentRequirements(http, apiKey, input.endpointId, input.network);
|
|
34
|
-
const verification = await verifyPaymentAddress(http, apiKey, requirements.payTo);
|
|
35
|
-
const execution2 = await http.post("/v1/consume", input, apiKey);
|
|
36
|
-
return {
|
|
37
|
-
execution: execution2,
|
|
38
|
-
payment: {
|
|
39
|
-
requirements,
|
|
40
|
-
verified: verification.valid
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const execution = await http.post("/v1/consume", input, apiKey);
|
|
45
|
-
return { execution };
|
|
46
|
-
};
|
|
47
|
-
var isUuid = (value) => {
|
|
48
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// src/commands/discover.ts
|
|
52
|
-
var runDiscoverCommand = async (http, apiKey, input) => {
|
|
53
|
-
if (input.pageSize < 1 || input.pageSize > 3) {
|
|
54
|
-
throw new CliError("pageSize must be between 1 and 3.");
|
|
55
|
-
}
|
|
56
|
-
const params = new URLSearchParams;
|
|
57
|
-
params.set("q", input.q);
|
|
58
|
-
params.set("page", String(input.page));
|
|
59
|
-
params.set("pageSize", String(input.pageSize));
|
|
60
|
-
if (input.category)
|
|
61
|
-
params.set("category", input.category);
|
|
62
|
-
if (input.authType)
|
|
63
|
-
params.set("authType", input.authType);
|
|
64
|
-
if (typeof input.minPrice === "number") {
|
|
65
|
-
params.set("minPrice", String(input.minPrice));
|
|
66
|
-
}
|
|
67
|
-
if (typeof input.maxPrice === "number") {
|
|
68
|
-
params.set("maxPrice", String(input.maxPrice));
|
|
69
|
-
}
|
|
70
|
-
return http.get(`/v1/discover?${params.toString()}`, apiKey);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// src/commands/feedback.ts
|
|
74
|
-
var runFeedbackCommand = async (http, apiKey, input) => {
|
|
75
|
-
if (!isUuid2(input.executionId)) {
|
|
76
|
-
throw new CliError("executionId must be a valid UUID.");
|
|
77
|
-
}
|
|
78
|
-
if (!Number.isInteger(input.rank) || input.rank < 0 || input.rank > 10) {
|
|
79
|
-
throw new CliError("rank must be an integer between 0 and 10.");
|
|
80
|
-
}
|
|
81
|
-
if (typeof input.feedback === "string" && input.feedback.length > 1000) {
|
|
82
|
-
throw new CliError("feedback cannot exceed 1000 characters.");
|
|
83
|
-
}
|
|
84
|
-
return http.post("/v1/consume/feedback", input, apiKey);
|
|
85
|
-
};
|
|
86
|
-
var isUuid2 = (value) => {
|
|
87
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// src/commands/login.ts
|
|
91
|
-
import { stdin, stdout } from "process";
|
|
92
|
-
import { createInterface } from "readline/promises";
|
|
93
|
-
|
|
94
|
-
// src/lib/config.ts
|
|
95
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
96
|
-
import { homedir } from "os";
|
|
97
|
-
import { dirname, join } from "path";
|
|
98
|
-
var CONFIG_PATH = join(homedir(), ".lidian", "config.json");
|
|
99
|
-
var getConfigPath = () => CONFIG_PATH;
|
|
100
|
-
var readConfig = async () => {
|
|
101
|
-
try {
|
|
102
|
-
const raw = await readFile(CONFIG_PATH, "utf8");
|
|
103
|
-
const parsed = JSON.parse(raw);
|
|
104
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
105
|
-
return {};
|
|
106
|
-
}
|
|
107
|
-
const apiKey = "apiKey" in parsed && typeof parsed.apiKey === "string" ? parsed.apiKey : undefined;
|
|
108
|
-
return { apiKey };
|
|
109
|
-
} catch {
|
|
110
|
-
return {};
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
var writeConfig = async (config) => {
|
|
114
|
-
await mkdir(dirname(CONFIG_PATH), { recursive: true });
|
|
115
|
-
await writeFile(CONFIG_PATH, `${JSON.stringify(config, null, 2)}
|
|
116
|
-
`, "utf8");
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// src/lib/output.ts
|
|
120
|
-
var print = (message) => {
|
|
121
|
-
process.stdout.write(`${message}
|
|
122
|
-
`);
|
|
123
|
-
};
|
|
124
|
-
var printError = (message) => {
|
|
125
|
-
process.stderr.write(`${message}
|
|
126
|
-
`);
|
|
127
|
-
};
|
|
128
|
-
var printResult = (result, asJson) => {
|
|
129
|
-
if (asJson) {
|
|
130
|
-
print(JSON.stringify(result, null, 2));
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
print(formatForHuman(result));
|
|
134
|
-
};
|
|
135
|
-
var printDiscoverResult = (result, asJson) => {
|
|
136
|
-
if (asJson) {
|
|
137
|
-
printResult(result, true);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
if (result.items.length === 0) {
|
|
141
|
-
print("No APIs found.");
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
print(`Found ${result.items.length} of ${result.total} APIs (page ${result.page}).`);
|
|
145
|
-
for (const item of result.items) {
|
|
146
|
-
const confidence = item.matchPercent ? ` confidence=${item.matchPercent.toFixed(1)}%` : "";
|
|
147
|
-
print(`- ${item.name} (${item.id}) auth=${item.authType} cost=${item.defaultCostPerUse}c (${formatUsd(item.defaultCostPerUse)})${confidence}`);
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
var printConsumeResult = (result, asJson) => {
|
|
151
|
-
if (asJson) {
|
|
152
|
-
printResult(result.execution, true);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
if (result.payment) {
|
|
156
|
-
print(`x402 preflight: payTo=${result.payment.requirements.payTo} amount=${result.payment.requirements.amountFormatted} verified=${String(result.payment.verified)}`);
|
|
157
|
-
}
|
|
158
|
-
printExecutionResult(result.execution);
|
|
159
|
-
};
|
|
160
|
-
var printAccountResult = (result, asJson) => {
|
|
161
|
-
if (asJson) {
|
|
162
|
-
printResult(result, true);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
print(`Account: ${result.user.id}`);
|
|
166
|
-
print(`Balance: ${result.balance.balance} cents (${formatUsd(result.balance.balance)})`);
|
|
167
|
-
};
|
|
168
|
-
var printFeedbackResult = (result, asJson) => {
|
|
169
|
-
if (asJson) {
|
|
170
|
-
printResult(result, true);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
const feedback = result.feedback ?? "<none>";
|
|
174
|
-
print(`Feedback saved for execution=${result.executionId} rank=${result.rank} submittedBy=${result.submittedBy}`);
|
|
175
|
-
print(`Updated at: ${result.updatedAt}`);
|
|
176
|
-
print(`Comment: ${feedback}`);
|
|
177
|
-
};
|
|
178
|
-
var printExecutionResult = (result) => {
|
|
179
|
-
print(`Execution ID: ${result.executionId}`);
|
|
180
|
-
print(`Execution succeeded. Spent=${result.credits.spent} cents (${formatUsd(result.credits.spent)}) balance=${result.credits.balance} cents (${formatUsd(result.credits.balance)})`);
|
|
181
|
-
print(JSON.stringify(result.data, null, 2));
|
|
182
|
-
};
|
|
183
|
-
var formatForHuman = (value) => {
|
|
184
|
-
if (typeof value === "string") {
|
|
185
|
-
return value;
|
|
186
|
-
}
|
|
187
|
-
return JSON.stringify(value, null, 2);
|
|
188
|
-
};
|
|
189
|
-
var formatUsd = (cents) => {
|
|
190
|
-
return `$${(cents / 100).toFixed(2)}`;
|
|
191
|
-
};
|
|
192
|
-
var fail = (error) => {
|
|
193
|
-
if (error instanceof CliError) {
|
|
194
|
-
printError(`Error: ${error.message}`);
|
|
195
|
-
process.exit(error.code);
|
|
196
|
-
}
|
|
197
|
-
if (error instanceof Error) {
|
|
198
|
-
printError(`Error: ${error.message}`);
|
|
199
|
-
process.exit(1);
|
|
200
|
-
}
|
|
201
|
-
printError("Error: Unknown failure");
|
|
202
|
-
process.exit(1);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// src/commands/login.ts
|
|
206
|
-
var runLoginCommand = async (input) => {
|
|
207
|
-
const key = input.key ?? await promptForKeyViaBrowserFlow();
|
|
208
|
-
validateApiKey(key);
|
|
209
|
-
const current = await readConfig();
|
|
210
|
-
await writeConfig({
|
|
211
|
-
...current,
|
|
212
|
-
apiKey: key
|
|
213
|
-
});
|
|
214
|
-
return { path: getConfigPath() };
|
|
215
|
-
};
|
|
216
|
-
var promptForKeyViaBrowserFlow = async () => {
|
|
217
|
-
const loginUrl = "https://app.lidian.ai/login?next=/user/api-keys";
|
|
218
|
-
openUrl(loginUrl);
|
|
219
|
-
print(`Open this URL to authenticate and create/copy an API key:
|
|
220
|
-
${loginUrl}`);
|
|
221
|
-
const rl = createInterface({ input: stdin, output: stdout });
|
|
222
|
-
try {
|
|
223
|
-
const entered = (await rl.question("Paste your API key (ld_...): ")).trim();
|
|
224
|
-
if (!entered) {
|
|
225
|
-
throw new CliError("No API key entered.");
|
|
226
|
-
}
|
|
227
|
-
return entered;
|
|
228
|
-
} finally {
|
|
229
|
-
rl.close();
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
var validateApiKey = (key) => {
|
|
233
|
-
if (!key.startsWith("ld_")) {
|
|
234
|
-
throw new CliError("Invalid API key format. Expected key starting with ld_.");
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
var openUrl = (url) => {
|
|
238
|
-
try {
|
|
239
|
-
if (process.platform === "darwin") {
|
|
240
|
-
Bun.spawn(["open", url], { stdout: "ignore", stderr: "ignore" });
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
if (process.platform === "win32") {
|
|
244
|
-
Bun.spawn(["cmd", "/c", "start", "", url], {
|
|
245
|
-
stdout: "ignore",
|
|
246
|
-
stderr: "ignore"
|
|
247
|
-
});
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
Bun.spawn(["xdg-open", url], { stdout: "ignore", stderr: "ignore" });
|
|
251
|
-
} catch {}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
// src/lib/auth.ts
|
|
255
|
-
var resolveApiKey = async (argsApiKey) => {
|
|
256
|
-
const config = await readConfig();
|
|
257
|
-
return argsApiKey ?? process.env.LIDIAN_API_KEY ?? config.apiKey;
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// src/lib/http.ts
|
|
261
|
-
var createHttpClient = (baseUrl) => {
|
|
262
|
-
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
263
|
-
return {
|
|
264
|
-
async get(path, apiKey) {
|
|
265
|
-
const response = await fetch(`${normalizedBaseUrl}${path}`, {
|
|
266
|
-
method: "GET",
|
|
267
|
-
headers: authHeaders(apiKey)
|
|
268
|
-
});
|
|
269
|
-
return handleResponse(response);
|
|
270
|
-
},
|
|
271
|
-
async post(path, body, apiKey) {
|
|
272
|
-
const response = await fetch(`${normalizedBaseUrl}${path}`, {
|
|
273
|
-
method: "POST",
|
|
274
|
-
headers: {
|
|
275
|
-
...authHeaders(apiKey),
|
|
276
|
-
"Content-Type": "application/json"
|
|
277
|
-
},
|
|
278
|
-
body: JSON.stringify(body)
|
|
279
|
-
});
|
|
280
|
-
return handleResponse(response);
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
};
|
|
284
|
-
var authHeaders = (apiKey) => {
|
|
285
|
-
if (!apiKey || apiKey.trim().length === 0) {
|
|
286
|
-
return {};
|
|
287
|
-
}
|
|
288
|
-
return {
|
|
289
|
-
Authorization: `Bearer ${apiKey}`
|
|
290
|
-
};
|
|
291
|
-
};
|
|
292
|
-
var handleResponse = async (response) => {
|
|
293
|
-
const json = await response.json().catch(() => null);
|
|
294
|
-
if (!response.ok) {
|
|
295
|
-
if (json && "success" in json && json.success === false) {
|
|
296
|
-
throw new CliError(`${json.error.code}: ${json.error.message}`, 1);
|
|
297
|
-
}
|
|
298
|
-
if (json && typeof json === "object" && "error" in json && typeof json.error === "string") {
|
|
299
|
-
throw new CliError(json.error, 1);
|
|
300
|
-
}
|
|
301
|
-
if (json && typeof json === "object" && "message" in json && typeof json.message === "string") {
|
|
302
|
-
throw new CliError(json.message, 1);
|
|
303
|
-
}
|
|
304
|
-
throw new CliError(`Request failed with status ${response.status}`, 1);
|
|
305
|
-
}
|
|
306
|
-
if (!json || !("success" in json) || json.success !== true) {
|
|
307
|
-
throw new CliError("Unexpected API response format", 1);
|
|
308
|
-
}
|
|
309
|
-
return json.data;
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
// src/index.ts
|
|
313
|
-
var DEFAULT_API_BASE = "https://api.lidian.ai";
|
|
314
|
-
var API_BASE_BY_ENV = {
|
|
315
|
-
production: "https://api.lidian.ai",
|
|
316
|
-
staging: "https://staging-api.lidian.ai"
|
|
317
|
-
};
|
|
318
|
-
var GLOBAL_OPTIONS = new Set(["api-key", "api-base", "env", "json", "help"]);
|
|
319
|
-
var BOOLEAN_OPTIONS = new Set(["json", "help"]);
|
|
320
|
-
var COMMAND_OPTIONS = {
|
|
321
|
-
discover: new Set([
|
|
322
|
-
"q",
|
|
323
|
-
"page",
|
|
324
|
-
"pageSize",
|
|
325
|
-
"category",
|
|
326
|
-
"auth-type",
|
|
327
|
-
"min-price",
|
|
328
|
-
"max-price"
|
|
329
|
-
]),
|
|
330
|
-
consume: new Set(["endpoint-id", "params", "payment-rail", "network"]),
|
|
331
|
-
feedback: new Set(["execution-id", "rank", "feedback"]),
|
|
332
|
-
account: new Set([]),
|
|
333
|
-
login: new Set(["key"])
|
|
334
|
-
};
|
|
335
|
-
var main = async () => {
|
|
336
|
-
if (process.argv.length <= 2 || process.argv.includes("--help")) {
|
|
337
|
-
printUsage();
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
const parsed = parseArgs(process.argv.slice(2));
|
|
341
|
-
const apiBase = resolveApiBase(asString(parsed.options["api-base"]), asEnvironment(asString(parsed.options.env) ?? process.env.LIDIAN_ENV));
|
|
342
|
-
const asJson = Boolean(parsed.options.json);
|
|
343
|
-
const http = createHttpClient(apiBase);
|
|
344
|
-
switch (parsed.command) {
|
|
345
|
-
case "login": {
|
|
346
|
-
const key = asString(parsed.options.key);
|
|
347
|
-
const result = await runLoginCommand({ key });
|
|
348
|
-
if (asJson) {
|
|
349
|
-
print(JSON.stringify({ success: true, data: result }, null, 2));
|
|
350
|
-
} else {
|
|
351
|
-
print(`Saved API key to ${result.path}`);
|
|
352
|
-
}
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
case "discover": {
|
|
356
|
-
const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
|
|
357
|
-
const qValue = asString(parsed.options.q);
|
|
358
|
-
if (!qValue) {
|
|
359
|
-
throw new CliError("Missing --q for discover command.");
|
|
360
|
-
}
|
|
361
|
-
const page = toInt(asString(parsed.options.page), 1);
|
|
362
|
-
const pageSize = toInt(asString(parsed.options.pageSize), 1);
|
|
363
|
-
const authType = asAuthType(asString(parsed.options["auth-type"]));
|
|
364
|
-
const minPrice = toNumber(asString(parsed.options["min-price"]), "min-price");
|
|
365
|
-
const maxPrice = toNumber(asString(parsed.options["max-price"]), "max-price");
|
|
366
|
-
const result = await runDiscoverCommand(http, apiKey, {
|
|
367
|
-
q: qValue,
|
|
368
|
-
page,
|
|
369
|
-
pageSize,
|
|
370
|
-
category: asString(parsed.options.category),
|
|
371
|
-
...authType ? { authType } : {},
|
|
372
|
-
...typeof minPrice === "number" ? { minPrice } : {},
|
|
373
|
-
...typeof maxPrice === "number" ? { maxPrice } : {}
|
|
374
|
-
});
|
|
375
|
-
printDiscoverResult(result, asJson);
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
case "consume": {
|
|
379
|
-
const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
|
|
380
|
-
const endpointIdValue = asString(parsed.options["endpoint-id"]);
|
|
381
|
-
if (!endpointIdValue) {
|
|
382
|
-
throw new CliError("Missing --endpoint-id for consume command.");
|
|
383
|
-
}
|
|
384
|
-
const paramsRaw = asString(parsed.options.params) ?? "{}";
|
|
385
|
-
const params = parseJsonObject(paramsRaw, "--params");
|
|
386
|
-
const paymentRail = resolvePaymentRail(asString(parsed.options["payment-rail"]), apiKey);
|
|
387
|
-
const network = asNetwork(asString(parsed.options.network));
|
|
388
|
-
const result = await runConsumeCommand(http, apiKey, {
|
|
389
|
-
endpointId: endpointIdValue,
|
|
390
|
-
params,
|
|
391
|
-
paymentRail,
|
|
392
|
-
...network ? { network } : {}
|
|
393
|
-
});
|
|
394
|
-
printConsumeResult(result, asJson);
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
case "account": {
|
|
398
|
-
const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
|
|
399
|
-
const result = await runAccountCommand(http, apiKey);
|
|
400
|
-
printAccountResult(result, asJson);
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
case "feedback": {
|
|
404
|
-
const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
|
|
405
|
-
const executionId = asString(parsed.options["execution-id"]);
|
|
406
|
-
if (!executionId) {
|
|
407
|
-
throw new CliError("Missing --execution-id for feedback command.");
|
|
408
|
-
}
|
|
409
|
-
const rankRaw = asString(parsed.options.rank);
|
|
410
|
-
if (!rankRaw) {
|
|
411
|
-
throw new CliError("Missing --rank for feedback command.");
|
|
412
|
-
}
|
|
413
|
-
const rank = toIntInRange(rankRaw, "rank", 0, 10);
|
|
414
|
-
const feedback = asString(parsed.options.feedback);
|
|
415
|
-
const result = await runFeedbackCommand(http, apiKey, {
|
|
416
|
-
executionId,
|
|
417
|
-
rank,
|
|
418
|
-
...feedback ? { feedback } : {}
|
|
419
|
-
});
|
|
420
|
-
printFeedbackResult(result, asJson);
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
default:
|
|
424
|
-
throw new CliError("Unknown command.", 1);
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
var parseArgs = (argv) => {
|
|
428
|
-
const command = argv[0];
|
|
429
|
-
if (command !== "discover" && command !== "consume" && command !== "feedback" && command !== "account" && command !== "login") {
|
|
430
|
-
printUsage();
|
|
431
|
-
throw new CliError("Invalid command. Use one of: login, discover, consume, feedback, account.", 1);
|
|
432
|
-
}
|
|
433
|
-
const options = {};
|
|
434
|
-
let index = 1;
|
|
435
|
-
while (index < argv.length) {
|
|
436
|
-
const token = argv[index];
|
|
437
|
-
if (!token || !token.startsWith("--")) {
|
|
438
|
-
throw new CliError(`Unexpected argument: ${token ?? "<empty>"}`);
|
|
439
|
-
}
|
|
440
|
-
const key = token.slice(2);
|
|
441
|
-
const allowedForCommand = COMMAND_OPTIONS[command];
|
|
442
|
-
if (!GLOBAL_OPTIONS.has(key) && !allowedForCommand.has(key)) {
|
|
443
|
-
throw new CliError(`Unknown option for ${command}: --${key}`);
|
|
444
|
-
}
|
|
445
|
-
const next = argv[index + 1];
|
|
446
|
-
if (!next || next.startsWith("--")) {
|
|
447
|
-
if (!BOOLEAN_OPTIONS.has(key)) {
|
|
448
|
-
throw new CliError(`Missing value for --${key}`);
|
|
449
|
-
}
|
|
450
|
-
options[key] = true;
|
|
451
|
-
index += 1;
|
|
452
|
-
continue;
|
|
453
|
-
}
|
|
454
|
-
options[key] = next;
|
|
455
|
-
index += 2;
|
|
456
|
-
}
|
|
457
|
-
return {
|
|
458
|
-
command,
|
|
459
|
-
options
|
|
460
|
-
};
|
|
461
|
-
};
|
|
462
|
-
var printUsage = () => {
|
|
463
|
-
print("Usage:");
|
|
464
|
-
print(" lidian login [--key ld_...] [--json]");
|
|
465
|
-
print(' lidian discover --q "<term>" [--page 1] [--pageSize 1..3] [--category <name>] [--auth-type none|api_key|bearer|basic|oauth2|custom]');
|
|
466
|
-
print(" [--min-price <cents>] [--max-price <cents>] [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]");
|
|
467
|
-
print(" lidian consume --endpoint-id <uuid> --params '<json>' [--payment-rail prepaid_credits|x402] [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]");
|
|
468
|
-
print(" [--network base|ethereum]");
|
|
469
|
-
print(' lidian feedback --execution-id <uuid> --rank <0..10> [--feedback "<text>"] [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]');
|
|
470
|
-
print(" lidian account [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]");
|
|
471
|
-
print("");
|
|
472
|
-
print("Env resolution:");
|
|
473
|
-
print(" --api-base > LIDIAN_API_BASE > --env > LIDIAN_ENV > production");
|
|
474
|
-
print(` production=${API_BASE_BY_ENV.production}`);
|
|
475
|
-
print(` staging=${API_BASE_BY_ENV.staging}`);
|
|
476
|
-
};
|
|
477
|
-
var asString = (value) => {
|
|
478
|
-
if (typeof value === "string")
|
|
479
|
-
return value;
|
|
480
|
-
return;
|
|
481
|
-
};
|
|
482
|
-
var toInt = (value, fallback) => {
|
|
483
|
-
if (!value)
|
|
484
|
-
return fallback;
|
|
485
|
-
const parsed = Number.parseInt(value, 10);
|
|
486
|
-
if (Number.isNaN(parsed) || parsed < 1) {
|
|
487
|
-
throw new CliError(`Invalid integer value: ${value}`);
|
|
488
|
-
}
|
|
489
|
-
return parsed;
|
|
490
|
-
};
|
|
491
|
-
var toIntInRange = (value, flagName, min, max) => {
|
|
492
|
-
const parsed = Number.parseInt(value, 10);
|
|
493
|
-
if (Number.isNaN(parsed) || String(parsed) !== value || parsed < min || parsed > max) {
|
|
494
|
-
throw new CliError(`Invalid --${flagName} value: ${value}. Expected integer ${min}..${max}.`);
|
|
495
|
-
}
|
|
496
|
-
return parsed;
|
|
497
|
-
};
|
|
498
|
-
var toNumber = (value, flagName) => {
|
|
499
|
-
if (!value)
|
|
500
|
-
return;
|
|
501
|
-
const parsed = Number(value);
|
|
502
|
-
if (Number.isNaN(parsed)) {
|
|
503
|
-
throw new CliError(`Invalid --${flagName} value: ${value}`);
|
|
504
|
-
}
|
|
505
|
-
return parsed;
|
|
506
|
-
};
|
|
507
|
-
var parseJsonObject = (value, flagName) => {
|
|
508
|
-
let parsed;
|
|
509
|
-
try {
|
|
510
|
-
parsed = JSON.parse(value);
|
|
511
|
-
} catch {
|
|
512
|
-
throw new CliError(`${flagName} must be valid JSON.`);
|
|
513
|
-
}
|
|
514
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
515
|
-
throw new CliError(`${flagName} must be a JSON object.`);
|
|
516
|
-
}
|
|
517
|
-
return parsed;
|
|
518
|
-
};
|
|
519
|
-
var asPaymentRail = (value) => {
|
|
520
|
-
if (value === "prepaid_credits" || value === "x402")
|
|
521
|
-
return value;
|
|
522
|
-
throw new CliError("Invalid --payment-rail. Use prepaid_credits or x402.");
|
|
523
|
-
};
|
|
524
|
-
var resolvePaymentRail = (value, apiKey) => {
|
|
525
|
-
if (value) {
|
|
526
|
-
return asPaymentRail(value);
|
|
527
|
-
}
|
|
528
|
-
return apiKey && apiKey.trim().length > 0 ? "prepaid_credits" : "x402";
|
|
529
|
-
};
|
|
530
|
-
var asAuthType = (value) => {
|
|
531
|
-
if (!value)
|
|
532
|
-
return;
|
|
533
|
-
const valid = new Set([
|
|
534
|
-
"none",
|
|
535
|
-
"api_key",
|
|
536
|
-
"bearer",
|
|
537
|
-
"basic",
|
|
538
|
-
"oauth2",
|
|
539
|
-
"custom"
|
|
540
|
-
]);
|
|
541
|
-
if (valid.has(value)) {
|
|
542
|
-
return value;
|
|
543
|
-
}
|
|
544
|
-
throw new CliError("Invalid --auth-type. Use none, api_key, bearer, basic, oauth2, or custom.");
|
|
545
|
-
};
|
|
546
|
-
var asNetwork = (value) => {
|
|
547
|
-
if (!value)
|
|
548
|
-
return;
|
|
549
|
-
if (value === "base" || value === "ethereum")
|
|
550
|
-
return value;
|
|
551
|
-
throw new CliError("Invalid --network. Use base or ethereum.");
|
|
552
|
-
};
|
|
553
|
-
var asEnvironment = (value) => {
|
|
554
|
-
if (!value)
|
|
555
|
-
return;
|
|
556
|
-
if (value === "production" || value === "staging")
|
|
557
|
-
return value;
|
|
558
|
-
throw new CliError("Invalid --env. Use production or staging.");
|
|
559
|
-
};
|
|
560
|
-
var resolveApiBase = (cliApiBase, environment) => {
|
|
561
|
-
if (cliApiBase)
|
|
562
|
-
return cliApiBase;
|
|
563
|
-
if (process.env.LIDIAN_API_BASE)
|
|
564
|
-
return process.env.LIDIAN_API_BASE;
|
|
565
|
-
if (environment)
|
|
566
|
-
return API_BASE_BY_ENV[environment];
|
|
567
|
-
return DEFAULT_API_BASE;
|
|
568
|
-
};
|
|
569
|
-
main().catch(fail);
|