@lidianai/cli 0.1.2 → 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/README.md CHANGED
@@ -43,6 +43,10 @@ When `--payment-rail x402` is used, CLI performs:
43
43
  Submit feedback later:
44
44
  4. `POST /v1/consume/feedback` with `executionId`, `rank`, optional `feedback`
45
45
 
46
+ Default payment rail behavior when `--payment-rail` is omitted:
47
+ - with API key/token: `prepaid_credits`
48
+ - without auth: `x402`
49
+
46
50
  ## Dev
47
51
 
48
52
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lidianai/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -17,7 +17,7 @@ export interface AccountApiResponse {
17
17
 
18
18
  export const runAccountCommand = async (
19
19
  http: HttpClient,
20
- apiKey: string,
20
+ apiKey: string | undefined,
21
21
  ): Promise<AccountApiResponse> => {
22
22
  return http.get<AccountApiResponse>("/v1/account", apiKey);
23
23
  };
@@ -34,7 +34,7 @@ export interface ConsumeCommandResult {
34
34
 
35
35
  export const runConsumeCommand = async (
36
36
  http: HttpClient,
37
- apiKey: string,
37
+ apiKey: string | undefined,
38
38
  input: ConsumeCommandInput,
39
39
  ): Promise<ConsumeCommandResult> => {
40
40
  if (!isUuid(input.endpointId)) {
@@ -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
  }>;
@@ -34,7 +43,7 @@ export interface DiscoverApiResponse {
34
43
 
35
44
  export const runDiscoverCommand = async (
36
45
  http: HttpClient,
37
- apiKey: string,
46
+ apiKey: string | undefined,
38
47
  input: DiscoverCommandInput,
39
48
  ): Promise<DiscoverApiResponse> => {
40
49
  if (input.pageSize < 1 || input.pageSize > 3) {
@@ -17,7 +17,7 @@ export interface FeedbackApiResponse {
17
17
 
18
18
  export const runFeedbackCommand = async (
19
19
  http: HttpClient,
20
- apiKey: string,
20
+ apiKey: string | undefined,
21
21
  input: FeedbackCommandInput,
22
22
  ): Promise<FeedbackApiResponse> => {
23
23
  if (!isUuid(input.executionId)) {
package/src/index.ts CHANGED
@@ -108,8 +108,9 @@ const main = async (): Promise<void> => {
108
108
  }
109
109
  const paramsRaw = asString(parsed.options.params) ?? "{}";
110
110
  const params = parseJsonObject(paramsRaw, "--params");
111
- const paymentRail = asPaymentRail(
112
- asString(parsed.options["payment-rail"]) ?? "prepaid_credits",
111
+ const paymentRail = resolvePaymentRail(
112
+ asString(parsed.options["payment-rail"]),
113
+ apiKey,
113
114
  );
114
115
  const network = asNetwork(asString(parsed.options.network));
115
116
  const result = await runConsumeCommand(http, apiKey, {
@@ -294,6 +295,16 @@ const asPaymentRail = (value: string): PaymentRail => {
294
295
  throw new CliError("Invalid --payment-rail. Use prepaid_credits or x402.");
295
296
  };
296
297
 
298
+ const resolvePaymentRail = (
299
+ value: string | undefined,
300
+ apiKey: string | undefined,
301
+ ): PaymentRail => {
302
+ if (value) {
303
+ return asPaymentRail(value);
304
+ }
305
+ return apiKey && apiKey.trim().length > 0 ? "prepaid_credits" : "x402";
306
+ };
307
+
297
308
  const asAuthType = (
298
309
  value: string | undefined,
299
310
  ):
package/src/lib/auth.ts CHANGED
@@ -1,15 +1,8 @@
1
1
  import { readConfig } from "@/lib/config";
2
- import { CliError } from "@/lib/errors";
3
2
 
4
3
  export const resolveApiKey = async (
5
4
  argsApiKey: string | undefined,
6
- ): Promise<string> => {
5
+ ): Promise<string | undefined> => {
7
6
  const config = await readConfig();
8
- const key = argsApiKey ?? process.env.LIDIAN_API_KEY ?? config.apiKey;
9
- if (!key) {
10
- throw new CliError(
11
- "Missing API key. Use `lidian login --key ld_...`, pass --api-key, or set LIDIAN_API_KEY.",
12
- );
13
- }
14
- return key;
7
+ return argsApiKey ?? process.env.LIDIAN_API_KEY ?? config.apiKey;
15
8
  };
package/src/lib/http.ts CHANGED
@@ -13,25 +13,30 @@ export interface ApiFailure {
13
13
  };
14
14
  }
15
15
 
16
- type ApiResponse<T> = ApiSuccess<T> | ApiFailure;
16
+ interface PlainApiError {
17
+ error?: string;
18
+ message?: string;
19
+ }
20
+
21
+ type ApiResponse<T> = ApiSuccess<T> | ApiFailure | PlainApiError;
17
22
 
18
23
  export interface HttpClient {
19
- get<T>(path: string, apiKey: string): Promise<T>;
20
- post<T, B>(path: string, body: B, apiKey: string): Promise<T>;
24
+ get<T>(path: string, apiKey?: string): Promise<T>;
25
+ post<T, B>(path: string, body: B, apiKey?: string): Promise<T>;
21
26
  }
22
27
 
23
28
  export const createHttpClient = (baseUrl: string): HttpClient => {
24
29
  const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
25
30
 
26
31
  return {
27
- async get<T>(path: string, apiKey: string): Promise<T> {
32
+ async get<T>(path: string, apiKey?: string): Promise<T> {
28
33
  const response = await fetch(`${normalizedBaseUrl}${path}`, {
29
34
  method: "GET",
30
35
  headers: authHeaders(apiKey),
31
36
  });
32
37
  return handleResponse<T>(response);
33
38
  },
34
- async post<T, B>(path: string, body: B, apiKey: string): Promise<T> {
39
+ async post<T, B>(path: string, body: B, apiKey?: string): Promise<T> {
35
40
  const response = await fetch(`${normalizedBaseUrl}${path}`, {
36
41
  method: "POST",
37
42
  headers: {
@@ -45,9 +50,14 @@ export const createHttpClient = (baseUrl: string): HttpClient => {
45
50
  };
46
51
  };
47
52
 
48
- const authHeaders = (apiKey: string): HeadersInit => ({
49
- Authorization: `Bearer ${apiKey}`,
50
- });
53
+ const authHeaders = (apiKey?: string): HeadersInit => {
54
+ if (!apiKey || apiKey.trim().length === 0) {
55
+ return {};
56
+ }
57
+ return {
58
+ Authorization: `Bearer ${apiKey}`,
59
+ };
60
+ };
51
61
 
52
62
  const handleResponse = async <T>(response: Response): Promise<T> => {
53
63
  const json = (await response
@@ -58,6 +68,22 @@ const handleResponse = async <T>(response: Response): Promise<T> => {
58
68
  if (json && "success" in json && json.success === false) {
59
69
  throw new CliError(`${json.error.code}: ${json.error.message}`, 1);
60
70
  }
71
+ if (
72
+ json &&
73
+ typeof json === "object" &&
74
+ "error" in json &&
75
+ typeof json.error === "string"
76
+ ) {
77
+ throw new CliError(json.error, 1);
78
+ }
79
+ if (
80
+ json &&
81
+ typeof json === "object" &&
82
+ "message" in json &&
83
+ typeof json.message === "string"
84
+ ) {
85
+ throw new CliError(json.message, 1);
86
+ }
61
87
  throw new CliError(`Request failed with status ${response.status}`, 1);
62
88
  }
63
89
 
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}) auth=${item.authType} cost=${item.defaultCostPerUse}c (${formatUsd(item.defaultCostPerUse)})${confidence}`,
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/src/lib/x402.ts CHANGED
@@ -27,7 +27,7 @@ export interface PaymentVerifyResponse {
27
27
 
28
28
  export const requestPaymentRequirements = async (
29
29
  http: HttpClient,
30
- apiKey: string,
30
+ apiKey: string | undefined,
31
31
  endpointId: string,
32
32
  network?: string,
33
33
  ): Promise<PaymentRequirementsResponse> => {
@@ -43,7 +43,7 @@ export const requestPaymentRequirements = async (
43
43
 
44
44
  export const verifyPaymentAddress = async (
45
45
  http: HttpClient,
46
- apiKey: string,
46
+ apiKey: string | undefined,
47
47
  payTo: string,
48
48
  ): Promise<PaymentVerifyResponse> => {
49
49
  return http.post<PaymentVerifyResponse, { payTo: string }>(
package/dist/index.js DELETED
@@ -1,556 +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
- const key = argsApiKey ?? process.env.LIDIAN_API_KEY ?? config.apiKey;
258
- if (!key) {
259
- throw new CliError("Missing API key. Use `lidian login --key ld_...`, pass --api-key, or set LIDIAN_API_KEY.");
260
- }
261
- return key;
262
- };
263
-
264
- // src/lib/http.ts
265
- var createHttpClient = (baseUrl) => {
266
- const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
267
- return {
268
- async get(path, apiKey) {
269
- const response = await fetch(`${normalizedBaseUrl}${path}`, {
270
- method: "GET",
271
- headers: authHeaders(apiKey)
272
- });
273
- return handleResponse(response);
274
- },
275
- async post(path, body, apiKey) {
276
- const response = await fetch(`${normalizedBaseUrl}${path}`, {
277
- method: "POST",
278
- headers: {
279
- ...authHeaders(apiKey),
280
- "Content-Type": "application/json"
281
- },
282
- body: JSON.stringify(body)
283
- });
284
- return handleResponse(response);
285
- }
286
- };
287
- };
288
- var authHeaders = (apiKey) => ({
289
- Authorization: `Bearer ${apiKey}`
290
- });
291
- var handleResponse = async (response) => {
292
- const json = await response.json().catch(() => null);
293
- if (!response.ok) {
294
- if (json && "success" in json && json.success === false) {
295
- throw new CliError(`${json.error.code}: ${json.error.message}`, 1);
296
- }
297
- throw new CliError(`Request failed with status ${response.status}`, 1);
298
- }
299
- if (!json || !("success" in json) || json.success !== true) {
300
- throw new CliError("Unexpected API response format", 1);
301
- }
302
- return json.data;
303
- };
304
-
305
- // src/index.ts
306
- var DEFAULT_API_BASE = "https://api.lidian.ai";
307
- var API_BASE_BY_ENV = {
308
- production: "https://api.lidian.ai",
309
- staging: "https://staging-api.lidian.ai"
310
- };
311
- var GLOBAL_OPTIONS = new Set(["api-key", "api-base", "env", "json", "help"]);
312
- var BOOLEAN_OPTIONS = new Set(["json", "help"]);
313
- var COMMAND_OPTIONS = {
314
- discover: new Set([
315
- "q",
316
- "page",
317
- "pageSize",
318
- "category",
319
- "auth-type",
320
- "min-price",
321
- "max-price"
322
- ]),
323
- consume: new Set(["endpoint-id", "params", "payment-rail", "network"]),
324
- feedback: new Set(["execution-id", "rank", "feedback"]),
325
- account: new Set([]),
326
- login: new Set(["key"])
327
- };
328
- var main = async () => {
329
- if (process.argv.length <= 2 || process.argv.includes("--help")) {
330
- printUsage();
331
- return;
332
- }
333
- const parsed = parseArgs(process.argv.slice(2));
334
- const apiBase = resolveApiBase(asString(parsed.options["api-base"]), asEnvironment(asString(parsed.options.env) ?? process.env.LIDIAN_ENV));
335
- const asJson = Boolean(parsed.options.json);
336
- const http = createHttpClient(apiBase);
337
- switch (parsed.command) {
338
- case "login": {
339
- const key = asString(parsed.options.key);
340
- const result = await runLoginCommand({ key });
341
- if (asJson) {
342
- print(JSON.stringify({ success: true, data: result }, null, 2));
343
- } else {
344
- print(`Saved API key to ${result.path}`);
345
- }
346
- return;
347
- }
348
- case "discover": {
349
- const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
350
- const qValue = asString(parsed.options.q);
351
- if (!qValue) {
352
- throw new CliError("Missing --q for discover command.");
353
- }
354
- const page = toInt(asString(parsed.options.page), 1);
355
- const pageSize = toInt(asString(parsed.options.pageSize), 1);
356
- const authType = asAuthType(asString(parsed.options["auth-type"]));
357
- const minPrice = toNumber(asString(parsed.options["min-price"]), "min-price");
358
- const maxPrice = toNumber(asString(parsed.options["max-price"]), "max-price");
359
- const result = await runDiscoverCommand(http, apiKey, {
360
- q: qValue,
361
- page,
362
- pageSize,
363
- category: asString(parsed.options.category),
364
- ...authType ? { authType } : {},
365
- ...typeof minPrice === "number" ? { minPrice } : {},
366
- ...typeof maxPrice === "number" ? { maxPrice } : {}
367
- });
368
- printDiscoverResult(result, asJson);
369
- return;
370
- }
371
- case "consume": {
372
- const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
373
- const endpointIdValue = asString(parsed.options["endpoint-id"]);
374
- if (!endpointIdValue) {
375
- throw new CliError("Missing --endpoint-id for consume command.");
376
- }
377
- const paramsRaw = asString(parsed.options.params) ?? "{}";
378
- const params = parseJsonObject(paramsRaw, "--params");
379
- const paymentRail = asPaymentRail(asString(parsed.options["payment-rail"]) ?? "prepaid_credits");
380
- const network = asNetwork(asString(parsed.options.network));
381
- const result = await runConsumeCommand(http, apiKey, {
382
- endpointId: endpointIdValue,
383
- params,
384
- paymentRail,
385
- ...network ? { network } : {}
386
- });
387
- printConsumeResult(result, asJson);
388
- return;
389
- }
390
- case "account": {
391
- const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
392
- const result = await runAccountCommand(http, apiKey);
393
- printAccountResult(result, asJson);
394
- return;
395
- }
396
- case "feedback": {
397
- const apiKey = await resolveApiKey(asString(parsed.options["api-key"]));
398
- const executionId = asString(parsed.options["execution-id"]);
399
- if (!executionId) {
400
- throw new CliError("Missing --execution-id for feedback command.");
401
- }
402
- const rankRaw = asString(parsed.options.rank);
403
- if (!rankRaw) {
404
- throw new CliError("Missing --rank for feedback command.");
405
- }
406
- const rank = toIntInRange(rankRaw, "rank", 0, 10);
407
- const feedback = asString(parsed.options.feedback);
408
- const result = await runFeedbackCommand(http, apiKey, {
409
- executionId,
410
- rank,
411
- ...feedback ? { feedback } : {}
412
- });
413
- printFeedbackResult(result, asJson);
414
- return;
415
- }
416
- default:
417
- throw new CliError("Unknown command.", 1);
418
- }
419
- };
420
- var parseArgs = (argv) => {
421
- const command = argv[0];
422
- if (command !== "discover" && command !== "consume" && command !== "feedback" && command !== "account" && command !== "login") {
423
- printUsage();
424
- throw new CliError("Invalid command. Use one of: login, discover, consume, feedback, account.", 1);
425
- }
426
- const options = {};
427
- let index = 1;
428
- while (index < argv.length) {
429
- const token = argv[index];
430
- if (!token || !token.startsWith("--")) {
431
- throw new CliError(`Unexpected argument: ${token ?? "<empty>"}`);
432
- }
433
- const key = token.slice(2);
434
- const allowedForCommand = COMMAND_OPTIONS[command];
435
- if (!GLOBAL_OPTIONS.has(key) && !allowedForCommand.has(key)) {
436
- throw new CliError(`Unknown option for ${command}: --${key}`);
437
- }
438
- const next = argv[index + 1];
439
- if (!next || next.startsWith("--")) {
440
- if (!BOOLEAN_OPTIONS.has(key)) {
441
- throw new CliError(`Missing value for --${key}`);
442
- }
443
- options[key] = true;
444
- index += 1;
445
- continue;
446
- }
447
- options[key] = next;
448
- index += 2;
449
- }
450
- return {
451
- command,
452
- options
453
- };
454
- };
455
- var printUsage = () => {
456
- print("Usage:");
457
- print(" lidian login [--key ld_...] [--json]");
458
- print(' lidian discover --q "<term>" [--page 1] [--pageSize 1..3] [--category <name>] [--auth-type none|api_key|bearer|basic|oauth2|custom]');
459
- print(" [--min-price <cents>] [--max-price <cents>] [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]");
460
- print(" lidian consume --endpoint-id <uuid> --params '<json>' [--payment-rail prepaid_credits|x402] [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]");
461
- print(" [--network base|ethereum]");
462
- print(' lidian feedback --execution-id <uuid> --rank <0..10> [--feedback "<text>"] [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]');
463
- print(" lidian account [--api-key <key>] [--env production|staging] [--api-base <url>] [--json]");
464
- print("");
465
- print("Env resolution:");
466
- print(" --api-base > LIDIAN_API_BASE > --env > LIDIAN_ENV > production");
467
- print(` production=${API_BASE_BY_ENV.production}`);
468
- print(` staging=${API_BASE_BY_ENV.staging}`);
469
- };
470
- var asString = (value) => {
471
- if (typeof value === "string")
472
- return value;
473
- return;
474
- };
475
- var toInt = (value, fallback) => {
476
- if (!value)
477
- return fallback;
478
- const parsed = Number.parseInt(value, 10);
479
- if (Number.isNaN(parsed) || parsed < 1) {
480
- throw new CliError(`Invalid integer value: ${value}`);
481
- }
482
- return parsed;
483
- };
484
- var toIntInRange = (value, flagName, min, max) => {
485
- const parsed = Number.parseInt(value, 10);
486
- if (Number.isNaN(parsed) || String(parsed) !== value || parsed < min || parsed > max) {
487
- throw new CliError(`Invalid --${flagName} value: ${value}. Expected integer ${min}..${max}.`);
488
- }
489
- return parsed;
490
- };
491
- var toNumber = (value, flagName) => {
492
- if (!value)
493
- return;
494
- const parsed = Number(value);
495
- if (Number.isNaN(parsed)) {
496
- throw new CliError(`Invalid --${flagName} value: ${value}`);
497
- }
498
- return parsed;
499
- };
500
- var parseJsonObject = (value, flagName) => {
501
- let parsed;
502
- try {
503
- parsed = JSON.parse(value);
504
- } catch {
505
- throw new CliError(`${flagName} must be valid JSON.`);
506
- }
507
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
508
- throw new CliError(`${flagName} must be a JSON object.`);
509
- }
510
- return parsed;
511
- };
512
- var asPaymentRail = (value) => {
513
- if (value === "prepaid_credits" || value === "x402")
514
- return value;
515
- throw new CliError("Invalid --payment-rail. Use prepaid_credits or x402.");
516
- };
517
- var asAuthType = (value) => {
518
- if (!value)
519
- return;
520
- const valid = new Set([
521
- "none",
522
- "api_key",
523
- "bearer",
524
- "basic",
525
- "oauth2",
526
- "custom"
527
- ]);
528
- if (valid.has(value)) {
529
- return value;
530
- }
531
- throw new CliError("Invalid --auth-type. Use none, api_key, bearer, basic, oauth2, or custom.");
532
- };
533
- var asNetwork = (value) => {
534
- if (!value)
535
- return;
536
- if (value === "base" || value === "ethereum")
537
- return value;
538
- throw new CliError("Invalid --network. Use base or ethereum.");
539
- };
540
- var asEnvironment = (value) => {
541
- if (!value)
542
- return;
543
- if (value === "production" || value === "staging")
544
- return value;
545
- throw new CliError("Invalid --env. Use production or staging.");
546
- };
547
- var resolveApiBase = (cliApiBase, environment) => {
548
- if (cliApiBase)
549
- return cliApiBase;
550
- if (process.env.LIDIAN_API_BASE)
551
- return process.env.LIDIAN_API_BASE;
552
- if (environment)
553
- return API_BASE_BY_ENV[environment];
554
- return DEFAULT_API_BASE;
555
- };
556
- main().catch(fail);