mirror of
https://iceshrimp.dev/iceshrimp/iceshrimp
synced 2024-11-27 06:18:06 +09:00
[wip] standalone frontend stuff
This commit is contained in:
parent
7f58107311
commit
0b2e9511e2
49
.pnp.cjs
generated
49
.pnp.cjs
generated
@ -3239,6 +3239,30 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@rollup/plugin-replace", [\
|
||||
["npm:5.0.5", {\
|
||||
"packageLocation": "./.yarn/cache/@rollup-plugin-replace-npm-5.0.5-42f61be6e8-bcf106346f.zip/node_modules/@rollup/plugin-replace/",\
|
||||
"packageDependencies": [\
|
||||
["@rollup/plugin-replace", "npm:5.0.5"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:5.0.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@rollup-plugin-replace-virtual-bb6943b0cc/0/cache/@rollup-plugin-replace-npm-5.0.5-42f61be6e8-bcf106346f.zip/node_modules/@rollup/plugin-replace/",\
|
||||
"packageDependencies": [\
|
||||
["@rollup/plugin-replace", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:5.0.5"],\
|
||||
["@rollup/pluginutils", "virtual:bb6943b0cca2c422f7a7afd65919f64a13f4e8693f7906299796ebe01591897f1a7622cbd9bd4db684f8c6acc1f55e4a4d48e34b460bcd763b5121a2b479f420#npm:5.1.0"],\
|
||||
["@types/rollup", null],\
|
||||
["magic-string", "npm:0.30.5"],\
|
||||
["rollup", "npm:3.26.2"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/rollup",\
|
||||
"rollup"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@rollup/pluginutils", [\
|
||||
["npm:3.1.0", {\
|
||||
"packageLocation": "./.yarn/cache/@rollup-pluginutils-npm-3.1.0-b44b222e7d-3b69f02893.zip/node_modules/@rollup/pluginutils/",\
|
||||
@ -3256,6 +3280,29 @@ const RAW_RUNTIME_STATE =
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:5.1.0", {\
|
||||
"packageLocation": "./.yarn/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip/node_modules/@rollup/pluginutils/",\
|
||||
"packageDependencies": [\
|
||||
["@rollup/pluginutils", "npm:5.1.0"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:bb6943b0cca2c422f7a7afd65919f64a13f4e8693f7906299796ebe01591897f1a7622cbd9bd4db684f8c6acc1f55e4a4d48e34b460bcd763b5121a2b479f420#npm:5.1.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@rollup-pluginutils-virtual-2c209a0117/0/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip/node_modules/@rollup/pluginutils/",\
|
||||
"packageDependencies": [\
|
||||
["@rollup/pluginutils", "virtual:bb6943b0cca2c422f7a7afd65919f64a13f4e8693f7906299796ebe01591897f1a7622cbd9bd4db684f8c6acc1f55e4a4d48e34b460bcd763b5121a2b479f420#npm:5.1.0"],\
|
||||
["@types/estree", "npm:1.0.1"],\
|
||||
["@types/rollup", null],\
|
||||
["estree-walker", "npm:2.0.2"],\
|
||||
["picomatch", "npm:2.3.1"],\
|
||||
["rollup", "npm:3.26.2"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/rollup",\
|
||||
"rollup"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:cf1428485ac6d7495e234c120f3000a61db869813c88397f285b8f9691f2488035a4fa06e3d208d181d90d55925c550cd96d3b139f098a04a0ef06802bcb7775#npm:3.1.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@rollup-pluginutils-virtual-228ea72560/0/cache/@rollup-pluginutils-npm-3.1.0-b44b222e7d-3b69f02893.zip/node_modules/@rollup/pluginutils/",\
|
||||
"packageDependencies": [\
|
||||
@ -8537,6 +8584,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@phosphor-icons/web", "npm:2.0.3"],\
|
||||
["@rollup/plugin-alias", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:3.1.9"],\
|
||||
["@rollup/plugin-json", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:4.1.0"],\
|
||||
["@rollup/plugin-replace", "virtual:658502eb4296e93abedc18b6aa9b26978f434f08d98e21ebb0e725354b8bb54b62db9c4a1893e460c694ff7500ff5cbafa4457b0dfd26b5838868666c861e990#npm:5.0.5"],\
|
||||
["@rollup/pluginutils", "npm:4.2.1"],\
|
||||
["@syuilo/aiscript", "npm:0.11.1"],\
|
||||
["@types/escape-regexp", "npm:0.0.1"],\
|
||||
@ -8592,6 +8640,7 @@ const RAW_RUNTIME_STATE =
|
||||
["prismjs", "npm:1.29.0"],\
|
||||
["punycode", "npm:2.3.0"],\
|
||||
["querystring", "npm:0.2.1"],\
|
||||
["reconnecting-websocket", "npm:4.4.0"],\
|
||||
["rndstr", "npm:1.0.0"],\
|
||||
["rollup", "npm:3.26.2"],\
|
||||
["s-age", "npm:1.1.2"],\
|
||||
|
BIN
.yarn/cache/@rollup-plugin-replace-npm-5.0.5-42f61be6e8-bcf106346f.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/@rollup-plugin-replace-npm-5.0.5-42f61be6e8-bcf106346f.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip
(Stored with Git LFS)
vendored
Normal file
BIN
.yarn/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
@ -17,6 +17,7 @@
|
||||
"@phosphor-icons/web": "^2.0.3",
|
||||
"@rollup/plugin-alias": "3.1.9",
|
||||
"@rollup/plugin-json": "4.1.0",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/pluginutils": "^4.2.1",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
@ -57,7 +58,6 @@
|
||||
"focus-trap": "^7.5.2",
|
||||
"focus-trap-vue": "^4.0.2",
|
||||
"gsap": "^3.12.2",
|
||||
"iceshrimp-js": "workspace:*",
|
||||
"idb-keyval": "6.2.1",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"json5": "2.2.3",
|
||||
@ -103,6 +103,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"eslint": "^8.45.0"
|
||||
"eslint": "^8.45.0",
|
||||
"reconnecting-websocket": "^4.4.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { defineAsyncComponent, reactive } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import { i18n } from "./i18n";
|
||||
import { del, get, set } from "@/scripts/idb-proxy";
|
||||
import { apiUrl } from "@/config";
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import type * as Misskey from "iceshrimp-js";
|
||||
import type * as Misskey from "@/iceshrimp-js";
|
||||
import XWindow from "@/components/MkWindow.vue";
|
||||
import MkTextarea from "@/components/form/textarea.vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
|
@ -102,7 +102,7 @@ import { defaultStore } from "@/store";
|
||||
import { addSkinTone, emojilist } from "@/scripts/emojilist";
|
||||
import { instance } from "@/instance";
|
||||
import { i18n } from "@/i18n";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js";
|
||||
|
||||
interface EmojiDef {
|
||||
emoji: string;
|
||||
|
@ -63,7 +63,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js";
|
||||
import { i18n } from "@/i18n";
|
||||
import { acct } from "@/filters/user";
|
||||
import { $i } from "@/account";
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted } from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import Cropper from "cropperjs";
|
||||
import tinycolor from "tinycolor2";
|
||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { length } from "stringz";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import { concat } from "@/scripts/array";
|
||||
import { i18n } from "@/i18n";
|
||||
import {defaultStore} from "@/store";
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent, ref } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
||||
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
||||
import bytes from "@/filters/bytes";
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent, ref } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import { defaultStore } from "@/store";
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
|
@ -140,7 +140,7 @@ import {
|
||||
ref,
|
||||
watch,
|
||||
} from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import MkButton from "./MkButton.vue";
|
||||
import XNavFolder from "@/components/MkDrive.navFolder.vue";
|
||||
import XFolder from "@/components/MkDrive.folder.vue";
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import type * as Misskey from "iceshrimp-js";
|
||||
import type * as Misskey from "@/iceshrimp-js";
|
||||
import ImgWithBlurhash from "@/components/MkImgWithBlurhash.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import XDrive from "@/components/MkDrive.vue";
|
||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||
import number from "@/filters/number";
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import XDrive from "@/components/MkDrive.vue";
|
||||
import XWindow from "@/components/MkWindow.vue";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -164,7 +164,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import XSection from "@/components/MkEmojiPicker.section.vue";
|
||||
import {
|
||||
emojilist,
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import * as os from "@/os";
|
||||
|
||||
const meta = ref<Misskey.entities.DetailedInstanceMetadata>();
|
||||
|
@ -53,7 +53,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
||||
import bytes from "@/filters/bytes";
|
||||
|
@ -62,7 +62,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeUnmount, onMounted } from "vue";
|
||||
import type * as Misskey from "iceshrimp-js";
|
||||
import type * as Misskey from "@/iceshrimp-js";
|
||||
import * as os from "@/os";
|
||||
import { stream } from "@/stream";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import bytes from "@/filters/bytes";
|
||||
import number from "@/filters/number";
|
||||
import MkModal from "@/components/MkModal.vue";
|
||||
|
@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as iceshrimp from "iceshrimp-js";
|
||||
import * as iceshrimp from "@/iceshrimp-js";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
|
||||
|
@ -60,7 +60,7 @@ import MkInput from "@/components/form/input.vue";
|
||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import { Instance } from "iceshrimp-js/built/entities";
|
||||
import { Instance } from "@/iceshrimp-js/entities";
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: "ok", selected: Instance): void;
|
||||
|
@ -90,7 +90,7 @@
|
||||
import { watch, ref, computed } from "vue";
|
||||
import VuePlyr from "vue-plyr";
|
||||
import "vue-plyr/dist/vue-plyr.css";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
|
||||
import ImgWithBlurhash from "@/components/MkImgWithBlurhash.vue";
|
||||
import { defaultStore } from "@/store";
|
||||
|
@ -58,7 +58,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from "vue";
|
||||
import VuePlyr from "vue-plyr";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import { ColdDeviceStorage } from "@/store";
|
||||
import "vue-plyr/dist/vue-plyr.css";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import PhotoSwipeLightbox from "photoswipe/lightbox";
|
||||
import PhotoSwipe from "photoswipe";
|
||||
import "photoswipe/style.css";
|
||||
|
@ -260,7 +260,7 @@
|
||||
import { computed, inject, onMounted, onUnmounted, reactive, ref } from "vue";
|
||||
import * as mfm from "mfm-js";
|
||||
import type { Ref } from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import MkNoteSub from "@/components/MkNoteSub.vue";
|
||||
import MkSubNoteContent from "./MkSubNoteContent.vue";
|
||||
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
||||
|
@ -164,7 +164,7 @@ import {
|
||||
reactive,
|
||||
ref,
|
||||
} from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkTab from "@/components/MkTab.vue";
|
||||
import MkNote from "@/components/MkNote.vue";
|
||||
import MkNoteSub from "@/components/MkNoteSub.vue";
|
||||
@ -185,7 +185,7 @@ import { getNoteMenu } from "@/scripts/get-note-menu";
|
||||
import { useNoteCapture } from "@/scripts/use-note-capture";
|
||||
import { deepClone } from "@/scripts/clone";
|
||||
import { stream } from "@/stream";
|
||||
import { NoteUpdatedEvent } from "iceshrimp-js/src/streaming.types";
|
||||
import { NoteUpdatedEvent } from "@/iceshrimp-js/streaming.types";
|
||||
import appear from "@/directives/appear";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -48,7 +48,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import { defaultStore, noteViewInterruptors } from "@/store";
|
||||
import MkVisibility from "@/components/MkVisibility.vue";
|
||||
import MkInstanceTicker from "@/components/MkInstanceTicker.vue";
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
||||
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
|
||||
|
||||
|
@ -181,7 +181,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { inject, ref } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
||||
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
|
||||
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
|
||||
|
@ -274,7 +274,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, watch } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
||||
import MkFollowButton from "@/components/MkFollowButton.vue";
|
||||
import XReactionTooltip from "@/components/MkReactionTooltip.vue";
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import { notificationTypes } from "iceshrimp-js";
|
||||
import { notificationTypes } from "@/iceshrimp-js";
|
||||
import MkSwitch from "./form/switch.vue";
|
||||
import MkInfo from "./MkInfo.vue";
|
||||
import MkButton from "./MkButton.vue";
|
||||
|
@ -54,7 +54,7 @@ import {
|
||||
computed,
|
||||
ref,
|
||||
} from "vue";
|
||||
import { notificationTypes } from "iceshrimp-js";
|
||||
import { notificationTypes } from "@/iceshrimp-js";
|
||||
import MkPagination, { Paging } from "@/components/MkPagination.vue";
|
||||
import XNotification from "@/components/MkNotification.vue";
|
||||
import XList from "@/components/MkDateSeparatedList.vue";
|
||||
|
@ -72,7 +72,7 @@ import {
|
||||
ref,
|
||||
watch,
|
||||
} from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import * as os from "@/os";
|
||||
import {
|
||||
onScrollTop,
|
||||
|
@ -53,7 +53,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import { sum } from "@/scripts/array";
|
||||
import { pleaseLogin } from "@/scripts/please-login";
|
||||
import * as os from "@/os";
|
||||
|
@ -235,11 +235,11 @@
|
||||
<script lang="ts" setup>
|
||||
import { inject, watch, nextTick, onMounted, defineAsyncComponent } from "vue";
|
||||
import * as mfm from "mfm-js";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import insertTextAtCursor from "insert-text-at-cursor";
|
||||
import { length } from "stringz";
|
||||
import { toASCII } from "punycode/";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import { throttle } from "throttle-debounce";
|
||||
import XNoteSimple from "@/components/MkNoteSimple.vue";
|
||||
import XNotePreview from "@/components/MkNotePreview.vue";
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkModal from "@/components/MkModal.vue";
|
||||
import MkPostForm from "@/components/MkPostForm.vue";
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import type { Note } from "iceshrimp-js/built/entities";
|
||||
import type { Note } from "@/iceshrimp-js/entities";
|
||||
import { pleaseLogin } from "@/scripts/please-login";
|
||||
import * as os from "@/os";
|
||||
import { $i } from "@/account";
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, watch } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkReactionIcon from "@/components/MkReactionIcon.vue";
|
||||
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XDetails from "@/components/MkReactionsViewer.details.vue";
|
||||
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
||||
import * as os from "@/os";
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import { $i } from "@/account";
|
||||
import XReaction from "@/components/MkReactionsViewer.reaction.vue";
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import Ripple from "@/components/MkRipple.vue";
|
||||
import XDetails from "@/components/MkUsersTooltip.vue";
|
||||
import { pleaseLogin } from "@/scripts/please-login";
|
||||
|
@ -4,7 +4,7 @@ import MkInput from "@/components/form/input.vue";
|
||||
import * as os from "@/os.js";
|
||||
import XSearchFilterDialog from "@/components/MkSearchFilterDialog.vue";
|
||||
import { onActivated, onMounted, onUnmounted, ref, toRefs } from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
|
||||
const props = defineProps<{
|
||||
query: string;
|
||||
|
@ -38,7 +38,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Note } from "iceshrimp-js/built/entities";
|
||||
import type { Note } from "@/iceshrimp-js/entities";
|
||||
import Ripple from "@/components/MkRipple.vue";
|
||||
import { pleaseLogin } from "@/scripts/please-login";
|
||||
import * as os from "@/os";
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import type { Note } from "iceshrimp-js/built/entities";
|
||||
import type { Note } from "@/iceshrimp-js/entities";
|
||||
import Ripple from "@/components/MkRipple.vue";
|
||||
import XDetails from "@/components/MkUsersTooltip.vue";
|
||||
import { pleaseLogin } from "@/scripts/please-login";
|
||||
|
@ -202,7 +202,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import * as mfm from "mfm-js";
|
||||
import * as os from "@/os";
|
||||
import XNoteSimple from "@/components/MkNoteSimple.vue";
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import { permissions as kinds } from "iceshrimp-js";
|
||||
import { permissions as kinds } from "@/iceshrimp-js";
|
||||
import MkInput from "./form/input.vue";
|
||||
import MkSwitch from "./form/switch.vue";
|
||||
import MkButton from "./MkButton.vue";
|
||||
|
@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { acct, userPage } from "@/filters/user";
|
||||
|
@ -86,7 +86,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkFollowButton from "@/components/MkFollowButton.vue";
|
||||
import XShowMoreButton from "@/components/MkShowMoreButton.vue";
|
||||
import MkNumber from "@/components/MkNumber.vue";
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -30,8 +30,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from "vue";
|
||||
import MkUserInfo from "@/components/MkUserInfo.vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import * as os from "@/os";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -89,7 +89,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkInput from "@/components/form/input.vue";
|
||||
import FormSplit from "@/components/form/split.vue";
|
||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||
|
@ -85,7 +85,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkInput from "@/components/form/input.vue";
|
||||
import FormSplit from "@/components/form/split.vue";
|
||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||
|
@ -126,7 +126,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, watch } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkModal from "@/components/MkModal.vue";
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import { toUnicode } from "punycode/";
|
||||
import { host as hostRaw } from "@/config";
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, watch } from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
|
||||
import { extractAvgColorFromBlurhash } from "@/scripts/extract-avg-color-from-blurhash";
|
||||
import { acct, userPage } from "@/filters/user";
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from "vue";
|
||||
import type { CustomEmoji } from "iceshrimp-js/built/entities";
|
||||
import type { CustomEmoji } from "@/iceshrimp-js/entities.js";
|
||||
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
|
||||
import { char2filePath } from "@/scripts/twemoji-base";
|
||||
import { defaultStore } from "@/store";
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -18,11 +18,15 @@ export const apiUrl = `${url}/api`;
|
||||
export const wsUrl = `${url
|
||||
.replace("http://", "ws://")
|
||||
.replace("https://", "wss://")}/streaming`;
|
||||
export const lang = localStorage.getItem("lang");
|
||||
export const lang = localStorage.getItem("lang") ?? 'en-US';
|
||||
export const langs = _LANGS_;
|
||||
export const locale = JSON.parse(localStorage.getItem("locale"));
|
||||
export let locale = JSON.parse(localStorage.getItem("locale"));
|
||||
export const version = _VERSION_;
|
||||
export const instanceName = siteName === "Iceshrimp" ? host : siteName;
|
||||
export let searchEngine = 'https://duckduckgo.com/?q=';
|
||||
export const ui = localStorage.getItem("ui");
|
||||
export const debug = localStorage.getItem("debug") === "true";
|
||||
|
||||
export function updateLocale(newLocale: any): void {
|
||||
locale = newLocale;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import { url } from "@/config";
|
||||
import { ParsedAcct } from "@/iceshrimp-js/acct.js";
|
||||
|
||||
export const acct = (user: misskey.Acct) => {
|
||||
return Acct.toString(user);
|
||||
export const acct = (user: ParsedAcct) => {
|
||||
return new Acct(user.username, user.host).toString();
|
||||
};
|
||||
|
||||
export const userName = (user: misskey.entities.User) => {
|
||||
|
@ -2,7 +2,7 @@ import { markRaw } from "vue";
|
||||
import { locale } from "@/config";
|
||||
import { I18n } from "@/scripts/i18n";
|
||||
|
||||
export const i18n = markRaw(new I18n(locale));
|
||||
export let i18n = markRaw(new I18n(locale));
|
||||
|
||||
// このファイルに書きたくないけどここに書かないと何故かVeturが認識しない
|
||||
declare module "@vue/runtime-core" {
|
||||
@ -11,3 +11,7 @@ declare module "@vue/runtime-core" {
|
||||
$ts: typeof i18n["locale"];
|
||||
}
|
||||
}
|
||||
|
||||
export function updateI18n(newLocale: any) {
|
||||
i18n.ts = newLocale;
|
||||
}
|
||||
|
32
packages/client/src/iceshrimp-js/acct.ts
Normal file
32
packages/client/src/iceshrimp-js/acct.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export type ParsedAcct = {
|
||||
username: string;
|
||||
host: string | null;
|
||||
}
|
||||
|
||||
export class Acct {
|
||||
public username: string;
|
||||
public host: string | null;
|
||||
|
||||
constructor(username: string, host: string | null) {
|
||||
this.username = username;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public static parse(acct: string): ParsedAcct {
|
||||
if (acct.startsWith("@")) acct = acct.slice(1);
|
||||
const split = acct.split("@", 2);
|
||||
return { username: split[0], host: split[1] ?? null };
|
||||
}
|
||||
|
||||
public static fromParsed(parsed: ParsedAcct) {
|
||||
return new this(parsed.username, parsed.host);
|
||||
}
|
||||
|
||||
public static toString(parsed: ParsedAcct) {
|
||||
return this.fromParsed(parsed).toString();
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.host == null ? this.username : `${this.username}@${this.host}`;
|
||||
}
|
||||
}
|
127
packages/client/src/iceshrimp-js/api.ts
Normal file
127
packages/client/src/iceshrimp-js/api.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import { Endpoints } from "./api.types.js";
|
||||
|
||||
const MK_API_ERROR = Symbol();
|
||||
|
||||
export type APIError = {
|
||||
id: string;
|
||||
code: string;
|
||||
message: string;
|
||||
kind: "client" | "server";
|
||||
info: Record<string, any>;
|
||||
};
|
||||
|
||||
export function isAPIError(reason: any): reason is APIError {
|
||||
return reason[MK_API_ERROR] === true;
|
||||
}
|
||||
|
||||
export type FetchLike = (
|
||||
input: string,
|
||||
init?: {
|
||||
method?: string;
|
||||
body?: string;
|
||||
credentials?: RequestCredentials;
|
||||
cache?: RequestCache;
|
||||
},
|
||||
) => Promise<{
|
||||
status: number;
|
||||
json(): Promise<any>;
|
||||
}>;
|
||||
|
||||
type IsNeverType<T> = [T] extends [never] ? true : false;
|
||||
|
||||
type StrictExtract<Union, Cond> = Cond extends Union ? Union : never;
|
||||
|
||||
type IsCaseMatched<
|
||||
E extends keyof Endpoints,
|
||||
P extends Endpoints[E]["req"],
|
||||
C extends number,
|
||||
> = IsNeverType<
|
||||
StrictExtract<Endpoints[E]["res"]["$switch"]["$cases"][C], [P, any]>
|
||||
> extends false
|
||||
? true
|
||||
: false;
|
||||
|
||||
type GetCaseResult<
|
||||
E extends keyof Endpoints,
|
||||
P extends Endpoints[E]["req"],
|
||||
C extends number,
|
||||
> = StrictExtract<Endpoints[E]["res"]["$switch"]["$cases"][C], [P, any]>[1];
|
||||
|
||||
export class APIClient {
|
||||
public origin: string;
|
||||
public credential: string | null | undefined;
|
||||
public fetch: FetchLike;
|
||||
|
||||
constructor(opts: {
|
||||
origin: APIClient["origin"];
|
||||
credential?: APIClient["credential"];
|
||||
fetch?: APIClient["fetch"] | null | undefined;
|
||||
}) {
|
||||
this.origin = opts.origin;
|
||||
this.credential = opts.credential;
|
||||
// ネイティブ関数をそのまま変数に代入して使おうとするとChromiumではIllegal invocationエラーが発生するため、
|
||||
// 環境で実装されているfetchを使う場合は無名関数でラップして使用する
|
||||
this.fetch = opts.fetch || ((...args) => fetch(...args));
|
||||
}
|
||||
|
||||
public request<E extends keyof Endpoints, P extends Endpoints[E]["req"]>(
|
||||
endpoint: E,
|
||||
params: P = {} as P,
|
||||
credential?: string | null | undefined,
|
||||
): Promise<
|
||||
Endpoints[E]["res"] extends {
|
||||
$switch: { $cases: [any, any][]; $default: any };
|
||||
}
|
||||
? IsCaseMatched<E, P, 0> extends true
|
||||
? GetCaseResult<E, P, 0>
|
||||
: IsCaseMatched<E, P, 1> extends true
|
||||
? GetCaseResult<E, P, 1>
|
||||
: IsCaseMatched<E, P, 2> extends true
|
||||
? GetCaseResult<E, P, 2>
|
||||
: IsCaseMatched<E, P, 3> extends true
|
||||
? GetCaseResult<E, P, 3>
|
||||
: IsCaseMatched<E, P, 4> extends true
|
||||
? GetCaseResult<E, P, 4>
|
||||
: IsCaseMatched<E, P, 5> extends true
|
||||
? GetCaseResult<E, P, 5>
|
||||
: IsCaseMatched<E, P, 6> extends true
|
||||
? GetCaseResult<E, P, 6>
|
||||
: IsCaseMatched<E, P, 7> extends true
|
||||
? GetCaseResult<E, P, 7>
|
||||
: IsCaseMatched<E, P, 8> extends true
|
||||
? GetCaseResult<E, P, 8>
|
||||
: IsCaseMatched<E, P, 9> extends true
|
||||
? GetCaseResult<E, P, 9>
|
||||
: Endpoints[E]["res"]["$switch"]["$default"]
|
||||
: Endpoints[E]["res"]
|
||||
> {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this.fetch(`${this.origin}/api/${endpoint}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
...params,
|
||||
i: credential !== undefined ? credential : this.credential,
|
||||
}),
|
||||
credentials: "omit",
|
||||
cache: "no-cache",
|
||||
})
|
||||
.then(async (res) => {
|
||||
const body = res.status === 204 ? null : await res.json();
|
||||
|
||||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
} else if (res.status === 204) {
|
||||
resolve(null);
|
||||
} else {
|
||||
reject({
|
||||
[MK_API_ERROR]: true,
|
||||
...body.error,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
return promise as any;
|
||||
}
|
||||
}
|
1088
packages/client/src/iceshrimp-js/api.types.ts
Normal file
1088
packages/client/src/iceshrimp-js/api.types.ts
Normal file
File diff suppressed because it is too large
Load Diff
58
packages/client/src/iceshrimp-js/consts.ts
Normal file
58
packages/client/src/iceshrimp-js/consts.ts
Normal file
@ -0,0 +1,58 @@
|
||||
export const notificationTypes = [
|
||||
"follow",
|
||||
"mention",
|
||||
"reply",
|
||||
"renote",
|
||||
"quote",
|
||||
"reaction",
|
||||
"pollVote",
|
||||
"pollEnded",
|
||||
"receiveFollowRequest",
|
||||
"followRequestAccepted",
|
||||
"groupInvited",
|
||||
"app",
|
||||
] as const;
|
||||
|
||||
export const noteVisibilities = [
|
||||
"public",
|
||||
"home",
|
||||
"followers",
|
||||
"specified",
|
||||
] as const;
|
||||
|
||||
export const ffVisibility = ["public", "followers", "private"] as const;
|
||||
|
||||
export const permissions = [
|
||||
"read:account",
|
||||
"write:account",
|
||||
"read:blocks",
|
||||
"write:blocks",
|
||||
"read:drive",
|
||||
"write:drive",
|
||||
"read:favorites",
|
||||
"write:favorites",
|
||||
"read:following",
|
||||
"write:following",
|
||||
"read:messaging",
|
||||
"write:messaging",
|
||||
"read:mutes",
|
||||
"write:mutes",
|
||||
"write:notes",
|
||||
"read:notifications",
|
||||
"write:notifications",
|
||||
"read:reactions",
|
||||
"write:reactions",
|
||||
"write:votes",
|
||||
"read:pages",
|
||||
"write:pages",
|
||||
"write:page-likes",
|
||||
"read:page-likes",
|
||||
"read:user-groups",
|
||||
"write:user-groups",
|
||||
"read:channels",
|
||||
"write:channels",
|
||||
"read:gallery",
|
||||
"write:gallery",
|
||||
"read:gallery-likes",
|
||||
"write:gallery-likes",
|
||||
];
|
494
packages/client/src/iceshrimp-js/entities.ts
Normal file
494
packages/client/src/iceshrimp-js/entities.ts
Normal file
@ -0,0 +1,494 @@
|
||||
export type ID = string;
|
||||
export type DateString = string;
|
||||
|
||||
type TODO = Record<string, any>;
|
||||
|
||||
// NOTE: 極力この型を使うのは避け、UserLite か UserDetailed か明示するように
|
||||
export type User = UserLite | UserDetailed;
|
||||
|
||||
export type UserLite = {
|
||||
id: ID;
|
||||
username: string;
|
||||
host: string | null;
|
||||
name: string;
|
||||
onlineStatus: "online" | "active" | "offline" | "unknown";
|
||||
avatarUrl: string;
|
||||
avatarBlurhash: string;
|
||||
alsoKnownAs: string[];
|
||||
movedToUri: any;
|
||||
emojis: {
|
||||
name: string;
|
||||
url: string;
|
||||
}[];
|
||||
instance?: {
|
||||
name: Instance["name"];
|
||||
softwareName: Instance["softwareName"];
|
||||
softwareVersion: Instance["softwareVersion"];
|
||||
iconUrl: Instance["iconUrl"];
|
||||
faviconUrl: Instance["faviconUrl"];
|
||||
themeColor: Instance["themeColor"];
|
||||
};
|
||||
};
|
||||
|
||||
export type UserDetailed = UserLite & {
|
||||
bannerBlurhash: string | null;
|
||||
bannerColor: string | null;
|
||||
bannerUrl: string | null;
|
||||
birthday: string | null;
|
||||
createdAt: DateString;
|
||||
description: string | null;
|
||||
ffVisibility: "public" | "followers" | "private";
|
||||
fields: {
|
||||
name: string;
|
||||
value: string;
|
||||
verified?: boolean;
|
||||
}[];
|
||||
followersCount: number;
|
||||
followingCount: number;
|
||||
hasPendingFollowRequestFromYou: boolean;
|
||||
hasPendingFollowRequestToYou: boolean;
|
||||
isAdmin: boolean;
|
||||
isBlocked: boolean;
|
||||
isBlocking: boolean;
|
||||
isBot: boolean;
|
||||
isCat: boolean;
|
||||
isFollowed: boolean;
|
||||
isFollowing: boolean;
|
||||
isLocked: boolean;
|
||||
isModerator: boolean;
|
||||
isMuted: boolean;
|
||||
isRenoteMuted: boolean;
|
||||
isSilenced: boolean;
|
||||
isSuspended: boolean;
|
||||
lang: string | null;
|
||||
lastFetchedAt?: DateString;
|
||||
location: string | null;
|
||||
notesCount: number;
|
||||
pinnedNoteIds: ID[];
|
||||
pinnedNotes: Note[];
|
||||
pinnedPage: Page | null;
|
||||
pinnedPageId: string | null;
|
||||
publicReactions: boolean;
|
||||
securityKeys: boolean;
|
||||
twoFactorEnabled: boolean;
|
||||
updatedAt: DateString | null;
|
||||
uri: string | null;
|
||||
url: string | null;
|
||||
};
|
||||
|
||||
export type UserGroup = TODO;
|
||||
|
||||
export type UserList = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
name: string;
|
||||
userIds: User["id"][];
|
||||
};
|
||||
|
||||
export type MeDetailed = UserDetailed & {
|
||||
avatarId: DriveFile["id"];
|
||||
bannerId: DriveFile["id"];
|
||||
autoAcceptFollowed: boolean;
|
||||
alwaysMarkNsfw: boolean;
|
||||
carefulBot: boolean;
|
||||
emailNotificationTypes: string[];
|
||||
hasPendingReceivedFollowRequest: boolean;
|
||||
hasUnreadAnnouncement: boolean;
|
||||
hasUnreadAntenna: boolean;
|
||||
hasUnreadChannel: boolean;
|
||||
hasUnreadMentions: boolean;
|
||||
hasUnreadMessagingMessage: boolean;
|
||||
hasUnreadNotification: boolean;
|
||||
hasUnreadSpecifiedNotes: boolean;
|
||||
hideOnlineStatus: boolean;
|
||||
injectFeaturedNote: boolean;
|
||||
integrations: Record<string, any>;
|
||||
isDeleted: boolean;
|
||||
isExplorable: boolean;
|
||||
mutedWords: string[][];
|
||||
mutingNotificationTypes: string[];
|
||||
noCrawle: boolean;
|
||||
preventAiLearning: boolean;
|
||||
receiveAnnouncementEmail: boolean;
|
||||
usePasswordLessLogin: boolean;
|
||||
[other: string]: any;
|
||||
};
|
||||
|
||||
export type DriveFile = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
isSensitive: boolean;
|
||||
name: string;
|
||||
thumbnailUrl: string;
|
||||
url: string;
|
||||
type: string;
|
||||
size: number;
|
||||
md5: string;
|
||||
blurhash: string;
|
||||
comment: string | null;
|
||||
properties: Record<string, any>;
|
||||
};
|
||||
|
||||
export type DriveFolder = TODO;
|
||||
|
||||
export type GalleryPost = TODO;
|
||||
|
||||
export type Note = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
text: string | null;
|
||||
cw: string | null;
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
reply?: Note;
|
||||
replyId: Note["id"];
|
||||
renote?: Note;
|
||||
renoteId: Note["id"];
|
||||
files: DriveFile[];
|
||||
fileIds: DriveFile["id"][];
|
||||
visibility: "public" | "home" | "followers" | "specified";
|
||||
visibleUserIds?: User["id"][];
|
||||
localOnly?: boolean;
|
||||
channel?: Channel["id"];
|
||||
myReaction?: string;
|
||||
isRenoted?: boolean;
|
||||
reactions: Record<string, number>;
|
||||
renoteCount: number;
|
||||
repliesCount: number;
|
||||
poll?: {
|
||||
expiresAt: DateString | null;
|
||||
multiple: boolean;
|
||||
choices: {
|
||||
isVoted: boolean;
|
||||
text: string;
|
||||
votes: number;
|
||||
}[];
|
||||
};
|
||||
emojis: {
|
||||
name: string;
|
||||
url: string;
|
||||
}[];
|
||||
uri?: string;
|
||||
url?: string;
|
||||
updatedAt?: DateString;
|
||||
isHidden?: boolean;
|
||||
};
|
||||
|
||||
export type NoteReaction = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
user: UserLite;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type Notification = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
isRead: boolean;
|
||||
} & (
|
||||
| {
|
||||
type: "reaction";
|
||||
reaction: string;
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note;
|
||||
}
|
||||
| {
|
||||
type: "reply";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note;
|
||||
}
|
||||
| {
|
||||
type: "renote";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note;
|
||||
}
|
||||
| {
|
||||
type: "quote";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note;
|
||||
}
|
||||
| {
|
||||
type: "mention";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note;
|
||||
}
|
||||
| {
|
||||
type: "pollVote";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note;
|
||||
}
|
||||
| {
|
||||
type: "follow";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
}
|
||||
| {
|
||||
type: "followRequestAccepted";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
}
|
||||
| {
|
||||
type: "receiveFollowRequest";
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
}
|
||||
| {
|
||||
type: "groupInvited";
|
||||
invitation: UserGroup;
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
}
|
||||
| {
|
||||
type: "app";
|
||||
header?: string | null;
|
||||
body: string;
|
||||
icon?: string | null;
|
||||
}
|
||||
);
|
||||
|
||||
export type MessagingMessage = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
file: DriveFile | null;
|
||||
fileId: DriveFile["id"] | null;
|
||||
isRead: boolean;
|
||||
reads: User["id"][];
|
||||
text: string | null;
|
||||
user: User;
|
||||
userId: User["id"];
|
||||
recipient?: User | null;
|
||||
recipientId: User["id"] | null;
|
||||
group?: UserGroup | null;
|
||||
groupId: UserGroup["id"] | null;
|
||||
};
|
||||
|
||||
export type CustomEmoji = {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
category: string;
|
||||
aliases: string[];
|
||||
};
|
||||
|
||||
export type LiteInstanceMetadata = {
|
||||
maintainerName: string | null;
|
||||
maintainerEmail: string | null;
|
||||
version: string;
|
||||
name: string | null;
|
||||
uri: string;
|
||||
description: string | null;
|
||||
tosUrl: string | null;
|
||||
disableRegistration: boolean;
|
||||
disableLocalTimeline: boolean;
|
||||
disableRecommendedTimeline: boolean;
|
||||
disableGlobalTimeline: boolean;
|
||||
driveCapacityPerLocalUserMb: number;
|
||||
driveCapacityPerRemoteUserMb: number;
|
||||
enableHcaptcha: boolean;
|
||||
hcaptchaSiteKey: string | null;
|
||||
enableRecaptcha: boolean;
|
||||
recaptchaSiteKey: string | null;
|
||||
swPublickey: string | null;
|
||||
maxNoteTextLength: number;
|
||||
enableEmail: boolean;
|
||||
enableGithubIntegration: boolean;
|
||||
enableDiscordIntegration: boolean;
|
||||
searchEngine: string;
|
||||
emojis: CustomEmoji[];
|
||||
images: {
|
||||
error: string;
|
||||
notFound: string;
|
||||
info: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type DetailedInstanceMetadata = LiteInstanceMetadata & {
|
||||
features: Record<string, any>;
|
||||
};
|
||||
|
||||
export type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata;
|
||||
|
||||
export type ServerInfo = {
|
||||
machine: string;
|
||||
cpu: {
|
||||
model: string;
|
||||
cores: number;
|
||||
};
|
||||
mem: {
|
||||
total: number;
|
||||
};
|
||||
fs: {
|
||||
total: number;
|
||||
used: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type Stats = {
|
||||
notesCount: number;
|
||||
originalNotesCount: number;
|
||||
usersCount: number;
|
||||
originalUsersCount: number;
|
||||
instances: number;
|
||||
driveUsageLocal: number;
|
||||
driveUsageRemote: number;
|
||||
};
|
||||
|
||||
export type Page = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
updatedAt: DateString;
|
||||
userId: User["id"];
|
||||
user: User;
|
||||
content: Record<string, any>[];
|
||||
variables: Record<string, any>[];
|
||||
title: string;
|
||||
name: string;
|
||||
summary: string | null;
|
||||
hideTitleWhenPinned: boolean;
|
||||
alignCenter: boolean;
|
||||
font: string;
|
||||
script: string;
|
||||
eyeCatchingImageId: DriveFile["id"] | null;
|
||||
eyeCatchingImage: DriveFile | null;
|
||||
attachedFiles: any;
|
||||
likedCount: number;
|
||||
isLiked?: boolean;
|
||||
};
|
||||
|
||||
export type PageEvent = {
|
||||
pageId: Page["id"];
|
||||
event: string;
|
||||
var: any;
|
||||
userId: User["id"];
|
||||
user: User;
|
||||
};
|
||||
|
||||
export type Announcement = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
updatedAt: DateString | null;
|
||||
text: string;
|
||||
title: string;
|
||||
imageUrl: string | null;
|
||||
isRead?: boolean;
|
||||
};
|
||||
|
||||
export type Antenna = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
name: string;
|
||||
keywords: string[][]; // TODO
|
||||
excludeKeywords: string[][]; // TODO
|
||||
src: "home" | "all" | "users" | "list" | "group" | "instances";
|
||||
userListId: ID | null; // TODO
|
||||
userGroupId: ID | null; // TODO
|
||||
users: string[]; // TODO
|
||||
instances: string[];
|
||||
caseSensitive: boolean;
|
||||
notify: boolean;
|
||||
withReplies: boolean;
|
||||
withFile: boolean;
|
||||
hasUnreadNote: boolean;
|
||||
};
|
||||
|
||||
export type App = TODO;
|
||||
|
||||
export type AuthSession = {
|
||||
id: ID;
|
||||
app: App;
|
||||
token: string;
|
||||
};
|
||||
|
||||
export type Clip = TODO;
|
||||
|
||||
export type NoteFavorite = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
noteId: Note["id"];
|
||||
note: Note;
|
||||
};
|
||||
|
||||
export type FollowRequest = {
|
||||
id: ID;
|
||||
follower: User;
|
||||
followee: User;
|
||||
};
|
||||
|
||||
export type Channel = {
|
||||
id: ID;
|
||||
// TODO
|
||||
};
|
||||
|
||||
export type Following = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
followerId: User["id"];
|
||||
followeeId: User["id"];
|
||||
};
|
||||
|
||||
export type FollowingFolloweePopulated = Following & {
|
||||
followee: UserDetailed;
|
||||
};
|
||||
|
||||
export type FollowingFollowerPopulated = Following & {
|
||||
follower: UserDetailed;
|
||||
};
|
||||
|
||||
export type Blocking = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
blockeeId: User["id"];
|
||||
blockee: UserDetailed;
|
||||
};
|
||||
|
||||
export type Instance = {
|
||||
id: ID;
|
||||
caughtAt: DateString;
|
||||
host: string;
|
||||
usersCount: number;
|
||||
notesCount: number;
|
||||
followingCount: number;
|
||||
followersCount: number;
|
||||
driveUsage: number;
|
||||
driveFiles: number;
|
||||
latestRequestSentAt: DateString | null;
|
||||
latestStatus: number | null;
|
||||
latestRequestReceivedAt: DateString | null;
|
||||
lastCommunicatedAt: DateString;
|
||||
isNotResponding: boolean;
|
||||
isSuspended: boolean;
|
||||
softwareName: string | null;
|
||||
softwareVersion: string | null;
|
||||
openRegistrations: boolean | null;
|
||||
name: string | null;
|
||||
description: string | null;
|
||||
maintainerName: string | null;
|
||||
maintainerEmail: string | null;
|
||||
iconUrl: string | null;
|
||||
faviconUrl: string | null;
|
||||
themeColor: string | null;
|
||||
infoUpdatedAt: DateString | null;
|
||||
};
|
||||
|
||||
export type Signin = {
|
||||
id: ID;
|
||||
createdAt: DateString;
|
||||
ip: string;
|
||||
headers: Record<string, any>;
|
||||
success: boolean;
|
||||
};
|
||||
|
||||
export type UserSorting =
|
||||
| "+follower"
|
||||
| "-follower"
|
||||
| "+createdAt"
|
||||
| "-createdAt"
|
||||
| "+updatedAt"
|
||||
| "-updatedAt";
|
||||
export type OriginType = "combined" | "local" | "remote";
|
21
packages/client/src/iceshrimp-js/index.ts
Normal file
21
packages/client/src/iceshrimp-js/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Endpoints } from "./api.types.js";
|
||||
import Stream, { Connection } from "./streaming.js";
|
||||
import { Channels } from "./streaming.types.js";
|
||||
import { Acct } from "./acct.js";
|
||||
import * as consts from "./consts.js";
|
||||
|
||||
|
||||
export type { Endpoints, Channels }
|
||||
export { Acct, Stream, Connection as ChannelConnection };
|
||||
|
||||
export const permissions = consts.permissions;
|
||||
export const notificationTypes = consts.notificationTypes;
|
||||
export const noteVisibilities = consts.noteVisibilities;
|
||||
export const ffVisibility = consts.ffVisibility;
|
||||
|
||||
// api extractor not supported yet
|
||||
//export * as api from './api';
|
||||
//export * as entities from './entities';
|
||||
import * as api from "./api.js";
|
||||
import * as entities from "./entities.js";
|
||||
export { api, entities };
|
391
packages/client/src/iceshrimp-js/streaming.ts
Normal file
391
packages/client/src/iceshrimp-js/streaming.ts
Normal file
@ -0,0 +1,391 @@
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import ReconnectingWebsocket from "reconnecting-websocket";
|
||||
import { BroadcastEvents, Channels } from "./streaming.types.js";
|
||||
|
||||
function autobind(instance: any): void {
|
||||
const prototype = Object.getPrototypeOf(instance);
|
||||
|
||||
const propertyNames = Object.getOwnPropertyNames(prototype);
|
||||
|
||||
for (const key of propertyNames) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
||||
|
||||
if (typeof descriptor?.value === "function" && key !== "constructor") {
|
||||
Object.defineProperty(instance, key, {
|
||||
value: instance[key].bind(instance),
|
||||
enumerable: descriptor.enumerable,
|
||||
configurable: descriptor.configurable,
|
||||
writable: descriptor.writable,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function urlQuery(
|
||||
obj: Record<string, string | number | boolean | undefined>,
|
||||
): string {
|
||||
const params = Object.entries(obj)
|
||||
.filter(([, v]) => (Array.isArray(v) ? v.length : v !== undefined))
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
.reduce(
|
||||
(a, [k, v]) => ((a[k] = v!), a),
|
||||
{} as Record<string, string | number | boolean>,
|
||||
);
|
||||
|
||||
return Object.entries(params)
|
||||
.map((e) => `${e[0]}=${encodeURIComponent(e[1])}`)
|
||||
.join("&");
|
||||
}
|
||||
|
||||
type AnyOf<T extends Record<any, any>> = T[keyof T];
|
||||
|
||||
type StreamEvents = {
|
||||
_connected_: void;
|
||||
_disconnected_: void;
|
||||
} & BroadcastEvents;
|
||||
|
||||
/**
|
||||
* Misskey stream connection
|
||||
*/
|
||||
export default class Stream extends EventEmitter<StreamEvents> {
|
||||
private stream: ReconnectingWebsocket;
|
||||
public state: "initializing" | "reconnecting" | "connected" = "initializing";
|
||||
private sharedConnectionPools: Pool[] = [];
|
||||
private sharedConnections: SharedConnection[] = [];
|
||||
private nonSharedConnections: NonSharedConnection[] = [];
|
||||
private idCounter = 0;
|
||||
|
||||
constructor(
|
||||
origin: string,
|
||||
user: { token: string } | null,
|
||||
options?: {
|
||||
WebSocket?: any;
|
||||
},
|
||||
) {
|
||||
super();
|
||||
autobind(this);
|
||||
options = options || {};
|
||||
|
||||
const query = urlQuery({
|
||||
i: user?.token,
|
||||
|
||||
// To prevent cache of an HTML such as error screen
|
||||
_t: Date.now(),
|
||||
});
|
||||
|
||||
const wsOrigin = origin
|
||||
.replace("http://", "ws://")
|
||||
.replace("https://", "wss://");
|
||||
|
||||
this.stream = new ReconnectingWebsocket(
|
||||
`${wsOrigin}/streaming?${query}`,
|
||||
"",
|
||||
{
|
||||
minReconnectionDelay: 1, // https://github.com/pladaria/reconnecting-websocket/issues/91
|
||||
WebSocket: options.WebSocket,
|
||||
},
|
||||
);
|
||||
this.stream.addEventListener("open", this.onOpen);
|
||||
this.stream.addEventListener("close", this.onClose);
|
||||
this.stream.addEventListener("message", this.onMessage);
|
||||
}
|
||||
|
||||
private genId(): string {
|
||||
return (++this.idCounter).toString();
|
||||
}
|
||||
|
||||
public useChannel<C extends keyof Channels>(
|
||||
channel: C,
|
||||
params?: Channels[C]["params"],
|
||||
name?: string,
|
||||
): Connection<Channels[C]> {
|
||||
if (params) {
|
||||
return this.connectToChannel(channel, params);
|
||||
} else {
|
||||
return this.useSharedConnection(channel, name);
|
||||
}
|
||||
}
|
||||
|
||||
private useSharedConnection<C extends keyof Channels>(
|
||||
channel: C,
|
||||
name?: string,
|
||||
): SharedConnection<Channels[C]> {
|
||||
let pool = this.sharedConnectionPools.find((p) => p.channel === channel);
|
||||
|
||||
if (pool == null) {
|
||||
pool = new Pool(this, channel, this.genId());
|
||||
this.sharedConnectionPools.push(pool);
|
||||
}
|
||||
|
||||
const connection = new SharedConnection(this, channel, pool, name);
|
||||
this.sharedConnections.push(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
public removeSharedConnection(connection: SharedConnection): void {
|
||||
this.sharedConnections = this.sharedConnections.filter(
|
||||
(c) => c !== connection,
|
||||
);
|
||||
}
|
||||
|
||||
public removeSharedConnectionPool(pool: Pool): void {
|
||||
this.sharedConnectionPools = this.sharedConnectionPools.filter(
|
||||
(p) => p !== pool,
|
||||
);
|
||||
}
|
||||
|
||||
private connectToChannel<C extends keyof Channels>(
|
||||
channel: C,
|
||||
params: Channels[C]["params"],
|
||||
): NonSharedConnection<Channels[C]> {
|
||||
const connection = new NonSharedConnection(
|
||||
this,
|
||||
channel,
|
||||
this.genId(),
|
||||
params,
|
||||
);
|
||||
this.nonSharedConnections.push(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
public disconnectToChannel(connection: NonSharedConnection): void {
|
||||
this.nonSharedConnections = this.nonSharedConnections.filter(
|
||||
(c) => c !== connection,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback of when open connection
|
||||
*/
|
||||
private onOpen(): void {
|
||||
const isReconnect = this.state === "reconnecting";
|
||||
|
||||
this.state = "connected";
|
||||
this.emit("_connected_");
|
||||
|
||||
// チャンネル再接続
|
||||
if (isReconnect) {
|
||||
for (const p of this.sharedConnectionPools) p.connect();
|
||||
for (const c of this.nonSharedConnections) c.connect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback of when close connection
|
||||
*/
|
||||
private onClose(): void {
|
||||
if (this.state === "connected") {
|
||||
this.state = "reconnecting";
|
||||
this.emit("_disconnected_");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback of when received a message from connection
|
||||
*/
|
||||
private onMessage(message: { data: string }): void {
|
||||
const { type, body } = JSON.parse(message.data);
|
||||
|
||||
if (type === "channel") {
|
||||
const id = body.id;
|
||||
|
||||
let connections: Connection[];
|
||||
|
||||
connections = this.sharedConnections.filter((c) => c.id === id);
|
||||
|
||||
if (connections.length === 0) {
|
||||
const found = this.nonSharedConnections.find((c) => c.id === id);
|
||||
if (found) {
|
||||
connections = [found];
|
||||
}
|
||||
}
|
||||
|
||||
for (const c of connections) {
|
||||
c.emit(body.type, body.body);
|
||||
c.inCount++;
|
||||
}
|
||||
} else {
|
||||
this.emit(type, body);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to connection
|
||||
*/
|
||||
public send(typeOrPayload: any, payload?: any): void {
|
||||
const data =
|
||||
payload === undefined
|
||||
? typeOrPayload
|
||||
: {
|
||||
type: typeOrPayload,
|
||||
body: payload,
|
||||
};
|
||||
|
||||
this.stream.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this connection
|
||||
*/
|
||||
public close(): void {
|
||||
this.stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: これらのクラスを Stream クラスの内部クラスにすれば余計なメンバをpublicにしないで済むかも?
|
||||
// もしくは @internal を使う? https://www.typescriptlang.org/tsconfig#stripInternal
|
||||
class Pool {
|
||||
public channel: string;
|
||||
public id: string;
|
||||
protected stream: Stream;
|
||||
public users = 0;
|
||||
private disposeTimerId: any;
|
||||
private isConnected = false;
|
||||
|
||||
constructor(stream: Stream, channel: string, id: string) {
|
||||
this.channel = channel;
|
||||
this.stream = stream;
|
||||
this.id = id;
|
||||
|
||||
this.stream.on("_disconnected_", this.onStreamDisconnected);
|
||||
}
|
||||
|
||||
private onStreamDisconnected(): void {
|
||||
this.isConnected = false;
|
||||
}
|
||||
|
||||
public inc(): void {
|
||||
if (this.users === 0 && !this.isConnected) {
|
||||
this.connect();
|
||||
}
|
||||
|
||||
this.users++;
|
||||
|
||||
// タイマー解除
|
||||
if (this.disposeTimerId) {
|
||||
clearTimeout(this.disposeTimerId);
|
||||
this.disposeTimerId = null;
|
||||
}
|
||||
}
|
||||
|
||||
public dec(): void {
|
||||
this.users--;
|
||||
|
||||
// そのコネクションの利用者が誰もいなくなったら
|
||||
if (this.users === 0) {
|
||||
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
||||
// 新たな利用者が現れなければコネクションを切断する
|
||||
this.disposeTimerId = setTimeout(() => {
|
||||
this.disconnect();
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
public connect(): void {
|
||||
if (this.isConnected) return;
|
||||
this.isConnected = true;
|
||||
this.stream.send("connect", {
|
||||
channel: this.channel,
|
||||
id: this.id,
|
||||
});
|
||||
}
|
||||
|
||||
private disconnect(): void {
|
||||
this.stream.off("_disconnected_", this.onStreamDisconnected);
|
||||
this.stream.send("disconnect", { id: this.id });
|
||||
this.stream.removeSharedConnectionPool(this);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Connection<
|
||||
Channel extends AnyOf<Channels> = any,
|
||||
> extends EventEmitter<Channel["events"]> {
|
||||
public channel: string;
|
||||
protected stream: Stream;
|
||||
public abstract id: string;
|
||||
|
||||
public name?: string; // for debug
|
||||
public inCount = 0; // for debug
|
||||
public outCount = 0; // for debug
|
||||
|
||||
constructor(stream: Stream, channel: string, name?: string) {
|
||||
super();
|
||||
|
||||
this.stream = stream;
|
||||
this.channel = channel;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public send<T extends keyof Channel["receives"]>(
|
||||
type: T,
|
||||
body: Channel["receives"][T],
|
||||
): void {
|
||||
this.stream.send("ch", {
|
||||
id: this.id,
|
||||
type: type,
|
||||
body: body,
|
||||
});
|
||||
|
||||
this.outCount++;
|
||||
}
|
||||
|
||||
public abstract dispose(): void;
|
||||
}
|
||||
|
||||
class SharedConnection<
|
||||
Channel extends AnyOf<Channels> = any,
|
||||
> extends Connection<Channel> {
|
||||
private pool: Pool;
|
||||
|
||||
public get id(): string {
|
||||
return this.pool.id;
|
||||
}
|
||||
|
||||
constructor(stream: Stream, channel: string, pool: Pool, name?: string) {
|
||||
super(stream, channel, name);
|
||||
|
||||
this.pool = pool;
|
||||
this.pool.inc();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.pool.dec();
|
||||
this.removeAllListeners();
|
||||
this.stream.removeSharedConnection(this);
|
||||
}
|
||||
}
|
||||
|
||||
class NonSharedConnection<
|
||||
Channel extends AnyOf<Channels> = any,
|
||||
> extends Connection<Channel> {
|
||||
public id: string;
|
||||
protected params: Channel["params"];
|
||||
|
||||
constructor(
|
||||
stream: Stream,
|
||||
channel: string,
|
||||
id: string,
|
||||
params: Channel["params"],
|
||||
) {
|
||||
super(stream, channel);
|
||||
|
||||
this.params = params;
|
||||
this.id = id;
|
||||
|
||||
this.connect();
|
||||
}
|
||||
|
||||
public connect(): void {
|
||||
this.stream.send("connect", {
|
||||
channel: this.channel,
|
||||
id: this.id,
|
||||
params: this.params,
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.removeAllListeners();
|
||||
this.stream.send("disconnect", { id: this.id });
|
||||
this.stream.disconnectToChannel(this);
|
||||
}
|
||||
}
|
197
packages/client/src/iceshrimp-js/streaming.types.ts
Normal file
197
packages/client/src/iceshrimp-js/streaming.types.ts
Normal file
@ -0,0 +1,197 @@
|
||||
import type {
|
||||
Antenna,
|
||||
CustomEmoji,
|
||||
DriveFile,
|
||||
MeDetailed,
|
||||
MessagingMessage,
|
||||
Note,
|
||||
Notification,
|
||||
PageEvent,
|
||||
User,
|
||||
UserGroup,
|
||||
} from "./entities.js";
|
||||
|
||||
type FIXME = any;
|
||||
|
||||
export type Channels = {
|
||||
main: {
|
||||
params: null;
|
||||
events: {
|
||||
notification: (payload: Notification) => void;
|
||||
mention: (payload: Note) => void;
|
||||
reply: (payload: Note) => void;
|
||||
renote: (payload: Note) => void;
|
||||
follow: (payload: User) => void; // 自分が他人をフォローしたとき
|
||||
followed: (payload: User) => void; // 他人が自分をフォローしたとき
|
||||
unfollow: (payload: User) => void; // 自分が他人をフォロー解除したとき
|
||||
meUpdated: (payload: MeDetailed) => void;
|
||||
pageEvent: (payload: PageEvent) => void;
|
||||
urlUploadFinished: (payload: { marker: string; file: DriveFile }) => void;
|
||||
readAllNotifications: () => void;
|
||||
unreadNotification: (payload: Notification) => void;
|
||||
unreadMention: (payload: Note["id"]) => void;
|
||||
readAllUnreadMentions: () => void;
|
||||
unreadSpecifiedNote: (payload: Note["id"]) => void;
|
||||
readAllUnreadSpecifiedNotes: () => void;
|
||||
readAllMessagingMessages: () => void;
|
||||
messagingMessage: (payload: MessagingMessage) => void;
|
||||
unreadMessagingMessage: (payload: MessagingMessage) => void;
|
||||
readAllAntennas: () => void;
|
||||
unreadAntenna: (payload: Antenna) => void;
|
||||
readAllAnnouncements: () => void;
|
||||
readAllChannels: () => void;
|
||||
unreadChannel: (payload: Note["id"]) => void;
|
||||
myTokenRegenerated: () => void;
|
||||
reversiNoInvites: () => void;
|
||||
reversiInvited: (payload: FIXME) => void;
|
||||
signin: (payload: FIXME) => void;
|
||||
registryUpdated: (payload: {
|
||||
scope?: string[];
|
||||
key: string;
|
||||
value: any | null;
|
||||
}) => void;
|
||||
driveFileCreated: (payload: DriveFile) => void;
|
||||
readAntenna: (payload: Antenna) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
homeTimeline: {
|
||||
params: null;
|
||||
events: {
|
||||
note: (payload: Note) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
localTimeline: {
|
||||
params: null;
|
||||
events: {
|
||||
note: (payload: Note) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
hybridTimeline: {
|
||||
params: null;
|
||||
events: {
|
||||
note: (payload: Note) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
recommendedTimeline: {
|
||||
params: null;
|
||||
events: {
|
||||
note: (payload: Note) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
globalTimeline: {
|
||||
params: null;
|
||||
events: {
|
||||
note: (payload: Note) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
antenna: {
|
||||
params: {
|
||||
antennaId: Antenna["id"];
|
||||
};
|
||||
events: {
|
||||
note: (payload: Note) => void;
|
||||
};
|
||||
receives: null;
|
||||
};
|
||||
messaging: {
|
||||
params: {
|
||||
otherparty?: User["id"] | null;
|
||||
group?: UserGroup["id"] | null;
|
||||
};
|
||||
events: {
|
||||
message: (payload: MessagingMessage) => void;
|
||||
deleted: (payload: MessagingMessage["id"]) => void;
|
||||
read: (payload: MessagingMessage["id"][]) => void;
|
||||
typers: (payload: User[]) => void;
|
||||
};
|
||||
receives: {
|
||||
read: {
|
||||
id: MessagingMessage["id"];
|
||||
};
|
||||
};
|
||||
};
|
||||
serverStats: {
|
||||
params: null;
|
||||
events: {
|
||||
stats: (payload: FIXME) => void;
|
||||
};
|
||||
receives: {
|
||||
requestLog: {
|
||||
id: string | number;
|
||||
length: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
queueStats: {
|
||||
params: null;
|
||||
events: {
|
||||
stats: (payload: FIXME) => void;
|
||||
};
|
||||
receives: {
|
||||
requestLog: {
|
||||
id: string | number;
|
||||
length: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type NoteUpdatedEvent =
|
||||
| {
|
||||
id: Note["id"];
|
||||
type: "reacted";
|
||||
body: {
|
||||
reaction: string;
|
||||
userId: User["id"];
|
||||
};
|
||||
}
|
||||
| {
|
||||
id: Note["id"];
|
||||
type: "unreacted";
|
||||
body: {
|
||||
reaction: string;
|
||||
userId: User["id"];
|
||||
};
|
||||
}
|
||||
| {
|
||||
id: Note["id"];
|
||||
type: "deleted";
|
||||
body: {
|
||||
deletedAt: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
id: Note["id"];
|
||||
type: "pollVoted";
|
||||
body: {
|
||||
choice: number;
|
||||
userId: User["id"];
|
||||
};
|
||||
}
|
||||
| {
|
||||
id: Note["id"];
|
||||
type: "replied";
|
||||
body: {
|
||||
id: Note["id"];
|
||||
};
|
||||
}
|
||||
| {
|
||||
id: Note["id"];
|
||||
type: "updated";
|
||||
body: {
|
||||
updatedAt: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type BroadcastEvents = {
|
||||
noteUpdated: (payload: NoteUpdatedEvent) => void;
|
||||
emojiAdded: (payload: {
|
||||
emoji: CustomEmoji;
|
||||
}) => void;
|
||||
};
|
15
packages/client/src/index.html
Normal file
15
packages/client/src/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>[dev] Iceshrimp</title>
|
||||
|
||||
<link rel="stylesheet" href="./style.scss" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script> let exports = {}; </script>
|
||||
<script type="module" src="./init.ts"></script>
|
||||
</body>
|
||||
</html>
|
@ -32,10 +32,10 @@ import { compareVersions } from "compare-versions";
|
||||
import widgets from "@/widgets";
|
||||
import directives from "@/directives";
|
||||
import components from "@/components";
|
||||
import { version, ui, lang, setHost, setSearchEngine } from "@/config";
|
||||
import { version, ui, lang, setHost, setSearchEngine, updateLocale } from "@/config";
|
||||
import { applyTheme } from "@/scripts/theme";
|
||||
import { isDeviceDarkmode } from "@/scripts/is-device-darkmode";
|
||||
import { i18n } from "@/i18n";
|
||||
import { i18n, updateI18n } from "@/i18n";
|
||||
import { confirm, alert, post, popup, toast, api } from "@/os";
|
||||
import { stream } from "@/stream";
|
||||
import * as sound from "@/scripts/sound";
|
||||
@ -96,6 +96,23 @@ function checkForSplash() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#region Detect language & fetch translations
|
||||
const localeVersion = localStorage.getItem('localeVersion');
|
||||
const localeOutdated = (localeVersion == null || localeVersion !== version);
|
||||
if (localeOutdated) {
|
||||
const res = await window.fetch(`/assets/locales/${lang}.${version}.json`);
|
||||
if (res.status === 200) {
|
||||
const newLocale = await res.text();
|
||||
const parsedNewLocale = JSON.parse(newLocale);
|
||||
localStorage.setItem('locale', newLocale);
|
||||
localStorage.setItem('localeVersion', version);
|
||||
updateLocale(parsedNewLocale);
|
||||
updateI18n(parsedNewLocale);
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
// タッチデバイスでCSSの:hoverを機能させる
|
||||
document.addEventListener("touchend", () => {}, { passive: true });
|
||||
|
||||
@ -363,6 +380,10 @@ function checkForSplash() {
|
||||
JSON.parse(instance.defaultDarkTheme),
|
||||
);
|
||||
defaultStore.set("themeInitial", false);
|
||||
} else if (defaultStore.state.darkMode) {
|
||||
applyTheme(darkTheme.value);
|
||||
} else {
|
||||
applyTheme(lightTheme.value);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { computed, reactive } from "vue";
|
||||
import { api } from "./os";
|
||||
import type * as Misskey from "iceshrimp-js";
|
||||
import type * as Misskey from "@/iceshrimp-js";
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { Component, markRaw, Ref, ref, defineAsyncComponent } from "vue";
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import insertTextAtCursor from "insert-text-at-cursor";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import { apiUrl, url } from "@/config";
|
||||
import MkPostFormDialog from "@/components/MkPostFormDialog.vue";
|
||||
import MkWaitingDialog from "@/components/MkWaitingDialog.vue";
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import { version } from "@/config";
|
||||
import * as os from "@/os";
|
||||
|
@ -81,7 +81,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent } from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import MkInput from "@/components/form/input.vue";
|
||||
import MkSelect from "@/components/form/select.vue";
|
||||
|
@ -17,7 +17,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||
import * as os from "@/os";
|
||||
import { acct } from "@/filters/user";
|
||||
|
@ -46,7 +46,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import JSON5 from "json5";
|
||||
import { Endpoints } from "iceshrimp-js";
|
||||
import { Endpoints } from "@/iceshrimp-js";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import MkInput from "@/components/form/input.vue";
|
||||
import MkTextarea from "@/components/form/textarea.vue";
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, provide } from "vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import XNotes from "@/components/MkNotes.vue";
|
||||
import { $i } from "@/account";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import * as os from "@/os";
|
||||
import { mainRouter } from "@/router";
|
||||
import { i18n } from "@/i18n";
|
||||
|
@ -340,7 +340,7 @@
|
||||
import { watch } from "vue";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import type * as iceshrimp from "iceshrimp-js";
|
||||
import type * as iceshrimp from "@/iceshrimp-js";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
import MkObjectView from "@/components/MkObjectView.vue";
|
||||
import FormLink from "@/components/form/link.vue";
|
||||
|
@ -89,7 +89,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, markRaw, onMounted, onUnmounted, watch } from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
|
@ -56,7 +56,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, watch } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import autosize from "autosize";
|
||||
//import insertTextAtCursor from 'insert-text-at-cursor';
|
||||
import { throttle } from "throttle-debounce";
|
||||
|
@ -84,7 +84,7 @@
|
||||
<script lang="ts" setup>
|
||||
import {} from "vue";
|
||||
import * as mfm from "mfm-js";
|
||||
import type * as Misskey from "iceshrimp-js";
|
||||
import type * as Misskey from "@/iceshrimp-js";
|
||||
import XMediaList from "@/components/MkMediaList.vue";
|
||||
import { extractUrlFromMfm } from "@/scripts/extract-url-from-mfm";
|
||||
import MkUrlPreview from "@/components/MkUrlPreview.vue";
|
||||
|
@ -98,8 +98,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, onMounted, nextTick, onBeforeUnmount } from "vue";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import XMessage from "./messaging-room.message.vue";
|
||||
import XForm from "./messaging-room.form.vue";
|
||||
import XList from "@/components/MkDateSeparatedList.vue";
|
||||
|
@ -115,7 +115,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import MkInput from "@/components/form/input.vue";
|
||||
import MkTextarea from "@/components/form/textarea.vue";
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineComponent, watch } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XNoteDetailed from "@/components/MkNoteDetailed.vue";
|
||||
import XNotes from "@/components/MkNotes.vue";
|
||||
import MkRemoteCaution from "@/components/MkRemoteCaution.vue";
|
||||
|
@ -54,7 +54,7 @@
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import { notificationTypes } from "iceshrimp-js";
|
||||
import { notificationTypes } from "@/iceshrimp-js";
|
||||
import XNotifications from "@/components/MkNotifications.vue";
|
||||
import XNotes from "@/components/MkNotes.vue";
|
||||
import * as os from "@/os";
|
||||
|
@ -378,6 +378,7 @@ watch(swipeOnDesktop, () => {
|
||||
watch(lang, () => {
|
||||
localStorage.setItem("lang", lang.value as string);
|
||||
localStorage.removeItem("locale");
|
||||
localStorage.removeItem('localeVersion');
|
||||
});
|
||||
|
||||
watch(fontSize, () => {
|
||||
|
@ -59,7 +59,7 @@ import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
import { $i } from "@/account";
|
||||
import { toString } from "iceshrimp-js/built/acct";
|
||||
import { Acct } from "@/iceshrimp-js";
|
||||
|
||||
let moveToAccount = $ref("");
|
||||
let accountAlias = $ref([""]);
|
||||
@ -71,7 +71,7 @@ async function init() {
|
||||
const aka = await os.api("users/show", { userIds: $i.alsoKnownAs });
|
||||
accountAlias =
|
||||
aka && aka.length > 0
|
||||
? aka.map((user) => `@${toString(user)}`)
|
||||
? aka.map((user) => `@${Acct.toString(user)}`)
|
||||
: [""];
|
||||
} else {
|
||||
accountAlias = [""];
|
||||
|
@ -50,7 +50,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent } from "vue";
|
||||
import { notificationTypes } from "iceshrimp-js";
|
||||
import { notificationTypes } from "@/iceshrimp-js";
|
||||
import FormButton from "@/components/MkButton.vue";
|
||||
import FormLink from "@/components/form/link.vue";
|
||||
import FormSection from "@/components/form/section.vue";
|
||||
|
@ -33,9 +33,9 @@
|
||||
// SPECIFICATION: https://misskey-hub.net/docs/features/share-form.html
|
||||
|
||||
import {} from "vue";
|
||||
import { noteVisibilities } from "iceshrimp-js";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import * as Misskey from "iceshrimp-js";
|
||||
import { noteVisibilities } from "@/iceshrimp-js";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import * as Misskey from "@/iceshrimp-js";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import XPostForm from "@/components/MkPostForm.vue";
|
||||
import * as os from "@/os";
|
||||
|
@ -340,7 +340,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
import MkObjectView from "@/components/MkObjectView.vue";
|
||||
import FormTextarea from "@/components/form/textarea.vue";
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkUserInfo from "@/components/MkUserInfo.vue";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
|
||||
|
@ -24,8 +24,8 @@ import {
|
||||
onUnmounted,
|
||||
watch,
|
||||
} from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XFollowList from "./follow-list.vue";
|
||||
import * as os from "@/os";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
|
@ -24,8 +24,8 @@ import {
|
||||
onUnmounted,
|
||||
watch,
|
||||
} from "vue";
|
||||
import * as Acct from "iceshrimp-js/built/acct";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import { Acct } from "@/iceshrimp-js"
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import XFollowList from "./follow-list.vue";
|
||||
import * as os from "@/os";
|
||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as misskey from "@/iceshrimp-js";
|
||||
import MkGalleryPostPreview from "@/components/MkGalleryPostPreview.vue";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
|
||||
|
@ -365,7 +365,7 @@ import { defineAsyncComponent, onMounted, onUnmounted } from "vue";
|
||||
import calcAge from "s-age";
|
||||
import cityTimezones from "city-timezones";
|
||||
import XUserTimeline from "./index.timeline.vue";
|
||||
import type * as misskey from "iceshrimp-js";
|
||||
import type * as misskey from "@/iceshrimp-js";
|
||||
import XNote from "@/components/MkNote.vue";
|
||||
import MkFollowButton from "@/components/MkFollowButton.vue";
|
||||
import MkRemoteCaution from "@/components/MkRemoteCaution.vue";
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user