prisma-generator-express 1.62.4 → 1.63.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 +234 -95
- package/dist/generators/generateRouteConfigType.js +26 -6
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.js +192 -27
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +100 -28
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +104 -36
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/utils/copyFiles.js +2 -0
- package/dist/utils/copyFiles.js.map +1 -1
- package/package.json +1 -1
- package/src/copy/docsRenderer.ts +1 -0
- package/src/copy/guardVariantError.ts +28 -0
- package/src/copy/guardVariantRouting.ts +109 -0
- package/src/copy/projectionDefaults.ts +5 -6
- package/src/copy/routeConfig.hono.ts +15 -5
- package/src/copy/routeConfig.ts +220 -27
- package/src/generators/generateRouteConfigType.ts +37 -6
- package/src/generators/generateRouter.ts +192 -27
- package/src/generators/generateRouterFastify.ts +100 -28
- package/src/generators/generateRouterHono.ts +104 -36
- package/src/utils/copyFiles.ts +2 -0
|
@@ -52,14 +52,36 @@ function emitReadOp(meta, modelName) {
|
|
|
52
52
|
const postReadBlock = meta.supportsPostRead
|
|
53
53
|
? ` if (postReadsEnabled) {
|
|
54
54
|
const postPath = ${meta.name === 'findMany' ? "basePath ? `${basePath}/read` : '/read'" : `path`}
|
|
55
|
-
router.post(
|
|
55
|
+
router.post(
|
|
56
|
+
postPath,
|
|
57
|
+
parseBodyAsQuery,
|
|
58
|
+
setShape(opConfig, '${opKind}'),
|
|
59
|
+
...opConfig.operationBefore,
|
|
60
|
+
requireVariantKey(),
|
|
61
|
+
variantBeforeDispatcher(opConfig),
|
|
62
|
+
${handlerName} as RequestHandler,
|
|
63
|
+
variantAfterDispatcher(opConfig),
|
|
64
|
+
...opConfig.operationAfter,
|
|
65
|
+
respond,
|
|
66
|
+
)
|
|
56
67
|
}`
|
|
57
68
|
: '';
|
|
58
69
|
return ` if (isEnabled(config.${meta.configKey})) {
|
|
59
|
-
const opConfig
|
|
60
|
-
const { before = [], after = [] } = opConfig
|
|
70
|
+
const opConfig = opFor('${meta.configKey}')
|
|
61
71
|
const path = ${pathValue}
|
|
62
|
-
router.get(
|
|
72
|
+
router.get(
|
|
73
|
+
path,
|
|
74
|
+
parseQuery,
|
|
75
|
+
setShape(opConfig, '${opKind}'),
|
|
76
|
+
...opConfig.operationBefore,
|
|
77
|
+
requireVariantKey(),
|
|
78
|
+
variantBeforeDispatcher(opConfig),
|
|
79
|
+
maybeProgressiveSSE(opConfig, core.${meta.coreName}, '${meta.name}'),
|
|
80
|
+
${handlerName} as RequestHandler,
|
|
81
|
+
variantAfterDispatcher(opConfig),
|
|
82
|
+
...opConfig.operationAfter,
|
|
83
|
+
respond,
|
|
84
|
+
)
|
|
63
85
|
${postReadBlock}
|
|
64
86
|
}`;
|
|
65
87
|
}
|
|
@@ -70,10 +92,19 @@ function emitWriteOp(meta, modelName) {
|
|
|
70
92
|
const respondFn = meta.successStatus === 201 ? 'respondCreated' : 'respond';
|
|
71
93
|
const opKind = opKindFor(meta.name);
|
|
72
94
|
return ` if (isEnabled(config.${meta.configKey})) {
|
|
73
|
-
const opConfig
|
|
74
|
-
const { before = [], after = [] } = opConfig
|
|
95
|
+
const opConfig = opFor('${meta.configKey}')
|
|
75
96
|
const path = ${pathValue}
|
|
76
|
-
router.${meta.method}(
|
|
97
|
+
router.${meta.method}(
|
|
98
|
+
path,
|
|
99
|
+
setShape(opConfig, '${opKind}'),
|
|
100
|
+
...opConfig.operationBefore,
|
|
101
|
+
requireVariantKey(),
|
|
102
|
+
variantBeforeDispatcher(opConfig),
|
|
103
|
+
${handlerName} as RequestHandler,
|
|
104
|
+
variantAfterDispatcher(opConfig),
|
|
105
|
+
...opConfig.operationAfter,
|
|
106
|
+
${respondFn},
|
|
107
|
+
)
|
|
77
108
|
}`;
|
|
78
109
|
}
|
|
79
110
|
function generateRouterFunction({ model, enums, guardShapesImport, importStyle, writeStrategy, findManyPaginatedMode, dropGuard, }) {
|
|
@@ -107,10 +138,19 @@ import type {
|
|
|
107
138
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
108
139
|
import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject } from '../misc${ext}'
|
|
109
140
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
110
|
-
import {
|
|
141
|
+
import {
|
|
142
|
+
normalizeOperation,
|
|
143
|
+
resolveOperationVariantKey,
|
|
144
|
+
validateCountSourceWhere,
|
|
145
|
+
validateOperationConfig,
|
|
146
|
+
validateUpdateEachConfig,
|
|
147
|
+
} from '../routeConfig${ext}'
|
|
148
|
+
import type { NormalizedOperationConfig } from '../routeConfig${ext}'
|
|
111
149
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
112
150
|
import { transformResult } from '../operationRuntime${ext}'
|
|
113
151
|
import { HttpError, mapError } from '../errorMapper${ext}'
|
|
152
|
+
import { formatGuardVariantResolutionError } from '../guardVariantError${ext}'
|
|
153
|
+
import type { GuardVariantResolution } from '../guardVariantRouting${ext}'
|
|
114
154
|
import { mergePaginationConfig } from '../pagination${ext}'
|
|
115
155
|
import {
|
|
116
156
|
acceptsEventStream,
|
|
@@ -134,12 +174,25 @@ const DROP_GUARD = ${dropGuard} || _env.E2E === 'true'
|
|
|
134
174
|
type OperationConfigLike = {
|
|
135
175
|
before?: RequestHandler[]
|
|
136
176
|
after?: RequestHandler[]
|
|
137
|
-
shape?:
|
|
177
|
+
shape?: unknown
|
|
178
|
+
variants?: Record<
|
|
179
|
+
string,
|
|
180
|
+
{
|
|
181
|
+
shape?: unknown
|
|
182
|
+
before?: RequestHandler[]
|
|
183
|
+
after?: RequestHandler[]
|
|
184
|
+
}
|
|
185
|
+
>
|
|
138
186
|
pagination?: Partial<PaginationConfig>
|
|
139
187
|
progressive?: Record<string, ProgressiveVariantConfig>
|
|
140
188
|
progressiveStages?: Record<string, ProgressiveStage<unknown>>
|
|
141
189
|
}
|
|
142
190
|
|
|
191
|
+
type NormalizedOp = NormalizedOperationConfig<RequestHandler, RequestHandler> & {
|
|
192
|
+
progressive?: Record<string, ProgressiveVariantConfig>
|
|
193
|
+
progressiveStages?: Record<string, ProgressiveStage<unknown>>
|
|
194
|
+
}
|
|
195
|
+
|
|
143
196
|
type ExtendedRequest = Request & {
|
|
144
197
|
prisma?: unknown
|
|
145
198
|
postgres?: unknown
|
|
@@ -151,13 +204,20 @@ type LocalsBag = {
|
|
|
151
204
|
routeConfig?: { pagination?: PaginationConfig }
|
|
152
205
|
guardShape?: Record<string, unknown>
|
|
153
206
|
guardCaller?: string
|
|
207
|
+
guardVariantKey?: string
|
|
208
|
+
guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
|
|
154
209
|
data?: unknown
|
|
155
210
|
}
|
|
156
211
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
212
|
+
function normalizeExpressOperation(
|
|
213
|
+
config: OperationConfigLike | undefined,
|
|
214
|
+
): NormalizedOp {
|
|
215
|
+
return {
|
|
216
|
+
...normalizeOperation<RequestHandler, RequestHandler>(config),
|
|
217
|
+
progressive: config?.progressive,
|
|
218
|
+
progressiveStages: config?.progressiveStages,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
161
221
|
|
|
162
222
|
function isQueryBuilderEnabled(config: { queryBuilder?: QueryBuilderConfig | false }): boolean {
|
|
163
223
|
if (config.queryBuilder === false) return false
|
|
@@ -176,6 +236,87 @@ function readLocals(res: Response): LocalsBag {
|
|
|
176
236
|
return res.locals as LocalsBag
|
|
177
237
|
}
|
|
178
238
|
|
|
239
|
+
function runHandlerSequence(
|
|
240
|
+
handlers: readonly RequestHandler[],
|
|
241
|
+
req: Request,
|
|
242
|
+
res: Response,
|
|
243
|
+
done: (error?: unknown) => void,
|
|
244
|
+
): void {
|
|
245
|
+
let index = 0
|
|
246
|
+
|
|
247
|
+
const dispatch = (error?: unknown): void => {
|
|
248
|
+
if (error !== undefined) {
|
|
249
|
+
done(error)
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (res.writableEnded || res.destroyed) return
|
|
254
|
+
|
|
255
|
+
const handler = handlers[index++]
|
|
256
|
+
if (!handler) {
|
|
257
|
+
done()
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let settled = false
|
|
262
|
+
const next = (nextError?: unknown): void => {
|
|
263
|
+
if (settled) return
|
|
264
|
+
settled = true
|
|
265
|
+
dispatch(nextError)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
const result = handler(req, res, next)
|
|
270
|
+
if (result && typeof (result as Promise<unknown>).then === 'function') {
|
|
271
|
+
void (result as Promise<unknown>).catch((promiseError) => {
|
|
272
|
+
if (settled) return
|
|
273
|
+
settled = true
|
|
274
|
+
dispatch(promiseError)
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
} catch (handlerError) {
|
|
278
|
+
if (settled) return
|
|
279
|
+
settled = true
|
|
280
|
+
dispatch(handlerError)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
dispatch()
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function variantBeforeDispatcher(opConfig: NormalizedOp): RequestHandler {
|
|
288
|
+
return (req, res, next) => {
|
|
289
|
+
const key = readLocals(res).guardVariantKey
|
|
290
|
+
const hooks =
|
|
291
|
+
key !== undefined
|
|
292
|
+
? (opConfig.variantHooks[key]?.before ?? [])
|
|
293
|
+
: []
|
|
294
|
+
runHandlerSequence(hooks, req, res, next)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function variantAfterDispatcher(opConfig: NormalizedOp): RequestHandler {
|
|
299
|
+
return (req, res, next) => {
|
|
300
|
+
const key = readLocals(res).guardVariantKey
|
|
301
|
+
const hooks =
|
|
302
|
+
key !== undefined
|
|
303
|
+
? (opConfig.variantHooks[key]?.after ?? [])
|
|
304
|
+
: []
|
|
305
|
+
runHandlerSequence(hooks, req, res, next)
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function requireVariantKey(): RequestHandler {
|
|
310
|
+
return (_req, res, next) => {
|
|
311
|
+
const failure = readLocals(res).guardVariantFailure
|
|
312
|
+
if (!failure) {
|
|
313
|
+
next()
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
next(new HttpError(400, formatGuardVariantResolutionError(failure)))
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
179
320
|
export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${modelName}RouteConfig<TCtx, TPrisma> = {}) {
|
|
180
321
|
validateCountSourceWhere(config.pagination?.countSource, '${modelName} pagination')
|
|
181
322
|
validateCountSourceWhere(
|
|
@@ -187,6 +328,12 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
187
328
|
|
|
188
329
|
const isEnabled = (value: unknown): boolean => value !== false && !!(config.enableAll || value)
|
|
189
330
|
|
|
331
|
+
const opFor = (key: string): NormalizedOp => {
|
|
332
|
+
const raw = (config as unknown as Record<string, unknown>)[key] as OperationConfigLike | undefined
|
|
333
|
+
validateOperationConfig(raw, '${modelName}.' + key)
|
|
334
|
+
return normalizeExpressOperation(raw)
|
|
335
|
+
}
|
|
336
|
+
|
|
190
337
|
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
191
338
|
const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
|
|
192
339
|
const basePath = customPrefix + modelPrefix
|
|
@@ -273,7 +420,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
273
420
|
next()
|
|
274
421
|
}
|
|
275
422
|
|
|
276
|
-
const setShape = (opConfig:
|
|
423
|
+
const setShape = (opConfig: NormalizedOp, opKind: OpKind): RequestHandler => {
|
|
277
424
|
return async (req, res, next) => {
|
|
278
425
|
try {
|
|
279
426
|
const locals = readLocals(res)
|
|
@@ -281,17 +428,32 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
281
428
|
if (merged) {
|
|
282
429
|
locals.routeConfig = { pagination: merged }
|
|
283
430
|
}
|
|
431
|
+
|
|
284
432
|
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
285
433
|
const headerValue = req.get(headerName)
|
|
286
434
|
const caller = config.guard?.resolveVariant?.(req) ?? headerValue ?? undefined
|
|
287
|
-
if (caller) locals.guardCaller = caller
|
|
288
|
-
|
|
435
|
+
if (typeof caller === 'string') locals.guardCaller = caller
|
|
436
|
+
|
|
437
|
+
const resolution = resolveOperationVariantKey(opConfig.guardRouting, caller)
|
|
438
|
+
if (!resolution.ok) {
|
|
439
|
+
locals.guardVariantFailure = resolution
|
|
440
|
+
next()
|
|
441
|
+
return
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const resolvedKey =
|
|
445
|
+
opConfig.guardRouting.kind === 'named'
|
|
446
|
+
? resolution.key
|
|
447
|
+
: undefined
|
|
448
|
+
if (resolvedKey !== undefined) locals.guardVariantKey = resolvedKey
|
|
449
|
+
|
|
450
|
+
if (opConfig.guardShape) {
|
|
289
451
|
if (!DROP_GUARD) {
|
|
290
|
-
locals.guardShape = opConfig.
|
|
452
|
+
locals.guardShape = opConfig.guardShape
|
|
291
453
|
} else {
|
|
292
454
|
await applyDroppedGuard(
|
|
293
|
-
opConfig.
|
|
294
|
-
|
|
455
|
+
opConfig.guardShape,
|
|
456
|
+
resolvedKey,
|
|
295
457
|
buildResolveContext(req),
|
|
296
458
|
opKind,
|
|
297
459
|
{
|
|
@@ -313,6 +475,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
313
475
|
)
|
|
314
476
|
}
|
|
315
477
|
}
|
|
478
|
+
|
|
316
479
|
next()
|
|
317
480
|
} catch (err) {
|
|
318
481
|
next(mapError(err))
|
|
@@ -321,7 +484,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
321
484
|
}
|
|
322
485
|
|
|
323
486
|
const maybeProgressiveSSE = (
|
|
324
|
-
opConfig:
|
|
487
|
+
opConfig: NormalizedOp,
|
|
325
488
|
coreFn: (ctx: OperationContext) => Promise<unknown>,
|
|
326
489
|
baseOp: string,
|
|
327
490
|
): RequestHandler => {
|
|
@@ -331,8 +494,9 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
331
494
|
if (!acceptsEventStream(req.headers.accept)) return next()
|
|
332
495
|
|
|
333
496
|
const locals = readLocals(res)
|
|
334
|
-
const variant = locals.guardCaller
|
|
335
|
-
const progressiveConfig =
|
|
497
|
+
const variant = locals.guardVariantKey ?? locals.guardCaller
|
|
498
|
+
const progressiveConfig =
|
|
499
|
+
variant !== undefined ? opConfig.progressive?.[variant] : undefined
|
|
336
500
|
|
|
337
501
|
try {
|
|
338
502
|
if (!progressiveConfig || progressiveConfig.enabled === false) {
|
|
@@ -460,19 +624,20 @@ ${readOpBlocks}
|
|
|
460
624
|
${writeOpBlocks}
|
|
461
625
|
|
|
462
626
|
if (config.updateEach) {
|
|
463
|
-
const
|
|
464
|
-
|
|
627
|
+
const rawUpdateEach = config.updateEach as unknown as OperationConfigLike
|
|
628
|
+
validateUpdateEachConfig(rawUpdateEach, '${modelName}.updateEach')
|
|
629
|
+
const opConfig = normalizeExpressOperation(rawUpdateEach)
|
|
630
|
+
if (opConfig.operationBefore.length === 0 && _env.NODE_ENV !== 'production') {
|
|
465
631
|
console.warn(
|
|
466
632
|
'[${modelName}Router] updateEach is enabled without a before hook. ' +
|
|
467
633
|
'This endpoint bypasses guard shapes and should be protected by authentication middleware.',
|
|
468
634
|
)
|
|
469
635
|
}
|
|
470
|
-
const { before = [], after = [] } = opConfig
|
|
471
636
|
const path = basePath ? \`\${basePath}/each\` : '/each'
|
|
472
637
|
router.post(
|
|
473
638
|
path,
|
|
474
639
|
setShape(opConfig, 'noop'),
|
|
475
|
-
...
|
|
640
|
+
...opConfig.operationBefore,
|
|
476
641
|
async (req: Request, res: Response, next: NextFunction) => {
|
|
477
642
|
try {
|
|
478
643
|
if (!Array.isArray(req.body)) {
|
|
@@ -485,7 +650,7 @@ ${writeOpBlocks}
|
|
|
485
650
|
next(mapError(err))
|
|
486
651
|
}
|
|
487
652
|
},
|
|
488
|
-
...
|
|
653
|
+
...opConfig.operationAfter,
|
|
489
654
|
respond,
|
|
490
655
|
)
|
|
491
656
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateRouter.js","sourceRoot":"","sources":["../../src/generators/generateRouter.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"generateRouter.js","sourceRoot":"","sources":["../../src/generators/generateRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,7 +56,7 @@ function emitReadOp(meta, modelName) {
|
|
|
56
56
|
: ` if (postReadsEnabled) instance.post(path, handleRead(opConfig, ${handlerName}, parseBodyAsQueryHook, '${opKind}'))`
|
|
57
57
|
: '';
|
|
58
58
|
return ` if (isEnabled(config.${meta.configKey})) {
|
|
59
|
-
const opConfig
|
|
59
|
+
const opConfig = opFor('${meta.configKey}')
|
|
60
60
|
const path = ${pathValue}
|
|
61
61
|
instance.get(path, handleRead(opConfig, ${handlerName}, parseQueryHook, '${opKind}'))
|
|
62
62
|
${postReadLine}
|
|
@@ -68,7 +68,7 @@ function emitWriteOp(meta, modelName) {
|
|
|
68
68
|
const pathValue = pathExpr(meta.pathSuffix);
|
|
69
69
|
const opKind = opKindFor(meta.name);
|
|
70
70
|
return ` if (isEnabled(config.${meta.configKey})) {
|
|
71
|
-
const opConfig
|
|
71
|
+
const opConfig = opFor('${meta.configKey}')
|
|
72
72
|
const path = ${pathValue}
|
|
73
73
|
instance.${meta.method}(path, handleWrite(opConfig, ${handlerName}, '${opKind}'))
|
|
74
74
|
}`;
|
|
@@ -100,10 +100,19 @@ import type {
|
|
|
100
100
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
101
101
|
import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject } from '../misc${ext}'
|
|
102
102
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
103
|
-
import {
|
|
103
|
+
import {
|
|
104
|
+
normalizeOperation,
|
|
105
|
+
resolveOperationVariantKey,
|
|
106
|
+
validateCountSourceWhere,
|
|
107
|
+
validateOperationConfig,
|
|
108
|
+
validateUpdateEachConfig,
|
|
109
|
+
} from '../routeConfig${ext}'
|
|
110
|
+
import type { NormalizedOperationConfig } from '../routeConfig${ext}'
|
|
104
111
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
105
112
|
import { transformResult } from '../operationRuntime${ext}'
|
|
106
113
|
import { HttpError, mapError } from '../errorMapper${ext}'
|
|
114
|
+
import { formatGuardVariantResolutionError } from '../guardVariantError${ext}'
|
|
115
|
+
import type { GuardVariantResolution } from '../guardVariantRouting${ext}'
|
|
107
116
|
import { mergePaginationConfig } from '../pagination${ext}'
|
|
108
117
|
import { applyDroppedGuard } from '../projectionDefaults${ext}'
|
|
109
118
|
import type { OpKind } from '../projectionDefaults${ext}'
|
|
@@ -118,10 +127,23 @@ const DROP_GUARD = ${dropGuard} || _env.E2E === 'true'
|
|
|
118
127
|
type OperationConfigLike = {
|
|
119
128
|
before?: FastifyHookHandler[]
|
|
120
129
|
after?: FastifyHookHandler[]
|
|
121
|
-
shape?:
|
|
130
|
+
shape?: unknown
|
|
131
|
+
variants?: Record<
|
|
132
|
+
string,
|
|
133
|
+
{
|
|
134
|
+
shape?: unknown
|
|
135
|
+
before?: FastifyHookHandler[]
|
|
136
|
+
after?: FastifyHookHandler[]
|
|
137
|
+
}
|
|
138
|
+
>
|
|
122
139
|
pagination?: Partial<PaginationConfig>
|
|
123
140
|
}
|
|
124
141
|
|
|
142
|
+
type NormalizedOp = NormalizedOperationConfig<
|
|
143
|
+
FastifyHookHandler,
|
|
144
|
+
FastifyHookHandler
|
|
145
|
+
>
|
|
146
|
+
|
|
125
147
|
type FastifyExtended = FastifyRequest & {
|
|
126
148
|
prisma?: unknown
|
|
127
149
|
postgres?: unknown
|
|
@@ -130,14 +152,17 @@ type FastifyExtended = FastifyRequest & {
|
|
|
130
152
|
routeConfig?: { pagination?: PaginationConfig }
|
|
131
153
|
guardShape?: Record<string, unknown>
|
|
132
154
|
guardCaller?: string
|
|
155
|
+
guardVariantKey?: string
|
|
156
|
+
guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
|
|
133
157
|
resultData?: unknown
|
|
134
158
|
resultStatus?: number
|
|
135
159
|
}
|
|
136
160
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
161
|
+
function normalizeFastifyOperation(
|
|
162
|
+
config: OperationConfigLike | undefined,
|
|
163
|
+
): NormalizedOp {
|
|
164
|
+
return normalizeOperation<FastifyHookHandler, FastifyHookHandler>(config)
|
|
165
|
+
}
|
|
141
166
|
|
|
142
167
|
function isQueryBuilderEnabled(config: RouteConfig): boolean {
|
|
143
168
|
if (config.queryBuilder === false) return false
|
|
@@ -177,7 +202,7 @@ function buildResolveContext(
|
|
|
177
202
|
|
|
178
203
|
function makeShapeHook(
|
|
179
204
|
config: ${modelName}RouteConfig,
|
|
180
|
-
opConfig:
|
|
205
|
+
opConfig: NormalizedOp,
|
|
181
206
|
opKind: OpKind,
|
|
182
207
|
): (request: FastifyRequest) => Promise<void> {
|
|
183
208
|
return async (request: FastifyRequest) => {
|
|
@@ -190,15 +215,27 @@ function makeShapeHook(
|
|
|
190
215
|
const caller = config.guard?.resolveVariant?.(request)
|
|
191
216
|
?? (Array.isArray(headerValue) ? headerValue[0] : headerValue)
|
|
192
217
|
?? undefined
|
|
193
|
-
if (caller) fx.guardCaller = caller
|
|
218
|
+
if (typeof caller === 'string') fx.guardCaller = caller
|
|
219
|
+
|
|
220
|
+
const resolution = resolveOperationVariantKey(opConfig.guardRouting, caller)
|
|
221
|
+
if (!resolution.ok) {
|
|
222
|
+
fx.guardVariantFailure = resolution
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const resolvedKey =
|
|
227
|
+
opConfig.guardRouting.kind === 'named'
|
|
228
|
+
? resolution.key
|
|
229
|
+
: undefined
|
|
230
|
+
if (resolvedKey !== undefined) fx.guardVariantKey = resolvedKey
|
|
194
231
|
|
|
195
|
-
if (opConfig.
|
|
232
|
+
if (opConfig.guardShape) {
|
|
196
233
|
if (!DROP_GUARD) {
|
|
197
|
-
fx.guardShape = opConfig.
|
|
234
|
+
fx.guardShape = opConfig.guardShape
|
|
198
235
|
} else {
|
|
199
236
|
await applyDroppedGuard(
|
|
200
|
-
opConfig.
|
|
201
|
-
|
|
237
|
+
opConfig.guardShape,
|
|
238
|
+
resolvedKey,
|
|
202
239
|
buildResolveContext(config, request),
|
|
203
240
|
opKind,
|
|
204
241
|
{
|
|
@@ -224,7 +261,7 @@ function makeShapeHook(
|
|
|
224
261
|
}
|
|
225
262
|
|
|
226
263
|
async function runHooks(
|
|
227
|
-
hooks: FastifyHookHandler[],
|
|
264
|
+
hooks: readonly FastifyHookHandler[],
|
|
228
265
|
request: FastifyRequest,
|
|
229
266
|
reply: FastifyReply,
|
|
230
267
|
): Promise<boolean> {
|
|
@@ -265,6 +302,12 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
265
302
|
await fastify.register(async (instance) => {
|
|
266
303
|
const isEnabled = (value: unknown): boolean => value !== false && !!(config.enableAll || value)
|
|
267
304
|
|
|
305
|
+
const opFor = (key: string): NormalizedOp => {
|
|
306
|
+
const raw = (config as unknown as Record<string, unknown>)[key] as OperationConfigLike | undefined
|
|
307
|
+
validateOperationConfig(raw, '${modelName}.' + key)
|
|
308
|
+
return normalizeFastifyOperation(raw)
|
|
309
|
+
}
|
|
310
|
+
|
|
268
311
|
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
269
312
|
const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
|
|
270
313
|
const basePath = customPrefix + modelPrefix
|
|
@@ -342,7 +385,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
342
385
|
}
|
|
343
386
|
|
|
344
387
|
const handleRead = (
|
|
345
|
-
opConfig:
|
|
388
|
+
opConfig: NormalizedOp,
|
|
346
389
|
handlerFn: (req: FastifyRequest, reply: FastifyReply) => Promise<void>,
|
|
347
390
|
parseFn: (req: FastifyRequest) => void,
|
|
348
391
|
opKind: OpKind,
|
|
@@ -350,10 +393,24 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
350
393
|
try {
|
|
351
394
|
parseFn(request)
|
|
352
395
|
await makeShapeHook(config, opConfig, opKind)(request)
|
|
353
|
-
|
|
354
|
-
|
|
396
|
+
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
397
|
+
|
|
398
|
+
const fx = request as FastifyExtended
|
|
399
|
+
if (fx.guardVariantFailure) {
|
|
400
|
+
throw new HttpError(
|
|
401
|
+
400,
|
|
402
|
+
formatGuardVariantResolutionError(fx.guardVariantFailure),
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const key = fx.guardVariantKey
|
|
407
|
+
const variantHooks =
|
|
408
|
+
key !== undefined ? opConfig.variantHooks[key] : undefined
|
|
409
|
+
|
|
410
|
+
if (await runHooks(variantHooks?.before ?? [], request, reply)) return
|
|
355
411
|
await handlerFn(request, reply)
|
|
356
|
-
if (await runHooks(after, request, reply)) return
|
|
412
|
+
if (await runHooks(variantHooks?.after ?? [], request, reply)) return
|
|
413
|
+
if (await runHooks(opConfig.operationAfter, request, reply)) return
|
|
357
414
|
sendResult(request, reply)
|
|
358
415
|
} catch (error: unknown) {
|
|
359
416
|
sendError(reply, error)
|
|
@@ -361,16 +418,30 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
361
418
|
}
|
|
362
419
|
|
|
363
420
|
const handleWrite = (
|
|
364
|
-
opConfig:
|
|
421
|
+
opConfig: NormalizedOp,
|
|
365
422
|
handlerFn: (req: FastifyRequest, reply: FastifyReply) => Promise<void>,
|
|
366
423
|
opKind: OpKind,
|
|
367
424
|
) => async (request: FastifyRequest, reply: FastifyReply) => {
|
|
368
425
|
try {
|
|
369
426
|
await makeShapeHook(config, opConfig, opKind)(request)
|
|
370
|
-
|
|
371
|
-
|
|
427
|
+
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
428
|
+
|
|
429
|
+
const fx = request as FastifyExtended
|
|
430
|
+
if (fx.guardVariantFailure) {
|
|
431
|
+
throw new HttpError(
|
|
432
|
+
400,
|
|
433
|
+
formatGuardVariantResolutionError(fx.guardVariantFailure),
|
|
434
|
+
)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const key = fx.guardVariantKey
|
|
438
|
+
const variantHooks =
|
|
439
|
+
key !== undefined ? opConfig.variantHooks[key] : undefined
|
|
440
|
+
|
|
441
|
+
if (await runHooks(variantHooks?.before ?? [], request, reply)) return
|
|
372
442
|
await handlerFn(request, reply)
|
|
373
|
-
if (await runHooks(after, request, reply)) return
|
|
443
|
+
if (await runHooks(variantHooks?.after ?? [], request, reply)) return
|
|
444
|
+
if (await runHooks(opConfig.operationAfter, request, reply)) return
|
|
374
445
|
sendResult(request, reply)
|
|
375
446
|
} catch (error: unknown) {
|
|
376
447
|
sendError(reply, error)
|
|
@@ -382,8 +453,10 @@ ${readOpBlocks}
|
|
|
382
453
|
${writeOpBlocks}
|
|
383
454
|
|
|
384
455
|
if (config.updateEach) {
|
|
385
|
-
const
|
|
386
|
-
|
|
456
|
+
const rawUpdateEach = config.updateEach as unknown as OperationConfigLike
|
|
457
|
+
validateUpdateEachConfig(rawUpdateEach, '${modelName}.updateEach')
|
|
458
|
+
const opConfig = normalizeFastifyOperation(rawUpdateEach)
|
|
459
|
+
if (opConfig.operationBefore.length === 0 && _env.NODE_ENV !== 'production') {
|
|
387
460
|
console.warn(
|
|
388
461
|
'[${modelName}Router] updateEach is enabled without a before hook. ' +
|
|
389
462
|
'This endpoint bypasses guard shapes and should be protected by authentication middleware.',
|
|
@@ -396,10 +469,9 @@ ${writeOpBlocks}
|
|
|
396
469
|
throw new HttpError(400, 'updateEach body must be an array of { where, data } items')
|
|
397
470
|
}
|
|
398
471
|
await makeShapeHook(config, opConfig, 'noop')(request)
|
|
399
|
-
|
|
400
|
-
if (await runHooks(before, request, reply)) return
|
|
472
|
+
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
401
473
|
await ${modelName}UpdateEach(request, reply)
|
|
402
|
-
if (await runHooks(
|
|
474
|
+
if (await runHooks(opConfig.operationAfter, request, reply)) return
|
|
403
475
|
sendResult(request, reply)
|
|
404
476
|
} catch (error: unknown) {
|
|
405
477
|
sendError(reply, error)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateRouterFastify.js","sourceRoot":"","sources":["../../src/generators/generateRouterFastify.ts"],"names":[],"mappings":";;AAwFA,
|
|
1
|
+
{"version":3,"file":"generateRouterFastify.js","sourceRoot":"","sources":["../../src/generators/generateRouterFastify.ts"],"names":[],"mappings":"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"}
|