import {z} from 'zod' export type GetApiV1AccountAccountSlugProjectProjectSlugAlertsArgs = {accountSlug: string, projectSlug: string}; export type GetApiV1AccountAccountSlugProjectProjectSlugAlertsOptions = {baseUrl?: string | undefined, ApiKeyAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const methodCallExpression = z.object({line_number: z.number().int(), call_position: z.enum(["first", "last", "any"])}); export const whitelistedCallerExpression = z.object({addresses: z.array(z.string())}); export const blacklistedCallerExpression = z.object({addresses: z.array(z.string())}); export const contractAddressExpression = z.object({address: z.string(), transaction_type: z.enum(["direct", "source", "internal"]).optional()}); export const networkExpression = z.object({network_id: z.string()}); export const tagExpression = z.object({tag: z.string(), transaction_type: z.enum(["direct", "source", "internal"]).optional()}); export const txStatusExpression = z.object({transaction_success: z.boolean().optional()}); export const parameterCondition = z.object({parameter_name: z.string(), operator: z.enum([">", ">=", "<", "<=", "==", "!=", "contains", "notContains"]), parameter_type: z.enum(["uint", "int", "bool", "address", "string", "byte"]), nested_parameter_type: z.string().optional(), comparison_value: z.string()}); export const functionParamsExpression = z.object({address: z.string(), function_line_number: z.number().int(), parameter_conditions: z.array(parameterCondition)}); export const txValueExpression = z.object({transaction_value: z.string(), operator: z.enum([">", ">=", "<", "<=", "==", "!="])}); export const emittedLogExpression = z.object({address: z.string(), event_name: z.string(), event_id: z.string(), match_any: z.boolean().optional(), decode_events: z.boolean().optional(), match_non_project_contracts: z.boolean().optional(), parameter_conditions: z.array(parameterCondition).optional()}); export const stateChangeExpression = z.object({address: z.string(), parameter_conditions: z.array(z.object({parameter_name: z.string(), parameter_type: z.string(), compare_change: z.boolean().optional(), compare_threshold: z.boolean().optional(), compare_percentage: z.boolean().optional(), comparison_value: z.string().optional(), operator: z.enum([">", "<", "==", ">=", "<="]).optional()}))}); export const viewFunctionExpression = z.object({address: z.string(), input: z.string(), network_id: z.string(), parameter_condition: z.object({compare_threshold: z.boolean().optional(), comparison_value: z.string().optional(), operator: z.enum([">", "<", "==", ">=", "<="]).optional(), parameter_type: z.string().optional()}).optional()}); export const ethBalanceExpression = z.object({address: z.string(), threshold: z.string()}); export const eRC20TransferMatcherExpression = z.object({address: z.string(), log_name: z.string(), balances: z.string()}); export const txErrorExpression = z.object({addresses_to_ignore: z.array(z.string()).optional()}); export const txInternalErrorExpression = z.object({addresses_to_match: z.array(z.string()).optional()}); export const noActionExpression = z.object({no_log: z.object({address: z.string().optional(), network_id: z.string().optional(), event_id: z.string().optional(), event_name: z.string().optional()}).optional(), no_transaction: z.object({address: z.string().optional(), is_from_address: z.boolean().optional(), network_id: z.string().optional(), transaction_success: z.boolean().optional()}).optional(), check_after_seconds: z.number().int()}); export const sandwichTransactionExpression = z.object({address: z.string(), transaction_type: z.enum(["direct", "source", "internal"]).optional()}); export const alertExpression = z.object({type: z.enum(["method_call", "whitelisted_caller_addresses", "blacklisted_caller_addresses", "contract_address", "network", "tag", "tx_status", "function_params", "tx_value", "emitted_log", "state_change", "view_function", "eth_balance", "erc20_transfer_matcher", "tx_error", "tx_internal_error", "no_action", "sandwich_transaction"]), expression: z.union([methodCallExpression, whitelistedCallerExpression, blacklistedCallerExpression, contractAddressExpression, networkExpression, tagExpression, txStatusExpression, functionParamsExpression, txValueExpression, emittedLogExpression, stateChangeExpression, viewFunctionExpression, ethBalanceExpression, eRC20TransferMatcherExpression, txErrorExpression, txInternalErrorExpression, noActionExpression, sandwichTransactionExpression])}); export const alert = z.object({id: z.string(), project_id: z.string(), name: z.string(), description: z.string().optional(), enabled: z.boolean(), color: z.enum(["#eeeeee", "#34ace0", "#ffda79", "#ff5252", "#33d9b2"]), severity: z.enum(["default", "info", "warning", "danger", "success"]), created_at: z.string(), updated_at: z.string(), is_editable: z.boolean(), delivery_channels: z.array(z.object({delivery_channel_id: z.string().optional(), enabled: z.boolean().optional(), created_at: z.string().optional()})).optional(), expressions: z.array(alertExpression)}); export const alertsGetResponse = z.object({alerts: z.array(alert).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List Alerts * * GET /v1/account/{accountSlug}/project/{projectSlug}/alerts * * Also accepts auth: BearerAuth */ export const getApiV1AccountAccountSlugProjectProjectSlugAlerts = async (args: GetApiV1AccountAccountSlugProjectProjectSlugAlertsArgs, options?: GetApiV1AccountAccountSlugProjectProjectSlugAlertsOptions) => { const {baseUrl = "https://api.tenderly.co/api", fetch: fetchFn = fetch, ApiKeyAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (ApiKeyAuth !== undefined) headers.set("X-Access-Key", ApiKeyAuth) const url = `${baseUrl.replace(/\/+$/, '')}/v1/account/${encodeURIComponent(String(args.accountSlug))}/project/${encodeURIComponent(String(args.projectSlug))}/alerts${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(alertsGetResponse, await res.json()) };