ebay-api 8.3.0 → 8.4.1
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 +45 -8
- package/dist/api/digitalSignature.d.ts +43 -0
- package/dist/api/digitalSignature.js +105 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +18 -0
- package/dist/api/restful/developer/keyManagement/index.d.ts +2 -4
- package/dist/api/restful/developer/keyManagement/index.js +5 -3
- package/dist/api/restful/index.d.ts +12 -7
- package/dist/api/restful/index.js +33 -17
- package/dist/api/traditional/XMLRequest.d.ts +3 -1
- package/dist/api/traditional/XMLRequest.js +3 -1
- package/dist/api/traditional/index.d.ts +1 -1
- package/dist/api/traditional/index.js +25 -15
- package/dist/eBayApi.d.ts +2 -1
- package/dist/eBayApi.js +12 -1
- package/dist/ebay-api.min.mjs +1 -1
- package/dist/errors/index.js +5 -0
- package/dist/types/apiTypes.d.ts +7 -0
- package/dist/types/traditonalTypes.d.ts +2 -1
- package/lib/api/digitalSignature.d.ts +43 -0
- package/lib/api/digitalSignature.js +112 -0
- package/lib/api/index.d.ts +2 -0
- package/lib/api/index.js +18 -0
- package/lib/api/restful/developer/keyManagement/index.d.ts +2 -4
- package/lib/api/restful/developer/keyManagement/index.js +5 -3
- package/lib/api/restful/index.d.ts +12 -7
- package/lib/api/restful/index.js +37 -21
- package/lib/api/traditional/XMLRequest.d.ts +3 -1
- package/lib/api/traditional/XMLRequest.js +2 -0
- package/lib/api/traditional/index.d.ts +1 -1
- package/lib/api/traditional/index.js +29 -19
- package/lib/eBayApi.d.ts +2 -1
- package/lib/eBayApi.js +12 -1
- package/lib/ebay-api.min.js +1 -1
- package/lib/errors/index.js +5 -0
- package/lib/types/apiTypes.d.ts +7 -0
- package/lib/types/traditonalTypes.d.ts +2 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/ebay-api)
|
|
10
10
|
|
|
11
11
|
This eBay API implements both Traditional \(xml\) and the RESTful eBay API.
|
|
12
|
-
It supports `client credentials grant` and `authorization code grant` \(Auth'N'Auth, OAuth2 and IAF\).
|
|
12
|
+
It supports `client credentials grant` and `authorization code grant` \(Auth'N'Auth, OAuth2 and IAF\). Digital Signature is supported too.
|
|
13
13
|
|
|
14
14
|
* [API Browser Examples](https://hendt.github.io/ebay-api/)
|
|
15
15
|
* [API Documentation](https://hendt.gitbook.io/ebay-api/)
|
|
@@ -21,7 +21,7 @@ It supports `client credentials grant` and `authorization code grant` \(Auth'N'A
|
|
|
21
21
|
|
|
22
22
|
## Changelog
|
|
23
23
|
|
|
24
|
-
* `v8.
|
|
24
|
+
* `v8.4.1` is the latest release.
|
|
25
25
|
* See [here](https://github.com/hendt/ebay-api/blob/master/CHANGELOG.md) for the full changelog.
|
|
26
26
|
|
|
27
27
|
## Implementation status
|
|
@@ -88,9 +88,9 @@ const eBay = new eBayApi({
|
|
|
88
88
|
|
|
89
89
|
siteId: eBayApi.SiteId.EBAY_US, // required for traditional APIs, see https://developer.ebay.com/DevZone/merchandising/docs/Concepts/SiteIDToGlobalID.html
|
|
90
90
|
|
|
91
|
-
marketplaceId: eBayApi.MarketplaceId.EBAY_US, //
|
|
92
|
-
acceptLanguage: eBayApi.Locale.en_US, //
|
|
93
|
-
contentLanguage: eBayApi.ContentLanguage.en_US, //
|
|
91
|
+
marketplaceId: eBayApi.MarketplaceId.EBAY_US, // default. required for RESTful APIs
|
|
92
|
+
acceptLanguage: eBayApi.Locale.en_US, // default
|
|
93
|
+
contentLanguage: eBayApi.ContentLanguage.en_US, // default.
|
|
94
94
|
|
|
95
95
|
// optional parameters, should be omitted if not used
|
|
96
96
|
devId: '-- devId --', // required for traditional Trading API
|
|
@@ -254,6 +254,8 @@ This is how it would look like if you use `express`:
|
|
|
254
254
|
```javascript
|
|
255
255
|
import eBayApi from 'ebay-api';
|
|
256
256
|
|
|
257
|
+
|
|
258
|
+
// This is your RUName endpoint like https://your-ebay.app/success
|
|
257
259
|
app.get('/success', async function (req, res) {
|
|
258
260
|
// 3. Get the parameter code that is placed as query parameter in redirected page
|
|
259
261
|
const code = req.query.code; // this is provided from eBay
|
|
@@ -306,6 +308,41 @@ app.get('/orders/:id', async function (req, res) {
|
|
|
306
308
|
});
|
|
307
309
|
```
|
|
308
310
|
|
|
311
|
+
## Digital Signature
|
|
312
|
+
Signatures are required when the call is made for EU- or UK-domiciled sellers, and only for the following APIs/methods:
|
|
313
|
+
|
|
314
|
+
* All methods in the Finances API -> (`eBay.finances.XXX.sign.YYY()`)
|
|
315
|
+
* issueRefund in the Fulfillment API -> (`eBay.sell.fulfillment.sign.issueRefund()`)
|
|
316
|
+
* GetAccount in the Trading API -> (`eBay.trading.GetAccount(null, { sign: true }))`)
|
|
317
|
+
* The following methods in the Post-Order API:
|
|
318
|
+
- Issue Inquiry Refund -> (`eBay.postOrder.inquiry.sign.issueInquiryRefund()`)
|
|
319
|
+
- Issue case refund -> (`eBay.postOrder.inquiry.sign.issueCaseRefund()`)
|
|
320
|
+
- Issue return refund -> (`eBay.postOrder.inquiry.sign.issueReturnRefund()`)
|
|
321
|
+
- Process Return Request -> (`eBay.postOrder.inquiry.sign.processReturnRequest()`)
|
|
322
|
+
- Create Cancellation Request -> (`eBay.postOrder.inquiry.sign.createCancellation()`)
|
|
323
|
+
- Approve Cancellation Request -> (`eBay.postOrder.inquiry.sign.approveCancellationRequest()`)
|
|
324
|
+
|
|
325
|
+
### How to use Digital Signature
|
|
326
|
+
```js
|
|
327
|
+
// 1. Create singning key and save it appropriatly
|
|
328
|
+
const signingKey = await eBay.developer.keyManagement.createSigningKey('ED25519');
|
|
329
|
+
// 2. Set the signature
|
|
330
|
+
eBay.setSignature(signingKey)
|
|
331
|
+
// or in constructor
|
|
332
|
+
eBay = new eBayApi({
|
|
333
|
+
appId: '...',
|
|
334
|
+
certId: '...',
|
|
335
|
+
signature: {
|
|
336
|
+
jwe: signingKey.jwe,
|
|
337
|
+
privateKey: signingKey.privateKey
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
// 3. Use the 'sign' keyword in Restful API
|
|
341
|
+
const summary = await eBay.sell.finances.sign.getSellerFundsSummary();
|
|
342
|
+
// 3. Or the 'sign' parameter in traditional API
|
|
343
|
+
const account = await eBay.trading.GetAccount(null, {sign: true});
|
|
344
|
+
```
|
|
345
|
+
|
|
309
346
|
## RESTful API
|
|
310
347
|
|
|
311
348
|
### How to set the Scope
|
|
@@ -340,7 +377,7 @@ In any case eBay adds a new subdomain, it's also possible to configure whatever
|
|
|
340
377
|
eBay.buy.browse.api({subdomain: 'apiy'}).getItem() // now it will use https://apiy.ebay.com
|
|
341
378
|
```
|
|
342
379
|
|
|
343
|
-
###
|
|
380
|
+
### Return raw RESTful API response
|
|
344
381
|
|
|
345
382
|
```javascript
|
|
346
383
|
eBay.buy.browse.api({
|
|
@@ -368,8 +405,8 @@ eBay.OAuth2.on('refreshClientToken', (token) => {
|
|
|
368
405
|
});
|
|
369
406
|
```
|
|
370
407
|
|
|
371
|
-
To
|
|
372
|
-
token `eBay.OAuth2.refreshClientToken()`.
|
|
408
|
+
To manual refresh the auth token use `eBay.OAuth2.refreshAuthToken()` and for the client
|
|
409
|
+
token use `eBay.OAuth2.refreshClientToken()`.
|
|
373
410
|
Keep in mind that you need the 'refresh_token' value set.
|
|
374
411
|
|
|
375
412
|
```javascript
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Cipher, Headers } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates the 'Content-Digest' header value for the input payload.
|
|
4
|
+
*
|
|
5
|
+
* @param {any} payload The request payload.
|
|
6
|
+
* @param {string} cipher The algorithm used to calculate the digest.
|
|
7
|
+
* @returns {string} contentDigest The 'Content-Digest' header value.
|
|
8
|
+
*/
|
|
9
|
+
export declare const generateContentDigestValue: (payload: unknown, cipher?: Cipher) => string;
|
|
10
|
+
export type SignatureComponents = {
|
|
11
|
+
method: string;
|
|
12
|
+
authority: string;
|
|
13
|
+
path: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Generates the base string.
|
|
17
|
+
*
|
|
18
|
+
* @param {any} headers The HTTP request headers.
|
|
19
|
+
* @param {SignatureComponents} signatureComponents The config.
|
|
20
|
+
* @param {any} payload The payload.
|
|
21
|
+
* @param {number} timestamp The timestamp.
|
|
22
|
+
* @returns {string} payload The base string.
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateBaseString(headers: Headers, signatureComponents: SignatureComponents, payload: any, timestamp?: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Generates the Signature-Input header value for the input payload.
|
|
27
|
+
*
|
|
28
|
+
* @param {any} payload The input config.
|
|
29
|
+
* @param {number} timestamp The timestamp.
|
|
30
|
+
* @returns {string} the 'Signature-Input' header value.
|
|
31
|
+
*/
|
|
32
|
+
export declare const generateSignatureInput: (payload: any, timestamp?: number) => string;
|
|
33
|
+
/**
|
|
34
|
+
* Generates the 'Signature' header.
|
|
35
|
+
*
|
|
36
|
+
* @param {any} headers The HTTP headers.
|
|
37
|
+
* @param {string} privateKey The HTTP headers.
|
|
38
|
+
* @param {SignatureComponents} signatureComponents The signature components
|
|
39
|
+
* @param {any} payload The payload
|
|
40
|
+
* @param {number} timestamp The payload
|
|
41
|
+
* @returns {string} the signature header value.
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateSignature(headers: any, privateKey: string, signatureComponents: SignatureComponents, payload: any, timestamp?: number): string;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { createHash, sign } from 'crypto';
|
|
2
|
+
const beginPrivateKey = '-----BEGIN PRIVATE KEY-----';
|
|
3
|
+
const endPrivateKey = '-----END PRIVATE KEY-----';
|
|
4
|
+
// based on https://github.com/ebay/digital-signature-nodejs-sdk
|
|
5
|
+
/**
|
|
6
|
+
* Returns the current UNIX timestamp.
|
|
7
|
+
*
|
|
8
|
+
* @returns {number} The unix timestamp.
|
|
9
|
+
*/
|
|
10
|
+
const getUnixTimestamp = () => Date.now() / 1000 | 0;
|
|
11
|
+
const getSignatureParams = (payload) => [
|
|
12
|
+
...payload ? ['content-digest'] : [],
|
|
13
|
+
'x-ebay-signature-key',
|
|
14
|
+
'@method',
|
|
15
|
+
'@path',
|
|
16
|
+
'@authority'
|
|
17
|
+
];
|
|
18
|
+
const getSignatureParamsValue = (payload) => getSignatureParams(payload).map(param => `"${param}"`).join(' ');
|
|
19
|
+
/**
|
|
20
|
+
* Generates the 'Content-Digest' header value for the input payload.
|
|
21
|
+
*
|
|
22
|
+
* @param {any} payload The request payload.
|
|
23
|
+
* @param {string} cipher The algorithm used to calculate the digest.
|
|
24
|
+
* @returns {string} contentDigest The 'Content-Digest' header value.
|
|
25
|
+
*/
|
|
26
|
+
export const generateContentDigestValue = (payload, cipher = 'sha256') => {
|
|
27
|
+
const payloadBuffer = Buffer.from(typeof payload === 'string' ? payload : JSON.stringify(payload));
|
|
28
|
+
const hash = createHash(cipher).update(payloadBuffer).digest('base64');
|
|
29
|
+
const algo = cipher === 'sha512' ? 'sha-512' : 'sha-256';
|
|
30
|
+
return `${algo}=:${hash}:`;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Generates the base string.
|
|
34
|
+
*
|
|
35
|
+
* @param {any} headers The HTTP request headers.
|
|
36
|
+
* @param {SignatureComponents} signatureComponents The config.
|
|
37
|
+
* @param {any} payload The payload.
|
|
38
|
+
* @param {number} timestamp The timestamp.
|
|
39
|
+
* @returns {string} payload The base string.
|
|
40
|
+
*/
|
|
41
|
+
export function generateBaseString(headers, signatureComponents, payload, timestamp = getUnixTimestamp()) {
|
|
42
|
+
try {
|
|
43
|
+
let baseString = '';
|
|
44
|
+
const signatureParams = getSignatureParams(payload);
|
|
45
|
+
signatureParams.forEach(param => {
|
|
46
|
+
baseString += `"${param.toLowerCase()}": `;
|
|
47
|
+
if (param.startsWith('@')) {
|
|
48
|
+
switch (param.toLowerCase()) {
|
|
49
|
+
case '@method':
|
|
50
|
+
baseString += signatureComponents.method;
|
|
51
|
+
break;
|
|
52
|
+
case '@authority':
|
|
53
|
+
baseString += signatureComponents.authority;
|
|
54
|
+
break;
|
|
55
|
+
case '@path':
|
|
56
|
+
baseString += signatureComponents.path;
|
|
57
|
+
break;
|
|
58
|
+
default:
|
|
59
|
+
throw new Error('Unknown pseudo header ' + param);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
if (!headers[param]) {
|
|
64
|
+
throw new Error('Header ' + param + ' not included in message');
|
|
65
|
+
}
|
|
66
|
+
baseString += headers[param];
|
|
67
|
+
}
|
|
68
|
+
baseString += '\n';
|
|
69
|
+
});
|
|
70
|
+
baseString += `"@signature-params": (${getSignatureParamsValue(payload)});created=${timestamp}`;
|
|
71
|
+
return baseString;
|
|
72
|
+
}
|
|
73
|
+
catch (ex) {
|
|
74
|
+
throw new Error(`Error calculating signature base: ${ex.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Generates the Signature-Input header value for the input payload.
|
|
79
|
+
*
|
|
80
|
+
* @param {any} payload The input config.
|
|
81
|
+
* @param {number} timestamp The timestamp.
|
|
82
|
+
* @returns {string} the 'Signature-Input' header value.
|
|
83
|
+
*/
|
|
84
|
+
export const generateSignatureInput = (payload, timestamp = getUnixTimestamp()) => `sig1=(${getSignatureParamsValue(payload)});created=${timestamp}`;
|
|
85
|
+
/**
|
|
86
|
+
* Generates the 'Signature' header.
|
|
87
|
+
*
|
|
88
|
+
* @param {any} headers The HTTP headers.
|
|
89
|
+
* @param {string} privateKey The HTTP headers.
|
|
90
|
+
* @param {SignatureComponents} signatureComponents The signature components
|
|
91
|
+
* @param {any} payload The payload
|
|
92
|
+
* @param {number} timestamp The payload
|
|
93
|
+
* @returns {string} the signature header value.
|
|
94
|
+
*/
|
|
95
|
+
export function generateSignature(headers, privateKey, signatureComponents, payload, timestamp = getUnixTimestamp()) {
|
|
96
|
+
const baseString = generateBaseString(headers, signatureComponents, payload, timestamp);
|
|
97
|
+
privateKey = privateKey.trim();
|
|
98
|
+
if (!privateKey.startsWith(beginPrivateKey)) {
|
|
99
|
+
privateKey = beginPrivateKey + '\n' + privateKey + '\n' + endPrivateKey;
|
|
100
|
+
}
|
|
101
|
+
const signatureBuffer = sign(undefined, // If algorithm is undefined, then it is dependent upon the private key type.
|
|
102
|
+
Buffer.from(baseString), privateKey);
|
|
103
|
+
const signature = signatureBuffer.toString('base64');
|
|
104
|
+
return `sig1=:${signature}:`;
|
|
105
|
+
}
|
package/dist/api/index.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ import Auth from '../auth/index.js';
|
|
|
2
2
|
import { IEBayApiRequest } from '../request.js';
|
|
3
3
|
import { AppConfig } from '../types/index.js';
|
|
4
4
|
import Base from './base.js';
|
|
5
|
+
import { SignatureComponents } from './digitalSignature.js';
|
|
5
6
|
/**
|
|
6
7
|
* Superclass with Auth container.
|
|
7
8
|
*/
|
|
8
9
|
export default abstract class Api extends Base {
|
|
9
10
|
readonly auth: Auth;
|
|
10
11
|
constructor(config: AppConfig, req?: IEBayApiRequest, auth?: Auth);
|
|
12
|
+
getDigitalSignatureHeaders(signatureComponents: SignatureComponents, payload: any): {};
|
|
11
13
|
}
|
package/dist/api/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Auth from '../auth/index.js';
|
|
2
2
|
import Base from './base.js';
|
|
3
|
+
import { generateContentDigestValue, generateSignature, generateSignatureInput } from './digitalSignature.js';
|
|
3
4
|
/**
|
|
4
5
|
* Superclass with Auth container.
|
|
5
6
|
*/
|
|
@@ -8,4 +9,21 @@ export default class Api extends Base {
|
|
|
8
9
|
super(config, req);
|
|
9
10
|
this.auth = auth || new Auth(this.config, this.req);
|
|
10
11
|
}
|
|
12
|
+
getDigitalSignatureHeaders(signatureComponents, payload) {
|
|
13
|
+
if (!this.config.signature) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
const digitalSignatureHeaders = {
|
|
17
|
+
'x-ebay-enforce-signature': true,
|
|
18
|
+
'x-ebay-signature-key': this.config.signature.jwe,
|
|
19
|
+
...payload ? {
|
|
20
|
+
'content-digest': generateContentDigestValue(payload, this.config.signature.cipher ?? 'sha256')
|
|
21
|
+
} : {},
|
|
22
|
+
'signature-input': generateSignatureInput(payload)
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
...digitalSignatureHeaders,
|
|
26
|
+
'signature': generateSignature(digitalSignatureHeaders, this.config.signature.privateKey, signatureComponents, payload)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
11
29
|
}
|
|
@@ -12,11 +12,9 @@ export default class KeyManagement extends Restful {
|
|
|
12
12
|
*/
|
|
13
13
|
getSigningKeys(): Promise<any>;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* This method creates keypairs.
|
|
16
16
|
*/
|
|
17
|
-
createSigningKey(
|
|
18
|
-
signingKeyCipher: string;
|
|
19
|
-
}): Promise<any>;
|
|
17
|
+
createSigningKey(signingKeyCipher: 'ED25519' | 'RSA'): Promise<any>;
|
|
20
18
|
/**
|
|
21
19
|
* This method returns the <b>Public Key</b>, <b>Public Key as JWE</b>,
|
|
22
20
|
* and metadata for a specified <code>signingKeyId</code> associated with the application key making the call.
|
|
@@ -17,10 +17,12 @@ export default class KeyManagement extends Restful {
|
|
|
17
17
|
return this.get(`/signing_key`);
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* This method creates keypairs.
|
|
21
21
|
*/
|
|
22
|
-
createSigningKey(
|
|
23
|
-
return this.post(`/signing_key`,
|
|
22
|
+
createSigningKey(signingKeyCipher) {
|
|
23
|
+
return this.post(`/signing_key`, {
|
|
24
|
+
signingKeyCipher
|
|
25
|
+
});
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
26
28
|
* This method returns the <b>Public Key</b>, <b>Public Key as JWE</b>,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import Api from '../index.js';
|
|
2
1
|
import Auth from '../../auth/index.js';
|
|
3
2
|
import { IEBayApiRequest } from '../../request.js';
|
|
4
3
|
import { ApiRequestConfig, AppConfig } from '../../types/index.js';
|
|
4
|
+
import Api from '../index.js';
|
|
5
5
|
export declare const defaultApiHeaders: Record<string, string>;
|
|
6
6
|
export type RestfulApiConfig = {
|
|
7
7
|
subdomain?: string;
|
|
8
8
|
useIaf?: boolean;
|
|
9
|
+
sign?: boolean;
|
|
9
10
|
apiVersion?: string;
|
|
10
11
|
basePath?: string;
|
|
11
12
|
schema?: string;
|
|
@@ -14,7 +15,7 @@ export type RestfulApiConfig = {
|
|
|
14
15
|
} & ApiRequestConfig;
|
|
15
16
|
export type ApiRequest = {
|
|
16
17
|
method: keyof IEBayApiRequest;
|
|
17
|
-
|
|
18
|
+
path: string;
|
|
18
19
|
config?: any;
|
|
19
20
|
data?: any;
|
|
20
21
|
};
|
|
@@ -50,12 +51,16 @@ export default abstract class Restful extends Api {
|
|
|
50
51
|
* Use "apiz" subdomain
|
|
51
52
|
*/
|
|
52
53
|
get apiz(): this;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Sign request
|
|
56
|
+
*/
|
|
57
|
+
get sign(): this;
|
|
58
|
+
get(path: string, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
|
|
59
|
+
delete(path: string, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
|
|
60
|
+
post(path: string, data?: any, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
|
|
61
|
+
put(path: string, data?: any, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
|
|
57
62
|
get additionalHeaders(): any;
|
|
58
|
-
enrichRequestConfig(
|
|
63
|
+
enrichRequestConfig(apiRequest: ApiRequest, payload?: any, apiConfig?: Required<RestfulApiConfig>): Promise<any>;
|
|
59
64
|
private doRequest;
|
|
60
65
|
private shouldRefreshToken;
|
|
61
66
|
private request;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Api from '../index.js';
|
|
2
1
|
import { EBayInvalidAccessToken, handleEBayError } from '../../errors/index.js';
|
|
2
|
+
import Api from '../index.js';
|
|
3
3
|
export const defaultApiHeaders = {
|
|
4
4
|
'Content-Type': 'application/json',
|
|
5
5
|
'Cache-Control': 'no-cache',
|
|
@@ -53,7 +53,8 @@ export default class Restful extends Api {
|
|
|
53
53
|
sandbox: this.config.sandbox,
|
|
54
54
|
tld: 'ebay.com',
|
|
55
55
|
headers: {},
|
|
56
|
-
returnResponse: false
|
|
56
|
+
returnResponse: false,
|
|
57
|
+
sign: false
|
|
57
58
|
};
|
|
58
59
|
}
|
|
59
60
|
get baseUrl() {
|
|
@@ -79,17 +80,23 @@ export default class Restful extends Api {
|
|
|
79
80
|
get apiz() {
|
|
80
81
|
return this.api({ subdomain: 'apiz' });
|
|
81
82
|
}
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Sign request
|
|
85
|
+
*/
|
|
86
|
+
get sign() {
|
|
87
|
+
return this.api({ sign: true });
|
|
84
88
|
}
|
|
85
|
-
async
|
|
86
|
-
return this.doRequest({ method: '
|
|
89
|
+
async get(path, config = {}, apiConfig) {
|
|
90
|
+
return this.doRequest({ method: 'get', path, config }, apiConfig);
|
|
87
91
|
}
|
|
88
|
-
async
|
|
89
|
-
return this.doRequest({ method: '
|
|
92
|
+
async delete(path, config = {}, apiConfig) {
|
|
93
|
+
return this.doRequest({ method: 'delete', path, config }, apiConfig);
|
|
90
94
|
}
|
|
91
|
-
async
|
|
92
|
-
return this.doRequest({ method: '
|
|
95
|
+
async post(path, data, config = {}, apiConfig) {
|
|
96
|
+
return this.doRequest({ method: 'post', path, data, config }, apiConfig);
|
|
97
|
+
}
|
|
98
|
+
async put(path, data, config = {}, apiConfig) {
|
|
99
|
+
return this.doRequest({ method: 'put', path, data, config }, apiConfig);
|
|
93
100
|
}
|
|
94
101
|
get additionalHeaders() {
|
|
95
102
|
return Object.keys(additionalHeaders)
|
|
@@ -101,18 +108,24 @@ export default class Restful extends Api {
|
|
|
101
108
|
return headers;
|
|
102
109
|
}, {});
|
|
103
110
|
}
|
|
104
|
-
async enrichRequestConfig(
|
|
111
|
+
async enrichRequestConfig(apiRequest, payload = null, apiConfig = this.apiConfig) {
|
|
105
112
|
const authHeader = await this.auth.getHeaderAuthorization(apiConfig.useIaf);
|
|
113
|
+
const signatureHeaders = apiConfig.sign ? this.getDigitalSignatureHeaders({
|
|
114
|
+
method: apiRequest.method.toUpperCase(),
|
|
115
|
+
authority: Restful.buildServerUrl('', apiConfig.subdomain, apiConfig.sandbox, apiConfig.tld),
|
|
116
|
+
path: apiConfig.apiVersion + apiConfig.basePath + apiRequest.path
|
|
117
|
+
}, payload) : {};
|
|
106
118
|
const headers = {
|
|
107
119
|
...defaultApiHeaders,
|
|
108
120
|
...this.additionalHeaders,
|
|
109
121
|
...authHeader,
|
|
110
|
-
...apiConfig.headers
|
|
122
|
+
...apiConfig.headers,
|
|
123
|
+
...signatureHeaders
|
|
111
124
|
};
|
|
112
125
|
return {
|
|
113
|
-
...config,
|
|
126
|
+
...apiRequest.config,
|
|
114
127
|
headers: {
|
|
115
|
-
...(config.headers || {}),
|
|
128
|
+
...(apiRequest.config.headers || {}),
|
|
116
129
|
...headers
|
|
117
130
|
}
|
|
118
131
|
};
|
|
@@ -136,17 +149,20 @@ export default class Restful extends Api {
|
|
|
136
149
|
if (error.name === EBayInvalidAccessToken.name) {
|
|
137
150
|
return true;
|
|
138
151
|
}
|
|
152
|
+
else if (error?.meta?.res?.status === 403 && this.apiConfig.basePath === '/sell/inventory/v1') {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
139
155
|
return error?.meta?.res?.status === 401 && this.apiConfig.basePath === '/post-order/v2';
|
|
140
156
|
}
|
|
141
157
|
async request(apiRequest, apiConfig = this.apiConfig, refreshToken = false) {
|
|
142
|
-
const {
|
|
158
|
+
const { path, method, data } = apiRequest;
|
|
143
159
|
const apiCfg = { ...this.apiConfig, ...apiConfig };
|
|
144
|
-
const endpoint = this.getServerUrl(apiCfg) +
|
|
160
|
+
const endpoint = this.getServerUrl(apiCfg) + path;
|
|
145
161
|
try {
|
|
146
162
|
if (refreshToken) {
|
|
147
163
|
await this.auth.OAuth2.refreshToken();
|
|
148
164
|
}
|
|
149
|
-
const enrichedConfig = await this.enrichRequestConfig(
|
|
165
|
+
const enrichedConfig = await this.enrichRequestConfig(apiRequest, data, apiCfg);
|
|
150
166
|
const args = ['get', 'delete'].includes(method) ? [enrichedConfig] : [data, enrichedConfig];
|
|
151
167
|
// @ts-ignore
|
|
152
168
|
const response = await this.req[method](endpoint, ...args);
|
|
@@ -34,12 +34,14 @@ export type TraditionalApiConfig = {
|
|
|
34
34
|
raw?: boolean;
|
|
35
35
|
parseOptions?: object;
|
|
36
36
|
useIaf?: boolean;
|
|
37
|
+
sign?: boolean;
|
|
37
38
|
hook?: (xml: string) => BodyHeaders;
|
|
38
39
|
} & ApiRequestConfig;
|
|
39
40
|
export type XMLReqConfig = TraditionalApiConfig & {
|
|
40
41
|
endpoint: string;
|
|
41
42
|
xmlns: string;
|
|
42
43
|
eBayAuthToken?: string | null;
|
|
44
|
+
digitalSignatureHeaders?: (payload: any) => Headers;
|
|
43
45
|
};
|
|
44
46
|
export declare const defaultApiConfig: Required<Omit<TraditionalApiConfig, 'hook'>>;
|
|
45
47
|
export declare const defaultHeaders: {
|
|
@@ -63,7 +65,7 @@ export default class XMLRequest {
|
|
|
63
65
|
* @param {Object} req the request
|
|
64
66
|
* @param {XMLReqConfig} config
|
|
65
67
|
*/
|
|
66
|
-
constructor(callName: string, fields: Fields, config: XMLReqConfig, req: IEBayApiRequest);
|
|
68
|
+
constructor(callName: string, fields: Fields | null, config: XMLReqConfig, req: IEBayApiRequest);
|
|
67
69
|
/**
|
|
68
70
|
* returns the expected name of XML node of a Request
|
|
69
71
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
|
-
import {
|
|
2
|
+
import { XMLBuilder, XMLParser } from 'fast-xml-parser';
|
|
3
3
|
import { checkEBayResponse, EbayNoCallError } from '../../errors/index.js';
|
|
4
4
|
const log = debug('ebay:xml:request');
|
|
5
5
|
export const defaultJSON2XMLOptions = {
|
|
@@ -32,6 +32,7 @@ export const defaultApiConfig = {
|
|
|
32
32
|
raw: false,
|
|
33
33
|
parseOptions: defaultXML2JSONParseOptions,
|
|
34
34
|
useIaf: true,
|
|
35
|
+
sign: false,
|
|
35
36
|
headers: {},
|
|
36
37
|
returnResponse: false
|
|
37
38
|
};
|
|
@@ -137,6 +138,7 @@ export default class XMLRequest {
|
|
|
137
138
|
const config = {
|
|
138
139
|
headers: {
|
|
139
140
|
...this.getHeaders(),
|
|
141
|
+
...this.config.digitalSignatureHeaders ? this.config.digitalSignatureHeaders(body) : {},
|
|
140
142
|
...(headers ? headers : {})
|
|
141
143
|
}
|
|
142
144
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stringify } from 'qs';
|
|
2
|
-
import Api from '../index.js';
|
|
3
2
|
import { EBayIAFTokenExpired, EBayIAFTokenInvalid, handleEBayError } from '../../errors/index.js';
|
|
3
|
+
import Api from '../index.js';
|
|
4
4
|
import ClientAlertsCalls from './clientAlerts/index.js';
|
|
5
5
|
import FindingCalls from './finding/index.js';
|
|
6
6
|
import MerchandisingCalls from './merchandising/index.js';
|
|
@@ -28,17 +28,15 @@ export default class Traditional extends Api {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
createTradingApi() {
|
|
31
|
-
if (!this.config.devId) {
|
|
32
|
-
throw new Error('devId is required for trading API.');
|
|
33
|
-
}
|
|
34
31
|
if (typeof this.config.siteId !== 'number') {
|
|
35
32
|
throw new Error('siteId is required for trading API.');
|
|
36
33
|
}
|
|
37
34
|
return this.createTraditionalXMLApi({
|
|
38
35
|
endpoint: {
|
|
39
|
-
production: '
|
|
40
|
-
sandbox: '
|
|
36
|
+
production: 'api.ebay.com',
|
|
37
|
+
sandbox: 'api.sandbox.ebay.com'
|
|
41
38
|
},
|
|
39
|
+
path: '/ws/api.dll',
|
|
42
40
|
calls: TradingCalls,
|
|
43
41
|
xmlns: 'urn:ebay:apis:eBLBaseComponents',
|
|
44
42
|
headers: (callName, accessToken) => ({
|
|
@@ -58,9 +56,10 @@ export default class Traditional extends Api {
|
|
|
58
56
|
}
|
|
59
57
|
return this.createTraditionalXMLApi({
|
|
60
58
|
endpoint: {
|
|
61
|
-
production: '
|
|
62
|
-
sandbox: '
|
|
59
|
+
production: 'open.api.ebay.com',
|
|
60
|
+
sandbox: 'open.api.sandbox.ebay.com'
|
|
63
61
|
},
|
|
62
|
+
path: '/shopping',
|
|
64
63
|
xmlns: 'urn:ebay:apis:eBLBaseComponents',
|
|
65
64
|
calls: ShoppingCalls,
|
|
66
65
|
headers: (callName, accessToken) => ({
|
|
@@ -76,9 +75,10 @@ export default class Traditional extends Api {
|
|
|
76
75
|
createFindingApi() {
|
|
77
76
|
return this.createTraditionalXMLApi({
|
|
78
77
|
endpoint: {
|
|
79
|
-
production: '
|
|
80
|
-
sandbox: '
|
|
78
|
+
production: 'svcs.ebay.com',
|
|
79
|
+
sandbox: 'svcs.sandbox.ebay.com'
|
|
81
80
|
},
|
|
81
|
+
path: '/services/search/FindingService/v1',
|
|
82
82
|
xmlns: 'http://www.ebay.com/marketplace/search/v1/services',
|
|
83
83
|
calls: FindingCalls,
|
|
84
84
|
headers: (callName) => ({
|
|
@@ -93,9 +93,10 @@ export default class Traditional extends Api {
|
|
|
93
93
|
}
|
|
94
94
|
const api = {
|
|
95
95
|
endpoint: {
|
|
96
|
-
production: '
|
|
97
|
-
sandbox: '
|
|
96
|
+
production: 'clientalerts.ebay.com',
|
|
97
|
+
sandbox: 'clientalerts.sandbox.ebay.com'
|
|
98
98
|
},
|
|
99
|
+
path: '/ws/ecasvc/ClientAlerts',
|
|
99
100
|
calls: ClientAlertsCalls
|
|
100
101
|
};
|
|
101
102
|
const endpoint = api.endpoint[this.config.sandbox ? 'sandbox' : 'production'];
|
|
@@ -129,9 +130,10 @@ export default class Traditional extends Api {
|
|
|
129
130
|
createMerchandisingApi() {
|
|
130
131
|
return this.createTraditionalXMLApi({
|
|
131
132
|
endpoint: {
|
|
132
|
-
production: '
|
|
133
|
-
sandbox: '
|
|
133
|
+
production: 'svcs.ebay.com',
|
|
134
|
+
sandbox: 'svcs.sandbox.ebay.com'
|
|
134
135
|
},
|
|
136
|
+
path: '/MerchandisingService',
|
|
135
137
|
xmlns: 'http://www.ebay.com/marketplace/services',
|
|
136
138
|
calls: MerchandisingCalls,
|
|
137
139
|
headers: (callName) => ({
|
|
@@ -160,14 +162,22 @@ export default class Traditional extends Api {
|
|
|
160
162
|
const eBayAuthToken = this.auth.authNAuth.eBayAuthToken;
|
|
161
163
|
const accessToken = !eBayAuthToken && apiConfig.useIaf ? (await this.auth.OAuth2.getAccessToken()) : null;
|
|
162
164
|
const useIaf = !eBayAuthToken && accessToken;
|
|
165
|
+
const host = this.config.sandbox ? api.endpoint.sandbox : api.endpoint.production;
|
|
163
166
|
return {
|
|
164
167
|
...apiConfig,
|
|
165
168
|
xmlns: api.xmlns,
|
|
166
|
-
endpoint: api.
|
|
169
|
+
endpoint: `https://${host}${api.path}`,
|
|
167
170
|
headers: {
|
|
168
171
|
...api.headers(callName, useIaf ? accessToken : null),
|
|
169
172
|
...apiConfig.headers
|
|
170
173
|
},
|
|
174
|
+
digitalSignatureHeaders: payload => {
|
|
175
|
+
return apiConfig.sign ? this.getDigitalSignatureHeaders({
|
|
176
|
+
method: 'POST',
|
|
177
|
+
authority: host,
|
|
178
|
+
path: api.path
|
|
179
|
+
}, payload) : {};
|
|
180
|
+
},
|
|
171
181
|
...(!useIaf ? { eBayAuthToken } : {})
|
|
172
182
|
};
|
|
173
183
|
}
|
package/dist/eBayApi.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { ContentLanguage, Locale, MarketplaceId, SiteId } from './enums/index.js
|
|
|
11
11
|
import * as errors from './errors/index.js';
|
|
12
12
|
import { IEBayApiRequest } from './request.js';
|
|
13
13
|
import * as types from './types/index.js';
|
|
14
|
-
import { AppConfig, ClientAlerts, Finding, Merchandising, Shopping, Trading } from './types/index.js';
|
|
14
|
+
import { AppConfig, ClientAlerts, Finding, Merchandising, Shopping, Signature, Trading } from './types/index.js';
|
|
15
15
|
export default class eBayApi extends Api {
|
|
16
16
|
static readonly SiteId: typeof enums.SiteId;
|
|
17
17
|
static readonly MarketplaceId: typeof enums.MarketplaceId;
|
|
@@ -54,5 +54,6 @@ export default class eBayApi extends Api {
|
|
|
54
54
|
get shopping(): Shopping;
|
|
55
55
|
get merchandising(): Merchandising;
|
|
56
56
|
get clientAlerts(): ClientAlerts;
|
|
57
|
+
setSignature(signature: Signature): void;
|
|
57
58
|
}
|
|
58
59
|
export { eBayApi, SiteId, MarketplaceId, ContentLanguage, Locale, enums, errors, types };
|