diff --git a/packages/sw/src/@types/global.d.ts b/packages/sw/src/@types/global.d.ts new file mode 100644 index 000000000..5aaef9412 --- /dev/null +++ b/packages/sw/src/@types/global.d.ts @@ -0,0 +1,7 @@ +type FIXME = any; + +declare const _LANGS_: string[][]; +declare const _VERSION_: string; +declare const _ENV_: string; +declare const _DEV_: boolean; +declare const _PERF_PREFIX_: string; diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts index 6744687fc..6e7845f66 100644 --- a/packages/sw/src/scripts/create-notification.ts +++ b/packages/sw/src/scripts/create-notification.ts @@ -30,7 +30,7 @@ export async function createNotification(data: pushNotificationDataMap[K]): Promise<[string, NotificationOptions] | null> { +async function composeNotification(data: pushNotificationDataMap[keyof pushNotificationDataMap]): Promise<[string, NotificationOptions] | null> { if (!swLang.i18n) swLang.fetchLocale(); const i18n = await swLang.i18n as I18n; const { t } = i18n; @@ -66,7 +66,7 @@ async function composeNotification(data case 'mention': return [t('_notification.youGotMention', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('at'), data, @@ -80,7 +80,7 @@ async function composeNotification(data case 'reply': return [t('_notification.youGotReply', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('arrow-back-up'), data, @@ -94,7 +94,7 @@ async function composeNotification(data case 'renote': return [t('_notification.youRenoted', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('repeat'), data, @@ -108,7 +108,7 @@ async function composeNotification(data case 'quote': return [t('_notification.youGotQuote', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('quote'), data, @@ -162,7 +162,7 @@ async function composeNotification(data } return [`${reaction} ${getUserName(data.body.user)}`, { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge, data, @@ -227,9 +227,9 @@ async function composeNotification(data }]; case 'app': - return [data.body.header || data.body.body, { - body: data.body.header && data.body.body, - icon: data.body.icon, + return [data.body.header ?? data.body.body, { + body: data.body.header ? data.body.body : '', + icon: data.body.icon ?? undefined, data, }]; @@ -246,7 +246,7 @@ async function composeNotification(data renotify: true, }]; } - return [t('_notification.youGotMessagingMessageFromGroup', { name: data.body.group.name }), { + return [t('_notification.youGotMessagingMessageFromGroup', { name: data.body.group?.name ?? '' }), { icon: data.body.user.avatarUrl, badge: iconUrl('messages'), tag: `messaging:group:${data.body.groupId}`, @@ -255,7 +255,7 @@ async function composeNotification(data }]; case 'unreadAntennaNote': return [t('_notification.unreadAntennaNote', { name: data.body.antenna.name }), { - body: `${getUserName(data.body.note.user)}: ${data.body.note.text || ''}`, + body: `${getUserName(data.body.note.user)}: ${data.body.note.text ?? ''}`, icon: data.body.note.user.avatarUrl, badge: iconUrl('antenna'), tag: `antenna:${data.body.antenna.id}`, @@ -272,7 +272,7 @@ export async function createEmptyNotification() { if (!swLang.i18n) swLang.fetchLocale(); const i18n = await swLang.i18n as I18n; const { t } = i18n; - + await self.registration.showNotification( t('_notification.emptyPushNotificationMessage'), { diff --git a/packages/sw/src/scripts/get-user-name.ts b/packages/sw/src/scripts/get-user-name.ts index d499ea020..ccc38c298 100644 --- a/packages/sw/src/scripts/get-user-name.ts +++ b/packages/sw/src/scripts/get-user-name.ts @@ -1,3 +1,7 @@ export default function(user: { name?: string | null, username: string }): string { + // Show username if name is empty. + // XXX: typescript-eslint has no configuration to allow using `||` against string. + // https://github.com/typescript-eslint/typescript-eslint/issues/4906 + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing return user.name || user.username; } diff --git a/packages/sw/src/scripts/notification-read.ts b/packages/sw/src/scripts/notification-read.ts index 5ad748b84..3b1dde0cd 100644 --- a/packages/sw/src/scripts/notification-read.ts +++ b/packages/sw/src/scripts/notification-read.ts @@ -28,7 +28,7 @@ class SwNotificationReadManager { } // プッシュ通知の既読をサーバーに送信 - public async read(data: pushNotificationDataMap[K]) { + public async read(data: pushNotificationDataMap[keyof pushNotificationDataMap]) { if (data.type !== 'notification' || !(data.userId in this.accounts)) return; const account = this.accounts[data.userId]; diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index d47563939..55f881cd4 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -5,11 +5,11 @@ import { pushNotificationDataMap } from '@/types'; import * as swos from '@/scripts/operations'; import { acct as getAcct } from '@/filters/user'; -self.addEventListener('install', ev => { +globalThis.addEventListener('install', ev => { ev.waitUntil(self.skipWaiting()); }); -self.addEventListener('activate', ev => { +globalThis.addEventListener('activate', ev => { ev.waitUntil( caches.keys() .then(cacheNames => Promise.all( @@ -21,7 +21,7 @@ self.addEventListener('activate', ev => { ); }); -self.addEventListener('fetch', ev => { +globalThis.addEventListener('fetch', ev => { let isHTMLRequest = false; if (ev.request.headers.get('sec-fetch-dest') === 'document') { isHTMLRequest = true; @@ -38,13 +38,13 @@ self.addEventListener('fetch', ev => { ); }); -self.addEventListener('push', ev => { +globalThis.addEventListener('push', ev => { // クライアント取得 ev.waitUntil(self.clients.matchAll({ includeUncontrolled: true, type: 'window' - }).then(async (clients: readonly WindowClient[]) => { - const data: pushNotificationDataMap[K] = ev.data?.json(); + }).then(async (clients: readonly WindowClient[]) => { + const data: pushNotificationDataMap[keyof pushNotificationDataMap] = ev.data?.json(); switch (data.type) { // case 'driveFileCreated': @@ -104,17 +104,17 @@ self.addEventListener('push', ev => { })); }); -self.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEventMap['notificationclick']) => { +globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEventMap['notificationclick']) => { ev.waitUntil((async () => { if (_DEV_) { console.log('notificationclick', ev.action, ev.notification.data); } - + const { action, notification } = ev; - const data: pushNotificationDataMap[K] = notification.data; + const data: pushNotificationDataMap[keyof pushNotificationDataMap] = notification.data; const { userId: loginId } = data; let client: WindowClient | null = null; - + switch (data.type) { case 'notification': switch (action) { @@ -180,27 +180,27 @@ self.addEventListener('notificationclick', that.read(data)); } - + notification.close(); })()); }); -self.addEventListener('notificationclose', (ev: ServiceWorkerGlobalScopeEventMap['notificationclose']) => { - const data: pushNotificationDataMap[K] = ev.notification.data; +globalThis.addEventListener('notificationclose', (ev: ServiceWorkerGlobalScopeEventMap['notificationclose']) => { + const data: pushNotificationDataMap[keyof pushNotificationDataMap] = ev.notification.data; if (data.type === 'notification') { swNotificationRead.then(that => that.read(data)); } }); -self.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => { +globalThis.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => { ev.waitUntil((async () => { switch (ev.data) { case 'clear': @@ -211,11 +211,11 @@ self.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message' )); return; // TODO } - + if (typeof ev.data === 'object') { // E.g. '[object Array]' → 'array' const otype = Object.prototype.toString.call(ev.data).slice(8, -1).toLowerCase(); - + if (otype === 'object') { if (ev.data.msg === 'initialize') { swLang.setLang(ev.data.lang);