Skip to content

Commit 0b8e0f8

Browse files
authored
Server Updates: Caching, Logging & CORS (#381)
* added cache reset cron + logging updates for apis * added standardResponseSchema to missing end-points to allow for error reporting * updated cors & auth to be on Request thus error messages can come in response * updated ts-node to tsx * updated logic to return [] for webhooks * removed console.log * Added getNonce end-point * updated get-nonces to get-nonce * cache cron schedule resets cacheCron * updated clearCachecron logging and added logic to check for cron schedule values * Added cron values check for all fields
1 parent 58c6abc commit 0b8e0f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+410
-42
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"cookie": "^0.5.0",
5353
"cookie-parser": "^1.4.6",
5454
"copyfiles": "^2.4.1",
55+
"cron-parser": "^4.9.0",
5556
"crypto-js": "^4.1.1",
5657
"dotenv": "^16.0.3",
5758
"ethers": "5",

src/db/configuration/getConfiguration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ export const getConfiguration = async (): Promise<Config> => {
188188
accessControlAllowOrigin: !!process.env.ACCESS_CONTROL_ALLOW_ORIGIN
189189
? process.env.ACCESS_CONTROL_ALLOW_ORIGIN
190190
: mandatoryAllowedCorsUrls.join(","),
191+
clearCacheCronSchedule: "*/30 * * * * *",
191192
},
192193
update: {},
193194
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "configuration" ADD COLUMN "clearCacheCronSchedule" TEXT NOT NULL DEFAULT '*/30 * * * * *';

src/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ model Configuration {
4242
// Wallet balance
4343
minWalletBalance String @default("20000000000000000") @map("minWalletBalance")
4444
accessControlAllowOrigin String @default("https://thirdweb.com,https://embed.ipfscdn.io") @map("accessControlAllowOrigin")
45+
clearCacheCronSchedule String @default("*/30 * * * * *") @map("clearCacheCronSchedule")
4546
4647
@@map("configuration")
4748
}

src/server/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as fs from "fs";
44
import path from "path";
55
import { URL } from "url";
66
import { deleteAllWalletNonces } from "../db/wallets/deleteAllWalletNonces";
7+
import { clearCacheCron } from "../utils/cron/clearCacheCron";
78
import { env } from "../utils/env";
89
import { logger } from "../utils/logger";
910
import { updateTxListener } from "./listerners/updateTxListener";
@@ -91,6 +92,7 @@ const main = async () => {
9192

9293
writeOpenApiToFile(server);
9394
await updateTxListener();
95+
await clearCacheCron("server");
9496
};
9597

9698
main();

src/server/middleware/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export const withAuth = async (server: FastifyInstance) => {
167167
server.decorateRequest("user", null);
168168

169169
// Add auth validation middleware to check for authenticated requests
170-
server.addHook("preHandler", async (req, res) => {
170+
server.addHook("onRequest", async (req, res) => {
171171
if (
172172
req.url === "/favicon.ico" ||
173173
req.url === "/" ||

src/server/middleware/cors/cors.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import {
1010
addOriginToVaryHeader,
1111
} from "./vary";
1212

13+
declare module "fastify" {
14+
interface FastifyRequest {
15+
corsPreflightEnabled: boolean;
16+
}
17+
}
18+
1319
interface ArrayOfValueOrArray<T> extends Array<ValueOrArray<T>> {}
1420

1521
type OriginCallback = (
@@ -150,7 +156,7 @@ export const fastifyCors = async (
150156
next();
151157
};
152158

153-
function normalizeCorsOptions(opts: FastifyCorsOptions) {
159+
const normalizeCorsOptions = (opts: FastifyCorsOptions): FastifyCorsOptions => {
154160
const corsOptions = { ...defaultOptions, ...opts };
155161
if (Array.isArray(opts.origin) && opts.origin.indexOf("*") !== -1) {
156162
corsOptions.origin = "*";
@@ -163,7 +169,7 @@ function normalizeCorsOptions(opts: FastifyCorsOptions) {
163169
corsOptions.cacheControl = undefined;
164170
}
165171
return corsOptions;
166-
}
172+
};
167173

168174
const addCorsHeadersHandler = (
169175
fastify: FastifyInstance,

src/server/middleware/cors/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FastifyInstance } from "fastify";
22
import { fastifyCors } from "./cors";
33

44
export const withCors = async (server: FastifyInstance) => {
5-
server.addHook("preHandler", (request, reply, next) => {
5+
server.addHook("onRequest", (request, reply, next) => {
66
fastifyCors(
77
server,
88
request,

src/server/middleware/error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const withErrorHandler = async (server: FastifyInstance) => {
3636
logger({
3737
service: "server",
3838
level: "error",
39-
message: `Encountered unhandled server error`,
39+
message: `Encountered server error`,
4040
error,
4141
});
4242

src/server/middleware/logs.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ export const withRequestLogs = async (server: FastifyInstance) => {
55
server.addHook("onRequest", async (request, reply) => {
66
if (
77
!request.routerPath?.includes("static") &&
8-
!request.routerPath?.includes("json")
8+
!request.routerPath?.includes("json") &&
9+
request.method !== "OPTIONS"
910
) {
1011
logger({
1112
service: "server",
@@ -29,13 +30,14 @@ export const withRequestLogs = async (server: FastifyInstance) => {
2930
if (
3031
!request.routerPath?.includes("static") &&
3132
!request.routerPath?.includes("json") &&
32-
!request.routerPath?.includes("/backend-wallet/import")
33+
!request.routerPath?.includes("/backend-wallet/import") &&
34+
request.method !== "OPTIONS"
3335
) {
3436
if (request.body && Object.keys(request.body).length > 0) {
3537
logger({
3638
service: "server",
3739
level: "info",
38-
message: `Request body`,
40+
message: `Request body - ${request.method} - ${request.routerPath}`,
3941
data: request.body,
4042
});
4143
}
@@ -44,7 +46,7 @@ export const withRequestLogs = async (server: FastifyInstance) => {
4446
logger({
4547
service: "server",
4648
level: "info",
47-
message: `Request params`,
49+
message: `Request params - ${request.method}`,
4850
data: request.params,
4951
});
5052
}
@@ -53,7 +55,7 @@ export const withRequestLogs = async (server: FastifyInstance) => {
5355
logger({
5456
service: "server",
5557
level: "info",
56-
message: `Request querystring`,
58+
message: `Request querystring - ${request.method} - ${request.routerPath}`,
5759
data: request.query,
5860
});
5961
}
@@ -63,7 +65,8 @@ export const withRequestLogs = async (server: FastifyInstance) => {
6365
server.addHook("onResponse", (request, reply, done) => {
6466
if (
6567
!request.routerPath?.includes("static") &&
66-
!request.routerPath?.includes("json")
68+
!request.routerPath?.includes("json") &&
69+
request.method !== "OPTIONS"
6770
) {
6871
logger({
6972
service: "server",

src/server/routes/auth/access-tokens/create.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { updateConfiguration } from "../../../../db/configuration/updateConfigur
77
import { createToken } from "../../../../db/tokens/createToken";
88
import { getConfig } from "../../../../utils/cache/getConfig";
99
import { env } from "../../../../utils/env";
10+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
1011
import { AccessTokenSchema } from "./getAll";
1112

1213
const BodySchema = Type.Object({
@@ -36,6 +37,7 @@ export async function createAccessToken(fastify: FastifyInstance) {
3637
operationId: "create",
3738
body: BodySchema,
3839
response: {
40+
...standardResponseSchema,
3941
[StatusCodes.OK]: ReplySchema,
4042
},
4143
},

src/server/routes/auth/access-tokens/getAll.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { getAccessTokens } from "../../../../db/tokens/getAccessTokens";
5+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
56

67
export const AccessTokenSchema = Type.Object({
78
id: Type.String(),
@@ -28,6 +29,7 @@ export async function getAllAccessTokens(fastify: FastifyInstance) {
2829
tags: ["Access Tokens"],
2930
operationId: "getAll",
3031
response: {
32+
...standardResponseSchema,
3133
[StatusCodes.OK]: ReplySchema,
3234
},
3335
},

src/server/routes/auth/access-tokens/revoke.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { revokeToken } from "../../../../db/tokens/revokeToken";
5+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
56

67
const BodySchema = Type.Object({
78
id: Type.String(),
@@ -27,6 +28,7 @@ export async function revokeAccessToken(fastify: FastifyInstance) {
2728
operationId: "revoke",
2829
body: BodySchema,
2930
response: {
31+
...standardResponseSchema,
3032
[StatusCodes.OK]: ReplySchema,
3133
},
3234
},

src/server/routes/auth/access-tokens/update.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { updateToken } from "../../../../db/tokens/updateToken";
5+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
56

67
const BodySchema = Type.Object({
78
id: Type.String(),
@@ -28,6 +29,7 @@ export async function updateAccessToken(fastify: FastifyInstance) {
2829
operationId: "update",
2930
body: BodySchema,
3031
response: {
32+
...standardResponseSchema,
3133
[StatusCodes.OK]: ReplySchema,
3234
},
3335
},

src/server/routes/auth/permissions/getAll.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { prisma } from "../../../../db/client";
5+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
56

67
const ReplySchema = Type.Object({
78
result: Type.Array(
@@ -25,6 +26,7 @@ export async function getAllPermissions(fastify: FastifyInstance) {
2526
tags: ["Permissions"],
2627
operationId: "getAll",
2728
response: {
29+
...standardResponseSchema,
2830
[StatusCodes.OK]: ReplySchema,
2931
},
3032
},

src/server/routes/auth/permissions/grant.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { updatePermissions } from "../../../../db/permissions/updatePermissions";
55
import { PermissionsSchema } from "../../../schemas/auth";
6+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
67

78
const BodySchema = Type.Object({
89
walletAddress: Type.String(),
@@ -30,6 +31,7 @@ export async function grantPermissions(fastify: FastifyInstance) {
3031
operationId: "grant",
3132
body: BodySchema,
3233
response: {
34+
...standardResponseSchema,
3335
[StatusCodes.OK]: ReplySchema,
3436
},
3537
},

src/server/routes/auth/permissions/revoke.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { deletePermissions } from "../../../../db/permissions/deletePermissions";
5+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
56

67
const BodySchema = Type.Object({
78
walletAddress: Type.String(),
@@ -27,6 +28,7 @@ export async function revokePermissions(fastify: FastifyInstance) {
2728
operationId: "revoke",
2829
body: BodySchema,
2930
response: {
31+
...standardResponseSchema,
3032
[StatusCodes.OK]: ReplySchema,
3133
},
3234
},
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { Static, Type } from "@sinclair/typebox";
2+
import { FastifyInstance } from "fastify";
3+
import { StatusCodes } from "http-status-codes";
4+
import { getWalletNonce } from "../../../db/wallets/getWalletNonce";
5+
import { createCustomError } from "../../middleware/error";
6+
import { standardResponseSchema } from "../../schemas/sharedApiSchemas";
7+
import { walletParamSchema } from "../../schemas/wallet";
8+
import { getChainIdFromChain } from "../../utils/chain";
9+
10+
const requestSchema = walletParamSchema;
11+
12+
const responseSchema = Type.Object({
13+
result: Type.Object({
14+
status: Type.String(),
15+
nonce: Type.String(),
16+
walletAddress: Type.String(),
17+
chain: Type.String(),
18+
}),
19+
});
20+
21+
responseSchema.example = {
22+
result: {
23+
nonce: "100",
24+
walletAddress: "0x...",
25+
chain: "1",
26+
},
27+
};
28+
29+
export const getBackendWalletNonce = async (fastify: FastifyInstance) => {
30+
fastify.route<{
31+
Params: Static<typeof requestSchema>;
32+
Reply: Static<typeof responseSchema>;
33+
}>({
34+
method: "GET",
35+
url: "/backend-wallet/:chain/:walletAddress/get-nonce",
36+
schema: {
37+
summary: "Get backend-wallet nonces from DB",
38+
description:
39+
"Get nonce for a backend wallets from DB. This is for debugging purposes and does not impact held tokens.",
40+
tags: ["Backend Wallet"],
41+
operationId: "getNonce",
42+
params: requestSchema,
43+
response: {
44+
...standardResponseSchema,
45+
[StatusCodes.OK]: responseSchema,
46+
},
47+
},
48+
handler: async (req, reply) => {
49+
const { chain, walletAddress } = req.params;
50+
const chainId = await getChainIdFromChain(chain);
51+
const walletNonce = await getWalletNonce({
52+
address: walletAddress,
53+
chainId,
54+
});
55+
56+
if (!walletNonce) {
57+
throw createCustomError(
58+
`No wallet nonce found for ${walletAddress} in DB`,
59+
StatusCodes.NOT_FOUND,
60+
"NOT_FOUND",
61+
);
62+
}
63+
64+
reply.status(StatusCodes.OK).send({
65+
result: {
66+
status: "success",
67+
nonce: walletNonce?.nonce.toString() ?? "0",
68+
walletAddress,
69+
chain,
70+
},
71+
});
72+
},
73+
});
74+
};

src/server/routes/backend-wallet/signMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { getWallet } from "../../../utils/cache/getWallet";
5+
import { standardResponseSchema } from "../../schemas/sharedApiSchemas";
56
import { walletAuthSchema } from "../../schemas/wallet";
67

78
const BodySchema = Type.Object({
@@ -27,6 +28,7 @@ export async function signMessage(fastify: FastifyInstance) {
2728
body: BodySchema,
2829
headers: Type.Omit(walletAuthSchema, ["x-account-address"]),
2930
response: {
31+
...standardResponseSchema,
3032
[StatusCodes.OK]: ReplySchema,
3133
},
3234
},

src/server/routes/backend-wallet/signTransaction.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { getWallet } from "../../../utils/cache/getWallet";
5+
import { standardResponseSchema } from "../../schemas/sharedApiSchemas";
56
import { walletAuthSchema } from "../../schemas/wallet";
67

78
const BodySchema = Type.Object({
@@ -42,6 +43,7 @@ export async function signTransaction(fastify: FastifyInstance) {
4243
body: BodySchema,
4344
headers: Type.Omit(walletAuthSchema, ["x-account-address"]),
4445
response: {
46+
...standardResponseSchema,
4547
[StatusCodes.OK]: ReplySchema,
4648
},
4749
},

src/server/routes/configuration/auth/get.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { getConfig } from "../../../../utils/cache/getConfig";
5+
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
56

67
export const ReplySchema = Type.Object({
78
result: Type.Object({
@@ -21,6 +22,7 @@ export async function getAuthConfiguration(fastify: FastifyInstance) {
2122
tags: ["Configuration"],
2223
operationId: "getAuthConfiguration",
2324
response: {
25+
...standardResponseSchema,
2426
[StatusCodes.OK]: ReplySchema,
2527
},
2628
},

0 commit comments

Comments
 (0)