diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8383da9..ec6bdb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2143,7 +2143,7 @@ packages: lodash-es: 4.17.21 nerf-dart: 1.0.0 normalize-url: 8.0.0 - npm: 10.2.1 + npm: 10.2.2 rc: 1.2.8 read-pkg: 8.1.0 registry-auth-token: 5.0.2 @@ -2843,7 +2843,7 @@ packages: hasBin: true dependencies: caniuse-lite: 1.0.30001559 - electron-to-chromium: 1.4.571 + electron-to-chromium: 1.4.574 node-releases: 2.0.13 update-browserslist-db: 1.0.13(browserslist@4.22.1) dev: true @@ -3302,8 +3302,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.571: - resolution: {integrity: sha512-Sc+VtKwKCDj3f/kLBjdyjMpNzoZsU6WuL/wFb6EH8USmHEcebxRXcRrVpOpayxd52tuey4RUDpUsw5OS5LhJqg==} + /electron-to-chromium@1.4.574: + resolution: {integrity: sha512-bg1m8L0n02xRzx4LsTTMbBPiUd9yIR+74iPtS/Ao65CuXvhVZHP0ym1kSdDG3yHFDXqHQQBKujlN1AQ8qZnyFg==} dev: true /emittery@0.13.1: @@ -3546,8 +3546,8 @@ packages: - supports-color dev: true - /eslint-plugin-es-x@7.2.0(eslint@8.52.0): - resolution: {integrity: sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==} + /eslint-plugin-es-x@7.3.0(eslint@8.52.0): + resolution: {integrity: sha512-W9zIs+k00I/I13+Bdkl/zG1MEO07G97XjUSQuH117w620SJ6bHtLUmoMvkGA2oYnI/gNdr+G7BONLyYnFaLLEQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' @@ -3601,7 +3601,7 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0) builtins: 5.0.1 eslint: 8.52.0 - eslint-plugin-es-x: 7.2.0(eslint@8.52.0) + eslint-plugin-es-x: 7.3.0(eslint@8.52.0) get-tsconfig: 4.7.2 ignore: 5.2.4 is-core-module: 2.13.1 @@ -3964,7 +3964,7 @@ packages: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 - universalify: 2.0.0 + universalify: 2.0.1 dev: true /fs.realpath@1.0.0: @@ -5124,7 +5124,7 @@ packages: /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: - universalify: 2.0.0 + universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 dev: true @@ -5277,7 +5277,7 @@ packages: tmpl: 1.0.5 dev: true - /marked-terminal@6.0.0(marked@9.1.4): + /marked-terminal@6.0.0(marked@9.1.5): resolution: {integrity: sha512-6rruICvqRfA4N+Mvdc0UyDbLA0A0nI5omtARIlin3P2F+aNc3EbW91Rd9HTuD0v9qWyHmNIu8Bt40gAnPfldsg==} engines: {node: '>=16.0.0'} peerDependencies: @@ -5287,13 +5287,13 @@ packages: cardinal: 2.1.1 chalk: 5.3.0 cli-table3: 0.6.3 - marked: 9.1.4 + marked: 9.1.5 node-emoji: 2.1.0 supports-hyperlinks: 3.0.0 dev: true - /marked@9.1.4: - resolution: {integrity: sha512-Mq83CCaClhXqhf8sLQ57c1unNelHEuFadK36ga+GeXR4FeT/5ssaC5PaCRVqMA74VYorzYRqdAaxxteIanh3Kw==} + /marked@9.1.5: + resolution: {integrity: sha512-14QG3shv8Kg/xc0Yh6TNkMj90wXH9mmldi5941I2OevfJ/FQAFLEwtwU2/FfgSAOMlWHrEukWSGQf8MiVYNG2A==} engines: {node: '>= 16'} hasBin: true dev: true @@ -5454,8 +5454,8 @@ packages: path-key: 4.0.0 dev: true - /npm@10.2.1: - resolution: {integrity: sha512-YVh8UDw5lR2bPS6rrS0aPG9ZXKDWeaeO/zMoZMp7g3Thrho9cqEnSrcvg4Pic2QhDAQptAynx5KgrPgCSRscqg==} + /npm@10.2.2: + resolution: {integrity: sha512-VSP/rh88wBQ+b7bz0NOdZQBQCuWLI/etpWfgUWDmNaMy0MuD1xJBMofEzuFojNpJANVaJCkN5U7KgfPdR2V1fg==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true dev: true @@ -6122,8 +6122,8 @@ packages: hook-std: 3.0.0 hosted-git-info: 7.0.1 lodash-es: 4.17.21 - marked: 9.1.4 - marked-terminal: 6.0.0(marked@9.1.4) + marked: 9.1.5 + marked-terminal: 6.0.0(marked@9.1.5) micromatch: 4.0.5 p-each-series: 3.0.0 p-reduce: 3.0.0 @@ -6719,8 +6719,8 @@ packages: resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} dev: true - /universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} dev: true diff --git a/src/api.ts b/src/api.ts index 9be1e9b..9396e7f 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,19 +1,3 @@ - - - - - - - - - - - - - - - - import type { Resource, ResourceRel } from './resource' import type { VersionType } from './resources/versions' diff --git a/src/client.ts b/src/client.ts index ba7b3d0..7230922 100644 --- a/src/client.ts +++ b/src/client.ts @@ -6,6 +6,7 @@ import type { InterceptorManager } from './interceptor' import config from './config' import type { Agent as HttpAgent } from 'http' import type { Agent as HttpsAgent } from 'https' +// import { packageInfo } from './util' import Debug from './debug' const debug = Debug('client') @@ -25,20 +26,25 @@ type RequestHeaders = Record // Subset of AxiosRequestConfig type RequestConfig = { - timeout?: number; - params?: RequestParams; - httpAgent?: HttpAgent; - httpsAgent?: HttpsAgent; - proxy?: ProxyConfig; + timeout?: number + params?: RequestParams + httpAgent?: HttpAgent + httpsAgent?: HttpsAgent + proxy?: ProxyConfig headers?: RequestHeaders } +type RequestConfigExtra = { + adapter?: Adapter + userAgent?: string +} + type ApiConfig = { domain?: string, accessToken: string } -type ApiClientInitConfig = ApiConfig & RequestConfig & { adapter?: Adapter } +type ApiClientInitConfig = ApiConfig & RequestConfig & RequestConfigExtra type ApiClientConfig = Partial @@ -67,12 +73,17 @@ class ApiClient { timeout: options.timeout || config.client.timeout, proxy: options.proxy, httpAgent: options.httpAgent, - httpsAgent: options.httpsAgent, + httpsAgent: options.httpsAgent } // Set custom headers const customHeaders = this.customHeaders(options.headers) + // Set User-Agent + // const userAgentData = packageInfo(['version', 'dependencies.axios'], { nestedName: true }) + let userAgent = options.userAgent || `SDK-provisioning axios/${axios.VERSION}` + if (!userAgent.includes('axios/')) userAgent += ` axios/${axios.VERSION}` + const axiosOptions: CreateAxiosDefaults = { baseURL: this.baseUrl, timeout: config.client.timeout, @@ -80,7 +91,8 @@ class ApiClient { ...customHeaders, 'Accept': 'application/vnd.api+json', 'Content-Type': 'application/vnd.api+json', - 'Authorization': 'Bearer ' + this.#accessToken + 'Authorization': 'Bearer ' + this.#accessToken, + 'User-Agent': userAgent }, ...axiosConfig } @@ -108,19 +120,35 @@ class ApiClient { if (config.httpAgent) def.httpAgent = config.httpAgent if (config.httpsAgent) def.httpsAgent = config.httpsAgent + if (config.adapter) this.adapter(config.adapter) + if (config.userAgent) this.userAgent(config.userAgent) + + // API Client config if (config.accessToken) { this.#accessToken = config.accessToken def.headers.common.Authorization = 'Bearer ' + this.#accessToken; } if (config.headers) def.headers.common = this.customHeaders(config.headers) - if (config.adapter) this.adapter(config.adapter) return this } + userAgent(userAgent: string): ApiClient { + if (userAgent) { + let ua = userAgent + if (!ua.includes('axios/')) { + // const axiosVer = packageInfo(['dependencies.axios'], { nestedName: true }) + if (axios.VERSION) ua += ` axios/${axios.VERSION}` + } + this.#client.defaults.headers['User-Agent'] = ua + } + return this + } + + adapter(adapter: Adapter): ApiClient { if (adapter) this.#client.defaults.adapter = adapter return this @@ -131,11 +159,14 @@ class ApiClient { debug('request %s %s, %O, %O', method, path, body || {}, options || {}) + // Ignored params alerts (in debug mode) + if (options?.adapter) debug('Adapter ignored in request config') + if (options?.userAgent) debug('User-Agent header ignored in request config') + const data = body ? { data: body } : undefined const url = path // Runtime request parameters - // const baseUrl = options?.organization ? baseURL(options.organization, options.domain) : undefined const accessToken = options?.accessToken || this.#accessToken const headers = this.customHeaders(options?.headers) @@ -158,7 +189,7 @@ class ApiClient { const customHeaders: RequestHeaders = {} if (headers) { for (const [name, value] of Object.entries(headers)) - if (!['accept', 'content-type', 'authorization'].includes(name.toLowerCase())) customHeaders[name] = value + if (!['accept', 'content-type', 'authorization', 'user-agent'].includes(name.toLowerCase())) customHeaders[name] = value } return customHeaders } diff --git a/src/util.ts b/src/util.ts index 861f432..d6a0553 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,5 @@ -import type { ObjectType } from "../src/common"; +import type { ObjectType } from "../src/common" +// import path from 'path' @@ -15,5 +16,32 @@ const sortObjectFields = (obj: ObjectType): ObjectType => { return sorted } +/* +const nestedField = (obj: any, field: string): { key: string, val: any } => { -export { sleep, sortObjectFields } + let fp = field + if (fp.endsWith('.')) fp = fp.substring(0, fp.length-1) + + const dots = field.split(".") + + const key = dots[dots.length-1] + let val = obj + while (dots.length && (val = val[dots.shift() || ''])); + + return { key, val } +} +*/ + +/* +const packageInfo = (fields?: string | string[], options?: any): Record => { + const pjson = require(path.resolve('./', 'package.json')) + return fields? (Array.isArray(fields)? fields : [ fields ]).reduce((info: any, field) => { + const nf = nestedField(pjson, field) + info[options?.nestedName? nf.key : field] = nf.val + return info + }, {}) : pjson +} +*/ + + +export { sleep, sortObjectFields, /* packageInfo */ }