ebay-api-mcp-server-node-local 1.0.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 +214 -0
- package/dist/constant/constants.js +48 -0
- package/dist/constant/constants.js.map +1 -0
- package/dist/helper/http-helper.js +140 -0
- package/dist/helper/http-helper.js.map +1 -0
- package/dist/helper/openapi-helper.js +114 -0
- package/dist/helper/openapi-helper.js.map +1 -0
- package/dist/helper/validation-helper.js +214 -0
- package/dist/helper/validation-helper.js.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/service/openapi-service.js +196 -0
- package/dist/service/openapi-service.js.map +1 -0
- package/eslint.config.js +58 -0
- package/package.json +50 -0
- package/src/constant/constants.ts +51 -0
- package/src/helper/http-helper.ts +154 -0
- package/src/helper/openapi-helper.ts +116 -0
- package/src/helper/validation-helper.ts +289 -0
- package/src/index.ts +75 -0
- package/src/integration.test.ts +140 -0
- package/src/service/openapi-service.ts +243 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +115 -0
- package/tsconfig.node.json +7 -0
- package/vitest.config.ts +20 -0
- package/vitest.setup.ts +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# eBay API MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides seamless integration with eBay's APIs through AI assistants and development tools.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This MCP server enables AI assistants (Claude Desktop, Cursor, Cline, VS Code extensions, etc.) to interact with eBay's comprehensive API ecosystem. It provides tools for API document retrieval, endpoint discovery, and direct API invocation, making it easy to integrate eBay marketplace functionality into AI-powered workflows.
|
|
8
|
+
|
|
9
|
+
### Key Features
|
|
10
|
+
|
|
11
|
+
- **API Discovery**: Automatically discover and explore eBay API endpoints
|
|
12
|
+
- **Dynamic Tool Generation**: Generate tools based on OpenAPI specifications
|
|
13
|
+
- **Multi-Environment Support**: Works with both sandbox and production environments
|
|
14
|
+
- **Comprehensive API Coverage**: Supports eBay's full API ecosystem
|
|
15
|
+
- **Type-Safe Operations**: Built with TypeScript for robust API interactions
|
|
16
|
+
- **MCP Integration**: Compatible with popular MCP hosts and AI assistants
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- **Node.js**: Version 22 or higher
|
|
21
|
+
- **eBay Developer Account**: Required for API access tokens
|
|
22
|
+
- **MCP Host**: Claude Desktop, Cursor, Cline, or other MCP-compatible application
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### 1. Clone and Setup
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone <repository-url>
|
|
30
|
+
cd ebay-api-mcp-server-node-local
|
|
31
|
+
npm install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Build the Project
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm run build
|
|
38
|
+
# or
|
|
39
|
+
yarn build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Environment Configuration
|
|
43
|
+
|
|
44
|
+
Set the following environment variables:
|
|
45
|
+
|
|
46
|
+
- `EBAY_CLIENT_TOKEN`: Your eBay API access token (required)
|
|
47
|
+
- `EBAY_API_ENV`: API environment - "sandbox" or "production" (default: "production")
|
|
48
|
+
|
|
49
|
+
## Authentication
|
|
50
|
+
|
|
51
|
+
### Obtaining an eBay API Token
|
|
52
|
+
|
|
53
|
+
#### Method 1: Using cURL
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
curl -v https://api.ebay.com/identity/v1/oauth2/token \
|
|
57
|
+
-H "Accept: application/json" \
|
|
58
|
+
-H "Accept-Language: en_US" \
|
|
59
|
+
-u "CLIENT_ID:CLIENT_SECRET" \
|
|
60
|
+
-d "grant_type=client_credentials"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For sandbox testing, use `https://api.sandbox.ebay.com/identity/v1/oauth2/token`
|
|
64
|
+
|
|
65
|
+
#### Method 2: Using Postman
|
|
66
|
+
|
|
67
|
+
1. Create a POST request to `https://api.ebay.com/identity/v1/oauth2/token`
|
|
68
|
+
2. Set Authorization to Basic Auth with your Client ID and Client Secret
|
|
69
|
+
3. Add form data: `grant_type=client_credentials`
|
|
70
|
+
4. Send the request
|
|
71
|
+
|
|
72
|
+
Response format:
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"access_token": "your_access_token_here",
|
|
76
|
+
"expires_in": 7200,
|
|
77
|
+
"token_type": "Application Access Token"
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
### Running the Server
|
|
84
|
+
|
|
85
|
+
#### With Environment Variables Set
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm start
|
|
89
|
+
# or
|
|
90
|
+
yarn start
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### With Inline Environment Variables
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
EBAY_CLIENT_TOKEN='your_token_here' EBAY_API_ENV='production' npm start
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Using npx
|
|
100
|
+
|
|
101
|
+
You can also run the server using `npx` in several ways:
|
|
102
|
+
|
|
103
|
+
**Option 1: Run the built server directly**
|
|
104
|
+
```bash
|
|
105
|
+
# First build the project
|
|
106
|
+
npm run build
|
|
107
|
+
|
|
108
|
+
# Then run with npx
|
|
109
|
+
npx node dist/index.js
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Option 2: Run with environment variables**
|
|
113
|
+
```bash
|
|
114
|
+
# Build first
|
|
115
|
+
npm run build
|
|
116
|
+
|
|
117
|
+
# Run with environment variables
|
|
118
|
+
EBAY_CLIENT_TOKEN='your_token_here' EBAY_API_ENV='production' npx node dist/index.js
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Option 3: Use npx to run npm scripts**
|
|
122
|
+
```bash
|
|
123
|
+
npx npm run build
|
|
124
|
+
npx npm start
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Option 4: Run TypeScript directly (if you have ts-node)**
|
|
128
|
+
```bash
|
|
129
|
+
npx ts-node src/index.ts
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## MCP Integration
|
|
133
|
+
|
|
134
|
+
### Configuration for Popular MCP Hosts
|
|
135
|
+
|
|
136
|
+
#### VS Code with MCP Extension
|
|
137
|
+
|
|
138
|
+
1. Create a `.vscode` folder in your project root
|
|
139
|
+
2. Create `mcp.json` with the following configuration:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"servers": {
|
|
144
|
+
"ebay-api-mcp-server": {
|
|
145
|
+
"type": "stdio",
|
|
146
|
+
"command": "node",
|
|
147
|
+
"args": ["./dist/index.js"],
|
|
148
|
+
"env": {
|
|
149
|
+
"EBAY_API_ENV": "production",
|
|
150
|
+
"EBAY_CLIENT_TOKEN": "YOUR_ACCESS_TOKEN"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Claude Desktop
|
|
158
|
+
|
|
159
|
+
Add to your Claude Desktop MCP configuration:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"mcpServers": {
|
|
164
|
+
"ebay-api": {
|
|
165
|
+
"command": "node",
|
|
166
|
+
"args": ["/path/to/ebay-api-mcp-server/dist/index.js"],
|
|
167
|
+
"env": {
|
|
168
|
+
"EBAY_CLIENT_TOKEN": "YOUR_ACCESS_TOKEN",
|
|
169
|
+
"EBAY_API_ENV": "production"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### Cursor
|
|
177
|
+
|
|
178
|
+
Configure in your Cursor MCP settings with similar JSON structure as above.
|
|
179
|
+
|
|
180
|
+
### Example Usage
|
|
181
|
+
|
|
182
|
+
Once configured, you can ask your AI assistant to:
|
|
183
|
+
|
|
184
|
+
- "Find an API for marketplace account deletion notifications"
|
|
185
|
+
- "Search for product listing APIs"
|
|
186
|
+
- "Get documentation for the Trading API"
|
|
187
|
+
- "Invoke the getBuyerRequirements endpoint"
|
|
188
|
+
|
|
189
|
+
## Troubleshooting
|
|
190
|
+
|
|
191
|
+
### Common Issues
|
|
192
|
+
|
|
193
|
+
**Authentication Errors**
|
|
194
|
+
- Verify your `EBAY_CLIENT_TOKEN` is valid and not expired
|
|
195
|
+
- Ensure you're using the correct environment (sandbox vs production)
|
|
196
|
+
- Check that your eBay developer account has the necessary permissions
|
|
197
|
+
|
|
198
|
+
**MCP Connection Issues**
|
|
199
|
+
- Verify the path to `dist/index.js` in your MCP configuration
|
|
200
|
+
- Ensure Node.js is in your system PATH
|
|
201
|
+
- Check that the server builds successfully with `npm run build`
|
|
202
|
+
|
|
203
|
+
**API Errors**
|
|
204
|
+
- Review eBay API documentation for endpoint-specific requirements
|
|
205
|
+
- Verify your token has the necessary scopes for the APIs you're trying to access
|
|
206
|
+
- Check rate limiting and usage quotas
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
## Support
|
|
210
|
+
|
|
211
|
+
For issues related to:
|
|
212
|
+
- **eBay API**: Consult the [eBay Developer Documentation](https://developer.ebay.com/)
|
|
213
|
+
- **MCP Protocol**: Visit the [Model Context Protocol documentation](https://modelcontextprotocol.io/)
|
|
214
|
+
- **This Server**: Open an issue in this repository
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used throughout the application
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Environment options for the eBay API
|
|
6
|
+
*/
|
|
7
|
+
export var ApiEnvironment;
|
|
8
|
+
(function (ApiEnvironment) {
|
|
9
|
+
ApiEnvironment["SANDBOX"] = "sandbox";
|
|
10
|
+
ApiEnvironment["PRODUCTION"] = "production";
|
|
11
|
+
})(ApiEnvironment || (ApiEnvironment = {}));
|
|
12
|
+
/**
|
|
13
|
+
* Utility to find ApiEnvironment by string value
|
|
14
|
+
* Returns SANDBOX if no match is found
|
|
15
|
+
*/
|
|
16
|
+
export function findApiEnvironmentByValue(value) {
|
|
17
|
+
const lowercaseValue = value?.toLowerCase();
|
|
18
|
+
const matchedEnv = Object.entries(ApiEnvironment)
|
|
19
|
+
.find(([_key, val]) => typeof val === "string" && val.toLowerCase() === lowercaseValue);
|
|
20
|
+
return matchedEnv ? matchedEnv[1] : ApiEnvironment.SANDBOX;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Recall apiDoc url by prompt
|
|
24
|
+
*/
|
|
25
|
+
export const RECALL_SPEC_BY_PROMPT_URL = "https://ebaypubapimcp3.vip.qa.ebay.com/developer-portal/api/v1/openapi-specs/search?query=%s";
|
|
26
|
+
/**
|
|
27
|
+
* url for query apiSpec with fields such as specTitle、operationId
|
|
28
|
+
*/
|
|
29
|
+
export const RECALL_SPEC_WITH_FIELD_URL = "https://ebaypubapimcp3.vip.qa.ebay.com/developer-portal/api/v1/openapi-specs/%s?operationId=%s";
|
|
30
|
+
/**
|
|
31
|
+
* Required environment variable names for the application
|
|
32
|
+
*/
|
|
33
|
+
export const REQUIRED_ENV_VARS = ["EBAY_CLIENT_TOKEN", "EBAY_API_ENV"];
|
|
34
|
+
/**
|
|
35
|
+
* API domain name, differentiated by api environment
|
|
36
|
+
*/
|
|
37
|
+
export const DOMAIN_NAME = {
|
|
38
|
+
[ApiEnvironment.SANDBOX]: "api.sandbox.ebay.com",
|
|
39
|
+
[ApiEnvironment.PRODUCTION]: "api.ebay.com",
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* List of supported calling methods, differentiated by api environment
|
|
43
|
+
*/
|
|
44
|
+
export const SUPPORTED_CALLING_METHODS = {
|
|
45
|
+
[ApiEnvironment.SANDBOX]: ["get", "put", "post", "delete", "options", "head", "patch", "trace"],
|
|
46
|
+
[ApiEnvironment.PRODUCTION]: ["get"],
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constant/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,CAAN,IAAY,cAGX;AAHD,WAAY,cAAc;IACxB,qCAAmB,CAAA;IACnB,2CAAyB,CAAA;AAC3B,CAAC,EAHW,cAAc,KAAd,cAAc,QAGzB;AACD;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAa;IACrD,MAAM,cAAc,GAAG,KAAK,EAAE,WAAW,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;SAC9C,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,CAAC;IAC1F,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAmB,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC;AAC/E,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,8FAA8F,CAAC;AACxI;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,gGAAgG,CAAC;AAE3I;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;AAEvE;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,sBAAsB;IAChD,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,cAAc;CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;IAC/F,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC;CACrC,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for HTTP requests
|
|
3
|
+
*/
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
import { DOMAIN_NAME, findApiEnvironmentByValue } from "../constant/constants.js";
|
|
6
|
+
const USER_ENVIRONMENT = findApiEnvironmentByValue(process.env.EBAY_API_ENV || "");
|
|
7
|
+
const USER_TOKEN = process.env.EBAY_CLIENT_TOKEN || "";
|
|
8
|
+
const SCHEMA_REQUEST_BODY = "requestBody";
|
|
9
|
+
/**
|
|
10
|
+
* Format axios error message for consistent error output
|
|
11
|
+
*/
|
|
12
|
+
export function formatAxiosError(error) {
|
|
13
|
+
let errorMessage = `Error in invokeAPI tool: ${error instanceof Error ? error.message : String(error)}`;
|
|
14
|
+
if (axios.isAxiosError(error)) {
|
|
15
|
+
if (error?.response?.data) {
|
|
16
|
+
errorMessage = JSON.stringify(error.response.data, null, 2);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return errorMessage;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build headers from input headers and fill with default headers
|
|
23
|
+
*/
|
|
24
|
+
export function buildHeadersFromInput(inputHeaders) {
|
|
25
|
+
const headers = {};
|
|
26
|
+
if (inputHeaders) {
|
|
27
|
+
for (const [key, value] of Object.entries(inputHeaders)) {
|
|
28
|
+
headers[key] = Array.isArray(value) ? value[0] : value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Add default headers
|
|
32
|
+
fillDefaultHeaderInfo(headers);
|
|
33
|
+
return headers;
|
|
34
|
+
}
|
|
35
|
+
export function fillDefaultHeaderInfo(headers) {
|
|
36
|
+
headers["Host"] = DOMAIN_NAME[USER_ENVIRONMENT];
|
|
37
|
+
headers["User-Agent"] = "EBAY-API-MCP-Tool/1.0";
|
|
38
|
+
headers["Authorization"] = `Bearer ${USER_TOKEN}`;
|
|
39
|
+
headers["Content-Type"] = headers["Content-Type"] || "application/json";
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build final URL by replacing path variables with their values
|
|
43
|
+
*/
|
|
44
|
+
export function buildFinalUrl(url, urlVariables) {
|
|
45
|
+
if (urlVariables) {
|
|
46
|
+
for (const [key, value] of Object.entries(urlVariables)) {
|
|
47
|
+
url = url.replace(new RegExp(`%7B${key}%7D`, "g"), encodeURIComponent(String(value)));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return url;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* replace url domain name by environment
|
|
54
|
+
*/
|
|
55
|
+
export function replaceDomainNameByEnvironment(url) {
|
|
56
|
+
try {
|
|
57
|
+
const urlObj = new URL(url);
|
|
58
|
+
const currentHostname = urlObj.hostname;
|
|
59
|
+
const expectedDomain = DOMAIN_NAME[USER_ENVIRONMENT];
|
|
60
|
+
if (currentHostname !== expectedDomain) {
|
|
61
|
+
urlObj.hostname = expectedDomain;
|
|
62
|
+
return urlObj.toString();
|
|
63
|
+
}
|
|
64
|
+
return url;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
// Fallback to string replacement if URL parsing fails
|
|
68
|
+
const expectedDomain = DOMAIN_NAME[USER_ENVIRONMENT];
|
|
69
|
+
for (const [env, domain] of Object.entries(DOMAIN_NAME)) {
|
|
70
|
+
if (env !== USER_ENVIRONMENT && url.includes(domain)) {
|
|
71
|
+
return url.replace(domain, expectedDomain);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return url;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build base URL from OpenAPI servers object
|
|
79
|
+
*/
|
|
80
|
+
export function buildBaseUrlFromOpenApi(openapi) {
|
|
81
|
+
const serverObj = openapi.servers?.[0] || { url: "" };
|
|
82
|
+
let baseUrl = serverObj.url;
|
|
83
|
+
if (serverObj.variables) {
|
|
84
|
+
for (const [key, value] of Object.entries(serverObj.variables)) {
|
|
85
|
+
baseUrl = baseUrl.replace(`{${key}}`, value.default);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return replaceDomainNameByEnvironment(baseUrl);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve path variables in a URL pattern
|
|
92
|
+
*/
|
|
93
|
+
export function resolvePath(pathPattern, pathVariables) {
|
|
94
|
+
if (!pathVariables) {
|
|
95
|
+
return pathPattern;
|
|
96
|
+
}
|
|
97
|
+
return pathPattern.replace(/{([^}]+)}/g, (match, key) => {
|
|
98
|
+
const value = pathVariables[key];
|
|
99
|
+
if (value === undefined) {
|
|
100
|
+
throw new Error(`Missing path variable: ${key}`);
|
|
101
|
+
}
|
|
102
|
+
return String(value);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Prepare request data
|
|
107
|
+
*/
|
|
108
|
+
export function prepareRequestData(input, operation, path) {
|
|
109
|
+
let resolvedPath = path;
|
|
110
|
+
const headers = {};
|
|
111
|
+
const params = {};
|
|
112
|
+
let data = undefined;
|
|
113
|
+
const pathParams = {};
|
|
114
|
+
let prop = input.properties || {};
|
|
115
|
+
Object.entries(prop).forEach(([key, value]) => {
|
|
116
|
+
if (key === SCHEMA_REQUEST_BODY) {
|
|
117
|
+
data = value;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const paramDef = operation.parameters?.find(p => !("$ref" in p) && p.name === key);
|
|
121
|
+
if (paramDef) {
|
|
122
|
+
if (paramDef.in === "header") {
|
|
123
|
+
headers[key] = String(value);
|
|
124
|
+
}
|
|
125
|
+
else if (paramDef.in === "query") {
|
|
126
|
+
params[key] = value;
|
|
127
|
+
}
|
|
128
|
+
else if (paramDef.in === "path") {
|
|
129
|
+
pathParams[key] = String(value);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
fillDefaultHeaderInfo(headers);
|
|
135
|
+
if (Object.keys(pathParams).length > 0) {
|
|
136
|
+
resolvedPath = resolvePath(resolvedPath, pathParams);
|
|
137
|
+
}
|
|
138
|
+
return { resolvedPath, headers, params, data };
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=http-helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-helper.js","sourceRoot":"","sources":["../../src/helper/http-helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI helper functions, including loading OpenAPI documents,
|
|
3
|
+
* parsing OpenAPI specs, building schemas, and converting to Zod schemas.
|
|
4
|
+
*/
|
|
5
|
+
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import axios from "axios";
|
|
8
|
+
import * as yaml from "js-yaml";
|
|
9
|
+
import util from "util";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
const SCHEMA_REQUEST_BODY = "requestBody";
|
|
12
|
+
/**
|
|
13
|
+
* Get OpenAPI docs from user config file, which contains urls or paths of OpenAPI specs.
|
|
14
|
+
*/
|
|
15
|
+
export async function getOpenApiDocumentsFromConfigFile() {
|
|
16
|
+
const docs = [];
|
|
17
|
+
const urlFile = process.env.EBAY_API_DOC_URL_FILE;
|
|
18
|
+
let urls = [];
|
|
19
|
+
if (urlFile && fs.existsSync(urlFile)) {
|
|
20
|
+
// url or path each line in the file
|
|
21
|
+
urls = fs.readFileSync(urlFile, "utf-8").split(/\r?\n/)
|
|
22
|
+
.map(line => line.trim())
|
|
23
|
+
.filter(line => line.length > 0 && !line.startsWith("#"));
|
|
24
|
+
}
|
|
25
|
+
console.error("Loading OpenAPI specifications from:", urls);
|
|
26
|
+
// parse opebapi doc from url/path
|
|
27
|
+
for (const specPath of urls) {
|
|
28
|
+
try {
|
|
29
|
+
const doc = await SwaggerParser.dereference(specPath);
|
|
30
|
+
docs.push(doc);
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
console.error(`getOpenApiDocumentsFromConfigFile#[Failed to load OpenAPI doc from the specPath : ${specPath}]`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return docs;
|
|
37
|
+
}
|
|
38
|
+
// Helper: remove ignored keys recursively
|
|
39
|
+
export function readSchema2Map(obj) {
|
|
40
|
+
const SCHEMA_IGNORE_KEYS = ["style", "explode", "exampleSetFlag", "types", "in", "required"];
|
|
41
|
+
if (Array.isArray(obj)) {
|
|
42
|
+
return obj.map(readSchema2Map);
|
|
43
|
+
}
|
|
44
|
+
else if (obj && typeof obj === "object") {
|
|
45
|
+
const out = {};
|
|
46
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
47
|
+
if (!SCHEMA_IGNORE_KEYS.includes(k)) {
|
|
48
|
+
out[k] = readSchema2Map(v);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
return obj;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parse OpenAPI document from string (supports both JSON and YAML)
|
|
57
|
+
*/
|
|
58
|
+
export async function parseOpenApiDoc(specTitle, operationId, specUrl) {
|
|
59
|
+
const url = util.format(specUrl, specTitle, operationId);
|
|
60
|
+
const apiSpecRes = await axios.get(url, {
|
|
61
|
+
httpsAgent: new (await import("https")).Agent({
|
|
62
|
+
rejectUnauthorized: false,
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
const docString = apiSpecRes.data;
|
|
66
|
+
try {
|
|
67
|
+
// Try parsing as JSON first
|
|
68
|
+
return JSON.parse(docString);
|
|
69
|
+
}
|
|
70
|
+
catch (jsonError) {
|
|
71
|
+
try {
|
|
72
|
+
// If JSON fails, try parsing as YAML
|
|
73
|
+
return yaml.load(docString);
|
|
74
|
+
}
|
|
75
|
+
catch (yamlError) {
|
|
76
|
+
const _jsonMsg = jsonError instanceof Error ? jsonError.message : String(jsonError);
|
|
77
|
+
const _yamlMsg = yamlError instanceof Error ? yamlError.message : String(yamlError);
|
|
78
|
+
console.error("failed to parse OpenAPI document !!!");
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build schema for an operation's input parameters
|
|
85
|
+
*/
|
|
86
|
+
export function buildOperationSchema(operation) {
|
|
87
|
+
const properties = {};
|
|
88
|
+
// handle request param
|
|
89
|
+
(operation.parameters || []).forEach(param => {
|
|
90
|
+
if ("$ref" in param) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const paramSchema = readSchema2Map(param);
|
|
94
|
+
properties[param.name] = paramSchema;
|
|
95
|
+
});
|
|
96
|
+
// handle request body
|
|
97
|
+
if (operation.requestBody && "content" in operation.requestBody &&
|
|
98
|
+
operation.requestBody.content?.["application/json"]?.schema) {
|
|
99
|
+
const requestBodySchema = readSchema2Map(operation.requestBody.content["application/json"].schema);
|
|
100
|
+
properties[SCHEMA_REQUEST_BODY] = requestBodySchema;
|
|
101
|
+
}
|
|
102
|
+
return { properties };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build Zod validation schema
|
|
106
|
+
*/
|
|
107
|
+
export function buildZodSchema(properties) {
|
|
108
|
+
const zodProperties = {};
|
|
109
|
+
Object.keys(properties).forEach(key => {
|
|
110
|
+
zodProperties[key] = z.any();
|
|
111
|
+
});
|
|
112
|
+
return zodProperties;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=openapi-helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-helper.js","sourceRoot":"","sources":["../../src/helper/openapi-helper.ts"],"names":[],"mappings":"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"}
|