prisma-generator-express 1.66.0 → 1.68.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 (130) hide show
  1. package/README.md +188 -3432
  2. package/dist/client/encodeQueryParams.js +3 -1
  3. package/dist/client/encodeQueryParams.js.map +1 -1
  4. package/dist/copy/misc.d.ts +1 -0
  5. package/dist/copy/misc.js +14 -0
  6. package/dist/copy/misc.js.map +1 -1
  7. package/dist/copy/operationDefinitions.d.ts +4 -1
  8. package/dist/copy/operationDefinitions.js +133 -9
  9. package/dist/copy/operationDefinitions.js.map +1 -1
  10. package/dist/generators/generateFastifyHandler.d.ts +2 -2
  11. package/dist/generators/generateFastifyHandler.js +68 -12
  12. package/dist/generators/generateFastifyHandler.js.map +1 -1
  13. package/dist/generators/generateHonoHandler.d.ts +2 -2
  14. package/dist/generators/generateHonoHandler.js +53 -6
  15. package/dist/generators/generateHonoHandler.js.map +1 -1
  16. package/dist/generators/generateHonoOpenApi.d.ts +13 -0
  17. package/dist/generators/generateHonoOpenApi.js +70 -0
  18. package/dist/generators/generateHonoOpenApi.js.map +1 -0
  19. package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
  20. package/dist/generators/generateImportPrismaStatement.js +6 -0
  21. package/dist/generators/generateImportPrismaStatement.js.map +1 -1
  22. package/dist/generators/generateMcpApp.d.ts +10 -0
  23. package/dist/generators/generateMcpApp.js +113 -0
  24. package/dist/generators/generateMcpApp.js.map +1 -0
  25. package/dist/generators/generateModelMcp.d.ts +9 -0
  26. package/dist/generators/generateModelMcp.js +145 -0
  27. package/dist/generators/generateModelMcp.js.map +1 -0
  28. package/dist/generators/generateModelMetadata.js +29 -15
  29. package/dist/generators/generateModelMetadata.js.map +1 -1
  30. package/dist/generators/generateOperationCore.d.ts +3 -3
  31. package/dist/generators/generateOperationCore.js +51 -16
  32. package/dist/generators/generateOperationCore.js.map +1 -1
  33. package/dist/generators/generateRelationMeta.js +2 -2
  34. package/dist/generators/generateRelationMeta.js.map +1 -1
  35. package/dist/generators/generateRouteConfigType.d.ts +2 -2
  36. package/dist/generators/generateRouteConfigType.js +29 -11
  37. package/dist/generators/generateRouteConfigType.js.map +1 -1
  38. package/dist/generators/generateRouter.d.ts +7 -4
  39. package/dist/generators/generateRouter.js +164 -65
  40. package/dist/generators/generateRouter.js.map +1 -1
  41. package/dist/generators/generateRouterFastify.d.ts +7 -4
  42. package/dist/generators/generateRouterFastify.js +106 -86
  43. package/dist/generators/generateRouterFastify.js.map +1 -1
  44. package/dist/generators/generateRouterHono.d.ts +7 -4
  45. package/dist/generators/generateRouterHono.js +59 -414
  46. package/dist/generators/generateRouterHono.js.map +1 -1
  47. package/dist/generators/generateRouterPartsHono.d.ts +14 -0
  48. package/dist/generators/generateRouterPartsHono.js +180 -0
  49. package/dist/generators/generateRouterPartsHono.js.map +1 -0
  50. package/dist/generators/generateUnifiedDocs.d.ts +1 -1
  51. package/dist/generators/generateUnifiedDocs.js +15 -8
  52. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  53. package/dist/generators/generateUnifiedHandler.d.ts +2 -2
  54. package/dist/generators/generateUnifiedHandler.js +42 -18
  55. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  56. package/dist/guardOptions.js +12 -7
  57. package/dist/guardOptions.js.map +1 -1
  58. package/dist/index.d.ts +3 -1
  59. package/dist/index.js +123 -4
  60. package/dist/index.js.map +1 -1
  61. package/dist/utils/copyFiles.d.ts +1 -1
  62. package/dist/utils/copyFiles.js +42 -7
  63. package/dist/utils/copyFiles.js.map +1 -1
  64. package/dist/utils/importExt.d.ts +1 -1
  65. package/dist/utils/mcpGate.d.ts +10 -0
  66. package/dist/utils/mcpGate.js +118 -0
  67. package/dist/utils/mcpGate.js.map +1 -0
  68. package/dist/utils/pathCasing.d.ts +4 -0
  69. package/dist/utils/pathCasing.js +40 -0
  70. package/dist/utils/pathCasing.js.map +1 -0
  71. package/dist/utils/resolveImportStyle.js +13 -5
  72. package/dist/utils/resolveImportStyle.js.map +1 -1
  73. package/dist/utils/writeFileSafely.js +6 -0
  74. package/dist/utils/writeFileSafely.js.map +1 -1
  75. package/package.json +22 -5
  76. package/src/bin.ts +1 -1
  77. package/src/client/encodeQueryParams.ts +39 -35
  78. package/src/constants.ts +1 -1
  79. package/src/copy/autoIncludePlanner.ts +93 -27
  80. package/src/copy/autoIncludePlannerGuarded.ts +171 -48
  81. package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
  82. package/src/copy/buildModelOpenApi.ts +229 -176
  83. package/src/copy/concurrency.ts +10 -8
  84. package/src/copy/docsRenderer.ts +14 -15
  85. package/src/copy/errorMapper.ts +68 -19
  86. package/src/copy/guardHelpers.ts +30 -9
  87. package/src/copy/materializedCount.ts +17 -5
  88. package/src/copy/mcpRuntime.ts +1017 -0
  89. package/src/copy/misc.ts +88 -68
  90. package/src/copy/ndjson.ts +72 -0
  91. package/src/copy/operationDefinitions.ts +177 -25
  92. package/src/copy/operationPipeline.ts +267 -0
  93. package/src/copy/operationRuntime.ts +124 -26
  94. package/src/copy/operationSchemas.ts +2773 -0
  95. package/src/copy/pagination.ts +35 -13
  96. package/src/copy/parseQueryParams.ts +47 -48
  97. package/src/copy/projectionDefaults.ts +6 -4
  98. package/src/copy/routeConfig.express.ts +16 -4
  99. package/src/copy/routeConfig.fastify.ts +16 -2
  100. package/src/copy/routeConfig.hono.ts +46 -14
  101. package/src/copy/routeConfig.ts +175 -40
  102. package/src/copy/routerParts.ts +524 -0
  103. package/src/copy/scalarTypes.ts +7 -2
  104. package/src/copy/sse.ts +72 -19
  105. package/src/generators/generateFastifyHandler.ts +77 -20
  106. package/src/generators/generateHonoHandler.ts +62 -14
  107. package/src/generators/generateHonoOpenApi.ts +93 -0
  108. package/src/generators/generateImportPrismaStatement.ts +93 -81
  109. package/src/generators/generateMcpApp.ts +133 -0
  110. package/src/generators/generateModelMcp.ts +208 -0
  111. package/src/generators/generateModelMetadata.ts +40 -22
  112. package/src/generators/generateOperationCore.ts +81 -33
  113. package/src/generators/generateRelationMeta.ts +23 -11
  114. package/src/generators/generateRouteConfigType.ts +39 -13
  115. package/src/generators/generateRouter.ts +171 -68
  116. package/src/generators/generateRouterFastify.ts +117 -89
  117. package/src/generators/generateRouterHono.ts +84 -464
  118. package/src/generators/generateRouterPartsHono.ts +220 -0
  119. package/src/generators/generateUnifiedDocs.ts +29 -8
  120. package/src/generators/generateUnifiedHandler.ts +47 -24
  121. package/src/generators/generateUnifiedScalarUI.ts +1 -1
  122. package/src/guardOptions.ts +105 -92
  123. package/src/index.ts +161 -6
  124. package/src/utils/copyFiles.ts +235 -168
  125. package/src/utils/importExt.ts +2 -2
  126. package/src/utils/mcpGate.ts +157 -0
  127. package/src/utils/pathCasing.ts +42 -0
  128. package/src/utils/resolveImportStyle.ts +37 -15
  129. package/src/utils/strings.ts +2 -2
  130. package/src/utils/writeFileSafely.ts +12 -2
@@ -1,8 +1,9 @@
1
- import { DMMF } from '@prisma/generator-helper'
1
+ import type { DMMF } from '@prisma/generator-helper'
2
2
  import { generateRouteConfigType } from './generateRouteConfigType'
3
- import { ImportStyle } from '../utils/resolveImportStyle'
3
+ import type { ImportStyle } from '../utils/resolveImportStyle'
4
4
  import { importExt } from '../utils/importExt'
5
- import { WriteStrategy, FindManyPaginatedMode } from '../constants'
5
+ import type { WriteStrategy, FindManyPaginatedMode } from '../constants'
6
+ import { modelPathSegment, type PathCase } from '../utils/pathCasing'
6
7
  import { OPERATION_METADATA } from '../copy/operationDefinitions'
7
8
 
8
9
  function pathExpr(suffix: string): string {
@@ -55,11 +56,11 @@ function emitReadOp(
55
56
 
56
57
  const postReadLine = meta.supportsPostRead
57
58
  ? meta.name === 'findMany'
58
- ? ` if (postReadsEnabled) {
59
+ ? ` if (resolvePostReadsEnabled(config.disablePostReads, opConfig.disablePostReads)) {
59
60
  const postPath = basePath ? \`\${basePath}/read\` : '/read'
60
61
  instance.post(postPath, handleRead(opConfig, ${handlerName}, parseBodyAsQueryHook, '${opKind}'))
61
62
  }`
62
- : ` if (postReadsEnabled) instance.post(path, handleRead(opConfig, ${handlerName}, parseBodyAsQueryHook, '${opKind}'))`
63
+ : ` if (resolvePostReadsEnabled(config.disablePostReads, opConfig.disablePostReads)) instance.post(path, handleRead(opConfig, ${handlerName}, parseBodyAsQueryHook, '${opKind}'))`
63
64
  : ''
64
65
 
65
66
  return ` if (isEnabled(config.${meta.configKey})) {
@@ -90,34 +91,41 @@ export function generateFastifyRouterFunction({
90
91
  model,
91
92
  enums,
92
93
  guardShapesImport,
94
+ clientImport,
93
95
  importStyle,
94
96
  writeStrategy,
95
97
  findManyPaginatedMode,
96
98
  dropGuard,
99
+ pathCase,
97
100
  }: {
98
101
  model: DMMF.Model
99
102
  enums: DMMF.DatamodelEnum[]
100
103
  guardShapesImport: string | null
104
+ clientImport?: string
101
105
  importStyle: ImportStyle
102
106
  writeStrategy: WriteStrategy
103
107
  findManyPaginatedMode: FindManyPaginatedMode
104
108
  dropGuard: boolean
109
+ pathCase: PathCase
105
110
  }): string {
106
111
  const ext = importExt(importStyle)
107
112
  const modelName = model.name
108
- const modelNameLower = modelName.toLowerCase()
109
- const routerFunctionName = `${modelName}Router`
113
+ const modelSegment = modelPathSegment(model.name, pathCase)
114
+ const routerFunctionName = `${model.name}Router`
110
115
 
111
- const handlerImports = OPERATION_METADATA
112
- .map((m) => ` ${modelName}${m.name.charAt(0).toUpperCase() + m.name.slice(1)},`)
113
- .join('\n')
116
+ const handlerImports = OPERATION_METADATA.map(
117
+ (m) => ` ${modelName}${m.name.charAt(0).toUpperCase() + m.name.slice(1)},`,
118
+ ).join('\n')
114
119
 
115
120
  const readOps = OPERATION_METADATA.filter((m) => m.kind === 'read')
116
- const writeOps = OPERATION_METADATA.filter((m) => m.kind === 'write' || m.kind === 'batch')
117
- .filter((m) => m.name !== 'updateEach')
121
+ const writeOps = OPERATION_METADATA.filter(
122
+ (m) => m.kind === 'write' || m.kind === 'batch',
123
+ ).filter((m) => m.name !== 'updateEach')
118
124
 
119
125
  const readOpBlocks = readOps.map((m) => emitReadOp(m, modelName)).join('\n\n')
120
- const writeOpBlocks = writeOps.map((m) => emitWriteOp(m, modelName)).join('\n\n')
126
+ const writeOpBlocks = writeOps
127
+ .map((m) => emitWriteOp(m, modelName))
128
+ .join('\n\n')
121
129
 
122
130
  return `import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyError } from 'fastify'
123
131
  import { startQueryBuilder } from '../queryBuilder${ext}'
@@ -129,35 +137,49 @@ import type {
129
137
  FastifyHookHandler,
130
138
  FindManyPaginatedMode,
131
139
  PaginationConfig,
140
+ PrismaClientLike,
141
+ QueryBuilderConfig,
132
142
  } from '../routeConfig.target${ext}'
133
143
  import { parseQueryParams } from '../parseQueryParams${ext}'
134
- import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject } from '../misc${ext}'
144
+ import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject, resolveDropGuardEnv } from '../misc${ext}'
135
145
  import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
136
146
  import {
137
147
  normalizeOperation,
138
- resolveOperationVariantKey,
139
148
  validateCountSourceWhere,
140
149
  validateOperationConfig,
141
150
  validateUpdateEachConfig,
151
+ resolvePostReadsEnabled,
152
+ warnIfUnguardedRoutes,
142
153
  } from '../routeConfig${ext}'
154
+ import type { RuntimeOperationOverride } from '../operationRuntime${ext}'
143
155
  import type { NormalizedOperationConfig } from '../routeConfig${ext}'
144
156
  import type { OperationContext } from '../operationRuntime${ext}'
145
157
  import { transformResult } from '../operationRuntime${ext}'
146
158
  import { HttpError, mapError } from '../errorMapper${ext}'
147
- import { formatGuardVariantResolutionError } from '../guardVariantError${ext}'
148
- import type { GuardVariantResolution } from '../guardVariantRouting${ext}'
149
159
  import { mergePaginationConfig } from '../pagination${ext}'
150
- import { applyDroppedGuard } from '../projectionDefaults${ext}'
160
+ import {
161
+ routeOperation,
162
+ prepareGuardOperation,
163
+ settleStage,
164
+ classifyError,
165
+ memoizeContext,
166
+ type ArgsChannel,
167
+ } from '../operationPipeline${ext}'
151
168
  import type { OpKind } from '../projectionDefaults${ext}'
152
169
  import { MODEL_FIELDS, MODEL_ENUMS } from './${modelName}Metadata${ext}'
153
170
 
154
- ${generateRouteConfigType(modelName, 'FastifyHookHandler', guardShapesImport, importStyle, 'fastify')}
171
+ ${generateRouteConfigType(modelName, 'FastifyHookHandler', guardShapesImport, importStyle, 'fastify', clientImport)}
155
172
  const _env = getEnv()
156
173
 
157
174
  const FIND_MANY_PAGINATED_MODE: FindManyPaginatedMode = '${findManyPaginatedMode}'
158
- const DROP_GUARD = ${dropGuard} || _env.E2E === 'true'
175
+ // Fixed at generation time. The environment bypass is resolved per hook,
176
+ // because it requires the configuration's explicit \`allowE2EGuardBypass: true\`:
177
+ // false or omitted means the environment cannot drop guards for this target.
178
+ const DROP_GUARD = ${dropGuard}
159
179
 
160
180
  type OperationConfigLike = {
181
+ authorize?: FastifyHookHandler
182
+ override?: RuntimeOperationOverride
161
183
  before?: FastifyHookHandler[]
162
184
  after?: FastifyHookHandler[]
163
185
  shape?: unknown
@@ -185,26 +207,51 @@ type FastifyExtended = FastifyRequest & {
185
207
  routeConfig?: { pagination?: PaginationConfig }
186
208
  guardShape?: Record<string, unknown>
187
209
  guardCaller?: string
210
+ operationOverride?: RuntimeOperationOverride
211
+ getContext?: () => Promise<unknown>
188
212
  guardVariantKey?: string
189
- guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
213
+ routeFailure?: { ok: false; failure: HttpError }
214
+ guardFailure?: { ok: false; failure: HttpError }
190
215
  resultData?: unknown
191
216
  resultStatus?: number
192
217
  }
193
218
 
219
+ function queryChannel(request: FastifyRequest): ArgsChannel {
220
+ const fx = request as FastifyExtended
221
+ return {
222
+ read: () => fx.parsedQuery,
223
+ write: (next) => {
224
+ fx.parsedQuery = next
225
+ },
226
+ }
227
+ }
228
+
229
+ function bodyChannel(request: FastifyRequest): ArgsChannel {
230
+ return {
231
+ read: () =>
232
+ isPlainObject(request.body)
233
+ ? (request.body as Record<string, unknown>)
234
+ : undefined,
235
+ write: (next) => {
236
+ ;(request as unknown as { body: unknown }).body = next
237
+ },
238
+ }
239
+ }
240
+
194
241
  function normalizeFastifyOperation(
195
242
  config: OperationConfigLike | undefined,
196
243
  ): NormalizedOp {
197
244
  return normalizeOperation<FastifyHookHandler, FastifyHookHandler>(config)
198
245
  }
199
246
 
200
- function isQueryBuilderEnabled(config: RouteConfig): boolean {
247
+ function isQueryBuilderEnabled(config: { queryBuilder?: QueryBuilderConfig | false }): boolean {
201
248
  if (config.queryBuilder === false) return false
202
249
  if (typeof config.queryBuilder === 'object' && config.queryBuilder.enabled === false) return false
203
250
  if (_env.NODE_ENV === 'production') return false
204
251
  return true
205
252
  }
206
253
 
207
- function getQueryBuilderConfig(config: RouteConfig) {
254
+ function getQueryBuilderConfig(config: { queryBuilder?: QueryBuilderConfig | false }) {
208
255
  if (config.queryBuilder === false) return null
209
256
  if (typeof config.queryBuilder === 'object') return config.queryBuilder
210
257
  return {}
@@ -225,21 +272,26 @@ function parseBodyAsQueryHook(request: FastifyRequest): void {
225
272
  (request as FastifyExtended).parsedQuery = sanitizeKeys(body as Record<string, unknown>)
226
273
  }
227
274
 
228
- function buildResolveContext(
229
- config: ${modelName}RouteConfig,
230
- request: FastifyRequest,
231
- ): (() => unknown | Promise<unknown>) | undefined {
232
- if (typeof config.resolveContext !== 'function') return undefined
233
- return () => (config.resolveContext as (r: FastifyRequest) => unknown | Promise<unknown>)(request)
234
- }
235
-
236
- function makeShapeHook(
237
- config: ${modelName}RouteConfig,
275
+ function makeShapeHook<TCtx, TPrisma extends PrismaClientLike>(
276
+ config: ${modelName}RouteConfig<TCtx, TPrisma>,
238
277
  opConfig: NormalizedOp,
239
278
  opKind: OpKind,
240
279
  ): (request: FastifyRequest) => Promise<void> {
280
+ /**
281
+ * The environment bypass, and it is OPT-IN for this target.
282
+ *
283
+ * \`PGE_DROP_GUARD=true\` (deprecated alias \`E2E=true\`) downgrading enforcement
284
+ * in a deployed environment is a real hazard: on most platforms it is an
285
+ * ordinary config var, set on staging, copied forward, flagged as
286
+ * security-relevant nowhere. It is honoured only when this configuration
287
+ * states \`allowE2EGuardBypass: true\` — false or omitted means the environment
288
+ * cannot drop guards. The generation-time \`DROP_GUARD\` literal is unchanged.
289
+ */
290
+ const dropGuard = DROP_GUARD || (config.allowE2EGuardBypass === true && resolveDropGuardEnv(_env))
241
291
  return async (request: FastifyRequest) => {
242
292
  const fx = request as FastifyExtended
293
+ fx.operationOverride = opConfig.override
294
+ fx.getContext = memoizeContext(() => config.resolveContext?.(request))
243
295
  const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
244
296
  if (merged) fx.routeConfig = { pagination: merged }
245
297
 
@@ -250,46 +302,28 @@ function makeShapeHook(
250
302
  ?? undefined
251
303
  if (typeof caller === 'string') fx.guardCaller = caller
252
304
 
253
- const resolution = resolveOperationVariantKey(opConfig.guardRouting, caller)
254
- if (!resolution.ok) {
255
- fx.guardVariantFailure = resolution
305
+ const routed = routeOperation({ guardRouting: opConfig.guardRouting, caller })
306
+ if (!routed.ok) {
307
+ fx.routeFailure = routed
256
308
  return
257
309
  }
258
310
 
259
- const resolvedKey =
260
- opConfig.guardRouting.kind === 'named'
261
- ? resolution.key
262
- : undefined
263
- if (resolvedKey !== undefined) fx.guardVariantKey = resolvedKey
264
-
265
- if (opConfig.guardShape) {
266
- if (!DROP_GUARD) {
267
- fx.guardShape = opConfig.guardShape
268
- } else {
269
- await applyDroppedGuard(
270
- opConfig.guardShape,
271
- resolvedKey,
272
- buildResolveContext(config, request),
273
- opKind,
274
- {
275
- readQuery: fx.parsedQuery,
276
- writeBody: isPlainObject(request.body)
277
- ? (request.body as Record<string, unknown>)
278
- : undefined,
279
- },
280
- () => {
281
- if (!fx.parsedQuery) fx.parsedQuery = {}
282
- return fx.parsedQuery
283
- },
284
- () => {
285
- if (!isPlainObject(request.body)) {
286
- ;(request as unknown as { body: unknown }).body = {}
287
- }
288
- return request.body as Record<string, unknown>
289
- },
290
- )
291
- }
311
+ if (routed.variantKey !== undefined) fx.guardVariantKey = routed.variantKey
312
+
313
+ const guard = await prepareGuardOperation(routed, {
314
+ guardShape: opConfig.guardShape,
315
+ opKind,
316
+ policy: { dropGuard, validateResolvedShapes: false },
317
+ getContext: typeof config.resolveContext === 'function' ? fx.getContext : undefined,
318
+ args: queryChannel(request),
319
+ writeArgs: bodyChannel(request),
320
+ })
321
+ if (!guard.ok) {
322
+ fx.guardFailure = guard
323
+ return
292
324
  }
325
+
326
+ fx.guardShape = guard.guardShape
293
327
  }
294
328
  }
295
329
 
@@ -322,7 +356,7 @@ function sendError(reply: FastifyReply, error: unknown): void {
322
356
  reply.code(httpError.status).send({ message: httpError.message })
323
357
  }
324
358
 
325
- export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
359
+ export async function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClientLike = PrismaClientLike>(
326
360
  fastify: FastifyInstance,
327
361
  config: ${modelName}RouteConfig<TCtx, TPrisma> = {},
328
362
  ) {
@@ -334,6 +368,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
334
368
 
335
369
  await fastify.register(async (instance) => {
336
370
  const isEnabled = (value: unknown): boolean => value !== false && !!(config.enableAll || value)
371
+ warnIfUnguardedRoutes('${modelName}', ['findMany', 'findUnique', 'findUniqueOrThrow', 'findFirst', 'findFirstOrThrow', 'findManyPaginated', 'count', 'aggregate', 'groupBy', 'create', 'createMany', 'createManyAndReturn', 'update', 'updateMany', 'updateManyAndReturn', 'upsert', 'delete', 'deleteMany'], config, isEnabled)
337
372
 
338
373
  const opFor = (key: string): NormalizedOp => {
339
374
  const raw = (config as unknown as Record<string, unknown>)[key] as OperationConfigLike | undefined
@@ -342,7 +377,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
342
377
  }
343
378
 
344
379
  const customPrefix = normalizePrefix(config.customUrlPrefix || '')
345
- const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
380
+ const modelPrefix = config.addModelPrefix !== false ? '/${modelSegment}' : ''
346
381
  const basePath = customPrefix + modelPrefix
347
382
 
348
383
  const openApiDisabled = config.disableOpenApi === true
@@ -351,7 +386,6 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
351
386
  || _env.DISABLE_OPENAPI === 'true'
352
387
  ))
353
388
 
354
- const postReadsEnabled = !config.disablePostReads
355
389
 
356
390
  let _openApiJsonCache: unknown = undefined
357
391
  const getOpenApiJson = (): unknown => {
@@ -360,8 +394,8 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
360
394
  '${modelName}',
361
395
  MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
362
396
  MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
363
- config,
364
- { format: 'json', writeStrategy: '${writeStrategy}' },
397
+ config as unknown as Parameters<typeof buildModelOpenApi>[3],
398
+ { format: 'json', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
365
399
  )
366
400
  }
367
401
  return _openApiJsonCache
@@ -373,8 +407,8 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
373
407
  '${modelName}',
374
408
  MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
375
409
  MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
376
- config,
377
- { format: 'yaml', writeStrategy: '${writeStrategy}' },
410
+ config as unknown as Parameters<typeof buildModelOpenApi>[3],
411
+ { format: 'yaml', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
378
412
  ) as string
379
413
  }
380
414
  return _openApiYamlCache
@@ -424,17 +458,14 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
424
458
  opKind: OpKind,
425
459
  ) => async (request: FastifyRequest, reply: FastifyReply) => {
426
460
  try {
461
+ if (await runHooks(opConfig.authorize ? [opConfig.authorize] : [], request, reply)) return
427
462
  parseFn(request)
428
463
  await makeShapeHook(config, opConfig, opKind)(request)
429
464
  if (await runHooks(opConfig.operationBefore, request, reply)) return
430
465
 
431
466
  const fx = request as FastifyExtended
432
- if (fx.guardVariantFailure) {
433
- throw new HttpError(
434
- 400,
435
- formatGuardVariantResolutionError(fx.guardVariantFailure),
436
- )
437
- }
467
+ if (fx.routeFailure) settleStage(fx.routeFailure)
468
+ if (fx.guardFailure) settleStage(fx.guardFailure)
438
469
 
439
470
  const key = fx.guardVariantKey
440
471
  const variantHooks =
@@ -456,16 +487,13 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
456
487
  opKind: OpKind,
457
488
  ) => async (request: FastifyRequest, reply: FastifyReply) => {
458
489
  try {
490
+ if (await runHooks(opConfig.authorize ? [opConfig.authorize] : [], request, reply)) return
459
491
  await makeShapeHook(config, opConfig, opKind)(request)
460
492
  if (await runHooks(opConfig.operationBefore, request, reply)) return
461
493
 
462
494
  const fx = request as FastifyExtended
463
- if (fx.guardVariantFailure) {
464
- throw new HttpError(
465
- 400,
466
- formatGuardVariantResolutionError(fx.guardVariantFailure),
467
- )
468
- }
495
+ if (fx.routeFailure) settleStage(fx.routeFailure)
496
+ if (fx.guardFailure) settleStage(fx.guardFailure)
469
497
 
470
498
  const key = fx.guardVariantKey
471
499
  const variantHooks =
@@ -514,4 +542,4 @@ ${writeOpBlocks}
514
542
  })
515
543
  }
516
544
  `
517
- }
545
+ }