@ditojs/server 2.48.0 → 2.49.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/package.json +8 -8
- package/src/app/Validator.js +22 -8
- package/src/cli/console.js +5 -5
- package/src/controllers/ControllerAction.js +2 -2
- package/src/models/Model.js +27 -9
- package/src/schema/index.js +1 -0
- package/src/schema/keywords/_extend.js +31 -0
- package/src/schema/keywords/_instanceof.js +2 -2
- package/src/schema/keywords/index.js +1 -0
- package/src/schema/properties.js +50 -11
- package/src/schema/properties.test.js +99 -26
- package/src/schema/types/_asset.js +31 -0
- package/src/schema/types/index.js +1 -0
- package/src/storage/AssetFile.js +0 -1
- package/src/storage/Storage.js +1 -1
- package/types/index.d.ts +5 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.49.0",
|
|
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",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"node >= 18"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@ditojs/admin": "^2.
|
|
29
|
-
"@ditojs/build": "^2.
|
|
30
|
-
"@ditojs/router": "^2.
|
|
31
|
-
"@ditojs/utils": "^2.
|
|
28
|
+
"@ditojs/admin": "^2.49.0",
|
|
29
|
+
"@ditojs/build": "^2.49.0",
|
|
30
|
+
"@ditojs/router": "^2.49.0",
|
|
31
|
+
"@ditojs/utils": "^2.49.0",
|
|
32
32
|
"@koa/cors": "^5.0.0",
|
|
33
33
|
"@koa/multer": "^3.1.0",
|
|
34
34
|
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"pino-pretty": "^13.0.0",
|
|
67
67
|
"pluralize": "^8.0.0",
|
|
68
68
|
"repl": "^0.1.3",
|
|
69
|
-
"type-fest": "^4.
|
|
69
|
+
"type-fest": "^4.41.0",
|
|
70
70
|
"uuid": "^11.1.0"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
@@ -84,11 +84,11 @@
|
|
|
84
84
|
"@types/koa-session": "^6.4.5",
|
|
85
85
|
"@types/koa-static": "^4.0.4",
|
|
86
86
|
"@types/koa__cors": "^5.0.0",
|
|
87
|
-
"@types/node": "^22.15.
|
|
87
|
+
"@types/node": "^22.15.17",
|
|
88
88
|
"knex": "^3.1.0",
|
|
89
89
|
"objection": "^3.1.5",
|
|
90
90
|
"typescript": "^5.8.3"
|
|
91
91
|
},
|
|
92
92
|
"types": "types",
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "8276ff1db64a82c03e1569e2403f378b0201ea3c"
|
|
94
94
|
}
|
package/src/app/Validator.js
CHANGED
|
@@ -3,10 +3,15 @@ import Ajv from 'ajv/dist/2020.js'
|
|
|
3
3
|
import addFormats from 'ajv-formats'
|
|
4
4
|
import { isArray, isObject, clone, isAsync, isPromise } from '@ditojs/utils'
|
|
5
5
|
import { formatJson } from '../utils/json.js'
|
|
6
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
keywords as defaultKeywords,
|
|
8
|
+
formats as defaultFormats,
|
|
9
|
+
types as defaultTypes,
|
|
10
|
+
convertSchema
|
|
11
|
+
} from '../schema/index.js'
|
|
7
12
|
|
|
8
|
-
// Dito does not rely on objection.AjvValidator but instead implements its
|
|
9
|
-
// validator instance that is shared across the whole app and handles schema
|
|
13
|
+
// Dito.js does not rely on objection.AjvValidator but instead implements its
|
|
14
|
+
// own validator instance that is shared across the whole app and handles schema
|
|
10
15
|
// compilation and caching differently:
|
|
11
16
|
// It relies on Ajv's addSchema() / getSchema() pattern in conjunction with the
|
|
12
17
|
// `schemaId: '$id'` option, and each schema is assigned an $id based on the
|
|
@@ -14,23 +19,25 @@ import * as schema from '../schema/index.js'
|
|
|
14
19
|
// easily validate nested structures.
|
|
15
20
|
|
|
16
21
|
export class Validator extends objection.Validator {
|
|
17
|
-
constructor({ options, keywords, formats } = {}) {
|
|
22
|
+
constructor({ options, keywords, formats, types } = {}) {
|
|
18
23
|
super()
|
|
19
24
|
|
|
20
25
|
this.options = {
|
|
21
26
|
...defaultOptions,
|
|
22
27
|
...options
|
|
23
28
|
}
|
|
24
|
-
|
|
25
29
|
this.keywords = {
|
|
26
|
-
...
|
|
30
|
+
...defaultKeywords,
|
|
27
31
|
...keywords
|
|
28
32
|
}
|
|
29
|
-
|
|
30
33
|
this.formats = {
|
|
31
|
-
...
|
|
34
|
+
...defaultFormats,
|
|
32
35
|
...formats
|
|
33
36
|
}
|
|
37
|
+
this.types = {
|
|
38
|
+
...defaultTypes,
|
|
39
|
+
...types
|
|
40
|
+
}
|
|
34
41
|
|
|
35
42
|
this.schemas = []
|
|
36
43
|
|
|
@@ -71,6 +78,13 @@ export class Validator extends objection.Validator {
|
|
|
71
78
|
})
|
|
72
79
|
)
|
|
73
80
|
|
|
81
|
+
addSchemas(this.types, (type, schema) => {
|
|
82
|
+
ajv.addSchema({
|
|
83
|
+
$id: type,
|
|
84
|
+
...this.processSchema(convertSchema(schema), options)
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
74
88
|
// Also add all model schemas that were already compiled so far.
|
|
75
89
|
for (const schema of this.schemas) {
|
|
76
90
|
ajv.addSchema(this.processSchema(schema, options))
|
package/src/cli/console.js
CHANGED
|
@@ -32,7 +32,7 @@ export default async function startConsole(app, config) {
|
|
|
32
32
|
server.eval = wrapEval(server)
|
|
33
33
|
|
|
34
34
|
server.defineCommand('usage', {
|
|
35
|
-
help: 'Detailed Dito Console usage information',
|
|
35
|
+
help: 'Detailed Dito.js Console usage information',
|
|
36
36
|
action() {
|
|
37
37
|
displayUsage(app, config, true)
|
|
38
38
|
this.displayPrompt()
|
|
@@ -40,7 +40,7 @@ export default async function startConsole(app, config) {
|
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
server.defineCommand('models', {
|
|
43
|
-
help: 'Display available Dito models',
|
|
43
|
+
help: 'Display available Dito.js models',
|
|
44
44
|
action() {
|
|
45
45
|
console.info(Object.keys(app.models).join(', '))
|
|
46
46
|
this.displayPrompt()
|
|
@@ -99,13 +99,13 @@ function displayUsage(app, config, details) {
|
|
|
99
99
|
console.info(deindent`
|
|
100
100
|
|
|
101
101
|
------------------------------------------------------------
|
|
102
|
-
Dito Console
|
|
102
|
+
Dito.js Console
|
|
103
103
|
|
|
104
104
|
Available references:
|
|
105
|
-
- Dito app: ${pico.cyan('app')}
|
|
105
|
+
- Dito.js app: ${pico.cyan('app')}
|
|
106
106
|
${
|
|
107
107
|
modelHandleNames.length > 0
|
|
108
|
-
? ` - Dito models: ${
|
|
108
|
+
? ` - Dito.js models: ${
|
|
109
109
|
modelHandleNames.map(m => pico.cyan(m)).join(', ')
|
|
110
110
|
}`
|
|
111
111
|
: ''
|
|
@@ -300,7 +300,7 @@ export default class ControllerAction {
|
|
|
300
300
|
if (objectType) {
|
|
301
301
|
if (value && isString(value)) {
|
|
302
302
|
if (!/^\{.*\}$/.test(value)) {
|
|
303
|
-
// Convert simplified Dito object notation to JSON, supporting:
|
|
303
|
+
// Convert simplified Dito.js object notation to JSON, supporting:
|
|
304
304
|
// - `"key1":X, "key2":Y` (curly braces are added and parsed through
|
|
305
305
|
// `JSON.parse()`)
|
|
306
306
|
// - `key1:X,key2:Y` (a simple parser is applied, splitting into
|
|
@@ -329,7 +329,7 @@ export default class ControllerAction {
|
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
if (objectType !== 'object' && isObject(value)) {
|
|
332
|
-
// Convert the Pojo to the desired Dito model:
|
|
332
|
+
// Convert the Pojo to the desired Dito.js model:
|
|
333
333
|
const modelClass = this.app.models[objectType]
|
|
334
334
|
if (modelClass && !(value instanceof modelClass)) {
|
|
335
335
|
value = modelClass.fromJson(value, modelOptions)
|
package/src/models/Model.js
CHANGED
|
@@ -343,7 +343,7 @@ export class Model extends objection.Model {
|
|
|
343
343
|
},
|
|
344
344
|
{}
|
|
345
345
|
),
|
|
346
|
-
|
|
346
|
+
unevaluatedProperties: false
|
|
347
347
|
},
|
|
348
348
|
{
|
|
349
349
|
type: 'object',
|
|
@@ -352,7 +352,7 @@ export class Model extends objection.Model {
|
|
|
352
352
|
type: 'string'
|
|
353
353
|
}
|
|
354
354
|
},
|
|
355
|
-
|
|
355
|
+
unevaluatedProperties: false
|
|
356
356
|
}
|
|
357
357
|
]
|
|
358
358
|
},
|
|
@@ -387,13 +387,21 @@ export class Model extends objection.Model {
|
|
|
387
387
|
return this._getCached(
|
|
388
388
|
'jsonSchema',
|
|
389
389
|
() => {
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
390
|
+
const definitions = {}
|
|
391
|
+
const schema = convertSchema(
|
|
392
|
+
{
|
|
393
|
+
type: 'object',
|
|
394
|
+
properties: this.definition.properties
|
|
395
|
+
},
|
|
396
|
+
{ definitions }
|
|
397
|
+
)
|
|
394
398
|
addRelationSchemas(this, schema.properties)
|
|
395
399
|
// Merge in root-level schema additions
|
|
396
400
|
assignDeeply(schema, this.definition.schema)
|
|
401
|
+
// Merge in definitions
|
|
402
|
+
if (Object.keys(definitions).length > 0) {
|
|
403
|
+
schema.definitions = definitions
|
|
404
|
+
}
|
|
397
405
|
return {
|
|
398
406
|
$id: this.name,
|
|
399
407
|
...schema
|
|
@@ -467,7 +475,17 @@ export class Model extends objection.Model {
|
|
|
467
475
|
static getAttributes(filter) {
|
|
468
476
|
const attributes = []
|
|
469
477
|
const { properties } = this.definition
|
|
470
|
-
|
|
478
|
+
const { definitions } = this.jsonSchema
|
|
479
|
+
for (let [name, property] of Object.entries(properties)) {
|
|
480
|
+
// Expand $refs so we can even find properties that uses definitions:
|
|
481
|
+
const { $ref, ...schema } = property
|
|
482
|
+
const definition = $ref && definitions?.[$ref]
|
|
483
|
+
if (definition) {
|
|
484
|
+
property = {
|
|
485
|
+
...schema,
|
|
486
|
+
...definition
|
|
487
|
+
}
|
|
488
|
+
}
|
|
471
489
|
if (filter(property)) {
|
|
472
490
|
attributes.push(name)
|
|
473
491
|
}
|
|
@@ -814,8 +832,8 @@ export class Model extends objection.Model {
|
|
|
814
832
|
// @override
|
|
815
833
|
static createValidator() {
|
|
816
834
|
// Use a shared validator per app, so model schema can reference each other.
|
|
817
|
-
// NOTE: The Dito Validator class creates and manages this shared
|
|
818
|
-
// Validator instance for us, we just need to return it here:
|
|
835
|
+
// NOTE: The Dito.js Validator class creates and manages this shared
|
|
836
|
+
// Objection Validator instance for us, we just need to return it here:
|
|
819
837
|
return this.app.validator
|
|
820
838
|
}
|
|
821
839
|
|
package/src/schema/index.js
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { resolve } from 'url'
|
|
2
|
+
import { MissingRefError } from 'ajv'
|
|
3
|
+
import { clone, mergeDeeply } from '@ditojs/utils'
|
|
4
|
+
|
|
5
|
+
export const $extend = {
|
|
6
|
+
macro(schemas, parentSchema, ctx) {
|
|
7
|
+
const [source, ...patch] = schemas.map(schema => {
|
|
8
|
+
const { $ref } = schema
|
|
9
|
+
if ($ref) {
|
|
10
|
+
const { baseId, self } = ctx
|
|
11
|
+
const id =
|
|
12
|
+
baseId && baseId !== '#'
|
|
13
|
+
? resolve(baseId, $ref)
|
|
14
|
+
: $ref
|
|
15
|
+
const validate = self.getSchema(id)
|
|
16
|
+
if (!validate) {
|
|
17
|
+
throw new MissingRefError(baseId, $ref)
|
|
18
|
+
}
|
|
19
|
+
schema = validate.schema
|
|
20
|
+
}
|
|
21
|
+
return schema
|
|
22
|
+
})
|
|
23
|
+
return mergeDeeply(clone(source), ...patch)
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
metaSchema: {
|
|
27
|
+
type: 'array',
|
|
28
|
+
items: { type: 'object' },
|
|
29
|
+
minItems: 2
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -14,8 +14,8 @@ export const _instanceof = {
|
|
|
14
14
|
},
|
|
15
15
|
|
|
16
16
|
validate(schema, data) {
|
|
17
|
-
// Support instanceof for basic JS types and Dito models. If `this` is
|
|
18
|
-
// validator's ctx (see passContext), then we can access the models and
|
|
17
|
+
// Support instanceof for basic JS types and Dito.js models. If `this` is
|
|
18
|
+
// the validator's ctx (see passContext), then we can access the models and
|
|
19
19
|
// check.
|
|
20
20
|
const models = this?.app?.models
|
|
21
21
|
for (const type of asArray(schema)) {
|
package/src/schema/properties.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { isObject, isArray, isString } from '@ditojs/utils'
|
|
1
|
+
import { isObject, isArray, isString, equals } from '@ditojs/utils'
|
|
2
2
|
|
|
3
3
|
export function convertSchema(schema, options = {}) {
|
|
4
4
|
if (isArray(schema)) {
|
|
5
|
-
// Needed for allOf, anyOf, oneOf, not, items:
|
|
5
|
+
// Needed for allOf, anyOf, oneOf, not, items, see below:
|
|
6
6
|
schema = schema.map(entry => convertSchema(entry, options))
|
|
7
7
|
} else if (isObject(schema)) {
|
|
8
8
|
// Create a shallow clone so we can modify and return:
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Also collect and propagate the definitions up to the root schema through
|
|
10
|
+
// `options.definitions`, as passed from `Model static get jsonSchema()`:
|
|
11
|
+
const { definitions, ...rest } = schema
|
|
12
|
+
mergeDefinitions(options.definitions, definitions, options)
|
|
13
|
+
schema = rest
|
|
14
|
+
const { $ref, type } = schema
|
|
11
15
|
if (schema.required === true) {
|
|
12
16
|
// Our 'required' is not the same as JSON Schema's: Use the 'required'
|
|
13
17
|
// format instead that only validates if the required value is not empty,
|
|
@@ -44,22 +48,31 @@ export function convertSchema(schema, options = {}) {
|
|
|
44
48
|
schema.prefixItems &&= convertSchema(schema.prefixItems, options)
|
|
45
49
|
schema.items &&= convertSchema(schema.items, options)
|
|
46
50
|
|
|
47
|
-
// Handle nested allOf, anyOf, oneOf
|
|
48
|
-
for (const key of ['allOf', 'anyOf', 'oneOf', 'not']) {
|
|
51
|
+
// Handle nested allOf, anyOf, oneOf & co. fields
|
|
52
|
+
for (const key of ['allOf', 'anyOf', 'oneOf', 'not', '$extend']) {
|
|
49
53
|
if (key in schema) {
|
|
50
54
|
schema[key] = convertSchema(schema[key], options)
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
if (isString(
|
|
58
|
+
if (isString($ref)) {
|
|
59
|
+
// If the $ref is a nested Dito.js definition, convert it to a JSON schema
|
|
60
|
+
// reference. If it is a full URL, use it as is.
|
|
61
|
+
schema.$ref = $ref.startsWith('#')
|
|
62
|
+
? `#/definitions/${$ref}`
|
|
63
|
+
: $ref
|
|
64
|
+
} else if (isString(type)) {
|
|
55
65
|
// Convert schema property notation to JSON schema
|
|
56
66
|
const jsonType = jsonTypes[type]
|
|
57
67
|
if (jsonType) {
|
|
58
68
|
schema.type = jsonType
|
|
59
|
-
if (
|
|
60
|
-
|
|
69
|
+
if (
|
|
70
|
+
(hasConvertedProperties || schema.discriminator) &&
|
|
71
|
+
!('unevaluatedProperties' in schema)
|
|
72
|
+
) {
|
|
73
|
+
// Invert the logic of `unevaluatedProperties` so that it needs to be
|
|
61
74
|
// explicitly set to `true`:
|
|
62
|
-
schema.
|
|
75
|
+
schema.unevaluatedProperties = false
|
|
63
76
|
}
|
|
64
77
|
} else if (['date', 'datetime', 'timestamp'].includes(type)) {
|
|
65
78
|
// Date properties can be submitted both as a string or a Date object.
|
|
@@ -105,7 +118,7 @@ export function convertSchema(schema, options = {}) {
|
|
|
105
118
|
return schema
|
|
106
119
|
}
|
|
107
120
|
|
|
108
|
-
|
|
121
|
+
function convertProperties(schemaProperties, options) {
|
|
109
122
|
const properties = {}
|
|
110
123
|
const required = []
|
|
111
124
|
for (const [key, property] of Object.entries(schemaProperties)) {
|
|
@@ -117,6 +130,32 @@ export function convertProperties(schemaProperties, options) {
|
|
|
117
130
|
return { properties, required }
|
|
118
131
|
}
|
|
119
132
|
|
|
133
|
+
function mergeDefinitions(definitions, defs, options) {
|
|
134
|
+
if (definitions && defs) {
|
|
135
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
136
|
+
if (!key.startsWith('#')) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`Invalid definition '${
|
|
139
|
+
key
|
|
140
|
+
}', the name of nested Dito.js definitions must start with '#': ${
|
|
141
|
+
JSON.stringify(def)
|
|
142
|
+
}`
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
const definition = definitions[key]
|
|
146
|
+
const converted = convertSchema(def, options)
|
|
147
|
+
if (definition && !equals(definition, converted)) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Duplicate nested definition for '${key}' with different schema: ${
|
|
150
|
+
JSON.stringify(def)
|
|
151
|
+
}`
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
definitions[key] = converted
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
120
159
|
function addFormat(schema, newFormat) {
|
|
121
160
|
// Support multiple `format` keywords through `allOf`:
|
|
122
161
|
const { allOf, format, ...rest } = schema
|
|
@@ -30,7 +30,7 @@ describe('convertSchema()', () => {
|
|
|
30
30
|
).toEqual({
|
|
31
31
|
type: 'object',
|
|
32
32
|
properties,
|
|
33
|
-
|
|
33
|
+
unevaluatedProperties: false
|
|
34
34
|
})
|
|
35
35
|
})
|
|
36
36
|
|
|
@@ -69,7 +69,7 @@ describe('convertSchema()', () => {
|
|
|
69
69
|
).toEqual({
|
|
70
70
|
type: 'object',
|
|
71
71
|
properties,
|
|
72
|
-
|
|
72
|
+
unevaluatedProperties: false
|
|
73
73
|
})
|
|
74
74
|
})
|
|
75
75
|
|
|
@@ -90,7 +90,7 @@ describe('convertSchema()', () => {
|
|
|
90
90
|
type: 'string'
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
|
-
|
|
93
|
+
unevaluatedProperties: false
|
|
94
94
|
})
|
|
95
95
|
})
|
|
96
96
|
|
|
@@ -121,7 +121,7 @@ describe('convertSchema()', () => {
|
|
|
121
121
|
format: 'required'
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
|
-
|
|
124
|
+
unevaluatedProperties: false,
|
|
125
125
|
required: ['myString', 'myNumber']
|
|
126
126
|
})
|
|
127
127
|
})
|
|
@@ -142,7 +142,7 @@ describe('convertSchema()', () => {
|
|
|
142
142
|
myString: { type: 'string' },
|
|
143
143
|
myNumber: { type: 'number' }
|
|
144
144
|
},
|
|
145
|
-
|
|
145
|
+
unevaluatedProperties: false,
|
|
146
146
|
required: ['myString', 'myNumber']
|
|
147
147
|
})
|
|
148
148
|
})
|
|
@@ -163,11 +163,11 @@ describe('convertSchema()', () => {
|
|
|
163
163
|
properties: {
|
|
164
164
|
myText: {
|
|
165
165
|
type: 'object',
|
|
166
|
-
|
|
166
|
+
unevaluatedProperties: false,
|
|
167
167
|
properties: {}
|
|
168
168
|
}
|
|
169
169
|
},
|
|
170
|
-
|
|
170
|
+
unevaluatedProperties: false
|
|
171
171
|
})
|
|
172
172
|
})
|
|
173
173
|
|
|
@@ -178,7 +178,7 @@ describe('convertSchema()', () => {
|
|
|
178
178
|
properties: {
|
|
179
179
|
myText: {
|
|
180
180
|
type: 'object',
|
|
181
|
-
|
|
181
|
+
unevaluatedProperties: true,
|
|
182
182
|
properties: {}
|
|
183
183
|
}
|
|
184
184
|
}
|
|
@@ -188,11 +188,11 @@ describe('convertSchema()', () => {
|
|
|
188
188
|
properties: {
|
|
189
189
|
myText: {
|
|
190
190
|
type: 'object',
|
|
191
|
-
|
|
191
|
+
unevaluatedProperties: true,
|
|
192
192
|
properties: {}
|
|
193
193
|
}
|
|
194
194
|
},
|
|
195
|
-
|
|
195
|
+
unevaluatedProperties: false
|
|
196
196
|
})
|
|
197
197
|
})
|
|
198
198
|
|
|
@@ -223,11 +223,11 @@ describe('convertSchema()', () => {
|
|
|
223
223
|
format: 'required'
|
|
224
224
|
}
|
|
225
225
|
},
|
|
226
|
-
|
|
226
|
+
unevaluatedProperties: false,
|
|
227
227
|
required: ['myProperty']
|
|
228
228
|
}
|
|
229
229
|
},
|
|
230
|
-
|
|
230
|
+
unevaluatedProperties: false
|
|
231
231
|
})
|
|
232
232
|
})
|
|
233
233
|
|
|
@@ -256,10 +256,10 @@ describe('convertSchema()', () => {
|
|
|
256
256
|
type: 'string'
|
|
257
257
|
}
|
|
258
258
|
},
|
|
259
|
-
|
|
259
|
+
unevaluatedProperties: false
|
|
260
260
|
}
|
|
261
261
|
},
|
|
262
|
-
|
|
262
|
+
unevaluatedProperties: false
|
|
263
263
|
})
|
|
264
264
|
})
|
|
265
265
|
|
|
@@ -295,7 +295,7 @@ describe('convertSchema()', () => {
|
|
|
295
295
|
format: 'date-time'
|
|
296
296
|
}
|
|
297
297
|
},
|
|
298
|
-
|
|
298
|
+
unevaluatedProperties: false
|
|
299
299
|
})
|
|
300
300
|
})
|
|
301
301
|
|
|
@@ -316,7 +316,7 @@ describe('convertSchema()', () => {
|
|
|
316
316
|
$ref: 'MyModel'
|
|
317
317
|
}
|
|
318
318
|
},
|
|
319
|
-
|
|
319
|
+
unevaluatedProperties: false
|
|
320
320
|
})
|
|
321
321
|
})
|
|
322
322
|
|
|
@@ -343,7 +343,7 @@ describe('convertSchema()', () => {
|
|
|
343
343
|
instanceof: 'MyModel'
|
|
344
344
|
}
|
|
345
345
|
},
|
|
346
|
-
|
|
346
|
+
unevaluatedProperties: false
|
|
347
347
|
})
|
|
348
348
|
})
|
|
349
349
|
|
|
@@ -366,7 +366,7 @@ describe('convertSchema()', () => {
|
|
|
366
366
|
nullable: true
|
|
367
367
|
}
|
|
368
368
|
},
|
|
369
|
-
|
|
369
|
+
unevaluatedProperties: false
|
|
370
370
|
})
|
|
371
371
|
})
|
|
372
372
|
|
|
@@ -391,7 +391,7 @@ describe('convertSchema()', () => {
|
|
|
391
391
|
]
|
|
392
392
|
}
|
|
393
393
|
},
|
|
394
|
-
|
|
394
|
+
unevaluatedProperties: false
|
|
395
395
|
})
|
|
396
396
|
})
|
|
397
397
|
|
|
@@ -415,7 +415,7 @@ describe('convertSchema()', () => {
|
|
|
415
415
|
nullable: true
|
|
416
416
|
}
|
|
417
417
|
},
|
|
418
|
-
|
|
418
|
+
unevaluatedProperties: false
|
|
419
419
|
})
|
|
420
420
|
})
|
|
421
421
|
|
|
@@ -440,7 +440,7 @@ describe('convertSchema()', () => {
|
|
|
440
440
|
nullable: true
|
|
441
441
|
}
|
|
442
442
|
},
|
|
443
|
-
|
|
443
|
+
unevaluatedProperties: false
|
|
444
444
|
})
|
|
445
445
|
})
|
|
446
446
|
|
|
@@ -504,7 +504,7 @@ describe('convertSchema()', () => {
|
|
|
504
504
|
}
|
|
505
505
|
},
|
|
506
506
|
required: ['prop1', 'prop2'],
|
|
507
|
-
|
|
507
|
+
unevaluatedProperties: false
|
|
508
508
|
},
|
|
509
509
|
{
|
|
510
510
|
type: 'object',
|
|
@@ -519,13 +519,13 @@ describe('convertSchema()', () => {
|
|
|
519
519
|
}
|
|
520
520
|
},
|
|
521
521
|
required: ['prop3', 'prop4'],
|
|
522
|
-
|
|
522
|
+
unevaluatedProperties: false
|
|
523
523
|
}
|
|
524
524
|
]
|
|
525
525
|
}
|
|
526
526
|
}
|
|
527
527
|
},
|
|
528
|
-
|
|
528
|
+
unevaluatedProperties: false
|
|
529
529
|
})
|
|
530
530
|
})
|
|
531
531
|
|
|
@@ -566,11 +566,11 @@ describe('convertSchema()', () => {
|
|
|
566
566
|
type: 'number'
|
|
567
567
|
}
|
|
568
568
|
},
|
|
569
|
-
|
|
569
|
+
unevaluatedProperties: false,
|
|
570
570
|
required: ['prop1', 'prop2']
|
|
571
571
|
}
|
|
572
572
|
},
|
|
573
|
-
|
|
573
|
+
unevaluatedProperties: false,
|
|
574
574
|
required: ['myObject']
|
|
575
575
|
})
|
|
576
576
|
})
|
|
@@ -605,6 +605,7 @@ describe('convertSchema()', () => {
|
|
|
605
605
|
).toEqual({
|
|
606
606
|
type: 'object',
|
|
607
607
|
discriminator: { propertyName: 'foo' },
|
|
608
|
+
unevaluatedProperties: false,
|
|
608
609
|
required: ['foo'],
|
|
609
610
|
oneOf: [
|
|
610
611
|
{
|
|
@@ -630,4 +631,76 @@ describe('convertSchema()', () => {
|
|
|
630
631
|
]
|
|
631
632
|
})
|
|
632
633
|
})
|
|
634
|
+
|
|
635
|
+
it('supports nested Dito.js definitions', () => {
|
|
636
|
+
const definitions = {}
|
|
637
|
+
expect(
|
|
638
|
+
convertSchema(
|
|
639
|
+
{
|
|
640
|
+
type: 'object',
|
|
641
|
+
properties: {
|
|
642
|
+
prop1: {
|
|
643
|
+
$ref: '#type1'
|
|
644
|
+
},
|
|
645
|
+
prop2: {
|
|
646
|
+
type: 'object',
|
|
647
|
+
properties: {
|
|
648
|
+
prop3: {
|
|
649
|
+
$ref: '#type2'
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
definitions: {
|
|
653
|
+
'#type2': {
|
|
654
|
+
type: 'object',
|
|
655
|
+
properties: {
|
|
656
|
+
prop3: {
|
|
657
|
+
type: 'string'
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
|
|
665
|
+
definitions: {
|
|
666
|
+
'#type1': {
|
|
667
|
+
type: 'integer'
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
{ definitions }
|
|
672
|
+
)
|
|
673
|
+
).toEqual({
|
|
674
|
+
type: 'object',
|
|
675
|
+
unevaluatedProperties: false,
|
|
676
|
+
properties: {
|
|
677
|
+
prop1: {
|
|
678
|
+
$ref: '#/definitions/#type1'
|
|
679
|
+
},
|
|
680
|
+
prop2: {
|
|
681
|
+
type: 'object',
|
|
682
|
+
unevaluatedProperties: false,
|
|
683
|
+
properties: {
|
|
684
|
+
prop3: {
|
|
685
|
+
$ref: '#/definitions/#type2'
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
})
|
|
691
|
+
expect(definitions).toEqual({
|
|
692
|
+
'#type1': {
|
|
693
|
+
type: 'integer'
|
|
694
|
+
},
|
|
695
|
+
'#type2': {
|
|
696
|
+
type: 'object',
|
|
697
|
+
unevaluatedProperties: false,
|
|
698
|
+
properties: {
|
|
699
|
+
prop3: {
|
|
700
|
+
type: 'string'
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
})
|
|
705
|
+
})
|
|
633
706
|
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const asset = {
|
|
2
|
+
type: 'object',
|
|
3
|
+
properties: {
|
|
4
|
+
key: {
|
|
5
|
+
type: 'string',
|
|
6
|
+
required: true
|
|
7
|
+
},
|
|
8
|
+
name: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
required: true
|
|
11
|
+
},
|
|
12
|
+
type: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
type: 'integer',
|
|
18
|
+
required: true
|
|
19
|
+
},
|
|
20
|
+
url: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
format: 'uri'
|
|
23
|
+
},
|
|
24
|
+
width: {
|
|
25
|
+
type: 'integer'
|
|
26
|
+
},
|
|
27
|
+
height: {
|
|
28
|
+
type: 'integer'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './_asset.js'
|
package/src/storage/AssetFile.js
CHANGED
package/src/storage/Storage.js
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Type definitions for Dito.js server
|
|
4
4
|
// Project: <https://github.com/ditojs/dito/>
|
|
5
5
|
|
|
6
|
-
// Export the entire Dito namespace.
|
|
6
|
+
// Export the entire Dito.js namespace.
|
|
7
7
|
|
|
8
8
|
import { ObjectCannedACL, S3ClientConfig } from '@aws-sdk/client-s3'
|
|
9
9
|
import { DateFormat } from '@ditojs/utils'
|
|
@@ -645,14 +645,15 @@ export class Model extends objection.Model {
|
|
|
645
645
|
}
|
|
646
646
|
|
|
647
647
|
/**
|
|
648
|
-
* Dito automatically adds an `id` property if a model property with the
|
|
648
|
+
* Dito.js automatically adds an `id` property if a model property with the
|
|
649
649
|
* `primary: true` setting is not already explicitly defined.
|
|
650
650
|
*/
|
|
651
651
|
readonly id: Id
|
|
652
652
|
|
|
653
653
|
/**
|
|
654
|
-
* Dito automatically adds a `foreignKeyId` property if foreign keys
|
|
655
|
-
* in relations definitions are not explicitly defined in the
|
|
654
|
+
* Dito.js automatically adds a `foreignKeyId` property if foreign keys
|
|
655
|
+
* occurring in relations definitions are not explicitly defined in the
|
|
656
|
+
* properties.
|
|
656
657
|
*/
|
|
657
658
|
readonly foreignKeyId: Id
|
|
658
659
|
|