Skip to content

Commit cd36d76

Browse files
Some backend boilerplate
1 parent 4fa231b commit cd36d76

File tree

12 files changed

+479
-66
lines changed

12 files changed

+479
-66
lines changed

deep-sea-stories/package.json

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
{
2-
"name": "deep-sea-stories",
3-
"packageManager": "yarn@4.9.2",
4-
"private": true,
5-
"workspaces": [
6-
"packages/*"
7-
],
8-
"devDependencies": {
9-
"@biomejs/biome": "2.2.4",
10-
"typescript": "^5.9.2"
11-
},
12-
"scripts": {
13-
"format": "biome format --write",
14-
"format:check": "biome format",
15-
"lint": "biome lint",
16-
"check": "biome check --write",
17-
"typecheck": "yarn workspaces foreach -A -p run typecheck"
18-
},
19-
"engines": {
20-
"node": ">= 24.0.0"
21-
}
2+
"name": "deep-sea-stories",
3+
"packageManager": "yarn@4.9.2",
4+
"private": true,
5+
"workspaces": [
6+
"packages/*"
7+
],
8+
"devDependencies": {
9+
"@biomejs/biome": "2.2.4",
10+
"typescript": "^5.9.2"
11+
},
12+
"scripts": {
13+
"format": "biome format --write",
14+
"format:check": "biome format",
15+
"lint": "biome lint",
16+
"check": "biome check --write",
17+
"typecheck": "yarn workspaces foreach -A -p run typecheck"
18+
},
19+
"engines": {
20+
"node": ">= 24.0.0"
21+
}
2222
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FISHJAM_ID="your-fishjam-id"
2+
FISHJAM_MANAGEMENT_TOKEN="your-management-token"
Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
{
2-
"name": "backend",
3-
"private": true,
4-
"main": "./src/main.ts",
5-
"type": "module",
6-
"dependencies": {
7-
"fastify": "^5.6.1",
8-
"pino-pretty": "^13.1.1"
9-
},
10-
"devDependencies": {
11-
"@tsconfig/node24": "^24.0.1",
12-
"@types/node": "^24.5.2",
13-
"tsx": "^4.20.6"
14-
},
15-
"scripts": {
16-
"build": "tsc -p tsconfig.json",
17-
"start": "tsx watch src/main.ts",
18-
"typecheck": "tsc --noEmit"
19-
}
2+
"name": "backend",
3+
"private": true,
4+
"main": "./src/main.ts",
5+
"type": "module",
6+
"dependencies": {
7+
"@fishjam-cloud/js-server-sdk": "^0.21.0",
8+
"dotenv": "^17.2.3",
9+
"fastify": "^5.6.1",
10+
"fastify-plugin": "^5.1.0",
11+
"fastify-type-provider-zod": "^6.0.0",
12+
"pino-pretty": "^13.1.1",
13+
"zod": "^4.1.11"
14+
},
15+
"devDependencies": {
16+
"@tsconfig/node24": "^24.0.1",
17+
"@types/node": "^24.5.2",
18+
"tsx": "^4.20.6"
19+
},
20+
"scripts": {
21+
"build": "tsc -p tsconfig.json",
22+
"start": "tsx watch src/main.ts",
23+
"typecheck": "tsc --noEmit"
24+
}
2025
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import dotenv from 'dotenv';
2+
import type { FastifyInstance } from 'fastify';
3+
import fp from 'fastify-plugin';
4+
import z from 'zod';
5+
6+
dotenv.config();
7+
8+
declare module 'fastify' {
9+
interface FastifyInstance {
10+
config: ConfigSchema;
11+
}
12+
}
13+
14+
export const configSchema = z.object({
15+
PORT: z.coerce.number().int().default(8000),
16+
FISHJAM_ID: z.string(),
17+
FISHJAM_URL: z.string().optional(),
18+
FISHJAM_MANAGEMENT_TOKEN: z.string(),
19+
});
20+
21+
type ConfigSchema = z.infer<typeof configSchema>;
22+
23+
export const fastifyConfig = fp((fastify: FastifyInstance) => {
24+
fastify.decorate('config', configSchema.parse(process.env));
25+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { FishjamClient, RoomId } from '@fishjam-cloud/js-server-sdk';
2+
3+
export async function createRoom(fishjam: FishjamClient) {
4+
return await fishjam.createRoom();
5+
}
6+
7+
export async function getRoom(fishjam: FishjamClient, roomId: RoomId) {
8+
return await fishjam.getRoom(roomId);
9+
}
Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,29 @@
1-
import Fastify, {
2-
type FastifyInstance,
3-
type RouteShorthandOptions,
4-
} from 'fastify';
1+
import Fastify from 'fastify';
2+
import {
3+
serializerCompiler,
4+
validatorCompiler,
5+
type ZodTypeProvider,
6+
} from 'fastify-type-provider-zod';
7+
import { fastifyConfig } from './config.js';
8+
import { fishjamPlugin } from './plugins/fishjam.js';
9+
import routes from './routes/index.js';
510

6-
const server: FastifyInstance = Fastify({
11+
const fastify = Fastify({
712
logger: { transport: { target: 'pino-pretty' } },
8-
});
9-
const port = 3000;
13+
}).withTypeProvider<ZodTypeProvider>();
1014

11-
const opts: RouteShorthandOptions = {
12-
schema: {
13-
response: {
14-
200: {
15-
type: 'object',
16-
properties: {
17-
pong: {
18-
type: 'string',
19-
},
20-
},
21-
},
22-
},
23-
},
24-
};
15+
fastify.setValidatorCompiler(validatorCompiler);
16+
fastify.setSerializerCompiler(serializerCompiler);
2517

26-
server.get('/ping', opts, async (_request, _reply) => {
27-
return { pong: 'it worked!' };
28-
});
18+
fastify.register(fastifyConfig);
19+
fastify.register(fishjamPlugin);
20+
21+
fastify.register(routes, { prefix: '/api/v1' });
2922

3023
try {
31-
await server.listen({ port });
24+
await fastify.ready();
25+
await fastify.listen({ port: fastify.config.PORT });
3226
} catch (err) {
33-
server.log.error(err);
27+
fastify.log.error(err);
3428
process.exit(1);
3529
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {
2+
FishjamBaseException,
3+
FishjamClient,
4+
} from '@fishjam-cloud/js-server-sdk';
5+
import type { FastifyInstance } from 'fastify';
6+
import fp from 'fastify-plugin';
7+
8+
declare module 'fastify' {
9+
interface FastifyInstance {
10+
fishjam: FishjamClient;
11+
}
12+
}
13+
14+
export const fishjamPlugin = fp(async (fastify: FastifyInstance) => {
15+
const fishjamClient = new FishjamClient({
16+
fishjamId: fastify.config.FISHJAM_ID,
17+
fishjamUrl: fastify.config.FISHJAM_URL,
18+
managementToken: fastify.config.FISHJAM_MANAGEMENT_TOKEN,
19+
});
20+
21+
try {
22+
await fishjamClient.getAllRooms();
23+
} catch (e) {
24+
if (e instanceof FishjamBaseException)
25+
throw Error('Invalid Fishjam configuration provided.');
26+
}
27+
28+
fastify.decorate('fishjam', fishjamClient);
29+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { FastifyInstance } from 'fastify';
2+
import rooms from './rooms.js';
3+
4+
export default function routes(fastify: FastifyInstance) {
5+
fastify.register(rooms, { prefix: '/rooms' });
6+
fastify.get('/', () => 'dupa');
7+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { RoomId } from '@fishjam-cloud/js-server-sdk';
2+
import type { FastifyPluginAsyncZod } from 'fastify-type-provider-zod';
3+
import z from 'zod';
4+
import { createRoom, getRoom } from '../controllers/rooms.js';
5+
import { roomSchema } from '../schemas.js';
6+
7+
const routes: FastifyPluginAsyncZod = async (fastify) => {
8+
fastify.post(
9+
'/',
10+
{
11+
schema: {
12+
response: {
13+
201: roomSchema,
14+
},
15+
},
16+
},
17+
async () => {
18+
return await createRoom(fastify.fishjam);
19+
},
20+
);
21+
22+
fastify.get(
23+
'/:roomId',
24+
{
25+
schema: {
26+
params: z.object({
27+
roomId: z.string(),
28+
}),
29+
response: {
30+
200: roomSchema,
31+
},
32+
},
33+
},
34+
async (req) => await getRoom(fastify.fishjam, req.params.roomId as RoomId),
35+
);
36+
};
37+
38+
export default routes;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import z from 'zod';
2+
3+
export const peerSchema = z.object({
4+
id: z.string(),
5+
});
6+
7+
export const roomSchema = z.object({
8+
id: z.string(),
9+
peers: peerSchema.array(),
10+
});

0 commit comments

Comments
 (0)