@wise-old-man/utils 3.3.10 → 3.3.12
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/dist/cjs/index.cjs +231 -0
- package/dist/es/index.js +231 -0
- package/dist/es/index.mjs +231 -0
- package/dist/index.d.ts +6 -4
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var axios = require('axios');
|
|
4
|
+
var prometheus = require('prom-client');
|
|
5
|
+
var zod = require('zod');
|
|
6
|
+
require('dotenv/config');
|
|
7
|
+
var fetchable = require('@attio/fetchable');
|
|
8
|
+
|
|
3
9
|
var config = {
|
|
4
10
|
defaultUserAgent: `WiseOldMan JS Client v${process.env.npm_package_version}`,
|
|
5
11
|
baseAPIUrl: 'https://api.wiseoldman.net/v2'
|
|
@@ -614,6 +620,7 @@ const Boss = {
|
|
|
614
620
|
VETION: 'vetion',
|
|
615
621
|
VORKATH: 'vorkath',
|
|
616
622
|
WINTERTODT: 'wintertodt',
|
|
623
|
+
YAMA: 'yama',
|
|
617
624
|
ZALCANO: 'zalcano',
|
|
618
625
|
ZULRAH: 'zulrah'
|
|
619
626
|
};
|
|
@@ -643,6 +650,8 @@ const PlayerType = {
|
|
|
643
650
|
};
|
|
644
651
|
const PlayerAnnotationType = {
|
|
645
652
|
OPT_OUT: 'opt_out',
|
|
653
|
+
OPT_OUT_GROUPS: 'opt_out_groups',
|
|
654
|
+
OPT_OUT_COMPETITIONS: 'opt_out_competitions',
|
|
646
655
|
BLOCKED: 'blocked',
|
|
647
656
|
FAKE_F2P: 'fake_f2p'
|
|
648
657
|
};
|
|
@@ -1966,6 +1975,7 @@ const BossProps = mapValues({
|
|
|
1966
1975
|
[Boss.VETION]: { name: "Vet'ion" },
|
|
1967
1976
|
[Boss.VORKATH]: { name: 'Vorkath' },
|
|
1968
1977
|
[Boss.WINTERTODT]: { name: 'Wintertodt' },
|
|
1978
|
+
[Boss.YAMA]: { name: 'Yama' },
|
|
1969
1979
|
[Boss.ZALCANO]: { name: 'Zalcano' },
|
|
1970
1980
|
[Boss.ZULRAH]: { name: 'Zulrah' }
|
|
1971
1981
|
}, props => (Object.assign(Object.assign({}, props), { type: exports.MetricType.BOSS, measure: exports.MetricMeasure.KILLS, isMembers: 'isMembers' in props ? props.isMembers : true, minimumValue: 'minimumValue' in props ? props.minimumValue : 5 })));
|
|
@@ -2057,6 +2067,226 @@ function getParentEfficiencyMetric(metric) {
|
|
|
2057
2067
|
return null;
|
|
2058
2068
|
}
|
|
2059
2069
|
|
|
2070
|
+
/**
|
|
2071
|
+
* This file has been created as a way to force any usage
|
|
2072
|
+
* of process.env to go through a dotenv.config first.
|
|
2073
|
+
*/
|
|
2074
|
+
/**
|
|
2075
|
+
* This ensures that an env var is required in prod but optional in dev/test.
|
|
2076
|
+
*/
|
|
2077
|
+
function prodOnly(varSchema) {
|
|
2078
|
+
if (process.env.NODE_ENV === 'production') {
|
|
2079
|
+
return varSchema;
|
|
2080
|
+
}
|
|
2081
|
+
return zod.z.optional(varSchema);
|
|
2082
|
+
}
|
|
2083
|
+
const envVariablesSchema = zod.z.object({
|
|
2084
|
+
// Prisma Database URL
|
|
2085
|
+
CORE_DATABASE_URL: zod.z.string().trim().min(1),
|
|
2086
|
+
// Redis Configs
|
|
2087
|
+
REDIS_HOST: zod.z.string().trim().min(1),
|
|
2088
|
+
REDIS_PORT: zod.z.coerce.number().positive().int(),
|
|
2089
|
+
// Node Environment
|
|
2090
|
+
NODE_ENV: zod.z.enum(['development', 'production', 'test']),
|
|
2091
|
+
// Port for the API to run on
|
|
2092
|
+
API_PORT: zod.z.optional(zod.z.coerce.number().positive().int()),
|
|
2093
|
+
// Admin Password (For mod+ operations)
|
|
2094
|
+
ADMIN_PASSWORD: prodOnly(zod.z.string().trim().min(1)),
|
|
2095
|
+
// Sentry (for error tracking)
|
|
2096
|
+
API_SENTRY_DSN: prodOnly(zod.z.string().trim().min(1)),
|
|
2097
|
+
// Patreon Token (to access their API)
|
|
2098
|
+
PATREON_BEARER_TOKEN: prodOnly(zod.z.string().trim().min(1)),
|
|
2099
|
+
// Discord Bot API URL (to send events to)
|
|
2100
|
+
DISCORD_BOT_API_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2101
|
+
// Our Prometheus metrics aggregator service URL
|
|
2102
|
+
PROMETHEUS_METRICS_SERVICE_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2103
|
+
// Discord Monitoring Webhooks
|
|
2104
|
+
DISCORD_PATREON_WEBHOOK_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2105
|
+
DISCORD_MONITORING_WEBHOOK_URL: prodOnly(zod.z.string().trim().min(1).url()),
|
|
2106
|
+
// Proxy Configs
|
|
2107
|
+
PROXY_LIST: prodOnly(zod.z.string().trim().min(1)),
|
|
2108
|
+
PROXY_USER: prodOnly(zod.z.string().trim().min(1)),
|
|
2109
|
+
PROXY_PASSWORD: prodOnly(zod.z.string().trim().min(1)),
|
|
2110
|
+
PROXY_PORT: prodOnly(zod.z.coerce.number().positive().int()),
|
|
2111
|
+
CPU_COUNT: prodOnly(zod.z.coerce.number().positive().int()),
|
|
2112
|
+
// Openai API Key
|
|
2113
|
+
OPENAI_API_KEY: prodOnly(zod.z.string().trim().min(1).startsWith('sk-'))
|
|
2114
|
+
});
|
|
2115
|
+
// This will load env vars from a .env file, type check them,and throw an error
|
|
2116
|
+
// (interrupting the process) if they're required and missing, or of an invalid type.
|
|
2117
|
+
try {
|
|
2118
|
+
envVariablesSchema.parse(process.env);
|
|
2119
|
+
}
|
|
2120
|
+
catch (error) {
|
|
2121
|
+
const errorPayload = JSON.stringify(error, null, 2);
|
|
2122
|
+
throw new Error(`Invalid environment variables. Please check env.ts for more info.\n${errorPayload}`);
|
|
2123
|
+
}
|
|
2124
|
+
function getThreadIndex() {
|
|
2125
|
+
if (process.env.pm_id === undefined) {
|
|
2126
|
+
return null;
|
|
2127
|
+
}
|
|
2128
|
+
return parseInt(process.env.pm_id, 10);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
class PrometheusService {
|
|
2132
|
+
constructor() {
|
|
2133
|
+
this.pushInterval = null;
|
|
2134
|
+
this.registry = new prometheus.Registry();
|
|
2135
|
+
this.registry.setDefaultLabels({ app: 'wise-old-man', threadIndex: getThreadIndex() });
|
|
2136
|
+
prometheus.collectDefaultMetrics({ register: this.registry });
|
|
2137
|
+
this.effectHistogram = new prometheus.Histogram({
|
|
2138
|
+
name: 'effect_duration_seconds',
|
|
2139
|
+
help: 'Duration of effects in microseconds',
|
|
2140
|
+
labelNames: ['effectName', 'status'],
|
|
2141
|
+
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2142
|
+
});
|
|
2143
|
+
this.httpHistogram = new prometheus.Histogram({
|
|
2144
|
+
name: 'http_request_duration_seconds',
|
|
2145
|
+
help: 'Duration of HTTP requests in microseconds',
|
|
2146
|
+
labelNames: ['method', 'route', 'status', 'userAgent'],
|
|
2147
|
+
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2148
|
+
});
|
|
2149
|
+
this.jobHistogram = new prometheus.Histogram({
|
|
2150
|
+
name: 'job_duration_seconds',
|
|
2151
|
+
help: 'Duration of jobs in microseconds',
|
|
2152
|
+
labelNames: ['jobName', 'status'],
|
|
2153
|
+
buckets: [0.1, 0.5, 1, 5, 10, 30, 60]
|
|
2154
|
+
});
|
|
2155
|
+
this.jobQueueGauge = new prometheus.Gauge({
|
|
2156
|
+
name: 'job_queue_size',
|
|
2157
|
+
help: 'Number of jobs in different states for each queue',
|
|
2158
|
+
labelNames: ['queueName', 'state']
|
|
2159
|
+
});
|
|
2160
|
+
this.eventCounter = new prometheus.Counter({
|
|
2161
|
+
name: 'event_counter',
|
|
2162
|
+
help: 'Count of events emitted',
|
|
2163
|
+
labelNames: ['eventType']
|
|
2164
|
+
});
|
|
2165
|
+
this.customPeriodCounter = new prometheus.Counter({
|
|
2166
|
+
name: 'custom_period_counter',
|
|
2167
|
+
help: 'Count of custom period expressions used',
|
|
2168
|
+
labelNames: ['customPeriod']
|
|
2169
|
+
});
|
|
2170
|
+
this.updatePlayerJobSourceCounter = new prometheus.Counter({
|
|
2171
|
+
name: 'update_player_job_source_counter',
|
|
2172
|
+
help: 'Count of update player jobs dispatched',
|
|
2173
|
+
labelNames: ['source']
|
|
2174
|
+
});
|
|
2175
|
+
this.runeMetricsHistogram = new prometheus.Histogram({
|
|
2176
|
+
name: 'runemetrics_duration_seconds',
|
|
2177
|
+
help: 'Duration of RuneMetrics requests in microseconds',
|
|
2178
|
+
labelNames: ['status'],
|
|
2179
|
+
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2180
|
+
});
|
|
2181
|
+
this.hiscoresHistogram = new prometheus.Histogram({
|
|
2182
|
+
name: 'hiscores_duration_seconds',
|
|
2183
|
+
help: 'Duration of hiscores requests in microseconds',
|
|
2184
|
+
labelNames: ['status'],
|
|
2185
|
+
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2186
|
+
});
|
|
2187
|
+
this.registry.registerMetric(this.jobHistogram);
|
|
2188
|
+
this.registry.registerMetric(this.jobQueueGauge);
|
|
2189
|
+
this.registry.registerMetric(this.httpHistogram);
|
|
2190
|
+
this.registry.registerMetric(this.effectHistogram);
|
|
2191
|
+
this.registry.registerMetric(this.eventCounter);
|
|
2192
|
+
this.registry.registerMetric(this.customPeriodCounter);
|
|
2193
|
+
this.registry.registerMetric(this.updatePlayerJobSourceCounter);
|
|
2194
|
+
this.registry.registerMetric(this.runeMetricsHistogram);
|
|
2195
|
+
this.registry.registerMetric(this.hiscoresHistogram);
|
|
2196
|
+
}
|
|
2197
|
+
init() {
|
|
2198
|
+
this.pushInterval = setInterval(() => {
|
|
2199
|
+
this.pushMetrics();
|
|
2200
|
+
}, 60000);
|
|
2201
|
+
}
|
|
2202
|
+
shutdown() {
|
|
2203
|
+
if (this.pushInterval !== null) {
|
|
2204
|
+
clearInterval(this.pushInterval);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
pushMetrics() {
|
|
2208
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2209
|
+
if (process.env.NODE_ENV === 'test') {
|
|
2210
|
+
return fetchable.errored({ code: 'NOT_ALLOWED_IN_TEST_ENV' });
|
|
2211
|
+
}
|
|
2212
|
+
if (!process.env.PROMETHEUS_METRICS_SERVICE_URL) {
|
|
2213
|
+
return fetchable.errored({ code: 'MISSING_METRICS_URL' });
|
|
2214
|
+
}
|
|
2215
|
+
const metricsResult = yield fetchable.fromPromise(this.registry.getMetricsAsJSON());
|
|
2216
|
+
if (fetchable.isErrored(metricsResult)) {
|
|
2217
|
+
return fetchable.errored({
|
|
2218
|
+
code: 'FAILED_TO_GET_PROMETHEUS_METRICS',
|
|
2219
|
+
subError: metricsResult.error
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
const requestResult = yield fetchable.fromPromise(axios.post(process.env.PROMETHEUS_METRICS_SERVICE_URL, {
|
|
2223
|
+
source: 'api',
|
|
2224
|
+
data: metricsResult.value,
|
|
2225
|
+
threadIndex: getThreadIndex()
|
|
2226
|
+
}));
|
|
2227
|
+
if (fetchable.isErrored(requestResult)) {
|
|
2228
|
+
return fetchable.errored({
|
|
2229
|
+
code: 'FAILED_TO_PUSH_PROMETHEUS_METRICS',
|
|
2230
|
+
subError: requestResult.error
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
return fetchable.complete(true);
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
trackHttpRequest() {
|
|
2237
|
+
return this.httpHistogram.startTimer();
|
|
2238
|
+
}
|
|
2239
|
+
trackRuneMetricsRequest() {
|
|
2240
|
+
return this.runeMetricsHistogram.startTimer();
|
|
2241
|
+
}
|
|
2242
|
+
trackHiscoresRequest() {
|
|
2243
|
+
return this.hiscoresHistogram.startTimer();
|
|
2244
|
+
}
|
|
2245
|
+
trackEffect(effectName, fn) {
|
|
2246
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2247
|
+
const endTimer = this.effectHistogram.startTimer();
|
|
2248
|
+
try {
|
|
2249
|
+
yield fn();
|
|
2250
|
+
endTimer({ effectName, status: 1 });
|
|
2251
|
+
}
|
|
2252
|
+
catch (error) {
|
|
2253
|
+
endTimer({ effectName, status: 0 });
|
|
2254
|
+
throw error;
|
|
2255
|
+
}
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
trackJob(jobName, handler) {
|
|
2259
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2260
|
+
const endTimer = this.jobHistogram.startTimer();
|
|
2261
|
+
try {
|
|
2262
|
+
yield handler();
|
|
2263
|
+
endTimer({ jobName, status: 1 });
|
|
2264
|
+
}
|
|
2265
|
+
catch (error) {
|
|
2266
|
+
endTimer({ jobName, status: 0 });
|
|
2267
|
+
throw error;
|
|
2268
|
+
}
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
trackEventEmitted(eventType) {
|
|
2272
|
+
this.eventCounter.inc({ eventType });
|
|
2273
|
+
}
|
|
2274
|
+
trackCustomPeriodExpression(customPeriod) {
|
|
2275
|
+
this.customPeriodCounter.inc({ customPeriod });
|
|
2276
|
+
}
|
|
2277
|
+
trackUpdatePlayerJobSource(source) {
|
|
2278
|
+
this.updatePlayerJobSourceCounter.inc({ source });
|
|
2279
|
+
}
|
|
2280
|
+
updateQueueMetrics(queueName, counts) {
|
|
2281
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2282
|
+
for (const [state, count] of Object.entries(counts)) {
|
|
2283
|
+
this.jobQueueGauge.set({ queueName, state }, count);
|
|
2284
|
+
}
|
|
2285
|
+
});
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
var prometheusService = new PrometheusService();
|
|
2289
|
+
|
|
2060
2290
|
const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
|
|
2061
2291
|
const PeriodProps = {
|
|
2062
2292
|
[Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300000 },
|
|
@@ -2084,6 +2314,7 @@ function parsePeriodExpression(periodExpression) {
|
|
|
2084
2314
|
durationMs: PeriodProps[fixed].milliseconds
|
|
2085
2315
|
};
|
|
2086
2316
|
}
|
|
2317
|
+
prometheusService.trackCustomPeriodExpression(fixed);
|
|
2087
2318
|
const result = fixed.match(CUSTOM_PERIOD_REGEX);
|
|
2088
2319
|
if (!result || result.length === 0 || result[0] !== fixed)
|
|
2089
2320
|
return null;
|
package/dist/es/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import prometheus from 'prom-client';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import 'dotenv/config';
|
|
5
|
+
import { errored, fromPromise, isErrored, complete } from '@attio/fetchable';
|
|
6
|
+
|
|
1
7
|
var config = {
|
|
2
8
|
defaultUserAgent: `WiseOldMan JS Client v${process.env.npm_package_version}`,
|
|
3
9
|
baseAPIUrl: 'https://api.wiseoldman.net/v2'
|
|
@@ -612,6 +618,7 @@ const Boss = {
|
|
|
612
618
|
VETION: 'vetion',
|
|
613
619
|
VORKATH: 'vorkath',
|
|
614
620
|
WINTERTODT: 'wintertodt',
|
|
621
|
+
YAMA: 'yama',
|
|
615
622
|
ZALCANO: 'zalcano',
|
|
616
623
|
ZULRAH: 'zulrah'
|
|
617
624
|
};
|
|
@@ -641,6 +648,8 @@ const PlayerType = {
|
|
|
641
648
|
};
|
|
642
649
|
const PlayerAnnotationType = {
|
|
643
650
|
OPT_OUT: 'opt_out',
|
|
651
|
+
OPT_OUT_GROUPS: 'opt_out_groups',
|
|
652
|
+
OPT_OUT_COMPETITIONS: 'opt_out_competitions',
|
|
644
653
|
BLOCKED: 'blocked',
|
|
645
654
|
FAKE_F2P: 'fake_f2p'
|
|
646
655
|
};
|
|
@@ -1964,6 +1973,7 @@ const BossProps = mapValues({
|
|
|
1964
1973
|
[Boss.VETION]: { name: "Vet'ion" },
|
|
1965
1974
|
[Boss.VORKATH]: { name: 'Vorkath' },
|
|
1966
1975
|
[Boss.WINTERTODT]: { name: 'Wintertodt' },
|
|
1976
|
+
[Boss.YAMA]: { name: 'Yama' },
|
|
1967
1977
|
[Boss.ZALCANO]: { name: 'Zalcano' },
|
|
1968
1978
|
[Boss.ZULRAH]: { name: 'Zulrah' }
|
|
1969
1979
|
}, props => (Object.assign(Object.assign({}, props), { type: MetricType.BOSS, measure: MetricMeasure.KILLS, isMembers: 'isMembers' in props ? props.isMembers : true, minimumValue: 'minimumValue' in props ? props.minimumValue : 5 })));
|
|
@@ -2055,6 +2065,226 @@ function getParentEfficiencyMetric(metric) {
|
|
|
2055
2065
|
return null;
|
|
2056
2066
|
}
|
|
2057
2067
|
|
|
2068
|
+
/**
|
|
2069
|
+
* This file has been created as a way to force any usage
|
|
2070
|
+
* of process.env to go through a dotenv.config first.
|
|
2071
|
+
*/
|
|
2072
|
+
/**
|
|
2073
|
+
* This ensures that an env var is required in prod but optional in dev/test.
|
|
2074
|
+
*/
|
|
2075
|
+
function prodOnly(varSchema) {
|
|
2076
|
+
if (process.env.NODE_ENV === 'production') {
|
|
2077
|
+
return varSchema;
|
|
2078
|
+
}
|
|
2079
|
+
return z.optional(varSchema);
|
|
2080
|
+
}
|
|
2081
|
+
const envVariablesSchema = z.object({
|
|
2082
|
+
// Prisma Database URL
|
|
2083
|
+
CORE_DATABASE_URL: z.string().trim().min(1),
|
|
2084
|
+
// Redis Configs
|
|
2085
|
+
REDIS_HOST: z.string().trim().min(1),
|
|
2086
|
+
REDIS_PORT: z.coerce.number().positive().int(),
|
|
2087
|
+
// Node Environment
|
|
2088
|
+
NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
2089
|
+
// Port for the API to run on
|
|
2090
|
+
API_PORT: z.optional(z.coerce.number().positive().int()),
|
|
2091
|
+
// Admin Password (For mod+ operations)
|
|
2092
|
+
ADMIN_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2093
|
+
// Sentry (for error tracking)
|
|
2094
|
+
API_SENTRY_DSN: prodOnly(z.string().trim().min(1)),
|
|
2095
|
+
// Patreon Token (to access their API)
|
|
2096
|
+
PATREON_BEARER_TOKEN: prodOnly(z.string().trim().min(1)),
|
|
2097
|
+
// Discord Bot API URL (to send events to)
|
|
2098
|
+
DISCORD_BOT_API_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2099
|
+
// Our Prometheus metrics aggregator service URL
|
|
2100
|
+
PROMETHEUS_METRICS_SERVICE_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2101
|
+
// Discord Monitoring Webhooks
|
|
2102
|
+
DISCORD_PATREON_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2103
|
+
DISCORD_MONITORING_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2104
|
+
// Proxy Configs
|
|
2105
|
+
PROXY_LIST: prodOnly(z.string().trim().min(1)),
|
|
2106
|
+
PROXY_USER: prodOnly(z.string().trim().min(1)),
|
|
2107
|
+
PROXY_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2108
|
+
PROXY_PORT: prodOnly(z.coerce.number().positive().int()),
|
|
2109
|
+
CPU_COUNT: prodOnly(z.coerce.number().positive().int()),
|
|
2110
|
+
// Openai API Key
|
|
2111
|
+
OPENAI_API_KEY: prodOnly(z.string().trim().min(1).startsWith('sk-'))
|
|
2112
|
+
});
|
|
2113
|
+
// This will load env vars from a .env file, type check them,and throw an error
|
|
2114
|
+
// (interrupting the process) if they're required and missing, or of an invalid type.
|
|
2115
|
+
try {
|
|
2116
|
+
envVariablesSchema.parse(process.env);
|
|
2117
|
+
}
|
|
2118
|
+
catch (error) {
|
|
2119
|
+
const errorPayload = JSON.stringify(error, null, 2);
|
|
2120
|
+
throw new Error(`Invalid environment variables. Please check env.ts for more info.\n${errorPayload}`);
|
|
2121
|
+
}
|
|
2122
|
+
function getThreadIndex() {
|
|
2123
|
+
if (process.env.pm_id === undefined) {
|
|
2124
|
+
return null;
|
|
2125
|
+
}
|
|
2126
|
+
return parseInt(process.env.pm_id, 10);
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
class PrometheusService {
|
|
2130
|
+
constructor() {
|
|
2131
|
+
this.pushInterval = null;
|
|
2132
|
+
this.registry = new prometheus.Registry();
|
|
2133
|
+
this.registry.setDefaultLabels({ app: 'wise-old-man', threadIndex: getThreadIndex() });
|
|
2134
|
+
prometheus.collectDefaultMetrics({ register: this.registry });
|
|
2135
|
+
this.effectHistogram = new prometheus.Histogram({
|
|
2136
|
+
name: 'effect_duration_seconds',
|
|
2137
|
+
help: 'Duration of effects in microseconds',
|
|
2138
|
+
labelNames: ['effectName', 'status'],
|
|
2139
|
+
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2140
|
+
});
|
|
2141
|
+
this.httpHistogram = new prometheus.Histogram({
|
|
2142
|
+
name: 'http_request_duration_seconds',
|
|
2143
|
+
help: 'Duration of HTTP requests in microseconds',
|
|
2144
|
+
labelNames: ['method', 'route', 'status', 'userAgent'],
|
|
2145
|
+
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2146
|
+
});
|
|
2147
|
+
this.jobHistogram = new prometheus.Histogram({
|
|
2148
|
+
name: 'job_duration_seconds',
|
|
2149
|
+
help: 'Duration of jobs in microseconds',
|
|
2150
|
+
labelNames: ['jobName', 'status'],
|
|
2151
|
+
buckets: [0.1, 0.5, 1, 5, 10, 30, 60]
|
|
2152
|
+
});
|
|
2153
|
+
this.jobQueueGauge = new prometheus.Gauge({
|
|
2154
|
+
name: 'job_queue_size',
|
|
2155
|
+
help: 'Number of jobs in different states for each queue',
|
|
2156
|
+
labelNames: ['queueName', 'state']
|
|
2157
|
+
});
|
|
2158
|
+
this.eventCounter = new prometheus.Counter({
|
|
2159
|
+
name: 'event_counter',
|
|
2160
|
+
help: 'Count of events emitted',
|
|
2161
|
+
labelNames: ['eventType']
|
|
2162
|
+
});
|
|
2163
|
+
this.customPeriodCounter = new prometheus.Counter({
|
|
2164
|
+
name: 'custom_period_counter',
|
|
2165
|
+
help: 'Count of custom period expressions used',
|
|
2166
|
+
labelNames: ['customPeriod']
|
|
2167
|
+
});
|
|
2168
|
+
this.updatePlayerJobSourceCounter = new prometheus.Counter({
|
|
2169
|
+
name: 'update_player_job_source_counter',
|
|
2170
|
+
help: 'Count of update player jobs dispatched',
|
|
2171
|
+
labelNames: ['source']
|
|
2172
|
+
});
|
|
2173
|
+
this.runeMetricsHistogram = new prometheus.Histogram({
|
|
2174
|
+
name: 'runemetrics_duration_seconds',
|
|
2175
|
+
help: 'Duration of RuneMetrics requests in microseconds',
|
|
2176
|
+
labelNames: ['status'],
|
|
2177
|
+
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2178
|
+
});
|
|
2179
|
+
this.hiscoresHistogram = new prometheus.Histogram({
|
|
2180
|
+
name: 'hiscores_duration_seconds',
|
|
2181
|
+
help: 'Duration of hiscores requests in microseconds',
|
|
2182
|
+
labelNames: ['status'],
|
|
2183
|
+
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2184
|
+
});
|
|
2185
|
+
this.registry.registerMetric(this.jobHistogram);
|
|
2186
|
+
this.registry.registerMetric(this.jobQueueGauge);
|
|
2187
|
+
this.registry.registerMetric(this.httpHistogram);
|
|
2188
|
+
this.registry.registerMetric(this.effectHistogram);
|
|
2189
|
+
this.registry.registerMetric(this.eventCounter);
|
|
2190
|
+
this.registry.registerMetric(this.customPeriodCounter);
|
|
2191
|
+
this.registry.registerMetric(this.updatePlayerJobSourceCounter);
|
|
2192
|
+
this.registry.registerMetric(this.runeMetricsHistogram);
|
|
2193
|
+
this.registry.registerMetric(this.hiscoresHistogram);
|
|
2194
|
+
}
|
|
2195
|
+
init() {
|
|
2196
|
+
this.pushInterval = setInterval(() => {
|
|
2197
|
+
this.pushMetrics();
|
|
2198
|
+
}, 60000);
|
|
2199
|
+
}
|
|
2200
|
+
shutdown() {
|
|
2201
|
+
if (this.pushInterval !== null) {
|
|
2202
|
+
clearInterval(this.pushInterval);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
pushMetrics() {
|
|
2206
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2207
|
+
if (process.env.NODE_ENV === 'test') {
|
|
2208
|
+
return errored({ code: 'NOT_ALLOWED_IN_TEST_ENV' });
|
|
2209
|
+
}
|
|
2210
|
+
if (!process.env.PROMETHEUS_METRICS_SERVICE_URL) {
|
|
2211
|
+
return errored({ code: 'MISSING_METRICS_URL' });
|
|
2212
|
+
}
|
|
2213
|
+
const metricsResult = yield fromPromise(this.registry.getMetricsAsJSON());
|
|
2214
|
+
if (isErrored(metricsResult)) {
|
|
2215
|
+
return errored({
|
|
2216
|
+
code: 'FAILED_TO_GET_PROMETHEUS_METRICS',
|
|
2217
|
+
subError: metricsResult.error
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
const requestResult = yield fromPromise(axios.post(process.env.PROMETHEUS_METRICS_SERVICE_URL, {
|
|
2221
|
+
source: 'api',
|
|
2222
|
+
data: metricsResult.value,
|
|
2223
|
+
threadIndex: getThreadIndex()
|
|
2224
|
+
}));
|
|
2225
|
+
if (isErrored(requestResult)) {
|
|
2226
|
+
return errored({
|
|
2227
|
+
code: 'FAILED_TO_PUSH_PROMETHEUS_METRICS',
|
|
2228
|
+
subError: requestResult.error
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
return complete(true);
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
trackHttpRequest() {
|
|
2235
|
+
return this.httpHistogram.startTimer();
|
|
2236
|
+
}
|
|
2237
|
+
trackRuneMetricsRequest() {
|
|
2238
|
+
return this.runeMetricsHistogram.startTimer();
|
|
2239
|
+
}
|
|
2240
|
+
trackHiscoresRequest() {
|
|
2241
|
+
return this.hiscoresHistogram.startTimer();
|
|
2242
|
+
}
|
|
2243
|
+
trackEffect(effectName, fn) {
|
|
2244
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2245
|
+
const endTimer = this.effectHistogram.startTimer();
|
|
2246
|
+
try {
|
|
2247
|
+
yield fn();
|
|
2248
|
+
endTimer({ effectName, status: 1 });
|
|
2249
|
+
}
|
|
2250
|
+
catch (error) {
|
|
2251
|
+
endTimer({ effectName, status: 0 });
|
|
2252
|
+
throw error;
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
trackJob(jobName, handler) {
|
|
2257
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2258
|
+
const endTimer = this.jobHistogram.startTimer();
|
|
2259
|
+
try {
|
|
2260
|
+
yield handler();
|
|
2261
|
+
endTimer({ jobName, status: 1 });
|
|
2262
|
+
}
|
|
2263
|
+
catch (error) {
|
|
2264
|
+
endTimer({ jobName, status: 0 });
|
|
2265
|
+
throw error;
|
|
2266
|
+
}
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
trackEventEmitted(eventType) {
|
|
2270
|
+
this.eventCounter.inc({ eventType });
|
|
2271
|
+
}
|
|
2272
|
+
trackCustomPeriodExpression(customPeriod) {
|
|
2273
|
+
this.customPeriodCounter.inc({ customPeriod });
|
|
2274
|
+
}
|
|
2275
|
+
trackUpdatePlayerJobSource(source) {
|
|
2276
|
+
this.updatePlayerJobSourceCounter.inc({ source });
|
|
2277
|
+
}
|
|
2278
|
+
updateQueueMetrics(queueName, counts) {
|
|
2279
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2280
|
+
for (const [state, count] of Object.entries(counts)) {
|
|
2281
|
+
this.jobQueueGauge.set({ queueName, state }, count);
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
var prometheusService = new PrometheusService();
|
|
2287
|
+
|
|
2058
2288
|
const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
|
|
2059
2289
|
const PeriodProps = {
|
|
2060
2290
|
[Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300000 },
|
|
@@ -2082,6 +2312,7 @@ function parsePeriodExpression(periodExpression) {
|
|
|
2082
2312
|
durationMs: PeriodProps[fixed].milliseconds
|
|
2083
2313
|
};
|
|
2084
2314
|
}
|
|
2315
|
+
prometheusService.trackCustomPeriodExpression(fixed);
|
|
2085
2316
|
const result = fixed.match(CUSTOM_PERIOD_REGEX);
|
|
2086
2317
|
if (!result || result.length === 0 || result[0] !== fixed)
|
|
2087
2318
|
return null;
|
package/dist/es/index.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import prometheus from 'prom-client';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import 'dotenv/config';
|
|
5
|
+
import { errored, fromPromise, isErrored, complete } from '@attio/fetchable';
|
|
6
|
+
|
|
1
7
|
var config = {
|
|
2
8
|
defaultUserAgent: `WiseOldMan JS Client v${process.env.npm_package_version}`,
|
|
3
9
|
baseAPIUrl: 'https://api.wiseoldman.net/v2'
|
|
@@ -612,6 +618,7 @@ const Boss = {
|
|
|
612
618
|
VETION: 'vetion',
|
|
613
619
|
VORKATH: 'vorkath',
|
|
614
620
|
WINTERTODT: 'wintertodt',
|
|
621
|
+
YAMA: 'yama',
|
|
615
622
|
ZALCANO: 'zalcano',
|
|
616
623
|
ZULRAH: 'zulrah'
|
|
617
624
|
};
|
|
@@ -641,6 +648,8 @@ const PlayerType = {
|
|
|
641
648
|
};
|
|
642
649
|
const PlayerAnnotationType = {
|
|
643
650
|
OPT_OUT: 'opt_out',
|
|
651
|
+
OPT_OUT_GROUPS: 'opt_out_groups',
|
|
652
|
+
OPT_OUT_COMPETITIONS: 'opt_out_competitions',
|
|
644
653
|
BLOCKED: 'blocked',
|
|
645
654
|
FAKE_F2P: 'fake_f2p'
|
|
646
655
|
};
|
|
@@ -1964,6 +1973,7 @@ const BossProps = mapValues({
|
|
|
1964
1973
|
[Boss.VETION]: { name: "Vet'ion" },
|
|
1965
1974
|
[Boss.VORKATH]: { name: 'Vorkath' },
|
|
1966
1975
|
[Boss.WINTERTODT]: { name: 'Wintertodt' },
|
|
1976
|
+
[Boss.YAMA]: { name: 'Yama' },
|
|
1967
1977
|
[Boss.ZALCANO]: { name: 'Zalcano' },
|
|
1968
1978
|
[Boss.ZULRAH]: { name: 'Zulrah' }
|
|
1969
1979
|
}, props => (Object.assign(Object.assign({}, props), { type: MetricType.BOSS, measure: MetricMeasure.KILLS, isMembers: 'isMembers' in props ? props.isMembers : true, minimumValue: 'minimumValue' in props ? props.minimumValue : 5 })));
|
|
@@ -2055,6 +2065,226 @@ function getParentEfficiencyMetric(metric) {
|
|
|
2055
2065
|
return null;
|
|
2056
2066
|
}
|
|
2057
2067
|
|
|
2068
|
+
/**
|
|
2069
|
+
* This file has been created as a way to force any usage
|
|
2070
|
+
* of process.env to go through a dotenv.config first.
|
|
2071
|
+
*/
|
|
2072
|
+
/**
|
|
2073
|
+
* This ensures that an env var is required in prod but optional in dev/test.
|
|
2074
|
+
*/
|
|
2075
|
+
function prodOnly(varSchema) {
|
|
2076
|
+
if (process.env.NODE_ENV === 'production') {
|
|
2077
|
+
return varSchema;
|
|
2078
|
+
}
|
|
2079
|
+
return z.optional(varSchema);
|
|
2080
|
+
}
|
|
2081
|
+
const envVariablesSchema = z.object({
|
|
2082
|
+
// Prisma Database URL
|
|
2083
|
+
CORE_DATABASE_URL: z.string().trim().min(1),
|
|
2084
|
+
// Redis Configs
|
|
2085
|
+
REDIS_HOST: z.string().trim().min(1),
|
|
2086
|
+
REDIS_PORT: z.coerce.number().positive().int(),
|
|
2087
|
+
// Node Environment
|
|
2088
|
+
NODE_ENV: z.enum(['development', 'production', 'test']),
|
|
2089
|
+
// Port for the API to run on
|
|
2090
|
+
API_PORT: z.optional(z.coerce.number().positive().int()),
|
|
2091
|
+
// Admin Password (For mod+ operations)
|
|
2092
|
+
ADMIN_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2093
|
+
// Sentry (for error tracking)
|
|
2094
|
+
API_SENTRY_DSN: prodOnly(z.string().trim().min(1)),
|
|
2095
|
+
// Patreon Token (to access their API)
|
|
2096
|
+
PATREON_BEARER_TOKEN: prodOnly(z.string().trim().min(1)),
|
|
2097
|
+
// Discord Bot API URL (to send events to)
|
|
2098
|
+
DISCORD_BOT_API_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2099
|
+
// Our Prometheus metrics aggregator service URL
|
|
2100
|
+
PROMETHEUS_METRICS_SERVICE_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2101
|
+
// Discord Monitoring Webhooks
|
|
2102
|
+
DISCORD_PATREON_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2103
|
+
DISCORD_MONITORING_WEBHOOK_URL: prodOnly(z.string().trim().min(1).url()),
|
|
2104
|
+
// Proxy Configs
|
|
2105
|
+
PROXY_LIST: prodOnly(z.string().trim().min(1)),
|
|
2106
|
+
PROXY_USER: prodOnly(z.string().trim().min(1)),
|
|
2107
|
+
PROXY_PASSWORD: prodOnly(z.string().trim().min(1)),
|
|
2108
|
+
PROXY_PORT: prodOnly(z.coerce.number().positive().int()),
|
|
2109
|
+
CPU_COUNT: prodOnly(z.coerce.number().positive().int()),
|
|
2110
|
+
// Openai API Key
|
|
2111
|
+
OPENAI_API_KEY: prodOnly(z.string().trim().min(1).startsWith('sk-'))
|
|
2112
|
+
});
|
|
2113
|
+
// This will load env vars from a .env file, type check them,and throw an error
|
|
2114
|
+
// (interrupting the process) if they're required and missing, or of an invalid type.
|
|
2115
|
+
try {
|
|
2116
|
+
envVariablesSchema.parse(process.env);
|
|
2117
|
+
}
|
|
2118
|
+
catch (error) {
|
|
2119
|
+
const errorPayload = JSON.stringify(error, null, 2);
|
|
2120
|
+
throw new Error(`Invalid environment variables. Please check env.ts for more info.\n${errorPayload}`);
|
|
2121
|
+
}
|
|
2122
|
+
function getThreadIndex() {
|
|
2123
|
+
if (process.env.pm_id === undefined) {
|
|
2124
|
+
return null;
|
|
2125
|
+
}
|
|
2126
|
+
return parseInt(process.env.pm_id, 10);
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
class PrometheusService {
|
|
2130
|
+
constructor() {
|
|
2131
|
+
this.pushInterval = null;
|
|
2132
|
+
this.registry = new prometheus.Registry();
|
|
2133
|
+
this.registry.setDefaultLabels({ app: 'wise-old-man', threadIndex: getThreadIndex() });
|
|
2134
|
+
prometheus.collectDefaultMetrics({ register: this.registry });
|
|
2135
|
+
this.effectHistogram = new prometheus.Histogram({
|
|
2136
|
+
name: 'effect_duration_seconds',
|
|
2137
|
+
help: 'Duration of effects in microseconds',
|
|
2138
|
+
labelNames: ['effectName', 'status'],
|
|
2139
|
+
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2140
|
+
});
|
|
2141
|
+
this.httpHistogram = new prometheus.Histogram({
|
|
2142
|
+
name: 'http_request_duration_seconds',
|
|
2143
|
+
help: 'Duration of HTTP requests in microseconds',
|
|
2144
|
+
labelNames: ['method', 'route', 'status', 'userAgent'],
|
|
2145
|
+
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10, 30]
|
|
2146
|
+
});
|
|
2147
|
+
this.jobHistogram = new prometheus.Histogram({
|
|
2148
|
+
name: 'job_duration_seconds',
|
|
2149
|
+
help: 'Duration of jobs in microseconds',
|
|
2150
|
+
labelNames: ['jobName', 'status'],
|
|
2151
|
+
buckets: [0.1, 0.5, 1, 5, 10, 30, 60]
|
|
2152
|
+
});
|
|
2153
|
+
this.jobQueueGauge = new prometheus.Gauge({
|
|
2154
|
+
name: 'job_queue_size',
|
|
2155
|
+
help: 'Number of jobs in different states for each queue',
|
|
2156
|
+
labelNames: ['queueName', 'state']
|
|
2157
|
+
});
|
|
2158
|
+
this.eventCounter = new prometheus.Counter({
|
|
2159
|
+
name: 'event_counter',
|
|
2160
|
+
help: 'Count of events emitted',
|
|
2161
|
+
labelNames: ['eventType']
|
|
2162
|
+
});
|
|
2163
|
+
this.customPeriodCounter = new prometheus.Counter({
|
|
2164
|
+
name: 'custom_period_counter',
|
|
2165
|
+
help: 'Count of custom period expressions used',
|
|
2166
|
+
labelNames: ['customPeriod']
|
|
2167
|
+
});
|
|
2168
|
+
this.updatePlayerJobSourceCounter = new prometheus.Counter({
|
|
2169
|
+
name: 'update_player_job_source_counter',
|
|
2170
|
+
help: 'Count of update player jobs dispatched',
|
|
2171
|
+
labelNames: ['source']
|
|
2172
|
+
});
|
|
2173
|
+
this.runeMetricsHistogram = new prometheus.Histogram({
|
|
2174
|
+
name: 'runemetrics_duration_seconds',
|
|
2175
|
+
help: 'Duration of RuneMetrics requests in microseconds',
|
|
2176
|
+
labelNames: ['status'],
|
|
2177
|
+
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2178
|
+
});
|
|
2179
|
+
this.hiscoresHistogram = new prometheus.Histogram({
|
|
2180
|
+
name: 'hiscores_duration_seconds',
|
|
2181
|
+
help: 'Duration of hiscores requests in microseconds',
|
|
2182
|
+
labelNames: ['status'],
|
|
2183
|
+
buckets: [0.1, 0.3, 0.5, 1, 5, 10, 30]
|
|
2184
|
+
});
|
|
2185
|
+
this.registry.registerMetric(this.jobHistogram);
|
|
2186
|
+
this.registry.registerMetric(this.jobQueueGauge);
|
|
2187
|
+
this.registry.registerMetric(this.httpHistogram);
|
|
2188
|
+
this.registry.registerMetric(this.effectHistogram);
|
|
2189
|
+
this.registry.registerMetric(this.eventCounter);
|
|
2190
|
+
this.registry.registerMetric(this.customPeriodCounter);
|
|
2191
|
+
this.registry.registerMetric(this.updatePlayerJobSourceCounter);
|
|
2192
|
+
this.registry.registerMetric(this.runeMetricsHistogram);
|
|
2193
|
+
this.registry.registerMetric(this.hiscoresHistogram);
|
|
2194
|
+
}
|
|
2195
|
+
init() {
|
|
2196
|
+
this.pushInterval = setInterval(() => {
|
|
2197
|
+
this.pushMetrics();
|
|
2198
|
+
}, 60000);
|
|
2199
|
+
}
|
|
2200
|
+
shutdown() {
|
|
2201
|
+
if (this.pushInterval !== null) {
|
|
2202
|
+
clearInterval(this.pushInterval);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
pushMetrics() {
|
|
2206
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2207
|
+
if (process.env.NODE_ENV === 'test') {
|
|
2208
|
+
return errored({ code: 'NOT_ALLOWED_IN_TEST_ENV' });
|
|
2209
|
+
}
|
|
2210
|
+
if (!process.env.PROMETHEUS_METRICS_SERVICE_URL) {
|
|
2211
|
+
return errored({ code: 'MISSING_METRICS_URL' });
|
|
2212
|
+
}
|
|
2213
|
+
const metricsResult = yield fromPromise(this.registry.getMetricsAsJSON());
|
|
2214
|
+
if (isErrored(metricsResult)) {
|
|
2215
|
+
return errored({
|
|
2216
|
+
code: 'FAILED_TO_GET_PROMETHEUS_METRICS',
|
|
2217
|
+
subError: metricsResult.error
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
const requestResult = yield fromPromise(axios.post(process.env.PROMETHEUS_METRICS_SERVICE_URL, {
|
|
2221
|
+
source: 'api',
|
|
2222
|
+
data: metricsResult.value,
|
|
2223
|
+
threadIndex: getThreadIndex()
|
|
2224
|
+
}));
|
|
2225
|
+
if (isErrored(requestResult)) {
|
|
2226
|
+
return errored({
|
|
2227
|
+
code: 'FAILED_TO_PUSH_PROMETHEUS_METRICS',
|
|
2228
|
+
subError: requestResult.error
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
return complete(true);
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
trackHttpRequest() {
|
|
2235
|
+
return this.httpHistogram.startTimer();
|
|
2236
|
+
}
|
|
2237
|
+
trackRuneMetricsRequest() {
|
|
2238
|
+
return this.runeMetricsHistogram.startTimer();
|
|
2239
|
+
}
|
|
2240
|
+
trackHiscoresRequest() {
|
|
2241
|
+
return this.hiscoresHistogram.startTimer();
|
|
2242
|
+
}
|
|
2243
|
+
trackEffect(effectName, fn) {
|
|
2244
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2245
|
+
const endTimer = this.effectHistogram.startTimer();
|
|
2246
|
+
try {
|
|
2247
|
+
yield fn();
|
|
2248
|
+
endTimer({ effectName, status: 1 });
|
|
2249
|
+
}
|
|
2250
|
+
catch (error) {
|
|
2251
|
+
endTimer({ effectName, status: 0 });
|
|
2252
|
+
throw error;
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
trackJob(jobName, handler) {
|
|
2257
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2258
|
+
const endTimer = this.jobHistogram.startTimer();
|
|
2259
|
+
try {
|
|
2260
|
+
yield handler();
|
|
2261
|
+
endTimer({ jobName, status: 1 });
|
|
2262
|
+
}
|
|
2263
|
+
catch (error) {
|
|
2264
|
+
endTimer({ jobName, status: 0 });
|
|
2265
|
+
throw error;
|
|
2266
|
+
}
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
trackEventEmitted(eventType) {
|
|
2270
|
+
this.eventCounter.inc({ eventType });
|
|
2271
|
+
}
|
|
2272
|
+
trackCustomPeriodExpression(customPeriod) {
|
|
2273
|
+
this.customPeriodCounter.inc({ customPeriod });
|
|
2274
|
+
}
|
|
2275
|
+
trackUpdatePlayerJobSource(source) {
|
|
2276
|
+
this.updatePlayerJobSourceCounter.inc({ source });
|
|
2277
|
+
}
|
|
2278
|
+
updateQueueMetrics(queueName, counts) {
|
|
2279
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2280
|
+
for (const [state, count] of Object.entries(counts)) {
|
|
2281
|
+
this.jobQueueGauge.set({ queueName, state }, count);
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
var prometheusService = new PrometheusService();
|
|
2287
|
+
|
|
2058
2288
|
const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
|
|
2059
2289
|
const PeriodProps = {
|
|
2060
2290
|
[Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300000 },
|
|
@@ -2082,6 +2312,7 @@ function parsePeriodExpression(periodExpression) {
|
|
|
2082
2312
|
durationMs: PeriodProps[fixed].milliseconds
|
|
2083
2313
|
};
|
|
2084
2314
|
}
|
|
2315
|
+
prometheusService.trackCustomPeriodExpression(fixed);
|
|
2085
2316
|
const result = fixed.match(CUSTOM_PERIOD_REGEX);
|
|
2086
2317
|
if (!result || result.length === 0 || result[0] !== fixed)
|
|
2087
2318
|
return null;
|
package/dist/index.d.ts
CHANGED
|
@@ -497,6 +497,7 @@ declare const Boss: {
|
|
|
497
497
|
readonly VETION: "vetion";
|
|
498
498
|
readonly VORKATH: "vorkath";
|
|
499
499
|
readonly WINTERTODT: "wintertodt";
|
|
500
|
+
readonly YAMA: "yama";
|
|
500
501
|
readonly ZALCANO: "zalcano";
|
|
501
502
|
readonly ZULRAH: "zulrah";
|
|
502
503
|
};
|
|
@@ -572,6 +573,7 @@ declare const Metric: {
|
|
|
572
573
|
readonly VETION: "vetion";
|
|
573
574
|
readonly VORKATH: "vorkath";
|
|
574
575
|
readonly WINTERTODT: "wintertodt";
|
|
576
|
+
readonly YAMA: "yama";
|
|
575
577
|
readonly ZALCANO: "zalcano";
|
|
576
578
|
readonly ZULRAH: "zulrah";
|
|
577
579
|
readonly LEAGUE_POINTS: "league_points";
|
|
@@ -640,6 +642,8 @@ declare const PlayerType: {
|
|
|
640
642
|
type PlayerType = (typeof PlayerType)[keyof typeof PlayerType];
|
|
641
643
|
declare const PlayerAnnotationType: {
|
|
642
644
|
readonly OPT_OUT: "opt_out";
|
|
645
|
+
readonly OPT_OUT_GROUPS: "opt_out_groups";
|
|
646
|
+
readonly OPT_OUT_COMPETITIONS: "opt_out_competitions";
|
|
643
647
|
readonly BLOCKED: "blocked";
|
|
644
648
|
readonly FAKE_F2P: "fake_f2p";
|
|
645
649
|
};
|
|
@@ -1402,9 +1406,6 @@ interface GroupStatistics {
|
|
|
1402
1406
|
averageStats: FormattedSnapshot;
|
|
1403
1407
|
metricLeaders: MetricLeaders;
|
|
1404
1408
|
}
|
|
1405
|
-
type MemberRoleChangeEvent = Omit<MemberActivity, 'createdAt'>;
|
|
1406
|
-
type MemberJoinedEvent = Omit<MemberActivity, 'createdAt' | 'previousRole'>;
|
|
1407
|
-
type MemberLeftEvent = Omit<MemberActivity, 'createdAt' | 'previousRole'>;
|
|
1408
1409
|
type MemberActivityWithPlayer = MemberActivity & {
|
|
1409
1410
|
player: Player;
|
|
1410
1411
|
};
|
|
@@ -1733,6 +1734,7 @@ declare const MetricProps: {
|
|
|
1733
1734
|
readonly vetion: BossProperties;
|
|
1734
1735
|
readonly vorkath: BossProperties;
|
|
1735
1736
|
readonly wintertodt: BossProperties;
|
|
1737
|
+
readonly yama: BossProperties;
|
|
1736
1738
|
readonly zalcano: BossProperties;
|
|
1737
1739
|
readonly zulrah: BossProperties;
|
|
1738
1740
|
readonly overall: SkillProperties;
|
|
@@ -2281,4 +2283,4 @@ declare class WOMClient extends BaseAPIClient {
|
|
|
2281
2283
|
constructor(options?: WOMClientOptions);
|
|
2282
2284
|
}
|
|
2283
2285
|
|
|
2284
|
-
export { ACTIVITIES, type Achievement, type AchievementDefinition, type AchievementProgress, type AchievementTemplate, Activity, type ActivityDelta, ActivityType, type ActivityValue, type AssertPlayerTypeResponse, BOSSES, type Bonus, Boss, type BossDelta, type BossMetaConfig, type BossValue, CAPPED_MAX_TOTAL_XP, COMBAT_SKILLS, COMPETITION_STATUSES, COMPETITION_TYPES, COMPUTED_METRICS, COUNTRY_CODES, type ChangeMemberRolePayload, CompetitionCSVTableType, type CompetitionDetails, type CompetitionDetailsCSVParams, type CompetitionListItem, CompetitionStatus, CompetitionStatusProps, CompetitionType, CompetitionTypeProps, type CompetitionWithParticipations, type CompetitionsSearchFilter, ComputedMetric, type ComputedMetricDelta, type ComputedMetricValue, Country, type CountryDetails, CountryProps, type CreateCompetitionPayload, type CreateCompetitionResponse, type CreateGroupPayload, type CreateGroupResponse, type DeltaGroupLeaderboardEntry, type DeltaLeaderboardEntry, type DeltaLeaderboardFilter, type DenyContext, type EditCompetitionPayload, type EditGroupPayload, EfficiencyAlgorithmType, type EfficiencyAlgorithmTypeUnion, type EfficiencyLeaderboardsFilter, type ExtendedAchievement, type ExtendedAchievementWithPlayer, F2P_BOSSES, type FlaggedPlayerReviewContext, type FormattedSnapshot, GROUP_ROLES, type GenericCountMessageResponse, type GenericMessageResponse, type GetGroupGainsFilter, type GetPlayerGainsResponse, type Group, type GroupDetails, type GroupHiscoresActivityItem, type GroupHiscoresBossItem, type GroupHiscoresComputedMetricItem, type GroupHiscoresEntry, type GroupHiscoresSkillItem, type GroupListItem, type GroupMemberFragment, type GroupRecordsFilter, GroupRole, GroupRoleProps, type GroupStatistics, MAX_LEVEL, MAX_SKILL_EXP, MAX_VIRTUAL_LEVEL, MEMBER_SKILLS, METRICS, type MapOf, type MeasuredDeltaProgress, type MemberActivityWithPlayer, type MemberInput, type
|
|
2286
|
+
export { ACTIVITIES, type Achievement, type AchievementDefinition, type AchievementProgress, type AchievementTemplate, Activity, type ActivityDelta, ActivityType, type ActivityValue, type AssertPlayerTypeResponse, BOSSES, type Bonus, Boss, type BossDelta, type BossMetaConfig, type BossValue, CAPPED_MAX_TOTAL_XP, COMBAT_SKILLS, COMPETITION_STATUSES, COMPETITION_TYPES, COMPUTED_METRICS, COUNTRY_CODES, type ChangeMemberRolePayload, CompetitionCSVTableType, type CompetitionDetails, type CompetitionDetailsCSVParams, type CompetitionListItem, CompetitionStatus, CompetitionStatusProps, CompetitionType, CompetitionTypeProps, type CompetitionWithParticipations, type CompetitionsSearchFilter, ComputedMetric, type ComputedMetricDelta, type ComputedMetricValue, Country, type CountryDetails, CountryProps, type CreateCompetitionPayload, type CreateCompetitionResponse, type CreateGroupPayload, type CreateGroupResponse, type DeltaGroupLeaderboardEntry, type DeltaLeaderboardEntry, type DeltaLeaderboardFilter, type DenyContext, type EditCompetitionPayload, type EditGroupPayload, EfficiencyAlgorithmType, type EfficiencyAlgorithmTypeUnion, type EfficiencyLeaderboardsFilter, type ExtendedAchievement, type ExtendedAchievementWithPlayer, F2P_BOSSES, type FlaggedPlayerReviewContext, type FormattedSnapshot, GROUP_ROLES, type GenericCountMessageResponse, type GenericMessageResponse, type GetGroupGainsFilter, type GetPlayerGainsResponse, type Group, type GroupDetails, type GroupHiscoresActivityItem, type GroupHiscoresBossItem, type GroupHiscoresComputedMetricItem, type GroupHiscoresEntry, type GroupHiscoresSkillItem, type GroupListItem, type GroupMemberFragment, type GroupRecordsFilter, GroupRole, GroupRoleProps, type GroupStatistics, MAX_LEVEL, MAX_SKILL_EXP, MAX_VIRTUAL_LEVEL, MEMBER_SKILLS, METRICS, type MapOf, type MeasuredDeltaProgress, type MemberActivityWithPlayer, type MemberInput, type MembershipWithGroup, type MembershipWithPlayer, Metric, type MetricLeaders, MetricMeasure, MetricProps, MetricType, type MetricValueKey, type NameChange, type NameChangeDetails, NameChangeStatus, type NameChangeWithPlayer, type NameChangesSearchFilter, PERIODS, PLAYER_BUILDS, PLAYER_STATUSES, PLAYER_TYPES, PRIVELEGED_GROUP_ROLES, type ParticipationWithCompetition, type ParticipationWithCompetitionAndStandings, type ParticipationWithPlayer, type ParticipationWithPlayerAndProgress, Period, PeriodProps, type Player, PlayerAnnotationType, type PlayerArchiveWithPlayer, PlayerBuild, PlayerBuildProps, type PlayerCompetitionStandingsFilter, type PlayerCompetitionsFilter, type PlayerDeltasMap, type PlayerDetails, type PlayerRecordsFilter, PlayerStatus, PlayerStatusProps, PlayerType, PlayerTypeProps, REAL_METRICS, REAL_SKILLS, type Record, type RecordLeaderboardEntry, type RecordLeaderboardFilter, SKILLS, SKILL_EXP_AT_99, Skill, type SkillDelta, type SkillMetaConfig, type SkillMetaMethod, type SkillValue, type SkipContext, type Snapshot, type SnapshotFragment, type Team, type TimeRangeFilter, type Top5ProgressResult, WOMClient, findCountry, findCountryByCode, findCountryByName, findGroupRole, findMetric, findPeriod, findPlayerBuild, findPlayerType, formatNumber, getCombatLevel, getExpForLevel, getLevel, getMetricMeasure, getMetricName, getMetricRankKey, getMetricValueKey, getMinimumValue, getParentEfficiencyMetric, isActivity, isBoss, isCompetitionStatus, isCompetitionType, isComputedMetric, isCountry, isGroupRole, isMetric, isPeriod, isPlayerBuild, isPlayerStatus, isPlayerType, isSkill, padNumber, parsePeriodExpression, round };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wise-old-man/utils",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.12",
|
|
4
4
|
"description": "A JavaScript/TypeScript client that interfaces and consumes the Wise Old Man API, an API that tracks and measures players' progress in Old School Runescape.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wiseoldman",
|