feat(guides) : add safer publishing and discovery
CI / Verify (push) Successful in 1m35s
CI / Build immutable images and deploy (push) Successful in 5m27s

This commit is contained in:
2026-09-19 13:32:57 +07:00 Unverified
parent 6698dc1302
commit 9896e8a4ad
27 changed files with 3213 additions and 108 deletions
+18
View File
@@ -239,10 +239,17 @@ export async function listPublicGuideCards() {
name: guides.name,
overview: guides.overview,
version: guides.version,
updatedAt: guides.updatedAt,
publishedAt: guides.publishedAt,
publishedCatalogVersion: guides.publishedCatalogVersion,
element: catalogCharacters.element,
weaponType: catalogCharacters.weaponType,
rarity: catalogCharacters.rarity,
coverObjectKey: media.objectKey,
})
.from(guides)
.innerJoin(media, eq(media.id, guides.coverMediaId))
.innerJoin(catalogCharacters, eq(catalogCharacters.key, guides.characterKey))
.where(and(eq(guides.isPublic, true), isNull(guides.trashedAt)))
.orderBy(desc(guides.sortOrder), desc(guides.createdAt), asc(guides.name)), getDb().select({
kind: glossaryAliases.kind,
@@ -307,6 +314,7 @@ export async function getGuideByCharacterKey(characterKey: string) {
return {
...row.guide,
coverUrl: publicMediaUrl(row.cover.objectKey),
coverStatus: row.cover.status,
posterArtUrl: poster[0] ? publicMediaUrl(poster[0].objectKey) : null,
posterBleeding: bleeding.map(({ layer, asset }) => ({ ...layer, blendMode: (posterBlendModes.has(layer.blendMode) ? layer.blendMode : "multiply") as PosterBlendMode, imageUrl: asset ? publicMediaUrl(asset.objectKey) : null })),
character: catalogCharacterWithUrls(row.character, materialByKey),
@@ -399,6 +407,7 @@ async function getGuideContent(slug: string, publicOnly: boolean) {
return {
...row.guide,
coverUrl: publicMediaUrl(row.cover.objectKey),
coverStatus: row.cover.status,
posterArtUrl: poster[0] ? publicMediaUrl(poster[0].objectKey) : null,
posterBleeding: bleeding.map(({ layer, asset }) => ({ ...layer, blendMode: (posterBlendModes.has(layer.blendMode) ? layer.blendMode : "multiply") as PosterBlendMode, imageUrl: asset ? publicMediaUrl(asset.objectKey) : null })),
character: { ...catalogCharacterWithUrls(row.character, materialByKey), aliases: groupedAliases.character.get(row.character.key) ?? [] },
@@ -449,4 +458,13 @@ export function getAdminGuideContent(slug: string) {
return getGuideContent(slug, false);
}
export async function getAdminGuideContentById(guideId: string) {
const [guide] = await getDb()
.select({ slug: guides.slug })
.from(guides)
.where(and(eq(guides.id, guideId), isNull(guides.trashedAt)))
.limit(1);
return guide ? getGuideContent(guide.slug, false) : null;
}
export type PublicGuide = NonNullable<Awaited<ReturnType<typeof getPublicGuide>>>;