spec(api): 一部APIをGETに対応・認証情報をヘッダーに (MisskeyIO#837)
This commit is contained in:
parent
58513c1b81
commit
3362c464c5
@ -11,6 +11,8 @@ export const meta = {
|
||||
tags: ['meta'],
|
||||
|
||||
requireCredential: false,
|
||||
allowGet: true,
|
||||
cacheSec: 60,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
|
@ -12,6 +12,8 @@ import UsersChart from '@/core/chart/charts/users.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: false,
|
||||
allowGet: true,
|
||||
cacheSec: 60,
|
||||
|
||||
tags: ['meta'],
|
||||
|
||||
|
@ -32,6 +32,11 @@
|
||||
renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
|
||||
}
|
||||
|
||||
if (localStorage.getItem('id') === null) {
|
||||
localStorage.setItem('id', crypto.randomUUID().replaceAll('-', ''));
|
||||
}
|
||||
let id = localStorage.getItem('id');
|
||||
|
||||
//#region Detect language & fetch translations
|
||||
if (!Object.hasOwn(localStorage, 'locale')) {
|
||||
let lang = localStorage.getItem('lang');
|
||||
@ -40,12 +45,11 @@
|
||||
}
|
||||
|
||||
const metaRes = await window.fetch('/api/meta', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({}),
|
||||
method: 'GET',
|
||||
credentials: 'omit',
|
||||
cache: 'no-cache',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Client-Transaction-Id': `${id}-misskey-${crypto.randomUUID().replaceAll('-', '')}`
|
||||
},
|
||||
});
|
||||
if (metaRes.status !== 200) {
|
||||
|
@ -62,10 +62,6 @@ export async function common(createVue: () => App<Element>) {
|
||||
});
|
||||
}
|
||||
|
||||
if (miLocalStorage.getItem('id') === null) {
|
||||
miLocalStorage.setItem('id', crypto.randomUUID());
|
||||
}
|
||||
|
||||
let isClientUpdated = false;
|
||||
|
||||
//#region クライアントが更新されたかチェック
|
||||
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
import { onMounted, shallowRef, ref, nextTick } from 'vue';
|
||||
import { Chart } from 'chart.js';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||
@ -52,7 +52,7 @@ async function renderChart() {
|
||||
}));
|
||||
};
|
||||
|
||||
const raw = await misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
|
||||
const raw = await misskeyApiGet('charts/active-users', { limit: chartLimit, span: 'day' });
|
||||
|
||||
fetching.value = false;
|
||||
|
||||
|
@ -79,7 +79,7 @@ import MkTimeline from '@/components/MkTimeline.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import { instanceName } from '@/config.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
@ -89,7 +89,7 @@ import { openInstanceMenu } from '@/ui/_common_/common';
|
||||
|
||||
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
||||
|
||||
misskeyApi('stats', {}).then((res) => {
|
||||
misskeyApiGet('stats').then((res) => {
|
||||
stats.value = res;
|
||||
});
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
import { computed, reactive } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const.js';
|
||||
|
||||
@ -47,7 +47,7 @@ export async function fetchInstance(force = false): Promise<Misskey.entities.Met
|
||||
}
|
||||
}
|
||||
|
||||
const meta = await misskeyApi('meta', {
|
||||
const meta = await misskeyApiGet('meta', {
|
||||
detail: true,
|
||||
});
|
||||
|
||||
|
@ -164,7 +164,7 @@ import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkInstanceStats from '@/components/MkInstanceStats.vue';
|
||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import number from '@/filters/number.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
@ -187,8 +187,7 @@ watch(tab, () => {
|
||||
}
|
||||
});
|
||||
|
||||
const initStats = () => misskeyApi('stats', {
|
||||
}).then((res) => {
|
||||
const initStats = () => misskeyApiGet('stats').then((res) => {
|
||||
stats.value = res;
|
||||
});
|
||||
|
||||
|
@ -63,7 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import MkNumberDiff from '@/components/MkNumberDiff.vue';
|
||||
import MkNumber from '@/components/MkNumber.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
@ -78,7 +78,7 @@ const fetching = ref(true);
|
||||
|
||||
onMounted(async () => {
|
||||
const [_stats, _onlineUsersCount] = await Promise.all([
|
||||
misskeyApi('stats', {}),
|
||||
misskeyApiGet('stats'),
|
||||
misskeyApiGet('get-online-users-count').then(res => res.count),
|
||||
]);
|
||||
stats.value = _stats;
|
||||
|
@ -15,11 +15,17 @@ export const pendingApiRequestsCount = ref(0);
|
||||
let id: string | null = miLocalStorage.getItem('id');
|
||||
export function generateClientTransactionId(initiator: string) {
|
||||
if (id === null) {
|
||||
id = crypto.randomUUID();
|
||||
id = crypto.randomUUID().replaceAll('-', '');
|
||||
miLocalStorage.setItem('id', id);
|
||||
}
|
||||
|
||||
return `${id}-${initiator}-${crypto.randomUUID()}`;
|
||||
// ハイフンが含まれている場合は除去
|
||||
if (id.includes('-')) {
|
||||
id = id.replaceAll('-', '');
|
||||
miLocalStorage.setItem('id', id);
|
||||
}
|
||||
|
||||
return `${id}-${initiator}-${crypto.randomUUID().replaceAll('-', '')}`;
|
||||
}
|
||||
|
||||
function handleResponse<_ResT>(
|
||||
@ -58,24 +64,22 @@ export function misskeyApi<
|
||||
if (endpoint.includes('://')) throw new Error('invalid endpoint');
|
||||
pendingApiRequestsCount.value++;
|
||||
|
||||
const credential = token ? token : $i ? $i.token : undefined;
|
||||
|
||||
const onFinally = () => {
|
||||
pendingApiRequestsCount.value--;
|
||||
};
|
||||
|
||||
const promise = new Promise<_ResT>((resolve, reject) => {
|
||||
// Append a credential
|
||||
if ($i) (data as any).i = $i.token;
|
||||
if (token !== undefined) (data as any).i = token;
|
||||
|
||||
// Send request
|
||||
const initiateTime = Date.now();
|
||||
window.fetch(`${apiUrl}/${endpoint}`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
credentials: 'omit',
|
||||
cache: 'no-cache',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': credential ? `Bearer ${credential}` : 'anonymous',
|
||||
'X-Client-Transaction-Id': generateClientTransactionId(initiator),
|
||||
},
|
||||
signal,
|
||||
@ -121,8 +125,8 @@ export function misskeyApiGet<
|
||||
window.fetch(`${apiUrl}/${endpoint}?${query}`, {
|
||||
method: 'GET',
|
||||
credentials: 'omit',
|
||||
cache: 'default',
|
||||
headers: {
|
||||
'Authorization': 'anonymous',
|
||||
'X-Client-Transaction-Id': generateClientTransactionId(initiator),
|
||||
},
|
||||
}).then(res => {
|
||||
|
@ -2535,6 +2535,13 @@ export type paths = {
|
||||
post: operations['invite___limit'];
|
||||
};
|
||||
'/meta': {
|
||||
/**
|
||||
* meta
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
get: operations['meta_get'];
|
||||
/**
|
||||
* meta
|
||||
* @description No description provided.
|
||||
@ -3229,6 +3236,13 @@ export type paths = {
|
||||
post: operations['server-info'];
|
||||
};
|
||||
'/stats': {
|
||||
/**
|
||||
* stats
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
get: operations['stats_get'];
|
||||
/**
|
||||
* stats
|
||||
* @description No description provided.
|
||||
@ -22271,6 +22285,60 @@ export type operations = {
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* meta
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
meta_get: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
/** @default true */
|
||||
detail?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
content: {
|
||||
'application/json': components['schemas']['MetaLite'] | components['schemas']['MetaDetailed'];
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* meta
|
||||
* @description No description provided.
|
||||
@ -26776,6 +26844,60 @@ export type operations = {
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* stats
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *No*
|
||||
*/
|
||||
stats_get: {
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
content: {
|
||||
'application/json': {
|
||||
notesCount: number;
|
||||
originalNotesCount: number;
|
||||
usersCount: number;
|
||||
originalUsersCount: number;
|
||||
instances: number;
|
||||
driveUsageLocal: number;
|
||||
driveUsageRemote: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
400: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Authentication error */
|
||||
401: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Forbidden error */
|
||||
403: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description I'm Ai */
|
||||
418: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
/** @description Internal server error */
|
||||
500: {
|
||||
content: {
|
||||
'application/json': components['schemas']['Error'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* stats
|
||||
* @description No description provided.
|
||||
|
Loading…
Reference in New Issue
Block a user