@live-change/peer-connection-frontend 0.8.36 → 0.8.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/front/components.d.ts +2 -0
- package/front/src/App.vue +1 -0
- package/front/src/components/Debugger.vue +2 -2
- package/front/src/components/{DevicesSelect.vue → DeviceSelect.vue} +43 -19
- package/front/src/components/PermissionsDialog.vue +1 -0
- package/front/src/components/VolumeIndicator.vue +209 -0
- package/front/src/router.js +1 -1
- package/index.js +2 -1
- package/package.json +18 -16
package/front/components.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ declare module 'vue' {
|
|
|
9
9
|
export interface GlobalComponents {
|
|
10
10
|
Button: typeof import('primevue/button')['default']
|
|
11
11
|
Debugger: typeof import('./src/components/Debugger.vue')['default']
|
|
12
|
+
DeviceSelect: typeof import('./src/components/DeviceSelect.vue')['default']
|
|
12
13
|
DevicesSelect: typeof import('./src/components/DevicesSelect.vue')['default']
|
|
13
14
|
Dialog: typeof import('primevue/dialog')['default']
|
|
14
15
|
Dropdown: typeof import('primevue/dropdown')['default']
|
|
@@ -16,5 +17,6 @@ declare module 'vue' {
|
|
|
16
17
|
PermissionsDialog: typeof import('./src/components/PermissionsDialog.vue')['default']
|
|
17
18
|
RouterLink: typeof import('vue-router')['RouterLink']
|
|
18
19
|
RouterView: typeof import('vue-router')['RouterView']
|
|
20
|
+
VolumeIndicator: typeof import('./src/components/VolumeIndicator.vue')['default']
|
|
19
21
|
}
|
|
20
22
|
}
|
package/front/src/App.vue
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
<div>
|
|
45
45
|
<h2>User media</h2>
|
|
46
|
-
<
|
|
46
|
+
<DeviceSelect v-model="selectedDevices" />
|
|
47
47
|
<hr>
|
|
48
48
|
<pre>{{ selectedDevices }}</pre>
|
|
49
49
|
<div class="mt-1 mb-3 flex align-items-center">
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
import Dropdown from "primevue/dropdown"
|
|
74
74
|
import Dialog from "primevue/dialog"
|
|
75
75
|
import PermissionsDialog from './PermissionsDialog.vue'
|
|
76
|
-
import
|
|
76
|
+
import DeviceSelect from './DeviceSelect.vue'
|
|
77
77
|
|
|
78
78
|
import { ref, unref, computed, watch, onMounted, onUnmounted, getCurrentInstance } from 'vue'
|
|
79
79
|
import { path, live, actions, api as useApi } from '@live-change/vue3-ssr'
|
|
@@ -19,22 +19,29 @@
|
|
|
19
19
|
</video>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="absolute top-0 left-0 w-full h-full flex flex-column justify-content-end align-items-center">
|
|
22
|
-
<div class="flex flex-row justify-content-between align-items-center h-5rem w-
|
|
22
|
+
<div class="flex flex-row justify-content-between align-items-center h-5rem w-7rem media-buttons">
|
|
23
|
+
|
|
23
24
|
<Button v-if="!selectedConstraints?.audio?.deviceId"
|
|
24
|
-
@click="handleDisabledAudioClick"
|
|
25
|
-
icon="
|
|
25
|
+
@click="handleDisabledAudioClick" raised
|
|
26
|
+
icon="bx bx-microphone-off" severity="secondary" rounded v-ripple />
|
|
26
27
|
<Button v-else-if="audioInputMuted" @click="audioInputMuted = false" raised
|
|
27
|
-
icon="
|
|
28
|
+
icon="bx bx-microphone-off" severity="danger" rounded v-ripple />
|
|
28
29
|
<Button v-else @click="audioInputMuted = true" raised
|
|
29
|
-
icon="
|
|
30
|
+
icon="bx bx-microphone" severity="success" rounded v-ripple />
|
|
30
31
|
|
|
31
32
|
<Button v-if="!selectedConstraints?.video?.deviceId"
|
|
32
|
-
@click="handleDisabledVideoClick"
|
|
33
|
-
icon="
|
|
33
|
+
@click="handleDisabledVideoClick" raised
|
|
34
|
+
icon="bx bx-camera-off" severity="secondary" rounded v-ripple />
|
|
34
35
|
<Button v-else-if="videoInputMuted" @click="videoInputMuted = false" raised
|
|
35
|
-
icon="
|
|
36
|
+
icon="bx bx-camera-off" severity="danger" rounded v-ripple />
|
|
36
37
|
<Button v-else @click="videoInputMuted = true" raised
|
|
37
|
-
icon="
|
|
38
|
+
icon="bx bx-camera" severity="success" rounded v-ripple />
|
|
39
|
+
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="absolute top-0 right-0">
|
|
43
|
+
<div class="m-3">
|
|
44
|
+
<VolumeIndicator :stream="userMedia" />
|
|
38
45
|
</div>
|
|
39
46
|
</div>
|
|
40
47
|
</div>
|
|
@@ -125,6 +132,14 @@
|
|
|
125
132
|
</div>
|
|
126
133
|
</template>
|
|
127
134
|
|
|
135
|
+
<style lang="scss">
|
|
136
|
+
.media-buttons {
|
|
137
|
+
.bx::before {
|
|
138
|
+
font-size: 1.69em;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
|
|
128
143
|
<script setup>
|
|
129
144
|
|
|
130
145
|
import { defineProps, defineModel, computed, ref, toRefs, onMounted, watch } from 'vue'
|
|
@@ -132,6 +147,7 @@
|
|
|
132
147
|
import { getUserMedia as getUserMediaNative, getDisplayMedia as getDisplayMediaNative, isUserMediaPermitted }
|
|
133
148
|
from "./userMedia.js"
|
|
134
149
|
import PermissionsDialog from './PermissionsDialog.vue'
|
|
150
|
+
import VolumeIndicator from './VolumeIndicator.vue'
|
|
135
151
|
|
|
136
152
|
const props = defineProps({
|
|
137
153
|
audioInputRequest: {
|
|
@@ -184,8 +200,10 @@
|
|
|
184
200
|
devices.value = await navigator.mediaDevices.enumerateDevices()
|
|
185
201
|
console.log("DEVICES", JSON.stringify(devices.value))
|
|
186
202
|
}
|
|
187
|
-
|
|
188
|
-
|
|
203
|
+
if(typeof window !== 'undefined') {
|
|
204
|
+
useEventListener(navigator.mediaDevices, 'devicechange', updateDevices)
|
|
205
|
+
onMounted(updateDevices)
|
|
206
|
+
}
|
|
189
207
|
|
|
190
208
|
const audioInputs = computed(() => devices.value.filter(device => device.kind === 'audioinput'))
|
|
191
209
|
const audioOutputs = computed(() => devices.value.filter(device => device.kind === 'audiooutput'))
|
|
@@ -208,13 +226,22 @@
|
|
|
208
226
|
})
|
|
209
227
|
|
|
210
228
|
watch(audioInputs, (value) => {
|
|
211
|
-
model.value
|
|
229
|
+
model.value = {
|
|
230
|
+
...model.value,
|
|
231
|
+
audioInput: value[0]
|
|
232
|
+
}
|
|
212
233
|
}, { immediate: true })
|
|
213
234
|
watch(audioOutputs, (value) => {
|
|
214
|
-
model.value
|
|
235
|
+
model.value = {
|
|
236
|
+
...model.value,
|
|
237
|
+
audioOutput: value[0]
|
|
238
|
+
}
|
|
215
239
|
}, { immediate: true })
|
|
216
240
|
watch(videoInputs, (value) => {
|
|
217
|
-
model.value
|
|
241
|
+
model.value = {
|
|
242
|
+
...model.value,
|
|
243
|
+
videoInput: value[0]
|
|
244
|
+
}
|
|
218
245
|
}, { immediate: true })
|
|
219
246
|
|
|
220
247
|
/* onMounted(() => {
|
|
@@ -234,9 +261,9 @@
|
|
|
234
261
|
const selectedConstraints = ref({ video: false, audio: false })
|
|
235
262
|
watch(() => ({
|
|
236
263
|
video: limitedMedia.value === 'audio' ? false :
|
|
237
|
-
{ deviceId: model.value
|
|
264
|
+
{ deviceId: model.value?.videoInput?.deviceId, ...constraints.value.video },
|
|
238
265
|
audio: limitedMedia.value === 'video' ? false :
|
|
239
|
-
{ deviceId: model.value
|
|
266
|
+
{ deviceId: model.value?.audioInput?.deviceId, ...constraints.value.audio }
|
|
240
267
|
}), ({ video, audio }) => {
|
|
241
268
|
console.log("SELECTED CONSTRAINTS", {
|
|
242
269
|
video: selectedConstraints.value.video?.deviceId,
|
|
@@ -383,9 +410,6 @@
|
|
|
383
410
|
//updateUserMedia()
|
|
384
411
|
})
|
|
385
412
|
|
|
386
|
-
window.um = userMedia
|
|
387
|
-
window.model = model
|
|
388
|
-
|
|
389
413
|
</script>
|
|
390
414
|
|
|
391
415
|
<style scoped>
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
const emit = defineEmits(['ok'])
|
|
97
97
|
|
|
98
98
|
watch(() => JSON.stringify(requiredPermissions.value), async value => {
|
|
99
|
+
if(typeof window === 'undefined') return
|
|
99
100
|
console.log("requiredPermissions", value)
|
|
100
101
|
|
|
101
102
|
for(const requiredPermission of JSON.parse(value)) {
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-row border-circle w-2rem h-2rem bg-primary-800
|
|
3
|
+
align-items-center justify-content-center">
|
|
4
|
+
<div class="volume-indicator-bar bg-white border-round" ref="low"></div>
|
|
5
|
+
<div class="volume-indicator-bar bg-white border-round" ref="mid"></div>
|
|
6
|
+
<div class="volume-indicator-bar bg-white border-round" ref="high"></div>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<style scoped lang="scss">
|
|
11
|
+
.volume-indicator-bar {
|
|
12
|
+
width: 0.3rem;
|
|
13
|
+
margin: 0.1rem;
|
|
14
|
+
}
|
|
15
|
+
.border-circle {
|
|
16
|
+
border-radius: 50%;
|
|
17
|
+
}
|
|
18
|
+
.bg-primary-700 {
|
|
19
|
+
background-color: #1976D2;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
|
|
25
|
+
import { ref, defineProps, computed, toRefs, onMounted, onUnmounted, watch } from 'vue'
|
|
26
|
+
|
|
27
|
+
const props = defineProps({
|
|
28
|
+
stream: {
|
|
29
|
+
type: Object,
|
|
30
|
+
required: true
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const { stream } = toRefs(props)
|
|
35
|
+
|
|
36
|
+
const speed = 0.46
|
|
37
|
+
const maxLogVolume = -2
|
|
38
|
+
const minLogVolume = -7
|
|
39
|
+
const lowFrequency = 230
|
|
40
|
+
const midFrequency = 460
|
|
41
|
+
const highFrequency = 1230
|
|
42
|
+
const filterQ = 0.1
|
|
43
|
+
const detune = 100
|
|
44
|
+
|
|
45
|
+
const minHeight = 3
|
|
46
|
+
const maxHeight = 15
|
|
47
|
+
|
|
48
|
+
const low = ref(null)
|
|
49
|
+
const mid = ref(null)
|
|
50
|
+
const high = ref(null)
|
|
51
|
+
|
|
52
|
+
let audioContext, mediaStreamSource
|
|
53
|
+
let lowFilter, midFilter, highFilter
|
|
54
|
+
let lowProcessor, midProcessor, highProcessor
|
|
55
|
+
let lowSlow = 0, midSlow = 0, highSlow = 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
function measureAmplitudeProcess(cb) {
|
|
59
|
+
return function(event) {
|
|
60
|
+
const numberOfChannels = event.inputBuffer.numberOfChannels
|
|
61
|
+
let instant = 0
|
|
62
|
+
for(let channelId = 0; channelId < numberOfChannels; channelId++) {
|
|
63
|
+
let sum = 0
|
|
64
|
+
const input = event.inputBuffer.getChannelData(channelId)
|
|
65
|
+
for (let i = 0; i < input.length; ++i) {
|
|
66
|
+
sum += input[i] * input[i]
|
|
67
|
+
}
|
|
68
|
+
instant += sum / input.length
|
|
69
|
+
}
|
|
70
|
+
cb(Math.sqrt(instant))
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleLow(instant) {
|
|
75
|
+
instant = Math.log(instant)
|
|
76
|
+
let value = lowSlow
|
|
77
|
+
if(!Number.isFinite(value)) value = -1000
|
|
78
|
+
value = instant * speed + value * (1 - speed)
|
|
79
|
+
if(value > maxLogVolume) value = maxLogVolume
|
|
80
|
+
if(value < minLogVolume) value = minLogVolume
|
|
81
|
+
const height = ((value - minLogVolume)/(maxLogVolume - minLogVolume))
|
|
82
|
+
* (maxHeight - minHeight) + minHeight
|
|
83
|
+
lowSlow = value
|
|
84
|
+
low.value.style.height = height + 'px'
|
|
85
|
+
}
|
|
86
|
+
function handleMid(instant) {
|
|
87
|
+
instant = Math.log(instant)
|
|
88
|
+
let value = midSlow
|
|
89
|
+
if(!Number.isFinite(value)) value = -1000
|
|
90
|
+
value = instant * speed + value * (1 - speed)
|
|
91
|
+
if(value > maxLogVolume) value = maxLogVolume
|
|
92
|
+
if(value < minLogVolume) value = minLogVolume
|
|
93
|
+
const height = ((value - minLogVolume)/(maxLogVolume - minLogVolume))
|
|
94
|
+
* (maxHeight - minHeight) + minHeight
|
|
95
|
+
midSlow = value
|
|
96
|
+
mid.value.style.height = height + 'px'
|
|
97
|
+
}
|
|
98
|
+
function handleHigh(instant) {
|
|
99
|
+
instant = Math.log(instant)
|
|
100
|
+
let value = highSlow
|
|
101
|
+
if(!Number.isFinite(value)) value = -1000
|
|
102
|
+
value = instant * speed + value * (1 - speed)
|
|
103
|
+
if(value > maxLogVolume) value = maxLogVolume
|
|
104
|
+
if(value < minLogVolume) value = minLogVolume
|
|
105
|
+
const height = ((value - minLogVolume)/(maxLogVolume - minLogVolume))
|
|
106
|
+
* (maxHeight - minHeight) + minHeight
|
|
107
|
+
highSlow = value
|
|
108
|
+
high.value.style.height = height + 'px'
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function startProcessingAudioStream(sourceStream) {
|
|
112
|
+
audioContext = new (window.AudioContext || window.webkitAudioContext)()
|
|
113
|
+
|
|
114
|
+
lowFilter = audioContext.createBiquadFilter()
|
|
115
|
+
lowFilter.type = 'lowpass'
|
|
116
|
+
lowFilter.frequency.value = lowFrequency
|
|
117
|
+
lowFilter.detune.value = detune
|
|
118
|
+
lowFilter.Q.value = filterQ
|
|
119
|
+
|
|
120
|
+
midFilter = audioContext.createBiquadFilter()
|
|
121
|
+
midFilter.type = 'bandpass'
|
|
122
|
+
midFilter.frequency.value = midFrequency
|
|
123
|
+
midFilter.detune.value = detune
|
|
124
|
+
midFilter.Q.value = filterQ
|
|
125
|
+
|
|
126
|
+
highFilter = audioContext.createBiquadFilter()
|
|
127
|
+
highFilter.type = 'highpass'
|
|
128
|
+
highFilter.frequency.value = highFrequency
|
|
129
|
+
highFilter.detune.value = detune
|
|
130
|
+
highFilter.Q.value = filterQ
|
|
131
|
+
|
|
132
|
+
lowProcessor = audioContext.createScriptProcessor(
|
|
133
|
+
2*2048, 1, 1)
|
|
134
|
+
lowProcessor.addEventListener('audioprocess', measureAmplitudeProcess(a => handleLow(a)))
|
|
135
|
+
|
|
136
|
+
midProcessor = audioContext.createScriptProcessor(
|
|
137
|
+
2*2048, 1, 1)
|
|
138
|
+
midProcessor.addEventListener('audioprocess', measureAmplitudeProcess(a => handleMid(a)))
|
|
139
|
+
|
|
140
|
+
highProcessor = audioContext.createScriptProcessor(
|
|
141
|
+
2*2048, 1, 1)
|
|
142
|
+
highProcessor.addEventListener('audioprocess', measureAmplitudeProcess(a => handleHigh(a)))
|
|
143
|
+
|
|
144
|
+
lowFilter.connect(lowProcessor)
|
|
145
|
+
midFilter.connect(midProcessor)
|
|
146
|
+
highFilter.connect(highProcessor)
|
|
147
|
+
|
|
148
|
+
lowProcessor.connect(audioContext.destination)
|
|
149
|
+
midProcessor.connect(audioContext.destination)
|
|
150
|
+
highProcessor.connect(audioContext.destination)
|
|
151
|
+
|
|
152
|
+
mediaStreamSource = audioContext.createMediaStreamSource(sourceStream)
|
|
153
|
+
mediaStreamSource.connect(lowFilter)
|
|
154
|
+
mediaStreamSource.connect(midFilter)
|
|
155
|
+
mediaStreamSource.connect(highFilter)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function stopProcessingAudioStream() {
|
|
159
|
+
if(mediaStreamSource) {
|
|
160
|
+
mediaStreamSource.disconnect()
|
|
161
|
+
mediaStreamSource = null
|
|
162
|
+
}
|
|
163
|
+
if(audioContext) audioContext.close()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function handleStreamChange() {
|
|
167
|
+
updateSource()
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
watch(stream, (newStream, oldStream) => {
|
|
171
|
+
if(oldStream) {
|
|
172
|
+
oldStream.removeEventListener('addtrack', handleStreamChange)
|
|
173
|
+
oldStream.removeEventListener('removetrack', handleStreamChange)
|
|
174
|
+
}
|
|
175
|
+
updateSource()
|
|
176
|
+
if(newStream) {
|
|
177
|
+
newStream.addEventListener('addtrack', handleStreamChange)
|
|
178
|
+
newStream.addEventListener('removetrack', handleStreamChange)
|
|
179
|
+
}
|
|
180
|
+
}, { immediate: true })
|
|
181
|
+
|
|
182
|
+
onMounted(() => {
|
|
183
|
+
updateSource()
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
function updateSource() {
|
|
187
|
+
console.log("UPDATE SOURCE", stream.value, "STARTED?")
|
|
188
|
+
if(mediaStreamSource) {
|
|
189
|
+
stopProcessingAudioStream()
|
|
190
|
+
}
|
|
191
|
+
if(stream.value && stream.value.getAudioTracks().length > 0) {
|
|
192
|
+
console.log("GOT AUDIO TRACKS!")
|
|
193
|
+
startProcessingAudioStream(stream.value)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
onUnmounted(() => {
|
|
198
|
+
if(stream.value) {
|
|
199
|
+
stream.value.removeEventListener('addtrack', handleStreamChange)
|
|
200
|
+
stream.value.removeEventListener('removetrack', handleStreamChange)
|
|
201
|
+
}
|
|
202
|
+
stopProcessingAudioStream()
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
</script>
|
|
206
|
+
|
|
207
|
+
<style scoped>
|
|
208
|
+
|
|
209
|
+
</style>
|
package/front/src/router.js
CHANGED
|
@@ -34,7 +34,7 @@ export function createRouter(app, config) {
|
|
|
34
34
|
history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
|
|
35
35
|
routes: [
|
|
36
36
|
...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) }),
|
|
37
|
-
...peerConnectionRoutes(config),
|
|
37
|
+
...peerConnectionRoutes({ ...config, prefix: '/peer-connection' }),
|
|
38
38
|
{
|
|
39
39
|
name: 'peer-connection:test-debugger', path: '/', meta: { },
|
|
40
40
|
component: () => import("./components/Debugger.vue"),
|
package/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Debugger from './front/src/components/Debugger.vue'
|
|
2
2
|
import DeviceSelect from './front/src/components/DeviceSelect.vue'
|
|
3
3
|
import PermissionsDialog from './front/src/components/PermissionsDialog.vue'
|
|
4
|
+
import VolumeIndicator from './front/src/components/VolumeIndicator.vue'
|
|
4
5
|
|
|
5
|
-
export { Debugger, DeviceSelect, PermissionsDialog }
|
|
6
|
+
export { Debugger, DeviceSelect, PermissionsDialog, VolumeIndicator }
|
|
6
7
|
|
|
7
8
|
import { createPeer } from './front/src/components/Peer.js'
|
|
8
9
|
import { createPeerConnection } from './front/src/components/PeerConnection.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/peer-connection-frontend",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.37",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"memDev": "dotenvx run -- node server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
|
|
6
6
|
"localDevInit": "rm tmp.db; dotenvx run -- node server/start.js localDev --enableSessions --initScript ./init.js",
|
|
@@ -22,23 +22,25 @@
|
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@live-change/cli": "^0.8.
|
|
26
|
-
"@live-change/dao": "^0.8.
|
|
27
|
-
"@live-change/dao-vue3": "^0.8.
|
|
28
|
-
"@live-change/dao-websocket": "^0.8.
|
|
29
|
-
"@live-change/framework": "^0.8.
|
|
30
|
-
"@live-change/password-authentication-service": "^0.8.
|
|
31
|
-
"@live-change/secret-code-service": "^0.8.
|
|
32
|
-
"@live-change/secret-link-service": "^0.8.
|
|
33
|
-
"@live-change/session-service": "^0.8.
|
|
34
|
-
"@live-change/user-frontend": "^0.8.
|
|
35
|
-
"@live-change/user-service": "^0.8.
|
|
36
|
-
"@live-change/vue3-components": "^0.8.
|
|
37
|
-
"@live-change/vue3-ssr": "^0.8.
|
|
25
|
+
"@live-change/cli": "^0.8.37",
|
|
26
|
+
"@live-change/dao": "^0.8.37",
|
|
27
|
+
"@live-change/dao-vue3": "^0.8.37",
|
|
28
|
+
"@live-change/dao-websocket": "^0.8.37",
|
|
29
|
+
"@live-change/framework": "^0.8.37",
|
|
30
|
+
"@live-change/password-authentication-service": "^0.8.37",
|
|
31
|
+
"@live-change/secret-code-service": "^0.8.37",
|
|
32
|
+
"@live-change/secret-link-service": "^0.8.37",
|
|
33
|
+
"@live-change/session-service": "^0.8.37",
|
|
34
|
+
"@live-change/user-frontend": "^0.8.37",
|
|
35
|
+
"@live-change/user-service": "^0.8.37",
|
|
36
|
+
"@live-change/vue3-components": "^0.8.37",
|
|
37
|
+
"@live-change/vue3-ssr": "^0.8.37",
|
|
38
38
|
"@vueuse/core": "^10.11.0",
|
|
39
|
+
"boxicons": "^2.1.4",
|
|
39
40
|
"codeceptjs-assert": "^0.0.5",
|
|
40
41
|
"compression": "^1.7.4",
|
|
41
42
|
"cross-env": "^7.0.3",
|
|
43
|
+
"feather-icons": "^4.29.2",
|
|
42
44
|
"get-port-sync": "1.0.1",
|
|
43
45
|
"primeflex": "^3.3.1",
|
|
44
46
|
"primeicons": "^7.0.0",
|
|
@@ -52,7 +54,7 @@
|
|
|
52
54
|
"vue3-scroll-border": "0.1.6"
|
|
53
55
|
},
|
|
54
56
|
"devDependencies": {
|
|
55
|
-
"@live-change/codeceptjs-helper": "^0.8.
|
|
57
|
+
"@live-change/codeceptjs-helper": "^0.8.37",
|
|
56
58
|
"codeceptjs": "^3.5.12",
|
|
57
59
|
"generate-password": "1.7.1",
|
|
58
60
|
"playwright": "^1.41.2",
|
|
@@ -63,5 +65,5 @@
|
|
|
63
65
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
64
66
|
"license": "BSD-3-Clause",
|
|
65
67
|
"description": "",
|
|
66
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "8b97a83258a3eccd08534d0376015781c4eefdec"
|
|
67
69
|
}
|