prisma-generator-express 1.41.0 → 1.43.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.
Files changed (45) hide show
  1. package/dist/generators/generateFastifyHandler.js +17 -4
  2. package/dist/generators/generateFastifyHandler.js.map +1 -1
  3. package/dist/generators/generateHonoHandler.js +4 -4
  4. package/dist/generators/generateOperationCore.d.ts +0 -1
  5. package/dist/generators/generateOperationCore.js +34 -546
  6. package/dist/generators/generateOperationCore.js.map +1 -1
  7. package/dist/generators/generateRelationMeta.d.ts +13 -0
  8. package/dist/generators/generateRelationMeta.js +106 -0
  9. package/dist/generators/generateRelationMeta.js.map +1 -0
  10. package/dist/generators/generateRouteConfigType.js +6 -6
  11. package/dist/generators/generateRouteConfigType.js.map +1 -1
  12. package/dist/generators/generateRouter.js +141 -60
  13. package/dist/generators/generateRouter.js.map +1 -1
  14. package/dist/generators/generateRouterFastify.js +127 -384
  15. package/dist/generators/generateRouterFastify.js.map +1 -1
  16. package/dist/generators/generateRouterHono.js +48 -36
  17. package/dist/generators/generateRouterHono.js.map +1 -1
  18. package/dist/generators/generateUnifiedHandler.js +24 -8
  19. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  20. package/dist/index.js +21 -5
  21. package/dist/index.js.map +1 -1
  22. package/dist/utils/copyFiles.js +12 -0
  23. package/dist/utils/copyFiles.js.map +1 -1
  24. package/dist/utils/writeFileSafely.js +3 -0
  25. package/dist/utils/writeFileSafely.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/copy/autoIncludePlanner.ts +299 -0
  28. package/src/copy/autoIncludeRuntime.ts +307 -0
  29. package/src/copy/operationRuntime.ts +603 -0
  30. package/src/copy/routeConfig.express.ts +5 -3
  31. package/src/copy/routeConfig.fastify.ts +2 -2
  32. package/src/copy/routeConfig.hono.ts +3 -3
  33. package/src/copy/routeConfig.ts +20 -9
  34. package/src/generators/generateFastifyHandler.ts +17 -4
  35. package/src/generators/generateHonoHandler.ts +4 -4
  36. package/src/generators/generateOperationCore.ts +34 -546
  37. package/src/generators/generateRelationMeta.ts +154 -0
  38. package/src/generators/generateRouteConfigType.ts +7 -7
  39. package/src/generators/generateRouter.ts +141 -60
  40. package/src/generators/generateRouterFastify.ts +127 -384
  41. package/src/generators/generateRouterHono.ts +48 -36
  42. package/src/generators/generateUnifiedHandler.ts +24 -8
  43. package/src/index.ts +25 -7
  44. package/src/utils/copyFiles.ts +13 -0
  45. package/src/utils/writeFileSafely.ts +3 -0
@@ -0,0 +1,154 @@
1
+ import { DMMF } from '@prisma/generator-helper'
2
+ import { ImportStyle } from '../utils/resolveImportStyle'
3
+ import { importExt } from '../utils/importExt'
4
+
5
+ type RelationDirection = 'parentOwnsFk' | 'childOwnsFk' | 'implicitM2M'
6
+
7
+ type RelationFieldMeta = {
8
+ name: string
9
+ type: string
10
+ isList: boolean
11
+ isRequired: boolean
12
+ direction: RelationDirection
13
+ parentLinkFields: string[]
14
+ childLinkFields: string[]
15
+ }
16
+
17
+ type ModelMeta = {
18
+ name: string
19
+ delegateKey: string
20
+ scalarFields: string[]
21
+ idFields: string[]
22
+ relations: Record<string, RelationFieldMeta>
23
+ }
24
+
25
+ function findOppositeField(
26
+ models: ReadonlyArray<DMMF.Model>,
27
+ targetModelName: string,
28
+ relationName: string | undefined,
29
+ selfModelName: string,
30
+ ): DMMF.Field | null {
31
+ if (!relationName) return null
32
+ const target = models.find((m) => m.name === targetModelName)
33
+ if (!target) return null
34
+ return target.fields.find(
35
+ (f) => f.kind === 'object' && f.relationName === relationName && f.type === selfModelName,
36
+ ) || null
37
+ }
38
+
39
+ function computeRelation(
40
+ field: DMMF.Field,
41
+ selfModelName: string,
42
+ models: ReadonlyArray<DMMF.Model>,
43
+ ): RelationFieldMeta {
44
+ const selfFrom = (field.relationFromFields ?? []) as string[]
45
+ const selfTo = (field.relationToFields ?? []) as string[]
46
+
47
+ if (selfFrom.length > 0) {
48
+ return {
49
+ name: field.name,
50
+ type: field.type,
51
+ isList: field.isList,
52
+ isRequired: field.isRequired,
53
+ direction: 'parentOwnsFk',
54
+ parentLinkFields: selfFrom,
55
+ childLinkFields: selfTo,
56
+ }
57
+ }
58
+
59
+ const opposite = findOppositeField(models, field.type, field.relationName, selfModelName)
60
+ if (opposite) {
61
+ const oppFrom = (opposite.relationFromFields ?? []) as string[]
62
+ const oppTo = (opposite.relationToFields ?? []) as string[]
63
+ if (oppFrom.length > 0) {
64
+ return {
65
+ name: field.name,
66
+ type: field.type,
67
+ isList: field.isList,
68
+ isRequired: field.isRequired,
69
+ direction: 'childOwnsFk',
70
+ parentLinkFields: oppTo,
71
+ childLinkFields: oppFrom,
72
+ }
73
+ }
74
+ }
75
+
76
+ return {
77
+ name: field.name,
78
+ type: field.type,
79
+ isList: field.isList,
80
+ isRequired: field.isRequired,
81
+ direction: 'implicitM2M',
82
+ parentLinkFields: [],
83
+ childLinkFields: [],
84
+ }
85
+ }
86
+
87
+ function buildModelMeta(
88
+ model: DMMF.Model,
89
+ models: ReadonlyArray<DMMF.Model>,
90
+ ): ModelMeta {
91
+ const scalarFields: string[] = []
92
+ const idFields: string[] = []
93
+ const relations: Record<string, RelationFieldMeta> = {}
94
+
95
+ for (const field of model.fields) {
96
+ if (field.kind === 'object') {
97
+ relations[field.name] = computeRelation(field, model.name, models)
98
+ } else if (field.kind === 'scalar' || field.kind === 'enum') {
99
+ scalarFields.push(field.name)
100
+ if (field.isId) idFields.push(field.name)
101
+ }
102
+ }
103
+
104
+ if (model.primaryKey && Array.isArray(model.primaryKey.fields)) {
105
+ for (const f of model.primaryKey.fields) {
106
+ if (!idFields.includes(f)) idFields.push(f)
107
+ }
108
+ }
109
+
110
+ return {
111
+ name: model.name,
112
+ delegateKey: model.name.charAt(0).toLowerCase() + model.name.slice(1),
113
+ scalarFields,
114
+ idFields,
115
+ relations,
116
+ }
117
+ }
118
+
119
+ export interface GenerateRelationMetaOptions {
120
+ model: DMMF.Model
121
+ allModels: ReadonlyArray<DMMF.Model>
122
+ importStyle: ImportStyle
123
+ }
124
+
125
+ export function generateRelationMeta(options: GenerateRelationMetaOptions): string {
126
+ const ext = importExt(options.importStyle)
127
+ const meta = buildModelMeta(options.model, options.allModels)
128
+ return `import type { ModelRelationMap } from '../autoIncludePlanner${ext}'
129
+
130
+ export const ${options.model.name}Relations: ModelRelationMap = ${JSON.stringify(meta, null, 2)}
131
+ `
132
+ }
133
+
134
+ export interface GenerateRelationModelsIndexOptions {
135
+ modelNames: ReadonlyArray<string>
136
+ importStyle: ImportStyle
137
+ }
138
+
139
+ export function generateRelationModelsIndex(options: GenerateRelationModelsIndexOptions): string {
140
+ const ext = importExt(options.importStyle)
141
+ const imports = options.modelNames
142
+ .map((n) => `import { ${n}Relations } from './${n}/${n}Relations${ext}'`)
143
+ .join('\n')
144
+ const entries = options.modelNames
145
+ .map((n) => ` ${n}: ${n}Relations,`)
146
+ .join('\n')
147
+ return `import type { ModelRelationMap } from './autoIncludePlanner${ext}'
148
+ ${imports}
149
+
150
+ export const relationModels: Record<string, ModelRelationMap> = {
151
+ ${entries}
152
+ }
153
+ `
154
+ }
@@ -53,8 +53,12 @@ export function generateRouteConfigType(
53
53
  const m = modelName
54
54
  const supportsProgressive = target === 'express'
55
55
 
56
+ const progressiveTypeImport = supportsProgressive
57
+ ? `import type { ProgressiveVariantConfig, ProgressiveStage } from '../routeConfig.target${ext}'\n\n`
58
+ : ''
59
+
56
60
  if (!guardShapesImport) {
57
- return `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string, any>, TCtx>\n`
61
+ return progressiveTypeImport + `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string, unknown>, TCtx>\n`
58
62
  }
59
63
 
60
64
  const shapeOps = Object.values(ROUTER_OP_TO_SHAPE_OP).filter((v, i, a) => a.indexOf(v) === i)
@@ -78,15 +82,11 @@ export function generateRouteConfigType(
78
82
 
79
83
  const omitKeys = ROUTER_OPERATIONS.map((k) => `'${k}'`).join('\n | ')
80
84
 
81
- const progressiveTypeImport = supportsProgressive
82
- ? `import type { ProgressiveVariantConfig, ProgressiveStage } from '../routeConfig.target${ext}'\n\n`
83
- : ''
84
-
85
85
  return (
86
86
  progressiveTypeImport +
87
- `import type {\n ${opShapeImports}\n} from '${guardShapesImport}'\n\n` +
87
+ `import type {\n ${opShapeImports}\n} from '${guardShapesImport}${ext}'\n\n` +
88
88
  `export type ${m}RouteConfig<TCtx = unknown> = Omit<\n` +
89
- ` RouteConfig<Record<string, any>, TCtx>,\n` +
89
+ ` RouteConfig<Record<string, unknown>, TCtx>,\n` +
90
90
  ` | ${omitKeys}\n` +
91
91
  ` | 'resolveContext'\n` +
92
92
  `> & {\n` +
@@ -20,6 +20,7 @@ export function generateRouterFunction({
20
20
  const modelName = model.name
21
21
  const prefix = toCamelCase(modelName)
22
22
  const modelNameLower = modelName.toLowerCase()
23
+ const delegateKey = modelName.charAt(0).toLowerCase() + modelName.slice(1)
23
24
  const routerFunctionName = `${prefix}Router`
24
25
 
25
26
  const fieldsMeta = model.fields.map((f) => ({
@@ -47,6 +48,7 @@ export function generateRouterFunction({
47
48
 
48
49
  return `import express from 'express'
49
50
  import type { Request, Response, NextFunction, RequestHandler } from 'express'
51
+ import { startQueryBuilder } from '../queryBuilder${ext}'
50
52
  import {
51
53
  ${prefix}FindUnique,
52
54
  ${prefix}FindUniqueOrThrow,
@@ -79,6 +81,8 @@ import {
79
81
  runProgressiveEndpoint,
80
82
  runSingleResultSSE,
81
83
  } from '../operationRuntime${ext}'
84
+ import { relationModels } from '../relationModels${ext}'
85
+ import { runAutoIncludeProgressive } from '../autoIncludeRuntime${ext}'
82
86
 
83
87
  ${generateRouteConfigType(modelName, 'RequestHandler', guardShapesImport, importStyle, 'express')}
84
88
  const _env = typeof process !== 'undefined' && process.env ? process.env : {} as Record<string, string | undefined>
@@ -86,9 +90,31 @@ const _env = typeof process !== 'undefined' && process.env ? process.env : {} as
86
90
  const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
87
91
  const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
88
92
 
89
- const defaultOpConfig = {
90
- before: [] as RequestHandler[],
91
- after: [] as RequestHandler[],
93
+ type OperationConfigLike = {
94
+ before?: RequestHandler[]
95
+ after?: RequestHandler[]
96
+ shape?: Record<string, unknown>
97
+ progressive?: Record<string, ProgressiveVariantConfig>
98
+ progressiveStages?: Record<string, ProgressiveStage<unknown>>
99
+ }
100
+
101
+ type ExtendedRequest = Request & {
102
+ prisma?: unknown
103
+ postgres?: unknown
104
+ sqlite?: unknown
105
+ }
106
+
107
+ type LocalsBag = {
108
+ parsedQuery?: Record<string, unknown>
109
+ routeConfig?: { pagination?: OperationContext['paginationConfig'] }
110
+ guardShape?: Record<string, unknown>
111
+ guardCaller?: string
112
+ data?: unknown
113
+ }
114
+
115
+ const defaultOpConfig: OperationConfigLike = {
116
+ before: [],
117
+ after: [],
92
118
  }
93
119
 
94
120
  function normalizePrefix(p: string): string {
@@ -113,6 +139,10 @@ function getQueryBuilderConfig(config: RouteConfig) {
113
139
  return {}
114
140
  }
115
141
 
142
+ function readLocals(res: Response): LocalsBag {
143
+ return res.locals as LocalsBag
144
+ }
145
+
116
146
  export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteConfig<TCtx> = {}) {
117
147
  const router = express.Router()
118
148
  router.use(express.json())
@@ -130,25 +160,34 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
130
160
  if (qbEnabled) {
131
161
  const qbConfig = getQueryBuilderConfig(config)
132
162
  if (qbConfig) {
133
- try { require('../queryBuilder${ext}').startQueryBuilder(qbConfig) } catch (err) { if (_env.NODE_ENV !== 'production') console.warn('[query-builder]', err) }
163
+ try {
164
+ startQueryBuilder(qbConfig)
165
+ } catch (err) {
166
+ if (_env.NODE_ENV !== 'production') console.warn('[query-builder]', err)
167
+ }
134
168
  }
135
169
  }
136
170
 
137
- const buildContext = (req: Request, res: Response): OperationContext => ({
138
- prisma: (req as any).prisma,
139
- postgres: (req as any).postgres,
140
- sqlite: (req as any).sqlite,
141
- parsedQuery: res.locals.parsedQuery,
142
- body: req.body,
143
- guardShape: res.locals.guardShape,
144
- guardCaller: res.locals.guardCaller,
145
- paginationConfig: res.locals.routeConfig?.pagination,
146
- })
171
+ const buildContext = (req: Request, res: Response): OperationContext => {
172
+ const extReq = req as ExtendedRequest
173
+ const locals = readLocals(res)
174
+ return {
175
+ prisma: extReq.prisma,
176
+ postgres: extReq.postgres,
177
+ sqlite: extReq.sqlite,
178
+ parsedQuery: locals.parsedQuery,
179
+ body: req.body,
180
+ guardShape: locals.guardShape,
181
+ guardCaller: locals.guardCaller,
182
+ paginationConfig: locals.routeConfig?.pagination,
183
+ }
184
+ }
147
185
 
148
186
  const parseQuery: RequestHandler = (req, res, next) => {
149
187
  const rawQuery = req.query
150
188
  if (rawQuery && Object.keys(rawQuery).length > 0) {
151
- res.locals.parsedQuery = parseQueryParams(rawQuery as Record<string, unknown>)
189
+ const parsed = parseQueryParams(rawQuery as Record<string, unknown>) as Record<string, unknown>
190
+ readLocals(res).parsedQuery = parsed
152
191
  }
153
192
  next()
154
193
  }
@@ -157,29 +196,37 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
157
196
  if (!req.body || typeof req.body !== 'object' || Array.isArray(req.body)) {
158
197
  return next({ status: 400, message: 'Request body must be a JSON object' })
159
198
  }
160
- res.locals.parsedQuery = sanitizeKeys(req.body)
199
+ readLocals(res).parsedQuery = sanitizeKeys(req.body as Record<string, unknown>)
161
200
  next()
162
201
  }
163
202
 
164
- const setShape = (opConfig: any): RequestHandler => {
203
+ const setShape = (opConfig: OperationConfigLike): RequestHandler => {
165
204
  return (req, res, next) => {
166
- res.locals.routeConfig = config
167
- const caller = config.guard?.resolveVariant?.(req)
168
- ?? req.get(config.guard?.variantHeader || 'x-api-variant')
169
- ?? undefined
170
- if (caller) res.locals.guardCaller = caller
171
- if (opConfig.shape) res.locals.guardShape = opConfig.shape
205
+ const locals = readLocals(res)
206
+ if (config.pagination) {
207
+ locals.routeConfig = { pagination: config.pagination }
208
+ }
209
+ const headerName = config.guard?.variantHeader || 'x-api-variant'
210
+ const headerValue = req.get(headerName)
211
+ const caller = config.guard?.resolveVariant?.(req) ?? headerValue ?? undefined
212
+ if (caller) locals.guardCaller = caller
213
+ if (opConfig.shape) locals.guardShape = opConfig.shape
172
214
  next()
173
215
  }
174
216
  }
175
217
 
176
- const maybeProgressiveSSE = (opConfig: any, coreFn: (ctx: OperationContext) => Promise<unknown>): RequestHandler => {
218
+ const maybeProgressiveSSE = (
219
+ opConfig: OperationConfigLike,
220
+ coreFn: (ctx: OperationContext) => Promise<unknown>,
221
+ baseOp: string,
222
+ ): RequestHandler => {
177
223
  return async (req, res, next) => {
178
224
  if (res.headersSent || res.writableEnded) return next()
179
225
  if (req.method !== 'GET') return next()
180
226
  if (!acceptsEventStream(req.headers.accept)) return next()
181
227
 
182
- const variant = res.locals.guardCaller as string | undefined
228
+ const locals = readLocals(res)
229
+ const variant = locals.guardCaller
183
230
  const progressiveConfig = variant ? opConfig.progressive?.[variant] : undefined
184
231
 
185
232
  try {
@@ -192,6 +239,38 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
192
239
  return
193
240
  }
194
241
 
242
+ if (progressiveConfig.mode === 'autoInclude') {
243
+ const isSingleRecordRead =
244
+ baseOp === 'findUnique' || baseOp === 'findUniqueOrThrow' ||
245
+ baseOp === 'findFirst' || baseOp === 'findFirstOrThrow'
246
+
247
+ if (!isSingleRecordRead) {
248
+ if (progressiveConfig.fallback === 'error') {
249
+ return next({ status: 400, message: 'autoInclude mode supports only single-record reads' })
250
+ }
251
+ await runSingleResultSSE({
252
+ req,
253
+ res,
254
+ coreQueryFn: () => coreFn(buildContext(req, res)),
255
+ })
256
+ return
257
+ }
258
+
259
+ await runAutoIncludeProgressive({
260
+ req,
261
+ res,
262
+ ctx: buildContext(req, res),
263
+ args: locals.parsedQuery ?? {},
264
+ baseOp: baseOp as 'findUnique' | 'findUniqueOrThrow' | 'findFirst' | 'findFirstOrThrow',
265
+ modelName: '${modelName}',
266
+ delegateKey: '${delegateKey}',
267
+ models: relationModels,
268
+ variantConfig: progressiveConfig,
269
+ coreQueryFn: () => coreFn(buildContext(req, res)),
270
+ })
271
+ return
272
+ }
273
+
195
274
  if (!Array.isArray(progressiveConfig.stages)) {
196
275
  return next({ status: 500, message: 'Progressive endpoint requires stages array' })
197
276
  }
@@ -213,12 +292,13 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
213
292
  req,
214
293
  res,
215
294
  ctx,
216
- prisma: (req as any).prisma,
295
+ prisma: (req as ExtendedRequest).prisma,
217
296
  variant: variant as string,
218
297
  stages: progressiveConfig.stages,
219
298
  stageRegistry,
220
299
  })
221
300
  } catch (err) {
301
+ console.error('[progressive] dispatch error:', err)
222
302
  if (!res.headersSent) {
223
303
  return next({ status: 500, message: 'Internal server error' })
224
304
  }
@@ -227,13 +307,13 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
227
307
  }
228
308
 
229
309
  const respond: RequestHandler = (_req, res) => {
230
- const data = res.locals.data
310
+ const data = readLocals(res).data
231
311
  if (data === undefined) return res.status(500).json({ message: 'No data set by handler' })
232
312
  return res.json(transformResult(data))
233
313
  }
234
314
 
235
315
  const respondCreated: RequestHandler = (_req, res) => {
236
- const data = res.locals.data
316
+ const data = readLocals(res).data
237
317
  if (data === undefined) return res.status(500).json({ message: 'No data set by handler' })
238
318
  return res.status(201).json(transformResult(data))
239
319
  }
@@ -242,76 +322,76 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
242
322
  const openapiJsonPath = basePath ? \`\${basePath}/openapi.json\` : '/openapi.json'
243
323
  const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
244
324
  router.get(openapiJsonPath, (_req, res) => {
245
- const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as any, MODEL_ENUMS as any, config, { format: 'json' })
325
+ const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1], MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2], config, { format: 'json' })
246
326
  res.json(spec)
247
327
  })
248
328
  router.get(openapiYamlPath, (_req, res) => {
249
- const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as any, MODEL_ENUMS as any, config, { format: 'yaml' })
329
+ const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1], MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2], config, { format: 'yaml' })
250
330
  res.type('application/yaml').send(spec as string)
251
331
  })
252
332
  }
253
333
 
254
334
  if (config.enableAll || config.findFirst) {
255
- const opConfig: any = config.findFirst || defaultOpConfig
335
+ const opConfig: OperationConfigLike = (config.findFirst as OperationConfigLike | undefined) ?? defaultOpConfig
256
336
  const { before = [], after = [] } = opConfig
257
337
  const path = basePath ? \`\${basePath}/first\` : '/first'
258
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirst), ${prefix}FindFirst as RequestHandler, ...after, respond)
338
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirst, 'findFirst'), ${prefix}FindFirst as RequestHandler, ...after, respond)
259
339
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirst as RequestHandler, ...after, respond)
260
340
  }
261
341
  if (config.enableAll || config.findFirstOrThrow) {
262
- const opConfig: any = config.findFirstOrThrow || defaultOpConfig
342
+ const opConfig: OperationConfigLike = (config.findFirstOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
263
343
  const { before = [], after = [] } = opConfig
264
344
  const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
265
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirstOrThrow), ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
345
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirstOrThrow, 'findFirstOrThrow'), ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
266
346
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
267
347
  }
268
348
  if (config.enableAll || config.findManyPaginated) {
269
- const opConfig: any = config.findManyPaginated || defaultOpConfig
349
+ const opConfig: OperationConfigLike = (config.findManyPaginated as OperationConfigLike | undefined) ?? defaultOpConfig
270
350
  const { before = [], after = [] } = opConfig
271
351
  const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
272
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findManyPaginated), ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
352
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findManyPaginated, 'findManyPaginated'), ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
273
353
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
274
354
  }
275
355
  if (config.enableAll || config.aggregate) {
276
- const opConfig: any = config.aggregate || defaultOpConfig
356
+ const opConfig: OperationConfigLike = (config.aggregate as OperationConfigLike | undefined) ?? defaultOpConfig
277
357
  const { before = [], after = [] } = opConfig
278
358
  const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
279
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.aggregate), ${prefix}Aggregate as RequestHandler, ...after, respond)
359
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.aggregate, 'aggregate'), ${prefix}Aggregate as RequestHandler, ...after, respond)
280
360
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Aggregate as RequestHandler, ...after, respond)
281
361
  }
282
362
  if (config.enableAll || config.count) {
283
- const opConfig: any = config.count || defaultOpConfig
363
+ const opConfig: OperationConfigLike = (config.count as OperationConfigLike | undefined) ?? defaultOpConfig
284
364
  const { before = [], after = [] } = opConfig
285
365
  const path = basePath ? \`\${basePath}/count\` : '/count'
286
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.count), ${prefix}Count as RequestHandler, ...after, respond)
366
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.count, 'count'), ${prefix}Count as RequestHandler, ...after, respond)
287
367
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Count as RequestHandler, ...after, respond)
288
368
  }
289
369
  if (config.enableAll || config.groupBy) {
290
- const opConfig: any = config.groupBy || defaultOpConfig
370
+ const opConfig: OperationConfigLike = (config.groupBy as OperationConfigLike | undefined) ?? defaultOpConfig
291
371
  const { before = [], after = [] } = opConfig
292
372
  const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
293
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.groupBy), ${prefix}GroupBy as RequestHandler, ...after, respond)
373
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.groupBy, 'groupBy'), ${prefix}GroupBy as RequestHandler, ...after, respond)
294
374
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}GroupBy as RequestHandler, ...after, respond)
295
375
  }
296
376
  if (config.enableAll || config.findUniqueOrThrow) {
297
- const opConfig: any = config.findUniqueOrThrow || defaultOpConfig
377
+ const opConfig: OperationConfigLike = (config.findUniqueOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
298
378
  const { before = [], after = [] } = opConfig
299
379
  const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
300
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUniqueOrThrow), ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
380
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUniqueOrThrow, 'findUniqueOrThrow'), ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
301
381
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
302
382
  }
303
383
  if (config.enableAll || config.findUnique) {
304
- const opConfig: any = config.findUnique || defaultOpConfig
384
+ const opConfig: OperationConfigLike = (config.findUnique as OperationConfigLike | undefined) ?? defaultOpConfig
305
385
  const { before = [], after = [] } = opConfig
306
386
  const path = basePath ? \`\${basePath}/unique\` : '/unique'
307
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUnique), ${prefix}FindUnique as RequestHandler, ...after, respond)
387
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUnique, 'findUnique'), ${prefix}FindUnique as RequestHandler, ...after, respond)
308
388
  if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUnique as RequestHandler, ...after, respond)
309
389
  }
310
390
  if (config.enableAll || config.findMany) {
311
- const opConfig: any = config.findMany || defaultOpConfig
391
+ const opConfig: OperationConfigLike = (config.findMany as OperationConfigLike | undefined) ?? defaultOpConfig
312
392
  const { before = [], after = [] } = opConfig
313
393
  const path = basePath || '/'
314
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findMany), ${prefix}FindMany as RequestHandler, ...after, respond)
394
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findMany, 'findMany'), ${prefix}FindMany as RequestHandler, ...after, respond)
315
395
  if (postReadsEnabled) {
316
396
  const postPath = basePath ? \`\${basePath}/read\` : '/read'
317
397
  router.post(postPath, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindMany as RequestHandler, ...after, respond)
@@ -319,63 +399,64 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
319
399
  }
320
400
 
321
401
  if (config.enableAll || config.createManyAndReturn) {
322
- const opConfig: any = config.createManyAndReturn || defaultOpConfig
402
+ const opConfig: OperationConfigLike = (config.createManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
323
403
  const { before = [], after = [] } = opConfig
324
404
  const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
325
405
  router.post(path, setShape(opConfig), ...before, ${prefix}CreateManyAndReturn as RequestHandler, ...after, respondCreated)
326
406
  }
327
407
  if (config.enableAll || config.createMany) {
328
- const opConfig: any = config.createMany || defaultOpConfig
408
+ const opConfig: OperationConfigLike = (config.createMany as OperationConfigLike | undefined) ?? defaultOpConfig
329
409
  const { before = [], after = [] } = opConfig
330
410
  const path = basePath ? \`\${basePath}/many\` : '/many'
331
411
  router.post(path, setShape(opConfig), ...before, ${prefix}CreateMany as RequestHandler, ...after, respondCreated)
332
412
  }
333
413
  if (config.enableAll || config.create) {
334
- const opConfig: any = config.create || defaultOpConfig
414
+ const opConfig: OperationConfigLike = (config.create as OperationConfigLike | undefined) ?? defaultOpConfig
335
415
  const { before = [], after = [] } = opConfig
336
416
  const path = basePath || '/'
337
417
  router.post(path, setShape(opConfig), ...before, ${prefix}Create as RequestHandler, ...after, respondCreated)
338
418
  }
339
419
  if (config.enableAll || config.updateManyAndReturn) {
340
- const opConfig: any = config.updateManyAndReturn || defaultOpConfig
420
+ const opConfig: OperationConfigLike = (config.updateManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
341
421
  const { before = [], after = [] } = opConfig
342
422
  const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
343
423
  router.put(path, setShape(opConfig), ...before, ${prefix}UpdateManyAndReturn as RequestHandler, ...after, respond)
344
424
  }
345
425
  if (config.enableAll || config.updateMany) {
346
- const opConfig: any = config.updateMany || defaultOpConfig
426
+ const opConfig: OperationConfigLike = (config.updateMany as OperationConfigLike | undefined) ?? defaultOpConfig
347
427
  const { before = [], after = [] } = opConfig
348
428
  const path = basePath ? \`\${basePath}/many\` : '/many'
349
429
  router.put(path, setShape(opConfig), ...before, ${prefix}UpdateMany as RequestHandler, ...after, respond)
350
430
  }
351
431
  if (config.enableAll || config.update) {
352
- const opConfig: any = config.update || defaultOpConfig
432
+ const opConfig: OperationConfigLike = (config.update as OperationConfigLike | undefined) ?? defaultOpConfig
353
433
  const { before = [], after = [] } = opConfig
354
434
  const path = basePath || '/'
355
435
  router.put(path, setShape(opConfig), ...before, ${prefix}Update as RequestHandler, ...after, respond)
356
436
  }
357
437
  if (config.enableAll || config.upsert) {
358
- const opConfig: any = config.upsert || defaultOpConfig
438
+ const opConfig: OperationConfigLike = (config.upsert as OperationConfigLike | undefined) ?? defaultOpConfig
359
439
  const { before = [], after = [] } = opConfig
360
440
  const path = basePath || '/'
361
441
  router.patch(path, setShape(opConfig), ...before, ${prefix}Upsert as RequestHandler, ...after, respond)
362
442
  }
363
443
  if (config.enableAll || config.deleteMany) {
364
- const opConfig: any = config.deleteMany || defaultOpConfig
444
+ const opConfig: OperationConfigLike = (config.deleteMany as OperationConfigLike | undefined) ?? defaultOpConfig
365
445
  const { before = [], after = [] } = opConfig
366
446
  const path = basePath ? \`\${basePath}/many\` : '/many'
367
447
  router.delete(path, setShape(opConfig), ...before, ${prefix}DeleteMany as RequestHandler, ...after, respond)
368
448
  }
369
449
  if (config.enableAll || config.delete) {
370
- const opConfig: any = config.delete || defaultOpConfig
450
+ const opConfig: OperationConfigLike = (config.delete as OperationConfigLike | undefined) ?? defaultOpConfig
371
451
  const { before = [], after = [] } = opConfig
372
452
  const path = basePath || '/'
373
453
  router.delete(path, setShape(opConfig), ...before, ${prefix}Delete as RequestHandler, ...after, respond)
374
454
  }
375
455
 
376
- router.use((err: any, _req: Request, res: Response, next: NextFunction) => {
377
- const status = typeof err.status === 'number' ? err.status : 500
378
- const message = err.message || 'Internal server error'
456
+ router.use((err: unknown, _req: Request, res: Response, next: NextFunction) => {
457
+ const e = err as { status?: number; message?: string }
458
+ const status = typeof e.status === 'number' ? e.status : 500
459
+ const message = e.message || 'Internal server error'
379
460
  if (!res.headersSent) return res.status(status).json({ message })
380
461
  next(err)
381
462
  })