diff --git a/src/api/coral-types.ts b/src/api/coral-types.ts index b9ffbca..666fa10 100644 --- a/src/api/coral-types.ts +++ b/src/api/coral-types.ts @@ -67,7 +67,7 @@ export interface AccountLoginParameter { /** /v3/Account/Login */ export interface AccountLogin { - user: CurrentUser; + user: CurrentUser; webApiServerCredential: { accessToken: string; expiresIn: number; @@ -83,9 +83,7 @@ export type AccountToken = AccountLogin; /** /v4/Account/Login */ export interface AccountLogin_4 { - user: Exclude & { - links: Exclude; - }; + user: CurrentUser; webApiServerCredential: { accessToken: string; expiresIn: number; @@ -377,7 +375,7 @@ export interface User { } /** /v4/User/ShowSelf */ -export interface CurrentUser { +export interface CurrentUser { id: number; nsaId: string; imageUri: string; @@ -386,17 +384,12 @@ export interface CurrentUser { supportId: string; isChildRestricted: boolean; etag: string; - links: { - nintendoAccount: { - membership: { - active: boolean; - }; - }; - friendCode: { - regenerable: boolean; - regenerableAt: number; - id: string; - }; + links: (boolean extends WithNintendoAccount ? { + nintendoAccount?: CurrentUserNintendoAccountLink; + } : true extends WithNintendoAccount ? { + nintendoAccount: CurrentUserNintendoAccountLink; + } : {}) & { + friendCode: CurrentUserFriendCodeLink; }; permissions: { playLog: PlayLogPermissions; @@ -406,6 +399,17 @@ export interface CurrentUser { presence: PresenceOnline_4 | PresenceOffline; } +export interface CurrentUserNintendoAccountLink { + membership: { + active: boolean; + }; +} +export interface CurrentUserFriendCodeLink { + regenerable: boolean; + regenerableAt: number; + id: string; +} + export enum PlayLogPermissions { EVERYONE = 'EVERYONE', FRIENDS = 'FRIENDS', diff --git a/src/api/coral.ts b/src/api/coral.ts index c8f8a10..9bf1ceb 100644 --- a/src/api/coral.ts +++ b/src/api/coral.ts @@ -63,7 +63,7 @@ export interface CoralApiInterface { getEvent(id: number): Promise>; getUser(id: number): Promise>; getUserByFriendCode(friend_code: string, hash?: string): Promise>; - getCurrentUser(): Promise>; + getCurrentUser(): Promise | CurrentUser>>; getReceivedFriendRequests(): Promise>; getSentFriendRequests(): Promise>; getFriendCodeUrl(): Promise>; @@ -260,7 +260,7 @@ export abstract class AbstractCoralApi { }); } - abstract getCurrentUser(): Promise>; + abstract getCurrentUser(): Promise | CurrentUser>>; async getFriendCodeUrl() { return this.call('/v3/Friend/CreateFriendCodeUrl', { @@ -502,7 +502,7 @@ export default class CoralApi extends AbstractCoralApi implements CoralApiInterf } async getCurrentUser() { - return this.call('/v4/User/ShowSelf', { + return this.call, {id: number}>('/v4/User/ShowSelf', { id: this[CoralUserIdSymbol], }); } diff --git a/src/api/znc-proxy.ts b/src/api/znc-proxy.ts index a97088d..b7493c8 100644 --- a/src/api/znc-proxy.ts +++ b/src/api/znc-proxy.ts @@ -175,7 +175,7 @@ export default class ZncProxyApi extends AbstractCoralApi implements CoralApiInt // } async getCurrentUser() { - const result = await this.fetchProxyApi<{user: CurrentUser}>('user'); + const result = await this.fetchProxyApi<{user: CurrentUser | CurrentUser}>('user'); return createResult(result, result.user); } @@ -338,7 +338,7 @@ export async function getPresenceFromUrl(presence_url: string, useragent?: strin const data = await response.json() as PresenceUrlResponse; - const user: CurrentUser | Friend | Friend_4 | undefined = + const user: CurrentUser | CurrentUser | Friend | Friend_4 | undefined = 'user' in data ? data.user : 'friend' in data ? data.friend : 'nsaId' in data ? data : diff --git a/src/app/browser/components/friend-code.tsx b/src/app/browser/components/friend-code.tsx index 75dcaef..a3b416a 100644 --- a/src/app/browser/components/friend-code.tsx +++ b/src/app/browser/components/friend-code.tsx @@ -1,10 +1,10 @@ import React, { useCallback, useMemo } from 'react'; import { StyleSheet, Text } from 'react-native'; -import { CurrentUser } from '../../../api/coral-types.js'; +import { CurrentUserFriendCodeLink } from '../../../api/coral-types.js'; import ipc from '../ipc.js'; export default function FriendCode(props: { - friendcode: CurrentUser['links']['friendCode']; + friendcode: CurrentUserFriendCodeLink; } | { id: string; }) { diff --git a/src/app/browser/components/nintendo-switch-user.tsx b/src/app/browser/components/nintendo-switch-user.tsx index d80bf21..1815a4c 100644 --- a/src/app/browser/components/nintendo-switch-user.tsx +++ b/src/app/browser/components/nintendo-switch-user.tsx @@ -6,7 +6,7 @@ export default function NintendoSwitchUser(props: { friend: Friend; nickname?: string; } | { - user: CurrentUser; + user: CurrentUser | CurrentUser; nickname?: string; }) { const user = 'friend' in props ? props.friend : props.user; diff --git a/src/app/main/ipc.ts b/src/app/main/ipc.ts index 9713b11..7825cbe 100644 --- a/src/app/main/ipc.ts +++ b/src/app/main/ipc.ts @@ -9,7 +9,7 @@ import { askAddNsoAccount, askAddPctlAccount } from './na-auth.js'; import { App } from './index.js'; import { EmbeddedPresenceMonitor } from './monitor.js'; import { DiscordPresenceConfiguration, DiscordPresenceSource, DiscordStatus, LoginItemOptions, WindowType } from '../common/types.js'; -import { CurrentUser, Friend, Game, PresencePlatform, PresenceState, WebService } from '../../api/coral-types.js'; +import { CurrentUser, CurrentUserFriendCodeLink, Friend, Game, PresencePlatform, PresenceState, WebService } from '../../api/coral-types.js'; import { NintendoAccountSessionTokenJwtPayload, NintendoAccountUser } from '../../api/na.js'; import { DiscordPresence } from '../../discord/types.js'; import { getDiscordRpcClients } from '../../discord/rpc.js'; @@ -201,7 +201,7 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) { handle('misc:share', (e, item: SharingItem) => new ShareMenu(item).popup({window: BrowserWindow.fromWebContents(e.sender)!})); - handle('menu:user', (e, user: NintendoAccountUser, nso?: CurrentUser, moon?: boolean) => + handle('menu:user', (e, user: NintendoAccountUser, nso?: CurrentUser | CurrentUser, moon?: boolean) => (buildUserMenu(appinstance, user, nso, moon, BrowserWindow.fromWebContents(e.sender) ?? undefined) .popup({window: BrowserWindow.fromWebContents(e.sender)!}), undefined)); handle('menu:add-user', e => (Menu.buildFromTemplate([ @@ -212,7 +212,7 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) { (item: MenuItem, window: BrowserWindow | undefined, event: KeyboardEvent) => askAddPctlAccount(appinstance, !event.shiftKey)}), ]).popup({window: BrowserWindow.fromWebContents(e.sender)!}), undefined)); - handle('menu:friend-code', (e, fc: CurrentUser['links']['friendCode']) => (Menu.buildFromTemplate([ + handle('menu:friend-code', (e, fc: CurrentUserFriendCodeLink) => (Menu.buildFromTemplate([ new MenuItem({label: 'SW-' + fc.id, enabled: false}), new MenuItem({label: t('friend_code.share')!, role: 'shareMenu', sharingItem: {texts: ['SW-' + fc.id]}}), new MenuItem({label: t('friend_code.copy')!, click: () => clipboard.writeText('SW-' + fc.id)}), @@ -223,7 +223,7 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) { formatParams: { date: { dateStyle: 'short', timeStyle: 'medium' } }, })!, enabled: false}), ]).popup({window: BrowserWindow.fromWebContents(e.sender)!}), undefined)); - handle('menu:friend', (e, user: NintendoAccountUser, nso: CurrentUser, friend: Friend) => + handle('menu:friend', (e, user: NintendoAccountUser, nso: CurrentUser | CurrentUser, friend: Friend) => (buildFriendMenu(appinstance, user, nso, friend) .popup({window: BrowserWindow.fromWebContents(e.sender)!}), undefined)); @@ -255,7 +255,7 @@ export function sendToAllWindows(channel: string, ...args: any[]) { } } -function buildUserMenu(app: App, user: NintendoAccountUser, nso?: CurrentUser, moon?: boolean, window?: BrowserWindow) { +function buildUserMenu(app: App, user: NintendoAccountUser, nso?: CurrentUser | CurrentUser, moon?: boolean, window?: BrowserWindow) { const t = app.i18n.getFixedT(null, 'menus', 'user'); const dm = app.monitors.getActiveDiscordPresenceMonitor(); const monitor = app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor && @@ -307,7 +307,7 @@ function buildUserMenu(app: App, user: NintendoAccountUser, nso?: CurrentUser, m ]); } -function buildFriendMenu(app: App, user: NintendoAccountUser, nso: CurrentUser, friend: Friend) { +function buildFriendMenu(app: App, user: NintendoAccountUser, nso: CurrentUser | CurrentUser, friend: Friend) { const t = app.i18n.getFixedT(null, 'menus', 'friend'); const discord_presence_source = app.monitors.getDiscordPresenceSource(); const discord_presence_active = !!discord_presence_source && 'na_id' in discord_presence_source && diff --git a/src/app/main/monitor.ts b/src/app/main/monitor.ts index 5b47712..d184cb2 100644 --- a/src/app/main/monitor.ts +++ b/src/app/main/monitor.ts @@ -574,7 +574,7 @@ export class ElectronNotificationManager extends NotificationManager { this.t = i18n.getFixedT(null, 'notifications'); } - async onFriendOnline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + async onFriendOnline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { const currenttitle = friend.presence.game as PresenceGame; new Notification({ @@ -585,7 +585,7 @@ export class ElectronNotificationManager extends NotificationManager { }).show(); } - async onFriendOffline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + async onFriendOffline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { new Notification({ title: friend.name, body: this.t('offline')!, @@ -593,7 +593,7 @@ export class ElectronNotificationManager extends NotificationManager { }).show(); } - async onFriendPlayingChangeTitle(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + async onFriendPlayingChangeTitle(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { const currenttitle = friend.presence.game as PresenceGame; new Notification({ @@ -604,7 +604,7 @@ export class ElectronNotificationManager extends NotificationManager { }).show(); } - async onFriendTitleStateChange(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + async onFriendTitleStateChange(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { const currenttitle = friend.presence.game as PresenceGame; new Notification({ diff --git a/src/app/preload/index.ts b/src/app/preload/index.ts index 472332b..6f80c00 100644 --- a/src/app/preload/index.ts +++ b/src/app/preload/index.ts @@ -7,7 +7,7 @@ import type { SavedToken } from '../../common/auth/coral.js'; import type { SavedMoonToken } from '../../common/auth/moon.js'; import type { UpdateCacheData } from '../../common/update.js'; import type { StatusUpdate } from '../../common/status.js'; -import type { Announcements_4, CoralSuccessResponse, CurrentUser, Friend, Friend_4, FriendCodeUrl, FriendCodeUser, GetActiveEventResult, ReceivedFriendRequests, SentFriendRequests, WebService, WebServices_4 } from '../../api/coral-types.js'; +import type { Announcements_4, CoralSuccessResponse, CurrentUser, CurrentUserFriendCodeLink, Friend, Friend_4, FriendCodeUrl, FriendCodeUser, GetActiveEventResult, ReceivedFriendRequests, SentFriendRequests, WebService, WebServices_4 } from '../../api/coral-types.js'; import type { DiscordPresence } from '../../discord/types.js'; import type { CachedErrorKey } from '../main/ipc.js'; import type { DiscordSetupProps } from '../browser/discord/index.js'; @@ -102,10 +102,10 @@ const ipc = { openExternalUrl: (url: string) => inv('misc:open-url', url), share: (item: SharingItem) => inv('misc:share', item), - showUserMenu: (user: NintendoAccountUserCoral | NintendoAccountUserMoon, nso?: CurrentUser, moon?: boolean) => inv('menu:user', user, nso, moon), + showUserMenu: (user: NintendoAccountUserCoral | NintendoAccountUserMoon, nso?: CurrentUser | CurrentUser, moon?: boolean) => inv('menu:user', user, nso, moon), showAddUserMenu: () => inv('menu:add-user'), - showFriendCodeMenu: (fc: CurrentUser['links']['friendCode']) => inv('menu:friend-code', fc), - showFriendMenu: (user: NintendoAccountUserCoral, nso: CurrentUser, friend: Friend_4) => inv('menu:friend', user, nso, friend), + showFriendCodeMenu: (fc: CurrentUserFriendCodeLink) => inv('menu:friend-code', fc), + showFriendMenu: (user: NintendoAccountUserCoral, nso: CurrentUser | CurrentUser, friend: Friend_4) => inv('menu:friend', user, nso, friend), registerEventListener: (event: string, listener: (args: any[]) => void) => events.on(event, listener), removeEventListener: (event: string, listener: (args: any[]) => void) => events.removeListener(event, listener), diff --git a/src/cli/nso/http-server.ts b/src/cli/nso/http-server.ts index 3135480..0a258db 100644 --- a/src/cli/nso/http-server.ts +++ b/src/cli/nso/http-server.ts @@ -962,7 +962,7 @@ class EventStreamNotificationManager extends NotificationManager { } onPresenceUpdated( - friend: CurrentUser | Friend, prev?: CurrentUser | Friend, type?: PresenceEvent, + friend: CurrentUser | Friend, prev?: CurrentUser | Friend, type?: PresenceEvent, naid?: string, ir?: boolean ) { this.stream.sendEvent(ZncPresenceEventStreamEvent.PRESENCE_UPDATED, { @@ -970,25 +970,25 @@ class EventStreamNotificationManager extends NotificationManager { }); } - onFriendOnline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendOnline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { this.stream.sendEvent(ZncPresenceEventStreamEvent.FRIEND_ONLINE, { id: friend.nsaId, presence: friend.presence, prev: prev?.presence, }); } - onFriendOffline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendOffline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { this.stream.sendEvent(ZncPresenceEventStreamEvent.FRIEND_OFFLINE, { id: friend.nsaId, presence: friend.presence, prev: prev?.presence, }); } - onFriendPlayingChangeTitle(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendPlayingChangeTitle(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { this.stream.sendEvent(ZncPresenceEventStreamEvent.FRIEND_TITLE_CHANGE, { id: friend.nsaId, presence: friend.presence, prev: prev?.presence, }); } - onFriendTitleStateChange(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendTitleStateChange(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { this.stream.sendEvent(ZncPresenceEventStreamEvent.FRIEND_TITLE_STATECHANGE, { id: friend.nsaId, presence: friend.presence, prev: prev?.presence, }); diff --git a/src/cli/nso/notify.ts b/src/cli/nso/notify.ts index 6270faa..d1f0daa 100644 --- a/src/cli/nso/notify.ts +++ b/src/cli/nso/notify.ts @@ -136,7 +136,7 @@ export class TerminalNotificationManager extends NotificationManager { super(); } - onFriendOnline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendOnline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { const currenttitle = friend.presence.game as PresenceGame; this.notifier.notify({ @@ -148,7 +148,7 @@ export class TerminalNotificationManager extends NotificationManager { }); } - onFriendOffline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendOffline(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { this.notifier.notify({ title: friend.name, message: 'Offline', @@ -156,7 +156,7 @@ export class TerminalNotificationManager extends NotificationManager { }); } - onFriendPlayingChangeTitle(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendPlayingChangeTitle(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { const currenttitle = friend.presence.game as PresenceGame; this.notifier.notify({ @@ -168,7 +168,7 @@ export class TerminalNotificationManager extends NotificationManager { }); } - onFriendTitleStateChange(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { + onFriendTitleStateChange(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean) { const currenttitle = friend.presence.game as PresenceGame; this.notifier.notify({ diff --git a/src/cli/nxapi-auth/link-url.ts b/src/cli/nxapi-auth/link-url.ts index 16601aa..8e34ccf 100644 --- a/src/cli/nxapi-auth/link-url.ts +++ b/src/cli/nxapi-auth/link-url.ts @@ -58,10 +58,10 @@ export async function handler(argv: ArgumentsCamelCase) { const friendcodeurl = await user.nso.getFriendCodeUrl(); const webservice = webservices.find(webservice => { + // Since coral 3.2.0 we can't check if the user has an active NSO + // membership, so just choose one that definitely won't fail const verifymembership = webservice.customAttributes.find(a => a.attrKey === 'verifyMembership'); - if (verifymembership?.attrValue === 'true' && - !user.data.nsoAccount.user.links.nintendoAccount.membership.active - ) return false; + if (verifymembership?.attrValue === 'true') return false; return true; }); diff --git a/src/cli/util/discord-activity.ts b/src/cli/util/discord-activity.ts index 59c9325..f37c4b7 100644 --- a/src/cli/util/discord-activity.ts +++ b/src/cli/util/discord-activity.ts @@ -1,7 +1,7 @@ import process from 'node:process'; import { fetch } from 'undici'; import { getPresenceFromUrl } from '../../api/znc-proxy.js'; -import { ActiveEvent, CurrentUser, Friend, PresenceGame, PresenceOffline, PresenceOnline, PresenceOnline_4, PresencePlatform, PresenceState } from '../../api/coral-types.js'; +import { ActiveEvent, CurrentUser, CurrentUserFriendCodeLink, Friend, PresenceGame, PresenceOffline, PresenceOnline, PresenceOnline_4, PresencePlatform, PresenceState } from '../../api/coral-types.js'; import type { Arguments as ParentArguments } from './index.js'; import { getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js'; import { DiscordPresenceContext, DiscordPresencePlayTime } from '../../discord/types.js'; @@ -184,8 +184,8 @@ async function getPresenceFromCoral(argv: ArgumentsCamelCase) { function getActivityFromPresence( argv: ArgumentsCamelCase, presence: Presence | null, - user?: CurrentUser | Friend, - friendcode?: CurrentUser['links']['friendCode'], + user?: CurrentUser | CurrentUser | Friend, + friendcode?: CurrentUserFriendCodeLink, activeevent?: ActiveEvent, proxy_response?: unknown, ) { diff --git a/src/client/coral.ts b/src/client/coral.ts index 7d6936f..b36a89f 100644 --- a/src/client/coral.ts +++ b/src/client/coral.ts @@ -56,7 +56,7 @@ export default class Coral { public chats: Result | null = null, public media: Result | null = null, public active_event: Result | null = null, - public current_user: Result | null = null, + public current_user: Result | CurrentUser> | null = null, ) { if (announcements) this.updated.announcements = Date.now(); if (friends) this.updated.friends = Date.now(); diff --git a/src/common/auth/util.ts b/src/common/auth/util.ts index fa7c02e..5cbf85e 100644 --- a/src/common/auth/util.ts +++ b/src/common/auth/util.ts @@ -118,6 +118,9 @@ export class RateLimitError extends Error implements HasErrorDescription { } export function checkMembershipActive(data: SavedToken) { + // Since 3.2.0 we can't check if the user has an active NSO membership + if (!('nintendoAccount' in data.nsoAccount.user.links)) return; + const membership = data.nsoAccount.user.links.nintendoAccount.membership; const active = typeof membership.active === 'object' ? (membership.active as typeof membership).active : membership.active; diff --git a/src/common/notify.ts b/src/common/notify.ts index 00ef669..1db53b0 100644 --- a/src/common/notify.ts +++ b/src/common/notify.ts @@ -1,8 +1,6 @@ -import persist from 'node-persist'; import { CoralApiInterface } from '../api/coral.js'; import { CurrentUser, Friend, Presence, PresenceState, CoralError, PresenceGame } from '../api/coral-types.js'; import { ErrorResponse } from '../api/util.js'; -import { SavedToken } from './auth/coral.js'; import { SplatNet2RecordsMonitor } from './splatnet2/monitor.js'; import createDebug from '../util/debug.js'; import Loop, { LoopResult } from '../util/loop.js'; @@ -35,7 +33,7 @@ export class ZncNotifications extends Loop { } async updateFriendsStatusForNotifications( - friends: (CurrentUser | Friend)[], + friends: (CurrentUser | Friend)[], naid = this.user.data.user.id, initialRun?: boolean ) { @@ -43,15 +41,15 @@ export class ZncNotifications extends Loop { } async updatePresenceForNotifications( - user: CurrentUser | null, friends: Friend[] | null, + user: CurrentUser | null, friends: Friend[] | null, naid = this.user.data.user.id, initialRun?: boolean ) { - await this.updateFriendsStatusForNotifications(([] as (CurrentUser | Friend)[]) + await this.updateFriendsStatusForNotifications(([] as (CurrentUser | Friend)[]) .concat(this.user_notifications && user ? [user] : []) .concat(this.friend_notifications && friends ? friends : []), naid, initialRun); } - async updatePresenceForSplatNet2Monitors(friends: (CurrentUser | Friend)[]) { + async updatePresenceForSplatNet2Monitors(friends: (CurrentUser | Friend)[]) { for (const friend of friends) { await this.updatePresenceForSplatNet2Monitor(friend.presence, friend.nsaId, friend.name); } @@ -91,8 +89,8 @@ export class ZncNotifications extends Loop { this.friend_notifications ? this.user.getFriends() : null, ]); - await this.updatePresenceForNotifications(user, friends, this.user.data.user.id, false); - if (user) await this.updatePresenceForSplatNet2Monitors([user]); + await this.updatePresenceForNotifications(user as CurrentUser, friends, this.user.data.user.id, false); + if (user) await this.updatePresenceForSplatNet2Monitors([user as CurrentUser]); } async handleError(err: ErrorResponse | NodeJS.ErrnoException): Promise { @@ -101,18 +99,18 @@ export class ZncNotifications extends Loop { } export class NotificationManager { - onPresenceUpdated?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, type?: PresenceEvent, naid?: string, ir?: boolean): void; + onPresenceUpdated?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, type?: PresenceEvent, naid?: string, ir?: boolean): void; - onFriendOnline?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; - onFriendOffline?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; - onFriendPlayingChangeTitle?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; - onFriendTitleStateChange?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; + onFriendOnline?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; + onFriendOffline?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; + onFriendPlayingChangeTitle?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; + onFriendTitleStateChange?(friend: CurrentUser | Friend, prev?: CurrentUser | Friend, naid?: string, ir?: boolean): void; - onlinefriends = new Map(); + onlinefriends = new Map | Friend)[]>(); accounts = new Map(); - updateFriendsStatusForNotifications(friends: (CurrentUser | Friend)[], naid: string, initialRun?: boolean) { - const newonlinefriends: (CurrentUser | Friend)[] = []; + updateFriendsStatusForNotifications(friends: (CurrentUser | Friend)[], naid: string, initialRun?: boolean) { + const newonlinefriends: (CurrentUser | Friend)[] = []; for (const friend of friends) { const prev = this.onlinefriends.get(naid)?.find(f => f.nsaId === friend.nsaId); diff --git a/src/common/presence.ts b/src/common/presence.ts index 85bfe03..2f7ad63 100644 --- a/src/common/presence.ts +++ b/src/common/presence.ts @@ -12,7 +12,7 @@ import { DiscordRpcClient, findDiscordRpcClient } from '../discord/rpc.js'; import { getDiscordPresence, getInactiveDiscordPresence } from '../discord/util.js'; import { DiscordPresencePlayTime, DiscordPresenceContext, DiscordPresence, ExternalMonitorConstructor, ExternalMonitor, ErrorResult } from '../discord/types.js'; import { CoralApiInterface } from '../api/coral.js'; -import { ActiveEvent, CurrentUser, Friend, Game, PresenceState, CoralError, PresenceOnline_4, PresenceOffline, PresenceOnline } from '../api/coral-types.js'; +import { ActiveEvent, CurrentUser, Friend, Game, PresenceState, CoralError, PresenceOnline_4, PresenceOffline, PresenceOnline, CurrentUserFriendCodeLink } from '../api/coral-types.js'; import { getPresenceFromUrl } from '../api/znc-proxy.js'; import { ErrorResponse, ResponseSymbol } from '../api/util.js'; import { CoralUser } from './users.js'; @@ -44,8 +44,8 @@ class ZncDiscordPresenceClient { protected i = 0; last_presence: Presence | null = null; - last_user: CurrentUser | Friend | null = null; - last_friendcode: CurrentUser['links']['friendCode'] | null = null; + last_user: CurrentUser | Friend | null = null; + last_friendcode: CurrentUserFriendCodeLink | null = null; last_event: ActiveEvent | null = null; last_activity: DiscordPresence | string | null = null; @@ -68,8 +68,8 @@ class ZncDiscordPresenceClient { async updatePresenceForDiscord( presence: Presence | null, - user?: CurrentUser | Friend | null, - friendcode?: CurrentUser['links']['friendCode'] | null, + user?: CurrentUser | Friend | null, + friendcode?: CurrentUserFriendCodeLink | null, activeevent?: ActiveEvent | null, ) { this.last_presence = presence; @@ -449,13 +449,13 @@ export class ZncDiscordPresence extends ZncNotifications { await this.savePresenceForTitleUpdateAt(friend.nsaId, friend.presence, this.discord.title?.since); } } else { - await this.discord.updatePresenceForDiscord(user!.presence, user, user!.links.friendCode, activeevent); + await this.discord.updatePresenceForDiscord(user!.presence, user as CurrentUser, user!.links.friendCode, activeevent); await this.savePresenceForTitleUpdateAt(user!.nsaId, user!.presence, this.discord.title?.since); } } - await this.updatePresenceForNotifications(user, friends, this.user.data.user.id, false); - if (user) await this.updatePresenceForSplatNet2Monitors([user]); + await this.updatePresenceForNotifications(user as CurrentUser, friends, this.user.data.user.id, false); + if (user) await this.updatePresenceForSplatNet2Monitors([user as CurrentUser]); } async onStop() { @@ -555,7 +555,7 @@ export class ZncProxyDiscordPresence extends Loop { this.last_data = data; this.proxy_temporary_errors = 0; - await this.discord.updatePresenceForDiscord(presence, user); + await this.discord.updatePresenceForDiscord(presence, user as Friend | CurrentUser); await this.updatePresenceForSplatNet2Monitor(presence, this.presence_url); const link_header = result[ResponseSymbol].headers.get('Link'); @@ -665,7 +665,7 @@ export class ZncProxyDiscordPresence extends Loop { this.updateStatusUpdateSource(links); }; - let user: CurrentUser | Friend | undefined = undefined; + let user: CurrentUser | Friend | undefined = undefined; let presence: Presence | null = null; this.last_data = {}; diff --git a/src/common/users.ts b/src/common/users.ts index 150c5bc..2b70cbc 100644 --- a/src/common/users.ts +++ b/src/common/users.ts @@ -109,7 +109,7 @@ export interface CoralUserData extends U chats: CoralSuccessResponse; media: CoralSuccessResponse; active_event: CoralSuccessResponse; - user: CoralSuccessResponse; + user: CoralSuccessResponse | CurrentUser>; } export class CoralUser implements CoralUserData { @@ -149,7 +149,7 @@ export class CoralUser implements CoralU public chats: CoralSuccessResponse, public media: CoralSuccessResponse, public active_event: CoralSuccessResponse, - public user: CoralSuccessResponse, + public user: CoralSuccessResponse | CurrentUser>, ) {} private async update(key: keyof CoralUser['updated'], callback: () => Promise, ttl: number) { diff --git a/src/discord/types.ts b/src/discord/types.ts index 86f8a1d..2f12b2f 100644 --- a/src/discord/types.ts +++ b/src/discord/types.ts @@ -1,18 +1,18 @@ import DiscordRPC from 'discord-rpc'; -import { ActiveEvent, CurrentUser, Friend, Game, PresencePlatform } from '../api/coral-types.js'; +import { ActiveEvent, CurrentUser, CurrentUserFriendCodeLink, Friend, Game, PresencePlatform } from '../api/coral-types.js'; import { ExternalMonitorPresenceInterface, ZncDiscordPresence, ZncProxyDiscordPresence } from '../common/presence.js'; import { EmbeddedLoop } from '../util/loop.js'; import { DiscordActivity } from './util.js'; export interface DiscordPresenceContext { - friendcode?: CurrentUser['links']['friendCode']; + friendcode?: CurrentUserFriendCodeLink; activeevent?: ActiveEvent; show_play_time?: DiscordPresencePlayTime; znc_discord_presence?: ZncDiscordPresence | ZncProxyDiscordPresence; proxy_response?: unknown; monitors?: ExternalMonitor[]; nsaid?: string; - user?: CurrentUser | Friend; + user?: CurrentUser | CurrentUser | Friend; platform?: PresencePlatform; }