feat: open page api

This commit is contained in:
Ephraim Atta-Duncan
2024-10-23 17:33:16 +00:00
parent b8310237e4
commit 68c8f098b6
15 changed files with 281 additions and 36 deletions

View File

@@ -1,36 +1 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3002](http://localhost:3002) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
# @documenso/documentation

40
apps/openpage-api/.gitignore vendored Normal file
View File

@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for commiting if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -0,0 +1 @@
# @documenso/openpage-api

View File

@@ -0,0 +1,12 @@
import { NextResponse } from 'next/server';
import { requestHandler } from '@/app/request-handler';
export const GET = requestHandler(async () => {
const res = await fetch('https://api.github.com/repos/documenso/documenso');
const { forks_count } = await res.json();
return NextResponse.json({
data: forks_count,
});
});

View File

@@ -0,0 +1,14 @@
import { NextResponse } from 'next/server';
import { requestHandler } from '@/app/request-handler';
export const GET = requestHandler(async () => {
const res = await fetch(
'https://api.github.com/search/issues?q=repo:documenso/documenso+type:issue+state:open&page=0&per_page=1',
);
const { total_count } = await res.json();
return NextResponse.json({
data: total_count,
});
});

View File

@@ -0,0 +1,14 @@
import { NextResponse } from 'next/server';
import { requestHandler } from '@/app/request-handler';
export const GET = requestHandler(async () => {
const res = await fetch(
'https://api.github.com/search/issues?q=repo:documenso/documenso/+is:pr+merged:>=2010-01-01&page=0&per_page=1',
);
const { total_count } = await res.json();
return NextResponse.json({
data: total_count,
});
});

View File

@@ -0,0 +1,17 @@
import { type NextRequest, NextResponse } from 'next/server';
const paths = [
{ path: '/forks', description: 'GitHub Forks' },
{ path: '/stars', description: 'GitHub Stars' },
{ path: '/issues', description: 'GitHub Merged Issues' },
{ path: '/prs', description: 'GitHub Pull Request' },
];
export function GET(request: NextRequest) {
const url = request.nextUrl.toString();
const apis = paths.map(({ path, description }) => {
return { path: url + path, description };
});
return NextResponse.json(apis);
}

View File

@@ -0,0 +1,12 @@
import { NextResponse } from 'next/server';
import { requestHandler } from '@/app/request-handler';
export const GET = requestHandler(async () => {
const res = await fetch('https://api.github.com/repos/documenso/documenso');
const { stargazers_count } = await res.json();
return NextResponse.json({
data: stargazers_count,
});
});

View File

@@ -0,0 +1,43 @@
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
type RouteHandler<T = Record<string, string | string[]>> = (
req: NextRequest,
ctx: { params: T },
) => Promise<Response> | Response;
function isAllowedOrigin(req: NextRequest): boolean {
const referer = req.headers.get('referer');
const host = req.headers.get('host');
if (referer && host) {
const refererUrl = new URL(referer);
return refererUrl.host === host;
}
if (host?.includes('localhost')) {
return true;
}
return false;
}
export function requestHandler<T = Record<string, string | string[]>>(
handler: RouteHandler<T>,
): RouteHandler<T> {
return async (req: NextRequest, ctx: { params: T }) => {
try {
if (!isAllowedOrigin(req)) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const result = await handler(req, ctx);
return result;
} catch (error) {
console.log(error);
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
}
};
}

View File

@@ -0,0 +1,20 @@
import { type NextRequest, NextResponse } from 'next/server';
const paths = [{ path: 'github', description: 'GitHub Data' }];
export function GET(request: NextRequest) {
const url = request.nextUrl.toString();
const apis = paths.map(({ path, description }) => {
return { path: url + path, description };
});
return NextResponse.json(apis, {
status: 200,
headers: {
// TODO: Update for marketing page
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
},
});
}

View File

@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
module.exports = nextConfig;

View File

@@ -0,0 +1,21 @@
{
"name": "@documenso/openpage-api",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3003",
"build": "next build",
"start": "next start",
"lint:fix": "next lint --fix",
"clean": "rimraf .next && rimraf node_modules",
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
},
"dependencies": {
"next": "14.2.6"
},
"devDependencies": {
"@types/node": "20.16.5",
"@types/react": "18.3.5",
"typescript": "5.5.4"
}
}

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

54
package-lock.json generated
View File

@@ -439,6 +439,56 @@
"node": ">=14.17"
}
},
"apps/openpage-api": {
"name": "@documenso/openpage-api",
"version": "1.0.0",
"dependencies": {
"next": "14.2.6"
},
"devDependencies": {
"@types/node": "20.16.5",
"@types/react": "18.3.5",
"typescript": "5.5.4"
}
},
"apps/openpage-api/node_modules/@types/node": {
"version": "20.16.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
"dev": true,
"dependencies": {
"undici-types": "~6.19.2"
}
},
"apps/openpage-api/node_modules/@types/react": {
"version": "18.3.5",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz",
"integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==",
"dev": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"apps/openpage-api/node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"apps/openpage-api/node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true
},
"apps/web": {
"name": "@documenso/web",
"version": "1.7.2-rc.1",
@@ -2671,6 +2721,10 @@
"nodemailer": "^6.9.3"
}
},
"node_modules/@documenso/openpage-api": {
"resolved": "apps/openpage-api",
"link": true
},
"node_modules/@documenso/pdf-sign": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@documenso/pdf-sign/-/pdf-sign-0.1.0.tgz",

View File

@@ -8,6 +8,7 @@
"dev:web": "turbo run dev --filter=@documenso/web",
"dev:marketing": "turbo run dev --filter=@documenso/marketing",
"dev:docs": "turbo run dev --filter=@documenso/documentation",
"dev:openpage-api": "turbo run dev --filter=@documenso/openpage-api",
"start": "turbo run start --filter=@documenso/web --filter=@documenso/marketing --filter=@documenso/documentation",
"lint": "turbo run lint",
"lint:fix": "turbo run lint:fix",