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.
Files changed (38) hide show
  1. package/README.md +45 -8
  2. package/dist/api/digitalSignature.d.ts +43 -0
  3. package/dist/api/digitalSignature.js +105 -0
  4. package/dist/api/index.d.ts +2 -0
  5. package/dist/api/index.js +18 -0
  6. package/dist/api/restful/developer/keyManagement/index.d.ts +2 -4
  7. package/dist/api/restful/developer/keyManagement/index.js +5 -3
  8. package/dist/api/restful/index.d.ts +12 -7
  9. package/dist/api/restful/index.js +33 -17
  10. package/dist/api/traditional/XMLRequest.d.ts +3 -1
  11. package/dist/api/traditional/XMLRequest.js +3 -1
  12. package/dist/api/traditional/index.d.ts +1 -1
  13. package/dist/api/traditional/index.js +25 -15
  14. package/dist/eBayApi.d.ts +2 -1
  15. package/dist/eBayApi.js +12 -1
  16. package/dist/ebay-api.min.mjs +1 -1
  17. package/dist/errors/index.js +5 -0
  18. package/dist/types/apiTypes.d.ts +7 -0
  19. package/dist/types/traditonalTypes.d.ts +2 -1
  20. package/lib/api/digitalSignature.d.ts +43 -0
  21. package/lib/api/digitalSignature.js +112 -0
  22. package/lib/api/index.d.ts +2 -0
  23. package/lib/api/index.js +18 -0
  24. package/lib/api/restful/developer/keyManagement/index.d.ts +2 -4
  25. package/lib/api/restful/developer/keyManagement/index.js +5 -3
  26. package/lib/api/restful/index.d.ts +12 -7
  27. package/lib/api/restful/index.js +37 -21
  28. package/lib/api/traditional/XMLRequest.d.ts +3 -1
  29. package/lib/api/traditional/XMLRequest.js +2 -0
  30. package/lib/api/traditional/index.d.ts +1 -1
  31. package/lib/api/traditional/index.js +29 -19
  32. package/lib/eBayApi.d.ts +2 -1
  33. package/lib/eBayApi.js +12 -1
  34. package/lib/ebay-api.min.js +1 -1
  35. package/lib/errors/index.js +5 -0
  36. package/lib/types/apiTypes.d.ts +7 -0
  37. package/lib/types/traditonalTypes.d.ts +2 -1
  38. package/package.json +2 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  [![npm](https://img.shields.io/npm/dt/ebay-api.svg?style=flat-square)](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.3.0` is the latest release.
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, // defautl. required for RESTful APIs
92
- acceptLanguage: eBayApi.Locale.en_US, // defautl
93
- contentLanguage: eBayApi.ContentLanguage.en_US, // defautl.
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
- ### Change RESTful API call config
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 manuel refresh the auth token use `eBay.OAuth2.refreshAuthToken()` and for the client
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
+ }
@@ -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
- * his method creates keypairs.
15
+ * This method creates keypairs.
16
16
  */
17
- createSigningKey(data: {
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
- * his method creates keypairs.
20
+ * This method creates keypairs.
21
21
  */
22
- createSigningKey(data) {
23
- return this.post(`/signing_key`, data);
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
- url: string;
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
- get(url: string, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
54
- delete(url: string, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
55
- post(url: string, data?: any, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
56
- put(url: string, data?: any, config?: any, apiConfig?: RestfulApiConfig): Promise<any>;
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(config?: any, apiConfig?: Required<RestfulApiConfig>): Promise<any>;
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
- async get(url, config = {}, apiConfig) {
83
- return this.doRequest({ method: 'get', url, config }, apiConfig);
83
+ /**
84
+ * Sign request
85
+ */
86
+ get sign() {
87
+ return this.api({ sign: true });
84
88
  }
85
- async delete(url, config = {}, apiConfig) {
86
- return this.doRequest({ method: 'delete', url, config }, apiConfig);
89
+ async get(path, config = {}, apiConfig) {
90
+ return this.doRequest({ method: 'get', path, config }, apiConfig);
87
91
  }
88
- async post(url, data, config = {}, apiConfig) {
89
- return this.doRequest({ method: 'post', url, data, config }, apiConfig);
92
+ async delete(path, config = {}, apiConfig) {
93
+ return this.doRequest({ method: 'delete', path, config }, apiConfig);
90
94
  }
91
- async put(url, data, config = {}, apiConfig) {
92
- return this.doRequest({ method: 'put', url, data, config }, apiConfig);
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(config = {}, apiConfig = this.apiConfig) {
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 { url, method, data, config } = apiRequest;
158
+ const { path, method, data } = apiRequest;
143
159
  const apiCfg = { ...this.apiConfig, ...apiConfig };
144
- const endpoint = this.getServerUrl(apiCfg) + url;
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(config, apiCfg);
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 { XMLParser, XMLBuilder } from 'fast-xml-parser';
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,5 +1,5 @@
1
- import Api from '../index.js';
2
1
  import { ClientAlerts, Finding, Merchandising, Shopping, Trading } from '../../types/index.js';
2
+ import Api from '../index.js';
3
3
  /**
4
4
  * Traditional eBay API.
5
5
  */
@@ -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: 'https://api.ebay.com/ws/api.dll',
40
- sandbox: 'https://api.sandbox.ebay.com/ws/api.dll'
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: 'https://open.api.ebay.com/shopping',
62
- sandbox: 'https://open.api.sandbox.ebay.com/shopping'
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: 'https://svcs.ebay.com/services/search/FindingService/v1',
80
- sandbox: 'https://svcs.sandbox.ebay.com/services/search/FindingService/v1'
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: 'https://clientalerts.ebay.com/ws/ecasvc/ClientAlerts',
97
- sandbox: 'https://clientalerts.sandbox.ebay.com/ws/ecasvc/ClientAlerts'
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: 'https://svcs.ebay.com/MerchandisingService',
133
- sandbox: 'https://svcs.sandbox.ebay.com/MerchandisingService'
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.endpoint[this.config.sandbox ? 'sandbox' : 'production'],
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 };