prisma-generator-express 1.65.1 → 1.66.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 +22 -12
- 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/generateRouterHono.js +49 -31
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/package.json +12 -1
- package/src/copy/routeConfig.hono.ts +7 -0
- package/src/generators/generateQueryBuilderHelper.ts +20 -4
- package/src/generators/generateRouterHono.ts +49 -31
package/README.md
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/favicon.svg" width="88" height="88" alt="Prisma Generator Express logo">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Prisma Generator Express</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>Ship Prisma APIs faster by generating Express, Fastify, or Hono CRUD routes, OpenAPI, pagination, hooks, and guard integration directly from your schema.</strong></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/prisma-generator-express"><img src="https://badge.fury.io/js/prisma-generator-express.svg" alt="npm version"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/prisma-generator-express"><img src="https://img.shields.io/npm/dt/prisma-generator-express.svg" alt="npm downloads"></a>
|
|
12
|
+
<a href="https://codecov.io/gh/multipliedtwice/prisma-generator-express"><img src="https://img.shields.io/codecov/c/github/multipliedtwice/prisma-generator-express/master.svg" alt="Coverage"></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/npm/l/prisma-generator-express.svg" alt="License"></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="https://multipliedtwice.github.io/prisma-generator-express/">Field Guide</a> ·
|
|
18
|
+
<a href="https://www.npmjs.com/package/prisma-generator-express">npm</a> ·
|
|
19
|
+
<a href="article-labs/guard/">Guard Evidence</a> ·
|
|
20
|
+
<a href="article-labs/http/">HTTP/PostgreSQL Evidence</a> ·
|
|
21
|
+
<a href="#documentation-endpoints">API Documentation</a>
|
|
22
|
+
</p>
|
|
13
23
|
|
|
14
24
|
Running `npx prisma generate` produces:
|
|
15
25
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { GeneratorOptions } from '@prisma/generator-helper';
|
|
2
|
-
export declare function generateQueryBuilderHelper(
|
|
2
|
+
export declare function generateQueryBuilderHelper(_options?: Partial<Pick<GeneratorOptions, 'schemaPath'>>): string;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateQueryBuilderHelper = generateQueryBuilderHelper;
|
|
4
|
-
function generateQueryBuilderHelper(
|
|
5
|
-
const schemaPath =
|
|
6
|
-
? JSON.stringify(options.schemaPath)
|
|
7
|
-
: "resolve(process.cwd(), 'prisma/schema.prisma')";
|
|
4
|
+
function generateQueryBuilderHelper(_options) {
|
|
5
|
+
const schemaPath = "resolve(process.cwd(), 'prisma/schema.prisma')";
|
|
8
6
|
return `import { spawn } from 'child_process'
|
|
9
7
|
import { resolve, join, dirname } from 'path'
|
|
10
8
|
import { existsSync, readFileSync } from 'fs'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateQueryBuilderHelper.js","sourceRoot":"","sources":["../../src/generators/generateQueryBuilderHelper.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"generateQueryBuilderHelper.js","sourceRoot":"","sources":["../../src/generators/generateQueryBuilderHelper.ts"],"names":[],"mappings":";;AAoBA,gEAiKC;AAjKD,SAAgB,0BAA0B,CACxC,QAAwD;IAExD,MAAM,UAAU,GAAG,gDAAgD,CAAA;IAEnE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA+DsC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FxD,CAAA;AACD,CAAC"}
|
|
@@ -131,13 +131,15 @@ const _env = getEnv()
|
|
|
131
131
|
// which is upstream behaviour. See generateRouterHono.ts.
|
|
132
132
|
const DROP_GUARD = ${dropGuard}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
134
|
+
/**
|
|
135
|
+
* DELIBERATELY NOT RECURSIVE.
|
|
136
|
+
*
|
|
137
|
+
* A self-referential JSON type sent through \`c.json()\` makes Hono's response
|
|
138
|
+
* inference instantiate without a fixed point, and TypeScript answers
|
|
139
|
+
* "type instantiation is excessively deep" — in the emitted file, for every
|
|
140
|
+
* consumer. One level is all this needs: the value is serialised, not walked.
|
|
141
|
+
*/
|
|
142
|
+
type JsonLike = string | number | boolean | null | unknown[] | Record<string, unknown>
|
|
141
143
|
|
|
142
144
|
type OperationConfigLike<TEnv extends HonoEnvBase> = {
|
|
143
145
|
before?: HonoBeforeHook<TEnv>[]
|
|
@@ -230,17 +232,30 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
230
232
|
const dropGuard = DROP_GUARD || (policy.allowE2EGuardBypass && _env.E2E === 'true')
|
|
231
233
|
|
|
232
234
|
return async (c: Context<GeneratedHonoEnv<TEnv>>): Promise<void> => {
|
|
235
|
+
/**
|
|
236
|
+
* INTERNAL REQUEST STATE IS SET THROUGH A CONCRETE CONTEXT.
|
|
237
|
+
*
|
|
238
|
+
* \`GeneratedHonoEnv<TEnv>['Variables']\` is \`HonoInternalVariables & TEnv['Variables']\`,
|
|
239
|
+
* and inside this generic function TypeScript cannot know that the consumer's
|
|
240
|
+
* half does not also declare \`routeConfig\` — so setting that key straight
|
|
241
|
+
* onto \`c\` is unassignable to the intersection and the emitted router does not
|
|
242
|
+
* typecheck under \`strict\` for ANY consumer. These keys belong to this
|
|
243
|
+
* router, so they are written through the internal shape they were declared
|
|
244
|
+
* in.
|
|
245
|
+
*/
|
|
246
|
+
const vars = c as unknown as HandlerContext
|
|
247
|
+
|
|
233
248
|
const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
|
|
234
|
-
if (merged)
|
|
249
|
+
if (merged) vars.set('routeConfig', { pagination: merged })
|
|
235
250
|
|
|
236
251
|
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
237
252
|
const headerValue = c.req.header(headerName)
|
|
238
253
|
const caller = config.guard?.resolveVariant?.(c) ?? headerValue ?? undefined
|
|
239
|
-
if (typeof caller === 'string')
|
|
254
|
+
if (typeof caller === 'string') vars.set('guardCaller', caller)
|
|
240
255
|
|
|
241
256
|
const resolution = resolveOperationVariantKey(opConfig.guardRouting, caller)
|
|
242
257
|
if (!resolution.ok) {
|
|
243
|
-
|
|
258
|
+
vars.set('guardVariantFailure', resolution)
|
|
244
259
|
return
|
|
245
260
|
}
|
|
246
261
|
|
|
@@ -248,11 +263,11 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
248
263
|
opConfig.guardRouting.kind === 'named'
|
|
249
264
|
? resolution.key
|
|
250
265
|
: undefined
|
|
251
|
-
if (resolvedKey !== undefined)
|
|
266
|
+
if (resolvedKey !== undefined) vars.set('guardVariantKey', resolvedKey)
|
|
252
267
|
|
|
253
268
|
if (opConfig.guardShape) {
|
|
254
269
|
const resolveCtx = typeof config.resolveContext === 'function'
|
|
255
|
-
? () => (config.resolveContext as (ctx: Context<GeneratedHonoEnv<TEnv>>) => unknown | Promise<unknown>)(c)
|
|
270
|
+
? () => (config.resolveContext as unknown as (ctx: Context<GeneratedHonoEnv<TEnv>>) => unknown | Promise<unknown>)(c)
|
|
256
271
|
: undefined
|
|
257
272
|
|
|
258
273
|
/**
|
|
@@ -265,18 +280,20 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
265
280
|
* behaviour: it is resolved at the point of use, and a function returning
|
|
266
281
|
* something unusable is not this router's business to refuse.
|
|
267
282
|
*/
|
|
268
|
-
let effectiveShape: unknown = opConfig.guardShape
|
|
283
|
+
let effectiveShape: Record<string, unknown> | undefined = opConfig.guardShape
|
|
269
284
|
if (policy.validateResolvedShapes) {
|
|
270
285
|
const resolution = await resolveGuardShapeOnce(opConfig.guardShape, resolvedKey, resolveCtx)
|
|
271
286
|
if (!resolution.ok) {
|
|
272
|
-
|
|
287
|
+
vars.set('guardShapeFailure', resolution.problem)
|
|
273
288
|
return
|
|
274
289
|
}
|
|
275
|
-
|
|
290
|
+
// \`ok\` means the resolved value is a shape object; the fallback keeps the
|
|
291
|
+
// declared shape rather than storing something the context cannot hold.
|
|
292
|
+
effectiveShape = isPlainObject(resolution.shape) ? resolution.shape : opConfig.guardShape
|
|
276
293
|
}
|
|
277
294
|
|
|
278
295
|
if (!dropGuard) {
|
|
279
|
-
|
|
296
|
+
vars.set('guardShape', effectiveShape)
|
|
280
297
|
} else {
|
|
281
298
|
await applyDroppedGuard(
|
|
282
299
|
effectiveShape,
|
|
@@ -284,24 +301,24 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
284
301
|
resolveCtx,
|
|
285
302
|
opKind,
|
|
286
303
|
{
|
|
287
|
-
readQuery:
|
|
288
|
-
writeBody: isPlainObject(
|
|
289
|
-
? (
|
|
304
|
+
readQuery: vars.get('parsedQuery'),
|
|
305
|
+
writeBody: isPlainObject(vars.get('body'))
|
|
306
|
+
? (vars.get('body') as Record<string, unknown>)
|
|
290
307
|
: undefined,
|
|
291
308
|
},
|
|
292
309
|
() => {
|
|
293
|
-
let target =
|
|
310
|
+
let target = vars.get('parsedQuery')
|
|
294
311
|
if (!target) {
|
|
295
312
|
target = {}
|
|
296
|
-
|
|
313
|
+
vars.set('parsedQuery', target)
|
|
297
314
|
}
|
|
298
315
|
return target
|
|
299
316
|
},
|
|
300
317
|
() => {
|
|
301
|
-
let target =
|
|
318
|
+
let target = vars.get('body')
|
|
302
319
|
if (!isPlainObject(target)) {
|
|
303
320
|
target = {}
|
|
304
|
-
|
|
321
|
+
vars.set('body', target)
|
|
305
322
|
}
|
|
306
323
|
return target as Record<string, unknown>
|
|
307
324
|
},
|
|
@@ -380,7 +397,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
380
397
|
'${modelName}',
|
|
381
398
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
382
399
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
383
|
-
config as
|
|
400
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
384
401
|
{ format: 'json', writeStrategy: '${writeStrategy}' },
|
|
385
402
|
)
|
|
386
403
|
}
|
|
@@ -393,14 +410,14 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
393
410
|
'${modelName}',
|
|
394
411
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
395
412
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
396
|
-
config as
|
|
413
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
397
414
|
{ format: 'yaml', writeStrategy: '${writeStrategy}' },
|
|
398
415
|
) as string
|
|
399
416
|
}
|
|
400
417
|
return _openApiYamlCache
|
|
401
418
|
}
|
|
402
419
|
|
|
403
|
-
if (config.queryBuilder &&
|
|
420
|
+
if (config.queryBuilder && _env.NODE_ENV !== 'production') {
|
|
404
421
|
console.warn(
|
|
405
422
|
'[${modelName}Router] queryBuilder config is present but Hono target does not auto-start it. ' +
|
|
406
423
|
'Run \`npx prisma-query-builder-ui\` in a separate process.',
|
|
@@ -408,7 +425,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
408
425
|
}
|
|
409
426
|
|
|
410
427
|
app.onError((err, c) => {
|
|
411
|
-
return sendError(c as HandlerContext, err)
|
|
428
|
+
return sendError(c as unknown as HandlerContext, err)
|
|
412
429
|
})
|
|
413
430
|
|
|
414
431
|
if (!openApiDisabled) {
|
|
@@ -438,14 +455,15 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
438
455
|
* that branch is inert rather than merely unreached when it is off.
|
|
439
456
|
*/
|
|
440
457
|
const settleGuard = (c: Context<GeneratedHonoEnv<TEnv>>): void => {
|
|
441
|
-
const
|
|
458
|
+
const vars = c as unknown as HandlerContext
|
|
459
|
+
const failure = vars.get('guardVariantFailure')
|
|
442
460
|
if (failure) {
|
|
443
461
|
throw new HTTPException(400, {
|
|
444
462
|
message: formatGuardVariantResolutionError(failure),
|
|
445
463
|
})
|
|
446
464
|
}
|
|
447
465
|
|
|
448
|
-
const shapeFailure =
|
|
466
|
+
const shapeFailure = vars.get('guardShapeFailure')
|
|
449
467
|
if (shapeFailure) {
|
|
450
468
|
throw new HTTPException(500, {
|
|
451
469
|
message: 'guard shape could not be resolved: ' + shapeFailure,
|
|
@@ -472,7 +490,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
472
490
|
// Upstream order: hooks first, guard failure after.
|
|
473
491
|
if (!SETTLE_BEFORE_HOOKS) settleGuard(c)
|
|
474
492
|
|
|
475
|
-
const key = c.get('guardVariantKey')
|
|
493
|
+
const key = (c as unknown as HandlerContext).get('guardVariantKey')
|
|
476
494
|
const variantHooks =
|
|
477
495
|
key !== undefined ? opConfig.variantHooks[key] : undefined
|
|
478
496
|
|
|
@@ -507,7 +525,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
507
525
|
// Upstream order: hooks first, guard failure after.
|
|
508
526
|
if (!SETTLE_BEFORE_HOOKS) settleGuard(c)
|
|
509
527
|
|
|
510
|
-
const key = c.get('guardVariantKey')
|
|
528
|
+
const key = (c as unknown as HandlerContext).get('guardVariantKey')
|
|
511
529
|
const variantHooks =
|
|
512
530
|
key !== undefined ? opConfig.variantHooks[key] : undefined
|
|
513
531
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateRouterHono.js","sourceRoot":"","sources":["../../src/generators/generateRouterHono.ts"],"names":[],"mappings":";;AAmIA,
|
|
1
|
+
{"version":3,"file":"generateRouterHono.js","sourceRoot":"","sources":["../../src/generators/generateRouterHono.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prisma-generator-express",
|
|
3
3
|
"description": "Prisma generator for Express, Fastify, and Hono CRUD APIs with OpenAPI documentation",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.66.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./guard-options": {
|
|
13
|
+
"types": "./dist/guardOptions.d.ts",
|
|
14
|
+
"default": "./dist/guardOptions.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
7
18
|
"license": "MIT",
|
|
8
19
|
"bin": "dist/bin.js",
|
|
9
20
|
"engines": {
|
|
@@ -38,6 +38,13 @@ export type HonoInternalVariables = {
|
|
|
38
38
|
guardCaller?: string
|
|
39
39
|
guardVariantKey?: string
|
|
40
40
|
guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
|
|
41
|
+
/**
|
|
42
|
+
* Set when `validateResolvedShapes` refuses what a shape function returned.
|
|
43
|
+
*
|
|
44
|
+
* It was written by the router and never declared here, so the emitted router
|
|
45
|
+
* failed to typecheck at exactly the line that implements the control.
|
|
46
|
+
*/
|
|
47
|
+
guardShapeFailure?: string
|
|
41
48
|
resultData?: unknown
|
|
42
49
|
resultStatus?: number
|
|
43
50
|
}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { GeneratorOptions } from '@prisma/generator-helper'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* THE EMITTED DEFAULT IS THE CONSUMER'S OWN SCHEMA, NEVER THE GENERATOR'S.
|
|
5
|
+
*
|
|
6
|
+
* This baked `options.schemaPath` — an ABSOLUTE path on the machine that ran
|
|
7
|
+
* `prisma generate` — into the generated helper as its runtime default. For a
|
|
8
|
+
* consumer that generates and runs in the same checkout that is invisible; for
|
|
9
|
+
* anyone else it is a path that does not exist, and for a generated artifact
|
|
10
|
+
* built in a staging directory it is worse than that: the directory is renamed
|
|
11
|
+
* away at adoption, so the shipped fallback can never resolve on ANY machine,
|
|
12
|
+
* including the one that produced it.
|
|
13
|
+
*
|
|
14
|
+
* `resolve(process.cwd(), 'prisma/schema.prisma')` — Prisma's own convention,
|
|
15
|
+
* relative to wherever the consumer's process runs — was already written here as
|
|
16
|
+
* the no-schemaPath branch. It is now the only default.
|
|
17
|
+
*
|
|
18
|
+
* THE EXPLICIT OVERRIDE IS UNTOUCHED: `startQueryBuilder({ schemaPath })` still
|
|
19
|
+
* wins, which is how a consumer with a different layout says so.
|
|
20
|
+
*/
|
|
3
21
|
export function generateQueryBuilderHelper(
|
|
4
|
-
|
|
22
|
+
_options?: Partial<Pick<GeneratorOptions, 'schemaPath'>>,
|
|
5
23
|
): string {
|
|
6
|
-
const schemaPath =
|
|
7
|
-
? JSON.stringify(options.schemaPath)
|
|
8
|
-
: "resolve(process.cwd(), 'prisma/schema.prisma')"
|
|
24
|
+
const schemaPath = "resolve(process.cwd(), 'prisma/schema.prisma')"
|
|
9
25
|
|
|
10
26
|
return `import { spawn } from 'child_process'
|
|
11
27
|
import { resolve, join, dirname } from 'path'
|
|
@@ -205,13 +205,15 @@ const _env = getEnv()
|
|
|
205
205
|
// which is upstream behaviour. See generateRouterHono.ts.
|
|
206
206
|
const DROP_GUARD = ${dropGuard}
|
|
207
207
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
208
|
+
/**
|
|
209
|
+
* DELIBERATELY NOT RECURSIVE.
|
|
210
|
+
*
|
|
211
|
+
* A self-referential JSON type sent through \`c.json()\` makes Hono's response
|
|
212
|
+
* inference instantiate without a fixed point, and TypeScript answers
|
|
213
|
+
* "type instantiation is excessively deep" — in the emitted file, for every
|
|
214
|
+
* consumer. One level is all this needs: the value is serialised, not walked.
|
|
215
|
+
*/
|
|
216
|
+
type JsonLike = string | number | boolean | null | unknown[] | Record<string, unknown>
|
|
215
217
|
|
|
216
218
|
type OperationConfigLike<TEnv extends HonoEnvBase> = {
|
|
217
219
|
before?: HonoBeforeHook<TEnv>[]
|
|
@@ -304,17 +306,30 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
304
306
|
const dropGuard = DROP_GUARD || (policy.allowE2EGuardBypass && _env.E2E === 'true')
|
|
305
307
|
|
|
306
308
|
return async (c: Context<GeneratedHonoEnv<TEnv>>): Promise<void> => {
|
|
309
|
+
/**
|
|
310
|
+
* INTERNAL REQUEST STATE IS SET THROUGH A CONCRETE CONTEXT.
|
|
311
|
+
*
|
|
312
|
+
* \`GeneratedHonoEnv<TEnv>['Variables']\` is \`HonoInternalVariables & TEnv['Variables']\`,
|
|
313
|
+
* and inside this generic function TypeScript cannot know that the consumer's
|
|
314
|
+
* half does not also declare \`routeConfig\` — so setting that key straight
|
|
315
|
+
* onto \`c\` is unassignable to the intersection and the emitted router does not
|
|
316
|
+
* typecheck under \`strict\` for ANY consumer. These keys belong to this
|
|
317
|
+
* router, so they are written through the internal shape they were declared
|
|
318
|
+
* in.
|
|
319
|
+
*/
|
|
320
|
+
const vars = c as unknown as HandlerContext
|
|
321
|
+
|
|
307
322
|
const merged = mergePaginationConfig(config.pagination, opConfig.pagination)
|
|
308
|
-
if (merged)
|
|
323
|
+
if (merged) vars.set('routeConfig', { pagination: merged })
|
|
309
324
|
|
|
310
325
|
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
311
326
|
const headerValue = c.req.header(headerName)
|
|
312
327
|
const caller = config.guard?.resolveVariant?.(c) ?? headerValue ?? undefined
|
|
313
|
-
if (typeof caller === 'string')
|
|
328
|
+
if (typeof caller === 'string') vars.set('guardCaller', caller)
|
|
314
329
|
|
|
315
330
|
const resolution = resolveOperationVariantKey(opConfig.guardRouting, caller)
|
|
316
331
|
if (!resolution.ok) {
|
|
317
|
-
|
|
332
|
+
vars.set('guardVariantFailure', resolution)
|
|
318
333
|
return
|
|
319
334
|
}
|
|
320
335
|
|
|
@@ -322,11 +337,11 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
322
337
|
opConfig.guardRouting.kind === 'named'
|
|
323
338
|
? resolution.key
|
|
324
339
|
: undefined
|
|
325
|
-
if (resolvedKey !== undefined)
|
|
340
|
+
if (resolvedKey !== undefined) vars.set('guardVariantKey', resolvedKey)
|
|
326
341
|
|
|
327
342
|
if (opConfig.guardShape) {
|
|
328
343
|
const resolveCtx = typeof config.resolveContext === 'function'
|
|
329
|
-
? () => (config.resolveContext as (ctx: Context<GeneratedHonoEnv<TEnv>>) => unknown | Promise<unknown>)(c)
|
|
344
|
+
? () => (config.resolveContext as unknown as (ctx: Context<GeneratedHonoEnv<TEnv>>) => unknown | Promise<unknown>)(c)
|
|
330
345
|
: undefined
|
|
331
346
|
|
|
332
347
|
/**
|
|
@@ -339,18 +354,20 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
339
354
|
* behaviour: it is resolved at the point of use, and a function returning
|
|
340
355
|
* something unusable is not this router's business to refuse.
|
|
341
356
|
*/
|
|
342
|
-
let effectiveShape: unknown = opConfig.guardShape
|
|
357
|
+
let effectiveShape: Record<string, unknown> | undefined = opConfig.guardShape
|
|
343
358
|
if (policy.validateResolvedShapes) {
|
|
344
359
|
const resolution = await resolveGuardShapeOnce(opConfig.guardShape, resolvedKey, resolveCtx)
|
|
345
360
|
if (!resolution.ok) {
|
|
346
|
-
|
|
361
|
+
vars.set('guardShapeFailure', resolution.problem)
|
|
347
362
|
return
|
|
348
363
|
}
|
|
349
|
-
|
|
364
|
+
// \`ok\` means the resolved value is a shape object; the fallback keeps the
|
|
365
|
+
// declared shape rather than storing something the context cannot hold.
|
|
366
|
+
effectiveShape = isPlainObject(resolution.shape) ? resolution.shape : opConfig.guardShape
|
|
350
367
|
}
|
|
351
368
|
|
|
352
369
|
if (!dropGuard) {
|
|
353
|
-
|
|
370
|
+
vars.set('guardShape', effectiveShape)
|
|
354
371
|
} else {
|
|
355
372
|
await applyDroppedGuard(
|
|
356
373
|
effectiveShape,
|
|
@@ -358,24 +375,24 @@ function makeShapeMiddleware<TCtx, TPrisma, TEnv extends HonoEnvBase>(
|
|
|
358
375
|
resolveCtx,
|
|
359
376
|
opKind,
|
|
360
377
|
{
|
|
361
|
-
readQuery:
|
|
362
|
-
writeBody: isPlainObject(
|
|
363
|
-
? (
|
|
378
|
+
readQuery: vars.get('parsedQuery'),
|
|
379
|
+
writeBody: isPlainObject(vars.get('body'))
|
|
380
|
+
? (vars.get('body') as Record<string, unknown>)
|
|
364
381
|
: undefined,
|
|
365
382
|
},
|
|
366
383
|
() => {
|
|
367
|
-
let target =
|
|
384
|
+
let target = vars.get('parsedQuery')
|
|
368
385
|
if (!target) {
|
|
369
386
|
target = {}
|
|
370
|
-
|
|
387
|
+
vars.set('parsedQuery', target)
|
|
371
388
|
}
|
|
372
389
|
return target
|
|
373
390
|
},
|
|
374
391
|
() => {
|
|
375
|
-
let target =
|
|
392
|
+
let target = vars.get('body')
|
|
376
393
|
if (!isPlainObject(target)) {
|
|
377
394
|
target = {}
|
|
378
|
-
|
|
395
|
+
vars.set('body', target)
|
|
379
396
|
}
|
|
380
397
|
return target as Record<string, unknown>
|
|
381
398
|
},
|
|
@@ -454,7 +471,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
454
471
|
'${modelName}',
|
|
455
472
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
456
473
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
457
|
-
config as
|
|
474
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
458
475
|
{ format: 'json', writeStrategy: '${writeStrategy}' },
|
|
459
476
|
)
|
|
460
477
|
}
|
|
@@ -467,14 +484,14 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
467
484
|
'${modelName}',
|
|
468
485
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
469
486
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
470
|
-
config as
|
|
487
|
+
config as unknown as Parameters<typeof buildModelOpenApi>[3],
|
|
471
488
|
{ format: 'yaml', writeStrategy: '${writeStrategy}' },
|
|
472
489
|
) as string
|
|
473
490
|
}
|
|
474
491
|
return _openApiYamlCache
|
|
475
492
|
}
|
|
476
493
|
|
|
477
|
-
if (config.queryBuilder &&
|
|
494
|
+
if (config.queryBuilder && _env.NODE_ENV !== 'production') {
|
|
478
495
|
console.warn(
|
|
479
496
|
'[${modelName}Router] queryBuilder config is present but Hono target does not auto-start it. ' +
|
|
480
497
|
'Run \`npx prisma-query-builder-ui\` in a separate process.',
|
|
@@ -482,7 +499,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
482
499
|
}
|
|
483
500
|
|
|
484
501
|
app.onError((err, c) => {
|
|
485
|
-
return sendError(c as HandlerContext, err)
|
|
502
|
+
return sendError(c as unknown as HandlerContext, err)
|
|
486
503
|
})
|
|
487
504
|
|
|
488
505
|
if (!openApiDisabled) {
|
|
@@ -512,14 +529,15 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
512
529
|
* that branch is inert rather than merely unreached when it is off.
|
|
513
530
|
*/
|
|
514
531
|
const settleGuard = (c: Context<GeneratedHonoEnv<TEnv>>): void => {
|
|
515
|
-
const
|
|
532
|
+
const vars = c as unknown as HandlerContext
|
|
533
|
+
const failure = vars.get('guardVariantFailure')
|
|
516
534
|
if (failure) {
|
|
517
535
|
throw new HTTPException(400, {
|
|
518
536
|
message: formatGuardVariantResolutionError(failure),
|
|
519
537
|
})
|
|
520
538
|
}
|
|
521
539
|
|
|
522
|
-
const shapeFailure =
|
|
540
|
+
const shapeFailure = vars.get('guardShapeFailure')
|
|
523
541
|
if (shapeFailure) {
|
|
524
542
|
throw new HTTPException(500, {
|
|
525
543
|
message: 'guard shape could not be resolved: ' + shapeFailure,
|
|
@@ -546,7 +564,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
546
564
|
// Upstream order: hooks first, guard failure after.
|
|
547
565
|
if (!SETTLE_BEFORE_HOOKS) settleGuard(c)
|
|
548
566
|
|
|
549
|
-
const key = c.get('guardVariantKey')
|
|
567
|
+
const key = (c as unknown as HandlerContext).get('guardVariantKey')
|
|
550
568
|
const variantHooks =
|
|
551
569
|
key !== undefined ? opConfig.variantHooks[key] : undefined
|
|
552
570
|
|
|
@@ -581,7 +599,7 @@ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any, TEnv extend
|
|
|
581
599
|
// Upstream order: hooks first, guard failure after.
|
|
582
600
|
if (!SETTLE_BEFORE_HOOKS) settleGuard(c)
|
|
583
601
|
|
|
584
|
-
const key = c.get('guardVariantKey')
|
|
602
|
+
const key = (c as unknown as HandlerContext).get('guardVariantKey')
|
|
585
603
|
const variantHooks =
|
|
586
604
|
key !== undefined ? opConfig.variantHooks[key] : undefined
|
|
587
605
|
|