Add embedded PGlite support as zero-config database option

Add @electric-sql/pglite so the server can run without an external
Postgres instance. When DATABASE_URL is not set, the server auto-creates
an embedded PGlite database in ./data/pglite with schema push on startup.

- Add createPgliteDb() alongside the existing createDb()
- Make DATABASE_URL optional in server config
- Update drizzle config to glob schema files
- Update migrate script to support both Postgres and PGlite
- Add data/ to .gitignore for local PGlite storage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Forgotten
2026-02-16 19:07:37 -06:00
parent e4752d0092
commit 4bc8e8baa9
10 changed files with 76 additions and 326 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ drizzle/meta/
.vite/
coverage/
.DS_Store
data/

View File

@@ -1,7 +1,7 @@
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/schema/index.ts",
schema: "./src/schema/*.ts",
out: "./src/migrations",
dialect: "postgresql",
dbCredentials: {

View File

@@ -14,12 +14,13 @@
"seed": "tsx src/seed.ts"
},
"dependencies": {
"@electric-sql/pglite": "^0.3.15",
"@paperclip/shared": "workspace:*",
"drizzle-orm": "^0.38.4",
"postgres": "^3.4.5"
},
"devDependencies": {
"drizzle-kit": "^0.30.4",
"drizzle-kit": "^0.31.9",
"tsx": "^4.19.2",
"typescript": "^5.7.3",
"vitest": "^3.0.5"

View File

@@ -1,10 +1,26 @@
import { drizzle } from "drizzle-orm/postgres-js";
import { mkdirSync } from "node:fs";
import { drizzle as drizzlePg } from "drizzle-orm/postgres-js";
import { drizzle as drizzlePglite } from "drizzle-orm/pglite";
import postgres from "postgres";
import { PGlite } from "@electric-sql/pglite";
import * as schema from "./schema/index.js";
export function createDb(url: string) {
const sql = postgres(url);
return drizzle(sql, { schema });
return drizzlePg(sql, { schema });
}
export async function createPgliteDb(dataDir: string) {
mkdirSync(dataDir, { recursive: true });
const client = new PGlite(dataDir);
const db = drizzlePglite({ client, schema });
// Auto-push schema to PGlite on startup (like drizzle-kit push)
const { pushSchema } = await import("drizzle-kit/api");
const { apply } = await pushSchema(schema, db as any);
await apply();
return db;
}
export type Db = ReturnType<typeof createDb>;

View File

@@ -1,2 +1,2 @@
export { createDb, type Db } from "./client.js";
export { createDb, createPgliteDb, type Db } from "./client.js";
export * from "./schema/index.js";

View File

@@ -1,13 +1,23 @@
import { migrate } from "drizzle-orm/postgres-js/migrator";
import { migrate as migratePg } from "drizzle-orm/postgres-js/migrator";
import { migrate as migratePglite } from "drizzle-orm/pglite/migrator";
import postgres from "postgres";
import { drizzle } from "drizzle-orm/postgres-js";
import { PGlite } from "@electric-sql/pglite";
import { drizzle as drizzlePg } from "drizzle-orm/postgres-js";
import { drizzle as drizzlePglite } from "drizzle-orm/pglite";
const migrationsFolder = new URL("./migrations", import.meta.url).pathname;
const url = process.env.DATABASE_URL;
if (!url) throw new Error("DATABASE_URL is required");
const sql = postgres(url, { max: 1 });
const db = drizzle(sql);
if (url) {
const sql = postgres(url, { max: 1 });
const db = drizzlePg(sql);
await migratePg(db, { migrationsFolder });
await sql.end();
} else {
const client = new PGlite("./data/pglite");
const db = drizzlePglite({ client });
await migratePglite(db, { migrationsFolder });
await client.close();
}
await migrate(db, { migrationsFolder: new URL("./migrations", import.meta.url).pathname });
await sql.end();
console.log("Migrations complete");

View File

@@ -0,0 +1 @@
{"version":"7","dialect":"postgresql","entries":[]}

327
pnpm-lock.yaml generated
View File

@@ -17,19 +17,22 @@ importers:
packages/db:
dependencies:
'@electric-sql/pglite':
specifier: ^0.3.15
version: 0.3.15
'@paperclip/shared':
specifier: workspace:*
version: link:../shared
drizzle-orm:
specifier: ^0.38.4
version: 0.38.4(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4)
version: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4)
postgres:
specifier: ^3.4.5
version: 3.4.8
devDependencies:
drizzle-kit:
specifier: ^0.30.4
version: 0.30.6
specifier: ^0.31.9
version: 0.31.9
tsx:
specifier: ^4.19.2
version: 4.21.0
@@ -60,7 +63,7 @@ importers:
version: link:../packages/shared
drizzle-orm:
specifier: ^0.38.4
version: 0.38.4(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4)
version: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4)
express:
specifier: ^5.1.0
version: 5.2.1
@@ -224,6 +227,9 @@ packages:
'@drizzle-team/brocli@0.10.2':
resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
'@electric-sql/pglite@0.3.15':
resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==}
'@esbuild-kit/core-utils@3.3.2':
resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==}
deprecated: 'Merged into tsx: https://tsx.is'
@@ -232,12 +238,6 @@ packages:
resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==}
deprecated: 'Merged into tsx: https://tsx.is'
'@esbuild/aix-ppc64@0.19.12':
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.25.12':
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
engines: {node: '>=18'}
@@ -256,12 +256,6 @@ packages:
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.19.12':
resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.25.12':
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
engines: {node: '>=18'}
@@ -280,12 +274,6 @@ packages:
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.19.12':
resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.25.12':
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
engines: {node: '>=18'}
@@ -304,12 +292,6 @@ packages:
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.19.12':
resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.25.12':
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
engines: {node: '>=18'}
@@ -328,12 +310,6 @@ packages:
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.19.12':
resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.25.12':
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
engines: {node: '>=18'}
@@ -352,12 +328,6 @@ packages:
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.19.12':
resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.25.12':
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
engines: {node: '>=18'}
@@ -376,12 +346,6 @@ packages:
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.19.12':
resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.25.12':
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
engines: {node: '>=18'}
@@ -400,12 +364,6 @@ packages:
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.19.12':
resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.12':
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
engines: {node: '>=18'}
@@ -424,12 +382,6 @@ packages:
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.19.12':
resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.25.12':
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
engines: {node: '>=18'}
@@ -448,12 +400,6 @@ packages:
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.19.12':
resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.25.12':
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
engines: {node: '>=18'}
@@ -472,12 +418,6 @@ packages:
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.19.12':
resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.25.12':
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
engines: {node: '>=18'}
@@ -496,12 +436,6 @@ packages:
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.19.12':
resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.25.12':
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
engines: {node: '>=18'}
@@ -520,12 +454,6 @@ packages:
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.19.12':
resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.25.12':
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
engines: {node: '>=18'}
@@ -544,12 +472,6 @@ packages:
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.19.12':
resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.25.12':
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
engines: {node: '>=18'}
@@ -568,12 +490,6 @@ packages:
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.19.12':
resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.25.12':
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
engines: {node: '>=18'}
@@ -592,12 +508,6 @@ packages:
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.19.12':
resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.25.12':
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
engines: {node: '>=18'}
@@ -616,12 +526,6 @@ packages:
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.19.12':
resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.25.12':
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
engines: {node: '>=18'}
@@ -652,12 +556,6 @@ packages:
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.19.12':
resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.12':
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
engines: {node: '>=18'}
@@ -688,12 +586,6 @@ packages:
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.19.12':
resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.12':
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
engines: {node: '>=18'}
@@ -724,12 +616,6 @@ packages:
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.19.12':
resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.25.12':
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
engines: {node: '>=18'}
@@ -748,12 +634,6 @@ packages:
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.19.12':
resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.25.12':
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
engines: {node: '>=18'}
@@ -772,12 +652,6 @@ packages:
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.19.12':
resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.25.12':
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
engines: {node: '>=18'}
@@ -796,12 +670,6 @@ packages:
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.19.12':
resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.25.12':
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
engines: {node: '>=18'}
@@ -837,9 +705,6 @@ packages:
'@paralleldrive/cuid2@2.3.1':
resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==}
'@petamoriken/float16@3.9.3':
resolution: {integrity: sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==}
'@pinojs/redact@0.4.0':
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==}
@@ -1292,8 +1157,8 @@ packages:
dezalgo@1.0.4:
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
drizzle-kit@0.30.6:
resolution: {integrity: sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g==}
drizzle-kit@0.31.9:
resolution: {integrity: sha512-GViD3IgsXn7trFyBUUHyTFBpH/FsHTxYJ66qdbVggxef4UBPHRYxQaRzYLTuekYnk9i5FIEL9pbBIwMqX/Uwrg==}
hasBin: true
drizzle-orm@0.38.4:
@@ -1406,10 +1271,6 @@ packages:
resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==}
engines: {node: '>=10.13.0'}
env-paths@3.0.0:
resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
@@ -1439,11 +1300,6 @@ packages:
engines: {node: '>=12'}
hasBin: true
esbuild@0.19.12:
resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
engines: {node: '>=12'}
hasBin: true
esbuild@0.25.12:
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
engines: {node: '>=18'}
@@ -1516,11 +1372,6 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
gel@2.2.0:
resolution: {integrity: sha512-q0ma7z2swmoamHQusey8ayo8+ilVdzDt4WTxSPzq/yRqvucWRfymRVMvNgmSC0XK7eNjjEZEcplxpgaNojKdmQ==}
engines: {node: '>= 18.0.0'}
hasBin: true
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@@ -1577,10 +1428,6 @@ packages:
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
isexe@3.1.5:
resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==}
engines: {node: '>=18'}
jiti@2.6.1:
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
hasBin: true
@@ -1871,11 +1718,6 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
engines: {node: '>=10'}
hasBin: true
send@1.2.1:
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
engines: {node: '>= 18'}
@@ -1890,10 +1732,6 @@ packages:
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
shell-quote@1.8.3:
resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
engines: {node: '>= 0.4'}
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
@@ -2132,11 +1970,6 @@ packages:
jsdom:
optional: true
which@4.0.0:
resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
engines: {node: ^16.13.0 || >=18.0.0}
hasBin: true
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
@@ -2267,6 +2100,8 @@ snapshots:
'@drizzle-team/brocli@0.10.2': {}
'@electric-sql/pglite@0.3.15': {}
'@esbuild-kit/core-utils@3.3.2':
dependencies:
esbuild: 0.18.20
@@ -2277,9 +2112,6 @@ snapshots:
'@esbuild-kit/core-utils': 3.3.2
get-tsconfig: 4.13.6
'@esbuild/aix-ppc64@0.19.12':
optional: true
'@esbuild/aix-ppc64@0.25.12':
optional: true
@@ -2289,9 +2121,6 @@ snapshots:
'@esbuild/android-arm64@0.18.20':
optional: true
'@esbuild/android-arm64@0.19.12':
optional: true
'@esbuild/android-arm64@0.25.12':
optional: true
@@ -2301,9 +2130,6 @@ snapshots:
'@esbuild/android-arm@0.18.20':
optional: true
'@esbuild/android-arm@0.19.12':
optional: true
'@esbuild/android-arm@0.25.12':
optional: true
@@ -2313,9 +2139,6 @@ snapshots:
'@esbuild/android-x64@0.18.20':
optional: true
'@esbuild/android-x64@0.19.12':
optional: true
'@esbuild/android-x64@0.25.12':
optional: true
@@ -2325,9 +2148,6 @@ snapshots:
'@esbuild/darwin-arm64@0.18.20':
optional: true
'@esbuild/darwin-arm64@0.19.12':
optional: true
'@esbuild/darwin-arm64@0.25.12':
optional: true
@@ -2337,9 +2157,6 @@ snapshots:
'@esbuild/darwin-x64@0.18.20':
optional: true
'@esbuild/darwin-x64@0.19.12':
optional: true
'@esbuild/darwin-x64@0.25.12':
optional: true
@@ -2349,9 +2166,6 @@ snapshots:
'@esbuild/freebsd-arm64@0.18.20':
optional: true
'@esbuild/freebsd-arm64@0.19.12':
optional: true
'@esbuild/freebsd-arm64@0.25.12':
optional: true
@@ -2361,9 +2175,6 @@ snapshots:
'@esbuild/freebsd-x64@0.18.20':
optional: true
'@esbuild/freebsd-x64@0.19.12':
optional: true
'@esbuild/freebsd-x64@0.25.12':
optional: true
@@ -2373,9 +2184,6 @@ snapshots:
'@esbuild/linux-arm64@0.18.20':
optional: true
'@esbuild/linux-arm64@0.19.12':
optional: true
'@esbuild/linux-arm64@0.25.12':
optional: true
@@ -2385,9 +2193,6 @@ snapshots:
'@esbuild/linux-arm@0.18.20':
optional: true
'@esbuild/linux-arm@0.19.12':
optional: true
'@esbuild/linux-arm@0.25.12':
optional: true
@@ -2397,9 +2202,6 @@ snapshots:
'@esbuild/linux-ia32@0.18.20':
optional: true
'@esbuild/linux-ia32@0.19.12':
optional: true
'@esbuild/linux-ia32@0.25.12':
optional: true
@@ -2409,9 +2211,6 @@ snapshots:
'@esbuild/linux-loong64@0.18.20':
optional: true
'@esbuild/linux-loong64@0.19.12':
optional: true
'@esbuild/linux-loong64@0.25.12':
optional: true
@@ -2421,9 +2220,6 @@ snapshots:
'@esbuild/linux-mips64el@0.18.20':
optional: true
'@esbuild/linux-mips64el@0.19.12':
optional: true
'@esbuild/linux-mips64el@0.25.12':
optional: true
@@ -2433,9 +2229,6 @@ snapshots:
'@esbuild/linux-ppc64@0.18.20':
optional: true
'@esbuild/linux-ppc64@0.19.12':
optional: true
'@esbuild/linux-ppc64@0.25.12':
optional: true
@@ -2445,9 +2238,6 @@ snapshots:
'@esbuild/linux-riscv64@0.18.20':
optional: true
'@esbuild/linux-riscv64@0.19.12':
optional: true
'@esbuild/linux-riscv64@0.25.12':
optional: true
@@ -2457,9 +2247,6 @@ snapshots:
'@esbuild/linux-s390x@0.18.20':
optional: true
'@esbuild/linux-s390x@0.19.12':
optional: true
'@esbuild/linux-s390x@0.25.12':
optional: true
@@ -2469,9 +2256,6 @@ snapshots:
'@esbuild/linux-x64@0.18.20':
optional: true
'@esbuild/linux-x64@0.19.12':
optional: true
'@esbuild/linux-x64@0.25.12':
optional: true
@@ -2487,9 +2271,6 @@ snapshots:
'@esbuild/netbsd-x64@0.18.20':
optional: true
'@esbuild/netbsd-x64@0.19.12':
optional: true
'@esbuild/netbsd-x64@0.25.12':
optional: true
@@ -2505,9 +2286,6 @@ snapshots:
'@esbuild/openbsd-x64@0.18.20':
optional: true
'@esbuild/openbsd-x64@0.19.12':
optional: true
'@esbuild/openbsd-x64@0.25.12':
optional: true
@@ -2523,9 +2301,6 @@ snapshots:
'@esbuild/sunos-x64@0.18.20':
optional: true
'@esbuild/sunos-x64@0.19.12':
optional: true
'@esbuild/sunos-x64@0.25.12':
optional: true
@@ -2535,9 +2310,6 @@ snapshots:
'@esbuild/win32-arm64@0.18.20':
optional: true
'@esbuild/win32-arm64@0.19.12':
optional: true
'@esbuild/win32-arm64@0.25.12':
optional: true
@@ -2547,9 +2319,6 @@ snapshots:
'@esbuild/win32-ia32@0.18.20':
optional: true
'@esbuild/win32-ia32@0.19.12':
optional: true
'@esbuild/win32-ia32@0.25.12':
optional: true
@@ -2559,9 +2328,6 @@ snapshots:
'@esbuild/win32-x64@0.18.20':
optional: true
'@esbuild/win32-x64@0.19.12':
optional: true
'@esbuild/win32-x64@0.25.12':
optional: true
@@ -2593,8 +2359,6 @@ snapshots:
dependencies:
'@noble/hashes': 1.8.0
'@petamoriken/float16@3.9.3': {}
'@pinojs/redact@0.4.0': {}
'@rolldown/pluginutils@1.0.0-beta.27': {}
@@ -2995,18 +2759,18 @@ snapshots:
asap: 2.0.6
wrappy: 1.0.2
drizzle-kit@0.30.6:
drizzle-kit@0.31.9:
dependencies:
'@drizzle-team/brocli': 0.10.2
'@esbuild-kit/esm-loader': 2.6.5
esbuild: 0.19.12
esbuild-register: 3.6.0(esbuild@0.19.12)
gel: 2.2.0
esbuild: 0.25.12
esbuild-register: 3.6.0(esbuild@0.25.12)
transitivePeerDependencies:
- supports-color
drizzle-orm@0.38.4(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4):
drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(postgres@3.4.8)(react@19.2.4):
optionalDependencies:
'@electric-sql/pglite': 0.3.15
'@types/react': 19.2.14
postgres: 3.4.8
react: 19.2.4
@@ -3028,8 +2792,6 @@ snapshots:
graceful-fs: 4.2.11
tapable: 2.3.0
env-paths@3.0.0: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
@@ -3047,10 +2809,10 @@ snapshots:
has-tostringtag: 1.0.2
hasown: 2.0.2
esbuild-register@3.6.0(esbuild@0.19.12):
esbuild-register@3.6.0(esbuild@0.25.12):
dependencies:
debug: 4.4.3
esbuild: 0.19.12
esbuild: 0.25.12
transitivePeerDependencies:
- supports-color
@@ -3079,32 +2841,6 @@ snapshots:
'@esbuild/win32-ia32': 0.18.20
'@esbuild/win32-x64': 0.18.20
esbuild@0.19.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.19.12
'@esbuild/android-arm': 0.19.12
'@esbuild/android-arm64': 0.19.12
'@esbuild/android-x64': 0.19.12
'@esbuild/darwin-arm64': 0.19.12
'@esbuild/darwin-x64': 0.19.12
'@esbuild/freebsd-arm64': 0.19.12
'@esbuild/freebsd-x64': 0.19.12
'@esbuild/linux-arm': 0.19.12
'@esbuild/linux-arm64': 0.19.12
'@esbuild/linux-ia32': 0.19.12
'@esbuild/linux-loong64': 0.19.12
'@esbuild/linux-mips64el': 0.19.12
'@esbuild/linux-ppc64': 0.19.12
'@esbuild/linux-riscv64': 0.19.12
'@esbuild/linux-s390x': 0.19.12
'@esbuild/linux-x64': 0.19.12
'@esbuild/netbsd-x64': 0.19.12
'@esbuild/openbsd-x64': 0.19.12
'@esbuild/sunos-x64': 0.19.12
'@esbuild/win32-arm64': 0.19.12
'@esbuild/win32-ia32': 0.19.12
'@esbuild/win32-x64': 0.19.12
esbuild@0.25.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.12
@@ -3248,17 +2984,6 @@ snapshots:
function-bind@1.1.2: {}
gel@2.2.0:
dependencies:
'@petamoriken/float16': 3.9.3
debug: 4.4.3
env-paths: 3.0.0
semver: 7.7.4
shell-quote: 1.8.3
which: 4.0.0
transitivePeerDependencies:
- supports-color
gensync@1.0.0-beta.2: {}
get-caller-file@2.0.5: {}
@@ -3317,8 +3042,6 @@ snapshots:
is-promise@4.0.0: {}
isexe@3.1.5: {}
jiti@2.6.1: {}
js-tokens@4.0.0: {}
@@ -3575,8 +3298,6 @@ snapshots:
semver@6.3.1: {}
semver@7.7.4: {}
send@1.2.1:
dependencies:
debug: 4.4.3
@@ -3606,8 +3327,6 @@ snapshots:
setprototypeof@1.2.0: {}
shell-quote@1.8.3: {}
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -3829,10 +3548,6 @@ snapshots:
- tsx
- yaml
which@4.0.0:
dependencies:
isexe: 3.1.5
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0

View File

@@ -1,16 +1,13 @@
export interface Config {
port: number;
databaseUrl: string;
databaseUrl: string | undefined;
serveUi: boolean;
}
export function loadConfig(): Config {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) throw new Error("DATABASE_URL is required");
return {
port: Number(process.env.PORT) || 3100,
databaseUrl,
databaseUrl: process.env.DATABASE_URL,
serveUi: process.env.SERVE_UI === "true",
};
}

View File

@@ -1,11 +1,20 @@
import { createDb } from "@paperclip/db";
import { createDb, createPgliteDb } from "@paperclip/db";
import { createApp } from "./app.js";
import { loadConfig } from "./config.js";
import { logger } from "./middleware/logger.js";
const config = loadConfig();
const db = createDb(config.databaseUrl);
const app = createApp(db, { serveUi: config.serveUi });
let db;
if (config.databaseUrl) {
db = createDb(config.databaseUrl);
} else {
logger.info("No DATABASE_URL set — using embedded PGlite (./data/pglite)");
db = await createPgliteDb("./data/pglite");
logger.info("PGlite ready, schema pushed");
}
const app = createApp(db as any, { serveUi: config.serveUi });
app.listen(config.port, () => {
logger.info(`Server listening on :${config.port}`);