@ditojs/server 2.100.0 → 3.0.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 +11 -14
- package/src/controllers/AdminController.js +2 -14
- package/src/models/Model.js +43 -7
- package/types/index.d.ts +187 -93
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.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/main/packages/server",
|
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
"src/",
|
|
13
13
|
"types/"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"types": "tsc --noEmit --esModuleInterop ./types/index.d.ts"
|
|
17
|
-
},
|
|
18
15
|
"bin": {
|
|
19
16
|
"dito": "./src/cli/index.js"
|
|
20
17
|
},
|
|
@@ -25,14 +22,13 @@
|
|
|
25
22
|
"node >= 18"
|
|
26
23
|
],
|
|
27
24
|
"dependencies": {
|
|
28
|
-
"@ditojs/admin": "^
|
|
29
|
-
"@ditojs/build": "^
|
|
30
|
-
"@ditojs/router": "^
|
|
31
|
-
"@ditojs/utils": "^
|
|
25
|
+
"@ditojs/admin": "^3.0.0",
|
|
26
|
+
"@ditojs/build": "^3.0.0",
|
|
27
|
+
"@ditojs/router": "^3.0.0",
|
|
28
|
+
"@ditojs/utils": "^3.0.0",
|
|
32
29
|
"@koa/cors": "^5.0.0",
|
|
33
30
|
"@koa/etag": "^5.0.2",
|
|
34
31
|
"@koa/multer": "^4.0.0",
|
|
35
|
-
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
|
36
32
|
"ajv": "^8.20.0",
|
|
37
33
|
"ajv-formats": "^3.0.1",
|
|
38
34
|
"bcryptjs": "^3.0.3",
|
|
@@ -62,7 +58,7 @@
|
|
|
62
58
|
"passthrough-counter": "^1.0.0",
|
|
63
59
|
"picocolors": "^1.1.1",
|
|
64
60
|
"picomatch": "^4.0.7",
|
|
65
|
-
"pino": "^10.
|
|
61
|
+
"pino": "^10.4.0",
|
|
66
62
|
"pino-pretty": "^13.1.3",
|
|
67
63
|
"pluralize": "^8.0.0",
|
|
68
64
|
"repl": "^0.1.3",
|
|
@@ -76,19 +72,20 @@
|
|
|
76
72
|
"objection": "^3.0.1"
|
|
77
73
|
},
|
|
78
74
|
"devDependencies": {
|
|
79
|
-
"@aws-sdk/client-s3": "^3.
|
|
80
|
-
"@aws-sdk/lib-storage": "^3.
|
|
75
|
+
"@aws-sdk/client-s3": "^3.1146.0",
|
|
76
|
+
"@aws-sdk/lib-storage": "^3.1146.0",
|
|
81
77
|
"@types/koa-bodyparser": "^4.3.13",
|
|
82
78
|
"@types/koa-compress": "^4.0.7",
|
|
79
|
+
"@types/koa-mount": "^4.0.5",
|
|
83
80
|
"@types/koa-response-time": "^2.1.5",
|
|
84
|
-
"@types/koa-session": "^6.4.5",
|
|
85
81
|
"@types/koa-static": "^4.0.4",
|
|
86
82
|
"@types/koa__cors": "^5.0.1",
|
|
87
83
|
"@types/koa__multer": "^2.0.8",
|
|
84
|
+
"@types/multer-s3": "^3.0.3",
|
|
88
85
|
"@types/node": "^26.6.4",
|
|
89
86
|
"knex": "^3.3.0",
|
|
90
87
|
"objection": "^3.1.5",
|
|
91
88
|
"typescript": "^6.0.3"
|
|
92
89
|
},
|
|
93
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "399f683a6ca227a03cfc0978fee9055383e6b3d8"
|
|
94
91
|
}
|
|
@@ -3,7 +3,6 @@ import Koa from 'koa'
|
|
|
3
3
|
import serve from 'koa-static'
|
|
4
4
|
import { defineConfig, createServer } from 'vite'
|
|
5
5
|
import createVuePlugin from '@vitejs/plugin-vue'
|
|
6
|
-
import { viteCommonjs as createCommonJsPlugin } from '@originjs/vite-plugin-commonjs'
|
|
7
6
|
import { testModuleIdentifier, getPostCssConfig } from '@ditojs/build'
|
|
8
7
|
import { assignDeeply } from '@ditojs/utils'
|
|
9
8
|
import { Controller } from './Controller.js'
|
|
@@ -178,7 +177,6 @@ export class AdminController extends Controller {
|
|
|
178
177
|
configFile: false,
|
|
179
178
|
plugins: [
|
|
180
179
|
createVuePlugin(),
|
|
181
|
-
createCommonJsPlugin(),
|
|
182
180
|
{
|
|
183
181
|
// Private plugin to inject script tag above main module that
|
|
184
182
|
// loads the `dito` object through its own end-point, see:
|
|
@@ -250,8 +248,7 @@ export class AdminController extends Controller {
|
|
|
250
248
|
'prosemirror-view'
|
|
251
249
|
]
|
|
252
250
|
: ditoPackages
|
|
253
|
-
)
|
|
254
|
-
...nonEsmDependencies
|
|
251
|
+
)
|
|
255
252
|
]
|
|
256
253
|
},
|
|
257
254
|
resolve: {
|
|
@@ -279,12 +276,6 @@ const ditoPackages = [
|
|
|
279
276
|
'@ditojs/utils'
|
|
280
277
|
]
|
|
281
278
|
|
|
282
|
-
const nonEsmDependencies = [
|
|
283
|
-
// All non-es modules need to be explicitly included here, and some of
|
|
284
|
-
// them only work due to the use of `createCommonJsPlugin()`.
|
|
285
|
-
'@lk77/vue3-color'
|
|
286
|
-
]
|
|
287
|
-
|
|
288
279
|
const coreDependencies = [
|
|
289
280
|
...ditoPackages,
|
|
290
281
|
|
|
@@ -296,12 +287,11 @@ const coreDependencies = [
|
|
|
296
287
|
'vue',
|
|
297
288
|
'@vue/*',
|
|
298
289
|
'@vueuse/*',
|
|
299
|
-
'
|
|
290
|
+
'vue-color',
|
|
300
291
|
'@kyvg/vue3-notification',
|
|
301
292
|
'vue-multiselect',
|
|
302
293
|
'vue-router',
|
|
303
294
|
'vue-upload-component',
|
|
304
|
-
'tinycolor2',
|
|
305
295
|
'focus-trap',
|
|
306
296
|
'tabbable',
|
|
307
297
|
'sortablejs',
|
|
@@ -314,8 +304,6 @@ const coreDependencies = [
|
|
|
314
304
|
'nanoid',
|
|
315
305
|
'punycode',
|
|
316
306
|
'rope-sequence',
|
|
317
|
-
'filesize',
|
|
318
|
-
'filesize-parser',
|
|
319
307
|
'tslib', // ?
|
|
320
308
|
'orderedmap',
|
|
321
309
|
'w3c-keyname'
|
package/src/models/Model.js
CHANGED
|
@@ -16,7 +16,9 @@ import {
|
|
|
16
16
|
setValueAtDataPath,
|
|
17
17
|
mapConcurrently,
|
|
18
18
|
assignDeeply,
|
|
19
|
-
deprecate
|
|
19
|
+
deprecate,
|
|
20
|
+
formatPlainDate,
|
|
21
|
+
parsePlainDate
|
|
20
22
|
} from '@ditojs/utils'
|
|
21
23
|
import { QueryBuilder } from '../query/index.js'
|
|
22
24
|
import { EventEmitter, KnexHelper } from '../lib/index.js'
|
|
@@ -443,10 +445,21 @@ export class Model extends objection.Model {
|
|
|
443
445
|
static get dateAttributes() {
|
|
444
446
|
return this._getCached(
|
|
445
447
|
'jsonSchema:dateAttributes',
|
|
448
|
+
() =>
|
|
449
|
+
this.getAttributes(
|
|
450
|
+
({ type, computed }) => !computed && type === 'date'
|
|
451
|
+
),
|
|
452
|
+
[]
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
static get datetimeAttributes() {
|
|
457
|
+
return this._getCached(
|
|
458
|
+
'jsonSchema:datetimeAttributes',
|
|
446
459
|
() =>
|
|
447
460
|
this.getAttributes(
|
|
448
461
|
({ type, computed }) => (
|
|
449
|
-
!computed && ['
|
|
462
|
+
!computed && ['datetime', 'timestamp'].includes(type)
|
|
450
463
|
)
|
|
451
464
|
),
|
|
452
465
|
[]
|
|
@@ -590,12 +603,20 @@ export class Model extends objection.Model {
|
|
|
590
603
|
// @override
|
|
591
604
|
$formatDatabaseJson(json) {
|
|
592
605
|
const { constructor } = this
|
|
593
|
-
for (const key of constructor.
|
|
606
|
+
for (const key of constructor.datetimeAttributes) {
|
|
594
607
|
const date = json[key]
|
|
595
608
|
if (date?.toISOString) {
|
|
596
609
|
json[key] = date.toISOString()
|
|
597
610
|
}
|
|
598
611
|
}
|
|
612
|
+
for (const key of constructor.dateAttributes) {
|
|
613
|
+
const date = json[key]
|
|
614
|
+
if (date?.toISOString) {
|
|
615
|
+
// Store dates as their plain date, as the database ignores the
|
|
616
|
+
// time zone when casting a timestamp to a date.
|
|
617
|
+
json[key] = formatPlainDate(date)
|
|
618
|
+
}
|
|
619
|
+
}
|
|
599
620
|
if (constructor.isSQLite()) {
|
|
600
621
|
// SQLite does not support boolean natively and needs conversion...
|
|
601
622
|
for (const key of constructor.booleanAttributes) {
|
|
@@ -636,10 +657,17 @@ export class Model extends objection.Model {
|
|
|
636
657
|
// @override
|
|
637
658
|
$parseJson(json, { trusted = false } = {}) {
|
|
638
659
|
const { constructor } = this
|
|
639
|
-
for (const key of
|
|
660
|
+
for (const key of [
|
|
661
|
+
...constructor.dateAttributes,
|
|
662
|
+
...constructor.datetimeAttributes
|
|
663
|
+
]) {
|
|
640
664
|
const date = json[key]
|
|
641
665
|
if (date !== undefined) {
|
|
642
|
-
|
|
666
|
+
// Parse plain dates like `2026-05-14` as local midnight, which is
|
|
667
|
+
// also how Postgres reads them for timestamps.
|
|
668
|
+
json[key] = isString(date)
|
|
669
|
+
? parsePlainDate(date) ?? new Date(date)
|
|
670
|
+
: date
|
|
643
671
|
}
|
|
644
672
|
}
|
|
645
673
|
// Convert plain asset files objects to AssetFile instances with references
|
|
@@ -652,13 +680,21 @@ export class Model extends objection.Model {
|
|
|
652
680
|
|
|
653
681
|
// @override
|
|
654
682
|
$formatJson(json) {
|
|
683
|
+
const { constructor } = this
|
|
655
684
|
// Remove hidden attributes.
|
|
656
|
-
for (const key of
|
|
685
|
+
for (const key of constructor.hiddenAttributes) {
|
|
657
686
|
delete json[key]
|
|
658
687
|
}
|
|
688
|
+
// Return dates as their plain date, see `$formatDatabaseJson()`.
|
|
689
|
+
for (const key of constructor.dateAttributes) {
|
|
690
|
+
const date = json[key]
|
|
691
|
+
if (date?.toISOString) {
|
|
692
|
+
json[key] = formatPlainDate(date)
|
|
693
|
+
}
|
|
694
|
+
}
|
|
659
695
|
// Sign asset files so clients can send them back with valid signatures.
|
|
660
696
|
// Clone file objects to avoid mutating the model's internals.
|
|
661
|
-
|
|
697
|
+
constructor._signAssetFiles(json)
|
|
662
698
|
return json
|
|
663
699
|
}
|
|
664
700
|
|
package/types/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { Options as KoaBodyParserOptions } from 'koa-bodyparser'
|
|
|
19
19
|
import { CompressOptions } from 'koa-compress'
|
|
20
20
|
import koaMount from 'koa-mount'
|
|
21
21
|
import koaResponseTime from 'koa-response-time'
|
|
22
|
-
import
|
|
22
|
+
import { CreateSessionOptions as KoaSessionOptions } from 'koa-session'
|
|
23
23
|
import multer from '@koa/multer'
|
|
24
24
|
import multerS3 from 'multer-s3'
|
|
25
25
|
import * as objection from 'objection'
|
|
@@ -185,7 +185,7 @@ export interface ApplicationConfig {
|
|
|
185
185
|
* @defaultValue `false`
|
|
186
186
|
* @see https://github.com/koajs/session
|
|
187
187
|
*/
|
|
188
|
-
session?: boolean | (
|
|
188
|
+
session?: boolean | (KoaSessionOptions & { modelClass: string })
|
|
189
189
|
/**
|
|
190
190
|
* Enable passport authentication middleware
|
|
191
191
|
*
|
|
@@ -413,7 +413,7 @@ export class Application<$Models extends Models = Models> {
|
|
|
413
413
|
ctx: KoaContext,
|
|
414
414
|
next: () => Promise<void>
|
|
415
415
|
) => OrPromiseOf<void>
|
|
416
|
-
):
|
|
416
|
+
): unknown
|
|
417
417
|
find(
|
|
418
418
|
method: string,
|
|
419
419
|
path: string
|
|
@@ -660,7 +660,8 @@ export class Application<$Models extends Models = Models> {
|
|
|
660
660
|
method: HTTPMethod,
|
|
661
661
|
path: string,
|
|
662
662
|
transacted: boolean,
|
|
663
|
-
middlewares: OrArrayOf<
|
|
663
|
+
middlewares: OrArrayOf<
|
|
664
|
+
(
|
|
664
665
|
ctx: KoaContext,
|
|
665
666
|
next: () => Promise<void>
|
|
666
667
|
) => OrPromiseOf<void>
|
|
@@ -683,21 +684,21 @@ export class Application<$Models extends Models = Models> {
|
|
|
683
684
|
|
|
684
685
|
export interface Application
|
|
685
686
|
extends Omit<
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
687
|
+
Koa,
|
|
688
|
+
| 'setMaxListeners'
|
|
689
|
+
| 'removeListener'
|
|
690
|
+
| 'removeAllListeners'
|
|
691
|
+
| 'prependOnceListener'
|
|
692
|
+
| 'prependListener'
|
|
693
|
+
| 'once'
|
|
694
|
+
| 'on'
|
|
695
|
+
| 'off'
|
|
696
|
+
| 'listeners'
|
|
697
|
+
| 'addListener'
|
|
698
|
+
| 'listenerCount'
|
|
699
|
+
| 'emit'
|
|
700
|
+
| 'eventNames'
|
|
701
|
+
>,
|
|
701
702
|
EventEmitter {}
|
|
702
703
|
|
|
703
704
|
export type SchemaType = LiteralUnion<
|
|
@@ -875,7 +876,7 @@ export interface ModelRelation<
|
|
|
875
876
|
filter?:
|
|
876
877
|
| string
|
|
877
878
|
| { [name: string]: unknown[] }
|
|
878
|
-
| ((query: QueryBuilder) => void)
|
|
879
|
+
| ((query: QueryBuilder<Model>) => void)
|
|
879
880
|
| Record<string, unknown>
|
|
880
881
|
/**
|
|
881
882
|
* Controls whether the auto-inserted foreign key property should be marked as
|
|
@@ -898,7 +899,7 @@ export interface ModelRelation<
|
|
|
898
899
|
* As an object: `modify: { active: true }` (converted to a find-filter)
|
|
899
900
|
*/
|
|
900
901
|
modify?:
|
|
901
|
-
| ((query: QueryBuilder) => void)
|
|
902
|
+
| ((query: QueryBuilder<Model>) => void)
|
|
902
903
|
| Record<string, unknown>
|
|
903
904
|
}
|
|
904
905
|
|
|
@@ -962,10 +963,15 @@ export type ModelProperty<T = any> = Schema<T> & {
|
|
|
962
963
|
*
|
|
963
964
|
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-scopes.md|Model Scopes}
|
|
964
965
|
*/
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
966
|
+
// Scopes, filters and modifiers are declared through methods, to make their
|
|
967
|
+
// parameters bivariant, so that models can type them with their own query
|
|
968
|
+
// builders, e.g. `QueryBuilder<MyModel>` instead of `QueryBuilder<Model>`.
|
|
969
|
+
export type ModelScope<$Model extends Model = Model> = {
|
|
970
|
+
bivarianceHack(
|
|
971
|
+
query: QueryBuilder<$Model>,
|
|
972
|
+
applyParentScope: (query: QueryBuilder<$Model>) => QueryBuilder<$Model>
|
|
973
|
+
): QueryBuilder<$Model, any> | void
|
|
974
|
+
}['bivarianceHack']
|
|
969
975
|
|
|
970
976
|
/**
|
|
971
977
|
* Map of scope names to scope functions. Scopes can be
|
|
@@ -984,10 +990,9 @@ export type ModelScopes<$Model extends Model = Model> = Record<
|
|
|
984
990
|
* Modifiers are reusable query fragments applied via
|
|
985
991
|
* `.modify('name')` on queries.
|
|
986
992
|
*/
|
|
987
|
-
export type ModelModifier<$Model extends Model = Model> =
|
|
988
|
-
query: QueryBuilder<$Model>,
|
|
989
|
-
|
|
990
|
-
) => void
|
|
993
|
+
export type ModelModifier<$Model extends Model = Model> = {
|
|
994
|
+
bivarianceHack(query: QueryBuilder<$Model>, ...args: any[]): void
|
|
995
|
+
}['bivarianceHack']
|
|
991
996
|
|
|
992
997
|
/**
|
|
993
998
|
* Map of modifier names to modifier functions.
|
|
@@ -1001,10 +1006,9 @@ export type ModelModifiers<$Model extends Model = Model> = Record<
|
|
|
1001
1006
|
* A filter handler function that modifies a query builder
|
|
1002
1007
|
* based on external parameters (e.g. from URL query strings).
|
|
1003
1008
|
*/
|
|
1004
|
-
export type ModelFilterFunction<$Model extends Model = Model> =
|
|
1005
|
-
queryBuilder: QueryBuilder<$Model>,
|
|
1006
|
-
|
|
1007
|
-
) => void
|
|
1009
|
+
export type ModelFilterFunction<$Model extends Model = Model> = {
|
|
1010
|
+
bivarianceHack(queryBuilder: QueryBuilder<$Model>, ...args: any[]): void
|
|
1011
|
+
}['bivarianceHack']
|
|
1008
1012
|
|
|
1009
1013
|
/**
|
|
1010
1014
|
* Registry of known filter type names for use with
|
|
@@ -1098,6 +1102,30 @@ export interface ModelAsset {
|
|
|
1098
1102
|
/** Map of property names to their asset configurations. */
|
|
1099
1103
|
export type ModelAssets = Record<string, ModelAsset>
|
|
1100
1104
|
|
|
1105
|
+
/**
|
|
1106
|
+
* Configuration for a controller's asset upload route, merged over the model's
|
|
1107
|
+
* asset definition of the same data path.
|
|
1108
|
+
*/
|
|
1109
|
+
export type ControllerAsset = ModelAsset & {
|
|
1110
|
+
transacted?: boolean
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Map of data paths, with support for `*` and `**` wildcards, to their asset
|
|
1115
|
+
* upload route configurations.
|
|
1116
|
+
*/
|
|
1117
|
+
export type ControllerAssets = {
|
|
1118
|
+
[dataPath: string]:
|
|
1119
|
+
| ControllerAsset
|
|
1120
|
+
| OrReadOnly<string[]>
|
|
1121
|
+
| ControllerAssetsAuthorize
|
|
1122
|
+
| undefined
|
|
1123
|
+
allow?: OrReadOnly<string[]>
|
|
1124
|
+
authorize?: ControllerAssetsAuthorize
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
type ControllerAssetsAuthorize = Authorize | Record<string, Authorize>
|
|
1128
|
+
|
|
1101
1129
|
export interface ModelOptions extends objection.ModelOptions {
|
|
1102
1130
|
graph?: boolean
|
|
1103
1131
|
async?: boolean
|
|
@@ -1134,7 +1162,20 @@ export type ModelHooks<$Model extends Model = Model> = {
|
|
|
1134
1162
|
}`]?: ModelHookFunction<$Model>
|
|
1135
1163
|
}
|
|
1136
1164
|
|
|
1137
|
-
|
|
1165
|
+
// objection's static side, minus the members that dito types with its own
|
|
1166
|
+
// `Model` and `QueryBuilder`. objection's versions use its own types, which
|
|
1167
|
+
// these can't be compatible with, e.g. modifiers receive objection's
|
|
1168
|
+
// QueryBuilder, while they always receive dito's at runtime.
|
|
1169
|
+
interface ObjectionModelStatic
|
|
1170
|
+
extends Omit<
|
|
1171
|
+
typeof objection.Model,
|
|
1172
|
+
'modifiers' | 'query' | 'fromJson' | 'createNotFoundError'
|
|
1173
|
+
> {
|
|
1174
|
+
new (): objection.Model
|
|
1175
|
+
}
|
|
1176
|
+
declare const ObjectionModel: ObjectionModelStatic
|
|
1177
|
+
|
|
1178
|
+
export class Model extends ObjectionModel {
|
|
1138
1179
|
static query<M extends Model>(
|
|
1139
1180
|
this: Constructor<M>,
|
|
1140
1181
|
trxOrKnex?: objection.TransactionOrKnex
|
|
@@ -1232,7 +1273,10 @@ export class Model extends objection.Model {
|
|
|
1232
1273
|
|
|
1233
1274
|
static get jsonAttributes(): string[]
|
|
1234
1275
|
static get booleanAttributes(): string[]
|
|
1276
|
+
/** The `date` attributes, stored and returned as plain dates. */
|
|
1235
1277
|
static get dateAttributes(): string[]
|
|
1278
|
+
/** The `datetime` and `timestamp` attributes. */
|
|
1279
|
+
static get datetimeAttributes(): string[]
|
|
1236
1280
|
static get computedAttributes(): string[]
|
|
1237
1281
|
static get hiddenAttributes(): string[]
|
|
1238
1282
|
|
|
@@ -1240,8 +1284,6 @@ export class Model extends objection.Model {
|
|
|
1240
1284
|
static app: Application<Models>
|
|
1241
1285
|
/** Whether the model has been initialized by the application. */
|
|
1242
1286
|
static initialized: boolean
|
|
1243
|
-
/** The QueryBuilder class used by this model. */
|
|
1244
|
-
static QueryBuilder: typeof QueryBuilder
|
|
1245
1287
|
/** Whether to deep-clone object attributes on read. */
|
|
1246
1288
|
static cloneObjectAttributes: boolean
|
|
1247
1289
|
/**
|
|
@@ -1499,6 +1541,8 @@ export class Model extends objection.Model {
|
|
|
1499
1541
|
$is(model: Model | null | undefined): boolean
|
|
1500
1542
|
/** Returns `true` if all named properties are defined. */
|
|
1501
1543
|
$has(...properties: string[]): boolean
|
|
1544
|
+
/** Returns the knex instance, as in objection. */
|
|
1545
|
+
$transaction(): Knex
|
|
1502
1546
|
/** Runs a callback within a transaction. */
|
|
1503
1547
|
$transaction(
|
|
1504
1548
|
handler: (trx: objection.Transaction) => Promise<any>
|
|
@@ -1885,7 +1929,7 @@ export class Controller {
|
|
|
1885
1929
|
base?: any,
|
|
1886
1930
|
options?: {
|
|
1887
1931
|
query?: Record<string, any>
|
|
1888
|
-
modify?: (query: QueryBuilder<
|
|
1932
|
+
modify?: (query: QueryBuilder<any>) => QueryBuilder<any>
|
|
1889
1933
|
forUpdate?: boolean
|
|
1890
1934
|
}
|
|
1891
1935
|
): Promise<Model | null>
|
|
@@ -1985,16 +2029,20 @@ export interface Controller extends EventEmitter {}
|
|
|
1985
2029
|
/** A named action parameter with a JSON Schema definition. */
|
|
1986
2030
|
export type ActionParameter = Schema & { name: string }
|
|
1987
2031
|
|
|
2032
|
+
// Handlers are declared through a method, to make their parameters, including
|
|
2033
|
+
// `this`, bivariant, so that controller subclasses remain assignable to their
|
|
2034
|
+
// base classes, e.g. in `ApplicationControllers`.
|
|
2035
|
+
type ControllerHandler<$Controller, $Args extends any[], $Result = any> = {
|
|
2036
|
+
bivarianceHack(this: $Controller, ...args: $Args): $Result
|
|
2037
|
+
}['bivarianceHack']
|
|
2038
|
+
|
|
1988
2039
|
/**
|
|
1989
2040
|
* Handler function for a model controller action. Receives
|
|
1990
2041
|
* the Koa context and any resolved action parameters. `this`
|
|
1991
2042
|
* is bound to the controller instance.
|
|
1992
2043
|
*/
|
|
1993
|
-
export type ModelControllerActionHandler<$ModelController = ModelController> =
|
|
1994
|
-
|
|
1995
|
-
ctx: KoaContext,
|
|
1996
|
-
...args: any[]
|
|
1997
|
-
) => any
|
|
2044
|
+
export type ModelControllerActionHandler<$ModelController = ModelController> =
|
|
2045
|
+
ControllerHandler<$ModelController, [ctx: KoaContext, ...args: any[]]>
|
|
1998
2046
|
|
|
1999
2047
|
/**
|
|
2000
2048
|
* Handler function for a controller action. Receives the Koa
|
|
@@ -2005,8 +2053,8 @@ export type ControllerActionHandler<
|
|
|
2005
2053
|
$Controller extends Controller = Controller,
|
|
2006
2054
|
$Params = Record<string, any>
|
|
2007
2055
|
> = keyof $Params extends never
|
|
2008
|
-
?
|
|
2009
|
-
:
|
|
2056
|
+
? ControllerHandler<$Controller, [ctx: KoaContext]>
|
|
2057
|
+
: ControllerHandler<$Controller, [ctx: KoaContext, params: $Params]>
|
|
2010
2058
|
|
|
2011
2059
|
type ModelDataKey<T, K extends keyof T> = K extends
|
|
2012
2060
|
| 'QueryBuilderType'
|
|
@@ -2171,7 +2219,9 @@ export type ModelControllerActions<$ModelController = ModelController> = {
|
|
|
2171
2219
|
authorize?: Authorize
|
|
2172
2220
|
}
|
|
2173
2221
|
|
|
2174
|
-
type ModelControllerMemberAction
|
|
2222
|
+
type ModelControllerMemberAction<
|
|
2223
|
+
$ModelController extends ModelControllerLike = ModelController
|
|
2224
|
+
> =
|
|
2175
2225
|
| (Omit<ModelControllerActionOptions<$ModelController>, 'parameters'> & {
|
|
2176
2226
|
parameters?: {
|
|
2177
2227
|
[key: string]: MemberActionParameter<
|
|
@@ -2187,7 +2237,9 @@ type ModelControllerMemberAction<$ModelController = ModelController> =
|
|
|
2187
2237
|
* `delete`). Member actions can use `{ from: 'member' }`
|
|
2188
2238
|
* parameters to receive the resolved member model.
|
|
2189
2239
|
*/
|
|
2190
|
-
export type ModelControllerMemberActions
|
|
2240
|
+
export type ModelControllerMemberActions<
|
|
2241
|
+
$ModelController extends ModelControllerLike = ModelController
|
|
2242
|
+
> = {
|
|
2191
2243
|
[name: ControllerActionName]: ModelControllerMemberAction<$ModelController>
|
|
2192
2244
|
allow?: OrReadOnly<ControllerActionName[]>
|
|
2193
2245
|
authorize?: Authorize
|
|
@@ -2306,38 +2358,39 @@ type AfterCollectionGetHookKey = `after:collection:get`
|
|
|
2306
2358
|
type AfterCustomHookKey =
|
|
2307
2359
|
`after:${ModelControllerHookType | '*'}:${ControllerActionName | '*'}`
|
|
2308
2360
|
|
|
2309
|
-
export type ModelControllerHooks
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2361
|
+
export type ModelControllerHooks<
|
|
2362
|
+
$ModelController extends ModelControllerLike = ModelController
|
|
2363
|
+
> = {
|
|
2364
|
+
[$Key in BeforeHookKey]?: ControllerHandler<
|
|
2365
|
+
$ModelController,
|
|
2366
|
+
[ctx: KoaContext, params?: Record<string, any>],
|
|
2367
|
+
void
|
|
2368
|
+
>
|
|
2315
2369
|
} & {
|
|
2316
|
-
[$Key in AfterDeleteHookKey]?:
|
|
2317
|
-
|
|
2318
|
-
ctx: KoaContext,
|
|
2319
|
-
|
|
2320
|
-
) => any
|
|
2370
|
+
[$Key in AfterDeleteHookKey]?: ControllerHandler<
|
|
2371
|
+
$ModelController,
|
|
2372
|
+
[ctx: KoaContext, result: { count: number }]
|
|
2373
|
+
>
|
|
2321
2374
|
} & {
|
|
2322
|
-
[$Key in AfterItemHookKey]?:
|
|
2323
|
-
|
|
2324
|
-
ctx: KoaContext,
|
|
2325
|
-
|
|
2326
|
-
) => any
|
|
2375
|
+
[$Key in AfterItemHookKey]?: ControllerHandler<
|
|
2376
|
+
$ModelController,
|
|
2377
|
+
[ctx: KoaContext, item: ModelFromModelController<$ModelController>]
|
|
2378
|
+
>
|
|
2327
2379
|
} & {
|
|
2328
|
-
[$Key in AfterCollectionGetHookKey]?:
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2380
|
+
[$Key in AfterCollectionGetHookKey]?: ControllerHandler<
|
|
2381
|
+
$ModelController,
|
|
2382
|
+
[
|
|
2383
|
+
ctx: KoaContext,
|
|
2384
|
+
result:
|
|
2385
|
+
| ModelFromModelController<$ModelController>[]
|
|
2386
|
+
| Page<ModelFromModelController<$ModelController>>
|
|
2387
|
+
]
|
|
2388
|
+
>
|
|
2335
2389
|
} & {
|
|
2336
|
-
[$Key in AfterCustomHookKey]?:
|
|
2337
|
-
|
|
2338
|
-
ctx: KoaContext,
|
|
2339
|
-
|
|
2340
|
-
) => any
|
|
2390
|
+
[$Key in AfterCustomHookKey]?: ControllerHandler<
|
|
2391
|
+
$ModelController,
|
|
2392
|
+
[ctx: KoaContext, result: any]
|
|
2393
|
+
>
|
|
2341
2394
|
}
|
|
2342
2395
|
|
|
2343
2396
|
/**
|
|
@@ -2520,12 +2573,11 @@ export class ModelController<
|
|
|
2520
2573
|
* object to assign them to the member.
|
|
2521
2574
|
*/
|
|
2522
2575
|
member?: ModelControllerMemberActions<this>
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
}
|
|
2576
|
+
/**
|
|
2577
|
+
* The asset upload routes, by data path, or `true` to use the model's
|
|
2578
|
+
* asset definitions.
|
|
2579
|
+
*/
|
|
2580
|
+
assets?: boolean | ControllerAssets
|
|
2529
2581
|
|
|
2530
2582
|
/**
|
|
2531
2583
|
* Lifecycle hooks that run before or after controller
|
|
@@ -2577,8 +2629,31 @@ export class ModelController<
|
|
|
2577
2629
|
* @see {@link QueryParameterOptions} for pagination parameters
|
|
2578
2630
|
*/
|
|
2579
2631
|
hooks?: ModelControllerHooks<this>
|
|
2580
|
-
/**
|
|
2581
|
-
|
|
2632
|
+
/**
|
|
2633
|
+
* The relations to expose as nested routes, by relation name. After setup,
|
|
2634
|
+
* each configuration is replaced with its RelationController instance.
|
|
2635
|
+
*/
|
|
2636
|
+
relations?: Record<string, ModelControllerRelation | RelationController>
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
/**
|
|
2640
|
+
* Configuration of a relation route on a model controller, from which the
|
|
2641
|
+
* {@link RelationController} is created. The relation's collection actions are
|
|
2642
|
+
* provided as `relation`, to make sense for both one- and many-relations.
|
|
2643
|
+
*/
|
|
2644
|
+
export type ModelControllerRelation = Partial<
|
|
2645
|
+
Pick<
|
|
2646
|
+
RelationController,
|
|
2647
|
+
| 'graph'
|
|
2648
|
+
| 'transacted'
|
|
2649
|
+
| 'scope'
|
|
2650
|
+
| 'allowScope'
|
|
2651
|
+
| 'allowFilter'
|
|
2652
|
+
| 'allowParam'
|
|
2653
|
+
>
|
|
2654
|
+
> & {
|
|
2655
|
+
relation?: ModelControllerActions<RelationController>
|
|
2656
|
+
member?: ModelControllerMemberActions<RelationController>
|
|
2582
2657
|
}
|
|
2583
2658
|
|
|
2584
2659
|
/**
|
|
@@ -3003,7 +3078,7 @@ export class QueryBuilder<
|
|
|
3003
3078
|
R = M[]
|
|
3004
3079
|
> extends objection.QueryBuilder<M, R> {
|
|
3005
3080
|
/** Clones the query with scope/filter state. */
|
|
3006
|
-
clone():
|
|
3081
|
+
clone(): this
|
|
3007
3082
|
/**
|
|
3008
3083
|
* Inherits scopes from a parent query.
|
|
3009
3084
|
* @override
|
|
@@ -3142,7 +3217,11 @@ export class QueryBuilder<
|
|
|
3142
3217
|
options?: DitoGraphOptions
|
|
3143
3218
|
): this
|
|
3144
3219
|
|
|
3145
|
-
|
|
3220
|
+
// Returns the query builder, which objection declares as `Promise<void>`.
|
|
3221
|
+
truncate(options?: {
|
|
3222
|
+
restart?: boolean
|
|
3223
|
+
cascade?: boolean
|
|
3224
|
+
}): this & Promise<void>
|
|
3146
3225
|
|
|
3147
3226
|
ArrayQueryBuilderType: QueryBuilder<M, M[]>
|
|
3148
3227
|
SingleQueryBuilderType: QueryBuilder<M, M>
|
|
@@ -3212,8 +3291,8 @@ export type PartialModelObject<T extends Model> = {
|
|
|
3212
3291
|
export type PartialDitoModelGraph<M extends Partial<Model>> = {
|
|
3213
3292
|
[K in objection.NonFunctionPropertyNames<M>]?: objection.Defined<
|
|
3214
3293
|
M[K]
|
|
3215
|
-
> extends Model
|
|
3216
|
-
? PartialDitoModelGraph<
|
|
3294
|
+
> extends infer D extends Model
|
|
3295
|
+
? PartialDitoModelGraph<D>
|
|
3217
3296
|
: objection.Defined<M[K]> extends Array<infer I>
|
|
3218
3297
|
? I extends Partial<Model>
|
|
3219
3298
|
? PartialDitoModelGraph<I>[]
|
|
@@ -3606,11 +3685,11 @@ export function convertRelation(
|
|
|
3606
3685
|
): Record<string, any>
|
|
3607
3686
|
|
|
3608
3687
|
export function getRelationClass(
|
|
3609
|
-
relation: string |
|
|
3610
|
-
):
|
|
3688
|
+
relation: string | objection.RelationType
|
|
3689
|
+
): objection.RelationType | null
|
|
3611
3690
|
|
|
3612
3691
|
export function isThroughRelationClass(
|
|
3613
|
-
relationClass:
|
|
3692
|
+
relationClass: objection.RelationType
|
|
3614
3693
|
): boolean
|
|
3615
3694
|
|
|
3616
3695
|
export function addRelationSchemas(
|
|
@@ -3682,11 +3761,25 @@ export interface KoaContextState {
|
|
|
3682
3761
|
[key: string]: unknown
|
|
3683
3762
|
}
|
|
3684
3763
|
|
|
3764
|
+
/**
|
|
3765
|
+
* The session on `ctx.session`, mirroring koa-session's `Session` class, which
|
|
3766
|
+
* it doesn't export.
|
|
3767
|
+
*/
|
|
3768
|
+
export type KoaSession = Record<string, any> & {
|
|
3769
|
+
isNew: boolean
|
|
3770
|
+
readonly length: number
|
|
3771
|
+
readonly populated: boolean
|
|
3772
|
+
maxAge: number
|
|
3773
|
+
save(callback?: (error?: Error) => void): Promise<void> | undefined
|
|
3774
|
+
regenerate(callback?: (error?: Error) => void): Promise<void> | undefined
|
|
3775
|
+
manuallyCommit(): Promise<void> | undefined
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3685
3778
|
export type KoaContext<$State = KoaContextState> = Koa.ParameterizedContext<
|
|
3686
3779
|
$State,
|
|
3687
3780
|
{
|
|
3688
3781
|
transaction: objection.Transaction
|
|
3689
|
-
session:
|
|
3782
|
+
session: KoaSession | null
|
|
3690
3783
|
logger: PinoLogger
|
|
3691
3784
|
}
|
|
3692
3785
|
> & {
|
|
@@ -3701,9 +3794,10 @@ type OrReadOnly<T> = Readonly<T> | T
|
|
|
3701
3794
|
|
|
3702
3795
|
type OrPromiseOf<T> = Promise<T> | T
|
|
3703
3796
|
|
|
3704
|
-
type
|
|
3705
|
-
|
|
3706
|
-
|
|
3797
|
+
type ModelControllerLike = { modelClass?: Class<Model> }
|
|
3798
|
+
|
|
3799
|
+
type ModelFromModelController<$ModelController extends ModelControllerLike> =
|
|
3800
|
+
InstanceType<Exclude<$ModelController['modelClass'], undefined>>
|
|
3707
3801
|
|
|
3708
3802
|
type SerializeModelPropertyValue<T> = T extends (infer U)[]
|
|
3709
3803
|
? SerializeModelPropertyValue<U>[]
|