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
package/src/copy/sse.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
ProgressiveStage,
|
|
6
6
|
ProgressiveStopResult,
|
|
7
7
|
ProgressivePatch,
|
|
8
|
+
PrismaClientLike,
|
|
8
9
|
} from './routeConfig'
|
|
9
10
|
|
|
10
11
|
export function acceptsEventStream(accept: string | undefined): boolean {
|
|
@@ -17,7 +18,11 @@ export function acceptsEventStream(accept: string | undefined): boolean {
|
|
|
17
18
|
|
|
18
19
|
const UNSAFE_PATH_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype'])
|
|
19
20
|
|
|
20
|
-
export function setByPath(
|
|
21
|
+
export function setByPath(
|
|
22
|
+
target: Record<string, unknown>,
|
|
23
|
+
path: string,
|
|
24
|
+
value: unknown,
|
|
25
|
+
): boolean {
|
|
21
26
|
const parts = path.split('.')
|
|
22
27
|
if (parts.length === 0) return false
|
|
23
28
|
for (const p of parts) {
|
|
@@ -31,8 +36,11 @@ export function setByPath(target: Record<string, unknown>, path: string, value:
|
|
|
31
36
|
if (process.env.NODE_ENV !== 'production') {
|
|
32
37
|
console.warn(
|
|
33
38
|
LOG_PREFIX,
|
|
34
|
-
'Dropping patch for "' +
|
|
35
|
-
|
|
39
|
+
'Dropping patch for "' +
|
|
40
|
+
path +
|
|
41
|
+
'": cannot traverse non-plain-object at segment "' +
|
|
42
|
+
part +
|
|
43
|
+
'"',
|
|
36
44
|
)
|
|
37
45
|
}
|
|
38
46
|
return false
|
|
@@ -61,7 +69,10 @@ export type SseWritable = {
|
|
|
61
69
|
destroyed: boolean
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
export function removeReqCloseListener(
|
|
72
|
+
export function removeReqCloseListener(
|
|
73
|
+
req: EventEmitterLike,
|
|
74
|
+
listener: () => void,
|
|
75
|
+
): void {
|
|
65
76
|
if (typeof req.off === 'function') {
|
|
66
77
|
req.off('close', listener)
|
|
67
78
|
} else if (typeof req.removeListener === 'function') {
|
|
@@ -75,12 +86,15 @@ export function initSSE(res: SseWritable): void {
|
|
|
75
86
|
res.setHeader('Cache-Control', 'no-cache, no-transform')
|
|
76
87
|
res.setHeader('Connection', 'keep-alive')
|
|
77
88
|
res.setHeader('X-Accel-Buffering', 'no')
|
|
89
|
+
res.setHeader('X-Stream-Protocol-Version', '1')
|
|
78
90
|
if (typeof res.flushHeaders === 'function') res.flushHeaders()
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
export function flushSSE(res: SseWritable): void {
|
|
82
94
|
if (typeof res.flush === 'function') {
|
|
83
|
-
try {
|
|
95
|
+
try {
|
|
96
|
+
res.flush()
|
|
97
|
+
} catch {}
|
|
84
98
|
}
|
|
85
99
|
}
|
|
86
100
|
|
|
@@ -96,11 +110,20 @@ export function sendSSE(res: SseWritable, payload: unknown): boolean {
|
|
|
96
110
|
}
|
|
97
111
|
}
|
|
98
112
|
|
|
99
|
-
export function sendSSEProgress(
|
|
113
|
+
export function sendSSEProgress(
|
|
114
|
+
res: SseWritable,
|
|
115
|
+
stage: string,
|
|
116
|
+
completed: number,
|
|
117
|
+
total: number,
|
|
118
|
+
): boolean {
|
|
100
119
|
return sendSSE(res, { type: 'progress', stage, completed, total })
|
|
101
120
|
}
|
|
102
121
|
|
|
103
|
-
export function sendSSEField(
|
|
122
|
+
export function sendSSEField(
|
|
123
|
+
res: SseWritable,
|
|
124
|
+
key: string,
|
|
125
|
+
value: unknown,
|
|
126
|
+
): boolean {
|
|
104
127
|
return sendSSE(res, { type: 'field', key, value })
|
|
105
128
|
}
|
|
106
129
|
|
|
@@ -126,7 +149,12 @@ export function sendSSENestedRelationBatch(
|
|
|
126
149
|
depth: number,
|
|
127
150
|
attachments: Array<{ locator: Array<number | string>; value: unknown }>,
|
|
128
151
|
): boolean {
|
|
129
|
-
return sendSSE(res, {
|
|
152
|
+
return sendSSE(res, {
|
|
153
|
+
type: 'nestedRelationBatch',
|
|
154
|
+
relationPath,
|
|
155
|
+
depth,
|
|
156
|
+
attachments,
|
|
157
|
+
})
|
|
130
158
|
}
|
|
131
159
|
|
|
132
160
|
export function sendSSEPageMeta(
|
|
@@ -157,7 +185,10 @@ export function safeSendError(res: SseWritable, message: string): void {
|
|
|
157
185
|
|
|
158
186
|
type IntervalHandle = ReturnType<typeof setInterval>
|
|
159
187
|
|
|
160
|
-
export function startSSEKeepalive(
|
|
188
|
+
export function startSSEKeepalive(
|
|
189
|
+
res: SseWritable,
|
|
190
|
+
intervalMs: number = 15000,
|
|
191
|
+
): IntervalHandle {
|
|
161
192
|
const handle = setInterval(() => {
|
|
162
193
|
if (res.writableEnded || res.destroyed) return
|
|
163
194
|
try {
|
|
@@ -170,12 +201,17 @@ export function startSSEKeepalive(res: SseWritable, intervalMs: number = 15000):
|
|
|
170
201
|
return handle
|
|
171
202
|
}
|
|
172
203
|
|
|
173
|
-
export function endSSE(
|
|
204
|
+
export function endSSE(
|
|
205
|
+
res: SseWritable,
|
|
206
|
+
keepaliveHandle: IntervalHandle | null,
|
|
207
|
+
): void {
|
|
174
208
|
if (keepaliveHandle) {
|
|
175
209
|
clearInterval(keepaliveHandle)
|
|
176
210
|
}
|
|
177
211
|
if (!res.writableEnded && !res.destroyed) {
|
|
178
|
-
try {
|
|
212
|
+
try {
|
|
213
|
+
res.end()
|
|
214
|
+
} catch {}
|
|
179
215
|
}
|
|
180
216
|
}
|
|
181
217
|
|
|
@@ -225,7 +261,9 @@ export interface RunSingleResultSSEOptions {
|
|
|
225
261
|
coreQueryFn: () => Promise<unknown>
|
|
226
262
|
}
|
|
227
263
|
|
|
228
|
-
export async function runSingleResultSSE(
|
|
264
|
+
export async function runSingleResultSSE(
|
|
265
|
+
options: RunSingleResultSSEOptions,
|
|
266
|
+
): Promise<void> {
|
|
229
267
|
const { req, res, coreQueryFn } = options
|
|
230
268
|
await withSSE({ res, label: 'single-result' }, async () => {
|
|
231
269
|
if (req.destroyed) return
|
|
@@ -236,20 +274,26 @@ export async function runSingleResultSSE(options: RunSingleResultSSEOptions): Pr
|
|
|
236
274
|
}
|
|
237
275
|
|
|
238
276
|
function isStopResult(value: unknown): value is ProgressiveStopResult<unknown> {
|
|
239
|
-
return
|
|
277
|
+
return (
|
|
278
|
+
typeof value === 'object' &&
|
|
279
|
+
value !== null &&
|
|
280
|
+
(value as { stop?: unknown }).stop === true
|
|
281
|
+
)
|
|
240
282
|
}
|
|
241
283
|
|
|
242
284
|
export interface RunProgressiveOptions {
|
|
243
285
|
req: EventEmitterLike
|
|
244
286
|
res: SseWritable
|
|
245
287
|
ctx: unknown
|
|
246
|
-
prisma:
|
|
288
|
+
prisma: PrismaClientLike
|
|
247
289
|
variant: string
|
|
248
290
|
stages: string[]
|
|
249
291
|
stageRegistry: Record<string, ProgressiveStage>
|
|
250
292
|
}
|
|
251
293
|
|
|
252
|
-
export async function runProgressiveEndpoint(
|
|
294
|
+
export async function runProgressiveEndpoint(
|
|
295
|
+
options: RunProgressiveOptions,
|
|
296
|
+
): Promise<void> {
|
|
253
297
|
const { req, res, ctx, prisma, variant, stages, stageRegistry } = options
|
|
254
298
|
const controller = new AbortController()
|
|
255
299
|
const onClose = () => controller.abort()
|
|
@@ -266,9 +310,18 @@ export async function runProgressiveEndpoint(options: RunProgressiveOptions): Pr
|
|
|
266
310
|
if (res.writableEnded || res.destroyed || signal.aborted) return
|
|
267
311
|
const stageName = stages[i]
|
|
268
312
|
const stage = stageRegistry[stageName]
|
|
269
|
-
if (!stage)
|
|
270
|
-
|
|
271
|
-
|
|
313
|
+
if (!stage)
|
|
314
|
+
throw new HttpError(500, 'Missing progressive stage: ' + stageName)
|
|
315
|
+
|
|
316
|
+
const result = await stage({
|
|
317
|
+
ctx,
|
|
318
|
+
req,
|
|
319
|
+
res,
|
|
320
|
+
prisma,
|
|
321
|
+
variant,
|
|
322
|
+
accumulated,
|
|
323
|
+
signal,
|
|
324
|
+
})
|
|
272
325
|
if (res.writableEnded || res.destroyed) return
|
|
273
326
|
|
|
274
327
|
if (isStopResult(result)) {
|
|
@@ -293,4 +346,4 @@ export async function runProgressiveEndpoint(options: RunProgressiveOptions): Pr
|
|
|
293
346
|
} finally {
|
|
294
347
|
removeReqCloseListener(req, onClose)
|
|
295
348
|
}
|
|
296
|
-
}
|
|
349
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DMMF } from '@prisma/generator-helper'
|
|
2
|
-
import { ImportStyle } from '../utils/resolveImportStyle'
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper'
|
|
2
|
+
import type { ImportStyle } from '../utils/resolveImportStyle'
|
|
3
3
|
import { importExt } from '../utils/importExt'
|
|
4
4
|
import { OPERATION_METADATA } from '../copy/operationDefinitions'
|
|
5
5
|
|
|
@@ -12,34 +12,69 @@ export function generateFastifyHandler(options: {
|
|
|
12
12
|
|
|
13
13
|
const readOps = OPERATION_METADATA.filter((m) => m.kind === 'read')
|
|
14
14
|
const writeOps = OPERATION_METADATA.filter(
|
|
15
|
-
(m) =>
|
|
15
|
+
(m) =>
|
|
16
|
+
(m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
const readHandlers = readOps
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const readHandlers = readOps
|
|
20
|
+
.map((meta) => {
|
|
21
|
+
const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
|
|
22
|
+
return `
|
|
21
23
|
export async function ${exportName}(
|
|
22
24
|
request: FastifyRequest,
|
|
23
25
|
_reply: FastifyReply,
|
|
24
26
|
): Promise<void> {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
+
const fx = request as FastifyExtended
|
|
28
|
+
const data = await executeOperation(
|
|
29
|
+
{ variantKey: fx.guardVariantKey, caller: fx.guardCaller },
|
|
30
|
+
{ guardShape: fx.guardShape },
|
|
31
|
+
{
|
|
32
|
+
core: core.${meta.coreName},
|
|
33
|
+
args: queryChannel(request),
|
|
34
|
+
body: request.body,
|
|
35
|
+
prisma: requirePrisma(fx.prisma),
|
|
36
|
+
postgres: fx.postgres,
|
|
37
|
+
sqlite: fx.sqlite,
|
|
38
|
+
pagination: fx.routeConfig?.pagination,
|
|
39
|
+
override: fx.operationOverride,
|
|
40
|
+
getContext: fx.getContext,
|
|
41
|
+
findManyPaginatedMode: fx.findManyPaginatedMode,
|
|
42
|
+
},
|
|
43
|
+
)
|
|
44
|
+
fx.resultData = data
|
|
27
45
|
}`
|
|
28
|
-
|
|
46
|
+
})
|
|
47
|
+
.join('\n')
|
|
29
48
|
|
|
30
|
-
const writeHandlers = writeOps
|
|
31
|
-
|
|
32
|
-
|
|
49
|
+
const writeHandlers = writeOps
|
|
50
|
+
.map((meta) => {
|
|
51
|
+
const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
|
|
52
|
+
return `
|
|
33
53
|
export async function ${exportName}(
|
|
34
54
|
request: FastifyRequest,
|
|
35
55
|
_reply: FastifyReply,
|
|
36
56
|
): Promise<void> {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
const fx = request as FastifyExtended
|
|
58
|
+
const data = await executeOperation(
|
|
59
|
+
{ variantKey: fx.guardVariantKey, caller: fx.guardCaller },
|
|
60
|
+
{ guardShape: fx.guardShape },
|
|
61
|
+
{
|
|
62
|
+
core: core.${meta.coreName},
|
|
63
|
+
args: queryChannel(request),
|
|
64
|
+
body: request.body,
|
|
65
|
+
prisma: requirePrisma(fx.prisma),
|
|
66
|
+
postgres: fx.postgres,
|
|
67
|
+
sqlite: fx.sqlite,
|
|
68
|
+
pagination: fx.routeConfig?.pagination,
|
|
69
|
+
override: fx.operationOverride,
|
|
70
|
+
getContext: fx.getContext,
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
fx.resultData = data
|
|
74
|
+
fx.resultStatus = ${meta.successStatus}
|
|
41
75
|
}`
|
|
42
|
-
|
|
76
|
+
})
|
|
77
|
+
.join('\n')
|
|
43
78
|
|
|
44
79
|
const updateEachExportName = `${modelName}UpdateEach`
|
|
45
80
|
const updateEachHandler = `
|
|
@@ -54,24 +89,45 @@ export async function ${updateEachExportName}(
|
|
|
54
89
|
|
|
55
90
|
return `import type { FastifyRequest, FastifyReply } from 'fastify'
|
|
56
91
|
import * as core from './${modelName}Core${ext}'
|
|
57
|
-
import type { OperationContext, FindManyPaginatedMode } from '../operationRuntime${ext}'
|
|
92
|
+
import type { RuntimeOperationOverride, OperationContext, FindManyPaginatedMode } from '../operationRuntime${ext}'
|
|
93
|
+
import type { PaginationConfig } from '../routeConfig${ext}'
|
|
94
|
+
import {
|
|
95
|
+
executeOperation,
|
|
96
|
+
requirePrisma,
|
|
97
|
+
type ArgsChannel,
|
|
98
|
+
} from '../operationPipeline${ext}'
|
|
58
99
|
|
|
59
100
|
type FastifyExtended = FastifyRequest & {
|
|
60
101
|
prisma?: unknown
|
|
61
102
|
postgres?: unknown
|
|
62
103
|
sqlite?: unknown
|
|
63
104
|
parsedQuery?: Record<string, unknown>
|
|
64
|
-
routeConfig?: { pagination?:
|
|
105
|
+
routeConfig?: { pagination?: PaginationConfig }
|
|
65
106
|
guardShape?: Record<string, unknown>
|
|
66
107
|
guardCaller?: string
|
|
108
|
+
guardVariantKey?: string
|
|
109
|
+
operationOverride?: RuntimeOperationOverride
|
|
110
|
+
getContext?: () => Promise<unknown>
|
|
67
111
|
findManyPaginatedMode?: FindManyPaginatedMode
|
|
68
112
|
resultData?: unknown
|
|
69
113
|
resultStatus?: number
|
|
70
114
|
}
|
|
71
115
|
|
|
116
|
+
function queryChannel(request: FastifyRequest): ArgsChannel {
|
|
117
|
+
const fx = request as FastifyExtended
|
|
118
|
+
return {
|
|
119
|
+
read: () => fx.parsedQuery,
|
|
120
|
+
write: (next) => {
|
|
121
|
+
fx.parsedQuery = next
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
72
126
|
function buildContext(request: FastifyRequest): OperationContext {
|
|
73
127
|
const req = request as FastifyExtended
|
|
74
128
|
return {
|
|
129
|
+
operationOverride: req.operationOverride,
|
|
130
|
+
resolveOperationContext: req.getContext,
|
|
75
131
|
prisma: req.prisma,
|
|
76
132
|
postgres: req.postgres,
|
|
77
133
|
sqlite: req.sqlite,
|
|
@@ -79,6 +135,7 @@ function buildContext(request: FastifyRequest): OperationContext {
|
|
|
79
135
|
body: request.body,
|
|
80
136
|
guardShape: req.guardShape,
|
|
81
137
|
guardCaller: req.guardCaller,
|
|
138
|
+
guardVariantKey: req.guardVariantKey,
|
|
82
139
|
paginationConfig: req.routeConfig?.pagination,
|
|
83
140
|
findManyPaginatedMode: req.findManyPaginatedMode,
|
|
84
141
|
}
|
|
@@ -87,4 +144,4 @@ ${readHandlers}
|
|
|
87
144
|
${writeHandlers}
|
|
88
145
|
${updateEachHandler}
|
|
89
146
|
`
|
|
90
|
-
}
|
|
147
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DMMF } from '@prisma/generator-helper'
|
|
2
|
-
import { ImportStyle } from '../utils/resolveImportStyle'
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper'
|
|
2
|
+
import type { ImportStyle } from '../utils/resolveImportStyle'
|
|
3
3
|
import { importExt } from '../utils/importExt'
|
|
4
4
|
import { OPERATION_METADATA } from '../copy/operationDefinitions'
|
|
5
5
|
|
|
@@ -12,27 +12,60 @@ export function generateHonoHandler(options: {
|
|
|
12
12
|
|
|
13
13
|
const readOps = OPERATION_METADATA.filter((m) => m.kind === 'read')
|
|
14
14
|
const writeOps = OPERATION_METADATA.filter(
|
|
15
|
-
(m) =>
|
|
15
|
+
(m) =>
|
|
16
|
+
(m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
const readHandlers = readOps
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const readHandlers = readOps
|
|
20
|
+
.map((meta) => {
|
|
21
|
+
const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
|
|
22
|
+
return `
|
|
21
23
|
export async function ${exportName}(c: HandlerContext): Promise<void> {
|
|
22
|
-
const data = await
|
|
24
|
+
const data = await executeOperation(
|
|
25
|
+
{ variantKey: c.get('guardVariantKey'), caller: c.get('guardCaller') },
|
|
26
|
+
{ guardShape: c.get('guardShape') },
|
|
27
|
+
{
|
|
28
|
+
core: core.${meta.coreName},
|
|
29
|
+
args: queryChannel(c),
|
|
30
|
+
body: c.get('body'),
|
|
31
|
+
prisma: requirePrisma(c.get('prisma')),
|
|
32
|
+
postgres: c.get('postgres'),
|
|
33
|
+
sqlite: c.get('sqlite'),
|
|
34
|
+
pagination: c.get('routeConfig')?.pagination,
|
|
35
|
+
override: c.get('operationOverride'),
|
|
36
|
+
getContext: c.get('getContext'),
|
|
37
|
+
},
|
|
38
|
+
)
|
|
23
39
|
c.set('resultData', data)
|
|
24
40
|
}`
|
|
25
|
-
|
|
41
|
+
})
|
|
42
|
+
.join('\n')
|
|
26
43
|
|
|
27
|
-
const writeHandlers = writeOps
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
const writeHandlers = writeOps
|
|
45
|
+
.map((meta) => {
|
|
46
|
+
const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
|
|
47
|
+
return `
|
|
30
48
|
export async function ${exportName}(c: HandlerContext): Promise<void> {
|
|
31
|
-
const data = await
|
|
49
|
+
const data = await executeOperation(
|
|
50
|
+
{ variantKey: c.get('guardVariantKey'), caller: c.get('guardCaller') },
|
|
51
|
+
{ guardShape: c.get('guardShape') },
|
|
52
|
+
{
|
|
53
|
+
core: core.${meta.coreName},
|
|
54
|
+
args: queryChannel(c),
|
|
55
|
+
body: c.get('body'),
|
|
56
|
+
prisma: requirePrisma(c.get('prisma')),
|
|
57
|
+
postgres: c.get('postgres'),
|
|
58
|
+
sqlite: c.get('sqlite'),
|
|
59
|
+
pagination: c.get('routeConfig')?.pagination,
|
|
60
|
+
override: c.get('operationOverride'),
|
|
61
|
+
getContext: c.get('getContext'),
|
|
62
|
+
},
|
|
63
|
+
)
|
|
32
64
|
c.set('resultData', data)
|
|
33
65
|
c.set('resultStatus', ${meta.successStatus})
|
|
34
66
|
}`
|
|
35
|
-
|
|
67
|
+
})
|
|
68
|
+
.join('\n')
|
|
36
69
|
|
|
37
70
|
const updateEachExportName = `${modelName}UpdateEach`
|
|
38
71
|
const updateEachHandler = `
|
|
@@ -45,12 +78,26 @@ export async function ${updateEachExportName}(c: HandlerContext): Promise<void>
|
|
|
45
78
|
return `import type { Context } from 'hono'
|
|
46
79
|
import * as core from './${modelName}Core${ext}'
|
|
47
80
|
import type { OperationContext } from '../operationRuntime${ext}'
|
|
81
|
+
import {
|
|
82
|
+
executeOperation,
|
|
83
|
+
requirePrisma,
|
|
84
|
+
type ArgsChannel,
|
|
85
|
+
} from '../operationPipeline${ext}'
|
|
48
86
|
import type { HonoInternalVariables } from '../routeConfig.target${ext}'
|
|
49
87
|
|
|
50
88
|
type HandlerContext = Context<{ Variables: HonoInternalVariables }>
|
|
51
89
|
|
|
90
|
+
function queryChannel(c: HandlerContext): ArgsChannel {
|
|
91
|
+
return {
|
|
92
|
+
read: () => c.get('parsedQuery'),
|
|
93
|
+
write: (next) => c.set('parsedQuery', next),
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
52
97
|
function buildContext(c: HandlerContext): OperationContext {
|
|
53
98
|
return {
|
|
99
|
+
operationOverride: c.get('operationOverride'),
|
|
100
|
+
resolveOperationContext: c.get('getContext'),
|
|
54
101
|
prisma: c.get('prisma'),
|
|
55
102
|
postgres: c.get('postgres'),
|
|
56
103
|
sqlite: c.get('sqlite'),
|
|
@@ -58,6 +105,7 @@ function buildContext(c: HandlerContext): OperationContext {
|
|
|
58
105
|
body: c.get('body'),
|
|
59
106
|
guardShape: c.get('guardShape'),
|
|
60
107
|
guardCaller: c.get('guardCaller'),
|
|
108
|
+
guardVariantKey: c.get('guardVariantKey'),
|
|
61
109
|
paginationConfig: c.get('routeConfig')?.pagination,
|
|
62
110
|
}
|
|
63
111
|
}
|
|
@@ -65,4 +113,4 @@ ${readHandlers}
|
|
|
65
113
|
${writeHandlers}
|
|
66
114
|
${updateEachHandler}
|
|
67
115
|
`
|
|
68
|
-
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { DMMF } from '@prisma/generator-helper'
|
|
2
|
+
import { generateRouteConfigType } from './generateRouteConfigType'
|
|
3
|
+
import type { ImportStyle } from '../utils/resolveImportStyle'
|
|
4
|
+
import { importExt } from '../utils/importExt'
|
|
5
|
+
import type { WriteStrategy } from '../constants'
|
|
6
|
+
import { modelPathSegment, type PathCase } from '../utils/pathCasing'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The per-model OpenAPI part, in a module of its own so the phase 9 boundary
|
|
10
|
+
* holds by construction: a bundle that does not import this file has no path
|
|
11
|
+
* to `buildModelOpenApi` or `yaml`, regardless of bundler side-effect
|
|
12
|
+
* heuristics.
|
|
13
|
+
*/
|
|
14
|
+
export function generateHonoOpenApiRoutes({
|
|
15
|
+
model,
|
|
16
|
+
enums,
|
|
17
|
+
guardShapesImport,
|
|
18
|
+
clientImport,
|
|
19
|
+
importStyle,
|
|
20
|
+
writeStrategy,
|
|
21
|
+
pathCase,
|
|
22
|
+
}: {
|
|
23
|
+
model: DMMF.Model
|
|
24
|
+
enums: DMMF.DatamodelEnum[]
|
|
25
|
+
guardShapesImport: string | null
|
|
26
|
+
clientImport?: string
|
|
27
|
+
importStyle: ImportStyle
|
|
28
|
+
writeStrategy: WriteStrategy
|
|
29
|
+
pathCase: PathCase
|
|
30
|
+
}): string {
|
|
31
|
+
const ext = importExt(importStyle)
|
|
32
|
+
const modelName = model.name
|
|
33
|
+
const modelSegment = modelPathSegment(modelName, pathCase)
|
|
34
|
+
const lower = modelName.charAt(0).toLowerCase() + modelName.slice(1)
|
|
35
|
+
|
|
36
|
+
return `import { Hono } from 'hono'
|
|
37
|
+
import type {
|
|
38
|
+
RouteConfig,
|
|
39
|
+
HonoEnvBase,
|
|
40
|
+
GeneratedHonoEnv,
|
|
41
|
+
PrismaClientLike,
|
|
42
|
+
} from '../routeConfig.target${ext}'
|
|
43
|
+
import { normalizePrefix, getEnv } from '../misc${ext}'
|
|
44
|
+
import { registerOpenApiRoutes } from '../routerParts${ext}'
|
|
45
|
+
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
46
|
+
import { MODEL_FIELDS, MODEL_ENUMS } from './${modelName}Metadata${ext}'
|
|
47
|
+
|
|
48
|
+
${generateRouteConfigType(modelName, 'HonoBeforeHook', guardShapesImport, importStyle, 'hono', clientImport)}
|
|
49
|
+
|
|
50
|
+
export function ${lower}OpenApi<TCtx = unknown, TPrisma extends PrismaClientLike = PrismaClientLike, TEnv extends HonoEnvBase = HonoEnvBase>(config: ${modelName}RouteConfig<TCtx, TPrisma, TEnv> = {}): Hono<GeneratedHonoEnv<TEnv>> {
|
|
51
|
+
const _env = getEnv()
|
|
52
|
+
const customPrefix = normalizePrefix(config.customUrlPrefix || '')
|
|
53
|
+
const modelPrefix = config.addModelPrefix !== false ? '/${modelSegment}' : ''
|
|
54
|
+
const basePath = customPrefix + modelPrefix
|
|
55
|
+
|
|
56
|
+
const openApiDisabled = config.disableOpenApi === true
|
|
57
|
+
|| (config.disableOpenApi !== false && (
|
|
58
|
+
_env.NODE_ENV === 'production'
|
|
59
|
+
|| _env.DISABLE_OPENAPI === 'true'
|
|
60
|
+
))
|
|
61
|
+
|
|
62
|
+
const app = new Hono<GeneratedHonoEnv<TEnv>>()
|
|
63
|
+
if (!openApiDisabled) {
|
|
64
|
+
let jsonCache: unknown = undefined
|
|
65
|
+
let yamlCache: string | undefined = undefined
|
|
66
|
+
registerOpenApiRoutes(app, basePath, () => {
|
|
67
|
+
if (jsonCache === undefined) {
|
|
68
|
+
jsonCache = buildModelOpenApi(
|
|
69
|
+
'${modelName}',
|
|
70
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
71
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
72
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
73
|
+
{ format: 'json', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
return jsonCache
|
|
77
|
+
}, () => {
|
|
78
|
+
if (yamlCache === undefined) {
|
|
79
|
+
yamlCache = buildModelOpenApi(
|
|
80
|
+
'${modelName}',
|
|
81
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
82
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
83
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
84
|
+
{ format: 'yaml', writeStrategy: '${writeStrategy}', pathSegment: '${modelSegment}' },
|
|
85
|
+
) as string
|
|
86
|
+
}
|
|
87
|
+
return yamlCache
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
return app
|
|
91
|
+
}
|
|
92
|
+
`
|
|
93
|
+
}
|