Skip to content

Commit 4197b2b

Browse files
committed
refactor notification templates and enhance test renderer with title and description support
1 parent 9a9d811 commit 4197b2b

3 files changed

Lines changed: 152 additions & 76 deletions

File tree

src/notify/template.ts

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { AlertRule, RendererRecord, TemplateFieldFormat, TemplateRendererConfig } from '../alert-config'
22
import { transactionLink } from '../utils/links'
3-
import { explorerUrl, formatAddress, formatValue } from './format'
3+
import { severityColors } from './const'
44
import { notifyDiscord } from './discord'
55
import type { EventRendererParams } from './event/event'
6+
import { formatAddress, formatValue } from './format'
67
import type { NotifyForTraceInput } from './trace'
7-
import { severityColors } from './const'
88

99
type TemplateContext = {
1010
decoded: Record<string, unknown>
@@ -43,11 +43,14 @@ export const createEventTemplateRenderer =
4343
interpolateTemplate(config.titleTemplate, { decoded, meta, rule: toRuleTemplateContext(rule) }) ??
4444
`${params.name ?? rule.displayName ?? rule.topic} - ${params.eventName}`,
4545
url: transactionLink(params.log.transactionHash, params.ctx.chain),
46-
description: interpolateTemplate(config.descriptionTemplate, {
47-
decoded,
48-
meta,
49-
rule: toRuleTemplateContext(rule),
50-
}),
46+
description:
47+
interpolateTemplate(config.descriptionTemplate, {
48+
decoded,
49+
meta,
50+
rule: toRuleTemplateContext(rule),
51+
}) ??
52+
rule.description ??
53+
undefined,
5154
fields: buildFields(config, { decoded, meta, rule: toRuleTemplateContext(rule) }, params.ctx.chain),
5255
},
5356
],
@@ -88,12 +91,17 @@ export const createTraceTemplateRenderer =
8891
title:
8992
interpolateTemplate(config.titleTemplate, { decoded, meta, rule: toRuleTemplateContext(rule) }) ??
9093
`${input.name ?? rule.displayName ?? rule.topic} - ${input.functionName ?? input.trace.type}`,
91-
url: input.trace.transaction?.hash ? transactionLink(input.trace.transaction.hash, input.ctx.chain) : undefined,
92-
description: interpolateTemplate(config.descriptionTemplate, {
93-
decoded,
94-
meta,
95-
rule: toRuleTemplateContext(rule),
96-
}),
94+
url: input.trace.transaction?.hash
95+
? transactionLink(input.trace.transaction.hash, input.ctx.chain)
96+
: undefined,
97+
description:
98+
interpolateTemplate(config.descriptionTemplate, {
99+
decoded,
100+
meta,
101+
rule: toRuleTemplateContext(rule),
102+
}) ??
103+
rule.description ??
104+
undefined,
97105
fields: buildFields(config, { decoded, meta, rule: toRuleTemplateContext(rule) }, input.ctx.chain),
98106
},
99107
],
@@ -108,7 +116,11 @@ function normalizeTemplateConfig(configJson: RendererRecord['configJson']): Temp
108116
return {}
109117
}
110118

111-
function buildFields(config: TemplateRendererConfig, context: TemplateContext, chain: EventRendererParams['ctx']['chain']) {
119+
function buildFields(
120+
config: TemplateRendererConfig,
121+
context: TemplateContext,
122+
chain: EventRendererParams['ctx']['chain'],
123+
) {
112124
return (config.fields ?? [])
113125
.map((field) => {
114126
const rawValue = getPathValue(context, field.path)
@@ -123,7 +135,11 @@ function buildFields(config: TemplateRendererConfig, context: TemplateContext, c
123135
.slice(0, 25)
124136
}
125137

126-
function formatTemplateField(value: unknown, format: TemplateFieldFormat, chain: EventRendererParams['ctx']['chain']): string {
138+
function formatTemplateField(
139+
value: unknown,
140+
format: TemplateFieldFormat,
141+
chain: EventRendererParams['ctx']['chain'],
142+
): string {
127143
if (value == null) return '_null_'
128144
if (format === 'timestamp') {
129145
const timestamp = typeof value === 'number' ? value : Number(value)
@@ -145,7 +161,9 @@ function formatTemplateField(value: unknown, format: TemplateFieldFormat, chain:
145161

146162
function interpolateTemplate(template: string | undefined, context: TemplateContext): string | undefined {
147163
if (!template?.trim()) return undefined
148-
return template.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_match, path) => stringifyTemplateValue(getPathValue(context, path)))
164+
return template.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_match, path) =>
165+
stringifyTemplateValue(getPathValue(context, path)),
166+
)
149167
}
150168

151169
function stringifyTemplateValue(value: unknown): string {
@@ -171,10 +189,7 @@ function isEmpty(value: unknown): boolean {
171189
return value == null || value === '' || (Array.isArray(value) && value.length === 0)
172190
}
173191

174-
function safeDecode(
175-
event: EventRendererParams['event'],
176-
log: EventRendererParams['log'],
177-
): Record<string, unknown> {
192+
function safeDecode(event: EventRendererParams['event'], log: EventRendererParams['log']): Record<string, unknown> {
178193
try {
179194
const decoded = event.decode(log)
180195
if (decoded && typeof decoded === 'object' && !Array.isArray(decoded)) {

src/server-extension/resolvers/test-render.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ class TestRenderResult {
1616

1717
@Field({ nullable: true })
1818
txHash?: string
19+
20+
@Field({ nullable: true })
21+
data?: string
1922
}
2023

2124
@Resolver()
@@ -25,6 +28,8 @@ export class TestRenderResolver {
2528
@Arg('rendererId') rendererId: string,
2629
@Arg('token') token: string,
2730
@Arg('data', { nullable: true }) data?: string,
31+
@Arg('title', { nullable: true }) title?: string,
32+
@Arg('description', { nullable: true }) description?: string,
2833
): Promise<TestRenderResult> {
2934
const expected = process.env.SQUID_TEST_RENDER_TOKEN
3035
if (!expected || token !== expected) {
@@ -34,20 +39,36 @@ export class TestRenderResolver {
3439
let parsedData: Record<string, unknown> | undefined
3540
if (data) {
3641
try {
37-
parsedData = JSON.parse(data)
42+
parsedData = JSON.parse(data, (_key, value) => {
43+
if (typeof value === 'string' && /^-?\d+n$/.test(value)) {
44+
return BigInt(value.slice(0, -1))
45+
}
46+
return value
47+
})
3848
} catch {
3949
throw new Error('Invalid JSON in data argument')
4050
}
4151
}
4252

4353
const { sendRendererTestAlert } = await import('../../test-render/service')
44-
const result = await sendRendererTestAlert(rendererId, parsedData)
54+
const result = await sendRendererTestAlert(rendererId, {
55+
data: parsedData,
56+
title: title ?? undefined,
57+
description: description ?? undefined,
58+
})
4559
return {
4660
ok: true,
4761
rendererId: result.rendererId,
4862
matchType: result.matchType,
4963
recordId: result.recordId,
5064
txHash: result.txHash ?? undefined,
65+
data: result.data
66+
? JSON.stringify(
67+
result.data,
68+
(_key, item) => (typeof item === 'bigint' ? `${item.toString()}n` : item),
69+
2,
70+
)
71+
: undefined,
5172
}
5273
}
5374
}

0 commit comments

Comments
 (0)