Skip to content

Commit

Permalink
Merge pull request #6 from ckb-cell/develop
Browse files Browse the repository at this point in the history
feat:  authentication and docker files
  • Loading branch information
ahonn authored Mar 20, 2024
2 parents 39131c5 + 0bb617a commit e845ac1
Show file tree
Hide file tree
Showing 23 changed files with 303 additions and 176 deletions.
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.vercel
coverage
dist
node_modules
.env
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
JWT_SECRET=
REDIS_URL=

ADMIN_USERNAME=
ADMIN_PASSWORD=

BITCOIN_JSON_RPC_URL=
BITCOIN_JSON_RPC_USERNAME=
BITCOIN_JSON_RPC_PASSWORD=
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
pull_request:
branches:
- main
- develop

jobs:
test:
Expand Down
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM node:20-slim

WORKDIR /app

COPY . .

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable pnpm

RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build

EXPOSE 3000
ENV ADDRESS=0.0.0.0 PORT=3000
CMD ["pnpm", "start"]
27 changes: 27 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: '3.8'

services:
app:
build:
context: .
ports:
- '3000:3000'
environment:
- REDIS_URL=redis://redis:6379
- JWT_SECRET=
- ADMIN_USERNAME=
- ADMIN_PASSWORD=
- BITCOIN_JSON_RPC_URL=
- BITCOIN_JSON_RPC_USERNAME=
- BITCOIN_JSON_RPC_PASSWORD=
- BITCOIN_ELECTRS_API_URL=
depends_on:
- redis

redis:
image: redis:latest
ports:
- '6379:6379'
volumes:
- ./data:/root/redis
- ./redis.conf:/usr/local/etc/redis/redis.conf
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@
"@fastify/sensible": "^5.5.0",
"@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^3.0.0",
"@fastify/type-provider-typebox": "^4.0.0",
"@sentry/node": "^7.102.1",
"@sentry/profiling-node": "^7.102.1",
"@sinclair/typebox": "^0.32.14",
"awilix": "^10.0.1",
"axios": "^1.6.7",
"dotenv": "^16.4.2",
"fastify": "^4.26.0",
"fastify-plugin": "^4.5.1",
"fastify-type-provider-zod": "^1.1.9",
"ioredis": "^5.3.2",
"lodash": "^4.17.21",
"multicoin-address-validator": "^0.5.16",
"pino": "^8.19.0",
"std-env": "^3.7.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/ioredis-mock": "^8.2.5",
"@types/lodash": "^4.17.0",
"@types/multicoin-address-validator": "^0.5.2",
"@types/node": "^20.11.17",
"@typescript-eslint/eslint-plugin": "^6.21.0",
Expand Down
58 changes: 39 additions & 19 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import swagger from './plugins/swagger';
import jwt from './plugins/jwt';
import cache from './plugins/cache';
import rateLimit from './plugins/rate-limit';
import { env } from './env';
import { env, getSafeEnvs } from './env';
import container from './container';
import { asValue } from 'awilix';
import options from './options';
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
import { serializerCompiler, validatorCompiler, ZodTypeProvider } from 'fastify-type-provider-zod';
import cors from './plugins/cors';

if (env.SENTRY_DSN_URL && env.NODE_ENV !== 'development') {
Expand All @@ -27,7 +27,11 @@ if (env.SENTRY_DSN_URL && env.NODE_ENV !== 'development') {
});
}

const isTokenRoutesEnable = env.NODE_ENV === 'production' ? env.ADMIN_USERNAME && env.ADMIN_PASSWORD : true;

async function routes(fastify: FastifyInstance) {
fastify.log.info(`Process env: ${JSON.stringify(getSafeEnvs(), null, 2)}`);

container.register({ logger: asValue(fastify.log) });
fastify.decorate('container', container);

Expand All @@ -39,7 +43,9 @@ async function routes(fastify: FastifyInstance) {
fastify.register(cache);
fastify.register(rateLimit);

fastify.register(tokenRoutes, { prefix: '/token' });
if (isTokenRoutesEnable) {
fastify.register(tokenRoutes, { prefix: '/token' });
}
fastify.register(bitcoinRoutes, { prefix: '/bitcoin/v1' });

fastify.setErrorHandler((error, _, reply) => {
Expand All @@ -55,7 +61,9 @@ async function routes(fastify: FastifyInstance) {
}

export function buildFastify() {
const app = fastify(options).withTypeProvider<TypeBoxTypeProvider>();
const app = fastify(options).withTypeProvider<ZodTypeProvider>();
app.setValidatorCompiler(validatorCompiler);
app.setSerializerCompiler(serializerCompiler);
app.register(routes);
return app;
}
8 changes: 8 additions & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import 'dotenv/config';
import z from 'zod';
import process from 'node:process';
import { omit } from 'lodash';

const envSchema = z.object({
NODE_ENV: z.string().default('development'),
PORT: z.string().optional(),
ADDRESS: z.string().optional(),
NETWORK: z.string().default('testnet'),

SENTRY_DSN_URL: z.string().optional(),
REDIS_URL: z.string().optional(),
RATE_LIMIT_PER_MINUTE: z.number().default(100),

ADMIN_USERNAME: z.string().optional(),
ADMIN_PASSWORD: z.string().optional(),

/**
* JWT_SECRET is used to sign the JWT token for authentication.
*/
Expand All @@ -31,3 +37,5 @@ const envSchema = z.object({

export type Env = z.infer<typeof envSchema>;
export const env = envSchema.parse(process.env);

export const getSafeEnvs = () => omit(env, ['ADMIN_PASSWORD', 'JWT_SECRET', 'BITCOIN_JSON_RPC_PASSWORD']);
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { env } from './env';
import { buildFastify } from './app';

const port = parseInt(env.PORT || '3000', 10);
const host = env.ADDRESS || '0.0.0.0';

const app = buildFastify();

app.listen({ port }, (err, address) => {
app.listen({ port, host }, (err, address) => {
if (err) {
console.error(err);
process.exit(1);
Expand Down
24 changes: 14 additions & 10 deletions src/options.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { FastifyBaseLogger, FastifyHttpOptions } from 'fastify';
import { provider } from 'std-env';
import { Server } from 'http';
import { env } from './env';

const envToLogger = {
development: {
transport: {
target: 'pino-pretty',
options: {
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
},
},
},
development:
provider !== 'vercel'
? {
transport: {
target: 'pino-pretty',
options: {
translateTime: 'HH:MM:ss Z',
ignore: 'pid,hostname',
},
},
}
: true,
production: true,
}
};

const options: FastifyHttpOptions<Server, FastifyBaseLogger> = {
logger: envToLogger[env.NODE_ENV as keyof typeof envToLogger],
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default fp(async (fastify) => {
return;
}

fastify.register(import('@fastify/redis'), { client: redis });
await fastify.register(import('@fastify/redis'), { client: redis });

fastify.addHook('onRequest', (request, reply, done) => {
if (request.url.startsWith(DOCS_ROUTE_PREFIX)) {
Expand Down
Loading

0 comments on commit e845ac1

Please sign in to comment.