From 7fe303505961c764561b93e3c34b9e8e83d70698 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:58:59 +0900 Subject: [PATCH] fix(backend): use `prefixItems` in `admin/queue/*-delayed` endpoint schema (#14468) * fix(backend): represent tuples with `prefixItems` * refactor(frontend): fix type errors * fix(backend): add `prefixItems` in `SchemaType` * fix(backend): add `unevaluatedItems: false` to disallow extra items * refactor(frontend): consolidate `'deliver' | 'queue'` type def into `queue.vue` * fix(backend): add `unevaluatedItems` in `SchemaType` --- packages/backend/src/misc/json-schema.ts | 9 ++++++ .../endpoints/admin/queue/deliver-delayed.ts | 19 ++++++------ .../endpoints/admin/queue/inbox-delayed.ts | 19 ++++++------ .../src/pages/admin/overview.queue.vue | 20 +++++++------ .../frontend/src/pages/admin/queue.chart.vue | 30 +++++++++---------- packages/frontend/src/pages/admin/queue.vue | 6 ++-- packages/misskey-js/src/autogen/types.ts | 4 +-- 7 files changed, 59 insertions(+), 48 deletions(-) diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index a721b8663c..040e36228c 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -144,7 +144,9 @@ export interface Schema extends OfSchema { readonly type?: TypeStringef; readonly nullable?: boolean; readonly optional?: boolean; + readonly prefixItems?: ReadonlyArray<Schema>; readonly items?: Schema; + readonly unevaluatedItems?: Schema | boolean; readonly properties?: Obj; readonly required?: ReadonlyArray<Extract<keyof NonNullable<this['properties']>, string>>; readonly description?: string; @@ -198,6 +200,7 @@ type UnionSchemaType<a extends readonly any[], X extends Schema = a[number]> = X //type UnionObjectSchemaType<a extends readonly any[], X extends Schema = a[number]> = X extends any ? ObjectSchemaType<X> : never; type UnionObjType<s extends Obj, a extends readonly any[], X extends ReadonlyArray<keyof s> = a[number]> = X extends any ? ObjType<s, X> : never; type ArrayUnion<T> = T extends any ? Array<T> : never; +type ArrayToTuple<X extends ReadonlyArray<Schema>> = { [K in keyof X]: SchemaType<X[K]> }; type ObjectSchemaTypeDef<p extends Schema> = p['ref'] extends keyof typeof refs ? Packed<p['ref']> : @@ -232,6 +235,12 @@ export type SchemaTypeDef<p extends Schema> = p['items']['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] : never ) : + p['prefixItems'] extends ReadonlyArray<Schema> ? ( + p['items'] extends NonNullable<Schema> ? [...ArrayToTuple<p['prefixItems']>, ...SchemaType<p['items']>[]] : + p['items'] extends false ? ArrayToTuple<p['prefixItems']> : + p['unevaluatedItems'] extends false ? ArrayToTuple<p['prefixItems']> : + [...ArrayToTuple<p['prefixItems']>, ...unknown[]] + ) : p['items'] extends NonNullable<Schema> ? SchemaType<p['items']>[] : any[] ) : diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts index 7a3410ffa7..f3e440b4cb 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts @@ -21,16 +21,15 @@ export const meta = { items: { type: 'array', optional: false, nullable: false, - items: { - anyOf: [ - { - type: 'string', - }, - { - type: 'number', - }, - ], - }, + prefixItems: [ + { + type: 'string', + }, + { + type: 'number', + }, + ], + unevaluatedItems: false, }, example: [[ 'example.com', diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index 305ae1af1d..e7589cba81 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -21,16 +21,15 @@ export const meta = { items: { type: 'array', optional: false, nullable: false, - items: { - anyOf: [ - { - type: 'string', - }, - { - type: 'number', - }, - ], - }, + prefixItems: [ + { + type: 'string', + }, + { + type: 'number', + }, + ], + unevaluatedItems: false, }, example: [[ 'example.com', diff --git a/packages/frontend/src/pages/admin/overview.queue.vue b/packages/frontend/src/pages/admin/overview.queue.vue index c7478f252a..fb190f5325 100644 --- a/packages/frontend/src/pages/admin/overview.queue.vue +++ b/packages/frontend/src/pages/admin/overview.queue.vue @@ -36,7 +36,9 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue'; +import * as Misskey from 'misskey-js'; import XChart from './overview.queue.chart.vue'; +import type { ApQueueDomain } from '@/pages/admin/queue.vue'; import number from '@/filters/number.js'; import { useStream } from '@/stream.js'; @@ -52,10 +54,10 @@ const chartDelayed = shallowRef<InstanceType<typeof XChart>>(); const chartWaiting = shallowRef<InstanceType<typeof XChart>>(); const props = defineProps<{ - domain: string; + domain: ApQueueDomain; }>(); -const onStats = (stats) => { +function onStats(stats: Misskey.entities.QueueStats) { activeSincePrevTick.value = stats[props.domain].activeSincePrevTick; active.value = stats[props.domain].active; delayed.value = stats[props.domain].delayed; @@ -65,13 +67,13 @@ const onStats = (stats) => { chartActive.value.pushData(stats[props.domain].active); chartDelayed.value.pushData(stats[props.domain].delayed); chartWaiting.value.pushData(stats[props.domain].waiting); -}; +} -const onStatsLog = (statsLog) => { - const dataProcess = []; - const dataActive = []; - const dataDelayed = []; - const dataWaiting = []; +function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) { + const dataProcess: Misskey.entities.QueueStats[ApQueueDomain]['activeSincePrevTick'][] = []; + const dataActive: Misskey.entities.QueueStats[ApQueueDomain]['active'][] = []; + const dataDelayed: Misskey.entities.QueueStats[ApQueueDomain]['delayed'][] = []; + const dataWaiting: Misskey.entities.QueueStats[ApQueueDomain]['waiting'][] = []; for (const stats of [...statsLog].reverse()) { dataProcess.push(stats[props.domain].activeSincePrevTick); @@ -84,7 +86,7 @@ const onStatsLog = (statsLog) => { chartActive.value.setData(dataActive); chartDelayed.value.setData(dataDelayed); chartWaiting.value.setData(dataWaiting); -}; +} onMounted(() => { connection.on('stats', onStats); diff --git a/packages/frontend/src/pages/admin/queue.chart.vue b/packages/frontend/src/pages/admin/queue.chart.vue index 8d3fe35320..960a263a86 100644 --- a/packages/frontend/src/pages/admin/queue.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.vue @@ -49,7 +49,9 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { markRaw, onMounted, onUnmounted, ref, shallowRef } from 'vue'; +import * as Misskey from 'misskey-js'; import XChart from './queue.chart.chart.vue'; +import type { ApQueueDomain } from '@/pages/admin/queue.vue'; import number from '@/filters/number.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { useStream } from '@/stream.js'; @@ -62,17 +64,17 @@ const activeSincePrevTick = ref(0); const active = ref(0); const delayed = ref(0); const waiting = ref(0); -const jobs = ref<(string | number)[][]>([]); +const jobs = ref<Misskey.Endpoints[`admin/queue/${ApQueueDomain}-delayed`]['res']>([]); const chartProcess = shallowRef<InstanceType<typeof XChart>>(); const chartActive = shallowRef<InstanceType<typeof XChart>>(); const chartDelayed = shallowRef<InstanceType<typeof XChart>>(); const chartWaiting = shallowRef<InstanceType<typeof XChart>>(); const props = defineProps<{ - domain: string; + domain: ApQueueDomain; }>(); -const onStats = (stats) => { +function onStats(stats: Misskey.entities.QueueStats) { activeSincePrevTick.value = stats[props.domain].activeSincePrevTick; active.value = stats[props.domain].active; delayed.value = stats[props.domain].delayed; @@ -82,13 +84,13 @@ const onStats = (stats) => { chartActive.value.pushData(stats[props.domain].active); chartDelayed.value.pushData(stats[props.domain].delayed); chartWaiting.value.pushData(stats[props.domain].waiting); -}; +} -const onStatsLog = (statsLog) => { - const dataProcess = []; - const dataActive = []; - const dataDelayed = []; - const dataWaiting = []; +function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) { + const dataProcess: Misskey.entities.QueueStats[ApQueueDomain]['activeSincePrevTick'][] = []; + const dataActive: Misskey.entities.QueueStats[ApQueueDomain]['active'][] = []; + const dataDelayed: Misskey.entities.QueueStats[ApQueueDomain]['delayed'][] = []; + const dataWaiting: Misskey.entities.QueueStats[ApQueueDomain]['waiting'][] = []; for (const stats of [...statsLog].reverse()) { dataProcess.push(stats[props.domain].activeSincePrevTick); @@ -101,14 +103,12 @@ const onStatsLog = (statsLog) => { chartActive.value.setData(dataActive); chartDelayed.value.setData(dataDelayed); chartWaiting.value.setData(dataWaiting); -}; +} onMounted(() => { - if (props.domain === 'inbox' || props.domain === 'deliver') { - misskeyApi(`admin/queue/${props.domain}-delayed`).then(result => { - jobs.value = result; - }); - } + misskeyApi(`admin/queue/${props.domain}-delayed`).then(result => { + jobs.value = result; + }); connection.on('stats', onStats); connection.on('statsLog', onStatsLog); diff --git a/packages/frontend/src/pages/admin/queue.vue b/packages/frontend/src/pages/admin/queue.vue index 8d77d927d7..284db894b8 100644 --- a/packages/frontend/src/pages/admin/queue.vue +++ b/packages/frontend/src/pages/admin/queue.vue @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref, computed } from 'vue'; +import { ref, computed, type Ref } from 'vue'; import XQueue from './queue.chart.vue'; import XHeader from './_header_.vue'; import * as os from '@/os.js'; @@ -25,7 +25,9 @@ import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkButton from '@/components/MkButton.vue'; -const tab = ref('deliver'); +export type ApQueueDomain = 'deliver' | 'inbox'; + +const tab: Ref<ApQueueDomain> = ref('deliver'); function clear() { os.confirm({ diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 37f1bf2d38..b99a5373bb 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -8218,7 +8218,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': ((string | number)[])[]; + 'application/json': [string, number][]; }; }; /** @description Client error */ @@ -8264,7 +8264,7 @@ export type operations = { /** @description OK (with results) */ 200: { content: { - 'application/json': ((string | number)[])[]; + 'application/json': [string, number][]; }; }; /** @description Client error */ -- GitLab