@orth/cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -0
- package/dist/analytics.d.ts +5 -0
- package/dist/analytics.js +53 -0
- package/dist/api.d.ts +81 -0
- package/dist/api.js +85 -0
- package/dist/commands/account.d.ts +4 -0
- package/dist/commands/account.js +60 -0
- package/dist/commands/api.d.ts +6 -0
- package/dist/commands/api.js +150 -0
- package/dist/commands/apiRequest.d.ts +6 -0
- package/dist/commands/apiRequest.js +36 -0
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/auth.js +42 -0
- package/dist/commands/code.d.ts +3 -0
- package/dist/commands/code.js +43 -0
- package/dist/commands/run.d.ts +7 -0
- package/dist/commands/run.js +78 -0
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.js +47 -0
- package/dist/commands/skills.d.ts +28 -0
- package/dist/commands/skills.js +638 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +36 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +249 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Orthogonal CLI
|
|
2
|
+
|
|
3
|
+
CLI to access all APIs and agent skills on the Orthogonal platform.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install globally
|
|
11
|
+
npm install -g @orth/cli
|
|
12
|
+
|
|
13
|
+
# Or use npx
|
|
14
|
+
npx @orth/cli <command>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Authentication
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Login with API key
|
|
21
|
+
orth login --key orth_live_your_key
|
|
22
|
+
|
|
23
|
+
# Or set environment variable
|
|
24
|
+
export ORTHOGONAL_API_KEY=orth_live_your_key
|
|
25
|
+
|
|
26
|
+
# Check auth status
|
|
27
|
+
orth whoami
|
|
28
|
+
|
|
29
|
+
# Logout
|
|
30
|
+
orth logout
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API Commands
|
|
34
|
+
|
|
35
|
+
### Search & Browse
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Search for APIs
|
|
39
|
+
orth api search "email finder"
|
|
40
|
+
orth api search "web scraping" --limit 20
|
|
41
|
+
|
|
42
|
+
# List all APIs
|
|
43
|
+
orth api list
|
|
44
|
+
|
|
45
|
+
# Show API endpoints
|
|
46
|
+
orth api show hunter
|
|
47
|
+
|
|
48
|
+
# Show endpoint details
|
|
49
|
+
orth api show hunter /v2/domain-search
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Call APIs
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# GET request with query params
|
|
56
|
+
orth api run hunter /v2/domain-search -q domain=stripe.com
|
|
57
|
+
|
|
58
|
+
# POST request with body
|
|
59
|
+
orth api run olostep /v1/scrapes --body '{"url": "https://stripe.com"}'
|
|
60
|
+
|
|
61
|
+
# Raw output for piping
|
|
62
|
+
orth api run hunter /v2/domain-search -q domain=stripe.com --raw | jq '.emails'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Generate Code
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# TypeScript (default)
|
|
69
|
+
orth api code hunter /v2/domain-search
|
|
70
|
+
|
|
71
|
+
# Python
|
|
72
|
+
orth api code hunter /v2/domain-search --lang python
|
|
73
|
+
|
|
74
|
+
# cURL
|
|
75
|
+
orth api code hunter /v2/domain-search --lang curl
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Request an API
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Request an API to be added to the platform
|
|
82
|
+
orth api request https://docs.example.com/api -d "Weather data API"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Skills Commands
|
|
86
|
+
|
|
87
|
+
### Browse & Search
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# List verified & discoverable skills
|
|
91
|
+
orth skills list
|
|
92
|
+
|
|
93
|
+
# Search for skills
|
|
94
|
+
orth skills search "react best practices"
|
|
95
|
+
|
|
96
|
+
# Show skill details
|
|
97
|
+
orth skills show owner/skill-name
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Install Skills
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Install a skill to all supported agents
|
|
104
|
+
orth skills add owner/skill-name
|
|
105
|
+
|
|
106
|
+
# Install for a specific agent only
|
|
107
|
+
orth skills add owner/skill-name --agent cursor
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Installs to 7 agent skill directories:
|
|
111
|
+
|
|
112
|
+
| Agent | Directory |
|
|
113
|
+
|-------|-----------|
|
|
114
|
+
| Cursor | `~/.cursor/skills/` |
|
|
115
|
+
| Claude Code | `~/.claude/skills/` |
|
|
116
|
+
| GitHub Copilot | `~/.github/skills/` |
|
|
117
|
+
| Windsurf | `~/.codeium/windsurf/skills/` |
|
|
118
|
+
| Codex | `~/.agents/skills/` |
|
|
119
|
+
| Gemini | `~/.gemini/skills/` |
|
|
120
|
+
| OpenClaw | `~/.openclaw/skills/` |
|
|
121
|
+
|
|
122
|
+
### Create & Publish Skills
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Initialize a new skill from template
|
|
126
|
+
orth skills init my-skill
|
|
127
|
+
orth skills init my-skill --bare # SKILL.md only, no subdirectories
|
|
128
|
+
|
|
129
|
+
# Create a skill from a GitHub repo
|
|
130
|
+
orth skills create https://github.com/owner/repo
|
|
131
|
+
orth skills create owner/repo --path skills/my-skill --ref main
|
|
132
|
+
|
|
133
|
+
# Submit a local skill to the platform
|
|
134
|
+
orth skills submit ./my-skill
|
|
135
|
+
orth skills submit --name "My Skill" --tags "react,testing"
|
|
136
|
+
|
|
137
|
+
# Request verification (required before discoverability)
|
|
138
|
+
orth skills request-verification owner/my-skill
|
|
139
|
+
|
|
140
|
+
# Request a skill to be added (by description or GitHub URL)
|
|
141
|
+
orth skills request "A skill for React testing patterns"
|
|
142
|
+
orth skills request https://github.com/owner/cool-skill
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Verification Workflow
|
|
146
|
+
|
|
147
|
+
1. **Submit** your skill → it's on the platform but not publicly visible
|
|
148
|
+
2. **Request verification** → our team reviews it
|
|
149
|
+
3. **Once verified** → toggle discoverability on/off from your [dashboard](https://orthogonal.com/dashboard/skills)
|
|
150
|
+
|
|
151
|
+
## Account
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Check balance
|
|
155
|
+
orth balance
|
|
156
|
+
|
|
157
|
+
# View usage
|
|
158
|
+
orth usage --limit 20
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Shorthand Aliases
|
|
162
|
+
|
|
163
|
+
These top-level commands are aliases for their `orth api` counterparts:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
orth search "query" # → orth api search "query"
|
|
167
|
+
orth run slug /path # → orth api run slug /path
|
|
168
|
+
orth code slug /path # → orth api code slug /path
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Install dependencies
|
|
175
|
+
npm install
|
|
176
|
+
|
|
177
|
+
# Build
|
|
178
|
+
npm run build
|
|
179
|
+
|
|
180
|
+
# Watch mode
|
|
181
|
+
npm run dev
|
|
182
|
+
|
|
183
|
+
# Run tests
|
|
184
|
+
npm test
|
|
185
|
+
|
|
186
|
+
# Watch tests
|
|
187
|
+
npm run test:watch
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trackEvent = trackEvent;
|
|
4
|
+
const config_js_1 = require("./config.js");
|
|
5
|
+
const CLI_VERSION = process.env.npm_package_version || "0.2.0";
|
|
6
|
+
const BASE_URL = "https://api.orth.sh/v1";
|
|
7
|
+
/**
|
|
8
|
+
* Fire-and-forget analytics event for CLI usage tracking.
|
|
9
|
+
* Never blocks, never throws, never shows errors to the user.
|
|
10
|
+
*/
|
|
11
|
+
function trackEvent(command, args) {
|
|
12
|
+
// Don't track if no API key (not authenticated)
|
|
13
|
+
const apiKey = (0, config_js_1.getApiKey)();
|
|
14
|
+
if (!apiKey)
|
|
15
|
+
return;
|
|
16
|
+
const payload = {
|
|
17
|
+
command,
|
|
18
|
+
args: args ? sanitizeArgs(args) : undefined,
|
|
19
|
+
cliVersion: CLI_VERSION,
|
|
20
|
+
os: process.platform,
|
|
21
|
+
nodeVersion: process.version,
|
|
22
|
+
apiKeyPrefix: apiKey.substring(0, 12),
|
|
23
|
+
timestamp: new Date().toISOString(),
|
|
24
|
+
};
|
|
25
|
+
// Fire and forget - don't await, don't catch visible errors
|
|
26
|
+
fetch(`${BASE_URL}/cli/events`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: {
|
|
29
|
+
Authorization: `Bearer ${apiKey}`,
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
"x-orthogonal-source": "cli",
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(payload),
|
|
34
|
+
}).catch(() => {
|
|
35
|
+
// Silently ignore - analytics should never affect CLI operation
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Remove any potentially sensitive values from args
|
|
40
|
+
*/
|
|
41
|
+
function sanitizeArgs(args) {
|
|
42
|
+
const sanitized = {};
|
|
43
|
+
const sensitiveKeys = ["key", "apiKey", "token", "secret", "password"];
|
|
44
|
+
for (const [key, value] of Object.entries(args)) {
|
|
45
|
+
if (sensitiveKeys.some((s) => key.toLowerCase().includes(s))) {
|
|
46
|
+
sanitized[key] = "[REDACTED]";
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
sanitized[key] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return sanitized;
|
|
53
|
+
}
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export declare function apiRequest<T = unknown>(endpoint: string, options?: {
|
|
2
|
+
method?: string;
|
|
3
|
+
body?: unknown;
|
|
4
|
+
}): Promise<T>;
|
|
5
|
+
export interface SearchResponse {
|
|
6
|
+
results: Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
endpoints: Array<{
|
|
10
|
+
path: string;
|
|
11
|
+
method: string;
|
|
12
|
+
description: string;
|
|
13
|
+
price?: number;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
count: number;
|
|
17
|
+
apisCount: number;
|
|
18
|
+
}
|
|
19
|
+
export interface DetailsResponse {
|
|
20
|
+
api?: string | {
|
|
21
|
+
name: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
};
|
|
25
|
+
path?: string;
|
|
26
|
+
method?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
price?: number | string;
|
|
29
|
+
parameters?: {
|
|
30
|
+
query?: Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
type: string;
|
|
33
|
+
required: boolean;
|
|
34
|
+
description?: string;
|
|
35
|
+
}>;
|
|
36
|
+
body?: Array<{
|
|
37
|
+
name: string;
|
|
38
|
+
type: string;
|
|
39
|
+
required: boolean;
|
|
40
|
+
description?: string;
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
endpoint?: {
|
|
44
|
+
path: string;
|
|
45
|
+
method: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
price?: number | string;
|
|
48
|
+
queryParams?: Array<{
|
|
49
|
+
name: string;
|
|
50
|
+
type: string;
|
|
51
|
+
required: boolean;
|
|
52
|
+
description?: string;
|
|
53
|
+
}>;
|
|
54
|
+
bodyParams?: Array<{
|
|
55
|
+
name: string;
|
|
56
|
+
type: string;
|
|
57
|
+
required: boolean;
|
|
58
|
+
description?: string;
|
|
59
|
+
}>;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export interface RunResponse {
|
|
63
|
+
success: boolean;
|
|
64
|
+
data: unknown;
|
|
65
|
+
price?: string;
|
|
66
|
+
priceCents?: number;
|
|
67
|
+
requestId?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface IntegrateResponse {
|
|
70
|
+
api: string;
|
|
71
|
+
path: string;
|
|
72
|
+
snippets: Record<string, string>;
|
|
73
|
+
}
|
|
74
|
+
export declare function search(prompt: string, limit?: number): Promise<SearchResponse>;
|
|
75
|
+
export declare function getDetails(api: string, path: string): Promise<DetailsResponse>;
|
|
76
|
+
export declare function run(api: string, path: string, options?: {
|
|
77
|
+
method?: string;
|
|
78
|
+
query?: Record<string, string>;
|
|
79
|
+
body?: unknown;
|
|
80
|
+
}): Promise<RunResponse>;
|
|
81
|
+
export declare function integrate(api: string, path: string, format?: string): Promise<IntegrateResponse>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiRequest = apiRequest;
|
|
4
|
+
exports.search = search;
|
|
5
|
+
exports.getDetails = getDetails;
|
|
6
|
+
exports.run = run;
|
|
7
|
+
exports.integrate = integrate;
|
|
8
|
+
const config_js_1 = require("./config.js");
|
|
9
|
+
const BASE_URL = "https://api.orth.sh/v1";
|
|
10
|
+
async function apiRequest(endpoint, options = {}) {
|
|
11
|
+
const apiKey = (0, config_js_1.requireApiKey)();
|
|
12
|
+
const res = await fetch(`${BASE_URL}${endpoint}`, {
|
|
13
|
+
method: options.method || "GET",
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization: `Bearer ${apiKey}`,
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
"x-orthogonal-source": "cli",
|
|
18
|
+
},
|
|
19
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
20
|
+
});
|
|
21
|
+
const data = (await res.json());
|
|
22
|
+
if (!res.ok || data.success === false) {
|
|
23
|
+
// Include more details in error message
|
|
24
|
+
let errorMsg = data.error || `API request failed with status ${res.status}`;
|
|
25
|
+
// Add any additional error details from the response
|
|
26
|
+
if (data.message) {
|
|
27
|
+
errorMsg += `: ${data.message}`;
|
|
28
|
+
}
|
|
29
|
+
if (data.data?.error) {
|
|
30
|
+
errorMsg += ` - ${data.data.error}`;
|
|
31
|
+
if (data.data?.message) {
|
|
32
|
+
errorMsg += `: ${data.data.message}`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Handle Hunter-style errors array
|
|
36
|
+
if (data.data?.errors &&
|
|
37
|
+
Array.isArray(data.data.errors)) {
|
|
38
|
+
const errors = data.data.errors;
|
|
39
|
+
for (const err of errors) {
|
|
40
|
+
if (err.details) {
|
|
41
|
+
errorMsg += `\n → ${err.details}`;
|
|
42
|
+
}
|
|
43
|
+
else if (err.id) {
|
|
44
|
+
errorMsg += `\n → ${err.id}: ${err.code || ""}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (data.details) {
|
|
49
|
+
errorMsg += `\n Details: ${JSON.stringify(data.details)}`;
|
|
50
|
+
}
|
|
51
|
+
throw new Error(errorMsg);
|
|
52
|
+
}
|
|
53
|
+
// Return the whole response, not just data field
|
|
54
|
+
return data;
|
|
55
|
+
}
|
|
56
|
+
async function search(prompt, limit = 10) {
|
|
57
|
+
return apiRequest("/search", {
|
|
58
|
+
method: "POST",
|
|
59
|
+
body: { prompt, limit },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function getDetails(api, path) {
|
|
63
|
+
return apiRequest("/details", {
|
|
64
|
+
method: "POST",
|
|
65
|
+
body: { api, path },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function run(api, path, options = {}) {
|
|
69
|
+
return apiRequest("/run", {
|
|
70
|
+
method: "POST",
|
|
71
|
+
body: {
|
|
72
|
+
api,
|
|
73
|
+
path,
|
|
74
|
+
method: options.method || "GET",
|
|
75
|
+
query: options.query,
|
|
76
|
+
body: options.body,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function integrate(api, path, format = "orth-sdk") {
|
|
81
|
+
return apiRequest("/integrate", {
|
|
82
|
+
method: "POST",
|
|
83
|
+
body: { api, path, format },
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.balanceCommand = balanceCommand;
|
|
7
|
+
exports.usageCommand = usageCommand;
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const ora_1 = __importDefault(require("ora"));
|
|
10
|
+
const api_js_1 = require("../api.js");
|
|
11
|
+
async function balanceCommand() {
|
|
12
|
+
const spinner = (0, ora_1.default)("Fetching balance...").start();
|
|
13
|
+
try {
|
|
14
|
+
// Note: This endpoint may not exist yet - placeholder
|
|
15
|
+
const data = await (0, api_js_1.apiRequest)("/account/balance");
|
|
16
|
+
spinner.stop();
|
|
17
|
+
if (data && data.balance !== undefined) {
|
|
18
|
+
console.log(chalk_1.default.bold("\nAccount Balance:"));
|
|
19
|
+
console.log(chalk_1.default.green.bold(` $${data.balance.toFixed(2)} ${data.currency || "USD"}`));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(chalk_1.default.gray("Balance information not available."));
|
|
23
|
+
console.log(chalk_1.default.gray("Check your balance at: https://orthogonal.com/dashboard"));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
spinner.stop();
|
|
28
|
+
// Graceful fallback if endpoint doesn't exist
|
|
29
|
+
console.log(chalk_1.default.gray("Balance information not available via API."));
|
|
30
|
+
console.log(chalk_1.default.gray("Check your balance at: https://orthogonal.com/dashboard"));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function usageCommand(options) {
|
|
34
|
+
const spinner = (0, ora_1.default)("Fetching usage...").start();
|
|
35
|
+
try {
|
|
36
|
+
// Note: This endpoint may not exist yet - placeholder
|
|
37
|
+
const data = await (0, api_js_1.apiRequest)(`/account/usage?limit=${options.limit}`);
|
|
38
|
+
spinner.stop();
|
|
39
|
+
if (data?.usage && data.usage.length > 0) {
|
|
40
|
+
console.log(chalk_1.default.bold("\nRecent API Usage:\n"));
|
|
41
|
+
for (const item of data.usage) {
|
|
42
|
+
const date = new Date(item.timestamp).toLocaleString();
|
|
43
|
+
console.log(chalk_1.default.gray(date.padEnd(22)) +
|
|
44
|
+
chalk_1.default.cyan(item.api.padEnd(15)) +
|
|
45
|
+
chalk_1.default.white(item.path.padEnd(30)) +
|
|
46
|
+
chalk_1.default.green(`$${item.cost.toFixed(4)}`));
|
|
47
|
+
}
|
|
48
|
+
console.log(chalk_1.default.bold(`\nTotal: $${data.total.toFixed(2)}`));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(chalk_1.default.gray("No recent usage data available."));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
spinner.stop();
|
|
56
|
+
// Graceful fallback if endpoint doesn't exist
|
|
57
|
+
console.log(chalk_1.default.gray("Usage information not available via API."));
|
|
58
|
+
console.log(chalk_1.default.gray("Check your usage at: https://orthogonal.com/dashboard/usage"));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.apiCommand = apiCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const api_js_1 = require("../api.js");
|
|
10
|
+
async function apiCommand(slug, path, options) {
|
|
11
|
+
const spinner = (0, ora_1.default)("Loading...").start();
|
|
12
|
+
try {
|
|
13
|
+
if (!slug) {
|
|
14
|
+
// List all APIs - search multiple terms to get broader coverage
|
|
15
|
+
const searches = await Promise.all([
|
|
16
|
+
(0, api_js_1.search)("api", 50),
|
|
17
|
+
(0, api_js_1.search)("data", 50),
|
|
18
|
+
(0, api_js_1.search)("search", 50),
|
|
19
|
+
(0, api_js_1.search)("email", 50),
|
|
20
|
+
]);
|
|
21
|
+
spinner.stop();
|
|
22
|
+
// Merge and dedupe results
|
|
23
|
+
const allResults = searches.flatMap(s => s.results || []);
|
|
24
|
+
const data = {
|
|
25
|
+
results: allResults,
|
|
26
|
+
count: allResults.length,
|
|
27
|
+
apisCount: new Set(allResults.map(r => r.slug)).size,
|
|
28
|
+
};
|
|
29
|
+
console.log(chalk_1.default.bold("\nAvailable APIs:\n"));
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const api of data.results) {
|
|
32
|
+
if (!api.slug || seen.has(api.slug))
|
|
33
|
+
continue;
|
|
34
|
+
seen.add(api.slug);
|
|
35
|
+
console.log(chalk_1.default.cyan.bold(api.slug.padEnd(20)) +
|
|
36
|
+
chalk_1.default.white(api.name || "") +
|
|
37
|
+
chalk_1.default.gray(` (${api.endpoints?.length || 0} endpoints)`));
|
|
38
|
+
}
|
|
39
|
+
console.log(chalk_1.default.gray("\nRun 'orth api <slug>' to see endpoints for an API"));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (path) {
|
|
43
|
+
// Show endpoint details
|
|
44
|
+
const data = await (0, api_js_1.getDetails)(slug, path);
|
|
45
|
+
spinner.stop();
|
|
46
|
+
console.log(chalk_1.default.bold(`\n${chalk_1.default.cyan(slug)}${chalk_1.default.white(path)}\n`));
|
|
47
|
+
// Get description from endpoint object if available
|
|
48
|
+
const desc = data.description || data.endpoint?.description;
|
|
49
|
+
console.log(chalk_1.default.gray(desc || "No description"));
|
|
50
|
+
// Get price
|
|
51
|
+
const price = data.price || data.endpoint?.price;
|
|
52
|
+
if (price) {
|
|
53
|
+
console.log(chalk_1.default.green(`\nPrice: ${typeof price === 'number' ? '$' + price : price}`));
|
|
54
|
+
}
|
|
55
|
+
// Get params from nested endpoint object if needed
|
|
56
|
+
const queryParams = data.parameters?.query || data.endpoint?.queryParams || [];
|
|
57
|
+
const bodyParams = data.parameters?.body || data.endpoint?.bodyParams || [];
|
|
58
|
+
if (queryParams.length > 0) {
|
|
59
|
+
console.log(chalk_1.default.bold("\nQuery Parameters:"));
|
|
60
|
+
for (const param of queryParams) {
|
|
61
|
+
const required = param.required ? chalk_1.default.red("*") : "";
|
|
62
|
+
console.log(chalk_1.default.yellow(` ${param.name}${required}`) +
|
|
63
|
+
chalk_1.default.gray(` (${param.type})`) +
|
|
64
|
+
(param.description ? chalk_1.default.gray(` - ${param.description}`) : ""));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (bodyParams.length > 0) {
|
|
68
|
+
console.log(chalk_1.default.bold("\nBody Parameters:"));
|
|
69
|
+
for (const param of bodyParams) {
|
|
70
|
+
const required = param.required ? chalk_1.default.red("*") : "";
|
|
71
|
+
console.log(chalk_1.default.yellow(` ${param.name}${required}`) +
|
|
72
|
+
chalk_1.default.gray(` (${param.type})`) +
|
|
73
|
+
(param.description ? chalk_1.default.gray(` - ${param.description}`) : ""));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Generate appropriate example
|
|
77
|
+
console.log(chalk_1.default.gray("\nExample:"));
|
|
78
|
+
if (bodyParams.length > 0) {
|
|
79
|
+
const exampleBody = {};
|
|
80
|
+
for (const param of bodyParams.slice(0, 3)) {
|
|
81
|
+
exampleBody[param.name] = param.type === 'object' ? '{}' : `<${param.name}>`;
|
|
82
|
+
}
|
|
83
|
+
console.log(chalk_1.default.white(` orth run ${slug} ${path} --body '${JSON.stringify(exampleBody)}'`));
|
|
84
|
+
}
|
|
85
|
+
else if (queryParams.length > 0) {
|
|
86
|
+
const exampleQuery = queryParams.slice(0, 2).map((p) => `-q ${p.name}=<value>`).join(' ');
|
|
87
|
+
console.log(chalk_1.default.white(` orth run ${slug} ${path} ${exampleQuery}`));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.log(chalk_1.default.white(` orth run ${slug} ${path}`));
|
|
91
|
+
}
|
|
92
|
+
// x402 direct payment info
|
|
93
|
+
if (options?.x402 || options?.x402Full) {
|
|
94
|
+
const x402Url = `https://x402.orth.sh/${slug}${path}`;
|
|
95
|
+
// Determine HTTP method: POST if body params, GET otherwise
|
|
96
|
+
const method = bodyParams.length > 0 ? 'POST' : 'GET';
|
|
97
|
+
if (options?.x402 && !options?.x402Full) {
|
|
98
|
+
// Minimal output - just the URL
|
|
99
|
+
console.log(`\n${x402Url}`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Full output - actually call the endpoint and get the 402 response
|
|
103
|
+
try {
|
|
104
|
+
const fetchOptions = { method };
|
|
105
|
+
if (method === 'POST') {
|
|
106
|
+
fetchOptions.headers = { 'Content-Type': 'application/json' };
|
|
107
|
+
fetchOptions.body = '{}';
|
|
108
|
+
}
|
|
109
|
+
const response = await fetch(x402Url, fetchOptions);
|
|
110
|
+
const responseData = await response.json();
|
|
111
|
+
console.log(chalk_1.default.bold.magenta("\n── x402 Payment Details ──\n"));
|
|
112
|
+
console.log(chalk_1.default.cyan(`URL: ${x402Url}`));
|
|
113
|
+
console.log(chalk_1.default.yellow(`Method: ${method}`));
|
|
114
|
+
console.log(chalk_1.default.gray(`Status: ${response.status}\n`));
|
|
115
|
+
console.log(JSON.stringify(responseData, null, 2));
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.log(chalk_1.default.red(`\nFailed to fetch x402 details: ${err}`));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Show API endpoints
|
|
125
|
+
const data = await (0, api_js_1.search)(slug, 20);
|
|
126
|
+
spinner.stop();
|
|
127
|
+
const api = data.results.find((a) => a.slug === slug);
|
|
128
|
+
if (!api) {
|
|
129
|
+
console.log(chalk_1.default.yellow(`API '${slug}' not found.`));
|
|
130
|
+
console.log(chalk_1.default.gray("Run 'orth api' to see available APIs"));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
console.log(chalk_1.default.bold(`\n${chalk_1.default.cyan(api.name)} (${api.slug})\n`));
|
|
134
|
+
for (const endpoint of api.endpoints) {
|
|
135
|
+
const method = chalk_1.default.yellow(endpoint.method.padEnd(6));
|
|
136
|
+
const price = endpoint.price ? chalk_1.default.green(`$${endpoint.price.toFixed(2)}`) : chalk_1.default.gray("free");
|
|
137
|
+
console.log(`${method} ${chalk_1.default.white(endpoint.path)} ${price}`);
|
|
138
|
+
if (endpoint.description) {
|
|
139
|
+
console.log(chalk_1.default.gray(` ${endpoint.description.slice(0, 80)}${endpoint.description.length > 80 ? "..." : ""}`));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
console.log(chalk_1.default.gray("\nRun 'orth api " + slug + " <path>' for endpoint details"));
|
|
143
|
+
console.log(chalk_1.default.gray("Run 'orth run " + slug + " <path>' to call an endpoint"));
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
spinner.stop();
|
|
147
|
+
console.error(chalk_1.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.apiRequestCommand = apiRequestCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const api_js_1 = require("../api.js");
|
|
10
|
+
/**
|
|
11
|
+
* orth api request <docsUrl> - Request an API to be added to the platform
|
|
12
|
+
*/
|
|
13
|
+
async function apiRequestCommand(docsUrl, options) {
|
|
14
|
+
const spinner = (0, ora_1.default)("Submitting API request...").start();
|
|
15
|
+
try {
|
|
16
|
+
await (0, api_js_1.apiRequest)("/requests/api", {
|
|
17
|
+
method: "POST",
|
|
18
|
+
body: {
|
|
19
|
+
docsUrl,
|
|
20
|
+
description: options.description,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
spinner.stop();
|
|
24
|
+
console.log(chalk_1.default.green("\n✓ API request submitted!"));
|
|
25
|
+
console.log(chalk_1.default.gray("Our team has been notified and will review your request."));
|
|
26
|
+
console.log(chalk_1.default.gray(` Docs URL: ${docsUrl}`));
|
|
27
|
+
if (options.description) {
|
|
28
|
+
console.log(chalk_1.default.gray(` Notes: ${options.description}`));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
spinner.stop();
|
|
33
|
+
console.error(chalk_1.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|