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.
Files changed (106) hide show
  1. package/README.md +51 -3480
  2. package/dist/client/encodeQueryParams.js +3 -1
  3. package/dist/client/encodeQueryParams.js.map +1 -1
  4. package/dist/copy/misc.d.ts +1 -0
  5. package/dist/copy/misc.js +14 -0
  6. package/dist/copy/misc.js.map +1 -1
  7. package/dist/copy/operationDefinitions.js +69 -6
  8. package/dist/copy/operationDefinitions.js.map +1 -1
  9. package/dist/generators/generateFastifyHandler.d.ts +2 -2
  10. package/dist/generators/generateFastifyHandler.js +15 -5
  11. package/dist/generators/generateFastifyHandler.js.map +1 -1
  12. package/dist/generators/generateHonoHandler.d.ts +2 -2
  13. package/dist/generators/generateHonoHandler.js +12 -5
  14. package/dist/generators/generateHonoHandler.js.map +1 -1
  15. package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
  16. package/dist/generators/generateImportPrismaStatement.js +6 -0
  17. package/dist/generators/generateImportPrismaStatement.js.map +1 -1
  18. package/dist/generators/generateModelMetadata.js +20 -10
  19. package/dist/generators/generateModelMetadata.js.map +1 -1
  20. package/dist/generators/generateOperationCore.d.ts +3 -3
  21. package/dist/generators/generateOperationCore.js +51 -16
  22. package/dist/generators/generateOperationCore.js.map +1 -1
  23. package/dist/generators/generateQueryBuilderHelper.d.ts +1 -1
  24. package/dist/generators/generateQueryBuilderHelper.js +2 -4
  25. package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
  26. package/dist/generators/generateRelationMeta.js +2 -2
  27. package/dist/generators/generateRelationMeta.js.map +1 -1
  28. package/dist/generators/generateRouteConfigType.d.ts +2 -2
  29. package/dist/generators/generateRouteConfigType.js +29 -11
  30. package/dist/generators/generateRouteConfigType.js.map +1 -1
  31. package/dist/generators/generateRouter.d.ts +7 -4
  32. package/dist/generators/generateRouter.js +107 -14
  33. package/dist/generators/generateRouter.js.map +1 -1
  34. package/dist/generators/generateRouterFastify.d.ts +7 -4
  35. package/dist/generators/generateRouterFastify.js +56 -28
  36. package/dist/generators/generateRouterFastify.js.map +1 -1
  37. package/dist/generators/generateRouterHono.d.ts +7 -4
  38. package/dist/generators/generateRouterHono.js +84 -53
  39. package/dist/generators/generateRouterHono.js.map +1 -1
  40. package/dist/generators/generateUnifiedDocs.d.ts +1 -1
  41. package/dist/generators/generateUnifiedDocs.js +15 -8
  42. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  43. package/dist/generators/generateUnifiedHandler.d.ts +2 -2
  44. package/dist/generators/generateUnifiedHandler.js +11 -3
  45. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  46. package/dist/guardOptions.js +12 -7
  47. package/dist/guardOptions.js.map +1 -1
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.js +22 -1
  50. package/dist/index.js.map +1 -1
  51. package/dist/utils/copyFiles.js +22 -6
  52. package/dist/utils/copyFiles.js.map +1 -1
  53. package/dist/utils/importExt.d.ts +1 -1
  54. package/dist/utils/pathCasing.d.ts +4 -0
  55. package/dist/utils/pathCasing.js +40 -0
  56. package/dist/utils/pathCasing.js.map +1 -0
  57. package/dist/utils/resolveImportStyle.js +13 -5
  58. package/dist/utils/resolveImportStyle.js.map +1 -1
  59. package/dist/utils/writeFileSafely.js.map +1 -1
  60. package/package.json +16 -3
  61. package/src/bin.ts +1 -1
  62. package/src/client/encodeQueryParams.ts +39 -35
  63. package/src/constants.ts +1 -1
  64. package/src/copy/autoIncludePlanner.ts +93 -27
  65. package/src/copy/autoIncludePlannerGuarded.ts +171 -48
  66. package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
  67. package/src/copy/buildModelOpenApi.ts +153 -50
  68. package/src/copy/concurrency.ts +10 -8
  69. package/src/copy/errorMapper.ts +68 -19
  70. package/src/copy/guardHelpers.ts +30 -9
  71. package/src/copy/materializedCount.ts +17 -5
  72. package/src/copy/misc.ts +88 -68
  73. package/src/copy/ndjson.ts +72 -0
  74. package/src/copy/operationDefinitions.ts +99 -21
  75. package/src/copy/operationRuntime.ts +100 -12
  76. package/src/copy/pagination.ts +25 -11
  77. package/src/copy/parseQueryParams.ts +47 -48
  78. package/src/copy/projectionDefaults.ts +6 -4
  79. package/src/copy/routeConfig.express.ts +16 -4
  80. package/src/copy/routeConfig.fastify.ts +16 -2
  81. package/src/copy/routeConfig.hono.ts +19 -9
  82. package/src/copy/routeConfig.ts +174 -39
  83. package/src/copy/scalarTypes.ts +7 -2
  84. package/src/copy/sse.ts +72 -19
  85. package/src/generators/generateFastifyHandler.ts +24 -13
  86. package/src/generators/generateHonoHandler.ts +21 -13
  87. package/src/generators/generateImportPrismaStatement.ts +93 -81
  88. package/src/generators/generateModelMetadata.ts +24 -12
  89. package/src/generators/generateOperationCore.ts +81 -33
  90. package/src/generators/generateQueryBuilderHelper.ts +20 -4
  91. package/src/generators/generateRelationMeta.ts +23 -11
  92. package/src/generators/generateRouteConfigType.ts +39 -13
  93. package/src/generators/generateRouter.ts +114 -17
  94. package/src/generators/generateRouterFastify.ts +67 -31
  95. package/src/generators/generateRouterHono.ts +108 -60
  96. package/src/generators/generateUnifiedDocs.ts +29 -8
  97. package/src/generators/generateUnifiedHandler.ts +16 -8
  98. package/src/generators/generateUnifiedScalarUI.ts +1 -1
  99. package/src/guardOptions.ts +105 -92
  100. package/src/index.ts +46 -4
  101. package/src/utils/copyFiles.ts +199 -168
  102. package/src/utils/importExt.ts +2 -2
  103. package/src/utils/pathCasing.ts +42 -0
  104. package/src/utils/resolveImportStyle.ts +37 -15
  105. package/src/utils/strings.ts +2 -2
  106. package/src/utils/writeFileSafely.ts +6 -2
@@ -1,5 +1,9 @@
1
1
  import { HttpError, LOG_PREFIX } from './errorMapper'
2
- import { assertGuard, buildCountShape, type PrismaDelegateLike } from './guardHelpers'
2
+ import {
3
+ assertGuard,
4
+ buildCountShape,
5
+ type PrismaDelegateLike,
6
+ } from './guardHelpers'
3
7
  import { countFromMaterializedView } from './materializedCount'
4
8
  import { isPlainObject } from './misc'
5
9
  import type { PaginationConfig, PaginationCountSource } from './routeConfig'
@@ -13,11 +17,16 @@ export function applyPaginationLimits(
13
17
  ): Record<string, unknown> {
14
18
  if (!config) return query
15
19
  const result: Record<string, unknown> = { ...query }
16
- if (!hasGuardShape && result.take === undefined && config.defaultLimit !== undefined) {
20
+ if (
21
+ !hasGuardShape &&
22
+ result.take === undefined &&
23
+ config.defaultLimit !== undefined
24
+ ) {
17
25
  result.take = config.defaultLimit
18
26
  }
19
27
  if (config.maxLimit !== undefined && result.take !== undefined) {
20
- const takeNum = typeof result.take === 'number' ? result.take : Number(result.take)
28
+ const takeNum =
29
+ typeof result.take === 'number' ? result.take : Number(result.take)
21
30
  if (!Number.isFinite(takeNum)) {
22
31
  throw new HttpError(400, 'Invalid take: must be a finite number')
23
32
  }
@@ -65,7 +74,10 @@ export function mergePaginationConfig(
65
74
  ...(base ?? {}),
66
75
  ...(override ?? {}),
67
76
  }
68
- const mergedCountSource = mergeCountSource(base?.countSource, override?.countSource)
77
+ const mergedCountSource = mergeCountSource(
78
+ base?.countSource,
79
+ override?.countSource,
80
+ )
69
81
  if (mergedCountSource) {
70
82
  merged.countSource = mergedCountSource
71
83
  } else {
@@ -76,7 +88,8 @@ export function mergePaginationConfig(
76
88
 
77
89
  export function normalizeDistinct(value: unknown): string[] {
78
90
  if (typeof value === 'string') return [value]
79
- if (Array.isArray(value)) return value.filter((v): v is string => typeof v === 'string')
91
+ if (Array.isArray(value))
92
+ return value.filter((v): v is string => typeof v === 'string')
80
93
  return []
81
94
  }
82
95
 
@@ -118,10 +131,9 @@ export async function countForPagination(
118
131
  if (query.where) countArgs.where = query.where
119
132
  if (countShape) {
120
133
  assertGuard(delegate)
121
- return (await delegate.guard(
122
- countShape as Record<string, unknown>,
123
- caller,
124
- ).count(countArgs)) as number
134
+ return (await delegate
135
+ .guard(countShape as Record<string, unknown>, caller)
136
+ .count(countArgs)) as number
125
137
  }
126
138
  return (await delegate.count(countArgs)) as number
127
139
  }
@@ -140,7 +152,9 @@ export async function countForPagination(
140
152
  if (results.length > effectiveLimit) {
141
153
  console.warn(
142
154
  LOG_PREFIX,
143
- 'Distinct count exceeds ' + effectiveLimit + ', falling back to approximate total',
155
+ 'Distinct count exceeds ' +
156
+ effectiveLimit +
157
+ ', falling back to approximate total',
144
158
  )
145
159
  return runCount()
146
160
  }
@@ -148,4 +162,4 @@ export async function countForPagination(
148
162
  }
149
163
 
150
164
  return runCount()
151
- }
165
+ }
@@ -1,48 +1,47 @@
1
- import { isObject, isSafeKey, sanitizeKeys } from './misc'
2
-
3
- type QueryParams =
4
- | string
5
- | Record<string, unknown>
6
- | string[]
7
- | Record<string, unknown>[]
8
- | undefined
9
-
10
- const NUMERIC_KEYS = new Set(['take', 'skip'])
11
- const INTEGER_RE = /^-?\d+$/
12
-
13
- const parseQueryValue = (value: string, key?: string): unknown => {
14
- if (value.startsWith('{') || value.startsWith('[') || value.startsWith('"')) {
15
- try {
16
- const parsed = JSON.parse(value)
17
- return sanitizeKeys(parsed)
18
- } catch {
19
- }
20
- }
21
- if (value === 'true') return true
22
- if (value === 'false') return false
23
- if (value === 'null') return null
24
- if (key && NUMERIC_KEYS.has(key) && INTEGER_RE.test(value)) {
25
- return parseInt(value, 10)
26
- }
27
- return value
28
- }
29
-
30
- export const parseQueryParams = (params: QueryParams): unknown => {
31
- if (typeof params === 'string') return parseQueryValue(params)
32
- if (Array.isArray(params)) {
33
- return params.map((item) =>
34
- typeof item === 'string' ? parseQueryValue(item) : sanitizeKeys(item),
35
- )
36
- }
37
- if (isObject(params)) {
38
- const parsedParams: Record<string, unknown> = {}
39
- for (const key of Object.keys(params)) {
40
- if (!isSafeKey(key)) continue
41
- const raw = params[key]
42
- parsedParams[key] =
43
- typeof raw === 'string' ? parseQueryValue(raw, key) : sanitizeKeys(raw)
44
- }
45
- return parsedParams
46
- }
47
- return params
48
- }
1
+ import { isObject, isSafeKey, sanitizeKeys } from './misc'
2
+
3
+ type QueryParams =
4
+ | string
5
+ | Record<string, unknown>
6
+ | string[]
7
+ | Record<string, unknown>[]
8
+ | undefined
9
+
10
+ const NUMERIC_KEYS = new Set(['take', 'skip'])
11
+ const INTEGER_RE = /^-?\d+$/
12
+
13
+ const parseQueryValue = (value: string, key?: string): unknown => {
14
+ if (value.startsWith('{') || value.startsWith('[') || value.startsWith('"')) {
15
+ try {
16
+ const parsed = JSON.parse(value)
17
+ return sanitizeKeys(parsed)
18
+ } catch {}
19
+ }
20
+ if (value === 'true') return true
21
+ if (value === 'false') return false
22
+ if (value === 'null') return null
23
+ if (key && NUMERIC_KEYS.has(key) && INTEGER_RE.test(value)) {
24
+ return parseInt(value, 10)
25
+ }
26
+ return value
27
+ }
28
+
29
+ export const parseQueryParams = (params: QueryParams): unknown => {
30
+ if (typeof params === 'string') return parseQueryValue(params)
31
+ if (Array.isArray(params)) {
32
+ return params.map((item) =>
33
+ typeof item === 'string' ? parseQueryValue(item) : sanitizeKeys(item),
34
+ )
35
+ }
36
+ if (isObject(params)) {
37
+ const parsedParams: Record<string, unknown> = {}
38
+ for (const key of Object.keys(params)) {
39
+ if (!isSafeKey(key)) continue
40
+ const raw = params[key]
41
+ parsedParams[key] =
42
+ typeof raw === 'string' ? parseQueryValue(raw, key) : sanitizeKeys(raw)
43
+ }
44
+ return parsedParams
45
+ }
46
+ return params
47
+ }
@@ -64,8 +64,7 @@ function emptyForced(): WhereForced {
64
64
 
65
65
  function hasForced(f: WhereForced): boolean {
66
66
  return (
67
- Object.keys(f.conditions).length > 0 ||
68
- Object.keys(f.relations).length > 0
67
+ Object.keys(f.conditions).length > 0 || Object.keys(f.relations).length > 0
69
68
  )
70
69
  }
71
70
 
@@ -423,7 +422,10 @@ export async function applyDroppedGuard(
423
422
  : emptyForced()
424
423
 
425
424
  const forcedData =
426
- opKind === 'create' || opKind === 'createMany' || opKind === 'update' || opKind === 'updateMany'
425
+ opKind === 'create' ||
426
+ opKind === 'createMany' ||
427
+ opKind === 'update' ||
428
+ opKind === 'updateMany'
427
429
  ? isPlainObject(resolved.data)
428
430
  ? extractForcedFromDataConfig(resolved.data)
429
431
  : {}
@@ -474,4 +476,4 @@ export async function applyDroppedGuard(
474
476
  if (Object.keys(forcedUpdate).length > 0) {
475
477
  target.update = mergeForcedData(target.update, forcedUpdate)
476
478
  }
477
- }
479
+ }
@@ -4,6 +4,7 @@ import type {
4
4
  BaseRouteConfig,
5
5
  ProgressiveStage,
6
6
  ProgressiveVariantConfig,
7
+ PrismaClientLike,
7
8
  QueryBuilderConfig,
8
9
  OpenApiServerConfig,
9
10
  OpenApiSecuritySchemeConfig,
@@ -21,6 +22,7 @@ export type {
21
22
  FindManyPaginatedMode,
22
23
  PaginationConfig,
23
24
  PaginationCountSource,
25
+ PrismaClientLike,
24
26
  }
25
27
 
26
28
  export type {
@@ -40,13 +42,13 @@ export type OperationConfig<TShape = Record<string, unknown>> =
40
42
  export type ReadOperationConfig<
41
43
  TShape = Record<string, unknown>,
42
44
  TCtx = unknown,
43
- TPrisma = any,
45
+ TPrisma extends PrismaClientLike = PrismaClientLike,
44
46
  > = BaseOperationConfig<RequestHandler, TShape> & {
45
47
  progressive?: Record<string, ProgressiveVariantConfig>
46
48
  progressiveStages?: Record<string, ProgressiveStage<TCtx, TPrisma>>
47
49
  }
48
50
 
49
- type ReadOperationOverrides<TShape, TCtx, TPrisma> = {
51
+ type ReadOperationOverrides<TShape, TCtx, TPrisma extends PrismaClientLike> = {
50
52
  findFirst?: ReadOperationConfig<TShape, TCtx, TPrisma> | false
51
53
  findFirstOrThrow?: ReadOperationConfig<TShape, TCtx, TPrisma> | false
52
54
  findUnique?: ReadOperationConfig<TShape, TCtx, TPrisma> | false
@@ -61,6 +63,16 @@ type ReadOperationOverrides<TShape, TCtx, TPrisma> = {
61
63
  export type RouteConfig<
62
64
  TShape = Record<string, unknown>,
63
65
  TCtx = unknown,
64
- TPrisma = any,
66
+ TPrisma extends PrismaClientLike = PrismaClientLike,
65
67
  > = BaseRouteConfig<RequestHandler, Request, TShape, TCtx> &
66
- ReadOperationOverrides<TShape, TCtx, TPrisma>
68
+ ReadOperationOverrides<TShape, TCtx, TPrisma> & {
69
+ /**
70
+ * Honour `PGE_DROP_GUARD=true` in the environment as a guard bypass
71
+ * (deprecated alias: `E2E=true`). **Default `false` for this target.**
72
+ *
73
+ * Only the explicit `true` enables it; false or omitted means the
74
+ * environment cannot drop guards. The generation-time `dropGuard` literal
75
+ * is independent of this control and unchanged.
76
+ */
77
+ allowE2EGuardBypass?: boolean
78
+ }
@@ -9,6 +9,7 @@ import type {
9
9
  FindManyPaginatedMode,
10
10
  PaginationConfig,
11
11
  PaginationCountSource,
12
+ PrismaClientLike,
12
13
  } from './routeConfig'
13
14
 
14
15
  export type {
@@ -19,6 +20,7 @@ export type {
19
20
  FindManyPaginatedMode,
20
21
  PaginationConfig,
21
22
  PaginationCountSource,
23
+ PrismaClientLike,
22
24
  }
23
25
 
24
26
  export type FastifyHookHandler = (
@@ -29,5 +31,17 @@ export type FastifyHookHandler = (
29
31
  export type OperationConfig<TShape = Record<string, unknown>> =
30
32
  BaseOperationConfig<FastifyHookHandler, TShape>
31
33
 
32
- export type RouteConfig<TShape = Record<string, unknown>, TCtx = unknown> =
33
- BaseRouteConfig<FastifyHookHandler, FastifyRequest, TShape, TCtx>
34
+ export type RouteConfig<
35
+ TShape = Record<string, unknown>,
36
+ TCtx = unknown,
37
+ > = BaseRouteConfig<FastifyHookHandler, FastifyRequest, TShape, TCtx> & {
38
+ /**
39
+ * Honour `PGE_DROP_GUARD=true` in the environment as a guard bypass
40
+ * (deprecated alias: `E2E=true`). **Default `false` for this target.**
41
+ *
42
+ * Only the explicit `true` enables it; false or omitted means the
43
+ * environment cannot drop guards. The generation-time `dropGuard` literal
44
+ * is independent of this control and unchanged.
45
+ */
46
+ allowE2EGuardBypass?: boolean
47
+ }
@@ -1,3 +1,4 @@
1
+ import type { RuntimeOperationOverride } from './operationRuntime'
1
2
  import type { Context } from 'hono'
2
3
  import type { GuardVariantResolution } from './guardVariantRouting'
3
4
  import type {
@@ -10,6 +11,7 @@ import type {
10
11
  FindManyPaginatedMode,
11
12
  PaginationConfig,
12
13
  PaginationCountSource,
14
+ PrismaClientLike,
13
15
  } from './routeConfig'
14
16
 
15
17
  export type {
@@ -20,6 +22,7 @@ export type {
20
22
  FindManyPaginatedMode,
21
23
  PaginationConfig,
22
24
  PaginationCountSource,
25
+ PrismaClientLike,
23
26
  }
24
27
 
25
28
  export type HonoEnvBase = {
@@ -28,6 +31,8 @@ export type HonoEnvBase = {
28
31
  }
29
32
 
30
33
  export type HonoInternalVariables = {
34
+ operationOverride?: RuntimeOperationOverride
35
+ resolveOperationContext?: () => unknown | Promise<unknown>
31
36
  prisma?: unknown
32
37
  postgres?: unknown
33
38
  sqlite?: unknown
@@ -38,13 +43,20 @@ export type HonoInternalVariables = {
38
43
  guardCaller?: string
39
44
  guardVariantKey?: string
40
45
  guardVariantFailure?: Extract<GuardVariantResolution, { ok: false }>
46
+ /**
47
+ * Set when `validateResolvedShapes` refuses what a shape function returned.
48
+ *
49
+ * It was written by the router and never declared here, so the emitted router
50
+ * failed to typecheck at exactly the line that implements the control.
51
+ */
52
+ guardShapeFailure?: string
41
53
  resultData?: unknown
42
54
  resultStatus?: number
43
55
  }
44
56
 
45
57
  export type GeneratedHonoEnv<TEnv extends HonoEnvBase = HonoEnvBase> = {
46
58
  Variables: HonoInternalVariables & TEnv['Variables']
47
- Bindings: TEnv['Bindings']
59
+ Bindings: NonNullable<TEnv['Bindings']>
48
60
  }
49
61
 
50
62
  export type HonoBeforeHook<TEnv extends HonoEnvBase = HonoEnvBase> = (
@@ -56,16 +68,13 @@ export type HonoAfterHook<TEnv extends HonoEnvBase = HonoEnvBase> = (
56
68
  ) => Promise<Response | void> | Response | void
57
69
 
58
70
  /** @deprecated use HonoBeforeHook or HonoAfterHook */
59
- export type HonoHookHandler<TEnv extends HonoEnvBase = HonoEnvBase> = HonoBeforeHook<TEnv>
71
+ export type HonoHookHandler<TEnv extends HonoEnvBase = HonoEnvBase> =
72
+ HonoBeforeHook<TEnv>
60
73
 
61
74
  export type OperationConfig<
62
75
  TShape = Record<string, unknown>,
63
76
  TEnv extends HonoEnvBase = HonoEnvBase,
64
- > = BaseOperationConfig<
65
- HonoBeforeHook<TEnv>,
66
- TShape,
67
- HonoAfterHook<TEnv>
68
- >
77
+ > = BaseOperationConfig<HonoBeforeHook<TEnv>, TShape, HonoAfterHook<TEnv>>
69
78
 
70
79
  export type UpdateEachConfig<TEnv extends HonoEnvBase = HonoEnvBase> = {
71
80
  before?: HonoBeforeHook<TEnv>[]
@@ -173,7 +182,8 @@ export type RouteConfig<
173
182
  guardResolutionOrder?: 'after-hooks' | 'before-hooks'
174
183
 
175
184
  /**
176
- * Honour `E2E=true` in the environment as a guard bypass. **Default `true`.**
185
+ * Honour `PGE_DROP_GUARD=true` in the environment as a guard bypass
186
+ * (deprecated alias: `E2E=true`). **Default `true`.**
177
187
  *
178
188
  * Upstream behaviour, and a real hazard on an edge runtime where that variable
179
189
  * is an ordinary config var — set on staging, copied forward, flagged as
@@ -211,4 +221,4 @@ export type RouteConfig<
211
221
  count?: OperationConfig<TShape, TEnv> | false
212
222
  groupBy?: OperationConfig<TShape, TEnv> | false
213
223
  updateEach?: UpdateEachConfig<TEnv>
214
- }
224
+ }