1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-23 19:14:19 +02:00

Merge branch 'develop' into copilot/add-user-mute-settings

This commit is contained in:
かっこかり
2025-11-10 18:38:04 +09:00
committed by GitHub
36 changed files with 376 additions and 161 deletions

View File

@@ -13,17 +13,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPagination>
</template>
<script lang="ts" setup>
<script lang="ts" setup generic="P extends IPaginator">
import * as Misskey from 'misskey-js';
import type { IPaginator } from '@/utility/paginator.js';
import type { IPaginator, ExtractorFunction } from '@/utility/paginator.js';
import MkChannelPreview from '@/components/MkChannelPreview.vue';
import MkPagination from '@/components/MkPagination.vue';
import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{
paginator: IPaginator;
paginator: P;
noGap?: boolean;
extractor?: (item: any) => Misskey.entities.Channel;
extractor?: ExtractorFunction<P, Misskey.entities.Channel>;
}>(), {
extractor: (item) => item,
});

View File

@@ -38,7 +38,7 @@ export const Default = {
};
},
args: {
imageFile: file(),
imageFile: new File([], 'image.webp', { type: 'image/webp' }),
aspectRatio: NaN,
},
parameters: {

View File

@@ -60,7 +60,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<button class="_buttonPrimary" style="padding: 4px; border-radius: 8px;" @click="addVisibleUser"><i class="ti ti-plus ti-fw"></i></button>
</div>
</div>
<MkInfo v-if="!store.r.tips.value.postForm" :class="$style.showHowToUse"><button class="_textButton" @click="showTour">{{ i18n.ts._postForm.showHowToUse }}</button></MkInfo>
<MkInfo v-if="!store.r.tips.value.postForm" :class="$style.showHowToUse" closable @close="closeTip('postForm')">
<button class="_textButton" @click="showTour">{{ i18n.ts._postForm.showHowToUse }}</button>
</MkInfo>
<MkInfo v-if="scheduledAt != null" :class="$style.scheduledAt">
<I18n :src="i18n.ts.scheduleToPostOnX" tag="span">
<template #x>

View File

@@ -120,6 +120,7 @@ function onPasskeyLogin(): void {
.then((res) => {
passkeyContext.value = res.context ?? '';
credentialRequest.value = parseRequestOptionsFromJSON({
// @ts-expect-error TODO: misskey-js由来の型@simplewebauthn/typesとフロントエンド由来の型@github/webauthn-jsonが合わない
publicKey: res.option,
});
@@ -134,7 +135,7 @@ function onPasskeyDone(credential: AuthenticationPublicKeyCredential): void {
waiting.value = true;
if (doingPasskeyFromInputPage.value) {
misskeyApi('signin-with-passkey', {
misskeyApi<Misskey.entities.SigninWithPasskeyResponse>('signin-with-passkey', {
credential: credential.toJSON(),
context: passkeyContext.value,
}).then((res) => {
@@ -149,6 +150,7 @@ function onPasskeyDone(credential: AuthenticationPublicKeyCredential): void {
tryLogin({
username: userInfo.value.username,
password: password.value,
// @ts-expect-error TODO: misskey-js由来の型@simplewebauthn/typesとフロントエンド由来の型@github/webauthn-jsonが合わない
credential: credential.toJSON(),
});
}
@@ -253,6 +255,7 @@ async function tryLogin(req: Partial<Misskey.entities.SigninFlowRequest>): Promi
case 'passkey': {
if (webAuthnSupported()) {
credentialRequest.value = parseRequestOptionsFromJSON({
// @ts-expect-error TODO: misskey-js由来の型@simplewebauthn/typesとフロントエンド由来の型@github/webauthn-jsonが合わない
publicKey: res.authRequest,
});
page.value = 'passkey';

View File

@@ -15,17 +15,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPagination>
</template>
<script lang="ts" setup>
<script lang="ts" setup generic="P extends IPaginator">
import * as Misskey from 'misskey-js';
import type { IPaginator } from '@/utility/paginator.js';
import type { IPaginator, ExtractorFunction } from '@/utility/paginator.js';
import MkUserInfo from '@/components/MkUserInfo.vue';
import MkPagination from '@/components/MkPagination.vue';
import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{
paginator: IPaginator;
paginator: P;
noGap?: boolean;
extractor?: (item: any) => Misskey.entities.UserDetailed;
extractor?: ExtractorFunction<P, Misskey.entities.UserDetailed>;
}>(), {
extractor: (item) => item,
});

View File

@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<h1 :class="$style.mainTitle">
<!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に -->
<!-- <img class="logo" v-if="instance.logoImageUrl" :src="instance.logoImageUrl"><span v-else class="text">{{ instanceName }}</span> -->
<span>{{ instanceName }}</span>
<MkA to="/">{{ instanceName }}</MkA>
</h1>
<div :class="$style.mainAbout">
<!-- eslint-disable-next-line vue/no-v-html -->

View File

@@ -19,10 +19,13 @@ export function useForm<T extends Record<string, any>>(initialState: T, save: (n
const currentState = reactive<T>(copy(initialState));
const previousState = reactive<T>(copy(initialState));
const modifiedStates = reactive<Record<keyof T, boolean>>({} as any);
for (const key in currentState) {
modifiedStates[key] = false;
}
const modifiedStates = reactive<Record<keyof T, boolean>>((() => {
const obj: Record<keyof T, boolean> = {} as Record<keyof T, boolean>;
for (const key in initialState) {
obj[key] = false;
}
return obj;
})());
const modified = computed(() => Object.values(modifiedStates).some(v => v));
const modifiedCount = computed(() => Object.values(modifiedStates).filter(v => v).length);

View File

@@ -4,13 +4,14 @@
*/
import type { InjectionKey, Ref } from 'vue';
import type { PageMetadata } from '@/page.js';
import type { Router } from '@/router.js';
export const DI = {
routerCurrentDepth: Symbol() as InjectionKey<number>,
router: Symbol() as InjectionKey<Router>,
mock: Symbol() as InjectionKey<boolean>,
pageMetadata: Symbol() as InjectionKey<Ref<Record<string, any> | null>>,
pageMetadata: Symbol() as InjectionKey<Ref<PageMetadata | null>>,
viewId: Symbol() as InjectionKey<string>,
currentStickyTop: Symbol() as InjectionKey<Ref<number>>,
currentStickyBottom: Symbol() as InjectionKey<Ref<number>>,

View File

@@ -7,7 +7,7 @@ import type { Directive } from 'vue';
import { getBgColor } from '@/utility/get-bg-color.js';
import { globalEvents } from '@/events.js';
const handlerMap = new WeakMap<any, any>();
const handlerMap = new WeakMap<HTMLElement, () => void>();
export const adaptiveBorderDirective = {
mounted(src) {

View File

@@ -119,9 +119,9 @@ export const userPreviewDirective = {
// TODO: 新たにプロパティを作るのをやめMapを使う
// ただメモリ的には↓の方が省メモリかもしれないので検討中
const self = (el as any)._userPreviewDirective_ = {} as any;
self.preview = new UserPreview(el, binding.value);
el._userPreviewDirective_ = {
preview: new UserPreview(el, binding.value),
};
},
unmounted(el, binding) {

View File

@@ -59,7 +59,7 @@ export class Pizzax<T extends StateDef> {
private pizzaxChannel: BroadcastChannel<PizzaxChannelMessage<T>>;
// 簡易的にキューイングして占有ロックとする
private currentIdbJob: Promise<any> = Promise.resolve();
private currentIdbJob: Promise<unknown> = Promise.resolve();
private addIdbSetJob<T>(job: () => Promise<T>) {
const promise = this.currentIdbJob.then(job, err => {
console.error('Pizzax failed to save data to idb!', err);

View File

@@ -257,7 +257,7 @@ const {
const user = ref(result.user);
const info = ref(result.info);
const ips = ref(result.ips);
const ap = ref<any>(null);
const ap = ref<Misskey.entities.ApGetResponse | null>(null);
const moderator = ref(info.value.isModerator);
const silenced = ref(info.value.isSilenced);
const suspended = ref(info.value.isSuspended);

View File

@@ -44,7 +44,7 @@ async function addRelay() {
if (canceled || inbox == null) return;
misskeyApi('admin/relays/add', {
inbox,
}).then((relay: any) => {
}).then(() => {
refresh();
}).catch((err: any) => {
os.alert({

View File

@@ -161,7 +161,11 @@ async function _fetch_() {
},
raw: res.data,
};
} catch (err: any) {
} catch (err) {
if (!(err instanceof Error)) {
throw err;
}
switch (err.message.toLowerCase()) {
case 'this theme is already installed':
errorKV.value = {

View File

@@ -36,7 +36,17 @@ misskeyApi('antennas/show', { antennaId: props.antennaId }).then((antennaRespons
antenna.value = antennaResponse;
});
const headerActions = computed(() => []);
const headerActions = computed(() => antenna.value ? [{
icon: 'ti ti-timeline',
text: i18n.ts.timeline,
handler: () => {
router.push('/timeline/antenna/:antennaId', {
params: {
antennaId: antenna.value!.id,
},
});
},
}] : []);
const headerTabs = computed(() => []);
definePage(() => ({

View File

@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton :link="true" to="/my/antennas/create" primary :class="$style.add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<div v-if="antennas.length > 0" class="_gaps">
<MkA v-for="antenna in antennas" :key="antenna.id" :class="$style.antenna" :to="`/my/antennas/${antenna.id}`">
<MkA v-for="antenna in antennas" :key="antenna.id" :class="$style.antenna" :to="`/timeline/antenna/${antenna.id}`">
<div class="name">{{ antenna.name }}</div>
</MkA>
</div>

View File

@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton primary rounded style="margin: 0 auto;" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton>
<div v-if="items.length > 0" class="_gaps">
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`">
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/timeline/list/${list.id}`">
<div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.tsx.nUsers({ n: `${list.userIds!.length}/${$i.policies['userEachUserListsLimit']}` }) }})</span></div>
<MkAvatars :userIds="list.userIds!" :limit="10"/>
</MkA>

View File

@@ -26,10 +26,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.members }}</template>
<template #caption>{{ i18n.tsx.nUsers({ n: `${list.userIds!.length}/${$i.policies['userEachUserListsLimit']}` }) }}</template>
<div class="_gaps_s">
<MkButton rounded primary style="margin: 0 auto;" @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
<div class="_gaps">
<MkButton rounded primary style="margin: 0 auto;" @click="addUser()"><i class="ti ti-plus"></i> {{ i18n.ts.addUser }}</MkButton>
<MkPagination :paginator="membershipsPaginator" withControl>
<MkPagination :paginator="membershipsPaginator">
<template #default="{ items }">
<div class="_gaps_s">
<div v-for="item in items" :key="item.id">
@@ -67,12 +67,13 @@ import MkInput from '@/components/MkInput.vue';
import { userListsCache } from '@/cache.js';
import { ensureSignin } from '@/i.js';
import MkPagination from '@/components/MkPagination.vue';
import { mainRouter } from '@/router.js';
import { prefer } from '@/preferences.js';
import { useRouter } from '@/router.js';
import { Paginator } from '@/utility/paginator.js';
const $i = ensureSignin();
const router = useRouter();
const props = defineProps<{
listId: string;
}>();
@@ -162,7 +163,7 @@ async function deleteList() {
listId: list.value.id,
});
userListsCache.delete();
mainRouter.push('/my/lists');
router.push('/my/lists');
}
async function updateSettings() {
@@ -181,7 +182,17 @@ async function updateSettings() {
watch(() => props.listId, fetchList, { immediate: true });
const headerActions = computed(() => []);
const headerActions = computed(() => list.value ? [{
icon: 'ti ti-timeline',
text: i18n.ts.timeline,
handler: () => {
router.push('/timeline/list/:listId', {
params: {
listId: list.value!.id,
},
});
},
}] : []);
const headerTabs = computed(() => []);

View File

@@ -60,6 +60,7 @@ import { Interpreter, Parser, utils } from '@syuilo/aiscript';
import type { Ref } from 'vue';
import type { AsUiComponent } from '@/aiscript/ui.js';
import type { AsUiRoot } from '@/aiscript/ui.js';
import type { Value } from '@syuilo/aiscript/interpreter/value.js';
import MkContainer from '@/components/MkContainer.vue';
import MkButton from '@/components/MkButton.vue';
import MkTextarea from '@/components/MkTextarea.vue';
@@ -141,7 +142,7 @@ async function run() {
switch (type) {
case 'end': logs.value.push({
id: Math.random(),
text: utils.valToString(params.val, true),
text: utils.valToString(params.val as Value, true),
print: false,
}); break;
default: break;

View File

@@ -603,6 +603,18 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif']">
<MkPreferenceContainer k="disableShowingAnimatedImages">
<MkSwitch :modelValue="!disableShowingAnimatedImages" @update:modelValue="v => disableShowingAnimatedImages = !v">
<template #label><SearchLabel>{{ i18n.ts._settings.enableAnimatedImages }}</SearchLabel></template>
<template #caption>
<SearchText>{{ i18n.ts.turnOffToImprovePerformance }}</SearchText>
<div>{{ i18n.ts.disableShowingAnimatedImages_caption }}</div>
</template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['blur']">
<MkPreferenceContainer k="useBlurEffect">
<MkSwitch v-model="useBlurEffect">

View File

@@ -7,8 +7,6 @@ import * as Misskey from 'misskey-js';
import { markRaw } from 'vue';
import { $i } from '@/i.js';
import { wsOrigin } from '@@/js/config.js';
// TODO: No WebsocketモードでStreamMockが使えそう
//import { StreamMock } from '@/utility/stream-mock.js';
// heart beat interval in ms
const HEART_BEAT_INTERVAL = 1000 * 60;

View File

@@ -8,16 +8,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<a v-if="isRoot" href="https://github.com/misskey-dev/misskey" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--MI_THEME-panel); color:var(--MI_THEME-fg); position: fixed; z-index: 10; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
<div v-if="!narrow && !isRoot" :class="$style.side">
<div :class="$style.banner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div>
<div :class="$style.dashboard">
<div :class="$style.sideBanner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div>
<div :class="$style.sideDashboard">
<MkVisitorDashboard/>
</div>
</div>
<div :class="$style.main">
<button v-if="!isRoot" :class="$style.homeButton" class="_button" @click="goHome">
<i class="ti ti-home"></i>
</button>
<div v-if="narrow && !isRoot" :class="$style.header">
<img :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.headerIcon"/>
<MkA to="/" :class="$style.headerTitle">{{ instanceName }}</MkA>
<MkButton primary rounded :class="$style.headerButton" @click="goHome">{{ i18n.ts.signup }}</MkButton>
</div>
<div :class="$style.content">
<RouterView/>
</div>
@@ -38,6 +40,7 @@ import { i18n } from '@/i18n.js';
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
import { mainRouter } from '@/router.js';
import { DI } from '@/di.js';
import MkButton from '@/components/MkButton.vue';
const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
@@ -93,16 +96,26 @@ onMounted(() => {
min-width: 0;
}
.homeButton {
position: fixed;
z-index: 1000;
bottom: 16px;
right: 16px;
width: 60px;
height: 60px;
.header {
padding: 16px;
display: flex;
align-items: center;
background: var(--MI_THEME-panel);
border-radius: 999px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.headerIcon {
width: 48px;
vertical-align: bottom;
border-radius: 8px;
}
.headerTitle {
margin: 0 16px;
font-weight: bold;
}
.headerButton {
margin-left: auto;
}
.side {
@@ -112,7 +125,7 @@ onMounted(() => {
background: var(--MI_THEME-accent);
}
.banner {
.sideBanner {
position: absolute;
top: 0;
left: 0;
@@ -124,7 +137,7 @@ onMounted(() => {
mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);
}
.dashboard {
.sideDashboard {
padding: 32px;
}

View File

@@ -124,7 +124,7 @@ export function uploadFile(file: File | Blob, options: {
const driveFile = JSON.parse(ev.target.response);
globalEvents.emit('driveFileCreated', driveFile);
resolve(driveFile);
}) as (ev: ProgressEvent<EventTarget>) => any;
}) as (ev: ProgressEvent<EventTarget>) => void;
if (options.onProgress) {
xhr.upload.onprogress = ev => {

View File

@@ -13,7 +13,7 @@ interface CommonParamDef {
type: string;
label?: string;
caption?: string;
default: any;
default: unknown;
}
interface NumberParamDef extends CommonParamDef {

View File

@@ -5,7 +5,7 @@
import { ref, shallowRef, triggerRef } from 'vue';
import * as Misskey from 'misskey-js';
import type { ComputedRef, Ref, ShallowRef } from 'vue';
import type { ComputedRef, Ref, ShallowRef, UnwrapRef } from 'vue';
import { misskeyApi } from '@/utility/misskey-api.js';
const MAX_ITEMS = 30;
@@ -19,7 +19,12 @@ export type MisskeyEntity = {
_shouldInsertAd_?: boolean;
};
type FilterByEpRes<E extends Record<string, any>> = {
type AbsEndpointType = {
req: unknown;
res: unknown;
};
type FilterByEpRes<E extends Record<string, AbsEndpointType>> = {
[K in keyof E]: E[K]['res'] extends Array<{ id: string }> ? K : never
}[keyof E];
export type PaginatorCompatibleEndpointPaths = FilterByEpRes<Misskey.Endpoints>;
@@ -27,6 +32,8 @@ export type PaginatorCompatibleEndpoints = {
[K in PaginatorCompatibleEndpointPaths]: Misskey.Endpoints[K];
};
export type ExtractorFunction<P extends IPaginator, T> = (item: UnwrapRef<P['items']>[number]) => T;
export interface IPaginator<T = unknown, _T = T & MisskeyEntity> {
/**
* 外部から直接操作しないでください

View File

@@ -1,81 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { EventEmitter } from 'eventemitter3';
import * as Misskey from 'misskey-js';
import type { Channels, StreamEvents, IStream, IChannelConnection } from 'misskey-js';
type AnyOf<T extends Record<any, any>> = T[keyof T];
type OmitFirst<T extends any[]> = T extends [any, ...infer R] ? R : never;
/**
* Websocket無効化時に使うStreamのモックなにもしない
*/
export class StreamMock extends EventEmitter<StreamEvents> implements IStream {
public readonly state = 'initializing';
constructor(...args: ConstructorParameters<typeof Misskey.Stream>) {
super();
// do nothing
}
public useChannel<C extends keyof Channels>(channel: C, params?: Channels[C]['params'], name?: string): ChannelConnectionMock<Channels[C]> {
return new ChannelConnectionMock(this, channel, name);
}
public removeSharedConnection(connection: any): void {
// do nothing
}
public removeSharedConnectionPool(pool: any): void {
// do nothing
}
public disconnectToChannel(): void {
// do nothing
}
public send(typeOrPayload: string): void;
public send(typeOrPayload: string, payload: any): void;
public send(typeOrPayload: Record<string, any> | any[]): void;
public send(typeOrPayload: string | Record<string, any> | any[], payload?: any): void {
// do nothing
}
public ping(): void {
// do nothing
}
public heartbeat(): void {
// do nothing
}
public close(): void {
// do nothing
}
}
class ChannelConnectionMock<Channel extends AnyOf<Channels> = any> extends EventEmitter<Channel['events']> implements IChannelConnection<Channel> {
public id = '';
public name?: string; // for debug
public inCount = 0; // for debug
public outCount = 0; // for debug
public channel: string;
constructor(stream: IStream, ...args: OmitFirst<ConstructorParameters<typeof Misskey.ChannelConnection<Channel>>>) {
super();
this.channel = args[0];
this.name = args[1];
}
public send<T extends keyof Channel['receives']>(type: T, body: Channel['receives'][T]): void {
// do nothing
}
public dispose(): void {
// do nothing
}
}

View File

@@ -222,7 +222,8 @@ export class WatermarkRenderer {
},
});
} else {
throw new Error(`Unrecognized layer type: ${(layer as any).type}`);
// @ts-expect-error Should be unreachable
throw new Error(`Unrecognized layer type: ${layer.type}`);
}
}

View File

@@ -24,6 +24,7 @@ import { Interpreter, Parser, utils } from '@syuilo/aiscript';
import { useWidgetPropsManager } from './widget.js';
import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js';
import type { FormWithDefault, GetFormResultType } from '@/utility/form.js';
import type { Value } from '@syuilo/aiscript/interpreter/value.js';
import * as os from '@/os.js';
import MkContainer from '@/components/MkContainer.vue';
import { aiScriptReadline, createAiScriptEnv } from '@/aiscript/api.js';
@@ -83,7 +84,7 @@ const run = async () => {
switch (type) {
case 'end': logs.value.push({
id: genId(),
text: utils.valToString(params.val, true),
text: utils.valToString(params.val as Value, true),
print: false,
}); break;
default: break;

View File

@@ -10,7 +10,7 @@
"declaration": false,
"sourceMap": false,
"target": "ES2022",
"module": "ES2022",
"module": "esnext",
"moduleResolution": "Bundler",
"removeComments": false,
"noLib": false,