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.
- package/README.md +188 -3432
- package/dist/client/encodeQueryParams.js +3 -1
- package/dist/client/encodeQueryParams.js.map +1 -1
- package/dist/copy/misc.d.ts +1 -0
- package/dist/copy/misc.js +14 -0
- package/dist/copy/misc.js.map +1 -1
- package/dist/copy/operationDefinitions.d.ts +4 -1
- package/dist/copy/operationDefinitions.js +133 -9
- package/dist/copy/operationDefinitions.js.map +1 -1
- package/dist/generators/generateFastifyHandler.d.ts +2 -2
- package/dist/generators/generateFastifyHandler.js +68 -12
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.d.ts +2 -2
- package/dist/generators/generateHonoHandler.js +53 -6
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateHonoOpenApi.d.ts +13 -0
- package/dist/generators/generateHonoOpenApi.js +70 -0
- package/dist/generators/generateHonoOpenApi.js.map +1 -0
- package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
- package/dist/generators/generateImportPrismaStatement.js +6 -0
- package/dist/generators/generateImportPrismaStatement.js.map +1 -1
- package/dist/generators/generateMcpApp.d.ts +10 -0
- package/dist/generators/generateMcpApp.js +113 -0
- package/dist/generators/generateMcpApp.js.map +1 -0
- package/dist/generators/generateModelMcp.d.ts +9 -0
- package/dist/generators/generateModelMcp.js +145 -0
- package/dist/generators/generateModelMcp.js.map +1 -0
- package/dist/generators/generateModelMetadata.js +29 -15
- package/dist/generators/generateModelMetadata.js.map +1 -1
- package/dist/generators/generateOperationCore.d.ts +3 -3
- package/dist/generators/generateOperationCore.js +51 -16
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateRelationMeta.js +2 -2
- package/dist/generators/generateRelationMeta.js.map +1 -1
- package/dist/generators/generateRouteConfigType.d.ts +2 -2
- package/dist/generators/generateRouteConfigType.js +29 -11
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.d.ts +7 -4
- package/dist/generators/generateRouter.js +164 -65
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +7 -4
- package/dist/generators/generateRouterFastify.js +106 -86
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.d.ts +7 -4
- package/dist/generators/generateRouterHono.js +59 -414
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateRouterPartsHono.d.ts +14 -0
- package/dist/generators/generateRouterPartsHono.js +180 -0
- package/dist/generators/generateRouterPartsHono.js.map +1 -0
- package/dist/generators/generateUnifiedDocs.d.ts +1 -1
- package/dist/generators/generateUnifiedDocs.js +15 -8
- package/dist/generators/generateUnifiedDocs.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.d.ts +2 -2
- package/dist/generators/generateUnifiedHandler.js +42 -18
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/guardOptions.js +12 -7
- package/dist/guardOptions.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +123 -4
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.d.ts +1 -1
- package/dist/utils/copyFiles.js +42 -7
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/importExt.d.ts +1 -1
- package/dist/utils/mcpGate.d.ts +10 -0
- package/dist/utils/mcpGate.js +118 -0
- package/dist/utils/mcpGate.js.map +1 -0
- package/dist/utils/pathCasing.d.ts +4 -0
- package/dist/utils/pathCasing.js +40 -0
- package/dist/utils/pathCasing.js.map +1 -0
- package/dist/utils/resolveImportStyle.js +13 -5
- package/dist/utils/resolveImportStyle.js.map +1 -1
- package/dist/utils/writeFileSafely.js +6 -0
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +22 -5
- package/src/bin.ts +1 -1
- package/src/client/encodeQueryParams.ts +39 -35
- package/src/constants.ts +1 -1
- package/src/copy/autoIncludePlanner.ts +93 -27
- package/src/copy/autoIncludePlannerGuarded.ts +171 -48
- package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
- package/src/copy/buildModelOpenApi.ts +229 -176
- package/src/copy/concurrency.ts +10 -8
- package/src/copy/docsRenderer.ts +14 -15
- package/src/copy/errorMapper.ts +68 -19
- package/src/copy/guardHelpers.ts +30 -9
- package/src/copy/materializedCount.ts +17 -5
- package/src/copy/mcpRuntime.ts +1017 -0
- package/src/copy/misc.ts +88 -68
- package/src/copy/ndjson.ts +72 -0
- package/src/copy/operationDefinitions.ts +177 -25
- package/src/copy/operationPipeline.ts +267 -0
- package/src/copy/operationRuntime.ts +124 -26
- package/src/copy/operationSchemas.ts +2773 -0
- package/src/copy/pagination.ts +35 -13
- package/src/copy/parseQueryParams.ts +47 -48
- package/src/copy/projectionDefaults.ts +6 -4
- package/src/copy/routeConfig.express.ts +16 -4
- package/src/copy/routeConfig.fastify.ts +16 -2
- package/src/copy/routeConfig.hono.ts +46 -14
- package/src/copy/routeConfig.ts +175 -40
- package/src/copy/routerParts.ts +524 -0
- package/src/copy/scalarTypes.ts +7 -2
- package/src/copy/sse.ts +72 -19
- package/src/generators/generateFastifyHandler.ts +77 -20
- package/src/generators/generateHonoHandler.ts +62 -14
- package/src/generators/generateHonoOpenApi.ts +93 -0
- package/src/generators/generateImportPrismaStatement.ts +93 -81
- package/src/generators/generateMcpApp.ts +133 -0
- package/src/generators/generateModelMcp.ts +208 -0
- package/src/generators/generateModelMetadata.ts +40 -22
- package/src/generators/generateOperationCore.ts +81 -33
- package/src/generators/generateRelationMeta.ts +23 -11
- package/src/generators/generateRouteConfigType.ts +39 -13
- package/src/generators/generateRouter.ts +171 -68
- package/src/generators/generateRouterFastify.ts +117 -89
- package/src/generators/generateRouterHono.ts +84 -464
- package/src/generators/generateRouterPartsHono.ts +220 -0
- package/src/generators/generateUnifiedDocs.ts +29 -8
- package/src/generators/generateUnifiedHandler.ts +47 -24
- package/src/generators/generateUnifiedScalarUI.ts +1 -1
- package/src/guardOptions.ts +105 -92
- package/src/index.ts +161 -6
- package/src/utils/copyFiles.ts +235 -168
- package/src/utils/importExt.ts +2 -2
- package/src/utils/mcpGate.ts +157 -0
- package/src/utils/pathCasing.ts +42 -0
- package/src/utils/resolveImportStyle.ts +37 -15
- package/src/utils/strings.ts +2 -2
- 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 (
|
|
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 (
|
|
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
|
|
109
|
-
const routerFunctionName = `${
|
|
113
|
+
const modelSegment = modelPathSegment(model.name, pathCase)
|
|
114
|
+
const routerFunctionName = `${model.name}Router`
|
|
110
115
|
|
|
111
|
-
const handlerImports = OPERATION_METADATA
|
|
112
|
-
|
|
113
|
-
|
|
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(
|
|
117
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
254
|
-
if (!
|
|
255
|
-
fx.
|
|
305
|
+
const routed = routeOperation({ guardRouting: opConfig.guardRouting, caller })
|
|
306
|
+
if (!routed.ok) {
|
|
307
|
+
fx.routeFailure = routed
|
|
256
308
|
return
|
|
257
309
|
}
|
|
258
310
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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 =
|
|
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 ? '/${
|
|
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.
|
|
433
|
-
|
|
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.
|
|
464
|
-
|
|
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
|
+
}
|