-
Notifications
You must be signed in to change notification settings - Fork 104
Expand file tree
/
Copy pathbackfill.ts
More file actions
110 lines (99 loc) · 3.34 KB
/
backfill.ts
File metadata and controls
110 lines (99 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { type Static, Type } from "@sinclair/typebox";
import type { FastifyInstance } from "fastify";
import { StatusCodes } from "http-status-codes";
import { TransactionDB } from "../../../shared/db/transactions/db";
import { standardResponseSchema } from "../../schemas/shared-api-schemas";
// SPECIAL LOGIC FOR AMEX
// Two admin routes to backfill transaction data:
// - loadBackfillRoute: Load queueId to status/transactionHash mappings
// - clearBackfillRoute: Clear all backfill entries
// See https://github.com/thirdweb-dev/solutions-customer-scripts/blob/main/amex/scripts/load-backfill-via-api.ts
const MinedEntrySchema = Type.Object({
queueId: Type.String({ description: "Queue ID (UUID)" }),
status: Type.Literal("mined"),
transactionHash: Type.String({ description: "Transaction hash (0x...)" }),
});
const ErroredEntrySchema = Type.Object({
queueId: Type.String({ description: "Queue ID (UUID)" }),
status: Type.Literal("errored"),
});
const loadRequestBodySchema = Type.Object({
entries: Type.Array(
Type.Union([MinedEntrySchema, ErroredEntrySchema], {
description: "Entry with status 'mined' requires transactionHash; status 'errored' does not",
}),
{
description: "Array of queueId to status/transactionHash mappings",
maxItems: 10000,
},
),
});
const loadResponseBodySchema = Type.Object({
result: Type.Object({
inserted: Type.Integer({ description: "Number of entries inserted" }),
skipped: Type.Integer({
description: "Number of entries skipped (already exist)",
}),
}),
});
const clearResponseBodySchema = Type.Object({
result: Type.Object({
deleted: Type.Integer({ description: "Number of entries deleted" }),
}),
});
export async function loadBackfillRoute(fastify: FastifyInstance) {
fastify.route<{
Body: Static<typeof loadRequestBodySchema>;
Reply: Static<typeof loadResponseBodySchema>;
}>({
method: "POST",
url: "/admin/backfill",
schema: {
summary: "Load backfill entries",
description:
"Load queueId to transactionHash mappings into the backfill table. Uses SETNX to never overwrite existing entries.",
tags: ["Admin"],
operationId: "loadBackfill",
body: loadRequestBodySchema,
response: {
...standardResponseSchema,
[StatusCodes.OK]: loadResponseBodySchema,
},
hide: true,
},
handler: async (request, reply) => {
const { entries } = request.body;
const { inserted, skipped } =
await TransactionDB.bulkSetBackfill(entries);
reply.status(StatusCodes.OK).send({
result: { inserted, skipped },
});
},
});
}
export async function clearBackfillRoute(fastify: FastifyInstance) {
fastify.route<{
Reply: Static<typeof clearResponseBodySchema>;
}>({
method: "DELETE",
url: "/admin/backfill",
schema: {
summary: "Clear backfill table",
description:
"Delete all entries from the backfill table. This action cannot be undone.",
tags: ["Admin"],
operationId: "clearBackfill",
response: {
...standardResponseSchema,
[StatusCodes.OK]: clearResponseBodySchema,
},
hide: true,
},
handler: async (_request, reply) => {
const deleted = await TransactionDB.clearBackfill();
reply.status(StatusCodes.OK).send({
result: { deleted },
});
},
});
}