diff --git a/.env.example b/.env.example index ff96e1a..98f6fc8 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ -DATABASE_URL=postgresql://postgres:xxxxxx@localhost:6666/postgres - -# Optional: first admin for an empty instance. `bun run db:seed` creates an admin only when no user has role=admin yet (same username/password rules as registration). +# DATABASE_URL=postgresql://postgres:xxxxxx@localhost:6666/postgres +DATABASE_URL=file:./db.sqlite +NITRO_PORT=3399 +# Optional: first admin for an empty instance. Creates an admin only when no user has role=admin yet (same username/password rules as registration). BOOTSTRAP_ADMIN_USERNAME= BOOTSTRAP_ADMIN_PASSWORD= \ No newline at end of file diff --git a/app/components/AppShell.vue b/app/components/AppShell.vue index d9c93de..155c33b 100644 --- a/app/components/AppShell.vue +++ b/app/components/AppShell.vue @@ -17,7 +17,7 @@ const { allowRegister, siteName } = useGlobalConfig() const logoutLoading = ref(false) onMounted(() => { - refresh(true).catch(() => {}) + refresh().catch(() => {}) }) const displayName = computed(() => { diff --git a/app/layouts/public.vue b/app/layouts/public.vue index 13be99e..70db257 100644 --- a/app/layouts/public.vue +++ b/app/layouts/public.vue @@ -65,7 +65,7 @@ function syncModeFromStorage() { } onMounted(() => { - refresh(true).catch(() => {}) + refresh().catch(() => {}) syncModeFromStorage() }) diff --git a/build-files/run.sh b/build-files/run.sh index ba1bc71..694caf6 100644 --- a/build-files/run.sh +++ b/build-files/run.sh @@ -5,4 +5,5 @@ if [ -f .env ]; then fi node server/migrate-sqlite.js migrations +node server/seed.js node server/index.mjs \ No newline at end of file diff --git a/build-files/seed.js b/build-files/seed.js index 79cccc0..e1a0bf1 100644 --- a/build-files/seed.js +++ b/build-files/seed.js @@ -8,6 +8,7 @@ */ import Database from 'better-sqlite3' import { hash } from 'bcryptjs' +import { mkdirSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' @@ -23,12 +24,25 @@ function derivePublicSlug(username) { return PUBLIC_SLUG_REGEX.test(lower) ? lower : null } -function openSqlite() { - const dbUrl = process.env.DATABASE_URL || '' - const sqlitePath = dbUrl.startsWith('file:') ? dbUrl.slice(5) : dbUrl - if (!sqlitePath) { +/** + * 与 `migrate-sqlite.js` 一致:相对路径相对 `process.cwd()`(例如 `.output/run.sh` 下与迁移写入同一文件)。 + * Nitro 内 `resolveSqliteDatabaseUrl` 在无法锚定 drizzle-pkg 时也会回退到 cwd,避免「迁移/seed 成功、服务 CANTOPEN」。 + */ +function resolveSqliteFilePath(dbUrl) { + const stripped = dbUrl.startsWith('file:') ? dbUrl.slice('file:'.length) : dbUrl + if (!stripped) { throw new Error('DATABASE_URL 未设置,且未提供有效的 SQLite 文件路径') } + if (path.isAbsolute(stripped)) { + return stripped + } + return path.resolve(process.cwd(), stripped) +} + +function openSqlite() { + const dbUrl = process.env.DATABASE_URL || '' + const sqlitePath = resolveSqliteFilePath(dbUrl) + mkdirSync(path.dirname(sqlitePath), { recursive: true }) return new Database(sqlitePath) } diff --git a/packages/drizzle-pkg/database/sqlite/db-bun.ts b/packages/drizzle-pkg/database/sqlite/db-bun.ts new file mode 100644 index 0000000..59579ea --- /dev/null +++ b/packages/drizzle-pkg/database/sqlite/db-bun.ts @@ -0,0 +1,21 @@ +import { drizzle } from "drizzle-orm/bun-sqlite"; +import { resolveSqliteDatabaseUrl } from "../../lib/resolve-sqlite-url"; + +/** + * Bun 无法加载 better-sqlite3 原生模块;`bun run seed.ts` 等脚本使用本模块。 + * Nitro/Node 服务端仍用 `db.ts`(better-sqlite3)。 + */ +const rawUrl = process.env.DATABASE_URL; +if (!rawUrl) { + throw new Error("DATABASE_URL 未设置"); +} +const resolvedUrl = resolveSqliteDatabaseUrl(rawUrl); +process.env.DATABASE_URL = resolvedUrl; + +const sqlitePath = resolvedUrl.startsWith("file:") + ? resolvedUrl.slice("file:".length) + : resolvedUrl; + +const _db = drizzle(sqlitePath); + +export { _db as dbGlobal }; diff --git a/packages/drizzle-pkg/database/sqlite/db.ts b/packages/drizzle-pkg/database/sqlite/db.ts index 180e2e6..89b9cf9 100644 --- a/packages/drizzle-pkg/database/sqlite/db.ts +++ b/packages/drizzle-pkg/database/sqlite/db.ts @@ -1,4 +1,4 @@ -import { drizzle } from "drizzle-orm/libsql"; +import { drizzle } from "drizzle-orm/better-sqlite3"; import { resolveSqliteDatabaseUrl } from "../../lib/resolve-sqlite-url"; if (process.env.NODE_ENV === "production") { @@ -13,6 +13,11 @@ if (!rawUrl) { const resolvedUrl = resolveSqliteDatabaseUrl(rawUrl); process.env.DATABASE_URL = resolvedUrl; -const _db = drizzle(resolvedUrl); +// better-sqlite3 需要裸文件路径;`file:` 前缀仍保留在 DATABASE_URL 供 drizzle-kit 等使用 +const sqlitePath = resolvedUrl.startsWith("file:") + ? resolvedUrl.slice("file:".length) + : resolvedUrl; + +const _db = drizzle(sqlitePath); export { _db as dbGlobal }; \ No newline at end of file diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite index d47bf7e..e3b7ba5 100644 Binary files a/packages/drizzle-pkg/db.sqlite and b/packages/drizzle-pkg/db.sqlite differ diff --git a/packages/drizzle-pkg/lib/paths.ts b/packages/drizzle-pkg/lib/paths.ts index 860b6e6..a91277a 100644 --- a/packages/drizzle-pkg/lib/paths.ts +++ b/packages/drizzle-pkg/lib/paths.ts @@ -18,7 +18,7 @@ function isDrizzlePkgRoot(dir: string): boolean { /** * `drizzle-pkg` 包根目录(与 `package.json`、`db.sqlite` 同级)。 * - 开发:用 `import.meta` 锚定,避免 cwd 变化把 `file:db.sqlite` 指到错误文件(只读 / DBMOVED)。 - * - 生产:打包后 chunk 路径不可靠,回退到 `cwd/packages/drizzle-pkg`;部署时建议使用绝对 `DATABASE_URL`。 + * - 生产:打包后 chunk 路径不可靠,回退到 `cwd/packages/drizzle-pkg`;再不行则回退 `process.cwd()`(与 `.output` 下 migrate/seed 的相对 `DATABASE_URL` 一致)。 */ export function getDrizzlePkgRoot(): string { const fromMeta = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); @@ -29,5 +29,5 @@ export function getDrizzlePkgRoot(): string { if (isDrizzlePkgRoot(fromCwd)) { return fromCwd; } - return fromMeta; + return process.cwd(); } diff --git a/packages/drizzle-pkg/seed.ts b/packages/drizzle-pkg/seed.ts index 169241b..c8f393f 100644 --- a/packages/drizzle-pkg/seed.ts +++ b/packages/drizzle-pkg/seed.ts @@ -1,7 +1,7 @@ import "./env"; import { hash } from "bcryptjs"; import { eq, sql } from "drizzle-orm"; -import { dbGlobal } from "./lib/db"; +import { dbGlobal } from "./database/sqlite/db-bun"; import { users } from "./lib/schema/auth"; /** Match `server/service/auth/index.ts` */