mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-10-08 10:47:48 +08:00
Found by the second PR review: - With AWS_BEARER_TOKEN_BEDROCK set on the server, a request with the user's AWS keys ran on the server's token: the Bedrock SDK prefers it. Checked with Bedrock: invalid user keys used to get an answer. - An OpenAI key with the official URL filled in (the settings form does that) went to the Responses API. Back to main's rule: a configured base URL uses Chat Completions. - A user's Ollama key went to the server's OLLAMA_BASE_URL, for chat and for the model list. Like every other provider, it goes to the user's base URL or Ollama Cloud. - The server's keyless Ollama and EdgeOne were not counted in the quota. - AI_MODEL models on the server's keys ran on any provider with a server key, not only on AI_PROVIDER. - A user's Azure key without a base URL used the server's resource name. - The admin panel's Test button failed whenever access codes were set. - DeepSeek's errors in the stream (plain text) were shown as they were, without a hint and also on the server's keys. Bedrock's throttling in the stream was not recognised as a rate limit. - The EdgeOne function accepted text/plain; x=application/json, which other sites can send without a CORS preflight. - Desktop app: a launch that found the old port taken for a moment (the previous version still quitting after an update) remembered the new port for good. The new port is kept only when Windows reserves the old one. A failed read of the presets file moved it aside as corrupt, and a save could then replace the presets. Switching presets on the same port now reloads the page. The dev launcher no longer misses a preset change made before or during a restart.
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
// @vitest-environment node
|
|
import { existsSync, mkdtempSync, readdirSync, writeFileSync } from "node:fs"
|
|
import { tmpdir } from "node:os"
|
|
import { join } from "node:path"
|
|
import { beforeEach, describe, expect, it, vi } from "vitest"
|
|
|
|
const userData = vi.hoisted(() => ({ dir: "" }))
|
|
vi.mock("electron", () => ({
|
|
app: { getPath: () => userData.dir },
|
|
safeStorage: { isEncryptionAvailable: () => false },
|
|
}))
|
|
|
|
// Make the next read of the presets file fail, like a file an antivirus
|
|
// scanner holds on Windows
|
|
const readFails = vi.hoisted(() => ({ next: false }))
|
|
vi.mock("node:fs", async (importOriginal) => {
|
|
const fs = await importOriginal<typeof import("node:fs")>()
|
|
return {
|
|
...fs,
|
|
readFileSync: ((...args: Parameters<typeof fs.readFileSync>) => {
|
|
if (readFails.next && String(args[0]).endsWith(".json")) {
|
|
readFails.next = false
|
|
throw Object.assign(new Error("EBUSY: resource busy"), {
|
|
code: "EBUSY",
|
|
})
|
|
}
|
|
return fs.readFileSync(...args)
|
|
}) as typeof fs.readFileSync,
|
|
}
|
|
})
|
|
|
|
import { createPreset, loadPresets } from "@/electron/main/config-manager"
|
|
|
|
const presetsFile = () => join(userData.dir, "config-presets.json")
|
|
|
|
beforeEach(() => {
|
|
userData.dir = mkdtempSync(join(tmpdir(), "config-manager-"))
|
|
readFails.next = false
|
|
})
|
|
|
|
describe("config presets file", () => {
|
|
it("keeps a file it could not read for now", () => {
|
|
createPreset({ name: "Mine", config: { AI_PROVIDER: "openai" } })
|
|
|
|
readFails.next = true
|
|
expect(loadPresets().presets).toEqual([])
|
|
expect(existsSync(presetsFile())).toBe(true)
|
|
|
|
// A save based on that empty read must not replace the presets
|
|
readFails.next = true
|
|
expect(() =>
|
|
createPreset({ name: "New", config: { AI_PROVIDER: "openai" } }),
|
|
).toThrow()
|
|
expect(loadPresets().presets.map((p) => p.name)).toEqual(["Mine"])
|
|
})
|
|
|
|
it("moves a file that is not JSON aside", () => {
|
|
writeFileSync(presetsFile(), "{not json")
|
|
expect(loadPresets().presets).toEqual([])
|
|
expect(existsSync(presetsFile())).toBe(false)
|
|
expect(
|
|
readdirSync(userData.dir).some((f) =>
|
|
f.startsWith("config-presets.json.corrupt-"),
|
|
),
|
|
).toBe(true)
|
|
})
|
|
})
|