@ditojs/server 1.5.1 → 1.5.4
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Server – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/server",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
|
31
31
|
"ajv": "^8.11.0",
|
|
32
32
|
"ajv-formats": "^2.1.1",
|
|
33
|
-
"aws-sdk": "^2.
|
|
33
|
+
"aws-sdk": "^2.1108.0",
|
|
34
34
|
"axios": "^0.26.1",
|
|
35
35
|
"bcryptjs": "^2.4.3",
|
|
36
36
|
"bytes": "^3.1.2",
|
|
@@ -76,10 +76,10 @@
|
|
|
76
76
|
"objection": "^3.0.1"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"knex": "^1.0.
|
|
79
|
+
"knex": "^1.0.5",
|
|
80
80
|
"objection": "^3.0.1",
|
|
81
81
|
"pg": "^8.7.3",
|
|
82
82
|
"sqlite3": "^5.0.2"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "fa4ff0e996e9d043a226d54c5e9ab263ccf1ad5f"
|
|
85
85
|
}
|
package/src/app/Application.js
CHANGED
|
@@ -22,8 +22,8 @@ import helmet from 'koa-helmet'
|
|
|
22
22
|
import responseTime from 'koa-response-time'
|
|
23
23
|
import Router from '@ditojs/router'
|
|
24
24
|
import {
|
|
25
|
-
isArray, isObject, isString, asArray, isPlainObject,
|
|
26
|
-
parseDataPath, normalizeDataPath,
|
|
25
|
+
isArray, isObject, isString, asArray, isPlainObject, isModule,
|
|
26
|
+
hyphenate, clone, merge, parseDataPath, normalizeDataPath, toPromiseCallback
|
|
27
27
|
} from '@ditojs/utils'
|
|
28
28
|
import SessionStore from './SessionStore.js'
|
|
29
29
|
import { Validator } from './Validator.js'
|
|
@@ -88,6 +88,9 @@ export class Application extends Koa {
|
|
|
88
88
|
this.models = Object.create(null)
|
|
89
89
|
this.services = Object.create(null)
|
|
90
90
|
this.controllers = Object.create(null)
|
|
91
|
+
this.server = null
|
|
92
|
+
this.isRunning = false
|
|
93
|
+
|
|
91
94
|
this.setupLogger()
|
|
92
95
|
this.setupKnex()
|
|
93
96
|
this.setupMiddleware(middleware)
|
|
@@ -283,10 +286,6 @@ export class Application extends Koa {
|
|
|
283
286
|
return Object.values(this.services).find(callback)
|
|
284
287
|
}
|
|
285
288
|
|
|
286
|
-
forEachService(callback) {
|
|
287
|
-
return Promise.all(Object.values(this.services).map(callback))
|
|
288
|
-
}
|
|
289
|
-
|
|
290
289
|
addControllers(controllers, namespace) {
|
|
291
290
|
for (const [key, value] of Object.entries(controllers)) {
|
|
292
291
|
if (isModule(value) || isPlainObject(value)) {
|
|
@@ -718,46 +717,56 @@ export class Application extends Koa {
|
|
|
718
717
|
this.on('error', this.logError)
|
|
719
718
|
}
|
|
720
719
|
await this.emit('before:start')
|
|
721
|
-
await
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const server = this.listen(port, host, () => {
|
|
725
|
-
const { port } = server.address()
|
|
720
|
+
this.server = await new Promise(resolve => {
|
|
721
|
+
const server = this.listen(this.config.server, () => {
|
|
722
|
+
const { address, port } = server.address()
|
|
726
723
|
console.info(
|
|
727
|
-
`Dito server started at http://${
|
|
724
|
+
`Dito.js server started at http://${address}:${port}`
|
|
728
725
|
)
|
|
729
726
|
resolve(server)
|
|
730
727
|
})
|
|
731
|
-
if (!server) {
|
|
732
|
-
reject(new Error(`Unable to start server at http://${host}:${port}`))
|
|
733
|
-
}
|
|
734
728
|
})
|
|
729
|
+
if (!this.server) {
|
|
730
|
+
throw new Error('Unable to start Dito.js server')
|
|
731
|
+
}
|
|
732
|
+
this.isRunning = true
|
|
735
733
|
await this.emit('after:start')
|
|
736
734
|
}
|
|
737
735
|
|
|
738
|
-
async stop() {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
736
|
+
async stop(timeout = 0) {
|
|
737
|
+
if (!this.server) {
|
|
738
|
+
throw new Error('Dito.js server is not running')
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const promise = (async () => {
|
|
742
|
+
await this.emit('before:stop')
|
|
743
|
+
this.isRunning = false
|
|
744
|
+
await new Promise((resolve, reject) => {
|
|
745
|
+
this.server.close(toPromiseCallback(resolve, reject))
|
|
746
|
+
})
|
|
747
|
+
// Hack to make sure that the server is closed, even if sockets are still
|
|
748
|
+
// open after `server.close()`, see: https://stackoverflow.com/a/36830072
|
|
749
|
+
this.server.emit('close')
|
|
750
|
+
this.server = null
|
|
751
|
+
await this.emit('after:stop')
|
|
752
|
+
})()
|
|
753
|
+
|
|
754
|
+
if (timeout > 0) {
|
|
755
|
+
await Promise.race([
|
|
756
|
+
promise,
|
|
757
|
+
new Promise((resolve, reject) =>
|
|
758
|
+
setTimeout(reject,
|
|
759
|
+
timeout,
|
|
760
|
+
new Error(
|
|
761
|
+
`Timeout reached while stopping Dito.js server (${timeout}ms)`
|
|
762
|
+
)
|
|
763
|
+
)
|
|
764
|
+
)
|
|
765
|
+
])
|
|
766
|
+
} else {
|
|
767
|
+
await promise
|
|
768
|
+
}
|
|
769
|
+
|
|
761
770
|
if (this.config.log.errors !== false) {
|
|
762
771
|
this.off('error', this.logError)
|
|
763
772
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
|
+
import { exit } from 'process'
|
|
2
3
|
import Koa from 'koa'
|
|
3
4
|
import serve from 'koa-static'
|
|
4
5
|
import { defineConfig, createServer } from 'vite'
|
|
@@ -32,6 +33,7 @@ export class AdminController extends Controller {
|
|
|
32
33
|
this.mode = this.config.mode || (
|
|
33
34
|
this.app.config.env === 'development' ? 'development' : 'production'
|
|
34
35
|
)
|
|
36
|
+
this.closed = false
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
getPath(name) {
|
|
@@ -80,16 +82,25 @@ export class AdminController extends Controller {
|
|
|
80
82
|
// Shield admin views against unauthorized access.
|
|
81
83
|
const authorization = this.processAuthorize(this.authorize)
|
|
82
84
|
return async (ctx, next) => {
|
|
83
|
-
if (
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
if (this.closed) {
|
|
86
|
+
// Avoid strange behavior during shut-down of the vite dev server.
|
|
87
|
+
// Sending back a 408 response seems to work best, while a 503 sadly
|
|
88
|
+
// would put the client into a state that prevents the server from a
|
|
89
|
+
// proper shut-down, and a 205 would kill future hot-reloads.
|
|
90
|
+
ctx.status = 408 // Request Timeout
|
|
91
|
+
} else if (ctx.url === '/dito.js') {
|
|
92
|
+
// Don't call `next()`
|
|
93
|
+
this.sendDitoObject(ctx)
|
|
94
|
+
} else {
|
|
95
|
+
if (/\/views\b/.test(ctx.url)) {
|
|
96
|
+
await this.handleAuthorization(authorization, ctx)
|
|
97
|
+
}
|
|
98
|
+
await next()
|
|
88
99
|
}
|
|
89
|
-
await next()
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
|
|
103
|
+
// @override
|
|
93
104
|
compose() {
|
|
94
105
|
this.koa = new Koa()
|
|
95
106
|
this.koa.use(this.middleware())
|
|
@@ -128,6 +139,33 @@ export class AdminController extends Controller {
|
|
|
128
139
|
}
|
|
129
140
|
}
|
|
130
141
|
})
|
|
142
|
+
|
|
143
|
+
this.closed = false
|
|
144
|
+
|
|
145
|
+
// Monkey-patch `process.exit()` to filter out the calls caused by vite's
|
|
146
|
+
// handling of SIGTERM, see: https://github.com/vitejs/vite/issues/7627
|
|
147
|
+
process.exit = code => {
|
|
148
|
+
// Filter out calls from inside vite by looking at the stack trace.
|
|
149
|
+
if (new Error().stack.includes('/vite/dist/')) {
|
|
150
|
+
// vite's own `exitProcess()` just called `process.exit(), and this
|
|
151
|
+
// means it has already called `server.close()` internally.
|
|
152
|
+
this.closed = true
|
|
153
|
+
process.exit = exit
|
|
154
|
+
} else {
|
|
155
|
+
exit(code)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.app.once('after:stop', () => {
|
|
160
|
+
// For good timing it seems crucial to not add more ticks with async
|
|
161
|
+
// signature, so we directly return the `server.close()` promise instead.
|
|
162
|
+
process.exit = exit
|
|
163
|
+
if (!this.closed) {
|
|
164
|
+
this.closed = true
|
|
165
|
+
return server.close()
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
|
|
131
169
|
this.koa.use(handleConnectMiddleware(server.middlewares, {
|
|
132
170
|
expandMountPath: true
|
|
133
171
|
}))
|
|
@@ -26,6 +26,12 @@ export class Controller {
|
|
|
26
26
|
initialize() {
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// @return {Application|Function} [app or function]
|
|
30
|
+
compose() {
|
|
31
|
+
// To be overridden in sub-classes, if the controller needs to install
|
|
32
|
+
// middleware. For normal routes, use `this.app.addRoute()` instead.
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
setup(isRoot = true, setupActionsObject = true) {
|
|
30
36
|
this._setupEmitter(this.hooks, {
|
|
31
37
|
// Support wildcard hooks only on controllers:
|
|
@@ -246,12 +252,6 @@ export class Controller {
|
|
|
246
252
|
])
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
// @return {Application|Function} [app or function]
|
|
250
|
-
compose() {
|
|
251
|
-
// To be overridden in sub-classes, if the controller needs to install
|
|
252
|
-
// middleware. For normal routes, use `this.app.addRoute()` instead.
|
|
253
|
-
}
|
|
254
|
-
|
|
255
255
|
getPath(type, path) {
|
|
256
256
|
// To be overridden by sub-classes.
|
|
257
257
|
return path
|