@gearbox-protocol/cli-utils 6.16.2 → 9.0.0-beta.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.
Files changed (60) hide show
  1. package/dist/index.d.ts +436 -19
  2. package/dist/index.js +1402 -19
  3. package/dist/index.js.map +1 -0
  4. package/package.json +26 -13
  5. package/dist/CensoredString.d.ts +0 -8
  6. package/dist/CensoredString.js +0 -31
  7. package/dist/CensoredURL.d.ts +0 -11
  8. package/dist/CensoredURL.js +0 -53
  9. package/dist/SSMManager.d.ts +0 -5
  10. package/dist/SSMManager.js +0 -30
  11. package/dist/SecretsManager.d.ts +0 -6
  12. package/dist/SecretsManager.js +0 -52
  13. package/dist/Whitelist.d.ts +0 -30
  14. package/dist/Whitelist.js +0 -84
  15. package/dist/Zommand.d.ts +0 -25
  16. package/dist/Zommand.js +0 -98
  17. package/dist/compressedConfig.d.ts +0 -10
  18. package/dist/compressedConfig.js +0 -22
  19. package/dist/createPinoCensor.d.ts +0 -5
  20. package/dist/createPinoCensor.js +0 -53
  21. package/dist/fetchRetry.d.ts +0 -7
  22. package/dist/fetchRetry.js +0 -26
  23. package/dist/getFirstHttpTransportOptions.d.ts +0 -7
  24. package/dist/getFirstHttpTransportOptions.js +0 -13
  25. package/dist/getPromisePath.d.ts +0 -7
  26. package/dist/getPromisePath.js +0 -18
  27. package/dist/getProviders.d.ts +0 -4
  28. package/dist/getProviders.js +0 -104
  29. package/dist/notifications/NotificationsService.d.ts +0 -19
  30. package/dist/notifications/NotificationsService.js +0 -76
  31. package/dist/notifications/SignlNotifier.d.ts +0 -13
  32. package/dist/notifications/SignlNotifier.js +0 -58
  33. package/dist/notifications/SlackNotifier.d.ts +0 -8
  34. package/dist/notifications/SlackNotifier.js +0 -38
  35. package/dist/notifications/TelegramNotifier.d.ts +0 -14
  36. package/dist/notifications/TelegramNotifier.js +0 -119
  37. package/dist/notifications/ThrottleManager.d.ts +0 -18
  38. package/dist/notifications/ThrottleManager.js +0 -40
  39. package/dist/notifications/createNotifier.d.ts +0 -4
  40. package/dist/notifications/createNotifier.js +0 -18
  41. package/dist/notifications/index.d.ts +0 -4
  42. package/dist/notifications/index.js +0 -4
  43. package/dist/notifications/schema.d.ts +0 -33
  44. package/dist/notifications/schema.js +0 -46
  45. package/dist/notifications/types.d.ts +0 -91
  46. package/dist/notifications/types.js +0 -1
  47. package/dist/providers-schema.d.ts +0 -49
  48. package/dist/providers-schema.js +0 -122
  49. package/dist/providers.d.ts +0 -6
  50. package/dist/providers.js +0 -103
  51. package/dist/resolveYamlFiles.d.ts +0 -40
  52. package/dist/resolveYamlFiles.js +0 -170
  53. package/dist/schema-primitives.d.ts +0 -10
  54. package/dist/schema-primitives.js +0 -30
  55. package/dist/sleep.d.ts +0 -1
  56. package/dist/sleep.js +0 -6
  57. package/dist/uncensorMap.d.ts +0 -4
  58. package/dist/uncensorMap.js +0 -3
  59. package/dist/whitelist-schema.d.ts +0 -54
  60. package/dist/whitelist-schema.js +0 -21
package/dist/Zommand.js DELETED
@@ -1,98 +0,0 @@
1
- import { Command, Option } from "@commander-js/extra-typings";
2
- import * as z4 from "zod/v4/core";
3
- import { decompressObject } from "./compressedConfig.js";
4
- import { resolveYamlFiles } from "./resolveYamlFiles.js";
5
- export const zommandRegistry = z4.registry();
6
- export class Zommand extends Command {
7
- #schema;
8
- #templatedData;
9
- #envToObjectKeys = {};
10
- constructor(name, opts) {
11
- super(name);
12
- const { schema, templateData, configFile = true, inlineConfig = true, } = opts;
13
- this.#schema = schema;
14
- this.#templatedData = templateData;
15
- const def = this.#schema._zod.def;
16
- if (def.type === "object") {
17
- this.#addOptionsFromObject(def);
18
- }
19
- else if (def.type === "union") {
20
- for (const o of def.options) {
21
- const opt = o;
22
- if (opt._zod.def.type === "object") {
23
- this.#addOptionsFromObject(opt._zod.def);
24
- }
25
- }
26
- }
27
- else {
28
- throw new Error(`expected object schema, got ${this.#schema._zod.def.type}`);
29
- }
30
- if (configFile) {
31
- let opt = new Option("--config [file]", "config file (or s3 link");
32
- if (typeof configFile === "string") {
33
- opt = opt.default(configFile);
34
- }
35
- this.addOption(opt);
36
- }
37
- if (inlineConfig) {
38
- this.addOption(new Option("--inline-config [config]", "inline config"));
39
- }
40
- }
41
- #addOptionsFromObject(def) {
42
- const shape = def.shape;
43
- for (const [key, optionSchema] of Object.entries(shape)) {
44
- const meta = zommandRegistry.get(optionSchema);
45
- if (!meta) {
46
- continue;
47
- }
48
- // this avoids duplicate options in case of discriminated unions
49
- const existing = this.options.find(o => o.flags === meta.flags);
50
- if (!existing) {
51
- let description = meta.description;
52
- if (meta.env) {
53
- description = `${description} (env variable ${meta.env})`;
54
- }
55
- this.addOption(new Option(meta.flags, description));
56
- if (meta.env) {
57
- this.#envToObjectKeys[meta.env] = key;
58
- }
59
- }
60
- }
61
- }
62
- action(fn) {
63
- return super.action(async (...args) => {
64
- const argz = args;
65
- const _cmd = argz.splice(-1);
66
- const [{ config, inlineConfig, ...opts }] = argz.splice(-1);
67
- let fromYaml = {};
68
- if (config) {
69
- fromYaml = await resolveYamlFiles(config, {
70
- ...process.env,
71
- ...this.#templatedData,
72
- });
73
- }
74
- let fromInlineConfig = {};
75
- if (inlineConfig) {
76
- fromInlineConfig = await decompressObject(inlineConfig, this.#templatedData);
77
- }
78
- else if (process.env.INLINE_CONFIG) {
79
- fromInlineConfig = await decompressObject(process.env.INLINE_CONFIG, this.#templatedData);
80
- }
81
- const schemaFromEnv = {};
82
- for (const [env, key] of Object.entries(this.#envToObjectKeys)) {
83
- if (process.env[env]) {
84
- schemaFromEnv[key] = process.env[env];
85
- }
86
- }
87
- // deep merge is not required: env and cli flags are for top-level only
88
- const combined = {
89
- ...schemaFromEnv,
90
- ...fromYaml,
91
- ...fromInlineConfig,
92
- ...opts,
93
- };
94
- const data = z4.parse(this.#schema, combined);
95
- await fn.apply(this, [...argz, data, this]);
96
- });
97
- }
98
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * Compress a plain JS object into a base64url string
3
- * suitable for env vars.
4
- */
5
- export declare function compressObject(obj: unknown): string;
6
- /**
7
- * Decompress a base64url string back into a JS object
8
- * Allows to pass template data to resolve promises/env
9
- */
10
- export declare function decompressObject<T = unknown>(value: string, templateData?: Record<string, unknown>): Promise<T>;
@@ -1,22 +0,0 @@
1
- import { deflateSync, inflateSync } from "node:zlib";
2
- import { resolveFromObject } from "./resolveYamlFiles.js";
3
- /**
4
- * Compress a plain JS object into a base64url string
5
- * suitable for env vars.
6
- */
7
- export function compressObject(obj) {
8
- const json = JSON.stringify(obj);
9
- const compressed = deflateSync(Buffer.from(json, "utf8"));
10
- return compressed.toString("base64url");
11
- }
12
- /**
13
- * Decompress a base64url string back into a JS object
14
- * Allows to pass template data to resolve promises/env
15
- */
16
- export async function decompressObject(value, templateData) {
17
- const compressed = Buffer.from(value, "base64url");
18
- const str = inflateSync(compressed).toString("utf8");
19
- const json = JSON.parse(str);
20
- const result = await resolveFromObject(json, templateData);
21
- return result;
22
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Gathers known secrets from a config and returns a function that replaces each raw secret with its masked representation.
3
- * Intended for pino's `hooks.streamWrite`
4
- */
5
- export declare function createPinoCensor(config: unknown): (s: string) => string;
@@ -1,53 +0,0 @@
1
- import { CensoredString } from "./CensoredString.js";
2
- import { CensoredURL } from "./CensoredURL.js";
3
- /**
4
- * Raw values shorter than this are not censored, to avoid masking unrelated
5
- * substrings throughout the log output.
6
- */
7
- const MIN_SECRET_LENGTH = 4;
8
- function escapeRegExp(value) {
9
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10
- }
11
- function collectSecrets(value, out) {
12
- if (value == null) {
13
- return;
14
- }
15
- if (value instanceof CensoredString || value instanceof CensoredURL) {
16
- const raw = value.value;
17
- if (raw.length >= MIN_SECRET_LENGTH) {
18
- out.set(raw, value.toString());
19
- }
20
- return;
21
- }
22
- if (typeof value !== "object") {
23
- return;
24
- }
25
- if (Array.isArray(value)) {
26
- for (const item of value) {
27
- collectSecrets(item, out);
28
- }
29
- return;
30
- }
31
- for (const item of Object.values(value)) {
32
- collectSecrets(item, out);
33
- }
34
- }
35
- /**
36
- * Gathers known secrets from a config and returns a function that replaces each raw secret with its masked representation.
37
- * Intended for pino's `hooks.streamWrite`
38
- */
39
- export function createPinoCensor(config) {
40
- const map = new Map();
41
- collectSecrets(config, map);
42
- if (map.size === 0) {
43
- return s => s;
44
- }
45
- // Longer secrets first so a secret that is a substring of another does not
46
- // shadow the longer match.
47
- const pattern = [...map.keys()]
48
- .sort((a, b) => b.length - a.length)
49
- .map(escapeRegExp)
50
- .join("|");
51
- const re = new RegExp(pattern, "g");
52
- return s => s.replace(re, m => map.get(m) ?? m);
53
- }
@@ -1,7 +0,0 @@
1
- interface RetrySettings {
2
- retries?: number;
3
- retryInterval?: number;
4
- validateResponse?: (response: Response) => void;
5
- }
6
- export declare function fetchRetry(input: string | URL, init?: RequestInit & RetrySettings): Promise<Response>;
7
- export {};
@@ -1,26 +0,0 @@
1
- // Mirror of packages/shared/src/fetchRetry.ts; keep in sync.
2
- import { sleep } from "./sleep.js";
3
- const DEFAULT_RETRIES = 5;
4
- const DEFAULT_RETRY_INTERVAL = 1000;
5
- export async function fetchRetry(input, init = {}) {
6
- const { retries = DEFAULT_RETRIES, retryInterval = DEFAULT_RETRY_INTERVAL, validateResponse, ...options } = init;
7
- try {
8
- const response = await fetch(input, options);
9
- validateResponse?.(response);
10
- return response;
11
- }
12
- catch (e) {
13
- if (retries > 0) {
14
- await sleep(retryInterval);
15
- return fetchRetry(input, {
16
- ...options,
17
- retries: retries - 1,
18
- retryInterval,
19
- validateResponse,
20
- });
21
- }
22
- else {
23
- throw e;
24
- }
25
- }
26
- }
@@ -1,7 +0,0 @@
1
- import type { HttpTransportConfig } from "viem";
2
- import type { ProvidersSchema } from "./providers-schema.js";
3
- export interface HttpTransportOptions {
4
- url?: string | undefined;
5
- config: HttpTransportConfig;
6
- }
7
- export declare function getFirstHttpTransportOptions(config: ProvidersSchema): HttpTransportOptions;
@@ -1,13 +0,0 @@
1
- import { getProviders } from "./getProviders.js";
2
- export function getFirstHttpTransportOptions(config) {
3
- const [provider] = getProviders(config);
4
- if (!provider) {
5
- throw new Error("No provider found");
6
- }
7
- return {
8
- url: provider.url,
9
- config: {
10
- ...provider.httpTransportOptions,
11
- },
12
- };
13
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * Similar to lodash.get, but supports promises
3
- * @param object
4
- * @param keys
5
- * @returns
6
- */
7
- export default function getPromisePath<V = any>(object: any, path: string): Promise<V>;
@@ -1,18 +0,0 @@
1
- /**
2
- * Similar to lodash.get, but supports promises
3
- * @param object
4
- * @param keys
5
- * @returns
6
- */
7
- export default async function getPromisePath(object, path) {
8
- return getPromised(object, path.split("."));
9
- }
10
- async function getPromised(object, keys) {
11
- if (keys.length === 0) {
12
- return Promise.resolve(object);
13
- }
14
- const [key, ...rest] = keys;
15
- const value = object[key];
16
- const resolved = await Promise.resolve(value);
17
- return getPromised(resolved, rest);
18
- }
@@ -1,4 +0,0 @@
1
- import type { ILogger } from "@gearbox-protocol/sdk";
2
- import type { ProviderConfig } from "@gearbox-protocol/sdk/dev";
3
- import type { ProvidersSchema } from "./providers-schema.js";
4
- export declare function getProviders(config: ProvidersSchema, logger?: ILogger): ProviderConfig[];
@@ -1,104 +0,0 @@
1
- import { CensoredURL } from "./CensoredURL.js";
2
- import { getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getThirdWebUrl, } from "./providers.js";
3
- export function getProviders(config, logger) {
4
- const { network, enabledProviders = [
5
- "erpc",
6
- "custom",
7
- "drpc",
8
- "alchemy",
9
- "ankr",
10
- "thirdweb",
11
- ], alchemyKeys = [], ankrKeys = [], drpcKeys = [], thirdwebKeys = [], jsonRpcProviders = [], erpcProjectId, erpcUrl, } = config;
12
- const result = [];
13
- for (const p of enabledProviders) {
14
- switch (p) {
15
- case "alchemy":
16
- result.push(...alchemyKeys.map(k => ({
17
- name: "alchemy",
18
- url: getAlchemyUrl(network, k.value),
19
- })));
20
- break;
21
- case "drpc":
22
- result.push(...drpcKeys.map(k => ({
23
- name: "drpc",
24
- url: getDrpcUrl(network, k.value),
25
- })));
26
- break;
27
- case "ankr":
28
- result.push(...ankrKeys.map(k => ({
29
- name: "ankr",
30
- url: getAnkrUrl(network, k.value),
31
- })));
32
- break;
33
- case "thirdweb":
34
- result.push(...thirdwebKeys.map(k => ({
35
- name: "thirdweb",
36
- url: getThirdWebUrl(network, k.value),
37
- })));
38
- break;
39
- case "custom":
40
- result.push(...jsonRpcProviders.map((url) => {
41
- const urlObj = new URL(url.value);
42
- const hasCredentials = urlObj.username || urlObj.password;
43
- let cleanUrl = url.value;
44
- let httpTransportOptions = {};
45
- if (hasCredentials) {
46
- // Create URL without credentials
47
- const cleanUrlObj = new URL(url.value);
48
- cleanUrlObj.username = "";
49
- cleanUrlObj.password = "";
50
- cleanUrl = cleanUrlObj.toString();
51
- // Create Basic Auth header
52
- const credentials = `${urlObj.username}:${urlObj.password}`;
53
- const encodedCredentials = Buffer.from(credentials).toString("base64");
54
- httpTransportOptions = {
55
- fetchOptions: {
56
- headers: {
57
- Authorization: `Basic ${encodedCredentials}`,
58
- },
59
- },
60
- };
61
- }
62
- return {
63
- name: getTopLevelDomain(urlObj),
64
- url: cleanUrl,
65
- httpTransportOptions,
66
- };
67
- }));
68
- break;
69
- case "erpc":
70
- if (erpcProjectId && erpcUrl) {
71
- result.push({
72
- name: "erpc",
73
- url: getErpcKey(network, erpcProjectId, erpcUrl),
74
- });
75
- }
76
- break;
77
- }
78
- }
79
- if (logger) {
80
- const providers = result
81
- .filter(p => !!p.url)
82
- .map(p => ({
83
- name: p.name,
84
- url: new CensoredURL(p.url),
85
- }));
86
- logger.debug({ providers, network }, "gathered providers");
87
- }
88
- return result
89
- .map(p => ({
90
- ...p,
91
- httpClientOptions: {
92
- ...p.httpTransportOptions,
93
- methods: { exclude: ["eth_fillTransaction"] },
94
- },
95
- }))
96
- .filter(p => !!p.url);
97
- }
98
- /**
99
- * Take the last two parts for top-level domain (e.g., "google.com" from "a.b.c.google.com")
100
- **/
101
- function getTopLevelDomain({ hostname }) {
102
- const parts = hostname.split(".");
103
- return parts.length >= 2 ? parts.slice(-2).join(".") : hostname;
104
- }
@@ -1,19 +0,0 @@
1
- import { type ILogger } from "@gearbox-protocol/sdk";
2
- import type { Address } from "viem";
3
- import { type SignlServiceOptions } from "./SignlNotifier.js";
4
- import type { NotificationConfig } from "./schema.js";
5
- import type { INotificationService, NotificationLike } from "./types.js";
6
- export interface NotificationsServiceOptions {
7
- notifications: Array<NotificationConfig & {
8
- recipient?: Address;
9
- }>;
10
- signl?: SignlServiceOptions;
11
- }
12
- export declare class NotificationsService implements INotificationService {
13
- #private;
14
- constructor(options: NotificationsServiceOptions, logger?: ILogger);
15
- registerRecipient(address: Address, options: NotificationConfig): void;
16
- signl(message: string, dedupeKey?: string): void;
17
- alert(msg: NotificationLike): void;
18
- notify(msg: NotificationLike): void;
19
- }
@@ -1,76 +0,0 @@
1
- import { ADDRESS_0X0, AddressMap } from "@gearbox-protocol/sdk";
2
- import { createNotifier } from "./createNotifier.js";
3
- import SignlNotifier from "./SignlNotifier.js";
4
- export class NotificationsService {
5
- #logger;
6
- #notifiers = new AddressMap();
7
- #signlNotifier;
8
- constructor(options, logger) {
9
- this.#logger = logger;
10
- for (const n of options.notifications) {
11
- const recipient = n.recipient ?? ADDRESS_0X0;
12
- const notifier = createNotifier(n, logger);
13
- if (notifier) {
14
- this.#notifiers.upsert(recipient, notifier);
15
- }
16
- }
17
- if (options.signl) {
18
- this.#signlNotifier = new SignlNotifier(options.signl);
19
- }
20
- else {
21
- this.#logger?.warn("signl notifier not configured");
22
- }
23
- }
24
- registerRecipient(address, options) {
25
- const notifier = createNotifier(options, this.#logger);
26
- if (notifier) {
27
- this.#notifiers.upsert(address, notifier);
28
- }
29
- }
30
- signl(message, dedupeKey) {
31
- this.#signlNotifier?.alert(message, dedupeKey);
32
- }
33
- alert(msg) {
34
- this.#notify(msg, "alert");
35
- }
36
- notify(msg) {
37
- this.#notify(msg, "notification");
38
- }
39
- #notify(msg, severity) {
40
- const message = this.#toNotification(msg);
41
- for (const [addr, notifier] of this.#notifiers.entries()) {
42
- const recipient = addr === ADDRESS_0X0 ? undefined : addr;
43
- const recipientNotification = message.messageFor(recipient);
44
- if (recipientNotification) {
45
- const notification = this.#toDedupableNotification(recipientNotification);
46
- notifier.notify(notification, severity);
47
- // log global notifications
48
- if (addr === ADDRESS_0X0) {
49
- if (severity === "alert") {
50
- this.#logger?.warn(notification.plain);
51
- }
52
- else {
53
- this.#logger?.debug(notification.plain);
54
- }
55
- }
56
- }
57
- }
58
- }
59
- #toNotification(message) {
60
- // global notification without deduplication
61
- if (typeof message === "string" || !("messageFor" in message)) {
62
- return {
63
- messageFor: (recipient) => (recipient ? undefined : message),
64
- };
65
- }
66
- return message;
67
- }
68
- #toDedupableNotification(msg) {
69
- if (typeof msg === "string") {
70
- return {
71
- plain: msg,
72
- };
73
- }
74
- return msg;
75
- }
76
- }
@@ -1,13 +0,0 @@
1
- import type { ILogger } from "@gearbox-protocol/sdk";
2
- import type { SignlConfig } from "./schema.js";
3
- import type { ThrottleFn } from "./types.js";
4
- export type SignlServiceOptions = SignlConfig & {
5
- retryInterval?: number;
6
- retryCount?: number;
7
- throttleFn?: ThrottleFn;
8
- };
9
- export default class SignlNotifier {
10
- #private;
11
- constructor(opts: SignlServiceOptions, logger?: ILogger);
12
- alert(message: string, dedupeKey?: string): void;
13
- }
@@ -1,58 +0,0 @@
1
- import { withRetry } from "viem";
2
- import { ThrottleManager } from "./ThrottleManager.js";
3
- const DEFAULT_RETRY_INTERVAL = 1000;
4
- const DEFAULT_RETRY_COUNT = 5;
5
- export default class SignlNotifier {
6
- #logger;
7
- #apiKey;
8
- #teamId;
9
- #retryInterval;
10
- #retryCount;
11
- #throttleManager = new ThrottleManager();
12
- #throttleFn;
13
- constructor(opts, logger) {
14
- this.#apiKey = opts.apiKey;
15
- this.#teamId = opts.teamId;
16
- this.#retryInterval = opts.retryInterval ?? DEFAULT_RETRY_INTERVAL;
17
- this.#retryCount = opts.retryCount ?? DEFAULT_RETRY_COUNT;
18
- this.#logger = logger;
19
- this.#throttleFn = opts.throttleFn;
20
- this.#logger?.info(opts, "signl notifier configured");
21
- }
22
- alert(message, dedupeKey) {
23
- void this.#sendAlert(message, dedupeKey).catch(e => this.#logger?.error(e));
24
- }
25
- async #sendAlert(message, dedupeKey) {
26
- if (dedupeKey && !this.#throttleManager.canSend(dedupeKey)) {
27
- return;
28
- }
29
- const text = message.slice(0, 64); // it's to be shown in mobile notifications anyways
30
- this.#logger?.debug("sending signl alert");
31
- await withRetry(async () => {
32
- const resp = await fetch(`https://connect.signl4.com/api/v2/alerts?x-s4-api-key=${this.#apiKey.value}`, {
33
- method: "POST",
34
- headers: {
35
- "Content-Type": "application/json",
36
- },
37
- body: JSON.stringify({
38
- category: "emergency",
39
- severity: 0,
40
- teamId: this.#teamId.value,
41
- text,
42
- title: "GEARBOX ALERT",
43
- }),
44
- });
45
- if (resp.ok) {
46
- this.#logger?.warn("signl alert sent");
47
- const data = await resp.json();
48
- this.#logger?.info(`signl alert response: ${JSON.stringify(data)}`);
49
- }
50
- else {
51
- throw new Error(`signl api error ${resp.status}: ${resp.statusText}`);
52
- }
53
- }, { delay: this.#retryInterval, retryCount: this.#retryCount });
54
- if (dedupeKey) {
55
- this.#throttleManager.onSent(dedupeKey, this.#throttleFn);
56
- }
57
- }
58
- }
@@ -1,8 +0,0 @@
1
- import type { ILogger } from "@gearbox-protocol/sdk";
2
- import type { SlackConfig } from "./schema.js";
3
- import type { IDedupableNotification, INotifier, NotificationSeverity } from "./types.js";
4
- export declare class SlackNotifier implements INotifier {
5
- #private;
6
- constructor(config: SlackConfig, logger?: ILogger);
7
- notify(message: IDedupableNotification, severity: NotificationSeverity): void;
8
- }
@@ -1,38 +0,0 @@
1
- // TODO: no throttling or deduplication yet
2
- export class SlackNotifier {
3
- #config;
4
- #logger;
5
- constructor(config, logger) {
6
- this.#config = config;
7
- this.#logger = logger;
8
- }
9
- notify(message, severity) {
10
- if (this.#config.alertsOnly && severity === "notification") {
11
- return;
12
- }
13
- const emoji = severity === "alert" ? "🚨" : "â„šī¸";
14
- const messageText = typeof message === "string" ? message : message.plain;
15
- void this.#sendToSlack(`${emoji} Alert: ${messageText}`);
16
- }
17
- async #sendToSlack(text) {
18
- try {
19
- this.#logger?.debug(`Sending message to Slack: ${text}`);
20
- // Use fetch instead of axios to avoid adding dependencies
21
- const response = await fetch(this.#config.webhookUrl.value, {
22
- method: "POST",
23
- headers: {
24
- "Content-Type": "application/json",
25
- },
26
- body: JSON.stringify({ text }),
27
- });
28
- if (!response.ok) {
29
- throw new Error(`HTTP error! status: ${response.status}`);
30
- }
31
- this.#logger?.debug("Slack message sent successfully");
32
- }
33
- catch (error) {
34
- this.#logger?.error("Error sending Slack message:", error);
35
- throw error;
36
- }
37
- }
38
- }
@@ -1,14 +0,0 @@
1
- import type { ILogger } from "@gearbox-protocol/sdk";
2
- import type { TelegramConfig } from "./schema.js";
3
- import type { IDedupableNotification, INotifier, NotificationSeverity } from "./types.js";
4
- export type TelegramNotifierOptions = TelegramConfig & {
5
- retryInterval?: number;
6
- retryCount?: number;
7
- maxChunkSize?: number;
8
- fetchFn?: typeof fetch;
9
- };
10
- export declare class TelegramNotifier implements INotifier {
11
- #private;
12
- constructor(opts: TelegramNotifierOptions, logger?: ILogger);
13
- notify(message: IDedupableNotification, severity: NotificationSeverity): void;
14
- }