@gravity-ui/gateway 4.6.0 → 4.7.1-alpha.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.
Files changed (95) hide show
  1. package/README.md +179 -3
  2. package/{build → dist/commonjs}/components/grpc.d.ts +5 -5
  3. package/{build → dist/commonjs}/components/grpc.js +109 -90
  4. package/{build → dist/commonjs}/components/mixed.d.ts +4 -4
  5. package/{build → dist/commonjs}/components/mixed.js +11 -12
  6. package/{build → dist/commonjs}/components/rest.d.ts +5 -5
  7. package/{build → dist/commonjs}/components/rest.js +42 -35
  8. package/{build → dist/commonjs}/constants.d.ts +2 -2
  9. package/{build → dist/commonjs}/constants.js +29 -19
  10. package/{build → dist/commonjs}/index.d.ts +9 -8
  11. package/{build → dist/commonjs}/index.js +35 -46
  12. package/{build → dist/commonjs}/models/common.d.ts +19 -8
  13. package/{build → dist/commonjs}/models/context.d.ts +0 -1
  14. package/dist/commonjs/package.json +3 -0
  15. package/dist/commonjs/utils/axios.d.ts +4 -0
  16. package/{build → dist/commonjs}/utils/axios.js +3 -4
  17. package/{build → dist/commonjs}/utils/common.d.ts +4 -3
  18. package/{build → dist/commonjs}/utils/common.js +19 -8
  19. package/{build → dist/commonjs}/utils/create-context-api.d.ts +2 -2
  20. package/{build → dist/commonjs}/utils/create-context-api.js +5 -6
  21. package/{build → dist/commonjs}/utils/grpc-reflection.js +15 -35
  22. package/{build → dist/commonjs}/utils/grpc.d.ts +1 -1
  23. package/{build → dist/commonjs}/utils/grpc.js +10 -11
  24. package/dist/commonjs/utils/overrideEndpoints/index.d.ts +2 -0
  25. package/dist/commonjs/utils/overrideEndpoints/index.js +4 -0
  26. package/{build → dist/commonjs}/utils/overrideEndpoints/overrideEndpoints.d.ts +1 -1
  27. package/{build → dist/commonjs}/utils/overrideEndpoints/overrideEndpoints.js +1 -2
  28. package/dist/commonjs/utils/package-root.d.ts +1 -0
  29. package/dist/commonjs/utils/package-root.js +44 -0
  30. package/{build → dist/commonjs}/utils/parse-error.d.ts +5 -5
  31. package/{build → dist/commonjs}/utils/parse-error.js +19 -19
  32. package/{build → dist/commonjs}/utils/proto-path-resolver.d.ts +1 -1
  33. package/{build → dist/commonjs}/utils/proto-path-resolver.js +24 -15
  34. package/{build → dist/commonjs}/utils/redact-sensitive-headers.d.ts +1 -2
  35. package/{build → dist/commonjs}/utils/redact-sensitive-headers.js +1 -2
  36. package/dist/commonjs/utils/source-dir.d.ts +1 -0
  37. package/dist/commonjs/utils/source-dir.js +41 -0
  38. package/{build → dist/commonjs}/utils/typed-api.d.ts +1 -1
  39. package/{build → dist/commonjs}/utils/typed-api.js +1 -2
  40. package/{build → dist/commonjs}/utils/validate.js +6 -10
  41. package/dist/esm/components/grpc.d.ts +24 -0
  42. package/dist/esm/components/grpc.js +691 -0
  43. package/dist/esm/components/mixed.d.ts +11 -0
  44. package/dist/esm/components/mixed.js +62 -0
  45. package/dist/esm/components/rest.d.ts +8 -0
  46. package/dist/esm/components/rest.js +357 -0
  47. package/dist/esm/constants.d.ts +53 -0
  48. package/dist/esm/constants.js +82 -0
  49. package/dist/esm/index.d.ts +13 -0
  50. package/dist/esm/index.js +274 -0
  51. package/dist/esm/models/common.d.ts +289 -0
  52. package/dist/esm/models/common.js +5 -0
  53. package/dist/esm/models/context.d.ts +22 -0
  54. package/dist/esm/models/context.js +1 -0
  55. package/dist/esm/models/error.d.ts +12 -0
  56. package/dist/esm/models/error.js +1 -0
  57. package/dist/esm/package.json +3 -0
  58. package/{build → dist/esm}/utils/axios.d.ts +1 -1
  59. package/dist/esm/utils/axios.js +24 -0
  60. package/dist/esm/utils/common.d.ts +16 -0
  61. package/dist/esm/utils/common.js +48 -0
  62. package/dist/esm/utils/create-context-api.d.ts +4 -0
  63. package/dist/esm/utils/create-context-api.js +38 -0
  64. package/dist/esm/utils/grpc-reflection.d.ts +28 -0
  65. package/dist/esm/utils/grpc-reflection.js +72 -0
  66. package/dist/esm/utils/grpc.d.ts +15 -0
  67. package/dist/esm/utils/grpc.js +72 -0
  68. package/dist/esm/utils/overrideEndpoints/index.d.ts +2 -0
  69. package/dist/esm/utils/overrideEndpoints/index.js +2 -0
  70. package/dist/esm/utils/overrideEndpoints/overrideEndpoints.d.ts +17 -0
  71. package/dist/esm/utils/overrideEndpoints/overrideEndpoints.js +96 -0
  72. package/dist/esm/utils/package-root.d.ts +1 -0
  73. package/dist/esm/utils/package-root.js +8 -0
  74. package/dist/esm/utils/parse-error.d.ts +30 -0
  75. package/dist/esm/utils/parse-error.js +214 -0
  76. package/dist/esm/utils/proto-path-resolver.d.ts +2 -0
  77. package/dist/esm/utils/proto-path-resolver.js +23 -0
  78. package/dist/esm/utils/redact-sensitive-headers.d.ts +3 -0
  79. package/dist/esm/utils/redact-sensitive-headers.js +12 -0
  80. package/dist/esm/utils/source-dir.d.ts +1 -0
  81. package/dist/esm/utils/source-dir.js +4 -0
  82. package/dist/esm/utils/typed-api.d.ts +2 -0
  83. package/dist/esm/utils/typed-api.js +3 -0
  84. package/dist/esm/utils/validate.d.ts +4 -0
  85. package/dist/esm/utils/validate.js +47 -0
  86. package/package.json +41 -16
  87. package/build/utils/overrideEndpoints/index.d.ts +0 -2
  88. package/build/utils/overrideEndpoints/index.js +0 -4
  89. /package/bin/{patch.js → patch.cjs} +0 -0
  90. /package/{build → dist/commonjs}/models/common.js +0 -0
  91. /package/{build → dist/commonjs}/models/context.js +0 -0
  92. /package/{build → dist/commonjs}/models/error.d.ts +0 -0
  93. /package/{build → dist/commonjs}/models/error.js +0 -0
  94. /package/{build → dist/commonjs}/utils/grpc-reflection.d.ts +0 -0
  95. /package/{build → dist/commonjs}/utils/validate.d.ts +0 -0
@@ -0,0 +1,11 @@
1
+ import { ApiActionConfig, ApiByScope, ApiServiceMixedActionConfig, GatewayConfig, GatewayRequest, GatewayResponse, SchemasByScope } from '../models/common.js';
2
+ import { GatewayContext } from '../models/context.js';
3
+ import { AppErrorConstructor } from '../models/error.js';
4
+ import type { GrpcContext } from './grpc.js';
5
+ export declare function createMixedAction<TSchema extends SchemasByScope, Context extends GatewayContext, Req extends GatewayRequest<Context>, Res extends GatewayResponse>(config: ApiServiceMixedActionConfig<Context, Req, Res, any, any, any>, api: ApiByScope<TSchema, Context, Req, Res>, serviceName: string, actionName: string, extra: {
6
+ config: GatewayConfig<Context, Req, Res>;
7
+ grpcContext: GrpcContext;
8
+ }, ErrorConstructor: AppErrorConstructor): (actionConfig: ApiActionConfig<Context, any>) => Promise<{
9
+ responseData: any;
10
+ debugHeaders: {};
11
+ }>;
@@ -0,0 +1,62 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { DEFAULT_LANG_HEADER, Lang } from '../constants.js';
13
+ import { handleError } from '../utils/common.js';
14
+ import { generateContextApi } from '../utils/create-context-api.js';
15
+ import { parseMixedError } from '../utils/parse-error.js';
16
+ export function createMixedAction(config, api, serviceName, actionName, extra, ErrorConstructor) {
17
+ return async (actionConfig) => {
18
+ const { args } = actionConfig, context = __rest(actionConfig, ["args"]);
19
+ const ctx = actionConfig.ctx.create(`Gateway ${serviceName} ${actionName} [mixed]`, {
20
+ tags: {
21
+ action: actionName,
22
+ service: serviceName,
23
+ type: 'mixed',
24
+ },
25
+ });
26
+ const contextApi = generateContextApi(api, Object.assign(Object.assign({}, context), { ctx }));
27
+ try {
28
+ const responseData = await config(contextApi, args, Object.assign(Object.assign({ headers: actionConfig.headers, lang: actionConfig.headers[DEFAULT_LANG_HEADER] || Lang.Ru, ctx }, extra), { abortSignal: actionConfig.abortSignal }));
29
+ ctx.log('Request completed');
30
+ return {
31
+ responseData,
32
+ debugHeaders: {},
33
+ };
34
+ }
35
+ catch (e) {
36
+ if (e instanceof Object && 'error' in e) {
37
+ handleError(ErrorConstructor, e, ctx, 'Request failed', {
38
+ actionName,
39
+ serviceName,
40
+ });
41
+ throw e;
42
+ }
43
+ if (e instanceof Error) {
44
+ const parsedError = parseMixedError(e);
45
+ handleError(ErrorConstructor, e, ctx, 'Request failed', {
46
+ actionName,
47
+ serviceName,
48
+ });
49
+ throw {
50
+ error: parsedError,
51
+ };
52
+ }
53
+ handleError(ErrorConstructor, e, ctx, 'Request failed');
54
+ throw {
55
+ error: e,
56
+ };
57
+ }
58
+ finally {
59
+ ctx.end();
60
+ }
61
+ };
62
+ }
@@ -0,0 +1,8 @@
1
+ import { ApiActionConfig, ApiServiceRestActionConfig, EndpointsConfig, GatewayApiOptions, Headers } from '../models/common.js';
2
+ import { GatewayContext } from '../models/context.js';
3
+ import { AppErrorConstructor } from '../models/error.js';
4
+ export declare function createRestAction<Context extends GatewayContext>(endpoints: EndpointsConfig | undefined, config: ApiServiceRestActionConfig<Context, any, any>, serviceKey: string, actionName: string, options: GatewayApiOptions<Context>, ErrorConstructor: AppErrorConstructor): (actionConfig: ApiActionConfig<Context, any>) => Promise<{
5
+ responseData: unknown;
6
+ responseHeaders?: Headers;
7
+ debugHeaders: Headers;
8
+ }>;
@@ -0,0 +1,357 @@
1
+ import querystring from 'querystring';
2
+ import url from 'url';
3
+ import _ from 'lodash';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { DEFAULT_LANG_HEADER, DEFAULT_PROXY_HEADERS, DEFAULT_TIMEOUT, ECMA_STRING_SIZE, Lang, VERSION, } from '../constants.js';
6
+ import { getAxiosClient } from '../utils/axios.js';
7
+ import { getProxyHeadersArgs, handleError, isExtendedActionEndpoint, isExtendedRestActionEndpoint, sanitizeDebugHeaders, } from '../utils/common.js';
8
+ import { parseRestError } from '../utils/parse-error.js';
9
+ import { redactSensitiveHeaders } from '../utils/redact-sensitive-headers.js';
10
+ import { encodePathParams, getPathArgsProxy, validateArgs } from '../utils/validate.js';
11
+ function getRestResponseSize(data, ctx, ErrorConstructor) {
12
+ var _a;
13
+ let responseSize = 0;
14
+ try {
15
+ responseSize = ECMA_STRING_SIZE * ((_a = JSON.stringify(data)) === null || _a === void 0 ? void 0 : _a.length);
16
+ }
17
+ catch (error) {
18
+ handleError(ErrorConstructor, error, ctx, 'Calculate response size failed');
19
+ }
20
+ return responseSize;
21
+ }
22
+ function getConfigSerializerFunction(config) {
23
+ if (typeof config.paramsSerializer === 'function') {
24
+ return config.paramsSerializer;
25
+ }
26
+ if (config.paramsSerializer && 'serialize' in config.paramsSerializer) {
27
+ return config.paramsSerializer.serialize;
28
+ }
29
+ return undefined;
30
+ }
31
+ export function createRestAction(endpoints, config, serviceKey, actionName, options, ErrorConstructor) {
32
+ var _a, _b, _c, _d;
33
+ const timeout = (_c = (_a = config === null || config === void 0 ? void 0 : config.timeout) !== null && _a !== void 0 ? _a : (_b = options === null || options === void 0 ? void 0 : options.axiosConfig) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : options === null || options === void 0 ? void 0 : options.timeout;
34
+ const defaultAxiosClient = getAxiosClient(timeout, config === null || config === void 0 ? void 0 : config.retries, (_d = config === null || config === void 0 ? void 0 : config.axiosRetryCondition) !== null && _d !== void 0 ? _d : options === null || options === void 0 ? void 0 : options.axiosRetryCondition, options === null || options === void 0 ? void 0 : options.axiosConfig, options === null || options === void 0 ? void 0 : options.axiosInterceptors);
35
+ /* eslint-disable complexity */
36
+ return async function action(actionConfig) {
37
+ var _a, _b, _c, _d, _e, _f, _g, _h;
38
+ const { args, requestId, headers: requestHeaders, ctx: parentCtx, authArgs, userId, abortSignal, } = actionConfig;
39
+ const debugHeaders = {};
40
+ const lang = requestHeaders[DEFAULT_LANG_HEADER] || Lang.Ru; // header might be empty string
41
+ const serviceName = (options === null || options === void 0 ? void 0 : options.serviceName) || serviceKey;
42
+ const idempotency = config.idempotency;
43
+ const ctx = parentCtx.create(`Gateway ${serviceName} ${actionName} [rest]`, {
44
+ tags: {
45
+ action: actionName,
46
+ service: serviceName,
47
+ type: 'rest',
48
+ },
49
+ });
50
+ ctx.log('Initiating request');
51
+ const validationSchema = config.validationSchema || options.validationSchema;
52
+ if (validationSchema) {
53
+ const invalidParams = validateArgs(args, validationSchema);
54
+ if (invalidParams) {
55
+ ctx.log('Invalid params', { invalidParams });
56
+ ctx.end();
57
+ return Promise.reject({
58
+ error: {
59
+ status: 400,
60
+ message: 'Validation failed',
61
+ code: 'INVALID_PARAMS',
62
+ details: {
63
+ title: 'Invalid params',
64
+ description: invalidParams,
65
+ },
66
+ },
67
+ debugHeaders,
68
+ });
69
+ }
70
+ }
71
+ let endpointData = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpoint;
72
+ if (typeof config.endpoint === 'function') {
73
+ endpointData = config.endpoint(endpoints, args);
74
+ }
75
+ else if (config.endpoint) {
76
+ endpointData = _.get(endpoints, [config.endpoint]);
77
+ }
78
+ if (!endpointData) {
79
+ const errorText = `Gateway config error. Endpoint has been not found in service "${serviceKey}"`;
80
+ ctx.log(errorText, { serviceName, actionName });
81
+ ctx.end();
82
+ return Promise.reject({
83
+ error: {
84
+ status: 400,
85
+ code: 'ENDPOINT_NOT_FOUND',
86
+ message: errorText,
87
+ },
88
+ });
89
+ }
90
+ const actionEndpoint = isExtendedActionEndpoint(endpointData)
91
+ ? endpointData.path
92
+ : endpointData;
93
+ const endpointAxiosConfig = isExtendedRestActionEndpoint(endpointData)
94
+ ? endpointData.axiosConfig
95
+ : undefined;
96
+ const pathArgs = config.validationSchema
97
+ ? encodePathParams(args)
98
+ : getPathArgsProxy(args, options.encodePathArgs);
99
+ const actionPath = typeof config.path === 'function' ? config.path(pathArgs) : config.path;
100
+ const actionURL = actionEndpoint + actionPath;
101
+ const parsedActionURL = url.parse(actionURL);
102
+ const proxyHeaders = [...DEFAULT_PROXY_HEADERS];
103
+ let actionHeaders = {
104
+ // It's important not to lose the port in HOST header
105
+ host: (_a = parsedActionURL.host) !== null && _a !== void 0 ? _a : undefined,
106
+ accept: 'application/json, */*',
107
+ 'accept-encoding': 'gzip, deflate',
108
+ 'accept-language': lang,
109
+ 'x-gateway-version': VERSION,
110
+ };
111
+ let proxyHeadersExtra;
112
+ const proxyHeadersCaller = (proxyHeadersFunc) => {
113
+ if (proxyHeadersExtra === undefined) {
114
+ proxyHeadersExtra = getProxyHeadersArgs(serviceName, actionName);
115
+ }
116
+ return proxyHeadersFunc(Object.assign({}, requestHeaders), 'rest', proxyHeadersExtra);
117
+ };
118
+ if (typeof options.proxyHeaders === 'function') {
119
+ Object.assign(actionHeaders, proxyHeadersCaller(options.proxyHeaders));
120
+ }
121
+ else if (Array.isArray(options.proxyHeaders)) {
122
+ proxyHeaders.push(...options.proxyHeaders);
123
+ }
124
+ if (typeof config.proxyHeaders === 'function') {
125
+ Object.assign(actionHeaders, proxyHeadersCaller(config.proxyHeaders));
126
+ }
127
+ else if (Array.isArray(config.proxyHeaders)) {
128
+ proxyHeaders.push(...config.proxyHeaders);
129
+ }
130
+ for (const headerName of proxyHeaders) {
131
+ if (actionHeaders[headerName] === undefined) {
132
+ actionHeaders[headerName] = requestHeaders[headerName];
133
+ }
134
+ }
135
+ if (requestId) {
136
+ actionHeaders['x-request-id'] = requestId;
137
+ }
138
+ if (idempotency) {
139
+ actionHeaders['idempotency-key'] = requestHeaders['idempotency-key'] || uuidv4();
140
+ }
141
+ const authHeaders = ((_b = config.getAuthHeaders) !== null && _b !== void 0 ? _b : options.getAuthHeaders)({
142
+ actionType: 'rest',
143
+ serviceName,
144
+ requestHeaders,
145
+ authArgs,
146
+ });
147
+ Object.assign(actionHeaders, authHeaders);
148
+ actionHeaders = _.omitBy(actionHeaders, _.isUndefined);
149
+ let params;
150
+ if (config.params) {
151
+ try {
152
+ params = await config.params(args, actionHeaders, { ctx });
153
+ }
154
+ catch (error) {
155
+ handleError(ErrorConstructor, error, ctx, 'Getting config params failed');
156
+ }
157
+ }
158
+ const { body = undefined, query = undefined, headers = actionHeaders } = params !== null && params !== void 0 ? params : {};
159
+ let requestBody;
160
+ const serializer = getConfigSerializerFunction(config);
161
+ const preparedQuery = serializer && query ? serializer(query) : querystring.stringify(query);
162
+ const requestUrl = actionURL + (query ? '?' + preparedQuery : '');
163
+ try {
164
+ let encodedRequestBody = '';
165
+ if (body instanceof Buffer) {
166
+ encodedRequestBody = '[Buffer]';
167
+ }
168
+ else {
169
+ encodedRequestBody = encodeURIComponent(typeof body === 'object' ? JSON.stringify(body) : String(body));
170
+ }
171
+ if (encodedRequestBody.length < 256) {
172
+ requestBody = encodedRequestBody;
173
+ }
174
+ }
175
+ catch (error) {
176
+ handleError(ErrorConstructor, error, ctx, 'Stringify request body failed');
177
+ }
178
+ Object.assign(debugHeaders, {
179
+ 'x-api-request-method': config.method,
180
+ 'x-api-request-url': requestUrl,
181
+ 'x-api-request-body': requestBody ? requestBody : null,
182
+ 'x-api-request-lang': lang,
183
+ 'x-request-id': requestId,
184
+ 'x-gateway-version': VERSION,
185
+ });
186
+ if (headers['content-type']) {
187
+ debugHeaders['x-api-content-type'] = headers['content-type'];
188
+ }
189
+ if (typeof options.proxyDebugHeaders === 'function') {
190
+ Object.assign(debugHeaders, proxyHeadersCaller(options.proxyDebugHeaders));
191
+ }
192
+ else if (Array.isArray(options.proxyDebugHeaders)) {
193
+ for (const headerName of options.proxyDebugHeaders) {
194
+ if (headers[headerName] !== undefined) {
195
+ debugHeaders[`x-gateway-${headerName}`] = headers[headerName];
196
+ }
197
+ }
198
+ }
199
+ const startRequestTime = Date.now();
200
+ let axiosClient = defaultAxiosClient;
201
+ const customActionTimeout = (_e = (_d = (_c = actionConfig.timeout) !== null && _c !== void 0 ? _c : config.timeout) !== null && _d !== void 0 ? _d : endpointAxiosConfig === null || endpointAxiosConfig === void 0 ? void 0 : endpointAxiosConfig.timeout) !== null && _e !== void 0 ? _e : timeout;
202
+ if (actionConfig.timeout || endpointAxiosConfig) {
203
+ const customActionAxiosConfig = Object.assign(Object.assign({}, ((options === null || options === void 0 ? void 0 : options.axiosConfig) || {})), (endpointAxiosConfig || {}));
204
+ axiosClient = getAxiosClient(customActionTimeout, config === null || config === void 0 ? void 0 : config.retries, options.axiosRetryCondition, customActionAxiosConfig, options === null || options === void 0 ? void 0 : options.axiosInterceptors);
205
+ }
206
+ headers['x-request-timeout'] = customActionTimeout !== null && customActionTimeout !== void 0 ? customActionTimeout : DEFAULT_TIMEOUT;
207
+ ctx.log('Starting request', { debugHeaders: sanitizeDebugHeaders(debugHeaders) });
208
+ const requestData = {
209
+ timestamp: startRequestTime,
210
+ service: serviceName,
211
+ action: actionName,
212
+ requestId,
213
+ requestMethod: config.method,
214
+ requestUrl: actionURL,
215
+ traceId: ((_f = ctx.getTraceId) === null || _f === void 0 ? void 0 : _f.call(ctx)) || '',
216
+ userId: userId || '',
217
+ };
218
+ const requestConfig = {
219
+ url: actionURL,
220
+ method: config.method,
221
+ data: body,
222
+ params: query,
223
+ headers: ctx ? Object.assign(Object.assign({}, ctx.getMetadata()), headers) : headers,
224
+ maxRedirects: config.maxRedirects,
225
+ signal: config.abortOnClientDisconnect ? abortSignal : undefined,
226
+ };
227
+ if (config.paramsSerializer) {
228
+ Object.assign(requestConfig, {
229
+ paramsSerializer: config.paramsSerializer,
230
+ });
231
+ }
232
+ if (config.responseType) {
233
+ Object.assign(requestConfig, {
234
+ responseType: config.responseType,
235
+ });
236
+ }
237
+ try {
238
+ const response = await axiosClient.request(requestConfig);
239
+ const responseHeaders = {};
240
+ const endRequestTime = Date.now();
241
+ requestData.requestTime = endRequestTime - startRequestTime;
242
+ const actualResponseContentType = (_g = response.headers) === null || _g === void 0 ? void 0 : _g['Content-Type'];
243
+ const expectedResponseContentType = config.expectedResponseContentType || options.expectedResponseContentType;
244
+ if (actualResponseContentType && expectedResponseContentType) {
245
+ let isInvalidResponseContentType;
246
+ if (Array.isArray(expectedResponseContentType)) {
247
+ isInvalidResponseContentType = !expectedResponseContentType.includes(String(actualResponseContentType));
248
+ }
249
+ else {
250
+ isInvalidResponseContentType =
251
+ expectedResponseContentType !== actualResponseContentType;
252
+ }
253
+ if (isInvalidResponseContentType) {
254
+ ctx.log('Invalid response content type', {
255
+ expectedResponseContentType,
256
+ actualResponseContentType,
257
+ });
258
+ ctx.end();
259
+ return Promise.reject({
260
+ error: {
261
+ status: 415,
262
+ message: 'Response content type validation failed',
263
+ code: 'INVALID_RESPONSE_CONTENT_TYPE',
264
+ details: {
265
+ title: 'Invalid response content type',
266
+ description: `Expected to get ${expectedResponseContentType} but got ${actualResponseContentType}`,
267
+ },
268
+ },
269
+ debugHeaders,
270
+ });
271
+ }
272
+ }
273
+ if (config.transformResponseData) {
274
+ try {
275
+ response.data = await config.transformResponseData(response.data, {
276
+ args,
277
+ ctx,
278
+ headers: response.headers,
279
+ });
280
+ ctx.log('Transformed response data');
281
+ }
282
+ catch (error) {
283
+ handleError(ErrorConstructor, error, ctx, 'Transform response data failed');
284
+ }
285
+ }
286
+ if (config.proxyResponseHeaders) {
287
+ const proxyResponseHeaders = [];
288
+ if (typeof config.proxyResponseHeaders === 'function') {
289
+ Object.assign(responseHeaders, config.proxyResponseHeaders(Object.assign({}, response.headers), 'rest'));
290
+ }
291
+ else if (Array.isArray(config.proxyResponseHeaders)) {
292
+ proxyResponseHeaders.push(...config.proxyResponseHeaders);
293
+ }
294
+ for (const headerName of proxyResponseHeaders) {
295
+ if (responseHeaders[headerName] === undefined) {
296
+ responseHeaders[headerName] = response.headers[headerName];
297
+ }
298
+ }
299
+ }
300
+ if (options === null || options === void 0 ? void 0 : options.sendStats) {
301
+ options.sendStats(Object.assign(Object.assign({}, requestData), { responseSize: getRestResponseSize(response === null || response === void 0 ? void 0 : response.data, ctx, ErrorConstructor), restStatus: 200 }), redactSensitiveHeaders(parentCtx, headers), parentCtx, { debugHeaders: sanitizeDebugHeaders(debugHeaders) });
302
+ }
303
+ else {
304
+ ctx.stats(Object.assign(Object.assign({}, requestData), { responseStatus: 200 }));
305
+ }
306
+ ctx.log('Request completed', { debugHeaders: sanitizeDebugHeaders(debugHeaders) });
307
+ ctx.end();
308
+ return { responseData: response.data, responseHeaders, debugHeaders };
309
+ }
310
+ catch (error) {
311
+ let parsedError;
312
+ const endRequestTime = new Date().getTime();
313
+ requestData.requestTime = endRequestTime - startRequestTime;
314
+ if (error &&
315
+ error instanceof Object &&
316
+ 'response' in error &&
317
+ config.transformResponseError) {
318
+ try {
319
+ parsedError = await config.transformResponseError(error.response, {
320
+ args,
321
+ ctx,
322
+ });
323
+ ctx.log('Transformed response error');
324
+ }
325
+ catch (error) {
326
+ handleError(ErrorConstructor, error, ctx, 'Transform response error failed');
327
+ }
328
+ }
329
+ if (!parsedError) {
330
+ try {
331
+ parsedError = parseRestError(error, lang);
332
+ }
333
+ catch (error) {
334
+ handleError(ErrorConstructor, error, ctx, 'Error parse rest error');
335
+ }
336
+ }
337
+ const responseStatus = _.get(parsedError, 'status') || _.get(error, 'status', 500);
338
+ if (options === null || options === void 0 ? void 0 : options.sendStats) {
339
+ options.sendStats(Object.assign(Object.assign({}, requestData), { responseSize: getRestResponseSize((_h = error === null || error === void 0 ? void 0 : error.response) === null || _h === void 0 ? void 0 : _h.data, ctx, ErrorConstructor), restStatus: responseStatus, userId }), redactSensitiveHeaders(parentCtx, headers), parentCtx, { debugHeaders: sanitizeDebugHeaders(debugHeaders) });
340
+ }
341
+ else {
342
+ ctx.stats(Object.assign(Object.assign({}, requestData), { responseStatus }));
343
+ }
344
+ ctx.logError('Request failed', error, {
345
+ actionURL,
346
+ parsedError,
347
+ serviceName,
348
+ debugHeaders: sanitizeDebugHeaders(debugHeaders),
349
+ });
350
+ ctx.end();
351
+ return Promise.reject({
352
+ error: Object.assign(Object.assign({}, parsedError), { requestId }),
353
+ debugHeaders,
354
+ });
355
+ }
356
+ };
357
+ }
@@ -0,0 +1,53 @@
1
+ import * as http from 'http';
2
+ import * as https from 'https';
3
+ import * as grpc from '@grpc/grpc-js';
4
+ export declare const VERSION: any;
5
+ export declare enum Lang {
6
+ Ru = "ru",
7
+ En = "en"
8
+ }
9
+ export declare const DEFAULT_TIMEOUT: number;
10
+ export declare const DEFAULT_LANG_HEADER = "accept-language";
11
+ export declare const DEFAULT_PROXY_HEADERS: string[];
12
+ export declare const DEFAULT_AXIOS_OPTIONS: {
13
+ maxContentLength: number;
14
+ httpAgent: http.Agent;
15
+ httpsAgent: https.Agent;
16
+ };
17
+ export declare const DEFAULT_GRPC_OPTIONS: {
18
+ 'grpc.max_receive_message_length': number;
19
+ 'grpc.keepalive_time_ms': number;
20
+ 'grpc.keepalive_timeout_ms': number;
21
+ 'grpc.keepalive_permit_without_calls': number;
22
+ };
23
+ export declare const DEFAULT_PROTO_LOADER_OPTIONS: {
24
+ longs: StringConstructor;
25
+ enums: StringConstructor;
26
+ defaults: boolean;
27
+ oneofs: boolean;
28
+ };
29
+ /**
30
+ * Byte sizes are taken from ECMAScript Language Specification
31
+ * http://www.ecma-international.org/ecma-262/5.1/
32
+ */
33
+ export declare const ECMA_STRING_SIZE = 2;
34
+ export declare const ANY_ACTION_SYMBOL = "*";
35
+ export declare const RETRYABLE_STATUS_CODES: Array<grpc.status | undefined>;
36
+ export declare const RECREATE_SERVICE_CODES: Array<grpc.status | undefined>;
37
+ /**
38
+ * Common validation schema for action's parameters. You can use it in GatewayConfig as validationSchema
39
+ * Validates the parameter type: only number, object, or string are allowed.
40
+ * For strings, disallows characters: ".", "?", "#", "/", "\"
41
+ */
42
+ export declare const DEFAULT_VALIDATION_SCHEMA: {
43
+ additionalProperties: {
44
+ oneOf: ({
45
+ type: string;
46
+ pattern?: undefined;
47
+ } | {
48
+ type: string;
49
+ pattern: string;
50
+ })[];
51
+ };
52
+ };
53
+ export declare const AXIOS_RETRY_NAMESPACE = "axios-retry";
@@ -0,0 +1,82 @@
1
+ import * as fs from 'fs';
2
+ import * as http from 'http';
3
+ import * as https from 'https';
4
+ import * as path from 'path';
5
+ import * as grpc from '@grpc/grpc-js';
6
+ import { packageRoot } from './utils/package-root.js';
7
+ const packageJson = JSON.parse(fs.readFileSync(path.resolve(packageRoot, 'package.json'), 'utf-8'));
8
+ export const VERSION = packageJson.version;
9
+ export var Lang;
10
+ (function (Lang) {
11
+ Lang["Ru"] = "ru";
12
+ Lang["En"] = "en";
13
+ })(Lang || (Lang = {}));
14
+ export const DEFAULT_TIMEOUT = 25 * 1000;
15
+ export const DEFAULT_LANG_HEADER = 'accept-language';
16
+ export const DEFAULT_PROXY_HEADERS = [
17
+ 'origin',
18
+ 'user-agent',
19
+ 'referer',
20
+ 'x-real-ip',
21
+ 'x-forwarded-for',
22
+ ];
23
+ export const DEFAULT_AXIOS_OPTIONS = {
24
+ maxContentLength: 1024 * 1024 * 100, // 100 Mb
25
+ httpAgent: new http.Agent({
26
+ // https://github.com/nodejs/node/blob/master/lib/_http_agent.js#L233
27
+ family: 6,
28
+ }),
29
+ httpsAgent: new https.Agent({
30
+ // https://github.com/nodejs/node/blob/master/lib/_http_agent.js#L233
31
+ family: 6,
32
+ }),
33
+ };
34
+ export const DEFAULT_GRPC_OPTIONS = {
35
+ 'grpc.max_receive_message_length': 1024 * 1024 * 100, // 100 Mb
36
+ 'grpc.keepalive_time_ms': 10000,
37
+ 'grpc.keepalive_timeout_ms': 1000,
38
+ 'grpc.keepalive_permit_without_calls': 1,
39
+ };
40
+ export const DEFAULT_PROTO_LOADER_OPTIONS = {
41
+ longs: String,
42
+ enums: String,
43
+ defaults: true,
44
+ oneofs: true,
45
+ };
46
+ /**
47
+ * Byte sizes are taken from ECMAScript Language Specification
48
+ * http://www.ecma-international.org/ecma-262/5.1/
49
+ */
50
+ export const ECMA_STRING_SIZE = 2;
51
+ export const ANY_ACTION_SYMBOL = '*';
52
+ export const RETRYABLE_STATUS_CODES = [
53
+ grpc.status.UNAVAILABLE,
54
+ grpc.status.CANCELLED,
55
+ grpc.status.ABORTED,
56
+ grpc.status.UNKNOWN,
57
+ ];
58
+ export const RECREATE_SERVICE_CODES = [
59
+ grpc.status.DEADLINE_EXCEEDED,
60
+ ];
61
+ /**
62
+ * Common validation schema for action's parameters. You can use it in GatewayConfig as validationSchema
63
+ * Validates the parameter type: only number, object, or string are allowed.
64
+ * For strings, disallows characters: ".", "?", "#", "/", "\"
65
+ */
66
+ export const DEFAULT_VALIDATION_SCHEMA = {
67
+ additionalProperties: {
68
+ oneOf: [
69
+ {
70
+ type: 'number',
71
+ },
72
+ {
73
+ type: 'string',
74
+ pattern: '^((?!(\\.\\.|\\?|#|\\\\|\\/)).)*$',
75
+ },
76
+ {
77
+ type: 'object',
78
+ },
79
+ ],
80
+ },
81
+ };
82
+ export const AXIOS_RETRY_NAMESPACE = 'axios-retry';
@@ -0,0 +1,13 @@
1
+ import { ApiWithRoot, GatewayConfig, GatewayRequest, GatewayResponse, SchemasByScope } from './models/common.js';
2
+ import { GatewayContext } from './models/context.js';
3
+ export * from './utils/typed-api.js';
4
+ export * from './utils/grpc-reflection.js';
5
+ export { isRetryableGrpcError } from './utils/grpc.js';
6
+ export * from './models/common.js';
7
+ export * from './models/context.js';
8
+ export * from './models/error.js';
9
+ export declare function getGatewayControllers<TSchema extends SchemasByScope, Context extends GatewayContext, Req extends GatewayRequest<Context>, Res extends GatewayResponse>(schemasByScope: TSchema, config: GatewayConfig<Context, Req, Res>): {
10
+ controller: (req: Req, res: Res) => Promise<any>;
11
+ api: ApiWithRoot<TSchema, Context, Req, Res>;
12
+ };
13
+ export default getGatewayControllers;