mirror of
https://github.com/SrIzan10/helium.git
synced 2026-06-06 00:56:58 +00:00
feat: screensharing working on chrome
This commit is contained in:
@@ -6,28 +6,22 @@ import { toast } from 'vue-sonner';
|
||||
|
||||
const viewerStore = useViewerStore()
|
||||
const { code: codeRef } = storeToRefs(viewerStore)
|
||||
const { send, data } = useWebSocket('ws://localhost:3000/ws/signaling', {
|
||||
const { send } = useWebSocket('ws://localhost:3000/ws/signaling', {
|
||||
autoReconnect: true,
|
||||
//heartbeat: true,
|
||||
onMessage: async (ws, ev) => {
|
||||
const message = JSON.parse(ev.data)
|
||||
if (message.event === 'joined') {
|
||||
toast.success('stweam joined successfullay')
|
||||
toast.success('stream joined successfully')
|
||||
}
|
||||
if (message.event === 'offer') {
|
||||
const peerConnection = new RTCPeerConnection({
|
||||
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
|
||||
iceServers: [
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
],
|
||||
});
|
||||
await peerConnection.setRemoteDescription(message.sdp);
|
||||
|
||||
const answer = await peerConnection.createAnswer();
|
||||
await peerConnection.setLocalDescription(answer);
|
||||
send(JSON.stringify({
|
||||
event: 'answer',
|
||||
targetId: message.data.streamerId,
|
||||
sdp: answer,
|
||||
}))
|
||||
|
||||
viewerStore.setPeerConnection(peerConnection);
|
||||
|
||||
peerConnection.ontrack = (event) => {
|
||||
if (event.streams && event.streams[0] && videofeedRef.value) {
|
||||
videofeedRef.value.srcObject = event.streams[0];
|
||||
@@ -38,22 +32,38 @@ const { send, data } = useWebSocket('ws://localhost:3000/ws/signaling', {
|
||||
if (event.candidate) {
|
||||
send(JSON.stringify({
|
||||
event: 'ice-candidate',
|
||||
targetId: message.data.streamerId,
|
||||
targetId: message.senderId,
|
||||
candidate: event.candidate,
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
await peerConnection.setRemoteDescription(new RTCSessionDescription(message.sdp));
|
||||
|
||||
const answer = await peerConnection.createAnswer();
|
||||
await peerConnection.setLocalDescription(answer);
|
||||
|
||||
send(JSON.stringify({
|
||||
event: 'answer',
|
||||
targetId: message.senderId,
|
||||
sdp: answer,
|
||||
}))
|
||||
}
|
||||
|
||||
if (message.event === 'ice-candidate') {
|
||||
if (viewerStore.peerConnection && viewerStore.peerConnection.remoteDescription) {
|
||||
await viewerStore.peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const videofeedRef = ref<HTMLVideoElement|null>(null);
|
||||
|
||||
const startWebRTCConnection = async () => {
|
||||
send(JSON.stringify({
|
||||
event: 'join-room',
|
||||
data: {
|
||||
roomId: viewerStore.code,
|
||||
}
|
||||
roomId: viewerStore.code,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -71,7 +81,7 @@ watch(codeRef, (newCode) => {
|
||||
<p>code is {{ viewerStore.code }}</p>
|
||||
<app-code-input />
|
||||
|
||||
<video ref="videofeedRef" autoplay playsinline muted></video>
|
||||
<video ref="videofeedRef" autoplay playsinline style="width: 100%; max-width: 1200px; background: black;"></video>
|
||||
|
||||
<NuxtLink to="/stream"><Button>host instead?</Button></NuxtLink>
|
||||
</template>
|
||||
|
||||
@@ -5,44 +5,63 @@ import { useStreamerStore } from '~/state/streamer';
|
||||
|
||||
const streamerStore = useStreamerStore()
|
||||
const videofeedRef = ref<HTMLVideoElement|null>(null);
|
||||
const { send, data, ws } = useWebSocket('ws://localhost:3000/ws/signaling', {
|
||||
const localStream = ref<MediaStream|null>(null);
|
||||
|
||||
const { send } = useWebSocket('ws://localhost:3000/ws/signaling', {
|
||||
autoReconnect: true,
|
||||
//heartbeat: true,
|
||||
onMessage: async (ws, ev) => {
|
||||
const message = JSON.parse(ev.data)
|
||||
|
||||
if (message.event === 'room-created') {
|
||||
const roomId = message.roomId
|
||||
streamerStore.setCode(roomId)
|
||||
streamerStore.setCode(message.roomId)
|
||||
}
|
||||
|
||||
if (message.event === 'viewer-joined') {
|
||||
const peerConnection = new RTCPeerConnection({
|
||||
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
|
||||
});
|
||||
streamerStore.addPeerConnection(message.data.viewerId, peerConnection)
|
||||
streamerStore.addPeerConnection(message.viewerId, peerConnection)
|
||||
|
||||
// Add media tracks to peer connection
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach(track => {
|
||||
peerConnection.addTrack(track, localStream.value!);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle ICE candidates
|
||||
peerConnection.onicecandidate = (event) => {
|
||||
if (event.candidate) {
|
||||
send(JSON.stringify({
|
||||
event: 'ice-candidate',
|
||||
targetId: message.viewerId,
|
||||
candidate: event.candidate,
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
const offer = await peerConnection.createOffer();
|
||||
await peerConnection.setLocalDescription(offer);
|
||||
|
||||
send(JSON.stringify({
|
||||
event: 'offer',
|
||||
targetId: message.data.viewerId,
|
||||
targetId: message.viewerId,
|
||||
sdp: offer,
|
||||
}))
|
||||
}
|
||||
|
||||
if (message.event === 'ice-candidate') {
|
||||
ws.send(JSON.stringify({
|
||||
event: 'ice-candidate',
|
||||
targetId: message.data.senderId,
|
||||
candidate: message.data.candidate,
|
||||
}))
|
||||
const pc = streamerStore.peerConnections[message.from];
|
||||
if (pc) {
|
||||
await pc.addIceCandidate(new RTCIceCandidate(message.candidate));
|
||||
}
|
||||
}
|
||||
|
||||
if (message.event === 'answer') {
|
||||
const pc = streamerStore.peerConnections[message.data.viewerId];
|
||||
if (!pc) {
|
||||
console.error('peerconnection not found for peerid: ', message.data.viewerId);
|
||||
return;
|
||||
};
|
||||
const remoteDesc = new RTCSessionDescription(message.data.sdp);
|
||||
await pc.setRemoteDescription(remoteDesc);
|
||||
const pc = streamerStore.peerConnections[message.from];
|
||||
if (pc) {
|
||||
await pc.setRemoteDescription(new RTCSessionDescription(message.sdp));
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -53,6 +72,8 @@ async function startScreenShare() {
|
||||
audio: false,
|
||||
});
|
||||
|
||||
localStream.value = stream;
|
||||
|
||||
if (videofeedRef.value) {
|
||||
videofeedRef.value.srcObject = stream;
|
||||
}
|
||||
@@ -69,4 +90,4 @@ async function startScreenShare() {
|
||||
</Button>
|
||||
<p>Your stream code: {{ streamerStore.code }}</p>
|
||||
<video ref="videofeedRef" autoplay playsinline muted></video>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -3,10 +3,14 @@ import { defineStore} from 'pinia';
|
||||
export const useViewerStore = defineStore('viewer', {
|
||||
state: () => ({
|
||||
code: '',
|
||||
peerConnection: null as RTCPeerConnection | null,
|
||||
}),
|
||||
actions: {
|
||||
setCode(code: string) {
|
||||
this.code = code;
|
||||
},
|
||||
setPeerConnection(pc: RTCPeerConnection) {
|
||||
this.peerConnection = pc;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -16,6 +16,7 @@
|
||||
"@vueuse/core": "^14.0.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"ioredis": "^5.8.2",
|
||||
"lucide-vue-next": "^0.548.0",
|
||||
"nuxt": "^4.2.0",
|
||||
"pinia": "^3.0.3",
|
||||
@@ -32,6 +33,7 @@
|
||||
"@iconify-json/radix-icons": "^1.2.5",
|
||||
"@iconify/vue": "^5.0.0",
|
||||
"@nuxtjs/color-mode": "^3.5.2",
|
||||
"@types/node": "^24.9.2",
|
||||
"nuxi": "^3.29.3",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
|
||||
118
pnpm-lock.yaml
generated
118
pnpm-lock.yaml
generated
@@ -13,7 +13,7 @@ importers:
|
||||
version: 0.11.2(magicast@0.5.0)(pinia@3.0.3(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3)))
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.16
|
||||
version: 4.1.16(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 4.1.16(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vueuse/core':
|
||||
specifier: ^14.0.0
|
||||
version: 14.0.0(vue@3.5.22(typescript@5.9.3))
|
||||
@@ -23,12 +23,15 @@ importers:
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
ioredis:
|
||||
specifier: ^5.8.2
|
||||
version: 5.8.2
|
||||
lucide-vue-next:
|
||||
specifier: ^0.548.0
|
||||
version: 0.548.0(vue@3.5.22(typescript@5.9.3))
|
||||
nuxt:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
version: 4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
pinia:
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))
|
||||
@@ -55,7 +58,7 @@ importers:
|
||||
version: 4.6.3(vue@3.5.22(typescript@5.9.3))
|
||||
vue-sonner:
|
||||
specifier: ^2.0.9
|
||||
version: 2.0.9(@nuxt/kit@4.2.0(magicast@0.5.0))(@nuxt/schema@4.2.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))
|
||||
version: 2.0.9(@nuxt/kit@4.2.0(magicast@0.5.0))(@nuxt/schema@4.2.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))
|
||||
devDependencies:
|
||||
'@iconify-json/radix-icons':
|
||||
specifier: ^1.2.5
|
||||
@@ -66,6 +69,9 @@ importers:
|
||||
'@nuxtjs/color-mode':
|
||||
specifier: ^3.5.2
|
||||
version: 3.5.2(magicast@0.5.0)
|
||||
'@types/node':
|
||||
specifier: ^24.9.2
|
||||
version: 24.9.2
|
||||
nuxi:
|
||||
specifier: ^3.29.3
|
||||
version: 3.29.3
|
||||
@@ -1292,6 +1298,9 @@ packages:
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/node@24.9.2':
|
||||
resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==}
|
||||
|
||||
'@types/parse-path@7.1.0':
|
||||
resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==}
|
||||
deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed.
|
||||
@@ -3246,6 +3255,9 @@ packages:
|
||||
unctx@2.4.1:
|
||||
resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==}
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
|
||||
undici@7.16.0:
|
||||
resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==}
|
||||
engines: {node: '>=20.18.1'}
|
||||
@@ -4037,11 +4049,11 @@ snapshots:
|
||||
|
||||
'@nuxt/devalue@2.0.2': {}
|
||||
|
||||
'@nuxt/devtools-kit@2.7.0(magicast@0.3.5)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@nuxt/devtools-kit@2.7.0(magicast@0.3.5)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@nuxt/kit': 3.20.0(magicast@0.3.5)
|
||||
execa: 8.0.1
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
@@ -4056,12 +4068,12 @@ snapshots:
|
||||
prompts: 2.4.2
|
||||
semver: 7.7.3
|
||||
|
||||
'@nuxt/devtools@2.7.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
'@nuxt/devtools@2.7.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@nuxt/devtools-kit': 2.7.0(magicast@0.3.5)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@nuxt/devtools-kit': 2.7.0(magicast@0.3.5)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@nuxt/devtools-wizard': 2.7.0
|
||||
'@nuxt/kit': 3.20.0(magicast@0.3.5)
|
||||
'@vue/devtools-core': 7.7.7(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@vue/devtools-core': 7.7.7(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@vue/devtools-kit': 7.7.7
|
||||
birpc: 2.6.1
|
||||
consola: 3.4.2
|
||||
@@ -4086,9 +4098,9 @@ snapshots:
|
||||
sirv: 3.0.2
|
||||
structured-clone-es: 1.0.0
|
||||
tinyglobby: 0.2.15
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-plugin-inspect: 11.3.3(@nuxt/kit@3.20.0(magicast@0.3.5))(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vite-plugin-vue-tracer: 1.0.1(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-plugin-inspect: 11.3.3(@nuxt/kit@3.20.0(magicast@0.3.5))(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vite-plugin-vue-tracer: 1.0.1(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
which: 5.0.0
|
||||
ws: 8.18.3
|
||||
transitivePeerDependencies:
|
||||
@@ -4174,7 +4186,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/nitro-server@4.2.0(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.9.3)':
|
||||
'@nuxt/nitro-server@4.2.0(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@nuxt/devalue': 2.0.2
|
||||
'@nuxt/kit': 4.2.0(magicast@0.5.0)
|
||||
@@ -4192,7 +4204,7 @@ snapshots:
|
||||
klona: 2.0.6
|
||||
mocked-exports: 0.1.1
|
||||
nitropack: 2.12.9
|
||||
nuxt: 4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
pathe: 2.0.3
|
||||
pkg-types: 2.3.0
|
||||
radix3: 1.1.2
|
||||
@@ -4263,12 +4275,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/vite-builder@4.2.0(lightningcss@1.30.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)':
|
||||
'@nuxt/vite-builder@4.2.0(@types/node@24.9.2)(lightningcss@1.30.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)':
|
||||
dependencies:
|
||||
'@nuxt/kit': 4.2.0(magicast@0.5.0)
|
||||
'@rollup/plugin-replace': 6.0.2(rollup@4.52.5)
|
||||
'@vitejs/plugin-vue': 6.0.1(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@vitejs/plugin-vue': 6.0.1(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
autoprefixer: 10.4.21(postcss@8.5.6)
|
||||
consola: 3.4.2
|
||||
cssnano: 7.1.1(postcss@8.5.6)
|
||||
@@ -4283,7 +4295,7 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
mlly: 1.8.0
|
||||
mocked-exports: 0.1.1
|
||||
nuxt: 4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
pathe: 2.0.3
|
||||
pkg-types: 2.3.0
|
||||
postcss: 8.5.6
|
||||
@@ -4292,9 +4304,9 @@ snapshots:
|
||||
std-env: 3.10.0
|
||||
ufo: 1.6.1
|
||||
unenv: 2.0.0-rc.23
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-node: 3.2.4(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-plugin-checker: 0.11.0(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-plugin-checker: 0.11.0(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
vue-bundle-renderer: 2.2.0
|
||||
transitivePeerDependencies:
|
||||
@@ -4818,12 +4830,12 @@ snapshots:
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.16
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.16
|
||||
|
||||
'@tailwindcss/vite@4.1.16(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@tailwindcss/vite@4.1.16(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.1.16
|
||||
'@tailwindcss/oxide': 4.1.16
|
||||
tailwindcss: 4.1.16
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
'@tanstack/virtual-core@3.13.12': {}
|
||||
|
||||
@@ -4839,6 +4851,10 @@ snapshots:
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/node@24.9.2':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
'@types/parse-path@7.1.0':
|
||||
dependencies:
|
||||
parse-path: 7.1.0
|
||||
@@ -4872,22 +4888,22 @@ snapshots:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
|
||||
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
|
||||
'@rolldown/pluginutils': 1.0.0-beta.45
|
||||
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5)
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-vue@6.0.1(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue@6.0.1(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.29
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
|
||||
'@volar/language-core@2.4.23':
|
||||
@@ -4971,14 +4987,14 @@ snapshots:
|
||||
dependencies:
|
||||
'@vue/devtools-kit': 7.7.7
|
||||
|
||||
'@vue/devtools-core@7.7.7(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
'@vue/devtools-core@7.7.7(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@vue/devtools-kit': 7.7.7
|
||||
'@vue/devtools-shared': 7.7.7
|
||||
mitt: 3.0.1
|
||||
nanoid: 5.1.6
|
||||
pathe: 2.0.3
|
||||
vite-hot-client: 2.1.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vite-hot-client: 2.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- vite
|
||||
@@ -6204,16 +6220,16 @@ snapshots:
|
||||
|
||||
nuxi@3.29.3: {}
|
||||
|
||||
nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1):
|
||||
nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@dxup/nuxt': 0.2.0(magicast@0.5.0)
|
||||
'@nuxt/cli': 3.29.3(magicast@0.5.0)
|
||||
'@nuxt/devtools': 2.7.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@nuxt/devtools': 2.7.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3))
|
||||
'@nuxt/kit': 4.2.0(magicast@0.5.0)
|
||||
'@nuxt/nitro-server': 4.2.0(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.9.3)
|
||||
'@nuxt/nitro-server': 4.2.0(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.9.3)
|
||||
'@nuxt/schema': 4.2.0
|
||||
'@nuxt/telemetry': 2.6.6(magicast@0.5.0)
|
||||
'@nuxt/vite-builder': 4.2.0(lightningcss@1.30.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)
|
||||
'@nuxt/vite-builder': 4.2.0(@types/node@24.9.2)(lightningcss@1.30.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1))(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))(yaml@2.8.1)
|
||||
'@unhead/vue': 2.0.19(vue@3.5.22(typescript@5.9.3))
|
||||
'@vue/shared': 3.5.22
|
||||
c12: 3.3.1(magicast@0.5.0)
|
||||
@@ -6265,6 +6281,7 @@ snapshots:
|
||||
vue-router: 4.6.3(vue@3.5.22(typescript@5.9.3))
|
||||
optionalDependencies:
|
||||
'@parcel/watcher': 2.5.1
|
||||
'@types/node': 24.9.2
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
- '@azure/cosmos'
|
||||
@@ -7074,6 +7091,8 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
unplugin: 2.3.10
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
|
||||
undici@7.16.0: {}
|
||||
|
||||
unenv@2.0.0-rc.23:
|
||||
@@ -7193,23 +7212,23 @@ snapshots:
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vite-dev-rpc@1.1.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
vite-dev-rpc@1.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
birpc: 2.6.1
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-hot-client: 2.1.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-hot-client: 2.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
|
||||
vite-hot-client@2.1.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
vite-hot-client@2.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
vite-node@3.2.4(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
vite-node@3.2.4(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.3
|
||||
es-module-lexer: 1.7.0
|
||||
pathe: 2.0.3
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
@@ -7224,7 +7243,7 @@ snapshots:
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vite-plugin-checker@0.11.0(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
vite-plugin-checker@0.11.0(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
chokidar: 4.0.3
|
||||
@@ -7233,12 +7252,12 @@ snapshots:
|
||||
picomatch: 4.0.3
|
||||
tiny-invariant: 1.3.3
|
||||
tinyglobby: 0.2.15
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vscode-uri: 3.1.0
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
vite-plugin-inspect@11.3.3(@nuxt/kit@3.20.0(magicast@0.3.5))(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
vite-plugin-inspect@11.3.3(@nuxt/kit@3.20.0(magicast@0.3.5))(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
ansis: 4.2.0
|
||||
debug: 4.4.3
|
||||
@@ -7248,24 +7267,24 @@ snapshots:
|
||||
perfect-debounce: 2.0.0
|
||||
sirv: 3.0.2
|
||||
unplugin-utils: 0.3.1
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-dev-rpc: 1.1.0(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-dev-rpc: 1.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
optionalDependencies:
|
||||
'@nuxt/kit': 3.20.0(magicast@0.3.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite-plugin-vue-tracer@1.0.1(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)):
|
||||
vite-plugin-vue-tracer@1.0.1(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)):
|
||||
dependencies:
|
||||
estree-walker: 3.0.3
|
||||
exsolve: 1.0.7
|
||||
magic-string: 0.30.21
|
||||
pathe: 2.0.3
|
||||
source-map-js: 1.2.1
|
||||
vite: 7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
|
||||
vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.11
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -7274,6 +7293,7 @@ snapshots:
|
||||
rollup: 4.52.5
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 24.9.2
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.30.2
|
||||
@@ -7297,11 +7317,11 @@ snapshots:
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
|
||||
vue-sonner@2.0.9(@nuxt/kit@4.2.0(magicast@0.5.0))(@nuxt/schema@4.2.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)):
|
||||
vue-sonner@2.0.9(@nuxt/kit@4.2.0(magicast@0.5.0))(@nuxt/schema@4.2.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)):
|
||||
optionalDependencies:
|
||||
'@nuxt/kit': 4.2.0(magicast@0.5.0)
|
||||
'@nuxt/schema': 4.2.0
|
||||
nuxt: 4.2.0(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@24.9.2)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(rollup@4.52.5)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
|
||||
vue@3.5.22(typescript@5.9.3):
|
||||
dependencies:
|
||||
|
||||
@@ -1,31 +1,62 @@
|
||||
import Redis from "ioredis";
|
||||
|
||||
// thanks nitropack smh
|
||||
type Peer = Parameters<NonNullable<Parameters<typeof defineWebSocketHandler>[0]['message']>>[0];
|
||||
|
||||
const rooms: Record<string, { broadcaster: Peer, viewers: Peer[] }> = {};
|
||||
const client = new Redis(process.env.REDIS_URL!);
|
||||
const activePeers = new Map<string, Peer>();
|
||||
|
||||
async function getRoom(roomId: string) {
|
||||
const data = await client.get(`room:${roomId}`);
|
||||
return data ? JSON.parse(data) : null;
|
||||
}
|
||||
|
||||
async function saveRoom(roomId: string, data: { broadcaster: string, viewers: string[] }) {
|
||||
await client.set(`room:${roomId}`, JSON.stringify(data));
|
||||
}
|
||||
|
||||
async function deleteRoom(roomId: string) {
|
||||
await client.del(`room:${roomId}`);
|
||||
}
|
||||
|
||||
async function getAllRoomIds() {
|
||||
return await client.keys('room:*');
|
||||
}
|
||||
|
||||
export default defineWebSocketHandler({
|
||||
message(peer, message) {
|
||||
open(peer) {
|
||||
activePeers.set(peer.id, peer);
|
||||
console.log('[ws] peer connected', peer.id);
|
||||
},
|
||||
|
||||
async message(peer, message) {
|
||||
// TODO: proper typing
|
||||
//if (message.text() === 'ping') return;
|
||||
const msg = message.json() as any;
|
||||
console.log("[ws] message", peer.id, msg);
|
||||
|
||||
if (msg.event === 'create-room') {
|
||||
const roomId = generateRoomId();
|
||||
rooms[roomId] = { broadcaster: peer, viewers: [] };
|
||||
await saveRoom(roomId, { broadcaster: peer.id, viewers: [] });
|
||||
peer.send(JSON.stringify({ event: 'room-created', roomId }));
|
||||
}
|
||||
if (msg.event === 'join-room') {
|
||||
const room = rooms[msg.roomId];
|
||||
const room = await getRoom(msg.roomId);
|
||||
if (room) {
|
||||
room.viewers.push(peer);
|
||||
room.broadcaster.send(JSON.stringify({ event: 'viewer-joined', viewerId: peer.id }));
|
||||
room.viewers.push(peer.id);
|
||||
await saveRoom(msg.roomId, room);
|
||||
// Notify viewer they joined
|
||||
peer.send(JSON.stringify({ event: 'joined', roomId: msg.roomId }));
|
||||
// Notify broadcaster
|
||||
const broadcasterPeer = activePeers.get(room.broadcaster);
|
||||
if (broadcasterPeer) {
|
||||
broadcasterPeer.send(JSON.stringify({ event: 'viewer-joined', viewerId: peer.id }));
|
||||
}
|
||||
} else {
|
||||
peer.send(JSON.stringify({ event: 'error', message: 'Room not found' }));
|
||||
}
|
||||
}
|
||||
if (msg.event === 'offer') {
|
||||
const viewerSocket = findSocketById(msg.targetId);
|
||||
const viewerSocket = activePeers.get(msg.targetId);
|
||||
if (viewerSocket) {
|
||||
viewerSocket.send(JSON.stringify({
|
||||
event: 'offer',
|
||||
@@ -35,17 +66,17 @@ export default defineWebSocketHandler({
|
||||
}
|
||||
}
|
||||
if (msg.event === 'answer') {
|
||||
const broadcasterSocket = findSocketById(msg.targetId)
|
||||
const broadcasterSocket = activePeers.get(msg.targetId);
|
||||
if (broadcasterSocket) {
|
||||
broadcasterSocket.send({
|
||||
broadcasterSocket.send(JSON.stringify({
|
||||
event: 'answer',
|
||||
sdp: msg.sdp,
|
||||
from: peer.id,
|
||||
})
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (msg.event === 'ice-candidate') {
|
||||
const targetSocket = findSocketById(msg.targetId);
|
||||
const targetSocket = activePeers.get(msg.targetId);
|
||||
if (targetSocket) {
|
||||
targetSocket.send(JSON.stringify({
|
||||
event: 'ice-candidate',
|
||||
@@ -56,20 +87,35 @@ export default defineWebSocketHandler({
|
||||
}
|
||||
},
|
||||
|
||||
close(peer, event) {
|
||||
async close(peer, event) {
|
||||
console.log("[ws] close", peer.id, event);
|
||||
for (const [roomId, room] of Object.entries(rooms)) {
|
||||
if (room.broadcaster.id === peer.id) {
|
||||
activePeers.delete(peer.id);
|
||||
|
||||
const roomKeys = await getAllRoomIds();
|
||||
for (const key of roomKeys) {
|
||||
const roomId = key.replace('room:', '');
|
||||
const room = await getRoom(roomId);
|
||||
|
||||
if (!room) continue;
|
||||
|
||||
if (room.broadcaster === peer.id) {
|
||||
// broadcaster disconnected, close room
|
||||
room.viewers.forEach(viewer => {
|
||||
viewer.send(JSON.stringify({ event: 'room-closed' }));
|
||||
room.viewers.forEach((viewerId: string) => {
|
||||
const viewer = activePeers.get(viewerId);
|
||||
if (viewer) {
|
||||
viewer.send(JSON.stringify({ event: 'room-closed' }));
|
||||
}
|
||||
});
|
||||
delete rooms[roomId];
|
||||
await deleteRoom(roomId);
|
||||
} else {
|
||||
const viewerIndex = room.viewers.findIndex(v => v.id === peer.id);
|
||||
const viewerIndex = room.viewers.indexOf(peer.id);
|
||||
if (viewerIndex !== -1) {
|
||||
room.viewers.splice(viewerIndex, 1);
|
||||
room.broadcaster.send(JSON.stringify({ event: 'viewer-left', viewerId: peer.id }));
|
||||
await saveRoom(roomId, room);
|
||||
const broadcasterPeer = activePeers.get(room.broadcaster);
|
||||
if (broadcasterPeer) {
|
||||
broadcasterPeer.send(JSON.stringify({ event: 'viewer-left', viewerId: peer.id }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,12 +125,3 @@ export default defineWebSocketHandler({
|
||||
function generateRoomId(): string {
|
||||
return Math.random().toString().slice(2, 8);
|
||||
}
|
||||
|
||||
function findSocketById(id: string): Peer | null {
|
||||
for (const room of Object.values(rooms)) {
|
||||
if (room.broadcaster.id === id) return room.broadcaster;
|
||||
const viewer = room.viewers.find(v => v.id === id);
|
||||
if (viewer) return viewer;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user