prisma-generator-express 1.67.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 +223 -28
- package/dist/copy/operationDefinitions.d.ts +4 -1
- package/dist/copy/operationDefinitions.js +64 -3
- package/dist/copy/operationDefinitions.js.map +1 -1
- package/dist/generators/generateFastifyHandler.js +55 -9
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.js +44 -4
- 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/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 +9 -5
- package/dist/generators/generateModelMetadata.js.map +1 -1
- package/dist/generators/generateRouter.js +62 -56
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +56 -64
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +43 -411
- 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/generateUnifiedHandler.js +36 -20
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +101 -3
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.d.ts +1 -1
- package/dist/utils/copyFiles.js +20 -1
- package/dist/utils/copyFiles.js.map +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/writeFileSafely.js +6 -0
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +18 -3
- package/src/copy/buildModelOpenApi.ts +76 -126
- package/src/copy/docsRenderer.ts +14 -15
- package/src/copy/mcpRuntime.ts +1017 -0
- package/src/copy/operationDefinitions.ts +78 -4
- package/src/copy/operationPipeline.ts +267 -0
- package/src/copy/operationRuntime.ts +24 -14
- package/src/copy/operationSchemas.ts +2773 -0
- package/src/copy/pagination.ts +10 -2
- package/src/copy/routeConfig.hono.ts +34 -5
- package/src/copy/routeConfig.ts +1 -1
- package/src/copy/routerParts.ts +524 -0
- package/src/generators/generateFastifyHandler.ts +55 -9
- package/src/generators/generateHonoHandler.ts +44 -4
- package/src/generators/generateHonoOpenApi.ts +93 -0
- package/src/generators/generateMcpApp.ts +133 -0
- package/src/generators/generateModelMcp.ts +208 -0
- package/src/generators/generateModelMetadata.ts +16 -10
- package/src/generators/generateRouter.ts +62 -56
- package/src/generators/generateRouterFastify.ts +56 -64
- package/src/generators/generateRouterHono.ts +49 -459
- package/src/generators/generateRouterPartsHono.ts +220 -0
- package/src/generators/generateUnifiedHandler.ts +36 -21
- package/src/index.ts +116 -3
- package/src/utils/copyFiles.ts +36 -0
- package/src/utils/mcpGate.ts +157 -0
- package/src/utils/writeFileSafely.ts +6 -0
|
@@ -189,7 +189,6 @@ import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject, resolveDropGuardE
|
|
|
189
189
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
190
190
|
import {
|
|
191
191
|
normalizeOperation,
|
|
192
|
-
resolveOperationVariantKey,
|
|
193
192
|
validateCountSourceWhere,
|
|
194
193
|
validateOperationConfig,
|
|
195
194
|
validateUpdateEachConfig,
|
|
@@ -201,8 +200,14 @@ import type { NormalizedOperationConfig } from '../routeConfig${ext}'
|
|
|
201
200
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
202
201
|
import { transformResult } from '../operationRuntime${ext}'
|
|
203
202
|
import { HttpError, mapError } from '../errorMapper${ext}'
|
|
204
|
-
import {
|
|
205
|
-
|
|
203
|
+
import {
|
|
204
|
+
routeOperation,
|
|
205
|
+
prepareGuardOperation,
|
|
206
|
+
settleStage,
|
|
207
|
+
classifyError,
|
|
208
|
+
memoizeContext,
|
|
209
|
+
type ArgsChannel,
|
|
210
|
+
} from '../operationPipeline${ext}'
|
|
206
211
|
import { mergePaginationConfig } from '../pagination${ext}'
|
|
207
212
|
import { acceptsNdjson, runNdjsonFindMany } from '../ndjson${ext}'
|
|
208
213
|
import {
|
|
@@ -214,7 +219,6 @@ import {
|
|
|
214
219
|
} from '../sse${ext}'
|
|
215
220
|
import { relationModels } from '../relationModels${ext}'
|
|
216
221
|
import { runAutoIncludeProgressive } from '../autoIncludeRuntime${ext}'
|
|
217
|
-
import { applyDroppedGuard } from '../projectionDefaults${ext}'
|
|
218
222
|
import type { OpKind } from '../projectionDefaults${ext}'
|
|
219
223
|
import { MODEL_FIELDS, MODEL_ENUMS } from './${modelName}Metadata${ext}'
|
|
220
224
|
|
|
@@ -263,12 +267,34 @@ type LocalsBag = {
|
|
|
263
267
|
guardShape?: Record<string, unknown>
|
|
264
268
|
guardCaller?: string
|
|
265
269
|
operationOverride?: RuntimeOperationOverride
|
|
266
|
-
|
|
270
|
+
getContext?: () => Promise<unknown>
|
|
267
271
|
guardVariantKey?: string
|
|
268
|
-
|
|
272
|
+
routeFailure?: { ok: false; failure: HttpError }
|
|
273
|
+
guardFailure?: { ok: false; failure: HttpError }
|
|
269
274
|
data?: unknown
|
|
270
275
|
}
|
|
271
276
|
|
|
277
|
+
function queryChannel(res: Response): ArgsChannel {
|
|
278
|
+
return {
|
|
279
|
+
read: () => readLocals(res).parsedQuery,
|
|
280
|
+
write: (next) => {
|
|
281
|
+
readLocals(res).parsedQuery = next
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function bodyChannel(req: Request): ArgsChannel {
|
|
287
|
+
return {
|
|
288
|
+
read: () =>
|
|
289
|
+
isPlainObject(req.body)
|
|
290
|
+
? (req.body as Record<string, unknown>)
|
|
291
|
+
: undefined,
|
|
292
|
+
write: (next) => {
|
|
293
|
+
req.body = next
|
|
294
|
+
},
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
272
298
|
function normalizeExpressOperation(
|
|
273
299
|
config: OperationConfigLike | undefined,
|
|
274
300
|
): NormalizedOp {
|
|
@@ -372,12 +398,15 @@ function variantAfterDispatcher(opConfig: NormalizedOp): RequestHandler {
|
|
|
372
398
|
|
|
373
399
|
function requireVariantKey(): RequestHandler {
|
|
374
400
|
return (_req, res, next) => {
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
401
|
+
const locals = readLocals(res)
|
|
402
|
+
try {
|
|
403
|
+
if (locals.routeFailure) settleStage(locals.routeFailure)
|
|
404
|
+
if (locals.guardFailure) settleStage(locals.guardFailure)
|
|
405
|
+
} catch (err) {
|
|
406
|
+
next(err)
|
|
378
407
|
return
|
|
379
408
|
}
|
|
380
|
-
next(
|
|
409
|
+
next()
|
|
381
410
|
}
|
|
382
411
|
}
|
|
383
412
|
|
|
@@ -451,7 +480,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClie
|
|
|
451
480
|
const locals = readLocals(res)
|
|
452
481
|
return {
|
|
453
482
|
operationOverride: locals.operationOverride,
|
|
454
|
-
resolveOperationContext: locals.
|
|
483
|
+
resolveOperationContext: locals.getContext,
|
|
455
484
|
prisma: extReq.prisma,
|
|
456
485
|
postgres: extReq.postgres,
|
|
457
486
|
sqlite: extReq.sqlite,
|
|
@@ -465,11 +494,6 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClie
|
|
|
465
494
|
}
|
|
466
495
|
}
|
|
467
496
|
|
|
468
|
-
const buildResolveContext = (req: Request): (() => unknown | Promise<unknown>) | undefined => {
|
|
469
|
-
if (typeof config.resolveContext !== 'function') return undefined
|
|
470
|
-
return () => (config.resolveContext as (r: Request) => unknown | Promise<unknown>)(req)
|
|
471
|
-
}
|
|
472
|
-
|
|
473
497
|
const parseQuery: RequestHandler = (req, res, next) => {
|
|
474
498
|
const rawQuery = req.query
|
|
475
499
|
if (rawQuery && Object.keys(rawQuery).length > 0) {
|
|
@@ -501,11 +525,10 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClie
|
|
|
501
525
|
|
|
502
526
|
const setShape = (opConfig: NormalizedOp, opKind: OpKind): RequestHandler => {
|
|
503
527
|
return async (req, res, next) => {
|
|
528
|
+
const locals = readLocals(res)
|
|
504
529
|
try {
|
|
505
|
-
const locals = readLocals(res)
|
|
506
530
|
locals.operationOverride = opConfig.override
|
|
507
|
-
|
|
508
|
-
locals.resolveOperationContext = () => context ??= Promise.resolve(config.resolveContext?.(req))
|
|
531
|
+
locals.getContext = memoizeContext(() => config.resolveContext?.(req))
|
|
509
532
|
const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
|
|
510
533
|
if (merged) {
|
|
511
534
|
locals.routeConfig = { pagination: merged }
|
|
@@ -516,51 +539,34 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClie
|
|
|
516
539
|
const caller = config.guard?.resolveVariant?.(req) ?? headerValue ?? undefined
|
|
517
540
|
if (typeof caller === 'string') locals.guardCaller = caller
|
|
518
541
|
|
|
519
|
-
const
|
|
520
|
-
if (!
|
|
521
|
-
locals.
|
|
542
|
+
const routed = routeOperation({ guardRouting: opConfig.guardRouting, caller })
|
|
543
|
+
if (!routed.ok) {
|
|
544
|
+
locals.routeFailure = routed
|
|
522
545
|
next()
|
|
523
546
|
return
|
|
524
547
|
}
|
|
525
548
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
opKind,
|
|
541
|
-
{
|
|
542
|
-
readQuery: locals.parsedQuery,
|
|
543
|
-
writeBody: isPlainObject(req.body)
|
|
544
|
-
? (req.body as Record<string, unknown>)
|
|
545
|
-
: undefined,
|
|
546
|
-
},
|
|
547
|
-
() => {
|
|
548
|
-
if (!locals.parsedQuery) locals.parsedQuery = {}
|
|
549
|
-
return locals.parsedQuery
|
|
550
|
-
},
|
|
551
|
-
() => {
|
|
552
|
-
if (!isPlainObject(req.body)) {
|
|
553
|
-
req.body = {}
|
|
554
|
-
}
|
|
555
|
-
return req.body as Record<string, unknown>
|
|
556
|
-
},
|
|
557
|
-
)
|
|
558
|
-
}
|
|
549
|
+
if (routed.variantKey !== undefined) locals.guardVariantKey = routed.variantKey
|
|
550
|
+
|
|
551
|
+
const guard = await prepareGuardOperation(routed, {
|
|
552
|
+
guardShape: opConfig.guardShape,
|
|
553
|
+
opKind,
|
|
554
|
+
policy: { dropGuard, validateResolvedShapes: false },
|
|
555
|
+
getContext: typeof config.resolveContext === 'function' ? locals.getContext : undefined,
|
|
556
|
+
args: queryChannel(res),
|
|
557
|
+
writeArgs: bodyChannel(req),
|
|
558
|
+
})
|
|
559
|
+
if (!guard.ok) {
|
|
560
|
+
locals.guardFailure = guard
|
|
561
|
+
next()
|
|
562
|
+
return
|
|
559
563
|
}
|
|
560
564
|
|
|
565
|
+
locals.guardShape = guard.guardShape
|
|
566
|
+
|
|
561
567
|
next()
|
|
562
568
|
} catch (err) {
|
|
563
|
-
next(
|
|
569
|
+
next(classifyError(err))
|
|
564
570
|
}
|
|
565
571
|
}
|
|
566
572
|
}
|
|
@@ -145,7 +145,6 @@ import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject, resolveDropGuardE
|
|
|
145
145
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
146
146
|
import {
|
|
147
147
|
normalizeOperation,
|
|
148
|
-
resolveOperationVariantKey,
|
|
149
148
|
validateCountSourceWhere,
|
|
150
149
|
validateOperationConfig,
|
|
151
150
|
validateUpdateEachConfig,
|
|
@@ -157,10 +156,15 @@ import type { NormalizedOperationConfig } from '../routeConfig${ext}'
|
|
|
157
156
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
158
157
|
import { transformResult } from '../operationRuntime${ext}'
|
|
159
158
|
import { HttpError, mapError } from '../errorMapper${ext}'
|
|
160
|
-
import { formatGuardVariantResolutionError } from '../guardVariantError${ext}'
|
|
161
|
-
import type { GuardVariantResolution } from '../guardVariantRouting${ext}'
|
|
162
159
|
import { mergePaginationConfig } from '../pagination${ext}'
|
|
163
|
-
import {
|
|
160
|
+
import {
|
|
161
|
+
routeOperation,
|
|
162
|
+
prepareGuardOperation,
|
|
163
|
+
settleStage,
|
|
164
|
+
classifyError,
|
|
165
|
+
memoizeContext,
|
|
166
|
+
type ArgsChannel,
|
|
167
|
+
} from '../operationPipeline${ext}'
|
|
164
168
|
import type { OpKind } from '../projectionDefaults${ext}'
|
|
165
169
|
import { MODEL_FIELDS, MODEL_ENUMS } from './${modelName}Metadata${ext}'
|
|
166
170
|
|
|
@@ -204,13 +208,36 @@ type FastifyExtended = FastifyRequest & {
|
|
|
204
208
|
guardShape?: Record<string, unknown>
|
|
205
209
|
guardCaller?: string
|
|
206
210
|
operationOverride?: RuntimeOperationOverride
|
|
207
|
-
|
|
211
|
+
getContext?: () => Promise<unknown>
|
|
208
212
|
guardVariantKey?: string
|
|
209
|
-
|
|
213
|
+
routeFailure?: { ok: false; failure: HttpError }
|
|
214
|
+
guardFailure?: { ok: false; failure: HttpError }
|
|
210
215
|
resultData?: unknown
|
|
211
216
|
resultStatus?: number
|
|
212
217
|
}
|
|
213
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
|
+
|
|
214
241
|
function normalizeFastifyOperation(
|
|
215
242
|
config: OperationConfigLike | undefined,
|
|
216
243
|
): NormalizedOp {
|
|
@@ -245,14 +272,6 @@ function parseBodyAsQueryHook(request: FastifyRequest): void {
|
|
|
245
272
|
(request as FastifyExtended).parsedQuery = sanitizeKeys(body as Record<string, unknown>)
|
|
246
273
|
}
|
|
247
274
|
|
|
248
|
-
function buildResolveContext<TCtx, TPrisma extends PrismaClientLike>(
|
|
249
|
-
config: ${modelName}RouteConfig<TCtx, TPrisma>,
|
|
250
|
-
request: FastifyRequest,
|
|
251
|
-
): (() => unknown | Promise<unknown>) | undefined {
|
|
252
|
-
if (typeof config.resolveContext !== 'function') return undefined
|
|
253
|
-
return () => (config.resolveContext as (r: FastifyRequest) => unknown | Promise<unknown>)(request)
|
|
254
|
-
}
|
|
255
|
-
|
|
256
275
|
function makeShapeHook<TCtx, TPrisma extends PrismaClientLike>(
|
|
257
276
|
config: ${modelName}RouteConfig<TCtx, TPrisma>,
|
|
258
277
|
opConfig: NormalizedOp,
|
|
@@ -272,8 +291,7 @@ function makeShapeHook<TCtx, TPrisma extends PrismaClientLike>(
|
|
|
272
291
|
return async (request: FastifyRequest) => {
|
|
273
292
|
const fx = request as FastifyExtended
|
|
274
293
|
fx.operationOverride = opConfig.override
|
|
275
|
-
|
|
276
|
-
fx.resolveOperationContext = () => context ??= Promise.resolve(config.resolveContext?.(request))
|
|
294
|
+
fx.getContext = memoizeContext(() => config.resolveContext?.(request))
|
|
277
295
|
const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
|
|
278
296
|
if (merged) fx.routeConfig = { pagination: merged }
|
|
279
297
|
|
|
@@ -284,46 +302,28 @@ function makeShapeHook<TCtx, TPrisma extends PrismaClientLike>(
|
|
|
284
302
|
?? undefined
|
|
285
303
|
if (typeof caller === 'string') fx.guardCaller = caller
|
|
286
304
|
|
|
287
|
-
const
|
|
288
|
-
if (!
|
|
289
|
-
fx.
|
|
305
|
+
const routed = routeOperation({ guardRouting: opConfig.guardRouting, caller })
|
|
306
|
+
if (!routed.ok) {
|
|
307
|
+
fx.routeFailure = routed
|
|
290
308
|
return
|
|
291
309
|
}
|
|
292
310
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
buildResolveContext(config, request),
|
|
307
|
-
opKind,
|
|
308
|
-
{
|
|
309
|
-
readQuery: fx.parsedQuery,
|
|
310
|
-
writeBody: isPlainObject(request.body)
|
|
311
|
-
? (request.body as Record<string, unknown>)
|
|
312
|
-
: undefined,
|
|
313
|
-
},
|
|
314
|
-
() => {
|
|
315
|
-
if (!fx.parsedQuery) fx.parsedQuery = {}
|
|
316
|
-
return fx.parsedQuery
|
|
317
|
-
},
|
|
318
|
-
() => {
|
|
319
|
-
if (!isPlainObject(request.body)) {
|
|
320
|
-
;(request as unknown as { body: unknown }).body = {}
|
|
321
|
-
}
|
|
322
|
-
return request.body as Record<string, unknown>
|
|
323
|
-
},
|
|
324
|
-
)
|
|
325
|
-
}
|
|
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
|
|
326
324
|
}
|
|
325
|
+
|
|
326
|
+
fx.guardShape = guard.guardShape
|
|
327
327
|
}
|
|
328
328
|
}
|
|
329
329
|
|
|
@@ -464,12 +464,8 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma extends Pris
|
|
|
464
464
|
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
465
465
|
|
|
466
466
|
const fx = request as FastifyExtended
|
|
467
|
-
if (fx.
|
|
468
|
-
|
|
469
|
-
400,
|
|
470
|
-
formatGuardVariantResolutionError(fx.guardVariantFailure),
|
|
471
|
-
)
|
|
472
|
-
}
|
|
467
|
+
if (fx.routeFailure) settleStage(fx.routeFailure)
|
|
468
|
+
if (fx.guardFailure) settleStage(fx.guardFailure)
|
|
473
469
|
|
|
474
470
|
const key = fx.guardVariantKey
|
|
475
471
|
const variantHooks =
|
|
@@ -496,12 +492,8 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma extends Pris
|
|
|
496
492
|
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
497
493
|
|
|
498
494
|
const fx = request as FastifyExtended
|
|
499
|
-
if (fx.
|
|
500
|
-
|
|
501
|
-
400,
|
|
502
|
-
formatGuardVariantResolutionError(fx.guardVariantFailure),
|
|
503
|
-
)
|
|
504
|
-
}
|
|
495
|
+
if (fx.routeFailure) settleStage(fx.routeFailure)
|
|
496
|
+
if (fx.guardFailure) settleStage(fx.guardFailure)
|
|
505
497
|
|
|
506
498
|
const key = fx.guardVariantKey
|
|
507
499
|
const variantHooks =
|