badgen.net/libs/serve-badge-next.ts

112 wiersze
2.8 KiB
TypeScript

import { badgen } from 'badgen'
import icons from 'badgen-icons'
import originalUrl from 'original-url'
import { BadgenParams } from './types'
import type { NextApiRequest, NextApiResponse } from 'next'
type ServeBadgeOptions = {
code?: number
sMaxAge?: number,
params: BadgenParams
}
export function serveBadgeNext (req: NextApiRequest, res: NextApiResponse, options: ServeBadgeOptions) {
const { code = 200, sMaxAge = 3600, params } = options
const { subject, status, color } = params
const query = req.query
const { list, scale, cache } = req.query
const iconMeta = resolveIcon(query.icon, query.iconWidth)
const badgeParams = {
labelColor: resolveColor(query.labelColor, '555'),
subject: formatSVGText(typeof query.label === 'string' ? query.label : subject),
status: formatSVGText(transformStatus(status, { list })),
color: resolveColor(query.color || color, 'blue'),
style: resolveBadgeStyle(req),
icon: iconMeta.src,
iconWidth: iconMeta.width,
scale: parseFloat(String(scale)) || 1,
}
const badgeSVGString = badgen(badgeParams)
// Minimum s-maxage is set to 300s(5m)
if (res.getHeader('cache-control') === undefined) {
const cacheMaxAge = cache ? Math.max(parseInt(String(cache)), 300) : sMaxAge
res.setHeader('cache-control', `public, max-age=86400, s-maxage=${cacheMaxAge}, stale-while-revalidate=86400`)
}
res.setHeader('Content-Type', 'image/svg+xml;charset=utf-8')
res.statusCode = code
res.send(badgeSVGString)
}
function resolveBadgeStyle (req: NextApiRequest, style?: string | string[]): 'flat' | 'classic' {
if (style === 'flat') {
return 'flat'
}
if (process.env.BADGE_STYLE === 'flat') {
return 'flat'
}
if (originalUrl(req).hostname.includes('flat')) {
return 'flat'
}
return 'classic'
}
function formatSVGText (text: string): string {
return text
.replace(/%2F/g, '/') // simple decode
}
function transformStatus (status: any, { list }): string {
status = String(status)
if (list !== undefined) {
if (list === '1' || list === '') list = '|' // compatible
status = status.replace(/,/g, ` ${list} `)
}
return status
}
function resolveColor (color: string | string[] | undefined, defaultColor: string): string {
if (color !== undefined) {
return String(color)
}
return defaultColor
}
type ResolvedIcon = {
src?: string
width?: number
}
function resolveIcon (icon?: string | string[], width?: string | string[]): ResolvedIcon {
const iconArg = String(icon) || ''
const widthNum = parseInt(String(width)) || 10
const builtinIcon = icons[icon]
if (builtinIcon) {
return {
src: builtinIcon.base64,
width: widthNum || builtinIcon.width
}
}
if (iconArg.startsWith('data:image/')) {
return { src: iconArg, width: widthNum }
}
return {}
}