diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue
index 46bcd42558..f8d3d810b7 100644
--- a/packages/client/src/components/drive.vue
+++ b/packages/client/src/components/drive.vue
@@ -53,6 +53,7 @@ import XFolder from './drive.folder.vue';
 import XFile from './drive.file.vue';
 import MkButton from './ui/button.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 export default defineComponent({
 	components: {
@@ -140,7 +141,7 @@ export default defineComponent({
 			});
 		}
 
-		this.connection = markRaw(os.stream.useChannel('drive'));
+		this.connection = markRaw(stream.useChannel('drive'));
 
 		this.connection.on('fileCreated', this.onStreamDriveFileCreated);
 		this.connection.on('fileUpdated', this.onStreamDriveFileUpdated);
diff --git a/packages/client/src/components/follow-button.vue b/packages/client/src/components/follow-button.vue
index 7136261914..b16b22f26f 100644
--- a/packages/client/src/components/follow-button.vue
+++ b/packages/client/src/components/follow-button.vue
@@ -30,6 +30,7 @@
 <script lang="ts">
 import { defineComponent, markRaw } from 'vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 export default defineComponent({
 	props: {
@@ -71,7 +72,7 @@ export default defineComponent({
 	},
 
 	mounted() {
-		this.connection = markRaw(os.stream.useChannel('main'));
+		this.connection = markRaw(stream.useChannel('main'));
 
 		this.connection.on('follow', this.onFollowChange);
 		this.connection.on('unfollow', this.onFollowChange);
diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue
index 55a02f1e73..a5cb2f0426 100644
--- a/packages/client/src/components/note-detailed.vue
+++ b/packages/client/src/components/note-detailed.vue
@@ -140,6 +140,7 @@ import { checkWordMute } from '@/scripts/check-word-mute';
 import { userPage } from '@/filters/user';
 import { notePage } from '@/filters/note';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { noteActions, noteViewInterruptors } from '@/store';
 import { reactionPicker } from '@/scripts/reaction-picker';
 import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
@@ -260,7 +261,7 @@ export default defineComponent({
 
 	async created() {
 		if (this.$i) {
-			this.connection = os.stream;
+			this.connection = stream;
 		}
 
 		this.muted = await checkWordMute(this.appearNote, this.$i, this.$store.state.mutedWords);
diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue
index c4040388a9..3cf924928a 100644
--- a/packages/client/src/components/note.vue
+++ b/packages/client/src/components/note.vue
@@ -122,6 +122,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
 import { checkWordMute } from '@/scripts/check-word-mute';
 import { userPage } from '@/filters/user';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { noteActions, noteViewInterruptors } from '@/store';
 import { reactionPicker } from '@/scripts/reaction-picker';
 import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
@@ -245,7 +246,7 @@ export default defineComponent({
 
 	async created() {
 		if (this.$i) {
-			this.connection = os.stream;
+			this.connection = stream;
 		}
 
 		this.collapsed = this.appearNote.cw == null && this.appearNote.text && (
diff --git a/packages/client/src/components/notification.vue b/packages/client/src/components/notification.vue
index 37a88edc64..5659c899be 100644
--- a/packages/client/src/components/notification.vue
+++ b/packages/client/src/components/notification.vue
@@ -74,6 +74,7 @@ import { notePage } from '@/filters/note';
 import { userPage } from '@/filters/user';
 import { i18n } from '@/i18n';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { useTooltip } from '@/scripts/use-tooltip';
 
 export default defineComponent({
@@ -106,7 +107,7 @@ export default defineComponent({
 			if (!props.notification.isRead) {
 				const readObserver = new IntersectionObserver((entries, observer) => {
 					if (!entries.some(entry => entry.isIntersecting)) return;
-					os.stream.send('readNotification', {
+					stream.send('readNotification', {
 						id: props.notification.id
 					});
 					observer.disconnect();
@@ -114,7 +115,7 @@ export default defineComponent({
 
 				readObserver.observe(elRef.value);
 
-				const connection = os.stream.useChannel('main');
+				const connection = stream.useChannel('main');
 				connection.on('readAllNotifications', () => readObserver.disconnect());
 
 				onUnmounted(() => {
diff --git a/packages/client/src/components/notifications.vue b/packages/client/src/components/notifications.vue
index f3e5ee32f7..328888c355 100644
--- a/packages/client/src/components/notifications.vue
+++ b/packages/client/src/components/notifications.vue
@@ -28,6 +28,7 @@ import XList from './date-separated-list.vue';
 import XNote from './note.vue';
 import { notificationTypes } from 'misskey-js';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import MkButton from '@/components/ui/button.vue';
 
 export default defineComponent({
@@ -100,7 +101,7 @@ export default defineComponent({
 	},
 
 	mounted() {
-		this.connection = markRaw(os.stream.useChannel('main'));
+		this.connection = markRaw(stream.useChannel('main'));
 		this.connection.on('notification', this.onNotification);
 	},
 
@@ -112,7 +113,7 @@ export default defineComponent({
 		onNotification(notification) {
 			const isMuted = !this.allIncludeTypes.includes(notification.type);
 			if (isMuted || document.visibilityState === 'visible') {
-				os.stream.send('readNotification', {
+				stream.send('readNotification', {
 					id: notification.id
 				});
 			}
diff --git a/packages/client/src/components/post-form.vue b/packages/client/src/components/post-form.vue
index 4265c575e2..24f35da2e9 100644
--- a/packages/client/src/components/post-form.vue
+++ b/packages/client/src/components/post-form.vue
@@ -74,11 +74,11 @@ import { formatTimeString } from '@/scripts/format-time-string';
 import { Autocomplete } from '@/scripts/autocomplete';
 import { noteVisibilities } from 'misskey-js';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { selectFiles } from '@/scripts/select-file';
 import { defaultStore, notePostInterruptors, postFormActions } from '@/store';
 import { throttle } from 'throttle-debounce';
 import MkInfo from '@/components/ui/info.vue';
-import { defaultStore } from '@/store';
 
 export default defineComponent({
 	components: {
@@ -176,7 +176,7 @@ export default defineComponent({
 			imeText: '',
 			typing: throttle(3000, () => {
 				if (this.channel) {
-					os.stream.send('typingOnChannel', { channel: this.channel.id });
+					stream.send('typingOnChannel', { channel: this.channel.id });
 				}
 			}),
 			postFormActions,
diff --git a/packages/client/src/components/taskmanager.vue b/packages/client/src/components/taskmanager.vue
index 6901d88c2c..c5d2c6d8f8 100644
--- a/packages/client/src/components/taskmanager.vue
+++ b/packages/client/src/components/taskmanager.vue
@@ -83,6 +83,7 @@ import MkTab from '@/components/tab.vue';
 import MkButton from '@/components/ui/button.vue';
 import follow from '@/directives/follow-append';
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 export default defineComponent({
 	components: {
@@ -104,15 +105,15 @@ export default defineComponent({
 		const connections = shallowRef([]);
 		const pools = shallowRef([]);
 		const refreshStreamInfo = () => {
-			console.log(os.stream.sharedConnectionPools, os.stream.sharedConnections, os.stream.nonSharedConnections);
-			const conn = os.stream.sharedConnections.map(c => ({
+			console.log(stream.sharedConnectionPools, stream.sharedConnections, stream.nonSharedConnections);
+			const conn = stream.sharedConnections.map(c => ({
 				id: c.id, name: c.name, channel: c.channel, users: c.pool.users, in: c.inCount, out: c.outCount,
-			})).concat(os.stream.nonSharedConnections.map(c => ({
+			})).concat(stream.nonSharedConnections.map(c => ({
 				id: c.id, name: c.name, channel: c.channel, users: null, in: c.inCount, out: c.outCount,
 			})));
 			conn.sort((a, b) => (a.id > b.id) ? 1 : -1);
 			connections.value = conn;
-			pools.value = os.stream.sharedConnectionPools;
+			pools.value = stream.sharedConnectionPools;
 		};
 		const interval = setInterval(refreshStreamInfo, 1000);
 		onBeforeUnmount(() => {
diff --git a/packages/client/src/components/timeline.vue b/packages/client/src/components/timeline.vue
index f8a800872f..53697671b2 100644
--- a/packages/client/src/components/timeline.vue
+++ b/packages/client/src/components/timeline.vue
@@ -6,6 +6,7 @@
 import { defineComponent, markRaw } from 'vue';
 import XNotes from './notes.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as sound from '@/scripts/sound';
 
 export default defineComponent({
@@ -92,33 +93,33 @@ export default defineComponent({
 			this.query = {
 				antennaId: this.antenna
 			};
-			this.connection = markRaw(os.stream.useChannel('antenna', {
+			this.connection = markRaw(stream.useChannel('antenna', {
 				antennaId: this.antenna
 			}));
 			this.connection.on('note', prepend);
 		} else if (this.src == 'home') {
 			endpoint = 'notes/timeline';
-			this.connection = markRaw(os.stream.useChannel('homeTimeline'));
+			this.connection = markRaw(stream.useChannel('homeTimeline'));
 			this.connection.on('note', prepend);
 
-			this.connection2 = markRaw(os.stream.useChannel('main'));
+			this.connection2 = markRaw(stream.useChannel('main'));
 			this.connection2.on('follow', onChangeFollowing);
 			this.connection2.on('unfollow', onChangeFollowing);
 		} else if (this.src == 'local') {
 			endpoint = 'notes/local-timeline';
-			this.connection = markRaw(os.stream.useChannel('localTimeline'));
+			this.connection = markRaw(stream.useChannel('localTimeline'));
 			this.connection.on('note', prepend);
 		} else if (this.src == 'social') {
 			endpoint = 'notes/hybrid-timeline';
-			this.connection = markRaw(os.stream.useChannel('hybridTimeline'));
+			this.connection = markRaw(stream.useChannel('hybridTimeline'));
 			this.connection.on('note', prepend);
 		} else if (this.src == 'global') {
 			endpoint = 'notes/global-timeline';
-			this.connection = markRaw(os.stream.useChannel('globalTimeline'));
+			this.connection = markRaw(stream.useChannel('globalTimeline'));
 			this.connection.on('note', prepend);
 		} else if (this.src == 'mentions') {
 			endpoint = 'notes/mentions';
-			this.connection = markRaw(os.stream.useChannel('main'));
+			this.connection = markRaw(stream.useChannel('main'));
 			this.connection.on('mention', prepend);
 		} else if (this.src == 'directs') {
 			endpoint = 'notes/mentions';
@@ -130,14 +131,14 @@ export default defineComponent({
 					prepend(note);
 				}
 			};
-			this.connection = markRaw(os.stream.useChannel('main'));
+			this.connection = markRaw(stream.useChannel('main'));
 			this.connection.on('mention', onNote);
 		} else if (this.src == 'list') {
 			endpoint = 'notes/user-list-timeline';
 			this.query = {
 				listId: this.list
 			};
-			this.connection = markRaw(os.stream.useChannel('userList', {
+			this.connection = markRaw(stream.useChannel('userList', {
 				listId: this.list
 			}));
 			this.connection.on('note', prepend);
@@ -148,7 +149,7 @@ export default defineComponent({
 			this.query = {
 				channelId: this.channel
 			};
-			this.connection = markRaw(os.stream.useChannel('channel', {
+			this.connection = markRaw(stream.useChannel('channel', {
 				channelId: this.channel
 			}));
 			this.connection.on('note', prepend);
diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts
index 4ed69e0ec0..1ea205d5c8 100644
--- a/packages/client/src/os.ts
+++ b/packages/client/src/os.ts
@@ -12,8 +12,6 @@ import { resolve } from '@/router';
 import { $i } from '@/account';
 import { defaultStore } from '@/store';
 
-export const stream = markRaw(new Misskey.Stream(url, $i));
-
 export const pendingApiRequestsCount = ref(0);
 let apiRequestsCount = 0; // for debug
 export const apiRequests = ref([]); // for debug
diff --git a/packages/client/src/pages/admin/metrics.vue b/packages/client/src/pages/admin/metrics.vue
index 05b64b235c..f566061ceb 100644
--- a/packages/client/src/pages/admin/metrics.vue
+++ b/packages/client/src/pages/admin/metrics.vue
@@ -101,6 +101,7 @@ const alpha = (hex, a) => {
 	return `rgba(${r}, ${g}, ${b}, ${a})`;
 };
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 export default defineComponent({
 	components: {
@@ -119,7 +120,7 @@ export default defineComponent({
 			stats: null,
 			serverInfo: null,
 			connection: null,
-			queueConnection: markRaw(os.stream.useChannel('queueStats')),
+			queueConnection: markRaw(stream.useChannel('queueStats')),
 			memUsage: 0,
 			chartCpuMem: null,
 			chartNet: null,
@@ -150,7 +151,7 @@ export default defineComponent({
 		os.api('admin/server-info', {}).then(res => {
 			this.serverInfo = res;
 
-			this.connection = markRaw(os.stream.useChannel('serverStats'));
+			this.connection = markRaw(stream.useChannel('serverStats'));
 			this.connection.on('stats', this.onStats);
 			this.connection.on('statsLog', this.onStatsLog);
 			this.connection.send('requestLog', {
diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue
index da5fc0ba6d..59a4281599 100644
--- a/packages/client/src/pages/admin/overview.vue
+++ b/packages/client/src/pages/admin/overview.vue
@@ -81,6 +81,7 @@ import number from '@/filters/number';
 import MkInstanceInfo from './instance.vue';
 import XMetrics from './metrics.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as symbols from '@/symbols';
 
 export default defineComponent({
@@ -113,7 +114,7 @@ export default defineComponent({
 			notesComparedToThePrevDay: null,
 			fetchJobs: () => os.api('admin/queue/deliver-delayed', {}),
 			fetchModLogs: () => os.api('admin/show-moderation-logs', {}),
-			queueStatsConnection: markRaw(os.stream.useChannel('queueStats')),
+			queueStatsConnection: markRaw(stream.useChannel('queueStats')),
 		}
 	},
 
diff --git a/packages/client/src/pages/admin/queue.vue b/packages/client/src/pages/admin/queue.vue
index 37a87089cb..49f3c63e82 100644
--- a/packages/client/src/pages/admin/queue.vue
+++ b/packages/client/src/pages/admin/queue.vue
@@ -17,6 +17,7 @@ import XQueue from './queue.chart.vue';
 import FormBase from '@/components/debobigego/base.vue';
 import FormButton from '@/components/debobigego/button.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as symbols from '@/symbols';
 
 export default defineComponent({
@@ -36,7 +37,7 @@ export default defineComponent({
 				icon: 'fas fa-clipboard-list',
 				bg: 'var(--bg)',
 			},
-			connection: markRaw(os.stream.useChannel('queueStats')),
+			connection: markRaw(stream.useChannel('queueStats')),
 		}
 	},
 
diff --git a/packages/client/src/pages/messaging/index.vue b/packages/client/src/pages/messaging/index.vue
index 01f9d4518f..554ebc4b6b 100644
--- a/packages/client/src/pages/messaging/index.vue
+++ b/packages/client/src/pages/messaging/index.vue
@@ -44,6 +44,7 @@ import * as Acct from 'misskey-js/built/acct';
 import MkButton from '@/components/ui/button.vue';
 import { acct } from '@/filters/user';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as symbols from '@/symbols';
 
 export default defineComponent({
@@ -66,7 +67,7 @@ export default defineComponent({
 	},
 
 	mounted() {
-		this.connection = markRaw(os.stream.useChannel('messagingIndex'));
+		this.connection = markRaw(stream.useChannel('messagingIndex'));
 
 		this.connection.on('message', this.onMessage);
 		this.connection.on('read', this.onRead);
diff --git a/packages/client/src/pages/messaging/messaging-room.form.vue b/packages/client/src/pages/messaging/messaging-room.form.vue
index 8d92c430f1..f2a90fbfba 100644
--- a/packages/client/src/pages/messaging/messaging-room.form.vue
+++ b/packages/client/src/pages/messaging/messaging-room.form.vue
@@ -28,6 +28,7 @@ import * as autosize from 'autosize';
 import { formatTimeString } from '@/scripts/format-time-string';
 import { selectFile } from '@/scripts/select-file';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { Autocomplete } from '@/scripts/autocomplete';
 import { throttle } from 'throttle-debounce';
 
@@ -48,7 +49,7 @@ export default defineComponent({
 			file: null,
 			sending: false,
 			typing: throttle(3000, () => {
-				os.stream.send('typingOnMessaging', this.user ? { partner: this.user.id } : { group: this.group.id });
+				stream.send('typingOnMessaging', this.user ? { partner: this.user.id } : { group: this.group.id });
 			}),
 		};
 	},
diff --git a/packages/client/src/pages/messaging/messaging-room.vue b/packages/client/src/pages/messaging/messaging-room.vue
index ffc7f7bc0d..1bcee01d29 100644
--- a/packages/client/src/pages/messaging/messaging-room.vue
+++ b/packages/client/src/pages/messaging/messaging-room.vue
@@ -43,6 +43,7 @@ import XForm from './messaging-room.form.vue';
 import * as Acct from 'misskey-js/built/acct';
 import { isBottom, onScrollBottom, scroll } from '@/scripts/scroll';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { popout } from '@/scripts/popout';
 import * as sound from '@/scripts/sound';
 import * as symbols from '@/symbols';
@@ -141,7 +142,7 @@ const Component = defineComponent({
 				this.group = group;
 			}
 
-			this.connection = markRaw(os.stream.useChannel('messaging', {
+			this.connection = markRaw(stream.useChannel('messaging', {
 				otherparty: this.user ? this.user.id : undefined,
 				group: this.group ? this.group.id : undefined,
 			}));
diff --git a/packages/client/src/pages/reversi/game.vue b/packages/client/src/pages/reversi/game.vue
index b1ed632904..697d2898b9 100644
--- a/packages/client/src/pages/reversi/game.vue
+++ b/packages/client/src/pages/reversi/game.vue
@@ -9,6 +9,7 @@ import { defineComponent, markRaw } from 'vue';
 import GameSetting from './game.setting.vue';
 import GameBoard from './game.board.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as symbols from '@/symbols';
 
 export default defineComponent({
@@ -61,7 +62,7 @@ export default defineComponent({
 				if (this.connection) {
 					this.connection.dispose();
 				}
-				this.connection = markRaw(os.stream.useChannel('gamesReversiGame', {
+				this.connection = markRaw(stream.useChannel('gamesReversiGame', {
 					gameId: this.game.id
 				}));
 				this.connection.on('started', this.onStarted);
diff --git a/packages/client/src/pages/reversi/index.vue b/packages/client/src/pages/reversi/index.vue
index 0b118531fc..93c22c02f3 100644
--- a/packages/client/src/pages/reversi/index.vue
+++ b/packages/client/src/pages/reversi/index.vue
@@ -62,6 +62,7 @@
 <script lang="ts">
 import { defineComponent, markRaw } from 'vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import MkButton from '@/components/ui/button.vue';
 import MkFolder from '@/components/ui/folder.vue';
 import * as symbols from '@/symbols';
@@ -92,7 +93,7 @@ export default defineComponent({
 
 	mounted() {
 		if (this.$i) {
-			this.connection = markRaw(os.stream.useChannel('gamesReversi'));
+			this.connection = markRaw(stream.useChannel('gamesReversi'));
 
 			this.connection.on('invited', this.onInvited);
 
diff --git a/packages/client/src/pizzax.ts b/packages/client/src/pizzax.ts
index 8a742e85fe..0611599a29 100644
--- a/packages/client/src/pizzax.ts
+++ b/packages/client/src/pizzax.ts
@@ -1,6 +1,7 @@
 import { onUnmounted, Ref, ref, watch } from 'vue';
 import { $i } from './account';
-import { api, stream } from './os';
+import { api } from './os';
+import { stream } from './stream';
 
 type StateDef = Record<string, {
 	where: 'account' | 'device' | 'deviceAccount';
@@ -70,21 +71,20 @@ export class Storage<T extends StateDef> {
 					}
 					localStorage.setItem(this.keyForLocalStorage + '::cache::' + $i.id, JSON.stringify(cache));
 				});
-
-				// streamingのuser storage updateイベントを監視して更新
-				this.connection.on('registryUpdated', ({ scope, key, value }: { scope: string[], key: keyof T, value: T[typeof key]['default'] }) => {
-					if (scope[1] !== this.key || this.state[key] === value) return;
-
-					this.state[key] = value;
-					this.reactiveState[key].value = value;
-
-					const cache = JSON.parse(localStorage.getItem(this.keyForLocalStorage + '::cache::' + $i.id) || '{}');
-					if (cache[key] !== value) {
-						cache[key] = value;
-						localStorage.setItem(this.keyForLocalStorage + '::cache::' + $i.id, JSON.stringify(cache));
-					}
-				});
 			}, 1);
+			// streamingのuser storage updateイベントを監視して更新
+			this.connection.on('registryUpdated', ({ scope, key, value }: { scope: string[], key: keyof T, value: T[typeof key]['default'] }) => {
+				if (scope[1] !== this.key || this.state[key] === value) return;
+
+				this.state[key] = value;
+				this.reactiveState[key].value = value;
+
+				const cache = JSON.parse(localStorage.getItem(this.keyForLocalStorage + '::cache::' + $i.id) || '{}');
+				if (cache[key] !== value) {
+					cache[key] = value;
+					localStorage.setItem(this.keyForLocalStorage + '::cache::' + $i.id, JSON.stringify(cache));
+				}
+			});
 		}
 	}
 
diff --git a/packages/client/src/scripts/select-file.ts b/packages/client/src/scripts/select-file.ts
index 6019890444..6bb3f8bf8a 100644
--- a/packages/client/src/scripts/select-file.ts
+++ b/packages/client/src/scripts/select-file.ts
@@ -1,4 +1,5 @@
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { i18n } from '@/i18n';
 import { defaultStore } from '@/store';
 import { DriveFile } from 'misskey-js/built/entities';
@@ -48,7 +49,7 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv
 
 				const marker = Math.random().toString(); // TODO: UUIDとか使う
 
-				const connection = os.stream.useChannel('main');
+				const connection = stream.useChannel('main');
 				connection.on('urlUploadFinished', data => {
 					if (data.marker === marker) {
 						res(multiple ? [data.file] : data.file);
diff --git a/packages/client/src/stream.ts b/packages/client/src/stream.ts
new file mode 100644
index 0000000000..10502444b6
--- /dev/null
+++ b/packages/client/src/stream.ts
@@ -0,0 +1,6 @@
+import * as Misskey from 'misskey-js';
+import { markRaw } from 'vue';
+import { $i } from '@/account';
+import { url } from '@/config';
+
+export const stream = markRaw(new Misskey.Stream(url, $i));
diff --git a/packages/client/src/ui/_common_/stream-indicator.vue b/packages/client/src/ui/_common_/stream-indicator.vue
index 3f86f94549..c75c6d1c0a 100644
--- a/packages/client/src/ui/_common_/stream-indicator.vue
+++ b/packages/client/src/ui/_common_/stream-indicator.vue
@@ -11,6 +11,7 @@
 <script lang="ts">
 import { defineComponent } from 'vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 export default defineComponent({
 	data() {
@@ -20,14 +21,14 @@ export default defineComponent({
 	},
 	computed: {
 		stream() {
-			return os.stream;
+			return stream;
 		},
 	},
 	created() {
-		os.stream.on('_disconnected_', this.onDisconnected);
+		stream.on('_disconnected_', this.onDisconnected);
 	},
 	beforeUnmount() {
-		os.stream.off('_disconnected_', this.onDisconnected);
+		stream.off('_disconnected_', this.onDisconnected);
 	},
 	methods: {
 		onDisconnected() {
diff --git a/packages/client/src/ui/chat/note.vue b/packages/client/src/ui/chat/note.vue
index 6927dd0eaf..fa5faa4ec3 100644
--- a/packages/client/src/ui/chat/note.vue
+++ b/packages/client/src/ui/chat/note.vue
@@ -118,6 +118,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
 import { checkWordMute } from '@/scripts/check-word-mute';
 import { userPage } from '@/filters/user';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { noteActions, noteViewInterruptors } from '@/store';
 import { reactionPicker } from '@/scripts/reaction-picker';
 import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
@@ -243,7 +244,7 @@ export default defineComponent({
 
 	async created() {
 		if (this.$i) {
-			this.connection = os.stream;
+			this.connection = stream;
 		}
 
 		this.collapsed = this.appearNote.cw == null && this.appearNote.text && (
diff --git a/packages/client/src/ui/chat/pages/channel.vue b/packages/client/src/ui/chat/pages/channel.vue
index 13c735cd47..2755cc92b7 100644
--- a/packages/client/src/ui/chat/pages/channel.vue
+++ b/packages/client/src/ui/chat/pages/channel.vue
@@ -26,6 +26,7 @@ import { computed, defineComponent, markRaw } from 'vue';
 import * as Misskey from 'misskey-js';
 import XNotes from '../notes.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as sound from '@/scripts/sound';
 import { scrollToBottom, getScrollPosition, getScrollContainer } from '@/scripts/scroll';
 import follow from '@/directives/follow-append';
@@ -106,7 +107,7 @@ export default defineComponent({
 			sound.play(note.userId === this.$i.id ? 'noteMy' : 'note');
 		};
 
-		this.connection = markRaw(os.stream.useChannel('channel', {
+		this.connection = markRaw(stream.useChannel('channel', {
 			channelId: this.channelId
 		}));
 		this.connection.on('note', prepend);
diff --git a/packages/client/src/ui/chat/pages/timeline.vue b/packages/client/src/ui/chat/pages/timeline.vue
index 07e847ad73..f67d333398 100644
--- a/packages/client/src/ui/chat/pages/timeline.vue
+++ b/packages/client/src/ui/chat/pages/timeline.vue
@@ -17,6 +17,7 @@
 import { computed, defineComponent, markRaw } from 'vue';
 import XNotes from '../notes.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import * as sound from '@/scripts/sound';
 import { scrollToBottom, getScrollPosition, getScrollContainer } from '@/scripts/scroll';
 import follow from '@/directives/follow-append';
@@ -90,23 +91,23 @@ export default defineComponent({
 
 		if (this.src == 'home') {
 			endpoint = 'notes/timeline';
-			this.connection = markRaw(os.stream.useChannel('homeTimeline'));
+			this.connection = markRaw(stream.useChannel('homeTimeline'));
 			this.connection.on('note', prepend);
 
-			this.connection2 = markRaw(os.stream.useChannel('main'));
+			this.connection2 = markRaw(stream.useChannel('main'));
 			this.connection2.on('follow', onChangeFollowing);
 			this.connection2.on('unfollow', onChangeFollowing);
 		} else if (this.src == 'local') {
 			endpoint = 'notes/local-timeline';
-			this.connection = markRaw(os.stream.useChannel('localTimeline'));
+			this.connection = markRaw(stream.useChannel('localTimeline'));
 			this.connection.on('note', prepend);
 		} else if (this.src == 'social') {
 			endpoint = 'notes/hybrid-timeline';
-			this.connection = markRaw(os.stream.useChannel('hybridTimeline'));
+			this.connection = markRaw(stream.useChannel('hybridTimeline'));
 			this.connection.on('note', prepend);
 		} else if (this.src == 'global') {
 			endpoint = 'notes/global-timeline';
-			this.connection = markRaw(os.stream.useChannel('globalTimeline'));
+			this.connection = markRaw(stream.useChannel('globalTimeline'));
 			this.connection.on('note', prepend);
 		}
 
diff --git a/packages/client/src/ui/chat/post-form.vue b/packages/client/src/ui/chat/post-form.vue
index 8c572e3b1c..0f04096653 100644
--- a/packages/client/src/ui/chat/post-form.vue
+++ b/packages/client/src/ui/chat/post-form.vue
@@ -59,6 +59,7 @@ import * as Acct from 'misskey-js/built/acct';
 import { formatTimeString } from '@/scripts/format-time-string';
 import { Autocomplete } from '@/scripts/autocomplete';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import { selectFiles } from '@/scripts/select-file';
 import { notePostInterruptors, postFormActions } from '@/store';
 import { throttle } from 'throttle-debounce';
@@ -130,7 +131,7 @@ export default defineComponent({
 			imeText: '',
 			typing: throttle(3000, () => {
 				if (this.channel) {
-					os.stream.send('typingOnChannel', { channel: this.channel });
+					stream.send('typingOnChannel', { channel: this.channel });
 				}
 			}),
 			postFormActions,
diff --git a/packages/client/src/widgets/job-queue.vue b/packages/client/src/widgets/job-queue.vue
index ef440881e5..1b7c71de67 100644
--- a/packages/client/src/widgets/job-queue.vue
+++ b/packages/client/src/widgets/job-queue.vue
@@ -49,6 +49,7 @@
 import { defineComponent, markRaw } from 'vue';
 import define from './define';
 import * as os from '@/os';
+import { stream } from '@/stream';
 import number from '@/filters/number';
 import * as sound from '@/scripts/sound';
 
@@ -70,7 +71,7 @@ export default defineComponent({
 	extends: widget,
 	data() {
 		return {
-			connection: markRaw(os.stream.useChannel('queueStats')),
+			connection: markRaw(stream.useChannel('queueStats')),
 			inbox: {
 				activeSincePrevTick: 0,
 				active: 0,
diff --git a/packages/client/src/widgets/photos.vue b/packages/client/src/widgets/photos.vue
index a91d4f6c49..7a0b54027b 100644
--- a/packages/client/src/widgets/photos.vue
+++ b/packages/client/src/widgets/photos.vue
@@ -20,6 +20,7 @@ import MkContainer from '@/components/ui/container.vue';
 import define from './define';
 import { getStaticImageUrl } from '@/scripts/get-static-image-url';
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 const widget = define({
 	name: 'photos',
@@ -48,7 +49,7 @@ export default defineComponent({
 		};
 	},
 	mounted() {
-		this.connection = markRaw(os.stream.useChannel('main'));
+		this.connection = markRaw(stream.useChannel('main'));
 
 		this.connection.on('driveFileCreated', this.onDriveFileCreated);
 
diff --git a/packages/client/src/widgets/server-metric/index.vue b/packages/client/src/widgets/server-metric/index.vue
index 019e16fb33..107b750906 100644
--- a/packages/client/src/widgets/server-metric/index.vue
+++ b/packages/client/src/widgets/server-metric/index.vue
@@ -23,6 +23,7 @@ import XCpu from './cpu.vue';
 import XMemory from './mem.vue';
 import XDisk from './disk.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
 
 const widget = define({
 	name: 'serverMetric',
@@ -63,7 +64,7 @@ export default defineComponent({
 		os.api('server-info', {}).then(res => {
 			this.meta = res;
 		});
-		this.connection = markRaw(os.stream.useChannel('serverStats'));
+		this.connection = markRaw(stream.useChannel('serverStats'));
 	},
 	unmounted() {
 		this.connection.dispose();