From f269841a83002daf6743f8ed2c173da66a662618 Mon Sep 17 00:00:00 2001 From: FineArchs <133759614+FineArchs@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:21:45 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20AiScript=E3=81=A7=E3=83=AA=E3=83=A2?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=81=AE?= =?UTF-8?q?API=E3=82=92=E5=8F=A9=E3=81=8F=E9=96=A2=E6=95=B0=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20(#11887)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add Mk:apiExternal * fix * lint * Update CHANGELOG.md * Update api.ts * add apiExternal() * add apiExternal() * allow / ambiguity * use os.apiExternal() * add checks * fix url --- CHANGELOG.md | 1 + packages/frontend/src/os.ts | 4 +- packages/frontend/src/scripts/aiscript/api.ts | 10 ++++ packages/frontend/src/scripts/api.ts | 46 ++++++++++++++++++- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b51ffb9..ac4b6f05a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ - Feat: Playで直接投稿フォームを埋め込めるように(`Ui:C:postForm`) - Feat: クライアントを起動している間、デバイスの画面が自動でオフになるのを防ぐオプションを追加 - Feat: 新しい実績を追加 +- Feat: リモートサーバーのAPIを叩く用の関数を追加(`Mk:apiExternal`) - Enhance: ノート詳細ページでリノート一覧、リアクション一覧タブを追加 - ノートのメニューからは当該項目は消えました - Enhance: センシティブなメディアを目立たせる設定を追加 diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index 8aed5797e..8093335a2 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -5,8 +5,8 @@ // TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する -import { pendingApiRequestsCount, api, apiGet } from '@/scripts/api.js'; -export { pendingApiRequestsCount, api, apiGet }; +import { pendingApiRequestsCount, api, apiExternal, apiGet } from '@/scripts/api.js'; +export { pendingApiRequestsCount, api, apiExternal, apiGet }; import { Component, markRaw, Ref, ref, defineAsyncComponent } from 'vue'; import { EventEmitter } from 'eventemitter3'; import insertTextAtCursor from 'insert-text-at-cursor'; diff --git a/packages/frontend/src/scripts/aiscript/api.ts b/packages/frontend/src/scripts/aiscript/api.ts index 9f60e52ce..f049a51b9 100644 --- a/packages/frontend/src/scripts/aiscript/api.ts +++ b/packages/frontend/src/scripts/aiscript/api.ts @@ -48,6 +48,16 @@ export function createAiScriptEnv(opts) { return values.ERROR('request_failed', utils.jsToVal(err)); }); }), + 'Mk:apiExternal': values.FN_NATIVE(async ([host, ep, param, token]) => { + utils.assertString(host); + utils.assertString(ep); + if (token) utils.assertString(token); + return os.apiExternal(host.value, ep.value, utils.valToJs(param), token?.value).then(res => { + return utils.jsToVal(res); + }, err => { + return values.ERROR('request_failed', utils.jsToVal(err)); + }); + }), 'Mk:save': values.FN_NATIVE(([key, value]) => { utils.assertString(key); miLocalStorage.setItem(`aiscript:${opts.storageKey}:${key.value}`, JSON.stringify(utils.valToJs(value))); diff --git a/packages/frontend/src/scripts/api.ts b/packages/frontend/src/scripts/api.ts index 9259c8801..080977e5e 100644 --- a/packages/frontend/src/scripts/api.ts +++ b/packages/frontend/src/scripts/api.ts @@ -11,6 +11,7 @@ export const pendingApiRequestsCount = ref(0); // Implements Misskey.api.ApiClient.request export function api(endpoint: E, data: P = {} as any, token?: string | null | undefined, signal?: AbortSignal): Promise { + if (endpoint.includes('://')) throw new Error('invalid endpoint'); pendingApiRequestsCount.value++; const onFinally = () => { @@ -23,7 +24,50 @@ export function api -1 ? endpoint : `${apiUrl}/${endpoint}`, { + window.fetch(`${apiUrl}/${endpoint}`, { + method: 'POST', + body: JSON.stringify(data), + credentials: 'omit', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json', + }, + signal, + }).then(async (res) => { + const body = res.status === 204 ? null : await res.json(); + + if (res.status === 200) { + resolve(body); + } else if (res.status === 204) { + resolve(); + } else { + reject(body.error); + } + }).catch(reject); + }); + + promise.then(onFinally, onFinally); + + return promise; +} + +export function apiExternal(hostUrl: string, endpoint: E, data: P = {} as any, token?: string | null | undefined, signal?: AbortSignal): Promise { + if (!/^https?:\/\//.test(hostUrl)) throw new Error('invalid host name'); + if (endpoint.includes('://')) throw new Error('invalid endpoint'); + pendingApiRequestsCount.value++; + + const onFinally = () => { + pendingApiRequestsCount.value--; + }; + + const promise = new Promise((resolve, reject) => { + // Append a credential + (data as any).i = token; + + const fullUrl = (hostUrl.slice(-1) === '/' ? hostUrl.slice(0, -1) : hostUrl) + + '/api/' + (endpoint.slice(0, 1) === '/' ? endpoint.slice(1) : endpoint); + // Send request + window.fetch(fullUrl, { method: 'POST', body: JSON.stringify(data), credentials: 'omit',