@live-change/peer-connection-frontend 0.0.3

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.
@@ -0,0 +1,51 @@
1
+ function oldUserMediaFactory() {
2
+ if(navigator.getUserMedia) return (...args) => navigator.getUserMedia(...args)
3
+ if(navigator.webkitGetUserMedia) return (...args) => navigator.webkitGetUserMedia(...args)
4
+ if(navigator.mozGetUserMedia) return (...args) => navigator.mozGetUserMedia(...args)
5
+ }
6
+
7
+ function userMediaFactory() {
8
+ if(typeof window == 'undefined') return null
9
+ if(typeof navigator == 'undefined') return null
10
+ if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
11
+ return (constraints) => navigator.mediaDevices.getUserMedia(constraints)
12
+ }
13
+ return (constraints) => new Promise((resolve, reject) => {
14
+ const getUserMedia = oldUserMediaFactory()
15
+ getUserMedia(constraints, resolve, reject)
16
+ })
17
+ }
18
+
19
+ function displayMediaFactory() {
20
+ if(typeof window == 'undefined') return null
21
+ if(typeof navigator == 'undefined') return null
22
+ if(navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
23
+ return (constraints) => navigator.mediaDevices.getDisplayMedia(constraints)
24
+ }
25
+ return null
26
+ }
27
+
28
+ async function isUserMediaPermitted(constraints = { audio: true, video: true }) {
29
+ if(!navigator.permissions) return true
30
+ console.log("QUERING FOR PERMISSIONS", constraints)
31
+ const { audio, video } = constraints
32
+ const [microphonePermission, cameraPermission] = (await Promise.all([
33
+ audio
34
+ ? navigator.permissions.query({ name: 'microphone' }).catch(err => true)
35
+ : Promise.resolve(null),
36
+ video
37
+ ? navigator.permissions.query({ name: 'camera' }).catch(err => true)
38
+ : Promise.resolve(null)
39
+ ]))
40
+ console.log("MICROPHONE PERMISSION", microphonePermission && microphonePermission.state)
41
+ console.log("CAMERA PERMISSION", cameraPermission && cameraPermission.state)
42
+ if(microphonePermission && microphonePermission.state == 'denied') return false
43
+ if(cameraPermission && cameraPermission.state == 'denied') return false
44
+ return true
45
+ }
46
+
47
+ const getUserMedia = userMediaFactory()
48
+ const getDisplayMedia = displayMediaFactory()
49
+
50
+ export { getUserMedia, getDisplayMedia, isUserMediaPermitted }
51
+
@@ -0,0 +1,24 @@
1
+ import { createApp } from './main'
2
+ import { clientApi } from '@live-change/vue3-ssr/clientApi.js'
3
+
4
+ import {
5
+ createSharedElementDirective,
6
+ SharedElementRouteGuard
7
+ } from 'v-shared-element'
8
+
9
+
10
+ window.api = clientApi({
11
+ use: [ ]
12
+ })
13
+
14
+ const { app, router } = createApp(api)
15
+
16
+ app.use(createSharedElementDirective())
17
+ router.beforeEach(SharedElementRouteGuard)
18
+ window.process = window.process || null
19
+
20
+ // wait until router is ready before mounting to ensure hydration match
21
+ router.isReady().then(() => {
22
+ const instance = app.mount('#app', true)
23
+ app._container._vnode = instance.$.vnode
24
+ })
@@ -0,0 +1,59 @@
1
+ import { renderToString } from 'vue/server-renderer'
2
+ import { renderMetaToString } from 'vue-meta/ssr'
3
+
4
+ import { serverApi } from '@live-change/vue3-ssr/serverApi.js'
5
+
6
+ import { createApp } from './main'
7
+
8
+ function escapeHtml(unsafe) {
9
+ return unsafe
10
+ .replace(/&/g, "&")
11
+ .replace(/</g, "&lt;")
12
+ .replace(/>/g, "&gt;")
13
+ .replace(/"/g, "&quot;")
14
+ .replace(/'/g, "&#039;");
15
+ }
16
+
17
+ export async function render({ url, dao, windowId }) {
18
+ const api = await serverApi(dao, {
19
+ use: [ ]
20
+ })
21
+
22
+ const { app, router } = createApp(api)
23
+
24
+ // set the router to the desired URL before rendering
25
+ router.push(url)
26
+ await router.isReady()
27
+
28
+ // prefetch data
29
+ await api.preFetchRoute(router.currentRoute, router)
30
+
31
+ // passing SSR context object which will be available via useSSRContext()
32
+ // @vitejs/plugin-vue injects code into a component's setup() that registers
33
+ // itself on ctx.modules. After the render, ctx.modules would contain all the
34
+ // components that have been instantiated during this render call.
35
+ const ctx = {}
36
+ const html = await renderToString(app, ctx)
37
+ await renderMetaToString(app, ctx)
38
+
39
+ const data = api.prerenderCache.cacheData()
40
+ //console.log("PRERENDER CACHE", Array.from(api.prerenderCache.cache.keys()))
41
+ //console.log("PRERENDER CACHE EXTENDED", Array.from(api.prerenderCache.extendedCache.keys()))
42
+
43
+ // the SSR manifest generated by Vite contains module -> chunk/asset mapping
44
+ // which we can then use to determine what files need to be preloaded for this
45
+ // request.
46
+
47
+ const metaManager = app.config.globalProperties.$metaManager
48
+ const activeMeta = metaManager.target.context.active
49
+ //console.log("ACTIVE META", activeMeta)
50
+ //console.log("TELEPORTS", ctx.teleports)
51
+ ctx.teleports.head = [
52
+ ...(activeMeta.title ? [`<title data-vm-ssr="true">${escapeHtml(activeMeta.title)}</title>`] : []),
53
+ ...((activeMeta.meta || []).map(meta => `<meta ${Object.keys(meta).map(
54
+ key => `${escapeHtml(key)}="${escapeHtml(meta[key])}"`
55
+ ).join(' ')}>`))
56
+ ].join('\n')
57
+
58
+ return { html, data, meta: ctx.teleports, modules: ctx.modules }
59
+ }
@@ -0,0 +1,60 @@
1
+ import { createSSRApp } from 'vue'
2
+ import { createMetaManager } from 'vue-meta'
3
+
4
+ import { registerComponents } from '@live-change/vue3-components'
5
+ import ReactiveDaoVue from '@live-change/dao-vue3'
6
+
7
+ import PrimeVue from 'primevue/config'
8
+ import ConfirmationService from 'primevue/confirmationservice'
9
+ import { PrimeVueConfirmSymbol } from 'primevue/useconfirm'
10
+ import { PrimeVueToastSymbol } from 'primevue/usetoast'
11
+ import ToastService from 'primevue/toastservice'
12
+ import StyleClass from 'primevue/styleclass'
13
+ import Ripple from 'primevue/ripple'
14
+ import BadgeDirective from 'primevue/badgedirective'
15
+
16
+ import App from './App.vue'
17
+ import { createRouter } from './router'
18
+
19
+ import emailValidator from "@live-change/email-service/clientEmailValidator.js"
20
+ import passwordValidator from "@live-change/password-authentication-service/clientPasswordValidator.js"
21
+
22
+ // SSR requires a fresh app instance per request, therefore we export a function
23
+ // that creates a fresh app instance. If using Vuex, we'd also be creating a
24
+ // fresh store here.
25
+ export function createApp(api) {
26
+ api.validators.email = emailValidator
27
+ api.validators.password = passwordValidator
28
+
29
+ const app = createSSRApp(App)
30
+ app.config.devtools = true
31
+
32
+ api.installInstanceProperties(app.config.globalProperties)
33
+
34
+ registerComponents(app)
35
+ app.use(ReactiveDaoVue, { dao: api })
36
+
37
+ const router = createRouter(app)
38
+ app.use(router)
39
+
40
+ app.use(PrimeVue, {
41
+ ripple: true
42
+ })
43
+
44
+ app.use(ConfirmationService)
45
+ app.provide(PrimeVueConfirmSymbol, app.config.globalProperties.$confirm)
46
+
47
+ app.use(ToastService)
48
+ app.provide(PrimeVueToastSymbol, app.config.globalProperties.$toast)
49
+
50
+ app.directive('styleclass', StyleClass)
51
+ app.directive('ripple', Ripple)
52
+ app.directive('badge', BadgeDirective)
53
+
54
+ const meta = createMetaManager({
55
+ isSSR: import.meta.env.SSR
56
+ })
57
+ app.use(meta)
58
+
59
+ return { app, router }
60
+ }
@@ -0,0 +1,63 @@
1
+ import {
2
+ createMemoryHistory,
3
+ createRouter as _createRouter,
4
+ createWebHistory
5
+ } from 'vue-router'
6
+
7
+
8
+ export function routes(config = {}) {
9
+ const { prefix = '/', route = (r) => r } = config
10
+ return [
11
+ route({
12
+ name: 'debugger', path: prefix + '/debugger/:channelType/:channel', meta: { },
13
+ component: () => import("./components/Debugger.vue")
14
+ }),
15
+ route({
16
+ name: 'testDebugger', path: prefix + '', meta: { },
17
+ component: () => import("./components/Debugger.vue"),
18
+ props: {
19
+ channelType: 'example_Example',
20
+ channel: 'one'
21
+ }
22
+ })
23
+
24
+ ]
25
+ }
26
+
27
+ export async function sitemap(route, api) {
28
+
29
+ }
30
+
31
+ import { client as useClient } from '@live-change/vue3-ssr'
32
+
33
+ export function createRouter(app, config) {
34
+ //console.log("APP CTX", app._context)
35
+ const client = useClient(app._context)
36
+ const router = _createRouter({
37
+ // use appropriate history implementation for server/client
38
+ // import.meta.env.SSR is injected by Vite.
39
+ history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
40
+ routes: routes(config)
41
+ })
42
+ router.beforeEach(async (to, from) => {
43
+ if(to?.matched.find(m => m?.meta.signedIn)) {
44
+ if(!client.value.user) {
45
+ console.log("REDIRECT TO LOGIN BECAUSE PAGE REQUIRES LOGIN!")
46
+ router.redirectAfterSignIn = to.fullPath
47
+ return { name: 'user:signIn' }
48
+ }
49
+ }
50
+ if(to?.matched.find(m => m?.meta.signedOut)) {
51
+ if(client.value.user) {
52
+ console.log("REDIRECT TO USER INDEX BECAUSE PAGE REQUIRES LOGOUT!")
53
+ return { name: 'user:settings' }
54
+ }
55
+ }
56
+ if(to && to.name == 'user:signIn' && from?.matched.find(m => m?.meta.saveForSignIn)) {
57
+ console.log("SAVE FOR LOGIN", from.fullPath)
58
+ localStorage.redirectAfterLogin = from.fullPath
59
+ }
60
+ })
61
+ return router
62
+ }
63
+
@@ -0,0 +1,118 @@
1
+ const path = require('path')
2
+ const vuePlugin = require('@vitejs/plugin-vue')
3
+ import { defineConfig } from 'vite'
4
+ import findFreePorts from "find-free-ports"
5
+ import { visualizer } from 'rollup-plugin-visualizer'
6
+ import viteImages from 'vite-plugin-vue-images'
7
+ import viteCompression from 'vite-plugin-compression'
8
+
9
+ const ssrTransformCustomDir = () => {
10
+ return {
11
+ props: [],
12
+ needRuntime: true
13
+ }
14
+ }
15
+
16
+ export default defineConfig(async ({ command, mode }) => {
17
+ return {
18
+ define: {
19
+ ENV_BASE_HREF: JSON.stringify(process.env.BASE_HREF || 'http://localhost:8001')
20
+ },
21
+ server: {
22
+ hmr: {
23
+ port: (await findFreePorts())[0]
24
+ }
25
+ },
26
+ plugins: [
27
+ vuePlugin({
28
+ template: {
29
+ compilerOptions: {
30
+ // whitespace: "preserve",
31
+ directiveTransforms: {
32
+ 'ripple': ssrTransformCustomDir,
33
+ 'styleclass': ssrTransformCustomDir,
34
+ 'badge': ssrTransformCustomDir,
35
+ 'shared-element': ssrTransformCustomDir
36
+ }
37
+ }
38
+ },
39
+ }),
40
+ viteImages({ extensions: ['jpg', 'jpeg', 'png', 'svg', 'webp'] }),
41
+ viteCompression({ algorithm: 'brotliCompress', ext: '.br' }),
42
+ viteCompression({ algorithm: 'gzip', ext: '.gz' }),
43
+ viteCompression({ algorithm: 'deflate', ext: '.zz' }),
44
+ visualizer({
45
+ filename: '../stats.html'
46
+ }),
47
+ ],
48
+ build: {
49
+ minify: false,
50
+ commonjsOptions: {
51
+ transformMixedEsModules: true,
52
+ include: [
53
+ /node_modules/,
54
+ /live-change-framework\/framework\//,
55
+ /live-change-framework\/uid\//,
56
+ /live-change-dao\/dao\//,
57
+ /live-change-dao\/dao-sockjs\//,
58
+ /live-change-dao\/dao-websocket\//,
59
+ ]
60
+ }
61
+ },
62
+ ssr: {
63
+ external: [
64
+ '@live-change/dao',
65
+ '@live-change/vue-api',
66
+ '@live-change/vue-api-session',
67
+ '@live-change/uid',
68
+ '@live-change/framework',
69
+ '@live-change/framework/lib/utils/validators.js',
70
+ 'debug',
71
+ 'vite'
72
+ ],
73
+ noExternal: [
74
+ 'vue-meta',
75
+ '@live-change/vue3-components',
76
+ '@live-change/dao-vue3',
77
+ '@live-change/vue3-ssr',
78
+ 'vue3-scroll-border'
79
+ ]
80
+ },
81
+ optimizeDeps: {
82
+ include: [
83
+ '@live-change/vue-api',
84
+ '@live-change/vue-api-session',
85
+ '@live-change/dao',
86
+ '@live-change/dao-sockjs',
87
+ '@live-change/dao-websocket',
88
+ '@live-change/uid',
89
+ '@live-change/framework',
90
+ '@live-change/framework/lib/utils/validators.js',
91
+ 'debug'
92
+ ]
93
+ },
94
+
95
+ resolve: {
96
+ alias: [
97
+ { find: 'debug', replacement: 'debug/src/browser.js' },
98
+ { find: 'universal-websocket-client', replacement: 'universal-websocket-client/browser.js' },
99
+ { find: 'sockjs-client', replacement: 'sockjs-client/dist/sockjs.min.js' },
100
+ { find: '@', replacement: path.resolve(__dirname, './src') },
101
+ { find: '#user', replacement: path.resolve(__dirname, '.') }
102
+ ],
103
+ },
104
+ resolvers: [{
105
+ fileToRequest(filePath) {
106
+ console.log('@@@', filePath);
107
+ if (filePath.startsWith(srcPath)) {
108
+ return `/@/${path.relative(srcPath, filePath)}`
109
+ }
110
+ },
111
+ requestToFile(publicPath) {
112
+ if (publicPath.startsWith('/@/')) {
113
+ return path.join(srcPath, publicPath.replace(/^\/@\//, ''))
114
+ }
115
+ },
116
+ }],
117
+ }
118
+ })
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@live-change/peer-connection-frontend",
3
+ "version": "0.0.3",
4
+ "scripts": {
5
+ "memDev": "lcli memDev --enableSessions --initScript ./init.js",
6
+ "localDevInit": "rm tmp.db; lcli localDev --enableSessions --initScript ./init.js",
7
+ "localDev": "lcli localDev --enableSessions",
8
+ "dev": "lcli dev --enableSessions",
9
+ "ssrDev": "lcli ssrDev --enableSessions",
10
+ "serveAllMem": "cross-env NODE_ENV=production lcli ssrServer --withApi --withServices --updateServices --enableSessions --withDb --dbBackend mem --createDb",
11
+ "serveAll": "cross-env NODE_ENV=production lcli ssrServer --withApi --withServices --updateServices --enableSessions",
12
+ "serve": "cross-env NODE_ENV=production lcli ssrServer --enableSessions",
13
+ "apiServer": "lcli apiServer --enableSessions",
14
+ "devApiServer": "lcli devApiServer --enableSessions",
15
+ "memApiServer": "lcli memApiServer --enableSessions",
16
+ "build": "cd front; yarn build:client && yarn build:server",
17
+ "build:client": "cd front; vite build --ssrManifest --outDir dist/client",
18
+ "build:server": "cd front; vite build --ssr src/entry-server.js --outDir dist/server",
19
+ "generate": "vite build --ssrManifest --outDir dist/static && yarn build:server && node prerender",
20
+ "debug": "node --inspect-brk server"
21
+ },
22
+ "dependencies": {
23
+ "@live-change/framework": "0.6.5",
24
+ "@live-change/cli": "0.6.5",
25
+ "@live-change/dao": "0.4.13",
26
+ "@live-change/dao-vue3": "0.4.13",
27
+ "@live-change/dao-websocket": "0.4.13",
28
+ "@live-change/vue3-ssr": "0.2.14",
29
+ "@live-change/vue3-components": "0.2.12",
30
+ "@live-change/session-service": "0.2.39",
31
+ "@live-change/user-service": "0.2.37",
32
+ "@live-change/password-authentication-service": "0.2.39",
33
+ "@live-change/secret-link-service": "0.2.39",
34
+ "@live-change/secret-code-service": "0.2.39",
35
+ "@live-change/user-frontend": "0.0.3",
36
+ "@vitejs/plugin-vue": "^2.3.1",
37
+ "@vitejs/plugin-vue-jsx": "^1.3.10",
38
+ "@vue/compiler-sfc": "^3.2.33",
39
+ "@vueuse/core": "^8.3.1",
40
+ "v-shared-element": "3.1.0",
41
+ "vue3-scroll-border": "0.1.2",
42
+ "codeceptjs-assert": "^0.0.5",
43
+ "compression": "^1.7.4",
44
+ "cross-env": "^7.0.3",
45
+ "get-port-sync": "1.0.1",
46
+ "primeicons": "^5.0.0",
47
+ "primevue": "^3.15.0",
48
+ "primeflex": "^3.2.1",
49
+ "rollup-plugin-node-builtins": "^2.1.2",
50
+ "serialize-javascript": "^6.0.0",
51
+ "serve-static": "^1.15.0",
52
+ "vite": "^2.9.6",
53
+ "vue": "^3.2.33",
54
+ "vue-meta": "^3.0.0-alpha.9",
55
+ "vue-router": "^4.0.14",
56
+ "vite-plugin-compression": "0.5.1",
57
+ "vite-plugin-vue-images": "^0.6.1",
58
+ "rollup-plugin-visualizer": "5.6.0"
59
+ },
60
+ "devDependencies": {
61
+ "@live-change/codeceptjs-helper": "0.6.5",
62
+ "@wdio/selenium-standalone-service": "^7.19.5",
63
+ "codeceptjs": "^3.3.1",
64
+ "playwright": "^1.21.1",
65
+ "random-profile-generator": "^2.3.0",
66
+ "txtgen": "^3.0.1",
67
+ "generate-password": "1.7.0",
68
+ "webdriverio": "^7.19.5"
69
+ },
70
+ "author": "",
71
+ "license": "ISC",
72
+ "description": ""
73
+ }
package/server/init.js ADDED
@@ -0,0 +1,7 @@
1
+ const App = require('@live-change/framework')
2
+ const app = App.app()
3
+
4
+ module.exports = async function(services) {
5
+
6
+
7
+ }
@@ -0,0 +1,25 @@
1
+ module.exports = {
2
+ services: [
3
+ {
4
+ name: 'timer',
5
+ path: '@live-change/timer-service'
6
+ },
7
+ {
8
+ name: 'session',
9
+ path: '@live-change/session-service',
10
+ createSessionOnUpdate: true
11
+ },
12
+ {
13
+ name: 'online',
14
+ path: '@live-change/online-service',
15
+ createSessionOnUpdate: true
16
+ },
17
+ {
18
+ name: 'peerConnection',
19
+ path: '@live-change/peer-connection-service',
20
+ turn: {
21
+ urls: 'turn:turn1.xaos.ninja:4433;turn:turn2.xaos.ninja:4433'
22
+ }
23
+ }
24
+ ]
25
+ }