@chainlink/external-adapter-framework 0.0.46 → 0.0.56
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/adapter.d.ts +18 -1
- package/adapter.js +69 -3
- package/adapter.js.map +1 -0
- package/background-executor.js +31 -0
- package/background-executor.js.map +1 -0
- package/cache/factory.d.ts +2 -2
- package/cache/factory.js +11 -46
- package/cache/factory.js.map +1 -0
- package/cache/index.js +3 -2
- package/cache/index.js.map +1 -0
- package/cache/local.js.map +1 -0
- package/cache/metrics.js.map +1 -0
- package/cache/redis.js.map +1 -0
- package/config/index.d.ts +34 -0
- package/config/index.js +40 -62
- package/config/index.js.map +1 -0
- package/config/provider-limits.js.map +1 -0
- package/examples/bank-frick/accounts.d.ts +15 -1
- package/examples/bank-frick/accounts.js.map +1 -0
- package/examples/bank-frick/config/index.d.ts +15 -2
- package/examples/bank-frick/config/index.js.map +1 -0
- package/examples/bank-frick/index.d.ts +15 -1
- package/examples/bank-frick/index.js.map +1 -0
- package/examples/bank-frick/util.js.map +1 -0
- package/examples/coingecko/batch-warming.d.ts +7 -0
- package/examples/coingecko/batch-warming.js +54 -0
- package/examples/coingecko/batch-warming.js.map +1 -0
- package/examples/coingecko/index.d.ts +2 -0
- package/examples/coingecko/index.js +12 -0
- package/examples/coingecko/index.js.map +1 -0
- package/examples/coingecko/rest.d.ts +12 -0
- package/examples/coingecko/rest.js +55 -0
- package/examples/coingecko/rest.js.map +1 -0
- package/examples/coingecko/src/config/index.js.map +1 -0
- package/examples/coingecko/src/crypto-utils.d.ts +31 -0
- package/examples/coingecko/src/crypto-utils.js +60 -0
- package/examples/coingecko/src/crypto-utils.js.map +1 -0
- package/examples/coingecko/src/endpoint/coins.js +3 -1
- package/examples/coingecko/src/endpoint/coins.js.map +1 -0
- package/examples/coingecko/src/endpoint/crypto-marketcap.d.ts +1 -1
- package/examples/coingecko/src/endpoint/crypto-marketcap.js +4 -4
- package/examples/coingecko/src/endpoint/crypto-marketcap.js.map +1 -0
- package/examples/coingecko/src/endpoint/crypto-volume.d.ts +1 -1
- package/examples/coingecko/src/endpoint/crypto-volume.js +4 -4
- package/examples/coingecko/src/endpoint/crypto-volume.js.map +1 -0
- package/examples/coingecko/src/endpoint/crypto.d.ts +1 -1
- package/examples/coingecko/src/endpoint/crypto.js +4 -4
- package/examples/coingecko/src/endpoint/crypto.js.map +1 -0
- package/examples/coingecko/src/endpoint/dominance.d.ts +1 -1
- package/examples/coingecko/src/endpoint/dominance.js +4 -4
- package/examples/coingecko/src/endpoint/dominance.js.map +1 -0
- package/examples/coingecko/src/endpoint/global-marketcap.d.ts +1 -1
- package/examples/coingecko/src/endpoint/global-marketcap.js +4 -4
- package/examples/coingecko/src/endpoint/global-marketcap.js.map +1 -0
- package/examples/coingecko/src/endpoint/index.js.map +1 -0
- package/examples/coingecko/src/global-utils.d.ts +27 -0
- package/examples/coingecko/src/global-utils.js +46 -0
- package/examples/coingecko/src/global-utils.js.map +1 -0
- package/examples/coingecko/src/index.d.ts +1 -1
- package/examples/coingecko/src/index.js.map +1 -0
- package/examples/coingecko-old/batch-warming.js.map +1 -0
- package/examples/coingecko-old/index.js.map +1 -0
- package/examples/coingecko-old/rest.js +4 -1
- package/examples/coingecko-old/rest.js.map +1 -0
- package/examples/genesis/config/index.d.ts +7 -0
- package/examples/genesis/config/index.js +10 -0
- package/examples/genesis/config/index.js.map +1 -0
- package/examples/genesis/index.d.ts +2 -0
- package/examples/genesis/index.js +12 -0
- package/examples/genesis/index.js.map +1 -0
- package/examples/genesis/sseStream.d.ts +16 -0
- package/examples/genesis/sseStream.js +141 -0
- package/examples/genesis/sseStream.js.map +1 -0
- package/examples/ncfx/config/index.js.map +1 -0
- package/examples/ncfx/index.js.map +1 -0
- package/examples/ncfx/websocket.js.map +1 -0
- package/index.js.map +1 -0
- package/metrics/constants.js.map +1 -0
- package/metrics/index.d.ts +2 -0
- package/metrics/index.js +12 -1
- package/metrics/index.js.map +1 -0
- package/metrics/util.js.map +1 -0
- package/package.json +7 -5
- package/rate-limiting/background/fixed-frequency.js +0 -3
- package/rate-limiting/background/fixed-frequency.js.map +1 -0
- package/rate-limiting/index.d.ts +1 -0
- package/rate-limiting/index.js +3 -2
- package/rate-limiting/index.js.map +1 -0
- package/rate-limiting/metrics.js.map +1 -0
- package/rate-limiting/request/simple-counting.js.map +1 -0
- package/transports/batch-warming.d.ts +2 -2
- package/transports/batch-warming.js +13 -6
- package/transports/batch-warming.js.map +1 -0
- package/transports/index.d.ts +2 -1
- package/transports/index.js +27 -0
- package/transports/index.js.map +1 -0
- package/transports/metrics.d.ts +3 -0
- package/transports/metrics.js +17 -1
- package/transports/metrics.js.map +1 -0
- package/transports/rest.d.ts +8 -2
- package/transports/rest.js +13 -13
- package/transports/rest.js.map +1 -0
- package/transports/sse.d.ts +41 -0
- package/transports/sse.js +95 -0
- package/transports/sse.js.map +1 -0
- package/transports/util.js.map +1 -0
- package/transports/websocket.d.ts +2 -2
- package/transports/websocket.js +12 -11
- package/transports/websocket.js.map +1 -0
- package/util/censor/censor-list.d.ts +9 -0
- package/util/censor/censor-list.js +12 -0
- package/util/censor/censor-list.js.map +1 -0
- package/util/index.d.ts +1 -0
- package/util/index.js +3 -1
- package/util/index.js.map +1 -0
- package/util/logger.d.ts +3 -0
- package/util/logger.js +20 -1
- package/util/logger.js.map +1 -0
- package/util/request.d.ts +52 -6
- package/util/request.js.map +1 -0
- package/util/subscription-set/expiring-sorted-set.d.ts +0 -1
- package/util/subscription-set/expiring-sorted-set.js +0 -12
- package/util/subscription-set/expiring-sorted-set.js.map +1 -0
- package/util/subscription-set/redis-sorted-set.d.ts +9 -0
- package/util/subscription-set/redis-sorted-set.js +28 -0
- package/util/subscription-set/redis-sorted-set.js.map +1 -0
- package/util/subscription-set/subscription-set.d.ts +5 -4
- package/util/subscription-set/subscription-set.js +13 -5
- package/util/subscription-set/subscription-set.js.map +1 -0
- package/util/test-payload-loader.js.map +1 -0
- package/validation/error.js.map +1 -0
- package/validation/index.js +10 -9
- package/validation/index.js.map +1 -0
- package/validation/input-params.d.ts +1 -1
- package/validation/input-params.js.map +1 -0
- package/validation/input-validator.d.ts +16 -0
- package/validation/input-validator.js +123 -0
- package/validation/input-validator.js.map +1 -0
- package/validation/override-functions.js.map +1 -0
package/transports/index.js
CHANGED
|
@@ -10,6 +10,18 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
10
10
|
if (k2 === undefined) k2 = k;
|
|
11
11
|
o[k2] = m[k];
|
|
12
12
|
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
13
25
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
26
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
27
|
};
|
|
@@ -17,9 +29,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
29
|
exports.buildTransportHandler = exports.buildCacheEntriesFromResults = void 0;
|
|
18
30
|
const cache_1 = require("../cache");
|
|
19
31
|
const util_1 = require("../util");
|
|
32
|
+
const transportMetrics = __importStar(require("./metrics"));
|
|
33
|
+
const client = __importStar(require("prom-client"));
|
|
20
34
|
__exportStar(require("./batch-warming"), exports);
|
|
21
35
|
__exportStar(require("./rest"), exports);
|
|
22
36
|
__exportStar(require("./websocket"), exports);
|
|
37
|
+
__exportStar(require("./sse"), exports);
|
|
23
38
|
const logger = (0, util_1.makeLogger)('Transport');
|
|
24
39
|
/**
|
|
25
40
|
* Helper method to build cache entries to set after getting a bunch of responses from a DP.
|
|
@@ -73,17 +88,29 @@ const buildTransportHandler = (adapter) => async (req, reply) => {
|
|
|
73
88
|
return reply.send(immediateResponse);
|
|
74
89
|
}
|
|
75
90
|
}
|
|
91
|
+
// Observe the idle time taken for polling response
|
|
92
|
+
const metricsTimer = transportMetrics.transportPollingDurationSeconds
|
|
93
|
+
.labels({ endpoint: req.requestContext.endpointName })
|
|
94
|
+
.startTimer();
|
|
76
95
|
logger.debug('Transport is set up, polling cache for response...');
|
|
77
96
|
const response = await (0, cache_1.pollResponseFromCache)(adapter.dependencies.cache, req.requestContext.cacheKey, {
|
|
78
97
|
maxRetries: adapter.config.CACHE_POLLING_MAX_RETRIES,
|
|
79
98
|
sleep: adapter.config.CACHE_POLLING_SLEEP_MS,
|
|
80
99
|
});
|
|
100
|
+
metricsTimer({ succeeded: String(!!response) });
|
|
81
101
|
if (response) {
|
|
82
102
|
logger.debug('Got a response from the cache, sending that back');
|
|
83
103
|
return reply.send(response);
|
|
84
104
|
}
|
|
105
|
+
// Record polling mechanism failure to return response
|
|
106
|
+
transportMetrics.transportPollingFailureCount
|
|
107
|
+
.labels({ endpoint: req.requestContext.endpointName })
|
|
108
|
+
.inc();
|
|
85
109
|
logger.debug('Ran out of polling attempts, returning timeout');
|
|
86
110
|
reply.statusCode = 504;
|
|
87
111
|
return reply.send();
|
|
88
112
|
};
|
|
89
113
|
exports.buildTransportHandler = buildTransportHandler;
|
|
114
|
+
if (process.env['METRICS_ENABLED'] === 'false') {
|
|
115
|
+
client.register.clear();
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transports/index.ts"],"names":[],"mappings":"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"}
|
package/transports/metrics.d.ts
CHANGED
|
@@ -20,3 +20,6 @@ export declare const wsConnectionErrors: client.Counter<"message" | "url">;
|
|
|
20
20
|
export declare const wsSubscriptionActive: client.Gauge<"feed_id" | "connection_url" | "subscription_key">;
|
|
21
21
|
export declare const wsSubscriptionTotal: client.Counter<"feed_id" | "connection_url" | "subscription_key">;
|
|
22
22
|
export declare const wsMessageTotal: client.Counter<"feed_id" | "subscription_key">;
|
|
23
|
+
export declare const bgExecuteSubscriptionSetCount: client.Gauge<"endpoint" | "transport_type">;
|
|
24
|
+
export declare const transportPollingFailureCount: client.Counter<"endpoint">;
|
|
25
|
+
export declare const transportPollingDurationSeconds: client.Gauge<"succeeded" | "endpoint">;
|
package/transports/metrics.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.wsMessageTotal = exports.wsSubscriptionTotal = exports.wsSubscriptionActive = exports.wsConnectionErrors = exports.wsConnectionActive = exports.recordWsMessageMetrics = exports.messageSubsLabels = exports.connectionErrorLabels = exports.dataProviderRequestDurationSeconds = exports.dataProviderRequests = exports.dataProviderMetricsLabel = void 0;
|
|
26
|
+
exports.transportPollingDurationSeconds = exports.transportPollingFailureCount = exports.bgExecuteSubscriptionSetCount = exports.wsMessageTotal = exports.wsSubscriptionTotal = exports.wsSubscriptionActive = exports.wsConnectionErrors = exports.wsConnectionActive = exports.recordWsMessageMetrics = exports.messageSubsLabels = exports.connectionErrorLabels = exports.dataProviderRequestDurationSeconds = exports.dataProviderRequests = exports.dataProviderMetricsLabel = void 0;
|
|
27
27
|
const client = __importStar(require("prom-client"));
|
|
28
28
|
const cache_1 = require("../cache");
|
|
29
29
|
const constants_1 = require("../metrics/constants");
|
|
@@ -103,3 +103,19 @@ exports.wsMessageTotal = new client.Counter({
|
|
|
103
103
|
help: 'The number of messages received in total',
|
|
104
104
|
labelNames: ['feed_id', 'subscription_key'],
|
|
105
105
|
});
|
|
106
|
+
// V3 specific metrics
|
|
107
|
+
exports.bgExecuteSubscriptionSetCount = new client.Gauge({
|
|
108
|
+
name: 'bg_execute_subscription_set_count',
|
|
109
|
+
help: 'The number of active subscriptions in background execute',
|
|
110
|
+
labelNames: ['endpoint', 'transport_type'],
|
|
111
|
+
});
|
|
112
|
+
exports.transportPollingFailureCount = new client.Counter({
|
|
113
|
+
name: 'transport_polling_failure_count',
|
|
114
|
+
help: 'The number of times the polling mechanism ran out of attempts and failed to return a response',
|
|
115
|
+
labelNames: ['endpoint'],
|
|
116
|
+
});
|
|
117
|
+
exports.transportPollingDurationSeconds = new client.Gauge({
|
|
118
|
+
name: 'transport_polling_duration_seconds',
|
|
119
|
+
help: 'A histogram bucket of the distribution of transport polling idle time durations',
|
|
120
|
+
labelNames: ['endpoint', 'succeeded'],
|
|
121
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/transports/metrics.ts"],"names":[],"mappings":"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"}
|
package/transports/rest.d.ts
CHANGED
|
@@ -21,7 +21,10 @@ export declare class RestTransport<AdapterParams, ProviderRequestBody, ProviderR
|
|
|
21
21
|
prepareRequest: (req: AdapterRequest<AdapterParams>, config: AdapterConfig<CustomSettings>) => AxiosRequestConfig<ProviderRequestBody> | Promise<AxiosRequestConfig<ProviderRequestBody>>;
|
|
22
22
|
parseResponse: (req: AdapterRequest<AdapterParams>, res: AxiosResponse<ProviderResponseBody>, config: AdapterConfig<CustomSettings>) => AdapterResponse<ProviderResponseBody> | Promise<AdapterResponse<ProviderResponseBody>>;
|
|
23
23
|
options: {
|
|
24
|
-
|
|
24
|
+
requestCoalescing: {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
entropyMax?: number;
|
|
27
|
+
};
|
|
25
28
|
};
|
|
26
29
|
};
|
|
27
30
|
inFlightPrefix: string;
|
|
@@ -31,7 +34,10 @@ export declare class RestTransport<AdapterParams, ProviderRequestBody, ProviderR
|
|
|
31
34
|
prepareRequest: (req: AdapterRequest<AdapterParams>, config: AdapterConfig<CustomSettings>) => AxiosRequestConfig<ProviderRequestBody> | Promise<AxiosRequestConfig<ProviderRequestBody>>;
|
|
32
35
|
parseResponse: (req: AdapterRequest<AdapterParams>, res: AxiosResponse<ProviderResponseBody>, config: AdapterConfig<CustomSettings>) => AdapterResponse<ProviderResponseBody> | Promise<AdapterResponse<ProviderResponseBody>>;
|
|
33
36
|
options: {
|
|
34
|
-
|
|
37
|
+
requestCoalescing: {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
entropyMax?: number;
|
|
40
|
+
};
|
|
35
41
|
};
|
|
36
42
|
});
|
|
37
43
|
initialize(dependencies: AdapterDependencies, config: AdapterConfig): Promise<void>;
|
package/transports/rest.js
CHANGED
|
@@ -50,14 +50,17 @@ class RestTransport {
|
|
|
50
50
|
this.cache = dependencies.cache;
|
|
51
51
|
this.rateLimiter = dependencies.requestRateLimiter;
|
|
52
52
|
// Allow enabling/disabling request coalescing through env var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
53
|
+
this.config.options.requestCoalescing.enabled = config.REQUEST_COALESCING_ENABLED;
|
|
54
|
+
this.config.options.requestCoalescing.entropyMax = config.REQUEST_COALESCING_ENTROPY_MAX;
|
|
56
55
|
}
|
|
57
56
|
async hasBeenSetUp(req) {
|
|
58
|
-
if (!this.config.options.
|
|
57
|
+
if (!this.config.options.requestCoalescing.enabled) {
|
|
59
58
|
return false;
|
|
60
59
|
}
|
|
60
|
+
// Add some entropy here because of possible scenario where the key won't be set before multiple
|
|
61
|
+
// other instances in a burst request try to access the coalescing key.
|
|
62
|
+
const randomMs = Math.random() * (this.config.options.requestCoalescing.entropyMax || 0);
|
|
63
|
+
await (0, util_1.sleep)(randomMs);
|
|
61
64
|
// Check if request is in flight
|
|
62
65
|
const inFlight = await this.cache.get(this.inFlightPrefix + req.requestContext.cacheKey);
|
|
63
66
|
if (inFlight) {
|
|
@@ -85,12 +88,11 @@ class RestTransport {
|
|
|
85
88
|
await this.waitUntilUnderRateLimit(options, retry + 1);
|
|
86
89
|
}
|
|
87
90
|
async setup(req, config) {
|
|
88
|
-
if (this.config.options.
|
|
91
|
+
if (this.config.options.requestCoalescing.enabled) {
|
|
92
|
+
const ttl = config.REST_TRANSPORT_MAX_RATE_LIMIT_RETRIES *
|
|
93
|
+
config.REST_TRANSPORT_MS_BETWEEN_RATE_LIMIT_RETRIES;
|
|
89
94
|
logger.debug('Setting up rest transport, setting request in flight in cache');
|
|
90
|
-
|
|
91
|
-
// TODO: Set viable ttl to approximate timeout from API
|
|
92
|
-
// TODO: Make this ttl configurable
|
|
93
|
-
await this.cache.set(this.inFlightPrefix + req.requestContext.cacheKey, true, 2000); // Can't use Infinity for things like Redis
|
|
95
|
+
await this.cache.set(this.inFlightPrefix + req.requestContext.cacheKey, true, ttl + 100); // Can't use Infinity for things like Redis
|
|
94
96
|
}
|
|
95
97
|
const request = await this.config.prepareRequest(req, config);
|
|
96
98
|
logger.trace('Check if we are under rate limits to perform request');
|
|
@@ -100,13 +102,12 @@ class RestTransport {
|
|
|
100
102
|
});
|
|
101
103
|
logger.trace('Sending request to data provider...');
|
|
102
104
|
const providerResponse = await (0, util_2.axiosRequest)(request, config);
|
|
103
|
-
logger.debug(`Got response from provider, parsing (raw body: ${providerResponse.data})`);
|
|
105
|
+
logger.debug(`Got response from provider, parsing (raw body: ${providerResponse.data})`);
|
|
104
106
|
const parsedResponse = await this.config.parseResponse(req, providerResponse, config);
|
|
105
107
|
if (config.API_VERBOSE) {
|
|
106
108
|
parsedResponse.data = providerResponse.data;
|
|
107
109
|
}
|
|
108
110
|
if (config.METRICS_ENABLED && config.EXPERIMENTAL_METRICS_ENABLED) {
|
|
109
|
-
// TODO: Potentially create function to add all telemetry data
|
|
110
111
|
parsedResponse.maxAge = Date.now() + config.CACHE_MAX_AGE;
|
|
111
112
|
parsedResponse.meta = {
|
|
112
113
|
metrics: { feedId: req.requestContext.meta?.metrics?.feedId || 'N/A' },
|
|
@@ -127,8 +128,7 @@ class RestTransport {
|
|
|
127
128
|
...req.requestContext.meta,
|
|
128
129
|
metrics: { ...req.requestContext.meta?.metrics, cacheHit: false },
|
|
129
130
|
};
|
|
130
|
-
|
|
131
|
-
if (this.config.options.coalescing) {
|
|
131
|
+
if (this.config.options.requestCoalescing.enabled) {
|
|
132
132
|
logger.debug('Set provider response in cache, removing in flight from cache');
|
|
133
133
|
await this.cache.delete(this.inFlightPrefix);
|
|
134
134
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../../src/transports/rest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Cache } from '../cache';
|
|
2
|
+
import EventSource from 'eventsource';
|
|
3
|
+
import { SettingsMap, AdapterConfig } from '../config';
|
|
4
|
+
import { AxiosRequestConfig } from 'axios';
|
|
5
|
+
import { SubscriptionSet } from '../util';
|
|
6
|
+
import { AdapterRequest, ProviderResult } from '../util/request';
|
|
7
|
+
import { Transport } from './';
|
|
8
|
+
import { AdapterContext, AdapterDependencies } from '../adapter';
|
|
9
|
+
export interface SSEConfig {
|
|
10
|
+
url: string;
|
|
11
|
+
eventSourceInitDict?: EventSource.EventSourceInitDict;
|
|
12
|
+
}
|
|
13
|
+
export declare class SSETransport<AdapterParams, ProviderRequestBody, ProviderResponseBody, CustomSettings extends SettingsMap> implements Transport<AdapterParams, ProviderResponseBody, CustomSettings> {
|
|
14
|
+
private config;
|
|
15
|
+
EventSource: typeof EventSource;
|
|
16
|
+
cache: Cache;
|
|
17
|
+
eventListeners: {
|
|
18
|
+
type: string;
|
|
19
|
+
parseResponse: (evt: MessageEvent) => ProviderResult<AdapterParams>;
|
|
20
|
+
}[];
|
|
21
|
+
sseConnection?: EventSource;
|
|
22
|
+
subscriptionSet: SubscriptionSet<AdapterParams>;
|
|
23
|
+
timeOfLastReq: number;
|
|
24
|
+
localSubscriptions: AdapterParams[];
|
|
25
|
+
constructor(config: {
|
|
26
|
+
prepareSSEConnectionConfig: (params: AdapterParams[], context: AdapterContext<CustomSettings>) => SSEConfig;
|
|
27
|
+
prepareKeepAliveRequest: (context: AdapterContext<CustomSettings>) => AxiosRequestConfig<ProviderRequestBody>;
|
|
28
|
+
prepareSubscriptionRequest: (params: AdapterParams[], context: AdapterContext<CustomSettings>) => AxiosRequestConfig<ProviderRequestBody>;
|
|
29
|
+
prepareUnsubscriptionRequest: (params: AdapterParams[], context: AdapterContext<CustomSettings>) => AxiosRequestConfig<ProviderRequestBody>;
|
|
30
|
+
eventListeners: {
|
|
31
|
+
type: string;
|
|
32
|
+
parseResponse: (evt: MessageEvent) => ProviderResult<AdapterParams>[];
|
|
33
|
+
}[];
|
|
34
|
+
keepaliveSleepMs?: number;
|
|
35
|
+
pollingSleepMs?: number;
|
|
36
|
+
});
|
|
37
|
+
initialize(dependencies: AdapterDependencies, config: AdapterConfig<SettingsMap>, endpointName: string): Promise<void>;
|
|
38
|
+
hasBeenSetUp(): Promise<boolean>;
|
|
39
|
+
setup(req: AdapterRequest<AdapterParams>, config: AdapterConfig<CustomSettings>): Promise<void>;
|
|
40
|
+
backgroundExecute(context: AdapterContext<CustomSettings>): Promise<number>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SSETransport = void 0;
|
|
7
|
+
const eventsource_1 = __importDefault(require("eventsource"));
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const util_1 = require("../util");
|
|
10
|
+
const _1 = require("./");
|
|
11
|
+
const logger = (0, util_1.makeLogger)('SSETransport');
|
|
12
|
+
class SSETransport {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.EventSource = eventsource_1.default;
|
|
16
|
+
this.timeOfLastReq = 0;
|
|
17
|
+
// The double sets serve to create a simple polling mechanism instead of needing a subscription
|
|
18
|
+
// This one would not; this is always local state
|
|
19
|
+
this.localSubscriptions = [];
|
|
20
|
+
}
|
|
21
|
+
async initialize(dependencies, config, endpointName) {
|
|
22
|
+
this.cache = dependencies.cache;
|
|
23
|
+
this.subscriptionSet = dependencies.subscriptionSetFactory.buildSet(endpointName);
|
|
24
|
+
if (dependencies.eventSource) {
|
|
25
|
+
this.EventSource = dependencies.eventSource;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async hasBeenSetUp() {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
async setup(req, config) {
|
|
32
|
+
logger.debug(`Adding entry to subscription set: [${req.requestContext.cacheKey}] = ${req.requestContext.data}`);
|
|
33
|
+
await this.subscriptionSet.add(req.requestContext.cacheKey, req.requestContext.data, config.SSE_SUBSCRIPTION_TTL);
|
|
34
|
+
}
|
|
35
|
+
// Unlike cache warming, this execute will manage subscriptions
|
|
36
|
+
async backgroundExecute(context) {
|
|
37
|
+
logger.debug('Starting background execute, getting subscriptions from sorted set');
|
|
38
|
+
const desiredSubs = await this.subscriptionSet.getAll();
|
|
39
|
+
logger.debug('Generating delta (subscribes & unsubscribes)');
|
|
40
|
+
// TODO: More efficient algorithm, this is really easy to read, but high(er) time complexity
|
|
41
|
+
const subscribeParams = desiredSubs.filter((s) => !this.localSubscriptions.includes(s));
|
|
42
|
+
const unsubscribeParams = this.localSubscriptions.filter((s) => !desiredSubs.includes(s));
|
|
43
|
+
logger.debug(`${subscribeParams.length} new subscriptions; ${unsubscribeParams.length} to unsubscribe`);
|
|
44
|
+
if (subscribeParams.length) {
|
|
45
|
+
logger.trace(`Will subscribe to: ${subscribeParams}`);
|
|
46
|
+
}
|
|
47
|
+
if (unsubscribeParams.length) {
|
|
48
|
+
logger.trace(`Will unsubscribe to: ${unsubscribeParams}`);
|
|
49
|
+
}
|
|
50
|
+
if ((subscribeParams.length || unsubscribeParams.length) &&
|
|
51
|
+
(!this.sseConnection || this.sseConnection.readyState !== this.sseConnection.OPEN)) {
|
|
52
|
+
logger.debug('No established connection and new subscriptions available, connecting to SSE');
|
|
53
|
+
const sseConfig = this.config.prepareSSEConnectionConfig(subscribeParams, context);
|
|
54
|
+
this.sseConnection = new this.EventSource(sseConfig.url, sseConfig.eventSourceInitDict);
|
|
55
|
+
const eventHandlerGenerator = (listener) => {
|
|
56
|
+
return (e) => {
|
|
57
|
+
const providerResponses = listener.parseResponse(e);
|
|
58
|
+
const cacheEntries = (0, _1.buildCacheEntriesFromResults)(providerResponses, context);
|
|
59
|
+
this.cache.setMany(cacheEntries, context.adapterConfig.CACHE_MAX_AGE);
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
this.config.eventListeners.forEach((listener) => {
|
|
63
|
+
this.sseConnection?.addEventListener(listener.type, eventHandlerGenerator(listener));
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const makeRequest = async (req) => {
|
|
67
|
+
try {
|
|
68
|
+
const res = await axios_1.default.request(req);
|
|
69
|
+
logger.debug(res.data, `response status ${res.statusText} from keepalive request`);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
logger.error(err, `Error on keepalive request`);
|
|
73
|
+
}
|
|
74
|
+
this.timeOfLastReq = Date.now();
|
|
75
|
+
};
|
|
76
|
+
if (subscribeParams.length) {
|
|
77
|
+
const subscribeRequest = this.config.prepareSubscriptionRequest(subscribeParams, context);
|
|
78
|
+
makeRequest(subscribeRequest);
|
|
79
|
+
}
|
|
80
|
+
if (unsubscribeParams.length) {
|
|
81
|
+
const unsubscribeRequest = this.config.prepareUnsubscriptionRequest(unsubscribeParams, context);
|
|
82
|
+
makeRequest(unsubscribeRequest);
|
|
83
|
+
}
|
|
84
|
+
if (desiredSubs.length &&
|
|
85
|
+
Date.now() - this.timeOfLastReq > context.adapterConfig.SSE_KEEPALIVE_SLEEP) {
|
|
86
|
+
const prepareKeepAliveRequest = this.config.prepareKeepAliveRequest(context);
|
|
87
|
+
makeRequest(prepareKeepAliveRequest);
|
|
88
|
+
}
|
|
89
|
+
logger.debug('Setting local state to cache value');
|
|
90
|
+
this.localSubscriptions = desiredSubs;
|
|
91
|
+
logger.debug('Background execute complete');
|
|
92
|
+
return context.adapterConfig.SSE_SUBSCRIPTION_UPDATE_SLEEP;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.SSETransport = SSETransport;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../src/transports/sse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/transports/util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4E;AAE5E,+CAK4B;AAC5B,4DAA6C;AAE7C;;;;;GAKG;AACI,KAAK,UAAU,YAAY,CAKhC,OAAgD,EAChD,MAAqC;IAErC,MAAM,aAAa,GAAG,gBAAgB,CAAC,kCAAkC,CAAC,UAAU,EAAE,CAAA;IACtF,IAAI,gBAAqD,CAAA;IACzD,IAAI;QACF,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,WAAW,CAAA;QACpC,gBAAgB,GAAG,MAAM,eAAK,CAAC,OAAO,CAAuB,OAAO,CAAC,CAAA;KACtE;IAAC,OAAO,CAAU,EAAE;QACnB,MAAM,KAAK,GAAG,CAAe,CAAA;QAC7B,gBAAgB;QAChB,IAAI,kBAAsC,CAAA;QAC1C,IAAI,YAA0B,CAAA;QAC9B,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE;YACjC,YAAY,GAAG,IAAI,2BAAmB,CAAC,EAAE,CAAC,CAAA;YAC1C,kBAAkB,GAAG,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAA;YACnD,YAAY,CAAC,IAAI,GAAG,qCAAqC,CAAA;SAC1D;aAAM,IAAI,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE;YAClC,YAAY,GAAG,IAAI,gCAAwB,CAAC,EAAE,CAAC,CAAA;YAC/C,kBAAkB,GAAG,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAA;SAC7C;aAAM;YACL,YAAY,GAAG,IAAI,8BAAsB,CAAC,EAAE,CAAC,CAAA;YAC7C,kBAAkB,GAAG,CAAC,CAAA,CAAC,wBAAwB;SAChD;QACD,+CAA+C;QAC/C,gBAAgB,CAAC,oBAAoB;aAClC,MAAM,CAAC,gBAAgB,CAAC,wBAAwB,CAAC,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;aACrF,GAAG,EAAE,CAAA;QAER,YAAY,CAAC,UAAU,GAAG,GAAG,CAAA;QAC7B,YAAY,CAAC,kBAAkB,GAAG,kBAAkB,CAAA;QACpD,YAAY,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,CAAA;QACrC,YAAY,CAAC,KAAK,GAAG,KAAK,CAAA;QAC1B,YAAY,CAAC,aAAa,GAAG,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAA;QAClD,YAAY,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;QAE9B,MAAM,YAAY,CAAA;KACnB;YAAS;QACR,qEAAqE;QACrE,aAAa,EAAE,CAAA;KAChB;IAED,oDAAoD;IACpD,gBAAgB,CAAC,oBAAoB;SAClC,MAAM,CAAC,gBAAgB,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;SAC1F,GAAG,EAAE,CAAA;IAER,OAAO,gBAAgB,CAAA;AACzB,CAAC;AArDD,oCAqDC"}
|
|
@@ -69,8 +69,8 @@ export declare class WebSocketTransport<AdapterParams, ProviderDataMessage, Cust
|
|
|
69
69
|
localSubscriptions: AdapterParams[];
|
|
70
70
|
wsConnection: WebSocket;
|
|
71
71
|
constructor(config: WebSocketTransportConfig<AdapterParams, ProviderDataMessage, CustomSettings>);
|
|
72
|
-
initialize(dependencies: AdapterDependencies): Promise<void>;
|
|
73
|
-
hasBeenSetUp(
|
|
72
|
+
initialize(dependencies: AdapterDependencies, _: AdapterConfig, endpointName: string): Promise<void>;
|
|
73
|
+
hasBeenSetUp(): Promise<boolean>;
|
|
74
74
|
setup(req: AdapterRequest<AdapterParams>, config: AdapterConfig<CustomSettings>): Promise<void>;
|
|
75
75
|
serializeMessage(payload: unknown): string;
|
|
76
76
|
deserializeMessage(data: WebSocket.Data): ProviderDataMessage;
|
package/transports/websocket.js
CHANGED
|
@@ -56,21 +56,19 @@ class WebSocketTransport {
|
|
|
56
56
|
// This one would not; this is always local state
|
|
57
57
|
this.localSubscriptions = [];
|
|
58
58
|
}
|
|
59
|
-
async initialize(dependencies) {
|
|
59
|
+
async initialize(dependencies, _, endpointName) {
|
|
60
60
|
this.cache = dependencies.cache;
|
|
61
61
|
this.rateLimiter = dependencies.backgroundExecuteRateLimiter;
|
|
62
|
-
this.subscriptionSet = dependencies.subscriptionSetFactory.buildSet();
|
|
62
|
+
this.subscriptionSet = dependencies.subscriptionSetFactory.buildSet(endpointName);
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
// This might need coalescing to avoid too frequent ttl updates
|
|
65
|
+
async hasBeenSetUp() {
|
|
66
|
+
return false;
|
|
66
67
|
}
|
|
67
68
|
async setup(req, config) {
|
|
68
69
|
logger.debug(`Adding entry to subscription set: [${req.requestContext.cacheKey}] = ${req.requestContext.data}`);
|
|
69
70
|
await this.subscriptionSet.add(req.requestContext.cacheKey, req.requestContext.data, config.WS_SUBSCRIPTION_TTL);
|
|
70
71
|
}
|
|
71
|
-
// TODO: Maybe we don't do this, and leave the preparation on the adapter's side?
|
|
72
|
-
// TODO: Maybe we store adapter params pre-prepared? That would be more efficient
|
|
73
|
-
// Assuming always JSON payloads for now, makes it all cleaner
|
|
74
72
|
serializeMessage(payload) {
|
|
75
73
|
return typeof payload === 'string' ? payload : JSON.stringify(payload);
|
|
76
74
|
}
|
|
@@ -80,7 +78,8 @@ class WebSocketTransport {
|
|
|
80
78
|
establishWsConnection(context) {
|
|
81
79
|
return new Promise((resolve) => {
|
|
82
80
|
const ctor = WebSocketClassProvider.get();
|
|
83
|
-
|
|
81
|
+
const url = context.adapterConfig.WS_API_ENDPOINT || this.config.url;
|
|
82
|
+
this.wsConnection = new ctor(url);
|
|
84
83
|
this.wsConnection.addEventListener('open', async (event) => {
|
|
85
84
|
logger.debug(`Opened websocket connection. (event type ${event.type})`);
|
|
86
85
|
await this.config.handlers.open(this.wsConnection, context);
|
|
@@ -91,7 +90,6 @@ class WebSocketTransport {
|
|
|
91
90
|
resolve(true);
|
|
92
91
|
});
|
|
93
92
|
this.wsConnection.addEventListener('message', async (event) => {
|
|
94
|
-
// TODO: Assuming JSON always, maybe use BSON also?
|
|
95
93
|
const parsed = this.deserializeMessage(event.data);
|
|
96
94
|
logger.trace(`Got ws message: ${parsed}`);
|
|
97
95
|
const results = this.config.handlers.message(parsed, context);
|
|
@@ -102,6 +100,7 @@ class WebSocketTransport {
|
|
|
102
100
|
}
|
|
103
101
|
});
|
|
104
102
|
this.wsConnection.addEventListener('error', async (event) => {
|
|
103
|
+
logger.debug(`Error occurred in web socket connection. Error: ${event.error} ; Message: ${event.message}`);
|
|
105
104
|
// Record connection error count
|
|
106
105
|
transportMetrics.wsConnectionErrors
|
|
107
106
|
.labels(transportMetrics.connectionErrorLabels(event.message))
|
|
@@ -119,8 +118,11 @@ class WebSocketTransport {
|
|
|
119
118
|
async backgroundExecute(context) {
|
|
120
119
|
logger.debug('Starting background execute, getting subscriptions from sorted set');
|
|
121
120
|
const desiredSubs = await this.subscriptionSet.getAll();
|
|
121
|
+
// Keep track of active subscriptions for background execute
|
|
122
|
+
transportMetrics.bgExecuteSubscriptionSetCount
|
|
123
|
+
.labels({ endpoint: context.adapterEndpoint.name, transport_type: 'websocket' })
|
|
124
|
+
.set(desiredSubs.length);
|
|
122
125
|
logger.debug('Generating delta (subscribes & unsubscribes)');
|
|
123
|
-
// TODO: More efficient algorithm, this is really easy to read, but high(er) time complexity
|
|
124
126
|
const subscribeParams = desiredSubs.filter((s) => !this.localSubscriptions.includes(s));
|
|
125
127
|
const subscribes = subscribeParams
|
|
126
128
|
.map(this.config.builders.subscribeMessage)
|
|
@@ -148,7 +150,6 @@ class WebSocketTransport {
|
|
|
148
150
|
logger.debug('No established connection and new subscriptions available, connecting to WS');
|
|
149
151
|
await this.establishWsConnection(context);
|
|
150
152
|
}
|
|
151
|
-
// TODO: Close connection at some point?
|
|
152
153
|
logger.debug('Sending subs/unsubs if there are any');
|
|
153
154
|
const messages = unsubscribes.concat(subscribes);
|
|
154
155
|
for (const message of messages) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/transports/websocket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class CensorList {
|
|
4
|
+
static getAll() {
|
|
5
|
+
return this.censorList;
|
|
6
|
+
}
|
|
7
|
+
static set(censorList) {
|
|
8
|
+
this.censorList = censorList;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.default = CensorList;
|
|
12
|
+
CensorList.censorList = [];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"censor-list.js","sourceRoot":"","sources":["../../../../src/util/censor/censor-list.ts"],"names":[],"mappings":";;AAAA,MAAqB,UAAU;IAE7B,MAAM,CAAC,MAAM;QACX,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,UAA4B;QACrC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;;AAPH,6BAQC;AAPQ,qBAAU,GAAqB,EAAE,CAAA"}
|
package/util/index.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export * from './subscription-set/subscription-set';
|
|
|
9
9
|
export declare const sleep: (ms: number) => Promise<void>;
|
|
10
10
|
export declare const isObject: (o: unknown) => boolean;
|
|
11
11
|
export declare const isArray: (o: unknown) => boolean;
|
|
12
|
+
export declare const isEmpty: (o: unknown) => boolean;
|
|
12
13
|
export declare type PromiseOrValue<T> = Promise<T> | T;
|
package/util/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.isArray = exports.isObject = exports.sleep = void 0;
|
|
17
|
+
exports.isEmpty = exports.isArray = exports.isObject = exports.sleep = void 0;
|
|
18
18
|
__exportStar(require("./request"), exports);
|
|
19
19
|
__exportStar(require("./logger"), exports);
|
|
20
20
|
__exportStar(require("./subscription-set/subscription-set"), exports);
|
|
@@ -33,3 +33,5 @@ const isObject = (o) => o !== null && typeof o === 'object' && Array.isArray(o)
|
|
|
33
33
|
exports.isObject = isObject;
|
|
34
34
|
const isArray = (o) => o !== null && typeof o === 'object' && Array.isArray(o);
|
|
35
35
|
exports.isArray = isArray;
|
|
36
|
+
const isEmpty = (o) => o === undefined || o === null || o === '';
|
|
37
|
+
exports.isEmpty = isEmpty;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/util/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,4CAAyB;AACzB,2CAAwB;AACxB,sEAAmD;AAEnD;;;;GAIG;AACI,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAJY,QAAA,KAAK,SAIjB;AAEM,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAW,EAAE,CAC9C,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAA;AADtD,QAAA,QAAQ,YAC8C;AAE5D,MAAM,OAAO,GAAG,CAAC,CAAU,EAAW,EAAE,CAC7C,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAD5C,QAAA,OAAO,WACqC;AAElD,MAAM,OAAO,GAAG,CAAC,CAAU,EAAW,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAA;AAA5E,QAAA,OAAO,WAAqE"}
|
package/util/logger.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export declare type Store = {
|
|
|
27
27
|
*/
|
|
28
28
|
export declare const makeLogger: (layer: string) => pino.Logger<{
|
|
29
29
|
level: string;
|
|
30
|
+
hooks: {
|
|
31
|
+
logMethod(this: pino.Logger<pino.LoggerOptions>, inputArgs: [msg: string, ...args: any[]], method: pino.LogFn): void;
|
|
32
|
+
};
|
|
30
33
|
mixin(): {};
|
|
31
34
|
transport: {
|
|
32
35
|
target: string;
|
package/util/logger.js
CHANGED
|
@@ -8,6 +8,7 @@ const pino_1 = __importDefault(require("pino"));
|
|
|
8
8
|
const config_1 = require("../config");
|
|
9
9
|
const crypto_1 = require("crypto");
|
|
10
10
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
11
|
+
const censor_list_1 = __importDefault(require("./censor/censor-list"));
|
|
11
12
|
exports.asyncLocalStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
12
13
|
const debugTransport = {
|
|
13
14
|
target: 'pino-pretty',
|
|
@@ -22,6 +23,13 @@ const debugTransport = {
|
|
|
22
23
|
// Base logger, shouldn't be used because we want layers to be specified
|
|
23
24
|
const baseLogger = (0, pino_1.default)({
|
|
24
25
|
level: process.env['LOG_LEVEL']?.toLowerCase() || config_1.BaseSettings.LOG_LEVEL.default,
|
|
26
|
+
hooks: {
|
|
27
|
+
logMethod(inputArgs, method) {
|
|
28
|
+
// Censor each argument of logger
|
|
29
|
+
const censorList = censor_list_1.default.getAll();
|
|
30
|
+
return method.apply(this, inputArgs.map((arg) => censor(arg, censorList)));
|
|
31
|
+
},
|
|
32
|
+
},
|
|
25
33
|
mixin() {
|
|
26
34
|
if (process.env['CORRELATION_ID_ENABLED'] === 'true') {
|
|
27
35
|
const store = exports.asyncLocalStorage.getStore();
|
|
@@ -31,7 +39,9 @@ const baseLogger = (0, pino_1.default)({
|
|
|
31
39
|
}
|
|
32
40
|
return {};
|
|
33
41
|
},
|
|
34
|
-
transport: process.env['DEBUG'] === 'true'
|
|
42
|
+
transport: process.env['DEBUG'] === 'true' || process.env['NODE_ENV'] === 'development'
|
|
43
|
+
? debugTransport
|
|
44
|
+
: undefined,
|
|
35
45
|
});
|
|
36
46
|
/**
|
|
37
47
|
* Instead of using a global logger instance, we want to force using a child logger
|
|
@@ -60,3 +70,12 @@ const loggingContextMiddleware = (req, res, done) => {
|
|
|
60
70
|
});
|
|
61
71
|
};
|
|
62
72
|
exports.loggingContextMiddleware = loggingContextMiddleware;
|
|
73
|
+
// Obj is typed as "any" because it could be a variety of structures in the logger
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
function censor(obj, censorList) {
|
|
76
|
+
let stringified = JSON.stringify(obj);
|
|
77
|
+
censorList.forEach((entry) => {
|
|
78
|
+
stringified = stringified.replace(entry.value, `[${entry.key} REDACTED]`);
|
|
79
|
+
});
|
|
80
|
+
return stringified;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/util/logger.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAuB;AACvB,sCAAwC;AAGxC,mCAAmC;AACnC,uDAAoD;AACpD,uEAAiE;AAEpD,QAAA,iBAAiB,GAAG,IAAI,oCAAiB,EAAE,CAAA;AAMxD,MAAM,cAAc,GAAG;IACrB,MAAM,EAAE,aAAa;IACrB,OAAO,EAAE;QACP,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,OAAO;QACnB,MAAM,EAAE,oBAAoB;QAC5B,aAAa,EAAE,kCAAkC;QACjD,aAAa,EAAE,uBAAuB;KACvC;CACF,CAAA;AAED,wEAAwE;AACxE,MAAM,UAAU,GAAG,IAAA,cAAI,EAAC;IACtB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,IAAI,qBAAY,CAAC,SAAS,CAAC,OAAO;IAChF,KAAK,EAAE;QACL,SAAS,CAAC,SAAS,EAAE,MAAM;YACzB,iCAAiC;YACjC,MAAM,UAAU,GAAG,qBAAU,CAAC,MAAM,EAAE,CAAA;YACtC,OAAO,MAAM,CAAC,KAAK,CACjB,IAAI,EACJ,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,CAA2B,CAC1E,CAAA;QACH,CAAC;KACF;IACD,KAAK;QACH,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,KAAK,MAAM,EAAE;YACpD,MAAM,KAAK,GAAG,yBAAiB,CAAC,QAAQ,EAAW,CAAA;YACnD,IAAI,KAAK,EAAE;gBACT,OAAO,KAAK,CAAA;aACb;SACF;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IACD,SAAS,EACP,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa;QAC1E,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,SAAS;CAChB,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACI,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAA3D,QAAA,UAAU,cAAiD;AAEjE,MAAM,wBAAwB,GAAG,CACtC,GAAmB,EACnB,GAAiB,EACjB,IAA6B,EAC7B,EAAE;IACF,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,IAAA,mBAAU,GAAE,CAAA;IACrE,yBAAiB,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,EAAE,GAAG,EAAE;QAC3D,IAAI,EAAE,CAAA;IACR,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AATY,QAAA,wBAAwB,4BASpC;AAED,kFAAkF;AAClF,8DAA8D;AAC9D,SAAS,MAAM,CAAC,GAAQ,EAAE,UAA4B;IACpD,IAAI,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IACrC,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,GAAG,YAAY,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IACF,OAAO,WAAW,CAAA;AACpB,CAAC"}
|