@ditojs/server 0.271.0 → 0.274.0
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/lib/app/Application.js +68 -25
- package/lib/app/SessionStore.js +3 -1
- package/lib/app/Validator.js +16 -2
- package/lib/app/index.js +7 -1
- package/lib/cli/console.js +14 -4
- package/lib/cli/db/createMigration.js +16 -4
- package/lib/cli/db/index.js +7 -1
- package/lib/cli/db/listAssetConfig.js +4 -2
- package/lib/cli/db/migrate.js +3 -3
- package/lib/cli/db/reset.js +3 -3
- package/lib/cli/db/rollback.js +3 -3
- package/lib/cli/db/seed.js +14 -6
- package/lib/cli/db/unlock.js +3 -3
- package/lib/cli/index.js +9 -5
- package/lib/controllers/AdminController.js +18 -6
- package/lib/controllers/CollectionController.js +15 -1
- package/lib/controllers/Controller.js +28 -4
- package/lib/controllers/ControllerAction.js +18 -6
- package/lib/controllers/RelationController.js +9 -3
- package/lib/controllers/UserController.js +15 -1
- package/lib/controllers/index.js +7 -1
- package/lib/decorators/index.js +7 -1
- package/lib/decorators/parameters.js +4 -2
- package/lib/decorators/returns.js +4 -2
- package/lib/errors/DatabaseError.js +5 -19
- package/lib/errors/ResponseError.js +4 -14
- package/lib/errors/index.js +7 -1
- package/lib/graph/DitoGraphProcessor.js +5 -1
- package/lib/graph/expression.js +5 -1
- package/lib/graph/graph.js +18 -2
- package/lib/graph/index.js +7 -1
- package/lib/index.js +7 -1
- package/lib/lib/index.js +7 -1
- package/lib/middleware/findRoute.js +7 -1
- package/lib/middleware/index.js +7 -1
- package/lib/middleware/logRequests.js +4 -4
- package/lib/mixins/AssetMixin.js +4 -4
- package/lib/mixins/SessionMixin.js +4 -4
- package/lib/mixins/TimeStampedMixin.js +4 -4
- package/lib/mixins/UserMixin.js +10 -4
- package/lib/mixins/index.js +7 -1
- package/lib/models/Model.js +41 -22
- package/lib/models/definitions/filters.js +9 -1
- package/lib/models/definitions/properties.js +7 -1
- package/lib/models/definitions/scopes.js +9 -1
- package/lib/models/index.js +7 -1
- package/lib/query/QueryBuilder.js +11 -1
- package/lib/query/QueryFilters.js +11 -1
- package/lib/query/index.js +7 -1
- package/lib/schema/formats/index.js +7 -1
- package/lib/schema/index.js +10 -2
- package/lib/schema/keywords/index.js +7 -1
- package/lib/schema/properties.js +11 -1
- package/lib/schema/relations.js +18 -4
- package/lib/services/index.js +7 -1
- package/lib/storage/DiskStorage.js +7 -1
- package/lib/storage/Storage.js +5 -1
- package/lib/storage/index.js +7 -1
- package/lib/utils/emitter.js +5 -1
- package/lib/utils/index.js +15 -1
- package/lib/utils/json.js +9 -0
- package/lib/utils/object.js +9 -3
- package/package.json +31 -31
- package/src/app/Application.js +40 -11
- package/src/app/Validator.js +2 -1
- package/src/cli/console.js +3 -3
- package/src/cli/db/createMigration.js +3 -3
- package/src/cli/db/listAssetConfig.js +3 -1
- package/src/cli/db/migrate.js +4 -4
- package/src/cli/db/reset.js +4 -4
- package/src/cli/db/rollback.js +4 -4
- package/src/cli/db/seed.js +6 -6
- package/src/cli/db/unlock.js +2 -2
- package/src/cli/index.js +3 -3
- package/src/controllers/AdminController.js +3 -2
- package/src/controllers/Controller.js +8 -8
- package/src/controllers/ControllerAction.js +7 -5
- package/src/controllers/RelationController.js +2 -2
- package/src/decorators/parameters.js +2 -2
- package/src/decorators/returns.js +2 -2
- package/src/errors/DatabaseError.js +2 -23
- package/src/errors/ResponseError.js +1 -8
- package/src/middleware/logRequests.js +9 -9
- package/src/models/Model.js +13 -8
- package/src/utils/index.js +1 -0
- package/src/utils/json.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.274.0",
|
|
4
4
|
"description": "Dito.js Server – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/server",
|
|
@@ -25,34 +25,33 @@
|
|
|
25
25
|
"yarn": ">= 1.0.0"
|
|
26
26
|
},
|
|
27
27
|
"browserslist": [
|
|
28
|
-
"node 14"
|
|
28
|
+
"node >= 14"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@babel/core": "^7.
|
|
32
|
-
"@babel/runtime": "^7.
|
|
33
|
-
"@ditojs/admin": "^0.
|
|
34
|
-
"@ditojs/router": "^0.
|
|
35
|
-
"@ditojs/utils": "^0.
|
|
31
|
+
"@babel/core": "^7.17.5",
|
|
32
|
+
"@babel/runtime": "^7.17.2",
|
|
33
|
+
"@ditojs/admin": "^0.274.0",
|
|
34
|
+
"@ditojs/router": "^0.274.0",
|
|
35
|
+
"@ditojs/utils": "^0.274.0",
|
|
36
36
|
"@koa/cors": "^3.1.0",
|
|
37
37
|
"@koa/multer": "^3.0.0",
|
|
38
|
-
"@vue/cli-service": "^4.5.
|
|
38
|
+
"@vue/cli-service": "^4.5.15",
|
|
39
39
|
"ajv": "^7.2.4",
|
|
40
40
|
"ajv-formats": "^1.6.1",
|
|
41
|
-
"aws-sdk": "^2.
|
|
42
|
-
"axios": "^0.
|
|
43
|
-
"babel-loader": "^8.2.
|
|
41
|
+
"aws-sdk": "^2.1087.0",
|
|
42
|
+
"axios": "^0.26.0",
|
|
43
|
+
"babel-loader": "^8.2.3",
|
|
44
44
|
"bcryptjs": "^2.4.3",
|
|
45
|
-
"bytes": "^3.1.
|
|
46
|
-
"
|
|
47
|
-
"core-js": "^3.18.1",
|
|
45
|
+
"bytes": "^3.1.2",
|
|
46
|
+
"core-js": "^3.21.1",
|
|
48
47
|
"data-uri-to-buffer": "^3.0.1",
|
|
49
|
-
"eventemitter2": "^6.4.
|
|
48
|
+
"eventemitter2": "^6.4.5",
|
|
50
49
|
"file-type": "^16.5.3",
|
|
51
|
-
"fs-extra": "^10.0.
|
|
50
|
+
"fs-extra": "^10.0.1",
|
|
52
51
|
"html-webpack-tags-plugin": "^2.0.17",
|
|
53
|
-
"image-size": "^1.0.
|
|
54
|
-
"is-svg": "^4.3.
|
|
55
|
-
"koa": "^2.13.
|
|
52
|
+
"image-size": "^1.0.1",
|
|
53
|
+
"is-svg": "^4.3.2",
|
|
54
|
+
"koa": "^2.13.4",
|
|
56
55
|
"koa-bodyparser": "^4.3.0",
|
|
57
56
|
"koa-compose": "^4.1.0",
|
|
58
57
|
"koa-compress": "^5.1.0",
|
|
@@ -66,14 +65,15 @@
|
|
|
66
65
|
"koa-session": "^6.2.0",
|
|
67
66
|
"koa-static": "^5.0.0",
|
|
68
67
|
"koa-webpack": "^6.0.0",
|
|
69
|
-
"mime-types": "^2.1.
|
|
70
|
-
"multer": "^1.4.
|
|
71
|
-
"multer-s3": "^2.
|
|
72
|
-
"nanoid": "^3.1
|
|
73
|
-
"parse-duration": "^1.0.
|
|
68
|
+
"mime-types": "^2.1.34",
|
|
69
|
+
"multer": "^1.4.4",
|
|
70
|
+
"multer-s3": "^2.10.0",
|
|
71
|
+
"nanoid": "^3.3.1",
|
|
72
|
+
"parse-duration": "^1.0.2",
|
|
74
73
|
"passport-local": "^1.0.0",
|
|
75
74
|
"passthrough-counter": "^1.0.0",
|
|
76
|
-
"
|
|
75
|
+
"picocolors": "^1.0.0",
|
|
76
|
+
"pino": "^6.14.0",
|
|
77
77
|
"pino-pretty": "^6.0.0",
|
|
78
78
|
"pluralize": "^8.0.0",
|
|
79
79
|
"repl": "^0.1.3",
|
|
@@ -89,16 +89,16 @@
|
|
|
89
89
|
"objection": "^2.2.0"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@babel/cli": "^7.
|
|
93
|
-
"@babel/preset-env": "^7.
|
|
94
|
-
"@ditojs/babel-preset": "^0.
|
|
92
|
+
"@babel/cli": "^7.17.6",
|
|
93
|
+
"@babel/preset-env": "^7.16.11",
|
|
94
|
+
"@ditojs/babel-preset": "^0.274.0",
|
|
95
95
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
96
96
|
"babel-plugin-module-resolver": "^4.1.0",
|
|
97
97
|
"knex": "^0.21.21",
|
|
98
|
-
"objection": "^2.2.
|
|
99
|
-
"pg": "^8.7.
|
|
98
|
+
"objection": "^2.2.18",
|
|
99
|
+
"pg": "^8.7.3",
|
|
100
100
|
"rimraf": "^3.0.2",
|
|
101
101
|
"sqlite3": "^5.0.2"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "0ebfe0bb8913f9d338bb91a0a507e7a4c6e49ecb"
|
|
104
104
|
}
|
package/src/app/Application.js
CHANGED
|
@@ -2,7 +2,7 @@ import Koa from 'koa'
|
|
|
2
2
|
import Knex from 'knex'
|
|
3
3
|
import util from 'util'
|
|
4
4
|
import axios from 'axios'
|
|
5
|
-
import
|
|
5
|
+
import pico from 'picocolors'
|
|
6
6
|
import zlib from 'zlib'
|
|
7
7
|
import pino from 'pino'
|
|
8
8
|
import os from 'os'
|
|
@@ -23,7 +23,13 @@ import { Controller, AdminController } from '@/controllers'
|
|
|
23
23
|
import { Service } from '@/services'
|
|
24
24
|
import { Storage } from '@/storage'
|
|
25
25
|
import { convertSchema } from '@/schema'
|
|
26
|
-
import {
|
|
26
|
+
import { formatJson } from '@/utils'
|
|
27
|
+
import {
|
|
28
|
+
ResponseError,
|
|
29
|
+
ValidationError,
|
|
30
|
+
DatabaseError,
|
|
31
|
+
AssetError
|
|
32
|
+
} from '@/errors'
|
|
27
33
|
import SessionStore from './SessionStore'
|
|
28
34
|
import { Validator } from './Validator'
|
|
29
35
|
import {
|
|
@@ -157,7 +163,7 @@ export class Application extends Koa {
|
|
|
157
163
|
}
|
|
158
164
|
if (Object.keys(data).length > 0) {
|
|
159
165
|
console.info(
|
|
160
|
-
|
|
166
|
+
pico.yellow.bold(`\n${modelClass.name}:\n`),
|
|
161
167
|
util.inspect(data, {
|
|
162
168
|
colors: true,
|
|
163
169
|
depth: null,
|
|
@@ -472,11 +478,26 @@ export class Application extends Koa {
|
|
|
472
478
|
}
|
|
473
479
|
}
|
|
474
480
|
|
|
475
|
-
createValidationError({ type, message, errors, options }) {
|
|
481
|
+
createValidationError({ type, message, errors, options, json }) {
|
|
476
482
|
return new ValidationError({
|
|
477
483
|
type,
|
|
478
484
|
message,
|
|
479
|
-
errors: this.validator.parseErrors(errors, options)
|
|
485
|
+
errors: this.validator.parseErrors(errors, options),
|
|
486
|
+
// Only include the JSON data in the error if `log.errors.json`is set.
|
|
487
|
+
json: this.config.log.errors?.json ? json : undefined
|
|
488
|
+
})
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
createDatabaseError(error) {
|
|
492
|
+
// Remove knex SQL query and move to separate `sql` property.
|
|
493
|
+
// TODO: Fix this properly in Knex / Objection instead, see:
|
|
494
|
+
// https://gitter.im/Vincit/objection.js?at=5a68728f5a9ebe4f75ca40b0
|
|
495
|
+
const [, sql, message] = error.message.match(/^([\s\S]*) - ([\s\S]*?)$/) ||
|
|
496
|
+
[null, null, error.message]
|
|
497
|
+
return new DatabaseError(error, {
|
|
498
|
+
message,
|
|
499
|
+
// Only include the SQL query in the error if `log.errors.sql`is set.
|
|
500
|
+
sql: this.config.log.errors?.sql ? sql : undefined
|
|
480
501
|
})
|
|
481
502
|
}
|
|
482
503
|
|
|
@@ -485,13 +506,15 @@ export class Application extends Koa {
|
|
|
485
506
|
|
|
486
507
|
this.use(attachLogger(this.logger))
|
|
487
508
|
|
|
488
|
-
this.use(handleError())
|
|
489
509
|
if (app.responseTime !== false) {
|
|
490
510
|
this.use(responseTime(getOptions(app.responseTime)))
|
|
491
511
|
}
|
|
492
512
|
if (log.requests) {
|
|
493
513
|
this.use(logRequests())
|
|
494
514
|
}
|
|
515
|
+
// Needs to be positioned after the request logger to log the correct
|
|
516
|
+
// response status.
|
|
517
|
+
this.use(handleError())
|
|
495
518
|
if (app.helmet !== false) {
|
|
496
519
|
this.use(helmet(getOptions(app.helmet)))
|
|
497
520
|
}
|
|
@@ -605,6 +628,12 @@ export class Application extends Koa {
|
|
|
605
628
|
}
|
|
606
629
|
}
|
|
607
630
|
this.knex = Knex(knex)
|
|
631
|
+
// Support PostgreSQL type parser mappings in the config.
|
|
632
|
+
if (knex.client === 'postgresql' && knex.typeParsers) {
|
|
633
|
+
for (const [type, parser] of Object.entries(knex.typeParsers)) {
|
|
634
|
+
this.knex.client.driver.types.setTypeParser(type, parser)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
608
637
|
if (log.sql) {
|
|
609
638
|
this.setupKnexLogging()
|
|
610
639
|
}
|
|
@@ -655,7 +684,7 @@ export class Application extends Koa {
|
|
|
655
684
|
|
|
656
685
|
formatError(err) {
|
|
657
686
|
const message = err.toJSON
|
|
658
|
-
?
|
|
687
|
+
? formatJson(err.toJSON())
|
|
659
688
|
: err.message || err
|
|
660
689
|
const str = `${err.name}: ${message}`
|
|
661
690
|
return err.stack && this.config.log.errors?.stack !== false
|
|
@@ -823,13 +852,13 @@ export class Application extends Koa {
|
|
|
823
852
|
if (!data) {
|
|
824
853
|
console.info(
|
|
825
854
|
`${
|
|
826
|
-
|
|
855
|
+
pico.red('INFO:')
|
|
827
856
|
} Asset ${
|
|
828
|
-
|
|
857
|
+
pico.green(`'${file.name}'`)
|
|
829
858
|
} is from a foreign source, fetching from ${
|
|
830
|
-
|
|
859
|
+
pico.green(`'${file.url}'`)
|
|
831
860
|
} and adding to storage ${
|
|
832
|
-
|
|
861
|
+
pico.green(`'${storage.name}'`)
|
|
833
862
|
}...`
|
|
834
863
|
)
|
|
835
864
|
const response = await axios.request({
|
package/src/app/Validator.js
CHANGED
|
@@ -2,6 +2,7 @@ import objection from 'objection'
|
|
|
2
2
|
import Ajv from 'ajv'
|
|
3
3
|
import addFormats from 'ajv-formats'
|
|
4
4
|
import { isArray, isObject, clone, isAsync, isPromise } from '@ditojs/utils'
|
|
5
|
+
import { formatJson } from '@/utils'
|
|
5
6
|
import * as schema from '@/schema'
|
|
6
7
|
|
|
7
8
|
// Dito does not rely on objection.AjvValidator but instead implements its own
|
|
@@ -83,7 +84,7 @@ export class Validator extends objection.Validator {
|
|
|
83
84
|
}
|
|
84
85
|
return opts
|
|
85
86
|
}, {})
|
|
86
|
-
const cacheKey =
|
|
87
|
+
const cacheKey = formatJson(opts, false)
|
|
87
88
|
const { ajv } = this.ajvCache[cacheKey] || (this.ajvCache[cacheKey] = {
|
|
88
89
|
ajv: this.createAjv(opts),
|
|
89
90
|
options
|
package/src/cli/console.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import repl from 'repl'
|
|
2
2
|
import path from 'path'
|
|
3
3
|
import fs from 'fs-extra'
|
|
4
|
-
import
|
|
4
|
+
import pico from 'picocolors'
|
|
5
5
|
import objection from 'objection'
|
|
6
6
|
import { isFunction, deindent } from '@ditojs/utils'
|
|
7
7
|
|
|
@@ -100,11 +100,11 @@ function displayUsage(app, config, details) {
|
|
|
100
100
|
Dito Console
|
|
101
101
|
|
|
102
102
|
Available references:
|
|
103
|
-
- Dito app: ${
|
|
103
|
+
- Dito app: ${pico.cyan('app')}
|
|
104
104
|
${
|
|
105
105
|
modelHandleNames.length > 0
|
|
106
106
|
? ` - Dito models: ${
|
|
107
|
-
modelHandleNames.map(m =>
|
|
107
|
+
modelHandleNames.map(m => pico.cyan(m)).join(', ')
|
|
108
108
|
}`
|
|
109
109
|
: ''
|
|
110
110
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import fs from 'fs-extra'
|
|
3
|
-
import
|
|
3
|
+
import pico from 'picocolors'
|
|
4
4
|
import { getRelationClass, isThroughRelationClass } from '@/schema'
|
|
5
5
|
import {
|
|
6
6
|
isObject, isArray, isString, deindent, capitalize
|
|
@@ -52,7 +52,7 @@ export async function createMigration(app, name, ...modelNames) {
|
|
|
52
52
|
const file = path.join(migrationDir, filename)
|
|
53
53
|
if (await fs.exists(file)) {
|
|
54
54
|
// This should never happen, but let's be on the safe side here:
|
|
55
|
-
console.info(
|
|
55
|
+
console.info(pico.red(`Migration '${filename}' already exists.`))
|
|
56
56
|
return false
|
|
57
57
|
} else {
|
|
58
58
|
await fs.writeFile(file, deindent`
|
|
@@ -64,7 +64,7 @@ export async function createMigration(app, name, ...modelNames) {
|
|
|
64
64
|
${getCode(dropTables)}
|
|
65
65
|
}
|
|
66
66
|
`)
|
|
67
|
-
console.info(
|
|
67
|
+
console.info(pico.cyan(`Migration '${filename}' successfully created.`))
|
|
68
68
|
return true
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { formatJson } from '@/utils'
|
|
2
|
+
|
|
1
3
|
export async function listAssetConfig(app, ...args) {
|
|
2
4
|
const assetConfig = app.getAssetConfig({
|
|
3
5
|
models: args.length > 0 ? args : Object.keys(app.models),
|
|
4
6
|
normalizeDbNames: true
|
|
5
7
|
})
|
|
6
|
-
console.info(
|
|
8
|
+
console.info(formatJson(assetConfig))
|
|
7
9
|
return true
|
|
8
10
|
}
|
package/src/cli/db/migrate.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pico from 'picocolors'
|
|
2
2
|
|
|
3
3
|
export async function migrate(knex) {
|
|
4
4
|
const [batch, log] = await knex.migrate.latest()
|
|
5
5
|
console.info(log.length === 0
|
|
6
|
-
?
|
|
7
|
-
:
|
|
8
|
-
|
|
6
|
+
? pico.cyan('Already up to date')
|
|
7
|
+
: pico.green(`Batch ${batch} run: ${log.length} migrations\n`) +
|
|
8
|
+
pico.cyan(log.join('\n')))
|
|
9
9
|
return true
|
|
10
10
|
}
|
package/src/cli/db/reset.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pico from 'picocolors'
|
|
2
2
|
import { migrate } from './migrate'
|
|
3
3
|
|
|
4
4
|
export async function reset(knex) {
|
|
@@ -11,10 +11,10 @@ export async function reset(knex) {
|
|
|
11
11
|
migrations.push(...log)
|
|
12
12
|
}
|
|
13
13
|
console.info(migrations.length === 0
|
|
14
|
-
?
|
|
15
|
-
:
|
|
14
|
+
? pico.cyan('Already at the base migration')
|
|
15
|
+
: pico.green(`${batches.length > 1 ? 'Batches' : 'Batch'} ${batches} ` +
|
|
16
16
|
`rolled back: ${migrations.length} migrations\n`) +
|
|
17
|
-
|
|
17
|
+
pico.cyan(migrations.join('\n')))
|
|
18
18
|
await migrate(knex)
|
|
19
19
|
return true
|
|
20
20
|
}
|
package/src/cli/db/rollback.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pico from 'picocolors'
|
|
2
2
|
|
|
3
3
|
export async function rollback(knex) {
|
|
4
4
|
const [batch, log] = await knex.migrate.rollback()
|
|
5
5
|
console.info(log.length === 0
|
|
6
|
-
?
|
|
7
|
-
:
|
|
8
|
-
|
|
6
|
+
? pico.cyan('Already at the base migration')
|
|
7
|
+
: pico.green(`Batch ${batch} rolled back: ${log.length} migrations\n`) +
|
|
8
|
+
pico.cyan(log.join('\n')))
|
|
9
9
|
return true
|
|
10
10
|
}
|
package/src/cli/db/seed.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import fs from 'fs-extra'
|
|
3
|
-
import
|
|
3
|
+
import pico from 'picocolors'
|
|
4
4
|
import util from 'util'
|
|
5
5
|
import pluralize from 'pluralize'
|
|
6
6
|
import { isFunction, isArray, camelize } from '@ditojs/utils'
|
|
@@ -57,18 +57,18 @@ async function handleSeed(app, base, seed, modelClass) {
|
|
|
57
57
|
}
|
|
58
58
|
if (isArray(res)) {
|
|
59
59
|
console.info(
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
pico.green(`${base}:`),
|
|
61
|
+
pico.cyan(`${res.length} seed records created.`)
|
|
62
62
|
)
|
|
63
63
|
} else {
|
|
64
64
|
console.info(
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
pico.red(`${base}:`),
|
|
66
|
+
pico.cyan('No seed records created.')
|
|
67
67
|
)
|
|
68
68
|
}
|
|
69
69
|
} catch (err) {
|
|
70
70
|
console.error(
|
|
71
|
-
|
|
71
|
+
pico.red(`${base}:`),
|
|
72
72
|
util.inspect(err, {
|
|
73
73
|
colors: true,
|
|
74
74
|
depth: null,
|
package/src/cli/db/unlock.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pico from 'picocolors'
|
|
2
2
|
|
|
3
3
|
export async function unlock(knex) {
|
|
4
4
|
await knex.migrate.forceFreeMigrationsLock()
|
|
5
5
|
console.info(
|
|
6
|
-
|
|
6
|
+
pico.green(`Successfully unlocked the migrations lock table`)
|
|
7
7
|
)
|
|
8
8
|
return true
|
|
9
9
|
}
|
package/src/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env babel-node
|
|
2
2
|
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
4
|
+
import pico from 'picocolors'
|
|
5
5
|
import Knex from 'knex'
|
|
6
6
|
import { isPlainObject, isFunction, camelize } from '@ditojs/utils'
|
|
7
7
|
import * as db from './db'
|
|
@@ -47,10 +47,10 @@ async function execute() {
|
|
|
47
47
|
} catch (err) {
|
|
48
48
|
if (err instanceof Error) {
|
|
49
49
|
console.error(
|
|
50
|
-
|
|
50
|
+
pico.red(`${err.detail ? `${err.detail}\n` : ''}${err.stack}`)
|
|
51
51
|
)
|
|
52
52
|
} else {
|
|
53
|
-
console.error(
|
|
53
|
+
console.error(pico.red(err))
|
|
54
54
|
}
|
|
55
55
|
process.exit(1)
|
|
56
56
|
}
|
|
@@ -6,8 +6,9 @@ import koaWebpack from 'koa-webpack'
|
|
|
6
6
|
import historyApiFallback from 'koa-connect-history-api-fallback'
|
|
7
7
|
import VueService from '@vue/cli-service'
|
|
8
8
|
import HtmlWebpackTagsPlugin from 'html-webpack-tags-plugin'
|
|
9
|
-
import { ControllerError } from '@/errors'
|
|
10
9
|
import { Controller } from './Controller'
|
|
10
|
+
import { ControllerError } from '@/errors'
|
|
11
|
+
import { formatJson } from '@/utils'
|
|
11
12
|
import { isString, isObject } from '@ditojs/utils'
|
|
12
13
|
|
|
13
14
|
export class AdminController extends Controller {
|
|
@@ -59,7 +60,7 @@ export class AdminController extends Controller {
|
|
|
59
60
|
sendDitoObject(ctx) {
|
|
60
61
|
// Send back the global dito object as JavaScript code.
|
|
61
62
|
ctx.type = 'text/javascript'
|
|
62
|
-
ctx.body = `window.dito = ${
|
|
63
|
+
ctx.body = `window.dito = ${formatJson(this.getDitoObject())}`
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
middleware() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pico from 'picocolors'
|
|
2
2
|
import { getOwnProperty, getAllKeys, describeFunction } from '@/utils'
|
|
3
3
|
import { EventEmitter } from '@/lib'
|
|
4
4
|
import ControllerAction from './ControllerAction'
|
|
@@ -44,11 +44,11 @@ export class Controller {
|
|
|
44
44
|
this.url = namespace ? `/${namespace}${url}` : url
|
|
45
45
|
this.log(
|
|
46
46
|
`${
|
|
47
|
-
namespace ?
|
|
47
|
+
namespace ? pico.green(`/${namespace}/`) : ''
|
|
48
48
|
}${
|
|
49
|
-
|
|
49
|
+
pico.cyan(path)
|
|
50
50
|
}${
|
|
51
|
-
|
|
51
|
+
pico.white(':')
|
|
52
52
|
}`,
|
|
53
53
|
this.level
|
|
54
54
|
)
|
|
@@ -92,13 +92,13 @@ export class Controller {
|
|
|
92
92
|
setupRoute(verb, url, transacted, authorize, action, handlers) {
|
|
93
93
|
this.log(
|
|
94
94
|
`${
|
|
95
|
-
|
|
95
|
+
pico.magenta(verb.toUpperCase())
|
|
96
96
|
} ${
|
|
97
|
-
|
|
97
|
+
pico.green(this.url)
|
|
98
98
|
}${
|
|
99
|
-
|
|
99
|
+
pico.cyan(url.slice(this.url.length))
|
|
100
100
|
} ${
|
|
101
|
-
|
|
101
|
+
pico.white(this.describeAuthorize(authorize))
|
|
102
102
|
}`,
|
|
103
103
|
this.level + 1
|
|
104
104
|
)
|
|
@@ -165,8 +165,9 @@ export default class ControllerAction {
|
|
|
165
165
|
if (errors.length > 0) {
|
|
166
166
|
throw this.createValidationError({
|
|
167
167
|
type: 'ParameterValidation',
|
|
168
|
-
message:
|
|
169
|
-
errors
|
|
168
|
+
message: 'The provided action parameters are not valid',
|
|
169
|
+
errors,
|
|
170
|
+
json: getData()
|
|
170
171
|
})
|
|
171
172
|
}
|
|
172
173
|
}
|
|
@@ -189,8 +190,9 @@ export default class ControllerAction {
|
|
|
189
190
|
} catch (error) {
|
|
190
191
|
throw this.createValidationError({
|
|
191
192
|
type: 'ResultValidation',
|
|
192
|
-
message:
|
|
193
|
-
errors: error.errors
|
|
193
|
+
message: 'The returned action result is not valid',
|
|
194
|
+
errors: error.errors,
|
|
195
|
+
json: getResult()
|
|
194
196
|
})
|
|
195
197
|
}
|
|
196
198
|
}
|
|
@@ -229,7 +231,7 @@ export default class ControllerAction {
|
|
|
229
231
|
|
|
230
232
|
coerceValue(type, value, modelOptions) {
|
|
231
233
|
// See if param needs additional coercion:
|
|
232
|
-
if (['date', 'datetime', 'timestamp'].includes(type)) {
|
|
234
|
+
if (value && ['date', 'datetime', 'timestamp'].includes(type)) {
|
|
233
235
|
value = new Date(value)
|
|
234
236
|
} else {
|
|
235
237
|
// See if the defined type(s) require coercion to objects:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pico from 'picocolors'
|
|
2
2
|
import { ControllerError } from '@/errors'
|
|
3
3
|
import { CollectionController } from './CollectionController'
|
|
4
4
|
import { setupPropertyInheritance, getScope } from '@/utils'
|
|
@@ -32,7 +32,7 @@ export class RelationController extends CollectionController {
|
|
|
32
32
|
// Initialize:
|
|
33
33
|
this.path = this.app.normalizePath(this.name)
|
|
34
34
|
this.url = `${this.parent.url}/${this.parent.getPath('member', this.path)}`
|
|
35
|
-
this.log(`${
|
|
35
|
+
this.log(`${pico.blue(this.path)}${pico.white(':')}`, this.level)
|
|
36
36
|
// Copy over all fields in the relation object except the ones that are
|
|
37
37
|
// going to be inherited in `setup()` (relation, member, allow), for
|
|
38
38
|
// settings like scope, etc.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isArray, isObject } from '@ditojs/utils'
|
|
2
|
-
import { createDecorator, deprecate } from '@/utils'
|
|
2
|
+
import { createDecorator, deprecate, formatJson } from '@/utils'
|
|
3
3
|
|
|
4
4
|
export function parameters(parameters, options) {
|
|
5
5
|
if (isObject(parameters)) {
|
|
@@ -7,7 +7,7 @@ export function parameters(parameters, options) {
|
|
|
7
7
|
if (!isObject(first)) {
|
|
8
8
|
deprecate(
|
|
9
9
|
`@parameters(${
|
|
10
|
-
|
|
10
|
+
formatJson(parameters, false)
|
|
11
11
|
}) with parameter schema object is deprecated: Schema object should be passed nested inside an array or object definition.`
|
|
12
12
|
)
|
|
13
13
|
parameters = [...arguments]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isObject } from '@ditojs/utils'
|
|
2
|
-
import { createDecorator } from '@/utils'
|
|
2
|
+
import { createDecorator, formatJson } from '@/utils'
|
|
3
3
|
|
|
4
4
|
export function returns(returns, options) {
|
|
5
5
|
if (!isObject(returns)) {
|
|
6
6
|
throw new Error(
|
|
7
7
|
`@returns(${
|
|
8
|
-
|
|
8
|
+
formatJson(returns, false)
|
|
9
9
|
}) needs to be defined using an object parameter definition`
|
|
10
10
|
)
|
|
11
11
|
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from 'objection'
|
|
9
9
|
|
|
10
10
|
export class DatabaseError extends WrappedError {
|
|
11
|
-
constructor(error) {
|
|
11
|
+
constructor(error, overrides) {
|
|
12
12
|
const status =
|
|
13
13
|
error instanceof CheckViolationError ? 400
|
|
14
14
|
: error instanceof NotNullViolationError ? 400
|
|
@@ -16,28 +16,7 @@ export class DatabaseError extends WrappedError {
|
|
|
16
16
|
: error instanceof DataError ? 400
|
|
17
17
|
: error instanceof DBError ? 500
|
|
18
18
|
: 400
|
|
19
|
-
|
|
20
|
-
// TODO: Fix this properly in Knex / Objection instead, see:
|
|
21
|
-
// https://gitter.im/Vincit/objection.js?at=5a68728f5a9ebe4f75ca40b0
|
|
22
|
-
const [, sql, message] = error.message.match(/^([\s\S]*) - ([\s\S]*?)$/) ||
|
|
23
|
-
[null, null, error.message]
|
|
24
|
-
const overrides = {
|
|
25
|
-
type: error.constructor.name,
|
|
26
|
-
message,
|
|
27
|
-
sql,
|
|
28
|
-
status
|
|
29
|
-
}
|
|
19
|
+
overrides = { type: error.constructor.name, status, ...overrides }
|
|
30
20
|
super(error, overrides, { message: 'Database error', status })
|
|
31
21
|
}
|
|
32
|
-
|
|
33
|
-
toJSON() {
|
|
34
|
-
// Remove SQL query from displayed data in front-end when not in development
|
|
35
|
-
// or test.
|
|
36
|
-
if (process.env.NODE_ENV !== 'development' ||
|
|
37
|
-
process.env.NODE_ENV !== 'test') {
|
|
38
|
-
const { sql, ...data } = this.data
|
|
39
|
-
return data
|
|
40
|
-
}
|
|
41
|
-
return this.data
|
|
42
|
-
}
|
|
43
22
|
}
|
|
@@ -21,14 +21,7 @@ export class ResponseError extends Error {
|
|
|
21
21
|
? { message: error }
|
|
22
22
|
: error || {}
|
|
23
23
|
const { status, ...data } = { ...defaults, ...object }
|
|
24
|
-
|
|
25
|
-
if (process.env.NODE_ENV === 'test' && error === object) {
|
|
26
|
-
// Include full JSON error in message during tests, for better reporting.
|
|
27
|
-
const { message: _, ...rest } = data
|
|
28
|
-
if (Object.keys(rest).length > 0) {
|
|
29
|
-
message = `${message}\nError Data:\n${JSON.stringify(rest, null, 2)}`
|
|
30
|
-
}
|
|
31
|
-
}
|
|
24
|
+
const { message, code } = data
|
|
32
25
|
super(message)
|
|
33
26
|
this.name = this.constructor.name
|
|
34
27
|
this.status = status
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Middleware inspired by 'koa-logger'. Adapted and extended to our needs.
|
|
3
3
|
*/
|
|
4
4
|
import bytes from 'bytes'
|
|
5
|
-
import
|
|
5
|
+
import pico from 'picocolors'
|
|
6
6
|
import Counter from 'passthrough-counter'
|
|
7
7
|
|
|
8
8
|
export function logRequests({ ignoreUrls } = {}) {
|
|
@@ -58,11 +58,11 @@ function logRequest(ctx) {
|
|
|
58
58
|
logger.trace(
|
|
59
59
|
{ req: ctx.req },
|
|
60
60
|
`${
|
|
61
|
-
|
|
61
|
+
pico.gray('<--')
|
|
62
62
|
} ${
|
|
63
|
-
|
|
63
|
+
pico.bold(ctx.method)
|
|
64
64
|
} ${
|
|
65
|
-
|
|
65
|
+
pico.gray(ctx.originalUrl)
|
|
66
66
|
}`
|
|
67
67
|
)
|
|
68
68
|
}
|
|
@@ -93,15 +93,15 @@ function logResponse({ ctx, start, length, err }) {
|
|
|
93
93
|
logger[level](
|
|
94
94
|
{ req: ctx.req, res: ctx.res },
|
|
95
95
|
`${
|
|
96
|
-
|
|
96
|
+
pico.bold(ctx.method)
|
|
97
97
|
} ${
|
|
98
|
-
|
|
98
|
+
pico.gray(ctx.originalUrl)
|
|
99
99
|
} ${
|
|
100
|
-
|
|
100
|
+
pico[statusColor](status)
|
|
101
101
|
} ${
|
|
102
|
-
|
|
102
|
+
pico.gray(formattedTime)
|
|
103
103
|
} ${
|
|
104
|
-
|
|
104
|
+
pico.gray(formattedLength)
|
|
105
105
|
}`
|
|
106
106
|
)
|
|
107
107
|
}
|