From 14d95eb8fe6377ba578780213f8436bb5e456627 Mon Sep 17 00:00:00 2001 From: Ishaan Dey Date: Sun, 21 Apr 2024 22:55:49 -0400 Subject: [PATCH] improve backend logic --- .../database/drizzle/0004_fantastic_venom.sql | 1 + .../database/drizzle/meta/0004_snapshot.json | 126 ++++++++++++++++++ backend/database/drizzle/meta/_journal.json | 7 + backend/database/package-lock.json | 56 ++++++-- backend/database/package.json | 3 +- backend/database/src/index.ts | 2 + backend/database/src/schema.ts | 1 + backend/server/dist/index.js | 47 +++++-- backend/server/dist/types.js | 3 + backend/server/src/index.ts | 63 +++++++-- backend/server/src/types.ts | 17 +++ frontend/lib/types.ts | 1 + 12 files changed, 296 insertions(+), 31 deletions(-) create mode 100644 backend/database/drizzle/0004_fantastic_venom.sql create mode 100644 backend/database/drizzle/meta/0004_snapshot.json create mode 100644 backend/server/dist/types.js create mode 100644 backend/server/src/types.ts diff --git a/backend/database/drizzle/0004_fantastic_venom.sql b/backend/database/drizzle/0004_fantastic_venom.sql new file mode 100644 index 0000000..cb39826 --- /dev/null +++ b/backend/database/drizzle/0004_fantastic_venom.sql @@ -0,0 +1 @@ +ALTER TABLE sandbox ADD `init` integer DEFAULT false; \ No newline at end of file diff --git a/backend/database/drizzle/meta/0004_snapshot.json b/backend/database/drizzle/meta/0004_snapshot.json new file mode 100644 index 0000000..2326fd1 --- /dev/null +++ b/backend/database/drizzle/meta/0004_snapshot.json @@ -0,0 +1,126 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "d6bdd707-d4ac-4a04-9052-aa97d5452e4a", + "prevId": "90f199c9-66a1-4c89-9a19-f7fbd5a35236", + "tables": { + "sandbox": { + "name": "sandbox", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "init": { + "name": "init", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sandbox_id_unique": { + "name": "sandbox_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "sandbox_user_id_user_id_fk": { + "name": "sandbox_user_id_user_id_fk", + "tableFrom": "sandbox", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_unique": { + "name": "user_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/backend/database/drizzle/meta/_journal.json b/backend/database/drizzle/meta/_journal.json index fb07bbb..a69d7ad 100644 --- a/backend/database/drizzle/meta/_journal.json +++ b/backend/database/drizzle/meta/_journal.json @@ -29,6 +29,13 @@ "when": 1713412439820, "tag": "0003_outgoing_hammerhead", "breakpoints": true + }, + { + "idx": 4, + "version": "5", + "when": 1713753819469, + "tag": "0004_fantastic_venom", + "breakpoints": true } ] } \ No newline at end of file diff --git a/backend/database/package-lock.json b/backend/database/package-lock.json index 35c888b..ebb9ed3 100644 --- a/backend/database/package-lock.json +++ b/backend/database/package-lock.json @@ -12,6 +12,7 @@ "better-sqlite3": "^9.5.0", "cross-env": "^7.0.3", "drizzle-orm": "^0.30.8", + "itty-router": "^5.0.16", "itty-router-extras": "^0.4.6", "zod": "^3.22.4" }, @@ -19,7 +20,7 @@ "@cloudflare/vitest-pool-workers": "^0.1.0", "@cloudflare/workers-types": "^4.20240405.0", "@types/itty-router-extras": "^0.4.3", - "drizzle-kit": "^0.20.14", + "drizzle-kit": "^0.20.17", "typescript": "^5.0.4", "vitest": "1.3.0", "wrangler": "^3.0.0" @@ -152,15 +153,6 @@ "node": ">=12" } }, - "node_modules/@drizzle-team/studio": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.39.tgz", - "integrity": "sha512-c5Hkm7MmQC2n5qAsKShjQrHoqlfGslB8+qWzsGGZ+2dHMRTNG60UuzalF0h0rvBax5uzPXuGkYLGaQ+TUX3yMw==", - "dev": true, - "dependencies": { - "superjson": "^2.2.1" - } - }, "node_modules/@esbuild-kit/core-utils": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", @@ -969,6 +961,25 @@ "node": ">=14" } }, + "node_modules/@hono/node-server": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.11.0.tgz", + "integrity": "sha512-TLIJq9TMtD1NEG1mVoqNUn1Ita0qSaB5XboZErjFBcO/GJYXwWY4dVdTi9G0lbxtu0x+hJXDItcLaFHb7rlFTw==", + "dev": true, + "engines": { + "node": ">=18.14.1" + } + }, + "node_modules/@hono/zod-validator": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.2.1.tgz", + "integrity": "sha512-HFoxln7Q6JsE64qz2WBS28SD33UB2alp3aRKmcWnNLDzEL1BLsWfbdX6e1HIiUprHYTIXf5y7ax8eYidKUwyaA==", + "dev": true, + "peerDependencies": { + "hono": ">=3.9.0", + "zod": "^3.19.1" + } + }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -1852,13 +1863,14 @@ } }, "node_modules/drizzle-kit": { - "version": "0.20.14", - "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.20.14.tgz", - "integrity": "sha512-0fHv3YIEaUcSVPSGyaaBfOi9bmpajjhbJNdPsRMIUvYdLVxBu9eGjH8mRc3Qk7HVmEidFc/lhG1YyJhoXrn5yA==", + "version": "0.20.17", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.20.17.tgz", + "integrity": "sha512-mLVDS4nXmO09wFVlzGrdshWnAL+U9eQGC5zRs6hTN6Q9arwQGWU2XnZ17I8BM8Quau8CQRx3Ms6VPgRWJFVp7Q==", "dev": true, "dependencies": { - "@drizzle-team/studio": "^0.0.39", "@esbuild-kit/esm-loader": "^2.5.5", + "@hono/node-server": "^1.9.0", + "@hono/zod-validator": "^0.2.0", "camelcase": "^7.0.1", "chalk": "^5.2.0", "commander": "^9.4.1", @@ -1867,9 +1879,11 @@ "esbuild-register": "^3.5.0", "glob": "^8.1.0", "hanji": "^0.0.5", + "hono": "^4.1.4", "json-diff": "0.9.0", "minimatch": "^7.4.3", "semver": "^7.5.4", + "superjson": "^2.2.1", "zod": "^3.20.2" }, "bin": { @@ -2798,6 +2812,15 @@ "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", "dev": true }, + "node_modules/hono": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.2.6.tgz", + "integrity": "sha512-AtbHZJYWsm+uFHLz0C6xltX7hjOV44a55gSEGBfoQOJ00KSxEUOoiIkmd+NXfapNX0j2GCKhqMmYeegBdHRwcQ==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -2935,6 +2958,11 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/itty-router": { + "version": "5.0.16", + "resolved": "https://registry.npmjs.org/itty-router/-/itty-router-5.0.16.tgz", + "integrity": "sha512-Kzk07Cx1dXvwtbCVeLvIT7W9uQaJc3UdWb6L57aSt8usqAWpQJziH3UgSWw2k7up00ImPeNACXY7zHE7eEPd7w==" + }, "node_modules/itty-router-extras": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/itty-router-extras/-/itty-router-extras-0.4.6.tgz", diff --git a/backend/database/package.json b/backend/database/package.json index d102689..6aae34c 100644 --- a/backend/database/package.json +++ b/backend/database/package.json @@ -15,7 +15,7 @@ "@cloudflare/vitest-pool-workers": "^0.1.0", "@cloudflare/workers-types": "^4.20240405.0", "@types/itty-router-extras": "^0.4.3", - "drizzle-kit": "^0.20.14", + "drizzle-kit": "^0.20.17", "typescript": "^5.0.4", "vitest": "1.3.0", "wrangler": "^3.0.0" @@ -25,6 +25,7 @@ "better-sqlite3": "^9.5.0", "cross-env": "^7.0.3", "drizzle-orm": "^0.30.8", + "itty-router": "^5.0.16", "itty-router-extras": "^0.4.6", "zod": "^3.22.4" } diff --git a/backend/database/src/index.ts b/backend/database/src/index.ts index 39349e0..4dbe97d 100644 --- a/backend/database/src/index.ts +++ b/backend/database/src/index.ts @@ -13,6 +13,8 @@ export interface Env { DB: D1Database; } +// https://github.com/drizzle-team/drizzle-orm/tree/main/examples/cloudflare-d1 + export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { const url = new URL(request.url); diff --git a/backend/database/src/schema.ts b/backend/database/src/schema.ts index bf8e49d..bf33478 100644 --- a/backend/database/src/schema.ts +++ b/backend/database/src/schema.ts @@ -25,6 +25,7 @@ export const sandbox = sqliteTable("sandbox", { name: text("name").notNull(), type: text("type", { enum: ["react", "node"] }).notNull(), bucket: text("bucket"), + init: integer("init", { mode: "boolean" }).default(false), userId: text("user_id") .notNull() .references(() => user.id), diff --git a/backend/server/dist/index.js b/backend/server/dist/index.js index 663c20f..71a67f8 100644 --- a/backend/server/dist/index.js +++ b/backend/server/dist/index.js @@ -16,6 +16,7 @@ const express_1 = __importDefault(require("express")); const dotenv_1 = __importDefault(require("dotenv")); const http_1 = require("http"); const socket_io_1 = require("socket.io"); +const zod_1 = require("zod"); dotenv_1.default.config(); const app = (0, express_1.default)(); const port = process.env.PORT || 4000; @@ -26,24 +27,54 @@ const io = new socket_io_1.Server(httpServer, { origin: "*", }, }); +const handshakeSchema = zod_1.z.object({ + userId: zod_1.z.string(), + sandboxId: zod_1.z.string(), + type: zod_1.z.enum(["node", "react"]), + EIO: zod_1.z.string(), + transport: zod_1.z.string(), +}); io.use((socket, next) => __awaiter(void 0, void 0, void 0, function* () { const q = socket.handshake.query; console.log("middleware"); - console.log(q); - if (!q.userId || !q.sandboxId) { + const parseQuery = handshakeSchema.safeParse(q); + if (!parseQuery.success) { + console.log("Invalid request."); next(new Error("Invalid request.")); + return; } - const dbUser = yield fetch(`http://localhost:8787/api/user?id=${q.userId}`); - const dbUserJSON = yield dbUser.json(); - if (!dbUserJSON || !dbUserJSON.sandbox.includes(q.sandboxId)) { + const query = parseQuery.data; + const dbUser = yield fetch(`http://localhost:8787/api/user?id=${query.userId}`); + const dbUserJSON = (yield dbUser.json()); + console.log("dbUserJSON:", dbUserJSON); + if (!dbUserJSON) { + console.log("DB error."); + next(new Error("DB error.")); + return; + } + const sandbox = dbUserJSON.sandbox.find((s) => s.id === query.sandboxId); + if (!sandbox) { + console.log("Invalid credentials."); next(new Error("Invalid credentials.")); + return; } + const data = { + userId: query.userId, + sandboxId: query.sandboxId, + type: query.type, + init: sandbox.init, + }; + socket.data = data; next(); })); io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () { - console.log(`connection`); - const userId = socket.handshake.query.userId; - console.log(userId); + const data = socket.data; + console.log("init:", data.init); + if (!data.init) { + // const dbUser = await fetch( + // `http://localhost:8787/sandbox/${data.sandboxId}/init` + // ) + } // socket.emit("loaded", { // rootContent: await fetchDir("/workspace", "") // }); diff --git a/backend/server/dist/types.js b/backend/server/dist/types.js new file mode 100644 index 0000000..764f96f --- /dev/null +++ b/backend/server/dist/types.js @@ -0,0 +1,3 @@ +"use strict"; +// DB Types +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/backend/server/src/index.ts b/backend/server/src/index.ts index ce9e9c3..3a7809d 100644 --- a/backend/server/src/index.ts +++ b/backend/server/src/index.ts @@ -4,6 +4,7 @@ import { createServer } from "http" import { Server } from "socket.io" import { z } from "zod" +import { User } from "./types" dotenv.config() @@ -17,31 +18,77 @@ const io = new Server(httpServer, { }, }) +const handshakeSchema = z.object({ + userId: z.string(), + sandboxId: z.string(), + type: z.enum(["node", "react"]), + EIO: z.string(), + transport: z.string(), +}) + io.use(async (socket, next) => { const q = socket.handshake.query console.log("middleware") - console.log(q) - if (!q.userId || !q.sandboxId) { + const parseQuery = handshakeSchema.safeParse(q) + + if (!parseQuery.success) { + console.log("Invalid request.") next(new Error("Invalid request.")) + return } - const dbUser = await fetch(`http://localhost:8787/api/user?id=${q.userId}`) - const dbUserJSON = await dbUser.json() + const query = parseQuery.data - if (!dbUserJSON || !dbUserJSON.sandbox.includes(q.sandboxId)) { + const dbUser = await fetch( + `http://localhost:8787/api/user?id=${query.userId}` + ) + const dbUserJSON = (await dbUser.json()) as User + + console.log("dbUserJSON:", dbUserJSON) + + if (!dbUserJSON) { + console.log("DB error.") + next(new Error("DB error.")) + return + } + + const sandbox = dbUserJSON.sandbox.find((s) => s.id === query.sandboxId) + + if (!sandbox) { + console.log("Invalid credentials.") next(new Error("Invalid credentials.")) + return } + const data = { + userId: query.userId, + sandboxId: query.sandboxId, + type: query.type, + init: sandbox.init, + } + + socket.data = data + next() }) io.on("connection", async (socket) => { - console.log(`connection`) - const userId = socket.handshake.query.userId + const data = socket.data as { + userId: string + sandboxId: string + type: "node" | "react" + init: boolean + } - console.log(userId) + console.log("init:", data.init) + + if (!data.init) { + // const dbUser = await fetch( + // `http://localhost:8787/sandbox/${data.sandboxId}/init` + // ) + } // socket.emit("loaded", { // rootContent: await fetchDir("/workspace", "") diff --git a/backend/server/src/types.ts b/backend/server/src/types.ts new file mode 100644 index 0000000..fc2851e --- /dev/null +++ b/backend/server/src/types.ts @@ -0,0 +1,17 @@ +// DB Types + +export type User = { + id: string + name: string + email: string + sandbox: Sandbox[] +} + +export type Sandbox = { + id: string + name: string + type: "react" | "node" + init: boolean + bucket: string | null + userId: string +} diff --git a/frontend/lib/types.ts b/frontend/lib/types.ts index f9bf047..fc2851e 100644 --- a/frontend/lib/types.ts +++ b/frontend/lib/types.ts @@ -11,6 +11,7 @@ export type Sandbox = { id: string name: string type: "react" | "node" + init: boolean bucket: string | null userId: string }