-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathapi.ts
More file actions
88 lines (80 loc) · 3.31 KB
/
api.ts
File metadata and controls
88 lines (80 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { basename } from 'pathe'
import { getIcons } from '@iconify/utils'
import { hash } from 'ohash'
import { createError, getQuery, type H3Event } from 'h3'
import { consola } from 'consola'
import type { NuxtIconRuntimeOptions } from '../../schema-types'
// @ts-expect-error tsconfig.server has the types
import { useAppConfig, getRequestURL, defineCachedEventHandler } from '#imports'
import { collections } from '#nuxt-icon-server-bundle'
const warnOnceSet = /* @__PURE__ */ new Set<string>()
const DEFAULT_ENDPOINT = 'https://api.iconify.design'
function getInstallCommand(pkg: string): string {
const ua = process.env.npm_config_user_agent || ''
if (ua.startsWith('pnpm')) return `pnpm add -D ${pkg}`
if (ua.startsWith('yarn')) return `yarn add -D ${pkg}`
if (ua.startsWith('bun')) return `bun add -D ${pkg}`
return `npm i -D ${pkg}`
}
export default defineCachedEventHandler(async (event: H3Event) => {
const url = getRequestURL(event) as URL
if (!url)
return createError({ status: 400, message: 'Invalid icon request' })
const options = useAppConfig().icon as NuxtIconRuntimeOptions
const collectionName = event.context.params?.collection?.replace(/\.json$/, '')
const collection = collectionName
? await collections[collectionName]?.()
: null
const apiEndPoint = options.iconifyApiEndpoint || DEFAULT_ENDPOINT
const icons = url.searchParams.get('icons')?.split(',')
if (collection) {
if (icons?.length) {
const data = getIcons(
collection,
icons,
)
consola.debug(`[Icon] serving ${(icons || []).map(i => '`' + collectionName + ':' + i + '`').join(',')} from bundled collection`)
return data
}
}
else if (import.meta.dev) {
// Warn only once per collection, and only with the default endpoint
if (collectionName && !warnOnceSet.has(collectionName) && apiEndPoint === DEFAULT_ENDPOINT) {
consola.warn([
`[Icon] Collection \`${collectionName}\` is not found locally`,
`We suggest to install it via \`${getInstallCommand(`@iconify-json/${collectionName}`)}\` to provide the best end-user experience.`,
].join('\n'))
warnOnceSet.add(collectionName)
}
}
if (options.fallbackToApi === true || options.fallbackToApi === 'server-only') {
const apiUrl = new URL('./' + basename(url.pathname) + url.search, apiEndPoint)
consola.debug(`[Icon] fetching ${(icons || []).map(i => '`' + collectionName + ':' + i + '`').join(',')} from iconify api`)
if (apiUrl.host !== new URL(apiEndPoint).host) {
return createError({ status: 400, message: 'Invalid icon request' })
}
try {
const data = await $fetch(apiUrl.href)
return data
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
catch (e: any) {
consola.error(e)
if (e.status === 404)
return createError({ status: 404 })
else
return createError({ status: 500, message: 'Failed to fetch fallback icon' })
}
}
return createError({ status: 404 })
}, {
group: 'nuxt',
name: 'icon',
getKey(event: H3Event) {
const collection = event.context.params?.collection?.replace(/\.json$/, '') || 'unknown'
const icons = String(getQuery(event).icons || '')
return `${collection}_${icons.split(',')[0]}_${icons.length}_${hash(icons)}`
},
swr: true,
maxAge: 60 * 60 * 24 * 7, // 1 week
})