From ab1967f27f0d2c43cb9d6cdb90714afcaaf311e7 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Mon, 10 Aug 2026 16:54:31 -0400 Subject: [PATCH] fix(core): runtime-neutral legacy credential import --- .../20260805200742_import_legacy_credentials.ts | 7 ++++--- packages/core/test/database-migration.test.ts | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts b/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts index 05ddc4ef141e..8dd33be7ea74 100644 --- a/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts +++ b/packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts @@ -1,3 +1,4 @@ +import { readFile } from "node:fs/promises" import path from "node:path" import { sql } from "drizzle-orm" import { Effect, Option, Schema } from "effect" @@ -41,9 +42,9 @@ export default migration export function importLegacyCredentials(tx: Parameters[0], filepath: string) { return Effect.gen(function* () { - const file = Bun.file(filepath) - if (!(yield* Effect.promise(() => file.exists()))) return - const input = Option.getOrUndefined(decodeJson(yield* Effect.promise(() => file.text()))) + const content = yield* Effect.promise(() => readFile(filepath, "utf8").catch(() => undefined)) + if (content === undefined) return + const input = Option.getOrUndefined(decodeJson(content)) if (typeof input !== "object" || input === null || Array.isArray(input)) { return yield* Effect.fail(new Error("Legacy credential file must contain an object")) } diff --git a/packages/core/test/database-migration.test.ts b/packages/core/test/database-migration.test.ts index 5a58432d22dc..d9e8e8f975be 100644 --- a/packages/core/test/database-migration.test.ts +++ b/packages/core/test/database-migration.test.ts @@ -164,6 +164,20 @@ describe("DatabaseMigration", () => { expect(await Bun.file(source).text()).toBe(content) }) + test("skips legacy credential import when the source file is absent", async () => { + await using tmp = await tmpdir() + + await run( + Effect.gen(function* () { + const db = yield* makeDb + yield* DatabaseMigration.apply(db) + yield* db.transaction((tx) => importLegacyCredentials(tx, path.join(tmp.path, "missing-auth.json"))) + + expect(yield* db.all(sql`SELECT id FROM credential`)).toEqual([]) + }), + ) + }) + test("rolls back a failed migration without recording it", async () => { await run( Effect.gen(function* () {