Merge branch 'misskey-develop' into merge/2025-03-24

# Conflicts:
#	.github/workflows/api-misskey-js.yml
#	.github/workflows/changelog-check.yml
#	.github/workflows/check-misskey-js-autogen.yml
#	.github/workflows/get-api-diff.yml
#	.github/workflows/lint.yml
#	.github/workflows/locale.yml
#	.github/workflows/on-release-created.yml
#	.github/workflows/storybook.yml
#	.github/workflows/test-backend.yml
#	.github/workflows/test-federation.yml
#	.github/workflows/test-frontend.yml
#	.github/workflows/test-misskey-js.yml
#	.github/workflows/test-production.yml
#	.github/workflows/validate-api-json.yml
#	locales/index.d.ts
#	package.json
#	packages/misskey-js/generator/package.json
#	packages/misskey-js/package.json
#	pnpm-lock.yaml
#	scripts/changelog-checker/package-lock.json
#	scripts/changelog-checker/package.json
This commit is contained in:
Hazelnoot 2025-04-01 09:58:59 -04:00
commit 7ff15816d1
35 changed files with 716 additions and 379 deletions

View file

@ -142,11 +142,6 @@
document.documentElement.classList.add('useSystemFont');
}
const wallpaper = localStorage.getItem('wallpaper');
if (wallpaper) {
document.documentElement.style.backgroundImage = `url(${wallpaper})`;
}
const customCss = localStorage.getItem('customCss');
if (customCss && customCss.length > 0) {
const style = document.createElement('style');

View file

@ -34,7 +34,7 @@
"typescript": "5.8.2",
"uuid": "11.1.0",
"json5": "2.2.3",
"vite": "6.2.3",
"vite": "6.2.4",
"vue": "3.5.13"
},
"devDependencies": {

View file

@ -35,7 +35,6 @@
header: ':alpha<0.7<@panel',
navBg: '@panel',
navFg: '@fg',
navHoverFg: ':lighten<17<@fg',
navActive: '@accent',
navIndicator: '@indicator',
link: '#44a4c1',
@ -65,7 +64,6 @@
inputBorder: 'rgba(255, 255, 255, 0.1)',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
driveFolderBg: ':alpha<0.3<@accent',
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
badge: '#31b1ce',
messageBg: '@bg',
success: '#86b300',

View file

@ -35,7 +35,6 @@
header: ':alpha<0.7<@panel',
navBg: '@panel',
navFg: '@fg',
navHoverFg: ':darken<17<@fg',
navActive: '@accent',
navIndicator: '@indicator',
link: '#44a4c1',
@ -65,7 +64,6 @@
inputBorder: 'rgba(0, 0, 0, 0.1)',
inputBorderHover: 'rgba(0, 0, 0, 0.2)',
driveFolderBg: ':alpha<0.3<@accent',
wallpaperOverlay: 'rgba(255, 255, 255, 0.5)',
badge: '#31b1ce',
messageBg: '@bg',
success: '#86b300',

View file

@ -31,7 +31,6 @@
navActive: '@accent',
infoWarnBg: '#42321c',
infoWarnFg: '#ffbd3e',
navHoverFg: ':lighten<17<@fg',
dateLabelFg: '@fg',
inputBorder: 'rgba(255, 255, 255, 0.1)',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
@ -47,7 +46,6 @@
fgOnWhite: '@accent',
panelHighlight: ':lighten<3<@panel',
scrollbarHandle: 'rgba(255, 255, 255, 0.2)',
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
},

View file

@ -42,7 +42,6 @@
fgOnWhite: '@accent',
infoWarnBg: '#42321c',
infoWarnFg: '#ffbd3e',
navHoverFg: ':lighten<17<@fg',
codeBoolean: '#c59eff',
dateLabelFg: '@fg',
inputBorder: 'rgba(255, 255, 255, 0.1)',
@ -59,7 +58,6 @@
panelHighlight: ':lighten<3<@panel',
scrollbarHandle: 'rgba(255, 255, 255, 0.2)',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',

View file

@ -43,7 +43,6 @@
fgOnWhite: '@accent',
infoWarnBg: '#42321c',
infoWarnFg: '#ffbd3e',
navHoverFg: ':lighten<17<@fg',
codeBoolean: '#c59eff',
dateLabelFg: '@fg',
inputBorder: 'rgba(255, 255, 255, 0.1)',
@ -61,7 +60,6 @@
panelHighlight: ':lighten<3<@panel',
scrollbarHandle: '#74747433',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',

View file

@ -34,7 +34,6 @@
navActive: '@accent',
infoWarnBg: '#fff0db',
infoWarnFg: '#8f6e31',
navHoverFg: ':darken<17<@fg',
dateLabelFg: '@fg',
inputBorder: 'rgba(0, 0, 0, 0.1)',
inputBorderHover: 'rgba(0, 0, 0, 0.2)',
@ -49,7 +48,6 @@
htmlThemeColor: '@bg',
panelHighlight: ':darken<3<@panel',
scrollbarHandle: 'rgba(0, 0, 0, 0.2)',
wallpaperOverlay: 'rgba(255, 255, 255, 0.5)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: '@divider',
scrollbarHandleHover: 'rgba(0, 0, 0, 0.4)',

View file

@ -75,7 +75,7 @@
"typescript": "5.8.2",
"uuid": "11.1.0",
"v-code-diff": "1.13.1",
"vite": "6.2.3",
"vite": "6.2.4",
"vue": "3.5.13",
"vuedraggable": "next",
"wanakana": "5.3.1"

View file

@ -12,11 +12,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<path transform="scale(.26458)" d="m439.77 247.19c-43.673 0-78.832 35.157-78.832 78.83v249.98h407.06v-328.81z" :fill="themeVariables.panel"/>
</g>
<circle cx="32" cy="83" r="21" :fill="themeVariables.accentedBg"/>
<circle cx="136" cy="106" r="23" :fill="themeVariables.fg" fill-opacity="0.5"/>
<g :fill="themeVariables.fg" fill-rule="evenodd">
<rect x="171" y="88" width="48" height="6" ry="3"/>
<rect x="171" y="108" width="48" height="6" ry="3"/>
<rect x="171" y="128" width="48" height="6" ry="3"/>
<g>
<rect x="120" y="88" width="40" height="6" ry="3" :fill="themeVariables.fg"/>
<rect x="170" y="88" width="20" height="6" ry="3" :fill="themeVariables.mention"/>
<rect x="120" y="108" width="20" height="6" ry="3" :fill="themeVariables.hashtag"/>
<rect x="150" y="108" width="40" height="6" ry="3" :fill="themeVariables.fg"/>
<rect x="120" y="128" width="40" height="6" ry="3" :fill="themeVariables.fg"/>
<rect x="170" y="128" width="20" height="6" ry="3" :fill="themeVariables.link"/>
</g>
<path d="m65.498 40.892h137.7" :stroke="themeVariables.divider" stroke-width="0.75"/>
<g transform="matrix(.60823 0 0 .60823 25.45 75.755)" fill="none" :stroke="themeVariables.accent" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
@ -53,14 +55,23 @@ const themeVariables = ref<{
bg: string;
panel: string;
fg: string;
mention: string;
hashtag: string;
link: string;
divider: string;
accent: string;
accentedBg: string;
navBg: string;
success: string;
warn: string;
error: string;
}>({
bg: 'var(--MI_THEME-bg)',
panel: 'var(--MI_THEME-panel)',
fg: 'var(--MI_THEME-fg)',
mention: 'var(--MI_THEME-mention)',
hashtag: 'var(--MI_THEME-hashtag)',
link: 'var(--MI_THEME-link)',
divider: 'var(--MI_THEME-divider)',
accent: 'var(--MI_THEME-accent)',
accentedBg: 'var(--MI_THEME-accentedBg)',
@ -86,6 +97,9 @@ watch(() => props.theme, (theme) => {
bg: compiled.bg ?? 'var(--MI_THEME-bg)',
panel: compiled.panel ?? 'var(--MI_THEME-panel)',
fg: compiled.fg ?? 'var(--MI_THEME-fg)',
mention: compiled.mention ?? 'var(--MI_THEME-mention)',
hashtag: compiled.hashtag ?? 'var(--MI_THEME-hashtag)',
link: compiled.link ?? 'var(--MI_THEME-link)',
divider: compiled.divider ?? 'var(--MI_THEME-divider)',
accent: compiled.accent ?? 'var(--MI_THEME-accent)',
accentedBg: compiled.accentedBg ?? 'var(--MI_THEME-accentedBg)',

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<div>
<MkAnimBg style="position: absolute;"/>
<div class="_pageScrollable" style="position: absolute; top: 0; width: 100%; height: 100%;">
<div class="_pageScrollable" :class="$style.body">
<slot></slot>
</div>
</div>
@ -17,5 +17,13 @@ import MkAnimBg from '@/components/MkAnimBg.vue';
</script>
<style lang="scss" module>
.body {
position: absolute;
top: 0;
width: 100%;
height: 100%;
// _pageScrollable
background: transparent !important;
}
</style>

View file

@ -17,7 +17,6 @@ export type Keys = (
'lang' |
'drafts' |
'hashtags' |
'wallpaper' |
'colorScheme' |
'useSystemFont' |
'fontSize' |

View file

@ -12,6 +12,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch>
</SearchMarker>
<hr>
<SearchMarker :keywords="['ui', 'root', 'page']">
<MkPreferenceContainer k="deck.useSimpleUiForNonRootPages">
<MkSwitch v-model="useSimpleUiForNonRootPages">
@ -74,19 +76,29 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkRange>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['wallpaper']">
<MkPreferenceContainer k="deck.wallpaper">
<MkButton v-if="wallpaper == null" @click="setWallpaper"><SearchLabel>{{ i18n.ts.setWallpaper }}</SearchLabel></MkButton>
<MkButton v-else @click="wallpaper = null">{{ i18n.ts.removeWallpaper }}</MkButton>
</MkPreferenceContainer>
</SearchMarker>
</div>
</SearchMarker>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { computed, ref, watch } from 'vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkRange from '@/components/MkRange.vue';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import { prefer } from '@/preferences.js';
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
import { reloadAsk } from '@/utility/reload-ask.js';
import { selectFile } from '@/utility/select-file.js';
const navWindow = prefer.model('deck.navWindow');
const useSimpleUiForNonRootPages = prefer.model('deck.useSimpleUiForNonRootPages');
@ -95,6 +107,17 @@ const columnAlign = prefer.model('deck.columnAlign');
const columnGap = prefer.model('deck.columnGap');
const menuPosition = prefer.model('deck.menuPosition');
const navbarPosition = prefer.model('deck.navbarPosition');
const wallpaper = prefer.model('deck.wallpaper');
watch(wallpaper, async () => {
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
});
function setWallpaper(ev: MouseEvent) {
selectFile(ev.currentTarget ?? ev.target, null).then(file => {
wallpaper.value = file.url;
});
}
const profilesSyncEnabled = ref(prefer.isSyncEnabled('deck.profiles'));

View file

@ -189,17 +189,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormLink to="/theme-editor"><template #icon><i class="ti ti-paint"></i></template>{{ i18n.ts._theme.make }}</FormLink>
</div>
</FormSection>
<SearchMarker :keywords="['wallpaper']">
<MkButton v-if="wallpaper == null" @click="setWallpaper"><SearchLabel>{{ i18n.ts.setWallpaper }}</SearchLabel></MkButton>
<MkButton v-else @click="wallpaper = null">{{ i18n.ts.removeWallpaper }}</MkButton>
</SearchMarker>
</div>
</SearchMarker>
</template>
<script lang="ts" setup>
import { computed, onActivated, ref, watch } from 'vue';
import { computed, ref, watch } from 'vue';
import JSON5 from 'json5';
import defaultLightTheme from '@@/themes/l-light.json5';
import defaultDarkTheme from '@@/themes/d-green-lime.json5';
@ -207,7 +202,6 @@ import type { Theme } from '@/theme.js';
import MkSwitch from '@/components/MkSwitch.vue';
import FormSection from '@/components/form/section.vue';
import FormLink from '@/components/form/link.vue';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkThemePreview from '@/components/MkThemePreview.vue';
import { getBuiltinThemesRef, getThemesRef } from '@/theme.js';
@ -262,7 +256,6 @@ const lightThemeId = computed({
const darkMode = computed(store.makeGetterSetter('darkMode'));
const syncDeviceDarkMode = prefer.model('syncDeviceDarkMode');
const wallpaper = ref(miLocalStorage.getItem('wallpaper'));
const themesCount = installedThemes.value.length;
watch(syncDeviceDarkMode, () => {
@ -271,21 +264,6 @@ watch(syncDeviceDarkMode, () => {
}
});
watch(wallpaper, async () => {
if (wallpaper.value == null) {
miLocalStorage.removeItem('wallpaper');
} else {
miLocalStorage.setItem('wallpaper', wallpaper.value);
}
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
});
function setWallpaper(event) {
selectFile(event.currentTarget ?? event.target, null).then(file => {
wallpaper.value = file.url;
});
}
const headerActions = computed(() => []);
const headerTabs = computed(() => []);

View file

@ -431,6 +431,9 @@ export const PREF_DEF = {
'deck.navbarPosition': {
default: 'left' as 'left' | 'top' | 'bottom',
},
'deck.wallpaper': {
default: null as string | null,
},
'chat.showSenderName': {
default: false,

View file

@ -228,7 +228,7 @@ function more() {
&:hover {
text-decoration: none;
color: var(--MI_THEME-navHoverFg);
color: light-dark(hsl(from var(--MI_THEME-navFg) h s calc(l - 17)), hsl(from var(--MI_THEME-navFg) h s calc(l + 17)));
}
&.active {

View file

@ -149,7 +149,7 @@ onMounted(() => {
&:hover {
text-decoration: none;
color: var(--MI_THEME-navHoverFg);
color: light-dark(hsl(from var(--MI_THEME-navFg) h s calc(l - 17)), hsl(from var(--MI_THEME-navFg) h s calc(l + 17)));
}
&.active {

View file

@ -463,7 +463,7 @@ function menuEdit() {
&:hover {
text-decoration: none;
color: var(--MI_THEME-navHoverFg);
color: light-dark(hsl(from var(--MI_THEME-navFg) h s calc(l - 17)), hsl(from var(--MI_THEME-navFg) h s calc(l + 17)));
}
&.active {

View file

@ -117,13 +117,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { computed, defineAsyncComponent, ref, useTemplateRef, watch } from 'vue';
import { computed, defineAsyncComponent, ref, useTemplateRef } from 'vue';
import { v4 as uuid } from 'uuid';
import XCommon from './_common_/common.vue';
import XSidebar from '@/ui/_common_/navbar.vue';
import XNavbarH from '@/ui/_common_/navbar-h.vue';
import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os.js';
import { navbarItemDef } from '@/navbar.js';
import { $i } from '@/i.js';
@ -143,7 +142,6 @@ import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue';
import XFollowingColumn from '@/ui/deck/following-column.vue';
import { mainRouter } from '@/router.js';
import { columns, layout, columnTypes, switchProfileMenu, addColumn as addColumnToStore, deleteProfile as deleteProfile_ } from '@/deck.js';
import { miLocalStorage } from '@/local-storage.js';
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue'));
@ -178,7 +176,7 @@ window.addEventListener('resize', () => {
});
const snapScroll = deviceKind === 'smartphone' || deviceKind === 'tablet';
const withWallpaper = miLocalStorage.getItem('wallpaper') != null;
const withWallpaper = prefer.s['deck.wallpaper'] != null;
const drawerMenuShowing = ref(false);
const gap = prefer.r['deck.columnGap'];
@ -234,9 +232,6 @@ function onWheel(ev: WheelEvent) {
}
}
window.document.documentElement.style.overflowY = 'hidden';
window.document.documentElement.style.scrollBehavior = 'auto';
async function deleteProfile() {
if (prefer.s['deck.profile'] == null) return;
@ -251,6 +246,12 @@ async function deleteProfile() {
os.success();
}
window.document.documentElement.style.overflowY = 'hidden';
window.document.documentElement.style.scrollBehavior = 'auto';
if (prefer.s['deck.wallpaper'] != null) {
window.document.documentElement.style.backgroundImage = `url(${prefer.s['deck.wallpaper']})`;
}
</script>
<style lang="scss" module>

View file

@ -48,13 +48,13 @@ import type { MenuItem } from '@/types/menu.js';
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from '@/deck.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { miLocalStorage } from '@/local-storage.js';
import { prefer } from '@/preferences.js';
provide('shouldHeaderThin', true);
provide('shouldOmitHeaderTitle', true);
provide('forceSpacerMin', true);
const withWallpaper = miLocalStorage.getItem('wallpaper') != null;
const withWallpaper = prefer.s['deck.wallpaper'] != null;
const props = withDefaults(defineProps<{
column: Column;

View file

@ -37,11 +37,6 @@ export const searchIndexes: SearchIndexItem[] = [
label: i18n.ts.themeForDarkMode,
keywords: ['dark', 'theme'],
},
{
id: '8wcoRp76b',
label: i18n.ts.setWallpaper,
keywords: ['wallpaper'],
},
],
label: i18n.ts.theme,
keywords: ['theme'],
@ -861,40 +856,45 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['sync', 'profiles', 'devices'],
},
{
id: 'iEF0gqNAo',
id: 'wWH4pxMQN',
label: i18n.ts._deck.useSimpleUiForNonRootPages,
keywords: ['ui', 'root', 'page'],
},
{
id: 'BNdSeWxZn',
id: '3LR509BvD',
label: i18n.ts.defaultNavigationBehaviour,
keywords: ['default', 'navigation', 'behaviour', 'window'],
},
{
id: 'zT9pGm8DF',
id: 'ybU8RLXgm',
label: i18n.ts._deck.alwaysShowMainColumn,
keywords: ['always', 'show', 'main', 'column'],
},
{
id: '5dk2xv1vc',
id: 'xRasZyAVl',
label: i18n.ts._deck.columnAlign,
keywords: ['column', 'align'],
},
{
id: 'gtdEA4FTa',
id: '6qcyPd0oJ',
label: i18n.ts._deck.deckMenuPosition,
keywords: ['menu', 'position'],
},
{
id: 'DHVFdPBT6',
id: '4zk2Now4S',
label: i18n.ts._deck.navbarPosition,
keywords: ['navbar', 'position'],
},
{
id: '3UQ8rUssZ',
id: 'CGNtJ2I3n',
label: i18n.ts._deck.columnGap,
keywords: ['column', 'gap', 'margin'],
},
{
id: 'rxPDMo7bE',
label: i18n.ts.setWallpaper,
keywords: ['wallpaper'],
},
],
label: i18n.ts.deck,
keywords: ['deck', 'ui'],

View file

@ -9,9 +9,9 @@ import type { toHiragana as toHiraganaType } from 'wanakana';
let toHiragana: typeof toHiraganaType = (str?: string) => str ?? '';
let isWanakanaLoaded = false;
/**
/**
* lazy-loading
*
*
* 使
*/
export async function initIntlString(forceWanakana = false) {
@ -82,16 +82,17 @@ export function normalizeStringWithHiragana(str: string) {
/** aとbが同じかどうか */
export function compareStringEquals(a: string, b: string) {
return (
normalizeString(a) === normalizeString(b) ||
normalizeStringWithHiragana(a) === normalizeStringWithHiragana(b)
);
if (a === b) return true; // まったく同じ場合はtrue。なお、ーマライズ前後で文字数が変化することがあるため、文字数が違うからといってfalseにはできない
if (normalizeString(a) === normalizeString(b)) return true;
if (normalizeStringWithHiragana(a) === normalizeStringWithHiragana(b)) return true;
return false;
}
/** baseにqueryが含まれているかどうか */
export function compareStringIncludes(base: string, query: string) {
return (
normalizeString(base).includes(normalizeString(query)) ||
normalizeStringWithHiragana(base).includes(normalizeStringWithHiragana(query))
);
if (base === query) return true; // まったく同じ場合は含まれていると考えてよいのでtrue
if (base.includes(query)) return true;
if (normalizeString(base).includes(normalizeString(query))) return true;
if (normalizeStringWithHiragana(base).includes(normalizeStringWithHiragana(query))) return true;
return false;
}

View file

@ -8,9 +8,9 @@
},
"devDependencies": {
"@readme/openapi-parser": "2.7.0",
"@types/node": "22.13.9",
"@typescript-eslint/eslint-plugin": "8.27.0",
"@typescript-eslint/parser": "8.27.0",
"@types/node": "22.13.15",
"@typescript-eslint/eslint-plugin": "8.29.0",
"@typescript-eslint/parser": "8.29.0",
"eslint": "9.22.0",
"openapi-types": "12.1.3",
"openapi-typescript": "6.7.6",

View file

@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
"version": "2025.3.2-beta.20",
"version": "2025.4.0-beta.0",
"description": "Misskey SDK for JavaScript",
"license": "MIT",
"main": "./built/index.js",
@ -35,12 +35,12 @@
"directory": "packages/misskey-js"
},
"devDependencies": {
"@microsoft/api-extractor": "7.51.1",
"@microsoft/api-extractor": "7.52.2",
"@swc/jest": "0.2.37",
"@types/jest": "29.5.14",
"@types/node": "22.13.9",
"@typescript-eslint/eslint-plugin": "8.27.0",
"@typescript-eslint/parser": "8.27.0",
"@types/node": "22.13.15",
"@typescript-eslint/eslint-plugin": "8.29.0",
"@typescript-eslint/parser": "8.29.0",
"jest": "29.7.0",
"jest-fetch-mock": "3.0.3",
"jest-websocket-mock": "2.5.0",
@ -50,7 +50,7 @@
"execa": "8.0.1",
"tsd": "0.31.2",
"typescript": "5.8.2",
"esbuild": "0.25.0",
"esbuild": "0.25.2",
"glob": "11.0.1"
},
"files": [