mirror of
https://github.com/documenso/documenso.git
synced 2026-07-09 04:24:59 +10:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84ad7a6c2b |
@@ -6,4 +6,4 @@
|
||||
/build/
|
||||
|
||||
# Vite
|
||||
vite.config.ts.timestamp*
|
||||
vite.config.*.timestamp*
|
||||
@@ -1,8 +1 @@
|
||||
@import '@documenso/ui/styles/theme.css';
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--font-sans: 'Inter';
|
||||
--font-signature: 'Caveat';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,6 @@ export const links: Route.LinksFunction = () => [
|
||||
rel: 'stylesheet',
|
||||
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
|
||||
},
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href: 'https://fonts.googleapis.com/css2?family=Caveat:wght@400..600&display=swap',
|
||||
},
|
||||
{ rel: 'stylesheet', href: stylesheet },
|
||||
];
|
||||
|
||||
|
||||
@@ -8,12 +8,6 @@ export function meta({}: Route.MetaArgs) {
|
||||
];
|
||||
}
|
||||
|
||||
export const loader = () => {
|
||||
return {
|
||||
message: 'Hello World' as const,
|
||||
};
|
||||
};
|
||||
|
||||
export default function Home() {
|
||||
return <Welcome />;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"name": "@documenso/remix",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production react-router build",
|
||||
"dev": "tsx watch --ignore \"vite.config.ts*\" server/main.ts",
|
||||
"dev": "tsx watch --ignore \"vite.config.{ts,mts,js,mjs}*\" server/main.ts",
|
||||
"start": "cross-env NODE_ENV=production node dist/server/index.js",
|
||||
"typecheck": "react-router typegen && tsc"
|
||||
},
|
||||
|
||||
+25
-17
@@ -3,15 +3,17 @@ import { type HttpBindings } from '@hono/node-server';
|
||||
import { Hono } from 'hono';
|
||||
import { reactRouter } from 'remix-hono/handler';
|
||||
|
||||
type Bindings = HttpBindings;
|
||||
import { IS_APP_WEB } from '@documenso/lib/constants/app';
|
||||
|
||||
const app = new Hono<{ Bindings: Bindings }>();
|
||||
console.log({ IS_APP_WEB });
|
||||
|
||||
type Bindings = HttpBindings;
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const viteDevServer = isProduction
|
||||
? undefined
|
||||
: await import('vite').then(async (vite) =>
|
||||
: import('vite').then(async (vite) =>
|
||||
vite.createServer({
|
||||
server: { middlewareMode: true },
|
||||
}),
|
||||
@@ -23,23 +25,29 @@ const reactRouterMiddleware = remember('reactRouterMiddleware', async () =>
|
||||
build: isProduction
|
||||
? // @ts-expect-error build/server/index.js is a build artifact
|
||||
await import('../build/server/index.js')
|
||||
: async () => viteDevServer!.ssrLoadModule('virtual:react-router/server-build'),
|
||||
: async () => (await viteDevServer)!.ssrLoadModule('virtual:react-router/server-build'),
|
||||
}),
|
||||
);
|
||||
|
||||
// app.get('/', (c) => c.text('Hello, world!'));
|
||||
if (viteDevServer) {
|
||||
app.use('*', async (c, next) => {
|
||||
return new Promise((resolve) => {
|
||||
viteDevServer.middlewares(c.env.incoming, c.env.outgoing, () => resolve(next()));
|
||||
export const getApp = async () => {
|
||||
const app = new Hono<{ Bindings: Bindings }>();
|
||||
|
||||
const resolvedDevServer = await viteDevServer;
|
||||
|
||||
// app.get('/', (c) => c.text('Hello, world!'));
|
||||
if (resolvedDevServer) {
|
||||
app.use('*', async (c, next) => {
|
||||
return new Promise((resolve) => {
|
||||
resolvedDevServer.middlewares(c.env.incoming, c.env.outgoing, () => resolve(next()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
app.use('*', async (c, next) => {
|
||||
const middleware = await reactRouterMiddleware;
|
||||
|
||||
return middleware(c, next);
|
||||
});
|
||||
}
|
||||
|
||||
app.use('*', async (c, next) => {
|
||||
const middleware = await reactRouterMiddleware;
|
||||
|
||||
return middleware(c, next);
|
||||
});
|
||||
|
||||
export default app;
|
||||
return app;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { serve } from '@hono/node-server';
|
||||
|
||||
import app from './app';
|
||||
import { getApp } from './app';
|
||||
|
||||
serve(app, (info) => {
|
||||
console.log(`Server is running on http://localhost:${info.port}`);
|
||||
async function main() {
|
||||
const app = await getApp();
|
||||
|
||||
serve(app, (info) => {
|
||||
console.log(`Server is running on http://localhost:${info.port}`);
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('Failed to start server:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -6,22 +6,35 @@
|
||||
".react-router/types/**/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
"types": ["node", "vite/client"],
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ES2022"
|
||||
],
|
||||
"types": [
|
||||
"node",
|
||||
"vite/client"
|
||||
],
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "bundler",
|
||||
"jsx": "react-jsx",
|
||||
"rootDirs": [".", "./.react-router/types"],
|
||||
"rootDirs": [
|
||||
".",
|
||||
"./.react-router/types"
|
||||
],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./app/*"]
|
||||
"~/*": [
|
||||
"./app/*"
|
||||
]
|
||||
},
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
"moduleDetection": "force",
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// @ts-expect-error This is just due to our root config, it's a non-issue
|
||||
import { reactRouter } from '@react-router/dev/vite';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
Generated
-35
@@ -2767,10 +2767,6 @@
|
||||
"resolved": "packages/assets",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@documenso/auth": {
|
||||
"resolved": "packages/auth",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@documenso/documentation": {
|
||||
"resolved": "apps/documentation",
|
||||
"link": true
|
||||
@@ -36166,37 +36162,6 @@
|
||||
"name": "@documenso/assets",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"packages/auth": {
|
||||
"name": "@documenso/auth",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@documenso/prisma": "*",
|
||||
"hono": "^4.6.15",
|
||||
"luxon": "^3.5.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"ts-pattern": "^5.0.5",
|
||||
"zod": "3.24.1"
|
||||
}
|
||||
},
|
||||
"packages/auth/node_modules/nanoid": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz",
|
||||
"integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18"
|
||||
}
|
||||
},
|
||||
"packages/ee": {
|
||||
"name": "@documenso/ee",
|
||||
"version": "0.0.0",
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { Hono } from 'hono';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AuthenticationErrorCode } from './server/error-codes';
|
||||
import { AuthenticationError } from './server/errors';
|
||||
import { getSession } from './server/lib/session';
|
||||
|
||||
export const auth = new Hono();
|
||||
|
||||
auth.get('/session', async (c) => {
|
||||
const authorization = c.req.header('Authorization');
|
||||
|
||||
const userAgent = c.req.header('User-Agent');
|
||||
const ipAddress = c.req.header('X-Forwarded-For');
|
||||
|
||||
if (!authorization) {
|
||||
return new AuthenticationError(
|
||||
AuthenticationErrorCode.MissingToken,
|
||||
'Missing authorization header',
|
||||
).toHonoResponse(c);
|
||||
}
|
||||
|
||||
// Add your session validation logic here
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars, prefer-const
|
||||
let { session, user } = await getSession(authorization);
|
||||
|
||||
const diff = DateTime.fromJSDate(session.expires).diffNow('days');
|
||||
|
||||
if (diff.days <= 3) {
|
||||
session = await prisma.session.update({
|
||||
where: {
|
||||
id: session.id,
|
||||
},
|
||||
data: {
|
||||
expires: DateTime.now().plus({ days: 7 }).toJSDate(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
session,
|
||||
user,
|
||||
});
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
export * from './handler';
|
||||
export * from './server/errors';
|
||||
export * from './server/error-codes';
|
||||
export * from './server/middleware';
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "@documenso/auth",
|
||||
"version": "0.0.0",
|
||||
"main": "./index.ts",
|
||||
"types": "./index.ts",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"clean": "rimraf node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@documenso/prisma": "*",
|
||||
"hono": "^4.6.15",
|
||||
"luxon": "^3.5.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"ts-pattern": "^5.0.5",
|
||||
"zod": "3.24.1"
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { ContentfulStatusCode } from 'hono/utils/http-status';
|
||||
|
||||
export const AuthenticationErrorCode = {
|
||||
Unauthorized: 'UNAUTHORIZED',
|
||||
InvalidCredentials: 'INVALID_CREDENTIALS',
|
||||
SessionNotFound: 'SESSION_NOT_FOUND',
|
||||
SessionExpired: 'SESSION_EXPIRED',
|
||||
InvalidToken: 'INVALID_TOKEN',
|
||||
MissingToken: 'MISSING_TOKEN',
|
||||
} as const;
|
||||
|
||||
export type AuthenticationErrorCode =
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
(typeof AuthenticationErrorCode)[keyof typeof AuthenticationErrorCode] | (string & {});
|
||||
|
||||
export const ErrorStatusMap: Record<AuthenticationErrorCode, ContentfulStatusCode> = {
|
||||
[AuthenticationErrorCode.Unauthorized]: 401,
|
||||
[AuthenticationErrorCode.InvalidCredentials]: 401,
|
||||
[AuthenticationErrorCode.SessionNotFound]: 401,
|
||||
[AuthenticationErrorCode.SessionExpired]: 401,
|
||||
[AuthenticationErrorCode.InvalidToken]: 401,
|
||||
[AuthenticationErrorCode.MissingToken]: 400,
|
||||
};
|
||||
|
||||
export function getErrorStatus(code: AuthenticationErrorCode) {
|
||||
return ErrorStatusMap[code] ?? 400;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import type { Context } from 'hono';
|
||||
import type { ContentfulStatusCode } from 'hono/utils/http-status';
|
||||
|
||||
import type { AuthenticationErrorCode } from './error-codes';
|
||||
import { getErrorStatus } from './error-codes';
|
||||
|
||||
interface ErrorResponse {
|
||||
error: string;
|
||||
message: string;
|
||||
stack?: string;
|
||||
}
|
||||
|
||||
export class AuthenticationError extends Error {
|
||||
code: AuthenticationErrorCode;
|
||||
statusCode: ContentfulStatusCode;
|
||||
|
||||
constructor(code: AuthenticationErrorCode, message?: string, statusCode?: ContentfulStatusCode) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.name = 'AuthenticationError';
|
||||
// Use provided status code or look it up from the map
|
||||
this.statusCode = statusCode ?? getErrorStatus(code);
|
||||
}
|
||||
|
||||
toJSON(): ErrorResponse {
|
||||
return {
|
||||
error: this.code,
|
||||
message: this.message,
|
||||
...(process.env.NODE_ENV === 'development' && { stack: this.stack }),
|
||||
};
|
||||
}
|
||||
|
||||
toHonoResponse(c: Context) {
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
...this.toJSON(),
|
||||
},
|
||||
this.statusCode,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AuthenticationErrorCode } from '../error-codes';
|
||||
import { AuthenticationError } from '../errors';
|
||||
|
||||
export const getSession = async (token: string) => {
|
||||
const result = await prisma.session.findUnique({
|
||||
where: {
|
||||
sessionToken: token,
|
||||
},
|
||||
include: {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
throw new AuthenticationError(AuthenticationErrorCode.SessionNotFound);
|
||||
}
|
||||
|
||||
if (result.expires < new Date()) {
|
||||
throw new AuthenticationError(AuthenticationErrorCode.SessionExpired);
|
||||
}
|
||||
|
||||
const { user, ...session } = result;
|
||||
|
||||
return {
|
||||
session,
|
||||
user,
|
||||
};
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
const sessionTokenId = customAlphabet('abcdefhiklmnorstuvwxz', 10);
|
||||
|
||||
export const createSessionToken = (length = 10) => `session_${sessionTokenId(length)}` as const;
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "@documenso/tsconfig/react-library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"],
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user