@rvoh/psychic 2.0.2 → 2.0.4

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.
@@ -66,7 +66,7 @@ export default class PsychicCLI {
66
66
  program
67
67
  .command('generate:resource')
68
68
  .alias('g:resource')
69
- .description('create a Dream model, migration, controller, serializer, and spec placeholders')
69
+ .description('Generates a Dream model with corresponding spec factory, serializer, migration, and controller with the inheritance chain leading to that controller, with fleshed out specs for each resourceful action in the controller.')
70
70
  .option('--singular', 'generates a "resource" route instead of "resources", along with the necessary controller and spec changes')
71
71
  .option('--only <onlyActions>', `comma separated list of resourceful endpionts (e.g. "--only=create,show"); any of:
72
72
  - index
@@ -81,41 +81,50 @@ export default class PsychicCLI {
81
81
  .argument('<modelName>', 'the name of the model to create, e.g. Post or Settings/CommunicationPreferences')
82
82
  .argument('[columnsWithTypes...]', columnsWithTypesDescription)
83
83
  .action(async (route, modelName, columnsWithTypes, options) => {
84
- await initializePsychicApp({ bypassDreamIntegrityChecks: true });
84
+ await initializePsychicApp({
85
+ bypassDreamIntegrityChecks: true,
86
+ bypassDbConnectionsDuringInit: true,
87
+ });
85
88
  await PsychicBin.generateResource(route, modelName, columnsWithTypes, options);
86
89
  process.exit();
87
90
  });
88
91
  program
89
92
  .command('generate:controller')
90
93
  .alias('g:controller')
91
- .description('create a controller')
94
+ .description('Generates a controller and the inheritance chain leading to that controller, and a spec skeleton for the controller.')
92
95
  .argument('<controllerName>', 'the name of the controller to create, including namespaces, e.g. Posts or Api/V1/Posts')
93
96
  .argument('[actions...]', 'the names of controller actions to create')
94
97
  .action(async (controllerName, actions) => {
95
- await initializePsychicApp({ bypassDreamIntegrityChecks: true });
98
+ await initializePsychicApp({ bypassDreamIntegrityChecks: true, bypassDbConnectionsDuringInit: true });
96
99
  await PsychicBin.generateController(controllerName, actions);
97
100
  process.exit();
98
101
  });
99
102
  program
100
103
  .command('setup:sync:enums')
101
- .description('generates an initializer in your app for syncing enums to a particular path.')
104
+ .description('Generates an initializer in your app for syncing enums to a particular path.')
102
105
  .argument('<outfile>', 'the path from your backend directory to the location which you want the enums copied. Should end with .ts, i.e. "../client/src/api/enums.ts"')
103
106
  .option('--initializer-filename <initializerFilename>', 'the name you want the file to be in your initializers folder. defaults to `sync-enums.ts`')
104
107
  .action(async (outfile, { initializerName, }) => {
105
- await initializePsychicApp();
108
+ await initializePsychicApp({
109
+ bypassDreamIntegrityChecks: true,
110
+ bypassDbConnectionsDuringInit: true,
111
+ });
106
112
  await generateSyncEnumsInitializer(outfile, initializerName);
107
113
  process.exit();
108
114
  });
109
115
  program
110
116
  .command('setup:sync:openapi-redux')
111
- .description('generates openapi redux bindings to connect one of your openapi files to one of your clients')
117
+ .description('Generates openapi redux bindings to connect one of your openapi files to one of your clients.')
112
118
  .option('--schema-file <schemaFile>', 'the path from your api root to the openapi file you wish to use to generate your schema, i.e. ./src/openapi/openapi.json')
113
119
  .option('--api-file <apiFile>', 'the path to the boilerplate api file that will be used to scaffold your backend endpoints together with, i.e. ../client/app/api.ts')
114
120
  .option('--api-import <apiImport>', 'the camelCased name of the export from your api module, i.e. emptyBackendApi')
115
121
  .option('--output-file <outputFile>', 'the path to the file that will contain your typescript openapi redux bindings, i.e. ../client/app/myBackendApi.ts')
116
122
  .option('--export-name <exportName>', 'the camelCased name to use for your exported api, i.e. myBackendApi')
117
123
  .action(async ({ schemaFile, apiFile, apiImport, outputFile, exportName, }) => {
118
- await initializePsychicApp();
124
+ await initializePsychicApp({
125
+ bypassDreamIntegrityChecks: true,
126
+ bypassDbConnectionsDuringInit: true,
127
+ });
119
128
  await generateOpenapiReduxBindings({
120
129
  exportName,
121
130
  schemaFile,
@@ -127,18 +136,21 @@ export default class PsychicCLI {
127
136
  });
128
137
  program
129
138
  .command('setup:sync:openapi-typescript')
130
- .description('generates an initializer in your app for converting one of your openapi files to typescript')
139
+ .description('Generates an initializer in your app for converting one of your openapi files to typescript.')
131
140
  .argument('<openapiFilepath>', 'the path from your backend directory to the openapi file you wish to scan, i.e. "./src/openapi/openapi.json"')
132
141
  .argument('<outfile>', 'the path from your backend directory to the location which you want the openapi types written to. Must end with .d.ts, i.e. "./src/conf/openapi/openapi.types.d.ts"')
133
142
  .option('--initializer-filename <initializerFilename>', 'the name you want the file to be in your initializers folder. defaults to `sync-openapi-typescript.ts`')
134
143
  .action(async (openapiFilepath, outfile, { initializerName, }) => {
135
- await initializePsychicApp();
144
+ await initializePsychicApp({
145
+ bypassDreamIntegrityChecks: true,
146
+ bypassDbConnectionsDuringInit: true,
147
+ });
136
148
  await generateSyncOpenapiTypescriptInitializer(openapiFilepath, outfile, initializerName);
137
149
  process.exit();
138
150
  });
139
151
  program
140
152
  .command('routes')
141
- .description('examines your current models, building a type-map of the associations so that the ORM can understand your relational setup. This is commited to your repo, and synced to the dream repo for consumption within the underlying library.')
153
+ .description('Prints a list of routes defined by the application, including path arguments and the controller/action reached by the route.')
142
154
  .action(async () => {
143
155
  await initializePsychicApp();
144
156
  PsychicBin.printRoutes();
@@ -146,7 +158,7 @@ export default class PsychicCLI {
146
158
  });
147
159
  program
148
160
  .command('sync')
149
- .description('sync introspects your database, updating your schema to reflect, and then syncs the new schema with the installed dream node module, allowing it provide your schema to the underlying kysely integration')
161
+ .description("Generates types from the current state of the database. Generates OpenAPI specs from @OpenAPI decorated controller actions. Additional sync actions may be customized with `on('cli:sync', async () => {})` in conf/app.ts or in an initializer in `conf/initializers/`.")
150
162
  .option('--ignore-errors')
151
163
  .option('--schema-only')
152
164
  .action(async (options) => {
@@ -172,13 +184,13 @@ export default class PsychicCLI {
172
184
  });
173
185
  program
174
186
  .command('sync:routes')
175
- .description('reads the routes generated by your app and generates a cache file, which is then used to give autocomplete support to the route helper, amoongst other things.')
187
+ .description('Reads the routes generated by your app and generates a cache file, which is then used to give autocomplete support to the route helper and other things.')
176
188
  .action(async () => {
177
189
  await PsychicBin.syncRoutes();
178
190
  });
179
191
  program
180
192
  .command('sync:openapi')
181
- .description('syncs openapi.json file to current state of all psychic controllers within the app')
193
+ .description('Syncs openapi.json file to current state of all psychic controllers within the app')
182
194
  .action(async () => {
183
195
  await initializePsychicApp();
184
196
  await PsychicBin.syncOpenapiJson();
@@ -66,7 +66,7 @@ export default class PsychicCLI {
66
66
  program
67
67
  .command('generate:resource')
68
68
  .alias('g:resource')
69
- .description('create a Dream model, migration, controller, serializer, and spec placeholders')
69
+ .description('Generates a Dream model with corresponding spec factory, serializer, migration, and controller with the inheritance chain leading to that controller, with fleshed out specs for each resourceful action in the controller.')
70
70
  .option('--singular', 'generates a "resource" route instead of "resources", along with the necessary controller and spec changes')
71
71
  .option('--only <onlyActions>', `comma separated list of resourceful endpionts (e.g. "--only=create,show"); any of:
72
72
  - index
@@ -81,41 +81,50 @@ export default class PsychicCLI {
81
81
  .argument('<modelName>', 'the name of the model to create, e.g. Post or Settings/CommunicationPreferences')
82
82
  .argument('[columnsWithTypes...]', columnsWithTypesDescription)
83
83
  .action(async (route, modelName, columnsWithTypes, options) => {
84
- await initializePsychicApp({ bypassDreamIntegrityChecks: true });
84
+ await initializePsychicApp({
85
+ bypassDreamIntegrityChecks: true,
86
+ bypassDbConnectionsDuringInit: true,
87
+ });
85
88
  await PsychicBin.generateResource(route, modelName, columnsWithTypes, options);
86
89
  process.exit();
87
90
  });
88
91
  program
89
92
  .command('generate:controller')
90
93
  .alias('g:controller')
91
- .description('create a controller')
94
+ .description('Generates a controller and the inheritance chain leading to that controller, and a spec skeleton for the controller.')
92
95
  .argument('<controllerName>', 'the name of the controller to create, including namespaces, e.g. Posts or Api/V1/Posts')
93
96
  .argument('[actions...]', 'the names of controller actions to create')
94
97
  .action(async (controllerName, actions) => {
95
- await initializePsychicApp({ bypassDreamIntegrityChecks: true });
98
+ await initializePsychicApp({ bypassDreamIntegrityChecks: true, bypassDbConnectionsDuringInit: true });
96
99
  await PsychicBin.generateController(controllerName, actions);
97
100
  process.exit();
98
101
  });
99
102
  program
100
103
  .command('setup:sync:enums')
101
- .description('generates an initializer in your app for syncing enums to a particular path.')
104
+ .description('Generates an initializer in your app for syncing enums to a particular path.')
102
105
  .argument('<outfile>', 'the path from your backend directory to the location which you want the enums copied. Should end with .ts, i.e. "../client/src/api/enums.ts"')
103
106
  .option('--initializer-filename <initializerFilename>', 'the name you want the file to be in your initializers folder. defaults to `sync-enums.ts`')
104
107
  .action(async (outfile, { initializerName, }) => {
105
- await initializePsychicApp();
108
+ await initializePsychicApp({
109
+ bypassDreamIntegrityChecks: true,
110
+ bypassDbConnectionsDuringInit: true,
111
+ });
106
112
  await generateSyncEnumsInitializer(outfile, initializerName);
107
113
  process.exit();
108
114
  });
109
115
  program
110
116
  .command('setup:sync:openapi-redux')
111
- .description('generates openapi redux bindings to connect one of your openapi files to one of your clients')
117
+ .description('Generates openapi redux bindings to connect one of your openapi files to one of your clients.')
112
118
  .option('--schema-file <schemaFile>', 'the path from your api root to the openapi file you wish to use to generate your schema, i.e. ./src/openapi/openapi.json')
113
119
  .option('--api-file <apiFile>', 'the path to the boilerplate api file that will be used to scaffold your backend endpoints together with, i.e. ../client/app/api.ts')
114
120
  .option('--api-import <apiImport>', 'the camelCased name of the export from your api module, i.e. emptyBackendApi')
115
121
  .option('--output-file <outputFile>', 'the path to the file that will contain your typescript openapi redux bindings, i.e. ../client/app/myBackendApi.ts')
116
122
  .option('--export-name <exportName>', 'the camelCased name to use for your exported api, i.e. myBackendApi')
117
123
  .action(async ({ schemaFile, apiFile, apiImport, outputFile, exportName, }) => {
118
- await initializePsychicApp();
124
+ await initializePsychicApp({
125
+ bypassDreamIntegrityChecks: true,
126
+ bypassDbConnectionsDuringInit: true,
127
+ });
119
128
  await generateOpenapiReduxBindings({
120
129
  exportName,
121
130
  schemaFile,
@@ -127,18 +136,21 @@ export default class PsychicCLI {
127
136
  });
128
137
  program
129
138
  .command('setup:sync:openapi-typescript')
130
- .description('generates an initializer in your app for converting one of your openapi files to typescript')
139
+ .description('Generates an initializer in your app for converting one of your openapi files to typescript.')
131
140
  .argument('<openapiFilepath>', 'the path from your backend directory to the openapi file you wish to scan, i.e. "./src/openapi/openapi.json"')
132
141
  .argument('<outfile>', 'the path from your backend directory to the location which you want the openapi types written to. Must end with .d.ts, i.e. "./src/conf/openapi/openapi.types.d.ts"')
133
142
  .option('--initializer-filename <initializerFilename>', 'the name you want the file to be in your initializers folder. defaults to `sync-openapi-typescript.ts`')
134
143
  .action(async (openapiFilepath, outfile, { initializerName, }) => {
135
- await initializePsychicApp();
144
+ await initializePsychicApp({
145
+ bypassDreamIntegrityChecks: true,
146
+ bypassDbConnectionsDuringInit: true,
147
+ });
136
148
  await generateSyncOpenapiTypescriptInitializer(openapiFilepath, outfile, initializerName);
137
149
  process.exit();
138
150
  });
139
151
  program
140
152
  .command('routes')
141
- .description('examines your current models, building a type-map of the associations so that the ORM can understand your relational setup. This is commited to your repo, and synced to the dream repo for consumption within the underlying library.')
153
+ .description('Prints a list of routes defined by the application, including path arguments and the controller/action reached by the route.')
142
154
  .action(async () => {
143
155
  await initializePsychicApp();
144
156
  PsychicBin.printRoutes();
@@ -146,7 +158,7 @@ export default class PsychicCLI {
146
158
  });
147
159
  program
148
160
  .command('sync')
149
- .description('sync introspects your database, updating your schema to reflect, and then syncs the new schema with the installed dream node module, allowing it provide your schema to the underlying kysely integration')
161
+ .description("Generates types from the current state of the database. Generates OpenAPI specs from @OpenAPI decorated controller actions. Additional sync actions may be customized with `on('cli:sync', async () => {})` in conf/app.ts or in an initializer in `conf/initializers/`.")
150
162
  .option('--ignore-errors')
151
163
  .option('--schema-only')
152
164
  .action(async (options) => {
@@ -172,13 +184,13 @@ export default class PsychicCLI {
172
184
  });
173
185
  program
174
186
  .command('sync:routes')
175
- .description('reads the routes generated by your app and generates a cache file, which is then used to give autocomplete support to the route helper, amoongst other things.')
187
+ .description('Reads the routes generated by your app and generates a cache file, which is then used to give autocomplete support to the route helper and other things.')
176
188
  .action(async () => {
177
189
  await PsychicBin.syncRoutes();
178
190
  });
179
191
  program
180
192
  .command('sync:openapi')
181
- .description('syncs openapi.json file to current state of all psychic controllers within the app')
193
+ .description('Syncs openapi.json file to current state of all psychic controllers within the app')
182
194
  .action(async () => {
183
195
  await initializePsychicApp();
184
196
  await PsychicBin.syncOpenapiJson();
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "@rvoh/psychic",
4
4
  "description": "Typescript web framework",
5
- "version": "2.0.2",
5
+ "version": "2.0.4",
6
6
  "author": "RVOHealth",
7
7
  "repository": {
8
8
  "type": "git",
@@ -78,7 +78,7 @@
78
78
  "yoctocolors": "^2.1.1"
79
79
  },
80
80
  "peerDependencies": {
81
- "@rvoh/dream": "^2.0.1",
81
+ "@rvoh/dream": "^2.0.3",
82
82
  "@types/express": "^5.0.1",
83
83
  "commander": "^12.1.0",
84
84
  "express": "^5.1.0",
@@ -87,7 +87,7 @@
87
87
  "devDependencies": {
88
88
  "@eslint/js": "^9.19.0",
89
89
  "@jest-mock/express": "^3.0.0",
90
- "@rvoh/dream": "^2.0.1",
90
+ "@rvoh/dream": "^2.0.3",
91
91
  "@rvoh/dream-spec-helpers": "^2.0.0",
92
92
  "@rvoh/psychic-spec-helpers": "^2.0.0",
93
93
  "@types/express": "^5.0.1",
@@ -122,4 +122,4 @@
122
122
  "winston": "^3.14.2"
123
123
  },
124
124
  "packageManager": "yarn@4.7.0"
125
- }
125
+ }
package/CHANGELOG.md DELETED
@@ -1,383 +0,0 @@
1
- ## 2.0.2
2
-
3
- bump glob to close dependabot alerts
4
-
5
- ## 2.0.1
6
-
7
- - stop exporting `pluralize` since it's just a direct export of `pluralize-esm`
8
-
9
- ## 2.0.0
10
-
11
- - namespace package exports
12
- - remove `including` support from `paramsFor`
13
-
14
- ## 1.14.0
15
-
16
- - generated code uses absolute imports
17
- - account for change in Dream in which `Virtual` decorator requires OpenAPI shape
18
- - throw a more detailed error when DreamSerializer.attribute used to render a non-database, non-Virtual decorated property
19
- - fix OpenAPI generated when paginating/scrollPaginating an STI base model
20
- - add `--ignore-errors` option to `yarn psy sync` so can build complicated OpenAPI shapes and serializers without needing to follow a set order
21
-
22
- ## 1.13.0
23
-
24
- - bump to Dream 1.12.0, which changes DateTime and CalendarDate to throw an exception rather than allowing invalid datetimes/dates
25
-
26
- ## 1.12.3
27
-
28
- - fix setup:sync:openapi-redux and setup:sync:openapi-typescript cli
29
- - include 404 in resource controller spec status code types
30
- - default SameSite header to 'Strict'
31
- - resource controllers generated with the `singular` flag load the resource with `firstOrFail()`, not `.findOrFail(this.castParam('id', 'string'))`
32
-
33
- ## 1.12.2
34
-
35
- - when using `combining` in requestBody for an OpenAPI decorator, it will now override any params brought in through serializable introspection.
36
-
37
- ## 1.12.1
38
-
39
- - increase depth of OpenAPI validation error logs
40
- - fix generated resource controller spec
41
-
42
- ## 1.12.0
43
-
44
- - `scrollPagination` support
45
- - sort client enums when syncing to reduce needless diff churn
46
- - leverage RequestBody in generated resource controller specs
47
-
48
- ## 1.11.1
49
-
50
- - export PsychicLogos
51
- - export colorize
52
-
53
- ## 1.11.0
54
-
55
- - match Dream change from `bypassModelIntegrityCheck` to `bypassDreamIntegrityChecks`
56
- - match Dream change to allow automatic OpenAPI generation from `delegatedAttribute` serialization of associated models
57
- - fix resource controller spec generator missing date and datetime in spec ensuring model owned by another user is not updated
58
- - resource controller spec generator supports array attributes
59
- - generated resource controller spec data type `DreamRequestAttributes`, not `UpdateableProperties`
60
- - call `.toISO()` on all DateTime and CalendarDate properties going into request to conform to types
61
- - only pluralize the route if not designated as `singular`; pluralize before generating controller name so the controller name matches the route in the routes file
62
- - increase depth of inspection during error logging
63
-
64
- ## 1.10.5
65
-
66
- - add "combining" option to requestBody for OpenAPI decorator, enabling you to combine additional openapi fields to the request body, while still leveraging the powerful automatically-generated request body.
67
- - syncing client enums now sync types along with values
68
- - better dev logging
69
-
70
- ## 1.10.4
71
-
72
- Fix issue with rendering incorrect enum descriptions when suppressResponseEnums is set to true and enums are explicitly overridden in the openapi option.
73
-
74
- ## 1.10.3
75
-
76
- - respect `required: false` when generating OpenAPI spec
77
-
78
- ## 1.10.2
79
-
80
- - return 400 instead of throwing error and 500 when there is a column overflow at the database level (let database validation suffice for enforcing data length validation rather than requiring model level validation)
81
-
82
- ## 1.10.1
83
-
84
- - OpenAPI and castParam validation errors are logged only when `NODE_DEBUG=psychic`
85
-
86
- ## 1.10.0
87
-
88
- - remove OpenAPI and Dream validation error response configuration and do not respond with errors (don't introduce such a difference between development and production environments)
89
- - log validation errors in test and dev (not prod to avoid DOS)
90
- - remove distinction between 400 and 422 to block ability of attacker to get feedback on how far into the system their request made it
91
-
92
- ## 1.9.0
93
-
94
- 1. Validate params against OpenAPI at the latest possible of:
95
- a. when the params are accessed
96
- b. when about to render the action
97
- This ensures that we return the proper 401/403 response instead of 400 for authenticated endpoints that fail authentication and prevents unauthenticated requests from gaining information about the API
98
-
99
- 2. Ability to configure whether or not OpenAPI validation errors include detailed information
100
-
101
- ## 1.8.6
102
-
103
- remove dead env variable, now that we are open sourced
104
-
105
- ## 1.8.5
106
-
107
- Do not hard crash when initializing a psychic application when one of the openapi routes is not found for an openapi-decorated controller endpoint. We will continue to raise this exception when building openapi specs, but not when booting up the psychic application, since one can define routes that are i.e. not available in certain environments, and we don't want this to cause hard crashes when our app boots in those environments.
108
-
109
- ## 1.8.4
110
-
111
- - OpenAPI decorator with default 204 status does not throw an exception when passed a Dream model without a `serializers` getter
112
- - OpenAPI decorator that defines an explicit OpenAPI shape for the default status code does not throw an exception when passed a Dream model without a `serializers` getter
113
-
114
- ## 1.8.3
115
-
116
- - don't build openapi when `bypassModelIntegrityCheck: true`
117
-
118
- ## 1.8.2
119
-
120
- - openapi validation properly coerces non-array query params to arrays when validating, since both express and ajv fail to do this under the hood properly. This solves issues where sending up array params with only a single item in them are not treated as arrays.
121
-
122
- ## 1.8.1
123
-
124
- - do not coerce types in ajv when processing request or response bodies during validation. Type coercion will still happen for headers and query params, since they will need to respect the schema type specified in the openapi docuement.
125
-
126
- ## 1.8.0
127
-
128
- - remove unused `clientRoot` config
129
-
130
- ## 1.7.2
131
-
132
- - generate admin routes in routes.admin.ts (requires `routes.admin.ts` next to `routes.ts`)
133
-
134
- ## 1.7.1
135
-
136
- - compute openapi doc during intiialization, rather than problematically reading from a file cache
137
-
138
- ## 1.7.0
139
-
140
- - `sanitizeResponseJson` config to automatically escape `<`, `>`, `&`, `/`, `\`, `'`, and `"` unicode representations when rendering json to satisfy security reviews (e.g., a pentest report recently called this out on one of our applications). For all practical purposes, this doesn't protect against anything (now that we have the `nosniff` header) since `JSON.parse` on the other end restores the original, dangerous string. Modern front end web frameworks already handle safely displaying arbitrary content, so further sanitization generally isn't needed. This version does provide the `sanitizeString` function that could be used to sanitize individual strings, replacing the above characters with string representations of the unicode characters that will survive Psychic converting to json and then parsing that json (i.e.: `<` will end up as the string "\u003c")
141
-
142
- - Fix openapi serializer fallback issue introduced in 1.6.3, where we mistakenly double render data that has already been serialized.
143
-
144
- ## 1.6.4
145
-
146
- Raise an exception if attempting to import an openapi file during PsychicApp.init when in production. We will still swallow the exception in non-prod environments so that one can create a new openapi configuration and run sync without getting an error.
147
-
148
- ## 1.6.3
149
-
150
- - castParam accepts raw openapi shapes as type arguments, correctly casting the result to an interface representing the provided openapi shape.
151
-
152
- ```ts
153
- class MyController extends ApplicationController {
154
- public index() {
155
- const myParam = this.castParam('myParam', {
156
- type: 'array',
157
- items: {
158
- anyOf: [{ type: 'string' }, { type: 'number' }],
159
- },
160
- })
161
- myParam[0] // string | number
162
- }
163
- }
164
- ```
165
-
166
- - simplify the needlessly-robust new psychic router patterns by making expressApp optional, essentially reverting us back to the same psychic router we had prior to the recent openapi validation changes.
167
-
168
- - fallback to serializer specified in openapi decorator before falling back to dream serializer when rendering dreams
169
-
170
- ## 1.6.2
171
-
172
- fix OpenAPI spec generation by DRYing up generation of request and response body
173
-
174
- ## 1.6.1
175
-
176
- fix issue preventing validation fallbacks from properly overriding on OpenAPI decorator calls when explicitly opting out of validation
177
-
178
- ## 1.6.0
179
-
180
- enables validation to be added to both openapi configurations, as well as to `OpenAPI` decorator calls, enabling the developer to granularly control validation logic for their endpoints.
181
-
182
- To leverage global config:
183
-
184
- ```ts
185
- // conf/app.ts
186
- export default async (psy: PsychicApp) => {
187
- ...
188
-
189
- psy.set('openapi', {
190
- // ...
191
- validate: {
192
- headers: true,
193
- requestBody: true,
194
- query: true,
195
- responseBody: AppEnv.isTest,
196
- },
197
- })
198
- }
199
- ```
200
-
201
- To leverage endpoint config:
202
-
203
- ```ts
204
- // controllers/PetsController
205
- export default class PetsController {
206
- @OpenAPI(Pet, {
207
- ...
208
- validate: {
209
- headers: true,
210
- requestBody: true,
211
- query: true,
212
- responseBody: AppEnv.isTest,
213
- }
214
- })
215
- public async index() {
216
- ...
217
- }
218
- }
219
- ```
220
-
221
- This PR additionally formally introduces a new possible error type for 400 status codes, and to help distinguish, it also introduces a `type` field, which can be either `openapi` or `dream` to aid the developer in easily handling the various cases.
222
-
223
- We have made a conscious decision to render openapi errors in the exact format that ajv returns, since it empowers the developer to utilize tools which can already respond to ajv errors.
224
-
225
- For added flexibility, this PR includes the ability to provide configuration overrides for the ajv instance, as well as the ability to provide an initialization function to override ajv behavior, since much of the configuration for ajv is driven by method calls, rather than simple config.
226
-
227
- ```ts
228
- // controllers/PetsController
229
- export default class PetsController {
230
- @OpenAPI(Pet, {
231
- ...
232
- validate: {
233
- ajvOptions: {
234
- // this is off by default, but you will
235
- // always want to keep this off in prod
236
- // to avoid DoS vulnerabilities
237
- allErrors: AppEnv.isTest,
238
-
239
- // provide a custom init function to further
240
- // configure your ajv instance before validating
241
- init: ajv => {
242
- ajv.addFormat('myFormat', {
243
- type: 'string',
244
- validate: data => MY_FORMAT_REGEX.test(data),
245
- })
246
- }
247
- }
248
- }
249
- })
250
- public async index() {
251
- ...
252
- }
253
- }
254
- ```
255
-
256
- ## 1.5.5
257
-
258
- - ensure that openapi-typescript and typescript are not required dependencies when running migrations with --skip-sync flag
259
-
260
- ## 1.5.4
261
-
262
- - fix issue when providing the `including` argument exclusively to an OpenAPI decorator's `requestBody`
263
-
264
- ## 1.5.3
265
-
266
- - add missing peer dependency for openapi-typescript, allow BIGINT type when generating openapi-typescript bigints
267
-
268
- ## 1.5.2
269
-
270
- - ensure that bigints are converted to number | string when generating openapi-typescript type files
271
-
272
- ## 1.5.1
273
-
274
- - fix issue with enum syncing related to multi-db engine support regression
275
-
276
- ## 1.5.0
277
-
278
- - add support for multiple database engines in dream
279
-
280
- ## 1.2.3
281
-
282
- - add support for the connectionName argument when generating a resource
283
-
284
- ## 1.2.2
285
-
286
- - bump supertest and express-session to close dependabot issues [53](https://github.com/rvohealth/psychic/security/dependabot/53), [56](https://github.com/rvohealth/psychic/security/dependabot/56), and [57](https://github.com/rvohealth/psychic/security/dependabot/57)
287
-
288
- ## 1.2.1
289
-
290
- - add ability to set custom import extension, which will be used when generating new files for your application
291
-
292
- ## 1.2.0
293
-
294
- - update for Dream 1.4.0
295
-
296
- ## 1.1.11
297
-
298
- - 400 is more appropriate than 422 for `DataTypeColumnTypeMismatch`
299
-
300
- ## 1.1.10
301
-
302
- - Don't include deletedAt in generated create/update actions in resource specs since deletedAt is for deleting
303
-
304
- - return 422 if Dream throws `NotNullViolation` or `CheckConstraintViolation`
305
-
306
- ## 1.1.9
307
-
308
- - return 422 if dream throws `DataTypeColumnTypeMismatch`, which happens when a dream is saved to the database with data that cannot be inserted into the respective columns, usually because of a type mismatch.
309
-
310
- - castParam will now encase params in an array when being explicitly casted as an array type, bypassing a known bug in express from causing arrays with single items in them to be treated as non-arrays.
311
-
312
- ## 1.1.8
313
-
314
- - Tap into CliFileWriter provided by dream to tap into file reversion for sync files, since the auto-sync function in psychic can fail and leave your file tree in a bad state.
315
-
316
- ## 1.1.7
317
-
318
- - Add support for middleware arrays, enabling express plugins like passport
319
-
320
- ## 1.1.6
321
-
322
- - fix regression caused by missing --schema-only option in psychic cli
323
-
324
- ## 1.1.5
325
-
326
- - pass packageManager through to dream, now that it accepts a packageManager setting.
327
- - update dream shadowing within psychic application initialization to take place after initializers and plugins are processed, so that those initializers and plugins have an opportunity to adjust the settings.
328
-
329
- ## 1.1.4
330
-
331
- - fix regressions to redux bindings caused by default openapi path location changes
332
- - resource generator can handle prefixing slashes
333
-
334
- ## 1.1.3
335
-
336
- - fix more minor issues with redux openapi bindings
337
-
338
- ## 1.1.2
339
-
340
- - Fix various issues with openapi redux bindings
341
- - raise hard exception if accidentally using openapi route params in an expressjs route path
342
-
343
- ## 1.1.1
344
-
345
- Fix route printing regression causing route printouts to show the path instead of the action
346
-
347
- ## v1.1.0
348
-
349
- Provides easier access to express middleware by exposing `PsychicApp#use`, which enables a developer to provide express middleware directly through the psychcic application, without tapping into any hooks.
350
-
351
- ```ts
352
- psy.use((_, res) => {
353
- res.send(
354
- 'this will be run after psychic middleware (i.e. cors and bodyParser) are processed, but before routes are processed',
355
- )
356
- })
357
- ```
358
-
359
- Some middleware needs to be run before other middleware, so we expose an optional first argument which can be provided so explicitly send your middleware into express at various stages of the psychic configuration process. For example, to inject your middleware before cors and bodyParser are configured, provide `before-middleware` as the first argument. To initialize your middleware after the psychic default middleware, but before your routes have been processed, provide `after-middleware` as the first argument (or simply provide a callback function directly, since this is the default). To run after routes have been processed, provide `after-routes` as the first argument.
360
-
361
- ```ts
362
- psy.use('before-middleware', (_, res) => {
363
- res.send('this will be run before psychic has configured any default middleware')
364
- })
365
-
366
- psy.use('after-middleware', (_, res) => {
367
- res.send('this will be run after psychic has configured default middleware')
368
- })
369
-
370
- psy.use('after-routes', (_, res) => {
371
- res.send('this will be run after psychic has processed all the routes in your conf/routes.ts file')
372
- })
373
- ```
374
-
375
- Additionally, a new overload has been added to all CRUD methods on the PsychicRouter class, enabling you to provide RequestHandler middleware directly to psychic, like so:
376
-
377
- ```ts
378
- // conf/routes.ts
379
-
380
- r.get('helloworld', (req, res, next) => {
381
- res.json({ hello: 'world' })
382
- })
383
- ```