mirror of
https://github.com/movie-web/backend.git
synced 2025-09-13 08:03:27 +00:00
add basic repo setup, with user creation
This commit is contained in:
1
.docker/development/.gitignore
vendored
Normal file
1
.docker/development/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
config.env
|
35
.docker/development/HOW-TO-USE.md
Normal file
35
.docker/development/HOW-TO-USE.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# how to use docker development?
|
||||||
|
|
||||||
|
## How to setup?
|
||||||
|
1. have docker installed
|
||||||
|
2. create a `config.env` in `/.docker/development`. inspire its contents from `example.config.env`
|
||||||
|
|
||||||
|
## how to run?
|
||||||
|
1. while in directory `/.docker/development` run `docker compose up -d`
|
||||||
|
1.1 if running first time in docker, make sure you have no node_modules folder present in `/`.
|
||||||
|
|
||||||
|
## not working? try this:
|
||||||
|
1. while in directory `/.docker/development` run `docker compose down -v`
|
||||||
|
2. remove `node_modules` directory in `/` if it exists
|
||||||
|
3. remove `.env` and `config.json` file in `/` if any of them exist
|
||||||
|
4. while in directory `/.docker/development` run `docker compose up -d --build`
|
||||||
|
|
||||||
|
## how to stop?
|
||||||
|
1. while in directory `/.docker/development` run `docker compose down`
|
||||||
|
> NOTE: if you want also delete all saved data for a full reset, run `docker compose down -v` instead
|
||||||
|
|
||||||
|
## how do I access the terminal for the backend service?
|
||||||
|
make sure the docker services are running, then run `docker attach mw_backend-1`.
|
||||||
|
this will appear to show nothing at first, but all new logs will show up,
|
||||||
|
and anything you type in the terminal now affect the backend service.
|
||||||
|
> Warning: doing CTRL+C will shut down the backend service, it will not kick your terminal back to its original shell.
|
||||||
|
|
||||||
|
## how do I read logs?
|
||||||
|
1. while in directory `/.docker/development` run `docker compose ps`
|
||||||
|
2. note the name of the service you want to see the logs of
|
||||||
|
3. while in directory `/.docker/development` run `docker compose logs <NAME>`. fill in the name of the service without the brackets.
|
||||||
|
|
||||||
|
## Exposed ports
|
||||||
|
- http://localhost:8081 - backend API
|
||||||
|
- http://localhost:8082 - postgres web UI
|
||||||
|
- postgres://localhost:5432 - postgres
|
47
.docker/development/docker-compose.yml
Normal file
47
.docker/development/docker-compose.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
name: "mw_backend"
|
||||||
|
|
||||||
|
services:
|
||||||
|
# required services
|
||||||
|
postgres:
|
||||||
|
image: postgres
|
||||||
|
ports:
|
||||||
|
- '5432:5432'
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
volumes:
|
||||||
|
- 'postgres_data:/var/lib/postgresql/data'
|
||||||
|
|
||||||
|
# custom services
|
||||||
|
backend:
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
build:
|
||||||
|
dockerfile: ./dev.Dockerfile
|
||||||
|
context: ../../
|
||||||
|
volumes:
|
||||||
|
- '../../:/app'
|
||||||
|
env_file:
|
||||||
|
- './config.env'
|
||||||
|
ports:
|
||||||
|
- '8081:8080'
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
environment:
|
||||||
|
- WAIT_HOSTS=postgres:5432
|
||||||
|
|
||||||
|
# util services
|
||||||
|
pgweb:
|
||||||
|
image: sosedoff/pgweb
|
||||||
|
ports:
|
||||||
|
- "8082:8081"
|
||||||
|
links:
|
||||||
|
- postgres:postgres
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
1
.docker/development/example.config.env
Normal file
1
.docker/development/example.config.env
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MWB_USE_PRESETS=dev,dockerdev
|
@@ -4,3 +4,4 @@ config.json
|
|||||||
dist
|
dist
|
||||||
.git
|
.git
|
||||||
.vscode
|
.vscode
|
||||||
|
.docker
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
FROM node:18-alpine
|
FROM node:20-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# install dependencies
|
# install dependencies
|
||||||
@@ -11,6 +11,6 @@ RUN npm run build
|
|||||||
|
|
||||||
# start server
|
# start server
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
ENV CONF_SERVER__PORT=80
|
ENV MWB_SERVER__PORT=80
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
CMD ["npm", "run", "start"]
|
CMD ["npm", "run", "start"]
|
||||||
|
@@ -1,2 +1,11 @@
|
|||||||
# backend
|
# backend
|
||||||
Backend for movie-web
|
Backend for movie-web
|
||||||
|
|
||||||
|
## Todo list
|
||||||
|
- [ ] endpoint to consume provider metrics
|
||||||
|
- [ ] register endpoint
|
||||||
|
- [ ] remove user endpoint
|
||||||
|
- [ ] ratelimits for all endpoints
|
||||||
|
- [ ] metrics for all http requests
|
||||||
|
- [ ] session CRUD endpoints
|
||||||
|
- [ ] data save endpoints
|
||||||
|
9
dev.Dockerfile
Normal file
9
dev.Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# wait script for development
|
||||||
|
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.7.3/wait /wait
|
||||||
|
RUN chmod +x /wait
|
||||||
|
|
||||||
|
VOLUME [ "/app" ]
|
||||||
|
CMD npm i && /wait && npm run dev
|
4663
package-lock.json
generated
Normal file
4663
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^8.3.0",
|
"@fastify/cors": "^8.3.0",
|
||||||
|
"@mikro-orm/core": "^5.9.0",
|
||||||
|
"@mikro-orm/postgresql": "^5.9.0",
|
||||||
"fastify": "^4.21.0",
|
"fastify": "^4.21.0",
|
||||||
"fastify-type-provider-zod": "^1.1.9",
|
"fastify-type-provider-zod": "^1.1.9",
|
||||||
"neat-config": "^2.0.0",
|
"neat-config": "^2.0.0",
|
||||||
|
@@ -9,4 +9,7 @@ export const devFragment: FragmentSchema = {
|
|||||||
format: 'pretty',
|
format: 'pretty',
|
||||||
debug: true,
|
debug: true,
|
||||||
},
|
},
|
||||||
|
postgres: {
|
||||||
|
syncSchema: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
7
src/config/fragments/docker.ts
Normal file
7
src/config/fragments/docker.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { FragmentSchema } from '@/config/fragments/types';
|
||||||
|
|
||||||
|
export const dockerFragment: FragmentSchema = {
|
||||||
|
postgres: {
|
||||||
|
connection: 'postgres://postgres:postgres@postgres:5432/postgres',
|
||||||
|
},
|
||||||
|
};
|
@@ -1,9 +1,11 @@
|
|||||||
import { devFragment } from '@/config/fragments/dev';
|
import { devFragment } from '@/config/fragments/dev';
|
||||||
|
import { dockerFragment } from '@/config/fragments/docker';
|
||||||
import { configSchema } from '@/config/schema';
|
import { configSchema } from '@/config/schema';
|
||||||
import { createConfigLoader } from 'neat-config';
|
import { createConfigLoader } from 'neat-config';
|
||||||
|
|
||||||
const fragments = {
|
const fragments = {
|
||||||
dev: devFragment,
|
dev: devFragment,
|
||||||
|
dockerdev: dockerFragment,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const conf = createConfigLoader()
|
export const conf = createConfigLoader()
|
||||||
|
@@ -26,4 +26,16 @@ export const configSchema = z.object({
|
|||||||
debug: z.coerce.boolean().default(false),
|
debug: z.coerce.boolean().default(false),
|
||||||
})
|
})
|
||||||
.default({}),
|
.default({}),
|
||||||
|
postgres: z.object({
|
||||||
|
// connection URL for postgres database
|
||||||
|
connection: z.string(),
|
||||||
|
|
||||||
|
// run all migrations on boot of the application
|
||||||
|
migrateOnBoot: z.coerce.boolean().default(false),
|
||||||
|
|
||||||
|
// try to sync the schema on boot, useful for development
|
||||||
|
// will always keep the database schema in sync with the connected database
|
||||||
|
// it is extremely destructive, do not use it EVER in production
|
||||||
|
syncSchema: z.coerce.boolean().default(false),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
31
src/db/models/User.ts
Normal file
31
src/db/models/User.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Entity, PrimaryKey, Property, types } from '@mikro-orm/core';
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
|
@Entity({ tableName: 'users' })
|
||||||
|
export class User {
|
||||||
|
@PrimaryKey({ name: 'id', type: 'uuid' })
|
||||||
|
id: string = randomUUID();
|
||||||
|
|
||||||
|
@Property({ type: 'date' })
|
||||||
|
createdAt: Date = new Date();
|
||||||
|
|
||||||
|
@Property({ type: 'text' })
|
||||||
|
name!: string;
|
||||||
|
|
||||||
|
@Property({ name: 'permissions', type: types.array })
|
||||||
|
roles: string[] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserDTO {
|
||||||
|
id: string;
|
||||||
|
roles: string[];
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatUser(user: User): UserDTO {
|
||||||
|
return {
|
||||||
|
id: user.id,
|
||||||
|
roles: user.roles,
|
||||||
|
createdAt: user.createdAt.toISOString(),
|
||||||
|
};
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
import { setupFastify } from '@/modules/fastify';
|
import { setupFastify } from '@/modules/fastify';
|
||||||
|
import { setupMikroORM } from '@/modules/mikro';
|
||||||
import { scopedLogger } from '@/services/logger';
|
import { scopedLogger } from '@/services/logger';
|
||||||
|
|
||||||
const log = scopedLogger('mw-backend');
|
const log = scopedLogger('mw-backend');
|
||||||
@@ -9,6 +10,7 @@ async function bootstrap(): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await setupFastify();
|
await setupFastify();
|
||||||
|
await setupMikroORM();
|
||||||
|
|
||||||
log.info(`App setup, ready to accept connections`, {
|
log.info(`App setup, ready to accept connections`, {
|
||||||
evt: 'success',
|
evt: 'success',
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { helloRouter } from '@/routes/hello';
|
import { manageAuthRouter } from '@/routes/auth/manage';
|
||||||
import { FastifyInstance } from 'fastify';
|
import { FastifyInstance } from 'fastify';
|
||||||
|
|
||||||
export async function setupRoutes(app: FastifyInstance) {
|
export async function setupRoutes(app: FastifyInstance) {
|
||||||
app.register(helloRouter);
|
app.register(manageAuthRouter.register);
|
||||||
}
|
}
|
||||||
|
44
src/modules/mikro/index.ts
Normal file
44
src/modules/mikro/index.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { conf } from '@/config';
|
||||||
|
import { scopedLogger } from '@/services/logger';
|
||||||
|
import { PostgreSqlDriver } from '@mikro-orm/postgresql';
|
||||||
|
import { MikroORM } from '@mikro-orm/core';
|
||||||
|
import { createORM } from './orm';
|
||||||
|
|
||||||
|
const log = scopedLogger('orm');
|
||||||
|
let orm: MikroORM<PostgreSqlDriver> | null = null;
|
||||||
|
|
||||||
|
export function getORM() {
|
||||||
|
if (!orm) throw new Error('ORM not set');
|
||||||
|
return orm;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setupMikroORM() {
|
||||||
|
log.info(`Connecting to postgres`, { evt: 'connecting' });
|
||||||
|
const mikro = await createORM(conf.postgres.connection, (msg) =>
|
||||||
|
log.info(msg),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (conf.postgres.syncSchema) {
|
||||||
|
const generator = mikro.getSchemaGenerator();
|
||||||
|
try {
|
||||||
|
await generator.updateSchema();
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
await generator.clearDatabase();
|
||||||
|
await generator.updateSchema();
|
||||||
|
} catch {
|
||||||
|
await generator.clearDatabase();
|
||||||
|
await generator.dropSchema();
|
||||||
|
await generator.updateSchema();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf.postgres.migrateOnBoot) {
|
||||||
|
const migrator = mikro.getMigrator();
|
||||||
|
await migrator.up();
|
||||||
|
}
|
||||||
|
|
||||||
|
orm = mikro;
|
||||||
|
log.info(`Connected to postgres - ORM is setup!`, { evt: 'success' });
|
||||||
|
}
|
17
src/modules/mikro/orm.ts
Normal file
17
src/modules/mikro/orm.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { MikroORM, PostgreSqlDriver } from '@mikro-orm/postgresql';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export async function createORM(url: string, log: (msg: string) => void) {
|
||||||
|
return await MikroORM.init<PostgreSqlDriver>({
|
||||||
|
type: 'postgresql',
|
||||||
|
clientUrl: url,
|
||||||
|
entities: ['./models/**/*.js'],
|
||||||
|
entitiesTs: ['./models/**/*.ts'],
|
||||||
|
baseDir: path.join(__dirname, '../../db'),
|
||||||
|
migrations: {
|
||||||
|
pathTs: './migrations/**/*.ts',
|
||||||
|
path: './migrations/**/*.ts',
|
||||||
|
},
|
||||||
|
logger: log,
|
||||||
|
});
|
||||||
|
}
|
25
src/routes/auth/manage.ts
Normal file
25
src/routes/auth/manage.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { User, formatUser } from '@/db/models/User';
|
||||||
|
import { handle } from '@/services/handler';
|
||||||
|
import { makeRouter } from '@/services/router';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
const registerSchema = z.object({
|
||||||
|
name: z.string().max(500).min(1),
|
||||||
|
device: z.string().max(500).min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const manageAuthRouter = makeRouter((app) => {
|
||||||
|
app.post(
|
||||||
|
'/auth/register',
|
||||||
|
{ schema: { body: registerSchema } },
|
||||||
|
handle(({ em, body }) => {
|
||||||
|
const user = new User();
|
||||||
|
user.name = body.name;
|
||||||
|
em.persistAndFlush(user);
|
||||||
|
|
||||||
|
return {
|
||||||
|
user: formatUser(user),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
@@ -1,7 +0,0 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
|
||||||
|
|
||||||
export const helloRouter: FastifyPluginAsync = async (app) => {
|
|
||||||
app.get('/ping', (req, res) => {
|
|
||||||
res.send('pong!');
|
|
||||||
});
|
|
||||||
};
|
|
5
src/services/access.ts
Normal file
5
src/services/access.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const roles = {
|
||||||
|
ADMIN: 'ADMIN', // has access to admin endpoints
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type Roles = (typeof roles)[keyof typeof roles];
|
5
src/services/auth.ts
Normal file
5
src/services/auth.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { Roles } from '@/services/access';
|
||||||
|
|
||||||
|
export function assertHasRole(_role: Roles) {
|
||||||
|
throw new Error('requires role');
|
||||||
|
}
|
127
src/services/handler.ts
Normal file
127
src/services/handler.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import { getORM } from '@/modules/mikro';
|
||||||
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
|
import {
|
||||||
|
ContextConfigDefault,
|
||||||
|
FastifyBaseLogger,
|
||||||
|
FastifyReply,
|
||||||
|
FastifyRequest,
|
||||||
|
FastifySchema,
|
||||||
|
RawReplyDefaultExpression,
|
||||||
|
RawRequestDefaultExpression,
|
||||||
|
RawServerBase,
|
||||||
|
RawServerDefault,
|
||||||
|
RouteGenericInterface,
|
||||||
|
RouteHandlerMethod,
|
||||||
|
} from 'fastify';
|
||||||
|
import { ZodTypeProvider } from 'fastify-type-provider-zod';
|
||||||
|
import { ResolveFastifyReplyReturnType } from 'fastify/types/type-provider';
|
||||||
|
|
||||||
|
export type RequestContext<
|
||||||
|
RawServer extends RawServerBase = RawServerDefault,
|
||||||
|
RawRequest extends
|
||||||
|
RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
|
||||||
|
RawReply extends
|
||||||
|
RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
|
||||||
|
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
|
||||||
|
ContextConfig = ContextConfigDefault,
|
||||||
|
SchemaCompiler extends FastifySchema = FastifySchema,
|
||||||
|
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||||
|
> = {
|
||||||
|
req: FastifyRequest<
|
||||||
|
RouteGeneric,
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
SchemaCompiler,
|
||||||
|
ZodTypeProvider,
|
||||||
|
ContextConfig,
|
||||||
|
Logger
|
||||||
|
>;
|
||||||
|
res: FastifyReply<
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
RawReply,
|
||||||
|
RouteGeneric,
|
||||||
|
ContextConfig,
|
||||||
|
SchemaCompiler,
|
||||||
|
ZodTypeProvider
|
||||||
|
>;
|
||||||
|
body: FastifyRequest<
|
||||||
|
RouteGeneric,
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
SchemaCompiler,
|
||||||
|
ZodTypeProvider,
|
||||||
|
ContextConfig,
|
||||||
|
Logger
|
||||||
|
>['body'];
|
||||||
|
params: FastifyRequest<
|
||||||
|
RouteGeneric,
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
SchemaCompiler,
|
||||||
|
ZodTypeProvider,
|
||||||
|
ContextConfig,
|
||||||
|
Logger
|
||||||
|
>['params'];
|
||||||
|
query: FastifyRequest<
|
||||||
|
RouteGeneric,
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
SchemaCompiler,
|
||||||
|
ZodTypeProvider,
|
||||||
|
ContextConfig,
|
||||||
|
Logger
|
||||||
|
>['query'];
|
||||||
|
em: EntityManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function handle<
|
||||||
|
RawServer extends RawServerBase = RawServerDefault,
|
||||||
|
RawRequest extends
|
||||||
|
RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
|
||||||
|
RawReply extends
|
||||||
|
RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
|
||||||
|
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
|
||||||
|
ContextConfig = ContextConfigDefault,
|
||||||
|
SchemaCompiler extends FastifySchema = FastifySchema,
|
||||||
|
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||||
|
>(
|
||||||
|
handler: (
|
||||||
|
ctx: RequestContext<
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
RawReply,
|
||||||
|
RouteGeneric,
|
||||||
|
ContextConfig,
|
||||||
|
SchemaCompiler,
|
||||||
|
Logger
|
||||||
|
>,
|
||||||
|
) => ResolveFastifyReplyReturnType<
|
||||||
|
ZodTypeProvider,
|
||||||
|
SchemaCompiler,
|
||||||
|
RouteGeneric
|
||||||
|
>,
|
||||||
|
): RouteHandlerMethod<
|
||||||
|
RawServer,
|
||||||
|
RawRequest,
|
||||||
|
RawReply,
|
||||||
|
RouteGeneric,
|
||||||
|
ContextConfig,
|
||||||
|
SchemaCompiler,
|
||||||
|
ZodTypeProvider,
|
||||||
|
Logger
|
||||||
|
> {
|
||||||
|
const reqHandler: any = async (req: any, res: any) => {
|
||||||
|
res.send(
|
||||||
|
await handler({
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
body: req.body,
|
||||||
|
params: req.params,
|
||||||
|
query: req.query,
|
||||||
|
em: getORM().em.fork(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return reqHandler;
|
||||||
|
}
|
32
src/services/router.ts
Normal file
32
src/services/router.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
FastifyBaseLogger,
|
||||||
|
FastifyInstance,
|
||||||
|
FastifyPluginAsync,
|
||||||
|
RawReplyDefaultExpression,
|
||||||
|
RawRequestDefaultExpression,
|
||||||
|
RawServerBase,
|
||||||
|
} from 'fastify';
|
||||||
|
import { ZodTypeProvider } from 'fastify-type-provider-zod';
|
||||||
|
|
||||||
|
export type Instance = FastifyInstance<
|
||||||
|
RawServerBase,
|
||||||
|
RawRequestDefaultExpression<RawServerBase>,
|
||||||
|
RawReplyDefaultExpression<RawServerBase>,
|
||||||
|
FastifyBaseLogger,
|
||||||
|
ZodTypeProvider
|
||||||
|
>;
|
||||||
|
export type RegisterPlugin = FastifyPluginAsync<
|
||||||
|
Record<never, never>,
|
||||||
|
RawServerBase,
|
||||||
|
ZodTypeProvider
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function makeRouter(cb: (app: Instance) => void): {
|
||||||
|
register: RegisterPlugin;
|
||||||
|
} {
|
||||||
|
return {
|
||||||
|
register: async (app) => {
|
||||||
|
cb(app);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
Reference in New Issue
Block a user