Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turso migration #76

Merged
merged 4 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .env.example

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ yarn-error.log*
# Misc
.DS_Store
*.pem

# SQLite
local.db
15 changes: 15 additions & 0 deletions apps/collab-server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The following is a sample a .env file, to get started create a copy and name
# it ".env".

NODE_ENV=development

# Must match NEXTAUTH_SECRET on front-end as it is used to sign and validate JWTs
AUTH_SECRET=secret

TURSO_DATABASE_URL=file:../../local.db

# Production

# NODE_ENV=production
# TURSO_AUTH_TOKEN=

2 changes: 2 additions & 0 deletions apps/collab-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
"@hocuspocus/extension-logger": "^2.8.1",
"@hocuspocus/extension-sqlite": "^2.8.1",
"@hocuspocus/server": "^2.8.1",
"@libsql/client": "^0.5.3",
"jose": "^5.2.2",
"mysql2": "^3.6.5",
"zod": "^3.22.4"
},
"devDependencies": {
"@jotter/typescript-config": "*",
"@types/node": "^20.10.1",
"dotenv": "^16.4.5",
"tsx": "^4.6.1",
"typescript": "^5.3.2"
}
Expand Down
16 changes: 12 additions & 4 deletions apps/collab-server/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from "zod";
import "dotenv/config";

type EnvironmentVariables = z.infer<typeof envSchema>;

Expand All @@ -12,11 +13,18 @@ declare global {
const envSchema = z.object({
NODE_ENV: z.union([z.literal("development"), z.literal("production")]),
PORT: z.optional(z.string()),
DATABASE_USER: z.string().min(1),
DATABASE_PASS: z.string().min(1),
DATABASE_HOST: z.string().min(1),
DATABASE_NAME: z.string().min(1),
AUTH_SECRET: z.string().min(1),
TURSO_DATABASE_URL: z.string().min(1),
TURSO_AUTH_TOKEN: z
.string()
.min(1)
.optional()
.refine((token) => {
if (process.env.NODE_ENV === "production") {
return Boolean(token);
}
return true;
}, "A token is required to access production database."),
});

export const env = envSchema.parse(process.env);
57 changes: 0 additions & 57 deletions apps/collab-server/src/extensions/MySQL.ts

This file was deleted.

23 changes: 4 additions & 19 deletions apps/collab-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Database } from "@hocuspocus/extension-database";
import { Logger } from "@hocuspocus/extension-logger";
import { Hocuspocus } from "@hocuspocus/server";
import MySQL from "./extensions/MySQL.js";
import { env } from "./env.js";
import { jwtVerify } from "jose";
import { env } from "./env.js";
import tursoConfiguration from "./turso-config.js";

const PORT = env.PORT ? Number(env.PORT) : 1234;
const IS_PRODUCTION = env.NODE_ENV === "production";

// Configure the server …
const server = new Hocuspocus({
Expand All @@ -16,22 +16,7 @@ const server = new Hocuspocus({
await jwtVerify(data.token, key);
},

extensions: [
new Logger(),

new MySQL({
user: env.DATABASE_USER,
host: env.DATABASE_HOST,
database: env.DATABASE_NAME,
password: env.DATABASE_PASS,

// Enable SSL on production. Production database will reject the connection
// when this flag is not set.
ssl: {
rejectUnauthorized: IS_PRODUCTION,
},
}),
],
extensions: [new Logger(), new Database(tursoConfiguration)],
});

// // … and run it!
Expand Down
41 changes: 41 additions & 0 deletions apps/collab-server/src/turso-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { DatabaseConfiguration } from "@hocuspocus/extension-database";
import { createClient } from "@libsql/client";
import { env } from "./env.js";

const client = createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN,
});

const tursoConfiguration: DatabaseConfiguration = {
async fetch({ documentName }) {
const res = await client.execute({
sql: `SELECT name, data
FROM document
WHERE name = ?
`,
args: [documentName],
});

const data = res.rows[0]?.data;
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}

return null;
},

async store({ documentName, state: documentData }) {
const now = new Date().getTime();
await client.execute({
sql: `UPDATE document
SET data = ?,
modifiedOn = ?
WHERE name = ?
`,
args: [documentName, now, documentData],
});
},
};

export default tursoConfiguration;
5 changes: 1 addition & 4 deletions apps/front-end/.env
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
NEXT_PUBLIC_COLLAB_SERVER_URL=ws://localhost:1234

# Local development database
# This should match the same one configured for the collaboration server
DATABASE_URL=mysql://root:pass@localhost/jotter

TURSO_DATABASE_URL=file:../../local.db

NEXTAUTH_URL=http://localhost:3000
4 changes: 2 additions & 2 deletions apps/front-end/drizzle.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { defineConfig } from "drizzle-kit";

export default defineConfig({
schema: "./src/schema.ts",
driver: "mysql2",
driver: "libsql",
out: "./drizzle",
dbCredentials: {
uri: process.env.DATABASE_URL!,
url: process.env.TURSO_DATABASE_URL!,
},
});
9 changes: 4 additions & 5 deletions apps/front-end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
"version": "0.1.0",
"private": true,
"scripts": {
"predev": "docker compose --env-file ../../.env up -d",
"dev": "next dev",
"dev:collab": "turbo run dev --filter=front-end --filter=collab-server",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test:e2e": "playwright test",
"db:generate": "drizzle-kit generate:mysql",
"db:push": "drizzle-kit push:mysql"
"db:generate": "drizzle-kit generate:sqlite",
"db:push": "drizzle-kit push:sqlite"
},
"dependencies": {
"@auth/drizzle-adapter": "^0.7.0",
Expand All @@ -24,6 +23,7 @@
"@lexical/selection": "^0.13.0",
"@lexical/utils": "^0.13.0",
"@lexical/yjs": "^0.13.0",
"@libsql/client": "^0.5.3",
"@radix-ui/react-accordion": "^1.1.1",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-context-menu": "^2.1.3",
Expand All @@ -40,13 +40,12 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^0.2.0",
"drizzle-orm": "^0.29.3",
"drizzle-orm": "^0.29.5",
"eslint": "^8.51.0",
"eslint-config-next": "^14.1.1",
"jose": "^5.2.2",
"jotai": "^2.4.3",
"lexical": "^0.13.0",
"mysql2": "^3.9.1",
"nanoid": "^5.0.2",
"next": "^14.1.1",
"next-auth": "^4.24.5",
Expand Down
12 changes: 11 additions & 1 deletion apps/front-end/src/config/env-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ const envSchema = z.object({
DISCORD_SECRET: z.string().min(1),
DISCORD_CLIENT_ID: z.string().min(1),
NEXTAUTH_SECRET: z.string().min(1),
DATABASE_URL: z.string().min(1),
TURSO_DATABASE_URL: z.string().min(1),
TURSO_AUTH_TOKEN: z
.string()
.min(1)
.optional()
.refine((token) => {
if (process.env.NODE_ENV === "production") {
return Boolean(token);
}
return true;
}, "A token is required to access production database."),
NEXTAUTH_URL: z.string().min(1),
});

Expand Down
11 changes: 7 additions & 4 deletions apps/front-end/src/lib/db.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import mysql from "mysql2/promise";
import env from "@/config/env-server";
import { drizzle } from "drizzle-orm/mysql2";
import * as schema from "@/schema";
import { createClient } from "@libsql/client";
import { drizzle } from "drizzle-orm/libsql";

const connection = await mysql.createConnection(env.DATABASE_URL);
const connection = await createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN,
});

const db = drizzle(connection, { mode: "planetscale", schema });
const db = drizzle(connection, { schema });

export default db;
Loading
Loading