tapimo 0.10.1 → 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 +5249 -3572
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -76
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +2 -144
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +74 -74
- 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/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +206 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +4 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +2 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- 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 +7 -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/balances.d.ts +11 -11
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +2 -6
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +5 -5
- package/dist/apps/data/routes/earn.d.ts +4 -4
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +63 -34
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +8 -4
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +115 -77
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +26 -26
- package/dist/apps/data/routes/receipts.d.ts +240 -239
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +15 -14
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +12 -12
- package/dist/apps/data/routes/tokens.d.ts +4 -4
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +4 -3
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +282 -282
- package/dist/apps/data/routes/transfers.d.ts +13 -13
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +25 -7
- package/dist/apps/data/routes/transfers.js.map +1 -1
- 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 +1519 -643
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +134 -740
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +3 -3
- package/dist/apps/funding/App.d.ts +233 -0
- package/dist/apps/funding/App.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts +331 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.js +207 -11
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
- 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 +2 -2
- package/dist/apps/management/routes/invite-links.d.ts +42 -42
- package/dist/apps/management/routes/members.d.ts +2 -2
- package/dist/apps/management/routes/projects.d.ts +40 -40
- 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 +53 -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/fundingDepositAddresses.d.ts +20 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
- package/dist/db/tables/fundingDepositAddresses.js +17 -0
- package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
- package/dist/db/tables/fundingDeposits.d.ts +41 -0
- package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
- package/dist/db/tables/fundingDeposits.js +69 -0
- package/dist/db/tables/fundingDeposits.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/Auth.d.ts +0 -26
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +0 -33
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Credential.d.ts +27 -0
- package/dist/internal/Credential.d.ts.map +1 -0
- package/dist/internal/Credential.js +34 -0
- package/dist/internal/Credential.js.map +1 -0
- package/dist/internal/EarnRates.js +11 -7
- package/dist/internal/EarnRates.js.map +1 -1
- package/dist/internal/Log.d.ts +8 -0
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +4 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts +50 -116
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +60 -106
- 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/Tidx.d.ts +4 -3
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +2 -2
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Viem.d.ts +4 -3
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +3 -2
- package/dist/internal/Viem.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 +85 -44
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +94 -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/index.d.ts +1 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -0
- package/dist/internal/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.test.ts +30 -0
- package/src/App.ts +3 -0
- package/src/Client.test-d.ts +55 -2
- package/src/Webhooks.ts +2 -221
- package/src/analytics/Analytics.test.ts +34 -0
- package/src/analytics/Analytics.ts +206 -0
- package/src/analytics/tables/requestEvents.ts +6 -0
- package/src/apps/composition.test.ts +1 -0
- package/src/apps/data/App.ts +10 -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/balances.ts +2 -6
- package/src/apps/data/routes/earn.ts +64 -34
- package/src/apps/data/routes/exchanges.test.ts +8 -3
- package/src/apps/data/routes/exchanges.ts +134 -82
- package/src/apps/data/routes/receipts.ts +16 -14
- package/src/apps/data/routes/tokens.ts +3 -2
- package/src/apps/data/routes/transactions.bench.ts +8 -0
- package/src/apps/data/routes/transfers.ts +36 -10
- package/src/apps/data/routes/webhooks.test.ts +179 -1497
- package/src/apps/data/routes/webhooks.ts +172 -975
- package/src/apps/funding/routes/deposit-addresses.test.ts +216 -2
- package/src/apps/funding/routes/deposit-addresses.ts +254 -18
- package/src/apps/funding/routes/transfers.test.ts +17 -2
- 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 +59 -0
- package/src/db/Schema.ts +13 -0
- package/src/db/tables/fundingDepositAddresses.test.ts +28 -0
- package/src/db/tables/fundingDepositAddresses.ts +39 -0
- package/src/db/tables/fundingDeposits.test.ts +82 -0
- package/src/db/tables/fundingDeposits.ts +130 -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/Auth.test.ts +0 -48
- package/src/internal/Auth.ts +0 -59
- package/src/internal/Credential.test.ts +51 -0
- package/src/internal/Credential.ts +58 -0
- package/src/internal/EarnRates.ts +13 -7
- package/src/internal/Log.test.ts +3 -1
- package/src/internal/Log.ts +14 -0
- package/src/internal/MetricSink.test.ts +75 -358
- package/src/internal/MetricSink.ts +117 -246
- package/src/internal/Schema.test.ts +18 -0
- package/src/internal/Schema.ts +13 -2
- package/src/internal/Tidx.ts +5 -4
- package/src/internal/Viem.test.ts +4 -0
- package/src/internal/Viem.ts +6 -4
- package/src/internal/WebhookTransfer.ts +1 -351
- package/src/internal/Webhooks.test.ts +111 -139
- package/src/internal/Webhooks.ts +181 -105
- 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/index.test.ts +1 -0
- package/src/internal/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,6 +1,7 @@
|
|
|
1
1
|
import type { ExpressionBuilder, Selectable } from 'kysely'
|
|
2
2
|
import { sql } from 'kysely'
|
|
3
3
|
|
|
4
|
+
import * as Scope from '../../Scope.js'
|
|
4
5
|
import type * as Webhooks from '../../internal/Webhooks.js'
|
|
5
6
|
import type * as Db from '../Db.js'
|
|
6
7
|
import type * as db_Schema from '../Schema.js'
|
|
@@ -40,6 +41,7 @@ export function toSubscription(row: Record): Webhooks.Subscription {
|
|
|
40
41
|
...(row.context === null ? {} : { context: row.context }),
|
|
41
42
|
createdAt: row.createdAt,
|
|
42
43
|
destination: row.destination,
|
|
44
|
+
...(row.environment === null ? {} : { environment: row.environment }),
|
|
43
45
|
eventType: row.eventType,
|
|
44
46
|
...(row.expiresAt === null ? {} : { expiresAt: row.expiresAt }),
|
|
45
47
|
failureCount: row.failureCount,
|
|
@@ -50,6 +52,7 @@ export function toSubscription(row: Record): Webhooks.Subscription {
|
|
|
50
52
|
row.ownerType === 'api_key'
|
|
51
53
|
? { orgId: row.ownerId, type: 'api_key' }
|
|
52
54
|
: { payer: row.ownerId, type: 'mpp' },
|
|
55
|
+
...(row.projectId === null ? {} : { projectId: row.projectId }),
|
|
53
56
|
secret: row.secret,
|
|
54
57
|
status: row.status,
|
|
55
58
|
updatedAt: row.updatedAt,
|
|
@@ -75,6 +78,7 @@ export async function insert(
|
|
|
75
78
|
context: subscription.context ?? null,
|
|
76
79
|
createdAt: subscription.createdAt,
|
|
77
80
|
destination: subscription.destination,
|
|
81
|
+
environment: subscription.environment ?? null,
|
|
78
82
|
eventType: subscription.eventType,
|
|
79
83
|
expiresAt: subscription.expiresAt ?? null,
|
|
80
84
|
failureCount: subscription.failureCount,
|
|
@@ -84,6 +88,7 @@ export async function insert(
|
|
|
84
88
|
ownerId: ownerId(subscription.owner),
|
|
85
89
|
ownerType: subscription.owner.type,
|
|
86
90
|
pollerCursor: options.pollerCursor ?? null,
|
|
91
|
+
projectId: subscription.projectId ?? null,
|
|
87
92
|
secret: subscription.secret,
|
|
88
93
|
status: subscription.status,
|
|
89
94
|
updatedAt: subscription.updatedAt,
|
|
@@ -94,7 +99,7 @@ export async function insert(
|
|
|
94
99
|
export declare namespace insert {
|
|
95
100
|
/** Options for {@link insert}. */
|
|
96
101
|
type Options = {
|
|
97
|
-
/** Initial
|
|
102
|
+
/** Initial cursor committed with the subscription. */
|
|
98
103
|
pollerCursor?: string | undefined
|
|
99
104
|
}
|
|
100
105
|
}
|
|
@@ -129,7 +134,7 @@ export declare namespace insertWithinLimit {
|
|
|
129
134
|
maxPerOwner: number
|
|
130
135
|
/** ISO timestamp used to exclude expired rows from the count. */
|
|
131
136
|
now: string
|
|
132
|
-
/** Initial
|
|
137
|
+
/** Initial cursor committed with the subscription. */
|
|
133
138
|
pollerCursor?: string | undefined
|
|
134
139
|
}
|
|
135
140
|
}
|
|
@@ -149,15 +154,17 @@ export async function get(
|
|
|
149
154
|
owner: Webhooks.Owner,
|
|
150
155
|
id: string,
|
|
151
156
|
now: string,
|
|
157
|
+
access?: Webhooks.Access,
|
|
152
158
|
): Promise<Webhooks.Subscription | null> {
|
|
153
|
-
|
|
159
|
+
let query = db.kysely
|
|
154
160
|
.selectFrom('webhook_subscriptions')
|
|
155
161
|
.selectAll()
|
|
156
162
|
.where('id', '=', id)
|
|
157
163
|
.where('ownerType', '=', owner.type)
|
|
158
164
|
.where('ownerId', '=', ownerId(owner))
|
|
159
165
|
.where(live(now))
|
|
160
|
-
|
|
166
|
+
if (access) query = query.where(privateResourceAccess(access))
|
|
167
|
+
const row = await query.executeTakeFirst()
|
|
161
168
|
return row ? toSubscription(row) : null
|
|
162
169
|
}
|
|
163
170
|
|
|
@@ -183,6 +190,7 @@ export async function list(
|
|
|
183
190
|
.where('ownerId', '=', ownerId(owner))
|
|
184
191
|
.where(live(options.now))
|
|
185
192
|
.orderBy('id', 'desc')
|
|
193
|
+
if (options.access) query = query.where(privateResourceAccess(options.access))
|
|
186
194
|
if (options.cursor) query = query.where('id', '<', options.cursor)
|
|
187
195
|
if (options.offset) query = query.offset(options.offset)
|
|
188
196
|
if (options.limit !== undefined) query = query.limit(options.limit)
|
|
@@ -192,6 +200,8 @@ export async function list(
|
|
|
192
200
|
export declare namespace list {
|
|
193
201
|
/** Options for {@link list}. */
|
|
194
202
|
type Options = {
|
|
203
|
+
/** Private-resource visibility scope. */
|
|
204
|
+
access?: Webhooks.Access | undefined
|
|
195
205
|
/** Return subscriptions older than this id (keyset paging, newest first). */
|
|
196
206
|
cursor?: string | undefined
|
|
197
207
|
/** Maximum subscriptions to return. */
|
|
@@ -211,14 +221,20 @@ export declare namespace list {
|
|
|
211
221
|
* @param now - ISO timestamp expiry is evaluated against.
|
|
212
222
|
* @returns The count.
|
|
213
223
|
*/
|
|
214
|
-
export async function count(
|
|
215
|
-
|
|
224
|
+
export async function count(
|
|
225
|
+
db: Db.Db,
|
|
226
|
+
owner: Webhooks.Owner,
|
|
227
|
+
now: string,
|
|
228
|
+
access?: Webhooks.Access,
|
|
229
|
+
): Promise<number> {
|
|
230
|
+
let query = db.kysely
|
|
216
231
|
.selectFrom('webhook_subscriptions')
|
|
217
232
|
.select((eb) => eb.fn.countAll().as('count'))
|
|
218
233
|
.where('ownerType', '=', owner.type)
|
|
219
234
|
.where('ownerId', '=', ownerId(owner))
|
|
220
235
|
.where(live(now))
|
|
221
|
-
|
|
236
|
+
if (access) query = query.where(privateResourceAccess(access))
|
|
237
|
+
const row = await query.executeTakeFirstOrThrow()
|
|
222
238
|
return Number(row.count)
|
|
223
239
|
}
|
|
224
240
|
|
|
@@ -275,21 +291,42 @@ export async function remove(
|
|
|
275
291
|
owner: Webhooks.Owner,
|
|
276
292
|
id: string,
|
|
277
293
|
now: string,
|
|
294
|
+
access?: Webhooks.Access,
|
|
278
295
|
): Promise<boolean> {
|
|
279
|
-
|
|
296
|
+
let query = db.kysely
|
|
280
297
|
.deleteFrom('webhook_subscriptions')
|
|
281
298
|
.where('id', '=', id)
|
|
282
299
|
.where('ownerType', '=', owner.type)
|
|
283
300
|
.where('ownerId', '=', ownerId(owner))
|
|
284
301
|
.where(live(now))
|
|
285
|
-
|
|
302
|
+
if (access) query = query.where(privateResourceAccess(access))
|
|
303
|
+
const result = await query.executeTakeFirst()
|
|
286
304
|
return result.numDeletedRows > 0n
|
|
287
305
|
}
|
|
288
306
|
|
|
307
|
+
function privateResourceAccess(access: Webhooks.Access) {
|
|
308
|
+
const fundingRead = access.scopes.some(
|
|
309
|
+
(scope) => scope === Scope.wildcard || scope === 'funding:read',
|
|
310
|
+
)
|
|
311
|
+
return (eb: ExpressionBuilder<Db.Database, 'webhook_subscriptions'>) =>
|
|
312
|
+
eb.or([
|
|
313
|
+
eb('eventType', '!=', 'funding:deposit.updated'),
|
|
314
|
+
...(fundingRead
|
|
315
|
+
? [
|
|
316
|
+
eb.and([
|
|
317
|
+
eb('eventType', '=', 'funding:deposit.updated'),
|
|
318
|
+
eb('environment', '=', access.environment),
|
|
319
|
+
...(access.projectId === undefined ? [] : [eb('projectId', '=', access.projectId)]),
|
|
320
|
+
]),
|
|
321
|
+
]
|
|
322
|
+
: []),
|
|
323
|
+
])
|
|
324
|
+
}
|
|
325
|
+
|
|
289
326
|
/**
|
|
290
|
-
* Lists live `active` subscriptions for a `(chainId, eventType)` stream
|
|
291
|
-
*
|
|
292
|
-
*
|
|
327
|
+
* Lists live `active` subscriptions for a `(chainId, eventType)` stream,
|
|
328
|
+
* served by the partial status index. Each row carries its cursor so callers
|
|
329
|
+
* avoid a per-subscription read.
|
|
293
330
|
*
|
|
294
331
|
* @param db - The database.
|
|
295
332
|
* @param chainId - Chain the stream belongs to.
|
|
@@ -316,8 +353,8 @@ export async function listActive(
|
|
|
316
353
|
}
|
|
317
354
|
|
|
318
355
|
/**
|
|
319
|
-
* Lists every live `active` subscription on a chain in one read.
|
|
320
|
-
*
|
|
356
|
+
* Lists every live `active` subscription on a chain in one read. Callers
|
|
357
|
+
* group the rows by event type so empty streams cost no extra database reads.
|
|
321
358
|
*
|
|
322
359
|
* @param db - The database.
|
|
323
360
|
* @param options - Chain, configured event types, and expiry time.
|
|
@@ -342,43 +379,58 @@ export async function listActiveForChain(
|
|
|
342
379
|
}
|
|
343
380
|
|
|
344
381
|
export declare namespace listActiveForChain {
|
|
345
|
-
/** Filters for the
|
|
382
|
+
/** Filters for the chain-level subscription read. */
|
|
346
383
|
type Options = {
|
|
347
384
|
/** Chain whose subscriptions to read. */
|
|
348
385
|
chainId: number
|
|
349
|
-
/** Event types
|
|
386
|
+
/** Event types eligible for the read. */
|
|
350
387
|
eventTypes: readonly Webhooks.EventType[]
|
|
351
388
|
/** ISO timestamp expiry is evaluated against. */
|
|
352
389
|
now: string
|
|
353
390
|
}
|
|
354
391
|
}
|
|
355
392
|
|
|
356
|
-
/**
|
|
357
|
-
|
|
358
|
-
* across event types. Feeds the cron's cursor-freshness fallback gate.
|
|
359
|
-
*
|
|
360
|
-
* @param db - The database.
|
|
361
|
-
* @param chainId - Chain whose cursors to read.
|
|
362
|
-
* @param now - ISO timestamp expiry is evaluated against.
|
|
363
|
-
* @returns The non-null cursors, unordered.
|
|
364
|
-
*/
|
|
365
|
-
export async function listActiveCursors(
|
|
393
|
+
/** Lists live funding deposit subscriptions visible to one deposit owner. */
|
|
394
|
+
export async function listActiveForFundingDeposit(
|
|
366
395
|
db: Db.Db,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const rows = await db.kysely
|
|
396
|
+
options: listActiveForFundingDeposit.Options,
|
|
397
|
+
): Promise<Webhooks.Subscription[]> {
|
|
398
|
+
let query = db.kysely
|
|
371
399
|
.selectFrom('webhook_subscriptions')
|
|
372
|
-
.
|
|
373
|
-
.where('chainId', '=', chainId)
|
|
400
|
+
.selectAll()
|
|
401
|
+
.where('chainId', '=', options.chainId)
|
|
402
|
+
.where('environment', '=', options.environment)
|
|
403
|
+
.where('eventType', '=', 'funding:deposit.updated')
|
|
404
|
+
.where('ownerId', '=', options.orgId)
|
|
405
|
+
.where('ownerType', '=', 'api_key')
|
|
374
406
|
.where('status', '=', 'active')
|
|
375
|
-
.where(live(now))
|
|
376
|
-
|
|
377
|
-
|
|
407
|
+
.where(live(options.now))
|
|
408
|
+
const projectId = options.projectId
|
|
409
|
+
query =
|
|
410
|
+
projectId === undefined
|
|
411
|
+
? query.where('projectId', 'is', null)
|
|
412
|
+
: query.where((eb) => eb.or([eb('projectId', 'is', null), eb('projectId', '=', projectId)]))
|
|
413
|
+
return (await query.orderBy('id').execute()).map(toSubscription)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export declare namespace listActiveForFundingDeposit {
|
|
417
|
+
/** Ownership scope and chain for a funding deposit event. */
|
|
418
|
+
type Options = {
|
|
419
|
+
/** Destination Tempo chain id. */
|
|
420
|
+
chainId: number
|
|
421
|
+
/** Deposit API-key environment. */
|
|
422
|
+
environment: 'production' | 'sandbox'
|
|
423
|
+
/** ISO timestamp used to exclude expired subscriptions. */
|
|
424
|
+
now: string
|
|
425
|
+
/** Owning organization id. */
|
|
426
|
+
orgId: string
|
|
427
|
+
/** Attributed deposit project, when present. */
|
|
428
|
+
projectId?: string | undefined
|
|
429
|
+
}
|
|
378
430
|
}
|
|
379
431
|
|
|
380
432
|
/**
|
|
381
|
-
* Reads a subscription's
|
|
433
|
+
* Reads a subscription's keyset cursor.
|
|
382
434
|
*
|
|
383
435
|
* @param db - The database.
|
|
384
436
|
* @param id - The subscription id (`wh_…`).
|
|
@@ -393,107 +445,6 @@ export async function getCursor(db: Db.Db, id: string): Promise<string | null> {
|
|
|
393
445
|
return row?.pollerCursor ?? null
|
|
394
446
|
}
|
|
395
447
|
|
|
396
|
-
/**
|
|
397
|
-
* Writes a subscription's poller cursor. Deliberately does not touch
|
|
398
|
-
* `updatedAt` — the cursor advances every tick and is not a user mutation.
|
|
399
|
-
*
|
|
400
|
-
* @param db - The database.
|
|
401
|
-
* @param id - The subscription id (`wh_…`).
|
|
402
|
-
* @param cursor - The keyset cursor to store.
|
|
403
|
-
*/
|
|
404
|
-
export async function setCursor(db: Db.Db, id: string, cursor: string): Promise<void> {
|
|
405
|
-
await db.kysely
|
|
406
|
-
.updateTable('webhook_subscriptions')
|
|
407
|
-
.set({ pollerCursor: cursor })
|
|
408
|
-
.where('id', '=', id)
|
|
409
|
-
.execute()
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Writes a poller cursor only when the stored cursor still matches the caller's
|
|
414
|
-
* observed value.
|
|
415
|
-
*
|
|
416
|
-
* @param db - The database.
|
|
417
|
-
* @param options - Subscription, expected cursor, and next cursor.
|
|
418
|
-
* @returns Whether the cursor was updated.
|
|
419
|
-
*/
|
|
420
|
-
export async function compareAndSetCursor(
|
|
421
|
-
db: Db.Db,
|
|
422
|
-
options: compareAndSetCursor.Options,
|
|
423
|
-
): Promise<boolean> {
|
|
424
|
-
let query = db.kysely
|
|
425
|
-
.updateTable('webhook_subscriptions')
|
|
426
|
-
.set({ pollerCursor: options.cursor })
|
|
427
|
-
.where('id', '=', options.subscriptionId)
|
|
428
|
-
query =
|
|
429
|
-
options.expectedCursor === null
|
|
430
|
-
? query.where('pollerCursor', 'is', null)
|
|
431
|
-
: query.where('pollerCursor', '=', options.expectedCursor)
|
|
432
|
-
const result = await query.executeTakeFirst()
|
|
433
|
-
return result.numUpdatedRows > 0n
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
export declare namespace compareAndSetCursor {
|
|
437
|
-
/** Options for {@link compareAndSetCursor}. */
|
|
438
|
-
type Options = {
|
|
439
|
-
/** Next keyset cursor. */
|
|
440
|
-
cursor: string
|
|
441
|
-
/** Cursor observed before scanning, or null for an uninitialized subscription. */
|
|
442
|
-
expectedCursor: string | null
|
|
443
|
-
/** Subscription whose cursor advances. */
|
|
444
|
-
subscriptionId: string
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* Writes multiple poller cursors when each stored value still matches the
|
|
450
|
-
* caller's observed value.
|
|
451
|
-
*
|
|
452
|
-
* @param db - The database.
|
|
453
|
-
* @param options - Candidate cursor writes.
|
|
454
|
-
* @returns Subscription ids whose cursors were updated.
|
|
455
|
-
*/
|
|
456
|
-
export async function compareAndSetCursors(
|
|
457
|
-
db: Db.Db,
|
|
458
|
-
options: compareAndSetCursors.Options,
|
|
459
|
-
): Promise<Set<string>> {
|
|
460
|
-
if (options.cursors.length === 0) return new Set()
|
|
461
|
-
const values = JSON.stringify(options.cursors)
|
|
462
|
-
type Candidate = {
|
|
463
|
-
cursor: string
|
|
464
|
-
expectedCursor: string | null
|
|
465
|
-
subscriptionId: string
|
|
466
|
-
}
|
|
467
|
-
const result = await db.kysely
|
|
468
|
-
.with(
|
|
469
|
-
'candidates',
|
|
470
|
-
() => sql<Candidate>`(
|
|
471
|
-
SELECT
|
|
472
|
-
candidate."subscriptionId" AS subscription_id,
|
|
473
|
-
candidate."expectedCursor" AS expected_cursor,
|
|
474
|
-
candidate.cursor
|
|
475
|
-
FROM jsonb_to_recordset(${values}::jsonb)
|
|
476
|
-
AS candidate("subscriptionId" text, "expectedCursor" text, cursor text)
|
|
477
|
-
)`,
|
|
478
|
-
)
|
|
479
|
-
.updateTable('webhook_subscriptions as subscription')
|
|
480
|
-
.from('candidates as candidate')
|
|
481
|
-
.set((eb) => ({ pollerCursor: eb.ref('candidate.cursor') }))
|
|
482
|
-
.whereRef('subscription.id', '=', 'candidate.subscriptionId')
|
|
483
|
-
.whereRef('subscription.pollerCursor', 'is not distinct from', 'candidate.expectedCursor')
|
|
484
|
-
.returning('subscription.id as subscriptionId')
|
|
485
|
-
.execute()
|
|
486
|
-
return new Set(result.map((row) => row.subscriptionId))
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
export declare namespace compareAndSetCursors {
|
|
490
|
-
/** Options for {@link compareAndSetCursors}. */
|
|
491
|
-
type Options = {
|
|
492
|
-
/** Candidate cursor writes. */
|
|
493
|
-
cursors: readonly compareAndSetCursor.Options[]
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
448
|
/**
|
|
498
449
|
* Records a successful delivery: resets the consecutive-failure counter and
|
|
499
450
|
* stamps `lastDeliveryAt`.
|
|
@@ -549,7 +500,7 @@ export async function recordFailure(
|
|
|
549
500
|
|
|
550
501
|
/**
|
|
551
502
|
* Deletes expired subscriptions (their delivery rows cascade). Called
|
|
552
|
-
* best-effort
|
|
503
|
+
* best-effort on a schedule.
|
|
553
504
|
*
|
|
554
505
|
* @param db - The database.
|
|
555
506
|
* @param now - ISO timestamp expiry is evaluated against.
|
|
@@ -2100,54 +2100,6 @@ describe('ensureProject', () => {
|
|
|
2100
2100
|
})
|
|
2101
2101
|
})
|
|
2102
2102
|
|
|
2103
|
-
describe('parseCredential', () => {
|
|
2104
|
-
test('parses credentials keyed by chain id', () => {
|
|
2105
|
-
const credential = Auth.parseCredential(
|
|
2106
|
-
JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone:secret' }),
|
|
2107
|
-
)
|
|
2108
|
-
|
|
2109
|
-
expect(credential).toEqual({ 4217: 'mainnet:secret', 421700001: 'zone:secret' })
|
|
2110
|
-
})
|
|
2111
|
-
|
|
2112
|
-
test('supports a shared credential', () => {
|
|
2113
|
-
expect(Auth.parseCredential('shared:secret')).toBe('shared:secret')
|
|
2114
|
-
})
|
|
2115
|
-
|
|
2116
|
-
test('rejects malformed credential maps', () => {
|
|
2117
|
-
expect(() => Auth.parseCredential('{"4217":1}')).toThrowErrorMatchingInlineSnapshot(
|
|
2118
|
-
`[Error: Expected a credential or a chain-id-to-credential JSON object.]`,
|
|
2119
|
-
)
|
|
2120
|
-
})
|
|
2121
|
-
})
|
|
2122
|
-
|
|
2123
|
-
describe('resolveCredential', () => {
|
|
2124
|
-
test('infers Basic auth from a credential containing a colon', () => {
|
|
2125
|
-
expect(Auth.resolveCredential({ chainId: 4217, value: 'user:password' })).toEqual({
|
|
2126
|
-
basicAuth: 'user:password',
|
|
2127
|
-
})
|
|
2128
|
-
})
|
|
2129
|
-
|
|
2130
|
-
test('infers Bearer auth from a credential without a colon', () => {
|
|
2131
|
-
expect(Auth.resolveCredential({ chainId: 4217, value: 'bearer-token' })).toEqual({
|
|
2132
|
-
basicAuth: undefined,
|
|
2133
|
-
bearerAuth: 'bearer-token',
|
|
2134
|
-
})
|
|
2135
|
-
})
|
|
2136
|
-
|
|
2137
|
-
test('selects a credential by chain id', () => {
|
|
2138
|
-
const value = JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone-token' })
|
|
2139
|
-
|
|
2140
|
-
expect(Auth.resolveCredential({ chainId: 4217, value })).toEqual({
|
|
2141
|
-
basicAuth: 'mainnet:secret',
|
|
2142
|
-
})
|
|
2143
|
-
expect(Auth.resolveCredential({ chainId: 421700001, value })).toEqual({
|
|
2144
|
-
basicAuth: undefined,
|
|
2145
|
-
bearerAuth: 'zone-token',
|
|
2146
|
-
})
|
|
2147
|
-
expect(Auth.resolveCredential({ chainId: 42431, value })).toEqual({ basicAuth: undefined })
|
|
2148
|
-
})
|
|
2149
|
-
})
|
|
2150
|
-
|
|
2151
2103
|
function createScopedApp(options: {
|
|
2152
2104
|
auth?: Auth.Context | undefined
|
|
2153
2105
|
routes: readonly { path: string; policy: Auth.require.Policy }[]
|
package/src/internal/Auth.ts
CHANGED
|
@@ -1674,65 +1674,6 @@ type RateLimitAccess = PaymentAccess & {
|
|
|
1674
1674
|
rateLimit: RateLimit.Result
|
|
1675
1675
|
}
|
|
1676
1676
|
|
|
1677
|
-
/** Shared or per-chain credentials. */
|
|
1678
|
-
export type ChainCredential = string | Record<number, string>
|
|
1679
|
-
|
|
1680
|
-
/** Parses shared or per-chain credentials from an environment value. */
|
|
1681
|
-
export function parseCredential(value: ChainCredential | undefined): parseCredential.ReturnType {
|
|
1682
|
-
if (!value) return undefined
|
|
1683
|
-
if (typeof value !== 'string') return value
|
|
1684
|
-
const credentials = (() => {
|
|
1685
|
-
try {
|
|
1686
|
-
return JSON.parse(value) as unknown
|
|
1687
|
-
} catch {
|
|
1688
|
-
return value
|
|
1689
|
-
}
|
|
1690
|
-
})()
|
|
1691
|
-
if (typeof credentials === 'string') return credentials
|
|
1692
|
-
if (
|
|
1693
|
-
!credentials ||
|
|
1694
|
-
typeof credentials !== 'object' ||
|
|
1695
|
-
Array.isArray(credentials) ||
|
|
1696
|
-
Object.values(credentials).some((credential) => typeof credential !== 'string')
|
|
1697
|
-
)
|
|
1698
|
-
throw new Error('Expected a credential or a chain-id-to-credential JSON object.')
|
|
1699
|
-
return credentials as Record<number, string>
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
export declare namespace parseCredential {
|
|
1703
|
-
/** Parsed shared or per-chain credentials. */
|
|
1704
|
-
type ReturnType = ChainCredential | undefined
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
|
-
/** Resolves a chain credential and infers its HTTP authorization scheme. */
|
|
1708
|
-
export function resolveCredential(
|
|
1709
|
-
options: resolveCredential.Options,
|
|
1710
|
-
): resolveCredential.ReturnType {
|
|
1711
|
-
const credentials = parseCredential(options.value)
|
|
1712
|
-
const credential = typeof credentials === 'string' ? credentials : credentials?.[options.chainId]
|
|
1713
|
-
if (!credential) return { basicAuth: undefined }
|
|
1714
|
-
if (credential.includes(':')) return { basicAuth: credential }
|
|
1715
|
-
return { basicAuth: undefined, bearerAuth: credential }
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
export declare namespace resolveCredential {
|
|
1719
|
-
/** Options for resolving a chain credential. */
|
|
1720
|
-
type Options = {
|
|
1721
|
-
/** Chain id selecting a per-chain credential. */
|
|
1722
|
-
chainId: number
|
|
1723
|
-
/** Shared or per-chain credentials. */
|
|
1724
|
-
value?: ChainCredential | undefined
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
/** Resolved HTTP authorization credentials. */
|
|
1728
|
-
type ReturnType = {
|
|
1729
|
-
/** Basic credentials inferred from a value containing a colon. */
|
|
1730
|
-
basicAuth: string | undefined
|
|
1731
|
-
/** Bearer credential inferred from a value without a colon. */
|
|
1732
|
-
bearerAuth?: string | undefined
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
1677
|
/**
|
|
1737
1678
|
* How long to wait for the rate-limit counter before failing open. A hot
|
|
1738
1679
|
* counter backend (e.g. a single Durable Object serving one busy quota bucket)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as Credential from './Credential.js'
|
|
2
|
+
|
|
3
|
+
describe('parseCredential', () => {
|
|
4
|
+
test('parses credentials keyed by chain id', () => {
|
|
5
|
+
const credential = Credential.parseCredential(
|
|
6
|
+
JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone:secret' }),
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
expect(credential).toEqual({ 4217: 'mainnet:secret', 421700001: 'zone:secret' })
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('supports a shared credential', () => {
|
|
13
|
+
expect(Credential.parseCredential('shared:secret')).toBe('shared:secret')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('rejects malformed credential maps', () => {
|
|
17
|
+
expect(() => Credential.parseCredential('{"4217":1}')).toThrowErrorMatchingInlineSnapshot(
|
|
18
|
+
`[Error: Expected a credential or a chain-id-to-credential JSON object.]`,
|
|
19
|
+
)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('resolveCredential', () => {
|
|
24
|
+
test('infers Basic auth from a credential containing a colon', () => {
|
|
25
|
+
expect(Credential.resolveCredential({ chainId: 4217, value: 'user:password' })).toEqual({
|
|
26
|
+
basicAuth: 'user:password',
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('infers Bearer auth from a credential without a colon', () => {
|
|
31
|
+
expect(Credential.resolveCredential({ chainId: 4217, value: 'bearer-token' })).toEqual({
|
|
32
|
+
basicAuth: undefined,
|
|
33
|
+
bearerAuth: 'bearer-token',
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('selects a credential by chain id', () => {
|
|
38
|
+
const value = JSON.stringify({ 4217: 'mainnet:secret', 421700001: 'zone-token' })
|
|
39
|
+
|
|
40
|
+
expect(Credential.resolveCredential({ chainId: 4217, value })).toEqual({
|
|
41
|
+
basicAuth: 'mainnet:secret',
|
|
42
|
+
})
|
|
43
|
+
expect(Credential.resolveCredential({ chainId: 421700001, value })).toEqual({
|
|
44
|
+
basicAuth: undefined,
|
|
45
|
+
bearerAuth: 'zone-token',
|
|
46
|
+
})
|
|
47
|
+
expect(Credential.resolveCredential({ chainId: 42431, value })).toEqual({
|
|
48
|
+
basicAuth: undefined,
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Shared or per-chain credentials. */
|
|
2
|
+
export type ChainCredential = string | Record<number, string>
|
|
3
|
+
|
|
4
|
+
/** Parses shared or per-chain credentials from an environment value. */
|
|
5
|
+
export function parseCredential(value: ChainCredential | undefined): parseCredential.ReturnType {
|
|
6
|
+
if (!value) return undefined
|
|
7
|
+
if (typeof value !== 'string') return value
|
|
8
|
+
const credentials = (() => {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(value) as unknown
|
|
11
|
+
} catch {
|
|
12
|
+
return value
|
|
13
|
+
}
|
|
14
|
+
})()
|
|
15
|
+
if (typeof credentials === 'string') return credentials
|
|
16
|
+
if (
|
|
17
|
+
!credentials ||
|
|
18
|
+
typeof credentials !== 'object' ||
|
|
19
|
+
Array.isArray(credentials) ||
|
|
20
|
+
Object.values(credentials).some((credential) => typeof credential !== 'string')
|
|
21
|
+
)
|
|
22
|
+
throw new Error('Expected a credential or a chain-id-to-credential JSON object.')
|
|
23
|
+
return credentials as Record<number, string>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export declare namespace parseCredential {
|
|
27
|
+
/** Parsed shared or per-chain credentials. */
|
|
28
|
+
type ReturnType = ChainCredential | undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Resolves a chain credential and infers its HTTP authorization scheme. */
|
|
32
|
+
export function resolveCredential(
|
|
33
|
+
options: resolveCredential.Options,
|
|
34
|
+
): resolveCredential.ReturnType {
|
|
35
|
+
const credentials = parseCredential(options.value)
|
|
36
|
+
const credential = typeof credentials === 'string' ? credentials : credentials?.[options.chainId]
|
|
37
|
+
if (!credential) return { basicAuth: undefined }
|
|
38
|
+
if (credential.includes(':')) return { basicAuth: credential }
|
|
39
|
+
return { basicAuth: undefined, bearerAuth: credential }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare namespace resolveCredential {
|
|
43
|
+
/** Options for resolving a chain credential. */
|
|
44
|
+
type Options = {
|
|
45
|
+
/** Chain id selecting a per-chain credential. */
|
|
46
|
+
chainId: number
|
|
47
|
+
/** Shared or per-chain credentials. */
|
|
48
|
+
value?: ChainCredential | undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Resolved HTTP authorization credentials. */
|
|
52
|
+
type ReturnType = {
|
|
53
|
+
/** Basic credentials inferred from a value containing a colon. */
|
|
54
|
+
basicAuth: string | undefined
|
|
55
|
+
/** Bearer credential inferred from a value without a colon. */
|
|
56
|
+
bearerAuth?: string | undefined
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -246,6 +246,12 @@ async function measurePage(options: measurePage.Options): Promise<Measurement |
|
|
|
246
246
|
() => undefined,
|
|
247
247
|
)
|
|
248
248
|
|
|
249
|
+
// The migration scan is independent of historical quotes, so keep its TIDX
|
|
250
|
+
// round trip off the RPC critical path.
|
|
251
|
+
const migrations = recentMigrations(options).then(
|
|
252
|
+
(value) => ({ status: 'fulfilled', value }) as const,
|
|
253
|
+
(reason: unknown) => ({ reason, status: 'rejected' }) as const,
|
|
254
|
+
)
|
|
249
255
|
const rates = new Map<string, string>()
|
|
250
256
|
await Promise.all(
|
|
251
257
|
options.vaults.map(async (vault) => {
|
|
@@ -263,13 +269,13 @@ async function measurePage(options: measurePage.Options): Promise<Measurement |
|
|
|
263
269
|
}),
|
|
264
270
|
)
|
|
265
271
|
if (rates.size === 0) return { measuredAt, rates }
|
|
272
|
+
const migrationResult = await migrations
|
|
266
273
|
|
|
267
274
|
// A migration inside the window bridges two different yield engines, so the
|
|
268
|
-
// window resets instead of reporting growth across the swap.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
for (const { blockNumber, vault } of migrations)
|
|
275
|
+
// window resets instead of reporting growth across the swap.
|
|
276
|
+
if (migrationResult.status === 'rejected') throw migrationResult.reason
|
|
277
|
+
if (!migrationResult.value) return undefined
|
|
278
|
+
for (const { blockNumber, vault } of migrationResult.value)
|
|
273
279
|
if (blockNumber > start.number && blockNumber <= end.number) rates.delete(vault)
|
|
274
280
|
return { measuredAt, rates }
|
|
275
281
|
}
|
|
@@ -306,9 +312,9 @@ async function boundaryBlocks(options: boundaryBlocks.Options): Promise<Boundari
|
|
|
306
312
|
const result = await options.getTidx(chainId).fetch({
|
|
307
313
|
chainId,
|
|
308
314
|
query: `
|
|
309
|
-
(SELECT num, timestamp FROM blocks WHERE timestamp <= '${endInstant}' ORDER BY num DESC LIMIT 1)
|
|
315
|
+
(SELECT num, timestamp FROM blocks WHERE timestamp <= '${endInstant}' ORDER BY timestamp DESC, num DESC LIMIT 1)
|
|
310
316
|
UNION ALL
|
|
311
|
-
(SELECT num, timestamp FROM blocks WHERE timestamp <= '${startInstant}' ORDER BY num DESC LIMIT 1)
|
|
317
|
+
(SELECT num, timestamp FROM blocks WHERE timestamp <= '${startInstant}' ORDER BY timestamp DESC, num DESC LIMIT 1)
|
|
312
318
|
` as string,
|
|
313
319
|
})
|
|
314
320
|
const rows = result.rows.flatMap((row) => {
|
package/src/internal/Log.test.ts
CHANGED
|
@@ -51,10 +51,11 @@ describe('middleware', () => {
|
|
|
51
51
|
`)
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
test('includes
|
|
54
|
+
test('includes failed optional funding counts', async () => {
|
|
55
55
|
const entries: Log.Entry[] = []
|
|
56
56
|
const api = app({ emit: (entry) => void entries.push(entry) })
|
|
57
57
|
api.get('/v1/funding/transfers', (c) => {
|
|
58
|
+
c.set('fundingDepositCountFailed', true)
|
|
58
59
|
c.set('fundingTransferCountFailed', true)
|
|
59
60
|
return c.json({ data: [], nextCursor: null }, 200)
|
|
60
61
|
})
|
|
@@ -63,6 +64,7 @@ describe('middleware', () => {
|
|
|
63
64
|
|
|
64
65
|
expect(stable(entries[0]!)).toMatchInlineSnapshot(`
|
|
65
66
|
{
|
|
67
|
+
"fundingDepositCountFailed": true,
|
|
66
68
|
"fundingTransferCountFailed": true,
|
|
67
69
|
"level": "info",
|
|
68
70
|
"method": "GET",
|