@vtex/api 7.3.1 → 7.4.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/CHANGELOG.md +11 -0
- package/README.md +3 -0
- package/lib/clients/IOClients.d.ts +2 -1
- package/lib/clients/IOClients.js +3 -0
- package/lib/clients/janus/Catalog/index.d.ts +7 -0
- package/lib/clients/janus/Catalog/index.js +37 -0
- package/lib/clients/janus/Catalog/types.d.ts +5 -0
- package/lib/clients/janus/Catalog/types.js +2 -0
- package/lib/clients/janus/{LicenseManager.d.ts → LicenseManager/index.d.ts} +6 -2
- package/lib/clients/janus/LicenseManager/index.js +91 -0
- package/lib/clients/janus/LicenseManager/types.d.ts +16 -0
- package/lib/clients/janus/LicenseManager/types.js +2 -0
- package/lib/clients/janus/LicenseManager/utils.d.ts +6 -0
- package/lib/clients/janus/LicenseManager/utils.js +40 -0
- package/lib/clients/janus/index.d.ts +1 -0
- package/lib/clients/janus/index.js +1 -0
- package/lib/service/metrics/metrics.d.ts +2 -2
- package/lib/service/metrics/metrics.js +13 -13
- package/lib/service/metrics/otelRequestMetricsMiddleware.js +1 -1
- package/lib/service/telemetry/client.js +23 -23
- package/lib/service/worker/index.js +1 -1
- package/lib/service/worker/runtime/graphql/schema/schemaDirectives/Auth.js +2 -2
- package/lib/service/worker/runtime/http/middlewares/timings.js +1 -1
- package/lib/utils/buildFullPath.js +3 -3
- package/package.json +2 -2
- package/lib/clients/janus/LicenseManager.js +0 -59
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [7.4.0] - 2026-06-22
|
|
11
|
+
### Changed
|
|
12
|
+
- Renamed the base `IOClients` Janus Catalog getter from `catalogSystem` to
|
|
13
|
+
`janusCatalogSystem` to avoid a name collision with apps that already define
|
|
14
|
+
their own `catalogSystem` client (e.g. vtex-apps/promotion-cloner).
|
|
15
|
+
### Added
|
|
16
|
+
- Base `IOClients` getter `janusCatalogSystem` (Janus Catalog) and
|
|
17
|
+
`licenseManager.listBindings`, plus binding-mapping helpers
|
|
18
|
+
(getCanonicalAndAlternateAddresses, inferTargetProduct) used by the
|
|
19
|
+
Tenant API migration.
|
|
20
|
+
|
|
10
21
|
## [7.3.1] - 2026-01-06
|
|
11
22
|
|
|
12
23
|
### Added
|
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# VTEX IO API Client for Node
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
This library enables developers to quickly integrate with the VTEX IO APIs and create full fledged node services using VTEX IO.
|
|
4
5
|
|
|
5
6
|
[](https://travis-ci.org/vtex/node-vtex-api)
|
|
@@ -63,3 +64,5 @@ export const example = async (ctx: Context, next: () => Promise<void>) => {
|
|
|
63
64
|
Now, when you get a workspace up and running for your app with `vtex link`, you'll have this package linked as well.
|
|
64
65
|
|
|
65
66
|
> When done developing, don't forget to unlink it from `<your-app>/node`: `yarn unlink @vtex/api`
|
|
67
|
+
|
|
68
|
+
<!-- Test PR to validate SonarQube configuration -->
|
|
@@ -5,7 +5,7 @@ import { CatalogGraphQL } from './apps/catalogGraphQL/index';
|
|
|
5
5
|
import { ID, MasterData, PaymentProvider } from './external';
|
|
6
6
|
import { Apps, Assets, BillingMetrics, Events, Registry, Router, VBase, Workspaces } from './infra';
|
|
7
7
|
import { IOClientConstructor } from './IOClient';
|
|
8
|
-
import { LicenseManager, Segment, Session, TenantClient } from './janus';
|
|
8
|
+
import { LicenseManager, Segment, Session, TenantClient, Catalog } from './janus';
|
|
9
9
|
export type ClientsImplementation<T extends IOClients> = new (clientOptions: Record<string, InstanceOptions>, ctx: IOContext) => T;
|
|
10
10
|
export declare class IOClients {
|
|
11
11
|
private clientOptions;
|
|
@@ -31,6 +31,7 @@ export declare class IOClients {
|
|
|
31
31
|
get vbase(): VBase;
|
|
32
32
|
get workspaces(): Workspaces;
|
|
33
33
|
get catalogGraphQL(): CatalogGraphQL;
|
|
34
|
+
get janusCatalogSystem(): Catalog;
|
|
34
35
|
get paymentProvider(): PaymentProvider;
|
|
35
36
|
protected getOrSet<TClient extends IOClientConstructor>(key: string, Implementation: TClient): InstanceType<TClient>;
|
|
36
37
|
}
|
package/lib/clients/IOClients.js
CHANGED
|
@@ -69,6 +69,9 @@ class IOClients {
|
|
|
69
69
|
get catalogGraphQL() {
|
|
70
70
|
return this.getOrSet('catalogGraphQL', index_1.CatalogGraphQL);
|
|
71
71
|
}
|
|
72
|
+
get janusCatalogSystem() {
|
|
73
|
+
return this.getOrSet('janusCatalogSystem', janus_1.Catalog);
|
|
74
|
+
}
|
|
72
75
|
get paymentProvider() {
|
|
73
76
|
return this.getOrSet('paymentProvider', external_1.PaymentProvider);
|
|
74
77
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RequestConfig } from '../../../HttpClient';
|
|
2
|
+
import { JanusClient } from '../JanusClient';
|
|
3
|
+
import { SalesChannel } from './types';
|
|
4
|
+
export declare class Catalog extends JanusClient {
|
|
5
|
+
getSalesChannel(id: number, config?: RequestConfig): Promise<SalesChannel>;
|
|
6
|
+
getDefaultSalesChannel(config?: RequestConfig): Promise<SalesChannel>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Catalog = void 0;
|
|
4
|
+
const HttpClient_1 = require("../../../HttpClient");
|
|
5
|
+
const JanusClient_1 = require("../JanusClient");
|
|
6
|
+
const BASE_URL = '/api/catalog_system';
|
|
7
|
+
const routes = {
|
|
8
|
+
salesChannel: (salesChannelId) => `${BASE_URL}/pub/saleschannel/${salesChannelId}`,
|
|
9
|
+
defaultSalesChannel: () => `${BASE_URL}/pub/saleschannel/default`,
|
|
10
|
+
};
|
|
11
|
+
class Catalog extends JanusClient_1.JanusClient {
|
|
12
|
+
getSalesChannel(id, config) {
|
|
13
|
+
const metric = 'catalog-saleschannel';
|
|
14
|
+
return this.http.get(routes.salesChannel(id), {
|
|
15
|
+
inflightKey: HttpClient_1.inflightUrlWithQuery,
|
|
16
|
+
metric,
|
|
17
|
+
...config,
|
|
18
|
+
tracing: {
|
|
19
|
+
requestSpanNameSuffix: metric,
|
|
20
|
+
...config === null || config === void 0 ? void 0 : config.tracing,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
getDefaultSalesChannel(config) {
|
|
25
|
+
const metric = 'catalog-saleschannel-default';
|
|
26
|
+
return this.http.get(routes.defaultSalesChannel(), {
|
|
27
|
+
inflightKey: HttpClient_1.inflightUrlWithQuery,
|
|
28
|
+
metric,
|
|
29
|
+
...config,
|
|
30
|
+
tracing: {
|
|
31
|
+
requestSpanNameSuffix: metric,
|
|
32
|
+
...config === null || config === void 0 ? void 0 : config.tracing,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.Catalog = Catalog;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { RequestTracingConfig } from '
|
|
2
|
-
import { JanusClient } from '
|
|
1
|
+
import { RequestTracingConfig, RequestConfig } from '../../../HttpClient';
|
|
2
|
+
import { JanusClient } from '../JanusClient';
|
|
3
|
+
import { APIBindingRes } from './types';
|
|
4
|
+
export * from './types';
|
|
5
|
+
export * from './utils';
|
|
3
6
|
export declare class LicenseManager extends JanusClient {
|
|
4
7
|
getAccountData(VtexIdclientAutCookie: string, tracingConfig?: RequestTracingConfig): Promise<any>;
|
|
5
8
|
getTopbarData(VtexIdclientAutCookie: string, tracingConfig?: RequestTracingConfig): Promise<any>;
|
|
6
9
|
canAccessResource(VtexIdclientAutCookie: string, resourceKey: string, tracingConfig?: RequestTracingConfig): Promise<boolean>;
|
|
10
|
+
listBindings(tenant: string, config?: RequestConfig): Promise<APIBindingRes[]>;
|
|
7
11
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.LicenseManager = void 0;
|
|
18
|
+
const HttpClient_1 = require("../../../HttpClient");
|
|
19
|
+
const JanusClient_1 = require("../JanusClient");
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./utils"), exports);
|
|
22
|
+
const TWO_MINUTES_S = 2 * 60;
|
|
23
|
+
const BASE_URL = '/api/license-manager';
|
|
24
|
+
const routes = {
|
|
25
|
+
accountData: () => `${BASE_URL}/account`,
|
|
26
|
+
resourceAccess: (resourceKey) => `${BASE_URL}/resources/${encodeURIComponent(resourceKey)}/access`,
|
|
27
|
+
topbarData: () => `${BASE_URL}/site/pvt/newtopbar`,
|
|
28
|
+
listBindings: (tenant) => `${BASE_URL}/binding/site/${encodeURIComponent(tenant)}`,
|
|
29
|
+
};
|
|
30
|
+
class LicenseManager extends JanusClient_1.JanusClient {
|
|
31
|
+
getAccountData(VtexIdclientAutCookie, tracingConfig) {
|
|
32
|
+
const metric = 'lm-account-data';
|
|
33
|
+
return this.http.get(routes.accountData(), {
|
|
34
|
+
forceMaxAge: TWO_MINUTES_S,
|
|
35
|
+
headers: {
|
|
36
|
+
VtexIdclientAutCookie,
|
|
37
|
+
},
|
|
38
|
+
inflightKey: HttpClient_1.inflightUrlWithQuery,
|
|
39
|
+
metric,
|
|
40
|
+
tracing: {
|
|
41
|
+
requestSpanNameSuffix: metric,
|
|
42
|
+
...tracingConfig === null || tracingConfig === void 0 ? void 0 : tracingConfig.tracing,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
getTopbarData(VtexIdclientAutCookie, tracingConfig) {
|
|
47
|
+
const metric = 'lm-topbar-data';
|
|
48
|
+
return this.http.get(routes.topbarData(), {
|
|
49
|
+
headers: {
|
|
50
|
+
VtexIdclientAutCookie,
|
|
51
|
+
},
|
|
52
|
+
metric,
|
|
53
|
+
tracing: {
|
|
54
|
+
requestSpanNameSuffix: metric,
|
|
55
|
+
...tracingConfig === null || tracingConfig === void 0 ? void 0 : tracingConfig.tracing,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
canAccessResource(VtexIdclientAutCookie, resourceKey, tracingConfig) {
|
|
60
|
+
const metric = 'lm-resource-access';
|
|
61
|
+
return this.http
|
|
62
|
+
.get(routes.resourceAccess(resourceKey), {
|
|
63
|
+
headers: {
|
|
64
|
+
VtexIdclientAutCookie,
|
|
65
|
+
},
|
|
66
|
+
metric,
|
|
67
|
+
tracing: {
|
|
68
|
+
requestSpanNameSuffix: metric,
|
|
69
|
+
...tracingConfig === null || tracingConfig === void 0 ? void 0 : tracingConfig.tracing,
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
.then(() => true, () => false);
|
|
73
|
+
}
|
|
74
|
+
listBindings(tenant, config) {
|
|
75
|
+
const metric = 'lm-list-bindings';
|
|
76
|
+
return this.http.get(routes.listBindings(tenant), {
|
|
77
|
+
inflightKey: HttpClient_1.inflightUrlWithQuery,
|
|
78
|
+
memoizeable: true,
|
|
79
|
+
metric,
|
|
80
|
+
headers: {
|
|
81
|
+
VtexIdclientAutCookie: this.context.authToken,
|
|
82
|
+
},
|
|
83
|
+
...config,
|
|
84
|
+
tracing: {
|
|
85
|
+
requestSpanNameSuffix: metric,
|
|
86
|
+
...config === null || config === void 0 ? void 0 : config.tracing,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.LicenseManager = LicenseManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface APIAddress {
|
|
2
|
+
Host: string;
|
|
3
|
+
IsCanonical: boolean;
|
|
4
|
+
BasePath: string;
|
|
5
|
+
Localization: {
|
|
6
|
+
[k: string]: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export interface APIBindingRes {
|
|
10
|
+
Id: string;
|
|
11
|
+
Addresses: APIAddress[];
|
|
12
|
+
SiteName: string;
|
|
13
|
+
DefaultSalesChannelId: number | null;
|
|
14
|
+
DefaultLocale: string;
|
|
15
|
+
SupportedLocales: string[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { APIBindingRes } from './types';
|
|
2
|
+
export declare const getCanonicalAndAlternateAddresses: (lmBinding: APIBindingRes) => {
|
|
3
|
+
canonicalBaseAddress: string;
|
|
4
|
+
alternateBaseAddresses: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare const inferTargetProduct: (canonicalBaseAddress: string, alternateBaseAddresses: string[]) => 'vtex-admin' | 'vtex-storefront';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inferTargetProduct = exports.getCanonicalAndAlternateAddresses = void 0;
|
|
4
|
+
const buildAddressPath = (basePath, localizationKey) => {
|
|
5
|
+
if (basePath === '') {
|
|
6
|
+
return `/${localizationKey}`;
|
|
7
|
+
}
|
|
8
|
+
if (localizationKey === '') {
|
|
9
|
+
return `/${basePath}`;
|
|
10
|
+
}
|
|
11
|
+
return `/${basePath}/${localizationKey}`;
|
|
12
|
+
};
|
|
13
|
+
const getCanonicalAndAlternateAddresses = (lmBinding) => {
|
|
14
|
+
let canonicalBaseAddress = '';
|
|
15
|
+
const alternateBaseAddresses = [];
|
|
16
|
+
for (const addressEntry of lmBinding.Addresses) {
|
|
17
|
+
const localizationKeys = Object.keys(addressEntry.Localization);
|
|
18
|
+
for (const localizationKey of localizationKeys) {
|
|
19
|
+
alternateBaseAddresses.push(addressEntry.Host + buildAddressPath(addressEntry.BasePath, localizationKey));
|
|
20
|
+
}
|
|
21
|
+
if (addressEntry.IsCanonical) {
|
|
22
|
+
// The canonical address is built from the shortest localization key.
|
|
23
|
+
const [shortestLocalizationKey = ''] = [...localizationKeys].sort((a, b) => a.length - b.length);
|
|
24
|
+
canonicalBaseAddress = addressEntry.Host + buildAddressPath(addressEntry.BasePath, shortestLocalizationKey);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// The canonical address must not also appear in the alternates list.
|
|
28
|
+
const canonicalIndexInAlternates = alternateBaseAddresses.indexOf(canonicalBaseAddress);
|
|
29
|
+
if (canonicalIndexInAlternates !== -1) {
|
|
30
|
+
alternateBaseAddresses.splice(canonicalIndexInAlternates, 1);
|
|
31
|
+
}
|
|
32
|
+
return { canonicalBaseAddress, alternateBaseAddresses };
|
|
33
|
+
};
|
|
34
|
+
exports.getCanonicalAndAlternateAddresses = getCanonicalAndAlternateAddresses;
|
|
35
|
+
const inferTargetProduct = (canonicalBaseAddress, alternateBaseAddresses) => {
|
|
36
|
+
const isAdmin = canonicalBaseAddress.endsWith('myvtex.com/admin') ||
|
|
37
|
+
alternateBaseAddresses.some(address => address.endsWith('myvtex.com/admin'));
|
|
38
|
+
return isAdmin ? 'vtex-admin' : 'vtex-storefront';
|
|
39
|
+
};
|
|
40
|
+
exports.inferTargetProduct = inferTargetProduct;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Types } from '@vtex/diagnostics-nodejs';
|
|
2
2
|
export declare const RequestsMetricLabels: {
|
|
3
|
-
readonly STATUS_CODE: "status_code";
|
|
4
|
-
readonly REQUEST_HANDLER: "handler";
|
|
5
3
|
readonly ACCOUNT_NAME: "vtex.account.name";
|
|
4
|
+
readonly REQUEST_HANDLER: "handler";
|
|
5
|
+
readonly STATUS_CODE: "status_code";
|
|
6
6
|
};
|
|
7
7
|
export interface OtelRequestInstruments {
|
|
8
8
|
concurrentRequests: Types.Gauge;
|
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getOtelInstruments = exports.RequestsMetricLabels = void 0;
|
|
4
|
-
const client_1 = require("./client");
|
|
5
4
|
const constants_1 = require("../../constants");
|
|
5
|
+
const client_1 = require("./client");
|
|
6
6
|
exports.RequestsMetricLabels = {
|
|
7
|
-
STATUS_CODE: 'status_code',
|
|
8
|
-
REQUEST_HANDLER: 'handler',
|
|
9
7
|
ACCOUNT_NAME: constants_1.AttributeKeys.VTEX_ACCOUNT_NAME,
|
|
8
|
+
REQUEST_HANDLER: 'handler',
|
|
9
|
+
STATUS_CODE: 'status_code',
|
|
10
10
|
};
|
|
11
11
|
const createOtelConcurrentRequestsInstrument = async () => {
|
|
12
12
|
const metricsClient = await (0, client_1.getMetricClient)();
|
|
13
13
|
return metricsClient.createGauge('io_http_requests_current', {
|
|
14
14
|
description: 'The current number of requests in course.',
|
|
15
|
-
unit: '1'
|
|
15
|
+
unit: '1',
|
|
16
16
|
});
|
|
17
17
|
};
|
|
18
18
|
const createOtelRequestsTimingsInstrument = async () => {
|
|
19
19
|
const metricsClient = await (0, client_1.getMetricClient)();
|
|
20
20
|
return metricsClient.createHistogram('runtime_http_requests_duration_milliseconds', {
|
|
21
21
|
description: 'The incoming http requests total duration.',
|
|
22
|
-
unit: 'ms'
|
|
22
|
+
unit: 'ms',
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
25
|
const createOtelTotalRequestsInstrument = async () => {
|
|
26
26
|
const metricsClient = await (0, client_1.getMetricClient)();
|
|
27
27
|
return metricsClient.createCounter('runtime_http_requests_total', {
|
|
28
28
|
description: 'The total number of HTTP requests.',
|
|
29
|
-
unit: '1'
|
|
29
|
+
unit: '1',
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
32
|
const createOtelRequestsResponseSizesInstrument = async () => {
|
|
33
33
|
const metricsClient = await (0, client_1.getMetricClient)();
|
|
34
34
|
return metricsClient.createHistogram('runtime_http_response_size_bytes', {
|
|
35
35
|
description: 'The outgoing response sizes (only applicable when the response isn\'t a stream).',
|
|
36
|
-
unit: 'bytes'
|
|
36
|
+
unit: 'bytes',
|
|
37
37
|
});
|
|
38
38
|
};
|
|
39
39
|
const createOtelTotalAbortedRequestsInstrument = async () => {
|
|
40
40
|
const metricsClient = await (0, client_1.getMetricClient)();
|
|
41
41
|
return metricsClient.createCounter('runtime_http_aborted_requests_total', {
|
|
42
42
|
description: 'The total number of HTTP requests aborted.',
|
|
43
|
-
unit: '1'
|
|
43
|
+
unit: '1',
|
|
44
44
|
});
|
|
45
45
|
};
|
|
46
46
|
class OtelInstrumentsSingleton {
|
|
47
|
-
constructor() { }
|
|
48
47
|
static getInstance() {
|
|
49
48
|
if (!OtelInstrumentsSingleton.instance) {
|
|
50
49
|
OtelInstrumentsSingleton.instance = new OtelInstrumentsSingleton();
|
|
51
50
|
}
|
|
52
51
|
return OtelInstrumentsSingleton.instance;
|
|
53
52
|
}
|
|
53
|
+
constructor() { }
|
|
54
54
|
async getInstruments() {
|
|
55
55
|
if (this.instruments) {
|
|
56
56
|
return this.instruments;
|
|
@@ -73,19 +73,19 @@ class OtelInstrumentsSingleton {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
async initializeInstruments() {
|
|
76
|
-
const [concurrentRequests, requestTimings, totalRequests, responseSizes, abortedRequests] = await Promise.all([
|
|
76
|
+
const [concurrentRequests, requestTimings, totalRequests, responseSizes, abortedRequests,] = await Promise.all([
|
|
77
77
|
createOtelConcurrentRequestsInstrument(),
|
|
78
78
|
createOtelRequestsTimingsInstrument(),
|
|
79
79
|
createOtelTotalRequestsInstrument(),
|
|
80
80
|
createOtelRequestsResponseSizesInstrument(),
|
|
81
|
-
createOtelTotalAbortedRequestsInstrument()
|
|
81
|
+
createOtelTotalAbortedRequestsInstrument(),
|
|
82
82
|
]);
|
|
83
83
|
return {
|
|
84
|
+
abortedRequests,
|
|
84
85
|
concurrentRequests,
|
|
85
86
|
requestTimings,
|
|
86
|
-
totalRequests,
|
|
87
87
|
responseSizes,
|
|
88
|
-
|
|
88
|
+
totalRequests,
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -11,7 +11,7 @@ const addOtelRequestMetricsMiddleware = () => {
|
|
|
11
11
|
try {
|
|
12
12
|
return await Promise.race([
|
|
13
13
|
(0, metrics_1.getOtelInstruments)(),
|
|
14
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for OpenTelemetry instruments initialization')), INSTRUMENTS_INITIALIZATION_TIMEOUT))
|
|
14
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for OpenTelemetry instruments initialization')), INSTRUMENTS_INITIALIZATION_TIMEOUT)),
|
|
15
15
|
]);
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resetTelemetry = exports.initializeTelemetry = void 0;
|
|
4
|
+
const instrumentation_koa_1 = require("@opentelemetry/instrumentation-koa");
|
|
4
5
|
const diagnostics_nodejs_1 = require("@vtex/diagnostics-nodejs");
|
|
5
6
|
const constants_1 = require("../../constants");
|
|
6
|
-
const instrumentation_koa_1 = require("@opentelemetry/instrumentation-koa");
|
|
7
7
|
const hostMetrics_1 = require("../metrics/instruments/hostMetrics");
|
|
8
8
|
const APPLICATION_ID = constants_1.APP.ID || 'vtex-io-app';
|
|
9
9
|
class TelemetryClientSingleton {
|
|
10
|
+
static getInstance() {
|
|
11
|
+
if (!TelemetryClientSingleton.instance) {
|
|
12
|
+
TelemetryClientSingleton.instance = new TelemetryClientSingleton();
|
|
13
|
+
}
|
|
14
|
+
return TelemetryClientSingleton.instance;
|
|
15
|
+
}
|
|
10
16
|
constructor() {
|
|
11
17
|
this.initializationPromise = undefined;
|
|
12
18
|
this.initializeTracesClient = async (telemetryClient) => await telemetryClient.newTracesClient({
|
|
@@ -18,8 +24,8 @@ class TelemetryClientSingleton {
|
|
|
18
24
|
exporter: diagnostics_nodejs_1.Exporters.CreateExporter(diagnostics_nodejs_1.Exporters.CreateMetricsExporterConfig({
|
|
19
25
|
endpoint: constants_1.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
20
26
|
interval: 60,
|
|
21
|
-
timeoutSeconds: 60,
|
|
22
27
|
temporality: 'delta',
|
|
28
|
+
timeoutSeconds: 60,
|
|
23
29
|
}), 'otlp'),
|
|
24
30
|
});
|
|
25
31
|
this.initializeLogsClient = async (telemetryClient) => await telemetryClient.newLogsClient({
|
|
@@ -29,17 +35,23 @@ class TelemetryClientSingleton {
|
|
|
29
35
|
loggerName: `node-vtex-api-${APPLICATION_ID}`,
|
|
30
36
|
});
|
|
31
37
|
}
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
|
|
38
|
+
async getTelemetryClients() {
|
|
39
|
+
if (this.telemetryClients) {
|
|
40
|
+
return this.telemetryClients;
|
|
35
41
|
}
|
|
36
|
-
|
|
42
|
+
if (this.initializationPromise) {
|
|
43
|
+
return this.initializationPromise;
|
|
44
|
+
}
|
|
45
|
+
this.initializationPromise = this.initializeTelemetryClients();
|
|
46
|
+
return this.initializationPromise;
|
|
47
|
+
}
|
|
48
|
+
reset() {
|
|
49
|
+
this.telemetryClients = undefined;
|
|
50
|
+
this.initializationPromise = undefined;
|
|
37
51
|
}
|
|
38
52
|
async initializeTelemetryClients() {
|
|
39
53
|
try {
|
|
40
54
|
const telemetryClient = await (0, diagnostics_nodejs_1.NewTelemetryClient)(constants_1.DK_APP_ID, 'node-vtex-api', APPLICATION_ID, {
|
|
41
|
-
// Use built-in no-op functionality when telemetry is disabled
|
|
42
|
-
noop: !constants_1.DIAGNOSTICS_TELEMETRY_ENABLED,
|
|
43
55
|
additionalAttrs: {
|
|
44
56
|
[constants_1.AttributeKeys.VTEX_IO_APP_ID]: APPLICATION_ID,
|
|
45
57
|
'vendor': constants_1.APP.VENDOR,
|
|
@@ -47,6 +59,8 @@ class TelemetryClientSingleton {
|
|
|
47
59
|
[constants_1.AttributeKeys.VTEX_IO_WORKSPACE_NAME]: constants_1.WORKSPACE,
|
|
48
60
|
[constants_1.AttributeKeys.VTEX_IO_WORKSPACE_TYPE]: constants_1.PRODUCTION ? 'production' : 'development',
|
|
49
61
|
},
|
|
62
|
+
// Use built-in no-op functionality when telemetry is disabled
|
|
63
|
+
noop: !constants_1.DIAGNOSTICS_TELEMETRY_ENABLED,
|
|
50
64
|
});
|
|
51
65
|
const [tracesClient, metricsClient, logsClient] = await Promise.all([
|
|
52
66
|
this.initializeTracesClient(telemetryClient),
|
|
@@ -59,8 +73,8 @@ class TelemetryClientSingleton {
|
|
|
59
73
|
...diagnostics_nodejs_1.Instrumentation.CommonInstrumentations.minimal(),
|
|
60
74
|
new instrumentation_koa_1.KoaInstrumentation(),
|
|
61
75
|
new hostMetrics_1.HostMetricsInstrumentation({
|
|
62
|
-
name: 'host-metrics-instrumentation',
|
|
63
76
|
meterProvider: metricsClient.provider(),
|
|
77
|
+
name: 'host-metrics-instrumentation',
|
|
64
78
|
}),
|
|
65
79
|
];
|
|
66
80
|
telemetryClient.registerInstrumentations(instrumentations);
|
|
@@ -81,20 +95,6 @@ class TelemetryClientSingleton {
|
|
|
81
95
|
this.initializationPromise = undefined;
|
|
82
96
|
}
|
|
83
97
|
}
|
|
84
|
-
async getTelemetryClients() {
|
|
85
|
-
if (this.telemetryClients) {
|
|
86
|
-
return this.telemetryClients;
|
|
87
|
-
}
|
|
88
|
-
if (this.initializationPromise) {
|
|
89
|
-
return this.initializationPromise;
|
|
90
|
-
}
|
|
91
|
-
this.initializationPromise = this.initializeTelemetryClients();
|
|
92
|
-
return this.initializationPromise;
|
|
93
|
-
}
|
|
94
|
-
reset() {
|
|
95
|
-
this.telemetryClients = undefined;
|
|
96
|
-
this.initializationPromise = undefined;
|
|
97
|
-
}
|
|
98
98
|
}
|
|
99
99
|
async function initializeTelemetry() {
|
|
100
100
|
return TelemetryClientSingleton.getInstance().getTelemetryClients();
|
|
@@ -14,8 +14,8 @@ const constants_1 = require("../../constants");
|
|
|
14
14
|
const loaders_1 = require("../loaders");
|
|
15
15
|
const console_1 = require("../logger/console");
|
|
16
16
|
const loggerTypes_1 = require("../logger/loggerTypes");
|
|
17
|
-
const requestMetricsMiddleware_1 = require("../metrics/requestMetricsMiddleware");
|
|
18
17
|
const otelRequestMetricsMiddleware_1 = require("../metrics/otelRequestMetricsMiddleware");
|
|
18
|
+
const requestMetricsMiddleware_1 = require("../metrics/requestMetricsMiddleware");
|
|
19
19
|
const TracerSingleton_1 = require("../tracing/TracerSingleton");
|
|
20
20
|
const tracingMiddlewares_1 = require("../tracing/tracingMiddlewares");
|
|
21
21
|
const listeners_1 = require("./listeners");
|
|
@@ -50,7 +50,7 @@ async function auth(ctx, authArgs) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
function parseArgs(authArgs) {
|
|
53
|
-
if (authArgs.scope
|
|
53
|
+
if (authArgs.scope === 'PUBLIC') {
|
|
54
54
|
return authArgs;
|
|
55
55
|
}
|
|
56
56
|
if (!authArgs.productCode || !authArgs.resourceCode) {
|
|
@@ -63,7 +63,7 @@ class Auth extends graphql_tools_1.SchemaDirectiveVisitor {
|
|
|
63
63
|
const { resolve = graphql_1.defaultFieldResolver } = field;
|
|
64
64
|
field.resolve = async (root, args, ctx, info) => {
|
|
65
65
|
const authArgs = parseArgs(this.args);
|
|
66
|
-
if (!authArgs.scope || authArgs.scope
|
|
66
|
+
if (!authArgs.scope || authArgs.scope === 'PRIVATE') {
|
|
67
67
|
await auth(ctx, authArgs);
|
|
68
68
|
}
|
|
69
69
|
return resolve(root, args, ctx, info);
|
|
@@ -61,8 +61,8 @@ async function timings(ctx, next) {
|
|
|
61
61
|
// We only need to provide the response-specific attributes here
|
|
62
62
|
if (global.diagnosticsMetrics) {
|
|
63
63
|
const responseAttributes = {
|
|
64
|
-
status_code: statusCode,
|
|
65
64
|
status,
|
|
65
|
+
status_code: statusCode,
|
|
66
66
|
};
|
|
67
67
|
// Record latency histogram (record all requests, not just successful ones)
|
|
68
68
|
global.diagnosticsMetrics.recordLatency(total, responseAttributes);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// It is used to build a full URL by combining a base URL with a relative URL.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
// It is originally not intended to be used directly, but rather as a utility function within the Axios library.
|
|
6
|
-
// Since Axios 1.0, this function is not exported by default, and the team does not recommend using it directly,
|
|
6
|
+
// Since Axios 1.0, this function is not exported by default, and the team does not recommend using it directly,
|
|
7
7
|
// as it may not be available in future versions.
|
|
8
8
|
// The function takes a base URL and a relative URL as input, and returns the full URL.
|
|
9
9
|
// It handles both absolute and relative URLs, and ensures that the resulting URL is properly formatted.
|
|
@@ -19,8 +19,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
* @returns {string} The combined full path
|
|
20
20
|
*/
|
|
21
21
|
function default_1(baseURL, requestedURL, allowAbsoluteUrls) {
|
|
22
|
-
|
|
23
|
-
if (baseURL && (isRelativeUrl || allowAbsoluteUrls
|
|
22
|
+
const isRelativeUrl = !isAbsoluteURL(requestedURL);
|
|
23
|
+
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
|
|
24
24
|
return combineURLs(baseURL, requestedURL);
|
|
25
25
|
}
|
|
26
26
|
return requestedURL;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtex/api",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "VTEX I/O API client",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"format-lint": "yarn format && yarn lint",
|
|
20
20
|
"prepublishOnly": "bash ./scripts/publishLock.sh",
|
|
21
21
|
"ci:build": "yarn build && yarn gen",
|
|
22
|
-
"ci:test": "yarn test --ci",
|
|
22
|
+
"ci:test": "yarn test --ci --coverage",
|
|
23
23
|
"ci:prettier-check": "prettier --check --config ./.prettierrc \"src/**/*.ts\" \"src/**/*.js\""
|
|
24
24
|
},
|
|
25
25
|
"jest": {
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LicenseManager = void 0;
|
|
4
|
-
const qs_1 = require("qs");
|
|
5
|
-
const JanusClient_1 = require("./JanusClient");
|
|
6
|
-
const TWO_MINUTES_S = 2 * 60;
|
|
7
|
-
const BASE_URL = '/api/license-manager';
|
|
8
|
-
const routes = {
|
|
9
|
-
accountData: `${BASE_URL}/account`,
|
|
10
|
-
resourceAccess: `${BASE_URL}/resources`,
|
|
11
|
-
topbarData: `${BASE_URL}/site/pvt/newtopbar`,
|
|
12
|
-
};
|
|
13
|
-
const inflightKey = ({ baseURL, url, params }) => {
|
|
14
|
-
return baseURL + url + (0, qs_1.stringify)(params, { arrayFormat: 'repeat', addQueryPrefix: true });
|
|
15
|
-
};
|
|
16
|
-
class LicenseManager extends JanusClient_1.JanusClient {
|
|
17
|
-
getAccountData(VtexIdclientAutCookie, tracingConfig) {
|
|
18
|
-
const metric = 'lm-account-data';
|
|
19
|
-
return this.http.get(routes.accountData, {
|
|
20
|
-
forceMaxAge: TWO_MINUTES_S,
|
|
21
|
-
headers: {
|
|
22
|
-
VtexIdclientAutCookie,
|
|
23
|
-
},
|
|
24
|
-
inflightKey,
|
|
25
|
-
metric,
|
|
26
|
-
tracing: {
|
|
27
|
-
requestSpanNameSuffix: metric,
|
|
28
|
-
...tracingConfig === null || tracingConfig === void 0 ? void 0 : tracingConfig.tracing,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
getTopbarData(VtexIdclientAutCookie, tracingConfig) {
|
|
33
|
-
const metric = 'lm-topbar-data';
|
|
34
|
-
return this.http.get(routes.topbarData, {
|
|
35
|
-
headers: {
|
|
36
|
-
VtexIdclientAutCookie,
|
|
37
|
-
},
|
|
38
|
-
metric,
|
|
39
|
-
tracing: {
|
|
40
|
-
requestSpanNameSuffix: metric,
|
|
41
|
-
...tracingConfig === null || tracingConfig === void 0 ? void 0 : tracingConfig.tracing,
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
canAccessResource(VtexIdclientAutCookie, resourceKey, tracingConfig) {
|
|
46
|
-
const metric = 'lm-resource-access';
|
|
47
|
-
return this.http.get(`${routes.resourceAccess}/${resourceKey}/access`, {
|
|
48
|
-
headers: {
|
|
49
|
-
VtexIdclientAutCookie,
|
|
50
|
-
},
|
|
51
|
-
metric,
|
|
52
|
-
tracing: {
|
|
53
|
-
requestSpanNameSuffix: metric,
|
|
54
|
-
...tracingConfig === null || tracingConfig === void 0 ? void 0 : tracingConfig.tracing,
|
|
55
|
-
},
|
|
56
|
-
}).then(() => true, () => false);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.LicenseManager = LicenseManager;
|