@ditojs/server 2.85.2 → 2.87.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 +14 -14
- package/src/cli/db/createMigration.js +4 -1
- package/src/controllers/Controller.js +6 -2
- package/src/mixins/AssetMixin.js +4 -2
- package/src/models/Model.js +3 -3
- package/src/storage/AssetFile.js +2 -0
- package/src/storage/Storage.js +40 -3
- package/src/storage/Storage.test.js +58 -0
- package/types/index.d.ts +1712 -349
- package/types/tests/application.test-d.ts +26 -0
- package/types/tests/controller.test-d.ts +113 -0
- package/types/tests/errors.test-d.ts +53 -0
- package/types/tests/fixtures.ts +19 -0
- package/types/tests/model.test-d.ts +193 -0
- package/types/tests/query-builder.test-d.ts +106 -0
- package/types/tests/relation.test-d.ts +83 -0
- package/types/tests/storage.test-d.ts +113 -0
package/types/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { CompressOptions } from 'koa-compress'
|
|
|
20
20
|
import koaMount from 'koa-mount'
|
|
21
21
|
import koaResponseTime from 'koa-response-time'
|
|
22
22
|
import koaSession from 'koa-session'
|
|
23
|
+
import multer from '@koa/multer'
|
|
23
24
|
import multerS3 from 'multer-s3'
|
|
24
25
|
import * as objection from 'objection'
|
|
25
26
|
import { KnexSnakeCaseMappersFactory } from 'objection'
|
|
@@ -39,6 +40,16 @@ export type Page<$Model extends Model = Model> = {
|
|
|
39
40
|
results: $Model[]
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
/** Result of compiling action parameter definitions. */
|
|
44
|
+
export type CompiledParametersValidator = {
|
|
45
|
+
list: Array<{ name: string | null } & Schema>
|
|
46
|
+
schema: Schema | null
|
|
47
|
+
asObject: boolean
|
|
48
|
+
dataName: string
|
|
49
|
+
validate: ((data: unknown) => boolean | PromiseLike<boolean>) | null
|
|
50
|
+
hasModelRefs: boolean
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
export type ApplicationConfig = {
|
|
43
54
|
/** @defaultValue `production` */
|
|
44
55
|
env?: 'production' | 'development'
|
|
@@ -101,7 +112,7 @@ export type ApplicationConfig = {
|
|
|
101
112
|
* Whether to normalize paths from camel case to kebab case.
|
|
102
113
|
*
|
|
103
114
|
* @defaultValue `false`
|
|
104
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
115
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/controllers.md#path-normalization|Path Normalization}
|
|
105
116
|
*/
|
|
106
117
|
normalizePaths?: boolean
|
|
107
118
|
/**
|
|
@@ -126,7 +137,7 @@ export type ApplicationConfig = {
|
|
|
126
137
|
*/
|
|
127
138
|
helmet?: boolean | Parameters<typeof helmet>[0]
|
|
128
139
|
logger?: {
|
|
129
|
-
prettyPrint
|
|
140
|
+
prettyPrint?: PrettyOptions
|
|
130
141
|
} & PinoLoggerOptions
|
|
131
142
|
/**
|
|
132
143
|
* Configure body parser.
|
|
@@ -179,21 +190,36 @@ export type ApplicationConfig = {
|
|
|
179
190
|
// See https://github.com/brianc/node-pg-types/blob/master/index.d.ts#L67
|
|
180
191
|
typeParsers?: Record<number, <I extends string | Buffer>(value: I) => any>
|
|
181
192
|
}
|
|
182
|
-
/**
|
|
183
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Service configurations keyed by service name. Pass
|
|
195
|
+
* `false` as a value to disable a service.
|
|
196
|
+
*/
|
|
197
|
+
services?: Record<string, Record<string, unknown> | false>
|
|
184
198
|
storages?: StorageConfigs
|
|
199
|
+
/** Logger configuration at the application level. */
|
|
200
|
+
logger?: {
|
|
201
|
+
prettyPrint?: PrettyOptions
|
|
202
|
+
} & PinoLoggerOptions
|
|
185
203
|
assets?: {
|
|
186
204
|
/**
|
|
187
|
-
* Threshold after which unused assets that haven't
|
|
188
|
-
* timeframe are removed.
|
|
205
|
+
* Threshold after which unused assets that haven't
|
|
206
|
+
* seen changes for given timeframe are removed.
|
|
189
207
|
*
|
|
190
|
-
* @example
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* @default `0`
|
|
208
|
+
* @example '1 hr 20 mins'
|
|
209
|
+
* @defaultValue `'24h'`
|
|
194
210
|
* @see https://www.npmjs.com/package/parse-duration
|
|
195
211
|
*/
|
|
196
212
|
cleanupTimeThreshold?: string | number
|
|
213
|
+
/**
|
|
214
|
+
* Threshold after which dangling assets (uploaded
|
|
215
|
+
* but never persisted) are removed. Cannot be set to
|
|
216
|
+
* 0 as the file would be deleted immediately after
|
|
217
|
+
* upload.
|
|
218
|
+
*
|
|
219
|
+
* @defaultValue `'24h'`
|
|
220
|
+
* @see https://www.npmjs.com/package/parse-duration
|
|
221
|
+
*/
|
|
222
|
+
danglingTimeThreshold?: string | number
|
|
197
223
|
}
|
|
198
224
|
}
|
|
199
225
|
|
|
@@ -205,14 +231,14 @@ export type MulterS3File = {
|
|
|
205
231
|
contentDisposition: null
|
|
206
232
|
storageClass: string
|
|
207
233
|
serverSideEncryption: null
|
|
208
|
-
metadata:
|
|
234
|
+
metadata: Record<string, string>
|
|
209
235
|
location: string
|
|
210
236
|
etag: string
|
|
211
237
|
}
|
|
212
238
|
|
|
213
239
|
export type StorageConfigs = { [key: string]: StorageConfig }
|
|
214
240
|
|
|
215
|
-
|
|
241
|
+
interface CommonStorageConfig {
|
|
216
242
|
/**
|
|
217
243
|
* The concurrency at which assets are added to storage.
|
|
218
244
|
*
|
|
@@ -236,7 +262,7 @@ export type S3StorageConfig = CommonStorageConfig & {
|
|
|
236
262
|
's3' | 'key' | 'contentType' | 'metadata'
|
|
237
263
|
>
|
|
238
264
|
|
|
239
|
-
export
|
|
265
|
+
export interface DiskStorageConfig extends CommonStorageConfig {
|
|
240
266
|
type: 'disk'
|
|
241
267
|
/**
|
|
242
268
|
* The path to the directory where assets are stored on.
|
|
@@ -300,7 +326,7 @@ export interface ApiConfig {
|
|
|
300
326
|
* prefer to use another path normalization algorithm, they can be defined the
|
|
301
327
|
* api settings passed to the DitoAdmin constructor.
|
|
302
328
|
*
|
|
303
|
-
* @
|
|
329
|
+
* @defaultValue Application.config.app.normalizePaths
|
|
304
330
|
*/
|
|
305
331
|
normalizePaths?: boolean
|
|
306
332
|
/** Auth resources */
|
|
@@ -329,9 +355,8 @@ export interface ApiConfig {
|
|
|
329
355
|
resources?: Record<string, (resource: ApiResource | string) => string>
|
|
330
356
|
|
|
331
357
|
/**
|
|
332
|
-
* Optionally override / extend headers
|
|
333
|
-
*
|
|
334
|
-
* @defaultValue `
|
|
358
|
+
* Optionally override / extend headers sent with API
|
|
359
|
+
* requests.
|
|
335
360
|
*/
|
|
336
361
|
headers?: Record<string, string>
|
|
337
362
|
}
|
|
@@ -355,41 +380,261 @@ export class Application<$Models extends Models = Models> {
|
|
|
355
380
|
basePath?: string
|
|
356
381
|
config?: ApplicationConfig
|
|
357
382
|
validator?: Validator
|
|
358
|
-
|
|
359
|
-
|
|
383
|
+
router?: {
|
|
384
|
+
add(
|
|
385
|
+
method: string,
|
|
386
|
+
path: string,
|
|
387
|
+
handler: Function
|
|
388
|
+
): this
|
|
389
|
+
find(
|
|
390
|
+
method: string,
|
|
391
|
+
path: string
|
|
392
|
+
): {
|
|
393
|
+
status: number
|
|
394
|
+
handler?: Function
|
|
395
|
+
params?: Record<string, string>
|
|
396
|
+
allowed: string[]
|
|
397
|
+
}
|
|
398
|
+
getAllowedMethods(
|
|
399
|
+
path?: string | null,
|
|
400
|
+
exclude?: string | null
|
|
401
|
+
): string[]
|
|
402
|
+
normalizePath(path: string): string
|
|
403
|
+
}
|
|
360
404
|
/**
|
|
361
405
|
* Subscribe to application events. Event names: `'before:start'`,
|
|
362
406
|
* `'after:start'`, `'before:stop'`, `'after:stop'`, `'error'`
|
|
363
407
|
*/
|
|
364
|
-
events?: Record<
|
|
365
|
-
|
|
408
|
+
events?: Record<
|
|
409
|
+
string,
|
|
410
|
+
(this: Application<$Models>, ...args: any[]) => void
|
|
411
|
+
>
|
|
412
|
+
models?: $Models
|
|
366
413
|
controllers?: ApplicationControllers
|
|
367
|
-
|
|
414
|
+
/** Service classes or instances to register. */
|
|
368
415
|
services?: Services
|
|
369
416
|
middleware?: Koa.Middleware
|
|
370
417
|
})
|
|
371
418
|
|
|
419
|
+
/** The base path for resolving relative paths. */
|
|
420
|
+
basePath: string
|
|
421
|
+
/** The merged application configuration. */
|
|
422
|
+
config: ApplicationConfig
|
|
423
|
+
/** The Knex instance for database access. */
|
|
424
|
+
knex: Knex
|
|
425
|
+
/** The HTTP server instance, or `null` if not started. */
|
|
426
|
+
server: import('http').Server | null
|
|
427
|
+
/** Whether the application is currently running. */
|
|
428
|
+
isRunning: boolean
|
|
429
|
+
/** The schema validator instance. */
|
|
430
|
+
validator: Validator
|
|
431
|
+
/** Registered storage instances by name. */
|
|
432
|
+
storages: Record<string, Storage>
|
|
433
|
+
/** Registered service instances by name. */
|
|
434
|
+
services: Record<string, Service>
|
|
435
|
+
/** Registered controller instances by name. */
|
|
436
|
+
controllers: Record<string, Controller>
|
|
372
437
|
models: $Models
|
|
438
|
+
|
|
373
439
|
setup(): Promise<void>
|
|
440
|
+
/** Calls `start()` and exits the process on failure. */
|
|
374
441
|
execute(): Promise<void>
|
|
375
442
|
start(): Promise<void>
|
|
376
443
|
stop(timeout?: number): Promise<void>
|
|
377
|
-
|
|
444
|
+
|
|
445
|
+
/** Configures the pino logger instance. */
|
|
446
|
+
setupLogger(): void
|
|
447
|
+
/** Configures the Knex database connection. */
|
|
448
|
+
setupKnex(): void
|
|
449
|
+
/**
|
|
450
|
+
* Configures all Koa middleware (logger, error
|
|
451
|
+
* handling, CORS, compression, session, passport,
|
|
452
|
+
* etc.).
|
|
453
|
+
*/
|
|
454
|
+
setupMiddleware(middleware?: Koa.Middleware): void
|
|
455
|
+
|
|
456
|
+
addStorage(
|
|
457
|
+
config: StorageConfig | Storage,
|
|
458
|
+
name?: string
|
|
459
|
+
): Storage
|
|
460
|
+
|
|
378
461
|
addStorages(storages: StorageConfigs): void
|
|
379
462
|
setupStorages(): Promise<void>
|
|
380
|
-
|
|
463
|
+
/** Returns a storage by name, or `null` if not found. */
|
|
464
|
+
getStorage(name: string): Storage | null
|
|
465
|
+
|
|
466
|
+
addService(
|
|
467
|
+
service: Service | Class<Service>,
|
|
468
|
+
name?: string
|
|
469
|
+
): void
|
|
470
|
+
|
|
381
471
|
addServices(services: Services): void
|
|
382
472
|
setupServices(): Promise<void>
|
|
473
|
+
/** Returns a service by name. */
|
|
474
|
+
getService(name: string): Service | null
|
|
475
|
+
/** Finds a service matching the given predicate. */
|
|
476
|
+
findService(
|
|
477
|
+
callback: (service: Service) => boolean
|
|
478
|
+
): Service | null
|
|
479
|
+
|
|
383
480
|
addModel(model: Class<Model>): void
|
|
384
481
|
addModels(models: Models): void
|
|
385
482
|
setupModels(): Promise<void>
|
|
386
|
-
|
|
387
|
-
|
|
483
|
+
/**
|
|
484
|
+
* Returns a model class by name. Also looks up
|
|
485
|
+
* `${name}Model` if the name doesn't already end in
|
|
486
|
+
* 'Model'.
|
|
487
|
+
*/
|
|
488
|
+
getModel(name: string): Class<Model> | null
|
|
489
|
+
/** Finds a model class matching the given predicate. */
|
|
490
|
+
findModel(
|
|
491
|
+
callback: (model: Class<Model>) => boolean
|
|
492
|
+
): Class<Model> | null
|
|
493
|
+
|
|
494
|
+
addController(
|
|
495
|
+
controller: Controller | Class<Controller>,
|
|
496
|
+
namespace?: string
|
|
497
|
+
): void
|
|
498
|
+
|
|
499
|
+
addControllers(
|
|
500
|
+
controllers: ApplicationControllers,
|
|
501
|
+
namespace?: string
|
|
502
|
+
): void
|
|
503
|
+
|
|
388
504
|
setupControllers(): Promise<void>
|
|
389
|
-
|
|
505
|
+
/** Returns a controller by its URL. */
|
|
506
|
+
getController(url: string): Controller | null
|
|
507
|
+
/**
|
|
508
|
+
* Finds a controller matching the given predicate.
|
|
509
|
+
*/
|
|
510
|
+
findController(
|
|
511
|
+
callback: (controller: Controller) => boolean
|
|
512
|
+
): Controller | null
|
|
513
|
+
|
|
514
|
+
/** Returns the admin controller, if registered. */
|
|
515
|
+
getAdminController(): AdminController | null
|
|
516
|
+
|
|
517
|
+
/** Compiles a JSON schema into a validation function. */
|
|
518
|
+
compileValidator(
|
|
519
|
+
jsonSchema: Schema,
|
|
520
|
+
options?: Record<string, any>
|
|
521
|
+
): Ajv.ValidateFunction | null
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Compiles action parameter definitions into a
|
|
525
|
+
* validation function and metadata.
|
|
526
|
+
*/
|
|
527
|
+
compileParametersValidator(
|
|
528
|
+
parameters:
|
|
529
|
+
| Record<string, Schema>
|
|
530
|
+
| Array<{ name?: string } & Schema>,
|
|
531
|
+
options?: Record<string, any>
|
|
532
|
+
): CompiledParametersValidator
|
|
533
|
+
|
|
534
|
+
/** Creates a ValidationError from raw error data. */
|
|
535
|
+
createValidationError(error: {
|
|
536
|
+
type: string
|
|
537
|
+
message?: string
|
|
538
|
+
errors: Ajv.ErrorObject[]
|
|
539
|
+
options?: Record<string, any>
|
|
540
|
+
json?: any
|
|
541
|
+
}): ValidationError
|
|
542
|
+
|
|
543
|
+
/** Creates a DatabaseError from a native DB error. */
|
|
544
|
+
createDatabaseError(error: dbErrors.DBError): DatabaseError
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Wraps a database identifier through Knex's
|
|
548
|
+
* `wrapIdentifier` (e.g. camelCase to snake_case).
|
|
549
|
+
*/
|
|
550
|
+
normalizeIdentifier(identifier: string): string
|
|
551
|
+
/**
|
|
552
|
+
* Reverses a database identifier through Knex's
|
|
553
|
+
* `postProcessResponse` (e.g. snake_case to camelCase).
|
|
554
|
+
*/
|
|
555
|
+
denormalizeIdentifier(identifier: string): string
|
|
556
|
+
/** Normalizes a URL path. */
|
|
557
|
+
normalizePath(path: string): string
|
|
558
|
+
|
|
559
|
+
/** Formats an error for logging/response. */
|
|
560
|
+
formatError(error: Error | ResponseError): unknown
|
|
561
|
+
|
|
562
|
+
/** Logs an error to the application logger. */
|
|
563
|
+
logError(error: Error | ResponseError, ctx?: KoaContext): void
|
|
564
|
+
/** Releases unused assets past the cleanup threshold. */
|
|
565
|
+
releaseUnusedAssets(options?: {
|
|
566
|
+
timeThreshold?: string | number | null
|
|
567
|
+
transaction?: objection.Transaction | null
|
|
568
|
+
concurrency?: number
|
|
569
|
+
}): Promise<Model[] | undefined>
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Creates Asset model records for the given files.
|
|
573
|
+
* Returns inserted assets, or `null` if no AssetModel
|
|
574
|
+
* is registered.
|
|
575
|
+
*/
|
|
576
|
+
createAssets(
|
|
577
|
+
storage: Storage,
|
|
578
|
+
files: AssetFile[],
|
|
579
|
+
count?: number,
|
|
580
|
+
transaction?: objection.Transaction | null
|
|
581
|
+
): Promise<Model[] | null>
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Handles added, removed, and changed asset files.
|
|
585
|
+
* Imports foreign assets, updates counts, and schedules
|
|
586
|
+
* cleanup. Returns imported files when an AssetModel is
|
|
587
|
+
* registered.
|
|
588
|
+
*/
|
|
589
|
+
handleAddedAndRemovedAssets(
|
|
590
|
+
storage: Storage,
|
|
591
|
+
addedFiles: AssetFile[],
|
|
592
|
+
removedFiles: AssetFile[],
|
|
593
|
+
changedFiles: AssetFile[],
|
|
594
|
+
transaction?: objection.Transaction | null
|
|
595
|
+
): Promise<AssetFile[] | undefined>
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Finds and imports missing assets from external
|
|
599
|
+
* sources (data URIs, file:// URLs, or HTTP URLs).
|
|
600
|
+
* Returns the list of imported files.
|
|
601
|
+
*/
|
|
602
|
+
addForeignAssets(
|
|
603
|
+
storage: Storage,
|
|
604
|
+
files: AssetFile[],
|
|
605
|
+
transaction?: objection.Transaction | null
|
|
606
|
+
): Promise<AssetFile[]>
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Handles modifications to existing asset files by
|
|
610
|
+
* updating their stored data. Returns the list of
|
|
611
|
+
* modified files.
|
|
612
|
+
*/
|
|
613
|
+
handleModifiedAssets(
|
|
614
|
+
storage: Storage,
|
|
615
|
+
files: AssetFile[],
|
|
616
|
+
transaction?: objection.Transaction | null
|
|
617
|
+
): Promise<AssetFile[]>
|
|
618
|
+
|
|
619
|
+
addRoute(
|
|
620
|
+
method: HTTPMethod,
|
|
621
|
+
path: string,
|
|
622
|
+
transacted: boolean,
|
|
623
|
+
middlewares: OrArrayOf<(ctx: KoaContext, next: Function) => void>,
|
|
624
|
+
controller?: Controller | null,
|
|
625
|
+
action?: any
|
|
626
|
+
): void
|
|
627
|
+
|
|
628
|
+
loadAdminViteConfig(): Promise<UserConfig | null>
|
|
629
|
+
getAssetConfig(options?: {
|
|
630
|
+
models?: string[]
|
|
631
|
+
normalizeDbNames?: boolean
|
|
632
|
+
}): Record<string, Record<string, Record<string, any>>>
|
|
633
|
+
|
|
634
|
+
defineAdminViteConfig(config?: UserConfig): UserConfig | null
|
|
390
635
|
logger: PinoLogger
|
|
391
636
|
requestStorage: AsyncLocalStorage<AsyncRequestLocals>
|
|
392
|
-
requestLocals: AsyncRequestLocals
|
|
637
|
+
requestLocals: Partial<AsyncRequestLocals>
|
|
393
638
|
}
|
|
394
639
|
|
|
395
640
|
export interface Application
|
|
@@ -428,7 +673,7 @@ export interface ModelRelation {
|
|
|
428
673
|
/**
|
|
429
674
|
* The type of relation
|
|
430
675
|
*
|
|
431
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
676
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-relations.md#relation-types|Relation Types}
|
|
432
677
|
*/
|
|
433
678
|
relation: LiteralUnion<
|
|
434
679
|
'belongsTo' | 'hasMany' | 'hasOne' | 'manyToMany' | 'hasOneThrough'
|
|
@@ -449,7 +694,7 @@ export interface ModelRelation {
|
|
|
449
694
|
* When set to true the join model class and table is to be built
|
|
450
695
|
* automatically, or allows to specify an existing one manually.
|
|
451
696
|
*
|
|
452
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
697
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-relations.md#join-models-and-tables|Join Models and Tables}
|
|
453
698
|
*/
|
|
454
699
|
through?:
|
|
455
700
|
| boolean
|
|
@@ -494,12 +739,15 @@ export interface ModelRelation {
|
|
|
494
739
|
*/
|
|
495
740
|
scope?: string
|
|
496
741
|
/**
|
|
497
|
-
* Optionally, a filter
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
* filter names as keys and argument arrays as values.
|
|
742
|
+
* Optionally, a filter to apply when loading the relation's models.
|
|
743
|
+
* Accepts a Dito.js filter name/object (resolved via the related model's
|
|
744
|
+
* filters), or a callback/find-filter object as an alias for `modify`.
|
|
501
745
|
*/
|
|
502
|
-
filter?:
|
|
746
|
+
filter?:
|
|
747
|
+
| string
|
|
748
|
+
| { [name: string]: unknown[] }
|
|
749
|
+
| ((query: QueryBuilder) => void)
|
|
750
|
+
| Record<string, unknown>
|
|
503
751
|
/**
|
|
504
752
|
* Controls whether the auto-inserted foreign key property should be marked as
|
|
505
753
|
* nullable. This only makes sense on a 'belongsTo' relation, where the model
|
|
@@ -513,6 +761,16 @@ export interface ModelRelation {
|
|
|
513
761
|
* their owner.
|
|
514
762
|
*/
|
|
515
763
|
owner?: boolean
|
|
764
|
+
/**
|
|
765
|
+
* An optional modify callback or find-filter object to scope the relation
|
|
766
|
+
* query. This is the Objection.js-native way to modify relation queries.
|
|
767
|
+
*
|
|
768
|
+
* As a function: `modify: query => query.where('active', true)`
|
|
769
|
+
* As an object: `modify: { active: true }` (converted to a find-filter)
|
|
770
|
+
*/
|
|
771
|
+
modify?:
|
|
772
|
+
| ((query: QueryBuilder) => void)
|
|
773
|
+
| Record<string, unknown>
|
|
516
774
|
}
|
|
517
775
|
|
|
518
776
|
export type ModelProperty<T = any> = Schema<T> & {
|
|
@@ -544,8 +802,9 @@ export type ModelProperty<T = any> = Schema<T> & {
|
|
|
544
802
|
*/
|
|
545
803
|
unique?: boolean | string
|
|
546
804
|
/**
|
|
547
|
-
* Marks the column for a property of type 'integer' to be
|
|
548
|
-
* migrations, by calling the .
|
|
805
|
+
* Marks the column for a property of type 'integer' to be
|
|
806
|
+
* unsigned in the migrations, by calling the .unsigned()
|
|
807
|
+
* method.
|
|
549
808
|
*/
|
|
550
809
|
unsigned?: boolean
|
|
551
810
|
/**
|
|
@@ -567,45 +826,90 @@ export type ModelProperty<T = any> = Schema<T> & {
|
|
|
567
826
|
hidden?: boolean
|
|
568
827
|
}
|
|
569
828
|
|
|
829
|
+
/**
|
|
830
|
+
* A scope function that modifies a query builder in-place
|
|
831
|
+
* to apply filtering or ordering logic. The return value
|
|
832
|
+
* is ignored at runtime.
|
|
833
|
+
*
|
|
834
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-scopes.md|Model Scopes}
|
|
835
|
+
*/
|
|
570
836
|
export type ModelScope<$Model extends Model = Model> = (
|
|
571
|
-
this: $Model,
|
|
572
837
|
query: QueryBuilder<$Model>,
|
|
573
838
|
applyParentScope: (query: QueryBuilder<$Model>) => QueryBuilder<$Model>
|
|
574
839
|
) => QueryBuilder<$Model, any> | void
|
|
575
840
|
|
|
841
|
+
/**
|
|
842
|
+
* Map of scope names to scope functions. Scopes can be
|
|
843
|
+
* applied via `withScope()` on queries or set as defaults
|
|
844
|
+
* on controllers.
|
|
845
|
+
*
|
|
846
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-scopes.md|Model Scopes}
|
|
847
|
+
*/
|
|
576
848
|
export type ModelScopes<$Model extends Model = Model> = Record<
|
|
577
849
|
string,
|
|
578
850
|
ModelScope<$Model>
|
|
579
851
|
>
|
|
580
852
|
|
|
853
|
+
/**
|
|
854
|
+
* A filter handler function that modifies a query builder
|
|
855
|
+
* based on external parameters (e.g. from URL query strings).
|
|
856
|
+
*/
|
|
581
857
|
export type ModelFilterFunction<$Model extends Model = Model> = (
|
|
582
858
|
queryBuilder: QueryBuilder<$Model>,
|
|
583
859
|
...args: any[]
|
|
584
860
|
) => void
|
|
585
861
|
|
|
862
|
+
/**
|
|
863
|
+
* A model filter definition. Can be one of:
|
|
864
|
+
*
|
|
865
|
+
* - A **built-in filter** reference (`{ filter: 'text' }` or
|
|
866
|
+
* `{ filter: 'date-range' }`) with optional `properties`.
|
|
867
|
+
* - A **custom filter** with a `handler` function, optional
|
|
868
|
+
* `parameters` schema for validation, and optional
|
|
869
|
+
* `response` schema.
|
|
870
|
+
* - A bare **handler function** as shorthand.
|
|
871
|
+
*
|
|
872
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-filters.md|Model Filters}
|
|
873
|
+
*/
|
|
586
874
|
export type ModelFilter<$Model extends Model = Model> =
|
|
587
875
|
| {
|
|
588
|
-
filter: 'text' | 'date-range'
|
|
876
|
+
filter: LiteralUnion<'text' | 'date-range'>
|
|
589
877
|
properties?: string[]
|
|
590
878
|
}
|
|
591
879
|
| {
|
|
592
880
|
handler: ModelFilterFunction<$Model>
|
|
593
881
|
parameters?: { [key: string]: Schema }
|
|
882
|
+
response?: Schema
|
|
594
883
|
// TODO: validate type
|
|
595
884
|
validate?: any
|
|
596
885
|
}
|
|
597
886
|
| ModelFilterFunction<$Model>
|
|
598
887
|
|
|
888
|
+
/**
|
|
889
|
+
* Map of filter names to filter definitions.
|
|
890
|
+
*
|
|
891
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-filters.md|Model Filters}
|
|
892
|
+
*/
|
|
599
893
|
export type ModelFilters<$Model extends Model = Model> = Record<
|
|
600
894
|
string,
|
|
601
895
|
ModelFilter<$Model>
|
|
602
896
|
>
|
|
603
897
|
|
|
898
|
+
/**
|
|
899
|
+
* Configuration for a model asset property, linking it to a
|
|
900
|
+
* named storage backend.
|
|
901
|
+
*/
|
|
604
902
|
export interface ModelAsset {
|
|
903
|
+
/** The name of the storage backend to use. */
|
|
605
904
|
storage: string
|
|
905
|
+
/**
|
|
906
|
+
* Whether to read image dimensions (width/height) on
|
|
907
|
+
* upload.
|
|
908
|
+
*/
|
|
606
909
|
readDimensions?: boolean
|
|
607
910
|
}
|
|
608
911
|
|
|
912
|
+
/** Map of property names to their asset configurations. */
|
|
609
913
|
export type ModelAssets = Record<string, ModelAsset>
|
|
610
914
|
|
|
611
915
|
export interface ModelOptions extends objection.ModelOptions {
|
|
@@ -618,6 +922,23 @@ type ModelHookFunction<$Model extends Model> = (
|
|
|
618
922
|
args: objection.StaticHookArguments<$Model>
|
|
619
923
|
) => void
|
|
620
924
|
|
|
925
|
+
/**
|
|
926
|
+
* Map of lifecycle hook names to handler functions. Hook
|
|
927
|
+
* names follow the pattern `'before:operation'` or
|
|
928
|
+
* `'after:operation'` where operation is `find`, `insert`,
|
|
929
|
+
* `update`, or `delete`.
|
|
930
|
+
*
|
|
931
|
+
* @example
|
|
932
|
+
* ```ts
|
|
933
|
+
* static hooks: ModelHooks<MyModel> = {
|
|
934
|
+
* 'before:insert': ({ items }) => {
|
|
935
|
+
* for (const item of items) {
|
|
936
|
+
* item.createdAt = new Date()
|
|
937
|
+
* }
|
|
938
|
+
* }
|
|
939
|
+
* }
|
|
940
|
+
* ```
|
|
941
|
+
*/
|
|
621
942
|
export type ModelHooks<$Model extends Model = Model> = {
|
|
622
943
|
[key in `${'before' | 'after'}:${
|
|
623
944
|
| 'find'
|
|
@@ -628,64 +949,448 @@ export type ModelHooks<$Model extends Model = Model> = {
|
|
|
628
949
|
}
|
|
629
950
|
|
|
630
951
|
export class Model extends objection.Model {
|
|
631
|
-
|
|
952
|
+
constructor(json?: Record<string, any>)
|
|
953
|
+
|
|
954
|
+
/** @see {@link https://github.com/ditojs/dito/blob/main/docs/model-properties.md|Model Properties} */
|
|
632
955
|
static properties: ModelProperties
|
|
633
956
|
|
|
634
|
-
/** @see {@link https://github.com/ditojs/dito/blob/
|
|
957
|
+
/** @see {@link https://github.com/ditojs/dito/blob/main/docs/model-relations.md|Model Relations} */
|
|
635
958
|
static relations: ModelRelations
|
|
636
959
|
|
|
637
|
-
/** @see {@link https://github.com/ditojs/dito/blob/
|
|
960
|
+
/** @see {@link https://github.com/ditojs/dito/blob/main/docs/model-scopes.md|Model Scopes} */
|
|
638
961
|
static scopes: ModelScopes<Model>
|
|
639
962
|
|
|
640
|
-
/** @see {@link https://github.com/ditojs/dito/blob/
|
|
963
|
+
/** @see {@link https://github.com/ditojs/dito/blob/main/docs/model-filters.md|Model Filters} */
|
|
641
964
|
static filters: ModelFilters<Model>
|
|
642
965
|
|
|
643
966
|
static hooks: ModelHooks<Model>
|
|
644
967
|
|
|
645
968
|
static assets: ModelAssets
|
|
646
969
|
|
|
647
|
-
|
|
970
|
+
/** The merged definition object, assembled from the class hierarchy. */
|
|
971
|
+
static get definition(): {
|
|
972
|
+
properties: ModelProperties
|
|
973
|
+
relations: ModelRelations
|
|
974
|
+
scopes: ModelScopes
|
|
975
|
+
filters: ModelFilters
|
|
976
|
+
hooks: ModelHooks
|
|
977
|
+
assets: ModelAssets
|
|
978
|
+
options: Record<string, any>
|
|
979
|
+
modifiers: Record<
|
|
980
|
+
string,
|
|
981
|
+
(
|
|
982
|
+
builder: objection.QueryBuilder<any, any>,
|
|
983
|
+
...args: any[]
|
|
984
|
+
) => void
|
|
985
|
+
>
|
|
986
|
+
schema: Record<string, any>
|
|
987
|
+
[key: string]: any
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/** Derived from class name (removes 'Model' suffix). */
|
|
991
|
+
static get tableName(): string
|
|
992
|
+
/** Returns the primary key column(s). */
|
|
993
|
+
static get idColumn(): string | string[]
|
|
994
|
+
/**
|
|
995
|
+
* Returns the cached converted relation mappings for
|
|
996
|
+
* the model.
|
|
997
|
+
*/
|
|
998
|
+
static get relationMappings(): Record<
|
|
999
|
+
string,
|
|
1000
|
+
objection.RelationMapping<Model>
|
|
1001
|
+
>
|
|
1002
|
+
|
|
1003
|
+
/** Returns the cached converted JSON schema. */
|
|
1004
|
+
static get jsonSchema(): Record<string, any>
|
|
1005
|
+
/** Aliases `computedAttributes`. */
|
|
1006
|
+
static get virtualAttributes(): string[]
|
|
1007
|
+
|
|
1008
|
+
static get jsonAttributes(): string[]
|
|
1009
|
+
static get booleanAttributes(): string[]
|
|
1010
|
+
static get dateAttributes(): string[]
|
|
1011
|
+
static get computedAttributes(): string[]
|
|
1012
|
+
static get hiddenAttributes(): string[]
|
|
1013
|
+
|
|
1014
|
+
/** The application instance this model is registered with. */
|
|
1015
|
+
static app: Application<Models>
|
|
1016
|
+
/** Whether the model has been initialized by the application. */
|
|
1017
|
+
static initialized: boolean
|
|
1018
|
+
/** The QueryBuilder class used by this model. */
|
|
1019
|
+
static QueryBuilder: typeof QueryBuilder
|
|
1020
|
+
/** Whether to deep-clone object attributes on read. */
|
|
1021
|
+
static cloneObjectAttributes: boolean
|
|
1022
|
+
/**
|
|
1023
|
+
* Only pick properties defined in jsonSchema
|
|
1024
|
+
* for database JSON.
|
|
1025
|
+
*/
|
|
1026
|
+
static pickJsonSchemaProperties: boolean
|
|
1027
|
+
/** Whether to use LIMIT 1 in first() queries. */
|
|
1028
|
+
static useLimitInFirst: boolean
|
|
1029
|
+
|
|
1030
|
+
/** Called by the application during model registration. */
|
|
1031
|
+
static configure(app: Application<Models>): void
|
|
1032
|
+
/** Sets up model schema, relations, and scopes. */
|
|
1033
|
+
static setup(): void
|
|
1034
|
+
/**
|
|
1035
|
+
* Async initialization hook. Override in subclasses for
|
|
1036
|
+
* setup that requires async operations.
|
|
1037
|
+
* @overridable
|
|
1038
|
+
*/
|
|
1039
|
+
static initialize(): void | Promise<void>
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Creates a model instance from JSON data. Dito's
|
|
1043
|
+
* override adds async validation support: returns a
|
|
1044
|
+
* Promise when `options.async` is true.
|
|
1045
|
+
* @override
|
|
1046
|
+
*/
|
|
1047
|
+
static fromJson<M extends Model>(
|
|
1048
|
+
this: Constructor<M>,
|
|
1049
|
+
json: Record<string, any>,
|
|
1050
|
+
options?: ModelOptions
|
|
1051
|
+
): M | Promise<M>
|
|
1052
|
+
|
|
1053
|
+
/** Returns the named scope function, if defined. */
|
|
1054
|
+
static getScope(name: string): ModelScope | undefined
|
|
1055
|
+
/** Returns whether the model has the named scope. */
|
|
1056
|
+
static hasScope(name: string): boolean
|
|
1057
|
+
/**
|
|
1058
|
+
* Creates a reference instance containing only the
|
|
1059
|
+
* identifier properties.
|
|
1060
|
+
*/
|
|
1061
|
+
static getReference(
|
|
1062
|
+
modelOrId: Model | Id,
|
|
1063
|
+
includeProperties?: string[]
|
|
1064
|
+
): Model
|
|
1065
|
+
|
|
1066
|
+
/** Returns whether the given value is a model reference. */
|
|
1067
|
+
static isReference(obj: unknown): boolean
|
|
1068
|
+
/** Returns the named property definition, if found. */
|
|
1069
|
+
static getProperty(name: string): ModelProperty | null
|
|
1070
|
+
/** Returns the model's query modifiers. */
|
|
1071
|
+
static getModifiers(): Record<
|
|
1072
|
+
string,
|
|
1073
|
+
(
|
|
1074
|
+
builder: objection.QueryBuilder<any, any>,
|
|
1075
|
+
...args: any[]
|
|
1076
|
+
) => void
|
|
1077
|
+
>
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* Returns property names matching the given filter
|
|
1081
|
+
* function.
|
|
1082
|
+
*/
|
|
1083
|
+
static getAttributes(
|
|
1084
|
+
filter: (property: ModelProperty) => boolean
|
|
1085
|
+
): string[]
|
|
1086
|
+
|
|
1087
|
+
/** Returns relations where this model is the related side. */
|
|
1088
|
+
static getRelatedRelations(): objection.Relation[]
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Maps property names to column names (identity
|
|
1092
|
+
* function — naming is handled at Knex level).
|
|
1093
|
+
* @override
|
|
1094
|
+
*/
|
|
1095
|
+
static propertyNameToColumnName(
|
|
1096
|
+
propertyName: string
|
|
1097
|
+
): string
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Maps column names to property names (identity
|
|
1101
|
+
* function — naming is handled at Knex level).
|
|
1102
|
+
* @override
|
|
1103
|
+
*/
|
|
1104
|
+
static columnNameToPropertyName(
|
|
1105
|
+
columnName: string
|
|
1106
|
+
): string
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Handles modifiers not found directly on the model by
|
|
1110
|
+
* checking scopes and special prefixes.
|
|
1111
|
+
* @override
|
|
1112
|
+
*/
|
|
1113
|
+
static modifierNotFound(
|
|
1114
|
+
query: QueryBuilder<Model>,
|
|
1115
|
+
modifier: string | Function
|
|
1116
|
+
): void
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* Creates a NotFoundError with model context.
|
|
1120
|
+
* @override
|
|
1121
|
+
*/
|
|
1122
|
+
static createNotFoundError(
|
|
1123
|
+
ctx: Record<string, any>,
|
|
1124
|
+
error?: Error
|
|
1125
|
+
): NotFoundError
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* Returns the shared application validator.
|
|
1129
|
+
* @override
|
|
1130
|
+
*/
|
|
1131
|
+
static createValidator(): Validator
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Creates a typed validation or relation error from
|
|
1135
|
+
* raw error data.
|
|
1136
|
+
* @override
|
|
1137
|
+
*/
|
|
1138
|
+
static createValidationError(error: {
|
|
1139
|
+
type: string
|
|
1140
|
+
message?: string
|
|
1141
|
+
errors: any[]
|
|
1142
|
+
options?: Record<string, any>
|
|
1143
|
+
json?: any
|
|
1144
|
+
}): ResponseError
|
|
1145
|
+
|
|
1146
|
+
/** Starts a new transaction. */
|
|
1147
|
+
static transaction(): Promise<objection.Transaction>
|
|
1148
|
+
/** Runs a callback within a transaction. */
|
|
1149
|
+
static transaction(
|
|
1150
|
+
handler: (trx: objection.Transaction) => Promise<any>
|
|
1151
|
+
): Promise<any>
|
|
1152
|
+
|
|
1153
|
+
static transaction(
|
|
1154
|
+
trx: objection.Transaction,
|
|
1155
|
+
handler: (trx: objection.Transaction) => Promise<any>
|
|
1156
|
+
): Promise<any>
|
|
1157
|
+
|
|
1158
|
+
static getPropertyOrRelationAtDataPath(
|
|
1159
|
+
dataPath: OrArrayOf<string>
|
|
1160
|
+
): {
|
|
1161
|
+
property?: ModelProperty | null
|
|
1162
|
+
relation?: objection.Relation | null
|
|
1163
|
+
wildcard?: string | null
|
|
1164
|
+
dataPath?: string | null
|
|
1165
|
+
nestedDataPath?: string | null
|
|
1166
|
+
name?: string
|
|
1167
|
+
expression?: string | null
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* Creates a query builder for a relation. Unlike
|
|
1172
|
+
* Objection.js, Dito automatically aliases the query
|
|
1173
|
+
* to the relation name.
|
|
1174
|
+
* @override
|
|
1175
|
+
*/
|
|
1176
|
+
static relatedQuery<M extends Model>(
|
|
1177
|
+
this: Constructor<M>,
|
|
1178
|
+
relationName: string,
|
|
1179
|
+
trx?: objection.Transaction
|
|
1180
|
+
): QueryBuilder<M>
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* Hook called before find queries.
|
|
1184
|
+
* @overridable
|
|
1185
|
+
*/
|
|
1186
|
+
static beforeFind(
|
|
1187
|
+
args: objection.StaticHookArguments<Model>
|
|
1188
|
+
): Promise<void>
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* Hook called after find queries.
|
|
1192
|
+
* @overridable
|
|
1193
|
+
*/
|
|
1194
|
+
static afterFind(
|
|
1195
|
+
args: objection.StaticHookArguments<Model>
|
|
1196
|
+
): Promise<void>
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Hook called before insert queries.
|
|
1200
|
+
* @overridable
|
|
1201
|
+
*/
|
|
1202
|
+
static beforeInsert(
|
|
1203
|
+
args: objection.StaticHookArguments<Model>
|
|
1204
|
+
): Promise<void>
|
|
1205
|
+
|
|
1206
|
+
/**
|
|
1207
|
+
* Hook called after insert queries.
|
|
1208
|
+
* @overridable
|
|
1209
|
+
*/
|
|
1210
|
+
static afterInsert(
|
|
1211
|
+
args: objection.StaticHookArguments<Model>
|
|
1212
|
+
): Promise<void>
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Hook called before update queries.
|
|
1216
|
+
* @overridable
|
|
1217
|
+
*/
|
|
1218
|
+
static beforeUpdate(
|
|
1219
|
+
args: objection.StaticHookArguments<Model>
|
|
1220
|
+
): Promise<void>
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Hook called after update queries.
|
|
1224
|
+
* @overridable
|
|
1225
|
+
*/
|
|
1226
|
+
static afterUpdate(
|
|
1227
|
+
args: objection.StaticHookArguments<Model>
|
|
1228
|
+
): Promise<void>
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Hook called before delete queries.
|
|
1232
|
+
* @overridable
|
|
1233
|
+
*/
|
|
1234
|
+
static beforeDelete(
|
|
1235
|
+
args: objection.StaticHookArguments<Model>
|
|
1236
|
+
): Promise<void>
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* Hook called after delete queries.
|
|
1240
|
+
* @overridable
|
|
1241
|
+
*/
|
|
1242
|
+
static afterDelete(
|
|
1243
|
+
args: objection.StaticHookArguments<Model>
|
|
1244
|
+
): Promise<void>
|
|
648
1245
|
|
|
649
1246
|
static count: {
|
|
650
|
-
(column?: objection.ColumnRef, options?: { as: string }): number
|
|
651
|
-
(aliasToColumnDict: Record<string, string | string[]>): number
|
|
652
|
-
(...columns: objection.ColumnRef[]): number
|
|
1247
|
+
(column?: objection.ColumnRef, options?: { as: string }): Promise<number>
|
|
1248
|
+
(aliasToColumnDict: Record<string, string | string[]>): Promise<number>
|
|
1249
|
+
(...columns: objection.ColumnRef[]): Promise<number>
|
|
653
1250
|
}
|
|
654
1251
|
|
|
655
1252
|
/**
|
|
656
|
-
*
|
|
657
|
-
*
|
|
1253
|
+
* Filters a model graph using a relation expression,
|
|
1254
|
+
* removing any data not matching the expression.
|
|
1255
|
+
*/
|
|
1256
|
+
static filterGraph(
|
|
1257
|
+
modelGraph: Model | Model[],
|
|
1258
|
+
expr: string | objection.RelationExpression<Model>
|
|
1259
|
+
): Model | Model[]
|
|
1260
|
+
|
|
1261
|
+
/**
|
|
1262
|
+
* Populates a model graph by loading relations defined
|
|
1263
|
+
* in the given expression.
|
|
1264
|
+
*/
|
|
1265
|
+
static populateGraph(
|
|
1266
|
+
modelGraph: Model | Model[],
|
|
1267
|
+
expr: string | objection.RelationExpression<Model>,
|
|
1268
|
+
trx?: objection.Transaction
|
|
1269
|
+
): Promise<Model | Model[]>
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Dito.js automatically adds an `id` property if a model
|
|
1273
|
+
* property with the `primary: true` setting is not
|
|
1274
|
+
* already explicitly defined.
|
|
658
1275
|
*/
|
|
659
1276
|
readonly id: Id
|
|
660
1277
|
|
|
661
1278
|
/**
|
|
662
|
-
* Dito.js automatically adds a `foreignKeyId` property
|
|
663
|
-
* occurring in relations definitions are
|
|
664
|
-
* properties.
|
|
1279
|
+
* Dito.js automatically adds a `foreignKeyId` property
|
|
1280
|
+
* if foreign keys occurring in relations definitions are
|
|
1281
|
+
* not explicitly defined in the properties.
|
|
665
1282
|
*/
|
|
666
1283
|
readonly foreignKeyId: Id
|
|
667
1284
|
|
|
668
1285
|
QueryBuilderType: QueryBuilder<this, this[]>
|
|
669
1286
|
|
|
670
|
-
// Todo: include application settings
|
|
671
1287
|
$app: Application<Models>
|
|
672
|
-
|
|
1288
|
+
/**
|
|
1289
|
+
* Called after model construction. Override in subclasses
|
|
1290
|
+
* for custom instance initialization.
|
|
1291
|
+
* @overridable
|
|
1292
|
+
*/
|
|
1293
|
+
$initialize(): void
|
|
1294
|
+
$is(model: Model | null | undefined): boolean
|
|
1295
|
+
/** Returns `true` if all named properties are defined. */
|
|
1296
|
+
$has(...properties: string[]): boolean
|
|
1297
|
+
/** Runs a callback within a transaction. */
|
|
1298
|
+
$transaction(
|
|
1299
|
+
handler: (trx: objection.Transaction) => Promise<any>
|
|
1300
|
+
): Promise<any>
|
|
1301
|
+
|
|
1302
|
+
$transaction(
|
|
1303
|
+
trx: objection.Transaction,
|
|
1304
|
+
handler: (trx: objection.Transaction) => Promise<any>
|
|
1305
|
+
): Promise<any>
|
|
1306
|
+
|
|
1307
|
+
/** Emits an event on this model instance. */
|
|
1308
|
+
$emit(event: string, ...args: any[]): Promise<any[]>
|
|
1309
|
+
/**
|
|
1310
|
+
* Filters a model graph using a relation expression,
|
|
1311
|
+
* removing data not matching the expression.
|
|
1312
|
+
*/
|
|
1313
|
+
$filterGraph(
|
|
1314
|
+
modelGraph: Model | Model[],
|
|
1315
|
+
expr: string | objection.RelationExpression<Model>
|
|
1316
|
+
): Model | Model[]
|
|
1317
|
+
|
|
1318
|
+
/**
|
|
1319
|
+
* Populates a model graph by loading relations defined
|
|
1320
|
+
* in the given expression.
|
|
1321
|
+
*/
|
|
1322
|
+
$populateGraph(
|
|
1323
|
+
modelGraph: Model | Model[],
|
|
1324
|
+
expr: string | objection.RelationExpression<Model>,
|
|
1325
|
+
trx?: objection.Transaction
|
|
1326
|
+
): Promise<Model | Model[]>
|
|
1327
|
+
|
|
673
1328
|
$update(
|
|
674
|
-
attributes: Partial<
|
|
1329
|
+
attributes: Partial<ModelDataProperties<this>>,
|
|
675
1330
|
trx?: objection.Transaction
|
|
676
1331
|
): objection.SingleQueryBuilder<objection.QueryBuilderType<this>>
|
|
677
1332
|
|
|
678
1333
|
$patch(
|
|
679
|
-
attributes: Partial<
|
|
1334
|
+
attributes: Partial<ModelDataProperties<this>>,
|
|
680
1335
|
trx?: objection.Transaction
|
|
681
1336
|
): objection.SingleQueryBuilder<objection.QueryBuilderType<this>>
|
|
682
1337
|
|
|
683
1338
|
$validate<$JSON extends null | {}>(
|
|
684
1339
|
json?: $JSON,
|
|
685
1340
|
options?: ModelOptions & Record<string, any>
|
|
686
|
-
): Promise<$JSON | this>
|
|
1341
|
+
): ($JSON | this) | Promise<$JSON | this>
|
|
1342
|
+
|
|
1343
|
+
$validateGraph(
|
|
1344
|
+
options: ModelOptions & Record<string, any>
|
|
1345
|
+
): Promise<this>
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Sets JSON data on the model instance. Triggers
|
|
1349
|
+
* `$initialize()` when appropriate.
|
|
1350
|
+
* @override
|
|
1351
|
+
*/
|
|
1352
|
+
$setJson(
|
|
1353
|
+
json: Record<string, any>,
|
|
1354
|
+
options?: ModelOptions
|
|
1355
|
+
): this
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Formats data for database storage. Converts dates to
|
|
1359
|
+
* ISO strings, handles boolean conversion for SQLite,
|
|
1360
|
+
* and removes computed properties.
|
|
1361
|
+
* @override @overridable
|
|
1362
|
+
*/
|
|
1363
|
+
$formatDatabaseJson(
|
|
1364
|
+
json: Record<string, any>
|
|
1365
|
+
): Record<string, any>
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Parses data from the database. Converts SQLite
|
|
1369
|
+
* booleans back and delegates to `$parseJson()` for
|
|
1370
|
+
* date and AssetFile handling.
|
|
1371
|
+
* @override @overridable
|
|
1372
|
+
*/
|
|
1373
|
+
$parseDatabaseJson(
|
|
1374
|
+
json: Record<string, any>
|
|
1375
|
+
): Record<string, any>
|
|
687
1376
|
|
|
688
|
-
|
|
1377
|
+
/**
|
|
1378
|
+
* Parses general JSON data. Converts date strings to
|
|
1379
|
+
* Date objects and handles asset file conversion.
|
|
1380
|
+
* @override @overridable
|
|
1381
|
+
*/
|
|
1382
|
+
$parseJson(
|
|
1383
|
+
json: Record<string, any>
|
|
1384
|
+
): Record<string, any>
|
|
1385
|
+
|
|
1386
|
+
/**
|
|
1387
|
+
* Formats data for API output. Removes hidden
|
|
1388
|
+
* attributes from the JSON representation.
|
|
1389
|
+
* @override @overridable
|
|
1390
|
+
*/
|
|
1391
|
+
$formatJson(
|
|
1392
|
+
json: Record<string, any>
|
|
1393
|
+
): Record<string, any>
|
|
689
1394
|
|
|
690
1395
|
/* -------------------- Start QueryBuilder.mixin(Model) ------------------- */
|
|
691
1396
|
static first: StaticQueryBuilderMethod<'first'>
|
|
@@ -708,13 +1413,15 @@ export class Model extends objection.Model {
|
|
|
708
1413
|
static insert: StaticQueryBuilderMethod<'insert'>
|
|
709
1414
|
static upsert: StaticQueryBuilderMethod<'upsert'>
|
|
710
1415
|
static update: StaticQueryBuilderMethod<'update'>
|
|
711
|
-
static relate: StaticQueryBuilderMethod<'relate'>
|
|
712
1416
|
static patch: StaticQueryBuilderMethod<'patch'>
|
|
713
|
-
|
|
714
|
-
static truncate: StaticQueryBuilderMethod<'truncate'>
|
|
715
1417
|
static delete: StaticQueryBuilderMethod<'delete'>
|
|
1418
|
+
|
|
1419
|
+
static updateById: StaticQueryBuilderMethod<'updateById'>
|
|
1420
|
+
static patchById: StaticQueryBuilderMethod<'patchById'>
|
|
716
1421
|
static deleteById: StaticQueryBuilderMethod<'deleteById'>
|
|
717
1422
|
|
|
1423
|
+
static truncate: StaticQueryBuilderMethod<'truncate'>
|
|
1424
|
+
|
|
718
1425
|
static insertAndFetch: StaticQueryBuilderMethod<'insertAndFetch'>
|
|
719
1426
|
static upsertAndFetch: StaticQueryBuilderMethod<'upsertAndFetch'>
|
|
720
1427
|
static updateAndFetch: StaticQueryBuilderMethod<'updateAndFetch'>
|
|
@@ -756,7 +1463,7 @@ export class Model extends objection.Model {
|
|
|
756
1463
|
static whereNotColumn: StaticQueryBuilderMethod<'whereNotColumn'>
|
|
757
1464
|
static whereComposite: StaticQueryBuilderMethod<'whereComposite'>
|
|
758
1465
|
static whereInComposite: StaticQueryBuilderMethod<'whereInComposite'>
|
|
759
|
-
static whereNotInComposite: StaticQueryBuilderMethod<'
|
|
1466
|
+
static whereNotInComposite: StaticQueryBuilderMethod<'whereNotInComposite'>
|
|
760
1467
|
static whereJsonHasAny: StaticQueryBuilderMethod<'whereJsonHasAny'>
|
|
761
1468
|
static whereJsonHasAll: StaticQueryBuilderMethod<'whereJsonHasAll'>
|
|
762
1469
|
static whereJsonIsArray: StaticQueryBuilderMethod<'whereJsonIsArray'>
|
|
@@ -803,6 +1510,13 @@ export type ModelRelations = Record<string, ModelRelation>
|
|
|
803
1510
|
|
|
804
1511
|
export type ModelProperties = Record<string, ModelProperty>
|
|
805
1512
|
|
|
1513
|
+
/**
|
|
1514
|
+
* A controller action definition. Either an options object
|
|
1515
|
+
* with `handler`, `method`, `path`, `authorize`, etc., or a
|
|
1516
|
+
* bare handler function. The HTTP method and path are
|
|
1517
|
+
* derived from the action name key (e.g. `'postImport'`
|
|
1518
|
+
* maps to `POST /import`).
|
|
1519
|
+
*/
|
|
806
1520
|
export type ControllerAction<$Controller extends Controller = Controller> =
|
|
807
1521
|
| ControllerActionOptions<$Controller>
|
|
808
1522
|
| ControllerActionHandler<$Controller>
|
|
@@ -810,29 +1524,47 @@ export type ControllerAction<$Controller extends Controller = Controller> =
|
|
|
810
1524
|
export class Controller {
|
|
811
1525
|
app: Application
|
|
812
1526
|
/**
|
|
813
|
-
* Optionally provide the controller path. A default is
|
|
814
|
-
* normalized class name otherwise.
|
|
1527
|
+
* Optionally provide the controller path. A default is
|
|
1528
|
+
* deducted from the normalized class name otherwise.
|
|
815
1529
|
*/
|
|
816
1530
|
path?: string
|
|
817
1531
|
/**
|
|
818
|
-
* The controller's name. If not provided, it is
|
|
819
|
-
* the controller class name.
|
|
820
|
-
*
|
|
1532
|
+
* The controller's name. If not provided, it is
|
|
1533
|
+
* automatically deducted from the controller class name.
|
|
1534
|
+
* If this name ends in 'Controller', that is stripped
|
|
1535
|
+
* off the name, so 'GreetingsController' turns into
|
|
1536
|
+
* 'Greetings'.
|
|
821
1537
|
*/
|
|
822
1538
|
name?: string
|
|
823
1539
|
/**
|
|
824
|
-
* The controller's namespace, which is prepended to path
|
|
825
|
-
* absolute controller route. Note that
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
*
|
|
1540
|
+
* The controller's namespace, which is prepended to path
|
|
1541
|
+
* to generate the absolute controller route. Note that
|
|
1542
|
+
* it is rare to provide this manually. Usually Dito.js
|
|
1543
|
+
* determines the namespace automatically from the
|
|
1544
|
+
* controller object passed to the Dito.js application's
|
|
1545
|
+
* constructor and its sub-objects.
|
|
829
1546
|
*
|
|
830
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
1547
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/controllers.md#namespaces Namespaces}
|
|
831
1548
|
*/
|
|
832
1549
|
namespace?: string
|
|
1550
|
+
/** The fully resolved URL for this controller. */
|
|
1551
|
+
url?: string
|
|
1552
|
+
/**
|
|
1553
|
+
* Whether actions should be transacted by default.
|
|
1554
|
+
* Can be overridden per-action.
|
|
1555
|
+
*/
|
|
1556
|
+
transacted?: boolean
|
|
1557
|
+
/** Whether this controller has been initialized. */
|
|
1558
|
+
initialized: boolean
|
|
1559
|
+
/** The nesting level of this controller. */
|
|
1560
|
+
level: number
|
|
1561
|
+
/** Whether to log routes during setup. */
|
|
1562
|
+
logRoutes: boolean
|
|
1563
|
+
|
|
833
1564
|
/**
|
|
834
|
-
* A list of allowed actions. If provided, only the
|
|
835
|
-
* as strings will be mapped to
|
|
1565
|
+
* A list of allowed actions. If provided, only the
|
|
1566
|
+
* action names listed here as strings will be mapped to
|
|
1567
|
+
* routes, everything else will be omitted.
|
|
836
1568
|
*/
|
|
837
1569
|
allow?: OrReadOnly<ControllerActionName[]>
|
|
838
1570
|
|
|
@@ -840,9 +1572,28 @@ export class Controller {
|
|
|
840
1572
|
authorize?: Authorize
|
|
841
1573
|
actions?: ControllerActions<this>
|
|
842
1574
|
|
|
1575
|
+
/** Returns the logger, optionally scoped to a context. */
|
|
1576
|
+
getLogger(ctx?: KoaContext): PinoLogger
|
|
1577
|
+
/** The controller's logger instance. */
|
|
1578
|
+
get logger(): PinoLogger
|
|
1579
|
+
/**
|
|
1580
|
+
* Returns a member model for the request context.
|
|
1581
|
+
* No-op in the base class; override in subclasses.
|
|
1582
|
+
*/
|
|
1583
|
+
getMember(
|
|
1584
|
+
ctx?: KoaContext,
|
|
1585
|
+
base?: any,
|
|
1586
|
+
options?: {
|
|
1587
|
+
query?: Record<string, any>
|
|
1588
|
+
modify?: (query: QueryBuilder<Model>) => QueryBuilder<Model>
|
|
1589
|
+
forUpdate?: boolean
|
|
1590
|
+
}
|
|
1591
|
+
): Promise<Model | null>
|
|
1592
|
+
|
|
1593
|
+
setProperty(key: string, value: unknown): void
|
|
1594
|
+
|
|
843
1595
|
/**
|
|
844
|
-
*
|
|
845
|
-
* which sets up the actions and routes, and the custom `async initialize()`.
|
|
1596
|
+
* Called right after the constructor, before `setup()` and `initialize()`.
|
|
846
1597
|
* @overridable
|
|
847
1598
|
*/
|
|
848
1599
|
configure(): void
|
|
@@ -853,8 +1604,6 @@ export class Controller {
|
|
|
853
1604
|
* @overridable
|
|
854
1605
|
*/
|
|
855
1606
|
initialize(): Promise<void>
|
|
856
|
-
// TODO: type reflectActionsObject
|
|
857
|
-
reflectActionsObject(): any
|
|
858
1607
|
/**
|
|
859
1608
|
* @overridable
|
|
860
1609
|
*/
|
|
@@ -874,8 +1623,8 @@ export class Controller {
|
|
|
874
1623
|
handlers: ((ctx: KoaContext, next: Function) => void)[]
|
|
875
1624
|
): void
|
|
876
1625
|
|
|
877
|
-
setupActions(type: string):
|
|
878
|
-
setupActionRoute(type:
|
|
1626
|
+
setupActions(type: string): any
|
|
1627
|
+
setupActionRoute(type: string, action: ControllerAction): void
|
|
879
1628
|
setupAssets(): any
|
|
880
1629
|
setupAssetRoute(
|
|
881
1630
|
dataPath: OrArrayOf<string>,
|
|
@@ -892,55 +1641,88 @@ export class Controller {
|
|
|
892
1641
|
/** To be overridden by sub-classes. */
|
|
893
1642
|
getPath(type: string, path: string): string
|
|
894
1643
|
getUrl(type: string, path: string): string
|
|
895
|
-
inheritValues(type: string):
|
|
896
|
-
processValues(values:
|
|
897
|
-
|
|
898
|
-
values: any
|
|
1644
|
+
inheritValues(type: string): Record<string, unknown> | undefined
|
|
1645
|
+
processValues(values: Record<string, unknown>): {
|
|
1646
|
+
values: Record<string, unknown>
|
|
899
1647
|
allow: string[]
|
|
900
|
-
authorize: Authorize
|
|
1648
|
+
authorize: Record<string, Authorize>
|
|
901
1649
|
}
|
|
902
1650
|
|
|
903
1651
|
emitHook(
|
|
904
1652
|
type: string,
|
|
905
|
-
handleResult:
|
|
906
|
-
ctx:
|
|
1653
|
+
handleResult: boolean,
|
|
1654
|
+
ctx: KoaContext,
|
|
907
1655
|
...args: any[]
|
|
908
1656
|
): Promise<any>
|
|
909
1657
|
|
|
910
|
-
processAuthorize(
|
|
911
|
-
|
|
912
|
-
|
|
1658
|
+
processAuthorize(
|
|
1659
|
+
authorize: Authorize
|
|
1660
|
+
): (ctx: KoaContext, member?: Model) => OrPromiseOf<boolean>
|
|
1661
|
+
|
|
1662
|
+
describeAuthorize(authorize: Authorize): string
|
|
1663
|
+
handleAuthorization(
|
|
1664
|
+
authorization: (
|
|
1665
|
+
ctx: KoaContext,
|
|
1666
|
+
member?: Model
|
|
1667
|
+
) => OrPromiseOf<boolean>,
|
|
1668
|
+
ctx: KoaContext,
|
|
1669
|
+
member?: Model
|
|
1670
|
+
): Promise<void>
|
|
913
1671
|
}
|
|
914
1672
|
|
|
1673
|
+
export interface Controller extends EventEmitter {}
|
|
1674
|
+
|
|
1675
|
+
/** A named action parameter with a JSON Schema definition. */
|
|
915
1676
|
export type ActionParameter = Schema & { name: string }
|
|
916
1677
|
|
|
1678
|
+
/**
|
|
1679
|
+
* Handler function for a model controller action. Receives
|
|
1680
|
+
* the Koa context and any resolved action parameters. `this`
|
|
1681
|
+
* is bound to the controller instance.
|
|
1682
|
+
*/
|
|
917
1683
|
export type ModelControllerActionHandler<
|
|
918
1684
|
$ModelController extends ModelController = ModelController
|
|
919
1685
|
> = (this: $ModelController, ctx: KoaContext, ...args: any[]) => any
|
|
920
1686
|
|
|
1687
|
+
/**
|
|
1688
|
+
* Handler function for a controller action. Receives the Koa
|
|
1689
|
+
* context and any resolved action parameters. `this` is
|
|
1690
|
+
* bound to the controller instance.
|
|
1691
|
+
*/
|
|
921
1692
|
export type ControllerActionHandler<
|
|
922
1693
|
$Controller extends Controller = Controller
|
|
923
1694
|
> = (this: $Controller, ctx: KoaContext, ...args: any[]) => any
|
|
924
1695
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1696
|
+
type ModelDataKey<T, K extends keyof T> = K extends
|
|
1697
|
+
| 'QueryBuilderType'
|
|
1698
|
+
| 'foreignKeyId'
|
|
1699
|
+
| `$${string}`
|
|
1700
|
+
? never
|
|
1701
|
+
: T[K] extends (...args: any[]) => any
|
|
1702
|
+
? never
|
|
1703
|
+
: K
|
|
1704
|
+
|
|
1705
|
+
type ModelDataProperties<$Model extends Model = Model> = {
|
|
1706
|
+
[K in keyof $Model as ModelDataKey<$Model, K>]: $Model[K] extends Model
|
|
1707
|
+
? ModelDataProperties<$Model[K]>
|
|
928
1708
|
: $Model[K]
|
|
929
1709
|
}
|
|
930
1710
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1711
|
+
/**
|
|
1712
|
+
* Authorization configuration for controllers and actions.
|
|
1713
|
+
*
|
|
1714
|
+
* - `boolean`: `true` requires authentication, `false` is
|
|
1715
|
+
* public.
|
|
1716
|
+
* - `'$self'`: Authorized only if the member matches the
|
|
1717
|
+
* authenticated user.
|
|
1718
|
+
* - `'$owner'`: Authorized if the member is owned by the
|
|
1719
|
+
* authenticated user (via `Model.$hasOwner()`).
|
|
1720
|
+
* - Any other `string`: Checked as a role via
|
|
1721
|
+
* `UserModel.$hasRole()`.
|
|
1722
|
+
* - `function`: Dynamically resolves to any of the above.
|
|
1723
|
+
* - `Record<HTTPMethod, string | string[]>`: Per-method
|
|
1724
|
+
* role authorization.
|
|
1725
|
+
*/
|
|
944
1726
|
export type Authorize =
|
|
945
1727
|
| boolean
|
|
946
1728
|
| OrArrayOf<LiteralUnion<'$self' | '$owner'>>
|
|
@@ -978,7 +1760,7 @@ export type BaseControllerActionOptions = {
|
|
|
978
1760
|
* Validates action parameters and maps them to Koa's `ctx.query` object
|
|
979
1761
|
* passed to the action handler.
|
|
980
1762
|
*
|
|
981
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
1763
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-properties.md Model Properties}
|
|
982
1764
|
*/
|
|
983
1765
|
parameters?: { [key: string]: Schema }
|
|
984
1766
|
/**
|
|
@@ -986,13 +1768,13 @@ export type BaseControllerActionOptions = {
|
|
|
986
1768
|
* optionally maps the value to a key inside a returned object when it
|
|
987
1769
|
* contains a `name` property.
|
|
988
1770
|
*
|
|
989
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
1771
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-properties.md Model Properties}
|
|
990
1772
|
*/
|
|
991
1773
|
response?: Schema & { name?: string }
|
|
992
1774
|
/**
|
|
993
1775
|
* The scope(s) to be applied to every query executed through the action.
|
|
994
1776
|
*
|
|
995
|
-
* @see {@link https://github.com/ditojs/dito/blob/
|
|
1777
|
+
* @see {@link https://github.com/ditojs/dito/blob/main/docs/model-scopes.md Model Scopes}
|
|
996
1778
|
*/
|
|
997
1779
|
scope?: string[]
|
|
998
1780
|
/**
|
|
@@ -1039,12 +1821,21 @@ export type MemberActionParameter<$Model extends Model = Model> =
|
|
|
1039
1821
|
modify?: (query: QueryBuilder<$Model>) => QueryBuilder<$Model>
|
|
1040
1822
|
}
|
|
1041
1823
|
|
|
1824
|
+
/**
|
|
1825
|
+
* A model controller action: either an options object with
|
|
1826
|
+
* `handler` or a bare handler function.
|
|
1827
|
+
*/
|
|
1042
1828
|
export type ModelControllerAction<
|
|
1043
1829
|
$ModelController extends ModelController = ModelController
|
|
1044
1830
|
> =
|
|
1045
1831
|
| ModelControllerActionOptions<$ModelController>
|
|
1046
1832
|
| ModelControllerActionHandler<$ModelController>
|
|
1047
1833
|
|
|
1834
|
+
/**
|
|
1835
|
+
* Map of action names to action definitions for a model
|
|
1836
|
+
* controller's collection-level actions (e.g. `getList`,
|
|
1837
|
+
* `postCreate`).
|
|
1838
|
+
*/
|
|
1048
1839
|
export type ModelControllerActions<
|
|
1049
1840
|
$ModelController extends ModelController = ModelController
|
|
1050
1841
|
> = {
|
|
@@ -1065,6 +1856,12 @@ type ModelControllerMemberAction<
|
|
|
1065
1856
|
})
|
|
1066
1857
|
| ModelControllerActionHandler<$ModelController>
|
|
1067
1858
|
|
|
1859
|
+
/**
|
|
1860
|
+
* Map of action names to action definitions for a model
|
|
1861
|
+
* controller's member-level actions (e.g. `get`, `patch`,
|
|
1862
|
+
* `delete`). Member actions can use `{ from: 'member' }`
|
|
1863
|
+
* parameters to receive the resolved member model.
|
|
1864
|
+
*/
|
|
1068
1865
|
export type ModelControllerMemberActions<
|
|
1069
1866
|
$ModelController extends ModelController = ModelController
|
|
1070
1867
|
> = {
|
|
@@ -1073,15 +1870,33 @@ export type ModelControllerMemberActions<
|
|
|
1073
1870
|
authorize?: Authorize
|
|
1074
1871
|
}
|
|
1075
1872
|
|
|
1873
|
+
/**
|
|
1874
|
+
* Action name pattern: an HTTP method followed by an
|
|
1875
|
+
* optional suffix, e.g. `'getStats'`, `'postImport'`,
|
|
1876
|
+
* `'deleteAll'`.
|
|
1877
|
+
*/
|
|
1076
1878
|
export type ControllerActionName = `${HTTPMethod}${string}`
|
|
1077
1879
|
|
|
1880
|
+
/**
|
|
1881
|
+
* Map of action names to action definitions for a
|
|
1882
|
+
* controller. Supports `allow` to whitelist specific
|
|
1883
|
+
* actions and `authorize` for group-level authorization.
|
|
1884
|
+
*/
|
|
1078
1885
|
export type ControllerActions<$Controller extends Controller = Controller> = {
|
|
1079
1886
|
[name: ControllerActionName]: ControllerAction<$Controller>
|
|
1080
1887
|
allow?: OrReadOnly<ControllerActionName[]>
|
|
1081
1888
|
authorize?: Authorize
|
|
1082
1889
|
}
|
|
1083
1890
|
|
|
1084
|
-
export class UsersController<
|
|
1891
|
+
export class UsersController<
|
|
1892
|
+
M extends Model = Model
|
|
1893
|
+
> extends ModelController<M> {
|
|
1894
|
+
/**
|
|
1895
|
+
* Returns whether the current request is authenticated
|
|
1896
|
+
* and the user is an instance of the controller's model.
|
|
1897
|
+
*/
|
|
1898
|
+
isAuthenticated(ctx: KoaContext): boolean
|
|
1899
|
+
}
|
|
1085
1900
|
|
|
1086
1901
|
export class AdminController extends Controller {
|
|
1087
1902
|
config: AdminConfig
|
|
@@ -1097,8 +1912,8 @@ export class AdminController extends Controller {
|
|
|
1097
1912
|
|
|
1098
1913
|
sendDitoObject(ctx: Koa.Context): void
|
|
1099
1914
|
middleware(): Koa.Middleware
|
|
1100
|
-
setupViteServer(): void
|
|
1101
|
-
defineViteConfig(config
|
|
1915
|
+
setupViteServer(): Promise<void>
|
|
1916
|
+
defineViteConfig(config?: UserConfig): UserConfig
|
|
1102
1917
|
}
|
|
1103
1918
|
type ModelControllerHookType = 'collection' | 'member'
|
|
1104
1919
|
type ModelControllerHookKeys<
|
|
@@ -1123,8 +1938,6 @@ type ModelControllerHook<
|
|
|
1123
1938
|
result: objection.Page<ModelFromModelController<$ModelController>>
|
|
1124
1939
|
) => any
|
|
1125
1940
|
|
|
1126
|
-
type HookHandler = () => void
|
|
1127
|
-
|
|
1128
1941
|
type HookKeysFromController<$ModelController extends ModelController> =
|
|
1129
1942
|
| ModelControllerHookKeys<
|
|
1130
1943
|
Exclude<
|
|
@@ -1161,93 +1974,235 @@ type ModelControllerHooks<
|
|
|
1161
1974
|
> = {
|
|
1162
1975
|
[$Key in HookKeysFromController<$ModelController>]?: HandlerFromHookKey<
|
|
1163
1976
|
$ModelController,
|
|
1164
|
-
|
|
1977
|
+
$Key
|
|
1165
1978
|
>
|
|
1166
1979
|
}
|
|
1167
1980
|
|
|
1981
|
+
/**
|
|
1982
|
+
* Scope(s) to apply to all queries in a model controller.
|
|
1983
|
+
* A single scope name or an array of scope names.
|
|
1984
|
+
*/
|
|
1168
1985
|
export type ModelControllerScope = OrArrayOf<string>
|
|
1169
1986
|
|
|
1170
|
-
|
|
1987
|
+
/**
|
|
1988
|
+
* Abstract base class for controllers that operate on
|
|
1989
|
+
* model collections. Provides CRUD action infrastructure,
|
|
1990
|
+
* query building, and member resolution.
|
|
1991
|
+
*/
|
|
1992
|
+
export class CollectionController<
|
|
1993
|
+
$Model extends Model = Model
|
|
1994
|
+
> extends Controller {
|
|
1171
1995
|
/**
|
|
1172
|
-
* The model class
|
|
1173
|
-
*
|
|
1174
|
-
* registered with the application. As a convention, model controller names
|
|
1175
|
-
* should always be provided in pluralized form.
|
|
1996
|
+
* The model class this controller operates on. Set by
|
|
1997
|
+
* subclasses during configuration.
|
|
1176
1998
|
*/
|
|
1177
1999
|
modelClass?: Class<$Model>
|
|
1178
2000
|
/**
|
|
1179
|
-
*
|
|
1180
|
-
* instance level as in the controller base class, they are to be wrapped in a
|
|
1181
|
-
* designated object in order to be assigned to the collection.
|
|
2001
|
+
* Whether to use graph methods for insert/update/patch.
|
|
1182
2002
|
*
|
|
1183
|
-
*
|
|
1184
|
-
* of action names under the `allow` key. Only the action names listed there
|
|
1185
|
-
* will be mapped to routes, everything else will be omitted.
|
|
2003
|
+
* @defaultValue `false`
|
|
1186
2004
|
*/
|
|
1187
|
-
|
|
2005
|
+
graph?: boolean
|
|
2006
|
+
/** Whether the controller handles relate operations. */
|
|
2007
|
+
relate?: boolean
|
|
1188
2008
|
/**
|
|
1189
|
-
*
|
|
1190
|
-
* level as in the controller base class, they are to be wrapped in a
|
|
1191
|
-
* designated object in order to be assigned to the member.
|
|
1192
|
-
*
|
|
1193
|
-
* To limit which member actions will be mapped to routes, supply an array of
|
|
1194
|
-
* action names under the `allow` key. Only the action names listed there will
|
|
1195
|
-
* be mapped to routes, everything else will be omitted.
|
|
2009
|
+
* Whether the controller handles unrelate operations.
|
|
1196
2010
|
*/
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
2011
|
+
unrelate?: boolean
|
|
2012
|
+
/** Whether this is a one-to-one relation controller. */
|
|
2013
|
+
isOneToOne: boolean
|
|
2014
|
+
/** The route parameter name for the member id. */
|
|
2015
|
+
idParam: string
|
|
2016
|
+
/**
|
|
2017
|
+
* The scope(s) to apply to every query executed through
|
|
2018
|
+
* this controller.
|
|
2019
|
+
*/
|
|
2020
|
+
scope?: ModelControllerScope
|
|
2021
|
+
allowScope?: boolean | OrArrayOf<string>
|
|
2022
|
+
allowFilter?: boolean | OrArrayOf<string>
|
|
2023
|
+
allowParam?: OrArrayOf<LiteralUnion<keyof QueryParameterOptions>>
|
|
1204
2024
|
|
|
1205
2025
|
/**
|
|
1206
|
-
*
|
|
2026
|
+
* The controller's collection actions with built-in CRUD
|
|
2027
|
+
* defaults.
|
|
1207
2028
|
*/
|
|
1208
|
-
|
|
2029
|
+
collection?: ModelControllerActions<CollectionController<$Model>>
|
|
1209
2030
|
/**
|
|
1210
|
-
*
|
|
1211
|
-
*
|
|
1212
|
-
*
|
|
1213
|
-
* @see {@link https://github.com/ditojs/dito/blob/master/docs/model-queries.md#graph-methods Model Queries – Graph Methods}
|
|
2031
|
+
* The controller's member actions with built-in CRUD
|
|
2032
|
+
* defaults.
|
|
1214
2033
|
*/
|
|
1215
|
-
|
|
2034
|
+
member?: ModelControllerMemberActions<CollectionController<$Model>>
|
|
2035
|
+
|
|
2036
|
+
/** Creates a query builder for this controller's model. */
|
|
2037
|
+
query(trx?: objection.Transaction): QueryBuilder<$Model>
|
|
1216
2038
|
/**
|
|
1217
|
-
*
|
|
1218
|
-
*
|
|
1219
|
-
* supported parameter is allowed.
|
|
1220
|
-
*
|
|
1221
|
-
* @see {@link https://github.com/ditojs/dito/blob/master/docs/model-queries.md#find-methods) Model Queries – Find Methods}
|
|
2039
|
+
* Applies controller-level scopes and configuration to
|
|
2040
|
+
* a query builder.
|
|
1222
2041
|
*/
|
|
1223
|
-
|
|
2042
|
+
setupQuery(
|
|
2043
|
+
query: QueryBuilder<$Model>,
|
|
2044
|
+
base?: any
|
|
2045
|
+
): QueryBuilder<$Model>
|
|
2046
|
+
|
|
1224
2047
|
/**
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
* supported scope is allowed.
|
|
1228
|
-
*
|
|
1229
|
-
* @see {@link https://github.com/ditojs/dito/blob/master/docs/model-scopes.md Model Scopes}
|
|
2048
|
+
* Extracts the member id from the request context's
|
|
2049
|
+
* route parameters.
|
|
1230
2050
|
*/
|
|
1231
|
-
|
|
2051
|
+
getMemberId(ctx: KoaContext): Id | Id[]
|
|
1232
2052
|
/**
|
|
1233
|
-
*
|
|
1234
|
-
* parameter to the default model actions. If none is provided, every
|
|
1235
|
-
* supported filter is allowed.
|
|
1236
|
-
*
|
|
1237
|
-
* @see {@link https://github.com/ditojs/dito/blob/master/docs/model-filters.md Model Filters}
|
|
2053
|
+
* Retrieves the model id from a model instance.
|
|
1238
2054
|
*/
|
|
1239
|
-
|
|
2055
|
+
getModelId(model: $Model): Id | Id[]
|
|
1240
2056
|
/**
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
* @see {@link https://github.com/ditojs/dito/blob/master/docs/model-scopes.md Model Scopes}
|
|
2057
|
+
* Retrieves a member model from the database for the
|
|
2058
|
+
* current request context.
|
|
1244
2059
|
*/
|
|
1245
|
-
|
|
1246
|
-
|
|
2060
|
+
getMember(
|
|
2061
|
+
ctx: KoaContext,
|
|
2062
|
+
base?: any,
|
|
2063
|
+
options?: {
|
|
2064
|
+
query?: Record<string, any>
|
|
2065
|
+
modify?: (query: QueryBuilder<$Model>) => QueryBuilder<$Model>
|
|
2066
|
+
forUpdate?: boolean
|
|
2067
|
+
}
|
|
2068
|
+
): Promise<$Model | null>
|
|
2069
|
+
|
|
2070
|
+
/**
|
|
2071
|
+
* Executes a controller action within a transaction
|
|
2072
|
+
* context.
|
|
2073
|
+
*/
|
|
2074
|
+
execute(
|
|
2075
|
+
ctx: KoaContext,
|
|
2076
|
+
execute: (
|
|
2077
|
+
query: QueryBuilder<$Model>,
|
|
2078
|
+
trx?: objection.Transaction
|
|
2079
|
+
) => any
|
|
2080
|
+
): Promise<any>
|
|
2081
|
+
|
|
2082
|
+
/**
|
|
2083
|
+
* Extracts model IDs from the request body collection,
|
|
2084
|
+
* validating each ID.
|
|
2085
|
+
*/
|
|
2086
|
+
getCollectionIds(ctx: KoaContext): Array<Id | Id[]>
|
|
2087
|
+
/**
|
|
2088
|
+
* Returns relevant IDs for the current request: from
|
|
2089
|
+
* route params for member requests, from body for
|
|
2090
|
+
* collection requests.
|
|
2091
|
+
*/
|
|
2092
|
+
getIds(ctx: KoaContext): Array<Id | Id[]>
|
|
2093
|
+
/**
|
|
2094
|
+
* Returns the request context extended with a memberId
|
|
2095
|
+
* property.
|
|
2096
|
+
*/
|
|
2097
|
+
getContextWithMemberId(
|
|
2098
|
+
ctx: KoaContext,
|
|
2099
|
+
memberId?: Id | Id[]
|
|
2100
|
+
): KoaContext
|
|
2101
|
+
|
|
2102
|
+
/**
|
|
2103
|
+
* Validates and coerces a model ID using the model
|
|
2104
|
+
* class's reference mechanism.
|
|
2105
|
+
*/
|
|
2106
|
+
validateId(id: any): Id | Id[]
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* Executes an insert/update/patch action and fetches
|
|
2110
|
+
* the result. Supports both normal and DitoGraph modes.
|
|
2111
|
+
*/
|
|
2112
|
+
executeAndFetch(
|
|
2113
|
+
action: string,
|
|
2114
|
+
ctx: KoaContext,
|
|
2115
|
+
modify?: (
|
|
2116
|
+
query: QueryBuilder<$Model>,
|
|
2117
|
+
trx?: objection.Transaction
|
|
2118
|
+
) => void,
|
|
2119
|
+
body?: Record<string, any>
|
|
2120
|
+
): Promise<$Model>
|
|
2121
|
+
|
|
2122
|
+
/**
|
|
2123
|
+
* Executes a by-id mutation action and fetches the
|
|
2124
|
+
* result. Throws NotFoundError if not found.
|
|
2125
|
+
*/
|
|
2126
|
+
executeAndFetchById(
|
|
2127
|
+
action: string,
|
|
2128
|
+
ctx: KoaContext,
|
|
2129
|
+
modify?: (
|
|
2130
|
+
query: QueryBuilder<$Model>,
|
|
2131
|
+
trx?: objection.Transaction
|
|
2132
|
+
) => void,
|
|
2133
|
+
body?: Record<string, any>
|
|
2134
|
+
): Promise<$Model>
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
/**
|
|
2138
|
+
* Controller for a top-level model resource. Extends
|
|
2139
|
+
* CollectionController with relation and asset setup.
|
|
2140
|
+
*/
|
|
2141
|
+
export class ModelController<
|
|
2142
|
+
$Model extends Model = Model
|
|
2143
|
+
> extends CollectionController<$Model> {
|
|
2144
|
+
/**
|
|
2145
|
+
* The model class this controller represents. If not
|
|
2146
|
+
* provided, the singularized controller name is used
|
|
2147
|
+
* to look up the model class in models registered with
|
|
2148
|
+
* the application.
|
|
2149
|
+
*/
|
|
2150
|
+
modelClass?: Class<$Model>
|
|
2151
|
+
/**
|
|
2152
|
+
* The controller's collection actions. Wrap actions in
|
|
2153
|
+
* this object to assign them to the collection.
|
|
2154
|
+
*/
|
|
2155
|
+
collection?: ModelControllerActions<ModelController<$Model>>
|
|
2156
|
+
/**
|
|
2157
|
+
* The controller's member actions. Wrap actions in this
|
|
2158
|
+
* object to assign them to the member.
|
|
2159
|
+
*/
|
|
2160
|
+
member?: ModelControllerMemberActions<ModelController<$Model>>
|
|
2161
|
+
assets?:
|
|
2162
|
+
| boolean
|
|
2163
|
+
| {
|
|
2164
|
+
allow?: OrArrayOf<string>
|
|
2165
|
+
authorize: Record<string, OrArrayOf<string>>
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* When nothing is returned from a hook, the standard
|
|
2170
|
+
* action result is used.
|
|
2171
|
+
*/
|
|
2172
|
+
hooks?: ModelControllerHooks<ModelController<$Model>>
|
|
2173
|
+
/** Map of relation name to RelationController instance. */
|
|
2174
|
+
relations?: Record<string, RelationController>
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
/**
|
|
2178
|
+
* Controller for nested relation resources. Created
|
|
2179
|
+
* automatically by ModelController during relation setup.
|
|
2180
|
+
*/
|
|
2181
|
+
export class RelationController<
|
|
2182
|
+
$Model extends Model = Model
|
|
2183
|
+
> extends CollectionController<$Model> {
|
|
2184
|
+
/** The parent controller that owns this relation. */
|
|
2185
|
+
parent: CollectionController
|
|
2186
|
+
|
|
2187
|
+
/** The raw relation definition object. */
|
|
2188
|
+
object: Record<string, unknown>
|
|
2189
|
+
|
|
2190
|
+
/** The Objection.js relation instance. */
|
|
2191
|
+
relationInstance: objection.Relation
|
|
2192
|
+
|
|
2193
|
+
/** The raw relation definition from the parent. */
|
|
2194
|
+
relationDefinition: Record<string, unknown>
|
|
2195
|
+
|
|
2196
|
+
/** Whether this is a one-to-one relation. */
|
|
2197
|
+
isOneToOne: boolean
|
|
2198
|
+
/** Whether relate operations are supported. */
|
|
2199
|
+
relate: boolean
|
|
2200
|
+
/** Whether unrelate operations are supported. */
|
|
2201
|
+
unrelate: boolean
|
|
1247
2202
|
}
|
|
1248
2203
|
|
|
1249
2204
|
export class Validator extends objection.Validator {
|
|
1250
|
-
constructor(
|
|
2205
|
+
constructor(options?: {
|
|
1251
2206
|
options?: {
|
|
1252
2207
|
/** @defaultValue `false` */
|
|
1253
2208
|
async?: boolean
|
|
@@ -1274,15 +2229,66 @@ export class Validator extends objection.Validator {
|
|
|
1274
2229
|
}
|
|
1275
2230
|
keywords?: Record<string, Keyword>
|
|
1276
2231
|
formats?: Record<string, Format>
|
|
2232
|
+
types?: Record<string, any>
|
|
1277
2233
|
})
|
|
2234
|
+
|
|
2235
|
+
/**
|
|
2236
|
+
* Compiles a JSON schema into a validation function.
|
|
2237
|
+
* Supports sync, async, and throwing modes via options.
|
|
2238
|
+
*/
|
|
2239
|
+
compile(
|
|
2240
|
+
jsonSchema: Schema,
|
|
2241
|
+
options?: Record<string, any>
|
|
2242
|
+
): Ajv.ValidateFunction
|
|
2243
|
+
|
|
2244
|
+
/** Adds a schema to all cached Ajv instances. */
|
|
2245
|
+
addSchema(jsonSchema: Schema): void
|
|
2246
|
+
|
|
2247
|
+
/**
|
|
2248
|
+
* Returns a cached Ajv instance for the given options,
|
|
2249
|
+
* creating one if needed.
|
|
2250
|
+
*/
|
|
2251
|
+
getAjv(options?: Record<string, any>): Ajv.default
|
|
2252
|
+
|
|
2253
|
+
/** Creates a new Ajv instance with the given options. */
|
|
2254
|
+
createAjv(options?: Record<string, any>): Ajv.default
|
|
2255
|
+
|
|
2256
|
+
/**
|
|
2257
|
+
* Converts Ajv validation errors into an Objection.js
|
|
2258
|
+
* style error hash.
|
|
2259
|
+
*/
|
|
2260
|
+
parseErrors(
|
|
2261
|
+
errors: Ajv.ErrorObject[],
|
|
2262
|
+
options?: Record<string, any>
|
|
2263
|
+
): Record<string, any[]>
|
|
2264
|
+
|
|
2265
|
+
/**
|
|
2266
|
+
* Processes a JSON schema for patch or async validation
|
|
2267
|
+
* modes.
|
|
2268
|
+
*/
|
|
2269
|
+
processSchema(
|
|
2270
|
+
jsonSchema: Schema,
|
|
2271
|
+
options?: Record<string, any>
|
|
2272
|
+
): Schema
|
|
2273
|
+
|
|
2274
|
+
/** Returns a registered keyword definition by name. */
|
|
2275
|
+
getKeyword(name: string): Keyword | undefined
|
|
2276
|
+
|
|
2277
|
+
/** Returns a registered format definition by name. */
|
|
2278
|
+
getFormat(name: string): Format | undefined
|
|
2279
|
+
|
|
2280
|
+
/** Prefixes error instance paths with a given prefix. */
|
|
2281
|
+
prefixInstancePaths(
|
|
2282
|
+
errors: Ajv.ErrorObject[],
|
|
2283
|
+
prefix: string
|
|
2284
|
+
): Ajv.ErrorObject[]
|
|
1278
2285
|
}
|
|
1279
2286
|
|
|
1280
2287
|
// NOTE: Because EventEmitter overrides a number of EventEmitter2 methods with
|
|
1281
2288
|
// changed signatures, we are unable to extend it.
|
|
1282
2289
|
export class EventEmitter {
|
|
1283
|
-
static mixin: (target: any) =>
|
|
2290
|
+
static mixin: (target: any) => void
|
|
1284
2291
|
constructor(options?: EventEmitter2.ConstructorOptions)
|
|
1285
|
-
responds(event: EventEmitter2.event): boolean
|
|
1286
2292
|
emit(
|
|
1287
2293
|
event: EventEmitter2.event | EventEmitter2.eventNS,
|
|
1288
2294
|
...values: any[]
|
|
@@ -1293,20 +2299,42 @@ export class EventEmitter {
|
|
|
1293
2299
|
listener: EventEmitter2.ListenerFn
|
|
1294
2300
|
): this
|
|
1295
2301
|
|
|
2302
|
+
on(
|
|
2303
|
+
event: string[],
|
|
2304
|
+
listener: EventEmitter2.ListenerFn
|
|
2305
|
+
): this
|
|
2306
|
+
|
|
2307
|
+
on(
|
|
2308
|
+
event: Record<string, EventEmitter2.ListenerFn>
|
|
2309
|
+
): this
|
|
2310
|
+
|
|
1296
2311
|
off(
|
|
1297
2312
|
event: EventEmitter2.event | EventEmitter2.eventNS,
|
|
1298
2313
|
listener: EventEmitter2.ListenerFn
|
|
1299
2314
|
): this
|
|
1300
2315
|
|
|
2316
|
+
off(
|
|
2317
|
+
event: string[],
|
|
2318
|
+
listener: EventEmitter2.ListenerFn
|
|
2319
|
+
): this
|
|
2320
|
+
|
|
2321
|
+
off(
|
|
2322
|
+
event: Record<string, EventEmitter2.ListenerFn>
|
|
2323
|
+
): this
|
|
2324
|
+
|
|
1301
2325
|
once(
|
|
1302
2326
|
event: EventEmitter2.event | EventEmitter2.eventNS,
|
|
1303
2327
|
listener: EventEmitter2.ListenerFn
|
|
1304
2328
|
): this
|
|
1305
2329
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
):
|
|
2330
|
+
once(
|
|
2331
|
+
event: string[],
|
|
2332
|
+
listener: EventEmitter2.ListenerFn
|
|
2333
|
+
): this
|
|
2334
|
+
|
|
2335
|
+
once(
|
|
2336
|
+
event: Record<string, EventEmitter2.ListenerFn>
|
|
2337
|
+
): this
|
|
1310
2338
|
|
|
1311
2339
|
// From EventEmitter2:
|
|
1312
2340
|
emitAsync(
|
|
@@ -1402,9 +2430,9 @@ export class EventEmitter {
|
|
|
1402
2430
|
stopListeningTo(
|
|
1403
2431
|
target?: EventEmitter2.GeneralEventEmitter,
|
|
1404
2432
|
event?: EventEmitter2.event | EventEmitter2.eventNS
|
|
1405
|
-
):
|
|
2433
|
+
): boolean
|
|
1406
2434
|
|
|
1407
|
-
hasListeners(event?:
|
|
2435
|
+
hasListeners(event?: string): boolean
|
|
1408
2436
|
static once(
|
|
1409
2437
|
emitter: EventEmitter2.EventEmitter2,
|
|
1410
2438
|
event: EventEmitter2.event | EventEmitter2.eventNS,
|
|
@@ -1414,13 +2442,49 @@ export class EventEmitter {
|
|
|
1414
2442
|
static defaultMaxListeners: number
|
|
1415
2443
|
}
|
|
1416
2444
|
|
|
2445
|
+
/**
|
|
2446
|
+
* Options for Dito.js graph operations (`insertDitoGraph`,
|
|
2447
|
+
* `upsertDitoGraph`, `updateDitoGraph`, `patchDitoGraph`).
|
|
2448
|
+
* Controls how nested relation graphs are persisted.
|
|
2449
|
+
*/
|
|
1417
2450
|
export interface DitoGraphOptions {
|
|
2451
|
+
/**
|
|
2452
|
+
* Strategy for fetching existing data before upserting.
|
|
2453
|
+
*
|
|
2454
|
+
* - `'OnlyNeeded'`: Fetch only data needed to determine
|
|
2455
|
+
* changes.
|
|
2456
|
+
* - `'OnlyIdentifiers'`: Fetch only IDs for comparison.
|
|
2457
|
+
* - `'Everything'`: Fetch all existing graph data.
|
|
2458
|
+
*/
|
|
1418
2459
|
fetchStrategy?: 'OnlyNeeded' | 'OnlyIdentifiers' | 'Everything'
|
|
2460
|
+
/**
|
|
2461
|
+
* Whether to relate existing models found in the graph
|
|
2462
|
+
* instead of inserting new ones.
|
|
2463
|
+
*/
|
|
1419
2464
|
relate?: boolean
|
|
2465
|
+
/** Whether to allow `#ref` references in the graph. */
|
|
1420
2466
|
allowRefs?: boolean
|
|
2467
|
+
/**
|
|
2468
|
+
* Whether to insert models that don't exist in the
|
|
2469
|
+
* database yet during an upsert.
|
|
2470
|
+
*/
|
|
1421
2471
|
insertMissing?: boolean
|
|
2472
|
+
/**
|
|
2473
|
+
* Whether to unrelate models removed from the graph
|
|
2474
|
+
* (sets the foreign key to `null` instead of deleting).
|
|
2475
|
+
*/
|
|
1422
2476
|
unrelate?: boolean
|
|
2477
|
+
/**
|
|
2478
|
+
* Whether to update existing models found in the graph
|
|
2479
|
+
* (as opposed to only inserting new ones).
|
|
2480
|
+
*/
|
|
1423
2481
|
update?: boolean
|
|
2482
|
+
/**
|
|
2483
|
+
* Enables special handling for cyclic graph upserts,
|
|
2484
|
+
* where self-referential relations are broken into two
|
|
2485
|
+
* phases.
|
|
2486
|
+
*/
|
|
2487
|
+
cyclic?: boolean
|
|
1424
2488
|
}
|
|
1425
2489
|
|
|
1426
2490
|
export type QueryParameterOptions = {
|
|
@@ -1434,22 +2498,37 @@ export type QueryParameterOptions = {
|
|
|
1434
2498
|
range?: [number, number] | string
|
|
1435
2499
|
limit?: number
|
|
1436
2500
|
offset?: number
|
|
1437
|
-
order?:
|
|
2501
|
+
order?: OrArrayOf<string>
|
|
1438
2502
|
}
|
|
1439
2503
|
export type QueryParameterOptionKey = keyof QueryParameterOptions
|
|
1440
2504
|
|
|
1441
2505
|
export class Service {
|
|
1442
2506
|
constructor(app: Application<Models>, name?: string)
|
|
1443
|
-
|
|
2507
|
+
|
|
2508
|
+
/** The application instance. */
|
|
2509
|
+
app: Application<Models>
|
|
2510
|
+
/** The camelized service name. */
|
|
2511
|
+
name: string
|
|
2512
|
+
/** The service configuration. */
|
|
2513
|
+
config: Record<string, unknown> | null
|
|
2514
|
+
/** Whether this service has been initialized. */
|
|
2515
|
+
initialized: boolean
|
|
2516
|
+
|
|
2517
|
+
setup(config: Record<string, unknown>): void
|
|
2518
|
+
|
|
1444
2519
|
/**
|
|
1445
|
-
*
|
|
2520
|
+
* Override in sub-classes if the service needs async
|
|
2521
|
+
* initialization.
|
|
1446
2522
|
* @overridable
|
|
1447
2523
|
*/
|
|
1448
2524
|
initialize(): Promise<void>
|
|
2525
|
+
|
|
1449
2526
|
/** @overridable */
|
|
1450
2527
|
start(): Promise<void>
|
|
2528
|
+
|
|
1451
2529
|
/** @overridable */
|
|
1452
2530
|
stop(): Promise<void>
|
|
2531
|
+
|
|
1453
2532
|
get logger(): PinoLogger
|
|
1454
2533
|
}
|
|
1455
2534
|
export type Services = Record<string, Class<Service> | Service>
|
|
@@ -1458,124 +2537,147 @@ export class QueryBuilder<
|
|
|
1458
2537
|
M extends Model,
|
|
1459
2538
|
R = M[]
|
|
1460
2539
|
> extends objection.QueryBuilder<M, R> {
|
|
2540
|
+
/** Clones the query with scope/filter state. */
|
|
2541
|
+
clone(): QueryBuilder<M, R>
|
|
2542
|
+
/**
|
|
2543
|
+
* Inherits scopes from a parent query.
|
|
2544
|
+
* @override
|
|
2545
|
+
*/
|
|
2546
|
+
childQueryOf(
|
|
2547
|
+
query: QueryBuilder<Model>,
|
|
2548
|
+
options?: Record<string, any>
|
|
2549
|
+
): this
|
|
2550
|
+
|
|
2551
|
+
/**
|
|
2552
|
+
* Creates a find-only copy of this query (clears
|
|
2553
|
+
* `runAfter` callbacks).
|
|
2554
|
+
* @override
|
|
2555
|
+
*/
|
|
2556
|
+
toFindQuery(): QueryBuilder<M, M[]>
|
|
2557
|
+
|
|
1461
2558
|
/**
|
|
1462
2559
|
* Returns true if the query defines normal selects: select(), column(),
|
|
1463
2560
|
* columns()
|
|
1464
2561
|
*/
|
|
1465
|
-
hasNormalSelects
|
|
2562
|
+
hasNormalSelects(): boolean
|
|
1466
2563
|
/**
|
|
1467
|
-
* Returns true if the query defines special selects:
|
|
1468
|
-
*
|
|
2564
|
+
* Returns true if the query defines special selects:
|
|
2565
|
+
* distinct(), count(), countDistinct(), min(), max(),
|
|
2566
|
+
* sum(), sumDistinct(), avg(), avgDistinct()
|
|
1469
2567
|
*/
|
|
1470
|
-
hasSpecialSelects
|
|
1471
|
-
withScope
|
|
2568
|
+
hasSpecialSelects(): boolean
|
|
2569
|
+
withScope(...scopes: string[]): this
|
|
1472
2570
|
/**
|
|
1473
|
-
* Clear all scopes defined with `withScope()` statements,
|
|
1474
|
-
* default scope.
|
|
2571
|
+
* Clear all scopes defined with `withScope()` statements,
|
|
2572
|
+
* preserving the default scope.
|
|
1475
2573
|
*/
|
|
1476
|
-
clearWithScope
|
|
1477
|
-
ignoreScope
|
|
1478
|
-
applyScope
|
|
1479
|
-
allowScope
|
|
1480
|
-
clearAllowScope
|
|
1481
|
-
applyFilter:
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
withGraph: (
|
|
2574
|
+
clearWithScope(): this
|
|
2575
|
+
ignoreScope(...scopes: string[]): this
|
|
2576
|
+
applyScope(...scopes: string[]): this
|
|
2577
|
+
allowScope(...scopes: string[]): void
|
|
2578
|
+
clearAllowScope(): void
|
|
2579
|
+
applyFilter(name: string, ...args: unknown[]): this
|
|
2580
|
+
applyFilter(filters: { [name: string]: unknown[] }): this
|
|
2581
|
+
allowFilter(...filters: string[]): void
|
|
2582
|
+
/** Omits properties from the query result. */
|
|
2583
|
+
omit(...properties: string[]): void
|
|
2584
|
+
withGraph(
|
|
1488
2585
|
expr: objection.RelationExpression<M>,
|
|
1489
|
-
options?: objection.GraphOptions & {
|
|
1490
|
-
|
|
2586
|
+
options?: objection.GraphOptions & {
|
|
2587
|
+
algorithm?: 'fetch' | 'join'
|
|
2588
|
+
}
|
|
2589
|
+
): this
|
|
1491
2590
|
|
|
1492
|
-
toSQL
|
|
2591
|
+
toSQL(): { sql: string; bindings: unknown[] }
|
|
1493
2592
|
raw: Knex.RawBuilder
|
|
1494
2593
|
selectRaw: SetReturnType<Knex.RawBuilder, this>
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
// pluck: <K extends objection.ModelProps<M>>(
|
|
1498
|
-
// key: K
|
|
1499
|
-
// ) => QueryBuilder<M, ReflectArrayType<R, M[K]>>
|
|
1500
|
-
loadDataPath: (
|
|
2594
|
+
pluck(key: string): this
|
|
2595
|
+
loadDataPath(
|
|
1501
2596
|
dataPath: string[] | string,
|
|
1502
|
-
options
|
|
1503
|
-
|
|
2597
|
+
options?: objection.GraphOptions & {
|
|
2598
|
+
algorithm?: 'fetch' | 'join'
|
|
2599
|
+
}
|
|
2600
|
+
): this
|
|
1504
2601
|
|
|
1505
|
-
upsert
|
|
2602
|
+
upsert(
|
|
1506
2603
|
data: PartialModelObject<M>,
|
|
1507
2604
|
options?: {
|
|
1508
|
-
update
|
|
1509
|
-
fetch
|
|
2605
|
+
update?: boolean
|
|
2606
|
+
fetch?: boolean
|
|
1510
2607
|
}
|
|
1511
|
-
)
|
|
2608
|
+
): this
|
|
1512
2609
|
|
|
1513
|
-
find
|
|
2610
|
+
find(
|
|
1514
2611
|
query: QueryParameterOptions,
|
|
1515
2612
|
allowParam?:
|
|
1516
2613
|
| QueryParameterOptionKey[]
|
|
1517
2614
|
| {
|
|
1518
|
-
[key in
|
|
2615
|
+
[key in QueryParameterOptionKey]?: boolean
|
|
1519
2616
|
}
|
|
1520
|
-
)
|
|
2617
|
+
): this
|
|
1521
2618
|
|
|
1522
|
-
patchById
|
|
1523
|
-
updateById
|
|
1524
|
-
upsertAndFetch
|
|
1525
|
-
insertDitoGraph
|
|
2619
|
+
patchById(id: Id, data: PartialModelObject<M>): this
|
|
2620
|
+
updateById(id: Id, data: PartialModelObject<M>): this
|
|
2621
|
+
upsertAndFetch(data: PartialModelObject<M>): this
|
|
2622
|
+
insertDitoGraph(
|
|
1526
2623
|
data: PartialDitoModelGraph<M>,
|
|
1527
2624
|
options?: DitoGraphOptions
|
|
1528
|
-
)
|
|
2625
|
+
): this
|
|
1529
2626
|
|
|
1530
|
-
insertDitoGraphAndFetch
|
|
2627
|
+
insertDitoGraphAndFetch(
|
|
1531
2628
|
data: PartialDitoModelGraph<M>,
|
|
1532
2629
|
options?: DitoGraphOptions
|
|
1533
|
-
)
|
|
2630
|
+
): this
|
|
1534
2631
|
|
|
1535
|
-
upsertDitoGraph
|
|
2632
|
+
upsertDitoGraph(
|
|
1536
2633
|
data: PartialDitoModelGraph<M>,
|
|
1537
2634
|
options?: DitoGraphOptions
|
|
1538
|
-
)
|
|
2635
|
+
): this
|
|
1539
2636
|
|
|
1540
|
-
upsertDitoGraphAndFetch
|
|
1541
|
-
|
|
2637
|
+
upsertDitoGraphAndFetch(
|
|
2638
|
+
data: PartialDitoModelGraph<M>,
|
|
2639
|
+
options?: DitoGraphOptions
|
|
2640
|
+
): this
|
|
2641
|
+
|
|
2642
|
+
upsertDitoGraphAndFetchById(
|
|
1542
2643
|
id: Id,
|
|
1543
|
-
data:
|
|
2644
|
+
data: PartialDitoModelGraph<M>,
|
|
1544
2645
|
options?: DitoGraphOptions
|
|
1545
|
-
)
|
|
2646
|
+
): this
|
|
1546
2647
|
|
|
1547
|
-
updateDitoGraph
|
|
2648
|
+
updateDitoGraph(
|
|
1548
2649
|
data: PartialDitoModelGraph<M>,
|
|
1549
2650
|
options?: DitoGraphOptions
|
|
1550
|
-
)
|
|
2651
|
+
): this
|
|
1551
2652
|
|
|
1552
|
-
updateDitoGraphAndFetch
|
|
2653
|
+
updateDitoGraphAndFetch(
|
|
1553
2654
|
data: PartialDitoModelGraph<M>,
|
|
1554
2655
|
options?: DitoGraphOptions
|
|
1555
|
-
)
|
|
2656
|
+
): this
|
|
1556
2657
|
|
|
1557
|
-
updateDitoGraphAndFetchById
|
|
2658
|
+
updateDitoGraphAndFetchById(
|
|
1558
2659
|
id: Id,
|
|
1559
|
-
data:
|
|
2660
|
+
data: PartialDitoModelGraph<M>,
|
|
1560
2661
|
options?: DitoGraphOptions
|
|
1561
|
-
)
|
|
2662
|
+
): this
|
|
1562
2663
|
|
|
1563
|
-
patchDitoGraph
|
|
2664
|
+
patchDitoGraph(
|
|
1564
2665
|
data: PartialDitoModelGraph<M>,
|
|
1565
2666
|
options?: DitoGraphOptions
|
|
1566
|
-
)
|
|
2667
|
+
): this
|
|
1567
2668
|
|
|
1568
|
-
patchDitoGraphAndFetch
|
|
2669
|
+
patchDitoGraphAndFetch(
|
|
1569
2670
|
data: PartialDitoModelGraph<M>,
|
|
1570
2671
|
options?: DitoGraphOptions
|
|
1571
|
-
)
|
|
2672
|
+
): this
|
|
1572
2673
|
|
|
1573
|
-
patchDitoGraphAndFetchById
|
|
2674
|
+
patchDitoGraphAndFetchById(
|
|
1574
2675
|
id: Id,
|
|
1575
2676
|
data: PartialDitoModelGraph<M>,
|
|
1576
2677
|
options?: DitoGraphOptions
|
|
1577
|
-
)
|
|
1578
|
-
|
|
2678
|
+
): this
|
|
2679
|
+
|
|
2680
|
+
truncate(options?: { restart?: boolean; cascade?: boolean }): this
|
|
1579
2681
|
|
|
1580
2682
|
ArrayQueryBuilderType: QueryBuilder<M, M[]>
|
|
1581
2683
|
SingleQueryBuilderType: QueryBuilder<M, M>
|
|
@@ -1585,6 +2687,51 @@ export class QueryBuilder<
|
|
|
1585
2687
|
}
|
|
1586
2688
|
export interface QueryBuilder<M extends Model, R = M[]> extends KnexHelper {}
|
|
1587
2689
|
|
|
2690
|
+
/**
|
|
2691
|
+
* Registry of built-in query parameter handlers (scope,
|
|
2692
|
+
* filter, range, limit, offset, order). Used by
|
|
2693
|
+
* `QueryBuilder.find()` to apply URL query parameters.
|
|
2694
|
+
*/
|
|
2695
|
+
type QueryParameterHandler = (
|
|
2696
|
+
query: QueryBuilder<Model>,
|
|
2697
|
+
key: string,
|
|
2698
|
+
value: unknown
|
|
2699
|
+
) => void
|
|
2700
|
+
|
|
2701
|
+
export const QueryParameters: {
|
|
2702
|
+
register(name: string, handler: QueryParameterHandler): void
|
|
2703
|
+
register(
|
|
2704
|
+
handlers: Record<string, QueryParameterHandler>
|
|
2705
|
+
): void
|
|
2706
|
+
get(name: string): QueryParameterHandler | undefined
|
|
2707
|
+
has(name: string): boolean
|
|
2708
|
+
getAllowed(): Record<string, boolean>
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
export type QueryFilterDefinition = {
|
|
2712
|
+
parameters?: Record<string, Schema>
|
|
2713
|
+
handler: (
|
|
2714
|
+
query: QueryBuilder<Model>,
|
|
2715
|
+
property: string,
|
|
2716
|
+
...args: unknown[]
|
|
2717
|
+
) => void
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
/**
|
|
2721
|
+
* Registry of built-in query filters (text, date-range).
|
|
2722
|
+
* Provides reusable filter implementations that can be
|
|
2723
|
+
* referenced by name in model filter definitions.
|
|
2724
|
+
*/
|
|
2725
|
+
export const QueryFilters: {
|
|
2726
|
+
register(name: string, definition: QueryFilterDefinition): void
|
|
2727
|
+
register(
|
|
2728
|
+
definitions: Record<string, QueryFilterDefinition>
|
|
2729
|
+
): void
|
|
2730
|
+
get(name: string): QueryFilterDefinition | undefined
|
|
2731
|
+
has(name: string): boolean
|
|
2732
|
+
getAllowed(): Record<string, boolean>
|
|
2733
|
+
}
|
|
2734
|
+
|
|
1588
2735
|
export type PartialModelObject<T extends Model> = {
|
|
1589
2736
|
[K in objection.NonFunctionPropertyNames<T>]?: objection.Defined<
|
|
1590
2737
|
T[K]
|
|
@@ -1620,17 +2767,22 @@ export class ResponseError extends Error {
|
|
|
1620
2767
|
/** The error message. */
|
|
1621
2768
|
message?: string
|
|
1622
2769
|
/**
|
|
1623
|
-
* An optional code to be used to distinguish
|
|
1624
|
-
* instances.
|
|
2770
|
+
* An optional code to be used to distinguish
|
|
2771
|
+
* different error instances.
|
|
1625
2772
|
*/
|
|
1626
2773
|
code?: string | number
|
|
1627
2774
|
}
|
|
2775
|
+
| Error
|
|
1628
2776
|
| string,
|
|
1629
|
-
defaults?: { message?: string; status?: number }
|
|
2777
|
+
defaults?: { message?: string; status?: number },
|
|
2778
|
+
overrides?: Record<string, unknown>
|
|
1630
2779
|
)
|
|
1631
2780
|
|
|
1632
2781
|
status: number
|
|
1633
2782
|
code?: string | number
|
|
2783
|
+
/** Additional error data. */
|
|
2784
|
+
data?: Record<string, unknown>
|
|
2785
|
+
toJSON(): Record<string, unknown>
|
|
1634
2786
|
}
|
|
1635
2787
|
export class AssetError extends ResponseError {}
|
|
1636
2788
|
export class AuthenticationError extends ResponseError {}
|
|
@@ -1642,12 +2794,13 @@ export class DatabaseError extends ResponseError {
|
|
|
1642
2794
|
| dbErrors.NotNullViolationError
|
|
1643
2795
|
| dbErrors.ConstraintViolationError
|
|
1644
2796
|
| dbErrors.DataError
|
|
1645
|
-
| dbErrors.DBError
|
|
2797
|
+
| dbErrors.DBError,
|
|
2798
|
+
overrides?: Record<string, unknown>
|
|
1646
2799
|
)
|
|
1647
2800
|
}
|
|
1648
2801
|
export class GraphError extends ResponseError {}
|
|
1649
2802
|
export class ModelError extends ResponseError {
|
|
1650
|
-
constructor(model: Class<Model> | Model)
|
|
2803
|
+
constructor(model: Class<Model> | Model, error?: unknown)
|
|
1651
2804
|
}
|
|
1652
2805
|
export class NotFoundError extends ResponseError {}
|
|
1653
2806
|
export class NotImplementedError extends ResponseError {}
|
|
@@ -1655,18 +2808,180 @@ export class QueryBuilderError extends ResponseError {}
|
|
|
1655
2808
|
export class RelationError extends ResponseError {}
|
|
1656
2809
|
export class ValidationError extends ResponseError {}
|
|
1657
2810
|
export class ControllerError extends ResponseError {
|
|
1658
|
-
constructor(
|
|
2811
|
+
constructor(
|
|
2812
|
+
controller:
|
|
2813
|
+
| Function
|
|
2814
|
+
| { constructor: { name: string } },
|
|
2815
|
+
error?: unknown
|
|
2816
|
+
)
|
|
1659
2817
|
}
|
|
1660
2818
|
/* ------------------------------- End Errors ------------------------------ */
|
|
1661
2819
|
|
|
1662
|
-
/*
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
2820
|
+
/* ----------------------------- Start Storage ----------------------------- */
|
|
2821
|
+
/**
|
|
2822
|
+
* Base class for file storage backends. Subclasses handle
|
|
2823
|
+
* disk and S3 storage.
|
|
2824
|
+
*/
|
|
2825
|
+
export class Storage {
|
|
2826
|
+
constructor(app: Application<Models>, config: StorageConfig)
|
|
2827
|
+
/** The application instance. */
|
|
2828
|
+
app: Application<Models>
|
|
2829
|
+
/** The storage configuration. */
|
|
2830
|
+
config: StorageConfig
|
|
2831
|
+
/** The storage name. */
|
|
2832
|
+
name: string
|
|
2833
|
+
/** The base URL for accessing stored files. */
|
|
2834
|
+
url?: string
|
|
2835
|
+
/** The file system path for disk storage. */
|
|
2836
|
+
path?: string
|
|
2837
|
+
/**
|
|
2838
|
+
* Upload concurrency limit.
|
|
2839
|
+
*
|
|
2840
|
+
* @defaultValue `8`
|
|
2841
|
+
*/
|
|
2842
|
+
concurrency: number
|
|
2843
|
+
/** Whether this storage has been initialized. */
|
|
2844
|
+
initialized: boolean
|
|
2845
|
+
|
|
2846
|
+
/** Sets up the storage backend. */
|
|
2847
|
+
setup(): Promise<void>
|
|
2848
|
+
/**
|
|
2849
|
+
* Override in sub-classes for async initialization.
|
|
2850
|
+
* @overridable
|
|
2851
|
+
*/
|
|
2852
|
+
initialize(): Promise<void>
|
|
2853
|
+
/**
|
|
2854
|
+
* Returns a multer-compatible storage object for handling
|
|
2855
|
+
* uploads, or null if no underlying storage is configured.
|
|
2856
|
+
*/
|
|
2857
|
+
getUploadStorage(
|
|
2858
|
+
config: multer.Options
|
|
2859
|
+
): multer.StorageEngine | null
|
|
2860
|
+
|
|
2861
|
+
/** Returns a multer upload handler for this storage. */
|
|
2862
|
+
getUploadHandler(
|
|
2863
|
+
config: multer.Options
|
|
2864
|
+
): Koa.Middleware | null
|
|
2865
|
+
|
|
2866
|
+
/**
|
|
2867
|
+
* Generates a unique storage key from a filename,
|
|
2868
|
+
* combining a UUID with the file extension.
|
|
2869
|
+
*/
|
|
2870
|
+
getUniqueKey(name: string): string
|
|
2871
|
+
/**
|
|
2872
|
+
* Checks whether the given URL is allowed as an import
|
|
2873
|
+
* source based on `config.allowedImports`.
|
|
2874
|
+
*/
|
|
2875
|
+
isImportSourceAllowed(url: string): boolean
|
|
2876
|
+
/** Adds a file to storage. */
|
|
2877
|
+
addFile(file: AssetFile, data: Buffer): Promise<AssetFile>
|
|
2878
|
+
/** Removes a file from storage. */
|
|
2879
|
+
removeFile(file: AssetFile): Promise<void>
|
|
2880
|
+
/** Reads a file's contents from storage. */
|
|
2881
|
+
readFile(file: AssetFile): Promise<Buffer>
|
|
2882
|
+
/** Lists all keys in the storage. */
|
|
2883
|
+
listKeys(): Promise<string[]>
|
|
2884
|
+
/** Returns the file system path for a file, if any. */
|
|
2885
|
+
getFilePath(file: AssetFile): string | undefined
|
|
2886
|
+
/** Returns the public URL for a file, if any. */
|
|
2887
|
+
getFileUrl(file: AssetFile): string | undefined
|
|
2888
|
+
|
|
2889
|
+
/**
|
|
2890
|
+
* Converts a multer upload object to the internal file
|
|
2891
|
+
* format.
|
|
2892
|
+
*/
|
|
2893
|
+
convertStorageFile(
|
|
2894
|
+
storageFile: StorageFile
|
|
2895
|
+
): AssetFileObject
|
|
2896
|
+
|
|
2897
|
+
/**
|
|
2898
|
+
* Converts an array of multer upload objects to the
|
|
2899
|
+
* internal file format.
|
|
2900
|
+
*/
|
|
2901
|
+
convertStorageFiles(
|
|
2902
|
+
storageFiles: StorageFile[]
|
|
2903
|
+
): AssetFileObject[]
|
|
2904
|
+
|
|
2905
|
+
/**
|
|
2906
|
+
* Converts a plain file object into an AssetFile
|
|
2907
|
+
* instance in-place on this storage.
|
|
2908
|
+
*/
|
|
2909
|
+
convertAssetFile(file: AssetFileObject): void
|
|
1668
2910
|
|
|
1669
|
-
type
|
|
2911
|
+
/** Registers a storage subclass by type name. */
|
|
2912
|
+
static register(storageClass: Class<Storage>): void
|
|
2913
|
+
/** Retrieves a registered storage class by type name. */
|
|
2914
|
+
static get(type: string): Class<Storage> | null
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
/**
|
|
2918
|
+
* Represents a file asset with metadata. Created from
|
|
2919
|
+
* uploaded files or imported URLs.
|
|
2920
|
+
*/
|
|
2921
|
+
export class AssetFile {
|
|
2922
|
+
constructor(options: {
|
|
2923
|
+
name: string
|
|
2924
|
+
data: string | Buffer
|
|
2925
|
+
type?: string
|
|
2926
|
+
width?: number
|
|
2927
|
+
height?: number
|
|
2928
|
+
})
|
|
2929
|
+
|
|
2930
|
+
/** Unique storage key (UUID + extension). */
|
|
2931
|
+
key: string
|
|
2932
|
+
/** The original filename. */
|
|
2933
|
+
name: string
|
|
2934
|
+
/** The file's MIME type, set from options or detected from data. */
|
|
2935
|
+
type: string | undefined
|
|
2936
|
+
/** File size in bytes. */
|
|
2937
|
+
size: number
|
|
2938
|
+
/** Image width, if dimensions were read. */
|
|
2939
|
+
width?: number
|
|
2940
|
+
/** Image height, if dimensions were read. */
|
|
2941
|
+
height?: number
|
|
2942
|
+
/** The public URL for this file, set after storage upload. */
|
|
2943
|
+
url?: string
|
|
2944
|
+
/** The file data buffer. */
|
|
2945
|
+
get data(): Buffer | null
|
|
2946
|
+
/** The storage instance this file belongs to. */
|
|
2947
|
+
get storage(): Storage | null
|
|
2948
|
+
/** The file system path, if stored on disk. */
|
|
2949
|
+
get path(): string | undefined
|
|
2950
|
+
/** Reads the file's contents from storage. */
|
|
2951
|
+
read(): Promise<Buffer | null>
|
|
2952
|
+
|
|
2953
|
+
/**
|
|
2954
|
+
* Converts a plain object into an AssetFile instance
|
|
2955
|
+
* in-place on the given storage.
|
|
2956
|
+
*/
|
|
2957
|
+
static convert(
|
|
2958
|
+
object: Record<string, any>,
|
|
2959
|
+
storage: Storage
|
|
2960
|
+
): void
|
|
2961
|
+
|
|
2962
|
+
/** Creates a new AssetFile from the given options. */
|
|
2963
|
+
static create(options: {
|
|
2964
|
+
name: string
|
|
2965
|
+
data: string | Buffer
|
|
2966
|
+
type?: string
|
|
2967
|
+
width?: number
|
|
2968
|
+
height?: number
|
|
2969
|
+
}): AssetFile
|
|
2970
|
+
|
|
2971
|
+
/**
|
|
2972
|
+
* Generates a unique storage key for a filename,
|
|
2973
|
+
* combining a UUID with the file extension.
|
|
2974
|
+
*/
|
|
2975
|
+
static getUniqueKey(name: string): string
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
export interface StorageFile extends multer.File {
|
|
2979
|
+
key: string
|
|
2980
|
+
width?: number
|
|
2981
|
+
height?: number
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
export type AssetFileObject = {
|
|
1670
2985
|
// The unique key within the storage (uuid/v4 + file extension)
|
|
1671
2986
|
key: string
|
|
1672
2987
|
// The original filename
|
|
@@ -1678,10 +2993,16 @@ type AssetFileObject = {
|
|
|
1678
2993
|
// The public url of the file
|
|
1679
2994
|
url: string
|
|
1680
2995
|
// The width of the image if the storage defines `config.readDimensions`
|
|
1681
|
-
width
|
|
2996
|
+
width?: number
|
|
1682
2997
|
// The height of the image if the storage defines `config.readDimensions`
|
|
1683
|
-
height
|
|
2998
|
+
height?: number
|
|
2999
|
+
// HMAC signature of the key, present in upload responses, stripped before
|
|
3000
|
+
// persistence.
|
|
3001
|
+
signature?: string
|
|
1684
3002
|
}
|
|
3003
|
+
/* ------------------------------ End Storage ------------------------------ */
|
|
3004
|
+
|
|
3005
|
+
/* ------------------------------ Start Mixins ----------------------------- */
|
|
1685
3006
|
|
|
1686
3007
|
export const AssetMixin: <T extends Constructor<{}>>(
|
|
1687
3008
|
target: T
|
|
@@ -1691,6 +3012,12 @@ export const AssetMixin: <T extends Constructor<{}>>(
|
|
|
1691
3012
|
file: AssetFileObject
|
|
1692
3013
|
storage: string
|
|
1693
3014
|
count: number
|
|
3015
|
+
createdAt: Date
|
|
3016
|
+
updatedAt: Date
|
|
3017
|
+
$parseJson(
|
|
3018
|
+
json: object,
|
|
3019
|
+
opt?: ModelOptions
|
|
3020
|
+
): object
|
|
1694
3021
|
}>
|
|
1695
3022
|
|
|
1696
3023
|
export const AssetModel: ReturnType<typeof AssetMixin<typeof Model>>
|
|
@@ -1710,7 +3037,7 @@ export const SessionMixin: <T extends Constructor<{}>>(
|
|
|
1710
3037
|
) => T &
|
|
1711
3038
|
Constructor<{
|
|
1712
3039
|
id: string
|
|
1713
|
-
value:
|
|
3040
|
+
value: Record<string, unknown>
|
|
1714
3041
|
}>
|
|
1715
3042
|
|
|
1716
3043
|
export const SessionModel: ReturnType<typeof SessionMixin<typeof Model>>
|
|
@@ -1742,8 +3069,14 @@ export const UserMixin: <T extends Constructor<{}>>(
|
|
|
1742
3069
|
sessionScope?: OrArrayOf<string>
|
|
1743
3070
|
}
|
|
1744
3071
|
|
|
1745
|
-
|
|
1746
|
-
|
|
3072
|
+
/** Registers the passport strategy for this user class. */
|
|
3073
|
+
setup(): void
|
|
3074
|
+
|
|
3075
|
+
/** Authenticates a user via Passport. */
|
|
3076
|
+
login(
|
|
3077
|
+
ctx: KoaContext,
|
|
3078
|
+
options?: Record<string, unknown>
|
|
3079
|
+
): Promise<InstanceType<typeof UserModel>>
|
|
1747
3080
|
|
|
1748
3081
|
sessionQuery(
|
|
1749
3082
|
trx: Knex.Transaction
|
|
@@ -1752,72 +3085,11 @@ export const UserMixin: <T extends Constructor<{}>>(
|
|
|
1752
3085
|
|
|
1753
3086
|
export const UserModel: ReturnType<typeof UserMixin<typeof Model>>
|
|
1754
3087
|
|
|
1755
|
-
/**
|
|
1756
|
-
* Apply the action mixin to a controller action, in order to determine which
|
|
1757
|
-
* HTTP method (`'get'`, `'post'`, `'put'`, `'delete'` or `'patch'`) the action
|
|
1758
|
-
* should listen to and optionally the path to which it is mapped, defined in
|
|
1759
|
-
* relation to the route path of its controller. By default, the normalized
|
|
1760
|
-
* method name is used as the action's path, and the `'get'` method is assigned
|
|
1761
|
-
* if none is provided.
|
|
1762
|
-
*/
|
|
1763
|
-
export const action: (method: string, path: string) => Mixin
|
|
1764
|
-
|
|
1765
|
-
/**
|
|
1766
|
-
* Apply the authorize mixin to a controller action, in order to determines
|
|
1767
|
-
* whether or how the request is authorized. This value can either be one of the
|
|
1768
|
-
* values as described below, an array of them or a function which returns one
|
|
1769
|
-
* or more of them.
|
|
1770
|
-
*
|
|
1771
|
-
* - Boolean: `true` if the action should be authorized, `false` otherwise.
|
|
1772
|
-
* - '$self': The requested member is checked against `ctx.state.user` and the
|
|
1773
|
-
* action is only authorized if it matches the member.
|
|
1774
|
-
* - '$owner': The member is asked if it is owned by `ctx.state.user` through
|
|
1775
|
-
* the optional `Model.$hasOwner()` method.
|
|
1776
|
-
* - Any string: `ctx.state.user` is checked for this role through the
|
|
1777
|
-
* overridable `UserModel.hasRole()` method.
|
|
1778
|
-
*/
|
|
1779
|
-
export const authorize: (
|
|
1780
|
-
authorize: (ctx: KoaContext) => void | boolean | OrArrayOf<string>
|
|
1781
|
-
) => Mixin
|
|
1782
|
-
|
|
1783
|
-
/**
|
|
1784
|
-
* Apply the parameters mixin to a controller action, in order to apply
|
|
1785
|
-
* automatic mapping of Koa.js' `ctx.query` object to method parameters along
|
|
1786
|
-
* with their automatic validation.
|
|
1787
|
-
*
|
|
1788
|
-
* @see {@link https://github.com/ditojs/dito/blob/master/docs/model-properties.md Model Properties}
|
|
1789
|
-
*/
|
|
1790
|
-
export const parameters: (params: { [key: string]: Schema }) => Mixin
|
|
1791
|
-
|
|
1792
|
-
/**
|
|
1793
|
-
* Apply the response mixin to a controller action, in order to provide a schema
|
|
1794
|
-
* for the value returned from the action handler and optionally map the value
|
|
1795
|
-
* to a key inside a returned object when it contains a `name` property.
|
|
1796
|
-
*/
|
|
1797
|
-
export const response: (
|
|
1798
|
-
response: Schema & { name?: string },
|
|
1799
|
-
options: any
|
|
1800
|
-
) => Mixin
|
|
1801
|
-
|
|
1802
|
-
/**
|
|
1803
|
-
* Apply the scope mixin to a controller action, in order to determine the
|
|
1804
|
-
* scope(s) to be applied when loading the relation's models. The scope needs to
|
|
1805
|
-
* be defined in the related model class' scopes definitions.
|
|
1806
|
-
*/
|
|
1807
|
-
export const scope: (...scopes: string[]) => Mixin
|
|
1808
|
-
|
|
1809
|
-
/**
|
|
1810
|
-
* Apply the transacted mixin to a controller action in order to determine
|
|
1811
|
-
* whether queries in the action should be executed within a transaction. Any
|
|
1812
|
-
* failure will mean the database will rollback any queries executed to the
|
|
1813
|
-
* pre-transaction state.
|
|
1814
|
-
*/
|
|
1815
|
-
export const transacted: () => Mixin
|
|
1816
|
-
|
|
1817
3088
|
/* ------------------------------ End Mixins ----------------------------- */
|
|
1818
3089
|
|
|
1819
3090
|
export type HTTPMethod =
|
|
1820
3091
|
| 'get'
|
|
3092
|
+
| 'head'
|
|
1821
3093
|
| 'post'
|
|
1822
3094
|
| 'put'
|
|
1823
3095
|
| 'delete'
|
|
@@ -1827,7 +3099,7 @@ export type HTTPMethod =
|
|
|
1827
3099
|
| 'connect'
|
|
1828
3100
|
|
|
1829
3101
|
export interface KnexHelper {
|
|
1830
|
-
getDialect(): string
|
|
3102
|
+
getDialect(): string | null
|
|
1831
3103
|
|
|
1832
3104
|
isPostgreSQL(): boolean
|
|
1833
3105
|
|
|
@@ -1838,11 +3110,70 @@ export interface KnexHelper {
|
|
|
1838
3110
|
isMsSQL(): boolean
|
|
1839
3111
|
}
|
|
1840
3112
|
|
|
3113
|
+
export function convertSchema(
|
|
3114
|
+
schema: Schema,
|
|
3115
|
+
options?: Record<string, any>,
|
|
3116
|
+
parentEntry?: Record<string, any> | null
|
|
3117
|
+
): Record<string, any>
|
|
3118
|
+
|
|
3119
|
+
export function convertRelations(
|
|
3120
|
+
ownerModelClass: Class<Model>,
|
|
3121
|
+
relations: ModelRelations,
|
|
3122
|
+
models: Models
|
|
3123
|
+
): Record<string, any>
|
|
3124
|
+
|
|
3125
|
+
export function convertRelation(
|
|
3126
|
+
schema: ModelRelation,
|
|
3127
|
+
models: Models
|
|
3128
|
+
): Record<string, any>
|
|
3129
|
+
|
|
3130
|
+
export function getRelationClass(
|
|
3131
|
+
relation: string | typeof objection.Relation
|
|
3132
|
+
): typeof objection.Relation | null
|
|
3133
|
+
|
|
3134
|
+
export function isThroughRelationClass(
|
|
3135
|
+
relationClass: typeof objection.Relation
|
|
3136
|
+
): boolean
|
|
3137
|
+
|
|
3138
|
+
export function addRelationSchemas(
|
|
3139
|
+
modelClass: Class<Model>,
|
|
3140
|
+
properties: Record<string, ModelProperty>
|
|
3141
|
+
): void
|
|
3142
|
+
|
|
1841
3143
|
export type Keyword =
|
|
1842
3144
|
| SetOptional<Ajv.MacroKeywordDefinition, 'keyword'>
|
|
1843
3145
|
| SetOptional<Ajv.CodeKeywordDefinition, 'keyword'>
|
|
1844
3146
|
| SetOptional<Ajv.FuncKeywordDefinition, 'keyword'>
|
|
1845
3147
|
export type Format = Ajv.ValidateFunction | Ajv.FormatDefinition<string>
|
|
3148
|
+
|
|
3149
|
+
/** Built-in AJV keyword definitions. */
|
|
3150
|
+
export const keywords: {
|
|
3151
|
+
specificType: Keyword
|
|
3152
|
+
primary: Keyword
|
|
3153
|
+
foreign: Keyword
|
|
3154
|
+
unique: Keyword
|
|
3155
|
+
index: Keyword
|
|
3156
|
+
computed: Keyword
|
|
3157
|
+
hidden: Keyword
|
|
3158
|
+
unsigned: Keyword
|
|
3159
|
+
_instanceof: Keyword
|
|
3160
|
+
validate: Keyword
|
|
3161
|
+
validateAsync: Keyword
|
|
3162
|
+
relate: Keyword
|
|
3163
|
+
range: Keyword
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
/** Built-in AJV format definitions. */
|
|
3167
|
+
export const formats: {
|
|
3168
|
+
empty: Format
|
|
3169
|
+
required: Format
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
/** Built-in schema type definitions. */
|
|
3173
|
+
export const types: {
|
|
3174
|
+
asset: Record<string, any>
|
|
3175
|
+
color: Record<string, any>
|
|
3176
|
+
}
|
|
1846
3177
|
export type Id = string | number
|
|
1847
3178
|
export type KoaContext<$State = any> = Koa.ParameterizedContext<
|
|
1848
3179
|
$State,
|
|
@@ -1855,8 +3186,6 @@ export type KoaContext<$State = any> = Koa.ParameterizedContext<
|
|
|
1855
3186
|
|
|
1856
3187
|
type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>)
|
|
1857
3188
|
|
|
1858
|
-
type ReflectArrayType<Source, Target> = Source extends any[] ? Target[] : Target
|
|
1859
|
-
|
|
1860
3189
|
type OrArrayOf<T> = T[] | T
|
|
1861
3190
|
|
|
1862
3191
|
type OrReadOnly<T> = Readonly<T> | T
|
|
@@ -1866,46 +3195,80 @@ type OrPromiseOf<T> = Promise<T> | T
|
|
|
1866
3195
|
type ModelFromModelController<$ModelController extends ModelController> =
|
|
1867
3196
|
InstanceType<Exclude<$ModelController['modelClass'], undefined>>
|
|
1868
3197
|
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
3198
|
+
type SerializeModelPropertyValue<T> = T extends (infer U)[]
|
|
3199
|
+
? SerializeModelPropertyValue<U>[]
|
|
3200
|
+
: T extends Model
|
|
3201
|
+
? SerializedModel<T>
|
|
3202
|
+
: T extends Date
|
|
3203
|
+
? string
|
|
3204
|
+
: T
|
|
3205
|
+
|
|
3206
|
+
/**
|
|
3207
|
+
* Extracts the JSON-serialized data properties from a Dito
|
|
3208
|
+
* Model, stripping methods, `$`-prefixed, and internal keys.
|
|
3209
|
+
* Converts `Date` to `string` to reflect JSON serialization.
|
|
3210
|
+
*/
|
|
3211
|
+
export type SerializedModel<T extends Model> = {
|
|
3212
|
+
-readonly [K in keyof T as ModelDataKey<T, K>]: SerializeModelPropertyValue<
|
|
3213
|
+
T[K]
|
|
3214
|
+
>
|
|
1873
3215
|
}
|
|
1874
3216
|
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
>
|
|
3217
|
+
/** @deprecated Use `SerializedModel` instead. */
|
|
3218
|
+
export type SelectModelProperties<T extends Model> = SerializedModel<T>
|
|
3219
|
+
/** @deprecated Use `keyof SerializedModel<T>` instead. */
|
|
3220
|
+
export type SelectModelKeys<T extends Model> = keyof SerializedModel<T>
|
|
3221
|
+
/** @deprecated Use `SerializedModel` instead. */
|
|
3222
|
+
export type ExtractModelProperties<T extends Model> = SerializedModel<T>
|
|
3223
|
+
/** @deprecated Use `keyof SerializedModel<T>` instead. */
|
|
3224
|
+
export type SelectModelPropertyKeys<T extends Model> = keyof SerializedModel<T>
|
|
1881
3225
|
|
|
1882
3226
|
/* ---------------------- Extended from Ajv JSON Schema --------------------- */
|
|
1883
3227
|
|
|
3228
|
+
/**
|
|
3229
|
+
* Dito.js JSON Schema type, extending the AJV JSON Schema type with
|
|
3230
|
+
* Dito.js-specific validation keywords (`validate`, `validateAsync`,
|
|
3231
|
+
* `instanceof`).
|
|
3232
|
+
*
|
|
3233
|
+
* Used throughout the framework for model property definitions, action
|
|
3234
|
+
* parameters, and response schemas.
|
|
3235
|
+
*
|
|
3236
|
+
* @template T - The TypeScript type that this schema validates against.
|
|
3237
|
+
*
|
|
3238
|
+
* @example
|
|
3239
|
+
* ```ts
|
|
3240
|
+
* const schema: Schema<string> = {
|
|
3241
|
+
* type: 'string',
|
|
3242
|
+
* minLength: 1,
|
|
3243
|
+
* validate: ({ data, app }) => typeof data === 'string'
|
|
3244
|
+
* }
|
|
3245
|
+
* ```
|
|
3246
|
+
*/
|
|
1884
3247
|
export type Schema<T = any> = JSONSchemaType<T> & {
|
|
1885
3248
|
// keywords/_validate.js
|
|
1886
3249
|
validate?: (params: {
|
|
1887
|
-
data:
|
|
1888
|
-
parentData: object |
|
|
1889
|
-
rootData: object |
|
|
3250
|
+
data: unknown
|
|
3251
|
+
parentData: object | unknown[]
|
|
3252
|
+
rootData: object | unknown[]
|
|
1890
3253
|
dataPath: string
|
|
1891
3254
|
parentIndex?: number
|
|
1892
3255
|
parentKey?: string
|
|
1893
3256
|
app: Application<Models>
|
|
1894
3257
|
validator: Validator
|
|
1895
|
-
options:
|
|
3258
|
+
options: unknown
|
|
1896
3259
|
}) => boolean | void
|
|
1897
3260
|
|
|
1898
3261
|
// keywords/_validate.js
|
|
1899
3262
|
validateAsync?: (params: {
|
|
1900
|
-
data:
|
|
1901
|
-
parentData: object |
|
|
1902
|
-
rootData: object |
|
|
3263
|
+
data: unknown
|
|
3264
|
+
parentData: object | unknown[]
|
|
3265
|
+
rootData: object | unknown[]
|
|
1903
3266
|
dataPath: string
|
|
1904
3267
|
parentIndex?: number
|
|
1905
3268
|
parentKey?: string
|
|
1906
3269
|
app: Application<Models>
|
|
1907
3270
|
validator: Validator
|
|
1908
|
-
options:
|
|
3271
|
+
options: unknown
|
|
1909
3272
|
}) => Promise<boolean | void>
|
|
1910
3273
|
|
|
1911
3274
|
// keywords/_instanceof.js
|