xapi-to 0.1.11 → 0.1.13
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 +5 -0
- package/package.json +1 -1
- package/src/client.ts +2 -1
- package/src/codegen.ts +9 -8
- package/src/commands/action.ts +11 -7
- package/src/commands/config.ts +19 -0
- package/src/commands/register.ts +30 -12
- package/src/index.ts +14 -2
package/README.md
CHANGED
|
@@ -21,6 +21,9 @@ cd xapi-cli && bun install
|
|
|
21
21
|
# 1. Register a new account (apiKey saved automatically)
|
|
22
22
|
xapi register
|
|
23
23
|
|
|
24
|
+
# 1b. Or register with an inviter's referral code (please replace xapito to your referral code)
|
|
25
|
+
xapi register --referral-code xapito
|
|
26
|
+
|
|
24
27
|
# 2. Or set an existing key
|
|
25
28
|
xapi config set apiKey=sk-xxx
|
|
26
29
|
|
|
@@ -76,6 +79,8 @@ xapi oauth providers # list available providers
|
|
|
76
79
|
|
|
77
80
|
```bash
|
|
78
81
|
xapi register # create account, saves apiKey automatically
|
|
82
|
+
xapi register --referral-code xapito # register with an inviter's referral code (please replace xapito to your referral code)
|
|
83
|
+
xapi register xapito # positional shorthand for --referral-code
|
|
79
84
|
xapi balance # show USD balance
|
|
80
85
|
xapi topup # generate payment URL
|
|
81
86
|
xapi topup --method stripe --amount 10 # stripe, $10
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -124,13 +124,14 @@ export async function actionCall(
|
|
|
124
124
|
actionId: string,
|
|
125
125
|
input: Record<string, unknown>,
|
|
126
126
|
opts: ClientOptions,
|
|
127
|
+
httpMethod?: string,
|
|
127
128
|
) {
|
|
128
129
|
return request<unknown>(
|
|
129
130
|
`${baseUrl(opts)}/v1/actions/execute`,
|
|
130
131
|
{
|
|
131
132
|
method: 'POST',
|
|
132
133
|
headers: headers(opts.apiKey),
|
|
133
|
-
body: JSON.stringify({ action_id: actionId, input }),
|
|
134
|
+
body: JSON.stringify({ action_id: actionId, ...(httpMethod ? { method: httpMethod } : {}), input }),
|
|
134
135
|
},
|
|
135
136
|
EXECUTE_TIMEOUT_MS,
|
|
136
137
|
);
|
package/src/codegen.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface CodegenParams {
|
|
|
13
13
|
actionId: string;
|
|
14
14
|
input: Record<string, unknown>;
|
|
15
15
|
actionHost: string;
|
|
16
|
+
method?: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
interface ResolvedTarget {
|
|
@@ -109,8 +110,8 @@ function baseUrl(actionHost: string): string {
|
|
|
109
110
|
return `${scheme(actionHost)}://${actionHost}/v1/actions/execute`;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
function jsonBody(actionId: string, input: Record<string, unknown
|
|
113
|
-
return JSON.stringify({ action_id: actionId, input }, null, 2);
|
|
113
|
+
function jsonBody(actionId: string, input: Record<string, unknown>, method?: string): string {
|
|
114
|
+
return JSON.stringify({ action_id: actionId, ...(method ? { method } : {}), input }, null, 2);
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/** Re-indent a multi-line string so continuation lines are aligned */
|
|
@@ -127,7 +128,7 @@ function shellEscape(s: string): string {
|
|
|
127
128
|
|
|
128
129
|
function genCurl(params: CodegenParams): string {
|
|
129
130
|
const url = baseUrl(params.actionHost);
|
|
130
|
-
const body = jsonBody(params.actionId, params.input);
|
|
131
|
+
const body = jsonBody(params.actionId, params.input, params.method);
|
|
131
132
|
return [
|
|
132
133
|
'# Set XAPI_KEY env var or replace with your key',
|
|
133
134
|
`curl -X POST '${shellEscape(url)}' \\`,
|
|
@@ -139,7 +140,7 @@ function genCurl(params: CodegenParams): string {
|
|
|
139
140
|
|
|
140
141
|
function genPython(lib: 'requests' | 'httpx', params: CodegenParams): string {
|
|
141
142
|
const url = baseUrl(params.actionHost);
|
|
142
|
-
const payload = { action_id: params.actionId, input: params.input };
|
|
143
|
+
const payload = { action_id: params.actionId, ...(params.method ? { method: params.method } : {}), input: params.input };
|
|
143
144
|
return [
|
|
144
145
|
`# pip install ${lib}`,
|
|
145
146
|
'# Set XAPI_KEY env var or replace with your key',
|
|
@@ -160,7 +161,7 @@ function genPython(lib: 'requests' | 'httpx', params: CodegenParams): string {
|
|
|
160
161
|
|
|
161
162
|
function genJavaScriptFetch(params: CodegenParams): string {
|
|
162
163
|
const url = baseUrl(params.actionHost);
|
|
163
|
-
const body = jsonBody(params.actionId, params.input);
|
|
164
|
+
const body = jsonBody(params.actionId, params.input, params.method);
|
|
164
165
|
return [
|
|
165
166
|
'// Set XAPI_KEY env var or replace with your key',
|
|
166
167
|
`const resp = await fetch("${url}", {`,
|
|
@@ -177,7 +178,7 @@ function genJavaScriptFetch(params: CodegenParams): string {
|
|
|
177
178
|
|
|
178
179
|
function genJavaScriptAxios(params: CodegenParams): string {
|
|
179
180
|
const url = baseUrl(params.actionHost);
|
|
180
|
-
const body = jsonBody(params.actionId, params.input);
|
|
181
|
+
const body = jsonBody(params.actionId, params.input, params.method);
|
|
181
182
|
return [
|
|
182
183
|
'// npm install axios',
|
|
183
184
|
'// Set XAPI_KEY env var or replace with your key',
|
|
@@ -199,7 +200,7 @@ function genJavaScriptAxios(params: CodegenParams): string {
|
|
|
199
200
|
|
|
200
201
|
function genTypescriptFetch(params: CodegenParams): string {
|
|
201
202
|
const url = baseUrl(params.actionHost);
|
|
202
|
-
const body = jsonBody(params.actionId, params.input);
|
|
203
|
+
const body = jsonBody(params.actionId, params.input, params.method);
|
|
203
204
|
return [
|
|
204
205
|
'// Set XAPI_KEY env var or replace with your key',
|
|
205
206
|
`const resp: Response = await fetch("${url}", {`,
|
|
@@ -217,7 +218,7 @@ function genTypescriptFetch(params: CodegenParams): string {
|
|
|
217
218
|
|
|
218
219
|
function genGo(params: CodegenParams): string {
|
|
219
220
|
const url = baseUrl(params.actionHost);
|
|
220
|
-
const body = jsonBody(params.actionId, params.input);
|
|
221
|
+
const body = jsonBody(params.actionId, params.input, params.method);
|
|
221
222
|
const escaped = body.replace(/`/g, '` + "`" + `');
|
|
222
223
|
return [
|
|
223
224
|
'// Set XAPI_KEY env var or replace with your key',
|
package/src/commands/action.ts
CHANGED
|
@@ -278,8 +278,8 @@ export async function actionGet(args: string[], flags: Record<string, string>) {
|
|
|
278
278
|
);
|
|
279
279
|
}
|
|
280
280
|
const action = filtered[0] as any;
|
|
281
|
-
const
|
|
282
|
-
const result = generateCode(flags.code, { actionId: id, input, actionHost: cfg.actionHost });
|
|
281
|
+
const { method: _schemaMethod, ...cleanCodeInput } = buildDefaultInput(action.input ?? {});
|
|
282
|
+
const result = generateCode(flags.code, { actionId: id, input: cleanCodeInput, actionHost: cfg.actionHost, method: action.method });
|
|
283
283
|
outputCode(result, flags);
|
|
284
284
|
return;
|
|
285
285
|
}
|
|
@@ -303,20 +303,24 @@ export async function actionCall(args: string[], flags: Record<string, string>)
|
|
|
303
303
|
} catch {
|
|
304
304
|
err('--input must be valid JSON');
|
|
305
305
|
}
|
|
306
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
307
|
+
err('--input must be a JSON object');
|
|
308
|
+
}
|
|
306
309
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
+
// method 作为独立参数传递,兼容 input 内的 method
|
|
311
|
+
const { method: inputMethod, ...cleanInput } = input;
|
|
312
|
+
const method = flags.method?.toUpperCase()
|
|
313
|
+
|| (typeof inputMethod === 'string' ? inputMethod.toUpperCase() : undefined);
|
|
310
314
|
|
|
311
315
|
if (flags.code) {
|
|
312
|
-
const result = generateCode(flags.code, { actionId: id, input, actionHost: cfg.actionHost });
|
|
316
|
+
const result = generateCode(flags.code, { actionId: id, input: cleanInput, actionHost: cfg.actionHost, method });
|
|
313
317
|
outputCode(result, flags);
|
|
314
318
|
return;
|
|
315
319
|
}
|
|
316
320
|
|
|
317
321
|
requireApiKey(cfg);
|
|
318
322
|
try {
|
|
319
|
-
const res = await client.actionCall(id,
|
|
323
|
+
const res = await client.actionCall(id, cleanInput, cfg, method);
|
|
320
324
|
output(res, flags.format as any);
|
|
321
325
|
} catch (e: any) {
|
|
322
326
|
err('call failed', e.message);
|
package/src/commands/config.ts
CHANGED
|
@@ -6,6 +6,25 @@ import { getConfig, saveConfig, showConfig } from '../config.ts';
|
|
|
6
6
|
import { healthCheck } from '../client.ts';
|
|
7
7
|
import { output, err } from '../format.ts';
|
|
8
8
|
|
|
9
|
+
export const CONFIG_HELP = `xapi config - Manage CLI configuration
|
|
10
|
+
|
|
11
|
+
USAGE
|
|
12
|
+
xapi config <command> [flags]
|
|
13
|
+
|
|
14
|
+
COMMANDS
|
|
15
|
+
show Show current config (host, apiKey path, etc.)
|
|
16
|
+
set apiKey=<key> Save API key to ~/.xapi/config.json
|
|
17
|
+
health Check backend connectivity (alias: xapi health)
|
|
18
|
+
|
|
19
|
+
FLAGS
|
|
20
|
+
--format json|pretty|table Output format
|
|
21
|
+
|
|
22
|
+
EXAMPLES
|
|
23
|
+
xapi config show
|
|
24
|
+
xapi config set apiKey=xapi_abc123
|
|
25
|
+
xapi config health
|
|
26
|
+
`;
|
|
27
|
+
|
|
9
28
|
export async function configShow(args: string[], flags: Record<string, string>) {
|
|
10
29
|
showConfig();
|
|
11
30
|
}
|
package/src/commands/register.ts
CHANGED
|
@@ -2,34 +2,43 @@
|
|
|
2
2
|
* register command: create a new user account
|
|
3
3
|
*
|
|
4
4
|
* POST /auth/register — no auth required
|
|
5
|
-
* Returns apiKey (shown once), claimCode, claimUrl, tweetTemplate
|
|
5
|
+
* Returns apiKey (shown once), claimCode, referralCode, claimUrl, tweetTemplate
|
|
6
6
|
* Automatically saves apiKey to ~/.xapi/config.json
|
|
7
|
+
*
|
|
8
|
+
* Optional referral code (please replace xapito to the actual referral code):
|
|
9
|
+
* xapi register --referral-code xapito
|
|
10
|
+
* xapi register --referralCode xapito # alias
|
|
11
|
+
* xapi register xapito # positional shorthand
|
|
7
12
|
*/
|
|
8
13
|
|
|
9
14
|
import { XAPI_API_HOST, saveConfig, scheme } from '../config.ts';
|
|
10
15
|
import { output, err } from '../format.ts';
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
interface RegisterResponse {
|
|
18
|
+
apiKey: string;
|
|
19
|
+
claimCode: string;
|
|
20
|
+
referralCode?: string;
|
|
21
|
+
claimSessionId: string;
|
|
22
|
+
claimUrl: string;
|
|
23
|
+
tweetTemplate: string;
|
|
24
|
+
user: { id: string; accountType: string };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function registerAccount(referralCode?: string): Promise<RegisterResponse> {
|
|
13
28
|
const controller = new AbortController();
|
|
14
29
|
const timer = setTimeout(() => controller.abort(), 15_000);
|
|
15
30
|
try {
|
|
16
31
|
const res = await fetch(`${scheme(XAPI_API_HOST)}://${XAPI_API_HOST}/api/auth/register`, {
|
|
17
32
|
method: 'POST',
|
|
18
33
|
headers: { 'Content-Type': 'application/json' },
|
|
34
|
+
body: JSON.stringify(referralCode ? { referralCode } : {}),
|
|
19
35
|
signal: controller.signal,
|
|
20
36
|
});
|
|
21
37
|
if (!res.ok) {
|
|
22
38
|
const text = await res.text();
|
|
23
39
|
throw new Error(`HTTP ${res.status}: ${text.slice(0, 300)}`);
|
|
24
40
|
}
|
|
25
|
-
return res.json() as Promise<
|
|
26
|
-
apiKey: string;
|
|
27
|
-
claimCode: string;
|
|
28
|
-
claimSessionId: string;
|
|
29
|
-
claimUrl: string;
|
|
30
|
-
tweetTemplate: string;
|
|
31
|
-
user: { id: string; accountType: string };
|
|
32
|
-
}>;
|
|
41
|
+
return res.json() as Promise<RegisterResponse>;
|
|
33
42
|
} finally {
|
|
34
43
|
clearTimeout(timer);
|
|
35
44
|
}
|
|
@@ -37,20 +46,29 @@ async function registerAccount() {
|
|
|
37
46
|
|
|
38
47
|
export async function register(args: string[], flags: Record<string, string>) {
|
|
39
48
|
try {
|
|
40
|
-
|
|
49
|
+
// 邀请码来源优先级:--referral-code > --referralCode > 第一个位置参数
|
|
50
|
+
const rawReferral =
|
|
51
|
+
flags['referral-code'] ?? flags['referralCode'] ?? args[0];
|
|
52
|
+
const referralCode =
|
|
53
|
+
typeof rawReferral === 'string' && rawReferral !== 'true' && rawReferral.length > 0
|
|
54
|
+
? rawReferral
|
|
55
|
+
: undefined;
|
|
56
|
+
|
|
57
|
+
const res = await registerAccount(referralCode);
|
|
41
58
|
|
|
42
|
-
// auto-save apiKey
|
|
43
59
|
saveConfig({ apiKey: res.apiKey });
|
|
44
60
|
|
|
45
61
|
output({
|
|
46
62
|
apiKey: res.apiKey,
|
|
47
63
|
user: res.user,
|
|
64
|
+
referralCode: res.referralCode,
|
|
48
65
|
claim: {
|
|
49
66
|
code: res.claimCode,
|
|
50
67
|
sessionId: res.claimSessionId,
|
|
51
68
|
url: res.claimUrl,
|
|
52
69
|
},
|
|
53
70
|
tweetTemplate: res.tweetTemplate,
|
|
71
|
+
...(referralCode ? { referredBy: referralCode } : {}),
|
|
54
72
|
note: 'apiKey saved to ~/.xapi/config.json',
|
|
55
73
|
}, flags.format as any);
|
|
56
74
|
} catch (e: any) {
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* xapi config show
|
|
14
14
|
* xapi config set apiKey=<key>
|
|
15
|
+
* xapi config health
|
|
15
16
|
* xapi health
|
|
16
17
|
*
|
|
17
18
|
* Global flags:
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
|
|
27
28
|
import * as actionCmds from './commands/action.ts';
|
|
28
29
|
import * as cfgCmds from './commands/config.ts';
|
|
30
|
+
const { CONFIG_HELP } = cfgCmds;
|
|
29
31
|
import * as regCmds from './commands/register.ts';
|
|
30
32
|
import * as topupCmds from './commands/topup.ts';
|
|
31
33
|
import * as balanceCmds from './commands/balance.ts';
|
|
@@ -88,6 +90,7 @@ COMMANDS
|
|
|
88
90
|
get <id> [--method GET|POST|...] Get action schema (filter by HTTP method)
|
|
89
91
|
--code <target> Generate code snippet (curl, py, js, ts, go)
|
|
90
92
|
call <id> --input '{"key":"val"}' Execute an action
|
|
93
|
+
--method GET|POST|... Override HTTP method
|
|
91
94
|
--code <target> Generate code snippet instead of executing
|
|
92
95
|
Variants: python.requests, python.httpx, javascript.fetch, javascript.axios
|
|
93
96
|
|
|
@@ -96,7 +99,8 @@ COMMANDS
|
|
|
96
99
|
oauth unbind <binding-id> Remove an OAuth binding
|
|
97
100
|
oauth providers List available OAuth providers
|
|
98
101
|
|
|
99
|
-
register
|
|
102
|
+
register [referral-code] Create a new user account (apiKey saved automatically)
|
|
103
|
+
--referral-code <code> Register with an inviter's referral code (also: --referralCode, or as positional arg)
|
|
100
104
|
balance Show current account balance
|
|
101
105
|
topup [--amount <usd>] [--method stripe|x402] Generate payment URL
|
|
102
106
|
|
|
@@ -104,6 +108,7 @@ COMMANDS
|
|
|
104
108
|
|
|
105
109
|
config show Show current config
|
|
106
110
|
config set apiKey=<key> Save API key to ~/.xapi/config.json
|
|
111
|
+
config health Check backend connectivity (alias: xapi health)
|
|
107
112
|
|
|
108
113
|
GLOBAL FLAGS
|
|
109
114
|
--format json|pretty|table Output format (default: json)
|
|
@@ -116,6 +121,8 @@ ENV VARS
|
|
|
116
121
|
|
|
117
122
|
EXAMPLES
|
|
118
123
|
xapi register
|
|
124
|
+
xapi register --referral-code xapito # register with an inviter's referral code
|
|
125
|
+
xapi register xapito # positional shorthand
|
|
119
126
|
xapi list --format table
|
|
120
127
|
xapi list --source capability
|
|
121
128
|
xapi search twitter --source api
|
|
@@ -181,12 +188,17 @@ async function main() {
|
|
|
181
188
|
|
|
182
189
|
// ── Config commands ──
|
|
183
190
|
case 'config': {
|
|
191
|
+
if (flags.help || rest.length === 0) {
|
|
192
|
+
console.log(CONFIG_HELP);
|
|
193
|
+
process.exit(0);
|
|
194
|
+
}
|
|
184
195
|
const [subCmd, ...subRest] = rest;
|
|
185
196
|
switch (subCmd) {
|
|
186
197
|
case 'show': return cfgCmds.configShow(subRest, flags);
|
|
187
198
|
case 'set': return cfgCmds.configSet(subRest, flags);
|
|
199
|
+
case 'health': return cfgCmds.configHealth(subRest, flags);
|
|
188
200
|
default:
|
|
189
|
-
console.error(JSON.stringify({ error: `unknown config command: ${subCmd}
|
|
201
|
+
console.error(JSON.stringify({ error: `unknown config command: ${subCmd}`, hint: 'valid commands: show, set, health' }));
|
|
190
202
|
process.exit(1);
|
|
191
203
|
}
|
|
192
204
|
break;
|