diff --git a/packages/admin/vite.config.ts b/packages/admin/vite.config.ts
index 67a8eea..5528bdb 100644
--- a/packages/admin/vite.config.ts
+++ b/packages/admin/vite.config.ts
@@ -5,8 +5,10 @@ import react from "@vitejs/plugin-react";
export default defineConfig({
root: "src",
envDir: "..",
+ base: process.env.APP_ROOT,
build: {
outDir: "../dist",
+ emptyOutDir: true,
},
plugins: [
react({
diff --git a/packages/build/Dockerfile b/packages/build/Dockerfile
new file mode 100644
index 0000000..0651cc3
--- /dev/null
+++ b/packages/build/Dockerfile
@@ -0,0 +1,18 @@
+# this file needs to be copied to /build
+
+FROM node:20-alpine
+
+RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
+WORKDIR /home/node/app
+COPY --chown=node:node . /home/node/app/
+USER node
+RUN npm install --omit=dev
+RUN npx prisma generate
+
+ENV PORT 3000
+ENV NODE_ENV production
+ENV SERVE_CLIENT /home/node/app/packages/client
+ENV SERVE_ADMIN /home/node/app/packages/admin
+
+EXPOSE 3000
+CMD [ "npm", "-w", "packages/server", "start" ]
\ No newline at end of file
diff --git a/packages/build/build-all.sh b/packages/build/build-all.sh
new file mode 100755
index 0000000..b59daa9
--- /dev/null
+++ b/packages/build/build-all.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+# builds client, admin & server into one folder
+# - client is mounted at /
+# - admin is mounted at /admin
+
+# ensure we are in packages/build
+MY_DIR="$(cd "$(dirname "$0")"; pwd)"
+OUT_DIR="$(cd "$MY_DIR/../../build"; pwd)"
+cd $MY_DIR
+
+# empty out directory
+rm -rf $OUT_DIR/*
+mkdir -p $OUT_DIR/packages/lib
+mkdir -p $OUT_DIR/packages/client
+mkdir -p $OUT_DIR/packages/admin
+mkdir -p $OUT_DIR/packages/server
+mkdir -p $OUT_DIR/prisma
+
+cp $MY_DIR/../../package.json $MY_DIR/../../package-lock.json $OUT_DIR/
+
+LIB_DIR="$MY_DIR/../../packages/lib"
+CLIENT_DIR="$MY_DIR/../../packages/client"
+ADMIN_DIR="$MY_DIR/../../packages/admin"
+SERVER_DIR="$MY_DIR/../../packages/server"
+PRISMA_DIR="$SERVER_DIR/prisma"
+
+cp -r $PRISMA_DIR/schema.prisma $PRISMA_DIR/migrations $OUT_DIR/prisma/
+
+# --- Shared Library ---
+
+echo "Building lib..."
+
+cd "$MY_DIR/../.." && npm run-script build:lib
+cd $LIB_DIR
+mv dist $OUT_DIR/packages/lib
+cp package.json $OUT_DIR/packages/lib/
+
+# janky? fix to keep imports in dev
+sed -i -e 's/"main": ".*"/"main": ".\/dist\/index.js"/' $OUT_DIR/packages/lib/package.json
+
+# --- Main Client ---
+
+echo "Building client..."
+
+cd "$MY_DIR/../.." && npm run-script build:client
+cd $CLIENT_DIR
+mv dist/* $OUT_DIR/packages/client
+rm -r dist # this dir is empty, delete it to prevent confusion
+
+# --- Admin Client ---
+
+echo "Building admin..."
+
+cd "$MY_DIR/../../" && APP_ROOT=/admin npm run-script build:admin
+cd $ADMIN_DIR
+mv dist/* $OUT_DIR/packages/admin
+rm -r dist # this dir is empty, delete it to prevent confusion
+
+# --- Server ---
+
+echo "Building server..."
+
+cd "$MY_DIR/../../" && npm run-script build:server
+cd $SERVER_DIR
+mv dist $OUT_DIR/packages/server
+cp package.json tool.sh $OUT_DIR/packages/server
+# rm -r dist # this dir is empty, delete it to prevent confusion
\ No newline at end of file
diff --git a/packages/build/docker-build.sh b/packages/build/docker-build.sh
new file mode 100755
index 0000000..28977bc
--- /dev/null
+++ b/packages/build/docker-build.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+MY_DIR="$(cd "$(dirname "$0")"; pwd)"
+OUT_DIR="$(cd "$MY_DIR/../../build"; pwd)"
+cd $MY_DIR
+
+cp Dockerfile $OUT_DIR/
+cd $OUT_DIR
+
+docker build . -t sc07/canvas
\ No newline at end of file
diff --git a/packages/client/vite.config.js b/packages/client/vite.config.js
index e37b7d9..4ebd99e 100644
--- a/packages/client/vite.config.js
+++ b/packages/client/vite.config.js
@@ -6,6 +6,7 @@ export default defineConfig({
envDir: "..",
build: {
outDir: "../dist",
+ emptyOutDir: true,
},
plugins: [
react({
diff --git a/packages/lib/package.json b/packages/lib/package.json
index 2132803..1b031a4 100644
--- a/packages/lib/package.json
+++ b/packages/lib/package.json
@@ -2,6 +2,9 @@
"name": "@sc07-canvas/lib",
"version": "1.0.0",
"main": "./src/index.ts",
+ "scripts": {
+ "build": "tsc"
+ },
"dependencies": {
"eventemitter3": "^5.0.1"
}
diff --git a/packages/lib/src/index.ts b/packages/lib/src/index.ts
index 59b11be..000a9b1 100644
--- a/packages/lib/src/index.ts
+++ b/packages/lib/src/index.ts
@@ -1,3 +1,4 @@
import * as net from "./net";
+import { CanvasLib } from "./canvas";
-export { net };
+export { net, CanvasLib };
diff --git a/packages/lib/tsconfig.json b/packages/lib/tsconfig.json
new file mode 100644
index 0000000..7bcbd1e
--- /dev/null
+++ b/packages/lib/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "@tsconfig/recommended/tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist",
+ "inlineSourceMap": true,
+ "jsx": "react",
+ "declaration": true,
+ },
+}
diff --git a/packages/server/package.json b/packages/server/package.json
index 1beb4cf..f502c9b 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -1,11 +1,14 @@
{
"name": "@sc07-canvas/server",
"version": "1.0.0",
- "main": "./build/index.js",
"scripts": {
"dev": "DOTENV_CONFIG_PATH=.env.local nodemon -r dotenv/config src/index.ts",
+ "start": "node dist/index.js",
+ "build": "tsc",
"lint": "eslint .",
- "prisma:studio": "prisma studio"
+ "prisma:studio": "prisma studio",
+ "prisma:migrate": "prisma migrate deploy",
+ "prisma:seed:palette": "./tool.sh seed_palette"
},
"keywords": [],
"author": "",
@@ -21,7 +24,6 @@
"nodemon": "^3.0.1",
"prettier": "^3.0.1",
"prisma": "^5.3.1",
- "prisma-dbml-generator": "^0.12.0",
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
},
@@ -31,6 +33,7 @@
"connect-redis": "^7.1.1",
"express": "^4.18.2",
"express-session": "^1.17.3",
+ "prisma-dbml-generator": "^0.12.0",
"redis": "^4.6.12",
"socket.io": "^4.7.2",
"winston": "^3.11.0"
diff --git a/packages/server/src/lib/Express.ts b/packages/server/src/lib/Express.ts
index fee8085..99473c3 100644
--- a/packages/server/src/lib/Express.ts
+++ b/packages/server/src/lib/Express.ts
@@ -1,4 +1,5 @@
import http from "node:http";
+import path from "node:path";
import express, { type Express } from "express";
import expressSession from "express-session";
import RedisStore from "connect-redis";
@@ -28,6 +29,49 @@ export class ExpressServer {
this.app = express();
this.httpServer = http.createServer(this.app);
+ if (process.env.SERVE_CLIENT) {
+ // client is needing to serve
+ Logger.info(
+ "Serving client UI at / using root " +
+ path.join(__dirname, process.env.SERVE_CLIENT)
+ );
+ this.app.use(express.static(process.env.SERVE_CLIENT));
+ } else {
+ this.app.get("/", (req, res) => {
+ res.status(404).contentType("html").send(`
+
+
+ Canvas Server
+
+
+ Canvas Server
+ This instance is not serving the client
+ This instance might not be configured correctly
+
+
+ `);
+ });
+ }
+
+ if (process.env.SERVE_ADMIN) {
+ // client is needing to serve
+ Logger.info(
+ "Serving admin UI at /admin using root " +
+ path.join(__dirname, process.env.SERVE_ADMIN)
+ );
+ const assetsDir = path.join(__dirname, process.env.SERVE_ADMIN, "assets");
+ const indexFile = path.join(
+ __dirname,
+ process.env.SERVE_ADMIN,
+ "index.html"
+ );
+
+ this.app.use("/admin/assets", express.static(assetsDir));
+ this.app.use("/admin/*", (req, res) => {
+ res.sendFile(indexFile);
+ });
+ }
+
this.app.use(session);
this.app.use("/api", APIRoutes);
diff --git a/packages/server/src/models/User.ts b/packages/server/src/models/User.ts
index e1ab2ca..e3486cb 100644
--- a/packages/server/src/models/User.ts
+++ b/packages/server/src/models/User.ts
@@ -71,12 +71,20 @@ export class User {
return Date.now() - this._updatedAt >= 1000 * 60;
}
- static async fromAuthSession(auth: AuthSession): Promise {
- const user = await this.fromSub(
- auth.user.username + "@" + auth.service.instance.hostname
- );
- user.authSession = auth;
- return user;
+ static async fromAuthSession(auth: AuthSession): Promise {
+ try {
+ const user = await this.fromSub(
+ auth.user.username + "@" + auth.service.instance.hostname
+ );
+ user.authSession = auth;
+ return user;
+ } catch (e) {
+ if (e instanceof UserNotFound) {
+ return undefined;
+ } else {
+ throw e;
+ }
+ }
}
static async fromSub(sub: string): Promise {
diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts
index 8c20f35..5911e63 100644
--- a/packages/server/src/types.ts
+++ b/packages/server/src/types.ts
@@ -31,6 +31,15 @@ declare global {
* Specifically setting CORS origin is required because of use of credentials (cookies)
*/
CLIENT_ORIGIN?: string;
+
+ /**
+ * If set, use this relative path to serve the client at the root
+ */
+ SERVE_CLIENT?: string;
+ /**
+ * If set, use this relative path to serve the admin UI at /admin
+ */
+ SERVE_ADMIN?: string;
}
}
}
diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json
index 42c5ace..688d497 100644
--- a/packages/server/tsconfig.json
+++ b/packages/server/tsconfig.json
@@ -2,6 +2,7 @@
"extends": "@tsconfig/recommended/tsconfig.json",
"compilerOptions": {
"rootDir": "src",
- "outDir": "build"
- }
+ "outDir": "dist",
+ "inlineSourceMap": true,
+ },
}