import { flattenEmojiData } from 'emojibase'; import type { CompactEmoji, FlatCompactEmoji } from 'emojibase'; import type { ApiCustomEmojiJSON } from '@/flavours/glitch/api_types/custom_emoji'; import { putEmojiData, putCustomEmojiData, loadLatestEtag, putLatestEtag, } from './database'; import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale'; import type { LocaleOrCustom } from './types'; import { emojiLogger } from './utils'; const log = emojiLogger('loader'); export async function importEmojiData(localeString: string) { const locale = toSupportedLocale(localeString); const emojis = await fetchAndCheckEtag(locale); if (!emojis) { return; } const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis); log('loaded %d for %s locale', flattenedEmojis.length, locale); await putEmojiData(flattenedEmojis, locale); } export async function importCustomEmojiData() { const emojis = await fetchAndCheckEtag('custom'); if (!emojis) { return; } log('loaded %d custom emojis', emojis.length); await putCustomEmojiData(emojis); } async function fetchAndCheckEtag( localeOrCustom: LocaleOrCustom, ): Promise { const locale = toSupportedLocaleOrCustom(localeOrCustom); // Use location.origin as this script may be loaded from a CDN domain. const url = new URL(location.origin); if (locale === 'custom') { url.pathname = '/api/v1/custom_emojis'; } else { // This doesn't use isDevelopment() as that module loads initial state // which breaks workers, as they cannot access the DOM. url.pathname = `/packs${import.meta.env.DEV ? '-dev' : ''}/emoji/${locale}.json`; } const oldEtag = await loadLatestEtag(locale); const response = await fetch(url, { headers: { 'Content-Type': 'application/json', 'If-None-Match': oldEtag ?? '', // Send the old ETag to check for modifications }, }); // If not modified, return null if (response.status === 304) { return null; } if (!response.ok) { throw new Error( `Failed to fetch emoji data for ${localeOrCustom}: ${response.statusText}`, ); } const data = (await response.json()) as ResultType; if (!Array.isArray(data)) { throw new Error( `Unexpected data format for ${localeOrCustom}: expected an array`, ); } // Store the ETag for future requests const etag = response.headers.get('ETag'); if (etag) { await putLatestEtag(etag, localeOrCustom); } return data; }