chore(server, stage-*): resolve type issue

This commit is contained in:
RainbowBird
2026-01-08 00:44:25 +08:00
parent d5a536ab8f
commit 059048f939
6 changed files with 51 additions and 47 deletions
+4 -3
View File
@@ -41,6 +41,7 @@ export function createCharacterRoutes(characterService: CharacterService) {
throw createBadRequestError('Invalid Request', 'INVALID_REQUEST', result.issues)
}
// @ts-expect-error - TODO: Fix this
const character = await characterService.create({
...result.output,
character: {
@@ -48,7 +49,7 @@ export function createCharacterRoutes(characterService: CharacterService) {
ownerId: user.id,
creatorId: user.id,
},
} as any)
})
return c.json(character, 201)
})
@@ -64,7 +65,7 @@ export function createCharacterRoutes(characterService: CharacterService) {
throw createBadRequestError('Invalid Request', 'INVALID_REQUEST', result.issues)
}
const existing = await characterService.findById(id, { withRelations: false })
const existing = await characterService.findById(id)
if (!existing)
throw createNotFoundError()
if (existing.ownerId !== user.id)
@@ -78,7 +79,7 @@ export function createCharacterRoutes(characterService: CharacterService) {
const user = c.get('user')!
const id = c.req.param('id')
const existing = await characterService.findById(id, { withRelations: false })
const existing = await characterService.findById(id)
if (!existing)
throw createNotFoundError()
if (existing.ownerId !== user.id)
+1 -1
View File
@@ -40,7 +40,7 @@ export function createProviderRoutes(providerService: ProviderService) {
const provider = await providerService.createUserConfig({
...result.output,
ownerId: user.id,
} as any)
})
return c.json(provider, 201)
})
+23 -27
View File
@@ -8,23 +8,21 @@ import * as userCharacterSchema from '../schemas/user-character'
export function createCharacterService(db: Database<typeof fullSchema>) {
return {
async findById(id: string, options: { withRelations?: boolean } = { withRelations: true }) {
async findById(id: string) {
return await db.query.character.findFirst({
where: and(
eq(schema.character.id, id),
isNull(schema.character.deletedAt),
),
with: options.withRelations
? {
capabilities: true,
avatarModels: true,
i18n: true,
prompts: true,
likes: true,
bookmarks: true,
cover: true,
}
: undefined,
with: {
capabilities: true,
avatarModels: true,
i18n: true,
prompts: true,
likes: true,
bookmarks: true,
cover: true,
},
})
},
@@ -44,18 +42,16 @@ export function createCharacterService(db: Database<typeof fullSchema>) {
})
},
async findAll(options: { withRelations?: boolean } = { withRelations: true }) {
async findAll() {
return await db.query.character.findMany({
where: isNull(schema.character.deletedAt),
with: options.withRelations
? {
i18n: true,
capabilities: true,
likes: true,
bookmarks: true,
cover: true,
}
: undefined,
with: {
i18n: true,
capabilities: true,
likes: true,
bookmarks: true,
cover: true,
},
})
},
@@ -150,30 +146,30 @@ export function createCharacterService(db: Database<typeof fullSchema>) {
await tx.insert(schema.characterCovers).values({
...data.cover,
characterId: inserted.id,
} as schema.NewCharacterCover)
})
}
if (data.capabilities?.length) {
await tx.insert(schema.characterCapabilities).values(
data.capabilities.map(c => ({ ...c, characterId: inserted.id }) as schema.NewCharacterCapability),
data.capabilities.map(c => ({ ...c, characterId: inserted.id })),
)
}
if (data.avatarModels?.length) {
await tx.insert(schema.avatarModel).values(
data.avatarModels.map(a => ({ ...a, characterId: inserted.id }) as schema.NewAvatarModel),
data.avatarModels.map(a => ({ ...a, characterId: inserted.id })),
)
}
if (data.i18n?.length) {
await tx.insert(schema.characterI18n).values(
data.i18n.map(i => ({ ...i, characterId: inserted.id }) as schema.NewCharacterI18n),
data.i18n.map(i => ({ ...i, characterId: inserted.id })),
)
}
if (data.prompts?.length) {
await tx.insert(schema.characterPrompts).values(
data.prompts.map(p => ({ ...p, characterId: inserted.id }) as schema.NewCharacterPrompt),
data.prompts.map(p => ({ ...p, characterId: inserted.id })),
)
}
@@ -10,7 +10,7 @@ import CharacterDialog from './components/CharacterDialog.vue'
import CharacterItem from './components/CharacterItem.vue'
const characterStore = useCharacterStore()
const { characters, isLoading } = storeToRefs(characterStore)
const { characters } = storeToRefs(characterStore)
// Fetch on mount
onMounted(() => {
@@ -22,7 +22,7 @@ const searchQuery = ref('')
const filteredCharacters = computed(() => {
const query = searchQuery.value.toLowerCase()
return Array.from(characters.value.values()).filter((char) => {
const i18n = char.i18n.find(i => i.language === 'en') || char.i18n[0]
const i18n = char.i18n?.find(i => i.language === 'en') || char.i18n?.[0]
return i18n?.name.toLowerCase().includes(query) || i18n?.description.toLowerCase().includes(query)
})
})
@@ -87,7 +87,7 @@ function handleActivate(char: Character) {
</div>
<!-- Content -->
<div v-if="isLoading && characters.size === 0" class="flex flex-1 items-center justify-center">
<div v-if="characters.size === 0" class="flex flex-1 items-center justify-center">
<div class="i-svg-spinners:90-ring-with-bg text-4xl text-primary-500" />
</div>
+13 -7
View File
@@ -1,10 +1,12 @@
import type { Character, CreateCharacterPayload, UpdateCharacterPayload } from '../types/character'
import { defineStore } from 'pinia'
import { parse } from 'valibot'
import { ref } from 'vue'
import { client } from '../composables/api'
import { useAsyncState } from '../composables/use-async-state'
import { CharacterWithRelationsSchema } from '../types/character'
export const useCharacterStore = defineStore('characters', () => {
const characters = ref<Map<string, Character>>(new Map())
@@ -21,7 +23,7 @@ export const useCharacterStore = defineStore('characters', () => {
characters.value.clear()
for (const char of data) {
characters.value.set(char.id, char)
characters.value.set(char.id, parse(CharacterWithRelationsSchema, char))
}
}, { immediate: true })
}
@@ -34,7 +36,8 @@ export const useCharacterStore = defineStore('characters', () => {
if (!res.ok) {
throw new Error('Failed to fetch character')
}
const character = await res.json()
const data = await res.json()
const character = parse(CharacterWithRelationsSchema, data)
characters.value.set(character.id, character)
return character
@@ -49,7 +52,8 @@ export const useCharacterStore = defineStore('characters', () => {
if (!res.ok) {
throw new Error('Failed to create character')
}
const character = await res.json()
const data = await res.json()
const character = parse(CharacterWithRelationsSchema, data)
characters.value.set(character.id, character)
return character
@@ -58,14 +62,16 @@ export const useCharacterStore = defineStore('characters', () => {
async function update(id: string, payload: UpdateCharacterPayload) {
return useAsyncState(async () => {
const res = await client.api.characters[':id'].$patch({
const res = await (client.api.characters[':id'].$patch)({
param: { id },
// @ts-expect-error FIXME: hono client typing misses json option for this route
json: payload,
})
if (!res.ok) {
throw new Error('Failed to update character')
}
const character = await res.json()
const data = await res.json()
const character = parse(CharacterWithRelationsSchema, data)
characters.value.set(character.id, character)
return character
@@ -87,7 +93,7 @@ export const useCharacterStore = defineStore('characters', () => {
async function like(id: string) {
return useAsyncState(async () => {
const res = await client.api.characters[':id'].$patch({
const res = await client.api.characters[':id'].like.$post({
param: { id },
})
if (!res.ok) {
@@ -100,7 +106,7 @@ export const useCharacterStore = defineStore('characters', () => {
async function bookmark(id: string) {
return useAsyncState(async () => {
const res = await client.api.characters[':id'].$patch({
const res = await client.api.characters[':id'].bookmark.$post({
param: { id },
})
if (!res.ok) {
+7 -6
View File
@@ -77,6 +77,7 @@ export const CharacterBaseSchema = object({
characterId: string(),
createdAt: DateSchema,
updatedAt: DateSchema,
deletedAt: optional(DateSchema),
})
export const CharacterCapabilitySchema = object({
@@ -121,12 +122,12 @@ export const CharacterPromptSchema = object({
export const CharacterWithRelationsSchema = object({
...CharacterBaseSchema.entries,
capabilities: array(CharacterCapabilitySchema),
avatarModels: array(AvatarModelSchema),
i18n: array(CharacterI18nSchema),
prompts: array(CharacterPromptSchema),
likes: array(object({ userId: string(), characterId: string() })),
bookmarks: array(object({ userId: string(), characterId: string() })),
capabilities: optional(array(CharacterCapabilitySchema)),
avatarModels: optional(array(AvatarModelSchema)),
i18n: optional(array(CharacterI18nSchema)),
prompts: optional(array(CharacterPromptSchema)),
likes: optional(array(object({ userId: string(), characterId: string() }))),
bookmarks: optional(array(object({ userId: string(), characterId: string() }))),
})
// --- API Request Schemas ---