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