@live-change/server 0.1.18 → 0.1.21
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/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/lib/Renderer.js +38 -1
- package/lib/Services.js +6 -4
- package/lib/SsrServer.js +50 -24
- package/lib/TestServer.js +3 -2
- package/lib/setupApiServer.js +13 -0
- package/lib/setupApp.js +4 -2
- package/package.json +5 -4
- package/server.iml +9 -0
package/.idea/misc.xml
ADDED
package/.idea/vcs.xml
ADDED
package/lib/Renderer.js
CHANGED
|
@@ -3,6 +3,8 @@ const path = require('path')
|
|
|
3
3
|
const serialize = require('serialize-javascript')
|
|
4
4
|
const renderTemplate = require('./renderTemplate.js')
|
|
5
5
|
|
|
6
|
+
const { SitemapStream } = require('sitemap')
|
|
7
|
+
|
|
6
8
|
class Renderer {
|
|
7
9
|
constructor(manifest, settings) {
|
|
8
10
|
this.manifest = manifest
|
|
@@ -15,7 +17,9 @@ class Renderer {
|
|
|
15
17
|
await this.setupVite()
|
|
16
18
|
} else {
|
|
17
19
|
const serverEntryPath = path.resolve(this.root, './dist/server/entry-server.js')
|
|
18
|
-
this.
|
|
20
|
+
this.module = require(serverEntryPath)
|
|
21
|
+
this.renderer = this.module.render
|
|
22
|
+
this.sitemap = this.module.sitemap
|
|
19
23
|
const templatePath = path.resolve(this.root, 'dist/client/index.html')
|
|
20
24
|
this.template = await fs.promises.readFile(templatePath, { encoding: 'utf-8' })
|
|
21
25
|
}
|
|
@@ -117,6 +121,39 @@ class Renderer {
|
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
async getSitemap() {
|
|
125
|
+
if(this.settings.dev) {
|
|
126
|
+
/// Reload every request
|
|
127
|
+
const entryPath = path.resolve(this.root, 'src/entry-server.js')
|
|
128
|
+
return (await this.vite.ssrLoadModule(entryPath)).sitemap
|
|
129
|
+
} else {
|
|
130
|
+
return this.sitemap
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async renderSitemap({ dao }, res) {
|
|
135
|
+
try {
|
|
136
|
+
res.header('Content-Type', 'application/xml')
|
|
137
|
+
res.status(200)
|
|
138
|
+
const smStream = new SitemapStream({ hostname: (process.env.BASE_HREF || "https://sitemap.com")+'/' })
|
|
139
|
+
smStream.pipe(res)
|
|
140
|
+
const sitemapFunction = await this.getSitemap()
|
|
141
|
+
const { sitemap, router } = await sitemapFunction({ dao })
|
|
142
|
+
function route(location, opts) {
|
|
143
|
+
smStream.write({ url: router.resolve(location).href, changefreq: 'daily', priority: 0.5, ...opts })
|
|
144
|
+
}
|
|
145
|
+
console.log("SR", sitemap, router)
|
|
146
|
+
await sitemap(route)
|
|
147
|
+
//route({ name: 'index' })
|
|
148
|
+
smStream.end()
|
|
149
|
+
} catch(err) {
|
|
150
|
+
console.error("SITEMAP RENDERING ERROR", err)
|
|
151
|
+
res.status(503)
|
|
152
|
+
res.end(`<h4>Internal server error</h4><pre>${err.stack || err.code || err}</pre>`)
|
|
153
|
+
//if(profileOp) await profileLog.end({ ...profileOp, state: 'error', error: err })
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
120
157
|
fixStackTrace(e) {
|
|
121
158
|
this.vite && this.vite.ssrFixStacktrace(e)
|
|
122
159
|
}
|
package/lib/Services.js
CHANGED
|
@@ -4,6 +4,8 @@ const path = require('path')
|
|
|
4
4
|
const resolve = require('util').promisify(require('resolve'))
|
|
5
5
|
const app = require("@live-change/framework").app()
|
|
6
6
|
|
|
7
|
+
const debug = require('debug')('framework')
|
|
8
|
+
|
|
7
9
|
class Services {
|
|
8
10
|
constructor(configPath) {
|
|
9
11
|
if(!configPath) throw new Error("services config parameter is required")
|
|
@@ -18,12 +20,12 @@ class Services {
|
|
|
18
20
|
|
|
19
21
|
async resolve(file) {
|
|
20
22
|
const path = await resolve(file, { basedir: this.servicesDir })
|
|
21
|
-
|
|
23
|
+
debug("PATH RESOLVE", file, "IN", this.servicesDir, "=>", path)
|
|
22
24
|
return path
|
|
23
25
|
}
|
|
24
26
|
async getServiceEntryFile(config) {
|
|
25
27
|
const path = await resolve(config.path, { basedir: this.servicesDir })
|
|
26
|
-
|
|
28
|
+
debug("PATH RESOLVE", config.path, "IN", this.servicesDir, "=>", path)
|
|
27
29
|
return path
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -39,14 +41,14 @@ class Services {
|
|
|
39
41
|
if(this.config.plugins) {
|
|
40
42
|
for(const plugin of this.config.plugins) {
|
|
41
43
|
const entryFile = await this.getServiceEntryFile(plugin)
|
|
42
|
-
|
|
44
|
+
debug("PLUGIN", plugin, 'ENTRY FILE', entryFile)
|
|
43
45
|
this.plugins.push(require(entryFile))
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
if(this.config.services) {
|
|
47
49
|
for(const service of this.config.services) {
|
|
48
50
|
const entryFile = await this.getServiceEntryFile(service)
|
|
49
|
-
|
|
51
|
+
debug("SERVICE", service, 'ENTRY FILE', entryFile)
|
|
50
52
|
const definition = require(entryFile)
|
|
51
53
|
if(definition.name != service.name) {
|
|
52
54
|
console.error("SERVICE", service, "NAME", service.name, "MISMATCH", definition.name)
|
package/lib/SsrServer.js
CHANGED
|
@@ -21,7 +21,7 @@ class SsrServer {
|
|
|
21
21
|
|
|
22
22
|
this.instanceId = encodeNumber(hashCode(
|
|
23
23
|
`ssr${process.pid}${require("os").hostname()} ${process.cwd()}/${process.argv.join(' ')}`))
|
|
24
|
-
this.uidGenerator = uidGenerator(this.instanceId, 1)
|
|
24
|
+
this.uidGenerator = uidGenerator(this.instanceId, 1, this.settings.uidBorders)
|
|
25
25
|
|
|
26
26
|
this.root = this.settings.root || process.cwd()
|
|
27
27
|
}
|
|
@@ -54,6 +54,23 @@ class SsrServer {
|
|
|
54
54
|
await this.setupSsr()
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
async createDao(credentials, clientIp) {
|
|
58
|
+
let dao
|
|
59
|
+
if(this.settings.daoFactory) {
|
|
60
|
+
dao = await this.settings.daoFactory(credentials, clientIp)
|
|
61
|
+
} else {
|
|
62
|
+
const host = (this.settings.apiHost == '0.0.0.0' || !this.settings.apiHost)
|
|
63
|
+
? 'localhost' : this.settings.apiHost
|
|
64
|
+
dao = await serverDao(credentials, clientIp, {
|
|
65
|
+
remoteUrl: `ws://${host}:${this.settings.apiPort || 8002}/api/ws`
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
if(!dao) {
|
|
69
|
+
throw new Error("Impossible to render page without data access object. Define apiServer or daoFactory!")
|
|
70
|
+
}
|
|
71
|
+
return dao
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
async setupSsr() {
|
|
58
75
|
const readCredentials = this.settings.readCredentials || ((req) => {
|
|
59
76
|
const cookies = cookie.parse(req.headers.cookie || '')
|
|
@@ -70,6 +87,13 @@ class SsrServer {
|
|
|
70
87
|
})
|
|
71
88
|
}
|
|
72
89
|
})
|
|
90
|
+
|
|
91
|
+
this.express.get('/sitemap.xml', async (req, res) => {
|
|
92
|
+
const sitemap = await this.renderer.getSitemap()
|
|
93
|
+
const clientIp = getIp(req)
|
|
94
|
+
const dao = await this.createDao({ sessionKey: 'sitemap' })
|
|
95
|
+
this.renderer.renderSitemap({ dao, clientIp }, res)
|
|
96
|
+
})
|
|
73
97
|
this.express.use('*', async (req, res) => {
|
|
74
98
|
const url = req.originalUrl
|
|
75
99
|
const clientIp = getIp(req)
|
|
@@ -77,33 +101,35 @@ class SsrServer {
|
|
|
77
101
|
const credentials = readCredentials(req)
|
|
78
102
|
const windowId = this.uidGenerator()
|
|
79
103
|
try {
|
|
80
|
-
|
|
81
|
-
if(this.settings.daoFactory) {
|
|
82
|
-
dao = await this.settings.daoFactory(credentials, clientIp)
|
|
83
|
-
} else {
|
|
84
|
-
const host = (this.settings.apiHost == '0.0.0.0' || !this.settings.apiHost)
|
|
85
|
-
? 'localhost' : this.settings.apiHost
|
|
86
|
-
dao = await serverDao(credentials, clientIp, {
|
|
87
|
-
remoteUrl: `ws://${host}:${this.settings.apiPort || 8002}/api/ws`
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
if(!dao)
|
|
91
|
-
throw new Error("Impossible to render page without data access object. Define apiServer or daoFactory!")
|
|
92
|
-
|
|
104
|
+
const dao = await this.createDao(credentials, clientIp)
|
|
93
105
|
const version = this.version
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
let html
|
|
108
|
+
let error
|
|
96
109
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
for(let retry = 0; retry < 3; retry ++) {
|
|
111
|
+
try {
|
|
112
|
+
html = await this.renderer.renderPage({ url, dao, clientIp, credentials, windowId, version })
|
|
113
|
+
break
|
|
114
|
+
} catch(e) {
|
|
115
|
+
error = e
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if(html) {
|
|
119
|
+
res.status(200)
|
|
120
|
+
writeCredentials(res, credentials)
|
|
121
|
+
res.set({
|
|
122
|
+
'Content-Type': 'text/html'
|
|
123
|
+
})
|
|
124
|
+
res.end(html)
|
|
125
|
+
} else {
|
|
126
|
+
if(error.stack) this.renderer.fixStackTrace(error)
|
|
127
|
+
console.error("RENDERING ERROR", error.stack || error)
|
|
128
|
+
res.status(500).end(error.stack || error)
|
|
129
|
+
}
|
|
103
130
|
} catch (e) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
res.status(500).end(e.stack)
|
|
131
|
+
console.error("ERROR", e.stack || e)
|
|
132
|
+
res.status(500).end(e.stack || e)
|
|
107
133
|
}
|
|
108
134
|
})
|
|
109
135
|
}
|
package/lib/TestServer.js
CHANGED
|
@@ -27,7 +27,7 @@ class TestServer {
|
|
|
27
27
|
|
|
28
28
|
app.instanceId = encodeNumber(hashCode(
|
|
29
29
|
`app${process.pid}${require("os").hostname()} ${process.cwd()}/${process.argv.join(' ')}`))
|
|
30
|
-
app.uidGenerator = uidGenerator(app.instanceId, 1)
|
|
30
|
+
app.uidGenerator = uidGenerator(app.instanceId, 1, '[]')
|
|
31
31
|
this.dbServer = await setupDbServer({ dbBackend: 'mem' })
|
|
32
32
|
const loopbackDao = await createLoopbackDao('local', () => this.dbServer.createDao('local'))
|
|
33
33
|
app.dao = loopbackDao
|
|
@@ -60,8 +60,9 @@ class TestServer {
|
|
|
60
60
|
|
|
61
61
|
await new Promise((resolve, reject) => {
|
|
62
62
|
this.httpServer = this.expressServer.listen(this.config.port || 0, () => {
|
|
63
|
-
this.port = this.expressServer.address().port
|
|
63
|
+
this.port = this.expressServer.address().port
|
|
64
64
|
this.url = `http://localhost:${this.expressServer.address().port}`
|
|
65
|
+
process.env.SSR_PORT = this.port
|
|
65
66
|
resolve()
|
|
66
67
|
})
|
|
67
68
|
})
|
package/lib/setupApiServer.js
CHANGED
|
@@ -39,6 +39,19 @@ async function setupApiServer(settings) {
|
|
|
39
39
|
}
|
|
40
40
|
})
|
|
41
41
|
}
|
|
42
|
+
if(settings.dbAccess) {
|
|
43
|
+
local.serverDatabase = {
|
|
44
|
+
observable(what) {
|
|
45
|
+
return app.dao.observable(['database', ...what.slice(1)])
|
|
46
|
+
},
|
|
47
|
+
get(what) {
|
|
48
|
+
return app.dao.get(['database', ...what.slice(1)])
|
|
49
|
+
},
|
|
50
|
+
request(what, ...args) {
|
|
51
|
+
return app.dao.request(['database', ...what.slice(1)], ...args)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
42
55
|
return local
|
|
43
56
|
},
|
|
44
57
|
shareDefinition: true,
|
package/lib/setupApp.js
CHANGED
|
@@ -4,12 +4,14 @@ const setupDbServer = require('./setupDbServer.js')
|
|
|
4
4
|
const setupDbClient = require('./setupDbClient.js')
|
|
5
5
|
const createLoopbackDao = require('./createLoopbackDao.js')
|
|
6
6
|
|
|
7
|
+
const debug = require('debug')('server:app')
|
|
8
|
+
|
|
7
9
|
async function setupApp(settings, env = process.env) {
|
|
8
10
|
const app = require("@live-change/framework").app()
|
|
9
11
|
app.instanceId = encodeNumber(hashCode(
|
|
10
12
|
`app${process.pid}${require("os").hostname()} ${process.cwd()}/${process.argv.join(' ')}`))
|
|
11
|
-
app.uidGenerator = uidGenerator(app.instanceId, 1)
|
|
12
|
-
|
|
13
|
+
app.uidGenerator = uidGenerator(app.instanceId, 1, settings.uidBorders)
|
|
14
|
+
debug("SETUP APP", settings)
|
|
13
15
|
let dbServer
|
|
14
16
|
if(settings.withDb) {
|
|
15
17
|
dbServer = await setupDbServer(settings)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Live Change Framework - server",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@live-change/dao": "^0.3.12",
|
|
25
25
|
"@live-change/dao-sockjs": "^0.2.1",
|
|
26
|
-
"@live-change/db-server": "^0.
|
|
26
|
+
"@live-change/db-server": "^0.5.3",
|
|
27
27
|
"@live-change/framework": "^0.5.10",
|
|
28
28
|
"@live-change/vue3-ssr": "^0.1.7",
|
|
29
|
-
"@live-change/uid": "^0.1.
|
|
29
|
+
"@live-change/uid": "^0.1.4",
|
|
30
30
|
"http-proxy-middleware": "2.0.1",
|
|
31
31
|
"dotenv": "^10.0.0",
|
|
32
32
|
"express": "^4.17.1",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@live-change/sockjs": "^0.4.0-rc.1",
|
|
37
37
|
"websocket": "^1.0.34",
|
|
38
38
|
"yargs": "^17.3.0",
|
|
39
|
-
"express-static-gzip": "2.1.1"
|
|
39
|
+
"express-static-gzip": "2.1.1",
|
|
40
|
+
"sitemap": "^6.3.6"
|
|
40
41
|
}
|
|
41
42
|
}
|
package/server.iml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
+
<exclude-output />
|
|
5
|
+
<content url="file://$MODULE_DIR$" />
|
|
6
|
+
<orderEntry type="inheritedJdk" />
|
|
7
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
8
|
+
</component>
|
|
9
|
+
</module>
|