prisma-generator-express 1.65.2 → 1.67.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 +51 -3480
- 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.js +69 -6
- package/dist/copy/operationDefinitions.js.map +1 -1
- package/dist/generators/generateFastifyHandler.d.ts +2 -2
- package/dist/generators/generateFastifyHandler.js +15 -5
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.d.ts +2 -2
- package/dist/generators/generateHonoHandler.js +12 -5
- package/dist/generators/generateHonoHandler.js.map +1 -1
- 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/generateModelMetadata.js +20 -10
- 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/generateQueryBuilderHelper.d.ts +1 -1
- package/dist/generators/generateQueryBuilderHelper.js +2 -4
- package/dist/generators/generateQueryBuilderHelper.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 +107 -14
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +7 -4
- package/dist/generators/generateRouterFastify.js +56 -28
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.d.ts +7 -4
- package/dist/generators/generateRouterHono.js +84 -53
- package/dist/generators/generateRouterHono.js.map +1 -1
- 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 +11 -3
- 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 +1 -1
- package/dist/index.js +22 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.js +22 -6
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/importExt.d.ts +1 -1
- 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.map +1 -1
- package/package.json +16 -3
- 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 +153 -50
- package/src/copy/concurrency.ts +10 -8
- package/src/copy/errorMapper.ts +68 -19
- package/src/copy/guardHelpers.ts +30 -9
- package/src/copy/materializedCount.ts +17 -5
- package/src/copy/misc.ts +88 -68
- package/src/copy/ndjson.ts +72 -0
- package/src/copy/operationDefinitions.ts +99 -21
- package/src/copy/operationRuntime.ts +100 -12
- package/src/copy/pagination.ts +25 -11
- 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 +19 -9
- package/src/copy/routeConfig.ts +174 -39
- package/src/copy/scalarTypes.ts +7 -2
- package/src/copy/sse.ts +72 -19
- package/src/generators/generateFastifyHandler.ts +24 -13
- package/src/generators/generateHonoHandler.ts +21 -13
- package/src/generators/generateImportPrismaStatement.ts +93 -81
- package/src/generators/generateModelMetadata.ts +24 -12
- package/src/generators/generateOperationCore.ts +81 -33
- package/src/generators/generateQueryBuilderHelper.ts +20 -4
- package/src/generators/generateRelationMeta.ts +23 -11
- package/src/generators/generateRouteConfigType.ts +39 -13
- package/src/generators/generateRouter.ts +114 -17
- package/src/generators/generateRouterFastify.ts +67 -31
- package/src/generators/generateRouterHono.ts +108 -60
- package/src/generators/generateUnifiedDocs.ts +29 -8
- package/src/generators/generateUnifiedHandler.ts +16 -8
- package/src/generators/generateUnifiedScalarUI.ts +1 -1
- package/src/guardOptions.ts +105 -92
- package/src/index.ts +46 -4
- package/src/utils/copyFiles.ts +199 -168
- package/src/utils/importExt.ts +2 -2
- 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 +6 -2
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateRouterFunction = generateRouterFunction;
|
|
4
4
|
const generateRouteConfigType_1 = require("./generateRouteConfigType");
|
|
5
5
|
const importExt_1 = require("../utils/importExt");
|
|
6
|
+
const pathCasing_1 = require("../utils/pathCasing");
|
|
6
7
|
const operationDefinitions_1 = require("../copy/operationDefinitions");
|
|
7
8
|
function pathExpr(basePath, suffix) {
|
|
8
9
|
if (!suffix)
|
|
@@ -50,10 +51,11 @@ function emitReadOp(meta, modelName) {
|
|
|
50
51
|
const pathValue = pathExpr('basePath', meta.pathSuffix);
|
|
51
52
|
const opKind = opKindFor(meta.name);
|
|
52
53
|
const postReadBlock = meta.supportsPostRead
|
|
53
|
-
? ` if (
|
|
54
|
+
? ` if (resolvePostReadsEnabled(config.disablePostReads, opConfig.disablePostReads)) {
|
|
54
55
|
const postPath = ${meta.name === 'findMany' ? "basePath ? `${basePath}/read` : '/read'" : `path`}
|
|
55
56
|
router.post(
|
|
56
57
|
postPath,
|
|
58
|
+
...(opConfig.authorize ? [opConfig.authorize] : []),
|
|
57
59
|
parseBodyAsQuery,
|
|
58
60
|
setShape(opConfig, '${opKind}'),
|
|
59
61
|
...opConfig.operationBefore,
|
|
@@ -71,12 +73,14 @@ function emitReadOp(meta, modelName) {
|
|
|
71
73
|
const path = ${pathValue}
|
|
72
74
|
router.get(
|
|
73
75
|
path,
|
|
76
|
+
...(opConfig.authorize ? [opConfig.authorize] : []),
|
|
74
77
|
parseQuery,
|
|
75
78
|
setShape(opConfig, '${opKind}'),
|
|
76
79
|
...opConfig.operationBefore,
|
|
77
80
|
requireVariantKey(),
|
|
78
81
|
variantBeforeDispatcher(opConfig),
|
|
79
82
|
maybeProgressiveSSE(opConfig, core.${meta.coreName}, '${meta.name}'),
|
|
83
|
+
${meta.name === 'findMany' ? 'maybeNdjsonFindMany(core.findMany),' : ''}
|
|
80
84
|
${handlerName} as RequestHandler,
|
|
81
85
|
variantAfterDispatcher(opConfig),
|
|
82
86
|
...opConfig.operationAfter,
|
|
@@ -96,6 +100,7 @@ function emitWriteOp(meta, modelName) {
|
|
|
96
100
|
const path = ${pathValue}
|
|
97
101
|
router.${meta.method}(
|
|
98
102
|
path,
|
|
103
|
+
...(opConfig.authorize ? [opConfig.authorize] : []),
|
|
99
104
|
setShape(opConfig, '${opKind}'),
|
|
100
105
|
...opConfig.operationBefore,
|
|
101
106
|
requireVariantKey(),
|
|
@@ -107,10 +112,10 @@ function emitWriteOp(meta, modelName) {
|
|
|
107
112
|
)
|
|
108
113
|
}`;
|
|
109
114
|
}
|
|
110
|
-
function generateRouterFunction({ model, enums, guardShapesImport, importStyle, writeStrategy, findManyPaginatedMode, dropGuard, }) {
|
|
115
|
+
function generateRouterFunction({ model, enums, guardShapesImport, clientImport, importStyle, writeStrategy, findManyPaginatedMode, dropGuard, pathCase, }) {
|
|
111
116
|
const ext = (0, importExt_1.importExt)(importStyle);
|
|
112
117
|
const modelName = model.name;
|
|
113
|
-
const
|
|
118
|
+
const modelSegment = (0, pathCasing_1.modelPathSegment)(modelName, pathCase);
|
|
114
119
|
const delegateKey = modelName.charAt(0).toLowerCase() + modelName.slice(1);
|
|
115
120
|
const routerFunctionName = `${modelName}Router`;
|
|
116
121
|
const handlerImports = operationDefinitions_1.OPERATION_METADATA.filter((m) => m.name !== 'updateEach')
|
|
@@ -134,9 +139,10 @@ import type {
|
|
|
134
139
|
QueryBuilderConfig,
|
|
135
140
|
FindManyPaginatedMode,
|
|
136
141
|
PaginationConfig,
|
|
142
|
+
PrismaClientLike,
|
|
137
143
|
} from '../routeConfig.target${ext}'
|
|
138
144
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
139
|
-
import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject } from '../misc${ext}'
|
|
145
|
+
import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject, resolveDropGuardEnv } from '../misc${ext}'
|
|
140
146
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
141
147
|
import {
|
|
142
148
|
normalizeOperation,
|
|
@@ -144,7 +150,10 @@ import {
|
|
|
144
150
|
validateCountSourceWhere,
|
|
145
151
|
validateOperationConfig,
|
|
146
152
|
validateUpdateEachConfig,
|
|
153
|
+
resolvePostReadsEnabled,
|
|
154
|
+
warnIfUnguardedRoutes,
|
|
147
155
|
} from '../routeConfig${ext}'
|
|
156
|
+
import type { RuntimeOperationOverride } from '../operationRuntime${ext}'
|
|
148
157
|
import type { NormalizedOperationConfig } from '../routeConfig${ext}'
|
|
149
158
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
150
159
|
import { transformResult } from '../operationRuntime${ext}'
|
|
@@ -152,6 +161,7 @@ import { HttpError, mapError } from '../errorMapper${ext}'
|
|
|
152
161
|
import { formatGuardVariantResolutionError } from '../guardVariantError${ext}'
|
|
153
162
|
import type { GuardVariantResolution } from '../guardVariantRouting${ext}'
|
|
154
163
|
import { mergePaginationConfig } from '../pagination${ext}'
|
|
164
|
+
import { acceptsNdjson, runNdjsonFindMany } from '../ndjson${ext}'
|
|
155
165
|
import {
|
|
156
166
|
acceptsEventStream,
|
|
157
167
|
runProgressiveEndpoint,
|
|
@@ -165,13 +175,18 @@ import { applyDroppedGuard } from '../projectionDefaults${ext}'
|
|
|
165
175
|
import type { OpKind } from '../projectionDefaults${ext}'
|
|
166
176
|
import { MODEL_FIELDS, MODEL_ENUMS } from './${modelName}Metadata${ext}'
|
|
167
177
|
|
|
168
|
-
${(0, generateRouteConfigType_1.generateRouteConfigType)(modelName, 'RequestHandler', guardShapesImport, importStyle, 'express')}
|
|
178
|
+
${(0, generateRouteConfigType_1.generateRouteConfigType)(modelName, 'RequestHandler', guardShapesImport, importStyle, 'express', clientImport)}
|
|
169
179
|
const _env = getEnv()
|
|
170
180
|
|
|
171
181
|
const FIND_MANY_PAGINATED_MODE: FindManyPaginatedMode = '${findManyPaginatedMode}'
|
|
172
|
-
|
|
182
|
+
// Fixed at generation time. The environment bypass is resolved per router,
|
|
183
|
+
// because it requires the configuration's explicit \`allowE2EGuardBypass: true\`:
|
|
184
|
+
// false or omitted means the environment cannot drop guards for this target.
|
|
185
|
+
const DROP_GUARD = ${dropGuard}
|
|
173
186
|
|
|
174
187
|
type OperationConfigLike = {
|
|
188
|
+
authorize?: RequestHandler
|
|
189
|
+
override?: RuntimeOperationOverride
|
|
175
190
|
before?: RequestHandler[]
|
|
176
191
|
after?: RequestHandler[]
|
|
177
192
|
shape?: unknown
|
|
@@ -194,7 +209,7 @@ type NormalizedOp = NormalizedOperationConfig<RequestHandler, RequestHandler> &
|
|
|
194
209
|
}
|
|
195
210
|
|
|
196
211
|
type ExtendedRequest = Request & {
|
|
197
|
-
prisma?:
|
|
212
|
+
prisma?: PrismaClientLike
|
|
198
213
|
postgres?: unknown
|
|
199
214
|
sqlite?: unknown
|
|
200
215
|
}
|
|
@@ -204,6 +219,8 @@ type LocalsBag = {
|
|
|
204
219
|
routeConfig?: { pagination?: PaginationConfig }
|
|
205
220
|
guardShape?: Record<string, unknown>
|
|
206
221
|
guardCaller?: string
|
|
222
|
+
operationOverride?: RuntimeOperationOverride
|
|
223
|
+
resolveOperationContext?: () => unknown | Promise<unknown>
|
|
207
224
|
guardVariantKey?: string
|
|
208
225
|
guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
|
|
209
226
|
data?: unknown
|
|
@@ -321,7 +338,7 @@ function requireVariantKey(): RequestHandler {
|
|
|
321
338
|
}
|
|
322
339
|
}
|
|
323
340
|
|
|
324
|
-
export function ${routerFunctionName}<TCtx = unknown, TPrisma =
|
|
341
|
+
export function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClientLike = PrismaClientLike>(config: ${modelName}RouteConfig<TCtx, TPrisma> = {}) {
|
|
325
342
|
validateCountSourceWhere(config.pagination?.countSource, '${modelName} pagination')
|
|
326
343
|
validateCountSourceWhere(
|
|
327
344
|
(config.findManyPaginated && typeof config.findManyPaginated === 'object' ? config.findManyPaginated : undefined)?.pagination?.countSource,
|
|
@@ -331,6 +348,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
331
348
|
const router = express.Router()
|
|
332
349
|
|
|
333
350
|
const isEnabled = (value: unknown): boolean => value !== false && !!(config.enableAll || value)
|
|
351
|
+
warnIfUnguardedRoutes('${modelName}', ['findMany', 'findUnique', 'findUniqueOrThrow', 'findFirst', 'findFirstOrThrow', 'findManyPaginated', 'count', 'aggregate', 'groupBy', 'create', 'createMany', 'createManyAndReturn', 'update', 'updateMany', 'updateManyAndReturn', 'upsert', 'delete', 'deleteMany'], config, isEnabled)
|
|
334
352
|
|
|
335
353
|
const opFor = (key: string): NormalizedOp => {
|
|
336
354
|
const raw = (config as unknown as Record<string, unknown>)[key] as OperationConfigLike | undefined
|
|
@@ -339,13 +357,12 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
339
357
|
}
|
|
340
358
|
|
|
341
359
|
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
342
|
-
const modelPrefix = config.addModelPrefix !== false ? '/${
|
|
360
|
+
const modelPrefix = config.addModelPrefix !== false ? '/${modelSegment}' : ''
|
|
343
361
|
const basePath = customPrefix + modelPrefix
|
|
344
362
|
|
|
345
363
|
const openApiDisabled = config.disableOpenApi === true
|
|
346
364
|
|| (config.disableOpenApi !== false && (_env.DISABLE_OPENAPI === 'true' || _env.NODE_ENV === 'production'))
|
|
347
365
|
|
|
348
|
-
const postReadsEnabled = !config.disablePostReads
|
|
349
366
|
|
|
350
367
|
let _openApiJsonCache: unknown = undefined
|
|
351
368
|
const getOpenApiJson = (): unknown => {
|
|
@@ -355,7 +372,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
355
372
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
356
373
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
357
374
|
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
358
|
-
{ format: 'json', writeStrategy: '${writeStrategy}' },
|
|
375
|
+
{ format: 'json', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
|
|
359
376
|
)
|
|
360
377
|
}
|
|
361
378
|
return _openApiJsonCache
|
|
@@ -368,7 +385,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
368
385
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
369
386
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
370
387
|
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
371
|
-
{ format: 'yaml', writeStrategy: '${writeStrategy}' },
|
|
388
|
+
{ format: 'yaml', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
|
|
372
389
|
) as string
|
|
373
390
|
}
|
|
374
391
|
return _openApiYamlCache
|
|
@@ -390,6 +407,8 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
390
407
|
const extReq = req as ExtendedRequest
|
|
391
408
|
const locals = readLocals(res)
|
|
392
409
|
return {
|
|
410
|
+
operationOverride: locals.operationOverride,
|
|
411
|
+
resolveOperationContext: locals.resolveOperationContext,
|
|
393
412
|
prisma: extReq.prisma,
|
|
394
413
|
postgres: extReq.postgres,
|
|
395
414
|
sqlite: extReq.sqlite,
|
|
@@ -397,6 +416,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
397
416
|
body: req.body,
|
|
398
417
|
guardShape: locals.guardShape,
|
|
399
418
|
guardCaller: locals.guardCaller,
|
|
419
|
+
guardVariantKey: locals.guardVariantKey,
|
|
400
420
|
paginationConfig: locals.routeConfig?.pagination,
|
|
401
421
|
findManyPaginatedMode: FIND_MANY_PAGINATED_MODE,
|
|
402
422
|
}
|
|
@@ -424,10 +444,25 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
424
444
|
next()
|
|
425
445
|
}
|
|
426
446
|
|
|
447
|
+
/**
|
|
448
|
+
* The environment bypass, and it is OPT-IN for this target.
|
|
449
|
+
*
|
|
450
|
+
* \`PGE_DROP_GUARD=true\` (deprecated alias \`E2E=true\`) downgrading enforcement
|
|
451
|
+
* in a deployed environment is a real hazard: on most platforms it is an
|
|
452
|
+
* ordinary config var, set on staging, copied forward, flagged as
|
|
453
|
+
* security-relevant nowhere. It is honoured only when this configuration
|
|
454
|
+
* states \`allowE2EGuardBypass: true\` — false or omitted means the environment
|
|
455
|
+
* cannot drop guards. The generation-time \`DROP_GUARD\` literal is unchanged.
|
|
456
|
+
*/
|
|
457
|
+
const dropGuard = DROP_GUARD || (config.allowE2EGuardBypass === true && resolveDropGuardEnv(_env))
|
|
458
|
+
|
|
427
459
|
const setShape = (opConfig: NormalizedOp, opKind: OpKind): RequestHandler => {
|
|
428
460
|
return async (req, res, next) => {
|
|
429
461
|
try {
|
|
430
462
|
const locals = readLocals(res)
|
|
463
|
+
locals.operationOverride = opConfig.override
|
|
464
|
+
let context: Promise<unknown> | undefined
|
|
465
|
+
locals.resolveOperationContext = () => context ??= Promise.resolve(config.resolveContext?.(req))
|
|
431
466
|
const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
|
|
432
467
|
if (merged) {
|
|
433
468
|
locals.routeConfig = { pagination: merged }
|
|
@@ -452,7 +487,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
452
487
|
if (resolvedKey !== undefined) locals.guardVariantKey = resolvedKey
|
|
453
488
|
|
|
454
489
|
if (opConfig.guardShape) {
|
|
455
|
-
if (!
|
|
490
|
+
if (!dropGuard) {
|
|
456
491
|
locals.guardShape = opConfig.guardShape
|
|
457
492
|
} else {
|
|
458
493
|
await applyDroppedGuard(
|
|
@@ -487,6 +522,41 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
487
522
|
}
|
|
488
523
|
}
|
|
489
524
|
|
|
525
|
+
const maybeNdjsonFindMany = (
|
|
526
|
+
coreFn: (ctx: OperationContext) => Promise<unknown>,
|
|
527
|
+
): RequestHandler => {
|
|
528
|
+
return async (req, res, next) => {
|
|
529
|
+
if (res.headersSent || res.writableEnded) return next()
|
|
530
|
+
if (req.method !== 'GET') return next()
|
|
531
|
+
if (!acceptsNdjson(req.headers.accept)) return next()
|
|
532
|
+
|
|
533
|
+
const locals = readLocals(res)
|
|
534
|
+
const rawArgs = (locals.parsedQuery ?? {}) as Record<string, unknown>
|
|
535
|
+
const args = { ...rawArgs }
|
|
536
|
+
const paginationCfg = mergePaginationConfig(config.pagination, undefined)
|
|
537
|
+
const requestedTake = typeof rawArgs.take === 'number' ? rawArgs.take : undefined
|
|
538
|
+
const initialSkip = typeof rawArgs.skip === 'number' ? rawArgs.skip : 0
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
await runNdjsonFindMany({
|
|
542
|
+
res,
|
|
543
|
+
isClosed: () => req.destroyed,
|
|
544
|
+
fetchPage: (skip, pageTake) =>
|
|
545
|
+
coreFn({
|
|
546
|
+
...buildContext(req, res),
|
|
547
|
+
parsedQuery: { ...args, skip, take: pageTake },
|
|
548
|
+
}),
|
|
549
|
+
initialSkip,
|
|
550
|
+
requestedTake,
|
|
551
|
+
defaultLimit: paginationCfg?.defaultLimit,
|
|
552
|
+
maxLimit: paginationCfg?.maxLimit ?? 1000,
|
|
553
|
+
})
|
|
554
|
+
} catch (err) {
|
|
555
|
+
next(err)
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
490
560
|
const maybeProgressiveSSE = (
|
|
491
561
|
opConfig: NormalizedOp,
|
|
492
562
|
coreFn: (ctx: OperationContext) => Promise<unknown>,
|
|
@@ -513,6 +583,23 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
513
583
|
}
|
|
514
584
|
|
|
515
585
|
if (progressiveConfig.mode === 'autoInclude') {
|
|
586
|
+
if (progressiveConfig.experimental !== true) {
|
|
587
|
+
if (_env.NODE_ENV !== 'production') {
|
|
588
|
+
console.warn(
|
|
589
|
+
'[prisma-generator-express] auto-include progressive is experimental; set \`experimental: true\` on the progressive config to enable it. Falling back.'
|
|
590
|
+
)
|
|
591
|
+
}
|
|
592
|
+
if (progressiveConfig.fallback === 'error') {
|
|
593
|
+
emitTerminalSSEError(res, 'auto-include requires experimental: true')
|
|
594
|
+
return
|
|
595
|
+
}
|
|
596
|
+
await runSingleResultSSE({
|
|
597
|
+
req,
|
|
598
|
+
res,
|
|
599
|
+
coreQueryFn: () => coreFn(buildContext(req, res)),
|
|
600
|
+
})
|
|
601
|
+
return
|
|
602
|
+
}
|
|
516
603
|
const isAutoIncludeReadable =
|
|
517
604
|
baseOp === 'findUnique' || baseOp === 'findUniqueOrThrow' ||
|
|
518
605
|
baseOp === 'findFirst' || baseOp === 'findFirstOrThrow' ||
|
|
@@ -580,11 +667,16 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${m
|
|
|
580
667
|
}
|
|
581
668
|
|
|
582
669
|
const ctx = await config.resolveContext(req)
|
|
670
|
+
const prismaClient = (req as ExtendedRequest).prisma
|
|
671
|
+
if (!prismaClient) {
|
|
672
|
+
emitTerminalSSEError(res, 'Progressive endpoint requires req.prisma to be set')
|
|
673
|
+
return
|
|
674
|
+
}
|
|
583
675
|
await runProgressiveEndpoint({
|
|
584
676
|
req,
|
|
585
677
|
res,
|
|
586
678
|
ctx,
|
|
587
|
-
prisma:
|
|
679
|
+
prisma: prismaClient,
|
|
588
680
|
variant: variant as string,
|
|
589
681
|
stages: progressiveConfig.stages,
|
|
590
682
|
stageRegistry,
|
|
@@ -640,6 +732,7 @@ ${writeOpBlocks}
|
|
|
640
732
|
const path = basePath ? \`\${basePath}/each\` : '/each'
|
|
641
733
|
router.post(
|
|
642
734
|
path,
|
|
735
|
+
...(opConfig.authorize ? [opConfig.authorize] : []),
|
|
643
736
|
setShape(opConfig, 'noop'),
|
|
644
737
|
...opConfig.operationBefore,
|
|
645
738
|
async (req: Request, res: Response, next: NextFunction) => {
|
|
@@ -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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"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { DMMF } from '@prisma/generator-helper';
|
|
2
|
-
import { ImportStyle } from '../utils/resolveImportStyle';
|
|
3
|
-
import { WriteStrategy, FindManyPaginatedMode } from '../constants';
|
|
4
|
-
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper';
|
|
2
|
+
import type { ImportStyle } from '../utils/resolveImportStyle';
|
|
3
|
+
import type { WriteStrategy, FindManyPaginatedMode } from '../constants';
|
|
4
|
+
import { type PathCase } from '../utils/pathCasing';
|
|
5
|
+
export declare function generateFastifyRouterFunction({ model, enums, guardShapesImport, clientImport, importStyle, writeStrategy, findManyPaginatedMode, dropGuard, pathCase, }: {
|
|
5
6
|
model: DMMF.Model;
|
|
6
7
|
enums: DMMF.DatamodelEnum[];
|
|
7
8
|
guardShapesImport: string | null;
|
|
9
|
+
clientImport?: string;
|
|
8
10
|
importStyle: ImportStyle;
|
|
9
11
|
writeStrategy: WriteStrategy;
|
|
10
12
|
findManyPaginatedMode: FindManyPaginatedMode;
|
|
11
13
|
dropGuard: boolean;
|
|
14
|
+
pathCase: PathCase;
|
|
12
15
|
}): string;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateFastifyRouterFunction = generateFastifyRouterFunction;
|
|
4
4
|
const generateRouteConfigType_1 = require("./generateRouteConfigType");
|
|
5
5
|
const importExt_1 = require("../utils/importExt");
|
|
6
|
+
const pathCasing_1 = require("../utils/pathCasing");
|
|
6
7
|
const operationDefinitions_1 = require("../copy/operationDefinitions");
|
|
7
8
|
function pathExpr(suffix) {
|
|
8
9
|
if (!suffix)
|
|
@@ -49,11 +50,11 @@ function emitReadOp(meta, modelName) {
|
|
|
49
50
|
const opKind = opKindFor(meta.name);
|
|
50
51
|
const postReadLine = meta.supportsPostRead
|
|
51
52
|
? meta.name === 'findMany'
|
|
52
|
-
? ` if (
|
|
53
|
+
? ` if (resolvePostReadsEnabled(config.disablePostReads, opConfig.disablePostReads)) {
|
|
53
54
|
const postPath = basePath ? \`\${basePath}/read\` : '/read'
|
|
54
55
|
instance.post(postPath, handleRead(opConfig, ${handlerName}, parseBodyAsQueryHook, '${opKind}'))
|
|
55
56
|
}`
|
|
56
|
-
: ` if (
|
|
57
|
+
: ` if (resolvePostReadsEnabled(config.disablePostReads, opConfig.disablePostReads)) instance.post(path, handleRead(opConfig, ${handlerName}, parseBodyAsQueryHook, '${opKind}'))`
|
|
57
58
|
: '';
|
|
58
59
|
return ` if (isEnabled(config.${meta.configKey})) {
|
|
59
60
|
const opConfig = opFor('${meta.configKey}')
|
|
@@ -73,19 +74,18 @@ function emitWriteOp(meta, modelName) {
|
|
|
73
74
|
instance.${meta.method}(path, handleWrite(opConfig, ${handlerName}, '${opKind}'))
|
|
74
75
|
}`;
|
|
75
76
|
}
|
|
76
|
-
function generateFastifyRouterFunction({ model, enums, guardShapesImport, importStyle, writeStrategy, findManyPaginatedMode, dropGuard, }) {
|
|
77
|
+
function generateFastifyRouterFunction({ model, enums, guardShapesImport, clientImport, importStyle, writeStrategy, findManyPaginatedMode, dropGuard, pathCase, }) {
|
|
77
78
|
const ext = (0, importExt_1.importExt)(importStyle);
|
|
78
79
|
const modelName = model.name;
|
|
79
|
-
const
|
|
80
|
-
const routerFunctionName = `${
|
|
81
|
-
const handlerImports = operationDefinitions_1.OPERATION_METADATA
|
|
82
|
-
.map((m) => ` ${modelName}${m.name.charAt(0).toUpperCase() + m.name.slice(1)},`)
|
|
83
|
-
.join('\n');
|
|
80
|
+
const modelSegment = (0, pathCasing_1.modelPathSegment)(model.name, pathCase);
|
|
81
|
+
const routerFunctionName = `${model.name}Router`;
|
|
82
|
+
const handlerImports = operationDefinitions_1.OPERATION_METADATA.map((m) => ` ${modelName}${m.name.charAt(0).toUpperCase() + m.name.slice(1)},`).join('\n');
|
|
84
83
|
const readOps = operationDefinitions_1.OPERATION_METADATA.filter((m) => m.kind === 'read');
|
|
85
|
-
const writeOps = operationDefinitions_1.OPERATION_METADATA.filter((m) => m.kind === 'write' || m.kind === 'batch')
|
|
86
|
-
.filter((m) => m.name !== 'updateEach');
|
|
84
|
+
const writeOps = operationDefinitions_1.OPERATION_METADATA.filter((m) => m.kind === 'write' || m.kind === 'batch').filter((m) => m.name !== 'updateEach');
|
|
87
85
|
const readOpBlocks = readOps.map((m) => emitReadOp(m, modelName)).join('\n\n');
|
|
88
|
-
const writeOpBlocks = writeOps
|
|
86
|
+
const writeOpBlocks = writeOps
|
|
87
|
+
.map((m) => emitWriteOp(m, modelName))
|
|
88
|
+
.join('\n\n');
|
|
89
89
|
return `import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyError } from 'fastify'
|
|
90
90
|
import { startQueryBuilder } from '../queryBuilder${ext}'
|
|
91
91
|
import {
|
|
@@ -96,9 +96,11 @@ import type {
|
|
|
96
96
|
FastifyHookHandler,
|
|
97
97
|
FindManyPaginatedMode,
|
|
98
98
|
PaginationConfig,
|
|
99
|
+
PrismaClientLike,
|
|
100
|
+
QueryBuilderConfig,
|
|
99
101
|
} from '../routeConfig.target${ext}'
|
|
100
102
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
101
|
-
import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject } from '../misc${ext}'
|
|
103
|
+
import { sanitizeKeys, normalizePrefix, getEnv, isPlainObject, resolveDropGuardEnv } from '../misc${ext}'
|
|
102
104
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
103
105
|
import {
|
|
104
106
|
normalizeOperation,
|
|
@@ -106,7 +108,10 @@ import {
|
|
|
106
108
|
validateCountSourceWhere,
|
|
107
109
|
validateOperationConfig,
|
|
108
110
|
validateUpdateEachConfig,
|
|
111
|
+
resolvePostReadsEnabled,
|
|
112
|
+
warnIfUnguardedRoutes,
|
|
109
113
|
} from '../routeConfig${ext}'
|
|
114
|
+
import type { RuntimeOperationOverride } from '../operationRuntime${ext}'
|
|
110
115
|
import type { NormalizedOperationConfig } from '../routeConfig${ext}'
|
|
111
116
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
112
117
|
import { transformResult } from '../operationRuntime${ext}'
|
|
@@ -118,13 +123,18 @@ import { applyDroppedGuard } from '../projectionDefaults${ext}'
|
|
|
118
123
|
import type { OpKind } from '../projectionDefaults${ext}'
|
|
119
124
|
import { MODEL_FIELDS, MODEL_ENUMS } from './${modelName}Metadata${ext}'
|
|
120
125
|
|
|
121
|
-
${(0, generateRouteConfigType_1.generateRouteConfigType)(modelName, 'FastifyHookHandler', guardShapesImport, importStyle, 'fastify')}
|
|
126
|
+
${(0, generateRouteConfigType_1.generateRouteConfigType)(modelName, 'FastifyHookHandler', guardShapesImport, importStyle, 'fastify', clientImport)}
|
|
122
127
|
const _env = getEnv()
|
|
123
128
|
|
|
124
129
|
const FIND_MANY_PAGINATED_MODE: FindManyPaginatedMode = '${findManyPaginatedMode}'
|
|
125
|
-
|
|
130
|
+
// Fixed at generation time. The environment bypass is resolved per hook,
|
|
131
|
+
// because it requires the configuration's explicit \`allowE2EGuardBypass: true\`:
|
|
132
|
+
// false or omitted means the environment cannot drop guards for this target.
|
|
133
|
+
const DROP_GUARD = ${dropGuard}
|
|
126
134
|
|
|
127
135
|
type OperationConfigLike = {
|
|
136
|
+
authorize?: FastifyHookHandler
|
|
137
|
+
override?: RuntimeOperationOverride
|
|
128
138
|
before?: FastifyHookHandler[]
|
|
129
139
|
after?: FastifyHookHandler[]
|
|
130
140
|
shape?: unknown
|
|
@@ -152,6 +162,8 @@ type FastifyExtended = FastifyRequest & {
|
|
|
152
162
|
routeConfig?: { pagination?: PaginationConfig }
|
|
153
163
|
guardShape?: Record<string, unknown>
|
|
154
164
|
guardCaller?: string
|
|
165
|
+
operationOverride?: RuntimeOperationOverride
|
|
166
|
+
resolveOperationContext?: () => unknown | Promise<unknown>
|
|
155
167
|
guardVariantKey?: string
|
|
156
168
|
guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
|
|
157
169
|
resultData?: unknown
|
|
@@ -164,14 +176,14 @@ function normalizeFastifyOperation(
|
|
|
164
176
|
return normalizeOperation<FastifyHookHandler, FastifyHookHandler>(config)
|
|
165
177
|
}
|
|
166
178
|
|
|
167
|
-
function isQueryBuilderEnabled(config:
|
|
179
|
+
function isQueryBuilderEnabled(config: { queryBuilder?: QueryBuilderConfig | false }): boolean {
|
|
168
180
|
if (config.queryBuilder === false) return false
|
|
169
181
|
if (typeof config.queryBuilder === 'object' && config.queryBuilder.enabled === false) return false
|
|
170
182
|
if (_env.NODE_ENV === 'production') return false
|
|
171
183
|
return true
|
|
172
184
|
}
|
|
173
185
|
|
|
174
|
-
function getQueryBuilderConfig(config:
|
|
186
|
+
function getQueryBuilderConfig(config: { queryBuilder?: QueryBuilderConfig | false }) {
|
|
175
187
|
if (config.queryBuilder === false) return null
|
|
176
188
|
if (typeof config.queryBuilder === 'object') return config.queryBuilder
|
|
177
189
|
return {}
|
|
@@ -192,21 +204,35 @@ function parseBodyAsQueryHook(request: FastifyRequest): void {
|
|
|
192
204
|
(request as FastifyExtended).parsedQuery = sanitizeKeys(body as Record<string, unknown>)
|
|
193
205
|
}
|
|
194
206
|
|
|
195
|
-
function buildResolveContext(
|
|
196
|
-
config: ${modelName}RouteConfig,
|
|
207
|
+
function buildResolveContext<TCtx, TPrisma extends PrismaClientLike>(
|
|
208
|
+
config: ${modelName}RouteConfig<TCtx, TPrisma>,
|
|
197
209
|
request: FastifyRequest,
|
|
198
210
|
): (() => unknown | Promise<unknown>) | undefined {
|
|
199
211
|
if (typeof config.resolveContext !== 'function') return undefined
|
|
200
212
|
return () => (config.resolveContext as (r: FastifyRequest) => unknown | Promise<unknown>)(request)
|
|
201
213
|
}
|
|
202
214
|
|
|
203
|
-
function makeShapeHook(
|
|
204
|
-
config: ${modelName}RouteConfig,
|
|
215
|
+
function makeShapeHook<TCtx, TPrisma extends PrismaClientLike>(
|
|
216
|
+
config: ${modelName}RouteConfig<TCtx, TPrisma>,
|
|
205
217
|
opConfig: NormalizedOp,
|
|
206
218
|
opKind: OpKind,
|
|
207
219
|
): (request: FastifyRequest) => Promise<void> {
|
|
220
|
+
/**
|
|
221
|
+
* The environment bypass, and it is OPT-IN for this target.
|
|
222
|
+
*
|
|
223
|
+
* \`PGE_DROP_GUARD=true\` (deprecated alias \`E2E=true\`) downgrading enforcement
|
|
224
|
+
* in a deployed environment is a real hazard: on most platforms it is an
|
|
225
|
+
* ordinary config var, set on staging, copied forward, flagged as
|
|
226
|
+
* security-relevant nowhere. It is honoured only when this configuration
|
|
227
|
+
* states \`allowE2EGuardBypass: true\` — false or omitted means the environment
|
|
228
|
+
* cannot drop guards. The generation-time \`DROP_GUARD\` literal is unchanged.
|
|
229
|
+
*/
|
|
230
|
+
const dropGuard = DROP_GUARD || (config.allowE2EGuardBypass === true && resolveDropGuardEnv(_env))
|
|
208
231
|
return async (request: FastifyRequest) => {
|
|
209
232
|
const fx = request as FastifyExtended
|
|
233
|
+
fx.operationOverride = opConfig.override
|
|
234
|
+
let context: Promise<unknown> | undefined
|
|
235
|
+
fx.resolveOperationContext = () => context ??= Promise.resolve(config.resolveContext?.(request))
|
|
210
236
|
const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
|
|
211
237
|
if (merged) fx.routeConfig = { pagination: merged }
|
|
212
238
|
|
|
@@ -230,7 +256,7 @@ function makeShapeHook(
|
|
|
230
256
|
if (resolvedKey !== undefined) fx.guardVariantKey = resolvedKey
|
|
231
257
|
|
|
232
258
|
if (opConfig.guardShape) {
|
|
233
|
-
if (!
|
|
259
|
+
if (!dropGuard) {
|
|
234
260
|
fx.guardShape = opConfig.guardShape
|
|
235
261
|
} else {
|
|
236
262
|
await applyDroppedGuard(
|
|
@@ -289,7 +315,7 @@ function sendError(reply: FastifyReply, error: unknown): void {
|
|
|
289
315
|
reply.code(httpError.status).send({ message: httpError.message })
|
|
290
316
|
}
|
|
291
317
|
|
|
292
|
-
export async function ${routerFunctionName}<TCtx = unknown, TPrisma =
|
|
318
|
+
export async function ${routerFunctionName}<TCtx = unknown, TPrisma extends PrismaClientLike = PrismaClientLike>(
|
|
293
319
|
fastify: FastifyInstance,
|
|
294
320
|
config: ${modelName}RouteConfig<TCtx, TPrisma> = {},
|
|
295
321
|
) {
|
|
@@ -301,6 +327,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
301
327
|
|
|
302
328
|
await fastify.register(async (instance) => {
|
|
303
329
|
const isEnabled = (value: unknown): boolean => value !== false && !!(config.enableAll || value)
|
|
330
|
+
warnIfUnguardedRoutes('${modelName}', ['findMany', 'findUnique', 'findUniqueOrThrow', 'findFirst', 'findFirstOrThrow', 'findManyPaginated', 'count', 'aggregate', 'groupBy', 'create', 'createMany', 'createManyAndReturn', 'update', 'updateMany', 'updateManyAndReturn', 'upsert', 'delete', 'deleteMany'], config, isEnabled)
|
|
304
331
|
|
|
305
332
|
const opFor = (key: string): NormalizedOp => {
|
|
306
333
|
const raw = (config as unknown as Record<string, unknown>)[key] as OperationConfigLike | undefined
|
|
@@ -309,7 +336,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
309
336
|
}
|
|
310
337
|
|
|
311
338
|
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
312
|
-
const modelPrefix = config.addModelPrefix !== false ? '/${
|
|
339
|
+
const modelPrefix = config.addModelPrefix !== false ? '/${modelSegment}' : ''
|
|
313
340
|
const basePath = customPrefix + modelPrefix
|
|
314
341
|
|
|
315
342
|
const openApiDisabled = config.disableOpenApi === true
|
|
@@ -318,7 +345,6 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
318
345
|
|| _env.DISABLE_OPENAPI === 'true'
|
|
319
346
|
))
|
|
320
347
|
|
|
321
|
-
const postReadsEnabled = !config.disablePostReads
|
|
322
348
|
|
|
323
349
|
let _openApiJsonCache: unknown = undefined
|
|
324
350
|
const getOpenApiJson = (): unknown => {
|
|
@@ -327,8 +353,8 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
327
353
|
'${modelName}',
|
|
328
354
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
329
355
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
330
|
-
config,
|
|
331
|
-
{ format: 'json', writeStrategy: '${writeStrategy}' },
|
|
356
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
357
|
+
{ format: 'json', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
|
|
332
358
|
)
|
|
333
359
|
}
|
|
334
360
|
return _openApiJsonCache
|
|
@@ -340,8 +366,8 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
340
366
|
'${modelName}',
|
|
341
367
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
342
368
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
343
|
-
config,
|
|
344
|
-
{ format: 'yaml', writeStrategy: '${writeStrategy}' },
|
|
369
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
370
|
+
{ format: 'yaml', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
|
|
345
371
|
) as string
|
|
346
372
|
}
|
|
347
373
|
return _openApiYamlCache
|
|
@@ -391,6 +417,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
391
417
|
opKind: OpKind,
|
|
392
418
|
) => async (request: FastifyRequest, reply: FastifyReply) => {
|
|
393
419
|
try {
|
|
420
|
+
if (await runHooks(opConfig.authorize ? [opConfig.authorize] : [], request, reply)) return
|
|
394
421
|
parseFn(request)
|
|
395
422
|
await makeShapeHook(config, opConfig, opKind)(request)
|
|
396
423
|
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
@@ -423,6 +450,7 @@ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
|
|
|
423
450
|
opKind: OpKind,
|
|
424
451
|
) => async (request: FastifyRequest, reply: FastifyReply) => {
|
|
425
452
|
try {
|
|
453
|
+
if (await runHooks(opConfig.authorize ? [opConfig.authorize] : [], request, reply)) return
|
|
426
454
|
await makeShapeHook(config, opConfig, opKind)(request)
|
|
427
455
|
if (await runHooks(opConfig.operationBefore, request, reply)) return
|
|
428
456
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateRouterFastify.js","sourceRoot":"","sources":["../../src/generators/generateRouterFastify.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"generateRouterFastify.js","sourceRoot":"","sources":["../../src/generators/generateRouterFastify.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { DMMF } from '@prisma/generator-helper';
|
|
2
|
-
import { ImportStyle } from '../utils/resolveImportStyle';
|
|
3
|
-
import { WriteStrategy } from '../constants';
|
|
4
|
-
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper';
|
|
2
|
+
import type { ImportStyle } from '../utils/resolveImportStyle';
|
|
3
|
+
import type { WriteStrategy } from '../constants';
|
|
4
|
+
import { type PathCase } from '../utils/pathCasing';
|
|
5
|
+
export declare function generateHonoRouterFunction({ model, enums, guardShapesImport, clientImport, importStyle, writeStrategy, dropGuard, pathCase, }: {
|
|
5
6
|
model: DMMF.Model;
|
|
6
7
|
enums: DMMF.DatamodelEnum[];
|
|
7
8
|
guardShapesImport: string | null;
|
|
9
|
+
clientImport?: string;
|
|
8
10
|
importStyle: ImportStyle;
|
|
9
11
|
writeStrategy: WriteStrategy;
|
|
10
12
|
dropGuard: boolean;
|
|
13
|
+
pathCase: PathCase;
|
|
11
14
|
}): string;
|