Skip to content

Commit 14027c0

Browse files
authored
Merge pull request #783 from galnir/upgrade-to-v14
Upgrade to v14
2 parents 6d4598b + 4a2783b commit 14027c0

File tree

118 files changed

+5804
-3745
lines changed

Some content is hidden

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

118 files changed

+5804
-3745
lines changed

package-lock.json

Lines changed: 4128 additions & 2027 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,19 @@
3030
},
3131
"homepage": "https://github.com/galnir/Master-Bot#readme",
3232
"dependencies": {
33-
"@prisma/client": "^4.8.1",
34-
"@trpc/client": "^10.1.0",
35-
"@trpc/next": "^10.1.0",
36-
"@trpc/react-query": "^10.1.0",
37-
"@trpc/server": "^10.1.0",
38-
"concurrently": "^7.3.0",
33+
"@prisma/client": "^4.12.0",
34+
"@trpc/client": "^10.19.1",
35+
"@trpc/next": "^10.19.1",
36+
"@trpc/react-query": "^10.19.1",
37+
"@trpc/server": "^10.19.1",
38+
"axios": "^1.3.5",
39+
"concurrently": "^8.0.1",
3940
"cpy-cli": "^4.2.0",
40-
"superjson": "^1.9.1",
41-
"zod": "^3.18.0"
41+
"superjson": "^1.12.2",
42+
"zod": "^3.21.4"
4243
},
4344
"devDependencies": {
44-
"prisma": "^4.8.1",
45-
"typescript": "^4.7.4"
45+
"prisma": "^4.12.0",
46+
"typescript": "^5.0.4"
4647
}
4748
}

packages/api/src/createContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import * as trpc from '@trpc/server';
33
import * as trpcNext from '@trpc/server/adapters/next';
44
import { Session } from 'next-auth';
5-
import { unstable_getServerSession as getServerSession } from 'next-auth';
5+
import { getServerSession } from 'next-auth';
66
import { authOptions as nextAuthOptions } from '../../dashboard/src/pages/api/auth/[...nextauth]';
77
import { prisma } from './db/client';
88

packages/api/src/routers/channel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export const channelRouter = t.router({
2626
}
2727
}
2828
);
29-
const responseChannels: APIGuildChannel<any>[] = await response.json();
29+
const responseChannels =
30+
(await response.json()) as APIGuildChannel<any>[];
3031

3132
const channels: APIGuildTextChannel<0>[] = responseChannels.filter(
3233
channel => channel.type === 0

packages/api/src/routers/command.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export const commandRouter = t.router({
8282
}
8383
}
8484
);
85-
const commands: CommandType[] = await response.json();
85+
const commands = (await response.json()) as CommandType[];
8686

8787
return { commands };
8888
} catch (e) {

packages/api/src/routers/guild.ts

Lines changed: 27 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { z } from 'zod';
33
import { APIGuild, APIRole } from 'discord-api-types/v10';
44
import { TRPCError } from '@trpc/server';
55
import { getFetch } from '@trpc/client';
6+
import axiosInstance from '../utils/axiosWithRefresh';
67

78
const fetch = getFetch();
89

@@ -50,7 +51,7 @@ export const guildRouter = t.router({
5051
}
5152
);
5253

53-
const guild: APIGuild = await response.json();
54+
const guild = (await response.json()) as APIGuild;
5455

5556
return { guild };
5657
} catch {
@@ -229,25 +230,8 @@ export const guildRouter = t.router({
229230

230231
return { guild };
231232
}),
232-
getAllFromLocal: t.procedure
233-
.input(
234-
z.object({
235-
ownerId: z.string()
236-
})
237-
)
238-
.query(async ({ ctx, input }) => {
239-
const { ownerId } = input;
240-
241-
const guilds = await ctx.prisma.guild.findMany({
242-
where: {
243-
ownerId: ownerId as string
244-
}
245-
});
246-
247-
return { guilds };
248-
}),
249233
getAll: t.procedure.query(async ({ ctx }) => {
250-
if (!ctx.session) {
234+
if (!ctx.session || !ctx.session.user) {
251235
throw new TRPCError({
252236
message: 'Not Authenticated',
253237
code: 'UNAUTHORIZED'
@@ -258,10 +242,6 @@ export const guildRouter = t.router({
258242
where: {
259243
// @ts-ignore
260244
userId: ctx.session?.user?.id
261-
},
262-
select: {
263-
access_token: true,
264-
providerAccountId: true
265245
}
266246
});
267247

@@ -272,26 +252,33 @@ export const guildRouter = t.router({
272252
});
273253
}
274254

275-
const dbGuilds = await ctx.prisma.guild.findMany({
276-
where: {
277-
ownerId: account.providerAccountId
278-
}
279-
});
280-
281-
// fetch guilds the user is owner in from discord api using the ownerId and token
282255
try {
283-
const response = await fetch(`https://discord.com/api/users/@me/guilds`, {
284-
headers: {
285-
Authorization: `Bearer ${account.access_token}`
256+
const dbGuilds = await ctx.prisma.guild.findMany({
257+
where: {
258+
ownerId: account.providerAccountId
286259
}
287260
});
288261

289-
const userGuilds: APIGuild[] = await response.json();
290-
if (!userGuilds.length) {
291-
return { guilds: dbGuilds };
292-
}
293-
const guildsUserOwns = userGuilds.filter(guild => guild.owner);
294-
return { apiGuilds: guildsUserOwns, dbGuilds };
262+
const response = await axiosInstance.get(
263+
'https://discord.com/api/users/@me/guilds',
264+
{
265+
headers: {
266+
Authorization: `Bearer ${account.access_token}`,
267+
// @ts-ignore
268+
'X-User-Id': ctx.session.user.id,
269+
'X-Refresh-Token': account.refresh_token
270+
}
271+
}
272+
);
273+
274+
const apiGuilds = response.data as APIGuild[];
275+
276+
const apiGuildsOwns = apiGuilds.filter(guild => guild.owner);
277+
278+
return {
279+
apiGuilds: apiGuildsOwns,
280+
dbGuilds
281+
};
295282
} catch (e) {
296283
console.error(e);
297284
throw new TRPCError({
@@ -300,47 +287,6 @@ export const guildRouter = t.router({
300287
});
301288
}
302289
}),
303-
getAllFromDiscordAPI: t.procedure.query(async ({ ctx }) => {
304-
if (!ctx.session) {
305-
throw new TRPCError({
306-
message: 'Not Authenticated',
307-
code: 'UNAUTHORIZED'
308-
});
309-
}
310-
311-
const account = await ctx.prisma.account.findFirst({
312-
where: {
313-
// @ts-ignore
314-
userId: ctx.session?.user?.id
315-
},
316-
select: {
317-
access_token: true,
318-
providerAccountId: true,
319-
user: {
320-
select: {
321-
discordId: true
322-
}
323-
}
324-
}
325-
});
326-
327-
if (!account || !account.access_token) {
328-
throw new TRPCError({
329-
code: 'NOT_FOUND',
330-
message: 'Account not found'
331-
});
332-
}
333-
334-
const response = await fetch(`https://discord.com/api/users/@me/guilds`, {
335-
headers: {
336-
Authorization: `Bearer ${account.access_token}`
337-
}
338-
});
339-
340-
const userGuilds: APIGuild[] = await response.json();
341-
342-
return { guilds: userGuilds, discordId: account.user.discordId };
343-
}),
344290
updateTwitchNotifications: t.procedure
345291
.input(
346292
z.object({
@@ -397,7 +343,7 @@ export const guildRouter = t.router({
397343
}
398344
);
399345

400-
const roles: APIRole[] = await response.json();
346+
const roles = (await response.json()) as APIRole[];
401347

402348
return { roles };
403349
})

packages/api/src/routers/hub.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const hubRouter = t.router({
3333
})
3434
}
3535
);
36-
parent = await response.json();
36+
parent = (await response.json()) as any;
3737
} catch (e) {
3838
console.log(e);
3939
throw new TRPCError({
@@ -59,7 +59,7 @@ export const hubRouter = t.router({
5959
})
6060
}
6161
);
62-
hubChannel = await response.json();
62+
hubChannel = (await response.json()) as any;
6363
} catch {
6464
throw new TRPCError({
6565
message: 'Could not create channel',
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import axios from 'axios';
2+
import { prisma } from '../db/client';
3+
const axiosInstance = axios.create();
4+
5+
// Refresh access token if expired and retry the request
6+
axiosInstance.interceptors.response.use(undefined, async error => {
7+
// console.log('error is', error);
8+
if (error.response && error.response.status === 401) {
9+
const clientId = process.env.DISCORD_CLIENT_ID;
10+
const clientSecret = process.env.DISCORD_CLIENT_SECRET;
11+
12+
if (!clientId || !clientSecret) {
13+
return Promise.reject(error);
14+
}
15+
16+
const originalRequest = error.config;
17+
const refreshToken = originalRequest.headers['X-Refresh-Token'];
18+
const userId = originalRequest.headers['X-User-Id'];
19+
20+
// Remove the custom headers
21+
delete originalRequest.headers['X-Refresh-Token'];
22+
delete originalRequest.headers['X-User-Id'];
23+
24+
// Check if we've already tried to refresh the token for this request
25+
if (!originalRequest._retry) {
26+
originalRequest._retry = true;
27+
28+
// Refresh the access token using your refreshAccessToken function
29+
const newTokens = await refreshAccessToken(
30+
clientId,
31+
clientSecret,
32+
refreshToken
33+
);
34+
35+
if (newTokens) {
36+
// Update the access token and refresh token in your database
37+
await prisma.user.update({
38+
where: {
39+
id: userId
40+
},
41+
data: {}
42+
});
43+
44+
// Update the access token in the original request's headers
45+
originalRequest.headers[
46+
'Authorization'
47+
] = `Bearer ${newTokens.accessToken}`;
48+
49+
// Retry the original request with the new access token
50+
return axiosInstance(originalRequest);
51+
}
52+
}
53+
}
54+
55+
// If the error isn't due to an expired token, pass it along
56+
return Promise.reject(error);
57+
});
58+
59+
async function refreshAccessToken(
60+
clientId: string,
61+
clientSecret: string,
62+
refreshToken: string
63+
) {
64+
try {
65+
const response = await axios.post(
66+
'https://discord.com/api/oauth2/token',
67+
null,
68+
{
69+
params: {
70+
client_id: clientId,
71+
client_secret: clientSecret,
72+
grant_type: 'refresh_token',
73+
refresh_token: refreshToken
74+
},
75+
headers: {
76+
'Content-Type': 'application/x-www-form-urlencoded'
77+
}
78+
}
79+
);
80+
81+
const {
82+
access_token,
83+
refresh_token: newRefreshToken,
84+
expires_in
85+
} = response.data;
86+
87+
// Update the access and refresh tokens in your database
88+
89+
return {
90+
accessToken: access_token,
91+
refreshToken: newRefreshToken,
92+
expiresIn: expires_in
93+
};
94+
} catch (error) {
95+
console.error('Error refreshing access token:', error);
96+
return null;
97+
}
98+
}
99+
100+
export default axiosInstance;

0 commit comments

Comments
 (0)