tapimo 0.10.2 → 0.11.0
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/App.d.ts +3412 -1968
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js.map +1 -1
- package/dist/Webhooks.d.ts +0 -75
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +1 -143
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +74 -74
- package/dist/admin/apps/api-keys.d.ts +4 -4
- package/dist/admin/apps/earn-vaults.d.ts +1 -1
- package/dist/admin/apps/organizations.d.ts +3 -3
- package/dist/admin/apps/verified-tokens.d.ts +74 -74
- package/dist/apps/data/App.d.ts +3618 -2954
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +5 -2
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +1 -1
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +55 -27
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +343 -343
- package/dist/apps/data/routes/balances.d.ts +11 -11
- package/dist/apps/data/routes/blocks.d.ts +5 -5
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/earn.d.ts +4 -4
- package/dist/apps/data/routes/exchanges.d.ts +4 -4
- package/dist/apps/data/routes/fee-amm.d.ts +26 -26
- package/dist/apps/data/routes/indexer.d.ts +34 -34
- package/dist/apps/data/routes/receipts.d.ts +236 -236
- package/dist/apps/data/routes/tokenlist.d.ts +12 -12
- package/dist/apps/data/routes/tokens.d.ts +3 -3
- package/dist/apps/data/routes/transactions.d.ts +1 -1
- package/dist/apps/data/routes/transfers.d.ts +13 -13
- package/dist/apps/data/routes/valuation.d.ts +21 -21
- package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
- package/dist/apps/data/routes/webhooks.d.ts +1011 -151
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +124 -737
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +31 -31
- package/dist/apps/funding/routes/deposit-addresses.d.ts +2 -2
- package/dist/apps/funding/routes/providers.d.ts +13 -13
- package/dist/apps/funding/routes/transfers.d.ts +33 -33
- package/dist/apps/management/App.d.ts +793 -16
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +50 -50
- package/dist/apps/management/routes/faucet.d.ts +31 -31
- package/dist/apps/management/routes/invite-links.d.ts +42 -42
- package/dist/apps/management/routes/members.d.ts +79 -79
- package/dist/apps/management/routes/projects.d.ts +40 -40
- package/dist/apps/management/routes/usage.d.ts +80 -80
- package/dist/apps/management/routes/webhooks.d.ts +1031 -59
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/management/routes/webhooks.js +27 -4
- package/dist/apps/management/routes/webhooks.js.map +1 -1
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +21 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +7 -1
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +9 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/webhookQueueEvents.d.ts +3 -1
- package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
- package/dist/db/tables/webhookQueueEvents.js +4 -0
- package/dist/db/tables/webhookQueueEvents.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +33 -69
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +63 -100
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/MetricSink.d.ts +35 -125
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +50 -121
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/Schema.d.ts +3 -1
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +4 -2
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/WebhookTransfer.d.ts +1 -55
- package/dist/internal/WebhookTransfer.d.ts.map +1 -1
- package/dist/internal/WebhookTransfer.js +1 -239
- package/dist/internal/WebhookTransfer.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +83 -44
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +87 -73
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/funding/DepositWebhook.d.ts +25 -0
- package/dist/internal/funding/DepositWebhook.d.ts.map +1 -0
- package/dist/internal/funding/DepositWebhook.js +74 -0
- package/dist/internal/funding/DepositWebhook.js.map +1 -0
- package/dist/internal/funding/Reconciliation.d.ts +6 -0
- package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
- package/dist/internal/funding/Reconciliation.js +42 -10
- package/dist/internal/funding/Reconciliation.js.map +1 -1
- package/dist/internal/funding/index.d.ts +1 -0
- package/dist/internal/funding/index.d.ts.map +1 -1
- package/dist/internal/funding/index.js +1 -0
- package/dist/internal/funding/index.js.map +1 -1
- package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
- package/dist/internal/webhookDestinations/slack.js +16 -0
- package/dist/internal/webhookDestinations/slack.js.map +1 -1
- package/package.json +1 -1
- package/src/App.ts +3 -0
- package/src/Client.test-d.ts +22 -1
- package/src/Webhooks.ts +1 -220
- package/src/apps/data/App.ts +8 -2
- package/src/apps/data/routes/activities.test.ts +107 -11
- package/src/apps/data/routes/activities.ts +64 -32
- package/src/apps/data/routes/webhooks.test.ts +179 -1497
- package/src/apps/data/routes/webhooks.ts +150 -974
- package/src/apps/management/routes/webhooks.test.ts +79 -1
- package/src/apps/management/routes/webhooks.ts +40 -4
- package/src/db/Db.test.ts +1 -5
- package/src/db/Db.ts +23 -0
- package/src/db/Schema.ts +13 -0
- package/src/db/tables/organizations.test.ts +5 -2
- package/src/db/tables/webhookQueueEvents.ts +7 -1
- package/src/db/tables/webhookSubscriptions.ts +89 -138
- package/src/internal/MetricSink.test.ts +41 -373
- package/src/internal/MetricSink.ts +92 -273
- package/src/internal/Schema.test.ts +18 -0
- package/src/internal/Schema.ts +13 -2
- package/src/internal/WebhookTransfer.ts +1 -351
- package/src/internal/Webhooks.test.ts +102 -139
- package/src/internal/Webhooks.ts +175 -106
- package/src/internal/funding/DepositWebhook.test.ts +131 -0
- package/src/internal/funding/DepositWebhook.ts +101 -0
- package/src/internal/funding/Reconciliation.test.ts +14 -0
- package/src/internal/funding/Reconciliation.ts +161 -86
- package/src/internal/funding/index.test.ts +1 -0
- package/src/internal/funding/index.ts +1 -0
- package/src/internal/webhookDestinations/slack.ts +15 -0
- package/src/Webhooks.bench.ts +0 -714
- package/src/Webhooks.memory.bench.ts +0 -250
- package/src/Webhooks.test.ts +0 -146
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
/** @module-tag localnet */
|
|
2
|
-
/**
|
|
3
|
-
* Measures retained database-factory memory and dense transfer-scan allocations.
|
|
4
|
-
* Set `WEBHOOK_MEMORY_SNAPSHOT_DIR` to write V8 heap snapshots for retained objects.
|
|
5
|
-
*/
|
|
6
|
-
import * as fs from 'node:fs'
|
|
7
|
-
import * as path from 'node:path'
|
|
8
|
-
import * as v8 from 'node:v8'
|
|
9
|
-
import { nanoid } from 'nanoid'
|
|
10
|
-
import { sendTransactionSync } from 'viem/actions'
|
|
11
|
-
import { Actions, Addresses } from 'viem/tempo'
|
|
12
|
-
import { Webhooks } from 'tapimo'
|
|
13
|
-
import { bench } from 'vite-plus/test'
|
|
14
|
-
|
|
15
|
-
import * as Db from './db/Db.js'
|
|
16
|
-
import * as Cursor from './internal/Cursor.js'
|
|
17
|
-
import * as Runtime from '../test/runtime.js'
|
|
18
|
-
import * as TestApp from '../test/App.js'
|
|
19
|
-
import * as Tempo from '../test/Tempo.js'
|
|
20
|
-
import * as TestViem from '../test/Viem.js'
|
|
21
|
-
|
|
22
|
-
const batchSize = 200
|
|
23
|
-
const endOfBlockIndex = 2_147_483_647
|
|
24
|
-
const factoryTicks = positiveInteger('WEBHOOK_MEMORY_FACTORY_TICKS', 25)
|
|
25
|
-
const mebibyte = 1024 * 1024
|
|
26
|
-
const runtime = Runtime.get()
|
|
27
|
-
const transferCallsPerTransaction = 32
|
|
28
|
-
const transferCount = positiveInteger('WEBHOOK_MEMORY_TRANSFER_COUNT', 3_600)
|
|
29
|
-
|
|
30
|
-
type Memory = {
|
|
31
|
-
arrayBuffers: number
|
|
32
|
-
external: number
|
|
33
|
-
heapUsed: number
|
|
34
|
-
rss: number
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
type Report = {
|
|
38
|
-
after: Memory
|
|
39
|
-
afterOperation: Memory
|
|
40
|
-
afterOperationDelta: Memory
|
|
41
|
-
before: Memory
|
|
42
|
-
delta: Memory
|
|
43
|
-
details?: Record<string, number> | undefined
|
|
44
|
-
label: string
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const reports: Report[] = []
|
|
48
|
-
|
|
49
|
-
beforeAll(() => {
|
|
50
|
-
if (runtime.mode !== 'localnet')
|
|
51
|
-
throw new Error('Run webhook memory benchmarks with TEMPO_ENV=localnet.')
|
|
52
|
-
if (!globalThis.gc)
|
|
53
|
-
throw new Error('Run webhook memory benchmarks with NODE_OPTIONS=--expose-gc.')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
afterAll(() => {
|
|
57
|
-
process.stdout.write(`WEBHOOK_MEMORY_REPORT ${JSON.stringify(reports)}\n`)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
describe('webhook poller memory', () => {
|
|
61
|
-
bench(
|
|
62
|
-
`factory-created databases / ${factoryTicks} ticks`,
|
|
63
|
-
async () => {
|
|
64
|
-
reports.push(await measureFactoryRetention())
|
|
65
|
-
},
|
|
66
|
-
{ iterations: 1, time: 0, warmupIterations: 0, warmupTime: 0 },
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
bench(
|
|
70
|
-
`transfer firehose / ${transferCount} generated transfers`,
|
|
71
|
-
async () => {
|
|
72
|
-
reports.push(await measureTransferFirehose())
|
|
73
|
-
},
|
|
74
|
-
{ iterations: 1, time: 0, warmupIterations: 0, warmupTime: 0 },
|
|
75
|
-
)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
async function measureFactoryRetention(): Promise<Report> {
|
|
79
|
-
const databases: Db.Db[] = []
|
|
80
|
-
const schema = `memory_${nanoid()}`
|
|
81
|
-
const database = Db.postgres({ connectionString: Runtime.postgresUrl, schema })
|
|
82
|
-
await database.migrate()
|
|
83
|
-
await Webhooks.createSubscription(database, {
|
|
84
|
-
chainId: runtime.chainId,
|
|
85
|
-
destination: { type: 'url', url: 'https://hooks.example.com/bench/memory/factory' },
|
|
86
|
-
eventType: 'block:created',
|
|
87
|
-
owner: { orgId: 'org_benchmark', type: 'api_key' },
|
|
88
|
-
})
|
|
89
|
-
const headBlockNumber = Number(await TestViem.getClient().getBlockNumber())
|
|
90
|
-
const poller = Webhooks.createPoller({
|
|
91
|
-
db: () => {
|
|
92
|
-
const database = Db.postgres({ connectionString: Runtime.postgresUrl, schema })
|
|
93
|
-
databases.push(database)
|
|
94
|
-
return database
|
|
95
|
-
},
|
|
96
|
-
defaultChainId: runtime.chainId,
|
|
97
|
-
dispatchBatch: async () => ({ ok: true }),
|
|
98
|
-
rpc: TestApp.rpc,
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
const report = await measure('factory-retained', async () => {
|
|
103
|
-
for (let index = 0; index < factoryTicks; index++)
|
|
104
|
-
await poller.tick({
|
|
105
|
-
confirmations: 0,
|
|
106
|
-
eventTypes: ['block:created'],
|
|
107
|
-
headBlockNumber,
|
|
108
|
-
maxBlocks: 1,
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
writeHeapSnapshot('factory-retained')
|
|
112
|
-
return { ...report, details: { databases: databases.length, ticks: factoryTicks } }
|
|
113
|
-
} finally {
|
|
114
|
-
await Promise.allSettled(databases.map((database) => database.close()))
|
|
115
|
-
await database.close()
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function measureTransferFirehose(): Promise<Report> {
|
|
120
|
-
const database = TestApp.database()
|
|
121
|
-
const client = Tempo.getClient({ account: Tempo.accounts[0] })
|
|
122
|
-
const startBlockNumber = Number(await TestViem.getClient().getBlockNumber())
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
for (let offset = 0; offset < transferCount; offset += transferCallsPerTransaction) {
|
|
126
|
-
const length = Math.min(transferCallsPerTransaction, transferCount - offset)
|
|
127
|
-
await sendTransactionSync(client, {
|
|
128
|
-
account: Tempo.accounts[0],
|
|
129
|
-
calls: Array.from({ length }, () =>
|
|
130
|
-
Actions.token.transfer.call(client, {
|
|
131
|
-
amount: 1n,
|
|
132
|
-
to: Tempo.accounts[1].address,
|
|
133
|
-
token: Addresses.pathUsd,
|
|
134
|
-
}),
|
|
135
|
-
),
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const headBlockNumber = Number(await TestViem.getClient().getBlockNumber())
|
|
140
|
-
const subscription = await Webhooks.createSubscription(database, {
|
|
141
|
-
chainId: runtime.chainId,
|
|
142
|
-
destination: { type: 'url', url: 'https://hooks.example.com/bench/memory/firehose' },
|
|
143
|
-
eventType: 'token:transfer',
|
|
144
|
-
filters: {},
|
|
145
|
-
owner: { orgId: 'org_benchmark', type: 'api_key' },
|
|
146
|
-
})
|
|
147
|
-
await Webhooks.setCursor(
|
|
148
|
-
database,
|
|
149
|
-
subscription.id,
|
|
150
|
-
Cursor.encode([startBlockNumber, endOfBlockIndex]),
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
let dispatched = 0
|
|
154
|
-
let serializedBytes = 0
|
|
155
|
-
const poller = Webhooks.createPoller({
|
|
156
|
-
db: database,
|
|
157
|
-
defaultChainId: runtime.chainId,
|
|
158
|
-
dispatchBatch: async (dispatchables) => {
|
|
159
|
-
dispatched += dispatchables.length
|
|
160
|
-
for (const body of dispatchables)
|
|
161
|
-
serializedBytes += new TextEncoder().encode(JSON.stringify({ body })).byteLength
|
|
162
|
-
return { ok: true }
|
|
163
|
-
},
|
|
164
|
-
rpc: TestApp.rpc,
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
const report = await measure('transfer-firehose', async () => {
|
|
168
|
-
const result = await poller.tick({
|
|
169
|
-
batchSize,
|
|
170
|
-
confirmations: 0,
|
|
171
|
-
eventTypes: ['token:transfer'],
|
|
172
|
-
headBlockNumber,
|
|
173
|
-
maxBlocks: 500,
|
|
174
|
-
})
|
|
175
|
-
if (result.dispatched === 0 || result.dispatched !== dispatched)
|
|
176
|
-
throw new Error(`Unexpected dispatch count: ${result.dispatched} / ${dispatched}.`)
|
|
177
|
-
if (result.dispatched > batchSize)
|
|
178
|
-
throw new Error(`Dispatch count ${result.dispatched} exceeded batch size ${batchSize}.`)
|
|
179
|
-
if (serializedBytes === 0) throw new Error('Expected serialized webhook queue messages.')
|
|
180
|
-
})
|
|
181
|
-
writeHeapSnapshot('transfer-firehose-retained')
|
|
182
|
-
return {
|
|
183
|
-
...report,
|
|
184
|
-
details: { dispatched, serializedBytes, transferCount },
|
|
185
|
-
}
|
|
186
|
-
} finally {
|
|
187
|
-
await database.close()
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async function measure(label: string, fn: () => Promise<void>): Promise<Report> {
|
|
192
|
-
collectGarbage()
|
|
193
|
-
const before = memoryUsage()
|
|
194
|
-
await fn()
|
|
195
|
-
const afterOperation = memoryUsage()
|
|
196
|
-
collectGarbage()
|
|
197
|
-
const after = memoryUsage()
|
|
198
|
-
return {
|
|
199
|
-
after,
|
|
200
|
-
afterOperation,
|
|
201
|
-
afterOperationDelta: subtract(afterOperation, before),
|
|
202
|
-
before,
|
|
203
|
-
delta: subtract(after, before),
|
|
204
|
-
label,
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function collectGarbage(): void {
|
|
209
|
-
globalThis.gc?.()
|
|
210
|
-
globalThis.gc?.()
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function memoryUsage(): Memory {
|
|
214
|
-
const usage = process.memoryUsage()
|
|
215
|
-
return {
|
|
216
|
-
arrayBuffers: mebibytes(usage.arrayBuffers),
|
|
217
|
-
external: mebibytes(usage.external),
|
|
218
|
-
heapUsed: mebibytes(usage.heapUsed),
|
|
219
|
-
rss: mebibytes(usage.rss),
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function mebibytes(bytes: number): number {
|
|
224
|
-
return Math.round((bytes / mebibyte) * 100) / 100
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function positiveInteger(name: string, fallback: number): number {
|
|
228
|
-
const input = process.env[name]
|
|
229
|
-
if (!input) return fallback
|
|
230
|
-
const value = Number(input)
|
|
231
|
-
if (!Number.isSafeInteger(value) || value < 1)
|
|
232
|
-
throw new Error(`${name} must be a positive integer.`)
|
|
233
|
-
return value
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function subtract(after: Memory, before: Memory): Memory {
|
|
237
|
-
return {
|
|
238
|
-
arrayBuffers: after.arrayBuffers - before.arrayBuffers,
|
|
239
|
-
external: after.external - before.external,
|
|
240
|
-
heapUsed: after.heapUsed - before.heapUsed,
|
|
241
|
-
rss: after.rss - before.rss,
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function writeHeapSnapshot(label: string): void {
|
|
246
|
-
const directory = process.env.WEBHOOK_MEMORY_SNAPSHOT_DIR
|
|
247
|
-
if (!directory) return
|
|
248
|
-
fs.mkdirSync(directory, { recursive: true })
|
|
249
|
-
v8.writeHeapSnapshot(path.join(directory, `${label}.heapsnapshot`))
|
|
250
|
-
}
|
package/src/Webhooks.test.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { Metrics, Webhooks } from 'tapimo'
|
|
2
|
-
import * as TestApp from '../test/App.js'
|
|
3
|
-
|
|
4
|
-
describe('createPoller', () => {
|
|
5
|
-
/** Decodes the opaque `(block, index)` keyset cursor the poller stores. */
|
|
6
|
-
function decodeCursor(token: string | null): [number, number] | null {
|
|
7
|
-
if (!token) return null
|
|
8
|
-
const json = atob(token.replaceAll('-', '+').replaceAll('_', '/'))
|
|
9
|
-
return JSON.parse(json) as [number, number]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
test('binds a database and runs a tick at an injected head', async () => {
|
|
13
|
-
const db = TestApp.database()
|
|
14
|
-
const subscription = await Webhooks.createSubscription(db, {
|
|
15
|
-
chainId: 42431,
|
|
16
|
-
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
17
|
-
eventType: 'token:transfer',
|
|
18
|
-
owner: { orgId: 'org_test', type: 'api_key' },
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
const poller = Webhooks.createPoller({
|
|
22
|
-
db,
|
|
23
|
-
defaultChainId: 42431,
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
// A brand-new subscription anchors at the confirmed head on its first tick
|
|
27
|
-
// (no backfill), so this exercises the createPoller → poll wiring (db
|
|
28
|
-
// binding, default chain id, injected head, and result shape) without an
|
|
29
|
-
// upstream request. Detailed scanner behavior lives in the route test.
|
|
30
|
-
const result = await poller.tick({ headBlockNumber: 200 })
|
|
31
|
-
|
|
32
|
-
expect(result).toMatchInlineSnapshot(`
|
|
33
|
-
{
|
|
34
|
-
"chainId": 42431,
|
|
35
|
-
"dispatched": 0,
|
|
36
|
-
"failed": 0,
|
|
37
|
-
"safeBlock": 199,
|
|
38
|
-
"scanned": 0,
|
|
39
|
-
"subscriptions": 1,
|
|
40
|
-
}
|
|
41
|
-
`)
|
|
42
|
-
expect(decodeCursor(await Webhooks.getCursor(db, subscription.id))).toMatchInlineSnapshot(`
|
|
43
|
-
[
|
|
44
|
-
199,
|
|
45
|
-
2147483647,
|
|
46
|
-
]
|
|
47
|
-
`)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('records active subscriptions before scanning', async () => {
|
|
51
|
-
const db = TestApp.database()
|
|
52
|
-
await Webhooks.createSubscription(db, {
|
|
53
|
-
chainId: 42431,
|
|
54
|
-
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
55
|
-
eventType: 'block:created',
|
|
56
|
-
owner: { orgId: 'org_test', type: 'api_key' },
|
|
57
|
-
})
|
|
58
|
-
const gauges: { name: string; tags: Metrics.Tags; value: number }[] = []
|
|
59
|
-
const poller = Webhooks.createPoller({
|
|
60
|
-
db,
|
|
61
|
-
defaultChainId: 42431,
|
|
62
|
-
metrics: Metrics.from({
|
|
63
|
-
count() {},
|
|
64
|
-
flush() {},
|
|
65
|
-
gauge(name, value, tags = {}) {
|
|
66
|
-
gauges.push({ name, tags, value })
|
|
67
|
-
},
|
|
68
|
-
histogram() {},
|
|
69
|
-
}),
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
await poller.tick({ eventTypes: ['block:created'], headBlockNumber: 200 })
|
|
73
|
-
|
|
74
|
-
expect(gauges).toMatchInlineSnapshot(`
|
|
75
|
-
[
|
|
76
|
-
{
|
|
77
|
-
"name": "webhook_poller_active_subscription_count",
|
|
78
|
-
"tags": {
|
|
79
|
-
"chain_id": "42431",
|
|
80
|
-
},
|
|
81
|
-
"value": 1,
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"name": "webhook_subscription_cursor_lag_blocks",
|
|
85
|
-
"tags": {
|
|
86
|
-
"chain_id": "42431",
|
|
87
|
-
},
|
|
88
|
-
"value": 0,
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
"name": "webhook_poller_safe_block",
|
|
92
|
-
"tags": {
|
|
93
|
-
"chain_id": "42431",
|
|
94
|
-
},
|
|
95
|
-
"value": 199,
|
|
96
|
-
},
|
|
97
|
-
]
|
|
98
|
-
`)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
test('clamps a creation checkpoint to genesis', async () => {
|
|
102
|
-
const db = TestApp.database()
|
|
103
|
-
const subscription = await Webhooks.createSubscription(
|
|
104
|
-
db,
|
|
105
|
-
{
|
|
106
|
-
chainId: 42431,
|
|
107
|
-
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
108
|
-
eventType: 'block:created',
|
|
109
|
-
owner: { orgId: 'org_test', type: 'api_key' },
|
|
110
|
-
},
|
|
111
|
-
{ startBlockNumber: 1 },
|
|
112
|
-
)
|
|
113
|
-
const poller = Webhooks.createPoller({
|
|
114
|
-
db,
|
|
115
|
-
defaultChainId: 42431,
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
await poller.tick({
|
|
119
|
-
eventTypes: ['block:created'],
|
|
120
|
-
headBlockNumber: 1,
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
expect(decodeCursor(await Webhooks.getCursor(db, subscription.id))).toEqual([0, 2_147_483_647])
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
test('keeps a factory-created database open after each tick', async () => {
|
|
127
|
-
const db = TestApp.database()
|
|
128
|
-
await Webhooks.createSubscription(db, {
|
|
129
|
-
chainId: 42431,
|
|
130
|
-
destination: { type: 'url', url: 'https://hooks.example.com/x' },
|
|
131
|
-
eventType: 'block:created',
|
|
132
|
-
owner: { orgId: 'org_test', type: 'api_key' },
|
|
133
|
-
})
|
|
134
|
-
const poller = Webhooks.createPoller({
|
|
135
|
-
db: () => db,
|
|
136
|
-
defaultChainId: 42431,
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
await poller.tick({
|
|
140
|
-
eventTypes: ['block:created'],
|
|
141
|
-
headBlockNumber: 1,
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
await expect(Webhooks.maxCursorBlock(db, 42431)).resolves.toBe(0)
|
|
145
|
-
})
|
|
146
|
-
})
|