@ditojs/server 2.50.0 → 2.51.1

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": "2.50.0",
3
+ "version": "2.51.1",
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",
@@ -26,10 +26,10 @@
26
26
  "node >= 18"
27
27
  ],
28
28
  "dependencies": {
29
- "@ditojs/admin": "^2.50.0",
30
- "@ditojs/build": "^2.50.0",
31
- "@ditojs/router": "^2.50.0",
32
- "@ditojs/utils": "^2.50.0",
29
+ "@ditojs/admin": "^2.51.0",
30
+ "@ditojs/build": "^2.51.0",
31
+ "@ditojs/router": "^2.51.0",
32
+ "@ditojs/utils": "^2.51.0",
33
33
  "@koa/cors": "^5.0.0",
34
34
  "@koa/multer": "^3.1.0",
35
35
  "@originjs/vite-plugin-commonjs": "^1.0.3",
@@ -41,7 +41,6 @@
41
41
  "eventemitter2": "^6.4.9",
42
42
  "file-type": "^20.5.0",
43
43
  "helmet": "^8.1.0",
44
- "is-stream": "^4.0.1",
45
44
  "koa": "^3.0.0",
46
45
  "koa-bodyparser": "^4.4.1",
47
46
  "koa-compose": "^4.1.0",
@@ -86,10 +85,10 @@
86
85
  "@types/koa-session": "^6.4.5",
87
86
  "@types/koa-static": "^4.0.4",
88
87
  "@types/koa__cors": "^5.0.0",
89
- "@types/node": "^22.15.17",
88
+ "@types/node": "^22.15.18",
90
89
  "knex": "^3.1.0",
91
90
  "objection": "^3.1.5",
92
91
  "typescript": "^5.8.3"
93
92
  },
94
- "gitHead": "24ab390e75addc046571ffa7161c75569b11e4f5"
93
+ "gitHead": "b9faeb3c676bb792da67a028fa7de3bbdbc85de4"
95
94
  }
@@ -534,6 +534,15 @@ export class Application extends Koa {
534
534
  const schema = properties
535
535
  ? convertSchema({ type: 'object', properties }, options)
536
536
  : null
537
+
538
+ // Method to recursively check the compiled JSON schema and its sub-schemas
539
+ // to see if it has any `$ref` references to model schemas:
540
+ const hasModelRefs = schema => (
541
+ !!this.models[schema?.$ref] ||
542
+ (isArray(schema) || isPlainObject(schema)) &&
543
+ Object.values(schema).some(hasModelRefs)
544
+ )
545
+
537
546
  const validate = this.compileValidator(schema, {
538
547
  // For parameters, always coerce types, including arrays.
539
548
  coerceTypes: 'array',
@@ -552,7 +561,10 @@ export class Application extends Koa {
552
561
  validate: validate
553
562
  ? // Use `call()` to pass ctx as context to Ajv, see passContext:
554
563
  data => validate.call(ctx, data)
555
- : null
564
+ : null,
565
+ get hasModelRefs() {
566
+ return hasModelRefs(schema)
567
+ }
556
568
  }
557
569
  }
558
570
 
@@ -776,6 +788,9 @@ export class Application extends Koa {
776
788
  if (this.config.log.errors?.stack === false) {
777
789
  delete copy.stack
778
790
  delete copy.cause
791
+ } else {
792
+ // Explicitly copy the stack trace, as clone() might not copy it.
793
+ copy.stack = error.stack
779
794
  }
780
795
  // Use `util.inspect()` instead of Pino's internal error logging for better
781
796
  // stack traces and logging of error data.
@@ -96,20 +96,18 @@ export class Validator extends objection.Validator {
96
96
  getAjv(options = {}) {
97
97
  // Cache Ajv instances by keys that represent their options. For improved
98
98
  // matching, convert options to a version with all default values missing:
99
- const opts = Object.entries(options).reduce((opts, [key, value]) => {
100
- if (key in validatorOptions && value !== validatorOptions[key]) {
101
- opts[key] = value
102
- }
103
- return opts
104
- }, {})
105
- const cacheKey = formatJson(opts, false)
106
- const { ajv } = (
107
- this.ajvCache[cacheKey] ||
108
- (this.ajvCache[cacheKey] = {
109
- ajv: this.createAjv(opts),
110
- options
111
- })
99
+ const filteredOptions = Object.fromEntries(
100
+ Object.entries(options).filter(
101
+ ([key, value]) => (
102
+ key in validatorOptions && value !== validatorOptions[key]
103
+ )
104
+ )
112
105
  )
106
+ const cacheKey = formatJson(filteredOptions, false)
107
+ const { ajv } = (this.ajvCache[cacheKey] ??= {
108
+ ajv: this.createAjv(filteredOptions),
109
+ options: filteredOptions
110
+ })
113
111
  return ajv
114
112
  }
115
113
 
@@ -205,6 +203,9 @@ export class Validator extends objection.Validator {
205
203
  })
206
204
  if (async) {
207
205
  schema.$async = true
206
+ for (const definition of Object.values(schema.definitions || {})) {
207
+ definition.$async = true
208
+ }
208
209
  }
209
210
  return schema
210
211
  }
@@ -1,4 +1,11 @@
1
- import { isString, isObject, asArray, clone, deprecate } from '@ditojs/utils'
1
+ import {
2
+ isString,
3
+ isObject,
4
+ asArray,
5
+ clone,
6
+ convertToJson,
7
+ deprecate
8
+ } from '@ditojs/utils'
2
9
 
3
10
  export default class ControllerAction {
4
11
  constructor(
@@ -118,8 +125,14 @@ export default class ControllerAction {
118
125
  const { identifier } = this
119
126
  await this.controller.emitHook(`before:${identifier}`, false, ctx, ...args)
120
127
  const response = await this.callHandler(ctx, ...args)
128
+ const result =
129
+ // Don't convert response to JSON if it isn't being validated (e.g. useful
130
+ // for streams or buffers), or if the response contains model references.
131
+ !this.response.validate || this.response.hasModelRefs
132
+ ? response
133
+ : convertToJson(response)
121
134
  return this.validateResponse(
122
- await this.controller.emitHook(`after:${identifier}`, true, ctx, response)
135
+ await this.controller.emitHook(`after:${identifier}`, true, ctx, result)
123
136
  )
124
137
  }
125
138
 
@@ -147,7 +147,7 @@ describe('convertSchema()', () => {
147
147
  })
148
148
  })
149
149
 
150
- it(`expands 'object' schemas with properties to JSON schemas allowing no additional properties`, () => {
150
+ it(`expands 'object' schemas with properties to JSON schemas allowing no unevaluated properties`, () => {
151
151
  expect(
152
152
  convertSchema({
153
153
  type: 'object',
@@ -171,7 +171,7 @@ describe('convertSchema()', () => {
171
171
  })
172
172
  })
173
173
 
174
- it('preserves pre-existing settings for no additional properties', () => {
174
+ it('preserves pre-existing settings for no unevaluated properties', () => {
175
175
  expect(
176
176
  convertSchema({
177
177
  type: 'object',
@@ -0,0 +1,4 @@
1
+ export const color = {
2
+ type: 'string',
3
+ format: 'hexcolor'
4
+ }
@@ -1 +1,2 @@
1
1
  export * from './_asset.js'
2
+ export * from './_color.js'
package/src/utils/koa.js DELETED
@@ -1,12 +0,0 @@
1
- import { isString } from '@ditojs/utils'
2
- import { isStream } from 'is-stream'
3
-
4
- export function isSupportedKoaBody(body) {
5
- return (
6
- Buffer.isBuffer(body) ||
7
- isString(body) ||
8
- body instanceof Blob ||
9
- body instanceof Response ||
10
- isStream(body)
11
- )
12
- }