prisma-generator-express 1.64.2 → 1.64.3

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.
@@ -0,0 +1,226 @@
1
+ /**
2
+ * PUBLIC, COMPILED METADATA for the Hono guard controls.
3
+ *
4
+ * **Why this file exists separately from `src/copy/routeConfig.ts`.**
5
+ * `src/copy/**` is excluded from the TypeScript build (`tsconfig.json`) because
6
+ * those files are copied verbatim into a generated project rather than compiled
7
+ * into this package. So anything defined only there is absent from `dist` and
8
+ * unreachable through the package entry point — which made the first version of
9
+ * this metadata unusable by the very consumer it was written for.
10
+ *
11
+ * This module is compiled, exported from `src/index.ts`, and therefore importable
12
+ * as `require('prisma-generator-express').GUARD_OPTION_METADATA` from an
13
+ * installed package. `test/consumer/packedMetadata.test.ts` proves that by packing
14
+ * the tarball and importing it the way a consumer would.
15
+ *
16
+ * **Scope, stated narrowly.** This is authoritative for the seven M8.7 GUARD
17
+ * controls and nothing else. The generator has many other public settings that
18
+ * change the emitted API — `dropGuard`, the target, the write strategy, the
19
+ * pagination mode, prefixes, OpenAPI options, the query-builder toggle — and none
20
+ * of them are described here yet. A configuration UI cannot build a complete
21
+ * screen from this file alone, and should not pretend otherwise.
22
+ *
23
+ * **Duplication is deliberate and guarded.** The runtime defaults live in
24
+ * `src/copy/routeConfig.ts` because the generated project needs them with no
25
+ * dependency on this package. They cannot import each other across the compile
26
+ * boundary, so the values appear twice and
27
+ * `test/unit/copy/guardOptionIndependence.test.ts` asserts the two agree, against
28
+ * the resolver the router actually runs. Drift fails a test rather than shipping a
29
+ * UI that advertises a default the code does not apply.
30
+ */
31
+
32
+ export type GuardResolutionOrder = 'after-hooks' | 'before-hooks'
33
+
34
+ export type GuardPolicy = {
35
+ requireGuardShape: boolean
36
+ validateGuardShapes: boolean
37
+ requireDefaultVariantOptIn: boolean
38
+ enableUpdateEach: boolean
39
+ guardResolutionOrder: GuardResolutionOrder
40
+ allowE2EGuardBypass: boolean
41
+ validateResolvedShapes: boolean
42
+ }
43
+
44
+ /**
45
+ * The public package's pre-1.64.2 behaviour, exactly.
46
+ *
47
+ * An unset option resolves to the value here. Changing one changes what every
48
+ * consumer who configured nothing gets on upgrade, which is the failure 1.64.2
49
+ * shipped and this table exists to prevent.
50
+ */
51
+ export const UPSTREAM_GUARD_DEFAULTS: Readonly<GuardPolicy> = Object.freeze({
52
+ requireGuardShape: false,
53
+ validateGuardShapes: false,
54
+ requireDefaultVariantOptIn: false,
55
+ enableUpdateEach: true,
56
+ guardResolutionOrder: 'after-hooks',
57
+ allowE2EGuardBypass: true,
58
+ validateResolvedShapes: false,
59
+ })
60
+
61
+ /**
62
+ * Every control at its most restrictive — a SHORTCUT, not a mode.
63
+ *
64
+ * Spread it, change what you disagree with, store the result. There is
65
+ * deliberately no `preset: 'hardened'` option anywhere in this package: a stored
66
+ * preset NAME would let a future version silently change what an existing
67
+ * configuration does, which is the same class of mistake as 1.64.2.
68
+ */
69
+ export const HARDENED_GUARD_PROFILE: Readonly<GuardPolicy> = Object.freeze({
70
+ requireGuardShape: true,
71
+ validateGuardShapes: true,
72
+ requireDefaultVariantOptIn: true,
73
+ enableUpdateEach: false,
74
+ guardResolutionOrder: 'before-hooks',
75
+ allowE2EGuardBypass: false,
76
+ validateResolvedShapes: true,
77
+ })
78
+
79
+ export type GuardOptionMetadata = {
80
+ name: keyof GuardPolicy
81
+ type: 'boolean' | 'enum'
82
+ values?: readonly string[]
83
+ default: boolean | string
84
+ hardened: boolean | string
85
+ label: string
86
+ description: string
87
+ /** Present where the permissive value can emit an unguarded or caller-selected route. */
88
+ warning: string
89
+ /** The target whose generated router reads this control. */
90
+ target: 'hono'
91
+ }
92
+
93
+ /**
94
+ * Machine-readable description of the seven guard controls.
95
+ *
96
+ * `target: 'hono'` on every entry is not decoration. These options are declared
97
+ * on the Hono route configuration only, because only the Hono generator reads
98
+ * them; declaring them on the shared base made Express and Fastify accept them in
99
+ * TypeScript and ignore them at runtime, which is a false public API.
100
+ */
101
+ export const GUARD_OPTION_METADATA: readonly GuardOptionMetadata[] = Object.freeze([
102
+ {
103
+ name: 'requireGuardShape',
104
+ type: 'boolean',
105
+ default: UPSTREAM_GUARD_DEFAULTS.requireGuardShape,
106
+ hardened: HARDENED_GUARD_PROFILE.requireGuardShape,
107
+ label: 'Require a guard on every enabled operation',
108
+ description:
109
+ 'Refuses at router construction when an operation defines neither "shape" nor "variants".',
110
+ warning:
111
+ "Off, an operation nobody configured passes the caller's own where/select/include straight to Prisma.",
112
+ target: 'hono',
113
+ },
114
+ {
115
+ name: 'validateGuardShapes',
116
+ type: 'boolean',
117
+ default: UPSTREAM_GUARD_DEFAULTS.validateGuardShapes,
118
+ hardened: HARDENED_GUARD_PROFILE.validateGuardShapes,
119
+ label: 'Validate guard shapes',
120
+ description:
121
+ 'Refuses an empty shape, and one mixing guard keys with non-guard keys, at the top level and inside variants.',
122
+ warning:
123
+ 'Off, "shape: {}" reads as guarded and constrains nothing. On, strict validation may reject existing route configs.',
124
+ target: 'hono',
125
+ },
126
+ {
127
+ name: 'requireDefaultVariantOptIn',
128
+ type: 'boolean',
129
+ default: UPSTREAM_GUARD_DEFAULTS.requireDefaultVariantOptIn,
130
+ hardened: HARDENED_GUARD_PROFILE.requireDefaultVariantOptIn,
131
+ label: 'Require confirmation for a "default" variant',
132
+ description:
133
+ 'A variant named "default" must set allowDefaultVariant: true to be accepted.',
134
+ warning: 'A "default" variant answers every unrecognised, blank and missing caller.',
135
+ target: 'hono',
136
+ },
137
+ {
138
+ name: 'enableUpdateEach',
139
+ type: 'boolean',
140
+ default: UPSTREAM_GUARD_DEFAULTS.enableUpdateEach,
141
+ hardened: HARDENED_GUARD_PROFILE.enableUpdateEach,
142
+ label: 'Register the updateEach batch route',
143
+ description: 'Mounts POST <base>/each. Set false to refuse it at router construction.',
144
+ warning:
145
+ 'updateEach bypasses guard shapes entirely; only a development-only warning stands between it and an unguarded mass update.',
146
+ target: 'hono',
147
+ },
148
+ {
149
+ name: 'guardResolutionOrder',
150
+ type: 'enum',
151
+ values: Object.freeze(['after-hooks', 'before-hooks']),
152
+ default: UPSTREAM_GUARD_DEFAULTS.guardResolutionOrder,
153
+ hardened: HARDENED_GUARD_PROFILE.guardResolutionOrder,
154
+ label: 'When guard failures are raised',
155
+ description:
156
+ 'after-hooks is the upstream behaviour; before-hooks settles variant and shape resolution before any operation hook runs.',
157
+ warning:
158
+ 'With after-hooks, a hook that returns a Response can answer a request whose guard was never established.',
159
+ target: 'hono',
160
+ },
161
+ {
162
+ name: 'allowE2EGuardBypass',
163
+ type: 'boolean',
164
+ default: UPSTREAM_GUARD_DEFAULTS.allowE2EGuardBypass,
165
+ hardened: HARDENED_GUARD_PROFILE.allowE2EGuardBypass,
166
+ label: 'Honour the E2E environment guard bypass',
167
+ description: 'Treats E2E=true in the environment as a request to drop the guard.',
168
+ warning:
169
+ 'A runtime variable can weaken a deployed artifact after generation. On an edge runtime this is an ordinary config var.',
170
+ target: 'hono',
171
+ },
172
+ {
173
+ name: 'validateResolvedShapes',
174
+ type: 'boolean',
175
+ default: UPSTREAM_GUARD_DEFAULTS.validateResolvedShapes,
176
+ hardened: HARDENED_GUARD_PROFILE.validateResolvedShapes,
177
+ label: 'Validate what a shape function returns',
178
+ description:
179
+ 'Checks a dynamically resolved shape before use and fails the request with 500 if it is unusable. Also resolves it exactly once.',
180
+ warning:
181
+ 'Off, a shape function returning {} or undefined runs the operation unguarded, once per request.',
182
+ target: 'hono',
183
+ },
184
+ ])
185
+
186
+ /**
187
+ * What this metadata does NOT cover.
188
+ *
189
+ * Exported so a consumer can display the gap rather than infer completeness from
190
+ * silence, and so a test can assert the claim is narrow. Every name here is a
191
+ * public setting that changes the emitted API and has no entry above.
192
+ */
193
+ export const GUARD_METADATA_SCOPE = Object.freeze({
194
+ covers: 'the seven M8.7 guard controls on the Hono target',
195
+ complete: false,
196
+ notDescribedYet: Object.freeze([
197
+ 'dropGuard',
198
+ 'target',
199
+ 'writeStrategy',
200
+ 'findManyPaginated / pagination mode',
201
+ 'pagination.countSource',
202
+ 'addModelPrefix / customUrlPrefix / specBasePath',
203
+ 'disableOpenApi and the OpenAPI metadata options',
204
+ 'disablePostReads',
205
+ 'queryBuilder',
206
+ 'guard.resolveVariant / guard.variantHeader',
207
+ ]),
208
+ })
209
+
210
+ /** Fill in the defaults. Absent means upstream, never an opinion. */
211
+ export function resolveGuardPolicy(config: Partial<GuardPolicy> | undefined): GuardPolicy {
212
+ return {
213
+ requireGuardShape: config?.requireGuardShape ?? UPSTREAM_GUARD_DEFAULTS.requireGuardShape,
214
+ validateGuardShapes:
215
+ config?.validateGuardShapes ?? UPSTREAM_GUARD_DEFAULTS.validateGuardShapes,
216
+ requireDefaultVariantOptIn:
217
+ config?.requireDefaultVariantOptIn ?? UPSTREAM_GUARD_DEFAULTS.requireDefaultVariantOptIn,
218
+ enableUpdateEach: config?.enableUpdateEach ?? UPSTREAM_GUARD_DEFAULTS.enableUpdateEach,
219
+ guardResolutionOrder:
220
+ config?.guardResolutionOrder ?? UPSTREAM_GUARD_DEFAULTS.guardResolutionOrder,
221
+ allowE2EGuardBypass:
222
+ config?.allowE2EGuardBypass ?? UPSTREAM_GUARD_DEFAULTS.allowE2EGuardBypass,
223
+ validateResolvedShapes:
224
+ config?.validateResolvedShapes ?? UPSTREAM_GUARD_DEFAULTS.validateResolvedShapes,
225
+ }
226
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,22 @@
1
+ /**
2
+ * Public, compiled configuration metadata (M8.7).
3
+ *
4
+ * Re-exported here because `src/copy/**` is excluded from the build, so anything
5
+ * defined only there never reaches `dist` and cannot be imported from an
6
+ * installed package. See src/guardOptions.ts.
7
+ *
8
+ * Authoritative for the seven Hono guard controls only — `GUARD_METADATA_SCOPE`
9
+ * lists what is not described yet.
10
+ */
11
+ export {
12
+ GUARD_OPTION_METADATA,
13
+ GUARD_METADATA_SCOPE,
14
+ UPSTREAM_GUARD_DEFAULTS,
15
+ HARDENED_GUARD_PROFILE,
16
+ resolveGuardPolicy,
17
+ } from './guardOptions'
18
+ export type { GuardPolicy, GuardOptionMetadata, GuardResolutionOrder } from './guardOptions'
19
+
1
20
  import {
2
21
  generatorHandler,
3
22
  GeneratorOptions,