[Re] refactor(misskey-js): 警告をすべて解決 (#14277)

* chore(misskey-js): Unchanged files with check annotationsで紛らわしい部分の警告を抑制 ロジック面は後で直す

* dummy change to see if the feature do not report them (to be reverted after the check)

* refactor: 型合わせ

* refactor: fix warnings from c22dd6358b

* lint

* 型合わせ

* キャスト

* pnpm build-misskey-js-with-types

* Revert "dummy change to see if the feature do not report them (to be reverted after the check)"

This reverts commit 67072e3ca6.

* eliminate reversiGame any

* move reversiGame types

* lint

* Update packages/misskey-js/src/streaming.ts

Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>

* Update acct.ts

* run api extractor

* re-run api extractor

---------

Co-authored-by: Kisaragi Marine <kisaragi.effective@gmail.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
This commit is contained in:
Sayamame-beans 2024-07-25 16:40:14 +09:00 committed by GitHub
parent befa8e4a7f
commit 3d8eda14a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 118 additions and 73 deletions

View file

@ -1,6 +1,7 @@
import tsParser from '@typescript-eslint/parser'; import tsParser from '@typescript-eslint/parser';
import sharedConfig from '../shared/eslint.config.js'; import sharedConfig from '../shared/eslint.config.js';
// eslint-disable-next-line import/no-default-export
export default [ export default [
...sharedConfig, ...sharedConfig,
{ {

View file

@ -551,7 +551,7 @@ type Channel = components['schemas']['Channel'];
// Warning: (ae-forgotten-export) The symbol "AnyOf" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "AnyOf" needs to be exported by the entry point index.d.ts
// //
// @public (undocumented) // @public (undocumented)
export abstract class ChannelConnection<Channel extends AnyOf<Channels> = any> extends EventEmitter<Channel['events']> { export abstract class ChannelConnection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends EventEmitter<Channel['events']> {
constructor(stream: Stream, channel: string, name?: string); constructor(stream: Stream, channel: string, name?: string);
// (undocumented) // (undocumented)
channel: string; channel: string;
@ -771,12 +771,12 @@ export type Channels = {
user1: boolean; user1: boolean;
user2: boolean; user2: boolean;
}) => void; }) => void;
updateSettings: (payload: { updateSettings: <K extends ReversiUpdateKey>(payload: {
userId: User['id']; userId: User['id'];
key: string; key: K;
value: any; value: ReversiGameDetailed[K];
}) => void; }) => void;
log: (payload: Record<string, any>) => void; log: (payload: Record<string, unknown>) => void;
}; };
receives: { receives: {
putStone: { putStone: {
@ -785,10 +785,7 @@ export type Channels = {
}; };
ready: boolean; ready: boolean;
cancel: null | Record<string, never>; cancel: null | Record<string, never>;
updateSettings: { updateSettings: ReversiUpdateSettings<ReversiUpdateKey>;
key: string;
value: any;
};
claimTimeIsUp: null | Record<string, never>; claimTimeIsUp: null | Record<string, never>;
}; };
}; };
@ -2730,7 +2727,7 @@ type PagesUnlikeRequest = operations['pages___unlike']['requestBody']['content']
type PagesUpdateRequest = operations['pages___update']['requestBody']['content']['application/json']; type PagesUpdateRequest = operations['pages___update']['requestBody']['content']['application/json'];
// @public (undocumented) // @public (undocumented)
function parse(acct: string): Acct; function parse(_acct: string): Acct;
// Warning: (ae-forgotten-export) The symbol "Values" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Values" needs to be exported by the entry point index.d.ts
// //
@ -2969,7 +2966,7 @@ export class Stream extends EventEmitter<StreamEvents> {
constructor(origin: string, user: { constructor(origin: string, user: {
token: string; token: string;
} | null, options?: { } | null, options?: {
WebSocket?: any; WebSocket?: WebSocket;
}); });
// (undocumented) // (undocumented)
close(): void; close(): void;
@ -2992,9 +2989,9 @@ export class Stream extends EventEmitter<StreamEvents> {
// (undocumented) // (undocumented)
send(typeOrPayload: string): void; send(typeOrPayload: string): void;
// (undocumented) // (undocumented)
send(typeOrPayload: string, payload: any): void; send(typeOrPayload: string, payload: unknown): void;
// (undocumented) // (undocumented)
send(typeOrPayload: Record<string, any> | any[]): void; send(typeOrPayload: Record<string, unknown> | unknown[]): void;
// (undocumented) // (undocumented)
state: 'initializing' | 'reconnecting' | 'connected'; state: 'initializing' | 'reconnecting' | 'connected';
// (undocumented) // (undocumented)
@ -3229,7 +3226,9 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['
// Warnings were encountered during analysis: // Warnings were encountered during analysis:
// //
// src/entities.ts:34:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/entities.ts:35:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:220:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:230:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts
// (No @packageDocumentation comment for this package) // (No @packageDocumentation comment for this package)

View file

@ -3,7 +3,8 @@ export type Acct = {
host: string | null; host: string | null;
}; };
export function parse(acct: string): Acct { export function parse(_acct: string): Acct {
let acct = _acct;
if (acct.startsWith('@')) acct = acct.substring(1); if (acct.startsWith('@')) acct = acct.substring(1);
const split = acct.split('@', 2); const split = acct.split('@', 2);
return { username: split[0], host: split[1] || null }; return { username: split[0], host: split[1] || null };

View file

@ -14,6 +14,7 @@ export type APIError = {
code: string; code: string;
message: string; message: string;
kind: 'client' | 'server'; kind: 'client' | 'server';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
info: Record<string, any>; info: Record<string, any>;
}; };
@ -29,6 +30,7 @@ export type FetchLike = (input: string, init?: {
headers: { [key in string]: string } headers: { [key in string]: string }
}) => Promise<{ }) => Promise<{
status: number; status: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
json(): Promise<any>; json(): Promise<any>;
}>; }>;
@ -49,6 +51,7 @@ export class APIClient {
this.fetch = opts.fetch ?? ((...args) => fetch(...args)); this.fetch = opts.fetch ?? ((...args) => fetch(...args));
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private assertIsRecord<T>(obj: T): obj is T & Record<string, any> { private assertIsRecord<T>(obj: T): obj is T & Record<string, any> {
return obj !== null && typeof obj === 'object' && !Array.isArray(obj); return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
} }

View file

@ -28,11 +28,13 @@ type StrictExtract<Union, Cond> = Cond extends Union ? Union : never;
type IsCaseMatched<E extends keyof Endpoints, P extends Endpoints[E]['req'], C extends number> = type IsCaseMatched<E extends keyof Endpoints, P extends Endpoints[E]['req'], C extends number> =
Endpoints[E]['res'] extends SwitchCase Endpoints[E]['res'] extends SwitchCase
// eslint-disable-next-line @typescript-eslint/no-explicit-any
? IsNeverType<StrictExtract<Endpoints[E]['res']['$switch']['$cases'][C], [P, any]>> extends false ? true : false ? IsNeverType<StrictExtract<Endpoints[E]['res']['$switch']['$cases'][C], [P, any]>> extends false ? true : false
: false : false
type GetCaseResult<E extends keyof Endpoints, P extends Endpoints[E]['req'], C extends number> = type GetCaseResult<E extends keyof Endpoints, P extends Endpoints[E]['req'], C extends number> =
Endpoints[E]['res'] extends SwitchCase Endpoints[E]['res'] extends SwitchCase
// eslint-disable-next-line @typescript-eslint/no-explicit-any
? StrictExtract<Endpoints[E]['res']['$switch']['$cases'][C], [P, any]>[1] ? StrictExtract<Endpoints[E]['res']['$switch']['$cases'][C], [P, any]>[1]
: never : never

View file

@ -1,3 +1,13 @@
import type { operations } from './autogen/types.js';
import type {
AbuseReportNotificationRecipient, Ad,
Announcement,
EmojiDetailed, InviteCode,
MetaDetailed,
Note,
Role, SystemWebhook, UserLite,
} from './autogen/models.js';
export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const; export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const;
export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;
@ -135,10 +145,30 @@ export const moderationLogTypes = [
'unsetUserBanner', 'unsetUserBanner',
] as const; ] as const;
// See: packages/backend/src/core/ReversiService.ts@L410
export const reversiUpdateKeys = [
'map',
'bw',
'isLlotheo',
'canPutEverywhere',
'loopedBoard',
'timeLimitForEachTurn',
] as const;
export type ReversiUpdateKey = typeof reversiUpdateKeys[number];
type AvatarDecoration = UserLite['avatarDecorations'][number];
type ReceivedAbuseReport = {
reportId: AbuseReportNotificationRecipient['id'];
report: operations['admin___abuse-user-reports']['responses'][200]['content']['application/json'];
forwarded: boolean;
};
export type ModerationLogPayloads = { export type ModerationLogPayloads = {
updateServerSettings: { updateServerSettings: {
before: any | null; before: MetaDetailed | null;
after: any | null; after: MetaDetailed | null;
}; };
suspend: { suspend: {
userId: string; userId: string;
@ -159,16 +189,16 @@ export type ModerationLogPayloads = {
}; };
addCustomEmoji: { addCustomEmoji: {
emojiId: string; emojiId: string;
emoji: any; emoji: EmojiDetailed;
}; };
updateCustomEmoji: { updateCustomEmoji: {
emojiId: string; emojiId: string;
before: any; before: EmojiDetailed;
after: any; after: EmojiDetailed;
}; };
deleteCustomEmoji: { deleteCustomEmoji: {
emojiId: string; emojiId: string;
emoji: any; emoji: EmojiDetailed;
}; };
assignRole: { assignRole: {
userId: string; userId: string;
@ -187,16 +217,16 @@ export type ModerationLogPayloads = {
}; };
createRole: { createRole: {
roleId: string; roleId: string;
role: any; role: Role;
}; };
updateRole: { updateRole: {
roleId: string; roleId: string;
before: any; before: Role;
after: any; after: Role;
}; };
deleteRole: { deleteRole: {
roleId: string; roleId: string;
role: any; role: Role;
}; };
clearQueue: Record<string, never>; clearQueue: Record<string, never>;
promoteQueue: Record<string, never>; promoteQueue: Record<string, never>;
@ -211,39 +241,39 @@ export type ModerationLogPayloads = {
noteUserId: string; noteUserId: string;
noteUserUsername: string; noteUserUsername: string;
noteUserHost: string | null; noteUserHost: string | null;
note: any; note: Note;
}; };
createGlobalAnnouncement: { createGlobalAnnouncement: {
announcementId: string; announcementId: string;
announcement: any; announcement: Announcement;
}; };
createUserAnnouncement: { createUserAnnouncement: {
announcementId: string; announcementId: string;
announcement: any; announcement: Announcement;
userId: string; userId: string;
userUsername: string; userUsername: string;
userHost: string | null; userHost: string | null;
}; };
updateGlobalAnnouncement: { updateGlobalAnnouncement: {
announcementId: string; announcementId: string;
before: any; before: Announcement;
after: any; after: Announcement;
}; };
updateUserAnnouncement: { updateUserAnnouncement: {
announcementId: string; announcementId: string;
before: any; before: Announcement;
after: any; after: Announcement;
userId: string; userId: string;
userUsername: string; userUsername: string;
userHost: string | null; userHost: string | null;
}; };
deleteGlobalAnnouncement: { deleteGlobalAnnouncement: {
announcementId: string; announcementId: string;
announcement: any; announcement: Announcement;
}; };
deleteUserAnnouncement: { deleteUserAnnouncement: {
announcementId: string; announcementId: string;
announcement: any; announcement: Announcement;
userId: string; userId: string;
userUsername: string; userUsername: string;
userHost: string | null; userHost: string | null;
@ -281,37 +311,37 @@ export type ModerationLogPayloads = {
}; };
resolveAbuseReport: { resolveAbuseReport: {
reportId: string; reportId: string;
report: any; report: ReceivedAbuseReport;
forwarded: boolean; forwarded: boolean;
}; };
createInvitation: { createInvitation: {
invitations: any[]; invitations: InviteCode[];
}; };
createAd: { createAd: {
adId: string; adId: string;
ad: any; ad: Ad;
}; };
updateAd: { updateAd: {
adId: string; adId: string;
before: any; before: Ad;
after: any; after: Ad;
}; };
deleteAd: { deleteAd: {
adId: string; adId: string;
ad: any; ad: Ad;
}; };
createAvatarDecoration: { createAvatarDecoration: {
avatarDecorationId: string; avatarDecorationId: string;
avatarDecoration: any; avatarDecoration: AvatarDecoration;
}; };
updateAvatarDecoration: { updateAvatarDecoration: {
avatarDecorationId: string; avatarDecorationId: string;
before: any; before: AvatarDecoration;
after: any; after: AvatarDecoration;
}; };
deleteAvatarDecoration: { deleteAvatarDecoration: {
avatarDecorationId: string; avatarDecorationId: string;
avatarDecoration: any; avatarDecoration: AvatarDecoration;
}; };
unsetUserAvatar: { unsetUserAvatar: {
userId: string; userId: string;
@ -327,28 +357,28 @@ export type ModerationLogPayloads = {
}; };
createSystemWebhook: { createSystemWebhook: {
systemWebhookId: string; systemWebhookId: string;
webhook: any; webhook: SystemWebhook;
}; };
updateSystemWebhook: { updateSystemWebhook: {
systemWebhookId: string; systemWebhookId: string;
before: any; before: SystemWebhook;
after: any; after: SystemWebhook;
}; };
deleteSystemWebhook: { deleteSystemWebhook: {
systemWebhookId: string; systemWebhookId: string;
webhook: any; webhook: SystemWebhook;
}; };
createAbuseReportNotificationRecipient: { createAbuseReportNotificationRecipient: {
recipientId: string; recipientId: string;
recipient: any; recipient: AbuseReportNotificationRecipient;
}; };
updateAbuseReportNotificationRecipient: { updateAbuseReportNotificationRecipient: {
recipientId: string; recipientId: string;
before: any; before: AbuseReportNotificationRecipient;
after: any; after: AbuseReportNotificationRecipient;
}; };
deleteAbuseReportNotificationRecipient: { deleteAbuseReportNotificationRecipient: {
recipientId: string; recipientId: string;
recipient: any; recipient: AbuseReportNotificationRecipient;
}; };
}; };

View file

@ -7,7 +7,7 @@ import {
Role, Role,
RolePolicies, RolePolicies,
User, User,
UserDetailedNotMe UserDetailedNotMe,
} from './autogen/models.js'; } from './autogen/models.js';
export * from './autogen/entities.js'; export * from './autogen/entities.js';
@ -19,6 +19,7 @@ export type DateString = string;
export type PageEvent = { export type PageEvent = {
pageId: Page['id']; pageId: Page['id'];
event: string; event: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var: any; var: any;
userId: User['id']; userId: User['id'];
user: User; user: User;

View file

@ -15,7 +15,7 @@ export function urlQuery(obj: Record<string, string | number | boolean | undefin
.join('&'); .join('&');
} }
type AnyOf<T extends Record<any, any>> = T[keyof T]; type AnyOf<T extends Record<PropertyKey, unknown>> = T[keyof T];
type StreamEvents = { type StreamEvents = {
_connected_: void; _connected_: void;
@ -25,6 +25,7 @@ type StreamEvents = {
/** /**
* Misskey stream connection * Misskey stream connection
*/ */
// eslint-disable-next-line import/no-default-export
export default class Stream extends EventEmitter<StreamEvents> { export default class Stream extends EventEmitter<StreamEvents> {
private stream: _ReconnectingWebsocket.default; private stream: _ReconnectingWebsocket.default;
public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing'; public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing';
@ -34,7 +35,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
private idCounter = 0; private idCounter = 0;
constructor(origin: string, user: { token: string; } | null, options?: { constructor(origin: string, user: { token: string; } | null, options?: {
WebSocket?: any; WebSocket?: WebSocket;
}) { }) {
super(); super();
@ -51,6 +52,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
this.send = this.send.bind(this); this.send = this.send.bind(this);
this.close = this.close.bind(this); this.close = this.close.bind(this);
// eslint-disable-next-line no-param-reassign
options = options ?? { }; options = options ?? { };
const query = urlQuery({ const query = urlQuery({
@ -91,8 +93,8 @@ export default class Stream extends EventEmitter<StreamEvents> {
this.sharedConnectionPools.push(pool); this.sharedConnectionPools.push(pool);
} }
const connection = new SharedConnection(this, channel, pool, name); const connection = new SharedConnection<Channels[C]>(this, channel, pool, name);
this.sharedConnections.push(connection); this.sharedConnections.push(connection as unknown as SharedConnection);
return connection; return connection;
} }
@ -106,7 +108,7 @@ export default class Stream extends EventEmitter<StreamEvents> {
private connectToChannel<C extends keyof Channels>(channel: C, params: Channels[C]['params']): NonSharedConnection<Channels[C]> { private connectToChannel<C extends keyof Channels>(channel: C, params: Channels[C]['params']): NonSharedConnection<Channels[C]> {
const connection = new NonSharedConnection(this, channel, this.genId(), params); const connection = new NonSharedConnection(this, channel, this.genId(), params);
this.nonSharedConnections.push(connection); this.nonSharedConnections.push(connection as unknown as NonSharedConnection);
return connection; return connection;
} }
@ -174,9 +176,9 @@ export default class Stream extends EventEmitter<StreamEvents> {
* ! JSONで行われます ! * ! JSONで行われます !
*/ */
public send(typeOrPayload: string): void public send(typeOrPayload: string): void
public send(typeOrPayload: string, payload: any): void public send(typeOrPayload: string, payload: unknown): void
public send(typeOrPayload: Record<string, any> | any[]): void public send(typeOrPayload: Record<string, unknown> | unknown[]): void
public send(typeOrPayload: string | Record<string, any> | any[], payload?: any): void { public send(typeOrPayload: string | Record<string, unknown> | unknown[], payload?: unknown): void {
if (typeof typeOrPayload === 'string') { if (typeof typeOrPayload === 'string') {
this.stream.send(JSON.stringify({ this.stream.send(JSON.stringify({
type: typeOrPayload, type: typeOrPayload,
@ -211,7 +213,7 @@ class Pool {
public id: string; public id: string;
protected stream: Stream; protected stream: Stream;
public users = 0; public users = 0;
private disposeTimerId: any; private disposeTimerId: ReturnType<typeof setTimeout> | null = null;
private isConnected = false; private isConnected = false;
constructor(stream: Stream, channel: string, id: string) { constructor(stream: Stream, channel: string, id: string) {
@ -275,7 +277,7 @@ class Pool {
} }
} }
export abstract class Connection<Channel extends AnyOf<Channels> = any> extends EventEmitter<Channel['events']> { export abstract class Connection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends EventEmitter<Channel['events']> {
public channel: string; public channel: string;
protected stream: Stream; protected stream: Stream;
public abstract id: string; public abstract id: string;
@ -309,7 +311,7 @@ export abstract class Connection<Channel extends AnyOf<Channels> = any> extends
public abstract dispose(): void; public abstract dispose(): void;
} }
class SharedConnection<Channel extends AnyOf<Channels> = any> extends Connection<Channel> { class SharedConnection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends Connection<Channel> {
private pool: Pool; private pool: Pool;
public get id(): string { public get id(): string {
@ -328,11 +330,11 @@ class SharedConnection<Channel extends AnyOf<Channels> = any> extends Connection
public dispose(): void { public dispose(): void {
this.pool.dec(); this.pool.dec();
this.removeAllListeners(); this.removeAllListeners();
this.stream.removeSharedConnection(this); this.stream.removeSharedConnection(this as unknown as SharedConnection);
} }
} }
class NonSharedConnection<Channel extends AnyOf<Channels> = any> extends Connection<Channel> { class NonSharedConnection<Channel extends AnyOf<Channels> = AnyOf<Channels>> extends Connection<Channel> {
public id: string; public id: string;
protected params: Channel['params']; protected params: Channel['params'];
@ -359,6 +361,6 @@ class NonSharedConnection<Channel extends AnyOf<Channels> = any> extends Connect
public dispose(): void { public dispose(): void {
this.removeAllListeners(); this.removeAllListeners();
this.stream.send('disconnect', { id: this.id }); this.stream.send('disconnect', { id: this.id });
this.stream.disconnectToChannel(this); this.stream.disconnectToChannel(this as unknown as NonSharedConnection);
} }
} }

View file

@ -21,6 +21,14 @@ import {
ServerStatsLog, ServerStatsLog,
ReversiGameDetailed, ReversiGameDetailed,
} from './entities.js'; } from './entities.js';
import {
ReversiUpdateKey,
} from './consts.js';
type ReversiUpdateSettings<K extends ReversiUpdateKey> = {
key: K;
value: ReversiGameDetailed[K];
};
export type Channels = { export type Channels = {
main: { main: {
@ -51,6 +59,7 @@ export type Channels = {
registryUpdated: (payload: { registryUpdated: (payload: {
scope?: string[]; scope?: string[];
key: string; key: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any | null; value: any | null;
}) => void; }) => void;
driveFileCreated: (payload: DriveFile) => void; driveFileCreated: (payload: DriveFile) => void;
@ -208,8 +217,8 @@ export type Channels = {
ended: (payload: { winnerId: User['id'] | null; game: ReversiGameDetailed; }) => void; ended: (payload: { winnerId: User['id'] | null; game: ReversiGameDetailed; }) => void;
canceled: (payload: { userId: User['id']; }) => void; canceled: (payload: { userId: User['id']; }) => void;
changeReadyStates: (payload: { user1: boolean; user2: boolean; }) => void; changeReadyStates: (payload: { user1: boolean; user2: boolean; }) => void;
updateSettings: (payload: { userId: User['id']; key: string; value: any; }) => void; updateSettings: <K extends ReversiUpdateKey>(payload: { userId: User['id']; key: K; value: ReversiGameDetailed[K]; }) => void;
log: (payload: Record<string, any>) => void; log: (payload: Record<string, unknown>) => void;
}; };
receives: { receives: {
putStone: { putStone: {
@ -218,10 +227,7 @@ export type Channels = {
}; };
ready: boolean; ready: boolean;
cancel: null | Record<string, never>; cancel: null | Record<string, never>;
updateSettings: { updateSettings: ReversiUpdateSettings<ReversiUpdateKey>;
key: string;
value: any;
};
claimTimeIsUp: null | Record<string, never>; claimTimeIsUp: null | Record<string, never>;
} }
} }