@ditojs/server 2.32.1 → 2.32.3

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.32.1",
3
+ "version": "2.32.3",
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,22 +25,22 @@
25
25
  "node >= 18"
26
26
  ],
27
27
  "dependencies": {
28
- "@ditojs/admin": "^2.32.1",
29
- "@ditojs/build": "^2.32.0",
30
- "@ditojs/router": "^2.32.0",
31
- "@ditojs/utils": "^2.32.0",
28
+ "@ditojs/admin": "^2.32.2",
29
+ "@ditojs/build": "^2.32.2",
30
+ "@ditojs/router": "^2.32.2",
31
+ "@ditojs/utils": "^2.32.2",
32
32
  "@koa/cors": "^5.0.0",
33
33
  "@koa/multer": "^3.0.2",
34
34
  "@originjs/vite-plugin-commonjs": "^1.0.3",
35
- "@vitejs/plugin-vue": "^5.1.3",
36
- "@vue/compiler-sfc": "3.5.2",
35
+ "@vitejs/plugin-vue": "^5.1.4",
36
+ "@vue/compiler-sfc": "^3.5.6",
37
37
  "ajv": "^8.17.1",
38
38
  "ajv-formats": "^2.1.1",
39
39
  "bcryptjs": "^2.4.3",
40
40
  "bytes": "^3.1.2",
41
41
  "data-uri-to-buffer": "^6.0.2",
42
42
  "eventemitter2": "^6.4.9",
43
- "file-type": "^19.4.1",
43
+ "file-type": "^19.5.0",
44
44
  "koa": "^2.15.3",
45
45
  "koa-bodyparser": "^4.4.1",
46
46
  "koa-compose": "^4.1.0",
@@ -67,10 +67,10 @@
67
67
  "pino-pretty": "^11.2.2",
68
68
  "pluralize": "^8.0.0",
69
69
  "repl": "^0.1.3",
70
- "type-fest": "^4.26.0",
70
+ "type-fest": "^4.26.1",
71
71
  "uuid": "^10.0.0",
72
- "vite": "^5.4.3",
73
- "vue": "^3.5.2"
72
+ "vite": "^5.4.6",
73
+ "vue": "^3.5.6"
74
74
  },
75
75
  "peerDependencies": {
76
76
  "@aws-sdk/client-s3": "^3.0.0",
@@ -87,11 +87,11 @@
87
87
  "@types/koa-session": "^6.4.5",
88
88
  "@types/koa-static": "^4.0.4",
89
89
  "@types/koa__cors": "^5.0.0",
90
- "@types/node": "^22.5.4",
90
+ "@types/node": "^22.5.5",
91
91
  "knex": "^3.1.0",
92
92
  "objection": "^3.1.4",
93
- "typescript": "^5.5.4"
93
+ "typescript": "^5.6.2"
94
94
  },
95
95
  "types": "types",
96
- "gitHead": "22008a15e26380fa7b226ca115f0643bfa88334d"
96
+ "gitHead": "18442b45101f469e53efd91e93854ef954dfb785"
97
97
  }
@@ -197,7 +197,9 @@ export class CollectionController extends Controller {
197
197
  collection = this.convertToCoreActions({
198
198
  async get(ctx, modify) {
199
199
  const result = await this.execute(ctx, (query, trx) => {
200
- query.find(ctx.query, this.allowParam).modify(getModify(modify, trx))
200
+ query
201
+ .find(ctx.filteredQuery, this.allowParam)
202
+ .modify(getModify(modify, trx))
201
203
  return this.isOneToOne ? query.first() : query
202
204
  })
203
205
  // This method doesn't always return an array:
@@ -210,7 +212,7 @@ export class CollectionController extends Controller {
210
212
  const count = await this.execute(ctx, (query, trx) =>
211
213
  query
212
214
  .ignoreScope()
213
- .find(ctx.query, this.allowParam)
215
+ .find(ctx.filteredQuery, this.allowParam)
214
216
  .modify(query => this.isOneToOne && query.throwIfNotFound())
215
217
  .modify(getModify(modify, trx))
216
218
  .modify(query => (this.unrelate ? query.unrelate() : query.delete()))
@@ -248,7 +250,7 @@ export class CollectionController extends Controller {
248
250
  return this.execute(ctx, (query, trx) =>
249
251
  query
250
252
  .findById(ctx.memberId)
251
- .find(ctx.query, this.allowParam)
253
+ .find(ctx.filteredQuery, this.allowParam)
252
254
  .throwIfNotFound()
253
255
  .modify(getModify(modify, trx))
254
256
  )
@@ -259,7 +261,7 @@ export class CollectionController extends Controller {
259
261
  query
260
262
  .ignoreScope()
261
263
  .findById(ctx.memberId)
262
- .find(ctx.query, this.allowParam)
264
+ .find(ctx.filteredQuery, this.allowParam)
263
265
  .throwIfNotFound()
264
266
  .modify(getModify(modify, trx))
265
267
  .modify(query => (this.unrelate ? query.unrelate() : query.delete()))
@@ -84,20 +84,35 @@ export default class ControllerAction {
84
84
  // - 'query': Use `ctx.request.query`, regardless of the action's method.
85
85
  // - 'body': Use `ctx.request.body`, regardless of the action's method.
86
86
  getParams(ctx, from = this.paramsName) {
87
- const value = from === 'path' ? ctx.params : ctx.request[from]
87
+ const params = from === 'path' ? ctx.params : ctx.request[from]
88
88
  // koa-bodyparser always sets an object, even when there is no body.
89
89
  // Detect this here and return null instead.
90
90
  const isNull = (
91
91
  from === 'body' &&
92
92
  ctx.request.headers['content-length'] === '0' &&
93
- Object.keys(value).length === 0
93
+ Object.keys(params).length === 0
94
94
  )
95
- return isNull ? null : value
95
+ return isNull ? null : params
96
96
  }
97
97
 
98
98
  async callAction(ctx) {
99
99
  const params = await this.validateParameters(ctx)
100
- const { args, member } = await this.collectArguments(ctx, params)
100
+ const { args, member } = await this.collectArguments(
101
+ ctx,
102
+ params
103
+ )
104
+ let filteredQuery = null
105
+ Object.defineProperty(ctx, 'filteredQuery', {
106
+ get: () => {
107
+ filteredQuery ??=
108
+ params && this.paramsName === 'query'
109
+ ? this.filterParameters(params)
110
+ : params
111
+ return filteredQuery
112
+ },
113
+ enumerable: false,
114
+ configurable: true
115
+ })
101
116
  await this.controller.handleAuthorization(this.authorization, ctx, member)
102
117
  const { identifier } = this
103
118
  await this.controller.emitHook(`before:${identifier}`, false, ctx, ...args)
@@ -119,11 +134,12 @@ export default class ControllerAction {
119
134
  if (!this.parameters.validate) {
120
135
  return null
121
136
  }
122
- // Since validation also performs coercion, create a clone of the params
123
- // so that this doesn't modify the data on `ctx`.
137
+ // Since validation also performs coercion, create a shallow clone of the
138
+ // params so that this doesn't modify the data on `ctx`.Actually used values
139
+ // themselves are deep cloned below.
124
140
  // NOTE: The data can be either an object or an array.
125
- const data = clone(this.getParams(ctx))
126
- let params = data || {}
141
+ const data = { ...this.getParams(ctx) }
142
+ let params = {}
127
143
  const { dataName } = this.parameters
128
144
  let unwrapRoot = false
129
145
  const errors = []
@@ -152,12 +168,14 @@ export default class ControllerAction {
152
168
  params = {}
153
169
  }
154
170
  params[paramName] = data
171
+ } else {
172
+ params[paramName] = clone(data[paramName])
155
173
  }
156
174
  if (from) {
157
175
  // Allow parameters to be 'borrowed' from other objects.
158
- const data = this.getParams(ctx, from)
176
+ const source = this.getParams(ctx, from)
159
177
  // See above for an explanation of `clone()`:
160
- params[paramName] = clone(wrapRoot ? data : data?.[paramName])
178
+ params[paramName] = clone(wrapRoot ? source : source?.[paramName])
161
179
  }
162
180
  try {
163
181
  const value = params[paramName]
@@ -263,6 +281,21 @@ export default class ControllerAction {
263
281
  return { args, member }
264
282
  }
265
283
 
284
+ filterParameters(params) {
285
+ const filtered = {}
286
+ const consumedNames = Object.fromEntries(
287
+ this.parameters.list
288
+ .filter(param => !!param.name)
289
+ .map(param => [param.name, true])
290
+ )
291
+ for (const [key, value] of Object.entries(params)) {
292
+ if (!consumedNames[key]) {
293
+ filtered[key] = value
294
+ }
295
+ }
296
+ return filtered
297
+ }
298
+
266
299
  coerceValue(type, value, modelOptions) {
267
300
  // See if param needs additional coercion:
268
301
  if (value && ['date', 'datetime', 'timestamp'].includes(type)) {